Skip to content

Commit

Permalink
feat: allow any value in multi-select dataview
Browse files Browse the repository at this point in the history
fixes #54
  • Loading branch information
danielo515 committed Jan 2, 2024
1 parent 1834bf5 commit fa9da3d
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 104 deletions.
27 changes: 21 additions & 6 deletions src/FormModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ import { FolderSuggest } from "./suggesters/suggestFolder";

export type SubmitFn = (formResult: FormResult) => void;

const notify = throttle((msg: string) => log_notice("⚠️ The form has errors ⚠️", msg, "notice-warning"), 2000);
const notify = throttle(
(msg: string) => log_notice("⚠️ The form has errors ⚠️", msg, "notice-warning"),
2000,
);
const notifyError = (title: string) =>
throttle((msg: string) => log_notice(`🚨 ${title} 🚨`, msg, "notice-error"), 2000);

Expand All @@ -34,7 +37,10 @@ export class FormModal extends Modal {
options?: FormOptions,
) {
super(app);
this.initialFormValues = formDataFromFormDefaults(modalDefinition.fields, options?.values ?? {});
this.initialFormValues = formDataFromFormDefaults(
modalDefinition.fields,
options?.values ?? {},
);
this.formEngine = makeFormEngine((result) => {
this.onSubmit(FormResult.make(result, "ok"));
this.close();
Expand All @@ -46,7 +52,8 @@ export class FormModal extends Modal {
const { contentEl } = this;
// This class is very important for scoped styles
contentEl.addClass("modal-form");
if (this.modalDefinition.customClassname) contentEl.addClass(this.modalDefinition.customClassname);
if (this.modalDefinition.customClassname)
contentEl.addClass(this.modalDefinition.customClassname);
contentEl.createEl("h1", { text: this.modalDefinition.title });
this.modalDefinition.fields.forEach((definition) => {
const fieldBase = new Setting(contentEl)
Expand Down Expand Up @@ -155,19 +162,24 @@ export class FormModal extends Modal {
});
case "multiselect": {
const source = fieldInput.source;
const allowUnknownValues =
source === "dataview" ? fieldInput.allowUnknownValues : false;
const options =
source == "fixed"
? fieldInput.multi_select_options
: source == "notes"
? pipe(
? 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);
: executeSandboxedDvQuery(
sandboxedDvQuery(fieldInput.query),
this.app,
);
fieldStore.value.set(initialValue ?? []);
this.svelteComponents.push(
new MultiSelect({
Expand All @@ -178,13 +190,16 @@ export class FormModal extends Modal {
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 #
const options = Object.keys(this.app.metadataCache.getTags()).map((tag) =>
tag.slice(1),
); // remove the #
fieldStore.value.set(initialValue ?? []);
this.svelteComponents.push(
new MultiSelect({
Expand Down
8 changes: 4 additions & 4 deletions src/core/InputDefinitionSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
BaseSchema,
enumType,
Output,
boolean,
} from "valibot";

/**
Expand Down Expand Up @@ -92,7 +93,9 @@ const MultiSelectQuerySchema = object({
type: literal("multiselect"),
source: literal("dataview"),
query: nonEmptyString("dataview query"),
allowUnknownValues: optional(boolean(), false),
});

export const MultiselectSchema = union([
MultiSelectNotesSchema,
MultiSelectFixedSchema,
Expand Down Expand Up @@ -120,10 +123,7 @@ export const InputTypeSchema = union([
DocumentBlock,
]);

export const InputTypeToParserMap: Record<
AllFieldTypes,
ParsingFn<BaseSchema>
> = {
export const InputTypeToParserMap: Record<AllFieldTypes, ParsingFn<BaseSchema>> = {
number: parseC(InputBasicSchema),
text: parseC(InputBasicSchema),
email: parseC(InputBasicSchema),
Expand Down
10 changes: 3 additions & 7 deletions src/core/formDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ export function isSelectFromNotes(input: unknown): input is selectFromNotes {
return is(SelectFromNotesSchema, input);
}

export function isInputNoteFromFolder(
input: unknown,
): input is inputNoteFromFolder {
export function isInputNoteFromFolder(input: unknown): input is inputNoteFromFolder {
return is(InputNoteFromFolderSchema, input);
}
export function isInputSelectFixed(input: unknown): input is inputSelectFixed {
Expand Down Expand Up @@ -103,6 +101,7 @@ export type EditableInput = {
options?: { value: string; label: string }[];
multi_select_options?: string[];
query?: string;
allowUnknownValues?: boolean;
};

export type EditableFormDefinition = FormDefinition & {
Expand Down Expand Up @@ -157,10 +156,7 @@ export function isValidFormDefinition(input: unknown): input is FormDefinition {
return true;
}

export function duplicateForm(
formName: string,
forms: (FormDefinition | MigrationError)[],
) {
export function duplicateForm(formName: string, forms: (FormDefinition | MigrationError)[]) {
return pipe(
forms,
A.findFirstMap((f) => {
Expand Down
6 changes: 3 additions & 3 deletions src/exampleModalDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,13 @@ export const exampleModalDefinition: FormDefinition = {
type: "multiselect",
source: "dataview",
query: 'dv.pages("#person").map(p => p.file.name)',
allowUnknownValues: true,
},
},
{
name: "best_fried",
label: "Best friend",
description: "Pick one",
description: "Select of type note from a folder",
input: {
type: "select",
source: "notes",
Expand All @@ -96,8 +97,7 @@ export const exampleModalDefinition: FormDefinition = {
{
name: "dataview_example",
label: "Dataview example",
description:
"Only people matching the dataview query will be shown",
description: "Only people matching the dataview query will be shown",
input: {
type: "dataview",
query: 'dv.pages("#person").filter(p => p.age < 30).map(p => p.file.name)',
Expand Down
1 change: 0 additions & 1 deletion src/suggesters/MultiSuggest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export class MultiSuggest extends AbstractInputSuggest<string> {
}

selectSuggestion(content: string, evt: MouseEvent | KeyboardEvent): void {
console.log("selectSuggestion", content);
this.onSelectCb(content);
this.inputEl.value = "";
this.close();
Expand Down
98 changes: 30 additions & 68 deletions src/views/FormBuilder.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@
import { pipe } from "fp-ts/lib/function";
import { A } from "@std";
import Tabs from "./components/Tabs.svelte";
import {
ParsedTemplate,
parsedTemplateToString,
} from "src/core/template/templateParser";
import { ParsedTemplate, parsedTemplateToString } from "src/core/template/templateParser";
import InputBuilderDocumentBlock from "./components/InputBuilderDocumentBlock.svelte";
export let definition: EditableFormDefinition = {
Expand Down Expand Up @@ -145,9 +142,7 @@
{fieldNames}
{saveTemplate}
templateString={definition.template
? parsedTemplateToString(
definition.template.parsedTemplate,
)
? parsedTemplateToString(definition.template.parsedTemplate)
: ""}
/>
</div>
Expand All @@ -156,31 +151,22 @@
<fieldset class="flex column gap2 header">
<label for="name">Form unique name</label>
<span class="hint"
>This name will identify this form uniquely, and will be
the value you need to provide when calling the method
openForm</span
>This name will identify this form uniquely, and will be the value you need
to provide when calling the method openForm</span
>
<input
type="text"
placeholder="Name"
id="name"
bind:value={definition.name}
/>
<input type="text" placeholder="Name" id="name" bind:value={definition.name} />
<label for="title">Form title</label>
<span class="hint"
>This is the title that will be shown in the modal when
the form is visible</span
>This is the title that will be shown in the modal when the form is visible</span
>
<input
type="text"
placeholder="Title"
id="title"
bind:value={definition.title}
/>
<label for="customClassname">Custom class Name</label><span
class="hint"
>In case you want to add a class name to the modal form
to customize it</span
<label for="customClassname">Custom class Name</label><span class="hint"
>In case you want to add a class name to the modal form to customize it</span
><input
type="text"
id="customClassname"
Expand All @@ -196,33 +182,25 @@
name: "",
label: "",
description: "",
input: { type: "text" },
input: { type: "text", allowUnknownValues: false },
},
];
// onChange();
activeFieldIndex = definition.fields.length - 1;
}}>Add more fields</button
>
<button
type="button"
on:click={handlePreview}
disabled={!isValid}>Preview</button
<button type="button" on:click={handlePreview} disabled={!isValid}
>Preview</button
>
<button
class="mod-cta"
type="submit"
disabled={!isValid}>Save and close</button
<button class="mod-cta" type="submit" disabled={!isValid}
>Save and close</button
>
<button
type="button"
class="mod-warning"
on:click={onCancel}>Cancel</button
<button type="button" class="mod-warning" on:click={onCancel}>Cancel</button
>
</div>
{#if errors.length > 0}
<h3 style="margin: 0;">
<span class="error">Form is invalid</span>, check
the following:
<span class="error">Form is invalid</span>, check the following:
</h3>
<ul style="margin: 0;">
{#each errors as error}
Expand Down Expand Up @@ -251,8 +229,7 @@
{@const delete_id = `delete_${index}`}
<div
class="flex column md-row gap2"
use:scrollWhenActive={index ===
activeFieldIndex}
use:scrollWhenActive={index === activeFieldIndex}
>
<div class="flex column gap1">
<label for={`name_${index}`}>Name</label>
Expand All @@ -274,23 +251,16 @@
</div>

{#if ["text", "email", "tel", "number", "note", "tag", "dataview", "multiselect"].includes(field.input.type)}
<FormRow
label="Make required"
id={`required_${index}`}
>
<Toggle
bind:checked={field.isRequired}
tabindex={index}
/>
<FormRow label="Make required" id={`required_${index}`}>
<Toggle bind:checked={field.isRequired} tabindex={index} />
</FormRow>
{/if}
<div class="flex column gap1">
<label
for={delete_id}
style:visibility={"hidden"}
style:overflow={"hidden"}
style:white-space={"nowrap"}
>delete {index}</label
style:white-space={"nowrap"}>delete {index}</label
>
</div>
</div>
Expand All @@ -307,14 +277,9 @@
</div>
<div class="flex column gap1">
<label for={`type_${index}`}>Type</label>
<select
bind:value={field.input.type}
id={`type_${index}`}
>
<select bind:value={field.input.type} id={`type_${index}`}>
{#each Object.entries(InputTypeReadable) as type}
<option value={type[0]}
>{type[1]}</option
>
<option value={type[0]}>{type[1]}</option>
{/each}
</select>
</div>
Expand All @@ -328,16 +293,17 @@
bind:folder={field.input.folder}
notifyChange={onChange}
is_multi={false}
allowUnknownValues={false}
{app}
/>
{:else if field.input.type === "multiselect"}
<InputBuilderSelect
{index}
bind:source={field.input.source}
bind:options={field.input
.multi_select_options}
bind:options={field.input.multi_select_options}
bind:folder={field.input.folder}
bind:query={field.input.query}
bind:allowUnknownValues={field.input.allowUnknownValues}
notifyChange={onChange}
is_multi={true}
{app}
Expand Down Expand Up @@ -375,7 +341,7 @@
bind:value={field.input.query}
{app}
/>
{:else if field.input.type === "document_block"}
{:else if field.input.type === "document_block"}
<InputBuilderDocumentBlock
{index}
bind:body={field.input.body}
Expand All @@ -391,25 +357,21 @@
/>
<button
type="button"
disabled={index ===
definition.fields.length - 1}
disabled={index === definition.fields.length - 1}
use:setIcon={"arrow-down"}
on:click={() => moveField(index, "down")}
/>
<button
type="button"
on:click={() => duplicateField(index)}
<button type="button" on:click={() => duplicateField(index)}
>Duplicate</button
>
<button
use:setIcon={"trash"}
type="button"
id={delete_id}
on:click={() => {
definition.fields =
definition.fields.filter(
(_, i) => i !== index,
);
definition.fields = definition.fields.filter(
(_, i) => i !== index,
);
}}
/>
</div>
Expand Down
Loading

0 comments on commit fa9da3d

Please sign in to comment.