main
vue 215 lines 6.64 KB
Raw
1 <template>
2 <div>
3 <CardEntity :embedded hoverable clickable @click.stop="showDetails = true">
4 <template #headerMain>
5 <div class="flex items-center gap-2">
6 {{ flow.session_id }}
7 </div>
8 </template>
9 <template #headerExtra>
10 <n-popover overlap placement="top-end" class="max-h-64" scrollable to="body">
11 <template #trigger>
12 <div class="flex cursor-help items-center gap-2">
13 <span>
14 {{ formatDate(flow.start_time, dFormats.datetimesec) }}
15 </span>
16 <Icon :name="TimeIcon" :size="16" />
17 </div>
18 </template>
19 <div class="flex flex-col px-1 py-2">
20 <AgentFlowTimeline :flow />
21 </div>
22 </n-popover>
23 </template>
24 <template #default>
25 <div class="flex flex-wrap gap-2">
26 <Badge
27 v-for="artifact of flow.artifacts_with_results"
28 :key="artifact"
29 color="primary"
30 type="splitted"
31 >
32 <template #value>
33 {{ artifact }}
34 </template>
35 </Badge>
36 </div>
37 </template>
38 <template #mainExtra>
39 <div class="flex flex-wrap items-center gap-3">
40 <Badge type="splitted" color="primary">
41 <template #label>State</template>
42 <template #value>
43 {{ flow.state || "-" }}
44 </template>
45 </Badge>
46 <Badge type="splitted" color="primary">
47 <template #label>Status</template>
48 <template #value>
49 {{ flow.status || "-" }}
50 </template>
51 </Badge>
52 <Badge type="splitted" color="primary">
53 <template #label>Exec. time</template>
54 <template #value>
55 {{ executionDuration }}
56 </template>
57 </Badge>
58 <Badge :type="flow.dirty ? 'active' : 'muted'">
59 <template #iconRight>
60 <Icon :name="flow.dirty ? EnabledIcon : DisabledIcon" :size="14" />
61 </template>
62 <template #label>Dirty</template>
63 </Badge>
64 <Badge :type="flow.user_notified ? 'active' : 'muted'">
65 <template #iconRight>
66 <Icon :name="flow.user_notified ? EnabledIcon : DisabledIcon" :size="14" />
67 </template>
68 <template #label>User notified</template>
69 </Badge>
70 </div>
71 </template>
72 </CardEntity>
73
74 <n-modal
75 v-model:show="showDetails"
76 preset="card"
77 content-class="p-0!"
78 :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(550px, 90vh)', overflow: 'hidden' }"
79 :title="`Agent Flow: ${flow.session_id}`"
80 :bordered="false"
81 segmented
82 >
83 <n-tabs type="line" animated :tabs-padding="24">
84 <n-tab-pane name="Info" tab="Info" display-directive="show">
85 <div v-if="properties" class="grid-auto-fit-200 grid gap-2 p-6 pt-3">
86 <CardKV v-for="(value, key) of properties" :key>
87 <template #key>
88 {{ key }}
89 </template>
90 <template #value>
91 {{ value === "" ? "-" : (value ?? "-") }}
92 </template>
93 </CardKV>
94 </div>
95 </n-tab-pane>
96 <n-tab-pane name="Backtrace" tab="Backtrace" display-directive="show">
97 <div class="p-6 pt-3">
98 <n-input
99 :value="flow.backtrace"
100 type="textarea"
101 readonly
102 placeholder="Empty"
103 size="large"
104 :autosize="{
105 minRows: 3,
106 maxRows: 18
107 }"
108 />
109 </div>
110 </n-tab-pane>
111 <n-tab-pane name="Timeline" tab="Timeline" display-directive="show:lazy">
112 <div class="p-6 pt-3">
113 <AgentFlowTimeline :flow />
114 </div>
115 </n-tab-pane>
116 <n-tab-pane name="Logs" tab="Logs" display-directive="show:lazy">
117 <div v-if="flow.logs.length" class="p-6 pt-3">
118 <ul>
119 <li v-for="log of flow.logs" :key="log">
120 {{ log }}
121 </li>
122 </ul>
123 </div>
124 <n-empty v-else description="No items found" class="h-48 justify-center" />
125 </n-tab-pane>
126 <n-tab-pane name="Uploaded files" tab="Uploaded files" display-directive="show:lazy">
127 <div v-if="flow.uploaded_files.length" class="p-6 pt-3">
128 <ul>
129 <li v-for="file of flow.uploaded_files" :key="file">
130 {{ file }}
131 </li>
132 </ul>
133 </div>
134 <n-empty v-else description="No items found" class="h-48 justify-center" />
135 </n-tab-pane>
136 <n-tab-pane name="Query stats" tab="Query stats" display-directive="show:lazy">
137 <div class="p-6 pt-3">
138 <template v-if="flow.query_stats.length">
139 <AgentFlowQueryStat
140 v-for="stat of flow.query_stats"
141 :key="stat.first_active + stat.last_active"
142 :stat
143 embedded
144 class="item-appear item-appear-bottom item-appear-005 mb-2"
145 />
146 </template>
147 <n-empty v-else description="No items found" class="h-48 justify-center" />
148 </div>
149 </n-tab-pane>
150 <n-tab-pane name="Request" tab="Request" display-directive="show:lazy">
151 <div class="p-6 pt-3">
152 <SimpleJsonViewer
153 class="vuesjv-override"
154 :model-value="flow.request"
155 :initial-expanded-depth="2"
156 />
157 </div>
158 </n-tab-pane>
159 <n-tab-pane name="Collect" tab="Collect" display-directive="show:lazy">
160 <n-scrollbar class="max-h-106" trigger="none">
161 <div class="px-7">
162 <AgentFlowCollectList :flow />
163 </div>
164 </n-scrollbar>
165 </n-tab-pane>
166 </n-tabs>
167 </n-modal>
168 </div>
169 </template>
170
171 <script setup lang="ts">
172 import type { FlowResult } from "@/types/flow.d"
173 import _pick from "lodash/pick"
174 import { NEmpty, NInput, NModal, NPopover, NScrollbar, NTabPane, NTabs } from "naive-ui"
175 import { computed, defineAsyncComponent, ref } from "vue"
176 import { SimpleJsonViewer } from "vue-sjv"
177 import Badge from "@/components/common/Badge.vue"
178 import CardEntity from "@/components/common/cards/CardEntity.vue"
179 import CardKV from "@/components/common/cards/CardKV.vue"
180 import Icon from "@/components/common/Icon.vue"
181 import { useSettingsStore } from "@/stores/settings"
182 import dayjs from "@/utils/dayjs"
183 import { formatDate } from "@/utils/format"
184 import "@/assets/scss/overrides/vuesjv-override.scss"
185
186 const { flow, embedded } = defineProps<{ flow: FlowResult; embedded?: boolean }>()
187 const AgentFlowTimeline = defineAsyncComponent(() => import("./AgentFlowTimeline.vue"))
188 const AgentFlowQueryStat = defineAsyncComponent(() => import("./AgentFlowQueryStat.vue"))
189 const AgentFlowCollectList = defineAsyncComponent(() => import("./AgentFlowCollectList.vue"))
190
191 const TimeIcon = "carbon:time"
192 const DisabledIcon = "carbon:subtract"
193 const EnabledIcon = "ri:check-line"
194
195 const showDetails = ref(false)
196 const dFormats = useSettingsStore().dateFormat
197
198 const executionDuration = computed(() => dayjs.duration(flow.execution_duration).humanize())
199
200 const properties = computed(() => {
201 return _pick(flow, [
202 "client_id",
203 "next_response_id",
204 "outstanding_requests",
205 "total_collected_rows",
206 "total_expected_uploaded_bytes",
207 "total_loads",
208 "total_logs",
209 "total_requests",
210 "total_uploaded_bytes",
211 "total_uploaded_files",
212 "user_notified"
213 ])
214 })
215 </script>