@cat-factory/app 0.32.1 → 0.33.0
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/BoardCanvas.vue +0 -2
- package/app/components/layout/AccountTeamSettings.vue +58 -9
- package/app/components/layout/BoardSwitcher.vue +8 -20
- package/app/components/layout/SideBar.vue +15 -0
- package/app/components/settings/AccountSettingsPanel.vue +24 -0
- package/app/components/settings/ProviderConnectionPanel.vue +117 -0
- package/app/pages/index.vue +2 -0
- package/app/stores/ui.ts +13 -0
- package/app/stores/workspaceSettings.ts +2 -0
- package/app/types/domain.ts +6 -0
- package/nuxt.config.ts +0 -1
- package/package.json +1 -2
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { VueFlow, useVueFlow, type NodeMouseEvent } from '@vue-flow/core'
|
|
3
3
|
import { Background } from '@vue-flow/background'
|
|
4
|
-
import { Controls } from '@vue-flow/controls'
|
|
5
4
|
import { MiniMap } from '@vue-flow/minimap'
|
|
6
5
|
import BlockNode from './nodes/BlockNode.vue'
|
|
7
6
|
import EpicNode from './nodes/EpicNode.vue'
|
|
@@ -177,7 +176,6 @@ async function onDrop(event: DragEvent) {
|
|
|
177
176
|
>
|
|
178
177
|
<Background pattern-color="#1e293b" :gap="22" :size="1.4" />
|
|
179
178
|
<MiniMap pannable zoomable :node-color="minimapColor" class="!bg-slate-900/80" />
|
|
180
|
-
<Controls position="bottom-left" />
|
|
181
179
|
|
|
182
180
|
<template #node-block="props">
|
|
183
181
|
<BlockNode :id="props.id" />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, onMounted, ref } from 'vue'
|
|
2
|
+
import { computed, onMounted, ref, watch } from 'vue'
|
|
3
3
|
import type { AccountRole } from '~/types/domain'
|
|
4
4
|
import AccountDeploymentSettings from '~/components/layout/AccountDeploymentSettings.vue'
|
|
5
5
|
|
|
@@ -21,6 +21,12 @@ const ROLE_ITEMS: { label: string; value: AccountRole }[] = [
|
|
|
21
21
|
|
|
22
22
|
/** Whether the signed-in caller is an admin of this account (drives edit affordances). */
|
|
23
23
|
const isAdmin = computed(() => accounts.activeAccount?.roles?.includes('admin') ?? false)
|
|
24
|
+
/**
|
|
25
|
+
* Members / roles / invitations are org-scoped — the backend rejects membership on a
|
|
26
|
+
* personal account. For a personal account we show a "create an organization" CTA in
|
|
27
|
+
* their place; the email sender + account API keys remain available either way.
|
|
28
|
+
*/
|
|
29
|
+
const isOrg = computed(() => accounts.activeAccount?.type === 'org')
|
|
24
30
|
|
|
25
31
|
async function updateMemberRoles(userId: string, roles: AccountRole[]) {
|
|
26
32
|
try {
|
|
@@ -41,16 +47,44 @@ function notifyError(title: string, e: unknown) {
|
|
|
41
47
|
})
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
|
|
50
|
+
async function loadAll(accountId: string) {
|
|
45
51
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
const jobs: Promise<unknown>[] = [accounts.loadEmailConnection(accountId)]
|
|
53
|
+
// The roster only applies to org accounts.
|
|
54
|
+
if (isOrg.value) jobs.push(accounts.loadRoster(accountId))
|
|
55
|
+
await Promise.all(jobs)
|
|
50
56
|
} catch (e) {
|
|
51
57
|
notifyError('Could not load team settings', e)
|
|
52
58
|
}
|
|
53
|
-
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
onMounted(() => void loadAll(props.accountId))
|
|
62
|
+
// Reload when the active account changes while the panel is open (e.g. after creating an
|
|
63
|
+
// organization from the CTA below, which switches the active account to the new org).
|
|
64
|
+
watch(
|
|
65
|
+
() => props.accountId,
|
|
66
|
+
(id) => {
|
|
67
|
+
if (id) void loadAll(id)
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
// ---- create organization (personal-account CTA) ---------------------------
|
|
72
|
+
const newOrgName = ref('')
|
|
73
|
+
|
|
74
|
+
async function createOrganization() {
|
|
75
|
+
const name = newOrgName.value.trim()
|
|
76
|
+
if (!name) return
|
|
77
|
+
busy.value = true
|
|
78
|
+
try {
|
|
79
|
+
await accounts.createOrg(name)
|
|
80
|
+
newOrgName.value = ''
|
|
81
|
+
toast.add({ title: 'Organization created', icon: 'i-lucide-check' })
|
|
82
|
+
} catch (e) {
|
|
83
|
+
notifyError('Could not create organization', e)
|
|
84
|
+
} finally {
|
|
85
|
+
busy.value = false
|
|
86
|
+
}
|
|
87
|
+
}
|
|
54
88
|
|
|
55
89
|
// ---- invitations ----------------------------------------------------------
|
|
56
90
|
const inviteEmail = ref('')
|
|
@@ -125,8 +159,23 @@ async function disconnectEmail() {
|
|
|
125
159
|
|
|
126
160
|
<template>
|
|
127
161
|
<div class="space-y-6 text-sm">
|
|
162
|
+
<!-- personal-account CTA: members/roles/invitations need an organization -->
|
|
163
|
+
<section v-if="!isOrg" class="rounded-md border border-slate-800 bg-slate-800/40 p-4">
|
|
164
|
+
<h3 class="mb-1 font-semibold text-white">Invite teammates & manage roles</h3>
|
|
165
|
+
<p class="mb-3 text-slate-400">
|
|
166
|
+
Members, roles and invitations live on an organization. Create one to invite teammates and
|
|
167
|
+
manage their roles — your personal boards stay as they are.
|
|
168
|
+
</p>
|
|
169
|
+
<form class="flex gap-2" @submit.prevent="createOrganization">
|
|
170
|
+
<UInput v-model="newOrgName" placeholder="Acme Inc." class="flex-1" />
|
|
171
|
+
<UButton type="submit" color="primary" :loading="busy" icon="i-lucide-plus">
|
|
172
|
+
Create organization
|
|
173
|
+
</UButton>
|
|
174
|
+
</form>
|
|
175
|
+
</section>
|
|
176
|
+
|
|
128
177
|
<!-- members -->
|
|
129
|
-
<section>
|
|
178
|
+
<section v-if="isOrg">
|
|
130
179
|
<h3 class="mb-2 font-semibold text-white">Members</h3>
|
|
131
180
|
<ul class="space-y-1">
|
|
132
181
|
<li
|
|
@@ -153,7 +202,7 @@ async function disconnectEmail() {
|
|
|
153
202
|
</section>
|
|
154
203
|
|
|
155
204
|
<!-- invitations -->
|
|
156
|
-
<section>
|
|
205
|
+
<section v-if="isOrg">
|
|
157
206
|
<h3 class="mb-2 font-semibold text-white">Invite a teammate</h3>
|
|
158
207
|
<form class="flex gap-2" @submit.prevent="sendInvite">
|
|
159
208
|
<UInput
|
|
@@ -8,6 +8,7 @@ import type { CloudProvider } from '~/types/domain'
|
|
|
8
8
|
// board switcher over the single unscoped context.
|
|
9
9
|
const accounts = useAccountsStore()
|
|
10
10
|
const workspace = useWorkspaceStore()
|
|
11
|
+
const ui = useUiStore()
|
|
11
12
|
const toast = useToast()
|
|
12
13
|
|
|
13
14
|
const busy = ref(false)
|
|
@@ -52,10 +53,13 @@ const accountItems = computed<DropdownMenuItem[][]>(() => [
|
|
|
52
53
|
})),
|
|
53
54
|
[
|
|
54
55
|
{ label: 'New organization…', icon: 'i-lucide-plus', onSelect: () => openPrompt('account') },
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
:
|
|
56
|
+
// Account & team settings (members + roles + invitations + email sender). The panel
|
|
57
|
+
// itself handles personal accounts (prompting to create an org), so this is not gated.
|
|
58
|
+
{
|
|
59
|
+
label: 'Account settings…',
|
|
60
|
+
icon: 'i-lucide-users',
|
|
61
|
+
onSelect: () => ui.openAccountSettings(),
|
|
62
|
+
},
|
|
59
63
|
// Admins can set the account-wide default provider new services inherit.
|
|
60
64
|
...(accounts.activeAccount?.roles?.includes('admin')
|
|
61
65
|
? [
|
|
@@ -184,12 +188,6 @@ async function submitPrompt() {
|
|
|
184
188
|
busy.value = false
|
|
185
189
|
}
|
|
186
190
|
}
|
|
187
|
-
|
|
188
|
-
// ---- account settings modal (members / invitations / email) ----------------
|
|
189
|
-
const settingsOpen = ref(false)
|
|
190
|
-
function openSettings() {
|
|
191
|
-
settingsOpen.value = true
|
|
192
|
-
}
|
|
193
191
|
</script>
|
|
194
192
|
|
|
195
193
|
<template>
|
|
@@ -266,15 +264,5 @@ function openSettings() {
|
|
|
266
264
|
</form>
|
|
267
265
|
</template>
|
|
268
266
|
</UModal>
|
|
269
|
-
|
|
270
|
-
<!-- account team settings: members, invitations, email sender -->
|
|
271
|
-
<UModal v-model:open="settingsOpen" title="Team settings">
|
|
272
|
-
<template #body>
|
|
273
|
-
<AccountTeamSettings
|
|
274
|
-
v-if="accounts.activeAccountId"
|
|
275
|
-
:account-id="accounts.activeAccountId"
|
|
276
|
-
/>
|
|
277
|
-
</template>
|
|
278
|
-
</UModal>
|
|
279
267
|
</div>
|
|
280
268
|
</template>
|
|
@@ -14,6 +14,7 @@ const github = useGitHubStore()
|
|
|
14
14
|
const slack = useSlackStore()
|
|
15
15
|
const library = useFragmentLibraryStore()
|
|
16
16
|
const workspace = useWorkspaceStore()
|
|
17
|
+
const accounts = useAccountsStore()
|
|
17
18
|
const ui = useUiStore()
|
|
18
19
|
|
|
19
20
|
// Resolve whether the document-source / task-source / GitHub integrations are
|
|
@@ -203,6 +204,20 @@ watch(
|
|
|
203
204
|
>
|
|
204
205
|
Model Configuration
|
|
205
206
|
</UButton>
|
|
207
|
+
<!-- Account & team: members + roles, invitations, email sender, account API keys.
|
|
208
|
+
Shown once accounts (auth) are enabled. -->
|
|
209
|
+
<UButton
|
|
210
|
+
v-if="accounts.enabled"
|
|
211
|
+
block
|
|
212
|
+
color="primary"
|
|
213
|
+
variant="soft"
|
|
214
|
+
size="sm"
|
|
215
|
+
icon="i-lucide-users"
|
|
216
|
+
class="justify-start"
|
|
217
|
+
@click="ui.openAccountSettings()"
|
|
218
|
+
>
|
|
219
|
+
Account settings
|
|
220
|
+
</UButton>
|
|
206
221
|
</div>
|
|
207
222
|
</section>
|
|
208
223
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// Account & team settings — a modal host for the per-account team panel (members +
|
|
3
|
+
// roles, invitations, email sender, account-wide API keys). Account-scoped, distinct
|
|
4
|
+
// from Workspace settings. Opened from the SideBar Configuration section and the
|
|
5
|
+
// account switcher; bound to the `ui` store so any surface can open it.
|
|
6
|
+
import AccountTeamSettings from '~/components/layout/AccountTeamSettings.vue'
|
|
7
|
+
|
|
8
|
+
const ui = useUiStore()
|
|
9
|
+
const accounts = useAccountsStore()
|
|
10
|
+
|
|
11
|
+
const open = computed({
|
|
12
|
+
get: () => ui.accountSettingsOpen,
|
|
13
|
+
set: (v: boolean) => (v ? ui.openAccountSettings() : ui.closeAccountSettings()),
|
|
14
|
+
})
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<UModal v-model:open="open" title="Account & team" :ui="{ content: 'max-w-3xl' }">
|
|
19
|
+
<template #body>
|
|
20
|
+
<AccountTeamSettings v-if="accounts.activeAccountId" :account-id="accounts.activeAccountId" />
|
|
21
|
+
<p v-else class="text-sm text-slate-400">No account selected.</p>
|
|
22
|
+
</template>
|
|
23
|
+
</UModal>
|
|
24
|
+
</template>
|
|
@@ -44,6 +44,41 @@ const meta = computed(() => (kind.value ? META[kind.value] : null))
|
|
|
44
44
|
const descriptor = computed(() => (kind.value ? store.descriptorFor(kind.value) : null))
|
|
45
45
|
const connection = computed(() => (kind.value ? store.connectionFor(kind.value) : null))
|
|
46
46
|
|
|
47
|
+
// --- Local-mode infrastructure delegation -------------------------------------------
|
|
48
|
+
// In local mode this same screen is where a developer chooses, per workspace, whether to
|
|
49
|
+
// run on this machine (host Docker for agents, in-container docker-compose for the Tester)
|
|
50
|
+
// or delegate to an external service. The two opt-ins live here together to make the
|
|
51
|
+
// cross-cutting nature explicit: the environment provider you configure on this screen is
|
|
52
|
+
// one half; the runner pool (its own screen) is the other. Each toggle is enabled only
|
|
53
|
+
// once its provider is registered. Shown only in local mode and only on the environment
|
|
54
|
+
// kind (so it appears once, alongside the env provider it relates to).
|
|
55
|
+
const auth = useAuthStore()
|
|
56
|
+
const settings = useWorkspaceSettingsStore()
|
|
57
|
+
const isLocal = computed(() => auth.localMode?.enabled === true)
|
|
58
|
+
const showLocalDelegation = computed(() => isLocal.value && kind.value === 'environment')
|
|
59
|
+
// Gating: a toggle's external option is selectable only when its provider is registered.
|
|
60
|
+
const runnerPoolRegistered = computed(() => !!store.connectionFor('runner-pool'))
|
|
61
|
+
const envRegistered = computed(() => !!store.connectionFor('environment'))
|
|
62
|
+
const savingDelegation = ref(false)
|
|
63
|
+
|
|
64
|
+
async function setDelegation(patch: {
|
|
65
|
+
delegateAgentsToRunnerPool?: boolean
|
|
66
|
+
delegateTestEnvToProvider?: boolean
|
|
67
|
+
}) {
|
|
68
|
+
savingDelegation.value = true
|
|
69
|
+
try {
|
|
70
|
+
await settings.update(patch)
|
|
71
|
+
} catch (e) {
|
|
72
|
+
notifyError('Could not update delegation', e)
|
|
73
|
+
} finally {
|
|
74
|
+
savingDelegation.value = false
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function openRunnerPoolPanel() {
|
|
79
|
+
ui.openProviderConnection('runner-pool')
|
|
80
|
+
}
|
|
81
|
+
|
|
47
82
|
// "View logs": the provisioning event history for this provider's subsystem — every
|
|
48
83
|
// spin-up / tear-down attempt with its outcome and the exact error. The panel kind
|
|
49
84
|
// maps 1:1 to the log subsystem ('environment' / 'runner-pool').
|
|
@@ -82,6 +117,9 @@ watch(
|
|
|
82
117
|
kind,
|
|
83
118
|
(k) => {
|
|
84
119
|
if (k) void store.loadKind(k).then(resetDraft)
|
|
120
|
+
// In local mode the env panel also gates the agents toggle on a registered runner
|
|
121
|
+
// pool, so load that provider's connection state too (the env kind already loads above).
|
|
122
|
+
if (k === 'environment' && isLocal.value) void store.loadKind('runner-pool')
|
|
85
123
|
},
|
|
86
124
|
{ immediate: true },
|
|
87
125
|
)
|
|
@@ -228,6 +266,85 @@ function fieldHelp(key: string): string | undefined {
|
|
|
228
266
|
<IntegrationBackTitle :title="meta?.title ?? 'Provider'" @back="back" />
|
|
229
267
|
</template>
|
|
230
268
|
<template #body>
|
|
269
|
+
<!-- Local-mode infrastructure delegation: the local-vs-external choice for BOTH
|
|
270
|
+
container agents AND the Tester's ephemeral environments, made once here. -->
|
|
271
|
+
<section
|
|
272
|
+
v-if="showLocalDelegation"
|
|
273
|
+
class="mb-4 space-y-3 rounded-lg border border-slate-700 bg-slate-900/40 p-3"
|
|
274
|
+
>
|
|
275
|
+
<div>
|
|
276
|
+
<h3 class="text-sm font-semibold text-slate-200">Local delegation</h3>
|
|
277
|
+
<p class="mt-1 text-[11px] text-slate-400">
|
|
278
|
+
By default this machine runs everything locally — container agents on host Docker, the
|
|
279
|
+
Tester's infrastructure via in-container docker-compose. Opt in below to delegate either
|
|
280
|
+
concern to an external service instead. Applies only in local mode.
|
|
281
|
+
</p>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<!-- Container agents → self-hosted runner pool -->
|
|
285
|
+
<div class="space-y-1">
|
|
286
|
+
<label class="flex items-center gap-2">
|
|
287
|
+
<USwitch
|
|
288
|
+
size="sm"
|
|
289
|
+
:model-value="settings.settings.delegateAgentsToRunnerPool"
|
|
290
|
+
:disabled="savingDelegation || !runnerPoolRegistered"
|
|
291
|
+
@update:model-value="(v) => setDelegation({ delegateAgentsToRunnerPool: v })"
|
|
292
|
+
/>
|
|
293
|
+
<span class="text-sm text-slate-200">Run container agents on the runner pool</span>
|
|
294
|
+
</label>
|
|
295
|
+
<p class="pl-9 text-[11px] text-slate-400">
|
|
296
|
+
Dispatch every container agent (coder, tester, merger, bootstrap, …) to this workspace's
|
|
297
|
+
self-hosted runner pool instead of host Docker.
|
|
298
|
+
<template v-if="!runnerPoolRegistered">
|
|
299
|
+
<button
|
|
300
|
+
type="button"
|
|
301
|
+
class="text-sky-400 underline underline-offset-2 hover:text-sky-300"
|
|
302
|
+
@click="openRunnerPoolPanel"
|
|
303
|
+
>
|
|
304
|
+
Register a runner pool
|
|
305
|
+
</button>
|
|
306
|
+
first to enable this.
|
|
307
|
+
</template>
|
|
308
|
+
</p>
|
|
309
|
+
</div>
|
|
310
|
+
|
|
311
|
+
<!-- Tester environments → environment provider -->
|
|
312
|
+
<div class="space-y-1">
|
|
313
|
+
<label class="flex items-center gap-2">
|
|
314
|
+
<USwitch
|
|
315
|
+
size="sm"
|
|
316
|
+
:model-value="settings.settings.delegateTestEnvToProvider"
|
|
317
|
+
:disabled="savingDelegation || !envRegistered"
|
|
318
|
+
@update:model-value="(v) => setDelegation({ delegateTestEnvToProvider: v })"
|
|
319
|
+
/>
|
|
320
|
+
<span class="text-sm text-slate-200">
|
|
321
|
+
Provision Tester environments via the provider
|
|
322
|
+
</span>
|
|
323
|
+
</label>
|
|
324
|
+
<p class="pl-9 text-[11px] text-slate-400">
|
|
325
|
+
Stand the Tester's preview environment up through the environment provider configured
|
|
326
|
+
below instead of in-container docker-compose. Connect a provider first to enable this.
|
|
327
|
+
</p>
|
|
328
|
+
</div>
|
|
329
|
+
</section>
|
|
330
|
+
|
|
331
|
+
<!-- In local mode the local-vs-external toggle for agents lives on the Ephemeral
|
|
332
|
+
environments screen (alongside the env toggle), so they're configured together. -->
|
|
333
|
+
<p
|
|
334
|
+
v-if="isLocal && kind === 'runner-pool'"
|
|
335
|
+
class="mb-4 rounded-md border border-slate-700 bg-slate-900/40 px-3 py-2 text-[11px] text-slate-400"
|
|
336
|
+
>
|
|
337
|
+
Register your pool here, then enable "Run container agents on the runner pool" on the
|
|
338
|
+
<button
|
|
339
|
+
type="button"
|
|
340
|
+
class="text-sky-400 underline underline-offset-2 hover:text-sky-300"
|
|
341
|
+
@click="ui.openProviderConnection('environment')"
|
|
342
|
+
>
|
|
343
|
+
Ephemeral environments
|
|
344
|
+
</button>
|
|
345
|
+
screen to route this workspace's agents to it.
|
|
346
|
+
</p>
|
|
347
|
+
|
|
231
348
|
<div v-if="descriptor" class="space-y-4">
|
|
232
349
|
<div class="flex items-start justify-between gap-3">
|
|
233
350
|
<p class="text-xs text-slate-400">{{ meta?.blurb }}</p>
|
package/app/pages/index.vue
CHANGED
|
@@ -29,6 +29,7 @@ import FragmentLibraryPanel from '~/components/fragments/FragmentLibraryPanel.vu
|
|
|
29
29
|
import CommandBar from '~/components/layout/CommandBar.vue'
|
|
30
30
|
import IntegrationsHub from '~/components/layout/IntegrationsHub.vue'
|
|
31
31
|
import WorkspaceSettingsPanel from '~/components/settings/WorkspaceSettingsPanel.vue'
|
|
32
|
+
import AccountSettingsPanel from '~/components/settings/AccountSettingsPanel.vue'
|
|
32
33
|
import ObservabilityConnectionPanel from '~/components/settings/ObservabilityConnectionPanel.vue'
|
|
33
34
|
import ProviderConnectionPanel from '~/components/settings/ProviderConnectionPanel.vue'
|
|
34
35
|
import ProviderConfigBanner from '~/components/layout/ProviderConfigBanner.vue'
|
|
@@ -188,6 +189,7 @@ watch(
|
|
|
188
189
|
<CommandBar />
|
|
189
190
|
<IntegrationsHub />
|
|
190
191
|
<WorkspaceSettingsPanel />
|
|
192
|
+
<AccountSettingsPanel />
|
|
191
193
|
<ObservabilityConnectionPanel />
|
|
192
194
|
<ProviderConnectionPanel />
|
|
193
195
|
<ModelConfigurationPanel />
|
package/app/stores/ui.ts
CHANGED
|
@@ -96,6 +96,9 @@ export const useUiStore = defineStore('ui', () => {
|
|
|
96
96
|
// `workspaceSettingsTab` lets other surfaces deep-link straight to a tab.
|
|
97
97
|
const workspaceSettingsOpen = ref(false)
|
|
98
98
|
const workspaceSettingsTab = ref('workspace')
|
|
99
|
+
// Account/team-settings modal: the per-account members + roles + invitations + email
|
|
100
|
+
// sender panel (`AccountTeamSettings`). Account-scoped (distinct from workspace settings).
|
|
101
|
+
const accountSettingsOpen = ref(false)
|
|
99
102
|
// Observability integration: the post-release-health connection panel (Datadog
|
|
100
103
|
// today, pluggable). NB: distinct from `observabilityInstanceId` below, which is the
|
|
101
104
|
// LLM per-call observability panel.
|
|
@@ -380,6 +383,13 @@ export const useUiStore = defineStore('ui', () => {
|
|
|
380
383
|
function setWorkspaceSettingsTab(tab: string) {
|
|
381
384
|
workspaceSettingsTab.value = tab
|
|
382
385
|
}
|
|
386
|
+
function openAccountSettings() {
|
|
387
|
+
cameFromIntegrations.value = false
|
|
388
|
+
accountSettingsOpen.value = true
|
|
389
|
+
}
|
|
390
|
+
function closeAccountSettings() {
|
|
391
|
+
accountSettingsOpen.value = false
|
|
392
|
+
}
|
|
383
393
|
function openObservabilityConnection() {
|
|
384
394
|
cameFromIntegrations.value = false
|
|
385
395
|
observabilityConnectionOpen.value = true
|
|
@@ -555,6 +565,7 @@ export const useUiStore = defineStore('ui', () => {
|
|
|
555
565
|
cameFromIntegrations,
|
|
556
566
|
workspaceSettingsOpen,
|
|
557
567
|
workspaceSettingsTab,
|
|
568
|
+
accountSettingsOpen,
|
|
558
569
|
observabilityConnectionOpen,
|
|
559
570
|
providerConnectionKind,
|
|
560
571
|
modelConfigOpen,
|
|
@@ -617,6 +628,8 @@ export const useUiStore = defineStore('ui', () => {
|
|
|
617
628
|
openWorkspaceSettings,
|
|
618
629
|
closeWorkspaceSettings,
|
|
619
630
|
setWorkspaceSettingsTab,
|
|
631
|
+
openAccountSettings,
|
|
632
|
+
closeAccountSettings,
|
|
620
633
|
openObservabilityConnection,
|
|
621
634
|
closeObservabilityConnection,
|
|
622
635
|
openProviderConnection,
|
package/app/types/domain.ts
CHANGED
|
@@ -512,6 +512,10 @@ export interface WorkspaceSettings {
|
|
|
512
512
|
storeAgentContext: boolean
|
|
513
513
|
/** Whether the Kaizen agent grades agent steps after each run. On by default. */
|
|
514
514
|
kaizenEnabled: boolean
|
|
515
|
+
/** Local mode only: dispatch container agents to the runner pool instead of host Docker. */
|
|
516
|
+
delegateAgentsToRunnerPool: boolean
|
|
517
|
+
/** Local mode only: provision Tester environments via the env provider instead of DinD. */
|
|
518
|
+
delegateTestEnvToProvider: boolean
|
|
515
519
|
/** Spend budget currency (ISO 4217). Null ⇒ the built-in default (`EUR`). */
|
|
516
520
|
spendCurrency: string | null
|
|
517
521
|
/** Monthly spend budget in `spendCurrency`. Null ⇒ the built-in default. */
|
|
@@ -526,6 +530,8 @@ export interface UpdateWorkspaceSettingsInput {
|
|
|
526
530
|
taskLimitPerType?: Partial<Record<CreateTaskType, number>> | null
|
|
527
531
|
storeAgentContext?: boolean
|
|
528
532
|
kaizenEnabled?: boolean
|
|
533
|
+
delegateAgentsToRunnerPool?: boolean
|
|
534
|
+
delegateTestEnvToProvider?: boolean
|
|
529
535
|
spendCurrency?: string | null
|
|
530
536
|
spendMonthlyLimit?: number | null
|
|
531
537
|
}
|
package/nuxt.config.ts
CHANGED
|
@@ -49,7 +49,6 @@ export default defineNuxtConfig({
|
|
|
49
49
|
css: [
|
|
50
50
|
'@vue-flow/core/dist/style.css',
|
|
51
51
|
'@vue-flow/core/dist/theme-default.css',
|
|
52
|
-
'@vue-flow/controls/dist/style.css',
|
|
53
52
|
'@vue-flow/minimap/dist/style.css',
|
|
54
53
|
'@vue-flow/node-resizer/dist/style.css',
|
|
55
54
|
join(layerDir, 'app/assets/css/main.css'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
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",
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"@nuxt/ui": "^4.9.0",
|
|
21
21
|
"@pinia/nuxt": "^0.11.3",
|
|
22
22
|
"@vue-flow/background": "^1.3.2",
|
|
23
|
-
"@vue-flow/controls": "^1.1.3",
|
|
24
23
|
"@vue-flow/core": "^1.48.2",
|
|
25
24
|
"@vue-flow/minimap": "^1.5.4",
|
|
26
25
|
"@vue-flow/node-resizer": "^1.5.1",
|