diff --git a/frontend/src/lib/i18n/catalogs/en.js b/frontend/src/lib/i18n/catalogs/en.js
index a3a652d..d0613de 100644
--- a/frontend/src/lib/i18n/catalogs/en.js
+++ b/frontend/src/lib/i18n/catalogs/en.js
@@ -160,6 +160,15 @@ export default {
'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.',
+ 'workspaceTree.parentFolder': 'Parent folder',
+ 'workspaceTree.rootFolder': '(vault root)',
+ 'workspaceTree.folderTitle': 'Folders',
+ 'workspaceTree.folderEmpty': 'No Deals here',
+ 'workspaceTree.createFolder': 'Create Folder',
+ 'workspaceTree.folderNamePlaceholder': 'Folder name',
+ 'workspaceTree.folderIcon': 'Icon',
+ 'workspaceTree.folderColor': 'Color',
+ 'workspaceTree.folderCreateError': 'Could not create the folder. 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.',
diff --git a/frontend/src/lib/i18n/catalogs/ru.js b/frontend/src/lib/i18n/catalogs/ru.js
index 235d3fe..36295b9 100644
--- a/frontend/src/lib/i18n/catalogs/ru.js
+++ b/frontend/src/lib/i18n/catalogs/ru.js
@@ -160,6 +160,15 @@ export default {
'workspaceTree.createError': 'Не удалось создать Дело. Повторите попытку.',
'workspaceTree.renameError': 'Не удалось переименовать Дело. Повторите попытку.',
'workspaceTree.trashError': 'Не удалось переместить Дело в корзину. Повторите попытку.',
+ 'workspaceTree.parentFolder': 'Родительская папка',
+ 'workspaceTree.rootFolder': '(корень vault)',
+ 'workspaceTree.folderTitle': 'Папки',
+ 'workspaceTree.folderEmpty': 'Здесь нет Дел',
+ 'workspaceTree.createFolder': 'Создать папку',
+ 'workspaceTree.folderNamePlaceholder': 'Название папки',
+ 'workspaceTree.folderIcon': 'Иконка',
+ 'workspaceTree.folderColor': 'Цвет',
+ 'workspaceTree.folderCreateError': 'Не удалось создать папку. Повторите попытку.',
'pluginManager.loadError': 'Не удалось загрузить плагины. Повторите попытку.',
'pluginManager.reloadError': 'Не удалось перезагрузить плагины. Повторите попытку.',
'pluginManager.enableError': 'Не удалось включить плагин. Повторите попытку.',
diff --git a/frontend/src/lib/plugin-host/VerstakPluginAPI.js b/frontend/src/lib/plugin-host/VerstakPluginAPI.js
index 361d8d9..2357be0 100644
--- a/frontend/src/lib/plugin-host/VerstakPluginAPI.js
+++ b/frontend/src/lib/plugin-host/VerstakPluginAPI.js
@@ -584,6 +584,48 @@ export function createPluginAPI(pluginId) {
}
},
+ workspaces: {
+ list: async function() {
+ assertActive('workspaces.list');
+ return callBackend(pluginId, 'workspaces.list', () => App.ListWorkspaces());
+ },
+ getCurrent: async function() {
+ assertActive('workspaces.getCurrent');
+ return callBackend(pluginId, 'workspaces.getCurrent', () => App.GetCurrentWorkspace());
+ },
+ getTree: async function() {
+ assertActive('workspaces.getTree');
+ return callBackend(pluginId, 'workspaces.getTree', () => App.GetWorkspaceTree());
+ },
+ select: async function(path) {
+ assertActive('workspaces.select');
+ return callBackendErrorString(pluginId, 'workspaces.select', () => App.SetCurrentWorkspace(path));
+ },
+ create: async function(path, templateId) {
+ assertActive('workspaces.create');
+ return callBackend(pluginId, 'workspaces.create', () => App.CreateWorkspace(path, templateId || 'default'));
+ },
+ trash: async function(path) {
+ assertActive('workspaces.trash');
+ return callBackend(pluginId, 'workspaces.trash', () => App.TrashWorkspace(path));
+ },
+ move: async function(id, newParentId) {
+ assertActive('workspaces.move');
+ return callBackendErrorString(pluginId, 'workspaces.move', () => App.MoveWorkspace(id, newParentId));
+ }
+ },
+
+ folders: {
+ getMetadata: async function(path) {
+ assertActive('folders.getMetadata');
+ return callBackend(pluginId, 'folders.getMetadata', () => App.GetFolderMetadata(path));
+ },
+ setMetadata: async function(path, meta) {
+ assertActive('folders.setMetadata');
+ return callBackendErrorString(pluginId, 'folders.setMetadata', () => App.SetFolderMetadata(path, meta));
+ }
+ },
+
dispose: function() {
if (disposed) return;
disposed = true;
diff --git a/frontend/src/lib/shell/Sidebar.svelte b/frontend/src/lib/shell/Sidebar.svelte
index 35178b3..86b6431 100644
--- a/frontend/src/lib/shell/Sidebar.svelte
+++ b/frontend/src/lib/shell/Sidebar.svelte
@@ -2,6 +2,7 @@
import { onDestroy, onMount } from 'svelte';
import * as App from '../../../wailsjs/go/api/App';
import WorkspaceTree from './WorkspaceTree.svelte';
+ import PluginBundleHost from '../plugin-host/PluginBundleHost.svelte';
import GlobalSearch from './GlobalSearch.svelte';
import Icon from '../ui/Icon.svelte';
import { debug } from '../log/debug.js';
@@ -18,6 +19,7 @@
let plugins = [];
let vaultStatus = { status: 'unknown', path: '', vaultId: '' };
let sidebarItems = [];
+ let workspaceTreeProvider = null;
let errorMessage = '';
let locale = i18n.getLocale();
let unsubscribeLocale = null;
@@ -59,6 +61,19 @@
return plugin.status !== 'disabled' && plugin.status !== 'failed' && plugin.status !== 'incompatible' && plugin.status !== 'missing-required-capability';
});
sidebarItems.sort((a, b) => (a.position || 100) - (b.position || 100));
+
+ // Check for workspaceTree contribution
+ const wtContrib = (localizedContributions.workspaceTree || null);
+ if (wtContrib && wtContrib.pluginId && wtContrib.component) {
+ const wtPlugin = plugins.find(p => p.manifest?.id === wtContrib.pluginId);
+ if (wtPlugin && wtPlugin.status !== 'disabled' && wtPlugin.status !== 'failed' && wtPlugin.status !== 'incompatible' && wtPlugin.status !== 'missing-required-capability') {
+ workspaceTreeProvider = { pluginId: wtContrib.pluginId, component: wtContrib.component };
+ } else {
+ workspaceTreeProvider = null;
+ }
+ } else {
+ workspaceTreeProvider = null;
+ }
debug.log('[Sidebar] onMount: sidebarItems=' + sidebarItems.length);
flog('onMount: sidebarItems=' + sidebarItems.length);
} catch (e) {
@@ -123,7 +138,11 @@
{/if}
{#if vaultOpen}
-