feat(ai): render chart-json blocks as interactive charts
This commit is contained in:
1 parent
852ad1c808
commit
29c6d1fbed
22 files changed
+1214
-9
No files matched your search
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, toRaw, watch, type Component } from "vue";
|
||||
import { computed, defineAsyncComponent, h, nextTick, onMounted, onUnmounted, reactive, ref, toRaw, watch, type Component } from "vue";
|
||||
import { uuid } from "@/lib/common/utils";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { translateBackendError } from "@/i18n/backend-errors";
|
||||
@@ -176,6 +176,18 @@ import AiAttachmentCard from "@/components/editor/AiAttachmentCard.vue";
|
||||
import { resolveAiMessageCopyText } from "@/lib/ai/aiMessageCopy";
|
||||
|
||||
const { t } = useI18n();
|
||||
const AiChartRenderer = defineAsyncComponent({
|
||||
// Lazy-load the chart renderer (and with it the whole echarts bundle): echarts
|
||||
// is only pulled in when a message actually renders a chart-json segment.
|
||||
loader: () => import("@/components/ai/rich/AiChartRenderer.vue"),
|
||||
// A visible, fixed-height status prevents an async chunk from looking like a
|
||||
// failed chart and reserves the same viewport before the canvas is ready.
|
||||
loadingComponent: () =>
|
||||
h("div", { class: "my-2 flex min-h-60 h-[clamp(15rem,35vw,20rem)] w-full items-center justify-center gap-2 rounded-md border border-zinc-200 bg-zinc-50 text-xs text-zinc-500 dark:border-zinc-700/50 dark:bg-zinc-900 dark:text-zinc-400", role: "status", "aria-live": "polite" }, [
|
||||
h(Loader2, { class: "h-4 w-4 animate-spin", "aria-hidden": "true" }),
|
||||
h("span", t("common.loading")),
|
||||
]),
|
||||
});
|
||||
const settings = useSettingsStore();
|
||||
const connectionStore = useConnectionStore();
|
||||
const savedSqlStore = useSavedSqlStore();
|
||||
@@ -4701,6 +4713,7 @@ async function openExternalUrl(url: string) {
|
||||
<div v-if="seg.type === 'text'" class="ai-markdown whitespace-normal" @click.capture="onMarkdownClick">
|
||||
<div v-html="seg.html" />
|
||||
</div>
|
||||
<AiChartRenderer v-else-if="seg.type === 'chart'" :spec="seg.spec" :content="seg.content" />
|
||||
<div v-else class="my-2 overflow-hidden rounded-md border border-zinc-200 bg-zinc-50 dark:border-zinc-700/50 dark:bg-zinc-900">
|
||||
<div class="flex items-center border-b border-zinc-200 px-3 py-1.5 text-[10px] font-medium text-zinc-600 dark:border-zinc-700/50 dark:text-zinc-400">
|
||||
<component :is="seg.isSql ? Database : Terminal" class="h-3 w-3 mr-1.5" />
|
||||
|
||||
Reference in new issue
Block a user