Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f286001
feat(client): Rebuild the chat list filter as a properties menu
berry-13 Sep 23, 2026
81ae98b
feat(client): Show a project's chats under that project only
berry-13 Sep 23, 2026
339adb9
fix(client): Keep facet-filtered caches honest and the facets session…
berry-13 Sep 24, 2026
5943cd0
test(client): Mock the projects query the chats section now reads
berry-13 Sep 24, 2026
c2c7b12
test(e2e): Acceptance scenarios for the chat list properties menu
berry-13 Sep 26, 2026
d8015d5
fix(client): Call the account empty only once its projects have loaded
berry-13 Sep 26, 2026
c6f1d99
test(e2e): Scenario for the Filter submenu under a role without bookm…
berry-13 Sep 26, 2026
a26b261
fix(client): Drop a cached chat from an endpoint filter it no longer …
berry-13 Sep 26, 2026
1e87893
fix(client): List every chat when the projects fail to load
berry-13 Sep 26, 2026
14ae6a3
test(e2e): Scenario for project chats when the projects fail to load
berry-13 Sep 26, 2026
fe32448
fix(client): Count the bookmark filter once in the menu trigger
berry-13 Sep 26, 2026
8be99c8
fix(client): Stop the endpoint filter at the configured limit
berry-13 Sep 27, 2026
5e7dfc1
test(e2e): Scenario for the endpoint filter limit
berry-13 Sep 27, 2026
9b82761
fix(client): Hold the endpoint filter until its limit is known
berry-13 Sep 27, 2026
f35c752
fix(client): Keep a chosen bookmark removable and a failed config unl…
berry-13 Sep 27, 2026
99e1c6a
test(e2e): Scenario for a chosen bookmark whose count drops to zero
berry-13 Sep 27, 2026
6f85d9d
fix(client): Keep a chosen endpoint removable when the deployment sto…
berry-13 Sep 27, 2026
4d48f28
docs(client): Punctuate the list membership comments without dashes
berry-13 Sep 27, 2026
ba0fe4d
fix: Publish the chat list filter limits the list route enforces
berry-13 Sep 27, 2026
7a6cb82
fix(client): Keep a deleted bookmark removable from the filter
berry-13 Sep 27, 2026
c4bb4c2
fix(client): Offer a retry when a project's chats fail to load
berry-13 Sep 27, 2026
61a0a73
test(e2e): Scenario for a project whose chats fail to load
berry-13 Sep 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions api/server/routes/__tests__/config.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1096,3 +1096,52 @@ describe('passkey enrollment cap', () => {
expect(anonymous.body).not.toHaveProperty('maxPasskeysPerUser');
});
});

describe('chat list endpoint filter limit', () => {
it('publishes the base config limits only after authentication', async () => {
const { AppService } = require('@librechat/data-schemas');
const baseConfig = await AppService({
config: { conversationList: { maxEndpointFilters: 3, maxEndpointNameLength: 40 } },
});
mockGetAppConfig.mockResolvedValue(baseConfig);

const authenticated = await request(createApp(mockUser)).get('/api/config');
expect(authenticated.status).toBe(200);
expect(authenticated.body.conversationListLimits).toEqual({
maxEndpointFilters: 3,
maxEndpointNameLength: 40,
});
expect(mockGetAppConfig).toHaveBeenCalledWith({ baseOnly: true });

const anonymous = await request(createApp()).get('/api/config');
expect(anonymous.status).toBe(200);
expect(anonymous.body).not.toHaveProperty('conversationListLimits');
});

it('publishes the limits the list route enforces, not a principal override', async () => {
const { AppService } = require('@librechat/data-schemas');
const baseConfig = await AppService({
config: { conversationList: { maxEndpointFilters: 2 } },
});
const mergedConfig = await AppService({
config: { conversationList: { maxEndpointFilters: 9 } },
});
mockGetAppConfig.mockImplementation(async (options) =>
options?.baseOnly === true ? baseConfig : mergedConfig,
);

const response = await request(createApp(mockUser)).get('/api/config');
expect(response.body.conversationListLimits.maxEndpointFilters).toBe(2);
});

it('publishes the schema defaults for a deployment that sets none', async () => {
const { AppService } = require('@librechat/data-schemas');
mockGetAppConfig.mockResolvedValue(await AppService({ config: {} }));

const response = await request(createApp(mockUser)).get('/api/config');
expect(response.body.conversationListLimits).toEqual({
maxEndpointFilters: 50,
maxEndpointNameLength: 128,
});
});
});
13 changes: 9 additions & 4 deletions api/server/routes/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
isPasskeyEnabled,
buildPreLoginInterface,
resolveMaxPasskeysPerUser,
loadConversationListLimits,
} = require('@librechat/api');
const {
DEFAULT_MCP_APP_CSP_LIMITS,
Expand Down Expand Up @@ -250,10 +251,13 @@ router.get('/', async function (req, res) {
return res.status(200).send(payload);
}

const appConfig = await getAppConfig({
...getAppConfigOptionsFromUser(req.user),
failClosed: true,
});
const [appConfig, conversationListLimits] = await Promise.all([
getAppConfig({
...getAppConfigOptionsFromUser(req.user),
failClosed: true,
}),
loadConversationListLimits(getAppConfig),
]);
const codeEnvironmentDecisionVersion = resolveCodeEnvironmentDecisionVersion(
process.env.CODE_ENVIRONMENT_DECISION_VERSION,
);
Expand Down Expand Up @@ -295,6 +299,7 @@ router.get('/', async function (req, res) {
...preLoginPayload,
...publicSharePayload,
...buildPostLoginPayload(appConfig),
conversationListLimits,
sharedLinksSnapshotFilesEnabled: sharedLinksEnabled && isFileSnapshotEnabled(appConfig),
socialLogins: appConfig?.registration?.socialLogins ?? defaultSocialLogins,
interface: appConfig?.interfaceConfig,
Expand Down
Loading
Loading