@opengis/bi 1.2.32 → 1.2.34

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 (74) hide show
  1. package/README.md +92 -92
  2. package/dist/bi.js +1 -1
  3. package/dist/bi.umd.cjs +68 -68
  4. package/dist/{import-file-D-ISqB7l.js → import-file-BwxPX622.js} +1132 -1079
  5. package/dist/style.css +1 -1
  6. package/dist/{vs-funnel-bar-aoZzvriV.js → vs-funnel-bar-BV18EA4K.js} +3 -3
  7. package/dist/{vs-list-CBkyJSBj.js → vs-list-WrrWQ5KF.js} +32 -53
  8. package/dist/{vs-map-C3C11qmT.js → vs-map-CYd9vdrd.js} +3 -3
  9. package/dist/{vs-map-cluster-BsPmHIMx.js → vs-map-cluster-5TnGPuBH.js} +3 -3
  10. package/dist/{vs-number-d58ftpH5.js → vs-number-DUeRr7uz.js} +3 -3
  11. package/dist/{vs-table-BHa5Velm.js → vs-table-CZJnXfUv.js} +6 -6
  12. package/dist/{vs-text-Bq87gMTx.js → vs-text-D3nCPkgk.js} +4 -4
  13. package/package.json +77 -77
  14. package/plugin.js +21 -21
  15. package/server/helpers/mdToHTML.js +17 -17
  16. package/server/migrations/bi.dataset.sql +46 -46
  17. package/server/migrations/bi.sql +114 -114
  18. package/server/plugins/docs.js +48 -48
  19. package/server/plugins/hook.js +89 -89
  20. package/server/routes/dashboard/controllers/dashboard.import.js +103 -103
  21. package/server/routes/dashboard/controllers/dashboard.js +158 -158
  22. package/server/routes/dashboard/controllers/dashboard.list.js +60 -60
  23. package/server/routes/dashboard/controllers/utils/yaml.js +11 -11
  24. package/server/routes/dashboard/index.mjs +26 -26
  25. package/server/routes/data/controllers/data.js +230 -230
  26. package/server/routes/data/controllers/util/chartSQL.js +49 -49
  27. package/server/routes/data/controllers/util/normalizeData.js +65 -65
  28. package/server/routes/data/index.mjs +38 -38
  29. package/server/routes/dataset/controllers/bi.dataset.list.js +29 -29
  30. package/server/routes/dataset/controllers/bi.db.list.js +19 -19
  31. package/server/routes/dataset/controllers/comment.js +55 -55
  32. package/server/routes/dataset/controllers/createDatasetPost.js +134 -134
  33. package/server/routes/dataset/controllers/data.js +149 -149
  34. package/server/routes/dataset/controllers/dbTablePreview.js +58 -58
  35. package/server/routes/dataset/controllers/dbTables.js +34 -34
  36. package/server/routes/dataset/controllers/delete.js +40 -40
  37. package/server/routes/dataset/controllers/deleteDataset.js +52 -52
  38. package/server/routes/dataset/controllers/editDataset.js +90 -90
  39. package/server/routes/dataset/controllers/export.js +214 -214
  40. package/server/routes/dataset/controllers/form.js +99 -99
  41. package/server/routes/dataset/controllers/format.js +46 -46
  42. package/server/routes/dataset/controllers/insert.js +47 -47
  43. package/server/routes/dataset/controllers/table.js +68 -68
  44. package/server/routes/dataset/controllers/update.js +43 -43
  45. package/server/routes/dataset/index.mjs +132 -132
  46. package/server/routes/dataset/utils/convertJSONToCSV.js +17 -17
  47. package/server/routes/dataset/utils/convertJSONToXls.js +47 -47
  48. package/server/routes/dataset/utils/createTableQuery.js +59 -59
  49. package/server/routes/dataset/utils/datasetForms.js +1 -1
  50. package/server/routes/dataset/utils/descriptionList.js +45 -45
  51. package/server/routes/dataset/utils/downloadRemoteFile.js +58 -58
  52. package/server/routes/dataset/utils/executeQuery.js +46 -46
  53. package/server/routes/dataset/utils/getLayersData.js +106 -106
  54. package/server/routes/dataset/utils/getTableData.js +46 -46
  55. package/server/routes/dataset/utils/insertDataQuery.js +12 -12
  56. package/server/routes/dataset/utils/metaFormat.js +24 -24
  57. package/server/routes/edit/controllers/dashboard.add.js +36 -36
  58. package/server/routes/edit/controllers/dashboard.delete.js +39 -39
  59. package/server/routes/edit/controllers/dashboard.edit.js +61 -61
  60. package/server/routes/edit/controllers/widget.add.js +78 -78
  61. package/server/routes/edit/controllers/widget.del.js +58 -58
  62. package/server/routes/edit/controllers/widget.edit.js +115 -115
  63. package/server/routes/edit/index.mjs +33 -33
  64. package/server/routes/map/controllers/cluster.js +125 -125
  65. package/server/routes/map/controllers/clusterVtile.js +166 -166
  66. package/server/routes/map/controllers/geojson.js +127 -127
  67. package/server/routes/map/controllers/heatmap.js +118 -118
  68. package/server/routes/map/controllers/map.js +69 -69
  69. package/server/routes/map/controllers/utils/downloadClusterData.js +44 -44
  70. package/server/routes/map/controllers/vtile.js +183 -183
  71. package/server/routes/map/index.mjs +32 -32
  72. package/server/templates/page/login.html +58 -58
  73. package/server/utils/getWidget.js +118 -118
  74. package/utils.js +12 -12
@@ -1,103 +1,103 @@
1
- import path from 'node:path';
2
-
3
- import {
4
- config, logger, pgClients, getTemplate, getTemplatePath, dataInsert, dataUpdate,
5
- } from '@opengis/fastify-table/utils.js';
6
-
7
- export default async function dashboardImport({ pg = pgClients.client, query = {}, user = {} }, reply) {
8
- const time = Date.now();
9
-
10
- if (!query?.dashboard) {
11
- return reply.status(400).send('not enough query params: dashboard');
12
- }
13
-
14
- const list = getTemplatePath('dashboard').filter(el => el[0] === query.dashboard);
15
-
16
- if (!list?.length) {
17
- return reply.status(404).send(`dashboard not found`);
18
- }
19
-
20
- const client = await pg.connect();
21
- Object.assign(client, {
22
- options: pg.options,
23
- pk: pg.pk,
24
- pgType: pg.pgType,
25
- tlist: pg.tlist,
26
- });
27
-
28
- const ids = [];
29
- try {
30
- await client.query('BEGIN');
31
- const rows = await Promise.all(list.map(async ([filename]) => {
32
-
33
- const obj = await getTemplate('dashboard', filename);
34
- const index = obj?.find((el) => el[0] === 'index.yml')?.[1];
35
- const { db = pg.options?.database, description, filters, panels, table_name, title, tags, style, grid } = index || {};
36
-
37
- const dashboardId = await dataInsert({
38
- pg,
39
- table: 'bi.dashboard',
40
- data: {
41
- db,
42
- name: filename,
43
- description,
44
- filters,
45
- panels,
46
- table_name,
47
- title,
48
- words: tags?.join(','),
49
- style,
50
- grid,
51
- source: 'file',
52
- },
53
- uid: user?.uid,
54
- }).then(el => el.rows?.[0]?.dashboard_id);
55
- ids.push(dashboardId);
56
-
57
- const widgetList = panels?.reduce((acc, curr) => {
58
- curr.widgets?.forEach(item => acc.push(item));
59
- if (curr.widget) acc.push(curr.widget);
60
- return acc;
61
- }, []).filter(el => el) || [];
62
-
63
- const widgets = widgetList.length
64
- ? await Promise.all(obj.filter(el => widgetList.includes(path.parse(el[0]).name)).map(async ([widget, widgetData]) => {
65
- const { ext, name } = path.parse(widget);
66
- const data = ext === '.yml' ? widgetData : { type: 'text', data: { text: widgetData } };
67
- Object.assign(data, { name, x: widgetData?.data?.x, table_name: widgetData?.data?.table, dashboard_id: dashboardId });
68
-
69
- const res = await dataInsert({
70
- pg: client,
71
- table: 'bi.widget',
72
- data,
73
- uid: user?.uid,
74
- }).then(el => el.rows?.[0] || {});
75
- return res;
76
- }))
77
- : [];
78
- const test = await dataUpdate({
79
- pg: client,
80
- table: 'bi.dashboard',
81
- id: dashboardId,
82
- data: {
83
- widgets,
84
- },
85
- uid: user?.uid,
86
- });
87
- return { dashboardId, name: filename, widgets };
88
- }));
89
-
90
- await client.query('COMMIT');
91
- return { time: Date.now() - time, rows };
92
- } catch (err) {
93
- await client.query('ROLLBACK');
94
- if (ids.length) {
95
- const { rowCount = 0 } = await pg.query('delete from bi.dashboard where dashboard_id = any($1)', [ids]);
96
- console.log('ROLLBACK delete', rowCount, 'dashboard');
97
- // const { rowCount: rowCount1 = 0 } = await pg.query('delete from bi.widget where dashboard_id = any($1)', [ids]);
98
- // console.log('delete', rowCount1, 'widget');
99
- }
100
- logger.file('bi/dashboardImport/error', { error: err.toString(), stack: err.stack, ids });
101
- return reply.status(500).send(config.debug ? err.toString() : 'import error');
102
- }
103
- }
1
+ import path from 'node:path';
2
+
3
+ import {
4
+ config, logger, pgClients, getTemplate, getTemplatePath, dataInsert, dataUpdate,
5
+ } from '@opengis/fastify-table/utils.js';
6
+
7
+ export default async function dashboardImport({ pg = pgClients.client, query = {}, user = {} }, reply) {
8
+ const time = Date.now();
9
+
10
+ if (!query?.dashboard) {
11
+ return reply.status(400).send('not enough query params: dashboard');
12
+ }
13
+
14
+ const list = getTemplatePath('dashboard').filter(el => el[0] === query.dashboard);
15
+
16
+ if (!list?.length) {
17
+ return reply.status(404).send(`dashboard not found`);
18
+ }
19
+
20
+ const client = await pg.connect();
21
+ Object.assign(client, {
22
+ options: pg.options,
23
+ pk: pg.pk,
24
+ pgType: pg.pgType,
25
+ tlist: pg.tlist,
26
+ });
27
+
28
+ const ids = [];
29
+ try {
30
+ await client.query('BEGIN');
31
+ const rows = await Promise.all(list.map(async ([filename]) => {
32
+
33
+ const obj = await getTemplate('dashboard', filename);
34
+ const index = obj?.find((el) => el[0] === 'index.yml')?.[1];
35
+ const { db = pg.options?.database, description, filters, panels, table_name, title, tags, style, grid } = index || {};
36
+
37
+ const dashboardId = await dataInsert({
38
+ pg,
39
+ table: 'bi.dashboard',
40
+ data: {
41
+ db,
42
+ name: filename,
43
+ description,
44
+ filters,
45
+ panels,
46
+ table_name,
47
+ title,
48
+ words: tags?.join(','),
49
+ style,
50
+ grid,
51
+ source: 'file',
52
+ },
53
+ uid: user?.uid,
54
+ }).then(el => el.rows?.[0]?.dashboard_id);
55
+ ids.push(dashboardId);
56
+
57
+ const widgetList = panels?.reduce((acc, curr) => {
58
+ curr.widgets?.forEach(item => acc.push(item));
59
+ if (curr.widget) acc.push(curr.widget);
60
+ return acc;
61
+ }, []).filter(el => el) || [];
62
+
63
+ const widgets = widgetList.length
64
+ ? await Promise.all(obj.filter(el => widgetList.includes(path.parse(el[0]).name)).map(async ([widget, widgetData]) => {
65
+ const { ext, name } = path.parse(widget);
66
+ const data = ext === '.yml' ? widgetData : { type: 'text', data: { text: widgetData } };
67
+ Object.assign(data, { name, x: widgetData?.data?.x, table_name: widgetData?.data?.table, dashboard_id: dashboardId });
68
+
69
+ const res = await dataInsert({
70
+ pg: client,
71
+ table: 'bi.widget',
72
+ data,
73
+ uid: user?.uid,
74
+ }).then(el => el.rows?.[0] || {});
75
+ return res;
76
+ }))
77
+ : [];
78
+ const test = await dataUpdate({
79
+ pg: client,
80
+ table: 'bi.dashboard',
81
+ id: dashboardId,
82
+ data: {
83
+ widgets,
84
+ },
85
+ uid: user?.uid,
86
+ });
87
+ return { dashboardId, name: filename, widgets };
88
+ }));
89
+
90
+ await client.query('COMMIT');
91
+ return { time: Date.now() - time, rows };
92
+ } catch (err) {
93
+ await client.query('ROLLBACK');
94
+ if (ids.length) {
95
+ const { rowCount = 0 } = await pg.query('delete from bi.dashboard where dashboard_id = any($1)', [ids]);
96
+ console.log('ROLLBACK delete', rowCount, 'dashboard');
97
+ // const { rowCount: rowCount1 = 0 } = await pg.query('delete from bi.widget where dashboard_id = any($1)', [ids]);
98
+ // console.log('delete', rowCount1, 'widget');
99
+ }
100
+ logger.file('bi/dashboardImport/error', { error: err.toString(), stack: err.stack, ids });
101
+ return reply.status(500).send(config.debug ? err.toString() : 'import error');
102
+ }
103
+ }
@@ -1,158 +1,158 @@
1
- import yaml from 'js-yaml';
2
- import {
3
- pgClients,
4
- getTemplatePath,
5
- getTemplate,
6
- getPGAsync,
7
- getMeta,
8
- } from '@opengis/fastify-table/utils.js';
9
-
10
- export default async function dashboard({
11
- pg: pg1 = pgClients.client, params = {},
12
- }) {
13
- const time = Date.now();
14
- const { id } = params;
15
-
16
- if (!id) {
17
- return { message: 'not enough params: dashboard required', status: 400 };
18
- }
19
- const dashboards = getTemplatePath('dashboard');
20
-
21
- const fileDashboard = dashboards.find((el) => el[0] === id);
22
- if (!fileDashboard) {
23
- const sql = `select title, description, table_name, panels, grid, widgets, filters, style, words, db, public, updated_at as last_update
24
- from bi.dashboard where $1 in (dashboard_id, name)`;
25
-
26
- const data = await pg1.query(sql, [id]).then(el => el.rows?.[0] || {});
27
-
28
- let pg = pg1;
29
- try {
30
- const db = typeof data.db === 'string' && data.db.startsWith('{') ? JSON.parse(data.db) : { database: data.db };
31
- pg = data.pg || (data.db ? await getPGAsync(db) : null) || pg1;
32
- } catch (err) {
33
- data.error = err.toString();
34
- }
35
-
36
- data.type = 'bd';
37
- const { table_name: table } = data;
38
-
39
- if (!table) {
40
- return { message: 'not enough params: table required', status: 400 };
41
- }
42
-
43
- const loadTemplate = pg.pk?.['admin.doc_template'] ? await pg.query(
44
- 'select body from admin.doc_template where doc_type=5 and title=$1',
45
- [table]
46
- ).then(el => el.rows?.[0]?.body) : null;
47
-
48
- const sqlList = loadTemplate?.sql ? loadTemplate?.sql
49
- ?.filter?.(el => !el.disabled && el?.sql?.replace)
50
- ?.map?.((el, i) => `left join lateral (${el.sql.replace(/limit 1/ig, '')}) t${i} on 1=1`)?.join?.(' ') : '';
51
-
52
- const { fields = [] } = table && pg.pk?.[loadTemplate?.table || table] ? await pg.query(`select * from ${loadTemplate?.table || table} t ${sqlList || ''} limit 0`) : {};
53
-
54
- data?.widgets?.forEach?.(el => {
55
- const { style, data = {}, type, title, x, metrics } = el;
56
- el.yml = yaml.dump({ title, type, data: { x, metrics, ...data }, style, })
57
- // el.yml = yaml.dump({ style, data, type, title });
58
- });
59
-
60
- data.panels?.forEach?.(el => {
61
- const { title, type } = data?.widgets?.find(item => item.name === el.widget) || {};
62
- Object.assign(el, { title, type });
63
- });
64
-
65
- const meta = table ? await getMeta({ pg, table: loadTemplate?.table || table }) : {};
66
- const columnIndexes = meta?.columns?.reduce((acc, curr, idx) => Object.assign(acc, { [curr.name]: idx }), {}) || [];
67
-
68
- const columns = fields?.map(el => ({ name: el.name, title: meta?.columns[columnIndexes[el.name]]?.title || el.name, type: pg.pgType?.[el.dataTypeID] }));
69
-
70
- return {
71
- ...data || {},
72
- widgets: data?.widgets?.filter?.(el => el?.widget_id) || [],
73
- panels: data?.panels?.filter?.(el => el?.widget) || [],
74
- geom: !meta?.geom,
75
- error:
76
- table && !pg.pk?.[loadTemplate?.table || table] ? `table pkey not found: ${loadTemplate?.table || table}` : undefined,
77
- table_name: table,
78
- templateTable: loadTemplate?.table,
79
- time: Date.now() - time,
80
- columns,
81
- };
82
- }
83
-
84
- const fileData = await getTemplate('dashboard', id);
85
- const index = fileData.find((el) => el[0] === 'index.yml')[1];
86
-
87
- if (!index) {
88
- return { message: `not found ${id}`, status: 404 };
89
- }
90
-
91
- const data = index;
92
- data.type = 'file';
93
- const { table } = data?.data || { table: data?.table_name };
94
-
95
- let pg = pg1;
96
- try {
97
- pg = data.pg || (data.db ? await getPGAsync(data.db) : null) || pg1;
98
- } catch (err) {
99
- data.error = err.toString();
100
- }
101
-
102
- const { fields = [] } = table ? await pg.query(`select * from ${table} limit 0`) : {};
103
-
104
- const meta = await getMeta({ pg: pg1, table });
105
-
106
- const columns = meta?.columns
107
- ?.filter(el => fields.map(field => field.name).includes(el.name))
108
- ?.map(el => ({ name: el.name, title: el.title, type: pg.pgType?.[el.dataTypeID] }));
109
-
110
- const checks = index?.filters?.filter((el) => el?.id && fields.map((el) => el?.name).includes(el?.id) && el?.type === 'Check');
111
- if (checks?.length) {
112
- await Promise.all(checks.map(async (el) => {
113
- if (el?.data) {
114
- const options = await getTemplate('cls', el.data);
115
- Object.assign(el, { options });
116
- } else if (index?.table_name || index?.table) {
117
- const { rows = [] } = await pg.query(`select "${el.id}" as id, count(*) from ${index?.table_name || index?.table} group by "${el.id}"`);
118
- Object.assign(el, { options: rows });
119
- }
120
- }));
121
- }
122
- const ranges = index?.filters?.filter((el) => el?.id && fields.map((el) => el?.name).includes(el?.id) && el?.type === 'Range');
123
- if (ranges?.length) {
124
- await Promise.all(ranges.map(async (el) => {
125
- const rows = await pg.query(`select array[
126
- percentile_cont(0) within group (order by ${el.id}), percentile_cont(0.25) within group (order by ${el.id}),
127
- percentile_cont(0.5) within group (order by ${el.id}), percentile_cont(0.75) within group (order by ${el.id}),
128
- percentile_cont(1.0) within group (order by ${el.id})
129
- ] from ${index?.table_name || index?.table}`).then(el => el.rows?.[0]?.array || []);
130
- Object.assign(el, { options: rows });
131
- }));
132
- }
133
-
134
- // console.log(fileData)
135
- const widgets = fileData
136
- .filter((el) => el[0] !== 'index.yml')
137
- .map((el) =>
138
- el[1].data
139
- ? {
140
- name: el[0].split('.')[0],
141
- type: el[1].type,
142
- title: el[1].title,
143
- style: el[1].style,
144
- data: el[1].data,
145
-
146
- }
147
- : { name: el[0].split('.')[0], title: el[1] }
148
- );
149
-
150
- return {
151
- ...data,
152
- geom: !!meta?.geom,
153
- table_name: table,
154
- time: Date.now() - time,
155
- columns,
156
- widgets,
157
- };
158
- }
1
+ import yaml from 'js-yaml';
2
+ import {
3
+ pgClients,
4
+ getTemplatePath,
5
+ getTemplate,
6
+ getPGAsync,
7
+ getMeta,
8
+ } from '@opengis/fastify-table/utils.js';
9
+
10
+ export default async function dashboard({
11
+ pg: pg1 = pgClients.client, params = {},
12
+ }) {
13
+ const time = Date.now();
14
+ const { id } = params;
15
+
16
+ if (!id) {
17
+ return { message: 'not enough params: dashboard required', status: 400 };
18
+ }
19
+ const dashboards = getTemplatePath('dashboard');
20
+
21
+ const fileDashboard = dashboards.find((el) => el[0] === id);
22
+ if (!fileDashboard) {
23
+ const sql = `select title, description, table_name, panels, grid, widgets, filters, style, words, db, public, updated_at as last_update
24
+ from bi.dashboard where $1 in (dashboard_id, name)`;
25
+
26
+ const data = await pg1.query(sql, [id]).then(el => el.rows?.[0] || {});
27
+
28
+ let pg = pg1;
29
+ try {
30
+ const db = typeof data.db === 'string' && data.db.startsWith('{') ? JSON.parse(data.db) : { database: data.db };
31
+ pg = data.pg || (data.db ? await getPGAsync(db) : null) || pg1;
32
+ } catch (err) {
33
+ data.error = err.toString();
34
+ }
35
+
36
+ data.type = 'bd';
37
+ const { table_name: table } = data;
38
+
39
+ if (!table) {
40
+ return { message: 'not enough params: table required', status: 400 };
41
+ }
42
+
43
+ const loadTemplate = pg.pk?.['admin.doc_template'] ? await pg.query(
44
+ 'select body from admin.doc_template where doc_type=5 and title=$1',
45
+ [table]
46
+ ).then(el => el.rows?.[0]?.body) : null;
47
+
48
+ const sqlList = loadTemplate?.sql ? loadTemplate?.sql
49
+ ?.filter?.(el => !el.disabled && el?.sql?.replace)
50
+ ?.map?.((el, i) => `left join lateral (${el.sql.replace(/limit 1/ig, '')}) t${i} on 1=1`)?.join?.(' ') : '';
51
+
52
+ const { fields = [] } = table && pg.pk?.[loadTemplate?.table || table] ? await pg.query(`select * from ${loadTemplate?.table || table} t ${sqlList || ''} limit 0`) : {};
53
+
54
+ data?.widgets?.forEach?.(el => {
55
+ const { style, data = {}, type, title, x, metrics } = el;
56
+ el.yml = yaml.dump({ title, type, data: { x, metrics, ...data }, style, })
57
+ // el.yml = yaml.dump({ style, data, type, title });
58
+ });
59
+
60
+ data.panels?.forEach?.(el => {
61
+ const { title, type } = data?.widgets?.find(item => item.name === el.widget) || {};
62
+ Object.assign(el, { title, type });
63
+ });
64
+
65
+ const meta = table ? await getMeta({ pg, table: loadTemplate?.table || table }) : {};
66
+ const columnIndexes = meta?.columns?.reduce((acc, curr, idx) => Object.assign(acc, { [curr.name]: idx }), {}) || [];
67
+
68
+ const columns = fields?.map(el => ({ name: el.name, title: meta?.columns[columnIndexes[el.name]]?.title || el.name, type: pg.pgType?.[el.dataTypeID] }));
69
+
70
+ return {
71
+ ...data || {},
72
+ widgets: data?.widgets?.filter?.(el => el?.widget_id) || [],
73
+ panels: data?.panels?.filter?.(el => el?.widget) || [],
74
+ geom: !meta?.geom,
75
+ error:
76
+ table && !pg.pk?.[loadTemplate?.table || table] ? `table pkey not found: ${loadTemplate?.table || table}` : undefined,
77
+ table_name: table,
78
+ templateTable: loadTemplate?.table,
79
+ time: Date.now() - time,
80
+ columns,
81
+ };
82
+ }
83
+
84
+ const fileData = await getTemplate('dashboard', id);
85
+ const index = fileData.find((el) => el[0] === 'index.yml')[1];
86
+
87
+ if (!index) {
88
+ return { message: `not found ${id}`, status: 404 };
89
+ }
90
+
91
+ const data = index;
92
+ data.type = 'file';
93
+ const { table } = data?.data || { table: data?.table_name };
94
+
95
+ let pg = pg1;
96
+ try {
97
+ pg = data.pg || (data.db ? await getPGAsync(data.db) : null) || pg1;
98
+ } catch (err) {
99
+ data.error = err.toString();
100
+ }
101
+
102
+ const { fields = [] } = table ? await pg.query(`select * from ${table} limit 0`) : {};
103
+
104
+ const meta = await getMeta({ pg: pg1, table });
105
+
106
+ const columns = meta?.columns
107
+ ?.filter(el => fields.map(field => field.name).includes(el.name))
108
+ ?.map(el => ({ name: el.name, title: el.title, type: pg.pgType?.[el.dataTypeID] }));
109
+
110
+ const checks = index?.filters?.filter((el) => el?.id && fields.map((el) => el?.name).includes(el?.id) && el?.type === 'Check');
111
+ if (checks?.length) {
112
+ await Promise.all(checks.map(async (el) => {
113
+ if (el?.data) {
114
+ const options = await getTemplate('cls', el.data);
115
+ Object.assign(el, { options });
116
+ } else if (index?.table_name || index?.table) {
117
+ const { rows = [] } = await pg.query(`select "${el.id}" as id, count(*) from ${index?.table_name || index?.table} group by "${el.id}"`);
118
+ Object.assign(el, { options: rows });
119
+ }
120
+ }));
121
+ }
122
+ const ranges = index?.filters?.filter((el) => el?.id && fields.map((el) => el?.name).includes(el?.id) && el?.type === 'Range');
123
+ if (ranges?.length) {
124
+ await Promise.all(ranges.map(async (el) => {
125
+ const rows = await pg.query(`select array[
126
+ percentile_cont(0) within group (order by ${el.id}), percentile_cont(0.25) within group (order by ${el.id}),
127
+ percentile_cont(0.5) within group (order by ${el.id}), percentile_cont(0.75) within group (order by ${el.id}),
128
+ percentile_cont(1.0) within group (order by ${el.id})
129
+ ] from ${index?.table_name || index?.table}`).then(el => el.rows?.[0]?.array || []);
130
+ Object.assign(el, { options: rows });
131
+ }));
132
+ }
133
+
134
+ // console.log(fileData)
135
+ const widgets = fileData
136
+ .filter((el) => el[0] !== 'index.yml')
137
+ .map((el) =>
138
+ el[1].data
139
+ ? {
140
+ name: el[0].split('.')[0],
141
+ type: el[1].type,
142
+ title: el[1].title,
143
+ style: el[1].style,
144
+ data: el[1].data,
145
+
146
+ }
147
+ : { name: el[0].split('.')[0], title: el[1] }
148
+ );
149
+
150
+ return {
151
+ ...data,
152
+ geom: !!meta?.geom,
153
+ table_name: table,
154
+ time: Date.now() - time,
155
+ columns,
156
+ widgets,
157
+ };
158
+ }
@@ -1,60 +1,60 @@
1
- import { pgClients, getTemplatePath, getTemplate, getTemplateSync } from '@opengis/fastify-table/utils.js';
2
-
3
- const dirContent = getTemplatePath('dashboard').map(([filename, filepath]) => {
4
- const obj = getTemplateSync('dashboard', filename);
5
- const index = obj?.find?.((el) => el[0] === 'index.yml')?.[1];
6
- const { table_name, description, title } = index || {};
7
-
8
- return { name: filename, path: filepath, type: 'file', title, description, table_name };
9
- });
10
-
11
- const maxLimit = 100;
12
-
13
- export default async function dashboardList({
14
- pg = pgClients.client, query = {}, user = {}
15
- }) {
16
- const time = Date.now();
17
- const { type = 'file', page, search, sql } = query;
18
-
19
- const limit = Math.min(maxLimit, +(query.limit || 15));
20
- const offset = page && page > 0 ? (page - 1) * limit : 0;
21
-
22
- const dir = type === 'file' ? dirContent : [];
23
-
24
- const where = [search ? `lower(title) ~ $1` : null, type === 'viewer' ? `left(table_name,5)='demo.'` : null].filter(Boolean).join(' and ') || 'true';
25
- const q1 = `select count(*)::int as total, count(*) filter(where ${where})::int as filtered from bi.dashboard`;
26
-
27
- const q = `select dashboard_id as name, 'db' as type, title, description, table_name, words, public, updated_at as last_update from bi.dashboard where ${where} limit ${limit} offset ${offset}`;
28
-
29
- if (user?.user_type?.includes('admin') && ['db', 'viewer'].includes(type) && sql) {
30
- return `${q1};${q}`;
31
- }
32
-
33
- const args = [search].filter(Boolean);
34
- const { total = 0, filtered = 0 } = ['db', 'viewer'].includes(type) ? await pg.query(q1, args).then(el => el.rows?.[0] || {}) : {};
35
-
36
- const rows = ['db', 'viewer'].includes(type) ? await pg.query(q, args).then(el => el.rows || []) : [];
37
-
38
- if (type === 'viewer') {
39
- return {
40
- time: Date.now() - time,
41
- db: pg.options?.database,
42
- total,
43
- filtered,
44
- count: rows.length,
45
- rows,
46
- };
47
- }
48
-
49
- const list = (user?.user_type?.includes('admin') ? dir : dir.map(el => ({ ...el, path: undefined }))).concat(rows);
50
-
51
- const res = {
52
- time: Date.now() - time,
53
- db: pg.options?.database,
54
- total,
55
- filtered,
56
- count: rows.length,
57
- rows: list,
58
- };
59
- return res;
60
- }
1
+ import { pgClients, getTemplatePath, getTemplate, getTemplateSync } from '@opengis/fastify-table/utils.js';
2
+
3
+ const dirContent = getTemplatePath('dashboard').map(([filename, filepath]) => {
4
+ const obj = getTemplateSync('dashboard', filename);
5
+ const index = obj?.find?.((el) => el[0] === 'index.yml')?.[1];
6
+ const { table_name, description, title } = index || {};
7
+
8
+ return { name: filename, path: filepath, type: 'file', title, description, table_name };
9
+ });
10
+
11
+ const maxLimit = 100;
12
+
13
+ export default async function dashboardList({
14
+ pg = pgClients.client, query = {}, user = {}
15
+ }) {
16
+ const time = Date.now();
17
+ const { type = 'file', page, search, sql } = query;
18
+
19
+ const limit = Math.min(maxLimit, +(query.limit || 15));
20
+ const offset = page && page > 0 ? (page - 1) * limit : 0;
21
+
22
+ const dir = type === 'file' ? dirContent : [];
23
+
24
+ const where = [search ? `lower(title) ~ $1` : null, type === 'viewer' ? `left(table_name,5)='demo.'` : null].filter(Boolean).join(' and ') || 'true';
25
+ const q1 = `select count(*)::int as total, count(*) filter(where ${where})::int as filtered from bi.dashboard`;
26
+
27
+ const q = `select dashboard_id as name, 'db' as type, title, description, table_name, words, public, updated_at as last_update from bi.dashboard where ${where} limit ${limit} offset ${offset}`;
28
+
29
+ if (user?.user_type?.includes('admin') && ['db', 'viewer'].includes(type) && sql) {
30
+ return `${q1};${q}`;
31
+ }
32
+
33
+ const args = [search].filter(Boolean);
34
+ const { total = 0, filtered = 0 } = ['db', 'viewer'].includes(type) ? await pg.query(q1, args).then(el => el.rows?.[0] || {}) : {};
35
+
36
+ const rows = ['db', 'viewer'].includes(type) ? await pg.query(q, args).then(el => el.rows || []) : [];
37
+
38
+ if (type === 'viewer') {
39
+ return {
40
+ time: Date.now() - time,
41
+ db: pg.options?.database,
42
+ total,
43
+ filtered,
44
+ count: rows.length,
45
+ rows,
46
+ };
47
+ }
48
+
49
+ const list = (user?.user_type?.includes('admin') ? dir : dir.map(el => ({ ...el, path: undefined }))).concat(rows);
50
+
51
+ const res = {
52
+ time: Date.now() - time,
53
+ db: pg.options?.database,
54
+ total,
55
+ filtered,
56
+ count: rows.length,
57
+ rows: list,
58
+ };
59
+ return res;
60
+ }