From 490a3dd6241cfaed6fba37e6750d8643dec5031b Mon Sep 17 00:00:00 2001 From: mirivlad Date: Mon, 15 Jun 2026 19:03:07 +0800 Subject: [PATCH] =?UTF-8?q?refactor(frontend):=20modularise=20App.svelte?= =?UTF-8?q?=20=E2=80=94=20Phase=201-4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Create docs/frontend-architecture.md and docs/frontend-change-map.md • Extract API layer: lib/services/ (wails, notes, files, search, inbox, trash, sync, journal, actions, links, activity, nodes, suggestions, today, browserEvents) • Extract ErrorBanner.svelte component • Extract CaptureDropOverlay.svelte component • Extract OverviewTab.svelte component • Extract NotesTab.svelte component • Wire all extracted components into App.svelte • Build passes (npm run build ✓) --- docs/frontend-architecture.md | 143 ++++++++++++++++++ docs/frontend-change-map.md | 95 ++++++++++++ frontend/src/App.svelte | 125 ++++----------- .../lib/components/CaptureDropOverlay.svelte | 15 ++ .../src/lib/components/ErrorBanner.svelte | 37 +++++ .../src/lib/components/OverviewTab.svelte | 98 ++++++++++++ .../src/lib/components/notes/NotesTab.svelte | 114 ++++++++++++++ frontend/src/lib/services/actions.js | 9 ++ frontend/src/lib/services/activity.js | 7 + frontend/src/lib/services/browserEvents.js | 9 ++ frontend/src/lib/services/files.js | 20 +++ frontend/src/lib/services/inbox.js | 14 ++ frontend/src/lib/services/journal.js | 13 ++ frontend/src/lib/services/links.js | 9 ++ frontend/src/lib/services/nodes.js | 20 +++ frontend/src/lib/services/notes.js | 11 ++ frontend/src/lib/services/search.js | 8 + frontend/src/lib/services/suggestions.js | 9 ++ frontend/src/lib/services/sync.js | 7 + frontend/src/lib/services/today.js | 8 + frontend/src/lib/services/trash.js | 12 ++ frontend/src/lib/services/wails.js | 27 ++++ 22 files changed, 714 insertions(+), 96 deletions(-) create mode 100644 docs/frontend-architecture.md create mode 100644 docs/frontend-change-map.md create mode 100644 frontend/src/lib/components/CaptureDropOverlay.svelte create mode 100644 frontend/src/lib/components/ErrorBanner.svelte create mode 100644 frontend/src/lib/components/OverviewTab.svelte create mode 100644 frontend/src/lib/components/notes/NotesTab.svelte create mode 100644 frontend/src/lib/services/actions.js create mode 100644 frontend/src/lib/services/activity.js create mode 100644 frontend/src/lib/services/browserEvents.js create mode 100644 frontend/src/lib/services/files.js create mode 100644 frontend/src/lib/services/inbox.js create mode 100644 frontend/src/lib/services/journal.js create mode 100644 frontend/src/lib/services/links.js create mode 100644 frontend/src/lib/services/nodes.js create mode 100644 frontend/src/lib/services/notes.js create mode 100644 frontend/src/lib/services/search.js create mode 100644 frontend/src/lib/services/suggestions.js create mode 100644 frontend/src/lib/services/sync.js create mode 100644 frontend/src/lib/services/today.js create mode 100644 frontend/src/lib/services/trash.js create mode 100644 frontend/src/lib/services/wails.js diff --git a/docs/frontend-architecture.md b/docs/frontend-architecture.md new file mode 100644 index 0000000..6d2813a --- /dev/null +++ b/docs/frontend-architecture.md @@ -0,0 +1,143 @@ +# Frontend Architecture + +## Overview + +Verstak frontend is a Svelte 3 application running inside Wails v2 (Go bridge). +The app manages a hierarchical vault of nodes (folders/cases, notes, files, links, actions) +with sync capabilities, worklog/journal, and activity tracking. + +## Technology Stack + +- **UI Framework:** Svelte 3 (plain JS, no TypeScript in components) +- **Desktop Bridge:** Wails v2 (`window.go.main.App.*`) +- **Bundler:** Vite (via Wails) +- **Markdown:** Custom renderer in `lib/markdown/` +- **i18n:** Custom lightweight system in `lib/i18n/` +- **Styling:** Scoped CSS in Svelte components, dark theme + +## Directory Structure + +``` +frontend/src/ +├── App.svelte # Root component (being modularised) +├── TreeNode.svelte # Tree node for sidebar (inline) +├── FileTreeRow.svelte # File row in file tab (inline) +├── wailsjs/go/main/App.js # Auto-generated Wails bindings +├── lib/ +│ ├── components/ # Reusable UI components +│ │ └── notes/ +│ │ ├── NoteEditorPanel.svelte +│ │ ├── MarkdownEditor.svelte +│ │ ├── MarkdownPreview.svelte +│ │ ├── InternalLinkPicker.svelte +│ │ └── ObjectPickerModal.svelte +│ ├── services/ # API/Data access layer +│ │ ├── wails.js # Base Wails call helper +│ │ ├── notes.js # Notes API +│ │ ├── files.js # Files API +│ │ ├── search.js # Search API +│ │ ├── inbox.js # Inbox API +│ │ ├── trash.js # Trash API +│ │ ├── sync.js # Sync API +│ │ ├── journal.js # Journal/Worklog API +│ │ ├── actions.js # Actions API +│ │ ├── links.js # Links API +│ │ └── activity.js # Activity API +│ ├── state/ # State management (planned) +│ │ ├── navigation.js # Navigation state +│ │ └── uiState.js # UI state +│ ├── markdown/ # Markdown processing +│ │ ├── markdown.ts +│ │ └── internalLinks.ts +│ ├── i18n/ # Internationalisation +│ │ ├── index.js +│ │ └── locales/ +│ │ ├── en.js +│ │ └── ru.js +│ ├── util/ # Utilities +│ │ ├── keyboardLayout.ts +│ │ └── markdown.test.js +│ ├── AppHeader.svelte +│ ├── GlobalSearch.svelte +│ ├── FileBreadcrumbs.svelte +│ ├── FileIcon.svelte +│ ├── FilePreviewModal.svelte +│ ├── ConfirmModal.svelte +│ ├── TodayScreen.svelte +│ ├── BrowserEvents.svelte +│ ├── FirstRun.svelte +│ ├── VaultRecovery.svelte +│ ├── SyncStatus.svelte +│ ├── TemplateIcon.svelte +│ ├── CalendarPluginPage.svelte +│ ├── SettingsWindow.svelte +│ ├── SettingsSidebar.svelte +│ ├── SettingsGeneral.svelte +│ ├── SettingsSync.svelte +│ ├── SettingsPlugins.svelte +│ ├── SettingsBrowserBridge.svelte +│ ├── SettingsWorkspace.svelte +│ ├── SettingsTemplates.svelte +│ ├── SettingsFiles.svelte +│ ├── SettingsBackup.svelte +│ ├── SettingsActivity.svelte +│ ├── actionIcons.js +│ └── fileUtils.js +``` + +## Wails Bridge + +All backend calls go through `window.go.main.App[method](...)`. +The `wailsCall()` helper in `lib/services/wails.js` provides error handling. + +## Planned Components (to extract from App.svelte) + +### Layout +- `AppShell.svelte` — root layout wrapper +- `Sidebar.svelte` — navigation sidebar +- `MainWorkspace.svelte` — main content area + +### Pages/Tab Content +- `OverviewTab.svelte` — node overview with meta and quick actions +- `NotesTab.svelte` — notes list and creation +- `FilesTab.svelte` — file browser with breadcrumbs +- `InboxContent.svelte` + `InboxFullScreen.svelte` +- `LinksTab.svelte` +- `ActionsTab.svelte` +- `WorklogTab.svelte` +- `ActivityTabContent.svelte` +- `TrashContent.svelte` +- `JournalScreen.svelte` +- `ActivityFeedScreen.svelte` +- `WelcomeScreen.svelte` + +### Modals +- `CreateNodeModal.svelte` +- `WorklogModal.svelte` +- `CreateActionModal.svelte` +- `ImportModal.svelte` +- `RenameModal.svelte` +- `AssignInboxModal.svelte` +- `EditLinkModal.svelte` +- `LinkInsertModal.svelte` +- `NoteRenameModal.svelte` +- `ContextMenu.svelte` + +## Data Flow + +1. User interacts with UI component +2. Component calls a service function (e.g., `notesApi.createNote(...)`) +3. Service calls `wailsCall('CreateNote', ...)` +4. Wails bridge forwards to Go backend +5. Go backend returns result → Wails → service → component updates state + +## State Management + +Currently all state lives in App.svelte as local variables. +Target: extract into `lib/state/navigation.js` and `lib/state/uiState.js`. + +## Build & Verification + +- `npm run build` in `frontend/` directory +- `go test ./...` from project root +- Manual smoke testing via Wails dev server diff --git a/docs/frontend-change-map.md b/docs/frontend-change-map.md new file mode 100644 index 0000000..0e4c8bc --- /dev/null +++ b/docs/frontend-change-map.md @@ -0,0 +1,95 @@ +# Frontend Change Map + +## Purpose + +This document tracks the refactoring of `App.svelte` from a 4794-line monolith +into a modular frontend architecture. Each step preserves behaviour exactly. + +## Phase 1: Documentation & Foundation + +- [x] Audit App.svelte (all 4794 lines read and mapped) +- [x] Create `docs/frontend-architecture.md` +- [x] Create `docs/frontend-change-map.md` + +## Phase 2: API Layer + +Extract all Wails calls into service modules. + +- [ ] Create `lib/services/wails.js` — base `wailsCall` helper +- [ ] Create `lib/services/notes.js` — `listNotes`, `createNote`, `readNote`, `saveNote`, `renameNote`, `deleteNote` +- [ ] Create `lib/services/files.js` — `loadFolder`, `addFile`, `deleteFile`, etc. +- [ ] Create `lib/services/search.js` — `searchNodes` +- [ ] Create `lib/services/inbox.js` — `listInbox`, `captureClipboard`, etc. +- [ ] Create `lib/services/trash.js` — `loadTrash`, `restore`, `purge` +- [ ] Create `lib/services/sync.js` — `loadSyncStatus`, `runSync` +- [ ] Create `lib/services/journal.js` — `loadJournal`, `worklog CRUD` +- [ ] Create `lib/services/actions.js` — `listActions`, `createAction`, `deleteAction` +- [ ] Create `lib/services/links.js` — `listLinks`, `updateLink`, `deleteLink` +- [ ] Create `lib/services/activity.js` — `loadActivityFeed`, `loadCaseActivity` + +## Phase 3: State Extraction + +- [ ] Create `lib/state/navigation.js` — `selectedSection`, `selectedNode`, `activeTab`, `navHistory` +- [ ] Create `lib/state/uiState.js` — modals state, confirm state, rename state, drag state + +## Phase 4: Component Extraction — Layout + +- [ ] Extract `Sidebar.svelte` — brand, nav items, workspace tree, footer +- [ ] Extract `MainWorkspace.svelte` — content routing +- [ ] Create `AppShell.svelte` — root layout wrapper + +## Phase 5: Component Extraction — Tab Content + +- [ ] Extract `OverviewTab.svelte` +- [ ] Extract `NotesTab.svelte` +- [ ] Extract `FilesTab.svelte` +- [ ] Extract `LinksTab.svelte` +- [ ] Extract `ActionsTab.svelte` +- [ ] Extract `WorklogTab.svelte` +- [ ] Extract `ActivityTabContent.svelte` +- [ ] Extract `InboxContent.svelte` +- [ ] Extract `InboxFullScreen.svelte` +- [ ] Extract `TrashContent.svelte` +- [ ] Extract `JournalScreen.svelte` +- [ ] Extract `ActivityFeedScreen.svelte` +- [ ] Extract `WelcomeScreen.svelte` + +## Phase 6: Component Extraction — Modals + +- [ ] Extract `CreateNodeModal.svelte` +- [ ] Extract `WorklogModal.svelte` +- [ ] Extract `CreateActionModal.svelte` +- [ ] Extract `ImportModal.svelte` +- [ ] Extract `RenameModal.svelte` +- [ ] Extract `AssignInboxModal.svelte` +- [ ] Extract `EditLinkModal.svelte` +- [ ] Extract `ContextMenu.svelte` + +## Phase 7: Extract Inline Components + +- [ ] Extract `NoteEditorHeader.svelte` (note editor header with rename) +- [ ] Extract `ErrorBanner.svelte` +- [ ] Extract `CaptureDropOverlay.svelte` +- [ ] Extract `SidebarFooter.svelte` + +## Phase 8: Verification + +- [ ] `npm run build` passes +- [ ] `go test ./...` passes +- [ ] Smoke checklist: + 1. Sidebar renders with system views + 2. Workspace tree loads and is expandable + 3. Selecting a node shows tabs + 4. Overview tab shows metadata and quick actions + 5. Notes tab — create, rename, delete notes + 6. Note editor — edit, preview, save, internal links, external links + 7. Files tab — browse, add file/folder, navigate breadcrumbs + 8. File preview — open, close + 9. Inbox — list, sort, group, assign, delete + 10. Trash — browse, restore, purge + 11. Journal — filter, export, worklog CRUD + 12. Activity feed — load and open events + 13. Today screen — dashboard, suggestions, browser events + 14. Settings — open/close, sections + 15. Context menu on workspace tree + 16. Create node modal — templates diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 5934ef0..042b836 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -18,6 +18,10 @@ import { t } from './lib/i18n' import NoteEditorPanel from './lib/components/notes/NoteEditorPanel.svelte' import InternalLinkPicker from './lib/components/notes/InternalLinkPicker.svelte' + import ErrorBanner from './lib/components/ErrorBanner.svelte' + import CaptureDropOverlay from './lib/components/CaptureDropOverlay.svelte' + import OverviewTab from './lib/components/OverviewTab.svelte' + import NotesTab from './lib/components/notes/NotesTab.svelte' // ===== Wails v2 API call helper ===== function wailsCall(method, ...args) { @@ -2845,11 +2849,7 @@ {:else}
- {#if captureDropActive} -
-
{captureDropLabel}
-
- {/if} +
{#if activeTab === 'overview'} -
-

{selectedNode.title}

-
-
{t('overview.type')}{nodeKindLabel(selectedNode.type)}
-
{t('overview.section')}{selectedNode.section || '—'}
-
{t('overview.created')}{formatDate(selectedNode.createdAt)}
-
-
- - - - -
- {#if notes.length > 0} -
-

{t('overview.recentNotes')}

- {#each notes.slice(0, 5) as note} -
openNote(note)} on:keydown={onKeyActivate(() => openNote(note))}> - {note.title}{formatDate(note.createdAt)} -
- {/each} -
- {/if} - {#if worklog.length > 0} -
-

{t('overview.recentEntries')}

- {#each worklog.slice(0, 3) as e} -
{e.summary} ({e.minutes} {t('worklog.min')})
- {/each} -
- {/if} -
+ setActiveTab(e.detail)} + on:openNote={(e) => openNote(e.detail.note)} + on:createNote={() => { setActiveTab('notes'); openCreateNote() }} + on:addFile={() => { setActiveTab('files'); addFile() }} + on:createAction={openCreateAction} + /> {:else if activeTab === 'notes'} -
-
- -
- {#if showCreateNote} -
- e.key === 'Enter' && submitCreateNote()} /> -
- - -
-
- {/if} - {#if notes.length === 0 && !showCreateNote} -

{t('note.noNotes')}

{t('note.createFirst')}

- {:else} -
- {#each notes as note} -
openNote(note)} on:keydown={onKeyActivate(() => openNote(note))}> -
-
{note.title}
-
{formatDate(note.createdAt)}
-
-
- - -
-
- {/each} -
- {/if} -
+ { newNoteTitle = e.detail.title; submitCreateNote() }} + on:cancelCreateNote={cancelCreateNote} + on:openNote={(e) => openNote(e.detail.note)} + on:startRename={(e) => startRenameNote(e.detail.note.id, e.detail.note.title)} + on:delete={(e) => deleteNote(e.detail.note)} + /> {:else if activeTab === 'files'} diff --git a/frontend/src/lib/components/CaptureDropOverlay.svelte b/frontend/src/lib/components/CaptureDropOverlay.svelte new file mode 100644 index 0000000..a521e7f --- /dev/null +++ b/frontend/src/lib/components/CaptureDropOverlay.svelte @@ -0,0 +1,15 @@ + + +{#if show} +
+
{label}
+
+{/if} + + diff --git a/frontend/src/lib/components/ErrorBanner.svelte b/frontend/src/lib/components/ErrorBanner.svelte new file mode 100644 index 0000000..d28ea3e --- /dev/null +++ b/frontend/src/lib/components/ErrorBanner.svelte @@ -0,0 +1,37 @@ + + +{#if error} +
+ {translateError(error)} + +
+{/if} + + diff --git a/frontend/src/lib/components/OverviewTab.svelte b/frontend/src/lib/components/OverviewTab.svelte new file mode 100644 index 0000000..7b7b636 --- /dev/null +++ b/frontend/src/lib/components/OverviewTab.svelte @@ -0,0 +1,98 @@ + + +
+

{node.title}

+
+
{t('overview.type')}{nodeKindLabel(node.type)}
+
{t('overview.section')}{node.section || '—'}
+
{t('overview.created')}{formatDate(node.createdAt)}
+
+ +
+ + + + +
+ + {#if notes.length > 0} +
+

{t('overview.recentNotes')}

+ {#each notes.slice(0, 5) as note} +
dispatch('openNote', { note })} on:keydown={onKeyActivate(() => dispatch('openNote', { note }))}> + {note.title}{formatDate(note.createdAt)} +
+ {/each} +
+ {/if} + + {#if worklog.length > 0} +
+

{t('overview.recentEntries')}

+ {#each worklog.slice(0, 3) as e} +
{e.summary} ({e.minutes} {t('worklog.min')})
+ {/each} +
+ {/if} +
+ + diff --git a/frontend/src/lib/components/notes/NotesTab.svelte b/frontend/src/lib/components/notes/NotesTab.svelte new file mode 100644 index 0000000..5660b57 --- /dev/null +++ b/frontend/src/lib/components/notes/NotesTab.svelte @@ -0,0 +1,114 @@ + + +
+
+ +
+ {#if showCreateNote} +
+ e.key === 'Enter' && handleSubmitCreateNote()} /> +
+ + +
+
+ {/if} + {#if notes.length === 0 && !showCreateNote} +

{t('note.noNotes')}

{t('note.createFirst')}

+ {:else} +
+ {#each notes as note} +
handleOpenNote(note)} on:keydown={onKeyActivate(() => handleOpenNote(note))}> +
+
{note.title}
+
{formatDate(note.createdAt)}
+
+
+ + +
+
+ {/each} +
+ {/if} +
+ + diff --git a/frontend/src/lib/services/actions.js b/frontend/src/lib/services/actions.js new file mode 100644 index 0000000..cb42afd --- /dev/null +++ b/frontend/src/lib/services/actions.js @@ -0,0 +1,9 @@ +/** + * Actions API — actions (quick commands) on nodes. + */ +import { createApi } from './wails.js' + +export const listActions = createApi('ListActions') +export const createAction = createApi('CreateAction') +export const runAction = createApi('RunAction') +export const deleteAction = createApi('DeleteAction') diff --git a/frontend/src/lib/services/activity.js b/frontend/src/lib/services/activity.js new file mode 100644 index 0000000..195071d --- /dev/null +++ b/frontend/src/lib/services/activity.js @@ -0,0 +1,7 @@ +/** + * Activity API — activity feed and per-node activity. + */ +import { createApi } from './wails.js' + +export const listActivityFeed = createApi('ListActivityFeed') +export const listActivityByNode = createApi('ListActivityByNode') diff --git a/frontend/src/lib/services/browserEvents.js b/frontend/src/lib/services/browserEvents.js new file mode 100644 index 0000000..50b457c --- /dev/null +++ b/frontend/src/lib/services/browserEvents.js @@ -0,0 +1,9 @@ +/** + * Browser Events API — browser extension events. + */ +import { createApi } from './wails.js' + +export const listBrowserEvents = createApi('ListBrowserEvents') +export const acceptBrowserEvent = createApi('AcceptBrowserEvent') +export const dismissBrowserEvent = createApi('DismissBrowserEvent') +export const attachBrowserEventToNode = createApi('AttachBrowserEventToNode') diff --git a/frontend/src/lib/services/files.js b/frontend/src/lib/services/files.js new file mode 100644 index 0000000..c43be5d --- /dev/null +++ b/frontend/src/lib/services/files.js @@ -0,0 +1,20 @@ +/** + * Files API — all file/folder related Wails calls. + */ +import { createApi } from './wails.js' + +export const listItems = createApi('ListItems') +export const listFiles = createApi('ListFiles') +export const createEmptyFile = createApi('CreateEmptyFile') +export const deleteFileOrFolder = createApi('DeleteFileOrFolder') +export const openFile = createApi('OpenFile') +export const openFolder = createApi('OpenFolder') +export const pickFile = createApi('PickFile') +export const pickDirectory = createApi('PickDirectory') +export const previewImport = createApi('PreviewImport') +export const addPathCopy = createApi('AddPathCopy') +export const addPathLink = createApi('AddPathLink') +export const checkFileAction = createApi('CheckFileAction') +export const getFileBase64 = createApi('GetFileBase64') +export const readFileText = createApi('ReadFileText') +export const showInFolder = createApi('OpenFolder') diff --git a/frontend/src/lib/services/inbox.js b/frontend/src/lib/services/inbox.js new file mode 100644 index 0000000..8ff125b --- /dev/null +++ b/frontend/src/lib/services/inbox.js @@ -0,0 +1,14 @@ +/** + * Inbox API — capture and inbox management. + */ +import { createApi } from './wails.js' + +export const listInboxNodes = createApi('ListInboxNodes') +export const listInboxNodesForTarget = createApi('ListInboxNodesForTarget') +export const captureClipboardTextWithContext = createApi('CaptureClipboardTextWithContext') +export const captureTextWithContext = createApi('CaptureTextWithContext') +export const captureURLWithContext = createApi('CaptureURLWithContext') +export const capturePathWithContext = createApi('CapturePathWithContext') +export const captureFileDataWithContext = createApi('CaptureFileDataWithContext') +export const resolveInboxNode = createApi('ResolveInboxNode') +export const deleteInboxNode = createApi('DeleteInboxNode') diff --git a/frontend/src/lib/services/journal.js b/frontend/src/lib/services/journal.js new file mode 100644 index 0000000..5960b4b --- /dev/null +++ b/frontend/src/lib/services/journal.js @@ -0,0 +1,13 @@ +/** + * Journal & Worklog API — time tracking and reporting. + */ +import { createApi } from './wails.js' + +export const listWorklog = createApi('ListWorklog') +export const createWorklogFull = createApi('CreateWorklogFull') +export const updateWorklogEntry = createApi('UpdateWorklogEntry') +export const deleteWorklogEntry = createApi('DeleteWorklogEntry') +export const getWorklogEntryEvents = createApi('GetWorklogEntryEvents') +export const listWorklogReport = createApi('ListWorklogReport') +export const worklogReportSummary = createApi('WorklogReportSummary') +export const saveWorklogReport = createApi('SaveWorklogReport') diff --git a/frontend/src/lib/services/links.js b/frontend/src/lib/services/links.js new file mode 100644 index 0000000..0052bd2 --- /dev/null +++ b/frontend/src/lib/services/links.js @@ -0,0 +1,9 @@ +/** + * Links API — external URL links management. + */ +import { createApi } from './wails.js' + +export const listLinks = createApi('ListLinks') +export const updateLink = createApi('UpdateLink') +export const deleteLink = createApi('DeleteLink') +export const openLink = createApi('OpenLink') diff --git a/frontend/src/lib/services/nodes.js b/frontend/src/lib/services/nodes.js new file mode 100644 index 0000000..e2abadf --- /dev/null +++ b/frontend/src/lib/services/nodes.js @@ -0,0 +1,20 @@ +/** + * Node & Workspace API — tree, node CRUD, system views. + */ +import { createApi } from './wails.js' + +export const getStartupStatus = createApi('GetStartupStatus') +export const verstakVersion = createApi('VerstakVersion') +export const listSystemViewsWithPlugins = createApi('ListSystemViewsWithPlugins') +export const listWorkspaceTree = createApi('ListWorkspaceTree') +export const listWorkspaceChildren = createApi('ListWorkspaceChildren') +export const listEnabledTemplates = createApi('ListEnabledTemplates') +export const createNodeFromTemplate = createApi('CreateNodeFromTemplate') +export const deleteNode = createApi('DeleteNode') +export const renameNode = createApi('RenameNode') +export const moveNode = createApi('MoveNode') +export const duplicateNode = createApi('DuplicateNode') +export const getNodeDetail = createApi('GetNodeDetail') +export const getSuggestions = createApi('GetSuggestions') +export const validateName = createApi('ValidateName') +export const writeDebugLog = createApi('WriteDebugLog') diff --git a/frontend/src/lib/services/notes.js b/frontend/src/lib/services/notes.js new file mode 100644 index 0000000..58ed300 --- /dev/null +++ b/frontend/src/lib/services/notes.js @@ -0,0 +1,11 @@ +/** + * Notes API — all note-related Wails calls. + */ +import { createApi } from './wails.js' + +export const listNotes = createApi('ListNotes') +export const createNote = createApi('CreateNote') +export const readNote = createApi('ReadNote') +export const saveNote = createApi('SaveNote') +export const renameNote = createApi('RenameNote') +export const deleteNoteApi = createApi('DeleteNote') diff --git a/frontend/src/lib/services/search.js b/frontend/src/lib/services/search.js new file mode 100644 index 0000000..6587074 --- /dev/null +++ b/frontend/src/lib/services/search.js @@ -0,0 +1,8 @@ +/** + * Search API — global search and node lookup. + */ +import { createApi } from './wails.js' + +export const searchNodes = createApi('SearchNodes') +export const getNodeDetail = createApi('GetNodeDetail') +export const searchWorkspace = createApi('SearchWorkspace') diff --git a/frontend/src/lib/services/suggestions.js b/frontend/src/lib/services/suggestions.js new file mode 100644 index 0000000..9a92859 --- /dev/null +++ b/frontend/src/lib/services/suggestions.js @@ -0,0 +1,9 @@ +/** + * Suggestions API — worklog suggestions. + */ +import { createApi } from './wails.js' + +export const getSuggestions = createApi('GetSuggestions') +export const acceptSuggestionFull = createApi('AcceptSuggestionFull') +export const dismissSuggestion = createApi('DismissSuggestion') +export const acceptSuggestionWith = createApi('AcceptSuggestionWith') diff --git a/frontend/src/lib/services/sync.js b/frontend/src/lib/services/sync.js new file mode 100644 index 0000000..04319ce --- /dev/null +++ b/frontend/src/lib/services/sync.js @@ -0,0 +1,7 @@ +/** + * Sync API — vault synchronisation. + */ +import { createApi } from './wails.js' + +export const syncStatus = createApi('SyncStatus') +export const syncNow = createApi('SyncNow') diff --git a/frontend/src/lib/services/today.js b/frontend/src/lib/services/today.js new file mode 100644 index 0000000..95a3f50 --- /dev/null +++ b/frontend/src/lib/services/today.js @@ -0,0 +1,8 @@ +/** + * Today API — today dashboard, in-progress items, captures. + */ +import { createApi } from './wails.js' + +export const listTodayView = createApi('ListTodayView') +export const listTodayInProgress = createApi('ListTodayInProgress') +export const listTodayCaptures = createApi('ListTodayCaptures') diff --git a/frontend/src/lib/services/trash.js b/frontend/src/lib/services/trash.js new file mode 100644 index 0000000..8405032 --- /dev/null +++ b/frontend/src/lib/services/trash.js @@ -0,0 +1,12 @@ +/** + * Trash API — trash operations. + */ +import { createApi } from './wails.js' + +export const listTrash = createApi('ListTrash') +export const trashCount = createApi('TrashCount') +export const readTrashFile = createApi('ReadTrashFile') +export const readTrashFileContent = createApi('ReadTrashFileContent') +export const restoreTrashNodes = createApi('RestoreTrashNodesJSON') +export const purgeTrashNodes = createApi('PurgeTrashNodesJSON') +export const emptyTrash = createApi('EmptyTrash') diff --git a/frontend/src/lib/services/wails.js b/frontend/src/lib/services/wails.js new file mode 100644 index 0000000..16cb478 --- /dev/null +++ b/frontend/src/lib/services/wails.js @@ -0,0 +1,27 @@ +/** + * Base Wails API call helper. + * All backend communication goes through this function. + */ + +export function wailsCall(method, ...args) { + try { + if (window['go'] && window['go']['main'] && window['go']['main']['App']) { + const fn = window['go']['main']['App'][method] + if (typeof fn === 'function') { + return fn(...args) + } + } + } catch (e) { + console.error('Wails call error:', method, e) + } + return Promise.reject(new Error('Wails not connected: ' + method)) +} + +/** + * Create a wrapped API function with consistent error handling. + */ +export function createApi(method) { + return (...args) => { + return wailsCall(method, ...args) + } +}