mulmoclaude 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile.sandbox +100 -0
- package/README.md +17 -4
- package/bin/mulmoclaude.js +46 -15
- package/bin/prepare-dist.js +18 -2
- package/client/assets/chunk-CernVdwh.js +1 -0
- package/client/assets/chunk-D8eiyYIV-C1eAZMzz.js +1 -0
- package/client/assets/html2canvas-CDGcmOD3-BbPeutDg.js +5 -0
- package/client/assets/index-BbgSjFQ8.js +4968 -0
- package/client/assets/index-ECD0lgIv.css +2 -0
- package/client/assets/{index.es-D4YyL_Dg-BgT6a3Nd.js → index.es-DqtpmBm8-DJdTPdnc.js} +5 -5
- package/client/assets/material-symbols-outlined-BLDfUw-_.woff2 +0 -0
- package/client/assets/runtime-protocol-vue-6WYa8hAs.js +1 -0
- package/client/assets/runtime-vue-BVUzgYGA.js +1 -0
- package/client/assets/typeof-DBp4T-Ny-C2xoZtcz.js +1 -0
- package/client/assets/vue-1e_vz2LW.js +1 -0
- package/client/assets/vue.runtime.esm-bundler-DQ8Kjjui.js +4 -0
- package/client/index.html +33 -2
- package/package.json +20 -18
- package/sandbox-entrypoint.sh +106 -0
- package/server/accounting/accountNormalize.ts +32 -0
- package/server/accounting/defaultAccounts.ts +87 -0
- package/server/accounting/eventPublisher.ts +51 -0
- package/server/accounting/journal.ts +252 -0
- package/server/accounting/openingBalances.ts +114 -0
- package/server/accounting/report.ts +237 -0
- package/server/accounting/service.ts +718 -0
- package/server/accounting/snapshotCache.ts +333 -0
- package/server/accounting/timeSeries.ts +265 -0
- package/server/accounting/types.ts +148 -0
- package/server/agent/activeTools.ts +128 -0
- package/server/agent/attachmentConverter.ts +10 -5
- package/server/agent/backend/claude-code.ts +8 -2
- package/server/agent/backend/types.ts +1 -1
- package/server/agent/config.ts +101 -31
- package/server/agent/index.ts +45 -33
- package/server/agent/mcp-server.ts +146 -69
- package/server/agent/mcp-tools/index.ts +1 -5
- package/server/agent/mcp-tools/notify.ts +2 -22
- package/server/agent/mcp-tools/x.ts +0 -4
- package/server/agent/mcpHealth.ts +168 -0
- package/server/agent/plugin-names.ts +20 -77
- package/server/agent/prompt.ts +259 -51
- package/server/agent/resumeFailover.ts +1 -1
- package/server/agent/stream.ts +0 -1
- package/server/api/auth/bearerAuth.ts +5 -5
- package/server/api/csrfGuard.ts +1 -1
- package/server/api/routes/accounting.ts +366 -0
- package/server/api/routes/agent.ts +509 -46
- package/server/api/routes/attachment.ts +104 -0
- package/server/api/routes/chart.ts +2 -1
- package/server/api/routes/config.ts +12 -12
- package/server/api/routes/files.ts +105 -48
- package/server/api/routes/image.ts +70 -25
- package/server/api/routes/journal.ts +35 -0
- package/server/api/routes/mulmo-script.ts +358 -118
- package/server/api/routes/mulmoScriptValidate.ts +1 -1
- package/server/api/routes/news.ts +1 -1
- package/server/api/routes/notifications.ts +92 -22
- package/server/api/routes/notifier.ts +98 -0
- package/server/api/routes/pdf.ts +188 -48
- package/server/api/routes/plugins.ts +34 -14
- package/server/api/routes/presentHtml.ts +58 -3
- package/server/api/routes/roles.ts +1 -8
- package/server/api/routes/runtime-plugin.ts +224 -0
- package/server/api/routes/scheduler.ts +7 -5
- package/server/api/routes/schedulerHandlers.ts +1 -1
- package/server/api/routes/schedulerTasks.ts +8 -7
- package/server/api/routes/sessions.ts +234 -121
- package/server/api/routes/skills.ts +56 -51
- package/server/api/routes/sources.ts +52 -45
- package/server/api/routes/translation.ts +44 -0
- package/server/api/routes/wiki/frontmatter.ts +13 -65
- package/server/api/routes/wiki/history.ts +261 -0
- package/server/api/routes/wiki/pageIndex.ts +1 -1
- package/server/api/routes/wiki.ts +50 -26
- package/server/events/file-change.ts +83 -0
- package/server/events/notifications.ts +247 -91
- package/server/events/pub-sub/index.ts +1 -1
- package/server/events/relay-client.ts +5 -5
- package/server/events/scheduler-adapter.ts +2 -2
- package/server/events/session-store/index.ts +110 -22
- package/server/events/task-manager/index.ts +10 -9
- package/server/index.ts +509 -33
- package/server/notifier/engine.ts +419 -0
- package/server/notifier/legacy-adapters.ts +76 -0
- package/server/notifier/runtime-api.ts +74 -0
- package/server/notifier/store.ts +70 -0
- package/server/notifier/types.ts +121 -0
- package/server/plugins/dev-loader.ts +171 -0
- package/server/plugins/dev-watcher.ts +150 -0
- package/server/plugins/diagnostics.ts +188 -0
- package/server/plugins/preset-list.ts +52 -0
- package/server/plugins/preset-loader.ts +112 -0
- package/server/plugins/runtime-chat-api.ts +38 -0
- package/server/plugins/runtime-loader.ts +430 -0
- package/server/plugins/runtime-registry.ts +112 -0
- package/server/plugins/runtime-tasks-api.ts +50 -0
- package/server/plugins/runtime.ts +378 -0
- package/server/services/translation/cache.ts +72 -0
- package/server/services/translation/index.ts +106 -0
- package/server/services/translation/llm.ts +140 -0
- package/server/services/translation/types.ts +35 -0
- package/server/system/credentials.ts +13 -2
- package/server/system/env.ts +6 -1
- package/server/system/logger/formatters.ts +46 -4
- package/server/system/logger/index.ts +4 -4
- package/server/system/logger/sinks.ts +26 -5
- package/server/system/logger/types.ts +2 -2
- package/server/utils/dev-plugin-args.d.mts +11 -0
- package/server/utils/dev-plugin-args.mjs +43 -0
- package/server/utils/errors.ts +13 -4
- package/server/utils/files/accounting-io.ts +295 -0
- package/server/utils/files/atomic.ts +17 -49
- package/server/utils/files/attachment-store.ts +182 -0
- package/server/utils/files/html-io.ts +1 -7
- package/server/utils/files/html-store.ts +19 -0
- package/server/utils/files/image-store.ts +20 -22
- package/server/utils/files/index.ts +5 -15
- package/server/utils/files/journal-io.ts +7 -35
- package/server/utils/files/json.ts +2 -29
- package/server/utils/files/markdown-image-fill.ts +6 -37
- package/server/utils/files/markdown-store.ts +6 -21
- package/server/utils/files/naming.ts +3 -39
- package/server/utils/files/plugins-io.ts +100 -0
- package/server/utils/files/reference-dirs-io.ts +1 -9
- package/server/utils/files/roles-io.ts +2 -10
- package/server/utils/files/safe.ts +17 -19
- package/server/utils/files/scheduler-io.ts +1 -7
- package/server/utils/files/scheduler-overrides-io.ts +3 -12
- package/server/utils/files/session-io.ts +21 -30
- package/server/utils/files/spreadsheet-store.ts +9 -22
- package/server/utils/files/translation-io.ts +46 -0
- package/server/utils/files/user-tasks-io.ts +1 -7
- package/server/utils/files/workspace-io.ts +3 -79
- package/server/utils/gemini.ts +33 -11
- package/server/utils/html/htmlArtifactSplicer.ts +41 -0
- package/server/utils/markdown/frontmatter.ts +112 -0
- package/server/utils/regex.ts +56 -0
- package/server/utils/router.ts +41 -0
- package/server/utils/slug.ts +5 -3
- package/server/utils/time.ts +12 -0
- package/server/workspace/chat-index/indexer.ts +15 -2
- package/server/workspace/chat-index/summarizer.ts +1 -1
- package/server/workspace/custom-dirs.ts +1 -1
- package/server/workspace/helps/gemini.md +1 -1
- package/server/workspace/helps/guide.md +61 -0
- package/server/workspace/helps/index.md +4 -0
- package/server/workspace/helps/presenthtml.md +80 -0
- package/server/workspace/helps/sandbox.md +7 -0
- package/server/workspace/helps/storyteller.md +101 -0
- package/server/workspace/helps/telegram.md +1 -0
- package/server/workspace/helps/wiki.md +9 -7
- package/server/workspace/journal/archivist-cli.ts +7 -33
- package/server/workspace/journal/archivist-schemas.ts +5 -43
- package/server/workspace/journal/dailyPass.ts +34 -187
- package/server/workspace/journal/diff.ts +3 -28
- package/server/workspace/journal/index.ts +10 -81
- package/server/workspace/journal/indexFile.ts +3 -24
- package/server/workspace/journal/latestDaily.ts +51 -0
- package/server/workspace/journal/memoryExtractor.ts +4 -20
- package/server/workspace/journal/optimizationPass.ts +4 -21
- package/server/workspace/journal/paths.ts +4 -23
- package/server/workspace/journal/state.ts +6 -29
- package/server/workspace/memory/io.ts +213 -0
- package/server/workspace/memory/llm-classifier.ts +158 -0
- package/server/workspace/memory/migrate.ts +263 -0
- package/server/workspace/memory/run.ts +84 -0
- package/server/workspace/memory/topic-cluster.ts +218 -0
- package/server/workspace/memory/topic-detect.ts +67 -0
- package/server/workspace/memory/topic-index-hook.ts +128 -0
- package/server/workspace/memory/topic-io.ts +180 -0
- package/server/workspace/memory/topic-migrate.ts +248 -0
- package/server/workspace/memory/topic-run.ts +172 -0
- package/server/workspace/memory/topic-swap.ts +135 -0
- package/server/workspace/memory/topic-types.ts +142 -0
- package/server/workspace/memory/types.ts +83 -0
- package/server/workspace/news/reader.ts +4 -5
- package/server/workspace/paths.ts +124 -47
- package/server/workspace/roles.ts +2 -11
- package/server/workspace/skills/parser.ts +38 -55
- package/server/workspace/skills/user-tasks.ts +1 -2
- package/server/workspace/skills-preset/mc-library/SKILL.md +188 -0
- package/server/workspace/skills-preset.ts +196 -0
- package/server/workspace/sources/fetchers/githubIssues.ts +13 -11
- package/server/workspace/sources/fetchers/index.ts +1 -1
- package/server/workspace/sources/fetchers/rssParser.ts +1 -1
- package/server/workspace/sources/pipeline/index.ts +2 -2
- package/server/workspace/sources/pipeline/notify.ts +3 -3
- package/server/workspace/sources/pipeline/write.ts +2 -2
- package/server/workspace/sources/registry.ts +39 -61
- package/server/workspace/sources/robots.ts +1 -1
- package/server/workspace/tool-trace/classify.ts +2 -1
- package/server/workspace/tool-trace/index.ts +1 -1
- package/server/workspace/tool-trace/writeSearch.ts +6 -1
- package/server/workspace/wiki-backlinks/index.ts +19 -7
- package/server/workspace/wiki-backlinks/sessionBacklinks.ts +1 -0
- package/server/workspace/wiki-history/hook/snapshot.mjs +98 -0
- package/server/workspace/wiki-history/hook/snapshot.ts +135 -0
- package/server/workspace/wiki-history/provision.ts +181 -0
- package/server/workspace/wiki-pages/io.ts +217 -0
- package/server/workspace/wiki-pages/snapshot.ts +380 -0
- package/server/workspace/workspace.ts +75 -13
- package/src/App.vue +115 -40
- package/src/_runtime/protocol-vue.ts +21 -0
- package/src/_runtime/vue.ts +22 -0
- package/src/components/ChatInput.vue +14 -10
- package/src/components/CopyChatButton.vue +76 -0
- package/src/components/FileContentRenderer.vue +67 -14
- package/src/components/FileTree.vue +2 -2
- package/src/components/FilesView.vue +17 -1
- package/src/components/NewsView.vue +16 -2
- package/src/components/NotificationBell.vue +320 -93
- package/src/components/PageChatComposer.vue +5 -4
- package/src/components/PluginLauncher.vue +42 -6
- package/src/components/PluginScopedRoot.vue +87 -0
- package/src/components/RoleSelector.vue +12 -1
- package/src/components/RolesView.vue +562 -0
- package/src/components/SentAttachmentChip.vue +102 -0
- package/src/components/SessionHistoryPanel.vue +109 -20
- package/src/components/SessionRoleIcon.vue +7 -4
- package/src/components/SessionSidebar.vue +20 -7
- package/src/components/SessionTabBar.vue +1 -1
- package/src/components/SettingsMcpTab.vue +4 -4
- package/src/components/SettingsModal.vue +2 -0
- package/src/components/SidebarHeader.vue +16 -5
- package/src/components/SourcesManager.vue +23 -9
- package/src/components/SourcesView.vue +1 -1
- package/src/components/StackView.vue +102 -6
- package/src/components/SuggestionsPanel.vue +105 -16
- package/src/components/SystemFileBanner.vue +1 -1
- package/src/components/TodoExplorer.vue +4 -5
- package/src/components/todo/TodoAddDialog.vue +2 -3
- package/src/components/todo/TodoEditDialog.vue +1 -2
- package/src/components/todo/TodoEditPanel.vue +2 -3
- package/src/components/todo/TodoKanbanView.vue +8 -5
- package/src/components/todo/TodoListView.vue +3 -5
- package/src/components/todo/TodoTableView.vue +7 -5
- package/src/composables/useAccountingChannel.ts +58 -0
- package/src/composables/useActiveSession.ts +4 -25
- package/src/composables/useAppApi.ts +6 -44
- package/src/composables/useClipboardCopy.ts +3 -20
- package/src/composables/useContentDisplay.ts +33 -2
- package/src/composables/useDevPluginReload.ts +23 -0
- package/src/composables/useDynamicFavicon.ts +5 -31
- package/src/composables/useEventListeners.ts +0 -20
- package/src/composables/useExpandedDirs.ts +4 -15
- package/src/composables/useFaviconState.ts +12 -46
- package/src/composables/useFileChange.ts +53 -0
- package/src/composables/useFreshPluginData.ts +6 -43
- package/src/composables/useHealth.ts +14 -43
- package/src/composables/useImageErrorRepair.ts +104 -0
- package/src/composables/useLatestDaily.ts +40 -0
- package/src/composables/useMarkdownDoc.ts +39 -0
- package/src/composables/useMarkdownLinkHandler.ts +1 -1
- package/src/composables/useMcpTools.ts +3 -16
- package/src/composables/useNotifications.ts +138 -112
- package/src/composables/usePdfDownload.ts +17 -3
- package/src/composables/usePendingCalls.ts +8 -26
- package/src/composables/usePluginErrorBoundary.ts +68 -0
- package/src/composables/usePubSub.ts +9 -17
- package/src/composables/useRunElapsed.ts +5 -22
- package/src/composables/useSandboxStatus.ts +4 -20
- package/src/composables/useSessionDerived.ts +7 -15
- package/src/composables/useSessionHistory.ts +70 -29
- package/src/composables/useSessionSync.ts +25 -3
- package/src/composables/useSkillsList.ts +59 -0
- package/src/composables/useTranslatedQueries.ts +109 -0
- package/src/config/apiRoutes.ts +181 -80
- package/src/config/historyFilters.ts +5 -3
- package/src/config/hostEvents.ts +17 -0
- package/src/config/mcpCatalog.ts +277 -5
- package/src/config/pubsubChannels.ts +134 -12
- package/src/config/roles.ts +212 -147
- package/src/config/systemFileDescriptors.ts +5 -5
- package/src/config/toolNames.ts +52 -30
- package/src/config/workspacePaths.ts +26 -2
- package/src/lang/de.ts +483 -27
- package/src/lang/en.ts +448 -27
- package/src/lang/es.ts +474 -27
- package/src/lang/fr.ts +476 -27
- package/src/lang/ja.ts +465 -27
- package/src/lang/ko.ts +466 -27
- package/src/lang/pt-BR.ts +473 -27
- package/src/lang/zh.ts +463 -27
- package/src/lib/vue-i18n.ts +1 -1
- package/src/lib/wiki-page/slug.ts +66 -0
- package/src/main.ts +85 -0
- package/src/plugins/_extras.ts +58 -0
- package/src/plugins/_generated/metas.ts +42 -0
- package/src/plugins/_generated/registrations.ts +44 -0
- package/src/plugins/_generated/server-bindings.ts +47 -0
- package/src/plugins/accounting/Preview.vue +106 -0
- package/src/plugins/accounting/View.vue +632 -0
- package/src/plugins/accounting/actions.ts +34 -0
- package/src/plugins/accounting/api.ts +301 -0
- package/src/plugins/accounting/components/AccountEditor.vue +250 -0
- package/src/plugins/accounting/components/AccountRow.vue +50 -0
- package/src/plugins/accounting/components/AccountsList.vue +102 -0
- package/src/plugins/accounting/components/AccountsModal.vue +300 -0
- package/src/plugins/accounting/components/BalanceSheet.vue +186 -0
- package/src/plugins/accounting/components/BookSettings.vue +284 -0
- package/src/plugins/accounting/components/BookSwitcher.vue +78 -0
- package/src/plugins/accounting/components/DateRangePicker.vue +140 -0
- package/src/plugins/accounting/components/JournalEntryForm.vue +504 -0
- package/src/plugins/accounting/components/JournalList.vue +553 -0
- package/src/plugins/accounting/components/Ledger.vue +206 -0
- package/src/plugins/accounting/components/NewBookForm.vue +211 -0
- package/src/plugins/accounting/components/OpeningBalancesForm.vue +271 -0
- package/src/plugins/accounting/components/ProfitLoss.vue +160 -0
- package/src/plugins/accounting/components/accountDraft.ts +13 -0
- package/src/plugins/accounting/components/accountNumbering.ts +103 -0
- package/src/plugins/accounting/components/accountValidation.ts +75 -0
- package/src/plugins/accounting/components/useLatestRequest.ts +44 -0
- package/src/plugins/accounting/countries.ts +158 -0
- package/src/plugins/accounting/currencies.ts +64 -0
- package/src/plugins/accounting/dates.ts +51 -0
- package/src/plugins/accounting/definition.ts +199 -0
- package/src/plugins/accounting/fiscalYear.ts +136 -0
- package/src/plugins/accounting/index.ts +49 -0
- package/src/plugins/accounting/meta.ts +91 -0
- package/src/plugins/accounting/timeSeriesEnums.ts +16 -0
- package/src/plugins/api.ts +125 -0
- package/src/plugins/canvas/View.vue +38 -28
- package/src/plugins/canvas/definition.ts +10 -8
- package/src/plugins/canvas/index.ts +15 -8
- package/src/plugins/canvas/meta.ts +12 -0
- package/src/plugins/chart/Preview.vue +1 -1
- package/src/plugins/chart/View.vue +2 -2
- package/src/plugins/chart/definition.ts +12 -2
- package/src/plugins/chart/index.ts +15 -7
- package/src/plugins/chart/meta.ts +18 -0
- package/src/plugins/editImages/definition.ts +44 -0
- package/src/plugins/editImages/index.ts +43 -0
- package/src/plugins/editImages/meta.ts +5 -0
- package/src/plugins/generateImage/View.vue +3 -1
- package/src/plugins/generateImage/definition.ts +2 -0
- package/src/plugins/generateImage/index.ts +13 -5
- package/src/plugins/generateImage/meta.ts +5 -0
- package/src/plugins/index.ts +35 -0
- package/src/plugins/manageRoles/Preview.vue +7 -4
- package/src/plugins/manageRoles/View.vue +12 -8
- package/src/plugins/manageRoles/definition.ts +6 -0
- package/src/plugins/manageRoles/index.ts +7 -6
- package/src/plugins/manageSkills/View.vue +11 -7
- package/src/plugins/manageSkills/definition.ts +4 -1
- package/src/plugins/manageSkills/index.ts +14 -7
- package/src/plugins/manageSkills/meta.ts +21 -0
- package/src/plugins/manageSource/definition.ts +4 -1
- package/src/plugins/manageSource/index.ts +15 -7
- package/src/plugins/manageSource/meta.ts +21 -0
- package/src/plugins/markdown/Preview.vue +10 -8
- package/src/plugins/markdown/View.vue +84 -17
- package/src/plugins/markdown/definition.ts +7 -1
- package/src/plugins/markdown/index.ts +15 -8
- package/src/plugins/markdown/meta.ts +16 -0
- package/src/plugins/meta-types.ts +97 -0
- package/src/plugins/metas.ts +224 -0
- package/src/plugins/presentForm/Preview.vue +4 -15
- package/src/plugins/presentForm/View.vue +35 -78
- package/src/plugins/presentForm/definition.ts +7 -6
- package/src/plugins/presentForm/index.ts +12 -5
- package/src/plugins/presentForm/meta.ts +11 -0
- package/src/plugins/presentForm/plugin.ts +8 -9
- package/src/plugins/presentForm/types.ts +0 -24
- package/src/plugins/presentHtml/Preview.vue +1 -8
- package/src/plugins/presentHtml/View.vue +401 -30
- package/src/plugins/presentHtml/definition.ts +8 -5
- package/src/plugins/presentHtml/index.ts +15 -8
- package/src/plugins/presentHtml/meta.ts +14 -0
- package/src/plugins/presentMulmoScript/View.vue +327 -107
- package/src/plugins/presentMulmoScript/definition.ts +34 -7
- package/src/plugins/presentMulmoScript/helpers.ts +4 -5
- package/src/plugins/presentMulmoScript/index.ts +20 -7
- package/src/plugins/presentMulmoScript/meta.ts +52 -0
- package/src/plugins/scheduler/AutomationsPreview.vue +2 -8
- package/src/plugins/scheduler/Preview.vue +5 -2
- package/src/plugins/scheduler/TasksTab.vue +16 -36
- package/src/plugins/scheduler/View.vue +22 -54
- package/src/plugins/scheduler/automationsDefinition.ts +14 -9
- package/src/plugins/scheduler/automationsMeta.ts +5 -0
- package/src/plugins/scheduler/calendarDefinition.ts +4 -7
- package/src/plugins/scheduler/calendarMeta.ts +28 -0
- package/src/plugins/scheduler/formatSchedule.ts +6 -24
- package/src/plugins/scheduler/index.ts +26 -52
- package/src/plugins/scope.ts +57 -0
- package/src/plugins/server-bindings-types.ts +38 -0
- package/src/plugins/server.ts +32 -0
- package/src/plugins/skill/Preview.vue +25 -0
- package/src/plugins/skill/View.vue +125 -0
- package/src/plugins/skill/definition.ts +23 -0
- package/src/plugins/skill/index.ts +36 -0
- package/src/plugins/skill/plugin.ts +31 -0
- package/src/plugins/skill/types.ts +21 -0
- package/src/plugins/spreadsheet/Preview.vue +1 -3
- package/src/plugins/spreadsheet/View.vue +29 -49
- package/src/plugins/spreadsheet/cellHighlights.ts +2 -3
- package/src/plugins/spreadsheet/definition.ts +5 -2
- package/src/plugins/spreadsheet/index.ts +15 -8
- package/src/plugins/spreadsheet/keyboardNav.ts +38 -0
- package/src/plugins/spreadsheet/meta.ts +14 -0
- package/src/plugins/textResponse/Preview.vue +9 -1
- package/src/plugins/textResponse/View.vue +59 -8
- package/src/plugins/textResponse/index.ts +11 -3
- package/src/plugins/textResponse/plugin.ts +8 -10
- package/src/plugins/textResponse/types.ts +28 -0
- package/src/plugins/wiki/Preview.vue +6 -4
- package/src/plugins/wiki/View.vue +463 -254
- package/src/plugins/wiki/components/WikiPageBody.vue +159 -0
- package/src/plugins/wiki/helpers.ts +17 -0
- package/src/plugins/wiki/history/HistoryDetail.vue +325 -0
- package/src/plugins/wiki/history/HistoryTab.vue +167 -0
- package/src/plugins/wiki/history/RestoreConfirm.vue +63 -0
- package/src/plugins/wiki/history/api.ts +52 -0
- package/src/plugins/wiki/history/diff.ts +145 -0
- package/src/plugins/wiki/index.ts +42 -32
- package/src/plugins/wiki/meta.ts +10 -0
- package/src/plugins/wiki/pageEditLoader.ts +53 -0
- package/src/plugins/wiki/route.ts +8 -0
- package/src/router/guards.ts +2 -1
- package/src/router/index.ts +19 -0
- package/src/router/pageRoutes.ts +1 -0
- package/src/tools/index.ts +50 -51
- package/src/tools/runtimeLoader.ts +141 -0
- package/src/tools/types.ts +44 -1
- package/src/types/notification.ts +23 -0
- package/src/types/pastedFile.ts +10 -0
- package/src/types/session.ts +61 -3
- package/src/types/sse.ts +21 -6
- package/src/utils/agent/eventDispatch.ts +12 -9
- package/src/utils/agent/pastedAttachment.ts +35 -0
- package/src/utils/agent/request.ts +32 -3
- package/src/utils/agent/toolCalls.ts +7 -1
- package/src/utils/api.ts +1 -1
- package/src/utils/chat/exportMarkdown.ts +243 -0
- package/src/utils/errors.ts +10 -2
- package/src/utils/files/expandedDirs.ts +1 -1
- package/src/utils/filesPreview/todoPreview.ts +13 -2
- package/src/utils/format/date.ts +1 -3
- package/src/utils/format/jsonSyntax.ts +5 -0
- package/src/utils/html/iframeHeightReporterScript.ts +62 -0
- package/src/utils/html/previewCsp.ts +29 -2
- package/src/utils/image/htmlSrcAttrs.ts +122 -0
- package/src/utils/image/imageRepairInlineScript.ts +115 -0
- package/src/utils/image/resolve.ts +17 -3
- package/src/utils/image/rewriteMarkdownImageRefs.ts +62 -9
- package/src/utils/markdown/frontmatter.ts +125 -0
- package/src/utils/markdown/taskList.ts +7 -2
- package/src/utils/plugin/runtime.ts +132 -0
- package/src/utils/session/mergeSessions.ts +40 -37
- package/src/utils/session/sessionEntries.ts +74 -18
- package/src/utils/session/sessionHelpers.ts +54 -10
- package/src/utils/tools/result.ts +76 -14
- package/src/vite-env.d.ts +6 -0
- package/client/assets/html2canvas-Cx501zZr-Bug0qRNv.js +0 -5
- package/client/assets/index-CY-WpQUm.css +0 -2
- package/client/assets/index-DbTz2Mfs.js +0 -4911
- package/client/assets/material-symbols-outlined-NzYEeyps.woff2 +0 -0
- package/server/api/routes/html.ts +0 -114
- package/server/api/routes/todos.ts +0 -293
- package/server/api/routes/todosColumnsHandlers.ts +0 -333
- package/server/api/routes/todosHandlers.ts +0 -274
- package/server/api/routes/todosItemsHandlers.ts +0 -386
- package/server/utils/files/todos-io.ts +0 -29
- package/src/components/NotificationToast.vue +0 -75
- package/src/plugins/editImage/definition.ts +0 -27
- package/src/plugins/editImage/index.ts +0 -37
- package/src/plugins/presentHtml/helpers.ts +0 -72
- package/src/plugins/scheduler/LegacySchedulerView.vue +0 -32
- package/src/plugins/scheduler/legacyShape.ts +0 -34
- package/src/plugins/todo/Preview.vue +0 -68
- package/src/plugins/todo/View.vue +0 -378
- package/src/plugins/todo/composables/useTodos.ts +0 -179
- package/src/plugins/todo/definition.ts +0 -45
- package/src/plugins/todo/index.ts +0 -62
- package/src/plugins/todo/labels.ts +0 -163
- package/src/plugins/todo/priority.ts +0 -98
- package/src/plugins/todo/viewModes.ts +0 -19
- package/src/plugins/wiki/definition.ts +0 -25
- package/src/tools/legacyPluginNames.ts +0 -13
- package/src/utils/format/frontmatter.ts +0 -80
- package/src/utils/image/rewriteHtmlImageRefs.ts +0 -50
- package/src/utils/notification/dispatch.ts +0 -58
- /package/client/assets/{purify.es-Fx1Nqyry-BwJECkqS.js → purify.es-Fx1Nqyry-BSVNht6S.js} +0 -0
- /package/src/plugins/{editImage → editImages}/Preview.vue +0 -0
- /package/src/plugins/{editImage → editImages}/View.vue +0 -0
- /package/src/{config/schedulerActions.ts → plugins/scheduler/actions.ts} +0 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex flex-col gap-3" data-testid="accounting-ledger">
|
|
3
|
+
<div class="flex flex-wrap items-end gap-3">
|
|
4
|
+
<label class="text-xs text-gray-500 flex flex-col gap-1">
|
|
5
|
+
{{ t("pluginAccounting.ledger.selectAccount") }}
|
|
6
|
+
<select v-model="accountCode" class="h-8 px-2 rounded border border-gray-300 text-sm bg-white" data-testid="accounting-ledger-account">
|
|
7
|
+
<option value="">{{ DASH }}</option>
|
|
8
|
+
<option v-for="account in selectableAccounts" :key="account.code" :value="account.code">{{ formatAccountLabel(account) }}</option>
|
|
9
|
+
</select>
|
|
10
|
+
</label>
|
|
11
|
+
<DateRangePicker v-model="range" :fiscal-year-end="resolvedFiscalYearEnd" :opening-date="openingDate" />
|
|
12
|
+
<button class="h-8 px-2.5 rounded border border-gray-300 text-sm text-gray-600 hover:bg-gray-50" @click="refresh">
|
|
13
|
+
<span class="material-icons text-base align-middle">refresh</span>
|
|
14
|
+
</button>
|
|
15
|
+
</div>
|
|
16
|
+
<p v-if="loading" class="text-xs text-gray-400">{{ t("pluginAccounting.common.loading") }}</p>
|
|
17
|
+
<p v-else-if="error" class="text-xs text-red-500">{{ t("pluginAccounting.common.error", { error }) }}</p>
|
|
18
|
+
<template v-else-if="ledger">
|
|
19
|
+
<table class="w-full text-sm" :data-testid="showTaxRegistrationColumn ? 'accounting-ledger-table-with-tax-id' : 'accounting-ledger-table'">
|
|
20
|
+
<thead>
|
|
21
|
+
<tr class="text-xs text-gray-500 border-b border-gray-200">
|
|
22
|
+
<th class="text-left py-1 px-2">{{ t("pluginAccounting.ledger.columns.date") }}</th>
|
|
23
|
+
<th class="text-left py-1 px-2">{{ t("pluginAccounting.ledger.columns.memo") }}</th>
|
|
24
|
+
<th v-if="showTaxRegistrationColumn" class="text-left py-1 px-2 w-40">
|
|
25
|
+
{{ t("pluginAccounting.ledger.columns.taxRegistrationId") }}
|
|
26
|
+
</th>
|
|
27
|
+
<th class="text-right py-1 px-2 w-28">{{ t("pluginAccounting.ledger.columns.debit") }}</th>
|
|
28
|
+
<th class="text-right py-1 px-2 w-28">{{ t("pluginAccounting.ledger.columns.credit") }}</th>
|
|
29
|
+
<th class="text-right py-1 px-2 w-28">{{ t("pluginAccounting.ledger.columns.balance") }}</th>
|
|
30
|
+
</tr>
|
|
31
|
+
</thead>
|
|
32
|
+
<tbody>
|
|
33
|
+
<tr
|
|
34
|
+
v-for="row in ledger.rows"
|
|
35
|
+
:key="`${row.entryId}-${row.date}`"
|
|
36
|
+
:class="row.kind === 'void' || row.kind === 'void-marker' ? 'text-gray-400 line-through' : ''"
|
|
37
|
+
class="border-b border-gray-100"
|
|
38
|
+
>
|
|
39
|
+
<td class="py-1 px-2 whitespace-nowrap">{{ row.date }}</td>
|
|
40
|
+
<td class="py-1 px-2">
|
|
41
|
+
<span v-if="row.memo">{{ row.memo }}</span>
|
|
42
|
+
</td>
|
|
43
|
+
<td v-if="showTaxRegistrationColumn" class="py-1 px-2 font-mono text-xs">
|
|
44
|
+
<span v-if="row.taxRegistrationId">{{ row.taxRegistrationId }}</span>
|
|
45
|
+
</td>
|
|
46
|
+
<td class="py-1 px-2 text-right">
|
|
47
|
+
<span v-if="row.debit">{{ formatAmount(row.debit) }}</span>
|
|
48
|
+
</td>
|
|
49
|
+
<td class="py-1 px-2 text-right">
|
|
50
|
+
<span v-if="row.credit">{{ formatAmount(row.credit) }}</span>
|
|
51
|
+
</td>
|
|
52
|
+
<td class="py-1 px-2 text-right font-mono">{{ formatAmount(row.runningBalance) }}</td>
|
|
53
|
+
</tr>
|
|
54
|
+
</tbody>
|
|
55
|
+
<tfoot>
|
|
56
|
+
<tr class="font-semibold border-t border-gray-300">
|
|
57
|
+
<td :colspan="showTaxRegistrationColumn ? 5 : 4" class="py-1 px-2 text-right">
|
|
58
|
+
{{ t("pluginAccounting.ledger.closingBalance") }}
|
|
59
|
+
</td>
|
|
60
|
+
<td class="py-1 px-2 text-right">{{ formatAmount(ledger.closingBalance) }}</td>
|
|
61
|
+
</tr>
|
|
62
|
+
</tfoot>
|
|
63
|
+
</table>
|
|
64
|
+
</template>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<script setup lang="ts">
|
|
69
|
+
import { computed, ref, watch } from "vue";
|
|
70
|
+
import { useI18n } from "vue-i18n";
|
|
71
|
+
import { getLedger, type Account, type Ledger, type ReportPeriod } from "../api";
|
|
72
|
+
import { formatAmount as formatAmountWithCurrency } from "../currencies";
|
|
73
|
+
import { currentFiscalYearRange, resolveFiscalYearEnd, type DateRange, type FiscalYearEnd } from "../fiscalYear";
|
|
74
|
+
import { isTaxAccountCode } from "./accountNumbering";
|
|
75
|
+
import { useLatestRequest } from "./useLatestRequest";
|
|
76
|
+
import DateRangePicker from "./DateRangePicker.vue";
|
|
77
|
+
|
|
78
|
+
const { t } = useI18n();
|
|
79
|
+
|
|
80
|
+
const props = defineProps<{
|
|
81
|
+
bookId: string;
|
|
82
|
+
accounts: Account[];
|
|
83
|
+
currency: string;
|
|
84
|
+
version: number;
|
|
85
|
+
fiscalYearEnd?: FiscalYearEnd;
|
|
86
|
+
/** Opening-balance date for the active book — drives the "Lifetime"
|
|
87
|
+
* shortcut in the date picker (from = openingDate, to = today).
|
|
88
|
+
* When absent, the picker hides Lifetime; "All" still works. */
|
|
89
|
+
openingDate?: string;
|
|
90
|
+
/** Optional account to preselect (Accounts tab → click). Updates
|
|
91
|
+
* via the watcher below — assigning to the local `accountCode`
|
|
92
|
+
* ref keeps the dropdown's v-model authoritative for user edits. */
|
|
93
|
+
preselectAccountCode?: string;
|
|
94
|
+
}>();
|
|
95
|
+
|
|
96
|
+
const DASH = "—";
|
|
97
|
+
const accountCode = ref("");
|
|
98
|
+
const ledger = ref<Ledger | null>(null);
|
|
99
|
+
const loading = ref(false);
|
|
100
|
+
const error = ref<string | null>(null);
|
|
101
|
+
const { begin: beginRequest, isCurrent } = useLatestRequest();
|
|
102
|
+
|
|
103
|
+
const resolvedFiscalYearEnd = computed<FiscalYearEnd>(() => resolveFiscalYearEnd(props.fiscalYearEnd));
|
|
104
|
+
|
|
105
|
+
// Default range = current fiscal year. Re-evaluated when bookId or
|
|
106
|
+
// fiscalYearEnd changes (see watcher) so switching books resets to a
|
|
107
|
+
// sensible window rather than carrying the prior book's custom edits.
|
|
108
|
+
const range = ref<DateRange>(currentFiscalYearRange(resolvedFiscalYearEnd.value));
|
|
109
|
+
|
|
110
|
+
function formatAmount(value: number): string {
|
|
111
|
+
return formatAmountWithCurrency(value, props.currency);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function formatAccountLabel(account: Account): string {
|
|
115
|
+
// Name first so type-to-search in the <select> matches the
|
|
116
|
+
// human-meaningful word; the code goes in trailing parens.
|
|
117
|
+
return `${account.name} (${account.code})`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Hide deactivated accounts from the ledger picker; historical
|
|
121
|
+
// entries on a soft-deleted account are still inspectable via
|
|
122
|
+
// the journal-list filter (which intentionally shows every code
|
|
123
|
+
// so the past stays queryable).
|
|
124
|
+
const selectableAccounts = computed<Account[]>(() => props.accounts.filter((account) => account.active !== false));
|
|
125
|
+
|
|
126
|
+
// Surface the T-number column when the active account is in the
|
|
127
|
+
// input-tax band (14xx — e.g. 1400 Input Tax Receivable).
|
|
128
|
+
// Convention-driven so any custom account a user adds in the band
|
|
129
|
+
// participates without an opt-in flag. 24xx (Sales Tax Payable
|
|
130
|
+
// and friends) intentionally doesn't get the column — the
|
|
131
|
+
// counterparty registration ID matters for input-tax-credit
|
|
132
|
+
// eligibility on purchases, not for the seller-side liability.
|
|
133
|
+
const showTaxRegistrationColumn = computed<boolean>(() => {
|
|
134
|
+
if (!ledger.value) return false;
|
|
135
|
+
return isTaxAccountCode(ledger.value.accountCode);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Build a ReportPeriod from the current range. Both ends empty = no
|
|
139
|
+
// filter (full history); either end alone gets a sentinel on the
|
|
140
|
+
// other side so the server-side range filter still applies.
|
|
141
|
+
function periodFromRange(value: DateRange): ReportPeriod | undefined {
|
|
142
|
+
if (value.from === "" && value.to === "") return undefined;
|
|
143
|
+
return { kind: "range", from: value.from || "0000-01-01", to: value.to || "9999-12-31" };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function refresh(): Promise<void> {
|
|
147
|
+
const token = beginRequest();
|
|
148
|
+
if (!accountCode.value) {
|
|
149
|
+
ledger.value = null;
|
|
150
|
+
error.value = null;
|
|
151
|
+
loading.value = false;
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
loading.value = true;
|
|
155
|
+
error.value = null;
|
|
156
|
+
try {
|
|
157
|
+
const result = await getLedger(accountCode.value, periodFromRange(range.value), props.bookId);
|
|
158
|
+
// Drop the result if a newer refresh started (bookId or
|
|
159
|
+
// accountCode changed under us) — otherwise a slower earlier
|
|
160
|
+
// request could overwrite the fresh ledger.
|
|
161
|
+
if (!isCurrent(token)) return;
|
|
162
|
+
if (!result.ok) {
|
|
163
|
+
error.value = result.error;
|
|
164
|
+
ledger.value = null;
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
ledger.value = result.data.ledger;
|
|
168
|
+
} finally {
|
|
169
|
+
if (isCurrent(token)) loading.value = false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Reset to current-year window AND drop the selected account
|
|
174
|
+
// whenever the active book or its fiscal-year end changes. Without
|
|
175
|
+
// the accountCode reset, switching from book A (cash=1000) to book
|
|
176
|
+
// B (which may not even define 1000) fires a getLedger for a
|
|
177
|
+
// missing code and surfaces an avoidable 404. The range reset
|
|
178
|
+
// follows the same logic — a custom window from book A is
|
|
179
|
+
// meaningless against book B's entries.
|
|
180
|
+
watch(
|
|
181
|
+
() => [props.bookId, resolvedFiscalYearEnd.value],
|
|
182
|
+
() => {
|
|
183
|
+
accountCode.value = "";
|
|
184
|
+
range.value = currentFiscalYearRange(resolvedFiscalYearEnd.value);
|
|
185
|
+
},
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// Apply parent-supplied preselection (Accounts tab → click). The
|
|
189
|
+
// watcher fires on both initial mount (with `immediate`) and on
|
|
190
|
+
// every prop change so re-clicking the same account from the
|
|
191
|
+
// Accounts tab while already on the Ledger still routes through.
|
|
192
|
+
// Resets the range to the current fiscal year on each preselect so
|
|
193
|
+
// a stale custom window the user left behind on the Ledger doesn't
|
|
194
|
+
// hide the entries the Accounts tab handed off.
|
|
195
|
+
watch(
|
|
196
|
+
() => props.preselectAccountCode,
|
|
197
|
+
(next) => {
|
|
198
|
+
if (!next) return;
|
|
199
|
+
accountCode.value = next;
|
|
200
|
+
range.value = currentFiscalYearRange(resolvedFiscalYearEnd.value);
|
|
201
|
+
},
|
|
202
|
+
{ immediate: true },
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
watch(() => [props.bookId, props.version, accountCode.value, range.value.from, range.value.to], refresh, { immediate: true });
|
|
206
|
+
</script>
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- Form for creating a new book. Two layouts share one body:
|
|
3
|
+
• modal (default) — used by BookSwitcher's "+ New book…"
|
|
4
|
+
sentinel option. Backdrop click cancels.
|
|
5
|
+
• fullPage — used by View.vue on the first-run flow when
|
|
6
|
+
the workspace has zero books. No backdrop, no cancel:
|
|
7
|
+
the user MUST create their first book to proceed.
|
|
8
|
+
The submit calls createBook directly; on success it emits
|
|
9
|
+
the new book and its id, leaving the parent to update its
|
|
10
|
+
current selection / refetch. -->
|
|
11
|
+
<div :class="wrapperClass" data-testid="accounting-new-book-modal" @click.self="onBackdropClick">
|
|
12
|
+
<form class="bg-white p-4 rounded shadow-lg w-96 flex flex-col gap-3" data-testid="accounting-new-book-form" @submit.prevent="onSubmit">
|
|
13
|
+
<h3 class="text-base font-semibold">{{ t("pluginAccounting.bookSwitcher.newBook") }}</h3>
|
|
14
|
+
<p v-if="firstRun" class="text-xs text-gray-500" data-testid="accounting-new-book-firstrun">{{ t("pluginAccounting.bookSwitcher.firstRunHint") }}</p>
|
|
15
|
+
<label class="text-sm flex flex-col gap-1">
|
|
16
|
+
{{ t("pluginAccounting.bookSwitcher.nameLabel") }}
|
|
17
|
+
<input ref="nameInput" v-model="name" required class="h-8 px-2 rounded border border-gray-300 text-sm" data-testid="accounting-new-book-name" />
|
|
18
|
+
</label>
|
|
19
|
+
<label class="text-sm flex flex-col gap-1">
|
|
20
|
+
{{ t("pluginAccounting.bookSwitcher.currencyLabel") }}
|
|
21
|
+
<select v-model="currency" class="h-8 px-2 rounded border border-gray-300 text-sm bg-white" data-testid="accounting-new-book-currency">
|
|
22
|
+
<option v-for="opt in options" :key="opt.code" :value="opt.code">{{ opt.label }}</option>
|
|
23
|
+
</select>
|
|
24
|
+
</label>
|
|
25
|
+
<label class="text-sm flex flex-col gap-1">
|
|
26
|
+
{{ t("pluginAccounting.bookSwitcher.countryLabel") }}
|
|
27
|
+
<select v-model="country" class="h-8 px-2 rounded border border-gray-300 text-sm bg-white" data-testid="accounting-new-book-country">
|
|
28
|
+
<option value="">{{ t("pluginAccounting.bookSwitcher.countryPlaceholder") }}</option>
|
|
29
|
+
<option v-for="opt in countryOptions" :key="opt.code" :value="opt.code">{{ opt.label }}</option>
|
|
30
|
+
</select>
|
|
31
|
+
</label>
|
|
32
|
+
<p class="text-xs text-gray-500">{{ t("pluginAccounting.bookSwitcher.countryHint") }}</p>
|
|
33
|
+
<label class="text-sm flex flex-col gap-1">
|
|
34
|
+
{{ t("pluginAccounting.bookSwitcher.fiscalYearEndLabel") }}
|
|
35
|
+
<select
|
|
36
|
+
v-model="fiscalYearEnd"
|
|
37
|
+
required
|
|
38
|
+
class="h-8 px-2 rounded border border-gray-300 text-sm bg-white"
|
|
39
|
+
data-testid="accounting-new-book-fiscal-year-end"
|
|
40
|
+
>
|
|
41
|
+
<option v-for="opt in fiscalYearEndOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</option>
|
|
42
|
+
</select>
|
|
43
|
+
</label>
|
|
44
|
+
<p class="text-xs text-gray-500">{{ t("pluginAccounting.bookSwitcher.fiscalYearEndHint") }}</p>
|
|
45
|
+
<p v-if="error" class="text-xs text-red-500" data-testid="accounting-new-book-error">{{ error }}</p>
|
|
46
|
+
<div class="flex justify-end gap-2 mt-1">
|
|
47
|
+
<button v-if="showCancel" type="button" class="h-8 px-2.5 rounded border border-gray-300 text-sm text-gray-700 hover:bg-gray-50" @click="onCancel">
|
|
48
|
+
{{ t("pluginAccounting.common.cancel") }}
|
|
49
|
+
</button>
|
|
50
|
+
<button
|
|
51
|
+
type="submit"
|
|
52
|
+
class="h-8 px-2.5 rounded bg-blue-600 hover:bg-blue-700 text-white text-sm"
|
|
53
|
+
:disabled="creating"
|
|
54
|
+
data-testid="accounting-new-book-submit"
|
|
55
|
+
>
|
|
56
|
+
{{ creating ? t("pluginAccounting.common.loading") : t("pluginAccounting.bookSwitcher.create") }}
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
</form>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
<script setup lang="ts">
|
|
64
|
+
import { computed, nextTick, onMounted, ref } from "vue";
|
|
65
|
+
import { useI18n } from "vue-i18n";
|
|
66
|
+
import { createBook, type BookSummary } from "../api";
|
|
67
|
+
import { SUPPORTED_CURRENCY_CODES, localizedCurrencyName } from "../currencies";
|
|
68
|
+
import { SUPPORTED_COUNTRY_CODES, localizedCountryName, type SupportedCountryCode } from "../countries";
|
|
69
|
+
import { DEFAULT_FISCAL_YEAR_END, FISCAL_YEAR_ENDS, type FiscalYearEnd } from "../fiscalYear";
|
|
70
|
+
|
|
71
|
+
const { t, locale } = useI18n();
|
|
72
|
+
|
|
73
|
+
function regionFromLocaleTag(tag: string): SupportedCountryCode | "" {
|
|
74
|
+
try {
|
|
75
|
+
const { region } = new Intl.Locale(tag).maximize();
|
|
76
|
+
if (region && (SUPPORTED_COUNTRY_CODES as readonly string[]).includes(region)) {
|
|
77
|
+
return region as SupportedCountryCode;
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
/* fall through */
|
|
81
|
+
}
|
|
82
|
+
return "";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function guessDefaultCountry(uiLocaleTag: string): SupportedCountryCode | "" {
|
|
86
|
+
// Try the active vue-i18n locale first (the user's *app* language
|
|
87
|
+
// setting, e.g. "ja-JP"), then fall back to the browser's
|
|
88
|
+
// navigator.language. Either may produce a region segment that maps
|
|
89
|
+
// to a curated `SupportedCountryCode`. If neither does, leave the
|
|
90
|
+
// field unset rather than silently picking a default — the
|
|
91
|
+
// dropdown's "(choose a country)" option lets the user finish the
|
|
92
|
+
// selection themselves so an unsupported locale doesn't quietly
|
|
93
|
+
// become a US-jurisdiction book.
|
|
94
|
+
const fromUi = regionFromLocaleTag(uiLocaleTag);
|
|
95
|
+
if (fromUi !== "") return fromUi;
|
|
96
|
+
const browserTag = typeof navigator !== "undefined" && typeof navigator.language === "string" ? navigator.language : "";
|
|
97
|
+
return regionFromLocaleTag(browserTag);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const props = withDefaults(
|
|
101
|
+
defineProps<{
|
|
102
|
+
firstRun?: boolean;
|
|
103
|
+
cancelable?: boolean;
|
|
104
|
+
fullPage?: boolean;
|
|
105
|
+
}>(),
|
|
106
|
+
{ firstRun: false, cancelable: true, fullPage: false },
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const emit = defineEmits<{
|
|
110
|
+
cancel: [];
|
|
111
|
+
created: [book: BookSummary];
|
|
112
|
+
}>();
|
|
113
|
+
|
|
114
|
+
const name = ref("");
|
|
115
|
+
const currency = ref<string>("USD");
|
|
116
|
+
const country = ref<SupportedCountryCode | "">(guessDefaultCountry(locale.value));
|
|
117
|
+
const fiscalYearEnd = ref<FiscalYearEnd>(DEFAULT_FISCAL_YEAR_END);
|
|
118
|
+
const creating = ref(false);
|
|
119
|
+
const error = ref<string | null>(null);
|
|
120
|
+
const nameInput = ref<HTMLInputElement | null>(null);
|
|
121
|
+
|
|
122
|
+
onMounted(() => {
|
|
123
|
+
// Land focus in Name on open — the only required field; the
|
|
124
|
+
// currency select defaults to USD and the user usually leaves
|
|
125
|
+
// it. Without this the user has to click into the field before
|
|
126
|
+
// typing, which is friction for what should be a one-tap flow.
|
|
127
|
+
void nextTick(() => nameInput.value?.focus());
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
interface CurrencyOption {
|
|
131
|
+
code: string;
|
|
132
|
+
label: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const options = computed<CurrencyOption[]>(() =>
|
|
136
|
+
SUPPORTED_CURRENCY_CODES.map((code) => ({
|
|
137
|
+
code,
|
|
138
|
+
label: `${code} — ${localizedCurrencyName(code, locale.value)}`,
|
|
139
|
+
})),
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
interface CountryOption {
|
|
143
|
+
code: string;
|
|
144
|
+
label: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const countryOptions = computed<CountryOption[]>(() =>
|
|
148
|
+
SUPPORTED_COUNTRY_CODES.map((code) => ({
|
|
149
|
+
code,
|
|
150
|
+
label: `${code} — ${localizedCountryName(code, locale.value)}`,
|
|
151
|
+
})),
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
interface FiscalYearEndOption {
|
|
155
|
+
value: FiscalYearEnd;
|
|
156
|
+
label: string;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const fiscalYearEndOptions = computed<FiscalYearEndOption[]>(() =>
|
|
160
|
+
FISCAL_YEAR_ENDS.map((value) => ({
|
|
161
|
+
value,
|
|
162
|
+
label: t(`pluginAccounting.bookSwitcher.fiscalYearEnd${value}`),
|
|
163
|
+
})),
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Full-page mode replaces the AccountingApp chrome — fill the
|
|
167
|
+
// parent flex column with the form centered, no backdrop. Modal
|
|
168
|
+
// mode keeps the original viewport overlay behaviour.
|
|
169
|
+
const wrapperClass = computed(() =>
|
|
170
|
+
props.fullPage ? "flex-1 bg-white flex items-center justify-center p-6 overflow-auto" : "fixed inset-0 z-50 bg-black/20 flex items-center justify-center",
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// Cancel is hidden in full-page mode regardless of `cancelable`
|
|
174
|
+
// — the first-run flow forces the user to create a book.
|
|
175
|
+
const showCancel = computed(() => props.cancelable && !props.fullPage);
|
|
176
|
+
|
|
177
|
+
function onBackdropClick(): void {
|
|
178
|
+
if (props.fullPage) return;
|
|
179
|
+
onCancel();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function onCancel(): void {
|
|
183
|
+
if (!props.cancelable) return;
|
|
184
|
+
emit("cancel");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function onSubmit(): Promise<void> {
|
|
188
|
+
if (creating.value) return;
|
|
189
|
+
creating.value = true;
|
|
190
|
+
error.value = null;
|
|
191
|
+
try {
|
|
192
|
+
// Only forward `country` when the user actually picked one — the
|
|
193
|
+
// empty string is the dropdown's "(choose a country)" sentinel
|
|
194
|
+
// and must not land on disk as a literal "" value.
|
|
195
|
+
const pickedCountry: SupportedCountryCode | undefined = country.value === "" ? undefined : country.value;
|
|
196
|
+
const result = await createBook({
|
|
197
|
+
name: name.value.trim(),
|
|
198
|
+
currency: currency.value,
|
|
199
|
+
country: pickedCountry,
|
|
200
|
+
fiscalYearEnd: fiscalYearEnd.value,
|
|
201
|
+
});
|
|
202
|
+
if (!result.ok) {
|
|
203
|
+
error.value = result.error;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
emit("created", result.data.book);
|
|
207
|
+
} finally {
|
|
208
|
+
creating.value = false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
</script>
|