@opengis/bi 1.0.21 → 1.0.23

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 (71) hide show
  1. package/dist/bi.js +1 -1
  2. package/dist/bi.umd.cjs +109 -106
  3. package/dist/{import-file-C8BY90-b.js → import-file-DgBd_UN1.js} +20484 -18794
  4. package/dist/{map-component-mixin-CFtShPun.js → map-component-mixin-NewmNy_M.js} +502 -483
  5. package/dist/style.css +1 -1
  6. package/dist/{vs-calendar-B9vXdsaG.js → vs-calendar-CPXj4hBh.js} +1 -1
  7. package/dist/vs-donut-CUmi2ir5.js +148 -0
  8. package/dist/{vs-funnel-bar-Cj0O8tIf.js → vs-funnel-bar-B3DpbtUl.js} +1 -1
  9. package/dist/{vs-heatmap-C9oFph_f.js → vs-heatmap-COwT3bHE.js} +1 -1
  10. package/dist/{vs-map-WOn0RAU7.js → vs-map-DwyQHLpN.js} +2 -2
  11. package/dist/{vs-map-cluster-RJa6sNfI.js → vs-map-cluster-CnZ9g6k-.js} +2 -2
  12. package/dist/{vs-number-BG0szZL-.js → vs-number-LwROg9Oe.js} +5 -5
  13. package/dist/vs-table-Dt_MSaCC.js +68 -0
  14. package/dist/{vs-text-Kwl3-0yy.js → vs-text-DgAf3Ids.js} +2 -2
  15. package/package.json +6 -5
  16. package/plugin.js +1 -1
  17. package/server/helpers/mdToHTML.js +17 -0
  18. package/server/migrations/bi.dataset.sql +13 -0
  19. package/server/migrations/bi.sql +2 -0
  20. package/server/routes/dashboard/controllers/dashboard.js +10 -11
  21. package/server/routes/dashboard/controllers/dashboard.list.js +6 -6
  22. package/server/routes/data/controllers/data.js +14 -6
  23. package/server/routes/data/controllers/util/chartSQL.js +6 -3
  24. package/server/routes/dataset/controllers/bi.dataset.list.js +3 -1
  25. package/server/routes/dataset/controllers/comment.js +55 -0
  26. package/server/routes/dataset/controllers/createDatasetPost.js +132 -0
  27. package/server/routes/dataset/controllers/data.js +145 -0
  28. package/server/routes/{db → dataset}/controllers/dbTablePreview.js +17 -24
  29. package/server/routes/{db → dataset}/controllers/dbTables.js +7 -11
  30. package/server/routes/dataset/controllers/delete.js +39 -0
  31. package/server/routes/dataset/controllers/{bi.dataset.edit.js → editDataset.js} +32 -26
  32. package/server/routes/dataset/controllers/export.js +213 -0
  33. package/server/routes/dataset/controllers/form.js +99 -0
  34. package/server/routes/dataset/controllers/format.js +44 -0
  35. package/server/routes/dataset/controllers/insert.js +46 -0
  36. package/server/routes/dataset/controllers/table.js +69 -0
  37. package/server/routes/dataset/controllers/update.js +42 -0
  38. package/server/routes/dataset/index.mjs +88 -43
  39. package/server/routes/dataset/utils/convertJSONToCSV.js +17 -0
  40. package/server/routes/dataset/utils/convertJSONToXls.js +49 -0
  41. package/server/routes/dataset/utils/createTableQuery.js +59 -0
  42. package/server/routes/dataset/utils/datasetForms.js +1 -0
  43. package/server/routes/dataset/utils/descriptionList.js +46 -0
  44. package/server/routes/dataset/utils/downloadRemoteFile.js +58 -0
  45. package/server/routes/dataset/utils/executeQuery.js +46 -0
  46. package/server/routes/dataset/utils/getLayersData.js +107 -0
  47. package/server/routes/dataset/utils/getTableData.js +47 -0
  48. package/server/routes/dataset/utils/insertDataQuery.js +12 -0
  49. package/server/routes/dataset/utils/metaFormat.js +24 -0
  50. package/server/routes/edit/controllers/dashboard.add.js +3 -3
  51. package/server/routes/edit/controllers/widget.add.js +8 -3
  52. package/server/routes/edit/controllers/widget.edit.js +23 -5
  53. package/server/routes/map/controllers/cluster.js +41 -41
  54. package/server/routes/map/controllers/clusterVtile.js +5 -5
  55. package/server/routes/map/controllers/geojson.js +6 -6
  56. package/server/routes/map/controllers/heatmap.js +118 -0
  57. package/server/routes/map/controllers/map.js +3 -3
  58. package/server/routes/map/controllers/utils/downloadClusterData.js +6 -4
  59. package/server/routes/map/controllers/vtile.js +3 -3
  60. package/server/routes/map/index.mjs +2 -0
  61. package/server/utils/getWidget.js +10 -6
  62. package/server/routes/dataset/controllers/bi.dataset.add.js +0 -86
  63. package/server/routes/dataset/controllers/bi.dataset.data.add.js +0 -49
  64. package/server/routes/dataset/controllers/bi.dataset.data.del.js +0 -54
  65. package/server/routes/dataset/controllers/bi.dataset.data.edit.js +0 -55
  66. package/server/routes/dataset/controllers/bi.dataset.data.list.js +0 -71
  67. package/server/routes/dataset/controllers/bi.dataset.del.js +0 -48
  68. package/server/routes/dataset/controllers/bi.dataset.demo.add.js +0 -97
  69. package/server/routes/dataset/controllers/util/create.table.js +0 -21
  70. package/server/routes/dataset/controllers/util/prepare.data.js +0 -49
  71. package/server/routes/db/index.mjs +0 -17
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .custom-x-scrollbar{overflow-x:auto;overflow-y:clip}.custom-x-scrollbar::-webkit-scrollbar{height:6px}.custom-x-scrollbar::-webkit-scrollbar-thumb{background-color:#e0e0e0}.custom-x-scrollbar::-webkit-scrollbar-track{background-color:#f1f1f1}.ui-dialog__wrapper[data-v-e51369e3]{position:relative}.ui-dialog__modal[data-v-e51369e3]{margin:10px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);min-height:0;height:fit-content;max-height:80vh;overflow:hidden}.ui-dialog__content[data-v-e51369e3]{min-height:0;height:100%;overflow:auto}.ui-dialog__content[data-v-e51369e3]::-webkit-scrollbar{width:6px;height:6px;background-color:#f5f5f5}.ui-dialog__content[data-v-e51369e3]::-webkit-scrollbar-thumb{border-radius:10px;background-color:#d9d9d9bf}.ui-dialog__content[data-v-e51369e3]::-webkit-scrollbar-track{background-color:#f5f5f5}@media (max-width: 650px){.ui-dialog__modal[data-v-e51369e3]{top:50%}}.fade-enter-active[data-v-e51369e3],.fade-leave-active[data-v-e51369e3]{transition:opacity .2s}.fade-enter-from[data-v-e51369e3],.fade-leave-to[data-v-e51369e3]{opacity:0}.content-enter-active[data-v-e51369e3],.content-leave-active[data-v-e51369e3]{transition:transform .4s}.content-enter-from[data-v-e51369e3],.content-leave-to[data-v-e51369e3]{transform:translate(-50%,-50%) scale(.95)}.custom-scrollbar{overflow-y:auto;overflow-x:clip}.custom-scrollbar::-webkit-scrollbar{width:6px;margin-right:0}.custom-scrollbar::-webkit-scrollbar-thumb{background-color:#e0e0e0;border-radius:10px}.custom-scrollbar::-webkit-scrollbar-track{background-color:#f1f1f1}.vs-chart{width:100%;height:100%}.vs-chart-tooltip{border-radius:7px;max-height:100px;max-width:340px;min-width:140px;background-color:#fff;box-shadow:0 0 8px #0000002e}.vs-chart-tooltip__head{padding:5px;border-bottom:1px solid #eee;margin-bottom:5px}.vs-chart-tooltip__head-title{font-size:14px;font-weight:700;display:flex;align-items:center}.vs-chart-tooltip__head-value{margin-right:5px}.vs-chart-tooltip__head-series{font-size:14px;display:flex;align-items:center}.vs-chart-tooltip__color{width:12px;height:12px;display:block;border-radius:50%;margin-right:5px}.vs-chart-tooltip__body{padding:5px;font-size:14px;display:flex;align-items:start;flex-direction:column}.vs-chart-tooltip__body .vs-chart-tooltip__color{border-radius:3px}.vs-chart-tooltip__item{width:100%;display:flex;align-items:center;justify-content:space-between}.vs-chart-tooltip__text{margin-right:auto}.vs-chart-tooltip__body svg{margin-right:8px}body{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.vs-map-portal__legend[data-v-16c83b8b]{position:absolute;bottom:10px;right:45px}.vs-map-portal__legend-body[data-v-16c83b8b]{background-color:#fff;border-radius:12px;border:1px solid #dcdfe5;width:250px;padding:16px;max-height:250px}.map__settings{display:flex;padding:3px 1px;background:#fff;position:absolute;right:0;bottom:15px;height:30px;align-items:center;font-weight:100;text-align:center}.map__settings-item{display:flex;white-space:nowrap;padding:0 2px;font-size:10px;font-weight:400}.map__settings-attribution{padding:0}.map__settings-menu{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:15px!important;position:absolute;background-color:#fff;bottom:60px;right:90px;width:260px}.map__settings-menu-item{display:flex;align-items:center;color:#2c2c2c;margin-bottom:5px;font-size:12px;justify-content:space-between;height:28px}.map__settings-menu-item-text{height:28px;line-height:28px;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;display:inline-block;font-size:12px;height:40px;line-height:40px;outline:0;padding:0 10px}.map__settings-menu-item--checktext{color:#000!important;font-size:12px;display:inline-block;padding-left:10px;line-height:19px;cursor:pointer}.checked{color:#409eff!important}.vs-map-slot-layers[data-v-aebbde6b]{position:absolute;display:flex;bottom:10px;left:15px}.vs-map-slot-layers__layer[data-v-aebbde6b]{width:50px;height:50px;background-color:#fff;box-shadow:0 0 7px #434c5626;padding:5px;border-radius:5px;margin-top:10px;margin-right:10px;cursor:pointer;transition:all .3s}.vs-map-slot-layers__layer[data-v-aebbde6b]:hover{background-color:#eee}.vs-map-slot-layers__image[data-v-aebbde6b]{width:100%;border-radius:5px;object-fit:contain}.focused[data-v-aebbde6b]{background-color:#1989fa!important}.vs-map-portal__list{position:absolute}.vs-map-portal__legend-title{padding-bottom:5px;border-bottom:1px solid #ebebeb}.vs-map-portal__legend-button{cursor:pointer;display:flex;align-items:center;justify-content:center;flex-direction:column;height:35px;background-color:#fff;border-radius:5px;border:1px solid #dcdfe5;padding:5px}.vs-map-portal__legend-body{background-color:#fff;border-radius:5px;border:1px solid #dcdfe5;padding:5px;width:250px;max-height:250px}.vs-map-portal__legend-body__content{padding-top:10px}.vs-map-portal__legend-category{font-weight:700;margin-bottom:5px}.vs-map-portal__legend-item{margin-right:10px;display:flex;flex-shrink:0}.vs-map-portal__legend-item__color{width:16px;height:16px;border-radius:3px;margin-right:10px;display:flex;flex-shrink:0}.maplibregl-popup-content{padding:0}
1
+ @font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format("woff2");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format("woff2");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format("woff2");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format("woff2");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format("woff2");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format("woff2");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}body{font-family:Inter,Segoe UI,Helvetica Neue,Roboto,sans-serif;font-weight:400}h1{font-family:Inter,Segoe UI,Helvetica Neue,Roboto,sans-serif;font-weight:700}em{font-family:Inter,Segoe UI,Helvetica Neue,Roboto,sans-serif;font-style:italic}.custom-x-scrollbar{overflow-x:auto;overflow-y:clip}.custom-x-scrollbar::-webkit-scrollbar{height:6px}.custom-x-scrollbar::-webkit-scrollbar-thumb{background-color:#e0e0e0}.custom-x-scrollbar::-webkit-scrollbar-track{background-color:#f1f1f1}.custom-scrollbar{overflow-y:auto;overflow-x:clip}.custom-scrollbar::-webkit-scrollbar{width:6px;margin-right:0}.custom-scrollbar::-webkit-scrollbar-thumb{background-color:#e0e0e0;border-radius:10px}.custom-scrollbar::-webkit-scrollbar-track{background-color:#f1f1f1}.vs-chart{width:100%;height:100%}.vs-chart-tooltip{border-radius:7px;max-height:100px;max-width:340px;min-width:140px;background-color:#fff;box-shadow:0 0 8px #0000002e}.vs-chart-tooltip__head{padding:5px;border-bottom:1px solid #eee;margin-bottom:5px}.vs-chart-tooltip__head-title{font-size:14px;font-weight:700;display:flex;align-items:center}.vs-chart-tooltip__head-value{margin-right:5px}.vs-chart-tooltip__head-series{font-size:14px;display:flex;align-items:center}.vs-chart-tooltip__color{width:12px;height:12px;display:block;border-radius:50%;margin-right:5px}.vs-chart-tooltip__body{padding:5px;font-size:14px;display:flex;align-items:start;flex-direction:column}.vs-chart-tooltip__body .vs-chart-tooltip__color{border-radius:3px}.vs-chart-tooltip__item{width:100%;display:flex;align-items:center;justify-content:space-between}.vs-chart-tooltip__text{margin-right:auto}.vs-chart-tooltip__body svg{margin-right:8px}body{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.label[data-v-31ba6887]{margin-left:4px;font-size:16px}.vs-map-portal__legend[data-v-16c83b8b]{position:absolute;bottom:10px;right:45px}.vs-map-portal__legend-body[data-v-16c83b8b]{background-color:#fff;border-radius:12px;border:1px solid #dcdfe5;width:250px;padding:16px;max-height:250px}.map__settings{display:flex;padding:3px 1px;background:#fff;position:absolute;right:0;bottom:15px;height:30px;align-items:center;font-weight:100;text-align:center}.map__settings-item{display:flex;white-space:nowrap;padding:0 2px;font-size:10px;font-weight:400}.map__settings-attribution{padding:0}.map__settings-menu{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:15px!important;position:absolute;background-color:#fff;bottom:60px;right:90px;width:260px}.map__settings-menu-item{display:flex;align-items:center;color:#2c2c2c;margin-bottom:5px;font-size:12px;justify-content:space-between;height:28px}.map__settings-menu-item-text{height:28px;line-height:28px;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;display:inline-block;font-size:12px;height:40px;line-height:40px;outline:0;padding:0 10px}.map__settings-menu-item--checktext{color:#000!important;font-size:12px;display:inline-block;padding-left:10px;line-height:19px;cursor:pointer}.checked{color:#409eff!important}.vs-map-slot-layers[data-v-aebbde6b]{position:absolute;display:flex;bottom:10px;left:15px}.vs-map-slot-layers__layer[data-v-aebbde6b]{width:50px;height:50px;background-color:#fff;box-shadow:0 0 7px #434c5626;padding:5px;border-radius:5px;margin-top:10px;margin-right:10px;cursor:pointer;transition:all .3s}.vs-map-slot-layers__layer[data-v-aebbde6b]:hover{background-color:#eee}.vs-map-slot-layers__image[data-v-aebbde6b]{width:100%;border-radius:5px;object-fit:contain}.focused[data-v-aebbde6b]{background-color:#1989fa!important}.vs-map-portal__list{position:absolute}.vs-map-portal__legend-title{padding-bottom:5px;border-bottom:1px solid #ebebeb}.vs-map-portal__legend-button{cursor:pointer;display:flex;align-items:center;justify-content:center;flex-direction:column;height:35px;background-color:#fff;border-radius:5px;border:1px solid #dcdfe5;padding:5px}.vs-map-portal__legend-body{background-color:#fff;border-radius:5px;border:1px solid #dcdfe5;padding:5px;width:250px;max-height:250px}.vs-map-portal__legend-body__content{padding-top:10px}.vs-map-portal__legend-category{font-weight:700;margin-bottom:5px}.vs-map-portal__legend-item{margin-right:10px;display:flex;flex-shrink:0}.vs-map-portal__legend-item__color{width:16px;height:16px;border-radius:3px;margin-right:10px;display:flex;flex-shrink:0}.maplibregl-popup-content{padding:0}
@@ -1,4 +1,4 @@
1
- import { _ as l, c, i as h, t as p, h as d } from "./import-file-C8BY90-b.js";
1
+ import { _ as l, c, i as h, t as p, h as d } from "./import-file-DgBd_UN1.js";
2
2
  import { openBlock as u, createElementBlock as m } from "vue";
3
3
  const D = {
4
4
  name: "VsCalendar",
@@ -0,0 +1,148 @@
1
+ import { _ as y, c as g, a as c, P as h, b as l, i as b } from "./import-file-DgBd_UN1.js";
2
+ import { openBlock as x, createElementBlock as I } from "vue";
3
+ const v = {
4
+ name: "VsPie",
5
+ props: ["currentWidget"],
6
+ mixins: [g],
7
+ data() {
8
+ return {
9
+ chartInstance: null,
10
+ uniqueID: null,
11
+ resizeObserver: null
12
+ };
13
+ },
14
+ async mounted() {
15
+ var e;
16
+ this.uniqueID = this.widget, await this.$nextTick(), await this.getData();
17
+ const { series: t } = this.prepareData();
18
+ t && this.initChart(t);
19
+ const s = (e = this.$refs) == null ? void 0 : e.chart;
20
+ s && (this.resizeObserver = new ResizeObserver(() => {
21
+ var a;
22
+ this.chartInstance && ((a = this.chartInstance) == null || a.resize());
23
+ }), this.resizeObserver.observe(s));
24
+ },
25
+ unmounted() {
26
+ this.resizeObserver.disconnect();
27
+ },
28
+ methods: {
29
+ onChangedData() {
30
+ try {
31
+ if (this.sourceData) {
32
+ const { series: t, xs: s, ys: e } = this.prepareData();
33
+ t && (this == null || this.initChart(t, s, e));
34
+ }
35
+ } catch (t) {
36
+ console.error(t);
37
+ }
38
+ },
39
+ buildTooltipForDonut(t, s) {
40
+ const { name: e, value: a, percent: r } = t;
41
+ return `
42
+ <div style="background-color:${s[0]};font-size: 12px; font-family: Helvetica, Arial, sans-serif;color:#ffff; padding:5px; border-radius:5px; ![box-shadow:none]">
43
+ ${e}: ${c(a)} (${r}%)
44
+ </div>`;
45
+ },
46
+ prepareData() {
47
+ var t, s, e, a;
48
+ try {
49
+ const r = Array.from(
50
+ new Set(this.sourceData.map((n) => n[this.dimensions[0]]))
51
+ ), i = Array.from(
52
+ new Set(this.sourceData.map((n) => n[this.dimensions[1]]))
53
+ ), d = parseInt(
54
+ (t = this.sourceData) == null ? void 0 : t.reduce((n, o) => n += parseFloat(o == null ? void 0 : o.metric), 0)
55
+ ), u = r.map((n, o) => {
56
+ const D = (i[o] / d * 100).toFixed(2);
57
+ return {
58
+ name: `${n} (${D}%)`,
59
+ value: i[o]
60
+ };
61
+ }), p = ((s = this.styleData) == null ? void 0 : s.innerRadius) || "80%", m = ((e = this.styleData) == null ? void 0 : e.outerRadius) || "100%", f = [p, m];
62
+ return this.styleData.legend = h.getLegendOpions({
63
+ borderRadius: 10,
64
+ height: "100%",
65
+ padding: 10,
66
+ bottom: "0",
67
+ type: "scroll",
68
+ itemWidth: 14,
69
+ itemHeight: 14,
70
+ ...this.styleData.legend
71
+ }), this.styleData.label = h.getLabelOptions(
72
+ this.styleData.label
73
+ ), this.styleData.show_legend = ((a = this.styleData) == null ? void 0 : a.show_legend) || !0, { series: [
74
+ {
75
+ name: this.titleCharts ? this.titleCharts : this.dimensions[0],
76
+ type: "pie",
77
+ radius: f,
78
+ center: ["50%", "60%"],
79
+ height: "75%",
80
+ ...l(this.styleData),
81
+ data: u
82
+ }
83
+ ] };
84
+ } catch (r) {
85
+ return console.error(r), null;
86
+ }
87
+ },
88
+ async initChart(t) {
89
+ var s;
90
+ try {
91
+ const e = document.getElementById(this.uniqueID);
92
+ this.chartInstance = b(e);
93
+ const a = {
94
+ tooltip: {
95
+ trigger: "item",
96
+ formatter: (r) => this.buildTooltipForDonut(r, [r.color]),
97
+ borderWidth: 0,
98
+ appendToBody: !0,
99
+ borderColor: "transparent",
100
+ textStyle: {
101
+ color: "#000"
102
+ },
103
+ padding: [15, 15],
104
+ shadowColor: "transparent",
105
+ backgroundColor: "transparent"
106
+ },
107
+ series: t,
108
+ ...l({
109
+ ...this.styleData
110
+ }),
111
+ title: {
112
+ text: c(
113
+ parseInt(
114
+ (s = this.sourceData) == null ? void 0 : s.reduce(
115
+ (r, i) => r += parseFloat(i == null ? void 0 : i.metric),
116
+ 0
117
+ )
118
+ )
119
+ ),
120
+ left: "center",
121
+ top: "41%",
122
+ textStyle: {
123
+ color: "black",
124
+ fontWeight: 400,
125
+ fontSize: "22px"
126
+ }
127
+ }
128
+ };
129
+ this.chartInstance.setOption(a), this.$emit("update:currentWidget", this.chartInstance), this.chartInstance.resize(), window.addEventListener("resize", () => {
130
+ this.chartInstance.resize();
131
+ });
132
+ } catch (e) {
133
+ console.error(e);
134
+ }
135
+ }
136
+ }
137
+ }, w = ["id"];
138
+ function _(t, s, e, a, r, i) {
139
+ return x(), I("div", {
140
+ id: r.uniqueID,
141
+ ref: "chart",
142
+ class: "h-full min-h-[200px] flex items-center"
143
+ }, null, 8, w);
144
+ }
145
+ const O = /* @__PURE__ */ y(v, [["render", _]]);
146
+ export {
147
+ O as default
148
+ };
@@ -1,4 +1,4 @@
1
- import { _ as o, c, a as h, b as l, d as n, i as d } from "./import-file-C8BY90-b.js";
1
+ import { _ as o, c, d as h, a as l, b as n, i as d } from "./import-file-DgBd_UN1.js";
2
2
  import { openBlock as p, createElementBlock as u } from "vue";
3
3
  const m = {
4
4
  name: "VsFunnelBar",
@@ -1,4 +1,4 @@
1
- import { _ as u, c as m, a as d, i as f, t as x, e as y, g as c, d as D } from "./import-file-C8BY90-b.js";
1
+ import { _ as u, c as m, d, i as f, t as x, e as y, g as c, b as D } from "./import-file-DgBd_UN1.js";
2
2
  import { openBlock as _, createElementBlock as g } from "vue";
3
3
  const w = {
4
4
  name: "VsHeatmap",
@@ -1,5 +1,5 @@
1
- import { l as g, m as M } from "./map-component-mixin-CFtShPun.js";
2
- import { _ as w, c as y } from "./import-file-C8BY90-b.js";
1
+ import { l as g, m as M } from "./map-component-mixin-NewmNy_M.js";
2
+ import { _ as w, c as y } from "./import-file-DgBd_UN1.js";
3
3
  import { resolveComponent as i, openBlock as u, createElementBlock as _, createElementVNode as r, createBlock as V, createCommentVNode as v, createVNode as d } from "vue";
4
4
  const x = {
5
5
  mixins: [y, g, M],
@@ -1,5 +1,5 @@
1
- import { l as w, m as V, p as _ } from "./map-component-mixin-CFtShPun.js";
2
- import { _ as v, c as C } from "./import-file-C8BY90-b.js";
1
+ import { l as w, m as V, p as _ } from "./map-component-mixin-NewmNy_M.js";
2
+ import { _ as v, c as C } from "./import-file-DgBd_UN1.js";
3
3
  import { resolveComponent as a, openBlock as h, createElementBlock as $, createVNode as s, createElementVNode as u, createBlock as x, createCommentVNode as L } from "vue";
4
4
  const k = {
5
5
  mixins: [C, w, V],
@@ -1,4 +1,4 @@
1
- import { _ as c, c as o, f as n } from "./import-file-C8BY90-b.js";
1
+ import { _ as c, c as o, f as n } from "./import-file-DgBd_UN1.js";
2
2
  import { openBlock as i, createElementBlock as m, toDisplayString as s } from "vue";
3
3
  const u = {
4
4
  name: "VsNumber",
@@ -45,11 +45,11 @@ const u = {
45
45
  }
46
46
  }
47
47
  }
48
- }, h = { class: "font-[Inter,_Helvetica,_Arial] p-4 w-full text-[28px] pt-[10px] min-h-[150px] border-0" };
49
- function p(e, t, r, f, d, a) {
48
+ }, h = { class: "text-lg lg:text-xl xl:text-2xl text-gray-800 h-[32px] flex items-center" };
49
+ function x(e, t, r, f, l, a) {
50
50
  return i(), m("div", h, s(a.prefix) + s(a.formattedNumber), 1);
51
51
  }
52
- const x = /* @__PURE__ */ c(u, [["render", p]]);
52
+ const b = /* @__PURE__ */ c(u, [["render", x]]);
53
53
  export {
54
- x as default
54
+ b as default
55
55
  };
@@ -0,0 +1,68 @@
1
+ import { _ as p, c as h, d as m, a as f } from "./import-file-DgBd_UN1.js";
2
+ import { openBlock as a, createElementBlock as r, createElementVNode as s, Fragment as n, renderList as c, toDisplayString as d } from "vue";
3
+ const _ = {
4
+ name: "VsTable",
5
+ mixins: [h],
6
+ data() {
7
+ return {
8
+ values: null,
9
+ xs: null,
10
+ products: null
11
+ };
12
+ },
13
+ async mounted() {
14
+ await this.getData(), this.prepareData();
15
+ },
16
+ methods: {
17
+ onChangedData() {
18
+ try {
19
+ this.sourceData && this.prepareData();
20
+ } catch {
21
+ }
22
+ },
23
+ prepareData() {
24
+ try {
25
+ const t = Array.from(
26
+ new Set(this.sourceData.map((e) => e[this.dimensions[0]]))
27
+ );
28
+ this.dimensions[0].includes("date") ? this.xs = t.map((e) => m(e)) : this.xs = [...t], this.products = this.dimensions.filter((e, o) => o != 0), this.values = this.products.map((e, o) => ({
29
+ name: e,
30
+ data: this.sourceData.filter((l) => parseFloat(l[e])).map((l) => f(parseFloat(l[e])))
31
+ }));
32
+ } catch (t) {
33
+ console.error(t);
34
+ }
35
+ }
36
+ }
37
+ }, x = { class: "flex flex-col h-full pt-[16px] pb-[16px] space-y-4 rounded-xl custom-scrollbar" }, b = { class: "overflow-x-auto [&::-webkit-scrollbar]:h-2 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-track]:bg-gray-100 [&::-webkit-scrollbar-thumb]:bg-gray-300 custom-scrollbar" }, y = { class: "inline-block min-w-full align-middle" }, g = { class: "relative min-w-full divide-y divide-gray-200" }, v = { class: "sticky top-0 bg-white w-full after:absolute after:content-[''] after:block after:w-full after:h-px after:bg-stone-200" }, w = { class: "space-x-2" }, k = {
38
+ scope: "col",
39
+ class: "xl:min-w-[120px] min-w-48"
40
+ }, D = { class: "flex items-center px-1 py-3 font-medium text-gray-800 text-start gap-x-1 dark:text-neutral-200" }, $ = { class: "divide-y divide-gray-200" }, F = { class: "py-3 size-px whitespace-nowrap" }, T = { class: "text-sm text-gray-600" };
41
+ function B(t, e, o, l, E, N) {
42
+ return a(), r("div", x, [
43
+ s("div", b, [
44
+ s("div", y, [
45
+ s("table", g, [
46
+ s("thead", v, [
47
+ s("tr", w, [
48
+ (a(!0), r(n, null, c(t.dimensions, (i) => (a(), r("th", k, [
49
+ s("div", D, d(i), 1)
50
+ ]))), 256))
51
+ ])
52
+ ]),
53
+ (a(!0), r(n, null, c(t.sourceData, (i) => (a(), r("tbody", $, [
54
+ s("tr", null, [
55
+ (a(!0), r(n, null, c(t.dimensions, (u, S) => (a(), r("td", F, [
56
+ s("span", T, d(i == null ? void 0 : i[u]), 1)
57
+ ]))), 256))
58
+ ])
59
+ ]))), 256))
60
+ ])
61
+ ])
62
+ ])
63
+ ]);
64
+ }
65
+ const A = /* @__PURE__ */ p(_, [["render", B]]);
66
+ export {
67
+ A as default
68
+ };
@@ -1,7 +1,7 @@
1
1
  var ge = Object.defineProperty;
2
2
  var ke = (c, e, t) => e in c ? ge(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t;
3
3
  var k = (c, e, t) => ke(c, typeof e != "symbol" ? e + "" : e, t);
4
- import { _ as de, c as xe } from "./import-file-C8BY90-b.js";
4
+ import { _ as de, c as xe } from "./import-file-DgBd_UN1.js";
5
5
  import { openBlock as V, createElementBlock as J, createCommentVNode as be } from "vue";
6
6
  function Q() {
7
7
  return {
@@ -1508,7 +1508,7 @@ const Ke = {
1508
1508
  return null;
1509
1509
  }
1510
1510
  }
1511
- }, Ye = { class: "relative select-auto h-full py-4 rounded-xl p-4 box-border bg-white custom-scrollbar" }, et = ["innerHTML"];
1511
+ }, Ye = { class: "relative select-auto h-[calc(100%-40px)] py-4 rounded-xl p-4 box-border bg-white custom-scrollbar" }, et = ["innerHTML"];
1512
1512
  function tt(c, e, t, n, s, i) {
1513
1513
  return V(), J("div", Ye, [
1514
1514
  s.markedText ? (V(), J("div", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/bi",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "BI data visualization module",
5
5
  "main": "dist/bi.js",
6
6
  "browser": "dist/bi.umd.cjs",
@@ -47,11 +47,11 @@
47
47
  "dependencies": {
48
48
  "@highlightjs/vue-plugin": "github:highlightjs/vue-plugin",
49
49
  "@mapbox/sphericalmercator": "^1.2.0",
50
- "@opengis/fastify-auth": "^1.0.50",
50
+ "@opengis/fastify-auth": "^1.0.60",
51
51
  "@opengis/fastify-file": "^1.0.32",
52
- "@opengis/fastify-table": "^1.1.93",
53
- "@opengis/v3-core": "^0.3.8",
54
- "@opengis/v3-filter": "^0.0.39",
52
+ "@opengis/fastify-table": "^1.1.145",
53
+ "@opengis/v3-core": "^0.3.31",
54
+ "@opengis/v3-filter": "^0.0.62",
55
55
  "@turf/turf": "^7.1.0",
56
56
  "@vueuse/core": "^11.1.0",
57
57
  "axios": "^1.3.1",
@@ -63,6 +63,7 @@
63
63
  "highlight.js": "^11.10.0",
64
64
  "js-yaml": "^4.1.0",
65
65
  "maplibre-gl": "^4.7.1",
66
+ "markdown-it": "^14.1.0",
66
67
  "marked": "^14.1.2",
67
68
  "pinia": "^2.2.4",
68
69
  "vite": "^5.1.5",
package/plugin.js CHANGED
@@ -6,7 +6,7 @@ async function plugin(fastify, opts = config) {
6
6
  // API
7
7
  fastify.register(import('./server/routes/dashboard/index.mjs'), config);
8
8
  fastify.register(import('./server/routes/dataset/index.mjs'), config);
9
- fastify.register(import('./server/routes/db/index.mjs'), config);
9
+
10
10
  fastify.register(import('./server/routes/data/index.mjs'), config);
11
11
  fastify.register(import('./server/routes/edit/index.mjs'), config);
12
12
  }
@@ -0,0 +1,17 @@
1
+ import md from 'markdown-it';
2
+
3
+ const md1 = md({ html: true });
4
+
5
+ /**
6
+ * Перетворення з файла readme.md до формату HTML.
7
+ * Потрабно вставити в хелпер шлях до файла або текст readme.md і за допомогою бібліотеки markdown-it перетвориться в HTML.
8
+
9
+ * @returns {String} Returns HTML
10
+ */
11
+ export default function mdToHTML(data, options) {
12
+ // auto detect HTML or MD
13
+ // const result = md().render(data);
14
+ if (!data) return 'empty data';
15
+ const result = md1.render(data);
16
+ return result;
17
+ };
@@ -21,6 +21,18 @@ alter table bi.dataset add column if not exists editor_id text;
21
21
  alter table bi.dataset add column if not exists editor_date timestamp without time zone;
22
22
  alter table bi.dataset add column if not exists cdate timestamp without time zone;
23
23
  alter table bi.dataset alter column cdate set DEFAULT (now())::timestamp without time zone;
24
+ ALTER TABLE bi.dataset add column if not exists filter_list json;
25
+ ALTER TABLE bi.dataset add column if not exists dataset_file_path text;
26
+ ALTER TABLE bi.dataset add column if not exists files json;
27
+ ALTER TABLE bi.dataset add column if not exists style json;
28
+ ALTER TABLE bi.dataset add column if not exists data_source json;
29
+ ALTER TABLE bi.dataset add column if not exists setting json;
30
+ ALTER TABLE bi.dataset add column if not exists geom geometry;
31
+ ALTER TABLE bi.dataset add column if not exists pk text;
32
+ ALTER TABLE bi.dataset add column if not exists query text;
33
+ ALTER TABLE bi.dataset add column if not exists form_setting json;
34
+ ALTER TABLE bi.dataset add column if not exists access_level text;
35
+ ALTER TABLE bi.dataset add column if not exists export_columns text[];
24
36
 
25
37
  alter table bi.dataset add CONSTRAINT bi_dataset_id_pkey PRIMARY KEY (dataset_id);
26
38
 
@@ -30,3 +42,4 @@ COMMENT ON COLUMN bi.dataset.dataset_id IS 'PK';
30
42
  COMMENT ON COLUMN bi.dataset.name IS 'Назва';
31
43
  COMMENT ON COLUMN bi.dataset.file_path IS 'Шлях до імпортованого файлу';
32
44
  COMMENT ON COLUMN bi.dataset.table_name IS 'Таблиця';
45
+
@@ -17,6 +17,7 @@ alter table bi.dashboard alter column name set not null;
17
17
  alter table bi.dashboard add column if not exists panels json;
18
18
  alter table bi.dashboard add column if not exists grid json;
19
19
  alter table bi.dashboard add column if not exists filters json;
20
+ alter table bi.dashboard add column if not exists words text;
20
21
 
21
22
  alter table bi.dashboard add CONSTRAINT dashboard_id_pkey PRIMARY KEY (dashboard_id);
22
23
 
@@ -31,6 +32,7 @@ COMMENT ON COLUMN bi.dashboard.name IS 'Назва';
31
32
  COMMENT ON COLUMN bi.dashboard.panels IS 'Панелі віджетів';
32
33
  COMMENT ON COLUMN bi.dashboard.grid IS 'Сітка';
33
34
  COMMENT ON COLUMN bi.dashboard.filters IS 'Фільтри';
35
+ COMMENT ON COLUMN bi.dashboard.words IS 'Ключові слова';
34
36
 
35
37
  CREATE TABLE if not exists bi.widget ();
36
38
  alter table bi.widget drop constraint if exists widget_id_pk;
@@ -7,7 +7,6 @@ import {
7
7
  } from '@opengis/fastify-table/utils.js';
8
8
 
9
9
  export default async function dashboard({
10
- pg = pgClients.client,
11
10
  params = {},
12
11
  }) {
13
12
  const time = Date.now();
@@ -16,14 +15,14 @@ export default async function dashboard({
16
15
  if (!id) {
17
16
  return { message: 'not enough params: dashboard required', status: 400 };
18
17
  }
19
- const dashboards = await getTemplatePath('dashboard');
18
+ const dashboards = getTemplatePath('dashboard');
20
19
 
21
20
  const fileDashboard = dashboards.find((el) => el[0] === id);
22
21
  if (!fileDashboard) {
23
22
  const sql = `select title, description, table_name, panels, grid, widgets, filters, style
24
23
  from bi.dashboard where $1 in (dashboard_id, name)`;
25
24
 
26
- const data = await pg.query(sql, [id]).then((res) => res.rows?.[0] || {});
25
+ const data = await pgClients.client.query(sql, [id]).then((res) => res.rows?.[0] || {});
27
26
  data.type = 'bd';
28
27
  const { table_name: table } = data;
29
28
 
@@ -32,14 +31,14 @@ export default async function dashboard({
32
31
  }
33
32
 
34
33
  const { fields = [] } =
35
- table && pg.pk?.[table]
36
- ? await pg.query(`select * from ${table} limit 0`)
34
+ table && pgClients.client.pk?.[table]
35
+ ? await pgClients.client.query(`select * from ${table} limit 0`)
37
36
  : {};
38
37
 
39
38
  const columns = table
40
39
  ? fields.map(({ name, dataTypeID }) => ({
41
40
  name,
42
- type: pg.pgType?.[dataTypeID],
41
+ type: pgClients.client.pgType?.[dataTypeID],
43
42
  }))
44
43
  : [];
45
44
  data?.widgets?.forEach?.(el => {
@@ -50,7 +49,7 @@ export default async function dashboard({
50
49
  return {
51
50
  ...data || {},
52
51
  error:
53
- table && !pg.pk?.[table] ? `table pkey not found: ${table}` : undefined,
52
+ table && !pgClients.client.pk?.[table] ? `table pkey not found: ${table}` : undefined,
54
53
  table_name: table,
55
54
  time: Date.now() - time,
56
55
  columns,
@@ -68,10 +67,10 @@ export default async function dashboard({
68
67
  data.type = 'file';
69
68
  const { table } = data?.data || { table: data?.table_name };
70
69
 
71
- const pg1 = data.db ? await getPGAsync(data.db) : pg;
70
+ const pg = data.pg || (data.db ? await getPGAsync(data.db) : null) || pgClients.client;
72
71
 
73
72
  const { fields = [] } = table
74
- ? await pg1.query(`select * from ${table} limit 0`)
73
+ ? await pg.query(`select * from ${table} limit 0`)
75
74
  : {};
76
75
 
77
76
  const columns = fields.map(({ name, dataTypeID }) => ({
@@ -94,7 +93,7 @@ export default async function dashboard({
94
93
  const ranges = index?.filters?.filter((el) => el?.id && columns.map((el) => el?.name).includes(el?.id) && el?.type === 'Range');
95
94
  if (ranges?.length) {
96
95
  await Promise.all(ranges.map(async (el) => {
97
- const rows = await pg.query(`select array[
96
+ const rows = await pg.query(`select array[
98
97
  percentile_cont(0) within group (order by ${el.id}), percentile_cont(0.25) within group (order by ${el.id}),
99
98
  percentile_cont(0.5) within group (order by ${el.id}), percentile_cont(0.75) within group (order by ${el.id}),
100
99
  percentile_cont(1.0) within group (order by ${el.id})
@@ -118,7 +117,7 @@ export default async function dashboard({
118
117
  }
119
118
  : { name: el[0].split('.')[0], title: el[1] }
120
119
  );
121
-
120
+
122
121
  return {
123
122
  ...data,
124
123
  table_name: table,
@@ -5,16 +5,16 @@ import { pgClients, getTemplate, getTemplatePath } from '@opengis/fastify-table/
5
5
 
6
6
  const q = `select dashboard_id as name, 'db' as type, title, description, table_name from bi.dashboard`;
7
7
 
8
- export default async function data({ pg = pgClients.client }) {
8
+ export default async function data({ pg = pgClients.client, user = {} }) {
9
9
  const time = Date.now();
10
- const data = await getTemplatePath('dashboard');
10
+ const data = getTemplatePath('dashboard');
11
11
  const dir = await Promise.all(
12
- data.map(async ([filename]) => {
13
- const data = await getTemplate('dashboard', filename);
14
- const index = data.find((el) => el[0] === 'index.yml')[1];
12
+ data.map(async ([filename, filepath]) => {
13
+ const obj = await getTemplate('dashboard', filename);
14
+ const index = obj?.find((el) => el[0] === 'index.yml')?.[1];
15
15
  const { table_name, description, title } = index || {};
16
16
 
17
- return { name: filename, type: 'file', title, description, table_name };
17
+ return { name: filename, path: user?.user_type?.includes('admin') ? filepath : undefined, type: 'file', title, description, table_name };
18
18
  })
19
19
  );
20
20
 
@@ -2,7 +2,6 @@ import yaml from 'js-yaml';
2
2
 
3
3
  import {
4
4
  config,
5
- getPGAsync,
6
5
  autoIndex,
7
6
  pgClients,
8
7
  getSelectVal,
@@ -28,7 +27,7 @@ export default async function dataAPI({ query = {} }) {
28
27
 
29
28
  const { type, text, data = {}, controls, style, options } = widgetData;
30
29
 
31
- const pg = data.db ? await getPGAsync(data.db) : pgClients.client;
30
+ const pg = widgetData.pg || pgClients.client;
32
31
 
33
32
  const { fields: cols } = await pg.query(
34
33
  `select * from ${data.table} limit 0`
@@ -62,7 +61,7 @@ export default async function dataAPI({ query = {} }) {
62
61
 
63
62
  const columnList = columns.map(col => col.name);
64
63
  const groupbyColumnNotExists = groupby?.split?.(',')?.filter?.(el => !columnList.includes(el.trim()));
65
-
64
+
66
65
  if (groupby && groupbyColumnNotExists?.length) {
67
66
  return { message: `groupby column not found: ${groupbyColumnNotExists} (${data.table}/${pg.options?.database})`, status: 404 };
68
67
  }
@@ -97,6 +96,7 @@ export default async function dataAPI({ query = {} }) {
97
96
  const sql = (chartSQL[type] || chartSQL.chart)({
98
97
  where,
99
98
  metric,
99
+ columns: widgetData.columns,
100
100
  table: `(${optimizedSQL} ${samples ? 'limit 10' : ''})q`,
101
101
  x,
102
102
  groupData,
@@ -139,6 +139,12 @@ export default async function dataAPI({ query = {} }) {
139
139
  });
140
140
  }
141
141
 
142
+ const titles = Array.isArray(widgetData?.columns)
143
+ ? widgetData.columns.reduce((acc, curr) => Object.assign(acc, { [curr.name]: curr.title || curr.ua }), {})
144
+ : Object.keys(widgetData?.columns || {}).reduce((acc, curr) => Object.assign(acc, { [curr]: widgetData?.columns?.[curr] }), {});
145
+
146
+ const rows1 = type === 'table' ? rows.map(row => Object.keys(row || {}).reduce((acc, curr) => Object.assign(acc, { [titles?.[curr] || curr]: row?.[curr] }), {})) : rows;
147
+
142
148
  const yml = widgetData.yml || yaml.dump(extractYml(widgetData));
143
149
  const dimensions = fields.map((el) => el.name);
144
150
 
@@ -155,12 +161,15 @@ export default async function dataAPI({ query = {} }) {
155
161
  // data: query.format === 'data' ? dimensions.map(el => rows.map(r => r[el])) : undefined,
156
162
  source:
157
163
  query.format === 'array'
158
- ? dimensions.map((el) => rows.map((r) => r[el]))
159
- : rows,
164
+ ? dimensions.map((el) => rows1.map((r) => r[el]))
165
+ : rows1,
160
166
  style,
161
167
  options,
162
168
  controls,
163
169
  yml,
170
+ data: widgetData.data,
171
+ id: query.widget,
172
+ columnTypes,
164
173
  params: config?.local ? {
165
174
  x,
166
175
  cls,
@@ -171,7 +180,6 @@ export default async function dataAPI({ query = {} }) {
171
180
  groupby,
172
181
  sql,
173
182
  } : undefined,
174
- columnTypes,
175
183
  };
176
184
  return res;
177
185
  }
@@ -2,8 +2,11 @@ function number({ metric, where, table, samples }) {
2
2
  const sql = `select ${metric} from ${table} where ${where} ${samples ? 'limit 10' : ''}`;
3
3
  return sql;
4
4
  }
5
- function table({ columns, table, where, samples }) {
6
- return `select ${columns.map((el) => el.name || el)}::text from ${table} where ${where} ${samples ? 'limit 10' : 'limit 20'} `;
5
+ function table({ columns = [], table, where, samples }) {
6
+ const cols = Array.isArray(columns)
7
+ ? columns.map((el) => `"${(el.name || el).replace(/'/g, "''")}"`).join(',')
8
+ : Object.keys(columns).map(key => `"${key.replace(/'/g, "''")}"`).join(',');
9
+ return `select ${cols || '*'} from ${table} where ${where} ${samples ? 'limit 10' : 'limit 20'} `;
7
10
  }
8
11
 
9
12
  function chart({
@@ -39,4 +42,4 @@ function text() {
39
42
  return undefined;
40
43
  }
41
44
 
42
- export default { number, chart };
45
+ export default { number, chart, table };
@@ -17,7 +17,9 @@ const maxLimit = 100;
17
17
  * @returns {Object} rows Масив з колонками таблиці
18
18
  */
19
19
 
20
- export default async function biDatasetList({ pg = pgClients.client, query = {} }) {
20
+ const pg = pgClients.client;
21
+
22
+ export default async function biDatasetList({ query = {} }) {
21
23
 
22
24
  const limit = Math.min(maxLimit, +(query.limit || 20));
23
25
  const offset = query.page && query.page > 0 ? (query.page - 1) * limit : 0;