Show the first-boot wizard again #75
No files matched your search
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Coffey Labs
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { isLinkVisible, visibleLayouts } from './layout';
|
||||
import { withRegroupedSettings, SETTINGS_OVERVIEW_VIEW } from './settingsLayout';
|
||||
import type { Schema } from '@/types/schema';
|
||||
|
||||
// The shape a server in bootstrap mode serves: every layout present, and an
|
||||
// administrator who may only read and write x:Bootstrap.
|
||||
const served = {
|
||||
objects: {
|
||||
'x:Bootstrap': { type: 'singleton', description: '', permissionPrefix: 'sysBootstrap' },
|
||||
'x:Domain': { type: 'object', description: '', permissionPrefix: 'sysDomain' },
|
||||
'x:MtaStageEhlo': { type: 'singleton', description: '', permissionPrefix: 'sysMtaStageEhlo' },
|
||||
},
|
||||
schemas: {},
|
||||
fields: {},
|
||||
forms: {},
|
||||
lists: {},
|
||||
enums: {},
|
||||
dashboards: [],
|
||||
layouts: [
|
||||
{
|
||||
name: 'Management',
|
||||
icon: 'server',
|
||||
items: [
|
||||
{ link: { name: 'Domains', icon: 'globe', viewName: 'x:Domain' } },
|
||||
{ link: { name: 'Compliance', icon: 'scale', viewName: 'CustomComponent/ComplianceOverview' } },
|
||||
{ link: { name: 'Coming soon', icon: 'sparkles', viewName: 'CustomComponent/NotInThisConsole' } },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
icon: 'sliders-horizontal',
|
||||
items: [
|
||||
{
|
||||
container: {
|
||||
name: 'MTA',
|
||||
icon: 'route',
|
||||
items: [{ type: 'link', name: 'EHLO Stage', viewName: 'x:MtaStageEhlo' }],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
} as unknown as Schema;
|
||||
|
||||
const schema = withRegroupedSettings(served);
|
||||
const canGetFrom = (perms: string[]) => (prefix: string) => perms.includes(`${prefix}Get`);
|
||||
const hasPermFrom = (perms: string[]) => (perm: string) => perms.includes(perm);
|
||||
|
||||
describe('layout visibility', () => {
|
||||
it('leaves the bootstrap administrator no layout, so the wizard shows (inbuxa-server#135)', () => {
|
||||
const perms = ['sysBootstrapGet', 'sysBootstrapUpdate'];
|
||||
expect(visibleLayouts(schema, 'enterprise', canGetFrom(perms), hasPermFrom(perms))).toEqual([]);
|
||||
});
|
||||
|
||||
it('shows the Settings overview only beside a settings page the account may see', () => {
|
||||
const none = canGetFrom([]);
|
||||
const ehlo = canGetFrom(['sysMtaStageEhloGet']);
|
||||
expect(isLinkVisible(schema, SETTINGS_OVERVIEW_VIEW, 'enterprise', none)).toBe(false);
|
||||
expect(isLinkVisible(schema, SETTINGS_OVERVIEW_VIEW, 'enterprise', ehlo)).toBe(true);
|
||||
expect(visibleLayouts(schema, 'enterprise', ehlo).map((l) => l.name)).toEqual(['Settings']);
|
||||
});
|
||||
|
||||
it('hides a page this console cannot draw', () => {
|
||||
const all = () => true;
|
||||
expect(isLinkVisible(schema, 'CustomComponent/NotInThisConsole', 'enterprise', all)).toBe(false);
|
||||
});
|
||||
});
|
||||
+19
-1
@@ -9,6 +9,7 @@
|
||||
|
||||
import type { Layout, LayoutItem, LayoutSubItem, Schema } from '@/types/schema';
|
||||
import { resolveObject } from '@/lib/schemaResolver';
|
||||
import { SETTINGS_LAYOUT_NAME, SETTINGS_OVERVIEW_VIEW } from '@/lib/settingsLayout';
|
||||
|
||||
function findFirstSubLink(items: LayoutSubItem[]): string | null {
|
||||
for (const item of items) {
|
||||
@@ -111,8 +112,11 @@ function checkSpecialLink(
|
||||
return { visible: canGet ? canGet('sysAccountLock') : true, enterprise: false };
|
||||
}
|
||||
|
||||
// INBUXA: a page this console can't draw is hidden. A server newer than the
|
||||
// console lists pages the console doesn't know yet, and counting them as
|
||||
// visible hid the first-boot wizard (inbuxa-server#135).
|
||||
if (viewName.startsWith('CustomComponent/')) {
|
||||
return { visible: true, enterprise: false };
|
||||
return { visible: false, enterprise: false };
|
||||
}
|
||||
|
||||
// INBUXA: guided jobs are open to whoever may manage what they change.
|
||||
@@ -148,6 +152,20 @@ export function isLinkVisible(
|
||||
canGet: CanGet,
|
||||
hasPerm?: HasPermission,
|
||||
): boolean {
|
||||
// INBUXA: the Settings overview is the console's own page, there when any
|
||||
// settings page is. Visible on its own, it made the Settings layout visible
|
||||
// to the bootstrap administrator, and the wizard never showed.
|
||||
if (viewName === SETTINGS_OVERVIEW_VIEW) {
|
||||
const settings = schema.layouts.find((layout) => layout.name === SETTINGS_LAYOUT_NAME);
|
||||
return (
|
||||
settings?.items.some(
|
||||
(item) =>
|
||||
'container' in item &&
|
||||
findFirstVisibleSubLink(schema, item.container.items, edition, canGet, hasPerm) !== null,
|
||||
) ?? false
|
||||
);
|
||||
}
|
||||
|
||||
const special = checkSpecialLink(viewName, edition, hasPerm, canGet);
|
||||
if (special !== null) return special.visible;
|
||||
|
||||
|
||||
Reference in new issue
Block a user