@cat-factory/app 0.58.4 → 0.59.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/auth/LoginScreen.vue +116 -1
- package/app/components/panels/inspector/ServiceTestConfig.vue +41 -65
- package/app/components/panels/inspector/TaskAgentConfig.vue +3 -33
- package/app/components/settings/InfrastructureBackendPicker.vue +11 -8
- package/app/stores/auth.ts +53 -7
- package/app/stores/workspaceSettings.ts +0 -1
- package/app/types/domain.ts +1 -0
- package/i18n/locales/en.json +12 -10
- package/i18n/locales/es.json +12 -10
- package/i18n/locales/fr.json +12 -10
- package/i18n/locales/he.json +12 -10
- package/i18n/locales/ja.json +12 -10
- package/i18n/locales/pl.json +12 -10
- package/i18n/locales/tr.json +12 -10
- package/i18n/locales/uk.json +12 -10
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref } from 'vue'
|
|
2
|
+
import { computed, ref, watch } from 'vue'
|
|
3
3
|
import { apiErrorEnvelope } from '~/composables/api/errors'
|
|
4
4
|
|
|
5
5
|
const auth = useAuthStore()
|
|
@@ -123,6 +123,51 @@ function setMode(next: 'login' | 'signup' | 'forgot') {
|
|
|
123
123
|
const showOAuthDivider = computed(
|
|
124
124
|
() => auth.providers.password && (auth.providers.github || auth.providers.google),
|
|
125
125
|
)
|
|
126
|
+
|
|
127
|
+
// Hosted (remote node) PAT login: the user pastes their OWN source-control PAT, which the
|
|
128
|
+
// server resolves to an account and holds to its login/org/domain allowlist. The available
|
|
129
|
+
// providers come from the server (`auth.patProviders`); empty in local mode (which uses the
|
|
130
|
+
// configured-token flow above) and on OAuth-only facades like the Worker.
|
|
131
|
+
const remotePatProviders = computed<PatProvider[]>(() =>
|
|
132
|
+
isLocalMode.value ? [] : (auth.patProviders as PatProvider[]),
|
|
133
|
+
)
|
|
134
|
+
const remotePatProvider = ref<PatProvider>('github')
|
|
135
|
+
watch(
|
|
136
|
+
remotePatProviders,
|
|
137
|
+
(list) => {
|
|
138
|
+
if (list.length && !list.includes(remotePatProvider.value)) remotePatProvider.value = list[0]!
|
|
139
|
+
},
|
|
140
|
+
{ immediate: true },
|
|
141
|
+
)
|
|
142
|
+
const remotePatToken = ref('')
|
|
143
|
+
const remotePatBusy = ref(false)
|
|
144
|
+
const remotePatError = ref<string | null>(null)
|
|
145
|
+
|
|
146
|
+
async function submitRemotePat() {
|
|
147
|
+
remotePatError.value = null
|
|
148
|
+
remotePatBusy.value = true
|
|
149
|
+
try {
|
|
150
|
+
await auth.patLogin({ provider: remotePatProvider.value, token: remotePatToken.value.trim() })
|
|
151
|
+
if (typeof window !== 'undefined') window.location.assign(window.location.pathname)
|
|
152
|
+
} catch (e) {
|
|
153
|
+
remotePatError.value = apiErrorEnvelope(e)?.message ?? t('auth.login.signInFailed')
|
|
154
|
+
} finally {
|
|
155
|
+
remotePatBusy.value = false
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// A remote deployment (node service / Worker) that advertises no sign-in method at all:
|
|
160
|
+
// no OAuth, no password, no PAT, and not local mode. The auth gate still routes here (a
|
|
161
|
+
// remote facade has no anonymous tier), so instead of a blank card we explain that
|
|
162
|
+
// authentication isn't configured and there's nothing to sign in with yet.
|
|
163
|
+
const noSignInMethod = computed(
|
|
164
|
+
() =>
|
|
165
|
+
!isLocalMode.value &&
|
|
166
|
+
!auth.providers.github &&
|
|
167
|
+
!auth.providers.google &&
|
|
168
|
+
!auth.providers.password &&
|
|
169
|
+
remotePatProviders.value.length === 0,
|
|
170
|
+
)
|
|
126
171
|
</script>
|
|
127
172
|
|
|
128
173
|
<template>
|
|
@@ -296,6 +341,76 @@ const showOAuthDivider = computed(
|
|
|
296
341
|
</p>
|
|
297
342
|
</form>
|
|
298
343
|
|
|
344
|
+
<!-- Hosted (remote node) PAT login: paste your own source-control PAT -->
|
|
345
|
+
<template v-if="remotePatProviders.length > 0 && mode !== 'forgot'">
|
|
346
|
+
<div
|
|
347
|
+
v-if="auth.providers.github || auth.providers.google || auth.providers.password"
|
|
348
|
+
class="my-4 flex items-center gap-3 text-xs text-slate-500"
|
|
349
|
+
>
|
|
350
|
+
<span class="h-px flex-1 bg-slate-800" /> {{ t('auth.login.or') }}
|
|
351
|
+
<span class="h-px flex-1 bg-slate-800" />
|
|
352
|
+
</div>
|
|
353
|
+
<form class="space-y-3" @submit.prevent="submitRemotePat">
|
|
354
|
+
<div v-if="remotePatProviders.length > 1" class="flex gap-2">
|
|
355
|
+
<UButton
|
|
356
|
+
v-for="p in remotePatProviders"
|
|
357
|
+
:key="p"
|
|
358
|
+
:color="p === remotePatProvider ? 'primary' : 'neutral'"
|
|
359
|
+
:variant="p === remotePatProvider ? 'solid' : 'subtle'"
|
|
360
|
+
:icon="PROVIDER_ICONS[p]"
|
|
361
|
+
size="sm"
|
|
362
|
+
@click="remotePatProvider = p"
|
|
363
|
+
>
|
|
364
|
+
{{ PROVIDER_LABELS[p] }}
|
|
365
|
+
</UButton>
|
|
366
|
+
</div>
|
|
367
|
+
<UInput
|
|
368
|
+
v-model="remotePatToken"
|
|
369
|
+
type="password"
|
|
370
|
+
required
|
|
371
|
+
:placeholder="
|
|
372
|
+
t('auth.login.patPlaceholder', { provider: PROVIDER_LABELS[remotePatProvider] })
|
|
373
|
+
"
|
|
374
|
+
icon="i-lucide-key-round"
|
|
375
|
+
size="lg"
|
|
376
|
+
class="w-full"
|
|
377
|
+
/>
|
|
378
|
+
<p v-if="remotePatError" class="text-sm text-rose-400">{{ remotePatError }}</p>
|
|
379
|
+
<UButton
|
|
380
|
+
block
|
|
381
|
+
size="lg"
|
|
382
|
+
color="primary"
|
|
383
|
+
type="submit"
|
|
384
|
+
:icon="PROVIDER_ICONS[remotePatProvider]"
|
|
385
|
+
:loading="remotePatBusy"
|
|
386
|
+
>
|
|
387
|
+
{{ t('auth.login.signInWithPat', { provider: PROVIDER_LABELS[remotePatProvider] }) }}
|
|
388
|
+
</UButton>
|
|
389
|
+
<p class="px-1 text-center">
|
|
390
|
+
<a
|
|
391
|
+
:href="tokenCreateUrl(remotePatProvider)"
|
|
392
|
+
target="_blank"
|
|
393
|
+
rel="noopener noreferrer"
|
|
394
|
+
class="text-xs text-indigo-400 hover:underline"
|
|
395
|
+
>
|
|
396
|
+
{{
|
|
397
|
+
t('auth.localMode.createToken', { provider: PROVIDER_LABELS[remotePatProvider] })
|
|
398
|
+
}}
|
|
399
|
+
</a>
|
|
400
|
+
</p>
|
|
401
|
+
</form>
|
|
402
|
+
</template>
|
|
403
|
+
|
|
404
|
+
<!-- No sign-in method configured on a remote deployment: explain, don't show a blank card -->
|
|
405
|
+
<UAlert
|
|
406
|
+
v-if="noSignInMethod"
|
|
407
|
+
color="warning"
|
|
408
|
+
variant="subtle"
|
|
409
|
+
icon="i-lucide-shield-alert"
|
|
410
|
+
:title="t('auth.login.notConfiguredTitle')"
|
|
411
|
+
:description="t('auth.login.notConfiguredBody')"
|
|
412
|
+
/>
|
|
413
|
+
|
|
299
414
|
<!-- Forgot password: request a reset link by email -->
|
|
300
415
|
<form
|
|
301
416
|
v-if="auth.providers.password && mode === 'forgot'"
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
|
-
import type { Block, CloudProvider, InstanceSize } from '~/types/domain'
|
|
3
|
+
import type { Block, CloudProvider, InstanceSize, ProvisionType } from '~/types/domain'
|
|
4
4
|
import RepoTreeBrowser from '~/components/github/RepoTreeBrowser.vue'
|
|
5
5
|
|
|
6
|
-
// Service-level (frame) configuration:
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// size the service's container jobs run on.
|
|
10
|
-
//
|
|
11
|
-
// the
|
|
6
|
+
// Service-level (frame) configuration: the service-owned PROVISIONING — the provision
|
|
7
|
+
// TYPE this service produces (`infraless` / `docker-compose` / `kubernetes` / `custom`)
|
|
8
|
+
// plus, for docker-compose, the in-repo compose path the Tester stands up — and the
|
|
9
|
+
// cloud provider + instance size the service's container jobs run on. The WORKSPACE
|
|
10
|
+
// configures HOW each type is handled (the engine + connection), so this view only owns
|
|
11
|
+
// the "what + where". Autodiscovery suggests a compose path when the service is added.
|
|
12
12
|
const props = defineProps<{
|
|
13
13
|
block: Block
|
|
14
14
|
// Repo backing this service, supplied by the add-service modal when the block is
|
|
@@ -22,33 +22,33 @@ const github = useGitHubStore()
|
|
|
22
22
|
const services = useServicesStore()
|
|
23
23
|
const { t } = useI18n()
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// The service's declared provision type (absent ⇒ treated as `infraless`: no environment
|
|
26
|
+
// is stood up for the Tester). Switching type preserves the compose path so toggling away
|
|
27
|
+
// and back doesn't lose it.
|
|
28
|
+
const provisionType = computed<ProvisionType>(() => props.block.provisioning?.type ?? 'infraless')
|
|
29
|
+
const composePath = computed(() => props.block.provisioning?.composePath ?? '')
|
|
30
|
+
|
|
31
|
+
const PROVISION_TYPES = computed<{ value: ProvisionType; label: string }[]>(() => [
|
|
32
|
+
{ value: 'infraless', label: t('inspector.testConfig.provisionTypes.infraless') },
|
|
33
|
+
{ value: 'docker-compose', label: t('inspector.testConfig.provisionTypes.docker-compose') },
|
|
34
|
+
{ value: 'kubernetes', label: t('inspector.testConfig.provisionTypes.kubernetes') },
|
|
35
|
+
{ value: 'custom', label: t('inspector.testConfig.provisionTypes.custom') },
|
|
36
|
+
])
|
|
27
37
|
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
type
|
|
33
|
-
|
|
34
|
-
() => [
|
|
35
|
-
{
|
|
36
|
-
value: 'ephemeral',
|
|
37
|
-
label: t('inspector.testConfig.env.ephemeral'),
|
|
38
|
-
hint: t('inspector.testConfig.env.ephemeralHint'),
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
value: 'local',
|
|
42
|
-
label: t('inspector.testConfig.env.local'),
|
|
43
|
-
hint: t('inspector.testConfig.env.localHint'),
|
|
38
|
+
function setProvisionType(type: ProvisionType) {
|
|
39
|
+
// Carry the compose path across a switch so it isn't lost when toggling type.
|
|
40
|
+
board.updateBlock(props.block.id, {
|
|
41
|
+
provisioning: {
|
|
42
|
+
type,
|
|
43
|
+
...(type === 'docker-compose' && composePath.value ? { composePath: composePath.value } : {}),
|
|
44
44
|
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function setComposePath(value: string) {
|
|
49
|
+
board.updateBlock(props.block.id, {
|
|
50
|
+
provisioning: { type: 'docker-compose', composePath: value.trim() },
|
|
51
|
+
})
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// The provisioning hints (cloud provider + instance size) are advisory inputs to the
|
|
@@ -86,13 +86,6 @@ const effectiveProvider = computed<CloudProvider>(
|
|
|
86
86
|
() => props.block.cloudProvider ?? accounts.activeAccount?.defaultCloudProvider ?? 'cloudflare',
|
|
87
87
|
)
|
|
88
88
|
|
|
89
|
-
function setComposePath(value: string) {
|
|
90
|
-
board.updateBlock(props.block.id, { testComposePath: value.trim() })
|
|
91
|
-
}
|
|
92
|
-
function toggleNoInfra(value: boolean) {
|
|
93
|
-
board.updateBlock(props.block.id, { noInfraDependencies: value })
|
|
94
|
-
}
|
|
95
|
-
|
|
96
89
|
const PROVIDERS = computed<{ value: CloudProvider; label: string }[]>(() => [
|
|
97
90
|
{ value: 'cloudflare', label: 'Cloudflare' },
|
|
98
91
|
{ value: 'docker', label: t('inspector.testConfig.providers.docker') },
|
|
@@ -114,8 +107,6 @@ function setProvider(value: CloudProvider) {
|
|
|
114
107
|
function setSize(value: InstanceSize) {
|
|
115
108
|
board.updateBlock(props.block.id, { instanceSize: value })
|
|
116
109
|
}
|
|
117
|
-
|
|
118
|
-
const missingInfra = computed(() => !noInfra.value && composePath.value.trim() === '')
|
|
119
110
|
</script>
|
|
120
111
|
|
|
121
112
|
<template>
|
|
@@ -125,26 +116,25 @@ const missingInfra = computed(() => !noInfra.value && composePath.value.trim() =
|
|
|
125
116
|
</div>
|
|
126
117
|
|
|
127
118
|
<div class="space-y-1">
|
|
128
|
-
<span class="text-[11px] text-slate-400">{{ t('inspector.testConfig.
|
|
119
|
+
<span class="text-[11px] text-slate-400">{{ t('inspector.testConfig.provisionType') }}</span>
|
|
129
120
|
<div class="flex flex-wrap gap-1">
|
|
130
121
|
<UButton
|
|
131
|
-
v-for="
|
|
132
|
-
:key="
|
|
133
|
-
:color="
|
|
134
|
-
:variant="
|
|
122
|
+
v-for="p in PROVISION_TYPES"
|
|
123
|
+
:key="p.value"
|
|
124
|
+
:color="provisionType === p.value ? 'primary' : 'neutral'"
|
|
125
|
+
:variant="provisionType === p.value ? 'soft' : 'ghost'"
|
|
135
126
|
size="xs"
|
|
136
|
-
|
|
137
|
-
@click="setDefaultTestEnv(e.value)"
|
|
127
|
+
@click="setProvisionType(p.value)"
|
|
138
128
|
>
|
|
139
|
-
{{
|
|
129
|
+
{{ p.label }}
|
|
140
130
|
</UButton>
|
|
141
131
|
</div>
|
|
142
132
|
<p class="text-[11px] leading-snug text-slate-500">
|
|
143
|
-
{{ t('inspector.testConfig.
|
|
133
|
+
{{ t('inspector.testConfig.provisionTypeHint') }}
|
|
144
134
|
</p>
|
|
145
135
|
</div>
|
|
146
136
|
|
|
147
|
-
<div class="space-y-1">
|
|
137
|
+
<div v-if="provisionType === 'docker-compose'" class="space-y-1">
|
|
148
138
|
<label class="text-[11px] text-slate-400">{{ t('inspector.testConfig.composePath') }}</label>
|
|
149
139
|
<div class="flex items-center gap-1">
|
|
150
140
|
<UInput
|
|
@@ -152,7 +142,6 @@ const missingInfra = computed(() => !noInfra.value && composePath.value.trim() =
|
|
|
152
142
|
size="xs"
|
|
153
143
|
class="flex-1"
|
|
154
144
|
placeholder="docker-compose.yml"
|
|
155
|
-
:disabled="noInfra"
|
|
156
145
|
@blur="(e: FocusEvent) => setComposePath((e.target as HTMLInputElement).value)"
|
|
157
146
|
@keydown.enter="
|
|
158
147
|
(e: KeyboardEvent) => setComposePath((e.target as HTMLInputElement).value)
|
|
@@ -164,7 +153,6 @@ const missingInfra = computed(() => !noInfra.value && composePath.value.trim() =
|
|
|
164
153
|
variant="soft"
|
|
165
154
|
color="neutral"
|
|
166
155
|
icon="i-lucide-folder-search"
|
|
167
|
-
:disabled="noInfra"
|
|
168
156
|
:title="t('inspector.testConfig.browseRepo')"
|
|
169
157
|
@click="openBrowse"
|
|
170
158
|
/>
|
|
@@ -205,18 +193,6 @@ const missingInfra = computed(() => !noInfra.value && composePath.value.trim() =
|
|
|
205
193
|
</template>
|
|
206
194
|
</UModal>
|
|
207
195
|
|
|
208
|
-
<label class="flex items-center gap-2 text-[11px] text-slate-400">
|
|
209
|
-
<UCheckbox
|
|
210
|
-
:model-value="noInfra"
|
|
211
|
-
@update:model-value="(v: boolean | 'indeterminate') => toggleNoInfra(v === true)"
|
|
212
|
-
/>
|
|
213
|
-
{{ t('inspector.testConfig.noInfra') }}
|
|
214
|
-
</label>
|
|
215
|
-
|
|
216
|
-
<p v-if="missingInfra" class="text-[11px] leading-snug text-amber-500">
|
|
217
|
-
{{ t('inspector.testConfig.missingInfra') }}
|
|
218
|
-
</p>
|
|
219
|
-
|
|
220
196
|
<!-- Provisioning hints: advisory inputs to the ephemeral-environment provisioner.
|
|
221
197
|
Collapsed by default — most services never tune them. -->
|
|
222
198
|
<div class="border-t border-slate-800 pt-2">
|
|
@@ -5,7 +5,7 @@ import { useAgentConfigStore } from '~/stores/agentConfig'
|
|
|
5
5
|
import { useExecutionStore } from '~/stores/execution'
|
|
6
6
|
|
|
7
7
|
// Task-level configuration contributed by the agents in this task's selected
|
|
8
|
-
// pipeline (e.g. the
|
|
8
|
+
// pipeline (e.g. the Playwright agent's e2e target: CI vs ephemeral). Each value is
|
|
9
9
|
// editable until its contributing agent's step starts, then it freezes (the run is
|
|
10
10
|
// already consuming it). Persisted as a sparse id→value map on the block.
|
|
11
11
|
const props = defineProps<{ block: Block }>()
|
|
@@ -30,33 +30,6 @@ const descriptors = computed(() => {
|
|
|
30
30
|
|
|
31
31
|
const run = computed(() => execution.getByBlock(props.block.id))
|
|
32
32
|
|
|
33
|
-
// The Tester's environment descriptor inherits its default from the service frame this
|
|
34
|
-
// task lives under (set in the service inspector); a task only overrides it by clicking.
|
|
35
|
-
// Walk up the parent chain (frame → module → task) to find that default.
|
|
36
|
-
const serviceDefaultTestEnv = computed<'local' | 'ephemeral' | undefined>(() => {
|
|
37
|
-
let cur: Block | undefined = props.block
|
|
38
|
-
for (let i = 0; i < 8 && cur; i++) {
|
|
39
|
-
if (cur.level === 'frame') return cur.defaultTestEnvironment
|
|
40
|
-
if (!cur.parentId) break
|
|
41
|
-
cur = board.getBlock(cur.parentId)
|
|
42
|
-
}
|
|
43
|
-
return undefined
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
/** The effective default for a descriptor — the inherited service value for the Tester's
|
|
47
|
-
* environment, otherwise the descriptor's own static default. */
|
|
48
|
-
function effectiveDefault(d: { id: string; default: string }): string {
|
|
49
|
-
if (d.id === 'tester.environment' && serviceDefaultTestEnv.value) {
|
|
50
|
-
return serviceDefaultTestEnv.value
|
|
51
|
-
}
|
|
52
|
-
return d.default
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** Whether a descriptor's shown value is inherited (not explicitly pinned on this task). */
|
|
56
|
-
function isInherited(d: { id: string }): boolean {
|
|
57
|
-
return d.id === 'tester.environment' && props.block.agentConfig?.[d.id] === undefined
|
|
58
|
-
}
|
|
59
|
-
|
|
60
33
|
/** A descriptor freezes once its contributing agent's step has left `pending`. */
|
|
61
34
|
function isFrozen(agentKind: string): boolean {
|
|
62
35
|
const steps = run.value?.steps
|
|
@@ -84,9 +57,6 @@ function setValue(id: string, value: string) {
|
|
|
84
57
|
<div class="flex items-center justify-between">
|
|
85
58
|
<span class="text-[11px] text-slate-400">{{ d.label }}</span>
|
|
86
59
|
<div class="flex items-center gap-1.5">
|
|
87
|
-
<span v-if="isInherited(d)" class="text-[10px] text-slate-500">{{
|
|
88
|
-
t('inspector.agentConfig.inherited')
|
|
89
|
-
}}</span>
|
|
90
60
|
<UIcon
|
|
91
61
|
v-if="isFrozen(d.agentKind)"
|
|
92
62
|
name="i-lucide-lock"
|
|
@@ -99,8 +69,8 @@ function setValue(id: string, value: string) {
|
|
|
99
69
|
<UButton
|
|
100
70
|
v-for="opt in d.options"
|
|
101
71
|
:key="opt.value"
|
|
102
|
-
:color="valueOf(d.id,
|
|
103
|
-
:variant="valueOf(d.id,
|
|
72
|
+
:color="valueOf(d.id, d.default) === opt.value ? 'primary' : 'neutral'"
|
|
73
|
+
:variant="valueOf(d.id, d.default) === opt.value ? 'soft' : 'ghost'"
|
|
104
74
|
size="xs"
|
|
105
75
|
:disabled="isFrozen(d.agentKind)"
|
|
106
76
|
@click="setValue(d.id, opt.value)"
|
|
@@ -117,12 +117,18 @@ const poolConfigurable = computed(
|
|
|
117
117
|
providerConnections.isAvailable(connectionKind.value),
|
|
118
118
|
)
|
|
119
119
|
|
|
120
|
-
// The delegation flag is a genuine per-workspace toggle ONLY in local mode
|
|
121
|
-
|
|
120
|
+
// The delegation flag is a genuine per-workspace toggle ONLY in local mode, and ONLY on the
|
|
121
|
+
// execution axis: the Tester's environment is now driven by the SERVICE's declared provision
|
|
122
|
+
// type + per-type workspace handlers (no per-workspace test-env delegation toggle), so the
|
|
123
|
+
// testEnv axis is registration-driven (read-only "Active: …" + the connect forms) until the
|
|
124
|
+
// per-type infra configurator lands. See docs/initiatives/per-service-provision-types.md.
|
|
125
|
+
const writable = computed(
|
|
126
|
+
() => isLocal.value && props.axis === 'execution' && (cap.value?.available.length ?? 0) > 1,
|
|
127
|
+
)
|
|
122
128
|
const delegated = computed(() =>
|
|
123
129
|
props.axis === 'execution'
|
|
124
130
|
? settings.settings.delegateAgentsToRunnerPool
|
|
125
|
-
:
|
|
131
|
+
: connectionRegistered.value,
|
|
126
132
|
)
|
|
127
133
|
|
|
128
134
|
// The effective active backend (matches the prior ExecutionBackendSelector logic): local
|
|
@@ -214,11 +220,8 @@ const saving = ref(false)
|
|
|
214
220
|
async function setDelegate(value: boolean) {
|
|
215
221
|
saving.value = true
|
|
216
222
|
try {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
? { delegateAgentsToRunnerPool: value }
|
|
220
|
-
: { delegateTestEnvToProvider: value },
|
|
221
|
-
)
|
|
223
|
+
// Only reachable on the execution axis (`writable` is false for testEnv now).
|
|
224
|
+
await settings.update({ delegateAgentsToRunnerPool: value })
|
|
222
225
|
} catch (e) {
|
|
223
226
|
toast.add({
|
|
224
227
|
title: t('settings.infrastructure.updateFailed'),
|
package/app/stores/auth.ts
CHANGED
|
@@ -25,6 +25,18 @@ export const useAuthStore = defineStore(
|
|
|
25
25
|
const required = ref(false)
|
|
26
26
|
/** Which login providers the backend offers (drives the login UI). */
|
|
27
27
|
const providers = ref({ github: false, password: false, google: false })
|
|
28
|
+
/**
|
|
29
|
+
* Source-control providers a HOSTED facade (remote node) accepts a user-supplied PAT for.
|
|
30
|
+
* Drives the login screen's "sign in with a PAT" option on non-local deployments. Empty on
|
|
31
|
+
* the Worker (OAuth-only) and in local mode (which uses `localMode.patLogin` instead).
|
|
32
|
+
*/
|
|
33
|
+
const patProviders = ref<('github' | 'gitlab')[]>([])
|
|
34
|
+
/**
|
|
35
|
+
* Test-only: the backend advertised that it runs with NO authentication (its
|
|
36
|
+
* `TESTING_NO_AUTH` opt-in). When set, the SPA renders the board anonymously instead of
|
|
37
|
+
* gating to the login screen — even on a remote facade. Only ever true under the e2e suite.
|
|
38
|
+
*/
|
|
39
|
+
const testingNoAuth = ref(false)
|
|
28
40
|
/**
|
|
29
41
|
* Local-mode signals from the backend. Present only when running the local facade;
|
|
30
42
|
* `githubPatSetupUrl` is set when local mode has no GitHub PAT configured (drives the
|
|
@@ -48,18 +60,44 @@ export const useAuthStore = defineStore(
|
|
|
48
60
|
const autoLoginProvider = ref<'github' | 'gitlab' | null>(null)
|
|
49
61
|
/** True once the initial auth handshake has settled. */
|
|
50
62
|
const ready = ref(false)
|
|
63
|
+
/**
|
|
64
|
+
* True only once `getAuthConfig()` has resolved successfully. Distinguishes "the backend
|
|
65
|
+
* told us auth is off" from "we never reached the backend" (the bootstrap catch path),
|
|
66
|
+
* so an unreachable backend falls through to the board's own error UI instead of being
|
|
67
|
+
* mistaken for an unauthenticated session and gated to the login screen.
|
|
68
|
+
*/
|
|
69
|
+
const configLoaded = ref(false)
|
|
70
|
+
/**
|
|
71
|
+
* Whether this is the local-mode facade. Only the local facade reports `localMode`; the
|
|
72
|
+
* remote node service and the Cloudflare Worker never do. Used to tell "a developer's
|
|
73
|
+
* own machine (anonymous-but-dev-open is its own thing)" apart from "a remote deployment
|
|
74
|
+
* that has no anonymous tier".
|
|
75
|
+
*/
|
|
76
|
+
const isLocalFacade = computed(() => localMode.value !== null)
|
|
51
77
|
|
|
52
78
|
/** May the app render? True when auth is off, or on with a known user. */
|
|
53
79
|
const isAuthenticated = computed(() => !required.value || user.value !== null)
|
|
54
80
|
|
|
55
81
|
/**
|
|
56
|
-
* Whether the SPA must show the login screen before the board.
|
|
57
|
-
*
|
|
58
|
-
*
|
|
82
|
+
* Whether the SPA must show the login screen before the board.
|
|
83
|
+
*
|
|
84
|
+
* - Auth-enabled deployments gate on a user as before.
|
|
85
|
+
* - Local mode ALSO gates (even though its API stays dev-open), because anonymous local
|
|
86
|
+
* use can't store per-user credentials — see the login flow.
|
|
87
|
+
* - A REMOTE facade (node service / Worker) has NO anonymous tier: once the auth handshake
|
|
88
|
+
* has resolved and there's no user, gate — even when the backend reports auth "disabled"
|
|
89
|
+
* (a misconfigured/dev-open remote running without a provider). Previously this slipped
|
|
90
|
+
* through and dropped the user onto a board where every per-user action silently failed
|
|
91
|
+
* with no sign-in affordance; the login screen now surfaces that state (offering a
|
|
92
|
+
* provider, or explaining that none is configured).
|
|
59
93
|
*/
|
|
60
|
-
const needsLogin = computed(
|
|
61
|
-
|
|
62
|
-
|
|
94
|
+
const needsLogin = computed(() => {
|
|
95
|
+
if (!configLoaded.value || user.value !== null) return false
|
|
96
|
+
// A deployment that explicitly runs with no auth (the test opt-in) renders anonymously.
|
|
97
|
+
if (testingNoAuth.value) return false
|
|
98
|
+
if (isLocalFacade.value) return required.value || localMode.value?.enabled === true
|
|
99
|
+
return true
|
|
100
|
+
})
|
|
63
101
|
|
|
64
102
|
/** Pull a token handed back in the post-login URL fragment (#token=…). */
|
|
65
103
|
function consumeRedirectToken() {
|
|
@@ -78,10 +116,14 @@ export const useAuthStore = defineStore(
|
|
|
78
116
|
const config = await api.getAuthConfig()
|
|
79
117
|
required.value = config.enabled
|
|
80
118
|
if (config.providers) providers.value = config.providers
|
|
119
|
+
patProviders.value = config.patLogin?.providers ?? []
|
|
120
|
+
testingNoAuth.value = config.testingNoAuth ?? false
|
|
81
121
|
localMode.value = config.localMode ?? null
|
|
82
122
|
infrastructure.value = config.infrastructure ?? null
|
|
123
|
+
configLoaded.value = true
|
|
83
124
|
} catch {
|
|
84
|
-
// Backend unreachable — let the board's own error UI handle it
|
|
125
|
+
// Backend unreachable — let the board's own error UI handle it (configLoaded stays
|
|
126
|
+
// false, so we never mistake this for an unauthenticated session and gate it).
|
|
85
127
|
required.value = false
|
|
86
128
|
ready.value = true
|
|
87
129
|
return
|
|
@@ -229,10 +271,14 @@ export const useAuthStore = defineStore(
|
|
|
229
271
|
user,
|
|
230
272
|
required,
|
|
231
273
|
providers,
|
|
274
|
+
patProviders,
|
|
275
|
+
testingNoAuth,
|
|
232
276
|
localMode,
|
|
233
277
|
infrastructure,
|
|
234
278
|
autoLoginProvider,
|
|
235
279
|
ready,
|
|
280
|
+
configLoaded,
|
|
281
|
+
isLocalFacade,
|
|
236
282
|
isAuthenticated,
|
|
237
283
|
needsLogin,
|
|
238
284
|
bootstrap,
|
package/app/types/domain.ts
CHANGED
package/i18n/locales/en.json
CHANGED
|
@@ -424,13 +424,13 @@
|
|
|
424
424
|
},
|
|
425
425
|
"testConfig": {
|
|
426
426
|
"title": "Test infrastructure",
|
|
427
|
-
"
|
|
428
|
-
"
|
|
429
|
-
"
|
|
430
|
-
"
|
|
431
|
-
"
|
|
432
|
-
"
|
|
433
|
-
"
|
|
427
|
+
"provisionType": "Provision type",
|
|
428
|
+
"provisionTypeHint": "How this service stands up its environment for the Tester. The workspace configures how each type is handled (the engine + connection).",
|
|
429
|
+
"provisionTypes": {
|
|
430
|
+
"infraless": "No infrastructure",
|
|
431
|
+
"docker-compose": "Docker Compose",
|
|
432
|
+
"kubernetes": "Kubernetes",
|
|
433
|
+
"custom": "Custom"
|
|
434
434
|
},
|
|
435
435
|
"composePath": "docker-compose path",
|
|
436
436
|
"browseRepo": "Browse the repository for the compose file",
|
|
@@ -440,8 +440,6 @@
|
|
|
440
440
|
"selected": "Selected: {path}",
|
|
441
441
|
"noFileSelected": "No file selected.",
|
|
442
442
|
"useThisFile": "Use this file",
|
|
443
|
-
"noInfra": "No infra dependencies (the Tester spins nothing up)",
|
|
444
|
-
"missingInfra": "Set a docker-compose path or enable no infra dependencies, otherwise a pipeline with a Tester won't start.",
|
|
445
443
|
"provisioningTitle": "Ephemeral environment provisioning",
|
|
446
444
|
"provisioningHint": "A hint for provisioning this service's ephemeral test environment: which cloud provider to deploy to and how large an instance to request. Ignored for local (docker-compose) testing.",
|
|
447
445
|
"cloudProvider": "Cloud provider",
|
|
@@ -814,7 +812,11 @@
|
|
|
814
812
|
"sendResetLink": "Send reset link",
|
|
815
813
|
"backToSignIn": "Back to sign in",
|
|
816
814
|
"signInFailed": "Sign-in failed. Check your details and try again.",
|
|
817
|
-
"genericError": "Something went wrong. Please try again."
|
|
815
|
+
"genericError": "Something went wrong. Please try again.",
|
|
816
|
+
"notConfiguredTitle": "Authentication isn't configured",
|
|
817
|
+
"notConfiguredBody": "This deployment has no sign-in method enabled, so you can't sign in or access your workspaces. An administrator needs to configure an authentication provider (GitHub or Google OAuth, or email and password login).",
|
|
818
|
+
"patPlaceholder": "{provider} personal access token",
|
|
819
|
+
"signInWithPat": "Sign in with {provider} PAT"
|
|
818
820
|
},
|
|
819
821
|
"resetPassword": {
|
|
820
822
|
"title": "Reset password",
|
package/i18n/locales/es.json
CHANGED
|
@@ -387,13 +387,13 @@
|
|
|
387
387
|
},
|
|
388
388
|
"testConfig": {
|
|
389
389
|
"title": "Infraestructura de pruebas",
|
|
390
|
-
"
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
"
|
|
390
|
+
"provisionType": "Tipo de aprovisionamiento",
|
|
391
|
+
"provisionTypeHint": "Cómo este servicio levanta su entorno para el Tester. El espacio de trabajo configura cómo se gestiona cada tipo (el motor + la conexión).",
|
|
392
|
+
"provisionTypes": {
|
|
393
|
+
"infraless": "Sin infraestructura",
|
|
394
|
+
"docker-compose": "Docker Compose",
|
|
395
|
+
"kubernetes": "Kubernetes",
|
|
396
|
+
"custom": "Personalizado"
|
|
397
397
|
},
|
|
398
398
|
"composePath": "Ruta de docker-compose",
|
|
399
399
|
"browseRepo": "Explorar el repositorio en busca del archivo de compose",
|
|
@@ -403,8 +403,6 @@
|
|
|
403
403
|
"selected": "Seleccionado: {path}",
|
|
404
404
|
"noFileSelected": "Ningún archivo seleccionado.",
|
|
405
405
|
"useThisFile": "Usar este archivo",
|
|
406
|
-
"noInfra": "Sin dependencias de infraestructura (el Tester no levanta nada)",
|
|
407
|
-
"missingInfra": "Define una ruta de docker-compose o habilita sin dependencias de infraestructura; de lo contrario, un pipeline con un Tester no se iniciará.",
|
|
408
406
|
"provisioningTitle": "Aprovisionamiento del entorno efímero",
|
|
409
407
|
"provisioningHint": "Una indicación para aprovisionar el entorno de pruebas efímero de este servicio: en qué proveedor de nube desplegar y qué tamaño de instancia solicitar. Se ignora en las pruebas locales (docker-compose).",
|
|
410
408
|
"cloudProvider": "Proveedor de nube",
|
|
@@ -774,7 +772,11 @@
|
|
|
774
772
|
"sendResetLink": "Enviar enlace de restablecimiento",
|
|
775
773
|
"backToSignIn": "Volver al inicio de sesión",
|
|
776
774
|
"signInFailed": "Error al iniciar sesión. Revisa tus datos e inténtalo de nuevo.",
|
|
777
|
-
"genericError": "Algo salió mal. Inténtalo de nuevo."
|
|
775
|
+
"genericError": "Algo salió mal. Inténtalo de nuevo.",
|
|
776
|
+
"notConfiguredTitle": "La autenticación no está configurada",
|
|
777
|
+
"notConfiguredBody": "Este despliegue no tiene ningún método de inicio de sesión habilitado, por lo que no puedes iniciar sesión ni acceder a tus espacios de trabajo. Un administrador debe configurar un proveedor de autenticación (OAuth de GitHub o Google, o inicio de sesión con correo y contraseña).",
|
|
778
|
+
"patPlaceholder": "Token de acceso personal de {provider}",
|
|
779
|
+
"signInWithPat": "Iniciar sesión con un PAT de {provider}"
|
|
778
780
|
},
|
|
779
781
|
"resetPassword": {
|
|
780
782
|
"title": "Restablecer contraseña",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -387,13 +387,13 @@
|
|
|
387
387
|
},
|
|
388
388
|
"testConfig": {
|
|
389
389
|
"title": "Infrastructure de test",
|
|
390
|
-
"
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
"
|
|
390
|
+
"provisionType": "Type de provisionnement",
|
|
391
|
+
"provisionTypeHint": "Comment ce service met en place son environnement pour le Tester. L'espace de travail configure la gestion de chaque type (le moteur + la connexion).",
|
|
392
|
+
"provisionTypes": {
|
|
393
|
+
"infraless": "Aucune infrastructure",
|
|
394
|
+
"docker-compose": "Docker Compose",
|
|
395
|
+
"kubernetes": "Kubernetes",
|
|
396
|
+
"custom": "Personnalisé"
|
|
397
397
|
},
|
|
398
398
|
"composePath": "Chemin docker-compose",
|
|
399
399
|
"browseRepo": "Parcourir le dépôt pour trouver le fichier compose",
|
|
@@ -403,8 +403,6 @@
|
|
|
403
403
|
"selected": "Sélectionné : {path}",
|
|
404
404
|
"noFileSelected": "Aucun fichier sélectionné.",
|
|
405
405
|
"useThisFile": "Utiliser ce fichier",
|
|
406
|
-
"noInfra": "Aucune dépendance d'infrastructure (le Testeur ne met rien en place)",
|
|
407
|
-
"missingInfra": "Définissez un chemin docker-compose ou activez l'absence de dépendances d'infrastructure, sinon un pipeline avec un Testeur ne démarrera pas.",
|
|
408
406
|
"provisioningTitle": "Provisionnement de l'environnement éphémère",
|
|
409
407
|
"provisioningHint": "Une indication pour provisionner l'environnement de test éphémère de ce service : quel fournisseur cloud cibler et quelle taille d'instance demander. Ignoré pour les tests locaux (docker-compose).",
|
|
410
408
|
"cloudProvider": "Fournisseur cloud",
|
|
@@ -774,7 +772,11 @@
|
|
|
774
772
|
"sendResetLink": "Envoyer le lien de réinitialisation",
|
|
775
773
|
"backToSignIn": "Retour à la connexion",
|
|
776
774
|
"signInFailed": "Échec de la connexion. Vérifiez vos informations et réessayez.",
|
|
777
|
-
"genericError": "Une erreur s'est produite. Veuillez réessayer."
|
|
775
|
+
"genericError": "Une erreur s'est produite. Veuillez réessayer.",
|
|
776
|
+
"notConfiguredTitle": "L'authentification n'est pas configurée",
|
|
777
|
+
"notConfiguredBody": "Ce déploiement n'a aucune méthode de connexion activée, vous ne pouvez donc pas vous connecter ni accéder à vos espaces de travail. Un administrateur doit configurer un fournisseur d'authentification (OAuth GitHub ou Google, ou connexion par e-mail et mot de passe).",
|
|
778
|
+
"patPlaceholder": "Jeton d'accès personnel {provider}",
|
|
779
|
+
"signInWithPat": "Se connecter avec un PAT {provider}"
|
|
778
780
|
},
|
|
779
781
|
"resetPassword": {
|
|
780
782
|
"title": "Réinitialiser le mot de passe",
|
package/i18n/locales/he.json
CHANGED
|
@@ -387,13 +387,13 @@
|
|
|
387
387
|
},
|
|
388
388
|
"testConfig": {
|
|
389
389
|
"title": "תשתית בדיקות",
|
|
390
|
-
"
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
"
|
|
390
|
+
"provisionType": "סוג ההקצאה",
|
|
391
|
+
"provisionTypeHint": "כיצד שירות זה מקים את הסביבה שלו עבור ה-Tester. סביבת העבודה מגדירה כיצד מטופל כל סוג (המנוע + החיבור).",
|
|
392
|
+
"provisionTypes": {
|
|
393
|
+
"infraless": "ללא תשתית",
|
|
394
|
+
"docker-compose": "Docker Compose",
|
|
395
|
+
"kubernetes": "Kubernetes",
|
|
396
|
+
"custom": "מותאם אישית"
|
|
397
397
|
},
|
|
398
398
|
"composePath": "נתיב docker-compose",
|
|
399
399
|
"browseRepo": "עיין במאגר עבור קובץ ה-compose",
|
|
@@ -403,8 +403,6 @@
|
|
|
403
403
|
"selected": "נבחר: {path}",
|
|
404
404
|
"noFileSelected": "לא נבחר קובץ.",
|
|
405
405
|
"useThisFile": "השתמש בקובץ זה",
|
|
406
|
-
"noInfra": "אין תלויות תשתית (ה-Tester אינו מקים דבר)",
|
|
407
|
-
"missingInfra": "הגדר נתיב docker-compose או הפעל ללא תלויות תשתית, אחרת פייפליין עם Tester לא יתחיל.",
|
|
408
406
|
"provisioningTitle": "הקצאת סביבת בדיקות זמנית",
|
|
409
407
|
"provisioningHint": "רמז להקצאת סביבת הבדיקות הזמנית של שירות זה: לאיזה ספק ענן לפרוס וכמה גדול מופע לבקש. מתעלם בבדיקות מקומיות (docker-compose).",
|
|
410
408
|
"cloudProvider": "ספק ענן",
|
|
@@ -774,7 +772,11 @@
|
|
|
774
772
|
"sendResetLink": "שלח קישור איפוס",
|
|
775
773
|
"backToSignIn": "חזרה להתחברות",
|
|
776
774
|
"signInFailed": "ההתחברות נכשלה. בדוק את הפרטים שלך ונסה שוב.",
|
|
777
|
-
"genericError": "משהו השתבש. אנא נסה שוב."
|
|
775
|
+
"genericError": "משהו השתבש. אנא נסה שוב.",
|
|
776
|
+
"notConfiguredTitle": "האימות אינו מוגדר",
|
|
777
|
+
"notConfiguredBody": "בפריסה זו לא מופעלת אף שיטת התחברות, ולכן לא ניתן להתחבר או לגשת למרחבי העבודה שלך. מנהל המערכת צריך להגדיר ספק אימות (GitHub או Google OAuth, או התחברות עם אימייל וסיסמה).",
|
|
778
|
+
"patPlaceholder": "אסימון גישה אישי של {provider}",
|
|
779
|
+
"signInWithPat": "התחברות עם PAT של {provider}"
|
|
778
780
|
},
|
|
779
781
|
"resetPassword": {
|
|
780
782
|
"title": "אפס סיסמה",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -387,13 +387,13 @@
|
|
|
387
387
|
},
|
|
388
388
|
"testConfig": {
|
|
389
389
|
"title": "テストインフラ",
|
|
390
|
-
"
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
"
|
|
390
|
+
"provisionType": "プロビジョニングの種類",
|
|
391
|
+
"provisionTypeHint": "このサービスが Tester 用の環境をどのように立ち上げるか。各種類の扱い方(エンジンと接続)はワークスペースで設定します。",
|
|
392
|
+
"provisionTypes": {
|
|
393
|
+
"infraless": "インフラなし",
|
|
394
|
+
"docker-compose": "Docker Compose",
|
|
395
|
+
"kubernetes": "Kubernetes",
|
|
396
|
+
"custom": "カスタム"
|
|
397
397
|
},
|
|
398
398
|
"composePath": "docker-compose のパス",
|
|
399
399
|
"browseRepo": "リポジトリ内の compose ファイルを参照",
|
|
@@ -403,8 +403,6 @@
|
|
|
403
403
|
"selected": "選択中: {path}",
|
|
404
404
|
"noFileSelected": "ファイルが選択されていません。",
|
|
405
405
|
"useThisFile": "このファイルを使用",
|
|
406
|
-
"noInfra": "インフラ依存なし (Tester は何も立ち上げません)",
|
|
407
|
-
"missingInfra": "docker-compose のパスを設定するか、インフラ依存なしを有効にしてください。そうしないと Tester を含むパイプラインは開始しません。",
|
|
408
406
|
"provisioningTitle": "エフェメラルテスト環境のプロビジョニング",
|
|
409
407
|
"provisioningHint": "このサービスのエフェメラルテスト環境をプロビジョニングするためのヒント: どのクラウドプロバイダーにデプロイするか、どの程度の大きさのインスタンスを要求するか。ローカル (docker-compose) テストでは無視されます。",
|
|
410
408
|
"cloudProvider": "クラウドプロバイダー",
|
|
@@ -774,7 +772,11 @@
|
|
|
774
772
|
"sendResetLink": "リセットリンクを送信",
|
|
775
773
|
"backToSignIn": "サインインに戻る",
|
|
776
774
|
"signInFailed": "サインインに失敗しました。入力内容を確認して、もう一度お試しください。",
|
|
777
|
-
"genericError": "問題が発生しました。もう一度お試しください。"
|
|
775
|
+
"genericError": "問題が発生しました。もう一度お試しください。",
|
|
776
|
+
"notConfiguredTitle": "認証が設定されていません",
|
|
777
|
+
"notConfiguredBody": "このデプロイにはサインイン方法が有効になっていないため、サインインやワークスペースへのアクセスができません。管理者が認証プロバイダー(GitHub または Google の OAuth、あるいはメールアドレスとパスワードによるログイン)を設定する必要があります。",
|
|
778
|
+
"patPlaceholder": "{provider} のパーソナルアクセストークン",
|
|
779
|
+
"signInWithPat": "{provider} の PAT でサインイン"
|
|
778
780
|
},
|
|
779
781
|
"resetPassword": {
|
|
780
782
|
"title": "パスワードをリセット",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -387,13 +387,13 @@
|
|
|
387
387
|
},
|
|
388
388
|
"testConfig": {
|
|
389
389
|
"title": "Infrastruktura testowa",
|
|
390
|
-
"
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
"
|
|
390
|
+
"provisionType": "Typ provisioningu",
|
|
391
|
+
"provisionTypeHint": "Jak ta usługa uruchamia swoje środowisko dla Testera. Obszar roboczy konfiguruje sposób obsługi każdego typu (silnik + połączenie).",
|
|
392
|
+
"provisionTypes": {
|
|
393
|
+
"infraless": "Bez infrastruktury",
|
|
394
|
+
"docker-compose": "Docker Compose",
|
|
395
|
+
"kubernetes": "Kubernetes",
|
|
396
|
+
"custom": "Niestandardowy"
|
|
397
397
|
},
|
|
398
398
|
"composePath": "Ścieżka docker-compose",
|
|
399
399
|
"browseRepo": "Przeglądaj repozytorium w poszukiwaniu pliku compose",
|
|
@@ -403,8 +403,6 @@
|
|
|
403
403
|
"selected": "Wybrano: {path}",
|
|
404
404
|
"noFileSelected": "Nie wybrano pliku.",
|
|
405
405
|
"useThisFile": "Użyj tego pliku",
|
|
406
|
-
"noInfra": "Brak zależności infrastrukturalnych (Tester niczego nie stawia)",
|
|
407
|
-
"missingInfra": "Ustaw ścieżkę docker-compose lub włącz brak zależności infrastrukturalnych, w przeciwnym razie potok z Testerem się nie uruchomi.",
|
|
408
406
|
"provisioningTitle": "Udostępnianie środowiska efemerycznego",
|
|
409
407
|
"provisioningHint": "Wskazówka dotycząca udostępniania efemerycznego środowiska testowego tej usługi: do którego dostawcy chmury wdrożyć i jak duży zażądać instancji. Ignorowane przy testach lokalnych (docker-compose).",
|
|
410
408
|
"cloudProvider": "Dostawca chmury",
|
|
@@ -774,7 +772,11 @@
|
|
|
774
772
|
"sendResetLink": "Wyślij link resetujący",
|
|
775
773
|
"backToSignIn": "Powrót do logowania",
|
|
776
774
|
"signInFailed": "Logowanie nie powiodło się. Sprawdź swoje dane i spróbuj ponownie.",
|
|
777
|
-
"genericError": "Coś poszło nie tak. Spróbuj ponownie."
|
|
775
|
+
"genericError": "Coś poszło nie tak. Spróbuj ponownie.",
|
|
776
|
+
"notConfiguredTitle": "Uwierzytelnianie nie jest skonfigurowane",
|
|
777
|
+
"notConfiguredBody": "To wdrożenie nie ma włączonej żadnej metody logowania, więc nie możesz się zalogować ani uzyskać dostępu do swoich przestrzeni roboczych. Administrator musi skonfigurować dostawcę uwierzytelniania (OAuth GitHub lub Google albo logowanie e-mailem i hasłem).",
|
|
778
|
+
"patPlaceholder": "Osobisty token dostępu {provider}",
|
|
779
|
+
"signInWithPat": "Zaloguj się tokenem PAT {provider}"
|
|
778
780
|
},
|
|
779
781
|
"resetPassword": {
|
|
780
782
|
"title": "Zresetuj hasło",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -387,13 +387,13 @@
|
|
|
387
387
|
},
|
|
388
388
|
"testConfig": {
|
|
389
389
|
"title": "Test altyapısı",
|
|
390
|
-
"
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
"
|
|
390
|
+
"provisionType": "Sağlama türü",
|
|
391
|
+
"provisionTypeHint": "Bu hizmetin Tester için ortamını nasıl ayağa kaldırdığı. Her türün nasıl ele alınacağını (motor + bağlantı) çalışma alanı yapılandırır.",
|
|
392
|
+
"provisionTypes": {
|
|
393
|
+
"infraless": "Altyapısız",
|
|
394
|
+
"docker-compose": "Docker Compose",
|
|
395
|
+
"kubernetes": "Kubernetes",
|
|
396
|
+
"custom": "Özel"
|
|
397
397
|
},
|
|
398
398
|
"composePath": "docker-compose yolu",
|
|
399
399
|
"browseRepo": "compose dosyası için depoya göz at",
|
|
@@ -403,8 +403,6 @@
|
|
|
403
403
|
"selected": "Seçildi: {path}",
|
|
404
404
|
"noFileSelected": "Dosya seçilmedi.",
|
|
405
405
|
"useThisFile": "Bu dosyayı kullan",
|
|
406
|
-
"noInfra": "Altyapı bağımlılığı yok (Tester hiçbir şey ayağa kaldırmaz)",
|
|
407
|
-
"missingInfra": "Bir docker-compose yolu ayarlayın veya altyapı bağımlılığı yok seçeneğini etkinleştirin, aksi halde Tester içeren bir pipeline başlamaz.",
|
|
408
406
|
"provisioningTitle": "Geçici ortam sağlama",
|
|
409
407
|
"provisioningHint": "Bu servisin geçici test ortamını sağlamak için bir ipucu: hangi bulut sağlayıcısına dağıtılacağı ve ne kadar büyük bir örnek isteneceği. Yerel (docker-compose) testleri için yok sayılır.",
|
|
410
408
|
"cloudProvider": "Bulut sağlayıcı",
|
|
@@ -774,7 +772,11 @@
|
|
|
774
772
|
"sendResetLink": "Sıfırlama bağlantısı gönder",
|
|
775
773
|
"backToSignIn": "Oturum açmaya dön",
|
|
776
774
|
"signInFailed": "Oturum açma başarısız. Bilgilerinizi kontrol edip tekrar deneyin.",
|
|
777
|
-
"genericError": "Bir şeyler ters gitti. Lütfen tekrar deneyin."
|
|
775
|
+
"genericError": "Bir şeyler ters gitti. Lütfen tekrar deneyin.",
|
|
776
|
+
"notConfiguredTitle": "Kimlik doğrulama yapılandırılmamış",
|
|
777
|
+
"notConfiguredBody": "Bu dağıtımda etkin bir oturum açma yöntemi yok, bu nedenle oturum açamaz veya çalışma alanlarınıza erişemezsiniz. Bir yönetici, bir kimlik doğrulama sağlayıcısı (GitHub veya Google OAuth ya da e-posta ve parola ile oturum açma) yapılandırmalıdır.",
|
|
778
|
+
"patPlaceholder": "{provider} kişisel erişim belirteci",
|
|
779
|
+
"signInWithPat": "{provider} PAT ile oturum aç"
|
|
778
780
|
},
|
|
779
781
|
"resetPassword": {
|
|
780
782
|
"title": "Parolayı sıfırla",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -387,13 +387,13 @@
|
|
|
387
387
|
},
|
|
388
388
|
"testConfig": {
|
|
389
389
|
"title": "Тестова інфраструктура",
|
|
390
|
-
"
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
396
|
-
"
|
|
390
|
+
"provisionType": "Тип провіженінгу",
|
|
391
|
+
"provisionTypeHint": "Як ця служба піднімає своє середовище для Tester. Робочий простір налаштовує, як обробляється кожен тип (рушій + підключення).",
|
|
392
|
+
"provisionTypes": {
|
|
393
|
+
"infraless": "Без інфраструктури",
|
|
394
|
+
"docker-compose": "Docker Compose",
|
|
395
|
+
"kubernetes": "Kubernetes",
|
|
396
|
+
"custom": "Власний"
|
|
397
397
|
},
|
|
398
398
|
"composePath": "Шлях docker-compose",
|
|
399
399
|
"browseRepo": "Переглянути репозиторій у пошуках файлу compose",
|
|
@@ -403,8 +403,6 @@
|
|
|
403
403
|
"selected": "Вибрано: {path}",
|
|
404
404
|
"noFileSelected": "Файл не вибрано.",
|
|
405
405
|
"useThisFile": "Використати цей файл",
|
|
406
|
-
"noInfra": "Без інфраструктурних залежностей (Тестувальник нічого не піднімає)",
|
|
407
|
-
"missingInfra": "Вкажіть шлях docker-compose або увімкніть відсутність інфраструктурних залежностей, інакше конвеєр з Тестувальником не запуститься.",
|
|
408
406
|
"provisioningTitle": "Надання тимчасового середовища",
|
|
409
407
|
"provisioningHint": "Підказка для надання тимчасового тестового середовища цього сервісу: до якого хмарного провайдера розгортати та яку величину інстансу запитувати. Ігнорується для локального (docker-compose) тестування.",
|
|
410
408
|
"cloudProvider": "Хмарний провайдер",
|
|
@@ -774,7 +772,11 @@
|
|
|
774
772
|
"sendResetLink": "Надіслати посилання для скидання",
|
|
775
773
|
"backToSignIn": "Повернутися до входу",
|
|
776
774
|
"signInFailed": "Не вдалося увійти. Перевірте свої дані та спробуйте ще раз.",
|
|
777
|
-
"genericError": "Щось пішло не так. Спробуйте ще раз."
|
|
775
|
+
"genericError": "Щось пішло не так. Спробуйте ще раз.",
|
|
776
|
+
"notConfiguredTitle": "Автентифікацію не налаштовано",
|
|
777
|
+
"notConfiguredBody": "У цьому розгортанні не ввімкнено жодного способу входу, тому ви не можете увійти чи отримати доступ до своїх робочих просторів. Адміністратор має налаштувати постачальника автентифікації (OAuth GitHub або Google чи вхід за електронною поштою та паролем).",
|
|
778
|
+
"patPlaceholder": "Особистий токен доступу {provider}",
|
|
779
|
+
"signInWithPat": "Увійти за допомогою PAT {provider}"
|
|
778
780
|
},
|
|
779
781
|
"resetPassword": {
|
|
780
782
|
"title": "Скинути пароль",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.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.63.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@toad-contracts/testing": "0.3.2",
|