diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..ac1944e7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + ci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + # Every top-level folder must stay pullable on its own — no workspace-only + # dependency specifiers (workspace:/catalog:/link:/file:). + - name: Lint standalone packages + run: pnpm lint:standalone + + - name: Run tests + run: pnpm -r test diff --git a/account-history/package.json b/account-history/package.json index 52d5d7c3..e39681de 100644 --- a/account-history/package.json +++ b/account-history/package.json @@ -7,7 +7,9 @@ "scripts": { "build": "vite build", "dev": "vite build --watch", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge-repo-solid-primitives": "2.5.2" @@ -22,10 +24,12 @@ "@inkandswitch/patchwork-filesystem": "^0.0.4", "@inkandswitch/patchwork-plugins": "^0.0.6", "babel-preset-solid": "^1.9.9", + "happy-dom": "^15.11.7", "solid-js": "^1.9.9", "typescript": "^5.9.3", "vite": "^7.1.9", + "vite-plugin-css-injected-by-js": "^3.5.2", "vite-plugin-solid": "^2.11.10", - "vite-plugin-css-injected-by-js": "^3.5.2" + "vitest": "^3.2.4" } } diff --git a/account-history/vitest.config.ts b/account-history/vitest.config.ts new file mode 100644 index 00000000..715c53e5 --- /dev/null +++ b/account-history/vitest.config.ts @@ -0,0 +1,14 @@ +import {defineConfig} from "vitest/config" +import solid from "vite-plugin-solid" + +export default defineConfig({ + plugins: [solid()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, + resolve: { + conditions: ["development", "browser"], + }, +}) diff --git a/account-picker/package.json b/account-picker/package.json index 2959579a..96e11eae 100644 --- a/account-picker/package.json +++ b/account-picker/package.json @@ -14,7 +14,9 @@ "build": "node esbuild/build.ts", "dev": "node esbuild/watch.ts", "pushwatch": "pnpm dev pushwork", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge": "^3.2.5", @@ -34,6 +36,10 @@ "@babel/parser": "7.28.4", "babel-preset-solid": "^1.9.9", "esbuild": "^0.23.1", - "typescript": "^5.8.3" + "happy-dom": "^15.11.7", + "typescript": "^5.8.3", + "vite": "^7.1.9", + "vite-plugin-solid": "^2.11.10", + "vitest": "^3.2.4" } } diff --git a/account-picker/vitest.config.ts b/account-picker/vitest.config.ts new file mode 100644 index 00000000..715c53e5 --- /dev/null +++ b/account-picker/vitest.config.ts @@ -0,0 +1,14 @@ +import {defineConfig} from "vitest/config" +import solid from "vite-plugin-solid" + +export default defineConfig({ + plugins: [solid()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, + resolve: { + conditions: ["development", "browser"], + }, +}) diff --git a/add-doc-to-sidebar-button/package.json b/add-doc-to-sidebar-button/package.json index f59bda98..571cd2ae 100644 --- a/add-doc-to-sidebar-button/package.json +++ b/add-doc-to-sidebar-button/package.json @@ -5,12 +5,18 @@ "main": "./index.js", "scripts": { "sync": "pushwork sync", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge": "^3.2.5", "@automerge/automerge-repo": "^2.6.0-subduction.9", "@inkandswitch/patchwork-filesystem": "^0.0.4", "@inkandswitch/patchwork-plugins": "^0.0.6" + }, + "devDependencies": { + "happy-dom": "^15.11.7", + "vitest": "^3.2.4" } } diff --git a/add-doc-to-sidebar-button/vitest.config.ts b/add-doc-to-sidebar-button/vitest.config.ts new file mode 100644 index 00000000..44198156 --- /dev/null +++ b/add-doc-to-sidebar-button/vitest.config.ts @@ -0,0 +1,9 @@ +import {defineConfig} from "vitest/config" + +export default defineConfig({ + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, +}) diff --git a/codemirror-base/package.json b/codemirror-base/package.json index c8acf38b..5f340753 100644 --- a/codemirror-base/package.json +++ b/codemirror-base/package.json @@ -22,7 +22,9 @@ "build": "node esbuild/build.ts", "dev": "node esbuild/watch.ts", "pushwatch": "pnpm dev pushwork", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge-codemirror": "^0.2.0", @@ -49,7 +51,11 @@ "esbuild": "^0.23.1", "eslint": "^9.36.0", "globals": "^16.4.0", + "happy-dom": "^15.11.7", "typescript": "~5.9.3", - "typescript-eslint": "^8.45.0" + "typescript-eslint": "^8.45.0", + "vite": "^7.1.9", + "vite-plugin-solid": "^2.11.10", + "vitest": "^3.2.4" } } diff --git a/codemirror-base/vitest.config.ts b/codemirror-base/vitest.config.ts new file mode 100644 index 00000000..715c53e5 --- /dev/null +++ b/codemirror-base/vitest.config.ts @@ -0,0 +1,14 @@ +import {defineConfig} from "vitest/config" +import solid from "vite-plugin-solid" + +export default defineConfig({ + plugins: [solid()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, + resolve: { + conditions: ["development", "browser"], + }, +}) diff --git a/codemirror-markdown/package.json b/codemirror-markdown/package.json index 564c75a2..7d9e1312 100644 --- a/codemirror-markdown/package.json +++ b/codemirror-markdown/package.json @@ -30,7 +30,9 @@ "build": "node esbuild/build.ts", "dev": "node esbuild/watch.ts", "pushwatch": "pnpm dev pushwork", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge": "^3.2.5", @@ -56,7 +58,9 @@ "esbuild": "^0.23.1", "eslint": "^9.36.0", "globals": "^16.4.0", + "happy-dom": "^15.11.7", "typescript": "~5.9.3", - "typescript-eslint": "^8.45.0" + "typescript-eslint": "^8.45.0", + "vitest": "^3.2.4" } } diff --git a/codemirror-markdown/vitest.config.ts b/codemirror-markdown/vitest.config.ts new file mode 100644 index 00000000..44198156 --- /dev/null +++ b/codemirror-markdown/vitest.config.ts @@ -0,0 +1,9 @@ +import {defineConfig} from "vitest/config" + +export default defineConfig({ + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, +}) diff --git a/commands/package.json b/commands/package.json index 5eda98db..a16fafb5 100644 --- a/commands/package.json +++ b/commands/package.json @@ -14,7 +14,9 @@ "build": "node esbuild/build.ts", "dev": "node esbuild/watch.ts", "pushwatch": "pnpm dev pushwork", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@inkandswitch/patchwork-bootloader": "^0.0.4", @@ -23,6 +25,8 @@ }, "devDependencies": { "@automerge/automerge-repo": "^2.6.0-subduction.9", - "esbuild": "^0.23.1" + "esbuild": "^0.23.1", + "happy-dom": "^15.11.7", + "vitest": "^3.2.4" } } diff --git a/commands/vitest.config.ts b/commands/vitest.config.ts new file mode 100644 index 00000000..44198156 --- /dev/null +++ b/commands/vitest.config.ts @@ -0,0 +1,9 @@ +import {defineConfig} from "vitest/config" + +export default defineConfig({ + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, +}) diff --git a/comments-view/package.json b/comments-view/package.json index 06b7ead7..c10baaf0 100644 --- a/comments-view/package.json +++ b/comments-view/package.json @@ -8,7 +8,9 @@ "dev": "vite build --watch", "build": "vite build", "sync": "vite build && pushwork sync", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge": "3.3.0-fragments.1", @@ -27,9 +29,11 @@ "@typescript-eslint/parser": "^8.40.0", "eslint": "^9.34.0", "globals": "^16.4.0", + "happy-dom": "^15.11.7", "typescript-eslint": "^8.41.0", "vite": "^7.1.9", "vite-plugin-css-injected-by-js": "^3.5.2", - "vite-plugin-solid": "^2.11.10" + "vite-plugin-solid": "^2.11.10", + "vitest": "^3.2.4" } } diff --git a/comments-view/vitest.config.ts b/comments-view/vitest.config.ts new file mode 100644 index 00000000..715c53e5 --- /dev/null +++ b/comments-view/vitest.config.ts @@ -0,0 +1,14 @@ +import {defineConfig} from "vitest/config" +import solid from "vite-plugin-solid" + +export default defineConfig({ + plugins: [solid()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, + resolve: { + conditions: ["development", "browser"], + }, +}) diff --git a/contact/package.json b/contact/package.json index 4a12948b..237d709e 100644 --- a/contact/package.json +++ b/contact/package.json @@ -16,7 +16,9 @@ "build": "node esbuild/build.ts", "dev": "node esbuild/watch.ts", "pushwatch": "pnpm dev pushwork", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "keywords": [], "author": "Ink & Switch", @@ -29,7 +31,7 @@ "@inkandswitch/patchwork-providers": "^0.2.1", "@inkandswitch/patchwork-providers-react": "^0.2.1", "@radix-ui/react-avatar": "^1.1.10", -"lucide-react": "^0.469.0", + "lucide-react": "^0.469.0", "react": "^18.0.0", "react-dom": "^18.0.0" }, @@ -41,6 +43,9 @@ "@vitejs/plugin-react": "^4.5.1", "esbuild": "^0.23.1", "eslint-plugin-react-hooks": "^4.6.2", - "typescript": "^5.8.3" + "happy-dom": "^15.11.7", + "typescript": "^5.8.3", + "vite": "^7.1.9", + "vitest": "^3.2.4" } } diff --git a/contact/vitest.config.ts b/contact/vitest.config.ts new file mode 100644 index 00000000..1dd6c6a6 --- /dev/null +++ b/contact/vitest.config.ts @@ -0,0 +1,11 @@ +import {defineConfig} from "vitest/config" +import react from "@vitejs/plugin-react" + +export default defineConfig({ + plugins: [react()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, +}) diff --git a/doc-openwith/package.json b/doc-openwith/package.json index 9633edb6..4671ba8f 100644 --- a/doc-openwith/package.json +++ b/doc-openwith/package.json @@ -1,5 +1,13 @@ { "name": "document open with", "type": "module", - "main": "doc-openwith.js" + "main": "doc-openwith.js", + "devDependencies": { + "happy-dom": "^15.11.7", + "vitest": "^3.2.4" + }, + "scripts": { + "test": "vitest run", + "test:watch": "vitest" + } } diff --git a/doc-openwith/vitest.config.ts b/doc-openwith/vitest.config.ts new file mode 100644 index 00000000..44198156 --- /dev/null +++ b/doc-openwith/vitest.config.ts @@ -0,0 +1,9 @@ +import {defineConfig} from "vitest/config" + +export default defineConfig({ + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, +}) diff --git a/doc-presence/package.json b/doc-presence/package.json index 81e9e3c8..09ed84ec 100644 --- a/doc-presence/package.json +++ b/doc-presence/package.json @@ -1,5 +1,13 @@ { "name": "document presence", "type": "module", - "main": "doc-presence.js" + "main": "doc-presence.js", + "devDependencies": { + "happy-dom": "^15.11.7", + "vitest": "^3.2.4" + }, + "scripts": { + "test": "vitest run", + "test:watch": "vitest" + } } diff --git a/doc-presence/vitest.config.ts b/doc-presence/vitest.config.ts new file mode 100644 index 00000000..44198156 --- /dev/null +++ b/doc-presence/vitest.config.ts @@ -0,0 +1,9 @@ +import {defineConfig} from "vitest/config" + +export default defineConfig({ + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, +}) diff --git a/doc-title/package.json b/doc-title/package.json index 09464d8c..9a1a93b3 100644 --- a/doc-title/package.json +++ b/doc-title/package.json @@ -7,7 +7,9 @@ "dev": "vite build --watch", "build": "vite build", "sync": "vite build && pushwork sync", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge": "^3.2.5", @@ -23,8 +25,10 @@ "@typescript-eslint/parser": "^8.40.0", "eslint": "^9.34.0", "globals": "^16.4.0", + "happy-dom": "^15.11.7", "typescript-eslint": "^8.41.0", "vite": "^7.1.9", - "vite-plugin-css-injected-by-js": "^3.5.2" + "vite-plugin-css-injected-by-js": "^3.5.2", + "vitest": "^3.2.4" } } diff --git a/doc-title/vitest.config.ts b/doc-title/vitest.config.ts new file mode 100644 index 00000000..44198156 --- /dev/null +++ b/doc-title/vitest.config.ts @@ -0,0 +1,9 @@ +import {defineConfig} from "vitest/config" + +export default defineConfig({ + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, +}) diff --git a/drafts/package.json b/drafts/package.json index e392c66d..6377b99b 100644 --- a/drafts/package.json +++ b/drafts/package.json @@ -8,7 +8,9 @@ "dev": "vite build --watch", "build": "vite build", "sync": "vite build && pushwork sync", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge": "3.3.0-fragments.1", @@ -26,9 +28,11 @@ "@typescript-eslint/parser": "^8.40.0", "eslint": "^9.34.0", "globals": "^16.4.0", + "happy-dom": "^15.11.7", "typescript-eslint": "^8.41.0", "vite": "^7.1.9", "vite-plugin-css-injected-by-js": "^3.5.2", - "vite-plugin-solid": "^2.11.10" + "vite-plugin-solid": "^2.11.10", + "vitest": "^3.2.4" } } diff --git a/drafts/vitest.config.ts b/drafts/vitest.config.ts new file mode 100644 index 00000000..715c53e5 --- /dev/null +++ b/drafts/vitest.config.ts @@ -0,0 +1,14 @@ +import {defineConfig} from "vitest/config" +import solid from "vite-plugin-solid" + +export default defineConfig({ + plugins: [solid()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, + resolve: { + conditions: ["development", "browser"], + }, +}) diff --git a/file/package.json b/file/package.json index af47917e..895fd3a5 100644 --- a/file/package.json +++ b/file/package.json @@ -18,7 +18,9 @@ "build": "vite build", "dev": "vite build --watch", "push": "pnpm build && pushwork sync", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "keywords": [], "author": "Ink & Switch", @@ -54,8 +56,10 @@ }, "devDependencies": { "@inkandswitch/patchwork-bootloader": "^0.0.4", + "happy-dom": "^15.11.7", "typescript": "^5.8.3", "vite": "^5.4.19", - "vite-plugin-solid": "^2.10.0" + "vite-plugin-solid": "^2.10.0", + "vitest": "^3.2.4" } } diff --git a/file/vitest.config.ts b/file/vitest.config.ts new file mode 100644 index 00000000..715c53e5 --- /dev/null +++ b/file/vitest.config.ts @@ -0,0 +1,14 @@ +import {defineConfig} from "vitest/config" +import solid from "vite-plugin-solid" + +export default defineConfig({ + plugins: [solid()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, + resolve: { + conditions: ["development", "browser"], + }, +}) diff --git a/folder/package.json b/folder/package.json index a6fee2c7..9ffab513 100644 --- a/folder/package.json +++ b/folder/package.json @@ -15,7 +15,9 @@ "dev": "node esbuild/watch.ts", "pushwatch": "pnpm dev pushwork", "sync": "pnpm build && npx pushwork sync", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "keywords": [], "author": "Ink & Switch", @@ -27,6 +29,8 @@ }, "devDependencies": { "@automerge/automerge-repo": "^2.6.0-subduction.9", - "esbuild": "^0.23.1" + "esbuild": "^0.23.1", + "happy-dom": "^15.11.7", + "vitest": "^3.2.4" } } diff --git a/folder/vitest.config.ts b/folder/vitest.config.ts new file mode 100644 index 00000000..44198156 --- /dev/null +++ b/folder/vitest.config.ts @@ -0,0 +1,9 @@ +import {defineConfig} from "vitest/config" + +export default defineConfig({ + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, +}) diff --git a/frame-configurator/package.json b/frame-configurator/package.json index a91589f0..1676d49a 100644 --- a/frame-configurator/package.json +++ b/frame-configurator/package.json @@ -8,7 +8,9 @@ "watch": "vite --port 4444", "build": "vite build", "sync": "vite build && pushwork sync", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge": "^3.2.5", @@ -26,9 +28,11 @@ "babel-preset-solid": "^1.9.9", "eslint": "^9.34.0", "globals": "^16.4.0", + "happy-dom": "^15.11.7", "typescript-eslint": "^8.41.0", "vite": "^7.1.9", "vite-plugin-css-injected-by-js": "^3.5.2", - "vite-plugin-solid": "^2.11.10" + "vite-plugin-solid": "^2.11.10", + "vitest": "^3.2.4" } } diff --git a/frame-configurator/src/FrameConfigurator.tsx b/frame-configurator/src/FrameConfigurator.tsx index 2fe9e5f9..03781ab4 100644 --- a/frame-configurator/src/FrameConfigurator.tsx +++ b/frame-configurator/src/FrameConfigurator.tsx @@ -16,7 +16,11 @@ import { } from "solid-js"; import { createStore, reconcile } from "solid-js/store"; import { render } from "solid-js/web"; -import type { TinyPatchworkLayoutDoc } from "./types"; +import type { + TinyPatchworkLayoutDoc, + ThreepaneConfigDoc, + ToolRef, +} from "./types"; type ModuleOption = { id: string; @@ -465,14 +469,18 @@ function FrameConfiguratorUI(props: { () => props.handle.url ); + // The doctitle + contextbar config now live in the threepane config doc; we + // edit it here. Entries are [toolId, docId] pairs — the docid is the account + // doc (a placeholder; the frame feeds doctitle the selected doc). + const [threepaneDoc, threepaneHandle] = useDocument( + () => accountDoc()?.tools?.["threepane"] + ); + const allTools = useToolDescriptions(); const frameOptions = createMemo(() => filterToolsByTag([...allTools], "frame-tool") ); - const sidebarOptions = createMemo(() => - filterToolsByTag([...allTools], "sidebar-account") - ); const documentToolbarOptions = createMemo(() => filterToolsByTag([...allTools], "titlebar-tool") ); @@ -482,6 +490,22 @@ function FrameConfiguratorUI(props: { const docUrl = props.handle.url; + const doctitleIds = () => + threepaneDoc()?.doctitle?.tools?.map((ref) => ref[0]); + const contextIds = () => threepaneDoc()?.contextbar?.tabs?.map((ref) => ref[0]); + + const toPairs = (ids: string[]): ToolRef[] => + ids.map((id) => [id, docUrl]); + + const setDoctitle = (next: string[]) => + threepaneHandle()?.change((doc) => { + doc.doctitle.tools = toPairs(next); + }); + const setContext = (next: string[]) => + threepaneHandle()?.change((doc) => { + doc.contextbar.tabs = toPairs(next); + }); + const setField = ( key: K, value: TinyPatchworkLayoutDoc[K] @@ -491,16 +515,6 @@ function FrameConfiguratorUI(props: { }); }; - const setArrayField = ( - key: keyof TinyPatchworkLayoutDoc, - next: string[] - ) => { - props.handle.change((doc: any) => { - const arr = doc[key]; - arr.splice(0, arr.length, ...next); - }); - }; - return ( - setField("accountSidebarToolId", v as any)} - options={sidebarOptions()} - docUrl={docUrl} - /> - - setArrayField("documentToolbarToolIds", next)} - allOptions={documentToolbarOptions()} - docUrl={docUrl} - /> - - setArrayField("contextToolIds", next)} - allOptions={contextToolOptions()} - /> + Preparing layout configuration…

+ } + > + + + +
diff --git a/frame-configurator/src/types.ts b/frame-configurator/src/types.ts index fc8990de..d246dbf7 100644 --- a/frame-configurator/src/types.ts +++ b/frame-configurator/src/types.ts @@ -5,7 +5,18 @@ export type TinyPatchworkLayoutDoc = { moduleSettingsUrl: AutomergeUrl; frameToolId: string; - accountSidebarToolId: string; - contextToolIds: string[]; - documentToolbarToolIds: string[]; + /** @deprecated legacy fields, migrated into the threepane config doc */ + accountSidebarToolId?: string; + contextToolIds?: string[]; + documentToolbarToolIds?: string[]; + + tools?: Record; +}; + +export type ToolRef = [toolId: string, docId: AutomergeUrl]; + +export type ThreepaneConfigDoc = { + sidebar: { widgets: ToolRef[] }; + contextbar: { tabs: ToolRef[] }; + doctitle: { tools: ToolRef[] }; }; diff --git a/frame-configurator/vitest.config.ts b/frame-configurator/vitest.config.ts new file mode 100644 index 00000000..715c53e5 --- /dev/null +++ b/frame-configurator/vitest.config.ts @@ -0,0 +1,14 @@ +import {defineConfig} from "vitest/config" +import solid from "vite-plugin-solid" + +export default defineConfig({ + plugins: [solid()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, + resolve: { + conditions: ["development", "browser"], + }, +}) diff --git a/history-view/package.json b/history-view/package.json index 5a1f8728..8ed682a7 100644 --- a/history-view/package.json +++ b/history-view/package.json @@ -7,7 +7,9 @@ "dev": "vite build --watch", "build": "vite build", "sync": "vite build && pushwork sync", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@automerge/automerge": "3.3.0-fragments.1", @@ -27,10 +29,12 @@ "@typescript-eslint/parser": "^8.40.0", "eslint": "^9.34.0", "globals": "^16.4.0", + "happy-dom": "^15.11.7", "solid-js": "^1.9.10", "typescript-eslint": "^8.41.0", "vite": "^7.1.9", "vite-plugin-css-injected-by-js": "^3.5.2", - "vite-plugin-solid": "^2.11.10" + "vite-plugin-solid": "^2.11.10", + "vitest": "^3.2.4" } } diff --git a/history-view/vitest.config.ts b/history-view/vitest.config.ts new file mode 100644 index 00000000..715c53e5 --- /dev/null +++ b/history-view/vitest.config.ts @@ -0,0 +1,14 @@ +import {defineConfig} from "vitest/config" +import solid from "vite-plugin-solid" + +export default defineConfig({ + plugins: [solid()], + test: { + environment: "happy-dom", + globals: true, + passWithNoTests: true, + }, + resolve: { + conditions: ["development", "browser"], + }, +}) diff --git a/module-settings-manager/package.json b/module-settings-manager/package.json index f11098d0..88934d24 100644 --- a/module-settings-manager/package.json +++ b/module-settings-manager/package.json @@ -23,7 +23,9 @@ "build": "node esbuild/build.ts", "dev": "node esbuild/watch.ts", "pushwatch": "pnpm dev pushwork", - "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"" + "register": "pw-modules add \"$MODULE_SETTINGS_DOC_URL\" \"$(pushwork url)\"", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@inkandswitch/patchwork-bootloader": "^0.0.8", @@ -39,7 +41,11 @@ "@inkandswitch/patchwork-plugins": "^0.0.6", "babel-preset-solid": "^1.9.9", "esbuild": "^0.23.1", + "happy-dom": "^15.11.7", "solid-js": "^1.9.10", - "typescript": "~5.9.3" + "typescript": "~5.9.3", + "vite": "^7.1.9", + "vite-plugin-solid": "^2.11.10", + "vitest": "^3.2.4" } } diff --git a/module-settings-manager/src/module-settings/components/ModuleControls.tsx b/module-settings-manager/src/module-settings/components/ModuleControls.tsx index 86ae46d2..cb6bd175 100644 --- a/module-settings-manager/src/module-settings/components/ModuleControls.tsx +++ b/module-settings-manager/src/module-settings/components/ModuleControls.tsx @@ -17,9 +17,12 @@ import { import { DEFAULT_BRANCH, chosenBranchFor, + chosenPinFor, getModuleEntryKind, + publishVersions, type BranchesDoc, type ModuleSettingsDocWithBranches, + type UrlHeads, } from "../utils/module-types.ts"; import { unregisterPlugins } from "@inkandswitch/patchwork-plugins"; import { @@ -75,6 +78,12 @@ export function ModuleControls(props: ModuleControlsProps) { /> + ; + userSettingsHandle?: DocHandle; +} + +/** + * Pin a folder module to a frozen previous version. Pins are written into the + * user's own settings doc (like branch choices) under `pinned`, keyed by the + * folder URL. The watcher then loads that exact, already-cached version instead + * of the latest, and stops hot-reloading it until unpinned. + */ +function VersionControls(props: VersionControlsProps) { + // Write pins to the user's own settings doc so they're user-local. + const targetHandle = () => props.userSettingsHandle ?? props.settingsHandle; + const targetDoc = createMemo(() => makeDocumentProjection(targetHandle())); + + const [folderHandle] = createResource( + () => props.folderUrl, + (url) => props.repo.find<{ lastSyncAt?: number }>(url) + ); + + const versions = createMemo(() => { + const handle = folderHandle(); + return handle ? publishVersions(handle) : []; + }); + + const currentPin = createMemo(() => + chosenPinFor([targetDoc()], props.folderUrl) + ); + + const isPinned = createMemo(() => !!currentPin()); + + const sameHeads = (a: UrlHeads | undefined, b: UrlHeads | undefined) => + !!a && !!b && a.length === b.length && a.every((h, i) => h === b[i]); + + // The