diff --git a/electron.vite.config.ts b/electron.vite.config.ts index e034b4c..484d702 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -10,7 +10,13 @@ export default defineConfig({ }, plugins: [ externalizeDepsPlugin({ - exclude: ['@holochain/client', 'nanoid', 'appstore-tools', '@spartan-hc/bundles'], + exclude: [ + '@holochain/client', + 'nanoid', + 'appstore-tools', + '@spartan-hc/bundles', + 'get-folder-size', + ], }), ], }, diff --git a/package.json b/package.json index 333c782..5abc9ed 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "electron-serve": "^1.2.0", "electron-trpc": "^0.6.1", "elliptic": "6.5.5", + "get-folder-size": "5.0.0", "hc-launcher-rust-utils": "file:./rust-utils/dist", "js-sha256": "^0.11.0", "nanoid": "5.0.7", diff --git a/src/main/filesystem.ts b/src/main/filesystem.ts index 52cbd7e..1ca13d8 100644 --- a/src/main/filesystem.ts +++ b/src/main/filesystem.ts @@ -1,6 +1,7 @@ import { platform } from '@electron-toolkit/utils'; import { type App, app, session } from 'electron'; import fs from 'fs'; +import getFolderSize from 'get-folder-size'; import { nanoid } from 'nanoid'; import path from 'path'; @@ -74,6 +75,26 @@ type BackupInfo = { lastPartialbackup?: string; }; +// type StorageInfo = { +// chromium: number; +// logs: number; +// holochain: Record; +// lair: number; +// }; + +type HolochainStorageInfo = { + apps: number; + happs: number; + uis: number; + wasmCache: number; + conductor: number; + authored: number; + cache: number; + dht: number; + p2p: number; + wasm: number; +}; + export class LauncherFileSystem { public profileDataDir: string; public profileLogsDir: string; @@ -202,6 +223,16 @@ export class LauncherFileSystem { return path.join(this.holochainDataBase(holochainDataRoot), UIS_DIRNAME); } + /** + * This is the directory in which holochain databases (conductor, authored, cache, ...) are being stored + * + * @param holochainDataRoot + * @returns + */ + dbsDir(holochainDataRoot: HolochainDataRoot) { + return path.join(this.holochainDataBase(holochainDataRoot), CONDUCTOR_ENV_DIRNAME); + } + /** * Directory where metadata of an app instance is stored. For example which UI * it currently uses. @@ -243,6 +274,39 @@ export class LauncherFileSystem { return fs.existsSync(path.join(this.keystoreDir, 'lair-keystore-config.yaml')); }; + async getHolochainStorageInfo( + holochainDataRoot: HolochainDataRoot, + ): Promise { + if (holochainDataRoot.type !== 'partition') + throw new Error('Cannot get storage info for external holochain.'); + const appsStorage = await getFolderSize.loose(this.appsDir(holochainDataRoot)); + const happsStorage = await getFolderSize.loose(this.happsDir(holochainDataRoot)); + const uisStorage = await getFolderSize.loose(this.uisDir(holochainDataRoot)); + const dbsDir = this.dbsDir(holochainDataRoot); + const databasesDir = path.join(dbsDir, 'databases'); + + const wasmCache = await getFolderSize.loose(path.join(dbsDir, 'wasm-cache')); + const conductor = await getFolderSize.loose(path.join(databasesDir, 'conductor')); + const authored = await getFolderSize.loose(path.join(databasesDir, 'authored')); + const cache = await getFolderSize.loose(path.join(databasesDir, 'cache')); + const dht = await getFolderSize.loose(path.join(databasesDir, 'dht')); + const p2p = await getFolderSize.loose(path.join(databasesDir, 'p2p')); + const wasm = await getFolderSize.loose(path.join(databasesDir, 'wasm')); + + return { + apps: appsStorage, + happs: happsStorage, + uis: uisStorage, + wasmCache: wasmCache, + conductor: conductor, + authored: authored, + cache: cache, + dht: dht, + p2p: p2p, + wasm: wasm, + }; + } + async factoryReset(keepLogs = false) { if (keepLogs) throw new Error('Keeping logs across factory reset is currently not supported.'); if (platform.isWindows) { diff --git a/src/main/index.ts b/src/main/index.ts index 4c183b8..27a9d68 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -873,6 +873,12 @@ const router = t.router({ return !isInitializedValidated; }), + getHolochainStorageInfo: t.procedure.query(() => { + const defaultHolochainManager = HOLOCHAIN_MANAGERS[BREAKING_DEFAULT_HOLOCHAIN_VERSION]; + const holochainDataRoot = defaultHolochainManager.holochainDataRoot; + // TODO if required, return storage info for all Holochain versions if there ever are multiple + return LAUNCHER_FILE_SYSTEM.getHolochainStorageInfo(holochainDataRoot); + }), defaultHolochainVersion: t.procedure.query( () => HOLOCHAIN_MANAGERS[BREAKING_DEFAULT_HOLOCHAIN_VERSION].version, ), diff --git a/src/renderer/package.json b/src/renderer/package.json index d8abfa3..1a3db2f 100644 --- a/src/renderer/package.json +++ b/src/renderer/package.json @@ -13,6 +13,7 @@ }, "dependencies": { "@floating-ui/dom": "^1.6.5", + "@shoelace-style/shoelace": "2.15.1", "@skeletonlabs/skeleton": "2.10.1", "@skeletonlabs/tw-plugin": "0.4.0", "@tanstack/svelte-query": "^5.46.1", diff --git a/src/renderer/src/lib/helpers/other.ts b/src/renderer/src/lib/helpers/other.ts index d192fce..317e143 100644 --- a/src/renderer/src/lib/helpers/other.ts +++ b/src/renderer/src/lib/helpers/other.ts @@ -15,6 +15,28 @@ import { } from '$shared/types'; import { AppstoreFilterListsSchema } from '$types/happs'; +export function recursiveSum(obj: any): number { + let sum = 0; + + for (let key in obj) { + if (typeof obj[key] === 'object') { + sum += recursiveSum(obj[key]); + } else { + sum += obj[key]; + } + } + + return sum; +} + +export function divideObject(obj: any, divider: number) { + const newObj: any = {}; + for (let key in obj) { + newObj[key] = obj[key]/divider; + } + return newObj; +} + export const getCellId = (cellInfo: unknown): CellId | undefined => { const parsedCellInfo = CellInfoSchema.safeParse(cellInfo); @@ -28,25 +50,25 @@ export const getCellId = (cellInfo: unknown): CellId | undefined => { }; export function getCellNetworkSeed(cellInfo: any): string | undefined { - if (CellType.Provisioned in cellInfo) { - return cellInfo.provisioned.dna_modifiers.network_seed; - } - if (CellType.Cloned in cellInfo) { - return cellInfo.cloned.dna_modifiers.network_seed; - } - return undefined; + if (CellType.Provisioned in cellInfo) { + return cellInfo.provisioned.dna_modifiers.network_seed; + } + if (CellType.Cloned in cellInfo) { + return cellInfo.cloned.dna_modifiers.network_seed; + } + return undefined; } export function getCellName(cellInfo: any): string | undefined { - if (CellType.Provisioned in cellInfo) { - return cellInfo.provisioned.name; - } - if (CellType.Cloned in cellInfo) { - return cellInfo.cloned.name; - } - if (CellType.Stem in cellInfo) { - return cellInfo.stem.name; - } + if (CellType.Provisioned in cellInfo) { + return cellInfo.provisioned.name; + } + if (CellType.Cloned in cellInfo) { + return cellInfo.cloned.name; + } + if (CellType.Stem in cellInfo) { + return cellInfo.stem.name; + } } export const isNonEmptyString = (value: unknown): value is string => diff --git a/src/renderer/src/routes/settings/(menu)/+page.svelte b/src/renderer/src/routes/settings/(menu)/+page.svelte index fedd7b9..b7be6d6 100644 --- a/src/renderer/src/routes/settings/(menu)/+page.svelte +++ b/src/renderer/src/routes/settings/(menu)/+page.svelte @@ -1,18 +1,53 @@ -
-
-

{$i18n.t('holochainVersion')}

- {#if $defaultHolochainVersion.data} -

- {$defaultHolochainVersion.data.type}{#if 'version' in $defaultHolochainVersion.data}: {$defaultHolochainVersion - .data.version}{/if} -

- {/if} +
+
+ Holochain Logo +
+ Holochain +
+ {#if $defaultHolochainVersion.data && $defaultHolochainVersion.data.type === 'built-in'} + {$defaultHolochainVersion.data.version} + {/if} +
+
+ {#if $storageInfoQuery.data} + {@const storageInfoMB = divideObject($storageInfoQuery.data, 1e6)} + {@const totalStorage = recursiveSum(storageInfoMB)} +
+
{Math.round(totalStorage)} MB Used
+
+ +
+
+ {/if}
diff --git a/src/renderer/src/routes/settings/components/PercentageBar.svelte b/src/renderer/src/routes/settings/components/PercentageBar.svelte new file mode 100644 index 0000000..3ab8cdf --- /dev/null +++ b/src/renderer/src/routes/settings/components/PercentageBar.svelte @@ -0,0 +1,41 @@ + + +
+ {#each Object.entries(values) as [label, value], idx} + +
+
+ {/each} +
diff --git a/src/shared/types/holochain.ts b/src/shared/types/holochain.ts index a2ad0b2..c2c51cd 100644 --- a/src/shared/types/holochain.ts +++ b/src/shared/types/holochain.ts @@ -71,7 +71,7 @@ export const AppInfoSchema = z.object({ status: InstalledAppInfoStatusSchema, }); -const HolochainDataRootSchema = z.union([ +export const HolochainDataRootSchema = z.union([ z.object({ type: z.literal('partition'), name: z.string(), diff --git a/yarn.lock b/yarn.lock index 892d7be..281f6c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -247,6 +247,11 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0" integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== +"@ctrl/tinycolor@^4.0.2": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-4.1.0.tgz#91a8f8120ffc9da2feb2a38f7862b300d5e9691a" + integrity sha512-WyOx8cJQ+FQus4Mm4uPIZA64gbk3Wxh0so5Lcii0aJifqwoVOlfFtorjLE0Hen4OYyHZMXDWqMmaQemBhgxFRQ== + "@dabh/diagnostics@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" @@ -530,6 +535,21 @@ dependencies: "@floating-ui/utils" "^0.2.0" +"@floating-ui/core@^1.6.0": + version "1.6.7" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.7.tgz#7602367795a390ff0662efd1c7ae8ca74e75fb12" + integrity sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g== + dependencies: + "@floating-ui/utils" "^0.2.7" + +"@floating-ui/dom@^1.5.3": + version "1.6.10" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.10.tgz#b74c32f34a50336c86dcf1f1c845cf3a39e26d6f" + integrity sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A== + dependencies: + "@floating-ui/core" "^1.6.0" + "@floating-ui/utils" "^0.2.7" + "@floating-ui/dom@^1.6.5": version "1.6.5" resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.5.tgz#323f065c003f1d3ecf0ff16d2c2c4d38979f4cb9" @@ -543,6 +563,11 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.2.tgz#d8bae93ac8b815b2bd7a98078cf91e2724ef11e5" integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw== +"@floating-ui/utils@^0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.7.tgz#d0ece53ce99ab5a8e37ebdfe5e32452a2bfc073e" + integrity sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA== + "@holochain/client@0.18.0-dev.1": version "0.18.0-dev.1" resolved "https://registry.yarnpkg.com/@holochain/client/-/client-0.18.0-dev.1.tgz#711193f1401e5f10ef13d94df4579b9842bcc2b2" @@ -617,6 +642,23 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@lit-labs/ssr-dom-shim@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.1.tgz#2f3a8f1d688935c704dbc89132394a41029acbb8" + integrity sha512-wx4aBmgeGvFmOKucFKY+8VFJSYZxs9poN3SDNQFF6lT6NrQUnHiPB2PWz2sc4ieEcAaYYzN+1uWahEeTq2aRIQ== + +"@lit/react@^1.0.0": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@lit/react/-/react-1.0.5.tgz#9c53a8d719f91ef7edca0bdd68f5589ea579ffc1" + integrity sha512-RSHhrcuSMa4vzhqiTenzXvtQ6QDq3hSPsnHHO3jaPmmvVFeoNNm4DHoQ0zLdKAUvY3wP3tTENSUf7xpyVfrDEA== + +"@lit/reactive-element@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-2.0.4.tgz#8f2ed950a848016383894a26180ff06c56ae001b" + integrity sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ== + dependencies: + "@lit-labs/ssr-dom-shim" "^1.2.0" + "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -985,6 +1027,30 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz#0bb7ac3cd1c3292db1f39afdabfd03ccea3a3d34" integrity sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag== +"@shoelace-style/animations@^1.1.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@shoelace-style/animations/-/animations-1.2.0.tgz#e92dd4502f0585697d81df8305f31182b499b737" + integrity sha512-avvo1xxkLbv2dgtabdewBbqcJfV0e0zCwFqkPMnHFGbJbBHorRFfMAHh1NG9ymmXn0jW95ibUVH03E1NYXD6Gw== + +"@shoelace-style/localize@^3.1.2": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@shoelace-style/localize/-/localize-3.2.1.tgz#9aa0078bef68a357070b104df95c75701c962c79" + integrity sha512-r4C9C/5kSfMBIr0D9imvpRdCNXtUNgyYThc4YlS6K5Hchv1UyxNQ9mxwj+BTRH2i1Neits260sR3OjKMnplsFA== + +"@shoelace-style/shoelace@2.15.1": + version "2.15.1" + resolved "https://registry.yarnpkg.com/@shoelace-style/shoelace/-/shoelace-2.15.1.tgz#2fa6bd8e493801f5b5b4744fab0fa108bbc01934" + integrity sha512-3ecUw8gRwOtcZQ8kWWkjk4FTfObYQ/XIl3aRhxprESoOYV1cYhloYPsmQY38UoL3+pwJiZb5+LzX0l3u3Zl0GA== + dependencies: + "@ctrl/tinycolor" "^4.0.2" + "@floating-ui/dom" "^1.5.3" + "@lit/react" "^1.0.0" + "@shoelace-style/animations" "^1.1.0" + "@shoelace-style/localize" "^3.1.2" + composed-offset-position "^0.0.4" + lit "^3.0.0" + qr-creator "^1.0.0" + "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" @@ -1243,6 +1309,11 @@ resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== +"@types/trusted-types@^2.0.2": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== + "@types/verror@^1.10.3": version "1.10.10" resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.10.tgz#d5a4b56abac169bfbc8b23d291363a682e6fa087" @@ -2008,6 +2079,11 @@ compare-version@^0.1.2: resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080" integrity sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A== +composed-offset-position@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/composed-offset-position/-/composed-offset-position-0.0.4.tgz#ca8854abf15e3c235ecf4df125a27fe88af76ea4" + integrity sha512-vMlvu1RuNegVE0YsCDSV/X4X10j56mq7PCIyOKK74FxkXzGLwhOUmdkJLSdOBOMwWycobGUMgft2lp+YgTe8hw== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -2911,6 +2987,11 @@ get-east-asian-width@^1.0.0: resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz#5e6ebd9baee6fb8b7b6bd505221065f0cd91f64e" integrity sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA== +get-folder-size@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/get-folder-size/-/get-folder-size-5.0.0.tgz#554a248ec8315871f89d467244f52b4c9f94cde1" + integrity sha512-+fgtvbL83tSDypEK+T411GDBQVQtxv+qtQgbV+HVa/TYubqDhNd5ghH/D6cOHY9iC5/88GtOZB7WI8PXy2A3bg== + get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" @@ -3115,7 +3196,7 @@ hasown@^2.0.0: function-bind "^1.1.2" "hc-launcher-rust-utils@file:./rust-utils/dist": - version "0.202.1" + version "0.203.3" he@1.2.0: version "1.2.0" @@ -3574,6 +3655,31 @@ listr2@~8.2.1: rfdc "^1.3.1" wrap-ansi "^9.0.0" +lit-element@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-4.1.0.tgz#cea3eb25f15091e3fade07c4d917fa6aaf56ba7d" + integrity sha512-gSejRUQJuMQjV2Z59KAS/D4iElUhwKpIyJvZ9w+DIagIQjfJnhR20h2Q5ddpzXGS+fF0tMZ/xEYGMnKmaI/iww== + dependencies: + "@lit-labs/ssr-dom-shim" "^1.2.0" + "@lit/reactive-element" "^2.0.4" + lit-html "^3.2.0" + +lit-html@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-3.2.0.tgz#cb09071a8a1f5f0850873f9143f18f0260be1fda" + integrity sha512-pwT/HwoxqI9FggTrYVarkBKFN9MlTUpLrDHubTmW4SrkL3kkqW5gxwbxMMUnbbRHBC0WTZnYHcjDSCM559VyfA== + dependencies: + "@types/trusted-types" "^2.0.2" + +lit@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lit/-/lit-3.2.0.tgz#2189d72bccbc335f733a67bfbbd295f015e68e05" + integrity sha512-s6tI33Lf6VpDu7u4YqsSX78D28bYQulM+VAzsGch4fx2H0eLZnJsUBsPWmGYSGoKDNbjtRv02rio1o+UdPVwvw== + dependencies: + "@lit/reactive-element" "^2.0.4" + lit-element "^4.1.0" + lit-html "^3.2.0" + localforage@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" @@ -4354,6 +4460,11 @@ purgecss@^6.0.0: postcss "^8.4.4" postcss-selector-parser "^6.0.7" +qr-creator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/qr-creator/-/qr-creator-1.0.0.tgz#f350a8f0b5be02bd1fc1ef133a038a06ef8bc5ef" + integrity sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"