From 5cad11f3f981a77727ef00268b5d071cd32c9c40 Mon Sep 17 00:00:00 2001 From: mirivlad Date: Tue, 14 Jul 2026 22:18:52 +0800 Subject: [PATCH] fix: use Deal terminology in desktop shell --- frontend/e2e/sidebar-opens-view.spec.js | 27 ++++++++++++ frontend/e2e/ux-p0.spec.js | 5 +++ frontend/e2e/workspace-templates.spec.js | 18 ++++---- frontend/src/App.svelte | 6 ++- frontend/src/lib/i18n/catalogs/en.js | 49 +++++++++++---------- frontend/src/lib/i18n/catalogs/ru.js | 47 +++++++++++--------- frontend/src/lib/shell/Sidebar.svelte | 15 +++++++ frontend/src/lib/shell/TodaySurface.svelte | 6 +-- frontend/src/lib/shell/WorkspaceHost.svelte | 10 ----- frontend/tests/user-terminology-test.mjs | 28 ++++++++++++ 10 files changed, 143 insertions(+), 68 deletions(-) create mode 100644 frontend/tests/user-terminology-test.mjs diff --git a/frontend/e2e/sidebar-opens-view.spec.js b/frontend/e2e/sidebar-opens-view.spec.js index a32ec57..11ae6cb 100644 --- a/frontend/e2e/sidebar-opens-view.spec.js +++ b/frontend/e2e/sidebar-opens-view.spec.js @@ -44,6 +44,33 @@ test.describe('B: Sidebar opens plugin view by item.view', () => { await expect(page.locator('.view-container .view-header h2')).toHaveText('Browser Inbox', { timeout: 10000 }); }); + test('selected global tool remains visibly active through navigation and sidebar reloads', async ({ page }) => { + const activity = page.locator('.sidebar .plugin-item').filter({ hasText: 'Activity' }); + const browserInbox = page.locator('.sidebar .plugin-item').filter({ hasText: 'Browser Inbox' }); + + await activity.click(); + await expect(activity).toHaveAttribute('aria-current', 'page'); + await expect(activity).toHaveClass(/is-active/); + + await page.evaluate(() => { + window.dispatchEvent(new CustomEvent('verstak:plugins-changed')); + }); + await expect(activity).toHaveAttribute('aria-current', 'page'); + + await page.evaluate(() => { + window.dispatchEvent(new CustomEvent('verstak:open-view', { + detail: { viewId: 'verstak.browser-inbox.view', pluginId: 'verstak.browser-inbox' }, + })); + }); + await expect(page.locator('.view-container .view-header h2')).toHaveText('Browser Inbox', { timeout: 10000 }); + await expect(browserInbox).toHaveAttribute('aria-current', 'page'); + await expect(browserInbox).toHaveClass(/is-active/); + await expect(activity).not.toHaveAttribute('aria-current', 'page'); + + await page.locator('.wt-label').filter({ hasText: 'Project' }).click(); + await expect(browserInbox).not.toHaveAttribute('aria-current', 'page'); + }); + test('Click sidebar item opens diagnostics view by view ID, not sidebar ID', async ({ page }) => { const sidebarItem = page.locator('.sidebar .plugin-item').filter({ hasText: 'Platform Test' }); await expect(sidebarItem).toBeVisible(); diff --git a/frontend/e2e/ux-p0.spec.js b/frontend/e2e/ux-p0.spec.js index 1c2c319..3ceb66a 100644 --- a/frontend/e2e/ux-p0.spec.js +++ b/frontend/e2e/ux-p0.spec.js @@ -38,6 +38,11 @@ test.describe('UX P0 shell flow', () => { await expect(page.locator('.plugin-manager')).toHaveCount(0); }); + test('Deal header does not expose the internal workspace type badge', async ({ page }) => { + await expect(page.locator('.workspace-host')).toBeVisible({ timeout: 10000 }); + await expect(page.locator('.workspace-type')).toHaveCount(0); + }); + test('status bar plugin contribution failures do not render large error panels', async ({ page }) => { await expect(page.locator('.workspace-host')).toBeVisible({ timeout: 10000 }); await expect(page.getByText('Plugin View Error')).toHaveCount(0); diff --git a/frontend/e2e/workspace-templates.spec.js b/frontend/e2e/workspace-templates.spec.js index ebf97a2..f936d9d 100644 --- a/frontend/e2e/workspace-templates.spec.js +++ b/frontend/e2e/workspace-templates.spec.js @@ -16,7 +16,7 @@ test.describe('Workspace templates', () => { }); async function openCreateModal(page) { - await page.locator('button[title="New workspace"]').click(); + await page.locator('button[title="New Deal"]').click(); const modal = page.locator('[data-workspace-create-modal]'); await expect(modal).toBeVisible(); return modal; @@ -30,18 +30,18 @@ test.describe('Workspace templates', () => { await expect(modal.locator('[data-workspace-template-tools]')).toContainText('Notes'); await expect(modal.locator('[data-workspace-template-tools]')).toContainText('Browser Inbox'); - await modal.getByRole('button', { name: 'Create workspace' }).click(); + await modal.getByRole('button', { name: 'Create Deal' }).click(); await expect(modal.locator('[data-workspace-create-error]')).toContainText('Name is required'); await modal.locator('[data-workspace-name]').fill('bad/name'); - await modal.getByRole('button', { name: 'Create workspace' }).click(); - await expect(modal.locator('[data-workspace-create-error]')).toContainText('invalid-workspace-name'); + await modal.getByRole('button', { name: 'Create Deal' }).click(); + await expect(modal.locator('[data-workspace-create-error]')).toContainText('Could not create the Deal. Please try again.'); await modal.locator('[data-workspace-name]').fill('ProjectPlan'); await modal.locator('[data-workspace-template]').selectOption('project'); await expect(modal.locator('[data-workspace-template-description]')).toContainText('Project planning'); await expect(modal.locator('[data-workspace-template-tools]')).toContainText('Todos'); - await modal.getByRole('button', { name: 'Create workspace' }).click(); + await modal.getByRole('button', { name: 'Create Deal' }).click(); await expect(page.locator('.wt-label').filter({ hasText: 'ProjectPlan' })).toBeVisible(); await expect.poll(async () => page.evaluate(async () => { @@ -65,7 +65,7 @@ test.describe('Workspace templates', () => { const modal = await openCreateModal(page); await modal.locator('[data-workspace-name]').fill('MinimalSpace'); await modal.locator('[data-workspace-template]').selectOption('minimal'); - await modal.getByRole('button', { name: 'Create workspace' }).click(); + await modal.getByRole('button', { name: 'Create Deal' }).click(); await expect(page.getByRole('tab', { name: 'Overview' })).toBeVisible(); await expect(page.getByRole('tab', { name: 'Notes' })).toBeVisible(); @@ -88,7 +88,7 @@ test.describe('Workspace templates', () => { await expect(todo).toHaveAttribute('data-template-tool-status', 'unavailable'); await modal.locator('[data-workspace-name]').fill('ProjectWithWarning'); - await modal.getByRole('button', { name: 'Create workspace' }).click(); + await modal.getByRole('button', { name: 'Create Deal' }).click(); const warning = page.locator('[data-workspace-template-warning]'); await expect(warning).toContainText('ProjectWithWarning'); @@ -100,14 +100,14 @@ test.describe('Workspace templates', () => { let modal = await openCreateModal(page); await modal.locator('[data-workspace-name]').fill('AdminSpace'); await modal.locator('[data-workspace-template]').selectOption('admin'); - await modal.getByRole('button', { name: 'Create workspace' }).click(); + await modal.getByRole('button', { name: 'Create Deal' }).click(); await expect(page.getByRole('tab', { name: 'Secrets' })).toBeVisible(); await page.evaluate(() => window.__wailsMock.setPluginStatus('verstak.todo', 'disabled', false)); modal = await openCreateModal(page); await modal.locator('[data-workspace-name]').fill('ProjectWithoutTodo'); await modal.locator('[data-workspace-template]').selectOption('project'); - await modal.getByRole('button', { name: 'Create workspace' }).click(); + await modal.getByRole('button', { name: 'Create Deal' }).click(); await expect(page.getByRole('tab', { name: 'Notes' })).toBeVisible(); await expect(page.getByRole('tab', { name: 'Files' })).toBeVisible(); diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 242c0d3..319d785 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -395,7 +395,11 @@ {:else}
- +
diff --git a/frontend/src/lib/i18n/catalogs/en.js b/frontend/src/lib/i18n/catalogs/en.js index f0f1e4e..9c87653 100644 --- a/frontend/src/lib/i18n/catalogs/en.js +++ b/frontend/src/lib/i18n/catalogs/en.js @@ -16,13 +16,13 @@ export default { 'sidebar.error.load': 'Failed to load sidebar', 'sidebar.error.ui': 'Plugin UI error', 'workspace.overview': 'Overview', - 'workspace.search': 'Workspace search', - 'workspace.tools': 'Workspace tools', - 'workspace.tool': 'Workspace tool', - 'workspace.emptyTools': 'No workspace tools available', - 'workspace.emptyToolsHint': 'Enable plugins with workspace tools or open Plugin Manager from settings.', - 'workspace.select': 'Select a workspace', - 'workspace.selectHint': 'Use the + button in Workspaces to add your first project.', + 'workspace.search': 'Search in this Deal', + 'workspace.tools': 'Deal tools', + 'workspace.tool': 'Deal tool', + 'workspace.emptyTools': 'No Deal tools available', + 'workspace.emptyToolsHint': 'Enable plugins with Deal tools or open Plugin Manager from settings.', + 'workspace.select': 'Select a Deal', + 'workspace.selectHint': 'Use the + button in Deals to add your first project.', 'common.details': 'Details', 'common.plugin': 'Plugin', 'common.component': 'Component', @@ -74,7 +74,7 @@ export default { 'pluginCard.count.sidebar': '{count} sidebar item(s)', 'pluginCard.count.statusbar': '{count} status bar item(s)', 'pluginCard.count.openProviders': '{count} openProviders', - 'pluginCard.count.workspace': '{count} workspace item(s)', + 'pluginCard.count.workspace': '{count} Deal tool(s)', 'pluginCard.degraded': 'Plugin is usable, but some optional capabilities are unavailable.', 'pluginCard.name': 'Name', 'pluginCard.contributions': 'Contributions', @@ -101,7 +101,7 @@ export default { 'vaultSelection.chooseExisting': 'Choose or enter an existing vault.', 'vaultSelection.subtitle': 'Choose a vault to start working', 'vaultSelection.createTitle': 'Create a new vault', - 'vaultSelection.createHint': 'Create a local vault folder for workspaces and projects.', + 'vaultSelection.createHint': 'Create a local vault folder for Deals and projects.', 'vaultSelection.pathPlaceholder': 'Choose or enter a path...', 'vaultSelection.creating': 'Creating...', 'vaultSelection.create': 'Create vault', @@ -112,15 +112,15 @@ export default { 'vaultSelection.recent': 'Recent vaults', 'common.cancel': 'Cancel', 'common.close': 'Close', - 'workspaceTree.title': 'Workspaces', - 'workspaceTree.new': 'New workspace', + 'workspaceTree.title': 'Deals', + 'workspaceTree.new': 'New Deal', 'workspaceTree.nameRequired': 'Name is required', - 'workspaceTree.chooseTemplate': 'Choose a workspace template', + 'workspaceTree.chooseTemplate': 'Choose a Deal template', 'workspaceTree.saveRename': 'Save rename', - 'workspaceTree.rename': 'Rename workspace', - 'workspaceTree.trash': 'Trash workspace', - 'workspaceTree.create': 'Create workspace', - 'workspaceTree.namePlaceholder': 'Workspace name', + 'workspaceTree.rename': 'Rename Deal', + 'workspaceTree.trash': 'Move Deal to trash', + 'workspaceTree.create': 'Create Deal', + 'workspaceTree.namePlaceholder': 'Deal name', 'workspaceTree.template': 'Template', 'workspaceTree.creating': 'Creating...', 'workspaceTree.templateAvailable': 'Available', @@ -167,7 +167,7 @@ export default { 'search.placeholder': 'Search', 'search.global': 'Global search', 'search.noResults': 'No results', - 'search.type.workspace': 'Workspace', + 'search.type.workspace': 'Deal', 'search.type.tool': 'Tool', 'search.type.folder': 'Folder', 'search.type.file': 'File', @@ -222,18 +222,21 @@ export default { 'overview.count.journal.many': '{count} journal entries', 'overview.count.pending.one': '{count} pending item', 'overview.count.pending.many': '{count} pending items', - 'overview.loadingContext': 'Loading workspace context...', + 'overview.loadingContext': 'Loading Deal context...', 'overview.lastActive': 'Last active {time}', - 'overview.noRecentActivity': 'No recent workspace activity', + 'overview.noRecentActivity': 'No recent Deal activity', 'overview.refresh': 'Refresh', - 'overview.summary': 'Workspace overview summary', + 'overview.summary': 'Deal overview summary', 'overview.continue': 'Continue working', - 'overview.continueHint': 'Pick up the next useful item in this workspace.', - 'overview.loadingSignals': 'Loading workspace signals...', + 'overview.continueHint': 'Pick up the next useful item in this Deal.', + 'overview.loadingSignals': 'Loading Deal signals...', 'overview.noResume': 'No clear resume point yet', 'overview.noResumeHint': 'Recent notes, files, captures, and journal entries will appear here.', 'overview.recentChanges': 'Recent changes', - 'overview.recentChangesHint': 'Latest meaningful activity in this workspace.', + 'overview.recentChangesHint': 'Latest meaningful activity in this Deal.', + 'overview.event.workspaceOpened': 'Opened Deal', + 'overview.event.activity': 'Deal activity', + 'overview.overviewNote': 'Deal overview note', 'overview.recentFilter': 'Recent changes filter', 'overview.loadingRecent': 'Loading recent changes...', 'overview.noChanges': 'No meaningful changes for this filter yet.', diff --git a/frontend/src/lib/i18n/catalogs/ru.js b/frontend/src/lib/i18n/catalogs/ru.js index dfc7491..a43c878 100644 --- a/frontend/src/lib/i18n/catalogs/ru.js +++ b/frontend/src/lib/i18n/catalogs/ru.js @@ -16,13 +16,13 @@ export default { 'sidebar.error.load': 'Не удалось загрузить боковую панель', 'sidebar.error.ui': 'Ошибка интерфейса плагина', 'workspace.overview': 'Обзор', - 'workspace.search': 'Поиск в рабочем пространстве', - 'workspace.tools': 'Инструменты рабочего пространства', - 'workspace.tool': 'Инструмент рабочего пространства', + 'workspace.search': 'Поиск в Деле', + 'workspace.tools': 'Инструменты Дела', + 'workspace.tool': 'Инструмент Дела', 'workspace.emptyTools': 'Нет доступных инструментов', - 'workspace.emptyToolsHint': 'Включите плагины с инструментами рабочего пространства или откройте Менеджер плагинов в настройках.', - 'workspace.select': 'Выберите рабочее пространство', - 'workspace.selectHint': 'Используйте кнопку + в разделе рабочих пространств, чтобы добавить первый проект.', + 'workspace.emptyToolsHint': 'Включите плагины с инструментами Дела или откройте Менеджер плагинов в настройках.', + 'workspace.select': 'Выберите Дело', + 'workspace.selectHint': 'Используйте кнопку + в разделе Дел, чтобы добавить первый проект.', 'common.details': 'Подробнее', 'common.plugin': 'Плагин', 'common.component': 'Компонент', @@ -74,7 +74,7 @@ export default { 'pluginCard.count.sidebar': 'элементов боковой панели: {count}', 'pluginCard.count.statusbar': 'элементов строки состояния: {count}', 'pluginCard.count.openProviders': 'обработчиков открытия: {count}', - 'pluginCard.count.workspace': 'инструментов рабочего пространства: {count}', + 'pluginCard.count.workspace': 'инструментов Дела: {count}', 'pluginCard.degraded': 'Плагин работает, но некоторые необязательные capabilities недоступны.', 'pluginCard.name': 'Название', 'pluginCard.contributions': 'Элементы интерфейса', @@ -101,7 +101,7 @@ export default { 'vaultSelection.chooseExisting': 'Выберите или введите существующее хранилище.', 'vaultSelection.subtitle': 'Выберите хранилище, чтобы начать работу', 'vaultSelection.createTitle': 'Создать новое хранилище', - 'vaultSelection.createHint': 'Создайте локальную папку хранилища для рабочих пространств и проектов.', + 'vaultSelection.createHint': 'Создайте локальную папку хранилища для Дел и проектов.', 'vaultSelection.pathPlaceholder': 'Выберите или введите путь...', 'vaultSelection.creating': 'Создание...', 'vaultSelection.create': 'Создать хранилище', @@ -112,15 +112,15 @@ export default { 'vaultSelection.recent': 'Недавние хранилища', 'common.cancel': 'Отмена', 'common.close': 'Закрыть', - 'workspaceTree.title': 'Рабочие пространства', - 'workspaceTree.new': 'Новое рабочее пространство', + 'workspaceTree.title': 'Дела', + 'workspaceTree.new': 'Новое Дело', 'workspaceTree.nameRequired': 'Введите название', - 'workspaceTree.chooseTemplate': 'Выберите шаблон рабочего пространства', + 'workspaceTree.chooseTemplate': 'Выберите шаблон Дела', 'workspaceTree.saveRename': 'Сохранить новое название', - 'workspaceTree.rename': 'Переименовать рабочее пространство', - 'workspaceTree.trash': 'Переместить рабочее пространство в корзину', - 'workspaceTree.create': 'Создать рабочее пространство', - 'workspaceTree.namePlaceholder': 'Название рабочего пространства', + 'workspaceTree.rename': 'Переименовать Дело', + 'workspaceTree.trash': 'Переместить Дело в корзину', + 'workspaceTree.create': 'Создать Дело', + 'workspaceTree.namePlaceholder': 'Название Дела', 'workspaceTree.template': 'Шаблон', 'workspaceTree.creating': 'Создание...', 'workspaceTree.templateAvailable': 'Доступен', @@ -167,7 +167,7 @@ export default { 'search.placeholder': 'Поиск', 'search.global': 'Глобальный поиск', 'search.noResults': 'Ничего не найдено', - 'search.type.workspace': 'Рабочее пространство', + 'search.type.workspace': 'Дело', 'search.type.tool': 'Инструмент', 'search.type.folder': 'Папка', 'search.type.file': 'Файл', @@ -222,18 +222,21 @@ export default { 'overview.count.journal.many': 'Записей журнала: {count}', 'overview.count.pending.one': 'Ожидают: {count}', 'overview.count.pending.many': 'Ожидают: {count}', - 'overview.loadingContext': 'Загрузка данных рабочего пространства...', + 'overview.loadingContext': 'Загрузка данных Дела...', 'overview.lastActive': 'Последняя активность: {time}', - 'overview.noRecentActivity': 'В рабочем пространстве пока нет недавней активности', + 'overview.noRecentActivity': 'В Деле пока нет недавней активности', 'overview.refresh': 'Обновить', - 'overview.summary': 'Сводка рабочего пространства', + 'overview.summary': 'Сводка Дела', 'overview.continue': 'Продолжить работу', - 'overview.continueHint': 'Вернитесь к следующему полезному делу в этом рабочем пространстве.', - 'overview.loadingSignals': 'Загрузка рабочих данных...', + 'overview.continueHint': 'Вернитесь к следующему полезному делу в этом Деле.', + 'overview.loadingSignals': 'Загрузка данных Дела...', 'overview.noResume': 'Пока неясно, с чего продолжить', 'overview.noResumeHint': 'Здесь появятся недавние заметки, файлы, сохранённое и записи журнала.', 'overview.recentChanges': 'Недавние изменения', - 'overview.recentChangesHint': 'Последняя важная активность в этом рабочем пространстве.', + 'overview.recentChangesHint': 'Последняя важная активность в этом Деле.', + 'overview.event.workspaceOpened': 'Открыто Дело', + 'overview.event.activity': 'Активность Дела', + 'overview.overviewNote': 'Обзорная заметка Дела', 'overview.recentFilter': 'Фильтр недавних изменений', 'overview.loadingRecent': 'Загрузка недавних изменений...', 'overview.noChanges': 'Для этого фильтра пока нет важных изменений.', diff --git a/frontend/src/lib/shell/Sidebar.svelte b/frontend/src/lib/shell/Sidebar.svelte index f9529a8..35178b3 100644 --- a/frontend/src/lib/shell/Sidebar.svelte +++ b/frontend/src/lib/shell/Sidebar.svelte @@ -8,6 +8,8 @@ import { i18n } from '../i18n/index.js'; export let showGlobalSearch = true; + export let activeView = null; + export let activeViewPluginId = ''; function flog(msg) { App.WriteFrontendLog('Sidebar', msg); @@ -26,6 +28,7 @@ })(locale); $: vaultOpen = vaultStatus.status === 'open'; + $: activeSidebarKey = activeView ? `${activeViewPluginId}:${activeView}` : ''; async function loadSidebar() { debug.log('[Sidebar] onMount: START'); @@ -107,6 +110,8 @@ {#each sidebarItems as item}