@antelopejs/dms-automation 0.0.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.
- package/LICENSE +190 -0
- package/README.md +95 -0
- package/dist/cluster/bus.d.ts +17 -0
- package/dist/cluster/bus.js +82 -0
- package/dist/cluster/bus.js.map +1 -0
- package/dist/cluster/instance.d.ts +1 -0
- package/dist/cluster/instance.js +6 -0
- package/dist/cluster/instance.js.map +1 -0
- package/dist/cluster/leader.d.ts +7 -0
- package/dist/cluster/leader.js +123 -0
- package/dist/cluster/leader.js.map +1 -0
- package/dist/cluster/mode.d.ts +3 -0
- package/dist/cluster/mode.js +25 -0
- package/dist/cluster/mode.js.map +1 -0
- package/dist/data/procedures-table.d.ts +66 -0
- package/dist/data/procedures-table.js +271 -0
- package/dist/data/procedures-table.js.map +1 -0
- package/dist/data/runs-table.d.ts +23 -0
- package/dist/data/runs-table.js +125 -0
- package/dist/data/runs-table.js.map +1 -0
- package/dist/db/index.d.ts +7 -0
- package/dist/db/index.js +24 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/models/automation_template.model.d.ts +58 -0
- package/dist/db/models/automation_template.model.js +134 -0
- package/dist/db/models/automation_template.model.js.map +1 -0
- package/dist/db/models/index.d.ts +3 -0
- package/dist/db/models/index.js +20 -0
- package/dist/db/models/index.js.map +1 -0
- package/dist/db/models/procedure.model.d.ts +25 -0
- package/dist/db/models/procedure.model.js +28 -0
- package/dist/db/models/procedure.model.js.map +1 -0
- package/dist/db/models/procedure_run.model.d.ts +34 -0
- package/dist/db/models/procedure_run.model.js +39 -0
- package/dist/db/models/procedure_run.model.js.map +1 -0
- package/dist/db/models/stats.model.d.ts +73 -0
- package/dist/db/models/stats.model.js +267 -0
- package/dist/db/models/stats.model.js.map +1 -0
- package/dist/db/models/type_config.model.d.ts +47 -0
- package/dist/db/models/type_config.model.js +51 -0
- package/dist/db/models/type_config.model.js.map +1 -0
- package/dist/db/tables/action_type_config.table.d.ts +7 -0
- package/dist/db/tables/action_type_config.table.js +35 -0
- package/dist/db/tables/action_type_config.table.js.map +1 -0
- package/dist/db/tables/automation_template.table.d.ts +11 -0
- package/dist/db/tables/automation_template.table.js +52 -0
- package/dist/db/tables/automation_template.table.js.map +1 -0
- package/dist/db/tables/index.d.ts +5 -0
- package/dist/db/tables/index.js +22 -0
- package/dist/db/tables/index.js.map +1 -0
- package/dist/db/tables/procedure.table.d.ts +10 -0
- package/dist/db/tables/procedure.table.js +48 -0
- package/dist/db/tables/procedure.table.js.map +1 -0
- package/dist/db/tables/procedure_run.table.d.ts +13 -0
- package/dist/db/tables/procedure_run.table.js +57 -0
- package/dist/db/tables/procedure_run.table.js.map +1 -0
- package/dist/db/tables/trigger_type_config.table.d.ts +7 -0
- package/dist/db/tables/trigger_type_config.table.js +35 -0
- package/dist/db/tables/trigger_type_config.table.js.map +1 -0
- package/dist/implementations/dms-automation/index.d.ts +19 -0
- package/dist/implementations/dms-automation/index.js +50 -0
- package/dist/implementations/dms-automation/index.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +121 -0
- package/dist/index.js.map +1 -0
- package/dist/pages/builder.d.ts +10 -0
- package/dist/pages/builder.js +28 -0
- package/dist/pages/builder.js.map +1 -0
- package/dist/pages/category.d.ts +1 -0
- package/dist/pages/category.js +10 -0
- package/dist/pages/category.js.map +1 -0
- package/dist/pages/index.d.ts +6 -0
- package/dist/pages/index.js +9 -0
- package/dist/pages/index.js.map +1 -0
- package/dist/pages/library.d.ts +10 -0
- package/dist/pages/library.js +28 -0
- package/dist/pages/library.js.map +1 -0
- package/dist/pages/overview.d.ts +10 -0
- package/dist/pages/overview.js +28 -0
- package/dist/pages/overview.js.map +1 -0
- package/dist/pages/procedures.d.ts +10 -0
- package/dist/pages/procedures.js +72 -0
- package/dist/pages/procedures.js.map +1 -0
- package/dist/pages/runs.d.ts +11 -0
- package/dist/pages/runs.js +61 -0
- package/dist/pages/runs.js.map +1 -0
- package/dist/routes/action-types.d.ts +23 -0
- package/dist/routes/action-types.js +80 -0
- package/dist/routes/action-types.js.map +1 -0
- package/dist/routes/data-node-types.d.ts +6 -0
- package/dist/routes/data-node-types.js +36 -0
- package/dist/routes/data-node-types.js.map +1 -0
- package/dist/routes/graphSchema.d.ts +92 -0
- package/dist/routes/graphSchema.js +60 -0
- package/dist/routes/graphSchema.js.map +1 -0
- package/dist/routes/index.d.ts +8 -0
- package/dist/routes/index.js +11 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/node-kinds.d.ts +9 -0
- package/dist/routes/node-kinds.js +35 -0
- package/dist/routes/node-kinds.js.map +1 -0
- package/dist/routes/procedures.d.ts +23 -0
- package/dist/routes/procedures.js +181 -0
- package/dist/routes/procedures.js.map +1 -0
- package/dist/routes/runs.d.ts +7 -0
- package/dist/routes/runs.js +81 -0
- package/dist/routes/runs.js.map +1 -0
- package/dist/routes/stats.d.ts +6 -0
- package/dist/routes/stats.js +35 -0
- package/dist/routes/stats.js.map +1 -0
- package/dist/routes/templates.d.ts +20 -0
- package/dist/routes/templates.js +243 -0
- package/dist/routes/templates.js.map +1 -0
- package/dist/routes/trigger-types.d.ts +24 -0
- package/dist/routes/trigger-types.js +80 -0
- package/dist/routes/trigger-types.js.map +1 -0
- package/dist/routes/typeConfigShared.d.ts +22 -0
- package/dist/routes/typeConfigShared.js +37 -0
- package/dist/routes/typeConfigShared.js.map +1 -0
- package/dist/runtime/builtins/actions/http.d.ts +13 -0
- package/dist/runtime/builtins/actions/http.js +47 -0
- package/dist/runtime/builtins/actions/http.js.map +1 -0
- package/dist/runtime/builtins/actions/index.d.ts +2 -0
- package/dist/runtime/builtins/actions/index.js +7 -0
- package/dist/runtime/builtins/actions/index.js.map +1 -0
- package/dist/runtime/builtins/actions/log.d.ts +13 -0
- package/dist/runtime/builtins/actions/log.js +49 -0
- package/dist/runtime/builtins/actions/log.js.map +1 -0
- package/dist/runtime/builtins/data/boolean.d.ts +2 -0
- package/dist/runtime/builtins/data/boolean.js +39 -0
- package/dist/runtime/builtins/data/boolean.js.map +1 -0
- package/dist/runtime/builtins/data/compare.d.ts +2 -0
- package/dist/runtime/builtins/data/compare.js +29 -0
- package/dist/runtime/builtins/data/compare.js.map +1 -0
- package/dist/runtime/builtins/data/constant.d.ts +2 -0
- package/dist/runtime/builtins/data/constant.js +29 -0
- package/dist/runtime/builtins/data/constant.js.map +1 -0
- package/dist/runtime/builtins/data/index.d.ts +2 -0
- package/dist/runtime/builtins/data/index.js +20 -0
- package/dist/runtime/builtins/data/index.js.map +1 -0
- package/dist/runtime/builtins/data/json.d.ts +2 -0
- package/dist/runtime/builtins/data/json.js +46 -0
- package/dist/runtime/builtins/data/json.js.map +1 -0
- package/dist/runtime/builtins/data/math.d.ts +2 -0
- package/dist/runtime/builtins/data/math.js +53 -0
- package/dist/runtime/builtins/data/math.js.map +1 -0
- package/dist/runtime/builtins/data/object.d.ts +2 -0
- package/dist/runtime/builtins/data/object.js +121 -0
- package/dist/runtime/builtins/data/object.js.map +1 -0
- package/dist/runtime/builtins/data/string.d.ts +2 -0
- package/dist/runtime/builtins/data/string.js +143 -0
- package/dist/runtime/builtins/data/string.js.map +1 -0
- package/dist/runtime/builtins/index.d.ts +17 -0
- package/dist/runtime/builtins/index.js +24 -0
- package/dist/runtime/builtins/index.js.map +1 -0
- package/dist/runtime/builtins/nodes/action.d.ts +1 -0
- package/dist/runtime/builtins/nodes/action.js +36 -0
- package/dist/runtime/builtins/nodes/action.js.map +1 -0
- package/dist/runtime/builtins/nodes/data.d.ts +1 -0
- package/dist/runtime/builtins/nodes/data.js +28 -0
- package/dist/runtime/builtins/nodes/data.js.map +1 -0
- package/dist/runtime/builtins/nodes/delay.d.ts +1 -0
- package/dist/runtime/builtins/nodes/delay.js +41 -0
- package/dist/runtime/builtins/nodes/delay.js.map +1 -0
- package/dist/runtime/builtins/nodes/forRange.d.ts +1 -0
- package/dist/runtime/builtins/nodes/forRange.js +52 -0
- package/dist/runtime/builtins/nodes/forRange.js.map +1 -0
- package/dist/runtime/builtins/nodes/foreach.d.ts +1 -0
- package/dist/runtime/builtins/nodes/foreach.js +31 -0
- package/dist/runtime/builtins/nodes/foreach.js.map +1 -0
- package/dist/runtime/builtins/nodes/groupInput.d.ts +1 -0
- package/dist/runtime/builtins/nodes/groupInput.js +11 -0
- package/dist/runtime/builtins/nodes/groupInput.js.map +1 -0
- package/dist/runtime/builtins/nodes/groupOutput.d.ts +1 -0
- package/dist/runtime/builtins/nodes/groupOutput.js +11 -0
- package/dist/runtime/builtins/nodes/groupOutput.js.map +1 -0
- package/dist/runtime/builtins/nodes/if.d.ts +1 -0
- package/dist/runtime/builtins/nodes/if.js +23 -0
- package/dist/runtime/builtins/nodes/if.js.map +1 -0
- package/dist/runtime/builtins/nodes/parallel.d.ts +1 -0
- package/dist/runtime/builtins/nodes/parallel.js +34 -0
- package/dist/runtime/builtins/nodes/parallel.js.map +1 -0
- package/dist/runtime/builtins/nodes/retry.d.ts +1 -0
- package/dist/runtime/builtins/nodes/retry.js +46 -0
- package/dist/runtime/builtins/nodes/retry.js.map +1 -0
- package/dist/runtime/builtins/nodes/setVariable.d.ts +1 -0
- package/dist/runtime/builtins/nodes/setVariable.js +31 -0
- package/dist/runtime/builtins/nodes/setVariable.js.map +1 -0
- package/dist/runtime/builtins/nodes/switch.d.ts +1 -0
- package/dist/runtime/builtins/nodes/switch.js +33 -0
- package/dist/runtime/builtins/nodes/switch.js.map +1 -0
- package/dist/runtime/builtins/nodes/trigger.d.ts +1 -0
- package/dist/runtime/builtins/nodes/trigger.js +25 -0
- package/dist/runtime/builtins/nodes/trigger.js.map +1 -0
- package/dist/runtime/builtins/nodes/tryCatch.d.ts +1 -0
- package/dist/runtime/builtins/nodes/tryCatch.js +35 -0
- package/dist/runtime/builtins/nodes/tryCatch.js.map +1 -0
- package/dist/runtime/builtins/triggers/cron.d.ts +9 -0
- package/dist/runtime/builtins/triggers/cron.js +52 -0
- package/dist/runtime/builtins/triggers/cron.js.map +1 -0
- package/dist/runtime/builtins/triggers/index.d.ts +2 -0
- package/dist/runtime/builtins/triggers/index.js +12 -0
- package/dist/runtime/builtins/triggers/index.js.map +1 -0
- package/dist/runtime/builtins/triggers/manual.d.ts +3 -0
- package/dist/runtime/builtins/triggers/manual.js +20 -0
- package/dist/runtime/builtins/triggers/manual.js.map +1 -0
- package/dist/runtime/builtins/triggers/webhook.d.ts +14 -0
- package/dist/runtime/builtins/triggers/webhook.js +90 -0
- package/dist/runtime/builtins/triggers/webhook.js.map +1 -0
- package/dist/runtime/executionResult.d.ts +6 -0
- package/dist/runtime/executionResult.js +3 -0
- package/dist/runtime/executionResult.js.map +1 -0
- package/dist/runtime/executor.d.ts +9 -0
- package/dist/runtime/executor.js +300 -0
- package/dist/runtime/executor.js.map +1 -0
- package/dist/runtime/flatten.d.ts +3 -0
- package/dist/runtime/flatten.js +188 -0
- package/dist/runtime/flatten.js.map +1 -0
- package/dist/runtime/nodeKinds.d.ts +64 -0
- package/dist/runtime/nodeKinds.js +43 -0
- package/dist/runtime/nodeKinds.js.map +1 -0
- package/dist/runtime/reconcileDiff.d.ts +9 -0
- package/dist/runtime/reconcileDiff.js +26 -0
- package/dist/runtime/reconcileDiff.js.map +1 -0
- package/dist/runtime/registry.d.ts +19 -0
- package/dist/runtime/registry.js +47 -0
- package/dist/runtime/registry.js.map +1 -0
- package/dist/runtime/resolveInputs.d.ts +14 -0
- package/dist/runtime/resolveInputs.js +64 -0
- package/dist/runtime/resolveInputs.js.map +1 -0
- package/dist/runtime/resolveSubgraph.d.ts +7 -0
- package/dist/runtime/resolveSubgraph.js +15 -0
- package/dist/runtime/resolveSubgraph.js.map +1 -0
- package/dist/runtime/subscriptions.d.ts +16 -0
- package/dist/runtime/subscriptions.js +419 -0
- package/dist/runtime/subscriptions.js.map +1 -0
- package/dist/runtime/subwalk.d.ts +17 -0
- package/dist/runtime/subwalk.js +74 -0
- package/dist/runtime/subwalk.js.map +1 -0
- package/dist/runtime/topo.d.ts +3 -0
- package/dist/runtime/topo.js +75 -0
- package/dist/runtime/topo.js.map +1 -0
- package/dist/runtime/typeOrigin.d.ts +7 -0
- package/dist/runtime/typeOrigin.js +24 -0
- package/dist/runtime/typeOrigin.js.map +1 -0
- package/dist/runtime/validate.d.ts +10 -0
- package/dist/runtime/validate.js +185 -0
- package/dist/runtime/validate.js.map +1 -0
- package/dist/runtime/validateTemplate.d.ts +3 -0
- package/dist/runtime/validateTemplate.js +54 -0
- package/dist/runtime/validateTemplate.js.map +1 -0
- package/dist/types/constants.d.ts +6 -0
- package/dist/types/constants.js +10 -0
- package/dist/types/constants.js.map +1 -0
- package/dist/types/graph.d.ts +51 -0
- package/dist/types/graph.js +23 -0
- package/dist/types/graph.js.map +1 -0
- package/dist/types/pagination.d.ts +8 -0
- package/dist/types/pagination.js +3 -0
- package/dist/types/pagination.js.map +1 -0
- package/dist/types/runLog.d.ts +26 -0
- package/dist/types/runLog.js +3 -0
- package/dist/types/runLog.js.map +1 -0
- package/frontend-vue/.prettierignore +4 -0
- package/frontend-vue/app/components/Actions.vue +141 -0
- package/frontend-vue/app/components/Catalog/TypeConfigForm.vue +166 -0
- package/frontend-vue/app/components/Catalog/TypeList.vue +198 -0
- package/frontend-vue/app/components/DataNodes.vue +259 -0
- package/frontend-vue/app/components/Editor/BuilderPalette.vue +234 -0
- package/frontend-vue/app/components/Editor/GraphCanvas.vue +994 -0
- package/frontend-vue/app/components/Editor/GroupPortEditor.vue +289 -0
- package/frontend-vue/app/components/Editor/JsonField.vue +63 -0
- package/frontend-vue/app/components/Editor/NodeInspector.vue +356 -0
- package/frontend-vue/app/components/Editor/ProcedureList.vue +156 -0
- package/frontend-vue/app/components/Editor/RunsDrawer.vue +312 -0
- package/frontend-vue/app/components/Editor/WiredField.vue +42 -0
- package/frontend-vue/app/components/Editor/nodes/GenericNode.vue +161 -0
- package/frontend-vue/app/components/Editor/nodes/GroupInputNode.vue +19 -0
- package/frontend-vue/app/components/Editor/nodes/GroupNode.vue +200 -0
- package/frontend-vue/app/components/Editor/nodes/GroupOutputNode.vue +19 -0
- package/frontend-vue/app/components/Editor/nodes/GroupSentinel.vue +161 -0
- package/frontend-vue/app/components/Editor/nodes/styles.ts +53 -0
- package/frontend-vue/app/components/Editor.vue +2504 -0
- package/frontend-vue/app/components/Library.vue +67 -0
- package/frontend-vue/app/components/Overview.vue +503 -0
- package/frontend-vue/app/components/RunDetailDrawer.vue +165 -0
- package/frontend-vue/app/components/RunFireTree.vue +170 -0
- package/frontend-vue/app/components/RunTraceDrawer.vue +59 -0
- package/frontend-vue/app/components/RunsStats.vue +126 -0
- package/frontend-vue/app/components/RunsTimelineDisplay.vue +287 -0
- package/frontend-vue/app/components/Templates.vue +663 -0
- package/frontend-vue/app/components/Triggers.vue +137 -0
- package/frontend-vue/app/composables/useAutomationNodeKinds.ts +48 -0
- package/frontend-vue/app/composables/useAutomationRuns.ts +75 -0
- package/frontend-vue/app/composables/useGraphConnect.ts +542 -0
- package/frontend-vue/app/plugins/runs-timeline-display.client.ts +16 -0
- package/frontend-vue/app/utils/automation.ts +51 -0
- package/frontend-vue/dms.frontend.ts +26 -0
- package/frontend-vue/eslint.config.mjs +24 -0
- package/frontend-vue/i18n/locales/dms-automation-en-GB.json +369 -0
- package/frontend-vue/i18n/locales/dms-automation-fr-FR.json +369 -0
- package/frontend-vue/package.json +33 -0
- package/frontend-vue/pnpm-lock.yaml +6483 -0
- package/frontend-vue/pnpm-workspace.yaml +2 -0
- package/package.json +81 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import type {
|
|
4
|
+
FireNode,
|
|
5
|
+
LogEntry,
|
|
6
|
+
RunDetail,
|
|
7
|
+
} from '../composables/useAutomationRuns'
|
|
8
|
+
import RunFireTree from './RunFireTree.vue'
|
|
9
|
+
|
|
10
|
+
const props = defineProps<{
|
|
11
|
+
run: RunDetail
|
|
12
|
+
procedureName?: string
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const statusColor = computed<'success' | 'error' | 'warning' | 'neutral'>(
|
|
16
|
+
() => {
|
|
17
|
+
if (props.run.status === 'ok') return 'success'
|
|
18
|
+
if (props.run.status === 'failed') return 'error'
|
|
19
|
+
return 'neutral'
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const startedAt = computed(() =>
|
|
24
|
+
props.run.startedAt ? new Date(props.run.startedAt).toLocaleString() : '—',
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const durationMs = computed<string>(() => {
|
|
28
|
+
if (!props.run.startedAt || !props.run.endedAt) return '—'
|
|
29
|
+
const s = new Date(props.run.startedAt).getTime()
|
|
30
|
+
const e = new Date(props.run.endedAt).getTime()
|
|
31
|
+
if (Number.isNaN(s) || Number.isNaN(e)) return '—'
|
|
32
|
+
return `${e - s} ms`
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
function prettyJson(text?: string | null): string {
|
|
36
|
+
if (!text) return ''
|
|
37
|
+
try {
|
|
38
|
+
return JSON.stringify(JSON.parse(text), null, 2)
|
|
39
|
+
} catch {
|
|
40
|
+
return text
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const payloadJson = computed(() => prettyJson(props.run.triggerPayload))
|
|
45
|
+
const hasPayload = computed(
|
|
46
|
+
() => !!props.run.triggerPayload && props.run.triggerPayload !== '{}',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const fires = computed<FireNode[]>(() => props.run.logs?.fires ?? [])
|
|
50
|
+
const entries = computed<LogEntry[]>(() => props.run.logs?.entries ?? [])
|
|
51
|
+
const hasLogs = computed(
|
|
52
|
+
() => fires.value.length > 0 || entries.value.length > 0,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
// Index entries and child fires by their parent fire id so the recursive
|
|
56
|
+
// RunFireTree component can do constant-time lookups while rendering.
|
|
57
|
+
const childrenOf = computed<Map<string, FireNode[]>>(() => {
|
|
58
|
+
const m = new Map<string, FireNode[]>()
|
|
59
|
+
for (const f of fires.value) {
|
|
60
|
+
if (f.parentFireId === null) continue
|
|
61
|
+
let list = m.get(f.parentFireId)
|
|
62
|
+
if (!list) {
|
|
63
|
+
list = []
|
|
64
|
+
m.set(f.parentFireId, list)
|
|
65
|
+
}
|
|
66
|
+
list.push(f)
|
|
67
|
+
}
|
|
68
|
+
return m
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const entriesOf = computed<Map<string, LogEntry[]>>(() => {
|
|
72
|
+
const m = new Map<string, LogEntry[]>()
|
|
73
|
+
for (const e of entries.value) {
|
|
74
|
+
let list = m.get(e.fireId)
|
|
75
|
+
if (!list) {
|
|
76
|
+
list = []
|
|
77
|
+
m.set(e.fireId, list)
|
|
78
|
+
}
|
|
79
|
+
list.push(e)
|
|
80
|
+
}
|
|
81
|
+
return m
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const rootFires = computed<FireNode[]>(() =>
|
|
85
|
+
fires.value.filter((f) => f.parentFireId === null),
|
|
86
|
+
)
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<template>
|
|
90
|
+
<div class="flex flex-col gap-4 p-1">
|
|
91
|
+
<div class="flex flex-col gap-2">
|
|
92
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
93
|
+
<UBadge :color="statusColor" variant="subtle" class="font-semibold">
|
|
94
|
+
{{ run.status.toUpperCase() }}
|
|
95
|
+
</UBadge>
|
|
96
|
+
<code
|
|
97
|
+
class="rounded-md bg-muted px-2 py-1 font-mono text-sm text-highlighted"
|
|
98
|
+
>
|
|
99
|
+
{{ procedureName ?? run.procedureId }}
|
|
100
|
+
</code>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="flex flex-wrap items-center gap-2 text-xs text-dimmed">
|
|
103
|
+
<span class="tabular-nums">{{ durationMs }}</span>
|
|
104
|
+
<span>·</span>
|
|
105
|
+
<span class="tabular-nums">{{ startedAt }}</span>
|
|
106
|
+
<span v-if="run.triggerNodeId">
|
|
107
|
+
· {{ $t('dms_automation.runs.detail.trigger') }}
|
|
108
|
+
<code class="font-mono">{{ run.triggerNodeId }}</code>
|
|
109
|
+
</span>
|
|
110
|
+
</div>
|
|
111
|
+
<p class="text-xs text-muted">
|
|
112
|
+
{{ $t('dms_automation.runs.detail.runId') }}
|
|
113
|
+
<code class="font-mono">{{ run._id }}</code>
|
|
114
|
+
</p>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<USeparator />
|
|
118
|
+
|
|
119
|
+
<section v-if="run.errorMessage" class="flex flex-col gap-2">
|
|
120
|
+
<h4 class="text-sm font-semibold text-error">
|
|
121
|
+
{{ $t('dms_automation.runs.detail.error') }}
|
|
122
|
+
</h4>
|
|
123
|
+
<pre
|
|
124
|
+
class="max-h-48 overflow-auto rounded-lg border border-default bg-muted p-3 text-[11px] text-toned"
|
|
125
|
+
>{{ run.errorMessage }}</pre>
|
|
126
|
+
</section>
|
|
127
|
+
|
|
128
|
+
<section v-if="hasPayload" class="flex flex-col gap-2">
|
|
129
|
+
<h4 class="text-sm font-semibold text-highlighted">
|
|
130
|
+
{{ $t('dms_automation.runs.detail.triggerPayload') }}
|
|
131
|
+
</h4>
|
|
132
|
+
<pre
|
|
133
|
+
class="max-h-64 overflow-auto rounded-lg border border-default bg-muted p-3 text-[11px] text-toned"
|
|
134
|
+
>{{ payloadJson }}</pre>
|
|
135
|
+
</section>
|
|
136
|
+
|
|
137
|
+
<section class="flex flex-col gap-2">
|
|
138
|
+
<h4 class="text-sm font-semibold text-highlighted">
|
|
139
|
+
{{ $t('dms_automation.runs.detail.logs') }}
|
|
140
|
+
</h4>
|
|
141
|
+
<p v-if="!hasLogs" class="text-xs italic text-dimmed">
|
|
142
|
+
{{ $t('dms_automation.runs.detail.noLogs') }}
|
|
143
|
+
</p>
|
|
144
|
+
<div
|
|
145
|
+
v-else
|
|
146
|
+
class="flex flex-col overflow-hidden rounded-lg border border-default"
|
|
147
|
+
>
|
|
148
|
+
<RunFireTree
|
|
149
|
+
v-for="fire in rootFires"
|
|
150
|
+
:key="fire.id"
|
|
151
|
+
:fire="fire"
|
|
152
|
+
:children-of="childrenOf"
|
|
153
|
+
:entries-of="entriesOf"
|
|
154
|
+
/>
|
|
155
|
+
</div>
|
|
156
|
+
</section>
|
|
157
|
+
|
|
158
|
+
<p
|
|
159
|
+
v-if="!run.errorMessage && !hasPayload && !hasLogs"
|
|
160
|
+
class="text-xs italic text-dimmed"
|
|
161
|
+
>
|
|
162
|
+
{{ $t('dms_automation.runs.detail.none') }}
|
|
163
|
+
</p>
|
|
164
|
+
</div>
|
|
165
|
+
</template>
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref } from 'vue'
|
|
3
|
+
import type {
|
|
4
|
+
FireNode,
|
|
5
|
+
LogEntry,
|
|
6
|
+
} from '../composables/useAutomationRuns'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
fire: FireNode
|
|
10
|
+
childrenOf: Map<string, FireNode[]>
|
|
11
|
+
entriesOf: Map<string, LogEntry[]>
|
|
12
|
+
}>()
|
|
13
|
+
|
|
14
|
+
defineOptions({ name: 'RunFireTree' })
|
|
15
|
+
|
|
16
|
+
const open = ref(true)
|
|
17
|
+
function toggle() {
|
|
18
|
+
open.value = !open.value
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ownEntries = computed<LogEntry[]>(
|
|
22
|
+
() => props.entriesOf.get(props.fire.id) ?? [],
|
|
23
|
+
)
|
|
24
|
+
const childFires = computed<FireNode[]>(
|
|
25
|
+
() => props.childrenOf.get(props.fire.id) ?? [],
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
type Item =
|
|
29
|
+
| { kind: 'entry'; ts: number; seq: number; entry: LogEntry }
|
|
30
|
+
| { kind: 'fire'; ts: number; seq: number; fire: FireNode }
|
|
31
|
+
|
|
32
|
+
// Chronological interleave of own log entries and child fires within this
|
|
33
|
+
// fire's scope. Sort by ts first; break ties with `seq` (the executor's
|
|
34
|
+
// monotonic event counter) so sub-millisecond iterations preserve their
|
|
35
|
+
// logical order — without this, "run ok" sometimes appears between
|
|
36
|
+
// iterations because the entry was pushed into the merge first.
|
|
37
|
+
const items = computed<Item[]>(() => {
|
|
38
|
+
const merged: Item[] = []
|
|
39
|
+
for (const entry of ownEntries.value) {
|
|
40
|
+
merged.push({ kind: 'entry', ts: entry.ts, seq: entry.seq, entry })
|
|
41
|
+
}
|
|
42
|
+
for (const child of childFires.value) {
|
|
43
|
+
merged.push({ kind: 'fire', ts: child.ts, seq: child.seq, fire: child })
|
|
44
|
+
}
|
|
45
|
+
merged.sort((a, b) => a.ts - b.ts || a.seq - b.seq)
|
|
46
|
+
return merged
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const headerLabel = computed(() => {
|
|
50
|
+
const f = props.fire
|
|
51
|
+
const port = f.port ? ` · ${f.port}` : ''
|
|
52
|
+
const iter =
|
|
53
|
+
typeof f.iteration === 'number' ? ` · iter ${f.iteration}` : ''
|
|
54
|
+
return `${f.sourceNodeId}${port}${iter}`
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const durationLabel = computed(() => {
|
|
58
|
+
const f = props.fire
|
|
59
|
+
if (typeof f.closedAt !== 'number') return '…'
|
|
60
|
+
return `${f.closedAt - f.ts} ms`
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// Track expanded entries by `seq` (executor-emitted, stable across
|
|
64
|
+
// reflows). Index-based keying flips state every time logs arrive in
|
|
65
|
+
// a different order.
|
|
66
|
+
const expandedEntrySeq = ref<Set<number>>(new Set())
|
|
67
|
+
function toggleExpanded(seq: number) {
|
|
68
|
+
if (expandedEntrySeq.value.has(seq)) expandedEntrySeq.value.delete(seq)
|
|
69
|
+
else expandedEntrySeq.value.add(seq)
|
|
70
|
+
expandedEntrySeq.value = new Set(expandedEntrySeq.value)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function iconFor(level: LogEntry['level']): { name: string; class: string } {
|
|
74
|
+
if (level === 'error') return { name: 'i-ph-x-circle', class: 'text-error' }
|
|
75
|
+
if (level === 'warn') return { name: 'i-ph-warning', class: 'text-warning' }
|
|
76
|
+
return { name: 'i-ph-info', class: 'text-muted' }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function formatTs(ms: number): string {
|
|
80
|
+
return `+${ms} ms`
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function nodeLabel(entry: LogEntry): string {
|
|
84
|
+
if (!entry.nodeId) return 'run'
|
|
85
|
+
return entry.nodeKind ? `${entry.nodeKind} · ${entry.nodeId}` : entry.nodeId
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function prettyValue(v: unknown): string {
|
|
89
|
+
try {
|
|
90
|
+
return JSON.stringify(v, null, 2)
|
|
91
|
+
} catch {
|
|
92
|
+
return String(v)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Short inline summary shown next to the message for `log`-source entries
|
|
97
|
+
// (e.g. `Body alpha`, `Body 42`). Falls back to a compact JSON snippet
|
|
98
|
+
// for arrays/objects; truncates anything longer than 40 chars.
|
|
99
|
+
function inlineSummary(v: unknown): string {
|
|
100
|
+
if (v === undefined || v === null) return ''
|
|
101
|
+
if (typeof v === 'string') return v.length > 40 ? `${v.slice(0, 40)}…` : v
|
|
102
|
+
if (typeof v === 'number' || typeof v === 'boolean') return String(v)
|
|
103
|
+
try {
|
|
104
|
+
const j = JSON.stringify(v)
|
|
105
|
+
return j.length > 40 ? `${j.slice(0, 40)}…` : j
|
|
106
|
+
} catch {
|
|
107
|
+
return ''
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</script>
|
|
111
|
+
|
|
112
|
+
<template>
|
|
113
|
+
<div class="flex flex-col">
|
|
114
|
+
<button
|
|
115
|
+
type="button"
|
|
116
|
+
class="grid grid-cols-[auto_auto_1fr_auto] items-center gap-2 px-2 py-1 text-left text-xs hover:bg-elevated border-b border-default"
|
|
117
|
+
@click="toggle"
|
|
118
|
+
>
|
|
119
|
+
<UIcon
|
|
120
|
+
:name="open ? 'i-ph-caret-down' : 'i-ph-caret-right'"
|
|
121
|
+
class="text-dimmed"
|
|
122
|
+
/>
|
|
123
|
+
<span class="font-mono tabular-nums text-dimmed">{{ formatTs(fire.ts) }}</span>
|
|
124
|
+
<span class="font-mono text-default truncate">{{ headerLabel }}</span>
|
|
125
|
+
<span class="font-mono tabular-nums text-dimmed">{{ durationLabel }}</span>
|
|
126
|
+
</button>
|
|
127
|
+
<div v-if="open" class="border-l-2 border-default pl-2 ml-2">
|
|
128
|
+
<template v-for="item in items" :key="`${item.kind}-${item.seq}`">
|
|
129
|
+
<RunFireTree
|
|
130
|
+
v-if="item.kind === 'fire'"
|
|
131
|
+
:fire="item.fire"
|
|
132
|
+
:children-of="childrenOf"
|
|
133
|
+
:entries-of="entriesOf"
|
|
134
|
+
/>
|
|
135
|
+
<div
|
|
136
|
+
v-else
|
|
137
|
+
class="border-b border-default last:border-b-0"
|
|
138
|
+
>
|
|
139
|
+
<button
|
|
140
|
+
type="button"
|
|
141
|
+
class="grid w-full grid-cols-[auto_auto_auto_1fr_auto] items-center gap-2 px-2 py-1 text-left text-xs hover:bg-elevated"
|
|
142
|
+
:disabled="item.entry.value === undefined"
|
|
143
|
+
@click="toggleExpanded(item.seq)"
|
|
144
|
+
>
|
|
145
|
+
<span class="font-mono tabular-nums text-dimmed">{{ formatTs(item.entry.ts) }}</span>
|
|
146
|
+
<UIcon :name="iconFor(item.entry.level).name" :class="iconFor(item.entry.level).class" />
|
|
147
|
+
<span class="font-mono text-muted truncate">{{ nodeLabel(item.entry) }}</span>
|
|
148
|
+
<span class="truncate text-default">
|
|
149
|
+
<span v-if="item.entry.source === 'exec'" class="mr-1 inline-block rounded bg-elevated px-1 py-px text-[10px] uppercase text-dimmed">exec</span>
|
|
150
|
+
{{ item.entry.message }}
|
|
151
|
+
<span
|
|
152
|
+
v-if="item.entry.source === 'log' && inlineSummary(item.entry.value)"
|
|
153
|
+
class="ml-2 font-mono text-dimmed"
|
|
154
|
+
>{{ inlineSummary(item.entry.value) }}</span>
|
|
155
|
+
</span>
|
|
156
|
+
<UIcon
|
|
157
|
+
v-if="item.entry.value !== undefined"
|
|
158
|
+
:name="expandedEntrySeq.has(item.seq) ? 'i-ph-caret-down' : 'i-ph-caret-right'"
|
|
159
|
+
class="text-dimmed"
|
|
160
|
+
/>
|
|
161
|
+
</button>
|
|
162
|
+
<pre
|
|
163
|
+
v-if="item.entry.value !== undefined && expandedEntrySeq.has(item.seq)"
|
|
164
|
+
class="max-h-48 overflow-auto bg-elevated px-3 py-2 text-[11px]"
|
|
165
|
+
>{{ prettyValue(item.entry.value) }}</pre>
|
|
166
|
+
</div>
|
|
167
|
+
</template>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
</template>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onMounted, ref } from 'vue'
|
|
3
|
+
import type { RunDetail, RunSummary } from '../composables/useAutomationRuns'
|
|
4
|
+
import RunDetailDrawer from './RunDetailDrawer.vue'
|
|
5
|
+
|
|
6
|
+
// Drawer body for a single run, opened by the timeline display's Trace
|
|
7
|
+
// button via `useDrawer` (which passes `rowData` and `procedureName`). The
|
|
8
|
+
// summary row carries no logs, so we re-fetch the full run by id here.
|
|
9
|
+
// Attribute fallthrough is disabled so extra injected props don't leak
|
|
10
|
+
// onto the DOM.
|
|
11
|
+
defineOptions({ inheritAttrs: false })
|
|
12
|
+
|
|
13
|
+
const props = defineProps<{
|
|
14
|
+
rowData: RunSummary
|
|
15
|
+
procedureName?: string
|
|
16
|
+
}>()
|
|
17
|
+
|
|
18
|
+
const { getRun, listProcedures } = useAutomationRuns()
|
|
19
|
+
|
|
20
|
+
const run = ref<RunDetail | null>(null)
|
|
21
|
+
const resolvedName = ref<string | undefined>(props.procedureName)
|
|
22
|
+
const loading = ref(true)
|
|
23
|
+
|
|
24
|
+
onMounted(async () => {
|
|
25
|
+
const [full] = await Promise.all([
|
|
26
|
+
// Fall back to the summary row (no logs) if the detail fetch fails, so the
|
|
27
|
+
// drawer still shows status/timing/error.
|
|
28
|
+
getRun(props.rowData._id).catch(() => props.rowData as RunDetail),
|
|
29
|
+
props.procedureName
|
|
30
|
+
? Promise.resolve()
|
|
31
|
+
: listProcedures()
|
|
32
|
+
.then((ps) => {
|
|
33
|
+
resolvedName.value = ps.find(
|
|
34
|
+
(p) => p._id === props.rowData.procedureId,
|
|
35
|
+
)?.name
|
|
36
|
+
})
|
|
37
|
+
.catch(() => {
|
|
38
|
+
/* name lookup is best-effort; falls back to procedureId */
|
|
39
|
+
}),
|
|
40
|
+
])
|
|
41
|
+
run.value = full
|
|
42
|
+
loading.value = false
|
|
43
|
+
})
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<div class="p-1">
|
|
48
|
+
<div v-if="loading" class="flex flex-col gap-3 p-1">
|
|
49
|
+
<USkeleton class="h-6 w-2/3" />
|
|
50
|
+
<USkeleton class="h-4 w-1/2" />
|
|
51
|
+
<USkeleton class="h-32 w-full" />
|
|
52
|
+
</div>
|
|
53
|
+
<RunDetailDrawer
|
|
54
|
+
v-else-if="run"
|
|
55
|
+
:run="run"
|
|
56
|
+
:procedure-name="resolvedName"
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, onMounted, ref } from 'vue'
|
|
3
|
+
import { formatDuration } from '../utils/automation'
|
|
4
|
+
|
|
5
|
+
// Page-level header + KPI cards for the Runs page, rendered ABOVE the TableView
|
|
6
|
+
// (registered as `dms-automation-runs-stats`, wired via `static stats` in
|
|
7
|
+
// src/pages/runs.ts). Self-contained: fetches its own stats snapshot. The run
|
|
8
|
+
// list, tabs, filters, export and pagination are owned by the TableView below.
|
|
9
|
+
|
|
10
|
+
const { $authFetch } = useAuthFetch()
|
|
11
|
+
|
|
12
|
+
interface StatsSnapshot {
|
|
13
|
+
health: { '24h': { avgDurationMs: number } }
|
|
14
|
+
runsPerDay7d: Array<{ day: string; ok: number; failed: number }>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const stats = ref<StatsSnapshot | null>(null)
|
|
18
|
+
const loading = ref(false)
|
|
19
|
+
|
|
20
|
+
const kpis = computed(() => {
|
|
21
|
+
const days = stats.value?.runsPerDay7d ?? []
|
|
22
|
+
const today = days[days.length - 1] ?? { ok: 0, failed: 0 }
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
key: 'today',
|
|
26
|
+
title: '$dms_automation.runs.kpis.today',
|
|
27
|
+
value: today.ok + today.failed,
|
|
28
|
+
icon: 'i-ph-activity',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
key: 'success',
|
|
32
|
+
title: '$dms_automation.runs.kpis.success',
|
|
33
|
+
value: today.ok,
|
|
34
|
+
icon: 'i-ph-check-circle',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
key: 'failed',
|
|
38
|
+
title: '$dms_automation.runs.kpis.failed',
|
|
39
|
+
value: today.failed,
|
|
40
|
+
icon: 'i-ph-x-circle',
|
|
41
|
+
},
|
|
42
|
+
]
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const avgDurationLabel = computed(() =>
|
|
46
|
+
formatDuration(stats.value?.health?.['24h']?.avgDurationMs ?? 0),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
async function loadStats() {
|
|
50
|
+
loading.value = true
|
|
51
|
+
try {
|
|
52
|
+
stats.value = await $authFetch<StatsSnapshot>('/api/automation/stats')
|
|
53
|
+
} catch {
|
|
54
|
+
/* KPIs are best-effort. */
|
|
55
|
+
} finally {
|
|
56
|
+
loading.value = false
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
onMounted(loadStats)
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<template>
|
|
64
|
+
<!--
|
|
65
|
+
Title / icon / description come from the page's native dms header
|
|
66
|
+
(src/pages/runs.ts) — only the refresh action lives here.
|
|
67
|
+
-->
|
|
68
|
+
<div class="runs-stats flex flex-col gap-5">
|
|
69
|
+
<section class="flex flex-wrap items-center justify-end gap-4">
|
|
70
|
+
<UButton
|
|
71
|
+
color="neutral"
|
|
72
|
+
variant="ghost"
|
|
73
|
+
icon="i-ph-arrows-clockwise"
|
|
74
|
+
:loading="loading"
|
|
75
|
+
:aria-label="$t('dms_automation.common.refresh')"
|
|
76
|
+
@click="loadStats"
|
|
77
|
+
/>
|
|
78
|
+
</section>
|
|
79
|
+
|
|
80
|
+
<!-- KPI stat cards -->
|
|
81
|
+
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
|
82
|
+
<template v-if="stats">
|
|
83
|
+
<DmsKpiCard
|
|
84
|
+
v-for="k in kpis"
|
|
85
|
+
:key="k.key"
|
|
86
|
+
variant="stat"
|
|
87
|
+
page-id="automation.runs"
|
|
88
|
+
:component-id="`runs-kpi-${k.key}`"
|
|
89
|
+
:title="k.title"
|
|
90
|
+
:icon="k.icon"
|
|
91
|
+
:static-value="k.value"
|
|
92
|
+
value-format="compact"
|
|
93
|
+
:show-delta="false"
|
|
94
|
+
/>
|
|
95
|
+
<DmsCard :padded="false" class="flex flex-col justify-between gap-2 p-4">
|
|
96
|
+
<div class="flex items-center justify-between">
|
|
97
|
+
<span class="font-mono text-[11px] uppercase tracking-wider text-dimmed">
|
|
98
|
+
{{ $t('dms_automation.runs.kpis.avgDuration') }}
|
|
99
|
+
</span>
|
|
100
|
+
<UIcon name="i-ph-clock" class="size-4 text-dimmed" />
|
|
101
|
+
</div>
|
|
102
|
+
<span class="text-2xl font-semibold tabular-nums text-highlighted">
|
|
103
|
+
{{ avgDurationLabel }}
|
|
104
|
+
</span>
|
|
105
|
+
</DmsCard>
|
|
106
|
+
</template>
|
|
107
|
+
<template v-else>
|
|
108
|
+
<DmsCard v-for="i in 4" :key="`skel-${i}`" :padded="false" class="p-5">
|
|
109
|
+
<USkeleton class="h-10 w-full" />
|
|
110
|
+
</DmsCard>
|
|
111
|
+
</template>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</template>
|
|
115
|
+
|
|
116
|
+
<style>
|
|
117
|
+
/* The Runs TableView sits directly under these KPI cards. Drop its native card
|
|
118
|
+
frame (background/border/shadow) so the whole page reads as one flat section;
|
|
119
|
+
the card's inner padding is kept so the table content stays aligned with the
|
|
120
|
+
KPI grid above. Scoped to the runs page via the .runs-stats marker. */
|
|
121
|
+
.dms-page-stack:has(.runs-stats) .dms-card.flow-root {
|
|
122
|
+
background-color: transparent;
|
|
123
|
+
border-color: transparent;
|
|
124
|
+
box-shadow: none;
|
|
125
|
+
}
|
|
126
|
+
</style>
|