@cat-factory/app 0.229.0 → 0.230.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 +59 -0
- package/app/components/board/AddTaskModal.vue +1 -0
- package/app/components/board/nodes/TaskCard.vue +1 -0
- package/app/components/inputGate/InputGateNotice.vue +3 -0
- package/app/components/judge/JudgeResultView.vue +13 -0
- package/app/components/panels/inspector/TaskExecution.vue +1 -0
- package/app/components/requirements/RequirementsReviewWindow.vue +8 -0
- package/app/stores/auth/mothership.ts +27 -1
- package/app/stores/auth/session.ts +11 -0
- package/app/stores/auth/ssoError.spec.ts +64 -0
- package/app/stores/auth.ts +36 -3
- package/app/utils/sso.spec.ts +39 -0
- package/app/utils/sso.ts +41 -0
- package/i18n/locales/de.json +18 -1
- package/i18n/locales/en.json +24 -1
- package/i18n/locales/es.json +18 -1
- package/i18n/locales/fr.json +18 -1
- package/i18n/locales/he.json +18 -1
- package/i18n/locales/it.json +18 -1
- package/i18n/locales/ja.json +18 -1
- package/i18n/locales/pl.json +18 -1
- package/i18n/locales/tr.json +18 -1
- package/i18n/locales/uk.json +18 -1
- package/package.json +2 -2
|
@@ -4,6 +4,7 @@ import { apiErrorEnvelope } from '~/composables/api/errors'
|
|
|
4
4
|
import SecretInput from '~/components/common/SecretInput.vue'
|
|
5
5
|
import type { VcsProvider } from '~/types/domain'
|
|
6
6
|
import { VCS_PROVIDER_ICONS, VCS_PROVIDER_LABELS, VCS_PROVIDER_TOKEN_URLS } from '~/utils/vcs'
|
|
7
|
+
import { SSO_ERROR_MESSAGE_KEYS } from '~/utils/sso'
|
|
7
8
|
|
|
8
9
|
const auth = useAuthStore()
|
|
9
10
|
const { t } = useI18n()
|
|
@@ -124,6 +125,18 @@ const showOAuthDivider = computed(
|
|
|
124
125
|
() => auth.providers.password && (auth.providers.github || auth.providers.google),
|
|
125
126
|
)
|
|
126
127
|
|
|
128
|
+
// Enterprise SSO. Led with, above the consumer providers, because on a deployment that configures
|
|
129
|
+
// it that is the intended way in — a person arriving at an org's board should not have to find
|
|
130
|
+
// their company's button under two they must not use. The label is the operator's own wording
|
|
131
|
+
// (it names their IdP), so it is rendered verbatim rather than through the catalog.
|
|
132
|
+
const ssoLabel = computed(() => auth.sso?.label ?? '')
|
|
133
|
+
// Translated copy for a refused round-trip, keyed off the machine-readable reason the backend
|
|
134
|
+
// handed back. Each reason has its own wording because the remedies differ: a missing directory
|
|
135
|
+
// group is something the user takes to IT, a failed code exchange is the operator's own config.
|
|
136
|
+
const ssoErrorMessage = computed(() =>
|
|
137
|
+
auth.ssoError ? t(SSO_ERROR_MESSAGE_KEYS[auth.ssoError]) : null,
|
|
138
|
+
)
|
|
139
|
+
|
|
127
140
|
// Hosted (remote node) PAT login: the user pastes their OWN source-control PAT, which the
|
|
128
141
|
// server resolves to an account and holds to its login/org/domain allowlist. The available
|
|
129
142
|
// providers come from the server (`auth.patProviders`) — GitHub always, GitLab when configured,
|
|
@@ -157,6 +170,16 @@ async function submitRemotePat() {
|
|
|
157
170
|
}
|
|
158
171
|
}
|
|
159
172
|
|
|
173
|
+
// Only divide SSO from what follows when something actually follows it.
|
|
174
|
+
const showSsoDivider = computed(
|
|
175
|
+
() =>
|
|
176
|
+
auth.providers.sso &&
|
|
177
|
+
(auth.providers.github ||
|
|
178
|
+
auth.providers.google ||
|
|
179
|
+
auth.providers.password ||
|
|
180
|
+
remotePatProviders.value.length > 0),
|
|
181
|
+
)
|
|
182
|
+
|
|
160
183
|
// A remote deployment (node service / Worker) that advertises no sign-in method at all:
|
|
161
184
|
// no OAuth, no password, no PAT, and not local mode. The auth gate still routes here (a
|
|
162
185
|
// remote facade has no anonymous tier), so instead of a blank card we explain that
|
|
@@ -167,6 +190,7 @@ const noSignInMethod = computed(
|
|
|
167
190
|
!auth.providers.github &&
|
|
168
191
|
!auth.providers.google &&
|
|
169
192
|
!auth.providers.password &&
|
|
193
|
+
!auth.providers.sso &&
|
|
170
194
|
remotePatProviders.value.length === 0,
|
|
171
195
|
)
|
|
172
196
|
</script>
|
|
@@ -261,6 +285,41 @@ const noSignInMethod = computed(
|
|
|
261
285
|
<span class="h-px flex-1 bg-slate-800" />
|
|
262
286
|
</div>
|
|
263
287
|
|
|
288
|
+
<!-- A refused SSO round-trip: name the rule that refused, don't return the user to an
|
|
289
|
+
unchanged sign-in button. -->
|
|
290
|
+
<UAlert
|
|
291
|
+
v-if="ssoErrorMessage && mode !== 'forgot'"
|
|
292
|
+
class="mb-4"
|
|
293
|
+
color="error"
|
|
294
|
+
variant="subtle"
|
|
295
|
+
icon="i-lucide-shield-x"
|
|
296
|
+
:title="t('auth.sso.failedTitle')"
|
|
297
|
+
:description="ssoErrorMessage"
|
|
298
|
+
data-testid="sso-error"
|
|
299
|
+
/>
|
|
300
|
+
|
|
301
|
+
<!-- Enterprise SSO: the deployment's OWN identity provider, led with where configured. -->
|
|
302
|
+
<div v-if="auth.providers.sso && mode !== 'forgot'" class="mb-2 space-y-2">
|
|
303
|
+
<UButton
|
|
304
|
+
block
|
|
305
|
+
size="lg"
|
|
306
|
+
color="primary"
|
|
307
|
+
icon="i-lucide-building-2"
|
|
308
|
+
data-testid="sso-signin"
|
|
309
|
+
@click="auth.loginWithSso(invite)"
|
|
310
|
+
>
|
|
311
|
+
{{ t('auth.sso.continueWith', { provider: ssoLabel }) }}
|
|
312
|
+
</UButton>
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
<div
|
|
316
|
+
v-if="showSsoDivider && mode !== 'forgot'"
|
|
317
|
+
class="my-4 flex items-center gap-3 text-xs text-slate-500"
|
|
318
|
+
>
|
|
319
|
+
<span class="h-px flex-1 bg-slate-800" /> {{ t('auth.login.or') }}
|
|
320
|
+
<span class="h-px flex-1 bg-slate-800" />
|
|
321
|
+
</div>
|
|
322
|
+
|
|
264
323
|
<!-- OAuth providers -->
|
|
265
324
|
<div v-if="mode !== 'forgot'" class="space-y-2">
|
|
266
325
|
<UButton
|
|
@@ -406,6 +406,7 @@ function selectTask() {
|
|
|
406
406
|
:icon="!runnable ? 'i-lucide-lock' : sandboxed ? 'i-lucide-shield' : 'i-lucide-play'"
|
|
407
407
|
:loading="starting"
|
|
408
408
|
:disabled="!runnable || starting"
|
|
409
|
+
data-testid="task-start"
|
|
409
410
|
:title="
|
|
410
411
|
!runnable
|
|
411
412
|
? t('board.task.waitingOn', { deps: unmet.map((d) => d.title).join(', ') })
|
|
@@ -148,6 +148,9 @@ async function resolve(choice: 'recheck' | 'proceed') {
|
|
|
148
148
|
v-for="issue in issues"
|
|
149
149
|
:key="`${issue.code}:${issue.field?.key ?? ''}`"
|
|
150
150
|
class="flex items-start gap-2 text-xs"
|
|
151
|
+
data-testid="input-gate-issue"
|
|
152
|
+
:data-issue-code="issue.code"
|
|
153
|
+
:data-issue-severity="issue.severity"
|
|
151
154
|
>
|
|
152
155
|
<UBadge
|
|
153
156
|
:color="issue.severity === 'blocking' ? 'warning' : 'neutral'"
|
|
@@ -170,6 +170,17 @@ async function act(choice: 'proceed' | 'bounce' | 'stop') {
|
|
|
170
170
|
</span>
|
|
171
171
|
</div>
|
|
172
172
|
|
|
173
|
+
<!-- The rubric asked for a model this deployment cannot serve, so something else scored
|
|
174
|
+
the work. Only this case is shown: a pin that was honoured says nothing the model
|
|
175
|
+
name doesn't, and being overridden by the task's own choice is the normal outcome. -->
|
|
176
|
+
<p
|
|
177
|
+
v-if="judge.modelPin?.status === 'unavailable'"
|
|
178
|
+
class="mt-2 rounded-md border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-[12px] leading-relaxed text-amber-200"
|
|
179
|
+
data-testid="judge-model-pin"
|
|
180
|
+
>
|
|
181
|
+
{{ t('judge.modelPinUnavailable', { model: judge.modelPin.requested }) }}
|
|
182
|
+
</p>
|
|
183
|
+
|
|
173
184
|
<!-- Why the judge did nothing, when it did nothing. A skipped judge must never read
|
|
174
185
|
like a clean pass. -->
|
|
175
186
|
<p
|
|
@@ -288,6 +299,8 @@ async function act(choice: 'proceed' | 'bounce' | 'stop') {
|
|
|
288
299
|
v-for="round in rounds"
|
|
289
300
|
:key="round.round"
|
|
290
301
|
class="flex flex-wrap items-center gap-2 rounded-md border border-slate-800 bg-slate-950/40 px-3 py-1.5 text-[12px] text-slate-300"
|
|
302
|
+
data-testid="judge-round"
|
|
303
|
+
:data-round-disposition="round.disposition"
|
|
291
304
|
>
|
|
292
305
|
<span class="text-slate-500">{{ t('judge.round', { round: round.round }) }}</span>
|
|
293
306
|
<span class="font-medium text-slate-100">{{
|
|
@@ -373,6 +373,7 @@ async function mergePr() {
|
|
|
373
373
|
<button
|
|
374
374
|
type="button"
|
|
375
375
|
class="flex min-w-0 cursor-pointer items-center gap-2 text-start transition hover:text-white"
|
|
376
|
+
data-testid="run-step-open"
|
|
376
377
|
:title="
|
|
377
378
|
s.output
|
|
378
379
|
? t('inspector.execution.viewDetailsOutput')
|
|
@@ -708,6 +708,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
708
708
|
<div
|
|
709
709
|
v-if="incorporated"
|
|
710
710
|
class="mb-4 flex items-center gap-2 rounded-lg border border-emerald-900/60 bg-emerald-950/30 p-4 text-sm text-emerald-300"
|
|
711
|
+
data-testid="requirements-settled"
|
|
711
712
|
>
|
|
712
713
|
<UIcon name="i-lucide-circle-check" class="h-5 w-5 shrink-0" />
|
|
713
714
|
{{ t('requirements.settled') }}
|
|
@@ -760,6 +761,9 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
760
761
|
<div
|
|
761
762
|
class="rounded-lg border border-slate-800 bg-slate-900/60 p-3"
|
|
762
763
|
:class="{ 'opacity-60': item.status === 'dismissed' }"
|
|
764
|
+
data-testid="requirements-finding"
|
|
765
|
+
:data-finding-status="item.status"
|
|
766
|
+
:data-finding-severity="item.severity"
|
|
763
767
|
>
|
|
764
768
|
<div class="flex items-start gap-2">
|
|
765
769
|
<UIcon
|
|
@@ -831,6 +835,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
831
835
|
size="xs"
|
|
832
836
|
:icon="opt.icon"
|
|
833
837
|
:disabled="frozen"
|
|
838
|
+
:data-testid="`requirements-mode-${opt.mode}`"
|
|
834
839
|
@click="setMode(item, opt.mode)"
|
|
835
840
|
>
|
|
836
841
|
{{ t(opt.labelKey) }}
|
|
@@ -881,6 +886,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
881
886
|
class="mt-2 w-full"
|
|
882
887
|
:placeholder="t('requirements.answerPlaceholder')"
|
|
883
888
|
:disabled="frozen"
|
|
889
|
+
data-testid="requirements-answer"
|
|
884
890
|
@blur="persistDraft(item)"
|
|
885
891
|
/>
|
|
886
892
|
<p
|
|
@@ -1170,6 +1176,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
1170
1176
|
:loading="acting"
|
|
1171
1177
|
:disabled="!access.canExecuteRuns.value"
|
|
1172
1178
|
:title="access.canExecuteRuns.value ? undefined : t('access.noRunExecute')"
|
|
1179
|
+
data-testid="requirements-proceed"
|
|
1173
1180
|
@click="proceed"
|
|
1174
1181
|
>
|
|
1175
1182
|
{{ t('requirements.actions.proceedNothing') }}
|
|
@@ -1183,6 +1190,7 @@ async function resolveExceeded(choice: 'extra-round' | 'proceed' | 'stop-reset')
|
|
|
1183
1190
|
:loading="reworking"
|
|
1184
1191
|
:disabled="!canIncorporate || !access.canExecuteRuns.value"
|
|
1185
1192
|
:title="access.canExecuteRuns.value ? undefined : t('access.noRunExecute')"
|
|
1193
|
+
data-testid="requirements-incorporate"
|
|
1186
1194
|
@click="incorporate()"
|
|
1187
1195
|
>
|
|
1188
1196
|
{{ t('requirements.actions.incorporateAnswers') }}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Ref } from 'vue'
|
|
2
|
+
import { SSO_ERROR_FRAGMENT_KEY, parseSsoErrorReason } from '@cat-factory/contracts'
|
|
2
3
|
import type { LocalModeConfig } from '@cat-factory/contracts'
|
|
3
4
|
import type { AuthUser } from '~/types/domain'
|
|
5
|
+
import type { SsoLoginFailure } from '~/utils/sso'
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Shared reactive state + injected dependencies the auth-store redirect factory closes over.
|
|
@@ -13,6 +15,8 @@ export interface AuthRedirectContext {
|
|
|
13
15
|
token: Ref<string | null>
|
|
14
16
|
localMode: Ref<LocalModeConfig | null>
|
|
15
17
|
mothershipError: Ref<string | null>
|
|
18
|
+
/** Why the last enterprise-SSO round-trip produced no session, when one was refused. */
|
|
19
|
+
ssoError: Ref<SsoLoginFailure | null>
|
|
16
20
|
/** Apply a freshly-minted token + user (the session factory's setter). */
|
|
17
21
|
applySession: (result: { token: string; user: AuthUser }) => void
|
|
18
22
|
}
|
|
@@ -23,7 +27,7 @@ export interface AuthRedirectContext {
|
|
|
23
27
|
* mode — exchanging a returning MOTHERSHIP session for a local one.
|
|
24
28
|
*/
|
|
25
29
|
export function createAuthRedirectActions(ctx: AuthRedirectContext) {
|
|
26
|
-
const { api, token, localMode, mothershipError, applySession } = ctx
|
|
30
|
+
const { api, token, localMode, mothershipError, ssoError, applySession } = ctx
|
|
27
31
|
|
|
28
32
|
/** Pull a token handed back in the post-login URL fragment (#token=…). */
|
|
29
33
|
function consumeRedirectToken() {
|
|
@@ -35,6 +39,27 @@ export function createAuthRedirectActions(ctx: AuthRedirectContext) {
|
|
|
35
39
|
history.replaceState(null, '', window.location.pathname + window.location.search)
|
|
36
40
|
}
|
|
37
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Pull the reason a REFUSED enterprise-SSO round-trip handed back (`#sso_error=<reason>`), the
|
|
44
|
+
* sibling of the `#token=` a successful one sets.
|
|
45
|
+
*
|
|
46
|
+
* A fragment rather than a query for the same reason the token is: it never reaches a server log
|
|
47
|
+
* or a `Referer`, and the reason names the deployment's own admission rules. Stripped from the
|
|
48
|
+
* URL afterwards so a reload doesn't resurrect a stale failure.
|
|
49
|
+
*/
|
|
50
|
+
function consumeSsoError() {
|
|
51
|
+
if (typeof window === 'undefined') return
|
|
52
|
+
const match = new RegExp(`(?:^#|[#&])${SSO_ERROR_FRAGMENT_KEY}=([^&]+)`).exec(
|
|
53
|
+
window.location.hash,
|
|
54
|
+
)
|
|
55
|
+
if (!match) return
|
|
56
|
+
// An unrecognised value came from a newer backend than this build: reported as `unknown`
|
|
57
|
+
// rather than rendered raw, and never dropped — the user clicked a button and is owed an
|
|
58
|
+
// answer about why they are back here.
|
|
59
|
+
ssoError.value = parseSsoErrorReason(decodeURIComponent(match[1]!)) ?? 'unknown'
|
|
60
|
+
history.replaceState(null, '', window.location.pathname + window.location.search)
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
/**
|
|
39
64
|
* Mothership mode: when the mothership OAuth redirect returns here (flagged
|
|
40
65
|
* `?mothership_connect=1`), the URL fragment carries a MOTHERSHIP session — not a local one.
|
|
@@ -101,6 +126,7 @@ export function createAuthRedirectActions(ctx: AuthRedirectContext) {
|
|
|
101
126
|
|
|
102
127
|
return {
|
|
103
128
|
consumeRedirectToken,
|
|
129
|
+
consumeSsoError,
|
|
104
130
|
maybeConnectMothership,
|
|
105
131
|
signInViaMothership,
|
|
106
132
|
maybeAcceptInvite,
|
|
@@ -44,6 +44,16 @@ export function createAuthSessionActions(ctx: AuthSessionContext) {
|
|
|
44
44
|
window.location.href = `${apiBase}/auth/google/login?${redirectTarget(invite)}`
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Send the browser to the deployment's OWN identity provider (enterprise SSO), returning here
|
|
49
|
+
* after. One entry point whichever IdP is configured: the backend resolves the provider from its
|
|
50
|
+
* discovery document, so there is nothing per-vendor for the SPA to know.
|
|
51
|
+
*/
|
|
52
|
+
function loginWithSso(invite?: string) {
|
|
53
|
+
if (typeof window === 'undefined') return
|
|
54
|
+
window.location.href = `${apiBase}/auth/sso/login?${redirectTarget(invite)}`
|
|
55
|
+
}
|
|
56
|
+
|
|
47
57
|
/** Apply a freshly-minted token + user (from password signup/login). */
|
|
48
58
|
function applySession(result: { token: string; user: AuthUser }) {
|
|
49
59
|
token.value = result.token
|
|
@@ -107,6 +117,7 @@ export function createAuthSessionActions(ctx: AuthSessionContext) {
|
|
|
107
117
|
applySession,
|
|
108
118
|
login,
|
|
109
119
|
loginWithGoogle,
|
|
120
|
+
loginWithSso,
|
|
110
121
|
signup,
|
|
111
122
|
passwordLogin,
|
|
112
123
|
patLogin,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ref } from 'vue'
|
|
2
|
+
import { beforeEach, describe, expect, it } from 'vitest'
|
|
3
|
+
import { createAuthRedirectActions } from './mothership'
|
|
4
|
+
import type { SsoLoginFailure } from '~/utils/sso'
|
|
5
|
+
|
|
6
|
+
// The other half of the SSO refusal contract: the backend lands the browser here with a
|
|
7
|
+
// machine-readable reason in the fragment, and this is what turns it into state the login screen
|
|
8
|
+
// renders. Worth pinning because the failure mode is silent — a reason the SPA drops leaves the
|
|
9
|
+
// user back on the same sign-in button with no explanation for the click that just failed.
|
|
10
|
+
|
|
11
|
+
/** Point `window.location` + `history` at a URL the consumer can read and rewrite. */
|
|
12
|
+
function setUrl(path: string): void {
|
|
13
|
+
history.replaceState(null, '', path)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function actions() {
|
|
17
|
+
const ssoError = ref<SsoLoginFailure | null>(null)
|
|
18
|
+
const factory = createAuthRedirectActions({
|
|
19
|
+
api: {} as never,
|
|
20
|
+
token: ref<string | null>(null),
|
|
21
|
+
localMode: ref(null),
|
|
22
|
+
mothershipError: ref<string | null>(null),
|
|
23
|
+
ssoError,
|
|
24
|
+
applySession: () => {},
|
|
25
|
+
})
|
|
26
|
+
return { ...factory, ssoError }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('consumeSsoError', () => {
|
|
30
|
+
beforeEach(() => setUrl('/'))
|
|
31
|
+
|
|
32
|
+
it('reads a known reason off the fragment', () => {
|
|
33
|
+
setUrl('/#sso_error=group_required')
|
|
34
|
+
const a = actions()
|
|
35
|
+
a.consumeSsoError()
|
|
36
|
+
expect(a.ssoError.value).toBe('group_required')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('strips the fragment so a reload does not resurrect a stale failure', () => {
|
|
40
|
+
setUrl('/board?ws=ws_1#sso_error=state_invalid')
|
|
41
|
+
actions().consumeSsoError()
|
|
42
|
+
expect(window.location.hash).toBe('')
|
|
43
|
+
// The rest of the URL is left alone.
|
|
44
|
+
expect(window.location.pathname + window.location.search).toBe('/board?ws=ws_1')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('reports an unrecognised reason as `unknown` rather than dropping it', () => {
|
|
48
|
+
// A reason from a NEWER backend than this build. Rendering the raw wire token to a user is
|
|
49
|
+
// wrong; showing nothing after a failed sign-in is worse.
|
|
50
|
+
setUrl('/#sso_error=reason_from_the_future')
|
|
51
|
+
const a = actions()
|
|
52
|
+
a.consumeSsoError()
|
|
53
|
+
expect(a.ssoError.value).toBe('unknown')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('leaves the state untouched when the fragment carries no SSO error', () => {
|
|
57
|
+
setUrl('/#token=abc')
|
|
58
|
+
const a = actions()
|
|
59
|
+
a.consumeSsoError()
|
|
60
|
+
expect(a.ssoError.value).toBeNull()
|
|
61
|
+
// The session token is another consumer's to read, so the fragment must survive.
|
|
62
|
+
expect(window.location.hash).toBe('#token=abc')
|
|
63
|
+
})
|
|
64
|
+
})
|
package/app/stores/auth.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
BackendMisconfigured,
|
|
3
3
|
InfrastructureCapabilities,
|
|
4
4
|
LocalModeConfig,
|
|
5
|
+
SsoConfigView,
|
|
5
6
|
} from '@cat-factory/contracts'
|
|
6
7
|
import { defineStore } from 'pinia'
|
|
7
8
|
import { computed, ref } from 'vue'
|
|
@@ -9,6 +10,7 @@ import type { AuthUser } from '~/types/domain'
|
|
|
9
10
|
import { retryWhileBackendUnreachable } from '~/utils/backendReady'
|
|
10
11
|
import { createAuthSessionActions } from '~/stores/auth/session'
|
|
11
12
|
import { createAuthRedirectActions } from '~/stores/auth/mothership'
|
|
13
|
+
import type { SsoLoginFailure } from '~/utils/sso'
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* "Login with GitHub" session state. The backend mints a signed session token
|
|
@@ -31,7 +33,20 @@ export const useAuthStore = defineStore(
|
|
|
31
33
|
/** Whether the backend requires authentication. */
|
|
32
34
|
const required = ref(false)
|
|
33
35
|
/** Which login providers the backend offers (drives the login UI). */
|
|
34
|
-
const providers = ref({ github: false, password: false, google: false })
|
|
36
|
+
const providers = ref({ github: false, password: false, google: false, sso: false })
|
|
37
|
+
/**
|
|
38
|
+
* Presentation for the deployment's OWN identity provider (enterprise SSO) — its
|
|
39
|
+
* operator-supplied label and protocol. Null unless `providers.sso` is set. The label names
|
|
40
|
+
* the operator's IdP, so it is the one piece of login copy the SPA renders verbatim rather
|
|
41
|
+
* than through the catalog.
|
|
42
|
+
*/
|
|
43
|
+
const sso = ref<SsoConfigView | null>(null)
|
|
44
|
+
/**
|
|
45
|
+
* Why the last enterprise-SSO sign-in produced no session, when one was refused. Captured
|
|
46
|
+
* from the `#sso_error=` fragment on boot so the login screen can name the rule that refused
|
|
47
|
+
* instead of returning the user to an unchanged sign-in button.
|
|
48
|
+
*/
|
|
49
|
+
const ssoError = ref<SsoLoginFailure | null>(null)
|
|
35
50
|
/**
|
|
36
51
|
* Source-control providers a HOSTED facade (remote node) accepts a user-supplied PAT for.
|
|
37
52
|
* Drives the login screen's "sign in with a PAT" option on non-local deployments. Empty on
|
|
@@ -134,14 +149,29 @@ export const useAuthStore = defineStore(
|
|
|
134
149
|
user,
|
|
135
150
|
autoLoginProvider,
|
|
136
151
|
})
|
|
137
|
-
const {
|
|
138
|
-
|
|
152
|
+
const {
|
|
153
|
+
consumeRedirectToken,
|
|
154
|
+
consumeSsoError,
|
|
155
|
+
maybeConnectMothership,
|
|
156
|
+
signInViaMothership,
|
|
157
|
+
maybeAcceptInvite,
|
|
158
|
+
} = createAuthRedirectActions({
|
|
159
|
+
api,
|
|
160
|
+
token,
|
|
161
|
+
localMode,
|
|
162
|
+
mothershipError,
|
|
163
|
+
ssoError,
|
|
164
|
+
applySession,
|
|
165
|
+
})
|
|
139
166
|
|
|
140
167
|
/** Resolve auth state: capture any redirect token, then check the backend. */
|
|
141
168
|
async function bootstrap() {
|
|
142
169
|
// A returning mothership-connect redirect is handled first (it carries a mothership session,
|
|
143
170
|
// which must be exchanged — not stored as a local token by `consumeRedirectToken`).
|
|
144
171
|
if (!(await maybeConnectMothership())) consumeRedirectToken()
|
|
172
|
+
// A refused SSO round-trip returns a reason instead of a token, and it must be read BEFORE
|
|
173
|
+
// the config call: the login screen renders from the same settled state either way.
|
|
174
|
+
consumeSsoError()
|
|
145
175
|
try {
|
|
146
176
|
// Tolerate a cold-start race: when the SPA and backend boot together, this first call
|
|
147
177
|
// can beat the backend's listener by a second or two. Retry a not-listening-yet socket
|
|
@@ -149,6 +179,7 @@ export const useAuthStore = defineStore(
|
|
|
149
179
|
const config = await retryWhileBackendUnreachable(() => api.getAuthConfig())
|
|
150
180
|
required.value = config.enabled
|
|
151
181
|
if (config.providers) providers.value = config.providers
|
|
182
|
+
sso.value = config.sso ?? null
|
|
152
183
|
patProviders.value = config.patLogin?.providers ?? []
|
|
153
184
|
testingNoAuth.value = config.testingNoAuth ?? false
|
|
154
185
|
localMode.value = config.localMode ?? null
|
|
@@ -211,6 +242,8 @@ export const useAuthStore = defineStore(
|
|
|
211
242
|
user,
|
|
212
243
|
required,
|
|
213
244
|
providers,
|
|
245
|
+
sso,
|
|
246
|
+
ssoError,
|
|
214
247
|
patProviders,
|
|
215
248
|
testingNoAuth,
|
|
216
249
|
localMode,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { SSO_ERROR_REASONS } from '@cat-factory/contracts'
|
|
3
|
+
import en from '../../i18n/locales/en.json'
|
|
4
|
+
import { SSO_ERROR_MESSAGE_KEYS } from './sso'
|
|
5
|
+
|
|
6
|
+
// The copy side of the SSO refusal contract. The `Record<SsoLoginFailure, string>` type already
|
|
7
|
+
// forces every reason to name a key, but a key is only a STRING: nothing there checks it exists in
|
|
8
|
+
// the catalog, and a typo renders the raw key path to a user who just failed to sign in. That is
|
|
9
|
+
// the assertion the type and the locale-parity guard structurally cannot make between them (parity
|
|
10
|
+
// compares locales to each other, so a key missing from ALL of them is parity-clean).
|
|
11
|
+
|
|
12
|
+
/** Resolve a dotted i18n key against the catalog, or undefined when it names nothing. */
|
|
13
|
+
function lookup(key: string): unknown {
|
|
14
|
+
return key
|
|
15
|
+
.split('.')
|
|
16
|
+
.reduce<unknown>(
|
|
17
|
+
(node, part) =>
|
|
18
|
+
node && typeof node === 'object' ? (node as Record<string, unknown>)[part] : undefined,
|
|
19
|
+
en,
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('SSO_ERROR_MESSAGE_KEYS', () => {
|
|
24
|
+
it('covers every wire reason EXACTLY once, plus the newer-backend fallback', () => {
|
|
25
|
+
// Derived from the vocabulary the backend actually ships rather than a pinned count, so a
|
|
26
|
+
// reason added there fails here until it has wording instead of silently rendering nothing.
|
|
27
|
+
expect(Object.keys(SSO_ERROR_MESSAGE_KEYS).sort()).toEqual(
|
|
28
|
+
[...SSO_ERROR_REASONS, 'unknown'].sort(),
|
|
29
|
+
)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('names a key that resolves to real copy for every reason', () => {
|
|
33
|
+
for (const [reason, key] of Object.entries(SSO_ERROR_MESSAGE_KEYS)) {
|
|
34
|
+
const copy = lookup(key)
|
|
35
|
+
expect(typeof copy, `${reason} -> ${key}`).toBe('string')
|
|
36
|
+
expect(copy as string, `${reason} -> ${key}`).not.toBe('')
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
})
|
package/app/utils/sso.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type SsoErrorReason } from '@cat-factory/contracts'
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Enterprise SSO presentation, in ONE place — the same convention as `utils/vcs.ts`.
|
|
5
|
+
//
|
|
6
|
+
// The backend does not localize prose (CLAUDE.md's i18n rule): a refused SSO round-trip lands
|
|
7
|
+
// back here with a machine-readable reason, and this module is where each reason becomes copy.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A failed SSO sign-in as the SPA models it: one of the wire reasons, or `unknown`.
|
|
12
|
+
*
|
|
13
|
+
* `unknown` is not a wire value — it is what a reason from a NEWER backend than this build reads
|
|
14
|
+
* as. Without it the alternatives are rendering the raw wire token to a user or showing nothing
|
|
15
|
+
* at all after a failed sign-in, and the second is the worse one: the user clicked the button and
|
|
16
|
+
* came back to the same button.
|
|
17
|
+
*/
|
|
18
|
+
export type SsoLoginFailure = SsoErrorReason | 'unknown'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The copy key per failure. An exhaustive `Record`, so a member added to the wire vocabulary
|
|
22
|
+
* fails this typecheck until it has wording — the drift guard the `UNAVAILABLE_REASONS` pattern
|
|
23
|
+
* establishes.
|
|
24
|
+
*
|
|
25
|
+
* The wording split matters more than it looks: `group_required` and `domain_not_allowed` are
|
|
26
|
+
* things the USER takes to their IT team, while `exchange_failed` and `token_invalid` are
|
|
27
|
+
* OPERATOR faults in the deployment's own configuration. One "sign-in failed" for all four sends
|
|
28
|
+
* every user to the wrong place.
|
|
29
|
+
*/
|
|
30
|
+
export const SSO_ERROR_MESSAGE_KEYS: Record<SsoLoginFailure, string> = {
|
|
31
|
+
state_invalid: 'auth.sso.errors.stateInvalid',
|
|
32
|
+
provider_denied: 'auth.sso.errors.providerDenied',
|
|
33
|
+
exchange_failed: 'auth.sso.errors.exchangeFailed',
|
|
34
|
+
token_invalid: 'auth.sso.errors.tokenInvalid',
|
|
35
|
+
subject_missing: 'auth.sso.errors.subjectMissing',
|
|
36
|
+
group_required: 'auth.sso.errors.groupRequired',
|
|
37
|
+
domain_not_allowed: 'auth.sso.errors.domainNotAllowed',
|
|
38
|
+
email_required: 'auth.sso.errors.emailRequired',
|
|
39
|
+
provider_unreachable: 'auth.sso.errors.providerUnreachable',
|
|
40
|
+
unknown: 'auth.sso.errors.unknown',
|
|
41
|
+
}
|
package/i18n/locales/de.json
CHANGED
|
@@ -3675,10 +3675,26 @@
|
|
|
3675
3675
|
"signInFailed": "Anmeldung fehlgeschlagen. Prüfen Sie Ihre Angaben und versuchen Sie es erneut.",
|
|
3676
3676
|
"genericError": "Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut.",
|
|
3677
3677
|
"notConfiguredTitle": "Authentifizierung ist nicht konfiguriert",
|
|
3678
|
-
"notConfiguredBody": "Für dieses Deployment ist keine Anmeldemethode aktiviert, daher können Sie sich nicht anmelden oder auf Ihre Workspaces zugreifen. Ein Administrator muss einen Authentifizierungs-Provider konfigurieren (GitHub- oder Google-OAuth oder E-Mail-/Passwort-Anmeldung).",
|
|
3678
|
+
"notConfiguredBody": "Für dieses Deployment ist keine Anmeldemethode aktiviert, daher können Sie sich nicht anmelden oder auf Ihre Workspaces zugreifen. Ein Administrator muss einen Authentifizierungs-Provider konfigurieren (Single Sign-on über den Identitätsprovider Ihrer Organisation, GitHub- oder Google-OAuth oder E-Mail-/Passwort-Anmeldung).",
|
|
3679
3679
|
"patPlaceholder": "{provider} Personal Access Token",
|
|
3680
3680
|
"signInWithPat": "Mit {provider}-PAT anmelden"
|
|
3681
3681
|
},
|
|
3682
|
+
"sso": {
|
|
3683
|
+
"continueWith": "Mit {provider} fortfahren",
|
|
3684
|
+
"failedTitle": "Single Sign-on wurde nicht abgeschlossen",
|
|
3685
|
+
"errors": {
|
|
3686
|
+
"stateInvalid": "Dieser Anmeldeversuch ist abgelaufen oder wurde bereits verwendet. Beginnen Sie erneut auf dieser Seite.",
|
|
3687
|
+
"providerDenied": "Ihr Identitätsprovider hat die Anmeldung abgelehnt. Falls Sie sie nicht selbst abgebrochen haben, fragen Sie Ihre IT-Abteilung, ob diese Anwendung Ihnen zugewiesen ist.",
|
|
3688
|
+
"exchangeFailed": "Dieses Deployment konnte den Austausch mit Ihrem Identitätsprovider nicht abschließen. Ein Administrator muss das Single-Sign-on-Client-Secret und die Redirect-URL prüfen.",
|
|
3689
|
+
"tokenInvalid": "Die Antwort Ihres Identitätsproviders konnte nicht verifiziert werden. Ein Administrator muss die Single-Sign-on-Konfiguration dieses Deployments prüfen.",
|
|
3690
|
+
"subjectMissing": "Ihr Identitätsprovider hat keine Benutzerkennung zurückgegeben, daher konnte kein Konto ermittelt werden. Ein Administrator muss prüfen, welche Claims freigegeben werden.",
|
|
3691
|
+
"groupRequired": "Die Anmeldung hat funktioniert, aber Sie sind in keiner Verzeichnisgruppe, die dieses Deployment nutzen darf. Bitten Sie Ihre IT-Abteilung, Sie hinzuzufügen.",
|
|
3692
|
+
"domainNotAllowed": "Ihre E-Mail-Domain darf sich bei diesem Deployment nicht anmelden. Fragen Sie Ihre IT-Abteilung, welches Konto Sie verwenden sollen.",
|
|
3693
|
+
"emailRequired": "Dieses Deployment beschränkt die Anmeldung auf bestimmte E-Mail-Domains, aber Ihr Identitätsprovider hat keine verifizierte E-Mail-Adresse freigegeben. Ein Administrator muss den E-Mail-Claim aktivieren.",
|
|
3694
|
+
"providerUnreachable": "Ihr Identitätsprovider hat beim Abschluss der Anmeldung nicht geantwortet, möglicherweise ist er oder die Verbindung zu ihm gestört. Versuchen Sie es in einem Moment erneut und informieren Sie einen Administrator, falls es weiterhin auftritt.",
|
|
3695
|
+
"unknown": "Single Sign-on ist aus einem Grund fehlgeschlagen, den diese Version nicht kennt. Versuchen Sie es erneut und informieren Sie einen Administrator, falls es weiterhin auftritt."
|
|
3696
|
+
}
|
|
3697
|
+
},
|
|
3682
3698
|
"resetPassword": {
|
|
3683
3699
|
"title": "Passwort zurücksetzen",
|
|
3684
3700
|
"subtitle": "Wählen Sie ein neues Passwort für Ihren Account.",
|
|
@@ -5551,6 +5567,7 @@
|
|
|
5551
5567
|
"threshold": "Schwellenwert {threshold}",
|
|
5552
5568
|
"thresholdHint": "Der Wert, den dieser Schritt erreichen musste, aus der Merge-Policy der Aufgabe. Darunter schickt der Judge die Arbeit mit seinen Befunden als Nacharbeit an den erzeugenden Schritt zurück oder parkt den Lauf für Sie, wenn kein Versuchsbudget mehr übrig ist.",
|
|
5553
5569
|
"rubricOverridden": "Raster des Arbeitsbereichs",
|
|
5570
|
+
"modelPinUnavailable": "Diese Prüfung wurde für das Modell {model} geschrieben, das diese Installation nicht ausführen kann. Die Arbeit wurde daher von einem anderen Modell bewertet.",
|
|
5554
5571
|
"reworkRounds": "Überarbeitung {spent}/{budget}",
|
|
5555
5572
|
"findingsHeading": "Was das Bewertungsraster beanstandet hat",
|
|
5556
5573
|
"roundsHeading": "Prüfrunden",
|
package/i18n/locales/en.json
CHANGED
|
@@ -1918,10 +1918,32 @@
|
|
|
1918
1918
|
"signInFailed": "Sign-in failed. Check your details and try again.",
|
|
1919
1919
|
"genericError": "Something went wrong. Please try again.",
|
|
1920
1920
|
"notConfiguredTitle": "Authentication isn't configured",
|
|
1921
|
-
"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).",
|
|
1921
|
+
"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 (single sign-on through your organization's identity provider, GitHub or Google OAuth, or email and password login).",
|
|
1922
1922
|
"patPlaceholder": "{provider} personal access token",
|
|
1923
1923
|
"signInWithPat": "Sign in with {provider} PAT"
|
|
1924
1924
|
},
|
|
1925
|
+
"sso": {
|
|
1926
|
+
"continueWith": "Continue with {provider}",
|
|
1927
|
+
"@continueWith": {
|
|
1928
|
+
"description": "Sign-in button for the deployment's own identity provider (enterprise SSO). {provider} is the operator-configured label (AUTH_SSO_LABEL) naming their IdP, e.g. \"Acme SSO\" or \"Okta\" - it is a proper noun supplied at runtime, so never translate the interpolated value."
|
|
1929
|
+
},
|
|
1930
|
+
"failedTitle": "Single sign-on didn't complete",
|
|
1931
|
+
"@failedTitle": {
|
|
1932
|
+
"description": "Title of the alert shown when an enterprise single-sign-on round-trip came back without a session. The per-reason detail underneath is the matching `errors.*` message."
|
|
1933
|
+
},
|
|
1934
|
+
"errors": {
|
|
1935
|
+
"stateInvalid": "That sign-in attempt has expired or was already used. Start again from this page.",
|
|
1936
|
+
"providerDenied": "Your identity provider refused the sign-in. If you didn't cancel it yourself, ask your IT team whether this application is assigned to you.",
|
|
1937
|
+
"exchangeFailed": "This deployment couldn't complete the exchange with your identity provider. An administrator needs to check its single sign-on client secret and redirect URL.",
|
|
1938
|
+
"tokenInvalid": "The response from your identity provider couldn't be verified. An administrator needs to check this deployment's single sign-on configuration.",
|
|
1939
|
+
"subjectMissing": "Your identity provider didn't return a user identifier, so no account could be resolved. An administrator needs to check which claims it releases.",
|
|
1940
|
+
"groupRequired": "Your sign-in worked, but you aren't in a directory group that's allowed to use this deployment. Ask your IT team to add you.",
|
|
1941
|
+
"domainNotAllowed": "Your email domain isn't allowed to sign in to this deployment. Ask your IT team which account to use.",
|
|
1942
|
+
"emailRequired": "This deployment restricts sign-in by email domain, but your identity provider didn't release a verified email address. An administrator needs to enable the email claim.",
|
|
1943
|
+
"providerUnreachable": "Your identity provider didn't respond while your sign-in was being completed, so it or the network to it may be down. Try again in a moment, and tell an administrator if it keeps happening.",
|
|
1944
|
+
"unknown": "Single sign-on failed for a reason this version doesn't recognise. Try again, and tell an administrator if it keeps happening."
|
|
1945
|
+
}
|
|
1946
|
+
},
|
|
1925
1947
|
"resetPassword": {
|
|
1926
1948
|
"title": "Reset password",
|
|
1927
1949
|
"subtitle": "Choose a new password for your account.",
|
|
@@ -4910,6 +4932,7 @@
|
|
|
4910
4932
|
"threshold": "threshold {threshold}",
|
|
4911
4933
|
"thresholdHint": "The score this step had to reach, taken from the task's merge policy. Below it the judge sends the work back to the step that produced it, with its findings as rework, or parks the run for you when no attempt budget is left.",
|
|
4912
4934
|
"rubricOverridden": "workspace rubric",
|
|
4935
|
+
"modelPinUnavailable": "This review was written for the {model} model, which this deployment cannot run, so another model scored the work.",
|
|
4913
4936
|
"reworkRounds": "rework {spent}/{budget}",
|
|
4914
4937
|
"findingsHeading": "What the rubric flagged",
|
|
4915
4938
|
"roundsHeading": "Review rounds",
|
package/i18n/locales/es.json
CHANGED
|
@@ -1820,10 +1820,26 @@
|
|
|
1820
1820
|
"signInFailed": "Error al iniciar sesión. Revisa tus datos e inténtalo de nuevo.",
|
|
1821
1821
|
"genericError": "Algo salió mal. Inténtalo de nuevo.",
|
|
1822
1822
|
"notConfiguredTitle": "La autenticación no está configurada",
|
|
1823
|
-
"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).",
|
|
1823
|
+
"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 (inicio de sesión único mediante el proveedor de identidad de tu organización, OAuth de GitHub o Google, o inicio de sesión con correo y contraseña).",
|
|
1824
1824
|
"patPlaceholder": "Token de acceso personal de {provider}",
|
|
1825
1825
|
"signInWithPat": "Iniciar sesión con un PAT de {provider}"
|
|
1826
1826
|
},
|
|
1827
|
+
"sso": {
|
|
1828
|
+
"continueWith": "Continuar con {provider}",
|
|
1829
|
+
"failedTitle": "El inicio de sesión único no se completó",
|
|
1830
|
+
"errors": {
|
|
1831
|
+
"stateInvalid": "Ese intento de inicio de sesión ha caducado o ya se usó. Vuelve a empezar desde esta página.",
|
|
1832
|
+
"providerDenied": "Tu proveedor de identidad rechazó el inicio de sesión. Si no lo cancelaste tú, pregunta a tu equipo de TI si esta aplicación está asignada a ti.",
|
|
1833
|
+
"exchangeFailed": "Este despliegue no pudo completar el intercambio con tu proveedor de identidad. Un administrador debe revisar el secreto de cliente y la URL de redirección del inicio de sesión único.",
|
|
1834
|
+
"tokenInvalid": "No se pudo verificar la respuesta de tu proveedor de identidad. Un administrador debe revisar la configuración de inicio de sesión único de este despliegue.",
|
|
1835
|
+
"subjectMissing": "Tu proveedor de identidad no devolvió un identificador de usuario, por lo que no se pudo resolver ninguna cuenta. Un administrador debe revisar qué claims publica.",
|
|
1836
|
+
"groupRequired": "Te has autenticado correctamente, pero no perteneces a ningún grupo del directorio autorizado a usar este despliegue. Pide a tu equipo de TI que te añada.",
|
|
1837
|
+
"domainNotAllowed": "Tu dominio de correo no tiene permitido iniciar sesión en este despliegue. Pregunta a tu equipo de TI qué cuenta debes usar.",
|
|
1838
|
+
"emailRequired": "Este despliegue restringe el inicio de sesión por dominio de correo, pero tu proveedor de identidad no publicó una dirección de correo verificada. Un administrador debe habilitar el claim de correo.",
|
|
1839
|
+
"providerUnreachable": "Tu proveedor de identidad no respondió mientras se completaba el inicio de sesión, por lo que puede estar caído o sin conexión. Vuelve a intentarlo en un momento y avisa a un administrador si sigue ocurriendo.",
|
|
1840
|
+
"unknown": "El inicio de sesión único falló por un motivo que esta versión no reconoce. Inténtalo de nuevo y avisa a un administrador si sigue ocurriendo."
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1827
1843
|
"resetPassword": {
|
|
1828
1844
|
"title": "Restablecer contraseña",
|
|
1829
1845
|
"subtitle": "Elige una nueva contraseña para tu cuenta.",
|
|
@@ -4693,6 +4709,7 @@
|
|
|
4693
4709
|
"threshold": "umbral {threshold}",
|
|
4694
4710
|
"thresholdHint": "La puntuacion que este paso tenia que alcanzar, tomada de la politica de fusion de la tarea. Por debajo, el juez devuelve el trabajo al paso que lo produjo con sus hallazgos como retrabajo, o aparca la ejecucion para ti cuando ya no queda presupuesto de intentos.",
|
|
4695
4711
|
"rubricOverridden": "rúbrica del espacio de trabajo",
|
|
4712
|
+
"modelPinUnavailable": "Esta revisión se escribió para el modelo {model}, que esta instalación no puede ejecutar, así que otro modelo puntuó el trabajo.",
|
|
4696
4713
|
"reworkRounds": "revisión {spent}/{budget}",
|
|
4697
4714
|
"findingsHeading": "Lo que señaló la rúbrica",
|
|
4698
4715
|
"roundsHeading": "Rondas de revisión",
|
package/i18n/locales/fr.json
CHANGED
|
@@ -1820,10 +1820,26 @@
|
|
|
1820
1820
|
"signInFailed": "Échec de la connexion. Vérifiez vos informations et réessayez.",
|
|
1821
1821
|
"genericError": "Une erreur s'est produite. Veuillez réessayer.",
|
|
1822
1822
|
"notConfiguredTitle": "L'authentification n'est pas configurée",
|
|
1823
|
-
"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).",
|
|
1823
|
+
"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 (authentification unique via le fournisseur d'identité de votre organisation, OAuth GitHub ou Google, ou connexion par e-mail et mot de passe).",
|
|
1824
1824
|
"patPlaceholder": "Jeton d'accès personnel {provider}",
|
|
1825
1825
|
"signInWithPat": "Se connecter avec un PAT {provider}"
|
|
1826
1826
|
},
|
|
1827
|
+
"sso": {
|
|
1828
|
+
"continueWith": "Continuer avec {provider}",
|
|
1829
|
+
"failedTitle": "L'authentification unique n'a pas abouti",
|
|
1830
|
+
"errors": {
|
|
1831
|
+
"stateInvalid": "Cette tentative de connexion a expiré ou a déjà été utilisée. Recommencez depuis cette page.",
|
|
1832
|
+
"providerDenied": "Votre fournisseur d'identité a refusé la connexion. Si vous ne l'avez pas annulée vous-même, demandez à votre service informatique si cette application vous est attribuée.",
|
|
1833
|
+
"exchangeFailed": "Ce déploiement n'a pas pu finaliser l'échange avec votre fournisseur d'identité. Un administrateur doit vérifier le secret client et l'URL de redirection de l'authentification unique.",
|
|
1834
|
+
"tokenInvalid": "La réponse de votre fournisseur d'identité n'a pas pu être vérifiée. Un administrateur doit vérifier la configuration de l'authentification unique de ce déploiement.",
|
|
1835
|
+
"subjectMissing": "Votre fournisseur d'identité n'a pas renvoyé d'identifiant utilisateur, aucun compte n'a donc pu être résolu. Un administrateur doit vérifier les claims qu'il expose.",
|
|
1836
|
+
"groupRequired": "Votre connexion a réussi, mais vous n'appartenez à aucun groupe de l'annuaire autorisé à utiliser ce déploiement. Demandez à votre service informatique de vous ajouter.",
|
|
1837
|
+
"domainNotAllowed": "Votre domaine de messagerie n'est pas autorisé à se connecter à ce déploiement. Demandez à votre service informatique quel compte utiliser.",
|
|
1838
|
+
"emailRequired": "Ce déploiement limite la connexion à certains domaines de messagerie, mais votre fournisseur d'identité n'a pas transmis d'adresse e-mail vérifiée. Un administrateur doit activer le claim e-mail.",
|
|
1839
|
+
"providerUnreachable": "Votre fournisseur d'identité n'a pas répondu pendant la finalisation de la connexion : lui-même ou le réseau qui y mène est peut-être indisponible. Réessayez dans un instant et prévenez un administrateur si cela persiste.",
|
|
1840
|
+
"unknown": "L'authentification unique a échoué pour une raison que cette version ne reconnaît pas. Réessayez et prévenez un administrateur si le problème persiste."
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1827
1843
|
"resetPassword": {
|
|
1828
1844
|
"title": "Réinitialiser le mot de passe",
|
|
1829
1845
|
"subtitle": "Choisissez un nouveau mot de passe pour votre compte.",
|
|
@@ -4693,6 +4709,7 @@
|
|
|
4693
4709
|
"threshold": "seuil {threshold}",
|
|
4694
4710
|
"thresholdHint": "Le score que cette etape devait atteindre, issu de la politique de fusion de la tache. En dessous, le juge renvoie le travail a l'etape qui l'a produit avec ses constats a reprendre, ou met l'execution en attente pour vous quand il ne reste plus de budget de tentatives.",
|
|
4695
4711
|
"rubricOverridden": "grille de l'espace de travail",
|
|
4712
|
+
"modelPinUnavailable": "Cette revue a été écrite pour le modèle {model}, que ce déploiement ne peut pas exécuter : un autre modèle a donc noté le travail.",
|
|
4696
4713
|
"reworkRounds": "reprise {spent}/{budget}",
|
|
4697
4714
|
"findingsHeading": "Ce que la grille a signalé",
|
|
4698
4715
|
"roundsHeading": "Tours de revue",
|
package/i18n/locales/he.json
CHANGED
|
@@ -1820,10 +1820,26 @@
|
|
|
1820
1820
|
"signInFailed": "ההתחברות נכשלה. בדוק את הפרטים שלך ונסה שוב.",
|
|
1821
1821
|
"genericError": "משהו השתבש. אנא נסה שוב.",
|
|
1822
1822
|
"notConfiguredTitle": "האימות אינו מוגדר",
|
|
1823
|
-
"notConfiguredBody": "בפריסה זו לא מופעלת אף שיטת התחברות, ולכן לא ניתן להתחבר או לגשת למרחבי העבודה שלך. מנהל המערכת צריך להגדיר ספק אימות (GitHub או Google OAuth, או התחברות עם אימייל וסיסמה).",
|
|
1823
|
+
"notConfiguredBody": "בפריסה זו לא מופעלת אף שיטת התחברות, ולכן לא ניתן להתחבר או לגשת למרחבי העבודה שלך. מנהל המערכת צריך להגדיר ספק אימות (התחברות מאוחדת דרך ספק הזהויות של הארגון שלכם, GitHub או Google OAuth, או התחברות עם אימייל וסיסמה).",
|
|
1824
1824
|
"patPlaceholder": "אסימון גישה אישי של {provider}",
|
|
1825
1825
|
"signInWithPat": "התחברות עם PAT של {provider}"
|
|
1826
1826
|
},
|
|
1827
|
+
"sso": {
|
|
1828
|
+
"continueWith": "המשך עם {provider}",
|
|
1829
|
+
"failedTitle": "ההתחברות המאוחדת לא הושלמה",
|
|
1830
|
+
"errors": {
|
|
1831
|
+
"stateInvalid": "ניסיון ההתחברות הזה פג או שכבר נעשה בו שימוש. התחילו מחדש מדף זה.",
|
|
1832
|
+
"providerDenied": "ספק הזהויות שלכם דחה את ההתחברות. אם לא ביטלתם אותה בעצמכם, בדקו עם צוות ה-IT אם היישום הזה מוקצה לכם.",
|
|
1833
|
+
"exchangeFailed": "הפריסה הזו לא הצליחה להשלים את ההחלפה עם ספק הזהויות שלכם. מנהל המערכת צריך לבדוק את סוד הלקוח ואת כתובת ההפניה של ההתחברות המאוחדת.",
|
|
1834
|
+
"tokenInvalid": "לא ניתן היה לאמת את התשובה מספק הזהויות שלכם. מנהל המערכת צריך לבדוק את הגדרות ההתחברות המאוחדת של הפריסה.",
|
|
1835
|
+
"subjectMissing": "ספק הזהויות לא החזיר מזהה משתמש, ולכן לא ניתן היה לאתר חשבון. מנהל המערכת צריך לבדוק אילו claims הוא חושף.",
|
|
1836
|
+
"groupRequired": "ההתחברות הצליחה, אך אינכם חברים בקבוצת ספרייה שמורשית להשתמש בפריסה הזו. בקשו מצוות ה-IT להוסיף אתכם.",
|
|
1837
|
+
"domainNotAllowed": "הדומיין של האימייל שלכם אינו מורשה להתחבר לפריסה הזו. בדקו עם צוות ה-IT באיזה חשבון להשתמש.",
|
|
1838
|
+
"emailRequired": "הפריסה הזו מגבילה התחברות לפי דומיין אימייל, אך ספק הזהויות לא חשף כתובת אימייל מאומתת. מנהל המערכת צריך להפעיל את claim האימייל.",
|
|
1839
|
+
"providerUnreachable": "ספק הזהויות שלך לא הגיב בעת השלמת ההתחברות, ולכן ייתכן שהוא או הרשת אליו אינם זמינים. נסו שוב בעוד רגע, ואם התקלה חוזרת דווחו למנהל המערכת.",
|
|
1840
|
+
"unknown": "ההתחברות המאוחדת נכשלה מסיבה שגרסה זו אינה מזהה. נסו שוב, ואם התקלה חוזרת עדכנו את מנהל המערכת."
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1827
1843
|
"resetPassword": {
|
|
1828
1844
|
"title": "אפס סיסמה",
|
|
1829
1845
|
"subtitle": "בחר סיסמה חדשה לחשבונך.",
|
|
@@ -4693,6 +4709,7 @@
|
|
|
4693
4709
|
"threshold": "סף {threshold}",
|
|
4694
4710
|
"thresholdHint": "הציון שהשלב הזה היה צריך להגיע אליו, לפי מדיניות המיזוג של המשימה. מתחת לכך השופט מחזיר את העבודה לשלב שיצר אותה, עם הממצאים לתיקון, או משהה עבורכם את ההרצה כשלא נותר תקציב ניסיונות.",
|
|
4695
4711
|
"rubricOverridden": "מחוון סביבת העבודה",
|
|
4712
|
+
"modelPinUnavailable": "הביקורת הזו נכתבה עבור המודל {model}, שהפריסה הזו לא יכולה להריץ, ולכן מודל אחר ניקד את העבודה.",
|
|
4696
4713
|
"reworkRounds": "עיבוד מחדש {spent}/{budget}",
|
|
4697
4714
|
"findingsHeading": "מה שהמחוון סימן",
|
|
4698
4715
|
"roundsHeading": "סבבי בדיקה",
|
package/i18n/locales/it.json
CHANGED
|
@@ -3675,10 +3675,26 @@
|
|
|
3675
3675
|
"signInFailed": "Accesso non riuscito. Controlla i tuoi dati e riprova.",
|
|
3676
3676
|
"genericError": "Qualcosa è andato storto. Riprova.",
|
|
3677
3677
|
"notConfiguredTitle": "L'autenticazione non è configurata",
|
|
3678
|
-
"notConfiguredBody": "Questo deployment non ha alcun metodo di accesso abilitato, quindi non puoi accedere o utilizzare i tuoi workspace. Un amministratore deve configurare un provider di autenticazione (OAuth GitHub o Google, oppure accesso con email e password).",
|
|
3678
|
+
"notConfiguredBody": "Questo deployment non ha alcun metodo di accesso abilitato, quindi non puoi accedere o utilizzare i tuoi workspace. Un amministratore deve configurare un provider di autenticazione (accesso unico tramite il provider di identità della tua organizzazione, OAuth GitHub o Google, oppure accesso con email e password).",
|
|
3679
3679
|
"patPlaceholder": "personal access token {provider}",
|
|
3680
3680
|
"signInWithPat": "Accedi con il PAT {provider}"
|
|
3681
3681
|
},
|
|
3682
|
+
"sso": {
|
|
3683
|
+
"continueWith": "Continua con {provider}",
|
|
3684
|
+
"failedTitle": "L'accesso unico non è stato completato",
|
|
3685
|
+
"errors": {
|
|
3686
|
+
"stateInvalid": "Questo tentativo di accesso è scaduto o è già stato usato. Riprova da questa pagina.",
|
|
3687
|
+
"providerDenied": "Il tuo provider di identità ha rifiutato l'accesso. Se non l'hai annullato tu, chiedi al team IT se questa applicazione ti è stata assegnata.",
|
|
3688
|
+
"exchangeFailed": "Questo deployment non ha potuto completare lo scambio con il tuo provider di identità. Un amministratore deve verificare il client secret e l'URL di reindirizzamento dell'accesso unico.",
|
|
3689
|
+
"tokenInvalid": "Non è stato possibile verificare la risposta del tuo provider di identità. Un amministratore deve controllare la configurazione dell'accesso unico di questo deployment.",
|
|
3690
|
+
"subjectMissing": "Il tuo provider di identità non ha restituito un identificatore utente, quindi non è stato possibile risolvere alcun account. Un amministratore deve controllare quali claim vengono esposti.",
|
|
3691
|
+
"groupRequired": "L'accesso è riuscito, ma non appartieni a nessun gruppo della directory autorizzato a usare questo deployment. Chiedi al team IT di aggiungerti.",
|
|
3692
|
+
"domainNotAllowed": "Il tuo dominio email non è autorizzato ad accedere a questo deployment. Chiedi al team IT quale account usare.",
|
|
3693
|
+
"emailRequired": "Questo deployment limita l'accesso per dominio email, ma il tuo provider di identità non ha esposto un indirizzo email verificato. Un amministratore deve abilitare il claim email.",
|
|
3694
|
+
"providerUnreachable": "Il tuo provider di identità non ha risposto durante il completamento dell'accesso, quindi potrebbe non essere raggiungibile. Riprova tra un momento e avvisa un amministratore se il problema persiste.",
|
|
3695
|
+
"unknown": "L'accesso unico è fallito per un motivo che questa versione non riconosce. Riprova e avvisa un amministratore se il problema persiste."
|
|
3696
|
+
}
|
|
3697
|
+
},
|
|
3682
3698
|
"resetPassword": {
|
|
3683
3699
|
"title": "Reimposta password",
|
|
3684
3700
|
"subtitle": "Scegli una nuova password per il tuo account.",
|
|
@@ -5551,6 +5567,7 @@
|
|
|
5551
5567
|
"threshold": "soglia {threshold}",
|
|
5552
5568
|
"thresholdHint": "Il punteggio che questo step doveva raggiungere, preso dalla policy di merge dell'attivita. Al di sotto il giudice rimanda il lavoro allo step che lo ha prodotto, con i suoi rilievi da correggere, oppure mette in pausa l'esecuzione per te quando non resta budget di tentativi.",
|
|
5553
5569
|
"rubricOverridden": "rubrica dello spazio di lavoro",
|
|
5570
|
+
"modelPinUnavailable": "Questa revisione è stata scritta per il modello {model}, che questa installazione non può eseguire, quindi il lavoro è stato valutato da un altro modello.",
|
|
5554
5571
|
"reworkRounds": "revisione {spent}/{budget}",
|
|
5555
5572
|
"findingsHeading": "Cosa ha segnalato la rubrica",
|
|
5556
5573
|
"roundsHeading": "Cicli di revisione",
|
package/i18n/locales/ja.json
CHANGED
|
@@ -1820,10 +1820,26 @@
|
|
|
1820
1820
|
"signInFailed": "サインインに失敗しました。入力内容を確認して、もう一度お試しください。",
|
|
1821
1821
|
"genericError": "問題が発生しました。もう一度お試しください。",
|
|
1822
1822
|
"notConfiguredTitle": "認証が設定されていません",
|
|
1823
|
-
"notConfiguredBody": "
|
|
1823
|
+
"notConfiguredBody": "このデプロイにはサインイン方法が有効になっていないため、サインインやワークスペースへのアクセスができません。管理者が認証プロバイダー(組織の ID プロバイダーによるシングルサインオン、GitHub または Google の OAuth、あるいはメールアドレスとパスワードによるログイン)を設定する必要があります。",
|
|
1824
1824
|
"patPlaceholder": "{provider} のパーソナルアクセストークン",
|
|
1825
1825
|
"signInWithPat": "{provider} の PAT でサインイン"
|
|
1826
1826
|
},
|
|
1827
|
+
"sso": {
|
|
1828
|
+
"continueWith": "{provider} で続行",
|
|
1829
|
+
"failedTitle": "シングルサインオンを完了できませんでした",
|
|
1830
|
+
"errors": {
|
|
1831
|
+
"stateInvalid": "このサインイン試行は期限切れか、すでに使用されています。このページからやり直してください。",
|
|
1832
|
+
"providerDenied": "ID プロバイダーがサインインを拒否しました。ご自身でキャンセルしていない場合は、このアプリケーションが割り当てられているか IT 部門に確認してください。",
|
|
1833
|
+
"exchangeFailed": "このデプロイは ID プロバイダーとの交換を完了できませんでした。管理者がシングルサインオンのクライアントシークレットとリダイレクト URL を確認する必要があります。",
|
|
1834
|
+
"tokenInvalid": "ID プロバイダーからの応答を検証できませんでした。管理者がこのデプロイのシングルサインオン設定を確認する必要があります。",
|
|
1835
|
+
"subjectMissing": "ID プロバイダーがユーザー識別子を返さなかったため、アカウントを特定できませんでした。管理者が公開しているクレームを確認する必要があります。",
|
|
1836
|
+
"groupRequired": "サインインは成功しましたが、このデプロイの利用を許可されたディレクトリグループに所属していません。IT 部門に追加を依頼してください。",
|
|
1837
|
+
"domainNotAllowed": "お使いのメールドメインはこのデプロイへのサインインを許可されていません。どのアカウントを使うべきか IT 部門に確認してください。",
|
|
1838
|
+
"emailRequired": "このデプロイはメールドメインでサインインを制限していますが、ID プロバイダーが検証済みのメールアドレスを公開しませんでした。管理者がメールクレームを有効にする必要があります。",
|
|
1839
|
+
"providerUnreachable": "サインインの完了中に ID プロバイダーから応答がありませんでした。プロバイダー自体か、そこへのネットワークが停止している可能性があります。少し待ってからもう一度お試しいただき、繰り返す場合は管理者にお知らせください。",
|
|
1840
|
+
"unknown": "このバージョンが認識できない理由でシングルサインオンに失敗しました。もう一度お試しいただき、繰り返す場合は管理者にご連絡ください。"
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1827
1843
|
"resetPassword": {
|
|
1828
1844
|
"title": "パスワードをリセット",
|
|
1829
1845
|
"subtitle": "アカウントの新しいパスワードを選択してください。",
|
|
@@ -4693,6 +4709,7 @@
|
|
|
4693
4709
|
"threshold": "しきい値 {threshold}",
|
|
4694
4710
|
"thresholdHint": "このステップが達成すべきスコアで、タスクのマージポリシーから取られます。これを下回ると、ジャッジは指摘事項を手戻りとして生成元のステップに差し戻すか、試行回数の予算が尽きている場合は実行を保留してあなたの判断を待ちます。",
|
|
4695
4711
|
"rubricOverridden": "ワークスペースのルーブリック",
|
|
4712
|
+
"modelPinUnavailable": "このレビューは {model} モデル向けに書かれていますが、このデプロイでは実行できないため、別のモデルが作業を採点しました。",
|
|
4696
4713
|
"reworkRounds": "手戻り {spent}/{budget}",
|
|
4697
4714
|
"findingsHeading": "ルーブリックが指摘した点",
|
|
4698
4715
|
"roundsHeading": "レビューの回数",
|
package/i18n/locales/pl.json
CHANGED
|
@@ -1820,10 +1820,26 @@
|
|
|
1820
1820
|
"signInFailed": "Logowanie nie powiodło się. Sprawdź swoje dane i spróbuj ponownie.",
|
|
1821
1821
|
"genericError": "Coś poszło nie tak. Spróbuj ponownie.",
|
|
1822
1822
|
"notConfiguredTitle": "Uwierzytelnianie nie jest skonfigurowane",
|
|
1823
|
-
"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).",
|
|
1823
|
+
"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 (logowanie jednokrotne przez dostawcę tożsamości Twojej organizacji, OAuth GitHub lub Google albo logowanie e-mailem i hasłem).",
|
|
1824
1824
|
"patPlaceholder": "Osobisty token dostępu {provider}",
|
|
1825
1825
|
"signInWithPat": "Zaloguj się tokenem PAT {provider}"
|
|
1826
1826
|
},
|
|
1827
|
+
"sso": {
|
|
1828
|
+
"continueWith": "Kontynuuj z {provider}",
|
|
1829
|
+
"failedTitle": "Nie udało się ukończyć logowania jednokrotnego",
|
|
1830
|
+
"errors": {
|
|
1831
|
+
"stateInvalid": "Ta próba logowania wygasła lub została już użyta. Zacznij ponownie z tej strony.",
|
|
1832
|
+
"providerDenied": "Twój dostawca tożsamości odrzucił logowanie. Jeśli nie anulowałeś go samodzielnie, zapytaj zespół IT, czy ta aplikacja jest do Ciebie przypisana.",
|
|
1833
|
+
"exchangeFailed": "To wdrożenie nie mogło zakończyć wymiany z dostawcą tożsamości. Administrator musi sprawdzić sekret klienta i adres przekierowania logowania jednokrotnego.",
|
|
1834
|
+
"tokenInvalid": "Nie udało się zweryfikować odpowiedzi dostawcy tożsamości. Administrator musi sprawdzić konfigurację logowania jednokrotnego tego wdrożenia.",
|
|
1835
|
+
"subjectMissing": "Dostawca tożsamości nie zwrócił identyfikatora użytkownika, więc nie udało się ustalić konta. Administrator musi sprawdzić, które oświadczenia (claims) są udostępniane.",
|
|
1836
|
+
"groupRequired": "Logowanie się udało, ale nie należysz do żadnej grupy katalogowej uprawnionej do korzystania z tego wdrożenia. Poproś zespół IT o dodanie Cię.",
|
|
1837
|
+
"domainNotAllowed": "Twoja domena e-mail nie ma uprawnień do logowania w tym wdrożeniu. Zapytaj zespół IT, którego konta użyć.",
|
|
1838
|
+
"emailRequired": "To wdrożenie ogranicza logowanie do wybranych domen e-mail, ale dostawca tożsamości nie udostępnił zweryfikowanego adresu e-mail. Administrator musi włączyć oświadczenie e-mail.",
|
|
1839
|
+
"providerUnreachable": "Twój dostawca tożsamości nie odpowiedział podczas kończenia logowania, więc on sam lub połączenie z nim może być niedostępne. Spróbuj ponownie po chwili, a jeśli problem się powtarza, powiadom administratora.",
|
|
1840
|
+
"unknown": "Logowanie jednokrotne nie powiodło się z powodu, którego ta wersja nie rozpoznaje. Spróbuj ponownie, a jeśli problem się powtarza, powiadom administratora."
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1827
1843
|
"resetPassword": {
|
|
1828
1844
|
"title": "Zresetuj hasło",
|
|
1829
1845
|
"subtitle": "Wybierz nowe hasło do swojego konta.",
|
|
@@ -4693,6 +4709,7 @@
|
|
|
4693
4709
|
"threshold": "próg {threshold}",
|
|
4694
4710
|
"thresholdHint": "Wynik, który ten krok musiał osiągnąć, wzięty z polityki scalania zadania. Poniżej sędzia odsyła pracę do kroku, który ją wytworzył, przekazując swoje uwagi do poprawy, albo wstrzymuje przebieg i czeka na Ciebie, gdy skończy się budżet prób.",
|
|
4695
4711
|
"rubricOverridden": "rubryka przestrzeni roboczej",
|
|
4712
|
+
"modelPinUnavailable": "Ta ocena została napisana dla modelu {model}, którego to wdrożenie nie może uruchomić, więc pracę ocenił inny model.",
|
|
4696
4713
|
"reworkRounds": "poprawki {spent}/{budget}",
|
|
4697
4714
|
"findingsHeading": "Co zgłosiła rubryka",
|
|
4698
4715
|
"roundsHeading": "Rundy przeglądu",
|
package/i18n/locales/tr.json
CHANGED
|
@@ -1820,10 +1820,26 @@
|
|
|
1820
1820
|
"signInFailed": "Oturum açma başarısız. Bilgilerinizi kontrol edip tekrar deneyin.",
|
|
1821
1821
|
"genericError": "Bir şeyler ters gitti. Lütfen tekrar deneyin.",
|
|
1822
1822
|
"notConfiguredTitle": "Kimlik doğrulama yapılandırılmamış",
|
|
1823
|
-
"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.",
|
|
1823
|
+
"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ı (kuruluşunuzun kimlik sağlayıcısı üzerinden tek oturum açma, GitHub veya Google OAuth ya da e-posta ve parola ile oturum açma) yapılandırmalıdır.",
|
|
1824
1824
|
"patPlaceholder": "{provider} kişisel erişim belirteci",
|
|
1825
1825
|
"signInWithPat": "{provider} PAT ile oturum aç"
|
|
1826
1826
|
},
|
|
1827
|
+
"sso": {
|
|
1828
|
+
"continueWith": "{provider} ile devam et",
|
|
1829
|
+
"failedTitle": "Tek oturum açma tamamlanamadı",
|
|
1830
|
+
"errors": {
|
|
1831
|
+
"stateInvalid": "Bu oturum açma denemesinin süresi doldu veya daha önce kullanıldı. Bu sayfadan yeniden başlayın.",
|
|
1832
|
+
"providerDenied": "Kimlik sağlayıcınız oturum açmayı reddetti. İptal eden siz değilseniz, bu uygulamanın size atanıp atanmadığını BT ekibinize sorun.",
|
|
1833
|
+
"exchangeFailed": "Bu dağıtım, kimlik sağlayıcınızla değişimi tamamlayamadı. Bir yöneticinin tek oturum açma istemci parolasını ve yönlendirme adresini kontrol etmesi gerekiyor.",
|
|
1834
|
+
"tokenInvalid": "Kimlik sağlayıcınızdan gelen yanıt doğrulanamadı. Bir yöneticinin bu dağıtımın tek oturum açma yapılandırmasını kontrol etmesi gerekiyor.",
|
|
1835
|
+
"subjectMissing": "Kimlik sağlayıcınız bir kullanıcı tanımlayıcısı döndürmedi, bu nedenle hiçbir hesap çözümlenemedi. Bir yöneticinin hangi taleplerin (claims) paylaşıldığını kontrol etmesi gerekiyor.",
|
|
1836
|
+
"groupRequired": "Oturum açma başarılı oldu, ancak bu dağıtımı kullanmasına izin verilen bir dizin grubunda değilsiniz. BT ekibinizden sizi eklemesini isteyin.",
|
|
1837
|
+
"domainNotAllowed": "E-posta alan adınızın bu dağıtımda oturum açma izni yok. Hangi hesabı kullanmanız gerektiğini BT ekibinize sorun.",
|
|
1838
|
+
"emailRequired": "Bu dağıtım oturum açmayı e-posta alan adına göre kısıtlıyor, ancak kimlik sağlayıcınız doğrulanmış bir e-posta adresi paylaşmadı. Bir yöneticinin e-posta talebini etkinleştirmesi gerekiyor.",
|
|
1839
|
+
"providerUnreachable": "Oturum açma işlemi tamamlanırken kimlik sağlayıcınız yanıt vermedi; sağlayıcı ya da ona giden ağ çalışmıyor olabilir. Biraz sonra yeniden deneyin, sorun sürerse bir yöneticiye bildirin.",
|
|
1840
|
+
"unknown": "Tek oturum açma, bu sürümün tanımadığı bir nedenle başarısız oldu. Tekrar deneyin ve sorun sürerse bir yöneticiye bildirin."
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1827
1843
|
"resetPassword": {
|
|
1828
1844
|
"title": "Parolayı sıfırla",
|
|
1829
1845
|
"subtitle": "Hesabınız için yeni bir parola seçin.",
|
|
@@ -4693,6 +4709,7 @@
|
|
|
4693
4709
|
"threshold": "eşik {threshold}",
|
|
4694
4710
|
"thresholdHint": "Bu adımın ulaşması gereken puan; görevin birleştirme politikasından alınır. Altında kaldığında hakem, bulgularını yeniden çalışma olarak ekleyip işi üreten adıma geri gönderir; deneme bütçesi kalmadıysa çalıştırmayı sizin için beklemeye alır.",
|
|
4695
4711
|
"rubricOverridden": "çalışma alanı ölçütü",
|
|
4712
|
+
"modelPinUnavailable": "Bu inceleme {model} modeli için yazıldı ancak bu kurulum onu çalıştıramıyor, bu yüzden işi başka bir model puanladı.",
|
|
4696
4713
|
"reworkRounds": "yeniden çalışma {spent}/{budget}",
|
|
4697
4714
|
"findingsHeading": "Ölçütün işaretledikleri",
|
|
4698
4715
|
"roundsHeading": "İnceleme turları",
|
package/i18n/locales/uk.json
CHANGED
|
@@ -1820,10 +1820,26 @@
|
|
|
1820
1820
|
"signInFailed": "Не вдалося увійти. Перевірте свої дані та спробуйте ще раз.",
|
|
1821
1821
|
"genericError": "Щось пішло не так. Спробуйте ще раз.",
|
|
1822
1822
|
"notConfiguredTitle": "Автентифікацію не налаштовано",
|
|
1823
|
-
"notConfiguredBody": "У цьому розгортанні не ввімкнено жодного способу входу, тому ви не можете увійти чи отримати доступ до своїх робочих просторів. Адміністратор має налаштувати постачальника автентифікації (OAuth GitHub або Google чи вхід за електронною поштою та паролем).",
|
|
1823
|
+
"notConfiguredBody": "У цьому розгортанні не ввімкнено жодного способу входу, тому ви не можете увійти чи отримати доступ до своїх робочих просторів. Адміністратор має налаштувати постачальника автентифікації (єдиний вхід через постачальника ідентифікації вашої організації, OAuth GitHub або Google чи вхід за електронною поштою та паролем).",
|
|
1824
1824
|
"patPlaceholder": "Особистий токен доступу {provider}",
|
|
1825
1825
|
"signInWithPat": "Увійти за допомогою PAT {provider}"
|
|
1826
1826
|
},
|
|
1827
|
+
"sso": {
|
|
1828
|
+
"continueWith": "Продовжити з {provider}",
|
|
1829
|
+
"failedTitle": "Єдиний вхід не завершено",
|
|
1830
|
+
"errors": {
|
|
1831
|
+
"stateInvalid": "Ця спроба входу застаріла або вже була використана. Почніть знову з цієї сторінки.",
|
|
1832
|
+
"providerDenied": "Ваш постачальник ідентифікації відмовив у вході. Якщо ви не скасовували його самостійно, запитайте у своєї ІТ-команди, чи призначено вам цей застосунок.",
|
|
1833
|
+
"exchangeFailed": "Це розгортання не змогло завершити обмін із вашим постачальником ідентифікації. Адміністратор має перевірити клієнтський секрет і URL перенаправлення єдиного входу.",
|
|
1834
|
+
"tokenInvalid": "Не вдалося перевірити відповідь вашого постачальника ідентифікації. Адміністратор має перевірити налаштування єдиного входу цього розгортання.",
|
|
1835
|
+
"subjectMissing": "Постачальник ідентифікації не повернув ідентифікатора користувача, тому обліковий запис не вдалося визначити. Адміністратор має перевірити, які claims він передає.",
|
|
1836
|
+
"groupRequired": "Вхід відбувся успішно, але ви не належите до жодної групи каталогу, якій дозволено користуватися цим розгортанням. Попросіть ІТ-команду додати вас.",
|
|
1837
|
+
"domainNotAllowed": "Вашому домену електронної пошти не дозволено входити до цього розгортання. Запитайте в ІТ-команди, який обліковий запис використати.",
|
|
1838
|
+
"emailRequired": "Це розгортання обмежує вхід за доменом електронної пошти, але ваш постачальник ідентифікації не передав підтвердженої адреси. Адміністратор має увімкнути claim електронної пошти.",
|
|
1839
|
+
"providerUnreachable": "Ваш постачальник ідентифікації не відповів під час завершення входу, тож він або мережа до нього можуть бути недоступні. Спробуйте ще раз за мить, а якщо це повторюється, повідомте адміністратора.",
|
|
1840
|
+
"unknown": "Єдиний вхід не вдався з причини, якої ця версія не розпізнає. Спробуйте ще раз, а якщо проблема повторюється, повідомте адміністратора."
|
|
1841
|
+
}
|
|
1842
|
+
},
|
|
1827
1843
|
"resetPassword": {
|
|
1828
1844
|
"title": "Скинути пароль",
|
|
1829
1845
|
"subtitle": "Виберіть новий пароль для свого облікового запису.",
|
|
@@ -4693,6 +4709,7 @@
|
|
|
4693
4709
|
"threshold": "поріг {threshold}",
|
|
4694
4710
|
"thresholdHint": "Оцінка, якої мав досягти цей крок, узята з політики злиття завдання. Нижче за неї суддя повертає роботу до кроку, що її створив, разом зі своїми зауваженнями на доопрацювання, або ставить запуск на паузу для вас, коли бюджет спроб вичерпано.",
|
|
4695
4711
|
"rubricOverridden": "рубрика робочого простору",
|
|
4712
|
+
"modelPinUnavailable": "Цю перевірку написано для моделі {model}, яку це розгортання не може запустити, тож роботу оцінила інша модель.",
|
|
4696
4713
|
"reworkRounds": "доопрацювання {spent}/{budget}",
|
|
4697
4714
|
"findingsHeading": "Що позначила рубрика",
|
|
4698
4715
|
"roundsHeading": "Раунди перевірки",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.230.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",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"valibot": "^1.4.2",
|
|
41
41
|
"vue": "3.5.40",
|
|
42
42
|
"wretch": "^3.0.9",
|
|
43
|
-
"@cat-factory/contracts": "0.
|
|
43
|
+
"@cat-factory/contracts": "0.247.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@toad-contracts/testing": "0.3.2",
|