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}