mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-27 07:40:07 +02:00
basic functionality
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
import type { LauncherActiveViewId } from "@app/lib/launcherLocalStorage";
|
||||
import {
|
||||
defaultLauncherViewConfig,
|
||||
parseIdListParam,
|
||||
type LauncherViewConfig,
|
||||
type LauncherViewRecord
|
||||
} from "@server/routers/launcher/types";
|
||||
import { z } from "zod";
|
||||
|
||||
const launcherUrlBooleanSchema = z
|
||||
.enum(["0", "1"])
|
||||
.transform((value) => value === "1");
|
||||
|
||||
export type LauncherUrlConfigOverrides = Partial<
|
||||
Pick<
|
||||
LauncherViewConfig,
|
||||
| "groupBy"
|
||||
| "layout"
|
||||
| "order"
|
||||
| "showLabels"
|
||||
| "showSiteTags"
|
||||
| "siteIds"
|
||||
| "labelIds"
|
||||
| "query"
|
||||
>
|
||||
>;
|
||||
|
||||
export type ParsedLauncherUrlState = {
|
||||
viewId: LauncherActiveViewId | null;
|
||||
configOverrides: LauncherUrlConfigOverrides;
|
||||
hasAnyLauncherParams: boolean;
|
||||
};
|
||||
|
||||
export type ResolvedLauncherState = {
|
||||
activeViewId: LauncherActiveViewId;
|
||||
config: LauncherViewConfig;
|
||||
savedConfig: LauncherViewConfig;
|
||||
};
|
||||
|
||||
const LAUNCHER_CONFIG_PARAM_KEYS = [
|
||||
"query",
|
||||
"groupBy",
|
||||
"layout",
|
||||
"order",
|
||||
"showLabels",
|
||||
"showSiteTags",
|
||||
"siteIds",
|
||||
"labelIds"
|
||||
] as const;
|
||||
|
||||
const LAUNCHER_URL_PARAM_KEYS = [
|
||||
"view",
|
||||
...LAUNCHER_CONFIG_PARAM_KEYS
|
||||
] as const;
|
||||
|
||||
export function hasLauncherConfigParams(searchParams: URLSearchParams) {
|
||||
return LAUNCHER_CONFIG_PARAM_KEYS.some((key) => searchParams.has(key));
|
||||
}
|
||||
|
||||
export function isLauncherConfigEqual(
|
||||
a: LauncherViewConfig,
|
||||
b: LauncherViewConfig
|
||||
) {
|
||||
return JSON.stringify(a) === JSON.stringify(b);
|
||||
}
|
||||
|
||||
export function getLauncherUrlBaseConfig(
|
||||
viewId: LauncherActiveViewId,
|
||||
views: LauncherViewRecord[]
|
||||
): LauncherViewConfig {
|
||||
if (viewId === "default") {
|
||||
return defaultLauncherViewConfig;
|
||||
}
|
||||
|
||||
const savedView = views.find((view) => view.viewId === viewId);
|
||||
return savedView?.config ?? defaultLauncherViewConfig;
|
||||
}
|
||||
|
||||
export function resolveLauncherConfig(
|
||||
baseConfig: LauncherViewConfig,
|
||||
overrides: LauncherUrlConfigOverrides
|
||||
): LauncherViewConfig {
|
||||
return {
|
||||
...baseConfig,
|
||||
...overrides,
|
||||
sortBy: "name"
|
||||
};
|
||||
}
|
||||
|
||||
function parseViewParam(value: string | null): LauncherActiveViewId | null {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value === "default") {
|
||||
return "default";
|
||||
}
|
||||
|
||||
const parsed = Number.parseInt(value, 10);
|
||||
if (!Number.isFinite(parsed)) {
|
||||
return "default";
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function parseConfigOverrides(
|
||||
searchParams: URLSearchParams
|
||||
): LauncherUrlConfigOverrides {
|
||||
const overrides: LauncherUrlConfigOverrides = {};
|
||||
|
||||
const query = searchParams.get("query");
|
||||
if (query !== null) {
|
||||
overrides.query = query;
|
||||
}
|
||||
|
||||
const groupBy = searchParams.get("groupBy");
|
||||
if (groupBy === "site" || groupBy === "label") {
|
||||
overrides.groupBy = groupBy;
|
||||
}
|
||||
|
||||
const layout = searchParams.get("layout");
|
||||
if (layout === "grid" || layout === "list") {
|
||||
overrides.layout = layout;
|
||||
}
|
||||
|
||||
const order = searchParams.get("order");
|
||||
if (order === "asc" || order === "desc") {
|
||||
overrides.order = order;
|
||||
}
|
||||
|
||||
const showLabels = searchParams.get("showLabels");
|
||||
if (showLabels !== null) {
|
||||
const parsed = launcherUrlBooleanSchema.safeParse(showLabels);
|
||||
if (parsed.success) {
|
||||
overrides.showLabels = parsed.data;
|
||||
}
|
||||
}
|
||||
|
||||
const showSiteTags = searchParams.get("showSiteTags");
|
||||
if (showSiteTags !== null) {
|
||||
const parsed = launcherUrlBooleanSchema.safeParse(showSiteTags);
|
||||
if (parsed.success) {
|
||||
overrides.showSiteTags = parsed.data;
|
||||
}
|
||||
}
|
||||
|
||||
const siteIds = searchParams.get("siteIds");
|
||||
if (siteIds !== null) {
|
||||
overrides.siteIds = parseIdListParam(siteIds);
|
||||
}
|
||||
|
||||
const labelIds = searchParams.get("labelIds");
|
||||
if (labelIds !== null) {
|
||||
overrides.labelIds = parseIdListParam(labelIds);
|
||||
}
|
||||
|
||||
return overrides;
|
||||
}
|
||||
|
||||
export function parseLauncherUrlState(
|
||||
searchParams: URLSearchParams
|
||||
): ParsedLauncherUrlState {
|
||||
const hasAnyLauncherParams = LAUNCHER_URL_PARAM_KEYS.some((key) =>
|
||||
searchParams.has(key)
|
||||
);
|
||||
|
||||
return {
|
||||
viewId: parseViewParam(searchParams.get("view")),
|
||||
configOverrides: parseConfigOverrides(searchParams),
|
||||
hasAnyLauncherParams
|
||||
};
|
||||
}
|
||||
|
||||
function isValidActiveViewId(
|
||||
viewId: LauncherActiveViewId,
|
||||
views: LauncherViewRecord[]
|
||||
) {
|
||||
return viewId === "default" || views.some((view) => view.viewId === viewId);
|
||||
}
|
||||
|
||||
export function resolveLauncherStateFromUrl(
|
||||
searchParams: URLSearchParams,
|
||||
views: LauncherViewRecord[],
|
||||
fallbackViewId: LauncherActiveViewId | null
|
||||
): ResolvedLauncherState {
|
||||
const parsed = parseLauncherUrlState(searchParams);
|
||||
|
||||
let activeViewId: LauncherActiveViewId = "default";
|
||||
|
||||
if (parsed.viewId !== null) {
|
||||
activeViewId = isValidActiveViewId(parsed.viewId, views)
|
||||
? parsed.viewId
|
||||
: "default";
|
||||
} else if (!parsed.hasAnyLauncherParams && fallbackViewId !== null) {
|
||||
activeViewId = isValidActiveViewId(fallbackViewId, views)
|
||||
? fallbackViewId
|
||||
: "default";
|
||||
}
|
||||
|
||||
const savedConfig = getLauncherUrlBaseConfig(activeViewId, views);
|
||||
|
||||
let config: LauncherViewConfig;
|
||||
if (hasLauncherConfigParams(searchParams)) {
|
||||
config = resolveLauncherConfig(
|
||||
defaultLauncherViewConfig,
|
||||
parsed.configOverrides
|
||||
);
|
||||
} else if (activeViewId !== "default") {
|
||||
config = savedConfig;
|
||||
} else {
|
||||
config = defaultLauncherViewConfig;
|
||||
}
|
||||
|
||||
return {
|
||||
activeViewId,
|
||||
config,
|
||||
savedConfig
|
||||
};
|
||||
}
|
||||
|
||||
function idListsEqual(a: number[], b: number[]) {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return a.every((value, index) => value === b[index]);
|
||||
}
|
||||
|
||||
export function serializeLauncherUrlState({
|
||||
viewId,
|
||||
config
|
||||
}: {
|
||||
viewId: LauncherActiveViewId;
|
||||
config: LauncherViewConfig;
|
||||
}): URLSearchParams {
|
||||
const baseConfig = defaultLauncherViewConfig;
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (viewId !== "default") {
|
||||
params.set("view", String(viewId));
|
||||
}
|
||||
|
||||
if (config.query !== baseConfig.query && config.query) {
|
||||
params.set("query", config.query);
|
||||
} else if (config.query !== baseConfig.query && !config.query) {
|
||||
params.set("query", "");
|
||||
}
|
||||
|
||||
if (config.groupBy !== baseConfig.groupBy) {
|
||||
params.set("groupBy", config.groupBy);
|
||||
}
|
||||
|
||||
if (config.layout !== baseConfig.layout) {
|
||||
params.set("layout", config.layout);
|
||||
}
|
||||
|
||||
if (config.order !== baseConfig.order) {
|
||||
params.set("order", config.order);
|
||||
}
|
||||
|
||||
if (config.showLabels !== baseConfig.showLabels) {
|
||||
params.set("showLabels", config.showLabels ? "1" : "0");
|
||||
}
|
||||
|
||||
if (config.showSiteTags !== baseConfig.showSiteTags) {
|
||||
params.set("showSiteTags", config.showSiteTags ? "1" : "0");
|
||||
}
|
||||
|
||||
if (!idListsEqual(config.siteIds, baseConfig.siteIds)) {
|
||||
if (config.siteIds.length > 0) {
|
||||
params.set("siteIds", config.siteIds.join(","));
|
||||
} else {
|
||||
params.set("siteIds", "");
|
||||
}
|
||||
}
|
||||
|
||||
if (!idListsEqual(config.labelIds, baseConfig.labelIds)) {
|
||||
if (config.labelIds.length > 0) {
|
||||
params.set("labelIds", config.labelIds.join(","));
|
||||
} else {
|
||||
params.set("labelIds", "");
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
export function buildLauncherPath(orgId: string, params: URLSearchParams) {
|
||||
const query = params.toString();
|
||||
return query ? `/${orgId}?${query}` : `/${orgId}`;
|
||||
}
|
||||
Reference in New Issue
Block a user