@blazes/data-visualization 1.0.0-alpha.1 → 1.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/.vite/manifest.json +26 -26
- package/dist/core/config/dashboard-config-schema.d.ts +13 -0
- package/dist/core/config/dashboard-config-schema.d.ts.map +1 -1
- package/dist/core/config/dashboard-config.d.ts +4 -0
- package/dist/core/config/dashboard-config.d.ts.map +1 -1
- package/dist/core/export/index.d.ts +1 -0
- package/dist/core/export/index.d.ts.map +1 -1
- package/dist/core/export/panel-export.d.ts +4 -0
- package/dist/core/export/panel-export.d.ts.map +1 -0
- package/dist/core/index.js +63 -61
- package/dist/core/runtime/dashboard-runtime.d.ts +4 -0
- package/dist/core/runtime/dashboard-runtime.d.ts.map +1 -1
- package/dist/{dashboard-runtime-8a-9P8Ku.js → dashboard-runtime-6VlVQIuQ.js} +27 -27
- package/dist/{dashboard-runtime-8a-9P8Ku.js.map → dashboard-runtime-6VlVQIuQ.js.map} +1 -1
- package/dist/experimental/s2/index.js +12 -12
- package/dist/index.css +1 -1
- package/dist/index.js +63 -61
- package/dist/{csv-Dyrr2yMA.js → panel-export-Di_5Frul.js} +24 -19
- package/dist/panel-export-Di_5Frul.js.map +1 -0
- package/dist/renderers/word-cloud/index.js +1 -1
- package/dist/{runtime-schema-BO2qLlvE.js → runtime-schema-BmeEvFU-.js} +42 -34
- package/dist/runtime-schema-BmeEvFU-.js.map +1 -0
- package/dist/{standard-definitions-DHtaLAf1.js → standard-definitions-hgJ-kOoz.js} +5 -5
- package/dist/{standard-definitions-DHtaLAf1.js.map → standard-definitions-hgJ-kOoz.js.map} +1 -1
- package/dist/vue/components/DashboardPanel.vue.d.ts.map +1 -1
- package/dist/vue/components/DashboardRenderer.vue.d.ts.map +1 -1
- package/dist/vue/index.js +609 -592
- package/dist/vue/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/csv-Dyrr2yMA.js.map +0 -1
- package/dist/runtime-schema-BO2qLlvE.js.map +0 -1
package/dist/vue/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/vue/components/DashboardFilterBar.vue","../../src/vue/components/DashboardPanel.vue","../../src/vue/composables/use-dashboard-runtime.ts","../../src/vue/export/browser-download.ts","../../src/vue/components/DashboardRenderer.vue","../../src/vue/renderers/chart-format.ts","../../src/vue/renderers/BarRenderer.vue","../../src/vue/renderers/LineRenderer.vue","../../src/vue/renderers/MetricRenderer.vue","../../src/vue/renderers/PieRenderer.vue","../../src/vue/renderers/TableRenderer.vue","../../src/vue/registry/register-standard.ts","../../src/vue/registry/renderer-registry.ts"],"sourcesContent":["<template>\n <div v-if=\"config\" class=\"dv-filter-bar\" :class=\"{ 'dv-filter-bar--flow': config.layout === 'flow' }\">\n <div class=\"dv-filter-bar__controls\">\n <div\n v-for=\"control in config.controls\"\n :key=\"control.id\"\n class=\"dv-filter-bar__control\"\n :class=\"`dv-filter-bar__control--${control.type}`\"\n :style=\"layoutStyle(control.layout)\"\n >\n <label class=\"dv-filter-bar__label\">{{ control.label }}</label>\n <template v-if=\"control.type === 'date-range'\">\n <div class=\"dv-filter-bar__date-range\">\n <a-range-picker\n class=\"dv-filter-bar__range-picker\"\n :allow-clear=\"false\"\n :disabled=\"control.disabled ?? false\"\n dropdown-class-name=\"dv-filter-bar__date-popup\"\n :format=\"control.format ?? 'YYYY-MM-DD'\"\n v-bind=\"dateRangeValueProps(control)\"\n value-format=\"YYYY-MM-DD\"\n @change=\"(value: unknown) => onDateRangeChange(control, value)\"\n >\n <template #separator>至</template>\n </a-range-picker>\n <a-radio-group\n v-if=\"control.presets?.length\"\n class=\"dv-filter-bar__presets\"\n :disabled=\"control.disabled ?? false\"\n size=\"small\"\n :value=\"activePreset(control)\"\n @change=\"onPresetChange(control, $event)\"\n >\n <a-radio-button v-for=\"preset in control.presets\" :key=\"preset.id\" :value=\"preset.id\">\n {{ preset.label }}\n </a-radio-button>\n </a-radio-group>\n </div>\n </template>\n <a-select\n v-else-if=\"control.type === 'multi-select'\"\n :allow-clear=\"control.allowClear ?? false\"\n :disabled=\"control.disabled ?? false\"\n :max-tag-count=\"control.maxTagCount ?? 'responsive'\"\n mode=\"multiple\"\n option-filter-prop=\"label\"\n :options=\"selectOptions(control.options)\"\n :placeholder=\"control.placeholder ?? ''\"\n :show-search=\"control.showSearch ?? false\"\n :value=\"selectValue(context.variables[control.variableId])\"\n @change=\"(value: unknown) => onSelectChange(control.variableId, value)\"\n />\n <a-select\n v-else\n :allow-clear=\"control.allowClear ?? false\"\n :disabled=\"control.disabled ?? false\"\n option-filter-prop=\"label\"\n :options=\"selectOptions(control.options)\"\n :placeholder=\"control.placeholder ?? ''\"\n :show-search=\"control.showSearch ?? false\"\n :value=\"selectValue(context.variables[control.variableId])\"\n @change=\"(value: unknown) => onSelectChange(control.variableId, value)\"\n />\n </div>\n </div>\n <a-tooltip v-if=\"config.showRefresh !== false\" title=\"刷新全部\">\n <a-button type=\"primary\" class=\"dv-filter-bar__refresh\" :loading=\"loading ?? false\" @click=\"$emit('refresh')\">\n <template #icon><RedoOutlined /></template>\n 刷新\n </a-button>\n </a-tooltip>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { RedoOutlined } from \"@ant-design/icons-vue\";\nimport {\n Button as AButton,\n RadioButton as ARadioButton,\n RadioGroup as ARadioGroup,\n RangePicker as ARangePicker,\n Select as ASelect,\n Tooltip as ATooltip\n} from \"ant-design-vue\";\n\nimport type {\n DashboardContext,\n DashboardFilterBarConfig,\n DashboardFilterControlConfig,\n DashboardVariablePatch,\n JsonValue\n} from \"../../core\";\n\ntype DateRangeControl = Extract<DashboardFilterControlConfig, { type: \"date-range\" }>;\n\nconst props = defineProps<{ config?: DashboardFilterBarConfig; context: DashboardContext; loading?: boolean }>();\nconst emit = defineEmits<{ change: [patch: DashboardVariablePatch]; refresh: [] }>();\n\nfunction layoutStyle(layout: DashboardFilterBarConfig[\"controls\"][number][\"layout\"]) {\n return {\n \"--dv-filter-xs\": String(layout.xs),\n \"--dv-filter-sm\": String(layout.sm ?? layout.xs),\n \"--dv-filter-md\": String(layout.md ?? layout.sm ?? layout.xs),\n \"--dv-filter-lg\": String(layout.lg ?? layout.md ?? layout.sm ?? layout.xs),\n \"--dv-filter-xl\": String(layout.xl ?? layout.lg ?? layout.md ?? layout.sm ?? layout.xs)\n };\n}\nfunction selectValue(value: JsonValue | undefined): any {\n return value;\n}\nfunction selectOptions(\n options: ReadonlyArray<{ label: string; value: string | number | boolean; disabled?: boolean }>\n): any[] {\n return options.map((option) => ({ ...option }));\n}\nfunction parseDate(value: JsonValue | undefined): Date | undefined {\n if (typeof value !== \"string\" || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return undefined;\n const date = new Date(`${value}T12:00:00Z`);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\nfunction formatDate(value: Date): string {\n return value.toISOString().slice(0, 10);\n}\nfunction yesterdayDate(): Date {\n const parts = new Intl.DateTimeFormat(\"en-CA\", {\n timeZone: props.context.timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\"\n }).formatToParts(new Date());\n const date = Object.fromEntries(parts.map((part) => [part.type, part.value]));\n const yesterday = new Date(`${date.year}-${date.month}-${date.day}T12:00:00Z`);\n yesterday.setUTCDate(yesterday.getUTCDate() - 1);\n return yesterday;\n}\nfunction contextValue(variableId: string): JsonValue | undefined {\n return props.context.variables[variableId];\n}\nfunction dateRangeValueProps(control: DateRangeControl): { value?: [string, string] } {\n const start = contextValue(control.startVariableId);\n const end = contextValue(control.endVariableId);\n if (typeof start !== \"string\" || typeof end !== \"string\" || !parseDate(start) || !parseDate(end)) {\n return {};\n }\n return { value: [start, end] };\n}\nfunction onDateRangeChange(control: DateRangeControl, value: unknown): void {\n if (!Array.isArray(value) || value.length !== 2) return;\n const [start, end] = value;\n if (typeof start !== \"string\" || typeof end !== \"string\") return;\n emit(\"change\", {\n [control.startVariableId]: start,\n [control.endVariableId]: end\n });\n}\nfunction activePreset(control: DateRangeControl): string | undefined {\n const start = parseDate(contextValue(control.startVariableId));\n const end = parseDate(contextValue(control.endVariableId));\n if (!start || !end || end.getTime() !== yesterdayDate().getTime()) return undefined;\n const days = Math.round((end.getTime() - start.getTime()) / 86_400_000) + 1;\n return control.presets?.find((preset) => preset.days === days)?.id;\n}\nfunction onPresetChange(control: DateRangeControl, event: { target: { value?: unknown } }): void {\n const presetId = typeof event.target.value === \"string\" ? event.target.value : undefined;\n const preset = control.presets?.find((item) => item.id === presetId);\n if (!preset) return;\n const end = yesterdayDate();\n const start = new Date(end);\n start.setUTCDate(start.getUTCDate() - preset.days + 1);\n emit(\"change\", {\n [control.startVariableId]: formatDate(start),\n [control.endVariableId]: formatDate(end)\n });\n}\nfunction onSelectChange(variableId: string, value: unknown): void {\n emit(\"change\", { [variableId]: (value ?? null) as JsonValue });\n}\n</script>\n\n<style scoped>\n.dv-filter-bar {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 11px 14px;\n background: #fff;\n border: 1px solid var(--dv-card-border, #e1e6ed);\n border-radius: 7px;\n box-shadow:\n 0 1px 2px rgb(16 24 40 / 3.5%),\n 0 5px 14px rgb(16 24 40 / 2.5%);\n}\n.dv-filter-bar__controls {\n flex: 1;\n display: grid;\n grid-template-columns: repeat(24, minmax(0, 1fr));\n column-gap: 16px;\n row-gap: 8px;\n}\n.dv-filter-bar__control {\n grid-column: span var(--dv-filter-xs);\n min-width: 0;\n}\n.dv-filter-bar__label {\n display: block;\n margin-bottom: 6px;\n color: var(--dv-text-secondary, #657184);\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n white-space: nowrap;\n}\n.dv-filter-bar__control :deep(.ant-select) {\n width: 100%;\n min-width: 0;\n}\n.dv-filter-bar__control :deep(.ant-select-single .ant-select-selector),\n.dv-filter-bar__control :deep(.ant-select-multiple .ant-select-selector) {\n height: 32px;\n min-height: 32px;\n}\n.dv-filter-bar__control :deep(.ant-select-multiple .ant-select-selection-overflow) {\n flex-wrap: nowrap;\n overflow: hidden;\n}\n.dv-filter-bar__date-range {\n display: flex;\n width: fit-content;\n min-width: 0;\n max-width: 100%;\n align-items: center;\n gap: 10px;\n}\n.dv-filter-bar__range-picker {\n width: 320px;\n min-width: 220px;\n max-width: 320px;\n height: 32px;\n flex: 0 1 320px;\n}\n.dv-filter-bar__presets {\n display: inline-flex;\n height: 32px;\n flex: none;\n align-items: center;\n gap: 2px;\n padding: 3px;\n border: 1px solid #e2e7ed;\n border-radius: 6px;\n background: #f3f5f7;\n}\n.dv-filter-bar__presets :deep(.ant-radio-button-wrapper) {\n height: 24px;\n padding: 0 8px;\n border: 0;\n border-radius: 4px;\n color: #737e8e;\n background: transparent;\n box-shadow: none;\n font-size: 12px;\n font-weight: 500;\n line-height: 24px;\n}\n.dv-filter-bar__presets :deep(.ant-radio-button-wrapper::before) {\n display: none;\n}\n.dv-filter-bar__presets :deep(.ant-radio-button-wrapper-checked) {\n color: var(--dv-primary, #315fc4);\n background: #fff;\n box-shadow:\n 0 1px 2px rgb(16 24 40 / 8%),\n 0 0 0 1px rgb(16 24 40 / 2.5%);\n font-weight: 600;\n}\n.dv-filter-bar :deep(.ant-select-selector),\n.dv-filter-bar :deep(.ant-picker) {\n border-color: #dce2e9;\n border-radius: 5px;\n box-shadow: none;\n}\n.dv-filter-bar__refresh {\n width: 78px;\n height: 32px;\n flex: 0 0 78px;\n border-color: var(--dv-primary, #315fc4);\n border-radius: 6px;\n background: var(--dv-primary, #315fc4);\n box-shadow: none;\n}\n@media (min-width: 576px) {\n .dv-filter-bar__control {\n grid-column: span var(--dv-filter-sm);\n }\n}\n@media (min-width: 768px) {\n .dv-filter-bar__control {\n grid-column: span var(--dv-filter-md);\n display: flex;\n align-items: center;\n }\n .dv-filter-bar__label {\n flex: none;\n margin: 0 8px 0 0;\n }\n .dv-filter-bar--flow .dv-filter-bar__controls {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n column-gap: 20px;\n }\n .dv-filter-bar--flow .dv-filter-bar__control {\n width: auto;\n flex: 0 1 auto;\n grid-column: auto;\n }\n .dv-filter-bar--flow .dv-filter-bar__control--select,\n .dv-filter-bar--flow .dv-filter-bar__control--multi-select {\n width: clamp(220px, 20vw, 320px);\n flex-basis: clamp(220px, 20vw, 320px);\n }\n}\n@media (min-width: 992px) {\n .dv-filter-bar__control {\n grid-column: span var(--dv-filter-lg);\n }\n}\n@media (min-width: 1200px) {\n .dv-filter-bar__control {\n grid-column: span var(--dv-filter-xl);\n }\n}\n@media (min-width: 768px) and (max-width: 1300px) {\n .dv-filter-bar__date-range {\n gap: 6px;\n }\n .dv-filter-bar__range-picker {\n width: 288px;\n min-width: 200px;\n max-width: 288px;\n flex-basis: 288px;\n }\n .dv-filter-bar__presets :deep(.ant-radio-button-wrapper) {\n padding: 0 5px;\n font-size: 11px;\n }\n}\n@media (max-width: 767px) {\n .dv-filter-bar {\n align-items: stretch;\n flex-direction: column;\n }\n .dv-filter-bar__refresh {\n align-self: flex-end;\n }\n .dv-filter-bar__controls {\n column-gap: 0;\n }\n .dv-filter-bar__date-range {\n width: 100%;\n align-items: stretch;\n flex-direction: column;\n }\n .dv-filter-bar__range-picker {\n width: 100%;\n min-width: 0;\n max-width: none;\n flex-basis: auto;\n }\n .dv-filter-bar__refresh {\n flex-basis: 32px;\n }\n :global(.dv-filter-bar__date-popup .ant-picker-panels > .ant-picker-panel:last-child) {\n display: none;\n }\n :global(.dv-filter-bar__date-popup .ant-picker-panel:first-child .ant-picker-header-next-btn),\n :global(.dv-filter-bar__date-popup .ant-picker-panel:first-child .ant-picker-header-super-next-btn) {\n visibility: visible !important;\n }\n}\n</style>\n","<template>\n <a-card class=\"dv-panel\" :class=\"{ 'dv-panel--metric': isMetricPanel }\" :body-style=\"bodyStyle\">\n <template #title>\n <div class=\"dv-panel__heading\">\n <span class=\"dv-panel__title-group\">\n <span class=\"dv-panel__title\">{{ panel.title }}</span>\n <a-tooltip v-if=\"panel.description\" :title=\"panel.description\"><QuestionCircleOutlined /></a-tooltip>\n </span>\n <span v-if=\"panel.titleNote\" class=\"dv-panel__title-note\">{{ panel.titleNote }}</span>\n </div>\n </template>\n <template #extra>\n <div class=\"dv-panel__actions\">\n <a-tooltip\n v-if=\"state.status === 'stale'\"\n :title=\"`刷新失败,当前展示上次成功数据${state.error?.message ? `:${state.error.message}` : ''}`\"\n >\n <WarningOutlined class=\"dv-panel__warning\" />\n </a-tooltip>\n <a-tooltip :title=\"refreshDisabled ? '正在刷新全部' : '刷新'\"\n ><a-button :disabled=\"refreshDisabled ?? false\" type=\"text\" size=\"small\" @click=\"$emit('refresh')\"\n ><template #icon><RedoOutlined /></template></a-button\n ></a-tooltip>\n <a-dropdown v-if=\"canDownload\" placement=\"bottomRight\" :trigger=\"['click']\">\n <a-tooltip title=\"下载\">\n <a-button type=\"text\" size=\"small\"\n ><template #icon><CloudDownloadOutlined /></template\n ></a-button>\n </a-tooltip>\n <template #overlay>\n <a-menu @click=\"onDownloadMenuClick\">\n <a-menu-item v-if=\"definition.capabilities.csv && state.dataset\" key=\"csv\">导出 CSV</a-menu-item>\n <a-menu-item v-if=\"definition.capabilities.png && state.viewModel\" key=\"png\">导出 PNG</a-menu-item>\n </a-menu>\n </template>\n </a-dropdown>\n <a-button\n v-for=\"action in panel.actions ?? []\"\n :key=\"action.id\"\n type=\"link\"\n size=\"small\"\n @click=\"$emit('action', action.id)\"\n >{{ action.label ?? action.id }}</a-button\n >\n </div>\n </template>\n\n <div v-if=\"filterSummary\" class=\"dv-panel__filters\">{{ filterSummary }}</div>\n <div v-if=\"panelFailure\" class=\"dv-panel__state dv-panel__state--failure\" role=\"status\">\n <div class=\"dv-panel__failure\">\n <ExclamationCircleOutlined class=\"dv-panel__failure-icon\" />\n <div class=\"dv-panel__failure-copy\">\n <div class=\"dv-panel__failure-heading\">{{ panelFailure.title }}</div>\n <div v-if=\"panelFailure.detail\" class=\"dv-panel__failure-detail\" :title=\"panelFailure.detail\">\n {{ panelFailure.detail }}\n </div>\n </div>\n <a-tooltip title=\"重试\">\n <a-button class=\"dv-panel__retry\" size=\"small\" aria-label=\"重试\" @click=\"$emit('retry')\">\n <template #icon><RedoOutlined /></template>\n <span class=\"dv-panel__retry-label\">重新加载</span>\n </a-button>\n </a-tooltip>\n </div>\n </div>\n <div v-else-if=\"state.status === 'loading' && !state.viewModel\" class=\"dv-panel__state dv-panel__state--loading\">\n <a-spin />\n </div>\n <template v-else-if=\"state.status === 'empty'\">\n <div v-if=\"isMetricPanel\" class=\"dv-panel__state dv-panel__state--metric-empty\">暂无数据</div>\n <div v-else class=\"dv-panel__state dv-panel__state--empty\" role=\"status\" aria-live=\"polite\">\n <span class=\"dv-panel__empty-icon\" aria-hidden=\"true\"><BarChartOutlined /></span>\n <div class=\"dv-panel__empty-copy\">\n <div class=\"dv-panel__empty-title\">暂无数据</div>\n </div>\n </div>\n </template>\n <div v-else-if=\"state.viewModel\" class=\"dv-panel__renderer\">\n <component\n :is=\"renderer\"\n ref=\"rendererRef\"\n :context=\"context\"\n :panel=\"panel\"\n :view-model=\"state.viewModel\"\n @visualization-event=\"$emit('visualizationEvent', $event)\"\n />\n <div v-if=\"state.isRefreshing\" class=\"dv-panel__refreshing\"><a-spin /></div>\n </div>\n <div v-else class=\"dv-panel__state dv-panel__idle\">等待加载</div>\n\n <div v-if=\"state.lastSuccessfulAt\" class=\"dv-panel__updated\">更新于 {{ updatedAt }}</div>\n </a-card>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n BarChartOutlined,\n CloudDownloadOutlined,\n ExclamationCircleOutlined,\n QuestionCircleOutlined,\n RedoOutlined,\n WarningOutlined\n} from \"@ant-design/icons-vue\";\nimport {\n Button as AButton,\n Card as ACard,\n Dropdown as ADropdown,\n Menu as AMenu,\n MenuItem as AMenuItem,\n Spin as ASpin,\n Tooltip as ATooltip\n} from \"ant-design-vue\";\nimport { computed, onErrorCaptured, ref, watch, type Component } from \"vue\";\n\nimport type {\n DashboardContext,\n PanelConfig,\n PanelRuntimeState,\n VisualizationEvent,\n VisualizationRendererDefinition\n} from \"../../core\";\nimport type { ChartRendererExpose } from \"../renderers\";\n\nconst props = defineProps<{\n panel: PanelConfig;\n state: PanelRuntimeState;\n context: DashboardContext;\n definition: VisualizationRendererDefinition;\n renderer: Component;\n filterSummary?: string;\n refreshDisabled?: boolean;\n}>();\nconst emit = defineEmits<{\n refresh: [];\n retry: [];\n exportCsv: [];\n exportPng: [];\n action: [actionId: string];\n visualizationEvent: [event: VisualizationEvent];\n}>();\n\nconst rendererRef = ref<ChartRendererExpose>();\nconst rendererError = ref<Error>();\nconst isMetricPanel = computed(() => props.panel.rendererId === \"metric\");\nconst panelFailure = computed(() => {\n if (rendererError.value) {\n return { title: \"图表暂时无法展示\", detail: rendererError.value.message };\n }\n if (props.state.status === \"error\" || props.state.status === \"cancelled\") {\n return { title: \"数据暂时无法加载\", detail: props.state.error?.message };\n }\n return undefined;\n});\nconst canDownload = computed(\n () =>\n (props.definition.capabilities.csv && Boolean(props.state.dataset)) ||\n (props.definition.capabilities.png && Boolean(props.state.viewModel))\n);\nconst bodyStyle = computed(() => {\n const panelMinHeight = props.panel.layout.minHeight ?? (isMetricPanel.value ? 119 : 401);\n const headerHeight = isMetricPanel.value ? 40 : 50;\n return { minHeight: `${Math.max(panelMinHeight - headerHeight - 2, isMetricPanel.value ? 77 : 190)}px` };\n});\nconst updatedAt = computed(() =>\n props.state.lastSuccessfulAt\n ? new Intl.DateTimeFormat(props.context.locale, { timeStyle: \"medium\", timeZone: props.context.timezone }).format(\n new Date(props.state.lastSuccessfulAt)\n )\n : \"\"\n);\n\nfunction exportPng(): string | undefined {\n return rendererRef.value?.exportPng?.();\n}\nfunction onDownloadMenuClick(event: { key: string | number }): void {\n if (event.key === \"csv\") emit(\"exportCsv\");\n if (event.key === \"png\") emit(\"exportPng\");\n}\nonErrorCaptured((error) => {\n rendererError.value = error instanceof Error ? error : new Error(String(error));\n return false;\n});\nwatch(\n () => [props.state.generation, props.state.viewModel] as const,\n () => {\n rendererError.value = undefined;\n }\n);\ndefineExpose({ exportPng });\n</script>\n\n<style scoped>\n.dv-panel {\n height: 100%;\n overflow: hidden;\n border: 1px solid var(--dv-card-border, #e1e6ed);\n border-radius: 7px;\n background: #fff;\n box-shadow:\n 0 1px 2px rgb(16 24 40 / 3.5%),\n 0 5px 14px rgb(16 24 40 / 2.5%);\n}\n.dv-panel :deep(.ant-card-head) {\n min-height: 50px;\n padding: 0 16px;\n border-bottom-color: var(--dv-card-divider, #edf0f4);\n}\n.dv-panel :deep(.ant-card-head-title),\n.dv-panel :deep(.ant-card-extra) {\n padding: 10px 0;\n}\n.dv-panel :deep(.ant-card-head-title) {\n padding: 13px 0;\n}\n.dv-panel :deep(.ant-card-body) {\n position: relative;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n padding: 15px 16px;\n}\n.dv-panel__heading,\n.dv-panel__title-group,\n.dv-panel__actions {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.dv-panel__heading {\n min-width: 0;\n flex-wrap: wrap;\n row-gap: 2px;\n line-height: 20px;\n}\n.dv-panel__title-group {\n min-width: 0;\n}\n.dv-panel__title-group :deep(.anticon) {\n flex-shrink: 0;\n}\n.dv-panel__title-note {\n min-width: 0;\n max-width: 100%;\n color: #98a2b3;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n overflow-wrap: anywhere;\n white-space: normal;\n}\n.dv-panel__title {\n overflow: hidden;\n color: var(--dv-text-title, #273244);\n font-size: 14px;\n font-weight: 650;\n line-height: 20px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dv-panel__heading :deep(svg) {\n color: #8a94a6;\n font-size: 13px;\n}\n.dv-panel__actions {\n gap: 4px;\n}\n.dv-panel__actions :deep(.ant-btn) {\n width: 28px;\n height: 28px;\n padding: 0;\n border-radius: 5px;\n color: #6e7889;\n}\n.dv-panel__actions :deep(.ant-btn:hover) {\n color: var(--dv-primary, #315fc4);\n background: #f0f4fa;\n}\n.dv-panel__filters {\n display: none;\n}\n.dv-panel__warning {\n color: #f59e0b;\n font-size: 15px;\n}\n.dv-panel__state {\n min-height: 190px;\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.dv-panel__state--empty {\n box-sizing: border-box;\n flex-direction: column;\n gap: 14px;\n padding: 24px 12px;\n text-align: center;\n}\n.dv-panel__empty-icon {\n display: grid;\n width: 56px;\n height: 56px;\n flex-shrink: 0;\n place-items: center;\n border: 1px solid var(--dv-card-divider, #edf0f4);\n border-radius: 16px;\n color: #8da2c5;\n background: linear-gradient(145deg, #f8fafd, #eff3f9);\n font-size: 26px;\n}\n.dv-panel__empty-copy {\n max-width: 100%;\n}\n.dv-panel__empty-title {\n color: var(--dv-text-secondary, #657184);\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n}\n.dv-panel :deep(.ant-spin) {\n color: var(--dv-primary, #315fc4);\n}\n.dv-panel :deep(.ant-spin-dot-item) {\n background-color: currentColor;\n}\n.dv-panel__failure {\n display: flex;\n max-width: min(320px, 100%);\n flex-direction: column;\n align-items: center;\n color: #667085;\n text-align: center;\n}\n.dv-panel__failure-copy {\n max-width: 100%;\n min-width: 0;\n}\n.dv-panel__failure-heading {\n overflow: hidden;\n color: #526075;\n font-size: 13px;\n font-weight: 600;\n line-height: 20px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dv-panel__failure-icon {\n margin-bottom: 9px;\n color: #8592a5;\n font-size: 22px;\n}\n.dv-panel__failure-detail {\n max-width: 100%;\n overflow: hidden;\n margin-top: 1px;\n color: #98a2b3;\n font-size: 12px;\n line-height: 18px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dv-panel__retry {\n width: auto;\n height: 28px;\n margin-top: 10px;\n padding: 0 10px;\n border-color: #dbe1e8;\n border-radius: 5px;\n color: #59677a;\n background: #fff;\n box-shadow: none;\n font-size: 12px;\n}\n.dv-panel__retry:hover,\n.dv-panel__retry:focus {\n border-color: #b8c7e5;\n color: var(--dv-primary, #315fc4);\n background: #f7f9fc;\n}\n.dv-panel__idle {\n color: #98a0ad;\n font-size: 12px;\n}\n.dv-panel__renderer {\n position: relative;\n min-width: 0;\n flex: 1;\n}\n.dv-panel__refreshing {\n position: absolute;\n z-index: 1;\n inset: 0;\n display: grid;\n place-items: center;\n background: rgb(255 255 255 / 76%);\n}\n.dv-panel__updated {\n display: none;\n margin-top: 8px;\n color: #98a0ad;\n font-size: 11px;\n text-align: right;\n}\n.dv-panel--metric :deep(.ant-card-head) {\n min-height: 40px;\n border-bottom: 0;\n}\n.dv-panel--metric :deep(.ant-card-head-title) {\n padding: 13px 0 4px;\n}\n.dv-panel--metric :deep(.ant-card-extra) {\n padding: 8px 0 0;\n}\n.dv-panel--metric :deep(.ant-card-body) {\n padding: 2px 16px 13px;\n}\n.dv-panel--metric .dv-panel__state--loading {\n min-height: 0;\n}\n.dv-panel--metric .dv-panel__state--failure {\n min-height: 0;\n}\n.dv-panel--metric .dv-panel__failure {\n width: fit-content;\n max-width: 100%;\n display: grid;\n grid-template-columns: 20px minmax(0, 1fr) 28px;\n column-gap: 8px;\n text-align: left;\n}\n.dv-panel--metric .dv-panel__failure-icon {\n margin-bottom: 0;\n font-size: 16px;\n}\n.dv-panel--metric .dv-panel__failure-detail {\n display: none;\n}\n.dv-panel--metric .dv-panel__retry {\n width: 28px;\n margin-top: 0;\n padding: 0;\n border-color: transparent;\n background: transparent;\n}\n.dv-panel--metric .dv-panel__retry-label {\n display: none;\n}\n.dv-panel--metric .dv-panel__state--metric-empty {\n min-height: 0;\n color: #98a0ad;\n font-size: 12px;\n line-height: 20px;\n}\n.dv-panel--metric .dv-panel__title {\n color: #637083;\n font-size: 13px;\n font-weight: 550;\n}\n.dv-panel--metric .dv-panel__actions {\n opacity: 0;\n transition: opacity 0.16s ease;\n}\n.dv-panel--metric:hover .dv-panel__actions,\n.dv-panel--metric:focus-within .dv-panel__actions {\n opacity: 1;\n}\n</style>\n","import { computed, onBeforeUnmount, onMounted, shallowRef } from \"vue\";\n\nimport type {\n DashboardRuntime,\n DashboardRuntimeSnapshot,\n DashboardVariablePatch,\n RefreshPanelsOptions\n} from \"../../core\";\n\nexport interface UseDashboardRuntimeOptions {\n autoLoad?: boolean;\n}\n\nexport function useDashboardRuntime(runtime: DashboardRuntime, options: UseDashboardRuntimeOptions = {}) {\n const snapshot = shallowRef<DashboardRuntimeSnapshot>(runtime.snapshot);\n let unsubscribe: (() => void) | undefined;\n\n onMounted(() => {\n unsubscribe = runtime.subscribe((next) => {\n snapshot.value = next;\n });\n if (options.autoLoad !== false) void runtime.load();\n });\n onBeforeUnmount(() => unsubscribe?.());\n\n return {\n snapshot,\n context: computed(() => snapshot.value.context),\n panelStates: computed(() => snapshot.value.panelStates),\n isLoading: computed(() => snapshot.value.isGlobalLoading),\n loadPanels: (panelIds: Iterable<string>) => runtime.loadPanels(panelIds),\n refreshAll: () => runtime.refreshAll(),\n refreshPanels: (panelIds: Iterable<string>, refreshOptions?: RefreshPanelsOptions) =>\n runtime.refreshPanels(panelIds, refreshOptions),\n refreshPanel: (panelId: string) => runtime.refreshPanel(panelId),\n retryPanel: (panelId: string) => runtime.retryPanel(panelId),\n setVariables: (patch: DashboardVariablePatch, panelIds?: Iterable<string>) => runtime.setVariables(patch, panelIds)\n };\n}\n","export function downloadBlob(content: BlobPart, mimeType: string, filename: string): void {\n const url = URL.createObjectURL(new Blob([content], { type: mimeType }));\n triggerDownload(url, filename);\n window.setTimeout(() => URL.revokeObjectURL(url), 0);\n}\n\nexport function downloadDataUrl(dataUrl: string, filename: string): void {\n triggerDownload(dataUrl, filename);\n}\n\nfunction triggerDownload(url: string, filename: string): void {\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n anchor.hidden = true;\n document.body.append(anchor);\n anchor.click();\n anchor.remove();\n}\n","<template>\n <section ref=\"dashboardElement\" class=\"dv-dashboard\">\n <header v-if=\"showHeader\" class=\"dv-dashboard__header\">\n <div>\n <h1>{{ runtime.config.title }}</h1>\n <p v-if=\"runtime.config.description\">{{ runtime.config.description }}</p>\n </div>\n </header>\n <DashboardFilterBar\n v-if=\"runtime.config.filterBar\"\n :config=\"runtime.config.filterBar\"\n :context=\"context\"\n :loading=\"isLoading\"\n @change=\"onVariablesChange\"\n @refresh=\"refreshAll\"\n />\n <div class=\"dv-dashboard__grid\">\n <div\n v-for=\"panel in runtime.config.panels\"\n :key=\"panel.id\"\n class=\"dv-dashboard__cell\"\n :data-panel-id=\"panel.id\"\n :style=\"panelStyle(panel)\"\n >\n <DashboardPanel\n :ref=\"(value) => setPanelRef(panel.id, value)\"\n :context=\"context\"\n :definition=\"runtime.dataRuntime.registries.rendererDefinitions.require(panel.rendererId)\"\n :filter-summary=\"filterSummary\"\n :panel=\"panel\"\n :refresh-disabled=\"isLoading\"\n :renderer=\"resolvePanelComponent(panel)\"\n :state=\"panelStates[panel.id]!\"\n @action=\"(actionId) => runtime.executePanelAction(panel.id, actionId)\"\n @export-csv=\"exportCsv(panel.id)\"\n @export-png=\"exportPng(panel.id)\"\n @refresh=\"refreshPanel(panel.id)\"\n @retry=\"retryPanel(panel.id)\"\n @visualization-event=\"(event) => runtime.dispatchEvent(event)\"\n />\n </div>\n </div>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, markRaw, onBeforeMount, onBeforeUnmount, onMounted, ref, toRaw, type Component } from \"vue\";\n\nimport {\n buildDashboardSearch,\n createPanelCsvFilename,\n serializePanelCsv,\n type DashboardRuntime,\n type DashboardVariablePatch,\n type PanelConfig\n} from \"../../core\";\nimport { useDashboardRuntime } from \"../composables\";\nimport { downloadBlob, downloadDataUrl } from \"../export\";\nimport type { DashboardPanelComponentMap, VueRendererRegistry } from \"../registry\";\nimport DashboardFilterBar from \"./DashboardFilterBar.vue\";\nimport DashboardPanel from \"./DashboardPanel.vue\";\n\nconst props = withDefaults(\n defineProps<{\n runtime: DashboardRuntime;\n rendererRegistry: VueRendererRegistry;\n panelComponents?: DashboardPanelComponentMap;\n autoLoad?: boolean;\n lazyLoad?: boolean;\n lazyLoadRootMargin?: string;\n syncUrl?: boolean;\n showHeader?: boolean;\n }>(),\n { autoLoad: true, lazyLoad: true, lazyLoadRootMargin: \"600px 0px\", syncUrl: true, showHeader: true }\n);\n\nconst panelRefs = new Map<string, InstanceType<typeof DashboardPanel>>();\nconst dashboardElement = ref<HTMLElement>();\nconst nearPanelIds = new Set<string>();\nconst pendingPanelIds = new Set<string>();\nlet intersectionObserver: IntersectionObserver | undefined;\nlet lazyObserverActive = false;\nlet loadQueued = false;\nonBeforeMount(() => {\n if (props.syncUrl && typeof window !== \"undefined\") props.runtime.restoreContext(window.location.search);\n});\nconst {\n context,\n panelStates,\n isLoading,\n loadPanels,\n refreshAll: refreshRuntimeAll,\n refreshPanels,\n refreshPanel,\n retryPanel,\n setVariables\n} = useDashboardRuntime(props.runtime, { autoLoad: props.autoLoad && !props.lazyLoad });\n\nonMounted(() => {\n if (!props.autoLoad || !props.lazyLoad) return;\n if (typeof IntersectionObserver === \"undefined\") {\n void refreshRuntimeAll();\n return;\n }\n lazyObserverActive = true;\n intersectionObserver = new IntersectionObserver(onPanelIntersection, {\n rootMargin: props.lazyLoadRootMargin\n });\n dashboardElement.value\n ?.querySelectorAll<HTMLElement>(\".dv-dashboard__cell\")\n .forEach((element) => intersectionObserver?.observe(element));\n});\nonBeforeUnmount(() => {\n intersectionObserver?.disconnect();\n intersectionObserver = undefined;\n lazyObserverActive = false;\n nearPanelIds.clear();\n pendingPanelIds.clear();\n});\n\nconst filterSummary = computed(() =>\n (props.runtime.config.variables ?? [])\n .map((variable) => `${variable.label}: ${formatVariable(context.value.variables[variable.id])}`)\n .join(\" · \")\n);\n\nfunction formatVariable(value: unknown): string {\n return Array.isArray(value) ? value.join(\", \") : String(value ?? \"--\");\n}\nfunction panelStyle(panel: PanelConfig) {\n const span = panel.layout.span;\n return {\n \"--dv-panel-xs\": String(span.xs),\n \"--dv-panel-sm\": String(span.sm ?? span.xs),\n \"--dv-panel-md\": String(span.md ?? span.sm ?? span.xs),\n \"--dv-panel-lg\": String(span.lg ?? span.md ?? span.sm ?? span.xs),\n \"--dv-panel-xl\": String(span.xl ?? span.lg ?? span.md ?? span.sm ?? span.xs)\n };\n}\nfunction resolvePanelComponent(panel: PanelConfig): Component {\n const component = props.panelComponents?.[panel.id] ?? props.rendererRegistry.require(panel.rendererId).component;\n return markRaw(toRaw(component));\n}\nfunction setPanelRef(panelId: string, value: unknown): void {\n if (value) panelRefs.set(panelId, value as InstanceType<typeof DashboardPanel>);\n else panelRefs.delete(panelId);\n}\nfunction onPanelIntersection(entries: IntersectionObserverEntry[]): void {\n entries.forEach((entry) => {\n const panelId = (entry.target as HTMLElement).dataset.panelId;\n if (!panelId) return;\n if (entry.isIntersecting) {\n nearPanelIds.add(panelId);\n pendingPanelIds.add(panelId);\n } else {\n nearPanelIds.delete(panelId);\n pendingPanelIds.delete(panelId);\n }\n });\n if (!pendingPanelIds.size || loadQueued) return;\n loadQueued = true;\n queueMicrotask(() => {\n loadQueued = false;\n const panelIds = Array.from(pendingPanelIds);\n pendingPanelIds.clear();\n void loadPanels(panelIds);\n });\n}\nfunction refreshAll(): ReturnType<DashboardRuntime[\"refreshAll\"]> {\n return lazyObserverActive ? refreshPanels(nearPanelIds, { deferUnselected: true }) : refreshRuntimeAll();\n}\nasync function onVariablesChange(patch: DashboardVariablePatch): Promise<void> {\n const pendingRefresh = setVariables(patch, lazyObserverActive ? nearPanelIds : undefined);\n if (props.syncUrl && typeof window !== \"undefined\") {\n const search = buildDashboardSearch(props.runtime.config, props.runtime.context, window.location.search);\n window.history.replaceState(\n window.history.state,\n \"\",\n `${window.location.pathname}${search}${window.location.hash}`\n );\n }\n await pendingRefresh;\n}\nfunction exportCsv(panelId: string): void {\n const panel = props.runtime.config.panels.find((candidate) => candidate.id === panelId)!;\n const dataset = panelStates.value[panelId]?.dataset;\n if (!dataset) return;\n const csv = serializePanelCsv(dataset, panel, context.value);\n downloadBlob(csv, \"text/csv;charset=utf-8\", createPanelCsvFilename(props.runtime.config.id, panel.id));\n}\nfunction exportPng(panelId: string): void {\n const dataUrl = panelRefs.get(panelId)?.exportPng();\n if (dataUrl) downloadDataUrl(dataUrl, `${props.runtime.config.id}-${panelId}.png`);\n}\n\ndefineExpose({ refreshAll, refreshPanel, exportCsv, exportPng });\n</script>\n\n<style scoped>\n.dv-dashboard {\n --dv-card-border: #e1e6ed;\n --dv-card-divider: #edf0f4;\n --dv-text-title: #273244;\n --dv-text-body: #182230;\n --dv-text-secondary: #657184;\n --dv-text-muted: #8a94a6;\n width: 100%;\n min-width: 0;\n color: var(--dv-text-body);\n}\n.dv-dashboard__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 16px;\n}\n.dv-dashboard__header h1 {\n margin: 0;\n font-size: 22px;\n font-weight: 650;\n line-height: 30px;\n letter-spacing: 0;\n}\n.dv-dashboard__header p {\n margin: 4px 0 0;\n color: #64748b;\n font-size: 13px;\n}\n.dv-dashboard__grid {\n display: grid;\n grid-template-columns: repeat(24, minmax(0, 1fr));\n gap: 14px;\n margin-top: 14px;\n}\n.dv-dashboard__cell {\n grid-column: span var(--dv-panel-xs);\n min-width: 0;\n}\n@media (min-width: 576px) {\n .dv-dashboard__cell {\n grid-column: span var(--dv-panel-sm);\n }\n}\n@media (min-width: 768px) {\n .dv-dashboard__cell {\n grid-column: span var(--dv-panel-md);\n }\n}\n@media (min-width: 992px) {\n .dv-dashboard__cell {\n grid-column: span var(--dv-panel-lg);\n }\n}\n@media (min-width: 1200px) {\n .dv-dashboard__cell {\n grid-column: span var(--dv-panel-xl);\n }\n}\n@media (max-width: 767px) {\n .dv-dashboard__grid {\n gap: 12px;\n }\n}\n</style>\n","import { FormatType } from \"@blazes/charts\";\n\nimport type { ValueFormat } from \"../../core\";\n\nexport function toChartFormat(format: ValueFormat): FormatType {\n if (format.type === \"percent\") return FormatType.PERCENT;\n if (format.type === \"decimal\") return FormatType.DECIMAL;\n return FormatType.COMMAS;\n}\n\nexport interface ChartRendererExpose {\n exportPng(): string | undefined;\n}\n\nexport function chartEventFields(value: unknown): Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : {};\n}\n","<template>\n <div class=\"dv-chart-renderer dv-bar-renderer\">\n <ChartBar ref=\"chartRef\" :option=\"option\" :size=\"Size.SMALL\" @data-point-click=\"onClick\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ChartBar, Size, type Bar } from \"@blazes/charts\";\nimport { computed, ref } from \"vue\";\n\nimport {\n valueFormatter,\n type BarViewModel,\n type DashboardContext,\n type PanelConfig,\n type VisualizationEvent\n} from \"../../core\";\nimport { STANDARD_CATEGORY_AXIS, STANDARD_CHART_COLORS, STANDARD_CHART_TOOLTIP, STANDARD_VALUE_AXIS } from \"../theme\";\nimport { chartEventFields, toChartFormat, type ChartRendererExpose } from \"./chart-format\";\n\nconst props = defineProps<{ viewModel: BarViewModel; panel: PanelConfig; context: DashboardContext }>();\nconst emit = defineEmits<{ visualizationEvent: [event: VisualizationEvent] }>();\nconst chartRef = ref<ChartRendererExpose>();\n\nfunction formatValue(value: unknown, series: BarViewModel[\"series\"][number], axis = false): string {\n const formatted = axis\n ? valueFormatter.formatAxis(value, series.format, props.context)\n : valueFormatter.formatTooltip(value, series.format, props.context);\n const formatOwnsUnit = series.format.type === \"currency\" || series.format.type === \"percent\" || series.format.unit;\n return value !== null && value !== undefined && value !== \"\" && series.unit && !formatOwnsUnit\n ? `${formatted}${series.unit}`\n : formatted;\n}\n\nconst option = computed<Bar.Option>(() => ({\n categories: [...props.viewModel.categories],\n colors: [...STANDARD_CHART_COLORS],\n orientation: props.viewModel.orientation,\n ...(props.viewModel.visibleCount !== undefined ? { visibleCount: props.viewModel.visibleCount } : {}),\n grid: {\n top: 18,\n right: props.viewModel.orientation === \"horizontal\" && props.viewModel.showLabels ? 78 : 18,\n bottom: 10,\n left: 16,\n containLabel: true\n },\n categoryAxis: {\n ...STANDARD_CATEGORY_AXIS,\n ...(props.viewModel.orientation === \"horizontal\" && props.viewModel.visibleCount !== undefined\n ? { inverse: true }\n : {}),\n axisLabel: { ...STANDARD_CATEGORY_AXIS.axisLabel, interval: 0 }\n },\n valueAxis: {\n ...STANDARD_VALUE_AXIS,\n splitNumber: 4,\n axisLabel: {\n ...STANDARD_VALUE_AXIS.axisLabel,\n hideOverlap: true,\n ...(props.viewModel.series[0]\n ? { formatter: (value: unknown) => formatValue(value, props.viewModel.series[0]!, true) }\n : {})\n }\n },\n tooltip: {\n ...STANDARD_CHART_TOOLTIP,\n axisPointer: { type: \"shadow\", shadowStyle: { color: \"rgba(91, 114, 238, 0.055)\" } }\n },\n ...(props.viewModel.stacked ? { stack: \"total\" } : {}),\n series: props.viewModel.series.map((series) => ({\n name: series.label,\n data: [...series.values],\n formatType: toChartFormat(series.format),\n valueFormatter: (value: unknown) => formatValue(value, series),\n showLabel: props.viewModel.showLabels,\n itemStyle: {\n borderRadius: props.viewModel.orientation === \"horizontal\" ? [0, 5, 5, 0] : [5, 5, 0, 0]\n }\n }))\n}));\n\nfunction onClick(raw: unknown): void {\n const event = chartEventFields(raw);\n const seriesIndex = typeof event.seriesIndex === \"number\" ? event.seriesIndex : 0;\n const binding = props.panel.binding.type === \"bar\" ? props.panel.binding : undefined;\n if (!binding) return;\n emit(\"visualizationEvent\", {\n type: \"dataPointClick\",\n panelId: props.panel.id,\n datasetId: binding.datasetId,\n fields: Object.freeze({\n [binding.categoryField]: event.name,\n ...(binding.seriesField ? { [binding.seriesField]: event.seriesName } : {}),\n [binding.valueFields[binding.seriesField ? 0 : seriesIndex] ?? binding.valueFields[0]!]: event.value\n })\n });\n}\n\nfunction exportPng(): string | undefined {\n return chartRef.value?.exportPng();\n}\ndefineExpose({ exportPng });\n</script>\n\n<style scoped>\n.dv-chart-renderer {\n width: 100%;\n min-width: 0;\n}\n.dv-bar-renderer :deep(.bar-container) {\n height: 320px !important;\n}\n.dv-bar-renderer :deep(.legend) {\n min-height: 18px;\n margin-bottom: 2px;\n padding: 0 4px;\n}\n.dv-bar-renderer :deep(.legend-container) {\n justify-content: flex-end;\n}\n.dv-bar-renderer :deep(.legend-item) {\n margin-right: 12px;\n color: #667085;\n font-size: 11px;\n}\n.dv-bar-renderer :deep(.legend-item-color) {\n width: 9px;\n height: 9px;\n border-radius: 3px;\n}\n</style>\n","<template>\n <div class=\"dv-chart-renderer dv-line-renderer\">\n <ChartLine ref=\"chartRef\" :option=\"option\" :size=\"Size.SMALL\" @data-point-click=\"onClick\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ChartLine, Size, type Line } from \"@blazes/charts\";\nimport { computed, ref } from \"vue\";\n\nimport {\n valueFormatter,\n type DashboardContext,\n type LineViewModel,\n type PanelConfig,\n type VisualizationEvent\n} from \"../../core\";\nimport { STANDARD_CATEGORY_AXIS, STANDARD_CHART_COLORS, STANDARD_CHART_TOOLTIP, STANDARD_VALUE_AXIS } from \"../theme\";\nimport { chartEventFields, toChartFormat, type ChartRendererExpose } from \"./chart-format\";\n\nconst props = defineProps<{ viewModel: LineViewModel; panel: PanelConfig; context: DashboardContext }>();\nconst emit = defineEmits<{ visualizationEvent: [event: VisualizationEvent] }>();\nconst chartRef = ref<ChartRendererExpose>();\n\nfunction formatAxisValue(value: unknown, series: LineViewModel[\"series\"][number]): string {\n const formatted = valueFormatter.formatAxis(value, series.format, props.context);\n return appendSeriesUnit(formatted, series);\n}\n\nfunction appendSeriesUnit(formatted: string, series: LineViewModel[\"series\"][number]): string {\n const formatOwnsUnit = series.format.type === \"currency\" || series.format.type === \"percent\" || series.format.unit;\n return series.unit && !formatOwnsUnit ? `${formatted}${series.unit}` : formatted;\n}\n\nconst option = computed<Line.Option>(() => {\n const axisSeries = Array.from(\n new Map(props.viewModel.series.map((series) => [series.axisKey, series] as const)).values()\n );\n const axisIndexes = new Map(axisSeries.map((series, index) => [series.axisKey, index]));\n\n return {\n colors: [...STANDARD_CHART_COLORS],\n grid: { top: 18, right: axisSeries.length > 1 ? 24 : 16, bottom: 10, left: 16, containLabel: true },\n tooltip: {\n ...STANDARD_CHART_TOOLTIP,\n axisPointer: { type: \"line\", lineStyle: { color: \"#b8c1d1\", type: \"dashed\" } }\n },\n xAxis: {\n data: props.viewModel.categories.map(String),\n ...STANDARD_CATEGORY_AXIS,\n ...(props.viewModel.categoryFormat\n ? {\n valueFormatter: (value: unknown) =>\n valueFormatter.formatAxis(value, props.viewModel.categoryFormat!, props.context)\n }\n : {})\n },\n yAxis: axisSeries.map((series, index) => ({\n ...STANDARD_VALUE_AXIS,\n position: index === 0 ? \"left\" : \"right\",\n show: index < 2,\n axisLabel: {\n ...STANDARD_VALUE_AXIS.axisLabel,\n formatter: (value: unknown) => formatAxisValue(value, series)\n },\n splitLine: {\n show: index === 0,\n lineStyle: { color: \"#edf0f5\", type: \"dashed\" }\n }\n })),\n series: props.viewModel.series.map((series, index) => ({\n name: series.label,\n data: series.values.map((value) => value ?? undefined),\n formatType: toChartFormat(series.format),\n valueFormatter: (value: unknown) => {\n const formatted = valueFormatter.formatTooltip(value, series.format, props.context);\n return value === null || value === undefined || value === \"\" ? formatted : appendSeriesUnit(formatted, series);\n },\n showLabel: props.viewModel.showLabels,\n smooth: props.viewModel.smooth,\n yAxisIndex: axisIndexes.get(series.axisKey) ?? 0,\n showSymbol: false,\n symbol: \"circle\",\n symbolSize: 7,\n lineStyle: { width: index === 0 ? 3 : 2.25 },\n ...(index === 0\n ? {\n areaStyle: {\n opacity: 1,\n color: {\n type: \"linear\",\n x: 0,\n y: 0,\n x2: 0,\n y2: 1,\n colorStops: [\n { offset: 0, color: \"rgba(79, 107, 237, 0.22)\" },\n { offset: 1, color: \"rgba(79, 107, 237, 0.015)\" }\n ]\n }\n }\n }\n : {})\n })),\n markLine: {\n xAxis: props.viewModel.annotations.filter((item) => item.type === \"category\").map((item) => String(item.value)),\n yAxis: props.viewModel.annotations.filter((item) => item.type === \"value\").map((item) => String(item.value))\n }\n };\n});\n\nfunction onClick(raw: unknown): void {\n const event = chartEventFields(raw);\n const seriesIndex = typeof event.seriesIndex === \"number\" ? event.seriesIndex : 0;\n const binding = props.panel.binding.type === \"line\" ? props.panel.binding : undefined;\n if (!binding) return;\n emit(\"visualizationEvent\", {\n type: \"dataPointClick\",\n panelId: props.panel.id,\n datasetId: binding.datasetId,\n fields: Object.freeze({\n [binding.xField]: event.name,\n ...(binding.seriesField ? { [binding.seriesField]: event.seriesName } : {}),\n [binding.yFields[binding.seriesField ? 0 : seriesIndex] ?? binding.yFields[0]!]: event.value\n })\n });\n}\n\nfunction exportPng(): string | undefined {\n return chartRef.value?.exportPng();\n}\ndefineExpose({ exportPng });\n</script>\n\n<style scoped>\n.dv-chart-renderer {\n width: 100%;\n min-width: 0;\n}\n.dv-line-renderer :deep(.line-container) {\n height: 320px;\n}\n.dv-line-renderer :deep(.legend) {\n min-height: 18px;\n margin-bottom: 2px;\n padding: 0 4px;\n}\n.dv-line-renderer :deep(.legend-container) {\n justify-content: flex-end;\n}\n.dv-line-renderer :deep(.legend-item) {\n margin-right: 12px;\n color: #667085;\n font-size: 11px;\n}\n.dv-line-renderer :deep(.legend-item-color) {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n</style>\n","<template>\n <div class=\"dv-metric\">\n <div class=\"dv-metric__value\">\n <span class=\"dv-metric__number\">{{ formattedValue }}</span>\n <span v-if=\"displayUnit\" class=\"dv-metric__unit\">{{ displayUnit }}</span>\n </div>\n <div v-if=\"viewModel.comparison\" class=\"dv-metric__comparison\">\n <span>{{ viewModel.comparison.label }}</span>\n <strong :class=\"`dv-metric__comparison--${comparisonTone}`\">\n <component :is=\"comparisonIcon\" />\n {{ formattedComparison }}\n </strong>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { FallOutlined, MinusOutlined, RiseOutlined } from \"@ant-design/icons-vue\";\nimport { computed } from \"vue\";\n\nimport { valueFormatter, type DashboardContext, type MetricViewModel, type PanelConfig } from \"../../core\";\n\nconst props = defineProps<{\n viewModel: MetricViewModel;\n panel: PanelConfig;\n context: DashboardContext;\n}>();\n\nconst formattedValue = computed(() =>\n valueFormatter.formatDisplay(props.viewModel.value, props.viewModel.format, props.context)\n);\nconst displayUnit = computed(() =>\n props.viewModel.format.type === \"currency\" || props.viewModel.format.type === \"percent\"\n ? undefined\n : props.viewModel.unit\n);\nconst formattedComparison = computed(() => {\n const comparison = props.viewModel.comparison;\n return comparison ? valueFormatter.formatDisplay(comparison.value, comparison.format, props.context) : \"\";\n});\nconst comparisonIcon = computed(() => {\n if (props.viewModel.comparison?.direction === \"up\") return RiseOutlined;\n if (props.viewModel.comparison?.direction === \"down\") return FallOutlined;\n return MinusOutlined;\n});\nconst comparisonTone = computed(() => {\n const comparison = props.viewModel.comparison;\n if (!comparison || comparison.direction === \"flat\") return \"neutral\";\n if (comparison.colorMode === \"direction\") {\n return comparison.direction === \"up\" ? \"unfavorable\" : \"favorable\";\n }\n if (comparison.meaning === \"neutral\") return \"neutral\";\n const favorable =\n (comparison.meaning === \"positive\" && comparison.direction === \"up\") ||\n (comparison.meaning === \"negative\" && comparison.direction === \"down\");\n return favorable ? \"favorable\" : \"unfavorable\";\n});\n</script>\n\n<style scoped>\n.dv-metric {\n min-height: 62px;\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n}\n.dv-metric__value {\n display: flex;\n align-items: baseline;\n column-gap: 4px;\n color: #172033;\n font-size: 29px;\n font-weight: 650;\n letter-spacing: 0;\n line-height: 1.2;\n white-space: nowrap;\n}\n.dv-metric__number {\n font-feature-settings: \"tnum\";\n font-variant-numeric: tabular-nums;\n}\n.dv-metric__unit {\n position: relative;\n top: -1px;\n color: #7d8797;\n font-size: 12px;\n font-weight: 400;\n line-height: 1;\n}\n.dv-metric__comparison {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-top: 7px;\n color: #7b8493;\n font-size: 12px;\n line-height: 18px;\n}\n.dv-metric__comparison strong {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 600;\n}\n.dv-metric__comparison--favorable {\n color: #00a870;\n}\n.dv-metric__comparison--unfavorable {\n color: #f53f3f;\n}\n.dv-metric__comparison--neutral {\n color: #7b8493;\n}\n</style>\n","<template>\n <div class=\"dv-chart-renderer dv-pie-renderer\">\n <ChartPie ref=\"chartRef\" :option=\"option\" :size=\"Size.SMALL\" @data-point-click=\"onClick\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ChartPie, Size, type Pie } from \"@blazes/charts\";\nimport { computed, ref } from \"vue\";\n\nimport {\n valueFormatter,\n type DashboardContext,\n type PanelConfig,\n type PieViewModel,\n type VisualizationEvent\n} from \"../../core\";\nimport { STANDARD_CHART_COLORS, STANDARD_CHART_TOOLTIP } from \"../theme\";\nimport { chartEventFields, toChartFormat, type ChartRendererExpose } from \"./chart-format\";\n\nconst props = defineProps<{ viewModel: PieViewModel; panel: PanelConfig; context: DashboardContext }>();\nconst emit = defineEmits<{ visualizationEvent: [event: VisualizationEvent] }>();\nconst chartRef = ref<ChartRendererExpose>();\n\nfunction formatValue(value: unknown): string {\n const formatted = valueFormatter.formatTooltip(value, props.viewModel.valueFormat, props.context);\n const formatOwnsUnit =\n props.viewModel.valueFormat.type === \"currency\" ||\n props.viewModel.valueFormat.type === \"percent\" ||\n props.viewModel.valueFormat.unit;\n return props.viewModel.unit && !formatOwnsUnit ? `${formatted}${props.viewModel.unit}` : formatted;\n}\n\nconst option = computed<Pie.Option>(() => ({\n colors: [...STANDARD_CHART_COLORS],\n donut: props.viewModel.donut,\n showLegend: props.viewModel.showLegend,\n showLabels: false,\n center: [\"50%\", \"43%\"],\n radius: props.viewModel.donut ? [\"50%\", \"70%\"] : \"70%\",\n itemStyle: { borderColor: \"#fff\", borderWidth: 3, borderRadius: 4 },\n tooltip: { ...STANDARD_CHART_TOOLTIP },\n series: props.viewModel.items.map((item) => ({\n name: item.label,\n data: item.value,\n formatType: toChartFormat(props.viewModel.valueFormat),\n valueFormatter: formatValue\n })),\n ...(props.viewModel.donut\n ? {\n aggregation: {\n total: props.viewModel.items.reduce((sum, item) => sum + item.value, 0),\n label: props.panel.title.replace(/占比$/, \"\"),\n valueFormatter: formatValue,\n ...(props.viewModel.unit ? { unit: props.viewModel.unit } : {})\n }\n }\n : {})\n}));\n\nfunction onClick(raw: unknown): void {\n const event = chartEventFields(raw);\n const binding = props.panel.binding.type === \"pie\" ? props.panel.binding : undefined;\n if (!binding) return;\n emit(\"visualizationEvent\", {\n type: \"dataPointClick\",\n panelId: props.panel.id,\n datasetId: binding.datasetId,\n fields: Object.freeze({ [binding.nameField]: event.name, [binding.valueField]: event.value })\n });\n}\n\nfunction exportPng(): string | undefined {\n return chartRef.value?.exportPng();\n}\ndefineExpose({ exportPng });\n</script>\n\n<style scoped>\n.dv-chart-renderer {\n width: 100%;\n min-width: 0;\n}\n.dv-pie-renderer :deep(.pie-container) {\n height: 320px !important;\n flex-direction: column-reverse;\n}\n.dv-pie-renderer :deep(.legend) {\n min-height: 18px;\n margin: 4px 0 0;\n padding: 0 4px;\n}\n.dv-pie-renderer :deep(.legend-item) {\n margin-right: 12px;\n color: #667085;\n font-size: 11px;\n}\n.dv-pie-renderer :deep(.legend-item-color) {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n</style>\n","<template>\n <div class=\"dv-table-scroll\">\n <a-table\n class=\"dv-table\"\n :columns=\"columns\"\n :data-source=\"[...viewModel.rows]\"\n :pagination=\"viewModel.showPagination ? { pageSize: viewModel.pageSize, showSizeChanger: false } : false\"\n :row-key=\"rowKey\"\n :scroll=\"{ x: 'max-content' }\"\n size=\"small\"\n @change=\"onChange\"\n :custom-row=\"customRow\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { FallOutlined, MinusOutlined, RiseOutlined } from \"@ant-design/icons-vue\";\nimport { Progress as AProgress, Table as ATable, Tag as ATag } from \"ant-design-vue\";\nimport type { ColumnsType } from \"ant-design-vue/es/table\";\nimport { computed, h, type Component } from \"vue\";\n\nimport {\n valueFormatter,\n type DashboardContext,\n type PanelConfig,\n type TableCellDisplay,\n type TableCellTone,\n type TableColumnViewModel,\n type TableViewModel,\n type VisualizationEvent\n} from \"../../core\";\n\nconst props = defineProps<{ viewModel: TableViewModel; panel: PanelConfig; context: DashboardContext }>();\nconst emit = defineEmits<{ visualizationEvent: [event: VisualizationEvent] }>();\n\nconst columns = computed<ColumnsType<Record<string, unknown>>>(() =>\n props.viewModel.columns.map((column) => ({\n title: column.label,\n dataIndex: column.field,\n key: column.field,\n ...(column.width ? { width: column.width } : {}),\n sorter: column.sortable,\n ...(column.filterable\n ? {\n filters: Array.from(new Set(props.viewModel.rows.map((row) => String(row[column.field] ?? \"\"))))\n .slice(0, 50)\n .map((value) => ({ text: value || \"--\", value })),\n onFilter: (value: string | number | boolean, row: Record<string, unknown>) =>\n String(row[column.field] ?? \"\") === String(value)\n }\n : {}),\n customRender: ({ text }: { text: unknown }) => renderCell(text, column)\n }))\n);\n\nfunction formatCellValue(text: unknown, column: TableColumnViewModel): string {\n return valueFormatter.formatDisplay(\n text,\n column.format ?? {\n type: column.dataType === \"date\" ? \"date\" : column.dataType === \"datetime\" ? \"datetime\" : \"number\"\n },\n props.context\n );\n}\n\nfunction renderCell(text: unknown, column: TableColumnViewModel) {\n const formatted = formatCellValue(text, column);\n if (!column.display) return formatted;\n if (column.display.type === \"progress\") return renderProgressCell(text, formatted, column.display);\n if (column.display.type === \"trend\") return renderTrendCell(text, formatted, column.display);\n return renderTagCell(text, formatted, column.display);\n}\n\nfunction finiteNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction renderProgressCell(\n text: unknown,\n formatted: string,\n display: Extract<TableCellDisplay, { type: \"progress\" }>\n) {\n const value = finiteNumber(text);\n if (value === undefined) return formatted;\n const max = display.max ?? 1;\n const percent = Math.min(100, Math.max(0, (value / max) * 100));\n return h(\"div\", { class: \"dv-table__progress-cell\" }, [\n h(AProgress, { percent, showInfo: false, size: \"small\", strokeWidth: 6 }),\n h(\"span\", { class: \"dv-table__cell-value\" }, formatted)\n ]);\n}\n\nfunction renderTrendCell(text: unknown, formatted: string, display: Extract<TableCellDisplay, { type: \"trend\" }>) {\n const value = finiteNumber(text);\n if (value === undefined) return formatted;\n const tone =\n value > 0\n ? (display.positiveTone ?? \"success\")\n : value < 0\n ? (display.negativeTone ?? \"danger\")\n : (display.zeroTone ?? \"neutral\");\n const icon: Component = value > 0 ? RiseOutlined : value < 0 ? FallOutlined : MinusOutlined;\n return h(\"span\", { class: [\"dv-table__trend\", `dv-table__trend--${tone}`] }, [h(icon), h(\"span\", formatted)]);\n}\n\nfunction renderTagCell(text: unknown, formatted: string, display: Extract<TableCellDisplay, { type: \"tag\" }>) {\n const tone = display.toneByValue?.[String(text ?? \"\")] ?? display.defaultTone ?? \"neutral\";\n return renderTag(formatted, tone);\n}\n\nfunction renderTag(label: string, tone: TableCellTone, icon?: Component) {\n return h(\n ATag,\n { class: [\"dv-table__tag\", `dv-table__tag--${tone}`] },\n { default: () => [...(icon ? [h(icon)] : []), h(\"span\", label)] }\n );\n}\n\nconst rowKeys = new WeakMap<object, string>();\nlet rowSequence = 0;\nfunction rowKey(row: Readonly<Record<string, unknown>>): string {\n const existing = rowKeys.get(row);\n if (existing) return existing;\n const key = `row-${++rowSequence}`;\n rowKeys.set(row, key);\n return key;\n}\nfunction customRow(row: Readonly<Record<string, unknown>>) {\n return {\n onClick: () =>\n emit(\"visualizationEvent\", {\n type: \"rowClick\",\n panelId: props.panel.id,\n datasetId: props.panel.binding.datasetId,\n fields: row\n })\n };\n}\nfunction onChange(): void {}\n</script>\n\n<style scoped>\n.dv-table :deep(.ant-table) {\n font-size: 12px;\n}\n.dv-table-scroll {\n width: 100%;\n overflow-x: auto;\n}\n.dv-table {\n min-width: 720px;\n}\n.dv-table :deep(.ant-table-thead > tr > th) {\n padding: 13px 16px;\n color: #5e6a7d;\n border-bottom: 1px solid #e5eaf0;\n font-weight: 600;\n background: #f7f9fb;\n}\n.dv-table :deep(.ant-table-tbody > tr > td) {\n padding: 14px 16px;\n color: #344054;\n border-bottom: 1px solid #edf0f4;\n}\n.dv-table :deep(.ant-table-tbody > tr.ant-table-row:hover > td) {\n background: #f8fafc;\n}\n.dv-table :deep(.dv-table__progress-cell) {\n display: grid;\n min-width: 160px;\n grid-template-columns: minmax(96px, 1fr) 48px;\n align-items: center;\n gap: 8px;\n}\n.dv-table :deep(.dv-table__progress-cell .ant-progress) {\n margin: 0;\n line-height: 1;\n}\n.dv-table :deep(.dv-table__progress-cell .ant-progress-inner) {\n background: #edf0f4;\n}\n.dv-table :deep(.dv-table__progress-cell .ant-progress-bg) {\n background: #315fc4;\n}\n.dv-table :deep(.dv-table__cell-value) {\n color: #657184;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.dv-table :deep(.dv-table__trend) {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 600;\n line-height: 18px;\n white-space: nowrap;\n}\n.dv-table :deep(.dv-table__trend--neutral) {\n color: #7b8493;\n}\n.dv-table :deep(.dv-table__trend--info) {\n color: #315fc4;\n}\n.dv-table :deep(.dv-table__trend--success) {\n color: #00a870;\n}\n.dv-table :deep(.dv-table__trend--warning) {\n color: #c2410c;\n}\n.dv-table :deep(.dv-table__trend--danger) {\n color: #f53f3f;\n}\n.dv-table :deep(.dv-table__tag) {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin: 0;\n border-radius: 4px;\n font-size: 12px;\n line-height: 20px;\n}\n.dv-table :deep(.dv-table__tag--neutral) {\n color: #475467;\n border-color: #e4e7ec;\n background: #f2f4f7;\n}\n.dv-table :deep(.dv-table__tag--info) {\n color: #315fc4;\n border-color: #cbdafa;\n background: #eff6ff;\n}\n.dv-table :deep(.dv-table__tag--success) {\n color: #027a48;\n border-color: #abefc6;\n background: #ecfdf3;\n}\n.dv-table :deep(.dv-table__tag--warning) {\n color: #c2410c;\n border-color: #fed7aa;\n background: #fff7ed;\n}\n.dv-table :deep(.dv-table__tag--danger) {\n color: #b42318;\n border-color: #fecdca;\n background: #fef3f2;\n}\n.dv-table :deep(.ant-table-pagination.ant-pagination) {\n display: flex;\n align-items: center;\n gap: 4px;\n margin: 16px 0 0;\n}\n.dv-table :deep(.ant-table-pagination.ant-pagination::after) {\n display: none;\n}\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-item),\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-prev),\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-next),\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-jump-prev),\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-jump-next) {\n display: flex;\n min-width: 28px;\n height: 28px;\n align-items: center;\n justify-content: center;\n margin: 0;\n border-radius: 5px;\n line-height: 1;\n}\n.dv-table :deep(.ant-table-pagination .ant-pagination-item > a),\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-link),\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-container) {\n display: flex;\n width: 100%;\n height: 100%;\n align-items: center;\n justify-content: center;\n padding: 0;\n line-height: 1;\n}\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-ellipsis) {\n display: flex;\n align-items: center;\n justify-content: center;\n letter-spacing: 1px;\n line-height: 1;\n text-indent: 0;\n}\n.dv-table :deep(.ant-table-pagination .anticon) {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n.dv-table :deep(.ant-table-pagination .anticon svg) {\n display: block;\n}\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-active) {\n border-color: var(--dv-primary, #315fc4);\n background: #f0f4fc;\n background: color-mix(in srgb, var(--dv-primary, #315fc4) 8%, white);\n}\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-active > a) {\n color: var(--dv-primary, #315fc4);\n}\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled) .ant-pagination-item:not(.ant-pagination-item-disabled):hover\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-item:not(.ant-pagination-item-disabled):focus-visible\n ) {\n border-color: var(--dv-primary, #315fc4);\n background: #f0f4fc;\n background: color-mix(in srgb, var(--dv-primary, #315fc4) 8%, white);\n}\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-item:not(.ant-pagination-item-disabled):hover\n > a\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-item:not(.ant-pagination-item-disabled):focus-visible\n > a\n ),\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-link-icon),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-prev:not(.ant-pagination-disabled):hover\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-prev:not(.ant-pagination-disabled):focus-visible\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-next:not(.ant-pagination-disabled):hover\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-next:not(.ant-pagination-disabled):focus-visible\n .ant-pagination-item-link\n ) {\n color: var(--dv-primary, #315fc4);\n}\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-prev:not(.ant-pagination-disabled):hover\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-prev:not(.ant-pagination-disabled):focus-visible\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-next:not(.ant-pagination-disabled):hover\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-next:not(.ant-pagination-disabled):focus-visible\n .ant-pagination-item-link\n ) {\n border-color: var(--dv-primary, #315fc4);\n}\n</style>\n","import BarRenderer from \"../renderers/BarRenderer.vue\";\nimport LineRenderer from \"../renderers/LineRenderer.vue\";\nimport MetricRenderer from \"../renderers/MetricRenderer.vue\";\nimport PieRenderer from \"../renderers/PieRenderer.vue\";\nimport TableRenderer from \"../renderers/TableRenderer.vue\";\nimport type { VueRendererRegistry } from \"./renderer-registry\";\n\nexport function registerStandardVueRenderers(registry: VueRendererRegistry): VueRendererRegistry {\n registry.registerMany([\n { id: \"metric\", component: MetricRenderer },\n { id: \"line\", component: LineRenderer },\n { id: \"bar\", component: BarRenderer },\n { id: \"pie\", component: PieRenderer },\n { id: \"table\", component: TableRenderer }\n ]);\n return registry;\n}\n","import type { Component } from \"vue\";\n\nimport { PluginRegistry } from \"../../core\";\n\nexport interface VueVisualizationRenderer {\n id: string;\n component: Component;\n}\n\nexport type DashboardPanelComponentMap = Readonly<Record<string, Component>>;\n\nexport class VueRendererRegistry extends PluginRegistry<VueVisualizationRenderer> {\n constructor() {\n super(\"VueVisualizationRenderer\");\n }\n}\n\nexport function createVueRendererRegistry(): VueRendererRegistry {\n return new VueRendererRegistry();\n}\n"],"names":["props","__props","emit","__emit","layoutStyle","layout","selectValue","value","selectOptions","options","option","parseDate","date","formatDate","yesterdayDate","parts","part","yesterday","contextValue","variableId","dateRangeValueProps","control","start","end","onDateRangeChange","activePreset","days","_b","_a","preset","onPresetChange","event","presetId","item","onSelectChange","rendererRef","ref","rendererError","isMetricPanel","computed","panelFailure","canDownload","bodyStyle","panelMinHeight","headerHeight","updatedAt","exportPng","onDownloadMenuClick","onErrorCaptured","error","watch","__expose","useDashboardRuntime","runtime","snapshot","shallowRef","unsubscribe","onMounted","next","onBeforeUnmount","panelIds","refreshOptions","panelId","patch","downloadBlob","content","mimeType","filename","url","triggerDownload","downloadDataUrl","dataUrl","anchor","panelRefs","dashboardElement","nearPanelIds","pendingPanelIds","intersectionObserver","lazyObserverActive","loadQueued","onBeforeMount","context","panelStates","isLoading","loadPanels","refreshRuntimeAll","refreshPanels","refreshPanel","retryPanel","setVariables","onPanelIntersection","element","filterSummary","variable","formatVariable","panelStyle","panel","span","resolvePanelComponent","component","markRaw","toRaw","setPanelRef","entries","entry","refreshAll","onVariablesChange","pendingRefresh","search","buildDashboardSearch","exportCsv","candidate","dataset","csv","serializePanelCsv","createPanelCsvFilename","toChartFormat","format","FormatType","chartEventFields","chartRef","formatValue","series","axis","formatted","valueFormatter","formatOwnsUnit","STANDARD_CHART_COLORS","STANDARD_CATEGORY_AXIS","STANDARD_VALUE_AXIS","STANDARD_CHART_TOOLTIP","onClick","raw","seriesIndex","binding","formatAxisValue","appendSeriesUnit","axisSeries","axisIndexes","index","formattedValue","displayUnit","formattedComparison","comparison","comparisonIcon","RiseOutlined","FallOutlined","MinusOutlined","comparisonTone","sum","columns","column","row","text","renderCell","formatCellValue","renderProgressCell","renderTrendCell","renderTagCell","finiteNumber","display","max","percent","h","AProgress","tone","icon","renderTag","label","ATag","rowKeys","rowSequence","rowKey","existing","key","customRow","onChange","registerStandardVueRenderers","registry","MetricRenderer","LineRenderer","BarRenderer","PieRenderer","TableRenderer","VueRendererRegistry","PluginRegistry","createVueRendererRegistry"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/vue/components/DashboardFilterBar.vue","../../src/vue/components/DashboardPanel.vue","../../src/vue/composables/use-dashboard-runtime.ts","../../src/vue/export/browser-download.ts","../../src/vue/components/DashboardRenderer.vue","../../src/vue/renderers/chart-format.ts","../../src/vue/renderers/BarRenderer.vue","../../src/vue/renderers/LineRenderer.vue","../../src/vue/renderers/MetricRenderer.vue","../../src/vue/renderers/PieRenderer.vue","../../src/vue/renderers/TableRenderer.vue","../../src/vue/registry/register-standard.ts","../../src/vue/registry/renderer-registry.ts"],"sourcesContent":["<template>\n <div v-if=\"config\" class=\"dv-filter-bar\" :class=\"{ 'dv-filter-bar--flow': config.layout === 'flow' }\">\n <div class=\"dv-filter-bar__controls\">\n <div\n v-for=\"control in config.controls\"\n :key=\"control.id\"\n class=\"dv-filter-bar__control\"\n :class=\"`dv-filter-bar__control--${control.type}`\"\n :style=\"layoutStyle(control.layout)\"\n >\n <label class=\"dv-filter-bar__label\">{{ control.label }}</label>\n <template v-if=\"control.type === 'date-range'\">\n <div class=\"dv-filter-bar__date-range\">\n <a-range-picker\n class=\"dv-filter-bar__range-picker\"\n :allow-clear=\"false\"\n :disabled=\"control.disabled ?? false\"\n dropdown-class-name=\"dv-filter-bar__date-popup\"\n :format=\"control.format ?? 'YYYY-MM-DD'\"\n v-bind=\"dateRangeValueProps(control)\"\n value-format=\"YYYY-MM-DD\"\n @change=\"(value: unknown) => onDateRangeChange(control, value)\"\n >\n <template #separator>至</template>\n </a-range-picker>\n <a-radio-group\n v-if=\"control.presets?.length\"\n class=\"dv-filter-bar__presets\"\n :disabled=\"control.disabled ?? false\"\n size=\"small\"\n :value=\"activePreset(control)\"\n @change=\"onPresetChange(control, $event)\"\n >\n <a-radio-button v-for=\"preset in control.presets\" :key=\"preset.id\" :value=\"preset.id\">\n {{ preset.label }}\n </a-radio-button>\n </a-radio-group>\n </div>\n </template>\n <a-select\n v-else-if=\"control.type === 'multi-select'\"\n :allow-clear=\"control.allowClear ?? false\"\n :disabled=\"control.disabled ?? false\"\n :max-tag-count=\"control.maxTagCount ?? 'responsive'\"\n mode=\"multiple\"\n option-filter-prop=\"label\"\n :options=\"selectOptions(control.options)\"\n :placeholder=\"control.placeholder ?? ''\"\n :show-search=\"control.showSearch ?? false\"\n :value=\"selectValue(context.variables[control.variableId])\"\n @change=\"(value: unknown) => onSelectChange(control.variableId, value)\"\n />\n <a-select\n v-else\n :allow-clear=\"control.allowClear ?? false\"\n :disabled=\"control.disabled ?? false\"\n option-filter-prop=\"label\"\n :options=\"selectOptions(control.options)\"\n :placeholder=\"control.placeholder ?? ''\"\n :show-search=\"control.showSearch ?? false\"\n :value=\"selectValue(context.variables[control.variableId])\"\n @change=\"(value: unknown) => onSelectChange(control.variableId, value)\"\n />\n </div>\n </div>\n <a-tooltip v-if=\"config.showRefresh !== false\" title=\"刷新全部\">\n <a-button type=\"primary\" class=\"dv-filter-bar__refresh\" :loading=\"loading ?? false\" @click=\"$emit('refresh')\">\n <template #icon><RedoOutlined /></template>\n 刷新\n </a-button>\n </a-tooltip>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { RedoOutlined } from \"@ant-design/icons-vue\";\nimport {\n Button as AButton,\n RadioButton as ARadioButton,\n RadioGroup as ARadioGroup,\n RangePicker as ARangePicker,\n Select as ASelect,\n Tooltip as ATooltip\n} from \"ant-design-vue\";\n\nimport type {\n DashboardContext,\n DashboardFilterBarConfig,\n DashboardFilterControlConfig,\n DashboardVariablePatch,\n JsonValue\n} from \"../../core\";\n\ntype DateRangeControl = Extract<DashboardFilterControlConfig, { type: \"date-range\" }>;\n\nconst props = defineProps<{ config?: DashboardFilterBarConfig; context: DashboardContext; loading?: boolean }>();\nconst emit = defineEmits<{ change: [patch: DashboardVariablePatch]; refresh: [] }>();\n\nfunction layoutStyle(layout: DashboardFilterBarConfig[\"controls\"][number][\"layout\"]) {\n return {\n \"--dv-filter-xs\": String(layout.xs),\n \"--dv-filter-sm\": String(layout.sm ?? layout.xs),\n \"--dv-filter-md\": String(layout.md ?? layout.sm ?? layout.xs),\n \"--dv-filter-lg\": String(layout.lg ?? layout.md ?? layout.sm ?? layout.xs),\n \"--dv-filter-xl\": String(layout.xl ?? layout.lg ?? layout.md ?? layout.sm ?? layout.xs)\n };\n}\nfunction selectValue(value: JsonValue | undefined): any {\n return value;\n}\nfunction selectOptions(\n options: ReadonlyArray<{ label: string; value: string | number | boolean; disabled?: boolean }>\n): any[] {\n return options.map((option) => ({ ...option }));\n}\nfunction parseDate(value: JsonValue | undefined): Date | undefined {\n if (typeof value !== \"string\" || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return undefined;\n const date = new Date(`${value}T12:00:00Z`);\n return Number.isNaN(date.getTime()) ? undefined : date;\n}\nfunction formatDate(value: Date): string {\n return value.toISOString().slice(0, 10);\n}\nfunction yesterdayDate(): Date {\n const parts = new Intl.DateTimeFormat(\"en-CA\", {\n timeZone: props.context.timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\"\n }).formatToParts(new Date());\n const date = Object.fromEntries(parts.map((part) => [part.type, part.value]));\n const yesterday = new Date(`${date.year}-${date.month}-${date.day}T12:00:00Z`);\n yesterday.setUTCDate(yesterday.getUTCDate() - 1);\n return yesterday;\n}\nfunction contextValue(variableId: string): JsonValue | undefined {\n return props.context.variables[variableId];\n}\nfunction dateRangeValueProps(control: DateRangeControl): { value?: [string, string] } {\n const start = contextValue(control.startVariableId);\n const end = contextValue(control.endVariableId);\n if (typeof start !== \"string\" || typeof end !== \"string\" || !parseDate(start) || !parseDate(end)) {\n return {};\n }\n return { value: [start, end] };\n}\nfunction onDateRangeChange(control: DateRangeControl, value: unknown): void {\n if (!Array.isArray(value) || value.length !== 2) return;\n const [start, end] = value;\n if (typeof start !== \"string\" || typeof end !== \"string\") return;\n emit(\"change\", {\n [control.startVariableId]: start,\n [control.endVariableId]: end\n });\n}\nfunction activePreset(control: DateRangeControl): string | undefined {\n const start = parseDate(contextValue(control.startVariableId));\n const end = parseDate(contextValue(control.endVariableId));\n if (!start || !end || end.getTime() !== yesterdayDate().getTime()) return undefined;\n const days = Math.round((end.getTime() - start.getTime()) / 86_400_000) + 1;\n return control.presets?.find((preset) => preset.days === days)?.id;\n}\nfunction onPresetChange(control: DateRangeControl, event: { target: { value?: unknown } }): void {\n const presetId = typeof event.target.value === \"string\" ? event.target.value : undefined;\n const preset = control.presets?.find((item) => item.id === presetId);\n if (!preset) return;\n const end = yesterdayDate();\n const start = new Date(end);\n start.setUTCDate(start.getUTCDate() - preset.days + 1);\n emit(\"change\", {\n [control.startVariableId]: formatDate(start),\n [control.endVariableId]: formatDate(end)\n });\n}\nfunction onSelectChange(variableId: string, value: unknown): void {\n emit(\"change\", { [variableId]: (value ?? null) as JsonValue });\n}\n</script>\n\n<style scoped>\n.dv-filter-bar {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 11px 14px;\n background: #fff;\n border: 1px solid var(--dv-card-border, #e1e6ed);\n border-radius: 7px;\n box-shadow:\n 0 1px 2px rgb(16 24 40 / 3.5%),\n 0 5px 14px rgb(16 24 40 / 2.5%);\n}\n.dv-filter-bar__controls {\n flex: 1;\n display: grid;\n grid-template-columns: repeat(24, minmax(0, 1fr));\n column-gap: 16px;\n row-gap: 8px;\n}\n.dv-filter-bar__control {\n grid-column: span var(--dv-filter-xs);\n min-width: 0;\n}\n.dv-filter-bar__label {\n display: block;\n margin-bottom: 6px;\n color: var(--dv-text-secondary, #657184);\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n white-space: nowrap;\n}\n.dv-filter-bar__control :deep(.ant-select) {\n width: 100%;\n min-width: 0;\n}\n.dv-filter-bar__control :deep(.ant-select-single .ant-select-selector),\n.dv-filter-bar__control :deep(.ant-select-multiple .ant-select-selector) {\n height: 32px;\n min-height: 32px;\n}\n.dv-filter-bar__control :deep(.ant-select-multiple .ant-select-selection-overflow) {\n flex-wrap: nowrap;\n overflow: hidden;\n}\n.dv-filter-bar__date-range {\n display: flex;\n width: fit-content;\n min-width: 0;\n max-width: 100%;\n align-items: center;\n gap: 10px;\n}\n.dv-filter-bar__range-picker {\n width: 320px;\n min-width: 220px;\n max-width: 320px;\n height: 32px;\n flex: 0 1 320px;\n}\n.dv-filter-bar__presets {\n display: inline-flex;\n height: 32px;\n flex: none;\n align-items: center;\n gap: 2px;\n padding: 3px;\n border: 1px solid #e2e7ed;\n border-radius: 6px;\n background: #f3f5f7;\n}\n.dv-filter-bar__presets :deep(.ant-radio-button-wrapper) {\n height: 24px;\n padding: 0 8px;\n border: 0;\n border-radius: 4px;\n color: #737e8e;\n background: transparent;\n box-shadow: none;\n font-size: 12px;\n font-weight: 500;\n line-height: 24px;\n}\n.dv-filter-bar__presets :deep(.ant-radio-button-wrapper::before) {\n display: none;\n}\n.dv-filter-bar__presets :deep(.ant-radio-button-wrapper-checked) {\n color: var(--dv-primary, #315fc4);\n background: #fff;\n box-shadow:\n 0 1px 2px rgb(16 24 40 / 8%),\n 0 0 0 1px rgb(16 24 40 / 2.5%);\n font-weight: 600;\n}\n.dv-filter-bar :deep(.ant-select-selector),\n.dv-filter-bar :deep(.ant-picker) {\n border-color: #dce2e9;\n border-radius: 5px;\n box-shadow: none;\n}\n.dv-filter-bar__refresh {\n width: 78px;\n height: 32px;\n flex: 0 0 78px;\n border-color: var(--dv-primary, #315fc4);\n border-radius: 6px;\n background: var(--dv-primary, #315fc4);\n box-shadow: none;\n}\n@media (min-width: 576px) {\n .dv-filter-bar__control {\n grid-column: span var(--dv-filter-sm);\n }\n}\n@media (min-width: 768px) {\n .dv-filter-bar__control {\n grid-column: span var(--dv-filter-md);\n display: flex;\n align-items: center;\n }\n .dv-filter-bar__label {\n flex: none;\n margin: 0 8px 0 0;\n }\n .dv-filter-bar--flow .dv-filter-bar__controls {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n column-gap: 20px;\n }\n .dv-filter-bar--flow .dv-filter-bar__control {\n width: auto;\n flex: 0 1 auto;\n grid-column: auto;\n }\n .dv-filter-bar--flow .dv-filter-bar__control--select,\n .dv-filter-bar--flow .dv-filter-bar__control--multi-select {\n width: clamp(220px, 20vw, 320px);\n flex-basis: clamp(220px, 20vw, 320px);\n }\n}\n@media (min-width: 992px) {\n .dv-filter-bar__control {\n grid-column: span var(--dv-filter-lg);\n }\n}\n@media (min-width: 1200px) {\n .dv-filter-bar__control {\n grid-column: span var(--dv-filter-xl);\n }\n}\n@media (min-width: 768px) and (max-width: 1300px) {\n .dv-filter-bar__date-range {\n gap: 6px;\n }\n .dv-filter-bar__range-picker {\n width: 288px;\n min-width: 200px;\n max-width: 288px;\n flex-basis: 288px;\n }\n .dv-filter-bar__presets :deep(.ant-radio-button-wrapper) {\n padding: 0 5px;\n font-size: 11px;\n }\n}\n@media (max-width: 767px) {\n .dv-filter-bar {\n align-items: stretch;\n flex-direction: column;\n }\n .dv-filter-bar__refresh {\n align-self: flex-end;\n }\n .dv-filter-bar__controls {\n column-gap: 0;\n }\n .dv-filter-bar__date-range {\n width: 100%;\n align-items: stretch;\n flex-direction: column;\n }\n .dv-filter-bar__range-picker {\n width: 100%;\n min-width: 0;\n max-width: none;\n flex-basis: auto;\n }\n .dv-filter-bar__refresh {\n flex-basis: 32px;\n }\n :global(.dv-filter-bar__date-popup .ant-picker-panels > .ant-picker-panel:last-child) {\n display: none;\n }\n :global(.dv-filter-bar__date-popup .ant-picker-panel:first-child .ant-picker-header-next-btn),\n :global(.dv-filter-bar__date-popup .ant-picker-panel:first-child .ant-picker-header-super-next-btn) {\n visibility: visible !important;\n }\n}\n</style>\n","<template>\n <a-card class=\"dv-panel\" :class=\"{ 'dv-panel--metric': isMetricPanel }\" :body-style=\"bodyStyle\">\n <template #title>\n <div class=\"dv-panel__heading\">\n <span class=\"dv-panel__title-group\">\n <span class=\"dv-panel__title\">{{ panel.title }}</span>\n <a-tooltip v-if=\"panel.description\" :title=\"panel.description\"><QuestionCircleOutlined /></a-tooltip>\n </span>\n <span v-if=\"panel.titleNote\" class=\"dv-panel__title-note\">{{ panel.titleNote }}</span>\n </div>\n </template>\n <template #extra>\n <div class=\"dv-panel__actions\">\n <a-tooltip\n v-if=\"state.status === 'stale'\"\n :title=\"`刷新失败,当前展示上次成功数据${state.error?.message ? `:${state.error.message}` : ''}`\"\n >\n <WarningOutlined class=\"dv-panel__warning\" />\n </a-tooltip>\n <a-tooltip :title=\"refreshDisabled ? '正在刷新全部' : '刷新'\"\n ><a-button :disabled=\"refreshDisabled ?? false\" type=\"text\" size=\"small\" @click=\"$emit('refresh')\"\n ><template #icon><RedoOutlined /></template></a-button\n ></a-tooltip>\n <a-dropdown v-if=\"canDownload\" placement=\"bottomRight\" :trigger=\"['click']\">\n <a-tooltip title=\"下载\">\n <a-button type=\"text\" size=\"small\"\n ><template #icon><CloudDownloadOutlined /></template\n ></a-button>\n </a-tooltip>\n <template #overlay>\n <a-menu @click=\"onDownloadMenuClick\">\n <a-menu-item v-if=\"canExportCsv\" key=\"csv\">导出 CSV</a-menu-item>\n <a-menu-item v-if=\"canExportPng\" key=\"png\">导出 PNG</a-menu-item>\n </a-menu>\n </template>\n </a-dropdown>\n <a-button\n v-for=\"action in panel.actions ?? []\"\n :key=\"action.id\"\n type=\"link\"\n size=\"small\"\n @click=\"$emit('action', action.id)\"\n >{{ action.label ?? action.id }}</a-button\n >\n </div>\n </template>\n\n <div v-if=\"filterSummary\" class=\"dv-panel__filters\">{{ filterSummary }}</div>\n <div v-if=\"panelFailure\" class=\"dv-panel__state dv-panel__state--failure\" role=\"status\">\n <div class=\"dv-panel__failure\">\n <ExclamationCircleOutlined class=\"dv-panel__failure-icon\" />\n <div class=\"dv-panel__failure-copy\">\n <div class=\"dv-panel__failure-heading\">{{ panelFailure.title }}</div>\n <div v-if=\"panelFailure.detail\" class=\"dv-panel__failure-detail\" :title=\"panelFailure.detail\">\n {{ panelFailure.detail }}\n </div>\n </div>\n <a-tooltip title=\"重试\">\n <a-button class=\"dv-panel__retry\" size=\"small\" aria-label=\"重试\" @click=\"$emit('retry')\">\n <template #icon><RedoOutlined /></template>\n <span class=\"dv-panel__retry-label\">重新加载</span>\n </a-button>\n </a-tooltip>\n </div>\n </div>\n <div v-else-if=\"state.status === 'loading' && !state.viewModel\" class=\"dv-panel__state dv-panel__state--loading\">\n <a-spin />\n </div>\n <template v-else-if=\"state.status === 'empty'\">\n <div v-if=\"isMetricPanel\" class=\"dv-panel__state dv-panel__state--metric-empty\">暂无数据</div>\n <div v-else class=\"dv-panel__state dv-panel__state--empty\" role=\"status\" aria-live=\"polite\">\n <span class=\"dv-panel__empty-icon\" aria-hidden=\"true\"><BarChartOutlined /></span>\n <div class=\"dv-panel__empty-copy\">\n <div class=\"dv-panel__empty-title\">暂无数据</div>\n </div>\n </div>\n </template>\n <div v-else-if=\"state.viewModel\" class=\"dv-panel__renderer\">\n <component\n :is=\"renderer\"\n ref=\"rendererRef\"\n :context=\"context\"\n :panel=\"panel\"\n :view-model=\"state.viewModel\"\n @visualization-event=\"$emit('visualizationEvent', $event)\"\n />\n <div v-if=\"state.isRefreshing\" class=\"dv-panel__refreshing\"><a-spin /></div>\n </div>\n <div v-else class=\"dv-panel__state dv-panel__idle\">等待加载</div>\n\n <div v-if=\"state.lastSuccessfulAt\" class=\"dv-panel__updated\">更新于 {{ updatedAt }}</div>\n </a-card>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n BarChartOutlined,\n CloudDownloadOutlined,\n ExclamationCircleOutlined,\n QuestionCircleOutlined,\n RedoOutlined,\n WarningOutlined\n} from \"@ant-design/icons-vue\";\nimport {\n Button as AButton,\n Card as ACard,\n Dropdown as ADropdown,\n Menu as AMenu,\n MenuItem as AMenuItem,\n Spin as ASpin,\n Tooltip as ATooltip\n} from \"ant-design-vue\";\nimport { computed, onErrorCaptured, ref, watch, type Component } from \"vue\";\nimport { isPanelExportEnabled } from \"../../core\";\n\nimport type {\n DashboardContext,\n PanelConfig,\n PanelRuntimeState,\n VisualizationEvent,\n VisualizationRendererDefinition\n} from \"../../core\";\nimport type { ChartRendererExpose } from \"../renderers\";\n\nconst props = defineProps<{\n panel: PanelConfig;\n state: PanelRuntimeState;\n context: DashboardContext;\n definition: VisualizationRendererDefinition;\n renderer: Component;\n filterSummary?: string;\n refreshDisabled?: boolean;\n}>();\nconst emit = defineEmits<{\n refresh: [];\n retry: [];\n exportCsv: [];\n exportPng: [];\n action: [actionId: string];\n visualizationEvent: [event: VisualizationEvent];\n}>();\n\nconst rendererRef = ref<ChartRendererExpose>();\nconst rendererError = ref<Error>();\nconst isMetricPanel = computed(() => props.panel.rendererId === \"metric\");\nconst panelFailure = computed(() => {\n if (rendererError.value) {\n return { title: \"图表暂时无法展示\", detail: rendererError.value.message };\n }\n if (props.state.status === \"error\" || props.state.status === \"cancelled\") {\n return { title: \"数据暂时无法加载\", detail: props.state.error?.message };\n }\n return undefined;\n});\nconst canExportCsv = computed(\n () => isPanelExportEnabled(props.panel, props.definition.capabilities, \"csv\") && Boolean(props.state.dataset)\n);\nconst canExportPng = computed(\n () => isPanelExportEnabled(props.panel, props.definition.capabilities, \"png\") && Boolean(props.state.viewModel)\n);\nconst canDownload = computed(() => canExportCsv.value || canExportPng.value);\nconst bodyStyle = computed(() => {\n const panelMinHeight = props.panel.layout.minHeight ?? (isMetricPanel.value ? 119 : 401);\n const headerHeight = isMetricPanel.value ? 40 : 50;\n return { minHeight: `${Math.max(panelMinHeight - headerHeight - 2, isMetricPanel.value ? 77 : 190)}px` };\n});\nconst updatedAt = computed(() =>\n props.state.lastSuccessfulAt\n ? new Intl.DateTimeFormat(props.context.locale, { timeStyle: \"medium\", timeZone: props.context.timezone }).format(\n new Date(props.state.lastSuccessfulAt)\n )\n : \"\"\n);\n\nfunction exportPng(): string | undefined {\n if (!canExportPng.value) return;\n return rendererRef.value?.exportPng?.();\n}\nfunction onDownloadMenuClick(event: { key: string | number }): void {\n if (event.key === \"csv\" && canExportCsv.value) emit(\"exportCsv\");\n if (event.key === \"png\" && canExportPng.value) emit(\"exportPng\");\n}\nonErrorCaptured((error) => {\n rendererError.value = error instanceof Error ? error : new Error(String(error));\n return false;\n});\nwatch(\n () => [props.state.generation, props.state.viewModel] as const,\n () => {\n rendererError.value = undefined;\n }\n);\ndefineExpose({ exportPng });\n</script>\n\n<style scoped>\n.dv-panel {\n height: 100%;\n overflow: hidden;\n border: 1px solid var(--dv-card-border, #e1e6ed);\n border-radius: 7px;\n background: #fff;\n box-shadow:\n 0 1px 2px rgb(16 24 40 / 3.5%),\n 0 5px 14px rgb(16 24 40 / 2.5%);\n}\n.dv-panel :deep(.ant-card-head) {\n min-height: 50px;\n padding: 0 16px;\n border-bottom-color: var(--dv-card-divider, #edf0f4);\n}\n.dv-panel :deep(.ant-card-head-title),\n.dv-panel :deep(.ant-card-extra) {\n padding: 10px 0;\n}\n.dv-panel :deep(.ant-card-head-title) {\n padding: 13px 0;\n}\n.dv-panel :deep(.ant-card-body) {\n position: relative;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n padding: 15px 16px;\n}\n.dv-panel__heading,\n.dv-panel__title-group,\n.dv-panel__actions {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.dv-panel__heading {\n min-width: 0;\n flex-wrap: wrap;\n row-gap: 2px;\n line-height: 20px;\n}\n.dv-panel__title-group {\n min-width: 0;\n}\n.dv-panel__title-group :deep(.anticon) {\n flex-shrink: 0;\n}\n.dv-panel__title-note {\n min-width: 0;\n max-width: 100%;\n color: #98a2b3;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n overflow-wrap: anywhere;\n white-space: normal;\n}\n.dv-panel__title {\n overflow: hidden;\n color: var(--dv-text-title, #273244);\n font-size: 14px;\n font-weight: 650;\n line-height: 20px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dv-panel__heading :deep(svg) {\n color: #8a94a6;\n font-size: 13px;\n}\n.dv-panel__actions {\n gap: 4px;\n}\n.dv-panel__actions :deep(.ant-btn) {\n width: 28px;\n height: 28px;\n padding: 0;\n border-radius: 5px;\n color: #6e7889;\n}\n.dv-panel__actions :deep(.ant-btn:hover) {\n color: var(--dv-primary, #315fc4);\n background: #f0f4fa;\n}\n.dv-panel__filters {\n display: none;\n}\n.dv-panel__warning {\n color: #f59e0b;\n font-size: 15px;\n}\n.dv-panel__state {\n min-height: 190px;\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.dv-panel__state--empty {\n box-sizing: border-box;\n flex-direction: column;\n gap: 14px;\n padding: 24px 12px;\n text-align: center;\n}\n.dv-panel__empty-icon {\n display: grid;\n width: 56px;\n height: 56px;\n flex-shrink: 0;\n place-items: center;\n border: 1px solid var(--dv-card-divider, #edf0f4);\n border-radius: 16px;\n color: #8da2c5;\n background: linear-gradient(145deg, #f8fafd, #eff3f9);\n font-size: 26px;\n}\n.dv-panel__empty-copy {\n max-width: 100%;\n}\n.dv-panel__empty-title {\n color: var(--dv-text-secondary, #657184);\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n}\n.dv-panel :deep(.ant-spin) {\n color: var(--dv-primary, #315fc4);\n}\n.dv-panel :deep(.ant-spin-dot-item) {\n background-color: currentColor;\n}\n.dv-panel__failure {\n display: flex;\n max-width: min(320px, 100%);\n flex-direction: column;\n align-items: center;\n color: #667085;\n text-align: center;\n}\n.dv-panel__failure-copy {\n max-width: 100%;\n min-width: 0;\n}\n.dv-panel__failure-heading {\n overflow: hidden;\n color: #526075;\n font-size: 13px;\n font-weight: 600;\n line-height: 20px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dv-panel__failure-icon {\n margin-bottom: 9px;\n color: #8592a5;\n font-size: 22px;\n}\n.dv-panel__failure-detail {\n max-width: 100%;\n overflow: hidden;\n margin-top: 1px;\n color: #98a2b3;\n font-size: 12px;\n line-height: 18px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dv-panel__retry {\n width: auto;\n height: 28px;\n margin-top: 10px;\n padding: 0 10px;\n border-color: #dbe1e8;\n border-radius: 5px;\n color: #59677a;\n background: #fff;\n box-shadow: none;\n font-size: 12px;\n}\n.dv-panel__retry:hover,\n.dv-panel__retry:focus {\n border-color: #b8c7e5;\n color: var(--dv-primary, #315fc4);\n background: #f7f9fc;\n}\n.dv-panel__idle {\n color: #98a0ad;\n font-size: 12px;\n}\n.dv-panel__renderer {\n position: relative;\n min-width: 0;\n flex: 1;\n}\n.dv-panel__refreshing {\n position: absolute;\n z-index: 1;\n inset: 0;\n display: grid;\n place-items: center;\n background: rgb(255 255 255 / 76%);\n}\n.dv-panel__updated {\n display: none;\n margin-top: 8px;\n color: #98a0ad;\n font-size: 11px;\n text-align: right;\n}\n.dv-panel--metric :deep(.ant-card-head) {\n min-height: 40px;\n border-bottom: 0;\n}\n.dv-panel--metric :deep(.ant-card-head-title) {\n padding: 13px 0 4px;\n}\n.dv-panel--metric :deep(.ant-card-extra) {\n padding: 8px 0 0;\n}\n.dv-panel--metric :deep(.ant-card-body) {\n padding: 2px 16px 13px;\n}\n.dv-panel--metric .dv-panel__state--loading {\n min-height: 0;\n}\n.dv-panel--metric .dv-panel__state--failure {\n min-height: 0;\n}\n.dv-panel--metric .dv-panel__failure {\n width: fit-content;\n max-width: 100%;\n display: grid;\n grid-template-columns: 20px minmax(0, 1fr) 28px;\n column-gap: 8px;\n text-align: left;\n}\n.dv-panel--metric .dv-panel__failure-icon {\n margin-bottom: 0;\n font-size: 16px;\n}\n.dv-panel--metric .dv-panel__failure-detail {\n display: none;\n}\n.dv-panel--metric .dv-panel__retry {\n width: 28px;\n margin-top: 0;\n padding: 0;\n border-color: transparent;\n background: transparent;\n}\n.dv-panel--metric .dv-panel__retry-label {\n display: none;\n}\n.dv-panel--metric .dv-panel__state--metric-empty {\n min-height: 0;\n color: #98a0ad;\n font-size: 12px;\n line-height: 20px;\n}\n.dv-panel--metric .dv-panel__title {\n color: #637083;\n font-size: 13px;\n font-weight: 550;\n}\n.dv-panel--metric .dv-panel__actions {\n opacity: 0;\n transition: opacity 0.16s ease;\n}\n.dv-panel--metric:hover .dv-panel__actions,\n.dv-panel--metric:focus-within .dv-panel__actions {\n opacity: 1;\n}\n</style>\n","import { computed, onBeforeUnmount, onMounted, shallowRef } from \"vue\";\n\nimport type {\n DashboardRuntime,\n DashboardRuntimeSnapshot,\n DashboardVariablePatch,\n RefreshPanelsOptions\n} from \"../../core\";\n\nexport interface UseDashboardRuntimeOptions {\n autoLoad?: boolean;\n}\n\nexport function useDashboardRuntime(runtime: DashboardRuntime, options: UseDashboardRuntimeOptions = {}) {\n const snapshot = shallowRef<DashboardRuntimeSnapshot>(runtime.snapshot);\n let unsubscribe: (() => void) | undefined;\n\n onMounted(() => {\n unsubscribe = runtime.subscribe((next) => {\n snapshot.value = next;\n });\n if (options.autoLoad !== false) void runtime.load();\n });\n onBeforeUnmount(() => unsubscribe?.());\n\n return {\n snapshot,\n context: computed(() => snapshot.value.context),\n panelStates: computed(() => snapshot.value.panelStates),\n isLoading: computed(() => snapshot.value.isGlobalLoading),\n loadPanels: (panelIds: Iterable<string>) => runtime.loadPanels(panelIds),\n refreshAll: () => runtime.refreshAll(),\n refreshPanels: (panelIds: Iterable<string>, refreshOptions?: RefreshPanelsOptions) =>\n runtime.refreshPanels(panelIds, refreshOptions),\n refreshPanel: (panelId: string) => runtime.refreshPanel(panelId),\n retryPanel: (panelId: string) => runtime.retryPanel(panelId),\n setVariables: (patch: DashboardVariablePatch, panelIds?: Iterable<string>) => runtime.setVariables(patch, panelIds)\n };\n}\n","export function downloadBlob(content: BlobPart, mimeType: string, filename: string): void {\n const url = URL.createObjectURL(new Blob([content], { type: mimeType }));\n triggerDownload(url, filename);\n window.setTimeout(() => URL.revokeObjectURL(url), 0);\n}\n\nexport function downloadDataUrl(dataUrl: string, filename: string): void {\n triggerDownload(dataUrl, filename);\n}\n\nfunction triggerDownload(url: string, filename: string): void {\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n anchor.hidden = true;\n document.body.append(anchor);\n anchor.click();\n anchor.remove();\n}\n","<template>\n <section ref=\"dashboardElement\" class=\"dv-dashboard\">\n <header v-if=\"showHeader\" class=\"dv-dashboard__header\">\n <div>\n <h1>{{ runtime.config.title }}</h1>\n <p v-if=\"runtime.config.description\">{{ runtime.config.description }}</p>\n </div>\n </header>\n <DashboardFilterBar\n v-if=\"runtime.config.filterBar\"\n :config=\"runtime.config.filterBar\"\n :context=\"context\"\n :loading=\"isLoading\"\n @change=\"onVariablesChange\"\n @refresh=\"refreshAll\"\n />\n <div class=\"dv-dashboard__grid\">\n <div\n v-for=\"panel in runtime.config.panels\"\n :key=\"panel.id\"\n class=\"dv-dashboard__cell\"\n :data-panel-id=\"panel.id\"\n :style=\"panelStyle(panel)\"\n >\n <DashboardPanel\n :ref=\"(value) => setPanelRef(panel.id, value)\"\n :context=\"context\"\n :definition=\"runtime.dataRuntime.registries.rendererDefinitions.require(panel.rendererId)\"\n :filter-summary=\"filterSummary\"\n :panel=\"panel\"\n :refresh-disabled=\"isLoading\"\n :renderer=\"resolvePanelComponent(panel)\"\n :state=\"panelStates[panel.id]!\"\n @action=\"(actionId) => runtime.executePanelAction(panel.id, actionId)\"\n @export-csv=\"exportCsv(panel.id)\"\n @export-png=\"exportPng(panel.id)\"\n @refresh=\"refreshPanel(panel.id)\"\n @retry=\"retryPanel(panel.id)\"\n @visualization-event=\"(event) => runtime.dispatchEvent(event)\"\n />\n </div>\n </div>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, markRaw, onBeforeMount, onBeforeUnmount, onMounted, ref, toRaw, type Component } from \"vue\";\n\nimport {\n buildDashboardSearch,\n createPanelCsvFilename,\n isPanelExportEnabled,\n serializePanelCsv,\n type DashboardRuntime,\n type DashboardVariablePatch,\n type PanelConfig\n} from \"../../core\";\nimport { useDashboardRuntime } from \"../composables\";\nimport { downloadBlob, downloadDataUrl } from \"../export\";\nimport type { DashboardPanelComponentMap, VueRendererRegistry } from \"../registry\";\nimport DashboardFilterBar from \"./DashboardFilterBar.vue\";\nimport DashboardPanel from \"./DashboardPanel.vue\";\n\nconst props = withDefaults(\n defineProps<{\n runtime: DashboardRuntime;\n rendererRegistry: VueRendererRegistry;\n panelComponents?: DashboardPanelComponentMap;\n autoLoad?: boolean;\n lazyLoad?: boolean;\n lazyLoadRootMargin?: string;\n syncUrl?: boolean;\n showHeader?: boolean;\n }>(),\n { autoLoad: true, lazyLoad: true, lazyLoadRootMargin: \"600px 0px\", syncUrl: true, showHeader: true }\n);\n\nconst panelRefs = new Map<string, InstanceType<typeof DashboardPanel>>();\nconst dashboardElement = ref<HTMLElement>();\nconst nearPanelIds = new Set<string>();\nconst pendingPanelIds = new Set<string>();\nlet intersectionObserver: IntersectionObserver | undefined;\nlet lazyObserverActive = false;\nlet loadQueued = false;\nonBeforeMount(() => {\n if (props.syncUrl && typeof window !== \"undefined\") props.runtime.restoreContext(window.location.search);\n});\nconst {\n context,\n panelStates,\n isLoading,\n loadPanels,\n refreshAll: refreshRuntimeAll,\n refreshPanels,\n refreshPanel,\n retryPanel,\n setVariables\n} = useDashboardRuntime(props.runtime, { autoLoad: props.autoLoad && !props.lazyLoad });\n\nonMounted(() => {\n if (!props.autoLoad || !props.lazyLoad) return;\n if (typeof IntersectionObserver === \"undefined\") {\n void refreshRuntimeAll();\n return;\n }\n lazyObserverActive = true;\n intersectionObserver = new IntersectionObserver(onPanelIntersection, {\n rootMargin: props.lazyLoadRootMargin\n });\n dashboardElement.value\n ?.querySelectorAll<HTMLElement>(\".dv-dashboard__cell\")\n .forEach((element) => intersectionObserver?.observe(element));\n});\nonBeforeUnmount(() => {\n intersectionObserver?.disconnect();\n intersectionObserver = undefined;\n lazyObserverActive = false;\n nearPanelIds.clear();\n pendingPanelIds.clear();\n});\n\nconst filterSummary = computed(() =>\n (props.runtime.config.variables ?? [])\n .map((variable) => `${variable.label}: ${formatVariable(context.value.variables[variable.id])}`)\n .join(\" · \")\n);\n\nfunction formatVariable(value: unknown): string {\n return Array.isArray(value) ? value.join(\", \") : String(value ?? \"--\");\n}\nfunction panelStyle(panel: PanelConfig) {\n const span = panel.layout.span;\n return {\n \"--dv-panel-xs\": String(span.xs),\n \"--dv-panel-sm\": String(span.sm ?? span.xs),\n \"--dv-panel-md\": String(span.md ?? span.sm ?? span.xs),\n \"--dv-panel-lg\": String(span.lg ?? span.md ?? span.sm ?? span.xs),\n \"--dv-panel-xl\": String(span.xl ?? span.lg ?? span.md ?? span.sm ?? span.xs)\n };\n}\nfunction resolvePanelComponent(panel: PanelConfig): Component {\n const component = props.panelComponents?.[panel.id] ?? props.rendererRegistry.require(panel.rendererId).component;\n return markRaw(toRaw(component));\n}\nfunction setPanelRef(panelId: string, value: unknown): void {\n if (value) panelRefs.set(panelId, value as InstanceType<typeof DashboardPanel>);\n else panelRefs.delete(panelId);\n}\nfunction onPanelIntersection(entries: IntersectionObserverEntry[]): void {\n entries.forEach((entry) => {\n const panelId = (entry.target as HTMLElement).dataset.panelId;\n if (!panelId) return;\n if (entry.isIntersecting) {\n nearPanelIds.add(panelId);\n pendingPanelIds.add(panelId);\n } else {\n nearPanelIds.delete(panelId);\n pendingPanelIds.delete(panelId);\n }\n });\n if (!pendingPanelIds.size || loadQueued) return;\n loadQueued = true;\n queueMicrotask(() => {\n loadQueued = false;\n const panelIds = Array.from(pendingPanelIds);\n pendingPanelIds.clear();\n void loadPanels(panelIds);\n });\n}\nfunction refreshAll(): ReturnType<DashboardRuntime[\"refreshAll\"]> {\n return lazyObserverActive ? refreshPanels(nearPanelIds, { deferUnselected: true }) : refreshRuntimeAll();\n}\nasync function onVariablesChange(patch: DashboardVariablePatch): Promise<void> {\n const pendingRefresh = setVariables(patch, lazyObserverActive ? nearPanelIds : undefined);\n if (props.syncUrl && typeof window !== \"undefined\") {\n const search = buildDashboardSearch(props.runtime.config, props.runtime.context, window.location.search);\n window.history.replaceState(\n window.history.state,\n \"\",\n `${window.location.pathname}${search}${window.location.hash}`\n );\n }\n await pendingRefresh;\n}\nfunction exportCsv(panelId: string): void {\n const panel = props.runtime.config.panels.find((candidate) => candidate.id === panelId);\n if (\n !panel ||\n !isPanelExportEnabled(\n panel,\n props.runtime.dataRuntime.registries.rendererDefinitions.require(panel.rendererId).capabilities,\n \"csv\"\n )\n )\n return;\n const dataset = panelStates.value[panelId]?.dataset;\n if (!dataset) return;\n const csv = serializePanelCsv(dataset, panel, context.value);\n downloadBlob(csv, \"text/csv;charset=utf-8\", createPanelCsvFilename(props.runtime.config.id, panel.id));\n}\nfunction exportPng(panelId: string): void {\n const panel = props.runtime.config.panels.find((candidate) => candidate.id === panelId);\n if (\n !panel ||\n !isPanelExportEnabled(\n panel,\n props.runtime.dataRuntime.registries.rendererDefinitions.require(panel.rendererId).capabilities,\n \"png\"\n )\n )\n return;\n const dataUrl = panelRefs.get(panelId)?.exportPng();\n if (dataUrl) downloadDataUrl(dataUrl, `${props.runtime.config.id}-${panelId}.png`);\n}\n\ndefineExpose({ refreshAll, refreshPanel, exportCsv, exportPng });\n</script>\n\n<style scoped>\n.dv-dashboard {\n --dv-card-border: #e1e6ed;\n --dv-card-divider: #edf0f4;\n --dv-text-title: #273244;\n --dv-text-body: #182230;\n --dv-text-secondary: #657184;\n --dv-text-muted: #8a94a6;\n width: 100%;\n min-width: 0;\n color: var(--dv-text-body);\n}\n.dv-dashboard__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 16px;\n}\n.dv-dashboard__header h1 {\n margin: 0;\n font-size: 22px;\n font-weight: 650;\n line-height: 30px;\n letter-spacing: 0;\n}\n.dv-dashboard__header p {\n margin: 4px 0 0;\n color: #64748b;\n font-size: 13px;\n}\n.dv-dashboard__grid {\n display: grid;\n grid-template-columns: repeat(24, minmax(0, 1fr));\n gap: 14px;\n margin-top: 14px;\n}\n.dv-dashboard__cell {\n grid-column: span var(--dv-panel-xs);\n min-width: 0;\n}\n@media (min-width: 576px) {\n .dv-dashboard__cell {\n grid-column: span var(--dv-panel-sm);\n }\n}\n@media (min-width: 768px) {\n .dv-dashboard__cell {\n grid-column: span var(--dv-panel-md);\n }\n}\n@media (min-width: 992px) {\n .dv-dashboard__cell {\n grid-column: span var(--dv-panel-lg);\n }\n}\n@media (min-width: 1200px) {\n .dv-dashboard__cell {\n grid-column: span var(--dv-panel-xl);\n }\n}\n@media (max-width: 767px) {\n .dv-dashboard__grid {\n gap: 12px;\n }\n}\n</style>\n","import { FormatType } from \"@blazes/charts\";\n\nimport type { ValueFormat } from \"../../core\";\n\nexport function toChartFormat(format: ValueFormat): FormatType {\n if (format.type === \"percent\") return FormatType.PERCENT;\n if (format.type === \"decimal\") return FormatType.DECIMAL;\n return FormatType.COMMAS;\n}\n\nexport interface ChartRendererExpose {\n exportPng(): string | undefined;\n}\n\nexport function chartEventFields(value: unknown): Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null ? (value as Record<string, unknown>) : {};\n}\n","<template>\n <div class=\"dv-chart-renderer dv-bar-renderer\">\n <ChartBar ref=\"chartRef\" :option=\"option\" :size=\"Size.SMALL\" @data-point-click=\"onClick\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ChartBar, Size, type Bar } from \"@blazes/charts\";\nimport { computed, ref } from \"vue\";\n\nimport {\n valueFormatter,\n type BarViewModel,\n type DashboardContext,\n type PanelConfig,\n type VisualizationEvent\n} from \"../../core\";\nimport { STANDARD_CATEGORY_AXIS, STANDARD_CHART_COLORS, STANDARD_CHART_TOOLTIP, STANDARD_VALUE_AXIS } from \"../theme\";\nimport { chartEventFields, toChartFormat, type ChartRendererExpose } from \"./chart-format\";\n\nconst props = defineProps<{ viewModel: BarViewModel; panel: PanelConfig; context: DashboardContext }>();\nconst emit = defineEmits<{ visualizationEvent: [event: VisualizationEvent] }>();\nconst chartRef = ref<ChartRendererExpose>();\n\nfunction formatValue(value: unknown, series: BarViewModel[\"series\"][number], axis = false): string {\n const formatted = axis\n ? valueFormatter.formatAxis(value, series.format, props.context)\n : valueFormatter.formatTooltip(value, series.format, props.context);\n const formatOwnsUnit = series.format.type === \"currency\" || series.format.type === \"percent\" || series.format.unit;\n return value !== null && value !== undefined && value !== \"\" && series.unit && !formatOwnsUnit\n ? `${formatted}${series.unit}`\n : formatted;\n}\n\nconst option = computed<Bar.Option>(() => ({\n categories: [...props.viewModel.categories],\n colors: [...STANDARD_CHART_COLORS],\n orientation: props.viewModel.orientation,\n ...(props.viewModel.visibleCount !== undefined ? { visibleCount: props.viewModel.visibleCount } : {}),\n grid: {\n top: 18,\n right: props.viewModel.orientation === \"horizontal\" && props.viewModel.showLabels ? 78 : 18,\n bottom: 10,\n left: 16,\n containLabel: true\n },\n categoryAxis: {\n ...STANDARD_CATEGORY_AXIS,\n ...(props.viewModel.orientation === \"horizontal\" && props.viewModel.visibleCount !== undefined\n ? { inverse: true }\n : {}),\n axisLabel: { ...STANDARD_CATEGORY_AXIS.axisLabel, interval: 0 }\n },\n valueAxis: {\n ...STANDARD_VALUE_AXIS,\n splitNumber: 4,\n axisLabel: {\n ...STANDARD_VALUE_AXIS.axisLabel,\n hideOverlap: true,\n ...(props.viewModel.series[0]\n ? { formatter: (value: unknown) => formatValue(value, props.viewModel.series[0]!, true) }\n : {})\n }\n },\n tooltip: {\n ...STANDARD_CHART_TOOLTIP,\n axisPointer: { type: \"shadow\", shadowStyle: { color: \"rgba(91, 114, 238, 0.055)\" } }\n },\n ...(props.viewModel.stacked ? { stack: \"total\" } : {}),\n series: props.viewModel.series.map((series) => ({\n name: series.label,\n data: [...series.values],\n formatType: toChartFormat(series.format),\n valueFormatter: (value: unknown) => formatValue(value, series),\n showLabel: props.viewModel.showLabels,\n itemStyle: {\n borderRadius: props.viewModel.orientation === \"horizontal\" ? [0, 5, 5, 0] : [5, 5, 0, 0]\n }\n }))\n}));\n\nfunction onClick(raw: unknown): void {\n const event = chartEventFields(raw);\n const seriesIndex = typeof event.seriesIndex === \"number\" ? event.seriesIndex : 0;\n const binding = props.panel.binding.type === \"bar\" ? props.panel.binding : undefined;\n if (!binding) return;\n emit(\"visualizationEvent\", {\n type: \"dataPointClick\",\n panelId: props.panel.id,\n datasetId: binding.datasetId,\n fields: Object.freeze({\n [binding.categoryField]: event.name,\n ...(binding.seriesField ? { [binding.seriesField]: event.seriesName } : {}),\n [binding.valueFields[binding.seriesField ? 0 : seriesIndex] ?? binding.valueFields[0]!]: event.value\n })\n });\n}\n\nfunction exportPng(): string | undefined {\n return chartRef.value?.exportPng();\n}\ndefineExpose({ exportPng });\n</script>\n\n<style scoped>\n.dv-chart-renderer {\n width: 100%;\n min-width: 0;\n}\n.dv-bar-renderer :deep(.bar-container) {\n height: 320px !important;\n}\n.dv-bar-renderer :deep(.legend) {\n min-height: 18px;\n margin-bottom: 2px;\n padding: 0 4px;\n}\n.dv-bar-renderer :deep(.legend-container) {\n justify-content: flex-end;\n}\n.dv-bar-renderer :deep(.legend-item) {\n margin-right: 12px;\n color: #667085;\n font-size: 11px;\n}\n.dv-bar-renderer :deep(.legend-item-color) {\n width: 9px;\n height: 9px;\n border-radius: 3px;\n}\n</style>\n","<template>\n <div class=\"dv-chart-renderer dv-line-renderer\">\n <ChartLine ref=\"chartRef\" :option=\"option\" :size=\"Size.SMALL\" @data-point-click=\"onClick\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ChartLine, Size, type Line } from \"@blazes/charts\";\nimport { computed, ref } from \"vue\";\n\nimport {\n valueFormatter,\n type DashboardContext,\n type LineViewModel,\n type PanelConfig,\n type VisualizationEvent\n} from \"../../core\";\nimport { STANDARD_CATEGORY_AXIS, STANDARD_CHART_COLORS, STANDARD_CHART_TOOLTIP, STANDARD_VALUE_AXIS } from \"../theme\";\nimport { chartEventFields, toChartFormat, type ChartRendererExpose } from \"./chart-format\";\n\nconst props = defineProps<{ viewModel: LineViewModel; panel: PanelConfig; context: DashboardContext }>();\nconst emit = defineEmits<{ visualizationEvent: [event: VisualizationEvent] }>();\nconst chartRef = ref<ChartRendererExpose>();\n\nfunction formatAxisValue(value: unknown, series: LineViewModel[\"series\"][number]): string {\n const formatted = valueFormatter.formatAxis(value, series.format, props.context);\n return appendSeriesUnit(formatted, series);\n}\n\nfunction appendSeriesUnit(formatted: string, series: LineViewModel[\"series\"][number]): string {\n const formatOwnsUnit = series.format.type === \"currency\" || series.format.type === \"percent\" || series.format.unit;\n return series.unit && !formatOwnsUnit ? `${formatted}${series.unit}` : formatted;\n}\n\nconst option = computed<Line.Option>(() => {\n const axisSeries = Array.from(\n new Map(props.viewModel.series.map((series) => [series.axisKey, series] as const)).values()\n );\n const axisIndexes = new Map(axisSeries.map((series, index) => [series.axisKey, index]));\n\n return {\n colors: [...STANDARD_CHART_COLORS],\n grid: { top: 18, right: axisSeries.length > 1 ? 24 : 16, bottom: 10, left: 16, containLabel: true },\n tooltip: {\n ...STANDARD_CHART_TOOLTIP,\n axisPointer: { type: \"line\", lineStyle: { color: \"#b8c1d1\", type: \"dashed\" } }\n },\n xAxis: {\n data: props.viewModel.categories.map(String),\n ...STANDARD_CATEGORY_AXIS,\n ...(props.viewModel.categoryFormat\n ? {\n valueFormatter: (value: unknown) =>\n valueFormatter.formatAxis(value, props.viewModel.categoryFormat!, props.context)\n }\n : {})\n },\n yAxis: axisSeries.map((series, index) => ({\n ...STANDARD_VALUE_AXIS,\n position: index === 0 ? \"left\" : \"right\",\n show: index < 2,\n axisLabel: {\n ...STANDARD_VALUE_AXIS.axisLabel,\n formatter: (value: unknown) => formatAxisValue(value, series)\n },\n splitLine: {\n show: index === 0,\n lineStyle: { color: \"#edf0f5\", type: \"dashed\" }\n }\n })),\n series: props.viewModel.series.map((series, index) => ({\n name: series.label,\n data: series.values.map((value) => value ?? undefined),\n formatType: toChartFormat(series.format),\n valueFormatter: (value: unknown) => {\n const formatted = valueFormatter.formatTooltip(value, series.format, props.context);\n return value === null || value === undefined || value === \"\" ? formatted : appendSeriesUnit(formatted, series);\n },\n showLabel: props.viewModel.showLabels,\n smooth: props.viewModel.smooth,\n yAxisIndex: axisIndexes.get(series.axisKey) ?? 0,\n showSymbol: false,\n symbol: \"circle\",\n symbolSize: 7,\n lineStyle: { width: index === 0 ? 3 : 2.25 },\n ...(index === 0\n ? {\n areaStyle: {\n opacity: 1,\n color: {\n type: \"linear\",\n x: 0,\n y: 0,\n x2: 0,\n y2: 1,\n colorStops: [\n { offset: 0, color: \"rgba(79, 107, 237, 0.22)\" },\n { offset: 1, color: \"rgba(79, 107, 237, 0.015)\" }\n ]\n }\n }\n }\n : {})\n })),\n markLine: {\n xAxis: props.viewModel.annotations.filter((item) => item.type === \"category\").map((item) => String(item.value)),\n yAxis: props.viewModel.annotations.filter((item) => item.type === \"value\").map((item) => String(item.value))\n }\n };\n});\n\nfunction onClick(raw: unknown): void {\n const event = chartEventFields(raw);\n const seriesIndex = typeof event.seriesIndex === \"number\" ? event.seriesIndex : 0;\n const binding = props.panel.binding.type === \"line\" ? props.panel.binding : undefined;\n if (!binding) return;\n emit(\"visualizationEvent\", {\n type: \"dataPointClick\",\n panelId: props.panel.id,\n datasetId: binding.datasetId,\n fields: Object.freeze({\n [binding.xField]: event.name,\n ...(binding.seriesField ? { [binding.seriesField]: event.seriesName } : {}),\n [binding.yFields[binding.seriesField ? 0 : seriesIndex] ?? binding.yFields[0]!]: event.value\n })\n });\n}\n\nfunction exportPng(): string | undefined {\n return chartRef.value?.exportPng();\n}\ndefineExpose({ exportPng });\n</script>\n\n<style scoped>\n.dv-chart-renderer {\n width: 100%;\n min-width: 0;\n}\n.dv-line-renderer :deep(.line-container) {\n height: 320px;\n}\n.dv-line-renderer :deep(.legend) {\n min-height: 18px;\n margin-bottom: 2px;\n padding: 0 4px;\n}\n.dv-line-renderer :deep(.legend-container) {\n justify-content: flex-end;\n}\n.dv-line-renderer :deep(.legend-item) {\n margin-right: 12px;\n color: #667085;\n font-size: 11px;\n}\n.dv-line-renderer :deep(.legend-item-color) {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n</style>\n","<template>\n <div class=\"dv-metric\">\n <div class=\"dv-metric__value\">\n <span class=\"dv-metric__number\">{{ formattedValue }}</span>\n <span v-if=\"displayUnit\" class=\"dv-metric__unit\">{{ displayUnit }}</span>\n </div>\n <div v-if=\"viewModel.comparison\" class=\"dv-metric__comparison\">\n <span>{{ viewModel.comparison.label }}</span>\n <strong :class=\"`dv-metric__comparison--${comparisonTone}`\">\n <component :is=\"comparisonIcon\" />\n {{ formattedComparison }}\n </strong>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { FallOutlined, MinusOutlined, RiseOutlined } from \"@ant-design/icons-vue\";\nimport { computed } from \"vue\";\n\nimport { valueFormatter, type DashboardContext, type MetricViewModel, type PanelConfig } from \"../../core\";\n\nconst props = defineProps<{\n viewModel: MetricViewModel;\n panel: PanelConfig;\n context: DashboardContext;\n}>();\n\nconst formattedValue = computed(() =>\n valueFormatter.formatDisplay(props.viewModel.value, props.viewModel.format, props.context)\n);\nconst displayUnit = computed(() =>\n props.viewModel.format.type === \"currency\" || props.viewModel.format.type === \"percent\"\n ? undefined\n : props.viewModel.unit\n);\nconst formattedComparison = computed(() => {\n const comparison = props.viewModel.comparison;\n return comparison ? valueFormatter.formatDisplay(comparison.value, comparison.format, props.context) : \"\";\n});\nconst comparisonIcon = computed(() => {\n if (props.viewModel.comparison?.direction === \"up\") return RiseOutlined;\n if (props.viewModel.comparison?.direction === \"down\") return FallOutlined;\n return MinusOutlined;\n});\nconst comparisonTone = computed(() => {\n const comparison = props.viewModel.comparison;\n if (!comparison || comparison.direction === \"flat\") return \"neutral\";\n if (comparison.colorMode === \"direction\") {\n return comparison.direction === \"up\" ? \"unfavorable\" : \"favorable\";\n }\n if (comparison.meaning === \"neutral\") return \"neutral\";\n const favorable =\n (comparison.meaning === \"positive\" && comparison.direction === \"up\") ||\n (comparison.meaning === \"negative\" && comparison.direction === \"down\");\n return favorable ? \"favorable\" : \"unfavorable\";\n});\n</script>\n\n<style scoped>\n.dv-metric {\n min-height: 62px;\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n}\n.dv-metric__value {\n display: flex;\n align-items: baseline;\n column-gap: 4px;\n color: #172033;\n font-size: 29px;\n font-weight: 650;\n letter-spacing: 0;\n line-height: 1.2;\n white-space: nowrap;\n}\n.dv-metric__number {\n font-feature-settings: \"tnum\";\n font-variant-numeric: tabular-nums;\n}\n.dv-metric__unit {\n position: relative;\n top: -1px;\n color: #7d8797;\n font-size: 12px;\n font-weight: 400;\n line-height: 1;\n}\n.dv-metric__comparison {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-top: 7px;\n color: #7b8493;\n font-size: 12px;\n line-height: 18px;\n}\n.dv-metric__comparison strong {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 600;\n}\n.dv-metric__comparison--favorable {\n color: #00a870;\n}\n.dv-metric__comparison--unfavorable {\n color: #f53f3f;\n}\n.dv-metric__comparison--neutral {\n color: #7b8493;\n}\n</style>\n","<template>\n <div class=\"dv-chart-renderer dv-pie-renderer\">\n <ChartPie ref=\"chartRef\" :option=\"option\" :size=\"Size.SMALL\" @data-point-click=\"onClick\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ChartPie, Size, type Pie } from \"@blazes/charts\";\nimport { computed, ref } from \"vue\";\n\nimport {\n valueFormatter,\n type DashboardContext,\n type PanelConfig,\n type PieViewModel,\n type VisualizationEvent\n} from \"../../core\";\nimport { STANDARD_CHART_COLORS, STANDARD_CHART_TOOLTIP } from \"../theme\";\nimport { chartEventFields, toChartFormat, type ChartRendererExpose } from \"./chart-format\";\n\nconst props = defineProps<{ viewModel: PieViewModel; panel: PanelConfig; context: DashboardContext }>();\nconst emit = defineEmits<{ visualizationEvent: [event: VisualizationEvent] }>();\nconst chartRef = ref<ChartRendererExpose>();\n\nfunction formatValue(value: unknown): string {\n const formatted = valueFormatter.formatTooltip(value, props.viewModel.valueFormat, props.context);\n const formatOwnsUnit =\n props.viewModel.valueFormat.type === \"currency\" ||\n props.viewModel.valueFormat.type === \"percent\" ||\n props.viewModel.valueFormat.unit;\n return props.viewModel.unit && !formatOwnsUnit ? `${formatted}${props.viewModel.unit}` : formatted;\n}\n\nconst option = computed<Pie.Option>(() => ({\n colors: [...STANDARD_CHART_COLORS],\n donut: props.viewModel.donut,\n showLegend: props.viewModel.showLegend,\n showLabels: false,\n center: [\"50%\", \"43%\"],\n radius: props.viewModel.donut ? [\"50%\", \"70%\"] : \"70%\",\n itemStyle: { borderColor: \"#fff\", borderWidth: 3, borderRadius: 4 },\n tooltip: { ...STANDARD_CHART_TOOLTIP },\n series: props.viewModel.items.map((item) => ({\n name: item.label,\n data: item.value,\n formatType: toChartFormat(props.viewModel.valueFormat),\n valueFormatter: formatValue\n })),\n ...(props.viewModel.donut\n ? {\n aggregation: {\n total: props.viewModel.items.reduce((sum, item) => sum + item.value, 0),\n label: props.panel.title.replace(/占比$/, \"\"),\n valueFormatter: formatValue,\n ...(props.viewModel.unit ? { unit: props.viewModel.unit } : {})\n }\n }\n : {})\n}));\n\nfunction onClick(raw: unknown): void {\n const event = chartEventFields(raw);\n const binding = props.panel.binding.type === \"pie\" ? props.panel.binding : undefined;\n if (!binding) return;\n emit(\"visualizationEvent\", {\n type: \"dataPointClick\",\n panelId: props.panel.id,\n datasetId: binding.datasetId,\n fields: Object.freeze({ [binding.nameField]: event.name, [binding.valueField]: event.value })\n });\n}\n\nfunction exportPng(): string | undefined {\n return chartRef.value?.exportPng();\n}\ndefineExpose({ exportPng });\n</script>\n\n<style scoped>\n.dv-chart-renderer {\n width: 100%;\n min-width: 0;\n}\n.dv-pie-renderer :deep(.pie-container) {\n height: 320px !important;\n flex-direction: column-reverse;\n}\n.dv-pie-renderer :deep(.legend) {\n min-height: 18px;\n margin: 4px 0 0;\n padding: 0 4px;\n}\n.dv-pie-renderer :deep(.legend-item) {\n margin-right: 12px;\n color: #667085;\n font-size: 11px;\n}\n.dv-pie-renderer :deep(.legend-item-color) {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n</style>\n","<template>\n <div class=\"dv-table-scroll\">\n <a-table\n class=\"dv-table\"\n :columns=\"columns\"\n :data-source=\"[...viewModel.rows]\"\n :pagination=\"viewModel.showPagination ? { pageSize: viewModel.pageSize, showSizeChanger: false } : false\"\n :row-key=\"rowKey\"\n :scroll=\"{ x: 'max-content' }\"\n size=\"small\"\n @change=\"onChange\"\n :custom-row=\"customRow\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { FallOutlined, MinusOutlined, RiseOutlined } from \"@ant-design/icons-vue\";\nimport { Progress as AProgress, Table as ATable, Tag as ATag } from \"ant-design-vue\";\nimport type { ColumnsType } from \"ant-design-vue/es/table\";\nimport { computed, h, type Component } from \"vue\";\n\nimport {\n valueFormatter,\n type DashboardContext,\n type PanelConfig,\n type TableCellDisplay,\n type TableCellTone,\n type TableColumnViewModel,\n type TableViewModel,\n type VisualizationEvent\n} from \"../../core\";\n\nconst props = defineProps<{ viewModel: TableViewModel; panel: PanelConfig; context: DashboardContext }>();\nconst emit = defineEmits<{ visualizationEvent: [event: VisualizationEvent] }>();\n\nconst columns = computed<ColumnsType<Record<string, unknown>>>(() =>\n props.viewModel.columns.map((column) => ({\n title: column.label,\n dataIndex: column.field,\n key: column.field,\n ...(column.width ? { width: column.width } : {}),\n sorter: column.sortable,\n ...(column.filterable\n ? {\n filters: Array.from(new Set(props.viewModel.rows.map((row) => String(row[column.field] ?? \"\"))))\n .slice(0, 50)\n .map((value) => ({ text: value || \"--\", value })),\n onFilter: (value: string | number | boolean, row: Record<string, unknown>) =>\n String(row[column.field] ?? \"\") === String(value)\n }\n : {}),\n customRender: ({ text }: { text: unknown }) => renderCell(text, column)\n }))\n);\n\nfunction formatCellValue(text: unknown, column: TableColumnViewModel): string {\n return valueFormatter.formatDisplay(\n text,\n column.format ?? {\n type: column.dataType === \"date\" ? \"date\" : column.dataType === \"datetime\" ? \"datetime\" : \"number\"\n },\n props.context\n );\n}\n\nfunction renderCell(text: unknown, column: TableColumnViewModel) {\n const formatted = formatCellValue(text, column);\n if (!column.display) return formatted;\n if (column.display.type === \"progress\") return renderProgressCell(text, formatted, column.display);\n if (column.display.type === \"trend\") return renderTrendCell(text, formatted, column.display);\n return renderTagCell(text, formatted, column.display);\n}\n\nfunction finiteNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction renderProgressCell(\n text: unknown,\n formatted: string,\n display: Extract<TableCellDisplay, { type: \"progress\" }>\n) {\n const value = finiteNumber(text);\n if (value === undefined) return formatted;\n const max = display.max ?? 1;\n const percent = Math.min(100, Math.max(0, (value / max) * 100));\n return h(\"div\", { class: \"dv-table__progress-cell\" }, [\n h(AProgress, { percent, showInfo: false, size: \"small\", strokeWidth: 6 }),\n h(\"span\", { class: \"dv-table__cell-value\" }, formatted)\n ]);\n}\n\nfunction renderTrendCell(text: unknown, formatted: string, display: Extract<TableCellDisplay, { type: \"trend\" }>) {\n const value = finiteNumber(text);\n if (value === undefined) return formatted;\n const tone =\n value > 0\n ? (display.positiveTone ?? \"success\")\n : value < 0\n ? (display.negativeTone ?? \"danger\")\n : (display.zeroTone ?? \"neutral\");\n const icon: Component = value > 0 ? RiseOutlined : value < 0 ? FallOutlined : MinusOutlined;\n return h(\"span\", { class: [\"dv-table__trend\", `dv-table__trend--${tone}`] }, [h(icon), h(\"span\", formatted)]);\n}\n\nfunction renderTagCell(text: unknown, formatted: string, display: Extract<TableCellDisplay, { type: \"tag\" }>) {\n const tone = display.toneByValue?.[String(text ?? \"\")] ?? display.defaultTone ?? \"neutral\";\n return renderTag(formatted, tone);\n}\n\nfunction renderTag(label: string, tone: TableCellTone, icon?: Component) {\n return h(\n ATag,\n { class: [\"dv-table__tag\", `dv-table__tag--${tone}`] },\n { default: () => [...(icon ? [h(icon)] : []), h(\"span\", label)] }\n );\n}\n\nconst rowKeys = new WeakMap<object, string>();\nlet rowSequence = 0;\nfunction rowKey(row: Readonly<Record<string, unknown>>): string {\n const existing = rowKeys.get(row);\n if (existing) return existing;\n const key = `row-${++rowSequence}`;\n rowKeys.set(row, key);\n return key;\n}\nfunction customRow(row: Readonly<Record<string, unknown>>) {\n return {\n onClick: () =>\n emit(\"visualizationEvent\", {\n type: \"rowClick\",\n panelId: props.panel.id,\n datasetId: props.panel.binding.datasetId,\n fields: row\n })\n };\n}\nfunction onChange(): void {}\n</script>\n\n<style scoped>\n.dv-table :deep(.ant-table) {\n font-size: 12px;\n}\n.dv-table-scroll {\n width: 100%;\n overflow-x: auto;\n}\n.dv-table {\n min-width: 720px;\n}\n.dv-table :deep(.ant-table-thead > tr > th) {\n padding: 13px 16px;\n color: #5e6a7d;\n border-bottom: 1px solid #e5eaf0;\n font-weight: 600;\n background: #f7f9fb;\n}\n.dv-table :deep(.ant-table-tbody > tr > td) {\n padding: 14px 16px;\n color: #344054;\n border-bottom: 1px solid #edf0f4;\n}\n.dv-table :deep(.ant-table-tbody > tr.ant-table-row:hover > td) {\n background: #f8fafc;\n}\n.dv-table :deep(.dv-table__progress-cell) {\n display: grid;\n min-width: 160px;\n grid-template-columns: minmax(96px, 1fr) 48px;\n align-items: center;\n gap: 8px;\n}\n.dv-table :deep(.dv-table__progress-cell .ant-progress) {\n margin: 0;\n line-height: 1;\n}\n.dv-table :deep(.dv-table__progress-cell .ant-progress-inner) {\n background: #edf0f4;\n}\n.dv-table :deep(.dv-table__progress-cell .ant-progress-bg) {\n background: #315fc4;\n}\n.dv-table :deep(.dv-table__cell-value) {\n color: #657184;\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.dv-table :deep(.dv-table__trend) {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 600;\n line-height: 18px;\n white-space: nowrap;\n}\n.dv-table :deep(.dv-table__trend--neutral) {\n color: #7b8493;\n}\n.dv-table :deep(.dv-table__trend--info) {\n color: #315fc4;\n}\n.dv-table :deep(.dv-table__trend--success) {\n color: #00a870;\n}\n.dv-table :deep(.dv-table__trend--warning) {\n color: #c2410c;\n}\n.dv-table :deep(.dv-table__trend--danger) {\n color: #f53f3f;\n}\n.dv-table :deep(.dv-table__tag) {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin: 0;\n border-radius: 4px;\n font-size: 12px;\n line-height: 20px;\n}\n.dv-table :deep(.dv-table__tag--neutral) {\n color: #475467;\n border-color: #e4e7ec;\n background: #f2f4f7;\n}\n.dv-table :deep(.dv-table__tag--info) {\n color: #315fc4;\n border-color: #cbdafa;\n background: #eff6ff;\n}\n.dv-table :deep(.dv-table__tag--success) {\n color: #027a48;\n border-color: #abefc6;\n background: #ecfdf3;\n}\n.dv-table :deep(.dv-table__tag--warning) {\n color: #c2410c;\n border-color: #fed7aa;\n background: #fff7ed;\n}\n.dv-table :deep(.dv-table__tag--danger) {\n color: #b42318;\n border-color: #fecdca;\n background: #fef3f2;\n}\n.dv-table :deep(.ant-table-pagination.ant-pagination) {\n display: flex;\n align-items: center;\n gap: 4px;\n margin: 16px 0 0;\n}\n.dv-table :deep(.ant-table-pagination.ant-pagination::after) {\n display: none;\n}\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-item),\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-prev),\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-next),\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-jump-prev),\n.dv-table :deep(.ant-table-pagination.ant-pagination > .ant-pagination-jump-next) {\n display: flex;\n min-width: 28px;\n height: 28px;\n align-items: center;\n justify-content: center;\n margin: 0;\n border-radius: 5px;\n line-height: 1;\n}\n.dv-table :deep(.ant-table-pagination .ant-pagination-item > a),\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-link),\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-container) {\n display: flex;\n width: 100%;\n height: 100%;\n align-items: center;\n justify-content: center;\n padding: 0;\n line-height: 1;\n}\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-ellipsis) {\n display: flex;\n align-items: center;\n justify-content: center;\n letter-spacing: 1px;\n line-height: 1;\n text-indent: 0;\n}\n.dv-table :deep(.ant-table-pagination .anticon) {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n}\n.dv-table :deep(.ant-table-pagination .anticon svg) {\n display: block;\n}\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-active) {\n border-color: var(--dv-primary, #315fc4);\n background: #f0f4fc;\n background: color-mix(in srgb, var(--dv-primary, #315fc4) 8%, white);\n}\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-active > a) {\n color: var(--dv-primary, #315fc4);\n}\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled) .ant-pagination-item:not(.ant-pagination-item-disabled):hover\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-item:not(.ant-pagination-item-disabled):focus-visible\n ) {\n border-color: var(--dv-primary, #315fc4);\n background: #f0f4fc;\n background: color-mix(in srgb, var(--dv-primary, #315fc4) 8%, white);\n}\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-item:not(.ant-pagination-item-disabled):hover\n > a\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-item:not(.ant-pagination-item-disabled):focus-visible\n > a\n ),\n.dv-table :deep(.ant-table-pagination .ant-pagination-item-link-icon),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-prev:not(.ant-pagination-disabled):hover\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-prev:not(.ant-pagination-disabled):focus-visible\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-next:not(.ant-pagination-disabled):hover\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-next:not(.ant-pagination-disabled):focus-visible\n .ant-pagination-item-link\n ) {\n color: var(--dv-primary, #315fc4);\n}\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-prev:not(.ant-pagination-disabled):hover\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-prev:not(.ant-pagination-disabled):focus-visible\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-next:not(.ant-pagination-disabled):hover\n .ant-pagination-item-link\n ),\n.dv-table\n :deep(\n .ant-table-pagination:not(.ant-pagination-disabled)\n .ant-pagination-next:not(.ant-pagination-disabled):focus-visible\n .ant-pagination-item-link\n ) {\n border-color: var(--dv-primary, #315fc4);\n}\n</style>\n","import BarRenderer from \"../renderers/BarRenderer.vue\";\nimport LineRenderer from \"../renderers/LineRenderer.vue\";\nimport MetricRenderer from \"../renderers/MetricRenderer.vue\";\nimport PieRenderer from \"../renderers/PieRenderer.vue\";\nimport TableRenderer from \"../renderers/TableRenderer.vue\";\nimport type { VueRendererRegistry } from \"./renderer-registry\";\n\nexport function registerStandardVueRenderers(registry: VueRendererRegistry): VueRendererRegistry {\n registry.registerMany([\n { id: \"metric\", component: MetricRenderer },\n { id: \"line\", component: LineRenderer },\n { id: \"bar\", component: BarRenderer },\n { id: \"pie\", component: PieRenderer },\n { id: \"table\", component: TableRenderer }\n ]);\n return registry;\n}\n","import type { Component } from \"vue\";\n\nimport { PluginRegistry } from \"../../core\";\n\nexport interface VueVisualizationRenderer {\n id: string;\n component: Component;\n}\n\nexport type DashboardPanelComponentMap = Readonly<Record<string, Component>>;\n\nexport class VueRendererRegistry extends PluginRegistry<VueVisualizationRenderer> {\n constructor() {\n super(\"VueVisualizationRenderer\");\n }\n}\n\nexport function createVueRendererRegistry(): VueRendererRegistry {\n return new VueRendererRegistry();\n}\n"],"names":["props","__props","emit","__emit","layoutStyle","layout","selectValue","value","selectOptions","options","option","parseDate","date","formatDate","yesterdayDate","parts","part","yesterday","contextValue","variableId","dateRangeValueProps","control","start","end","onDateRangeChange","activePreset","days","_b","_a","preset","onPresetChange","event","presetId","item","onSelectChange","rendererRef","ref","rendererError","isMetricPanel","computed","panelFailure","canExportCsv","isPanelExportEnabled","canExportPng","canDownload","bodyStyle","panelMinHeight","headerHeight","updatedAt","exportPng","onDownloadMenuClick","onErrorCaptured","error","watch","__expose","useDashboardRuntime","runtime","snapshot","shallowRef","unsubscribe","onMounted","next","onBeforeUnmount","panelIds","refreshOptions","panelId","patch","downloadBlob","content","mimeType","filename","url","triggerDownload","downloadDataUrl","dataUrl","anchor","panelRefs","dashboardElement","nearPanelIds","pendingPanelIds","intersectionObserver","lazyObserverActive","loadQueued","onBeforeMount","context","panelStates","isLoading","loadPanels","refreshRuntimeAll","refreshPanels","refreshPanel","retryPanel","setVariables","onPanelIntersection","element","filterSummary","variable","formatVariable","panelStyle","panel","span","resolvePanelComponent","component","markRaw","toRaw","setPanelRef","entries","entry","refreshAll","onVariablesChange","pendingRefresh","search","buildDashboardSearch","exportCsv","candidate","dataset","csv","serializePanelCsv","createPanelCsvFilename","toChartFormat","format","FormatType","chartEventFields","chartRef","formatValue","series","axis","formatted","valueFormatter","formatOwnsUnit","STANDARD_CHART_COLORS","STANDARD_CATEGORY_AXIS","STANDARD_VALUE_AXIS","STANDARD_CHART_TOOLTIP","onClick","raw","seriesIndex","binding","formatAxisValue","appendSeriesUnit","axisSeries","axisIndexes","index","formattedValue","displayUnit","formattedComparison","comparison","comparisonIcon","RiseOutlined","FallOutlined","MinusOutlined","comparisonTone","sum","columns","column","row","text","renderCell","formatCellValue","renderProgressCell","renderTrendCell","renderTagCell","finiteNumber","display","max","percent","h","AProgress","tone","icon","renderTag","label","ATag","rowKeys","rowSequence","rowKey","existing","key","customRow","onChange","registerStandardVueRenderers","registry","MetricRenderer","LineRenderer","BarRenderer","PieRenderer","TableRenderer","VueRendererRegistry","PluginRegistry","createVueRendererRegistry"],"mappings":"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"}
|
package/package.json
CHANGED
package/dist/csv-Dyrr2yMA.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"csv-Dyrr2yMA.js","sources":["../src/core/telemetry/telemetry.ts","../src/core/variable/dashboard-context.ts","../src/core/variable/url-state.ts","../src/core/registry/plugin-registry.ts","../src/core/export/csv.ts"],"sourcesContent":["export type VisualizationTelemetryEventName =\n | \"config_validated\"\n | \"request_started\"\n | \"request_succeeded\"\n | \"request_failed\"\n | \"request_cancelled\"\n | \"request_cache_hit\"\n | \"dataset_cache_hit\"\n | \"dataset_succeeded\"\n | \"dataset_failed\"\n | \"adapter_failed\"\n | \"renderer_failed\"\n | \"export_failed\"\n | \"variable_decode_error\";\n\nexport interface VisualizationTelemetryEvent {\n name: VisualizationTelemetryEventName;\n dashboardId: string;\n requestId?: string;\n datasetId?: string;\n panelId?: string;\n providerId?: string;\n operationId?: string;\n durationMs?: number;\n errorCode?: string;\n}\n\nexport type VisualizationTelemetrySink = (event: Readonly<VisualizationTelemetryEvent>) => void;\n\nexport function emitTelemetry(sink: VisualizationTelemetrySink | undefined, event: VisualizationTelemetryEvent): void {\n try {\n sink?.(Object.freeze({ ...event }));\n } catch {\n // Telemetry must never break dashboard execution.\n }\n}\n","import type { DashboardConfig } from \"../config/dashboard-config-schema\";\nimport { cloneJsonValue, isJsonValue, type JsonValue } from \"../config\";\n\nexport interface DashboardContext {\n dashboardId: string;\n variables: Readonly<Record<string, JsonValue>>;\n timezone: string;\n locale: string;\n}\n\nexport interface CreateDashboardContextOptions {\n timezone: string;\n locale: string;\n variables?: Readonly<Record<string, JsonValue>>;\n}\n\nexport class DashboardVariableError extends Error {\n readonly code: \"variable_not_found\" | \"variable_value_invalid\";\n readonly variableId: string;\n\n constructor(code: DashboardVariableError[\"code\"], variableId: string, message: string) {\n super(message);\n this.name = \"DashboardVariableError\";\n this.code = code;\n this.variableId = variableId;\n }\n}\n\nfunction findVariable(config: DashboardConfig, variableId: string) {\n const variable = config.variables?.find((candidate) => candidate.id === variableId);\n if (!variable) {\n throw new DashboardVariableError(\"variable_not_found\", variableId, `Dashboard variable not found: ${variableId}`);\n }\n return variable;\n}\n\nexport function createDashboardContext(\n config: DashboardConfig,\n options: CreateDashboardContextOptions\n): DashboardContext {\n const overrides = options.variables ?? {};\n const variables = Object.fromEntries(\n (config.variables ?? []).map((variable) => [\n variable.id,\n cloneJsonValue(\n Object.prototype.hasOwnProperty.call(overrides, variable.id) ? overrides[variable.id]! : variable.defaultValue\n )\n ])\n );\n\n return Object.freeze({\n dashboardId: config.id,\n variables: Object.freeze(variables),\n timezone: options.timezone,\n locale: options.locale\n });\n}\n\nexport function readDashboardVariable(\n config: DashboardConfig,\n context: DashboardContext,\n variableId: string\n): JsonValue {\n const variable = findVariable(config, variableId);\n return cloneJsonValue(\n Object.prototype.hasOwnProperty.call(context.variables, variableId)\n ? context.variables[variableId]!\n : variable.defaultValue\n );\n}\n\nexport function writeDashboardVariable(\n config: DashboardConfig,\n context: DashboardContext,\n variableId: string,\n value: JsonValue\n): DashboardContext {\n findVariable(config, variableId);\n if (!isJsonValue(value)) {\n throw new DashboardVariableError(\n \"variable_value_invalid\",\n variableId,\n `Dashboard variable value is not JSON serializable: ${variableId}`\n );\n }\n\n return Object.freeze({\n ...context,\n variables: Object.freeze({ ...context.variables, [variableId]: cloneJsonValue(value) })\n });\n}\n","import type { DashboardConfig, DashboardVariableConfig } from \"../config/dashboard-config-schema\";\nimport { isJsonValue, jsonValuesEqual, type JsonValue } from \"../config\";\nimport { emitTelemetry, type VisualizationTelemetrySink } from \"../telemetry\";\nimport {\n createDashboardContext,\n readDashboardVariable,\n writeDashboardVariable,\n type CreateDashboardContextOptions,\n type DashboardContext\n} from \"./dashboard-context\";\n\nexport interface VariableDiagnostic {\n level: \"warning\";\n code: \"variable_decode_error\";\n message: string;\n variableId: string;\n urlKey: string;\n}\n\nexport interface RestoreDashboardContextResult {\n context: DashboardContext;\n diagnostics: ReadonlyArray<VariableDiagnostic>;\n}\n\nfunction resolveCodec(variable: DashboardVariableConfig) {\n if (variable.urlCodec) {\n return variable.urlCodec;\n }\n if (Array.isArray(variable.defaultValue)) {\n if (variable.defaultValue.every((item) => typeof item === \"number\")) {\n return \"number-array\";\n }\n if (variable.defaultValue.every((item) => typeof item === \"string\")) {\n return \"string-array\";\n }\n return \"json\";\n }\n if (typeof variable.defaultValue === \"number\" || typeof variable.defaultValue === \"boolean\") {\n return typeof variable.defaultValue;\n }\n if (variable.defaultValue !== null && typeof variable.defaultValue === \"object\") {\n return \"json\";\n }\n return \"string\";\n}\n\nfunction decodeValue(rawValue: string, variable: DashboardVariableConfig): JsonValue | undefined {\n switch (resolveCodec(variable)) {\n case \"number\": {\n if (rawValue.trim() === \"\") return undefined;\n const value = Number(rawValue);\n return Number.isFinite(value) ? value : undefined;\n }\n case \"boolean\":\n return rawValue === \"true\" ? true : rawValue === \"false\" ? false : undefined;\n case \"string-array\":\n return rawValue ? rawValue.split(\",\") : [];\n case \"number-array\": {\n const values = rawValue ? rawValue.split(\",\").map(Number) : [];\n return values.every(Number.isFinite) ? values : undefined;\n }\n case \"json\":\n try {\n const value: unknown = JSON.parse(rawValue);\n return isJsonValue(value) ? value : undefined;\n } catch {\n return undefined;\n }\n default:\n return rawValue;\n }\n}\n\nfunction encodeValue(value: JsonValue, variable: DashboardVariableConfig): string {\n switch (resolveCodec(variable)) {\n case \"string-array\":\n case \"number-array\":\n return Array.isArray(value) ? value.join(\",\") : \"\";\n case \"json\":\n return JSON.stringify(value);\n default:\n return String(value ?? \"\");\n }\n}\n\nexport function restoreDashboardContextFromSearch(\n config: DashboardConfig,\n search: string,\n options: CreateDashboardContextOptions,\n telemetry?: VisualizationTelemetrySink\n): RestoreDashboardContextResult {\n const query = new URLSearchParams(search);\n const diagnostics: VariableDiagnostic[] = [];\n let context = createDashboardContext(config, options);\n\n for (const variable of config.variables ?? []) {\n if (!variable.urlKey || !query.has(variable.urlKey)) {\n continue;\n }\n\n const decoded = decodeValue(query.get(variable.urlKey) ?? \"\", variable);\n if (decoded === undefined) {\n diagnostics.push({\n level: \"warning\",\n code: \"variable_decode_error\",\n message: `Unable to decode URL variable ${variable.id}. The default value was used.`,\n variableId: variable.id,\n urlKey: variable.urlKey\n });\n emitTelemetry(telemetry, {\n name: \"variable_decode_error\",\n dashboardId: config.id,\n errorCode: \"variable_decode_error\"\n });\n continue;\n }\n\n context = writeDashboardVariable(config, context, variable.id, decoded);\n }\n\n return { context, diagnostics: Object.freeze(diagnostics) };\n}\n\nexport function buildDashboardSearch(config: DashboardConfig, context: DashboardContext, currentSearch = \"\"): string {\n const query = new URLSearchParams(currentSearch);\n\n for (const variable of config.variables ?? []) {\n if (!variable.urlKey) {\n continue;\n }\n\n const value = readDashboardVariable(config, context, variable.id);\n if (jsonValuesEqual(value, variable.defaultValue)) {\n query.delete(variable.urlKey);\n } else {\n query.set(variable.urlKey, encodeValue(value, variable));\n }\n }\n\n const value = query.toString();\n return value ? `?${value}` : \"\";\n}\n","export interface RegistryEntry {\n id: string;\n}\n\nexport interface ReadonlyRegistry<T extends RegistryEntry> {\n get(id: string): T | undefined;\n require(id: string): T;\n has(id: string): boolean;\n values(): ReadonlyArray<T>;\n}\n\nexport class RegistryError extends Error {\n readonly code: \"duplicate_registry_id\" | \"invalid_registry_id\" | \"registry_entry_not_found\";\n readonly registryName: string;\n readonly entryId: string;\n\n constructor(code: RegistryError[\"code\"], registryName: string, entryId: string, message: string) {\n super(message);\n this.name = \"RegistryError\";\n this.code = code;\n this.registryName = registryName;\n this.entryId = entryId;\n }\n}\n\nexport class PluginRegistry<T extends RegistryEntry> implements ReadonlyRegistry<T> {\n readonly #entries = new Map<string, T>();\n\n constructor(readonly name: string) {}\n\n register(entry: T): this {\n if (!entry.id.trim()) {\n throw new RegistryError(\"invalid_registry_id\", this.name, entry.id, `${this.name} entry ID cannot be empty.`);\n }\n if (this.#entries.has(entry.id)) {\n throw new RegistryError(\n \"duplicate_registry_id\",\n this.name,\n entry.id,\n `${this.name} entry is already registered: ${entry.id}`\n );\n }\n\n this.#entries.set(entry.id, entry);\n return this;\n }\n\n registerMany(entries: ReadonlyArray<T>): this {\n entries.forEach((entry) => this.register(entry));\n return this;\n }\n\n get(id: string): T | undefined {\n return this.#entries.get(id);\n }\n\n require(id: string): T {\n const entry = this.get(id);\n if (!entry) {\n throw new RegistryError(\"registry_entry_not_found\", this.name, id, `${this.name} entry is not registered: ${id}`);\n }\n return entry;\n }\n\n has(id: string): boolean {\n return this.#entries.has(id);\n }\n\n values(): ReadonlyArray<T> {\n return Array.from(this.#entries.values());\n }\n\n clear(): void {\n this.#entries.clear();\n }\n}\n","import type { DatasetResult } from \"../dataset\";\nimport { valueFormatter, type FormatterContext } from \"../formatter\";\nimport type { PanelBinding, PanelConfig, ValueFormat } from \"../config\";\n\nexport interface SerializePanelCsvOptions {\n includeBom?: boolean;\n lineEnding?: \"\\r\\n\" | \"\\n\";\n}\n\nfunction unique(values: ReadonlyArray<string | undefined>): string[] {\n return Array.from(new Set(values.filter((value): value is string => Boolean(value))));\n}\n\nexport function getPanelExportFields(binding: PanelBinding): string[] {\n switch (binding.type) {\n case \"metric\":\n return unique([binding.valueField, binding.compareField]);\n case \"line\":\n return unique([binding.xField, binding.seriesField, ...binding.yFields]);\n case \"bar\":\n return unique([binding.categoryField, binding.seriesField, ...binding.valueFields]);\n case \"pie\":\n return unique([binding.nameField, binding.valueField]);\n case \"table\":\n return unique(binding.columns);\n case \"wordCloud\":\n return unique([...binding.labelFields, binding.valueField, binding.semanticField]);\n case \"pivotTableS2\":\n return unique([...binding.rowFields, ...binding.columnFields, ...binding.valueFields]);\n }\n}\n\nfunction defaultFormat(dataType: DatasetResult[\"fields\"][number][\"dataType\"]): ValueFormat {\n if (dataType === \"date\") return { type: \"date\" };\n if (dataType === \"datetime\") return { type: \"datetime\" };\n if (dataType === \"number\") return { type: \"number\" };\n return { type: \"number\" };\n}\n\nfunction escapeCsv(value: string | number | boolean): string {\n const text = String(value);\n return /[\",\\r\\n]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nexport function serializePanelCsv(\n dataset: DatasetResult,\n panel: Pick<PanelConfig, \"binding\" | \"enhancement\">,\n _context: FormatterContext,\n options: SerializePanelCsvOptions = {}\n): string {\n const fieldIds = getPanelExportFields(panel.binding);\n const fieldsById = new Map(dataset.fields.map((field) => [field.key, field]));\n const fields = fieldIds.map((fieldId) => {\n const field = fieldsById.get(fieldId);\n if (!field) throw new Error(`CSV export field not found in dataset ${dataset.datasetId}: ${fieldId}`);\n return field;\n });\n const lineEnding = options.lineEnding ?? \"\\r\\n\";\n const lines = [\n fields.map((field) => escapeCsv(field.label)).join(\",\"),\n ...dataset.rows.map((row) =>\n fields\n .map((field) => {\n const format =\n panel.enhancement?.common?.formatOverrides?.[field.key] ?? field.format ?? defaultFormat(field.dataType);\n return escapeCsv(valueFormatter.formatExport(row[field.key], format));\n })\n .join(\",\")\n )\n ];\n return `${options.includeBom === false ? \"\" : \"\\uFEFF\"}${lines.join(lineEnding)}`;\n}\n\nexport function createPanelCsvFilename(dashboardId: string, panelId: string): string {\n const safe = `${dashboardId}-${panelId}`.replace(/[^A-Za-z0-9._-]+/g, \"-\").replace(/^-+|-+$/g, \"\");\n return `${safe || \"dashboard-panel\"}.csv`;\n}\n"],"names":["emitTelemetry","sink","event","DashboardVariableError","code","variableId","message","__publicField","findVariable","config","variable","_a","candidate","createDashboardContext","options","overrides","variables","cloneJsonValue","readDashboardVariable","context","writeDashboardVariable","value","isJsonValue","resolveCodec","item","decodeValue","rawValue","values","encodeValue","restoreDashboardContextFromSearch","search","telemetry","query","diagnostics","decoded","buildDashboardSearch","currentSearch","jsonValuesEqual","RegistryError","registryName","entryId","PluginRegistry","name","__privateAdd","_entries","entry","__privateGet","entries","id","unique","getPanelExportFields","binding","defaultFormat","dataType","escapeCsv","text","serializePanelCsv","dataset","panel","_context","fieldIds","fieldsById","field","fields","fieldId","lineEnding","lines","row","format","_c","_b","valueFormatter","createPanelCsvFilename","dashboardId","panelId"],"mappings":"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"}
|