@cat-factory/app 0.258.2 → 0.259.1
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/outcome/OutcomeSummaryWindow.logic.spec.ts +74 -0
- package/app/components/outcome/OutcomeSummaryWindow.logic.ts +63 -0
- package/app/components/outcome/OutcomeSummaryWindow.vue +137 -1
- package/app/utils/runOutcome.ts +5 -0
- package/i18n/locales/de.json +25 -0
- package/i18n/locales/en.json +25 -0
- package/i18n/locales/es.json +25 -0
- package/i18n/locales/fr.json +25 -0
- package/i18n/locales/he.json +25 -0
- package/i18n/locales/it.json +25 -0
- package/i18n/locales/ja.json +25 -0
- package/i18n/locales/pl.json +25 -0
- package/i18n/locales/tr.json +25 -0
- package/i18n/locales/uk.json +25 -0
- package/package.json +2 -2
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { readEnvironmentAgainstClock } from './OutcomeSummaryWindow.logic'
|
|
3
|
+
import type { OutcomeEnvironment } from '~/utils/runOutcome'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The one thing the outcome card decides for itself: whether the TTL the payload carries has
|
|
7
|
+
* lapsed, and what that changes. The reduction behind the card is clock-free on purpose, so this
|
|
8
|
+
* is the only place a reader is told an environment is past its expiry, and the failure it
|
|
9
|
+
* guards is the section's worst one: a green "Live" badge and a working-looking button on a row
|
|
10
|
+
* whose own expiry date is in the past.
|
|
11
|
+
*/
|
|
12
|
+
const NOW = 1_700_000_000_000
|
|
13
|
+
|
|
14
|
+
const env = (overrides: Partial<OutcomeEnvironment> = {}): OutcomeEnvironment => ({
|
|
15
|
+
url: 'https://preview.test',
|
|
16
|
+
state: 'live',
|
|
17
|
+
origin: 'deployer',
|
|
18
|
+
expiresAt: null,
|
|
19
|
+
retained: false,
|
|
20
|
+
frameId: 'frm_own',
|
|
21
|
+
environmentId: 'env_1',
|
|
22
|
+
detail: null,
|
|
23
|
+
...overrides,
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('readEnvironmentAgainstClock', () => {
|
|
27
|
+
it('offers a live environment whose TTL has not lapsed', () => {
|
|
28
|
+
const row = readEnvironmentAgainstClock(env({ expiresAt: NOW + 60_000 }), NOW)
|
|
29
|
+
expect(row).toMatchObject({ state: 'live', lapsed: false, openable: true })
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('withholds the link once the TTL has lapsed, and says the environment expired', () => {
|
|
33
|
+
const row = readEnvironmentAgainstClock(env({ expiresAt: NOW - 1 }), NOW)
|
|
34
|
+
expect(row).toMatchObject({ state: 'expired', lapsed: true, openable: false })
|
|
35
|
+
// The URL survives the lapse: it is what names the environment and what an operator greps.
|
|
36
|
+
expect(row.url).toBe('https://preview.test')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// A run with no disposer and no further polls keeps a `provisioning` row forever, and one
|
|
40
|
+
// whose TTL then lapsed never came up and never will.
|
|
41
|
+
it('applies the lapse to an environment still coming up', () => {
|
|
42
|
+
const row = readEnvironmentAgainstClock(env({ state: 'provisioning', expiresAt: NOW - 1 }), NOW)
|
|
43
|
+
expect(row).toMatchObject({ state: 'expired', lapsed: true, openable: false })
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// The clock may only answer the question the payload left open. Where a producer already said
|
|
47
|
+
// WHERE the environment went, that word is the more specific one and it stands.
|
|
48
|
+
it('never overwrites a state that already names where the environment went', () => {
|
|
49
|
+
for (const state of ['failed', 'reclaimed', 'reclaiming'] as const) {
|
|
50
|
+
const row = readEnvironmentAgainstClock(env({ state, expiresAt: NOW - 1 }), NOW)
|
|
51
|
+
expect(row).toMatchObject({ state, lapsed: false, openable: false })
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// `useNowTick` reads 0 until the card mounts, and every instant in history is "past" the epoch.
|
|
56
|
+
it('makes no clock-derived claim before the card has a clock', () => {
|
|
57
|
+
const row = readEnvironmentAgainstClock(env({ expiresAt: NOW - 1 }), 0)
|
|
58
|
+
expect(row).toMatchObject({ state: 'live', lapsed: false, openable: true })
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('offers nothing to click for a live environment that has no URL yet', () => {
|
|
62
|
+
const row = readEnvironmentAgainstClock(env({ url: null }), NOW)
|
|
63
|
+
expect(row).toMatchObject({ state: 'live', openable: false })
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
// A run that recorded no TTL is not an expired one: absent and lapsed are opposite facts.
|
|
67
|
+
it('leaves a row carrying no TTL exactly as the payload states it', () => {
|
|
68
|
+
expect(readEnvironmentAgainstClock(env(), NOW)).toMatchObject({
|
|
69
|
+
state: 'live',
|
|
70
|
+
lapsed: false,
|
|
71
|
+
openable: true,
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// What the outcome card's environment rows say once a CLOCK is applied to them, extracted from
|
|
2
|
+
// `OutcomeSummaryWindow.vue` so the rule can be asserted without mounting the card (see
|
|
3
|
+
// `OutcomeSummaryWindow.logic.spec.ts`).
|
|
4
|
+
//
|
|
5
|
+
// The reduction that produces those rows (`composeRunOutcome`) is deliberately clock-free: the
|
|
6
|
+
// SPA composes it live off its own store and `GET /api/v1/runs/:runId/outcome` composes it
|
|
7
|
+
// server-side, and a rule that read a clock would let the two disagree about one run for as long
|
|
8
|
+
// as their clocks differ. What the payload carries instead is the TTL INSTANT.
|
|
9
|
+
//
|
|
10
|
+
// Somebody still has to say what that instant means now, and it has to be the surface with the
|
|
11
|
+
// clock. Left unapplied, a run whose environment the TTL sweep reclaimed hours ago renders a
|
|
12
|
+
// green "Live" badge and an enabled Open button beside an expiry date in the past: three claims
|
|
13
|
+
// on one row, of which the date is the only true one.
|
|
14
|
+
|
|
15
|
+
import type { OutcomeEnvironment, OutcomeEnvironmentState } from '~/utils/runOutcome'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The states that describe an environment still STANDING, and so the only ones a lapsed TTL
|
|
19
|
+
* changes what they say.
|
|
20
|
+
*
|
|
21
|
+
* `failed`, `reclaimed` and `reclaiming` already name where the environment went or what is
|
|
22
|
+
* happening to it. A clock may not overwrite those with a less specific word: an environment
|
|
23
|
+
* that never came up did not then expire, and saying so would send a reader looking for a TTL
|
|
24
|
+
* where a provisioning failure is the thing to fix.
|
|
25
|
+
*/
|
|
26
|
+
const STANDING_ENVIRONMENT_STATES = new Set<OutcomeEnvironmentState>(['live', 'provisioning'])
|
|
27
|
+
|
|
28
|
+
/** One environment row as the card renders it: the payload's own fields, read against a clock. */
|
|
29
|
+
export interface OutcomeEnvironmentRow extends OutcomeEnvironment {
|
|
30
|
+
/** True when the row's TTL has lapsed against `nowMs` while it still claimed to be standing. */
|
|
31
|
+
lapsed: boolean
|
|
32
|
+
/** Whether the card offers the row as something to click. */
|
|
33
|
+
openable: boolean
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Apply the reader's clock to one environment row.
|
|
38
|
+
*
|
|
39
|
+
* `nowMs` of 0 means the card has not ticked yet (`useNowTick` reads 0 until mounted). No clock
|
|
40
|
+
* means no clock-derived claim: the row reads exactly as the payload states it rather than
|
|
41
|
+
* having every TTL lapse against the epoch.
|
|
42
|
+
*/
|
|
43
|
+
export function readEnvironmentAgainstClock(
|
|
44
|
+
entry: OutcomeEnvironment,
|
|
45
|
+
nowMs: number,
|
|
46
|
+
): OutcomeEnvironmentRow {
|
|
47
|
+
const lapsed =
|
|
48
|
+
nowMs > 0 &&
|
|
49
|
+
entry.expiresAt != null &&
|
|
50
|
+
entry.expiresAt <= nowMs &&
|
|
51
|
+
STANDING_ENVIRONMENT_STATES.has(entry.state)
|
|
52
|
+
const state = lapsed ? 'expired' : entry.state
|
|
53
|
+
return {
|
|
54
|
+
...entry,
|
|
55
|
+
state,
|
|
56
|
+
lapsed,
|
|
57
|
+
// A link is offered ONLY for a `live` row: an environment that has been reclaimed, has
|
|
58
|
+
// expired or never came up still shows its URL (an operator greps for it, and it says which
|
|
59
|
+
// environment the row is about) and must not be something a designer clicks expecting to see
|
|
60
|
+
// the change.
|
|
61
|
+
openable: state === 'live' && Boolean(entry.url),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -16,9 +16,12 @@
|
|
|
16
16
|
// judged against, which turns the tester's requirement IDS into the TITLES a reader came for.
|
|
17
17
|
import { computed, onUnmounted, ref, watch } from 'vue'
|
|
18
18
|
import type {
|
|
19
|
+
EnvironmentsGap,
|
|
19
20
|
OutcomeCheckKind,
|
|
20
21
|
OutcomeCheckState,
|
|
21
22
|
OutcomeDisposition,
|
|
23
|
+
OutcomeEnvironmentOrigin,
|
|
24
|
+
OutcomeEnvironmentState,
|
|
22
25
|
OutcomeSource,
|
|
23
26
|
OutcomeSpecJoin,
|
|
24
27
|
OutcomeVisual,
|
|
@@ -35,6 +38,8 @@ import { REPRODUCTION_STATUS_KEYS } from '~/utils/reproduction'
|
|
|
35
38
|
import type { RequirementVerdictStatus, TestConcernSeverity } from '~/types/domain'
|
|
36
39
|
import type { TestEnvironment } from '@cat-factory/contracts'
|
|
37
40
|
import { useArtifactBlobs } from '~/composables/useArtifactBlobs'
|
|
41
|
+
import { useNowTick } from '~/composables/useStepTimer'
|
|
42
|
+
import { readEnvironmentAgainstClock } from '~/components/outcome/OutcomeSummaryWindow.logic'
|
|
38
43
|
import ArtifactLightbox from '~/components/media/ArtifactLightbox.vue'
|
|
39
44
|
import ResultWindowShell from '~/components/panels/ResultWindowShell.vue'
|
|
40
45
|
import MarkdownProse from '~/components/common/MarkdownProse.vue'
|
|
@@ -46,7 +51,12 @@ const documents = useDocumentsStore()
|
|
|
46
51
|
const execution = useExecutionStore()
|
|
47
52
|
const serviceSpec = useServiceSpecStore()
|
|
48
53
|
const ui = useUiStore()
|
|
49
|
-
const { t } = useI18n()
|
|
54
|
+
const { t, d } = useI18n()
|
|
55
|
+
|
|
56
|
+
// The wall clock this card reads a TTL against. Coarse on purpose: an environment's expiry is
|
|
57
|
+
// the only thing here that moves with time, and a per-second tick would re-render the whole card
|
|
58
|
+
// for a boundary that matters at minute granularity.
|
|
59
|
+
const nowTick = useNowTick(30_000)
|
|
50
60
|
|
|
51
61
|
// Per-window blob cache for the captured views; revoked on unmount so the (large) image bytes
|
|
52
62
|
// don't outlive the card.
|
|
@@ -136,6 +146,38 @@ const SOURCES_GAP_KEYS: Record<SourcesGap, string> = {
|
|
|
136
146
|
run_unavailable: RUN_UNAVAILABLE_KEY,
|
|
137
147
|
none_linked: 'outcome.sources.gap.none_linked',
|
|
138
148
|
}
|
|
149
|
+
const ENVIRONMENTS_GAP_KEYS: Record<EnvironmentsGap, string> = {
|
|
150
|
+
run_unavailable: RUN_UNAVAILABLE_KEY,
|
|
151
|
+
no_environment_step: 'outcome.environments.gap.no_environment_step',
|
|
152
|
+
not_provisioned: 'outcome.environments.gap.not_provisioned',
|
|
153
|
+
infraless: 'outcome.environments.gap.infraless',
|
|
154
|
+
}
|
|
155
|
+
const ENVIRONMENT_STATE_KEYS: Record<OutcomeEnvironmentState, string> = {
|
|
156
|
+
live: 'outcome.environments.state.live',
|
|
157
|
+
provisioning: 'outcome.environments.state.provisioning',
|
|
158
|
+
failed: 'outcome.environments.state.failed',
|
|
159
|
+
reclaiming: 'outcome.environments.state.reclaiming',
|
|
160
|
+
reclaimed: 'outcome.environments.state.reclaimed',
|
|
161
|
+
expired: 'outcome.environments.state.expired',
|
|
162
|
+
}
|
|
163
|
+
const ENVIRONMENT_STATE_COLOR: Record<OutcomeEnvironmentState, BadgeColor> = {
|
|
164
|
+
live: 'success',
|
|
165
|
+
provisioning: 'info',
|
|
166
|
+
failed: 'error',
|
|
167
|
+
reclaiming: 'neutral',
|
|
168
|
+
reclaimed: 'neutral',
|
|
169
|
+
expired: 'neutral',
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Where the row came from, said out loud. `projected` is the one that changes what a reader
|
|
173
|
+
* should conclude (nothing has settled yet, so this row can still move), and the three are
|
|
174
|
+
* mapped exhaustively so a new producer cannot ship as a blank line.
|
|
175
|
+
*/
|
|
176
|
+
const ENVIRONMENT_ORIGIN_KEYS: Record<OutcomeEnvironmentOrigin, string> = {
|
|
177
|
+
deployer: 'outcome.environments.origin.deployer',
|
|
178
|
+
human_test: 'outcome.environments.origin.human_test',
|
|
179
|
+
projected: 'outcome.environments.origin.projected',
|
|
180
|
+
}
|
|
139
181
|
const VISUALS_GAP_KEYS: Record<VisualsGap, string> = {
|
|
140
182
|
run_unavailable: RUN_UNAVAILABLE_KEY,
|
|
141
183
|
no_visual_step: 'outcome.visuals.gap.no_visual_step',
|
|
@@ -337,6 +379,28 @@ const sourceRows = computed(() => {
|
|
|
337
379
|
}))
|
|
338
380
|
})
|
|
339
381
|
|
|
382
|
+
/**
|
|
383
|
+
* The environments the run stood up, with everything the row needs resolved once.
|
|
384
|
+
*
|
|
385
|
+
* The TTL is applied HERE rather than in the reduction, and that division is deliberate: the
|
|
386
|
+
* payload is clock-free so the endpoint's answer and this card's live composition cannot
|
|
387
|
+
* disagree about one run, and this surface is the one with a clock to say what the instant it
|
|
388
|
+
* carries means now. The rule itself lives in `OutcomeSummaryWindow.logic.ts`, where it is
|
|
389
|
+
* asserted without mounting the card.
|
|
390
|
+
*
|
|
391
|
+
* The frame is named by its BLOCK title where the board has it. A frame id says nothing to the
|
|
392
|
+
* person this card is for, so an unresolvable one renders as no label rather than as an id.
|
|
393
|
+
*/
|
|
394
|
+
const environmentRows = computed(() => {
|
|
395
|
+
const environments = outcome.value?.environments
|
|
396
|
+
if (!environments || environments.status !== 'reported') return []
|
|
397
|
+
return environments.entries.map((entry, index) => ({
|
|
398
|
+
...readEnvironmentAgainstClock(entry, nowTick.value),
|
|
399
|
+
key: `${index}:${entry.environmentId ?? entry.url ?? entry.frameId ?? 'env'}`,
|
|
400
|
+
service: entry.frameId ? (board.getBlock(entry.frameId)?.title ?? null) : null,
|
|
401
|
+
}))
|
|
402
|
+
})
|
|
403
|
+
|
|
340
404
|
/** Drill into the full test report (this card is the summary, never a replacement for it). */
|
|
341
405
|
function openTestReport() {
|
|
342
406
|
if (instance.value) ui.openTestEvidence(instance.value.id)
|
|
@@ -681,6 +745,78 @@ function openTestReport() {
|
|
|
681
745
|
</template>
|
|
682
746
|
</section>
|
|
683
747
|
|
|
748
|
+
<!-- Where to go and look: the running preview, which is the verification a person who does
|
|
749
|
+
not read diffs starts from. Beside the captured views on purpose: the shots are what
|
|
750
|
+
this run saw, this is the thing itself. -->
|
|
751
|
+
<section class="mb-5" data-testid="outcome-environments">
|
|
752
|
+
<h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
|
753
|
+
{{ t('outcome.environments.title') }}
|
|
754
|
+
</h3>
|
|
755
|
+
<template v-if="outcome.environments.status === 'reported'">
|
|
756
|
+
<div
|
|
757
|
+
v-for="row in environmentRows"
|
|
758
|
+
:key="row.key"
|
|
759
|
+
class="mb-2 rounded-md border border-slate-800 bg-slate-950/40 px-2.5 py-2 last:mb-0"
|
|
760
|
+
data-testid="outcome-environment"
|
|
761
|
+
:data-state="row.state"
|
|
762
|
+
>
|
|
763
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
764
|
+
<UBadge :color="ENVIRONMENT_STATE_COLOR[row.state]" variant="subtle" size="sm">
|
|
765
|
+
{{ t(ENVIRONMENT_STATE_KEYS[row.state]) }}
|
|
766
|
+
</UBadge>
|
|
767
|
+
<span v-if="row.service" class="truncate text-[12px] text-slate-300">
|
|
768
|
+
{{ row.service }}
|
|
769
|
+
</span>
|
|
770
|
+
<span class="text-[11px] text-slate-500">
|
|
771
|
+
{{ t(ENVIRONMENT_ORIGIN_KEYS[row.origin]) }}
|
|
772
|
+
</span>
|
|
773
|
+
</div>
|
|
774
|
+
<UButton
|
|
775
|
+
v-if="row.openable"
|
|
776
|
+
:to="row.url ?? undefined"
|
|
777
|
+
target="_blank"
|
|
778
|
+
rel="noopener"
|
|
779
|
+
external
|
|
780
|
+
color="primary"
|
|
781
|
+
variant="soft"
|
|
782
|
+
size="xs"
|
|
783
|
+
class="mt-1.5"
|
|
784
|
+
icon="i-lucide-external-link"
|
|
785
|
+
data-testid="outcome-environment-open"
|
|
786
|
+
>
|
|
787
|
+
{{ t('outcome.environments.open') }}
|
|
788
|
+
</UButton>
|
|
789
|
+
<p
|
|
790
|
+
v-else-if="row.url"
|
|
791
|
+
class="mt-1.5 break-all text-[12px] text-slate-500"
|
|
792
|
+
data-testid="outcome-environment-url"
|
|
793
|
+
>
|
|
794
|
+
{{ row.url }}
|
|
795
|
+
</p>
|
|
796
|
+
<p v-if="row.retained" class="mt-1 text-[11px] text-slate-400">
|
|
797
|
+
{{ t('outcome.environments.retained') }}
|
|
798
|
+
</p>
|
|
799
|
+
<p v-if="row.expiresAt" class="mt-1 text-[11px] text-slate-500">
|
|
800
|
+
{{
|
|
801
|
+
row.lapsed
|
|
802
|
+
? t('outcome.environments.expired', { date: d(new Date(row.expiresAt), 'long') })
|
|
803
|
+
: t('outcome.environments.expires', { date: d(new Date(row.expiresAt), 'long') })
|
|
804
|
+
}}
|
|
805
|
+
</p>
|
|
806
|
+
<p
|
|
807
|
+
v-if="row.detail"
|
|
808
|
+
class="mt-1 break-words text-[12px] leading-relaxed text-slate-500"
|
|
809
|
+
data-testid="outcome-environment-detail"
|
|
810
|
+
>
|
|
811
|
+
{{ row.detail }}
|
|
812
|
+
</p>
|
|
813
|
+
</div>
|
|
814
|
+
</template>
|
|
815
|
+
<p v-else class="text-[13px] italic leading-relaxed text-slate-500">
|
|
816
|
+
{{ t(ENVIRONMENTS_GAP_KEYS[outcome.environments.gap]) }}
|
|
817
|
+
</p>
|
|
818
|
+
</section>
|
|
819
|
+
|
|
684
820
|
<!-- The machine checks, listed only where one actually recorded a verdict. -->
|
|
685
821
|
<section v-if="checkRows.length" data-testid="outcome-checks">
|
|
686
822
|
<h3 class="mb-1.5 text-[11px] font-semibold uppercase tracking-wide text-slate-500">
|
package/app/utils/runOutcome.ts
CHANGED
|
@@ -24,6 +24,10 @@ export type {
|
|
|
24
24
|
OutcomeCheckState,
|
|
25
25
|
OutcomeConcern,
|
|
26
26
|
OutcomeDisposition,
|
|
27
|
+
OutcomeEnvironment,
|
|
28
|
+
OutcomeEnvironments,
|
|
29
|
+
OutcomeEnvironmentOrigin,
|
|
30
|
+
OutcomeEnvironmentState,
|
|
27
31
|
OutcomePullRequest,
|
|
28
32
|
OutcomeRequirement,
|
|
29
33
|
OutcomeRequirements,
|
|
@@ -33,6 +37,7 @@ export type {
|
|
|
33
37
|
OutcomeTests,
|
|
34
38
|
OutcomeVisual,
|
|
35
39
|
OutcomeVisuals,
|
|
40
|
+
EnvironmentsGap,
|
|
36
41
|
RequirementsGap,
|
|
37
42
|
RunOutcome,
|
|
38
43
|
RunUnavailableGap,
|
package/i18n/locales/de.json
CHANGED
|
@@ -6414,6 +6414,31 @@
|
|
|
6414
6414
|
"none_captured": "Die Oberfläche sollte aufgenommen werden, es wurde aber keine Ansicht erfasst."
|
|
6415
6415
|
}
|
|
6416
6416
|
},
|
|
6417
|
+
"environments": {
|
|
6418
|
+
"title": "Live-Umgebung",
|
|
6419
|
+
"open": "Live-Umgebung öffnen",
|
|
6420
|
+
"retained": "Diese Umgebung soll den Lauf überdauern.",
|
|
6421
|
+
"expires": "Läuft am {date} ab",
|
|
6422
|
+
"expired": "Abgelaufen am {date}",
|
|
6423
|
+
"state": {
|
|
6424
|
+
"live": "Live",
|
|
6425
|
+
"provisioning": "Wird bereitgestellt",
|
|
6426
|
+
"failed": "Kam nie hoch",
|
|
6427
|
+
"reclaiming": "Wird abgebaut",
|
|
6428
|
+
"reclaimed": "Abgebaut",
|
|
6429
|
+
"expired": "Abgelaufen"
|
|
6430
|
+
},
|
|
6431
|
+
"origin": {
|
|
6432
|
+
"deployer": "Von diesem Lauf bereitgestellt",
|
|
6433
|
+
"human_test": "Für den manuellen Test bereitgestellt",
|
|
6434
|
+
"projected": "Der Lauf arbeitet noch, das kann sich also noch ändern"
|
|
6435
|
+
},
|
|
6436
|
+
"gap": {
|
|
6437
|
+
"no_environment_step": "In dieser Pipeline stellt nichts eine Umgebung bereit, es gibt also nichts zu öffnen.",
|
|
6438
|
+
"not_provisioned": "Eine Umgebung sollte bereitgestellt werden, bisher wurde aber keine erfasst.",
|
|
6439
|
+
"infraless": "Dieser Service deklariert keine eigene Umgebung, es wurde also nichts bereitgestellt."
|
|
6440
|
+
}
|
|
6441
|
+
},
|
|
6417
6442
|
"checks": {
|
|
6418
6443
|
"title": "Prüfungen",
|
|
6419
6444
|
"row": "{kind}: {state}",
|
package/i18n/locales/en.json
CHANGED
|
@@ -6129,6 +6129,31 @@
|
|
|
6129
6129
|
"none_captured": "The interface was meant to be captured, but no view was."
|
|
6130
6130
|
}
|
|
6131
6131
|
},
|
|
6132
|
+
"environments": {
|
|
6133
|
+
"title": "Live environment",
|
|
6134
|
+
"open": "Open the live environment",
|
|
6135
|
+
"retained": "This environment is meant to outlive the run.",
|
|
6136
|
+
"expires": "Expires {date}",
|
|
6137
|
+
"expired": "Expired {date}",
|
|
6138
|
+
"state": {
|
|
6139
|
+
"live": "Live",
|
|
6140
|
+
"provisioning": "Coming up",
|
|
6141
|
+
"failed": "Never came up",
|
|
6142
|
+
"reclaiming": "Being torn down",
|
|
6143
|
+
"reclaimed": "Torn down",
|
|
6144
|
+
"expired": "Expired"
|
|
6145
|
+
},
|
|
6146
|
+
"origin": {
|
|
6147
|
+
"deployer": "Stood up by this run",
|
|
6148
|
+
"human_test": "Stood up for the hands-on test",
|
|
6149
|
+
"projected": "The run is still working, so this can still change"
|
|
6150
|
+
},
|
|
6151
|
+
"gap": {
|
|
6152
|
+
"no_environment_step": "Nothing in this pipeline stands an environment up, so there is nothing to open.",
|
|
6153
|
+
"not_provisioned": "An environment was meant to be stood up, and none has been recorded yet.",
|
|
6154
|
+
"infraless": "This service declares no environment of its own, so nothing was stood up."
|
|
6155
|
+
}
|
|
6156
|
+
},
|
|
6132
6157
|
"checks": {
|
|
6133
6158
|
"title": "Checks",
|
|
6134
6159
|
"row": "{kind}: {state}",
|
package/i18n/locales/es.json
CHANGED
|
@@ -5851,6 +5851,31 @@
|
|
|
5851
5851
|
"none_captured": "La interfaz debía capturarse, pero no se capturó ninguna vista."
|
|
5852
5852
|
}
|
|
5853
5853
|
},
|
|
5854
|
+
"environments": {
|
|
5855
|
+
"title": "Entorno en vivo",
|
|
5856
|
+
"open": "Abrir el entorno en vivo",
|
|
5857
|
+
"retained": "Este entorno está pensado para seguir existiendo después de la ejecución.",
|
|
5858
|
+
"expires": "Caduca el {date}",
|
|
5859
|
+
"expired": "Caducó el {date}",
|
|
5860
|
+
"state": {
|
|
5861
|
+
"live": "En vivo",
|
|
5862
|
+
"provisioning": "Levantándose",
|
|
5863
|
+
"failed": "Nunca llegó a levantarse",
|
|
5864
|
+
"reclaiming": "Desmontándose",
|
|
5865
|
+
"reclaimed": "Desmontado",
|
|
5866
|
+
"expired": "Caducado"
|
|
5867
|
+
},
|
|
5868
|
+
"origin": {
|
|
5869
|
+
"deployer": "Levantado por esta ejecución",
|
|
5870
|
+
"human_test": "Levantado para la prueba manual",
|
|
5871
|
+
"projected": "La ejecución sigue en curso, así que esto aún puede cambiar"
|
|
5872
|
+
},
|
|
5873
|
+
"gap": {
|
|
5874
|
+
"no_environment_step": "Nada en esta canalización levanta un entorno, así que no hay nada que abrir.",
|
|
5875
|
+
"not_provisioned": "Debía levantarse un entorno y todavía no se ha registrado ninguno.",
|
|
5876
|
+
"infraless": "Este servicio no declara ningún entorno propio, así que no se levantó nada."
|
|
5877
|
+
}
|
|
5878
|
+
},
|
|
5854
5879
|
"checks": {
|
|
5855
5880
|
"title": "Comprobaciones",
|
|
5856
5881
|
"row": "{kind}: {state}",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -5851,6 +5851,31 @@
|
|
|
5851
5851
|
"none_captured": "L'interface devait être capturée, mais aucune vue ne l'a été."
|
|
5852
5852
|
}
|
|
5853
5853
|
},
|
|
5854
|
+
"environments": {
|
|
5855
|
+
"title": "Environnement en ligne",
|
|
5856
|
+
"open": "Ouvrir l'environnement en ligne",
|
|
5857
|
+
"retained": "Cet environnement est censé survivre à l’exécution.",
|
|
5858
|
+
"expires": "Expire le {date}",
|
|
5859
|
+
"expired": "Expiré le {date}",
|
|
5860
|
+
"state": {
|
|
5861
|
+
"live": "En ligne",
|
|
5862
|
+
"provisioning": "En cours de création",
|
|
5863
|
+
"failed": "Jamais démarré",
|
|
5864
|
+
"reclaiming": "En cours de suppression",
|
|
5865
|
+
"reclaimed": "Supprimé",
|
|
5866
|
+
"expired": "Expiré"
|
|
5867
|
+
},
|
|
5868
|
+
"origin": {
|
|
5869
|
+
"deployer": "Créé par cette exécution",
|
|
5870
|
+
"human_test": "Créé pour le test manuel",
|
|
5871
|
+
"projected": "L'exécution est toujours en cours, cela peut encore changer"
|
|
5872
|
+
},
|
|
5873
|
+
"gap": {
|
|
5874
|
+
"no_environment_step": "Rien dans ce pipeline ne crée d'environnement, il n'y a donc rien à ouvrir.",
|
|
5875
|
+
"not_provisioned": "Un environnement devait être créé et aucun n'a encore été enregistré.",
|
|
5876
|
+
"infraless": "Ce service ne déclare aucun environnement propre, rien n'a donc été créé."
|
|
5877
|
+
}
|
|
5878
|
+
},
|
|
5854
5879
|
"checks": {
|
|
5855
5880
|
"title": "Contrôles",
|
|
5856
5881
|
"row": "{kind} : {state}",
|
package/i18n/locales/he.json
CHANGED
|
@@ -5851,6 +5851,31 @@
|
|
|
5851
5851
|
"none_captured": "הממשק היה אמור להיות מצולם, אך שום תצוגה לא נלכדה."
|
|
5852
5852
|
}
|
|
5853
5853
|
},
|
|
5854
|
+
"environments": {
|
|
5855
|
+
"title": "סביבה פעילה",
|
|
5856
|
+
"open": "פתיחת הסביבה הפעילה",
|
|
5857
|
+
"retained": "סביבה זו נועדה להישאר קיימת גם לאחר סיום ההרצה.",
|
|
5858
|
+
"expires": "פג תוקף ב־{date}",
|
|
5859
|
+
"expired": "פג תוקף ב-{date}",
|
|
5860
|
+
"state": {
|
|
5861
|
+
"live": "פעילה",
|
|
5862
|
+
"provisioning": "עולה",
|
|
5863
|
+
"failed": "מעולם לא עלתה",
|
|
5864
|
+
"reclaiming": "בפירוק",
|
|
5865
|
+
"reclaimed": "פורקה",
|
|
5866
|
+
"expired": "פג תוקף"
|
|
5867
|
+
},
|
|
5868
|
+
"origin": {
|
|
5869
|
+
"deployer": "הוקמה על ידי ההרצה הזו",
|
|
5870
|
+
"human_test": "הוקמה לצורך בדיקה ידנית",
|
|
5871
|
+
"projected": "ההרצה עדיין נמשכת, ולכן זה עשוי להשתנות"
|
|
5872
|
+
},
|
|
5873
|
+
"gap": {
|
|
5874
|
+
"no_environment_step": "שום שלב בצינור הזה אינו מקים סביבה, ולכן אין מה לפתוח.",
|
|
5875
|
+
"not_provisioned": "הייתה אמורה לקום סביבה, ועדיין לא נרשמה אף אחת.",
|
|
5876
|
+
"infraless": "השירות הזה אינו מגדיר סביבה משלו, ולכן לא הוקם דבר."
|
|
5877
|
+
}
|
|
5878
|
+
},
|
|
5854
5879
|
"checks": {
|
|
5855
5880
|
"title": "בדיקות",
|
|
5856
5881
|
"row": "{kind}: {state}",
|
package/i18n/locales/it.json
CHANGED
|
@@ -6414,6 +6414,31 @@
|
|
|
6414
6414
|
"none_captured": "L'interfaccia doveva essere catturata, ma non è stata catturata alcuna vista."
|
|
6415
6415
|
}
|
|
6416
6416
|
},
|
|
6417
|
+
"environments": {
|
|
6418
|
+
"title": "Ambiente attivo",
|
|
6419
|
+
"open": "Apri l'ambiente attivo",
|
|
6420
|
+
"retained": "Questo ambiente è pensato per sopravvivere all’esecuzione.",
|
|
6421
|
+
"expires": "Scade il {date}",
|
|
6422
|
+
"expired": "Scaduto il {date}",
|
|
6423
|
+
"state": {
|
|
6424
|
+
"live": "Attivo",
|
|
6425
|
+
"provisioning": "In avvio",
|
|
6426
|
+
"failed": "Mai avviato",
|
|
6427
|
+
"reclaiming": "In dismissione",
|
|
6428
|
+
"reclaimed": "Dismesso",
|
|
6429
|
+
"expired": "Scaduto"
|
|
6430
|
+
},
|
|
6431
|
+
"origin": {
|
|
6432
|
+
"deployer": "Avviato da questa esecuzione",
|
|
6433
|
+
"human_test": "Avviato per il test manuale",
|
|
6434
|
+
"projected": "L'esecuzione è ancora in corso, quindi può ancora cambiare"
|
|
6435
|
+
},
|
|
6436
|
+
"gap": {
|
|
6437
|
+
"no_environment_step": "In questa pipeline nulla avvia un ambiente, quindi non c'è niente da aprire.",
|
|
6438
|
+
"not_provisioned": "Doveva essere avviato un ambiente e finora non ne è stato registrato nessuno.",
|
|
6439
|
+
"infraless": "Questo servizio non dichiara un ambiente proprio, quindi non è stato avviato nulla."
|
|
6440
|
+
}
|
|
6441
|
+
},
|
|
6417
6442
|
"checks": {
|
|
6418
6443
|
"title": "Controlli",
|
|
6419
6444
|
"row": "{kind}: {state}",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -5851,6 +5851,31 @@
|
|
|
5851
5851
|
"none_captured": "画面を取得する予定でしたが、ビューは取得されませんでした。"
|
|
5852
5852
|
}
|
|
5853
5853
|
},
|
|
5854
|
+
"environments": {
|
|
5855
|
+
"title": "稼働中の環境",
|
|
5856
|
+
"open": "稼働中の環境を開く",
|
|
5857
|
+
"retained": "この環境は実行の終了後も残るように設定されています。",
|
|
5858
|
+
"expires": "{date} に期限切れ",
|
|
5859
|
+
"expired": "{date} に期限切れ",
|
|
5860
|
+
"state": {
|
|
5861
|
+
"live": "稼働中",
|
|
5862
|
+
"provisioning": "起動中",
|
|
5863
|
+
"failed": "起動できませんでした",
|
|
5864
|
+
"reclaiming": "破棄中",
|
|
5865
|
+
"reclaimed": "破棄済み",
|
|
5866
|
+
"expired": "期限切れ"
|
|
5867
|
+
},
|
|
5868
|
+
"origin": {
|
|
5869
|
+
"deployer": "この実行が用意した環境",
|
|
5870
|
+
"human_test": "手動テスト用に用意した環境",
|
|
5871
|
+
"projected": "実行がまだ続いているため、この内容は変わる可能性があります"
|
|
5872
|
+
},
|
|
5873
|
+
"gap": {
|
|
5874
|
+
"no_environment_step": "このパイプラインには環境を用意する処理がないため、開けるものはありません。",
|
|
5875
|
+
"not_provisioned": "環境が用意されるはずですが、まだ何も記録されていません。",
|
|
5876
|
+
"infraless": "このサービスは独自の環境を宣言していないため、何も用意されていません。"
|
|
5877
|
+
}
|
|
5878
|
+
},
|
|
5854
5879
|
"checks": {
|
|
5855
5880
|
"title": "チェック",
|
|
5856
5881
|
"row": "{kind}: {state}",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -5851,6 +5851,31 @@
|
|
|
5851
5851
|
"none_captured": "Interfejs miał zostać zarejestrowany, ale nie zapisano żadnego widoku."
|
|
5852
5852
|
}
|
|
5853
5853
|
},
|
|
5854
|
+
"environments": {
|
|
5855
|
+
"title": "Działające środowisko",
|
|
5856
|
+
"open": "Otwórz działające środowisko",
|
|
5857
|
+
"retained": "To środowisko ma istnieć dłużej niż samo uruchomienie.",
|
|
5858
|
+
"expires": "Wygasa {date}",
|
|
5859
|
+
"expired": "Wygasło {date}",
|
|
5860
|
+
"state": {
|
|
5861
|
+
"live": "Działa",
|
|
5862
|
+
"provisioning": "Uruchamiane",
|
|
5863
|
+
"failed": "Nigdy nie wystartowało",
|
|
5864
|
+
"reclaiming": "Usuwane",
|
|
5865
|
+
"reclaimed": "Usunięte",
|
|
5866
|
+
"expired": "Wygasło"
|
|
5867
|
+
},
|
|
5868
|
+
"origin": {
|
|
5869
|
+
"deployer": "Uruchomione przez ten przebieg",
|
|
5870
|
+
"human_test": "Uruchomione na potrzeby testu ręcznego",
|
|
5871
|
+
"projected": "Przebieg wciąż trwa, więc to może się jeszcze zmienić"
|
|
5872
|
+
},
|
|
5873
|
+
"gap": {
|
|
5874
|
+
"no_environment_step": "Nic w tym potoku nie uruchamia środowiska, więc nie ma czego otworzyć.",
|
|
5875
|
+
"not_provisioned": "Środowisko miało zostać uruchomione, ale żadnego jeszcze nie zapisano.",
|
|
5876
|
+
"infraless": "Ta usługa nie deklaruje własnego środowiska, więc nic nie zostało uruchomione."
|
|
5877
|
+
}
|
|
5878
|
+
},
|
|
5854
5879
|
"checks": {
|
|
5855
5880
|
"title": "Sprawdzenia",
|
|
5856
5881
|
"row": "{kind}: {state}",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -5851,6 +5851,31 @@
|
|
|
5851
5851
|
"none_captured": "Arayüzün yakalanması gerekiyordu ama hiçbir görünüm yakalanmadı."
|
|
5852
5852
|
}
|
|
5853
5853
|
},
|
|
5854
|
+
"environments": {
|
|
5855
|
+
"title": "Canlı ortam",
|
|
5856
|
+
"open": "Canlı ortamı aç",
|
|
5857
|
+
"retained": "Bu ortamın çalıştırma bittikten sonra da kalması amaçlanıyor.",
|
|
5858
|
+
"expires": "{date} tarihinde sona eriyor",
|
|
5859
|
+
"expired": "{date} tarihinde süresi doldu",
|
|
5860
|
+
"state": {
|
|
5861
|
+
"live": "Canlı",
|
|
5862
|
+
"provisioning": "Ayağa kalkıyor",
|
|
5863
|
+
"failed": "Hiç ayağa kalkmadı",
|
|
5864
|
+
"reclaiming": "Kaldırılıyor",
|
|
5865
|
+
"reclaimed": "Kaldırıldı",
|
|
5866
|
+
"expired": "Süresi doldu"
|
|
5867
|
+
},
|
|
5868
|
+
"origin": {
|
|
5869
|
+
"deployer": "Bu çalışma tarafından ayağa kaldırıldı",
|
|
5870
|
+
"human_test": "Elle yapılan test için ayağa kaldırıldı",
|
|
5871
|
+
"projected": "Çalışma sürüyor, bu yüzden bu durum değişebilir"
|
|
5872
|
+
},
|
|
5873
|
+
"gap": {
|
|
5874
|
+
"no_environment_step": "Bu hatta ortam ayağa kaldıran bir adım yok, açılacak bir şey de yok.",
|
|
5875
|
+
"not_provisioned": "Bir ortam ayağa kaldırılacaktı, ancak henüz hiçbiri kaydedilmedi.",
|
|
5876
|
+
"infraless": "Bu servis kendine ait bir ortam tanımlamıyor, bu yüzden hiçbir şey ayağa kaldırılmadı."
|
|
5877
|
+
}
|
|
5878
|
+
},
|
|
5854
5879
|
"checks": {
|
|
5855
5880
|
"title": "Denetimler",
|
|
5856
5881
|
"row": "{kind}: {state}",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -5851,6 +5851,31 @@
|
|
|
5851
5851
|
"none_captured": "Інтерфейс мали зняти, але жодного екрана не збережено."
|
|
5852
5852
|
}
|
|
5853
5853
|
},
|
|
5854
|
+
"environments": {
|
|
5855
|
+
"title": "Робоче середовище",
|
|
5856
|
+
"open": "Відкрити робоче середовище",
|
|
5857
|
+
"retained": "Це середовище має існувати й після завершення запуску.",
|
|
5858
|
+
"expires": "Діє до {date}",
|
|
5859
|
+
"expired": "Термін дії минув {date}",
|
|
5860
|
+
"state": {
|
|
5861
|
+
"live": "Працює",
|
|
5862
|
+
"provisioning": "Розгортається",
|
|
5863
|
+
"failed": "Так і не запустилося",
|
|
5864
|
+
"reclaiming": "Згортається",
|
|
5865
|
+
"reclaimed": "Згорнуто",
|
|
5866
|
+
"expired": "Термін вичерпано"
|
|
5867
|
+
},
|
|
5868
|
+
"origin": {
|
|
5869
|
+
"deployer": "Розгорнуто цим запуском",
|
|
5870
|
+
"human_test": "Розгорнуто для ручного тестування",
|
|
5871
|
+
"projected": "Запуск ще триває, тож це може змінитися"
|
|
5872
|
+
},
|
|
5873
|
+
"gap": {
|
|
5874
|
+
"no_environment_step": "У цьому конвеєрі ніщо не розгортає середовище, тож відкривати нічого.",
|
|
5875
|
+
"not_provisioned": "Середовище мало розгорнутися, але поки що не зафіксовано жодного.",
|
|
5876
|
+
"infraless": "Ця служба не оголошує власного середовища, тож нічого не розгорталося."
|
|
5877
|
+
}
|
|
5878
|
+
},
|
|
5854
5879
|
"checks": {
|
|
5855
5880
|
"title": "Перевірки",
|
|
5856
5881
|
"row": "{kind}: {state}",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.259.1",
|
|
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",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"valibot": "^1.4.2",
|
|
41
41
|
"vue": "3.5.41",
|
|
42
42
|
"wretch": "^3.0.9",
|
|
43
|
-
"@cat-factory/contracts": "0.
|
|
43
|
+
"@cat-factory/contracts": "0.289.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|