68c94dfa3a
* docs: define product and design direction * style: establish restrained workbench primitives * refactor: declutter board and task topbars * style: align dockview panel chrome * fix: align task topbar vcs control sizing * refactor: surface integrations navigation * fix: repair integrations and task creation workflow * refactor: include linear in integrations navigation * style: restore familiar workbench tones * fix: add dockview tab breathing room * fix: show configured integration shortcuts * fix: hover open integrations menu * fix: stabilize integrations hover menu * fix: align home and dockview topbars * fix: normalize home topbar controls * fix: compact home topbar height * fix: simplify home chrome and split buttons * fix: move integrations to left chrome * fix: restore home stats shortcut * fix: add dockview tab breathing room * fix: border home stats button * fix: streamline dockview topbar actions * fix: align task split button seam * fix: address review feedback * fix: restore topbar e2e affordances * fix: stabilize workflow e2e isolation * fix: add task topbar action overflow * fix: address PR review feedback
95 lines
3.0 KiB
TypeScript
95 lines
3.0 KiB
TypeScript
"use client";
|
|
|
|
import { useRouter } from "next/navigation";
|
|
import type { ComponentProps } from "react";
|
|
import { Button } from "@kandev/ui/button";
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogDescription,
|
|
} from "@kandev/ui/dialog";
|
|
import { IconAlertTriangle, IconExternalLink } from "@tabler/icons-react";
|
|
import { useAppStore } from "@/components/state-provider";
|
|
import type { HealthIssue } from "@/lib/types/health";
|
|
|
|
type HealthIndicatorButtonProps = {
|
|
hasIssues: boolean;
|
|
onClick: () => void;
|
|
size?: ComponentProps<typeof Button>["size"];
|
|
};
|
|
|
|
export function HealthIndicatorButton({
|
|
hasIssues,
|
|
onClick,
|
|
size = "icon",
|
|
}: HealthIndicatorButtonProps) {
|
|
if (!hasIssues) return null;
|
|
|
|
return (
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button variant="outline" size={size} onClick={onClick} className="cursor-pointer relative">
|
|
<IconAlertTriangle className="h-4 w-4 text-amber-500" />
|
|
<span className="absolute -top-1 -right-1 h-2.5 w-2.5 rounded-full bg-amber-500 border-2 border-background" />
|
|
<span className="sr-only">Setup Issues</span>
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>Setup Issues</TooltipContent>
|
|
</Tooltip>
|
|
);
|
|
}
|
|
|
|
type HealthIssuesDialogProps = {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
issues: HealthIssue[];
|
|
};
|
|
|
|
export function HealthIssuesDialog({ open, onOpenChange, issues }: HealthIssuesDialogProps) {
|
|
const router = useRouter();
|
|
const workspaceId = useAppStore((state) => state.workspaces.activeId);
|
|
|
|
const resolveUrl = (url: string) => url.replace("{workspaceId}", workspaceId ?? "");
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="sm:max-w-[480px]">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2">
|
|
<IconAlertTriangle className="h-5 w-5 text-amber-500" />
|
|
Setup Issues
|
|
</DialogTitle>
|
|
<DialogDescription>
|
|
{issues.length === 1
|
|
? "1 issue needs your attention"
|
|
: `${issues.length} issues need your attention`}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<div className="space-y-4 pt-2">
|
|
{issues.map((issue) => (
|
|
<div key={issue.id} className="rounded-lg border p-3 space-y-2">
|
|
<div className="font-medium text-sm">{issue.title}</div>
|
|
<div className="text-muted-foreground text-xs">{issue.message}</div>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
className="cursor-pointer h-7 text-xs"
|
|
onClick={() => {
|
|
onOpenChange(false);
|
|
router.push(resolveUrl(issue.fix_url));
|
|
}}
|
|
>
|
|
{issue.fix_label}
|
|
<IconExternalLink className="h-3 w-3 ml-1" />
|
|
</Button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|