mirror of
https://github.com/devonthesofa/obsidian-note-status.git
synced 2026-07-22 12:30:24 +00:00
chore: remove type casting; adds type validation
This commit is contained in:
parent
3fb95380be
commit
287d6bb918
5 changed files with 74 additions and 64 deletions
13
main.ts
13
main.ts
|
|
@ -311,7 +311,12 @@ export default class NoteStatus extends Plugin {
|
|||
// Multiple files selection menu
|
||||
this.registerEvent(
|
||||
this.app.workspace.on('files-menu', (menu, files) => {
|
||||
const mdFiles = files.filter(file => file instanceof TFile && file.extension === 'md') as TFile[];
|
||||
const mdFiles: TFile[] = [];
|
||||
for (const file of files) {
|
||||
if (file instanceof TFile && file.extension === 'md') {
|
||||
mdFiles.push(file);
|
||||
}
|
||||
}
|
||||
if (mdFiles.length > 0) {
|
||||
menu.addItem((item) =>
|
||||
item
|
||||
|
|
@ -465,12 +470,12 @@ export default class NoteStatus extends Plugin {
|
|||
checkNoteStatus(): void {
|
||||
try {
|
||||
const activeFile = this.app.workspace.getActiveFile();
|
||||
if (!activeFile || activeFile.extension !== 'md') {
|
||||
if (!activeFile || !(activeFile instanceof TFile) || activeFile.extension !== 'md') {
|
||||
this.statusBar.update(['unknown']);
|
||||
this.statusDropdown.update(['unknown']);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const statuses = this.statusService.getFileStatuses(activeFile);
|
||||
this.statusBar.update(statuses);
|
||||
this.statusDropdown.update(statuses);
|
||||
|
|
@ -491,7 +496,7 @@ export default class NoteStatus extends Plugin {
|
|||
getCurrentStatuses(): string[] {
|
||||
try {
|
||||
const activeFile = this.app.workspace.getActiveFile();
|
||||
if (!activeFile || activeFile.extension !== 'md') {
|
||||
if (!activeFile || !(activeFile instanceof TFile) || activeFile.extension !== 'md') {
|
||||
return ['unknown'];
|
||||
}
|
||||
return this.statusService.getFileStatuses(activeFile);
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ export class StatusService {
|
|||
*/
|
||||
public async updateNoteStatuses(newStatuses: string[], file?: TFile): Promise<void> {
|
||||
const targetFile = file || this.app.workspace.getActiveFile();
|
||||
if (!targetFile || targetFile.extension !== 'md') return;
|
||||
if (!targetFile || !(targetFile instanceof TFile) || targetFile.extension !== 'md') return;
|
||||
|
||||
// Use processFrontMatter instead of manual read/modify
|
||||
await this.app.fileManager.processFrontMatter(targetFile, (frontmatter) => {
|
||||
|
|
@ -261,7 +261,7 @@ export class StatusService {
|
|||
*/
|
||||
public async addNoteStatus(statusToAdd: string, file?: TFile): Promise<void> {
|
||||
const targetFile = file || this.app.workspace.getActiveFile();
|
||||
if (!targetFile || targetFile.extension !== 'md') return;
|
||||
if (!targetFile || !(targetFile instanceof TFile) || targetFile.extension !== 'md') return;
|
||||
|
||||
const currentStatuses = this.getFileStatuses(targetFile);
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ export class StatusService {
|
|||
*/
|
||||
public async removeNoteStatus(statusToRemove: string, file?: TFile): Promise<void> {
|
||||
const targetFile = file || this.app.workspace.getActiveFile();
|
||||
if (!targetFile || targetFile.extension !== 'md') return;
|
||||
if (!targetFile || !(targetFile instanceof TFile) || targetFile.extension !== 'md') return;
|
||||
|
||||
const currentStatuses = this.getFileStatuses(targetFile);
|
||||
const newStatuses = currentStatuses.filter(status => status !== statusToRemove);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { TFile, WorkspaceLeaf, View, Menu, Notice, setIcon } from 'obsidian';
|
||||
import { NoteStatusSettings } from '../../models/types';
|
||||
import { StatusService } from '../../services/status-service';
|
||||
import { ICONS } from '../../constants/icons';
|
||||
import NoteStatus from 'main';
|
||||
|
||||
/**
|
||||
|
|
@ -159,96 +158,96 @@ export class StatusPaneView extends View {
|
|||
private renderStatusGroup(container: HTMLElement, status: string, files: TFile[]): void {
|
||||
const groupEl = container.createDiv({ cls: 'status-group nav-folder' });
|
||||
const titleEl = groupEl.createDiv({ cls: 'nav-folder-title' });
|
||||
|
||||
|
||||
// Create a container for the collapse button and title
|
||||
const collapseContainer = titleEl.createDiv({ cls: 'collapse-indicator' });
|
||||
setIcon(collapseContainer, 'chevron-down');
|
||||
|
||||
|
||||
// Create a container for the title content
|
||||
const titleContentContainer = titleEl.createDiv({ cls: 'nav-folder-title-content' });
|
||||
|
||||
|
||||
const statusIcon = this.statusService.getStatusIcon(status);
|
||||
titleContentContainer.createSpan({
|
||||
text: `${status} ${statusIcon} (${files.length})`,
|
||||
cls: `status-${status}`
|
||||
text: `${status} ${statusIcon} (${files.length})`,
|
||||
cls: `status-${status}`
|
||||
});
|
||||
|
||||
|
||||
// Handle collapsing/expanding behavior
|
||||
titleEl.style.cursor = 'pointer';
|
||||
const isCollapsed = this.settings.collapsedStatuses[status] ?? false;
|
||||
|
||||
|
||||
if (isCollapsed) {
|
||||
groupEl.addClass('is-collapsed');
|
||||
collapseContainer.empty();
|
||||
setIcon(collapseContainer, 'chevron-right');
|
||||
}
|
||||
|
||||
titleEl.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
const isCurrentlyCollapsed = groupEl.hasClass('is-collapsed');
|
||||
|
||||
// Toggle the collapsed state
|
||||
if (isCurrentlyCollapsed) {
|
||||
groupEl.removeClass('is-collapsed');
|
||||
collapseContainer.empty();
|
||||
setIcon(collapseContainer, 'chevron-down');
|
||||
} else {
|
||||
groupEl.addClass('is-collapsed');
|
||||
collapseContainer.empty();
|
||||
setIcon(collapseContainer, 'chevron-right');
|
||||
}
|
||||
|
||||
// Update the settings
|
||||
this.settings.collapsedStatuses[status] = !isCurrentlyCollapsed;
|
||||
|
||||
// Trigger settings save
|
||||
window.dispatchEvent(new CustomEvent('note-status:settings-changed'));
|
||||
}
|
||||
|
||||
titleEl.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
const isCurrentlyCollapsed = groupEl.hasClass('is-collapsed');
|
||||
|
||||
// Toggle the collapsed state
|
||||
if (isCurrentlyCollapsed) {
|
||||
groupEl.removeClass('is-collapsed');
|
||||
collapseContainer.empty();
|
||||
setIcon(collapseContainer, 'chevron-down');
|
||||
} else {
|
||||
groupEl.addClass('is-collapsed');
|
||||
collapseContainer.empty();
|
||||
setIcon(collapseContainer, 'chevron-right');
|
||||
}
|
||||
|
||||
// Update the settings
|
||||
this.settings.collapsedStatuses[status] = !isCurrentlyCollapsed;
|
||||
|
||||
// Trigger settings save
|
||||
window.dispatchEvent(new CustomEvent('note-status:settings-changed'));
|
||||
});
|
||||
|
||||
|
||||
// Create and populate child elements
|
||||
const childrenEl = groupEl.createDiv({ cls: 'nav-folder-children' });
|
||||
|
||||
|
||||
// Sort files by name
|
||||
files.sort((a, b) => a.basename.localeCompare(b.basename));
|
||||
|
||||
|
||||
// Create file list items
|
||||
files.forEach(file => {
|
||||
this.createFileListItem(childrenEl, file, status);
|
||||
this.createFileListItem(childrenEl, file, status);
|
||||
});
|
||||
}
|
||||
|
||||
private createFileListItem(container: HTMLElement, file: TFile, status: string): void {
|
||||
const fileEl = container.createDiv({ cls: 'nav-file' });
|
||||
const fileTitleEl = fileEl.createDiv({ cls: 'nav-file-title' });
|
||||
|
||||
|
||||
// Add file icon if in standard view
|
||||
if (!this.settings.compactView) {
|
||||
const fileIcon = fileTitleEl.createDiv({ cls: 'nav-file-icon' });
|
||||
setIcon(fileIcon, 'file');
|
||||
const fileIcon = fileTitleEl.createDiv({ cls: 'nav-file-icon' });
|
||||
setIcon(fileIcon, 'file');
|
||||
}
|
||||
|
||||
|
||||
// Add file name
|
||||
fileTitleEl.createSpan({
|
||||
text: file.basename,
|
||||
cls: 'nav-file-title-content'
|
||||
text: file.basename,
|
||||
cls: 'nav-file-title-content'
|
||||
});
|
||||
|
||||
|
||||
// Add status indicator
|
||||
fileTitleEl.createSpan({
|
||||
cls: `note-status-icon nav-file-tag status-${status}`,
|
||||
text: this.statusService.getStatusIcon(status)
|
||||
cls: `note-status-icon nav-file-tag status-${status}`,
|
||||
text: this.statusService.getStatusIcon(status)
|
||||
});
|
||||
|
||||
|
||||
// Add click handler to open the file
|
||||
fileEl.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.app.workspace.openLinkText(file.path, file.path, true);
|
||||
e.preventDefault();
|
||||
this.app.workspace.openLinkText(file.path, file.path, true);
|
||||
});
|
||||
|
||||
|
||||
// Add context menu
|
||||
fileEl.addEventListener('contextmenu', (e) => {
|
||||
e.preventDefault();
|
||||
this.showFileContextMenu(e, file);
|
||||
e.preventDefault();
|
||||
this.showFileContextMenu(e, file);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -329,20 +329,20 @@ export class ExplorerIntegration {
|
|||
public getSelectedFiles(): TFile[] {
|
||||
const fileExplorer = this.app.workspace.getLeavesOfType('file-explorer')[0];
|
||||
if (!fileExplorer || !fileExplorer.view) return [];
|
||||
|
||||
|
||||
const fileExplorerView = fileExplorer.view as FileExplorerView;
|
||||
if (!fileExplorerView.fileItems) return [];
|
||||
|
||||
|
||||
const selectedFiles: TFile[] = [];
|
||||
|
||||
Object.entries(fileExplorerView.fileItems).forEach(([_, item]) => {
|
||||
if (item.el?.classList.contains('is-selected') &&
|
||||
item.file instanceof TFile &&
|
||||
item.file.extension === 'md') {
|
||||
item.file && item.file instanceof TFile &&
|
||||
item.file.extension === 'md') {
|
||||
selectedFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return selectedFiles;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ export class StatusContextMenu {
|
|||
public showForFiles(files: TFile[], position?: { x: number; y: number }): void {
|
||||
if (files.length === 0) return;
|
||||
|
||||
// Para un solo archivo, mostrar dropdown directamente
|
||||
// For a single file, show dropdown directly
|
||||
if (files.length === 1) {
|
||||
this.showSingleFileDropdown(files[0], position);
|
||||
return;
|
||||
}
|
||||
|
||||
// Para múltiples archivos, mostrar menú primero
|
||||
// For multiple files, show menu first
|
||||
this.showMultipleFilesMenu(files, position);
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +116,11 @@ export class StatusContextMenu {
|
|||
* Shows a context menu for a single file
|
||||
*/
|
||||
public showForFile(file: TFile, event: MouseEvent): void {
|
||||
// Ensure file is a valid TFile instance before proceeding
|
||||
if (!(file instanceof TFile) || file.extension !== 'md') {
|
||||
return;
|
||||
}
|
||||
|
||||
const position = { x: event.clientX, y: event.clientY };
|
||||
|
||||
this.statusDropdown.openStatusDropdown({
|
||||
|
|
@ -133,7 +138,8 @@ export class StatusContextMenu {
|
|||
* Handle status update for a specific file
|
||||
*/
|
||||
private async handleStatusUpdateForFile(file: TFile, statuses: string[]): Promise<void> {
|
||||
if (statuses.length === 0) return;
|
||||
// Add instanceof check for safety
|
||||
if (!(file instanceof TFile) || file.extension !== 'md' || statuses.length === 0) return;
|
||||
|
||||
// Update the file with the selected status
|
||||
if (this.settings.useMultipleStatuses) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue