|
11 | 11 | v-for="(entry, key) of sortedEntries" |
12 | 12 | :key="key" |
13 | 13 | :journal-entry="entry" |
| 14 | + @click="openEntryDetails(entry)" |
14 | 15 | ></BuilderJournalEntry> |
15 | 16 | </div> |
| 17 | + |
| 18 | + <!-- Drawer for entry details --> |
| 19 | + <WdsDrawer |
| 20 | + v-model="isDrawerOpen" |
| 21 | + title="Execution Details" |
| 22 | + size="large" |
| 23 | + > |
| 24 | + <BuilderJournalEntryDetails |
| 25 | + v-if="selectedEntry" |
| 26 | + :entry="selectedEntry" |
| 27 | + @re-run="handleReRun" |
| 28 | + @go-to-trigger="handleGoToTrigger" |
| 29 | + /> |
| 30 | + </WdsDrawer> |
16 | 31 | </div> |
17 | 32 | </template> |
18 | 33 |
|
19 | 34 | <script setup lang="ts"> |
20 | | -import { computed, inject, onMounted, onActivated, ref } from "vue"; |
| 35 | +import { computed, inject, ref, shallowRef, onActivated, onMounted } from "vue"; |
21 | 36 | import BuilderJournalHeader from "./journal/BuilderJournalHeader.vue"; |
22 | 37 | import BuilderJournalEntry from "./journal/BuilderJournalEntry.vue"; |
| 38 | +import BuilderJournalEntryDetails from "./journal/BuilderJournalEntryDetails.vue"; |
| 39 | +import WdsDrawer from "@/wds/WdsDrawer.vue"; |
23 | 40 | import { convertAbsolutePathtoFullURL } from "@/utils/url"; |
| 41 | +import { downloadJson } from "@/utils/blob"; |
24 | 42 | import { useToasts } from "./useToast"; |
25 | 43 | import { Component, WriterComponentDefinition } from "@/writerTypes"; |
26 | 44 | import injectionKeys from "@/injectionKeys"; |
27 | 45 | import type { JournalFilters } from "./journal/journalTypes"; |
| 46 | +import { useComponentActions } from "./useComponentActions"; |
28 | 47 |
|
29 | 48 | defineOptions({ |
30 | 49 | name: "BuilderJournal", |
31 | 50 | }); |
32 | 51 |
|
33 | 52 | const { pushToast } = useToasts(); |
34 | 53 | const wf = inject(injectionKeys.core); |
| 54 | +const builderManager = inject(injectionKeys.builderManager); |
| 55 | +
|
| 56 | +const { goToComponentParentPage, goToChild } = useComponentActions( |
| 57 | + wf, |
| 58 | + builderManager, |
| 59 | +); |
35 | 60 |
|
36 | 61 | type ComponentInfo = { |
37 | 62 | type: "blueprint" | "block"; |
@@ -72,6 +97,14 @@ const filters = ref<JournalFilters>({ |
72 | 97 | instanceTypes: [], |
73 | 98 | }); |
74 | 99 |
|
| 100 | +const selectedEntry = shallowRef<JournalEntry | null>(null); |
| 101 | +const isDrawerOpen = computed({ |
| 102 | + get: () => !!selectedEntry.value, |
| 103 | + set: (value) => { |
| 104 | + if (!value) selectedEntry.value = null; |
| 105 | + }, |
| 106 | +}); |
| 107 | +
|
75 | 108 | const entries = computed<Record<string, JournalEntry>>(() => { |
76 | 109 | return Object.fromEntries( |
77 | 110 | Object.entries(rawEntries.value).map(([key, entry]) => { |
@@ -185,20 +218,7 @@ const downloadAsJson = () => { |
185 | 218 | return [key, rawEntries.value[key]]; |
186 | 219 | }), |
187 | 220 | ); |
188 | | - const jsonString = JSON.stringify(rawFiltered, null, 2); |
189 | | - const blob = new Blob([jsonString], { type: "application/json" }); |
190 | | -
|
191 | | - const url = URL.createObjectURL(blob); |
192 | | - try { |
193 | | - const a = document.createElement("a"); |
194 | | - a.href = url; |
195 | | - a.download = "agent-journal.json"; |
196 | | - document.body.appendChild(a); |
197 | | - a.click(); |
198 | | - document.body.removeChild(a); |
199 | | - } finally { |
200 | | - window.URL.revokeObjectURL(url); |
201 | | - } |
| 221 | + downloadJson(rawFiltered, "agent-journal.json"); |
202 | 222 | }; |
203 | 223 |
|
204 | 224 | async function deleteEntries() { |
@@ -239,6 +259,34 @@ async function deleteEntries() { |
239 | 259 | rawEntries.value = newRawEntries; |
240 | 260 | } |
241 | 261 |
|
| 262 | +function openEntryDetails(entry: JournalEntry) { |
| 263 | + selectedEntry.value = entry; |
| 264 | +} |
| 265 | +
|
| 266 | +function handleReRun(entry: JournalEntry) { |
| 267 | + // TODO: Implement re-run logic |
| 268 | + // This would trigger the same blueprint/workflow with the same inputs |
| 269 | + pushToast({ |
| 270 | + type: "info", |
| 271 | + message: `Re-run functionality for ${entry.title} will be implemented soon`, |
| 272 | + }); |
| 273 | + // Placeholder for re-run implementation |
| 274 | + // Will trigger the blueprint/workflow execution with entry data |
| 275 | +} |
| 276 | +
|
| 277 | +function handleGoToTrigger(entry: JournalEntry) { |
| 278 | + // Close the drawer |
| 279 | + selectedEntry.value = null; |
| 280 | +
|
| 281 | + // Go to the trigger component |
| 282 | + goToComponentParentPage(entry.trigger.component.id); |
| 283 | + goToChild(entry.trigger.component.id); |
| 284 | + pushToast({ |
| 285 | + type: "success", |
| 286 | + message: `Jumped to ${entry.title}`, |
| 287 | + }); |
| 288 | +} |
| 289 | +
|
242 | 290 | onMounted(() => { |
243 | 291 | loadEntries(); |
244 | 292 | }); |
|
0 commit comments