diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 0000000..ee6160a --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,38 @@ +name: PR Lint + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + pull-requests: read + +jobs: + conventional-commits: + name: Conventional commit title + runs-on: ubuntu-latest + steps: + - name: Validate PR title follows Conventional Commits + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + # Conventional Commits pattern: type(scope)!: description + # Types: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert + PATTERN='^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(.+\))?!?: .{3,}' + if echo "$PR_TITLE" | grep -qE "$PATTERN"; then + echo "✅ PR title follows Conventional Commits format: $PR_TITLE" + else + echo "❌ PR title does not follow Conventional Commits format." + echo "" + echo "Expected format: type(scope): description" + echo "Examples:" + echo " feat(storage): add blob compression" + echo " fix(sync): handle disconnected peers gracefully" + echo " docs: update CONTRIBUTING guide" + echo " chore(deps): bump @plures/design-dojo to 0.10.6" + echo "" + echo "Valid types: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert" + echo "" + echo "Got: $PR_TITLE" + exit 1 + fi diff --git a/web/svelte/package-lock.json b/web/svelte/package-lock.json index 555892a..6bf2aab 100644 --- a/web/svelte/package-lock.json +++ b/web/svelte/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "dependencies": { "@monaco-editor/loader": "^1.5.0", + "@plures/design-dojo": "^0.10.6", "cytoscape": "^3.29.3", "cytoscape-cola": "^2.5.1", "cytoscape-cose-bilkent": "^4.1.0", @@ -561,7 +562,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -572,7 +572,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -583,7 +582,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -593,14 +591,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -662,6 +658,20 @@ "state-local": "^1.0.6" } }, + "node_modules/@plures/design-dojo": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/@plures/design-dojo/-/design-dojo-0.10.6.tgz", + "integrity": "sha512-hGNgrKwAwbQsP5WeVC5faR/hF/5mTBxp0+9TSJAAxrLlaakMGeIig2k9WMDe6XIjzGUr4CHZ9njo5Sxb5XK/pQ==", + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "svelte": "^5.0.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", @@ -1016,7 +1026,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.6.tgz", "integrity": "sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==", - "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^8.9.0" @@ -1065,21 +1074,18 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, "license": "MIT" }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "dev": true, "license": "MIT" }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1109,7 +1115,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -1119,7 +1124,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">= 0.4" @@ -1129,7 +1133,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -1281,7 +1284,6 @@ "version": "5.6.3", "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz", "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==", - "dev": true, "license": "MIT" }, "node_modules/esbuild": { @@ -1330,14 +1332,12 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "dev": true, "license": "MIT" }, "node_modules/esrap": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.3.tgz", "integrity": "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -1413,7 +1413,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.6" @@ -1436,7 +1435,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", - "dev": true, "license": "MIT" }, "node_modules/lodash": { @@ -1449,7 +1447,6 @@ "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -1618,7 +1615,6 @@ "version": "5.53.5", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.5.tgz", "integrity": "sha512-YkqERnF05g8KLdDZwZrF8/i1eSbj6Eoat8Jjr2IfruZz9StLuBqo8sfCSzjosNKd+ZrQ8DkKZDjpO5y3ht1Pow==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", @@ -1777,7 +1773,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", - "dev": true, "license": "MIT" } } diff --git a/web/svelte/package.json b/web/svelte/package.json index 59884af..b98aec1 100644 --- a/web/svelte/package.json +++ b/web/svelte/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@monaco-editor/loader": "^1.5.0", + "@plures/design-dojo": "^0.10.6", "cytoscape": "^3.29.3", "cytoscape-cola": "^2.5.1", "cytoscape-cose-bilkent": "^4.1.0", diff --git a/web/svelte/src/App.svelte b/web/svelte/src/App.svelte index e9dab0a..2bb8157 100644 --- a/web/svelte/src/App.svelte +++ b/web/svelte/src/App.svelte @@ -1,6 +1,9 @@ - - - - + + {#snippet children()} + + {/snippet} + -
- + + {#snippet children({ activeTab })} + {#if activeTab === "data"} + (sidebarCollapsed = c)} + > + {#snippet children()} + + {/snippet} + {#snippet main()} +
+ + +
+ {/snippet} +
+ {:else} +
+ {#if activeTab === "types"} + + {:else if activeTab === "history"} + + {:else if activeTab === "crdt"} + + {:else if activeTab === "import"} + + {:else if activeTab === "graph"} + + {:else if activeTab === "vector"} + + {:else if activeTab === "faceted"} + + {:else if activeTab === "notebooks"} + + {:else if activeTab === "queries"} + + {:else if activeTab === "rules"} + + {:else if activeTab === "tasks"} + + {:else if activeTab === "mesh"} + + {:else if activeTab === "storage"} + + {:else if activeTab === "profiling"} + + {:else if activeTab === "security"} + + {:else if activeTab === "packaging"} + + {:else if activeTab === "billing"} + + {:else if activeTab === "sqlite"} + + {:else if activeTab === "p2p"} + + {:else if activeTab === "identity"} + + {:else if activeTab === "sharing"} + + {:else if activeTab === "sync"} + + {:else if activeTab === "settings"} + + {/if} +
+ {/if} + {/snippet} +
- {#if activeView === "data"} -
-
- -
-
- - -
-
- {:else if activeView === "types"} -
- -
- {:else if activeView === "history"} -
- -
- {:else if activeView === "crdt"} -
- -
- {:else if activeView === "import"} -
- -
- {:else if activeView === "graph"} -
- -
- {:else if activeView === "vector"} -
- -
- {:else if activeView === "faceted"} -
- -
- {:else if activeView === "notebooks"} -
- -
- {:else if activeView === "queries"} -
- -
- {:else if activeView === "rules"} -
- -
- {:else if activeView === "tasks"} -
- -
- {:else if activeView === "mesh"} -
- -
- {:else if activeView === "storage"} -
- -
- {:else if activeView === "profiling"} -
- -
- {:else if activeView === "security"} -
- -
- {:else if activeView === "packaging"} -
- -
- {:else if activeView === "billing"} -
- -
- {:else if activeView === "sqlite"} -
- -
- {:else if activeView === "p2p"} -
- -
- {:else if activeView === "identity"} -
- -
- {:else if activeView === "sharing"} -
- -
- {:else if activeView === "sync"} -
- -
- {:else if activeView === "settings"} -
- -
- {/if} + + {#snippet children()} + + {#if db.selectedId} + + {/if} + + + {/snippet} + - - -
+ + diff --git a/web/svelte/src/components/GraphView.svelte b/web/svelte/src/components/GraphView.svelte index d9a3a0a..17ee7f3 100644 --- a/web/svelte/src/components/GraphView.svelte +++ b/web/svelte/src/components/GraphView.svelte @@ -1,6 +1,6 @@ @@ -41,8 +45,8 @@ @@ -53,8 +57,8 @@ @@ -63,8 +67,8 @@ @@ -73,7 +77,7 @@ diff --git a/web/svelte/src/components/VirtualList.svelte b/web/svelte/src/components/VirtualList.svelte index b8dfa85..bce426a 100644 --- a/web/svelte/src/components/VirtualList.svelte +++ b/web/svelte/src/components/VirtualList.svelte @@ -1,24 +1,31 @@ -
+
- + {#if children} + {@render children({ visible, startIndex })} + {/if}
@@ -26,7 +33,7 @@ diff --git a/web/svelte/src/lib/state.svelte.ts b/web/svelte/src/lib/state.svelte.ts new file mode 100644 index 0000000..c25b0ec --- /dev/null +++ b/web/svelte/src/lib/state.svelte.ts @@ -0,0 +1,40 @@ +/** Svelte 5 runes-based shared application state. Replaces legacy writable/derived stores. */ + +export type NodeItem = { id: string; data: Record }; + +export type AppSettings = { + kvPath?: string; + port?: number; + apiPortOffset?: number; + peers?: string[]; + dark?: boolean; +}; + +class DbState { + nodes = $state>({}); + selectedId = $state(null); + settings = $state({}); + + readonly selected = $derived.by((): NodeItem | null => + this.selectedId ? (this.nodes[this.selectedId] ?? null) : null, + ); + + upsertNode(item: NodeItem): void { + this.nodes = { ...this.nodes, [item.id]: item }; + } + + removeNode(id: string): void { + const copy = { ...this.nodes }; + delete copy[id]; + this.nodes = copy; + } + + setAll(items: NodeItem[]): void { + const map: Record = {}; + for (const it of items) map[it.id] = it; + this.nodes = map; + } +} + +/** Singleton reactive state for the entire PluresDB UI. */ +export const db = new DbState(); diff --git a/web/svelte/vite.config.ts b/web/svelte/vite.config.ts index 8685257..cd5a5af 100644 --- a/web/svelte/vite.config.ts +++ b/web/svelte/vite.config.ts @@ -6,5 +6,8 @@ export default defineConfig({ build: { outDir: "../dist", emptyOutDir: true, + rollupOptions: { + external: ["@tauri-apps/api/window"], + }, }, });