2025-07-15 15:30:17 +00:00
|
|
|
import { App, TFile } from "obsidian";
|
|
|
|
|
import {
|
|
|
|
|
GroupedStatuses,
|
|
|
|
|
NoteStatus,
|
|
|
|
|
NoteStatus as NoteStatusType,
|
2025-07-20 07:39:50 +00:00
|
|
|
StatusIdentifier,
|
|
|
|
|
ScopedStatusName,
|
2025-07-15 15:30:17 +00:00
|
|
|
} from "@/types/noteStatus";
|
|
|
|
|
import settingsService from "@/core/settingsService";
|
|
|
|
|
import eventBus from "./eventBus";
|
2025-07-20 07:39:50 +00:00
|
|
|
import { PREDEFINED_TEMPLATES } from "@/constants/predefinedTemplates";
|
2025-07-15 15:30:17 +00:00
|
|
|
|
|
|
|
|
export abstract class BaseNoteStatusService {
|
|
|
|
|
static app: App;
|
|
|
|
|
statuses: GroupedStatuses;
|
|
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
this.statuses = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static initialize(app: App) {
|
|
|
|
|
BaseNoteStatusService.app = app;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-20 07:39:50 +00:00
|
|
|
static parseStatusIdentifier(
|
|
|
|
|
identifier: StatusIdentifier,
|
|
|
|
|
): ScopedStatusName {
|
|
|
|
|
if (typeof identifier === "string") {
|
|
|
|
|
if (identifier.includes(":")) {
|
|
|
|
|
const [templateId, name] = identifier.split(":", 2);
|
|
|
|
|
return { templateId, name };
|
|
|
|
|
}
|
|
|
|
|
return { name: identifier };
|
|
|
|
|
}
|
|
|
|
|
return identifier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static formatStatusIdentifier(scopedName: ScopedStatusName): string {
|
|
|
|
|
if (scopedName.templateId) {
|
|
|
|
|
return `${scopedName.templateId}:${scopedName.name}`;
|
|
|
|
|
}
|
|
|
|
|
return scopedName.name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static resolveStatusFromIdentifier(
|
|
|
|
|
identifier: StatusIdentifier,
|
|
|
|
|
): NoteStatus | undefined {
|
|
|
|
|
const parsed = BaseNoteStatusService.parseStatusIdentifier(identifier);
|
|
|
|
|
const availableStatuses =
|
|
|
|
|
BaseNoteStatusService.getAllAvailableStatuses();
|
|
|
|
|
|
|
|
|
|
if (parsed.templateId) {
|
|
|
|
|
return availableStatuses.find(
|
|
|
|
|
(s) =>
|
|
|
|
|
s.name === parsed.name &&
|
|
|
|
|
s.templateId === parsed.templateId,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return availableStatuses.find((s) => s.name === parsed.name);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-15 15:30:17 +00:00
|
|
|
private static allEnabledTemplatesStatuses(): NoteStatusType[] {
|
|
|
|
|
if (settingsService.settings.useCustomStatusesOnly) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
const enabledTemplates = PREDEFINED_TEMPLATES.filter((template) =>
|
|
|
|
|
settingsService.settings.enabledTemplates.includes(template.id),
|
|
|
|
|
);
|
|
|
|
|
return enabledTemplates.flatMap((t) => t.statuses);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static getAllAvailableStatuses(): NoteStatus[] {
|
|
|
|
|
const availableStatuses = [
|
|
|
|
|
...settingsService.settings.customStatuses,
|
|
|
|
|
...BaseNoteStatusService.allEnabledTemplatesStatuses(),
|
|
|
|
|
];
|
|
|
|
|
return availableStatuses;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:36:58 +00:00
|
|
|
// static async insertStatusMetadataInEditor(file: TFile): Promise<void> {
|
|
|
|
|
// const tagPrefix = settingsService.settings.tagPrefix;
|
|
|
|
|
//
|
|
|
|
|
// await BaseNoteStatusService.app.fileManager.processFrontMatter(
|
|
|
|
|
// file,
|
|
|
|
|
// (frontmatter) => {
|
|
|
|
|
// const noteStatusFrontmatter =
|
|
|
|
|
// (frontmatter?.[tagPrefix] as string[]) || [];
|
|
|
|
|
// if (!noteStatusFrontmatter.length) {
|
|
|
|
|
// frontmatter[tagPrefix] = [];
|
|
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// );
|
|
|
|
|
// }
|
2025-07-15 15:30:17 +00:00
|
|
|
|
2025-07-20 07:39:50 +00:00
|
|
|
protected statusNameToObject(statusName: string | StatusIdentifier) {
|
|
|
|
|
if (typeof statusName === "string") {
|
|
|
|
|
return BaseNoteStatusService.resolveStatusFromIdentifier(
|
|
|
|
|
statusName,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return BaseNoteStatusService.resolveStatusFromIdentifier(statusName);
|
2025-07-15 15:30:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected getStatusMetadataKeys(): string[] {
|
|
|
|
|
return [settingsService.settings.tagPrefix];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
abstract populateStatuses(): void;
|
|
|
|
|
abstract removeStatus(
|
|
|
|
|
frontmatterTagName: string,
|
|
|
|
|
status: NoteStatus,
|
|
|
|
|
): Promise<boolean>;
|
|
|
|
|
abstract addStatus(
|
|
|
|
|
frontmatterTagName: string,
|
2025-07-20 07:39:50 +00:00
|
|
|
statusIdentifier: StatusIdentifier,
|
2025-07-15 15:30:17 +00:00
|
|
|
): Promise<boolean>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class NoteStatusService extends BaseNoteStatusService {
|
|
|
|
|
private file: TFile;
|
|
|
|
|
|
|
|
|
|
constructor(file: TFile) {
|
|
|
|
|
super();
|
|
|
|
|
this.file = file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public populateStatuses(): void {
|
|
|
|
|
const STATUS_METADATA_KEYS = this.getStatusMetadataKeys();
|
|
|
|
|
this.statuses = Object.fromEntries(
|
|
|
|
|
STATUS_METADATA_KEYS.map((key) => [key, []]),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!this.file) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cachedMetadata =
|
|
|
|
|
BaseNoteStatusService.app.metadataCache.getFileCache(this.file);
|
|
|
|
|
const frontmatter = cachedMetadata?.frontmatter;
|
|
|
|
|
if (!frontmatter) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STATUS_METADATA_KEYS.forEach((key) => {
|
|
|
|
|
const value = frontmatter[key];
|
|
|
|
|
if (value) {
|
|
|
|
|
let statuses: (NoteStatusType | undefined)[] = [];
|
|
|
|
|
if (Array.isArray(value)) {
|
|
|
|
|
statuses = value.map((v) =>
|
|
|
|
|
this.statusNameToObject(v.toString()),
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
statuses = [this.statusNameToObject(value.toString())];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
statuses = statuses.filter((s) => s !== undefined);
|
|
|
|
|
if (
|
|
|
|
|
statuses.length &&
|
|
|
|
|
!settingsService.settings.useMultipleStatuses
|
|
|
|
|
) {
|
|
|
|
|
statuses = statuses.slice(0, 1);
|
|
|
|
|
}
|
|
|
|
|
this.statuses[key] = statuses as NoteStatusType[];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async removeStatus(
|
|
|
|
|
frontmatterTagName: string,
|
|
|
|
|
status: NoteStatus,
|
|
|
|
|
): Promise<boolean> {
|
|
|
|
|
let removed = false;
|
2025-07-20 07:39:50 +00:00
|
|
|
const targetIdentifier = status.templateId
|
|
|
|
|
? BaseNoteStatusService.formatStatusIdentifier({
|
|
|
|
|
templateId: status.templateId,
|
|
|
|
|
name: status.name,
|
|
|
|
|
})
|
|
|
|
|
: status.name;
|
|
|
|
|
|
2025-07-15 15:30:17 +00:00
|
|
|
await BaseNoteStatusService.app.fileManager.processFrontMatter(
|
|
|
|
|
this.file,
|
|
|
|
|
(frontmatter) => {
|
|
|
|
|
const noteStatusFrontmatter =
|
|
|
|
|
(frontmatter?.[frontmatterTagName] as string[]) || [];
|
|
|
|
|
if (!noteStatusFrontmatter.length) return;
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(noteStatusFrontmatter)) {
|
2025-07-20 08:32:41 +00:00
|
|
|
// First try to find exact match (scoped or legacy)
|
|
|
|
|
let i = noteStatusFrontmatter.findIndex(
|
2025-07-20 07:39:50 +00:00
|
|
|
(statusName: string) => statusName === targetIdentifier,
|
2025-07-15 15:30:17 +00:00
|
|
|
);
|
2025-07-20 08:32:41 +00:00
|
|
|
|
|
|
|
|
// If not found and we're looking for a scoped status, try legacy format
|
|
|
|
|
if (i === -1 && status.templateId) {
|
|
|
|
|
i = noteStatusFrontmatter.findIndex(
|
|
|
|
|
(statusName: string) => statusName === status.name,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-15 15:30:17 +00:00
|
|
|
if (i !== -1) {
|
|
|
|
|
noteStatusFrontmatter.splice(i, 1);
|
|
|
|
|
removed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (removed) {
|
|
|
|
|
eventBus.publish("frontmatter-manually-changed", {
|
|
|
|
|
file: this.file,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return removed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async clearStatus(frontmatterTagName: string): Promise<boolean> {
|
|
|
|
|
await BaseNoteStatusService.app.fileManager.processFrontMatter(
|
|
|
|
|
this.file,
|
|
|
|
|
(frontmatter) => {
|
|
|
|
|
if (frontmatterTagName in frontmatter) {
|
2025-07-19 15:17:34 +00:00
|
|
|
frontmatter[frontmatterTagName] = [];
|
2025-07-15 15:30:17 +00:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
eventBus.publish("frontmatter-manually-changed", { file: this.file });
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async overrideStatuses(
|
|
|
|
|
frontmatterTagName: string,
|
2025-07-20 07:39:50 +00:00
|
|
|
statusIdentifiers: StatusIdentifier[],
|
2025-07-15 15:30:17 +00:00
|
|
|
): Promise<boolean> {
|
2025-07-20 07:39:50 +00:00
|
|
|
const formattedIdentifiers = statusIdentifiers.map((id) =>
|
|
|
|
|
typeof id === "string"
|
|
|
|
|
? id
|
|
|
|
|
: BaseNoteStatusService.formatStatusIdentifier(id),
|
|
|
|
|
);
|
2025-07-15 15:30:17 +00:00
|
|
|
await BaseNoteStatusService.app.fileManager.processFrontMatter(
|
|
|
|
|
this.file,
|
|
|
|
|
(frontmatter) => {
|
|
|
|
|
if (
|
|
|
|
|
frontmatterTagName in frontmatter &&
|
|
|
|
|
Array.isArray(frontmatter[frontmatterTagName])
|
|
|
|
|
) {
|
|
|
|
|
frontmatter[frontmatterTagName].splice(0);
|
2025-07-20 07:39:50 +00:00
|
|
|
frontmatter[frontmatterTagName].push(
|
|
|
|
|
...formattedIdentifiers,
|
|
|
|
|
);
|
2025-07-15 15:30:17 +00:00
|
|
|
}
|
2025-07-20 07:39:50 +00:00
|
|
|
frontmatter[frontmatterTagName] = [...formattedIdentifiers];
|
2025-07-15 15:30:17 +00:00
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
eventBus.publish("frontmatter-manually-changed", { file: this.file });
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async addStatus(
|
|
|
|
|
frontmatterTagName: string,
|
2025-07-20 07:39:50 +00:00
|
|
|
statusIdentifier: StatusIdentifier,
|
2025-07-15 15:30:17 +00:00
|
|
|
): Promise<boolean> {
|
|
|
|
|
let added = false;
|
2025-07-20 07:39:50 +00:00
|
|
|
const formattedIdentifier =
|
|
|
|
|
typeof statusIdentifier === "string"
|
|
|
|
|
? statusIdentifier
|
|
|
|
|
: BaseNoteStatusService.formatStatusIdentifier(
|
|
|
|
|
statusIdentifier,
|
|
|
|
|
);
|
|
|
|
|
|
2025-07-15 15:30:17 +00:00
|
|
|
await BaseNoteStatusService.app.fileManager.processFrontMatter(
|
|
|
|
|
this.file,
|
|
|
|
|
(frontmatter) => {
|
|
|
|
|
const noteStatusFrontmatter =
|
|
|
|
|
(frontmatter?.[frontmatterTagName] as string[]) || [];
|
|
|
|
|
if (!settingsService.settings.useMultipleStatuses) {
|
2025-07-20 07:39:50 +00:00
|
|
|
frontmatter[frontmatterTagName] = [formattedIdentifier];
|
2025-07-15 15:30:17 +00:00
|
|
|
added = true;
|
|
|
|
|
} else {
|
2025-07-19 15:36:58 +00:00
|
|
|
// Ensure frontmatter property exists as an array
|
|
|
|
|
if (
|
|
|
|
|
!frontmatter[frontmatterTagName] ||
|
|
|
|
|
!Array.isArray(frontmatter[frontmatterTagName])
|
|
|
|
|
) {
|
|
|
|
|
frontmatter[frontmatterTagName] = [];
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-20 08:32:41 +00:00
|
|
|
// Check if we already have this status (exact match)
|
|
|
|
|
const exactMatch = noteStatusFrontmatter.findIndex(
|
2025-07-20 07:39:50 +00:00
|
|
|
(statusName: string) =>
|
|
|
|
|
statusName === formattedIdentifier,
|
2025-07-15 15:30:17 +00:00
|
|
|
);
|
2025-07-20 08:32:41 +00:00
|
|
|
|
|
|
|
|
if (exactMatch === -1) {
|
|
|
|
|
// Check if we have a legacy version of this scoped status
|
|
|
|
|
let legacyIndex = -1;
|
|
|
|
|
if (
|
|
|
|
|
typeof statusIdentifier !== "string" &&
|
|
|
|
|
statusIdentifier.templateId
|
|
|
|
|
) {
|
|
|
|
|
legacyIndex = noteStatusFrontmatter.findIndex(
|
|
|
|
|
(statusName: string) =>
|
|
|
|
|
statusName === statusIdentifier.name,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (legacyIndex !== -1) {
|
|
|
|
|
// Replace legacy with scoped version
|
|
|
|
|
noteStatusFrontmatter[legacyIndex] =
|
|
|
|
|
formattedIdentifier;
|
|
|
|
|
added = true;
|
|
|
|
|
} else {
|
|
|
|
|
// Add new status
|
|
|
|
|
frontmatter[frontmatterTagName].push(
|
|
|
|
|
formattedIdentifier,
|
|
|
|
|
);
|
|
|
|
|
added = true;
|
|
|
|
|
}
|
2025-07-15 15:30:17 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
if (added) {
|
|
|
|
|
eventBus.publish("frontmatter-manually-changed", {
|
|
|
|
|
file: this.file,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return added;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class MultipleNoteStatusService extends BaseNoteStatusService {
|
|
|
|
|
private files: TFile[];
|
|
|
|
|
|
|
|
|
|
constructor(files: TFile[]) {
|
|
|
|
|
super();
|
|
|
|
|
this.files = files;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
selectedFilesQTY() {
|
|
|
|
|
return this.files.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public populateStatuses(): void {
|
|
|
|
|
const STATUS_METADATA_KEYS = this.getStatusMetadataKeys();
|
|
|
|
|
|
|
|
|
|
this.statuses = Object.fromEntries(
|
|
|
|
|
STATUS_METADATA_KEYS.map((key) => [key, []]),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const allStatuses = new Map<string, Set<string>>();
|
|
|
|
|
|
|
|
|
|
this.files.forEach((file) => {
|
|
|
|
|
const cachedMetadata =
|
|
|
|
|
BaseNoteStatusService.app.metadataCache.getFileCache(file);
|
|
|
|
|
const frontmatter = cachedMetadata?.frontmatter;
|
|
|
|
|
if (!frontmatter) return;
|
|
|
|
|
|
|
|
|
|
STATUS_METADATA_KEYS.forEach((key) => {
|
|
|
|
|
const value = frontmatter[key];
|
|
|
|
|
if (value) {
|
|
|
|
|
if (!allStatuses.has(key)) {
|
|
|
|
|
allStatuses.set(key, new Set());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const statusNames = Array.isArray(value) ? value : [value];
|
|
|
|
|
statusNames.forEach((name) =>
|
|
|
|
|
allStatuses.get(key)!.add(name.toString()),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
STATUS_METADATA_KEYS.forEach((key) => {
|
|
|
|
|
const statusNames = allStatuses.get(key);
|
|
|
|
|
if (statusNames) {
|
|
|
|
|
const statuses = Array.from(statusNames)
|
|
|
|
|
.map((name) => this.statusNameToObject(name))
|
|
|
|
|
.filter((s) => s !== undefined) as NoteStatusType[];
|
|
|
|
|
|
|
|
|
|
this.statuses[key] = statuses;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async removeStatus(
|
|
|
|
|
frontmatterTagName: string,
|
|
|
|
|
status: NoteStatus,
|
|
|
|
|
): Promise<boolean> {
|
|
|
|
|
let removedFromAny = false;
|
2025-07-20 07:39:50 +00:00
|
|
|
const targetIdentifier = status.templateId
|
|
|
|
|
? BaseNoteStatusService.formatStatusIdentifier({
|
|
|
|
|
templateId: status.templateId,
|
|
|
|
|
name: status.name,
|
|
|
|
|
})
|
|
|
|
|
: status.name;
|
2025-07-15 15:30:17 +00:00
|
|
|
|
|
|
|
|
const promises = this.files.map(async (file) => {
|
|
|
|
|
let removed = false;
|
|
|
|
|
await BaseNoteStatusService.app.fileManager.processFrontMatter(
|
|
|
|
|
file,
|
|
|
|
|
(frontmatter) => {
|
|
|
|
|
const noteStatusFrontmatter =
|
|
|
|
|
frontmatter[frontmatterTagName];
|
|
|
|
|
if (!noteStatusFrontmatter) return;
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(noteStatusFrontmatter)) {
|
2025-07-20 08:32:41 +00:00
|
|
|
// First try to find exact match (scoped or legacy)
|
|
|
|
|
let index = noteStatusFrontmatter.findIndex(
|
2025-07-20 07:39:50 +00:00
|
|
|
(statusName: string) =>
|
|
|
|
|
statusName === targetIdentifier,
|
2025-07-15 15:30:17 +00:00
|
|
|
);
|
2025-07-20 08:32:41 +00:00
|
|
|
|
|
|
|
|
// If not found and we're looking for a scoped status, try legacy format
|
|
|
|
|
if (index === -1 && status.templateId) {
|
|
|
|
|
index = noteStatusFrontmatter.findIndex(
|
|
|
|
|
(statusName: string) =>
|
|
|
|
|
statusName === status.name,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-15 15:30:17 +00:00
|
|
|
if (index !== -1) {
|
|
|
|
|
noteStatusFrontmatter.splice(index, 1);
|
|
|
|
|
removed = true;
|
|
|
|
|
}
|
2025-07-20 08:32:41 +00:00
|
|
|
} else if (
|
|
|
|
|
noteStatusFrontmatter === targetIdentifier ||
|
|
|
|
|
(status.templateId &&
|
|
|
|
|
noteStatusFrontmatter === status.name)
|
|
|
|
|
) {
|
2025-07-15 15:30:17 +00:00
|
|
|
delete frontmatter[frontmatterTagName];
|
|
|
|
|
removed = true;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
return removed;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const results = await Promise.all(promises);
|
|
|
|
|
removedFromAny = results.some((result) => result);
|
|
|
|
|
|
|
|
|
|
if (removedFromAny) {
|
|
|
|
|
this.files.forEach((file) => {
|
|
|
|
|
eventBus.publish("frontmatter-manually-changed", { file });
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return removedFromAny;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async addStatus(
|
|
|
|
|
frontmatterTagName: string,
|
2025-07-20 07:39:50 +00:00
|
|
|
statusIdentifier: StatusIdentifier,
|
2025-07-15 15:30:17 +00:00
|
|
|
): Promise<boolean> {
|
|
|
|
|
let addedToAny = false;
|
2025-07-20 07:39:50 +00:00
|
|
|
const formattedIdentifier =
|
|
|
|
|
typeof statusIdentifier === "string"
|
|
|
|
|
? statusIdentifier
|
|
|
|
|
: BaseNoteStatusService.formatStatusIdentifier(
|
|
|
|
|
statusIdentifier,
|
|
|
|
|
);
|
2025-07-15 15:30:17 +00:00
|
|
|
|
|
|
|
|
const promises = this.files.map(async (file) => {
|
|
|
|
|
let added = false;
|
|
|
|
|
await BaseNoteStatusService.app.fileManager.processFrontMatter(
|
|
|
|
|
file,
|
|
|
|
|
(frontmatter) => {
|
|
|
|
|
const noteStatusFrontmatter =
|
|
|
|
|
frontmatter[frontmatterTagName];
|
|
|
|
|
|
|
|
|
|
if (!noteStatusFrontmatter) {
|
2025-07-20 07:39:50 +00:00
|
|
|
frontmatter[frontmatterTagName] = [formattedIdentifier];
|
2025-07-15 15:30:17 +00:00
|
|
|
added = true;
|
|
|
|
|
} else if (Array.isArray(noteStatusFrontmatter)) {
|
2025-07-20 07:39:50 +00:00
|
|
|
if (
|
|
|
|
|
!noteStatusFrontmatter.includes(formattedIdentifier)
|
|
|
|
|
) {
|
|
|
|
|
noteStatusFrontmatter.push(formattedIdentifier);
|
2025-07-15 15:30:17 +00:00
|
|
|
added = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-07-20 07:39:50 +00:00
|
|
|
if (noteStatusFrontmatter !== formattedIdentifier) {
|
2025-07-15 15:30:17 +00:00
|
|
|
frontmatter[frontmatterTagName] = [
|
|
|
|
|
noteStatusFrontmatter,
|
2025-07-20 07:39:50 +00:00
|
|
|
formattedIdentifier,
|
2025-07-15 15:30:17 +00:00
|
|
|
];
|
|
|
|
|
added = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
return added;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const results = await Promise.all(promises);
|
|
|
|
|
addedToAny = results.some((result) => result);
|
|
|
|
|
|
|
|
|
|
if (addedToAny) {
|
|
|
|
|
this.files.forEach((file) => {
|
|
|
|
|
eventBus.publish("frontmatter-manually-changed", { file });
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return addedToAny;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getFilesWithStatus(
|
|
|
|
|
frontmatterTagName: string,
|
|
|
|
|
status: NoteStatus,
|
|
|
|
|
): TFile[] {
|
2025-07-20 07:39:50 +00:00
|
|
|
const targetIdentifier = status.templateId
|
|
|
|
|
? BaseNoteStatusService.formatStatusIdentifier({
|
|
|
|
|
templateId: status.templateId,
|
|
|
|
|
name: status.name,
|
|
|
|
|
})
|
|
|
|
|
: status.name;
|
|
|
|
|
|
2025-07-15 15:30:17 +00:00
|
|
|
return this.files.filter((file) => {
|
|
|
|
|
const cachedMetadata =
|
|
|
|
|
BaseNoteStatusService.app.metadataCache.getFileCache(file);
|
|
|
|
|
const frontmatter = cachedMetadata?.frontmatter;
|
|
|
|
|
if (!frontmatter) return false;
|
|
|
|
|
|
|
|
|
|
const value = frontmatter[frontmatterTagName];
|
|
|
|
|
if (!value) return false;
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(value)) {
|
2025-07-20 08:32:41 +00:00
|
|
|
// Check for exact match first, then legacy format if scoped
|
|
|
|
|
return (
|
|
|
|
|
value.includes(targetIdentifier) ||
|
|
|
|
|
(status.templateId && value.includes(status.name))
|
|
|
|
|
);
|
2025-07-15 15:30:17 +00:00
|
|
|
}
|
2025-07-20 08:32:41 +00:00
|
|
|
// Check for exact match first, then legacy format if scoped
|
|
|
|
|
return (
|
|
|
|
|
value === targetIdentifier ||
|
|
|
|
|
(status.templateId && value === status.name)
|
|
|
|
|
);
|
2025-07-15 15:30:17 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|