From a10f9ec609a8f5a1956e917035133e7a55574c57 Mon Sep 17 00:00:00 2001 From: Karn Date: Sat, 30 Aug 2025 17:38:52 +0100 Subject: [PATCH 1/3] Allow batch / folder import by id as well as title --- src/main.ts | 112 +++++++++++++++---------- src/modals/MediaDbFolderImportModal.ts | 26 ++++-- 2 files changed, 90 insertions(+), 48 deletions(-) diff --git a/src/main.ts b/src/main.ts index c9853af..8a92528 100644 --- a/src/main.ts +++ b/src/main.ts @@ -621,9 +621,14 @@ export default class MediaDbPlugin extends Plugin { const erroredFiles: { filePath: string; error: string }[] = []; let canceled: boolean = false; - const { selectedAPI, titleFieldName, appendContent } = await new Promise<{ selectedAPI: string; titleFieldName: string; appendContent: boolean }>(resolve => { - new MediaDbFolderImportModal(this.app, this, (selectedAPI: string, titleFieldName: string, appendContent: boolean) => { - resolve({ selectedAPI, titleFieldName, appendContent }); + const { selectedAPI, titleFieldName, idFieldName, appendContent } = await new Promise<{ + selectedAPI: string; + titleFieldName: string; + idFieldName: string; + appendContent: boolean; + }>(resolve => { + new MediaDbFolderImportModal(this.app, this, (selectedAPI: string, titleFieldName: string, idFieldName: string, appendContent: boolean) => { + resolve({ selectedAPI, titleFieldName, idFieldName, appendContent }); }).open(); }); @@ -637,54 +642,75 @@ export default class MediaDbPlugin extends Plugin { const metadata = this.getMetadataFromFileCache(file); - const title = metadata[titleFieldName]; - if (!title || typeof title !== 'string') { - erroredFiles.push({ filePath: file.path, error: `metadata field '${titleFieldName}' not found, empty, or not a string` }); - continue; - } + // Querying by ID takes priority, doesn't require user to select from multiple matches + const id = metadata[idFieldName]; + if (id && typeof id === 'string') { + try { + const model = await this.apiManager.queryDetailedInfoById(id, selectedAPI); + if (model) { + await this.createMediaDbNotes([model], appendContent ? file : undefined); + } else { + erroredFiles.push({ filePath: file.path, error: `Failed to query API with id: ${id}` }); + } + } catch (e) { + erroredFiles.push({ filePath: file.path, error: `${e}` }); + continue; + } + } else { + // Query API with title instead, requires user to select best match + const title = metadata[titleFieldName]; + if (!title || typeof title !== 'string') { + erroredFiles.push({ filePath: file.path, error: `metadata field '${titleFieldName}' not found, empty, or not a string` }); + continue; + } - let results: MediaTypeModel[] = []; - try { - results = await this.apiManager.query(title, [selectedAPI]); - } catch (e) { - erroredFiles.push({ filePath: file.path, error: `${e}` }); - continue; - } - if (!results || results.length === 0) { - erroredFiles.push({ filePath: file.path, error: `no search results` }); - continue; - } + let results: MediaTypeModel[] = []; + try { + results = await this.apiManager.query(title, [selectedAPI]); + } catch (e) { + erroredFiles.push({ filePath: file.path, error: `${e}` }); + continue; + } + if (!results || results.length === 0) { + erroredFiles.push({ filePath: file.path, error: `no search results` }); + continue; + } - const { selectModalResult, selectModal } = await this.modalHelper.createSelectModal({ elements: results, skipButton: true, modalTitle: `Results for '${title}'` }); + const { selectModalResult, selectModal } = await this.modalHelper.createSelectModal({ + elements: results, + skipButton: true, + modalTitle: `Results for '${title}'`, + }); - if (selectModalResult.code === ModalResultCode.ERROR) { - erroredFiles.push({ filePath: file.path, error: selectModalResult.error.message }); - selectModal.close(); - continue; - } + if (selectModalResult.code === ModalResultCode.ERROR) { + erroredFiles.push({ filePath: file.path, error: selectModalResult.error.message }); + selectModal.close(); + continue; + } - if (selectModalResult.code === ModalResultCode.CLOSE) { - erroredFiles.push({ filePath: file.path, error: 'user canceled' }); - selectModal.close(); - canceled = true; - continue; - } + if (selectModalResult.code === ModalResultCode.CLOSE) { + erroredFiles.push({ filePath: file.path, error: 'user canceled' }); + selectModal.close(); + canceled = true; + continue; + } - if (selectModalResult.code === ModalResultCode.SKIP) { - erroredFiles.push({ filePath: file.path, error: 'user skipped' }); - selectModal.close(); - continue; - } + if (selectModalResult.code === ModalResultCode.SKIP) { + erroredFiles.push({ filePath: file.path, error: 'user skipped' }); + selectModal.close(); + continue; + } - if (selectModalResult.data.selected.length === 0) { - erroredFiles.push({ filePath: file.path, error: `no search results selected` }); - continue; - } + if (selectModalResult.data.selected.length === 0) { + erroredFiles.push({ filePath: file.path, error: `no search results selected` }); + continue; + } - const detailedResults = await this.queryDetails(selectModalResult.data.selected); - await this.createMediaDbNotes(detailedResults, appendContent ? file : undefined); + const detailedResults = await this.queryDetails(selectModalResult.data.selected); + await this.createMediaDbNotes(detailedResults, appendContent ? file : undefined); - selectModal.close(); + selectModal.close(); + } } } diff --git a/src/modals/MediaDbFolderImportModal.ts b/src/modals/MediaDbFolderImportModal.ts index 995df1a..478fa25 100644 --- a/src/modals/MediaDbFolderImportModal.ts +++ b/src/modals/MediaDbFolderImportModal.ts @@ -4,23 +4,25 @@ import type MediaDbPlugin from '../main'; export class MediaDbFolderImportModal extends Modal { plugin: MediaDbPlugin; - onSubmit: (selectedAPI: string, titleFieldName: string, appendContent: boolean) => void; + onSubmit: (selectedAPI: string, titleFieldName: string, idFieldName: string, appendContent: boolean) => void; selectedApi: string; searchBtn?: ButtonComponent; titleFieldName: string; + idFieldName: string; appendContent: boolean; - constructor(app: App, plugin: MediaDbPlugin, onSubmit: (selectedAPI: string, titleFieldName: string, appendContent: boolean) => void) { + constructor(app: App, plugin: MediaDbPlugin, onSubmit: (selectedAPI: string, titleFieldName: string, idFieldName: string, appendContent: boolean) => void) { super(app); this.plugin = plugin; this.onSubmit = onSubmit; this.selectedApi = plugin.apiManager.apis[0].apiName; this.titleFieldName = ''; + this.idFieldName = ''; this.appendContent = false; } submit(): void { - this.onSubmit(this.selectedApi, this.titleFieldName, this.appendContent); + this.onSubmit(this.selectedApi, this.titleFieldName, this.idFieldName, this.appendContent); this.close(); } @@ -43,7 +45,7 @@ export class MediaDbFolderImportModal extends Modal { apiSelectorWrapper.appendChild(apiSelectorComponent.selectEl); contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); - contentEl.createEl('h3', { text: 'Append note content to Media DB entry.' }); + contentEl.createEl('h3', { text: 'Append note content to Media DB entry?' }); const appendContentToggleElementWrapper = contentEl.createEl('div', { cls: 'media-db-plugin-list-wrapper' }); const appendContentToggleTextWrapper = appendContentToggleElementWrapper.createEl('div', { cls: 'media-db-plugin-list-text-wrapper' }); @@ -60,7 +62,7 @@ export class MediaDbFolderImportModal extends Modal { appendContentToggleComponentWrapper.appendChild(appendContentToggle.toggleEl); contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); - contentEl.createEl('h3', { text: 'The name of the metadata field that should be used as the title to query.' }); + contentEl.createEl('h3', { text: "Name of 'title' metadata field to use in API query." }); const placeholder = 'title'; const titleFieldNameComponent = new TextComponent(contentEl); @@ -74,6 +76,20 @@ export class MediaDbFolderImportModal extends Modal { }); contentEl.appendChild(titleFieldNameComponent.inputEl); + contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); + contentEl.createEl('h3', { text: "Name of 'id' metadata field to use in API query (if present, will be used instead of title)." }); + + const idFieldNameComponent = new TextComponent(contentEl); + idFieldNameComponent.inputEl.style.width = '100%'; + idFieldNameComponent.setPlaceholder('id'); + idFieldNameComponent.onChange(value => (this.idFieldName = value)); + idFieldNameComponent.inputEl.addEventListener('keydown', ke => { + if (ke.key === 'Enter') { + this.submit(); + } + }); + contentEl.appendChild(idFieldNameComponent.inputEl); + contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); new Setting(contentEl) From 4798f1144b39965a87bc53e4bc17be31d5d09bc1 Mon Sep 17 00:00:00 2001 From: Karn Date: Wed, 3 Sep 2025 18:48:53 +0100 Subject: [PATCH 2/3] Refactor bulk folder import logic to better switch between title and id lookup methods --- src/main.ts | 35 +++++------ src/modals/MediaDbFolderImportModal.ts | 84 +++++++++++++++----------- 2 files changed, 63 insertions(+), 56 deletions(-) diff --git a/src/main.ts b/src/main.ts index 8a92528..2019209 100644 --- a/src/main.ts +++ b/src/main.ts @@ -621,14 +621,14 @@ export default class MediaDbPlugin extends Plugin { const erroredFiles: { filePath: string; error: string }[] = []; let canceled: boolean = false; - const { selectedAPI, titleFieldName, idFieldName, appendContent } = await new Promise<{ + const { selectedAPI, lookupMethod, fieldName, appendContent } = await new Promise<{ selectedAPI: string; - titleFieldName: string; - idFieldName: string; + lookupMethod: string; + fieldName: string; appendContent: boolean; }>(resolve => { - new MediaDbFolderImportModal(this.app, this, (selectedAPI: string, titleFieldName: string, idFieldName: string, appendContent: boolean) => { - resolve({ selectedAPI, titleFieldName, idFieldName, appendContent }); + new MediaDbFolderImportModal(this.app, this, (selectedAPI: string, lookupMethod: string, fieldName: string, appendContent: boolean) => { + resolve({ selectedAPI, lookupMethod, fieldName, appendContent }); }).open(); }); @@ -641,32 +641,27 @@ export default class MediaDbPlugin extends Plugin { } const metadata = this.getMetadataFromFileCache(file); + const lookupValue = metadata[fieldName]; - // Querying by ID takes priority, doesn't require user to select from multiple matches - const id = metadata[idFieldName]; - if (id && typeof id === 'string') { + if (!lookupValue || typeof lookupValue !== 'string') { + erroredFiles.push({ filePath: file.path, error: `metadata field '${fieldName}' not found, empty, or not a string` }); + continue; + } else if (lookupMethod == 'id') { try { - const model = await this.apiManager.queryDetailedInfoById(id, selectedAPI); + const model = await this.apiManager.queryDetailedInfoById(lookupValue, selectedAPI); if (model) { await this.createMediaDbNotes([model], appendContent ? file : undefined); } else { - erroredFiles.push({ filePath: file.path, error: `Failed to query API with id: ${id}` }); + erroredFiles.push({ filePath: file.path, error: `Failed to query API with id: ${lookupValue}` }); } } catch (e) { erroredFiles.push({ filePath: file.path, error: `${e}` }); continue; } - } else { - // Query API with title instead, requires user to select best match - const title = metadata[titleFieldName]; - if (!title || typeof title !== 'string') { - erroredFiles.push({ filePath: file.path, error: `metadata field '${titleFieldName}' not found, empty, or not a string` }); - continue; - } - + } else if (lookupMethod == 'title') { let results: MediaTypeModel[] = []; try { - results = await this.apiManager.query(title, [selectedAPI]); + results = await this.apiManager.query(lookupValue, [selectedAPI]); } catch (e) { erroredFiles.push({ filePath: file.path, error: `${e}` }); continue; @@ -679,7 +674,7 @@ export default class MediaDbPlugin extends Plugin { const { selectModalResult, selectModal } = await this.modalHelper.createSelectModal({ elements: results, skipButton: true, - modalTitle: `Results for '${title}'`, + modalTitle: `Results for '${lookupValue}'`, }); if (selectModalResult.code === ModalResultCode.ERROR) { diff --git a/src/modals/MediaDbFolderImportModal.ts b/src/modals/MediaDbFolderImportModal.ts index 478fa25..729f3fd 100644 --- a/src/modals/MediaDbFolderImportModal.ts +++ b/src/modals/MediaDbFolderImportModal.ts @@ -1,28 +1,29 @@ import type { App, ButtonComponent } from 'obsidian'; import { DropdownComponent, Modal, Setting, TextComponent, ToggleComponent } from 'obsidian'; import type MediaDbPlugin from '../main'; +import type { APIModel } from 'src/api/APIModel'; export class MediaDbFolderImportModal extends Modal { plugin: MediaDbPlugin; - onSubmit: (selectedAPI: string, titleFieldName: string, idFieldName: string, appendContent: boolean) => void; + onSubmit: (selectedAPI: string, lookupMethod: string, fieldName: string, appendContent: boolean) => void; selectedApi: string; searchBtn?: ButtonComponent; - titleFieldName: string; - idFieldName: string; + lookupMethod: string; + fieldName: string; appendContent: boolean; - constructor(app: App, plugin: MediaDbPlugin, onSubmit: (selectedAPI: string, titleFieldName: string, idFieldName: string, appendContent: boolean) => void) { + constructor(app: App, plugin: MediaDbPlugin, onSubmit: (selectedAPI: string, lookupMethod: string, fieldName: string, appendContent: boolean) => void) { super(app); this.plugin = plugin; this.onSubmit = onSubmit; this.selectedApi = plugin.apiManager.apis[0].apiName; - this.titleFieldName = ''; - this.idFieldName = ''; + this.lookupMethod = ''; + this.fieldName = ''; this.appendContent = false; } submit(): void { - this.onSubmit(this.selectedApi, this.titleFieldName, this.idFieldName, this.appendContent); + this.onSubmit(this.selectedApi, this.lookupMethod, this.fieldName, this.appendContent); this.close(); } @@ -31,18 +32,14 @@ export class MediaDbFolderImportModal extends Modal { contentEl.createEl('h2', { text: 'Import folder as Media DB entries' }); - const apiSelectorWrapper = contentEl.createEl('div', { cls: 'media-db-plugin-list-wrapper' }); - const apiSelectorTextWrapper = apiSelectorWrapper.createEl('div', { cls: 'media-db-plugin-list-text-wrapper' }); - apiSelectorTextWrapper.createEl('span', { text: 'API to search', cls: 'media-db-plugin-list-text' }); - - const apiSelectorComponent = new DropdownComponent(apiSelectorWrapper); - apiSelectorComponent.onChange((value: string) => { + const onAPIChange = (value: string) => { this.selectedApi = value; + }; + const apiOptions = this.plugin.apiManager.apis.map((api: APIModel) => { + return { value: api.apiName, display: api.apiName }; }); - for (const api of this.plugin.apiManager.apis) { - apiSelectorComponent.addOption(api.apiName, api.apiName); - } - apiSelectorWrapper.appendChild(apiSelectorComponent.selectEl); + + this.createDropdownEl(contentEl, 'API to search', onAPIChange, apiOptions); contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); contentEl.createEl('h3', { text: 'Append note content to Media DB entry?' }); @@ -62,33 +59,35 @@ export class MediaDbFolderImportModal extends Modal { appendContentToggleComponentWrapper.appendChild(appendContentToggle.toggleEl); contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); - contentEl.createEl('h3', { text: "Name of 'title' metadata field to use in API query." }); - - const placeholder = 'title'; - const titleFieldNameComponent = new TextComponent(contentEl); - titleFieldNameComponent.inputEl.style.width = '100%'; - titleFieldNameComponent.setPlaceholder(placeholder); - titleFieldNameComponent.onChange(value => (this.titleFieldName = value)); - titleFieldNameComponent.inputEl.addEventListener('keydown', ke => { - if (ke.key === 'Enter') { - this.submit(); - } + contentEl.createEl('h3', { text: 'Media lookup method' }); + contentEl.createEl('p', { + text: 'Choose whether to search the API by title (can return multiple results) or lookup directly using an ID (returns at most one result), and specify the name of the frontmatter property which contains the title or ID of the media.', }); - contentEl.appendChild(titleFieldNameComponent.inputEl); + + const onlookupMethodChange = (value: string) => { + this.lookupMethod = value; + }; + const lookupMethodOptions = [ + { value: 'title', display: 'Title' }, + { value: 'id', display: 'ID' }, + ]; + this.createDropdownEl(contentEl, 'Lookup media by', onlookupMethodChange, lookupMethodOptions); contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); - contentEl.createEl('h3', { text: "Name of 'id' metadata field to use in API query (if present, will be used instead of title)." }); - const idFieldNameComponent = new TextComponent(contentEl); - idFieldNameComponent.inputEl.style.width = '100%'; - idFieldNameComponent.setPlaceholder('id'); - idFieldNameComponent.onChange(value => (this.idFieldName = value)); - idFieldNameComponent.inputEl.addEventListener('keydown', ke => { + const fieldNameWrapperEl = contentEl.createEl('div', { cls: 'media-db-plugin-list-wrapper' }); + const fieldNameLabelWrapperEl = fieldNameWrapperEl.createEl('div', { cls: 'media-db-plugin-list-text-wrapper' }); + fieldNameLabelWrapperEl.createEl('span', { text: 'Using the property named', cls: 'media-db-plugin-list-text' }); + + const fieldNameComponent = new TextComponent(fieldNameWrapperEl); + fieldNameComponent.setPlaceholder('title / id'); + fieldNameComponent.onChange(value => (this.fieldName = value)); + fieldNameComponent.inputEl.addEventListener('keydown', ke => { if (ke.key === 'Enter') { this.submit(); } }); - contentEl.appendChild(idFieldNameComponent.inputEl); + contentEl.appendChild(fieldNameWrapperEl); contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); @@ -109,6 +108,19 @@ export class MediaDbFolderImportModal extends Modal { }); } + createDropdownEl(parentEl: HTMLElement, label: string, onChange: { (value: string): void }, options: { value: string; display: string }[]): void { + const wrapperEl = parentEl.createEl('div', { cls: 'media-db-plugin-list-wrapper' }); + const labelWrapperEl = wrapperEl.createEl('div', { cls: 'media-db-plugin-list-text-wrapper' }); + labelWrapperEl.createEl('span', { text: label, cls: 'media-db-plugin-list-text' }); + + const dropDownComponent = new DropdownComponent(wrapperEl); + dropDownComponent.onChange(onChange); + for (const option of options) { + dropDownComponent.addOption(option.value, option.display); + } + wrapperEl.appendChild(dropDownComponent.selectEl); + } + onClose(): void { const { contentEl } = this; contentEl.empty(); From 29269aa990266e0b2ffe8782422cedb1a609ba6c Mon Sep 17 00:00:00 2001 From: Karn Date: Wed, 3 Sep 2025 20:37:04 +0100 Subject: [PATCH 3/3] Further refactoring of the bulk / folder import logic --- src/main.ts | 8 +++-- src/modals/MediaDbFolderImportModal.ts | 42 +++++++++++++++----------- src/utils/BulkImportLookupMethod.ts | 4 +++ 3 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 src/utils/BulkImportLookupMethod.ts diff --git a/src/main.ts b/src/main.ts index 2019209..c6bfb59 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,6 +26,7 @@ import type { SearchModalOptions } from './utils/ModalHelper'; import { ModalHelper, ModalResultCode } from './utils/ModalHelper'; import type { CreateNoteOptions } from './utils/Utils'; import { dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString, unCamelCase, hasTemplaterPlugin, useTemplaterPluginInFile } from './utils/Utils'; +import { BulkImportLookupMethod } from 'src/utils/BulkImportLookupMethod'; export type Metadata = Record; @@ -646,7 +647,7 @@ export default class MediaDbPlugin extends Plugin { if (!lookupValue || typeof lookupValue !== 'string') { erroredFiles.push({ filePath: file.path, error: `metadata field '${fieldName}' not found, empty, or not a string` }); continue; - } else if (lookupMethod == 'id') { + } else if (lookupMethod === BulkImportLookupMethod.ID) { try { const model = await this.apiManager.queryDetailedInfoById(lookupValue, selectedAPI); if (model) { @@ -658,7 +659,7 @@ export default class MediaDbPlugin extends Plugin { erroredFiles.push({ filePath: file.path, error: `${e}` }); continue; } - } else if (lookupMethod == 'title') { + } else if (lookupMethod === BulkImportLookupMethod.TITLE) { let results: MediaTypeModel[] = []; try { results = await this.apiManager.query(lookupValue, [selectedAPI]); @@ -705,6 +706,9 @@ export default class MediaDbPlugin extends Plugin { await this.createMediaDbNotes(detailedResults, appendContent ? file : undefined); selectModal.close(); + } else { + erroredFiles.push({ filePath: file.path, error: `invalid lookup type` }); + continue; } } } diff --git a/src/modals/MediaDbFolderImportModal.ts b/src/modals/MediaDbFolderImportModal.ts index 729f3fd..ef9bcf8 100644 --- a/src/modals/MediaDbFolderImportModal.ts +++ b/src/modals/MediaDbFolderImportModal.ts @@ -2,6 +2,7 @@ import type { App, ButtonComponent } from 'obsidian'; import { DropdownComponent, Modal, Setting, TextComponent, ToggleComponent } from 'obsidian'; import type MediaDbPlugin from '../main'; import type { APIModel } from 'src/api/APIModel'; +import { BulkImportLookupMethod } from 'src/utils/BulkImportLookupMethod'; export class MediaDbFolderImportModal extends Modal { plugin: MediaDbPlugin; @@ -17,7 +18,7 @@ export class MediaDbFolderImportModal extends Modal { this.plugin = plugin; this.onSubmit = onSubmit; this.selectedApi = plugin.apiManager.apis[0].apiName; - this.lookupMethod = ''; + this.lookupMethod = BulkImportLookupMethod.TITLE; this.fieldName = ''; this.appendContent = false; } @@ -32,14 +33,16 @@ export class MediaDbFolderImportModal extends Modal { contentEl.createEl('h2', { text: 'Import folder as Media DB entries' }); - const onAPIChange = (value: string) => { - this.selectedApi = value; - }; - const apiOptions = this.plugin.apiManager.apis.map((api: APIModel) => { - return { value: api.apiName, display: api.apiName }; - }); - - this.createDropdownEl(contentEl, 'API to search', onAPIChange, apiOptions); + this.createDropdownEl( + contentEl, + 'API to search', + (value: string) => { + this.selectedApi = value; + }, + this.plugin.apiManager.apis.map((api: APIModel) => { + return { value: api.apiName, display: api.apiName }; + }), + ); contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); contentEl.createEl('h3', { text: 'Append note content to Media DB entry?' }); @@ -64,14 +67,17 @@ export class MediaDbFolderImportModal extends Modal { text: 'Choose whether to search the API by title (can return multiple results) or lookup directly using an ID (returns at most one result), and specify the name of the frontmatter property which contains the title or ID of the media.', }); - const onlookupMethodChange = (value: string) => { - this.lookupMethod = value; - }; - const lookupMethodOptions = [ - { value: 'title', display: 'Title' }, - { value: 'id', display: 'ID' }, - ]; - this.createDropdownEl(contentEl, 'Lookup media by', onlookupMethodChange, lookupMethodOptions); + this.createDropdownEl( + contentEl, + 'Lookup media by', + (value: string) => { + this.lookupMethod = value; + }, + [ + { value: BulkImportLookupMethod.TITLE, display: 'Title' }, + { value: BulkImportLookupMethod.ID, display: 'ID' }, + ], + ); contentEl.createDiv({ cls: 'media-db-plugin-spacer' }); @@ -108,7 +114,7 @@ export class MediaDbFolderImportModal extends Modal { }); } - createDropdownEl(parentEl: HTMLElement, label: string, onChange: { (value: string): void }, options: { value: string; display: string }[]): void { + createDropdownEl(parentEl: HTMLElement, label: string, onChange: (value: string) => void, options: { value: string; display: string }[]): void { const wrapperEl = parentEl.createEl('div', { cls: 'media-db-plugin-list-wrapper' }); const labelWrapperEl = wrapperEl.createEl('div', { cls: 'media-db-plugin-list-text-wrapper' }); labelWrapperEl.createEl('span', { text: label, cls: 'media-db-plugin-list-text' }); diff --git a/src/utils/BulkImportLookupMethod.ts b/src/utils/BulkImportLookupMethod.ts new file mode 100644 index 0000000..d785723 --- /dev/null +++ b/src/utils/BulkImportLookupMethod.ts @@ -0,0 +1,4 @@ +export enum BulkImportLookupMethod { + ID = 'id', + TITLE = 'title', +}