@blazes/data-visualization 1.0.0-alpha.0 → 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 <a-empty v-else class=\"dv-panel__state\" description=\"暂无数据\" />\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 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 Empty as AEmpty,\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 :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":";;;;;;;;;;;;;;;;;;;AA+FA,UAAMA,IAAQC,GACRC,IAAOC;AAEb,aAASC,EAAYC,GAAgE;AACnF,aAAO;AAAA,QACL,kBAAkB,OAAOA,EAAO,EAAE;AAAA,QAClC,kBAAkB,OAAOA,EAAO,MAAMA,EAAO,EAAE;AAAA,QAC/C,kBAAkB,OAAOA,EAAO,MAAMA,EAAO,MAAMA,EAAO,EAAE;AAAA,QAC5D,kBAAkB,OAAOA,EAAO,MAAMA,EAAO,MAAMA,EAAO,MAAMA,EAAO,EAAE;AAAA,QACzE,kBAAkB,OAAOA,EAAO,MAAMA,EAAO,MAAMA,EAAO,MAAMA,EAAO,MAAMA,EAAO,EAAE;AAAA,MAAA;AAAA,IAE1F;AACA,aAASC,EAAYC,GAAmC;AACtD,aAAOA;AAAA,IACT;AACA,aAASC,EACPC,GACO;AACP,aAAOA,EAAQ,IAAI,CAACC,OAAY,EAAE,GAAGA,IAAS;AAAA,IAChD;AACA,aAASC,EAAUJ,GAAgD;AACjE,UAAI,OAAOA,KAAU,YAAY,CAAC,sBAAsB,KAAKA,CAAK,EAAG;AACrE,YAAMK,IAAO,oBAAI,KAAK,GAAGL,CAAK,YAAY;AAC1C,aAAO,OAAO,MAAMK,EAAK,QAAA,CAAS,IAAI,SAAYA;AAAA,IACpD;AACA,aAASC,EAAWN,GAAqB;AACvC,aAAOA,EAAM,YAAA,EAAc,MAAM,GAAG,EAAE;AAAA,IACxC;AACA,aAASO,IAAsB;AAC7B,YAAMC,IAAQ,IAAI,KAAK,eAAe,SAAS;AAAA,QAC7C,UAAUf,EAAM,QAAQ;AAAA,QACxB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,KAAK;AAAA,MAAA,CACN,EAAE,cAAc,oBAAI,MAAM,GACrBY,IAAO,OAAO,YAAYG,EAAM,IAAI,CAACC,MAAS,CAACA,EAAK,MAAMA,EAAK,KAAK,CAAC,CAAC,GACtEC,IAAY,oBAAI,KAAK,GAAGL,EAAK,IAAI,IAAIA,EAAK,KAAK,IAAIA,EAAK,GAAG,YAAY;AAC7E,aAAAK,EAAU,WAAWA,EAAU,WAAA,IAAe,CAAC,GACxCA;AAAA,IACT;AACA,aAASC,EAAaC,GAA2C;AAC/D,aAAOnB,EAAM,QAAQ,UAAUmB,CAAU;AAAA,IAC3C;AACA,aAASC,EAAoBC,GAAyD;AACpF,YAAMC,IAAQJ,EAAaG,EAAQ,eAAe,GAC5CE,IAAML,EAAaG,EAAQ,aAAa;AAC9C,aAAI,OAAOC,KAAU,YAAY,OAAOC,KAAQ,YAAY,CAACZ,EAAUW,CAAK,KAAK,CAACX,EAAUY,CAAG,IACtF,CAAA,IAEF,EAAE,OAAO,CAACD,GAAOC,CAAG,EAAA;AAAA,IAC7B;AACA,aAASC,EAAkBH,GAA2Bd,GAAsB;AAC1E,UAAI,CAAC,MAAM,QAAQA,CAAK,KAAKA,EAAM,WAAW,EAAG;AACjD,YAAM,CAACe,GAAOC,CAAG,IAAIhB;AACrB,MAAI,OAAOe,KAAU,YAAY,OAAOC,KAAQ,YAChDrB,EAAK,UAAU;AAAA,QACb,CAACmB,EAAQ,eAAe,GAAGC;AAAA,QAC3B,CAACD,EAAQ,aAAa,GAAGE;AAAA,MAAA,CAC1B;AAAA,IACH;AACA,aAASE,EAAaJ,GAA+C;;AACnE,YAAMC,IAAQX,EAAUO,EAAaG,EAAQ,eAAe,CAAC,GACvDE,IAAMZ,EAAUO,EAAaG,EAAQ,aAAa,CAAC;AACzD,UAAI,CAACC,KAAS,CAACC,KAAOA,EAAI,QAAA,MAAcT,EAAA,EAAgB,QAAA,EAAW;AACnE,YAAMY,IAAO,KAAK,OAAOH,EAAI,QAAA,IAAYD,EAAM,aAAa,KAAU,IAAI;AAC1E,cAAOK,KAAAC,IAAAP,EAAQ,YAAR,gBAAAO,EAAiB,KAAK,CAACC,MAAWA,EAAO,SAASH,OAAlD,gBAAAC,EAAyD;AAAA,IAClE;AACA,aAASG,EAAeT,GAA2BU,GAA8C;;AAC/F,YAAMC,IAAW,OAAOD,EAAM,OAAO,SAAU,WAAWA,EAAM,OAAO,QAAQ,QACzEF,KAASD,IAAAP,EAAQ,YAAR,gBAAAO,EAAiB,KAAK,CAACK,MAASA,EAAK,OAAOD;AAC3D,UAAI,CAACH,EAAQ;AACb,YAAMN,IAAMT,EAAA,GACNQ,IAAQ,IAAI,KAAKC,CAAG;AAC1B,MAAAD,EAAM,WAAWA,EAAM,WAAA,IAAeO,EAAO,OAAO,CAAC,GACrD3B,EAAK,UAAU;AAAA,QACb,CAACmB,EAAQ,eAAe,GAAGR,EAAWS,CAAK;AAAA,QAC3C,CAACD,EAAQ,aAAa,GAAGR,EAAWU,CAAG;AAAA,MAAA,CACxC;AAAA,IACH;AACA,aAASW,EAAef,GAAoBZ,GAAsB;AAChE,MAAAL,EAAK,UAAU,EAAE,CAACiB,CAAU,GAAIZ,KAAS,MAAoB;AAAA,IAC/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1DA,UAAMP,IAAQC,GASRC,IAAOC,GASPgC,IAAcC,EAAA,GACdC,IAAgBD,EAAA,GAChBE,IAAgBC,EAAS,MAAMvC,EAAM,MAAM,eAAe,QAAQ,GAClEwC,IAAeD,EAAS,MAAM;;AAClC,UAAIF,EAAc;AAChB,eAAO,EAAE,OAAO,YAAY,QAAQA,EAAc,MAAM,QAAA;AAE1D,UAAIrC,EAAM,MAAM,WAAW,WAAWA,EAAM,MAAM,WAAW;AAC3D,eAAO,EAAE,OAAO,YAAY,SAAQ4B,IAAA5B,EAAM,MAAM,UAAZ,gBAAA4B,EAAmB,QAAA;AAAA,IAG3D,CAAC,GACKa,IAAcF;AAAA,MAClB,MACGvC,EAAM,WAAW,aAAa,OAAO,EAAQA,EAAM,MAAM,WACzDA,EAAM,WAAW,aAAa,OAAO,EAAQA,EAAM,MAAM;AAAA,IAAS,GAEjE0C,IAAYH,EAAS,MAAM;AAC/B,YAAMI,IAAiB3C,EAAM,MAAM,OAAO,cAAcsC,EAAc,QAAQ,MAAM,MAC9EM,IAAeN,EAAc,QAAQ,KAAK;AAChD,aAAO,EAAE,WAAW,GAAG,KAAK,IAAIK,IAAiBC,IAAe,GAAGN,EAAc,QAAQ,KAAK,GAAG,CAAC,KAAA;AAAA,IACpG,CAAC,GACKO,IAAYN;AAAA,MAAS,MACzBvC,EAAM,MAAM,mBACR,IAAI,KAAK,eAAeA,EAAM,QAAQ,QAAQ,EAAE,WAAW,UAAU,UAAUA,EAAM,QAAQ,SAAA,CAAU,EAAE;AAAA,QACvG,IAAI,KAAKA,EAAM,MAAM,gBAAgB;AAAA,MAAA,IAEvC;AAAA,IAAA;AAGN,aAAS8C,IAAgC;;AACvC,cAAOnB,KAAAC,IAAAO,EAAY,UAAZ,gBAAAP,EAAmB,cAAnB,gBAAAD,EAAA,KAAAC;AAAA,IACT;AACA,aAASmB,EAAoBhB,GAAuC;AAClE,MAAIA,EAAM,QAAQ,SAAO7B,EAAK,WAAW,GACrC6B,EAAM,QAAQ,SAAO7B,EAAK,WAAW;AAAA,IAC3C;AACA,WAAA8C,GAAgB,CAACC,OACfZ,EAAc,QAAQY,aAAiB,QAAQA,IAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,GACvE,GACR,GACDC;AAAA,MACE,MAAM,CAAClD,EAAM,MAAM,YAAYA,EAAM,MAAM,SAAS;AAAA,MACpD,MAAM;AACJ,QAAAqC,EAAc,QAAQ;AAAA,MACxB;AAAA,IAAA,GAEFc,EAAa,EAAE,WAAAL,GAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1KnB,SAASM,GAAoBC,GAA2B5C,IAAsC,IAAI;AACvG,QAAM6C,IAAWC,GAAqCF,EAAQ,QAAQ;AACtE,MAAIG;AAEJ,SAAAC,GAAU,MAAM;AACd,IAAAD,IAAcH,EAAQ,UAAU,CAACK,MAAS;AACxC,MAAAJ,EAAS,QAAQI;AAAA,IACnB,CAAC,GACGjD,EAAQ,aAAa,MAAY4C,EAAQ,KAAA;AAAA,EAC/C,CAAC,GACDM,GAAgB,MAAMH,KAAA,gBAAAA,GAAe,GAE9B;AAAA,IACL,UAAAF;AAAA,IACA,SAASf,EAAS,MAAMe,EAAS,MAAM,OAAO;AAAA,IAC9C,aAAaf,EAAS,MAAMe,EAAS,MAAM,WAAW;AAAA,IACtD,WAAWf,EAAS,MAAMe,EAAS,MAAM,eAAe;AAAA,IACxD,YAAY,CAACM,MAA+BP,EAAQ,WAAWO,CAAQ;AAAA,IACvE,YAAY,MAAMP,EAAQ,WAAA;AAAA,IAC1B,eAAe,CAACO,GAA4BC,MAC1CR,EAAQ,cAAcO,GAAUC,CAAc;AAAA,IAChD,cAAc,CAACC,MAAoBT,EAAQ,aAAaS,CAAO;AAAA,IAC/D,YAAY,CAACA,MAAoBT,EAAQ,WAAWS,CAAO;AAAA,IAC3D,cAAc,CAACC,GAA+BH,MAAgCP,EAAQ,aAAaU,GAAOH,CAAQ;AAAA,EAAA;AAEtH;ACtCO,SAASI,GAAaC,GAAmBC,GAAkBC,GAAwB;AACxF,QAAMC,IAAM,IAAI,gBAAgB,IAAI,KAAK,CAACH,CAAO,GAAG,EAAE,MAAMC,EAAA,CAAU,CAAC;AACvE,EAAAG,GAAgBD,GAAKD,CAAQ,GAC7B,OAAO,WAAW,MAAM,IAAI,gBAAgBC,CAAG,GAAG,CAAC;AACrD;AAEO,SAASE,GAAgBC,GAAiBJ,GAAwB;AACvE,EAAAE,GAAgBE,GAASJ,CAAQ;AACnC;AAEA,SAASE,GAAgBD,GAAaD,GAAwB;AAC5D,QAAMK,IAAS,SAAS,cAAc,GAAG;AACzC,EAAAA,EAAO,OAAOJ,GACdI,EAAO,WAAWL,GAClBK,EAAO,SAAS,IAChB,SAAS,KAAK,OAAOA,CAAM,GAC3BA,EAAO,MAAA,GACPA,EAAO,OAAA;AACT;;;;;;;;;;;;;;;;;AC4CA,UAAMxE,IAAQC,GAcRwE,wBAAgB,IAAA,GAChBC,IAAmBtC,EAAA,GACnBuC,wBAAmB,IAAA,GACnBC,wBAAsB,IAAA;AAC5B,QAAIC,GACAC,IAAqB,IACrBC,IAAa;AACjB,IAAAC,GAAc,MAAM;AAClB,MAAIhF,EAAM,WAAW,OAAO,SAAW,SAAmB,QAAQ,eAAe,OAAO,SAAS,MAAM;AAAA,IACzG,CAAC;AACD,UAAM;AAAA,MACJ,SAAAiF;AAAA,MACA,aAAAC;AAAA,MACA,WAAAC;AAAA,MACA,YAAAC;AAAA,MACA,YAAYC;AAAA,MACZ,eAAAC;AAAA,MACA,cAAAC;AAAA,MACA,YAAAC;AAAA,MACA,cAAAC;AAAA,IAAA,IACErC,GAAoBpD,EAAM,SAAS,EAAE,UAAUA,EAAM,YAAY,CAACA,EAAM,UAAU;AAEtF,IAAAyD,GAAU,MAAM;;AACd,UAAI,GAACzD,EAAM,YAAY,CAACA,EAAM,WAC9B;AAAA,YAAI,OAAO,uBAAyB,KAAa;AAC/C,UAAKqF,EAAA;AACL;AAAA,QACF;AACA,QAAAP,IAAqB,IACrBD,IAAuB,IAAI,qBAAqBa,IAAqB;AAAA,UACnE,YAAY1F,EAAM;AAAA,QAAA,CACnB,IACD4B,IAAA8C,EAAiB,UAAjB,QAAA9C,EACI,iBAA8B,uBAC/B,QAAQ,CAAC+D,MAAYd,KAAA,gBAAAA,EAAsB,QAAQc;AAAA;AAAA,IACxD,CAAC,GACDhC,GAAgB,MAAM;AACpB,MAAAkB,KAAA,QAAAA,EAAsB,cACtBA,IAAuB,QACvBC,IAAqB,IACrBH,EAAa,MAAA,GACbC,EAAgB,MAAA;AAAA,IAClB,CAAC;AAED,UAAMgB,IAAgBrD;AAAA,MAAS,OAC5BvC,EAAM,QAAQ,OAAO,aAAa,IAChC,IAAI,CAAC6F,MAAa,GAAGA,EAAS,KAAK,KAAKC,EAAeb,EAAQ,MAAM,UAAUY,EAAS,EAAE,CAAC,CAAC,EAAE,EAC9F,KAAK,KAAK;AAAA,IAAA;AAGf,aAASC,EAAevF,GAAwB;AAC9C,aAAO,MAAM,QAAQA,CAAK,IAAIA,EAAM,KAAK,IAAI,IAAI,OAAOA,KAAS,IAAI;AAAA,IACvE;AACA,aAASwF,EAAWC,GAAoB;AACtC,YAAMC,IAAOD,EAAM,OAAO;AAC1B,aAAO;AAAA,QACL,iBAAiB,OAAOC,EAAK,EAAE;AAAA,QAC/B,iBAAiB,OAAOA,EAAK,MAAMA,EAAK,EAAE;AAAA,QAC1C,iBAAiB,OAAOA,EAAK,MAAMA,EAAK,MAAMA,EAAK,EAAE;AAAA,QACrD,iBAAiB,OAAOA,EAAK,MAAMA,EAAK,MAAMA,EAAK,MAAMA,EAAK,EAAE;AAAA,QAChE,iBAAiB,OAAOA,EAAK,MAAMA,EAAK,MAAMA,EAAK,MAAMA,EAAK,MAAMA,EAAK,EAAE;AAAA,MAAA;AAAA,IAE/E;AACA,aAASC,EAAsBF,GAA+B;;AAC5D,YAAMG,MAAYvE,IAAA5B,EAAM,oBAAN,gBAAA4B,EAAwBoE,EAAM,QAAOhG,EAAM,iBAAiB,QAAQgG,EAAM,UAAU,EAAE;AACxG,aAAOI,GAAQC,GAAMF,CAAS,CAAC;AAAA,IACjC;AACA,aAASG,EAAYxC,GAAiBvD,GAAsB;AAC1D,MAAIA,IAAOkE,EAAU,IAAIX,GAASvD,CAA4C,IACzEkE,EAAU,OAAOX,CAAO;AAAA,IAC/B;AACA,aAAS4B,GAAoBa,GAA4C;AAYvE,MAXAA,EAAQ,QAAQ,CAACC,MAAU;AACzB,cAAM1C,IAAW0C,EAAM,OAAuB,QAAQ;AACtD,QAAK1C,MACD0C,EAAM,kBACR7B,EAAa,IAAIb,CAAO,GACxBc,EAAgB,IAAId,CAAO,MAE3Ba,EAAa,OAAOb,CAAO,GAC3Bc,EAAgB,OAAOd,CAAO;AAAA,MAElC,CAAC,GACG,GAACc,EAAgB,QAAQG,OAC7BA,IAAa,IACb,eAAe,MAAM;AACnB,QAAAA,IAAa;AACb,cAAMnB,IAAW,MAAM,KAAKgB,CAAe;AAC3C,QAAAA,EAAgB,MAAA,GACXQ,EAAWxB,CAAQ;AAAA,MAC1B,CAAC;AAAA,IACH;AACA,aAAS6C,KAAyD;AAChE,aAAO3B,IAAqBQ,EAAcX,GAAc,EAAE,iBAAiB,GAAA,CAAM,IAAIU,EAAA;AAAA,IACvF;AACA,mBAAeqB,GAAkB3C,GAA8C;AAC7E,YAAM4C,IAAiBlB,EAAa1B,GAAOe,IAAqBH,IAAe,MAAS;AACxF,UAAI3E,EAAM,WAAW,OAAO,SAAW,KAAa;AAClD,cAAM4G,IAASC,GAAqB7G,EAAM,QAAQ,QAAQA,EAAM,QAAQ,SAAS,OAAO,SAAS,MAAM;AACvG,eAAO,QAAQ;AAAA,UACb,OAAO,QAAQ;AAAA,UACf;AAAA,UACA,GAAG,OAAO,SAAS,QAAQ,GAAG4G,CAAM,GAAG,OAAO,SAAS,IAAI;AAAA,QAAA;AAAA,MAE/D;AACA,YAAMD;AAAA,IACR;AACA,aAASG,GAAUhD,GAAuB;;AACxC,YAAMkC,IAAQhG,EAAM,QAAQ,OAAO,OAAO,KAAK,CAAC+G,OAAcA,GAAU,OAAOjD,CAAO,GAChFkD,KAAUpF,KAAAsD,EAAY,MAAMpB,CAAO,MAAzB,gBAAAlC,GAA4B;AAC5C,UAAI,CAACoF,EAAS;AACd,YAAMC,IAAMC,GAAkBF,GAAShB,GAAOf,EAAQ,KAAK;AAC3D,MAAAjB,GAAaiD,GAAK,0BAA0BE,GAAuBnH,EAAM,QAAQ,OAAO,IAAIgG,EAAM,EAAE,CAAC;AAAA,IACvG;AACA,aAASlD,GAAUgB,GAAuB;;AACxC,YAAMS,KAAU3C,IAAA6C,EAAU,IAAIX,CAAO,MAArB,gBAAAlC,EAAwB;AACxC,MAAI2C,KAASD,GAAgBC,GAAS,GAAGvE,EAAM,QAAQ,OAAO,EAAE,IAAI8D,CAAO,MAAM;AAAA,IACnF;AAEA,WAAAX,EAAa,EAAE,YAAAsD,IAAY,cAAAlB,GAAc,WAAAuB,IAAW,WAAAhE,IAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/LxD,SAASsE,GAAcC,GAAiC;AAC7D,SAAIA,EAAO,SAAS,YAAkBC,EAAW,UAC7CD,EAAO,SAAS,YAAkBC,EAAW,UAC1CA,EAAW;AACpB;AAMO,SAASC,GAAiBhH,GAAmD;AAClF,SAAO,OAAOA,KAAU,YAAYA,MAAU,OAAQA,IAAoC,CAAA;AAC5F;;;;;;;;;;ACIA,UAAMP,IAAQC,GACRC,IAAOC,GACPqH,IAAWpF,EAAA;AAEjB,aAASqF,EAAYlH,GAAgBmH,GAAwCC,IAAO,IAAe;AACjG,YAAMC,IAAYD,IACdE,EAAe,WAAWtH,GAAOmH,EAAO,QAAQ1H,EAAM,OAAO,IAC7D6H,EAAe,cAActH,GAAOmH,EAAO,QAAQ1H,EAAM,OAAO,GAC9D8H,IAAiBJ,EAAO,OAAO,SAAS,cAAcA,EAAO,OAAO,SAAS,aAAaA,EAAO,OAAO;AAC9G,aAAOnH,KAAU,QAA+BA,MAAU,MAAMmH,EAAO,QAAQ,CAACI,IAC5E,GAAGF,CAAS,GAAGF,EAAO,IAAI,KAC1BE;AAAA,IACN;AAEA,UAAMlH,IAAS6B,EAAqB,OAAO;AAAA,MACzC,YAAY,CAAC,GAAGvC,EAAM,UAAU,UAAU;AAAA,MAC1C,QAAQ,CAAC,GAAG+H,EAAqB;AAAA,MACjC,aAAa/H,EAAM,UAAU;AAAA,MAC7B,GAAIA,EAAM,UAAU,iBAAiB,SAAY,EAAE,cAAcA,EAAM,UAAU,aAAA,IAAiB,CAAA;AAAA,MAClG,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,OAAOA,EAAM,UAAU,gBAAgB,gBAAgBA,EAAM,UAAU,aAAa,KAAK;AAAA,QACzF,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,cAAc;AAAA,MAAA;AAAA,MAEhB,cAAc;AAAA,QACZ,GAAGgI;AAAA,QACH,GAAIhI,EAAM,UAAU,gBAAgB,gBAAgBA,EAAM,UAAU,iBAAiB,SACjF,EAAE,SAAS,GAAA,IACX,CAAA;AAAA,QACJ,WAAW,EAAE,GAAGgI,EAAuB,WAAW,UAAU,EAAA;AAAA,MAAE;AAAA,MAEhE,WAAW;AAAA,QACT,GAAGC;AAAA,QACH,aAAa;AAAA,QACb,WAAW;AAAA,UACT,GAAGA,EAAoB;AAAA,UACvB,aAAa;AAAA,UACb,GAAIjI,EAAM,UAAU,OAAO,CAAC,IACxB,EAAE,WAAW,CAACO,MAAmBkH,EAAYlH,GAAOP,EAAM,UAAU,OAAO,CAAC,GAAI,EAAI,MACpF,CAAA;AAAA,QAAC;AAAA,MACP;AAAA,MAEF,SAAS;AAAA,QACP,GAAGkI;AAAA,QACH,aAAa,EAAE,MAAM,UAAU,aAAa,EAAE,OAAO,8BAA4B;AAAA,MAAE;AAAA,MAErF,GAAIlI,EAAM,UAAU,UAAU,EAAE,OAAO,QAAA,IAAY,CAAA;AAAA,MACnD,QAAQA,EAAM,UAAU,OAAO,IAAI,CAAC0H,OAAY;AAAA,QAC9C,MAAMA,EAAO;AAAA,QACb,MAAM,CAAC,GAAGA,EAAO,MAAM;AAAA,QACvB,YAAYN,GAAcM,EAAO,MAAM;AAAA,QACvC,gBAAgB,CAACnH,MAAmBkH,EAAYlH,GAAOmH,CAAM;AAAA,QAC7D,WAAW1H,EAAM,UAAU;AAAA,QAC3B,WAAW;AAAA,UACT,cAAcA,EAAM,UAAU,gBAAgB,eAAe,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,QAAA;AAAA,MACzF,EACA;AAAA,IAAA,EACF;AAEF,aAASmI,EAAQC,GAAoB;AACnC,YAAMrG,IAAQwF,GAAiBa,CAAG,GAC5BC,IAAc,OAAOtG,EAAM,eAAgB,WAAWA,EAAM,cAAc,GAC1EuG,IAAUtI,EAAM,MAAM,QAAQ,SAAS,QAAQA,EAAM,MAAM,UAAU;AAC3E,MAAKsI,KACLpI,EAAK,sBAAsB;AAAA,QACzB,MAAM;AAAA,QACN,SAASF,EAAM,MAAM;AAAA,QACrB,WAAWsI,EAAQ;AAAA,QACnB,QAAQ,OAAO,OAAO;AAAA,UACpB,CAACA,EAAQ,aAAa,GAAGvG,EAAM;AAAA,UAC/B,GAAIuG,EAAQ,cAAc,EAAE,CAACA,EAAQ,WAAW,GAAGvG,EAAM,WAAA,IAAe,CAAA;AAAA,UACxE,CAACuG,EAAQ,YAAYA,EAAQ,cAAc,IAAID,CAAW,KAAKC,EAAQ,YAAY,CAAC,CAAE,GAAGvG,EAAM;AAAA,QAAA,CAChG;AAAA,MAAA,CACF;AAAA,IACH;AAEA,aAASe,IAAgC;;AACvC,cAAOlB,IAAA4F,EAAS,UAAT,gBAAA5F,EAAgB;AAAA,IACzB;AACA,WAAAuB,EAAa,EAAE,WAAAL,GAAW;;;;;;;;;;;;;;;;;;;ACjF1B,UAAM9C,IAAQC,GACRC,IAAOC,GACPqH,IAAWpF,EAAA;AAEjB,aAASmG,EAAgBhI,GAAgBmH,GAAiD;AACxF,YAAME,IAAYC,EAAe,WAAWtH,GAAOmH,EAAO,QAAQ1H,EAAM,OAAO;AAC/E,aAAOwI,EAAiBZ,GAAWF,CAAM;AAAA,IAC3C;AAEA,aAASc,EAAiBZ,GAAmBF,GAAiD;AAC5F,YAAMI,IAAiBJ,EAAO,OAAO,SAAS,cAAcA,EAAO,OAAO,SAAS,aAAaA,EAAO,OAAO;AAC9G,aAAOA,EAAO,QAAQ,CAACI,IAAiB,GAAGF,CAAS,GAAGF,EAAO,IAAI,KAAKE;AAAA,IACzE;AAEA,UAAMlH,IAAS6B,EAAsB,MAAM;AACzC,YAAMkG,IAAa,MAAM;AAAA,QACvB,IAAI,IAAIzI,EAAM,UAAU,OAAO,IAAI,CAAC0H,MAAW,CAACA,EAAO,SAASA,CAAM,CAAU,CAAC,EAAE,OAAA;AAAA,MAAO,GAEtFgB,IAAc,IAAI,IAAID,EAAW,IAAI,CAACf,GAAQiB,MAAU,CAACjB,EAAO,SAASiB,CAAK,CAAC,CAAC;AAEtF,aAAO;AAAA,QACL,QAAQ,CAAC,GAAGZ,EAAqB;AAAA,QACjC,MAAM,EAAE,KAAK,IAAI,OAAOU,EAAW,SAAS,IAAI,KAAK,IAAI,QAAQ,IAAI,MAAM,IAAI,cAAc,GAAA;AAAA,QAC7F,SAAS;AAAA,UACP,GAAGP;AAAA,UACH,aAAa,EAAE,MAAM,QAAQ,WAAW,EAAE,OAAO,WAAW,MAAM,SAAA,EAAS;AAAA,QAAE;AAAA,QAE/E,OAAO;AAAA,UACL,MAAMlI,EAAM,UAAU,WAAW,IAAI,MAAM;AAAA,UAC3C,GAAGgI;AAAA,UACH,GAAIhI,EAAM,UAAU,iBAChB;AAAA,YACE,gBAAgB,CAACO,MACfsH,EAAe,WAAWtH,GAAOP,EAAM,UAAU,gBAAiBA,EAAM,OAAO;AAAA,UAAA,IAEnF,CAAA;AAAA,QAAC;AAAA,QAEP,OAAOyI,EAAW,IAAI,CAACf,GAAQiB,OAAW;AAAA,UACxC,GAAGV;AAAA,UACH,UAAUU,MAAU,IAAI,SAAS;AAAA,UACjC,MAAMA,IAAQ;AAAA,UACd,WAAW;AAAA,YACT,GAAGV,EAAoB;AAAA,YACvB,WAAW,CAAC1H,MAAmBgI,EAAgBhI,GAAOmH,CAAM;AAAA,UAAA;AAAA,UAE9D,WAAW;AAAA,YACT,MAAMiB,MAAU;AAAA,YAChB,WAAW,EAAE,OAAO,WAAW,MAAM,SAAA;AAAA,UAAS;AAAA,QAChD,EACA;AAAA,QACF,QAAQ3I,EAAM,UAAU,OAAO,IAAI,CAAC0H,GAAQiB,OAAW;AAAA,UACrD,MAAMjB,EAAO;AAAA,UACb,MAAMA,EAAO,OAAO,IAAI,CAACnH,MAAUA,KAAS,MAAS;AAAA,UACrD,YAAY6G,GAAcM,EAAO,MAAM;AAAA,UACvC,gBAAgB,CAACnH,MAAmB;AAClC,kBAAMqH,IAAYC,EAAe,cAActH,GAAOmH,EAAO,QAAQ1H,EAAM,OAAO;AAClF,mBAAOO,KAAU,QAA+BA,MAAU,KAAKqH,IAAYY,EAAiBZ,GAAWF,CAAM;AAAA,UAC/G;AAAA,UACA,WAAW1H,EAAM,UAAU;AAAA,UAC3B,QAAQA,EAAM,UAAU;AAAA,UACxB,YAAY0I,EAAY,IAAIhB,EAAO,OAAO,KAAK;AAAA,UAC/C,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,YAAY;AAAA,UACZ,WAAW,EAAE,OAAOiB,MAAU,IAAI,IAAI,KAAA;AAAA,UACtC,GAAIA,MAAU,IACV;AAAA,YACE,WAAW;AAAA,cACT,SAAS;AAAA,cACT,OAAO;AAAA,gBACL,MAAM;AAAA,gBACN,GAAG;AAAA,gBACH,GAAG;AAAA,gBACH,IAAI;AAAA,gBACJ,IAAI;AAAA,gBACJ,YAAY;AAAA,kBACV,EAAE,QAAQ,GAAG,OAAO,2BAAA;AAAA,kBACpB,EAAE,QAAQ,GAAG,OAAO,4BAAA;AAAA,gBAA4B;AAAA,cAClD;AAAA,YACF;AAAA,UACF,IAEF,CAAA;AAAA,QAAC,EACL;AAAA,QACF,UAAU;AAAA,UACR,OAAO3I,EAAM,UAAU,YAAY,OAAO,CAACiC,MAASA,EAAK,SAAS,UAAU,EAAE,IAAI,CAACA,MAAS,OAAOA,EAAK,KAAK,CAAC;AAAA,UAC9G,OAAOjC,EAAM,UAAU,YAAY,OAAO,CAACiC,MAASA,EAAK,SAAS,OAAO,EAAE,IAAI,CAACA,MAAS,OAAOA,EAAK,KAAK,CAAC;AAAA,QAAA;AAAA,MAC7G;AAAA,IAEJ,CAAC;AAED,aAASkG,EAAQC,GAAoB;AACnC,YAAMrG,IAAQwF,GAAiBa,CAAG,GAC5BC,IAAc,OAAOtG,EAAM,eAAgB,WAAWA,EAAM,cAAc,GAC1EuG,IAAUtI,EAAM,MAAM,QAAQ,SAAS,SAASA,EAAM,MAAM,UAAU;AAC5E,MAAKsI,KACLpI,EAAK,sBAAsB;AAAA,QACzB,MAAM;AAAA,QACN,SAASF,EAAM,MAAM;AAAA,QACrB,WAAWsI,EAAQ;AAAA,QACnB,QAAQ,OAAO,OAAO;AAAA,UACpB,CAACA,EAAQ,MAAM,GAAGvG,EAAM;AAAA,UACxB,GAAIuG,EAAQ,cAAc,EAAE,CAACA,EAAQ,WAAW,GAAGvG,EAAM,WAAA,IAAe,CAAA;AAAA,UACxE,CAACuG,EAAQ,QAAQA,EAAQ,cAAc,IAAID,CAAW,KAAKC,EAAQ,QAAQ,CAAC,CAAE,GAAGvG,EAAM;AAAA,QAAA,CACxF;AAAA,MAAA,CACF;AAAA,IACH;AAEA,aAASe,IAAgC;;AACvC,cAAOlB,IAAA4F,EAAS,UAAT,gBAAA5F,EAAgB;AAAA,IACzB;AACA,WAAAuB,EAAa,EAAE,WAAAL,GAAW;;;;;;;;;;;;;;;;;;;;;;;;AC7G1B,UAAM9C,IAAQC,GAMR2I,IAAiBrG;AAAA,MAAS,MAC9BsF,EAAe,cAAc7H,EAAM,UAAU,OAAOA,EAAM,UAAU,QAAQA,EAAM,OAAO;AAAA,IAAA,GAErF6I,IAActG;AAAA,MAAS,MAC3BvC,EAAM,UAAU,OAAO,SAAS,cAAcA,EAAM,UAAU,OAAO,SAAS,YAC1E,SACAA,EAAM,UAAU;AAAA,IAAA,GAEhB8I,IAAsBvG,EAAS,MAAM;AACzC,YAAMwG,IAAa/I,EAAM,UAAU;AACnC,aAAO+I,IAAalB,EAAe,cAAckB,EAAW,OAAOA,EAAW,QAAQ/I,EAAM,OAAO,IAAI;AAAA,IACzG,CAAC,GACKgJ,IAAiBzG,EAAS,MAAM;;AACpC,eAAIX,IAAA5B,EAAM,UAAU,eAAhB,gBAAA4B,EAA4B,eAAc,OAAaqH,OACvDtH,IAAA3B,EAAM,UAAU,eAAhB,gBAAA2B,EAA4B,eAAc,SAAeuH,KACtDC;AAAA,IACT,CAAC,GACKC,IAAiB7G,EAAS,MAAM;AACpC,YAAMwG,IAAa/I,EAAM,UAAU;AACnC,aAAI,CAAC+I,KAAcA,EAAW,cAAc,SAAe,YACvDA,EAAW,cAAc,cACpBA,EAAW,cAAc,OAAO,gBAAgB,cAErDA,EAAW,YAAY,YAAkB,YAE1CA,EAAW,YAAY,cAAcA,EAAW,cAAc,QAC9DA,EAAW,YAAY,cAAcA,EAAW,cAAc,SAC9C,cAAc;AAAA,IACnC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCD,UAAM/I,IAAQC,GACRC,IAAOC,GACPqH,IAAWpF,EAAA;AAEjB,aAASqF,EAAYlH,GAAwB;AAC3C,YAAMqH,IAAYC,EAAe,cAActH,GAAOP,EAAM,UAAU,aAAaA,EAAM,OAAO,GAC1F8H,IACJ9H,EAAM,UAAU,YAAY,SAAS,cACrCA,EAAM,UAAU,YAAY,SAAS,aACrCA,EAAM,UAAU,YAAY;AAC9B,aAAOA,EAAM,UAAU,QAAQ,CAAC8H,IAAiB,GAAGF,CAAS,GAAG5H,EAAM,UAAU,IAAI,KAAK4H;AAAA,IAC3F;AAEA,UAAMlH,IAAS6B,EAAqB,OAAO;AAAA,MACzC,QAAQ,CAAC,GAAGwF,EAAqB;AAAA,MACjC,OAAO/H,EAAM,UAAU;AAAA,MACvB,YAAYA,EAAM,UAAU;AAAA,MAC5B,YAAY;AAAA,MACZ,QAAQ,CAAC,OAAO,KAAK;AAAA,MACrB,QAAQA,EAAM,UAAU,QAAQ,CAAC,OAAO,KAAK,IAAI;AAAA,MACjD,WAAW,EAAE,aAAa,QAAQ,aAAa,GAAG,cAAc,EAAA;AAAA,MAChE,SAAS,EAAE,GAAGkI,GAAA;AAAA,MACd,QAAQlI,EAAM,UAAU,MAAM,IAAI,CAACiC,OAAU;AAAA,QAC3C,MAAMA,EAAK;AAAA,QACX,MAAMA,EAAK;AAAA,QACX,YAAYmF,GAAcpH,EAAM,UAAU,WAAW;AAAA,QACrD,gBAAgByH;AAAA,MAAA,EAChB;AAAA,MACF,GAAIzH,EAAM,UAAU,QAChB;AAAA,QACE,aAAa;AAAA,UACX,OAAOA,EAAM,UAAU,MAAM,OAAO,CAACqJ,GAAKpH,MAASoH,IAAMpH,EAAK,OAAO,CAAC;AAAA,UACtE,OAAOjC,EAAM,MAAM,MAAM,QAAQ,OAAO,EAAE;AAAA,UAC1C,gBAAgByH;AAAA,UAChB,GAAIzH,EAAM,UAAU,OAAO,EAAE,MAAMA,EAAM,UAAU,SAAS,CAAA;AAAA,QAAC;AAAA,MAC/D,IAEF,CAAA;AAAA,IAAC,EACL;AAEF,aAASmI,EAAQC,GAAoB;AACnC,YAAMrG,IAAQwF,GAAiBa,CAAG,GAC5BE,IAAUtI,EAAM,MAAM,QAAQ,SAAS,QAAQA,EAAM,MAAM,UAAU;AAC3E,MAAKsI,KACLpI,EAAK,sBAAsB;AAAA,QACzB,MAAM;AAAA,QACN,SAASF,EAAM,MAAM;AAAA,QACrB,WAAWsI,EAAQ;AAAA,QACnB,QAAQ,OAAO,OAAO,EAAE,CAACA,EAAQ,SAAS,GAAGvG,EAAM,MAAM,CAACuG,EAAQ,UAAU,GAAGvG,EAAM,OAAO;AAAA,MAAA,CAC7F;AAAA,IACH;AAEA,aAASe,IAAgC;;AACvC,cAAOlB,IAAA4F,EAAS,UAAT,gBAAA5F,EAAgB;AAAA,IACzB;AACA,WAAAuB,EAAa,EAAE,WAAAL,GAAW;;;;;;;;;;;;;;;;;;;AC1C1B,UAAM9C,IAAQC,GACRC,IAAOC,GAEPmJ,IAAU/G;AAAA,MAA+C,MAC7DvC,EAAM,UAAU,QAAQ,IAAI,CAACuJ,OAAY;AAAA,QACvC,OAAOA,EAAO;AAAA,QACd,WAAWA,EAAO;AAAA,QAClB,KAAKA,EAAO;AAAA,QACZ,GAAIA,EAAO,QAAQ,EAAE,OAAOA,EAAO,MAAA,IAAU,CAAA;AAAA,QAC7C,QAAQA,EAAO;AAAA,QACf,GAAIA,EAAO,aACP;AAAA,UACE,SAAS,MAAM,KAAK,IAAI,IAAIvJ,EAAM,UAAU,KAAK,IAAI,CAACwJ,MAAQ,OAAOA,EAAID,EAAO,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAC5F,MAAM,GAAG,EAAE,EACX,IAAI,CAAChJ,OAAW,EAAE,MAAMA,KAAS,MAAM,OAAAA,IAAQ;AAAA,UAClD,UAAU,CAACA,GAAkCiJ,MAC3C,OAAOA,EAAID,EAAO,KAAK,KAAK,EAAE,MAAM,OAAOhJ,CAAK;AAAA,QAAA,IAEpD,CAAA;AAAA,QACJ,cAAc,CAAC,EAAE,MAAAkJ,QAA8BC,EAAWD,GAAMF,CAAM;AAAA,MAAA,EACtE;AAAA,IAAA;AAGJ,aAASI,EAAgBF,GAAeF,GAAsC;AAC5E,aAAO1B,EAAe;AAAA,QACpB4B;AAAA,QACAF,EAAO,UAAU;AAAA,UACf,MAAMA,EAAO,aAAa,SAAS,SAASA,EAAO,aAAa,aAAa,aAAa;AAAA,QAAA;AAAA,QAE5FvJ,EAAM;AAAA,MAAA;AAAA,IAEV;AAEA,aAAS0J,EAAWD,GAAeF,GAA8B;AAC/D,YAAM3B,IAAY+B,EAAgBF,GAAMF,CAAM;AAC9C,aAAKA,EAAO,UACRA,EAAO,QAAQ,SAAS,aAAmBK,EAAmBH,GAAM7B,GAAW2B,EAAO,OAAO,IAC7FA,EAAO,QAAQ,SAAS,UAAgBM,EAAgBJ,GAAM7B,GAAW2B,EAAO,OAAO,IACpFO,EAAcL,GAAM7B,GAAW2B,EAAO,OAAO,IAHxB3B;AAAA,IAI9B;AAEA,aAASmC,EAAaxJ,GAAoC;AACxD,aAAO,OAAOA,KAAU,YAAY,OAAO,SAASA,CAAK,IAAIA,IAAQ;AAAA,IACvE;AAEA,aAASqJ,EACPH,GACA7B,GACAoC,GACA;AACA,YAAMzJ,IAAQwJ,EAAaN,CAAI;AAC/B,UAAIlJ,MAAU,OAAW,QAAOqH;AAChC,YAAMqC,IAAMD,EAAQ,OAAO,GACrBE,IAAU,KAAK,IAAI,KAAK,KAAK,IAAI,GAAI3J,IAAQ0J,IAAO,GAAG,CAAC;AAC9D,aAAOE,EAAE,OAAO,EAAE,OAAO,6BAA6B;AAAA,QACpDA,EAAEC,IAAW,EAAE,SAAAF,GAAS,UAAU,IAAO,MAAM,SAAS,aAAa,GAAG;AAAA,QACxEC,EAAE,QAAQ,EAAE,OAAO,uBAAA,GAA0BvC,CAAS;AAAA,MAAA,CACvD;AAAA,IACH;AAEA,aAASiC,EAAgBJ,GAAe7B,GAAmBoC,GAAuD;AAChH,YAAMzJ,IAAQwJ,EAAaN,CAAI;AAC/B,UAAIlJ,MAAU,OAAW,QAAOqH;AAChC,YAAMyC,IACJ9J,IAAQ,IACHyJ,EAAQ,gBAAgB,YACzBzJ,IAAQ,IACLyJ,EAAQ,gBAAgB,WACxBA,EAAQ,YAAY,WACvBM,IAAkB/J,IAAQ,IAAI0I,KAAe1I,IAAQ,IAAI2I,KAAeC;AAC9E,aAAOgB,EAAE,QAAQ,EAAE,OAAO,CAAC,mBAAmB,oBAAoBE,CAAI,EAAE,KAAK,CAACF,EAAEG,CAAI,GAAGH,EAAE,QAAQvC,CAAS,CAAC,CAAC;AAAA,IAC9G;AAEA,aAASkC,EAAcL,GAAe7B,GAAmBoC,GAAqD;;AAC5G,YAAMK,MAAOzI,IAAAoI,EAAQ,gBAAR,gBAAApI,EAAsB,OAAO6H,KAAQ,EAAE,OAAMO,EAAQ,eAAe;AACjF,aAAOO,EAAU3C,GAAWyC,CAAI;AAAA,IAClC;AAEA,aAASE,EAAUC,GAAeH,GAAqBC,GAAkB;AACvE,aAAOH;AAAA,QACLM;AAAAA,QACA,EAAE,OAAO,CAAC,iBAAiB,kBAAkBJ,CAAI,EAAE,EAAA;AAAA,QACnD,EAAE,SAAS,MAAM,CAA6BF,EAAE,QAAQK,CAAK,CAAC,EAAA;AAAA,MAAE;AAAA,IAEpE;AAEA,UAAME,wBAAc,QAAA;AACpB,QAAIC,IAAc;AAClB,aAASC,EAAOpB,GAAgD;AAC9D,YAAMqB,IAAWH,EAAQ,IAAIlB,CAAG;AAChC,UAAIqB,EAAU,QAAOA;AACrB,YAAMC,IAAM,OAAO,EAAEH,CAAW;AAChC,aAAAD,EAAQ,IAAIlB,GAAKsB,CAAG,GACbA;AAAA,IACT;AACA,aAASC,EAAUvB,GAAwC;AACzD,aAAO;AAAA,QACL,SAAS,MACPtJ,EAAK,sBAAsB;AAAA,UACzB,MAAM;AAAA,UACN,SAASF,EAAM,MAAM;AAAA,UACrB,WAAWA,EAAM,MAAM,QAAQ;AAAA,UAC/B,QAAQwJ;AAAA,QAAA,CACT;AAAA,MAAA;AAAA,IAEP;AACA,aAASwB,IAAiB;AAAA,IAAC;;;;;;;;;;;;;;;;ACpIpB,SAASC,GAA6BC,GAAoD;AAC/F,SAAAA,EAAS,aAAa;AAAA,IACpB,EAAE,IAAI,UAAU,WAAWC,GAAA;AAAA,IAC3B,EAAE,IAAI,QAAQ,WAAWC,GAAA;AAAA,IACzB,EAAE,IAAI,OAAO,WAAWC,GAAA;AAAA,IACxB,EAAE,IAAI,OAAO,WAAWC,GAAA;AAAA,IACxB,EAAE,IAAI,SAAS,WAAWC,GAAA;AAAA,EAAc,CACzC,GACML;AACT;ACLO,MAAMM,WAA4BC,GAAyC;AAAA,EAChF,cAAc;AACZ,UAAM,0BAA0B;AAAA,EAClC;AACF;AAEO,SAASC,KAAiD;AAC/D,SAAO,IAAIF,GAAA;AACb;"}
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blazes/data-visualization",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.0-alpha.1",
4
4
  "description": "Framework-independent data visualization runtime with Vue renderers for Blazes applications.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",