diff --git a/schemas/json/dandi/global.json b/schemas/json/dandi/global.json index 15ad771c0..c841a1cf8 100644 --- a/schemas/json/dandi/global.json +++ b/schemas/json/dandi/global.json @@ -2,7 +2,8 @@ "properties": { "api_key": { "type": "string", - "format": "password" + "format": "password", + "description": "Log in to DANDI, click on your user initials in the top-right corner, and copy your API key from the resulting pop-up.
Note: The main archive and the staging (testing) server have different API keys." } }, "required": ["api_key"] diff --git a/src/renderer/src/stories/DandiResults.js b/src/renderer/src/stories/DandiResults.js index 86cb1e29b..8f1c4cd52 100644 --- a/src/renderer/src/stories/DandiResults.js +++ b/src/renderer/src/stories/DandiResults.js @@ -36,8 +36,7 @@ export class DandiResults extends LitElement { const otherElIds = ["embargo_status"]; - const liveId = this.id; // '000552' // From Huszar - const dandiset = await get(liveId, isStaging(this.id) ? "staging" : undefined); + const dandiset = await get(this.id, isStaging(this.id) ? "staging" : undefined); otherElIds.forEach((str) => handleId(str, dandiset)); elIds.forEach((str) => handleId(str, dandiset.draft_version)); diff --git a/src/renderer/src/stories/Dashboard.js b/src/renderer/src/stories/Dashboard.js index 121391965..70ad37502 100644 --- a/src/renderer/src/stories/Dashboard.js +++ b/src/renderer/src/stories/Dashboard.js @@ -233,10 +233,13 @@ export class Dashboard extends LitElement { pageState = state.pages[id] = { visited: false, active: false, + saved: false, pageLabel: page.info.label, pageTitle: page.info.title, }; + info.states = pageState; + state.active = false; pageState.active = false; diff --git a/src/renderer/src/stories/JSONSchemaForm.js b/src/renderer/src/stories/JSONSchemaForm.js index 3fc1d1219..aa2912722 100644 --- a/src/renderer/src/stories/JSONSchemaForm.js +++ b/src/renderer/src/stories/JSONSchemaForm.js @@ -1,4 +1,6 @@ import { LitElement, css, html } from "lit"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; + import { Accordion } from "./Accordion"; import { checkStatus } from "../validation"; diff --git a/src/renderer/src/stories/JSONSchemaForm.stories.js b/src/renderer/src/stories/JSONSchemaForm.stories.js index 97dad2eb3..a59857ef8 100644 --- a/src/renderer/src/stories/JSONSchemaForm.stories.js +++ b/src/renderer/src/stories/JSONSchemaForm.stories.js @@ -22,6 +22,7 @@ const defaultSchema = { test: { type: "string", default: true, + description: "This is a test description", }, warn: { type: "string", diff --git a/src/renderer/src/stories/JSONSchemaInput.js b/src/renderer/src/stories/JSONSchemaInput.js index b6bfd37cd..fde0b43af 100644 --- a/src/renderer/src/stories/JSONSchemaInput.js +++ b/src/renderer/src/stories/JSONSchemaInput.js @@ -77,6 +77,8 @@ export class JSONSchemaInput extends LitElement { width: 100%; padding-top: 4px; color: dimgray !important; + margin: 0 0 1em; + line-height: 1.4285em; } `; } diff --git a/src/renderer/src/stories/pages/Page.js b/src/renderer/src/stories/pages/Page.js index bbcc0d0a6..c4a52659b 100644 --- a/src/renderer/src/stories/pages/Page.js +++ b/src/renderer/src/stories/pages/Page.js @@ -64,7 +64,7 @@ export class Page extends LitElement { this.beforeTransition(); // Otherwise note unsaved updates if present - if (this.unsavedUpdates) { + if (this.unsavedUpdates || this.info.states?.saved) { if (transition === 1) await this.save(); // Save before a single forward transition else { Swal.fire({ @@ -95,6 +95,7 @@ export class Page extends LitElement { save = async (overrides, runBeforeSave = true) => { if (runBeforeSave) await this.beforeSave(); save(this, overrides); + this.info.states.saved = true; this.unsavedUpdates = false; }; diff --git a/src/renderer/src/stories/pages/guided-mode/options/GuidedUpload.js b/src/renderer/src/stories/pages/guided-mode/options/GuidedUpload.js index d05b9bcd9..24a9c3f99 100644 --- a/src/renderer/src/stories/pages/guided-mode/options/GuidedUpload.js +++ b/src/renderer/src/stories/pages/guided-mode/options/GuidedUpload.js @@ -17,7 +17,7 @@ export class GuidedUploadPage extends Page { beforeSave = () => { const globalState = this.info.globalState; - const isNewDandiset = globalState.upload.dandiset_id !== this.localState.dandiset_id; + const isNewDandiset = globalState.upload?.dandiset_id !== this.localState.dandiset_id; merge({ upload: this.localState }, globalState); // Merge the local and global states if (isNewDandiset) delete globalState.upload.results; // Clear the preview results entirely if a new dandiset }; @@ -47,21 +47,17 @@ export class GuidedUploadPage extends Page { if (!result || !result.isConfirmed) return this.to(1); } - const results = await uploadToDandi.call(this, { + globalUploadInfo.results = await uploadToDandi.call(this, { ...globalUploadInfo.info, project: globalState.project.name, }); - globalUploadInfo.results = results; // Save the preview results - - this.unsavedUpdates = true; // Ensure that this saves automatically - this.to(1); }, }; render() { - const state = (this.localState = merge(this.info.globalState.upload ?? { info: {}, results: null }, {})); + const state = (this.localState = merge(this.info.globalState.upload ?? { info: {} }, {})); this.form = new JSONSchemaForm({ schema: dandiUploadSchema, diff --git a/src/renderer/src/stories/pages/guided-mode/results/GuidedResults.js b/src/renderer/src/stories/pages/guided-mode/results/GuidedResults.js index 43e5ad642..882041d34 100644 --- a/src/renderer/src/stories/pages/guided-mode/results/GuidedResults.js +++ b/src/renderer/src/stories/pages/guided-mode/results/GuidedResults.js @@ -9,14 +9,14 @@ export class GuidedResultsPage extends Page { } render() { - const { conversion } = this.info.globalState.conversion; + const { conversion } = this.info.globalState; if (!conversion) return html`

Your conversion failed. Please try again.

`; const { dandiset_id } = this.info.globalState.upload?.info ?? {}; - return DandiResults({ id: dandiset_id, files: conversion }); + return new DandiResults({ id: dandiset_id, files: conversion }); } } diff --git a/src/renderer/src/stories/pages/uploads/UploadsPage.js b/src/renderer/src/stories/pages/uploads/UploadsPage.js index 7d366467d..2e4691212 100644 --- a/src/renderer/src/stories/pages/uploads/UploadsPage.js +++ b/src/renderer/src/stories/pages/uploads/UploadsPage.js @@ -18,7 +18,7 @@ import { DandiResults } from "../../DandiResults.js"; export const isStaging = (id) => parseInt(id) >= 100000; -export async function uploadToDandi(info) { +export async function uploadToDandi(info, type = "project" in info ? "" : "folder") { const api_key = global.data.DANDI?.api_key; if (!api_key) { await Swal.fire({ @@ -31,8 +31,8 @@ export async function uploadToDandi(info) { return this.to("settings"); } - return await run( - "upload/folder", + const result = await run( + type ? `upload/${type}` : "upload", { ...info, staging: isStaging(info.dandiset_id), // Automatically detect staging IDs @@ -40,9 +40,20 @@ export async function uploadToDandi(info) { }, { title: "Uploading to DANDI" } ).catch((e) => { - this.notify(e.message, "error"); + notyf.open({ + type: "error", + message: e.message, + }); throw e; }); + + if (result) + notyf.open({ + type: "success", + message: `${info.project ?? info.nwb_folder_path} successfully uploaded to Dandiset ${info.dandiset_id}`, + }); + + return result; } export class UploadsPage extends Page { @@ -58,14 +69,7 @@ export class UploadsPage extends Page { label: defaultButtonMessage, onClick: async () => { await this.form.validate(); // Will throw an error in the callback - const results = await uploadToDandi.call(this, { ...globalState }); - - if (results) - notyf.open({ - type: "success", - message: `${globalState.nwb_folder_path} successfully uploaded to Dandiset ${globalState.dandiset_id}`, - }); - + await uploadToDandi.call(this, { ...global.data.uploads }); global.data.uploads = {}; global.save();