fix(gateway): decouple admin navigation loading

This commit is contained in:
2026-08-09 11:51:00 +00:00
parent fd0f874d55
commit 7361828641
9 changed files with 141 additions and 23 deletions
+12
View File
@@ -1474,6 +1474,18 @@ export const adminRouter = router({
}),
}),
profiles: router({
listNavigation: adminProcedure.query(async ({ ctx }) => {
const adminAuth = requireAdminAuth(ctx);
return orderGatewayProfiles(await ctx.profiles.listProfiles())
.filter((profile) => canReadProfile(adminAuth, profile.profileName))
.map((profile) => ({
profileName: profile.profileName,
profile: profile.profile,
meta: {
...(typeof profile.meta.korName === 'string' ? { korName: profile.meta.korName } : {}),
},
}));
}),
list: adminProcedure.query(async ({ ctx }) => {
const adminAuth = requireAdminAuth(ctx);
const profiles = orderGatewayProfiles(await ctx.profiles.listProfiles()).filter((profile) =>
+26 -1
View File
@@ -65,6 +65,7 @@ const buildCaller = async (
const updatedMetas: Record<string, unknown>[] = [];
const auditEvents: AdminAuditEventRecord[] = [];
let reconcileCount = 0;
let runtimeStateListCount = 0;
let storedNotice = options.initialNotice ?? '';
const profile = {
profileName: 'che:2',
@@ -244,7 +245,10 @@ const buildCaller = async (
}
},
cleanupStaleWorkspaces: async () => ({ removed: [], skipped: [] }),
listRuntimeStates: async () => [],
listRuntimeStates: async () => {
runtimeStateListCount += 1;
return [];
},
},
profileStatus: new InMemoryProfileStatusService(),
requestHeaders: { 'x-session-token': session.sessionToken },
@@ -293,6 +297,7 @@ const buildCaller = async (
updatedMetas,
auditEvents,
getReconcileCount: () => reconcileCount,
getRuntimeStateListCount: () => runtimeStateListCount,
getStoredNotice: () => storedNotice,
getReleaseLogPollCount: () => releaseLogPollCount,
setStoredNotice: (notice: string) => {
@@ -301,6 +306,26 @@ const buildCaller = async (
};
};
describe('admin profile navigation API', () => {
it('returns the scoped menu inventory without loading PM2 runtime state', async () => {
const harness = await buildCaller(
async () => {
throw new Error('not used');
},
{ adminRoles: ['admin.profiles.manage:che:2'], firstUserIsAdmin: false }
);
await expect(harness.caller.admin.profiles.listNavigation()).resolves.toEqual([
{
profileName: 'che:2',
profile: 'che',
meta: {},
},
]);
expect(harness.getRuntimeStateListCount()).toBe(0);
});
});
describe('gateway notice API', () => {
const dirtyNotice =
'<b>점검</b><br><script>globalThis.__noticeXss=1</script>' +