f09e938673
Migrates the eleven remaining files that `i18next/no-literal-string` flagged outside `app/office`, `app/demo` and the task-create surfaces owned by #2326: the session prepare panel, the onboarding agents step, the host system-metrics readout, the system-health issues dialog, the shared panel search bar, the mermaid diagram block, the settings agent card, both release-notes surfaces, and the shared data-table pair. Findings drop 884 -> 826 (-58) and the guard allowlist grows 442 -> 453, file by file rather than by directory since every one of these directories still holds un-migrated files. Defects repaired beyond the codemod's output: - `data-table-pagination.tsx` rendered `{count} results` as a bare JSX fragment, invisible to both plural gates. It is now one interpolated key with `_one`/`_other`, as are the health-dialog issue count and the release-notes "N new releases" helper. - Two mixed literal+expression blocks were half-converted, rendering identically in English while being structurally untranslatable. Both were rebuilt as a single message. - The codemod re-sorted `settings.json` into `localeCompare` order and re-encoded every non-ASCII character to `\uXXXX` under a comment claiming it matched the existing files. No catalog is stored escaped and only `common` is in that order, so both halves were reverted; all four catalogs are additions-only. - Copy in default parameters and plain helpers is invisible to the lint rule, so `Search…`, the six prepare-panel header labels, the setup-script step name and error, the metric labels, `lastUpdatedText` and `buildDescription` were migrated by hand. `task:preparingEnvironment` was already taken by #2326 holding "Preparing environment" without the ellipsis this surface renders, so the prepare panel uses `preparingEnvironmentEllipsis` rather than silently changing its copy. Units, wire ids, the `{workspaceId}` URL token, the `"ellipsis"` page sentinel and every mermaid theme/CSS value stay English as protocol.
93 lines
3.1 KiB
TypeScript
93 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import ReactMarkdown from "react-markdown";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogDescription,
|
|
} from "@kandev/ui/dialog";
|
|
import { ScrollArea } from "@kandev/ui/scroll-area";
|
|
import { Badge } from "@kandev/ui/badge";
|
|
import { Separator } from "@kandev/ui/separator";
|
|
import { IconExternalLink } from "@tabler/icons-react";
|
|
import { remarkPlugins, markdownComponents } from "@/components/shared/markdown-components";
|
|
import { getReleaseUrl } from "@/lib/release-notes";
|
|
import type { ChangelogEntry } from "@/lib/changelog";
|
|
import type { TFunction } from "i18next";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
type ReleaseNotesDialogProps = {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
entries: ChangelogEntry[];
|
|
latestVersion: string;
|
|
};
|
|
|
|
function buildDescription(t: TFunction, entries: ChangelogEntry[]): string {
|
|
if (entries.length === 1) {
|
|
return entries[0].date
|
|
? t("common:releasedOn", { date: entries[0].date })
|
|
: t("common:latestReleaseNotes");
|
|
}
|
|
return t("common:newReleases", { count: entries.length });
|
|
}
|
|
|
|
export function ReleaseNotesDialog({
|
|
open,
|
|
onOpenChange,
|
|
entries,
|
|
latestVersion,
|
|
}: ReleaseNotesDialogProps) {
|
|
const { t } = useTranslation();
|
|
const releaseUrl = getReleaseUrl(latestVersion);
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="sm:max-w-[520px]">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2">
|
|
{t("common:whatSNew")}
|
|
<Badge variant="secondary">v{latestVersion}</Badge>
|
|
</DialogTitle>
|
|
<DialogDescription>{buildDescription(t, entries)}</DialogDescription>
|
|
</DialogHeader>
|
|
<ScrollArea className="max-h-[60vh] pr-4">
|
|
<div className="space-y-4">
|
|
{entries.map((entry, index) => (
|
|
<div key={entry.version}>
|
|
{entries.length > 1 && (
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Badge variant="outline">v{entry.version}</Badge>
|
|
{entry.date && (
|
|
<span className="text-xs text-muted-foreground">{entry.date}</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
<div className="markdown-body text-sm">
|
|
<ReactMarkdown remarkPlugins={remarkPlugins} components={markdownComponents}>
|
|
{entry.notes}
|
|
</ReactMarkdown>
|
|
</div>
|
|
{index < entries.length - 1 && <Separator className="mt-4" />}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</ScrollArea>
|
|
<div className="pt-2 border-t border-border">
|
|
<a
|
|
href={releaseUrl}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors cursor-pointer"
|
|
>
|
|
{t("common:viewFullReleaseOnGithub")}
|
|
<IconExternalLink className="h-3 w-3" />
|
|
</a>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|