Compare commits

...

2 Commits

Author SHA1 Message Date
tigerenwork b66fec5075 fix: stay on 'verify' tab after mark a verify step as done 2026-02-05 18:14:52 +08:00
tigerenwork 55060cd5b7 feat: change 'copy' button background and text when clicked 2026-02-05 17:50:39 +08:00
3 changed files with 55 additions and 17 deletions

View File

@ -16,6 +16,9 @@ interface ReleaseDetailPageProps {
params: Promise<{ params: Promise<{
id: string; id: string;
}>; }>;
searchParams: Promise<{
tab?: string;
}>;
} }
const typeColors: Record<string, string> = { const typeColors: Record<string, string> = {
@ -40,10 +43,12 @@ function getStatusColor(status: string) {
export const dynamic = 'force-dynamic'; export const dynamic = 'force-dynamic';
export default async function ReleaseDetailPage({ params }: ReleaseDetailPageProps) { export default async function ReleaseDetailPage({ params, searchParams }: ReleaseDetailPageProps) {
const { id } = await params; const { id } = await params;
const { tab } = await searchParams;
const releaseId = parseInt(id); const releaseId = parseInt(id);
const release = await getReleaseById(releaseId); const release = await getReleaseById(releaseId);
const activeTab = tab === 'verify' ? 'verify' : 'deploy';
if (!release) { if (!release) {
notFound(); notFound();
@ -186,13 +191,17 @@ export default async function ReleaseDetailPage({ params }: ReleaseDetailPagePro
{/* Matrix View (for active) */} {/* Matrix View (for active) */}
{release.status === 'active' && ( {release.status === 'active' && (
<Tabs defaultValue="deploy"> <Tabs defaultValue={activeTab}>
<TabsList> <TabsList>
<TabsTrigger value="deploy"> <TabsTrigger value="deploy" asChild>
Deploy ({stats.done + stats.skipped}/{stats.total}) <Link href={`/releases/${releaseId}?tab=deploy`}>
Deploy ({stats.done + stats.skipped}/{stats.total})
</Link>
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="verify"> <TabsTrigger value="verify" asChild>
Verify <Link href={`/releases/${releaseId}?tab=verify`}>
Verify
</Link>
</TabsTrigger> </TabsTrigger>
</TabsList> </TabsList>

View File

@ -45,8 +45,9 @@ export function ReleaseMatrixClient({ stepsByCluster, category, releaseId }: Rel
const handleActionComplete = () => { const handleActionComplete = () => {
setRefreshKey(prev => prev + 1); setRefreshKey(prev => prev + 1);
setIsPanelOpen(false); setIsPanelOpen(false);
// Refresh the page to get updated data // Refresh the page to get updated data, preserving the current tab
window.location.reload(); const currentUrl = new URL(window.location.href);
window.location.href = currentUrl.toString();
}; };
// Server actions wrapped in async functions // Server actions wrapped in async functions

View File

@ -17,6 +17,42 @@ import {
DialogTrigger, DialogTrigger,
} from '@/components/ui/dialog'; } from '@/components/ui/dialog';
// Copy button with subtle feedback
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
};
return (
<Button
variant="ghost"
size="sm"
onClick={handleCopy}
className={`h-7 px-2 transition-colors duration-200 ${
copied
? 'text-green-600 bg-green-50 hover:bg-green-100 hover:text-green-700'
: 'text-slate-500 hover:text-slate-700'
}`}
>
{copied ? (
<>
<Check className="w-3.5 h-3.5 mr-1" />
Copied
</>
) : (
<>
<Copy className="w-3.5 h-3.5 mr-1" />
Copy
</>
)}
</Button>
);
}
interface StepDetailPanelProps { interface StepDetailPanelProps {
step: any; step: any;
template: any; template: any;
@ -223,15 +259,7 @@ export function StepDetailPanel({
<div className="flex items-center justify-between mb-2"> <div className="flex items-center justify-between mb-2">
<label className="text-sm font-medium text-slate-500">Content</label> <label className="text-sm font-medium text-slate-500">Content</label>
{!isEditing && ( {!isEditing && (
<Button <CopyButton text={step.content} />
variant="ghost"
size="sm"
onClick={() => navigator.clipboard.writeText(step.content)}
className="h-7 px-2 text-slate-500 hover:text-slate-700"
>
<Copy className="w-3.5 h-3.5 mr-1" />
Copy
</Button>
)} )}
</div> </div>