complexqa_frontend_core 1.3.1 → 1.4.1

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": "complexqa_frontend_core",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
4
4
  "description": "core of web ",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,4 +1,4 @@
1
- import { clone_object, echo, is_array } from "../utils/utils";
1
+ import { clone_object, echo, is_array, is_object } from "../utils/utils";
2
2
  import axios from "axios";
3
3
  import * as qs from "query-string";
4
4
  import { ApiException } from "../exceptions/ApiException";
@@ -85,9 +85,9 @@ export class ApiAbstractElementClass
85
85
 
86
86
  let url = `/${ this.api_prefix }/${ this.module_prefix }/search`;
87
87
 
88
- payload = this.#handle_request_payload(payload);
89
- let response = this.#api_request(url, payload);
90
- response = this.#handle_response(response);
88
+ payload = this.handle_request_payload(payload);
89
+ let response = this.api_request(url, payload);
90
+ response = this.handle_response(response);
91
91
 
92
92
  return {
93
93
  response: response,
@@ -158,9 +158,9 @@ export class ApiAbstractElementClass
158
158
 
159
159
  let url = `/${ this.api_prefix }/${ this.module_prefix }/create`;
160
160
 
161
- payload = this.#handle_request_payload(payload);
162
- let response = this.#api_request(url, payload);
163
- response = this.#handle_response(response);
161
+ payload = this.handle_request_payload(payload);
162
+ let response = this.api_request(url, payload);
163
+ response = this.handle_response(response);
164
164
 
165
165
  return {
166
166
  response: response,
@@ -206,9 +206,9 @@ export class ApiAbstractElementClass
206
206
 
207
207
  let url = `/${ this.api_prefix }/${ this.module_prefix }/update_property`;
208
208
 
209
- payload = this.#handle_request_payload(payload);
210
- let response = this.#api_request(url, payload);
211
- response = this.#handle_response(response);
209
+ payload = this.handle_request_payload(payload);
210
+ let response = this.api_request(url, payload);
211
+ response = this.handle_response(response);
212
212
 
213
213
  return {
214
214
  response: response,
@@ -239,9 +239,9 @@ export class ApiAbstractElementClass
239
239
 
240
240
  let url = `/${ this.api_prefix }/${ this.module_prefix }/delete`;
241
241
 
242
- payload = this.#handle_request_payload(payload);
243
- let response = this.#api_request(url, payload);
244
- response = this.#handle_response(response);
242
+ payload = this.handle_request_payload(payload);
243
+ let response = this.api_request(url, payload);
244
+ response = this.handle_response(response);
245
245
 
246
246
  return {
247
247
  response: response,
@@ -255,12 +255,12 @@ export class ApiAbstractElementClass
255
255
 
256
256
  /******************************************************************************************/
257
257
 
258
- #handle_request_payload(payload)
258
+ handle_request_payload(payload)
259
259
  {
260
- return this.#object_replace_null_recursively(payload);
260
+ return this.object_replace_null_recursively(payload);
261
261
  }
262
262
 
263
- #object_replace_null_recursively(object)
263
+ object_replace_null_recursively(object)
264
264
  {
265
265
  let result = clone_object(object);
266
266
  for (let key in result)
@@ -271,7 +271,7 @@ export class ApiAbstractElementClass
271
271
  }
272
272
  else if (( result[ key ]?.constructor === Object ) || ( result[ key ]?.constructor === Array ))
273
273
  {
274
- result[ key ] = this.#object_replace_null_recursively(result[ key ]);
274
+ result[ key ] = this.object_replace_null_recursively(result[ key ]);
275
275
  }
276
276
  }
277
277
 
@@ -286,8 +286,9 @@ export class ApiAbstractElementClass
286
286
  * @param method
287
287
  * @returns {Promise<Promise<axios.AxiosResponse<any>> | *>}
288
288
  * @version v.0.2 (26/01/2025)
289
+ * @todo - валидация входящих параметров
289
290
  */
290
- async #api_request(url, payload, method = 'POST')
291
+ async api_request(url, payload, method = 'POST')
291
292
  {
292
293
  let request_params;
293
294
  if (!payload)
@@ -299,9 +300,9 @@ export class ApiAbstractElementClass
299
300
  request_params = clone_object(payload)
300
301
  }
301
302
 
302
- request_params = this.#mixin_service_params(request_params);
303
+ request_params = this.mixin_service_params(request_params);
303
304
 
304
- console.log({payload, request_params});
305
+ //console.log({payload, request_params});
305
306
 
306
307
 
307
308
  if (this.host_api)
@@ -335,6 +336,7 @@ export class ApiAbstractElementClass
335
336
  *
336
337
  * @param object
337
338
  * @returns {string}
339
+ * @todo - валидация входящих параметров
338
340
  */
339
341
  object_to_string(object)
340
342
  {
@@ -344,7 +346,7 @@ export class ApiAbstractElementClass
344
346
  }
345
347
 
346
348
 
347
- #mixin_service_params(params)
349
+ mixin_service_params(params)
348
350
  {
349
351
  params.client = 'webapp';
350
352
  return params;
@@ -357,7 +359,7 @@ export class ApiAbstractElementClass
357
359
  * @returns {Promise<any>}
358
360
  * @version v.0.1 (01/06/2024)
359
361
  */
360
- #handle_response(response)
362
+ handle_response(response)
361
363
  {
362
364
  response = response.then((api_response) =>
363
365
  {
@@ -379,15 +381,19 @@ export class ApiAbstractElementClass
379
381
 
380
382
  if (( api_code >= 200 ) && ( api_code <= 299 ))
381
383
  {
382
- if (is_array(api_response?.data) && this.element_class_instance)
384
+ if (is_array(api_response?.data?.api_result) && this.element_class_instance)
383
385
  {
384
- let result = api_response?.data.map((row) =>
386
+ let result = api_response?.data.api_result.map((row) =>
385
387
  {
386
388
  return new this.element_class_instance(row);
387
389
  });
388
390
 
389
391
  return result;
390
392
  }
393
+ else if (is_object(api_response?.data?.api_result))
394
+ {
395
+ return api_response?.data?.api_result;
396
+ }
391
397
  else
392
398
  {
393
399
  return api_response?.data;
@@ -14,4 +14,29 @@ export class ProjectApi extends ApiAbstractElementClass
14
14
  super(options);
15
15
  this.set_element_class_instance(typeProject);
16
16
  }
17
+
18
+
19
+
20
+
21
+ /**
22
+ *
23
+ * All test cases + suites
24
+ *
25
+ * @version v.1.0 (23/08/2025)
26
+ * @param payload
27
+ * @todo - валидация входящих параметров
28
+ */
29
+ async get_test_structure(payload)
30
+ {
31
+ let url = `/web_api/project/get/test_structure`;
32
+
33
+ payload = this.handle_request_payload(payload);
34
+ let response = this.api_request(url, payload);
35
+ response = this.handle_response(response);
36
+
37
+ return {
38
+ response: response,
39
+ payload : payload
40
+ };
41
+ }
17
42
  }
@@ -0,0 +1,33 @@
1
+ /**
2
+ *
3
+ * @version v.0.1 (19/08/2025)
4
+ */
5
+ export class abstractAppConfiguration
6
+ {
7
+ static init_options = false;
8
+
9
+ static config = {};
10
+
11
+ static state = {
12
+ loaded: false
13
+ }
14
+
15
+
16
+ /**
17
+ *
18
+ * @version v.0.1 (19/08/2025)
19
+ * @param init_options - надо ли?
20
+ */
21
+ constructor(init_options = false)
22
+ {}
23
+
24
+ /**
25
+ *
26
+ * @version v.0.1 (19/08/2025)
27
+ * @param element_type
28
+ * @param section
29
+ * @param lang ???
30
+ */
31
+ static get_config(element_type = false, section = false, lang = false)
32
+ {}
33
+ }
@@ -0,0 +1,119 @@
1
+ import { abstractAppConfiguration } from "./abstract_app_configuration.js";
2
+ import { typeMenuElement } from "../types/family_service/typeMenuElement.js";
3
+ import { UserService } from "../services/UserService.js";
4
+
5
+ /**
6
+ * Основное меню (верхнее)
7
+ *
8
+ * @version v.0.1 (19/08/2025)
9
+ */
10
+ export class MenuConfigurationMain extends abstractAppConfiguration
11
+ {
12
+ static config = {};
13
+
14
+ static state = {
15
+ loaded: false
16
+ }
17
+
18
+
19
+ /**
20
+ *
21
+ * @param init_options
22
+ */
23
+ constructor(init_options = false)
24
+ {
25
+ super();
26
+ if (this.constructor._instance)
27
+ {
28
+ return this.constructor._instance;
29
+ }
30
+
31
+ this.init_options = init_options;
32
+
33
+ this.constructor._instance = this;
34
+
35
+ MenuConfigurationMain.bootstrap();
36
+ }
37
+
38
+
39
+ /**
40
+ * Не понятно пока как лучше организовать
41
+ * @version v.0.1 (17/08/2025)
42
+ */
43
+ static bootstrap()
44
+ {
45
+ if (this.state.loaded)
46
+ {
47
+ return;
48
+ }
49
+
50
+ this.bootstrap_menu();
51
+
52
+ this.state.loaded = true;
53
+ }
54
+
55
+ static bootstrap_menu()
56
+ {
57
+ this.config.menu_elements = this.bootstrap_menu_elements();
58
+ }
59
+
60
+
61
+ /**
62
+ *
63
+ * @returns {boolean|*}
64
+ */
65
+ static get_config()
66
+ {
67
+ if (!this.state.loaded)
68
+ {
69
+ this.bootstrap();
70
+ }
71
+
72
+ return this.config;
73
+ }
74
+
75
+
76
+ /**
77
+ *
78
+ * @version v.0.1 (19/08/2025)
79
+ * @returns {[typeMenuElement]}
80
+ */
81
+ static bootstrap_menu_elements()
82
+ {
83
+ let locale = UserService.get_current_language();
84
+
85
+ // @todo - use serviceTranslate
86
+
87
+ let response = [];
88
+
89
+ response.push(new typeMenuElement({
90
+ link : `/web/${ locale }/project/listing`,
91
+ text : 'Projects',
92
+ icon : '?',
93
+ sort_order: 1,
94
+ }));
95
+
96
+ response.push(new typeMenuElement({
97
+ link : `/web/${ locale }/test_case/listing`,
98
+ text : 'Test Cases',
99
+ icon : '?',
100
+ sort_order: 2,
101
+ }));
102
+
103
+ response.push(new typeMenuElement({
104
+ link : `/web/${ locale }/test_run/listing`,
105
+ text : 'Test Runs',
106
+ icon : '?',
107
+ sort_order: 3,
108
+ }));
109
+
110
+ /*response.push(new typeMenuElement({
111
+ link : `/web/${ locale }/task/listing`,
112
+ text : 'To Do',
113
+ icon : '?',
114
+ sort_order: 4,
115
+ }));*/
116
+
117
+ return response;
118
+ }
119
+ }
@@ -0,0 +1,140 @@
1
+ import { abstractAppConfiguration } from "./abstract_app_configuration.js";
2
+ import { UserService } from "../services/UserService.js";
3
+ import { typeMenuElement } from "../types/family_service/typeMenuElement.js";
4
+
5
+ /**
6
+ * Дополнительное меню (нижнее)
7
+ *
8
+ * @version v.0.1 (19/08/2025)
9
+ */
10
+ export class MenuConfigurationSecondary extends abstractAppConfiguration
11
+ {
12
+ static config = {};
13
+
14
+ static state = {
15
+ loaded: false
16
+ }
17
+
18
+
19
+
20
+ /**
21
+ *
22
+ * @param init_options
23
+ */
24
+ constructor(init_options = false)
25
+ {
26
+ super();
27
+ if (this.constructor._instance)
28
+ {
29
+ return this.constructor._instance;
30
+ }
31
+
32
+ this.init_options = init_options;
33
+
34
+ this.constructor._instance = this;
35
+
36
+ MenuConfigurationSecondary.bootstrap();
37
+ }
38
+
39
+
40
+
41
+
42
+ /**
43
+ * Не понятно пока как лучше организовать
44
+ * @version v.0.1 (17/08/2025)
45
+ */
46
+ static bootstrap()
47
+ {
48
+ if (this.state.loaded)
49
+ {
50
+ return;
51
+ }
52
+
53
+ this.bootstrap_menu();
54
+
55
+ this.state.loaded = true;
56
+ }
57
+
58
+ static bootstrap_menu()
59
+ {
60
+ this.config.menu_elements = this.bootstrap_menu_elements();
61
+ }
62
+
63
+
64
+ /**
65
+ *
66
+ * @returns {boolean|*}
67
+ */
68
+ static get_config()
69
+ {
70
+ if (!this.state.loaded)
71
+ {
72
+ this.bootstrap();
73
+ }
74
+
75
+ return this.config;
76
+ }
77
+
78
+
79
+ /**
80
+ *
81
+ * @version v.0.1 (19/08/2025)
82
+ * @returns {[typeMenuElement]}
83
+ */
84
+ static bootstrap_menu_elements()
85
+ {
86
+ let locale = UserService.get_current_language();
87
+
88
+ // @todo - use serviceTranslate
89
+
90
+ let response = [];
91
+
92
+ response.push(new typeMenuElement({
93
+ link : `/web/${ locale }/user_profile`,
94
+ text : 'User Settings',
95
+ icon : '?',
96
+ sort_order: 1,
97
+ }));
98
+
99
+ let lang_sub_menu = [];
100
+
101
+ lang_sub_menu.push(new typeMenuElement({
102
+ link : `/web/en`, // @todo - get current routing and replace $lang
103
+ text : `EN`,
104
+ icon : '?',
105
+ sort_order: 1,
106
+ reload: true,
107
+ }));
108
+
109
+ lang_sub_menu.push(new typeMenuElement({
110
+ link : `/web/ru`, // @todo - get current routing and replace $lang
111
+ text : `RU`,
112
+ icon : '?',
113
+ sort_order: 2,
114
+ reload: true,
115
+ }));
116
+
117
+ response.push(new typeMenuElement({
118
+ link : false,
119
+ text : `Language ${ locale }`,
120
+ icon : '?',
121
+ sort_order: 2,
122
+ sub_menu : lang_sub_menu
123
+ }));
124
+
125
+ response.push(new typeMenuElement({
126
+ link : `/web/${ locale }/team_management/team/listing`,
127
+ text : 'Teams',
128
+ icon : '?',
129
+ sort_order: 3,
130
+ }));
131
+
132
+ /*
133
+ feedback
134
+ docs
135
+ admins
136
+ */
137
+
138
+ return response;
139
+ }
140
+ }
@@ -1,15 +1,13 @@
1
1
  import { typeTableConfiguration } from "../types/family_service/typeTableConfiguration.js";
2
2
  import { typeTableColumn } from "../types/family_service/typeTableColumn.js";
3
+ import { abstractAppConfiguration } from "./abstract_app_configuration.js";
3
4
 
4
5
  /**
5
6
  *
6
7
  * @version v.0.1 (17/08/2025)
7
8
  */
8
- export class TableConfiguration
9
+ export class TableConfiguration extends abstractAppConfiguration
9
10
  {
10
-
11
- static init_options = false;
12
-
13
11
  static config = {};
14
12
 
15
13
  static state = {
@@ -22,6 +20,7 @@ export class TableConfiguration
22
20
  */
23
21
  constructor(init_options = false)
24
22
  {
23
+ super();
25
24
  if (this.constructor._instance)
26
25
  {
27
26
  return this.constructor._instance;
@@ -31,7 +30,7 @@ export class TableConfiguration
31
30
 
32
31
  this.constructor._instance = this;
33
32
 
34
- this.#bootstrap();
33
+ TableConfiguration.bootstrap();
35
34
  }
36
35
 
37
36
 
@@ -48,7 +47,7 @@ export class TableConfiguration
48
47
  {
49
48
  if (!this.state.loaded)
50
49
  {
51
- this.#bootstrap();
50
+ this.bootstrap();
52
51
  }
53
52
 
54
53
  if (this.config?.[ element_type ]?.[ section ])
@@ -72,14 +71,14 @@ export class TableConfiguration
72
71
  * Не понятно пока как лучше организовать
73
72
  * @version v.0.1 (17/08/2025)
74
73
  */
75
- static #bootstrap()
74
+ static bootstrap()
76
75
  {
77
76
  if (this.state.loaded)
78
77
  {
79
78
  return;
80
79
  }
81
80
 
82
- this.#bootstrap_test_case();
81
+ this.bootstrap_test_case();
83
82
 
84
83
  this.state.loaded = true;
85
84
  }
@@ -89,11 +88,11 @@ export class TableConfiguration
89
88
  *
90
89
  * @version v.0.1 (17/08/2025)
91
90
  */
92
- static #bootstrap_test_case()
91
+ static bootstrap_test_case()
93
92
  {
94
93
  let payload_listing = {};
95
94
 
96
- let columns = this.#bootstrap_test_case_columns();
95
+ let columns = this.bootstrap_test_case_columns();
97
96
 
98
97
  payload_listing.config = new typeTableConfiguration({
99
98
  columns: columns
@@ -109,7 +108,7 @@ export class TableConfiguration
109
108
  *
110
109
  * @version v.0.1 (17/08/2025)
111
110
  */
112
- static #bootstrap_test_case_columns()
111
+ static bootstrap_test_case_columns()
113
112
  {
114
113
  let response = [];
115
114
 
@@ -1,6 +1,7 @@
1
1
  import { abstractService } from "./abstractService";
2
2
  import i18next from 'i18next';
3
3
  import { Api } from "../api";
4
+ import { echo, in_array } from "../utils/utils.js";
4
5
 
5
6
  /**
6
7
  *
@@ -21,10 +21,10 @@ export class typeProject extends familyGeneralElement
21
21
  api_key = 'project';
22
22
 
23
23
  structure_scheme = {
24
- project_id : 'integer | require',
25
- project_name : 'string | require',
26
- project_description : 'string | optional',
27
- project_status : 'string | enum | require',
24
+ project_id : 'integer | require',
25
+ project_name : 'string | require',
26
+ project_description: 'string | optional',
27
+ project_status : 'string | enum | require',
28
28
  team_id : 'integer | require',
29
29
  //reference_document_ids: 'array | reference | optional',
30
30
  };
@@ -87,6 +87,48 @@ export class typeProject extends familyGeneralElement
87
87
 
88
88
  /******************************************************************************************/
89
89
 
90
+ /**
91
+ *
92
+ * All test cases + suites
93
+ * @version v.1.0 (23/08/2025)
94
+ * @param project_id
95
+ * @param callback
96
+ * @returns {Promise<any>}
97
+ */
98
+ async get_test_structure(project_id = false, callback = {})
99
+ {
100
+ if (!project_id)
101
+ {
102
+ project_id = this.project_id;
103
+ }
104
+
105
+ let payload = {
106
+ project_id: project_id
107
+ }
108
+ /**
109
+ * {Api} ApiService
110
+ */
111
+ return ApiService[ this.api_key ].get_test_structure(payload).then((response) =>
112
+ {
113
+ if (typeof callback?.success === 'function')
114
+ {
115
+ callback?.success({ response, payload })
116
+ }
117
+ }).catch((error) =>
118
+ {
119
+ echo({ error });
120
+ if (typeof callback?.error === 'function')
121
+ {
122
+ callback?.error({ error, payload })
123
+ }
124
+ }).finally((response) =>
125
+ {
126
+ if (typeof callback?.final === 'function')
127
+ {
128
+ callback?.final({ response, payload })
129
+ }
130
+ });
131
+ }
90
132
 
91
133
  /**
92
134
  *
@@ -0,0 +1,32 @@
1
+ import { familyService } from "./familyService.js";
2
+
3
+ /**
4
+ *
5
+ * @version v.0.1 (19/08/2025)
6
+ */
7
+ export class typeMenuElement extends familyService
8
+ {
9
+ link = false; // при FALSE - нет <a>
10
+ text;
11
+ icon = false;
12
+ sort_order = 0;
13
+ sub_menu = false;
14
+ reload = false; // при TRUE - надо полностью перезагрузить
15
+
16
+ constructor(data = false)
17
+ {
18
+ super();
19
+ if (data && typeof data === 'object')
20
+ {
21
+ _.mapObject(data, (value, key) =>
22
+ {
23
+ if (this.hasOwnProperty(key))
24
+ {
25
+ this [ key ] = value;
26
+ }
27
+ });
28
+ }
29
+
30
+ return this;
31
+ }
32
+ }