mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 18:41:08 +02:00
i18n(api-keys): translate ListView via $_() — workbench module mirrors page strings
Adds 2 keys (label_rate_unit_short, action_revoking_short) to the
existing api-keys.page namespace and routes the workbench-embedded
ListView through them:
- Header "+ API Key" button → page.action_create
- Active Keys section header + empty state → existing keys
- Key card metadata: rate-per-min chip, "Created: {date}", revoke button (with revoking state)
- Revoked section header + "Revoked: {date}" line
- "How to Use" section + STT/TTS labels
- Modal: "API Key Created" success state + warning + Copied! toast + Done button
- Modal: Create form (Key Name + placeholder, Scopes, Rate Limit + req/min unit) + Cancel/Create/Creating
- Backdrop close-modal aria-label
- err_pick_scope error fallback
- Date formatter: 'de-DE' → get(locale) ?? 'de'
Baselines: hardcoded 1130 → 1119 (11 cleared); missing-keys baseline unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5dc0494bb7
commit
e712faf7b7
7 changed files with 70 additions and 34 deletions
|
|
@ -42,6 +42,8 @@
|
|||
"action_cancel": "Abbrechen",
|
||||
"action_creating": "Erstelle…",
|
||||
"action_create_key": "Key erstellen",
|
||||
"action_close_modal": "Modal schließen"
|
||||
"action_close_modal": "Modal schließen",
|
||||
"label_rate_unit_short": "Anf./Min.",
|
||||
"action_revoking_short": "..."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
"action_cancel": "Cancel",
|
||||
"action_creating": "Creating…",
|
||||
"action_create_key": "Create Key",
|
||||
"action_close_modal": "Close modal"
|
||||
"action_close_modal": "Close modal",
|
||||
"label_rate_unit_short": "req/min",
|
||||
"action_revoking_short": "..."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
"action_cancel": "Cancelar",
|
||||
"action_creating": "Creando…",
|
||||
"action_create_key": "Crear key",
|
||||
"action_close_modal": "Cerrar modal"
|
||||
"action_close_modal": "Cerrar modal",
|
||||
"label_rate_unit_short": "req/min",
|
||||
"action_revoking_short": "..."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
"action_cancel": "Annuler",
|
||||
"action_creating": "Création…",
|
||||
"action_create_key": "Créer la key",
|
||||
"action_close_modal": "Fermer la modale"
|
||||
"action_close_modal": "Fermer la modale",
|
||||
"label_rate_unit_short": "req/min",
|
||||
"action_revoking_short": "..."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
"action_cancel": "Annulla",
|
||||
"action_creating": "Creazione…",
|
||||
"action_create_key": "Crea key",
|
||||
"action_close_modal": "Chiudi modale"
|
||||
"action_close_modal": "Chiudi modale",
|
||||
"label_rate_unit_short": "req/min",
|
||||
"action_revoking_short": "..."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
import { Button, Input, Card, Badge } from '@mana/shared-ui';
|
||||
import { Check, Copy, Info, Key, Plus, Prohibit } from '@mana/shared-icons';
|
||||
import { apiKeysService, type ApiKey, type ApiKeyWithSecret } from '$lib/api/api-keys';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { get } from 'svelte/store';
|
||||
import { locale } from 'svelte-i18n';
|
||||
|
||||
let loading = $state(true);
|
||||
let apiKeys = $state<ApiKey[]>([]);
|
||||
|
|
@ -47,7 +50,7 @@
|
|||
if (newKeyScopes.stt) scopes.push('stt');
|
||||
if (newKeyScopes.tts) scopes.push('tts');
|
||||
if (scopes.length === 0) {
|
||||
error = 'Please select at least one scope';
|
||||
error = $_('api-keys.page.err_pick_scope');
|
||||
return;
|
||||
}
|
||||
creating = true;
|
||||
|
|
@ -96,8 +99,9 @@
|
|||
}
|
||||
|
||||
function formatDate(dateString: string | null): string {
|
||||
if (!dateString) return 'Never';
|
||||
return new Date(dateString).toLocaleDateString('de-DE', {
|
||||
if (!dateString) return $_('api-keys.page.never');
|
||||
const lang = get(locale) ?? 'de';
|
||||
return new Date(dateString).toLocaleDateString(lang, {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
|
|
@ -110,7 +114,8 @@
|
|||
<div class="apikeys-page">
|
||||
<div class="header">
|
||||
<button class="add-btn" onclick={() => (showCreateModal = true)}>
|
||||
<Plus size={14} weight="bold" /> API Key
|
||||
<Plus size={14} weight="bold" />
|
||||
{$_('api-keys.page.action_create')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -127,14 +132,14 @@
|
|||
<div class="section">
|
||||
<div class="section-header">
|
||||
<Key size={16} />
|
||||
<span class="section-title">Active Keys</span>
|
||||
<span class="section-title">{$_('api-keys.page.section_active_title')}</span>
|
||||
<span class="section-count">{activeKeys.length}</span>
|
||||
</div>
|
||||
|
||||
{#if activeKeys.length === 0}
|
||||
<div class="empty">
|
||||
<Key size={32} />
|
||||
<p>No API keys yet</p>
|
||||
<p>{$_('api-keys.page.empty_title')}</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="key-list">
|
||||
|
|
@ -144,11 +149,19 @@
|
|||
<div class="key-name-row">
|
||||
<span class="key-name">{key.name}</span>
|
||||
<span class="key-scope">{key.scopes.join(', ')}</span>
|
||||
<span class="key-rate">{key.rateLimitRequests}/min</span>
|
||||
<span class="key-rate"
|
||||
>{$_('api-keys.page.rate_per_min', {
|
||||
values: { rate: key.rateLimitRequests },
|
||||
})}</span
|
||||
>
|
||||
</div>
|
||||
<div class="key-meta">
|
||||
<code class="key-prefix">{key.keyPrefix}</code>
|
||||
<span>Created: {formatDate(key.createdAt)}</span>
|
||||
<span
|
||||
>{$_('api-keys.page.label_created', {
|
||||
values: { date: formatDate(key.createdAt) },
|
||||
})}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
|
|
@ -156,7 +169,9 @@
|
|||
disabled={revoking === key.id}
|
||||
onclick={() => handleRevoke(key.id)}
|
||||
>
|
||||
{revoking === key.id ? '...' : 'Revoke'}
|
||||
{revoking === key.id
|
||||
? $_('api-keys.page.action_revoking_short')
|
||||
: $_('api-keys.page.action_revoke')}
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
@ -169,7 +184,7 @@
|
|||
<div class="section dimmed">
|
||||
<div class="section-header">
|
||||
<Prohibit size={16} />
|
||||
<span class="section-title">Revoked</span>
|
||||
<span class="section-title">{$_('api-keys.page.section_revoked_title')}</span>
|
||||
<span class="section-count">{revokedKeys.length}</span>
|
||||
</div>
|
||||
<div class="key-list">
|
||||
|
|
@ -179,7 +194,11 @@
|
|||
<span class="key-name strikethrough">{key.name}</span>
|
||||
<div class="key-meta">
|
||||
<code class="key-prefix">{key.keyPrefix}</code>
|
||||
<span>Revoked: {formatDate(key.revokedAt)}</span>
|
||||
<span
|
||||
>{$_('api-keys.page.label_revoked_at', {
|
||||
values: { date: formatDate(key.revokedAt) },
|
||||
})}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -192,10 +211,10 @@
|
|||
<div class="section">
|
||||
<div class="section-header">
|
||||
<Info size={16} />
|
||||
<span class="section-title">How to Use</span>
|
||||
<span class="section-title">{$_('api-keys.page.section_howto_title')}</span>
|
||||
</div>
|
||||
<div class="usage-block">
|
||||
<p class="usage-label">Speech-to-Text (STT)</p>
|
||||
<p class="usage-label">{$_('api-keys.page.label_stt')}</p>
|
||||
<pre class="usage-code"><code
|
||||
>curl -X POST https://gpu-stt.mana.how/transcribe \
|
||||
-H "X-API-Key: sk_live_..." \
|
||||
|
|
@ -203,7 +222,7 @@
|
|||
></pre>
|
||||
</div>
|
||||
<div class="usage-block">
|
||||
<p class="usage-label">Text-to-Speech (TTS)</p>
|
||||
<p class="usage-label">{$_('api-keys.page.label_tts')}</p>
|
||||
<pre class="usage-code"><code
|
||||
>curl -X POST https://tts-api.mana.how/synthesize/kokoro \
|
||||
-H "X-API-Key: sk_live_..." \
|
||||
|
|
@ -219,33 +238,39 @@
|
|||
<!-- Create API Key Modal -->
|
||||
{#if showCreateModal}
|
||||
<div class="modal-backdrop">
|
||||
<button class="backdrop-btn" onclick={closeCreateModal} aria-label="Close modal"></button>
|
||||
<button
|
||||
class="backdrop-btn"
|
||||
onclick={closeCreateModal}
|
||||
aria-label={$_('api-keys.page.action_close_modal')}
|
||||
></button>
|
||||
<div class="modal">
|
||||
{#if createdKey}
|
||||
<div class="modal-success">
|
||||
<div class="success-icon"><Check size={20} /></div>
|
||||
<h3 class="modal-title">API Key Created</h3>
|
||||
<p class="modal-hint">Copy your API key now. You won't be able to see it again.</p>
|
||||
<h3 class="modal-title">{$_('api-keys.page.modal_created_title')}</h3>
|
||||
<p class="modal-hint">{$_('api-keys.page.modal_created_warning')}</p>
|
||||
<div class="key-display">
|
||||
<code>{createdKey.key}</code>
|
||||
<button class="copy-btn" onclick={() => copyToClipboard(createdKey!.key)}>
|
||||
{#if copied}<Check size={16} />{:else}<Copy size={16} />{/if}
|
||||
</button>
|
||||
</div>
|
||||
{#if copied}<p class="copied-msg">Copied!</p>{/if}
|
||||
<button class="done-btn" onclick={closeCreateModal}>Done</button>
|
||||
{#if copied}<p class="copied-msg">{$_('api-keys.page.toast_copied')}</p>{/if}
|
||||
<button class="done-btn" onclick={closeCreateModal}
|
||||
>{$_('api-keys.page.action_done')}</button
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
<h3 class="modal-title">Create API Key</h3>
|
||||
<label class="field-label" for="wbKeyName">Key Name</label>
|
||||
<h3 class="modal-title">{$_('api-keys.page.modal_create_title')}</h3>
|
||||
<label class="field-label" for="wbKeyName">{$_('api-keys.page.label_key_name')}</label>
|
||||
<input
|
||||
id="wbKeyName"
|
||||
type="text"
|
||||
class="field-input"
|
||||
bind:value={newKeyName}
|
||||
placeholder="e.g., Production API Key"
|
||||
placeholder={$_('api-keys.page.placeholder_key_name')}
|
||||
/>
|
||||
<span class="field-label">Scopes</span>
|
||||
<span class="field-label">{$_('api-keys.page.label_scopes')}</span>
|
||||
<div class="scope-checks">
|
||||
<label class="scope-check">
|
||||
<input type="checkbox" bind:checked={newKeyScopes.stt} /> STT
|
||||
|
|
@ -254,7 +279,7 @@
|
|||
<input type="checkbox" bind:checked={newKeyScopes.tts} /> TTS
|
||||
</label>
|
||||
</div>
|
||||
<label class="field-label" for="wbRateLimit">Rate Limit</label>
|
||||
<label class="field-label" for="wbRateLimit">{$_('api-keys.page.label_rate_limit')}</label>
|
||||
<div class="rate-row">
|
||||
<input
|
||||
id="wbRateLimit"
|
||||
|
|
@ -262,16 +287,18 @@
|
|||
class="field-input rate-input"
|
||||
bind:value={newKeyRateLimit}
|
||||
/>
|
||||
<span class="rate-unit">req/min</span>
|
||||
<span class="rate-unit">{$_('api-keys.page.label_rate_unit_short')}</span>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="cancel-btn" onclick={closeCreateModal}>Cancel</button>
|
||||
<button class="cancel-btn" onclick={closeCreateModal}
|
||||
>{$_('api-keys.page.action_cancel')}</button
|
||||
>
|
||||
<button
|
||||
class="create-btn"
|
||||
disabled={!newKeyName.trim() || (!newKeyScopes.stt && !newKeyScopes.tts) || creating}
|
||||
onclick={handleCreate}
|
||||
>
|
||||
{creating ? 'Creating...' : 'Create'}
|
||||
{creating ? $_('api-keys.page.action_creating') : $_('api-keys.page.action_create_key')}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"apps/mana/apps/web/src/lib/components/dashboard/widgets/CardsProgressWidget.svelte": 4,
|
||||
"apps/mana/apps/web/src/lib/components/dashboard/widgets/MusicLibraryWidget.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/components/DetailViewShell.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/components/feedback/FeedbackQuickModal.svelte": 6,
|
||||
"apps/mana/apps/web/src/lib/components/feedback/FeedbackQuickModal.svelte": 7,
|
||||
"apps/mana/apps/web/src/lib/components/feedback/GlobalFeedbackPill.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/components/KeyboardShortcutsModal.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/components/landing/LandingEditor.svelte": 16,
|
||||
|
|
@ -46,7 +46,6 @@
|
|||
"apps/mana/apps/web/src/lib/modules/ai-health/ListView.svelte": 2,
|
||||
"apps/mana/apps/web/src/lib/modules/ai-insights/ListView.svelte": 4,
|
||||
"apps/mana/apps/web/src/lib/modules/ai-workbench/ListView.svelte": 8,
|
||||
"apps/mana/apps/web/src/lib/modules/api-keys/ListView.svelte": 11,
|
||||
"apps/mana/apps/web/src/lib/modules/articles/components/AddUrlForm.svelte": 4,
|
||||
"apps/mana/apps/web/src/lib/modules/articles/components/HighlightMenu.svelte": 5,
|
||||
"apps/mana/apps/web/src/lib/modules/articles/components/HomeSectionSources.svelte": 1,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue