diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 5733d1566a..a8bc67c8a5 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -78,7 +78,7 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "Search query. Supports title:\u003csubstring\u003e (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status:\u003cdraft\\|open\\|merged\\|closed\u003e as repeated or comma-separated values, source:\u003ccreated_by_me\\|shared_with_me\\|all\u003e, diff_url:\u003curl\u003e (quote values containing colons), pr:\u003cnumber\u003e (exact PR number match), repo:\u003cowner/repo\u003e (case-insensitive substring match against git remote origin or URL), pr_title:\u003ctext\u003e (case-insensitive PR title substring). Bare terms are not supported; use title:\u003cvalue\u003e for title filtering.", + "description": "Search query. Supports title:\u003csubstring\u003e (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status:\u003cdraft\\|open\\|merged\\|closed\u003e as repeated or comma-separated values, source:\u003ccreated_by_me\\|shared_with_me\u003e, diff_url:\u003curl\u003e (quote values containing colons), pr:\u003cnumber\u003e (exact PR number match), repo:\u003cowner/repo\u003e (case-insensitive substring match against git remote origin or URL), pr_title:\u003ctext\u003e (case-insensitive PR title substring). Bare terms are not supported; use title:\u003cvalue\u003e for title filtering.", "name": "q", "in": "query" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index af2e95dc05..5725db5c9b 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -59,7 +59,7 @@ "parameters": [ { "type": "string", - "description": "Search query. Supports title:\u003csubstring\u003e (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status:\u003cdraft\\|open\\|merged\\|closed\u003e as repeated or comma-separated values, source:\u003ccreated_by_me\\|shared_with_me\\|all\u003e, diff_url:\u003curl\u003e (quote values containing colons), pr:\u003cnumber\u003e (exact PR number match), repo:\u003cowner/repo\u003e (case-insensitive substring match against git remote origin or URL), pr_title:\u003ctext\u003e (case-insensitive PR title substring). Bare terms are not supported; use title:\u003cvalue\u003e for title filtering.", + "description": "Search query. Supports title:\u003csubstring\u003e (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status:\u003cdraft\\|open\\|merged\\|closed\u003e as repeated or comma-separated values, source:\u003ccreated_by_me\\|shared_with_me\u003e, diff_url:\u003curl\u003e (quote values containing colons), pr:\u003cnumber\u003e (exact PR number match), repo:\u003cowner/repo\u003e (case-insensitive substring match against git remote origin or URL), pr_title:\u003ctext\u003e (case-insensitive PR title substring). Bare terms are not supported; use title:\u003cvalue\u003e for title filtering.", "name": "q", "in": "query" }, diff --git a/coderd/database/modelqueries.go b/coderd/database/modelqueries.go index c8f27d9702..98102aa34f 100644 --- a/coderd/database/modelqueries.go +++ b/coderd/database/modelqueries.go @@ -750,9 +750,6 @@ type chatQuerier interface { } func (q *sqlQuerier) GetAuthorizedChats(ctx context.Context, arg GetChatsParams, prepared rbac.PreparedAuthorized) ([]GetChatsRow, error) { - if arg.OwnedOnly && arg.SharedOnly { - return nil, xerrors.New("owned_only and shared_only cannot both be true") - } if (arg.OwnedOnly || arg.SharedOnly) && arg.ViewerID == uuid.Nil { return nil, xerrors.New("viewer_id required when owned_only or shared_only is true") } @@ -774,8 +771,8 @@ func (q *sqlQuerier) GetAuthorizedChats(ctx context.Context, arg GetChatsParams, query := fmt.Sprintf("-- name: GetAuthorizedChats :many\n%s", filtered) rows, err := q.db.QueryContext(ctx, query, arg.OwnedOnly, - arg.ViewerID, arg.SharedOnly, + arg.ViewerID, arg.SharedWithUserID, pq.Array(arg.SharedWithGroupIds), arg.Archived, diff --git a/coderd/database/querier_test.go b/coderd/database/querier_test.go index 32142917f9..b7c3490c98 100644 --- a/coderd/database/querier_test.go +++ b/coderd/database/querier_test.go @@ -1587,12 +1587,14 @@ func TestGetAuthorizedChatsACLSharing(t *testing.T) { require.Equal(t, sharedACL, sharedOnly[0].Chat.UserACL) require.Empty(t, sharedOnly[0].Chat.GroupACL) - _, err = db.GetAuthorizedChats(ctx, database.GetChatsParams{ - OwnedOnly: true, - SharedOnly: true, - ViewerID: recipient.ID, + ownedAndShared, err := db.GetAuthorizedChats(ctx, database.GetChatsParams{ + OwnedOnly: true, + SharedOnly: true, + ViewerID: recipient.ID, + SharedWithUserID: recipient.ID, }, preparedRecipient) - require.ErrorContains(t, err, "owned_only and shared_only") + require.NoError(t, err) + require.ElementsMatch(t, []uuid.UUID{ownerChat.ID, recipientChat.ID}, chatIDs(ownedAndShared)) authzdb := dbauthz.New(db, authorizer, slogtest.Make(t, &slogtest.Options{}), coderdtest.AccessControlStorePointer()) recipientCtx := dbauthz.As(ctx, recipientSubject) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index f5d4bc7cf8..96258d521c 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -8023,19 +8023,18 @@ SELECT FROM chats_expanded WHERE - CASE - WHEN $1::boolean THEN chats_expanded.owner_id = $2::uuid - ELSE true - END - AND CASE - WHEN $3::boolean THEN - chats_expanded.owner_id != $2::uuid + ( + (NOT $1::boolean AND NOT $2::boolean) + OR ($1::boolean AND chats_expanded.owner_id = $3::uuid) + OR ( + $2::boolean + AND chats_expanded.owner_id != $3::uuid AND ( chats_expanded.user_acl ? ($4::uuid)::text OR chats_expanded.group_acl ?| $5::text[] ) - ELSE true - END + ) + ) AND CASE WHEN $6 :: boolean IS NULL THEN true ELSE chats_expanded.archived = $6 :: boolean @@ -8174,8 +8173,8 @@ LIMIT type GetChatsParams struct { OwnedOnly bool `db:"owned_only" json:"owned_only"` - ViewerID uuid.UUID `db:"viewer_id" json:"viewer_id"` SharedOnly bool `db:"shared_only" json:"shared_only"` + ViewerID uuid.UUID `db:"viewer_id" json:"viewer_id"` SharedWithUserID uuid.UUID `db:"shared_with_user_id" json:"shared_with_user_id"` SharedWithGroupIds []string `db:"shared_with_group_ids" json:"shared_with_group_ids"` Archived sql.NullBool `db:"archived" json:"archived"` @@ -8200,8 +8199,8 @@ type GetChatsRow struct { func (q *sqlQuerier) GetChats(ctx context.Context, arg GetChatsParams) ([]GetChatsRow, error) { rows, err := q.db.QueryContext(ctx, getChats, arg.OwnedOnly, - arg.ViewerID, arg.SharedOnly, + arg.ViewerID, arg.SharedWithUserID, pq.Array(arg.SharedWithGroupIds), arg.Archived, diff --git a/coderd/database/queries/chats.sql b/coderd/database/queries/chats.sql index 106e2cc3e6..0d3810acb0 100644 --- a/coderd/database/queries/chats.sql +++ b/coderd/database/queries/chats.sql @@ -481,19 +481,18 @@ SELECT FROM chats_expanded WHERE - CASE - WHEN @owned_only::boolean THEN chats_expanded.owner_id = @viewer_id::uuid - ELSE true - END - AND CASE - WHEN @shared_only::boolean THEN - chats_expanded.owner_id != @viewer_id::uuid + ( + (NOT @owned_only::boolean AND NOT @shared_only::boolean) + OR (@owned_only::boolean AND chats_expanded.owner_id = @viewer_id::uuid) + OR ( + @shared_only::boolean + AND chats_expanded.owner_id != @viewer_id::uuid AND ( chats_expanded.user_acl ? (@shared_with_user_id::uuid)::text OR chats_expanded.group_acl ?| @shared_with_group_ids::text[] ) - ELSE true - END + ) + ) AND CASE WHEN sqlc.narg('archived') :: boolean IS NULL THEN true ELSE chats_expanded.archived = sqlc.narg('archived') :: boolean diff --git a/coderd/exp_chats.go b/coderd/exp_chats.go index b6b32bd7a9..3375267575 100644 --- a/coderd/exp_chats.go +++ b/coderd/exp_chats.go @@ -339,7 +339,7 @@ func (api *API) chatsByWorkspace(rw http.ResponseWriter, r *http.Request) { // @Security CoderSessionToken // @Tags Chats // @Produce json -// @Param q query string false "Search query. Supports title: (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status: as repeated or comma-separated values, source:, diff_url: (quote values containing colons), pr: (exact PR number match), repo: (case-insensitive substring match against git remote origin or URL), pr_title: (case-insensitive PR title substring). Bare terms are not supported; use title: for title filtering." +// @Param q query string false "Search query. Supports title: (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status: as repeated or comma-separated values, source:, diff_url: (quote values containing colons), pr: (exact PR number match), repo: (case-insensitive substring match against git remote origin or URL), pr_title: (case-insensitive PR title substring). Bare terms are not supported; use title: for title filtering." // @Param label query string false "Filter by label as key:value. Repeat for multiple (AND logic)." // @Success 200 {array} codersdk.Chat // @Router /api/experimental/chats [get] diff --git a/coderd/exp_chats_acl_test.go b/coderd/exp_chats_acl_test.go index ed765afafa..48d59e14c8 100644 --- a/coderd/exp_chats_acl_test.go +++ b/coderd/exp_chats_acl_test.go @@ -432,9 +432,9 @@ func TestListChatsSharedScope(t *testing.T) { shared: map[uuid.UUID]bool{sharedChat.ID: true}, }, { - name: "all", + name: "created by me and shared with me", opts: &codersdk.ListChatsOptions{ - Source: codersdk.ChatListSourceAll, + Query: "source:created_by_me,shared_with_me", }, expected: map[uuid.UUID]struct{}{viewerChat.ID: {}, sharedChat.ID: {}}, shared: map[uuid.UUID]bool{viewerChat.ID: false, sharedChat.ID: true}, diff --git a/coderd/exp_chats_test.go b/coderd/exp_chats_test.go index c55d58c269..dea596aae8 100644 --- a/coderd/exp_chats_test.go +++ b/coderd/exp_chats_test.go @@ -1002,6 +1002,91 @@ func TestListChats(t *testing.T) { require.Equal(t, memberChats[0].ID, memberChats[0].DiffStatus.ChatID) }) + t.Run("SourceCreatedByMeAndSharedWithMeExcludesUnsharedReadableChats", func(t *testing.T) { + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitLong) + client, db := newChatClientWithDatabase(t) + firstUser := coderdtest.CreateFirstUser(t, client.Client) + modelConfig := createChatModelConfig(t, client) + ownerClientRaw, owner := coderdtest.CreateAnotherUser(t, client.Client, firstUser.OrganizationID, rbac.RoleOwner()) + ownerClient := codersdk.NewExperimentalClient(ownerClientRaw) + memberClientRaw, member := coderdtest.CreateAnotherUser(t, client.Client, firstUser.OrganizationID, rbac.ScopedRoleAgentsAccess(firstUser.OrganizationID)) + memberClient := codersdk.NewExperimentalClient(memberClientRaw) + + ownedChat := dbgen.Chat(t, db, database.Chat{ + OrganizationID: firstUser.OrganizationID, + OwnerID: owner.ID, + LastModelConfigID: modelConfig.ID, + Title: "owner created chat", + Status: database.ChatStatusCompleted, + }) + sharedChat := dbgen.Chat(t, db, database.Chat{ + OrganizationID: firstUser.OrganizationID, + OwnerID: member.ID, + LastModelConfigID: modelConfig.ID, + Title: "member shared chat", + Status: database.ChatStatusCompleted, + }) + unsharedReadableChat := dbgen.Chat(t, db, database.Chat{ + OrganizationID: firstUser.OrganizationID, + OwnerID: firstUser.UserID, + LastModelConfigID: modelConfig.ID, + Title: "unshared readable chat", + Status: database.ChatStatusCompleted, + }) + + err := db.UpdateChatACLByID(dbauthz.As(ctx, rbac.Subject{ + ID: member.ID.String(), + Roles: rbac.RoleIdentifiers{rbac.RoleOwner()}, + Scope: rbac.ScopeAll, + }), database.UpdateChatACLByIDParams{ + ID: sharedChat.ID, + UserACL: database.ChatACL{ + owner.ID.String(): database.ChatACLEntry{Permissions: []policy.Action{policy.ActionRead}}, + }, + GroupACL: database.ChatACL{}, + }) + require.NoError(t, err) + + ownerChats, err := ownerClient.ListChats(ctx, &codersdk.ListChatsOptions{ + Query: "source:created_by_me,shared_with_me", + }) + require.NoError(t, err) + + ownerChatIDs := make(map[uuid.UUID]struct{}, len(ownerChats)) + for _, chat := range ownerChats { + ownerChatIDs[chat.ID] = struct{}{} + } + require.Contains(t, ownerChatIDs, ownedChat.ID) + require.Contains(t, ownerChatIDs, sharedChat.ID) + require.NotContains(t, ownerChatIDs, unsharedReadableChat.ID) + + sharedOnlyChats, err := ownerClient.ListChats(ctx, &codersdk.ListChatsOptions{ + Source: codersdk.ChatListSourceSharedWithMe, + }) + require.NoError(t, err) + sharedOnlyChatIDs := make(map[uuid.UUID]struct{}, len(sharedOnlyChats)) + for _, chat := range sharedOnlyChats { + sharedOnlyChatIDs[chat.ID] = struct{}{} + } + require.Contains(t, sharedOnlyChatIDs, sharedChat.ID) + require.NotContains(t, sharedOnlyChatIDs, ownedChat.ID) + require.NotContains(t, sharedOnlyChatIDs, unsharedReadableChat.ID) + + memberChats, err := memberClient.ListChats(ctx, &codersdk.ListChatsOptions{ + Query: "source:created_by_me,shared_with_me", + }) + require.NoError(t, err) + memberChatIDs := make(map[uuid.UUID]struct{}, len(memberChats)) + for _, chat := range memberChats { + memberChatIDs[chat.ID] = struct{}{} + } + require.Contains(t, memberChatIDs, sharedChat.ID) + require.NotContains(t, memberChatIDs, ownedChat.ID) + require.NotContains(t, memberChatIDs, unsharedReadableChat.ID) + }) + t.Run("OrgMemberWithoutAgentsAccessCannotAccessOwnChats", func(t *testing.T) { t.Parallel() ctx := testutil.Context(t, testutil.WaitLong) diff --git a/coderd/searchquery/search.go b/coderd/searchquery/search.go index 4c6e33bd41..ac2ae5a34a 100644 --- a/coderd/searchquery/search.go +++ b/coderd/searchquery/search.go @@ -5,6 +5,7 @@ import ( "database/sql" "fmt" "net/url" + "slices" "strconv" "strings" "time" @@ -611,22 +612,29 @@ func Chats(query string) (database.GetChatsParams, []codersdk.ValidationError) { filter.TitleQuery = parser.String(values, "", "title") filter.PrTitleQuery = parser.String(values, "", "pr_title") filter.RepoQuery = parser.String(values, "", "repo") - if source := parser.String(values, "", "source"); source != "" { + sources := httpapi.ParseCustomList(parser, values, nil, "source", func(v string) (string, error) { + source := strings.ToLower(strings.TrimSpace(v)) switch source { - case "created_by_me": + case "created_by_me", "shared_with_me": + return source, nil + default: + return "", xerrors.Errorf("%q is not a valid value", v) + } + }) + if len(sources) > 0 { + hasCreatedByMe := slices.Contains(sources, "created_by_me") + hasSharedWithMe := slices.Contains(sources, "shared_with_me") + + switch { + case hasCreatedByMe && hasSharedWithMe: filter.OwnedOnly = true - filter.SharedOnly = false - case "shared_with_me": + filter.SharedOnly = true + case hasSharedWithMe: filter.OwnedOnly = false filter.SharedOnly = true - case "all": - filter.OwnedOnly = false - filter.SharedOnly = false default: - parser.Errors = append(parser.Errors, codersdk.ValidationError{ - Field: "source", - Detail: fmt.Sprintf("%q is not a valid value", source), - }) + filter.OwnedOnly = true + filter.SharedOnly = false } } diff --git a/coderd/searchquery/search_test.go b/coderd/searchquery/search_test.go index a04d1e9d03..dc7ca9a25e 100644 --- a/coderd/searchquery/search_test.go +++ b/coderd/searchquery/search_test.go @@ -1378,11 +1378,9 @@ func TestSearchChats(t *testing.T) { }, }, { - Name: "SourceAll", - Query: "source:all", - Expected: database.GetChatsParams{ - Archived: sql.NullBool{Bool: false, Valid: true}, - }, + Name: "SourceAllInvalid", + Query: "source:all", + ExpectedErrorContains: "source", }, { Name: "SourceInvalid", @@ -1390,9 +1388,22 @@ func TestSearchChats(t *testing.T) { ExpectedErrorContains: "source", }, { - Name: "SourceRepeated", - Query: "source:created_by_me source:shared_with_me", - ExpectedErrorContains: "source", + Name: "SourceCreatedByMeAndSharedWithMe", + Query: "source:created_by_me,shared_with_me", + Expected: database.GetChatsParams{ + Archived: sql.NullBool{Bool: false, Valid: true}, + OwnedOnly: true, + SharedOnly: true, + }, + }, + { + Name: "SourceRepeated", + Query: "source:created_by_me source:shared_with_me", + Expected: database.GetChatsParams{ + Archived: sql.NullBool{Bool: false, Valid: true}, + OwnedOnly: true, + SharedOnly: true, + }, }, { Name: "ExtraParam", diff --git a/codersdk/chats.go b/codersdk/chats.go index 6d5e559cc9..4fce8a32c2 100644 --- a/codersdk/chats.go +++ b/codersdk/chats.go @@ -2047,8 +2047,6 @@ const ( ChatListSourceCreatedByMe ChatListSource = "created_by_me" // ChatListSourceSharedWithMe returns chats shared with the caller. ChatListSourceSharedWithMe ChatListSource = "shared_with_me" - // ChatListSourceAll returns both owned and shared chats. - ChatListSourceAll ChatListSource = "all" ) // ListChatsOptions are optional parameters for ListChats. diff --git a/docs/reference/api/chats.md b/docs/reference/api/chats.md index e9a75bef3a..d66d4b3669 100644 --- a/docs/reference/api/chats.md +++ b/docs/reference/api/chats.md @@ -17,10 +17,10 @@ Experimental: this endpoint is subject to change. ### Parameters -| Name | In | Type | Required | Description | -|---------|-------|--------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `q` | query | string | false | Search query. Supports title: (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status: as repeated or comma-separated values, source:, diff_url: (quote values containing colons), pr: (exact PR number match), repo: (case-insensitive substring match against git remote origin or URL), pr_title: (case-insensitive PR title substring). Bare terms are not supported; use title: for title filtering. | -| `label` | query | string | false | Filter by label as key:value. Repeat for multiple (AND logic). | +| Name | In | Type | Required | Description | +|---------|-------|--------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `q` | query | string | false | Search query. Supports title: (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status: as repeated or comma-separated values, source:, diff_url: (quote values containing colons), pr: (exact PR number match), repo: (case-insensitive substring match against git remote origin or URL), pr_title: (case-insensitive PR title substring). Bare terms are not supported; use title: for title filtering. | +| `label` | query | string | false | Filter by label as key:value. Repeat for multiple (AND logic). | ### Example responses diff --git a/site/src/api/queries/chats.test.ts b/site/src/api/queries/chats.test.ts index 92e00f2201..81890268de 100644 --- a/site/src/api/queries/chats.test.ts +++ b/site/src/api/queries/chats.test.ts @@ -1543,13 +1543,13 @@ describe("infiniteChats", () => { }); }); - it("builds q from archived, prStatuses, chatStatus, and source", async () => { + it("builds q from archived, prStatuses, chatStatus, and sources", async () => { vi.mocked(API.experimental.getChats).mockResolvedValue([]); const { queryFn } = infiniteChats({ archived: true, prStatuses: ["draft", "open", "merged"], chatStatus: "unread", - source: "all", + sources: ["created_by_me", "shared_with_me"], }); await queryFn({ pageParam: 0 }); @@ -1557,7 +1557,7 @@ describe("infiniteChats", () => { expect(API.experimental.getChats).toHaveBeenCalledWith({ limit: PAGE_LIMIT, offset: 0, - q: "archived:true pr_status:draft,open,merged has_unread:true source:all", + q: "archived:true pr_status:draft,open,merged has_unread:true source:created_by_me,shared_with_me", }); }); diff --git a/site/src/api/queries/chats.ts b/site/src/api/queries/chats.ts index 0fef28d451..1238bb4373 100644 --- a/site/src/api/queries/chats.ts +++ b/site/src/api/queries/chats.ts @@ -34,7 +34,7 @@ type InfiniteChatsFilters = Readonly<{ archived?: boolean; prStatuses?: readonly ChatListPRStatusFilter[]; chatStatus?: ChatListStatusFilter; - source?: TypesGen.ChatListSource; + sources?: readonly TypesGen.ChatListSource[]; }>; export const infiniteChatsKey = (filters?: InfiniteChatsFilters) => @@ -559,8 +559,8 @@ const getInfiniteChatsQueryString = ( if (filters?.chatStatus) { qParts.push(`has_unread:${filters.chatStatus === "unread"}`); } - if (filters?.source) { - qParts.push(`source:${filters.source}`); + if (filters?.sources?.length) { + qParts.push(`source:${filters.sources.join(",")}`); } return qParts.length > 0 ? qParts.join(" ") : undefined; }; diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 4af14815d6..50e67e7342 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -2151,10 +2151,9 @@ export const ChatInputPartTypes: ChatInputPartType[] = [ ]; // From codersdk/chats.go -export type ChatListSource = "all" | "created_by_me" | "shared_with_me"; +export type ChatListSource = "created_by_me" | "shared_with_me"; export const ChatListSources: ChatListSource[] = [ - "all", "created_by_me", "shared_with_me", ]; diff --git a/site/src/pages/AgentsPage/AgentsPage.tsx b/site/src/pages/AgentsPage/AgentsPage.tsx index b68011bf8a..a04f7fa0ff 100644 --- a/site/src/pages/AgentsPage/AgentsPage.tsx +++ b/site/src/pages/AgentsPage/AgentsPage.tsx @@ -56,10 +56,7 @@ import { AgentsPageView } from "./AgentsPageView"; import { emptyInputStorageKey } from "./components/AgentCreateForm"; import { useAgentsPageKeybindings } from "./hooks/useAgentsPageKeybindings"; import { useAgentsPWA } from "./hooks/useAgentsPWA"; -import { - AGENT_SOURCE_ORDER, - getAgentSidebarFilters, -} from "./utils/agentSidebarFilters"; +import { getAgentSidebarFilters } from "./utils/agentSidebarFilters"; import { archiveChatAndDeleteWorkspace, resolveArchiveAndDeleteAction, @@ -152,16 +149,12 @@ const AgentsPage: FC = () => { sidebarFilters.chatStatuses.length === 1 ? sidebarFilters.chatStatuses[0] : undefined; - const sourceFilter = - sidebarFilters.sources.length === AGENT_SOURCE_ORDER.length - ? "all" - : sidebarFilters.sources[0]; const chatsQuery = useInfiniteQuery( infiniteChats({ archived: archivedFilter, prStatuses: sidebarFilters.prStatuses, chatStatus: chatStatusFilter, - source: sourceFilter, + sources: sidebarFilters.sources, }), ); // Model queries are kept here for the sidebar, which displays