feat(studio): MCP suggestions + Approvals/Audit/Settings i18n (v0.26.0)

- Add curated catalogue of 9 official Anthropic MCP servers as
  click-to-prefill chips in the Add-MCP-server dialog. Operator
  still confirms via "Add + discover"; nothing is auto-spawned,
  preserving the regulated-environment trust model.
- Localize Approvals page: pending/history empty states, status
  pills, payload preview, approve/reject toasts, reject dialog,
  history detail dialog, expires-in pill.
- Localize Audit page: filter chips, clear-log dialog and toasts,
  no-events / hub-unreachable empty states, live-status bar with
  pluralized event count, hash-chain-verified badge, System AI
  panel (cached pill, latency, regenerate tooltip, asking
  state), event-detail dialog actions.
- Localize Settings dialog: hub-endpoint section, channel
  blurb + popup-menu items, System AI panel headers and
  off-blurb, MCP/N8N panel headers + pluralized counts +
  refresh/add/remove tooltips, Add-MCP and Add-n8n dialogs
  (intro, suggestions label, all field labels and hints, save
  buttons, toasts).

Field labels that map directly to JSON keys (event_id, flow,
step, module, provider, endpoint, model) stay English by design
— they're technical identifiers, not UI copy.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-05-08 02:38:11 +02:00
parent 349619d68e
commit d25b4c87ae
9 changed files with 2022 additions and 209 deletions

View file

@ -284,6 +284,288 @@ abstract class AppLocalizations {
/// **'App language. Affects every page; bilingual store entries also flip via this toggle.'**
String get settingsLanguageHint;
/// No description provided for @settingsHubEndpointHint.
///
/// In en, this message translates to:
/// **'Where should Studio connect? Default is the local hub at 127.0.0.1:50051.'**
String get settingsHubEndpointHint;
/// No description provided for @settingsTlsSubtitle.
///
/// In en, this message translates to:
/// **'https/grpc-secure'**
String get settingsTlsSubtitle;
/// No description provided for @settingsPortError.
///
/// In en, this message translates to:
/// **'port must be 165535'**
String get settingsPortError;
/// No description provided for @channelsBlurb.
///
/// In en, this message translates to:
/// **'Switch hub channel (writes ~/.fai/current-channel and restarts the daemon). Connect just changes Studio\'s wire.'**
String get channelsBlurb;
/// No description provided for @channelsActionsTooltip.
///
/// In en, this message translates to:
/// **'Channel actions'**
String get channelsActionsTooltip;
/// No description provided for @systemAiHeader.
///
/// In en, this message translates to:
/// **'SYSTEM AI'**
String get systemAiHeader;
/// No description provided for @systemAiEnabled.
///
/// In en, this message translates to:
/// **'enabled'**
String get systemAiEnabled;
/// No description provided for @systemAiOff.
///
/// In en, this message translates to:
/// **'off'**
String get systemAiOff;
/// No description provided for @systemAiEdit.
///
/// In en, this message translates to:
/// **'Edit…'**
String get systemAiEdit;
/// No description provided for @systemAiConfigure.
///
/// In en, this message translates to:
/// **'Configure…'**
String get systemAiConfigure;
/// No description provided for @systemAiOffBlurb.
///
/// In en, this message translates to:
/// **'Off — failure explanations on the audit page are disabled. Click Configure… to pick a provider (Ollama / OpenAI / LM Studio / vLLM / Custom). Operator config is rewritten in place; no daemon restart needed.'**
String get systemAiOffBlurb;
/// No description provided for @mcpServersCount.
///
/// In en, this message translates to:
/// **'{n} {n, plural, =1{server} other{servers}}'**
String mcpServersCount(int n);
/// No description provided for @mcpRediscoverTooltip.
///
/// In en, this message translates to:
/// **'Re-run discovery'**
String get mcpRediscoverTooltip;
/// No description provided for @mcpAddTooltip.
///
/// In en, this message translates to:
/// **'Add MCP server'**
String get mcpAddTooltip;
/// No description provided for @mcpRemoveTooltip.
///
/// In en, this message translates to:
/// **'Remove server'**
String get mcpRemoveTooltip;
/// No description provided for @mcpToolsCount.
///
/// In en, this message translates to:
/// **'{n} {n, plural, =1{tool} other{tools}}'**
String mcpToolsCount(int n);
/// No description provided for @n8nEndpointsCount.
///
/// In en, this message translates to:
/// **'{n} {n, plural, =1{endpoint} other{endpoints}}'**
String n8nEndpointsCount(int n);
/// No description provided for @n8nWorkflowsCount.
///
/// In en, this message translates to:
/// **'{n} {n, plural, =1{workflow} other{workflows}}'**
String n8nWorkflowsCount(int n);
/// No description provided for @n8nRediscoverTooltip.
///
/// In en, this message translates to:
/// **'Re-run discovery'**
String get n8nRediscoverTooltip;
/// No description provided for @n8nAddTooltip.
///
/// In en, this message translates to:
/// **'Add n8n endpoint'**
String get n8nAddTooltip;
/// No description provided for @n8nRemoveTooltip.
///
/// In en, this message translates to:
/// **'Remove endpoint'**
String get n8nRemoveTooltip;
/// No description provided for @addMcpTitle.
///
/// In en, this message translates to:
/// **'Add MCP server'**
String get addMcpTitle;
/// No description provided for @addMcpIntro.
///
/// In en, this message translates to:
/// **'Tools the server advertises via `tools/list` appear in the Store as `mcp.<name>.<tool>` capabilities.'**
String get addMcpIntro;
/// No description provided for @addMcpSuggestionsLabel.
///
/// In en, this message translates to:
/// **'Suggested servers — click to pre-fill'**
String get addMcpSuggestionsLabel;
/// No description provided for @addMcpNameLabel.
///
/// In en, this message translates to:
/// **'Name (no dots)'**
String get addMcpNameLabel;
/// No description provided for @addMcpNameHint.
///
/// In en, this message translates to:
/// **'filesystem'**
String get addMcpNameHint;
/// No description provided for @addMcpEndpointLabel.
///
/// In en, this message translates to:
/// **'Endpoint'**
String get addMcpEndpointLabel;
/// No description provided for @addMcpEndpointHint.
///
/// In en, this message translates to:
/// **'http://127.0.0.1:3001/mcp'**
String get addMcpEndpointHint;
/// No description provided for @addMcpApiKeyLabel.
///
/// In en, this message translates to:
/// **'API key env var (optional)'**
String get addMcpApiKeyLabel;
/// No description provided for @addMcpApiKeyHint.
///
/// In en, this message translates to:
/// **'MCP_FILESYSTEM_TOKEN'**
String get addMcpApiKeyHint;
/// No description provided for @addMcpNotesLabel.
///
/// In en, this message translates to:
/// **'Notes (optional)'**
String get addMcpNotesLabel;
/// No description provided for @addMcpAddButton.
///
/// In en, this message translates to:
/// **'Add + discover'**
String get addMcpAddButton;
/// No description provided for @addN8nTitle.
///
/// In en, this message translates to:
/// **'Add n8n endpoint'**
String get addN8nTitle;
/// No description provided for @addN8nIntro.
///
/// In en, this message translates to:
/// **'Active workflows surface in the Store as `n8n.<name>.<workflow_slug>` capabilities.'**
String get addN8nIntro;
/// No description provided for @addN8nNameLabel.
///
/// In en, this message translates to:
/// **'Name (no dots)'**
String get addN8nNameLabel;
/// No description provided for @addN8nNameHint.
///
/// In en, this message translates to:
/// **'ops'**
String get addN8nNameHint;
/// No description provided for @addN8nBaseUrlLabel.
///
/// In en, this message translates to:
/// **'Base URL (without /api/v1)'**
String get addN8nBaseUrlLabel;
/// No description provided for @addN8nBaseUrlHint.
///
/// In en, this message translates to:
/// **'https://n8n.example.com'**
String get addN8nBaseUrlHint;
/// No description provided for @addN8nApiKeyLabel.
///
/// In en, this message translates to:
/// **'API key env var (optional)'**
String get addN8nApiKeyLabel;
/// No description provided for @addN8nApiKeyHint.
///
/// In en, this message translates to:
/// **'N8N_OPS_KEY'**
String get addN8nApiKeyHint;
/// No description provided for @addN8nNotesLabel.
///
/// In en, this message translates to:
/// **'Notes (optional)'**
String get addN8nNotesLabel;
/// No description provided for @addN8nAddButton.
///
/// In en, this message translates to:
/// **'Add + discover'**
String get addN8nAddButton;
/// No description provided for @addedMcpToast.
///
/// In en, this message translates to:
/// **'Added MCP server \"{name}\".'**
String addedMcpToast(String name);
/// No description provided for @addedN8nToast.
///
/// In en, this message translates to:
/// **'Added n8n endpoint \"{name}\".'**
String addedN8nToast(String name);
/// No description provided for @addFailedToast.
///
/// In en, this message translates to:
/// **'Add failed: {error}'**
String addFailedToast(String error);
/// No description provided for @removeFailedToast.
///
/// In en, this message translates to:
/// **'Remove failed: {error}'**
String removeFailedToast(String error);
/// No description provided for @refreshFailedToast.
///
/// In en, this message translates to:
/// **'Refresh failed: {error}'**
String refreshFailedToast(String error);
/// No description provided for @channelsHeader.
///
/// In en, this message translates to:
@ -440,6 +722,192 @@ abstract class AppLocalizations {
/// **'Run a flow to populate the audit stream.\nEvents appear here within seconds.'**
String get auditNoEventsHint;
/// No description provided for @auditFilterAll.
///
/// In en, this message translates to:
/// **'all'**
String get auditFilterAll;
/// No description provided for @auditFilterFlow.
///
/// In en, this message translates to:
/// **'flow'**
String get auditFilterFlow;
/// No description provided for @auditFilterStep.
///
/// In en, this message translates to:
/// **'step'**
String get auditFilterStep;
/// No description provided for @auditFilterModule.
///
/// In en, this message translates to:
/// **'module'**
String get auditFilterModule;
/// No description provided for @auditClearLogTooltip.
///
/// In en, this message translates to:
/// **'Clear log (local/dev channels only)'**
String get auditClearLogTooltip;
/// No description provided for @auditClearedToast.
///
/// In en, this message translates to:
/// **'Cleared {n} events on channel \"{channel}\". Chain reseeded with marker.'**
String auditClearedToast(int n, String channel);
/// No description provided for @auditClearFailed.
///
/// In en, this message translates to:
/// **'Clear failed: {detail}'**
String auditClearFailed(String detail);
/// No description provided for @auditExplain.
///
/// In en, this message translates to:
/// **'Explain'**
String get auditExplain;
/// No description provided for @auditReask.
///
/// In en, this message translates to:
/// **'Re-ask'**
String get auditReask;
/// No description provided for @auditAsking.
///
/// In en, this message translates to:
/// **'Asking…'**
String get auditAsking;
/// No description provided for @auditSystemAi.
///
/// In en, this message translates to:
/// **'SYSTEM AI'**
String get auditSystemAi;
/// No description provided for @auditCachedPill.
///
/// In en, this message translates to:
/// **'cached'**
String get auditCachedPill;
/// No description provided for @auditOriginalLatency.
///
/// In en, this message translates to:
/// **'orig {ms} ms'**
String auditOriginalLatency(int ms);
/// No description provided for @auditLatency.
///
/// In en, this message translates to:
/// **'{ms} ms'**
String auditLatency(int ms);
/// No description provided for @auditRegenerateTooltip.
///
/// In en, this message translates to:
/// **'Regenerate — skip cache, ask the model again'**
String get auditRegenerateTooltip;
/// No description provided for @auditLiveStatus.
///
/// In en, this message translates to:
/// **'live · polling 2s · {n} {n, plural, =1{event} other{events}}'**
String auditLiveStatus(int n);
/// No description provided for @auditDisconnected.
///
/// In en, this message translates to:
/// **'disconnected · {error}'**
String auditDisconnected(String error);
/// No description provided for @auditHashChainVerified.
///
/// In en, this message translates to:
/// **'hash chain verified'**
String get auditHashChainVerified;
/// No description provided for @auditDetailHeader.
///
/// In en, this message translates to:
/// **'DETAIL'**
String get auditDetailHeader;
/// No description provided for @auditAskingFull.
///
/// In en, this message translates to:
/// **'Asking the configured System AI…'**
String get auditAskingFull;
/// No description provided for @auditFixLabel.
///
/// In en, this message translates to:
/// **'FIX'**
String get auditFixLabel;
/// No description provided for @auditCachedTooltipKnown.
///
/// In en, this message translates to:
/// **'Served from the local cache. Originally generated on {at}{hits}.'**
String auditCachedTooltipKnown(String at, String hits);
/// No description provided for @auditCachedTooltipUnknown.
///
/// In en, this message translates to:
/// **'Served from the local cache. Originally generated at unknown time{hits}.'**
String auditCachedTooltipUnknown(String hits);
/// No description provided for @auditCachedTooltipHits.
///
/// In en, this message translates to:
/// **' · {n} hits'**
String auditCachedTooltipHits(int n);
/// No description provided for @auditConfigureSystemAi.
///
/// In en, this message translates to:
/// **'Configure System AI in Settings (Cmd+,)'**
String get auditConfigureSystemAi;
/// No description provided for @auditClearDialogTitle.
///
/// In en, this message translates to:
/// **'Clear audit log?'**
String get auditClearDialogTitle;
/// No description provided for @auditClearDialogBody.
///
/// In en, this message translates to:
/// **'Wipes every audit event on the active channel and seeds a fresh chain.reset marker carrying reviewer + reason. Refused on beta / production. Irreversible.'**
String get auditClearDialogBody;
/// No description provided for @auditClearReviewerLabel.
///
/// In en, this message translates to:
/// **'Reviewer'**
String get auditClearReviewerLabel;
/// No description provided for @auditClearReasonLabel.
///
/// In en, this message translates to:
/// **'Reason (recorded in chain.reset marker)'**
String get auditClearReasonLabel;
/// No description provided for @auditClearReasonHelper.
///
/// In en, this message translates to:
/// **'Required — auditors will read this.'**
String get auditClearReasonHelper;
/// No description provided for @auditClearLogButton.
///
/// In en, this message translates to:
/// **'Clear log'**
String get auditClearLogButton;
/// No description provided for @modulesTitle.
///
/// In en, this message translates to:
@ -554,6 +1022,138 @@ abstract class AppLocalizations {
/// **'All caught up. New `system.approval@^0` steps land here automatically.'**
String get approvalsInboxHint;
/// No description provided for @approvalsReloadTooltip.
///
/// In en, this message translates to:
/// **'Reload'**
String get approvalsReloadTooltip;
/// No description provided for @approvalsPillPending.
///
/// In en, this message translates to:
/// **'pending'**
String get approvalsPillPending;
/// No description provided for @approvalsPillApproved.
///
/// In en, this message translates to:
/// **'approved'**
String get approvalsPillApproved;
/// No description provided for @approvalsPillRejected.
///
/// In en, this message translates to:
/// **'rejected'**
String get approvalsPillRejected;
/// No description provided for @approvalsPillExpired.
///
/// In en, this message translates to:
/// **'expired'**
String get approvalsPillExpired;
/// No description provided for @approvalsPayloadPreview.
///
/// In en, this message translates to:
/// **'PAYLOAD PREVIEW'**
String get approvalsPayloadPreview;
/// No description provided for @approvalsApproveButton.
///
/// In en, this message translates to:
/// **'Approve'**
String get approvalsApproveButton;
/// No description provided for @approvalsRejectButton.
///
/// In en, this message translates to:
/// **'Reject'**
String get approvalsRejectButton;
/// No description provided for @approvalsRejectDialogTitle.
///
/// In en, this message translates to:
/// **'Reject approval'**
String get approvalsRejectDialogTitle;
/// No description provided for @approvalsRejectReasonLabel.
///
/// In en, this message translates to:
/// **'Reason (recorded in audit log)'**
String get approvalsRejectReasonLabel;
/// No description provided for @approvalsApprovedToast.
///
/// In en, this message translates to:
/// **'approved · {flow} {step}'**
String approvalsApprovedToast(String flow, String step);
/// No description provided for @approvalsRejectedToast.
///
/// In en, this message translates to:
/// **'rejected · {flow} {step}'**
String approvalsRejectedToast(String flow, String step);
/// No description provided for @approvalsApproveFailed.
///
/// In en, this message translates to:
/// **'approve failed: {error}'**
String approvalsApproveFailed(String error);
/// No description provided for @approvalsRejectFailed.
///
/// In en, this message translates to:
/// **'reject failed: {error}'**
String approvalsRejectFailed(String error);
/// No description provided for @approvalsHistoryEmpty.
///
/// In en, this message translates to:
/// **'No history yet'**
String get approvalsHistoryEmpty;
/// No description provided for @approvalsHistoryEmptyHint.
///
/// In en, this message translates to:
/// **'Decided approvals (approved / rejected / expired) appear here.\nThe audit log keeps the full hash-chained record.'**
String get approvalsHistoryEmptyHint;
/// No description provided for @approvalsDialogDecided.
///
/// In en, this message translates to:
/// **'decided'**
String get approvalsDialogDecided;
/// No description provided for @approvalsDialogCreated.
///
/// In en, this message translates to:
/// **'created'**
String get approvalsDialogCreated;
/// No description provided for @approvalsDialogReason.
///
/// In en, this message translates to:
/// **'reason'**
String get approvalsDialogReason;
/// No description provided for @approvalsDialogPrompt.
///
/// In en, this message translates to:
/// **'PROMPT'**
String get approvalsDialogPrompt;
/// No description provided for @approvalsExpiresIn.
///
/// In en, this message translates to:
/// **'{minutes}m'**
String approvalsExpiresIn(int minutes);
/// No description provided for @approvalsExpiresInHours.
///
/// In en, this message translates to:
/// **'{hours}h'**
String approvalsExpiresInHours(int hours);
/// No description provided for @doctorTitle.
///
/// In en, this message translates to: