Skip to content

Commit

Permalink
Merge pull request #329 from NeurodataWithoutBorders/fix-exit
Browse files Browse the repository at this point in the history
Fix Exit Button
  • Loading branch information
CodyCBakerPhD authored Aug 25, 2023
2 parents da8a697 + d391c98 commit c8daef6
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 108 deletions.
17 changes: 1 addition & 16 deletions src/renderer/src/dependencies/globals.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
import { app, isElectron, path, port, remote } from "../electron/index.js";
import { Notyf } from "notyf";
import checkChromatic from "chromatic/isChromatic";

import paths from "../../../../paths.config.json" assert { type: "json" };

import lottie from "lottie-web";
import { joinPath } from "../globals.js";

export const reloadPageToHome = () => {
if (isStorybook) return;
window.location = isElectron ? window.location.pathname : window.location.origin;
}; // Clear all query params

// Filesystem Management
export const homeDirectory = app?.getPath("home") ?? "";
export const appDirectory = homeDirectory ? joinPath(homeDirectory, paths.root) : "";
export const guidedProgressFilePath = homeDirectory ? joinPath(appDirectory, ...paths.subfolders.progress) : "";

export const isStorybook = window.location.href.includes("iframe.html");
export * from "./simple.js";

// ---------- Lottie Helper ----------
const isChromatic = checkChromatic();
Expand Down
15 changes: 15 additions & 0 deletions src/renderer/src/dependencies/simple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { app, isElectron } from "../electron/index.js";
import paths from "../../../../paths.config.json" assert { type: "json" };
import { joinPath } from "../globals.js";

export const reloadPageToHome = () => {
if (isStorybook) return;
window.location = isElectron ? window.location.pathname : window.location.origin;
}; // Clear all query params

// Filesystem Management
export const homeDirectory = app?.getPath("home") ?? "";
export const appDirectory = homeDirectory ? joinPath(homeDirectory, paths.root) : "";
export const guidedProgressFilePath = homeDirectory ? joinPath(appDirectory, ...paths.subfolders.progress) : "";

export const isStorybook = window.location.href.includes("iframe.html");
96 changes: 12 additions & 84 deletions src/renderer/src/progress.js → src/renderer/src/progress/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import Swal from "sweetalert2";

import { guidedProgressFilePath, reloadPageToHome, isStorybook, appDirectory } from "./dependencies/globals.js";
import { fs } from "./electron/index.js";
import { joinPath, runOnLoad } from "./globals.js";
import { merge } from "./stories/pages/utils.js";
import { guidedProgressFilePath, reloadPageToHome, isStorybook, appDirectory } from "../dependencies/simple.js";
import { fs } from "../electron/index.js";
import { joinPath, runOnLoad } from "../globals.js";
import { merge } from "../stories/pages/utils.js";
import { updateAppProgress, updateFile, updateURLParams } from "./update.js";

export * from "./update";

class GlobalAppConfig {
path = `${appDirectory}/config.json`;
Expand All @@ -28,66 +31,6 @@ export const hasEntry = (name) => {
return existingProgressNames.includes(name);
};

export const update = (newDatasetName, previousDatasetName) => {
//If updataing the dataset, update the old banner image path with a new one
if (previousDatasetName) {
if (previousDatasetName === newDatasetName) return "No changes made to dataset name";

if (hasEntry(newDatasetName))
throw new Error("An existing progress file already exists with that name. Please choose a different name.");

// update old progress file with new dataset name
const oldProgressFilePath = `${guidedProgressFilePath}/${previousDatasetName}.json`;
const newProgressFilePath = `${guidedProgressFilePath}/${newDatasetName}.json`;
if (fs) fs.renameSync(oldProgressFilePath, newProgressFilePath);
else {
localStorage.setItem(newProgressFilePath, localStorage.getItem(oldProgressFilePath));
localStorage.removeItem(oldProgressFilePath);
}

return "Dataset name updated";
} else throw new Error("No previous dataset name provided");
};

export const getCurrentProjectName = () => {
const params = new URLSearchParams(location.search);
return params.get("project");
};

function updateURLParams(paramsToUpdate) {
const params = new URLSearchParams(location.search);
for (let key in paramsToUpdate) {
const value = paramsToUpdate[key];
if (value == undefined) params.remove(key);
else params.set(key, value);
}

// Update browser history state
const value = `${location.pathname}?${params}`;
if (history.state) Object.assign(history.state, paramsToUpdate);
window.history.pushState(history.state, null, value);
}

export const updateAppProgress = (
pageId,
dataOrProjectName = {},
projectName = typeof dataOrProjectName === "string" ? dataOrProjectName : undefined
) => {
const transitionOffPipeline = pageId && pageId.split("/")[0] !== "conversion";

if (transitionOffPipeline) {
updateURLParams({ project: undefined });
return; // Only save last page if within the conversion workflow
}

if (projectName) updateURLParams({ project: projectName });

// Is a project name
if (dataOrProjectName === projectName) updateFile(dataOrProjectName, (data) => (data["page-before-exit"] = pageId));
// Is a data object
else dataOrProjectName["page-before-exit"] = pageId;
};

export const save = (page, overrides = {}) => {
const globalState = merge(overrides, page.info.globalState); // Merge the overrides into the actual global state

Expand All @@ -102,26 +45,6 @@ export const save = (page, overrides = {}) => {
});
};

//Destination: HOMEDIR/NWB_GUIDE/pipelines
export const updateFile = (projectName, callback) => {
let data = get(projectName);

if (callback) {
const result = callback(data);
if (result && typeof result === "object") data = result;
}

data["last-modified"] = new Date(); // Always update the last modified time

var guidedFilePath = joinPath(guidedProgressFilePath, projectName + ".json");

// Save the file through the available mechanisms
if (fs) {
if (!fs.existsSync(guidedProgressFilePath)) fs.mkdirSync(guidedProgressFilePath, { recursive: true }); //create progress folder if one does not exist
fs.writeFileSync(guidedFilePath, JSON.stringify(data, null, 2));
} else localStorage.setItem(guidedFilePath, JSON.stringify(data));
};

export const getEntries = () => {
if (fs && !fs.existsSync(guidedProgressFilePath)) fs.mkdirSync(guidedProgressFilePath, { recursive: true }); //Check if progress folder exists. If not, create it.
const progressFiles = fs ? fs.readdirSync(guidedProgressFilePath) : Object.keys(localStorage);
Expand All @@ -135,6 +58,11 @@ export const getAll = (progressFiles) => {
});
};

export const getCurrentProjectName = () => {
const params = new URLSearchParams(location.search);
return params.get("project");
};

export const get = (name) => {
if (!name) {
const params = new URLSearchParams(location.search);
Expand Down
79 changes: 79 additions & 0 deletions src/renderer/src/progress/update.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { guidedProgressFilePath } from "../dependencies/simple.js";
import { fs } from "../electron/index.js";
import { joinPath } from "../globals.js";
import { get } from "./index.js";

export const update = (newDatasetName, previousDatasetName) => {
//If updataing the dataset, update the old banner image path with a new one
if (previousDatasetName) {
if (previousDatasetName === newDatasetName) return "No changes made to dataset name";

if (hasEntry(newDatasetName))
throw new Error("An existing progress file already exists with that name. Please choose a different name.");

// update old progress file with new dataset name
const oldProgressFilePath = `${guidedProgressFilePath}/${previousDatasetName}.json`;
const newProgressFilePath = `${guidedProgressFilePath}/${newDatasetName}.json`;
if (fs) fs.renameSync(oldProgressFilePath, newProgressFilePath);
else {
localStorage.setItem(newProgressFilePath, localStorage.getItem(oldProgressFilePath));
localStorage.removeItem(oldProgressFilePath);
}

return "Dataset name updated";
} else throw new Error("No previous dataset name provided");
};

export function updateURLParams(paramsToUpdate) {
const params = new URLSearchParams(location.search);
for (let key in paramsToUpdate) {
const value = paramsToUpdate[key];
if (value == undefined) params.delete(key);
else params.set(key, value);
}

// Update browser history state
const value = `${location.pathname}?${params}`;
if (history.state) Object.assign(history.state, paramsToUpdate);
window.history.pushState(history.state, null, value);
}

export const updateAppProgress = (
pageId,
dataOrProjectName = {},
projectName = typeof dataOrProjectName === "string" ? dataOrProjectName : undefined
) => {
const transitionOffPipeline = pageId && pageId.split("/")[0] !== "conversion";

if (transitionOffPipeline) {
updateURLParams({ project: undefined });
return; // Only save last page if within the conversion workflow
}

if (projectName) updateURLParams({ project: projectName });

// Is a project name
if (dataOrProjectName === projectName) updateFile(dataOrProjectName, (data) => (data["page-before-exit"] = pageId));
// Is a data object
else dataOrProjectName["page-before-exit"] = pageId;
};

//Destination: HOMEDIR/NWB_GUIDE/pipelines
export const updateFile = (projectName, callback) => {
let data = get(projectName);

if (callback) {
const result = callback(data);
if (result && typeof result === "object") data = result;
}

data["last-modified"] = new Date(); // Always update the last modified time

var guidedFilePath = joinPath(guidedProgressFilePath, projectName + ".json");

// Save the file through the available mechanisms
if (fs) {
if (!fs.existsSync(guidedProgressFilePath)) fs.mkdirSync(guidedProgressFilePath, { recursive: true }); //create progress folder if one does not exist
fs.writeFileSync(guidedFilePath, JSON.stringify(data, null, 2));
} else localStorage.setItem(guidedFilePath, JSON.stringify(data));
};
2 changes: 1 addition & 1 deletion src/renderer/src/stories/Dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import "../../../../node_modules/@sweetalert2/theme-bulma/bulma.css";
import "../../assets/css/guided.css";
import isElectron from "../electron/check.js";
import { isStorybook, reloadPageToHome } from "../dependencies/globals.js";
import { getCurrentProjectName, updateAppProgress } from "../progress.js";
import { getCurrentProjectName, updateAppProgress } from "../progress/index.js";

// import "https://jsuites.net/v4/jsuites.js"
// import "https://bossanova.uk/jspreadsheet/v4/jexcel.js"
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/stories/pages/Page.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LitElement, html } from "lit";
import { openProgressSwal, runConversion } from "./guided-mode/options/utils.js";
import { get, save } from "../../progress.js";
import { get, save } from "../../progress/index.js";
import { dismissNotification, notify } from "../../dependencies/globals.js";
import { merge, randomizeElements, mapSessions } from "./utils.js";

Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/stories/pages/guided-mode/GuidedHome.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Page } from "../Page.js";
import { ProgressCard } from "./ProgressCard.js";

import { startLottie } from "../../../dependencies/globals.js";
import * as progress from "../../../progress.js";
import * as progress from "../../../progress/index.js";
import { newDataset } from "../../../../assets/lotties/index.js";

export class GuidedHomePage extends Page {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/stories/pages/guided-mode/ProgressCard.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { html, LitElement } from "lit";
import * as progress from "../../../progress.js";
import * as progress from "../../../progress/index.js";

export class ProgressCard extends LitElement {
static get properties() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { html } from "lit";
import { hasEntry, update } from "../../../../progress.js";
import { hasEntry, update } from "../../../../progress/index.js";
import { JSONSchemaForm } from "../../../JSONSchemaForm.js";
import { Page } from "../../Page.js";
import { validateOnChange } from "../../../../validation/index.js";
Expand Down
3 changes: 1 addition & 2 deletions src/renderer/src/stories/pages/tutorial/Tutorial.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import { unsafeSVG } from "lit/directives/unsafe-svg.js";
import { JSONSchemaForm } from "../../JSONSchemaForm.js";
import { Page } from "../Page.js";
import tutorialSchema from "../../../../../../schemas/json/tutorial.schema.json" assert { type: "json" };
import guideGlobalMetadata from "../../../../../../guideGlobalMetadata.json" assert { type: "json" };

import { run } from "../guided-mode/options/utils.js";
import "../../Button.js";
import { InfoBox } from "../../InfoBox.js";
import { hasEntry, get, save, remove, resume, global } from "../../../progress.js";
import { hasEntry, get, save, remove, resume, global } from "../../../progress/index.js";

import { electron } from "../../../electron/index.js";

Expand Down
94 changes: 94 additions & 0 deletions src/renderer/src/stories/pages/uploads/UploadsPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { html } from "lit";
import { JSONSchemaForm } from "../../JSONSchemaForm.js";
import { Page } from "../Page.js";
import { onThrow } from "../../../errors";
import dandiUploadSchema from "../../../../../../schemas/json/dandi/upload.json";
import dandiStandaloneSchema from "../../../../../../schemas/json/dandi/standalone.json";
const dandiSchema = merge(dandiStandaloneSchema, dandiUploadSchema, { arrays: true });

import { Button } from "../../Button.js";
import { global } from "../../../progress/index.js";
import { merge } from "../utils.js";

import { run } from "../guided-mode/options/utils.js";
import { notyf } from "../../../dependencies/globals.js";
import Swal from "sweetalert2";

export async function uploadToDandi(info) {
if (!("api_key" in (global.data.DANDI ?? {}))) {
await Swal.fire({
title: "Your DANDI API key is not configured.",
html: "Edit your settings to include this value.",
icon: "warning",
confirmButtonText: "Go to Settings",
});

return this.to("settings");
}

info.staging = parseInt(info.dandiset_id) >= 100000; // Automatically detect staging IDs
info.api_key = global.data.DANDI.api_key;

return await run("upload", info, { title: "Uploading to DANDI" }).catch((e) => {
this.notify(e.message, "error");
throw e;
});
}

export class UploadsPage extends Page {
constructor(...args) {
super(...args);
}

render() {
const globalState = (global.data.uploads = global.data.uploads ?? {});
const defaultButtonMessage = "Upload Files";

const button = new Button({
label: defaultButtonMessage,
onClick: async () => {
await this.form.validate(); // Will throw an error in the callback
const results = await uploadToDandi.call(this, { ...global.data.uploads });
if (results)
notyf.open({
type: "success",
message: `${info.nwb_folder_path} successfully uploaded to Dandiset ${info.dandiset_id}`,
});
},
});

const folderPathKey = "nwb_folder_path";
// NOTE: API Keys and Dandiset IDs persist across selected project
this.form = new JSONSchemaForm({
results: globalState,
schema: dandiSchema,
onUpdate: ([id]) => {
if (id === folderPathKey) {
for (let key in dandiSchema.properties) {
const input = this.form.getInput([key]);
if (key !== folderPathKey) input.updateData(""); // Clear the results of the form
}
}

global.save();
},
onThrow,
});

return html`
<div style="display: flex; align-items: end; justify-content: space-between; margin-bottom: 10px;">
<h1 style="margin: 0;">DANDI Uploads</h1>
</div>
<p>This page allows you to upload folders with NWB files to the DANDI Archive.</p>
<hr />
<div>
${this.form}
<hr />
${button}
</div>
`;
}
}

customElements.get("nwbguide-uploads-page") || customElements.define("nwbguide-uploads-page", UploadsPage);
Loading

0 comments on commit c8daef6

Please sign in to comment.