Timeline: default filter to "all" + add missing statuses + team scope
Three fixes for an empty Production Timeline: 1. Default statusFilter flipped from ACTIVE → "all". Fresh imports land at PIPELINE status (brief-accepted), so ACTIVE-default hid every project on first load. 2. Status dropdown was missing PIPELINE and CANCELED — so even after you realised ACTIVE was wrong you couldn't pick PIPELINE. Added both. 3. /api/timeline was scoping by organizationId only, not ClientTeam visibility. Non-ADMIN users would have seen cross-team projects. AND-in visibleProjectsWhere(ctx) now — same pattern as the rest of the service layer.
This commit is contained in:
parent
4fde413aa9
commit
0ba7c2b464
2 changed files with 17 additions and 6 deletions
|
|
@ -41,7 +41,9 @@ const ZOOM_LABELS: Record<ZoomLevel, string> = {
|
|||
|
||||
export default function TimelinePage() {
|
||||
const [zoom, setZoom] = useState<ZoomLevel>("day");
|
||||
const [statusFilter, setStatusFilter] = useState<string>("ACTIVE");
|
||||
// Default to "all" — previously ACTIVE, which hid every PIPELINE project
|
||||
// (i.e. everything freshly imported) and left the timeline empty.
|
||||
const [statusFilter, setStatusFilter] = useState<string>("all");
|
||||
const [priorityFilter, setPriorityFilter] = useState<string>("all");
|
||||
|
||||
const { data: projects, isLoading } = useTimeline({
|
||||
|
|
@ -205,9 +207,11 @@ export default function TimelinePage() {
|
|||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All Statuses</SelectItem>
|
||||
<SelectItem value="PIPELINE">Pipeline</SelectItem>
|
||||
<SelectItem value="ACTIVE">Active</SelectItem>
|
||||
<SelectItem value="ON_HOLD">On Hold</SelectItem>
|
||||
<SelectItem value="COMPLETED">Completed</SelectItem>
|
||||
<SelectItem value="CANCELED">Canceled</SelectItem>
|
||||
<SelectItem value="ARCHIVED">Archived</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { serverError } from "@/lib/api-utils";
|
||||
import { requireAuth } from "@/lib/rbac/require-auth";
|
||||
import { requireAuth, visibilityContextFromSession } from "@/lib/rbac/require-auth";
|
||||
import { visibleProjectsWhere } from "@/lib/rbac/visibility";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
// GET /api/timeline?status=ACTIVE&priority=&projectIds=
|
||||
|
|
@ -16,13 +17,19 @@ export async function GET(request: NextRequest) {
|
|||
const projectIds = projectIdsParam ? projectIdsParam.split(",") : undefined;
|
||||
|
||||
const organizationId = session.user.organizationId;
|
||||
const ctx = visibilityContextFromSession(session);
|
||||
|
||||
// Build project filter
|
||||
const projectWhere: any = { organizationId };
|
||||
if (statusFilter) projectWhere.status = statusFilter;
|
||||
// Build project filter — AND-in the team visibility scope so non-ADMIN
|
||||
// users only see projects on the ClientTeams they belong to (previously
|
||||
// the timeline leaked cross-team data).
|
||||
const baseFilter: any = { organizationId };
|
||||
if (statusFilter) baseFilter.status = statusFilter;
|
||||
if (projectIds && projectIds.length > 0) {
|
||||
projectWhere.id = { in: projectIds };
|
||||
baseFilter.id = { in: projectIds };
|
||||
}
|
||||
const projectWhere: any = {
|
||||
AND: [baseFilter, await visibleProjectsWhere(ctx)],
|
||||
};
|
||||
|
||||
const delivWhere: any = {};
|
||||
if (priorityFilter) delivWhere.priority = priorityFilter;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue