mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 13:24:55 +01:00
Add live run issue filter
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
2e0111b11e
commit
4fb8e337e9
13 files changed
+266
-50
No files matched your search
@@ -79,5 +79,6 @@ describe("IssueFiltersPopover", () => {
|
||||
element.className.includes("md:grid-cols-3"),
|
||||
);
|
||||
expect(layoutGrid?.className).toContain("grid-cols-1");
|
||||
expect(popoverContent?.textContent).toContain("Live runs only");
|
||||
});
|
||||
});
|
||||
@@ -344,9 +344,16 @@ export function IssueFiltersPopover({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{enableRoutineVisibilityFilter ? (
|
||||
<div className="space-y-1">
|
||||
<span className="text-xs text-muted-foreground">Visibility</span>
|
||||
<div className="space-y-1">
|
||||
<span className="text-xs text-muted-foreground">Visibility</span>
|
||||
<label className="flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1 hover:bg-accent/50">
|
||||
<Checkbox
|
||||
checked={state.liveOnly}
|
||||
onCheckedChange={(checked) => onChange({ liveOnly: checked === true })}
|
||||
/>
|
||||
<span className="text-sm">Live runs only</span>
|
||||
</label>
|
||||
{enableRoutineVisibilityFilter ? (
|
||||
<label className="flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1 hover:bg-accent/50">
|
||||
<Checkbox
|
||||
checked={state.hideRoutineExecutions}
|
||||
@@ -354,8 +361,8 @@ export function IssueFiltersPopover({
|
||||
/>
|
||||
<span className="text-sm">Hide routine runs</span>
|
||||
</label>
|
||||
</div>
|
||||
) : null}
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
issuePriorityOrder,
|
||||
normalizeIssueFilterState,
|
||||
resolveIssueFilterWorkspaceId,
|
||||
shouldIncludeIssueFilterWorkspaceOption,
|
||||
issueStatusOrder,
|
||||
type IssueFilterState,
|
||||
} from "../lib/issue-filters";
|
||||
@@ -483,6 +484,10 @@ export function IssuesList({
|
||||
}
|
||||
return map;
|
||||
}, [projects]);
|
||||
const defaultProjectWorkspaceIds = useMemo(
|
||||
() => new Set(defaultProjectWorkspaceIdByProjectId.values()),
|
||||
[defaultProjectWorkspaceIdByProjectId],
|
||||
);
|
||||
|
||||
const executionWorkspaceById = useMemo(() => {
|
||||
const map = new Map<string, {
|
||||
@@ -499,17 +504,27 @@ export function IssuesList({
|
||||
}
|
||||
return map;
|
||||
}, [executionWorkspaces]);
|
||||
const issueFilterWorkspaceContext = useMemo(() => ({
|
||||
executionWorkspaceById,
|
||||
defaultProjectWorkspaceIdByProjectId,
|
||||
}), [defaultProjectWorkspaceIdByProjectId, executionWorkspaceById]);
|
||||
|
||||
const workspaceNameMap = useMemo(() => {
|
||||
const map = new Map<string, string>();
|
||||
for (const [workspaceId, workspace] of projectWorkspaceById) {
|
||||
if (!shouldIncludeIssueFilterWorkspaceOption({ id: workspaceId }, defaultProjectWorkspaceIds)) continue;
|
||||
map.set(workspaceId, workspace.name);
|
||||
}
|
||||
for (const [workspaceId, workspace] of executionWorkspaceById) {
|
||||
if (!shouldIncludeIssueFilterWorkspaceOption({
|
||||
id: workspaceId,
|
||||
mode: workspace.mode,
|
||||
projectWorkspaceId: workspace.projectWorkspaceId,
|
||||
}, defaultProjectWorkspaceIds)) continue;
|
||||
map.set(workspaceId, workspace.name);
|
||||
}
|
||||
return map;
|
||||
}, [executionWorkspaceById, projectWorkspaceById]);
|
||||
}, [defaultProjectWorkspaceIds, executionWorkspaceById, projectWorkspaceById]);
|
||||
|
||||
const workspaceOptions = useMemo(() => {
|
||||
const options = new Map<string, string>();
|
||||
@@ -635,9 +650,27 @@ export function IssuesList({
|
||||
const searchScopedIssues = normalizedIssueSearch.length > 0 && searchWithinLoadedIssues
|
||||
? sourceIssues.filter((issue) => issueMatchesLocalSearch(issue, normalizedIssueSearch))
|
||||
: sourceIssues;
|
||||
const filteredByControls = applyIssueFilters(searchScopedIssues, viewState, currentUserId, enableRoutineVisibilityFilter);
|
||||
const filteredByControls = applyIssueFilters(
|
||||
searchScopedIssues,
|
||||
viewState,
|
||||
currentUserId,
|
||||
enableRoutineVisibilityFilter,
|
||||
liveIssueIds,
|
||||
issueFilterWorkspaceContext,
|
||||
);
|
||||
return sortIssues(filteredByControls, viewState);
|
||||
}, [boardIssues, issues, searchedIssues, searchWithinLoadedIssues, viewState, normalizedIssueSearch, currentUserId, enableRoutineVisibilityFilter]);
|
||||
}, [
|
||||
boardIssues,
|
||||
issues,
|
||||
searchedIssues,
|
||||
searchWithinLoadedIssues,
|
||||
viewState,
|
||||
normalizedIssueSearch,
|
||||
currentUserId,
|
||||
enableRoutineVisibilityFilter,
|
||||
liveIssueIds,
|
||||
issueFilterWorkspaceContext,
|
||||
]);
|
||||
|
||||
const { data: labels } = useQuery({
|
||||
queryKey: queryKeys.issues.labels(selectedCompanyId!),
|
||||
@@ -664,7 +697,10 @@ export function IssuesList({
|
||||
.map((p) => ({ key: p, label: issueFilterLabel(p), items: groups[p]! }));
|
||||
}
|
||||
if (viewState.groupBy === "workspace") {
|
||||
const groups = groupBy(filtered, (issue) => resolveIssueFilterWorkspaceId(issue) ?? "__no_workspace");
|
||||
const groups = groupBy(
|
||||
filtered,
|
||||
(issue) => resolveIssueFilterWorkspaceId(issue, issueFilterWorkspaceContext) ?? "__no_workspace",
|
||||
);
|
||||
return Object.keys(groups)
|
||||
.sort((a, b) => {
|
||||
// Groups with items first, "no workspace" last
|
||||
@@ -708,7 +744,17 @@ export function IssuesList({
|
||||
: (agentName(key) ?? key.slice(0, 8)),
|
||||
items: groups[key]!,
|
||||
}));
|
||||
}, [filtered, viewState.groupBy, agents, agentName, currentUserId, workspaceNameMap, issueTitleMap, companyUserLabelMap]);
|
||||
}, [
|
||||
filtered,
|
||||
issueFilterWorkspaceContext,
|
||||
viewState.groupBy,
|
||||
agents,
|
||||
agentName,
|
||||
currentUserId,
|
||||
workspaceNameMap,
|
||||
issueTitleMap,
|
||||
companyUserLabelMap,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (viewState.viewMode !== "list") return;
|
||||
@@ -1125,7 +1171,7 @@ export function IssuesList({
|
||||
columns={visibleTrailingIssueColumns}
|
||||
projectName={issueProject?.name ?? null}
|
||||
projectColor={issueProject?.color ?? null}
|
||||
workspaceId={resolveIssueFilterWorkspaceId(issue)}
|
||||
workspaceId={resolveIssueFilterWorkspaceId(issue, issueFilterWorkspaceContext)}
|
||||
workspaceName={resolveIssueWorkspaceName(issue, {
|
||||
executionWorkspaceById,
|
||||
projectWorkspaceById,
|
||||
|
||||
Reference in new issue
Block a user