fix: resolve all web app ESLint linter warnings (#246)
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
'use client';
|
||||
|
||||
import { memo } from 'react';
|
||||
import { IconLoader2, IconFileInvoice, IconSend, IconChevronDown } from '@tabler/icons-react';
|
||||
import { Button } from '@kandev/ui/button';
|
||||
import { DialogClose } from '@kandev/ui/dialog';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@kandev/ui/dropdown-menu';
|
||||
import { SHORTCUTS } from '@/lib/keyboard/constants';
|
||||
import { KeyboardShortcutTooltip } from '@/components/keyboard-shortcut-tooltip';
|
||||
|
||||
type UpdateButtonProps = {
|
||||
isCreatingTask: boolean;
|
||||
hasTitle: boolean;
|
||||
onUpdate: () => void;
|
||||
};
|
||||
|
||||
function UpdateButton({ isCreatingTask, hasTitle, onUpdate }: UpdateButtonProps) {
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
variant="default"
|
||||
className="w-full h-10 cursor-pointer sm:w-auto sm:h-7 gap-1.5"
|
||||
disabled={isCreatingTask || !hasTitle}
|
||||
onClick={onUpdate}
|
||||
>
|
||||
{isCreatingTask ? (
|
||||
<>
|
||||
<IconLoader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
Updating...
|
||||
</>
|
||||
) : (
|
||||
'Update'
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
type StartTaskSplitButtonProps = {
|
||||
isCreatingTask: boolean;
|
||||
disabled: boolean;
|
||||
isEditMode: boolean;
|
||||
onAltAction: () => void;
|
||||
};
|
||||
|
||||
function StartTaskSplitButton({ isCreatingTask, disabled, isEditMode, onAltAction }: StartTaskSplitButtonProps) {
|
||||
return (
|
||||
<div className="inline-flex rounded-md border border-border overflow-hidden sm:h-7 h-10">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="default"
|
||||
className="rounded-none border-0 cursor-pointer gap-1.5 h-full"
|
||||
disabled={disabled}
|
||||
>
|
||||
{isCreatingTask ? <IconLoader2 className="h-3.5 w-3.5 animate-spin" /> : <IconSend className="h-3.5 w-3.5" />}
|
||||
{isCreatingTask ? 'Starting...' : 'Start task'}
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="default"
|
||||
className="rounded-none border-0 border-l border-primary-foreground/20 px-2 cursor-pointer h-full"
|
||||
disabled={disabled}
|
||||
>
|
||||
<IconChevronDown className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-auto min-w-max">
|
||||
<DropdownMenuItem
|
||||
onClick={onAltAction}
|
||||
className="cursor-pointer whitespace-nowrap focus:bg-muted/80 hover:bg-muted/80"
|
||||
>
|
||||
{isEditMode ? 'Update task' : 'Create without starting agent'}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type DefaultSubmitButtonProps = {
|
||||
isCreatingSession: boolean;
|
||||
isCreatingTask: boolean;
|
||||
isSessionMode: boolean;
|
||||
isCreateMode: boolean;
|
||||
isEditMode: boolean;
|
||||
hasDescription: boolean;
|
||||
isPassthroughProfile: boolean;
|
||||
disabled: boolean;
|
||||
};
|
||||
|
||||
function DefaultSubmitButton({
|
||||
isCreatingSession, isCreatingTask,
|
||||
isSessionMode, isCreateMode, isEditMode,
|
||||
hasDescription, isPassthroughProfile, disabled,
|
||||
}: DefaultSubmitButtonProps) {
|
||||
const planModeStyle = isCreateMode && !hasDescription
|
||||
? 'bg-blue-600 border-blue-500 text-white hover:bg-blue-700 hover:text-white'
|
||||
: '';
|
||||
|
||||
return (
|
||||
<Button
|
||||
type="submit"
|
||||
variant="default"
|
||||
className={`w-full h-10 cursor-pointer sm:w-auto sm:h-7 gap-1.5 ${planModeStyle}`}
|
||||
disabled={disabled || isCreatingSession || isCreatingTask || (isSessionMode ? (!hasDescription && !isPassthroughProfile) : false)}
|
||||
>
|
||||
{(() => {
|
||||
if (isCreatingSession || isCreatingTask) {
|
||||
return (
|
||||
<>
|
||||
<IconLoader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
{isEditMode ? 'Updating...' : 'Starting...'}
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (isSessionMode) return 'Create Session';
|
||||
if (isCreateMode) {
|
||||
return (
|
||||
<>
|
||||
<IconFileInvoice className="h-3.5 w-3.5" />
|
||||
Start Plan Mode
|
||||
</>
|
||||
);
|
||||
}
|
||||
return 'Update task';
|
||||
})()}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export type TaskCreateDialogFooterProps = {
|
||||
isSessionMode: boolean;
|
||||
isCreateMode: boolean;
|
||||
isEditMode: boolean;
|
||||
isTaskStarted: boolean;
|
||||
isPassthroughProfile: boolean;
|
||||
isCreatingSession: boolean;
|
||||
isCreatingTask: boolean;
|
||||
hasTitle: boolean;
|
||||
hasDescription: boolean;
|
||||
hasRepositorySelection: boolean;
|
||||
branch: string;
|
||||
agentProfileId: string;
|
||||
workspaceId: string | null;
|
||||
effectiveWorkflowId: string | null;
|
||||
executorHint: string | null;
|
||||
onCancel: () => void;
|
||||
onUpdateWithoutAgent: () => void;
|
||||
onCreateWithoutAgent: () => void;
|
||||
};
|
||||
|
||||
function isMissingWorkflowCtx(isCreateMode: boolean, workspaceId: string | null, effectiveWorkflowId: string | null) {
|
||||
return isCreateMode && (!workspaceId || !effectiveWorkflowId);
|
||||
}
|
||||
|
||||
function computeFooterState(props: TaskCreateDialogFooterProps) {
|
||||
const { isSessionMode, isCreateMode, isEditMode, isPassthroughProfile, isCreatingTask, hasTitle, hasDescription, hasRepositorySelection, branch, agentProfileId, workspaceId, effectiveWorkflowId } = props;
|
||||
const showStartTask = (isCreateMode && (hasDescription || isPassthroughProfile)) || Boolean(isEditMode && agentProfileId);
|
||||
const missingCtx = isMissingWorkflowCtx(isCreateMode, workspaceId, effectiveWorkflowId);
|
||||
const splitDisabled = isCreatingTask || !hasTitle || !hasRepositorySelection || !branch || !agentProfileId || missingCtx;
|
||||
const defaultDisabled = isSessionMode ? !agentProfileId : !hasTitle || !hasRepositorySelection || !branch || missingCtx;
|
||||
return { showStartTask, splitDisabled, defaultDisabled };
|
||||
}
|
||||
|
||||
export const TaskCreateDialogFooter = memo(function TaskCreateDialogFooter(props: TaskCreateDialogFooterProps) {
|
||||
const { isSessionMode, isCreateMode, isEditMode, isTaskStarted, isPassthroughProfile, isCreatingSession, isCreatingTask, hasTitle, hasDescription, executorHint, onCancel, onUpdateWithoutAgent, onCreateWithoutAgent } = props;
|
||||
const { showStartTask, splitDisabled, defaultDisabled } = computeFooterState(props);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isSessionMode && !isTaskStarted && executorHint && (
|
||||
<div className="flex flex-1 items-center gap-3 text-sm text-muted-foreground">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{executorHint}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="outline" onClick={onCancel} disabled={isCreatingSession || isCreatingTask} className="w-full h-10 border-0 cursor-pointer sm:w-auto sm:h-7 sm:border">
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<KeyboardShortcutTooltip shortcut={SHORTCUTS.SUBMIT}>
|
||||
{(() => {
|
||||
if (isTaskStarted) {
|
||||
return <UpdateButton isCreatingTask={isCreatingTask} hasTitle={hasTitle} onUpdate={onUpdateWithoutAgent} />;
|
||||
}
|
||||
if (showStartTask) {
|
||||
return (
|
||||
<StartTaskSplitButton
|
||||
isCreatingTask={isCreatingTask}
|
||||
disabled={splitDisabled}
|
||||
isEditMode={isEditMode}
|
||||
onAltAction={isEditMode ? onUpdateWithoutAgent : onCreateWithoutAgent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<DefaultSubmitButton
|
||||
isCreatingSession={isCreatingSession}
|
||||
isCreatingTask={isCreatingTask}
|
||||
isSessionMode={isSessionMode}
|
||||
isCreateMode={isCreateMode}
|
||||
isEditMode={isEditMode}
|
||||
hasDescription={hasDescription}
|
||||
isPassthroughProfile={isPassthroughProfile}
|
||||
disabled={defaultDisabled}
|
||||
/>
|
||||
);
|
||||
})()}
|
||||
</KeyboardShortcutTooltip>
|
||||
</>
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user