├── tools ├── index.ts ├── workspace-plugin │ ├── src │ │ ├── executors │ │ │ └── is-published │ │ │ │ ├── schema.d.ts │ │ │ │ └── schema.json │ │ └── generators │ │ │ └── viz-component │ │ │ ├── files │ │ │ ├── type.ts__tmpl__ │ │ │ ├── viz-__dashedName__.tsx__tmpl__ │ │ │ └── translation.ts__tmpl__ │ │ │ └── schema.json │ ├── package.json │ ├── executors.json │ ├── generators.json │ ├── tsconfig.lib.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── jest.config.ts │ └── .eslintrc.json ├── tsconfig.plugin.json └── tsconfig.tools.json ├── .dockerignore ├── .eslintignore ├── dashboard ├── src │ ├── shared │ ├── model │ │ ├── utils │ │ │ └── index.ts │ │ ├── meta-model │ │ │ ├── context │ │ │ │ └── index.ts │ │ │ ├── dashboard │ │ │ │ ├── index.ts │ │ │ │ └── content │ │ │ │ │ ├── mock-context │ │ │ │ │ └── index.ts │ │ │ │ │ ├── sql-snippet │ │ │ │ │ └── index.ts │ │ │ │ │ ├── layout │ │ │ │ │ └── index.ts │ │ │ │ │ ├── view │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── widgets │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── types.ts │ │ │ │ │ ├── filter │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── widgets │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── types.ts │ │ │ │ │ ├── query │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ │ ├── panel │ │ │ │ │ ├── index.ts │ │ │ │ │ └── style │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ ├── datasources │ │ │ │ ├── index.ts │ │ │ │ └── datasource.ts │ │ │ ├── global-sql-snippets │ │ │ │ ├── index.ts │ │ │ │ └── global-sql-snippet.ts │ │ │ └── index.ts │ │ ├── render-model │ │ │ ├── index.ts │ │ │ └── dashboard │ │ │ │ ├── index.ts │ │ │ │ └── content │ │ │ │ ├── layouts │ │ │ │ └── index.ts │ │ │ │ ├── filters │ │ │ │ ├── types.ts │ │ │ │ └── index.ts │ │ │ │ ├── views │ │ │ │ └── index.ts │ │ │ │ ├── panels │ │ │ │ └── index.ts │ │ │ │ ├── queries │ │ │ │ └── index.ts │ │ │ │ ├── sql-snippets │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ │ └── index.ts │ │ └── index.ts │ ├── vite-env.d.ts │ ├── types │ │ ├── filter.ts │ │ ├── index.ts │ │ └── utils.ts │ ├── dashboard-editor │ │ ├── model │ │ │ ├── layouts │ │ │ │ └── index.ts │ │ │ ├── datasources │ │ │ │ ├── db-info │ │ │ │ │ └── index.ts │ │ │ │ ├── mm-info │ │ │ │ │ └── index.ts │ │ │ │ └── datasource.ts │ │ │ ├── panels │ │ │ │ └── index.ts │ │ │ ├── queries │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ └── ui │ │ │ ├── settings │ │ │ ├── content │ │ │ │ ├── edit-panel │ │ │ │ │ └── variable-config │ │ │ │ │ │ └── index.ts │ │ │ │ ├── edit-query │ │ │ │ │ └── merico-metric-query-editor-form │ │ │ │ │ │ ├── query-tabs │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── edit-metric-query │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── dimension-selector │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── dimension-icon │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ └── table-styles.ts │ │ │ │ │ │ ├── preview-data │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── preview-query-and-vars │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── merico-icons │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── view-query-vars │ │ │ │ │ └── index.tsx │ │ │ │ ├── db-explorer-modal │ │ │ │ │ └── db-explorer │ │ │ │ │ │ ├── full-space-loading.tsx │ │ │ │ │ │ └── structure │ │ │ │ │ │ └── tooltip-value.tsx │ │ │ │ └── edit-view │ │ │ │ │ └── edit-view-form │ │ │ │ │ └── config-fields │ │ │ │ │ ├── modal │ │ │ │ │ └── modal-title-editor │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── index.tsx │ │ │ └── navbar │ │ │ │ └── nav-links.module.css │ │ │ ├── header │ │ │ ├── spotlight │ │ │ │ └── index.ts │ │ │ └── index.tsx │ │ │ └── index.ts │ ├── interactions │ │ ├── trigger │ │ │ └── index.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-current-interaction-manager.ts │ │ │ └── use-watch-triggers.ts │ │ ├── operation │ │ │ └── index.ts │ │ ├── components │ │ │ └── index.ts │ │ ├── index.ts │ │ └── interactions-viewer │ │ │ ├── node-with-interactions │ │ │ ├── index.css │ │ │ └── types.ts │ │ │ └── data │ │ │ └── types.ts │ ├── utils │ │ ├── rich-text │ │ │ └── index.ts │ │ ├── template │ │ │ ├── editor │ │ │ │ ├── index.ts │ │ │ │ ├── utils.ts │ │ │ │ └── template-input.tsx │ │ │ ├── render │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── usage.ts │ │ ├── mantine.ts │ │ ├── shallow-to-js.ts │ │ ├── color-feed.ts │ │ ├── color-mapping.ts │ │ ├── diff-json.ts │ │ ├── index.ts │ │ └── dashboard-state.ts │ ├── components │ │ ├── filter │ │ │ ├── filter-select │ │ │ │ └── editor │ │ │ │ │ └── index.ts │ │ │ ├── filter-merico-date-range │ │ │ │ └── widget │ │ │ │ │ └── calendar │ │ │ │ │ └── index.ts │ │ │ ├── filter-tree │ │ │ │ ├── filter-tree-select │ │ │ │ │ ├── editor │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── render │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── filter-tree-single-select │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── editor │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── render │ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── common │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── query-data-to-tree.ts │ │ │ ├── filter-settings │ │ │ │ ├── types.ts │ │ │ │ └── filter-settings.css │ │ │ ├── use-update-filter-preview-values.ts │ │ │ ├── error-message-or-not-found.tsx │ │ │ └── filter-date-range │ │ │ │ └── widget │ │ │ │ └── hints.tsx │ │ ├── plugins │ │ │ ├── common-echarts-fields │ │ │ │ ├── tooltip-metric │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── stats-around-viz │ │ │ │ │ └── index.ts │ │ │ │ ├── axis-label-rotate │ │ │ │ │ └── index.ts │ │ │ │ ├── regression-line │ │ │ │ │ └── index.ts │ │ │ │ ├── x-axis-position │ │ │ │ │ ├── types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── y-axis-position │ │ │ │ │ ├── types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── line-type │ │ │ │ │ ├── types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── orientation │ │ │ │ │ ├── types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── name-text-align │ │ │ │ │ ├── types.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── series-unit │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── symbol-size │ │ │ │ │ └── index.ts │ │ │ │ ├── line-area-style │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── series-order │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── label-position │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── visual-map │ │ │ │ │ ├── index.ts │ │ │ │ │ └── visual-map-editor │ │ │ │ │ │ └── types.ts │ │ │ │ ├── number-or-dynamic-value │ │ │ │ │ └── index.ts │ │ │ │ ├── axis-label-overflow │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ └── x-axis-label-formatter │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ ├── viz-components │ │ │ │ ├── merico-stats │ │ │ │ │ ├── migrators │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── v2.ts │ │ │ │ │ └── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ ├── stats │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── type.ts │ │ │ │ │ └── translation.ts │ │ │ │ ├── pie-chart │ │ │ │ │ ├── editors │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── pie-color-map-editor │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── palette.ts │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── option │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── button │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── translation.ts │ │ │ │ ├── rich-text │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── cartesian │ │ │ │ │ ├── option │ │ │ │ │ │ ├── series │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── variables.ts │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── editors │ │ │ │ │ │ ├── echarts-zooming-field │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ └── tooltip │ │ │ │ │ │ └── index.tsx │ │ │ │ ├── heatmap │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── option │ │ │ │ │ │ ├── grid.ts │ │ │ │ │ │ └── series.ts │ │ │ │ │ └── editors │ │ │ │ │ │ └── tooltip │ │ │ │ │ │ └── index.tsx │ │ │ │ ├── merico-linear-gauge │ │ │ │ │ ├── render │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── editor │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── sections-editor │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── palette.ts │ │ │ │ ├── merico-panel-groups │ │ │ │ │ ├── render │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── editor │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── type.ts │ │ │ │ ├── table │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── boxplot-chart │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── option │ │ │ │ │ │ ├── series │ │ │ │ │ │ │ └── custom │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── type.ts │ │ │ │ │ │ ├── common.ts │ │ │ │ │ │ └── grid.ts │ │ │ │ │ └── editors │ │ │ │ │ │ └── tooltip │ │ │ │ │ │ └── index.tsx │ │ │ │ ├── merico-heatmap │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── render │ │ │ │ │ │ └── option │ │ │ │ │ │ │ ├── grid.ts │ │ │ │ │ │ │ └── series.ts │ │ │ │ │ └── editors │ │ │ │ │ │ └── tooltip │ │ │ │ │ │ └── index.tsx │ │ │ │ ├── pareto-chart │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── option │ │ │ │ │ │ └── types.ts │ │ │ │ ├── horizontal-bar-chart │ │ │ │ │ ├── option │ │ │ │ │ │ ├── series │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── variables.ts │ │ │ │ │ └── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ ├── calendar-heatmap │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── option │ │ │ │ │ │ └── legend.ts │ │ │ │ │ └── editors │ │ │ │ │ │ └── tooltip │ │ │ │ │ │ └── index.tsx │ │ │ │ ├── regression-chart │ │ │ │ │ └── render │ │ │ │ │ │ ├── toolbox │ │ │ │ │ │ ├── choose-data-keys │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── data-key-selector │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── use-data-key.ts │ │ │ │ ├── scatter-chart │ │ │ │ │ ├── triggers │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── option │ │ │ │ │ │ ├── legend.ts │ │ │ │ │ │ ├── dataset.ts │ │ │ │ │ │ └── grid.ts │ │ │ │ ├── viz-dashboard-state │ │ │ │ │ ├── render │ │ │ │ │ │ └── item │ │ │ │ │ │ │ ├── selection-table.module.css │ │ │ │ │ │ │ └── context-state.tsx │ │ │ │ │ └── type.ts │ │ │ │ ├── merico-estimation-chart │ │ │ │ │ ├── option │ │ │ │ │ │ └── series │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── toolbox │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── translation.ts │ │ │ │ ├── viz-merico-gqm │ │ │ │ │ ├── type.ts │ │ │ │ │ └── translation.ts │ │ │ │ ├── radar-chart │ │ │ │ │ └── option │ │ │ │ │ │ ├── formatter.ts │ │ │ │ │ │ └── series.label.ts │ │ │ │ ├── bar-3d-chart │ │ │ │ │ └── translation.ts │ │ │ │ ├── funnel │ │ │ │ │ └── option │ │ │ │ │ │ └── index.ts │ │ │ │ ├── sunburst │ │ │ │ │ └── option │ │ │ │ │ │ └── types.ts │ │ │ │ └── text │ │ │ │ │ ├── translation.ts │ │ │ │ │ └── type.ts │ │ │ ├── editor-components │ │ │ │ ├── field-array-tabs │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── color-type │ │ │ │ │ ├── type.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── flex │ │ │ │ │ ├── index.ts │ │ │ │ │ └── type.ts │ │ │ │ └── index.ts │ │ │ ├── color-manager │ │ │ │ ├── index.ts │ │ │ │ ├── type.ts │ │ │ │ └── color-manager.ts │ │ │ ├── plugin-data-migrator │ │ │ │ └── index.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── use-tab-state.ts │ │ │ │ ├── use-row-data-map.ts │ │ │ │ ├── use-channel-event.ts │ │ │ │ └── use-current-viz-instance.ts │ │ │ ├── panel-addon │ │ │ │ └── index.ts │ │ │ ├── viz-manager │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── colors │ │ │ │ ├── sequential-color.ts │ │ │ │ └── diverging-color.ts │ │ │ ├── message-channels.spec.ts │ │ │ ├── index.ts │ │ │ ├── message-channels.ts │ │ │ └── test-utils.tsx │ │ ├── view │ │ │ ├── index.ts │ │ │ ├── view-component │ │ │ │ └── utils │ │ │ │ │ └── index.ts │ │ │ └── layout │ │ │ │ ├── index.ts │ │ │ │ └── index.css │ │ ├── panel │ │ │ ├── index.tsx │ │ │ ├── panel-editor │ │ │ │ └── dropdown-menu-items │ │ │ │ │ ├── index.ts │ │ │ │ │ └── dropdown-menu-items.tsx │ │ │ ├── settings │ │ │ │ └── common │ │ │ │ │ └── variable-selector │ │ │ │ │ └── index.ts │ │ │ ├── panel-render │ │ │ │ ├── full-screen-render │ │ │ │ │ └── index.ts │ │ │ │ ├── viz │ │ │ │ │ ├── viz.css │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── dropdown-menu-items │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── refresh.tsx │ │ │ │ │ ├── download-data.tsx │ │ │ │ │ ├── download-schema.tsx │ │ │ │ │ └── dropdown-menu-items.tsx │ │ │ ├── utils.ts │ │ │ └── index.css │ │ └── widgets │ │ │ ├── rich-text-editor │ │ │ ├── color-picker-control │ │ │ │ └── index.ts │ │ │ ├── line-height-mark │ │ │ │ └── index.ts │ │ │ ├── color-mapping-mark │ │ │ │ └── index.ts │ │ │ ├── dynamic-color-mark │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ │ ├── function-editor │ │ │ ├── index.ts │ │ │ └── types.ts │ │ │ ├── color-picker-popover │ │ │ └── index.ts │ │ │ └── index.ts │ ├── i18n │ │ ├── index.ts │ │ └── i18next-context.tsx │ ├── dashboard-render │ │ ├── index.ts │ │ └── model │ │ │ └── index.ts │ ├── test │ │ ├── setup.ts │ │ └── test-utils.ts │ ├── emotion.d.ts │ ├── styles │ │ ├── default-echarts-options │ │ │ ├── index.ts │ │ │ ├── tooltip.ts │ │ │ ├── y-axis.ts │ │ │ └── x-axis.ts │ │ └── action-icon-group-style.ts │ ├── global.d.ts │ └── contexts │ │ ├── render-content-model-context.ts │ │ ├── customize-screenshot-context.ts │ │ ├── index.ts │ │ ├── dashboard-action-context.ts │ │ ├── dashboard-theme-context.ts │ │ ├── layout-state-context.ts │ │ ├── additional-panel-menu-items.ts │ │ └── dates-provider.tsx ├── tsconfig.test.json ├── cypress │ ├── fixtures │ │ └── example.json │ └── support │ │ └── component-index.html ├── tsconfig.node.json ├── tsconfig.cypress.json ├── .gitignore └── index.html ├── website ├── src │ ├── frames │ │ ├── admin │ │ │ ├── index.css │ │ │ └── navbar │ │ │ │ └── index.tsx │ │ ├── app │ │ │ ├── index.css │ │ │ └── navbar-toggler.tsx │ │ ├── socket-client-frame │ │ │ ├── types.ts │ │ │ └── socket-context.ts │ │ └── dashboard-editor-frame │ │ │ └── index.tsx │ ├── contexts │ │ └── index.ts │ ├── global.d.ts │ ├── api-caller │ │ ├── status.typs.ts │ │ ├── types.ts │ │ ├── custom-function.types.ts │ │ ├── dashboard.typed.ts │ │ ├── dashboard.transform.ts │ │ ├── status.ts │ │ ├── custom-function.ts │ │ ├── dashboard-content-changelog.types.ts │ │ └── api-key.ts │ ├── components │ │ ├── readonly-monaco-editor │ │ │ └── index.css │ │ ├── account-type-icon.tsx │ │ ├── load-favicon.tsx │ │ └── logo │ │ │ └── index.tsx │ ├── types │ │ └── dayjs-locale.d.ts │ ├── pages │ │ ├── dashboard-editor-page │ │ │ ├── content-rebase-warning │ │ │ │ └── rebase-editor │ │ │ │ │ └── index.ts │ │ │ ├── index.css │ │ │ └── more-dashboard-info │ │ │ │ ├── types.ts │ │ │ │ ├── whos-editing │ │ │ │ └── types.ts │ │ │ │ ├── dashboard-changlog-modal │ │ │ │ └── changelog-modal-trigger.tsx │ │ │ │ ├── use-modal-states.ts │ │ │ │ └── dashboard-header-menu-items.tsx │ │ ├── dashboard-render-page │ │ │ ├── content.css │ │ │ ├── placeholder.tsx │ │ │ └── index.tsx │ │ ├── status-page │ │ │ └── index.tsx │ │ ├── account-page │ │ │ └── index.tsx │ │ ├── api-key-page │ │ │ └── index.tsx │ │ ├── data-source-page │ │ │ └── index.tsx │ │ └── sql-snippet-page │ │ │ └── index.tsx │ ├── emotion.d.ts │ ├── utils │ │ ├── dashboard-json-type-def.ts │ │ └── configure-monaco-editor │ │ │ └── index.ts │ ├── vite-env.d.ts │ └── index.css ├── .env.sample ├── README.md ├── tsconfig.node.json ├── cypress │ ├── fixtures │ │ └── example.json │ └── support │ │ └── component-index.html ├── tsconfig.cypress.json ├── .gitignore ├── index.html └── cypress.config.ts ├── settings-form ├── README.md ├── src │ ├── shared │ ├── i18n │ │ ├── index.ts │ │ ├── i18next-context.tsx │ │ └── i18n.ts │ ├── vite-env.d.ts │ ├── api-caller │ │ ├── types.ts │ │ ├── role.typed.ts │ │ ├── api-key.typed.ts │ │ ├── role.ts │ │ ├── index.ts │ │ └── account.typed.ts │ ├── api-key │ │ ├── index.tsx │ │ └── styles.ts │ ├── components │ │ ├── index.ts │ │ └── submit-form-button.tsx │ ├── datasource │ │ ├── index.tsx │ │ ├── edit-data-source │ │ │ └── types.ts │ │ ├── add-data-source │ │ │ └── types.ts │ │ └── styles.ts │ ├── sql_snippet │ │ ├── index.tsx │ │ └── styles.ts │ ├── account │ │ ├── index.tsx │ │ └── styles.ts │ ├── emotion.d.ts │ ├── global.d.ts │ └── utils │ │ └── load-monaco-editor.ts ├── tsconfig.node.json ├── .gitignore ├── index.html ├── project.json └── tsconfig.json ├── shared ├── src │ ├── index.ts │ └── api-client │ │ └── index.ts ├── README.md ├── tsconfig.lib.json ├── project.json ├── .eslintrc.json └── tsconfig.json ├── api ├── test-teardown-globals.js ├── src │ ├── cli │ │ └── clearCache.ts │ ├── preset │ │ ├── sql_snippets │ │ │ ├── config.example.json │ │ │ └── README.md │ │ ├── custom_functions │ │ │ ├── README.md │ │ │ └── config.example.js │ │ └── data_sources │ │ │ └── README.md │ ├── dashboard_migration │ │ └── handlers │ │ │ ├── 2.0.0.ts │ │ │ ├── 2.1.0.ts │ │ │ ├── 4.5.1.ts │ │ │ ├── 4.5.0.ts │ │ │ ├── 4.5.2.ts │ │ │ ├── 4.5.3.ts │ │ │ ├── 6.7.0.ts │ │ │ ├── 5.9.1.ts │ │ │ ├── 4.10.0.ts │ │ │ ├── 5.9.2.ts │ │ │ ├── 11.0.0.ts │ │ │ ├── 4.14.1.ts │ │ │ └── 9.11.0.ts │ ├── api_models │ │ └── cache.ts │ ├── models │ │ ├── dashboard_changelog.ts │ │ ├── dashboard_content_changelog.ts │ │ ├── role.ts │ │ ├── sql_snippet.ts │ │ ├── custom_function.ts │ │ ├── base.ts │ │ ├── job.ts │ │ ├── dashboard_content.ts │ │ ├── config.ts │ │ └── dashboard_permission.ts │ ├── plugins │ │ └── index.js │ ├── data_sources │ │ ├── migrations │ │ │ ├── 1660005273691-add-extension-citext.ts │ │ │ └── 1675750180197-add-group-column-to-dashboard-table.ts │ │ └── dashboard.ts │ ├── middleware │ │ ├── ensureAuthEnabled.ts │ │ ├── localization.ts │ │ └── permission.ts │ └── utils │ │ ├── logger.ts │ │ └── constants.ts ├── tests │ ├── e2e │ │ ├── constants.ts │ │ ├── tsconfig.json │ │ ├── jest.mock.ts │ │ └── 00_init_db.test.ts │ ├── unit │ │ ├── jest.setup.ts │ │ └── tsconfig.json │ └── integration │ │ ├── tsconfig.json │ │ ├── 00_seed.test.ts │ │ └── jest.util.ts ├── tsconfig.json ├── swagger │ └── assets │ │ ├── favicon-16x16.png │ │ └── favicon-32x32.png ├── tsconfig.dist.json ├── test.sequencer.js ├── jest-u.config.js ├── jest-i.config.js ├── jest.config.js ├── project.json ├── jest-e2e.config.js └── base.json ├── .yarn └── versions │ ├── 34a1b820.yml │ ├── 3fa39196.yml │ ├── e4a2d889.yml │ └── b2f619d3.yml ├── .prettierignore ├── jest.preset.js ├── .husky └── pre-commit ├── Dockerfile-website ├── .prettierrc.js ├── .yarnrc.yml ├── jest.config.ts ├── .eslintrc.json ├── .vscode └── settings.json ├── CHANGELOG.md ├── .github └── renovate.json └── Dockerfile-api /tools/index.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /dashboard/src/shared: -------------------------------------------------------------------------------- 1 | ../../shared/src -------------------------------------------------------------------------------- /website/src/frames/admin/index.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /settings-form/README.md: -------------------------------------------------------------------------------- 1 | # Settings Form 2 | -------------------------------------------------------------------------------- /settings-form/src/shared: -------------------------------------------------------------------------------- 1 | ../../shared/src -------------------------------------------------------------------------------- /shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './api-client'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './draft'; 2 | -------------------------------------------------------------------------------- /settings-form/src/i18n/index.ts: -------------------------------------------------------------------------------- 1 | export * from './i18n'; 2 | -------------------------------------------------------------------------------- /dashboard/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /settings-form/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /website/src/contexts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './language-context'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/context/index.ts: -------------------------------------------------------------------------------- 1 | export * from './context'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/index.ts: -------------------------------------------------------------------------------- 1 | export * from './content'; 2 | -------------------------------------------------------------------------------- /dashboard/src/types/filter.ts: -------------------------------------------------------------------------------- 1 | export { DashboardFilterType } from '~/model'; 2 | -------------------------------------------------------------------------------- /api/test-teardown-globals.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | process.exit(0); 3 | }; 4 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/model/layouts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './layouts'; 2 | -------------------------------------------------------------------------------- /dashboard/src/interactions/trigger/index.ts: -------------------------------------------------------------------------------- 1 | export * from './trigger-manager-impl'; 2 | -------------------------------------------------------------------------------- /dashboard/src/utils/rich-text/index.ts: -------------------------------------------------------------------------------- 1 | export * from './parse-rich-text-content'; 2 | -------------------------------------------------------------------------------- /website/.env.sample: -------------------------------------------------------------------------------- 1 | VITE_API_BASE_URL=http://localhost:31200/ 2 | VITE_WEBSITE_BASE_URL=/ -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-select/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './editor'; 2 | -------------------------------------------------------------------------------- /shared/README.md: -------------------------------------------------------------------------------- 1 | # shared 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | -------------------------------------------------------------------------------- /.yarn/versions/34a1b820.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@devtable/root" 3 | - "@devtable/dashboard" 4 | -------------------------------------------------------------------------------- /.yarn/versions/3fa39196.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@devtable/root" 3 | - "@devtable/dashboard" 4 | -------------------------------------------------------------------------------- /.yarn/versions/e4a2d889.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@devtable/root" 3 | - "@devtable/dashboard" 4 | -------------------------------------------------------------------------------- /api/src/cli/clearCache.ts: -------------------------------------------------------------------------------- 1 | import { clearCache } from '../utils/cache'; 2 | 3 | clearCache(); 4 | -------------------------------------------------------------------------------- /api/tests/e2e/constants.ts: -------------------------------------------------------------------------------- 1 | export const notFoundId = '3e7acce4-b8cd-4c01-b009-d2ea33a07258'; 2 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/model/datasources/db-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './db-info'; 2 | -------------------------------------------------------------------------------- /dashboard/src/i18n/index.ts: -------------------------------------------------------------------------------- 1 | export * from './i18n'; 2 | export * from './i18next-context'; 3 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/layouts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './layouts'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/tooltip-metric/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-stats/migrators/index.ts: -------------------------------------------------------------------------------- 1 | export * from './v2'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/stats/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './click-stats'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/view/index.ts: -------------------------------------------------------------------------------- 1 | export * from './view-editor'; 2 | export * from './view-render'; 3 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-editor'; 2 | export * from './model'; 3 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-render/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-render'; 2 | export * from './model'; 3 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/mock-context/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mock-context'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/sql-snippet/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sql-snippet'; 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .yarn/* 2 | **/*/dist 3 | api/swagger 4 | *.json 5 | *.html 6 | /.nx/cache 7 | /.nx/workspace-data -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-merico-date-range/widget/calendar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './calendar'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './panel-editor'; 2 | export * from './panel-render'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/pie-chart/editors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './radius-slider'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/view/view-component/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-download-div-screenshot'; 2 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/model/panels/index.ts: -------------------------------------------------------------------------------- 1 | export * from './panel'; 2 | export * from './panels'; 3 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/model/queries/index.ts: -------------------------------------------------------------------------------- 1 | export * from './query'; 2 | export * from './queries'; 3 | -------------------------------------------------------------------------------- /dashboard/src/utils/template/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './template-input'; 2 | export * from './utils'; 3 | -------------------------------------------------------------------------------- /api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./base", 3 | "exclude": ["node_modules", "build", "_build", "tests"] 4 | } 5 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-editor/dropdown-menu-items/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dropdown-menu-items'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/settings/common/variable-selector/index.ts: -------------------------------------------------------------------------------- 1 | export * from './variable-selector'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/editor-components/field-array-tabs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './field-array-tabs'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/view/layout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './edit-layout'; 2 | export * from './render-layout'; 3 | -------------------------------------------------------------------------------- /dashboard/src/utils/template/render/index.ts: -------------------------------------------------------------------------------- 1 | export * from './render-jsx'; 2 | export * from './render-string'; 3 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /website/src/global.d.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2 | type $TSFixMe = any; 3 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | yarn exec nx format --uncommitted 5 | -------------------------------------------------------------------------------- /api/tests/unit/jest.setup.ts: -------------------------------------------------------------------------------- 1 | module.exports = async (globalConfig) => { 2 | process.env.ENABLE_AUTH = '1'; 3 | }; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/color-manager/index.ts: -------------------------------------------------------------------------------- 1 | export * from './color-manager'; 2 | export * from './impl'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/stats-around-viz/index.ts: -------------------------------------------------------------------------------- 1 | export * from './stats-around-viz'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/button/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickButton } from './click-button'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-stats/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './click-merico-stats'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/rich-text/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './click-rich-text-block'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/rich-text-editor/color-picker-control/index.ts: -------------------------------------------------------------------------------- 1 | export * from './color-picker-control'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/datasources/index.ts: -------------------------------------------------------------------------------- 1 | export * from './datasources'; 2 | export * from './datasource'; 3 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/filters/types.ts: -------------------------------------------------------------------------------- 1 | export type FilterValuesType = Record; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/views/index.ts: -------------------------------------------------------------------------------- 1 | export * from './view'; 2 | export * from './views'; 3 | -------------------------------------------------------------------------------- /website/src/api-caller/status.typs.ts: -------------------------------------------------------------------------------- 1 | export type VersionResp = { 2 | semver: string; 3 | version: string; 4 | }; 5 | -------------------------------------------------------------------------------- /Dockerfile-website: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | COPY ./website/dist /usr/share/nginx/html 4 | 5 | CMD exec nginx -g 'daemon off;' 6 | -------------------------------------------------------------------------------- /api/swagger/assets/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merico-dev/table/HEAD/api/swagger/assets/favicon-16x16.png -------------------------------------------------------------------------------- /api/swagger/assets/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/merico-dev/table/HEAD/api/swagger/assets/favicon-32x32.png -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/filter-tree-select/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './filter-tree-select-editor'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/filter-tree-select/render/index.ts: -------------------------------------------------------------------------------- 1 | export * from './filter-tree-select-render'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/axis-label-rotate/index.ts: -------------------------------------------------------------------------------- 1 | export * from './axis-label-rotate-input'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/cartesian/option/series/types.ts: -------------------------------------------------------------------------------- 1 | export type DataTemplateType = [string, 0]; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/function-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './function-editor'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-panel/variable-config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './variables-editor'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './meta-model'; 2 | export * from './render-model'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/filters/index.ts: -------------------------------------------------------------------------------- 1 | export * from './filters'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /.yarn/versions/b2f619d3.yml: -------------------------------------------------------------------------------- 1 | undecided: 2 | - "@devtable/root" 3 | - "@devtable/settings-form" 4 | - "@devtable/website" 5 | -------------------------------------------------------------------------------- /api/src/preset/sql_snippets/config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "snippet1": "test snippet 1", 3 | "snippet2": "test snippet 2" 4 | } 5 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/filter-tree-select/index.ts: -------------------------------------------------------------------------------- 1 | export * from './editor'; 2 | export * from './render'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/cartesian/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickEchartSeries } from './click-echart'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/heatmap/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickHeatBlock } from './click-heat-block'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-linear-gauge/render/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viz-merico-linear-gauge'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-panel-groups/render/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viz-merico-panel-groups'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/pie-chart/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickPieChart } from './click-pie-chart'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/table/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickCellContent } from './click-cell-content'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/layout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './layout-item'; 2 | export * from './layout-set'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/filter-tree-single-select/index.ts: -------------------------------------------------------------------------------- 1 | export * from './editor'; 2 | export * from './render'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/regression-line/index.ts: -------------------------------------------------------------------------------- 1 | export * from './option'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/x-axis-position/types.ts: -------------------------------------------------------------------------------- 1 | export type EChartsXAxisPosition = 'top' | 'bottom'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/y-axis-position/types.ts: -------------------------------------------------------------------------------- 1 | export type EChartsYAxisPosition = 'left' | 'right'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/editor-components/color-type/type.ts: -------------------------------------------------------------------------------- 1 | export type ColorType = 'static' | 'interpolation' | 'none'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/boxplot-chart/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickBoxplotSeries } from './click-boxplot'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-heatmap/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickHeatBlock } from './click-heat-block'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-linear-gauge/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viz-merico-linear-gauge-editor'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-linear-gauge/editor/sections-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sections-editor'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-panel-groups/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viz-merico-panel-groups-editor'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/pareto-chart/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickParetoSeries } from './click-pareto'; 2 | -------------------------------------------------------------------------------- /dashboard/src/interactions/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-watch-triggers'; 2 | export * from './use-current-interaction-manager'; 3 | -------------------------------------------------------------------------------- /dashboard/src/test/setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import { vi } from 'vitest'; 3 | global.jest = vi as $TSFixMe; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/filter-tree-single-select/editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './filter-tree-single-select-editor'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/filter-tree-single-select/render/index.ts: -------------------------------------------------------------------------------- 1 | export * from './filter-tree-single-select-render'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/line-type/types.ts: -------------------------------------------------------------------------------- 1 | export type IEChartsLineType = 'solid' | 'dashed' | 'dotted'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/orientation/types.ts: -------------------------------------------------------------------------------- 1 | export type ChartingOrientation = 'horizontal' | 'vertical'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/editor-components/color-type/index.ts: -------------------------------------------------------------------------------- 1 | export * from './color-type-selector'; 2 | export * from './type'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/horizontal-bar-chart/option/series/types.ts: -------------------------------------------------------------------------------- 1 | export type DataTemplateType = [string, 0]; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/horizontal-bar-chart/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './click-horizontal-bar-chart-series'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/pie-chart/editors/pie-color-map-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './pie-color-map-editor'; 2 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/header/spotlight/index.ts: -------------------------------------------------------------------------------- 1 | export * from './editor-spotlight'; 2 | export * from './spotlight-control'; 3 | -------------------------------------------------------------------------------- /tools/workspace-plugin/src/executors/is-published/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface IsPublishedExecutorSchema { 2 | packageJson: string; 3 | } 4 | -------------------------------------------------------------------------------- /website/src/api-caller/types.ts: -------------------------------------------------------------------------------- 1 | export type PaginationResponse = { 2 | total: number; 3 | offset: number; 4 | data: T[]; 5 | }; 6 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/line-type/index.ts: -------------------------------------------------------------------------------- 1 | export * from './line-type-selector'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/name-text-align/types.ts: -------------------------------------------------------------------------------- 1 | export type EChartsNameTextAlign = 'left' | 'center' | 'right'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/orientation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './orientation-selector'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/series-unit/index.ts: -------------------------------------------------------------------------------- 1 | export * from './series-unit-field'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/symbol-size/index.ts: -------------------------------------------------------------------------------- 1 | export * from './symbol-size-selector'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/calendar-heatmap/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickCalendarDate } from './click-calendar-date'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/regression-chart/render/toolbox/choose-data-keys/index.ts: -------------------------------------------------------------------------------- 1 | export * from './choose-data-keys'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/regression-chart/render/toolbox/data-key-selector/index.ts: -------------------------------------------------------------------------------- 1 | export * from './data-key-selector'; 2 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/scatter-chart/triggers/index.ts: -------------------------------------------------------------------------------- 1 | export { ClickScatterChartSeries } from './click-scatter-chart'; 2 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/query-tabs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './query-tabs'; 2 | -------------------------------------------------------------------------------- /dashboard/src/interactions/operation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './operations'; 2 | export { OperationManager } from './operation-manager-impl'; 3 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/global-sql-snippets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './global-sql-snippet'; 2 | export * from './global-sql-snippets'; 3 | -------------------------------------------------------------------------------- /dashboard/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard'; 2 | export * from './filter'; 3 | export type { AnyObject, Ready } from './utils'; 4 | -------------------------------------------------------------------------------- /settings-form/src/api-caller/types.ts: -------------------------------------------------------------------------------- 1 | export type PaginationResponse = { 2 | total: number; 3 | offset: number; 4 | data: T[]; 5 | }; 6 | -------------------------------------------------------------------------------- /settings-form/src/api-key/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './add-api-key'; 2 | export * from './api-key-list'; 3 | export * from './delete-api-key'; 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | singleQuote: true, 4 | trailingComma: 'all', 5 | jsxSingleQuote: false, 6 | }; 7 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/line-area-style/index.ts: -------------------------------------------------------------------------------- 1 | export * from './line-area-style-field'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/series-order/index.ts: -------------------------------------------------------------------------------- 1 | export * from './series-order-selector'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/plugin-data-migrator/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugin-data-migrator'; 2 | export * from './version-based-migrator'; 3 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/preview-data/index.ts: -------------------------------------------------------------------------------- 1 | export * from './preview-data'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/view/index.ts: -------------------------------------------------------------------------------- 1 | export * from './view'; 2 | export * from './widgets'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /settings-form/src/api-caller/role.typed.ts: -------------------------------------------------------------------------------- 1 | export interface IRole { 2 | id: string; 3 | description: string; 4 | permissions: string[]; 5 | } 6 | -------------------------------------------------------------------------------- /website/src/components/readonly-monaco-editor/index.css: -------------------------------------------------------------------------------- 1 | .website-readonly-monaco-editor { 2 | border-radius: 0px; 3 | overflow: hidden; 4 | } 5 | -------------------------------------------------------------------------------- /website/src/types/dayjs-locale.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'dayjs/locale/*' { 2 | const locale: Record; 3 | export default locale; 4 | } 5 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | nodeLinker: node-modules 6 | 7 | yarnPath: .yarn/releases/yarn-4.12.0.cjs 8 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/full-screen-render/index.ts: -------------------------------------------------------------------------------- 1 | export * from './full-screen-panel'; 2 | export * from './use-panel-full-screen'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/label-position/index.ts: -------------------------------------------------------------------------------- 1 | export * from './label-position-selector'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/name-text-align/index.ts: -------------------------------------------------------------------------------- 1 | export * from './name-text-align-selector'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/x-axis-position/index.ts: -------------------------------------------------------------------------------- 1 | export * from './x-axis-position-selector'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/y-axis-position/index.ts: -------------------------------------------------------------------------------- 1 | export * from './y-axis-position-selector'; 2 | export * from './types'; 3 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/filter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './filter'; 2 | export * from './types'; 3 | export * from './widgets'; 4 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/panels/index.ts: -------------------------------------------------------------------------------- 1 | export * from './panel'; 2 | export * from './panels'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /dashboard/src/utils/template/index.ts: -------------------------------------------------------------------------------- 1 | export * from './editor'; 2 | export * from './render'; 3 | export * from './types'; 4 | export * from './utils'; 5 | -------------------------------------------------------------------------------- /settings-form/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './minimal-mocaco-editor'; 2 | export * from './submit-form-button'; 3 | export * from './with-entry'; 4 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/view/widgets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './division'; 2 | export * from './modal'; 3 | export * from './tabs'; 4 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/queries/index.ts: -------------------------------------------------------------------------------- 1 | export * from './queries'; 2 | export * from './query'; 3 | export * from './mute-query'; 4 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjectsAsync } from '@nx/jest'; 2 | 3 | export default async () => ({ 4 | projects: await getJestProjectsAsync(), 5 | }); 6 | -------------------------------------------------------------------------------- /settings-form/src/datasource/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './add-data-source'; 2 | export * from './data-source-list'; 3 | export * from './delete-data-source'; 4 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Dashboard Demo 2 | 3 | ## Development 4 | 5 | ```bash 6 | $ nx dev website 7 | ``` 8 | 9 | see `package.json` for more scripts 10 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-render/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard'; 2 | export * from './content'; 3 | export { type IContentRenderModel } from './types'; 4 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './query'; 2 | export * from './types'; 3 | export * from './merico-metric-query'; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/index.ts: -------------------------------------------------------------------------------- 1 | export * from './filter-tree-select'; 2 | export * from './filter-tree-single-select'; 3 | export * from './common'; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/viz/viz.css: -------------------------------------------------------------------------------- 1 | .viz-root { 2 | width: 100%; 3 | overflow: auto; 4 | flex-grow: 1; 5 | background-color: white; 6 | } 7 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/visual-map/index.ts: -------------------------------------------------------------------------------- 1 | export * from './visual-map-editor'; 2 | export * from './types'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/preview-query-and-vars/index.ts: -------------------------------------------------------------------------------- 1 | export * from './preview-query-and-vars'; 2 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/query-tabs/edit-metric-query/index.ts: -------------------------------------------------------------------------------- 1 | export * from './edit-metric-query'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/view/types.ts: -------------------------------------------------------------------------------- 1 | export enum EViewComponentType { 2 | Division = 'div', 3 | Modal = 'modal', 4 | Tabs = 'tabs', 5 | } 6 | -------------------------------------------------------------------------------- /shared/src/api-client/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './utils'; 3 | export * from './default-api-client'; 4 | export * from './facade-api-client'; 5 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/viz/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viz'; 2 | export * from './panel-error-or-state-message'; 3 | export * from './panel-viz-section'; 4 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/index.ts: -------------------------------------------------------------------------------- 1 | export * from './header'; 2 | export * from './navbar'; 3 | export * from './settings'; 4 | export * from './header/spotlight'; 5 | -------------------------------------------------------------------------------- /api/src/preset/sql_snippets/README.md: -------------------------------------------------------------------------------- 1 | To add preset sql snippets, make a copy of config.example.json and rename it to config.json. 2 | Modify the file according to the examples. 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/boxplot-chart/option/series/custom/index.ts: -------------------------------------------------------------------------------- 1 | export * from './box'; 2 | export * from './scatter'; 3 | export * from './outliers'; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/boxplot-chart/option/type.ts: -------------------------------------------------------------------------------- 1 | export type SeriesNames = { 2 | Box: string; 3 | Scatter: string; 4 | Outlier: string; 5 | }; 6 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard'; 2 | export * from './datasources'; 3 | export * from './global-sql-snippets'; 4 | export * from './context'; 5 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/editor-components/flex/index.ts: -------------------------------------------------------------------------------- 1 | export * from './justify-content-selector'; 2 | export * from './align-items-selector'; 3 | export * from './type'; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './use-channel-event'; 2 | export * from './use-storage-data'; 3 | export * from './use-handle-chart-render-finished'; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/rich-text-editor/line-height-mark/index.ts: -------------------------------------------------------------------------------- 1 | export * from './line-height-mark'; 2 | export * from './line-height-control'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-editor-page/content-rebase-warning/rebase-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './rebase-dashboard-config-modal'; 2 | export { diffNodes } from './diff-nodes'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/pareto-chart/option/types.ts: -------------------------------------------------------------------------------- 1 | export type TLineDataItem = [string | number, number]; 2 | export type BarData = [string | number, number][]; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/rich-text-editor/color-mapping-mark/index.ts: -------------------------------------------------------------------------------- 1 | export * from './color-mapping-mark'; 2 | export * from './color-mapping-control'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/rich-text-editor/dynamic-color-mark/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dynamic-color-mark'; 2 | export * from './dynamic-color-control'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/query-tabs/edit-metric-query/dimension-selector/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dimension-selector'; 2 | -------------------------------------------------------------------------------- /settings-form/src/api-caller/api-key.typed.ts: -------------------------------------------------------------------------------- 1 | export interface IAPIKey { 2 | id: string; 3 | name: string; 4 | role_id: string; 5 | app_id: string; 6 | app_secret: string; 7 | } 8 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-settings/types.ts: -------------------------------------------------------------------------------- 1 | import { FilterMetaInstance } from '~/model'; 2 | 3 | export interface IFilterSettingsForm { 4 | filters: FilterMetaInstance[]; 5 | } 6 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/number-or-dynamic-value/index.ts: -------------------------------------------------------------------------------- 1 | export * from './field'; 2 | export * from './get-number-or-dynamic-value'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /dashboard/src/interactions/components/index.ts: -------------------------------------------------------------------------------- 1 | export { InteractionSettingsPanel } from './interaction-settings'; 2 | export { VariableList, type IVariableListProps } from './variable-list'; 3 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/query-tabs/edit-metric-query/dimension-selector/dimension-icon/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dimension-icon'; 2 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/sql-snippets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './sql-snippet'; 2 | export * from './sql-snippets'; 3 | export * from './types'; 4 | export * from './utils'; 5 | -------------------------------------------------------------------------------- /settings-form/src/sql_snippet/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './add-sql_snippet'; 2 | export * from './update-sql_snippet'; 3 | export * from './sql_snippet-list'; 4 | export * from './delete-sql_snippet'; 5 | -------------------------------------------------------------------------------- /website/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /api/src/preset/custom_functions/README.md: -------------------------------------------------------------------------------- 1 | To add preset custom functions, make a copy of config.example.js and rename it to config.js. 2 | It is advised to use arrow functions for function definitions. 3 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/utils.ts: -------------------------------------------------------------------------------- 1 | export function doesVizRequiresData(type: string) { 2 | const vizTypes = ['richText', 'button', 'vizDashboardState']; 3 | return !vizTypes.includes(type); 4 | } 5 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/model/datasources/mm-info/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mm-info'; 2 | export * from './metric-detail'; 3 | export * from './metric-detail.types'; 4 | export * from './metrics'; 5 | -------------------------------------------------------------------------------- /dashboard/src/interactions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks'; 2 | export * from './components'; 3 | export * from './operation'; 4 | export * from './trigger'; 5 | export * from './interaction-manager'; 6 | -------------------------------------------------------------------------------- /settings-form/src/datasource/edit-data-source/types.ts: -------------------------------------------------------------------------------- 1 | import { TDataSourceConfig } from '../../api-caller/datasource.typed'; 2 | 3 | export interface IFormValues { 4 | config: TDataSourceConfig; 5 | } 6 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-render-page/content.css: -------------------------------------------------------------------------------- 1 | .dashboard-page-content { 2 | display: flex; 3 | flex-direction: column; 4 | flex-wrap: nowrap; 5 | height: 100%; 6 | overflow: hidden; 7 | } 8 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/index.css: -------------------------------------------------------------------------------- 1 | .panel-root { 2 | height: 100%; 3 | width: 100%; 4 | max-width: 100%; 5 | background: transparent; 6 | border-radius: 4px; 7 | position: relative; 8 | } 9 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/panel-addon/index.ts: -------------------------------------------------------------------------------- 1 | export * from './panel-addon-manager'; 2 | export { PanelAddonProvider, usePanelAddonSlot } from '~/components/panel/panel-render/panel-addon-context'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/rich-text/type.ts: -------------------------------------------------------------------------------- 1 | export interface IRichTextConf { 2 | content: ''; 3 | } 4 | 5 | export const DEFAULT_CONFIG: IRichTextConf = { 6 | content: '', 7 | }; 8 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/panel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './panel'; 2 | export * from './viz'; 3 | export * from './style'; 4 | export * from './title'; 5 | export * from './variable'; 6 | -------------------------------------------------------------------------------- /dashboard/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src", "**/*.spec.ts"], 4 | "exclude": [], 5 | "compilerOptions": { 6 | "types": ["vitest/globals"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tools/workspace-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workspace-plugin", 3 | "version": "0.0.1", 4 | "type": "commonjs", 5 | "generators": "./generators.json", 6 | "executors": "./executors.json" 7 | } 8 | -------------------------------------------------------------------------------- /website/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /dashboard/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/visual-map/visual-map-editor/types.ts: -------------------------------------------------------------------------------- 1 | import { VisualMap } from '../types'; 2 | 3 | export type VisualMapPartialForm = { 4 | visualMap: VisualMap; 5 | }; 6 | -------------------------------------------------------------------------------- /settings-form/src/account/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './add-account'; 2 | export * from './account-list'; 3 | export * from './delete-account'; 4 | export * from './login'; 5 | export type { IStyles } from './styles'; 6 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-editor-page/index.css: -------------------------------------------------------------------------------- 1 | .load-and-render-dashboard-editor { 2 | display: flex; 3 | flex-direction: column; 4 | flex-wrap: nowrap; 5 | height: 100%; 6 | overflow: hidden; 7 | } 8 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/viz-dashboard-state/render/item/selection-table.module.css: -------------------------------------------------------------------------------- 1 | .table { 2 | font-size: 12px !important; 3 | } 4 | .table th, 5 | .table td { 6 | padding: 5px 10px; 7 | } 8 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/color-picker-popover/index.ts: -------------------------------------------------------------------------------- 1 | export * from './color-input'; 2 | export * from './color-picker-popover'; 3 | export * from './utils'; 4 | export * from './color-picker-popover-for-viz'; 5 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/color-manager/type.ts: -------------------------------------------------------------------------------- 1 | export interface IValueMapper { 2 | /** 3 | * Maps any number to a number between 0 and 100 4 | * @param from 5 | */ 6 | mapValue(from: number): number; 7 | } 8 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/axis-label-overflow/index.ts: -------------------------------------------------------------------------------- 1 | export * from './axis-label-overflow-field'; 2 | export * from './types'; 3 | export * from './overflow-field'; 4 | export * from './overflow-option'; 5 | -------------------------------------------------------------------------------- /api/src/preset/data_sources/README.md: -------------------------------------------------------------------------------- 1 | To add preset datasources, make a copy of config.example.json and rename it to config.json. 2 | The configuration for each type follows the same rules as using the frontend to configure datasources. 3 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './expected-structure'; 2 | export * from './query-data-to-tree'; 3 | export * from './switcher-icon'; 4 | export * from './tree-icon'; 5 | export * from './types'; 6 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/index.ts: -------------------------------------------------------------------------------- 1 | export * from './panel-render'; 2 | export * from './viz'; 3 | export * from './full-screen-render'; 4 | export * from './description-popover'; 5 | export * from './client-panel-render'; 6 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/boxplot-chart/option/common.ts: -------------------------------------------------------------------------------- 1 | import { IBoxplotDataItem } from '../type'; 2 | 3 | export const BOXPLOT_DATA_ITEM_KEYS: Array = ['max', 'q3', 'median', 'q1', 'min']; 4 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/merico-icons/types.ts: -------------------------------------------------------------------------------- 1 | export type MericoIconProps = { 2 | width: number | string; 3 | height: number | string; 4 | color?: string; 5 | }; 6 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/editor-components/flex/type.ts: -------------------------------------------------------------------------------- 1 | export type JustifyContent = 'center' | 'left' | 'right' | 'space-between' | 'space-around' | 'space-evenly'; 2 | export type AlignItems = 'start' | 'center' | 'end' | 'stretch'; 3 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/pie-chart/option/types.ts: -------------------------------------------------------------------------------- 1 | export type TDataItem = { 2 | name: string; 3 | value: number; 4 | color?: string; 5 | ratio: number; 6 | percentage: string; 7 | items?: TDataItem[]; 8 | }; 9 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './views'; 2 | export * from './panels'; 3 | export * from './filters'; 4 | export * from './queries'; 5 | export * from './layouts'; 6 | export * from './sql-snippets'; 7 | -------------------------------------------------------------------------------- /tools/workspace-plugin/src/generators/viz-component/files/type.ts__tmpl__: -------------------------------------------------------------------------------- 1 | export interface I<%= pascalcase(name) %>Conf { 2 | hello: string; 3 | } 4 | 5 | export const DEFAULT_CONFIG: I<%= pascalcase(name) %>Conf = { 6 | hello: 'world' 7 | }; 8 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/x-axis-label-formatter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './function-editor'; 2 | export * from './get-echarts-x-axis-tick-label'; 3 | export * from './x-axis-label-formatter-field'; 4 | export * from './types'; 5 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/query/types.ts: -------------------------------------------------------------------------------- 1 | export enum DataSourceType { 2 | Postgresql = 'postgresql', 3 | MySQL = 'mysql', 4 | HTTP = 'http', 5 | Transform = 'transform', 6 | MericoMetricSystem = 'merico_metric_system', 7 | } 8 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './filters'; 2 | export * from './queries'; 3 | export * from './sql-snippets'; 4 | export * from './dashboard'; 5 | export * from './views'; 6 | export * from './panels'; 7 | export * from './content'; 8 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/merico-icons/index.ts: -------------------------------------------------------------------------------- 1 | export * from './external-link'; 2 | export * from './play'; 3 | export * from './copy'; 4 | export * from './delete'; 5 | export * from './more'; 6 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-query/merico-metric-query-editor-form/query-tabs/edit-metric-query/table-styles.ts: -------------------------------------------------------------------------------- 1 | export const MetricTableStyles = { 2 | tbody: { 3 | td: { 4 | fontFamily: 'monospace', 5 | }, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /api/tests/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../base", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "~/*": ["../../src/*"] 7 | }, 8 | "types": ["node", "jest"], 9 | "strictNullChecks": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /settings-form/src/datasource/add-data-source/types.ts: -------------------------------------------------------------------------------- 1 | import { DataSourceType, TDataSourceConfig } from '../../api-caller/datasource.typed'; 2 | 3 | export interface IFormValues { 4 | type: DataSourceType; 5 | key: string; 6 | config: TDataSourceConfig; 7 | } 8 | -------------------------------------------------------------------------------- /api/tests/unit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../base", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "~/*": ["../../src/*"] 7 | }, 8 | "types": ["node", "jest"], 9 | "strictNullChecks": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/sql-snippets/types.ts: -------------------------------------------------------------------------------- 1 | import { Instance } from 'mobx-state-tree'; 2 | import { SQLSnippetsRenderModel } from './sql-snippets'; 3 | 4 | export type SQLSnippetsRenderModelInstance = Instance; 5 | -------------------------------------------------------------------------------- /api/tests/e2e/jest.mock.ts: -------------------------------------------------------------------------------- 1 | import { NextFunction, Request, Response } from 'express'; 2 | 3 | jest.mock('~/middleware/validation', () => ({ 4 | validate: () => (req: Request, res: Response, next: NextFunction) => next(), 5 | validateClass: (type, data) => data, 6 | })); 7 | -------------------------------------------------------------------------------- /api/tests/integration/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../base", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "~/*": ["../../src/*"] 7 | }, 8 | "types": ["node", "jest"], 9 | "strictNullChecks": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/tooltip-metric/types.ts: -------------------------------------------------------------------------------- 1 | import { SeriesUnitType } from '../series-unit'; 2 | 3 | export interface IEchartsTooltipMetric { 4 | id: string; 5 | data_key: TDataKey; 6 | name: string; 7 | unit: SeriesUnitType; 8 | } 9 | -------------------------------------------------------------------------------- /website/src/pages/status-page/index.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@mantine/core'; 2 | import { StatusTable } from './table'; 3 | 4 | export function StatusPage() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/scatter-chart/option/legend.ts: -------------------------------------------------------------------------------- 1 | export function getLegend() { 2 | const ret: Record = { 3 | show: false, 4 | bottom: 0, 5 | left: 'center', 6 | type: 'scroll', 7 | }; 8 | return ret; 9 | } 10 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/viz-dashboard-state/type.ts: -------------------------------------------------------------------------------- 1 | export interface IVizDashboardStateConf { 2 | all: boolean; 3 | keys: string[]; 4 | } 5 | 6 | export const DEFAULT_CONFIG: IVizDashboardStateConf = { 7 | all: true, 8 | keys: [], 9 | }; 10 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/rich-text-editor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './custom-rich-text-editor'; 2 | export * from './dynamic-color-mark'; 3 | export * from './font-size-extension'; 4 | export * from './readonly-rich-text-editor'; 5 | export * from './rich-text-editor-modal'; 6 | -------------------------------------------------------------------------------- /dashboard/src/emotion.d.ts: -------------------------------------------------------------------------------- 1 | import '@mantine/core'; 2 | 3 | import type { EmotionStyles, EmotionSx } from '@mantine/emotion'; 4 | 5 | declare module '@mantine/core' { 6 | export interface BoxProps { 7 | sx?: EmotionSx; 8 | styles?: EmotionStyles; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /dashboard/src/styles/default-echarts-options/index.ts: -------------------------------------------------------------------------------- 1 | import * as xAxis from './x-axis'; 2 | import * as yAxis from './y-axis'; 3 | import * as tooltip from './tooltip'; 4 | 5 | export const defaultEchartsOptions = { 6 | ...xAxis, 7 | ...yAxis, 8 | ...tooltip, 9 | }; 10 | -------------------------------------------------------------------------------- /website/src/api-caller/custom-function.types.ts: -------------------------------------------------------------------------------- 1 | export type TCustomFunctionDefinition = () => Record; 2 | export type TCustomFunctionDto = { 3 | id: string; 4 | is_preset: boolean; 5 | definition: string; 6 | create_time: string; 7 | update_time: string; 8 | }; 9 | -------------------------------------------------------------------------------- /website/src/emotion.d.ts: -------------------------------------------------------------------------------- 1 | import '@mantine/core'; 2 | 3 | import type { EmotionStyles, EmotionSx } from '@mantine/emotion'; 4 | 5 | declare module '@mantine/core' { 6 | export interface BoxProps { 7 | sx?: EmotionSx; 8 | styles?: EmotionStyles; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /settings-form/src/emotion.d.ts: -------------------------------------------------------------------------------- 1 | import '@mantine/core'; 2 | 3 | import type { EmotionStyles, EmotionSx } from '@mantine/emotion'; 4 | 5 | declare module '@mantine/core' { 6 | export interface BoxProps { 7 | sx?: EmotionSx; 8 | styles?: EmotionStyles; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-editor-page/more-dashboard-info/types.ts: -------------------------------------------------------------------------------- 1 | export type TModalState = { 2 | opened: boolean; 3 | open: () => void; 4 | close: () => void; 5 | }; 6 | 7 | export type TModalStates = { 8 | changelog: TModalState; 9 | version: TModalState; 10 | }; 11 | -------------------------------------------------------------------------------- /website/src/api-caller/dashboard.typed.ts: -------------------------------------------------------------------------------- 1 | export type TDashboardMetaInfo = { 2 | id: string; 3 | name: string; 4 | group: string; 5 | content_id: string | null; 6 | create_time: string; 7 | update_time: string; 8 | is_removed: boolean; 9 | is_preset?: boolean; 10 | }; 11 | -------------------------------------------------------------------------------- /dashboard/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "resolveJsonModule": true 7 | }, 8 | "include": ["vite.config.ts", "package.json","./rollup-plugin-write-version-file.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/dropdown-menu-items/index.ts: -------------------------------------------------------------------------------- 1 | export * from './download-data'; 2 | export * from './download-screenshot'; 3 | export * from './download-schema'; 4 | export * from './enter-fullscreen'; 5 | export * from './refresh'; 6 | export * from './dropdown-menu-items'; 7 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-manager/index.ts: -------------------------------------------------------------------------------- 1 | export { VizManager } from './impl'; 2 | export type { IVizManager, IPanelInfo } from './types'; 3 | export { VizConfigComponent, VizViewComponent } from './components'; 4 | export type { IViewPanelInfo, IViewComponentProps } from './components'; 5 | -------------------------------------------------------------------------------- /dashboard/src/global.d.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2 | type $TSFixMe = any; 3 | 4 | type TFunctionString = string; 5 | 6 | type TPanelData = Record; 7 | type TQueryData = Record[]; 8 | type TDataKey = string; // queryID.columnKey 9 | -------------------------------------------------------------------------------- /settings-form/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "resolveJsonModule": true 7 | }, 8 | "include": ["vite.config.ts", "package.json", "./rollup-plugin-write-version-file.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /tools/tsconfig.plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": "./", 4 | "outDir": "./dist/nx-plugin", 5 | "module": "commonjs", 6 | "target": "ES2019", 7 | "sourceMap": false, 8 | "skipLibCheck": true 9 | }, 10 | "exclude": ["node_modules", "dist"] 11 | } 12 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": "./", 4 | "outDir": "./dist/generators", 5 | "module": "commonjs", 6 | "target": "ES2019", 7 | "sourceMap": false, 8 | "skipLibCheck": true 9 | }, 10 | "exclude": ["node_modules", "dist"] 11 | } 12 | -------------------------------------------------------------------------------- /tools/workspace-plugin/executors.json: -------------------------------------------------------------------------------- 1 | { 2 | "executors": { 3 | "is-published": { 4 | "implementation": "./src/executors/is-published/executor", 5 | "schema": "./src/executors/is-published/schema.json", 6 | "description": "is-published executor" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tools/workspace-plugin/generators.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "viz-component": { 4 | "implementation": "./src/generators/viz-component", 5 | "schema": "./src/generators/viz-component/schema.json", 6 | "description": "Generator viz-component" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/series-order/types.ts: -------------------------------------------------------------------------------- 1 | export type SeriesOrder = { 2 | key: 'name' | 'value' | ''; 3 | order: 'asc' | 'desc'; 4 | }; 5 | export const getDefaultSeriesOrder = () => 6 | ({ 7 | key: '', 8 | order: 'desc', 9 | } as SeriesOrder); 10 | -------------------------------------------------------------------------------- /settings-form/src/api-caller/role.ts: -------------------------------------------------------------------------------- 1 | import { APIClient } from './request'; 2 | import { IRole } from './role.typed'; 3 | 4 | export const role = { 5 | list: async (): Promise => { 6 | const res: IRole[] = await APIClient.get()('/role/list', {}, {}); 7 | return res; 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/2.0.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * from before-versioning state to 2.0.0 3 | * @param schema 4 | * @returns schema with version set to 2.0.0 5 | */ 6 | export function main(schema: Record) { 7 | return { 8 | ...schema, 9 | version: '2.0.0', 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /shared/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"] 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /website/src/frames/app/index.css: -------------------------------------------------------------------------------- 1 | .App { 2 | padding: 1em; 3 | } 4 | 5 | .website-app .mantine-AppShell-main::-webkit-scrollbar { 6 | width: 0 !important; 7 | height: 0 !important; 8 | } 9 | .website-app .mantine-AppShell-main { 10 | overflow: -moz-scrollbars-none; 11 | -ms-overflow-style: none; 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/cartesian/option/utils/types.ts: -------------------------------------------------------------------------------- 1 | export type TEchartsSeriesType = 'line' | 'bar' | 'scatter'; 2 | 3 | export interface IEchartsSeriesItem { 4 | name: string; 5 | color?: string; 6 | type: TEchartsSeriesType; 7 | hide_in_legend: boolean; 8 | yAxisIndex: number; 9 | } 10 | -------------------------------------------------------------------------------- /dashboard/src/styles/default-echarts-options/tooltip.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { AnyObject } from '~/types'; 3 | 4 | export const tooltip = { 5 | confine: true, 6 | appendToBody: true, 7 | }; 8 | 9 | export function getTooltip(option: AnyObject) { 10 | return _.defaultsDeep({}, option, tooltip); 11 | } 12 | -------------------------------------------------------------------------------- /website/src/utils/dashboard-json-type-def.ts: -------------------------------------------------------------------------------- 1 | export const DashboardJSONTypeDef = { 2 | type: 'object', 3 | properties: { 4 | views: { type: 'array' }, 5 | panels: { type: 'array' }, 6 | filters: { type: 'array' }, 7 | definition: { type: 'object' }, 8 | version: { type: 'string' }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/2.1.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * from before-versioning state to 2.0.0 3 | * @param schema 4 | * @returns schema with version set to 2.0.0 5 | */ 6 | export function main(schema: Record) { 7 | return { 8 | filters: [], 9 | ...schema, 10 | version: '2.1.0', 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/hooks/use-tab-state.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | export function useTabState(initialTab: string | null) { 4 | const [tab, setTab] = useState(initialTab); 5 | useEffect(() => { 6 | setTab(initialTab); 7 | }, [initialTab]); 8 | return { tab, setTab }; 9 | } 10 | -------------------------------------------------------------------------------- /tools/workspace-plugin/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"] 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/global-sql-snippets/global-sql-snippet.ts: -------------------------------------------------------------------------------- 1 | import { types } from 'mobx-state-tree'; 2 | 3 | export const GlobalSQLSnippetMeta = types.model({ 4 | id: types.string, 5 | content: types.string, 6 | create_time: types.string, 7 | update_time: types.string, 8 | is_preset: types.boolean, 9 | }); 10 | -------------------------------------------------------------------------------- /settings-form/src/global.d.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2 | type $TSFixMe = any; 3 | 4 | interface ISettingsFormConfig { 5 | basename: string; 6 | apiBaseURL: string; 7 | app_id?: string; 8 | app_secret?: string; 9 | monacoPath: string; 10 | } 11 | 12 | type TFunctionString = string; 13 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@typescript-eslint/recommended"], 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["@typescript-eslint"], 5 | "root": true, 6 | "overrides": [ 7 | { 8 | "files": "*.json", 9 | "parser": "jsonc-eslint-parser", 10 | "rules": {} 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/table/utils.ts: -------------------------------------------------------------------------------- 1 | import { ColumnAlignType } from './type'; 2 | 3 | type JustifyType = 'flex-start' | 'center' | 'flex-end'; 4 | 5 | export const AlignmentToFlexJustify: Record = { 6 | left: 'flex-start', 7 | center: 'center', 8 | right: 'flex-end', 9 | }; 10 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/index.ts: -------------------------------------------------------------------------------- 1 | export * from './mock-context'; 2 | export * from './panel'; 3 | export * from './query'; 4 | export * from './layout'; 5 | export * from './sql-snippet'; 6 | export * from './filter'; 7 | export * from './view'; 8 | export * from './types'; 9 | export * from './initial-content'; 10 | -------------------------------------------------------------------------------- /api/src/preset/custom_functions/config.example.js: -------------------------------------------------------------------------------- 1 | const example_custom_function1 = () => { 2 | console.log('this is an example custom function 1'); 3 | }; 4 | 5 | const example_custom_function2 = () => { 6 | console.log('this is an example custom function 2'); 7 | }; 8 | 9 | export { example_custom_function1, example_custom_function2 }; 10 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/filter/widgets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './checkbox'; 2 | export * from './date-range'; 3 | export * from './multi-select'; 4 | export * from './select'; 5 | export * from './text-input'; 6 | export * from './tree-select'; 7 | export * from './tree-single-select'; 8 | export * from './merico-date-range'; 9 | -------------------------------------------------------------------------------- /dashboard/src/utils/usage.ts: -------------------------------------------------------------------------------- 1 | export const UsageRegs = { 2 | sqlSnippet: /(?<=sql_snippets\.)([^\?}.]+)/gm, 3 | context: /(?<=context\.)([^\?}.]+)/gm, 4 | filter: /(?<=filters\.)([^\?}.]+)/gm, 5 | }; 6 | 7 | export type DependencyInfo = { 8 | type: 'sql_snippet' | 'context' | 'filter'; 9 | key: string; 10 | valid: boolean; 11 | }; 12 | -------------------------------------------------------------------------------- /website/tsconfig.cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src", "cypress"], 4 | "exclude": ["**/*.spec.ts"], 5 | "compilerOptions": { 6 | "types": ["cypress", "@testing-library/cypress", "chai"], 7 | "paths": { 8 | "@cy/*": ["./cypress/*"], 9 | "~/*": ["./src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-estimation-chart/option/series/utils.ts: -------------------------------------------------------------------------------- 1 | export function getIndicatorColorStyle(color: string) { 2 | const ret = [`background-color: ${color}`]; 3 | if (color === 'rgba(255, 255, 255, 1)') { 4 | ret.push('box-shadow: 0px 0px 1px 0px rgba(0,0,0,.5)'); 5 | } 6 | return ret.join(';'); 7 | } 8 | -------------------------------------------------------------------------------- /dashboard/src/contexts/render-content-model-context.ts: -------------------------------------------------------------------------------- 1 | import { IContentRenderModel } from '../dashboard-render'; 2 | import { useContentModelContext } from './content-model-context'; 3 | 4 | export const useRenderContentModelContext = () => useContentModelContext(); 5 | 6 | // use a separate file to allow tsc generate proper types 7 | -------------------------------------------------------------------------------- /dashboard/tsconfig.cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src", "cypress"], 4 | "exclude": ["**/*.spec.ts"], 5 | "compilerOptions": { 6 | "types": ["cypress", "@testing-library/cypress", "chai"], 7 | "paths": { 8 | "@cy/*": ["./cypress/*"], 9 | "~/*": ["./src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /shared/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shared", 3 | "$schema": "../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "shared/src", 5 | "projectType": "library", 6 | "targets": { 7 | "lint": { 8 | "executor": "@nx/eslint:lint", 9 | "outputs": ["{options.outputFile}"] 10 | } 11 | }, 12 | "tags": [] 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/horizontal-bar-chart/option/utils/types.ts: -------------------------------------------------------------------------------- 1 | export type TEchartsSeriesType = 'bar' | 'scatter'; 2 | 3 | export interface IEchartsSeriesItem { 4 | name: string; 5 | color?: string; 6 | type: TEchartsSeriesType; 7 | hide_in_legend: boolean; 8 | xAxisIndex: number; 9 | yAxisIndex: number; 10 | } 11 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/viz-merico-gqm/type.ts: -------------------------------------------------------------------------------- 1 | export interface IMericoGQMConf { 2 | expertSystemURL: string; 3 | path: string; 4 | goal: string; 5 | question: string; 6 | } 7 | 8 | export const DEFAULT_CONFIG: IMericoGQMConf = { 9 | expertSystemURL: '', 10 | path: '', 11 | goal: '', 12 | question: '', 13 | }; 14 | -------------------------------------------------------------------------------- /dashboard/src/utils/mantine.ts: -------------------------------------------------------------------------------- 1 | import { ComboboxItem } from '@mantine/core'; 2 | 3 | type SelectChangeHandler = (v: T, option: ComboboxItem) => void; 4 | export const getSelectChangeHandler = (func: SelectChangeHandler) => { 5 | return (v: string | null, option: ComboboxItem) => { 6 | v !== null && func(v as T, option); 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /tools/workspace-plugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | }, 6 | "files": [], 7 | "include": [], 8 | "references": [ 9 | { 10 | "path": "./tsconfig.lib.json" 11 | }, 12 | { 13 | "path": "./tsconfig.spec.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /dashboard/src/types/utils.ts: -------------------------------------------------------------------------------- 1 | export type AnyObject = Record; 2 | export type Ready = T & { [P in TK]-?: NonNullable }; 3 | 4 | export const typeAssert = { 5 | // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function 6 | shouldExtends(): void {}, 7 | }; 8 | -------------------------------------------------------------------------------- /dashboard/src/utils/shallow-to-js.ts: -------------------------------------------------------------------------------- 1 | import { toJS } from 'mobx'; 2 | import { cloneDeepWith } from 'lodash'; 3 | 4 | export const shallowToJS = (obj: T): T => { 5 | return cloneDeepWith(obj, (value, key) => { 6 | if (key === undefined) { 7 | return; 8 | } 9 | if (value) { 10 | return toJS(value); 11 | } 12 | }); 13 | }; 14 | -------------------------------------------------------------------------------- /website/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | interface ImportMetaEnv { 4 | readonly VITE_API_BASE_URL: string; 5 | readonly VITE_WEBSITE_BASE_URL: string; 6 | readonly VITE_WEBSITE_ROUTER_MIDDLEWARE_KEY: string; 7 | // more env variables... 8 | } 9 | 10 | interface ImportMeta { 11 | readonly env: ImportMetaEnv; 12 | } 13 | -------------------------------------------------------------------------------- /tools/workspace-plugin/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /api/src/api_models/cache.ts: -------------------------------------------------------------------------------- 1 | import { ApiModel, ApiModelProperty } from 'swagger-express-ts'; 2 | 3 | @ApiModel({ 4 | description: 'Cache clear request object', 5 | name: 'CacheClearRequest', 6 | }) 7 | export class CacheClearRequest { 8 | @ApiModelProperty({ 9 | description: 'Content id', 10 | required: true, 11 | }) 12 | content_id: string; 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/calendar-heatmap/option/legend.ts: -------------------------------------------------------------------------------- 1 | export function getLegend(oneYearMode: boolean, years: string[]) { 2 | return { 3 | show: !oneYearMode, 4 | selectedMode: 'single', 5 | top: 5, 6 | right: 5, 7 | data: years.map((name) => ({ 8 | name, 9 | icon: 'circle', 10 | })), 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/regression-chart/render/use-data-key.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | export const useDataKey = (initialKey: TDataKey) => { 4 | const [value, set] = useState(initialKey); 5 | return { 6 | value, 7 | set, 8 | }; 9 | }; 10 | 11 | export type UseDataKeyReturn = ReturnType; 12 | -------------------------------------------------------------------------------- /dashboard/src/interactions/interactions-viewer/node-with-interactions/index.css: -------------------------------------------------------------------------------- 1 | .react-flow__node-interaction { 2 | padding: 10px; 3 | border-radius: 3px; 4 | width: 150px; 5 | font-size: 12px; 6 | color: #222; 7 | text-align: center; 8 | border-width: 1px; 9 | border-style: solid; 10 | border-color: #1a192b; 11 | background-color: white; 12 | } 13 | -------------------------------------------------------------------------------- /api/tsconfig.dist.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "~/*": ["dist/*", "src/*"], 6 | "express": ["node_modules/express/lib/express"] 7 | } 8 | }, 9 | "exclude": ["node_modules", "build", "_build"], 10 | "rules": { 11 | "no-unused-expression": true, 12 | "no-floating-promises": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './about-function-utils'; 2 | export * from './custom-selector-item'; 3 | export * from './function-editor'; 4 | export * from './inline-function-input'; 5 | export * from './minimal-monaco-editor'; 6 | export * from './modal-function-editor'; 7 | export * from './rich-text-editor'; 8 | export * from './color-picker-popover'; 9 | -------------------------------------------------------------------------------- /dashboard/src/contexts/customize-screenshot-context.ts: -------------------------------------------------------------------------------- 1 | import { noop } from 'lodash'; 2 | import React from 'react'; 3 | 4 | export interface ICustomizeScreenshotContext { 5 | onScreenshot: (canvas: HTMLCanvasElement) => void; 6 | } 7 | 8 | export const CustomizeScreenshotContext = React.createContext({ 9 | onScreenshot: noop, 10 | }); 11 | -------------------------------------------------------------------------------- /settings-form/src/api-caller/index.ts: -------------------------------------------------------------------------------- 1 | import { account } from './account'; 2 | import { api_key } from './api-key'; 3 | import { datasource } from './datasource'; 4 | import { role } from './role'; 5 | import { sql_snippet } from './sql_snippet'; 6 | 7 | export const APICaller = { 8 | datasource, 9 | account, 10 | role, 11 | api_key, 12 | sql_snippet, 13 | }; 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "prettier.configPath": ".prettierrc.js", 3 | "prettier.prettierPath": "./node_modules/prettier", 4 | "editor.defaultFormatter": "esbenp.prettier-vscode", 5 | "[typescriptreact]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | }, 8 | "eslint.validate": [ 9 | "json" 10 | ], 11 | "git-blame.gitWebUrl": "" 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/series-unit/types.ts: -------------------------------------------------------------------------------- 1 | export interface SeriesUnitType { 2 | text: string; 3 | show_in_tooltip: boolean; 4 | show_in_legend: boolean; 5 | } 6 | 7 | export function getDefaultSeriesUnit(): SeriesUnitType { 8 | return { 9 | text: '', 10 | show_in_tooltip: false, 11 | show_in_legend: false, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/editor-components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viz-config-banner'; 2 | export * from './horizontal-align-selector'; 3 | export * from './vertical-align-selector'; 4 | export * from './color-interpolation-select'; 5 | export * from './color-mapping-editor'; 6 | export * from './color-type'; 7 | export * from './flex'; 8 | export * from './field-array-tabs'; 9 | -------------------------------------------------------------------------------- /settings-form/src/account/styles.ts: -------------------------------------------------------------------------------- 1 | import { MantineSize } from '@mantine/core'; 2 | 3 | export interface IStyles { 4 | size: MantineSize; 5 | spacing: MantineSize; 6 | button: { 7 | size: MantineSize; 8 | }; 9 | } 10 | 11 | export const defaultStyles: IStyles = { 12 | size: 'sm', 13 | spacing: 'md', 14 | button: { 15 | size: 'xs', 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /settings-form/src/api-key/styles.ts: -------------------------------------------------------------------------------- 1 | import { MantineSize } from '@mantine/core'; 2 | 3 | export interface IStyles { 4 | size: MantineSize; 5 | spacing: MantineSize; 6 | button: { 7 | size: MantineSize; 8 | }; 9 | } 10 | 11 | export const defaultStyles: IStyles = { 12 | size: 'sm', 13 | spacing: 'md', 14 | button: { 15 | size: 'xs', 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /settings-form/src/datasource/styles.ts: -------------------------------------------------------------------------------- 1 | import { MantineSize } from '@mantine/core'; 2 | 3 | export interface IStyles { 4 | size: MantineSize; 5 | spacing: MantineSize; 6 | button: { 7 | size: MantineSize; 8 | }; 9 | } 10 | 11 | export const defaultStyles: IStyles = { 12 | size: 'sm', 13 | spacing: 'md', 14 | button: { 15 | size: 'xs', 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /settings-form/src/sql_snippet/styles.ts: -------------------------------------------------------------------------------- 1 | import { MantineSize } from '@mantine/core'; 2 | 3 | export interface IStyles { 4 | size: MantineSize; 5 | spacing: MantineSize; 6 | button: { 7 | size: MantineSize; 8 | }; 9 | } 10 | 11 | export const defaultStyles: IStyles = { 12 | size: 'sm', 13 | spacing: 'md', 14 | button: { 15 | size: 'xs', 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /website/src/api-caller/dashboard.transform.ts: -------------------------------------------------------------------------------- 1 | import { IDashboard } from '@devtable/dashboard'; 2 | import { TDashboardMetaInfo } from './dashboard.typed'; 3 | 4 | export function normalizeDBDashboard({ id, name, group, content_id }: TDashboardMetaInfo): IDashboard { 5 | return { 6 | id, 7 | name, 8 | group, 9 | content_id, 10 | } as IDashboard; 11 | } 12 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-render-page/placeholder.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from '@mantine/core'; 2 | 3 | export function PleaseChooseADashboard() { 4 | return
Please choose a dashboard to proceed
; 5 | } 6 | 7 | export function DashboardIsEmpty() { 8 | return
This dashboard is empty
; 9 | } 10 | -------------------------------------------------------------------------------- /website/cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /api/src/models/dashboard_changelog.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column } from 'typeorm'; 2 | import { BaseModel } from './base'; 3 | 4 | @Entity() 5 | export default class DashboardChangelog extends BaseModel { 6 | @Column('uuid', { 7 | name: 'dashboard_id', 8 | comment: '报表ID', 9 | }) 10 | dashboard_id: string; 11 | 12 | @Column('text', { name: 'diff' }) 13 | diff: string; 14 | } 15 | -------------------------------------------------------------------------------- /api/tests/integration/00_seed.test.ts: -------------------------------------------------------------------------------- 1 | import { seed } from './seed/seed'; 2 | import { connectionHook } from './jest.util'; 3 | import { RoleService } from '~/services/role.service'; 4 | 5 | describe('System Init', () => { 6 | connectionHook(); 7 | 8 | it('seed', async () => { 9 | await seed(); 10 | await RoleService.ensureFixedRolePermissions(); 11 | }, 120000); 12 | }); 13 | -------------------------------------------------------------------------------- /dashboard/cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | stats.html 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-settings/filter-settings.css: -------------------------------------------------------------------------------- 1 | .filter-settings-tabs { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | .filter-settings-tabs .mantine-Tabs-panel { 6 | height: calc(100% - 25px); 7 | } 8 | .filter-settings-tabs .mantine-Tabs-tabsListWrapper { 9 | flex: 0; 10 | } 11 | .filter-settings-tabs .mantine-Tabs-body { 12 | flex: 1; 13 | overflow: auto; 14 | } 15 | -------------------------------------------------------------------------------- /tools/workspace-plugin/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'tools/workspace-plugin', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 7 | }, 8 | moduleFileExtensions: ['ts', 'js', 'html'], 9 | coverageDirectory: '../../coverage/tools/workspace-plugin', 10 | }; 11 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/common/types.ts: -------------------------------------------------------------------------------- 1 | export interface ITreeDataQueryOption { 2 | label: string; 3 | value: string; 4 | parent_value: string; 5 | description?: string; 6 | } 7 | 8 | export interface ITreeDataRenderItem { 9 | label: string | JSX.Element; 10 | value: string; 11 | parent_value: string; 12 | description?: string; 13 | filterBasis: string; 14 | } 15 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/colors/sequential-color.ts: -------------------------------------------------------------------------------- 1 | import chroma from 'chroma-js'; 2 | import { IColorInterpolation } from '~/types/plugin'; 3 | 4 | export const createSequentialColorPalette = (colors: string[]): IColorInterpolation['getColor'] => { 5 | const fn = chroma.bezier(colors); 6 | return function (value: number): string { 7 | return fn(value / 100).hex(); 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /settings-form/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | stats.html 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /shared/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /website/src/api-caller/status.ts: -------------------------------------------------------------------------------- 1 | import { get } from './request'; 2 | import { VersionResp } from './status.typs'; 3 | 4 | export const StatusAPI = { 5 | /** 6 | * get api version 7 | */ 8 | version: async (signal?: AbortSignal): Promise => { 9 | const res = await get(signal)('/version', {}); 10 | return res; 11 | }, 12 | }; 13 | 14 | export const status = StatusAPI; 15 | -------------------------------------------------------------------------------- /api/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import fs from 'fs-extra'; 3 | 4 | export const sqlRewriter = ( 5 | fs.existsSync(path.resolve(__dirname, './sqlrewriter.js')) 6 | ? require(path.resolve(__dirname, './sqlrewriter.js')) 7 | : { 8 | default: async (sql, env) => { 9 | return { 10 | sql, 11 | }; 12 | }, 13 | } 14 | ).default; 15 | -------------------------------------------------------------------------------- /api/test.sequencer.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const Sequencer = require('@jest/test-sequencer').default; 3 | 4 | class CustomSequencer extends Sequencer { 5 | sort(tests) { 6 | const copyTests = Array.from(tests); 7 | return copyTests.sort((testA, testB) => (testA.path > testB.path ? 1 : -1)); 8 | } 9 | } 10 | 11 | module.exports = CustomSequencer; 12 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/stats/type.ts: -------------------------------------------------------------------------------- 1 | import { VerticalAlign } from '../../editor-components'; 2 | 3 | export interface IVizStatsConf { 4 | content: string; 5 | vertical_align: VerticalAlign; 6 | } 7 | export const DEFAULT_CONFIG: IVizStatsConf = { 8 | content: 'Use double curly brackets to wrap js code: {{ new Date().getTime() }}', 9 | vertical_align: 'center', 10 | }; 11 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-render-page/index.tsx: -------------------------------------------------------------------------------- 1 | import { useParams } from 'react-router-dom'; 2 | import { DashboardPageContent } from './content'; 3 | import { PleaseChooseADashboard } from './placeholder'; 4 | 5 | export function DashboardRenderPage() { 6 | const { id } = useParams(); 7 | if (!id) { 8 | return ; 9 | } 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/hooks/use-row-data-map.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { useMemo } from 'react'; 3 | import { parseDataKey } from '~/utils'; 4 | 5 | export function useRowDataMap(data: TPanelData, dataKey: TDataKey) { 6 | return useMemo(() => { 7 | const { queryID, columnKey } = parseDataKey(dataKey); 8 | return _.keyBy(data[queryID], columnKey); 9 | }, [data, dataKey]); 10 | } 11 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/view-query-vars/index.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from '@mantine/core'; 2 | import { observer } from 'mobx-react-lite'; 3 | import { QueryVariablesGuide } from './query-variables-guide'; 4 | 5 | export const ViewQueryVars = observer(() => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }); 12 | -------------------------------------------------------------------------------- /dashboard/src/components/widgets/function-editor/types.ts: -------------------------------------------------------------------------------- 1 | // [ startLine, startColumn, endLine, endColumn ] 2 | export type MonacoEditorRestrictionRange = [number, number, number, number]; 3 | 4 | export type MonacoEditorRestriction = { 5 | range: MonacoEditorRestrictionRange; 6 | label?: string; 7 | allowMultiline?: boolean; 8 | validate?: (currentlyTypedValue: any, newRange: any, info: any) => boolean; 9 | }; 10 | -------------------------------------------------------------------------------- /api/src/models/dashboard_content_changelog.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column } from 'typeorm'; 2 | import { BaseModel } from './base'; 3 | 4 | @Entity() 5 | export default class DashboardContentChangelog extends BaseModel { 6 | @Column('uuid', { 7 | name: 'dashboard_content_id', 8 | comment: '报表内容ID', 9 | }) 10 | dashboard_content_id: string; 11 | 12 | @Column('text', { name: 'diff' }) 13 | diff: string; 14 | } 15 | -------------------------------------------------------------------------------- /dashboard/src/contexts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dashboard-context'; 2 | export * from './dashboard-theme-context'; 3 | export * from './content-model-context'; 4 | export * from './layout-state-context'; 5 | export * from './panel-context'; 6 | export * from './full-screen-panel-context'; 7 | export * from './dates-provider'; 8 | export * from './render-content-model-context'; 9 | export * from './additional-panel-menu-items'; 10 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/db-explorer-modal/db-explorer/full-space-loading.tsx: -------------------------------------------------------------------------------- 1 | import { Box, LoadingOverlay } from '@mantine/core'; 2 | 3 | export const FullSpaceLoading = ({ visible }: { visible: boolean }) => { 4 | return ( 5 | 6 | 7 | 8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /dashboard/src/i18n/i18next-context.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useEffect } from 'react'; 2 | import { I18nextProvider } from 'react-i18next'; 3 | import i18n from './i18n'; 4 | 5 | export function I18nextContextProvider({ lang, children }: { lang: string; children: ReactNode }) { 6 | useEffect(() => { 7 | i18n.changeLanguage(lang); 8 | }, [lang]); 9 | 10 | return {children}; 11 | } 12 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/hooks/use-channel-event.ts: -------------------------------------------------------------------------------- 1 | import { ListenerFn, EventEmitter2 } from 'eventemitter2'; 2 | import { useEffect } from 'react'; 3 | 4 | export function useChannelEvent(channel: EventEmitter2, event: string, listener: ListenerFn) { 5 | useEffect(() => { 6 | channel.on(event, listener); 7 | return () => { 8 | channel.off(event, listener); 9 | }; 10 | }, [channel, event, listener]); 11 | } 12 | -------------------------------------------------------------------------------- /settings-form/src/i18n/i18next-context.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useEffect } from 'react'; 2 | import { I18nextProvider } from 'react-i18next'; 3 | import i18n from './i18n'; 4 | 5 | export function I18nextContextProvider({ lang, children }: { lang: string; children: ReactNode }) { 6 | useEffect(() => { 7 | i18n.changeLanguage(lang); 8 | }, [lang]); 9 | 10 | return {children}; 11 | } 12 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/4.5.1.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * migrate to v4.5.1 3 | * Changes: add name to view 4 | * @param schema 5 | * @returns schema with version set to 4.5.1 6 | */ 7 | export function main({ filters, views, ...rest }: Record) { 8 | return { 9 | filters, 10 | views: views.map((v) => ({ 11 | ...v, 12 | name: v.id, 13 | })), 14 | ...rest, 15 | version: '4.5.1', 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /dashboard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | @devtable/dashboard 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/editor-components/field-array-tabs/types.ts: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import { ArrayPath, FieldArrayWithId, FieldValues, Path, PathValue } from 'react-hook-form'; 3 | 4 | export type ControlledField = FieldArrayWithId, 'id'> & PathValue>; 5 | export type FieldArrayTabsChildren = ({ field, index }: { field: FieldItem; index: number }) => ReactNode; 6 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-panel-groups/type.ts: -------------------------------------------------------------------------------- 1 | export type MericoPanelGroupItem = { 2 | name: string; 3 | comment: string; 4 | panelIDs: string[]; 5 | }; 6 | 7 | export type VizMericoPanelGroupsConf = { 8 | groups: MericoPanelGroupItem[]; 9 | }; 10 | 11 | export const getDefaultConfig = () => { 12 | const config: VizMericoPanelGroupsConf = { 13 | groups: [], 14 | }; 15 | return config; 16 | }; 17 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-view/edit-view-form/config-fields/modal/modal-title-editor/types.ts: -------------------------------------------------------------------------------- 1 | export interface ICustomModalTitle { 2 | enabled: boolean; 3 | func_content: string; 4 | } 5 | 6 | export const DEFAULT_CUSTOM_MODAL_TITLE = { 7 | enabled: false, 8 | func_content: ['function text({ filters, context}) {', ' // your code goes here', ' return "text"', '}'].join( 9 | '\n', 10 | ), 11 | }; 12 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-tree/common/query-data-to-tree.ts: -------------------------------------------------------------------------------- 1 | import { arrayToTree } from 'performant-array-to-tree'; 2 | import { ITreeDataRenderItem } from './types'; 3 | 4 | export function queryDataToTree(queryData: ITreeDataRenderItem[]) { 5 | const tree = arrayToTree(queryData, { 6 | id: 'value', 7 | parentId: 'parent_value', 8 | childrenField: 'children', 9 | dataField: null, 10 | }); 11 | return tree; 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/boxplot-chart/option/series/custom/utils.ts: -------------------------------------------------------------------------------- 1 | import { CustomSeriesRenderItemAPI } from 'echarts'; 2 | 3 | export const BOX_WIDTH = [10, 40]; 4 | 5 | export function getLayout(api: CustomSeriesRenderItemAPI) { 6 | // Leftside for scatter 7 | // Rightside for box 8 | return api.barLayout({ 9 | barMinWidth: BOX_WIDTH[0], 10 | barMaxWidth: BOX_WIDTH[1], 11 | count: 2, 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/viz-dashboard-state/render/item/context-state.tsx: -------------------------------------------------------------------------------- 1 | import { TDashboardStateItem } from '~/model'; 2 | import { ItemBadge } from './item-badge'; 3 | 4 | export const ContextState = ({ item }: { item: TDashboardStateItem }) => { 5 | if (item.type !== 'context') { 6 | return null; 7 | } 8 | 9 | return ; 10 | }; 11 | -------------------------------------------------------------------------------- /settings-form/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | @devtable/settings-form 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | @devtable 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /dashboard/src/contexts/dashboard-action-context.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | 4 | export interface IDashboardActionContext { 5 | viewPanelInFullScreen: (id: string) => void; 6 | inFullScreen: boolean; 7 | } 8 | 9 | const initialContext = { 10 | viewPanelInFullScreen: _.noop, 11 | inFullScreen: false, 12 | }; 13 | 14 | export const DashboardActionContext = React.createContext(initialContext); 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 15.58.9 (2025-12-09) 2 | 3 | ### 🚀 Features 4 | 5 | - **rich-text-editor:** Add line height control ([e1ab982d7](https://github.com/merico-dev/table/commit/e1ab982d7)) 6 | 7 | ### ❤️ Thank You 8 | 9 | - ZeekoZhu 10 | 11 | ## v15.58.9 (2025-12-09) 12 | 13 | ### 🚀 Features 14 | 15 | - **rich-text-editor:** Add line height control ([e1ab982d7](https://github.com/merico-dev/table/commit/e1ab982d7)) 16 | 17 | ### ❤️ Thank You 18 | 19 | - ZeekoZhu -------------------------------------------------------------------------------- /api/tests/e2e/00_init_db.test.ts: -------------------------------------------------------------------------------- 1 | import { connectionHook } from './jest.util'; 2 | import { dashboardDataSource } from '~/data_sources/dashboard'; 3 | import { RoleService } from '~/services/role.service'; 4 | 5 | describe('System Init', () => { 6 | connectionHook(); 7 | 8 | it('migrate', async () => { 9 | await dashboardDataSource.runMigrations({ transaction: 'none' }); 10 | await RoleService.ensureFixedRolePermissions(); 11 | }, 120000); 12 | }); 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/x-axis-label-formatter/types.ts: -------------------------------------------------------------------------------- 1 | export interface IXAxisLabelFormatter { 2 | enabled: boolean; 3 | func_content: string; 4 | } 5 | 6 | export function getDefaultXAxisLabelFormatter(): IXAxisLabelFormatter { 7 | return { 8 | enabled: false, 9 | func_content: ['function label(value, index) {', ' // your code goes here', ' // return value', '}'].join( 10 | '\n', 11 | ), 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-manager/types.ts: -------------------------------------------------------------------------------- 1 | import { IDashboardPanel } from '~/types'; 2 | import { VizComponent, VizInstance } from '~/types/plugin'; 3 | 4 | export type IPanelInfo = Omit; 5 | 6 | export interface IVizManager { 7 | readonly availableVizList: VizComponent[]; 8 | 9 | resolveComponent(type: string): VizComponent; 10 | 11 | getOrCreateInstance(panel: IPanelInfo): VizInstance; 12 | } 13 | -------------------------------------------------------------------------------- /website/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 4 | 'Droid Sans', 'Helvetica Neue', sans-serif; 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | } 8 | 9 | * { 10 | box-sizing: border-box; 11 | } 12 | 13 | code { 14 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; 15 | } 16 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/4.5.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * migrate to v4.5.0 3 | * @param schema 4 | * @returns schema with version set to 4.5.0 5 | */ 6 | export function main({ filters, panels, ...rest }: Record) { 7 | return { 8 | filters, 9 | views: [ 10 | { 11 | id: 'Main', 12 | type: 'div', 13 | config: {}, 14 | panels, 15 | }, 16 | ], 17 | ...rest, 18 | version: '4.5.0', 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/4.5.2.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * migrate to v4.5.2 3 | * Changes: add visibleInViewsIDs to filter 4 | * @param schema 5 | * @returns schema with version set to 4.5.2 6 | */ 7 | export function main({ filters, views, ...rest }: Record) { 8 | return { 9 | filters: filters.map((f) => ({ 10 | ...f, 11 | visibleInViewsIDs: 'Main', 12 | })), 13 | views, 14 | ...rest, 15 | version: '4.5.2', 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/4.5.3.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * migrate to v4.5.3 3 | * Changes: fix mistyped visibleInViewsIDs 4 | * @param schema 5 | * @returns schema with version set to 4.5.3 6 | */ 7 | export function main({ filters, views, ...rest }: Record) { 8 | return { 9 | filters: filters.map((f) => ({ 10 | ...f, 11 | visibleInViewsIDs: ['Main'], 12 | })), 13 | views, 14 | ...rest, 15 | version: '4.5.3', 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/scatter-chart/option/dataset.ts: -------------------------------------------------------------------------------- 1 | import { parseDataKey } from '~/utils'; 2 | import { IScatterChartConf } from '../type'; 3 | 4 | export function getDataset(conf: IScatterChartConf, data: TPanelData) { 5 | if (!conf.x_axis.data_key) { 6 | return []; 7 | } 8 | const x = parseDataKey(conf.x_axis.data_key); 9 | const source = data[x.queryID]; 10 | return [ 11 | { 12 | source, 13 | }, 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-editor-page/more-dashboard-info/whos-editing/types.ts: -------------------------------------------------------------------------------- 1 | export type PresenceType = { 2 | [key: string]: { 3 | // [id:type]: { type, name, count } 4 | type: string; 5 | name: string; 6 | count: number; 7 | }; 8 | }; 9 | 10 | export type PresenceDataItemType = 'APIKEY' | 'ACCOUNT'; 11 | 12 | export type PresenceDataItem = { 13 | id: string; 14 | type: PresenceDataItemType; 15 | name: string; 16 | count: number; 17 | }; 18 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/6.7.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Changes: add name to query, init name with id 3 | * @param schema 4 | * @returns new schema 5 | */ 6 | export function main({ definition, ...rest }: Record) { 7 | return { 8 | definition: { 9 | ...definition, 10 | queries: definition.queries.map((q) => ({ 11 | ...q, 12 | name: q.id, 13 | })), 14 | }, 15 | ...rest, 16 | version: '6.7.0', 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/radar-chart/option/formatter.ts: -------------------------------------------------------------------------------- 1 | import { TNumberFormat, formatNumber } from '~/utils'; 2 | 3 | export function getFormatter(formatter: TNumberFormat) { 4 | if (!formatter) { 5 | return (value: number) => value; 6 | } 7 | return (value: number) => { 8 | try { 9 | return formatNumber(value, formatter); 10 | } catch (error) { 11 | console.error(error); 12 | return value; 13 | } 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /tools/workspace-plugin/src/executors/is-published/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "version": 2, 4 | "title": "IsPublished executor", 5 | "description": "Check if a package version is published on npm and fail if it is", 6 | "type": "object", 7 | "properties": { 8 | "packageJson": { 9 | "type": "string", 10 | "description": "Path to the package.json file" 11 | } 12 | }, 13 | "required": ["packageJson"] 14 | } 15 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/heatmap/option/grid.ts: -------------------------------------------------------------------------------- 1 | import { IHeatmapConf } from '../type'; 2 | 3 | export function getGrid(conf: IHeatmapConf) { 4 | let bottom = 0; 5 | if (conf.x_axis.name) { 6 | bottom += 20; 7 | } 8 | 9 | return { 10 | show: true, 11 | top: 45, 12 | left: 5, 13 | right: 5, 14 | bottom, 15 | containLabel: true, 16 | borderColor: 'none', 17 | backgroundColor: '#E7E7E9', 18 | z: 1, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-stats/migrators/v2.ts: -------------------------------------------------------------------------------- 1 | import { TMericoStatsConf, TMericoStatsMetric } from '../type'; 2 | 3 | export function v2(legacyConf: any): TMericoStatsConf { 4 | const { metrics, ...rest } = legacyConf; 5 | return { 6 | ...rest, 7 | metrics: metrics.map((m: TMericoStatsMetric) => ({ 8 | ...m, 9 | postfix: m.postfix ?? { 10 | type: 'text', 11 | value: '', 12 | }, 13 | })), 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/pie-chart/option/index.ts: -------------------------------------------------------------------------------- 1 | import { IPieChartConf } from '../type'; 2 | import { getDataset } from './dataset'; 3 | import { getSeries } from './series'; 4 | import { getTooltip } from './tooltip'; 5 | 6 | export function getOption(conf: IPieChartConf, data: TPanelData, width: number) { 7 | return { 8 | dataset: getDataset(conf, data), 9 | tooltip: getTooltip(conf), 10 | series: getSeries(conf, data, width), 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/contexts/dashboard-theme-context.ts: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | import { RenderSearchButtonProps } from '..'; 3 | 4 | const DashboardThemeContext = React.createContext<{ 5 | renderSearchButton?: (props: RenderSearchButtonProps) => ReactNode; 6 | }>({}); 7 | 8 | export const DashboardThemeContextProvider = DashboardThemeContext.Provider; 9 | 10 | export function useDashboardThemeContext() { 11 | return React.useContext(DashboardThemeContext); 12 | } 13 | -------------------------------------------------------------------------------- /tools/workspace-plugin/src/generators/viz-component/files/viz-__dashedName__.tsx__tmpl__: -------------------------------------------------------------------------------- 1 | import { VizViewProps } from '~/types/plugin'; 2 | import { useStorageData } from '~/components/plugins'; 3 | import { DEFAULT_CONFIG, I<%= pascalcase(name) %>Conf } from './type'; 4 | 5 | export function Viz<%= pascalcase(name) %>({ context }: VizViewProps) { 6 | const { value: conf } = useStorageDataConf>(context.instanceData, 'config'); 7 | return
Hello World
; 8 | } 9 | -------------------------------------------------------------------------------- /website/src/pages/account-page/index.tsx: -------------------------------------------------------------------------------- 1 | import { AccountList } from '@devtable/settings-form'; 2 | import { Box } from '@mantine/core'; 3 | import { SettingsFormConfig } from '../../utils/config'; 4 | import { useLanguageContext } from '../../contexts'; 5 | 6 | export function AccountsPage() { 7 | const { lang } = useLanguageContext(); 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /website/src/pages/api-key-page/index.tsx: -------------------------------------------------------------------------------- 1 | import { APIKeyList } from '@devtable/settings-form'; 2 | import { Box } from '@mantine/core'; 3 | import { SettingsFormConfig } from '../../utils/config'; 4 | import { useLanguageContext } from '../../contexts'; 5 | 6 | export function APIKeyPage() { 7 | const { lang } = useLanguageContext(); 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-heatmap/render/option/grid.ts: -------------------------------------------------------------------------------- 1 | import { TMericoHeatmapConf } from '../../type'; 2 | 3 | export function getGrid(conf: TMericoHeatmapConf) { 4 | let bottom = 0; 5 | if (conf.x_axis.name) { 6 | bottom += 20; 7 | } 8 | 9 | return { 10 | top: 45, 11 | left: 5, 12 | right: 5, 13 | bottom, 14 | containLabel: true, 15 | borderColor: 'none', 16 | backgroundColor: '#E7E7E9', 17 | z: 1, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/viz-merico-gqm/translation.ts: -------------------------------------------------------------------------------- 1 | import { TranslationPatch } from '~/types/plugin'; 2 | 3 | const en = { 4 | merico_gqm: { 5 | viz_name: 'Merico GQM', 6 | }, 7 | }; 8 | 9 | const zh = { 10 | merico_gqm: { 11 | viz_name: '思码逸GQM组件', 12 | }, 13 | }; 14 | 15 | export const translation: TranslationPatch = [ 16 | { 17 | lang: 'en', 18 | resources: en, 19 | }, 20 | { 21 | lang: 'zh', 22 | resources: zh, 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /dashboard/src/utils/color-feed.ts: -------------------------------------------------------------------------------- 1 | import { ChartTheme } from '~/styles/register-themes'; 2 | export function* getColorFeed(paletteKey: keyof typeof ChartTheme.graphics): Generator { 3 | const theme = ChartTheme.graphics[paletteKey]; 4 | if (!theme) { 5 | throw new Error('Invalid palette key provided'); 6 | } 7 | 8 | const palette = Object.values(theme); 9 | 10 | let i = 0; 11 | while (true) { 12 | yield palette[i % palette.length]; 13 | i++; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dashboard/src/utils/color-mapping.ts: -------------------------------------------------------------------------------- 1 | import { interpolate } from 'popmotion'; 2 | 3 | export interface InterpolateColorOption { 4 | valueRange: number[]; 5 | colorRange: string[]; 6 | } 7 | export class InterpolateColor { 8 | mapper: (v: number) => string; 9 | 10 | constructor({ valueRange, colorRange }: InterpolateColorOption) { 11 | this.mapper = interpolate(valueRange, colorRange); 12 | } 13 | 14 | getColor(value: number) { 15 | return this.mapper(value); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /website/src/components/account-type-icon.tsx: -------------------------------------------------------------------------------- 1 | import { ActionIcon } from '@mantine/core'; 2 | import { IconApi, IconUser } from '@tabler/icons-react'; 3 | 4 | export const AccountTypeIcon = ({ type }: { type: 'ACCOUNT' | 'APIKEY' | null }) => { 5 | if (!type) { 6 | return null; 7 | } 8 | return ( 9 | 10 | {type === 'APIKEY' ? : } 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/use-update-filter-preview-values.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { useEditContentModelContext } from '~/contexts'; 3 | 4 | export function useUpdateFilterPreviewValues(formValue: any) { 5 | const content = useEditContentModelContext(); 6 | 7 | useEffect(() => { 8 | // this form is not a controlled component, 9 | // so we need to manually update the model 10 | content.filters.updatePreviewValues?.(formValue); 11 | }, [formValue]); 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/bar-3d-chart/translation.ts: -------------------------------------------------------------------------------- 1 | import { TranslationPatch } from '~/types/plugin'; 2 | 3 | const en = { 4 | bar_chart_3d: { 5 | viz_name: 'Bar Chart(3D)', 6 | }, 7 | }; 8 | 9 | const zh = { 10 | bar_chart_3d: { 11 | viz_name: '柱图(3D)', 12 | }, 13 | }; 14 | 15 | export const translation: TranslationPatch = [ 16 | { 17 | lang: 'en', 18 | resources: en, 19 | }, 20 | { 21 | lang: 'zh', 22 | resources: zh, 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /website/src/frames/admin/navbar/index.tsx: -------------------------------------------------------------------------------- 1 | import { AppShell } from '@mantine/core'; 2 | import { AdminPageLinks } from './admin-page-links'; 3 | import { AdminSystemNavActions } from './admin-system-nav-actions'; 4 | 5 | export function AdminNavbar() { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /website/src/frames/socket-client-frame/types.ts: -------------------------------------------------------------------------------- 1 | // FIXME(leto): import from api/src/utils/websocket.ts 2 | export enum SERVER_CHANNELS { 3 | DASHBOARD = 'DASHBOARD', 4 | DASHBOARD_EDIT_PRESENCE = 'DASHBOARD_EDIT_PRESENCE', 5 | } 6 | 7 | // FIXME(leto): import from api/src/utils/websocket.ts 8 | export enum CLIENT_CHANNELS { 9 | DASHBOARD_GET_EDIT_PRESENCE = 'DASHBOARD_GET_EDIT_PRESENCE', 10 | DASHBOARD_START_EDIT = 'DASHBOARD_START_EDIT', 11 | DASHBOARD_END_EDIT = 'DASHBOARD_END_EDIT', 12 | } 13 | -------------------------------------------------------------------------------- /website/src/pages/data-source-page/index.tsx: -------------------------------------------------------------------------------- 1 | import { DataSourceList } from '@devtable/settings-form'; 2 | import { Box } from '@mantine/core'; 3 | import { SettingsFormConfig } from '../../utils/config'; 4 | import { useLanguageContext } from '../../contexts'; 5 | 6 | export function DataSourcePage() { 7 | const { lang } = useLanguageContext(); 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /website/src/pages/sql-snippet-page/index.tsx: -------------------------------------------------------------------------------- 1 | import { SQLSnippetList } from '@devtable/settings-form'; 2 | import { Box } from '@mantine/core'; 3 | import { SettingsFormConfig } from '../../utils/config'; 4 | import { useLanguageContext } from '../../contexts'; 5 | 6 | export function SQLSnippetPage() { 7 | const { lang } = useLanguageContext(); 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/5.9.1.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Changes: add _name to filter.config to avoid incorrect type inference 3 | * @param schema 4 | * @returns new schema 5 | */ 6 | export function main({ filters, views, ...rest }: Record) { 7 | return { 8 | filters: filters.map((f) => ({ 9 | ...f, 10 | config: { 11 | _name: f.type, 12 | ...f.config, 13 | }, 14 | })), 15 | views, 16 | ...rest, 17 | version: '5.9.1', 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/boxplot-chart/option/grid.ts: -------------------------------------------------------------------------------- 1 | import { IBoxplotChartConf } from '../type'; 2 | 3 | export function getGrid(conf: IBoxplotChartConf) { 4 | const grid = { 5 | top: 35, 6 | left: 20, 7 | right: 15, 8 | bottom: 25, 9 | containLabel: true, 10 | }; 11 | 12 | if (conf.legend.orient === 'vertical') { 13 | grid.right = 80; 14 | } 15 | if (conf.dataZoom.x_axis_slider) { 16 | grid.top = 50; 17 | } 18 | 19 | return grid; 20 | } 21 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-estimation-chart/toolbox/index.tsx: -------------------------------------------------------------------------------- 1 | import { Group } from '@mantine/core'; 2 | import { BasisMetricSelector, IBasisMetricSelector } from './basis-metric-selector'; 3 | import { MetricsDescription } from './metric-description'; 4 | 5 | export function Toolbox(props: IBasisMetricSelector) { 6 | return ( 7 | 8 | 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /api/src/data_sources/migrations/1660005273691-add-extension-citext.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class addExtensionCitext1660005273691 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS citext`); 6 | } 7 | 8 | public async down(queryRunner: QueryRunner): Promise { 9 | await queryRunner.query(`DROP EXTENSION IF EXISTS citext`); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /api/src/models/role.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; 2 | 3 | @Entity() 4 | export default class Role { 5 | @PrimaryGeneratedColumn('identity', { 6 | name: 'id', 7 | comment: '实体id', 8 | }) 9 | id: string; 10 | 11 | @Column('text', { 12 | nullable: false, 13 | name: 'description', 14 | }) 15 | description: string; 16 | 17 | @Column('jsonb', { 18 | nullable: false, 19 | name: 'permissions', 20 | }) 21 | permissions: string[]; 22 | } 23 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/heatmap/editors/tooltip/index.tsx: -------------------------------------------------------------------------------- 1 | import { Control, UseFormWatch } from 'react-hook-form'; 2 | import { IHeatmapConf } from '../../type'; 3 | import { TooltipMetricsField } from './metrics'; 4 | 5 | interface ITooltipField { 6 | control: Control; 7 | watch: UseFormWatch; 8 | } 9 | export function TooltipField({ control, watch }: ITooltipField) { 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /settings-form/src/api-caller/account.typed.ts: -------------------------------------------------------------------------------- 1 | export interface IAccount { 2 | id: string; 3 | name: string; 4 | email: string; 5 | role_id: string; 6 | create_time: string; 7 | update_time: string; 8 | } 9 | 10 | export interface IEditAccountPayload { 11 | id: string; 12 | name: string; 13 | email: string; 14 | role_id: string; 15 | reset_password: boolean; 16 | new_password?: string; 17 | } 18 | 19 | export interface ILoginResp { 20 | account: IAccount; 21 | token: string; 22 | } 23 | -------------------------------------------------------------------------------- /shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true 11 | }, 12 | "files": [], 13 | "include": [], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /api/src/middleware/ensureAuthEnabled.ts: -------------------------------------------------------------------------------- 1 | import * as express from 'express'; 2 | import { AUTH_ENABLED } from '../utils/constants'; 3 | import { ApiError, AUTH_NOT_ENABLED } from '../utils/errors'; 4 | import { translate } from '../utils/i18n'; 5 | 6 | export default function ensureAuthEnabled(req: express.Request, res: express.Response, next: express.NextFunction) { 7 | if (!AUTH_ENABLED) { 8 | throw new ApiError(AUTH_NOT_ENABLED, { message: translate('AUTH_NOT_ENABLED', req.locale) }); 9 | } 10 | next(); 11 | } 12 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/message-channels.spec.ts: -------------------------------------------------------------------------------- 1 | import { IMessageChannels } from '~/types/plugin'; 2 | import { MessageChannels } from './message-channels'; 3 | 4 | describe('message channels', () => { 5 | let channels: IMessageChannels; 6 | beforeEach(() => { 7 | channels = new MessageChannels(); 8 | }); 9 | test('can get channel', () => { 10 | const alice = channels.getChannel('alice'); 11 | const alice2 = channels.getChannel('alice'); 12 | expect(alice).toBe(alice2); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /website/src/components/load-favicon.tsx: -------------------------------------------------------------------------------- 1 | import { useRequest } from 'ahooks'; 2 | import { Helmet } from 'react-helmet-async'; 3 | import { ConfigAPI } from '../api-caller/config'; 4 | 5 | export const LoadFavicon = () => { 6 | const { data } = useRequest(ConfigAPI.getWebsiteSettings); 7 | if (!data?.WEBSITE_FAVICON_URL) { 8 | return null; 9 | } 10 | return ( 11 | 12 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/funnel/option/index.ts: -------------------------------------------------------------------------------- 1 | import { AnyObject } from '~/types'; 2 | import { IFunnelConf } from '../type'; 3 | import { getSeries } from './series'; 4 | import { getTooltip } from './tooltip'; 5 | 6 | export function getOption(conf: IFunnelConf, data: TPanelData) { 7 | return { 8 | grid: { 9 | top: 0, 10 | left: 0, 11 | right: 0, 12 | bottom: 0, 13 | }, 14 | tooltip: getTooltip(conf, data), 15 | series: getSeries(conf, data), 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/radar-chart/option/series.label.ts: -------------------------------------------------------------------------------- 1 | import { IRadarChartConf } from '../type'; 2 | import { getFormatter } from './formatter'; 3 | 4 | export function getSeriesLabel(conf: IRadarChartConf) { 5 | return { 6 | show: conf.label.enabled, 7 | formatter: ({ dimensionIndex, value }: { dimensionIndex: number; value: number }) => { 8 | const formatter = getFormatter(conf.dimensions[dimensionIndex].formatter); 9 | return formatter(value); 10 | }, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /api/jest-u.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const defaultConfig = require('./jest.config'); 3 | 4 | module.exports = { 5 | ...defaultConfig, 6 | coverageDirectory: './coverage-u/', 7 | globalSetup: '/tests/unit/jest.setup.ts', 8 | testRegex: '(/tests/unit/.*(test|spec|unit))\\.(jsx?|tsx?)$', 9 | roots: ['/tests/unit/'], 10 | maxWorkers: 1, 11 | globals: { 12 | 'ts-jest': { 13 | tsconfig: 'tests/unit/tsconfig.json', 14 | }, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /dashboard/src/styles/default-echarts-options/y-axis.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { AnyObject } from '~/types'; 3 | 4 | export const yAxis = { 5 | axisTick: { 6 | show: false, 7 | }, 8 | axisLine: { 9 | show: false, 10 | lineStyle: { 11 | width: 3, 12 | }, 13 | }, 14 | splitLine: { 15 | show: true, 16 | lineStyle: { 17 | type: 'dashed', 18 | }, 19 | }, 20 | }; 21 | 22 | export function getYAxis(option: AnyObject) { 23 | return _.defaultsDeep({}, option, yAxis); 24 | } 25 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-heatmap/editors/tooltip/index.tsx: -------------------------------------------------------------------------------- 1 | import { Control, UseFormWatch } from 'react-hook-form'; 2 | import { TMericoHeatmapConf } from '../../type'; 3 | import { TooltipMetricsField } from './metrics'; 4 | 5 | interface ITooltipField { 6 | control: Control; 7 | watch: UseFormWatch; 8 | } 9 | export function TooltipField({ control, watch }: ITooltipField) { 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-editor-page/more-dashboard-info/dashboard-changlog-modal/changelog-modal-trigger.tsx: -------------------------------------------------------------------------------- 1 | import { Menu } from '@mantine/core'; 2 | import { IconHistory } from '@tabler/icons-react'; 3 | import { TModalState } from '../types'; 4 | 5 | interface IProps { 6 | state: TModalState; 7 | } 8 | export const DashboardChangelogModalTrigger = ({ state }: IProps) => { 9 | return ( 10 | }> 11 | Changelog 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/calendar-heatmap/editors/tooltip/index.tsx: -------------------------------------------------------------------------------- 1 | import { Control, UseFormWatch } from 'react-hook-form'; 2 | import { ICalendarHeatmapConf } from '../../type'; 3 | import { TooltipMetricsField } from './metrics'; 4 | 5 | interface ITooltipField { 6 | control: Control; 7 | watch: UseFormWatch; 8 | } 9 | export function TooltipField({ control, watch }: ITooltipField) { 10 | return ; 11 | } 12 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/scatter-chart/option/grid.ts: -------------------------------------------------------------------------------- 1 | import { IScatterChartConf } from '../type'; 2 | 3 | export function getGrid(conf: IScatterChartConf) { 4 | const hasYAxisName = conf.y_axes.some((y) => !!y.name); 5 | let top = 15; 6 | if (hasYAxisName) { 7 | top += 20; 8 | } 9 | if (conf.dataZoom.x_axis_slider) { 10 | top += 20; 11 | } 12 | 13 | let bottom = 5; 14 | if (conf.x_axis.name) { 15 | bottom += 15; 16 | } 17 | 18 | return { 19 | top, 20 | bottom, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /dashboard/src/utils/diff-json.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { AnyObject } from '..'; 3 | 4 | function printChanges(a: any, b: any) { 5 | if (_.isEqual(a, b)) { 6 | return; 7 | } 8 | if (Array.isArray(a) && Array.isArray(b)) { 9 | a.forEach((_a, i) => { 10 | printChanges(_a, b[i]); 11 | }); 12 | return; 13 | } 14 | console.log(a, b); 15 | } 16 | 17 | export function printJSONChanges(a: AnyObject, b: AnyObject) { 18 | Object.keys(a).forEach((k) => { 19 | printChanges(a[k], b[k]); 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/label-position/types.ts: -------------------------------------------------------------------------------- 1 | export type IEchartsLabelPosition = 2 | | 'top' 3 | | 'left' 4 | | 'right' 5 | | 'bottom' 6 | | 'inside' 7 | | 'insideLeft' 8 | | 'insideRight' 9 | | 'insideTop' 10 | | 'insideBottom' 11 | | 'insideTopLeft' 12 | | 'insideBottomLeft' 13 | | 'insideTopRight' 14 | | 'insideBottomRight' 15 | | 'outside'; 16 | 17 | export type LabelPositionOptionType = { 18 | label: string; 19 | value: IEchartsLabelPosition; 20 | disabled?: boolean; 21 | }; 22 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './viz-manager'; 2 | export * from './plugin-context'; 3 | export * from './plugin-data-migrator'; 4 | export * from './hooks'; 5 | export * from './color-manager'; 6 | export { onVizRendered, notifyVizRendered } from './viz-components/viz-instance-api'; 7 | export { ServiceLocator, Token } from './service/service-locator'; 8 | export { useServiceLocator } from './service/service-locator/use-service-locator'; 9 | export type { IServiceLocator, IDisposable } from './service/service-locator'; 10 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-estimation-chart/translation.ts: -------------------------------------------------------------------------------- 1 | import { TranslationPatch } from '~/types/plugin'; 2 | 3 | const en = { 4 | merico_estimation_chart: { 5 | viz_name: 'Merico Estimation Chart', 6 | }, 7 | }; 8 | 9 | const zh = { 10 | merico_estimation_chart: { 11 | viz_name: '思码逸估算分析图', 12 | }, 13 | }; 14 | 15 | export const translation: TranslationPatch = [ 16 | { 17 | lang: 'en', 18 | resources: en, 19 | }, 20 | { 21 | lang: 'zh', 22 | resources: zh, 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /settings-form/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "settings-form", 3 | "$schema": "../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "targets": { 6 | "check": { 7 | "executor": "nx:run-commands", 8 | "options": { 9 | "command": "echo noop, build runs type-checking automatically" 10 | } 11 | }, 12 | "dev": { 13 | "executor": "nx:run-script", 14 | "options": { 15 | "script": "dev-build" 16 | }, 17 | "dependsOn": ["^build"] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /website/src/components/logo/index.tsx: -------------------------------------------------------------------------------- 1 | import { useRequest } from 'ahooks'; 2 | import { ConfigAPI } from '../../api-caller/config'; 3 | import { LogoLink } from './logo-link'; 4 | import { Box } from '@mantine/core'; 5 | 6 | export const Logo = ({ height }: { height: string | number }) => { 7 | const { data } = useRequest(ConfigAPI.getWebsiteSettings); 8 | if (!data) { 9 | return null; 10 | } 11 | 12 | return ( 13 | 14 | 15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /website/src/frames/app/navbar-toggler.tsx: -------------------------------------------------------------------------------- 1 | import { ActionIcon, Tooltip } from '@mantine/core'; 2 | import { IconLayoutSidebar } from '@tabler/icons-react'; 3 | 4 | export const NavbarToggler = ({ collapsed, expand }: { collapsed: boolean; expand: () => void }) => { 5 | if (!collapsed) { 6 | return null; 7 | } 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/pie-chart/editors/pie-color-map-editor/palette.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { ChartTheme } from '~/styles/register-themes'; 3 | 4 | export type PieChartPaletteOption = { 5 | name: string; 6 | colors: string[]; 7 | }; 8 | export const PieChartPalettes = Object.entries( 9 | _.pick(ChartTheme.graphics, ['compared', 'level', 'depth', 'multiple']), 10 | ).map(([name, record]) => { 11 | return { 12 | name, 13 | colors: Object.values(record), 14 | } as PieChartPaletteOption; 15 | }); 16 | -------------------------------------------------------------------------------- /dashboard/src/contexts/layout-state-context.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface ILayoutStateContext { 4 | inEditMode: boolean; 5 | } 6 | 7 | const initialContext = { 8 | inEditMode: false, 9 | }; 10 | 11 | export const LayoutStateContext = React.createContext(initialContext); 12 | 13 | export function useLayoutStateContext() { 14 | const ctx = React.useContext(LayoutStateContext); 15 | if (!ctx) { 16 | throw new Error('Please use LayoutStateContext.Provider'); 17 | } 18 | return ctx; 19 | } 20 | -------------------------------------------------------------------------------- /tools/workspace-plugin/src/generators/viz-component/files/translation.ts__tmpl__: -------------------------------------------------------------------------------- 1 | import { TranslationPatch } from '~/types/plugin'; 2 | 3 | const en = { 4 | <%= camelcase(name) %>: { 5 | viz_name: '<%= pascalcase(name) %>', 6 | }, 7 | }; 8 | 9 | const zh = { 10 | <%= camelcase(name) %>: { 11 | viz_name: '<%= pascalcase(name) %>', 12 | }, 13 | }; 14 | 15 | export const translation: TranslationPatch = [ 16 | { 17 | lang: 'en', 18 | resources: en, 19 | }, 20 | { 21 | lang: 'zh', 22 | resources: zh, 23 | }, 24 | ]; 25 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-linear-gauge/editor/sections-editor/palette.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { ChartTheme } from '~/styles/register-themes'; 3 | 4 | export type PieChartPaletteOption = { 5 | name: string; 6 | colors: string[]; 7 | }; 8 | export const PieChartPalettes = Object.entries( 9 | _.pick(ChartTheme.graphics, ['compared', 'level', 'depth', 'multiple']), 10 | ).map(([name, record]) => { 11 | return { 12 | name, 13 | colors: Object.values(record), 14 | } as PieChartPaletteOption; 15 | }); 16 | -------------------------------------------------------------------------------- /api/src/models/sql_snippet.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column, PrimaryColumn } from 'typeorm'; 2 | import { BaseModel } from './base'; 3 | 4 | @Entity() 5 | export default class SqlSnippet extends BaseModel { 6 | @PrimaryColumn('character varying', { 7 | nullable: false, 8 | name: 'id', 9 | }) 10 | id: string; 11 | 12 | @Column('text', { 13 | nullable: false, 14 | name: 'content', 15 | }) 16 | content: string; 17 | 18 | @Column('boolean', { 19 | default: false, 20 | name: 'is_preset', 21 | }) 22 | is_preset: boolean; 23 | } 24 | -------------------------------------------------------------------------------- /api/src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import * as logger from 'npmlog'; 2 | 3 | export const enum LOG_LEVELS { 4 | INFO = 'info', 5 | WARN = 'warn', 6 | ERROR = 'error', 7 | } 8 | 9 | export enum LOG_LABELS { 10 | SERVER = 'SERVER', 11 | DASHBOARD_SCHEMA = 'DASHBOARD_SCHEMA', 12 | API = 'API', 13 | SERVICE = 'SERVICE', 14 | AXIOS = 'AXIOS', 15 | WEBSOCKET = 'WEBSOCKET', 16 | QUERY_MISMATCH = 'QUERY_MISMATCH', 17 | } 18 | 19 | export default function log(level: LOG_LEVELS, label: LOG_LABELS, message: any) { 20 | logger[level](label, message); 21 | } 22 | -------------------------------------------------------------------------------- /dashboard/src/utils/template/editor/utils.ts: -------------------------------------------------------------------------------- 1 | import { randomId } from '@mantine/hooks'; 2 | import { defaultNumberFormat } from '~/utils'; 3 | import { ITemplateVariable } from '../types'; 4 | 5 | export function getANewVariable() { 6 | return { 7 | name: randomId(), 8 | size: '20px', 9 | weight: 'bold', 10 | color: { 11 | type: 'static', 12 | staticColor: 'blue', 13 | }, 14 | data_field: '', 15 | aggregation: { type: 'none', config: {} }, 16 | formatter: defaultNumberFormat, 17 | } as ITemplateVariable; 18 | } 19 | -------------------------------------------------------------------------------- /tools/workspace-plugin/src/generators/viz-component/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "$id": "viz-component", 5 | "type": "object", 6 | "properties": { 7 | "name": { 8 | "type": "string", 9 | "description": "component name", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | } 14 | }, 15 | "path": { 16 | "type": "string", 17 | "description": "path to the generated files" 18 | } 19 | }, 20 | "required": ["name"] 21 | } 22 | -------------------------------------------------------------------------------- /api/src/data_sources/dashboard.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { DataSource } from 'typeorm'; 3 | 4 | // eslint-disable-next-line @typescript-eslint/no-var-requires 5 | require('dotenv').config({ path: path.join(__dirname, '../../.env') }); 6 | 7 | export const dashboardDataSource = new DataSource({ 8 | type: 'postgres', 9 | url: process.env.PG_URL, 10 | migrationsTableName: 'schema_migrations', 11 | migrations: ['src/data_sources/migrations/*.ts', 'dist/data_sources/migrations/*.js'], 12 | entities: ['src/models/*.ts', 'dist/models/*.js'], 13 | }); 14 | -------------------------------------------------------------------------------- /dashboard/src/styles/default-echarts-options/x-axis.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { AnyObject } from '~/types'; 3 | 4 | export const xAxis = { 5 | axisTick: { 6 | show: true, 7 | alignWithLabel: true, 8 | lineStyle: { 9 | width: 2, 10 | }, 11 | }, 12 | axisLine: { 13 | show: true, 14 | lineStyle: { 15 | width: 3, 16 | }, 17 | }, 18 | splitLine: { 19 | show: false, 20 | }, 21 | z: 3, 22 | }; 23 | 24 | export function getXAxis(option: AnyObject) { 25 | return _.defaultsDeep({}, option, xAxis); 26 | } 27 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/cartesian/option/utils/variables.ts: -------------------------------------------------------------------------------- 1 | import { AnyObject } from '~/types'; 2 | import { formatAggregatedValue, getAggregatedValue, ITemplateVariable } from '~/utils'; 3 | 4 | export function getVariableValueMap(data: TPanelData, variables: ITemplateVariable[]) { 5 | const ret: Record = {}; 6 | 7 | variables.map((variable) => { 8 | const value = getAggregatedValue(variable, data); 9 | ret[variable.name] = formatAggregatedValue(variable, value); 10 | }); 11 | 12 | return ret; 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './template'; 2 | export * from './aggregation'; 3 | export * from './color-feed'; 4 | export * from './color-mapping'; 5 | export * from './dashboard-state'; 6 | export * from './data'; 7 | export * from './diff-json'; 8 | export * from './error-boundary'; 9 | export * from './function-utils'; 10 | export * from './http-query'; 11 | export * from './number'; 12 | export * from './register-echarts'; 13 | export * from './shallow-to-js'; 14 | export * from './sql'; 15 | export * from './usage'; 16 | export * from './rich-text'; 17 | -------------------------------------------------------------------------------- /api/src/models/custom_function.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column, PrimaryColumn } from 'typeorm'; 2 | import { BaseModel } from './base'; 3 | 4 | @Entity() 5 | export default class CustomFunction extends BaseModel { 6 | @PrimaryColumn('character varying', { 7 | nullable: false, 8 | name: 'id', 9 | }) 10 | id: string; 11 | 12 | @Column('text', { 13 | nullable: false, 14 | name: 'definition', 15 | }) 16 | definition: string; 17 | 18 | @Column('boolean', { 19 | default: false, 20 | name: 'is_preset', 21 | }) 22 | is_preset: boolean; 23 | } 24 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/colors/diverging-color.ts: -------------------------------------------------------------------------------- 1 | import chroma from 'chroma-js'; 2 | import { IColorInterpolation } from '~/types/plugin'; 3 | 4 | export const createDivergingColorPalette = (left: string[], right: string[]): IColorInterpolation['getColor'] => { 5 | const leftColor = chroma.bezier(left); 6 | const rightColor = chroma.bezier(right); 7 | return function (value: number): string { 8 | if (value < 50) { 9 | return leftColor((value * 2) / 100).hex(); 10 | } 11 | return rightColor(((value - 50) * 2) / 100).hex(); 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/sunburst/option/types.ts: -------------------------------------------------------------------------------- 1 | import { SunburstItemType } from '../type'; 2 | 3 | export type TreeItemIn = { 4 | id: string; 5 | parent_id: string | null; 6 | } & SunburstItemType; 7 | 8 | export type TreeItemOut = TreeItemIn & { 9 | children: TreeItemOut[]; 10 | }; 11 | 12 | export interface IEchartsSunburstLabelFormatter { 13 | treePathInfo: { 14 | name: string; 15 | dataIndex: number; 16 | value: number; 17 | }[]; 18 | name: string; 19 | value: number; 20 | marker: string; 21 | color: string; 22 | } 23 | -------------------------------------------------------------------------------- /dashboard/src/interactions/hooks/use-current-interaction-manager.ts: -------------------------------------------------------------------------------- 1 | import { IVizManager, tokens } from '~/components/plugins'; 2 | import { IVizInteractionManager, VizInstance } from '~/types/plugin'; 3 | import { useServiceLocator } from '~/components/plugins/service/service-locator/use-service-locator'; 4 | 5 | export const useCurrentInteractionManager = ({}: { 6 | vizManager: IVizManager; 7 | instance: VizInstance; 8 | }): IVizInteractionManager => { 9 | const sl = useServiceLocator(); 10 | return sl.getRequired(tokens.instanceScope.interactionManager); 11 | }; 12 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/4.10.0.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Changes: introduce panel.style & panel.style.border 3 | * @param schema 4 | * @returns new schema 5 | */ 6 | export function main({ views, ...rest }: Record) { 7 | return { 8 | views: views.map((v) => ({ 9 | ...v, 10 | panels: v.panels.map((p) => ({ 11 | ...p, 12 | style: { 13 | border: { 14 | enabled: !!p.style?.border?.enabled, 15 | }, 16 | }, 17 | })), 18 | })), 19 | ...rest, 20 | version: '4.10.0', 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/cartesian/editors/echarts-zooming-field/types.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | export type TEchartsDataZoomConfig = { 4 | x_axis_scroll: boolean; 5 | y_axis_scroll: boolean; 6 | x_axis_slider: boolean; 7 | y_axis_slider: boolean; 8 | }; 9 | 10 | export const DEFAULT_DATA_ZOOM_CONFIG = { 11 | x_axis_scroll: false, 12 | y_axis_scroll: false, 13 | x_axis_slider: false, 14 | y_axis_slider: false, 15 | }; 16 | 17 | export function getDefaultDataZoomConfig() { 18 | return _.cloneDeep(DEFAULT_DATA_ZOOM_CONFIG); 19 | } 20 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/horizontal-bar-chart/option/utils/variables.ts: -------------------------------------------------------------------------------- 1 | import { AnyObject } from '~/types'; 2 | import { formatAggregatedValue, getAggregatedValue, ITemplateVariable } from '~/utils'; 3 | 4 | export function getVariableValueMap(data: TPanelData, variables: ITemplateVariable[]) { 5 | const ret: Record = {}; 6 | 7 | variables.map((variable) => { 8 | const value = getAggregatedValue(variable, data); 9 | ret[variable.name] = formatAggregatedValue(variable, value); 10 | }); 11 | 12 | return ret; 13 | } 14 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-editor-page/more-dashboard-info/use-modal-states.ts: -------------------------------------------------------------------------------- 1 | import { useDisclosure } from '@mantine/hooks'; 2 | import { TModalState, TModalStates } from './types'; 3 | 4 | function useModalState(): TModalState { 5 | const [opened, { open, close }] = useDisclosure(false); 6 | return { 7 | opened, 8 | open, 9 | close, 10 | }; 11 | } 12 | 13 | export function useModalStates(): TModalStates { 14 | const changelog = useModalState(); 15 | const version = useModalState(); 16 | return { 17 | changelog, 18 | version, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /website/src/utils/configure-monaco-editor/index.ts: -------------------------------------------------------------------------------- 1 | import { loader } from '@monaco-editor/react'; 2 | import { MonacoPath } from '../config'; 3 | import { configureSQLLanguage } from './configure-sql-language'; 4 | import { configureDiffLanguage } from './custom-diff-language'; 5 | 6 | const cleanURL = (str: string) => { 7 | return str.replace(/([^:])(\/\/+)/g, '$1/'); 8 | }; 9 | const path = cleanURL(MonacoPath); 10 | loader.config({ paths: { vs: path } }); 11 | loader.init().then((monaco) => { 12 | configureDiffLanguage(monaco); 13 | configureSQLLanguage(monaco); 14 | }); 15 | -------------------------------------------------------------------------------- /dashboard/src/utils/dashboard-state.ts: -------------------------------------------------------------------------------- 1 | import { TDashboardStateValues, TPayloadForSQL } from '~/model'; 2 | 3 | export function getEmptyDashboardStateValues(): TDashboardStateValues { 4 | return { 5 | filters: {}, 6 | context: {}, 7 | }; 8 | } 9 | 10 | export function payloadToDashboardStateValues(payload: TPayloadForSQL) { 11 | const empty = getEmptyDashboardStateValues(); 12 | if (!payload) { 13 | return getEmptyDashboardStateValues(); 14 | } 15 | const { filters = empty.filters, context = empty.context } = payload; 16 | return { filters, context }; 17 | } 18 | -------------------------------------------------------------------------------- /dashboard/src/utils/template/editor/template-input.tsx: -------------------------------------------------------------------------------- 1 | import { TextInput, TextInputProps } from '@mantine/core'; 2 | import { ChangeEventHandler, forwardRef } from 'react'; 3 | 4 | interface ITemplateInput extends Omit { 5 | value: string; 6 | onChange: ChangeEventHandler; 7 | } 8 | 9 | export const TemplateInput = forwardRef(function TemplateInput( 10 | { value, onChange, ...rest }: ITemplateInput, 11 | ref: $TSFixMe, 12 | ) { 13 | return ; 14 | }); 15 | -------------------------------------------------------------------------------- /tools/workspace-plugin/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | }, 17 | { 18 | "files": ["./package.json", "./generators.json", "./executors.json"], 19 | "parser": "jsonc-eslint-parser", 20 | "rules": {} 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /api/src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const SALT_ROUNDS = 12; 2 | export const SECRET_KEY = process.env.SECRET_KEY; 3 | export const TOKEN_VALIDITY = 7 * 24 * 3600; 4 | export const AUTH_ENABLED = process.env.ENABLE_AUTH !== '0'; 5 | export const DATABASE_CONNECTION_TIMEOUT_MS = parseInt(process.env.DATABASE_CONNECTION_TIMEOUT_MS ?? '30000'); 6 | export const DATABASE_POOL_SIZE = parseInt(process.env.DATABASE_POOL_SIZE ?? '10'); 7 | export const DEFAULT_LANGUAGE = 'en'; 8 | export const CACHE_RETAIN_TIME = '86400'; 9 | export const QUERY_PARSING_ENABLED = process.env.ENABLE_QUERY_PARSER === '1'; 10 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/hooks/use-current-viz-instance.ts: -------------------------------------------------------------------------------- 1 | import { useCreation } from 'ahooks'; 2 | import { useContext } from 'react'; 3 | import { IPanelInfo, PluginContext } from '~/components/plugins'; 4 | import { useRenderPanelContext } from '~/contexts'; 5 | 6 | export const useCurrentVizInstance = () => { 7 | const { panel } = useRenderPanelContext(); 8 | const { vizManager } = useContext(PluginContext); 9 | const panelInfo: IPanelInfo = panel.json; 10 | 11 | return useCreation(() => vizManager.getOrCreateInstance(panelInfo), [vizManager, panel.viz.type]); 12 | }; 13 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/db-explorer-modal/db-explorer/structure/tooltip-value.tsx: -------------------------------------------------------------------------------- 1 | import { ActionIcon, Tooltip } from '@mantine/core'; 2 | import { IconInfoCircle } from '@tabler/icons-react'; 3 | 4 | export const TooltipValue = ({ value }: { value: string }) => { 5 | if (value === null || value === '') { 6 | return null; 7 | } 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageRules": [ 3 | { 4 | "matchPackagePatterns": ["^@tiptap/"], 5 | "groupName": "tiptap packages" 6 | }, 7 | { 8 | "matchPackagePatterns": ["^@mantine/"], 9 | "groupName": "mantine packages" 10 | }, 11 | { 12 | "matchPackagePatterns": ["^@nrwl/"], 13 | "groupName": "Nrwl packages" 14 | }, 15 | { 16 | "matchPackagePatterns": ["^prosemirror"], 17 | "enabled": false 18 | }, 19 | { 20 | "matchPackagePatterns": ["^@types/"], 21 | "automerge": true 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/button/translation.ts: -------------------------------------------------------------------------------- 1 | import { TranslationPatch } from '~/types/plugin'; 2 | 3 | const en = { 4 | button: { 5 | viz_name: 'Button', 6 | click: { 7 | label: 'Click this button', 8 | }, 9 | }, 10 | }; 11 | 12 | const zh = { 13 | button: { 14 | viz_name: '按钮', 15 | click: { 16 | label: '点击此按钮', 17 | }, 18 | }, 19 | }; 20 | 21 | export const translation: TranslationPatch = [ 22 | { 23 | lang: 'en', 24 | resources: en, 25 | }, 26 | { 27 | lang: 'zh', 28 | resources: zh, 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /dashboard/src/components/view/layout/index.css: -------------------------------------------------------------------------------- 1 | .dashboard-layout { 2 | margin: 5px; 3 | } 4 | .react-grid-item { 5 | padding: 0; 6 | } 7 | .react-grid-item.react-grid-placeholder { 8 | background: black !important; 9 | opacity: 0.3 !important; 10 | } 11 | .panel-grid-item { 12 | padding: 5px; 13 | min-height: 38px; 14 | } 15 | .remove-panel { 16 | position: absolute; 17 | right: 2px; 18 | top: 0; 19 | cursor: pointer; 20 | } 21 | .code-textarea textarea { 22 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace; 23 | } 24 | -------------------------------------------------------------------------------- /api/src/models/base.ts: -------------------------------------------------------------------------------- 1 | import { Column, PrimaryGeneratedColumn } from 'typeorm'; 2 | 3 | export class BaseModel { 4 | @PrimaryGeneratedColumn('uuid', { 5 | name: 'id', 6 | comment: '实体id', 7 | }) 8 | id: string; 9 | 10 | @Column('timestamp with time zone', { 11 | nullable: false, 12 | default: () => 'CURRENT_TIMESTAMP', 13 | name: 'create_time', 14 | }) 15 | create_time: Date; 16 | 17 | @Column('timestamp with time zone', { 18 | nullable: false, 19 | default: () => 'CURRENT_TIMESTAMP', 20 | name: 'update_time', 21 | }) 22 | update_time: Date; 23 | } 24 | -------------------------------------------------------------------------------- /api/tests/integration/jest.util.ts: -------------------------------------------------------------------------------- 1 | import { dashboardDataSource } from '~/data_sources/dashboard'; 2 | 3 | export function connectionHook(): void { 4 | beforeAll(async () => { 5 | dashboardDataSource.setOptions({ url: process.env.INTEGRATION_TEST_PG_URL! }); 6 | await dashboardDataSource.initialize(); 7 | }); 8 | afterAll(async () => { 9 | await dashboardDataSource.destroy(); 10 | }); 11 | } 12 | 13 | function timeout(ms: number) { 14 | return new Promise((resolve) => setTimeout(resolve, ms)); 15 | } 16 | export async function sleep(ms: number) { 17 | await timeout(ms); 18 | } 19 | -------------------------------------------------------------------------------- /api/src/middleware/localization.ts: -------------------------------------------------------------------------------- 1 | import * as express from 'express'; 2 | import { ConfigService } from '../services/config.service'; 3 | import { DEFAULT_LANGUAGE } from '../utils/constants'; 4 | 5 | export default async function localization(req: express.Request, res: express.Response, next: express.NextFunction) { 6 | if (req.headers['accept-language'] === undefined && req.body.auth) { 7 | const configService = new ConfigService(); 8 | const langConfig = await configService.get('lang', req.body.auth); 9 | req.locale = langConfig.value ?? DEFAULT_LANGUAGE; 10 | } 11 | next(); 12 | } 13 | -------------------------------------------------------------------------------- /api/src/middleware/permission.ts: -------------------------------------------------------------------------------- 1 | import * as express from 'express'; 2 | import { Account } from '../api_models/account'; 3 | import { ApiKey } from '../api_models/api'; 4 | import { CHECK_PERMISSION, RoleService } from '../services/role.service'; 5 | 6 | export default function permission(requiredPermission: CHECK_PERMISSION) { 7 | return (req: express.Request, res: express.Response, next: express.NextFunction) => { 8 | const auth: Account | ApiKey | undefined = req.body.auth; 9 | RoleService.checkPermission(requiredPermission, req.locale, auth?.permissions); 10 | next(); 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/color-manager/color-manager.ts: -------------------------------------------------------------------------------- 1 | import { IColorInterpolation, IColorPaletteItem, ISingleColor } from '~/types/plugin'; 2 | 3 | export interface IColorManager { 4 | getStaticColors(): ISingleColor[]; 5 | getColorInterpolations(): IColorInterpolation[]; 6 | 7 | register(paletteItem: T): void; 8 | 9 | decodeStaticColor(key: string): ISingleColor | undefined; 10 | 11 | encodeColor(color: IColorPaletteItem): string; 12 | decodeInterpolation(key: string): IColorInterpolation | undefined; 13 | 14 | // todo: color interpolation 15 | } 16 | -------------------------------------------------------------------------------- /dashboard/src/model/render-model/dashboard/content/sql-snippets/utils.ts: -------------------------------------------------------------------------------- 1 | import { TPayloadForSQLSnippet } from '~/model'; 2 | import { AnyObject } from '~/types'; 3 | import { formatSQL } from '~/utils'; 4 | 5 | export function formatSQLSnippet(list: AnyObject[], idKey: string, valueKey: string, params: TPayloadForSQLSnippet) { 6 | return list.reduce((ret, curr) => { 7 | try { 8 | ret[curr[idKey]] = formatSQL(curr[valueKey], params); 9 | } catch (error) { 10 | ret[curr[idKey]] = (error as any).message; 11 | } 12 | return ret; 13 | }, {} as Record); 14 | } 15 | -------------------------------------------------------------------------------- /settings-form/src/i18n/i18n.ts: -------------------------------------------------------------------------------- 1 | import { createInstance } from 'i18next'; 2 | import { initReactI18next } from 'react-i18next'; 3 | import LanguageDetector from 'i18next-browser-languagedetector'; 4 | import 'intl-pluralrules'; 5 | import { en } from './en'; 6 | import { zh } from './zh'; 7 | 8 | const i18n = createInstance({ 9 | debug: false, 10 | fallbackLng: 'en', 11 | interpolation: { 12 | escapeValue: false, 13 | }, 14 | resources: { 15 | en, 16 | zh, 17 | }, 18 | }) 19 | .use(LanguageDetector) 20 | .use(initReactI18next); 21 | 22 | i18n.init(); 23 | export default i18n; 24 | -------------------------------------------------------------------------------- /api/jest-i.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const defaultConfig = require('./jest.config'); 3 | 4 | module.exports = { 5 | ...defaultConfig, 6 | coverageDirectory: './coverage-i/', 7 | globalSetup: '/tests/integration/jest.setup.ts', 8 | testRegex: '(/tests/integration/.*(test|spec|integration))\\.(jsx?|tsx?)$', 9 | roots: ['/tests/integration/'], 10 | testSequencer: './test.sequencer.js', 11 | maxWorkers: 1, 12 | globals: { 13 | 'ts-jest': { 14 | tsconfig: 'tests/integration/tsconfig.json', 15 | }, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/stats/translation.ts: -------------------------------------------------------------------------------- 1 | import { TranslationPatch } from '~/types/plugin'; 2 | 3 | const en = { 4 | stats: { 5 | viz_name: 'Stats', 6 | click_stats: { 7 | trigger: 'Click stats text', 8 | }, 9 | }, 10 | }; 11 | 12 | const zh = { 13 | stats: { 14 | viz_name: '数据指标', 15 | click_stats: { 16 | trigger: '点击文字', 17 | }, 18 | }, 19 | }; 20 | 21 | export const translation: TranslationPatch = [ 22 | { 23 | lang: 'en', 24 | resources: en, 25 | }, 26 | { 27 | lang: 'zh', 28 | resources: zh, 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/model/datasources/datasource.ts: -------------------------------------------------------------------------------- 1 | import { Instance, types } from 'mobx-state-tree'; 2 | import { DataSourceMetaModel } from '~/model/meta-model/datasources'; 3 | import { DBInfoModel } from './db-info'; 4 | import { MMInfoModel } from './mm-info'; 5 | 6 | export const DataSourceModel = types.compose( 7 | 'DataSourceModel', 8 | DataSourceMetaModel, 9 | types.model({ 10 | dbInfo: types.optional(DBInfoModel, {}), 11 | mericoMetricInfo: types.optional(MMInfoModel, {}), 12 | }), 13 | ); 14 | 15 | export type DataSourceModelInstance = Instance; 16 | -------------------------------------------------------------------------------- /settings-form/src/components/submit-form-button.tsx: -------------------------------------------------------------------------------- 1 | import { Button, MantineSize } from '@mantine/core'; 2 | import { IconDeviceFloppy } from '@tabler/icons-react'; 3 | import { useTranslation } from 'react-i18next'; 4 | 5 | type Props = { 6 | size: MantineSize; 7 | disabled?: boolean; 8 | }; 9 | export function SubmitFormButton({ size, disabled }: Props) { 10 | const { t } = useTranslation(); 11 | return ( 12 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /Dockerfile-api: -------------------------------------------------------------------------------- 1 | FROM docker.io/node:20 as installer 2 | 3 | ENV YARN_NPM_REGISTRY_SERVER=https://registry.npmmirror.com 4 | 5 | COPY api /code/api 6 | 7 | # Javascript 8 | 9 | WORKDIR /code/api/_build 10 | 11 | ENV YARN_VERSION 3.6.1 12 | ENV YARN_IGNORE_NODE 1 13 | 14 | RUN yarn set version $YARN_VERSION 15 | RUN yarn config set nodeLinker node-modules 16 | RUN yarn install 17 | 18 | FROM node:20 19 | # fix trivy issues 20 | RUN apt update && apt upgrade -y 21 | 22 | COPY --from=installer /code/api/_build /code/api/_build 23 | 24 | WORKDIR /code/api/_build 25 | RUN yarn config set nodeLinker node-modules 26 | -------------------------------------------------------------------------------- /api/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '^.+\\.(j|t)sx?$': ['ts-jest'], 4 | }, 5 | testTimeout: 15000, 6 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 7 | moduleDirectories: ['node_modules'], 8 | collectCoverageFrom: ['./src/**/*.ts'], 9 | coverageReporters: ['text', 'text-summary', 'lcov', 'json'], 10 | clearMocks: true, 11 | bail: 1, 12 | moduleNameMapper: { 13 | '^~/(.*)$': '/src/$1', 14 | }, 15 | roots: ['/tests/'], 16 | cacheDirectory: '/.jest_cache', 17 | globalTeardown: './test-teardown-globals.js', 18 | }; 19 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/message-channels.ts: -------------------------------------------------------------------------------- 1 | import EventEmitter2 from 'eventemitter2'; 2 | import { IMessageChannels } from '~/types/plugin'; 3 | 4 | export class MessageChannels implements IMessageChannels { 5 | private channels = new Map(); 6 | globalChannel = new EventEmitter2(); 7 | 8 | getChannel(name: string): EventEmitter2 { 9 | const result = this.channels.get(name); 10 | if (result) { 11 | return result; 12 | } 13 | const channel = new EventEmitter2(); 14 | this.channels.set(name, channel); 15 | return channel; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /dashboard/src/test/test-utils.ts: -------------------------------------------------------------------------------- 1 | import { cleanup, render } from '@testing-library/react'; 2 | import React from 'react'; 3 | import { afterEach } from 'vitest'; 4 | 5 | afterEach(() => { 6 | cleanup(); 7 | }); 8 | 9 | const customRender = (ui: React.ReactElement, options = {}) => 10 | render(ui, { 11 | // wrap provider(s) here if needed 12 | wrapper: ({ children }) => children, 13 | ...options, 14 | }); 15 | 16 | export * from '@testing-library/react'; 17 | export { default as userEvent } from '@testing-library/user-event'; 18 | // override render export 19 | export { customRender as render }; 20 | -------------------------------------------------------------------------------- /website/src/api-caller/custom-function.ts: -------------------------------------------------------------------------------- 1 | import { TCustomFunctionDefinition, TCustomFunctionDto } from './custom-function.types'; 2 | import { post } from './request'; 3 | 4 | export const custom_function = { 5 | get: (id: string, signal?: AbortSignal) => async (): Promise => { 6 | try { 7 | const res: TCustomFunctionDto = await post(signal)('/custom_function/get', { id }); 8 | const ret = new Function(`return ${res.definition}`)() as TCustomFunctionDefinition; 9 | return ret; 10 | } catch (error) { 11 | return null; 12 | } 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /website/src/api-caller/dashboard-content-changelog.types.ts: -------------------------------------------------------------------------------- 1 | import { PaginationResponse } from './types'; 2 | 3 | export type DashboardContentChangelogDBType = { 4 | id: string; 5 | diff: string; 6 | create_time: string; 7 | dashboard_id: string; 8 | }; 9 | 10 | export type ListDashboardContentChangelogReqType = { 11 | filter: { 12 | dashboard_content_id: { value: string; isFuzzy: false }; 13 | }; 14 | pagination: { 15 | page: number; 16 | pagesize: number; 17 | }; 18 | }; 19 | 20 | export type ListDashboardContentChangelogRespType = PaginationResponse; 21 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/header/index.tsx: -------------------------------------------------------------------------------- 1 | import { observer } from 'mobx-react-lite'; 2 | import { IDashbaordEditorHeaderMain, MainHeader } from './main-header'; 3 | import { SubHeader } from './sub-header'; 4 | 5 | 6 | interface IDashboardEditorHeader extends IDashbaordEditorHeaderMain { 7 | [key: string]: any; 8 | } 9 | 10 | export const DashboardEditorHeader = observer((props: IDashboardEditorHeader) => { 11 | return ( 12 | <> 13 | 14 | 15 | 16 | ); 17 | }); 18 | 19 | export type { OnExitParams, OnExitCallback } from './main-header'; 20 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/5.9.2.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Changes: add variables to panel config 3 | * @param schema 4 | * @returns new schema 5 | */ 6 | export function main({ views, ...rest }: Record) { 7 | return { 8 | views: views.map((view: Record) => { 9 | return { 10 | panels: view.panels.map((panel: Record) => { 11 | return { 12 | variables: panel.variables || [], 13 | ...panel, 14 | }; 15 | }), 16 | ...view, 17 | }; 18 | }), 19 | ...rest, 20 | version: '5.9.2', 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/error-message-or-not-found.tsx: -------------------------------------------------------------------------------- 1 | import { Text } from '@mantine/core'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | interface IProps { 5 | errorMessage?: string; 6 | } 7 | 8 | export const ErrorMessageOrNotFound = ({ errorMessage }: IProps) => { 9 | const { t } = useTranslation(); 10 | if (errorMessage) { 11 | return ( 12 | 13 | {errorMessage} 14 | 15 | ); 16 | } 17 | return ( 18 | 19 | {t('filter.widget.common.selector_option_empty')} 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/merico-heatmap/render/option/series.ts: -------------------------------------------------------------------------------- 1 | import { TMericoHeatmapConf } from '../../type'; 2 | 3 | export function getSeries(conf: TMericoHeatmapConf, seriesData: any[]) { 4 | const { heat_block } = conf; 5 | 6 | return { 7 | type: 'heatmap', 8 | name: heat_block.name, 9 | xAxisId: 'main-x-axis', 10 | yAxisIndex: 0, 11 | datasetIndex: 0, 12 | itemStyle: { 13 | borderWidth: 0, 14 | }, 15 | data: seriesData, 16 | label: heat_block.label, 17 | labelLayout: { 18 | hideOverlap: true, 19 | }, 20 | z: 2, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /website/src/pages/dashboard-editor-page/more-dashboard-info/dashboard-header-menu-items.tsx: -------------------------------------------------------------------------------- 1 | import { observer } from 'mobx-react-lite'; 2 | import { TModalStates } from './types'; 3 | import { DashboardChangelogModalTrigger } from './dashboard-changlog-modal/changelog-modal-trigger'; 4 | import { Menu } from '@mantine/core'; 5 | 6 | interface IProps { 7 | states: TModalStates; 8 | } 9 | 10 | export const DashboardHeaderMenuItems = observer(({ states }: IProps) => { 11 | return ( 12 | <> 13 | 14 | 15 | 16 | ); 17 | }); 18 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/boxplot-chart/editors/tooltip/index.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from '@mantine/core'; 2 | import { Control, UseFormWatch } from 'react-hook-form'; 3 | import { IBoxplotChartConf } from '../../type'; 4 | import { TooltipMetricsField } from './metrics'; 5 | 6 | interface ITooltipField { 7 | control: Control; 8 | watch: UseFormWatch; 9 | } 10 | export function TooltipField({ control, watch }: ITooltipField) { 11 | return ( 12 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /dashboard/src/interactions/hooks/use-watch-triggers.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import { ITriggerSnapshot, IVizTriggerManager } from '~/types/plugin'; 3 | 4 | export const useTriggerSnapshotList = (triggerManager: IVizTriggerManager, triggerSchemaId: string) => { 5 | const [state, setState] = useState[]>([]); 6 | useEffect(() => { 7 | return triggerManager.watchTriggerSnapshotList((list) => 8 | setState(list.filter((it) => it.schemaRef === triggerSchemaId) as unknown as ITriggerSnapshot[]), 9 | ); 10 | }, []); 11 | 12 | return state; 13 | }; 14 | -------------------------------------------------------------------------------- /api/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "$schema": "../node_modules/nx/schemas/project-schema.json", 4 | "targets": { 5 | "build": { 6 | "executor": "nx:run-commands", 7 | "inputs": ["{projectRoot}/**/*", "!{projectRoot}/_build/**/*"], 8 | "outputs": ["{projectRoot}/_build"], 9 | "dependsOn": ["^build"], 10 | "options": { 11 | "commands": ["gulp build"], 12 | "cwd": "api" 13 | } 14 | }, 15 | "dev": { 16 | "executor": "nx:run-script", 17 | "options": { 18 | "script": "dev" 19 | }, 20 | "dependsOn": ["^dev"] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /api/src/models/job.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column } from 'typeorm'; 2 | import { BaseModel } from './base'; 3 | 4 | @Entity() 5 | export default class Job extends BaseModel { 6 | @Column('character varying', { 7 | nullable: false, 8 | primary: false, 9 | name: 'type', 10 | }) 11 | type: string; 12 | 13 | @Column('character varying', { 14 | nullable: false, 15 | primary: false, 16 | name: 'status', 17 | }) 18 | status: string; 19 | 20 | @Column('jsonb', { name: 'params' }) 21 | params: Record; 22 | 23 | @Column('jsonb', { name: 'result' }) 24 | result: Record; 25 | } 26 | -------------------------------------------------------------------------------- /dashboard/src/components/filter/filter-date-range/widget/hints.tsx: -------------------------------------------------------------------------------- 1 | import { Badge, Divider, Group } from '@mantine/core'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | export const Hints = ({ max_days }: { max_days: number }) => { 5 | const { t } = useTranslation(); 6 | if (!max_days) { 7 | return null; 8 | } 9 | return ( 10 | <> 11 | 12 | 13 | {t('filter.widget.date_range.x_max_days', { max_days })} 14 | 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/cartesian/editors/tooltip/index.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from '@mantine/core'; 2 | import { Control, UseFormWatch } from 'react-hook-form'; 3 | import { ICartesianChartConf } from '../../type'; 4 | import { TooltipMetricsField } from './metrics'; 5 | 6 | interface ITooltipField { 7 | control: Control; 8 | watch: UseFormWatch; 9 | } 10 | export function TooltipField({ control, watch }: ITooltipField) { 11 | return ( 12 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /dashboard/src/contexts/additional-panel-menu-items.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { PanelMenuItem } from '~/types'; 3 | 4 | export interface IAdditionalPanelMenuItemsContext { 5 | items: PanelMenuItem[]; 6 | } 7 | 8 | const initialContext = { 9 | items: [], 10 | }; 11 | 12 | export const AdditionalPanelMenuItemsContext = React.createContext(initialContext); 13 | export const AdditionalPanelMenuItemsContextProvider = AdditionalPanelMenuItemsContext.Provider; 14 | 15 | export function useAdditionalPanelMenuItems() { 16 | return React.useContext(AdditionalPanelMenuItemsContext); 17 | } 18 | -------------------------------------------------------------------------------- /api/jest-e2e.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const defaultConfig = require('./jest.config'); 3 | 4 | module.exports = { 5 | ...defaultConfig, 6 | coverageDirectory: './coverage-e2e/', 7 | globalSetup: '/tests/e2e/jest.setup.ts', 8 | setupFilesAfterEnv: ['/tests/e2e/jest.mock.ts'], 9 | testRegex: '(/tests/e2e/.*(test|spec|e2e))\\.(jsx?|tsx?)$', 10 | roots: ['/tests/e2e/'], 11 | testSequencer: './test.sequencer.js', 12 | testTimeout: 60000, 13 | globals: { 14 | 'ts-jest': { 15 | tsconfig: 'tests/e2e/tsconfig.json', 16 | }, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/dropdown-menu-items/refresh.tsx: -------------------------------------------------------------------------------- 1 | import { Menu } from '@mantine/core'; 2 | import { IconRefresh } from '@tabler/icons-react'; 3 | import { observer } from 'mobx-react-lite'; 4 | import { useTranslation } from 'react-i18next'; 5 | import { useRenderPanelContext } from '~/contexts'; 6 | 7 | export const Refresh = observer(() => { 8 | const { t } = useTranslation(); 9 | const { panel } = useRenderPanelContext(); 10 | return ( 11 | }> 12 | {t('common.actions.refresh')} 13 | 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /dashboard/src/interactions/interactions-viewer/data/types.ts: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from 'react'; 2 | import { Node } from 'reactflow'; 3 | import { EViewComponentType } from '~/model'; 4 | 5 | export type TFlowNode_View = Node & { 6 | _node_type: 'view-root'; 7 | _view_type: EViewComponentType; 8 | _view_level: number; 9 | _sub_view_ids: string[]; 10 | _tab_view_ids: string[]; // for tabs only 11 | style: CSSProperties; 12 | }; 13 | 14 | export type TFlowNode_Default = Node & { 15 | _node_type: 'filter-root' | 'filter' | 'open-link-root' | 'panel'; 16 | }; 17 | export type TFlowNode = TFlowNode_View | TFlowNode_Default; 18 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/line-area-style/types.ts: -------------------------------------------------------------------------------- 1 | export type EchartsLineAreaStyle = { 2 | enabled: boolean; 3 | color: string; 4 | origin: 'auto' | 'start' | 'end'; 5 | shadowBlur: number; 6 | shadowColor: string; 7 | shadowOffsetX: number; 8 | shadowOffsetY: number; 9 | opacity: number; 10 | }; 11 | 12 | export function getDefaultLineAreaStyle(): EchartsLineAreaStyle { 13 | return { 14 | enabled: false, 15 | color: '', 16 | origin: 'auto', 17 | shadowBlur: 0, 18 | shadowColor: '', 19 | shadowOffsetX: 0, 20 | shadowOffsetY: 0, 21 | opacity: 0.7, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/heatmap/option/series.ts: -------------------------------------------------------------------------------- 1 | import { IHeatmapConf } from '../type'; 2 | 3 | export function getSeries(conf: IHeatmapConf, seriesData: any[], borderWidth: number) { 4 | const { heat_block } = conf; 5 | 6 | return { 7 | type: 'heatmap', 8 | name: heat_block.name, 9 | xAxisId: 'main-x-axis', 10 | yAxisIndex: 0, 11 | datasetIndex: 0, 12 | itemStyle: { 13 | borderColor: 'white', 14 | borderWidth, 15 | }, 16 | data: seriesData, 17 | label: heat_block.label, 18 | labelLayout: { 19 | hideOverlap: true, 20 | }, 21 | z: 2, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/text/translation.ts: -------------------------------------------------------------------------------- 1 | import { TranslationPatch } from '~/types/plugin'; 2 | 3 | const en = { 4 | text: { 5 | viz_name: 'Text', 6 | content: { 7 | label: 'Text content', 8 | edit: 'Edit Content', 9 | }, 10 | }, 11 | }; 12 | 13 | const zh = { 14 | text: { 15 | viz_name: '文本', 16 | content: { 17 | label: '文本内容', 18 | edit: '编辑文本内容', 19 | }, 20 | }, 21 | }; 22 | 23 | export const translation: TranslationPatch = [ 24 | { 25 | lang: 'en', 26 | resources: en, 27 | }, 28 | { 29 | lang: 'zh', 30 | resources: zh, 31 | }, 32 | ]; 33 | -------------------------------------------------------------------------------- /api/src/models/dashboard_content.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column } from 'typeorm'; 2 | import { BaseModel } from './base'; 3 | import { Content } from '../api_models/dashboard_content'; 4 | 5 | @Entity() 6 | export default class DashboardContent extends BaseModel { 7 | @Column('uuid', { 8 | nullable: false, 9 | name: 'dashboard_id', 10 | comment: '报表ID', 11 | }) 12 | dashboard_id: string; 13 | 14 | @Column('character varying', { 15 | nullable: false, 16 | name: 'name', 17 | }) 18 | name: string; 19 | 20 | @Column('jsonb', { 21 | nullable: false, 22 | name: 'content', 23 | }) 24 | content: Content; 25 | } 26 | -------------------------------------------------------------------------------- /dashboard/src/interactions/interactions-viewer/node-with-interactions/types.ts: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export type TInteraction = 4 | | { 5 | schemaRef: 'builtin:op:open-link'; 6 | urlTemplate: string; 7 | shortURLTemplate: string; 8 | } 9 | | { 10 | schemaRef: 'builtin:op:set_filter_values'; 11 | filters: { key: string; label: string }[]; 12 | } 13 | | { 14 | schemaRef: 'builtin:op:clear_filter_values'; 15 | filters: { key: string; label: string }[]; 16 | }; 17 | 18 | export type TInteractionLine = { 19 | key: string; 20 | icon: ReactNode; 21 | text: ReactNode; 22 | }; 23 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/filter/types.ts: -------------------------------------------------------------------------------- 1 | import { types } from 'mobx-state-tree'; 2 | 3 | export enum DashboardFilterType { 4 | Select = 'select', 5 | MultiSelect = 'multi-select', 6 | TreeSelect = 'tree-select', 7 | TreeSingleSelect = 'tree-single-select', 8 | TextInput = 'text-input', 9 | Checkbox = 'checkbox', 10 | DateRange = 'date-range', 11 | MericoDateRange = 'merico-date-range', 12 | } 13 | 14 | export type DefaultValueMode = 'intersect' | 'reset'; 15 | export const DefaultValueModeModelType = types.optional( 16 | types.enumeration(['intersect', 'reset']), 17 | 'intersect', 18 | ); 19 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/dropdown-menu-items/download-data.tsx: -------------------------------------------------------------------------------- 1 | import { Menu } from '@mantine/core'; 2 | import { IconDownload } from '@tabler/icons-react'; 3 | import { observer } from 'mobx-react-lite'; 4 | import { useTranslation } from 'react-i18next'; 5 | import { useRenderPanelContext } from '~/contexts'; 6 | 7 | export const DownloadData = observer(() => { 8 | const { t } = useTranslation(); 9 | const { panel } = useRenderPanelContext(); 10 | return ( 11 | }> 12 | {t('common.actions.download_data')} 13 | 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/dropdown-menu-items/download-schema.tsx: -------------------------------------------------------------------------------- 1 | import { Menu } from '@mantine/core'; 2 | import { IconCode } from '@tabler/icons-react'; 3 | import { observer } from 'mobx-react-lite'; 4 | import { useTranslation } from 'react-i18next'; 5 | import { useRenderPanelContext } from '~/contexts'; 6 | 7 | export const DownloadSchema = observer(() => { 8 | const { t } = useTranslation(); 9 | const { panel } = useRenderPanelContext(); 10 | return ( 11 | }> 12 | {t('common.actions.download_schema')} 13 | 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/content/edit-view/edit-view-form/config-fields/index.tsx: -------------------------------------------------------------------------------- 1 | import { observer } from 'mobx-react-lite'; 2 | import { ViewMetaInstance } from '~/model'; 3 | import { ViewDivisionConfigFields } from './config.division'; 4 | import { ViewTabsConfigFields } from './config.tabs'; 5 | import { ViewModalConfigFields } from './modal'; 6 | 7 | export const ConfigFields = observer(({ view }: { view: ViewMetaInstance }) => { 8 | return ( 9 | <> 10 | 11 | 12 | 13 | 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /website/src/frames/dashboard-editor-frame/index.tsx: -------------------------------------------------------------------------------- 1 | import { Notifications } from '@mantine/notifications'; 2 | import { Navigate, Outlet } from 'react-router-dom'; 3 | import { DashboardStoreProvider } from '../app/models/dashboard-store-context'; 4 | import { useAccountContext } from '../require-auth/account-context'; 5 | 6 | export function DashboardEditorFrame() { 7 | const { canEdit } = useAccountContext(); 8 | if (!canEdit) { 9 | return ; 10 | } 11 | return ( 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /dashboard/src/utils/template/types.ts: -------------------------------------------------------------------------------- 1 | import { TNumberFormat } from '~/utils'; 2 | import { AggregationType } from '../aggregation'; 3 | 4 | export type ColorConfType = 5 | | { 6 | type: 'static'; 7 | staticColor: string; 8 | } 9 | | { 10 | type: 'continuous'; 11 | valueRange: number[]; 12 | colorRange: string[]; 13 | } 14 | | { 15 | type: 'piecewise'; // TODO 16 | }; 17 | 18 | export interface ITemplateVariable { 19 | name: string; 20 | data_field: string; 21 | aggregation: AggregationType; 22 | formatter: TNumberFormat; 23 | color: ColorConfType; 24 | size: string; 25 | weight: string; 26 | } 27 | -------------------------------------------------------------------------------- /website/src/api-caller/api-key.ts: -------------------------------------------------------------------------------- 1 | import { IAPIKey } from '@devtable/settings-form'; 2 | import { post } from './request'; 3 | import { PaginationResponse } from './types'; 4 | 5 | export const api_key = { 6 | list: async (signal?: AbortSignal): Promise> => { 7 | const res = await post(signal)('/api/key/list', { 8 | filter: { 9 | search: '', 10 | }, 11 | sort: [ 12 | { 13 | field: 'name', 14 | order: 'ASC', 15 | }, 16 | ], 17 | pagination: { 18 | page: 1, 19 | pagesize: 1000, 20 | }, 21 | }); 22 | return res; 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/test-utils.tsx: -------------------------------------------------------------------------------- 1 | import { VizComponent } from '~/types/plugin'; 2 | 3 | export function createMockPlugin(id = 'foo', components: string[] = ['mockViz'], others: Partial = {}) { 4 | return { 5 | id: id, 6 | manifest: { 7 | color: [], 8 | viz: components.map( 9 | (name) => 10 | ({ 11 | name, 12 | configRender: () => Hello, 13 | viewRender: () => World, 14 | migrator: {} as $TSFixMe, 15 | ...others, 16 | } as VizComponent), 17 | ), 18 | }, 19 | version: '1.1.1', 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /dashboard/src/dashboard-editor/ui/settings/navbar/nav-links.module.css: -------------------------------------------------------------------------------- 1 | .menu_target:global(.mantine-ActionIcon-root) { 2 | width: 40px; 3 | height: 100%; 4 | min-height: 40px; 5 | position: absolute; 6 | top: 0; 7 | right: 0; 8 | bottom: 0; 9 | border-radius: 0; 10 | } 11 | 12 | .query:global(.mantine-NavLink-root) { 13 | padding: 0; 14 | } 15 | 16 | .query :global(.mantine-NavLink-body) { 17 | padding: 9px 6px 9px 12px; 18 | } 19 | .query :global(.mantine-NavLink-label) { 20 | display: block; 21 | width: calc(100% - 40px); 22 | word-break: break-all; 23 | } 24 | 25 | .query :global(.mantine-NavLink-section) { 26 | margin-left: 0px; 27 | } 28 | -------------------------------------------------------------------------------- /settings-form/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /api/src/data_sources/migrations/1675750180197-add-group-column-to-dashboard-table.ts: -------------------------------------------------------------------------------- 1 | import { MigrationInterface, QueryRunner } from 'typeorm'; 2 | 3 | export class addGroupColumnToDashboardTable1675750180197 implements MigrationInterface { 4 | public async up(queryRunner: QueryRunner): Promise { 5 | await queryRunner.query( 6 | `ALTER TABLE dashboard 7 | ADD COLUMN "group" VARCHAR NOT NULL DEFAULT '' 8 | `, 9 | ); 10 | } 11 | 12 | public async down(queryRunner: QueryRunner): Promise { 13 | await queryRunner.query( 14 | `ALTER TABLE dashboard 15 | DROP COLUMN "group" 16 | `, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-editor/dropdown-menu-items/dropdown-menu-items.tsx: -------------------------------------------------------------------------------- 1 | import { observer } from 'mobx-react-lite'; 2 | 3 | import { useRenderPanelContext } from '~/contexts/panel-context'; 4 | import { ViewMetaInstance } from '~/model'; 5 | import { useItems } from './use-items'; 6 | 7 | type Props = { 8 | view: ViewMetaInstance; 9 | }; 10 | 11 | export const PanelDropdownMenuItems = observer(({ view }: Props) => { 12 | const { getEchartsOptions, panel } = useRenderPanelContext(); 13 | const items = useItems(view); 14 | return items.map((item) => item.render({ getEchartsOptions, inEditMode: true, panelID: panel.id, viewID: view.id })); 15 | }); 16 | -------------------------------------------------------------------------------- /dashboard/src/components/panel/panel-render/dropdown-menu-items/dropdown-menu-items.tsx: -------------------------------------------------------------------------------- 1 | import { observer } from 'mobx-react-lite'; 2 | 3 | import { useRenderPanelContext } from '~/contexts/panel-context'; 4 | import { ViewMetaInstance } from '~/model'; 5 | import { useItems } from './use-items'; 6 | 7 | type Props = { 8 | view: ViewMetaInstance; 9 | }; 10 | 11 | export const PanelDropdownMenuItems = observer(({ view }: Props) => { 12 | const { getEchartsOptions, panel } = useRenderPanelContext(); 13 | const items = useItems(view); 14 | return items.map((item) => item.render({ getEchartsOptions, inEditMode: false, panelID: panel.id, viewID: view.id })); 15 | }); 16 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/11.0.0.ts: -------------------------------------------------------------------------------- 1 | function upgradeQueries(queries: Record[]) { 2 | return queries.map((p) => { 3 | const { dep_query_ids, ...rest } = p; 4 | return { 5 | ...rest, 6 | dep_query_ids: dep_query_ids ?? [], 7 | }; 8 | }); 9 | } 10 | 11 | /** 12 | * https://github.com/merico-dev/table/issues/1308 13 | */ 14 | export function main({ definition, ...rest }: Record) { 15 | const finalQueries = upgradeQueries(definition.queries); 16 | return { 17 | ...rest, 18 | definition: { 19 | ...definition, 20 | queries: finalQueries, 21 | }, 22 | version: '11.0.0', 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/4.14.1.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Changes: add default_value to filter.date_range 3 | * @param schema 4 | * @returns new schema 5 | */ 6 | export function main({ filters, views, ...rest }: Record) { 7 | return { 8 | filters: filters.map((f) => { 9 | if (f.type !== 'date-range') { 10 | return f; 11 | } 12 | return { 13 | ...f, 14 | config: { 15 | ...f.config, 16 | default_value: Array.isArray(f.config.default_value) ? f.config.default_value : [null, null], 17 | }, 18 | }; 19 | }), 20 | views, 21 | ...rest, 22 | version: '4.14.1', 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /api/src/models/config.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column } from 'typeorm'; 2 | import { BaseModel } from './base'; 3 | 4 | @Entity() 5 | export default class Config extends BaseModel { 6 | @Column('character varying', { 7 | nullable: false, 8 | name: 'resource_type', 9 | }) 10 | resource_type: string; 11 | 12 | @Column('character varying', { 13 | nullable: true, 14 | name: 'resource_id', 15 | }) 16 | resource_id: string; 17 | 18 | @Column('character varying', { 19 | nullable: false, 20 | name: 'key', 21 | }) 22 | key: string; 23 | 24 | @Column('text', { 25 | nullable: false, 26 | name: 'value', 27 | }) 28 | value: string; 29 | } 30 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/common-echarts-fields/axis-label-overflow/types.ts: -------------------------------------------------------------------------------- 1 | export interface IEchartsOverflow { 2 | width: number; 3 | overflow: 'truncate' | 'break' | 'breakAll'; 4 | ellipsis: '...'; 5 | } 6 | 7 | export interface IAxisLabelOverflow { 8 | on_axis: IEchartsOverflow; 9 | in_tooltip: IEchartsOverflow; 10 | } 11 | 12 | export function getDefaultAxisLabelOverflow(): IAxisLabelOverflow { 13 | return { 14 | on_axis: { 15 | width: 80, 16 | overflow: 'truncate', 17 | ellipsis: '...', 18 | }, 19 | in_tooltip: { 20 | width: 200, 21 | overflow: 'break', 22 | ellipsis: '...', 23 | }, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/dashboard/content/panel/style/index.ts: -------------------------------------------------------------------------------- 1 | import { types } from 'mobx-state-tree'; 2 | import { PanelStyleBorderMeta, type IPanelStyleBorderMeta } from './border'; 3 | 4 | export const PanelStyleMeta = types 5 | .model('PanelStyleMeta', { 6 | border: PanelStyleBorderMeta, 7 | }) 8 | .views((self) => ({ 9 | get json() { 10 | const { border } = self; 11 | return { 12 | border: border.json, 13 | }; 14 | }, 15 | })) 16 | .actions((self) => ({})); 17 | 18 | export interface IPanelStyleMeta { 19 | border: IPanelStyleBorderMeta; 20 | json: { 21 | border: IPanelStyleBorderMeta['json']; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /website/src/frames/socket-client-frame/socket-context.ts: -------------------------------------------------------------------------------- 1 | import { Socket } from 'socket.io-client'; 2 | import React from 'react'; 3 | 4 | type SocketContextType = { 5 | socket: Socket | null; 6 | }; 7 | 8 | type SocketContextOutType = { 9 | socket: Socket; 10 | }; 11 | 12 | const SocketContext = React.createContext({ 13 | socket: null, 14 | }); 15 | 16 | export const SocketContextProvider = SocketContext.Provider; 17 | 18 | export function useSocketContext() { 19 | const c = React.useContext(SocketContext); 20 | if (!c.socket) { 21 | throw new Error('Please use SocketContextProvider'); 22 | } 23 | return c as SocketContextOutType; 24 | } 25 | -------------------------------------------------------------------------------- /api/src/models/dashboard_permission.ts: -------------------------------------------------------------------------------- 1 | import { Entity, Column } from 'typeorm'; 2 | import { PermissionResource } from '../api_models/dashboard_permission'; 3 | import { BaseModel } from './base'; 4 | 5 | @Entity() 6 | export default class DashboardPermission extends BaseModel { 7 | @Column('uuid', { 8 | name: 'owner_id', 9 | nullable: true, 10 | }) 11 | owner_id: string | null; 12 | 13 | @Column('character varying', { 14 | name: 'owner_type', 15 | nullable: true, 16 | }) 17 | owner_type: 'ACCOUNT' | 'APIKEY' | null; 18 | 19 | @Column('jsonb', { 20 | name: 'access', 21 | nullable: false, 22 | }) 23 | access: PermissionResource[]; 24 | } 25 | -------------------------------------------------------------------------------- /dashboard/src/model/meta-model/datasources/datasource.ts: -------------------------------------------------------------------------------- 1 | import { Instance, types } from 'mobx-state-tree'; 2 | import { TDataSourceConfig } from '~/api-caller/types'; 3 | import { DataSourceType } from '~/model'; 4 | 5 | export const DataSourceMetaModel = types.model('DataSourceMetaModel', { 6 | id: types.string, 7 | type: types.enumeration('DataSourceType', [ 8 | DataSourceType.HTTP, 9 | DataSourceType.MySQL, 10 | DataSourceType.Postgresql, 11 | DataSourceType.MericoMetricSystem, 12 | ]), 13 | key: types.string, 14 | config: types.frozen(), 15 | }); 16 | 17 | export type DataSourceMetaModelInstance = Instance; 18 | -------------------------------------------------------------------------------- /dashboard/src/contexts/dates-provider.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useMemo } from 'react'; 2 | import { DatesProvider as MantineDatesProvider } from '@mantine/dates'; 3 | import { useTranslation } from 'react-i18next'; 4 | 5 | const lang2dayjsLocale = { 6 | en: 'en', 7 | zh: 'zh-cn', 8 | }; 9 | export function DatesProvider({ children }: { children: ReactNode }) { 10 | const { i18n } = useTranslation(); 11 | const locale = useMemo(() => { 12 | const lang = i18n.language as 'zh' | 'en'; 13 | return lang2dayjsLocale[lang] ?? 'en'; 14 | }, [i18n.language]); 15 | 16 | return {children}; 17 | } 18 | -------------------------------------------------------------------------------- /dashboard/src/styles/action-icon-group-style.ts: -------------------------------------------------------------------------------- 1 | export const ActionIconGroupStyle = { 2 | '> button': { 3 | '&:first-of-type': { 4 | borderTopRightRadius: 0, 5 | borderBottomRightRadius: 0, 6 | borderRightWidth: 0.5, 7 | }, 8 | ':not(:first-of-type):not(:last-of-type)': { 9 | borderTopRightRadius: 0, 10 | borderBottomRightRadius: 0, 11 | borderTopLeftRadius: 0, 12 | borderBottomLeftRadius: 0, 13 | borderLeftWidth: 0.5, 14 | borderRightWidth: 0.5, 15 | }, 16 | '&:last-of-type': { 17 | borderTopLeftRadius: 0, 18 | borderBottomLeftRadius: 0, 19 | borderLeftWidth: 0.5, 20 | }, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /api/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "allowSyntheticDefaultImports": true, 5 | "module": "commonjs", 6 | "esModuleInterop": true, 7 | "types": ["reflect-metadata", "swagger-express-ts", "node"], 8 | "downlevelIteration": true, 9 | "moduleResolution": "node", 10 | "experimentalDecorators": true, 11 | "emitDecoratorMetadata": true, 12 | "allowJs": true, 13 | "checkJs": false, 14 | "skipLibCheck": true, 15 | "noEmit": true, 16 | "resolveJsonModule": true, 17 | "strictNullChecks": true 18 | }, 19 | "rules": { 20 | "no-unused-expression": true, 21 | "no-floating-promises": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/viz-components/text/type.ts: -------------------------------------------------------------------------------- 1 | import { HorizontalAlign } from '../../editor-components'; 2 | 3 | export const DEFAULT_TEXT_FUNC_CONTENT = [ 4 | 'function text({ data, variables, filters, context}) {', 5 | ' // your code goes here', 6 | ' return "text"', 7 | '}', 8 | ].join('\n'); 9 | 10 | export interface IVizTextConf { 11 | func_content: string; 12 | horizontal_align: HorizontalAlign; 13 | font_size: string; 14 | font_weight: string; 15 | } 16 | 17 | export const DEFAULT_CONFIG: IVizTextConf = { 18 | func_content: DEFAULT_TEXT_FUNC_CONTENT, 19 | horizontal_align: 'left', 20 | font_size: '14px', 21 | font_weight: 'normal', 22 | }; 23 | -------------------------------------------------------------------------------- /settings-form/src/utils/load-monaco-editor.ts: -------------------------------------------------------------------------------- 1 | import { loader } from '@monaco-editor/react'; 2 | import { useEffect } from 'react'; 3 | 4 | const cleanURL = (str: string) => { 5 | return str.replace(/([^:])(\/\/+)/g, '$1/'); 6 | }; 7 | 8 | export function useLoadMonacoEditor(monacoPath: string) { 9 | useEffect(() => { 10 | const loaded = loader.__getMonacoInstance(); 11 | if (loaded) { 12 | return; 13 | } 14 | 15 | console.log('loading monaco for @devtable/settings-form'); 16 | const path = cleanURL(monacoPath); 17 | loader.config({ paths: { vs: path } }); 18 | loader.init().then((monaco) => console.log('monaco instance:', monaco)); 19 | }, []); 20 | } 21 | -------------------------------------------------------------------------------- /website/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import dts from 'vite-plugin-dts'; 3 | import tsconfigPaths from 'vite-tsconfig-paths'; 4 | import { defineConfig } from 'cypress'; 5 | 6 | export default defineConfig({ 7 | component: { 8 | devServer: { 9 | framework: 'react', 10 | bundler: 'vite', 11 | viteConfig: { 12 | plugins: [ 13 | tsconfigPaths({ 14 | projects: ['./tsconfig.cypress.json'], 15 | }), 16 | dts({ 17 | entryRoot: resolve(__dirname, 'src'), 18 | insertTypesEntry: true, 19 | }), 20 | ], 21 | }, 22 | }, 23 | }, 24 | video: false, 25 | }); 26 | -------------------------------------------------------------------------------- /api/src/dashboard_migration/handlers/9.11.0.ts: -------------------------------------------------------------------------------- 1 | function upgradeQueries(queries: Record[]) { 2 | return queries.map((q) => { 3 | const { react_to = [], ...rest } = q; 4 | return { 5 | ...rest, 6 | react_to, 7 | }; 8 | }); 9 | } 10 | 11 | /** 12 | * https://github.com/merico-dev/table/issues/980 13 | * @param schema 14 | * @returns new schema 15 | */ 16 | export function main({ definition, ...rest }: Record) { 17 | const finalQueries = upgradeQueries(definition.queries); 18 | return { 19 | ...rest, 20 | definition: { 21 | ...definition, 22 | queries: finalQueries, 23 | }, 24 | version: '9.11.0', 25 | }; 26 | } 27 | --------------------------------------------------------------------------------