Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions e2e/folder-panel.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,50 @@ test('folder panel supports view modes navigation and refresh', async ({ createW
await expect(mainWindow.locator('.file-preview-text')).toContainText('after refresh')
})

test('folder panel aggregates markdown tasks recursively', async ({ createWorkspace, mainWindow }) => {
const workspace = await createWorkspace({
name: 'folder-panel-tasks',
seed: {
directories: ['work/nested', 'work/dist'],
files: {
'work/plan.md': ['# Plan', '', '- [x] Root done', '- [ ] Root todo', ''].join('\n'),
'work/nested/roadmap.md': [
'# Roadmap',
'',
'## Phase 1',
'',
'- [ ] Nested todo',
'- [x] Nested done',
'',
].join('\n'),
'work/dist/ignored.md': ['# Build output', '', '- [ ] Ignored todo', ''].join('\n'),
},
},
})

await setProjectRoot(mainWindow, workspace.rootDir)
await openFileExplorer(mainWindow)

await fileExplorerItem(mainWindow, 'work').dblclick()
await folderViewButton(mainWindow, 'Tasks').click()

await expect(mainWindow.locator('.file-tasks__summary')).toContainText('2 done')
await expect(mainWindow.locator('.file-tasks__summary')).toContainText('2 remaining')
await expect(mainWindow.locator('.file-tasks__summary')).toContainText('2 files')
await expect(mainWindow.locator('.folder-tasks__file-header').filter({ hasText: 'plan.md' })).toContainText('.')
await expect(mainWindow.locator('.folder-tasks__file-header').filter({ hasText: 'roadmap.md' })).toContainText('nested')
await expect(mainWindow.locator('.folder-tasks')).not.toContainText('Ignored todo')

await workspace.writeText('work/nested/fresh.md', ['# Fresh', '', '- [ ] Watched nested task', ''].join('\n'))
await expect(mainWindow.locator('.file-tasks__summary')).toContainText('3 remaining')
await expect(mainWindow.locator('.folder-tasks__file-header').filter({ hasText: 'fresh.md' })).toBeVisible()

await mainWindow.locator('.folder-tasks__file-header').filter({ hasText: 'roadmap.md' }).dblclick()
await expect(mainWindow.locator('.file-mode-switcher__button--active')).toHaveText('Tasks')
await expect(mainWindow.locator('.file-tasks__summary')).toContainText('1 done')
await expect(mainWindow.locator('.file-tasks__summary')).toContainText('1 remaining')
})

test('folder panel context menu mirrors file operations', async ({ createWorkspace, mainWindow }) => {
const workspace = await createWorkspace({
name: 'folder-panel-ops',
Expand Down
1 change: 1 addition & 0 deletions e2e/settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ test('normalizes custom file viewer extension defaults', () => {
{ extension: '.bin', defaultMode: 'hex' },
{ extension: '.bad', defaultMode: 'preview' },
],
folderTaskIgnoredDirectories: defaultTerminalSettings.fileViewer.folderTaskIgnoredDirectories,
refreshIntervalSeconds: 9,
})
})
Expand Down
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@xterm/xterm": "^6.0.0",
"dockview": "^6.6.1",
"framer-motion": "^12.40.0",
"highlight.js": "^11.11.1",
"lucide-react": "^1.17.0",
"markdown-it": "^14.2.0",
"monaco-editor": "^0.55.1",
Expand Down
25 changes: 23 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2483,8 +2483,26 @@ const ProjectWorkspace = forwardRef<
if (existingPanelId) {
const existingPanel = api.getPanel(existingPanelId);
if (existingPanel) {
if (options?.initialMode) {
existingPanel.api.updateParameters({
...existingPanel.params,
initialMode: options.initialMode,
});
}
existingPanel.api.setActive();
syncPanelFocusState();
if (options?.initialMode) {
window.requestAnimationFrame(() => {
window.dispatchEvent(
new CustomEvent('terminay-file-mode-request', {
detail: {
mode: options.initialMode,
path: filePath,
},
}),
);
});
}
return;
}
}
Expand Down Expand Up @@ -4928,12 +4946,15 @@ const ProjectWorkspace = forwardRef<

useEffect(() => {
const onOpenFileEvent = (event: Event) => {
const customEvent = event as CustomEvent<{ path?: string }>;
const customEvent = event as CustomEvent<{
initialMode?: FileViewerMode;
path?: string;
}>;
const filePath = customEvent.detail?.path;
if (!filePath) {
return;
}
void openFile(filePath);
void openFile(filePath, { initialMode: customEvent.detail.initialMode });
};

window.addEventListener('terminay-open-file', onOpenFileEvent);
Expand Down
19 changes: 19 additions & 0 deletions src/components/file-viewer/FilePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,25 @@ export function FilePanel(props: IDockviewPanelProps<FilePanelInstanceParams>) {
}
}, [])

useEffect(() => {
const onModeRequest = (event: Event) => {
const customEvent = event as CustomEvent<{ mode?: FileViewerMode; path?: string }>
if (customEvent.detail?.path !== filePath || !customEvent.detail.mode) {
return
}

hasSelectedModeRef.current = true
hasAppliedDefaultModeRef.current = true
setMode(customEvent.detail.mode)
sessionStoreRef.current?.setMode(customEvent.detail.mode)
}

window.addEventListener('terminay-file-mode-request', onModeRequest)
return () => {
window.removeEventListener('terminay-file-mode-request', onModeRequest)
}
}, [filePath])

const refreshDiff = useCallback(
async (targetPath: string, options?: { keepPrevious?: boolean }) => {
if (!isMountedRef.current) {
Expand Down
Loading
Loading