mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 01:50:39 +09:00
Add inbox issue search fallback
This commit is contained in:
parent
03a2cf5c8a
commit
fcab770518
3 changed files with 140 additions and 6 deletions
|
|
@ -20,6 +20,7 @@ import {
|
|||
getApprovalsForTab,
|
||||
getInboxWorkItems,
|
||||
getInboxKeyboardSelectionIndex,
|
||||
getInboxSearchFallbackIssues,
|
||||
getRecentTouchedIssues,
|
||||
getUnreadTouchedIssues,
|
||||
groupInboxWorkItems,
|
||||
|
|
@ -611,6 +612,65 @@ describe("inbox helpers", () => {
|
|||
).toEqual(["newer", "older"]);
|
||||
});
|
||||
|
||||
it("uses remote issue results only when local inbox search has no matches", () => {
|
||||
const remoteMatch = makeIssue("remote-match", false);
|
||||
remoteMatch.status = "in_progress";
|
||||
|
||||
expect(
|
||||
getInboxSearchFallbackIssues({
|
||||
query: "pull/3303",
|
||||
filteredWorkItems: [],
|
||||
archivedSearchIssues: [],
|
||||
remoteIssues: [remoteMatch],
|
||||
issueFilters: {
|
||||
statuses: ["in_progress"],
|
||||
priorities: [],
|
||||
assignees: [],
|
||||
labels: [],
|
||||
projects: [],
|
||||
workspaces: [],
|
||||
showRoutineExecutions: false,
|
||||
},
|
||||
}).map((issue) => issue.id),
|
||||
).toEqual(["remote-match"]);
|
||||
|
||||
expect(
|
||||
getInboxSearchFallbackIssues({
|
||||
query: "pull/3303",
|
||||
filteredWorkItems: [{ kind: "issue", timestamp: 1, issue: makeIssue("local", false) }],
|
||||
archivedSearchIssues: [],
|
||||
remoteIssues: [remoteMatch],
|
||||
issueFilters: {
|
||||
statuses: [],
|
||||
priorities: [],
|
||||
assignees: [],
|
||||
labels: [],
|
||||
projects: [],
|
||||
workspaces: [],
|
||||
showRoutineExecutions: false,
|
||||
},
|
||||
}),
|
||||
).toEqual([]);
|
||||
|
||||
expect(
|
||||
getInboxSearchFallbackIssues({
|
||||
query: "pull/3303",
|
||||
filteredWorkItems: [],
|
||||
archivedSearchIssues: [makeIssue("archived", false)],
|
||||
remoteIssues: [remoteMatch],
|
||||
issueFilters: {
|
||||
statuses: [],
|
||||
priorities: [],
|
||||
assignees: [],
|
||||
labels: [],
|
||||
projects: [],
|
||||
workspaces: [],
|
||||
showRoutineExecutions: false,
|
||||
},
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("defaults the remembered inbox tab to mine and persists all", () => {
|
||||
localStorage.clear();
|
||||
expect(loadLastInboxTab()).toBe("mine");
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import type {
|
|||
JoinRequest,
|
||||
} from "@paperclipai/shared";
|
||||
import {
|
||||
applyIssueFilters,
|
||||
defaultIssueFilterState,
|
||||
type IssueFilterState,
|
||||
} from "./issue-filters";
|
||||
|
|
@ -370,6 +371,30 @@ export function getArchivedInboxSearchIssues({
|
|||
.sort(sortIssuesByMostRecentActivity);
|
||||
}
|
||||
|
||||
export function getInboxSearchFallbackIssues({
|
||||
query,
|
||||
filteredWorkItems,
|
||||
archivedSearchIssues,
|
||||
remoteIssues,
|
||||
issueFilters,
|
||||
currentUserId,
|
||||
enableRoutineVisibilityFilter = false,
|
||||
}: {
|
||||
query: string;
|
||||
filteredWorkItems: InboxWorkItem[];
|
||||
archivedSearchIssues: Issue[];
|
||||
remoteIssues: Issue[];
|
||||
issueFilters: IssueFilterState;
|
||||
currentUserId?: string | null;
|
||||
enableRoutineVisibilityFilter?: boolean;
|
||||
}): Issue[] {
|
||||
const normalizedQuery = query.trim();
|
||||
if (!normalizedQuery) return [];
|
||||
if (filteredWorkItems.length > 0) return [];
|
||||
if (archivedSearchIssues.length > 0) return [];
|
||||
return applyIssueFilters(remoteIssues, issueFilters, currentUserId, enableRoutineVisibilityFilter);
|
||||
}
|
||||
|
||||
export function resolveIssueWorkspaceName(
|
||||
issue: Pick<Issue, "executionWorkspaceId" | "projectId" | "projectWorkspaceId">,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ import {
|
|||
getArchivedInboxSearchIssues,
|
||||
getInboxWorkItems,
|
||||
getInboxKeyboardSelectionIndex,
|
||||
getInboxSearchFallbackIssues,
|
||||
getLatestFailedRunsByAgent,
|
||||
matchesInboxIssueSearch,
|
||||
getRecentTouchedIssues,
|
||||
|
|
@ -642,6 +643,7 @@ export function Inbox() {
|
|||
retry: false,
|
||||
});
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const normalizedSearchQuery = searchQuery.trim();
|
||||
const [filterPreferences, setFilterPreferences] = useState<InboxFilterPreferences>(
|
||||
() => loadInboxFilterPreferences(selectedCompanyId),
|
||||
);
|
||||
|
|
@ -945,7 +947,7 @@ export function Inbox() {
|
|||
);
|
||||
|
||||
const filteredWorkItems = useMemo(() => {
|
||||
const q = searchQuery.trim().toLowerCase();
|
||||
const q = normalizedSearchQuery.toLowerCase();
|
||||
if (!q) return workItemsToRender;
|
||||
return workItemsToRender.filter((item) => {
|
||||
if (item.kind === "issue") {
|
||||
|
|
@ -987,12 +989,12 @@ export function Inbox() {
|
|||
});
|
||||
}, [
|
||||
workItemsToRender,
|
||||
searchQuery,
|
||||
agentById,
|
||||
defaultProjectWorkspaceIdByProjectId,
|
||||
executionWorkspaceById,
|
||||
issueById,
|
||||
isolatedWorkspacesEnabled,
|
||||
normalizedSearchQuery,
|
||||
projectWorkspaceById,
|
||||
]);
|
||||
|
||||
|
|
@ -1002,7 +1004,7 @@ export function Inbox() {
|
|||
? getArchivedInboxSearchIssues({
|
||||
visibleIssues: visibleMineIssues,
|
||||
searchableIssues: visibleTouchedIssues,
|
||||
query: searchQuery,
|
||||
query: normalizedSearchQuery,
|
||||
isolatedWorkspacesEnabled,
|
||||
executionWorkspaceById,
|
||||
projectWorkspaceById,
|
||||
|
|
@ -1013,13 +1015,60 @@ export function Inbox() {
|
|||
defaultProjectWorkspaceIdByProjectId,
|
||||
executionWorkspaceById,
|
||||
isolatedWorkspacesEnabled,
|
||||
normalizedSearchQuery,
|
||||
projectWorkspaceById,
|
||||
searchQuery,
|
||||
tab,
|
||||
visibleMineIssues,
|
||||
visibleTouchedIssues,
|
||||
],
|
||||
);
|
||||
const shouldUseIssueSearchFallback =
|
||||
!!selectedCompanyId
|
||||
&& normalizedSearchQuery.length > 0
|
||||
&& filteredWorkItems.length === 0
|
||||
&& archivedSearchIssues.length === 0;
|
||||
const { data: remoteIssueSearchResults = [] } = useQuery({
|
||||
queryKey: [
|
||||
...queryKeys.issues.search(selectedCompanyId!, normalizedSearchQuery, undefined, 25),
|
||||
"inbox-fallback",
|
||||
issueFilters,
|
||||
],
|
||||
queryFn: () =>
|
||||
issuesApi.list(selectedCompanyId!, {
|
||||
q: normalizedSearchQuery,
|
||||
limit: 25,
|
||||
includeRoutineExecutions: true,
|
||||
}),
|
||||
enabled: shouldUseIssueSearchFallback,
|
||||
placeholderData: (previousData) => previousData,
|
||||
});
|
||||
const issueSearchFallbackResults = useMemo(
|
||||
() =>
|
||||
getInboxSearchFallbackIssues({
|
||||
query: normalizedSearchQuery,
|
||||
filteredWorkItems,
|
||||
archivedSearchIssues,
|
||||
remoteIssues: remoteIssueSearchResults,
|
||||
issueFilters,
|
||||
currentUserId,
|
||||
enableRoutineVisibilityFilter: true,
|
||||
}),
|
||||
[
|
||||
archivedSearchIssues,
|
||||
currentUserId,
|
||||
filteredWorkItems,
|
||||
issueFilters,
|
||||
normalizedSearchQuery,
|
||||
remoteIssueSearchResults,
|
||||
],
|
||||
);
|
||||
const effectiveWorkItems = useMemo(
|
||||
() =>
|
||||
issueSearchFallbackResults.length > 0
|
||||
? getInboxWorkItems({ issues: issueSearchFallbackResults, approvals: [] })
|
||||
: filteredWorkItems,
|
||||
[filteredWorkItems, issueSearchFallbackResults],
|
||||
);
|
||||
const archivedSearchIssueIds = useMemo(
|
||||
() => new Set(archivedSearchIssues.map((issue) => issue.id)),
|
||||
[archivedSearchIssues],
|
||||
|
|
@ -1037,14 +1086,14 @@ export function Inbox() {
|
|||
}, []);
|
||||
const [collapsedInboxParents, setCollapsedInboxParents] = useState<Set<string>>(new Set());
|
||||
const groupedSections = useMemo<InboxGroupedSection[]>(() => [
|
||||
...buildGroupedInboxSections(filteredWorkItems, groupBy, nestingEnabled),
|
||||
...buildGroupedInboxSections(effectiveWorkItems, groupBy, nestingEnabled),
|
||||
...buildGroupedInboxSections(
|
||||
getInboxWorkItems({ issues: archivedSearchIssues, approvals: [] }),
|
||||
groupBy,
|
||||
nestingEnabled,
|
||||
{ keyPrefix: "archived-search:", isArchivedSearch: true },
|
||||
),
|
||||
], [archivedSearchIssues, filteredWorkItems, groupBy, nestingEnabled]);
|
||||
], [archivedSearchIssues, effectiveWorkItems, groupBy, nestingEnabled]);
|
||||
const totalVisibleWorkItems = useMemo(
|
||||
() => groupedSections.reduce((count, group) => count + group.displayItems.length, 0),
|
||||
[groupedSections],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue