Files
Stalwart-webui/src/lib/layout.ts
T
2026-04-20 15:02:57 +02:00

196 lines
5.8 KiB
TypeScript

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
import type { Layout, LayoutItem, LayoutSubItem, Schema } from '@/types/schema';
import { resolveObject } from '@/lib/schemaResolver';
function findFirstSubLink(items: LayoutSubItem[]): string | null {
for (const item of items) {
if (item.type === 'link') return item.viewName;
if (item.type === 'container') {
const found = findFirstSubLink(item.items);
if (found) return found;
}
}
return null;
}
export function findFirstLinkInLayout(items: LayoutItem[] | Layout): string | null {
const list = Array.isArray(items) ? items : items.items;
for (const item of list) {
if ('link' in item) return item.link.viewName;
if ('container' in item) {
const found = findFirstSubLink(item.container.items);
if (found) return found;
}
}
return null;
}
export type CanGet = (permissionPrefix: string) => boolean;
export type HasPermission = (permission: string) => boolean;
interface SpecialLinkInfo {
visible: boolean;
enterprise: boolean;
}
function checkSpecialLink(
viewName: string,
edition: string,
hasPerm?: HasPermission,
canGet?: CanGet,
): SpecialLinkInfo | null {
if (viewName.startsWith('Dashboard/') || viewName === 'CustomComponent/Dashboard') {
if (edition === 'oss') return { visible: false, enterprise: true };
const hasLiveMetrics = hasPerm ? hasPerm('liveMetrics') : true;
const hasTraceGet = canGet ? canGet('sysTrace') : true;
return { visible: hasLiveMetrics && hasTraceGet, enterprise: true };
}
if (viewName === 'CustomComponent/LiveDelivery') {
const allowed = hasPerm ? hasPerm('liveDeliveryTest') : true;
return { visible: allowed, enterprise: false };
}
if (viewName === 'CustomComponent/LiveTracing') {
if (edition === 'oss') return { visible: false, enterprise: true };
const allowed = hasPerm ? hasPerm('liveTracing') : true;
return { visible: allowed, enterprise: true };
}
if (viewName.startsWith('CustomComponent/')) {
return { visible: true, enterprise: false };
}
return null;
}
export function isLinkVisible(
schema: Schema,
viewName: string,
edition: string,
canGet: CanGet,
hasPerm?: HasPermission,
): boolean {
const special = checkSpecialLink(viewName, edition, hasPerm, canGet);
if (special !== null) return special.visible;
const obj = schema.objects[viewName];
if (!obj) return false;
const resolved = resolveObject(schema, viewName);
if (!resolved) return false;
if (!canGet(resolved.permissionPrefix)) return false;
if (resolved.enterprise && edition === 'oss') return false;
return true;
}
export function isLinkEnterprise(schema: Schema, viewName: string, edition: string): boolean {
const special = checkSpecialLink(viewName, edition);
if (special !== null) return special.enterprise;
const obj = schema.objects[viewName];
if (!obj) return false;
if (obj.type === 'view') {
const parent = schema.objects[obj.objectName];
return parent?.type !== 'view' && parent?.enterprise === true;
}
return obj.enterprise === true;
}
function findFirstVisibleSubLink(
schema: Schema,
items: LayoutSubItem[],
edition: string,
canGet: CanGet,
hasPerm?: HasPermission,
): string | null {
for (const item of items) {
if (item.type === 'link') {
if (isLinkVisible(schema, item.viewName, edition, canGet, hasPerm)) return item.viewName;
} else if (item.type === 'container') {
const found = findFirstVisibleSubLink(schema, item.items, edition, canGet, hasPerm);
if (found) return found;
}
}
return null;
}
export function findFirstVisibleLinkInLayout(
schema: Schema,
layout: Layout,
edition: string,
canGet: CanGet,
hasPerm?: HasPermission,
): string | null {
for (const item of layout.items) {
if ('link' in item) {
if (isLinkVisible(schema, item.link.viewName, edition, canGet, hasPerm)) return item.link.viewName;
} else if ('container' in item) {
const found = findFirstVisibleSubLink(schema, item.container.items, edition, canGet, hasPerm);
if (found) return found;
}
}
return null;
}
export function isLinkAccessible(
schema: Schema,
viewName: string,
edition: string,
canGet: CanGet,
hasPerm?: HasPermission,
): boolean {
if (!isLinkVisible(schema, viewName, edition, canGet, hasPerm)) return false;
if (edition === 'community' && isLinkEnterprise(schema, viewName, edition)) return false;
return true;
}
function findFirstAccessibleSubLink(
schema: Schema,
items: LayoutSubItem[],
edition: string,
canGet: CanGet,
hasPerm?: HasPermission,
): string | null {
for (const item of items) {
if (item.type === 'link') {
if (isLinkAccessible(schema, item.viewName, edition, canGet, hasPerm)) return item.viewName;
} else if (item.type === 'container') {
const found = findFirstAccessibleSubLink(schema, item.items, edition, canGet, hasPerm);
if (found) return found;
}
}
return null;
}
export function findFirstAccessibleLinkInLayout(
schema: Schema,
layout: Layout,
edition: string,
canGet: CanGet,
hasPerm?: HasPermission,
): string | null {
for (const item of layout.items) {
if ('link' in item) {
if (isLinkAccessible(schema, item.link.viewName, edition, canGet, hasPerm)) return item.link.viewName;
} else if ('container' in item) {
const found = findFirstAccessibleSubLink(schema, item.container.items, edition, canGet, hasPerm);
if (found) return found;
}
}
return null;
}
export function visibleLayouts(schema: Schema, edition: string, canGet: CanGet, hasPerm?: HasPermission): Layout[] {
return schema.layouts.filter(
(layout) => findFirstVisibleLinkInLayout(schema, layout, edition, canGet, hasPerm) !== null,
);
}