@opengis/bi 1.2.0 → 1.2.1

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 (73) hide show
  1. package/dist/bi.js +1 -1
  2. package/dist/bi.umd.cjs +1 -1
  3. package/dist/{import-file-Bx4xpxVb.js → import-file-D06AZEtP.js} +11 -11
  4. package/dist/{vs-funnel-bar-C_TceUrc.js → vs-funnel-bar-C8m-602x.js} +1 -1
  5. package/dist/{vs-list-DyhLUIPb.js → vs-list-BJ0NjSm5.js} +1 -1
  6. package/dist/{vs-map-BtQJNN4L.js → vs-map-PLlJqaaW.js} +2 -2
  7. package/dist/{vs-map-cluster-BbPUosvt.js → vs-map-cluster-9tV6eiDA.js} +2 -2
  8. package/dist/{vs-number-D2GkU586.js → vs-number-B2V_BPer.js} +1 -1
  9. package/dist/{vs-table-D_Yn9QqB.js → vs-table-WGE9jyDq.js} +1 -1
  10. package/dist/{vs-text-BivVd6cY.js → vs-text-DkLKRC7F.js} +1 -1
  11. package/package.json +8 -8
  12. package/plugin.js +22 -0
  13. package/server/helpers/mdToHTML.js +17 -0
  14. package/server/migrations/bi.dataset.sql +46 -0
  15. package/server/migrations/bi.sql +112 -0
  16. package/server/plugins/docs.js +48 -0
  17. package/server/plugins/hook.js +89 -0
  18. package/server/plugins/vite.js +69 -0
  19. package/server/routes/dashboard/controllers/dashboard.import.js +103 -0
  20. package/server/routes/dashboard/controllers/dashboard.js +157 -0
  21. package/server/routes/dashboard/controllers/dashboard.list.js +40 -0
  22. package/server/routes/dashboard/controllers/utils/yaml.js +11 -0
  23. package/server/routes/dashboard/index.mjs +26 -0
  24. package/server/routes/data/controllers/data.js +229 -0
  25. package/server/routes/data/controllers/util/chartSQL.js +49 -0
  26. package/server/routes/data/controllers/util/normalizeData.js +65 -0
  27. package/server/routes/data/index.mjs +32 -0
  28. package/server/routes/dataset/controllers/bi.dataset.list.js +29 -0
  29. package/server/routes/dataset/controllers/bi.db.list.js +19 -0
  30. package/server/routes/dataset/controllers/comment.js +55 -0
  31. package/server/routes/dataset/controllers/createDatasetPost.js +134 -0
  32. package/server/routes/dataset/controllers/data.js +149 -0
  33. package/server/routes/dataset/controllers/dbTablePreview.js +58 -0
  34. package/server/routes/dataset/controllers/dbTables.js +34 -0
  35. package/server/routes/dataset/controllers/delete.js +40 -0
  36. package/server/routes/dataset/controllers/deleteDataset.js +52 -0
  37. package/server/routes/dataset/controllers/editDataset.js +90 -0
  38. package/server/routes/dataset/controllers/export.js +213 -0
  39. package/server/routes/dataset/controllers/form.js +99 -0
  40. package/server/routes/dataset/controllers/format.js +46 -0
  41. package/server/routes/dataset/controllers/insert.js +47 -0
  42. package/server/routes/dataset/controllers/table.js +68 -0
  43. package/server/routes/dataset/controllers/update.js +43 -0
  44. package/server/routes/dataset/index.mjs +132 -0
  45. package/server/routes/dataset/utils/convertJSONToCSV.js +17 -0
  46. package/server/routes/dataset/utils/convertJSONToXls.js +47 -0
  47. package/server/routes/dataset/utils/createTableQuery.js +59 -0
  48. package/server/routes/dataset/utils/datasetForms.js +1 -0
  49. package/server/routes/dataset/utils/descriptionList.js +46 -0
  50. package/server/routes/dataset/utils/downloadRemoteFile.js +58 -0
  51. package/server/routes/dataset/utils/executeQuery.js +46 -0
  52. package/server/routes/dataset/utils/getLayersData.js +107 -0
  53. package/server/routes/dataset/utils/getTableData.js +47 -0
  54. package/server/routes/dataset/utils/insertDataQuery.js +12 -0
  55. package/server/routes/dataset/utils/metaFormat.js +24 -0
  56. package/server/routes/edit/controllers/dashboard.add.js +36 -0
  57. package/server/routes/edit/controllers/dashboard.delete.js +39 -0
  58. package/server/routes/edit/controllers/dashboard.edit.js +61 -0
  59. package/server/routes/edit/controllers/widget.add.js +78 -0
  60. package/server/routes/edit/controllers/widget.del.js +58 -0
  61. package/server/routes/edit/controllers/widget.edit.js +106 -0
  62. package/server/routes/edit/index.mjs +33 -0
  63. package/server/routes/map/controllers/cluster.js +125 -0
  64. package/server/routes/map/controllers/clusterVtile.js +166 -0
  65. package/server/routes/map/controllers/geojson.js +127 -0
  66. package/server/routes/map/controllers/heatmap.js +118 -0
  67. package/server/routes/map/controllers/map.js +69 -0
  68. package/server/routes/map/controllers/utils/downloadClusterData.js +45 -0
  69. package/server/routes/map/controllers/vtile.js +183 -0
  70. package/server/routes/map/index.mjs +32 -0
  71. package/server/templates/page/login.html +59 -0
  72. package/server/utils/getWidget.js +117 -0
  73. package/utils.js +12 -0
package/dist/bi.js CHANGED
@@ -1,4 +1,4 @@
1
- import { V, m as r, v as t, h as e, k as i, g as o, l as g, j as n, i as B, n as P } from "./import-file-Bx4xpxVb.js";
1
+ import { V, m as r, v as t, h as e, k as i, g as o, l as g, j as n, i as B, n as P } from "./import-file-D06AZEtP.js";
2
2
  export {
3
3
  V as VsBar,
4
4
  r as VsDashboard,
package/dist/bi.umd.cjs CHANGED
@@ -16,7 +16,7 @@
16
16
  </span>
17
17
  <span>${this.getMetricValue(w==null?void 0:w.data)}</span>
18
18
  </div>
19
- `}),y+="</div>",y}},xAxis:{data:e!=null&&e.length?e:null,type:e?"category":"value",name:((r=(s=this.styleData)==null?void 0:s.x_axis)==null?void 0:r.name)||"",axisLabel:{...Mt((i=this.styleData)==null?void 0:i.x_axis),formatter:m=>{var b,y;const u=this.formatDate(m);return((y=(b=this.styleData)==null?void 0:b.x_axis)==null?void 0:y.overflow)==="ellipsis"&&u.length>10?`${u.slice(0,10)}...`:u}}},yAxis:{data:n!=null&&n.length?n:null,type:n?"category":"value",name:((l=(a=this.styleData)==null?void 0:a.y_axis)==null?void 0:l.name)||"",axisLabel:Mt((c=this.styleData)==null?void 0:c.y_axis)},series:t!=null&&t.length?t:null,...Z(this.styleData),grid:{bottom:"0%",right:"0%",left:"0%",top:"20px",containLabel:!0,...((h=this.styleData)==null?void 0:h.grid)||{}}};await p.setOption(g),p.resize(),this.widgetInstance=p,this.$emit("update:currentWidget",p)}catch(d){console.error(d)}},async setSeriesOption(t,e){const n=t.getOption(),{series:s=[]}=n,r=s.map(i=>({...i,...e}));t.setOption({...n,series:r})},async changeOptionsByName(t,e){const n=document.getElementById(t);if(!n)return null;const s=echarts.getInstanceByDom(n);if(!s)return null;const r=s.getOption();e.seriesOptions&&this.setSeriesOption(s,e.seriesOptions),s.setOption({...r,...e.options,tooltip:{...js.getTooltipOptions(e.options.tooltip.show)}})},async changeData(t){var e;try{let n=this.dashboard?`${this.prefix||""}/bi-data?dashboard=${this.dashboard}&widget=${this.widget}`:`${this.prefix||""}/bi-data?&widget=${this.widget}`;(e=t==null?void 0:t.granularity)!=null&&e.length&&(n+=`&granularity=${t.granularity}`),t!=null&&t.metrics&&(n+=`&metrics=${t.metrics}`),this.getDataFromURL(n)}catch(n){console.error(n)}},async setFilter(t){const e=`${this.prefix||""}/bi-data?dashboard=${this.dashboardName}&widget=${this.widgetName}${t||""}`;await this.getDataFromURL(e)},async changeStyle(t,e){this.styleData[t]=e,this.onChangedData()},getMetricValue(t){var s;const e=(t==null?void 0:t.metric)||t;return parseFloat(e)?(s=z(e,{notation:"standard"}))==null?void 0:s.replaceAll(","," "):e}}},E=(t,e)=>{const n=t.__vccOpts||t;for(const[s,r]of e)n[s]=r;return n},Hs={name:"VsBar",mixins:[O],data(){return{resizeObserver:null}},computed:{uniqueID(){return this.widget}},async mounted(){var e;this.getData(),this.onChangedData();const t=(e=this.$refs)==null?void 0:e.chart;t&&(this.resizeObserver=new ResizeObserver(()=>{var n;this.widgetInstance&&((n=this.widgetInstance)==null||n.resize())}),this.resizeObserver.observe(t))},unmounted(){this.resizeObserver.disconnect()},methods:{async onChangedData(){try{if(this.sourceData){await this.$nextTick();const{series:t,xs:e,ys:n}=this.prepareData();t&&(this==null||this.initChart(t,e,n))}}catch(t){console.error(t)}},prepareData(){var t,e,n,s,r,i;try{if(!((t=this.sourceData)!=null&&t.length))return{series:[],xs:[],ys:void 0};const a=Array.from(new Set(this.sourceData.filter(g=>g[this.dimensions[0]]).map(g=>g[this.dimensions[0]])));let l;this.dimensions[0].includes("date")?l=a.map(g=>Q(g)):l=[...a];let c,h;((e=this.styleData)==null?void 0:e.horizontal)===!0?h=[...l]:c=[...l];const d=this.sourceData.filter(g=>parseFloat(g[this.dimensions[1]])&&g[this.dimensions[0]]).map(g=>parseFloat(g[this.dimensions[1]]));let p;return((n=this.styleData)==null?void 0:n.stack)!==!1?p=this.prepareStackData():((s=this.styleData)==null?void 0:s.negative_waterfall)===!0?p=this.prepareNegativeWaterfall():((r=this.styleData)==null?void 0:r.waterfall)===!0?p=this.prepareWaterfallData(d):((i=this.styleData)==null?void 0:i.accumulative)===!0?p=this.prepareAccumulative(d):p=this.dimensions.slice(1).map((m,u)=>({name:m,type:"bar",stack:`a${u}`,data:this.sourceData.filter(b=>parseFloat(b[m])&&m).map(b=>parseFloat(b[m]))})),{series:p,xs:c,ys:h}}catch(a){return console.error(a),{series:[],xs:[],ys:[]}}},prepareWaterfallData(t){let e=t.reduce((i,a)=>i+a,0);const n=[e,...t],s=n.map((i,a)=>{if(a===0)return 0;const l=e-i;return e-=i,l>=0?l:0});return[{type:"bar",stack:"Total",itemStyle:{borderColor:"transparent",color:"transparent"},data:s,tooltip:{show:!1}},{name:this.title?this.title:this.dimensions[0],type:"bar",stack:"Total",data:n}]},prepareStackData(){return this.dimensions.slice(1).map(n=>({name:n,type:"bar",stack:"a",data:this.sourceData.filter(s=>parseFloat(s[n])&&n).map(s=>parseFloat(s[n]))}))},prepareNegativeWaterfall(){const t=this.sourceData.map(i=>Number.isNaN(i[this.dimensions[1]])?0:Number(i[this.dimensions[1]])),e=this.sourceData.map(i=>Number.isNaN(i[this.dimensions[2]])?0:Number(i[this.dimensions[2]]));let n=0;const s=t.map((i,a)=>{const l=n;return n+=Number.isNaN(i)?0:i,a===0&&(n-=Number.isNaN(e[a])?0:e[a]),n-=Number.isNaN(e[a+1])?0:e[a+1],l>=0?l:0});return[{type:"bar",stack:"a",itemStyle:{borderColor:"transparent",color:"transparent"},data:s,tooltip:{show:!1}},{name:this.dimensions[1],type:"bar",stack:"a",data:t},{name:this.dimensions[2],type:"bar",stack:"a",data:e}]},prepareAccumulative(t){let e=0;const n=t.map(r=>(e+=r,e));return[{name:this.titleCharts,type:"bar",stack:"Total",data:n}]}}},Ws=["id"];function Zs(t,e,n,s,r,i){return o.openBlock(),o.createElementBlock("div",{id:i.uniqueID,ref:"chart",class:"h-full w-full min-h-[200px]"},null,8,Ws)}const Ie=E(Hs,[["render",Zs]]),Js=Object.freeze(Object.defineProperty({__proto__:null,default:Ie},Symbol.toStringTag,{value:"Module"})),Gs={name:"VsPie",props:["currentWidget"],mixins:[O],data(){return{chartInstance:null,resizeObserver:null}},computed:{uniqueID(){return this.widget}},async mounted(){var n;await this.$nextTick(),await this.getData();const{series:t}=this.prepareData()||{};t&&this.initChart(t);const e=(n=this.$refs)==null?void 0:n.chart;e&&(this.resizeObserver=new ResizeObserver(()=>{this.chartInstance&&this.chartInstance.resize()}),this.resizeObserver.observe(e))},beforeUnmount(){var t;(t=this.resizeObserver)==null||t.disconnect()},methods:{onChangedData(){try{if(this.sourceData){const{series:t,xs:e,ys:n}=this.prepareData();t&&this.initChart(t,e,n)}}catch(t){console.error(t)}},buildTooltipForDonut(t,e){const{name:n,value:s,percent:r}=t;return`
19
+ `}),y+="</div>",y}},xAxis:{data:e!=null&&e.length?e:null,type:e?"category":"value",name:((r=(s=this.styleData)==null?void 0:s.x_axis)==null?void 0:r.name)||"",axisLabel:{...Mt((i=this.styleData)==null?void 0:i.x_axis),formatter:m=>{var b,y;const u=this.formatDate(m);return((y=(b=this.styleData)==null?void 0:b.x_axis)==null?void 0:y.overflow)==="ellipsis"&&u.length>10?`${u.slice(0,10)}...`:u}}},yAxis:{data:n!=null&&n.length?n:null,type:n?"category":"value",name:((l=(a=this.styleData)==null?void 0:a.y_axis)==null?void 0:l.name)||"",axisLabel:Mt((c=this.styleData)==null?void 0:c.y_axis)},series:t!=null&&t.length?t:null,...Z(this.styleData),grid:{bottom:"0%",right:"0%",left:"0%",top:"20px",containLabel:!0,...((h=this.styleData)==null?void 0:h.grid)||{}}};await p.setOption(g),p.resize(),this.widgetInstance=p,this.$emit("update:currentWidget",p)}catch(d){console.error(d)}},async setSeriesOption(t,e){const n=t.getOption(),{series:s=[]}=n,r=s.map(i=>({...i,...e}));t.setOption({...n,series:r})},async changeOptionsByName(t,e){const n=document.getElementById(t);if(!n)return null;const s=echarts.getInstanceByDom(n);if(!s)return null;const r=s.getOption();e.seriesOptions&&this.setSeriesOption(s,e.seriesOptions),s.setOption({...r,...e.options,tooltip:{...js.getTooltipOptions(e.options.tooltip.show)}})},async changeData(t){var e;try{let n=this.dashboard?`${this.prefix||""}/bi-data?dashboard=${this.dashboard}&widget=${this.widget}`:`${this.prefix||""}/bi-data?&widget=${this.widget}`;(e=t==null?void 0:t.granularity)!=null&&e.length&&(n+=`&granularity=${t.granularity}`),t!=null&&t.metrics&&(n+=`&metrics=${t.metrics}`),this.getDataFromURL(n)}catch(n){console.error(n)}},async setFilter(t){const e=`${this.prefix||""}/bi-data?dashboard=${this.dashboardName}&widget=${this.widgetName}${t||""}`;await this.getDataFromURL(e)},async changeStyle(t,e){this.styleData[t]=e,this.onChangedData()},getMetricValue(t){var s;const e=(t==null?void 0:t.metric)||t;return parseFloat(e)?(s=z(e,{notation:"standard"}))==null?void 0:s.replaceAll(","," "):e}}},Hs={name:"VsBar",mixins:[O],data(){return{resizeObserver:null}},computed:{uniqueID(){return this.widget}},async mounted(){var e;this.getData(),this.onChangedData();const t=(e=this.$refs)==null?void 0:e.chart;t&&(this.resizeObserver=new ResizeObserver(()=>{var n;this.widgetInstance&&((n=this.widgetInstance)==null||n.resize())}),this.resizeObserver.observe(t))},unmounted(){this.resizeObserver.disconnect()},methods:{async onChangedData(){try{if(this.sourceData){await this.$nextTick();const{series:t,xs:e,ys:n}=this.prepareData();t&&(this==null||this.initChart(t,e,n))}}catch(t){console.error(t)}},prepareData(){var t,e,n,s,r,i;try{if(!((t=this.sourceData)!=null&&t.length))return{series:[],xs:[],ys:void 0};const a=Array.from(new Set(this.sourceData.filter(g=>g[this.dimensions[0]]).map(g=>g[this.dimensions[0]])));let l;this.dimensions[0].includes("date")?l=a.map(g=>Q(g)):l=[...a];let c,h;((e=this.styleData)==null?void 0:e.horizontal)===!0?h=[...l]:c=[...l];const d=this.sourceData.filter(g=>parseFloat(g[this.dimensions[1]])&&g[this.dimensions[0]]).map(g=>parseFloat(g[this.dimensions[1]]));let p;return((n=this.styleData)==null?void 0:n.stack)!==!1?p=this.prepareStackData():((s=this.styleData)==null?void 0:s.negative_waterfall)===!0?p=this.prepareNegativeWaterfall():((r=this.styleData)==null?void 0:r.waterfall)===!0?p=this.prepareWaterfallData(d):((i=this.styleData)==null?void 0:i.accumulative)===!0?p=this.prepareAccumulative(d):p=this.dimensions.slice(1).map((m,u)=>({name:m,type:"bar",stack:`a${u}`,data:this.sourceData.filter(b=>parseFloat(b[m])&&m).map(b=>parseFloat(b[m]))})),{series:p,xs:c,ys:h}}catch(a){return console.error(a),{series:[],xs:[],ys:[]}}},prepareWaterfallData(t){let e=t.reduce((i,a)=>i+a,0);const n=[e,...t],s=n.map((i,a)=>{if(a===0)return 0;const l=e-i;return e-=i,l>=0?l:0});return[{type:"bar",stack:"Total",itemStyle:{borderColor:"transparent",color:"transparent"},data:s,tooltip:{show:!1}},{name:this.title?this.title:this.dimensions[0],type:"bar",stack:"Total",data:n}]},prepareStackData(){return this.dimensions.slice(1).map(n=>({name:n,type:"bar",stack:"a",data:this.sourceData.filter(s=>parseFloat(s[n])&&n).map(s=>parseFloat(s[n]))}))},prepareNegativeWaterfall(){const t=this.sourceData.map(i=>Number.isNaN(i[this.dimensions[1]])?0:Number(i[this.dimensions[1]])),e=this.sourceData.map(i=>Number.isNaN(i[this.dimensions[2]])?0:Number(i[this.dimensions[2]]));let n=0;const s=t.map((i,a)=>{const l=n;return n+=Number.isNaN(i)?0:i,a===0&&(n-=Number.isNaN(e[a])?0:e[a]),n-=Number.isNaN(e[a+1])?0:e[a+1],l>=0?l:0});return[{type:"bar",stack:"a",itemStyle:{borderColor:"transparent",color:"transparent"},data:s,tooltip:{show:!1}},{name:this.dimensions[1],type:"bar",stack:"a",data:t},{name:this.dimensions[2],type:"bar",stack:"a",data:e}]},prepareAccumulative(t){let e=0;const n=t.map(r=>(e+=r,e));return[{name:this.titleCharts,type:"bar",stack:"Total",data:n}]}}},E=(t,e)=>{const n=t.__vccOpts||t;for(const[s,r]of e)n[s]=r;return n},Ws=["id"];function Zs(t,e,n,s,r,i){return o.openBlock(),o.createElementBlock("div",{id:i.uniqueID,ref:"chart",class:"h-full w-full min-h-[200px]"},null,8,Ws)}const Ie=E(Hs,[["render",Zs]]),Js=Object.freeze(Object.defineProperty({__proto__:null,default:Ie},Symbol.toStringTag,{value:"Module"})),Gs={name:"VsPie",props:["currentWidget"],mixins:[O],data(){return{chartInstance:null,resizeObserver:null}},computed:{uniqueID(){return this.widget}},async mounted(){var n;await this.$nextTick(),await this.getData();const{series:t}=this.prepareData()||{};t&&this.initChart(t);const e=(n=this.$refs)==null?void 0:n.chart;e&&(this.resizeObserver=new ResizeObserver(()=>{this.chartInstance&&this.chartInstance.resize()}),this.resizeObserver.observe(e))},beforeUnmount(){var t;(t=this.resizeObserver)==null||t.disconnect()},methods:{onChangedData(){try{if(this.sourceData){const{series:t,xs:e,ys:n}=this.prepareData();t&&this.initChart(t,e,n)}}catch(t){console.error(t)}},buildTooltipForDonut(t,e){const{name:n,value:s,percent:r}=t;return`
20
20
  <div style="background-color:${e[0]}; font-size:12px; font-family:Helvetica, Arial, sans-serif; color:#ffff; padding:5px; border-radius:5px;">
21
21
  ${n==null?void 0:n.replace("null","Не визначено")}: ${z(s)} (${r}%)
22
22
  </div>`},prepareData(){var t,e,n,s,r,i;try{if(this.styleData=this.styleData||{},!((t=this.sourceData)!=null&&t.length))return console.warn("No source data available"),null;const a=Array.from(new Set((this.sourceData||[]).map(u=>u[this.dimensions[0]]))),l=Array.from(new Set((this.sourceData||[]).map(u=>u[this.dimensions[1]]))),c=parseInt((this.sourceData||[]).reduce((u,b)=>u+parseFloat((b==null?void 0:b.metric)||0),0),10),h=a.map((u,b)=>{const y=(l[b]/c*100).toFixed(2);return{name:`${u} (${y}%)`,value:l[b]}}),d=((e=this.styleData)==null?void 0:e.innerRadius)||"80%",p=((n=this.styleData)==null?void 0:n.outerRadius)||"100%",g=[d,p];return this.styleData.legend=be.getLegendOpions({borderRadius:10,height:"100%",padding:10,bottom:"0",type:"scroll",itemWidth:14,itemHeight:14,formatter:u=>{var b;return(b=u==null?void 0:u.replace("null","Не визначено"))==null?void 0:b.replace("NaN","0.00")},...((s=this.styleData)==null?void 0:s.legend)||{}}),this.styleData.label=be.getLabelOptions((r=this.styleData)==null?void 0:r.label),this.styleData.show_legend=((i=this.styleData)==null?void 0:i.show_legend)??!0,{series:[{name:this.titleCharts?this.titleCharts:this.dimensions[0],type:"pie",radius:g,center:["50%","60%"],height:"75%",...Z(this.styleData),data:h}]}}catch(a){return console.error("Error in prepareData:",a),null}},async initChart(t){try{if(!t){console.warn("No series data available for chart initialization");return}const e=this.$refs.chart;if(!e){console.warn("Chart DOM element not found");return}this.chartInstance=echarts.init(e);const n=parseInt((this.sourceData||[]).reduce((r,i)=>r+parseFloat((i==null?void 0:i.metric)||0),0),10),s={tooltip:{trigger:"item",formatter:r=>this.buildTooltipForDonut(r,[r.color]),borderWidth:0,appendToBody:!0,borderColor:"transparent",textStyle:{color:"#000"},padding:[15,15],shadowColor:"transparent",backgroundColor:"transparent"},series:t,...Z(this.styleData||{}),title:{text:z(n),left:"center",top:"41%",textStyle:{color:"black",fontWeight:400,fontSize:"22px"}}};this.chartInstance.setOption(s),this.$emit("update:currentWidget",this.chartInstance),this.chartInstance.resize(),window.addEventListener("resize",()=>{var r;(r=this.chartInstance)==null||r.resize()})}catch(e){console.error("Error in initChart:",e)}}}},vs=["id"];function Ks(t,e,n,s,r,i){return o.openBlock(),o.createElementBlock("div",{id:i.uniqueID,ref:"chart",class:"h-full min-h-[200px] flex items-center"},null,8,vs)}const It=E(Gs,[["render",Ks]]),Qs=Object.freeze(Object.defineProperty({__proto__:null,default:It},Symbol.toStringTag,{value:"Module"})),Xs={name:"VsPie",props:["currentWidget"],mixins:[O],data(){return{chartInstance:null,resizeObserver:null}},computed:{uniqueID(){return this.widget}},async mounted(){var n;await this.$nextTick(),await this.getData();const{series:t}=this.prepareData()||{};t&&this.initChart(t);const e=(n=this.$refs)==null?void 0:n.chart;e&&(this.resizeObserver=new ResizeObserver(()=>{this.chartInstance&&this.chartInstance.resize()}),this.resizeObserver.observe(e))},unmounted(){var t;(t=this.resizeObserver)==null||t.disconnect()},methods:{onChangedData(){try{if(this.sourceData){const{series:t,xs:e,ys:n}=this.prepareData();t&&this.initChart(t,e,n)}}catch(t){console.error(t)}},buildTooltipForDonut(t,e){const{name:n,value:s,percent:r}=t;return`
@@ -2022,11 +2022,6 @@ const Ze = [
2022
2022
  ) : t;
2023
2023
  }
2024
2024
  }
2025
- }, R = (e, t) => {
2026
- const r = e.__vccOpts || e;
2027
- for (const [s, n] of t)
2028
- r[s] = n;
2029
- return r;
2030
2025
  }, us = {
2031
2026
  name: "VsBar",
2032
2027
  mixins: [M],
@@ -2179,6 +2174,11 @@ const Ze = [
2179
2174
  ];
2180
2175
  }
2181
2176
  }
2177
+ }, R = (e, t) => {
2178
+ const r = e.__vccOpts || e;
2179
+ for (const [s, n] of t)
2180
+ r[s] = n;
2181
+ return r;
2182
2182
  }, ds = ["id"];
2183
2183
  function fs(e, t, r, s, n, o) {
2184
2184
  return y(), _("div", {
@@ -2889,8 +2889,8 @@ const hn = /* @__PURE__ */ R(on, [["render", fn]]), pn = /* @__PURE__ */ Object.
2889
2889
  }
2890
2890
  }, yn = {
2891
2891
  "bi-bar": O(() => Promise.resolve().then(() => ps)),
2892
- "bi-number": O(() => import("./vs-number-D2GkU586.js")),
2893
- "bi-text": O(() => import("./vs-text-BivVd6cY.js")),
2892
+ "bi-number": O(() => import("./vs-number-B2V_BPer.js")),
2893
+ "bi-text": O(() => import("./vs-text-DkLKRC7F.js")),
2894
2894
  "bi-listbar": O(() => Promise.resolve().then(() => pn)),
2895
2895
  "bi-pie": O(() => Promise.resolve().then(() => vs)),
2896
2896
  "bi-donut": O(() => Promise.resolve().then(() => ys)),
@@ -2898,10 +2898,10 @@ const hn = /* @__PURE__ */ R(on, [["render", fn]]), pn = /* @__PURE__ */ Object.
2898
2898
  "bi-stat": O(() => Promise.resolve().then(() => Hs)),
2899
2899
  "bi-pivot": O(() => Promise.resolve().then(() => Po)),
2900
2900
  "bi-progress": O(() => Promise.resolve().then(() => nn)),
2901
- "bi-funnel": O(() => import("./vs-funnel-bar-C_TceUrc.js")),
2902
- "bi-map": O(() => import("./vs-map-BtQJNN4L.js")),
2903
- "bi-cluster": O(() => import("./vs-map-cluster-BbPUosvt.js")),
2904
- "bi-table": O(() => import("./vs-table-D_Yn9QqB.js"))
2901
+ "bi-funnel": O(() => import("./vs-funnel-bar-C8m-602x.js")),
2902
+ "bi-map": O(() => import("./vs-map-PLlJqaaW.js")),
2903
+ "bi-cluster": O(() => import("./vs-map-cluster-9tV6eiDA.js")),
2904
+ "bi-table": O(() => import("./vs-table-WGE9jyDq.js"))
2905
2905
  }, xn = { class: "flex items-center space-x-2" }, _n = /* @__PURE__ */ Et({
2906
2906
  __name: "vs-bi-switch",
2907
2907
  props: /* @__PURE__ */ Le({
@@ -1,4 +1,4 @@
1
- import { _ as n, c, a as h, b as l, d as o } from "./import-file-Bx4xpxVb.js";
1
+ import { _ as n, c, a as h, b as l, d as o } from "./import-file-D06AZEtP.js";
2
2
  import { openBlock as d, createElementBlock as p } from "vue";
3
3
  const u = {
4
4
  name: "VsFunnelBar",
@@ -1,5 +1,5 @@
1
1
  import { openBlock as l, createElementBlock as h, createStaticVNode as V, createElementVNode as a, withDirectives as B, toDisplayString as L, vShow as P, Fragment as z, renderList as S, normalizeClass as G, resolveComponent as j, createVNode as D } from "vue";
2
- import { _ as p } from "./import-file-Bx4xpxVb.js";
2
+ import { _ as p } from "./import-file-D06AZEtP.js";
3
3
  function N(t) {
4
4
  return [
5
5
  {
@@ -1,5 +1,5 @@
1
- import { l as E, c as L, p as $, V as T, a as B, b as H, d as O, e as F } from "./vs-list-DyhLUIPb.js";
2
- import { _ as V, c as N } from "./import-file-Bx4xpxVb.js";
1
+ import { l as E, c as L, p as $, V as T, a as B, b as H, d as O, e as F } from "./vs-list-BJ0NjSm5.js";
2
+ import { _ as V, c as N } from "./import-file-D06AZEtP.js";
3
3
  import { resolveComponent as u, openBlock as i, createElementBlock as p, Fragment as w, createElementVNode as l, createVNode as x, createBlock as C, Teleport as P, toDisplayString as f, createCommentVNode as m, renderList as S, normalizeStyle as k, normalizeClass as I } from "vue";
4
4
  const R = {
5
5
  components: { legendIcon: E, closeIcon: L },
@@ -1,5 +1,5 @@
1
- import { l as F, c as G, p as T, e as A, V as P, b as Z, d as q, a as D } from "./vs-list-DyhLUIPb.js";
2
- import { _ as x, c as K, V as W, e as j } from "./import-file-Bx4xpxVb.js";
1
+ import { l as F, c as G, p as T, e as A, V as P, b as Z, d as q, a as D } from "./vs-list-BJ0NjSm5.js";
2
+ import { _ as x, c as K, V as W, e as j } from "./import-file-D06AZEtP.js";
3
3
  import { openBlock as c, createElementBlock as p, createElementVNode as r, normalizeClass as I, Fragment as N, renderList as R, toDisplayString as O, normalizeStyle as J, createCommentVNode as S, createStaticVNode as Q, resolveComponent as g, createBlock as M, resolveDynamicComponent as U, withDirectives as k, createVNode as z, vShow as C } from "vue";
4
4
  const X = {
5
5
  components: { legendIcon: F, closeIcon: G },
@@ -1,4 +1,4 @@
1
- import { _ as c, c as o, f as n } from "./import-file-Bx4xpxVb.js";
1
+ import { _ as c, c as o, f as n } from "./import-file-D06AZEtP.js";
2
2
  import { openBlock as i, createElementBlock 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, a as _, b } from "./import-file-Bx4xpxVb.js";
1
+ import { _ as m, c as f, a as _, b } from "./import-file-D06AZEtP.js";
2
2
  import { openBlock as a, createElementBlock 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,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-Bx4xpxVb.js";
4
+ import { _ as de, c as xe } from "./import-file-D06AZEtP.js";
5
5
  import { openBlock as V, createElementBlock as J, createCommentVNode as be } from "vue";
6
6
  function Q() {
7
7
  return {
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@opengis/bi",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "BI data visualization module",
5
5
  "main": "dist/bi.js",
6
6
  "browser": "dist/bi.umd.cjs",
7
7
  "type": "module",
8
8
  "files": [
9
- "dist"
9
+ "dist",
10
+ "server",
11
+ "plugin.js",
12
+ "utils.js"
10
13
  ],
11
14
  "scripts": {
12
15
  "prepublishOnly": "npm run build",
@@ -20,7 +23,7 @@
20
23
  "test": "node --test",
21
24
  "test21": "node --test ./test/plugins/*",
22
25
  "start": "node server.js",
23
- "prod": "cross-env NODE_ENV=production npm run start",
26
+ "prod": "NODE_ENV=production npm run start",
24
27
  "docs:i": "npm install --prefix ./docs",
25
28
  "docs:dev": "npm run --prefix ./docs docs:dev",
26
29
  "docs:build": "npm run --prefix ./docs docs:build",
@@ -42,21 +45,18 @@
42
45
  "@highlightjs/vue-plugin": "github:highlightjs/vue-plugin",
43
46
  "@jspreadsheet-ce/vue": "^5.0.0",
44
47
  "@mapbox/sphericalmercator": "^1.2.0",
45
- "@opengis/fastify-auth": "1.1.1",
46
- "@opengis/fastify-table": "1.4.29",
48
+ "@opengis/fastify-table": "^2.0.33",
47
49
  "@opengis/v3-core": "^0.3.93",
48
50
  "@opengis/v3-filter": "^0.0.71",
51
+ "cross-env": "^10.1.0",
49
52
  "@turf/turf": "^7.1.0",
50
53
  "axios": "^1.3.1",
51
- "cross-env": "^7.0.3",
52
54
  "echarts": "^5.5.1",
53
55
  "highlight.js": "^11.10.0",
54
- "maplibre-gl": "^4.7.1",
55
56
  "marked": "^14.1.2",
56
57
  "vite": "^5.1.5",
57
58
  "vue": "^3.4.27",
58
59
  "vue-router": "^4.4.3",
59
- "vue3-ace-editor": "^2.2.4",
60
60
  "@eslint/eslintrc": "^3.1.0",
61
61
  "@eslint/js": "^9.12.0",
62
62
  "@types/echarts": "^4.9.22",
package/plugin.js ADDED
@@ -0,0 +1,22 @@
1
+ import fp from 'fastify-plugin';
2
+ // import path from 'node:path';
3
+ // import { fileURLToPath } from 'url';
4
+
5
+ //import { config, addTemplateDir, execMigrations } from '@opengis/fastify-table/utils.js';
6
+
7
+ //const fileName = fileURLToPath(import.meta.url);
8
+ // const dirName = path.dirname(fileName);
9
+
10
+ async function plugin(fastify, opt) {
11
+ fastify.register(import('./server/routes/dashboard/index.mjs'), opt);
12
+ fastify.register(import('./server/routes/dataset/index.mjs'), opt);
13
+
14
+ fastify.register(import('./server/routes/data/index.mjs'), opt);
15
+ fastify.register(import('./server/routes/edit/index.mjs'), opt);
16
+ fastify.register(import('./server/routes/map/index.mjs'), opt);
17
+ // config.templates?.forEach(el => addTemplateDir(el));
18
+
19
+ // const dir = path.join(dirName, 'server/migrations');
20
+ // execMigrations(dir).catch(err => console.log(err));
21
+ }
22
+ export default fp(plugin);
@@ -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
+ };
@@ -0,0 +1,46 @@
1
+ create schema if not exists bi;
2
+
3
+ CREATE TABLE if not exists bi.dataset ();
4
+ alter table bi.dataset drop constraint if exists bi_dataset_id_pkey cascade;
5
+
6
+ alter table bi.dataset add column if not exists dataset_id text;
7
+ alter table bi.dataset alter column dataset_id set not null;
8
+ alter table bi.dataset alter column dataset_id set default next_id();
9
+
10
+ alter table bi.dataset add column if not exists name text;
11
+ alter table bi.dataset add column if not exists db text;
12
+ alter table bi.dataset add column if not exists source_type text;
13
+ alter table bi.dataset add column if not exists file_path text;
14
+ alter table bi.dataset add column if not exists table_name text;
15
+
16
+ alter table bi.dataset add column if not exists sql_list json;
17
+ alter table bi.dataset add column if not exists column_list json;
18
+
19
+ alter table bi.dataset add column if not exists uid text;
20
+ alter table bi.dataset add column if not exists editor_id text;
21
+ alter table bi.dataset add column if not exists editor_date timestamp without time zone;
22
+ alter table bi.dataset add column if not exists cdate timestamp without time zone;
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[];
36
+ ALTER TABLE bi.dataset add column if not exists dashboard_list text[];
37
+
38
+ alter table bi.dataset add CONSTRAINT bi_dataset_id_pkey PRIMARY KEY (dataset_id);
39
+
40
+ COMMENT ON TABLE bi.dataset IS 'Набори даних';
41
+
42
+ COMMENT ON COLUMN bi.dataset.dataset_id IS 'PK';
43
+ COMMENT ON COLUMN bi.dataset.name IS 'Назва';
44
+ COMMENT ON COLUMN bi.dataset.file_path IS 'Шлях до імпортованого файлу';
45
+ COMMENT ON COLUMN bi.dataset.table_name IS 'Таблиця';
46
+
@@ -0,0 +1,112 @@
1
+ create schema if not exists bi;
2
+
3
+ CREATE TABLE if not exists bi.dashboard ();
4
+ alter table bi.dashboard drop constraint if exists dashboard_id_pkey cascade;
5
+
6
+ alter table bi.dashboard add column if not exists dashboard_id text;
7
+ alter table bi.dashboard alter column dashboard_id set not null;
8
+ alter table bi.dashboard alter column dashboard_id set default next_id();
9
+
10
+ alter table bi.dashboard add column if not exists title text;
11
+ alter table bi.dashboard add column if not exists description text;
12
+ alter table bi.dashboard add column if not exists widgets json;
13
+ alter table bi.dashboard add column if not exists table_name text;
14
+ alter table bi.dashboard add column if not exists style json;
15
+ alter table bi.dashboard add column if not exists name text;
16
+ alter table bi.dashboard alter column name set not null;
17
+ alter table bi.dashboard add column if not exists panels json;
18
+ alter table bi.dashboard add column if not exists grid json;
19
+ alter table bi.dashboard add column if not exists filters json;
20
+ alter table bi.dashboard add column if not exists words text;
21
+ alter table bi.dashboard add column if not exists public boolean;
22
+ alter table bi.dashboard add column if not exists db text;
23
+ alter table bi.dashboard add column if not exists uid text;
24
+ alter table bi.dashboard add column if not exists cdate timestamp without time zone;
25
+ alter table bi.dashboard add column if not exists source text;
26
+
27
+ alter table bi.dashboard add CONSTRAINT dashboard_id_pkey PRIMARY KEY (dashboard_id);
28
+
29
+ COMMENT ON TABLE bi.dashboard IS 'Дашборди';
30
+ COMMENT ON COLUMN bi.dashboard.dashboard_id IS 'PK';
31
+ COMMENT ON COLUMN bi.dashboard.title IS 'Заголовок';
32
+ COMMENT ON COLUMN bi.dashboard.description IS 'Опис';
33
+ COMMENT ON COLUMN bi.dashboard.widgets IS 'Віджети';
34
+ COMMENT ON COLUMN bi.dashboard.table_name IS 'Назва таблиці';
35
+ COMMENT ON COLUMN bi.dashboard.style IS 'Стилі';
36
+ COMMENT ON COLUMN bi.dashboard.name IS 'Назва';
37
+ COMMENT ON COLUMN bi.dashboard.panels IS 'Панелі віджетів';
38
+ COMMENT ON COLUMN bi.dashboard.grid IS 'Сітка';
39
+ COMMENT ON COLUMN bi.dashboard.filters IS 'Фільтри';
40
+ COMMENT ON COLUMN bi.dashboard.words IS 'Ключові слова';
41
+ COMMENT ON COLUMN bi.dashboard.public IS 'Публічний доступ';
42
+ COMMENT ON COLUMN bi.dashboard.db IS 'БД';
43
+ COMMENT ON COLUMN bi.dashboard.uid IS 'User ID';
44
+ COMMENT ON COLUMN bi.dashboard.cdate IS 'Creation date';
45
+ COMMENT ON COLUMN bi.dashboard.source IS 'Джерело (file)';
46
+
47
+ CREATE TABLE if not exists bi.widget ();
48
+ alter table bi.widget drop constraint if exists widget_id_pk;
49
+ alter table bi.widget drop constraint if exists widget_id_fkey;
50
+
51
+ alter table bi.widget add column if not exists widget_id text;
52
+ alter table bi.widget alter column widget_id set not null;
53
+ alter table bi.widget alter column widget_id set default next_id();
54
+ alter table bi.widget add column if not exists type text;
55
+ alter table bi.widget add column if not exists title text;
56
+ alter table bi.widget add column if not exists style json;
57
+ alter table bi.widget add column if not exists data json;
58
+ alter table bi.widget add column if not exists table_name text;
59
+ alter table bi.widget add column if not exists dashboard_id text;
60
+ alter table bi.widget add column if not exists name text;
61
+ alter table bi.widget add column if not exists x text;
62
+ alter table bi.widget add column if not exists col numeric;
63
+ alter table bi.widget add column if not exists metrics text;
64
+ alter table bi.widget add column if not exists yml text;
65
+ alter table bi.widget add column if not exists query text;
66
+ alter table bi.widget add column if not exists cls text;
67
+
68
+ alter table bi.widget add CONSTRAINT widget_id_pk PRIMARY KEY (widget_id);
69
+ alter table bi.widget add CONSTRAINT widget_id_fkey FOREIGN KEY (dashboard_id) REFERENCES bi.dashboard (dashboard_id);
70
+
71
+ COMMENT ON TABLE bi.widget IS 'Віджети';
72
+ COMMENT ON COLUMN bi.widget.widget_id IS 'PK';
73
+ COMMENT ON COLUMN bi.widget.type IS 'Тип';
74
+ COMMENT ON COLUMN bi.widget.title IS 'Назва';
75
+ COMMENT ON COLUMN bi.widget.style IS 'Стилі';
76
+ COMMENT ON COLUMN bi.widget.yml IS 'Yml';
77
+ COMMENT ON COLUMN bi.widget.query IS 'Запит до таблиці';
78
+ COMMENT ON COLUMN bi.widget.x IS 'Колонка для осі метрик';
79
+ COMMENT ON COLUMN bi.widget.cls IS 'Класифікатор метрик';
80
+ COMMENT ON COLUMN bi.widget.yml IS 'Yml';
81
+ COMMENT ON COLUMN bi.widget.data IS 'Дані';
82
+ COMMENT ON COLUMN bi.widget.table_name IS 'Назва таблиці';
83
+ COMMENT ON COLUMN bi.widget.dashboard_id IS 'Ідентифікатор дашборду';
84
+
85
+ create table if not exists bi.cluster();
86
+ alter table bi.cluster drop constraint if exists bi_cluster_cluster_id_pkey;
87
+ alter table bi.cluster drop constraint if exists bi_cluster_title_type_unique;
88
+
89
+ alter table bi.cluster add column if not exists cluster_id text;
90
+ alter table bi.cluster alter column cluster_id set not null;
91
+ alter table bi.cluster alter column cluster_id set default next_id();
92
+
93
+ alter table bi.cluster alter column cluster_id set default next_id();
94
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS title text;
95
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS type text;
96
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS codifier text;
97
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS geom geometry(MultiPolygon,4326);
98
+
99
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS uid text;
100
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS files json;
101
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS cdate timestamp without time zone;
102
+ alter table bi.cluster alter column cdate set DEFAULT (now())::timestamp without time zone;
103
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS editor_id text;
104
+ ALTER TABLE bi.cluster ADD COLUMN IF NOT EXISTS editor_date timestamp without time zone;
105
+
106
+ ALTER TABLE bi.cluster ADD CONSTRAINT bi_cluster_cluster_id_pkey PRIMARY KEY (cluster_id);
107
+ ALTER TABLE bi.cluster ADD CONSTRAINT bi_cluster_title_type_unique UNIQUE(title, type);
108
+
109
+ comment on table bi.cluster is 'Дані для побудови cluster віджетів';
110
+
111
+ comment on column bi.cluster.title is 'Назва';
112
+ comment on column bi.cluster.type is 'Тип кластеру';
@@ -0,0 +1,48 @@
1
+ import path, { dirname } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import fs from 'fs';
4
+
5
+ const dir = dirname(fileURLToPath(import.meta.url));
6
+ const root = `${dir}/../../`;
7
+
8
+ async function plugin(fastify, opts) {
9
+ fastify.get('/docs*', async (req, reply) => {
10
+ if (!fs.existsSync(path.join(root, 'docs/.vitepress/dist/'))) {
11
+ return reply.status(404).send('docs not exists');
12
+ }
13
+
14
+ const { params } = req;
15
+ const url = params['*'];
16
+
17
+ const filePath =
18
+ url && url[url.length - 1] !== '/'
19
+ ? path.join(root, 'docs/.vitepress/dist/', url)
20
+ : path.join(root, 'docs/.vitepress/dist/', url, 'index.html');
21
+
22
+ if (!fs.existsSync(filePath)) {
23
+ return reply.status(404).send('File not found');
24
+ }
25
+
26
+ const ext = path.extname(filePath);
27
+ const mime = {
28
+ '.js': 'text/javascript',
29
+ '.css': 'text/css',
30
+ '.woff2': 'application/font-woff',
31
+ '.png': 'image/png',
32
+ '.svg': 'image/svg+xml',
33
+ '.jpg': 'image/jpg',
34
+ '.html': 'text/html',
35
+ '.json': 'application/json',
36
+ '.pdf': 'application/pdf',
37
+ }[ext];
38
+
39
+ const stream = fs.createReadStream(filePath);
40
+ stream.on('error', (err) => {
41
+ reply.status(500).send('Error reading file');
42
+ });
43
+
44
+ return mime ? reply.type(mime).send(stream) : reply.send(stream);
45
+ });
46
+ }
47
+
48
+ export default plugin;
@@ -0,0 +1,89 @@
1
+ import fp from 'fastify-plugin';
2
+ import fs from 'fs';
3
+
4
+ // the use of fastify-plugin is required to be able
5
+ // to export the decorators to the outer scope
6
+
7
+ async function plugin(fastify) {
8
+ // preSerialization
9
+ fastify.addHook('preSerialization', async (req, reply, payload) => {
10
+ if (!req.session?.passport?.user?.uid) {
11
+ // return reply.redirect('/login');
12
+ }
13
+ if (req.url.includes('/suggest/') && !req.query.json) {
14
+ return payload?.data;
15
+ }
16
+ if (payload.redirect) {
17
+ return reply.redirect(payload.redirect);
18
+ }
19
+ if (reply.sent) {
20
+ return null;
21
+ }
22
+
23
+ if ([200, 400, 403, 409, 404, 500].includes(payload.status)) {
24
+ reply.status(payload.status);
25
+ }
26
+ /* if (payload.headers) {
27
+ reply.headers(payload.headers);
28
+ } */
29
+ if (payload.buffer) {
30
+ return payload.buffer;
31
+ }
32
+ if (payload.file) {
33
+ // const buffer = await readFile(payload.file);
34
+ // return reply.send(buffer);
35
+ const stream = fs.createReadStream(payload.file);
36
+ return stream;
37
+ // return reply.send(stream);
38
+ }
39
+
40
+ if (payload.message) {
41
+ return payload.message;
42
+ }
43
+ return payload;
44
+ });
45
+
46
+ // preValidation
47
+ fastify.addHook('preValidation', async (req) => {
48
+ const parseRawBody =
49
+ ['POST', 'PUT'].includes(req.method) &&
50
+ req.body &&
51
+ typeof req.body === 'string' &&
52
+ req.body.trim(/\r\n/g).startsWith('{') &&
53
+ req.body.trim(/\r\n/g).endsWith('}');
54
+ if (parseRawBody) {
55
+ try {
56
+ req.body = JSON.parse(req.body || '{}');
57
+ } catch (err) {
58
+ // throw new Error('invalid body');
59
+ // return { error: 'invalid body', status: 400 };
60
+ }
61
+ }
62
+ });
63
+
64
+ // allow upload file
65
+ const kIsMultipart = Symbol.for('[FastifyMultipart.isMultipart]');
66
+ fastify.addContentTypeParser('multipart', (request, _, done) => {
67
+ request[kIsMultipart] = true;
68
+ done(null);
69
+ });
70
+
71
+ // parse Body
72
+ function contentParser(req, body, done) {
73
+ const parseBody = decodeURIComponent(body.toString())
74
+ .split('&')
75
+ .reduce((acc, el) => {
76
+ const [key, val] = el.split('=');
77
+ return { ...acc, [key]: val };
78
+ }, {});
79
+ done(null, parseBody);
80
+ }
81
+
82
+ fastify.addContentTypeParser(
83
+ 'application/x-www-form-urlencoded',
84
+ { parseAs: 'buffer' },
85
+ contentParser
86
+ );
87
+ }
88
+
89
+ export default fp(plugin);
@@ -0,0 +1,69 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import config from '../../config.js';
4
+
5
+ const { disableAuth } = config;
6
+ const isProduction = process.env.NODE_ENV === 'production';
7
+
8
+ async function plugin(fastify) {
9
+ // vite server
10
+ if (!isProduction) {
11
+ const vite = await import('vite');
12
+
13
+ const viteServer = await vite.createServer({
14
+ server: {
15
+ middlewareMode: true,
16
+ },
17
+ });
18
+ // hot reload
19
+ viteServer.watcher.on('all', (d, t) => {
20
+ if (!t.includes('module') && !t.includes('templates')) return;
21
+ // console.log(d, t);
22
+ viteServer.ws.send({ type: 'full-reload' });
23
+ });
24
+
25
+ // this is middleware for vite's dev servert
26
+ fastify.addHook('onRequest', async (req, reply) => {
27
+ // const { user } = req.session?.passport || {};
28
+ const next = () => new Promise((resolve) => {
29
+ viteServer.middlewares(req.raw, reply.raw, () => resolve());
30
+ });
31
+ await next();
32
+ });
33
+ fastify.get('*', async () => {});
34
+ return;
35
+ }
36
+
37
+ // From Build
38
+ fastify.get('*', async (req, reply) => {
39
+ // console.log(disableAuth)
40
+ if (!req.user && !disableAuth) return reply.redirect('/login');
41
+ const stream = fs.createReadStream('dist/index.html');
42
+ return reply
43
+ .headers({ 'Cache-Control': 'public, no-cache' })
44
+ .type('text/html')
45
+ .send(stream);
46
+ });
47
+ fastify.get('/assets/:file', async (req, reply) => {
48
+ const stream = fs.createReadStream(`dist/assets/${req.params.file}`);
49
+ const ext = path.extname(req.params.file);
50
+ const mime = {
51
+ '.js': 'text/javascript',
52
+ '.css': 'text/css',
53
+ '.woff2': 'application/font-woff',
54
+ '.png': 'image/png',
55
+ }[ext];
56
+ // reply.cacheControl('max-age', '1d');
57
+ return mime
58
+ ? reply
59
+ .headers({
60
+ 'Cache-Control': 'public, max-age=3600',
61
+ 'Content-Encoding': 'identity',
62
+ })
63
+ .type(mime)
64
+ .send(stream)
65
+ : stream;
66
+ });
67
+ }
68
+
69
+ export default plugin;