@opengis/bi 1.0.41 → 1.0.42

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.
@@ -1,4 +1,4 @@
1
- import { _ as y, c as D, i as g, a as c, b as h, P as l } from "./import-file-CcioJxEB.js";
1
+ import { _ as y, c as D, i as g, a as c, b as h, P as l } from "./import-file-XtDaxS3X.js";
2
2
  import { createElementBlock as b, openBlock as x } from "vue";
3
3
  const _ = {
4
4
  name: "VsPie",
@@ -1,4 +1,4 @@
1
- import { _ as n, c, i as h, b as o, d as l, a as d } from "./import-file-CcioJxEB.js";
1
+ import { _ as n, c, i as h, b as o, d as l, a as d } from "./import-file-XtDaxS3X.js";
2
2
  import { createElementBlock as p, openBlock as u } from "vue";
3
3
  const m = {
4
4
  name: "VsFunnelBar",
@@ -1,4 +1,4 @@
1
- import { _ as Qs, g as Vp, h as Np } from "./import-file-CcioJxEB.js";
1
+ import { _ as Qs, h as Vp, j as Np } from "./import-file-XtDaxS3X.js";
2
2
  import { createElementBlock as br, openBlock as wr, createElementVNode as Vt, createStaticVNode as jp, withDirectives as Up, toDisplayString as rh, vShow as $p, Fragment as ju, renderList as Uu, normalizeClass as qp, resolveComponent as Zp, createVNode as Gp } from "vue";
3
3
  const Hp = {}, Xp = {
4
4
  class: "shrink-0 size-3",
@@ -1,8 +1,8 @@
1
- import { c as R, l as A, p as N, b as P, V as Z, a as q, d as K, e as W, m as T } from "./vs-list-ONirzMum.js";
2
- import { _ as V, V as D, c as J, I as Q, e as U } from "./import-file-CcioJxEB.js";
3
- import { createElementBlock as h, createCommentVNode as S, openBlock as p, createElementVNode as l, normalizeClass as I, Fragment as O, renderList as F, toDisplayString as G, normalizeStyle as X, resolveComponent as u, withDirectives as z, createBlock as M, resolveDynamicComponent as Y, createVNode as w, vShow as C } from "vue";
4
- const j = {
5
- components: { legendIcon: A, closeIcon: R },
1
+ import { c as A, l as P, p as O, b as Z, V as q, a as K, d as W, e as D, m as T } from "./vs-list-C-gFvDvr.js";
2
+ import { _ as V, V as J, c as Q, e as N, I as U, g as X } from "./import-file-XtDaxS3X.js";
3
+ import { createElementBlock as h, createCommentVNode as S, openBlock as p, createElementVNode as l, normalizeClass as I, Fragment as F, renderList as G, toDisplayString as R, normalizeStyle as Y, resolveComponent as u, withDirectives as z, createBlock as M, resolveDynamicComponent as j, createVNode as w, vShow as C } from "vue";
4
+ const $ = {
5
+ components: { legendIcon: P, closeIcon: A },
6
6
  props: {
7
7
  mapId: { type: String },
8
8
  colors: { type: Array },
@@ -17,7 +17,7 @@ const j = {
17
17
  data() {
18
18
  return {
19
19
  isOpenLegend: !1,
20
- palette: N
20
+ palette: O
21
21
  // palette: ['#69D2E7', 'yellow', '#FE4365'],
22
22
  };
23
23
  },
@@ -45,37 +45,37 @@ const j = {
45
45
  return (t + 1) / this.sortedSizes.length;
46
46
  }
47
47
  }
48
- }, $ = {
48
+ }, ee = {
49
49
  key: 0,
50
50
  class: "absolute flex items-end w-fit bottom-[10px] max-w-[80%] left-[50%] translate-x-[-50%] bg-[rgba(255,255,255,0.7)] p-[10px] rounded"
51
- }, ee = { class: "w-[80px] mr-[10px]" }, te = ["title"], se = { class: "text-[10px] mb-[2px] text-[#1F2937] font-normal leading-[1.2]" };
52
- function oe(t, s, n, a, e, o) {
51
+ }, te = { class: "w-[80px] mr-[10px]" }, se = ["title"], oe = { class: "text-[10px] mb-[2px] text-[#1F2937] font-normal leading-[1.2]" };
52
+ function re(t, s, n, a, e, o) {
53
53
  var d;
54
- return (d = n.sizes) != null && d.length ? (p(), h("div", $, [
55
- l("div", ee, [
54
+ return (d = n.sizes) != null && d.length ? (p(), h("div", ee, [
55
+ l("div", te, [
56
56
  s[0] || (s[0] = l("p", { class: "text-[10px] mb-[2px] text-[#1F2937] leading-[1.2]" }, " Дані відсутні ", -1)),
57
57
  l("div", {
58
58
  class: I([o.sizeClass(t.index), "w-full border border-gray-500"])
59
59
  }, null, 2)
60
60
  ]),
61
- o.sortedSizes.length ? (p(!0), h(O, { key: 0 }, F(o.sortedSizes, (c, i) => {
62
- var v, x, _, m, g, y, f, b;
61
+ o.sortedSizes.length ? (p(!0), h(F, { key: 0 }, G(o.sortedSizes, (c, i) => {
62
+ var x, v, _, m, g, y, f, b;
63
63
  return p(), h("div", {
64
64
  class: "w-[80px]",
65
- title: i === ((v = o.sortedSizes) == null ? void 0 : v.length) - 1 ? ">" + c : i == ((x = o.sortedSizes) == null ? void 0 : x.length) - 1 ? ">" + o.sortedSizes[((_ = o.sortedSizes) == null ? void 0 : _.length) - 1] : c + "-" + o.sortedSizes[i + 1]
65
+ title: i === ((x = o.sortedSizes) == null ? void 0 : x.length) - 1 ? ">" + c : i == ((v = o.sortedSizes) == null ? void 0 : v.length) - 1 ? ">" + o.sortedSizes[((_ = o.sortedSizes) == null ? void 0 : _.length) - 1] : c + "-" + o.sortedSizes[i + 1]
66
66
  }, [
67
- l("p", se, G(i === ((m = o.sortedSizes) == null ? void 0 : m.length) - 1 ? ">" + parseInt(c) : i == ((g = o.sortedSizes) == null ? void 0 : g.length) - 1 ? ">" + parseInt(o.sortedSizes[((y = o.sortedSizes) == null ? void 0 : y.length) - 1]) : parseInt(c) + "-" + parseInt(o.sortedSizes[i + 1])), 1),
67
+ l("p", oe, R(i === ((m = o.sortedSizes) == null ? void 0 : m.length) - 1 ? ">" + parseInt(c) : i == ((g = o.sortedSizes) == null ? void 0 : g.length) - 1 ? ">" + parseInt(o.sortedSizes[((y = o.sortedSizes) == null ? void 0 : y.length) - 1]) : parseInt(c) + "-" + parseInt(o.sortedSizes[i + 1])), 1),
68
68
  l("div", {
69
69
  class: I([o.sizeClass(i), "w-full border border-r-0 border-gray-500"]),
70
- style: X({
70
+ style: Y({
71
71
  backgroundColor: ((b = (f = e.palette) == null ? void 0 : f[n.color]) == null ? void 0 : b[i]) || n.color
72
72
  })
73
73
  }, null, 6)
74
- ], 8, te);
74
+ ], 8, se);
75
75
  }), 256)) : S("", !0)
76
76
  ])) : S("", !0);
77
77
  }
78
- const re = /* @__PURE__ */ V(j, [["render", oe]]), ae = {}, ne = {
78
+ const ae = /* @__PURE__ */ V($, [["render", re]]), ne = {}, le = {
79
79
  xmlns: "http://www.w3.org/2000/svg",
80
80
  width: "24",
81
81
  height: "24",
@@ -87,8 +87,8 @@ const re = /* @__PURE__ */ V(j, [["render", oe]]), ae = {}, ne = {
87
87
  "stroke-linejoin": "round",
88
88
  class: "icon icon-tabler icons-tabler-outline icon-tabler-map"
89
89
  };
90
- function le(t, s) {
91
- return p(), h("svg", ne, s[0] || (s[0] = [
90
+ function ie(t, s) {
91
+ return p(), h("svg", le, s[0] || (s[0] = [
92
92
  l("path", {
93
93
  stroke: "none",
94
94
  d: "M0 0h24v24H0z",
@@ -99,24 +99,25 @@ function le(t, s) {
99
99
  l("path", { d: "M15 7v13" }, null, -1)
100
100
  ]));
101
101
  }
102
- const ie = /* @__PURE__ */ V(ae, [["render", le]]), pe = {
103
- mixins: [J, W],
102
+ const pe = /* @__PURE__ */ V(ne, [["render", ie]]), ce = {
103
+ mixins: [Q, D],
104
104
  components: {
105
- VsMapSetting: K,
106
- VsClusterLegend: re,
107
- VsMapGoHome: q,
108
- VsList: Z,
109
- VsMapSlotLayers: P,
110
- VsListbar: D
105
+ VsMapSetting: W,
106
+ VsClusterLegend: ae,
107
+ VsMapGoHome: K,
108
+ VsList: q,
109
+ VsMapSlotLayers: Z,
110
+ // VsListbar,
111
+ VsBar: J
111
112
  },
112
113
  data() {
113
114
  return {
114
115
  baseColor: "pink",
115
116
  kattotg: "",
116
117
  options: [
117
- { id: "map", text: "Карта", component: ie },
118
- { id: "table", text: "Таблиця", component: Q },
119
- { id: "chart", text: "Віджет", component: U }
118
+ { id: "map", text: "Карта", component: pe },
119
+ { id: "table", text: "Таблиця", component: U },
120
+ { id: "chart", text: "Віджет", component: X }
120
121
  ],
121
122
  activeTab: "map",
122
123
  mapId: `map-${Math.floor(Math.random() * 1e3)}`,
@@ -141,17 +142,19 @@ const ie = /* @__PURE__ */ V(ae, [["render", le]]), pe = {
141
142
  },
142
143
  methods: {
143
144
  async getMapData() {
144
- const t = await fetch(
145
- `/api/bi-cluster?widget=${this.widget}&dashboard=${this.dashboard}`
145
+ const t = await N.get(
146
+ `/bi-cluster?widget=${this.widget}&dashboard=${this.dashboard}`
147
+ ), { data: s } = await N.get(
148
+ `/bi-data?dashboard=${this.dashboard}&widget=${this.widget}`
146
149
  );
147
- this.data = await t.json();
150
+ console.log(s), this.data = t.data;
148
151
  },
149
152
  async loadHandler() {
150
153
  var a, e, o, d;
151
154
  this.baseColor = ((a = this.data.style) == null ? void 0 : a.color) || "blue";
152
155
  const t = ["case"];
153
156
  (d = (o = (e = this.data) == null ? void 0 : e.sizes) == null ? void 0 : o.reverse()) == null || d.forEach((c, i) => {
154
- t.push([">", ["get", "metric"], c]), t.push(N[this.baseColor][i]), i++;
157
+ t.push([">", ["get", "metric"], c]), t.push(O[this.baseColor][i]), i++;
155
158
  }), t.push("gray");
156
159
  const s = {
157
160
  type: "polygon",
@@ -231,23 +234,23 @@ const ie = /* @__PURE__ */ V(ae, [["render", le]]), pe = {
231
234
  }
232
235
  }
233
236
  }
234
- }, ce = { class: "h-full" }, de = { class: "flex items-start justify-between mb-[6px] w-full" }, he = { class: "text-gray-800 font-[600]" }, ue = { class: "flex gap-2" }, me = ["onClick"], ge = ["id"], ye = ["id"], fe = { class: "absolute flex flex-col right-[10px] top-[105px] gap-1" }, be = { class: "h-[calc(250px)]" };
237
+ }, de = { class: "h-full" }, he = { class: "flex items-start justify-between mb-[6px] w-full" }, ue = { class: "text-gray-800 font-[600]" }, me = { class: "flex gap-2" }, ge = ["onClick"], ye = ["id"], fe = ["id"], be = { class: "absolute flex flex-col right-[10px] top-[105px] gap-1" }, xe = { class: "h-[calc(250px)]" };
235
238
  function ve(t, s, n, a, e, o) {
236
239
  var m, g, y, f, b, k, L, E, B, H;
237
- const d = u("VsMapSetting"), c = u("VsMapSlotLayers"), i = u("VsMapGoHome"), v = u("VsClusterLegend"), x = u("VsList"), _ = u("VsListbar");
238
- return p(), h("div", ce, [
239
- l("div", de, [
240
- l("h3", he, G(t.title), 1),
241
- l("div", ue, [
242
- (p(!0), h(O, null, F(e.options, (r) => (p(), h("button", {
243
- class: I(["p-1 text-gray-700 border rounded-lg", [e.activeTab === (r == null ? void 0 : r.id) ? "ring-2 ring-blue-500" : ""]]),
244
- onClick: (xe) => e.activeTab = r == null ? void 0 : r.id
240
+ const d = u("VsMapSetting"), c = u("VsMapSlotLayers"), i = u("VsMapGoHome"), x = u("VsClusterLegend"), v = u("VsList"), _ = u("VsBar");
241
+ return p(), h("div", de, [
242
+ l("div", he, [
243
+ l("h3", ue, R(t.title), 1),
244
+ l("div", me, [
245
+ (p(!0), h(F, null, G(e.options, (r) => (p(), h("button", {
246
+ class: I(["p-1 text-gray-700 border rounded", [e.activeTab === (r == null ? void 0 : r.id) ? "ring-2 ring-blue-500" : ""]]),
247
+ onClick: (_e) => e.activeTab = r == null ? void 0 : r.id
245
248
  }, [
246
- (p(), M(Y(r == null ? void 0 : r.component), {
247
- height: "24",
248
- width: "24"
249
+ (p(), M(j(r == null ? void 0 : r.component), {
250
+ height: "16",
251
+ width: "16"
249
252
  }))
250
- ], 10, me))), 256))
253
+ ], 10, ge))), 256))
251
254
  ])
252
255
  ]),
253
256
  z(l("div", {
@@ -257,20 +260,20 @@ function ve(t, s, n, a, e, o) {
257
260
  l("div", {
258
261
  id: e.mapId,
259
262
  class: "h-[calc(100%-40px)] w-full flex items-end min-h-[250px]"
260
- }, null, 8, ye),
263
+ }, null, 8, fe),
261
264
  e.showSetting ? (p(), M(d, {
262
265
  key: 0,
263
266
  map: e.map,
264
267
  coordinates: e.coordinatesByMouse
265
268
  }, null, 8, ["map", "coordinates"])) : S("", !0),
266
269
  w(c, { map: e.map }, null, 8, ["map"]),
267
- l("div", fe, [
270
+ l("div", be, [
268
271
  w(i, {
269
272
  map: e.map,
270
273
  bbox: (m = e.data) == null ? void 0 : m.bounds
271
274
  }, null, 8, ["map", "bbox"])
272
275
  ]),
273
- w(v, {
276
+ w(x, {
274
277
  mapId: e.mapId,
275
278
  colors: (g = e.data) == null ? void 0 : g.colors,
276
279
  sizes: (y = e.data) == null ? void 0 : y.sizes,
@@ -278,10 +281,10 @@ function ve(t, s, n, a, e, o) {
278
281
  changeOpacityItem: "true",
279
282
  cluster: "true"
280
283
  }, null, 8, ["mapId", "colors", "sizes", "color"])
281
- ], 8, ge), [
284
+ ], 8, ye), [
282
285
  [C, e.activeTab == "map"]
283
286
  ]),
284
- z(w(x, {
287
+ z(w(v, {
285
288
  mapId: e.mapId,
286
289
  source: (f = e.data) == null ? void 0 : f.rows,
287
290
  total: ((b = e.data) == null ? void 0 : b.total) || 0,
@@ -290,7 +293,7 @@ function ve(t, s, n, a, e, o) {
290
293
  }, null, 8, ["mapId", "source", "total", "count"]), [
291
294
  [C, e.activeTab == "table"]
292
295
  ]),
293
- z(l("div", be, [
296
+ z(l("div", xe, [
294
297
  (E = (L = e.data) == null ? void 0 : L.rows) != null && E.length ? (p(), M(_, {
295
298
  key: 0,
296
299
  source: (H = (B = e.data) == null ? void 0 : B.rows) == null ? void 0 : H.map((r) => ({
@@ -303,7 +306,7 @@ function ve(t, s, n, a, e, o) {
303
306
  ])
304
307
  ]);
305
308
  }
306
- const ze = /* @__PURE__ */ V(pe, [["render", ve]]);
309
+ const Me = /* @__PURE__ */ V(ce, [["render", ve]]);
307
310
  export {
308
- ze as default
311
+ Me as default
309
312
  };
@@ -1,5 +1,5 @@
1
- import { c as L, l as $, p as B, V as H, a as O, b as T, d as F, m as S, e as N } from "./vs-list-ONirzMum.js";
2
- import { _ as C, c as R } from "./import-file-CcioJxEB.js";
1
+ import { c as L, l as $, p as B, V as H, a as O, b as T, d as F, m as S, e as N } from "./vs-list-C-gFvDvr.js";
2
+ import { _ as C, c as R } from "./import-file-XtDaxS3X.js";
3
3
  import { resolveComponent as u, createElementBlock as d, openBlock as n, Fragment as w, createElementVNode as a, createBlock as E, createCommentVNode as c, createVNode as f, Teleport as A, toDisplayString as b, renderList as k, normalizeStyle as I, normalizeClass as V } from "vue";
4
4
  const G = {
5
5
  components: { legendIcon: $, closeIcon: L },
@@ -98,7 +98,7 @@ function ee(e, t, s, o, r, l) {
98
98
  backgroundColor: i.color
99
99
  })
100
100
  }, null, 4)) : c("", !0),
101
- a("p", K, b(i.val), 1)
101
+ a("p", K, b(i.text || i.val), 1)
102
102
  ]))), 128))
103
103
  ])
104
104
  ])) : c("", !0),
@@ -1,4 +1,4 @@
1
- import { _ as c, c as o, f as n } from "./import-file-CcioJxEB.js";
1
+ import { _ as c, c as o, f as n } from "./import-file-XtDaxS3X.js";
2
2
  import { createElementBlock as i, openBlock as m, toDisplayString as s } from "vue";
3
3
  const u = {
4
4
  name: "VsNumber",
@@ -1,4 +1,4 @@
1
- import { _ as m, c as f, d as _, a as b } from "./import-file-CcioJxEB.js";
1
+ import { _ as m, c as f, d as _, a as b } from "./import-file-XtDaxS3X.js";
2
2
  import { createElementBlock as a, openBlock as r, createElementVNode as s, Fragment as n, renderList as c, toDisplayString as d } from "vue";
3
3
  const x = {
4
4
  name: "VsTable",
@@ -1,4 +1,4 @@
1
- import { _ as o, c as s, m as i } from "./import-file-CcioJxEB.js";
1
+ import { _ as o, c as s, m as i } from "./import-file-XtDaxS3X.js";
2
2
  import { createElementBlock as r, openBlock as n, createCommentVNode as a } from "vue";
3
3
  const c = {
4
4
  name: "VsText",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/bi",
3
- "version": "1.0.41",
3
+ "version": "1.0.42",
4
4
  "description": "BI data visualization module",
5
5
  "main": "dist/bi.js",
6
6
  "browser": "dist/bi.umd.cjs",
@@ -31,6 +31,7 @@ export default async function dashboard({
31
31
  } catch (err) {
32
32
  data.error = err.toString();
33
33
  }
34
+
34
35
  data.type = 'bd';
35
36
  const { table_name: table } = data;
36
37
 
@@ -38,7 +39,16 @@ export default async function dashboard({
38
39
  return { message: 'not enough params: table required', status: 400 };
39
40
  }
40
41
 
41
- const { fields = [] } = table && pg.pk?.[table] ? await pg.query(`select * from ${table} limit 0`) : {};
42
+ const loadTemplate = pg.pk?.['admin.doc_template'] ? await pg.query(
43
+ 'select body from admin.doc_template where doc_type=5 and title=$1',
44
+ [table]
45
+ ).then(el => el.rows?.[0]?.body) : null;
46
+
47
+ const sqlList = loadTemplate?.sql ? loadTemplate?.sql
48
+ ?.filter?.(el => !el.disabled && el?.sql?.replace)
49
+ ?.map?.((el, i) => `left join lateral (${el.sql.replace(/limit 1/ig, '')}) t${i} on 1=1`)?.join?.(' ') : '';
50
+
51
+ const { fields = [] } = table && pg.pk?.[loadTemplate?.table || table] ? await pg.query(`select * from ${loadTemplate?.table || table} t ${sqlList || ''} limit 0`) : {};
42
52
 
43
53
  data?.widgets?.forEach?.(el => {
44
54
  const { style, data = {}, type, title, x, metrics } = el;
@@ -51,11 +61,10 @@ export default async function dashboard({
51
61
  Object.assign(el, { title, type });
52
62
  });
53
63
 
54
- const meta = table ? await getMeta({ pg, table }) : {};
64
+ const meta = table ? await getMeta({ pg, table: loadTemplate?.table || table }) : {};
65
+ const columnIndexes = meta?.columns?.reduce((acc, curr, idx) => Object.assign(acc, { [curr.name]: idx }), {}) || [];
55
66
 
56
- const columns = meta?.columns
57
- ?.filter(el => fields.map(field => field.name).includes(el.name))
58
- ?.map(el => ({ name: el.name, title: el.title, type: pg.pgType?.[el.dataTypeID] }));
67
+ const columns = fields?.map(el => ({ name: el.name, title: meta?.columns[columnIndexes[el.name]]?.title || el.name, type: pg.pgType?.[el.dataTypeID] }));
59
68
 
60
69
  return {
61
70
  ...data || {},
@@ -63,8 +72,9 @@ export default async function dashboard({
63
72
  panels: data?.panels?.filter?.(el => el?.widget) || [],
64
73
  geom: !meta?.geom,
65
74
  error:
66
- table && !pg.pk?.[table] ? `table pkey not found: ${table}` : undefined,
75
+ table && !pg.pk?.[loadTemplate?.table || table] ? `table pkey not found: ${loadTemplate?.table || table}` : undefined,
67
76
  table_name: table,
77
+ templateTable: loadTemplate?.table,
68
78
  time: Date.now() - time,
69
79
  columns,
70
80
  };
@@ -34,7 +34,7 @@ export default async function dataAPI(req, reply) {
34
34
  const pg = widgetData.pg || req.pg || pgClients.client;
35
35
 
36
36
  const { fields: cols } = await pg.query(
37
- `select * from ${data.table} limit 0`
37
+ `select * from ${data.table} t ${widgetData.tableSQL || data.tableSQL || ''} limit 0`
38
38
  );
39
39
  const columnTypes = cols.map((el) => ({
40
40
  name: el.name,
@@ -65,8 +65,8 @@ export default async function dataAPI(req, reply) {
65
65
  return { message: `table not found: ${data.table} (${pg.options?.database})`, status: 404 };
66
66
  }
67
67
 
68
- const columnList = columns.map(col => col.name);
69
- const groupbyColumnNotExists = groupby?.split?.(',')?.filter?.(el => !columnList.includes(el.trim()));
68
+ // const columnList = columns.map(col => col.name);
69
+ const groupbyColumnNotExists = groupby?.split?.(',')?.filter?.(el => !columnTypes.map(el => el.name).includes(el.trim()));
70
70
 
71
71
  if (groupby && groupbyColumnNotExists?.length) {
72
72
  return { message: `groupby column not found: ${groupbyColumnNotExists} (${data.table}/${pg.options?.database})`, status: 404 };
@@ -83,7 +83,7 @@ export default async function dataAPI(req, reply) {
83
83
 
84
84
  if (query.sql === '2') return { x, metric, table, tableSQL, data, groupData };
85
85
 
86
- const order = data.order || (type === 'listbar' ? 'metric desc' : null);
86
+ const order = data.order || (type === 'listbar' && cols.find(el => el.name === 'metric') ? 'metric desc' : null);
87
87
 
88
88
  const fData =
89
89
  filter || search
@@ -139,7 +139,8 @@ export default async function dataAPI(req, reply) {
139
139
  };
140
140
  }
141
141
 
142
- if (config.debug) console.log(sql, user?.uid);
142
+ if (config.trace) console.log(sql, user?.uid);
143
+
143
144
  const { rows, fields } = await pg.query(sql.replace('{{uid}}', user?.uid)); // test with limit
144
145
 
145
146
  if (cls) {
@@ -57,7 +57,7 @@ function normalizeData(data, query = {}, columnTypes = []) {
57
57
  const where = `${data.query || '1=1'} and ${custom || 'true'}`;
58
58
 
59
59
  const tableSQL = data.tableSQL?.length
60
- ? `(select * from ${data?.table} t ${data.tableSQL.join(' \n ')} where ${where})q`
60
+ ? `(select * from ${data?.table} t ${data.tableSQL || ''} where ${where})q`
61
61
  : undefined;
62
62
 
63
63
  return { x, cls, metric, table, where, tableSQL, groupby, xName, xType, yName, yType, error: skip.length ? skip.join(',') : undefined };
@@ -1,5 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { dataInsert, dataUpdate, pgClients } from "@opengis/fastify-table/utils.js";
2
+ import { dataInsert, dataUpdate, getPGAsync, pgClients } from "@opengis/fastify-table/utils.js";
3
3
 
4
4
  /* eslint-disable import/extensions */
5
5
  import { yamlSafe } from '../../../../utils.js';
@@ -20,12 +20,19 @@ export default async function widgetAdd({ pg = pgClients.client, params = {}, bo
20
20
  const row = await pg.query(`select dashboard_id, widgets, panels, table_name, db from bi.dashboard
21
21
  where $1 in (dashboard_id,name)`, [dashboardName]).then(el => el.rows?.[0] || {});
22
22
 
23
+ const pg1 = row?.db ? await getPGAsync(row.db) : pg;
24
+
23
25
  const tableName = data.data?.table
24
26
  || data?.table
25
27
  || data.table_name
26
28
  || row.table_name;
27
29
 
28
- if (!tableName || !(pg.pk?.[tableName] || pgClients[data.db || row.db || 'client']?.pk?.[tableName])) {
30
+ const loadTemplate = pg1.pk?.['admin.doc_template'] ? await pg1.query(
31
+ 'select body from admin.doc_template where doc_type=5 and title=$1',
32
+ [tableName]
33
+ ).then(el => el.rows?.[0]?.body) : null;
34
+
35
+ if (!tableName || !(pg.pk?.[loadTemplate?.table || tableName] || pgClients[data.db || row.db || 'client']?.pk?.[loadTemplate?.table || tableName])) {
29
36
  return { message: 'bad params: table', status: 400 };
30
37
  }
31
38
 
@@ -37,8 +37,18 @@ export default async function widgetEdit({ pg = pgClients.client, body, params }
37
37
  .reduce((p, el) => ({ ...p, [el]: data[el] }), {});
38
38
 
39
39
  // get table
40
- const tableName = body.table || widgetData.data?.table_name || widgetData.data?.table || widgetData?.table_name || templateData.table;
41
- if (!tableName || !(pg.pk?.[tableName] || pgClients[widgetData?.data?.db || templateData?.db || 'client']?.pk?.[tableName])) {
40
+ const tableName = body.table
41
+ || widgetData.data?.table_name
42
+ || widgetData.data?.table
43
+ || widgetData?.table_name
44
+ || templateData.table;
45
+
46
+ const loadTemplate = pg.pk?.['admin.doc_template'] ? await pg.query(
47
+ 'select body from admin.doc_template where doc_type=5 and title=$1',
48
+ [tableName]
49
+ ).then(el => el.rows?.[0]?.body) : null;
50
+
51
+ if (!tableName || !(pg.pk?.[loadTemplate?.table || tableName] || pgClients[widgetData?.data?.db || templateData?.db || 'client']?.pk?.[loadTemplate?.table || tableName])) {
42
52
  return { message: 'bad params: table ' + tableName, status: 400 };
43
53
  }
44
54
 
@@ -31,9 +31,9 @@ export default async function map(req) {
31
31
  );
32
32
  if (data?.cls) {
33
33
  const vals = await getSelectVal({
34
- pg, name: data.cls, values: rows.map(el => el.val),
34
+ pg, name: data.cls, values: rows.map(el => el.val), ar: true,
35
35
  });
36
- rows.forEach(row => Object.assign(row, { val: vals?.[row.val || ''] || row.val }));
36
+ rows.forEach(row => Object.assign(row, { ...vals?.find?.(el => el.id === row.val) || { text: row.val } }));
37
37
  }
38
38
  Object.assign(res, { colors: rows }); // кольори для легенди
39
39
  }
@@ -85,10 +85,15 @@ async function getWidget({ pg: pg1 = pgClients.client, dashboard, widget }) {
85
85
  };
86
86
  }
87
87
 
88
- const { pk, view } = await getMeta({ pg: widgetDb, table: main?.table });
88
+ const loadTemplate = pg.pk?.['admin.doc_template'] ? await pg.query(
89
+ 'select body from admin.doc_template where doc_type=5 and title=$1',
90
+ [main.table]
91
+ ).then(el => el.rows?.[0]?.body) : null;
92
+
93
+ const { pk, view, columns = [] } = await getMeta({ pg: widgetDb, table: loadTemplate?.table || main?.table });
89
94
  if (!pk && !view) {
90
95
  return {
91
- message: /* json.error || */ `invalid ${widget ? 'widget' : 'dashboard'}: table not found (${main?.table})`,
96
+ message: /* json.error || */ `invalid ${widget ? 'widget' : 'dashboard'}: table not found (${loadTemplate?.table || main?.table})`,
92
97
  status: 404,
93
98
  };
94
99
  }
@@ -97,6 +102,16 @@ async function getWidget({ pg: pg1 = pgClients.client, dashboard, widget }) {
97
102
  (el, i) => `left join lateral(${el})t${i + 1} on 1=1`
98
103
  );
99
104
 
100
- return { ...main, pg: widgetDb, sql: widgetData?.sql, limit: widgetData?.limit, tableSQL, data, type, text, controls, style, options, yml };
105
+ const columnList = columns.map(col => col.name);
106
+
107
+ const res = { ...main, pg: widgetDb, sql: widgetData?.sql, limit: widgetData?.limit, tableSQL, data, type, text, controls, style, options, yml };
108
+ if (res.x && !columnList.includes(res.x) && !loadTemplate?.table) {
109
+ Object.assign(res, { x: null, error: `column does not exists: ${res.x} at table ${res.table}` });
110
+ }
111
+ if (loadTemplate?.table) {
112
+ Object.assign(res.data || {}, { table: loadTemplate?.table });
113
+ Object.assign(res, { table: loadTemplate?.table, table_name: loadTemplate?.table, tableSQL: loadTemplate.sql?.filter?.(el => !el.disabled && el?.sql?.replace)?.map?.((el, i) => `left join lateral(${el.sql})t${i + 1} on 1=1`)?.join?.(' ') });
114
+ }
115
+ return res;
101
116
  }
102
117
  export default getWidget;