@cat-factory/app 0.75.2 → 0.77.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/TaskDependencyEdges.vue +64 -0
- package/app/components/panels/InspectorPanel.vue +4 -0
- package/app/components/panels/inspector/FrontendConfig.vue +536 -269
- package/app/components/panels/inspector/ServiceConnections.vue +151 -0
- package/app/components/panels/inspector/TaskRunSettings.vue +66 -0
- package/app/composables/api/infraHandlers.ts +6 -0
- package/app/stores/infraConfig.ts +11 -0
- package/app/types/domain.ts +3 -0
- package/i18n/locales/en.json +37 -2
- package/i18n/locales/es.json +37 -2
- package/i18n/locales/fr.json +37 -2
- package/i18n/locales/he.json +37 -2
- package/i18n/locales/ja.json +37 -2
- package/i18n/locales/pl.json +37 -2
- package/i18n/locales/tr.json +37 -2
- package/i18n/locales/uk.json +37 -2
- package/package.json +2 -2
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import type { Block, ServiceConnection } from '~/types/domain'
|
|
4
|
+
|
|
5
|
+
// Service-frame (`type: 'service'`) connections: the other services this one USES
|
|
6
|
+
// (consumer→provider edges, stored on this frame — the consumer end). Each row picks a
|
|
7
|
+
// provider service frame and optionally describes the relationship (folded into agent
|
|
8
|
+
// prompts when the provider is involved in a task). The rows ARE the board's
|
|
9
|
+
// service→service links, and the source of a task's "involved services" choices.
|
|
10
|
+
// Persisted as serviceConnections on the block via the shared updateBlock PATCH.
|
|
11
|
+
// The read-only "Used by" list below is the reverse direction, computed from the
|
|
12
|
+
// OTHER frames' connections targeting this one.
|
|
13
|
+
const props = defineProps<{ block: Block }>()
|
|
14
|
+
|
|
15
|
+
const board = useBoardStore()
|
|
16
|
+
const { t } = useI18n()
|
|
17
|
+
|
|
18
|
+
const connections = computed<ServiceConnection[]>(() => props.block.serviceConnections ?? [])
|
|
19
|
+
|
|
20
|
+
function save(next: ServiceConnection[]) {
|
|
21
|
+
board.updateBlock(props.block.id, { serviceConnections: next })
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Provider candidates: every OTHER service frame on the board. A frame already used by
|
|
25
|
+
// another row is excluded per row (duplicates are rejected server-side too).
|
|
26
|
+
const serviceFrames = computed(() =>
|
|
27
|
+
board.frames.filter((b) => b.type === 'service' && b.id !== props.block.id),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
function targetItems(index: number) {
|
|
31
|
+
const takenElsewhere = new Set(
|
|
32
|
+
connections.value.filter((_, i) => i !== index).map((c) => c.serviceBlockId),
|
|
33
|
+
)
|
|
34
|
+
return serviceFrames.value
|
|
35
|
+
.filter((f) => !takenElsewhere.has(f.id))
|
|
36
|
+
.map((f) => ({ label: f.title || f.id, value: f.id }))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function replaceConnection(index: number, next: ServiceConnection) {
|
|
40
|
+
save(connections.value.map((c, i) => (i === index ? next : c)))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function setTarget(index: number, serviceBlockId: string) {
|
|
44
|
+
const c = connections.value[index]
|
|
45
|
+
if (c) replaceConnection(index, { ...c, serviceBlockId })
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function setDescription(index: number, value: string) {
|
|
49
|
+
const c = connections.value[index]
|
|
50
|
+
if (c) replaceConnection(index, { ...c, description: value.trim() || undefined })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// A new row starts on the first still-available provider; with none available the add
|
|
54
|
+
// button is disabled, so a placeholder row never round-trips an invalid PATCH.
|
|
55
|
+
const nextAvailable = computed(() => {
|
|
56
|
+
const taken = new Set(connections.value.map((c) => c.serviceBlockId))
|
|
57
|
+
return serviceFrames.value.find((f) => !taken.has(f.id))
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
function addConnection() {
|
|
61
|
+
const target = nextAvailable.value
|
|
62
|
+
if (target) save([...connections.value, { serviceBlockId: target.id }])
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function removeConnection(index: number) {
|
|
66
|
+
save(connections.value.filter((_, i) => i !== index))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Reverse direction, read-only: the service frames whose own connections name this one.
|
|
70
|
+
const usedBy = computed(() =>
|
|
71
|
+
board.frames.filter(
|
|
72
|
+
(b) =>
|
|
73
|
+
b.type === 'service' &&
|
|
74
|
+
b.id !== props.block.id &&
|
|
75
|
+
(b.serviceConnections ?? []).some((c) => c.serviceBlockId === props.block.id),
|
|
76
|
+
),
|
|
77
|
+
)
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<template>
|
|
81
|
+
<div class="space-y-2 border-t border-slate-800 pt-2" data-testid="service-connections">
|
|
82
|
+
<div class="flex items-center justify-between">
|
|
83
|
+
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
84
|
+
{{ t('inspector.serviceConnections.title') }}
|
|
85
|
+
</span>
|
|
86
|
+
<UButton
|
|
87
|
+
size="xs"
|
|
88
|
+
variant="ghost"
|
|
89
|
+
color="neutral"
|
|
90
|
+
icon="i-lucide-plus"
|
|
91
|
+
:disabled="!nextAvailable"
|
|
92
|
+
data-testid="service-connection-add"
|
|
93
|
+
@click="addConnection"
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
<p class="text-[11px] leading-snug text-slate-500">
|
|
97
|
+
{{ t('inspector.serviceConnections.hint') }}
|
|
98
|
+
</p>
|
|
99
|
+
|
|
100
|
+
<div v-if="connections.length" class="space-y-1.5">
|
|
101
|
+
<div
|
|
102
|
+
v-for="(c, i) in connections"
|
|
103
|
+
:key="c.serviceBlockId"
|
|
104
|
+
class="flex items-center gap-1"
|
|
105
|
+
data-testid="service-connection-row"
|
|
106
|
+
>
|
|
107
|
+
<USelect
|
|
108
|
+
:model-value="c.serviceBlockId"
|
|
109
|
+
:items="targetItems(i)"
|
|
110
|
+
size="xs"
|
|
111
|
+
class="flex-1"
|
|
112
|
+
data-testid="service-connection-target"
|
|
113
|
+
@update:model-value="(v: string) => setTarget(i, v)"
|
|
114
|
+
/>
|
|
115
|
+
<UInput
|
|
116
|
+
:model-value="c.description ?? ''"
|
|
117
|
+
size="xs"
|
|
118
|
+
class="flex-1"
|
|
119
|
+
maxlength="300"
|
|
120
|
+
:placeholder="t('inspector.serviceConnections.descriptionPlaceholder')"
|
|
121
|
+
data-testid="service-connection-description"
|
|
122
|
+
@blur="(e: FocusEvent) => setDescription(i, (e.target as HTMLInputElement).value)"
|
|
123
|
+
@keydown.enter="
|
|
124
|
+
(e: KeyboardEvent) => setDescription(i, (e.target as HTMLInputElement).value)
|
|
125
|
+
"
|
|
126
|
+
/>
|
|
127
|
+
<UButton
|
|
128
|
+
size="xs"
|
|
129
|
+
variant="ghost"
|
|
130
|
+
color="neutral"
|
|
131
|
+
icon="i-lucide-x"
|
|
132
|
+
:title="t('inspector.serviceConnections.remove')"
|
|
133
|
+
data-testid="service-connection-remove"
|
|
134
|
+
@click="removeConnection(i)"
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
<div v-else class="text-[11px] text-slate-500">
|
|
139
|
+
{{ t('inspector.serviceConnections.empty') }}
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div v-if="usedBy.length" class="space-y-1" data-testid="service-connections-used-by">
|
|
143
|
+
<span class="text-[11px] text-slate-400">{{ t('inspector.serviceConnections.usedBy') }}</span>
|
|
144
|
+
<div class="flex flex-wrap gap-1">
|
|
145
|
+
<UBadge v-for="f in usedBy" :key="f.id" size="sm" variant="soft" color="neutral">
|
|
146
|
+
{{ f.title || f.id }}
|
|
147
|
+
</UBadge>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</template>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, onMounted } from 'vue'
|
|
3
|
+
import { connectionNeighborIds } from '@cat-factory/contracts'
|
|
3
4
|
import type { Block } from '~/types/domain'
|
|
4
5
|
import type { WritebackOverride } from '~/types/tracker'
|
|
5
6
|
import { mergePresetOptionLabel, mergePresetThresholds } from '~/utils/mergePreset'
|
|
@@ -154,6 +155,33 @@ function setPipeline(id: string) {
|
|
|
154
155
|
board.updateBlock(props.block.id, { pipelineId: id })
|
|
155
156
|
}
|
|
156
157
|
|
|
158
|
+
// ---- involved services ------------------------------------------------------
|
|
159
|
+
// Which of the connected services are directly involved in this task (beyond its own
|
|
160
|
+
// service, which is always implicit): each involved service is spun up as an ephemeral
|
|
161
|
+
// environment alongside it, and the coding agent may change its repo too. Choices come
|
|
162
|
+
// from the frame's connection NEIGHBORS (either direction). An id whose connection was
|
|
163
|
+
// removed after selection is stale: badged, and dropped on the next toggle (the write
|
|
164
|
+
// gate would reject it).
|
|
165
|
+
const connectedServices = computed(() => {
|
|
166
|
+
const frame = taskFrame.value
|
|
167
|
+
if (!frame) return []
|
|
168
|
+
return [...connectionNeighborIds(board.blocks, frame.id)]
|
|
169
|
+
.map((id) => board.getBlock(id))
|
|
170
|
+
.filter((b): b is Block => !!b)
|
|
171
|
+
})
|
|
172
|
+
const involvedIds = computed(() => props.block.involvedServiceIds ?? [])
|
|
173
|
+
const staleInvolvedServices = computed(() => {
|
|
174
|
+
const connected = new Set(connectedServices.value.map((b) => b.id))
|
|
175
|
+
return involvedIds.value.filter((id) => !connected.has(id))
|
|
176
|
+
})
|
|
177
|
+
function toggleInvolved(serviceId: string, on: boolean) {
|
|
178
|
+
const connected = new Set(connectedServices.value.map((b) => b.id))
|
|
179
|
+
const kept = involvedIds.value.filter((id) => id !== serviceId && connected.has(id))
|
|
180
|
+
board.updateBlock(props.block.id, {
|
|
181
|
+
involvedServiceIds: on ? [...kept, serviceId] : kept,
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
157
185
|
// ---- issue-tracker writeback overrides -------------------------------------
|
|
158
186
|
// Per-task overrides for the two workspace writeback toggles (comment on PR open,
|
|
159
187
|
// close linked issue on merge). null override ⇒ inherit the workspace default.
|
|
@@ -400,6 +428,44 @@ const technicalLabel = computed(() => {
|
|
|
400
428
|
</div>
|
|
401
429
|
</div>
|
|
402
430
|
|
|
431
|
+
<!-- involved services: connected services this task spans (envs + possible code changes) -->
|
|
432
|
+
<div data-testid="involved-services">
|
|
433
|
+
<div class="mb-1 flex items-center justify-between">
|
|
434
|
+
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
435
|
+
{{ t('inspector.runSettings.involvedServices') }}
|
|
436
|
+
</span>
|
|
437
|
+
</div>
|
|
438
|
+
<div v-if="connectedServices.length" class="space-y-1">
|
|
439
|
+
<UCheckbox
|
|
440
|
+
v-for="s in connectedServices"
|
|
441
|
+
:key="s.id"
|
|
442
|
+
:model-value="involvedIds.includes(s.id)"
|
|
443
|
+
:label="s.title || s.id"
|
|
444
|
+
size="xs"
|
|
445
|
+
data-testid="involved-service-toggle"
|
|
446
|
+
@update:model-value="(v: boolean | 'indeterminate') => toggleInvolved(s.id, v === true)"
|
|
447
|
+
/>
|
|
448
|
+
</div>
|
|
449
|
+
<div v-else class="text-[11px] text-slate-500">
|
|
450
|
+
{{ t('inspector.runSettings.involvedServicesEmpty') }}
|
|
451
|
+
</div>
|
|
452
|
+
<div v-if="staleInvolvedServices.length" class="mt-1 flex flex-wrap gap-1">
|
|
453
|
+
<UBadge
|
|
454
|
+
v-for="id in staleInvolvedServices"
|
|
455
|
+
:key="id"
|
|
456
|
+
size="sm"
|
|
457
|
+
variant="soft"
|
|
458
|
+
color="warning"
|
|
459
|
+
:title="t('inspector.runSettings.involvedServiceStale')"
|
|
460
|
+
>
|
|
461
|
+
{{ board.getBlock(id)?.title ?? id }}
|
|
462
|
+
</UBadge>
|
|
463
|
+
</div>
|
|
464
|
+
<div class="mt-1 text-[11px] text-slate-500">
|
|
465
|
+
{{ t('inspector.runSettings.involvedServicesHint') }}
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
|
|
403
469
|
<!-- issue-tracker writeback overrides -->
|
|
404
470
|
<div>
|
|
405
471
|
<div class="mb-1 flex items-center justify-between">
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
detectFrontendConfigContract,
|
|
2
3
|
detectServiceProvisioningContract,
|
|
3
4
|
listEnvironmentHandlersContract,
|
|
4
5
|
listEnvironmentUserHandlersContract,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
upsertEnvironmentUserHandlerContract,
|
|
13
14
|
} from '@cat-factory/contracts'
|
|
14
15
|
import type {
|
|
16
|
+
DetectFrontendConfigInput,
|
|
15
17
|
DetectServiceProvisioningInput,
|
|
16
18
|
ProvisionType,
|
|
17
19
|
RegisterEnvironmentHandlerInput,
|
|
@@ -47,6 +49,10 @@ export function infraHandlersApi({ send, ws }: ApiContext) {
|
|
|
47
49
|
detectServiceProvisioning: (workspaceId: string, body: DetectServiceProvisioningInput) =>
|
|
48
50
|
send(detectServiceProvisioningContract, { pathPrefix: ws(workspaceId), body }),
|
|
49
51
|
|
|
52
|
+
// Auto-detect a non-binding recommended frontend config from a frontend repo.
|
|
53
|
+
detectFrontendConfig: (workspaceId: string, body: DetectFrontendConfigInput) =>
|
|
54
|
+
send(detectFrontendConfigContract, { pathPrefix: ws(workspaceId), body }),
|
|
55
|
+
|
|
50
56
|
// Generate/fix a service's custom manifest via the fixer coding agent (async repair run).
|
|
51
57
|
repairCustomManifest: (workspaceId: string, body: RepairCustomManifestInput) =>
|
|
52
58
|
send(repairCustomManifestContract, { pathPrefix: ws(workspaceId), body }),
|
|
@@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
|
|
|
2
2
|
import { ref, type Ref } from 'vue'
|
|
3
3
|
import type {
|
|
4
4
|
CustomManifestType,
|
|
5
|
+
DetectFrontendConfigInput,
|
|
5
6
|
DetectServiceProvisioningInput,
|
|
6
7
|
EnvironmentHandlerView,
|
|
7
8
|
ProvisionType,
|
|
@@ -113,6 +114,15 @@ export const useInfraConfigStore = defineStore('infraConfig', () => {
|
|
|
113
114
|
return api.detectServiceProvisioning(ws.requireId(), input)
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Auto-detect a NON-BINDING recommended frontend config from a frontend repo. The SPA prefills a
|
|
119
|
+
* preview the user applies; nothing is persisted server-side. Pure repo introspection.
|
|
120
|
+
*/
|
|
121
|
+
async function detectFrontendConfig(input: DetectFrontendConfigInput) {
|
|
122
|
+
const ws = useWorkspaceStore()
|
|
123
|
+
return api.detectFrontendConfig(ws.requireId(), input)
|
|
124
|
+
}
|
|
125
|
+
|
|
116
126
|
/**
|
|
117
127
|
* Generate (or fix) a service's custom manifest via the fixer coding agent. Dispatches a
|
|
118
128
|
* durable async repair run and returns immediately with `usedAgent`/`repairJobId`; the run is
|
|
@@ -192,6 +202,7 @@ export const useInfraConfigStore = defineStore('infraConfig', () => {
|
|
|
192
202
|
registerHandler,
|
|
193
203
|
testHandler,
|
|
194
204
|
detectProvisioning,
|
|
205
|
+
detectFrontendConfig,
|
|
195
206
|
repairCustomManifest,
|
|
196
207
|
unregisterHandler,
|
|
197
208
|
upsertCustomType,
|
package/app/types/domain.ts
CHANGED
|
@@ -33,10 +33,13 @@ export type {
|
|
|
33
33
|
FrontendConfig,
|
|
34
34
|
FrontendBackendBinding,
|
|
35
35
|
FrontendBackendSource,
|
|
36
|
+
ServiceConnection,
|
|
36
37
|
FrontendBranch,
|
|
37
38
|
FrontendPackageManager,
|
|
38
39
|
FrontendServeMode,
|
|
39
40
|
FrontendEnvInjection,
|
|
41
|
+
FrontendConfigRecommendation,
|
|
42
|
+
FrontendDetectionNote,
|
|
40
43
|
AgentConfigOption,
|
|
41
44
|
AgentConfigDescriptor,
|
|
42
45
|
TestConcernSeverity,
|
package/i18n/locales/en.json
CHANGED
|
@@ -485,14 +485,37 @@
|
|
|
485
485
|
"frontendConfig": {
|
|
486
486
|
"title": "Frontend",
|
|
487
487
|
"hint": "How to build, serve, and mock this frontend for a self-contained UI test. Bindings below link it to the backend services it calls.",
|
|
488
|
+
"detect": {
|
|
489
|
+
"title": "Detect from repo",
|
|
490
|
+
"button": "Detect",
|
|
491
|
+
"hint": "Read the linked repo and propose a config to review before applying. Nothing is saved until you apply.",
|
|
492
|
+
"error": "Couldn't read the repo. Check the frontend is linked to a connected repository.",
|
|
493
|
+
"none": "Nothing frontend-shaped was detected. Set the frontend directory (for a monorepo) or fill the fields in manually.",
|
|
494
|
+
"apply": "Apply",
|
|
495
|
+
"dismiss": "Dismiss",
|
|
496
|
+
"confidenceHigh": "sure",
|
|
497
|
+
"confidenceLow": "guess"
|
|
498
|
+
},
|
|
499
|
+
"groups": {
|
|
500
|
+
"build": "Build",
|
|
501
|
+
"serve": "Serve",
|
|
502
|
+
"mocking": "Mocking",
|
|
503
|
+
"envInjection": "Env injection",
|
|
504
|
+
"bindings": "Backend bindings",
|
|
505
|
+
"preview": "Preview"
|
|
506
|
+
},
|
|
488
507
|
"packageManager": "Package manager",
|
|
508
|
+
"directory": "Frontend directory",
|
|
509
|
+
"directoryHint": "The frontend app's subfolder in the repo (a monorepo, e.g. frontend/). Leave empty if the app is at the repo root.",
|
|
489
510
|
"installCommand": "Install command",
|
|
490
511
|
"buildScript": "Build script",
|
|
491
512
|
"outputDir": "Output directory",
|
|
492
513
|
"serveMode": "Serve mode",
|
|
493
514
|
"serveStatic": "Static",
|
|
494
515
|
"serveCommand": "Command",
|
|
495
|
-
"
|
|
516
|
+
"serveStaticDesc": "serves the built output directory as static files. Cheapest for a UI test of a fully built app.",
|
|
517
|
+
"serveCommandDesc": "runs a package.json script (e.g. preview) to serve the app, for builds that need a running server.",
|
|
518
|
+
"serveEnvAxisNote": "Separate from Env injection (build-time vs runtime) below, which controls how backend URLs reach the app, not how it is served.",
|
|
496
519
|
"serveScript": "Serve script",
|
|
497
520
|
"servePort": "Serve port",
|
|
498
521
|
"mockMappingsPath": "Mock mappings path",
|
|
@@ -523,6 +546,14 @@
|
|
|
523
546
|
}
|
|
524
547
|
}
|
|
525
548
|
},
|
|
549
|
+
"serviceConnections": {
|
|
550
|
+
"title": "Service connections",
|
|
551
|
+
"hint": "The other services this one uses, e.g. a service that sends its emails. Connections draw edges on the board, and tasks can mark a connected service as directly involved.",
|
|
552
|
+
"descriptionPlaceholder": "How this service uses it, e.g. sends emails via it",
|
|
553
|
+
"remove": "Remove connection",
|
|
554
|
+
"empty": "No connections. Add one to link this service to another service it uses.",
|
|
555
|
+
"usedBy": "Used by"
|
|
556
|
+
},
|
|
526
557
|
"releaseHealth": {
|
|
527
558
|
"title": "Post-release health",
|
|
528
559
|
"clear": "Clear",
|
|
@@ -746,7 +777,11 @@
|
|
|
746
777
|
"responsibleProduct": "Responsible product",
|
|
747
778
|
"responsibleEmpty": "Unassigned. Set a product owner to notify them when requirement review flags this task.",
|
|
748
779
|
"autoStartDependents": "Auto-start dependents",
|
|
749
|
-
"autoStartHint": "When this task merges, automatically start the tasks that depend on it (once their other dependencies are also done)."
|
|
780
|
+
"autoStartHint": "When this task merges, automatically start the tasks that depend on it (once their other dependencies are also done).",
|
|
781
|
+
"involvedServices": "Involved services",
|
|
782
|
+
"involvedServicesHint": "Connected services directly involved in this task: each spins up as an ephemeral environment alongside this task's own service, and the coding agent may change their repositories too.",
|
|
783
|
+
"involvedServicesEmpty": "No connected services. Connect services on the service frame to select them here.",
|
|
784
|
+
"involvedServiceStale": "No longer connected to this task's service; it is dropped on the next change."
|
|
750
785
|
}
|
|
751
786
|
},
|
|
752
787
|
"panels": {
|
package/i18n/locales/es.json
CHANGED
|
@@ -442,14 +442,37 @@
|
|
|
442
442
|
"frontendConfig": {
|
|
443
443
|
"title": "Frontend",
|
|
444
444
|
"hint": "Cómo compilar, servir y simular este frontend para una prueba de interfaz autónoma. Las vinculaciones de abajo lo conectan con los servicios de backend a los que llama.",
|
|
445
|
+
"detect": {
|
|
446
|
+
"title": "Detectar del repositorio",
|
|
447
|
+
"button": "Detectar",
|
|
448
|
+
"hint": "Lee el repositorio vinculado y propone una configuración para revisar antes de aplicar. No se guarda nada hasta que la apliques.",
|
|
449
|
+
"error": "No se pudo leer el repositorio. Comprueba que el frontend esté vinculado a un repositorio conectado.",
|
|
450
|
+
"none": "No se detectó nada con forma de frontend. Indica el directorio del frontend (para un monorepo) o rellena los campos manualmente.",
|
|
451
|
+
"apply": "Aplicar",
|
|
452
|
+
"dismiss": "Descartar",
|
|
453
|
+
"confidenceHigh": "seguro",
|
|
454
|
+
"confidenceLow": "estimación"
|
|
455
|
+
},
|
|
456
|
+
"groups": {
|
|
457
|
+
"build": "Compilación",
|
|
458
|
+
"serve": "Servicio",
|
|
459
|
+
"mocking": "Simulación",
|
|
460
|
+
"envInjection": "Inyección de entorno",
|
|
461
|
+
"bindings": "Vinculaciones de backend",
|
|
462
|
+
"preview": "Vista previa"
|
|
463
|
+
},
|
|
445
464
|
"packageManager": "Gestor de paquetes",
|
|
465
|
+
"directory": "Directorio del frontend",
|
|
466
|
+
"directoryHint": "La subcarpeta de la app frontend en el repositorio (un monorepo, p. ej. frontend/). Déjalo vacío si la app está en la raíz del repositorio.",
|
|
446
467
|
"installCommand": "Comando de instalación",
|
|
447
468
|
"buildScript": "Script de compilación",
|
|
448
469
|
"outputDir": "Directorio de salida",
|
|
449
470
|
"serveMode": "Modo de servicio",
|
|
450
471
|
"serveStatic": "Estático",
|
|
451
472
|
"serveCommand": "Comando",
|
|
452
|
-
"
|
|
473
|
+
"serveStaticDesc": "sirve el directorio de salida compilado como archivos estáticos. Lo más económico para una prueba de interfaz de una app ya compilada.",
|
|
474
|
+
"serveCommandDesc": "ejecuta un script de package.json (p. ej. preview) para servir la app, para compilaciones que necesitan un servidor en ejecución.",
|
|
475
|
+
"serveEnvAxisNote": "Distinto de la Inyección de entorno (en compilación vs. en tiempo de ejecución) de abajo, que controla cómo llegan las URL del backend a la app, no cómo se sirve.",
|
|
453
476
|
"serveScript": "Script de servicio",
|
|
454
477
|
"servePort": "Puerto de servicio",
|
|
455
478
|
"mockMappingsPath": "Ruta de asignaciones de simulación",
|
|
@@ -480,6 +503,14 @@
|
|
|
480
503
|
}
|
|
481
504
|
}
|
|
482
505
|
},
|
|
506
|
+
"serviceConnections": {
|
|
507
|
+
"title": "Conexiones de servicios",
|
|
508
|
+
"hint": "Los otros servicios que este utiliza, p. ej. un servicio que envía sus correos. Las conexiones dibujan aristas en el tablero, y las tareas pueden marcar un servicio conectado como directamente involucrado.",
|
|
509
|
+
"descriptionPlaceholder": "Cómo lo usa este servicio, p. ej. envía correos a través de él",
|
|
510
|
+
"remove": "Eliminar conexión",
|
|
511
|
+
"empty": "Sin conexiones. Añade una para vincular este servicio con otro servicio que utiliza.",
|
|
512
|
+
"usedBy": "Usado por"
|
|
513
|
+
},
|
|
483
514
|
"releaseHealth": {
|
|
484
515
|
"title": "Salud posterior al lanzamiento",
|
|
485
516
|
"clear": "Limpiar",
|
|
@@ -703,7 +734,11 @@
|
|
|
703
734
|
"responsibleProduct": "Producto responsable",
|
|
704
735
|
"responsibleEmpty": "Sin asignar. Define un responsable de producto para notificarle cuando la revisión de requisitos marque esta tarea.",
|
|
705
736
|
"autoStartDependents": "Iniciar dependientes automáticamente",
|
|
706
|
-
"autoStartHint": "Cuando esta tarea se fusione, inicia automáticamente las tareas que dependen de ella (una vez que sus otras dependencias también estén completas)."
|
|
737
|
+
"autoStartHint": "Cuando esta tarea se fusione, inicia automáticamente las tareas que dependen de ella (una vez que sus otras dependencias también estén completas).",
|
|
738
|
+
"involvedServices": "Servicios involucrados",
|
|
739
|
+
"involvedServicesHint": "Servicios conectados directamente involucrados en esta tarea: cada uno se levanta como un entorno efímero junto al servicio propio de la tarea, y el agente de código puede modificar también sus repositorios.",
|
|
740
|
+
"involvedServicesEmpty": "No hay servicios conectados. Conecta servicios en el marco del servicio para seleccionarlos aquí.",
|
|
741
|
+
"involvedServiceStale": "Ya no está conectado al servicio de esta tarea; se eliminará con el próximo cambio."
|
|
707
742
|
}
|
|
708
743
|
},
|
|
709
744
|
"panels": {
|
package/i18n/locales/fr.json
CHANGED
|
@@ -442,14 +442,37 @@
|
|
|
442
442
|
"frontendConfig": {
|
|
443
443
|
"title": "Frontend",
|
|
444
444
|
"hint": "Comment compiler, servir et simuler ce frontend pour un test d'interface autonome. Les liaisons ci-dessous le relient aux services de backend qu'il appelle.",
|
|
445
|
+
"detect": {
|
|
446
|
+
"title": "Détecter depuis le dépôt",
|
|
447
|
+
"button": "Détecter",
|
|
448
|
+
"hint": "Lit le dépôt lié et propose une configuration à vérifier avant application. Rien n'est enregistré tant que vous n'appliquez pas.",
|
|
449
|
+
"error": "Impossible de lire le dépôt. Vérifiez que le frontend est lié à un dépôt connecté.",
|
|
450
|
+
"none": "Aucun élément de type frontend détecté. Indiquez le répertoire du frontend (pour un monorepo) ou renseignez les champs manuellement.",
|
|
451
|
+
"apply": "Appliquer",
|
|
452
|
+
"dismiss": "Ignorer",
|
|
453
|
+
"confidenceHigh": "sûr",
|
|
454
|
+
"confidenceLow": "estimation"
|
|
455
|
+
},
|
|
456
|
+
"groups": {
|
|
457
|
+
"build": "Compilation",
|
|
458
|
+
"serve": "Service",
|
|
459
|
+
"mocking": "Simulation",
|
|
460
|
+
"envInjection": "Injection d'environnement",
|
|
461
|
+
"bindings": "Liaisons backend",
|
|
462
|
+
"preview": "Aperçu"
|
|
463
|
+
},
|
|
445
464
|
"packageManager": "Gestionnaire de paquets",
|
|
465
|
+
"directory": "Répertoire du frontend",
|
|
466
|
+
"directoryHint": "Le sous-dossier de l'app frontend dans le dépôt (un monorepo, p. ex. frontend/). Laissez vide si l'app est à la racine du dépôt.",
|
|
446
467
|
"installCommand": "Commande d'installation",
|
|
447
468
|
"buildScript": "Script de compilation",
|
|
448
469
|
"outputDir": "Répertoire de sortie",
|
|
449
470
|
"serveMode": "Mode de service",
|
|
450
471
|
"serveStatic": "Statique",
|
|
451
472
|
"serveCommand": "Commande",
|
|
452
|
-
"
|
|
473
|
+
"serveStaticDesc": "sert le répertoire de sortie compilé en fichiers statiques. Le plus économique pour un test d'interface d'une app entièrement compilée.",
|
|
474
|
+
"serveCommandDesc": "exécute un script de package.json (p. ex. preview) pour servir l'app, pour les compilations nécessitant un serveur en fonctionnement.",
|
|
475
|
+
"serveEnvAxisNote": "Distinct de l'Injection d'environnement (à la compilation vs à l'exécution) ci-dessous, qui contrôle comment les URL du backend atteignent l'app, pas comment elle est servie.",
|
|
453
476
|
"serveScript": "Script de service",
|
|
454
477
|
"servePort": "Port de service",
|
|
455
478
|
"mockMappingsPath": "Chemin des mappages de simulation",
|
|
@@ -480,6 +503,14 @@
|
|
|
480
503
|
}
|
|
481
504
|
}
|
|
482
505
|
},
|
|
506
|
+
"serviceConnections": {
|
|
507
|
+
"title": "Connexions de services",
|
|
508
|
+
"hint": "Les autres services que celui-ci utilise, p. ex. un service qui envoie ses e-mails. Les connexions tracent des liens sur le tableau, et les tâches peuvent marquer un service connecté comme directement impliqué.",
|
|
509
|
+
"descriptionPlaceholder": "Comment ce service l'utilise, p. ex. envoie des e-mails via lui",
|
|
510
|
+
"remove": "Supprimer la connexion",
|
|
511
|
+
"empty": "Aucune connexion. Ajoutez-en une pour relier ce service à un autre service qu'il utilise.",
|
|
512
|
+
"usedBy": "Utilisé par"
|
|
513
|
+
},
|
|
483
514
|
"releaseHealth": {
|
|
484
515
|
"title": "Santé post-déploiement",
|
|
485
516
|
"clear": "Effacer",
|
|
@@ -703,7 +734,11 @@
|
|
|
703
734
|
"responsibleProduct": "Produit responsable",
|
|
704
735
|
"responsibleEmpty": "Non assigné. Définissez un responsable produit pour le notifier lorsque la revue d'exigences signale cette tâche.",
|
|
705
736
|
"autoStartDependents": "Démarrer automatiquement les dépendants",
|
|
706
|
-
"autoStartHint": "Lorsque cette tâche est fusionnée, démarrer automatiquement les tâches qui en dépendent (une fois que leurs autres dépendances sont également terminées)."
|
|
737
|
+
"autoStartHint": "Lorsque cette tâche est fusionnée, démarrer automatiquement les tâches qui en dépendent (une fois que leurs autres dépendances sont également terminées).",
|
|
738
|
+
"involvedServices": "Services impliqués",
|
|
739
|
+
"involvedServicesHint": "Services connectés directement impliqués dans cette tâche : chacun démarre comme environnement éphémère aux côtés du service propre de la tâche, et l'agent de code peut aussi modifier leurs dépôts.",
|
|
740
|
+
"involvedServicesEmpty": "Aucun service connecté. Connectez des services sur le cadre du service pour les sélectionner ici.",
|
|
741
|
+
"involvedServiceStale": "N'est plus connecté au service de cette tâche ; il sera retiré au prochain changement."
|
|
707
742
|
}
|
|
708
743
|
},
|
|
709
744
|
"panels": {
|
package/i18n/locales/he.json
CHANGED
|
@@ -442,14 +442,37 @@
|
|
|
442
442
|
"frontendConfig": {
|
|
443
443
|
"title": "Frontend",
|
|
444
444
|
"hint": "כיצד לבנות, להגיש ולדמות את ה-frontend הזה לבדיקת ממשק עצמאית. הקישורים למטה מחברים אותו לשירותי ה-backend שהוא קורא אליהם.",
|
|
445
|
+
"detect": {
|
|
446
|
+
"title": "זהה מהמאגר",
|
|
447
|
+
"button": "זהה",
|
|
448
|
+
"hint": "קורא את המאגר המקושר ומציע תצורה לבדיקה לפני החלה. שום דבר לא נשמר עד שתחיל.",
|
|
449
|
+
"error": "לא ניתן לקרוא את המאגר. ודא שה-frontend מקושר למאגר מחובר.",
|
|
450
|
+
"none": "לא זוהה דבר בעל מבנה frontend. הגדר את תיקיית ה-frontend (עבור monorepo) או מלא את השדות ידנית.",
|
|
451
|
+
"apply": "החל",
|
|
452
|
+
"dismiss": "בטל",
|
|
453
|
+
"confidenceHigh": "בטוח",
|
|
454
|
+
"confidenceLow": "ניחוש"
|
|
455
|
+
},
|
|
456
|
+
"groups": {
|
|
457
|
+
"build": "בנייה",
|
|
458
|
+
"serve": "הגשה",
|
|
459
|
+
"mocking": "הדמיה",
|
|
460
|
+
"envInjection": "הזרקת סביבה",
|
|
461
|
+
"bindings": "קישורי backend",
|
|
462
|
+
"preview": "תצוגה מקדימה"
|
|
463
|
+
},
|
|
445
464
|
"packageManager": "מנהל חבילות",
|
|
465
|
+
"directory": "תיקיית frontend",
|
|
466
|
+
"directoryHint": "תת-התיקייה של אפליקציית ה-frontend במאגר (monorepo, למשל frontend/). השאר ריק אם האפליקציה נמצאת בשורש המאגר.",
|
|
446
467
|
"installCommand": "פקודת התקנה",
|
|
447
468
|
"buildScript": "סקריפט בנייה",
|
|
448
469
|
"outputDir": "תיקיית פלט",
|
|
449
470
|
"serveMode": "מצב הגשה",
|
|
450
471
|
"serveStatic": "סטטי",
|
|
451
472
|
"serveCommand": "פקודה",
|
|
452
|
-
"
|
|
473
|
+
"serveStaticDesc": "מגיש את תיקיית פלט הבנייה כקבצים סטטיים. הזול ביותר לבדיקת ממשק של אפליקציה בנויה במלואה.",
|
|
474
|
+
"serveCommandDesc": "מריץ סקריפט מ-package.json (למשל preview) כדי להגיש את האפליקציה, עבור בנייה הזקוקה לשרת פעיל.",
|
|
475
|
+
"serveEnvAxisNote": "נפרד מהזרקת הסביבה (בזמן בנייה מול זמן ריצה) שלמטה, השולטת כיצד כתובות ה-backend מגיעות לאפליקציה, לא כיצד היא מוגשת.",
|
|
453
476
|
"serveScript": "סקריפט הגשה",
|
|
454
477
|
"servePort": "פורט הגשה",
|
|
455
478
|
"mockMappingsPath": "נתיב מיפויי הדמיה",
|
|
@@ -480,6 +503,14 @@
|
|
|
480
503
|
}
|
|
481
504
|
}
|
|
482
505
|
},
|
|
506
|
+
"serviceConnections": {
|
|
507
|
+
"title": "חיבורי שירותים",
|
|
508
|
+
"hint": "השירותים האחרים שהשירות הזה משתמש בהם, למשל שירות ששולח עבורו הודעות דואר. חיבורים מציירים קשתות על הלוח, ומשימות יכולות לסמן שירות מחובר כמעורב ישירות.",
|
|
509
|
+
"descriptionPlaceholder": "איך השירות הזה משתמש בו, למשל שולח דרכו הודעות דואר",
|
|
510
|
+
"remove": "הסר חיבור",
|
|
511
|
+
"empty": "אין חיבורים. הוסיפו אחד כדי לקשר שירות זה לשירות אחר שהוא משתמש בו.",
|
|
512
|
+
"usedBy": "בשימוש על ידי"
|
|
513
|
+
},
|
|
483
514
|
"releaseHealth": {
|
|
484
515
|
"title": "תקינות לאחר שחרור",
|
|
485
516
|
"clear": "נקה",
|
|
@@ -703,7 +734,11 @@
|
|
|
703
734
|
"responsibleProduct": "מוצר אחראי",
|
|
704
735
|
"responsibleEmpty": "לא משויך. הגדר בעלים של מוצר כדי ליידע אותו כאשר סקירת הדרישות מסמנת משימה זו.",
|
|
705
736
|
"autoStartDependents": "הפעלה אוטומטית של תלויות",
|
|
706
|
-
"autoStartHint": "כאשר משימה זו ממוזגת, הפעל אוטומטית את המשימות התלויות בה (לאחר שגם שאר התלויות שלהן הושלמו)."
|
|
737
|
+
"autoStartHint": "כאשר משימה זו ממוזגת, הפעל אוטומטית את המשימות התלויות בה (לאחר שגם שאר התלויות שלהן הושלמו).",
|
|
738
|
+
"involvedServices": "שירותים מעורבים",
|
|
739
|
+
"involvedServicesHint": "שירותים מחוברים המעורבים ישירות במשימה זו: כל אחד מהם מוקם כסביבה זמנית לצד השירות של המשימה, וסוכן הקוד עשוי לשנות גם את המאגרים שלהם.",
|
|
740
|
+
"involvedServicesEmpty": "אין שירותים מחוברים. חברו שירותים במסגרת השירות כדי לבחור אותם כאן.",
|
|
741
|
+
"involvedServiceStale": "כבר לא מחובר לשירות של משימה זו; הוא יוסר בשינוי הבא."
|
|
707
742
|
}
|
|
708
743
|
},
|
|
709
744
|
"panels": {
|
package/i18n/locales/ja.json
CHANGED
|
@@ -442,14 +442,37 @@
|
|
|
442
442
|
"frontendConfig": {
|
|
443
443
|
"title": "フロントエンド",
|
|
444
444
|
"hint": "自己完結型の UI テストのために、このフロントエンドをビルド、配信、モックする方法。下のバインディングは、呼び出すバックエンドサービスとフロントエンドをつなぎます。",
|
|
445
|
+
"detect": {
|
|
446
|
+
"title": "リポジトリから検出",
|
|
447
|
+
"button": "検出",
|
|
448
|
+
"hint": "リンクされたリポジトリを読み取り、適用前に確認できる設定を提案します。適用するまで何も保存されません。",
|
|
449
|
+
"error": "リポジトリを読み取れませんでした。フロントエンドが接続済みリポジトリにリンクされているか確認してください。",
|
|
450
|
+
"none": "フロントエンドらしきものは検出されませんでした。(モノレポの場合は)フロントエンドのディレクトリを指定するか、手動で入力してください。",
|
|
451
|
+
"apply": "適用",
|
|
452
|
+
"dismiss": "却下",
|
|
453
|
+
"confidenceHigh": "確実",
|
|
454
|
+
"confidenceLow": "推測"
|
|
455
|
+
},
|
|
456
|
+
"groups": {
|
|
457
|
+
"build": "ビルド",
|
|
458
|
+
"serve": "配信",
|
|
459
|
+
"mocking": "モック",
|
|
460
|
+
"envInjection": "環境変数の注入",
|
|
461
|
+
"bindings": "バックエンドバインディング",
|
|
462
|
+
"preview": "プレビュー"
|
|
463
|
+
},
|
|
445
464
|
"packageManager": "パッケージマネージャー",
|
|
465
|
+
"directory": "フロントエンドのディレクトリ",
|
|
466
|
+
"directoryHint": "リポジトリ内のフロントエンドアプリのサブフォルダー(モノレポ、例: frontend/)。アプリがリポジトリのルートにある場合は空のままにします。",
|
|
446
467
|
"installCommand": "インストールコマンド",
|
|
447
468
|
"buildScript": "ビルドスクリプト",
|
|
448
469
|
"outputDir": "出力ディレクトリ",
|
|
449
470
|
"serveMode": "配信モード",
|
|
450
471
|
"serveStatic": "静的",
|
|
451
472
|
"serveCommand": "コマンド",
|
|
452
|
-
"
|
|
473
|
+
"serveStaticDesc": "ビルド出力ディレクトリを静的ファイルとして配信します。完全にビルド済みのアプリの UI テストに最も低コストです。",
|
|
474
|
+
"serveCommandDesc": "package.json のスクリプト(例: preview)を実行してアプリを配信します。サーバーの起動が必要なビルド向けです。",
|
|
475
|
+
"serveEnvAxisNote": "下の環境変数の注入(ビルド時とランタイム)とは別物で、そちらはバックエンド URL がアプリにどう届くかを制御し、配信方法ではありません。",
|
|
453
476
|
"serveScript": "配信スクリプト",
|
|
454
477
|
"servePort": "配信ポート",
|
|
455
478
|
"mockMappingsPath": "モックマッピングのパス",
|
|
@@ -480,6 +503,14 @@
|
|
|
480
503
|
}
|
|
481
504
|
}
|
|
482
505
|
},
|
|
506
|
+
"serviceConnections": {
|
|
507
|
+
"title": "サービス接続",
|
|
508
|
+
"hint": "このサービスが利用する他のサービス(例: メール送信を担うサービス)。接続はボード上にエッジとして描画され、タスクは接続先サービスを直接関与としてマークできます。",
|
|
509
|
+
"descriptionPlaceholder": "このサービスの利用方法(例: これを介してメールを送信)",
|
|
510
|
+
"remove": "接続を削除",
|
|
511
|
+
"empty": "接続はありません。このサービスが利用する別のサービスとリンクするには追加してください。",
|
|
512
|
+
"usedBy": "利用元"
|
|
513
|
+
},
|
|
483
514
|
"releaseHealth": {
|
|
484
515
|
"title": "リリース後の健全性",
|
|
485
516
|
"clear": "クリア",
|
|
@@ -703,7 +734,11 @@
|
|
|
703
734
|
"responsibleProduct": "担当プロダクト",
|
|
704
735
|
"responsibleEmpty": "未割り当て。要件レビューがこのタスクをフラグしたときに通知するため、プロダクトオーナーを設定してください。",
|
|
705
736
|
"autoStartDependents": "依存タスクを自動開始",
|
|
706
|
-
"autoStartHint": "このタスクがマージされたら、それに依存するタスクを (他の依存関係も完了したら) 自動的に開始します。"
|
|
737
|
+
"autoStartHint": "このタスクがマージされたら、それに依存するタスクを (他の依存関係も完了したら) 自動的に開始します。",
|
|
738
|
+
"involvedServices": "関与するサービス",
|
|
739
|
+
"involvedServicesHint": "このタスクに直接関与する接続済みサービス。各サービスはタスク自身のサービスと並んで一時的な環境として起動され、コーディングエージェントがそのリポジトリを変更することもあります。",
|
|
740
|
+
"involvedServicesEmpty": "接続済みのサービスはありません。ここで選択するには、サービスフレームでサービスを接続してください。",
|
|
741
|
+
"involvedServiceStale": "このタスクのサービスとの接続が解除されています。次回の変更時に削除されます。"
|
|
707
742
|
}
|
|
708
743
|
},
|
|
709
744
|
"panels": {
|