diff --git a/frontend/e2e/command-palette.spec.js b/frontend/e2e/command-palette.spec.js index 29b63ce..e5f76f7 100644 --- a/frontend/e2e/command-palette.spec.js +++ b/frontend/e2e/command-palette.spec.js @@ -124,4 +124,20 @@ test.describe('Command Palette', () => { await expect(page.locator('.modal[aria-label="Plugin Settings"]')).toBeVisible({ timeout: 10000 }); await expect(page.locator('.modal-header h3')).toContainText('Sync'); }); + + test('keeps technical command failures out of the palette status', async ({ page }) => { + await page.evaluate(() => { + window.go.api.App.PluginSyncNow = () => Promise.resolve('[plugin:verstak.sync] sync.now failed: internal service code 42'); + }); + + await page.keyboard.press(process.platform === 'darwin' ? 'Meta+K' : 'Control+K'); + const palette = page.locator('.command-palette'); + await palette.locator('[data-command-palette-input]').fill('sync now'); + await page.keyboard.press('Enter'); + + const status = page.locator('[data-command-palette-status="error"]'); + await expect(status).toContainText('Could not run Sync Now. Please try again.'); + await expect(status).not.toContainText('[plugin:'); + await expect(status).not.toContainText('sync.now'); + }); }); diff --git a/frontend/src/lib/i18n/catalogs/en.js b/frontend/src/lib/i18n/catalogs/en.js index f1ac9b1..f0f1e4e 100644 --- a/frontend/src/lib/i18n/catalogs/en.js +++ b/frontend/src/lib/i18n/catalogs/en.js @@ -96,8 +96,8 @@ export default { 'common.loading': 'Loading...', 'common.browse': 'Browse...', 'vaultSelection.chooseNew': 'Choose or enter a folder for the new vault.', - 'vaultSelection.createError': 'Could not create vault: {error}', - 'vaultSelection.openError': 'Could not open vault: {error}', + 'vaultSelection.createError': 'Could not create the vault. Please try again.', + 'vaultSelection.openError': 'Could not open the vault. Please try again.', 'vaultSelection.chooseExisting': 'Choose or enter an existing vault.', 'vaultSelection.subtitle': 'Choose a vault to start working', 'vaultSelection.createTitle': 'Create a new vault', @@ -135,6 +135,18 @@ export default { 'workspaceTree.templateToolNoTabs': 'No Deal tab provided', 'workspaceTree.templateWillBeIncomplete': 'This Deal will be created without the unavailable components.', 'workspaceTree.templateIncompleteCreated': '«{name}» was created with unavailable components.', + 'workspaceTree.templatesError': 'Could not load Deal templates. Please try again.', + 'workspaceTree.loadError': 'Could not load Deals. Please try again.', + 'workspaceTree.selectError': 'Could not select this Deal. Please try again.', + 'workspaceTree.createError': 'Could not create the Deal. Please try again.', + 'workspaceTree.renameError': 'Could not rename the Deal. Please try again.', + 'workspaceTree.trashError': 'Could not move the Deal to trash. Please try again.', + 'pluginManager.loadError': 'Could not load plugins. Please try again.', + 'pluginManager.reloadError': 'Could not reload plugins. Please try again.', + 'pluginManager.enableError': 'Could not enable the plugin. Please try again.', + 'pluginManager.disableError': 'Could not disable the plugin. Please try again.', + 'pluginManager.settingsLoadError': 'Could not load plugin settings. Please try again.', + 'pluginManager.settingsUnavailable': 'Plugin settings are unavailable.', 'command.openOverview': 'Open Overview', 'command.openFiles': 'Open Files', 'command.openActivity': 'Open Activity', @@ -146,6 +158,7 @@ export default { 'command.openPluginManager': 'Open Plugin Manager', 'command.handled': '{title} handled', 'command.result': '{title} {status}', + 'command.failed': 'Could not run {title}. Please try again.', 'command.statusHandled': 'handled', 'command.palette': 'Command Palette', 'command.run': 'Run command', @@ -166,14 +179,14 @@ export default { 'workbench.noResource': 'No resource opened', 'bundle.noFrontend': 'Plugin has no frontend bundle', 'bundle.notFound': 'Plugin not found', - 'bundle.loadFailed': 'Failed to load bundle: {error}', + 'bundle.loadFailed': 'Could not load the plugin interface. Please try again.', 'bundle.emptyContent': 'empty content', - 'bundle.executionError': 'Bundle execution error: {error}', + 'bundle.executionError': 'Could not start the plugin interface. Please try again.', 'bundle.registrationMissing': 'Bundle loaded but no VerstakPluginRegister call detected', - 'bundle.componentMissing': 'Component "{component}" not found in bundle. Available: {available}', - 'bundle.mountError': 'Component mount error: {error}', + 'bundle.componentMissing': 'The requested plugin interface is unavailable.', + 'bundle.mountError': 'Could not open the plugin interface. Please try again.', 'bundle.mountUnavailable': 'Mount container not available', - 'bundle.unexpectedError': 'Unexpected error: {error}', + 'bundle.unexpectedError': 'Could not open the plugin interface. Please try again.', 'bundle.unknownError': 'Unknown error', 'bundle.frontendEntry': 'Frontend entry', 'bundle.availableComponents': 'Available components', diff --git a/frontend/src/lib/i18n/catalogs/ru.js b/frontend/src/lib/i18n/catalogs/ru.js index e34e3d0..dfc7491 100644 --- a/frontend/src/lib/i18n/catalogs/ru.js +++ b/frontend/src/lib/i18n/catalogs/ru.js @@ -96,8 +96,8 @@ export default { 'common.loading': 'Загрузка...', 'common.browse': 'Обзор...', 'vaultSelection.chooseNew': 'Выберите или введите папку для нового хранилища.', - 'vaultSelection.createError': 'Не удалось создать хранилище: {error}', - 'vaultSelection.openError': 'Не удалось открыть хранилище: {error}', + 'vaultSelection.createError': 'Не удалось создать хранилище. Повторите попытку.', + 'vaultSelection.openError': 'Не удалось открыть хранилище. Повторите попытку.', 'vaultSelection.chooseExisting': 'Выберите или введите существующее хранилище.', 'vaultSelection.subtitle': 'Выберите хранилище, чтобы начать работу', 'vaultSelection.createTitle': 'Создать новое хранилище', @@ -135,6 +135,18 @@ export default { 'workspaceTree.templateToolNoTabs': 'Не предоставляет вкладку Дела', 'workspaceTree.templateWillBeIncomplete': 'Дело будет создано без недоступных компонентов.', 'workspaceTree.templateIncompleteCreated': 'Дело «{name}» создано с недоступными компонентами.', + 'workspaceTree.templatesError': 'Не удалось загрузить шаблоны Дел. Повторите попытку.', + 'workspaceTree.loadError': 'Не удалось загрузить Дела. Повторите попытку.', + 'workspaceTree.selectError': 'Не удалось выбрать это Дело. Повторите попытку.', + 'workspaceTree.createError': 'Не удалось создать Дело. Повторите попытку.', + 'workspaceTree.renameError': 'Не удалось переименовать Дело. Повторите попытку.', + 'workspaceTree.trashError': 'Не удалось переместить Дело в корзину. Повторите попытку.', + 'pluginManager.loadError': 'Не удалось загрузить плагины. Повторите попытку.', + 'pluginManager.reloadError': 'Не удалось перезагрузить плагины. Повторите попытку.', + 'pluginManager.enableError': 'Не удалось включить плагин. Повторите попытку.', + 'pluginManager.disableError': 'Не удалось выключить плагин. Повторите попытку.', + 'pluginManager.settingsLoadError': 'Не удалось загрузить настройки плагина. Повторите попытку.', + 'pluginManager.settingsUnavailable': 'Настройки плагина недоступны.', 'command.openOverview': 'Открыть обзор', 'command.openFiles': 'Открыть файлы', 'command.openActivity': 'Открыть активность', @@ -146,6 +158,7 @@ export default { 'command.openPluginManager': 'Открыть менеджер плагинов', 'command.handled': 'Выполнено: {title}', 'command.result': '{title}: {status}', + 'command.failed': 'Не удалось выполнить команду «{title}». Повторите попытку.', 'command.statusHandled': 'выполнено', 'command.palette': 'Палитра команд', 'command.run': 'Выполнить команду', @@ -166,14 +179,14 @@ export default { 'workbench.noResource': 'Ресурс не открыт', 'bundle.noFrontend': 'У плагина нет frontend bundle', 'bundle.notFound': 'Плагин не найден', - 'bundle.loadFailed': 'Не удалось загрузить bundle: {error}', + 'bundle.loadFailed': 'Не удалось загрузить интерфейс плагина. Повторите попытку.', 'bundle.emptyContent': 'пустое содержимое', - 'bundle.executionError': 'Ошибка выполнения bundle: {error}', + 'bundle.executionError': 'Не удалось запустить интерфейс плагина. Повторите попытку.', 'bundle.registrationMissing': 'Bundle загружен, но вызов VerstakPluginRegister не обнаружен', - 'bundle.componentMissing': 'Компонент «{component}» не найден в bundle. Доступны: {available}', - 'bundle.mountError': 'Ошибка подключения компонента: {error}', + 'bundle.componentMissing': 'Запрошенный интерфейс плагина недоступен.', + 'bundle.mountError': 'Не удалось открыть интерфейс плагина. Повторите попытку.', 'bundle.mountUnavailable': 'Контейнер для подключения недоступен', - 'bundle.unexpectedError': 'Непредвиденная ошибка: {error}', + 'bundle.unexpectedError': 'Не удалось открыть интерфейс плагина. Повторите попытку.', 'bundle.unknownError': 'Неизвестная ошибка', 'bundle.frontendEntry': 'Точка входа frontend', 'bundle.availableComponents': 'Доступные компоненты', diff --git a/frontend/src/lib/plugin-host/PluginBundleHost.svelte b/frontend/src/lib/plugin-host/PluginBundleHost.svelte index 1d5b993..071c96e 100644 --- a/frontend/src/lib/plugin-host/PluginBundleHost.svelte +++ b/frontend/src/lib/plugin-host/PluginBundleHost.svelte @@ -83,6 +83,11 @@ return { value: result, error: '' }; } + function reportError(key, fallback, details) { + console.warn('[PluginBundleHost] ' + key + ':', details); + return tr(key, undefined, fallback); + } + async function loadAndMount(pId, compId, nextPropsKey) { // If same plugin+component and already mounted, skip if (currentPluginId === pId && currentComponent === compId && currentPropsKey === nextPropsKey && loadState === 'loaded') { @@ -125,7 +130,7 @@ const content = assetResult.value; if (assetResult.error || !content) { loadState = 'error'; - errorText = tr('bundle.loadFailed', { error: assetResult.error || tr('bundle.emptyContent') }); + errorText = reportError('bundle.loadFailed', 'Could not load the plugin interface. Please try again.', assetResult.error || tr('bundle.emptyContent')); return; } @@ -136,8 +141,7 @@ fn(); } catch (e) { loadState = 'error'; - errorText = tr('bundle.executionError', { error: e.message }); - console.error('[PluginBundleHost] bundle exec error:', e); + errorText = reportError('bundle.executionError', 'Could not start the plugin interface. Please try again.', e); return; } @@ -154,10 +158,7 @@ const comp = components[compId]; if (!comp || !comp.mount) { loadState = 'error'; - errorText = tr('bundle.componentMissing', { - component: compId, - available: Object.keys(components).join(', ') || tr('common.none'), - }); + errorText = tr('bundle.componentMissing', undefined, 'The requested plugin interface is unavailable.'); return; } @@ -177,8 +178,7 @@ errorText = ''; } catch (e) { loadState = 'error'; - errorText = tr('bundle.mountError', { error: e.message }); - console.error('[PluginBundleHost] mount error:', e); + errorText = reportError('bundle.mountError', 'Could not open the plugin interface. Please try again.', e); } } else { loadState = 'error'; @@ -186,8 +186,7 @@ } } catch (e) { loadState = 'error'; - errorText = tr('bundle.unexpectedError', { error: e.message || e }); - console.error('[PluginBundleHost] error:', e); + errorText = reportError('bundle.unexpectedError', 'Could not open the plugin interface. Please try again.', e); } } @@ -208,17 +207,18 @@
{tr('pluginView.error')}
-{tr('common.plugin')}: {currentPluginId || tr('common.unknown')}
{tr('common.component')}: {currentComponent || tr('common.unknown')}
- {#if pluginInfo} {/if} {#if getComponentList().length > 0} {/if} -