mirror of
https://github.com/aleksejs1/obsidian-contact-sync-plugin.git
synced 2026-07-22 12:40:24 +00:00
Add customizable naming strategy for filenames as Last First. Implements #16
This commit is contained in:
parent
ce40b97799
commit
5a76df5856
10 changed files with 103 additions and 14 deletions
|
|
@ -19,6 +19,8 @@ Each contact becomes a separate note with YAML frontmatter for metadata and free
|
|||
|
||||
- 📛 Filename prefix support (e.g. `p Ivan Ivanov.md`)
|
||||
|
||||
- 🏷️ Customizable naming strategy for filenames as last name first (e.g. `p Ivanov Ivan.md`)
|
||||
|
||||
- 🧩 Multiple naming strategies for frontmatter keys:
|
||||
- **Default**: Customizable prefix (e.g., `s_name`, `s_email_2`).
|
||||
- **VCF (vCard)**: Fully compatible with the [VCF Contacts](https://github.com/broekema41/obsidian-vcf-contacts) plugin.
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ describe('ContactNoteWriter', () => {
|
|||
trackSyncTime: true,
|
||||
renameFiles: false,
|
||||
namingStrategy: NamingStrategy.Default,
|
||||
lastFirst: false,
|
||||
};
|
||||
|
||||
await contactNoteWriter.writeNotesForContacts(
|
||||
|
|
@ -174,6 +175,7 @@ describe('ContactNoteWriter', () => {
|
|||
trackSyncTime: true,
|
||||
renameFiles: false,
|
||||
namingStrategy: NamingStrategy.Default,
|
||||
lastFirst: false,
|
||||
};
|
||||
|
||||
await contactNoteWriter.writeNotesForContacts(
|
||||
|
|
@ -222,6 +224,7 @@ describe('ContactNoteWriter', () => {
|
|||
trackSyncTime: true,
|
||||
renameFiles: false,
|
||||
namingStrategy: NamingStrategy.Default,
|
||||
lastFirst: false,
|
||||
};
|
||||
|
||||
await contactNoteWriter.writeNotesForContacts(
|
||||
|
|
@ -264,6 +267,7 @@ describe('ContactNoteWriter', () => {
|
|||
trackSyncTime: true,
|
||||
renameFiles: false,
|
||||
namingStrategy: NamingStrategy.Default,
|
||||
lastFirst: false,
|
||||
};
|
||||
|
||||
await contactNoteWriter.writeNotesForContacts(
|
||||
|
|
@ -304,6 +308,7 @@ describe('ContactNoteWriter', () => {
|
|||
trackSyncTime: true,
|
||||
renameFiles: false,
|
||||
namingStrategy: NamingStrategy.Default,
|
||||
lastFirst: false,
|
||||
};
|
||||
|
||||
await contactNoteWriter.writeNotesForContacts(
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ describe('ContactNoteWriterUpdate', () => {
|
|||
trackSyncTime: true,
|
||||
renameFiles: false,
|
||||
namingStrategy: NamingStrategy.Default,
|
||||
lastFirst: false,
|
||||
};
|
||||
|
||||
await contactNoteWriter.writeNotesForContacts(
|
||||
|
|
@ -160,6 +161,7 @@ describe('ContactNoteWriterUpdate', () => {
|
|||
trackSyncTime: true,
|
||||
renameFiles: false,
|
||||
namingStrategy: NamingStrategy.Default,
|
||||
lastFirst: false,
|
||||
};
|
||||
|
||||
await contactNoteWriter.writeNotesForContacts(
|
||||
|
|
|
|||
|
|
@ -37,4 +37,5 @@ export const DEFAULT_SETTINGS: ContactSyncSettings = {
|
|||
organizationAsLink: false,
|
||||
renameFiles: false,
|
||||
namingStrategy: NamingStrategy.Default,
|
||||
lastFirst: false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -85,6 +85,10 @@ export const ru = {
|
|||
File: 'Файл',
|
||||
'Contact ID': 'ID контакта',
|
||||
'Audit complete. Report saved to': 'Аудит завершен. Отчет сохранен в',
|
||||
'Format file names as Last First':
|
||||
'Форматировать имена файлов как Фамилия Имя',
|
||||
'If enabled, contact file names will be formatted as Last First instead of First Last':
|
||||
'Если включено, имена файлов контактов будут форматироваться как Фамилия Имя вместо Имя Фамилия',
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -174,6 +178,10 @@ export const lv = {
|
|||
File: 'Fails',
|
||||
'Contact ID': 'Kontakta ID',
|
||||
'Audit complete. Report saved to': 'Audits pabeigts. Pārskats saglabāts',
|
||||
'Format file names as Last First':
|
||||
'Formatēt failu nosaukumus kā Uzvārds Vārds',
|
||||
'If enabled, contact file names will be formatted as Last First instead of First Last':
|
||||
'Ja iespējots, kontaktu failu nosaukumi tiks formatēti kā Uzvārds Vārds, nevis Vārds Uzvārds',
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -262,4 +270,7 @@ export const en = {
|
|||
File: 'File',
|
||||
'Contact ID': 'Contact ID',
|
||||
'Audit complete. Report saved to': 'Audit complete. Report saved to',
|
||||
'Format file names as Last First': 'Format file names as Last First',
|
||||
'If enabled, contact file names will be formatted as Last First instead of First Last':
|
||||
'If enabled, contact file names will be formatted as Last First instead of First Last',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ export default class GoogleContactsSyncPlugin extends Plugin {
|
|||
trackSyncTime: this.settings.trackSyncTime,
|
||||
renameFiles: this.settings.renameFiles,
|
||||
namingStrategy: this.settings.namingStrategy,
|
||||
lastFirst: this.settings.lastFirst,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,22 @@ export class ContactSyncSettingTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t('Format file names as Last First'))
|
||||
.setDesc(
|
||||
t(
|
||||
'If enabled, contact file names will be formatted as Last First instead of First Last'
|
||||
)
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.lastFirst)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.lastFirst = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t('Naming strategy'))
|
||||
.setDesc(t('Strategy to generate frontmatter keys from contact data'))
|
||||
|
|
|
|||
|
|
@ -113,12 +113,13 @@ export class ContactNoteWriter {
|
|||
return;
|
||||
}
|
||||
|
||||
let filename = this.getFilename(
|
||||
contact,
|
||||
id,
|
||||
config.folderPath,
|
||||
config.prefix
|
||||
);
|
||||
const filenameContext = {
|
||||
folderPath: config.folderPath,
|
||||
prefix: config.prefix,
|
||||
lastFirst: config.lastFirst,
|
||||
};
|
||||
|
||||
let filename = this.getFilename(contact, id, filenameContext);
|
||||
if (!filename) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -190,23 +191,69 @@ export class ContactNoteWriter {
|
|||
* @param id - The contact ID.
|
||||
* @param folderPath - The folder path where the note will be stored.
|
||||
* @param prefix - The prefix to use for the filename.
|
||||
* @param lastFirst - Whether to format the name as Last First.
|
||||
* @returns The generated filename, or null if the name is not available.
|
||||
*/
|
||||
private getFilename(
|
||||
contact: GoogleContact,
|
||||
id: string,
|
||||
context: Record<string, string | boolean>
|
||||
): string | null {
|
||||
const displayNameLastFirst = this.getLastFirstName(
|
||||
contact,
|
||||
context.lastFirst as boolean
|
||||
);
|
||||
if (displayNameLastFirst) {
|
||||
return this.getNormalizedFilename(
|
||||
displayNameLastFirst,
|
||||
context.folderPath as string,
|
||||
context.prefix as string
|
||||
);
|
||||
}
|
||||
|
||||
const displayName = contact.names?.[0]?.displayName;
|
||||
if (displayName) {
|
||||
return this.getNormalizedFilename(
|
||||
displayName,
|
||||
context.folderPath as string,
|
||||
context.prefix as string
|
||||
);
|
||||
}
|
||||
|
||||
const organizationName = contact.organizations?.[0]?.name;
|
||||
if (organizationName) {
|
||||
return this.getNormalizedFilename(
|
||||
organizationName,
|
||||
context.folderPath as string,
|
||||
context.prefix as string
|
||||
);
|
||||
}
|
||||
|
||||
if (id) {
|
||||
return this.getNormalizedFilename(
|
||||
id,
|
||||
context.folderPath as string,
|
||||
context.prefix as string
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private getNormalizedFilename(
|
||||
name: string,
|
||||
folderPath: string,
|
||||
prefix: string
|
||||
): string | null {
|
||||
// Try displayName first, then organization name, then fall back to ID
|
||||
const name =
|
||||
contact.names?.[0]?.displayName ?? contact.organizations?.[0]?.name ?? id;
|
||||
if (!name) {
|
||||
): string {
|
||||
const safeName = name.replace(/[\\/:*?"<>|]/g, '_');
|
||||
return normalizePath(`${folderPath}/${prefix}${safeName}.md`);
|
||||
}
|
||||
|
||||
private getLastFirstName(contact: GoogleContact, lastFirst: boolean) {
|
||||
if (!lastFirst) {
|
||||
return null;
|
||||
}
|
||||
const safeName = name.replace(/[\\/:*?"<>|]/g, '_');
|
||||
const filename = normalizePath(`${folderPath}/${prefix}${safeName}.md`);
|
||||
return filename;
|
||||
return contact.names?.[0]?.displayNameLastFirst?.replace(/,/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ export interface ContactNoteConfig {
|
|||
trackSyncTime: boolean;
|
||||
renameFiles: boolean;
|
||||
namingStrategy: NamingStrategy;
|
||||
lastFirst: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ export interface ContactSyncSettings {
|
|||
|
||||
/** Naming strategy to use for contact properties */
|
||||
namingStrategy: NamingStrategy;
|
||||
|
||||
/** Whether to format names as Last, First */
|
||||
lastFirst: boolean;
|
||||
}
|
||||
|
||||
export enum NamingStrategy {
|
||||
|
|
|
|||
Loading…
Reference in a new issue