@coopenomics/desktop 2025.11.17-alpha-2 → 2025.11.17-alpha-4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coopenomics/desktop",
3
- "version": "2025.11.17-alpha-2",
3
+ "version": "2025.11.17-alpha-4",
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.17-alpha-2",
29
- "@coopenomics/notifications": "2025.11.17-alpha-2",
30
- "@coopenomics/sdk": "2025.11.17-alpha-2",
28
+ "@coopenomics/controller": "2025.11.17-alpha-4",
29
+ "@coopenomics/notifications": "2025.11.17-alpha-4",
30
+ "@coopenomics/sdk": "2025.11.17-alpha-4",
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.17-alpha-2",
62
+ "cooptypes": "2025.11.17-alpha-4",
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": "31e65ac2e3978e747ef9282a523c380b9975e0a6"
126
+ "gitHead": "16393dbc9d82015b329840ea57f0bff498f08556"
127
127
  }
@@ -71,18 +71,20 @@ export const useCmdkMenuStore = defineStore(namespace, () => {
71
71
 
72
72
  // Вычисляем роль пользователя
73
73
  const userRole = computed(() =>
74
- user.isChairman ? 'chairman' : user.isMember ? 'member' : 'user'
74
+ user.isChairman.value ? 'chairman' : user.isMember.value ? 'member' : 'user'
75
75
  );
76
76
 
77
77
  // Группировка воркспейсов с их страницами
78
78
  const groupedItems = computed<GroupedItem[]>(() => {
79
79
 
80
- return desktop.workspaceMenus
80
+ const result = desktop.workspaceMenus
81
81
  .filter(
82
- (item) =>
83
- item.meta?.roles?.includes(userRole.value) ||
84
- item.meta?.roles === undefined ||
85
- item.meta?.roles.length === 0
82
+ (item) => {
83
+ const hasRole = item.meta?.roles?.includes(userRole.value);
84
+ const noRoles = item.meta?.roles === undefined || item.meta?.roles.length === 0;
85
+ const passes = hasRole || noRoles;
86
+ return passes;
87
+ }
86
88
  )
87
89
  .map(workspace => ({
88
90
  workspaceName: workspace.workspaceName,
@@ -114,7 +116,9 @@ const groupedItems = computed<GroupedItem[]>(() => {
114
116
  meta: page.meta,
115
117
  shortcut: getShortcut(page.name),
116
118
  }))
117
- }));
119
+ } ));
120
+
121
+ return result;
118
122
  });
119
123
 
120
124
  // Поиск и фильтрация
@@ -85,6 +85,7 @@ export const useDesktopStore = defineStore(namespace, () => {
85
85
 
86
86
  const workspaceMenus = computed<WorkspaceMenuItem[]>(() => {
87
87
  if (!currentDesktop.value) return [];
88
+
88
89
  return currentDesktop.value.workspaces.map((ws) => {
89
90
  const routes: RouteRecordRaw[] = (ws as any).routes || [];
90
91
  const meta: RouteMeta =
@@ -117,20 +118,23 @@ export const useDesktopStore = defineStore(namespace, () => {
117
118
  }
118
119
 
119
120
  // Функция для определения и выбора дефолтного рабочего стола
120
- function selectDefaultWorkspace() {
121
+ function selectDefaultWorkspace(ignoreSaved = false) {
121
122
  // Сбрасываем состояние загрузки на случай если оно было установлено
122
123
  isWorkspaceChanging.value = false;
123
124
 
124
125
  // Проверяем, был ли ранее сохранен рабочий стол (SSR-safe)
125
- const savedWorkspace = safeLocalStorageGetItem(STORAGE_KEY_WORKSPACE);
126
+ // Но игнорируем сохраненный выбор если передан флаг ignoreSaved (например, после логина)
127
+ if (!ignoreSaved) {
128
+ const savedWorkspace = safeLocalStorageGetItem(STORAGE_KEY_WORKSPACE);
126
129
 
127
- if (
128
- savedWorkspace &&
129
- currentDesktop.value?.workspaces.some((ws) => ws.name === savedWorkspace)
130
- ) {
131
- // Устанавливаем сохраненный рабочий стол без включения состояния загрузки (это инициализация)
132
- activeWorkspaceName.value = savedWorkspace;
133
- return;
130
+ if (
131
+ savedWorkspace &&
132
+ currentDesktop.value?.workspaces.some((ws) => ws.name === savedWorkspace)
133
+ ) {
134
+ // Устанавливаем сохраненный рабочий стол без включения состояния загрузки (это инициализация)
135
+ activeWorkspaceName.value = savedWorkspace;
136
+ return;
137
+ }
134
138
  }
135
139
 
136
140
  // Получаем настройки системы
@@ -156,8 +160,8 @@ export const useDesktopStore = defineStore(namespace, () => {
156
160
  safeLocalStorageSetItem(STORAGE_KEY_WORKSPACE, defaultWorkspace);
157
161
  } else {
158
162
  // Если настроенный рабочий стол недоступен, используем participant
159
- activeWorkspaceName.value = 'participant';
160
- safeLocalStorageSetItem(STORAGE_KEY_WORKSPACE, 'participant');
163
+ activeWorkspaceName.value = 'participant';
164
+ safeLocalStorageSetItem(STORAGE_KEY_WORKSPACE, 'participant');
161
165
  }
162
166
  }
163
167
 
@@ -28,9 +28,9 @@ export function useCurrentUser() {
28
28
 
29
29
  // Computed свойства для проверки статуса
30
30
  isRegistrationComplete: computed(() => session.isRegistrationComplete),
31
- isChairman: session.isChairman,
32
- isMember: session.isMember,
33
- isAuth: session.isAuth,
31
+ isChairman: computed(() => session.isChairman),
32
+ isMember: computed(() => session.isMember),
33
+ isAuth: computed(() => session.isAuth),
34
34
 
35
35
  // Методы
36
36
  setCurrentUserAccount: session.setCurrentUserAccount,
@@ -109,15 +109,27 @@ const submit = async () => {
109
109
  desktops.setWorkspaceChanging(false);
110
110
  router.push({ name: 'signup' });
111
111
  } else {
112
+ const session = useSessionStore();
113
+
114
+ // Дожидаемся завершения загрузки данных пользователя (включая роль)
115
+ let attempts = 0;
116
+ const maxAttempts = 50; // 5 секунд максимум
117
+
118
+ while (!session.loadComplete && attempts < maxAttempts) {
119
+ await new Promise((resolve) => setTimeout(resolve, 100));
120
+ attempts++;
121
+ }
122
+
112
123
  // Пробуем перейти по сохраненному URL
113
124
  if (!navigateToSavedUrl()) {
114
125
  // Если сохраненного URL нет, переходим на страницу по умолчанию
115
- desktops.selectDefaultWorkspace();
126
+ // Теперь selectDefaultWorkspace будет работать с актуальными данными о роли
127
+ // Передаем ignoreSaved=true чтобы пересчитать рабочий стол на основе новой роли
128
+ desktops.selectDefaultWorkspace(true);
116
129
  desktops.goToDefaultPage(router);
117
130
  }
118
131
 
119
132
  // Проверяем, если данные уже загружены, выключаем лоадер
120
- const session = useSessionStore();
121
133
  if (session.loadComplete) {
122
134
  desktops.setWorkspaceChanging(false);
123
135
  }
@@ -3,7 +3,7 @@ q-card(flat)
3
3
  QuestionsTable(
4
4
  :decisions='decisions',
5
5
  :loading='loading',
6
- :isChairman='currentUser.isChairman',
6
+ :isChairman='currentUser.isChairman.value',
7
7
  :format-decision-title='formatDecisionTitle',
8
8
  :is-voted-for='isVotedFor',
9
9
  :is-voted-against='isVotedAgainst',
@@ -118,7 +118,8 @@ watch(
118
118
  }
119
119
 
120
120
  // Теперь выбираем рабочий стол с обновленными данными о роли
121
- desktops.selectDefaultWorkspace();
121
+ // Передаем ignoreSaved=true чтобы пересчитать на основе новой роли
122
+ desktops.selectDefaultWorkspace(true);
122
123
  desktops.goToDefaultPage(router);
123
124
 
124
125
  // Показываем диалог разрешения уведомлений после успешной регистрации
@@ -128,7 +129,7 @@ watch(
128
129
  } catch (e) {
129
130
  console.error('Ошибка при обновлении данных пользователя:', e);
130
131
  // В случае ошибки все равно пытаемся перейти
131
- desktops.selectDefaultWorkspace();
132
+ desktops.selectDefaultWorkspace(true);
132
133
  desktops.goToDefaultPage(router);
133
134
 
134
135
  // Показываем диалог разрешения уведомлений даже при ошибке
@@ -183,7 +184,8 @@ watch(
183
184
  }
184
185
 
185
186
  // Теперь выбираем рабочий стол с обновленными данными о роли
186
- desktops.selectDefaultWorkspace();
187
+ // Передаем ignoreSaved=true чтобы пересчитать на основе новой роли
188
+ desktops.selectDefaultWorkspace(true);
187
189
  desktops.goToDefaultPage(router);
188
190
 
189
191
  // Показываем диалог разрешения уведомлений после успешной регистрации
@@ -193,7 +195,7 @@ watch(
193
195
  } catch (e) {
194
196
  console.error('Ошибка при обновлении данных пользователя:', e);
195
197
  // В случае ошибки все равно пытаемся перейти
196
- desktops.selectDefaultWorkspace();
198
+ desktops.selectDefaultWorkspace(true);
197
199
  desktops.goToDefaultPage(router);
198
200
 
199
201
  // Показываем диалог разрешения уведомлений даже при ошибке
@@ -109,13 +109,13 @@ const init = async () => {
109
109
  // Запускаем автообновление инстанса каждые 30 секунд (включает начальную загрузку)
110
110
  stopInstanceRefresh = await connectionAgreement.startInstanceAutoRefresh(30000);
111
111
 
112
- // Ждем загрузки данных инстанса перед определением шага
113
- if (connectionAgreement.currentInstance === null) {
112
+ // Ждем завершения загрузки данных инстанса (независимо от того, есть инстанс или нет)
113
+ if (connectionAgreement.currentInstanceLoading) {
114
114
  await new Promise<void>((resolve) => {
115
115
  const unwatch = watch(
116
- () => connectionAgreement.currentInstance,
117
- (instance) => {
118
- if (instance !== null) {
116
+ () => connectionAgreement.currentInstanceLoading,
117
+ (isLoading) => {
118
+ if (!isLoading) {
119
119
  unwatch();
120
120
  resolve();
121
121
  }
@@ -130,27 +130,29 @@ const init = async () => {
130
130
  }
131
131
 
132
132
  const instance = connectionAgreement.currentInstance;
133
+ const hasInstanceError = connectionAgreement.currentInstanceError;
133
134
 
134
135
  // Определяем шаг на основе текущего прогресса установки (при каждом заходе)
135
- if (instance && typeof instance.progress === 'number') {
136
- if (instance.progress > 0) {
137
- // Если установка уже идет (прогресс > 0), переходим к шагу установки
138
- console.log('🔄 Установка уже идет, прогресс:', instance.progress, '→ шаг 6');
139
- connectionAgreement.setCurrentStep(6);
140
- } else if (instance.progress === 0) {
141
- // Если установки еще нет, начинаем с начала
142
- if (system.info.is_unioned) {
143
- // Если кооператив не является членом союза, начинаем с нулевого шага
144
- connectionAgreement.setCurrentStep(0);
145
- } else {
146
- // Если кооператив уже член союза, начинаем с первого шага
147
- connectionAgreement.setCurrentStep(1);
148
- }
149
- }
150
- } else {
151
- // Если данные еще не загружены, начинаем с шага 1 по умолчанию
152
- console.log('⏳ Данные инстанса еще не загружены, устанавливаем шаг 1 по умолчанию');
136
+ if (hasInstanceError) {
137
+ // Если есть ошибка загрузки инстанса, начинаем с шага 1 по умолчанию
138
+ console.log('❌ Ошибка загрузки инстанса, устанавливаем шаг 1 по умолчанию');
153
139
  connectionAgreement.setCurrentStep(1);
140
+ } else if (instance && typeof instance.progress === 'number' && instance.progress > 0) {
141
+ // Если установка уже идет (прогресс > 0), переходим к шагу установки
142
+ console.log('🔄 Установка уже идет, прогресс:', instance.progress, '→ шаг 6');
143
+ connectionAgreement.setCurrentStep(6);
144
+ } else {
145
+ // Если инстанса нет ИЛИ его прогресс = 0, определяем шаг на основе членства в союзе
146
+ const hasNoInstance = instance === null;
147
+ if (system.info.is_unioned) {
148
+ // Если кооператив не является членом союза, начинаем с нулевого шага
149
+ console.log(hasNoInstance ? 'ℹ️ Инстанс отсутствует, кооператив не в союзе → шаг 0' : '🔄 Установка не начата, кооператив не в союзе → шаг 0');
150
+ connectionAgreement.setCurrentStep(0);
151
+ } else {
152
+ // Если кооператив уже член союза, начинаем с первого шага
153
+ console.log(hasNoInstance ? 'ℹ️ Инстанс отсутствует, кооператив в союзе → шаг 1' : '🔄 Установка не начата, кооператив в союзе → шаг 1');
154
+ connectionAgreement.setCurrentStep(1);
155
+ }
154
156
  }
155
157
 
156
158
  // Скрываем лоадер после загрузки данных
@@ -4,8 +4,10 @@ q-btn.cmdk-trigger(
4
4
  dense,
5
5
  stack,
6
6
  @click="openCmdkDialog"
7
+ :color="buttonColor"
7
8
  :class="{ 'active': cmdkStore.activeWorkspaceIcon !== 'fa-solid fa-desktop' }"
8
9
  )
10
+
9
11
  .trigger-content
10
12
  q-icon.trigger-icon(:name="cmdkStore.activeWorkspaceIcon")
11
13
  .trigger-text {{ cmdkStore.activeWorkspaceTitle }}
@@ -14,9 +16,16 @@ q-btn.cmdk-trigger(
14
16
  </template>
15
17
 
16
18
  <script setup lang="ts">
19
+ import { computed } from 'vue';
20
+ import { useQuasar } from 'quasar';
17
21
  import { useCmdkMenuStore } from 'src/entities/CmdkMenu/model';
18
22
 
19
23
  const cmdkStore = useCmdkMenuStore();
24
+ const $q = useQuasar();
25
+
26
+ const isDark = computed(() => $q.dark.isActive);
27
+
28
+ const buttonColor = computed(() => isDark.value ? 'white' : 'black');
20
29
 
21
30
  const openCmdkDialog = () => {
22
31
  cmdkStore.openDialog();
@@ -52,13 +61,11 @@ const openCmdkDialog = () => {
52
61
 
53
62
  .trigger-icon {
54
63
  font-size: 20px;
55
- color: #00695c;
56
64
  }
57
65
 
58
66
  .trigger-text {
59
67
  font-size: 10px;
60
68
  font-weight: 500;
61
- color: #424242;
62
69
  text-align: center;
63
70
  max-width: 100%;
64
71
  overflow: hidden;