196 lines
5.8 KiB
TypeScript
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,
|
|
);
|
|
}
|