From 6c3e1e5b068573826e564d8648f6cf2714f61b1a Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Sun, 14 Jan 2024 12:30:19 +0100 Subject: [PATCH 1/2] feat: multi select notes uses the new notes input (better UI and search) --- src/FormModal.ts | 38 ++---- src/core/InputDefinitionSchema.ts | 1 + .../{MultiSuggest.ts => StringSuggest.ts} | 2 +- src/views/components/MultiSelect.svelte | 33 +---- src/views/components/MultiSelectModel.ts | 114 ++++++++++++++++++ 5 files changed, 131 insertions(+), 57 deletions(-) rename src/suggesters/{MultiSuggest.ts => StringSuggest.ts} (94%) create mode 100644 src/views/components/MultiSelectModel.ts diff --git a/src/FormModal.ts b/src/FormModal.ts index d19bb193..e9e9c0b9 100644 --- a/src/FormModal.ts +++ b/src/FormModal.ts @@ -16,6 +16,7 @@ import { FieldValue, FormEngine, makeFormEngine } from "./store/formStore"; import { Writable } from "svelte/store"; import { FolderSuggest } from "./suggesters/suggestFolder"; import { allowsUnknownValues } from "./core/InputDefinitionSchema"; +import { MultiSelectModel, MultiSelectTags } from "./views/components/MultiSelectModel"; export type SubmitFn = (formResult: FormResult) => void; @@ -164,55 +165,38 @@ export class FormModal extends Modal { slider.onChange(fieldStore.value.set); }); case "multiselect": { - const source = fieldInput.source; - const allowUnknownValues = allowsUnknownValues(fieldInput); - const options = - source == "fixed" - ? fieldInput.multi_select_options - : source == "notes" - ? pipe( - get_tfiles_from_folder(fieldInput.folder, this.app), - E.map(A.map((file) => file.basename)), - E.getOrElse((err) => { - log_error(err); - return [] as string[]; - }), - ) - : executeSandboxedDvQuery( - sandboxedDvQuery(fieldInput.query), - this.app, - ); fieldStore.value.set(initialValue ?? []); this.svelteComponents.push( new MultiSelect({ target: fieldBase.controlEl, props: { + model: MultiSelectModel( + fieldInput, + this.app, + fieldStore.value as Writable, + ), values: fieldStore.value as Writable, - availableOptions: options, errors: fieldStore.errors, setting: fieldBase, - app: this.app, - allowUnknownValues, }, }), ); return; } case "tag": { - const options = Object.keys(this.app.metadataCache.getTags()).map((tag) => - tag.slice(1), - ); // remove the # fieldStore.value.set(initialValue ?? []); this.svelteComponents.push( new MultiSelect({ target: fieldBase.controlEl, props: { values: fieldStore.value as Writable, - availableOptions: options, setting: fieldBase, errors: fieldStore.errors, - app: this.app, - allowUnknownValues: true, + model: MultiSelectTags( + fieldInput, + this.app, + fieldStore.value as Writable, + ), }, }), ); diff --git a/src/core/InputDefinitionSchema.ts b/src/core/InputDefinitionSchema.ts index 0b5cf4ca..e9714464 100644 --- a/src/core/InputDefinitionSchema.ts +++ b/src/core/InputDefinitionSchema.ts @@ -164,4 +164,5 @@ export type inputDataviewSource = Output; export type inputSelectFixed = Output; export type basicInput = Output; export type multiselect = Output; +export type inputTag = Output; export type inputType = Output; diff --git a/src/suggesters/MultiSuggest.ts b/src/suggesters/StringSuggest.ts similarity index 94% rename from src/suggesters/MultiSuggest.ts rename to src/suggesters/StringSuggest.ts index 982c89bd..7528d417 100644 --- a/src/suggesters/MultiSuggest.ts +++ b/src/suggesters/StringSuggest.ts @@ -1,6 +1,6 @@ import { AbstractInputSuggest, App } from "obsidian"; -export class MultiSuggest extends AbstractInputSuggest { +export class StringSuggest extends AbstractInputSuggest { content: Set; constructor( diff --git a/src/views/components/MultiSelect.svelte b/src/views/components/MultiSelect.svelte index e407caa7..a5a12ac5 100644 --- a/src/views/components/MultiSelect.svelte +++ b/src/views/components/MultiSelect.svelte @@ -1,46 +1,21 @@
diff --git a/src/views/components/MultiSelectModel.ts b/src/views/components/MultiSelectModel.ts new file mode 100644 index 00000000..52cce0cb --- /dev/null +++ b/src/views/components/MultiSelectModel.ts @@ -0,0 +1,114 @@ +import { A, pipe } from "@std"; +import { absurd } from "fp-ts/function"; +import { App } from "obsidian"; +import { multiselect, inputTag } from "src/core/InputDefinitionSchema"; +import { executeSandboxedDvQuery, sandboxedDvQuery } from "src/suggesters/SafeDataviewQuery"; +import { StringSuggest } from "src/suggesters/StringSuggest"; +import { FileSuggest } from "src/suggesters/suggestFile"; +import { Writable } from "svelte/store"; + +export interface MultiSelectModel { + createInput(element: HTMLInputElement): void; + removeValue(value: string): void; +} + +export function MultiSelectModel( + fieldInput: multiselect, + app: App, + values: Writable, +): MultiSelectModel { + const source = fieldInput.source; + const removeValue = (value: string) => + values.update((xs) => + pipe( + xs, + A.filter((x) => x !== value), + ), + ); + switch (source) { + case "dataview": + case "fixed": { + const remainingOptions = new Set( + source === "fixed" + ? fieldInput.multi_select_options + : executeSandboxedDvQuery(sandboxedDvQuery(fieldInput.query), app), + ); + return { + createInput(element: HTMLInputElement) { + new StringSuggest( + element, + remainingOptions, + (selected) => { + remainingOptions.delete(selected); + values.update((x) => [...x, selected]); + }, + app, + fieldInput.allowUnknownValues, + ); + }, + removeValue(value: string) { + remainingOptions.add(value); + removeValue(value); + }, + }; + } + case "notes": { + return { + createInput(element: HTMLInputElement) { + new FileSuggest( + app, + element, + { + renderSuggestion(file) { + return file.basename; + }, + selectSuggestion(file) { + values.update((x) => [...x, file.basename]); + return ""; + }, + }, + fieldInput.folder, + ); + }, + removeValue, + }; + } + default: + return absurd(source); + } +} + +export function MultiSelectTags( + fieldInput: inputTag, + app: App, + values: Writable, +): MultiSelectModel { + const remainingOptions = new Set( + Object.keys(app.metadataCache.getTags()).map( + (tag) => tag.slice(1) /** remove the leading # */, + ), + ); + return { + createInput(element: HTMLInputElement) { + new StringSuggest( + element, + remainingOptions, + (selected) => { + remainingOptions.delete(selected); + values.update((x) => [...x, selected]); + }, + app, + false, + ); + }, + removeValue(value: string) { + remainingOptions.add(value); + values.update((x) => + pipe( + x, + A.filter((x) => x !== value), + ), + ); + }, + }; +} From 7e43adba27b1bded61f042911e17ad0a8821b4ef Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Sun, 14 Jan 2024 12:31:53 +0100 Subject: [PATCH 2/2] chore: fix imports --- src/FormModal.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/FormModal.ts b/src/FormModal.ts index e9e9c0b9..1f37f224 100644 --- a/src/FormModal.ts +++ b/src/FormModal.ts @@ -9,13 +9,11 @@ import type { FormDefinition, FormOptions } from "./core/formDefinition"; import { FileSuggest } from "./suggesters/suggestFile"; import { DataviewSuggest } from "./suggesters/suggestFromDataview"; import { SvelteComponent } from "svelte"; -import { executeSandboxedDvQuery, sandboxedDvQuery } from "./suggesters/SafeDataviewQuery"; -import { A, E, parseFunctionBody, pipe, throttle } from "@std"; +import { E, parseFunctionBody, pipe, throttle } from "@std"; import { log_error, log_notice } from "./utils/Log"; import { FieldValue, FormEngine, makeFormEngine } from "./store/formStore"; import { Writable } from "svelte/store"; import { FolderSuggest } from "./suggesters/suggestFolder"; -import { allowsUnknownValues } from "./core/InputDefinitionSchema"; import { MultiSelectModel, MultiSelectTags } from "./views/components/MultiSelectModel"; export type SubmitFn = (formResult: FormResult) => void;