@opengis/admin 0.2.122 → 0.2.123

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. package/dist/{add-page-D9BweG1f.js → add-page-CNaov3n_.js} +1 -1
  2. package/dist/{admin-interface-Bq8kf59d.js → admin-interface-Bfl5z6ck.js} +582 -732
  3. package/dist/{admin-view-pmWjnncn.js → admin-view-DYePX_Un.js} +1 -1
  4. package/dist/admin.js +2 -2
  5. package/dist/admin.umd.cjs +50 -50
  6. package/dist/{card-view-DNKItKZ_.js → card-view-OkM8SWMi.js} +1 -1
  7. package/dist/{edit-page-DmanLFQC.js → edit-page-BXf-hnHj.js} +1 -1
  8. package/dist/{import-file-B3hz_TTe.js → import-file-Cds3w-U5.js} +15024 -14822
  9. package/dist/{profile-page-CnXrMOV_.js → profile-page-B7ofAYKr.js} +1 -1
  10. package/dist/style.css +1 -1
  11. package/module/settings/menu.json +21 -13
  12. package/package.json +3 -3
  13. package/server/plugins/hook.js +13 -1
  14. package/server/routes/menu/controllers/getMenu.js +9 -3
  15. package/server/routes/print/controllers/printTemplate.add.js +37 -0
  16. package/server/routes/print/controllers/printTemplate.delete.js +29 -0
  17. package/server/routes/print/controllers/printTemplate.edit.js +42 -0
  18. package/server/routes/print/controllers/printTemplate.js +24 -79
  19. package/server/routes/print/controllers/printTemplateList.js +20 -0
  20. package/server/routes/print/controllers/printTemplatePreview.js +81 -0
  21. package/server/routes/print/index.mjs +14 -2
  22. package/server/routes/properties/controllers/admin.properties.post.js +2 -2
  23. package/server/routes/properties/index.mjs +1 -1
  24. package/server/routes/report/controllers/data.js +76 -0
  25. package/server/routes/report/controllers/list.js +18 -0
  26. package/server/routes/report/index.mjs +7 -0
  27. package/server/routes/report/utils/formatValue.js +179 -0
  28. package/server/routes/report/utils/getFilterQuery.js +67 -0
@@ -0,0 +1,179 @@
1
+ const dateTypeList = ['date', 'timestamp', 'timestamp without time zone', 'timestamp with time zone'];
2
+ const numberTypeList = ['float8', 'int4', 'int8', 'numeric', 'double precision', 'integer'];
3
+ const isValidDate = (dateStr) => {
4
+ const [dd, mm, yyyy] = dateStr.split('.');
5
+ return new Date(mm + '/' + dd + '/' + yyyy).toString() !== 'Invalid Date';
6
+ };
7
+
8
+ function dt(y, m, d) {
9
+ return new Date(Date.UTC(y, m, d)).toISOString().slice(0, 10);
10
+ }
11
+ const dp = {
12
+ d: new Date().getDate(),
13
+ w: new Date().getDate() - (new Date().getDay() || 7) + 1,
14
+ m: new Date().getMonth(),
15
+ q: (new Date().getMonth() / 4).toFixed() * 3,
16
+ y: new Date().getFullYear(),
17
+ };
18
+
19
+ function formatDateISOString(date) {
20
+ if (!date?.includes('.')) return date;
21
+ const [day, month, year] = date.split('.');
22
+ return `${year}-${month}-${day}`;
23
+ }
24
+
25
+ function formatValue({
26
+ pg, filter = {}, name, value, operator = '=', dataTypeID, uid = 1, optimize,
27
+ }) {
28
+ const { data, sql, extra } = filter;
29
+ const pk = false;
30
+
31
+ if (!dataTypeID && !extra) return {};
32
+ const fieldType = extra ? pg.pgType?.[{ Date: 1114 }[filter?.type] || 25] : pg.pgType?.[dataTypeID];
33
+ if (!name || !value || !fieldType) return {};
34
+ const filterType = filter.type?.toLowerCase();
35
+
36
+ // current day, week, month, year etc.
37
+ if (dateTypeList.includes(fieldType) && !value?.includes('_') && ['cd', 'cw', 'cm', 'cq', 'cy'].includes(value)) {
38
+ const query = {
39
+ cd: `${name}::date = '${dt(dp.y, dp.m, dp.d)}'::date`,
40
+ cw: `${name}::date >= '${dt(dp.y, dp.m, dp.w)}'::date and ${name} <= '${dt(dp.y, dp.m, dp.w + 6)}'::date`,
41
+ cm: `${name}::date >= '${dt(dp.y, dp.m, 1)}'::date and ${name} <= '${dt(dp.y, dp.m + 1, 0)}'::date`,
42
+ cq: `${name}::date >= '${dt(dp.y, dp.q, 1)}'::date and ${name} <= '${dt(dp.y, dp.q + 3, 0)}'::date`,
43
+ cy: `${name}::date >= '${dt(dp.y, 0, 1)}'::date and ${name}::date <= '${dt(dp.y, 11, 31)}'::date`,
44
+ }[value];
45
+ return { op: '=', query, extra };
46
+ }
47
+
48
+ // date range
49
+ if (dateTypeList.includes(fieldType) && value?.includes('_')) {
50
+ const [min, max] = value.split('_');
51
+ const query = `${name} >= '${min}'::date and ${name} <= '${max}'::date`;
52
+ return { op: 'between', query, extra };
53
+ }
54
+
55
+ // v3 filter date range, example - "01.01.2024-31.12.2024"
56
+ if (dateTypeList.includes(fieldType) && value?.includes('.') && value?.indexOf('-') === 10 && value?.length === 21) {
57
+ const [startDate, endDate] = value.split('-');
58
+ const min = formatDateISOString(startDate);
59
+ const max = formatDateISOString(endDate);
60
+
61
+ if (!isValidDate(startDate) || !isValidDate(endDate)) {
62
+ return { op: 'between', query: 'false', extra };
63
+ }
64
+ const query = extra && pk
65
+ ? `${pk} in (select object_id from crm.extra_data where property_key='${name}' and value_date::date >= '${min}'::date and value_date::date <= '${max}'::date)`
66
+ : `${name}::date >= '${min}'::date and ${name}::date <= '${max}'::date`;
67
+ return { op: 'between', query, extra };
68
+ }
69
+
70
+ // my rows
71
+ if (value === 'me' && uid && fieldType === 'text') {
72
+ return { op: '=', query: extra ? `uid = '${uid}'` : `${name}::text = '${uid}'`, extra };
73
+ }
74
+
75
+ const formatType = {
76
+ float8: 'numeric',
77
+ int4: 'numeric',
78
+ int8: 'numeric',
79
+ varchar: 'text',
80
+ bool: 'boolean',
81
+ geometry: 'geom',
82
+ }[fieldType] || 'text';
83
+
84
+ if (optimize && optimize.name !== optimize.pk) {
85
+ const val = filterType === 'text' ? `ilike '%${value}%'` : `= any('{${value}}')`;
86
+ return {
87
+ op: '~',
88
+ query: fieldType?.includes('[]')
89
+ ? `${optimize.pk} && (select array_agg(${optimize.pk}) from ${optimize.table} where ${name} ${val} )`
90
+ : `${optimize.pk} in (select ${optimize.pk} from ${optimize.table} where ${name} ${val} )`,
91
+ extra,
92
+ };
93
+ }
94
+
95
+ if (fieldType?.includes('[]')) {
96
+ return { op: 'in', query: `'{${value}}'::text[] && ${name}::text[]`, extra };
97
+ }
98
+
99
+ // multiple items of 1 param
100
+ if (value?.indexOf(',') !== -1) {
101
+ const values = value.split(',').filter((el) => el !== 'null');
102
+ if (extra && pk) {
103
+ const query = value?.indexOf('null') !== -1
104
+ ? `${pk} in (select object_id from crm.extra_data where property_key='${name}' and ( value_text is null or value_text in (${values?.map((el) => `'"${el}"'`).join(',')}) ) )`
105
+ : `${pk} in (select object_id from crm.extra_data where property_key='${name}' and value_text in (${values?.map((el) => `'"${el}"'`).join(',')}) )`;
106
+ return { op: 'in', query, extra };
107
+ }
108
+ const query = value?.indexOf('null') !== -1
109
+ ? `( ${name} is null or ${name}::text in (${values?.map((el) => `'${el}'`).join(',')}) )`
110
+ : `${name}::text in (${value.split(',')?.map((el) => `'${el}'`).join(',')})`;
111
+ return { op: 'in', query, extra };
112
+ }
113
+
114
+ // v3 filter number range, example - "100_500"
115
+ if (numberTypeList.includes(fieldType) && value?.indexOf('_') !== -1) {
116
+ const [min, max] = value.split('_');
117
+ const query = (max === 'max' ? `${name} > ${min}` : null) || (min === 'min' ? `${name} <= ${max}` : null) || `${name} between ${min} and ${max}`;
118
+ return { op: 'between', query, extra };
119
+ }
120
+
121
+ // number range
122
+ if (numberTypeList.includes(fieldType) && value?.indexOf('-') !== -1) {
123
+ const [min, max] = value.split('-');
124
+ if (min === 'min' && max === 'max') return {};
125
+ const query = (max === 'max' ? `${name} > ${min}` : null) || (min === 'min' ? `${name} < ${max}` : null) || `${name} between ${min} and ${max}`;
126
+ return { op: 'between', query, extra };
127
+ }
128
+
129
+ if (['<', '>'].includes(operator)) {
130
+ const query = `${name} ${operator} '${value}'::${formatType}`;
131
+ return { op: operator, query, extra };
132
+ }
133
+
134
+ if (operator === '=' && filterType !== 'text' && !filter?.data) {
135
+ const query = {
136
+ null: `${name} is null`,
137
+ notnull: `${name} is not null`,
138
+ }[value] || `${name}::${formatType}='${value}'::${formatType}`;
139
+ return { op: '=', query, extra };
140
+ }
141
+
142
+ if (['~', '='].includes(operator)) {
143
+ const operator1 = (filterType === 'text' && (filter?.id || filter?.name) && operator === '=' ? '~' : operator);
144
+ const matchNull = { null: 'is null', notnull: 'is not null' }[value];
145
+ const match = matchNull || ((operator1 === '=' || filterType === 'autocomplete') ? `='${value}'` : `ilike '%${value}%'`);
146
+ if (extra && pk) {
147
+ const query = data && sql
148
+ ? `${pk} in (select object_id from crm.extra_data where property_key='${name}' and value_text in ( ( with q(id,name) as (${sql}) select id from q where ${filterType === 'autocomplete' ? 'id' : 'name'} ${match})))`
149
+ : `${pk} in (select object_id from crm.extra_data where property_key='${name}' and value_text ${match})`;
150
+ return { op: 'ilike', query, extra };
151
+ }
152
+
153
+ const query = filter?.data && filter?.sql
154
+ ? `${filter?.name || filter?.id} in ( ( with q(id,name) as (${filter?.sql}) select id from q where ${filterType === 'autocomplete' ? 'id' : 'name'}::text ${match}) )` // filter with cls
155
+ : `${name}::text ${match}`; // simple filter
156
+ // console.log(query);
157
+ return { op: 'ilike', query };
158
+ }
159
+
160
+ // json
161
+ if (name.includes('.')) {
162
+ const [col, prop] = name.split('.');
163
+ const query = ` ${col}->>'${prop}' in ('${value.join("','")}')`;
164
+ return { op: 'in', query, extra };
165
+ }
166
+
167
+ // geometry
168
+ if (['geometry'].includes(fieldType)) {
169
+ const bbox = value[0].split('_');
170
+
171
+ if (bbox?.length === 4) {
172
+ const query = ` ${name} && 'box(${bbox[0]} ${bbox[1]},${bbox[2]} ${bbox[3]})'::box2d `;
173
+ return { op: '&&', query, extra };
174
+ }
175
+ }
176
+ return {};
177
+ }
178
+
179
+ export default formatValue;
@@ -0,0 +1,67 @@
1
+ /* eslint-disable no-continue */
2
+
3
+ /**
4
+ * @param {Number} opt.json - (1|0) 1 - Результат - Object, 0 - String
5
+ * @param {String} opt.query - запит до таблиці
6
+ * @param {String} opt.hash - інформація з хешу по запиту
7
+ */
8
+
9
+ import formatValue from './formatValue.js';
10
+
11
+ function getFilterQuery({ pg, filter: filterStr, fields, filterList }) {
12
+ if (!filterStr) return null; // filter list API
13
+
14
+ const mainOperators = ['=', '~', '>', '<'];
15
+
16
+ const filterQueryArray = decodeURIComponent(filterStr?.replace(/%/g, '%25').replace(/%/g, '\\%')?.replace(/(^,)|(,$)/g, '')).replace(/'/g, '').split(/[;|]/);
17
+
18
+ const resultList = [];
19
+
20
+ for (let i = 0; i < filterQueryArray.length; i += 1) {
21
+ const item = filterQueryArray[i];
22
+ const operator = mainOperators?.find((el) => item.indexOf(el) !== -1) || '=';
23
+ const [name] = item.split(operator);
24
+
25
+ // skip already added filter
26
+ if (resultList.find((el) => el.name === name)) {
27
+ continue;
28
+ }
29
+
30
+ // filter
31
+ const filter = filterList?.find((el) => [el.id, el.name].includes(name)) || { type: 'text' };
32
+
33
+ // find all value
34
+ const value = filterQueryArray.filter((el) => el.startsWith(name)).map((el) => el.substring(name.length + 1)).join(',');
35
+
36
+ if (filter?.query) {
37
+ resultList.push({
38
+ name, value, query: filter?.query, operator: '=', filterType: filter.type, type: 'text',
39
+ });
40
+ continue;
41
+ }
42
+
43
+ // find field and skip not exists
44
+ const { dataTypeID } = fields?.find((el) => el.name === name) || {};
45
+
46
+ // format query
47
+ const {
48
+ op, query, filterType, fieldType,
49
+ } = formatValue({
50
+ pg,
51
+ filter,
52
+ name,
53
+ value,
54
+ operator,
55
+ dataTypeID,
56
+ }) || {};
57
+ if (!query) continue;
58
+
59
+ resultList.push({
60
+ name, value, query, operator: op, filterType, type: fieldType,
61
+ });
62
+ }
63
+
64
+ return resultList;
65
+ }
66
+
67
+ export default getFilterQuery;