Skip to content

Commit

Permalink
Merge pull request #350 from NeurodataWithoutBorders/file-or-folder-h…
Browse files Browse the repository at this point in the history
…andler

Handle Files and Folders Together
  • Loading branch information
CodyCBakerPhD authored Sep 15, 2023
2 parents e8c122b + 20c3026 commit fb6b9f0
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 25 deletions.
91 changes: 68 additions & 23 deletions src/renderer/src/stories/FileSystemSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ import { LitElement, css, html } from "lit";
import { remote } from "../electron/index";
const { dialog } = remote;

function getObjectTypeReferenceString(type, multiple, { nested, native } = {}) {
if (Array.isArray(type))
return `${multiple ? "" : "a "}${type
.map((type) => getObjectTypeReferenceString(type, multiple, { native, nested: true }))
.join(" / ")}`;

const isDir = type === "directory";
return multiple && (!isDir || (isDir && !native))
? type === "directory"
? "directories"
: "files"
: nested
? type
: `a ${type}`;
}

const componentCSS = css`
* {
box-sizing: border-box;
Expand All @@ -13,6 +29,16 @@ const componentCSS = css`
width: 100%;
}
:host([manytypes="true"]) > button {
cursor: default;
}
#button-div {
margin-top: 10px;
display: flex;
gap: 5px;
}
button {
background: WhiteSmoke;
border: 1px solid #c3c3c3;
Expand Down Expand Up @@ -130,9 +156,27 @@ export class FilesystemSelector extends LitElement {
this.dispatchEvent(event);
};

async selectFormat(type = this.type) {
if (dialog) {
const file = await this.#useElectronDialog(type);
const path = file.filePath ?? file.filePaths?.[0];
this.#handleFiles(path);
} else {
let handles = await (type === "directory"
? window.showDirectoryPicker()
: window.showOpenFilePicker({ multiple: this.multiple })
).catch((e) => this.#onCancel()); // Call using the same options

const result = Array.isArray(handles) ? handles.map((o) => o.name) : handles.name;
this.#handleFiles(result);
}
}

render() {
let resolved, isUpdated;

const isMultipleTypes = Array.isArray(this.type);
this.setAttribute("manytypes", isMultipleTypes);
const isArray = Array.isArray(this.value);
const len = isArray ? this.value.length : 0;

Expand All @@ -156,29 +200,12 @@ export class FilesystemSelector extends LitElement {
: this.value[0]
: this.value;

const objectTypeReference = this.multiple
? this.type === "directory"
? "directories"
: "files"
: `a ${this.type}`;
const objectTypeReference = getObjectTypeReferenceString(this.type, this.multiple);

return html`
<button
title=${isArray ? this.value.map((v, i) => `${i + 1}. ${v}`).join("\n") : this.value}
@click=${async () => {
if (dialog) {
const file = await this.#useElectronDialog(this.type);
const path = file.filePath ?? file.filePaths?.[0];
this.#handleFiles(path);
} else {
let handles = await (this.type === "directory"
? window.showDirectoryPicker
: window.showOpenFilePicker)({ multiple: this.multiple }).catch((e) => this.#onCancel()); // Call using the same options
const result = Array.isArray(handles) ? handles.map((o) => o.name) : handles.name;
this.#handleFiles(result);
}
}}
@click=${() => isMultipleTypes || this.selectFormat()}
@dragenter=${() => {
this.classList.add("active");
}}
Expand All @@ -201,17 +228,35 @@ export class FilesystemSelector extends LitElement {
${dialog
? ""
: html`<br /><small
>Cannot get full ${this.type} path${this.multiple ? "s" : ""} on web
distribution</small
>Cannot get full ${isMultipleTypes ? this.type.join(" / ") : this.type}
path${this.multiple ? "s" : ""} on web distribution</small
>`}
`
: html`<span>Drop ${objectTypeReference} here, or click to choose ${objectTypeReference}</span
>${this.multiple && this.type === "directory"
: html`<span
>Drop ${objectTypeReference}
here${isMultipleTypes
? ""
: `, or click to choose ${getObjectTypeReferenceString(this.type, this.multiple, {
native: true,
})}`}</span
>${this.multiple &&
(this.type === "directory" || (isMultipleTypes && this.type.includes("directory")))
? html`<br /><small
>Multiple directory support only available using drag-and-drop.</small
>`
: ""}`}
</button>
${isMultipleTypes
? html`<div id="button-div">
${this.type.map(
(type) =>
html`<nwb-button primary @click=${() => this.selectFormat(type)}
>Select
${getObjectTypeReferenceString(type, this.multiple, { native: true })}</nwb-button
>`
)}
</div>`
: ""}
`;
}
}
Expand Down
17 changes: 15 additions & 2 deletions src/renderer/src/stories/FileSystemSelector.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,30 @@ export default {

const Template = (args) => new FilesystemSelector(args);

const types = ["file", "directory"];

export const File = Template.bind({});
export const Folder = Template.bind({});
Folder.args = {
type: "directory",
type: types[1],
};

export const FileMultiple = Template.bind({});
FileMultiple.args = { multiple: true };

export const FolderMultiple = Template.bind({});
FolderMultiple.args = {
type: "directory",
type: types[1],
multiple: true,
};

export const Both = Template.bind({});
Both.args = {
type: types,
};

export const BothMultiple = Template.bind({});
BothMultiple.args = {
type: types,
multiple: true,
};
2 changes: 2 additions & 0 deletions src/renderer/src/stories/JSONSchemaInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { Modal } from "./Modal";
import { capitalize } from "./forms/utils";

const isFilesystemSelector = (format) => {
if (Array.isArray(format)) return format.map(isFilesystemSelector).every(Boolean) ? format : null;

const matched = name.match(/(.+_)?(.+)_paths?/);
if (!format && matched) format = matched[2] === "folder" ? "directory" : matched[2];
return ["file", "directory"].includes(format) ? format : null; // Handle file and directory formats
Expand Down

0 comments on commit fb6b9f0

Please sign in to comment.