feat(platform): harden access scoping and delivery baseline
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { clsx } from "clsx";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useAllocationHistory } from "~/hooks/useAllocationHistory.js";
|
||||
import { useProjectDragContext } from "~/hooks/useProjectDragContext.js";
|
||||
@@ -38,7 +39,13 @@ import { useMultiSelectIntersection } from "~/hooks/useMultiSelectIntersection.j
|
||||
// then wraps children with TimelineProvider. The inner content consumes context.
|
||||
|
||||
export function TimelineView() {
|
||||
const { data: session, status: sessionStatus } = useSession();
|
||||
const mousePosRef = useRef({ x: 0, y: 0 });
|
||||
const role = sessionStatus === "authenticated"
|
||||
? ((session.user as { role?: string } | undefined)?.role ?? "USER")
|
||||
: null;
|
||||
const isSelfServiceTimeline = role === "USER" || role === "VIEWER";
|
||||
const canManageTimeline = !isSelfServiceTimeline;
|
||||
|
||||
const { push: pushHistory, pushBatch: pushBatchHistory, undo, redo, canUndo, canRedo } = useAllocationHistory();
|
||||
const pushHistoryRef = useRef(pushHistory);
|
||||
@@ -147,8 +154,8 @@ export function TimelineView() {
|
||||
|
||||
const [openPanelProjectId, setOpenPanelProjectId] = useState<string | null>(null);
|
||||
const dragProjectId = dragState.isDragging ? dragState.projectId : null;
|
||||
const contextProjectId = dragProjectId ?? openPanelProjectId;
|
||||
const { contextResourceIds, contextAllocations } = useProjectDragContext(contextProjectId);
|
||||
const contextProjectId = canManageTimeline ? (dragProjectId ?? openPanelProjectId) : null;
|
||||
const { contextResourceIds, contextAllocations } = useProjectDragContext(contextProjectId, canManageTimeline);
|
||||
|
||||
return (
|
||||
<TimelineProvider
|
||||
@@ -189,6 +196,7 @@ export function TimelineView() {
|
||||
setOpenPanelProjectId={setOpenPanelProjectId}
|
||||
canUndo={canUndo}
|
||||
canRedo={canRedo}
|
||||
isSelfServiceTimeline={isSelfServiceTimeline}
|
||||
undo={undo}
|
||||
redo={redo}
|
||||
/>
|
||||
@@ -232,6 +240,7 @@ function TimelineViewContent({
|
||||
setOpenPanelProjectId,
|
||||
canUndo,
|
||||
canRedo,
|
||||
isSelfServiceTimeline,
|
||||
undo,
|
||||
redo,
|
||||
}: {
|
||||
@@ -278,6 +287,7 @@ function TimelineViewContent({
|
||||
setOpenPanelProjectId: React.Dispatch<React.SetStateAction<string | null>>;
|
||||
canUndo: boolean;
|
||||
canRedo: boolean;
|
||||
isSelfServiceTimeline: boolean;
|
||||
undo: () => Promise<void>;
|
||||
redo: () => Promise<void>;
|
||||
}) {
|
||||
@@ -642,7 +652,7 @@ function TimelineViewContent({
|
||||
onMouseUp={(e) => void onCanvasMouseUp(e)}
|
||||
onMouseLeave={onCanvasMouseLeave}
|
||||
onMouseDown={(e) => {
|
||||
if (e.button === 2) {
|
||||
if (!isSelfServiceTimeline && e.button === 2) {
|
||||
onCanvasRightMouseDown(e);
|
||||
}
|
||||
}}
|
||||
@@ -666,11 +676,11 @@ function TimelineViewContent({
|
||||
rangeState={effectiveRangeState}
|
||||
shiftPreview={shiftPreview}
|
||||
contextResourceIds={contextResourceIds}
|
||||
onAllocMouseDown={onAllocMouseDown}
|
||||
onAllocTouchStart={onAllocTouchStart}
|
||||
onRowMouseDown={onRowMouseDown}
|
||||
onRowTouchStart={onRowTouchStart}
|
||||
onAllocationContextMenu={openAllocationPopoverAt}
|
||||
onAllocMouseDown={isSelfServiceTimeline ? () => undefined : onAllocMouseDown}
|
||||
onAllocTouchStart={isSelfServiceTimeline ? () => undefined : onAllocTouchStart}
|
||||
onRowMouseDown={isSelfServiceTimeline ? () => undefined : onRowMouseDown}
|
||||
onRowTouchStart={isSelfServiceTimeline ? () => undefined : onRowTouchStart}
|
||||
onAllocationContextMenu={isSelfServiceTimeline ? () => undefined : openAllocationPopoverAt}
|
||||
multiSelectState={multiSelectState}
|
||||
CELL_WIDTH={CELL_WIDTH}
|
||||
dates={dates}
|
||||
@@ -689,15 +699,15 @@ function TimelineViewContent({
|
||||
allocDragState={allocDragState}
|
||||
rangeState={effectiveRangeState}
|
||||
multiSelectState={multiSelectState}
|
||||
onProjectBarMouseDown={onProjectBarMouseDown}
|
||||
onProjectBarTouchStart={onProjectBarTouchStart}
|
||||
onAllocMouseDown={onAllocMouseDown}
|
||||
onAllocTouchStart={onAllocTouchStart}
|
||||
onRowMouseDown={onRowMouseDown}
|
||||
onRowTouchStart={onRowTouchStart}
|
||||
onOpenPanel={setOpenPanelProjectId}
|
||||
onOpenDemandClick={setOpenDemandToAssign}
|
||||
onAllocationContextMenu={openAllocationPopoverAt}
|
||||
onProjectBarMouseDown={isSelfServiceTimeline ? () => undefined : onProjectBarMouseDown}
|
||||
onProjectBarTouchStart={isSelfServiceTimeline ? () => undefined : onProjectBarTouchStart}
|
||||
onAllocMouseDown={isSelfServiceTimeline ? () => undefined : onAllocMouseDown}
|
||||
onAllocTouchStart={isSelfServiceTimeline ? () => undefined : onAllocTouchStart}
|
||||
onRowMouseDown={isSelfServiceTimeline ? () => undefined : onRowMouseDown}
|
||||
onRowTouchStart={isSelfServiceTimeline ? () => undefined : onRowTouchStart}
|
||||
onOpenPanel={isSelfServiceTimeline ? () => undefined : setOpenPanelProjectId}
|
||||
onOpenDemandClick={isSelfServiceTimeline ? () => undefined : setOpenDemandToAssign}
|
||||
onAllocationContextMenu={isSelfServiceTimeline ? () => undefined : openAllocationPopoverAt}
|
||||
CELL_WIDTH={CELL_WIDTH}
|
||||
dates={dates}
|
||||
totalCanvasWidth={totalCanvasWidth}
|
||||
@@ -815,7 +825,7 @@ function TimelineViewContent({
|
||||
)}
|
||||
|
||||
{/* Allocation / Demand popover (click path) */}
|
||||
{popover && (() => {
|
||||
{!isSelfServiceTimeline && popover && (() => {
|
||||
// Check if clicked allocation is actually a demand
|
||||
const clickedDemand = openDemandsByProject.get(popover.projectId)?.find((d) => d.id === popover.allocationId);
|
||||
if (clickedDemand) {
|
||||
@@ -863,7 +873,7 @@ function TimelineViewContent({
|
||||
})()}
|
||||
|
||||
{/* Demand popover */}
|
||||
{demandPopover && (
|
||||
{!isSelfServiceTimeline && demandPopover && (
|
||||
<DemandPopover
|
||||
demand={demandPopover.demand}
|
||||
onClose={() => setDemandPopover(null)}
|
||||
@@ -892,7 +902,7 @@ function TimelineViewContent({
|
||||
)}
|
||||
|
||||
{/* New allocation popover */}
|
||||
{newAllocPopover && (
|
||||
{!isSelfServiceTimeline && newAllocPopover && (
|
||||
<NewAllocationPopover
|
||||
resourceId={newAllocPopover.resourceId}
|
||||
startDate={newAllocPopover.startDate}
|
||||
@@ -906,12 +916,12 @@ function TimelineViewContent({
|
||||
)}
|
||||
|
||||
{/* Project side panel */}
|
||||
{openPanelProjectId && (
|
||||
{!isSelfServiceTimeline && openPanelProjectId && (
|
||||
<ProjectPanel projectId={openPanelProjectId} onClose={() => setOpenPanelProjectId(null)} />
|
||||
)}
|
||||
|
||||
{/* Open-demand assignment modal */}
|
||||
{openDemandToAssign && (
|
||||
{!isSelfServiceTimeline && openDemandToAssign && (
|
||||
<FillOpenDemandModal
|
||||
allocation={openDemandToAssign}
|
||||
onClose={() => setOpenDemandToAssign(null)}
|
||||
|
||||
Reference in New Issue
Block a user