more ui/ux enhancements around labels and tables

This commit is contained in:
miloschwartz
2026-05-26 22:26:54 -07:00
parent 05e4ad3200
commit 938e9b0d49
13 changed files with 246 additions and 276 deletions
+25 -64
View File
@@ -37,7 +37,6 @@ import {
ChevronDown,
ChevronsUpDownIcon,
MoreHorizontal,
PlusIcon
} from "lucide-react";
import { useTranslations } from "next-intl";
import Link from "next/link";
@@ -46,7 +45,6 @@ import {
startTransition,
useEffect,
useMemo,
useOptimistic,
useState,
useTransition
} from "react";
@@ -61,11 +59,10 @@ import {
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { cn } from "@app/lib/cn";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
import { LabelBadge } from "./label-badge";
import { LabelOverflowBadge } from "./label-overflow-badge";
import { LabelsSelector, type SelectedLabel } from "./labels-selector";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import { type SelectedLabel } from "./labels-selector";
import { LabelColumnFilterButton } from "./LabelColumnFilterButton";
import { useLocalLabels } from "@app/hooks/useLocalLabels";
import { TableLabelsCell } from "./TableLabelsCell";
export type SiteRow = {
id: number;
@@ -124,12 +121,12 @@ export default function SitesTable({
const api = createApiClient(useEnvContext());
const t = useTranslations();
useEffect(() => {
const interval = setInterval(() => {
router.refresh();
}, 30_000);
return () => clearInterval(interval);
}, []);
// useEffect(() => {
// const interval = setInterval(() => {
// router.refresh();
// }, 30_000);
// return () => clearInterval(interval);
// }, []);
const booleanSearchFilterSchema = z
.enum(["true", "false"])
@@ -225,7 +222,7 @@ export default function SitesTable({
},
{
accessorKey: "online",
friendlyName: t("online"),
friendlyName: t("status"),
header: () => {
return (
<ColumnFilterButton
@@ -241,7 +238,7 @@ export default function SitesTable({
}
searchPlaceholder={t("searchPlaceholder")}
emptyMessage={t("emptySearchOptions")}
label={t("online")}
label={t("status")}
className="p-3"
/>
);
@@ -693,29 +690,26 @@ function SiteLabelCell({ site, orgId }: SiteLabelCellProps) {
const api = createApiClient(useEnvContext());
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const router = useRouter();
const labels = site.labels ?? [];
const [optimisticLabels, setOptimisticLabels] = useOptimistic(labels);
const [localLabels, setLocalLabels] = useLocalLabels(site.labels, site.id);
function toggleSiteLabel(
label: SelectedLabel,
action: "attach" | "detach"
) {
startTransition(async () => {
const previousLabels = localLabels;
void (async () => {
try {
if (action === "attach") {
setOptimisticLabels([...optimisticLabels, label]);
setLocalLabels([...previousLabels, label]);
await api.put(
`/org/${orgId}/label/${label.labelId}/attach`,
{ siteId: site.id }
);
} else {
setOptimisticLabels(
optimisticLabels.filter(
setLocalLabels(
previousLabels.filter(
(lb) => lb.labelId !== label.labelId
)
);
@@ -725,54 +719,21 @@ function SiteLabelCell({ site, orgId }: SiteLabelCellProps) {
);
}
} catch (e) {
setLocalLabels(previousLabels);
toast({
title: t("error"),
description: formatAxiosError(e, t("errorOccurred")),
variant: "destructive"
});
} finally {
router.refresh();
}
});
})();
}
const visibleLabels = optimisticLabels.slice(0, 3);
const overflowLabels = optimisticLabels.slice(3);
return (
<div className="inline-flex w-full min-w-0 flex-nowrap items-center gap-1 overflow-hidden">
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
<PopoverTrigger asChild>
<Button
size="icon"
variant="outline"
className="size-auto shrink-0 rounded-full p-1"
title={t("addLabels")}
>
<span className="sr-only">{t("addLabels")}</span>
<PlusIcon className="size-3" />
</Button>
</PopoverTrigger>
<PopoverContent align="center" className="p-0 w-full">
<LabelsSelector
orgId={orgId}
selectedLabels={optimisticLabels}
toggleLabel={toggleSiteLabel}
/>
</PopoverContent>
</Popover>
{visibleLabels.map((label) => (
<LabelBadge
key={label.labelId}
className="shrink-0"
onClick={() => setIsPopoverOpen(true)}
{...label}
/>
))}
<LabelOverflowBadge
labels={overflowLabels}
onClick={() => setIsPopoverOpen(true)}
/>
</div>
<TableLabelsCell
orgId={orgId}
localLabels={localLabels}
toggleLabel={toggleSiteLabel}
/>
);
}