diff --git a/src/electron/frontend/core/components/ProgressBar.ts b/src/electron/frontend/core/components/ProgressBar.ts index 46369e77b..8eeb71dab 100644 --- a/src/electron/frontend/core/components/ProgressBar.ts +++ b/src/electron/frontend/core/components/ProgressBar.ts @@ -1,6 +1,7 @@ import { LitElement, html, css, unsafeCSS } from 'lit'; +import { humanReadableBytes } from './utils/size'; export type ProgressProps = { size?: string, @@ -14,28 +15,6 @@ export type ProgressProps = { } } -export function humanReadableBytes(size: number | string) { - - // Define the units - const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - - // Initialize the index to 0 - let index = 0; - - // Convert the size to a floating point number - size = parseFloat(size); - - // Loop until the size is less than 1024 and increment the unit - while (size >= 1000 && index < units.length - 1) { - size /= 1000; - index += 1; - } - - // Return the size formatted with 2 decimal places and the appropriate unit - return `${size.toFixed(2)} ${units[index]}`; -} - - const animationDuration = 500 // ms export class ProgressBar extends LitElement { diff --git a/src/electron/frontend/core/components/pages/guided-mode/data/GuidedBackendConfiguration.js b/src/electron/frontend/core/components/pages/guided-mode/data/GuidedBackendConfiguration.js index 101de4642..035e576f3 100644 --- a/src/electron/frontend/core/components/pages/guided-mode/data/GuidedBackendConfiguration.js +++ b/src/electron/frontend/core/components/pages/guided-mode/data/GuidedBackendConfiguration.js @@ -13,9 +13,8 @@ import { until } from "lit/directives/until.js"; import { resolve } from "../../../../promises"; import { InstanceManager } from "../../../InstanceManager.js"; import { InspectorListItem } from "../../../preview/inspector/InspectorList.js"; -import { JSONSchemaInput } from "../../../JSONSchemaInput.js"; -import { getResourceUsage } from "../../../../validation/backend-configuration"; +import { getResourceUsageBytes } from "../../../../validation/backend-configuration"; import { resolveBackendResults, updateSchema } from "../../../../../../../schemas/backend-configuration.schema"; import { getInfoFromId } from "./utils.js"; @@ -187,7 +186,7 @@ export class GuidedBackendConfigurationPage extends ManagedPage { if (name === "chunk_shape") { const input = instance.getFormElement(path).inputs["chunk_shape"]; - const mbUsage = getResourceUsage(value, itemsizes[path.join("/")], 1e6); + const mbUsage = getResourceUsageBytes(value, itemsizes[path.join("/")], 1e6); if (mbUsage > 20) errors.push({ @@ -287,32 +286,34 @@ export class GuidedBackendConfigurationPage extends ManagedPage { header: "Sessions", instanceType: "Session", instances, + controls: [ - (id) => { - const instanceInfo = id - .split("/") - .reduce((acc, key) => acc[key.split("-").slice(1).join("-")], this.localState.results); - - const backend = instanceInfo.configuration.backend ?? this.workflow.file_format.value; - - return new JSONSchemaInput({ - path: [], - schema: { - type: "string", - placeholder: "Select backend type", - enum: Object.keys(backendMap), - enumLabels: backendMap, - strict: true, - }, - value: backend, - onUpdate: async (value) => { - if (instanceInfo.configuration.backend === value) return; - instanceInfo.configuration.backend = value; // Ensure new backend choice is persistent - await this.save(); - await this.#update(); - }, - }); - }, + // // NOTE: Removes session-specific control over the backend type since Zarr is not completely supported yet + // (id) => { + // const instanceInfo = id + // .split("/") + // .reduce((acc, key) => acc[key.split("-").slice(1).join("-")], this.localState.results); + + // const backend = instanceInfo.configuration.backend ?? this.workflow.file_format.value; + + // return new JSONSchemaInput({ + // path: [], + // schema: { + // type: "string", + // placeholder: "Select backend type", + // enum: Object.keys(backendMap), + // enumLabels: backendMap, + // strict: true, + // }, + // value: backend, + // onUpdate: async (value) => { + // if (instanceInfo.configuration.backend === value) return; + // instanceInfo.configuration.backend = value; // Ensure new backend choice is persistent + // await this.save(); + // await this.#update(); + // }, + // }); + // }, { name: "Save & Validate", primary: true, diff --git a/src/electron/frontend/core/components/pages/guided-mode/setup/Preform.js b/src/electron/frontend/core/components/pages/guided-mode/setup/Preform.js index 581a533d3..dfd122667 100644 --- a/src/electron/frontend/core/components/pages/guided-mode/setup/Preform.js +++ b/src/electron/frontend/core/components/pages/guided-mode/setup/Preform.js @@ -66,6 +66,7 @@ const questions = { title: "What file format would you like to use?", description: "Choose a default file format for your data.", default: "hdf5", + ignore: true, // NOTE: This ensures that users can only use the default (HDF5) format }, backend_configuration: { @@ -92,6 +93,11 @@ const defaults = Object.entries(questions).reduce((acc, [name, info]) => { return acc; }, {}); +const ignore = Object.entries(questions).reduce((acc, [name, info]) => { + if (info.ignore) acc[name] = true; + return acc; +}, {}); + const dependents = Object.entries(questions).reduce((acc, [name, info]) => { acc[name] = []; @@ -160,6 +166,7 @@ export class GuidedPreform extends Page { this.form = new JSONSchemaForm({ schema, + ignore, results: this.state, validateEmptyValues: false, // Only show errors after submission validateOnChange: function (name, parent, path, value) { diff --git a/src/electron/frontend/core/components/pages/settings/SettingsPage.js b/src/electron/frontend/core/components/pages/settings/SettingsPage.js index d5ea234ea..5c7088506 100644 --- a/src/electron/frontend/core/components/pages/settings/SettingsPage.js +++ b/src/electron/frontend/core/components/pages/settings/SettingsPage.js @@ -32,7 +32,8 @@ import examplePipelines from "../../../../../../example_pipelines.yml"; import { run } from "../guided-mode/options/utils.js"; import { joinPath } from "../../../globals"; import { Modal } from "../../Modal"; -import { ProgressBar, humanReadableBytes } from "../../ProgressBar"; +import { ProgressBar } from "../../ProgressBar"; +import { humanReadableBytes } from "../../utils/size"; const DATA_OUTPUT_PATH = joinPath(testDataFolderPath, "single_session_data"); const DATASET_OUTPUT_PATH = joinPath(testDataFolderPath, "multi_session_dataset"); diff --git a/src/electron/frontend/core/components/utils/size.ts b/src/electron/frontend/core/components/utils/size.ts new file mode 100644 index 000000000..2e0888134 --- /dev/null +++ b/src/electron/frontend/core/components/utils/size.ts @@ -0,0 +1,20 @@ +export function humanReadableBytes(size: number | string) { + + // Define the units + const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + + // Initialize the index to 0 + let index = 0; + + // Convert the size to a floating point number + size = parseFloat(size); + + // Loop until the size is less than 1024 and increment the unit + while (size >= 1000 && index < units.length - 1) { + size /= 1000; + index += 1; + } + + // Return the size formatted with 2 decimal places and the appropriate unit + return `${size.toFixed(2)} ${units[index]}`; +} diff --git a/src/electron/frontend/core/validation/backend-configuration.ts b/src/electron/frontend/core/validation/backend-configuration.ts index 516482788..16431dc93 100644 --- a/src/electron/frontend/core/validation/backend-configuration.ts +++ b/src/electron/frontend/core/validation/backend-configuration.ts @@ -1,3 +1,7 @@ +import { humanReadableBytes } from "../components/utils/size"; + const prod = (arr: number[]) => arr.reduce((accumulator, currentValue) => accumulator * currentValue, 1); -export const getResourceUsage = (shape: number[], itemsize: number, scale=1e9) => prod(shape) * (itemsize / scale) // Default to GB +export const getResourceUsageBytes = (shape: number[], itemsize: number, scale=1e9) => prod(shape) * (itemsize / scale) // Default to GB + +export const getResourceUsage = (shape: number[], itemsize: number) => humanReadableBytes(getResourceUsageBytes(shape, itemsize, 1)) diff --git a/src/schemas/backend-configuration.schema.ts b/src/schemas/backend-configuration.schema.ts index c7770fd50..2b36b5aed 100644 --- a/src/schemas/backend-configuration.schema.ts +++ b/src/schemas/backend-configuration.schema.ts @@ -14,7 +14,8 @@ export const resolveBackendResults = (schema, results, itemsize) => { const { full_shape } = results; if (copy.properties.filter_methods) copy.properties.filter_methods.description = "The ordered collection of filtering methods to apply to this dataset prior to compression.
Set blank to disable filtering" copy.properties.compression_method.description = "The specified compression method to apply to this dataset.
Set blank to disable compression" - copy.description = `Full Shape: ${full_shape}
Source size: ${getResourceUsage(full_shape, itemsize).toFixed(2)} GB`; // This is static + delete copy.properties.compression_method.default // Remove gzip as the default compression method + copy.description = `Full Shape: ${full_shape.join(' x ')}
Source size: ${getResourceUsage(full_shape, itemsize)}`; // This is static updateSchema(copy, results, itemsize) @@ -28,12 +29,12 @@ const propertiesToUpdate = [ ] // const bufferShapeDescription = (value, itemsize) => { -// return `Expected RAM usage: ${getResourceUsage(value, itemsize).toFixed(2)} GB.`; +// return `Expected RAM usage: ${getResourceUsage(value, itemsize)}.`; // } const chunkShapeDescription = (value, itemsize) => { const hasNull = value.includes(null) || value.includes(undefined); // Both null after JSON processing - const diskSpaceMessage = hasNull ? 'Disk space usage will be determined automatically' : `Disk space usage per chunk: ${getResourceUsage(value, itemsize, 1e6).toFixed(2)} MB`; + const diskSpaceMessage = hasNull ? 'Disk space usage will be determined automatically' : `Disk space usage per chunk: ${getResourceUsage(value, itemsize)}`; return `${diskSpaceMessage}
Leave blank to auto-specify the axis`; }