@cat-factory/app 0.155.0 → 0.157.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.
@@ -0,0 +1,146 @@
1
+ import { describe, it, expect, vi, type Mock } from 'vitest'
2
+ import { useGitHubStore } from '~/stores/github'
3
+ import { useWorkspaceStore } from '~/stores/workspace'
4
+ import type { GitHubConnection, VcsConnectOption } from '~/types/domain'
5
+
6
+ // The VCS connect surface of the (single, GitHub-shaped) repo store: which connect methods the
7
+ // deployment offers, the per-workspace GitLab PAT connect, and the provider-routed disconnect.
8
+ // These decide what the connect UI renders — an App picker a GitLab-only deployment can't serve,
9
+ // or a GitHub disconnect call against a GitLab connection, are exactly the failures worth pinning.
10
+
11
+ function connection(overrides: Partial<GitHubConnection> = {}): GitHubConnection {
12
+ return {
13
+ installationId: 42,
14
+ accountLogin: 'octocat',
15
+ targetType: 'User',
16
+ connectedAt: 1,
17
+ provider: 'github',
18
+ canCreateRepos: false,
19
+ canManageWorkflows: true,
20
+ ...overrides,
21
+ }
22
+ }
23
+
24
+ /** Stub the auto-imported `useApi()` with just the calls the connect actions make. */
25
+ function stubApi<T extends Record<string, Mock>>(api: T) {
26
+ const full = {
27
+ listGitHubRepos: vi.fn().mockResolvedValue([]),
28
+ listGitHubPullRequests: vi.fn().mockResolvedValue([]),
29
+ listGitHubIssues: vi.fn().mockResolvedValue([]),
30
+ ...api,
31
+ }
32
+ vi.stubGlobal('useApi', () => full)
33
+ return full
34
+ }
35
+
36
+ /** A store bound to an active workspace (the actions all resolve one). */
37
+ function storeWithWorkspace() {
38
+ useWorkspaceStore().workspaceId = 'ws-1'
39
+ return useGitHubStore()
40
+ }
41
+
42
+ describe('github store — VCS connect capability', () => {
43
+ it('probes the connection and the connect options together', async () => {
44
+ stubApi({
45
+ getGitHubConnection: vi.fn().mockResolvedValue({ connection: null }),
46
+ listVcsConnectOptions: vi.fn().mockResolvedValue({
47
+ options: [{ provider: 'gitlab', method: 'pat' }] satisfies VcsConnectOption[],
48
+ }),
49
+ })
50
+ const github = storeWithWorkspace()
51
+
52
+ await github.probe()
53
+
54
+ expect(github.available).toBe(true)
55
+ expect(github.canConnectGitHubApp).toBe(false)
56
+ expect(github.canConnectGitLabPat).toBe(true)
57
+ // A single-provider deployment names its provider, so the connect copy never says "choose".
58
+ expect(github.soleConnectProvider).toBe('gitlab')
59
+ })
60
+
61
+ it('reports no connect surface when the capability read fails, without hiding the integration', async () => {
62
+ // A member without `integrations.manage` gets a 403 here. That must degrade to "nothing to
63
+ // connect", NOT to a broken picker — and must not flip the whole integration off.
64
+ stubApi({
65
+ getGitHubConnection: vi.fn().mockResolvedValue({ connection: connection() }),
66
+ listVcsConnectOptions: vi.fn().mockRejectedValue(new Error('403')),
67
+ })
68
+ const github = storeWithWorkspace()
69
+
70
+ await github.probe()
71
+
72
+ expect(github.available).toBe(true)
73
+ expect(github.connectOptions).toEqual([])
74
+ expect(github.soleConnectProvider).toBeNull()
75
+ })
76
+
77
+ it('stays neutral when the deployment serves several providers', async () => {
78
+ stubApi({
79
+ getGitHubConnection: vi.fn().mockResolvedValue({ connection: null }),
80
+ listVcsConnectOptions: vi.fn().mockResolvedValue({
81
+ options: [
82
+ { provider: 'github', method: 'app' },
83
+ { provider: 'gitlab', method: 'pat' },
84
+ ] satisfies VcsConnectOption[],
85
+ }),
86
+ })
87
+ const github = storeWithWorkspace()
88
+
89
+ await github.probe()
90
+
91
+ expect(github.canConnectGitHubApp).toBe(true)
92
+ expect(github.canConnectGitLabPat).toBe(true)
93
+ expect(github.soleConnectProvider).toBeNull()
94
+ })
95
+
96
+ it('connects GitLab with a trimmed PAT and loads the projection', async () => {
97
+ const api = stubApi({
98
+ connectGitLab: vi.fn().mockResolvedValue(connection({ provider: 'gitlab' })),
99
+ })
100
+ const github = storeWithWorkspace()
101
+
102
+ await github.connectGitLab(' glpat-secret ')
103
+
104
+ expect(api.connectGitLab).toHaveBeenCalledWith('ws-1', 'glpat-secret')
105
+ expect(github.connected).toBe(true)
106
+ expect(github.provider).toBe('gitlab')
107
+ expect(github.available).toBe(true)
108
+ // Connecting seeds the projection reads, exactly as the App connect does.
109
+ expect(api.listGitHubRepos).toHaveBeenCalledWith('ws-1')
110
+ })
111
+
112
+ it('routes disconnect to the provider that is actually connected', async () => {
113
+ const api = stubApi({
114
+ connectGitLab: vi.fn().mockResolvedValue(connection({ provider: 'gitlab' })),
115
+ disconnectGitLab: vi.fn().mockResolvedValue(undefined),
116
+ disconnectGitHub: vi.fn().mockResolvedValue(undefined),
117
+ })
118
+ const github = storeWithWorkspace()
119
+ await github.connectGitLab('glpat-secret')
120
+
121
+ await github.disconnect()
122
+
123
+ expect(api.disconnectGitLab).toHaveBeenCalledWith('ws-1')
124
+ expect(api.disconnectGitHub).not.toHaveBeenCalled()
125
+ expect(github.connection).toBeNull()
126
+ })
127
+
128
+ it('disconnects a connection with no provider through the GitHub route', async () => {
129
+ // Backends predating the discriminator omit `provider`; those are GitHub App connections.
130
+ const api = stubApi({
131
+ getGitHubConnection: vi.fn().mockResolvedValue({
132
+ connection: { ...connection(), provider: undefined },
133
+ }),
134
+ listVcsConnectOptions: vi.fn().mockResolvedValue({ options: [] }),
135
+ disconnectGitHub: vi.fn().mockResolvedValue(undefined),
136
+ disconnectGitLab: vi.fn().mockResolvedValue(undefined),
137
+ })
138
+ const github = storeWithWorkspace()
139
+ await github.probe()
140
+
141
+ await github.disconnect()
142
+
143
+ expect(api.disconnectGitHub).toHaveBeenCalledWith('ws-1')
144
+ expect(api.disconnectGitLab).not.toHaveBeenCalled()
145
+ })
146
+ })
@@ -9,6 +9,8 @@ import type {
9
9
  GitHubPullRequest,
10
10
  GitHubRepo,
11
11
  RepoTreeEntry,
12
+ VcsConnectOption,
13
+ VcsProvider,
12
14
  } from '~/types/domain'
13
15
  import { useSingleFlightProbe } from '~/composables/useSingleFlightProbe'
14
16
  import { useUpsertList } from '~/composables/useUpsertList'
@@ -17,6 +19,7 @@ import { useServicesStore } from '~/stores/services'
17
19
  import { pullKey, type GitHubStoreContext } from '~/stores/github/context'
18
20
  import { createGitHubConnectionActions } from '~/stores/github/connection'
19
21
  import { createGitHubRepoActions } from '~/stores/github/repoActions'
22
+ import { createVcsConnectActions } from '~/stores/github/vcsConnect'
20
23
 
21
24
  /**
22
25
  * GitHub integration state: the workspace's App installation, the projected
@@ -33,8 +36,10 @@ export const useGitHubStore = defineStore('github', () => {
33
36
 
34
37
  /** null = unknown (not probed yet), true/false = integration on/off. */
35
38
  const available = ref<boolean | null>(null)
36
- /** The workspace's App installation, or null when not yet connected. */
39
+ /** The workspace's VCS connection (App installation or PAT), or null when not connected. */
37
40
  const connection = ref<GitHubConnection | null>(null)
41
+ /** The connect surfaces this deployment serves; resolved by the probe alongside `connection`. */
42
+ const connectOptions = ref<VcsConnectOption[]>([])
38
43
  /** Discovered App installations for the connect picker; loaded on demand. */
39
44
  const installations = ref<GitHubInstallationOption[]>([])
40
45
  const loadingInstallations = ref(false)
@@ -58,6 +63,26 @@ export const useGitHubStore = defineStore('github', () => {
58
63
  const syncing = ref(false)
59
64
 
60
65
  const connected = computed(() => connection.value !== null)
66
+ /**
67
+ * The provider backing the current connection. Presentation (labels, icons, host/URL shapes)
68
+ * keys off this; a connection from a backend predating the discriminator is a GitHub App one.
69
+ */
70
+ const provider = computed<VcsProvider>(() => connection.value?.provider ?? 'github')
71
+ /** Whether the deployment can serve a GitHub App connect / a per-workspace GitLab PAT connect. */
72
+ const canConnectGitHubApp = computed(() =>
73
+ connectOptions.value.some((o) => o.provider === 'github' && o.method === 'app'),
74
+ )
75
+ const canConnectGitLabPat = computed(() =>
76
+ connectOptions.value.some((o) => o.provider === 'gitlab' && o.method === 'pat'),
77
+ )
78
+ /**
79
+ * The single provider this deployment can connect, or null when it offers several (or none) —
80
+ * what the connect copy keys off so a one-provider deployment never says "choose a provider".
81
+ */
82
+ const soleConnectProvider = computed<VcsProvider | null>(() => {
83
+ const providers = new Set(connectOptions.value.map((o) => o.provider))
84
+ return providers.size === 1 ? [...providers][0]! : null
85
+ })
61
86
  /** Whether cat-factory can create repos under the connected account itself. */
62
87
  const canCreateRepos = computed(() => connection.value?.canCreateRepos === true)
63
88
  /**
@@ -104,17 +129,29 @@ export const useGitHubStore = defineStore('github', () => {
104
129
  return base ? `${base}/issues/${issue.number}` : null
105
130
  }
106
131
 
107
- /** Probe the integration: resolves `available` and the current connection. */
132
+ /**
133
+ * Probe the integration: resolves `available`, the current connection, and which connect
134
+ * surfaces the deployment serves. The capability read rides the same round trip (it is what
135
+ * the not-connected UI renders from), and degrades to "no connect surface" on its own.
136
+ */
108
137
  async function runProbe() {
109
138
  if (!workspace.workspaceId) return
110
139
  try {
111
- const { connection: conn } = await api.getGitHubConnection(workspace.requireId())
140
+ const [{ connection: conn }, options] = await Promise.all([
141
+ api.getGitHubConnection(workspace.requireId()),
142
+ api
143
+ .listVcsConnectOptions(workspace.requireId())
144
+ .then((r) => r.options)
145
+ .catch(() => []),
146
+ ])
112
147
  available.value = true
113
148
  connection.value = conn
149
+ connectOptions.value = options
114
150
  } catch {
115
151
  // 503 (integration disabled) or any error → hide the UI entry points.
116
152
  available.value = false
117
153
  connection.value = null
154
+ connectOptions.value = []
118
155
  }
119
156
  }
120
157
  // Single-flight the probe (app-startup initiative, item 12): `probe()` still re-reads on demand,
@@ -162,6 +199,7 @@ export const useGitHubStore = defineStore('github', () => {
162
199
  workspace,
163
200
  available,
164
201
  connection,
202
+ connectOptions,
165
203
  installations,
166
204
  loadingInstallations,
167
205
  repos,
@@ -180,6 +218,7 @@ export const useGitHubStore = defineStore('github', () => {
180
218
  }
181
219
  const connectionActions = createGitHubConnectionActions(context)
182
220
  const repoActions = createGitHubRepoActions(context)
221
+ const vcsConnectActions = createVcsConnectActions(context)
183
222
 
184
223
  /**
185
224
  * Drop the per-workspace projection + connection state (called on workspace switch)
@@ -189,6 +228,7 @@ export const useGitHubStore = defineStore('github', () => {
189
228
  function reset() {
190
229
  available.value = null
191
230
  connection.value = null
231
+ connectOptions.value = []
192
232
  installations.value = []
193
233
  repos.value = []
194
234
  availableRepos.value = []
@@ -201,6 +241,7 @@ export const useGitHubStore = defineStore('github', () => {
201
241
  return {
202
242
  available,
203
243
  connection,
244
+ connectOptions,
204
245
  installations,
205
246
  loadingInstallations,
206
247
  repos,
@@ -213,6 +254,10 @@ export const useGitHubStore = defineStore('github', () => {
213
254
  loading,
214
255
  syncing,
215
256
  connected,
257
+ provider,
258
+ canConnectGitHubApp,
259
+ canConnectGitLabPat,
260
+ soleConnectProvider,
216
261
  canCreateRepos,
217
262
  missingWorkflowsPermission,
218
263
  repoFor,
@@ -229,6 +274,7 @@ export const useGitHubStore = defineStore('github', () => {
229
274
  repoFiles,
230
275
  ...connectionActions,
231
276
  ...repoActions,
277
+ ...vcsConnectActions,
232
278
  reset,
233
279
  }
234
280
  })
@@ -18,6 +18,7 @@ export const useTrackerStore = defineStore('tracker', () => {
18
18
  linearTeamId: null,
19
19
  writebackCommentOnPrOpen: false,
20
20
  writebackResolveOnMerge: false,
21
+ writebackQuestionsOnPark: false,
21
22
  updatedAt: 0,
22
23
  })
23
24
 
@@ -31,6 +32,7 @@ export const useTrackerStore = defineStore('tracker', () => {
31
32
  linearTeamId: null,
32
33
  writebackCommentOnPrOpen: false,
33
34
  writebackResolveOnMerge: false,
35
+ writebackQuestionsOnPark: false,
34
36
  updatedAt: 0,
35
37
  }
36
38
  }
@@ -171,6 +171,7 @@ export type * from './tasks'
171
171
  export type * from './bootstrap'
172
172
  export type * from './envConfigRepair'
173
173
  export type * from './github'
174
+ export type * from './vcs'
174
175
  export type * from './accounts'
175
176
  export type * from './notifications'
176
177
  export type * from './slack'
@@ -0,0 +1,14 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Provider-neutral VCS vocabulary. The platform talks to several git providers
3
+ // (GitHub, GitLab, …) through one GitHub-shaped service layer, so the SPA's data
4
+ // stays neutral and only its PRESENTATION switches on the provider.
5
+ //
6
+ // All wire shapes come from @cat-factory/contracts (single source of truth).
7
+ // ---------------------------------------------------------------------------
8
+
9
+ import type { VcsProviderWire } from '@cat-factory/contracts'
10
+
11
+ export type { VcsConnectMethod, VcsConnectOption, VcsProviderWire } from '@cat-factory/contracts'
12
+
13
+ /** The VCS a connection / repository belongs to — the discriminator presentation keys off. */
14
+ export type VcsProvider = VcsProviderWire
@@ -0,0 +1,31 @@
1
+ import type { VcsProvider } from '~/types/domain'
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Shared VCS provider presentation. The platform's repo DATA is provider-neutral (one
5
+ // GitHub-shaped store serves GitLab through the backend adapter), so only presentation
6
+ // switches on the provider — and it switches HERE, once, rather than per component.
7
+ //
8
+ // Labels are brand names, kept verbatim in every locale, so they are constants rather than
9
+ // catalog keys (the same convention the login screen and the API-key provider descriptors
10
+ // already use). Anything that is PROSE stays in the i18n catalog, keyed per provider.
11
+ //
12
+ // Each map is an exhaustive `Record<VcsProvider, …>`: adding a provider to the union fails
13
+ // the typecheck here instead of silently rendering a GitHub icon for it.
14
+ // ---------------------------------------------------------------------------
15
+
16
+ /** Brand name, as rendered in titles and buttons. */
17
+ export const VCS_PROVIDER_LABELS: Record<VcsProvider, string> = {
18
+ github: 'GitHub',
19
+ gitlab: 'GitLab',
20
+ }
21
+
22
+ export const VCS_PROVIDER_ICONS: Record<VcsProvider, string> = {
23
+ github: 'i-lucide-github',
24
+ gitlab: 'i-lucide-gitlab',
25
+ }
26
+
27
+ /** Where a user creates a personal access token for the provider (the PAT connect flow). */
28
+ export const VCS_PROVIDER_TOKEN_URLS: Record<VcsProvider, string> = {
29
+ github: 'https://github.com/settings/tokens/new',
30
+ gitlab: 'https://gitlab.com/-/user_settings/personal_access_tokens',
31
+ }
@@ -350,6 +350,10 @@
350
350
  "resolveOnMerge": {
351
351
  "label": "Beim Mergen eines PR als gelöst schließen",
352
352
  "help": "Kommentiere, dass der PR gemergt wurde, und schließe / löse dann das verknüpfte Issue."
353
+ },
354
+ "questionsOnPark": {
355
+ "label": "Offene Fragen bei einem pausierten Headless-Lauf posten",
356
+ "help": "Wenn ein über die API gestarteter Lauf zur Klärung der Anforderungen pausiert, poste seine offenen Fragen — jeweils mit der ID, die eine Antwort nennt — am verknüpften Issue. In der App gestartete Aufgaben sind nicht betroffen."
353
357
  }
354
358
  },
355
359
  "probeFailure": {
@@ -1317,6 +1321,7 @@
1317
1321
  "issueWriteback": "Issue-Rückschreibung",
1318
1322
  "commentOnPrOpen": "Kommentar beim PR-Öffnen",
1319
1323
  "closeOnMerge": "Beim Mergen schließen",
1324
+ "questionsOnPark": "Fragen beim Pausieren stellen",
1320
1325
  "writebackHint": "Schreibt zurück in das verknüpfte Tracker-Issue dieser Aufgabe. Überschreibt den Workspace-Standard.",
1321
1326
  "responsibleProduct": "Verantwortliches Produkt",
1322
1327
  "responsibleEmpty": "Nicht zugewiesen. Setze einen Product Owner, um ihn zu benachrichtigen, wenn die Anforderungsprüfung diese Aufgabe kennzeichnet.",
@@ -2600,8 +2605,7 @@
2600
2605
  },
2601
2606
  "github": {
2602
2607
  "onboarding": {
2603
- "title": "cat-factory mit GitHub verbinden",
2604
- "intro": "cat-factory funktioniert, indem es Pull Requests in Ihren Repositorys öffnet. Installieren Sie die GitHub App auf Ihrem Account oder Ihrer Organisation, um fortzufahren; Sie können ihr jedes Repository oder eine Teilmenge gewähren.",
2608
+ "appIntro": "Installieren Sie die GitHub App auf Ihrem Account oder Ihrer Organisation; Sie können ihr jedes Repository oder eine Teilmenge gewähren.",
2605
2609
  "signedInAs": "Angemeldet als {login}",
2606
2610
  "signOut": "Abmelden"
2607
2611
  },
@@ -2675,7 +2679,6 @@
2675
2679
  "closed": "geschlossen"
2676
2680
  },
2677
2681
  "toast": {
2678
- "disconnected": "GitHub getrennt",
2679
2682
  "resync": "Neusynchronisierung {status}",
2680
2683
  "reposUpdated": "Verknüpfte Repositorys aktualisiert",
2681
2684
  "branchCreated": "Branch {name} erstellt",
@@ -2691,10 +2694,6 @@
2691
2694
  "createBranch": "Branch konnte nicht erstellt werden",
2692
2695
  "openPr": "Pull Request konnte nicht geöffnet werden",
2693
2696
  "merge": "Mergen nicht möglich"
2694
- },
2695
- "confirmDisconnect": {
2696
- "title": "GitHub trennen?",
2697
- "body": "Die App verliert den Zugriff auf Ihre Repositorys, bis Sie sie erneut verbinden."
2698
2697
  }
2699
2698
  },
2700
2699
  "addService": {
@@ -5188,5 +5187,40 @@
5188
5187
  "sourceUnlinked": "Quelle getrennt",
5189
5188
  "unlinkSourceFailed": "Quelle konnte nicht getrennt werden"
5190
5189
  }
5190
+ },
5191
+ "vcs": {
5192
+ "panel": {
5193
+ "title": "Quellcodeverwaltung",
5194
+ "patMeta": "Verbunden über ein persönliches Zugriffstoken",
5195
+ "confirmDisconnect": {
5196
+ "title": "{provider} trennen?",
5197
+ "body": "Die App verliert den Zugriff auf Ihre Repositorys, bis Sie sie erneut verbinden."
5198
+ },
5199
+ "toast": {
5200
+ "disconnected": "{provider} getrennt"
5201
+ }
5202
+ },
5203
+ "connect": {
5204
+ "or": "oder",
5205
+ "noneConfigured": "Für dieses Deployment ist keine Quellcodeverbindung konfiguriert. Bitten Sie einen Betreiber, eine GitHub App oder einen GitLab-Zugang einzurichten.",
5206
+ "gitlab": {
5207
+ "intro": "Fügen Sie ein persönliches GitLab-Zugriffstoken ein, um diesen Workspace zu verbinden. cat-factory nutzt es, um Ihre Projekte aufzulisten, Branches zu pushen und Merge Requests zu öffnen.",
5208
+ "tokenLabel": "Persönliches Zugriffstoken",
5209
+ "scope": "Benötigt den Bereich api",
5210
+ "createToken": "Token auf GitLab erstellen",
5211
+ "submit": "GitLab verbinden",
5212
+ "toast": {
5213
+ "connected": "GitLab verbunden"
5214
+ },
5215
+ "errors": {
5216
+ "connect": "GitLab konnte nicht verbunden werden"
5217
+ }
5218
+ }
5219
+ },
5220
+ "onboarding": {
5221
+ "title": "cat-factory mit {provider} verbinden",
5222
+ "titleAny": "cat-factory mit Ihren Repositorys verbinden",
5223
+ "intro": "cat-factory funktioniert, indem es Pull Requests in Ihren Repositorys öffnet. Verbinden Sie Ihren Repository-Anbieter, um fortzufahren."
5224
+ }
5191
5225
  }
5192
5226
  }
@@ -1088,6 +1088,7 @@
1088
1088
  "issueWriteback": "Issue writeback",
1089
1089
  "commentOnPrOpen": "Comment on PR open",
1090
1090
  "closeOnMerge": "Close on merge",
1091
+ "questionsOnPark": "Ask questions on park",
1091
1092
  "writebackHint": "Writes back to this task's linked tracker issue. Overrides the workspace default.",
1092
1093
  "responsibleProduct": "Responsible product",
1093
1094
  "responsibleEmpty": "Unassigned. Set a product owner to notify them when requirement review flags this task.",
@@ -2416,6 +2417,10 @@
2416
2417
  "resolveOnMerge": {
2417
2418
  "label": "Close as resolved when a PR merges",
2418
2419
  "help": "Comment that the PR merged, then close / resolve the linked issue."
2420
+ },
2421
+ "questionsOnPark": {
2422
+ "label": "Post open questions on a parked headless run",
2423
+ "help": "When a run started through the API pauses to clarify requirements, post its open questions — each with the id an answer names — on the linked issue. Tasks started in the app are unaffected."
2419
2424
  }
2420
2425
  },
2421
2426
  "probeFailure": {
@@ -3148,8 +3153,7 @@
3148
3153
  },
3149
3154
  "github": {
3150
3155
  "onboarding": {
3151
- "title": "Connect cat-factory to GitHub",
3152
- "intro": "cat-factory works by opening pull requests on your repositories. Install the GitHub App on your account or organization to continue, and you can grant it every repository or pick a subset.",
3156
+ "appIntro": "Install the GitHub App on your account or organization; you can grant it every repository or pick a subset.",
3153
3157
  "signedInAs": "Signed in as {login}",
3154
3158
  "signOut": "Sign out"
3155
3159
  },
@@ -3223,7 +3227,6 @@
3223
3227
  "closed": "closed"
3224
3228
  },
3225
3229
  "toast": {
3226
- "disconnected": "GitHub disconnected",
3227
3230
  "resync": "Resync {status}",
3228
3231
  "reposUpdated": "Linked repositories updated",
3229
3232
  "branchCreated": "Branch {name} created",
@@ -3239,10 +3242,6 @@
3239
3242
  "createBranch": "Could not create branch",
3240
3243
  "openPr": "Could not open pull request",
3241
3244
  "merge": "Could not merge"
3242
- },
3243
- "confirmDisconnect": {
3244
- "title": "Disconnect GitHub?",
3245
- "body": "The app will lose access to your repositories until you reconnect."
3246
3245
  }
3247
3246
  },
3248
3247
  "addService": {
@@ -5317,5 +5316,40 @@
5317
5316
  "sourceUnlinked": "Source unlinked",
5318
5317
  "unlinkSourceFailed": "Could not unlink source"
5319
5318
  }
5319
+ },
5320
+ "vcs": {
5321
+ "panel": {
5322
+ "title": "Source control",
5323
+ "patMeta": "Connected with a personal access token",
5324
+ "confirmDisconnect": {
5325
+ "title": "Disconnect {provider}?",
5326
+ "body": "The app will lose access to your repositories until you reconnect."
5327
+ },
5328
+ "toast": {
5329
+ "disconnected": "{provider} disconnected"
5330
+ }
5331
+ },
5332
+ "connect": {
5333
+ "or": "or",
5334
+ "noneConfigured": "No source-control connection is configured for this deployment. Ask an operator to set up a GitHub App or GitLab access.",
5335
+ "gitlab": {
5336
+ "intro": "Paste a GitLab personal access token to connect this workspace. cat-factory uses it to list your projects, push branches and open merge requests.",
5337
+ "tokenLabel": "Personal access token",
5338
+ "scope": "Needs the api scope",
5339
+ "createToken": "Create a token on GitLab",
5340
+ "submit": "Connect GitLab",
5341
+ "toast": {
5342
+ "connected": "GitLab connected"
5343
+ },
5344
+ "errors": {
5345
+ "connect": "Could not connect GitLab"
5346
+ }
5347
+ }
5348
+ },
5349
+ "onboarding": {
5350
+ "title": "Connect cat-factory to {provider}",
5351
+ "titleAny": "Connect cat-factory to your repositories",
5352
+ "intro": "cat-factory works by opening pull requests on your repositories. Connect your repository host to continue."
5353
+ }
5320
5354
  }
5321
5355
  }
@@ -1031,6 +1031,7 @@
1031
1031
  "issueWriteback": "Reescritura de incidencias",
1032
1032
  "commentOnPrOpen": "Comentar al abrir el PR",
1033
1033
  "closeOnMerge": "Cerrar al fusionar",
1034
+ "questionsOnPark": "Preguntar al pausarse",
1034
1035
  "writebackHint": "Reescribe en la incidencia del tracker vinculada a esta tarea. Anula el valor predeterminado del espacio de trabajo.",
1035
1036
  "responsibleProduct": "Producto responsable",
1036
1037
  "responsibleEmpty": "Sin asignar. Define un responsable de producto para notificarle cuando la revisión de requisitos marque esta tarea.",
@@ -2228,6 +2229,10 @@
2228
2229
  "resolveOnMerge": {
2229
2230
  "label": "Cerrar como resuelta cuando se fusiona un PR",
2230
2231
  "help": "Comenta que el PR se fusionó y luego cierra / resuelve la incidencia vinculada."
2232
+ },
2233
+ "questionsOnPark": {
2234
+ "label": "Publicar preguntas abiertas cuando un ejecución headless se detiene",
2235
+ "help": "Cuando una ejecución iniciada por la API se detiene para aclarar requisitos, publica sus preguntas abiertas — cada una con el id que debe nombrar la respuesta — en la incidencia vinculada. Las tareas iniciadas en la aplicación no se ven afectadas."
2231
2236
  }
2232
2237
  },
2233
2238
  "probeFailure": {
@@ -3061,8 +3066,7 @@
3061
3066
  },
3062
3067
  "github": {
3063
3068
  "onboarding": {
3064
- "title": "Conecta cat-factory con GitHub",
3065
- "intro": "cat-factory funciona abriendo solicitudes de incorporación de cambios en tus repositorios. Instala la GitHub App en tu cuenta u organización para continuar, y puedes concederle todos los repositorios o elegir un subconjunto.",
3069
+ "appIntro": "Instala la GitHub App en tu cuenta u organización; puedes concederle todos los repositorios o elegir un subconjunto.",
3066
3070
  "signedInAs": "Sesión iniciada como {login}",
3067
3071
  "signOut": "Cerrar sesión"
3068
3072
  },
@@ -3136,7 +3140,6 @@
3136
3140
  "closed": "cerrada"
3137
3141
  },
3138
3142
  "toast": {
3139
- "disconnected": "GitHub desconectado",
3140
3143
  "resync": "Resincronización {status}",
3141
3144
  "reposUpdated": "Repositorios vinculados actualizados",
3142
3145
  "branchCreated": "Rama {name} creada",
@@ -3152,10 +3155,6 @@
3152
3155
  "createBranch": "No se pudo crear la rama",
3153
3156
  "openPr": "No se pudo abrir la solicitud de incorporación de cambios",
3154
3157
  "merge": "No se pudo fusionar"
3155
- },
3156
- "confirmDisconnect": {
3157
- "title": "¿Desconectar GitHub?",
3158
- "body": "La app perderá acceso a tus repositorios hasta que vuelvas a conectar."
3159
3158
  }
3160
3159
  },
3161
3160
  "addService": {
@@ -5176,5 +5175,40 @@
5176
5175
  "sourceUnlinked": "Fuente desvinculada",
5177
5176
  "unlinkSourceFailed": "No se pudo desvincular la fuente"
5178
5177
  }
5178
+ },
5179
+ "vcs": {
5180
+ "panel": {
5181
+ "title": "Control de código fuente",
5182
+ "patMeta": "Conectado con un token de acceso personal",
5183
+ "confirmDisconnect": {
5184
+ "title": "¿Desconectar {provider}?",
5185
+ "body": "La app perderá acceso a tus repositorios hasta que vuelvas a conectar."
5186
+ },
5187
+ "toast": {
5188
+ "disconnected": "{provider} desconectado"
5189
+ }
5190
+ },
5191
+ "connect": {
5192
+ "or": "o",
5193
+ "noneConfigured": "Este despliegue no tiene configurada ninguna conexión de control de código. Pide a un operador que configure una GitHub App o el acceso a GitLab.",
5194
+ "gitlab": {
5195
+ "intro": "Pega un token de acceso personal de GitLab para conectar este espacio de trabajo. cat-factory lo usa para listar tus proyectos, subir ramas y abrir solicitudes de fusión.",
5196
+ "tokenLabel": "Token de acceso personal",
5197
+ "scope": "Necesita el ámbito api",
5198
+ "createToken": "Crear un token en GitLab",
5199
+ "submit": "Conectar GitLab",
5200
+ "toast": {
5201
+ "connected": "GitLab conectado"
5202
+ },
5203
+ "errors": {
5204
+ "connect": "No se pudo conectar GitLab"
5205
+ }
5206
+ }
5207
+ },
5208
+ "onboarding": {
5209
+ "title": "Conecta cat-factory con {provider}",
5210
+ "titleAny": "Conecta cat-factory con tus repositorios",
5211
+ "intro": "cat-factory funciona abriendo solicitudes de incorporación de cambios en tus repositorios. Conecta tu proveedor de repositorios para continuar."
5212
+ }
5179
5213
  }
5180
5214
  }