@cat-factory/app 0.116.7 → 0.116.9

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.
@@ -8,8 +8,9 @@
8
8
  //
9
9
  // MONOREPO support: a repo flagged a monorepo can back SEVERAL services, each
10
10
  // pinned to a subdirectory. When the selected repo is a monorepo, the user
11
- // browses its tree and picks the service's directory before adding (and may add
12
- // more than one, a subset of the repo's services).
11
+ // browses its tree and multi-selects the service directories to add from ANY
12
+ // parent folder, in one pass then adds them all at once. Directories that
13
+ // already back a service on this board are shown but not selectable.
13
14
  import type { FrameRepoType, GitHubAvailableRepo } from '~/types/domain'
14
15
  import GitHubConnect from '~/components/github/GitHubConnect.vue'
15
16
  import RepoSearchEmpty from '~/components/github/RepoSearchEmpty.vue'
@@ -136,11 +137,39 @@ const repoMenuItems = computed(() => {
136
137
  // repo + requires a directory when it creates the service). A repo already flagged a
137
138
  // monorepo (it backs other services) seeds the toggle on when selected.
138
139
  const isMonorepo = ref(false)
139
- const selectedDirectory = ref<string | undefined>(undefined)
140
+ // The cart of monorepo service directories the user has picked (repo-root-relative),
141
+ // accumulated across the whole browse session so picks from different parent folders
142
+ // coexist. Added all at once (see `addServices`), unlike the one-at-a-time whole-repo add.
143
+ const selectedDirectories = ref<string[]>([])
144
+
145
+ // Directories in the selected repo that ALREADY back a service on this board — surfaced
146
+ // so the tree browser can disable them (adding one again would be a no-op). Derived from
147
+ // the org catalog filtered to this repo; a whole-repo service (null directory) is ignored.
148
+ const addedDirectories = computed<string[]>(() => {
149
+ if (selectedRepoId.value === undefined) return []
150
+ return services.catalog
151
+ .filter((s) => s.repoGithubId === selectedRepoId.value && s.directory)
152
+ .map((s) => normalizeRepoPath(s.directory as string))
153
+ })
154
+ const addedDirSet = computed(() => new Set(addedDirectories.value))
140
155
 
141
156
  function toggleMonorepo(value: boolean) {
142
157
  isMonorepo.value = value
143
- selectedDirectory.value = undefined
158
+ selectedDirectories.value = []
159
+ }
160
+
161
+ // Add/remove a directory from the cart. Guards against an already-added directory (the
162
+ // browser disables it, but keep the model authoritative).
163
+ function toggleDirectory(path: string) {
164
+ if (addedDirSet.value.has(normalizeRepoPath(path))) return
165
+ const i = selectedDirectories.value.indexOf(path)
166
+ if (i >= 0) selectedDirectories.value.splice(i, 1)
167
+ else selectedDirectories.value.push(path)
168
+ }
169
+
170
+ function removeSelected(path: string) {
171
+ const i = selectedDirectories.value.indexOf(path)
172
+ if (i >= 0) selectedDirectories.value.splice(i, 1)
144
173
  }
145
174
 
146
175
  // On repo change, capture the picked repo (from the volatile loaded list, before a later
@@ -152,13 +181,13 @@ watch(selectedRepoId, (id) => {
152
181
  if (found) selectedRepo.value = found
153
182
  }
154
183
  isMonorepo.value = selectedRepo.value?.isMonorepo === true
155
- selectedDirectory.value = undefined
184
+ selectedDirectories.value = []
156
185
  configuredBlockId.value = undefined
157
186
  })
158
187
 
159
188
  function resetSelection() {
160
189
  selectedRepoId.value = undefined
161
- selectedDirectory.value = undefined
190
+ selectedDirectories.value = []
162
191
  isMonorepo.value = false
163
192
  configuredBlockId.value = undefined
164
193
  resetRepoSearch()
@@ -186,12 +215,11 @@ function openManageInstall() {
186
215
  if (manageInstallUrl.value) window.open(manageInstallUrl.value, '_blank', 'noopener')
187
216
  }
188
217
 
189
- // The just-added service, kept on the board store so the user can configure it (test
190
- // infra + fragments) right here — the same controls as the inspector. A monorepo can
191
- // host several services, so adding another keeps the modal open; a whole-repo service
192
- // can only be added once (its repo is then on the board).
218
+ // The just-added whole-repo service, kept on the board store so the user can configure it
219
+ // (test infra + fragments) right here — the same controls as the inspector. Only the
220
+ // whole-repo flow surfaces this inline configure step; a monorepo adds several services at
221
+ // once and they're configured later in the inspector.
193
222
  const configuredBlockId = ref<string | undefined>(undefined)
194
- const configuredDirectory = ref<string | undefined>(undefined)
195
223
  const configuredBlock = computed(() =>
196
224
  configuredBlockId.value ? board.getBlock(configuredBlockId.value) : undefined,
197
225
  )
@@ -210,12 +238,31 @@ watch(
210
238
  { immediate: true },
211
239
  )
212
240
 
213
- // A monorepo service needs a chosen directory; a whole-repo service can be added once.
241
+ // A whole-repo service is added once (then configured inline). A monorepo instead
242
+ // multi-selects directories and adds them together via `addServices`.
214
243
  const canAdd = computed(
215
244
  () =>
216
245
  !needsGitHub.value &&
217
246
  selectedRepoId.value !== undefined &&
218
- (isMonorepo.value ? !!selectedDirectory.value : !configuredBlockId.value),
247
+ !isMonorepo.value &&
248
+ !configuredBlockId.value,
249
+ )
250
+ const canAddServices = computed(
251
+ () =>
252
+ !needsGitHub.value &&
253
+ selectedRepoId.value !== undefined &&
254
+ isMonorepo.value &&
255
+ selectedDirectories.value.length > 0,
256
+ )
257
+
258
+ // Directories the user has picked but NOT yet committed via "Add N services". Closing the
259
+ // modal ("Done") would silently discard them — almost never what the user wants — so the
260
+ // footer's Done is disabled while any remain (see the template). Filtered against the
261
+ // already-added set for parity with `addServices`, so a stale cart entry can't block Done.
262
+ const hasPendingSelection = computed(
263
+ () =>
264
+ isMonorepo.value &&
265
+ selectedDirectories.value.some((d) => !addedDirSet.value.has(normalizeRepoPath(d))),
219
266
  )
220
267
 
221
268
  async function add() {
@@ -223,8 +270,10 @@ async function add() {
223
270
  adding.value = true
224
271
  try {
225
272
  const block = await board.addServiceFromRepo(selectedRepoId.value, {
226
- directory: isMonorepo.value ? selectedDirectory.value : undefined,
227
- isMonorepo: isMonorepo.value,
273
+ // The switch is off, so import the whole repo as ONE service. Send the flag
274
+ // explicitly: a repo already flagged a monorepo (the toggle seeds on) must be
275
+ // un-flagged here, or the backend still requires a service subdirectory and rejects.
276
+ isMonorepo: false,
228
277
  type: selectedType.value,
229
278
  // Place the imported frame in free space (centred in view) instead of the
230
279
  // backend's default stagger, so it never overlaps an existing service.
@@ -235,15 +284,57 @@ async function add() {
235
284
  // Centre the camera on the newly imported service.
236
285
  await focusFrame(block.id)
237
286
  configuredBlockId.value = block.id
238
- configuredDirectory.value = isMonorepo.value ? selectedDirectory.value : undefined
239
287
  toast.add({
240
288
  title: t('github.addService.toast.addedTitle'),
241
289
  description: t('github.addService.toast.addedDescription', { title: block.title }),
242
290
  icon: 'i-lucide-check',
243
291
  color: 'success',
244
292
  })
245
- // Ready to pick another monorepo service (the just-added directory is taken).
246
- selectedDirectory.value = undefined
293
+ } catch (e) {
294
+ toast.add({
295
+ title: t('github.addService.toast.addFailedTitle'),
296
+ description: e instanceof Error ? e.message : String(e),
297
+ icon: 'i-lucide-triangle-alert',
298
+ color: 'error',
299
+ })
300
+ } finally {
301
+ adding.value = false
302
+ }
303
+ }
304
+
305
+ // Add every directory in the cart as its own service, in one action. Each add lays the
306
+ // frame out in free space (seeing the ones added earlier in the loop, so they don't
307
+ // overlap); the projection is refreshed and the camera centres on the last one. The
308
+ // just-added directories then move to `addedDirectories`, so the cart is cleared and the
309
+ // tree marks them "added" — ready to pick more (from any folder) or close.
310
+ async function addServices() {
311
+ if (!canAddServices.value || selectedRepoId.value === undefined) return
312
+ const dirs = selectedDirectories.value.filter((d) => !addedDirSet.value.has(normalizeRepoPath(d)))
313
+ if (dirs.length === 0) return
314
+ adding.value = true
315
+ try {
316
+ let lastBlock: Awaited<ReturnType<typeof board.addServiceFromRepo>> | undefined
317
+ for (const directory of dirs) {
318
+ lastBlock = await board.addServiceFromRepo(selectedRepoId.value, {
319
+ directory,
320
+ isMonorepo: true,
321
+ type: selectedType.value,
322
+ position: freeFramePosition(),
323
+ })
324
+ }
325
+ await github.load()
326
+ if (lastBlock) await focusFrame(lastBlock.id)
327
+ selectedDirectories.value = []
328
+ toast.add({
329
+ title: t('github.addService.toast.servicesAddedTitle'),
330
+ description: t(
331
+ 'github.addService.toast.servicesAddedDescription',
332
+ { count: dirs.length },
333
+ dirs.length,
334
+ ),
335
+ icon: 'i-lucide-check',
336
+ color: 'success',
337
+ })
247
338
  } catch (e) {
248
339
  toast.add({
249
340
  title: t('github.addService.toast.addFailedTitle'),
@@ -329,8 +420,9 @@ function done() {
329
420
  <USelect v-model="selectedType" :items="typeItems" value-key="value" class="w-full" />
330
421
  </UFormField>
331
422
 
332
- <!-- monorepo handling: flag + directory picker -->
333
- <div v-if="selectedRepoId !== undefined" class="space-y-3">
423
+ <!-- monorepo handling: flag + multi-directory picker (hidden once a whole-repo
424
+ service has been added and is being configured inline) -->
425
+ <div v-if="selectedRepoId !== undefined && !configuredBlock" class="space-y-3">
334
426
  <USwitch
335
427
  :model-value="isMonorepo"
336
428
  :label="t('github.addService.monorepoLabel')"
@@ -340,23 +432,65 @@ function done() {
340
432
 
341
433
  <div
342
434
  v-if="isMonorepo"
343
- class="rounded-md border border-slate-700/60 bg-slate-900/40 p-3"
435
+ class="space-y-3 rounded-md border border-slate-700/60 bg-slate-900/40 p-3"
344
436
  >
345
- <p class="mb-2 text-xs text-slate-400">
437
+ <p class="text-xs text-slate-400">
346
438
  {{ t('github.addService.monorepoBrowseHint') }}
347
439
  </p>
348
440
  <RepoTreeBrowser
349
- v-model="selectedDirectory"
350
441
  :repo-github-id="selectedRepoId!"
351
442
  mode="dir"
443
+ multiple
444
+ :selected-paths="selectedDirectories"
445
+ :added-paths="addedDirectories"
446
+ @toggle="toggleDirectory"
352
447
  />
353
- <p class="mt-2 truncate text-xs text-slate-400">
354
- <template v-if="selectedDirectory">
355
- {{ t('github.addService.serviceDirectory') }}
356
- <code class="text-slate-200">{{ selectedDirectory }}</code>
357
- </template>
358
- <template v-else>{{ t('github.addService.noDirectorySelected') }}</template>
359
- </p>
448
+
449
+ <!-- the selection cart + the add action sit right beside the tree, so the
450
+ picked services and the button that adds them are never scrolled apart -->
451
+ <div class="space-y-2 rounded-md border border-slate-800 bg-slate-950/40 p-2.5">
452
+ <p class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
453
+ {{ t('github.addService.selectedServices') }}
454
+ </p>
455
+ <div v-if="selectedDirectories.length" class="flex flex-wrap gap-1.5">
456
+ <span
457
+ v-for="dir in selectedDirectories"
458
+ :key="dir"
459
+ class="inline-flex items-center gap-1 rounded bg-slate-800 px-2 py-0.5 text-xs text-slate-200"
460
+ >
461
+ <code class="text-slate-200">{{ dir }}</code>
462
+ <button
463
+ type="button"
464
+ class="text-slate-400 hover:text-slate-100"
465
+ :aria-label="t('github.addService.removeService', { directory: dir })"
466
+ @click="removeSelected(dir)"
467
+ >
468
+ <UIcon name="i-lucide-x" class="h-3 w-3" />
469
+ </button>
470
+ </span>
471
+ </div>
472
+ <p v-else class="text-xs text-slate-500">
473
+ {{ t('github.addService.noServicesSelected') }}
474
+ </p>
475
+ <div class="flex justify-end">
476
+ <UButton
477
+ color="primary"
478
+ icon="i-lucide-plus"
479
+ size="sm"
480
+ :loading="adding"
481
+ :disabled="!canAddServices"
482
+ @click="addServices"
483
+ >
484
+ {{
485
+ t(
486
+ 'github.addService.addServices',
487
+ { count: selectedDirectories.length },
488
+ selectedDirectories.length,
489
+ )
490
+ }}
491
+ </UButton>
492
+ </div>
493
+ </div>
360
494
  </div>
361
495
  </div>
362
496
 
@@ -373,7 +507,7 @@ function done() {
373
507
  </div>
374
508
  <ServiceTestConfig
375
509
  :block="configuredBlock"
376
- :repo="{ githubId: selectedRepoId!, directory: configuredDirectory }"
510
+ :repo="{ githubId: selectedRepoId! }"
377
511
  default-open
378
512
  />
379
513
  <ServiceFragments :block="configuredBlock" default-open />
@@ -395,22 +529,29 @@ function done() {
395
529
  </div>
396
530
 
397
531
  <div class="flex justify-end gap-2">
398
- <UButton v-if="configuredBlock" color="neutral" variant="soft" size="sm" @click="done">
532
+ <!-- Monorepo adds via the cart's own button; the footer only closes. A
533
+ whole-repo add shows its "Add service" button until one is added, then
534
+ the inline configure panel + this Done. -->
535
+ <UButton
536
+ v-if="configuredBlock || isMonorepo"
537
+ color="neutral"
538
+ variant="soft"
539
+ size="sm"
540
+ :disabled="hasPendingSelection"
541
+ :title="hasPendingSelection ? t('github.addService.donePendingHint') : undefined"
542
+ @click="done"
543
+ >
399
544
  {{ t('github.addService.done') }}
400
545
  </UButton>
401
546
  <UButton
402
- v-if="!configuredBlock || isMonorepo"
547
+ v-if="!isMonorepo && !configuredBlock"
403
548
  color="primary"
404
549
  icon="i-lucide-plus"
405
550
  :loading="adding"
406
551
  :disabled="!canAdd"
407
552
  @click="add"
408
553
  >
409
- {{
410
- configuredBlock && isMonorepo
411
- ? t('github.addService.addAnother')
412
- : t('github.addService.add')
413
- }}
554
+ {{ t('github.addService.add') }}
414
555
  </UButton>
415
556
  </div>
416
557
  </template>
@@ -6,20 +6,37 @@
6
6
  // The selected path (relative to the repo root, as GitHub returns it) is exposed
7
7
  // via `v-model`. The component owns its own navigation/loading state so callers
8
8
  // just bind a repo id + mode; it self-loads on mount and when those change.
9
+ //
10
+ // `dir` mode additionally supports `multiple`: instead of the single `v-model`
11
+ // path, the caller passes the current `selectedPaths` (a cart) + `addedPaths`
12
+ // (directories already on the board, shown disabled) and handles the `toggle`
13
+ // event to add/remove a directory. This lets one browse session accumulate
14
+ // several services from ANY parent folder (the monorepo add flow) — navigating
15
+ // away never drops earlier picks.
9
16
  import type { RepoTreeEntry } from '~/types/domain'
10
17
 
11
18
  const props = withDefaults(
12
19
  defineProps<{
13
20
  repoGithubId: number
14
21
  mode?: 'dir' | 'file'
15
- /** Currently picked path (repo-root-relative), via v-model. */
22
+ /** Currently picked path (repo-root-relative), via v-model. Single-select only. */
16
23
  modelValue?: string
17
24
  /** Directory to open at (e.g. a monorepo service's subdirectory). */
18
25
  startPath?: string
26
+ /** `dir` mode: accumulate a set of picks (via `selectedPaths`/`toggle`) instead of one. */
27
+ multiple?: boolean
28
+ /** `dir` + `multiple`: the current cart of picked directories (repo-root-relative). */
29
+ selectedPaths?: string[]
30
+ /** `dir` + `multiple`: directories already on the board — listed but not selectable. */
31
+ addedPaths?: string[]
19
32
  }>(),
20
- { mode: 'dir', startPath: '' },
33
+ { mode: 'dir', startPath: '', multiple: false, selectedPaths: () => [], addedPaths: () => [] },
21
34
  )
22
- const emit = defineEmits<{ 'update:modelValue': [string | undefined] }>()
35
+ const emit = defineEmits<{
36
+ 'update:modelValue': [string | undefined]
37
+ /** `dir` + `multiple`: the user asked to add/remove this directory from the cart. */
38
+ toggle: [string]
39
+ }>()
23
40
 
24
41
  const { t } = useI18n()
25
42
  const github = useGitHubStore()
@@ -29,6 +46,15 @@ const currentPath = ref(props.startPath)
29
46
  const treeEntries = ref<RepoTreeEntry[]>([])
30
47
  const loading = ref(false)
31
48
 
49
+ const selectedSet = computed(() => new Set(props.selectedPaths.map(normalizeRepoPath)))
50
+ const addedSet = computed(() => new Set(props.addedPaths.map(normalizeRepoPath)))
51
+ function isAdded(path: string): boolean {
52
+ return props.multiple && addedSet.value.has(normalizeRepoPath(path))
53
+ }
54
+ function isPicked(path: string): boolean {
55
+ return props.multiple ? selectedSet.value.has(normalizeRepoPath(path)) : props.modelValue === path
56
+ }
57
+
32
58
  const dirEntries = computed(() => treeEntries.value.filter((e) => e.type === 'dir'))
33
59
  const fileEntries = computed(() => treeEntries.value.filter((e) => e.type === 'file'))
34
60
  const isEmpty = computed(() =>
@@ -63,7 +89,13 @@ async function browseTo(path: string) {
63
89
  }
64
90
 
65
91
  function pick(path: string) {
66
- emit('update:modelValue', path)
92
+ if (props.multiple) {
93
+ // Already-on-board directories are shown for orientation but can't be re-added.
94
+ if (addedSet.value.has(normalizeRepoPath(path))) return
95
+ emit('toggle', path)
96
+ } else {
97
+ emit('update:modelValue', path)
98
+ }
67
99
  }
68
100
 
69
101
  // Re-open at the start path whenever the repo (or requested root) changes.
@@ -124,18 +156,21 @@ watch(
124
156
  <UIcon name="i-lucide-folder" class="h-4 w-4 shrink-0 text-amber-400" />
125
157
  <span class="truncate">{{ entry.name }}</span>
126
158
  </button>
159
+ <span
160
+ v-if="mode === 'dir' && isAdded(entry.path)"
161
+ class="flex shrink-0 items-center gap-1 text-xs text-slate-500"
162
+ >
163
+ <UIcon name="i-lucide-check" class="h-3.5 w-3.5" />
164
+ {{ t('github.repoTree.added') }}
165
+ </span>
127
166
  <UButton
128
- v-if="mode === 'dir'"
167
+ v-else-if="mode === 'dir'"
129
168
  size="xs"
130
169
  variant="soft"
131
- :color="modelValue === entry.path ? 'primary' : 'neutral'"
170
+ :color="isPicked(entry.path) ? 'primary' : 'neutral'"
132
171
  @click="pick(entry.path)"
133
172
  >
134
- {{
135
- modelValue === entry.path
136
- ? t('github.repoTree.selected')
137
- : t('github.repoTree.select')
138
- }}
173
+ {{ isPicked(entry.path) ? t('github.repoTree.selected') : t('github.repoTree.select') }}
139
174
  </UButton>
140
175
  </li>
141
176
  <template v-if="mode === 'file'">
@@ -164,14 +199,21 @@ watch(
164
199
  </div>
165
200
 
166
201
  <!-- dir mode: pin the current folder without descending into a child -->
167
- <div v-if="mode === 'dir' && currentPath" class="mt-2 flex justify-end">
202
+ <div
203
+ v-if="mode === 'dir' && currentPath && !isAdded(currentPath)"
204
+ class="mt-2 flex justify-end"
205
+ >
168
206
  <UButton
169
207
  size="xs"
170
208
  variant="soft"
171
- :color="modelValue === currentPath ? 'primary' : 'neutral'"
209
+ :color="isPicked(currentPath) ? 'primary' : 'neutral'"
172
210
  @click="pick(currentPath)"
173
211
  >
174
- {{ t('github.repoTree.useThisFolder') }}
212
+ {{
213
+ multiple && isPicked(currentPath)
214
+ ? t('github.repoTree.selected')
215
+ : t('github.repoTree.useThisFolder')
216
+ }}
175
217
  </UButton>
176
218
  </div>
177
219
  </div>
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Normalise a repo-root-relative path to its canonical, slash-trimmed form.
3
+ *
4
+ * GitHub returns tree entry paths with no surrounding slashes, but a stored service
5
+ * `directory` may carry them, so both the monorepo directory picker and the tree
6
+ * browser normalise before comparing a picked/added directory against a tree entry.
7
+ */
8
+ export function normalizeRepoPath(p: string): string {
9
+ return p.replace(/^\/+|\/+$/g, '')
10
+ }
@@ -2523,20 +2523,24 @@
2523
2523
  },
2524
2524
  "monorepoLabel": "Dies ist ein Monorepo (beherbergt mehr als einen Service)",
2525
2525
  "monorepoDescription": "Fügen Sie mehrere Services aus einem Repo hinzu, jeder an ein Unterverzeichnis gebunden.",
2526
- "monorepoBrowseHint": "Durchsuchen Sie das Repository und wählen Sie das Verzeichnis des Service aus, den Sie hinzufügen möchten. Agents, die an diesem Service arbeiten, laufen innerhalb dieses Unterverzeichnisses.",
2527
- "serviceDirectory": "Service-Verzeichnis:",
2528
- "noDirectorySelected": "Noch kein Verzeichnis ausgewählt.",
2526
+ "monorepoBrowseHint": "Durchsuchen Sie das Repository und wählen Sie die Verzeichnisse der Services aus, die Sie hinzufügen möchten – aus jedem beliebigen Ordner. Agents, die an einem Service arbeiten, laufen innerhalb seines Unterverzeichnisses.",
2527
+ "selectedServices": "Ausgewählte Services",
2528
+ "noServicesSelected": "Noch keine Services ausgewählt. Wählen Sie oben Verzeichnisse aus.",
2529
+ "addServices": "{count} Service hinzufügen | {count} Services hinzufügen",
2530
+ "removeService": "{directory} entfernen",
2529
2531
  "addedConfigure": "{title} hinzugefügt, konfigurieren Sie es",
2530
2532
  "grantAccess": "Der App Zugriff auf ein Repo gewähren",
2531
2533
  "grantAccessTitle": "Öffnen Sie die Installationseinstellungen der App, um ihr Zugriff auf ein Repository zu gewähren",
2532
2534
  "refreshList": "Liste aktualisieren",
2533
2535
  "done": "Fertig",
2536
+ "donePendingHint": "Füge zuerst die ausgewählten Services hinzu oder hebe die Auswahl auf – sonst werden diese Auswahlen verworfen.",
2534
2537
  "add": "Service hinzufügen",
2535
- "addAnother": "Weiteren Service hinzufügen",
2536
2538
  "toast": {
2537
2539
  "addedTitle": "Service hinzugefügt",
2538
2540
  "addedDescription": "{title} ist auf dem Board, konfigurieren Sie es unten.",
2539
- "addFailedTitle": "Service konnte nicht hinzugefügt werden"
2541
+ "addFailedTitle": "Service konnte nicht hinzugefügt werden",
2542
+ "servicesAddedTitle": "Services hinzugefügt",
2543
+ "servicesAddedDescription": "{count} Service zum Board hinzugefügt. | {count} Services zum Board hinzugefügt."
2540
2544
  }
2541
2545
  },
2542
2546
  "repoTree": {
@@ -2546,6 +2550,7 @@
2546
2550
  "empty": "Nichts hier.",
2547
2551
  "select": "Auswählen",
2548
2552
  "selected": "Ausgewählt",
2553
+ "added": "Hinzugefügt",
2549
2554
  "useThisFolder": "Diesen Ordner verwenden",
2550
2555
  "errors": {
2551
2556
  "listDirectory": "Verzeichnis konnte nicht aufgelistet werden"
@@ -2983,20 +2983,30 @@
2983
2983
  },
2984
2984
  "monorepoLabel": "This is a monorepo (hosts more than one service)",
2985
2985
  "monorepoDescription": "Add several services from one repo, each pinned to a subdirectory.",
2986
- "monorepoBrowseHint": "Browse the repository and pick the directory of the service you want to add. Agents working on this service will run within that subdirectory.",
2987
- "serviceDirectory": "Service directory:",
2988
- "noDirectorySelected": "No directory selected yet.",
2986
+ "monorepoBrowseHint": "Browse the repository and select the directories of the services you want to add — from any folder. Agents working on a service run within its subdirectory.",
2987
+ "selectedServices": "Selected services",
2988
+ "noServicesSelected": "No services selected yet. Pick directories above.",
2989
+ "addServices": "Add {count} service | Add {count} services",
2990
+ "@addServices": {
2991
+ "description": "Count-driven button label; resolved via t(key, { count }, count) so {count} also drives the plural choice. Provide ALL plural forms your language needs (English has 2; Polish/Ukrainian need 3 - one/few/many - via the custom pluralRules in i18n.config.ts)."
2992
+ },
2993
+ "removeService": "Remove {directory}",
2989
2994
  "addedConfigure": "{title} added, configure it",
2990
2995
  "grantAccess": "Grant the App access to a repo",
2991
2996
  "grantAccessTitle": "Open the App's installation settings to grant it access to a repository",
2992
2997
  "refreshList": "Refresh list",
2993
2998
  "done": "Done",
2999
+ "donePendingHint": "Add your selected services first, or clear the selection — otherwise those picks are discarded.",
2994
3000
  "add": "Add service",
2995
- "addAnother": "Add another service",
2996
3001
  "toast": {
2997
3002
  "addedTitle": "Service added",
2998
3003
  "addedDescription": "{title} is on the board, configure it below.",
2999
- "addFailedTitle": "Could not add service"
3004
+ "addFailedTitle": "Could not add service",
3005
+ "servicesAddedTitle": "Services added",
3006
+ "servicesAddedDescription": "{count} service added to the board. | {count} services added to the board.",
3007
+ "@servicesAddedDescription": {
3008
+ "description": "Count-driven toast; resolved via t(key, { count }, count) so {count} also drives the plural choice. Provide ALL plural forms your language needs (Polish/Ukrainian need 3 - one/few/many)."
3009
+ }
3000
3010
  }
3001
3011
  },
3002
3012
  "repoTree": {
@@ -3006,6 +3016,7 @@
3006
3016
  "empty": "Nothing here.",
3007
3017
  "select": "Select",
3008
3018
  "selected": "Selected",
3019
+ "added": "Added",
3009
3020
  "useThisFolder": "Use this folder",
3010
3021
  "errors": {
3011
3022
  "listDirectory": "Could not list directory"
@@ -2894,20 +2894,24 @@
2894
2894
  },
2895
2895
  "monorepoLabel": "Es un monorepo (aloja más de un servicio)",
2896
2896
  "monorepoDescription": "Añade varios servicios desde un repositorio, cada uno fijado a un subdirectorio.",
2897
- "monorepoBrowseHint": "Explora el repositorio y elige el directorio del servicio que quieres añadir. Los agentes que trabajen en este servicio se ejecutarán dentro de ese subdirectorio.",
2898
- "serviceDirectory": "Directorio del servicio:",
2899
- "noDirectorySelected": "Aún no se ha seleccionado ningún directorio.",
2897
+ "monorepoBrowseHint": "Explora el repositorio y selecciona los directorios de los servicios que quieres añadir, de cualquier carpeta. Los agentes que trabajen en un servicio se ejecutarán dentro de su subdirectorio.",
2898
+ "selectedServices": "Servicios seleccionados",
2899
+ "noServicesSelected": "Aún no hay servicios seleccionados. Elige directorios arriba.",
2900
+ "addServices": "Añadir {count} servicio | Añadir {count} servicios",
2901
+ "removeService": "Quitar {directory}",
2900
2902
  "addedConfigure": "{title} añadido, configúralo",
2901
2903
  "grantAccess": "Conceder a la App acceso a un repositorio",
2902
2904
  "grantAccessTitle": "Abrir la configuración de instalación de la App para concederle acceso a un repositorio",
2903
2905
  "refreshList": "Actualizar lista",
2904
2906
  "done": "Listo",
2907
+ "donePendingHint": "Añade primero los servicios seleccionados o borra la selección; de lo contrario, esas elecciones se descartan.",
2905
2908
  "add": "Añadir servicio",
2906
- "addAnother": "Añadir otro servicio",
2907
2909
  "toast": {
2908
2910
  "addedTitle": "Servicio añadido",
2909
2911
  "addedDescription": "{title} está en el tablero, configúralo abajo.",
2910
- "addFailedTitle": "No se pudo añadir el servicio"
2912
+ "addFailedTitle": "No se pudo añadir el servicio",
2913
+ "servicesAddedTitle": "Servicios añadidos",
2914
+ "servicesAddedDescription": "{count} servicio añadido al tablero. | {count} servicios añadidos al tablero."
2911
2915
  },
2912
2916
  "repoType": "Tipo de repositorio",
2913
2917
  "repoTypeHint": "Qué es este repositorio: un servicio backend, una aplicación frontend, una biblioteca compartida o un repositorio de documentación (solo documentos/spikes)."
@@ -2919,6 +2923,7 @@
2919
2923
  "empty": "No hay nada aquí.",
2920
2924
  "select": "Seleccionar",
2921
2925
  "selected": "Seleccionado",
2926
+ "added": "Añadido",
2922
2927
  "useThisFolder": "Usar esta carpeta",
2923
2928
  "errors": {
2924
2929
  "listDirectory": "No se pudo listar el directorio"
@@ -2894,20 +2894,24 @@
2894
2894
  },
2895
2895
  "monorepoLabel": "Ceci est un monorepo (héberge plusieurs services)",
2896
2896
  "monorepoDescription": "Ajoutez plusieurs services depuis un même dépôt, chacun rattaché à un sous-répertoire.",
2897
- "monorepoBrowseHint": "Parcourez le dépôt et choisissez le répertoire du service que vous voulez ajouter. Les agents travaillant sur ce service s'exécuteront dans ce sous-répertoire.",
2898
- "serviceDirectory": "Répertoire du service :",
2899
- "noDirectorySelected": "Aucun répertoire sélectionné pour le moment.",
2897
+ "monorepoBrowseHint": "Parcourez le dépôt et sélectionnez les répertoires des services que vous voulez ajouter, depuis n'importe quel dossier. Les agents travaillant sur un service s'exécutent dans son sous-répertoire.",
2898
+ "selectedServices": "Services sélectionnés",
2899
+ "noServicesSelected": "Aucun service sélectionné pour le moment. Choisissez des répertoires ci-dessus.",
2900
+ "addServices": "Ajouter {count} service | Ajouter {count} services",
2901
+ "removeService": "Retirer {directory}",
2900
2902
  "addedConfigure": "{title} ajouté, configurez-le",
2901
2903
  "grantAccess": "Accorder à l'App l'accès à un dépôt",
2902
2904
  "grantAccessTitle": "Ouvrir les paramètres d'installation de l'App pour lui accorder l'accès à un dépôt",
2903
2905
  "refreshList": "Actualiser la liste",
2904
2906
  "done": "Terminé",
2907
+ "donePendingHint": "Ajoutez d'abord les services sélectionnés ou effacez la sélection, sinon ces choix seront perdus.",
2905
2908
  "add": "Ajouter le service",
2906
- "addAnother": "Ajouter un autre service",
2907
2909
  "toast": {
2908
2910
  "addedTitle": "Service ajouté",
2909
2911
  "addedDescription": "{title} est sur le tableau, configurez-le ci-dessous.",
2910
- "addFailedTitle": "Impossible d'ajouter le service"
2912
+ "addFailedTitle": "Impossible d'ajouter le service",
2913
+ "servicesAddedTitle": "Services ajoutés",
2914
+ "servicesAddedDescription": "{count} service ajouté au tableau. | {count} services ajoutés au tableau."
2911
2915
  },
2912
2916
  "repoType": "Type de dépôt",
2913
2917
  "repoTypeHint": "Ce qu'est ce dépôt : un service backend, une application frontend, une bibliothèque partagée ou un dépôt de documentation (documents/spikes uniquement)."
@@ -2919,6 +2923,7 @@
2919
2923
  "empty": "Rien ici.",
2920
2924
  "select": "Sélectionner",
2921
2925
  "selected": "Sélectionné",
2926
+ "added": "Ajouté",
2922
2927
  "useThisFolder": "Utiliser ce dossier",
2923
2928
  "errors": {
2924
2929
  "listDirectory": "Impossible de lister le répertoire"
@@ -2905,20 +2905,24 @@
2905
2905
  },
2906
2906
  "monorepoLabel": "זהו מונורפו (מארח יותר משירות אחד)",
2907
2907
  "monorepoDescription": "הוסף כמה שירותים ממאגר אחד, כל אחד מוצמד לתת-ספרייה.",
2908
- "monorepoBrowseHint": "עיין במאגר ובחר את הספרייה של השירות שברצונך להוסיף. סוכנים העובדים על שירות זה ירוצו בתוך אותה תת-ספרייה.",
2909
- "serviceDirectory": "ספריית שירות:",
2910
- "noDirectorySelected": "לא נבחרה עדיין ספרייה.",
2908
+ "monorepoBrowseHint": "עיין במאגר ובחר את הספריות של השירותים שברצונך להוסיף — מכל תיקייה. סוכנים העובדים על שירות ירוצו בתוך תת-הספרייה שלו.",
2909
+ "selectedServices": "שירותים נבחרים",
2910
+ "noServicesSelected": "עדיין לא נבחרו שירותים. בחר ספריות למעלה.",
2911
+ "addServices": "הוסף שירות {count} | הוסף {count} שירותים",
2912
+ "removeService": "הסר {directory}",
2911
2913
  "addedConfigure": "{title} נוסף, הגדר אותו",
2912
2914
  "grantAccess": "הענק לאפליקציה גישה למאגר",
2913
2915
  "grantAccessTitle": "פתח את הגדרות ההתקנה של האפליקציה כדי להעניק לה גישה למאגר",
2914
2916
  "refreshList": "רענן רשימה",
2915
2917
  "done": "סיום",
2918
+ "donePendingHint": "הוסף תחילה את השירותים שנבחרו או נקה את הבחירה — אחרת בחירות אלה יימחקו.",
2916
2919
  "add": "הוסף שירות",
2917
- "addAnother": "הוסף שירות נוסף",
2918
2920
  "toast": {
2919
2921
  "addedTitle": "השירות נוסף",
2920
2922
  "addedDescription": "{title} על הלוח, הגדר אותו למטה.",
2921
- "addFailedTitle": "לא ניתן היה להוסיף שירות"
2923
+ "addFailedTitle": "לא ניתן היה להוסיף שירות",
2924
+ "servicesAddedTitle": "השירותים נוספו",
2925
+ "servicesAddedDescription": "שירות {count} נוסף ללוח. | {count} שירותים נוספו ללוח."
2922
2926
  },
2923
2927
  "repoType": "סוג המאגר",
2924
2928
  "repoTypeHint": "מה המאגר הזה: שירות בק-אנד, אפליקציית פרונט-אנד, ספרייה משותפת או מאגר תיעוד (מסמכים/ספייקים בלבד)."
@@ -2930,6 +2934,7 @@
2930
2934
  "empty": "אין כאן כלום.",
2931
2935
  "select": "בחר",
2932
2936
  "selected": "נבחר",
2937
+ "added": "נוסף",
2933
2938
  "useThisFolder": "השתמש בתיקייה זו",
2934
2939
  "errors": {
2935
2940
  "listDirectory": "לא ניתן היה לרשום את הספרייה"
@@ -2523,20 +2523,24 @@
2523
2523
  },
2524
2524
  "monorepoLabel": "Questo è un monorepo (ospita più di un servizio)",
2525
2525
  "monorepoDescription": "Aggiungi più servizi da un unico repo, ciascuno ancorato a una sottodirectory.",
2526
- "monorepoBrowseHint": "Sfoglia il repository e scegli la directory del servizio che vuoi aggiungere. Gli agenti che lavorano su questo servizio verranno eseguiti all'interno di quella sottodirectory.",
2527
- "serviceDirectory": "Directory del servizio:",
2528
- "noDirectorySelected": "Nessuna directory ancora selezionata.",
2526
+ "monorepoBrowseHint": "Sfoglia il repository e seleziona le directory dei servizi che vuoi aggiungere, da qualsiasi cartella. Gli agenti che lavorano su un servizio verranno eseguiti all'interno della sua sottodirectory.",
2527
+ "selectedServices": "Servizi selezionati",
2528
+ "noServicesSelected": "Nessun servizio ancora selezionato. Scegli le directory sopra.",
2529
+ "addServices": "Aggiungi {count} servizio | Aggiungi {count} servizi",
2530
+ "removeService": "Rimuovi {directory}",
2529
2531
  "addedConfigure": "{title} aggiunto, configuralo",
2530
2532
  "grantAccess": "Concedi alla App l'accesso a un repo",
2531
2533
  "grantAccessTitle": "Apri le impostazioni di installazione della App per concederle l'accesso a un repository",
2532
2534
  "refreshList": "Aggiorna l'elenco",
2533
2535
  "done": "Fatto",
2536
+ "donePendingHint": "Aggiungi prima i servizi selezionati oppure annulla la selezione, altrimenti quelle scelte andranno perse.",
2534
2537
  "add": "Aggiungi servizio",
2535
- "addAnother": "Aggiungi un altro servizio",
2536
2538
  "toast": {
2537
2539
  "addedTitle": "Servizio aggiunto",
2538
2540
  "addedDescription": "{title} è sulla board, configuralo qui sotto.",
2539
- "addFailedTitle": "Impossibile aggiungere il servizio"
2541
+ "addFailedTitle": "Impossibile aggiungere il servizio",
2542
+ "servicesAddedTitle": "Servizi aggiunti",
2543
+ "servicesAddedDescription": "{count} servizio aggiunto alla board. | {count} servizi aggiunti alla board."
2540
2544
  }
2541
2545
  },
2542
2546
  "repoTree": {
@@ -2546,6 +2550,7 @@
2546
2550
  "empty": "Niente qui.",
2547
2551
  "select": "Seleziona",
2548
2552
  "selected": "Selezionata",
2553
+ "added": "Aggiunto",
2549
2554
  "useThisFolder": "Usa questa cartella",
2550
2555
  "errors": {
2551
2556
  "listDirectory": "Impossibile elencare la directory"
@@ -2906,20 +2906,24 @@
2906
2906
  },
2907
2907
  "monorepoLabel": "これはモノレポです (複数のサービスをホストしています)",
2908
2908
  "monorepoDescription": "1つのリポジトリから複数のサービスを追加し、それぞれをサブディレクトリに固定します。",
2909
- "monorepoBrowseHint": "リポジトリを参照し、追加したいサービスのディレクトリを選択してください。このサービスで作業するエージェントは、そのサブディレクトリ内で実行されます。",
2910
- "serviceDirectory": "サービスディレクトリ:",
2911
- "noDirectorySelected": "ディレクトリはまだ選択されていません。",
2909
+ "monorepoBrowseHint": "リポジトリを参照し、追加したいサービスのディレクトリを任意のフォルダから選択してください。サービスで作業するエージェントは、そのサブディレクトリ内で実行されます。",
2910
+ "selectedServices": "選択したサービス",
2911
+ "noServicesSelected": "サービスがまだ選択されていません。上でディレクトリを選択してください。",
2912
+ "addServices": "{count}件のサービスを追加 | {count}件のサービスを追加",
2913
+ "removeService": "{directory} を削除",
2912
2914
  "addedConfigure": "{title}を追加しました。設定してください",
2913
2915
  "grantAccess": "Appにリポジトリへのアクセス権を付与",
2914
2916
  "grantAccessTitle": "Appのインストール設定を開いて、リポジトリへのアクセス権を付与します",
2915
2917
  "refreshList": "リストを更新",
2916
2918
  "done": "完了",
2919
+ "donePendingHint": "先に選択したサービスを追加するか、選択を解除してください。そうしないと、その選択は破棄されます。",
2917
2920
  "add": "サービスを追加",
2918
- "addAnother": "別のサービスを追加",
2919
2921
  "toast": {
2920
2922
  "addedTitle": "サービスを追加しました",
2921
2923
  "addedDescription": "{title}がボードに追加されました。以下で設定してください。",
2922
- "addFailedTitle": "サービスを追加できませんでした"
2924
+ "addFailedTitle": "サービスを追加できませんでした",
2925
+ "servicesAddedTitle": "サービスを追加しました",
2926
+ "servicesAddedDescription": "{count}件のサービスをボードに追加しました。 | {count}件のサービスをボードに追加しました。"
2923
2927
  },
2924
2928
  "repoType": "リポジトリの種類",
2925
2929
  "repoTypeHint": "このリポジトリの種類: バックエンドサービス、フロントエンドアプリ、共有ライブラリ、またはドキュメントリポジトリ(ドキュメント/スパイクのみ)。"
@@ -2931,6 +2935,7 @@
2931
2935
  "empty": "ここには何もありません。",
2932
2936
  "select": "選択",
2933
2937
  "selected": "選択済み",
2938
+ "added": "追加済み",
2934
2939
  "useThisFolder": "このフォルダを使用",
2935
2940
  "errors": {
2936
2941
  "listDirectory": "ディレクトリを一覧表示できませんでした"
@@ -2894,20 +2894,24 @@
2894
2894
  },
2895
2895
  "monorepoLabel": "To jest monorepo (zawiera więcej niż jedną usługę)",
2896
2896
  "monorepoDescription": "Dodaj kilka usług z jednego repozytorium, każdą przypiętą do podkatalogu.",
2897
- "monorepoBrowseHint": "Przeglądaj repozytorium i wybierz katalog usługi, którą chcesz dodać. Agenci pracujący nad usługą będą działać w obrębie tego podkatalogu.",
2898
- "serviceDirectory": "Katalog usługi:",
2899
- "noDirectorySelected": "Nie wybrano jeszcze żadnego katalogu.",
2897
+ "monorepoBrowseHint": "Przeglądaj repozytorium i wybierz katalogi usług, które chcesz dodać — z dowolnego folderu. Agenci pracujący nad usługą działają w obrębie jej podkatalogu.",
2898
+ "selectedServices": "Wybrane usługi",
2899
+ "noServicesSelected": "Nie wybrano jeszcze żadnych usług. Wybierz katalogi powyżej.",
2900
+ "addServices": "Dodaj {count} usługę | Dodaj {count} usługi | Dodaj {count} usług",
2901
+ "removeService": "Usuń {directory}",
2900
2902
  "addedConfigure": "Dodano {title}, skonfiguruj",
2901
2903
  "grantAccess": "Przyznaj aplikacji dostęp do repozytorium",
2902
2904
  "grantAccessTitle": "Otwórz ustawienia instalacji aplikacji, aby przyznać jej dostęp do repozytorium",
2903
2905
  "refreshList": "Odśwież listę",
2904
2906
  "done": "Gotowe",
2907
+ "donePendingHint": "Najpierw dodaj wybrane usługi albo wyczyść zaznaczenie — w przeciwnym razie te wybory zostaną odrzucone.",
2905
2908
  "add": "Dodaj usługę",
2906
- "addAnother": "Dodaj kolejną usługę",
2907
2909
  "toast": {
2908
2910
  "addedTitle": "Dodano usługę",
2909
2911
  "addedDescription": "{title} jest na tablicy, skonfiguruj ją poniżej.",
2910
- "addFailedTitle": "Nie udało się dodać usługi"
2912
+ "addFailedTitle": "Nie udało się dodać usługi",
2913
+ "servicesAddedTitle": "Dodano usługi",
2914
+ "servicesAddedDescription": "Dodano {count} usługę do tablicy. | Dodano {count} usługi do tablicy. | Dodano {count} usług do tablicy."
2911
2915
  },
2912
2916
  "repoType": "Typ repozytorium",
2913
2917
  "repoTypeHint": "Czym jest to repozytorium: usługą backendową, aplikacją frontendową, współdzieloną biblioteką lub repozytorium dokumentacji (tylko dokumenty/spike'i)."
@@ -2919,6 +2923,7 @@
2919
2923
  "empty": "Pusto.",
2920
2924
  "select": "Wybierz",
2921
2925
  "selected": "Wybrano",
2926
+ "added": "Dodano",
2922
2927
  "useThisFolder": "Użyj tego folderu",
2923
2928
  "errors": {
2924
2929
  "listDirectory": "Nie udało się wyświetlić katalogu"
@@ -2906,20 +2906,24 @@
2906
2906
  },
2907
2907
  "monorepoLabel": "Bu bir monorepo (birden fazla servis barındırır)",
2908
2908
  "monorepoDescription": "Tek depodan, her biri bir alt dizine sabitlenmiş birkaç servis ekleyin.",
2909
- "monorepoBrowseHint": "Depoyu inceleyin ve eklemek istediğiniz servisin dizinini seçin. Bu servis üzerinde çalışan ajanlar o alt dizin içinde çalışır.",
2910
- "serviceDirectory": "Servis dizini:",
2911
- "noDirectorySelected": "Henüz dizin seçilmedi.",
2909
+ "monorepoBrowseHint": "Depoyu inceleyin ve eklemek istediğiniz servislerin dizinlerini herhangi bir klasörden seçin. Bir servis üzerinde çalışan ajanlar onun alt dizininde çalışır.",
2910
+ "selectedServices": "Seçili servisler",
2911
+ "noServicesSelected": "Henüz servis seçilmedi. Yukarıdan dizin seçin.",
2912
+ "addServices": "{count} servis ekle | {count} servis ekle",
2913
+ "removeService": "{directory} öğesini kaldır",
2912
2914
  "addedConfigure": "{title} eklendi, yapılandırın",
2913
2915
  "grantAccess": "App'e bir depoya erişim ver",
2914
2916
  "grantAccessTitle": "App'e bir depoya erişim vermek için kurulum ayarlarını açın",
2915
2917
  "refreshList": "Listeyi yenile",
2916
2918
  "done": "Tamam",
2919
+ "donePendingHint": "Önce seçtiğiniz servisleri ekleyin ya da seçimi temizleyin; aksi halde bu seçimler atılır.",
2917
2920
  "add": "Servis ekle",
2918
- "addAnother": "Başka bir servis ekle",
2919
2921
  "toast": {
2920
2922
  "addedTitle": "Servis eklendi",
2921
2923
  "addedDescription": "{title} panoda, aşağıdan yapılandırın.",
2922
- "addFailedTitle": "Servis eklenemedi"
2924
+ "addFailedTitle": "Servis eklenemedi",
2925
+ "servicesAddedTitle": "Servisler eklendi",
2926
+ "servicesAddedDescription": "{count} servis panoya eklendi. | {count} servis panoya eklendi."
2923
2927
  },
2924
2928
  "repoType": "Depo türü",
2925
2929
  "repoTypeHint": "Bu deponun türü: bir backend servisi, bir frontend uygulaması, paylaşılan bir kütüphane veya bir doküman deposu (yalnızca doküman/spike)."
@@ -2931,6 +2935,7 @@
2931
2935
  "empty": "Burada bir şey yok.",
2932
2936
  "select": "Seç",
2933
2937
  "selected": "Seçildi",
2938
+ "added": "Eklendi",
2934
2939
  "useThisFolder": "Bu klasörü kullan",
2935
2940
  "errors": {
2936
2941
  "listDirectory": "Dizin listelenemedi"
@@ -2894,20 +2894,24 @@
2894
2894
  },
2895
2895
  "monorepoLabel": "Це монорепозиторій (містить більше одного сервісу)",
2896
2896
  "monorepoDescription": "Додайте кілька сервісів з одного репозиторію, кожен прикріплений до підкаталогу.",
2897
- "monorepoBrowseHint": "Перегляньте репозиторій і виберіть каталог сервісу, який хочете додати. Агенти, що працюють над цим сервісом, виконуватимуться в межах цього підкаталогу.",
2898
- "serviceDirectory": "Каталог сервісу:",
2899
- "noDirectorySelected": "Каталог ще не вибрано.",
2897
+ "monorepoBrowseHint": "Перегляньте репозиторій і виберіть каталоги сервісів, які хочете додати — з будь-якої папки. Агенти, що працюють над сервісом, виконуються в межах його підкаталогу.",
2898
+ "selectedServices": "Вибрані сервіси",
2899
+ "noServicesSelected": "Сервіси ще не вибрано. Виберіть каталоги вище.",
2900
+ "addServices": "Додати {count} сервіс | Додати {count} сервіси | Додати {count} сервісів",
2901
+ "removeService": "Видалити {directory}",
2900
2902
  "addedConfigure": "{title} додано, налаштуйте",
2901
2903
  "grantAccess": "Надати застосунку доступ до репозиторію",
2902
2904
  "grantAccessTitle": "Відкрити налаштування встановлення застосунку, щоб надати йому доступ до репозиторію",
2903
2905
  "refreshList": "Оновити список",
2904
2906
  "done": "Готово",
2907
+ "donePendingHint": "Спершу додайте вибрані сервіси або очистіть вибір — інакше ці позначення буде відкинуто.",
2905
2908
  "add": "Додати сервіс",
2906
- "addAnother": "Додати ще один сервіс",
2907
2909
  "toast": {
2908
2910
  "addedTitle": "Сервіс додано",
2909
2911
  "addedDescription": "{title} на дошці, налаштуйте його нижче.",
2910
- "addFailedTitle": "Не вдалося додати сервіс"
2912
+ "addFailedTitle": "Не вдалося додати сервіс",
2913
+ "servicesAddedTitle": "Сервіси додано",
2914
+ "servicesAddedDescription": "Додано {count} сервіс до дошки. | Додано {count} сервіси до дошки. | Додано {count} сервісів до дошки."
2911
2915
  },
2912
2916
  "repoType": "Тип репозиторію",
2913
2917
  "repoTypeHint": "Що це за репозиторій: бекенд-сервіс, фронтенд-застосунок, спільна бібліотека або репозиторій документації (лише документи/спайки)."
@@ -2919,6 +2923,7 @@
2919
2923
  "empty": "Тут нічого немає.",
2920
2924
  "select": "Вибрати",
2921
2925
  "selected": "Вибрано",
2926
+ "added": "Додано",
2922
2927
  "useThisFolder": "Використати цю папку",
2923
2928
  "errors": {
2924
2929
  "listDirectory": "Не вдалося отримати список каталогу"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/app",
3
- "version": "0.116.7",
3
+ "version": "0.116.9",
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",