fix: use Deal terminology in desktop shell

This commit is contained in:
mirivlad 2026-07-14 22:18:52 +08:00
parent dbef71f830
commit 5cad11f3f9
10 changed files with 143 additions and 68 deletions

View File

@ -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 }); 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 }) => { 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' }); const sidebarItem = page.locator('.sidebar .plugin-item').filter({ hasText: 'Platform Test' });
await expect(sidebarItem).toBeVisible(); await expect(sidebarItem).toBeVisible();

View File

@ -38,6 +38,11 @@ test.describe('UX P0 shell flow', () => {
await expect(page.locator('.plugin-manager')).toHaveCount(0); 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 }) => { 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.locator('.workspace-host')).toBeVisible({ timeout: 10000 });
await expect(page.getByText('Plugin View Error')).toHaveCount(0); await expect(page.getByText('Plugin View Error')).toHaveCount(0);

View File

@ -16,7 +16,7 @@ test.describe('Workspace templates', () => {
}); });
async function openCreateModal(page) { 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]'); const modal = page.locator('[data-workspace-create-modal]');
await expect(modal).toBeVisible(); await expect(modal).toBeVisible();
return modal; 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('Notes');
await expect(modal.locator('[data-workspace-template-tools]')).toContainText('Browser Inbox'); 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 expect(modal.locator('[data-workspace-create-error]')).toContainText('Name is required');
await modal.locator('[data-workspace-name]').fill('bad/name'); await modal.locator('[data-workspace-name]').fill('bad/name');
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('invalid-workspace-name'); 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-name]').fill('ProjectPlan');
await modal.locator('[data-workspace-template]').selectOption('project'); 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-description]')).toContainText('Project planning');
await expect(modal.locator('[data-workspace-template-tools]')).toContainText('Todos'); 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(page.locator('.wt-label').filter({ hasText: 'ProjectPlan' })).toBeVisible();
await expect.poll(async () => page.evaluate(async () => { await expect.poll(async () => page.evaluate(async () => {
@ -65,7 +65,7 @@ test.describe('Workspace templates', () => {
const modal = await openCreateModal(page); const modal = await openCreateModal(page);
await modal.locator('[data-workspace-name]').fill('MinimalSpace'); await modal.locator('[data-workspace-name]').fill('MinimalSpace');
await modal.locator('[data-workspace-template]').selectOption('minimal'); 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: 'Overview' })).toBeVisible();
await expect(page.getByRole('tab', { name: 'Notes' })).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 expect(todo).toHaveAttribute('data-template-tool-status', 'unavailable');
await modal.locator('[data-workspace-name]').fill('ProjectWithWarning'); 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]'); const warning = page.locator('[data-workspace-template-warning]');
await expect(warning).toContainText('ProjectWithWarning'); await expect(warning).toContainText('ProjectWithWarning');
@ -100,14 +100,14 @@ test.describe('Workspace templates', () => {
let modal = await openCreateModal(page); let modal = await openCreateModal(page);
await modal.locator('[data-workspace-name]').fill('AdminSpace'); await modal.locator('[data-workspace-name]').fill('AdminSpace');
await modal.locator('[data-workspace-template]').selectOption('admin'); 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 expect(page.getByRole('tab', { name: 'Secrets' })).toBeVisible();
await page.evaluate(() => window.__wailsMock.setPluginStatus('verstak.todo', 'disabled', false)); await page.evaluate(() => window.__wailsMock.setPluginStatus('verstak.todo', 'disabled', false));
modal = await openCreateModal(page); modal = await openCreateModal(page);
await modal.locator('[data-workspace-name]').fill('ProjectWithoutTodo'); await modal.locator('[data-workspace-name]').fill('ProjectWithoutTodo');
await modal.locator('[data-workspace-template]').selectOption('project'); 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: 'Notes' })).toBeVisible();
await expect(page.getByRole('tab', { name: 'Files' })).toBeVisible(); await expect(page.getByRole('tab', { name: 'Files' })).toBeVisible();

View File

@ -395,7 +395,11 @@
<VaultSelection /> <VaultSelection />
{:else} {:else}
<main> <main>
<Sidebar showGlobalSearch={currentView !== 'workspace' && currentView !== 'workspace-empty'} /> <Sidebar
showGlobalSearch={currentView !== 'workspace' && currentView !== 'workspace-empty'}
{activeView}
{activeViewPluginId}
/>
<CommandPalette /> <CommandPalette />
<section class="content-shell"> <section class="content-shell">

View File

@ -16,13 +16,13 @@ export default {
'sidebar.error.load': 'Failed to load sidebar', 'sidebar.error.load': 'Failed to load sidebar',
'sidebar.error.ui': 'Plugin UI error', 'sidebar.error.ui': 'Plugin UI error',
'workspace.overview': 'Overview', 'workspace.overview': 'Overview',
'workspace.search': 'Workspace search', 'workspace.search': 'Search in this Deal',
'workspace.tools': 'Workspace tools', 'workspace.tools': 'Deal tools',
'workspace.tool': 'Workspace tool', 'workspace.tool': 'Deal tool',
'workspace.emptyTools': 'No workspace tools available', 'workspace.emptyTools': 'No Deal tools available',
'workspace.emptyToolsHint': 'Enable plugins with workspace tools or open Plugin Manager from settings.', 'workspace.emptyToolsHint': 'Enable plugins with Deal tools or open Plugin Manager from settings.',
'workspace.select': 'Select a workspace', 'workspace.select': 'Select a Deal',
'workspace.selectHint': 'Use the + button in Workspaces to add your first project.', 'workspace.selectHint': 'Use the + button in Deals to add your first project.',
'common.details': 'Details', 'common.details': 'Details',
'common.plugin': 'Plugin', 'common.plugin': 'Plugin',
'common.component': 'Component', 'common.component': 'Component',
@ -74,7 +74,7 @@ export default {
'pluginCard.count.sidebar': '{count} sidebar item(s)', 'pluginCard.count.sidebar': '{count} sidebar item(s)',
'pluginCard.count.statusbar': '{count} status bar item(s)', 'pluginCard.count.statusbar': '{count} status bar item(s)',
'pluginCard.count.openProviders': '{count} openProviders', '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.degraded': 'Plugin is usable, but some optional capabilities are unavailable.',
'pluginCard.name': 'Name', 'pluginCard.name': 'Name',
'pluginCard.contributions': 'Contributions', 'pluginCard.contributions': 'Contributions',
@ -101,7 +101,7 @@ export default {
'vaultSelection.chooseExisting': 'Choose or enter an existing vault.', 'vaultSelection.chooseExisting': 'Choose or enter an existing vault.',
'vaultSelection.subtitle': 'Choose a vault to start working', 'vaultSelection.subtitle': 'Choose a vault to start working',
'vaultSelection.createTitle': 'Create a new vault', '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.pathPlaceholder': 'Choose or enter a path...',
'vaultSelection.creating': 'Creating...', 'vaultSelection.creating': 'Creating...',
'vaultSelection.create': 'Create vault', 'vaultSelection.create': 'Create vault',
@ -112,15 +112,15 @@ export default {
'vaultSelection.recent': 'Recent vaults', 'vaultSelection.recent': 'Recent vaults',
'common.cancel': 'Cancel', 'common.cancel': 'Cancel',
'common.close': 'Close', 'common.close': 'Close',
'workspaceTree.title': 'Workspaces', 'workspaceTree.title': 'Deals',
'workspaceTree.new': 'New workspace', 'workspaceTree.new': 'New Deal',
'workspaceTree.nameRequired': 'Name is required', 'workspaceTree.nameRequired': 'Name is required',
'workspaceTree.chooseTemplate': 'Choose a workspace template', 'workspaceTree.chooseTemplate': 'Choose a Deal template',
'workspaceTree.saveRename': 'Save rename', 'workspaceTree.saveRename': 'Save rename',
'workspaceTree.rename': 'Rename workspace', 'workspaceTree.rename': 'Rename Deal',
'workspaceTree.trash': 'Trash workspace', 'workspaceTree.trash': 'Move Deal to trash',
'workspaceTree.create': 'Create workspace', 'workspaceTree.create': 'Create Deal',
'workspaceTree.namePlaceholder': 'Workspace name', 'workspaceTree.namePlaceholder': 'Deal name',
'workspaceTree.template': 'Template', 'workspaceTree.template': 'Template',
'workspaceTree.creating': 'Creating...', 'workspaceTree.creating': 'Creating...',
'workspaceTree.templateAvailable': 'Available', 'workspaceTree.templateAvailable': 'Available',
@ -167,7 +167,7 @@ export default {
'search.placeholder': 'Search', 'search.placeholder': 'Search',
'search.global': 'Global search', 'search.global': 'Global search',
'search.noResults': 'No results', 'search.noResults': 'No results',
'search.type.workspace': 'Workspace', 'search.type.workspace': 'Deal',
'search.type.tool': 'Tool', 'search.type.tool': 'Tool',
'search.type.folder': 'Folder', 'search.type.folder': 'Folder',
'search.type.file': 'File', 'search.type.file': 'File',
@ -222,18 +222,21 @@ export default {
'overview.count.journal.many': '{count} journal entries', 'overview.count.journal.many': '{count} journal entries',
'overview.count.pending.one': '{count} pending item', 'overview.count.pending.one': '{count} pending item',
'overview.count.pending.many': '{count} pending items', 'overview.count.pending.many': '{count} pending items',
'overview.loadingContext': 'Loading workspace context...', 'overview.loadingContext': 'Loading Deal context...',
'overview.lastActive': 'Last active {time}', 'overview.lastActive': 'Last active {time}',
'overview.noRecentActivity': 'No recent workspace activity', 'overview.noRecentActivity': 'No recent Deal activity',
'overview.refresh': 'Refresh', 'overview.refresh': 'Refresh',
'overview.summary': 'Workspace overview summary', 'overview.summary': 'Deal overview summary',
'overview.continue': 'Continue working', 'overview.continue': 'Continue working',
'overview.continueHint': 'Pick up the next useful item in this workspace.', 'overview.continueHint': 'Pick up the next useful item in this Deal.',
'overview.loadingSignals': 'Loading workspace signals...', 'overview.loadingSignals': 'Loading Deal signals...',
'overview.noResume': 'No clear resume point yet', 'overview.noResume': 'No clear resume point yet',
'overview.noResumeHint': 'Recent notes, files, captures, and journal entries will appear here.', 'overview.noResumeHint': 'Recent notes, files, captures, and journal entries will appear here.',
'overview.recentChanges': 'Recent changes', '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.recentFilter': 'Recent changes filter',
'overview.loadingRecent': 'Loading recent changes...', 'overview.loadingRecent': 'Loading recent changes...',
'overview.noChanges': 'No meaningful changes for this filter yet.', 'overview.noChanges': 'No meaningful changes for this filter yet.',

View File

@ -16,13 +16,13 @@ export default {
'sidebar.error.load': 'Не удалось загрузить боковую панель', 'sidebar.error.load': 'Не удалось загрузить боковую панель',
'sidebar.error.ui': 'Ошибка интерфейса плагина', 'sidebar.error.ui': 'Ошибка интерфейса плагина',
'workspace.overview': 'Обзор', 'workspace.overview': 'Обзор',
'workspace.search': 'Поиск в рабочем пространстве', 'workspace.search': 'Поиск в Деле',
'workspace.tools': 'Инструменты рабочего пространства', 'workspace.tools': 'Инструменты Дела',
'workspace.tool': 'Инструмент рабочего пространства', 'workspace.tool': 'Инструмент Дела',
'workspace.emptyTools': 'Нет доступных инструментов', 'workspace.emptyTools': 'Нет доступных инструментов',
'workspace.emptyToolsHint': 'Включите плагины с инструментами рабочего пространства или откройте Менеджер плагинов в настройках.', 'workspace.emptyToolsHint': 'Включите плагины с инструментами Дела или откройте Менеджер плагинов в настройках.',
'workspace.select': 'Выберите рабочее пространство', 'workspace.select': 'Выберите Дело',
'workspace.selectHint': 'Используйте кнопку + в разделе рабочих пространств, чтобы добавить первый проект.', 'workspace.selectHint': 'Используйте кнопку + в разделе Дел, чтобы добавить первый проект.',
'common.details': 'Подробнее', 'common.details': 'Подробнее',
'common.plugin': 'Плагин', 'common.plugin': 'Плагин',
'common.component': 'Компонент', 'common.component': 'Компонент',
@ -74,7 +74,7 @@ export default {
'pluginCard.count.sidebar': 'элементов боковой панели: {count}', 'pluginCard.count.sidebar': 'элементов боковой панели: {count}',
'pluginCard.count.statusbar': 'элементов строки состояния: {count}', 'pluginCard.count.statusbar': 'элементов строки состояния: {count}',
'pluginCard.count.openProviders': 'обработчиков открытия: {count}', 'pluginCard.count.openProviders': 'обработчиков открытия: {count}',
'pluginCard.count.workspace': 'инструментов рабочего пространства: {count}', 'pluginCard.count.workspace': 'инструментов Дела: {count}',
'pluginCard.degraded': 'Плагин работает, но некоторые необязательные capabilities недоступны.', 'pluginCard.degraded': 'Плагин работает, но некоторые необязательные capabilities недоступны.',
'pluginCard.name': 'Название', 'pluginCard.name': 'Название',
'pluginCard.contributions': 'Элементы интерфейса', 'pluginCard.contributions': 'Элементы интерфейса',
@ -101,7 +101,7 @@ export default {
'vaultSelection.chooseExisting': 'Выберите или введите существующее хранилище.', 'vaultSelection.chooseExisting': 'Выберите или введите существующее хранилище.',
'vaultSelection.subtitle': 'Выберите хранилище, чтобы начать работу', 'vaultSelection.subtitle': 'Выберите хранилище, чтобы начать работу',
'vaultSelection.createTitle': 'Создать новое хранилище', 'vaultSelection.createTitle': 'Создать новое хранилище',
'vaultSelection.createHint': 'Создайте локальную папку хранилища для рабочих пространств и проектов.', 'vaultSelection.createHint': 'Создайте локальную папку хранилища для Дел и проектов.',
'vaultSelection.pathPlaceholder': 'Выберите или введите путь...', 'vaultSelection.pathPlaceholder': 'Выберите или введите путь...',
'vaultSelection.creating': 'Создание...', 'vaultSelection.creating': 'Создание...',
'vaultSelection.create': 'Создать хранилище', 'vaultSelection.create': 'Создать хранилище',
@ -112,15 +112,15 @@ export default {
'vaultSelection.recent': 'Недавние хранилища', 'vaultSelection.recent': 'Недавние хранилища',
'common.cancel': 'Отмена', 'common.cancel': 'Отмена',
'common.close': 'Закрыть', 'common.close': 'Закрыть',
'workspaceTree.title': 'Рабочие пространства', 'workspaceTree.title': 'Дела',
'workspaceTree.new': 'Новое рабочее пространство', 'workspaceTree.new': 'Новое Дело',
'workspaceTree.nameRequired': 'Введите название', 'workspaceTree.nameRequired': 'Введите название',
'workspaceTree.chooseTemplate': 'Выберите шаблон рабочего пространства', 'workspaceTree.chooseTemplate': 'Выберите шаблон Дела',
'workspaceTree.saveRename': 'Сохранить новое название', 'workspaceTree.saveRename': 'Сохранить новое название',
'workspaceTree.rename': 'Переименовать рабочее пространство', 'workspaceTree.rename': 'Переименовать Дело',
'workspaceTree.trash': 'Переместить рабочее пространство в корзину', 'workspaceTree.trash': 'Переместить Дело в корзину',
'workspaceTree.create': 'Создать рабочее пространство', 'workspaceTree.create': 'Создать Дело',
'workspaceTree.namePlaceholder': 'Название рабочего пространства', 'workspaceTree.namePlaceholder': 'Название Дела',
'workspaceTree.template': 'Шаблон', 'workspaceTree.template': 'Шаблон',
'workspaceTree.creating': 'Создание...', 'workspaceTree.creating': 'Создание...',
'workspaceTree.templateAvailable': 'Доступен', 'workspaceTree.templateAvailable': 'Доступен',
@ -167,7 +167,7 @@ export default {
'search.placeholder': 'Поиск', 'search.placeholder': 'Поиск',
'search.global': 'Глобальный поиск', 'search.global': 'Глобальный поиск',
'search.noResults': 'Ничего не найдено', 'search.noResults': 'Ничего не найдено',
'search.type.workspace': 'Рабочее пространство', 'search.type.workspace': 'Дело',
'search.type.tool': 'Инструмент', 'search.type.tool': 'Инструмент',
'search.type.folder': 'Папка', 'search.type.folder': 'Папка',
'search.type.file': 'Файл', 'search.type.file': 'Файл',
@ -222,18 +222,21 @@ export default {
'overview.count.journal.many': 'Записей журнала: {count}', 'overview.count.journal.many': 'Записей журнала: {count}',
'overview.count.pending.one': 'Ожидают: {count}', 'overview.count.pending.one': 'Ожидают: {count}',
'overview.count.pending.many': 'Ожидают: {count}', 'overview.count.pending.many': 'Ожидают: {count}',
'overview.loadingContext': 'Загрузка данных рабочего пространства...', 'overview.loadingContext': 'Загрузка данных Дела...',
'overview.lastActive': 'Последняя активность: {time}', 'overview.lastActive': 'Последняя активность: {time}',
'overview.noRecentActivity': 'В рабочем пространстве пока нет недавней активности', 'overview.noRecentActivity': 'В Деле пока нет недавней активности',
'overview.refresh': 'Обновить', 'overview.refresh': 'Обновить',
'overview.summary': 'Сводка рабочего пространства', 'overview.summary': 'Сводка Дела',
'overview.continue': 'Продолжить работу', 'overview.continue': 'Продолжить работу',
'overview.continueHint': 'Вернитесь к следующему полезному делу в этом рабочем пространстве.', 'overview.continueHint': 'Вернитесь к следующему полезному делу в этом Деле.',
'overview.loadingSignals': 'Загрузка рабочих данных...', 'overview.loadingSignals': 'Загрузка данных Дела...',
'overview.noResume': 'Пока неясно, с чего продолжить', 'overview.noResume': 'Пока неясно, с чего продолжить',
'overview.noResumeHint': 'Здесь появятся недавние заметки, файлы, сохранённое и записи журнала.', 'overview.noResumeHint': 'Здесь появятся недавние заметки, файлы, сохранённое и записи журнала.',
'overview.recentChanges': 'Недавние изменения', 'overview.recentChanges': 'Недавние изменения',
'overview.recentChangesHint': 'Последняя важная активность в этом рабочем пространстве.', 'overview.recentChangesHint': 'Последняя важная активность в этом Деле.',
'overview.event.workspaceOpened': 'Открыто Дело',
'overview.event.activity': 'Активность Дела',
'overview.overviewNote': 'Обзорная заметка Дела',
'overview.recentFilter': 'Фильтр недавних изменений', 'overview.recentFilter': 'Фильтр недавних изменений',
'overview.loadingRecent': 'Загрузка недавних изменений...', 'overview.loadingRecent': 'Загрузка недавних изменений...',
'overview.noChanges': 'Для этого фильтра пока нет важных изменений.', 'overview.noChanges': 'Для этого фильтра пока нет важных изменений.',

View File

@ -8,6 +8,8 @@
import { i18n } from '../i18n/index.js'; import { i18n } from '../i18n/index.js';
export let showGlobalSearch = true; export let showGlobalSearch = true;
export let activeView = null;
export let activeViewPluginId = '';
function flog(msg) { function flog(msg) {
App.WriteFrontendLog('Sidebar', msg); App.WriteFrontendLog('Sidebar', msg);
@ -26,6 +28,7 @@
})(locale); })(locale);
$: vaultOpen = vaultStatus.status === 'open'; $: vaultOpen = vaultStatus.status === 'open';
$: activeSidebarKey = activeView ? `${activeViewPluginId}:${activeView}` : '';
async function loadSidebar() { async function loadSidebar() {
debug.log('[Sidebar] onMount: START'); debug.log('[Sidebar] onMount: START');
@ -107,6 +110,8 @@
{#each sidebarItems as item} {#each sidebarItems as item}
<button <button
class="nav-item plugin-item vt-list-row" class="nav-item plugin-item vt-list-row"
class:is-active={activeSidebarKey === `${item.pluginId || ''}:${item.view || item.id}`}
aria-current={activeSidebarKey === `${item.pluginId || ''}:${item.view || item.id}` ? 'page' : undefined}
on:click={() => handleSidebarItem(item)} on:click={() => handleSidebarItem(item)}
type="button" type="button"
> >
@ -210,6 +215,16 @@
color: var(--vt-color-text-primary); color: var(--vt-color-text-primary);
} }
.nav-item.is-active {
background: var(--vt-color-surface-selected);
color: var(--vt-color-accent);
}
.nav-item.is-active :global(.nav-icon.icon-plugin) {
color: currentColor;
opacity: 1;
}
:global(.nav-icon) { :global(.nav-icon) {
width: 0.9rem; width: 0.9rem;
height: 0.9rem; height: 0.9rem;

View File

@ -326,8 +326,8 @@
if (type === 'browser.capture.converted') return `Converted capture ${quoted(name)}`; if (type === 'browser.capture.converted') return `Converted capture ${quoted(name)}`;
if (type === 'journal.entry.added' || type === 'worklog.entry.added') return `Added journal entry ${quoted(name)}`; if (type === 'journal.entry.added' || type === 'worklog.entry.added') return `Added journal entry ${quoted(name)}`;
if (type === 'action.started') return 'Work session detected'; if (type === 'action.started') return 'Work session detected';
if (type === 'workspace.opened') return 'Workspace opened'; if (type === 'workspace.opened') return tr('overview.event.workspaceOpened');
return item?.title || item?.summary || 'Workspace activity'; return item?.title || item?.summary || tr('overview.event.activity');
} }
function actionForCategory(category) { function actionForCategory(category) {
@ -519,7 +519,7 @@
keyResources: overview ? [{ keyResources: overview ? [{
id: overview.relativePath || overview.name, id: overview.relativePath || overview.name,
title: overview.name || fileName(overview.relativePath) || 'Overview.md', title: overview.name || fileName(overview.relativePath) || 'Overview.md',
meta: overview.relativePath || 'Workspace overview note', meta: overview.relativePath || tr('overview.overviewNote'),
actionKind: toolState.notes ? 'notes' : 'files', actionKind: toolState.notes ? 'notes' : 'files',
actionLabel: toolState.notes ? tr('overview.openNotes') : tr('overview.openFiles'), actionLabel: toolState.notes ? tr('overview.openNotes') : tr('overview.openFiles'),
}] : [], }] : [],

View File

@ -45,7 +45,6 @@
$: workspaceRootPath = selectedWorkspace?.rootPath || selectedWorkspace?.name || selectedWorkspace?.id || ''; $: workspaceRootPath = selectedWorkspace?.rootPath || selectedWorkspace?.name || selectedWorkspace?.id || '';
$: workspaceId = selectedWorkspace?.workspaceId || ''; $: workspaceId = selectedWorkspace?.workspaceId || '';
$: workspaceTitle = selectedWorkspace?.title || selectedWorkspace?.name || selectedWorkspace?.id || selectedWorkspaceName; $: workspaceTitle = selectedWorkspace?.title || selectedWorkspace?.name || selectedWorkspace?.id || selectedWorkspaceName;
$: workspaceType = selectedWorkspace?.type || 'workspace';
$: if (workspaceRootPath !== metadataWorkspaceRoot) { $: if (workspaceRootPath !== metadataWorkspaceRoot) {
metadataWorkspaceRoot = workspaceRootPath; metadataWorkspaceRoot = workspaceRootPath;
workspaceMetadata = null; workspaceMetadata = null;
@ -207,7 +206,6 @@
<div class="workspace-header vt-page-header"> <div class="workspace-header vt-page-header">
<div class="workspace-title-group"> <div class="workspace-title-group">
<span class="workspace-title vt-page-title">{workspaceTitle}</span> <span class="workspace-title vt-page-title">{workspaceTitle}</span>
<span class="workspace-type vt-badge accent">{workspaceType}</span>
</div> </div>
<div class="workspace-search" aria-label={tr('workspace.search')}> <div class="workspace-search" aria-label={tr('workspace.search')}>
<GlobalSearch /> <GlobalSearch />
@ -294,14 +292,6 @@
font-weight: 600; font-weight: 600;
} }
.workspace-type {
color: var(--vt-color-accent);
font-size: 0.75rem;
padding: 0.1rem 0.4rem;
border-radius: var(--vt-radius-sm);
background: var(--vt-color-accent-muted);
}
.workspace-search { .workspace-search {
width: min(27rem, 46vw); width: min(27rem, 46vw);
min-width: 16rem; min-width: 16rem;

View File

@ -0,0 +1,28 @@
import en from '../src/lib/i18n/catalogs/en.js';
import ru from '../src/lib/i18n/catalogs/ru.js';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const forbidden = [
['English catalog', /\bworkspace(?:s)?\b/i],
['Russian catalog', /рабоч(?:ее|ие|ем|его|их)\s+пространств(?:о|а|е)?/i],
];
for (const [name, pattern] of forbidden) {
const violations = Object.entries(name === 'English catalog' ? en : ru)
.filter(([, value]) => pattern.test(value));
if (violations.length) {
throw new Error(`${name} still exposes workspace terminology: ${violations.map(([key]) => key).join(', ')}`);
}
}
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const overview = fs.readFileSync(path.join(root, 'src/lib/shell/TodaySurface.svelte'), 'utf8');
for (const phrase of ['Workspace opened', 'Workspace activity', 'Workspace overview note']) {
if (overview.includes(phrase)) {
throw new Error(`Overview exposes workspace terminology: ${phrase}`);
}
}
console.log('desktop user terminology uses Deal/Дело');