@cat-factory/app 0.26.0 → 0.26.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/app/components/board/nodes/EpicNode.vue +3 -5
- package/app/components/layout/ProviderConfigBanner.vue +5 -1
- package/app/components/panels/inspector/EpicChildren.vue +13 -3
- package/app/components/panels/inspector/TaskRunSettings.vue +2 -2
- package/app/components/settings/ProviderConnectionPanel.vue +12 -4
- package/app/components/tasks/TaskSourceConnectModal.vue +2 -1
- package/app/composables/api/reviews.ts +1 -6
- package/package.json +1 -1
|
@@ -15,8 +15,8 @@ const block = computed<Block | undefined>(() => board.getBlock(props.id))
|
|
|
15
15
|
const members = computed(() => board.epicMembers(props.id))
|
|
16
16
|
const total = computed(() => members.value.length)
|
|
17
17
|
const done = computed(() => members.value.filter((m) => m.status === 'done').length)
|
|
18
|
-
const active = computed(
|
|
19
|
-
members.value.filter((m) => m.status === 'in_progress' || m.status === 'pr_ready').length,
|
|
18
|
+
const active = computed(
|
|
19
|
+
() => members.value.filter((m) => m.status === 'in_progress' || m.status === 'pr_ready').length,
|
|
20
20
|
)
|
|
21
21
|
const selected = computed(() => ui.selectedBlockId === props.id)
|
|
22
22
|
</script>
|
|
@@ -26,9 +26,7 @@ const selected = computed(() => ui.selectedBlockId === props.id)
|
|
|
26
26
|
v-if="block"
|
|
27
27
|
:data-block-id="block.id"
|
|
28
28
|
class="w-56 cursor-pointer rounded-lg border bg-slate-900/90 px-3 py-2 shadow-lg backdrop-blur transition-colors"
|
|
29
|
-
:class="
|
|
30
|
-
selected ? 'border-violet-400 ring-1 ring-violet-400/50' : 'border-violet-500/40'
|
|
31
|
-
"
|
|
29
|
+
:class="selected ? 'border-violet-400 ring-1 ring-violet-400/50' : 'border-violet-500/40'"
|
|
32
30
|
@click="ui.select(block.id)"
|
|
33
31
|
>
|
|
34
32
|
<div class="flex items-center gap-1.5">
|
|
@@ -42,7 +42,11 @@ const show = computed(() => pending.value.length > 0 && !dismissed.value)
|
|
|
42
42
|
<div class="min-w-0 flex-1">
|
|
43
43
|
<div class="flex items-start justify-between gap-3">
|
|
44
44
|
<h2 class="text-lg font-semibold text-amber-100">
|
|
45
|
-
{{
|
|
45
|
+
{{
|
|
46
|
+
pending.length > 1
|
|
47
|
+
? 'Providers need configuration'
|
|
48
|
+
: `${LABEL[pending[0]!]} needs configuration`
|
|
49
|
+
}}
|
|
46
50
|
</h2>
|
|
47
51
|
<UButton
|
|
48
52
|
color="neutral"
|
|
@@ -18,7 +18,10 @@ const done = computed(() => members.value.filter((m) => m.status === 'done').len
|
|
|
18
18
|
const groups = computed(() => {
|
|
19
19
|
const byService = new Map<
|
|
20
20
|
string,
|
|
21
|
-
{
|
|
21
|
+
{
|
|
22
|
+
service: Block | undefined
|
|
23
|
+
modules: Map<string, { module: Block | undefined; tasks: Block[] }>
|
|
24
|
+
}
|
|
22
25
|
>()
|
|
23
26
|
for (const task of members.value) {
|
|
24
27
|
const service = board.serviceOf(task)
|
|
@@ -29,7 +32,10 @@ const groups = computed(() => {
|
|
|
29
32
|
const parent = task.parentId ? board.getBlock(task.parentId) : undefined
|
|
30
33
|
const moduleKey = parent && parent.level === 'module' ? parent.id : '—'
|
|
31
34
|
if (!group.modules.has(moduleKey)) {
|
|
32
|
-
group.modules.set(moduleKey, {
|
|
35
|
+
group.modules.set(moduleKey, {
|
|
36
|
+
module: parent?.level === 'module' ? parent : undefined,
|
|
37
|
+
tasks: [],
|
|
38
|
+
})
|
|
33
39
|
}
|
|
34
40
|
group.modules.get(moduleKey)!.tasks.push(task)
|
|
35
41
|
}
|
|
@@ -51,7 +57,11 @@ const groups = computed(() => {
|
|
|
51
57
|
</div>
|
|
52
58
|
|
|
53
59
|
<div v-else class="space-y-2">
|
|
54
|
-
<div
|
|
60
|
+
<div
|
|
61
|
+
v-for="(group, gi) in groups"
|
|
62
|
+
:key="gi"
|
|
63
|
+
class="rounded-md border border-slate-700/60 p-2"
|
|
64
|
+
>
|
|
55
65
|
<div class="mb-1 flex items-center gap-1 text-[11px] font-medium text-slate-300">
|
|
56
66
|
<UIcon name="i-lucide-box" class="h-3 w-3 text-slate-500" />
|
|
57
67
|
{{ group.service?.title ?? 'Unassigned' }}
|
|
@@ -444,8 +444,8 @@ const technicalLabel = computed(() => {
|
|
|
444
444
|
/>
|
|
445
445
|
</div>
|
|
446
446
|
<div class="mt-1 text-[11px] text-slate-500">
|
|
447
|
-
When this task merges, automatically start the tasks that depend on it (once their
|
|
448
|
-
|
|
447
|
+
When this task merges, automatically start the tasks that depend on it (once their other
|
|
448
|
+
dependencies are also done).
|
|
449
449
|
</div>
|
|
450
450
|
</div>
|
|
451
451
|
</div>
|
|
@@ -107,13 +107,16 @@ const canSave = computed(() => {
|
|
|
107
107
|
* `manifestTemplate` scaffold on a first connect. Native providers only (a manifest provider
|
|
108
108
|
* has no template ⇒ null, and rotates secrets via the dedicated path instead).
|
|
109
109
|
*/
|
|
110
|
-
function buildManifestPayload(): {
|
|
110
|
+
function buildManifestPayload(): {
|
|
111
|
+
manifest: Record<string, unknown>
|
|
112
|
+
secrets: Record<string, string>
|
|
113
|
+
} | null {
|
|
111
114
|
const template = descriptor.value?.manifestTemplate
|
|
112
115
|
if (!template) return null
|
|
113
116
|
const base = descriptor.value?.savedManifest ?? template
|
|
114
117
|
const manifest: Record<string, unknown> = structuredClone(base)
|
|
115
118
|
const providerConfig: Record<string, unknown> = {
|
|
116
|
-
...(
|
|
119
|
+
...(manifest.providerConfig as Record<string, unknown> | undefined),
|
|
117
120
|
}
|
|
118
121
|
const secrets: Record<string, string> = {}
|
|
119
122
|
for (const f of descriptor.value?.configFields ?? []) {
|
|
@@ -249,7 +252,10 @@ function fieldHelp(key: string): string | undefined {
|
|
|
249
252
|
</p>
|
|
250
253
|
<!-- A native re-register replaces the whole manifest; secrets are write-only so they
|
|
251
254
|
must be re-supplied. Non-secret config is prefilled, so it survives a save. -->
|
|
252
|
-
<p
|
|
255
|
+
<p
|
|
256
|
+
v-if="connection && canAuthor && hasSecretFields"
|
|
257
|
+
class="text-[11px] text-amber-300/80"
|
|
258
|
+
>
|
|
253
259
|
Re-enter the secret field{{ secretFieldCount > 1 ? 's' : '' }} to save changes — stored
|
|
254
260
|
secrets are write-only and aren't shown.
|
|
255
261
|
</p>
|
|
@@ -257,7 +263,9 @@ function fieldHelp(key: string): string | undefined {
|
|
|
257
263
|
<UFormField
|
|
258
264
|
v-for="field in descriptor.configFields"
|
|
259
265
|
:key="field.key"
|
|
260
|
-
:label="
|
|
266
|
+
:label="
|
|
267
|
+
field.label + (field.required && field.default === undefined ? '' : ' (optional)')
|
|
268
|
+
"
|
|
261
269
|
:help="fieldHelp(field.key)"
|
|
262
270
|
>
|
|
263
271
|
<USelect
|
|
@@ -117,7 +117,8 @@ async function toggleEnabled(enabled: boolean) {
|
|
|
117
117
|
credentials to enter.
|
|
118
118
|
</p>
|
|
119
119
|
<p v-if="!available" class="text-[11px] text-amber-400">
|
|
120
|
-
Install the workspace's GitHub App (connect GitHub repos) to offer
|
|
120
|
+
Install the workspace's GitHub App (connect GitHub repos) to offer
|
|
121
|
+
{{ descriptor.label }}.
|
|
121
122
|
</p>
|
|
122
123
|
</template>
|
|
123
124
|
|
|
@@ -104,12 +104,7 @@ export function reviewsApi({ http, ws }: ApiContext) {
|
|
|
104
104
|
{ method: 'POST' },
|
|
105
105
|
),
|
|
106
106
|
|
|
107
|
-
reRequestRecommendation: (
|
|
108
|
-
workspaceId: string,
|
|
109
|
-
reviewId: string,
|
|
110
|
-
recId: string,
|
|
111
|
-
note: string,
|
|
112
|
-
) =>
|
|
107
|
+
reRequestRecommendation: (workspaceId: string, reviewId: string, recId: string, note: string) =>
|
|
113
108
|
http<RequirementReview>(
|
|
114
109
|
`${ws(workspaceId)}/requirement-reviews/${encodeURIComponent(reviewId)}/recommendations/${encodeURIComponent(recId)}/re-request`,
|
|
115
110
|
{ method: 'POST', body: { note } },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.1",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|