Compare commits

...

3 Commits

Author SHA1 Message Date
tigerenwork 4734c809d7 feat: adjust the sidebar width to 800px 2026-02-05 10:15:28 +08:00
tigerenwork c35dacf64c feat: resolve the codeblock overflow issue 2026-02-05 00:05:37 +08:00
tigerenwork 75e667c1d7 fix: fix reordering failure issue 2026-02-04 11:16:46 +08:00
4 changed files with 61 additions and 62 deletions

View File

@ -6,13 +6,11 @@ import { Button } from '@/components/ui/button';
interface CodeBlockProps {
code: string;
type: 'bash' | 'sql' | 'text';
type: 'bash' | 'sql' | 'text' | 'branch';
showLineNumbers?: boolean;
}
export function CodeBlock({ code, type, showLineNumbers = true }: CodeBlockProps) {
console.log('[CodeBlock] Render - code length:', code?.length, 'code preview:', code?.substring(0, 50), 'type:', type);
const [copied, setCopied] = useState(false);
// Compute highlighted code synchronously
@ -30,17 +28,14 @@ export function CodeBlock({ code, type, showLineNumbers = true }: CodeBlockProps
require('prismjs/components/prism-bash');
}
const language = type === 'text' ? 'text' : type;
const language = type === 'text' || type === 'branch' ? 'text' : type;
const grammar = Prism.languages[language] || Prism.languages.text;
return Prism.highlight(code, grammar, language);
} catch (e) {
console.error('[CodeBlock] Prism error:', e);
return code.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
}, [code, type]);
console.log('[CodeBlock] highlighted length:', highlighted?.length);
const handleCopy = async () => {
await navigator.clipboard.writeText(code);
setCopied(true);
@ -52,31 +47,21 @@ export function CodeBlock({ code, type, showLineNumbers = true }: CodeBlockProps
const highlightedLines = highlighted ? highlighted.split('\n') : [];
return (
<div className="relative group">
<Button
variant="ghost"
size="sm"
className="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity z-10"
onClick={handleCopy}
<div
className="rounded-lg bg-slate-900 p-4 text-sm overflow-x-auto"
style={{ maxWidth: '100%' }}
>
{copied ? (
<Check className="w-4 h-4 text-green-500" />
) : (
<Copy className="w-4 h-4" />
)}
</Button>
<div className="rounded-lg bg-slate-900 p-4 overflow-x-auto text-sm">
<pre className={`language-${type} m-0`}>
<pre className={`language-${type} m-0`} style={{ minWidth: '100%' }}>
{showLineNumbers ? (
<div className="flex">
{/* Line numbers column */}
<div className="flex flex-col text-slate-500 text-right pr-4 select-none min-w-[3rem]">
<div className="flex" style={{ minWidth: 0 }}>
{/* Line numbers column - fixed width */}
<div className="flex flex-col text-slate-500 text-right pr-4 select-none w-12 shrink-0">
{lines.map((_: string, i: number) => (
<span key={i}>{i + 1}</span>
))}
</div>
{/* Code column */}
<div className="flex flex-col">
<div className="flex flex-col" style={{ minWidth: 0 }}>
{highlightedLines.map((line: string, i: number) => (
<span
key={i}
@ -94,6 +79,5 @@ export function CodeBlock({ code, type, showLineNumbers = true }: CodeBlockProps
)}
</pre>
</div>
</div>
);
}

View File

@ -73,13 +73,7 @@ export function StepDetailPanel({
// Sync state when step changes
useEffect(() => {
console.log('[StepDetailPanel] useEffect triggered, step?.id:', step?.id);
if (step) {
console.log('[StepDetailPanel] Syncing state with step:', {
stepId: step.id,
stepName: step.name,
stepContent: step.content?.substring(0, 50),
});
setNotes(step.notes || '');
setEditContent(step.content || '');
setIsEditing(false);
@ -89,8 +83,6 @@ export function StepDetailPanel({
}
}, [step?.id]);
console.log('[StepDetailPanel] Render - step:', step?.id, 'step.content:', step?.content?.substring(0, 50), 'editContent:', editContent?.substring(0, 50));
if (!step) return null;
const isCustom = step.isCustom;
@ -189,7 +181,7 @@ export function StepDetailPanel({
return (
<Sheet open={isOpen} onOpenChange={onClose}>
<SheetContent key={step?.id} className="w-[600px] sm:max-w-[600px]">
<SheetContent key={step?.id} className="w-[800px] sm:max-w-[800px] overflow-hidden">
<SheetHeader className="px-6">
<div className="flex items-start justify-between">
<div>
@ -205,8 +197,9 @@ export function StepDetailPanel({
</div>
</SheetHeader>
<ScrollArea className="h-[calc(100vh-180px)] mt-6 px-6">
<div className="space-y-6">
<div style={{ width: '752px', maxWidth: '752px' }}>
<ScrollArea className="h-[calc(100vh-180px)] mt-6 px-6 w-full">
<div className="space-y-6" style={{ width: '704px', maxWidth: '704px' }}>
{/* Status & Type */}
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
@ -226,7 +219,7 @@ export function StepDetailPanel({
</div>
{/* Content */}
<div>
<div className="min-w-0" style={{ maxWidth: '100%' }}>
<div className="flex items-center justify-between mb-2">
<label className="text-sm font-medium text-slate-500">Content</label>
{!isEditing && (
@ -263,7 +256,9 @@ export function StepDetailPanel({
</div>
</div>
) : (
<div className="overflow-hidden" style={{ maxWidth: '100%', width: '100%' }}>
<CodeBlock code={step.content} type={step.type} />
</div>
)}
{/* Show original content if overridden */}
@ -376,6 +371,7 @@ export function StepDetailPanel({
)}
</div>
</ScrollArea>
</div>
</SheetContent>
</Sheet>
);

View File

@ -19,6 +19,7 @@ function ScrollArea({
<ScrollAreaPrimitive.Viewport
data-slot="scroll-area-viewport"
className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
style={{ maxWidth: '100%' }}
>
{children}
</ScrollAreaPrimitive.Viewport>

View File

@ -82,6 +82,23 @@ export async function reorderSteps(
category: StepCategory,
orderedIds: number[]
) {
// Two-phase update to avoid unique constraint violations
// Phase 1: Move all steps to temporary high values (offset by 10000)
for (let i = 0; i < orderedIds.length; i++) {
await db.update(stepTemplates)
.set({ orderIndex: i + 10000 })
.where(eq(stepTemplates.id, orderedIds[i]));
// Also update customer steps
await db.update(customerSteps)
.set({ orderIndex: i + 10000 })
.where(and(
eq(customerSteps.templateId, orderedIds[i]),
eq(customerSteps.category, category)
));
}
// Phase 2: Move to final positions
for (let i = 0; i < orderedIds.length; i++) {
await db.update(stepTemplates)
.set({ orderIndex: i })
@ -95,6 +112,7 @@ export async function reorderSteps(
eq(customerSteps.category, category)
));
}
revalidatePath(`/releases/${releaseId}/steps`);
}