From 76a47ad618b82a05c3b8bd415190752985d7ee2c Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Thu, 19 Mar 2026 07:43:17 +1100 Subject: [PATCH 1/6] error messages --- src/outline/manager.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/outline/manager.js b/src/outline/manager.js index 767a832e..6a9031ad 100644 --- a/src/outline/manager.js +++ b/src/outline/manager.js @@ -2106,11 +2106,16 @@ export default function (context) { const existing = p.querySelector('[data-outline-error-for="' + docUri + '"]') if (existing) return } + const detailStr = typeof detail === 'string' ? detail : (detail && detail.message) || '' + const errorStatus = (errObj && errObj.status) || (detailStr.match(/status:\s*(\d+)/) || [])[1] + const isAuthError = errorStatus === 401 || errorStatus === 403 || + errorStatus === '401' || errorStatus === '403' || + /Unauthorized|Forbidden/.test(detailStr) const message = UI.widgets.errorMessageBlock( dom, - detail, - '#fee', - errObj instanceof Error ? errObj : undefined + isAuthError ? 'You need to log in to see this resource.' : detail, + isAuthError ? '#d8d8d8' : '#fee', + !isAuthError && errObj instanceof Error ? errObj : undefined ) if (docUri) message.setAttribute('data-outline-error-for', docUri) p.appendChild(message) From 30b1a7a5ba01a14235b1bdefd3d2c53386addbcf Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Thu, 19 Mar 2026 07:43:36 +1100 Subject: [PATCH 2/6] logout and login --- src/mainPage/index.ts | 44 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/mainPage/index.ts b/src/mainPage/index.ts index 8c8b5345..15cf9f9b 100644 --- a/src/mainPage/index.ts +++ b/src/mainPage/index.ts @@ -4,16 +4,52 @@ */ import { LiveStore, NamedNode } from 'rdflib' +import { authSession, authn } from 'solid-logic' import { getOutliner } from '../index' import { createHeader } from './header' import { createFooter } from './footer' export default async function initMainPage (store: LiveStore, uri?: string | NamedNode | null) { const outliner = getOutliner(document) - uri = uri || window.location.href - let subject = uri - if (typeof uri === 'string') subject = store.sym(uri) - outliner.GotoSubject(subject, true, undefined, true, undefined) + const hasExplicitUriArg = uri !== undefined && uri !== null + const locationUrl = new URL(window.location.href) + const explicitUriQuery = locationUrl.searchParams.get('uri') + const isLoggedIn = !!(authSession.info && authSession.info.isLoggedIn) + const isBareAppRoot = locationUrl.pathname === '/' && !locationUrl.search && !locationUrl.hash + + if (isBareAppRoot && !hasExplicitUriArg && !explicitUriQuery) { + // At bare app root, avoid fetching '/' as data. If logged in, land on the user's profile instead. + let me = authn.currentUser() + if (isLoggedIn && !me) { + let webId = await authn.checkUser() + if (!webId) { + // Some IdP/session states resolve slightly after app bootstrap. + await new Promise(resolve => setTimeout(resolve, 300)) + webId = await authn.checkUser() + } + if (typeof webId === 'string') { + me = store.sym(webId) + } + } + if (isLoggedIn && me) { + outliner.GotoSubject(me, true, undefined, true, undefined) + } else if (isLoggedIn) { + // Optional override: set localStorage.solidosSafeLandingUri to a public resource URI. + const configuredLandingUri = window.localStorage.getItem('solidosSafeLandingUri') + if (configuredLandingUri) { + const fallbackUrl = new URL(configuredLandingUri, locationUrl.origin) + if (!(fallbackUrl.origin === locationUrl.origin && fallbackUrl.pathname === '/')) { + outliner.GotoSubject(store.sym(fallbackUrl.toString()), true, undefined, true, undefined) + } + } + } + } else { + uri = uri || window.location.href + let subject = uri + if (typeof uri === 'string') subject = store.sym(uri) + outliner.GotoSubject(subject, true, undefined, true, undefined) + } + const header = await createHeader(store, outliner) const footer = createFooter(store) return Promise.all([header, footer]) From 428742d50ba1062fd16f06cfa98ae5515297e2bd Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Sat, 21 Mar 2026 07:48:32 +1100 Subject: [PATCH 3/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/outline/manager.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/outline/manager.js b/src/outline/manager.js index 6a9031ad..0451846a 100644 --- a/src/outline/manager.js +++ b/src/outline/manager.js @@ -2108,8 +2108,9 @@ export default function (context) { } const detailStr = typeof detail === 'string' ? detail : (detail && detail.message) || '' const errorStatus = (errObj && errObj.status) || (detailStr.match(/status:\s*(\d+)/) || [])[1] - const isAuthError = errorStatus === 401 || errorStatus === 403 || - errorStatus === '401' || errorStatus === '403' || + const statusCode = Number(errorStatus) + const isAuthError = + (Number.isFinite(statusCode) && [401, 403].includes(statusCode)) || /Unauthorized|Forbidden/.test(detailStr) const message = UI.widgets.errorMessageBlock( dom, From 13884f3ea440578901b232dfb30ccce846cafa24 Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Sat, 21 Mar 2026 07:49:08 +1100 Subject: [PATCH 4/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/mainPage/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mainPage/index.ts b/src/mainPage/index.ts index 15cf9f9b..e8528b43 100644 --- a/src/mainPage/index.ts +++ b/src/mainPage/index.ts @@ -17,7 +17,7 @@ export default async function initMainPage (store: LiveStore, uri?: string | Nam const isLoggedIn = !!(authSession.info && authSession.info.isLoggedIn) const isBareAppRoot = locationUrl.pathname === '/' && !locationUrl.search && !locationUrl.hash - if (isBareAppRoot && !hasExplicitUriArg && !explicitUriQuery) { + if (isBareAppRoot && !hasExplicitUriArg && explicitUriQuery === null) { // At bare app root, avoid fetching '/' as data. If logged in, land on the user's profile instead. let me = authn.currentUser() if (isLoggedIn && !me) { From 5504248bcf8e9ef3187b10f86404a5b47204892e Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Sat, 21 Mar 2026 07:49:58 +1100 Subject: [PATCH 5/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/mainPage/index.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/mainPage/index.ts b/src/mainPage/index.ts index e8528b43..99acf252 100644 --- a/src/mainPage/index.ts +++ b/src/mainPage/index.ts @@ -37,9 +37,16 @@ export default async function initMainPage (store: LiveStore, uri?: string | Nam // Optional override: set localStorage.solidosSafeLandingUri to a public resource URI. const configuredLandingUri = window.localStorage.getItem('solidosSafeLandingUri') if (configuredLandingUri) { - const fallbackUrl = new URL(configuredLandingUri, locationUrl.origin) - if (!(fallbackUrl.origin === locationUrl.origin && fallbackUrl.pathname === '/')) { - outliner.GotoSubject(store.sym(fallbackUrl.toString()), true, undefined, true, undefined) + try { + const fallbackUrl = new URL(configuredLandingUri, locationUrl.origin) + const protocol = fallbackUrl.protocol + // Only allow safe HTTP(S) protocols, and avoid redirecting back to bare app root. + if ((protocol === 'http:' || protocol === 'https:') && + !(fallbackUrl.origin === locationUrl.origin && fallbackUrl.pathname === '/')) { + outliner.GotoSubject(store.sym(fallbackUrl.toString()), true, undefined, true, undefined) + } + } catch { + // Ignore invalid configuredLandingUri values. } } } From 6f9ae5fa2ba885b2817ce2a2c6b7cd664b93ce88 Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Sat, 25 Apr 2026 08:20:29 +1000 Subject: [PATCH 6/6] save changes --- src/form/pane.js | 13 ++++++---- src/humanReadablePane.js | 10 +++++-- src/mainPage/index.ts | 56 ---------------------------------------- src/outline/manager.js | 12 +++------ src/pad/padPane.ts | 4 +-- 5 files changed, 21 insertions(+), 74 deletions(-) diff --git a/src/form/pane.js b/src/form/pane.js index 9c655615..d6e3f784 100644 --- a/src/form/pane.js +++ b/src/form/pane.js @@ -6,6 +6,8 @@ import * as UI from 'solid-ui' import { authn } from 'solid-logic' import * as $rdf from 'rdflib' +import '../styles/formPane.css' + const ns = UI.ns export const formPane = { @@ -27,15 +29,16 @@ export const formPane = { const kb = context.session.store const dom = context.dom - const mention = function complain (message, style) { + const mention = function mention (message, className) { const pre = dom.createElement('p') - pre.setAttribute('style', style || 'color: grey; background-color: white') + pre.classList.add('formPaneMessage') + pre.classList.add(className || 'formPaneMessageInfo') box.appendChild(pre).textContent = message return pre } - const complain = function complain (message, style) { - mention(message, 'style', style || 'color: grey; background-color: #fdd;') + const complain = function complain (message) { + mention(message, 'formPaneMessageError') } const complainIfBad = function (ok, body) { @@ -103,7 +106,7 @@ export const formPane = { complainIfBad ) ) - e.setAttribute('style', 'margin-left: auto; display: block;') + e.classList.add('formPaneEditButton') } } const anchor = dom.createElement('a') diff --git a/src/humanReadablePane.js b/src/humanReadablePane.js index 76109a75..00645881 100644 --- a/src/humanReadablePane.js +++ b/src/humanReadablePane.js @@ -7,6 +7,7 @@ import { icons, ns } from 'solid-ui' import { Util } from 'rdflib' import { marked } from 'marked' import DOMPurify from 'dompurify' +import './styles/humanReadablePane.css' // Helper function to check if a URI has a markdown file extension const isMarkdownFile = (uri) => { @@ -178,6 +179,11 @@ const humanReadablePane = { div.setAttribute('class', 'docView') div.setAttribute('style', 'display: block; width: 100%; max-width: 100%; box-sizing: border-box;') + const setFrameDisplayStyles = function (frame, lines) { + frame.classList.add('doc', 'humanReadableFrame') + frame.style.setProperty('--human-readable-height', `${lines}em`) + } + // render markdown to html in a DIV element const renderMarkdownContent = function (frame) { kb.fetcher.webOperation('GET', subject.uri).then(response => { @@ -216,7 +222,7 @@ const humanReadablePane = { if (isMarkdown) { // For markdown, use a DIV element and render the content - const frame = myDocument.createElement('DIV') + const frame = myDocument.createElement('div') renderMarkdownContent(frame) const frameContainer = myDocument.createElement('div') frameContainer.setAttribute('style', 'display: block; width: 100%; max-width: 100%; box-sizing: border-box;') @@ -232,7 +238,7 @@ const humanReadablePane = { div.appendChild(frameContainer) } else { // For other content types, use IFRAME - const frame = myDocument.createElement('IFRAME') + const frame = myDocument.createElement('iframe') // Apply sandbox for HTML/XHTML if (ct === 'text/html' || ct === 'application/xhtml+xml') { diff --git a/src/mainPage/index.ts b/src/mainPage/index.ts index fedd7cca..a02f4f64 100644 --- a/src/mainPage/index.ts +++ b/src/mainPage/index.ts @@ -4,66 +4,11 @@ */ import { LiveStore, NamedNode } from 'rdflib' -<<<<<<< HEAD -import { authSession, authn } from 'solid-logic' -import { getOutliner } from '../index' -import { createHeader } from './header' -======= import { getOutliner, OutlineManager } from '../index' import { createHeader, refreshHeader } from './header' ->>>>>>> main import { createFooter } from './footer' import { createLeftSideMenu, refreshMenu } from './menu' -<<<<<<< HEAD -export default async function initMainPage (store: LiveStore, uri?: string | NamedNode | null) { - const outliner = getOutliner(document) - const hasExplicitUriArg = uri !== undefined && uri !== null - const locationUrl = new URL(window.location.href) - const explicitUriQuery = locationUrl.searchParams.get('uri') - const isLoggedIn = !!(authSession.info && authSession.info.isLoggedIn) - const isBareAppRoot = locationUrl.pathname === '/' && !locationUrl.search && !locationUrl.hash - - if (isBareAppRoot && !hasExplicitUriArg && explicitUriQuery === null) { - // At bare app root, avoid fetching '/' as data. If logged in, land on the user's profile instead. - let me = authn.currentUser() - if (isLoggedIn && !me) { - let webId = await authn.checkUser() - if (!webId) { - // Some IdP/session states resolve slightly after app bootstrap. - await new Promise(resolve => setTimeout(resolve, 300)) - webId = await authn.checkUser() - } - if (typeof webId === 'string') { - me = store.sym(webId) - } - } - if (isLoggedIn && me) { - outliner.GotoSubject(me, true, undefined, true, undefined) - } else if (isLoggedIn) { - // Optional override: set localStorage.solidosSafeLandingUri to a public resource URI. - const configuredLandingUri = window.localStorage.getItem('solidosSafeLandingUri') - if (configuredLandingUri) { - try { - const fallbackUrl = new URL(configuredLandingUri, locationUrl.origin) - const protocol = fallbackUrl.protocol - // Only allow safe HTTP(S) protocols, and avoid redirecting back to bare app root. - if ((protocol === 'http:' || protocol === 'https:') && - !(fallbackUrl.origin === locationUrl.origin && fallbackUrl.pathname === '/')) { - outliner.GotoSubject(store.sym(fallbackUrl.toString()), true, undefined, true, undefined) - } - } catch { - // Ignore invalid configuredLandingUri values. - } - } - } - } else { - uri = uri || window.location.href - let subject = uri - if (typeof uri === 'string') subject = store.sym(uri) - outliner.GotoSubject(subject, true, undefined, true, undefined) - } -======= export { refreshMenu as updateMenuLayout } from './menu' export { refreshHeader } from './header' @@ -90,7 +35,6 @@ export async function initMainPage ( uri = uri || window.location.href const subject: NamedNode = typeof uri === 'string' ? store.sym(uri) : uri outliner.GotoSubject(subject, true, undefined, true, undefined) ->>>>>>> main const header = await createHeader(store, outliner) const menu = createLeftSideMenu(subject, outliner) diff --git a/src/outline/manager.js b/src/outline/manager.js index b8c2d449..b57ef366 100644 --- a/src/outline/manager.js +++ b/src/outline/manager.js @@ -2196,17 +2196,11 @@ export default function (context) { const existing = p.querySelector('[data-outline-error-for="' + docUri + '"]') if (existing) return } - const detailStr = typeof detail === 'string' ? detail : (detail && detail.message) || '' - const errorStatus = (errObj && errObj.status) || (detailStr.match(/status:\s*(\d+)/) || [])[1] - const statusCode = Number(errorStatus) - const isAuthError = - (Number.isFinite(statusCode) && [401, 403].includes(statusCode)) || - /Unauthorized|Forbidden/.test(detailStr) const message = UI.widgets.errorMessageBlock( dom, - isAuthError ? 'You need to log in to see this resource.' : detail, - isAuthError ? '#d8d8d8' : '#fee', - !isAuthError && errObj instanceof Error ? errObj : undefined + detail, + '#fee', + errObj instanceof Error ? errObj : undefined ) if (docUri) message.setAttribute('data-outline-error-for', docUri) p.appendChild(message) diff --git a/src/pad/padPane.ts b/src/pad/padPane.ts index 1cc12876..645c6ad1 100644 --- a/src/pad/padPane.ts +++ b/src/pad/padPane.ts @@ -394,7 +394,7 @@ const paneDef: PaneDefinition = { // give the user links to the new app const p = div.appendChild(dom.createElement('p')) - p.setAttribute('style', 'font-size: 140%;') + p.classList.add('padPaneSuccess') p.innerHTML = 'Your