@opengis/bi 1.0.13 → 1.0.15

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 (58) hide show
  1. package/README.md +50 -52
  2. package/config.js +12 -12
  3. package/dist/bi.js +1 -1
  4. package/dist/bi.umd.cjs +120 -134
  5. package/dist/{import-file-1T7kpSzt.js → import-file-CRC0sYYT.js} +11974 -11522
  6. package/dist/{map-component-mixin-BLM9iEWA.js → map-component-mixin-BCtWEvzv.js} +4830 -3150
  7. package/dist/style.css +1 -1
  8. package/dist/vs-calendar-5ot79n0N.js +110 -0
  9. package/dist/vs-funnel-bar-CLo6gXI_.js +105 -0
  10. package/dist/vs-heatmap-DHGA8dRk.js +97 -0
  11. package/dist/{vs-map-cluster-Dfe9INqE.js → vs-map-cluster-CNgX6JVF.js} +28 -25
  12. package/dist/vs-map-pIn5wS4G.js +74 -0
  13. package/dist/vs-number-DYfok8VU.js +55 -0
  14. package/dist/{vs-text-DcrAdQ40.js → vs-text-Dckykz09.js} +19 -13
  15. package/package.json +107 -72
  16. package/plugin.js +14 -13
  17. package/server/migrations/bi.dataset.sql +26 -0
  18. package/server/migrations/bi.sql +93 -27
  19. package/server/plugins/docs.js +48 -47
  20. package/server/plugins/hook.js +89 -86
  21. package/server/plugins/vite.js +69 -55
  22. package/server/routes/dashboard/controllers/dashboard.delete.js +38 -35
  23. package/server/routes/dashboard/controllers/dashboard.js +118 -80
  24. package/server/routes/dashboard/controllers/dashboard.list.js +30 -39
  25. package/server/routes/dashboard/controllers/utils/yaml.js +11 -12
  26. package/server/routes/dashboard/index.mjs +25 -24
  27. package/server/routes/data/controllers/data.js +168 -97
  28. package/server/routes/data/controllers/util/chartSQL.js +42 -25
  29. package/server/routes/data/controllers/util/normalizeData.js +59 -34
  30. package/server/routes/data/index.mjs +29 -26
  31. package/server/routes/dataset/controllers/bi.dataset.demo.add.js +97 -0
  32. package/server/routes/dataset/controllers/bi.dataset.import.js +67 -0
  33. package/server/routes/dataset/controllers/util/create.table.js +22 -0
  34. package/server/routes/dataset/controllers/util/prepare.data.js +49 -0
  35. package/server/routes/dataset/index.mjs +19 -0
  36. package/server/routes/db/controllers/dbTablePreview.js +63 -0
  37. package/server/routes/db/controllers/dbTables.js +36 -0
  38. package/server/routes/db/index.mjs +17 -0
  39. package/server/routes/edit/controllers/dashboard.add.js +26 -23
  40. package/server/routes/edit/controllers/dashboard.edit.js +46 -37
  41. package/server/routes/edit/controllers/widget.add.js +75 -49
  42. package/server/routes/edit/controllers/widget.del.js +69 -63
  43. package/server/routes/edit/controllers/widget.edit.js +52 -82
  44. package/server/routes/edit/index.mjs +31 -27
  45. package/server/routes/map/controllers/cluster.js +109 -75
  46. package/server/routes/map/controllers/clusterVtile.js +166 -143
  47. package/server/routes/map/controllers/geojson.js +127 -101
  48. package/server/routes/map/controllers/map.js +60 -57
  49. package/server/routes/map/controllers/utils/downloadClusterData.js +43 -0
  50. package/server/routes/map/controllers/vtile.js +183 -161
  51. package/server/routes/map/index.mjs +25 -25
  52. package/server/utils/getWidget.js +85 -56
  53. package/utils.js +12 -11
  54. package/dist/vs-calendar-WiK1hcHS.js +0 -96
  55. package/dist/vs-funnel-bar-CpPbYZ0_.js +0 -92
  56. package/dist/vs-heatmap-BG4eIROH.js +0 -83
  57. package/dist/vs-map-BRk6Fmks.js +0 -66
  58. package/dist/vs-number-CJq-vi95.js +0 -39
@@ -1,63 +1,69 @@
1
- import dataDelete from '@opengis/fastify-table/crud/funcs/dataDelete.js';
2
- import dataUpdate from '@opengis/fastify-table/crud/funcs/dataUpdate.js';
3
- export default async function widgetDel({ pg = {}, params = {} }) {
4
- const { widget: widgetName, name: dashboardName } = params;
5
-
6
- if (!widgetName || !dashboardName) {
7
- return {
8
- message: 'not enough params: dashboard and widget name',
9
- status: 400
10
- };
11
- }
12
-
13
- try {
14
- const row = await pg
15
- .query(
16
- `select a.widget_id, b.dashboard_id from bi.widget a, bi.dashboard b
17
- where $2 in (a.widget_id, a.name) and $1 in (b.dashboard_id, b.name) order by 1,2`,
18
- [dashboardName, widgetName]
19
- )
20
- .then((res1) => res1.rows?.[0] || {});
21
-
22
- const { widget_id: widgetId, dashboard_id: dashboardId } = row || {};
23
-
24
- if (!widgetId) {
25
- return { message: `widget not found ${widgetName}`, status: 404 };
26
- }
27
-
28
- const res = await dataDelete({
29
- table: 'bi.widget',
30
- id: widgetId
31
- });
32
-
33
- const currentDashboard = await pg
34
- .query(
35
- `select * from bi.dashboard
36
- where $1 in (dashboard_id, name)`,
37
- [dashboardName]
38
- )
39
- .then((res1) => res1.rows?.[0] || {});
40
-
41
- const body = currentDashboard;
42
-
43
- if (!currentDashboard) {
44
- return { message: `dashboard not found ${dashboardName}`, status: 404 };
45
- }
46
- body.panels = Array.isArray(body.panels) && body.panels?.length ? body.panels?.filter((panel) => panel.widget !== widgetName) : undefined;
47
- body.widgets = Array.isArray(body.widgets) && body?.widgets?.length ? body.widgets?.filter((widget) => widget.name !== widgetName) : undefined;
48
-
49
- const res1 = await dataUpdate({
50
- table: 'bi.dashboard',
51
- id: dashboardId,
52
- data: body
53
- });
54
-
55
- return {
56
- message: `Deleted widget ${widgetName}`,
57
- status: 200,
58
- rows: res1
59
- };
60
- } catch (err) {
61
- return { error: err.toString(), status: 500 };
62
- }
63
- }
1
+ import { dataDelete, dataUpdate } from '@opengis/fastify-table/utils.js';
2
+
3
+ export default async function widgetDel({ pg = {}, params = {} }) {
4
+ const { widget: widgetName, name: dashboardName } = params;
5
+
6
+ if (!widgetName || !dashboardName) {
7
+ return {
8
+ message: 'not enough params: dashboard and widget name',
9
+ status: 400,
10
+ };
11
+ }
12
+
13
+ try {
14
+ const row = await pg
15
+ .query(
16
+ `select a.widget_id, b.dashboard_id from bi.widget a, bi.dashboard b
17
+ where $2 in (a.widget_id, a.name) and $1 in (b.dashboard_id, b.name) order by 1,2`,
18
+ [dashboardName, widgetName]
19
+ )
20
+ .then((res1) => res1.rows?.[0] || {});
21
+
22
+ const { widget_id: widgetId, dashboard_id: dashboardId } = row || {};
23
+
24
+ if (!widgetId) {
25
+ return { message: `widget not found ${widgetName}`, status: 404 };
26
+ }
27
+
28
+ const res = await dataDelete({
29
+ table: 'bi.widget',
30
+ id: widgetId,
31
+ });
32
+
33
+ const currentDashboard = await pg
34
+ .query(
35
+ `select * from bi.dashboard
36
+ where $1 in (dashboard_id, name)`,
37
+ [dashboardName]
38
+ )
39
+ .then((res1) => res1.rows?.[0] || {});
40
+
41
+ const body = currentDashboard;
42
+
43
+ if (!currentDashboard) {
44
+ return { message: `dashboard not found ${dashboardName}`, status: 404 };
45
+ }
46
+ body.panels =
47
+ Array.isArray(body.panels) && body.panels?.length
48
+ ? body.panels?.filter((panel) => panel.widget !== widgetName)
49
+ : undefined;
50
+ body.widgets =
51
+ Array.isArray(body.widgets) && body?.widgets?.length
52
+ ? body.widgets?.filter((widget) => widget.name !== widgetName)
53
+ : undefined;
54
+
55
+ const res1 = await dataUpdate({
56
+ table: 'bi.dashboard',
57
+ id: dashboardId,
58
+ data: body,
59
+ });
60
+
61
+ return {
62
+ message: `Deleted widget ${widgetName}`,
63
+ status: 200,
64
+ rows: res1,
65
+ };
66
+ } catch (err) {
67
+ return { error: err.toString(), status: 500 };
68
+ }
69
+ }
@@ -1,82 +1,52 @@
1
- import dataUpdate from '@opengis/fastify-table/crud/funcs/dataUpdate.js';
2
- export default async function widgetEdit({ pg = {}, funcs = {}, body = {}, params = {} }) {
3
- const { widget: widgetName, name: dashboardName } = params;
4
- const tableName = body.table_name;
5
- if (!widgetName || !dashboardName) {
6
- return {
7
- message: 'not enough params: dashboard and widget name',
8
- status: 400
9
- };
10
- }
11
-
12
- try {
13
- const row = await pg
14
- .query(
15
- `select a.widget_id, b.dashboard_id from bi.widget a, bi.dashboard b
16
- where $2 in (a.widget_id, a.name) and $1 in (b.dashboard_id, b.name) order by 1,2`,
17
- [dashboardName, widgetName]
18
- )
19
- .then((res1) => res1.rows?.[0] || {});
20
- const checkTable = await pg.query(`select * from bi.widget where $1 in (table_name)`, [
21
- tableName
22
- ]);
23
- const { widget_id: widgetId, dashboard_id: dashboardId } = row || {};
24
- if (!checkTable.rows.length) return { message: 'bad params', status: 401 };
25
-
26
- if (!widgetId) {
27
- return { message: `widget not found ${widgetName}`, status: 404 };
28
- }
29
-
30
- const res = await funcs.dataUpdate({
31
- table: 'bi.widget',
32
- id: widgetId,
33
- data: body
34
- });
35
-
36
- //\====================
37
- const currentDashboard = await pg
38
- .query(
39
- `select * from bi.dashboard
40
- where $1 in (dashboard_id, name)`,
41
- [dashboardName]
42
- )
43
- .then((res1) => res1.rows?.[0] || {});
44
- const bodyDashboard = currentDashboard;
45
-
46
- if (!currentDashboard) {
47
- return { message: `dashboard not found ${dashboardName}`, status: 404 };
48
- }
49
- bodyDashboard.panels =
50
- Array.isArray(bodyDashboard.panels) && bodyDashboard.panels?.length
51
- ? bodyDashboard.panels?.map((panel) => {
52
- if (panel.widget === widgetName) {
53
- panel.col = body.col;
54
- }
55
- return panel;
56
- })
57
- : undefined;
58
- bodyDashboard.widgets =
59
- Array.isArray(bodyDashboard.widgets) && bodyDashboard?.widgets?.length
60
- ? bodyDashboard.widgets?.map((widget) => {
61
- if (widget.name === widgetName) {
62
- return body;
63
- }
64
- return widget;
65
- })
66
- : undefined;
67
-
68
- const res1 = await dataUpdate({
69
- table: 'bi.dashboard',
70
- id: dashboardId,
71
- data: bodyDashboard
72
- });
73
-
74
- return {
75
- message: `Edited widget ${widgetName}`,
76
- status: 200,
77
- rows: res1
78
- };
79
- } catch (err) {
80
- return { error: err.toString(), status: 500 };
81
- }
82
- }
1
+ import { dataUpdate } from '@opengis/fastify-table/utils.js';
2
+
3
+ import { yamlSafe } from '../../../../utils.js';
4
+
5
+ export default async function widgetEdit({ pg, body, params, }) {
6
+ const { widget: widgetName, name: dashboardName } = params;
7
+ const data = body.yml && !body.style ? yamlSafe.load(body.yml) : body;
8
+
9
+ const tableName =
10
+ data.data?.table || data?.table || data.table_name || body.table_name;
11
+
12
+ if (!widgetName || !dashboardName) {
13
+ return {
14
+ message: 'not enough params: dashboard and widget name',
15
+ status: 400,
16
+ };
17
+ }
18
+
19
+
20
+ const { widget_id: widgetId } = await pg.query(
21
+ `select a.widget_id , b.dashboard_id from bi.widget a, bi.dashboard b
22
+ where $2 in (a.widget_id, a.name) and $1 in (b.dashboard_id, b.name) order by 1,2`,
23
+ [dashboardName, widgetName]
24
+ ).then((res1) => res1.rows?.[0] || {});
25
+
26
+ if (!widgetId) {
27
+ return { message: `widget not found ${widgetName}`, status: 404 };
28
+ }
29
+
30
+ if (!tableName || !pg.pk?.[tableName]) {
31
+ return { message: 'bad params: table', status: 400 };
32
+ }
33
+
34
+
35
+
36
+ // const widgetData = { ...data, data };
37
+ const widgetData = body.yml && !body.style ? data : { style: data.style, data: { x: data.x, metrics: data.metrics }, controls: data.controls, type: data.type, title: data.title, table_name: data.table_name };
38
+ // console.log(widgetId, widgetData)
39
+ if (body?.yml) Object.assign(widgetData, { yml: body.yml });
40
+ const rows = await dataUpdate({
41
+ table: 'bi.widget',
42
+ id: widgetId,
43
+ data: widgetData,
44
+ });
45
+
46
+ return {
47
+ message: rows,
48
+ status: 200,
49
+
50
+ };
51
+
52
+ }
@@ -1,27 +1,31 @@
1
- import widgetAdd from '../edit/controllers/widget.add.js';
2
- import widgetEdit from '../edit/controllers/widget.edit.js';
3
- import widgetDel from '../edit/controllers/widget.del.js';
4
- import dashboardEdit from '../edit/controllers/dashboard.edit.js';
5
- import dashboardAdd from '../edit/controllers/dashboard.add.js';
6
-
7
- const biSchema = {
8
- querystring: {
9
- widget: { type: 'string', pattern: '^([\\d\\w]+)$' },
10
- dashboard: { type: 'string', pattern: '^([\\d\\w]+)$' },
11
- list: { type: 'string', pattern: '^([\\d])$' },
12
- sql: { type: 'string', pattern: '^([\\d])$' }
13
- },
14
- params: {
15
- name: { type: 'string', pattern: '^([\\d\\w]+)$' },
16
- widget: { type: 'string', pattern: '^([\\d\\w]+)$' }
17
- },
18
- };
19
-
20
-
21
- export default async function route(fastify) {
22
- fastify.post(`/bi-dashboard/:name`, { schema: biSchema }, widgetAdd);
23
- fastify.put(`/bi-dashboard/:name/:widget`, { schema: biSchema }, widgetEdit);
24
- fastify.delete(`/bi-dashboard/:name/:widget`, { schema: biSchema }, widgetDel);
25
- fastify.post(`/bi-dashboard`, { schema: biSchema }, dashboardAdd);
26
- fastify.put(`/bi-dashboard/:name`, { schema: biSchema }, dashboardEdit);
27
- }
1
+ /* eslint-disable import/extensions */
2
+ import widgetAdd from './controllers/widget.add.js';
3
+ import widgetEdit from './controllers/widget.edit.js';
4
+ import widgetDel from './controllers/widget.del.js';
5
+ import dashboardEdit from './controllers/dashboard.edit.js';
6
+ import dashboardAdd from './controllers/dashboard.add.js';
7
+
8
+ const biSchema = {
9
+ querystring: {
10
+ widget: { type: 'string', pattern: '^([\\d\\w]+)$' },
11
+ dashboard: { type: 'string', pattern: '^([\\d\\w]+)$' },
12
+ list: { type: 'string', pattern: '^([\\d])$' },
13
+ sql: { type: 'string', pattern: '^([\\d])$' },
14
+ },
15
+ params: {
16
+ name: { type: 'string', pattern: '^([\\d\\w]+)$' },
17
+ widget: { type: 'string', pattern: '^([\\d\\w]+)$' },
18
+ },
19
+ };
20
+
21
+ export default async function route(fastify) {
22
+ fastify.post(`/bi-dashboard/:name`, { schema: biSchema }, widgetAdd);
23
+ fastify.put(`/bi-dashboard/:name/:widget`, { schema: biSchema }, widgetEdit);
24
+ fastify.delete(
25
+ `/bi-dashboard/:name/:widget`,
26
+ { schema: biSchema },
27
+ widgetDel
28
+ );
29
+ fastify.post(`/bi-dashboard`, { schema: biSchema }, dashboardAdd);
30
+ fastify.put(`/bi-dashboard/:name`, { schema: biSchema }, dashboardEdit);
31
+ }
@@ -1,75 +1,109 @@
1
-
2
- import { getWidget } from '../../../../utils.js';
3
-
4
- export default async function cluster({
5
- pg, funcs, query = {}, log,
6
- }) {
7
- const {
8
- widget, filter, dashboard, search,
9
- } = query;
10
-
11
- if (!widget) {
12
- return { message: 'not enough params: widget', status: 400 };
13
- }
14
-
15
- const { data } = await getWidget({ dashboard, widget })
16
-
17
- try {
18
-
19
- const pkey = pg.pk?.[data?.table];
20
-
21
- if (!pkey) {
22
- return { message: `invalid ${widget ? 'widget' : 'dashboard'}: table pk not found (${data?.table})`, status: 400 };
23
- }
24
-
25
- // data param
26
- const { table, query: where = '1=1', metrics = [], cluster, clusterTable = {} } = data;
27
-
28
- if (!cluster) {
29
- return { message: `invalid ${widget ? 'widget' : 'dashboard'}: cluster column not specified`, status: 400 };
30
- }
31
-
32
- if (!metrics.length) {
33
- return { message: `invalid ${widget ? 'widget' : 'dashboard'}: metric columns not found`, status: 400 };
34
- }
35
-
36
- if (!clusterTable?.name) {
37
- return { message: 'not enough widget params: clusterTable name', status: 400 };
38
- }
39
-
40
- if (clusterTable?.name && !pg.pk?.[clusterTable?.name]) {
41
- return { message: 'invalid widget params: clusterTable pkey not found', status: 404 };
42
- }
43
-
44
- const { total = 0 } = pg.pk?.[table]
45
- ? await pg.queryCache(`select oid::regclass as table, reltuples AS total from pg_class`)
46
- .then((res) => res.rows?.find((row) => row.table === table))
47
- : {};
48
-
49
- const { bbox } = await pg.query(`select st_asgeojson(box2d(geom))::json as bbox from ${table} where ${where || '1=1'}`).then((res1) => res1.rows?.[0] || {});
50
-
51
- // get sql
52
- const { optimizedSQL } = filter || search
53
- ? await funcs.getFilterSQL({ pg, table, filter, search })
54
- : {};
55
-
56
- const q = `select "${cluster}" as name, sum("${metrics[0]}")::float as metric
57
- from ${optimizedSQL ? `(${optimizedSQL})` : table} q
58
- left join lateral (select "${pg.pk?.[clusterTable?.name]}" as id from ${clusterTable?.name} where ${clusterTable?.title}=q."${cluster}" limit 1)b on 1=1
59
- where ${where} group by ${cluster}, b.id`;
60
-
61
- if (query.sql === '1') return q;
62
-
63
- // auto Index
64
- // funcs.autoIndex({ table, columns: (metrics || []).concat([cluster]) });
65
-
66
- const { rows = [] } = await pg.query(q);
67
- const vals = rows.map(el => el.metric - 0).sort((a, b) => a - b);
68
- const len = vals.length;
69
- const sizes = [vals[0], vals[Math.floor(len / 4)], vals[Math.floor(len / 2)], vals[Math.floor(len * 0.75)], vals[len - 1]]
70
- return { sizes, rows, bbox, count: rows.length, total };
71
- } catch (err) {
72
- log.error('bi/cluster', { error: err.toString(), query });
73
- return { error: err.toString(), status: 500 };
74
- }
75
- }
1
+ import { getFilterSQL } from '@opengis/fastify-table/utils.js';
2
+
3
+ import { getWidget } from '../../../../utils.js';
4
+
5
+ import downloadClusterData from './utils/downloadClusterData.js';
6
+
7
+ const clusterExists = {};
8
+
9
+ export default async function cluster({ pg, query = {}, log }) {
10
+ const { widget, filter, dashboard, search } = query;
11
+
12
+ if (!widget) {
13
+ return { message: 'not enough params: widget', status: 400 };
14
+ }
15
+
16
+ const { data } = await getWidget({ dashboard, widget });
17
+
18
+ try {
19
+ const pkey = pg.pk?.[data?.table];
20
+
21
+ if (!pkey) {
22
+ return {
23
+ message: `invalid ${widget ? 'widget' : 'dashboard'}: table pk not found (${data?.table})`,
24
+ status: 400,
25
+ };
26
+ }
27
+
28
+ // data param
29
+ const {
30
+ table,
31
+ query: where = '1=1',
32
+ metrics = [],
33
+ cluster,
34
+ clusterTable = {},
35
+ } = data;
36
+
37
+ if (!cluster) {
38
+ return {
39
+ message: `invalid ${widget ? 'widget' : 'dashboard'}: cluster column not specified`,
40
+ status: 400,
41
+ };
42
+ }
43
+
44
+ if (!metrics.length) {
45
+ return {
46
+ message: `invalid ${widget ? 'widget' : 'dashboard'}: metric columns not found`,
47
+ status: 400,
48
+ };
49
+ }
50
+
51
+ if (!clusterTable?.name) {
52
+ Object.assign(clusterTable, {
53
+ name: 'bi.cluster',
54
+ title: 'title',
55
+ query: `type='${cluster}'`,
56
+ });
57
+ }
58
+
59
+ if (cluster && !clusterExists[cluster]) {
60
+ const res = await downloadClusterData({ pg, log, cluster });
61
+ if (res) return res;
62
+ clusterExists[cluster] = 1;
63
+ }
64
+
65
+ if (clusterTable?.name && !pg.pk?.[clusterTable?.name]) {
66
+ return {
67
+ message: 'invalid widget params: clusterTable pkey not found',
68
+ status: 404,
69
+ };
70
+ }
71
+
72
+ const { bounds, extentStr } = await pg.query(`select count(*),
73
+ st_asgeojson(st_extent(geom))::json as bounds,
74
+ replace(regexp_replace(st_extent(geom)::box2d::text,'BOX\\(|\\)','','g'),' ',',') as "extentStr"
75
+ from ${table} where ${where || '1=1'}`).then((res) => res.rows?.[0] || {});
76
+ const extent = extentStr ? extentStr.split(',') : undefined;
77
+
78
+ // get sql
79
+ const { optimizedSQL } =
80
+ filter || search
81
+ ? await getFilterSQL({ pg, table, filter, search })
82
+ : {};
83
+
84
+ const q = `select "${cluster}" as name, sum("${metrics[0]}")::float as metric
85
+ from ${optimizedSQL ? `(${optimizedSQL})` : table} q
86
+ left join lateral (select "${pg.pk?.[clusterTable?.name]}" as id from ${clusterTable?.name} where ${clusterTable?.title}=q."${cluster}" limit 1)b on 1=1
87
+ where ${where} group by ${cluster}, b.id order by sum("${metrics[0]}")::float desc`;
88
+
89
+ if (query.sql === '1') return q;
90
+
91
+ // auto Index
92
+ // autoIndex({ table, columns: (metrics || []).concat([cluster]) });
93
+
94
+ const { rows = [] } = await pg.query(q);
95
+ const vals = rows.map((el) => el.metric - 0).sort((a, b) => a - b);
96
+ const len = vals.length;
97
+ const sizes = [
98
+ vals[0],
99
+ vals[Math.floor(len / 4)],
100
+ vals[Math.floor(len / 2)],
101
+ vals[Math.floor(len * 0.75)],
102
+ vals[len - 1],
103
+ ];
104
+ return { sizes, rows, bounds, extent, count: rows.length, total: rows?.reduce((acc, curr) => (curr.metric || 0) + acc, 0) };
105
+ } catch (err) {
106
+ log.error('bi/cluster', { error: err.toString(), query });
107
+ return { error: err.toString(), status: 500 };
108
+ }
109
+ }