Migrate settings to Obsidian 1.13 declarative API

This commit is contained in:
David V. Kimball 2026-05-29 23:25:15 -07:00
parent 4e6db84000
commit 7810285cb9
5 changed files with 288 additions and 15 deletions

View file

@ -1,7 +1,7 @@
{
"id": "property-over-file-name",
"name": "Property Over File Name",
"version": "0.7.8",
"version": "0.7.9",
"minAppVersion": "1.11.0",
"description": "Search, display, and insert notes using a specified note property instead of the file name.",
"author": "David V. Kimball",

View file

@ -1,6 +1,6 @@
{
"name": "property-over-file-name",
"version": "0.7.8",
"version": "0.7.9",
"description": "Search, display, and insert notes using a specified note property instead of the file name.",
"main": "main.js",
"type": "module",
@ -25,7 +25,7 @@
"eslint-plugin-obsidianmd": "^0.3.0",
"globals": "14.0.0",
"obsidian": "^1.11.0",
"obsidian-dev-skills": "^1.2.3",
"@davidvkimball/obsidian-dev-skills": "^1.3.0",
"tslib": "2.4.0",
"typescript": "5.8.3",
"typescript-eslint": "^8.50.1"

View file

@ -22,6 +22,9 @@ importers:
.:
devDependencies:
'@davidvkimball/obsidian-dev-skills':
specifier: ^1.3.0
version: 1.3.0
'@eslint/js':
specifier: ^9.30.1
version: 9.39.2
@ -52,9 +55,6 @@ importers:
obsidian:
specifier: ^1.11.0
version: 1.11.0(@codemirror/state@6.5.0)(@codemirror/view@6.38.6)
obsidian-dev-skills:
specifier: ^1.2.3
version: 1.2.3
tslib:
specifier: 2.4.0
version: 2.4.0
@ -73,6 +73,11 @@ packages:
'@codemirror/view@6.38.6':
resolution: {integrity: sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==}
'@davidvkimball/obsidian-dev-skills@1.3.0':
resolution: {integrity: sha512-C9HQ+PRYhZ2QFUdoFYjudXxrGD5SfXQtQl0Lxk61Bq1oD+/LV/57t8EeGSvWIL9/J67V08/MFOMvOf4/WgML9g==}
engines: {node: '>=18.0.0'}
hasBin: true
'@esbuild/aix-ppc64@0.25.5':
resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==}
engines: {node: '>=18'}
@ -1165,11 +1170,6 @@ packages:
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
engines: {node: '>= 0.4'}
obsidian-dev-skills@1.2.3:
resolution: {integrity: sha512-bYnajDRC7qbU46yY5uEZr+0u+xXWO9BIRerUWE6CkWvgwzltNctqgX7e1RJDC69NYjKBNrsfPCy9d2p7hM6Img==}
engines: {node: '>=18.0.0'}
hasBin: true
obsidian@1.11.0:
resolution: {integrity: sha512-lVqN9AmDWHzhNATi2tDnjqVgI6WUYKeT+lIsAycAyLt4XCC6zRsWzb+tFCiB7Rn3PpttefjoovilhYwvS4Iqxw==}
peerDependencies:
@ -1519,6 +1519,8 @@ snapshots:
style-mod: 4.1.3
w3c-keyname: 2.2.8
'@davidvkimball/obsidian-dev-skills@1.3.0': {}
'@esbuild/aix-ppc64@0.25.5':
optional: true
@ -2872,8 +2874,6 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
obsidian-dev-skills@1.2.3: {}
obsidian@1.11.0(@codemirror/state@6.5.0)(@codemirror/view@6.38.6):
dependencies:
'@codemirror/state': 6.5.0

View file

@ -1,4 +1,4 @@
import { App, PluginSettingTab , SettingGroup} from 'obsidian';
import { App, PluginSettingTab, Setting, SettingGroup } from 'obsidian';
import { ExcludedFilesBehavior, PropertyOverFileNamePlugin } from '../types';
@ -11,6 +11,278 @@ export class SettingTab extends PluginSettingTab {
this.plugin = plugin;
}
// 1.13.0+: framework calls this and skips display().
// Pre-1.13.0: this method is not invoked; display() below runs as before.
// See https://docs.obsidian.md/plugins/guides/migrate-declarative-settings
getSettingDefinitions() {
return [
{
name: 'Property key',
desc: 'The property to use as the display title. Falls back to the file name when no property is set for that item.',
// Render: value is trimmed with a fallback and the change refreshes every component.
render: (setting: Setting) => {
setting.addText(text => text
.setPlaceholder('Title')
.setValue(this.plugin.settings.propertyKey)
.onChange(async value => {
this.plugin.settings.propertyKey = value.trim() || 'title';
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateLinkSuggester();
this.plugin.updateGraphView();
this.plugin.updateBacklinks();
this.plugin.updateTabs();
this.plugin.updateExplorer();
this.plugin.updateWindowFrame();
this.plugin.updateBookmarks();
}));
},
},
{
name: 'When linking notes',
desc: 'Enable property-based titles in the link suggester.',
// Render: side effect (link suggester refresh).
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForLinking)
.onChange(async value => {
this.plugin.settings.enableForLinking = value;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateLinkSuggester();
}));
},
},
{
name: 'In quick switcher',
desc: 'Enable property-based titles in the quick switcher.',
// Render: save goes through saveSettings with the previous state so the quick switcher only re-registers when the value changes.
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForQuickSwitcher)
.onChange(async value => {
const prevQuickSwitcherState = this.plugin.settings.enableForQuickSwitcher;
this.plugin.settings.enableForQuickSwitcher = value;
await this.plugin.saveSettings(prevQuickSwitcherState);
}));
},
},
{
name: 'In properties',
desc: 'Enable property-based titles in the property link suggester.',
// Render: side effect (properties refresh).
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForProperties)
.onChange(async value => {
this.plugin.settings.enableForProperties = value;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateProperties();
}));
},
},
{
name: 'Include file name in fuzzy searches',
desc: 'Include note file names in fuzzy search results for link suggester and quick switcher.',
control: { type: 'toggle' as const, key: 'includeFilenameInSearch' },
},
{
name: 'Include aliases in fuzzy searches',
desc: 'Include property aliases in fuzzy search results for link suggester and quick switcher.',
control: { type: 'toggle' as const, key: 'includeAliasesInSearch' },
},
{
name: 'When dragging notes',
desc: 'Use property-based titles when dragging notes from the file explorer.',
control: { type: 'toggle' as const, key: 'enableForDragDrop' },
},
{
name: 'When naming bookmarks',
desc: 'Automatically use the configured property value as the default name when creating a bookmark.',
// Render: side effect (bookmarks refresh).
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForBookmarks)
.onChange(async value => {
this.plugin.settings.enableForBookmarks = value;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateBookmarks();
}));
},
},
{
name: 'In graph view',
desc: 'Use the property instead of the file name as the note\'s title in graph view.',
// Render: save goes through saveSettings, which always refreshes the graph view.
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForGraphView)
.onChange(async value => {
this.plugin.settings.enableForGraphView = value;
await this.plugin.saveSettings();
}));
},
},
{
name: 'In backlinks and outgoing links',
desc: 'Use the property instead of the file name in the linked mentions footer, dedicated backlinks panel, and outgoing links.',
// Render: side effect (backlinks refresh).
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForBacklinks)
.onChange(async value => {
this.plugin.settings.enableForBacklinks = value;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateBacklinks();
}));
},
},
{
name: 'Hide unlinked mentions (backlinks panel)',
desc: 'Hide the “Unlinked mentions” section in the backlinks panel and skip processing it. Useful for folder-note setups where file names like `index` make unlinked mentions noisy.',
// Render: side effect (backlinks refresh).
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.hideUnlinkedMentionsInBacklinks)
.onChange(async value => {
this.plugin.settings.hideUnlinkedMentionsInBacklinks = value;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateBacklinks();
}));
},
},
{
name: 'In tab titles',
desc: 'Use the property instead of the file name in tab titles.',
// Render: save goes through saveSettings with the previous tab state so tabs only re-register when the value changes.
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForTabs)
.onChange(async value => {
const prevTabState = this.plugin.settings.enableForTabs;
this.plugin.settings.enableForTabs = value;
await this.plugin.saveSettings(undefined, prevTabState);
}));
},
},
{
name: 'In window frame title',
desc: 'Use the property instead of the file name in the browser window title bar.',
// Render: side effect (window frame refresh).
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForWindowFrame)
.onChange(async value => {
this.plugin.settings.enableForWindowFrame = value;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateWindowFrame();
}));
},
},
{
name: 'In file explorer',
desc: 'Use the property instead of the file name in the file explorer.',
// Render: side effect (explorer refresh). Toggling this shows or hides the folder note file name row below,
// so refresh the DOM state to re-evaluate that row's visible predicate.
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableForExplorer)
.onChange(async value => {
this.plugin.settings.enableForExplorer = value;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateExplorer();
// Re-run the visible predicate so the folder note file name row appears
// or disappears. refreshDomState exists on Obsidian 1.13.0+, which is the
// only version that calls getSettingDefinitions in the first place.
const refresh = (this as unknown as { refreshDomState?: () => void }).refreshDomState;
if (refresh) refresh.call(this);
}));
},
},
{
name: 'Folder note file name',
desc: 'If a folder contains a file with this name that has the configured property, the folder will display that property value instead. This ensures compatibility with folder notes plugins. Leave blank to disable.',
// Shown only when the file explorer integration is enabled.
visible: () => this.plugin.settings.enableForExplorer,
// Render: value is trimmed and the change refreshes the explorer.
render: (setting: Setting) => {
setting.addText(text => text
.setPlaceholder('Index')
.setValue(this.plugin.settings.folderNoteFilename)
.onChange(async value => {
this.plugin.settings.folderNoteFilename = value.trim();
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateExplorer();
}));
},
},
{
name: 'Use simple search',
desc: 'Instead of using fuzzy search, simple search provides better performance with very large vaults (thousands of files).',
control: { type: 'toggle' as const, key: 'useSimpleSearch' },
},
{
name: 'Excluded files in quick switcher',
desc: 'How files in Obsidian\'s "excluded files" list should behave in the quick switcher.',
// Render: side effect (quick switcher refresh).
render: (setting: Setting) => {
setting.addDropdown(dropdown => dropdown
.addOptions({
deemphasize: 'Deemphasize (move to bottom & gray out)',
hide: 'Hide entirely',
ignore: 'Ignore (treat as normal files)',
})
.setValue(this.plugin.settings.quickSwitcherExcludedBehavior)
.onChange(async value => {
this.plugin.settings.quickSwitcherExcludedBehavior = value as ExcludedFilesBehavior;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateQuickSwitcher();
}));
},
},
{
name: 'Excluded files in link suggester',
desc: 'How files in Obsidian\'s "excluded files" list should behave in the link suggester.',
// Render: side effect (link suggester refresh).
render: (setting: Setting) => {
setting.addDropdown(dropdown => dropdown
.addOptions({
deemphasize: 'Deemphasize (move to bottom & gray out)',
hide: 'Hide entirely',
ignore: 'Ignore (treat as normal files)',
})
.setValue(this.plugin.settings.linkSuggesterExcludedBehavior)
.onChange(async value => {
this.plugin.settings.linkSuggesterExcludedBehavior = value as ExcludedFilesBehavior;
await this.plugin.saveData(this.plugin.settings);
this.plugin.updateLinkSuggester();
}));
},
},
{
name: 'Enable mdx file support',
desc: 'Enable support for .mdx files. When enabled, the plugin will read properties from mdx files manually (Obsidian\'s metadata cache only works for .md files).',
// Render: save goes through saveSettings and the change rebuilds the cache and refreshes every component.
render: (setting: Setting) => {
setting.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableMdxSupport)
.onChange(async value => {
this.plugin.settings.enableMdxSupport = value;
await this.plugin.saveSettings();
// Rebuild cache and refresh all components when MDX support is toggled
this.plugin.rebuildCache();
this.plugin.updateLinkSuggester();
this.plugin.updateQuickSwitcher();
this.plugin.updateGraphView();
this.plugin.updateBacklinks();
this.plugin.updateTabs();
this.plugin.updateExplorer();
this.plugin.updateWindowFrame();
this.plugin.updateBookmarks();
}));
},
},
];
}
display(): void {
const { containerEl } = this;
containerEl.empty();

View file

@ -12,5 +12,6 @@
"0.7.5": "1.11.0",
"0.7.6": "1.11.0",
"0.7.7": "1.11.0",
"0.7.8": "1.11.0"
"0.7.8": "1.11.0",
"0.7.9": "1.11.0"
}