@cat-factory/app 0.84.0 → 0.86.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/board/AddTaskModal.vue +4 -3
- package/app/components/board/RecurringPipelineModal.vue +19 -4
- package/app/components/focus/BlockFocusView.vue +4 -3
- package/app/components/panels/InspectorPanel.vue +5 -4
- package/app/components/panels/inspector/RecurringScheduleSettings.vue +23 -3
- package/app/components/panels/inspector/TaskRunSettings.vue +7 -4
- package/app/composables/api/recurring.ts +8 -3
- package/app/stores/recurringPipelines.ts +13 -5
- package/app/utils/pipeline.ts +30 -0
- package/i18n/locales/en.json +6 -2
- package/i18n/locales/es.json +6 -2
- package/i18n/locales/fr.json +6 -2
- package/i18n/locales/he.json +6 -2
- package/i18n/locales/ja.json +6 -2
- package/i18n/locales/pl.json +6 -2
- package/i18n/locales/tr.json +6 -2
- package/i18n/locales/uk.json +6 -2
- package/package.json +2 -2
|
@@ -16,7 +16,7 @@ import { DOC_KINDS } from '~/types/domain'
|
|
|
16
16
|
import ContextDocumentPicker from '~/components/documents/ContextDocumentPicker.vue'
|
|
17
17
|
import ContextIssuePicker from '~/components/tasks/ContextIssuePicker.vue'
|
|
18
18
|
import { mergePresetOptionLabel, mergePresetThresholds } from '~/utils/mergePreset'
|
|
19
|
-
import {
|
|
19
|
+
import { pipelineAllowedForManualStart } from '~/utils/pipeline'
|
|
20
20
|
|
|
21
21
|
const ui = useUiStore()
|
|
22
22
|
const board = useBoardStore()
|
|
@@ -197,9 +197,10 @@ const selectedModelPresetLabel = computed(() => {
|
|
|
197
197
|
})
|
|
198
198
|
|
|
199
199
|
// Hide UI-testing pipelines (`tester-ui` / `visual-confirmation`) when the target frame has no
|
|
200
|
-
// UI to exercise — they'd be refused server-side (see utils/pipeline + the backend gate).
|
|
200
|
+
// UI to exercise — they'd be refused server-side (see utils/pipeline + the backend gate). Also
|
|
201
|
+
// hide `'recurring'`-only pipelines: a one-off task start of one is refused at run start.
|
|
201
202
|
const selectablePipelines = computed(() =>
|
|
202
|
-
pipelines.pipelines.filter((p) =>
|
|
203
|
+
pipelines.pipelines.filter((p) => pipelineAllowedForManualStart(p, frame.value, board.blocks)),
|
|
203
204
|
)
|
|
204
205
|
const pipelineMenu = computed(() => [
|
|
205
206
|
[
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// pipeline is picked, the workspace issue-tracker choice is surfaced inline (it is
|
|
7
7
|
// where that pipeline files its ticket) and saved alongside.
|
|
8
8
|
import type { Recurrence, ScheduleTemplate } from '~/types/recurring'
|
|
9
|
-
import {
|
|
9
|
+
import { pipelineAllowedForSchedule } from '~/utils/pipeline'
|
|
10
10
|
|
|
11
11
|
const ui = useUiStore()
|
|
12
12
|
const board = useBoardStore()
|
|
@@ -32,6 +32,9 @@ const description = ref('')
|
|
|
32
32
|
const pipelineId = ref('')
|
|
33
33
|
const saving = ref(false)
|
|
34
34
|
const recurrence = ref<Recurrence>(defaultRecurrence())
|
|
35
|
+
// On-demand: no cadence, fires only via "run now". Because a person is present at fire time,
|
|
36
|
+
// its block may use an individual-usage subscription model (which a cadence schedule can't).
|
|
37
|
+
const onDemand = ref(false)
|
|
35
38
|
|
|
36
39
|
// Tracker config (only relevant when the tech-debt pipeline is picked).
|
|
37
40
|
const trackerKind = ref<'github' | 'jira' | 'linear' | null>(null)
|
|
@@ -49,8 +52,9 @@ function defaultRecurrence(): Recurrence {
|
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
// Hide UI-testing pipelines when the frame has no UI to exercise — they'd be refused at run start.
|
|
55
|
+
// Also hide `'one-off'`-only pipelines: attaching one to a schedule is refused server-side.
|
|
52
56
|
const selectablePipelines = computed(() =>
|
|
53
|
-
pipelines.pipelines.filter((p) =>
|
|
57
|
+
pipelines.pipelines.filter((p) => pipelineAllowedForSchedule(p, frame.value, board.blocks)),
|
|
54
58
|
)
|
|
55
59
|
const pipelineMenu = computed(() => [
|
|
56
60
|
selectablePipelines.value.map((p) => ({
|
|
@@ -83,6 +87,7 @@ watch(open, (isOpen) => {
|
|
|
83
87
|
pipelines.pipelines[0]?.id ??
|
|
84
88
|
''
|
|
85
89
|
recurrence.value = defaultRecurrence()
|
|
90
|
+
onDemand.value = false
|
|
86
91
|
saving.value = false
|
|
87
92
|
trackerKind.value = tracker.settings.tracker
|
|
88
93
|
jiraProjectKey.value = tracker.settings.jiraProjectKey ?? ''
|
|
@@ -110,7 +115,9 @@ async function add() {
|
|
|
110
115
|
pipelineId: pipelineId.value,
|
|
111
116
|
template: template.value,
|
|
112
117
|
name: name.value.trim(),
|
|
113
|
-
|
|
118
|
+
// An on-demand schedule carries no cadence; a scheduled one sends its recurrence.
|
|
119
|
+
onDemand: onDemand.value,
|
|
120
|
+
...(onDemand.value ? {} : { recurrence: recurrence.value }),
|
|
114
121
|
...(description.value.trim() ? { description: description.value.trim() } : {}),
|
|
115
122
|
})
|
|
116
123
|
ui.closeAddRecurring()
|
|
@@ -173,7 +180,15 @@ async function add() {
|
|
|
173
180
|
/>
|
|
174
181
|
</UFormField>
|
|
175
182
|
|
|
176
|
-
<
|
|
183
|
+
<div class="flex items-start gap-2 rounded-lg border border-slate-800 p-3">
|
|
184
|
+
<USwitch v-model="onDemand" size="sm" class="mt-0.5" />
|
|
185
|
+
<div class="space-y-0.5">
|
|
186
|
+
<p class="text-xs font-medium text-slate-200">{{ t('board.recurring.onDemand') }}</p>
|
|
187
|
+
<p class="text-[11px] text-slate-500">{{ t('board.recurring.onDemandHint') }}</p>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<RecurringRecurrenceEditor v-if="!onDemand" v-model="recurrence" />
|
|
177
192
|
|
|
178
193
|
<div v-if="isTechDebt" class="space-y-3 rounded-lg border border-slate-800 p-3">
|
|
179
194
|
<p class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { onKeyStroke } from '@vueuse/core'
|
|
3
3
|
import type { Block } from '~/types/domain'
|
|
4
4
|
import { blockTypeMeta, STATUS_META } from '~/utils/catalog'
|
|
5
|
-
import {
|
|
5
|
+
import { pipelineAllowedForManualStart } from '~/utils/pipeline'
|
|
6
6
|
import PipelineProgress from '~/components/pipeline/PipelineProgress.vue'
|
|
7
7
|
|
|
8
8
|
const board = useBoardStore()
|
|
@@ -27,11 +27,12 @@ const deps = computed(() =>
|
|
|
27
27
|
(block.value?.dependsOn ?? []).map((id) => board.getBlock(id)).filter((b): b is Block => !!b),
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
-
// Hide UI-testing pipelines when this block's frame has no UI to exercise
|
|
30
|
+
// Hide UI-testing pipelines when this block's frame has no UI to exercise, and `'recurring'`-only
|
|
31
|
+
// pipelines (a manual run of one is refused server-side) — see the backend gate.
|
|
31
32
|
const runMenu = computed(() => {
|
|
32
33
|
const frame = block.value ? board.serviceOf(block.value) : undefined
|
|
33
34
|
return pipelines.pipelines
|
|
34
|
-
.filter((p) =>
|
|
35
|
+
.filter((p) => pipelineAllowedForManualStart(p, frame, board.blocks))
|
|
35
36
|
.map((p) => ({
|
|
36
37
|
label: p.name,
|
|
37
38
|
icon: 'i-lucide-play',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { Block, BlockStatus } from '~/types/domain'
|
|
3
3
|
import { blockTypeMeta, STATUS_META } from '~/utils/catalog'
|
|
4
|
-
import {
|
|
4
|
+
import { pipelineAllowedForManualStart } from '~/utils/pipeline'
|
|
5
5
|
import TaskContextDocs from '~/components/documents/TaskContextDocs.vue'
|
|
6
6
|
import TaskContextIssues from '~/components/tasks/TaskContextIssues.vue'
|
|
7
7
|
import TaskAgentConfig from '~/components/panels/inspector/TaskAgentConfig.vue'
|
|
@@ -169,12 +169,13 @@ const taskBranchUrl = computed(() => {
|
|
|
169
169
|
return base ? `${base}/tree/${pr.branch}` : null
|
|
170
170
|
})
|
|
171
171
|
|
|
172
|
-
// Hide UI-testing pipelines when this block's frame has no UI to exercise
|
|
173
|
-
//
|
|
172
|
+
// Hide UI-testing pipelines when this block's frame has no UI to exercise, and `'recurring'`-only
|
|
173
|
+
// pipelines (a manual run of one is refused server-side) — they'd be refused at run start (see
|
|
174
|
+
// utils/pipeline + the backend gate).
|
|
174
175
|
const runMenu = computed(() => {
|
|
175
176
|
const frame = block.value ? board.serviceOf(block.value) : undefined
|
|
176
177
|
return pipelines.pipelines
|
|
177
|
-
.filter((p) =>
|
|
178
|
+
.filter((p) => pipelineAllowedForManualStart(p, frame, board.blocks))
|
|
178
179
|
.map((p) => ({
|
|
179
180
|
label: p.name,
|
|
180
181
|
icon: 'i-lucide-play',
|
|
@@ -150,8 +150,18 @@ function fmtTime(ms: number) {
|
|
|
150
150
|
<UIcon name="i-lucide-repeat" class="h-3.5 w-3.5" />
|
|
151
151
|
{{ t('inspector.recurring.title') }}
|
|
152
152
|
</span>
|
|
153
|
-
<UBadge
|
|
154
|
-
|
|
153
|
+
<UBadge
|
|
154
|
+
:color="schedule.onDemand ? 'primary' : schedule.enabled ? 'primary' : 'neutral'"
|
|
155
|
+
variant="subtle"
|
|
156
|
+
size="xs"
|
|
157
|
+
>
|
|
158
|
+
{{
|
|
159
|
+
schedule.onDemand
|
|
160
|
+
? t('inspector.recurring.onDemand')
|
|
161
|
+
: schedule.enabled
|
|
162
|
+
? t('inspector.recurring.active')
|
|
163
|
+
: t('inspector.recurring.paused')
|
|
164
|
+
}}
|
|
155
165
|
</UBadge>
|
|
156
166
|
</div>
|
|
157
167
|
|
|
@@ -159,7 +169,17 @@ function fmtTime(ms: number) {
|
|
|
159
169
|
<span class="text-slate-300">{{ pipelineName }}</span>
|
|
160
170
|
</p>
|
|
161
171
|
|
|
162
|
-
|
|
172
|
+
<!-- On-demand: no cadence, no pause/resume — it fires only when a person triggers it. -->
|
|
173
|
+
<template v-if="schedule.onDemand">
|
|
174
|
+
<p class="text-[11px] text-slate-500">{{ t('inspector.recurring.onDemandHint') }}</p>
|
|
175
|
+
<div class="flex flex-wrap gap-1.5 pt-1">
|
|
176
|
+
<UButton size="xs" variant="soft" icon="i-lucide-play" :loading="busy" @click="runNow">
|
|
177
|
+
{{ t('inspector.recurring.runNow') }}
|
|
178
|
+
</UButton>
|
|
179
|
+
</div>
|
|
180
|
+
</template>
|
|
181
|
+
|
|
182
|
+
<template v-else-if="!editing">
|
|
163
183
|
<p class="text-[11px] text-slate-400">{{ describeCadence(schedule.recurrence) }}</p>
|
|
164
184
|
<p class="text-[11px] text-slate-500">
|
|
165
185
|
{{ t('inspector.recurring.nextRun', { time: fmtTime(schedule.nextRunAt) }) }}
|
|
@@ -4,7 +4,7 @@ import { connectionNeighborIds } from '@cat-factory/contracts'
|
|
|
4
4
|
import type { Block } from '~/types/domain'
|
|
5
5
|
import type { WritebackOverride } from '~/types/tracker'
|
|
6
6
|
import { mergePresetOptionLabel, mergePresetThresholds } from '~/utils/mergePreset'
|
|
7
|
-
import {
|
|
7
|
+
import { pipelineAllowedForManualStart } from '~/utils/pipeline'
|
|
8
8
|
import InspectorSection from '~/components/panels/inspector/InspectorSection.vue'
|
|
9
9
|
|
|
10
10
|
const props = defineProps<{ block: Block }>()
|
|
@@ -132,11 +132,14 @@ function setModelPreset(id: string) {
|
|
|
132
132
|
const selectedPipeline = computed(() =>
|
|
133
133
|
props.block.pipelineId ? pipelines.getPipeline(props.block.pipelineId) : undefined,
|
|
134
134
|
)
|
|
135
|
-
// Hide UI-testing pipelines when this task's frame has no UI to exercise
|
|
136
|
-
//
|
|
135
|
+
// Hide UI-testing pipelines when this task's frame has no UI to exercise, and `'recurring'`-only
|
|
136
|
+
// pipelines (the task's manual Run control can't start one) — they'd be refused at run start
|
|
137
|
+
// (see utils/pipeline + the backend gate).
|
|
137
138
|
const taskFrame = computed(() => board.serviceOf(props.block))
|
|
138
139
|
const selectablePipelines = computed(() =>
|
|
139
|
-
pipelines.pipelines.filter((p) =>
|
|
140
|
+
pipelines.pipelines.filter((p) =>
|
|
141
|
+
pipelineAllowedForManualStart(p, taskFrame.value, board.blocks),
|
|
142
|
+
),
|
|
140
143
|
)
|
|
141
144
|
const pipelineMenu = computed(() => [
|
|
142
145
|
[
|
|
@@ -21,7 +21,7 @@ import type { ApiContext, Position } from './context'
|
|
|
21
21
|
type CreateScheduleBody = NonNullable<SendParams<typeof createScheduleContract>['body']>
|
|
22
22
|
|
|
23
23
|
/** Recurring (scheduled) pipelines + the in-org shared-service mount catalog. */
|
|
24
|
-
export function recurringApi({ send, ws }: ApiContext) {
|
|
24
|
+
export function recurringApi({ send, sendWith, ws, pwHeaders }: ApiContext) {
|
|
25
25
|
return {
|
|
26
26
|
// ---- recurring pipelines (scheduled runs against a service) -----------
|
|
27
27
|
listRecurringPipelines: (workspaceId: string) =>
|
|
@@ -46,8 +46,13 @@ export function recurringApi({ send, ws }: ApiContext) {
|
|
|
46
46
|
pathParams: { scheduleId: id },
|
|
47
47
|
}),
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// On-demand schedules may target an individual-usage model, so run-now carries the
|
|
50
|
+
// initiator's personal password (like a manual start) — prompted + retried on a 428.
|
|
51
|
+
runScheduleNow: (workspaceId: string, id: string, password?: string) =>
|
|
52
|
+
sendWith(pwHeaders(password), runScheduleNowContract, {
|
|
53
|
+
pathPrefix: ws(workspaceId),
|
|
54
|
+
pathParams: { scheduleId: id },
|
|
55
|
+
}),
|
|
51
56
|
|
|
52
57
|
// ---- in-org shared services (mount/unmount + org catalog) -------------
|
|
53
58
|
// The services this workspace mounts, and the org catalog it can mount from. A 503
|
|
@@ -80,12 +80,20 @@ export const useRecurringPipelinesStore = defineStore('recurringPipelines', () =
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Fire a schedule now. An on-demand schedule may target an individual-usage model, so the
|
|
85
|
+
* initiator's personal password is supplied transparently from the cache and prompted via
|
|
86
|
+
* the credential modal (then retried) when the server replies 428. Returns false when the
|
|
87
|
+
* user cancels the password prompt; true once the fire is accepted.
|
|
88
|
+
*/
|
|
89
|
+
async function runNow(id: string): Promise<boolean> {
|
|
84
90
|
const ws = useWorkspaceStore()
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
const personal = usePersonalSubscriptionsStore()
|
|
92
|
+
return personal.withCredential(async (password) => {
|
|
93
|
+
await api.runScheduleNow(ws.requireId(), id, password)
|
|
94
|
+
await loadRuns(id)
|
|
95
|
+
await ws.refresh()
|
|
96
|
+
})
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
/** Fetch (and cache) a schedule's run history for the inspector. */
|
package/app/utils/pipeline.ts
CHANGED
|
@@ -20,3 +20,33 @@ export function pipelineAllowedForFrame(
|
|
|
20
20
|
): boolean {
|
|
21
21
|
return !pipelineHasVisualStep(pipeline) || frameAllowsVisualPipeline(frame, blocks)
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
// Launch-availability filters, the surface counterpart to the backend's start-origin gate (a
|
|
25
|
+
// `'recurring'`-only pipeline can't be started as a one-off manual task, and a `'one-off'`-only
|
|
26
|
+
// pipeline can't be attached to a schedule). `availability` absent ⇒ `'both'` (unrestricted), so
|
|
27
|
+
// legacy/unset pipelines pass both. Composed with {@link pipelineAllowedForFrame} at each picker.
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Whether `pipeline` may be started as a MANUAL one-off task run (the board/inspector Run menus,
|
|
31
|
+
* the add-task modal, the task run-settings default). Excludes `'recurring'`-only pipelines the
|
|
32
|
+
* backend would refuse.
|
|
33
|
+
*/
|
|
34
|
+
export function pipelineAllowedForManualStart(
|
|
35
|
+
pipeline: Pipeline,
|
|
36
|
+
frame: Block | undefined,
|
|
37
|
+
blocks: readonly Block[],
|
|
38
|
+
): boolean {
|
|
39
|
+
return pipeline.availability !== 'recurring' && pipelineAllowedForFrame(pipeline, frame, blocks)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Whether `pipeline` may be attached to a RECURRING schedule (the recurring-pipeline modal).
|
|
44
|
+
* Excludes `'one-off'`-only pipelines the backend would refuse.
|
|
45
|
+
*/
|
|
46
|
+
export function pipelineAllowedForSchedule(
|
|
47
|
+
pipeline: Pipeline,
|
|
48
|
+
frame: Block | undefined,
|
|
49
|
+
blocks: readonly Block[],
|
|
50
|
+
): boolean {
|
|
51
|
+
return pipeline.availability !== 'one-off' && pipelineAllowedForFrame(pipeline, frame, blocks)
|
|
52
|
+
}
|
package/i18n/locales/en.json
CHANGED
|
@@ -217,7 +217,9 @@
|
|
|
217
217
|
"linearTeamId": "Linear team id",
|
|
218
218
|
"footerHint": "A single recurring task is added inside the service; each run replaces the last. Its run history is visible in the inspector.",
|
|
219
219
|
"submit": "Add recurring pipeline",
|
|
220
|
-
"addFailedTitle": "Could not add recurring pipeline"
|
|
220
|
+
"addFailedTitle": "Could not add recurring pipeline",
|
|
221
|
+
"onDemand": "On-demand (manual only)",
|
|
222
|
+
"onDemandHint": "Runs only when you trigger it, with no schedule. Because you are present each time, its task may use an individual-usage subscription model."
|
|
221
223
|
},
|
|
222
224
|
"failure": {
|
|
223
225
|
"containerFailedToStart": "Container failed to start",
|
|
@@ -481,7 +483,9 @@
|
|
|
481
483
|
"skipped": "Skipped"
|
|
482
484
|
},
|
|
483
485
|
"updateFailed": "Could not update schedule",
|
|
484
|
-
"runNowFailed": "Could not run now"
|
|
486
|
+
"runNowFailed": "Could not run now",
|
|
487
|
+
"onDemand": "On-demand",
|
|
488
|
+
"onDemandHint": "Manual only. Runs when you trigger it, and may use an individual-usage subscription model."
|
|
485
489
|
},
|
|
486
490
|
"fragments": {
|
|
487
491
|
"serviceTitle": "Service best practices",
|
package/i18n/locales/es.json
CHANGED
|
@@ -196,7 +196,9 @@
|
|
|
196
196
|
"linearTeamId": "ID del equipo de Linear",
|
|
197
197
|
"footerHint": "Se añade una única tarea recurrente dentro del servicio; cada ejecución reemplaza a la anterior. Su historial de ejecuciones es visible en el inspector.",
|
|
198
198
|
"submit": "Añadir pipeline recurrente",
|
|
199
|
-
"addFailedTitle": "No se pudo añadir la pipeline recurrente"
|
|
199
|
+
"addFailedTitle": "No se pudo añadir la pipeline recurrente",
|
|
200
|
+
"onDemand": "Bajo demanda (solo manual)",
|
|
201
|
+
"onDemandHint": "Se ejecuta solo cuando lo activas, sin programación. Como estás presente cada vez, su tarea puede usar un modelo de suscripción de uso individual."
|
|
200
202
|
},
|
|
201
203
|
"failure": {
|
|
202
204
|
"containerFailedToStart": "El contenedor no pudo iniciarse",
|
|
@@ -438,7 +440,9 @@
|
|
|
438
440
|
"skipped": "Omitida"
|
|
439
441
|
},
|
|
440
442
|
"updateFailed": "No se pudo actualizar la programación",
|
|
441
|
-
"runNowFailed": "No se pudo ejecutar ahora"
|
|
443
|
+
"runNowFailed": "No se pudo ejecutar ahora",
|
|
444
|
+
"onDemand": "Bajo demanda",
|
|
445
|
+
"onDemandHint": "Solo manual. Se ejecuta cuando lo activas y puede usar un modelo de suscripción de uso individual."
|
|
442
446
|
},
|
|
443
447
|
"fragments": {
|
|
444
448
|
"serviceTitle": "Buenas prácticas del servicio",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -196,7 +196,9 @@
|
|
|
196
196
|
"linearTeamId": "ID d’équipe Linear",
|
|
197
197
|
"footerHint": "Une seule tâche récurrente est ajoutée dans le service ; chaque exécution remplace la précédente. Son historique d’exécutions est visible dans l’inspecteur.",
|
|
198
198
|
"submit": "Ajouter la pipeline récurrente",
|
|
199
|
-
"addFailedTitle": "Impossible d’ajouter la pipeline récurrente"
|
|
199
|
+
"addFailedTitle": "Impossible d’ajouter la pipeline récurrente",
|
|
200
|
+
"onDemand": "À la demande (manuel uniquement)",
|
|
201
|
+
"onDemandHint": "Ne s'exécute que lorsque vous le déclenchez, sans planification. Comme vous êtes présent à chaque fois, sa tâche peut utiliser un modèle d'abonnement à usage individuel."
|
|
200
202
|
},
|
|
201
203
|
"failure": {
|
|
202
204
|
"containerFailedToStart": "Le conteneur n’a pas pu démarrer",
|
|
@@ -438,7 +440,9 @@
|
|
|
438
440
|
"skipped": "Ignoré"
|
|
439
441
|
},
|
|
440
442
|
"updateFailed": "Impossible de mettre à jour la planification",
|
|
441
|
-
"runNowFailed": "Impossible d'exécuter maintenant"
|
|
443
|
+
"runNowFailed": "Impossible d'exécuter maintenant",
|
|
444
|
+
"onDemand": "À la demande",
|
|
445
|
+
"onDemandHint": "Manuel uniquement. S'exécute lorsque vous le déclenchez et peut utiliser un modèle d'abonnement à usage individuel."
|
|
442
446
|
},
|
|
443
447
|
"fragments": {
|
|
444
448
|
"serviceTitle": "Bonnes pratiques du service",
|
package/i18n/locales/he.json
CHANGED
|
@@ -196,7 +196,9 @@
|
|
|
196
196
|
"linearTeamId": "מזהה צוות Linear",
|
|
197
197
|
"footerHint": "משימה מחזורית אחת נוספת בתוך השירות; כל ריצה מחליפה את הקודמת. היסטוריית הריצות שלה מוצגת במפקח.",
|
|
198
198
|
"submit": "הוסף צינור מחזורי",
|
|
199
|
-
"addFailedTitle": "לא ניתן היה להוסיף צינור מחזורי"
|
|
199
|
+
"addFailedTitle": "לא ניתן היה להוסיף צינור מחזורי",
|
|
200
|
+
"onDemand": "לפי דרישה (ידני בלבד)",
|
|
201
|
+
"onDemandHint": "רץ רק כשאתה מפעיל אותו, ללא תזמון. מכיוון שאתה נוכח בכל פעם, המשימה יכולה להשתמש במודל מנוי לשימוש אישי."
|
|
200
202
|
},
|
|
201
203
|
"failure": {
|
|
202
204
|
"containerFailedToStart": "מכל הקונטיינר נכשל בהפעלה",
|
|
@@ -438,7 +440,9 @@
|
|
|
438
440
|
"skipped": "דולג"
|
|
439
441
|
},
|
|
440
442
|
"updateFailed": "לא ניתן לעדכן את לוח הזמנים",
|
|
441
|
-
"runNowFailed": "לא ניתן להריץ עכשיו"
|
|
443
|
+
"runNowFailed": "לא ניתן להריץ עכשיו",
|
|
444
|
+
"onDemand": "לפי דרישה",
|
|
445
|
+
"onDemandHint": "ידני בלבד. רץ כשאתה מפעיל אותו, ויכול להשתמש במודל מנוי לשימוש אישי."
|
|
442
446
|
},
|
|
443
447
|
"fragments": {
|
|
444
448
|
"serviceTitle": "מומלצות עבודה לשירות",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -196,7 +196,9 @@
|
|
|
196
196
|
"linearTeamId": "Linear チーム ID",
|
|
197
197
|
"footerHint": "サービス内に繰り返しタスクが 1 つ追加され、各実行が前回を置き換えます。実行履歴はインスペクターで確認できます。",
|
|
198
198
|
"submit": "繰り返しパイプラインを追加",
|
|
199
|
-
"addFailedTitle": "繰り返しパイプラインを追加できませんでした"
|
|
199
|
+
"addFailedTitle": "繰り返しパイプラインを追加できませんでした",
|
|
200
|
+
"onDemand": "オンデマンド(手動のみ)",
|
|
201
|
+
"onDemandHint": "スケジュールはなく、手動で実行したときのみ動作します。毎回ユーザーが立ち会うため、タスクは個人利用のサブスクリプションモデルを使用できます。"
|
|
200
202
|
},
|
|
201
203
|
"failure": {
|
|
202
204
|
"containerFailedToStart": "コンテナの起動に失敗しました",
|
|
@@ -438,7 +440,9 @@
|
|
|
438
440
|
"skipped": "スキップ"
|
|
439
441
|
},
|
|
440
442
|
"updateFailed": "スケジュールを更新できませんでした",
|
|
441
|
-
"runNowFailed": "今すぐ実行できませんでした"
|
|
443
|
+
"runNowFailed": "今すぐ実行できませんでした",
|
|
444
|
+
"onDemand": "オンデマンド",
|
|
445
|
+
"onDemandHint": "手動のみ。実行したときに動作し、個人利用のサブスクリプションモデルを使用できます。"
|
|
442
446
|
},
|
|
443
447
|
"fragments": {
|
|
444
448
|
"serviceTitle": "サービスのベストプラクティス",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -196,7 +196,9 @@
|
|
|
196
196
|
"linearTeamId": "ID zespołu Linear",
|
|
197
197
|
"footerHint": "W usłudze dodawane jest jedno cykliczne zadanie; każde uruchomienie zastępuje poprzednie. Jego historia uruchomień jest widoczna w inspektorze.",
|
|
198
198
|
"submit": "Dodaj cykliczny pipeline",
|
|
199
|
-
"addFailedTitle": "Nie udało się dodać cyklicznego pipeline’u"
|
|
199
|
+
"addFailedTitle": "Nie udało się dodać cyklicznego pipeline’u",
|
|
200
|
+
"onDemand": "Na żądanie (tylko ręcznie)",
|
|
201
|
+
"onDemandHint": "Uruchamia się tylko po ręcznym wyzwoleniu, bez harmonogramu. Ponieważ za każdym razem jesteś obecny, jego zadanie może korzystać z modelu subskrypcji do użytku indywidualnego."
|
|
200
202
|
},
|
|
201
203
|
"failure": {
|
|
202
204
|
"containerFailedToStart": "Nie udało się uruchomić kontenera",
|
|
@@ -438,7 +440,9 @@
|
|
|
438
440
|
"skipped": "Pominięto"
|
|
439
441
|
},
|
|
440
442
|
"updateFailed": "Nie udało się zaktualizować harmonogramu",
|
|
441
|
-
"runNowFailed": "Nie udało się uruchomić teraz"
|
|
443
|
+
"runNowFailed": "Nie udało się uruchomić teraz",
|
|
444
|
+
"onDemand": "Na żądanie",
|
|
445
|
+
"onDemandHint": "Tylko ręcznie. Uruchamia się po wyzwoleniu i może korzystać z modelu subskrypcji do użytku indywidualnego."
|
|
442
446
|
},
|
|
443
447
|
"fragments": {
|
|
444
448
|
"serviceTitle": "Dobre praktyki usługi",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -196,7 +196,9 @@
|
|
|
196
196
|
"linearTeamId": "Linear takım kimliği",
|
|
197
197
|
"footerHint": "Servisin içine tek bir yinelenen görev eklenir; her çalıştırma bir öncekinin yerini alır. Çalıştırma geçmişi inceleme panelinde görünür.",
|
|
198
198
|
"submit": "Yinelenen pipeline ekle",
|
|
199
|
-
"addFailedTitle": "Yinelenen pipeline eklenemedi"
|
|
199
|
+
"addFailedTitle": "Yinelenen pipeline eklenemedi",
|
|
200
|
+
"onDemand": "İstek üzerine (yalnızca manuel)",
|
|
201
|
+
"onDemandHint": "Yalnızca siz tetiklediğinizde çalışır, zamanlama yoktur. Her seferinde siz hazır bulunduğunuz için görevi bireysel kullanımlı bir abonelik modeli kullanabilir."
|
|
200
202
|
},
|
|
201
203
|
"failure": {
|
|
202
204
|
"containerFailedToStart": "Konteyner başlatılamadı",
|
|
@@ -438,7 +440,9 @@
|
|
|
438
440
|
"skipped": "Atlandı"
|
|
439
441
|
},
|
|
440
442
|
"updateFailed": "Zamanlama güncellenemedi",
|
|
441
|
-
"runNowFailed": "Şimdi çalıştırılamadı"
|
|
443
|
+
"runNowFailed": "Şimdi çalıştırılamadı",
|
|
444
|
+
"onDemand": "İstek üzerine",
|
|
445
|
+
"onDemandHint": "Yalnızca manuel. Siz tetiklediğinizde çalışır ve bireysel kullanımlı bir abonelik modeli kullanabilir."
|
|
442
446
|
},
|
|
443
447
|
"fragments": {
|
|
444
448
|
"serviceTitle": "Servis en iyi uygulamaları",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -196,7 +196,9 @@
|
|
|
196
196
|
"linearTeamId": "ID команди Linear",
|
|
197
197
|
"footerHint": "У сервісі додається одне періодичне завдання; кожен запуск замінює попередній. Його історія запусків доступна в інспекторі.",
|
|
198
198
|
"submit": "Додати періодичний конвеєр",
|
|
199
|
-
"addFailedTitle": "Не вдалося додати періодичний конвеєр"
|
|
199
|
+
"addFailedTitle": "Не вдалося додати періодичний конвеєр",
|
|
200
|
+
"onDemand": "За запитом (лише вручну)",
|
|
201
|
+
"onDemandHint": "Запускається лише коли ви його активуєте, без розкладу. Оскільки ви присутні щоразу, його завдання може використовувати модель підписки для індивідуального використання."
|
|
200
202
|
},
|
|
201
203
|
"failure": {
|
|
202
204
|
"containerFailedToStart": "Не вдалося запустити контейнер",
|
|
@@ -438,7 +440,9 @@
|
|
|
438
440
|
"skipped": "Пропущено"
|
|
439
441
|
},
|
|
440
442
|
"updateFailed": "Не вдалося оновити розклад",
|
|
441
|
-
"runNowFailed": "Не вдалося запустити зараз"
|
|
443
|
+
"runNowFailed": "Не вдалося запустити зараз",
|
|
444
|
+
"onDemand": "За запитом",
|
|
445
|
+
"onDemandHint": "Лише вручну. Запускається коли ви активуєте, і може використовувати модель підписки для індивідуального використання."
|
|
442
446
|
},
|
|
443
447
|
"fragments": {
|
|
444
448
|
"serviceTitle": "Найкращі практики сервісу",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.86.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.93.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@toad-contracts/testing": "0.3.2",
|