show sites and labels for non admins

This commit is contained in:
miloschwartz
2026-07-01 12:17:36 -04:00
parent 75f481bc3d
commit 87e1a509ce
10 changed files with 583 additions and 16 deletions

View File

@@ -8,7 +8,7 @@ import {
CommandItem,
CommandList
} from "@app/components/ui/command";
import { orgQueries } from "@app/lib/queries";
import { launcherQueries, orgQueries } from "@app/lib/queries";
import { useQuery } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
import { useState } from "react";
@@ -27,6 +27,7 @@ type LabelsFilterSelectorProps = {
onToggle: (label: LabelFilterOption) => void;
onClear?: () => void;
showClear?: boolean;
scope?: "org" | "launcher";
};
export function LabelsFilterSelector({
@@ -34,19 +35,33 @@ export function LabelsFilterSelector({
isSelected,
onToggle,
onClear,
showClear = false
showClear = false,
scope = "org"
}: LabelsFilterSelectorProps) {
const t = useTranslations();
const [labelSearchQuery, setlabelsSearchQuery] = useState("");
const [debouncedQuery] = useDebounce(labelSearchQuery, 150);
const { data: labels = [] } = useQuery(
orgQueries.labels({
const orgLabelsQuery = useQuery({
...orgQueries.labels({
orgId,
query: debouncedQuery,
perPage: 500
})
);
}),
enabled: scope === "org"
});
const launcherLabelsQuery = useQuery({
...launcherQueries.labels({
orgId,
query: debouncedQuery,
perPage: 500
}),
enabled: scope === "launcher"
});
const labels =
scope === "launcher"
? (launcherLabelsQuery.data ?? [])
: (orgLabelsQuery.data ?? []);
return (
<Command shouldFilter={false}>

View File

@@ -1,4 +1,4 @@
import { orgQueries } from "@app/lib/queries";
import { launcherQueries, orgQueries } from "@app/lib/queries";
import { useQuery } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import {
@@ -19,6 +19,7 @@ export type MultiSitesSelectorProps = {
selectedSites: Selectedsite[];
onSelectionChange: (sites: Selectedsite[]) => void;
filterTypes?: string[];
scope?: "org" | "launcher";
};
export function formatMultiSitesSelectorLabel(
@@ -40,19 +41,33 @@ export function MultiSitesSelector({
orgId,
selectedSites,
onSelectionChange,
filterTypes
filterTypes,
scope = "org"
}: MultiSitesSelectorProps) {
const t = useTranslations();
const [siteSearchQuery, setSiteSearchQuery] = useState("");
const [debouncedQuery] = useDebounce(siteSearchQuery, 150);
const { data: sites = [] } = useQuery(
orgQueries.sites({
const orgSitesQuery = useQuery({
...orgQueries.sites({
orgId,
query: debouncedQuery,
perPage: 10
})
);
}),
enabled: scope === "org"
});
const launcherSitesQuery = useQuery({
...launcherQueries.sites({
orgId,
query: debouncedQuery,
perPage: 500
}),
enabled: scope === "launcher"
});
const sites =
scope === "launcher"
? (launcherSitesQuery.data ?? [])
: (orgSitesQuery.data ?? []);
const sitesShown = useMemo(() => {
const base = filterTypes

View File

@@ -17,7 +17,7 @@ import {
PopoverTrigger
} from "@app/components/ui/popover";
import { cn } from "@app/lib/cn";
import { orgQueries } from "@app/lib/queries";
import { launcherQueries } from "@app/lib/queries";
import { useQuery } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
import { ChevronsUpDown, Funnel } from "lucide-react";
@@ -44,12 +44,37 @@ export function LauncherFilterPopover({
const [labelsOpen, setLabelsOpen] = useState(false);
const { data: labels = [] } = useQuery(
orgQueries.labels({
launcherQueries.labels({
orgId,
perPage: 500
})
);
const { data: sites = [] } = useQuery(
launcherQueries.sites({
orgId,
perPage: 500
})
);
const resolvedSelectedSites: Selectedsite[] = useMemo(
() =>
selectedSites.map((selected) => {
const found = sites.find(
(site) => site.siteId === selected.siteId
);
return found
? {
siteId: found.siteId,
name: found.name,
type: found.type,
online: found.online
}
: selected;
}),
[sites, selectedSites]
);
const selectedLabelIds = useMemo(
() => new Set(selectedLabels.map((label) => label.labelId)),
[selectedLabels]
@@ -98,7 +123,7 @@ export function LauncherFilterPopover({
>
<span className="truncate text-left">
{formatMultiSitesSelectorLabel(
selectedSites,
resolvedSelectedSites,
t
)}
</span>
@@ -111,8 +136,9 @@ export function LauncherFilterPopover({
>
<MultiSitesSelector
orgId={orgId}
selectedSites={selectedSites}
selectedSites={resolvedSelectedSites}
onSelectionChange={onSitesChange}
scope="launcher"
/>
</PopoverContent>
</Popover>
@@ -145,6 +171,7 @@ export function LauncherFilterPopover({
>
<LabelsFilterSelector
orgId={orgId}
scope="launcher"
isSelected={(label) =>
selectedLabelIds.has(label.labelId)
}

View File

@@ -48,7 +48,9 @@ import type { ListResourcePoliciesResponse } from "@server/routers/resource/type
import type { GetResourcePolicyResponse } from "@server/routers/policy";
import type {
ListLauncherGroupsResponse,
ListLauncherLabelsResponse,
ListLauncherResourcesResponse,
ListLauncherSitesResponse,
ListLauncherViewsResponse,
LauncherListQuery,
LauncherViewConfig
@@ -1190,6 +1192,72 @@ export const launcherQueries = {
return res.data.data.views;
}
}),
sites: ({
orgId,
query,
perPage = 500
}: {
orgId: string;
query?: string;
perPage?: number;
}) =>
queryOptions({
queryKey: [
"ORG",
orgId,
"LAUNCHER",
"SITES",
{ query, perPage }
] as const,
queryFn: async ({ signal, meta }) => {
const sp = new URLSearchParams({
pageSize: perPage.toString()
});
if (query?.trim()) {
sp.set("query", query);
}
const res = await meta!.api.get<
AxiosResponse<ListLauncherSitesResponse>
>(`/org/${orgId}/launcher/sites?${sp.toString()}`, { signal });
return res.data.data.sites;
}
}),
labels: ({
orgId,
query,
perPage = 500
}: {
orgId: string;
query?: string;
perPage?: number;
}) =>
queryOptions({
queryKey: [
"ORG",
orgId,
"LAUNCHER",
"LABELS",
{ query, perPage }
] as const,
queryFn: async ({ signal, meta }) => {
const sp = new URLSearchParams({
pageSize: perPage.toString()
});
if (query?.trim()) {
sp.set("query", query);
}
const res = await meta!.api.get<
AxiosResponse<ListLauncherLabelsResponse>
>(`/org/${orgId}/launcher/labels?${sp.toString()}`, {
signal
});
return res.data.data.labels;
}
}),
groups: (orgId: string, filters: LauncherQueryFilters) =>
infiniteQueryOptions({
queryKey: ["ORG", orgId, "LAUNCHER", "GROUPS", filters] as const,