@coopenomics/desktop 2025.11.26-alpha-1 → 2025.11.26-alpha-5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@ import { agreementsBase } from 'src/shared/lib/consts/workspaces';
4
4
  import type { IWorkspaceConfig } from 'src/shared/lib/types/workspace';
5
5
 
6
6
  export default async function (): Promise<IWorkspaceConfig[]> {
7
+ console.log('📨 [ChatCoop Install] Extension install function called');
7
8
  return [{
8
9
  workspace: 'chatcoop',
9
10
  extension_name: 'chatcoop',
@@ -15,7 +16,7 @@ export default async function (): Promise<IWorkspaceConfig[]> {
15
16
  meta: {
16
17
  title: 'Кооперативный мессенджер',
17
18
  icon: 'fa-solid fa-comments',
18
- roles: ['user', 'chairman', 'member'],
19
+ roles: ['chairman', 'member', 'user'],
19
20
  },
20
21
  path: '/:coopname/chatcoop',
21
22
  name: 'chatcoop',
@@ -27,7 +28,7 @@ export default async function (): Promise<IWorkspaceConfig[]> {
27
28
  meta: {
28
29
  title: 'Быстрый клиент',
29
30
  icon: 'fa-solid fa-comments',
30
- roles: ['user', 'chairman', 'member'],
31
+ roles: ['chairman', 'member', 'user'],
31
32
  agreements: agreementsBase,
32
33
  requiresAuth: true,
33
34
  },
@@ -40,7 +41,7 @@ export default async function (): Promise<IWorkspaceConfig[]> {
40
41
  meta: {
41
42
  title: 'Мобильный клиент',
42
43
  icon: 'fa-solid fa-mobile-alt',
43
- roles: ['user', 'chairman', 'member'],
44
+ roles: ['chairman', 'member', 'user'],
44
45
  agreements: agreementsBase,
45
46
  requiresAuth: true,
46
47
  },
@@ -50,4 +51,5 @@ export default async function (): Promise<IWorkspaceConfig[]> {
50
51
  },
51
52
  ],
52
53
  }];
54
+
53
55
  }
@@ -30,6 +30,7 @@ div
30
30
  width="100%",
31
31
  :style="{ height: 'calc(100vh - 56px)' }"
32
32
  @load="onIframeLoaded"
33
+ allow="camera; microphone; display-capture"
33
34
  )
34
35
  </template>
35
36
 
@@ -43,21 +44,25 @@ const chatcoopStore = useChatCoopChatStore();
43
44
  const isIframeLoading = ref(true);
44
45
  let iframeLoadTimeout: number | null = null;
45
46
 
47
+ function startIframeLoading() {
48
+ if (!chatcoopStore.accountStatus?.iframeUrl) return;
49
+
50
+ isIframeLoading.value = true;
51
+
52
+ // Очищаем предыдущий таймаут
53
+ if (iframeLoadTimeout) {
54
+ clearTimeout(iframeLoadTimeout);
55
+ }
56
+
57
+ // Устанавливаем таймаут на 5 секунд как fallback
58
+ iframeLoadTimeout = window.setTimeout(() => {
59
+ isIframeLoading.value = false;
60
+ }, 5000);
61
+ }
62
+
46
63
  // Сбрасываем состояние загрузки iframe при изменении URL
47
64
  watch(() => chatcoopStore.accountStatus?.iframeUrl, () => {
48
- if (chatcoopStore.accountStatus?.iframeUrl) {
49
- isIframeLoading.value = true;
50
-
51
- // Очищаем предыдущий таймаут
52
- if (iframeLoadTimeout) {
53
- clearTimeout(iframeLoadTimeout);
54
- }
55
-
56
- // Устанавливаем таймаут на 5 секунд как fallback
57
- iframeLoadTimeout = window.setTimeout(() => {
58
- isIframeLoading.value = false;
59
- }, 5000);
60
- }
65
+ startIframeLoading();
61
66
  });
62
67
 
63
68
  function onIframeLoaded() {
@@ -81,6 +86,8 @@ async function handleAccountCreated() {
81
86
 
82
87
  onMounted(async () => {
83
88
  await chatcoopStore.loadAccountStatus();
89
+ // Инициализируем загрузку iframe после получения статуса аккаунта
90
+ startIframeLoading();
84
91
  });
85
92
  </script>
86
93
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coopenomics/desktop",
3
- "version": "2025.11.26-alpha-1",
3
+ "version": "2025.11.26-alpha-5",
4
4
  "description": "A Desktop Project",
5
5
  "productName": "Desktop App",
6
6
  "author": "Alex Ant <dacom.dark.sun@gmail.com>",
@@ -25,9 +25,9 @@
25
25
  "start": "node -r ./alias-resolver.js dist/ssr/index.js"
26
26
  },
27
27
  "dependencies": {
28
- "@coopenomics/controller": "2025.11.26-alpha-1",
29
- "@coopenomics/notifications": "2025.11.26-alpha-1",
30
- "@coopenomics/sdk": "2025.11.26-alpha-1",
28
+ "@coopenomics/controller": "2025.11.26-alpha-5",
29
+ "@coopenomics/notifications": "2025.11.26-alpha-5",
30
+ "@coopenomics/sdk": "2025.11.26-alpha-5",
31
31
  "@dicebear/collection": "^9.0.1",
32
32
  "@dicebear/core": "^9.0.1",
33
33
  "@editorjs/code": "^2.9.3",
@@ -59,7 +59,7 @@
59
59
  "@wharfkit/wallet-plugin-privatekey": "^1.1.0",
60
60
  "axios": "^1.2.1",
61
61
  "compression": "^1.7.4",
62
- "cooptypes": "2025.11.26-alpha-1",
62
+ "cooptypes": "2025.11.26-alpha-5",
63
63
  "dompurify": "^3.1.7",
64
64
  "dotenv": "^16.4.5",
65
65
  "email-regex": "^5.0.0",
@@ -123,5 +123,5 @@
123
123
  "npm": ">= 6.13.4",
124
124
  "yarn": ">= 1.21.1"
125
125
  },
126
- "gitHead": "3127a69b678224768cd8f32f486a9981516e99e3"
126
+ "gitHead": "53a1c103d691570643c7f98e0f656efc42edaee6"
127
127
  }
@@ -51,7 +51,13 @@ export const useDesktopStore = defineStore(namespace, () => {
51
51
  const leftDrawerOpen = ref<boolean>(true);
52
52
 
53
53
  async function loadDesktop(): Promise<void> {
54
+ console.log('🏠 [DesktopStore] Loading desktop from API...');
54
55
  const newDesktop = await api.getDesktop();
56
+ console.log('🏠 [DesktopStore] Desktop loaded from API:', {
57
+ workspacesCount: newDesktop.workspaces?.length,
58
+ workspaces: newDesktop.workspaces?.map(ws => ({ name: ws.name, title: ws.title }))
59
+ });
60
+
55
61
  // Если уже есть расширения, мерджим маршруты
56
62
  if (currentDesktop.value && currentDesktop.value.workspaces) {
57
63
  newDesktop.workspaces.forEach((newWs) => {
@@ -59,27 +65,43 @@ export const useDesktopStore = defineStore(namespace, () => {
59
65
  (ws) => ws.name === newWs.name,
60
66
  );
61
67
  if (oldWs && (oldWs as any).routes) {
68
+ console.log('🏠 [DesktopStore] Merging routes for workspace:', newWs.name);
62
69
  (newWs as any).routes = (oldWs as any).routes;
63
70
  }
64
71
  });
65
72
  }
73
+
66
74
  // Добавляем поле backNavigationButton если оно отсутствует
67
75
  currentDesktop.value = {
68
76
  ...newDesktop,
69
77
  backNavigationButton: currentDesktop.value?.backNavigationButton || null,
70
78
  };
79
+
80
+ console.log('🏠 [DesktopStore] Desktop updated, active workspace:', activeWorkspaceName.value);
71
81
  // Сбрасываем состояние загрузки после загрузки рабочего стола
72
82
  isWorkspaceChanging.value = false;
73
83
  }
74
84
 
75
85
 
76
86
  function setRoutes(workspaceName: string, routes: RouteRecordRaw[]): void {
77
- if (!currentDesktop.value) return;
87
+ if (!currentDesktop.value) {
88
+ console.warn('🏠 [DesktopStore] Cannot set routes: no current desktop');
89
+ return;
90
+ }
91
+
78
92
  const ws = currentDesktop.value.workspaces.find(
79
93
  (w) => w.name === workspaceName,
80
94
  );
95
+
81
96
  if (ws) {
97
+ console.log('🏠 [DesktopStore] Setting routes for workspace:', {
98
+ workspaceName,
99
+ routesCount: routes.length,
100
+ routes: routes.map(r => ({ name: r.name, path: r.path, meta: r.meta }))
101
+ });
82
102
  (ws as any).routes = routes;
103
+ } else {
104
+ console.warn('🏠 [DesktopStore] Workspace not found for setting routes:', workspaceName);
83
105
  }
84
106
  }
85
107
 
@@ -111,10 +133,12 @@ export const useDesktopStore = defineStore(namespace, () => {
111
133
  const activeWorkspaceName = ref<string | null>(null);
112
134
 
113
135
  function selectWorkspace(name: string) {
136
+ console.log('🏠 [DesktopStore] Selecting workspace:', name);
114
137
  isWorkspaceChanging.value = true;
115
138
  activeWorkspaceName.value = name;
116
139
  // Сохраняем выбранный рабочий стол в localStorage (SSR-safe)
117
140
  safeLocalStorageSetItem(STORAGE_KEY_WORKSPACE, name);
141
+ console.log('🏠 [DesktopStore] Workspace selected, active now:', activeWorkspaceName.value);
118
142
  }
119
143
 
120
144
  // Функция для определения и выбора дефолтного рабочего стола
@@ -166,13 +190,28 @@ export const useDesktopStore = defineStore(namespace, () => {
166
190
  }
167
191
 
168
192
  const activeSecondLevelRoutes = computed((): RouteRecordRaw[] => {
169
- if (!activeWorkspaceName.value) return [];
193
+ if (!activeWorkspaceName.value) {
194
+ console.log('🏠 [DesktopStore] No active workspace name for second level routes');
195
+ return [];
196
+ }
197
+
170
198
  const ws = workspaceMenus.value.find(
171
199
  (menu) => menu.workspaceName === activeWorkspaceName.value,
172
200
  );
173
- return ws && ws.mainRoute && ws.mainRoute.children
201
+
202
+ const routes = ws && ws.mainRoute && ws.mainRoute.children
174
203
  ? (ws.mainRoute.children as RouteRecordRaw[])
175
204
  : [];
205
+
206
+ console.log('🏠 [DesktopStore] Active second level routes computed:', {
207
+ activeWorkspaceName: activeWorkspaceName.value,
208
+ workspaceFound: !!ws,
209
+ mainRouteExists: !!ws?.mainRoute,
210
+ routesCount: routes.length,
211
+ routes: routes.map(r => ({ name: r.name, path: r.path, meta: r.meta }))
212
+ });
213
+
214
+ return routes;
176
215
  });
177
216
 
178
217
  function registerWorkspaceMenus(router: Router): void {
@@ -41,8 +41,13 @@ export const useSessionStore = defineStore('session', (): ISessionStore => {
41
41
  const session = ref();
42
42
 
43
43
  const setCurrentUserAccount = (account: IAccount | undefined) => {
44
+ console.log('👤 [SessionStore] Setting current user account:', {
45
+ hasAccount: !!account,
46
+ providerRole: account?.provider_account?.role,
47
+ isChairman: account?.provider_account?.role === 'chairman',
48
+ isMember: account?.provider_account?.role === 'member'
49
+ });
44
50
  currentUserAccount.value = account;
45
- console.log('account', account)
46
51
  };
47
52
 
48
53
  const clearAccount = () => {
@@ -91,13 +96,17 @@ export const useSessionStore = defineStore('session', (): ISessionStore => {
91
96
  ),
92
97
  );
93
98
 
94
- const isChairman = computed(
95
- () => currentUserAccount.value?.provider_account?.role === 'chairman',
96
- );
99
+ const isChairman = computed(() => {
100
+ const chairman = currentUserAccount.value?.provider_account?.role === 'chairman';
101
+ console.log('👤 [SessionStore] isChairman computed:', chairman, 'role:', currentUserAccount.value?.provider_account?.role);
102
+ return chairman;
103
+ });
97
104
 
98
- const isMember = computed(
99
- () => currentUserAccount.value?.provider_account?.role === 'member',
100
- );
105
+ const isMember = computed(() => {
106
+ const member = currentUserAccount.value?.provider_account?.role === 'member';
107
+ console.log('👤 [SessionStore] isMember computed:', member, 'role:', currentUserAccount.value?.provider_account?.role);
108
+ return member;
109
+ });
101
110
 
102
111
  // Удобные геттеры для различных типов данных
103
112
  const userAccount = computed(() => currentUserAccount.value?.user_account);
@@ -40,11 +40,20 @@ const install = async () => {
40
40
  isInstalling.value = true;
41
41
 
42
42
  try {
43
+ console.log('🔧 [InstallExtension] Starting extension installation:', props.extensionName);
43
44
  await installExtension(props.extensionName, true, props.config);
45
+ console.log('🔧 [InstallExtension] Extension installed on backend');
46
+
44
47
  // Сначала загружаем обновленный desktop с сервера
48
+ console.log('🔧 [InstallExtension] Loading desktop from server...');
45
49
  await desktop.loadDesktop();
50
+ console.log('🔧 [InstallExtension] Desktop loaded, current workspaces:', desktop.currentDesktop?.workspaces?.map(ws => ({ name: ws.name, title: ws.title })));
51
+
46
52
  // Затем динамически загружаем маршруты для установленного расширения
53
+ console.log('🔧 [InstallExtension] Loading extension routes...');
47
54
  await loadExtensionRoutes(props.extensionName, router);
55
+ console.log('🔧 [InstallExtension] Extension routes loaded');
56
+
48
57
  router.push({ name: 'one-extension' });
49
58
  SuccessAlert('Расширение установлено');
50
59
  } catch (e: unknown) {
@@ -40,6 +40,8 @@ export async function loadExtensionRoutes(
40
40
  const store = useDesktopStore();
41
41
 
42
42
  try {
43
+ console.log('📦 [LoadExtensionRoutes] Starting to load routes for extension:', extensionName);
44
+
43
45
  // Получаем все доступные модули расширений
44
46
  const allModules = import.meta.glob(
45
47
  '../../../extensions/**/install.{ts,js}',
@@ -54,22 +56,35 @@ export async function loadExtensionRoutes(
54
56
  });
55
57
 
56
58
  if (!modulePath) {
57
- console.warn(`No module found for extension "${extensionName}"`);
59
+ console.warn(`📦 [LoadExtensionRoutes] No module found for extension "${extensionName}"`);
58
60
  return;
59
61
  }
60
62
 
63
+ console.log('📦 [LoadExtensionRoutes] Found module path:', modulePath);
64
+
61
65
  const module = await allModules[modulePath]();
62
66
  if (module?.default) {
63
67
  const result = await module.default();
68
+ console.log('📦 [LoadExtensionRoutes] Module loaded, result:', result);
64
69
 
65
70
  // Поддержка обоих форматов: массив или одиночный объект (для обратной совместимости)
66
71
  const workspaceConfigs: IWorkspaceConfig[] = Array.isArray(result) ? result : [result];
67
72
 
73
+ console.log('📦 [LoadExtensionRoutes] Processing workspace configs:', workspaceConfigs.length);
74
+
68
75
  // Обрабатываем каждый workspace из расширения
69
76
  for (const config of workspaceConfigs) {
77
+ console.log('📦 [LoadExtensionRoutes] Processing workspace config:', {
78
+ workspace: config.workspace,
79
+ routesCount: config.routes?.length,
80
+ routes: config.routes?.map(r => ({ name: r.name, meta: r.meta }))
81
+ });
82
+
70
83
  if (config?.workspace && config?.routes?.length) {
71
84
  // Записываем маршруты в соответствующий workspace
85
+ console.log('📦 [LoadExtensionRoutes] Setting routes for workspace:', config.workspace);
72
86
  store.setRoutes(config.workspace, config.routes as any);
87
+
73
88
  // Регистрируем маршруты в router
74
89
  const baseRoute = router.getRoutes().find((r) => r.name === 'base');
75
90
  if (baseRoute) {
@@ -79,7 +94,10 @@ export async function loadExtensionRoutes(
79
94
  .getRoutes()
80
95
  .find((route) => route.name === r.name);
81
96
  if (!existingRoute) {
97
+ console.log('📦 [LoadExtensionRoutes] Adding route to router:', r.name);
82
98
  router.addRoute('base', r);
99
+ } else {
100
+ console.log('📦 [LoadExtensionRoutes] Route already exists, skipping:', r.name);
83
101
  }
84
102
  });
85
103
  }
@@ -87,12 +105,12 @@ export async function loadExtensionRoutes(
87
105
  }
88
106
 
89
107
  console.log(
90
- `Routes for extension "${extensionName}" loaded successfully (${workspaceConfigs.length} workspace(s))`,
108
+ `📦 [LoadExtensionRoutes] Routes for extension "${extensionName}" loaded successfully (${workspaceConfigs.length} workspace(s))`,
91
109
  );
92
110
  }
93
111
  } catch (error) {
94
112
  console.error(
95
- `Failed to load routes for extension "${extensionName}":`,
113
+ `📦 [LoadExtensionRoutes] Failed to load routes for extension "${extensionName}":`,
96
114
  error,
97
115
  );
98
116
  }
@@ -50,9 +50,17 @@ const evaluateCondition = (
50
50
  };
51
51
 
52
52
  // Вычисляем роль пользователя
53
- const userRole = computed(() =>
54
- session.isChairman ? 'chairman' : session.isMember ? 'member' : 'user'
55
- );
53
+ const userRole = computed(() => {
54
+ const role = session.isChairman ? 'chairman' : session.isMember ? 'member' : 'user';
55
+ console.log('🔍 [SecondLevelMenuList] User role computed:', {
56
+ role,
57
+ isChairman: session.isChairman,
58
+ isMember: session.isMember,
59
+ isAuth: session.isAuth,
60
+ currentUserAccount: session.currentUserAccount?.provider_account?.role
61
+ });
62
+ return role;
63
+ });
56
64
 
57
65
  // Контекст для evaluateCondition и проверки ролей
58
66
  const context = computed(() => {
@@ -63,28 +71,62 @@ const context = computed(() => {
63
71
  session.currentUserAccount?.private_account?.organization_data.type.toUpperCase() ===
64
72
  Zeus.OrganizationType.COOP;
65
73
 
66
- return {
74
+ const ctx = {
67
75
  isCoop,
68
76
  userRole: userRole.value,
69
77
  userAccount: session.currentUserAccount?.private_account,
70
78
  coopname: info.coopname,
71
79
  };
80
+
81
+ console.log('🔍 [SecondLevelMenuList] Context computed:', ctx);
82
+ return ctx;
72
83
  });
73
84
 
74
85
  // Используем активный второй уровень из store
75
86
  const filteredRoutes = computed<IRoute[]>(() => {
76
- return (desktop.activeSecondLevelRoutes as unknown as IRoute[]).filter(
77
- (r) => {
78
- const rolesMatch =
79
- r.meta?.roles?.includes(context.value.userRole) ||
80
- (r.meta?.roles && r.meta.roles.length === 0);
81
- const conditionMatch = r.meta?.conditions
82
- ? evaluateCondition(r.meta.conditions, context.value)
83
- : true;
84
- const hiddenMatch = r.meta?.hidden ? !r.meta.hidden : true;
85
- return rolesMatch && conditionMatch && hiddenMatch;
86
- },
87
- );
87
+ const activeRoutes = desktop.activeSecondLevelRoutes as unknown as IRoute[];
88
+
89
+ console.log('🔍 [SecondLevelMenuList] Active second level routes:', {
90
+ activeWorkspaceName: desktop.activeWorkspaceName,
91
+ activeRoutesCount: activeRoutes.length,
92
+ activeRoutes: activeRoutes.map(r => ({
93
+ name: r.name,
94
+ meta: r.meta,
95
+ path: r.path
96
+ }))
97
+ });
98
+
99
+ const filtered = activeRoutes.filter((r) => {
100
+ const rolesMatch =
101
+ r.meta?.roles?.includes(context.value.userRole) ||
102
+ (r.meta?.roles && r.meta.roles.length === 0);
103
+ const conditionMatch = r.meta?.conditions
104
+ ? evaluateCondition(r.meta.conditions, context.value)
105
+ : true;
106
+ const hiddenMatch = r.meta?.hidden ? !r.meta.hidden : true;
107
+
108
+ const result = rolesMatch && conditionMatch && hiddenMatch;
109
+
110
+ console.log('🔍 [SecondLevelMenuList] Route filtering:', {
111
+ routeName: r.name,
112
+ userRole: context.value.userRole,
113
+ routeRoles: r.meta?.roles,
114
+ rolesMatch,
115
+ conditionMatch,
116
+ hiddenMatch,
117
+ result,
118
+ routeMeta: r.meta
119
+ });
120
+
121
+ return result;
122
+ });
123
+
124
+ console.log('🔍 [SecondLevelMenuList] Filtered routes result:', {
125
+ filteredCount: filtered.length,
126
+ filteredRoutes: filtered.map(r => r.name)
127
+ });
128
+
129
+ return filtered;
88
130
  });
89
131
 
90
132
  // Функция для получения паттерна группы маршрутов