diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 9f07329ef..09b74deac 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -1,9 +1,13 @@ -name: "Chromatic Publish" +name: Chromatic -on: workflow_dispatch +on: + workflow_dispatch: + pull_request_review: + types: [submitted] jobs: test: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request_review' && github.event.review.state == 'approved') runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 diff --git a/guideGlobalMetadata.json b/guideGlobalMetadata.json index 711c4177d..671e14938 100644 --- a/guideGlobalMetadata.json +++ b/guideGlobalMetadata.json @@ -29,6 +29,7 @@ "PlexonRecordingInterface", "PlexonSortingInterface", "AxonaRecordingInterface", + "VideoInterface", "NeuralynxRecordingInterface", "AlphaOmegaRecordingInterface", "DeepLabCutInterface", @@ -40,6 +41,7 @@ "SpikeGLXConverterPipe", "BrukerTiffSinglePlaneConverter", "BrukerTiffMultiPlaneConverter", - "MiniscopeConverter" + "MiniscopeConverter", + "CellExplorerRecordingInterface" ] } diff --git a/schemas/json/generated/VideoInterface.json b/schemas/json/generated/VideoInterface.json new file mode 100644 index 000000000..259c53a3d --- /dev/null +++ b/schemas/json/generated/VideoInterface.json @@ -0,0 +1,28 @@ +{ + "required": [], + "properties": { + "VideoInterface": { + "required": [ + "file_paths" + ], + "properties": { + "file_paths": { + "type": "array" + }, + "verbose": { + "type": "boolean", + "default": false + } + }, + "type": "object", + "additionalProperties": false + } + }, + "type": "object", + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "source.schema.json", + "title": "Source data schema", + "description": "Schema for the source data, files and directories", + "version": "0.1.0" +} diff --git a/schemas/source-data.schema.ts b/schemas/source-data.schema.ts index f3622ee81..b47f5b51f 100644 --- a/schemas/source-data.schema.ts +++ b/schemas/source-data.schema.ts @@ -3,7 +3,16 @@ export default function preprocessSourceDataSchema (schema) { // Abstract across different interfaces - Object.values(schema.properties ?? {}).forEach((schema: any) => { + Object.entries(schema.properties ?? {}).forEach(([key, schema]: [string, any]) => { + + if (key === 'VideoInterface' || key === 'AudioInterface') { + if (schema.properties.file_paths) { + Object.assign(schema.properties.file_paths, { + description: 'Only one file supported at this time. Multiple file support coming soon.', + maxItems: 1, + }) + } + } // Do not show steps if (schema.properties.gain) schema.properties.gain.step = null diff --git a/src/main/main.ts b/src/main/main.ts index c49609885..f75cbfc29 100755 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -231,11 +231,14 @@ function initialize() { if (globals.mainWindow) return // Do not re-initialize if the main window is already declared + const minHeight = 800; + const minWidth = 1280; + const windowOptions = { - minWidth: 1121, - minHeight: 735, - width: 1121, - height: 735, + minWidth, + minHeight, + width: minWidth, + height: minHeight, center: true, show: false, icon, diff --git a/src/renderer/assets/css/nav.css b/src/renderer/assets/css/nav.css index e81e0d06c..494db926e 100755 --- a/src/renderer/assets/css/nav.css +++ b/src/renderer/assets/css/nav.css @@ -107,22 +107,41 @@ a[data-toggle="collapse"] { padding-bottom: 0px; } +#main-nav .sidebar-header img { + cursor: pointer; +} + #main-nav .sidebar-body { display: flex; flex-direction: column; justify-content: space-between; - overflow-y: auto; + overflow-y: hidden; margin-top: 15px; - border-top: 1px solid #d5d5d5; flex-grow: 1; + border-top: 1px solid #8f8f8f; +} + +#main-nav .sidebar-body > *:last-child { + background: var(--color-sidebar); + padding: 3px; + padding-top: 8px; + border-top: 1px solid #8f8f8f; +} + +#main-nav .sidebar-body > *:last-child h4 { + margin-top: 0px !important; } -#main-nav ul.components { +#main-nav .sidebar-body li { list-style: none; +} + +#main-nav ul { padding-right: 10px; padding-left: 3px; margin-right: 0; - margin-top: 10px; + margin-bottom: 0; + overflow-y: auto; } #main-nav ul p { diff --git a/src/renderer/src/pages.js b/src/renderer/src/pages.js index 1cf736108..7b30cda1d 100644 --- a/src/renderer/src/pages.js +++ b/src/renderer/src/pages.js @@ -37,6 +37,8 @@ dashboard.logo = logo; dashboard.name = "NWB GUIDE"; dashboard.renderNameInSidebar = false; +const resourcesGroup = "Resources"; + const overviewIcon = ` `${i + 1}. ${v}`).join("\n") : this.value} - @click=${() => isMultipleTypes || this.selectFormat()} - @dragenter=${() => { - this.classList.add("active"); - }} - @dragleave=${() => { - this.classList.remove("active"); - }} - @drop=${async (event) => { - event.preventDefault(); - event.stopPropagation(); - this.classList.remove("active"); - - let pathArr = []; - for (const f of event.dataTransfer.files) pathArr.push(f.path ?? f.name); - this.#handleFiles(pathArr); - }} - > - ${resolvedValueDisplay - ? html` - ${resolvedValueDisplay} - ${dialog - ? "" - : html`
Cannot get full ${isMultipleTypes ? this.type.join(" / ") : this.type} - path${this.multiple ? "s" : ""} on web distribution`} - ` - : html`Drop ${objectTypeReference} - here${isMultipleTypes +
+ + : html`
Cannot get full ${isMultipleTypes ? this.type.join(" / ") : this.type} + path${this.multiple ? "s" : ""} on web distribution`} + ` + : html`Drop ${objectTypeReference} + here${isMultipleTypes + ? "" + : `, or click to choose ${getObjectTypeReferenceString(this.type, this.multiple, { + native: true, + })}`}${this.multiple && + (this.type === "directory" || + (isMultipleTypes && this.type.includes("directory") && !dialog)) + ? html`
Multiple directory support only available using drag-and-drop.` + : ""}`} + + ${this.multiple && this.value.length > 1 + ? new List({ + items: this.value.map((v) => ({ value: v })), + editable: false, + onChange: function () { + instanceThis.value = this.items.map((item) => item.value); + }, + }) + : ""} +
${isMultipleTypes ? html`
${this.type.map( diff --git a/src/renderer/src/stories/List.ts b/src/renderer/src/stories/List.ts index 9e1f8a061..af3ad0222 100644 --- a/src/renderer/src/stories/List.ts +++ b/src/renderer/src/stories/List.ts @@ -317,6 +317,8 @@ export class List extends LitElement { this.items = [...this.items] } } + + this.onChange() // Register that the object has changed }; button.onClick = deleteListItem; diff --git a/src/renderer/src/stories/Table.js b/src/renderer/src/stories/Table.js index 9612ac6b6..9d211cd26 100644 --- a/src/renderer/src/stories/Table.js +++ b/src/renderer/src/stories/Table.js @@ -266,20 +266,20 @@ export class Table extends LitElement { } }; - let ogThis = this; + let instanceThis = this; const isRequired = this.isRequired(k); const validator = async function (value, callback) { - const validateEmptyCells = ogThis.validateEmptyCells; + const validateEmptyCells = instanceThis.validateEmptyCells; const willValidate = validateEmptyCells === true || (Array.isArray(validateEmptyCells) && validateEmptyCells.includes(k)); - value = ogThis.#getValue(value, colInfo); + value = instanceThis.#getValue(value, colInfo); // Clear empty values if not validated if (!value && !willValidate) { - ogThis.#handleValidationResult( + instanceThis.#handleValidationResult( [], // Clear errors this.row, this.col @@ -288,9 +288,9 @@ export class Table extends LitElement { return; } - if (value && k === ogThis.keyColumn && unresolved[this.row]) { - if (value in ogThis.data) { - ogThis.#handleValidationResult( + if (value && k === instanceThis.keyColumn && unresolved[this.row]) { + if (value in instanceThis.data) { + instanceThis.#handleValidationResult( [{ message: `${header(k)} already exists`, type: "error" }], this.row, this.col @@ -306,7 +306,7 @@ export class Table extends LitElement { } if (!value && isRequired) { - ogThis.#handleValidationResult( + instanceThis.#handleValidationResult( [{ message: `${header(k)} is a required property.`, type: "error" }], this.row, this.col diff --git a/src/renderer/src/stories/pages/guided-mode/data/GuidedSourceData.js b/src/renderer/src/stories/pages/guided-mode/data/GuidedSourceData.js index 86ff3c6e0..a3414cf75 100644 --- a/src/renderer/src/stories/pages/guided-mode/data/GuidedSourceData.js +++ b/src/renderer/src/stories/pages/guided-mode/data/GuidedSourceData.js @@ -104,14 +104,11 @@ export class GuidedSourceDataPage extends ManagedPage { if (isStorybook) return; if (result.message) { - const [ - type, - text = `
${result.traceback
-                                .trim()
-                                .split("\n")
-                                .slice(-2)[0]
-                                .trim()}
`, - ] = result.message.split(":"); + const [type, ...splitText] = result.message.split(":"); + const text = splitText.length + ? splitText.join(":").replaceAll("<", "<").replaceAll(">", ">") + : `
${result.traceback.trim().split("\n").slice(-2)[0].trim()}
`; + const message = `

Request Failed

${type}

${text}

`; this.notify(message, "error"); throw result; diff --git a/src/renderer/src/stories/sidebar.js b/src/renderer/src/stories/sidebar.js index 4e44801f7..aae92d3be 100644 --- a/src/renderer/src/stories/sidebar.js +++ b/src/renderer/src/stories/sidebar.js @@ -72,7 +72,7 @@ export class Sidebar extends LitElement { // Actually click the item let selectedItem = this.#selected ? (this.shadowRoot ?? this).querySelector(`ul[data-id='${this.#selected}']`) - : (this.shadowRoot ?? this).querySelector("ul").children[0]; + : (this.shadowRoot ?? this).querySelector("ul").querySelector("a"); if (this.initialize && selectedItem) selectedItem.click(); else if (this.#selected) this.selectItem(this.#selected); // Visually select the item @@ -139,7 +139,14 @@ export class Sidebar extends LitElement {