@cat-factory/app 0.124.0 → 0.126.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/panels/OperatorDashboardPanel.vue +41 -4
- package/app/components/settings/ApiTokensPanel.vue +46 -3
- package/app/stores/publicApiKeys.spec.ts +2 -1
- package/app/stores/publicApiKeys.ts +7 -4
- package/app/types/publicApiKeys.ts +1 -0
- package/i18n/locales/de.json +10 -0
- package/i18n/locales/en.json +10 -0
- package/i18n/locales/es.json +10 -0
- package/i18n/locales/fr.json +10 -0
- package/i18n/locales/he.json +10 -0
- package/i18n/locales/it.json +10 -0
- package/i18n/locales/ja.json +10 -0
- package/i18n/locales/pl.json +10 -0
- package/i18n/locales/tr.json +10 -0
- package/i18n/locales/uk.json +10 -0
- package/package.json +2 -2
|
@@ -345,8 +345,12 @@ watch(
|
|
|
345
345
|
>
|
|
346
346
|
{{ t('platformObservability.durations.empty') }}
|
|
347
347
|
</div>
|
|
348
|
-
<dl
|
|
349
|
-
|
|
348
|
+
<dl
|
|
349
|
+
v-else
|
|
350
|
+
class="grid grid-cols-3 gap-y-3 text-center"
|
|
351
|
+
data-testid="operator-durations"
|
|
352
|
+
>
|
|
353
|
+
<div>
|
|
350
354
|
<dt class="text-[11px] text-slate-500">
|
|
351
355
|
{{ t('platformObservability.durations.avg') }}
|
|
352
356
|
</dt>
|
|
@@ -354,7 +358,7 @@ watch(
|
|
|
354
358
|
{{ view.durations.avgMs == null ? '—' : formatMs(view.durations.avgMs) }}
|
|
355
359
|
</dd>
|
|
356
360
|
</div>
|
|
357
|
-
<div
|
|
361
|
+
<div>
|
|
358
362
|
<dt class="text-[11px] text-slate-500">
|
|
359
363
|
{{ t('platformObservability.durations.min') }}
|
|
360
364
|
</dt>
|
|
@@ -362,7 +366,7 @@ watch(
|
|
|
362
366
|
{{ view.durations.minMs == null ? '—' : formatMs(view.durations.minMs) }}
|
|
363
367
|
</dd>
|
|
364
368
|
</div>
|
|
365
|
-
<div
|
|
369
|
+
<div>
|
|
366
370
|
<dt class="text-[11px] text-slate-500">
|
|
367
371
|
{{ t('platformObservability.durations.max') }}
|
|
368
372
|
</dt>
|
|
@@ -370,6 +374,39 @@ watch(
|
|
|
370
374
|
{{ view.durations.maxMs == null ? '—' : formatMs(view.durations.maxMs) }}
|
|
371
375
|
</dd>
|
|
372
376
|
</div>
|
|
377
|
+
<div>
|
|
378
|
+
<dt class="text-[11px] text-slate-500">
|
|
379
|
+
{{ t('platformObservability.durations.p50') }}
|
|
380
|
+
</dt>
|
|
381
|
+
<dd
|
|
382
|
+
class="font-semibold text-slate-300"
|
|
383
|
+
data-testid="operator-duration-p50"
|
|
384
|
+
>
|
|
385
|
+
{{ view.durations.p50Ms == null ? '—' : formatMs(view.durations.p50Ms) }}
|
|
386
|
+
</dd>
|
|
387
|
+
</div>
|
|
388
|
+
<div>
|
|
389
|
+
<dt class="text-[11px] text-slate-500">
|
|
390
|
+
{{ t('platformObservability.durations.p90') }}
|
|
391
|
+
</dt>
|
|
392
|
+
<dd
|
|
393
|
+
class="font-semibold text-slate-300"
|
|
394
|
+
data-testid="operator-duration-p90"
|
|
395
|
+
>
|
|
396
|
+
{{ view.durations.p90Ms == null ? '—' : formatMs(view.durations.p90Ms) }}
|
|
397
|
+
</dd>
|
|
398
|
+
</div>
|
|
399
|
+
<div>
|
|
400
|
+
<dt class="text-[11px] text-slate-500">
|
|
401
|
+
{{ t('platformObservability.durations.p99') }}
|
|
402
|
+
</dt>
|
|
403
|
+
<dd
|
|
404
|
+
class="font-semibold text-slate-300"
|
|
405
|
+
data-testid="operator-duration-p99"
|
|
406
|
+
>
|
|
407
|
+
{{ view.durations.p99Ms == null ? '—' : formatMs(view.durations.p99Ms) }}
|
|
408
|
+
</dd>
|
|
409
|
+
</div>
|
|
373
410
|
</dl>
|
|
374
411
|
</div>
|
|
375
412
|
</div>
|
|
@@ -5,11 +5,30 @@
|
|
|
5
5
|
// only (label + created / last-used). To rotate a token, revoke it and mint a new one.
|
|
6
6
|
// Opened from the Integrations hub.
|
|
7
7
|
import { computed, ref, watch } from 'vue'
|
|
8
|
-
import type { PublicApiKey } from '~/types/publicApiKeys'
|
|
8
|
+
import type { PublicApiKey, PublicApiScope } from '~/types/publicApiKeys'
|
|
9
9
|
import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
|
|
10
10
|
import CopyButton from '~/components/common/CopyButton.vue'
|
|
11
11
|
|
|
12
12
|
const { t, d } = useI18n()
|
|
13
|
+
|
|
14
|
+
// The permission ladder a minted key can carry (read ⊂ write ⊂ admin), mirroring the backend
|
|
15
|
+
// contract. A `read` key can only observe; `write` adds create/start/manage; `admin` adds the
|
|
16
|
+
// destructive/merge-adjacent operations (e.g. deleting a task).
|
|
17
|
+
const SCOPES: PublicApiScope[] = ['read', 'write', 'admin']
|
|
18
|
+
|
|
19
|
+
/** Localized label for a scope — an exhaustive switch, so a new scope is a compile error here. */
|
|
20
|
+
function scopeLabel(scope: PublicApiScope): string {
|
|
21
|
+
switch (scope) {
|
|
22
|
+
case 'read':
|
|
23
|
+
return t('settings.apiTokens.scopes.read')
|
|
24
|
+
case 'write':
|
|
25
|
+
return t('settings.apiTokens.scopes.write')
|
|
26
|
+
case 'admin':
|
|
27
|
+
return t('settings.apiTokens.scopes.admin')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const scopeItems = computed(() => SCOPES.map((value) => ({ value, label: scopeLabel(value) })))
|
|
13
32
|
const ui = useUiStore()
|
|
14
33
|
const store = usePublicApiKeysStore()
|
|
15
34
|
const toast = useToast()
|
|
@@ -22,6 +41,8 @@ const open = computed({
|
|
|
22
41
|
const back = useIntegrationBack(open)
|
|
23
42
|
|
|
24
43
|
const label = ref('')
|
|
44
|
+
// The scope the next minted key will carry; defaults to the safe middle of the ladder.
|
|
45
|
+
const scope = ref<PublicApiScope>('write')
|
|
25
46
|
const busy = ref(false)
|
|
26
47
|
// The full raw secret from the most recent create — surfaced once, then dismissed. Never
|
|
27
48
|
// re-fetchable, so it lives only in this transient ref (not the store).
|
|
@@ -58,9 +79,10 @@ async function createToken() {
|
|
|
58
79
|
if (!trimmed) return
|
|
59
80
|
busy.value = true
|
|
60
81
|
try {
|
|
61
|
-
const created = await store.create(trimmed)
|
|
82
|
+
const created = await store.create(trimmed, scope.value)
|
|
62
83
|
newSecret.value = created.secret
|
|
63
84
|
label.value = ''
|
|
85
|
+
scope.value = 'write'
|
|
64
86
|
toast.add({
|
|
65
87
|
title: t('settings.apiTokens.toast.created'),
|
|
66
88
|
icon: 'i-lucide-check',
|
|
@@ -145,7 +167,17 @@ async function revokeToken(key: PublicApiKey) {
|
|
|
145
167
|
class="flex items-center justify-between gap-2 rounded-md border border-slate-800 px-3 py-2"
|
|
146
168
|
>
|
|
147
169
|
<div class="min-w-0 space-y-0.5">
|
|
148
|
-
<div class="
|
|
170
|
+
<div class="flex items-center gap-2">
|
|
171
|
+
<span class="truncate text-sm font-medium">{{ key.label }}</span>
|
|
172
|
+
<UBadge
|
|
173
|
+
color="neutral"
|
|
174
|
+
variant="subtle"
|
|
175
|
+
size="sm"
|
|
176
|
+
:data-testid="`api-token-scope-${key.id}`"
|
|
177
|
+
>
|
|
178
|
+
{{ scopeLabel(key.scope) }}
|
|
179
|
+
</UBadge>
|
|
180
|
+
</div>
|
|
149
181
|
<div class="text-[11px] text-slate-500">
|
|
150
182
|
{{
|
|
151
183
|
t('settings.apiTokens.list.created', {
|
|
@@ -190,6 +222,17 @@ async function revokeToken(key: PublicApiKey) {
|
|
|
190
222
|
@keyup.enter="createToken"
|
|
191
223
|
/>
|
|
192
224
|
</UFormField>
|
|
225
|
+
<UFormField
|
|
226
|
+
:label="t('settings.apiTokens.add.scope')"
|
|
227
|
+
:help="t('settings.apiTokens.add.scopeHelp')"
|
|
228
|
+
>
|
|
229
|
+
<USelect
|
|
230
|
+
v-model="scope"
|
|
231
|
+
:items="scopeItems"
|
|
232
|
+
class="w-full"
|
|
233
|
+
data-testid="api-token-scope"
|
|
234
|
+
/>
|
|
235
|
+
</UFormField>
|
|
193
236
|
<UButton
|
|
194
237
|
:loading="busy"
|
|
195
238
|
:disabled="!label.trim()"
|
|
@@ -10,6 +10,7 @@ function key(over: Partial<PublicApiKey> = {}): PublicApiKey {
|
|
|
10
10
|
accountId: 'acc1',
|
|
11
11
|
workspaceId: 'ws1',
|
|
12
12
|
label: 'CI',
|
|
13
|
+
scope: 'write',
|
|
13
14
|
createdAt: 1,
|
|
14
15
|
lastUsedAt: null,
|
|
15
16
|
revokedAt: null,
|
|
@@ -83,7 +84,7 @@ describe('publicApiKeys store', () => {
|
|
|
83
84
|
|
|
84
85
|
const store = usePublicApiKeysStore()
|
|
85
86
|
await store.load()
|
|
86
|
-
const result = await store.create('deploy')
|
|
87
|
+
const result = await store.create('deploy', 'admin')
|
|
87
88
|
|
|
88
89
|
expect(result.secret).toBe('cf_live_pak_new.abc')
|
|
89
90
|
expect(store.keys.map((k) => k.id)).toEqual(['pak_new', 'pak_old'])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { ref } from 'vue'
|
|
3
|
-
import type { CreatedPublicApiKey, PublicApiKey } from '~/types/publicApiKeys'
|
|
3
|
+
import type { CreatedPublicApiKey, PublicApiKey, PublicApiScope } from '~/types/publicApiKeys'
|
|
4
4
|
import { useWorkspaceStore } from '~/stores/workspace'
|
|
5
5
|
import { apiErrorStatus } from '~/composables/api/errors'
|
|
6
6
|
|
|
@@ -51,10 +51,13 @@ export const usePublicApiKeysStore = defineStore('publicApiKeys', () => {
|
|
|
51
51
|
return inFlight
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/**
|
|
55
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Mint a key with a permission `scope` (read ⊂ write ⊂ admin). Returns the created record
|
|
56
|
+
* PLUS the one-time raw secret (shown once).
|
|
57
|
+
*/
|
|
58
|
+
async function create(label: string, scope: PublicApiScope): Promise<CreatedPublicApiKey> {
|
|
56
59
|
const ws = useWorkspaceStore()
|
|
57
|
-
const created = await api.createPublicApiKey(ws.requireId(), { label })
|
|
60
|
+
const created = await api.createPublicApiKey(ws.requireId(), { label, scope })
|
|
58
61
|
// Prepend: the backend lists newest-first, so the freshly minted key belongs at the
|
|
59
62
|
// top — matching the order a subsequent `load()` would produce.
|
|
60
63
|
keys.value = [created.key, ...keys.value]
|
package/i18n/locales/de.json
CHANGED
|
@@ -541,8 +541,15 @@
|
|
|
541
541
|
"label": "Bezeichnung",
|
|
542
542
|
"labelHelp": "Ein Name, um dieses Token später wiederzuerkennen.",
|
|
543
543
|
"labelPlaceholder": "z. B. CI-Pipeline",
|
|
544
|
+
"scope": "Berechtigung",
|
|
545
|
+
"scopeHelp": "Was dieses Token darf: nur Lesen, Lesen und Schreiben oder Vollzugriff (der auch das Löschen erlaubt).",
|
|
544
546
|
"create": "Token erstellen"
|
|
545
547
|
},
|
|
548
|
+
"scopes": {
|
|
549
|
+
"read": "Nur Lesen",
|
|
550
|
+
"write": "Lesen und Schreiben",
|
|
551
|
+
"admin": "Vollzugriff"
|
|
552
|
+
},
|
|
546
553
|
"toast": {
|
|
547
554
|
"loadFailed": "API-Tokens konnten nicht geladen werden",
|
|
548
555
|
"created": "Token erstellt",
|
|
@@ -2801,6 +2808,9 @@
|
|
|
2801
2808
|
"avg": "Durchschnitt",
|
|
2802
2809
|
"min": "Min.",
|
|
2803
2810
|
"max": "Max.",
|
|
2811
|
+
"p50": "p50",
|
|
2812
|
+
"p90": "p90",
|
|
2813
|
+
"p99": "p99",
|
|
2804
2814
|
"empty": "Keine abgeschlossenen Läufe in diesem Zeitraum."
|
|
2805
2815
|
},
|
|
2806
2816
|
"live": {
|
package/i18n/locales/en.json
CHANGED
|
@@ -1416,6 +1416,9 @@
|
|
|
1416
1416
|
"avg": "Average",
|
|
1417
1417
|
"min": "Min",
|
|
1418
1418
|
"max": "Max",
|
|
1419
|
+
"p50": "p50",
|
|
1420
|
+
"p90": "p90",
|
|
1421
|
+
"p99": "p99",
|
|
1419
1422
|
"empty": "No completed runs in this window."
|
|
1420
1423
|
},
|
|
1421
1424
|
"live": {
|
|
@@ -2485,8 +2488,15 @@
|
|
|
2485
2488
|
"label": "Label",
|
|
2486
2489
|
"labelHelp": "A name to recognize this token by later.",
|
|
2487
2490
|
"labelPlaceholder": "e.g. CI pipeline",
|
|
2491
|
+
"scope": "Scope",
|
|
2492
|
+
"scopeHelp": "What this token can do: read-only, read and write, or full access (which also allows deleting).",
|
|
2488
2493
|
"create": "Create token"
|
|
2489
2494
|
},
|
|
2495
|
+
"scopes": {
|
|
2496
|
+
"read": "Read only",
|
|
2497
|
+
"write": "Read and write",
|
|
2498
|
+
"admin": "Full access"
|
|
2499
|
+
},
|
|
2490
2500
|
"toast": {
|
|
2491
2501
|
"loadFailed": "Could not load API tokens",
|
|
2492
2502
|
"created": "Token created",
|
package/i18n/locales/es.json
CHANGED
|
@@ -1359,6 +1359,9 @@
|
|
|
1359
1359
|
"avg": "Media",
|
|
1360
1360
|
"min": "Mín.",
|
|
1361
1361
|
"max": "Máx.",
|
|
1362
|
+
"p50": "p50",
|
|
1363
|
+
"p90": "p90",
|
|
1364
|
+
"p99": "p99",
|
|
1362
1365
|
"empty": "No hay ejecuciones completadas en este periodo."
|
|
1363
1366
|
},
|
|
1364
1367
|
"live": {
|
|
@@ -2300,8 +2303,15 @@
|
|
|
2300
2303
|
"label": "Etiqueta",
|
|
2301
2304
|
"labelHelp": "Un nombre para reconocer este token más adelante.",
|
|
2302
2305
|
"labelPlaceholder": "p. ej. pipeline de CI",
|
|
2306
|
+
"scope": "Alcance",
|
|
2307
|
+
"scopeHelp": "Lo que puede hacer este token: solo lectura, lectura y escritura o acceso completo (que también permite eliminar).",
|
|
2303
2308
|
"create": "Crear token"
|
|
2304
2309
|
},
|
|
2310
|
+
"scopes": {
|
|
2311
|
+
"read": "Solo lectura",
|
|
2312
|
+
"write": "Lectura y escritura",
|
|
2313
|
+
"admin": "Acceso completo"
|
|
2314
|
+
},
|
|
2305
2315
|
"toast": {
|
|
2306
2316
|
"loadFailed": "No se pudieron cargar los tokens de la API",
|
|
2307
2317
|
"created": "Token creado",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -1359,6 +1359,9 @@
|
|
|
1359
1359
|
"avg": "Moyenne",
|
|
1360
1360
|
"min": "Min.",
|
|
1361
1361
|
"max": "Max.",
|
|
1362
|
+
"p50": "p50",
|
|
1363
|
+
"p90": "p90",
|
|
1364
|
+
"p99": "p99",
|
|
1362
1365
|
"empty": "Aucune exécution terminée sur cette période."
|
|
1363
1366
|
},
|
|
1364
1367
|
"live": {
|
|
@@ -2300,8 +2303,15 @@
|
|
|
2300
2303
|
"label": "Libellé",
|
|
2301
2304
|
"labelHelp": "Un nom pour reconnaître ce jeton plus tard.",
|
|
2302
2305
|
"labelPlaceholder": "ex. pipeline CI",
|
|
2306
|
+
"scope": "Portée",
|
|
2307
|
+
"scopeHelp": "Ce que ce jeton peut faire : lecture seule, lecture et écriture, ou accès complet (qui autorise aussi la suppression).",
|
|
2303
2308
|
"create": "Créer le jeton"
|
|
2304
2309
|
},
|
|
2310
|
+
"scopes": {
|
|
2311
|
+
"read": "Lecture seule",
|
|
2312
|
+
"write": "Lecture et écriture",
|
|
2313
|
+
"admin": "Accès complet"
|
|
2314
|
+
},
|
|
2305
2315
|
"toast": {
|
|
2306
2316
|
"loadFailed": "Impossible de charger les jetons d'API",
|
|
2307
2317
|
"created": "Jeton créé",
|
package/i18n/locales/he.json
CHANGED
|
@@ -1359,6 +1359,9 @@
|
|
|
1359
1359
|
"avg": "ממוצע",
|
|
1360
1360
|
"min": "מינימום",
|
|
1361
1361
|
"max": "מקסימום",
|
|
1362
|
+
"p50": "p50",
|
|
1363
|
+
"p90": "p90",
|
|
1364
|
+
"p99": "p99",
|
|
1362
1365
|
"empty": "אין הרצות שהושלמו בטווח זה."
|
|
1363
1366
|
},
|
|
1364
1367
|
"live": {
|
|
@@ -2421,8 +2424,15 @@
|
|
|
2421
2424
|
"label": "תווית",
|
|
2422
2425
|
"labelHelp": "שם שיעזור לך לזהות את האסימון הזה בהמשך.",
|
|
2423
2426
|
"labelPlaceholder": "לדוגמה, צינור CI",
|
|
2427
|
+
"scope": "היקף הרשאות",
|
|
2428
|
+
"scopeHelp": "מה האסימון הזה יכול לעשות: קריאה בלבד, קריאה וכתיבה, או גישה מלאה (שמאפשרת גם מחיקה).",
|
|
2424
2429
|
"create": "צור אסימון"
|
|
2425
2430
|
},
|
|
2431
|
+
"scopes": {
|
|
2432
|
+
"read": "קריאה בלבד",
|
|
2433
|
+
"write": "קריאה וכתיבה",
|
|
2434
|
+
"admin": "גישה מלאה"
|
|
2435
|
+
},
|
|
2426
2436
|
"toast": {
|
|
2427
2437
|
"loadFailed": "לא ניתן לטעון את אסימוני ה-API",
|
|
2428
2438
|
"created": "האסימון נוצר",
|
package/i18n/locales/it.json
CHANGED
|
@@ -541,8 +541,15 @@
|
|
|
541
541
|
"label": "Etichetta",
|
|
542
542
|
"labelHelp": "Un nome per riconoscere questo token in seguito.",
|
|
543
543
|
"labelPlaceholder": "es. pipeline CI",
|
|
544
|
+
"scope": "Ambito",
|
|
545
|
+
"scopeHelp": "Cosa può fare questo token: sola lettura, lettura e scrittura o accesso completo (che consente anche l'eliminazione).",
|
|
544
546
|
"create": "Crea token"
|
|
545
547
|
},
|
|
548
|
+
"scopes": {
|
|
549
|
+
"read": "Sola lettura",
|
|
550
|
+
"write": "Lettura e scrittura",
|
|
551
|
+
"admin": "Accesso completo"
|
|
552
|
+
},
|
|
546
553
|
"toast": {
|
|
547
554
|
"loadFailed": "Impossibile caricare i token API",
|
|
548
555
|
"created": "Token creato",
|
|
@@ -2801,6 +2808,9 @@
|
|
|
2801
2808
|
"avg": "Media",
|
|
2802
2809
|
"min": "Min",
|
|
2803
2810
|
"max": "Max",
|
|
2811
|
+
"p50": "p50",
|
|
2812
|
+
"p90": "p90",
|
|
2813
|
+
"p99": "p99",
|
|
2804
2814
|
"empty": "Nessuna esecuzione completata in questo periodo."
|
|
2805
2815
|
},
|
|
2806
2816
|
"live": {
|
package/i18n/locales/ja.json
CHANGED
|
@@ -1359,6 +1359,9 @@
|
|
|
1359
1359
|
"avg": "平均",
|
|
1360
1360
|
"min": "最小",
|
|
1361
1361
|
"max": "最大",
|
|
1362
|
+
"p50": "p50",
|
|
1363
|
+
"p90": "p90",
|
|
1364
|
+
"p99": "p99",
|
|
1362
1365
|
"empty": "この期間に完了した実行はありません。"
|
|
1363
1366
|
},
|
|
1364
1367
|
"live": {
|
|
@@ -2422,8 +2425,15 @@
|
|
|
2422
2425
|
"label": "ラベル",
|
|
2423
2426
|
"labelHelp": "後でこのトークンを識別するための名前。",
|
|
2424
2427
|
"labelPlaceholder": "例: CI パイプライン",
|
|
2428
|
+
"scope": "権限範囲",
|
|
2429
|
+
"scopeHelp": "このトークンでできること: 読み取り専用、読み取りと書き込み、またはフルアクセス(削除も可能)。",
|
|
2425
2430
|
"create": "トークンを作成"
|
|
2426
2431
|
},
|
|
2432
|
+
"scopes": {
|
|
2433
|
+
"read": "読み取り専用",
|
|
2434
|
+
"write": "読み取りと書き込み",
|
|
2435
|
+
"admin": "フルアクセス"
|
|
2436
|
+
},
|
|
2427
2437
|
"toast": {
|
|
2428
2438
|
"loadFailed": "APIトークンを読み込めませんでした",
|
|
2429
2439
|
"created": "トークンを作成しました",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -1359,6 +1359,9 @@
|
|
|
1359
1359
|
"avg": "Średnia",
|
|
1360
1360
|
"min": "Min",
|
|
1361
1361
|
"max": "Maks",
|
|
1362
|
+
"p50": "p50",
|
|
1363
|
+
"p90": "p90",
|
|
1364
|
+
"p99": "p99",
|
|
1362
1365
|
"empty": "Brak ukończonych uruchomień w tym okresie."
|
|
1363
1366
|
},
|
|
1364
1367
|
"live": {
|
|
@@ -2300,8 +2303,15 @@
|
|
|
2300
2303
|
"label": "Etykieta",
|
|
2301
2304
|
"labelHelp": "Nazwa, po której później rozpoznasz ten token.",
|
|
2302
2305
|
"labelPlaceholder": "np. potok CI",
|
|
2306
|
+
"scope": "Zakres",
|
|
2307
|
+
"scopeHelp": "Co może ten token: tylko odczyt, odczyt i zapis lub pełny dostęp (który pozwala także na usuwanie).",
|
|
2303
2308
|
"create": "Utwórz token"
|
|
2304
2309
|
},
|
|
2310
|
+
"scopes": {
|
|
2311
|
+
"read": "Tylko odczyt",
|
|
2312
|
+
"write": "Odczyt i zapis",
|
|
2313
|
+
"admin": "Pełny dostęp"
|
|
2314
|
+
},
|
|
2305
2315
|
"toast": {
|
|
2306
2316
|
"loadFailed": "Nie udało się załadować tokenów API",
|
|
2307
2317
|
"created": "Token utworzony",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -1359,6 +1359,9 @@
|
|
|
1359
1359
|
"avg": "Ortalama",
|
|
1360
1360
|
"min": "En düşük",
|
|
1361
1361
|
"max": "En yüksek",
|
|
1362
|
+
"p50": "p50",
|
|
1363
|
+
"p90": "p90",
|
|
1364
|
+
"p99": "p99",
|
|
1362
1365
|
"empty": "Bu aralıkta tamamlanmış çalıştırma yok."
|
|
1363
1366
|
},
|
|
1364
1367
|
"live": {
|
|
@@ -2422,8 +2425,15 @@
|
|
|
2422
2425
|
"label": "Etiket",
|
|
2423
2426
|
"labelHelp": "Bu belirteci daha sonra tanımak için bir ad.",
|
|
2424
2427
|
"labelPlaceholder": "örn. CI hattı",
|
|
2428
|
+
"scope": "Kapsam",
|
|
2429
|
+
"scopeHelp": "Bu belirtecin yapabilecekleri: yalnızca okuma, okuma ve yazma ya da tam erişim (silmeye de izin verir).",
|
|
2425
2430
|
"create": "Belirteç oluştur"
|
|
2426
2431
|
},
|
|
2432
|
+
"scopes": {
|
|
2433
|
+
"read": "Yalnızca okuma",
|
|
2434
|
+
"write": "Okuma ve yazma",
|
|
2435
|
+
"admin": "Tam erişim"
|
|
2436
|
+
},
|
|
2427
2437
|
"toast": {
|
|
2428
2438
|
"loadFailed": "API belirteçleri yüklenemedi",
|
|
2429
2439
|
"created": "Belirteç oluşturuldu",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -1359,6 +1359,9 @@
|
|
|
1359
1359
|
"avg": "Середня",
|
|
1360
1360
|
"min": "Мін",
|
|
1361
1361
|
"max": "Макс",
|
|
1362
|
+
"p50": "p50",
|
|
1363
|
+
"p90": "p90",
|
|
1364
|
+
"p99": "p99",
|
|
1362
1365
|
"empty": "У цьому періоді немає завершених запусків."
|
|
1363
1366
|
},
|
|
1364
1367
|
"live": {
|
|
@@ -2300,8 +2303,15 @@
|
|
|
2300
2303
|
"label": "Мітка",
|
|
2301
2304
|
"labelHelp": "Назва, за якою ви пізніше впізнаєте цей токен.",
|
|
2302
2305
|
"labelPlaceholder": "напр. конвеєр CI",
|
|
2306
|
+
"scope": "Обсяг доступу",
|
|
2307
|
+
"scopeHelp": "Що може цей токен: лише читання, читання та запис або повний доступ (який також дозволяє видалення).",
|
|
2303
2308
|
"create": "Створити токен"
|
|
2304
2309
|
},
|
|
2310
|
+
"scopes": {
|
|
2311
|
+
"read": "Лише читання",
|
|
2312
|
+
"write": "Читання та запис",
|
|
2313
|
+
"admin": "Повний доступ"
|
|
2314
|
+
},
|
|
2305
2315
|
"toast": {
|
|
2306
2316
|
"loadFailed": "Не вдалося завантажити токени API",
|
|
2307
2317
|
"created": "Токен створено",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.126.0",
|
|
4
4
|
"description": "Reusable Nuxt layer for the Agent Architecture Board SPA (components, stores, composables, pages). Consume it from a thin deployment app via `extends: ['@cat-factory/app']` and point it at your backend with NUXT_PUBLIC_API_BASE. See deploy/frontend for an example.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"valibot": "^1.4.2",
|
|
35
35
|
"vue": "3.5.39",
|
|
36
36
|
"wretch": "^3.0.9",
|
|
37
|
-
"@cat-factory/contracts": "0.
|
|
37
|
+
"@cat-factory/contracts": "0.143.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@toad-contracts/testing": "0.3.2",
|