mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 04:07:05 +00:00
🔗 feat: Admin Panel Link in Settings for Admins (#14662)
Expose ADMIN_PANEL_URL through the startup config for users holding the access:admin capability, and render an Admin section in Settings > General with an external link to the admin panel. The URL is omitted server-side for unauthenticated requests and users without admin access.
This commit is contained in:
parent
1367672942
commit
c6bb77325a
11 changed files with 93 additions and 3 deletions
|
|
@ -103,6 +103,7 @@ afterEach(() => {
|
|||
delete process.env.SAML_CERT;
|
||||
delete process.env.SAML_SESSION_SECRET;
|
||||
delete process.env.ALLOW_ACCOUNT_DELETION;
|
||||
delete process.env.ADMIN_PANEL_URL;
|
||||
delete process.env.ANALYTICS_GTM_ID;
|
||||
delete process.env.CUSTOM_FOOTER;
|
||||
delete process.env.HELP_AND_FAQ_URL;
|
||||
|
|
@ -179,6 +180,7 @@ describe('GET /api/config', () => {
|
|||
process.env.ANALYTICS_GTM_ID = 'GTM-XYZ';
|
||||
process.env.CUSTOM_FOOTER = 'internal footer text';
|
||||
process.env.HELP_AND_FAQ_URL = 'https://internal.example.com/faq';
|
||||
process.env.ADMIN_PANEL_URL = 'https://admin.example.com';
|
||||
mockGetAppConfig.mockResolvedValue(baseAppConfig);
|
||||
const app = createApp(null);
|
||||
|
||||
|
|
@ -193,6 +195,7 @@ describe('GET /api/config', () => {
|
|||
expect(response.body).not.toHaveProperty('openidReuseTokens');
|
||||
expect(response.body).not.toHaveProperty('allowAccountDeletion');
|
||||
expect(response.body).not.toHaveProperty('customFooter');
|
||||
expect(response.body).not.toHaveProperty('adminPanelURL');
|
||||
});
|
||||
|
||||
it('should not include share-only fields when share context is requested', async () => {
|
||||
|
|
@ -627,6 +630,40 @@ describe('GET /api/config', () => {
|
|||
expect(mockHasCapability).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should include adminPanelURL for users with ACCESS_ADMIN capability', async () => {
|
||||
process.env.ADMIN_PANEL_URL = 'https://admin.example.com';
|
||||
mockGetAppConfig.mockResolvedValue(baseAppConfig);
|
||||
mockHasCapability.mockResolvedValue(true);
|
||||
const app = createApp(mockUser);
|
||||
|
||||
const response = await request(app).get('/api/config');
|
||||
|
||||
expect(response.body.adminPanelURL).toBe('https://admin.example.com');
|
||||
expect(mockHasCapability).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should omit adminPanelURL for authenticated users without ACCESS_ADMIN', async () => {
|
||||
process.env.ADMIN_PANEL_URL = 'https://admin.example.com';
|
||||
mockGetAppConfig.mockResolvedValue(baseAppConfig);
|
||||
mockHasCapability.mockResolvedValue(false);
|
||||
const app = createApp(mockUser);
|
||||
|
||||
const response = await request(app).get('/api/config');
|
||||
|
||||
expect(response.body).not.toHaveProperty('adminPanelURL');
|
||||
expect(mockHasCapability).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should omit adminPanelURL when ADMIN_PANEL_URL is not set', async () => {
|
||||
mockGetAppConfig.mockResolvedValue(baseAppConfig);
|
||||
mockHasCapability.mockResolvedValue(true);
|
||||
const app = createApp(mockUser);
|
||||
|
||||
const response = await request(app).get('/api/config');
|
||||
|
||||
expect(response.body).not.toHaveProperty('adminPanelURL');
|
||||
});
|
||||
|
||||
it('should return 500 when getAppConfig throws', async () => {
|
||||
mockGetAppConfig.mockRejectedValue(new Error('Config service failure'));
|
||||
const app = createApp(mockUser);
|
||||
|
|
|
|||
|
|
@ -319,15 +319,19 @@ router.get('/', async function (req, res) {
|
|||
payload.buildInfo = buildInfo;
|
||||
}
|
||||
|
||||
if (!payload.allowAccountDeletion) {
|
||||
const adminPanelURL = process.env.ADMIN_PANEL_URL;
|
||||
if (adminPanelURL || !payload.allowAccountDeletion) {
|
||||
try {
|
||||
const userId = req.user.id ?? req.user._id?.toString();
|
||||
if (userId) {
|
||||
const canDelete = await hasCapability(
|
||||
const hasAdminAccess = await hasCapability(
|
||||
{ id: userId, role: req.user.role ?? '', tenantId: req.user.tenantId },
|
||||
SystemCapabilities.ACCESS_ADMIN,
|
||||
);
|
||||
if (canDelete) {
|
||||
if (hasAdminAccess && adminPanelURL) {
|
||||
payload.adminPanelURL = adminPanelURL;
|
||||
}
|
||||
if (hasAdminAccess && !payload.allowAccountDeletion) {
|
||||
payload.allowAccountDeletion = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue