feat(frontend): i18n C2 components (config card, tasks panel, execute/import modals, picker)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { extractApiError } from '@/api/client';
|
||||
import { useC2Callbacks, useC2CallbackHistory, useImportC2 } from '@/hooks/useC2';
|
||||
import { C2CallbackPicker } from './C2CallbackPicker';
|
||||
@@ -18,6 +19,7 @@ export function ImportC2HistoryModal({
|
||||
engagementId,
|
||||
onClose,
|
||||
}: ImportC2HistoryModalProps): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const { push } = useToast();
|
||||
|
||||
const callbacksQuery = useC2Callbacks(engagementId, { enabled: true });
|
||||
@@ -70,12 +72,12 @@ export function ImportC2HistoryModal({
|
||||
});
|
||||
const msg =
|
||||
result.skipped > 0
|
||||
? `Imported ${result.imported} task(s), ${result.skipped} already attached`
|
||||
: `Imported ${result.imported} task(s)`;
|
||||
? t('c2.modal.import.toast.partial', { imported: result.imported, skipped: result.skipped })
|
||||
: t('c2.modal.import.toast.imported', { count: result.imported });
|
||||
push(msg, 'success');
|
||||
onClose();
|
||||
} catch (err) {
|
||||
setSubmitError(extractApiError(err, 'Could not import tasks'));
|
||||
setSubmitError(extractApiError(err, t('c2.modal.import.error.import')));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,12 +93,12 @@ export function ImportC2HistoryModal({
|
||||
|
||||
<div className="relative card-product w-full max-w-4xl mx-md flex flex-col gap-md max-h-[90vh] overflow-y-auto">
|
||||
<h2 id="c2-import-modal-title" className="text-[20px] font-medium text-ink">
|
||||
Import C2 history
|
||||
{t('c2.modal.import.title')}
|
||||
</h2>
|
||||
|
||||
{/* Step 1: callback picker */}
|
||||
<div className="flex flex-col gap-xs">
|
||||
<span className="text-[14px] font-medium text-ink">Select callback</span>
|
||||
<span className="text-[14px] font-medium text-ink">{t('c2.modal.picker.title')}</span>
|
||||
<C2CallbackPicker
|
||||
callbacks={callbacks}
|
||||
isLoading={callbacksQuery.isLoading}
|
||||
@@ -112,24 +114,24 @@ export function ImportC2HistoryModal({
|
||||
{selectedCallbackId !== null && (
|
||||
<div className="flex flex-col gap-xs">
|
||||
<span className="text-[14px] font-medium text-ink">
|
||||
Task history{' '}
|
||||
{t('c2.tasks.title')}{' '}
|
||||
{total > 0 && (
|
||||
<span className="text-graphite font-normal">({total} total)</span>
|
||||
<span className="text-graphite font-normal">({total} {t('c2.modal.import.total').toLowerCase()})</span>
|
||||
)}
|
||||
</span>
|
||||
|
||||
{historyQuery.isLoading && (
|
||||
<p className="text-[14px] text-graphite">Loading history…</p>
|
||||
<p className="text-[14px] text-graphite">{t('state.loading')}</p>
|
||||
)}
|
||||
|
||||
{historyQuery.isError && (
|
||||
<p className="text-[14px] text-bloom-deep">
|
||||
{extractApiError(historyQuery.error, 'Could not load history')}
|
||||
{extractApiError(historyQuery.error, t('c2.modal.import.error.import'))}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{!historyQuery.isLoading && historyTasks.length === 0 && !historyQuery.isError && (
|
||||
<p className="text-[14px] text-graphite">No task history for this callback.</p>
|
||||
<p className="text-[14px] text-graphite">{t('c2.modal.import.empty')}</p>
|
||||
)}
|
||||
|
||||
{historyTasks.length > 0 && (
|
||||
@@ -140,10 +142,10 @@ export function ImportC2HistoryModal({
|
||||
<tr className="bg-cloud border-b border-hairline">
|
||||
<th className="px-md py-sm w-8" aria-label="Select" />
|
||||
<th className="px-md py-sm text-left font-medium text-ink">#</th>
|
||||
<th className="px-md py-sm text-left font-medium text-ink">Command</th>
|
||||
<th className="px-md py-sm text-left font-medium text-ink">Status</th>
|
||||
<th className="px-md py-sm text-left font-medium text-ink">Completed</th>
|
||||
<th className="px-md py-sm text-left font-medium text-ink">Timestamp</th>
|
||||
<th className="px-md py-sm text-left font-medium text-ink">{t('c2.tasks.col.command')}</th>
|
||||
<th className="px-md py-sm text-left font-medium text-ink">{t('c2.tasks.col.status')}</th>
|
||||
<th className="px-md py-sm text-left font-medium text-ink">{t('c2.modal.import.col.completed')}</th>
|
||||
<th className="px-md py-sm text-left font-medium text-ink">{t('c2.modal.import.col.timestamp')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -175,7 +177,7 @@ export function ImportC2HistoryModal({
|
||||
<C2TaskStatusBadge status={task.status} />
|
||||
</td>
|
||||
<td className="px-md py-sm text-[14px]">
|
||||
{task.completed ? 'Yes' : 'No'}
|
||||
{task.completed ? t('common.yes') : t('common.no')}
|
||||
</td>
|
||||
<td className="px-md py-sm font-mono text-graphite">
|
||||
{task.created_at}
|
||||
@@ -195,10 +197,10 @@ export function ImportC2HistoryModal({
|
||||
onClick={() => setPage((p) => Math.max(1, p - 1))}
|
||||
disabled={page <= 1}
|
||||
>
|
||||
Prev
|
||||
{t('c2.modal.import.prev')}
|
||||
</button>
|
||||
<span>
|
||||
Page {page} of {totalPages}
|
||||
{t('c2.modal.import.page')} {page} {t('c2.modal.import.of')} {totalPages}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
@@ -207,11 +209,11 @@ export function ImportC2HistoryModal({
|
||||
onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
|
||||
disabled={page >= totalPages}
|
||||
>
|
||||
Next
|
||||
{t('c2.modal.import.next')}
|
||||
</button>
|
||||
{checkedIds.size > 0 && (
|
||||
<span className="ml-auto text-ink">
|
||||
{checkedIds.size} selected
|
||||
{checkedIds.size} {t('c2.modal.import.selected')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -235,7 +237,7 @@ export function ImportC2HistoryModal({
|
||||
onClick={onImport}
|
||||
disabled={!canImport || importMutation.isPending}
|
||||
>
|
||||
{importMutation.isPending ? 'Importing…' : 'Import selected'}
|
||||
{importMutation.isPending ? t('c2.modal.import.btn.importing') : t('c2.modal.import.btn.import')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -243,7 +245,7 @@ export function ImportC2HistoryModal({
|
||||
onClick={onClose}
|
||||
disabled={importMutation.isPending}
|
||||
>
|
||||
Cancel
|
||||
{t('c2.modal.import.btn.cancel')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user