mirror of
https://github.com/fosrl/pangolin.git
synced 2026-04-15 14:26:36 +00:00
remove extra sites query
This commit is contained in:
@@ -20,7 +20,7 @@ import {
|
||||
ArrowDown01Icon,
|
||||
ArrowUp10Icon,
|
||||
ArrowUpDown,
|
||||
ArrowUpRight,
|
||||
ChevronDown,
|
||||
ChevronsUpDownIcon,
|
||||
MoreHorizontal
|
||||
} from "lucide-react";
|
||||
@@ -38,16 +38,13 @@ import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||
import { useNavigationContext } from "@app/hooks/useNavigationContext";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import { ColumnFilterButton } from "./ColumnFilterButton";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger
|
||||
} from "@app/components/ui/popover";
|
||||
import { cn } from "@app/lib/cn";
|
||||
|
||||
export type InternalResourceSiteRow = {
|
||||
siteId: number;
|
||||
siteName: string;
|
||||
siteNiceId: string;
|
||||
online: boolean;
|
||||
};
|
||||
|
||||
export type InternalResourceRow = {
|
||||
@@ -113,99 +110,106 @@ function isSafeUrlForLink(href: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_SITE_LINKS = 3;
|
||||
type AggregateSitesStatus = "allOnline" | "partial" | "allOffline";
|
||||
|
||||
function ClientResourceSiteLinks({
|
||||
orgId,
|
||||
sites
|
||||
}: {
|
||||
orgId: string;
|
||||
sites: InternalResourceSiteRow[];
|
||||
}) {
|
||||
if (sites.length === 0) {
|
||||
return <span>-</span>;
|
||||
function aggregateSitesStatus(
|
||||
resourceSites: InternalResourceSiteRow[]
|
||||
): AggregateSitesStatus {
|
||||
if (resourceSites.length === 0) {
|
||||
return "allOffline";
|
||||
}
|
||||
const visible = sites.slice(0, MAX_SITE_LINKS);
|
||||
const overflow = sites.slice(MAX_SITE_LINKS);
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap items-center gap-1">
|
||||
{visible.map((site) => (
|
||||
<Link
|
||||
key={site.siteId}
|
||||
href={`/${orgId}/settings/sites/${site.siteNiceId}`}
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="w-full gap-1"
|
||||
>
|
||||
<span className="max-w-[10rem] truncate">
|
||||
{site.siteName}
|
||||
</span>
|
||||
<ArrowUpRight className="h-3 w-3 shrink-0" />
|
||||
</Button>
|
||||
</Link>
|
||||
))}
|
||||
{overflow.length > 0 ? (
|
||||
<OverflowSitesPopover orgId={orgId} sites={overflow} />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
const onlineCount = resourceSites.filter((rs) => rs.online).length;
|
||||
if (onlineCount === resourceSites.length) return "allOnline";
|
||||
if (onlineCount > 0) return "partial";
|
||||
return "allOffline";
|
||||
}
|
||||
|
||||
function OverflowSitesPopover({
|
||||
function aggregateStatusDotClass(status: AggregateSitesStatus): string {
|
||||
switch (status) {
|
||||
case "allOnline":
|
||||
return "bg-green-500";
|
||||
case "partial":
|
||||
return "bg-yellow-500";
|
||||
case "allOffline":
|
||||
default:
|
||||
return "bg-gray-500";
|
||||
}
|
||||
}
|
||||
|
||||
function ClientResourceSitesStatusCell({
|
||||
orgId,
|
||||
sites
|
||||
resourceSites
|
||||
}: {
|
||||
orgId: string;
|
||||
sites: InternalResourceSiteRow[];
|
||||
resourceSites: InternalResourceSiteRow[];
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const t = useTranslations();
|
||||
|
||||
if (resourceSites.length === 0) {
|
||||
return <span>-</span>;
|
||||
}
|
||||
|
||||
const aggregate = aggregateSitesStatus(resourceSites);
|
||||
const countLabel = t("multiSitesSelectorSitesCount", {
|
||||
count: resourceSites.length
|
||||
});
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="gap-1 px-2 font-normal"
|
||||
onMouseEnter={() => setOpen(true)}
|
||||
onMouseLeave={() => setOpen(false)}
|
||||
className="flex h-8 items-center gap-2 px-0 font-normal"
|
||||
>
|
||||
+{sites.length}
|
||||
<div
|
||||
className={cn(
|
||||
"h-2 w-2 shrink-0 rounded-full",
|
||||
aggregateStatusDotClass(aggregate)
|
||||
)}
|
||||
/>
|
||||
<span className="text-sm tabular-nums">{countLabel}</span>
|
||||
<ChevronDown className="h-3 w-3 shrink-0" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align="start"
|
||||
side="top"
|
||||
className="w-auto max-w-xs p-2"
|
||||
onMouseEnter={() => setOpen(true)}
|
||||
onMouseLeave={() => setOpen(false)}
|
||||
>
|
||||
<ul className="flex flex-col gap-1.5 text-sm">
|
||||
{sites.map((site) => (
|
||||
<li key={site.siteId}>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" className="min-w-56">
|
||||
{resourceSites.map((site) => {
|
||||
const isOnline = site.online;
|
||||
return (
|
||||
<DropdownMenuItem key={site.siteId} asChild>
|
||||
<Link
|
||||
href={`/${orgId}/settings/sites/${site.siteNiceId}`}
|
||||
className="flex cursor-pointer items-center justify-between gap-4"
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="w-full justify-start gap-1"
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<div
|
||||
className={cn(
|
||||
"h-2 w-2 shrink-0 rounded-full",
|
||||
isOnline
|
||||
? "bg-green-500"
|
||||
: "bg-gray-500"
|
||||
)}
|
||||
/>
|
||||
<span className="truncate">
|
||||
{site.siteName}
|
||||
</span>
|
||||
<ArrowUpRight className="ml-auto h-3 w-3 shrink-0" />
|
||||
</Button>
|
||||
</div>
|
||||
<span
|
||||
className={cn(
|
||||
"shrink-0 capitalize",
|
||||
isOnline
|
||||
? "text-green-600"
|
||||
: "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{isOnline ? t("online") : t("offline")}
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -243,8 +247,6 @@ export default function ClientResourcesTable({
|
||||
useState<InternalResourceRow | null>();
|
||||
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
||||
|
||||
const { data: sites = [] } = useQuery(orgQueries.sites({ orgId }));
|
||||
|
||||
const [isRefreshing, startTransition] = useTransition();
|
||||
|
||||
const refreshData = () => {
|
||||
@@ -339,9 +341,9 @@ export default function ClientResourcesTable({
|
||||
cell: ({ row }) => {
|
||||
const resourceRow = row.original;
|
||||
return (
|
||||
<ClientResourceSiteLinks
|
||||
<ClientResourceSitesStatusCell
|
||||
orgId={resourceRow.orgId}
|
||||
sites={resourceRow.sites}
|
||||
resourceSites={resourceRow.sites}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -599,7 +601,6 @@ export default function ClientResourcesTable({
|
||||
setOpen={setIsEditDialogOpen}
|
||||
resource={editingResource}
|
||||
orgId={orgId}
|
||||
sites={sites}
|
||||
onSuccess={() => {
|
||||
// Delay refresh to allow modal to close smoothly
|
||||
setTimeout(() => {
|
||||
@@ -614,7 +615,6 @@ export default function ClientResourcesTable({
|
||||
open={isCreateDialogOpen}
|
||||
setOpen={setIsCreateDialogOpen}
|
||||
orgId={orgId}
|
||||
sites={sites}
|
||||
onSuccess={() => {
|
||||
// Delay refresh to allow modal to close smoothly
|
||||
setTimeout(() => {
|
||||
|
||||
Reference in New Issue
Block a user