@cat-factory/app 0.196.1 → 0.198.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/README.md +105 -0
- package/app/components/github/AddServiceFromRepoModal.vue +6 -1
- package/app/components/tutorial/TutorialOverlay.logic.spec.ts +164 -0
- package/app/components/tutorial/TutorialOverlay.logic.ts +125 -0
- package/app/components/tutorial/TutorialOverlay.vue +307 -0
- package/app/components/tutorial/TutorialPrompt.vue +102 -0
- package/app/composables/pipelineErrorToast/bespokeConflicts.ts +181 -0
- package/app/composables/useNavContributions.ts +1 -0
- package/app/composables/usePipelineErrorToast.spec.ts +4 -1
- package/app/composables/usePipelineErrorToast.ts +24 -165
- package/app/composables/useTutorialTours.ts +18 -0
- package/app/modular/nav-contributions.spec.ts +14 -0
- package/app/modular/nav-contributions.ts +70 -0
- package/app/modular/nav-gates.logic.spec.ts +41 -0
- package/app/modular/nav-gates.logic.ts +36 -0
- package/app/modular/nav-gates.ts +54 -0
- package/app/modular/registry.spec.ts +6 -0
- package/app/modular/registry.ts +3 -1
- package/app/modular/slots.ts +7 -0
- package/app/modular/tutorial-tours.spec.ts +222 -0
- package/app/modular/tutorial-tours.ts +421 -0
- package/app/pages/index.vue +61 -0
- package/app/stores/board/dependencies.ts +52 -0
- package/app/stores/board/placement.ts +4 -37
- package/app/stores/execution/pendingGates.ts +109 -0
- package/app/stores/execution.ts +7 -94
- package/app/stores/requirements/recommendations.ts +77 -0
- package/app/stores/requirements.ts +17 -43
- package/app/stores/tutorial.spec.ts +135 -0
- package/app/stores/tutorial.ts +145 -0
- package/app/stores/workspace/commands.ts +77 -0
- package/app/stores/workspace.ts +11 -50
- package/app/utils/tutorial.spec.ts +115 -0
- package/app/utils/tutorial.ts +246 -0
- package/i18n/locales/de.json +209 -2
- package/i18n/locales/en.json +215 -2
- package/i18n/locales/es.json +209 -2
- package/i18n/locales/fr.json +209 -2
- package/i18n/locales/he.json +209 -2
- package/i18n/locales/it.json +209 -2
- package/i18n/locales/ja.json +209 -2
- package/i18n/locales/pl.json +209 -2
- package/i18n/locales/tr.json +209 -2
- package/i18n/locales/uk.json +209 -2
- package/package.json +1 -1
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import type { NavGates } from '~/modular/nav-contributions'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* In-app tutorial tours: the pure data model + geometry, shared by the tour catalog
|
|
5
|
+
* (`modular/tutorial-tours.ts`), the tutorial store, and the coach-mark overlay
|
|
6
|
+
* (`components/tutorial/TutorialOverlay.vue`).
|
|
7
|
+
*
|
|
8
|
+
* A tour is DATA, not components: an ordered list of steps, each pointing at an existing
|
|
9
|
+
* on-screen control by its `data-testid` and carrying i18n keys for what to tell the user.
|
|
10
|
+
* That keeps tours declarative (a consumer deployment contributes its own through the
|
|
11
|
+
* `tutorialTours` slot via `registerAppModule`, exactly like nav items) and keeps the whole
|
|
12
|
+
* runtime — anchor tracking, tooltip placement, advance handling — in ONE overlay component
|
|
13
|
+
* that every tour shares.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** How a step advances to the next one. */
|
|
17
|
+
export type TutorialAdvance =
|
|
18
|
+
/** The user reads and presses the tooltip's Next button (the default). */
|
|
19
|
+
| 'next'
|
|
20
|
+
/**
|
|
21
|
+
* The user clicks the highlighted control itself — the "now click this" steps. The
|
|
22
|
+
* tooltip shows a click hint instead of a Next button, so the app reacts to the real
|
|
23
|
+
* click (opening the real modal, creating the real task) and the tour follows along.
|
|
24
|
+
*/
|
|
25
|
+
| 'target-click'
|
|
26
|
+
|
|
27
|
+
/** Preferred tooltip side relative to the anchor; the overlay falls back when it can't fit. */
|
|
28
|
+
export type TutorialPlacement = 'top' | 'bottom' | 'left' | 'right'
|
|
29
|
+
|
|
30
|
+
export interface TutorialStep {
|
|
31
|
+
/** Stable id, unique within the tour (progress display + specs key off it). */
|
|
32
|
+
id: string
|
|
33
|
+
/**
|
|
34
|
+
* `data-testid` of the control this step points at. Absent = a centered card (intro /
|
|
35
|
+
* wrap-up steps). Reusing the e2e anchor vocabulary is deliberate: those ids are already
|
|
36
|
+
* the stable, behaviour-neutral way to name a control, and a tour stop is the same kind
|
|
37
|
+
* of consumer as a spec.
|
|
38
|
+
*
|
|
39
|
+
* A target names a KIND of control, not one instance: where several are on screen (one
|
|
40
|
+
* `task-card` per task, one `frame-add-task` per service) the first VISIBLE match wins,
|
|
41
|
+
* which may not be the one the user just produced. That is accepted rather than worked
|
|
42
|
+
* around — a tour teaches an affordance, and every match demonstrates the same one — so
|
|
43
|
+
* step copy must read correctly against any of them ("this is a task card", not "this is
|
|
44
|
+
* the task you just made").
|
|
45
|
+
*/
|
|
46
|
+
target?: string
|
|
47
|
+
/**
|
|
48
|
+
* Fallback `data-testid`s tried in order when {@link target} is absent from the DOM —
|
|
49
|
+
* for controls that render under a different id in some states (e.g. a frame's add-task
|
|
50
|
+
* button on an empty frame).
|
|
51
|
+
*/
|
|
52
|
+
altTargets?: readonly string[]
|
|
53
|
+
titleKey: string
|
|
54
|
+
bodyKey: string
|
|
55
|
+
/**
|
|
56
|
+
* Interpolation values for {@link bodyKey}'s `{named}` placeholders.
|
|
57
|
+
*
|
|
58
|
+
* The reason this exists rather than the value living in the catalogs: a step that names
|
|
59
|
+
* something FIXED and untranslatable — the sample repository a tour tells you to search
|
|
60
|
+
* for — would otherwise be spelled out in `en.json` and copied into nine other locales,
|
|
61
|
+
* where it reads as prose to translate and drifts the moment the value changes. Declared
|
|
62
|
+
* here it is written once, in code, beside the tour that needs it.
|
|
63
|
+
*
|
|
64
|
+
* Prose still belongs in the catalog: this is for proper nouns and code-shaped literals,
|
|
65
|
+
* the same split `frontend/app/README.md` states for inline placeholders in components.
|
|
66
|
+
*/
|
|
67
|
+
bodyParams?: Record<string, string | number>
|
|
68
|
+
placement?: TutorialPlacement
|
|
69
|
+
/** Defaults to `'next'`. */
|
|
70
|
+
advanceOn?: TutorialAdvance
|
|
71
|
+
/**
|
|
72
|
+
* How long the overlay waits for the target to appear before SKIPPING the step
|
|
73
|
+
* (ms, default {@link DEFAULT_TARGET_WAIT_MS}). A missing anchor is expected, not an
|
|
74
|
+
* error: the control may be RBAC-hidden, tier-hidden, or simply not part of this
|
|
75
|
+
* deployment, and a tour must degrade to the steps that do apply. Steps whose target
|
|
76
|
+
* only appears after the previous step's click (inside a just-opened modal) may need a
|
|
77
|
+
* longer wait.
|
|
78
|
+
*/
|
|
79
|
+
waitForTargetMs?: number
|
|
80
|
+
/**
|
|
81
|
+
* Applicability gate over the same reactive {@link NavGates} the tour's own `when` reads.
|
|
82
|
+
* A step this rejects is DROPPED from the tour before it runs; absent = always included.
|
|
83
|
+
*
|
|
84
|
+
* Deliberately distinct from the anchor skip above, because the two are different facts
|
|
85
|
+
* and only one of them is a defect in the tour. A skip means "this step's control should
|
|
86
|
+
* be here and isn't", which is what the final card reports as an abridged walkthrough. A
|
|
87
|
+
* `when` says "this branch of the flow is not what this board is doing" — a run parked on
|
|
88
|
+
* a decision has no approval gate to point at, and vice versa. Rendering the second as
|
|
89
|
+
* the first would tell a user who saw exactly the right walkthrough that they missed
|
|
90
|
+
* half of it, every single time.
|
|
91
|
+
*
|
|
92
|
+
* Use it only for a step whose ABSENCE is expected on a legitimate board; an anchor that
|
|
93
|
+
* merely might be slow keeps the wait budget instead.
|
|
94
|
+
*/
|
|
95
|
+
when?: (gates: NavGates) => boolean
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface TutorialTour {
|
|
99
|
+
/** Stable id; completion is persisted against it, so renaming one resets its state. */
|
|
100
|
+
id: string
|
|
101
|
+
titleKey: string
|
|
102
|
+
descriptionKey: string
|
|
103
|
+
icon?: string
|
|
104
|
+
/** Sort key in the tour list; ties break on `id` so the order is deterministic. */
|
|
105
|
+
order: number
|
|
106
|
+
/**
|
|
107
|
+
* Availability gate over the same reactive {@link NavGates} the nav catalog uses, so a
|
|
108
|
+
* tour about a surface the caller can't reach (no board write, no GitHub) never shows.
|
|
109
|
+
* Absent = always offered.
|
|
110
|
+
*/
|
|
111
|
+
when?: (gates: NavGates) => boolean
|
|
112
|
+
steps: readonly TutorialStep[]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** How long the overlay polls for a step's anchor before auto-skipping the step. */
|
|
116
|
+
export const DEFAULT_TARGET_WAIT_MS = 4000
|
|
117
|
+
|
|
118
|
+
/** How often the overlay re-queries / re-measures its anchor (canvas pans, panels open). */
|
|
119
|
+
export const TARGET_TRACK_INTERVAL_MS = 150
|
|
120
|
+
|
|
121
|
+
/** Deterministic tour-list order: `order`, then `id`. */
|
|
122
|
+
export function sortTours(tours: readonly TutorialTour[]): TutorialTour[] {
|
|
123
|
+
return [...tours].sort((a, b) => a.order - b.order || a.id.localeCompare(b.id))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Resolve every tour against the gates: drop the tours whose own `when` rejects them, drop
|
|
128
|
+
* the steps whose `when` rejects them, and then drop a tour left with no steps at all.
|
|
129
|
+
*
|
|
130
|
+
* That last rule is what makes per-step gating safe to reach for. A tour whose every step
|
|
131
|
+
* is branch-specific (the parked-run tour: some boards have a decision waiting, some an
|
|
132
|
+
* approval) would otherwise survive its own `when` and open on an empty cursor — which the
|
|
133
|
+
* overlay ends immediately, so the user presses Start and nothing happens.
|
|
134
|
+
*
|
|
135
|
+
* Pure and total, so `navSlotFilter` (which runs inside a reactive computed, once per gate
|
|
136
|
+
* flip) stays a straight fold and the rules above are unit-testable without a Vue runtime.
|
|
137
|
+
*/
|
|
138
|
+
export function resolveTours(tours: readonly TutorialTour[], gates: NavGates): TutorialTour[] {
|
|
139
|
+
const out: TutorialTour[] = []
|
|
140
|
+
for (const tour of tours) {
|
|
141
|
+
if (tour.when && !tour.when(gates)) continue
|
|
142
|
+
const steps = tour.steps.filter((s) => (s.when ? s.when(gates) : true))
|
|
143
|
+
if (steps.length === 0) continue
|
|
144
|
+
// Reuse the original object when nothing was dropped: the prompt keys its list on the
|
|
145
|
+
// tour, and a fresh object per gate read would re-render it on every unrelated flip.
|
|
146
|
+
out.push(steps.length === tour.steps.length ? tour : { ...tour, steps })
|
|
147
|
+
}
|
|
148
|
+
return out
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** A DOMRect-shaped box, structurally typed so the geometry below is unit-testable. */
|
|
152
|
+
export interface TutorialRect {
|
|
153
|
+
top: number
|
|
154
|
+
left: number
|
|
155
|
+
width: number
|
|
156
|
+
height: number
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface CoachMarkLayout {
|
|
160
|
+
top: number
|
|
161
|
+
left: number
|
|
162
|
+
/** The side actually used (a preferred side that doesn't fit falls back), or centered. */
|
|
163
|
+
placement: TutorialPlacement | 'center'
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Gap between the anchor's highlight ring and the tooltip card. */
|
|
167
|
+
const TOOLTIP_GAP = 12
|
|
168
|
+
/** Minimum distance the tooltip keeps from the viewport edges. */
|
|
169
|
+
const VIEWPORT_MARGIN = 8
|
|
170
|
+
|
|
171
|
+
const clamp = (value: number, min: number, max: number) =>
|
|
172
|
+
Math.min(Math.max(value, min), Math.max(min, max))
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Where the tooltip card goes for a given anchor. Pure geometry so the fallback rules are
|
|
176
|
+
* pinned by unit tests rather than eyeballed:
|
|
177
|
+
*
|
|
178
|
+
* - no anchor ⇒ centered (intro / wrap-up steps);
|
|
179
|
+
* - the preferred side is used when the card fits between anchor and viewport edge,
|
|
180
|
+
* otherwise sides are tried `bottom → top → right → left`;
|
|
181
|
+
* - nothing fits (tiny viewport) ⇒ the bottom position, clamped — partially covering the
|
|
182
|
+
* anchor beats disappearing off-screen;
|
|
183
|
+
* - the cross-axis is centered on the anchor and clamped to the viewport margin.
|
|
184
|
+
*/
|
|
185
|
+
export function computeCoachMarkLayout(
|
|
186
|
+
target: TutorialRect | null,
|
|
187
|
+
tooltip: { width: number; height: number },
|
|
188
|
+
viewport: { width: number; height: number },
|
|
189
|
+
preferred?: TutorialPlacement,
|
|
190
|
+
): CoachMarkLayout {
|
|
191
|
+
if (!target) {
|
|
192
|
+
return {
|
|
193
|
+
top: Math.max(VIEWPORT_MARGIN, (viewport.height - tooltip.height) / 2),
|
|
194
|
+
left: Math.max(VIEWPORT_MARGIN, (viewport.width - tooltip.width) / 2),
|
|
195
|
+
placement: 'center',
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const fits: Record<TutorialPlacement, boolean> = {
|
|
200
|
+
top: target.top - TOOLTIP_GAP - tooltip.height >= VIEWPORT_MARGIN,
|
|
201
|
+
bottom:
|
|
202
|
+
target.top + target.height + TOOLTIP_GAP + tooltip.height <=
|
|
203
|
+
viewport.height - VIEWPORT_MARGIN,
|
|
204
|
+
left: target.left - TOOLTIP_GAP - tooltip.width >= VIEWPORT_MARGIN,
|
|
205
|
+
right:
|
|
206
|
+
target.left + target.width + TOOLTIP_GAP + tooltip.width <= viewport.width - VIEWPORT_MARGIN,
|
|
207
|
+
}
|
|
208
|
+
const fallbackOrder: TutorialPlacement[] = ['bottom', 'top', 'right', 'left']
|
|
209
|
+
const placement =
|
|
210
|
+
preferred && fits[preferred]
|
|
211
|
+
? preferred
|
|
212
|
+
: (fallbackOrder.find((side) => fits[side]) ?? 'bottom')
|
|
213
|
+
|
|
214
|
+
const centeredLeft = target.left + target.width / 2 - tooltip.width / 2
|
|
215
|
+
const centeredTop = target.top + target.height / 2 - tooltip.height / 2
|
|
216
|
+
const maxLeft = viewport.width - tooltip.width - VIEWPORT_MARGIN
|
|
217
|
+
const maxTop = viewport.height - tooltip.height - VIEWPORT_MARGIN
|
|
218
|
+
|
|
219
|
+
switch (placement) {
|
|
220
|
+
case 'top':
|
|
221
|
+
return {
|
|
222
|
+
top: target.top - TOOLTIP_GAP - tooltip.height,
|
|
223
|
+
left: clamp(centeredLeft, VIEWPORT_MARGIN, maxLeft),
|
|
224
|
+
placement,
|
|
225
|
+
}
|
|
226
|
+
case 'bottom':
|
|
227
|
+
return {
|
|
228
|
+
// Clamped: this is also the "nothing fits" fallback, where overlap is accepted.
|
|
229
|
+
top: clamp(target.top + target.height + TOOLTIP_GAP, VIEWPORT_MARGIN, maxTop),
|
|
230
|
+
left: clamp(centeredLeft, VIEWPORT_MARGIN, maxLeft),
|
|
231
|
+
placement,
|
|
232
|
+
}
|
|
233
|
+
case 'left':
|
|
234
|
+
return {
|
|
235
|
+
top: clamp(centeredTop, VIEWPORT_MARGIN, maxTop),
|
|
236
|
+
left: target.left - TOOLTIP_GAP - tooltip.width,
|
|
237
|
+
placement,
|
|
238
|
+
}
|
|
239
|
+
case 'right':
|
|
240
|
+
return {
|
|
241
|
+
top: clamp(centeredTop, VIEWPORT_MARGIN, maxTop),
|
|
242
|
+
left: target.left + target.width + TOOLTIP_GAP,
|
|
243
|
+
placement,
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
package/i18n/locales/de.json
CHANGED
|
@@ -2132,7 +2132,8 @@
|
|
|
2132
2132
|
"sandbox": "Sandbox öffnen",
|
|
2133
2133
|
"shortcuts": "Tastenkürzel",
|
|
2134
2134
|
"bugHunt": "Fehlerjagd",
|
|
2135
|
-
"toggleUiMode": "Oberflächenmodus wechseln"
|
|
2135
|
+
"toggleUiMode": "Oberflächenmodus wechseln",
|
|
2136
|
+
"tutorial": "Tour starten"
|
|
2136
2137
|
},
|
|
2137
2138
|
"keywords": {
|
|
2138
2139
|
"newPipeline": "pipeline agents chain",
|
|
@@ -2154,7 +2155,8 @@
|
|
|
2154
2155
|
"sandbox": "sandbox prompt model test experiment judge fixture benchmark evaluate",
|
|
2155
2156
|
"shortcuts": "keyboard shortcuts keys hotkeys cheatsheet help",
|
|
2156
2157
|
"bugHunt": "fehler bug jagd triage backlog tracker nicht zugewiesen",
|
|
2157
|
-
"toggleUiMode": "oberfläche modus einfach erweitert anzeigen ausblenden"
|
|
2158
|
+
"toggleUiMode": "oberfläche modus einfach erweitert anzeigen ausblenden",
|
|
2159
|
+
"tutorial": "tutorial tour einführung hilfe onboarding lernen grundlagen"
|
|
2158
2160
|
}
|
|
2159
2161
|
},
|
|
2160
2162
|
"shortcuts": {
|
|
@@ -5906,5 +5908,210 @@
|
|
|
5906
5908
|
"titleAny": "cat-factory mit Ihren Repositorys verbinden",
|
|
5907
5909
|
"intro": "cat-factory funktioniert, indem es Pull Requests in Ihren Repositorys öffnet. Verbinden Sie Ihren Repository-Anbieter, um fortzufahren."
|
|
5908
5910
|
}
|
|
5911
|
+
},
|
|
5912
|
+
"tutorial": {
|
|
5913
|
+
"prompt": {
|
|
5914
|
+
"title": "Eine kurze Tour machen?",
|
|
5915
|
+
"intro": "Geführte Touren zeigen dir die App direkt auf diesem Bildschirm: Sie heben die echten Bedienelemente hervor und sagen dir, was du anklicken sollst.",
|
|
5916
|
+
"start": "Starten",
|
|
5917
|
+
"restart": "Wiederholen",
|
|
5918
|
+
"completed": "Abgeschlossen",
|
|
5919
|
+
"decline": "Nein danke",
|
|
5920
|
+
"later": "Vielleicht später",
|
|
5921
|
+
"empty": "Für deine Rolle auf diesem Board sind noch keine Touren verfügbar."
|
|
5922
|
+
},
|
|
5923
|
+
"overlay": {
|
|
5924
|
+
"next": "Weiter",
|
|
5925
|
+
"back": "Zurück",
|
|
5926
|
+
"skip": "Tour beenden",
|
|
5927
|
+
"done": "Fertig",
|
|
5928
|
+
"progress": "Schritt {current} von {total}",
|
|
5929
|
+
"ariaLabel": "Tutorial-Schritt",
|
|
5930
|
+
"abridged": "1 Schritt wurde übersprungen: dieses Element gehört nicht zu diesem Board. | {count} Schritte wurden übersprungen: diese Elemente gehören nicht zu diesem Board.",
|
|
5931
|
+
"searching": "Suche das hervorgehobene Element...",
|
|
5932
|
+
"clickHint": "Klicke auf das hervorgehobene Element, um fortzufahren"
|
|
5933
|
+
},
|
|
5934
|
+
"tours": {
|
|
5935
|
+
"boardBasics": {
|
|
5936
|
+
"title": "Board-Grundlagen",
|
|
5937
|
+
"description": "Orientierung: das Board, die Seitenleiste und die Befehlspalette.",
|
|
5938
|
+
"steps": {
|
|
5939
|
+
"welcome": {
|
|
5940
|
+
"title": "Willkommen!",
|
|
5941
|
+
"body": "Das ist dein Delivery-Board: Hier planst du Arbeit, Agenten übernehmen sie, und du prüfst die Ergebnisse. Diese kurze Tour zeigt dir die wichtigsten Bedienelemente."
|
|
5942
|
+
},
|
|
5943
|
+
"canvas": {
|
|
5944
|
+
"title": "Das Board",
|
|
5945
|
+
"body": "Services, Module und Aufgaben liegen auf dieser Fläche. Ziehe zum Verschieben, scrolle zum Zoomen und klicke auf eine Karte, um Details zu sehen."
|
|
5946
|
+
},
|
|
5947
|
+
"sidebar": {
|
|
5948
|
+
"title": "Die Seitenleiste",
|
|
5949
|
+
"body": "Alles Weitere findest du hier: Pipelines erstellen, Repositories und Integrationen verbinden, Workspace-Einstellungen."
|
|
5950
|
+
},
|
|
5951
|
+
"commandBar": {
|
|
5952
|
+
"title": "Die Befehlspalette",
|
|
5953
|
+
"body": "Der schnellste Weg zu jeder Aktion: öffnen und lostippen. Von dort kannst du dieses Tutorial jederzeit neu starten."
|
|
5954
|
+
},
|
|
5955
|
+
"toolbar": {
|
|
5956
|
+
"title": "Board-Steuerung",
|
|
5957
|
+
"body": "Mit diesen Steuerelementen zoomst du hinein und heraus oder bringst das ganze Board ins Bild."
|
|
5958
|
+
},
|
|
5959
|
+
"interfaceTier": {
|
|
5960
|
+
"title": "Einfach und erweitert",
|
|
5961
|
+
"body": "Die Oberfläche startet im einfachen Modus, der die alltäglichen Arbeitsflächen zeigt. Wechsle hier auf erweitert, wenn du zusätzlich die Flächen für Experimente, Bootstrap und Betrieb brauchst."
|
|
5962
|
+
},
|
|
5963
|
+
"finish": {
|
|
5964
|
+
"title": "Das war die Übersicht",
|
|
5965
|
+
"body": "Jetzt kennst du dich aus. Probiere die nächste Tour, um deine erste Aufgabe zu erstellen und auszuführen, oder komm später über die Befehlspalette zurück."
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5968
|
+
},
|
|
5969
|
+
"addService": {
|
|
5970
|
+
"title": "Erstes Repository hinzufügen",
|
|
5971
|
+
"description": "Verknüpfe ein Repository, damit das Board einen Service hat, für den du Arbeit planen kannst.",
|
|
5972
|
+
"steps": {
|
|
5973
|
+
"intro": {
|
|
5974
|
+
"title": "Beginne mit einem Repository",
|
|
5975
|
+
"body": "Arbeit passiert am Code, also braucht ein Board mindestens einen Service, bevor ein Agent irgendwo arbeiten kann. Diese Tour verknüpft einen."
|
|
5976
|
+
},
|
|
5977
|
+
"open": {
|
|
5978
|
+
"title": "Service aus Repository",
|
|
5979
|
+
"body": "Das öffnet die Repository-Auswahl. Sie listet die Repositories, die die Verbindung dieses Workspace sehen kann."
|
|
5980
|
+
},
|
|
5981
|
+
"search": {
|
|
5982
|
+
"title": "Repository auswählen",
|
|
5983
|
+
"body": "Suche nach einem deiner eigenen Repositories. Wenn du lieber an etwas Kleinem üben möchtest: {repo} ist ein Beispiel-Service, der für diese Touren absichtlich unfertig bleibt."
|
|
5984
|
+
},
|
|
5985
|
+
"add": {
|
|
5986
|
+
"title": "Hinzufügen",
|
|
5987
|
+
"body": "Das Repository wird zu einem Service-Rahmen auf dem Board. Später kannst du weitere hinzufügen, in einem Monorepo auch einen Service pro Ordner."
|
|
5988
|
+
},
|
|
5989
|
+
"finish": {
|
|
5990
|
+
"title": "Du hast einen Service",
|
|
5991
|
+
"body": "In diesem Rahmen leben die Aufgaben. Die nächste Tour legt eine hinein."
|
|
5992
|
+
}
|
|
5993
|
+
}
|
|
5994
|
+
},
|
|
5995
|
+
"firstTask": {
|
|
5996
|
+
"title": "Erstelle deine erste Aufgabe",
|
|
5997
|
+
"description": "Füge einem Service eine Aufgabe hinzu und sieh zu, wie sie auf dem Board erscheint.",
|
|
5998
|
+
"steps": {
|
|
5999
|
+
"intro": {
|
|
6000
|
+
"title": "Lass uns eine Aufgabe erstellen",
|
|
6001
|
+
"body": "Eine Aufgabe beschreibt ein gewünschtes Ergebnis; eine Agenten-Pipeline liefert es. Diese Tour führt dich Schritt für Schritt durch das Erstellen einer echten Aufgabe."
|
|
6002
|
+
},
|
|
6003
|
+
"addTask": {
|
|
6004
|
+
"title": "Aufgabe hinzufügen",
|
|
6005
|
+
"body": "Jeder Service-Rahmen hat einen Hinzufügen-Button in seiner Kopfzeile."
|
|
6006
|
+
},
|
|
6007
|
+
"describe": {
|
|
6008
|
+
"title": "Beschreibe das Ergebnis",
|
|
6009
|
+
"body": "Gib der Aufgabe einen kurzen Titel, der sagt, was am Ende erreicht sein soll. Normale Sprache genügt."
|
|
6010
|
+
},
|
|
6011
|
+
"create": {
|
|
6012
|
+
"title": "Erstelle die Aufgabe",
|
|
6013
|
+
"body": "Wenn die Beschreibung passt, erstelle die Aufgabe."
|
|
6014
|
+
},
|
|
6015
|
+
"card": {
|
|
6016
|
+
"title": "Aufgabenkarten",
|
|
6017
|
+
"body": "Das ist eine Aufgabenkarte. Von ihr aus startest du die Pipeline, verfolgst den Fortschritt und öffnest Ergebnisse."
|
|
6018
|
+
},
|
|
6019
|
+
"finish": {
|
|
6020
|
+
"title": "Gut gemacht",
|
|
6021
|
+
"body": "Das ist der Kernablauf: Aufgabe beschreiben, ausführen, Ergebnis prüfen. Entdecke die weiteren Touren, wann immer du magst."
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
},
|
|
6025
|
+
"runTask": {
|
|
6026
|
+
"title": "Aufgabe ausführen",
|
|
6027
|
+
"description": "Öffne eine Aufgabe, wähle ihre Pipeline und lass die Agenten loslegen.",
|
|
6028
|
+
"steps": {
|
|
6029
|
+
"intro": {
|
|
6030
|
+
"title": "Von der Aufgabe zum Lauf",
|
|
6031
|
+
"body": "Eine Aufgabe auf dem Board ist eine Anfrage. Wenn du sie öffnest, siehst du die Pipeline, die sie liefert, und die Bedienelemente, die sie starten."
|
|
6032
|
+
},
|
|
6033
|
+
"openTask": {
|
|
6034
|
+
"title": "Aufgabe öffnen",
|
|
6035
|
+
"body": "Ein Klick auf eine Karte öffnet ihren Inspektor, in dem alles zu dieser Aufgabe steht."
|
|
6036
|
+
},
|
|
6037
|
+
"inspector": {
|
|
6038
|
+
"title": "Der Inspektor",
|
|
6039
|
+
"body": "Status, Repository, Pipeline und der Lauf selbst: dieses Panel ist die ganze Geschichte der Aufgabe."
|
|
6040
|
+
},
|
|
6041
|
+
"pipeline": {
|
|
6042
|
+
"title": "Pipeline wählen",
|
|
6043
|
+
"body": "Eine Pipeline ist die Abfolge von Agenten, die die Arbeit erledigen: Spezifikation schreiben, umsetzen, prüfen, Checks laufen lassen, mergen. Wähle die, die zur Aufgabe passt."
|
|
6044
|
+
},
|
|
6045
|
+
"start": {
|
|
6046
|
+
"title": "Einen Lauf starten",
|
|
6047
|
+
"body": "Das startet die Pipeline wirklich, und Agenten verbrauchen Modellbudget. Deshalb bleibt der Klick bei dir: drücke ihn, wann du bereit bist, während dieser Tour oder danach."
|
|
6048
|
+
},
|
|
6049
|
+
"steps": {
|
|
6050
|
+
"title": "Beim Arbeiten zusehen",
|
|
6051
|
+
"body": "Jeder Schritt meldet seinen Fortschritt hier, live übertragen. Klicke einen Schritt an, um zu lesen, was der Agent tatsächlich produziert hat."
|
|
6052
|
+
},
|
|
6053
|
+
"finish": {
|
|
6054
|
+
"title": "Das ist der Kreislauf",
|
|
6055
|
+
"body": "Aufgabe planen, Pipeline wählen, starten, zusehen. Wenn ein Lauf etwas von dir braucht, hält er an und sagt es, was die nächste Tour behandelt."
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
},
|
|
6059
|
+
"answerPark": {
|
|
6060
|
+
"title": "Wartenden Lauf beantworten",
|
|
6061
|
+
"description": "Ein Lauf pausiert und wartet auf einen Menschen. Sieh, wo er fragt und wie du antwortest.",
|
|
6062
|
+
"steps": {
|
|
6063
|
+
"intro": {
|
|
6064
|
+
"title": "Ein Lauf wartet auf dich",
|
|
6065
|
+
"body": "Manche Schritte halten an und fragen: eine Rückfrage zu den Anforderungen, ein Plan zur Freigabe, eine Wahl zwischen Ansätzen. Ein pausierter Lauf wartet unbegrenzt auf eine Antwort, also bewegt sich nichts, bis du antwortest."
|
|
6066
|
+
},
|
|
6067
|
+
"resolve": {
|
|
6068
|
+
"title": "Wo er fragt",
|
|
6069
|
+
"body": "Eine Aufgabe, die auf einen Menschen wartet, zeigt das auf ihrer Karte und bietet diese Aktion an. Sie bringt dich direkt zu dem, was gefragt wird."
|
|
6070
|
+
},
|
|
6071
|
+
"decide": {
|
|
6072
|
+
"title": "Eine Antwort wählen",
|
|
6073
|
+
"body": "Jede Option ist eine echte Anweisung an den Lauf: wähle eine, und die Pipeline macht mit deiner Wahl weiter."
|
|
6074
|
+
},
|
|
6075
|
+
"approve": {
|
|
6076
|
+
"title": "Die Arbeit freigeben",
|
|
6077
|
+
"body": "Gib frei, damit der Lauf weitergeht, oder fordere Änderungen an, um den Schritt mit deinen Anmerkungen zurückzuschicken. Beides sind Antworten, und der Lauf läuft so oder so weiter."
|
|
6078
|
+
},
|
|
6079
|
+
"finish": {
|
|
6080
|
+
"title": "Nichts wartet stillschweigend",
|
|
6081
|
+
"body": "Wartende Aufgaben sind auf dem Board markiert und in der Werkzeugleiste gezählt, damit du sie findest, ohne zu suchen."
|
|
6082
|
+
}
|
|
6083
|
+
}
|
|
6084
|
+
},
|
|
6085
|
+
"reviewMerge": {
|
|
6086
|
+
"title": "Prüfen und mergen",
|
|
6087
|
+
"description": "Lies, was ein fertiger Lauf produziert hat, und bring es in den Hauptzweig.",
|
|
6088
|
+
"steps": {
|
|
6089
|
+
"intro": {
|
|
6090
|
+
"title": "Ein Lauf ist fertig",
|
|
6091
|
+
"body": "Fertig ist nicht dasselbe wie ausgeliefert. Eine Aufgabe ist erledigt, wenn ihr Pull Request gemergt ist, also geht es hier um die letzte Meile."
|
|
6092
|
+
},
|
|
6093
|
+
"openTask": {
|
|
6094
|
+
"title": "Aufgabe öffnen",
|
|
6095
|
+
"body": "Öffne eine Aufgabe, deren Lauf fertig ist. Ihr Inspektor enthält die vollständige Schrittliste."
|
|
6096
|
+
},
|
|
6097
|
+
"openStep": {
|
|
6098
|
+
"title": "Schritt öffnen",
|
|
6099
|
+
"body": "Ein Klick auf einen Schritt zeigt, was dieser Agent produziert hat: seinen Bericht, seine Befunde und was er geändert hat."
|
|
6100
|
+
},
|
|
6101
|
+
"result": {
|
|
6102
|
+
"title": "Das Ergebnis lesen",
|
|
6103
|
+
"body": "Das ist die eigene Darstellung des Agenten. Review-Schritte listen Befunde, ein Tester meldet Urteile, der Merger erklärt, wie er die Änderung bewertet hat."
|
|
6104
|
+
},
|
|
6105
|
+
"merge": {
|
|
6106
|
+
"title": "Mergen",
|
|
6107
|
+
"body": "Wenn ein Lauf einen Pull Request öffnet, bietet der Inspektor hier den Merge an. Eine Pipeline mit Merger-Schritt kann auch selbst mergen, wenn die Änderung über deinem Schwellenwert liegt."
|
|
6108
|
+
},
|
|
6109
|
+
"finish": {
|
|
6110
|
+
"title": "Ausgeliefert",
|
|
6111
|
+
"body": "Gemergte Arbeit markiert die Aufgabe auf dem Board als erledigt. Das ist der ganze Kreislauf: planen, ausführen, antworten, prüfen, mergen."
|
|
6112
|
+
}
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
}
|
|
5909
6116
|
}
|
|
5910
6117
|
}
|