Refine settings and panel preferences

This commit is contained in:
2026-04-02 00:58:43 +03:00
parent 69c97ea387
commit 760ab62c10
10 changed files with 853 additions and 286 deletions

View File

@@ -153,6 +153,24 @@ describe('panel api', () => {
expect(response.body.system.previewConfig).toContain('socks -p1180 -u2');
expect(response.body.service.lastEvent).toBe('System configuration updated from panel');
});
it('removes linked users when a service is deleted from settings', async () => {
const app = await createTestApp();
const token = await authorize(app);
const initial = await request(app).get('/api/state').set('Authorization', `Bearer ${token}`);
const system = createSystemPayload(initial.body);
system.services = system.services.filter((service) => service.id !== 'socks-main');
const response = await request(app).put('/api/system').set('Authorization', `Bearer ${token}`).send(system);
expect(response.status).toBe(200);
expect(response.body.userRecords.some((user: { username: string }) => user.username === 'night-shift')).toBe(
false,
);
expect(response.body.userRecords.some((user: { username: string }) => user.username === 'ops-east')).toBe(false);
expect(response.body.service.lastEvent).toMatch(/removed 2 linked users/i);
});
});
async function createTestApp() {

View File

@@ -129,8 +129,23 @@ export function createApp({ store, runtime, runtimeRootDir, auth }: AppServices)
app.put('/api/system', async (request, response, next) => {
try {
const state = await store.read();
state.system = validateSystemInput(request.body as Partial<UpdateSystemInput>, state.userRecords);
state.service.lastEvent = 'System configuration updated from panel';
const requestedSystem = request.body as Partial<UpdateSystemInput>;
const nextServiceIds = new Set(
(Array.isArray(requestedSystem.services) ? requestedSystem.services : []).map((service) => service.id),
);
const removedServiceIds = new Set(
state.system.services
.map((service) => service.id)
.filter((serviceId) => !nextServiceIds.has(serviceId)),
);
const removedUsers = state.userRecords.filter((user) => removedServiceIds.has(user.serviceId));
state.userRecords = state.userRecords.filter((user) => !removedServiceIds.has(user.serviceId));
state.system = validateSystemInput(requestedSystem, state.userRecords);
state.service.lastEvent =
removedUsers.length > 0
? `System configuration updated from panel and removed ${removedUsers.length} linked users`
: 'System configuration updated from panel';
await persistRuntimeMutation(store, runtime, state, runtimePaths);
response.json(await getSnapshot(store, runtime, runtimePaths));
} catch (error) {