diff --git a/new-web/package-lock.json b/new-web/package-lock.json index f99311c2..b8b92c26 100644 --- a/new-web/package-lock.json +++ b/new-web/package-lock.json @@ -8,14 +8,24 @@ "name": "new-web", "version": "0.0.1", "dependencies": { + "@battlefieldduck/xterm-svelte": "^2.1.0", "@fontsource/noto-sans": "^5.2.7", "@layerstack/svelte-stores": "^1.0.2", + "@lucide/svelte": "^0.516.0", + "@svelte-put/shortcut": "^4.1.0", + "@sveltestack/svelte-query": "^1.6.0", "adze": "^2.2.4", "axios": "^1.10.0", + "d3-shape": "^3.2.0", "date-fns": "^4.1.0", + "date-fns-tz": "^3.2.0", + "human-format": "^1.2.1", "is-cidr": "^5.1.1", "is-ip": "^5.0.1", + "layerchart": "^1.0.11", + "lucide-svelte": "^0.516.0", "svelte-i18n": "^4.0.1", + "tabulator-tables": "^6.3.1", "validator": "^13.15.15", "zod": "^3.25.67" }, @@ -23,19 +33,22 @@ "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", "@iconify/svelte": "^5.0.0", - "@lucide/svelte": "^0.516.0", + "@internationalized/date": "^3.8.2", "@sveltejs/adapter-static": "^3.0.8", "@sveltejs/kit": "^2.16.0", "@sveltejs/vite-plugin-svelte": "^5.0.0", "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", "@tailwindcss/vite": "^4.0.0", + "@types/tabulator-tables": "^6.2.6", + "bits-ui": "^2.8.0", "clsx": "^2.1.1", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^3.0.0", "globals": "^16.0.0", "mode-watcher": "^1.0.8", + "paneforge": "^1.0.0-next.5", "prettier": "^3.4.2", "prettier-plugin-svelte": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.11", @@ -51,6 +64,18 @@ "vite": "^6.2.6" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -64,6 +89,46 @@ "node": ">=6.0.0" } }, + "node_modules/@battlefieldduck/xterm-svelte": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@battlefieldduck/xterm-svelte/-/xterm-svelte-2.1.0.tgz", + "integrity": "sha512-OeuGnPqblPBc57WZ8TtcU2yX0MvMs7rMbhZaLethyD5i8/WqM/XJej0NOp0KcND8jNmPnBWjePwghAQDlDXnlw==", + "license": "MIT", + "dependencies": { + "@xterm/addon-attach": "^0.11.0", + "@xterm/addon-canvas": "^0.7.0", + "@xterm/addon-clipboard": "^0.1.0", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-image": "^0.8.0", + "@xterm/addon-search": "^0.15.0", + "@xterm/addon-serialize": "^0.13.0", + "@xterm/addon-unicode11": "^0.8.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/addon-webgl": "^0.18.0", + "@xterm/xterm": "^5.5.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@dagrejs/dagre": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@dagrejs/dagre/-/dagre-1.1.5.tgz", + "integrity": "sha512-Ghgrh08s12DCL5SeiR6AoyE80mQELTWhJBRmXfFoqDiFkR458vPEdgTbbjA0T+9ETNxUblnD0QW55tfdvi5pjQ==", + "license": "MIT", + "dependencies": { + "@dagrejs/graphlib": "2.2.4" + } + }, + "node_modules/@dagrejs/graphlib": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@dagrejs/graphlib/-/graphlib-2.2.4.tgz", + "integrity": "sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==", + "license": "MIT", + "engines": { + "node": ">17.0.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", @@ -674,6 +739,31 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.1.tgz", + "integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.1.tgz", + "integrity": "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.1", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, "node_modules/@fontsource/noto-sans": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@fontsource/noto-sans/-/noto-sans-5.2.7.tgz", @@ -823,6 +913,33 @@ "dev": true, "license": "MIT" }, + "node_modules/@internationalized/date": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.8.2.tgz", + "integrity": "sha512-/wENk7CbvLbkUvX1tu0mwq49CVkkWpkXubGel6birjRPyo6uQ4nQpnq5xZu823zRCwwn82zgHrvgF1vZyvmVgA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -884,6 +1001,20 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@layerstack/svelte-actions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@layerstack/svelte-actions/-/svelte-actions-1.0.1.tgz", + "integrity": "sha512-Tv8B3TeT7oaghx0R0I4avnSdfAT6GxEK+StL8k/hEaa009iNOIGFl3f76kfvNvPioQHAMFGtnWGLPHfsfD41nQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.13", + "@layerstack/utils": "1.0.1", + "d3-array": "^3.2.4", + "d3-scale": "^4.0.2", + "date-fns": "^4.1.0", + "lodash-es": "^4.17.21" + } + }, "node_modules/@layerstack/svelte-stores": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@layerstack/svelte-stores/-/svelte-stores-1.0.2.tgz", @@ -898,6 +1029,198 @@ "zod": "^3.24.2" } }, + "node_modules/@layerstack/tailwind": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@layerstack/tailwind/-/tailwind-1.0.1.tgz", + "integrity": "sha512-nlshEkUCfaV0zYzrFXVVYRnS8bnBjs4M7iui6l/tu6NeBBlxDivIyRraJkdYGCSL1lZHi6FqacLQ3eerHtz90A==", + "license": "MIT", + "dependencies": { + "@layerstack/utils": "^1.0.1", + "clsx": "^2.1.1", + "culori": "^4.0.1", + "d3-array": "^3.2.4", + "date-fns": "^4.1.0", + "lodash-es": "^4.17.21", + "tailwind-merge": "^2.5.4", + "tailwindcss": "^3.4.15" + } + }, + "node_modules/@layerstack/tailwind/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/@layerstack/tailwind/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@layerstack/tailwind/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/@layerstack/tailwind/node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/@layerstack/tailwind/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@layerstack/tailwind/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/@layerstack/tailwind/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@layerstack/tailwind/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/@layerstack/tailwind/node_modules/tailwind-merge": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/@layerstack/tailwind/node_modules/tailwindcss": { + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@layerstack/utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@layerstack/utils/-/utils-1.0.1.tgz", @@ -913,7 +1236,6 @@ "version": "0.516.0", "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-0.516.0.tgz", "integrity": "sha512-Ovkg2IgUeF85guSbnG9iPwUMMRuz+rdh8HsnKbD1uEY2Wv3d9qf0ERKFrz0ePZqmPXOedCPcf2a/rvRsqkaZcw==", - "dev": true, "license": "ISC", "peerDependencies": { "svelte": "^5" @@ -923,7 +1245,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -937,7 +1258,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -947,7 +1267,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -957,6 +1276,16 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", @@ -1244,6 +1573,15 @@ "win32" ] }, + "node_modules/@svelte-put/shortcut": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@svelte-put/shortcut/-/shortcut-4.1.0.tgz", + "integrity": "sha512-wImNEIkbxAIWFqlfuhcbC+jRPDeRa/uJGIXHMEVVD+jqL9xCwWNnkGQJ6Qb2XVszuRLHlb8SGZDL3Io/h3vs8w==", + "license": "MIT", + "peerDependencies": { + "svelte": "^5.1.0" + } + }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", @@ -1336,6 +1674,30 @@ "vite": "^6.0.0" } }, + "node_modules/@sveltestack/svelte-query": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sveltestack/svelte-query/-/svelte-query-1.6.0.tgz", + "integrity": "sha512-C0wWuh6av1zu3Pzwrg6EQmX3BhDZQ4gMAdYu6Tfv4bjbEZTB00uEDz52z92IZdONh+iUKuyo0xRZ2e16k2Xifg==", + "license": "MIT", + "peerDependencies": { + "broadcast-channel": "^4.5.0" + }, + "peerDependenciesMeta": { + "broadcast-channel": { + "optional": true + } + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@tailwindcss/forms": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz", @@ -1662,6 +2024,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/tabulator-tables": { + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/@types/tabulator-tables/-/tabulator-tables-6.2.6.tgz", + "integrity": "sha512-A+2VrqDluI6hNw5dQl1Z7b8pjQfAE62+3Kj0cFfenWzj0T0ewMicPrpPINHL7ASqz9u9FTDn1Mz1Ige2tF4Wlw==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.34.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz", @@ -1925,6 +2294,105 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "license": "ISC" }, + "node_modules/@xterm/addon-attach": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-attach/-/addon-attach-0.11.0.tgz", + "integrity": "sha512-JboCN0QAY6ZLY/SSB/Zl2cQ5zW1Eh4X3fH7BnuR1NB7xGRhzbqU2Npmpiw/3zFlxDaU88vtKzok44JKi2L2V2Q==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/addon-canvas": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-canvas/-/addon-canvas-0.7.0.tgz", + "integrity": "sha512-LF5LYcfvefJuJ7QotNRdRSPc9YASAVDeoT5uyXS/nZshZXjYplGXRECBGiznwvhNL2I8bq1Lf5MzRwstsYQ2Iw==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/addon-clipboard": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.1.0.tgz", + "integrity": "sha512-zdoM7p53T5sv/HbRTyp4hY0kKmEQ3MZvAvEtiXqNIHc/JdpqwByCtsTaQF5DX2n4hYdXRPO4P/eOS0QEhX1nPw==", + "license": "MIT", + "dependencies": { + "js-base64": "^3.7.5" + }, + "peerDependencies": { + "@xterm/xterm": "^5.4.0" + } + }, + "node_modules/@xterm/addon-fit": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz", + "integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/addon-image": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.8.0.tgz", + "integrity": "sha512-b/dqpFn3jUad2pUP5UpF4scPIh0WdxRQL/1qyiahGfUI85XZTCXo0py9G6AcOR2QYUw8eJ8EowGspT7BQcgw6A==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.2.0" + } + }, + "node_modules/@xterm/addon-search": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.15.0.tgz", + "integrity": "sha512-ZBZKLQ+EuKE83CqCmSSz5y1tx+aNOCUaA7dm6emgOX+8J9H1FWXZyrKfzjwzV+V14TV3xToz1goIeRhXBS5qjg==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/addon-serialize": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-serialize/-/addon-serialize-0.13.0.tgz", + "integrity": "sha512-kGs8o6LWAmN1l2NpMp01/YkpxbmO4UrfWybeGu79Khw5K9+Krp7XhXbBTOTc3GJRRhd6EmILjpR8k5+odY39YQ==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/addon-unicode11": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.8.0.tgz", + "integrity": "sha512-LxinXu8SC4OmVa6FhgwsVCBZbr8WoSGzBl2+vqe8WcQ6hb1r6Gj9P99qTNdPiFPh4Ceiu2pC8xukZ6+2nnh49Q==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/addon-web-links": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.11.0.tgz", + "integrity": "sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/addon-webgl": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.18.0.tgz", + "integrity": "sha512-xCnfMBTI+/HKPdRnSOHaJDRqEpq2Ugy8LEj9GiY4J3zJObo3joylIFaMvzBwbYRg8zLtkO0KQaStCeSfoaI2/w==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/xterm": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", + "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", + "license": "MIT" + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -1977,11 +2445,22 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1993,6 +2472,43 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2039,9 +2555,85 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bits-ui": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.8.0.tgz", + "integrity": "sha512-WiTZcCbYLm4Cx6/67NqXVSD0BkfNmdX8Abs84HpIaplX/wRRbg8tkMtJYlLw7mepgGvwGR3enLi6tFkcHU3JXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.0", + "@floating-ui/dom": "^1.7.0", + "css.escape": "^1.5.1", + "esm-env": "^1.1.2", + "runed": "^0.28.0", + "svelte-toolbelt": "^0.9.1", + "tabbable": "^6.2.0" + }, + "engines": { + "node": ">=20", + "pnpm": ">=8.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/huntabyte" + }, + "peerDependencies": { + "@internationalized/date": "^3.8.1", + "svelte": "^5.33.0" + } + }, + "node_modules/bits-ui/node_modules/runed": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.28.0.tgz", + "integrity": "sha512-k2xx7RuO9hWcdd9f+8JoBeqWtYrm5CALfgpkg2YDB80ds/QE4w0qqu34A7fqiAwiBBSBQOid7TLxwxVC27ymWQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "license": "MIT", + "dependencies": { + "esm-env": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^5.7.0" + } + }, + "node_modules/bits-ui/node_modules/svelte-toolbelt": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.9.1.tgz", + "integrity": "sha512-wBX6MtYw/kpht80j5zLpxJyR9soLizXPIAIWEVd9llAi17SR44ZdG291bldjB7r/K5duC0opDFcuhk2cA1hb8g==", + "dev": true, + "funding": [ + "https://github.com/sponsors/huntabyte" + ], + "dependencies": { + "clsx": "^2.1.1", + "runed": "^0.28.0", + "style-to-object": "^1.0.8" + }, + "engines": { + "node": ">=18", + "pnpm": ">=8.7.0" + }, + "peerDependencies": { + "svelte": "^5.30.2" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -2057,7 +2649,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -2089,6 +2680,15 @@ "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2188,7 +2788,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -2201,7 +2800,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/combined-stream": { @@ -2216,6 +2814,15 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2249,7 +2856,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -2260,11 +2866,17 @@ "node": ">= 8" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -2273,6 +2885,15 @@ "node": ">=4" } }, + "node_modules/culori": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/culori/-/culori-4.0.1.tgz", + "integrity": "sha512-LSnjA6HuIUOlkfKVbzi2OlToZE8OjFi667JWN9qNymXVXzGDmvuP60SSgC+e92sd7B7158f7Fy3Mb6rXS5EDPw==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/d": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", @@ -2298,6 +2919,298 @@ "node": ">=12" } }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo-voronoi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-geo-voronoi/-/d3-geo-voronoi-2.1.0.tgz", + "integrity": "sha512-kqE4yYuOjPbKdBXG0xztCacPwkVSK2REF1opSNrnqqtXJmNcM++UbwQ8SxvwP6IQTj9RvIjjK4qeiVsEfj0Z2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-delaunay": "6", + "d3-geo": "3", + "d3-tricontour": "1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate-path": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/d3-interpolate-path/-/d3-interpolate-path-2.3.0.tgz", + "integrity": "sha512-tZYtGXxBmbgHsIc9Wms6LS5u4w6KbP8C09a4/ZYc4KLMYYqub57rRBUgpUr2CIarIrJEpdAWWxWQvofgaMpbKQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-tile": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d3-tile/-/d3-tile-1.0.0.tgz", + "integrity": "sha512-79fnTKpPMPDS5xQ0xuS9ir0165NEwwkFpe/DSOmc2Gl9ldYzKKRDWogmTTE8wAJ8NA7PMapNfEcyKhI9Lxdu5Q==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-tricontour": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d3-tricontour/-/d3-tricontour-1.0.2.tgz", + "integrity": "sha512-HIRxHzHagPtUPNabjOlfcyismJYIsc+Xlq4mlsts4e8eAcwyq9Tgk/sYdyhlBpQ0MHwVquc/8j+e29YjXnmxeA==", + "license": "ISC", + "dependencies": { + "d3-delaunay": "6", + "d3-scale": "4" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/date-fns": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", @@ -2308,6 +3221,15 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/date-fns-tz": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.2.0.tgz", + "integrity": "sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==", + "license": "MIT", + "peerDependencies": { + "date-fns": "^3.0.0 || ^4.0.0" + } + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -2348,6 +3270,15 @@ "node": ">=0.10.0" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2374,6 +3305,18 @@ "dev": true, "license": "MIT" }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2388,6 +3331,18 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, "node_modules/enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -2824,7 +3779,6 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2841,7 +3795,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -2868,7 +3821,6 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -2906,7 +3858,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -2973,6 +3924,22 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", @@ -2993,7 +3960,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -3062,11 +4028,30 @@ "node": ">= 0.4" } }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -3075,6 +4060,30 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", @@ -3175,6 +4184,27 @@ "node": ">= 0.4" } }, + "node_modules/human-format": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/human-format/-/human-format-1.2.1.tgz", + "integrity": "sha512-o5Ldz62VWR5lYUZ8aVQaLKiN37NsHnmk3xjMoUjza3mGkk8MvMofgZT0T6HKSCKSJIir+AWk9Dx8KhxvZAUgCg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3262,6 +4292,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-cidr": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-5.1.1.tgz", @@ -3274,21 +4316,43 @@ "node": ">=14" } }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -3317,7 +4381,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -3354,9 +4417,23 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jiti": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", @@ -3367,6 +4444,12 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-base64": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", + "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==", + "license": "BSD-3-Clause" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3428,6 +4511,60 @@ "dev": true, "license": "MIT" }, + "node_modules/layercake": { + "version": "8.4.3", + "resolved": "https://registry.npmjs.org/layercake/-/layercake-8.4.3.tgz", + "integrity": "sha512-PZDduaPFxgHHkxlmsz5MVBECf6ZCT39DI3LgMVvuMwrmlrtlXwXUM/elJp46zHYzCE1j+cGyDuBDxnANv94tOQ==", + "license": "MIT", + "dependencies": { + "d3-array": "^3.2.4", + "d3-color": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0" + }, + "peerDependencies": { + "svelte": "3 - 5 || >=5.0.0-next.120", + "typescript": "^5.0.2" + } + }, + "node_modules/layerchart": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/layerchart/-/layerchart-1.0.11.tgz", + "integrity": "sha512-1Na3BO3a32x0X8PR3vCl7zwiD0NMp90deoxOJPrmIy+34INEPeyowv7NuJ0zfjNMA4BCDTYj/1xK4nnIIh8Nmw==", + "license": "MIT", + "dependencies": { + "@dagrejs/dagre": "^1.1.4", + "@layerstack/svelte-actions": "^1.0.1", + "@layerstack/svelte-stores": "^1.0.2", + "@layerstack/tailwind": "^1.0.1", + "@layerstack/utils": "^1.0.1", + "d3-array": "^3.2.4", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-dsv": "^3.0.1", + "d3-force": "^3.0.0", + "d3-geo": "^3.1.1", + "d3-geo-voronoi": "^2.1.0", + "d3-hierarchy": "^3.1.2", + "d3-interpolate": "^3.0.1", + "d3-interpolate-path": "^2.3.0", + "d3-path": "^3.1.0", + "d3-quadtree": "^3.0.1", + "d3-random": "^3.0.1", + "d3-sankey": "^0.12.3", + "d3-scale": "^4.0.2", + "d3-scale-chromatic": "^3.1.0", + "d3-shape": "^3.2.0", + "d3-tile": "^1.0.0", + "d3-time": "^3.1.0", + "date-fns": "^4.1.0", + "layercake": "^8.4.3", + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "svelte": "^3.56.0 || ^4.0.0 || ^5.0.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3691,6 +4828,12 @@ "node": ">=10" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", @@ -3740,6 +4883,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/lru-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", @@ -3749,6 +4898,15 @@ "es5-ext": "~0.10.2" } }, + "node_modules/lucide-svelte": { + "version": "0.516.0", + "resolved": "https://registry.npmjs.org/lucide-svelte/-/lucide-svelte-0.516.0.tgz", + "integrity": "sha512-8YmF3pke1owMbtdYWscJFN47dEqJ41oXz3hVRKnYjQbDXE9uYqkE9KnAME1268mBhsC97xTqMYh07/RYrojLKA==", + "license": "ISC", + "peerDependencies": { + "svelte": "^3 || ^4 || ^5.0.0-next.42" + } + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", @@ -3790,7 +4948,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -3800,7 +4957,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -3814,7 +4970,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -3871,7 +5026,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -3946,11 +5100,21 @@ "dev": true, "license": "MIT" }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -3978,6 +5142,33 @@ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "license": "ISC" }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -4028,6 +5219,42 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/paneforge": { + "version": "1.0.0-next.5", + "resolved": "https://registry.npmjs.org/paneforge/-/paneforge-1.0.0-next.5.tgz", + "integrity": "sha512-1ArDM+GMEO+o6pixEAFobhTkWkyxUDdHyw2bKruvQIXBStJmdRP7HoV4jNBZ/2i9UHDzmczxJzA3D2tKa91phw==", + "dev": true, + "license": "MIT", + "dependencies": { + "runed": "^0.23.4", + "svelte-toolbelt": "^0.7.1" + }, + "peerDependencies": { + "svelte": "^5.20.0" + } + }, + "node_modules/paneforge/node_modules/runed": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.23.4.tgz", + "integrity": "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "dependencies": { + "esm-env": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^5.7.0" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4055,12 +5282,33 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -4080,11 +5328,28 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4109,6 +5374,42 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, "node_modules/postcss-load-config": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", @@ -4149,6 +5450,44 @@ "node": ">= 6" } }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-safe-parser": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", @@ -4217,6 +5556,12 @@ "node": ">=4" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4353,7 +5698,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -4370,6 +5714,15 @@ ], "license": "MIT" }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -4384,6 +5737,26 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -4398,13 +5771,18 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { "version": "4.43.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz", @@ -4456,7 +5834,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -4492,6 +5869,12 @@ "svelte": "^5.7.0" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, "node_modules/sade": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", @@ -4504,6 +5887,12 @@ "node": ">=6" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -4528,7 +5917,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -4541,12 +5929,23 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/sirv": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", @@ -4566,12 +5965,107 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4595,6 +6089,37 @@ "inline-style-parser": "0.2.4" } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/super-regex": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-0.2.0.tgz", @@ -4625,6 +6150,18 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/svelte": { "version": "5.34.3", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.34.3.tgz", @@ -5214,6 +6751,19 @@ "svelte": "^5.7.0" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true, + "license": "MIT" + }, + "node_modules/tabulator-tables": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/tabulator-tables/-/tabulator-tables-6.3.1.tgz", + "integrity": "sha512-qFW7kfadtcaISQIibKAIy0f3eeIXUVi8242Vly1iJfMD79kfEGzfczNuPBN/80hDxHzQJXYbmJ8VipI40hQtfA==", + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", @@ -5288,6 +6838,27 @@ "node": ">=18" } }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/time-span": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", @@ -5347,7 +6918,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -5379,6 +6949,12 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -5418,7 +6994,6 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -5465,7 +7040,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, "license": "MIT" }, "node_modules/validator": { @@ -5575,7 +7149,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -5597,6 +7170,94 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -5611,10 +7272,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", - "dev": true, "license": "ISC", - "optional": true, - "peer": true, "bin": { "yaml": "bin.mjs" }, diff --git a/new-web/package.json b/new-web/package.json index db32ae21..9b08831e 100644 --- a/new-web/package.json +++ b/new-web/package.json @@ -17,19 +17,22 @@ "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", "@iconify/svelte": "^5.0.0", - "@lucide/svelte": "^0.516.0", + "@internationalized/date": "^3.8.2", "@sveltejs/adapter-static": "^3.0.8", "@sveltejs/kit": "^2.16.0", "@sveltejs/vite-plugin-svelte": "^5.0.0", "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", "@tailwindcss/vite": "^4.0.0", + "@types/tabulator-tables": "^6.2.6", + "bits-ui": "^2.8.0", "clsx": "^2.1.1", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^3.0.0", "globals": "^16.0.0", "mode-watcher": "^1.0.8", + "paneforge": "^1.0.0-next.5", "prettier": "^3.4.2", "prettier-plugin-svelte": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.11", @@ -45,14 +48,24 @@ "vite": "^6.2.6" }, "dependencies": { + "@battlefieldduck/xterm-svelte": "^2.1.0", "@fontsource/noto-sans": "^5.2.7", "@layerstack/svelte-stores": "^1.0.2", + "@lucide/svelte": "^0.516.0", + "@svelte-put/shortcut": "^4.1.0", + "@sveltestack/svelte-query": "^1.6.0", "adze": "^2.2.4", "axios": "^1.10.0", + "d3-shape": "^3.2.0", "date-fns": "^4.1.0", + "date-fns-tz": "^3.2.0", + "human-format": "^1.2.1", "is-cidr": "^5.1.1", "is-ip": "^5.0.1", + "layerchart": "^1.0.11", + "lucide-svelte": "^0.516.0", "svelte-i18n": "^4.0.1", + "tabulator-tables": "^6.3.1", "validator": "^13.15.15", "zod": "^3.25.67" } diff --git a/new-web/src/app.css b/new-web/src/app.css index e48f5f09..68f1002a 100644 --- a/new-web/src/app.css +++ b/new-web/src/app.css @@ -1,121 +1,125 @@ -@import "tailwindcss"; +@import 'tailwindcss'; -@import "tw-animate-css"; +@import 'tw-animate-css'; @custom-variant dark (&:is(.dark *)); :root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.129 0.042 264.695); - --card: oklch(1 0 0); - --card-foreground: oklch(0.129 0.042 264.695); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.129 0.042 264.695); - --primary: oklch(0.208 0.042 265.755); - --primary-foreground: oklch(0.984 0.003 247.858); - --secondary: oklch(0.968 0.007 247.896); - --secondary-foreground: oklch(0.208 0.042 265.755); - --muted: oklch(0.968 0.007 247.896); - --muted-foreground: oklch(0.554 0.046 257.417); - --accent: oklch(0.968 0.007 247.896); - --accent-foreground: oklch(0.208 0.042 265.755); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.929 0.013 255.508); - --input: oklch(0.929 0.013 255.508); - --ring: oklch(0.704 0.04 256.788); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.984 0.003 247.858); - --sidebar-foreground: oklch(0.129 0.042 264.695); - --sidebar-primary: oklch(0.208 0.042 265.755); - --sidebar-primary-foreground: oklch(0.984 0.003 247.858); - --sidebar-accent: oklch(0.968 0.007 247.896); - --sidebar-accent-foreground: oklch(0.208 0.042 265.755); - --sidebar-border: oklch(0.929 0.013 255.508); - --sidebar-ring: oklch(0.704 0.04 256.788); + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } .dark { - --background: oklch(0.129 0.042 264.695); - --foreground: oklch(0.984 0.003 247.858); - --card: oklch(0.208 0.042 265.755); - --card-foreground: oklch(0.984 0.003 247.858); - --popover: oklch(0.208 0.042 265.755); - --popover-foreground: oklch(0.984 0.003 247.858); - --primary: oklch(0.929 0.013 255.508); - --primary-foreground: oklch(0.208 0.042 265.755); - --secondary: oklch(0.279 0.041 260.031); - --secondary-foreground: oklch(0.984 0.003 247.858); - --muted: oklch(0.279 0.041 260.031); - --muted-foreground: oklch(0.704 0.04 256.788); - --accent: oklch(0.279 0.041 260.031); - --accent-foreground: oklch(0.984 0.003 247.858); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.551 0.027 264.364); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.208 0.042 265.755); - --sidebar-foreground: oklch(0.984 0.003 247.858); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.984 0.003 247.858); - --sidebar-accent: oklch(0.279 0.041 260.031); - --sidebar-accent-foreground: oklch(0.984 0.003 247.858); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.551 0.027 264.364); + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); } @theme inline { - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); - --color-background: var(--background); - --color-foreground: var(--foreground); - --color-card: var(--card); - --color-card-foreground: var(--card-foreground); - --color-popover: var(--popover); - --color-popover-foreground: var(--popover-foreground); - --color-primary: var(--primary); - --color-primary-foreground: var(--primary-foreground); - --color-secondary: var(--secondary); - --color-secondary-foreground: var(--secondary-foreground); - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); - --color-accent: var(--accent); - --color-accent-foreground: var(--accent-foreground); - --color-destructive: var(--destructive); - --color-border: var(--border); - --color-input: var(--input); - --color-ring: var(--ring); - --color-chart-1: var(--chart-1); - --color-chart-2: var(--chart-2); - --color-chart-3: var(--chart-3); - --color-chart-4: var(--chart-4); - --color-chart-5: var(--chart-5); - --color-sidebar: var(--sidebar); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-ring: var(--sidebar-ring); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); } @layer base { - * { - @apply border-border outline-ring/50; - } - body { - @apply bg-background text-foreground; - } -} \ No newline at end of file + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} + +@layer components { + @import './css/tabulator_simple.scss'; +} diff --git a/new-web/src/app.html b/new-web/src/app.html index 77a5ff52..2f615ff9 100644 --- a/new-web/src/app.html +++ b/new-web/src/app.html @@ -3,6 +3,7 @@ + %sveltekit.head% diff --git a/new-web/src/css/tabulator.scss b/new-web/src/css/tabulator.scss new file mode 100644 index 00000000..e9edcafa --- /dev/null +++ b/new-web/src/css/tabulator.scss @@ -0,0 +1,1657 @@ +@use 'sass:color'; + +//Main Theme Variables +$backgroundColor: #888 !default; //background color of tabulator +$borderColor: #999 !default; //border to tabulator +$textSize: 14px !default; //table text size + +//header theming +$headerBackgroundColor: #e6e6e6 !default; //border to tabulator +$headerTextColor: #555 !default; //header text color +$headerBorderColor: #aaa !default; //header border color +$headerSeparatorColor: #999 !default; //header bottom separator color +$headerMargin: 4px !default; //padding round header.io +//column header arrows +$sortArrowHover: #555 !default; +$sortArrowActive: #666 !default; +$sortArrowInactive: #bbb !default; + +$columnResizeGuideColor: #999 !default; + +//row theming +$rowBackgroundColor: #fff !default; //table row background color +$rowAltBackgroundColor: #efefef !default; //table row background color +$rowBorderColor: #aaa !default; //table border color +$rowTextColor: #333 !default; //table text color +$rowHoverBackground: #bbb !default; //row background color on hover + +$rowSelectedBackground: #9abcea !default; //row background color when selected +$rowSelectedBackgroundHover: #769bcc !default; //row background color when selected and hovered + +$editBoxColor: #1d68cd !default; //border color for edit boxes +$errorColor: #dd0000 !default; //error indication + +//footer theming +$footerBackgroundColor: #e6e6e6 !default; //border to tabulator +$footerTextColor: #555 !default; //footer text color +$footerBorderColor: #aaa !default; //footer border color +$footerSeparatorColor: #999 !default; //footer bottom separator color +$footerActiveColor: #d00 !default; //footer bottom active text color + +$spreadsheetActiveTabColor: #fff !default; //color for the active spreadsheet tab + +//range selection +$rangeBorderColor: #2975dd !default; //range border color +$rangeHandleColor: $rangeBorderColor !default; //range handle color +$rangeHeaderSelectedBackground: #3876ca !default; //header background color when selected +$rangeHeaderSelectedTextColor: #ffffff !default; //header text color when selected +$rangeHeaderHighlightBackground: #d6d6d6 !default; //header background color when highlighted +$rangeHeaderTextHighlightBackground: #000000 !default; //header text color when highlighted + +//Tabulator Containing Element +.tabulator { + position: relative; + + border: 1px solid $borderColor; + + background-color: $backgroundColor; + + font-size: $textSize; + text-align: left; + overflow: hidden; + + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -ms-transform: translateZ(0); + -o-transform: translateZ(0); + transform: translateZ(0); + + &[tabulator-layout='fitDataFill'] { + .tabulator-tableholder { + .tabulator-table { + min-width: 100%; + } + } + } + + &[tabulator-layout='fitDataTable'] { + display: inline-block; + } + + &.tabulator-block-select { + user-select: none; + } + + &.tabulator-ranges { + .tabulator-cell:not(.tabulator-editing) { + user-select: none; + } + } + + //column header containing element + .tabulator-header { + position: relative; + box-sizing: border-box; + + width: 100%; + + border-bottom: 1px solid $headerSeparatorColor; + background-color: $headerBackgroundColor; + color: $headerTextColor; + font-weight: bold; + + white-space: nowrap; + overflow: hidden; + + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: none; + -o-user-select: none; + + outline: none; + + &.tabulator-header-hidden { + display: none; + } + + .tabulator-header-contents { + position: relative; + overflow: hidden; + + .tabulator-headers { + display: inline-block; + } + } + + //individual column header element + .tabulator-col { + display: inline-flex; + position: relative; + box-sizing: border-box; + + flex-direction: column; + justify-content: flex-start; + + border-right: 1px solid $headerBorderColor; + background: $headerBackgroundColor; + + text-align: left; + vertical-align: bottom; + overflow: hidden; + + &.tabulator-moving { + position: absolute; + border: 1px solid $headerSeparatorColor; + background: color.adjust($headerBackgroundColor, $lightness: -10%); + pointer-events: none; + } + + &.tabulator-range-highlight { + background-color: $rangeHeaderHighlightBackground; + color: $rangeHeaderTextHighlightBackground; + } + + &.tabulator-range-selected { + background-color: $rangeHeaderSelectedBackground; + color: $rangeHeaderSelectedTextColor; + } + + //hold content of column header + .tabulator-col-content { + box-sizing: border-box; + position: relative; + padding: 4px; + + //header menu button + .tabulator-header-popup-button { + padding: 0 8px; + + &:hover { + cursor: pointer; + opacity: 0.6; + } + } + + //hold title and sort arrow + .tabulator-col-title-holder { + position: relative; + } + + //hold title of column header + .tabulator-col-title { + box-sizing: border-box; + width: 100%; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: bottom; + + &.tabulator-col-title-wrap { + white-space: normal; + text-overflow: initial; + } + + //element to hold title editor + .tabulator-title-editor { + box-sizing: border-box; + width: 100%; + + border: 1px solid #999; + + padding: 1px; + + background: #fff; + } + + .tabulator-header-popup-button + .tabulator-title-editor { + width: calc(100% - 22px); + } + } + + //column sorter arrow + .tabulator-col-sorter { + display: flex; + align-items: center; + + position: absolute; + top: 0; + bottom: 0; + right: 4px; + + .tabulator-arrow { + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid $sortArrowInactive; + } + } + } + + //complex header column group + &.tabulator-col-group { + //gelement to hold sub columns in column group + .tabulator-col-group-cols { + position: relative; + display: flex; + + border-top: 1px solid $headerBorderColor; + overflow: hidden; + + margin-right: -1px; + } + } + + //header filter containing element + .tabulator-header-filter { + position: relative; + box-sizing: border-box; + margin-top: 2px; + width: 100%; + text-align: center; + + //styling adjustment for inbuilt editors + textarea { + height: auto !important; + } + + svg { + margin-top: 3px; + } + + input { + &::-ms-clear { + width: 0; + height: 0; + } + } + } + + //styling child elements for sortable columns + &.tabulator-sortable { + .tabulator-col-title { + padding-right: 25px; + } + + @media (hover: hover) and (pointer: fine) { + &.tabulator-col-sorter-element:hover { + @apply cursor-pointer bg-neutral-200; + } + } + + &[aria-sort='none'] { + .tabulator-col-content .tabulator-col-sorter { + color: $sortArrowInactive; + + @media (hover: hover) and (pointer: fine) { + &.tabulator-col-sorter-element .tabulator-arrow:hover { + cursor: pointer; + border-bottom: 6px solid $sortArrowHover; + } + } + + .tabulator-arrow { + border-top: none; + border-bottom: 6px solid $sortArrowInactive; + } + } + } + + &[aria-sort='ascending'] { + .tabulator-col-content .tabulator-col-sorter { + color: $sortArrowActive; + + @media (hover: hover) and (pointer: fine) { + &.tabulator-col-sorter-element .tabulator-arrow:hover { + cursor: pointer; + border-bottom: 6px solid $sortArrowHover; + } + } + + .tabulator-arrow { + border-top: none; + border-bottom: 6px solid $sortArrowActive; + } + } + } + + &[aria-sort='descending'] { + .tabulator-col-content .tabulator-col-sorter { + color: $sortArrowActive; + + @media (hover: hover) and (pointer: fine) { + &.tabulator-col-sorter-element .tabulator-arrow:hover { + cursor: pointer; + border-top: 6px solid $sortArrowHover; + } + } + + .tabulator-arrow { + border-bottom: none; + border-top: 6px solid $sortArrowActive; + color: $sortArrowActive; + } + } + } + } + + &.tabulator-col-vertical { + .tabulator-col-content { + .tabulator-col-title { + writing-mode: vertical-rl; + text-orientation: mixed; + + display: flex; + align-items: center; + justify-content: center; + } + } + + &.tabulator-col-vertical-flip { + .tabulator-col-title { + transform: rotate(180deg); + } + } + + &.tabulator-sortable { + .tabulator-col-title { + padding-right: 0; + padding-top: 20px; + } + + &.tabulator-col-vertical-flip { + .tabulator-col-title { + padding-right: 0; + padding-bottom: 20px; + } + } + + .tabulator-col-sorter { + justify-content: center; + left: 0; + right: 0; + top: 4px; + bottom: auto; + } + } + } + } + + .tabulator-frozen { + position: sticky; + left: 0; + + // background-color: inherit; + + z-index: 11; + + &.tabulator-frozen-left { + border-right: 2px solid $rowBorderColor; + } + + &.tabulator-frozen-right { + border-left: 2px solid $rowBorderColor; + } + } + + .tabulator-calcs-holder { + box-sizing: border-box; + display: inline-block; + + background: color.adjust($headerBackgroundColor, $lightness: 5%) !important; + + border-top: 1px solid $rowBorderColor; + border-bottom: 1px solid $headerBorderColor; + + // overflow: hidden; + + .tabulator-row { + background: color.adjust($headerBackgroundColor, $lightness: 5%) !important; + + .tabulator-col-resize-handle { + display: none; + } + } + } + + .tabulator-frozen-rows-holder { + display: inline-block; + &:empty { + display: none; + } + } + } + + //scrolling element to hold table + .tabulator-tableholder { + position: relative; + width: 100%; + white-space: nowrap; + overflow: auto; + -webkit-overflow-scrolling: touch; + + &:focus { + outline: none; + } + + //default placeholder element + .tabulator-placeholder { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + + min-width: 100%; + width: 100%; + + &[tabulator-render-mode='virtual'] { + min-height: 100%; + } + + .tabulator-placeholder-contents { + display: inline-block; + text-align: center; + + padding: 10px; + + color: #ccc; + font-weight: bold; + font-size: 20px; + + white-space: normal; + } + } + + //element to hold table rows + .tabulator-table { + position: relative; + display: inline-block; + background-color: $rowBackgroundColor; + white-space: nowrap; + overflow: visible; + color: $rowTextColor; + + //row element + .tabulator-row { + &.tabulator-calcs { + font-weight: bold; + background: color.adjust($rowAltBackgroundColor, $lightness: -5%) !important; + + &.tabulator-calcs-top { + border-bottom: 2px solid $rowBorderColor; + } + + &.tabulator-calcs-bottom { + border-top: 2px solid $rowBorderColor; + } + } + } + } + + .tabulator-range-overlay { + position: absolute; + inset: 0; + z-index: 10; + pointer-events: none; + + .tabulator-range { + position: absolute; + box-sizing: border-box; + border: 1px solid $rangeBorderColor; + + &.tabulator-range-active::after { + content: ''; + position: absolute; + right: -3px; + bottom: -3px; + width: 6px; + height: 6px; + background-color: $rangeHandleColor; + border-radius: 999px; + } + } + + .tabulator-range-cell-active { + position: absolute; + box-sizing: border-box; + border: 2px solid $rangeBorderColor; + } + } + } + + //footer element + .tabulator-footer { + border-top: 1px solid $footerSeparatorColor; + background-color: $footerBackgroundColor; + + color: $footerTextColor; + font-weight: bold; + white-space: nowrap; + user-select: none; + + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: none; + -o-user-select: none; + + .tabulator-footer-contents { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + + padding: 5px 10px; + + &:empty { + display: none; + } + } + + .tabulator-spreadsheet-tabs { + margin-top: -5px; + + overflow-x: auto; + + .tabulator-spreadsheet-tab { + display: inline-block; + padding: 5px; + + border: $borderColor 1px solid; + border-top: none; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + + font-size: 0.9em; + + &:hover { + cursor: pointer; + opacity: 0.7; + } + + &.tabulator-spreadsheet-tab-active { + background: $spreadsheetActiveTabColor; + } + } + } + + .tabulator-calcs-holder { + box-sizing: border-box; + width: 100%; + + text-align: left; + + background: color.adjust($footerBackgroundColor, $lightness: 5%) !important; + border-bottom: 1px solid $rowBorderColor; + border-top: 1px solid $rowBorderColor; + + overflow: hidden; + + .tabulator-row { + display: inline-block; + background: color.adjust($footerBackgroundColor, $lightness: 5%) !important; + + .tabulator-col-resize-handle { + display: none; + } + } + + &:only-child { + margin-bottom: -5px; + border-bottom: none; + } + } + + & > * + .tabulator-page-counter { + margin-left: 10px; + } + + .tabulator-page-counter { + font-weight: normal; + } + + .tabulator-paginator { + flex: 1; + + text-align: right; + + color: $footerTextColor; + font-family: inherit; + font-weight: inherit; + font-size: inherit; + } + + //pagination container element + .tabulator-page-size { + display: inline-block; + + margin: 0 5px; + padding: 2px 5px; + + border: 1px solid $footerBorderColor; + border-radius: 3px; + } + + .tabulator-pages { + margin: 0 7px; + } + + //pagination button + .tabulator-page { + display: inline-block; + + margin: 0 2px; + padding: 2px 5px; + + border: 1px solid $footerBorderColor; + border-radius: 3px; + + background: rgba(255, 255, 255, 0.2); + + &.active { + color: $footerActiveColor; + } + + &:disabled { + opacity: 0.5; + } + + &:not(disabled) { + @media (hover: hover) and (pointer: fine) { + &:hover { + cursor: pointer; + background: rgba(0, 0, 0, 0.2); + color: #fff; + } + } + } + } + } + + //column resize handles + .tabulator-col-resize-handle { + position: relative; + display: inline-block; + width: 6px; + + margin-left: -3px; + margin-right: -3px; + + z-index: 11; + vertical-align: middle; + + @media (hover: hover) and (pointer: fine) { + &:hover { + cursor: ew-resize; + } + } + + &:last-of-type { + width: 3px; + margin-right: 0; + } + } + + //column resize guide + .tabulator-col-resize-guide { + position: absolute; + top: 0; + width: 4px; + height: 100%; + margin-left: -0.5px; + background-color: $columnResizeGuideColor; + opacity: 0.5; + } + + //row resize guide + .tabulator-row-resize-guide { + position: absolute; + left: 0; + width: 100%; + height: 4px; + margin-top: -0.5px; + background-color: $columnResizeGuideColor; + opacity: 0.5; + } + + //holding div that contains loader and covers tabulator element to prevent interaction + .tabulator-alert { + position: absolute; + display: flex; + align-items: center; + + top: 0; + left: 0; + z-index: 100; + + height: 100%; + width: 100%; + background: rgba(0, 0, 0, 0.4); + text-align: center; + + //loading message element + .tabulator-alert-msg { + display: inline-block; + + margin: 0 auto; + padding: 10px 20px; + + border-radius: 10px; + + background: #fff; + font-weight: bold; + font-size: 16px; + + //loading message + &.tabulator-alert-state-msg { + border: 4px solid #333; + color: #000; + } + + //error message + &.tabulator-alert-state-error { + border: 4px solid #d00; + color: #590000; + } + } + } +} + +//row element +.tabulator-row { + position: relative; + box-sizing: border-box; + min-height: $textSize + ($headerMargin * 2); + background-color: $rowBackgroundColor; + + &.tabulator-row-even { + background-color: $rowAltBackgroundColor; + } + + @media (hover: hover) and (pointer: fine) { + &.tabulator-selectable:hover { + background-color: $rowHoverBackground; + cursor: pointer; + } + } + + &.tabulator-selected { + background-color: $rowSelectedBackground; + } + + @media (hover: hover) and (pointer: fine) { + &.tabulator-selected:hover { + background-color: $rowSelectedBackgroundHover; + cursor: pointer; + } + } + + &.tabulator-row-moving { + border: 1px solid #000; + background: #fff; + } + + &.tabulator-moving { + position: absolute; + + border-top: 1px solid $rowBorderColor; + border-bottom: 1px solid $rowBorderColor; + + pointer-events: none; + z-index: 15; + } + + &.tabulator-range-highlight { + .tabulator-cell.tabulator-range-row-header { + background-color: $rangeHeaderHighlightBackground; + color: $rangeHeaderTextHighlightBackground; + } + + &.tabulator-range-selected { + .tabulator-cell.tabulator-range-row-header { + background-color: $rangeHeaderSelectedBackground; + color: $rangeHeaderSelectedTextColor; + } + } + } + + &.tabulator-range-selected { + .tabulator-cell.tabulator-range-row-header { + background-color: $rangeHeaderSelectedBackground; + color: $rangeHeaderSelectedTextColor; + } + } + + //row resize handles + .tabulator-row-resize-handle { + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 5px; + + &.prev { + top: 0; + bottom: auto; + } + + @media (hover: hover) and (pointer: fine) { + &:hover { + cursor: ns-resize; + } + } + } + + .tabulator-responsive-collapse { + box-sizing: border-box; + + padding: 5px; + + border-top: 1px solid $rowBorderColor; + border-bottom: 1px solid $rowBorderColor; + + &:empty { + display: none; + } + + table { + font-size: $textSize; + + tr { + td { + position: relative; + + &:first-of-type { + padding-right: 10px; + } + } + } + } + } + + //cell element + .tabulator-cell { + display: inline-block; + position: relative; + box-sizing: border-box; + padding: 4px; + // border-right:1px solid $rowBorderColor; + vertical-align: middle; + white-space: nowrap; + overflow: hidden; + // text-overflow: ellipsis; + outline: none; + + &.tabulator-row-header { + border-right: 1px solid $borderColor; + border-bottom: 1px solid $rowBorderColor; + background: $headerBackgroundColor; + } + + &.tabulator-frozen { + display: inline-block; + position: sticky; + + left: 0; + + background-color: inherit; + + z-index: 11; + + &.tabulator-frozen-left { + border: none; + } + + &.tabulator-frozen-right { + border: none; + } + } + + &.tabulator-editing { + border: 1px solid $editBoxColor; + outline: none; + + padding: 0; + + input, + select { + border: 1px; + background: transparent; + outline: none; + } + } + + &.tabulator-validation-fail { + border: 1px solid $errorColor; + + input, + select { + border: 1px; + background: transparent; + + color: $errorColor; + } + } + + //movable row handle + &.tabulator-row-handle { + display: inline-flex; + align-items: center; + justify-content: center; + + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: none; + -o-user-select: none; + + //handle holder + .tabulator-row-handle-box { + width: 80%; + + //Hamburger element + .tabulator-row-handle-bar { + width: 100%; + height: 3px; + margin-top: 2px; + background: #666; + } + } + } + + &.tabulator-range-selected:not(.tabulator-range-only-cell-selected):not( + .tabulator-range-row-header + ) { + background-color: $rowSelectedBackground; + } + + .tabulator-data-tree-branch-empty { + display: inline-block; + width: 7px; + } + + .tabulator-data-tree-branch { + display: inline-block; + vertical-align: middle; + + height: 9px; + width: 7px; + + margin-top: -9px; + margin-right: 5px; + + border-bottom-left-radius: 1px; + + border-left: 2px solid $rowBorderColor; + border-bottom: 2px solid $rowBorderColor; + } + + .tabulator-data-tree-control { + display: inline-flex; + justify-content: center; + align-items: center; + vertical-align: middle; + + height: 11px; + width: 11px; + + margin-right: 5px; + + border: 1px solid $rowTextColor; + border-radius: 2px; + background: rgba(0, 0, 0, 0.1); + + overflow: hidden; + + @media (hover: hover) and (pointer: fine) { + &:hover { + cursor: pointer; + background: rgba(0, 0, 0, 0.2); + } + } + + .tabulator-data-tree-control-collapse { + display: inline-block; + position: relative; + + height: 7px; + width: 1px; + + background: transparent; + + &:after { + position: absolute; + content: ''; + left: -3px; + top: 3px; + + height: 1px; + width: 7px; + + background: $rowTextColor; + } + } + + .tabulator-data-tree-control-expand { + display: inline-block; + position: relative; + + height: 7px; + width: 1px; + + background: $rowTextColor; + + &:after { + position: absolute; + content: ''; + left: -3px; + top: 3px; + + height: 1px; + width: 7px; + + background: $rowTextColor; + } + } + } + + .tabulator-responsive-collapse-toggle { + display: inline-flex; + align-items: center; + justify-content: center; + + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: none; + -o-user-select: none; + + height: 15px; + width: 15px; + + border-radius: 20px; + background: #666; + + color: $rowBackgroundColor; + font-weight: bold; + font-size: 1.1em; + + @media (hover: hover) and (pointer: fine) { + &:hover { + opacity: 0.7; + cursor: pointer; + } + } + + &.open { + .tabulator-responsive-collapse-toggle-close { + display: initial; + } + + .tabulator-responsive-collapse-toggle-open { + display: none; + } + } + + svg { + stroke: $rowBackgroundColor; + } + + .tabulator-responsive-collapse-toggle-close { + display: none; + } + } + + .tabulator-traffic-light { + display: inline-block; + height: 14px; + width: 14px; + + border-radius: 14px; + } + } + + //row grouping element + &.tabulator-group { + box-sizing: border-box; + border-bottom: 1px solid #999; + border-right: 1px solid $rowBorderColor; + border-top: 1px solid #999; + padding: 5px; + padding-left: 10px; + background: #ccc; + font-weight: bold; + + min-width: 100%; + + @media (hover: hover) and (pointer: fine) { + &:hover { + cursor: pointer; + background-color: rgba(0, 0, 0, 0.1); + } + } + + &.tabulator-group-visible { + .tabulator-arrow { + margin-right: 10px; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid $sortArrowActive; + border-bottom: 0; + } + } + + &.tabulator-group-level-1 { + padding-left: 30px; + } + + &.tabulator-group-level-2 { + padding-left: 50px; + } + + &.tabulator-group-level-3 { + padding-left: 70px; + } + + &.tabulator-group-level-4 { + padding-left: 90px; + } + + &.tabulator-group-level-5 { + padding-left: 110px; + } + + .tabulator-group-toggle { + display: inline-block; + } + + //sorting arrow + .tabulator-arrow { + display: inline-block; + width: 0; + height: 0; + margin-right: 16px; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-right: 0; + border-left: 6px solid $sortArrowActive; + vertical-align: middle; + } + + span { + margin-left: 10px; + color: #d00; + } + } +} + +.tabulator-toggle { + box-sizing: border-box; + + display: flex; + flex-direction: row; + + border: 1px solid #ccc; + background: #dcdcdc; + + &.tabulator-toggle-on { + background: #1c6cc2; + } + + .tabulator-toggle-switch { + box-sizing: border-box; + border: 1px solid #ccc; + + background: #fff; + } +} + +.tabulator-popup-container { + position: absolute; + display: inline-block; + box-sizing: border-box; + + background: $rowBackgroundColor; + border: 1px solid $rowBorderColor; + box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.2); + + font-size: $textSize; + + overflow-y: auto; + -webkit-overflow-scrolling: touch; + + z-index: 10000; +} + +.tabulator-popup { + padding: 5px; + + border-radius: 3px; +} + +.tabulator-tooltip { + max-width: Min(500px, 100%); + + padding: 3px 5px; + + border-radius: 2px; + box-shadow: none; + + font-size: 12px; + + pointer-events: none; +} + +.tabulator-menu { + .tabulator-menu-item { + position: relative; + box-sizing: border-box; + + padding: 5px 10px; + + user-select: none; + + &.tabulator-menu-item-disabled { + opacity: 0.5; + } + + @media (hover: hover) and (pointer: fine) { + &:not(.tabulator-menu-item-disabled):hover { + cursor: pointer; + background: $rowAltBackgroundColor; + } + } + + &.tabulator-menu-item-submenu { + padding-right: 25px; + + &::after { + display: inline-block; + position: absolute; + + top: calc(5px + 0.4em); + right: 10px; + height: 7px; + width: 7px; + + content: ''; + + border-width: 1px 1px 0 0; + border-style: solid; + border-color: $rowBorderColor; + vertical-align: top; + + transform: rotate(45deg); + } + } + } + + .tabulator-menu-separator { + border-top: 1px solid $rowBorderColor; + } +} + +.tabulator-edit-list { + max-height: 200px; + + font-size: $textSize; + + overflow-y: auto; + -webkit-overflow-scrolling: touch; + + .tabulator-edit-list-item { + padding: 4px; + + color: $rowTextColor; + outline: none; + + &.active { + color: $rowBackgroundColor; + background: $editBoxColor; + + &.focused { + outline: 1px solid rgba($rowBackgroundColor, 0.5); + } + } + + &.focused { + outline: 1px solid $editBoxColor; + } + + @media (hover: hover) and (pointer: fine) { + &:hover { + cursor: pointer; + + color: $rowBackgroundColor; + background: $editBoxColor; + } + } + } + + .tabulator-edit-list-placeholder { + padding: 4px; + + color: $rowTextColor; + text-align: center; + } + + .tabulator-edit-list-group { + border-bottom: 1px solid $rowBorderColor; + + padding: 4px; + padding-top: 6px; + + color: $rowTextColor; + font-weight: bold; + } + + .tabulator-edit-list-item, + .tabulator-edit-list-group { + &.tabulator-edit-list-group-level-2 { + padding-left: 12px; + } + + &.tabulator-edit-list-group-level-3 { + padding-left: 20px; + } + + &.tabulator-edit-list-group-level-4 { + padding-left: 28px; + } + + &.tabulator-edit-list-group-level-5 { + padding-left: 36px; + } + } +} + +//RTL Styling + +.tabulator.tabulator-ltr { + direction: ltr; +} + +.tabulator.tabulator-rtl { + text-align: initial; + direction: rtl; + + .tabulator-header { + .tabulator-col { + text-align: initial; + border-left: 1px solid $headerBorderColor; + border-right: initial; + + &.tabulator-col-group { + .tabulator-col-group-cols { + margin-right: initial; + margin-left: -1px; + } + } + + &.tabulator-sortable { + .tabulator-col-title { + padding-right: 0; + padding-left: 25px; + } + } + + .tabulator-col-content { + .tabulator-col-sorter { + left: 8px; + right: initial; + } + } + } + } + + .tabulator-tableholder { + .tabulator-range-overlay { + .tabulator-range { + &.tabulator-range-active::after { + content: ''; + position: absolute; + left: -3px; + right: initial; + bottom: -3px; + width: 6px; + height: 6px; + background-color: $rangeHandleColor; + border-radius: 999px; + } + } + } + } + + .tabulator-row { + .tabulator-cell { + border-right: initial; + border-left: 1px solid $rowBorderColor; + + .tabulator-data-tree-branch { + margin-right: initial; + margin-left: 5px; + + border-bottom-left-radius: initial; + border-bottom-right-radius: 1px; + + border-left: initial; + border-right: 2px solid $rowBorderColor; + } + + .tabulator-data-tree-control { + margin-right: initial; + margin-left: 5px; + } + + &.tabulator-frozen { + &.tabulator-frozen-left { + border-left: 2px solid $rowBorderColor; + } + + &.tabulator-frozen-right { + border-right: 2px solid $rowBorderColor; + } + } + } + + .tabulator-col-resize-handle { + &:last-of-type { + width: 3px; + margin-left: 0; + margin-right: -3px; + } + } + } + + .tabulator-footer { + .tabulator-calcs-holder { + text-align: initial; + } + } +} + +// Table print styling + +.tabulator-print-fullscreen { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + + z-index: 10000; +} + +body.tabulator-print-fullscreen-hide > *:not(.tabulator-print-fullscreen) { + display: none !important; +} + +.tabulator-print-table { + border-collapse: collapse; + + .tabulator-data-tree-branch { + display: inline-block; + vertical-align: middle; + + height: 9px; + width: 7px; + + margin-top: -9px; + margin-right: 5px; + + border-bottom-left-radius: 1px; + + border-left: 2px solid $rowBorderColor; + border-bottom: 2px solid $rowBorderColor; + } + + //row grouping element + .tabulator-print-table-group { + box-sizing: border-box; + border-bottom: 1px solid #999; + border-right: 1px solid $rowBorderColor; + border-top: 1px solid #999; + padding: 5px; + padding-left: 10px; + background: #ccc; + font-weight: bold; + + min-width: 100%; + + @media (hover: hover) and (pointer: fine) { + &:hover { + cursor: pointer; + background-color: rgba(0, 0, 0, 0.1); + } + } + + &.tabulator-group-visible { + .tabulator-arrow { + margin-right: 10px; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid $sortArrowActive; + border-bottom: 0; + } + } + + &.tabulator-group-level-1 { + td { + padding-left: 30px !important; + } + } + + &.tabulator-group-level-2 { + td { + padding-left: 50px !important; + } + } + + &.tabulator-group-level-3 { + td { + padding-left: 70px !important; + } + } + + &.tabulator-group-level-4 { + td { + padding-left: 90px !important; + } + } + + &.tabulator-group-level-5 { + td { + padding-left: 110px !important; + } + } + + .tabulator-group-toggle { + display: inline-block; + } + + //sorting arrow + .tabulator-arrow { + display: inline-block; + width: 0; + height: 0; + margin-right: 16px; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + border-right: 0; + border-left: 6px solid $sortArrowActive; + vertical-align: middle; + } + + span { + margin-left: 10px; + color: #d00; + } + } + + .tabulator-data-tree-control { + display: inline-flex; + justify-content: center; + align-items: center; + vertical-align: middle; + + height: 11px; + width: 11px; + + margin-right: 5px; + + border: 1px solid $rowTextColor; + border-radius: 2px; + background: rgba(0, 0, 0, 0.1); + + overflow: hidden; + + @media (hover: hover) and (pointer: fine) { + &:hover { + cursor: pointer; + background: rgba(0, 0, 0, 0.2); + } + } + + .tabulator-data-tree-control-collapse { + display: inline-block; + position: relative; + + height: 7px; + width: 1px; + + background: transparent; + + &:after { + position: absolute; + content: ''; + left: -3px; + top: 3px; + + height: 1px; + width: 7px; + + background: $rowTextColor; + } + } + + .tabulator-data-tree-control-expand { + display: inline-block; + position: relative; + + height: 7px; + width: 1px; + + background: $rowTextColor; + + &:after { + position: absolute; + content: ''; + left: -3px; + top: 3px; + + height: 1px; + width: 7px; + + background: $rowTextColor; + } + } + } +} diff --git a/new-web/src/css/tabulator_simple.scss b/new-web/src/css/tabulator_simple.scss new file mode 100644 index 00000000..bd0de7e5 --- /dev/null +++ b/new-web/src/css/tabulator_simple.scss @@ -0,0 +1,233 @@ +@use './tabulator.scss'; + +.tabulator { + @apply bg-primary border-none; + + .tabulator-header { + @apply border-border bg-background; + + .tabulator-header-contents { + @apply bg-background; + } + + .tabulator-col-content { + @apply bg-background hover:bg-muted; + } + + .tabulator-calcs-holder { + @apply !border-border !bg-background !border; + + .tabulator-row { + @apply !bg-background; + } + } + + .tabulator-col { + @apply bg-background; + + &.tabulator-sortable { + @media (hover: hover) and (pointer: fine) { + @apply border-border; + &.tabulator-col-sorter-element:hover { + @apply bg-background cursor-pointer; + } + } + } + } + + .tabulator-col-title-holder { + @apply text-black dark:text-white; + + .tabulator-col-title { + @apply text-black dark:text-white; + } + } + + .tabulator-col-title input { + @apply border-border border; + } + } + + .tabulator-row { + @apply border-border bg-background border-b text-black dark:text-white; + + @media (hover: hover) and (pointer: fine) { + &.tabulator-selectable:hover { + @apply bg-background; + cursor: pointer; + } + } + + .tabulator-cell { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + &:last-of-type { + border-right: none; + } + + &.tabulator-row-header { + border-bottom: none; + } + + .tabulator-data-tree-control { + @apply border-primary bg-primary; + + .tabulator-data-tree-control-collapse { + background: transparent; + &:after { + @apply bg-primary-foreground; + } + } + + .tabulator-data-tree-control-expand { + @apply bg-primary-foreground; + + &:after { + @apply bg-primary-foreground; + } + } + } + } + + &.tabulator-group { + span { + color: #666; + } + } + + .tabulator-frozen input { + @apply opacity-40; + background-color: rgb(63 63 70) !important; + @apply border-border border; + } + } + + .tabulator-tableholder { + .tabulator-cell { + .tabulator-data-tree-control { + @apply bg-primary; + } + } + + @apply bg-background; + .tabulator-placeholder { + span { + @apply text-secondary; + } + .tabulator-placeholder-contents { + @apply text-secondary; + } + } + } + + .tabulator-footer { + @apply border-border bg-background; + + .tabulator-footer-contents { + @apply text-black dark:text-white; + + .tabulator-paginator { + label { + @apply text-black dark:text-white; + } + + select { + @apply border-border bg-primary text-black dark:text-white; + } + + .tabulator-page { + @apply border-border bg-primary-foreground hover:border-primary/10 hover:bg-primary/10 dark:bg-muted hover:dark:border-muted hover:dark:bg-muted/10 text-black dark:text-white; + + &.active { + @apply !bg-primary !text-secondary; + } + + &:disabled { + opacity: 0.4; + } + } + } + } + + .tabulator-calcs-holder { + .tabulator-row { + @apply !bg-primary; + } + } + + .tabulator-spreadsheet-tabs { + .tabulator-spreadsheet-tab { + font-weight: normal; + + &.tabulator-spreadsheet-tab-active { + color: tabulator.$footerActiveColor; + font-weight: bold; + } + } + } + } +} + +.tabulator-table .tabulator-row-odd { + @apply border-border bg-background border-b border-none text-black dark:text-white; + + .tabulator-frozen { + @apply bg-secondary; + } + + @media (hover: hover) and (pointer: fine) { + &.tabulator-selectable:hover { + // @apply bg-background hover:bg-muted; + cursor: pointer; + } + } +} + +.tabulator-table .tabulator-row-even { + @apply border-border bg-background border-b border-none text-black dark:text-white; + + .tabulator-frozen { + @apply bg-secondary; + } + + .tabulator-frozen input { + @apply border-border border; + } + + @media (hover: hover) and (pointer: fine) { + &.tabulator-selectable:hover { + // @apply bg-background hover:bg-muted; + cursor: pointer; + } + } +} + +.tabulator-table .tabulator-selected { + @apply !bg-muted; +} + +.tabulator-table .tabulator-tree-level-0 .tabulator-cell:first-of-type { + padding-left: 9px; +} + +.tabulator-table .tabulator-tree-level-1 .tabulator-cell:first-of-type { + padding-left: 5px; +} + +.tabulator-table .tabulator-tree-level-2 .tabulator-cell:first-of-type { + padding-left: 12px; +} + +.tabulator-table .tabulator-tree-level-3 .tabulator-cell:first-of-type { + padding-left: 12px; +} + +.tabulator-print-table { + .tabulator-print-table-group { + span { + margin-left: 10px; + color: #666; + } + } +} diff --git a/new-web/src/lib/api/common.ts b/new-web/src/lib/api/common.ts new file mode 100644 index 00000000..6867453d --- /dev/null +++ b/new-web/src/lib/api/common.ts @@ -0,0 +1,90 @@ +/** + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 The FreeBSD Foundation. + * + * This software was developed by Hayzam Sherif + * of Alchemilla Ventures Pvt. Ltd. , + * under sponsorship from the FreeBSD Foundation. + */ + +import { browser } from '$app/environment'; +import { goto } from '$app/navigation'; +import { store as token } from '$lib/stores/auth'; +import adze from 'adze'; +import axios, { AxiosError, type AxiosInstance, type InternalAxiosRequestConfig } from 'axios'; +import { toast } from "svelte-sonner"; +import { get } from 'svelte/store'; + +export let ENDPOINT: string; +export let API_ENDPOINT: string; + +if (browser) { + ENDPOINT = window.location.origin; + API_ENDPOINT = `${window.location.origin}/api`; +} else { + ENDPOINT = ''; + API_ENDPOINT = ''; +} + +export const api: AxiosInstance = axios.create({ + baseURL: API_ENDPOINT +}); + +api.interceptors.request.use( + (config: InternalAxiosRequestConfig) => { + if (browser) { + if (get(token)) { + config.headers['Authorization'] = `Bearer ${get(token)}`; + } + } + return config; + }, + (error) => { + return Promise.reject(error); + } +); + +api.interceptors.response.use( + (response) => response, + async (error) => { + if (error.response?.status === 401 && browser) { + toast.error('Session expired, please login again', { + position: 'bottom-center' + }); + goto('/login'); + return; + } + handleAxiosError(error); + return Promise.reject(error); + } +); + +export function handleAxiosError(error: unknown): void { + if (!browser) return; + + if (!axios.isAxiosError(error)) { + toast.error('An unexpected error occurred', { + position: 'bottom-center' + }); + adze.withEmoji.error('An unexpected error occurred'); + return; + } + + const axiosError = error as AxiosError<{ message?: string }>; + if (axiosError.response) { + const errorMessage = + axiosError.response.data?.message || axiosError.message || 'An error occurred'; + // adze.withEmoji.error('Status:', axiosError.response.status); + // adze.withEmoji.error('Data:', axiosError.response.data); + // adze.withEmoji.error('Error message:', errorMessage); + // showToast({ text: errorMessage, type: 'error', timeout: 5000 }); + } else if (axiosError.request) { + // adze.withEmoji.error('No response:', axiosError.request); + // showToast({ + // text: 'No response from server', + // type: 'error', + // timeout: 5000 + // }); + } +} diff --git a/new-web/src/lib/api/disk/disk.ts b/new-web/src/lib/api/disk/disk.ts new file mode 100644 index 00000000..848d7608 --- /dev/null +++ b/new-web/src/lib/api/disk/disk.ts @@ -0,0 +1,33 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { DiskSchema, type Disk } from '$lib/types/disk/disk'; +import { apiRequest } from '$lib/utils/http'; +import { z } from 'zod/v4'; + +export async function listDisks(): Promise { + return await apiRequest('/disk/list', z.array(DiskSchema), 'GET'); +} + +export async function destroyDisk(disk: string): Promise { + return await apiRequest(`/disk/wipe`, APIResponseSchema, 'POST', { + device: disk + }); +} + +export async function destroyPartition(partition: string): Promise { + return await apiRequest(`/disk/delete-partition`, APIResponseSchema, 'POST', { + device: partition + }); +} + +export async function initializeGPT(disk: string): Promise { + return await apiRequest(`/disk/initialize-gpt`, APIResponseSchema, 'POST', { + device: disk + }); +} + +export async function createPartitions(disk: string, sizes: number[]): Promise { + return await apiRequest(`/disk/create-partitions`, APIResponseSchema, 'POST', { + device: disk, + sizes + }); +} diff --git a/new-web/src/lib/api/info/audit.ts b/new-web/src/lib/api/info/audit.ts new file mode 100644 index 00000000..26f3c752 --- /dev/null +++ b/new-web/src/lib/api/info/audit.ts @@ -0,0 +1,41 @@ +import { AuditLogSchema, type AuditLog } from '$lib/types/info/audit'; +import { apiRequest } from '$lib/utils/http'; +import { getTranslation } from '$lib/utils/i18n'; +import { capitalizeFirstLetter } from '$lib/utils/string'; + +export async function getAuditLogs(): Promise { + return await apiRequest('/info/audit-logs', AuditLogSchema, 'GET'); +} + +export function formatAction(action: string): string { + if (action.includes('|-|')) { + const parts = action.split('|-|'); + return capitalizeFirstLetter(getTranslation(parts[0], parts[0]), true) + ' ' + parts[1]; + } + + switch (action) { + case 'login': + return getTranslation('auth.login', 'Login'); + case 'revoke_token': + return getTranslation('auth.logout', 'Logout'); + default: + return action; + } +} + +export function formatStatus(status: string): string { + switch (status) { + case 'started': + return 'Started'; + case 'success': + return 'OK'; + case 'failure': + return 'Failed'; + case 'failed': + return 'Failed'; + case 'progress': + return 'In Progress'; + default: + return status; + } +} diff --git a/new-web/src/lib/api/info/basic.ts b/new-web/src/lib/api/info/basic.ts new file mode 100644 index 00000000..2f818ab8 --- /dev/null +++ b/new-web/src/lib/api/info/basic.ts @@ -0,0 +1,6 @@ +import { BasicInfoSchema, type BasicInfo } from '$lib/types/info/basic'; +import { apiRequest } from '$lib/utils/http'; + +export async function getBasicInfo(): Promise { + return await apiRequest('/info/basic', BasicInfoSchema, 'GET'); +} diff --git a/new-web/src/lib/api/info/cpu.ts b/new-web/src/lib/api/info/cpu.ts new file mode 100644 index 00000000..0d26dcbc --- /dev/null +++ b/new-web/src/lib/api/info/cpu.ts @@ -0,0 +1,20 @@ +import { + CPUInfoHistoricalSchema, + CPUInfoSchema, + type CPUInfo, + type CPUInfoHistorical +} from '$lib/types/info/cpu'; +import { apiRequest } from '$lib/utils/http'; +import type { QueryFunctionContext } from '@sveltestack/svelte-query'; + +export async function getCPUInfo( + queryObj?: QueryFunctionContext +): Promise { + if (queryObj) { + if (queryObj.queryKey.includes('cpuInfoHistorical')) { + return await apiRequest('/info/cpu/historical', CPUInfoHistoricalSchema, 'GET'); + } + } + + return await apiRequest('/info/cpu', CPUInfoSchema, 'GET'); +} diff --git a/new-web/src/lib/api/info/info.ts b/new-web/src/lib/api/info/info.ts new file mode 100644 index 00000000..e69de29b diff --git a/new-web/src/lib/api/info/notes.ts b/new-web/src/lib/api/info/notes.ts new file mode 100644 index 00000000..995db12d --- /dev/null +++ b/new-web/src/lib/api/info/notes.ts @@ -0,0 +1,41 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { NoteSchema, NotesSchema, type Note, type Notes } from '$lib/types/info/notes'; +import { apiRequest } from '$lib/utils/http'; +import { z } from 'zod/v4'; + +async function notesRequest( + endpoint: string, + method: 'GET' | 'POST' | 'PUT' | 'DELETE', + body?: object +): Promise { + let schema; + + if (method === 'GET') { + schema = z.array(NoteSchema); + } else if (method === 'POST') { + schema = NoteSchema; + } else { + schema = APIResponseSchema; + } + + return await apiRequest(endpoint, schema, method, body); +} + +export const getNotes = () => notesRequest('/info/notes', 'GET'); +export const deleteNote = (id: number) => notesRequest(`/info/notes/${id}`, 'DELETE'); + +export const createNote = async (title: string, content: string): Promise => { + return (await notesRequest('/info/notes', 'POST', { title, content })) as Note | APIResponse; +}; + +export const updateNote = async ( + id: number, + title: string, + content: string +): Promise => { + return (await notesRequest(`/info/notes/${id}`, 'PUT', { title, content })) as APIResponse; +}; + +export const deleteNotes = async (ids: number[]): Promise => { + return (await notesRequest('/info/notes/bulk-delete', 'POST', { ids })) as APIResponse; +}; diff --git a/new-web/src/lib/api/info/ram.ts b/new-web/src/lib/api/info/ram.ts new file mode 100644 index 00000000..849e316f --- /dev/null +++ b/new-web/src/lib/api/info/ram.ts @@ -0,0 +1,10 @@ +import { RAMInfoSchema, type RAMInfo } from '$lib/types/info/ram'; +import { apiRequest } from '$lib/utils/http'; + +export async function getRAMInfo(): Promise { + return await apiRequest('/info/ram', RAMInfoSchema, 'GET'); +} + +export async function getSwapInfo(): Promise { + return await apiRequest('/info/swap', RAMInfoSchema, 'GET'); +} diff --git a/new-web/src/lib/api/network/iface.ts b/new-web/src/lib/api/network/iface.ts new file mode 100644 index 00000000..d1efcdbb --- /dev/null +++ b/new-web/src/lib/api/network/iface.ts @@ -0,0 +1,6 @@ +import { IfaceSchema, type Iface } from '$lib/types/network/iface'; +import { apiRequest } from '$lib/utils/http'; + +export async function getInterfaces(): Promise { + return await apiRequest('/network/interface', IfaceSchema.array(), 'GET'); +} diff --git a/new-web/src/lib/api/network/switch.ts b/new-web/src/lib/api/network/switch.ts new file mode 100644 index 00000000..2c4d8997 --- /dev/null +++ b/new-web/src/lib/api/network/switch.ts @@ -0,0 +1,67 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { SwitchListSchema, type SwitchList } from '$lib/types/network/switch'; +import { apiRequest } from '$lib/utils/http'; + +export async function getSwitches(): Promise { + return await apiRequest('/network/switch', SwitchListSchema, 'GET'); +} + +export async function createSwitch( + name: string, + mtu: number, + vlan: number, + address: string, + address6: string, + privateSw: boolean, + dhcp: boolean, + ports: string[], + disableIPv6: boolean, + slaac: boolean +): Promise { + const body = { + name, + mtu, + vlan, + address, + address6, + private: privateSw, + ports, + dhcp, + disableIPv6, + slaac + }; + + return await apiRequest('/network/switch/standard', APIResponseSchema, 'POST', body); +} + +export async function deleteSwitch(id: number): Promise { + return await apiRequest(`/network/switch/standard/${id}`, APIResponseSchema, 'DELETE'); +} + +export async function updateSwitch( + id: number, + mtu: number, + vlan: number, + address: string, + address6: string, + privateSw: boolean, + ports: string[], + disableIPv6: boolean, + slaac: boolean, + dhcp: boolean +): Promise { + const body = { + id, + mtu, + vlan, + address, + address6, + private: privateSw, + ports, + disableIPv6, + slaac, + dhcp + }; + + return await apiRequest('/network/switch/standard', APIResponseSchema, 'PUT', body); +} diff --git a/new-web/src/lib/api/system/pci.ts b/new-web/src/lib/api/system/pci.ts new file mode 100644 index 00000000..06457db1 --- /dev/null +++ b/new-web/src/lib/api/system/pci.ts @@ -0,0 +1,24 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { + PCIDeviceSchema, + PPTDeviceSchema, + type PCIDevice, + type PPTDevice +} from '$lib/types/system/pci'; +import { apiRequest } from '$lib/utils/http'; + +export async function getPCIDevices(): Promise { + return await apiRequest('/system/pci-devices', PCIDeviceSchema.array(), 'GET'); +} + +export async function getPPTDevices(): Promise { + return await apiRequest('/system/ppt-devices', PPTDeviceSchema.array(), 'GET'); +} + +export async function addPPTDevice(domain: string, deviceID: string): Promise { + return await apiRequest('/system/ppt-devices', APIResponseSchema, 'POST', { domain, deviceID }); +} + +export async function removePPTDevice(deviceID: string): Promise { + return await apiRequest(`/system/ppt-devices/${deviceID}`, APIResponseSchema, 'DELETE'); +} diff --git a/new-web/src/lib/api/utilities/downloader.ts b/new-web/src/lib/api/utilities/downloader.ts new file mode 100644 index 00000000..684e7699 --- /dev/null +++ b/new-web/src/lib/api/utilities/downloader.ts @@ -0,0 +1,30 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { DownloadSchema, type Download } from '$lib/types/utilities/downloader'; +import { apiRequest } from '$lib/utils/http'; + +export async function getDownloads(): Promise { + return await apiRequest('/utilities/downloads', DownloadSchema.array(), 'GET'); +} + +export async function startDownload(url: string): Promise { + return await apiRequest('/utilities/downloads', APIResponseSchema, 'POST', { + url + }); +} + +export async function deleteDownload(id: number): Promise { + return await apiRequest(`/utilities/downloads/${id}`, APIResponseSchema, 'DELETE'); +} + +export async function bulkDeleteDownloads(ids: number[]): Promise { + return await apiRequest('/utilities/downloads/bulk-delete', APIResponseSchema, 'POST', { + ids + }); +} + +export async function getSignedURL(name: string, parentUUID: string): Promise { + return await apiRequest('/utilities/downloads/signed-url', APIResponseSchema, 'POST', { + name, + parentUUID + }); +} diff --git a/new-web/src/lib/api/vm/storage.ts b/new-web/src/lib/api/vm/storage.ts new file mode 100644 index 00000000..1cd8078d --- /dev/null +++ b/new-web/src/lib/api/vm/storage.ts @@ -0,0 +1,9 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { apiRequest } from '$lib/utils/http'; + +export async function storageDetach(vmId: number, storageId: number): Promise { + return await apiRequest(`/vm/storage/detach`, APIResponseSchema, 'POST', { + vmId, + storageId + }); +} diff --git a/new-web/src/lib/api/vm/vm.ts b/new-web/src/lib/api/vm/vm.ts new file mode 100644 index 00000000..50e880e8 --- /dev/null +++ b/new-web/src/lib/api/vm/vm.ts @@ -0,0 +1,69 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { + VMDomainSchema, + VMSchema, + VMStatSchema, + type CreateData, + type VM, + type VMDomain, + type VMStat +} from '$lib/types/vm/vm'; +import { apiRequest } from '$lib/utils/http'; +import { z } from 'zod/v4'; + +export async function getVMs(): Promise { + return await apiRequest('/vm', z.array(VMSchema), 'GET'); +} + +export async function newVM(data: CreateData): Promise { + return await apiRequest('/vm', APIResponseSchema, 'POST', { + name: data.name, + vmId: data.id, + iso: data.storage.iso, + storageType: data.storage.type, + storageDataset: data.storage.guid, + storageSize: data.storage.size, + storageEmulationType: data.storage.emulation, + switchId: data.network.switch, + switchEmulationType: data.network.emulation, + macAddress: data.network.mac, + cpuSockets: data.hardware.sockets, + cpuCores: data.hardware.cores, + cpuThreads: data.hardware.threads, + ram: data.hardware.memory, + vncPort: data.advanced.vncPort, + vncPassword: data.advanced.vncPassword, + vncWait: data.advanced.vncWait, + vncResolution: data.advanced.vncResolution, + startAtBoot: data.advanced.startAtBoot, + bootOrder: data.advanced.bootOrder, + pciDevices: data.hardware.passthroughIds, + description: data.description + }); +} + +export async function deleteVM(id: number): Promise { + return await apiRequest(`/vm/${id}`, APIResponseSchema, 'DELETE'); +} + +export async function getVMDomain(id: number | string): Promise { + return await apiRequest(`/vm/domain/${id}`, VMDomainSchema, 'GET'); +} + +export async function actionVm(id: number | string, action: string): Promise { + return await apiRequest(`/vm/${id}/${action}`, APIResponseSchema, 'POST'); +} + +export async function getStats(vmId: number, limit: number): Promise { + return await apiRequest(`/vm/stats`, z.array(VMStatSchema), 'POST', { + vmId, + limit + }); +} + +export async function updateDescription(id: number, description: string): Promise { + return await apiRequest(`/vm/description`, APIResponseSchema, 'PUT', { + id, + description + }); +} diff --git a/new-web/src/lib/api/zfs/datasets.ts b/new-web/src/lib/api/zfs/datasets.ts new file mode 100644 index 00000000..390405b2 --- /dev/null +++ b/new-web/src/lib/api/zfs/datasets.ts @@ -0,0 +1,113 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { + DatasetSchema, + PeriodicSnapshotSchema, + type Dataset, + type PeriodicSnapshot +} from '$lib/types/zfs/dataset'; + +import { apiRequest } from '$lib/utils/http'; + +export async function getDatasets(): Promise { + return await apiRequest('/zfs/datasets', DatasetSchema.array(), 'GET'); +} + +export async function deleteSnapshot( + snapshot: Dataset, + recursive: boolean = false +): Promise { + const param = recursive ? '?recursive=true' : ''; + return await apiRequest( + `/zfs/datasets/snapshot/${snapshot.properties.guid}${param}`, + APIResponseSchema, + 'DELETE' + ); +} + +export async function createSnapshot( + dataset: Dataset, + name: string, + recursive: boolean +): Promise { + return await apiRequest('/zfs/datasets/snapshot', APIResponseSchema, 'POST', { + name: name, + recursive: recursive, + guid: dataset.properties.guid + }); +} + +export async function getPeriodicSnapshots(): Promise { + return await apiRequest('/zfs/datasets/snapshot/periodic', PeriodicSnapshotSchema.array(), 'GET'); +} + +export async function createPeriodicSnapshot( + dataset: Dataset, + prefix: string, + recursive: boolean, + interval: number +): Promise { + return await apiRequest('/zfs/datasets/snapshot/periodic', APIResponseSchema, 'POST', { + guid: dataset.properties.guid, + prefix: prefix, + recursive: recursive, + interval: interval + }); +} + +export async function deletePeriodicSnapshot(guid: string): Promise { + return await apiRequest(`/zfs/datasets/snapshot/periodic/${guid}`, APIResponseSchema, 'DELETE'); +} + +export async function createFileSystem( + name: string, + parent: string, + properties: Record +): Promise { + return await apiRequest('/zfs/datasets/filesystem', APIResponseSchema, 'POST', { + name: name, + parent: parent, + properties: properties + }); +} + +export async function deleteFileSystem(dataset: Dataset): Promise { + return await apiRequest( + `/zfs/datasets/filesystem/${dataset.properties.guid}`, + APIResponseSchema, + 'DELETE' + ); +} + +export async function rollbackSnapshot(guid: string): Promise { + return await apiRequest(`/zfs/datasets/snapshot/rollback`, APIResponseSchema, 'POST', { + guid: guid, + destroyMoreRecent: true + }); +} + +export async function createVolume( + name: string, + parent: string, + props: Record +): Promise { + return await apiRequest('/zfs/datasets/volume', APIResponseSchema, 'POST', { + name: name, + parent: parent, + properties: props + }); +} + +export async function deleteVolume(dataset: Dataset): Promise { + return await apiRequest( + `/zfs/datasets/volume/${dataset.properties.guid}`, + APIResponseSchema, + 'DELETE' + ); +} + +export async function bulkDelete(datasets: Dataset[]): Promise { + const guids = datasets.map((dataset) => dataset.properties.guid); + return await apiRequest('/zfs/datasets/bulk-delete', APIResponseSchema, 'POST', { + guids: guids + }); +} diff --git a/new-web/src/lib/api/zfs/pool.ts b/new-web/src/lib/api/zfs/pool.ts new file mode 100644 index 00000000..b36c35d3 --- /dev/null +++ b/new-web/src/lib/api/zfs/pool.ts @@ -0,0 +1,77 @@ +import { APIResponseSchema, type APIResponse } from '$lib/types/common'; +import { + IODelayHistoricalSchema, + IODelaySchema, + PoolStatPointsResponseSchema, + ZpoolSchema, + type CreateZpool, + type IODelay, + type IODelayHistorical, + type PoolStatPointsResponse, + type ReplaceDevice, + type Zpool +} from '$lib/types/zfs/pool'; +import { apiRequest } from '$lib/utils/http'; +import type { QueryFunctionContext } from '@sveltestack/svelte-query'; + +export async function getIODelay( + queryObj: QueryFunctionContext | undefined +): Promise { + if (queryObj) { + if (queryObj.queryKey.includes('ioDelayHistorical')) { + const data = await apiRequest( + '/zfs/pool/io-delay/historical', + IODelayHistoricalSchema, + 'GET' + ); + return IODelayHistoricalSchema.parse(data); + } + } + + return await apiRequest('/zfs/pool/io-delay', IODelaySchema, 'GET'); +} + +export async function getPools(): Promise { + return await apiRequest('/zfs/pools', ZpoolSchema.array(), 'GET'); +} + +export async function createPool(data: CreateZpool) { + return await apiRequest('/zfs/pools', APIResponseSchema, 'POST', { + ...data + }); +} + +export async function replaceDevice(data: ReplaceDevice) { + return await apiRequest(`/zfs/pools/${data.name}/replace-device`, APIResponseSchema, 'POST', { + ...data + }); +} + +export async function deletePool(name: string) { + return await apiRequest(`/zfs/pools/${name}`, APIResponseSchema, 'DELETE'); +} + +export async function scrubPool(name: string) { + return await apiRequest(`/zfs/pools/${name}/scrub`, APIResponseSchema, 'POST'); +} + +export async function getPoolStats( + interval: number, + limit: number +): Promise { + return await apiRequest( + `/zfs/pool/stats/${interval}/${limit}`, + PoolStatPointsResponseSchema, + 'GET' + ); +} + +export async function editPool( + name: string, + properties: Record +): Promise { + return await apiRequest(`/zfs/pools`, APIResponseSchema, 'PATCH', { + name, + properties + }); +} diff --git a/new-web/src/lib/api/zfs/volumes.ts b/new-web/src/lib/api/zfs/volumes.ts new file mode 100644 index 00000000..e69de29b diff --git a/new-web/src/lib/components/custom/AlertDialog.svelte b/new-web/src/lib/components/custom/AlertDialog.svelte new file mode 100644 index 00000000..71a35c07 --- /dev/null +++ b/new-web/src/lib/components/custom/AlertDialog.svelte @@ -0,0 +1,42 @@ + + + + + + {getTranslation('are_you_sure', 'Are you sure?')} + + {#if customTitle} + {@html customTitle} + {:else} + {getTranslation( + 'common.permanent_delete_msg', + 'This action cannot be undone. This will permanently delete' + )} + {names.parent} {names.element}. + {/if} + + + + Cancel + Continue + + + diff --git a/new-web/src/lib/components/custom/BarChart.svelte b/new-web/src/lib/components/custom/BarChart.svelte new file mode 100644 index 00000000..00c0bd3b --- /dev/null +++ b/new-web/src/lib/components/custom/BarChart.svelte @@ -0,0 +1,92 @@ + + +
+ + + humanFormat(d)} + rule={{ + class: 'stroke-border dark:stroke-border' + }} + ticks={2} + /> + + + + + + + + {data.name} + + + + + + + +
diff --git a/new-web/src/lib/components/custom/CreateVM/Advanced.svelte b/new-web/src/lib/components/custom/CreateVM/Advanced.svelte new file mode 100644 index 00000000..3407f2e8 --- /dev/null +++ b/new-web/src/lib/components/custom/CreateVM/Advanced.svelte @@ -0,0 +1,112 @@ + + +
+
+ + +
+ +
+ + + +
+
+
+ + + +
+ + + + + +
+
diff --git a/new-web/src/lib/components/custom/CreateVM/Basic.svelte b/new-web/src/lib/components/custom/CreateVM/Basic.svelte new file mode 100644 index 00000000..94625d75 --- /dev/null +++ b/new-web/src/lib/components/custom/CreateVM/Basic.svelte @@ -0,0 +1,39 @@ + + +
+
+ + + +
+ + +
diff --git a/new-web/src/lib/components/custom/CreateVM/CreateVM.svelte b/new-web/src/lib/components/custom/CreateVM/CreateVM.svelte new file mode 100644 index 00000000..b14a3130 --- /dev/null +++ b/new-web/src/lib/components/custom/CreateVM/CreateVM.svelte @@ -0,0 +1,298 @@ + + + + +
+ + +
+ + Create Virtual Machine +
+

+ Configure your virtual machine with custom hardware and network settings +

+
+
+ +
+ + +
+
+ + + + {#each tabs as { value, label }} + {label} + {/each} + + + {#each tabs as { value, label }} + +
+ {#if value === 'basic'} + + {:else if value === 'storage'} + + {:else if value === 'network'} + + {:else if value === 'hardware'} + + {:else if value === 'advanced'} + + {/if} +
+
+ {/each} +
+ + +
+ +
+
+
+
diff --git a/new-web/src/lib/components/custom/CreateVM/Hardware.svelte b/new-web/src/lib/components/custom/CreateVM/Hardware.svelte new file mode 100644 index 00000000..dbc92ff4 --- /dev/null +++ b/new-web/src/lib/components/custom/CreateVM/Hardware.svelte @@ -0,0 +1,119 @@ + + +
+
+ + + + +
+ + {#if pptDevices && pptDevices.length > 0} +

PCI Passthrough

+
+ + {#each checkboxItems as item (item.pptId)} +
+
+ { + if (typeof v === 'boolean') toggle(item.pptId, v); + }} + /> +
+ +

+ pci{item.device.domain}:{item.device.bus}:{item.device.device}:{item.device + .function} +

+
+
+
+ {/each} +
+
+ {/if} +
diff --git a/new-web/src/lib/components/custom/CreateVM/Network.svelte b/new-web/src/lib/components/custom/CreateVM/Network.svelte new file mode 100644 index 00000000..b05f5ef8 --- /dev/null +++ b/new-web/src/lib/components/custom/CreateVM/Network.svelte @@ -0,0 +1,95 @@ + + +{#snippet radioItem(id: number, name: string)} + {@const i = `radio-${id}`} +
+ + +
+{/snippet} + +
+ + + {#if switches && switches.standard} + {#each switches.standard ?? [] as sw} + {@render radioItem(sw.id, sw.name)} + {/each} + {/if} + {@render radioItem(0, 'None')} + + + + {#if swStr !== '0'} +
+ + + +
+ {/if} +
diff --git a/new-web/src/lib/components/custom/CreateVM/Storage.svelte b/new-web/src/lib/components/custom/CreateVM/Storage.svelte new file mode 100644 index 00000000..c41434a9 --- /dev/null +++ b/new-web/src/lib/components/custom/CreateVM/Storage.svelte @@ -0,0 +1,230 @@ + + +{#snippet radioItem(type: string)} +
+ + +
+{/snippet} + +{#snippet storageDetail(type: string)} + {#if type === 'zvol'} + + {/if} + + {#if type === 'raw'} +
+ + + +
+ {/if} + + +{/snippet} + +
+ + + {#each ['zvol', 'raw', 'none'] as storageType} + {@render radioItem(storageType)} + {/each} + + + + {#if type !== 'none'} + {@render storageDetail(type)} + {/if} + + +
diff --git a/new-web/src/lib/components/custom/Header.svelte b/new-web/src/lib/components/custom/Header.svelte new file mode 100644 index 00000000..2c823ea6 --- /dev/null +++ b/new-web/src/lib/components/custom/Header.svelte @@ -0,0 +1,181 @@ + + +
+ + + + + + + + + + +
+ + + + + + + + + + + {#each menuData.menuItems as { icon, label, shortcut }} + label === 'Color Theme' && toggleMode()} + > + + {label} + {#if shortcut} + {shortcut} + {/if} + + {/each} + + + + logOut()}> + + Log out + ⌘⇧Q + + + +
+
diff --git a/new-web/src/lib/components/custom/KVTableModal.svelte b/new-web/src/lib/components/custom/KVTableModal.svelte new file mode 100644 index 00000000..4c24f5d6 --- /dev/null +++ b/new-web/src/lib/components/custom/KVTableModal.svelte @@ -0,0 +1,129 @@ + + + + +
+
+ {#if titles.icon} + + {/if} +

{titles.main}

+
+ + + + +
+ +
+ + + + {#if tableHeaders.length > 0} + {#each tableHeaders as header} + {header} + {/each} + {:else} + {titles.key} + {titles.value} + {/if} + + + + + {#if tableHeaders.length > 0} + {#each KV as Array> as row} + + {#each tableHeaders as header} + {row[header]} + {/each} + + {/each} + {:else} + {#each Object.entries(KV) as [key, value]} + {#if typeof value === 'object' && value !== null && !Array.isArray(value)} + + + + + + Object ({Object.keys(value).length} properties) + + + {#if expandedObjects[key]} + {#each Object.entries(value) as [nestedKey, nestedValue]} + + + {nestedKey} + + + {nestedValue} + + + {/each} + {/if} + {:else} + + {key} + {value} + + {/if} + {/each} + {/if} + + +
+
+
diff --git a/new-web/src/lib/components/custom/KeyValueTable.svelte b/new-web/src/lib/components/custom/KeyValueTable.svelte new file mode 100644 index 00000000..e575b574 --- /dev/null +++ b/new-web/src/lib/components/custom/KeyValueTable.svelte @@ -0,0 +1,17 @@ + + + + + + {#each data as item, i (i)} + + {item.key} + {item.value} + + {/each} + + diff --git a/new-web/src/lib/components/custom/LineGraph.svelte b/new-web/src/lib/components/custom/LineGraph.svelte new file mode 100644 index 00000000..cf758bec --- /dev/null +++ b/new-web/src/lib/components/custom/LineGraph.svelte @@ -0,0 +1,91 @@ + + + + + formatWithTimeZone(d, interval ? dateFormatString : 'hh:mm a')} + /> + String(formatValue(d, unformattedKeys, valueType))} + /> + + + + + {formatWithTimeZone(data.date, interval ? dateFormatString : 'hh:mm a')} + + + {#each Object.entries(data).filter(([key]) => key !== 'date') as [key, value]} + s.key === key)?.label || key} + value={formatValue(Number(value), unformattedKeys, valueType)} + color={series.find((s) => s.key === key)?.color || 'pink'} + /> + {/each} + + + + diff --git a/new-web/src/lib/components/custom/LoadingDialog.svelte b/new-web/src/lib/components/custom/LoadingDialog.svelte new file mode 100644 index 00000000..13ad5567 --- /dev/null +++ b/new-web/src/lib/components/custom/LoadingDialog.svelte @@ -0,0 +1,25 @@ + + + + + + {title} + + + {@html description} + + + + diff --git a/new-web/src/lib/components/custom/Login.svelte b/new-web/src/lib/components/custom/Login.svelte new file mode 100644 index 00000000..3767ba7e --- /dev/null +++ b/new-web/src/lib/components/custom/Login.svelte @@ -0,0 +1,152 @@ + + +
+ + + {#if mode.current === 'dark'} + Sylve Logo + {:else} + Sylve Logo + {/if} +

SYLVE

+
+ + +
+ + +
+
+ + +
+ +
+ + + + {authTypeValue} + + + {$_('auth.pam')} + {$_('auth.sylve')} + + +
+ +
+ + + + {languageValue} + + + English + Malayalam + + +
+
+ + +
+ + +
+ +
+
+
diff --git a/new-web/src/lib/components/custom/PieChart.svelte b/new-web/src/lib/components/custom/PieChart.svelte new file mode 100644 index 00000000..6827401f --- /dev/null +++ b/new-web/src/lib/components/custom/PieChart.svelte @@ -0,0 +1,34 @@ + + +
+ d.color)} + renderContext="svg" + legend + > + + + + + + + +
diff --git a/new-web/src/lib/components/custom/Terminal.svelte b/new-web/src/lib/components/custom/Terminal.svelte new file mode 100644 index 00000000..1e3d22c2 --- /dev/null +++ b/new-web/src/lib/components/custom/Terminal.svelte @@ -0,0 +1,274 @@ + + + + +{#if $terminalStore.isOpen && !$terminalStore.isMinimized} +
+
+
+
+ +
+ {$terminalStore.title} +
+ +
+ + +
+
+ + +
+ {#each $terminalStore.tabs as tab} +
visiblityAction('tab-select', tab.id)} + onkeydown={(e) => + (e.key === 'Enter' || e.key === ' ') && visiblityAction('tab-select', tab.id)} + role="button" + tabindex="0" + > + {tab.title} + {#if tabsCount > 1} + + {/if} +
+ {/each} +
+ +
+
+ + +
+ {#each $terminalStore.tabs as tab} + {#if tab.id === $terminalStore.activeTabId} +
+ +
+ {/if} + {/each} +
+
+
+{/if} diff --git a/new-web/src/lib/components/custom/Throbber.svelte b/new-web/src/lib/components/custom/Throbber.svelte new file mode 100644 index 00000000..64ec04e2 --- /dev/null +++ b/new-web/src/lib/components/custom/Throbber.svelte @@ -0,0 +1,195 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+ SYLVE +

+
+ + diff --git a/new-web/src/lib/components/custom/TreeTable.svelte b/new-web/src/lib/components/custom/TreeTable.svelte new file mode 100644 index 00000000..4a83f238 --- /dev/null +++ b/new-web/src/lib/components/custom/TreeTable.svelte @@ -0,0 +1,158 @@ + + +
diff --git a/new-web/src/lib/components/custom/TreeTable/Search.svelte b/new-web/src/lib/components/custom/TreeTable/Search.svelte new file mode 100644 index 00000000..a9420569 --- /dev/null +++ b/new-web/src/lib/components/custom/TreeTable/Search.svelte @@ -0,0 +1,64 @@ + + +
+
+ + + {#if expanded} + { + if (e.key === 'Escape') { + query = ''; + expanded = false; + } + }} + /> + {/if} +
+
diff --git a/new-web/src/lib/components/custom/TreeView.svelte b/new-web/src/lib/components/custom/TreeView.svelte new file mode 100644 index 00000000..e4a8caa1 --- /dev/null +++ b/new-web/src/lib/components/custom/TreeView.svelte @@ -0,0 +1,100 @@ + + +
  • + +
    + +

    + {getTranslation(`node.${item.label}`, item.label)} +

    +
    + {#if item.children} + + {/if} +
    +
  • + +{#if isOpen && item.children} +
      t }} style="overflow: hidden;"> + {#each item.children as child} + + {/each} +
    +{/if} diff --git a/new-web/src/lib/components/disk/CreatePartition.svelte b/new-web/src/lib/components/disk/CreatePartition.svelte new file mode 100644 index 00000000..f3780fa8 --- /dev/null +++ b/new-web/src/lib/components/disk/CreatePartition.svelte @@ -0,0 +1,278 @@ + + + close()}> + +
    + + Create Partitions + + + +
    + + +
    +
    + +
    + + + + Name + Size + Usage + Actions + + + + {#if disk && disk.partitions && disk.partitions.length > 0} + {#each disk.partitions as partition} + + {partition.name} + {humanFormat(partition.size)} + {partition.usage} + + Existing + + + {/each} + {/if} + + {#if newPartitions.length > 0} + {#each newPartitions as partition, index} + + {partition.name} + {humanFormat(partition.size)} + - + + + + + {/each} + {/if} + + {#if (!disk || !disk.partitions || disk.partitions.length === 0) && newPartitions.length === 0} + + + No partitions created yet + + + {/if} + + +
    + +
    +
    +
    + { + const value = Math.floor(e[0]); + currentPartition = value <= 0 ? 0 : value; + currentPartitionInput = humanFormat(currentPartition); + }} + /> +
    + + + +
    0 ? '' : 'cursor-not-allowed'}> + +
    +
    + +
    +

    + Size: {humanFormat(currentPartition)} +

    +

    + Remaining space: {humanFormat(remainingSpace)} +

    +
    +
    + {#if newPartitions.length > 0} +
    + +
    + +
    +
    +
    + {/if} +
    +
    diff --git a/new-web/src/lib/components/skeleton/BottomPanel.svelte b/new-web/src/lib/components/skeleton/BottomPanel.svelte new file mode 100644 index 00000000..93093a87 --- /dev/null +++ b/new-web/src/lib/components/skeleton/BottomPanel.svelte @@ -0,0 +1,66 @@ + + + + +
    + + + + Start Time + End Time + Node + User + Action + Status + + + + + {#each logs as log, i (i)} + + {convertDbTime(log.started)} + {convertDbTime(log.ended)} + {log.node} + {log.user}@{log.authType} + {formatAction(log.action)} + {formatStatus(log.status)} + + {/each} + + +
    +
    +
    diff --git a/new-web/src/lib/components/skeleton/LeftPanel.svelte b/new-web/src/lib/components/skeleton/LeftPanel.svelte new file mode 100644 index 00000000..9d82a4c2 --- /dev/null +++ b/new-web/src/lib/components/skeleton/LeftPanel.svelte @@ -0,0 +1,62 @@ + + +
    + +
    diff --git a/new-web/src/lib/components/skeleton/Shell.svelte b/new-web/src/lib/components/skeleton/Shell.svelte new file mode 100644 index 00000000..b403b760 --- /dev/null +++ b/new-web/src/lib/components/skeleton/Shell.svelte @@ -0,0 +1,52 @@ + + +
    +
    +
    +
    + + + + + + + + + + + {@render children?.()} + + + + + + + + + + +
    + + +
    +
    diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte new file mode 100644 index 00000000..a0056912 --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte @@ -0,0 +1,18 @@ + + + diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte new file mode 100644 index 00000000..a7b0cf79 --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte @@ -0,0 +1,18 @@ + + + diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte new file mode 100644 index 00000000..6c3c6046 --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte @@ -0,0 +1,27 @@ + + + + + + diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte new file mode 100644 index 00000000..2ec67dc2 --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte @@ -0,0 +1,17 @@ + + + diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte new file mode 100644 index 00000000..f78b97ab --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte new file mode 100644 index 00000000..c8fa7625 --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte new file mode 100644 index 00000000..a64ee768 --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte @@ -0,0 +1,20 @@ + + + diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte new file mode 100644 index 00000000..7ef2b5fb --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte @@ -0,0 +1,17 @@ + + + diff --git a/new-web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte new file mode 100644 index 00000000..b22d1d50 --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/new-web/src/lib/components/ui/alert-dialog/index.ts b/new-web/src/lib/components/ui/alert-dialog/index.ts new file mode 100644 index 00000000..cc281c58 --- /dev/null +++ b/new-web/src/lib/components/ui/alert-dialog/index.ts @@ -0,0 +1,39 @@ +import { AlertDialog as AlertDialogPrimitive } from "bits-ui"; +import Trigger from "./alert-dialog-trigger.svelte"; +import Title from "./alert-dialog-title.svelte"; +import Action from "./alert-dialog-action.svelte"; +import Cancel from "./alert-dialog-cancel.svelte"; +import Footer from "./alert-dialog-footer.svelte"; +import Header from "./alert-dialog-header.svelte"; +import Overlay from "./alert-dialog-overlay.svelte"; +import Content from "./alert-dialog-content.svelte"; +import Description from "./alert-dialog-description.svelte"; + +const Root = AlertDialogPrimitive.Root; +const Portal = AlertDialogPrimitive.Portal; + +export { + Root, + Title, + Action, + Cancel, + Portal, + Footer, + Header, + Trigger, + Overlay, + Content, + Description, + // + Root as AlertDialog, + Title as AlertDialogTitle, + Action as AlertDialogAction, + Cancel as AlertDialogCancel, + Portal as AlertDialogPortal, + Footer as AlertDialogFooter, + Header as AlertDialogHeader, + Trigger as AlertDialogTrigger, + Overlay as AlertDialogOverlay, + Content as AlertDialogContent, + Description as AlertDialogDescription, +}; diff --git a/new-web/src/lib/components/ui/badge/badge.svelte b/new-web/src/lib/components/ui/badge/badge.svelte new file mode 100644 index 00000000..50004570 --- /dev/null +++ b/new-web/src/lib/components/ui/badge/badge.svelte @@ -0,0 +1,50 @@ + + + + + + {@render children?.()} + diff --git a/new-web/src/lib/components/ui/badge/index.ts b/new-web/src/lib/components/ui/badge/index.ts new file mode 100644 index 00000000..64e0aa9b --- /dev/null +++ b/new-web/src/lib/components/ui/badge/index.ts @@ -0,0 +1,2 @@ +export { default as Badge } from "./badge.svelte"; +export { badgeVariants, type BadgeVariant } from "./badge.svelte"; diff --git a/new-web/src/lib/components/ui/card/card-action.svelte b/new-web/src/lib/components/ui/card/card-action.svelte new file mode 100644 index 00000000..cc36c566 --- /dev/null +++ b/new-web/src/lib/components/ui/card/card-action.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/new-web/src/lib/components/ui/card/card-content.svelte b/new-web/src/lib/components/ui/card/card-content.svelte new file mode 100644 index 00000000..bc90b837 --- /dev/null +++ b/new-web/src/lib/components/ui/card/card-content.svelte @@ -0,0 +1,15 @@ + + +
    + {@render children?.()} +
    diff --git a/new-web/src/lib/components/ui/card/card-description.svelte b/new-web/src/lib/components/ui/card/card-description.svelte new file mode 100644 index 00000000..9b20ac70 --- /dev/null +++ b/new-web/src/lib/components/ui/card/card-description.svelte @@ -0,0 +1,20 @@ + + +

    + {@render children?.()} +

    diff --git a/new-web/src/lib/components/ui/card/card-footer.svelte b/new-web/src/lib/components/ui/card/card-footer.svelte new file mode 100644 index 00000000..cf433539 --- /dev/null +++ b/new-web/src/lib/components/ui/card/card-footer.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/new-web/src/lib/components/ui/card/card-header.svelte b/new-web/src/lib/components/ui/card/card-header.svelte new file mode 100644 index 00000000..8a91abbf --- /dev/null +++ b/new-web/src/lib/components/ui/card/card-header.svelte @@ -0,0 +1,23 @@ + + +
    + {@render children?.()} +
    diff --git a/new-web/src/lib/components/ui/card/card-title.svelte b/new-web/src/lib/components/ui/card/card-title.svelte new file mode 100644 index 00000000..22586e61 --- /dev/null +++ b/new-web/src/lib/components/ui/card/card-title.svelte @@ -0,0 +1,20 @@ + + +
    + {@render children?.()} +
    diff --git a/new-web/src/lib/components/ui/card/card.svelte b/new-web/src/lib/components/ui/card/card.svelte new file mode 100644 index 00000000..99448cc9 --- /dev/null +++ b/new-web/src/lib/components/ui/card/card.svelte @@ -0,0 +1,23 @@ + + +
    + {@render children?.()} +
    diff --git a/new-web/src/lib/components/ui/card/index.ts b/new-web/src/lib/components/ui/card/index.ts new file mode 100644 index 00000000..4d3fce48 --- /dev/null +++ b/new-web/src/lib/components/ui/card/index.ts @@ -0,0 +1,25 @@ +import Root from "./card.svelte"; +import Content from "./card-content.svelte"; +import Description from "./card-description.svelte"; +import Footer from "./card-footer.svelte"; +import Header from "./card-header.svelte"; +import Title from "./card-title.svelte"; +import Action from "./card-action.svelte"; + +export { + Root, + Content, + Description, + Footer, + Header, + Title, + Action, + // + Root as Card, + Content as CardContent, + Description as CardDescription, + Footer as CardFooter, + Header as CardHeader, + Title as CardTitle, + Action as CardAction, +}; diff --git a/new-web/src/lib/components/ui/checkbox/checkbox.svelte b/new-web/src/lib/components/ui/checkbox/checkbox.svelte new file mode 100644 index 00000000..1622e05c --- /dev/null +++ b/new-web/src/lib/components/ui/checkbox/checkbox.svelte @@ -0,0 +1,36 @@ + + + + {#snippet children({ checked, indeterminate })} +
    + {#if checked} + + {:else if indeterminate} + + {/if} +
    + {/snippet} +
    diff --git a/new-web/src/lib/components/ui/checkbox/index.ts b/new-web/src/lib/components/ui/checkbox/index.ts new file mode 100644 index 00000000..6d92d945 --- /dev/null +++ b/new-web/src/lib/components/ui/checkbox/index.ts @@ -0,0 +1,6 @@ +import Root from "./checkbox.svelte"; +export { + Root, + // + Root as Checkbox, +}; diff --git a/new-web/src/lib/components/ui/command/command-dialog.svelte b/new-web/src/lib/components/ui/command/command-dialog.svelte new file mode 100644 index 00000000..5c9a82a8 --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-dialog.svelte @@ -0,0 +1,40 @@ + + + + + {title} + {description} + + + + + diff --git a/new-web/src/lib/components/ui/command/command-empty.svelte b/new-web/src/lib/components/ui/command/command-empty.svelte new file mode 100644 index 00000000..6726cd8d --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-empty.svelte @@ -0,0 +1,17 @@ + + + diff --git a/new-web/src/lib/components/ui/command/command-group.svelte b/new-web/src/lib/components/ui/command/command-group.svelte new file mode 100644 index 00000000..104f8170 --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-group.svelte @@ -0,0 +1,32 @@ + + + + {#if heading} + + {heading} + + {/if} + + diff --git a/new-web/src/lib/components/ui/command/command-input.svelte b/new-web/src/lib/components/ui/command/command-input.svelte new file mode 100644 index 00000000..240278a6 --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-input.svelte @@ -0,0 +1,26 @@ + + +
    + + +
    diff --git a/new-web/src/lib/components/ui/command/command-item.svelte b/new-web/src/lib/components/ui/command/command-item.svelte new file mode 100644 index 00000000..2297c978 --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-item.svelte @@ -0,0 +1,20 @@ + + + diff --git a/new-web/src/lib/components/ui/command/command-link-item.svelte b/new-web/src/lib/components/ui/command/command-link-item.svelte new file mode 100644 index 00000000..944c22dc --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-link-item.svelte @@ -0,0 +1,20 @@ + + + diff --git a/new-web/src/lib/components/ui/command/command-list.svelte b/new-web/src/lib/components/ui/command/command-list.svelte new file mode 100644 index 00000000..569f5957 --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-list.svelte @@ -0,0 +1,17 @@ + + + diff --git a/new-web/src/lib/components/ui/command/command-separator.svelte b/new-web/src/lib/components/ui/command/command-separator.svelte new file mode 100644 index 00000000..35c4c957 --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-separator.svelte @@ -0,0 +1,17 @@ + + + diff --git a/new-web/src/lib/components/ui/command/command-shortcut.svelte b/new-web/src/lib/components/ui/command/command-shortcut.svelte new file mode 100644 index 00000000..3d68bc56 --- /dev/null +++ b/new-web/src/lib/components/ui/command/command-shortcut.svelte @@ -0,0 +1,20 @@ + + + + {@render children?.()} + diff --git a/new-web/src/lib/components/ui/command/command.svelte b/new-web/src/lib/components/ui/command/command.svelte new file mode 100644 index 00000000..c64a77ef --- /dev/null +++ b/new-web/src/lib/components/ui/command/command.svelte @@ -0,0 +1,22 @@ + + + diff --git a/new-web/src/lib/components/ui/command/index.ts b/new-web/src/lib/components/ui/command/index.ts new file mode 100644 index 00000000..d3dbadea --- /dev/null +++ b/new-web/src/lib/components/ui/command/index.ts @@ -0,0 +1,40 @@ +import { Command as CommandPrimitive } from "bits-ui"; + +import Root from "./command.svelte"; +import Dialog from "./command-dialog.svelte"; +import Empty from "./command-empty.svelte"; +import Group from "./command-group.svelte"; +import Item from "./command-item.svelte"; +import Input from "./command-input.svelte"; +import List from "./command-list.svelte"; +import Separator from "./command-separator.svelte"; +import Shortcut from "./command-shortcut.svelte"; +import LinkItem from "./command-link-item.svelte"; + +const Loading = CommandPrimitive.Loading; + +export { + Root, + Dialog, + Empty, + Group, + Item, + LinkItem, + Input, + List, + Separator, + Shortcut, + Loading, + // + Root as Command, + Dialog as CommandDialog, + Empty as CommandEmpty, + Group as CommandGroup, + Item as CommandItem, + LinkItem as CommandLinkItem, + Input as CommandInput, + List as CommandList, + Separator as CommandSeparator, + Shortcut as CommandShortcut, + Loading as CommandLoading, +}; diff --git a/new-web/src/lib/components/ui/custom-input/checkbox.svelte b/new-web/src/lib/components/ui/custom-input/checkbox.svelte new file mode 100644 index 00000000..9048903b --- /dev/null +++ b/new-web/src/lib/components/ui/custom-input/checkbox.svelte @@ -0,0 +1,30 @@ + + +
    + + +
    diff --git a/new-web/src/lib/components/ui/custom-input/combobox.svelte b/new-web/src/lib/components/ui/custom-input/combobox.svelte new file mode 100644 index 00000000..5ebc232d --- /dev/null +++ b/new-web/src/lib/components/ui/custom-input/combobox.svelte @@ -0,0 +1,145 @@ + + +
    + + + + + + + + + + No data +
    + + {#each filteredData as element} + selectItem(element.value)} + onkeydown={(e) => { + if (e.key === 'Enter') selectItem(element.value); + }} + > + + {element.label} + + {/each} + +
    +
    +
    +
    +
    diff --git a/new-web/src/lib/components/ui/custom-input/value.svelte b/new-web/src/lib/components/ui/custom-input/value.svelte new file mode 100644 index 00000000..80b4b564 --- /dev/null +++ b/new-web/src/lib/components/ui/custom-input/value.svelte @@ -0,0 +1,49 @@ + + +
    + {#if label} + + {/if} + {#if type === 'textarea'} + diff --git a/new-web/src/lib/components/ui/tooltip/index.ts b/new-web/src/lib/components/ui/tooltip/index.ts new file mode 100644 index 00000000..313a7f06 --- /dev/null +++ b/new-web/src/lib/components/ui/tooltip/index.ts @@ -0,0 +1,21 @@ +import { Tooltip as TooltipPrimitive } from "bits-ui"; +import Trigger from "./tooltip-trigger.svelte"; +import Content from "./tooltip-content.svelte"; + +const Root = TooltipPrimitive.Root; +const Provider = TooltipPrimitive.Provider; +const Portal = TooltipPrimitive.Portal; + +export { + Root, + Trigger, + Content, + Provider, + Portal, + // + Root as Tooltip, + Content as TooltipContent, + Trigger as TooltipTrigger, + Provider as TooltipProvider, + Portal as TooltipPortal, +}; diff --git a/new-web/src/lib/components/ui/tooltip/tooltip-content.svelte b/new-web/src/lib/components/ui/tooltip/tooltip-content.svelte new file mode 100644 index 00000000..b0c399ca --- /dev/null +++ b/new-web/src/lib/components/ui/tooltip/tooltip-content.svelte @@ -0,0 +1,47 @@ + + + + + {@render children?.()} + + {#snippet child({ props })} +
    + {/snippet} +
    +
    +
    diff --git a/new-web/src/lib/components/ui/tooltip/tooltip-trigger.svelte b/new-web/src/lib/components/ui/tooltip/tooltip-trigger.svelte new file mode 100644 index 00000000..1acdaa47 --- /dev/null +++ b/new-web/src/lib/components/ui/tooltip/tooltip-trigger.svelte @@ -0,0 +1,7 @@ + + + diff --git a/new-web/src/lib/components/zfs/ViewSnapshotJobs.svelte b/new-web/src/lib/components/zfs/ViewSnapshotJobs.svelte new file mode 100644 index 00000000..8cb088e1 --- /dev/null +++ b/new-web/src/lib/components/zfs/ViewSnapshotJobs.svelte @@ -0,0 +1,156 @@ + + + close()}> + +
    + + +
    + + View Snapshot Jobs +
    +
    + +
    + + close()} + > + + +
    + +
    + + + + ID + Dataset + Prefix + Interval + Last Run + + + + + {#if periodicSnapshots && periodicSnapshots.length > 0} + {#each periodicSnapshots as snapshot, index} + + {snapshot.id} + {getDatasetName(snapshot.guid)} + {snapshot.prefix} + {intervalToString(snapshot.interval)} + {dateToAgo(snapshot.lastRunAt)} + + {#if !shadowDeleted.includes(snapshot.id)} + + + + {:else} + + Deleted + + {/if} + + {/each} + {:else} + + + No snapshot jobs + + + {/if} + + +
    + + +
    + + {#if shadowDeleted.length > 0} + + {/if} +
    +
    +
    +
    diff --git a/new-web/src/lib/utils/http.ts b/new-web/src/lib/utils/http.ts index 6e1c3b62..9c562691 100644 --- a/new-web/src/lib/utils/http.ts +++ b/new-web/src/lib/utils/http.ts @@ -12,132 +12,132 @@ import { api } from '$lib/api/common'; import { APIResponseSchema, type APIResponse } from '$lib/types/common'; import type { QueryFunctionContext } from '@sveltestack/svelte-query'; import adze from 'adze'; -import toast from 'svelte-french-toast'; +import { toast } from "svelte-sonner"; import { z } from 'zod/v4'; import { getValidationError } from './i18n'; export async function apiRequest( - endpoint: string, - schema: T, - method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH', - body?: unknown + endpoint: string, + schema: T, + method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH', + body?: unknown ): Promise> { - try { - const config = { - method, - url: endpoint, - ...(body ? { data: body } : {}) - }; + try { + const config = { + method, + url: endpoint, + ...(body ? { data: body } : {}) + }; - const response = await api.request({ ...config, validateStatus: () => true }); - const apiResponse = APIResponseSchema.safeParse(response.data); + const response = await api.request({ ...config, validateStatus: () => true }); + const apiResponse = APIResponseSchema.safeParse(response.data); - /* Couldn't parse response data into APIResponse so we'll just return the data? */ - if (!apiResponse.success) { - return apiResponse.data; - } + /* Couldn't parse response data into APIResponse so we'll just return the data? */ + if (!apiResponse.success) { + return apiResponse.data; + } - /* Caller asked for a raw response */ - if (schema._def.description === 'APIResponseSchema') { - return apiResponse.data as z.infer; - } + /* Caller asked for a raw response */ + if (schema._def.description === 'APIResponseSchema') { + return apiResponse.data as z.infer; + } - if (apiResponse.data.data) { - const parsedResult = schema.safeParse(apiResponse.data.data); - if (parsedResult.success) { - return parsedResult.data; - } else { - // console.log('Validation Error', parsedResult.error); - adze.withEmoji.warn('Zod Validation Error', parsedResult.error); - return getDefaultValue(schema, apiResponse.data); - } - } + if (apiResponse.data.data) { + const parsedResult = schema.safeParse(apiResponse.data.data); + if (parsedResult.success) { + return parsedResult.data; + } else { + // console.log('Validation Error', parsedResult.error); + adze.withEmoji.warn('Zod Validation Error', parsedResult.error); + return getDefaultValue(schema, apiResponse.data); + } + } - return getDefaultValue(schema, apiResponse.data); - } catch (error) { - return getDefaultValue(schema, { status: 'error' }); - } + return getDefaultValue(schema, apiResponse.data); + } catch (error) { + return getDefaultValue(schema, { status: 'error' }); + } } function getDefaultValue(schema: T, response: APIResponse): z.infer { - if (schema instanceof z.ZodArray) { - return [] as z.infer; - } + if (schema instanceof z.ZodArray) { + return [] as z.infer; + } - if (schema instanceof z.ZodObject) { - return response as z.infer; - } + if (schema instanceof z.ZodObject) { + return response as z.infer; + } - return undefined as z.infer; + return undefined as z.infer; } type CacheEntry = { - timestamp: number; - data: T; + timestamp: number; + data: T; }; export async function cachedFetch( - key: string, - fetchFunction: (queryObj?: QueryFunctionContext) => Promise, - duration: number + key: string, + fetchFunction: (queryObj?: QueryFunctionContext) => Promise, + duration: number ): Promise { - const now = Date.now(); - const storedEntry = localStorage.getItem(key); + const now = Date.now(); + const storedEntry = localStorage.getItem(key); - if (storedEntry) { - try { - const entry: CacheEntry = JSON.parse(storedEntry); - if (now - entry.timestamp < duration) { - return entry.data; - } - } catch (error) { - console.error(`Failed to parse cached data for key "${key}"`, error); - } - } + if (storedEntry) { + try { + const entry: CacheEntry = JSON.parse(storedEntry); + if (now - entry.timestamp < duration) { + return entry.data; + } + } catch (error) { + console.error(`Failed to parse cached data for key "${key}"`, error); + } + } - const data = await fetchFunction(); - const entry: CacheEntry = { timestamp: now, data }; - localStorage.setItem(key, JSON.stringify(entry)); - return data; + const data = await fetchFunction(); + const entry: CacheEntry = { timestamp: now, data }; + localStorage.setItem(key, JSON.stringify(entry)); + return data; } export async function updateCache(key: string, obj: T): Promise { - const now = Date.now(); - const storedEntry = localStorage.getItem(key); + const now = Date.now(); + const storedEntry = localStorage.getItem(key); - if (storedEntry) { - try { - const entry: CacheEntry = JSON.parse(storedEntry); - entry.data = obj; - entry.timestamp = now; - localStorage.setItem(key, JSON.stringify(entry)); - } catch (error) { - console.error(`Failed to parse cached data for key "${key}"`, error); - } - } + if (storedEntry) { + try { + const entry: CacheEntry = JSON.parse(storedEntry); + entry.data = obj; + entry.timestamp = now; + localStorage.setItem(key, JSON.stringify(entry)); + } catch (error) { + console.error(`Failed to parse cached data for key "${key}"`, error); + } + } } export function isAPIResponse(obj: any): obj is APIResponse { - return ( - obj && - typeof obj.status === 'string' && - (typeof obj.message === 'string' || typeof obj.error === 'string') - ); + return ( + obj && + typeof obj.status === 'string' && + (typeof obj.message === 'string' || typeof obj.error === 'string') + ); } export function handleValidationErrors(result: APIResponse, section: string): void { - adze.withEmoji.error('Validation Error', result); - if (result.error === 'validation_error') { - if (Array.isArray(result.data)) { - if (result.data.length > 0) { - toast.error(getValidationError(result.data[0], section), { - position: 'bottom-center' - }); - } - } - } + adze.withEmoji.error('Validation Error', result); + if (result.error === 'validation_error') { + if (Array.isArray(result.data)) { + if (result.data.length > 0) { + toast.error(getValidationError(result.data[0], section), { + position: 'bottom-center' + }); + } + } + } } export function handleAPIError(result: APIResponse): void { - adze.withEmoji.error('API Error', result); + adze.withEmoji.error('API Error', result); } diff --git a/new-web/src/lib/utils/vm/vm.ts b/new-web/src/lib/utils/vm/vm.ts index d6e56789..707401b4 100644 --- a/new-web/src/lib/utils/vm/vm.ts +++ b/new-web/src/lib/utils/vm/vm.ts @@ -1,96 +1,96 @@ import type { CreateData } from '$lib/types/vm/vm'; -import toast from 'svelte-french-toast'; +import { toast } from "svelte-sonner"; import { isValidMACAddress, isValidVMName } from '../string'; export function isValidCreateData(modal: CreateData): boolean { - const toastConfig: Record = { - duration: 3000, - position: 'bottom-center' - }; + const toastConfig: Record = { + duration: 3000, + position: 'bottom-center' + }; - if (!isValidVMName(modal.name)) { - toast.error('Invalid name', toastConfig); - return false; - } + if (!isValidVMName(modal.name)) { + toast.error('Invalid name', toastConfig); + return false; + } - if (modal.id < 1 || modal.id > 9999) { - toast.error('Invalid ID', toastConfig); - return false; - } + if (modal.id < 1 || modal.id > 9999) { + toast.error('Invalid ID', toastConfig); + return false; + } - if (modal.description && (modal.description.length < 1 || modal.description.length > 1024)) { - toast.error('Invalid description', toastConfig); - } + if (modal.description && (modal.description.length < 1 || modal.description.length > 1024)) { + toast.error('Invalid description', toastConfig); + } - if (modal.storage.type === 'raw') { - if (!modal.storage.size || modal.storage.size < 1024 * 1024 * 128) { - toast.error('Disk size must be >= 128 MiB', toastConfig); - } - } + if (modal.storage.type === 'raw') { + if (!modal.storage.size || modal.storage.size < 1024 * 1024 * 128) { + toast.error('Disk size must be >= 128 MiB', toastConfig); + } + } - if (modal.storage.type === 'raw' || modal.storage.type === 'zvol') { - if (!modal.storage.guid || modal.storage.guid.length < 1) { - const noun = modal.storage.type === 'raw' ? 'filesystem' : 'volume'; - toast.error(`No ${noun} selected`, toastConfig); - return false; - } - } + if (modal.storage.type === 'raw' || modal.storage.type === 'zvol') { + if (!modal.storage.guid || modal.storage.guid.length < 1) { + const noun = modal.storage.type === 'raw' ? 'filesystem' : 'volume'; + toast.error(`No ${noun} selected`, toastConfig); + return false; + } + } - if (modal.storage.emulation === '') { - toast.error('No emulation type selected', toastConfig); - } + if (modal.storage.emulation === '') { + toast.error('No emulation type selected', toastConfig); + } - if (modal.storage.type === 'none' && modal.storage.iso === '') { - toast.error('Atleast one disk or ISO must be selected', toastConfig); - return false; - } + if (modal.storage.type === 'none' && modal.storage.iso === '') { + toast.error('Atleast one disk or ISO must be selected', toastConfig); + return false; + } - if (modal.network.switch !== 0) { - if (modal.network.emulation === '') { - toast.error('No network emulation type selected', toastConfig); - return false; - } + if (modal.network.switch !== 0) { + if (modal.network.emulation === '') { + toast.error('No network emulation type selected', toastConfig); + return false; + } - if (modal.network.mac && isValidMACAddress(modal.network.mac) === false) { - toast.error('Invalid MAC address', toastConfig); - return false; - } - } + if (modal.network.mac && isValidMACAddress(modal.network.mac) === false) { + toast.error('Invalid MAC address', toastConfig); + return false; + } + } - if (modal.hardware.sockets < 1) { - toast.error('Sockets must be >= 1', toastConfig); - return false; - } + if (modal.hardware.sockets < 1) { + toast.error('Sockets must be >= 1', toastConfig); + return false; + } - if (modal.hardware.cores < 1) { - toast.error('Cores must be >= 1', toastConfig); - return false; - } + if (modal.hardware.cores < 1) { + toast.error('Cores must be >= 1', toastConfig); + return false; + } - if (modal.hardware.threads < 1) { - toast.error('Threads must be >= 1', toastConfig); - return false; - } + if (modal.hardware.threads < 1) { + toast.error('Threads must be >= 1', toastConfig); + return false; + } - if (modal.hardware.memory < 1024 * 1024 * 128) { - toast.error('Memory must be >= 128 MiB', toastConfig); - return false; - } + if (modal.hardware.memory < 1024 * 1024 * 128) { + toast.error('Memory must be >= 128 MiB', toastConfig); + return false; + } - if (modal.advanced.vncPort < 1 || modal.advanced.vncPort > 65535) { - toast.error('VNC port must be between 1 and 65535', toastConfig); - return false; - } + if (modal.advanced.vncPort < 1 || modal.advanced.vncPort > 65535) { + toast.error('VNC port must be between 1 and 65535', toastConfig); + return false; + } - if (modal.advanced.vncPassword && modal.advanced.vncPassword.length < 1) { - toast.error('VNC password required', toastConfig); - return false; - } + if (modal.advanced.vncPassword && modal.advanced.vncPassword.length < 1) { + toast.error('VNC password required', toastConfig); + return false; + } - if (modal.advanced.vncResolution === '') { - toast.error('No VNC resolution selected', toastConfig); - return false; - } + if (modal.advanced.vncResolution === '') { + toast.error('No VNC resolution selected', toastConfig); + return false; + } - return true; + return true; } diff --git a/new-web/src/lib/utils/zfs/dataset/fs.ts b/new-web/src/lib/utils/zfs/dataset/fs.ts index 42931faf..fe39472e 100644 --- a/new-web/src/lib/utils/zfs/dataset/fs.ts +++ b/new-web/src/lib/utils/zfs/dataset/fs.ts @@ -6,334 +6,334 @@ import { generateNumberFromString } from '$lib/utils/numbers'; import { capitalizeFirstLetter } from '$lib/utils/string'; import { renderWithIcon, sizeFormatter } from '$lib/utils/table'; import { cleanChildren } from '$lib/utils/tree-table'; -import toast from 'svelte-french-toast'; +import { toast } from 'svelte-sonner'; export const createFSProps = { - atime: [ - { - label: 'on', - value: 'on' - }, - { - label: 'off', - value: 'off' - } - ], - checksum: [ - { - label: 'on', - value: 'on' - }, - { - label: 'off', - value: 'off' - }, - { - label: 'fletcher2', - value: 'fletcher2' - }, - { - label: 'fletcher4', - value: 'fletcher4' - }, - { - label: 'sha256', - value: 'sha256' - }, - { - label: 'noparity', - value: 'noparity' - } - ], - compression: [ - { - label: 'on', - value: 'on' - }, - { - label: 'off', - value: 'off' - }, - { - label: 'gzip', - value: 'gzip' - }, - { - label: 'lz4', - value: 'lz4' - }, - { - label: 'lzjb', - value: 'lzjb' - }, - { - label: 'zle', - value: 'zle' - }, - { - label: 'zstd', - value: 'zstd' - }, - { - label: 'zstd-fast', - value: 'zstd-fast' - } - ], - dedup: [ - { - label: 'off', - value: 'off' - }, - { - label: 'on', - value: 'on' - }, - { - label: 'Verify', - value: 'verify' - } - ], - encryption: [ - { - label: 'off', - value: 'off' - }, - { - label: 'on', - value: 'on' - }, - { - label: 'aes-128-ccm', - value: 'aes-128-ccm' - }, - { - label: 'aes-192-ccm', - value: 'aes-192-ccm' - }, - { - label: 'aes-256-ccm', - value: 'aes-256-ccm' - }, - { - label: 'aes-128-gcm', - value: 'aes-128-gcm' - }, - { - label: 'aes-192-gcm', - value: 'aes-192-gcm' - }, - { - label: 'aes-256-gcm', - value: 'aes-256-gcm' - } - ] + atime: [ + { + label: 'on', + value: 'on' + }, + { + label: 'off', + value: 'off' + } + ], + checksum: [ + { + label: 'on', + value: 'on' + }, + { + label: 'off', + value: 'off' + }, + { + label: 'fletcher2', + value: 'fletcher2' + }, + { + label: 'fletcher4', + value: 'fletcher4' + }, + { + label: 'sha256', + value: 'sha256' + }, + { + label: 'noparity', + value: 'noparity' + } + ], + compression: [ + { + label: 'on', + value: 'on' + }, + { + label: 'off', + value: 'off' + }, + { + label: 'gzip', + value: 'gzip' + }, + { + label: 'lz4', + value: 'lz4' + }, + { + label: 'lzjb', + value: 'lzjb' + }, + { + label: 'zle', + value: 'zle' + }, + { + label: 'zstd', + value: 'zstd' + }, + { + label: 'zstd-fast', + value: 'zstd-fast' + } + ], + dedup: [ + { + label: 'off', + value: 'off' + }, + { + label: 'on', + value: 'on' + }, + { + label: 'Verify', + value: 'verify' + } + ], + encryption: [ + { + label: 'off', + value: 'off' + }, + { + label: 'on', + value: 'on' + }, + { + label: 'aes-128-ccm', + value: 'aes-128-ccm' + }, + { + label: 'aes-192-ccm', + value: 'aes-192-ccm' + }, + { + label: 'aes-256-ccm', + value: 'aes-256-ccm' + }, + { + label: 'aes-128-gcm', + value: 'aes-128-gcm' + }, + { + label: 'aes-192-gcm', + value: 'aes-192-gcm' + }, + { + label: 'aes-256-gcm', + value: 'aes-256-gcm' + } + ] }; export function generateTableData(grouped: GroupedByPool[]): { rows: Row[]; columns: Column[] } { - const rows: Row[] = []; - const columns: Column[] = [ - { - field: 'id', - title: 'ID', - visible: false - }, - { - field: 'name', - title: 'Name', - formatter: (cell) => { - const value = cell.getValue(); + const rows: Row[] = []; + const columns: Column[] = [ + { + field: 'id', + title: 'ID', + visible: false + }, + { + field: 'name', + title: 'Name', + formatter: (cell) => { + const value = cell.getValue(); - if (value.includes('@')) { - const [, snapshot] = value.split('@'); - return renderWithIcon('carbon:ibm-cloud-vpc-block-storage-snapshots', snapshot); - } + if (value.includes('@')) { + const [, snapshot] = value.split('@'); + return renderWithIcon('carbon:ibm-cloud-vpc-block-storage-snapshots', snapshot); + } - if (value.includes('/')) { - return renderWithIcon('material-symbols:files', value.substring(value.indexOf('/') + 1)); - } + if (value.includes('/')) { + return renderWithIcon('material-symbols:files', value.substring(value.indexOf('/') + 1)); + } - if (!value.includes('/') && !value.includes('@')) { - return renderWithIcon('bi:hdd-stack-fill', value); - } + if (!value.includes('/') && !value.includes('@')) { + return renderWithIcon('bi:hdd-stack-fill', value); + } - return `${value}`; - } - }, - { - field: 'used', - title: 'Used', - formatter: sizeFormatter - }, - { - field: 'avail', - title: 'Available', - formatter: sizeFormatter - }, - { - field: 'referenced', - title: 'Referenced', - formatter: sizeFormatter - }, - { - field: 'mountpoint', - title: 'Mount Point' - }, - { - field: 'type', - title: 'Type', - visible: false - } - ]; + return `${value}`; + } + }, + { + field: 'used', + title: 'Used', + formatter: sizeFormatter + }, + { + field: 'avail', + title: 'Available', + formatter: sizeFormatter + }, + { + field: 'referenced', + title: 'Referenced', + formatter: sizeFormatter + }, + { + field: 'mountpoint', + title: 'Mount Point' + }, + { + field: 'type', + title: 'Type', + visible: false + } + ]; - for (const group of grouped) { - const poolLevelFilesystem = group.filesystems.find( - (fs: Dataset) => fs.type === 'filesystem' && fs.name === group.name - ); + for (const group of grouped) { + const poolLevelFilesystem = group.filesystems.find( + (fs: Dataset) => fs.type === 'filesystem' && fs.name === group.name + ); - const filesystemChildren = group.filesystems.filter( - (fs) => fs.type === 'filesystem' && fs.name !== group.name - ); + const filesystemChildren = group.filesystems.filter( + (fs) => fs.type === 'filesystem' && fs.name !== group.name + ); - const snapshotChildren = group.snapshots; + const snapshotChildren = group.snapshots; - if (poolLevelFilesystem) { - const poolSnapshots = snapshotChildren.filter((snapshot) => - snapshot.name.startsWith(group.name + '@') - ); + if (poolLevelFilesystem) { + const poolSnapshots = snapshotChildren.filter((snapshot) => + snapshot.name.startsWith(group.name + '@') + ); - const childFilesystemsWithSnapshots = filesystemChildren.map((filesystem: Dataset) => ({ - id: generateNumberFromString(filesystem.name) + 1, - name: filesystem.name, - used: filesystem.used, - avail: filesystem.avail, - referenced: filesystem.referenced, - mountpoint: filesystem.mountpoint || '', - children: snapshotChildren - .filter((snapshot) => snapshot.name.startsWith(filesystem.name + '@')) - .map((snapshot: Dataset) => ({ - id: generateNumberFromString(snapshot.name) + 2, - name: snapshot.name, - used: snapshot.used, - avail: snapshot.avail, - referenced: snapshot.referenced, - mountpoint: snapshot.mountpoint || '', - children: [] - })), - type: filesystem.type - })); + const childFilesystemsWithSnapshots = filesystemChildren.map((filesystem: Dataset) => ({ + id: generateNumberFromString(filesystem.name) + 1, + name: filesystem.name, + used: filesystem.used, + avail: filesystem.avail, + referenced: filesystem.referenced, + mountpoint: filesystem.mountpoint || '', + children: snapshotChildren + .filter((snapshot) => snapshot.name.startsWith(filesystem.name + '@')) + .map((snapshot: Dataset) => ({ + id: generateNumberFromString(snapshot.name) + 2, + name: snapshot.name, + used: snapshot.used, + avail: snapshot.avail, + referenced: snapshot.referenced, + mountpoint: snapshot.mountpoint || '', + children: [] + })), + type: filesystem.type + })); - rows.push({ - id: generateNumberFromString(group.name), - name: group.name, - used: poolLevelFilesystem.used, - avail: poolLevelFilesystem.avail, - referenced: poolLevelFilesystem.referenced, - mountpoint: poolLevelFilesystem.mountpoint || '', - children: [ - ...poolSnapshots.map((snapshot: Dataset) => ({ - id: generateNumberFromString(snapshot.name) + 1, - name: snapshot.name, - used: snapshot.used, - avail: snapshot.avail, - referenced: snapshot.referenced, - mountpoint: snapshot.mountpoint || '', - children: [], - isPoolSnapshot: true - })), - ...childFilesystemsWithSnapshots - ].sort((a, b) => { - const aIsPoolSnapshot = a.hasOwnProperty('isPoolSnapshot'); - const bIsPoolSnapshot = b.hasOwnProperty('isPoolSnapshot'); - if (aIsPoolSnapshot && !bIsPoolSnapshot) return -1; - if (!aIsPoolSnapshot && bIsPoolSnapshot) return 1; - return a.name.localeCompare(b.name); - }), - type: 'pool' - }); - } else if (group.filesystems.length > 0) { - rows.push( - ...group.filesystems - .filter((fs) => fs.type === 'filesystem') - .map((filesystem: Dataset) => ({ - id: generateNumberFromString(filesystem.name), - name: filesystem.name, - used: filesystem.used, - avail: filesystem.avail, - referenced: filesystem.referenced, - mountpoint: filesystem.mountpoint || '', - children: snapshotChildren - .filter((snapshot) => snapshot.name.startsWith(filesystem.name + '@')) - .map((snapshot: Dataset) => ({ - id: generateNumberFromString(snapshot.name) + 1, - name: snapshot.name, - used: snapshot.used, - avail: snapshot.avail, - referenced: snapshot.referenced, - mountpoint: snapshot.mountpoint || '', - children: [] - })) - .sort((a, b) => a.name.localeCompare(b.name)) - })) - ); - } - } + rows.push({ + id: generateNumberFromString(group.name), + name: group.name, + used: poolLevelFilesystem.used, + avail: poolLevelFilesystem.avail, + referenced: poolLevelFilesystem.referenced, + mountpoint: poolLevelFilesystem.mountpoint || '', + children: [ + ...poolSnapshots.map((snapshot: Dataset) => ({ + id: generateNumberFromString(snapshot.name) + 1, + name: snapshot.name, + used: snapshot.used, + avail: snapshot.avail, + referenced: snapshot.referenced, + mountpoint: snapshot.mountpoint || '', + children: [], + isPoolSnapshot: true + })), + ...childFilesystemsWithSnapshots + ].sort((a, b) => { + const aIsPoolSnapshot = a.hasOwnProperty('isPoolSnapshot'); + const bIsPoolSnapshot = b.hasOwnProperty('isPoolSnapshot'); + if (aIsPoolSnapshot && !bIsPoolSnapshot) return -1; + if (!aIsPoolSnapshot && bIsPoolSnapshot) return 1; + return a.name.localeCompare(b.name); + }), + type: 'pool' + }); + } else if (group.filesystems.length > 0) { + rows.push( + ...group.filesystems + .filter((fs) => fs.type === 'filesystem') + .map((filesystem: Dataset) => ({ + id: generateNumberFromString(filesystem.name), + name: filesystem.name, + used: filesystem.used, + avail: filesystem.avail, + referenced: filesystem.referenced, + mountpoint: filesystem.mountpoint || '', + children: snapshotChildren + .filter((snapshot) => snapshot.name.startsWith(filesystem.name + '@')) + .map((snapshot: Dataset) => ({ + id: generateNumberFromString(snapshot.name) + 1, + name: snapshot.name, + used: snapshot.used, + avail: snapshot.avail, + referenced: snapshot.referenced, + mountpoint: snapshot.mountpoint || '', + children: [] + })) + .sort((a, b) => a.name.localeCompare(b.name)) + })) + ); + } + } - return { - rows: rows.map(cleanChildren), - columns - }; + return { + rows: rows.map(cleanChildren), + columns + }; } export function handleError(error: APIResponse): void { - if (error.error?.includes('dataset already exists')) { - let [key, value] = ['', '']; + if (error.error?.includes('dataset already exists')) { + let [key, value] = ['', '']; - if (error.error?.includes('snapshot')) { - key = 'zfs.datasets.snapshot_already_exists'; - value = 'snapshot already exists'; - } else { - key = 'zfs.datasets.filesystem_already_exists'; - value = 'filesystem already exists'; - } + if (error.error?.includes('snapshot')) { + key = 'zfs.datasets.snapshot_already_exists'; + value = 'snapshot already exists'; + } else { + key = 'zfs.datasets.filesystem_already_exists'; + value = 'filesystem already exists'; + } - toast.error(capitalizeFirstLetter(getTranslation(key, value)), { - position: 'bottom-center' - }); - } + toast.error(capitalizeFirstLetter(getTranslation(key, value)), { + position: 'bottom-center' + }); + } - if (error.error?.includes('numeric value is too large')) { - toast.error( - capitalizeFirstLetter( - getTranslation('zfs.datasets.numeric_value_too_large', 'Numeric value is too large') - ), - { - position: 'bottom-center' - } - ); - } + if (error.error?.includes('numeric value is too large')) { + toast.error( + capitalizeFirstLetter( + getTranslation('zfs.datasets.numeric_value_too_large', 'Numeric value is too large') + ), + { + position: 'bottom-center' + } + ); + } - if (error.error?.includes('invalid_encryption_key_length')) { - toast.error( - capitalizeFirstLetter( - getTranslation( - 'zfs.datasets.invalid_encryption_key_length', - 'Invalid encryption key length' - ) - ), - { - position: 'bottom-center' - } - ); - } + if (error.error?.includes('invalid_encryption_key_length')) { + toast.error( + capitalizeFirstLetter( + getTranslation( + 'zfs.datasets.invalid_encryption_key_length', + 'Invalid encryption key length' + ) + ), + { + position: 'bottom-center' + } + ); + } - if (error.error?.includes('pool or dataset is busy')) { - toast.error( - capitalizeFirstLetter( - getTranslation('zfs.datasets.pool_or_dataset_is_busy', 'Pool or dataset is busy') - ), - { - position: 'bottom-center' - } - ); - } + if (error.error?.includes('pool or dataset is busy')) { + toast.error( + capitalizeFirstLetter( + getTranslation('zfs.datasets.pool_or_dataset_is_busy', 'Pool or dataset is busy') + ), + { + position: 'bottom-center' + } + ); + } } diff --git a/new-web/src/lib/utils/zfs/dataset/volume.ts b/new-web/src/lib/utils/zfs/dataset/volume.ts index f8ea4597..9bf15560 100644 --- a/new-web/src/lib/utils/zfs/dataset/volume.ts +++ b/new-web/src/lib/utils/zfs/dataset/volume.ts @@ -6,322 +6,322 @@ import { generateNumberFromString } from '$lib/utils/numbers'; import { capitalizeFirstLetter } from '$lib/utils/string'; import { renderWithIcon, sizeFormatter } from '$lib/utils/table'; import { cleanChildren } from '$lib/utils/tree-table'; -import toast from 'svelte-french-toast'; +import { toast } from 'svelte-sonner'; export const createVolProps = { - atime: [ - { - label: 'on', - value: 'on' - }, - { - label: 'off', - value: 'off' - } - ], - checksum: [ - { - label: 'on', - value: 'on' - }, - { - label: 'off', - value: 'off' - }, - { - label: 'fletcher2', - value: 'fletcher2' - }, - { - label: 'fletcher4', - value: 'fletcher4' - }, - { - label: 'sha256', - value: 'sha256' - }, - { - label: 'noparity', - value: 'noparity' - } - ], - compression: [ - { - label: 'on', - value: 'on' - }, - { - label: 'off', - value: 'off' - }, - { - label: 'gzip', - value: 'gzip' - }, - { - label: 'lz4', - value: 'lz4' - }, - { - label: 'lzjb', - value: 'lzjb' - }, - { - label: 'zle', - value: 'zle' - }, - { - label: 'zstd', - value: 'zstd' - }, - { - label: 'zstd-fast', - value: 'zstd-fast' - } - ], - dedup: [ - { - label: 'off', - value: 'off' - }, - { - label: 'on', - value: 'on' - }, - { - label: 'Verify', - value: 'verify' - } - ], - encryption: [ - { - label: 'off', - value: 'off' - }, - { - label: 'on', - value: 'on' - }, - { - label: 'aes-128-ccm', - value: 'aes-128-ccm' - }, - { - label: 'aes-192-ccm', - value: 'aes-192-ccm' - }, - { - label: 'aes-256-ccm', - value: 'aes-256-ccm' - }, - { - label: 'aes-128-gcm', - value: 'aes-128-gcm' - }, - { - label: 'aes-192-gcm', - value: 'aes-192-gcm' - }, - { - label: 'aes-256-gcm', - value: 'aes-256-gcm' - } - ], - volblocksize: [ - { - label: '512B (Legacy HDD sectors)', - value: '512' - }, - { - label: '1K (1024B)', - value: '1024' - }, - { - label: '2K (2048B)', - value: '2048' - }, - { - label: '4K (4096B) - SSD/VMs', - value: '4096' - }, - { - label: '8K (8192B)', - value: '8192' - }, - { - label: '16K (16384B)', - value: '16384' - }, - { - label: '32K (32768B) - Sequential workloads', - value: '32768' - }, - { - label: '64K (65536B) - Large files', - value: '65536' - }, - { - label: '128K (131072B) Media/backups', - value: '131072' - } - ], - primarycache: [ - { - label: 'All', - value: 'all' - }, - { - label: 'Metadata', - value: 'metadata' - }, - { - label: 'None', - value: 'none' - } - ], - volmode: [ - { - label: 'default', - value: 'default' - }, - { - label: 'full', - value: 'full' - }, - { - label: 'geom', - value: 'geom' - }, - { - label: 'dev', - value: 'dev' - }, - { - label: 'none', - value: 'none' - } - ] + atime: [ + { + label: 'on', + value: 'on' + }, + { + label: 'off', + value: 'off' + } + ], + checksum: [ + { + label: 'on', + value: 'on' + }, + { + label: 'off', + value: 'off' + }, + { + label: 'fletcher2', + value: 'fletcher2' + }, + { + label: 'fletcher4', + value: 'fletcher4' + }, + { + label: 'sha256', + value: 'sha256' + }, + { + label: 'noparity', + value: 'noparity' + } + ], + compression: [ + { + label: 'on', + value: 'on' + }, + { + label: 'off', + value: 'off' + }, + { + label: 'gzip', + value: 'gzip' + }, + { + label: 'lz4', + value: 'lz4' + }, + { + label: 'lzjb', + value: 'lzjb' + }, + { + label: 'zle', + value: 'zle' + }, + { + label: 'zstd', + value: 'zstd' + }, + { + label: 'zstd-fast', + value: 'zstd-fast' + } + ], + dedup: [ + { + label: 'off', + value: 'off' + }, + { + label: 'on', + value: 'on' + }, + { + label: 'Verify', + value: 'verify' + } + ], + encryption: [ + { + label: 'off', + value: 'off' + }, + { + label: 'on', + value: 'on' + }, + { + label: 'aes-128-ccm', + value: 'aes-128-ccm' + }, + { + label: 'aes-192-ccm', + value: 'aes-192-ccm' + }, + { + label: 'aes-256-ccm', + value: 'aes-256-ccm' + }, + { + label: 'aes-128-gcm', + value: 'aes-128-gcm' + }, + { + label: 'aes-192-gcm', + value: 'aes-192-gcm' + }, + { + label: 'aes-256-gcm', + value: 'aes-256-gcm' + } + ], + volblocksize: [ + { + label: '512B (Legacy HDD sectors)', + value: '512' + }, + { + label: '1K (1024B)', + value: '1024' + }, + { + label: '2K (2048B)', + value: '2048' + }, + { + label: '4K (4096B) - SSD/VMs', + value: '4096' + }, + { + label: '8K (8192B)', + value: '8192' + }, + { + label: '16K (16384B)', + value: '16384' + }, + { + label: '32K (32768B) - Sequential workloads', + value: '32768' + }, + { + label: '64K (65536B) - Large files', + value: '65536' + }, + { + label: '128K (131072B) Media/backups', + value: '131072' + } + ], + primarycache: [ + { + label: 'All', + value: 'all' + }, + { + label: 'Metadata', + value: 'metadata' + }, + { + label: 'None', + value: 'none' + } + ], + volmode: [ + { + label: 'default', + value: 'default' + }, + { + label: 'full', + value: 'full' + }, + { + label: 'geom', + value: 'geom' + }, + { + label: 'dev', + value: 'dev' + }, + { + label: 'none', + value: 'none' + } + ] }; export function generateTableData(grouped: GroupedByPool[]): { rows: Row[]; columns: Column[] } { - const rows: Row[] = []; - const columns: Column[] = [ - { - field: 'id', - title: 'ID', - visible: false - }, - { - field: 'name', - title: 'Name', - formatter: (cell) => { - const value = cell.getValue(); - if (value.includes('@')) { - const [, snapshot] = value.split('@'); - return renderWithIcon('carbon:ibm-cloud-vpc-block-storage-snapshots', snapshot); - } + const rows: Row[] = []; + const columns: Column[] = [ + { + field: 'id', + title: 'ID', + visible: false + }, + { + field: 'name', + title: 'Name', + formatter: (cell) => { + const value = cell.getValue(); + if (value.includes('@')) { + const [, snapshot] = value.split('@'); + return renderWithIcon('carbon:ibm-cloud-vpc-block-storage-snapshots', snapshot); + } - if (value.includes('/')) { - const [, volume] = value.split('/'); - return renderWithIcon('carbon:volume-block-storage', volume); - } + if (value.includes('/')) { + const [, volume] = value.split('/'); + return renderWithIcon('carbon:volume-block-storage', volume); + } - if (!value.includes('/') && !value.includes('@')) { - return renderWithIcon('bi:hdd-stack-fill', value); - } + if (!value.includes('/') && !value.includes('@')) { + return renderWithIcon('bi:hdd-stack-fill', value); + } - return `${value}`; - } - }, - { - field: 'size', - title: 'Size', - formatter: sizeFormatter - }, - { - field: 'referenced', - title: 'Referenced', - formatter: sizeFormatter - }, - { - field: 'guid', - title: 'GUID', - visible: false - } - ]; + return `${value}`; + } + }, + { + field: 'size', + title: 'Size', + formatter: sizeFormatter + }, + { + field: 'referenced', + title: 'Referenced', + formatter: sizeFormatter + }, + { + field: 'guid', + title: 'GUID', + visible: false + } + ]; - for (const group of grouped) { - const poolRow: Row = { - id: generateNumberFromString(group.name), - name: group.name, - size: 0, - referenced: '-', - guid: undefined, - children: [] - }; + for (const group of grouped) { + const poolRow: Row = { + id: generateNumberFromString(group.name), + name: group.name, + size: 0, + referenced: '-', + guid: undefined, + children: [] + }; - poolRow.size = group.pool?.size; + poolRow.size = group.pool?.size; - const volumeChildren = group.volumes - .filter((vol) => vol.name !== group.name) - .map((vol) => { - const volumeRow: Row = { - id: generateNumberFromString(vol.name), - name: vol.name, - size: vol.volsize, - referenced: vol.referenced, - guid: vol.properties?.guid, - children: [] - }; + const volumeChildren = group.volumes + .filter((vol) => vol.name !== group.name) + .map((vol) => { + const volumeRow: Row = { + id: generateNumberFromString(vol.name), + name: vol.name, + size: vol.volsize, + referenced: vol.referenced, + guid: vol.properties?.guid, + children: [] + }; - const snapshots = group.snapshots.filter((snap) => snap.name.startsWith(vol.name + '@')); - volumeRow.children?.push( - ...snapshots.map((snap) => ({ - id: generateNumberFromString(snap.name), - name: snap.name, - size: snap.used, - referenced: snap.referenced, - guid: snap.properties?.guid, - children: [] - })) - ); + const snapshots = group.snapshots.filter((snap) => snap.name.startsWith(vol.name + '@')); + volumeRow.children?.push( + ...snapshots.map((snap) => ({ + id: generateNumberFromString(snap.name), + name: snap.name, + size: snap.used, + referenced: snap.referenced, + guid: snap.properties?.guid, + children: [] + })) + ); - return volumeRow; - }); + return volumeRow; + }); - poolRow.children?.push(...volumeChildren); - rows.push(poolRow); - } + poolRow.children?.push(...volumeChildren); + rows.push(poolRow); + } - return { - rows: rows.filter((row) => row.children && row.children.length > 0).map(cleanChildren), - columns - }; + return { + rows: rows.filter((row) => row.children && row.children.length > 0).map(cleanChildren), + columns + }; } export function handleError(error: APIResponse): void { - if (error.error?.includes('dataset_in_use_by_vm')) { - toast.error( - capitalizeFirstLetter( - getTranslation('zfs.datasets.dataset_in_use_by_vm', 'dataset is in use by a VM'), - true - ), - { - position: 'bottom-center' - } - ); + if (error.error?.includes('dataset_in_use_by_vm')) { + toast.error( + capitalizeFirstLetter( + getTranslation('zfs.datasets.dataset_in_use_by_vm', 'dataset is in use by a VM'), + true + ), + { + position: 'bottom-center' + } + ); - return; - } + return; + } - if (error.error?.includes('dataset already exists')) { - toast.error( - capitalizeFirstLetter( - getTranslation('zfs.datasets.dataset_already_exists', 'dataset already exists') - ), - { - position: 'bottom-center' - } - ); - } + if (error.error?.includes('dataset already exists')) { + toast.error( + capitalizeFirstLetter( + getTranslation('zfs.datasets.dataset_already_exists', 'dataset already exists') + ), + { + position: 'bottom-center' + } + ); + } } diff --git a/new-web/src/routes/+layout.svelte b/new-web/src/routes/+layout.svelte index 187bb140..6973d9bc 100644 --- a/new-web/src/routes/+layout.svelte +++ b/new-web/src/routes/+layout.svelte @@ -5,13 +5,127 @@ import { goto, replaceState } from '$app/navigation'; import { page } from '$app/state'; import { isTokenValid, login } from '$lib/api/auth'; - import { Button } from '$lib/components/ui/button/index.js'; + import Login from '$lib/components/custom/Login.svelte'; + import Throbber from '$lib/components/custom/Throbber.svelte'; + import Shell from '$lib/components/skeleton/Shell.svelte'; import { Toaster } from '$lib/components/ui/sonner/index.js'; + import { store as token } from '$lib/stores/auth'; + import { hostname } from '$lib/stores/basic'; + import '$lib/utils/i18n'; + import { preloadIcons } from '$lib/utils/icons'; + import { addTabulatorFilters } from '$lib/utils/table'; + import { QueryClient, QueryClientProvider } from '@sveltestack/svelte-query'; + import { ModeWatcher } from 'mode-watcher'; + import { onMount, tick } from 'svelte'; + import { toast } from 'svelte-sonner'; import '../app.css'; + const queryClient = new QueryClient(); let { children } = $props(); + let isLoggedIn = $state(false); + let isLoading = $state(true); + + $effect(() => { + if (isLoggedIn && $hostname) { + const path = window.location.pathname; + if (path === '/' || !path.startsWith(`/${$hostname}`)) { + goto(`/${$hostname}/summary`, { replaceState: true }); + } + } + }); + + $effect(() => { + if (page.state.hasOwnProperty('loggedOut')) { + toast.success('Logged out', { + position: 'bottom-center' + }); + } + }); + + onMount(async () => { + addTabulatorFilters(); + const faviconEl = document.getElementById('favicon'); + if (faviconEl) { + const darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; + if (darkMode) { + faviconEl.setAttribute('href', '/logo/white.svg'); + } else { + faviconEl.setAttribute('href', '/logo/black.svg'); + } + } + + if ($token) { + try { + if (await isTokenValid()) { + isLoggedIn = true; + } else { + $token = ''; + } + } catch (error) { + console.error('Token validation error:', error); + $token = ''; + } + } + + await preloadIcons(); + isLoading = false; + await tick(); + }); + + function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + async function handleLogin( + username: string, + password: string, + type: string, + language: string, + remember: boolean + ) { + let isError = false; + + try { + if (await login(username, password, type, remember, language)) { + isLoading = true; + isLoggedIn = true; + const path = window.location.pathname; + + if (path === '/' || !path.startsWith(`/${$hostname}`)) { + await goto(`/${$hostname}/summary`, { replaceState: true }); + } + } else { + isError = true; + isLoggedIn = false; + } + } catch (error) { + isError = true; + isLoggedIn = false; + } finally { + if (!isError) { + await sleep(2500); + isLoading = false; + } + } + return; + } - + + Sylve + -{@render children()} + + + +{#if isLoading} + +{:else if isLoggedIn && $hostname} + + + {@render children()} + + +{:else} + +{/if} diff --git a/new-web/src/routes/[node]/+layout.svelte b/new-web/src/routes/[node]/+layout.svelte new file mode 100644 index 00000000..4757dae7 --- /dev/null +++ b/new-web/src/routes/[node]/+layout.svelte @@ -0,0 +1,216 @@ + + + + +
    +
    +

    {capitalizeFirstLetter(getTranslation('common.datacenter', 'Datacenter'))}

    + +
    + + + +
    +
    + +
    +
    +
    + + +
    + {@render children?.()} +
    +
    +
    +
    diff --git a/new-web/src/routes/[node]/+layout.ts b/new-web/src/routes/[node]/+layout.ts new file mode 100644 index 00000000..e69de29b diff --git a/new-web/src/routes/[node]/+page.svelte b/new-web/src/routes/[node]/+page.svelte new file mode 100644 index 00000000..e69de29b diff --git a/new-web/src/routes/[node]/network/interfaces/+page.svelte b/new-web/src/routes/[node]/network/interfaces/+page.svelte new file mode 100644 index 00000000..02010a2e --- /dev/null +++ b/new-web/src/routes/[node]/network/interfaces/+page.svelte @@ -0,0 +1,103 @@ + + +{#snippet button(type: string)} + {#if type === 'view' && activeRow !== null && activeRow.length > 0} + + {/if} +{/snippet} + +
    +
    + + {@render button('view')} +
    + + + + +
    diff --git a/new-web/src/routes/[node]/network/interfaces/+page.ts b/new-web/src/routes/[node]/network/interfaces/+page.ts new file mode 100644 index 00000000..6d0e8230 --- /dev/null +++ b/new-web/src/routes/[node]/network/interfaces/+page.ts @@ -0,0 +1,13 @@ +import { getInterfaces } from '$lib/api/network/iface'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = 1000 * 60000; + const [interfaces] = await Promise.all([ + cachedFetch('networkInterfaces', async () => await getInterfaces(), cacheDuration) + ]); + + return { + interfaces + }; +} diff --git a/new-web/src/routes/[node]/network/switches/+page.svelte b/new-web/src/routes/[node]/network/switches/+page.svelte new file mode 100644 index 00000000..ae7b957e --- /dev/null +++ b/new-web/src/routes/[node]/network/switches/+page.svelte @@ -0,0 +1,605 @@ + + +{#snippet button(type: string)} + {#if activeRow && Object.keys(activeRow).length > 0} + {#if type === 'edit'} + + {:else if type === 'delete'} + + {/if} + {/if} +{/snippet} + +
    +
    + + + + {@render button('edit')} + {@render button('delete')} +
    + + +
    + +{#if confirmModals.active === 'newSwitch' || confirmModals.active === 'editSwitch'} + + +
    + + +
    + + {#if confirmModals.active === 'editSwitch'} + {capitalizeFirstLetter(getTranslation('common.edit', 'Edit'))} + {capitalizeFirstLetter(getTranslation('network.switch.switch', 'Switch'))} + {'- ' + confirmModals.editSwitch.oldName} + {:else} + {capitalizeFirstLetter(getTranslation('common.new', 'New'))} + {capitalizeFirstLetter(getTranslation('network.switch.switch', 'Switch'))} + {/if} +
    +
    +
    + +
    + + +
    +
    + + {#if confirmModals.active === 'newSwitch'} + + {/if} + +
    + + + +
    + +
    + + + +
    + + {#if confirmModals.active === 'newSwitch'} + + {:else} + + {/if} + +
    + + + + + + + +
    + + +
    + {#if confirmModals.active === 'editSwitch'} + + {:else} + + {/if} +
    +
    +
    +
    +{/if} + + { + const result = await deleteSwitch(confirmModals.deleteSwitch.id); + if (isAPIResponse(result) && result.status === 'success') { + let message = `${capitalizeFirstLetter(getTranslation('network.switch.switch', 'Switch'))} ${confirmModals.deleteSwitch.name} ${getTranslation('common.deleted', 'deleted')}`; + toast.success(message, { + position: 'bottom-center' + }); + } else { + if (result && result.error) { + if (result.error === 'switch_in_use_by_vm') { + toast.error( + getTranslation( + 'network.switch.errors.switch_in_use_by_vm', + 'Switch is in use by a VM' + ), + { + position: 'bottom-center' + } + ); + return; + } + } + + toast.error( + getTranslation('network.switch.errors.delete_switch', 'Error deleting switch'), + { + position: 'bottom-center' + } + ); + } + + activeRows = null; + + confirmModals.deleteSwitch.open = false; + confirmModals.deleteSwitch.name = ''; + confirmModals.deleteSwitch.id = 0; + }, + onCancel: () => { + confirmModals.deleteSwitch.open = false; + confirmModals.deleteSwitch.name = ''; + confirmModals.deleteSwitch.id = 0; + } + }} +> diff --git a/new-web/src/routes/[node]/network/switches/+page.ts b/new-web/src/routes/[node]/network/switches/+page.ts new file mode 100644 index 00000000..a3d90e8f --- /dev/null +++ b/new-web/src/routes/[node]/network/switches/+page.ts @@ -0,0 +1,16 @@ +import { getInterfaces } from '$lib/api/network/iface'; +import { getSwitches } from '$lib/api/network/switch'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = 1000 * 60000; + const [interfaces, switches] = await Promise.all([ + cachedFetch('networkInterfaces', async () => await getInterfaces(), cacheDuration), + cachedFetch('networkSwitches', async () => await getSwitches(), cacheDuration) + ]); + + return { + interfaces, + switches + }; +} diff --git a/new-web/src/routes/[node]/notes/+page.svelte b/new-web/src/routes/[node]/notes/+page.svelte new file mode 100644 index 00000000..1a09c0d9 --- /dev/null +++ b/new-web/src/routes/[node]/notes/+page.svelte @@ -0,0 +1,348 @@ + + +{#snippet button(type: string)} + {#if activeRow !== null && activeRow.length === 1} + {#if type === 'view-note'} + + {/if} + + {#if type === 'delete-note'} + + {/if} + + {#if type === 'edit-note'} + + {/if} + {/if} + + {#if activeRow !== null && activeRow.length > 1} + {#if type === 'bulk-delete-note'} + + {/if} + {/if} +{/snippet} + +
    +
    + + + + + {@render button('view-note')} + {@render button('edit-note')} + {@render button('delete-note')} + {@render button('bulk-delete-note')} +
    + + + +
    + + +
    + + {modalState.isEditMode + ? selectedId + ? capitalizeFirstLetter(getTranslation('common.edit', 'Edit')) + : capitalizeFirstLetter(getTranslation('common.new', 'New')) + : capitalizeFirstLetter(getTranslation('common.view', 'View'))} + {capitalizeFirstLetter(getTranslation('notes.note', 'Note'))} +
    +
    +
    +
    + + +
    +
    + + + +
    + + {#if modalState.isEditMode} +
    + +
    + {:else} +
    +

    + {capitalizeFirstLetter(getTranslation('common.content', 'Content'))} +

    +
    + {@html markdownToTailwindHTML(modalState.content)} +
    +
    + {/if} +
    +
    + +
    + {#if modalState.isEditMode} + + {/if} +
    +
    +
    +
    + +
    + +
    + + { + const id = activeRow ? activeRow[0]?.id : null; + const result = await deleteNote(id as number); + if (isAPIResponse(result) && result.status === 'success') { + handleNote(undefined, false, true); + } else { + handleValidationErrors(result as APIResponse, 'notes'); + } + }, + onCancel: () => { + modalState.isDeleteOpen = false; + } + }} + > + + { + const ids = activeRow + ? activeRow.map((row) => (typeof row.id === 'number' ? row.id : parseInt(row.id))) + : []; + const result = await deleteNotes(ids); + if (isAPIResponse(result) && result.status === 'success') { + handleNote(undefined, false, true); + } else { + handleValidationErrors(result as APIResponse, 'notes'); + } + }, + onCancel: () => { + modalState.isBulkDeleteOpen = false; + } + }} + > +
    diff --git a/new-web/src/routes/[node]/notes/+page.ts b/new-web/src/routes/[node]/notes/+page.ts new file mode 100644 index 00000000..bc95bccc --- /dev/null +++ b/new-web/src/routes/[node]/notes/+page.ts @@ -0,0 +1,13 @@ +import { getNotes } from '$lib/api/info/notes'; +import type { Note } from '$lib/types/info/notes'; +import { SEVEN_DAYS } from '$lib/utils'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = SEVEN_DAYS; + const [notes] = await Promise.all([cachedFetch('notes', async () => getNotes(), cacheDuration)]); + + return { + notes: notes as Note[] + }; +} diff --git a/new-web/src/routes/[node]/settings/device-passthrough/+page.svelte b/new-web/src/routes/[node]/settings/device-passthrough/+page.svelte new file mode 100644 index 00000000..6afc6e4e --- /dev/null +++ b/new-web/src/routes/[node]/settings/device-passthrough/+page.svelte @@ -0,0 +1,176 @@ + + +{#snippet button(type: string)} + {#if activeRow !== null && activeRow.length === 1} + {#if type === 'enable-passthrough' && !activeRow[0].name.startsWith('ppt')} + + {/if} + + {#if type === 'disable-passthrough' && activeRow[0].name.startsWith('ppt')} + + {/if} + {/if} +{/snippet} + +
    +
    + + + {@render button('enable-passthrough')} + {@render button('disable-passthrough')} +
    + +
    + +
    +
    + + { + if (modalState.action === 'add') { + const result = await addPPTDevice(modalState.add.domain, modalState.add.deviceId); + if (result.status === 'success') { + toast.success('Device added to passthrough', { + position: 'bottom-center' + }); + } else { + toast.error('Failed to add device to passthrough', { + position: 'bottom-center' + }); + } + + modalState.isOpen = false; + } + + if (modalState.action === 'remove') { + const result = await removePPTDevice(modalState.remove.id.toString()); + + if (result.status === 'success') { + toast.success('Device removed from passthrough', { + position: 'bottom-center' + }); + } else { + toast.error('Failed to remove device from passthrough', { + position: 'bottom-center' + }); + } + + modalState.isOpen = false; + } + }, + onCancel: () => { + modalState.isOpen = false; + } + }} +> diff --git a/new-web/src/routes/[node]/settings/device-passthrough/+page.ts b/new-web/src/routes/[node]/settings/device-passthrough/+page.ts new file mode 100644 index 00000000..477be7ec --- /dev/null +++ b/new-web/src/routes/[node]/settings/device-passthrough/+page.ts @@ -0,0 +1,16 @@ +import { getPCIDevices, getPPTDevices } from '$lib/api/system/pci'; +import { SEVEN_DAYS } from '$lib/utils'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = SEVEN_DAYS; + const [pciDevices, pptDevices] = await Promise.all([ + cachedFetch('pciDevices', async () => await getPCIDevices(), cacheDuration), + cachedFetch('pptDevices', async () => await getPPTDevices(), cacheDuration) + ]); + + return { + pciDevices, + pptDevices + }; +} diff --git a/new-web/src/routes/[node]/storage/disks/+page.svelte b/new-web/src/routes/[node]/storage/disks/+page.svelte new file mode 100644 index 00000000..d3dcd61f --- /dev/null +++ b/new-web/src/routes/[node]/storage/disks/+page.svelte @@ -0,0 +1,352 @@ + + +{#snippet button(type: string)} + {#if type == 'smart' && buttonAbilities.smart.ability} + + {/if} + + {#if type == 'gpt' && buttonAbilities.gpt.ability} + + {/if} + + {#if type == 'wipe-disk' && buttonAbilities.wipe.ability && activeDisk !== null} + + {/if} + + {#if type == 'wipe-partition' && buttonAbilities.wipe.ability && activePartition !== null} + + {/if} + + {#if type == 'partition' && buttonAbilities.createPartition.ability} + + {/if} +{/snippet} + +
    +
    + + + {@render button('smart')} + {@render button('gpt')} + {@render button('partition')} + {@render button('wipe-disk')} + {@render button('wipe-partition')} +
    + + { + smartModal.open = false; + } + }} + > + + +
    + + { + if (activeDisk || activePartition) { + const message = activeDisk + ? getTranslation('disk.full_wipe_success', 'Disk wiped successfully') + : getTranslation('disk.partition_wipe_success', 'Disk wiped successfully'); + + const result = activeDisk + ? await destroyDisk(`/dev/${activeDisk.device}`) + : await destroyPartition(`/dev/${activePartition?.name}`); + + if (result.status === 'success') { + toast.success(message, { position: 'bottom-center' }); + activeRow = null; + } else { + handleAPIError(result); + } + } + wipeModal.title = ''; + wipeModal.open = false; + }, + onCancel: () => { + wipeModal.title = ''; + wipeModal.open = false; + } + }} + customTitle={wipeModal.title} +> + + { + partitionModal.open = false; + partitionModal.disk = null; + }} +/> diff --git a/new-web/src/routes/[node]/storage/disks/+page.ts b/new-web/src/routes/[node]/storage/disks/+page.ts new file mode 100644 index 00000000..34c9c34a --- /dev/null +++ b/new-web/src/routes/[node]/storage/disks/+page.ts @@ -0,0 +1,17 @@ +import { listDisks } from '$lib/api/disk/disk'; +import { getPools } from '$lib/api/zfs/pool'; +import { SEVEN_DAYS } from '$lib/utils'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = SEVEN_DAYS; + const [disks, pools] = await Promise.all([ + cachedFetch('disks', async () => await listDisks(), cacheDuration), + cachedFetch('pools', getPools, cacheDuration) + ]); + + return { + disks, + pools + }; +} diff --git a/new-web/src/routes/[node]/storage/zfs/dashboard/+page.svelte b/new-web/src/routes/[node]/storage/zfs/dashboard/+page.svelte new file mode 100644 index 00000000..0d817ea4 --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/dashboard/+page.svelte @@ -0,0 +1,354 @@ + + +{#snippet card(type: string)} + + + +
    + + {getCardDetails(type).title} +
    +
    +
    + +

    + {counts[type as CardType]} +

    +
    +
    +{/snippet} + +
    +
    + {#each ['pools', 'datasets', 'file_systems', 'volumes', 'snapshots'] as type} +
    + {@render card(type)} +
    + {/each} +
    + +
    + {#if pools.length > 0} +
    + + + +
    +
    + + Pool Usage +
    + +
    +
    +
    + + +
    + +
    +
    +
    +
    + +
    + + + +
    +
    + + Dataset Compression +
    + +
    +
    +
    + + +
    + {#if histograms.compression.data.length === 0} +

    No data available

    + {:else} + + {/if} +
    +
    +
    +
    + +
    + + + +
    +
    + + PoolStats +
    + +
    + + +
    +
    +
    +
    + + +
    + {#if poolStatsData.length === 0} +

    No data available

    + {:else} + + {/if} +
    +
    +
    +
    + {/if} +
    +
    diff --git a/new-web/src/routes/[node]/storage/zfs/dashboard/+page.ts b/new-web/src/routes/[node]/storage/zfs/dashboard/+page.ts new file mode 100644 index 00000000..7d83a1ad --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/dashboard/+page.ts @@ -0,0 +1,19 @@ +import { getDatasets } from '$lib/api/zfs/datasets'; +import { getPools, getPoolStats } from '$lib/api/zfs/pool'; +import { SEVEN_DAYS } from '$lib/utils'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = SEVEN_DAYS; + const [datasets, pools, poolStats] = await Promise.all([ + cachedFetch('datasets', async () => await getDatasets(), cacheDuration), + cachedFetch('pools', getPools, cacheDuration), + cachedFetch('pool-stats', async () => await getPoolStats(1, 128), cacheDuration) + ]); + + return { + pools: pools, + datasets: datasets, + poolStats: poolStats + }; +} diff --git a/new-web/src/routes/[node]/storage/zfs/datasets/fs/+page.svelte b/new-web/src/routes/[node]/storage/zfs/datasets/fs/+page.svelte new file mode 100644 index 00000000..5fbcd7b5 --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/datasets/fs/+page.svelte @@ -0,0 +1,1008 @@ + + +{#snippet button(type: string)} + {#if activeRows && activeRows.length == 1} + {#if type === 'rollback-snapshot' && activeDataset?.type === 'snapshot'} + + {/if} + + {#if type === 'delete-snapshot' && activeDataset?.type === 'snapshot'} + + {/if} + + {#if type === 'create-snapshot' && activeDataset?.type === 'filesystem'} + + {/if} + + {#if type === 'delete-filesystem' && activeDataset?.type === 'filesystem' && activeDataset?.name.includes('/')} + + {/if} + {:else if activeRows && activeRows.length > 1} + {#if activeDatasets.length > 0 && !poolsSelected} + {#if type === 'bulk-delete'} + + {/if} + {/if} + {/if} +{/snippet} + +
    +
    + + + + {@render button('create-snapshot')} + {@render button('rollback-snapshot')} + {@render button('delete-snapshot')} + {@render button('delete-filesystem')} + {@render button('bulk-delete')} +
    + + +
    + +{#if confirmModals.active == 'deleteSnapshot' || confirmModals.active == 'deleteFilesystem'} + { + if (confirmModals.active) { + confirmAction(); + } + }, + onCancel: () => { + if (confirmModals.active) { + confirmModals[confirmModals.active].open = false; + } + } + }} + > +{/if} + +{#if confirmModals.active === 'bulkDeleteDatasets'} + { + if (confirmModals.active) { + confirmAction(); + } + }, + onCancel: () => { + if (confirmModals.active) { + confirmModals[confirmModals.active].open = false; + } + } + }} + > +{/if} + +{#if confirmModals.active === 'rollbackSnapshot'} + ${confirmModals[confirmModals.active].data.name}?`} + names={{ + parent: confirmModals.parent, + element: confirmModals.active ? confirmModals[confirmModals.active].title || '' : '' + }} + actions={{ + onConfirm: () => { + if (confirmModals.active) { + confirmAction(); + } + }, + onCancel: () => { + if (confirmModals.active) { + confirmModals[confirmModals.active].open = false; + } + } + }} + > +{/if} + +{#if confirmModals.active === 'createSnapshot'} + + +
    + + +
    + + Snapshot - + {confirmModals.createSnapshot.data.name !== '' + ? `${confirmModals.createSnapshot.title}@${confirmModals.createSnapshot.data.name}` + : `${confirmModals.createSnapshot.title}`} +
    +
    +
    +
    + + +
    +
    + +
    + + +
    + +
    + + +
    + + + + +
    +
    +{/if} + +{#if confirmModals.active === 'createFilesystem'} + + +
    + + + Create Filesystem + + +
    + + +
    +
    + +
    +
    +
    + + +
    + +
    + + { + confirmModals.createFilesystem.data.properties.parent = value?.value || ''; + }} + > + + + + + + + {#each grouped as pool} + {#each pool.filesystems as fs} + {fs.name} + {/each} + {/each} + + + +
    + +
    + + { + confirmModals.createFilesystem.data.properties.atime = value?.value || ''; + }} + > + + + + + + {#each zfsProperties.atime as option} + {option.label} + {/each} + + + + +
    + +
    + + { + confirmModals.createFilesystem.data.properties.checksum = value?.value || ''; + }} + > + + + + + + {#each zfsProperties.checksum as option} + {option.label} + {/each} + + + + +
    + +
    + + { + confirmModals.createFilesystem.data.properties.compression = value?.value || ''; + }} + > + + + + + + {#each zfsProperties.compression as option} + {option.label} + {/each} + + + + +
    + +
    + + { + confirmModals.createFilesystem.data.properties.dedup = value?.value || ''; + }} + > + + + + + + {#each zfsProperties.dedup as option} + {option.label} + {/each} + + + + +
    + +
    + + { + confirmModals.createFilesystem.data.properties.encryption = value?.value || ''; + }} + > + + + + + + {#each zfsProperties.encryption as option} + {option.label} + {/each} + + + + +
    + + {#if confirmModals.createFilesystem.data.properties.encryption !== 'off'} +
    + +
    + + + +
    +
    + {/if} + +
    + + +
    +
    +
    + + +
    + +
    +
    +
    +
    +{/if} diff --git a/new-web/src/routes/[node]/storage/zfs/datasets/fs/+page.ts b/new-web/src/routes/[node]/storage/zfs/datasets/fs/+page.ts new file mode 100644 index 00000000..96859628 --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/datasets/fs/+page.ts @@ -0,0 +1,17 @@ +import { getDatasets } from '$lib/api/zfs/datasets'; +import { getPools } from '$lib/api/zfs/pool'; +import { SEVEN_DAYS } from '$lib/utils'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = SEVEN_DAYS; + const [datasets, pools] = await Promise.all([ + cachedFetch('datasets', async () => await getDatasets(), cacheDuration), + cachedFetch('pools', getPools, cacheDuration) + ]); + + return { + pools: pools, + datasets: datasets + }; +} diff --git a/new-web/src/routes/[node]/storage/zfs/datasets/snapshots/+page.svelte b/new-web/src/routes/[node]/storage/zfs/datasets/snapshots/+page.svelte new file mode 100644 index 00000000..33bb1989 --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/datasets/snapshots/+page.svelte @@ -0,0 +1,538 @@ + + +{#snippet button(type: string)} + {#if type === 'delete-snapshot' && activeDataset !== null} + + {/if} + + {#if type === 'view-periodics' && activePeriodics.length > 0} + + {/if} +{/snippet} + +
    +
    + + + + + + + + {@render button('delete-snapshot')} + {@render button('view-periodics')} +
    + + +
    + +{#if confirmModals.active === 'createSnapshot'} + + +
    + + +
    + + Snapshot {confirmModals.createSnapshot.extraTitle} +
    +
    +
    +
    + + +
    +
    + + +
    + + + +
    + +
    + +
    + + + + + + +
    +
    +{/if} + +{#if confirmModals.active === 'deleteSnapshot'} + + + + {getTranslation('are_you_sure', 'Are you sure?')} + + +
    + {getTranslation( + 'common.permanent_delete_msg', + 'This action cannot be undone. This will permanently delete' + )} + {confirmModals.parent} + {confirmModals[confirmModals.active].title}. +
    + +
    + + +
    + + + { + confirmModals[confirmModals.active].open = false; + }} + > + Cancel + + { + confirmAction(); + }} + > + Delete + + +
    +
    +{/if} + + diff --git a/new-web/src/routes/[node]/storage/zfs/datasets/snapshots/+page.ts b/new-web/src/routes/[node]/storage/zfs/datasets/snapshots/+page.ts new file mode 100644 index 00000000..16d1b8a7 --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/datasets/snapshots/+page.ts @@ -0,0 +1,19 @@ +import { getDatasets, getPeriodicSnapshots } from '$lib/api/zfs/datasets'; +import { getPools } from '$lib/api/zfs/pool'; +import { SEVEN_DAYS } from '$lib/utils'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = SEVEN_DAYS; + const [datasets, pools, periodicSnapshots] = await Promise.all([ + cachedFetch('datasets', async () => await getDatasets(), cacheDuration), + cachedFetch('pools', getPools, cacheDuration), + cachedFetch('periodicSnapshots', async () => await getPeriodicSnapshots(), cacheDuration) + ]); + + return { + pools: pools, + periodicSnapshots: periodicSnapshots, + datasets: datasets + }; +} diff --git a/new-web/src/routes/[node]/storage/zfs/datasets/volumes/+page.svelte b/new-web/src/routes/[node]/storage/zfs/datasets/volumes/+page.svelte new file mode 100644 index 00000000..c7143f2c --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/datasets/volumes/+page.svelte @@ -0,0 +1,836 @@ + + +{#snippet button(type: string)} + {#if activeRows && activeRows.length == 1} + {#if type === 'create-snapshot' && activeVolume?.type === 'volume'} + + {/if} + + {#if type === 'delete-snapshot' && activeSnapshot?.type === 'snapshot'} + + {/if} + + {#if type === 'delete-volume' && activeVolume?.type === 'volume'} + + {/if} + {:else if activeRows && activeRows.length > 1} + {#if activeVolumes.length > 0 && type === 'delete-volumes' && !isPoolSelected} + + {/if} + {/if} +{/snippet} + +
    +
    + + + + {@render button('create-snapshot')} + {@render button('delete-snapshot')} + {@render button('delete-volume')} + {@render button('delete-volumes')} +
    + + +
    + +{#snippet simpleSlect(prop: keyof props, label: string, placeholder: string)} +
    + + option.value === confirmModals.createVolume.data.properties[prop] + )?.label || confirmModals.createVolume.data.properties[prop], + value: confirmModals.createVolume.data.properties[prop] + }} + onSelectedChange={(value) => { + confirmModals.createVolume.data.properties[prop] = value?.value || ''; + }} + > + + + + + + + {#each zfsProperties[prop] as option} + {option.label} + {/each} + + + +
    +{/snippet} + +{#if confirmModals.active === 'createVolume'} + + +
    + + + Create Volume + +
    + + +
    +
    + +
    +
    +
    + + +
    + +
    + + +
    + +
    + + { + confirmModals.createVolume.data.properties.parent = value?.value || ''; + }} + > + + + + + + + {#each grouped as group} + {group.pool.name} + {/each} + + + +
    + + {@render simpleSlect('volblocksize', 'Block Size', 'Select block size')} + {@render simpleSlect('checksum', 'Checksum', 'Select checksum algorithm')} + {@render simpleSlect('compression', 'Compression', 'Select compression type')} + {@render simpleSlect('dedup', 'Deduplication', 'Select deduplication mode')} + {@render simpleSlect('encryption', 'Encryption', 'Select encryption')} + {@render simpleSlect('primarycache', 'Primary Cache', 'Select primary cache mode')} + {@render simpleSlect('volmode', 'Volume Mode', 'Select volume mode')} + + {#if confirmModals.createVolume.data.properties.encryption !== 'off'} +
    + +
    + + + +
    +
    + {/if} +
    +
    + + +
    + +
    +
    +
    +
    +{/if} + +{#if confirmModals.active == 'deleteVolume'} + { + if (confirmModals.active) { + confirmAction(); + } + }, + onCancel: () => { + if (confirmModals.active) { + confirmModals[confirmModals.active].open = false; + } + } + }} + > +{/if} + +{#if confirmModals.active == 'deleteVolumes'} + { + if (confirmModals.active) { + confirmAction(); + } + }, + onCancel: () => { + if (confirmModals.active) { + console.log(confirmModals[confirmModals.active]); + confirmModals[confirmModals.active].open = false; + } + } + }} + > +{/if} + +{#if confirmModals.active === 'createSnapshot'} + + +
    + + +
    + + Snapshot - + {confirmModals.createSnapshot.data.name !== '' + ? `${confirmModals.createSnapshot.title}@${confirmModals.createSnapshot.data.name}` + : `${confirmModals.createSnapshot.title}`} +
    +
    +
    +
    + + +
    +
    + +
    + + +
    + + + + +
    +
    +{/if} + +{#if confirmModals.active == 'deleteSnapshot'} + { + if (confirmModals.active) { + confirmAction(); + } + }, + onCancel: () => { + if (confirmModals.active) { + confirmModals[confirmModals.active].open = false; + } + } + }} + > +{/if} diff --git a/new-web/src/routes/[node]/storage/zfs/datasets/volumes/+page.ts b/new-web/src/routes/[node]/storage/zfs/datasets/volumes/+page.ts new file mode 100644 index 00000000..96859628 --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/datasets/volumes/+page.ts @@ -0,0 +1,17 @@ +import { getDatasets } from '$lib/api/zfs/datasets'; +import { getPools } from '$lib/api/zfs/pool'; +import { SEVEN_DAYS } from '$lib/utils'; +import { cachedFetch } from '$lib/utils/http'; + +export async function load() { + const cacheDuration = SEVEN_DAYS; + const [datasets, pools] = await Promise.all([ + cachedFetch('datasets', async () => await getDatasets(), cacheDuration), + cachedFetch('pools', getPools, cacheDuration) + ]); + + return { + pools: pools, + datasets: datasets + }; +} diff --git a/new-web/src/routes/[node]/storage/zfs/pools/+page.svelte b/new-web/src/routes/[node]/storage/zfs/pools/+page.svelte new file mode 100644 index 00000000..996abb49 --- /dev/null +++ b/new-web/src/routes/[node]/storage/zfs/pools/+page.svelte @@ -0,0 +1,2068 @@ + + +{#snippet button(type: string)} + {#if activeRow && Object.keys(activeRow).length > 0} + {#if type === 'pool-status'} + {#if isPool(pools, activeRow.name)} + + {/if} + {/if} + + {#if type === 'pool-scrub'} + {#if isPool(pools, activeRow.name)} + + {/if} + {/if} + + {#if type === 'pool-edit'} + {#if isPool(pools, activeRow.name)} + + {/if} + {/if} + + {#if type === 'pool-delete'} + {#if isPool(pools, activeRow.name)} + + {/if} + {/if} + + {#if type === 'replace-device'} + {#if isReplaceableDevice(pools, activeRow.name)} + + {/if} + {/if} + {/if} +{/snippet} + +{#snippet diskContainer(type: string)} +
    + +
    + +
    + {#each useableDisks.filter((disk) => disk.type === type && disk.partitions.length === 0 && !isDiskInVdev(disk.uuid)) as disk (disk.uuid)} +
    +
    + {#if type === 'HDD'} + + {:else if type === 'SSD'} + + {:else if type === 'NVMe'} + + {/if} +
    +
    + {disk.device.replaceAll('/dev/', '')} +
    +
    + {humanFormat(disk.size)} +
    +
    + {/each} + + {#if useableDisks.filter((disk) => disk.type === type).length === 0 || useableDisks.filter((disk) => disk.type === type && disk.partitions.length === 0 && !isDiskInVdev(disk.uuid)).length === 0} +
    + {getTranslation('zfs.pool.no_available_disks', 'No available disks')} +
    + {/if} +
    +
    +
    +
    +{/snippet} + +{#snippet partitionsContainer()} +
    + +
    + +
    + {#each useablePartitions.filter((partition) => !modal.vdevContainers + .flatMap((vdev) => vdev.partitions) + .some((p) => p.name === partition.name)) as partition (partition.name)} +
    +
    + +
    +
    + {partition.name} +
    +
    + {humanFormat(partition.size)} +
    +
    + {/each} + + {#if useablePartitions.length === 0 || useablePartitions.filter((partition) => !modal.vdevContainers + .flatMap((vdev) => vdev.partitions) + .some((p) => p.name === partition.name)).length === 0} +
    + {getTranslation('zfs.pool.no_available_partitions', 'No available partitions')} +
    + {/if} +
    +
    +
    +
    +{/snippet} + +{#snippet vdevContainer(id: number)} + {#each modal.vdevContainers[id]?.disks || [] as disk (disk.uuid)} +
    + {#if disk.type === 'HDD'} + + {:else if disk.type === 'SSD'} + + {:else if disk.type === 'NVMe'} + + {/if} + +
    + {disk.device.split('/').pop()} +
    + + +
    + {/each} + + {#each modal.vdevContainers[id]?.partitions || [] as partition (partition.name)} +
    + + +
    + {partition.name.split('/').pop()} +
    + + +
    + {/each} +{/snippet} + +{#snippet vdevErrors(id: number)} + {#if getVdevErrors(id) !== ''} +
    + + + +

    + {@html getVdevErrors(id)} +

    +
    +
    +
    + {/if} +{/snippet} + +
    +
    + + + + {@render button('pool-status')} + {@render button('pool-scrub')} + {@render button('pool-edit')} + {@render button('pool-delete')} + {@render button('replace-device')} +
    + + +
    + + + +
    + + + {getTranslation( + 'zfs.pool.create_zfs_pool', + 'Create ZFS Pool' + )} + + +
    + + +
    +
    + + + + {capitalizeFirstLetter(getTranslation('common.devices', 'Devices'))} + + {capitalizeFirstLetter(getTranslation('common.options', 'Options'))} + + + + + + + + +
    + + rt.value === modal.raidType)?.label, + value: raidTypes.find((rt) => rt.value === modal.raidType)?.value + }} + onSelectedChange={(value) => { + modal.raidType = value?.value as ZpoolRaidType; + setRedundancyAvailability(); + }} + > + + + + + + {#each raidTypes as raidType} + {#if raidType.available} + {raidType.label} + {/if} + {/each} + + + +
    +
    + + +
    + + +
    + {#each Array(modal.vdevCount) as _, i} +
    + {@render vdevErrors(i)} + +
    handleDropToVdev(i, event), + dragover_class: 'droppable' + }} + > + {#if !vdevContains(i)} +
    + {i + 1} + Drop disks here +
    + {:else} +
    + {@render vdevContainer(i)} +
    + {/if} +
    +
    + {/each} +
    +
    +
    + + +
    + +
    + {@render diskContainer('HDD')} + {@render diskContainer('SSD')} + {@render diskContainer('NVMe')} + {@render partitionsContainer()} +
    +
    +
    +
    +
    + + + + +
    +
    + +