mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-07 14:44:52 +02:00
show no site category
This commit is contained in:
@@ -3572,6 +3572,7 @@
|
|||||||
"resourceLauncherDeleteView": "Delete View",
|
"resourceLauncherDeleteView": "Delete View",
|
||||||
"resourceLauncherViewAsAdmin": "View as Admin",
|
"resourceLauncherViewAsAdmin": "View as Admin",
|
||||||
"resourceLauncherUnlabeled": "Unlabeled",
|
"resourceLauncherUnlabeled": "Unlabeled",
|
||||||
|
"resourceLauncherNoSite": "No Site",
|
||||||
"resourceLauncherNoResourcesInGroup": "No resources in this group",
|
"resourceLauncherNoResourcesInGroup": "No resources in this group",
|
||||||
"resourceLauncherEmptyStateTitle": "No Resources Available",
|
"resourceLauncherEmptyStateTitle": "No Resources Available",
|
||||||
"resourceLauncherEmptyStateDescription": "You don't have access to any resources yet. Contact your administrator to request access.",
|
"resourceLauncherEmptyStateDescription": "You don't have access to any resources yet. Contact your administrator to request access.",
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
countDistinct,
|
countDistinct,
|
||||||
eq,
|
eq,
|
||||||
inArray,
|
inArray,
|
||||||
|
isNull,
|
||||||
like,
|
like,
|
||||||
or,
|
or,
|
||||||
sql
|
sql
|
||||||
@@ -38,6 +39,7 @@ import {
|
|||||||
formatSiteResourceAccess
|
formatSiteResourceAccess
|
||||||
} from "./formatLauncherAccess";
|
} from "./formatLauncherAccess";
|
||||||
import {
|
import {
|
||||||
|
LAUNCHER_NO_SITE_GROUP_KEY,
|
||||||
LAUNCHER_UNLABELED_GROUP_KEY,
|
LAUNCHER_UNLABELED_GROUP_KEY,
|
||||||
type LauncherGroup,
|
type LauncherGroup,
|
||||||
type LauncherLabel,
|
type LauncherLabel,
|
||||||
@@ -508,6 +510,83 @@ async function listSiteGroups(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let noSiteCount = 0;
|
||||||
|
|
||||||
|
if (accessible.resourceIds.length > 0 && siteFilterIds.length === 0) {
|
||||||
|
const noSitePublicConditions = [
|
||||||
|
inArray(resources.resourceId, accessible.resourceIds),
|
||||||
|
eq(resources.orgId, orgId),
|
||||||
|
eq(resources.enabled, true)
|
||||||
|
];
|
||||||
|
if (searchPublic) {
|
||||||
|
noSitePublicConditions.push(searchPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
let noSitePublicQuery = db
|
||||||
|
.select({
|
||||||
|
itemCount: countDistinct(resources.resourceId)
|
||||||
|
})
|
||||||
|
.from(resources)
|
||||||
|
.leftJoin(targets, eq(targets.resourceId, resources.resourceId));
|
||||||
|
|
||||||
|
if (labelFilterIds.length > 0) {
|
||||||
|
noSitePublicQuery = noSitePublicQuery.innerJoin(
|
||||||
|
resourceLabels,
|
||||||
|
eq(resourceLabels.resourceId, resources.resourceId)
|
||||||
|
);
|
||||||
|
noSitePublicConditions.push(
|
||||||
|
inArray(resourceLabels.labelId, labelFilterIds)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [noSitePublicRow] = await noSitePublicQuery.where(
|
||||||
|
and(...noSitePublicConditions, isNull(targets.targetId))
|
||||||
|
);
|
||||||
|
|
||||||
|
noSiteCount += Number(noSitePublicRow?.itemCount ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessible.siteResourceIds.length > 0 && siteFilterIds.length === 0) {
|
||||||
|
const noSiteSiteConditions = [
|
||||||
|
inArray(siteResources.siteResourceId, accessible.siteResourceIds),
|
||||||
|
eq(siteResources.orgId, orgId),
|
||||||
|
eq(siteResources.enabled, true)
|
||||||
|
];
|
||||||
|
if (searchSite) {
|
||||||
|
noSiteSiteConditions.push(searchSite);
|
||||||
|
}
|
||||||
|
|
||||||
|
let noSiteSiteQuery = db
|
||||||
|
.select({
|
||||||
|
itemCount: countDistinct(siteResources.siteResourceId)
|
||||||
|
})
|
||||||
|
.from(siteResources)
|
||||||
|
.leftJoin(
|
||||||
|
siteNetworks,
|
||||||
|
eq(siteResources.networkId, siteNetworks.networkId)
|
||||||
|
)
|
||||||
|
.leftJoin(sites, eq(siteNetworks.siteId, sites.siteId));
|
||||||
|
|
||||||
|
if (labelFilterIds.length > 0) {
|
||||||
|
noSiteSiteQuery = noSiteSiteQuery.innerJoin(
|
||||||
|
siteResourceLabels,
|
||||||
|
eq(
|
||||||
|
siteResourceLabels.siteResourceId,
|
||||||
|
siteResources.siteResourceId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
noSiteSiteConditions.push(
|
||||||
|
inArray(siteResourceLabels.labelId, labelFilterIds)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [noSiteSiteRow] = await noSiteSiteQuery.where(
|
||||||
|
and(...noSiteSiteConditions, isNull(sites.siteId))
|
||||||
|
);
|
||||||
|
|
||||||
|
noSiteCount += Number(noSiteSiteRow?.itemCount ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
let groups: LauncherGroup[] = Array.from(siteCountMap.values()).map(
|
let groups: LauncherGroup[] = Array.from(siteCountMap.values()).map(
|
||||||
(row) => ({
|
(row) => ({
|
||||||
groupKey: String(row.siteId),
|
groupKey: String(row.siteId),
|
||||||
@@ -519,6 +598,15 @@ async function listSiteGroups(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (noSiteCount > 0 && siteFilterIds.length === 0) {
|
||||||
|
groups.push({
|
||||||
|
groupKey: LAUNCHER_NO_SITE_GROUP_KEY,
|
||||||
|
name: "No Site",
|
||||||
|
groupType: "site",
|
||||||
|
itemCount: noSiteCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
groups.sort((a, b) => {
|
groups.sort((a, b) => {
|
||||||
const cmp = a.name.localeCompare(b.name, undefined, {
|
const cmp = a.name.localeCompare(b.name, undefined, {
|
||||||
sensitivity: "base"
|
sensitivity: "base"
|
||||||
@@ -923,6 +1011,20 @@ async function mapSiteResources(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterResourcesBySite(
|
||||||
|
items: LauncherResource[],
|
||||||
|
groupKey: string
|
||||||
|
): LauncherResource[] {
|
||||||
|
if (groupKey === LAUNCHER_NO_SITE_GROUP_KEY) {
|
||||||
|
return items.filter((item) => !item.site);
|
||||||
|
}
|
||||||
|
const siteId = Number.parseInt(groupKey, 10);
|
||||||
|
if (!Number.isFinite(siteId)) {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
return items.filter((item) => item.site?.siteId === siteId);
|
||||||
|
}
|
||||||
|
|
||||||
function filterResourcesByLabel(
|
function filterResourcesByLabel(
|
||||||
items: LauncherResource[],
|
items: LauncherResource[],
|
||||||
groupKey: string
|
groupKey: string
|
||||||
@@ -1052,10 +1154,14 @@ export async function listLauncherResourcesForUser(
|
|||||||
filteredSiteResourceIds
|
filteredSiteResourceIds
|
||||||
);
|
);
|
||||||
|
|
||||||
const siteIdFilter =
|
const parsedSiteId =
|
||||||
query.groupBy === "site"
|
query.groupBy === "site" &&
|
||||||
|
query.groupKey !== LAUNCHER_NO_SITE_GROUP_KEY
|
||||||
? Number.parseInt(query.groupKey, 10)
|
? Number.parseInt(query.groupKey, 10)
|
||||||
: undefined;
|
: Number.NaN;
|
||||||
|
const siteIdFilter = Number.isFinite(parsedSiteId)
|
||||||
|
? parsedSiteId
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const [publicItems, siteItems] = await Promise.all([
|
const [publicItems, siteItems] = await Promise.all([
|
||||||
mapPublicResources(
|
mapPublicResources(
|
||||||
@@ -1077,6 +1183,8 @@ export async function listLauncherResourcesForUser(
|
|||||||
|
|
||||||
if (query.groupBy === "label") {
|
if (query.groupBy === "label") {
|
||||||
items = filterResourcesByLabel(items, query.groupKey);
|
items = filterResourcesByLabel(items, query.groupKey);
|
||||||
|
} else if (query.groupBy === "site") {
|
||||||
|
items = filterResourcesBySite(items, query.groupKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
items = sortLauncherResources(items, query.order);
|
items = sortLauncherResources(items, query.order);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const LAUNCHER_UNLABELED_GROUP_KEY = "unlabeled";
|
export const LAUNCHER_UNLABELED_GROUP_KEY = "unlabeled";
|
||||||
|
export const LAUNCHER_NO_SITE_GROUP_KEY = "no-site";
|
||||||
|
|
||||||
export const launcherViewConfigSchema = z.object({
|
export const launcherViewConfigSchema = z.object({
|
||||||
groupBy: z.enum(["site", "label"]).default("site"),
|
groupBy: z.enum(["site", "label"]).default("site"),
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ import type {
|
|||||||
LauncherResource,
|
LauncherResource,
|
||||||
LauncherViewConfig
|
LauncherViewConfig
|
||||||
} from "@server/routers/launcher/types";
|
} from "@server/routers/launcher/types";
|
||||||
|
import {
|
||||||
|
LAUNCHER_NO_SITE_GROUP_KEY,
|
||||||
|
LAUNCHER_UNLABELED_GROUP_KEY
|
||||||
|
} from "@server/routers/launcher/types";
|
||||||
import { useInfiniteQuery } from "@tanstack/react-query";
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -140,9 +144,11 @@ export function LauncherGroupSection({
|
|||||||
}, [fetchNextPage, hasNextPage, isFetchingNextPage, isOpen]);
|
}, [fetchNextPage, hasNextPage, isFetchingNextPage, isOpen]);
|
||||||
|
|
||||||
const groupTitle =
|
const groupTitle =
|
||||||
group.groupKey === "unlabeled"
|
group.groupKey === LAUNCHER_UNLABELED_GROUP_KEY
|
||||||
? t("resourceLauncherUnlabeled")
|
? t("resourceLauncherUnlabeled")
|
||||||
: group.name;
|
: group.groupKey === LAUNCHER_NO_SITE_GROUP_KEY
|
||||||
|
? t("resourceLauncherNoSite")
|
||||||
|
: group.name;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapsible
|
<Collapsible
|
||||||
|
|||||||
Reference in New Issue
Block a user