@cat-factory/app 0.190.0 → 0.191.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 +10 -0
- package/app/components/environments/EnvironmentSetupWizard.vue +1 -0
- package/app/components/layout/InfraSetupBanner.vue +139 -35
- package/app/components/layout/NotificationsInbox.vue +5 -0
- package/app/components/panels/AgentStepDetail.vue +2 -0
- package/app/components/panels/ReportsPanel.vue +1 -0
- package/app/components/panels/inspector/TaskRunSettings.vue +1 -0
- package/app/components/pipeline/PipelinePreview.vue +1 -0
- package/app/components/prReview/PrReviewWindow.vue +1 -0
- package/app/components/settings/RiskPolicyPanel.vue +1 -0
- package/app/components/slack/SlackPanel.vue +2 -0
- package/app/composables/api/client.spec.ts +50 -0
- package/app/composables/api/client.ts +26 -1
- package/app/composables/useWorkspaceStream.ts +6 -0
- package/app/stores/ui/modals.ts +31 -8
- package/app/stores/workspace/infraSetup.ts +77 -0
- package/app/stores/workspace.spec.ts +129 -0
- package/app/stores/workspace.ts +12 -8
- package/app/utils/infraSetup.ts +29 -0
- package/i18n/locales/de.json +9 -0
- package/i18n/locales/en.json +9 -0
- package/i18n/locales/es.json +9 -0
- package/i18n/locales/fr.json +9 -0
- package/i18n/locales/he.json +9 -0
- package/i18n/locales/it.json +9 -0
- package/i18n/locales/ja.json +9 -0
- package/i18n/locales/pl.json +9 -0
- package/i18n/locales/tr.json +9 -0
- package/i18n/locales/uk.json +9 -0
- package/package.json +2 -2
|
@@ -236,3 +236,132 @@ describe('workspace store cold-open speculative snapshot', () => {
|
|
|
236
236
|
expect(ws.access).toBeNull()
|
|
237
237
|
})
|
|
238
238
|
})
|
|
239
|
+
|
|
240
|
+
// The reachability watcher pushes ONE area's transition as an `infraSetup` event, which the stream
|
|
241
|
+
// applies through `patchInfraSetup`. Two properties matter and neither is visible from the backend:
|
|
242
|
+
// the patch is TARGETED (a full refresh here would pay the whole snapshot aggregate for a one-field
|
|
243
|
+
// delta), and recovering an area drops its SESSION dismissal so a health state re-nags when it
|
|
244
|
+
// recurs — without which dismissing one outage would silence every later one for the session.
|
|
245
|
+
describe('workspace store infraSetup patching', () => {
|
|
246
|
+
/** A ui-store stub recording which areas had their session dismissal cleared. */
|
|
247
|
+
function stubUiStore() {
|
|
248
|
+
const cleared: string[] = []
|
|
249
|
+
vi.stubGlobal('useUiStore', () => ({
|
|
250
|
+
clearInfraSetupSessionDismissal: (area: string) => cleared.push(area),
|
|
251
|
+
}))
|
|
252
|
+
return cleared
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async function openBoard(infraSetup: Record<string, string>) {
|
|
256
|
+
const snap = {
|
|
257
|
+
...snapshot('ws1', [block('f1')]),
|
|
258
|
+
infraSetup,
|
|
259
|
+
} as unknown as WorkspaceSnapshot
|
|
260
|
+
const getWorkspace = vi.fn().mockResolvedValue(snap)
|
|
261
|
+
vi.stubGlobal('useApi', () => ({ getWorkspace }))
|
|
262
|
+
const ws = useWorkspaceStore()
|
|
263
|
+
await ws.switchTo('ws1')
|
|
264
|
+
return { ws, getWorkspace }
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
it('patches one area without refetching the snapshot', async () => {
|
|
268
|
+
stubUiStore()
|
|
269
|
+
const { ws, getWorkspace } = await openBoard({
|
|
270
|
+
agentExecutor: 'configured',
|
|
271
|
+
ephemeralEnvironments: 'configured',
|
|
272
|
+
binaryStorage: 'not_defined',
|
|
273
|
+
})
|
|
274
|
+
ws.patchInfraSetup('agentExecutor', 'unreachable')
|
|
275
|
+
expect(ws.infraSetup).toEqual({
|
|
276
|
+
agentExecutor: 'unreachable',
|
|
277
|
+
ephemeralEnvironments: 'configured',
|
|
278
|
+
binaryStorage: 'not_defined',
|
|
279
|
+
})
|
|
280
|
+
// One fetch: the initial switchTo. The live patch triggered no snapshot refresh.
|
|
281
|
+
expect(getWorkspace).toHaveBeenCalledTimes(1)
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('clears the area session dismissal on RECOVERY so the next outage re-nags', async () => {
|
|
285
|
+
const cleared = stubUiStore()
|
|
286
|
+
const { ws } = await openBoard({
|
|
287
|
+
agentExecutor: 'unreachable',
|
|
288
|
+
ephemeralEnvironments: 'configured',
|
|
289
|
+
binaryStorage: 'configured',
|
|
290
|
+
})
|
|
291
|
+
ws.patchInfraSetup('agentExecutor', 'configured')
|
|
292
|
+
expect(ws.infraSetup?.agentExecutor).toBe('configured')
|
|
293
|
+
expect(cleared).toEqual(['agentExecutor'])
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
it('leaves the session dismissal alone while the area is still unreachable', async () => {
|
|
297
|
+
const cleared = stubUiStore()
|
|
298
|
+
const { ws } = await openBoard({
|
|
299
|
+
agentExecutor: 'configured',
|
|
300
|
+
ephemeralEnvironments: 'configured',
|
|
301
|
+
binaryStorage: 'configured',
|
|
302
|
+
})
|
|
303
|
+
ws.patchInfraSetup('agentExecutor', 'unreachable')
|
|
304
|
+
expect(cleared).toEqual([])
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
it('is a no-op before the first snapshot has landed', () => {
|
|
308
|
+
// An event can arrive before the projection exists; `hydrate` is about to set the authoritative
|
|
309
|
+
// one (which already folds the recorded outage), so inventing a partial projection here would
|
|
310
|
+
// render a banner from a single field with the other areas unknown.
|
|
311
|
+
stubUiStore()
|
|
312
|
+
const ws = useWorkspaceStore()
|
|
313
|
+
ws.patchInfraSetup('agentExecutor', 'unreachable')
|
|
314
|
+
expect(ws.infraSetup).toBeNull()
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('refuses to mark an area unreachable that the projection does not call configured', async () => {
|
|
318
|
+
// The live patch honours the SAME rule as the backend's snapshot fold
|
|
319
|
+
// (`applyInfraSetupTransition`). Assigning unconditionally rendered a red "check that the
|
|
320
|
+
// service is running" banner over a `not_applicable`/`not_defined` area — which then vanished on
|
|
321
|
+
// the next reload, because the projection out-ranks the probe. A banner that contradicts the
|
|
322
|
+
// projection is worse than a late one.
|
|
323
|
+
stubUiStore()
|
|
324
|
+
const { ws } = await openBoard({
|
|
325
|
+
agentExecutor: 'not_applicable',
|
|
326
|
+
ephemeralEnvironments: 'not_defined',
|
|
327
|
+
binaryStorage: 'configured',
|
|
328
|
+
})
|
|
329
|
+
ws.patchInfraSetup('agentExecutor', 'unreachable')
|
|
330
|
+
ws.patchInfraSetup('ephemeralEnvironments', 'unreachable')
|
|
331
|
+
expect(ws.infraSetup?.agentExecutor).toBe('not_applicable')
|
|
332
|
+
expect(ws.infraSetup?.ephemeralEnvironments).toBe('not_defined')
|
|
333
|
+
// A refused patch must not caption its reason onto a status it does not describe.
|
|
334
|
+
expect(ws.infraSetupDetails).toEqual({})
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('keeps the probe reason for the banner, and drops it on recovery', async () => {
|
|
338
|
+
// The reason is the one thing on the banner that says WHY (a refused connection reads very
|
|
339
|
+
// differently from a rejected token), and it rides the live event only — the notification card
|
|
340
|
+
// is content-deduped, so persisting it there would re-toast the inbox for the whole outage.
|
|
341
|
+
stubUiStore()
|
|
342
|
+
const { ws } = await openBoard({
|
|
343
|
+
agentExecutor: 'configured',
|
|
344
|
+
ephemeralEnvironments: 'configured',
|
|
345
|
+
binaryStorage: 'configured',
|
|
346
|
+
})
|
|
347
|
+
ws.patchInfraSetup('agentExecutor', 'unreachable', 'connect ECONNREFUSED 10.0.0.4:6443')
|
|
348
|
+
expect(ws.infraSetupDetails.agentExecutor).toBe('connect ECONNREFUSED 10.0.0.4:6443')
|
|
349
|
+
ws.patchInfraSetup('agentExecutor', 'configured')
|
|
350
|
+
expect(ws.infraSetupDetails.agentExecutor).toBeUndefined()
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it('drops live probe reasons when an authoritative snapshot lands', async () => {
|
|
354
|
+
stubUiStore()
|
|
355
|
+
const { ws } = await openBoard({
|
|
356
|
+
agentExecutor: 'configured',
|
|
357
|
+
ephemeralEnvironments: 'configured',
|
|
358
|
+
binaryStorage: 'configured',
|
|
359
|
+
})
|
|
360
|
+
ws.patchInfraSetup('agentExecutor', 'unreachable', 'HTTP 502')
|
|
361
|
+
expect(ws.infraSetupDetails.agentExecutor).toBe('HTTP 502')
|
|
362
|
+
await ws.refresh()
|
|
363
|
+
// A reload mid-outage renders the banner with no reason line, which is honest: this session
|
|
364
|
+
// never saw the probe, and captioning a fresh status with a stale reason would not be.
|
|
365
|
+
expect(ws.infraSetupDetails).toEqual({})
|
|
366
|
+
})
|
|
367
|
+
})
|
package/app/stores/workspace.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { defineStore } from 'pinia'
|
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
3
|
import type {
|
|
4
4
|
BudgetCaps,
|
|
5
|
-
InfraSetup,
|
|
6
5
|
SpendStatus,
|
|
7
6
|
WorkspaceAccess,
|
|
8
7
|
WorkspaceListItem,
|
|
@@ -11,6 +10,7 @@ import type {
|
|
|
11
10
|
import { useAccountsStore } from '~/stores/accounts'
|
|
12
11
|
import { useBoardStore } from '~/stores/board'
|
|
13
12
|
import { applySnapshotToStores, resetPerBoardCaches } from '~/stores/workspace/hydrate'
|
|
13
|
+
import { createInfraSetupState } from '~/stores/workspace/infraSetup'
|
|
14
14
|
import { markBoot } from '~/utils/bootMarks'
|
|
15
15
|
import { retryWhileBackendUnreachable } from '~/utils/backendReady'
|
|
16
16
|
|
|
@@ -50,12 +50,14 @@ export const useWorkspaceStore = defineStore(
|
|
|
50
50
|
const userSpend = ref<SpendStatus | null>(null)
|
|
51
51
|
/** Operator hard ceilings on the account/user budget tiers (null until first load). */
|
|
52
52
|
const budgetCaps = ref<BudgetCaps | null>(null)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
// The infra-setup slice (the banner's projection + the live reachability patch), extracted
|
|
54
|
+
// because it is the one slice with RULES rather than a plain assign-from-snapshot.
|
|
55
|
+
const {
|
|
56
|
+
infraSetup,
|
|
57
|
+
infraSetupDetails,
|
|
58
|
+
hydrate: hydrateInfraSetup,
|
|
59
|
+
patchInfraSetup,
|
|
60
|
+
} = createInfraSetupState()
|
|
59
61
|
/**
|
|
60
62
|
* The signed-in caller's resolved workspace-RBAC access to the ACTIVE board — their
|
|
61
63
|
* effective role + the permission set it grants, from the auth gate's resolution
|
|
@@ -92,7 +94,7 @@ export const useWorkspaceStore = defineStore(
|
|
|
92
94
|
accountSpend.value = snapshot.accountSpend ?? null
|
|
93
95
|
userSpend.value = snapshot.userSpend ?? null
|
|
94
96
|
budgetCaps.value = snapshot.budgetCaps ?? null
|
|
95
|
-
|
|
97
|
+
hydrateInfraSetup(snapshot.infraSetup)
|
|
96
98
|
access.value = snapshot.access ?? null
|
|
97
99
|
// Keep the board list in step (e.g. a freshly created board, or a rename). The
|
|
98
100
|
// snapshot's `workspace` carries no `viewerRole` (that's a `GET /workspaces` list
|
|
@@ -283,6 +285,8 @@ export const useWorkspaceStore = defineStore(
|
|
|
283
285
|
userSpend,
|
|
284
286
|
budgetCaps,
|
|
285
287
|
infraSetup,
|
|
288
|
+
infraSetupDetails,
|
|
289
|
+
patchInfraSetup,
|
|
286
290
|
access,
|
|
287
291
|
init,
|
|
288
292
|
switchTo,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { InfraSetupArea } from '~/types/domain'
|
|
2
|
+
|
|
3
|
+
// Shared vocabulary for the infra-setup banner's two card kinds, used by the banner itself and by
|
|
4
|
+
// the ui store's session-dismissal book-keeping.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Which CLAIM an infra-setup card is making about an area. They share one banner surface but they
|
|
8
|
+
* are not interchangeable, and every dismissal rule keys off the difference:
|
|
9
|
+
* - `setup` — "you never configured this". A stable operator decision, so it may be dismissed
|
|
10
|
+
* permanently as well as for the session.
|
|
11
|
+
* - `outage` — "you DID configure it, and a live probe cannot reach it". A health state, so it is
|
|
12
|
+
* session-dismissible only and must re-nag on recurrence.
|
|
13
|
+
*/
|
|
14
|
+
export type InfraSetupCardKind = 'setup' | 'outage'
|
|
15
|
+
|
|
16
|
+
/** A session-dismissal key: one area's one KIND of card. */
|
|
17
|
+
export type InfraSetupDismissalKey = `${InfraSetupArea}:${InfraSetupCardKind}`
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The session-dismissal key for one area's card kind. A composite key rather than a bare area,
|
|
21
|
+
* because dismissing the setup nag must not silence the outage card that a later failure raises for
|
|
22
|
+
* the same area — a different claim about a different state.
|
|
23
|
+
*/
|
|
24
|
+
export function infraSetupDismissalKey(
|
|
25
|
+
area: InfraSetupArea,
|
|
26
|
+
kind: InfraSetupCardKind,
|
|
27
|
+
): InfraSetupDismissalKey {
|
|
28
|
+
return `${area}:${kind}`
|
|
29
|
+
}
|
package/i18n/locales/de.json
CHANGED
|
@@ -1979,6 +1979,7 @@
|
|
|
1979
1979
|
"clarity_review": "Als gelesen markieren",
|
|
1980
1980
|
"release_regression": "Bestätigen",
|
|
1981
1981
|
"platform_health": "Bestätigen",
|
|
1982
|
+
"infra_unreachable": "Bestätigen",
|
|
1982
1983
|
"decision_required": "Als gelesen markieren",
|
|
1983
1984
|
"human_test_ready": "Als gelesen markieren",
|
|
1984
1985
|
"visual_confirmation_ready": "Als gelesen markieren",
|
|
@@ -2027,11 +2028,13 @@
|
|
|
2027
2028
|
"infraSetupBanner": {
|
|
2028
2029
|
"agentExecutor": {
|
|
2029
2030
|
"title": "Agent-Executor nicht konfiguriert",
|
|
2031
|
+
"unreachableTitle": "Agent-Executor ist nicht erreichbar",
|
|
2030
2032
|
"body": "Dieses Deployment führt Agenten auf einem selbst gehosteten Runner-Pool aus, aber es ist keiner registriert, sodass kein Agent laufen kann, bis Sie einen verbinden.",
|
|
2031
2033
|
"action": "Runner-Pool konfigurieren"
|
|
2032
2034
|
},
|
|
2033
2035
|
"ephemeralEnvironments": {
|
|
2034
2036
|
"title": "Testumgebung nicht konfiguriert",
|
|
2037
|
+
"unreachableTitle": "Anbieter für Testumgebungen ist nicht erreichbar",
|
|
2035
2038
|
"body": "Es ist kein Anbieter für ephemere Umgebungen registriert, sodass Test-Agenten, die eine aktive Vorschau-Umgebung benötigen, nicht laufen können. Öffnen Sie unten „Testumgebungen“ und verbinden Sie einen Kubernetes-Cluster oder einen benutzerdefinierten HTTP-Umgebungsanbieter, um sie zu aktivieren.",
|
|
2036
2039
|
"action": "Environment konfigurieren"
|
|
2037
2040
|
},
|
|
@@ -2043,6 +2046,11 @@
|
|
|
2043
2046
|
"dismiss": {
|
|
2044
2047
|
"session": "Für diese Sitzung verwerfen",
|
|
2045
2048
|
"permanent": "Ich bin mit den Einschränkungen einverstanden, nicht erneut benachrichtigen"
|
|
2049
|
+
},
|
|
2050
|
+
"unreachable": {
|
|
2051
|
+
"body": "Die Verbindung ist eingerichtet, aber eine Live-Prüfung konnte sie gerade nicht erreichen. Damit ist das ein Ausfall und keine fehlende Einrichtung: Agenten, die darauf angewiesen sind, schlagen fehl, bis wieder eine Antwort kommt. Prüfen Sie, ob der Dienst läuft, und testen Sie die Verbindung dann erneut.",
|
|
2052
|
+
"reason": "Letzte Prüfung: {detail}",
|
|
2053
|
+
"action": "Verbindung prüfen"
|
|
2046
2054
|
}
|
|
2047
2055
|
},
|
|
2048
2056
|
"spendWarningBanner": {
|
|
@@ -4737,6 +4745,7 @@
|
|
|
4737
4745
|
},
|
|
4738
4746
|
"routable": {
|
|
4739
4747
|
"platform_health": "Plattformzustand",
|
|
4748
|
+
"infra_unreachable": "Infrastrukturausfälle",
|
|
4740
4749
|
"merge_review": "Merge-Review",
|
|
4741
4750
|
"pipeline_complete": "Pipeline abgeschlossen",
|
|
4742
4751
|
"ci_failed": "CI fehlgeschlagen",
|
package/i18n/locales/en.json
CHANGED
|
@@ -1962,6 +1962,7 @@
|
|
|
1962
1962
|
"clarity_review": "Mark read",
|
|
1963
1963
|
"release_regression": "Acknowledge",
|
|
1964
1964
|
"platform_health": "Acknowledge",
|
|
1965
|
+
"infra_unreachable": "Acknowledge",
|
|
1965
1966
|
"decision_required": "Mark read",
|
|
1966
1967
|
"human_test_ready": "Mark read",
|
|
1967
1968
|
"visual_confirmation_ready": "Mark read",
|
|
@@ -2010,11 +2011,13 @@
|
|
|
2010
2011
|
"infraSetupBanner": {
|
|
2011
2012
|
"agentExecutor": {
|
|
2012
2013
|
"title": "Agent executor not configured",
|
|
2014
|
+
"unreachableTitle": "Agent executor is unreachable",
|
|
2013
2015
|
"body": "This deployment runs agents on a self-hosted runner pool, but none is registered, so no agent can run until you connect one.",
|
|
2014
2016
|
"action": "Configure runner pool"
|
|
2015
2017
|
},
|
|
2016
2018
|
"ephemeralEnvironments": {
|
|
2017
2019
|
"title": "Test environment not configured",
|
|
2020
|
+
"unreachableTitle": "Test environment provider is unreachable",
|
|
2018
2021
|
"body": "No ephemeral environment provider is registered, so testing agents that need a live preview environment can't run. Open Test environments below and connect a Kubernetes cluster or a custom HTTP environment provider to enable them.",
|
|
2019
2022
|
"action": "Configure environment"
|
|
2020
2023
|
},
|
|
@@ -2026,6 +2029,11 @@
|
|
|
2026
2029
|
"dismiss": {
|
|
2027
2030
|
"session": "Dismiss for this session",
|
|
2028
2031
|
"permanent": "I'm OK with the limitations, don't notify me again"
|
|
2032
|
+
},
|
|
2033
|
+
"unreachable": {
|
|
2034
|
+
"body": "The connection is set up, but a live check could not reach it just now. That makes this an outage rather than a missing setup: agents that depend on it will fail until it answers again. Check that the service is running, then retest the connection.",
|
|
2035
|
+
"reason": "Last probe: {detail}",
|
|
2036
|
+
"action": "Check connection"
|
|
2029
2037
|
}
|
|
2030
2038
|
},
|
|
2031
2039
|
"spendWarningBanner": {
|
|
@@ -3695,6 +3703,7 @@
|
|
|
3695
3703
|
},
|
|
3696
3704
|
"routable": {
|
|
3697
3705
|
"platform_health": "Platform health",
|
|
3706
|
+
"infra_unreachable": "Infrastructure outages",
|
|
3698
3707
|
"merge_review": "Merge review",
|
|
3699
3708
|
"pipeline_complete": "Pipeline complete",
|
|
3700
3709
|
"ci_failed": "CI failed",
|
package/i18n/locales/es.json
CHANGED
|
@@ -1886,6 +1886,7 @@
|
|
|
1886
1886
|
"clarity_review": "Marcar como leída",
|
|
1887
1887
|
"release_regression": "Confirmar recepción",
|
|
1888
1888
|
"platform_health": "Confirmar recepción",
|
|
1889
|
+
"infra_unreachable": "Confirmar",
|
|
1889
1890
|
"decision_required": "Marcar como leída",
|
|
1890
1891
|
"human_test_ready": "Marcar como leída",
|
|
1891
1892
|
"visual_confirmation_ready": "Marcar como leída",
|
|
@@ -1940,11 +1941,13 @@
|
|
|
1940
1941
|
"infraSetupBanner": {
|
|
1941
1942
|
"agentExecutor": {
|
|
1942
1943
|
"title": "Ejecutor de agentes no configurado",
|
|
1944
|
+
"unreachableTitle": "El ejecutor de agentes no está accesible",
|
|
1943
1945
|
"body": "Este despliegue ejecuta los agentes en un pool de runners autoalojado, pero no hay ninguno registrado, así que ningún agente podrá ejecutarse hasta que conectes uno.",
|
|
1944
1946
|
"action": "Configurar pool de runners"
|
|
1945
1947
|
},
|
|
1946
1948
|
"ephemeralEnvironments": {
|
|
1947
1949
|
"title": "Entorno de pruebas no configurado",
|
|
1950
|
+
"unreachableTitle": "El proveedor de entornos de prueba no está accesible",
|
|
1948
1951
|
"body": "No hay ningún proveedor de entornos efímeros registrado, así que los agentes de pruebas que necesitan un entorno de vista previa activo no pueden ejecutarse. Abre Entornos de prueba abajo y conecta un clúster de Kubernetes o un proveedor de entornos HTTP personalizado para habilitarlos.",
|
|
1949
1952
|
"action": "Configurar entorno"
|
|
1950
1953
|
},
|
|
@@ -1956,6 +1959,11 @@
|
|
|
1956
1959
|
"dismiss": {
|
|
1957
1960
|
"session": "Descartar durante esta sesión",
|
|
1958
1961
|
"permanent": "Acepto las limitaciones, no volver a avisarme"
|
|
1962
|
+
},
|
|
1963
|
+
"unreachable": {
|
|
1964
|
+
"body": "La conexión está configurada, pero una comprobación en vivo no ha podido alcanzarla ahora mismo. Por eso se trata de una interrupción y no de una configuración pendiente: los agentes que dependen de ella fallarán hasta que vuelva a responder. Comprueba que el servicio esté en marcha y vuelve a probar la conexión.",
|
|
1965
|
+
"reason": "Última comprobación: {detail}",
|
|
1966
|
+
"action": "Comprobar conexión"
|
|
1959
1967
|
}
|
|
1960
1968
|
},
|
|
1961
1969
|
"spendWarningBanner": {
|
|
@@ -3586,6 +3594,7 @@
|
|
|
3586
3594
|
},
|
|
3587
3595
|
"routable": {
|
|
3588
3596
|
"platform_health": "Estado de la plataforma",
|
|
3597
|
+
"infra_unreachable": "Interrupciones de infraestructura",
|
|
3589
3598
|
"merge_review": "Revision de fusion",
|
|
3590
3599
|
"pipeline_complete": "Pipeline completado",
|
|
3591
3600
|
"ci_failed": "CI fallido",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -1886,6 +1886,7 @@
|
|
|
1886
1886
|
"clarity_review": "Marquer comme lu",
|
|
1887
1887
|
"release_regression": "Accuser réception",
|
|
1888
1888
|
"platform_health": "Accuser réception",
|
|
1889
|
+
"infra_unreachable": "Accuser réception",
|
|
1889
1890
|
"decision_required": "Marquer comme lu",
|
|
1890
1891
|
"human_test_ready": "Marquer comme lu",
|
|
1891
1892
|
"visual_confirmation_ready": "Marquer comme lu",
|
|
@@ -1940,11 +1941,13 @@
|
|
|
1940
1941
|
"infraSetupBanner": {
|
|
1941
1942
|
"agentExecutor": {
|
|
1942
1943
|
"title": "Exécuteur d'agents non configuré",
|
|
1944
|
+
"unreachableTitle": "L'exécuteur d'agents est inaccessible",
|
|
1943
1945
|
"body": "Ce déploiement exécute les agents sur un pool de runners auto-hébergé, mais aucun n'est enregistré, donc aucun agent ne pourra s'exécuter tant que vous n'en connectez pas un.",
|
|
1944
1946
|
"action": "Configurer le pool de runners"
|
|
1945
1947
|
},
|
|
1946
1948
|
"ephemeralEnvironments": {
|
|
1947
1949
|
"title": "Environnement de test non configuré",
|
|
1950
|
+
"unreachableTitle": "Le fournisseur d'environnements de test est inaccessible",
|
|
1948
1951
|
"body": "Aucun fournisseur d'environnements éphémères n'est enregistré, donc les agents de test qui nécessitent un environnement de prévisualisation actif ne peuvent pas s'exécuter. Ouvrez Environnements de test ci-dessous et connectez un cluster Kubernetes ou un fournisseur d'environnements HTTP personnalisé pour les activer.",
|
|
1949
1952
|
"action": "Configurer l'environnement"
|
|
1950
1953
|
},
|
|
@@ -1956,6 +1959,11 @@
|
|
|
1956
1959
|
"dismiss": {
|
|
1957
1960
|
"session": "Ignorer pour cette session",
|
|
1958
1961
|
"permanent": "J'accepte les limitations, ne plus me notifier"
|
|
1962
|
+
},
|
|
1963
|
+
"unreachable": {
|
|
1964
|
+
"body": "La connexion est configurée, mais une vérification en direct n'a pas pu l'atteindre à l'instant. Il s'agit donc d'une panne et non d'une configuration manquante : les agents qui en dépendent échoueront jusqu'à ce qu'une réponse revienne. Vérifiez que le service fonctionne, puis testez la connexion à nouveau.",
|
|
1965
|
+
"reason": "Dernière vérification : {detail}",
|
|
1966
|
+
"action": "Vérifier la connexion"
|
|
1959
1967
|
}
|
|
1960
1968
|
},
|
|
1961
1969
|
"spendWarningBanner": {
|
|
@@ -3586,6 +3594,7 @@
|
|
|
3586
3594
|
},
|
|
3587
3595
|
"routable": {
|
|
3588
3596
|
"platform_health": "Santé de la plateforme",
|
|
3597
|
+
"infra_unreachable": "Pannes d'infrastructure",
|
|
3589
3598
|
"merge_review": "Revue de fusion",
|
|
3590
3599
|
"pipeline_complete": "Pipeline termine",
|
|
3591
3600
|
"ci_failed": "Echec de CI",
|
package/i18n/locales/he.json
CHANGED
|
@@ -1886,6 +1886,7 @@
|
|
|
1886
1886
|
"clarity_review": "סמן כנקרא",
|
|
1887
1887
|
"release_regression": "אשר",
|
|
1888
1888
|
"platform_health": "אשר",
|
|
1889
|
+
"infra_unreachable": "אישור",
|
|
1889
1890
|
"decision_required": "סמן כנקרא",
|
|
1890
1891
|
"human_test_ready": "סמן כנקרא",
|
|
1891
1892
|
"visual_confirmation_ready": "סמן כנקרא",
|
|
@@ -1940,11 +1941,13 @@
|
|
|
1940
1941
|
"infraSetupBanner": {
|
|
1941
1942
|
"agentExecutor": {
|
|
1942
1943
|
"title": "מנוע הסוכנים אינו מוגדר",
|
|
1944
|
+
"unreachableTitle": "מריץ הסוכנים אינו נגיש",
|
|
1943
1945
|
"body": "פריסה זו מריצה סוכנים במאגר ראנרים בניהול עצמי, אך אף מאגר אינו רשום, ולכן אף סוכן לא יוכל לפעול עד שתחברו אחד.",
|
|
1944
1946
|
"action": "הגדרת מאגר ראנרים"
|
|
1945
1947
|
},
|
|
1946
1948
|
"ephemeralEnvironments": {
|
|
1947
1949
|
"title": "סביבת בדיקות אינה מוגדרת",
|
|
1950
|
+
"unreachableTitle": "ספק סביבות הבדיקה אינו נגיש",
|
|
1948
1951
|
"body": "לא רשום שום ספק סביבות ארעיות, ולכן סוכני בדיקה הזקוקים לסביבת תצוגה מקדימה פעילה אינם יכולים לפעול. פתחו את 'סביבות בדיקה' למטה וחברו אשכול Kubernetes או ספק סביבות HTTP מותאם אישית כדי להפעיל אותם.",
|
|
1949
1952
|
"action": "הגדרת סביבה"
|
|
1950
1953
|
},
|
|
@@ -1956,6 +1959,11 @@
|
|
|
1956
1959
|
"dismiss": {
|
|
1957
1960
|
"session": "התעלם להפעלה זו",
|
|
1958
1961
|
"permanent": "אני מסכים למגבלות, אל תודיעו לי שוב"
|
|
1962
|
+
},
|
|
1963
|
+
"unreachable": {
|
|
1964
|
+
"body": "החיבור מוגדר, אך בדיקה חיה לא הצליחה להגיע אליו כרגע. לכן מדובר בתקלה ולא בהגדרה חסרה: סוכנים שתלויים בו ייכשלו עד שתחזור תשובה. בדקו שהשירות פועל, ולאחר מכן בדקו את החיבור מחדש.",
|
|
1965
|
+
"reason": "בדיקה אחרונה: {detail}",
|
|
1966
|
+
"action": "בדיקת החיבור"
|
|
1959
1967
|
}
|
|
1960
1968
|
},
|
|
1961
1969
|
"spendWarningBanner": {
|
|
@@ -3597,6 +3605,7 @@
|
|
|
3597
3605
|
},
|
|
3598
3606
|
"routable": {
|
|
3599
3607
|
"platform_health": "תקינות הפלטפורמה",
|
|
3608
|
+
"infra_unreachable": "תקלות תשתית",
|
|
3600
3609
|
"merge_review": "סקירת מיזוג",
|
|
3601
3610
|
"pipeline_complete": "הצינור הושלם",
|
|
3602
3611
|
"ci_failed": "CI נכשל",
|
package/i18n/locales/it.json
CHANGED
|
@@ -1979,6 +1979,7 @@
|
|
|
1979
1979
|
"clarity_review": "Segna come letto",
|
|
1980
1980
|
"release_regression": "Conferma presa visione",
|
|
1981
1981
|
"platform_health": "Conferma presa visione",
|
|
1982
|
+
"infra_unreachable": "Conferma",
|
|
1982
1983
|
"decision_required": "Segna come letto",
|
|
1983
1984
|
"human_test_ready": "Segna come letto",
|
|
1984
1985
|
"visual_confirmation_ready": "Segna come letto",
|
|
@@ -2027,11 +2028,13 @@
|
|
|
2027
2028
|
"infraSetupBanner": {
|
|
2028
2029
|
"agentExecutor": {
|
|
2029
2030
|
"title": "Esecutore degli agenti non configurato",
|
|
2031
|
+
"unreachableTitle": "L'esecutore degli agenti non è raggiungibile",
|
|
2030
2032
|
"body": "Questo deployment esegue gli agenti su un runner pool self-hosted, ma nessuno è registrato, quindi nessun agente può funzionare finché non ne connetti uno.",
|
|
2031
2033
|
"action": "Configura il runner pool"
|
|
2032
2034
|
},
|
|
2033
2035
|
"ephemeralEnvironments": {
|
|
2034
2036
|
"title": "Ambiente di test non configurato",
|
|
2037
|
+
"unreachableTitle": "Il provider di ambienti di test non è raggiungibile",
|
|
2035
2038
|
"body": "Nessun provider di ambiente effimero è registrato, quindi gli agenti di test che necessitano di un ambiente di anteprima live non possono funzionare. Apri Ambienti di test qui sotto e connetti un cluster Kubernetes o un provider di ambienti HTTP personalizzato per abilitarli.",
|
|
2036
2039
|
"action": "Configura l'ambiente"
|
|
2037
2040
|
},
|
|
@@ -2043,6 +2046,11 @@
|
|
|
2043
2046
|
"dismiss": {
|
|
2044
2047
|
"session": "Ignora per questa sessione",
|
|
2045
2048
|
"permanent": "Accetto le limitazioni, non notificarmi più"
|
|
2049
|
+
},
|
|
2050
|
+
"unreachable": {
|
|
2051
|
+
"body": "La connessione è configurata, ma una verifica in tempo reale non è riuscita a raggiungerla in questo momento. Si tratta quindi di un'interruzione e non di una configurazione mancante: gli agenti che ne dipendono falliranno finché non arriverà di nuovo una risposta. Controlla che il servizio sia attivo, poi riprova la connessione.",
|
|
2052
|
+
"reason": "Ultima verifica: {detail}",
|
|
2053
|
+
"action": "Verifica connessione"
|
|
2046
2054
|
}
|
|
2047
2055
|
},
|
|
2048
2056
|
"spendWarningBanner": {
|
|
@@ -4737,6 +4745,7 @@
|
|
|
4737
4745
|
},
|
|
4738
4746
|
"routable": {
|
|
4739
4747
|
"platform_health": "Salute della piattaforma",
|
|
4748
|
+
"infra_unreachable": "Interruzioni dell’infrastruttura",
|
|
4740
4749
|
"merge_review": "Revisione del merge",
|
|
4741
4750
|
"pipeline_complete": "Pipeline completata",
|
|
4742
4751
|
"ci_failed": "CI non riuscita",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -1886,6 +1886,7 @@
|
|
|
1886
1886
|
"clarity_review": "既読にする",
|
|
1887
1887
|
"release_regression": "確認",
|
|
1888
1888
|
"platform_health": "確認",
|
|
1889
|
+
"infra_unreachable": "確認",
|
|
1889
1890
|
"decision_required": "既読にする",
|
|
1890
1891
|
"human_test_ready": "既読にする",
|
|
1891
1892
|
"visual_confirmation_ready": "既読にする",
|
|
@@ -1940,11 +1941,13 @@
|
|
|
1940
1941
|
"infraSetupBanner": {
|
|
1941
1942
|
"agentExecutor": {
|
|
1942
1943
|
"title": "エージェント実行環境が未設定です",
|
|
1944
|
+
"unreachableTitle": "エージェント実行環境に到達できません",
|
|
1943
1945
|
"body": "このデプロイはセルフホストのランナープールでエージェントを実行しますが、登録されているものがないため、接続するまでエージェントを実行できません。",
|
|
1944
1946
|
"action": "ランナープールを設定"
|
|
1945
1947
|
},
|
|
1946
1948
|
"ephemeralEnvironments": {
|
|
1947
1949
|
"title": "テスト環境が未設定です",
|
|
1950
|
+
"unreachableTitle": "テスト環境プロバイダーに到達できません",
|
|
1948
1951
|
"body": "エフェメラル環境プロバイダーが登録されていないため、稼働中のプレビュー環境を必要とするテストエージェントを実行できません。下の「テスト環境」を開き、Kubernetes クラスターまたはカスタム HTTP 環境プロバイダーを接続して有効にしてください。",
|
|
1949
1952
|
"action": "環境を設定"
|
|
1950
1953
|
},
|
|
@@ -1956,6 +1959,11 @@
|
|
|
1956
1959
|
"dismiss": {
|
|
1957
1960
|
"session": "このセッションでは非表示にする",
|
|
1958
1961
|
"permanent": "制限を理解しました。今後通知しない"
|
|
1962
|
+
},
|
|
1963
|
+
"unreachable": {
|
|
1964
|
+
"body": "接続は設定済みですが、ライブチェックでは到達できませんでした。つまり設定漏れではなく障害です。応答が戻るまで、これに依存するエージェントは失敗します。サービスが稼働しているか確認したうえで、接続を再テストしてください。",
|
|
1965
|
+
"reason": "最後のチェック: {detail}",
|
|
1966
|
+
"action": "接続を確認"
|
|
1959
1967
|
}
|
|
1960
1968
|
},
|
|
1961
1969
|
"spendWarningBanner": {
|
|
@@ -3598,6 +3606,7 @@
|
|
|
3598
3606
|
},
|
|
3599
3607
|
"routable": {
|
|
3600
3608
|
"platform_health": "プラットフォームの健全性",
|
|
3609
|
+
"infra_unreachable": "インフラ障害",
|
|
3601
3610
|
"merge_review": "マージレビュー",
|
|
3602
3611
|
"pipeline_complete": "パイプライン完了",
|
|
3603
3612
|
"ci_failed": "CI失敗",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -1886,6 +1886,7 @@
|
|
|
1886
1886
|
"clarity_review": "Oznacz jako przeczytane",
|
|
1887
1887
|
"release_regression": "Potwierdź",
|
|
1888
1888
|
"platform_health": "Potwierdź",
|
|
1889
|
+
"infra_unreachable": "Potwierdź",
|
|
1889
1890
|
"decision_required": "Oznacz jako przeczytane",
|
|
1890
1891
|
"human_test_ready": "Oznacz jako przeczytane",
|
|
1891
1892
|
"visual_confirmation_ready": "Oznacz jako przeczytane",
|
|
@@ -1940,11 +1941,13 @@
|
|
|
1940
1941
|
"infraSetupBanner": {
|
|
1941
1942
|
"agentExecutor": {
|
|
1942
1943
|
"title": "Wykonawca agentów nie jest skonfigurowany",
|
|
1944
|
+
"unreachableTitle": "Wykonawca agentów jest nieosiągalny",
|
|
1943
1945
|
"body": "To wdrożenie uruchamia agentów w samodzielnie hostowanej puli runnerów, ale żadna nie jest zarejestrowana, więc żaden agent nie będzie mógł działać, dopóki jej nie podłączysz.",
|
|
1944
1946
|
"action": "Skonfiguruj pulę runnerów"
|
|
1945
1947
|
},
|
|
1946
1948
|
"ephemeralEnvironments": {
|
|
1947
1949
|
"title": "Środowisko testowe nie jest skonfigurowane",
|
|
1950
|
+
"unreachableTitle": "Dostawca środowisk testowych jest nieosiągalny",
|
|
1948
1951
|
"body": "Nie zarejestrowano żadnego dostawcy środowisk efemerycznych, więc agenci testowi wymagający działającego środowiska podglądu nie mogą działać. Otwórz poniżej „Środowiska testowe” i podłącz klaster Kubernetes lub niestandardowego dostawcę środowisk HTTP, aby je włączyć.",
|
|
1949
1952
|
"action": "Skonfiguruj środowisko"
|
|
1950
1953
|
},
|
|
@@ -1956,6 +1959,11 @@
|
|
|
1956
1959
|
"dismiss": {
|
|
1957
1960
|
"session": "Odrzuć na tę sesję",
|
|
1958
1961
|
"permanent": "Akceptuję ograniczenia, nie powiadamiaj mnie ponownie"
|
|
1962
|
+
},
|
|
1963
|
+
"unreachable": {
|
|
1964
|
+
"body": "Połączenie jest skonfigurowane, ale kontrola na żywo nie mogła go teraz uzyskać. To awaria, a nie brak konfiguracji: agenci, którzy od tego zależą, będą kończyć się błędem, dopóki nie pojawi się znowu odpowiedź. Sprawdź, czy usługa działa, a następnie ponownie przetestuj połączenie.",
|
|
1965
|
+
"reason": "Ostatnia kontrola: {detail}",
|
|
1966
|
+
"action": "Sprawdź połączenie"
|
|
1959
1967
|
}
|
|
1960
1968
|
},
|
|
1961
1969
|
"spendWarningBanner": {
|
|
@@ -3586,6 +3594,7 @@
|
|
|
3586
3594
|
},
|
|
3587
3595
|
"routable": {
|
|
3588
3596
|
"platform_health": "Kondycja platformy",
|
|
3597
|
+
"infra_unreachable": "Awarie infrastruktury",
|
|
3589
3598
|
"merge_review": "Przeglad scalenia",
|
|
3590
3599
|
"pipeline_complete": "Pipeline ukonczony",
|
|
3591
3600
|
"ci_failed": "Niepowodzenie CI",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -1886,6 +1886,7 @@
|
|
|
1886
1886
|
"clarity_review": "Okundu olarak işaretle",
|
|
1887
1887
|
"release_regression": "Onayla",
|
|
1888
1888
|
"platform_health": "Onayla",
|
|
1889
|
+
"infra_unreachable": "Onayla",
|
|
1889
1890
|
"decision_required": "Okundu işaretle",
|
|
1890
1891
|
"human_test_ready": "Okundu işaretle",
|
|
1891
1892
|
"visual_confirmation_ready": "Okundu işaretle",
|
|
@@ -1940,11 +1941,13 @@
|
|
|
1940
1941
|
"infraSetupBanner": {
|
|
1941
1942
|
"agentExecutor": {
|
|
1942
1943
|
"title": "Aracı yürütücüsü yapılandırılmadı",
|
|
1944
|
+
"unreachableTitle": "Aracı yürütücüsüne erişilemiyor",
|
|
1943
1945
|
"body": "Bu dağıtım aracıları kendi barındırdığınız bir runner havuzunda çalıştırır, ancak kayıtlı bir havuz yok; bu yüzden bir tane bağlayana kadar hiçbir aracı çalışamaz.",
|
|
1944
1946
|
"action": "Runner havuzunu yapılandır"
|
|
1945
1947
|
},
|
|
1946
1948
|
"ephemeralEnvironments": {
|
|
1947
1949
|
"title": "Test ortamı yapılandırılmadı",
|
|
1950
|
+
"unreachableTitle": "Test ortamı sağlayıcısına erişilemiyor",
|
|
1948
1951
|
"body": "Kayıtlı bir geçici ortam sağlayıcısı yok; bu nedenle çalışan bir önizleme ortamına ihtiyaç duyan test aracıları çalışamaz. Aşağıdaki Test ortamları sekmesini açın ve etkinleştirmek için bir Kubernetes kümesi ya da özel bir HTTP ortam sağlayıcısı bağlayın.",
|
|
1949
1952
|
"action": "Ortamı yapılandır"
|
|
1950
1953
|
},
|
|
@@ -1956,6 +1959,11 @@
|
|
|
1956
1959
|
"dismiss": {
|
|
1957
1960
|
"session": "Bu oturum için kapat",
|
|
1958
1961
|
"permanent": "Kısıtlamaları kabul ediyorum, beni tekrar bilgilendirme"
|
|
1962
|
+
},
|
|
1963
|
+
"unreachable": {
|
|
1964
|
+
"body": "Bağlantı yapılandırılmış durumda, ancak canlı bir denetim şu anda ona ulaşamadı. Bu yüzden eksik bir yapılandırma değil bir kesinti söz konusu: buna bağlı aracılar yeniden yanıt gelene kadar başarısız olacak. Hizmetin çalıştığını doğrulayın, ardından bağlantıyı yeniden test edin.",
|
|
1965
|
+
"reason": "Son denetim: {detail}",
|
|
1966
|
+
"action": "Bağlantıyı denetle"
|
|
1959
1967
|
}
|
|
1960
1968
|
},
|
|
1961
1969
|
"spendWarningBanner": {
|
|
@@ -3598,6 +3606,7 @@
|
|
|
3598
3606
|
},
|
|
3599
3607
|
"routable": {
|
|
3600
3608
|
"platform_health": "Platform sağlığı",
|
|
3609
|
+
"infra_unreachable": "Altyapı kesintileri",
|
|
3601
3610
|
"merge_review": "Birleştirme incelemesi",
|
|
3602
3611
|
"pipeline_complete": "Pipeline tamamlandı",
|
|
3603
3612
|
"ci_failed": "CI başarısız",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -1886,6 +1886,7 @@
|
|
|
1886
1886
|
"clarity_review": "Позначити прочитаним",
|
|
1887
1887
|
"release_regression": "Підтвердити отримання",
|
|
1888
1888
|
"platform_health": "Підтвердити отримання",
|
|
1889
|
+
"infra_unreachable": "Підтвердити",
|
|
1889
1890
|
"decision_required": "Позначити прочитаним",
|
|
1890
1891
|
"human_test_ready": "Позначити прочитаним",
|
|
1891
1892
|
"visual_confirmation_ready": "Позначити прочитаним",
|
|
@@ -1940,11 +1941,13 @@
|
|
|
1940
1941
|
"infraSetupBanner": {
|
|
1941
1942
|
"agentExecutor": {
|
|
1942
1943
|
"title": "Виконавець агентів не налаштований",
|
|
1944
|
+
"unreachableTitle": "Виконавець агентів недоступний",
|
|
1943
1945
|
"body": "Це розгортання запускає агентів у самостійно розміщеному пулі раннерів, але жоден не зареєстрований, тож жоден агент не зможе працювати, доки ви не підключите його.",
|
|
1944
1946
|
"action": "Налаштувати пул раннерів"
|
|
1945
1947
|
},
|
|
1946
1948
|
"ephemeralEnvironments": {
|
|
1947
1949
|
"title": "Тестове середовище не налаштоване",
|
|
1950
|
+
"unreachableTitle": "Постачальник тестових середовищ недоступний",
|
|
1948
1951
|
"body": "Не зареєстровано жодного постачальника ефемерних середовищ, тож тестові агенти, яким потрібне робоче середовище попереднього перегляду, не можуть працювати. Відкрийте нижче «Тестові середовища» та підключіть кластер Kubernetes або власного постачальника середовищ HTTP, щоб увімкнути їх.",
|
|
1949
1952
|
"action": "Налаштувати середовище"
|
|
1950
1953
|
},
|
|
@@ -1956,6 +1959,11 @@
|
|
|
1956
1959
|
"dismiss": {
|
|
1957
1960
|
"session": "Відхилити на цю сесію",
|
|
1958
1961
|
"permanent": "Мене влаштовують обмеження, більше не сповіщати"
|
|
1962
|
+
},
|
|
1963
|
+
"unreachable": {
|
|
1964
|
+
"body": "З’єднання налаштоване, але жива перевірка щойно не змогла до нього дістатися. Тому це збій, а не відсутнє налаштування: агенти, які від нього залежать, завершуватимуться з помилкою, доки не з’явиться відповідь. Перевірте, чи працює служба, а потім протестуйте з’єднання ще раз.",
|
|
1965
|
+
"reason": "Остання перевірка: {detail}",
|
|
1966
|
+
"action": "Перевірити з’єднання"
|
|
1959
1967
|
}
|
|
1960
1968
|
},
|
|
1961
1969
|
"spendWarningBanner": {
|
|
@@ -3586,6 +3594,7 @@
|
|
|
3586
3594
|
},
|
|
3587
3595
|
"routable": {
|
|
3588
3596
|
"platform_health": "Стан платформи",
|
|
3597
|
+
"infra_unreachable": "Збої інфраструктури",
|
|
3589
3598
|
"merge_review": "Перевірка злиття",
|
|
3590
3599
|
"pipeline_complete": "Конвеєр завершено",
|
|
3591
3600
|
"ci_failed": "Збій CI",
|