@cat-factory/app 0.251.0 → 0.253.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.
@@ -1,6 +1,12 @@
1
1
  import { defineStore } from 'pinia'
2
- import { computed } from 'vue'
2
+ import { computed, ref } from 'vue'
3
3
  import type { Notification } from '~/types/domain'
4
+ import type {
5
+ NotificationRoutingMatrix,
6
+ NotificationSettings,
7
+ NotificationSettingsStatus,
8
+ } from '~/types/notifications'
9
+ import { ApiError } from '~/composables/api/errors'
4
10
  import type { ReviewEffort } from '~/types/merge'
5
11
  import { useUpsertList } from '~/composables/useUpsertList'
6
12
  import { useWorkspaceStore } from '~/stores/workspace'
@@ -109,5 +115,77 @@ export const useNotificationsStore = defineStore('notifications', () => {
109
115
  upsert(resolved)
110
116
  }
111
117
 
112
- return { open, hydrate, hydrateBaseline, upsert, byBlock, count, act, dismiss }
118
+ // ---- the notification manager (per-workspace channel routing) ------------
119
+ // Loaded on demand by the settings panel, never with the board: an inbox reader does not
120
+ // need the routing matrix, and the read 503s on a deployment with no routing store.
121
+
122
+ /** The workspace's routing settings, or null unless {@link settingsStatus} is `ready`. */
123
+ const settings = ref<NotificationSettings | null>(null)
124
+ /**
125
+ * How the last load ENDED, as four distinct states rather than a nullable boolean.
126
+ *
127
+ * `unavailable` and `failed` need different reactions and must not be collapsed: the first is
128
+ * settled ("this deployment wired no routing store"), the second is transient and leaves the
129
+ * board's real configuration UNKNOWN. A panel that cannot tell them apart renders the shipped
130
+ * defaults as though they were the board's own, and its save (a full replace) then writes
131
+ * that guess over whatever was stored.
132
+ */
133
+ const settingsStatus = ref<NotificationSettingsStatus>('unloaded')
134
+ const savingSettings = ref(false)
135
+
136
+ async function loadSettings() {
137
+ const ws = useWorkspaceStore()
138
+ settingsStatus.value = 'loading'
139
+ try {
140
+ settings.value = await api.getNotificationSettings(ws.requireId())
141
+ settingsStatus.value = 'ready'
142
+ } catch (error) {
143
+ settings.value = null
144
+ // A 503 is the opt-in shape (no routing store wired), not a failure to report: the panel
145
+ // renders the shipped defaults read-only. Anything else is a real error, which the panel
146
+ // states as such AND the caller still sees, so the server's own message reaches the toast.
147
+ if (isUnavailable(error)) {
148
+ settingsStatus.value = 'unavailable'
149
+ return
150
+ }
151
+ settingsStatus.value = 'failed'
152
+ throw error
153
+ }
154
+ }
155
+
156
+ /** Replace the routing overrides (a full replace; dropping a cell restores its default). */
157
+ async function updateSettings(matrix: NotificationRoutingMatrix) {
158
+ const ws = useWorkspaceStore()
159
+ savingSettings.value = true
160
+ try {
161
+ settings.value = await api.updateNotificationSettings(ws.requireId(), matrix)
162
+ } finally {
163
+ savingSettings.value = false
164
+ }
165
+ }
166
+
167
+ return {
168
+ open,
169
+ hydrate,
170
+ hydrateBaseline,
171
+ upsert,
172
+ byBlock,
173
+ count,
174
+ act,
175
+ dismiss,
176
+ settings,
177
+ settingsStatus,
178
+ savingSettings,
179
+ loadSettings,
180
+ updateSettings,
181
+ }
113
182
  })
183
+
184
+ /**
185
+ * Whether a failed load is the SETTLED "you can't have this" — the facade wired no routing store
186
+ * (503), rather than a transient fault. Only that resolves to `unavailable`; everything else
187
+ * becomes `failed` and propagates, so a later visit retries and the caller can report it.
188
+ */
189
+ function isUnavailable(error: unknown): boolean {
190
+ return error instanceof ApiError && error.statusCode === 503
191
+ }
@@ -472,6 +472,10 @@ function createIntegrationPanelModals(resetHubReturn: ResetHubReturn) {
472
472
  const githubOpen = ref(false)
473
473
  // Slack integration panel (connect the account's Slack + per-workspace routing).
474
474
  const slackOpen = ref(false)
475
+ // The notification manager: which notification types this board delivers on which channel
476
+ // (the in-app push and email). Distinct from `slackOpen`, which configures Slack's
477
+ // DESTINATION per type — this one decides the channels whose delivery is a plain yes/no.
478
+ const notificationSettingsOpen = ref(false)
475
479
  // Observability integration: the post-release-health connection panel (Datadog
476
480
  // today, pluggable). NB: distinct from `observabilityInstanceId`, which is the
477
481
  // LLM per-call observability panel (see the result-views slice).
@@ -516,6 +520,13 @@ function createIntegrationPanelModals(resetHubReturn: ResetHubReturn) {
516
520
  function closeSlack() {
517
521
  slackOpen.value = false
518
522
  }
523
+ function openNotificationSettings() {
524
+ resetHubReturn()
525
+ notificationSettingsOpen.value = true
526
+ }
527
+ function closeNotificationSettings() {
528
+ notificationSettingsOpen.value = false
529
+ }
519
530
  function openObservabilityConnection() {
520
531
  resetHubReturn()
521
532
  observabilityConnectionOpen.value = true
@@ -586,6 +597,7 @@ function createIntegrationPanelModals(resetHubReturn: ResetHubReturn) {
586
597
  return {
587
598
  githubOpen,
588
599
  slackOpen,
600
+ notificationSettingsOpen,
589
601
  observabilityConnectionOpen,
590
602
  operatorDashboardOpen,
591
603
  reportsOpen,
@@ -600,6 +612,8 @@ function createIntegrationPanelModals(resetHubReturn: ResetHubReturn) {
600
612
  closeGitHub,
601
613
  openSlack,
602
614
  closeSlack,
615
+ openNotificationSettings,
616
+ closeNotificationSettings,
603
617
  openObservabilityConnection,
604
618
  closeObservabilityConnection,
605
619
  openOperatorDashboard,
@@ -104,6 +104,10 @@ export type {
104
104
  HumanTestStepState,
105
105
  VisualConfirmStepState,
106
106
  VisualConfirmPair,
107
+ VisualConfirmReferenceOrigin,
108
+ VisualConfirmDesignGap,
109
+ VisualConfirmDesignGapReason,
110
+ VisualConfirmDesignReferences,
107
111
  VisualConfirmRound,
108
112
  ExecutionInstance,
109
113
  // The historical frontend name for a per-block review comment is the contract's
@@ -8,6 +8,10 @@
8
8
 
9
9
  export type {
10
10
  NotificationType,
11
+ NotificationDeliveryChannel,
12
+ NotificationChannelOverrides,
13
+ NotificationRoutingMatrix,
14
+ NotificationSettings,
11
15
  NotificationStatus,
12
16
  OnCallRecommendation,
13
17
  OnCallAssessment,
@@ -16,3 +20,17 @@ export type {
16
20
  Notification,
17
21
  ReleaseSignalWire as ReleaseSignal,
18
22
  } from '@cat-factory/contracts'
23
+
24
+ /**
25
+ * How the notification-manager settings load ENDED. Client-only (it describes the fetch, not a
26
+ * wire shape), and deliberately four states rather than a nullable boolean:
27
+ *
28
+ * - `unloaded` / `loading`: nothing to render a grid from yet.
29
+ * - `ready`: `settings` holds the board's own matrix.
30
+ * - `unavailable`: SETTLED. This deployment wired no routing store, so the shipped defaults are
31
+ * the whole truth and there is nothing to edit.
32
+ * - `failed`: the read broke, so the board's configuration is UNKNOWN. Distinct from
33
+ * `unavailable` because the panel must not offer a save: the write is a full replace, and
34
+ * saving a grid built from defaults would overwrite overrides nobody looked at.
35
+ */
36
+ export type NotificationSettingsStatus = 'unloaded' | 'loading' | 'ready' | 'unavailable' | 'failed'
@@ -2181,8 +2181,11 @@
2181
2181
  "fs": "Lokales Dateisystem",
2182
2182
  "s3": "Amazon S3 / S3-kompatibel",
2183
2183
  "r2": "Cloudflare R2",
2184
- "db": "Postgres-Datenbank"
2184
+ "db": "Postgres-Datenbank",
2185
+ "custom": "Eigener Speicher (dieses Deployment)"
2185
2186
  },
2187
+ "unregisteredStore": "{store} (in diesem Deployment nicht registriert)",
2188
+ "unregisteredStoreWarning": "Dieses Konto speichert Artefakte in „{store}“, was dieses Deployment nicht registriert. Es wird nichts gespeichert, bis Sie einen registrierten Speicher wählen oder der Speicher wieder im Code registriert wird.",
2186
2189
  "basePath": "Basispfad (Standard: .file-storage)",
2187
2190
  "region": "Region (z. B. us-east-1)",
2188
2191
  "bucket": "Bucket",
@@ -2495,7 +2498,8 @@
2495
2498
  "shortcuts": "Tastenkürzel",
2496
2499
  "bugHunt": "Fehlerjagd",
2497
2500
  "toggleUiMode": "Oberflächenmodus wechseln",
2498
- "foundationalServices": "Basisdienste"
2501
+ "foundationalServices": "Basisdienste",
2502
+ "notificationSettings": "Benachrichtigungs-Routing verwalten"
2499
2503
  },
2500
2504
  "keywords": {
2501
2505
  "newPipeline": "pipeline agents chain",
@@ -2519,7 +2523,8 @@
2519
2523
  "bugHunt": "fehler bug jagd triage backlog tracker nicht zugewiesen",
2520
2524
  "toggleUiMode": "oberfläche modus einfach erweitert anzeigen ausblenden",
2521
2525
  "tutorial": "tutorial tour einführung hilfe onboarding lernen grundlagen",
2522
- "foundationalServices": "gemeinsame Fähigkeit Plattform Dienst API Vertrag OpenAPI Katalog"
2526
+ "foundationalServices": "gemeinsame Fähigkeit Plattform Dienst API Vertrag OpenAPI Katalog",
2527
+ "notificationSettings": "benachrichtigungen e-mail routing kanäle posteingang"
2523
2528
  }
2524
2529
  },
2525
2530
  "shortcuts": {
@@ -2596,6 +2601,10 @@
2596
2601
  "bugHunt": {
2597
2602
  "label": "Fehlerjagd",
2598
2603
  "description": "Offene, nicht zugewiesene Fehler eines Boards bewerten und einen zum Beheben auswählen"
2604
+ },
2605
+ "notificationSettings": {
2606
+ "label": "Benachrichtigungen",
2607
+ "description": "Wählen Sie, welche Ereignisse den Posteingang und E-Mails erreichen."
2599
2608
  }
2600
2609
  }
2601
2610
  },
@@ -5470,7 +5479,8 @@
5470
5479
  "description": {
5471
5480
  "binary_generators_unreachable": "Die generativen Integrationen dieser Installation konnten gerade nicht gelesen werden, deshalb wurde der Lauf nicht gestartet. Es ist nichts falsch konfiguriert und keine Änderung nötig: versuchen Sie es erneut, sobald die Verbindung wieder steht.",
5472
5481
  "foundational_builtins_unreachable": "Die integrierten Basisdienste dieser Installation konnten gerade nicht gelesen werden. Es ist nichts falsch konfiguriert und keine Änderung nötig: versuchen Sie es erneut, sobald die Verbindung wieder steht.",
5473
- "connection_credentials_unreadable": "Die gespeicherten Zugangsdaten dieser Verbindung konnten nicht gelesen werden. Wenn diese Installation den Dienst mit dem zugehörigen Schlüssel erreicht, verbinden Sie die Quelle neu, um sie zu ersetzen; andernfalls versuchen Sie es erneut, sobald diese Verbindung wiederhergestellt ist."
5482
+ "connection_credentials_unreadable": "Die gespeicherten Zugangsdaten dieser Verbindung konnten nicht gelesen werden. Wenn diese Installation den Dienst mit dem zugehörigen Schlüssel erreicht, verbinden Sie die Quelle neu, um sie zu ersetzen; andernfalls versuchen Sie es erneut, sobald diese Verbindung wiederhergestellt ist.",
5483
+ "vcs_capability_unsupported": "Der mit diesem Workspace verbundene Quellcode-Anbieter bietet diesen Vorgang nicht an. Es ist nichts falsch konfiguriert und eine Einrichtung hilft hier nicht: Für diesen Anbieter ist der Vorgang nicht verfügbar."
5474
5484
  }
5475
5485
  },
5476
5486
  "action": {
@@ -5677,6 +5687,58 @@
5677
5687
  "body": "Slack-Benachrichtigungen werden gestoppt, bis du die Verbindung wiederherstellst."
5678
5688
  }
5679
5689
  },
5690
+ "notificationSettings": {
5691
+ "panel": {
5692
+ "title": "Benachrichtigungen",
5693
+ "intro": "Wählen Sie, welche Ereignisse dieses Board zustellt und über welchen Kanal. Nicht geänderte Einträge verwenden die Voreinstellung.",
5694
+ "inAppNote": "„In der App“ steuert nur die Live-Benachrichtigung. Die Karte wird ohnehin gespeichert und bleibt nach dem Neuladen im Posteingang.",
5695
+ "emailNote": "E-Mail erfordert einen für das Konto verbundenen Versanddienst (Kontoeinstellungen). Standardmäßig werden nur besonders wichtige Ereignisse verschickt.",
5696
+ "otherChannelsNote": "Slack und ausgehende Webhooks wählen ihre Ereignisliste dort, wo ihr Ziel konfiguriert wird.",
5697
+ "openSlack": "Slack-Routing"
5698
+ },
5699
+ "column": {
5700
+ "event": "Ereignis",
5701
+ "inApp": "In der App",
5702
+ "email": "E-Mail"
5703
+ },
5704
+ "action": {
5705
+ "save": "Speichern",
5706
+ "reset": "Standard wiederherstellen"
5707
+ },
5708
+ "toast": {
5709
+ "saved": "Benachrichtigungs-Routing gespeichert"
5710
+ },
5711
+ "error": {
5712
+ "load": "Benachrichtigungseinstellungen konnten nicht geladen werden",
5713
+ "save": "Benachrichtigungseinstellungen konnten nicht gespeichert werden"
5714
+ },
5715
+ "unavailable": "Diese Installation speichert kein Benachrichtigungs-Routing; alle Ereignisse verwenden die Voreinstellung.",
5716
+ "loadFailed": "Das Benachrichtigungs-Routing dieses Boards konnte nicht gelesen werden. Die Schalter unten zeigen daher nicht die aktuellen Einstellungen. Bitte erneut versuchen, bevor Sie etwas ändern.",
5717
+ "type": {
5718
+ "merge_review": "Merge-Review",
5719
+ "pipeline_complete": "Pipeline abgeschlossen",
5720
+ "ci_failed": "CI fehlgeschlagen",
5721
+ "test_failed": "Tests fehlgeschlagen",
5722
+ "requirement_review": "Anforderungs-Review",
5723
+ "clarity_review": "Klarheits-Review",
5724
+ "release_regression": "Release-Regression",
5725
+ "decision_required": "Entscheidung erforderlich",
5726
+ "human_test_ready": "Bereit für manuelle Tests",
5727
+ "visual_confirmation_ready": "Bereit für visuelle Bestätigung",
5728
+ "human_review": "Wartet auf Code-Review",
5729
+ "followup_pending": "Offene Folgepunkte",
5730
+ "fork_decision_pending": "Umsetzungsansatz",
5731
+ "judge_review": "Prüfurteil",
5732
+ "pr_review_ready": "PR-Review-Befunde",
5733
+ "initiative": "Initiativen-Updates",
5734
+ "platform_health": "Plattformzustand",
5735
+ "infra_unreachable": "Infrastrukturausfälle",
5736
+ "budget_paused": "Läufe pausiert (Budget)",
5737
+ "budget_threshold": "Budgetwarnung",
5738
+ "key_drift": "Abweichung des Verschlüsselungsschlüssels",
5739
+ "merge_tag_request": "Review-Aufwand angefragt"
5740
+ }
5741
+ },
5680
5742
  "docInterview": {
5681
5743
  "title": "Das Dokument verfeinern",
5682
5744
  "subtitle": "Beantworte die Fragen des Interviewers, damit er das Dokument formen kann",
@@ -6153,6 +6215,19 @@
6153
6215
  "history": {
6154
6216
  "heading": "Verlauf (keine Runden) | Verlauf ({count} Runde) | Verlauf ({count} Runden)",
6155
6217
  "fixRequested": "Korrektur angefordert"
6218
+ },
6219
+ "design": {
6220
+ "summary": "Keine Frames stammen aus dem verknüpften Design. | 1 Frame aus dem verknüpften Design. | {count} Frames aus dem verknüpften Design.",
6221
+ "dropped": "Es sind keine weiteren ausgeblendet. | 1 weiterer wird hier nicht angezeigt. | {count} weitere werden hier nicht angezeigt.",
6222
+ "gapDropped": "Keiner seiner Frames ist ausgeblendet. | 1 seiner Frames wird hier nicht angezeigt. | {count} seiner Frames werden hier nicht angezeigt.",
6223
+ "gapLine": "{title}:",
6224
+ "gap": {
6225
+ "partial": "nur ein Teil seiner Frames wurde gespeichert; aktualisiere das Dokument, um es erneut zu versuchen.",
6226
+ "failed": "seine Frames konnten beim letzten Import nicht geladen werden; aktualisiere das Dokument, um es erneut zu versuchen.",
6227
+ "none": "es enthält keine Frames zum Anzeigen.",
6228
+ "storage_unavailable": "beim Import war kein Bildspeicher konfiguriert, daher wurde nichts heruntergeladen.",
6229
+ "not_retained": "es sind keine Bilder dazu gespeichert. Die Quelle rendert möglicherweise keine Frames, oder das Dokument wurde importiert, bevor Frames aufbewahrt wurden; ein erneuter Import zeigt, was zutrifft."
6230
+ }
6156
6231
  }
6157
6232
  },
6158
6233
  "outcome": {
@@ -6399,6 +6474,7 @@
6399
6474
  },
6400
6475
  "actual": "Tatsächlich",
6401
6476
  "reference": "Referenz",
6477
+ "fromLinkedDesign": "· aus dem verknüpften Design",
6402
6478
  "actualAlt": "{view} (tatsächlich)",
6403
6479
  "referenceAlt": "{view} (Referenz)",
6404
6480
  "replace": "Ersetzen",
@@ -593,7 +593,8 @@
593
593
  "description": {
594
594
  "binary_generators_unreachable": "This deployment's generative integrations could not be read just now, so the run was not started. Nothing is misconfigured and no change is needed: try again once the connection recovers.",
595
595
  "foundational_builtins_unreachable": "This deployment's built-in foundational services could not be read just now. Nothing is misconfigured and no change is needed: try again once the connection recovers.",
596
- "connection_credentials_unreadable": "The stored credentials for this connection could not be read. If this deployment can reach the service holding its key, re-connect the source to replace them; otherwise try again once that connection recovers."
596
+ "connection_credentials_unreadable": "The stored credentials for this connection could not be read. If this deployment can reach the service holding its key, re-connect the source to replace them; otherwise try again once that connection recovers.",
597
+ "vcs_capability_unsupported": "The source-control provider connected to this workspace does not offer this operation. Nothing is misconfigured and setting something up will not help: it is unavailable for this provider."
597
598
  }
598
599
  },
599
600
  "action": {
@@ -2127,8 +2128,11 @@
2127
2128
  "fs": "Local filesystem",
2128
2129
  "s3": "Amazon S3 / S3-compatible",
2129
2130
  "r2": "Cloudflare R2",
2130
- "db": "Postgres database"
2131
+ "db": "Postgres database",
2132
+ "custom": "Custom store (this deployment)"
2131
2133
  },
2134
+ "unregisteredStore": "{store} (not registered on this deployment)",
2135
+ "unregisteredStoreWarning": "This account stores artifacts in “{store}”, which this deployment does not register. Nothing is being stored until you pick a registered store or the store is registered again in code.",
2132
2136
  "basePath": "Base path (default: .file-storage)",
2133
2137
  "region": "Region (e.g. us-east-1)",
2134
2138
  "bucket": "Bucket",
@@ -2441,7 +2445,8 @@
2441
2445
  "shortcuts": "Keyboard shortcuts",
2442
2446
  "bugHunt": "Bug hunt",
2443
2447
  "toggleUiMode": "Switch interface mode",
2444
- "foundationalServices": "Foundational services"
2448
+ "foundationalServices": "Foundational services",
2449
+ "notificationSettings": "Manage notification routing"
2445
2450
  },
2446
2451
  "keywords": {
2447
2452
  "newPipeline": "pipeline agents chain",
@@ -2465,7 +2470,8 @@
2465
2470
  "bugHunt": "bug hunt triage backlog issue tracker unassigned",
2466
2471
  "toggleUiMode": "interface mode basic advanced simple expert show hide",
2467
2472
  "tutorial": "tutorial onboarding tour guide help learn basics",
2468
- "foundationalServices": "shared capability platform service api contract openapi catalog"
2473
+ "foundationalServices": "shared capability platform service api contract openapi catalog",
2474
+ "notificationSettings": "notifications email routing channels inbox"
2469
2475
  }
2470
2476
  },
2471
2477
  "shortcuts": {
@@ -2542,6 +2548,10 @@
2542
2548
  "bugHunt": {
2543
2549
  "label": "Bug hunt",
2544
2550
  "description": "Rate a board's open, unassigned bugs and pick one to fix"
2551
+ },
2552
+ "notificationSettings": {
2553
+ "label": "Notifications",
2554
+ "description": "Choose which events reach the inbox and email."
2545
2555
  }
2546
2556
  }
2547
2557
  },
@@ -4356,6 +4366,58 @@
4356
4366
  "body": "Slack notifications will stop until you reconnect."
4357
4367
  }
4358
4368
  },
4369
+ "notificationSettings": {
4370
+ "panel": {
4371
+ "title": "Notifications",
4372
+ "intro": "Choose which events this board delivers, and on which channel. Anything left untouched uses the shipped default.",
4373
+ "inAppNote": "In-app controls the live push. The card is saved either way, so it is still in your inbox after a reload.",
4374
+ "emailNote": "Email needs a sender connected for the account (Account settings). By default only high-impact events are mailed.",
4375
+ "otherChannelsNote": "Slack and outbound webhooks pick their own event list where their destination is configured.",
4376
+ "openSlack": "Slack routing"
4377
+ },
4378
+ "column": {
4379
+ "event": "Event",
4380
+ "inApp": "In-app",
4381
+ "email": "Email"
4382
+ },
4383
+ "action": {
4384
+ "save": "Save",
4385
+ "reset": "Restore defaults"
4386
+ },
4387
+ "toast": {
4388
+ "saved": "Notification routing saved"
4389
+ },
4390
+ "error": {
4391
+ "load": "Could not load notification settings",
4392
+ "save": "Could not save notification settings"
4393
+ },
4394
+ "unavailable": "This deployment stores no notification routing, so every event uses the shipped default.",
4395
+ "loadFailed": "Could not read this board's notification routing, so the switches below are not its current settings. Retry before changing anything.",
4396
+ "type": {
4397
+ "merge_review": "Merge review",
4398
+ "pipeline_complete": "Pipeline complete",
4399
+ "ci_failed": "CI failed",
4400
+ "test_failed": "Tests failed",
4401
+ "requirement_review": "Requirement review",
4402
+ "clarity_review": "Clarity review",
4403
+ "release_regression": "Release regression",
4404
+ "decision_required": "Decision needed",
4405
+ "human_test_ready": "Ready for human testing",
4406
+ "visual_confirmation_ready": "Ready for visual confirmation",
4407
+ "human_review": "Awaiting code review",
4408
+ "followup_pending": "Follow-ups to decide",
4409
+ "fork_decision_pending": "Implementation approach",
4410
+ "judge_review": "Review verdict",
4411
+ "pr_review_ready": "PR review findings",
4412
+ "initiative": "Initiative updates",
4413
+ "platform_health": "Platform health",
4414
+ "infra_unreachable": "Infrastructure outages",
4415
+ "budget_paused": "Runs paused (budget)",
4416
+ "budget_threshold": "Budget warning",
4417
+ "key_drift": "Encryption-key drift",
4418
+ "merge_tag_request": "Review-effort tag requested"
4419
+ }
4420
+ },
4359
4421
  "docInterview": {
4360
4422
  "title": "Refine the document",
4361
4423
  "subtitle": "Answer the interviewer's questions so it can shape the document",
@@ -5866,6 +5928,19 @@
5866
5928
  "history": {
5867
5929
  "heading": "History (no rounds) | History ({count} round) | History ({count} rounds)",
5868
5930
  "fixRequested": "Fix requested"
5931
+ },
5932
+ "design": {
5933
+ "summary": "No frames came from the linked design. | 1 frame from the linked design. | {count} frames from the linked design.",
5934
+ "dropped": "No others are hidden. | 1 more is not shown here. | {count} more are not shown here.",
5935
+ "gapDropped": "None of its frames are hidden. | 1 of its frames is not shown here. | {count} of its frames are not shown here.",
5936
+ "gapLine": "{title}:",
5937
+ "gap": {
5938
+ "partial": "only part of its frames were retained; refresh the document to try again.",
5939
+ "failed": "its frames could not be downloaded at the last import; refresh the document to retry.",
5940
+ "none": "it has no frames to show.",
5941
+ "storage_unavailable": "no image storage was configured when it was imported, so nothing was downloaded.",
5942
+ "not_retained": "no images are held for it. Its source may not render frames, or it was imported before frames were kept; re-importing tells the two apart."
5943
+ }
5869
5944
  }
5870
5945
  },
5871
5946
  "outcome": {
@@ -6118,6 +6193,7 @@
6118
6193
  },
6119
6194
  "actual": "Actual",
6120
6195
  "reference": "Reference",
6196
+ "fromLinkedDesign": "· from the linked design",
6121
6197
  "actualAlt": "{view} (actual)",
6122
6198
  "referenceAlt": "{view} (reference)",
6123
6199
  "replace": "Replace",
@@ -530,7 +530,8 @@
530
530
  "description": {
531
531
  "binary_generators_unreachable": "No se han podido leer las integraciones generativas de esta instalación en este momento, así que no se ha iniciado la ejecución. No hay nada mal configurado ni hace falta ningún cambio: inténtalo de nuevo cuando se restablezca la conexión.",
532
532
  "foundational_builtins_unreachable": "No se han podido leer los servicios fundamentales integrados de esta instalación en este momento. No hay nada mal configurado ni hace falta ningún cambio: inténtalo de nuevo cuando se restablezca la conexión.",
533
- "connection_credentials_unreadable": "No se han podido leer las credenciales guardadas de esta conexión. Si esta instalación puede acceder al servicio que custodia su clave, vuelve a conectar la fuente para reemplazarlas; si no, inténtalo de nuevo cuando se restablezca esa conexión."
533
+ "connection_credentials_unreadable": "No se han podido leer las credenciales guardadas de esta conexión. Si esta instalación puede acceder al servicio que custodia su clave, vuelve a conectar la fuente para reemplazarlas; si no, inténtalo de nuevo cuando se restablezca esa conexión.",
534
+ "vcs_capability_unsupported": "El proveedor de control de código conectado a este espacio de trabajo no ofrece esta operación. No hay nada mal configurado y configurar algo no servirá de nada: no está disponible para este proveedor."
534
535
  }
535
536
  },
536
537
  "action": {
@@ -2020,8 +2021,11 @@
2020
2021
  "fs": "Sistema de archivos local",
2021
2022
  "s3": "Amazon S3 / compatible con S3",
2022
2023
  "r2": "Cloudflare R2",
2023
- "db": "Base de datos Postgres"
2024
+ "db": "Base de datos Postgres",
2025
+ "custom": "Almacén propio (este despliegue)"
2024
2026
  },
2027
+ "unregisteredStore": "{store} (no registrado en este despliegue)",
2028
+ "unregisteredStoreWarning": "Esta cuenta guarda los artefactos en «{store}», que este despliegue no registra. No se guarda nada hasta que elijas un almacén registrado o vuelvas a registrarlo en el código.",
2025
2029
  "basePath": "Ruta base (predeterminada: .file-storage)",
2026
2030
  "region": "Región (p. ej. us-east-1)",
2027
2031
  "bucket": "Bucket",
@@ -2334,7 +2338,8 @@
2334
2338
  "shortcuts": "Atajos de teclado",
2335
2339
  "bugHunt": "Caza de errores",
2336
2340
  "toggleUiMode": "Cambiar el modo de interfaz",
2337
- "foundationalServices": "Servicios fundamentales"
2341
+ "foundationalServices": "Servicios fundamentales",
2342
+ "notificationSettings": "Gestionar el enrutamiento de notificaciones"
2338
2343
  },
2339
2344
  "keywords": {
2340
2345
  "newPipeline": "canalización agentes cadena pipeline",
@@ -2358,7 +2363,8 @@
2358
2363
  "bugHunt": "error bug caza triaje backlog incidencias sin asignar",
2359
2364
  "toggleUiMode": "interfaz modo básico avanzado mostrar ocultar",
2360
2365
  "tutorial": "tutorial recorrido guía ayuda aprender introducción",
2361
- "foundationalServices": "capacidad compartida plataforma servicio api contrato openapi catálogo"
2366
+ "foundationalServices": "capacidad compartida plataforma servicio api contrato openapi catálogo",
2367
+ "notificationSettings": "notificaciones correo enrutamiento canales bandeja"
2362
2368
  }
2363
2369
  },
2364
2370
  "integrationsHub": {
@@ -2428,6 +2434,10 @@
2428
2434
  "bugHunt": {
2429
2435
  "label": "Caza de errores",
2430
2436
  "description": "Valora los errores abiertos y sin asignar de un tablero y elige uno para arreglar"
2437
+ },
2438
+ "notificationSettings": {
2439
+ "label": "Notificaciones",
2440
+ "description": "Elige qué eventos llegan a la bandeja y al correo."
2431
2441
  }
2432
2442
  }
2433
2443
  },
@@ -4219,6 +4229,58 @@
4219
4229
  "body": "Las notificaciones de Slack se detendrán hasta que vuelvas a conectar."
4220
4230
  }
4221
4231
  },
4232
+ "notificationSettings": {
4233
+ "panel": {
4234
+ "title": "Notificaciones",
4235
+ "intro": "Elige qué eventos entrega este tablero y por qué canal. Lo que no cambies usa el valor predeterminado.",
4236
+ "inAppNote": "«En la app» controla solo el aviso en vivo. La tarjeta se guarda igualmente y sigue en tu bandeja tras recargar.",
4237
+ "emailNote": "El correo requiere un remitente conectado en la cuenta (Ajustes de cuenta). De forma predeterminada solo se envían los eventos de alto impacto.",
4238
+ "otherChannelsNote": "Slack y los webhooks salientes eligen su propia lista de eventos donde se configura su destino.",
4239
+ "openSlack": "Enrutamiento de Slack"
4240
+ },
4241
+ "column": {
4242
+ "event": "Evento",
4243
+ "inApp": "En la app",
4244
+ "email": "Correo"
4245
+ },
4246
+ "action": {
4247
+ "save": "Guardar",
4248
+ "reset": "Restaurar valores predeterminados"
4249
+ },
4250
+ "toast": {
4251
+ "saved": "Enrutamiento de notificaciones guardado"
4252
+ },
4253
+ "error": {
4254
+ "load": "No se pudieron cargar los ajustes de notificaciones",
4255
+ "save": "No se pudieron guardar los ajustes de notificaciones"
4256
+ },
4257
+ "unavailable": "Esta instalación no almacena enrutamiento de notificaciones, así que todos los eventos usan el valor predeterminado.",
4258
+ "loadFailed": "No se pudo leer el enrutamiento de notificaciones de este tablero, así que los interruptores de abajo no son su configuración actual. Vuelve a intentarlo antes de cambiar nada.",
4259
+ "type": {
4260
+ "merge_review": "Revision de fusion",
4261
+ "pipeline_complete": "Pipeline completado",
4262
+ "ci_failed": "CI fallido",
4263
+ "test_failed": "Pruebas fallidas",
4264
+ "requirement_review": "Revision de requisitos",
4265
+ "clarity_review": "Revision de claridad",
4266
+ "release_regression": "Regresion de version",
4267
+ "decision_required": "Decisión necesaria",
4268
+ "human_test_ready": "Listo para pruebas humanas",
4269
+ "visual_confirmation_ready": "Listo para confirmacion visual",
4270
+ "human_review": "Esperando revisión de código",
4271
+ "followup_pending": "Seguimientos por decidir",
4272
+ "fork_decision_pending": "Enfoque de implementación",
4273
+ "judge_review": "Veredicto de revisión",
4274
+ "pr_review_ready": "Hallazgos de revisión de PR",
4275
+ "initiative": "Actualizaciones de la iniciativa",
4276
+ "platform_health": "Estado de la plataforma",
4277
+ "infra_unreachable": "Interrupciones de infraestructura",
4278
+ "budget_paused": "Ejecuciones en pausa (presupuesto)",
4279
+ "budget_threshold": "Aviso de presupuesto",
4280
+ "key_drift": "Desfase de la clave de cifrado",
4281
+ "merge_tag_request": "Solicitud de esfuerzo de revisión"
4282
+ }
4283
+ },
4222
4284
  "docInterview": {
4223
4285
  "title": "Refinar el documento",
4224
4286
  "subtitle": "Responde a las preguntas del entrevistador para dar forma al documento",
@@ -5597,6 +5659,19 @@
5597
5659
  "history": {
5598
5660
  "heading": "Historial (sin rondas) | Historial ({count} ronda) | Historial ({count} rondas)",
5599
5661
  "fixRequested": "Corrección solicitada"
5662
+ },
5663
+ "design": {
5664
+ "summary": "Ningún marco procede del diseño vinculado. | 1 marco del diseño vinculado. | {count} marcos del diseño vinculado.",
5665
+ "dropped": "No hay otros ocultos. | 1 más no se muestra aquí. | {count} más no se muestran aquí.",
5666
+ "gapDropped": "Ninguno de sus marcos está oculto. | 1 de sus marcos no se muestra aquí. | {count} de sus marcos no se muestran aquí.",
5667
+ "gapLine": "{title}:",
5668
+ "gap": {
5669
+ "partial": "solo se conservó parte de sus marcos; actualiza el documento para volver a intentarlo.",
5670
+ "failed": "no se pudieron descargar sus marcos en la última importación; actualiza el documento para reintentarlo.",
5671
+ "none": "no tiene marcos que mostrar.",
5672
+ "storage_unavailable": "no había almacenamiento de imágenes configurado cuando se importó, así que no se descargó nada.",
5673
+ "not_retained": "no hay imágenes guardadas para él. Puede que su origen no genere marcos, o que se importara antes de que se conservaran; volver a importarlo lo aclara."
5674
+ }
5600
5675
  }
5601
5676
  },
5602
5677
  "outcome": {
@@ -5843,6 +5918,7 @@
5843
5918
  },
5844
5919
  "actual": "Real",
5845
5920
  "reference": "Referencia",
5921
+ "fromLinkedDesign": "· del diseño vinculado",
5846
5922
  "actualAlt": "{view} (real)",
5847
5923
  "referenceAlt": "{view} (referencia)",
5848
5924
  "replace": "Reemplazar",