Files
pangolin/server/routers/launcher/launcherScale.ts
T
2026-07-02 22:07:30 -04:00

128 lines
3.5 KiB
TypeScript

import { regionalCache as cache } from "#dynamic/lib/cache";
import {
listLauncherGroupsForUser,
resolveAccessibleIds
} from "./launcherResourceAccess";
import {
parseIdListParam,
type LauncherScaleInfo,
type LauncherScaleQuery
} from "./types";
export const LAUNCHER_FULL_MAX_RESOURCES = 2000;
export const LAUNCHER_FULL_MAX_SITE_GROUPS = 200;
export const LAUNCHER_FULL_MAX_LABEL_GROUPS = 100;
export const LAUNCHER_FILTERED_SITE_GROUPING_MAX = 20;
const LAUNCHER_SCALE_TTL_SEC = 60;
function launcherScaleCacheKey(
orgId: string,
userId: string,
roleIds: number[],
query: LauncherScaleQuery
) {
const rolesKey = [...roleIds].sort((a, b) => a - b).join(",");
const filterKey = [
query.query,
query.groupBy,
query.siteIds ?? "",
query.labelIds ?? "",
query.sort_by,
query.order
].join("|");
return `launcherScale:${orgId}:${userId}:${rolesKey}:${filterKey}`;
}
async function getLauncherScaleForUserUncached(
orgId: string,
userId: string,
userRoleIds: number[],
query: LauncherScaleQuery
): Promise<LauncherScaleInfo> {
const accessible = await resolveAccessibleIds(orgId, userId, userRoleIds);
const resourceCount =
accessible.resourceIds.length + accessible.siteResourceIds.length;
const baselineQuery = {
query: "",
groupBy: "site" as const,
siteIds: undefined,
labelIds: undefined,
sort_by: "name" as const,
order: "asc" as const,
page: 1,
pageSize: 1
};
const [{ total: siteGroupCount }, { total: labelGroupCount }] =
await Promise.all([
listLauncherGroupsForUser(
orgId,
userId,
userRoleIds,
baselineQuery
),
listLauncherGroupsForUser(orgId, userId, userRoleIds, {
...baselineQuery,
groupBy: "label"
})
]);
const mode =
resourceCount <= LAUNCHER_FULL_MAX_RESOURCES &&
siteGroupCount <= LAUNCHER_FULL_MAX_SITE_GROUPS
? "full"
: "compact";
const siteFilterIds = parseIdListParam(query.siteIds);
const labelFilterIds = parseIdListParam(query.labelIds);
const allowSiteGrouping =
siteGroupCount <= LAUNCHER_FULL_MAX_SITE_GROUPS ||
(siteFilterIds.length > 0 &&
siteFilterIds.length <= LAUNCHER_FILTERED_SITE_GROUPING_MAX);
const allowLabelGrouping =
labelGroupCount <= LAUNCHER_FULL_MAX_LABEL_GROUPS ||
(labelFilterIds.length > 0 &&
labelFilterIds.length <= LAUNCHER_FILTERED_SITE_GROUPING_MAX);
const requireSearchOrFilter =
mode === "compact" && resourceCount > LAUNCHER_FULL_MAX_RESOURCES;
return {
mode,
resourceCount,
siteGroupCount,
labelGroupCount,
capabilities: {
allowSiteGrouping,
allowLabelGrouping,
requireSearchOrFilter
}
};
}
export async function getLauncherScaleForUser(
orgId: string,
userId: string,
userRoleIds: number[],
query: LauncherScaleQuery
): Promise<LauncherScaleInfo> {
const cacheKey = launcherScaleCacheKey(orgId, userId, userRoleIds, query);
const cached = await cache.get<LauncherScaleInfo>(cacheKey);
if (cached) {
return cached;
}
const result = await getLauncherScaleForUserUncached(
orgId,
userId,
userRoleIds,
query
);
await cache.set(cacheKey, result, LAUNCHER_SCALE_TTL_SEC);
return result;
}