complexqa_frontend_core 1.21.8 → 1.22.0

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.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/publish/api/file_app_api.js +30 -3
  3. package/publish/api/index.js +6 -0
  4. package/publish/api/project_api.js +31 -8
  5. package/publish/api/public_text_document_api.js +59 -0
  6. package/publish/api/text_document_api.js +230 -0
  7. package/publish/api/text_document_folder_api.js +16 -0
  8. package/publish/app_configuration/table/helpers/table_element_models.js +2 -0
  9. package/publish/app_configuration/table/sections/text_document.js +31 -0
  10. package/publish/app_configuration/table/table_configuration.js +2 -0
  11. package/publish/app_configuration/text_document_editor_config.js +27 -0
  12. package/publish/constants/text_document_limits.js +12 -0
  13. package/publish/index.js +11 -0
  14. package/publish/services/FileAppService.js +103 -10
  15. package/publish/types/core/0_familyGeneralElement.js +0 -2
  16. package/publish/types/element_translate/_familyUtil.i18n.js +302 -68
  17. package/publish/types/element_translate/typeTextDocument.i18n.js +201 -0
  18. package/publish/types/element_translate/typeTextDocumentFolder.i18n.js +108 -0
  19. package/publish/types/element_translate/typeUtilExecution.i18n.js +171 -0
  20. package/publish/types/element_translate/typeUtilExecutionScreenshotMulti.i18n.js +281 -65
  21. package/publish/types/family_elements/typeProject.js +35 -10
  22. package/publish/types/family_files/typeTextDocument.js +88 -0
  23. package/publish/types/family_files/typeTextDocumentFolder.js +68 -0
  24. package/publish/types/family_utils/typeUtilExecution.js +14 -3
  25. package/publish/utils/text_document_image.js +84 -0
@@ -64,6 +64,17 @@ export class FileAppService extends abstractService
64
64
  }
65
65
 
66
66
 
67
+ static #ensure_file_app_url_from_token(token_data)
68
+ {
69
+ const url = token_data?.file_app_url;
70
+
71
+ if (url && !FileAppService.get_file_app_url())
72
+ {
73
+ FileAppService.bootstrap({ file_app_url: url });
74
+ }
75
+ }
76
+
77
+
67
78
  /**
68
79
  * Upload browser File/Blob to File App (token via Main App bridge).
69
80
  *
@@ -73,6 +84,7 @@ export class FileAppService extends abstractService
73
84
  * @param {number} payload.entity_id
74
85
  * @param {string} payload.category
75
86
  * @param {string} [payload.original_name]
87
+ * @param {string} [payload.file_uuid] — re-upload / new version for existing file
76
88
  *
77
89
  * @returns {Promise<import('../types/family_files/typeFile.js').typeFile>}
78
90
  */
@@ -91,14 +103,7 @@ export class FileAppService extends abstractService
91
103
  const mime_type = file.type || 'application/octet-stream';
92
104
  const size_bytes = Number(file.size || 0);
93
105
  const original_name = String(payload.original_name || file.name || 'upload');
94
- const file_app_url = FileAppService.get_file_app_url();
95
-
96
- if (!file_app_url)
97
- {
98
- throw new Error('FileAppService.upload_file: file_app_url is not set');
99
- }
100
-
101
- const api = FileAppService.#get_api_service();
106
+ const api = FileAppService.#get_api_service();
102
107
 
103
108
  const token_wrap = await api.file_app.issue_access_token({
104
109
  scopes : [ 'file:upload', 'file:read' ],
@@ -107,7 +112,18 @@ export class FileAppService extends abstractService
107
112
  size_bytes,
108
113
  });
109
114
 
110
- const access_token = token_wrap?.response?.access_token;
115
+ const token_data = await token_wrap?.response;
116
+
117
+ FileAppService.#ensure_file_app_url_from_token(token_data);
118
+
119
+ const file_app_url = FileAppService.get_file_app_url();
120
+
121
+ if (!file_app_url)
122
+ {
123
+ throw new Error('FileAppService.upload_file: file_app_url is not set');
124
+ }
125
+
126
+ const access_token = token_data?.access_token;
111
127
 
112
128
  if (!access_token)
113
129
  {
@@ -121,6 +137,7 @@ export class FileAppService extends abstractService
121
137
  original_name,
122
138
  entity_type,
123
139
  entity_id,
140
+ ...(payload.file_uuid ? { file_uuid: String(payload.file_uuid) } : {}),
124
141
  }, {
125
142
  headers: {
126
143
  Authorization: `Bearer ${ access_token }`,
@@ -182,6 +199,26 @@ export class FileAppService extends abstractService
182
199
  }
183
200
 
184
201
 
202
+ /**
203
+ * List files attached to entity via Main App bridge.
204
+ *
205
+ * @param {object} payload
206
+ * @param {string} payload.entity_type
207
+ * @param {number} payload.entity_id
208
+ * @param {string} [payload.category]
209
+ *
210
+ * @returns {Promise<{ items: object[] }>}
211
+ */
212
+ static async list_entity_files(payload)
213
+ {
214
+ const api = FileAppService.#get_api_service();
215
+ const wrap = await api.file_app.list_files(payload);
216
+ const row = await wrap?.response;
217
+
218
+ return row?.items ? row : { items: row?.items ?? [] };
219
+ }
220
+
221
+
185
222
  /**
186
223
  * Refresh presigned URL via Main App bridge (lazy fallback when details wire expired).
187
224
  *
@@ -194,7 +231,7 @@ export class FileAppService extends abstractService
194
231
  {
195
232
  const api = FileAppService.#get_api_service();
196
233
  const wrap = await api.file_app.file_access_url({ file_uuid, disposition });
197
- const row = wrap?.response;
234
+ const row = await wrap?.response;
198
235
 
199
236
  if (!row?.url)
200
237
  {
@@ -216,4 +253,60 @@ export class FileAppService extends abstractService
216
253
  mime_type : row.mime_type || false,
217
254
  };
218
255
  }
256
+
257
+
258
+ /**
259
+ * Batch refresh presigned URLs (one token on Main App).
260
+ *
261
+ * @param {string[]} file_uuids
262
+ * @param {'inline'|'attachment'} [disposition]
263
+ *
264
+ * @returns {Promise<Record<string, { preview_url?: string, download_url?: string, preview_url_expires_at?: string|false, download_url_expires_at?: string|false, mime_type?: string|false }>>}
265
+ */
266
+ static async refresh_file_access_urls_batch(file_uuids, disposition = 'inline')
267
+ {
268
+ const uuids = Array.isArray(file_uuids)
269
+ ? file_uuids.filter(Boolean)
270
+ : [];
271
+
272
+ if (!uuids.length)
273
+ {
274
+ return {};
275
+ }
276
+
277
+ const api = FileAppService.#get_api_service();
278
+ const wrap = await api.file_app.file_access_urls({ file_uuids: uuids, disposition });
279
+ const row = await wrap?.response;
280
+ const by_uuid = row?.by_uuid ?? {};
281
+ const result = {};
282
+
283
+ for (const [file_uuid, access] of Object.entries(by_uuid))
284
+ {
285
+ const url = access?.url;
286
+
287
+ if (!url)
288
+ {
289
+ continue;
290
+ }
291
+
292
+ if (disposition === 'attachment')
293
+ {
294
+ result[file_uuid] = {
295
+ download_url : url,
296
+ download_url_expires_at : access.expires_at || false,
297
+ mime_type : access.mime_type || false,
298
+ };
299
+ }
300
+ else
301
+ {
302
+ result[file_uuid] = {
303
+ preview_url : url,
304
+ preview_url_expires_at : access.expires_at || false,
305
+ mime_type : access.mime_type || false,
306
+ };
307
+ }
308
+ }
309
+
310
+ return result;
311
+ }
219
312
  }
@@ -593,7 +593,6 @@ export class familyGeneralElement
593
593
  */
594
594
  async delete(element = false, callback = {})
595
595
  {
596
- echo({element});
597
596
  if (!this.api_key)
598
597
  {
599
598
  throw new Error('Error #404-2215 - element has no api_key');
@@ -618,7 +617,6 @@ export class familyGeneralElement
618
617
  payload = element;
619
618
  //payload[ this.get_primary_key() ] = element[ this.get_primary_key() ];
620
619
  }
621
- echo({payload});
622
620
 
623
621
  payload = this.normalize_payload(payload);
624
622
 
@@ -1,68 +1,302 @@
1
- /**
2
- * Общие переводы для family_utils.
3
- */
4
- export const familyUtil_i18n = {
5
- execution_status: {
6
- en: {
7
- pending : 'Pending',
8
- submit_failed: 'Submit failed',
9
- queued : 'Queued',
10
- completed : 'Completed',
11
- failed : 'Failed',
12
- },
13
- ru: {
14
- pending : 'Ожидание',
15
- submit_failed: 'Ошибка отправки',
16
- queued : 'В очереди',
17
- completed : 'Завершено',
18
- failed : 'Ошибка',
19
- },
20
- },
21
-
22
- event_type: {
23
- en: {
24
- pending : 'Pending',
25
- submit_failed : 'Submit failed',
26
- queued : 'Queued',
27
- completed : 'Completed',
28
- failed : 'Failed',
29
- callback_received: 'Callback received',
30
- deleted : 'Deleted',
31
- },
32
- ru: {
33
- pending : 'Ожидание',
34
- submit_failed : 'Ошибка отправки',
35
- queued : 'В очереди',
36
- completed : 'Завершено',
37
- failed : 'Ошибка',
38
- callback_received: 'Получен callback',
39
- deleted : 'Удалено',
40
- },
41
- },
42
-
43
- capture_matrix_preset: {
44
- en: {
45
- default: 'Default matrix',
46
- custom : 'Custom matrix',
47
- },
48
- ru: {
49
- default: 'Матрица по умолчанию',
50
- custom : 'Своя матрица',
51
- },
52
- },
53
-
54
- wait_until: {
55
- en: {
56
- load : 'Load',
57
- domcontentloaded: 'DOM content loaded',
58
- networkidle : 'Network idle',
59
- commit : 'Commit',
60
- },
61
- ru: {
62
- load : 'Load',
63
- domcontentloaded: 'DOM content loaded',
64
- networkidle : 'Network idle',
65
- commit : 'Commit',
66
- },
67
- },
68
- };
1
+ /**
2
+ * Общие переводы для family_utils.
3
+ */
4
+ export const familyUtil_i18n = {
5
+ execution_status: {
6
+ en: {
7
+ pending : 'Pending',
8
+ submit_failed: 'Submit failed',
9
+ queued : 'Queued',
10
+ completed : 'Completed',
11
+ failed : 'Failed',
12
+ },
13
+ ru: {
14
+ pending : 'Ожидание',
15
+ submit_failed: 'Ошибка отправки',
16
+ queued : 'В очереди',
17
+ completed : 'Завершено',
18
+ failed : 'Ошибка',
19
+ },
20
+ de: {
21
+ pending : 'Ausstehend',
22
+ submit_failed: 'Senden fehlgeschlagen',
23
+ queued : 'In Warteschlange',
24
+ completed : 'Abgeschlossen',
25
+ failed : 'Fehlgeschlagen',
26
+ },
27
+ ar: {
28
+ pending : 'قيد الانتظار',
29
+ submit_failed: 'فشل الإرسال',
30
+ queued : 'في قائمة الانتظار',
31
+ completed : 'مكتمل',
32
+ failed : 'فشل',
33
+ },
34
+ es: {
35
+ pending : 'Pendiente',
36
+ submit_failed: 'Error al enviar',
37
+ queued : 'En cola',
38
+ completed : 'Completado',
39
+ failed : 'Fallido',
40
+ },
41
+ fr: {
42
+ pending : 'En attente',
43
+ submit_failed: 'Échec de l\'envoi',
44
+ queued : 'En file d\'attente',
45
+ completed : 'Terminé',
46
+ failed : 'Échec',
47
+ },
48
+ hy: {
49
+ pending : 'Սպասում',
50
+ submit_failed: 'Ուղարկման սխալ',
51
+ queued : 'Հերթում',
52
+ completed : 'Ավարտված',
53
+ failed : 'Ձախողված',
54
+ },
55
+ it: {
56
+ pending : 'In attesa',
57
+ submit_failed: 'Invio non riuscito',
58
+ queued : 'In coda',
59
+ completed : 'Completato',
60
+ failed : 'Non riuscito',
61
+ },
62
+ pl: {
63
+ pending : 'Oczekujący',
64
+ submit_failed: 'Błąd wysyłki',
65
+ queued : 'W kolejce',
66
+ completed : 'Ukończony',
67
+ failed : 'Niepowodzenie',
68
+ },
69
+ pt: {
70
+ pending : 'Pendente',
71
+ submit_failed: 'Falha no envio',
72
+ queued : 'Na fila',
73
+ completed : 'Concluído',
74
+ failed : 'Falhou',
75
+ },
76
+ tt: {
77
+ pending : 'Көтү',
78
+ submit_failed: 'Җибәрү хатасы',
79
+ queued : 'Чередә',
80
+ completed : 'Тәмамланган',
81
+ failed : 'Хата',
82
+ },
83
+ },
84
+
85
+ event_type: {
86
+ en: {
87
+ pending : 'Pending',
88
+ submit_failed : 'Submit failed',
89
+ queued : 'Queued',
90
+ completed : 'Completed',
91
+ failed : 'Failed',
92
+ callback_received: 'Callback received',
93
+ deleted : 'Deleted',
94
+ },
95
+ ru: {
96
+ pending : 'Ожидание',
97
+ submit_failed : 'Ошибка отправки',
98
+ queued : 'В очереди',
99
+ completed : 'Завершено',
100
+ failed : 'Ошибка',
101
+ callback_received: 'Получен callback',
102
+ deleted : 'Удалено',
103
+ },
104
+ de: {
105
+ pending : 'Ausstehend',
106
+ submit_failed : 'Senden fehlgeschlagen',
107
+ queued : 'In Warteschlange',
108
+ completed : 'Abgeschlossen',
109
+ failed : 'Fehlgeschlagen',
110
+ callback_received: 'Callback empfangen',
111
+ deleted : 'Gelöscht',
112
+ },
113
+ ar: {
114
+ pending : 'قيد الانتظار',
115
+ submit_failed : 'فشل الإرسال',
116
+ queued : 'في قائمة الانتظار',
117
+ completed : 'مكتمل',
118
+ failed : 'فشل',
119
+ callback_received: 'تم استلام callback',
120
+ deleted : 'محذوف',
121
+ },
122
+ es: {
123
+ pending : 'Pendiente',
124
+ submit_failed : 'Error al enviar',
125
+ queued : 'En cola',
126
+ completed : 'Completado',
127
+ failed : 'Fallido',
128
+ callback_received: 'Callback recibido',
129
+ deleted : 'Eliminado',
130
+ },
131
+ fr: {
132
+ pending : 'En attente',
133
+ submit_failed : 'Échec de l\'envoi',
134
+ queued : 'En file d\'attente',
135
+ completed : 'Terminé',
136
+ failed : 'Échec',
137
+ callback_received: 'Callback reçu',
138
+ deleted : 'Supprimé',
139
+ },
140
+ hy: {
141
+ pending : 'Սպասում',
142
+ submit_failed : 'Ուղարկման սխալ',
143
+ queued : 'Հերթում',
144
+ completed : 'Ավարտված',
145
+ failed : 'Ձախողված',
146
+ callback_received: 'Callback ստացված',
147
+ deleted : 'Ջնջված',
148
+ },
149
+ it: {
150
+ pending : 'In attesa',
151
+ submit_failed : 'Invio non riuscito',
152
+ queued : 'In coda',
153
+ completed : 'Completato',
154
+ failed : 'Non riuscito',
155
+ callback_received: 'Callback ricevuto',
156
+ deleted : 'Eliminato',
157
+ },
158
+ pl: {
159
+ pending : 'Oczekujący',
160
+ submit_failed : 'Błąd wysyłki',
161
+ queued : 'W kolejce',
162
+ completed : 'Ukończony',
163
+ failed : 'Niepowodzenie',
164
+ callback_received: 'Otrzymano callback',
165
+ deleted : 'Usunięto',
166
+ },
167
+ pt: {
168
+ pending : 'Pendente',
169
+ submit_failed : 'Falha no envio',
170
+ queued : 'Na fila',
171
+ completed : 'Concluído',
172
+ failed : 'Falhou',
173
+ callback_received: 'Callback recebido',
174
+ deleted : 'Eliminado',
175
+ },
176
+ tt: {
177
+ pending : 'Көтү',
178
+ submit_failed : 'Җибәрү хатасы',
179
+ queued : 'Чередә',
180
+ completed : 'Тәмамланган',
181
+ failed : 'Хата',
182
+ callback_received: 'Callback алынган',
183
+ deleted : 'Бетерелгән',
184
+ },
185
+ },
186
+
187
+ capture_matrix_preset: {
188
+ en: {
189
+ default: 'Default matrix',
190
+ custom : 'Custom matrix',
191
+ },
192
+ ru: {
193
+ default: 'Матрица по умолчанию',
194
+ custom : 'Своя матрица',
195
+ },
196
+ de: {
197
+ default: 'Standardmatrix',
198
+ custom : 'Eigene Matrix',
199
+ },
200
+ ar: {
201
+ default: 'المصفوفة الافتراضية',
202
+ custom : 'مصفوفة مخصصة',
203
+ },
204
+ es: {
205
+ default: 'Matriz predeterminada',
206
+ custom : 'Matriz personalizada',
207
+ },
208
+ fr: {
209
+ default: 'Matrice par défaut',
210
+ custom : 'Matrice personnalisée',
211
+ },
212
+ hy: {
213
+ default: 'Լռելյայն матրիցա',
214
+ custom : 'Սեփական матրիցա',
215
+ },
216
+ it: {
217
+ default: 'Matrice predefinita',
218
+ custom : 'Matrice personalizzata',
219
+ },
220
+ pl: {
221
+ default: 'Macierz domyślna',
222
+ custom : 'Macierz własna',
223
+ },
224
+ pt: {
225
+ default: 'Matriz predefinida',
226
+ custom : 'Matriz personalizada',
227
+ },
228
+ tt: {
229
+ default: 'Гадәти матрица',
230
+ custom : 'Үз матрицасы',
231
+ },
232
+ },
233
+
234
+ wait_until: {
235
+ en: {
236
+ load : 'Load',
237
+ domcontentloaded: 'DOM content loaded',
238
+ networkidle : 'Network idle',
239
+ commit : 'Commit',
240
+ },
241
+ ru: {
242
+ load : 'Событие load',
243
+ domcontentloaded: 'DOM загружен',
244
+ networkidle : 'Сеть без активности',
245
+ commit : 'Commit навигации',
246
+ },
247
+ de: {
248
+ load : 'Load-Ereignis',
249
+ domcontentloaded: 'DOM-Inhalt geladen',
250
+ networkidle : 'Netzwerk inaktiv',
251
+ commit : 'Commit (Navigation)',
252
+ },
253
+ ar: {
254
+ load : 'حدث load',
255
+ domcontentloaded: 'تم تحميل DOM',
256
+ networkidle : 'الشبكة خاملة',
257
+ commit : 'Commit للتنقل',
258
+ },
259
+ es: {
260
+ load : 'Evento load',
261
+ domcontentloaded: 'DOM cargado',
262
+ networkidle : 'Red inactiva',
263
+ commit : 'Commit de navegación',
264
+ },
265
+ fr: {
266
+ load : 'Événement load',
267
+ domcontentloaded: 'DOM chargé',
268
+ networkidle : 'Réseau inactif',
269
+ commit : 'Commit de navigation',
270
+ },
271
+ hy: {
272
+ load : 'Load իրադարձություն',
273
+ domcontentloaded: 'DOM բեռնված',
274
+ networkidle : 'Ցանցը անգործ',
275
+ commit : 'Navigation commit',
276
+ },
277
+ it: {
278
+ load : 'Evento load',
279
+ domcontentloaded: 'DOM caricato',
280
+ networkidle : 'Rete inattiva',
281
+ commit : 'Commit di navigazione',
282
+ },
283
+ pl: {
284
+ load : 'Zdarzenie load',
285
+ domcontentloaded: 'DOM załadowany',
286
+ networkidle : 'Sieć bez aktywności',
287
+ commit : 'Commit nawigacji',
288
+ },
289
+ pt: {
290
+ load : 'Evento load',
291
+ domcontentloaded: 'DOM carregado',
292
+ networkidle : 'Rede inativa',
293
+ commit : 'Commit de navegação',
294
+ },
295
+ tt: {
296
+ load : 'Load вакыйасы',
297
+ domcontentloaded: 'DOM йөкләнгән',
298
+ networkidle : 'Челтәр буш',
299
+ commit : 'Нaviгация commit',
300
+ },
301
+ },
302
+ };