@thxgg/steward 0.1.13 → 0.1.14
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/.output/nitro.json +1 -1
- package/.output/public/_nuxt/-k8zG74W.js +61 -0
- package/.output/public/_nuxt/B-5VWizU.js +1 -0
- package/.output/public/_nuxt/{Bq6edYSd.js → BDqHART1.js} +1 -1
- package/.output/public/_nuxt/BMAq0QVD.js +42 -0
- package/.output/public/_nuxt/BPeTf9dd.js +1 -0
- package/.output/public/_nuxt/{dOaEkD-3.js → BubpH_wW.js} +1 -1
- package/.output/public/_nuxt/C2HGkiSP.js +1 -0
- package/.output/public/_nuxt/CMu9GKTH.js +4 -0
- package/.output/public/_nuxt/{BZ1iIOYp.js → CVvrkZkq.js} +1 -1
- package/.output/public/_nuxt/C_NevjZD.js +3 -0
- package/.output/public/_nuxt/Detail.CzXXlavD.css +1 -0
- package/.output/public/_nuxt/_prd_.KTotLoF_.css +1 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/b57a8fc3-6a38-4f58-b2ae-54768412ea40.json +1 -0
- package/.output/public/_nuxt/entry.LcDOtJnR.css +1 -0
- package/.output/public/_nuxt/{BFv4l3hn.js → nYTZJhvT.js} +1 -1
- package/.output/public/_nuxt/{kTT8NKtq.js → qKRNa41x.js} +1 -1
- package/.output/public/_nuxt/qt5OEWHC.js +1 -0
- package/.output/public/_nuxt/{C897Egk9.js → uTyw4SRK.js} +1 -1
- package/.output/public/_nuxt/{DoNqd8jQ.js → wbj-mIhK.js} +1 -1
- package/.output/server/chunks/_/task-graph.mjs +196 -0
- package/.output/server/chunks/_/task-graph.mjs.map +1 -0
- package/.output/server/chunks/build/{_prd_-CkKfJB6U.mjs → Detail-DC-KJQ1f.mjs} +911 -1688
- package/.output/server/chunks/build/Detail-DC-KJQ1f.mjs.map +1 -0
- package/.output/server/chunks/build/DiffViewer-styles-1.mjs-D0sb4vsK.mjs +4 -0
- package/.output/server/chunks/build/DiffViewer-styles-1.mjs-D0sb4vsK.mjs.map +1 -0
- package/.output/server/chunks/build/DiffViewer-styles.CkSjCQ0r.mjs +10 -0
- package/.output/server/chunks/build/DiffViewer-styles.CkSjCQ0r.mjs.map +1 -0
- package/.output/server/chunks/build/DiffViewer-styles.FJJuYjYB.mjs +8 -0
- package/.output/server/chunks/build/DiffViewer-styles.FJJuYjYB.mjs.map +1 -0
- package/.output/server/chunks/build/_prd_-C1C4GAhW.mjs +1596 -0
- package/.output/server/chunks/build/_prd_-C1C4GAhW.mjs.map +1 -0
- package/.output/server/chunks/build/client.precomputed.mjs +1 -1
- package/.output/server/chunks/build/{default-B5nw9_Xg.mjs → default-DWCOHHTE.mjs} +32 -20
- package/.output/server/chunks/build/default-DWCOHHTE.mjs.map +1 -0
- package/.output/server/chunks/build/{index-CTpuP9Mj.mjs → index-CckL_NBD.mjs} +2 -2
- package/.output/server/chunks/build/index-CckL_NBD.mjs.map +1 -0
- package/.output/server/chunks/build/{index-D21S97KB.mjs → index-QVeSHT3L.mjs} +3 -3
- package/.output/server/chunks/build/index-QVeSHT3L.mjs.map +1 -0
- package/.output/server/chunks/build/repo-graph-CTEkxiYd.mjs +205 -0
- package/.output/server/chunks/build/repo-graph-CTEkxiYd.mjs.map +1 -0
- package/.output/server/chunks/build/server.mjs +12 -3
- package/.output/server/chunks/build/styles.mjs +2 -2
- package/.output/server/chunks/build/{usePrd-YhvN6Ary.mjs → usePrd-SqcxGyFU.mjs} +20 -2
- package/.output/server/chunks/build/usePrd-SqcxGyFU.mjs.map +1 -0
- package/.output/server/chunks/nitro/nitro.mjs +566 -534
- package/.output/server/chunks/routes/api/repos/_repoId/graph.get.mjs +41 -0
- package/.output/server/chunks/routes/api/repos/_repoId/graph.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/repos/_repoId/prd/_prdSlug/graph.get.mjs +42 -0
- package/.output/server/chunks/routes/api/repos/_repoId/prd/_prdSlug/graph.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/repos/_repoId/prd/_prdSlug/progress.get.mjs +1 -1
- package/.output/server/chunks/routes/api/repos/_repoId/prd/_prdSlug/tasks/_taskId/commits.get.mjs +1 -1
- package/.output/server/chunks/routes/api/repos/_repoId/prd/_prdSlug/tasks.get.mjs +1 -1
- package/.output/server/chunks/routes/api/repos/_repoId/prds.get.mjs +1 -1
- package/.output/server/node_modules/@vue-flow/background/dist/vue-flow-background.mjs +126 -0
- package/.output/server/node_modules/@vue-flow/background/package.json +73 -0
- package/.output/server/node_modules/@vue-flow/controls/dist/vue-flow-controls.mjs +207 -0
- package/.output/server/node_modules/@vue-flow/controls/package.json +77 -0
- package/.output/server/node_modules/@vue-flow/core/dist/vue-flow-core.mjs +10186 -0
- package/.output/server/node_modules/@vue-flow/core/package.json +95 -0
- package/.output/server/package.json +4 -1
- package/dist/app/types/graph.js +1 -0
- package/dist/server/utils/task-graph.js +190 -0
- package/package.json +5 -1
- package/.output/public/_nuxt/BuQdImno.js +0 -1
- package/.output/public/_nuxt/CMUOpExW.js +0 -3
- package/.output/public/_nuxt/DE885CbX.js +0 -1
- package/.output/public/_nuxt/DomrzX-T.js +0 -76
- package/.output/public/_nuxt/R2cvz8mH.js +0 -4
- package/.output/public/_nuxt/_prd_.DYvuV73Q.css +0 -1
- package/.output/public/_nuxt/builds/meta/2ad99048-24f9-4cf6-8622-6c088fe0a244.json +0 -1
- package/.output/public/_nuxt/entry.Dk19PK4d.css +0 -1
- package/.output/server/chunks/build/DiffViewer-styles-1.mjs-ZdBUa15f.mjs +0 -4
- package/.output/server/chunks/build/DiffViewer-styles-1.mjs-ZdBUa15f.mjs.map +0 -1
- package/.output/server/chunks/build/DiffViewer-styles.CoMVrk_N.mjs +0 -8
- package/.output/server/chunks/build/DiffViewer-styles.CoMVrk_N.mjs.map +0 -1
- package/.output/server/chunks/build/DiffViewer-styles.cLfMOdMh.mjs +0 -10
- package/.output/server/chunks/build/DiffViewer-styles.cLfMOdMh.mjs.map +0 -1
- package/.output/server/chunks/build/_prd_-CkKfJB6U.mjs.map +0 -1
- package/.output/server/chunks/build/default-B5nw9_Xg.mjs.map +0 -1
- package/.output/server/chunks/build/index-CTpuP9Mj.mjs.map +0 -1
- package/.output/server/chunks/build/index-D21S97KB.mjs.map +0 -1
- package/.output/server/chunks/build/usePrd-YhvN6Ary.mjs.map +0 -1
|
@@ -0,0 +1,1596 @@
|
|
|
1
|
+
import { _ as __nuxt_component_0$2 } from './nuxt-link-SvT1nf8Z.mjs';
|
|
2
|
+
import { defineComponent, computed, ref, watch, inject, mergeProps, unref, withCtx, createVNode, createTextVNode, isRef, openBlock, createBlock, toDisplayString, createCommentVNode, renderSlot, resolveDynamicComponent, useSSRContext } from 'vue';
|
|
3
|
+
import { ssrRenderAttrs, ssrRenderComponent, ssrInterpolate, ssrRenderAttr, ssrRenderSlot, ssrRenderList, ssrRenderClass, ssrRenderVNode } from 'vue/server-renderer';
|
|
4
|
+
import { Loader2, AlertCircle, RefreshCw, FileText, LayoutGrid, GitBranch, User, Calendar, CircleDot, ExternalLink, Circle, CheckCircle2, PlayCircle, Minus, ArrowDown, ArrowUp } from 'lucide-vue-next';
|
|
5
|
+
import { _ as __nuxt_component_0$2$1, a as __nuxt_component_1$1, B as Badge } from './Detail-DC-KJQ1f.mjs';
|
|
6
|
+
import { marked } from 'marked';
|
|
7
|
+
import { codeToHtml } from 'shiki';
|
|
8
|
+
import DOMPurify from 'dompurify';
|
|
9
|
+
import { u as useRepos, a as usePrd, b as useToast, c as cn } from './usePrd-SqcxGyFU.mjs';
|
|
10
|
+
import { _ as _export_sfc } from './_plugin-vue_export-helper-1tPrXgE0.mjs';
|
|
11
|
+
import { reactiveOmit } from '@vueuse/core';
|
|
12
|
+
import { useForwardPropsEmits, TabsRoot, TabsList as TabsList$1, useForwardProps, TabsTrigger as TabsTrigger$1, TabsContent as TabsContent$1 } from 'reka-ui';
|
|
13
|
+
import { B as Button } from './index-CckL_NBD.mjs';
|
|
14
|
+
import { b as useRoute, a as useRouter } from './server.mjs';
|
|
15
|
+
import '../nitro/nitro.mjs';
|
|
16
|
+
import 'node:http';
|
|
17
|
+
import 'node:https';
|
|
18
|
+
import 'node:events';
|
|
19
|
+
import 'node:buffer';
|
|
20
|
+
import 'node:fs';
|
|
21
|
+
import 'node:path';
|
|
22
|
+
import 'node:crypto';
|
|
23
|
+
import 'node:os';
|
|
24
|
+
import 'node:url';
|
|
25
|
+
import '@vue-flow/background';
|
|
26
|
+
import '@vue-flow/controls';
|
|
27
|
+
import '@vue-flow/core';
|
|
28
|
+
import 'shiki/bundle/web';
|
|
29
|
+
import 'class-variance-authority';
|
|
30
|
+
import 'clsx';
|
|
31
|
+
import 'tailwind-merge';
|
|
32
|
+
import 'vue-sonner';
|
|
33
|
+
import '@vue/shared';
|
|
34
|
+
import 'perfect-debounce';
|
|
35
|
+
import '../routes/renderer.mjs';
|
|
36
|
+
import 'vue-bundle-renderer/runtime';
|
|
37
|
+
import 'unhead/server';
|
|
38
|
+
import 'devalue';
|
|
39
|
+
import 'unhead/utils';
|
|
40
|
+
import 'vue-router';
|
|
41
|
+
|
|
42
|
+
const _sfc_main$g = /* @__PURE__ */ defineComponent({
|
|
43
|
+
__name: "Meta",
|
|
44
|
+
__ssrInlineRender: true,
|
|
45
|
+
props: {
|
|
46
|
+
metadata: {}
|
|
47
|
+
},
|
|
48
|
+
setup(__props) {
|
|
49
|
+
const props = __props;
|
|
50
|
+
const statusVariant = computed(() => {
|
|
51
|
+
const status = props.metadata.status?.toLowerCase();
|
|
52
|
+
if (!status) return "secondary";
|
|
53
|
+
if (status.includes("complete") || status.includes("done")) return "default";
|
|
54
|
+
if (status.includes("progress") || status.includes("active")) return "default";
|
|
55
|
+
if (status.includes("draft")) return "secondary";
|
|
56
|
+
if (status.includes("blocked") || status.includes("paused")) return "destructive";
|
|
57
|
+
return "secondary";
|
|
58
|
+
});
|
|
59
|
+
const hasMetadata = computed(() => {
|
|
60
|
+
return props.metadata.author || props.metadata.date || props.metadata.status || props.metadata.shortcutStory;
|
|
61
|
+
});
|
|
62
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
63
|
+
if (unref(hasMetadata)) {
|
|
64
|
+
_push(`<div${ssrRenderAttrs(mergeProps({ class: "flex flex-wrap items-center gap-3 text-sm" }, _attrs))}>`);
|
|
65
|
+
if (__props.metadata.author) {
|
|
66
|
+
_push(`<div class="flex items-center gap-1.5 text-muted-foreground">`);
|
|
67
|
+
_push(ssrRenderComponent(unref(User), { class: "size-3.5" }, null, _parent));
|
|
68
|
+
_push(`<span>${ssrInterpolate(__props.metadata.author)}</span></div>`);
|
|
69
|
+
} else {
|
|
70
|
+
_push(`<!---->`);
|
|
71
|
+
}
|
|
72
|
+
if (__props.metadata.date) {
|
|
73
|
+
_push(`<div class="flex items-center gap-1.5 text-muted-foreground">`);
|
|
74
|
+
_push(ssrRenderComponent(unref(Calendar), { class: "size-3.5" }, null, _parent));
|
|
75
|
+
_push(`<span>${ssrInterpolate(__props.metadata.date)}</span></div>`);
|
|
76
|
+
} else {
|
|
77
|
+
_push(`<!---->`);
|
|
78
|
+
}
|
|
79
|
+
if (__props.metadata.status) {
|
|
80
|
+
_push(ssrRenderComponent(unref(Badge), {
|
|
81
|
+
variant: unref(statusVariant),
|
|
82
|
+
class: "gap-1"
|
|
83
|
+
}, {
|
|
84
|
+
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
85
|
+
if (_push2) {
|
|
86
|
+
_push2(ssrRenderComponent(unref(CircleDot), { class: "size-3" }, null, _parent2, _scopeId));
|
|
87
|
+
_push2(` ${ssrInterpolate(__props.metadata.status)}`);
|
|
88
|
+
} else {
|
|
89
|
+
return [
|
|
90
|
+
createVNode(unref(CircleDot), { class: "size-3" }),
|
|
91
|
+
createTextVNode(" " + toDisplayString(__props.metadata.status), 1)
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
}),
|
|
95
|
+
_: 1
|
|
96
|
+
}, _parent));
|
|
97
|
+
} else {
|
|
98
|
+
_push(`<!---->`);
|
|
99
|
+
}
|
|
100
|
+
if (__props.metadata.shortcutStory && __props.metadata.shortcutUrl) {
|
|
101
|
+
_push(`<a${ssrRenderAttr("href", __props.metadata.shortcutUrl)} target="_blank" rel="noopener noreferrer" class="inline-flex items-center gap-1.5 text-primary hover:underline">`);
|
|
102
|
+
_push(ssrRenderComponent(unref(ExternalLink), { class: "size-3.5" }, null, _parent));
|
|
103
|
+
_push(`<span>${ssrInterpolate(__props.metadata.shortcutStory)}</span></a>`);
|
|
104
|
+
} else if (__props.metadata.shortcutStory) {
|
|
105
|
+
_push(`<span class="flex items-center gap-1.5 text-muted-foreground">`);
|
|
106
|
+
_push(ssrRenderComponent(unref(ExternalLink), { class: "size-3.5" }, null, _parent));
|
|
107
|
+
_push(`<span>${ssrInterpolate(__props.metadata.shortcutStory)}</span></span>`);
|
|
108
|
+
} else {
|
|
109
|
+
_push(`<!---->`);
|
|
110
|
+
}
|
|
111
|
+
_push(`</div>`);
|
|
112
|
+
} else {
|
|
113
|
+
_push(`<!---->`);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const _sfc_setup$g = _sfc_main$g.setup;
|
|
119
|
+
_sfc_main$g.setup = (props, ctx) => {
|
|
120
|
+
const ssrContext = useSSRContext();
|
|
121
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/prd/Meta.vue");
|
|
122
|
+
return _sfc_setup$g ? _sfc_setup$g(props, ctx) : void 0;
|
|
123
|
+
};
|
|
124
|
+
const __nuxt_component_1 = Object.assign(_sfc_main$g, { __name: "PrdMeta" });
|
|
125
|
+
const _sfc_main$f = /* @__PURE__ */ defineComponent({
|
|
126
|
+
__name: "Viewer",
|
|
127
|
+
__ssrInlineRender: true,
|
|
128
|
+
props: {
|
|
129
|
+
content: {}
|
|
130
|
+
},
|
|
131
|
+
setup(__props) {
|
|
132
|
+
const props = __props;
|
|
133
|
+
const renderedHtml = ref("");
|
|
134
|
+
const isLoading = ref(true);
|
|
135
|
+
const purifyConfig = {
|
|
136
|
+
ADD_TAGS: ["style"],
|
|
137
|
+
ADD_ATTR: ["style", "class", "target", "rel"]
|
|
138
|
+
};
|
|
139
|
+
const renderer = new marked.Renderer();
|
|
140
|
+
renderer.link = ({ href, title, text }) => {
|
|
141
|
+
const titleAttr = title ? ` title="${title}"` : "";
|
|
142
|
+
return `<a href="${href}"${titleAttr} target="_blank" rel="noopener noreferrer">${text}</a>`;
|
|
143
|
+
};
|
|
144
|
+
async function highlightCode(code, lang) {
|
|
145
|
+
try {
|
|
146
|
+
return await codeToHtml(code, {
|
|
147
|
+
lang: lang || "text",
|
|
148
|
+
themes: {
|
|
149
|
+
light: "github-light",
|
|
150
|
+
dark: "github-dark"
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
} catch {
|
|
154
|
+
return `<pre><code class="language-${lang}">${escapeHtml(code)}</code></pre>`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function escapeHtml(text) {
|
|
158
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
159
|
+
}
|
|
160
|
+
async function renderMarkdown(content) {
|
|
161
|
+
const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g;
|
|
162
|
+
const placeholders = [];
|
|
163
|
+
let placeholderIndex = 0;
|
|
164
|
+
const contentWithPlaceholders = content.replace(codeBlockRegex, (_, lang, code) => {
|
|
165
|
+
const placeholder = `CODEBLOCK${placeholderIndex++}PLACEHOLDER`;
|
|
166
|
+
placeholders.push({ placeholder, lang: lang || "text", code: code.trim() });
|
|
167
|
+
return placeholder;
|
|
168
|
+
});
|
|
169
|
+
marked.setOptions({
|
|
170
|
+
renderer,
|
|
171
|
+
gfm: true,
|
|
172
|
+
breaks: true
|
|
173
|
+
});
|
|
174
|
+
let html = await marked.parse(contentWithPlaceholders);
|
|
175
|
+
const highlightPromises = placeholders.map(async ({ placeholder, lang, code }) => {
|
|
176
|
+
const highlighted = await highlightCode(code, lang);
|
|
177
|
+
return { placeholder, highlighted };
|
|
178
|
+
});
|
|
179
|
+
const results = await Promise.all(highlightPromises);
|
|
180
|
+
for (const { placeholder, highlighted } of results) {
|
|
181
|
+
html = html.replace(`<p>${placeholder}</p>`, highlighted);
|
|
182
|
+
html = html.replace(placeholder, highlighted);
|
|
183
|
+
}
|
|
184
|
+
return DOMPurify.sanitize(html, purifyConfig);
|
|
185
|
+
}
|
|
186
|
+
watch(() => props.content, async (newContent) => {
|
|
187
|
+
if (newContent) {
|
|
188
|
+
isLoading.value = true;
|
|
189
|
+
try {
|
|
190
|
+
renderedHtml.value = await renderMarkdown(newContent);
|
|
191
|
+
} finally {
|
|
192
|
+
isLoading.value = false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}, { immediate: true });
|
|
196
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
197
|
+
_push(`<div${ssrRenderAttrs(mergeProps({ class: "prd-viewer" }, _attrs))}>`);
|
|
198
|
+
if (unref(isLoading)) {
|
|
199
|
+
_push(`<div class="flex items-center justify-center py-8"><div class="size-6 animate-spin rounded-full border-2 border-primary border-t-transparent"></div></div>`);
|
|
200
|
+
} else {
|
|
201
|
+
_push(`<div class="prose prose-sm dark:prose-invert max-w-none">${unref(renderedHtml) ?? ""}</div>`);
|
|
202
|
+
}
|
|
203
|
+
_push(`</div>`);
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
const _sfc_setup$f = _sfc_main$f.setup;
|
|
208
|
+
_sfc_main$f.setup = (props, ctx) => {
|
|
209
|
+
const ssrContext = useSSRContext();
|
|
210
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/prd/Viewer.vue");
|
|
211
|
+
return _sfc_setup$f ? _sfc_setup$f(props, ctx) : void 0;
|
|
212
|
+
};
|
|
213
|
+
const __nuxt_component_2 = Object.assign(_sfc_main$f, { __name: "PrdViewer" });
|
|
214
|
+
const _sfc_main$e = /* @__PURE__ */ defineComponent({
|
|
215
|
+
__name: "Card",
|
|
216
|
+
__ssrInlineRender: true,
|
|
217
|
+
props: {
|
|
218
|
+
class: {}
|
|
219
|
+
},
|
|
220
|
+
setup(__props) {
|
|
221
|
+
const props = __props;
|
|
222
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
223
|
+
_push(`<div${ssrRenderAttrs(mergeProps({
|
|
224
|
+
"data-slot": "card",
|
|
225
|
+
class: unref(cn)(
|
|
226
|
+
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
|
227
|
+
props.class
|
|
228
|
+
)
|
|
229
|
+
}, _attrs))}>`);
|
|
230
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent);
|
|
231
|
+
_push(`</div>`);
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
const _sfc_setup$e = _sfc_main$e.setup;
|
|
236
|
+
_sfc_main$e.setup = (props, ctx) => {
|
|
237
|
+
const ssrContext = useSSRContext();
|
|
238
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/card/Card.vue");
|
|
239
|
+
return _sfc_setup$e ? _sfc_setup$e(props, ctx) : void 0;
|
|
240
|
+
};
|
|
241
|
+
const Card = Object.assign(_sfc_main$e, { __name: "UiCard" });
|
|
242
|
+
const _sfc_main$d = /* @__PURE__ */ defineComponent({
|
|
243
|
+
__name: "CardAction",
|
|
244
|
+
__ssrInlineRender: true,
|
|
245
|
+
props: {
|
|
246
|
+
class: {}
|
|
247
|
+
},
|
|
248
|
+
setup(__props) {
|
|
249
|
+
const props = __props;
|
|
250
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
251
|
+
_push(`<div${ssrRenderAttrs(mergeProps({
|
|
252
|
+
"data-slot": "card-action",
|
|
253
|
+
class: unref(cn)("col-start-2 row-span-2 row-start-1 self-start justify-self-end", props.class)
|
|
254
|
+
}, _attrs))}>`);
|
|
255
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent);
|
|
256
|
+
_push(`</div>`);
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
const _sfc_setup$d = _sfc_main$d.setup;
|
|
261
|
+
_sfc_main$d.setup = (props, ctx) => {
|
|
262
|
+
const ssrContext = useSSRContext();
|
|
263
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/card/CardAction.vue");
|
|
264
|
+
return _sfc_setup$d ? _sfc_setup$d(props, ctx) : void 0;
|
|
265
|
+
};
|
|
266
|
+
Object.assign(_sfc_main$d, { __name: "UiCardAction" });
|
|
267
|
+
const _sfc_main$c = /* @__PURE__ */ defineComponent({
|
|
268
|
+
__name: "CardContent",
|
|
269
|
+
__ssrInlineRender: true,
|
|
270
|
+
props: {
|
|
271
|
+
class: {}
|
|
272
|
+
},
|
|
273
|
+
setup(__props) {
|
|
274
|
+
const props = __props;
|
|
275
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
276
|
+
_push(`<div${ssrRenderAttrs(mergeProps({
|
|
277
|
+
"data-slot": "card-content",
|
|
278
|
+
class: unref(cn)("px-6", props.class)
|
|
279
|
+
}, _attrs))}>`);
|
|
280
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent);
|
|
281
|
+
_push(`</div>`);
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
const _sfc_setup$c = _sfc_main$c.setup;
|
|
286
|
+
_sfc_main$c.setup = (props, ctx) => {
|
|
287
|
+
const ssrContext = useSSRContext();
|
|
288
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/card/CardContent.vue");
|
|
289
|
+
return _sfc_setup$c ? _sfc_setup$c(props, ctx) : void 0;
|
|
290
|
+
};
|
|
291
|
+
const CardContent = Object.assign(_sfc_main$c, { __name: "UiCardContent" });
|
|
292
|
+
const _sfc_main$b = /* @__PURE__ */ defineComponent({
|
|
293
|
+
__name: "CardDescription",
|
|
294
|
+
__ssrInlineRender: true,
|
|
295
|
+
props: {
|
|
296
|
+
class: {}
|
|
297
|
+
},
|
|
298
|
+
setup(__props) {
|
|
299
|
+
const props = __props;
|
|
300
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
301
|
+
_push(`<p${ssrRenderAttrs(mergeProps({
|
|
302
|
+
"data-slot": "card-description",
|
|
303
|
+
class: unref(cn)("text-muted-foreground text-sm", props.class)
|
|
304
|
+
}, _attrs))}>`);
|
|
305
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent);
|
|
306
|
+
_push(`</p>`);
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
const _sfc_setup$b = _sfc_main$b.setup;
|
|
311
|
+
_sfc_main$b.setup = (props, ctx) => {
|
|
312
|
+
const ssrContext = useSSRContext();
|
|
313
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/card/CardDescription.vue");
|
|
314
|
+
return _sfc_setup$b ? _sfc_setup$b(props, ctx) : void 0;
|
|
315
|
+
};
|
|
316
|
+
Object.assign(_sfc_main$b, { __name: "UiCardDescription" });
|
|
317
|
+
const _sfc_main$a = /* @__PURE__ */ defineComponent({
|
|
318
|
+
__name: "CardFooter",
|
|
319
|
+
__ssrInlineRender: true,
|
|
320
|
+
props: {
|
|
321
|
+
class: {}
|
|
322
|
+
},
|
|
323
|
+
setup(__props) {
|
|
324
|
+
const props = __props;
|
|
325
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
326
|
+
_push(`<div${ssrRenderAttrs(mergeProps({
|
|
327
|
+
"data-slot": "card-footer",
|
|
328
|
+
class: unref(cn)("flex items-center px-6 [.border-t]:pt-6", props.class)
|
|
329
|
+
}, _attrs))}>`);
|
|
330
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent);
|
|
331
|
+
_push(`</div>`);
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
const _sfc_setup$a = _sfc_main$a.setup;
|
|
336
|
+
_sfc_main$a.setup = (props, ctx) => {
|
|
337
|
+
const ssrContext = useSSRContext();
|
|
338
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/card/CardFooter.vue");
|
|
339
|
+
return _sfc_setup$a ? _sfc_setup$a(props, ctx) : void 0;
|
|
340
|
+
};
|
|
341
|
+
Object.assign(_sfc_main$a, { __name: "UiCardFooter" });
|
|
342
|
+
const _sfc_main$9 = /* @__PURE__ */ defineComponent({
|
|
343
|
+
__name: "CardHeader",
|
|
344
|
+
__ssrInlineRender: true,
|
|
345
|
+
props: {
|
|
346
|
+
class: {}
|
|
347
|
+
},
|
|
348
|
+
setup(__props) {
|
|
349
|
+
const props = __props;
|
|
350
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
351
|
+
_push(`<div${ssrRenderAttrs(mergeProps({
|
|
352
|
+
"data-slot": "card-header",
|
|
353
|
+
class: unref(cn)("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", props.class)
|
|
354
|
+
}, _attrs))}>`);
|
|
355
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent);
|
|
356
|
+
_push(`</div>`);
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
const _sfc_setup$9 = _sfc_main$9.setup;
|
|
361
|
+
_sfc_main$9.setup = (props, ctx) => {
|
|
362
|
+
const ssrContext = useSSRContext();
|
|
363
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/card/CardHeader.vue");
|
|
364
|
+
return _sfc_setup$9 ? _sfc_setup$9(props, ctx) : void 0;
|
|
365
|
+
};
|
|
366
|
+
Object.assign(_sfc_main$9, { __name: "UiCardHeader" });
|
|
367
|
+
const _sfc_main$8 = /* @__PURE__ */ defineComponent({
|
|
368
|
+
__name: "CardTitle",
|
|
369
|
+
__ssrInlineRender: true,
|
|
370
|
+
props: {
|
|
371
|
+
class: {}
|
|
372
|
+
},
|
|
373
|
+
setup(__props) {
|
|
374
|
+
const props = __props;
|
|
375
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
376
|
+
_push(`<h3${ssrRenderAttrs(mergeProps({
|
|
377
|
+
"data-slot": "card-title",
|
|
378
|
+
class: unref(cn)("leading-none font-semibold", props.class)
|
|
379
|
+
}, _attrs))}>`);
|
|
380
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push, _parent);
|
|
381
|
+
_push(`</h3>`);
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
const _sfc_setup$8 = _sfc_main$8.setup;
|
|
386
|
+
_sfc_main$8.setup = (props, ctx) => {
|
|
387
|
+
const ssrContext = useSSRContext();
|
|
388
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/card/CardTitle.vue");
|
|
389
|
+
return _sfc_setup$8 ? _sfc_setup$8(props, ctx) : void 0;
|
|
390
|
+
};
|
|
391
|
+
Object.assign(_sfc_main$8, { __name: "UiCardTitle" });
|
|
392
|
+
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
|
|
393
|
+
__name: "Card",
|
|
394
|
+
__ssrInlineRender: true,
|
|
395
|
+
props: {
|
|
396
|
+
task: {},
|
|
397
|
+
blockedBy: {}
|
|
398
|
+
},
|
|
399
|
+
emits: ["click"],
|
|
400
|
+
setup(__props, { emit: __emit }) {
|
|
401
|
+
const props = __props;
|
|
402
|
+
const emit = __emit;
|
|
403
|
+
const categoryConfig = computed(() => {
|
|
404
|
+
switch (props.task.category) {
|
|
405
|
+
case "setup":
|
|
406
|
+
return { label: "Setup", variant: "secondary" };
|
|
407
|
+
case "feature":
|
|
408
|
+
return { label: "Feature", variant: "default" };
|
|
409
|
+
case "integration":
|
|
410
|
+
return { label: "Integration", variant: "outline" };
|
|
411
|
+
case "testing":
|
|
412
|
+
return { label: "Testing", variant: "secondary" };
|
|
413
|
+
case "documentation":
|
|
414
|
+
return { label: "Docs", variant: "secondary" };
|
|
415
|
+
default:
|
|
416
|
+
return { label: props.task.category, variant: "secondary" };
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
const priorityConfig = computed(() => {
|
|
420
|
+
switch (props.task.priority) {
|
|
421
|
+
case "critical":
|
|
422
|
+
return { icon: ArrowUp, class: "text-destructive", label: "Critical" };
|
|
423
|
+
case "high":
|
|
424
|
+
return { icon: ArrowUp, class: "text-orange-500", label: "High" };
|
|
425
|
+
case "medium":
|
|
426
|
+
return { icon: Minus, class: "text-muted-foreground", label: "Medium" };
|
|
427
|
+
case "low":
|
|
428
|
+
return { icon: ArrowDown, class: "text-muted-foreground", label: "Low" };
|
|
429
|
+
default:
|
|
430
|
+
return { icon: Minus, class: "text-muted-foreground", label: "Unknown" };
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
const isBlocked = computed(() => {
|
|
434
|
+
return props.blockedBy && props.blockedBy.length > 0;
|
|
435
|
+
});
|
|
436
|
+
const taskNumber = computed(() => {
|
|
437
|
+
const match = props.task.id.match(/(\d+)$/);
|
|
438
|
+
const value = match?.[1];
|
|
439
|
+
return value ? parseInt(value, 10) : 0;
|
|
440
|
+
});
|
|
441
|
+
const blockedCount = computed(() => {
|
|
442
|
+
return props.blockedBy?.length ?? 0;
|
|
443
|
+
});
|
|
444
|
+
function handleClick() {
|
|
445
|
+
emit("click", props.task);
|
|
446
|
+
}
|
|
447
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
448
|
+
_push(ssrRenderComponent(unref(Card), mergeProps({
|
|
449
|
+
class: ["cursor-pointer py-0 gap-0 transition-all hover:shadow-md hover:border-primary/50", { "opacity-60": unref(isBlocked) }],
|
|
450
|
+
onClick: handleClick
|
|
451
|
+
}, _attrs), {
|
|
452
|
+
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
453
|
+
if (_push2) {
|
|
454
|
+
_push2(ssrRenderComponent(unref(CardContent), { class: "p-2.5" }, {
|
|
455
|
+
default: withCtx((_2, _push3, _parent3, _scopeId2) => {
|
|
456
|
+
if (_push3) {
|
|
457
|
+
_push3(`<div class="flex items-center justify-between gap-2 mb-1.5"${_scopeId2}>`);
|
|
458
|
+
_push3(ssrRenderComponent(unref(Badge), {
|
|
459
|
+
variant: unref(categoryConfig).variant,
|
|
460
|
+
class: "text-xs"
|
|
461
|
+
}, {
|
|
462
|
+
default: withCtx((_3, _push4, _parent4, _scopeId3) => {
|
|
463
|
+
if (_push4) {
|
|
464
|
+
_push4(`${ssrInterpolate(unref(categoryConfig).label)}`);
|
|
465
|
+
} else {
|
|
466
|
+
return [
|
|
467
|
+
createTextVNode(toDisplayString(unref(categoryConfig).label), 1)
|
|
468
|
+
];
|
|
469
|
+
}
|
|
470
|
+
}),
|
|
471
|
+
_: 1
|
|
472
|
+
}, _parent3, _scopeId2));
|
|
473
|
+
ssrRenderVNode(_push3, createVNode(resolveDynamicComponent(unref(priorityConfig).icon), {
|
|
474
|
+
class: ["size-4", unref(priorityConfig).class],
|
|
475
|
+
title: unref(priorityConfig).label
|
|
476
|
+
}, null), _parent3, _scopeId2);
|
|
477
|
+
_push3(`</div><h4 class="text-sm font-medium leading-snug"${_scopeId2}><span class="text-muted-foreground"${_scopeId2}>#${ssrInterpolate(unref(taskNumber))}</span> ${ssrInterpolate(__props.task.title)}</h4>`);
|
|
478
|
+
if (unref(isBlocked)) {
|
|
479
|
+
_push3(`<div class="mt-2 flex items-center gap-1.5 text-xs text-destructive"${_scopeId2}>`);
|
|
480
|
+
_push3(ssrRenderComponent(unref(AlertCircle), { class: "size-3.5" }, null, _parent3, _scopeId2));
|
|
481
|
+
_push3(`<span${_scopeId2}>Blocked by ${ssrInterpolate(unref(blockedCount))} task${ssrInterpolate(unref(blockedCount) === 1 ? "" : "s")}</span></div>`);
|
|
482
|
+
} else {
|
|
483
|
+
_push3(`<!---->`);
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
return [
|
|
487
|
+
createVNode("div", { class: "flex items-center justify-between gap-2 mb-1.5" }, [
|
|
488
|
+
createVNode(unref(Badge), {
|
|
489
|
+
variant: unref(categoryConfig).variant,
|
|
490
|
+
class: "text-xs"
|
|
491
|
+
}, {
|
|
492
|
+
default: withCtx(() => [
|
|
493
|
+
createTextVNode(toDisplayString(unref(categoryConfig).label), 1)
|
|
494
|
+
]),
|
|
495
|
+
_: 1
|
|
496
|
+
}, 8, ["variant"]),
|
|
497
|
+
(openBlock(), createBlock(resolveDynamicComponent(unref(priorityConfig).icon), {
|
|
498
|
+
class: ["size-4", unref(priorityConfig).class],
|
|
499
|
+
title: unref(priorityConfig).label
|
|
500
|
+
}, null, 8, ["class", "title"]))
|
|
501
|
+
]),
|
|
502
|
+
createVNode("h4", { class: "text-sm font-medium leading-snug" }, [
|
|
503
|
+
createVNode("span", { class: "text-muted-foreground" }, "#" + toDisplayString(unref(taskNumber)), 1),
|
|
504
|
+
createTextVNode(" " + toDisplayString(__props.task.title), 1)
|
|
505
|
+
]),
|
|
506
|
+
unref(isBlocked) ? (openBlock(), createBlock("div", {
|
|
507
|
+
key: 0,
|
|
508
|
+
class: "mt-2 flex items-center gap-1.5 text-xs text-destructive"
|
|
509
|
+
}, [
|
|
510
|
+
createVNode(unref(AlertCircle), { class: "size-3.5" }),
|
|
511
|
+
createVNode("span", null, "Blocked by " + toDisplayString(unref(blockedCount)) + " task" + toDisplayString(unref(blockedCount) === 1 ? "" : "s"), 1)
|
|
512
|
+
])) : createCommentVNode("", true)
|
|
513
|
+
];
|
|
514
|
+
}
|
|
515
|
+
}),
|
|
516
|
+
_: 1
|
|
517
|
+
}, _parent2, _scopeId));
|
|
518
|
+
} else {
|
|
519
|
+
return [
|
|
520
|
+
createVNode(unref(CardContent), { class: "p-2.5" }, {
|
|
521
|
+
default: withCtx(() => [
|
|
522
|
+
createVNode("div", { class: "flex items-center justify-between gap-2 mb-1.5" }, [
|
|
523
|
+
createVNode(unref(Badge), {
|
|
524
|
+
variant: unref(categoryConfig).variant,
|
|
525
|
+
class: "text-xs"
|
|
526
|
+
}, {
|
|
527
|
+
default: withCtx(() => [
|
|
528
|
+
createTextVNode(toDisplayString(unref(categoryConfig).label), 1)
|
|
529
|
+
]),
|
|
530
|
+
_: 1
|
|
531
|
+
}, 8, ["variant"]),
|
|
532
|
+
(openBlock(), createBlock(resolveDynamicComponent(unref(priorityConfig).icon), {
|
|
533
|
+
class: ["size-4", unref(priorityConfig).class],
|
|
534
|
+
title: unref(priorityConfig).label
|
|
535
|
+
}, null, 8, ["class", "title"]))
|
|
536
|
+
]),
|
|
537
|
+
createVNode("h4", { class: "text-sm font-medium leading-snug" }, [
|
|
538
|
+
createVNode("span", { class: "text-muted-foreground" }, "#" + toDisplayString(unref(taskNumber)), 1),
|
|
539
|
+
createTextVNode(" " + toDisplayString(__props.task.title), 1)
|
|
540
|
+
]),
|
|
541
|
+
unref(isBlocked) ? (openBlock(), createBlock("div", {
|
|
542
|
+
key: 0,
|
|
543
|
+
class: "mt-2 flex items-center gap-1.5 text-xs text-destructive"
|
|
544
|
+
}, [
|
|
545
|
+
createVNode(unref(AlertCircle), { class: "size-3.5" }),
|
|
546
|
+
createVNode("span", null, "Blocked by " + toDisplayString(unref(blockedCount)) + " task" + toDisplayString(unref(blockedCount) === 1 ? "" : "s"), 1)
|
|
547
|
+
])) : createCommentVNode("", true)
|
|
548
|
+
]),
|
|
549
|
+
_: 1
|
|
550
|
+
})
|
|
551
|
+
];
|
|
552
|
+
}
|
|
553
|
+
}),
|
|
554
|
+
_: 1
|
|
555
|
+
}, _parent));
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
const _sfc_setup$7 = _sfc_main$7.setup;
|
|
560
|
+
_sfc_main$7.setup = (props, ctx) => {
|
|
561
|
+
const ssrContext = useSSRContext();
|
|
562
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/tasks/Card.vue");
|
|
563
|
+
return _sfc_setup$7 ? _sfc_setup$7(props, ctx) : void 0;
|
|
564
|
+
};
|
|
565
|
+
const __nuxt_component_0$1 = Object.assign(_sfc_main$7, { __name: "TasksCard" });
|
|
566
|
+
const _sfc_main$6 = /* @__PURE__ */ defineComponent({
|
|
567
|
+
__name: "Column",
|
|
568
|
+
__ssrInlineRender: true,
|
|
569
|
+
props: {
|
|
570
|
+
status: {},
|
|
571
|
+
tasks: {},
|
|
572
|
+
blockedByMap: {}
|
|
573
|
+
},
|
|
574
|
+
emits: ["taskClick"],
|
|
575
|
+
setup(__props, { emit: __emit }) {
|
|
576
|
+
const props = __props;
|
|
577
|
+
const emit = __emit;
|
|
578
|
+
const statusConfig = computed(() => {
|
|
579
|
+
switch (props.status) {
|
|
580
|
+
case "pending":
|
|
581
|
+
return {
|
|
582
|
+
label: "Pending",
|
|
583
|
+
icon: Circle,
|
|
584
|
+
headerClass: "bg-muted/50",
|
|
585
|
+
iconClass: "text-muted-foreground"
|
|
586
|
+
};
|
|
587
|
+
case "in_progress":
|
|
588
|
+
return {
|
|
589
|
+
label: "In Progress",
|
|
590
|
+
icon: PlayCircle,
|
|
591
|
+
headerClass: "bg-blue-500/10",
|
|
592
|
+
iconClass: "text-blue-500"
|
|
593
|
+
};
|
|
594
|
+
case "completed":
|
|
595
|
+
return {
|
|
596
|
+
label: "Completed",
|
|
597
|
+
icon: CheckCircle2,
|
|
598
|
+
headerClass: "bg-green-500/10",
|
|
599
|
+
iconClass: "text-green-500"
|
|
600
|
+
};
|
|
601
|
+
default:
|
|
602
|
+
return {
|
|
603
|
+
label: props.status,
|
|
604
|
+
icon: Circle,
|
|
605
|
+
headerClass: "bg-muted/50",
|
|
606
|
+
iconClass: "text-muted-foreground"
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
function getBlockedBy(taskId) {
|
|
611
|
+
return props.blockedByMap?.get(taskId) ?? [];
|
|
612
|
+
}
|
|
613
|
+
function handleTaskClick(task) {
|
|
614
|
+
emit("taskClick", task);
|
|
615
|
+
}
|
|
616
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
617
|
+
const _component_TasksCard = __nuxt_component_0$1;
|
|
618
|
+
_push(`<div${ssrRenderAttrs(mergeProps({ class: "flex h-full min-w-56 flex-1 flex-col overflow-hidden rounded-lg border border-border bg-card" }, _attrs))} data-v-a1317eba><div class="${ssrRenderClass([unref(statusConfig).headerClass, "flex items-center gap-2 rounded-t-lg border-b border-border px-3 py-2"])}" data-v-a1317eba>`);
|
|
619
|
+
ssrRenderVNode(_push, createVNode(resolveDynamicComponent(unref(statusConfig).icon), {
|
|
620
|
+
class: ["size-4", unref(statusConfig).iconClass]
|
|
621
|
+
}, null), _parent);
|
|
622
|
+
_push(`<h3 class="text-sm font-medium" data-v-a1317eba>${ssrInterpolate(unref(statusConfig).label)}</h3><span class="ml-auto text-xs text-muted-foreground" data-v-a1317eba>${ssrInterpolate(__props.tasks.length)}</span></div><div class="scrollbar-hide min-h-0 flex-1 overflow-y-auto p-1.5" data-v-a1317eba><div class="space-y-1.5" data-v-a1317eba><!--[-->`);
|
|
623
|
+
ssrRenderList(__props.tasks, (task) => {
|
|
624
|
+
_push(ssrRenderComponent(_component_TasksCard, {
|
|
625
|
+
key: task.id,
|
|
626
|
+
task,
|
|
627
|
+
"blocked-by": getBlockedBy(task.id),
|
|
628
|
+
onClick: handleTaskClick
|
|
629
|
+
}, null, _parent));
|
|
630
|
+
});
|
|
631
|
+
_push(`<!--]-->`);
|
|
632
|
+
if (__props.tasks.length === 0) {
|
|
633
|
+
_push(`<div class="py-8 text-center text-sm text-muted-foreground" data-v-a1317eba> No tasks </div>`);
|
|
634
|
+
} else {
|
|
635
|
+
_push(`<!---->`);
|
|
636
|
+
}
|
|
637
|
+
_push(`</div></div></div>`);
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
const _sfc_setup$6 = _sfc_main$6.setup;
|
|
642
|
+
_sfc_main$6.setup = (props, ctx) => {
|
|
643
|
+
const ssrContext = useSSRContext();
|
|
644
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/tasks/Column.vue");
|
|
645
|
+
return _sfc_setup$6 ? _sfc_setup$6(props, ctx) : void 0;
|
|
646
|
+
};
|
|
647
|
+
const __nuxt_component_0 = /* @__PURE__ */ Object.assign(_export_sfc(_sfc_main$6, [["__scopeId", "data-v-a1317eba"]]), { __name: "TasksColumn" });
|
|
648
|
+
const _sfc_main$5 = /* @__PURE__ */ defineComponent({
|
|
649
|
+
__name: "Board",
|
|
650
|
+
__ssrInlineRender: true,
|
|
651
|
+
props: {
|
|
652
|
+
tasks: {}
|
|
653
|
+
},
|
|
654
|
+
emits: ["taskClick"],
|
|
655
|
+
setup(__props, { emit: __emit }) {
|
|
656
|
+
const props = __props;
|
|
657
|
+
const emit = __emit;
|
|
658
|
+
function getTaskNumber(task) {
|
|
659
|
+
const match = task.id.match(/(\d+)$/);
|
|
660
|
+
const value = match?.[1];
|
|
661
|
+
return value ? parseInt(value, 10) : 0;
|
|
662
|
+
}
|
|
663
|
+
const pendingTasks = computed(
|
|
664
|
+
() => props.tasks.filter((t) => t.status === "pending").sort((a, b) => getTaskNumber(a) - getTaskNumber(b))
|
|
665
|
+
);
|
|
666
|
+
const inProgressTasks = computed(
|
|
667
|
+
() => props.tasks.filter((t) => t.status === "in_progress").sort((a, b) => getTaskNumber(a) - getTaskNumber(b))
|
|
668
|
+
);
|
|
669
|
+
const completedTasks = computed(
|
|
670
|
+
() => props.tasks.filter((t) => t.status === "completed").sort((a, b) => {
|
|
671
|
+
const aTime = a.completedAt ? new Date(a.completedAt).getTime() : 0;
|
|
672
|
+
const bTime = b.completedAt ? new Date(b.completedAt).getTime() : 0;
|
|
673
|
+
return bTime - aTime;
|
|
674
|
+
})
|
|
675
|
+
);
|
|
676
|
+
const blockedByMap = computed(() => {
|
|
677
|
+
const map = /* @__PURE__ */ new Map();
|
|
678
|
+
const completedIds = new Set(completedTasks.value.map((t) => t.id));
|
|
679
|
+
for (const task of props.tasks) {
|
|
680
|
+
if (task.dependencies.length > 0) {
|
|
681
|
+
const blockers = task.dependencies.filter((depId) => !completedIds.has(depId));
|
|
682
|
+
if (blockers.length > 0) {
|
|
683
|
+
map.set(task.id, blockers);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return map;
|
|
688
|
+
});
|
|
689
|
+
const columns = [
|
|
690
|
+
{ status: "pending", tasks: pendingTasks },
|
|
691
|
+
{ status: "in_progress", tasks: inProgressTasks },
|
|
692
|
+
{ status: "completed", tasks: completedTasks }
|
|
693
|
+
];
|
|
694
|
+
function handleTaskClick(task) {
|
|
695
|
+
emit("taskClick", task);
|
|
696
|
+
}
|
|
697
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
698
|
+
const _component_TasksColumn = __nuxt_component_0;
|
|
699
|
+
_push(`<div${ssrRenderAttrs(mergeProps({ class: "flex h-full gap-3 overflow-x-auto pb-2" }, _attrs))}><!--[-->`);
|
|
700
|
+
ssrRenderList(columns, (column) => {
|
|
701
|
+
_push(ssrRenderComponent(_component_TasksColumn, {
|
|
702
|
+
key: column.status,
|
|
703
|
+
status: column.status,
|
|
704
|
+
tasks: column.tasks.value,
|
|
705
|
+
"blocked-by-map": unref(blockedByMap),
|
|
706
|
+
onTaskClick: handleTaskClick
|
|
707
|
+
}, null, _parent));
|
|
708
|
+
});
|
|
709
|
+
_push(`<!--]--></div>`);
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
const _sfc_setup$5 = _sfc_main$5.setup;
|
|
714
|
+
_sfc_main$5.setup = (props, ctx) => {
|
|
715
|
+
const ssrContext = useSSRContext();
|
|
716
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/tasks/Board.vue");
|
|
717
|
+
return _sfc_setup$5 ? _sfc_setup$5(props, ctx) : void 0;
|
|
718
|
+
};
|
|
719
|
+
const __nuxt_component_3 = Object.assign(_sfc_main$5, { __name: "TasksBoard" });
|
|
720
|
+
const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|
721
|
+
__name: "Tabs",
|
|
722
|
+
__ssrInlineRender: true,
|
|
723
|
+
props: {
|
|
724
|
+
defaultValue: {},
|
|
725
|
+
orientation: {},
|
|
726
|
+
dir: {},
|
|
727
|
+
activationMode: {},
|
|
728
|
+
modelValue: {},
|
|
729
|
+
unmountOnHide: { type: Boolean },
|
|
730
|
+
asChild: { type: Boolean },
|
|
731
|
+
as: {},
|
|
732
|
+
class: {}
|
|
733
|
+
},
|
|
734
|
+
emits: ["update:modelValue"],
|
|
735
|
+
setup(__props, { emit: __emit }) {
|
|
736
|
+
const props = __props;
|
|
737
|
+
const emits = __emit;
|
|
738
|
+
const delegatedProps = reactiveOmit(props, "class");
|
|
739
|
+
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
740
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
741
|
+
_push(ssrRenderComponent(unref(TabsRoot), mergeProps({ "data-slot": "tabs" }, unref(forwarded), {
|
|
742
|
+
class: unref(cn)("flex flex-col gap-2", props.class)
|
|
743
|
+
}, _attrs), {
|
|
744
|
+
default: withCtx((slotProps, _push2, _parent2, _scopeId) => {
|
|
745
|
+
if (_push2) {
|
|
746
|
+
ssrRenderSlot(_ctx.$slots, "default", slotProps, null, _push2, _parent2, _scopeId);
|
|
747
|
+
} else {
|
|
748
|
+
return [
|
|
749
|
+
renderSlot(_ctx.$slots, "default", slotProps)
|
|
750
|
+
];
|
|
751
|
+
}
|
|
752
|
+
}),
|
|
753
|
+
_: 3
|
|
754
|
+
}, _parent));
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
const _sfc_setup$4 = _sfc_main$4.setup;
|
|
759
|
+
_sfc_main$4.setup = (props, ctx) => {
|
|
760
|
+
const ssrContext = useSSRContext();
|
|
761
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/tabs/Tabs.vue");
|
|
762
|
+
return _sfc_setup$4 ? _sfc_setup$4(props, ctx) : void 0;
|
|
763
|
+
};
|
|
764
|
+
const Tabs = Object.assign(_sfc_main$4, { __name: "UiTabs" });
|
|
765
|
+
const _sfc_main$3 = /* @__PURE__ */ defineComponent({
|
|
766
|
+
__name: "TabsContent",
|
|
767
|
+
__ssrInlineRender: true,
|
|
768
|
+
props: {
|
|
769
|
+
value: {},
|
|
770
|
+
forceMount: { type: Boolean },
|
|
771
|
+
asChild: { type: Boolean },
|
|
772
|
+
as: {},
|
|
773
|
+
class: {}
|
|
774
|
+
},
|
|
775
|
+
setup(__props) {
|
|
776
|
+
const props = __props;
|
|
777
|
+
const delegatedProps = reactiveOmit(props, "class");
|
|
778
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
779
|
+
_push(ssrRenderComponent(unref(TabsContent$1), mergeProps({
|
|
780
|
+
"data-slot": "tabs-content",
|
|
781
|
+
class: unref(cn)("flex-1 outline-none", props.class)
|
|
782
|
+
}, unref(delegatedProps), _attrs), {
|
|
783
|
+
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
784
|
+
if (_push2) {
|
|
785
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push2, _parent2, _scopeId);
|
|
786
|
+
} else {
|
|
787
|
+
return [
|
|
788
|
+
renderSlot(_ctx.$slots, "default")
|
|
789
|
+
];
|
|
790
|
+
}
|
|
791
|
+
}),
|
|
792
|
+
_: 3
|
|
793
|
+
}, _parent));
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
});
|
|
797
|
+
const _sfc_setup$3 = _sfc_main$3.setup;
|
|
798
|
+
_sfc_main$3.setup = (props, ctx) => {
|
|
799
|
+
const ssrContext = useSSRContext();
|
|
800
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/tabs/TabsContent.vue");
|
|
801
|
+
return _sfc_setup$3 ? _sfc_setup$3(props, ctx) : void 0;
|
|
802
|
+
};
|
|
803
|
+
const TabsContent = Object.assign(_sfc_main$3, { __name: "UiTabsContent" });
|
|
804
|
+
const _sfc_main$2 = /* @__PURE__ */ defineComponent({
|
|
805
|
+
__name: "TabsList",
|
|
806
|
+
__ssrInlineRender: true,
|
|
807
|
+
props: {
|
|
808
|
+
loop: { type: Boolean },
|
|
809
|
+
asChild: { type: Boolean },
|
|
810
|
+
as: {},
|
|
811
|
+
class: {}
|
|
812
|
+
},
|
|
813
|
+
setup(__props) {
|
|
814
|
+
const props = __props;
|
|
815
|
+
const delegatedProps = reactiveOmit(props, "class");
|
|
816
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
817
|
+
_push(ssrRenderComponent(unref(TabsList$1), mergeProps({ "data-slot": "tabs-list" }, unref(delegatedProps), {
|
|
818
|
+
class: unref(cn)(
|
|
819
|
+
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
|
820
|
+
props.class
|
|
821
|
+
)
|
|
822
|
+
}, _attrs), {
|
|
823
|
+
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
824
|
+
if (_push2) {
|
|
825
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push2, _parent2, _scopeId);
|
|
826
|
+
} else {
|
|
827
|
+
return [
|
|
828
|
+
renderSlot(_ctx.$slots, "default")
|
|
829
|
+
];
|
|
830
|
+
}
|
|
831
|
+
}),
|
|
832
|
+
_: 3
|
|
833
|
+
}, _parent));
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
const _sfc_setup$2 = _sfc_main$2.setup;
|
|
838
|
+
_sfc_main$2.setup = (props, ctx) => {
|
|
839
|
+
const ssrContext = useSSRContext();
|
|
840
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/tabs/TabsList.vue");
|
|
841
|
+
return _sfc_setup$2 ? _sfc_setup$2(props, ctx) : void 0;
|
|
842
|
+
};
|
|
843
|
+
const TabsList = Object.assign(_sfc_main$2, { __name: "UiTabsList" });
|
|
844
|
+
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
845
|
+
__name: "TabsTrigger",
|
|
846
|
+
__ssrInlineRender: true,
|
|
847
|
+
props: {
|
|
848
|
+
value: {},
|
|
849
|
+
disabled: { type: Boolean },
|
|
850
|
+
asChild: { type: Boolean },
|
|
851
|
+
as: {},
|
|
852
|
+
class: {}
|
|
853
|
+
},
|
|
854
|
+
setup(__props) {
|
|
855
|
+
const props = __props;
|
|
856
|
+
const delegatedProps = reactiveOmit(props, "class");
|
|
857
|
+
const forwardedProps = useForwardProps(delegatedProps);
|
|
858
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
859
|
+
_push(ssrRenderComponent(unref(TabsTrigger$1), mergeProps({
|
|
860
|
+
"data-slot": "tabs-trigger",
|
|
861
|
+
class: unref(cn)(
|
|
862
|
+
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
863
|
+
props.class
|
|
864
|
+
)
|
|
865
|
+
}, unref(forwardedProps), _attrs), {
|
|
866
|
+
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
867
|
+
if (_push2) {
|
|
868
|
+
ssrRenderSlot(_ctx.$slots, "default", {}, null, _push2, _parent2, _scopeId);
|
|
869
|
+
} else {
|
|
870
|
+
return [
|
|
871
|
+
renderSlot(_ctx.$slots, "default")
|
|
872
|
+
];
|
|
873
|
+
}
|
|
874
|
+
}),
|
|
875
|
+
_: 3
|
|
876
|
+
}, _parent));
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
});
|
|
880
|
+
const _sfc_setup$1 = _sfc_main$1.setup;
|
|
881
|
+
_sfc_main$1.setup = (props, ctx) => {
|
|
882
|
+
const ssrContext = useSSRContext();
|
|
883
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("components/ui/tabs/TabsTrigger.vue");
|
|
884
|
+
return _sfc_setup$1 ? _sfc_setup$1(props, ctx) : void 0;
|
|
885
|
+
};
|
|
886
|
+
const TabsTrigger = Object.assign(_sfc_main$1, { __name: "UiTabsTrigger" });
|
|
887
|
+
const TASK_QUERY_KEY = "task";
|
|
888
|
+
const TASK_PRD_QUERY_KEY = "taskPrd";
|
|
889
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
890
|
+
__name: "[prd]",
|
|
891
|
+
__ssrInlineRender: true,
|
|
892
|
+
setup(__props) {
|
|
893
|
+
function getSingleQueryParam(value) {
|
|
894
|
+
if (typeof value === "string") {
|
|
895
|
+
const trimmed = value.trim();
|
|
896
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
897
|
+
}
|
|
898
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
899
|
+
const first = value[0];
|
|
900
|
+
if (typeof first === "string") {
|
|
901
|
+
const trimmed = first.trim();
|
|
902
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return null;
|
|
906
|
+
}
|
|
907
|
+
const route = useRoute();
|
|
908
|
+
const router = useRouter();
|
|
909
|
+
const { selectRepo } = useRepos();
|
|
910
|
+
const {
|
|
911
|
+
fetchDocument,
|
|
912
|
+
fetchTasks,
|
|
913
|
+
fetchProgress,
|
|
914
|
+
fetchTaskCommits,
|
|
915
|
+
fetchPrdGraph
|
|
916
|
+
} = usePrd();
|
|
917
|
+
const { showError } = useToast();
|
|
918
|
+
const repoId = computed(() => route.params.repo);
|
|
919
|
+
const prdSlug = computed(() => route.params.prd);
|
|
920
|
+
const document = ref(null);
|
|
921
|
+
const tasksFile = ref(null);
|
|
922
|
+
const progressFile = ref(null);
|
|
923
|
+
const isLoading = ref(true);
|
|
924
|
+
const error = ref(null);
|
|
925
|
+
const activeTab = ref("document");
|
|
926
|
+
const prdGraph = ref(null);
|
|
927
|
+
const graphLoading = ref(false);
|
|
928
|
+
const graphError = ref(null);
|
|
929
|
+
const tasksByPrd = ref({});
|
|
930
|
+
const selectedTask = ref(null);
|
|
931
|
+
const selectedTaskPrdSlug = ref(null);
|
|
932
|
+
const detailOpen = ref(false);
|
|
933
|
+
const selectedTaskCommits = ref([]);
|
|
934
|
+
const taskQueryId = computed(() => getSingleQueryParam(route.query[TASK_QUERY_KEY]));
|
|
935
|
+
const taskQueryPrd = computed(() => getSingleQueryParam(route.query[TASK_PRD_QUERY_KEY]));
|
|
936
|
+
const routeTaskSelection = computed(() => {
|
|
937
|
+
if (!taskQueryId.value) {
|
|
938
|
+
return null;
|
|
939
|
+
}
|
|
940
|
+
return {
|
|
941
|
+
taskId: taskQueryId.value,
|
|
942
|
+
prdSlug: taskQueryPrd.value || prdSlug.value
|
|
943
|
+
};
|
|
944
|
+
});
|
|
945
|
+
function cacheTasksForPrd(slug, tasks) {
|
|
946
|
+
tasksByPrd.value = {
|
|
947
|
+
...tasksByPrd.value,
|
|
948
|
+
[slug]: tasks
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
async function getTasksForPrd(slug) {
|
|
952
|
+
if (slug === prdSlug.value) {
|
|
953
|
+
return tasksFile.value;
|
|
954
|
+
}
|
|
955
|
+
if (Object.prototype.hasOwnProperty.call(tasksByPrd.value, slug)) {
|
|
956
|
+
return tasksByPrd.value[slug] ?? null;
|
|
957
|
+
}
|
|
958
|
+
const tasks = await fetchTasks(slug);
|
|
959
|
+
cacheTasksForPrd(slug, tasks);
|
|
960
|
+
return tasks;
|
|
961
|
+
}
|
|
962
|
+
function buildBaseQuery() {
|
|
963
|
+
const query = {};
|
|
964
|
+
for (const [key, value] of Object.entries(route.query)) {
|
|
965
|
+
if (key === TASK_QUERY_KEY || key === TASK_PRD_QUERY_KEY) {
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
if (typeof value === "string") {
|
|
969
|
+
query[key] = value;
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
if (Array.isArray(value)) {
|
|
973
|
+
const values = value.filter((entry) => typeof entry === "string");
|
|
974
|
+
if (values.length > 0) {
|
|
975
|
+
query[key] = values;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return query;
|
|
980
|
+
}
|
|
981
|
+
async function syncTaskQuery(taskId, sourcePrdSlug = null) {
|
|
982
|
+
const nextQuery = buildBaseQuery();
|
|
983
|
+
if (taskId) {
|
|
984
|
+
nextQuery[TASK_QUERY_KEY] = taskId;
|
|
985
|
+
if (sourcePrdSlug && sourcePrdSlug !== prdSlug.value) {
|
|
986
|
+
nextQuery[TASK_PRD_QUERY_KEY] = sourcePrdSlug;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
const nextTaskId = typeof nextQuery[TASK_QUERY_KEY] === "string" ? nextQuery[TASK_QUERY_KEY] : null;
|
|
990
|
+
const nextTaskPrd = typeof nextQuery[TASK_PRD_QUERY_KEY] === "string" ? nextQuery[TASK_PRD_QUERY_KEY] : null;
|
|
991
|
+
if (taskQueryId.value === nextTaskId && taskQueryPrd.value === nextTaskPrd) {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
await router.replace({ query: nextQuery });
|
|
995
|
+
}
|
|
996
|
+
async function openTaskDetail(task, sourcePrdSlug) {
|
|
997
|
+
selectedTask.value = task;
|
|
998
|
+
selectedTaskPrdSlug.value = sourcePrdSlug;
|
|
999
|
+
detailOpen.value = true;
|
|
1000
|
+
selectedTaskCommits.value = [];
|
|
1001
|
+
await syncTaskQuery(task.id, sourcePrdSlug);
|
|
1002
|
+
selectedTaskCommits.value = await fetchTaskCommits(sourcePrdSlug, task.id);
|
|
1003
|
+
}
|
|
1004
|
+
async function syncTaskDetailFromRoute() {
|
|
1005
|
+
const selection = routeTaskSelection.value;
|
|
1006
|
+
if (!selection) {
|
|
1007
|
+
selectedTask.value = null;
|
|
1008
|
+
selectedTaskPrdSlug.value = null;
|
|
1009
|
+
selectedTaskCommits.value = [];
|
|
1010
|
+
detailOpen.value = false;
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
const sourceTasks = await getTasksForPrd(selection.prdSlug);
|
|
1014
|
+
const task = sourceTasks?.tasks.find((entry) => entry.id === selection.taskId);
|
|
1015
|
+
if (!task) {
|
|
1016
|
+
selectedTask.value = null;
|
|
1017
|
+
selectedTaskPrdSlug.value = null;
|
|
1018
|
+
selectedTaskCommits.value = [];
|
|
1019
|
+
detailOpen.value = false;
|
|
1020
|
+
showError("Task unavailable", `Could not find ${selection.taskId} in ${selection.prdSlug}.`);
|
|
1021
|
+
await syncTaskQuery(null);
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
const isSameTask = selectedTask.value?.id === task.id && selectedTaskPrdSlug.value === selection.prdSlug;
|
|
1025
|
+
selectedTask.value = task;
|
|
1026
|
+
selectedTaskPrdSlug.value = selection.prdSlug;
|
|
1027
|
+
detailOpen.value = true;
|
|
1028
|
+
if (!isSameTask) {
|
|
1029
|
+
selectedTaskCommits.value = await fetchTaskCommits(selection.prdSlug, task.id);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const taskTitles = computed(() => {
|
|
1033
|
+
const map = /* @__PURE__ */ new Map();
|
|
1034
|
+
const sourcePrdSlug = selectedTaskPrdSlug.value || prdSlug.value;
|
|
1035
|
+
const sourceTasks = sourcePrdSlug === prdSlug.value ? tasksFile.value : tasksByPrd.value[sourcePrdSlug] ?? null;
|
|
1036
|
+
if (!sourceTasks?.tasks) {
|
|
1037
|
+
return map;
|
|
1038
|
+
}
|
|
1039
|
+
for (const task of sourceTasks.tasks) {
|
|
1040
|
+
map.set(task.id, task.title);
|
|
1041
|
+
}
|
|
1042
|
+
return map;
|
|
1043
|
+
});
|
|
1044
|
+
watch(activeTab, (tab) => {
|
|
1045
|
+
});
|
|
1046
|
+
const fileChangeEvent = inject("fileChangeEvent", ref(null));
|
|
1047
|
+
async function loadDocument() {
|
|
1048
|
+
const doc = await fetchDocument(prdSlug.value);
|
|
1049
|
+
if (doc) {
|
|
1050
|
+
document.value = doc;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
async function loadTasksAndProgress() {
|
|
1054
|
+
const [tasks, progress] = await Promise.all([
|
|
1055
|
+
fetchTasks(prdSlug.value),
|
|
1056
|
+
fetchProgress(prdSlug.value)
|
|
1057
|
+
]);
|
|
1058
|
+
tasksFile.value = tasks;
|
|
1059
|
+
progressFile.value = progress;
|
|
1060
|
+
cacheTasksForPrd(prdSlug.value, tasks);
|
|
1061
|
+
}
|
|
1062
|
+
async function loadGraph(force = false) {
|
|
1063
|
+
graphLoading.value = true;
|
|
1064
|
+
try {
|
|
1065
|
+
if (!force && prdGraph.value?.prdSlug === prdSlug.value) {
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
const graph = await fetchPrdGraph(prdSlug.value);
|
|
1069
|
+
if (!graph) {
|
|
1070
|
+
graphError.value = "Failed to load PRD graph.";
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
prdGraph.value = graph;
|
|
1074
|
+
graphError.value = null;
|
|
1075
|
+
} finally {
|
|
1076
|
+
graphLoading.value = false;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
async function ensureGraphLoaded(force = false) {
|
|
1080
|
+
if (activeTab.value !== "graph") {
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
await loadGraph(force);
|
|
1084
|
+
}
|
|
1085
|
+
async function loadData() {
|
|
1086
|
+
isLoading.value = true;
|
|
1087
|
+
error.value = null;
|
|
1088
|
+
graphError.value = null;
|
|
1089
|
+
prdGraph.value = null;
|
|
1090
|
+
tasksByPrd.value = {};
|
|
1091
|
+
try {
|
|
1092
|
+
selectRepo(repoId.value);
|
|
1093
|
+
const [doc, tasks, progress] = await Promise.all([
|
|
1094
|
+
fetchDocument(prdSlug.value),
|
|
1095
|
+
fetchTasks(prdSlug.value),
|
|
1096
|
+
fetchProgress(prdSlug.value)
|
|
1097
|
+
]);
|
|
1098
|
+
if (!doc) {
|
|
1099
|
+
error.value = `PRD "${prdSlug.value}" not found in this repository.`;
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
document.value = doc;
|
|
1103
|
+
tasksFile.value = tasks;
|
|
1104
|
+
progressFile.value = progress;
|
|
1105
|
+
cacheTasksForPrd(prdSlug.value, tasks);
|
|
1106
|
+
if (!tasks && activeTab.value === "board") {
|
|
1107
|
+
activeTab.value = "document";
|
|
1108
|
+
}
|
|
1109
|
+
await ensureGraphLoaded();
|
|
1110
|
+
await syncTaskDetailFromRoute();
|
|
1111
|
+
} catch (err) {
|
|
1112
|
+
const fetchErr = err;
|
|
1113
|
+
if (fetchErr.statusCode === 404) {
|
|
1114
|
+
error.value = `PRD "${prdSlug.value}" not found. Check if the file exists in docs/prd/.`;
|
|
1115
|
+
} else if (fetchErr.statusCode === 500) {
|
|
1116
|
+
error.value = "Server error while loading the PRD. Check the file format.";
|
|
1117
|
+
showError("Server error", fetchErr.data?.message || "Failed to read PRD file");
|
|
1118
|
+
} else {
|
|
1119
|
+
error.value = "Failed to load PRD document. Please try again.";
|
|
1120
|
+
showError("Load failed", "Could not fetch the PRD document");
|
|
1121
|
+
}
|
|
1122
|
+
} finally {
|
|
1123
|
+
isLoading.value = false;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
watch(activeTab, async (tab) => {
|
|
1127
|
+
if (tab === "graph") {
|
|
1128
|
+
await ensureGraphLoaded();
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
watch(
|
|
1132
|
+
() => [route.query[TASK_QUERY_KEY], route.query[TASK_PRD_QUERY_KEY], prdSlug.value],
|
|
1133
|
+
async () => {
|
|
1134
|
+
if (isLoading.value) {
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
await syncTaskDetailFromRoute();
|
|
1138
|
+
}
|
|
1139
|
+
);
|
|
1140
|
+
watch(detailOpen, async (isOpen) => {
|
|
1141
|
+
if (!isOpen && routeTaskSelection.value) {
|
|
1142
|
+
await syncTaskQuery(null);
|
|
1143
|
+
}
|
|
1144
|
+
});
|
|
1145
|
+
watch(
|
|
1146
|
+
() => fileChangeEvent.value,
|
|
1147
|
+
async (event) => {
|
|
1148
|
+
if (!event) {
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
if (event.category === "prd") {
|
|
1152
|
+
await loadDocument();
|
|
1153
|
+
if (activeTab.value === "graph") {
|
|
1154
|
+
await loadGraph(true);
|
|
1155
|
+
}
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
if (event.category !== "tasks" && event.category !== "progress") {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
const isCurrentPrdChange = event.path?.includes(`/${prdSlug.value}/`) ?? false;
|
|
1162
|
+
if (isCurrentPrdChange) {
|
|
1163
|
+
await loadTasksAndProgress();
|
|
1164
|
+
prdGraph.value = null;
|
|
1165
|
+
}
|
|
1166
|
+
if (activeTab.value === "graph") {
|
|
1167
|
+
if (isCurrentPrdChange) {
|
|
1168
|
+
await loadGraph(true);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
);
|
|
1173
|
+
watch([repoId, prdSlug], loadData);
|
|
1174
|
+
async function handleTaskClick(task) {
|
|
1175
|
+
await openTaskDetail(task, prdSlug.value);
|
|
1176
|
+
}
|
|
1177
|
+
async function handleGraphTaskClick(payload) {
|
|
1178
|
+
const sourceTasks = await getTasksForPrd(payload.prdSlug);
|
|
1179
|
+
const task = sourceTasks?.tasks.find((entry) => entry.id === payload.taskId);
|
|
1180
|
+
if (!task) {
|
|
1181
|
+
showError("Task unavailable", `Could not find ${payload.taskId} in ${payload.prdSlug}.`);
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
await openTaskDetail(task, payload.prdSlug);
|
|
1185
|
+
}
|
|
1186
|
+
return (_ctx, _push, _parent, _attrs) => {
|
|
1187
|
+
const _component_NuxtLink = __nuxt_component_0$2;
|
|
1188
|
+
const _component_PrdMeta = __nuxt_component_1;
|
|
1189
|
+
const _component_PrdViewer = __nuxt_component_2;
|
|
1190
|
+
const _component_TasksBoard = __nuxt_component_3;
|
|
1191
|
+
const _component_GraphExplorer = __nuxt_component_0$2$1;
|
|
1192
|
+
const _component_TasksDetail = __nuxt_component_1$1;
|
|
1193
|
+
_push(`<div${ssrRenderAttrs(mergeProps({ class: "h-full p-4 md:p-6" }, _attrs))}>`);
|
|
1194
|
+
if (unref(isLoading)) {
|
|
1195
|
+
_push(`<div class="flex h-full items-center justify-center"><div class="flex flex-col items-center gap-4">`);
|
|
1196
|
+
_push(ssrRenderComponent(unref(Loader2), { class: "size-8 animate-spin text-primary" }, null, _parent));
|
|
1197
|
+
_push(`<p class="text-sm text-muted-foreground">Loading PRD...</p></div></div>`);
|
|
1198
|
+
} else if (unref(error)) {
|
|
1199
|
+
_push(`<div class="flex h-full items-center justify-center"><div class="flex max-w-md flex-col items-center gap-4 text-center">`);
|
|
1200
|
+
_push(ssrRenderComponent(unref(AlertCircle), { class: "size-12 text-destructive" }, null, _parent));
|
|
1201
|
+
_push(`<h2 class="text-lg font-semibold">Error Loading PRD</h2><p class="text-sm text-muted-foreground">${ssrInterpolate(unref(error))}</p><div class="flex gap-3">`);
|
|
1202
|
+
_push(ssrRenderComponent(unref(Button), {
|
|
1203
|
+
variant: "outline",
|
|
1204
|
+
size: "sm",
|
|
1205
|
+
onClick: loadData
|
|
1206
|
+
}, {
|
|
1207
|
+
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
1208
|
+
if (_push2) {
|
|
1209
|
+
_push2(ssrRenderComponent(unref(RefreshCw), { class: "mr-2 size-4" }, null, _parent2, _scopeId));
|
|
1210
|
+
_push2(` Retry `);
|
|
1211
|
+
} else {
|
|
1212
|
+
return [
|
|
1213
|
+
createVNode(unref(RefreshCw), { class: "mr-2 size-4" }),
|
|
1214
|
+
createTextVNode(" Retry ")
|
|
1215
|
+
];
|
|
1216
|
+
}
|
|
1217
|
+
}),
|
|
1218
|
+
_: 1
|
|
1219
|
+
}, _parent));
|
|
1220
|
+
_push(ssrRenderComponent(_component_NuxtLink, { to: "/" }, {
|
|
1221
|
+
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
1222
|
+
if (_push2) {
|
|
1223
|
+
_push2(ssrRenderComponent(unref(Button), {
|
|
1224
|
+
variant: "ghost",
|
|
1225
|
+
size: "sm"
|
|
1226
|
+
}, {
|
|
1227
|
+
default: withCtx((_2, _push3, _parent3, _scopeId2) => {
|
|
1228
|
+
if (_push3) {
|
|
1229
|
+
_push3(` Go back home `);
|
|
1230
|
+
} else {
|
|
1231
|
+
return [
|
|
1232
|
+
createTextVNode(" Go back home ")
|
|
1233
|
+
];
|
|
1234
|
+
}
|
|
1235
|
+
}),
|
|
1236
|
+
_: 1
|
|
1237
|
+
}, _parent2, _scopeId));
|
|
1238
|
+
} else {
|
|
1239
|
+
return [
|
|
1240
|
+
createVNode(unref(Button), {
|
|
1241
|
+
variant: "ghost",
|
|
1242
|
+
size: "sm"
|
|
1243
|
+
}, {
|
|
1244
|
+
default: withCtx(() => [
|
|
1245
|
+
createTextVNode(" Go back home ")
|
|
1246
|
+
]),
|
|
1247
|
+
_: 1
|
|
1248
|
+
})
|
|
1249
|
+
];
|
|
1250
|
+
}
|
|
1251
|
+
}),
|
|
1252
|
+
_: 1
|
|
1253
|
+
}, _parent));
|
|
1254
|
+
_push(`</div></div></div>`);
|
|
1255
|
+
} else if (unref(document)) {
|
|
1256
|
+
_push(`<div class="mx-auto max-w-6xl space-y-6"><div class="space-y-2"><h1 class="text-2xl font-bold tracking-tight">${ssrInterpolate(unref(document).name)}</h1>`);
|
|
1257
|
+
_push(ssrRenderComponent(_component_PrdMeta, {
|
|
1258
|
+
metadata: unref(document).metadata
|
|
1259
|
+
}, null, _parent));
|
|
1260
|
+
_push(`</div>`);
|
|
1261
|
+
_push(ssrRenderComponent(unref(Tabs), {
|
|
1262
|
+
modelValue: unref(activeTab),
|
|
1263
|
+
"onUpdate:modelValue": ($event) => isRef(activeTab) ? activeTab.value = $event : null,
|
|
1264
|
+
class: "w-full"
|
|
1265
|
+
}, {
|
|
1266
|
+
default: withCtx((_, _push2, _parent2, _scopeId) => {
|
|
1267
|
+
if (_push2) {
|
|
1268
|
+
_push2(ssrRenderComponent(unref(TabsList), null, {
|
|
1269
|
+
default: withCtx((_2, _push3, _parent3, _scopeId2) => {
|
|
1270
|
+
if (_push3) {
|
|
1271
|
+
_push3(ssrRenderComponent(unref(TabsTrigger), {
|
|
1272
|
+
value: "document",
|
|
1273
|
+
class: "gap-2"
|
|
1274
|
+
}, {
|
|
1275
|
+
default: withCtx((_3, _push4, _parent4, _scopeId3) => {
|
|
1276
|
+
if (_push4) {
|
|
1277
|
+
_push4(ssrRenderComponent(unref(FileText), { class: "size-4" }, null, _parent4, _scopeId3));
|
|
1278
|
+
_push4(` Document `);
|
|
1279
|
+
} else {
|
|
1280
|
+
return [
|
|
1281
|
+
createVNode(unref(FileText), { class: "size-4" }),
|
|
1282
|
+
createTextVNode(" Document ")
|
|
1283
|
+
];
|
|
1284
|
+
}
|
|
1285
|
+
}),
|
|
1286
|
+
_: 1
|
|
1287
|
+
}, _parent3, _scopeId2));
|
|
1288
|
+
_push3(ssrRenderComponent(unref(TabsTrigger), {
|
|
1289
|
+
value: "board",
|
|
1290
|
+
class: "gap-2",
|
|
1291
|
+
disabled: !unref(tasksFile)
|
|
1292
|
+
}, {
|
|
1293
|
+
default: withCtx((_3, _push4, _parent4, _scopeId3) => {
|
|
1294
|
+
if (_push4) {
|
|
1295
|
+
_push4(ssrRenderComponent(unref(LayoutGrid), { class: "size-4" }, null, _parent4, _scopeId3));
|
|
1296
|
+
_push4(` Task Board `);
|
|
1297
|
+
if (unref(tasksFile)) {
|
|
1298
|
+
_push4(`<span class="text-xs text-muted-foreground"${_scopeId3}> (${ssrInterpolate(unref(tasksFile).tasks.length)}) </span>`);
|
|
1299
|
+
} else {
|
|
1300
|
+
_push4(`<!---->`);
|
|
1301
|
+
}
|
|
1302
|
+
} else {
|
|
1303
|
+
return [
|
|
1304
|
+
createVNode(unref(LayoutGrid), { class: "size-4" }),
|
|
1305
|
+
createTextVNode(" Task Board "),
|
|
1306
|
+
unref(tasksFile) ? (openBlock(), createBlock("span", {
|
|
1307
|
+
key: 0,
|
|
1308
|
+
class: "text-xs text-muted-foreground"
|
|
1309
|
+
}, " (" + toDisplayString(unref(tasksFile).tasks.length) + ") ", 1)) : createCommentVNode("", true)
|
|
1310
|
+
];
|
|
1311
|
+
}
|
|
1312
|
+
}),
|
|
1313
|
+
_: 1
|
|
1314
|
+
}, _parent3, _scopeId2));
|
|
1315
|
+
_push3(ssrRenderComponent(unref(TabsTrigger), {
|
|
1316
|
+
value: "graph",
|
|
1317
|
+
class: "gap-2"
|
|
1318
|
+
}, {
|
|
1319
|
+
default: withCtx((_3, _push4, _parent4, _scopeId3) => {
|
|
1320
|
+
if (_push4) {
|
|
1321
|
+
_push4(ssrRenderComponent(unref(GitBranch), { class: "size-4" }, null, _parent4, _scopeId3));
|
|
1322
|
+
_push4(` Graph `);
|
|
1323
|
+
} else {
|
|
1324
|
+
return [
|
|
1325
|
+
createVNode(unref(GitBranch), { class: "size-4" }),
|
|
1326
|
+
createTextVNode(" Graph ")
|
|
1327
|
+
];
|
|
1328
|
+
}
|
|
1329
|
+
}),
|
|
1330
|
+
_: 1
|
|
1331
|
+
}, _parent3, _scopeId2));
|
|
1332
|
+
} else {
|
|
1333
|
+
return [
|
|
1334
|
+
createVNode(unref(TabsTrigger), {
|
|
1335
|
+
value: "document",
|
|
1336
|
+
class: "gap-2"
|
|
1337
|
+
}, {
|
|
1338
|
+
default: withCtx(() => [
|
|
1339
|
+
createVNode(unref(FileText), { class: "size-4" }),
|
|
1340
|
+
createTextVNode(" Document ")
|
|
1341
|
+
]),
|
|
1342
|
+
_: 1
|
|
1343
|
+
}),
|
|
1344
|
+
createVNode(unref(TabsTrigger), {
|
|
1345
|
+
value: "board",
|
|
1346
|
+
class: "gap-2",
|
|
1347
|
+
disabled: !unref(tasksFile)
|
|
1348
|
+
}, {
|
|
1349
|
+
default: withCtx(() => [
|
|
1350
|
+
createVNode(unref(LayoutGrid), { class: "size-4" }),
|
|
1351
|
+
createTextVNode(" Task Board "),
|
|
1352
|
+
unref(tasksFile) ? (openBlock(), createBlock("span", {
|
|
1353
|
+
key: 0,
|
|
1354
|
+
class: "text-xs text-muted-foreground"
|
|
1355
|
+
}, " (" + toDisplayString(unref(tasksFile).tasks.length) + ") ", 1)) : createCommentVNode("", true)
|
|
1356
|
+
]),
|
|
1357
|
+
_: 1
|
|
1358
|
+
}, 8, ["disabled"]),
|
|
1359
|
+
createVNode(unref(TabsTrigger), {
|
|
1360
|
+
value: "graph",
|
|
1361
|
+
class: "gap-2"
|
|
1362
|
+
}, {
|
|
1363
|
+
default: withCtx(() => [
|
|
1364
|
+
createVNode(unref(GitBranch), { class: "size-4" }),
|
|
1365
|
+
createTextVNode(" Graph ")
|
|
1366
|
+
]),
|
|
1367
|
+
_: 1
|
|
1368
|
+
})
|
|
1369
|
+
];
|
|
1370
|
+
}
|
|
1371
|
+
}),
|
|
1372
|
+
_: 1
|
|
1373
|
+
}, _parent2, _scopeId));
|
|
1374
|
+
_push2(ssrRenderComponent(unref(TabsContent), {
|
|
1375
|
+
value: "document",
|
|
1376
|
+
class: "mt-4"
|
|
1377
|
+
}, {
|
|
1378
|
+
default: withCtx((_2, _push3, _parent3, _scopeId2) => {
|
|
1379
|
+
if (_push3) {
|
|
1380
|
+
_push3(`<div class="rounded-lg border border-border bg-card p-4 md:p-6"${_scopeId2}>`);
|
|
1381
|
+
_push3(ssrRenderComponent(_component_PrdViewer, {
|
|
1382
|
+
content: unref(document).content
|
|
1383
|
+
}, null, _parent3, _scopeId2));
|
|
1384
|
+
_push3(`</div>`);
|
|
1385
|
+
} else {
|
|
1386
|
+
return [
|
|
1387
|
+
createVNode("div", { class: "rounded-lg border border-border bg-card p-4 md:p-6" }, [
|
|
1388
|
+
createVNode(_component_PrdViewer, {
|
|
1389
|
+
content: unref(document).content
|
|
1390
|
+
}, null, 8, ["content"])
|
|
1391
|
+
])
|
|
1392
|
+
];
|
|
1393
|
+
}
|
|
1394
|
+
}),
|
|
1395
|
+
_: 1
|
|
1396
|
+
}, _parent2, _scopeId));
|
|
1397
|
+
_push2(ssrRenderComponent(unref(TabsContent), {
|
|
1398
|
+
value: "board",
|
|
1399
|
+
class: "mt-4"
|
|
1400
|
+
}, {
|
|
1401
|
+
default: withCtx((_2, _push3, _parent3, _scopeId2) => {
|
|
1402
|
+
if (_push3) {
|
|
1403
|
+
if (unref(tasksFile)) {
|
|
1404
|
+
_push3(`<div class="h-[calc(100vh-280px)] min-h-[400px]"${_scopeId2}>`);
|
|
1405
|
+
_push3(ssrRenderComponent(_component_TasksBoard, {
|
|
1406
|
+
tasks: unref(tasksFile).tasks,
|
|
1407
|
+
onTaskClick: handleTaskClick
|
|
1408
|
+
}, null, _parent3, _scopeId2));
|
|
1409
|
+
_push3(`</div>`);
|
|
1410
|
+
} else {
|
|
1411
|
+
_push3(`<div class="py-12 text-center"${_scopeId2}>`);
|
|
1412
|
+
_push3(ssrRenderComponent(unref(LayoutGrid), { class: "mx-auto size-12 text-muted-foreground/50" }, null, _parent3, _scopeId2));
|
|
1413
|
+
_push3(`<p class="mt-4 text-muted-foreground"${_scopeId2}> No tasks found for this PRD </p><p class="mt-1 text-sm text-muted-foreground/70"${_scopeId2}> Task state has not been generated for this PRD yet. </p></div>`);
|
|
1414
|
+
}
|
|
1415
|
+
} else {
|
|
1416
|
+
return [
|
|
1417
|
+
unref(tasksFile) ? (openBlock(), createBlock("div", {
|
|
1418
|
+
key: 0,
|
|
1419
|
+
class: "h-[calc(100vh-280px)] min-h-[400px]"
|
|
1420
|
+
}, [
|
|
1421
|
+
createVNode(_component_TasksBoard, {
|
|
1422
|
+
tasks: unref(tasksFile).tasks,
|
|
1423
|
+
onTaskClick: handleTaskClick
|
|
1424
|
+
}, null, 8, ["tasks"])
|
|
1425
|
+
])) : (openBlock(), createBlock("div", {
|
|
1426
|
+
key: 1,
|
|
1427
|
+
class: "py-12 text-center"
|
|
1428
|
+
}, [
|
|
1429
|
+
createVNode(unref(LayoutGrid), { class: "mx-auto size-12 text-muted-foreground/50" }),
|
|
1430
|
+
createVNode("p", { class: "mt-4 text-muted-foreground" }, " No tasks found for this PRD "),
|
|
1431
|
+
createVNode("p", { class: "mt-1 text-sm text-muted-foreground/70" }, " Task state has not been generated for this PRD yet. ")
|
|
1432
|
+
]))
|
|
1433
|
+
];
|
|
1434
|
+
}
|
|
1435
|
+
}),
|
|
1436
|
+
_: 1
|
|
1437
|
+
}, _parent2, _scopeId));
|
|
1438
|
+
_push2(ssrRenderComponent(unref(TabsContent), {
|
|
1439
|
+
value: "graph",
|
|
1440
|
+
class: "mt-4"
|
|
1441
|
+
}, {
|
|
1442
|
+
default: withCtx((_2, _push3, _parent3, _scopeId2) => {
|
|
1443
|
+
if (_push3) {
|
|
1444
|
+
_push3(`<div class="h-[calc(100vh-300px)] min-h-[440px] motion-safe:transition-[opacity,transform] motion-safe:duration-200 motion-safe:ease-[var(--ease-out-cubic)] motion-reduce:transition-none"${_scopeId2}>`);
|
|
1445
|
+
_push3(ssrRenderComponent(_component_GraphExplorer, {
|
|
1446
|
+
payload: unref(prdGraph),
|
|
1447
|
+
scope: "prd",
|
|
1448
|
+
loading: unref(graphLoading),
|
|
1449
|
+
error: unref(graphError),
|
|
1450
|
+
onTaskClick: handleGraphTaskClick
|
|
1451
|
+
}, null, _parent3, _scopeId2));
|
|
1452
|
+
_push3(`</div>`);
|
|
1453
|
+
} else {
|
|
1454
|
+
return [
|
|
1455
|
+
createVNode("div", { class: "h-[calc(100vh-300px)] min-h-[440px] motion-safe:transition-[opacity,transform] motion-safe:duration-200 motion-safe:ease-[var(--ease-out-cubic)] motion-reduce:transition-none" }, [
|
|
1456
|
+
createVNode(_component_GraphExplorer, {
|
|
1457
|
+
payload: unref(prdGraph),
|
|
1458
|
+
scope: "prd",
|
|
1459
|
+
loading: unref(graphLoading),
|
|
1460
|
+
error: unref(graphError),
|
|
1461
|
+
onTaskClick: handleGraphTaskClick
|
|
1462
|
+
}, null, 8, ["payload", "loading", "error"])
|
|
1463
|
+
])
|
|
1464
|
+
];
|
|
1465
|
+
}
|
|
1466
|
+
}),
|
|
1467
|
+
_: 1
|
|
1468
|
+
}, _parent2, _scopeId));
|
|
1469
|
+
} else {
|
|
1470
|
+
return [
|
|
1471
|
+
createVNode(unref(TabsList), null, {
|
|
1472
|
+
default: withCtx(() => [
|
|
1473
|
+
createVNode(unref(TabsTrigger), {
|
|
1474
|
+
value: "document",
|
|
1475
|
+
class: "gap-2"
|
|
1476
|
+
}, {
|
|
1477
|
+
default: withCtx(() => [
|
|
1478
|
+
createVNode(unref(FileText), { class: "size-4" }),
|
|
1479
|
+
createTextVNode(" Document ")
|
|
1480
|
+
]),
|
|
1481
|
+
_: 1
|
|
1482
|
+
}),
|
|
1483
|
+
createVNode(unref(TabsTrigger), {
|
|
1484
|
+
value: "board",
|
|
1485
|
+
class: "gap-2",
|
|
1486
|
+
disabled: !unref(tasksFile)
|
|
1487
|
+
}, {
|
|
1488
|
+
default: withCtx(() => [
|
|
1489
|
+
createVNode(unref(LayoutGrid), { class: "size-4" }),
|
|
1490
|
+
createTextVNode(" Task Board "),
|
|
1491
|
+
unref(tasksFile) ? (openBlock(), createBlock("span", {
|
|
1492
|
+
key: 0,
|
|
1493
|
+
class: "text-xs text-muted-foreground"
|
|
1494
|
+
}, " (" + toDisplayString(unref(tasksFile).tasks.length) + ") ", 1)) : createCommentVNode("", true)
|
|
1495
|
+
]),
|
|
1496
|
+
_: 1
|
|
1497
|
+
}, 8, ["disabled"]),
|
|
1498
|
+
createVNode(unref(TabsTrigger), {
|
|
1499
|
+
value: "graph",
|
|
1500
|
+
class: "gap-2"
|
|
1501
|
+
}, {
|
|
1502
|
+
default: withCtx(() => [
|
|
1503
|
+
createVNode(unref(GitBranch), { class: "size-4" }),
|
|
1504
|
+
createTextVNode(" Graph ")
|
|
1505
|
+
]),
|
|
1506
|
+
_: 1
|
|
1507
|
+
})
|
|
1508
|
+
]),
|
|
1509
|
+
_: 1
|
|
1510
|
+
}),
|
|
1511
|
+
createVNode(unref(TabsContent), {
|
|
1512
|
+
value: "document",
|
|
1513
|
+
class: "mt-4"
|
|
1514
|
+
}, {
|
|
1515
|
+
default: withCtx(() => [
|
|
1516
|
+
createVNode("div", { class: "rounded-lg border border-border bg-card p-4 md:p-6" }, [
|
|
1517
|
+
createVNode(_component_PrdViewer, {
|
|
1518
|
+
content: unref(document).content
|
|
1519
|
+
}, null, 8, ["content"])
|
|
1520
|
+
])
|
|
1521
|
+
]),
|
|
1522
|
+
_: 1
|
|
1523
|
+
}),
|
|
1524
|
+
createVNode(unref(TabsContent), {
|
|
1525
|
+
value: "board",
|
|
1526
|
+
class: "mt-4"
|
|
1527
|
+
}, {
|
|
1528
|
+
default: withCtx(() => [
|
|
1529
|
+
unref(tasksFile) ? (openBlock(), createBlock("div", {
|
|
1530
|
+
key: 0,
|
|
1531
|
+
class: "h-[calc(100vh-280px)] min-h-[400px]"
|
|
1532
|
+
}, [
|
|
1533
|
+
createVNode(_component_TasksBoard, {
|
|
1534
|
+
tasks: unref(tasksFile).tasks,
|
|
1535
|
+
onTaskClick: handleTaskClick
|
|
1536
|
+
}, null, 8, ["tasks"])
|
|
1537
|
+
])) : (openBlock(), createBlock("div", {
|
|
1538
|
+
key: 1,
|
|
1539
|
+
class: "py-12 text-center"
|
|
1540
|
+
}, [
|
|
1541
|
+
createVNode(unref(LayoutGrid), { class: "mx-auto size-12 text-muted-foreground/50" }),
|
|
1542
|
+
createVNode("p", { class: "mt-4 text-muted-foreground" }, " No tasks found for this PRD "),
|
|
1543
|
+
createVNode("p", { class: "mt-1 text-sm text-muted-foreground/70" }, " Task state has not been generated for this PRD yet. ")
|
|
1544
|
+
]))
|
|
1545
|
+
]),
|
|
1546
|
+
_: 1
|
|
1547
|
+
}),
|
|
1548
|
+
createVNode(unref(TabsContent), {
|
|
1549
|
+
value: "graph",
|
|
1550
|
+
class: "mt-4"
|
|
1551
|
+
}, {
|
|
1552
|
+
default: withCtx(() => [
|
|
1553
|
+
createVNode("div", { class: "h-[calc(100vh-300px)] min-h-[440px] motion-safe:transition-[opacity,transform] motion-safe:duration-200 motion-safe:ease-[var(--ease-out-cubic)] motion-reduce:transition-none" }, [
|
|
1554
|
+
createVNode(_component_GraphExplorer, {
|
|
1555
|
+
payload: unref(prdGraph),
|
|
1556
|
+
scope: "prd",
|
|
1557
|
+
loading: unref(graphLoading),
|
|
1558
|
+
error: unref(graphError),
|
|
1559
|
+
onTaskClick: handleGraphTaskClick
|
|
1560
|
+
}, null, 8, ["payload", "loading", "error"])
|
|
1561
|
+
])
|
|
1562
|
+
]),
|
|
1563
|
+
_: 1
|
|
1564
|
+
})
|
|
1565
|
+
];
|
|
1566
|
+
}
|
|
1567
|
+
}),
|
|
1568
|
+
_: 1
|
|
1569
|
+
}, _parent));
|
|
1570
|
+
_push(`</div>`);
|
|
1571
|
+
} else {
|
|
1572
|
+
_push(`<!---->`);
|
|
1573
|
+
}
|
|
1574
|
+
_push(ssrRenderComponent(_component_TasksDetail, {
|
|
1575
|
+
open: unref(detailOpen),
|
|
1576
|
+
"onUpdate:open": ($event) => isRef(detailOpen) ? detailOpen.value = $event : null,
|
|
1577
|
+
task: unref(selectedTask),
|
|
1578
|
+
"task-titles": unref(taskTitles),
|
|
1579
|
+
commits: unref(selectedTaskCommits),
|
|
1580
|
+
"repo-id": unref(repoId),
|
|
1581
|
+
"task-prd-slug": unref(selectedTaskPrdSlug),
|
|
1582
|
+
"current-prd-slug": unref(prdSlug)
|
|
1583
|
+
}, null, _parent));
|
|
1584
|
+
_push(`</div>`);
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
});
|
|
1588
|
+
const _sfc_setup = _sfc_main.setup;
|
|
1589
|
+
_sfc_main.setup = (props, ctx) => {
|
|
1590
|
+
const ssrContext = useSSRContext();
|
|
1591
|
+
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/[repo]/[prd].vue");
|
|
1592
|
+
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1595
|
+
export { _sfc_main as default };
|
|
1596
|
+
//# sourceMappingURL=_prd_-C1C4GAhW.mjs.map
|