@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 +6 -6
- package/src/entities/CmdkMenu/model/store.ts +11 -7
- package/src/entities/Desktop/model/store.ts +15 -11
- package/src/entities/Session/composables/useCurrentUser.ts +3 -3
- package/src/features/User/LoginUser/ui/LoginForm/LoginForm.vue +14 -2
- package/src/pages/Cooperative/ListOfAgenda/ui/ListOfAgendaQuestions.vue +1 -1
- package/src/pages/Registrator/SignUp/SignUp.vue +6 -4
- package/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue +25 -23
- package/src/widgets/Desktop/CmdkTrigger/CmdkTrigger.vue +9 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coopenomics/desktop",
|
|
3
|
-
"version": "2025.11.17-alpha-
|
|
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-
|
|
29
|
-
"@coopenomics/notifications": "2025.11.17-alpha-
|
|
30
|
-
"@coopenomics/sdk": "2025.11.17-alpha-
|
|
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-
|
|
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": "
|
|
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
|
-
|
|
80
|
+
const result = desktop.workspaceMenus
|
|
81
81
|
.filter(
|
|
82
|
-
(item) =>
|
|
83
|
-
item.meta?.roles?.includes(userRole.value)
|
|
84
|
-
item.meta?.roles === undefined ||
|
|
85
|
-
|
|
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
|
-
|
|
126
|
+
// Но игнорируем сохраненный выбор если передан флаг ignoreSaved (например, после логина)
|
|
127
|
+
if (!ignoreSaved) {
|
|
128
|
+
const savedWorkspace = safeLocalStorageGetItem(STORAGE_KEY_WORKSPACE);
|
|
126
129
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
112
|
+
// Ждем завершения загрузки данных инстанса (независимо от того, есть инстанс или нет)
|
|
113
|
+
if (connectionAgreement.currentInstanceLoading) {
|
|
114
114
|
await new Promise<void>((resolve) => {
|
|
115
115
|
const unwatch = watch(
|
|
116
|
-
() => connectionAgreement.
|
|
117
|
-
(
|
|
118
|
-
if (
|
|
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 (
|
|
136
|
-
|
|
137
|
-
|
|
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;
|