@object-ui/plugin-gantt 6.2.2 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +150 -0
- package/README.md +109 -4
- package/dist/GanttView.d.ts +217 -0
- package/dist/GanttView.d.ts.map +1 -0
- package/dist/ObjectGantt.d.ts +38 -0
- package/dist/ObjectGantt.d.ts.map +1 -0
- package/dist/QuickFilterBar.d.ts +39 -0
- package/dist/QuickFilterBar.d.ts.map +1 -0
- package/dist/ResourceWorkload.d.ts +37 -0
- package/dist/ResourceWorkload.d.ts.map +1 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3449 -534
- package/dist/index.umd.cjs +93 -1
- package/dist/scheduling.d.ts +83 -0
- package/dist/scheduling.d.ts.map +1 -0
- package/dist/{packages/plugin-gantt/src/useGanttTranslation.d.ts → useGanttTranslation.d.ts} +3 -6
- package/dist/useGanttTranslation.d.ts.map +1 -0
- package/dist/workload.d.ts +73 -0
- package/dist/workload.d.ts.map +1 -0
- package/package.json +13 -12
- package/dist/packages/plugin-gantt/src/GanttView.d.ts +0 -43
- package/dist/packages/plugin-gantt/src/GanttView.d.ts.map +0 -1
- package/dist/packages/plugin-gantt/src/ObjectGantt.d.ts +0 -13
- package/dist/packages/plugin-gantt/src/ObjectGantt.d.ts.map +0 -1
- package/dist/packages/plugin-gantt/src/index.d.ts +0 -10
- package/dist/packages/plugin-gantt/src/index.d.ts.map +0 -1
- package/dist/packages/plugin-gantt/src/useGanttTranslation.d.ts.map +0 -1
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1,93 @@
|
|
|
1
|
-
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@objectstack/spec/ui"),require("@object-ui/plugin-detail"),require("@object-ui/components"),require("@object-ui/fields"),require("lucide-react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@objectstack/spec/ui`,`@object-ui/plugin-detail`,`@object-ui/components`,`@object-ui/fields`,`lucide-react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginGantt={},e.React,e.ObjectUICore,e.ObjectUIReact,e._objectstack_spec_ui,e._object_ui_plugin_detail,e.ObjectUIComponents,e._object_ui_fields,e.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c,l){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var u=Object.create,d=Object.defineProperty,f=Object.getOwnPropertyDescriptor,p=Object.getOwnPropertyNames,m=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty,g=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=p(t),a=0,o=i.length,s;a<o;a++)s=i[a],!h.call(e,s)&&s!==n&&d(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=f(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:u(m(e)),g(t||!e||!e.__esModule?d(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);var _={"gantt.column.taskName":`Task Name`,"gantt.column.start":`Start`,"gantt.column.end":`End`,"gantt.toolbar.prevPeriod":`Previous period`,"gantt.toolbar.nextPeriod":`Next period`,"gantt.toolbar.zoomIn":`Zoom in`,"gantt.toolbar.zoomOut":`Zoom out`,"gantt.toolbar.jumpToToday":`Jump to today`,"gantt.toolbar.today":`Today`,"gantt.toolbar.showTaskList":`Show task list`,"gantt.toolbar.hideTaskList":`Hide task list`},v=`gantt.column.taskName`;function y(e,t){let n=_[e]||e;if(t)for(let[e,r]of Object.entries(t))n=n.replace(`{{${e}}}`,String(r));return n}function b(){try{let e=(0,r.useObjectTranslation)();return e.t(v)===v?{t:y}:{t:e.t}}catch{return{t:y}}}function x(e){return e<640?35:e<1024?50:60}function S(e){return e<640?140:e<1024?220:320}function C(e){return e>=280}function w(e){return e<640?32:40}function T({tasks:e,startDate:n,endDate:r,onTaskClick:i,onTaskUpdate:a,className:s,inlineEdit:u=!1}){let{t:d}=b(),[f,p]=t.useState(new Date),m=t.useRef(null),{width:h}=(0,o.useResizeObserver)(m),g=h||(typeof window<`u`?window.innerWidth:1024),_=g<640,v=w(g),y=x(g),[T,E]=t.useState(null),D=T??y,[O,k]=t.useState(!1),A=t.useRef(!1);t.useEffect(()=>{!A.current&&_&&(k(!0),A.current=!0)},[_]);let j=O?0:S(g),M=C(j),[N,P]=t.useState(null),[F,I]=t.useState({}),[L,R]=t.useState(null),z=t.useRef(null);t.useEffect(()=>{z.current=L},[L]);let B=t.useRef(!1),V=t.useCallback(e=>{let t=1e3*60*60*24,n=t,r=e.dayDelta*t,i=new Date(e.originStart),a=new Date(e.originEnd);return e.mode===`move`?(i=new Date(e.originStart.getTime()+r),a=new Date(e.originEnd.getTime()+r)):e.mode===`resize-left`?(i=new Date(e.originStart.getTime()+r),a.getTime()-i.getTime()<n&&(i=new Date(a.getTime()-n))):e.mode===`resize-right`&&(a=new Date(e.originEnd.getTime()+r),a.getTime()-i.getTime()<n&&(a=new Date(i.getTime()+n))),{start:i,end:a}},[]);t.useEffect(()=>{if(!L)return;let t=e=>{let t=z.current;if(!t)return;let n=Math.round((e.clientX-t.originClientX)/Math.max(D,1));n!==t.dayDelta&&R({...t,dayDelta:n})},n=()=>{let t=z.current;if(t){if(t.dayDelta!==0){let n=e.find(e=>e.id===t.taskId);if(n&&a){let{start:e,end:r}=V(t);a(n,{start:e,end:r})}B.current=!0,window.setTimeout(()=>{B.current=!1},0)}R(null)}};return window.addEventListener(`pointermove`,t),window.addEventListener(`pointerup`,n),window.addEventListener(`pointercancel`,n),()=>{window.removeEventListener(`pointermove`,t),window.removeEventListener(`pointerup`,n),window.removeEventListener(`pointercancel`,n)}},[L,D,e,a,V]);let H=t.useCallback((e,t,n)=>{a&&(n.stopPropagation(),n.preventDefault(),R({taskId:e.id,mode:t,originStart:new Date(e.start),originEnd:new Date(e.end),originClientX:n.clientX,dayDelta:0}))},[a]),U=t.useMemo(()=>{let t=n?new Date(n):new Date,i=r?new Date(r):new Date;return!n&&e.length>0&&(t=new Date(Math.min(...e.map(e=>e.start.getTime()))),t.setDate(t.getDate()-7)),!r&&e.length>0&&(i=new Date(Math.max(...e.map(e=>e.end.getTime()))),i.setDate(i.getDate()+14)),t.setHours(0,0,0,0),i.setHours(23,59,59,999),{start:t,end:i}},[n,r,e]),W=t.useMemo(()=>{let e=[],t=new Date(U.start);for(;t<=U.end;)e.push({date:new Date(t),label:t.getDate().toString(),isWeekend:t.getDay()===0||t.getDay()===6}),t.setDate(t.getDate()+1);return e},[U]),G=t.useRef(null),K=t.useRef(null),q=t.useRef(null),J=t.useRef(null),Y=t.useRef(null),X=t.useCallback(e=>{if(e.touches.length===2){let t=e.touches[0].clientX-e.touches[1].clientX,n=e.touches[0].clientY-e.touches[1].clientY;Y.current={baseDistance:Math.max(1,Math.sqrt(t*t+n*n)),baseColumn:D}}},[D]),Z=t.useCallback(e=>{if(e.touches.length!==2||!Y.current)return;let t=e.touches[0].clientX-e.touches[1].clientX,n=e.touches[0].clientY-e.touches[1].clientY,r=Math.max(1,Math.sqrt(t*t+n*n))/Y.current.baseDistance;E(Math.max(15,Math.min(120,Math.round(Y.current.baseColumn*r))))},[]),ee=t.useCallback(()=>{Y.current=null},[]),Q=t.useMemo(()=>{let e=new Date;if(e<U.start||e>U.end)return null;let t=(e.getTime()-U.start.getTime())/(1440*60*1e3);return Math.round(t*D)},[U,D]),te=t.useCallback(()=>{if(Q==null||!J.current)return;let e=Math.max(0,Q-J.current.clientWidth/2);J.current.scrollTo({left:e,behavior:`smooth`})},[Q]),ne=e=>{G.current&&(G.current.scrollLeft=e.currentTarget.scrollLeft),K.current&&(K.current.scrollTop=e.currentTarget.scrollTop)},$=e=>{U.end.getTime()-U.start.getTime();let t=D,n=1e3*60*60*24,r=e.start.getTime()-U.start.getTime(),i=e.end.getTime()-e.start.getTime();return{left:r/n*t,width:Math.max(i/n*t,t)}};return(0,l.jsxs)(`div`,{ref:m,className:(0,o.cn)(`flex flex-col h-full bg-background overflow-hidden min-w-0`,s),children:[(0,l.jsxs)(`div`,{className:`flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 p-2 border-b bg-card`,children:[(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,"aria-label":d(`gantt.toolbar.prevPeriod`),children:(0,l.jsx)(c.ChevronLeft,{className:`h-4 w-4`})}),(0,l.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,"aria-label":d(`gantt.toolbar.nextPeriod`),children:(0,l.jsx)(c.ChevronRight,{className:`h-4 w-4`})}),(0,l.jsx)(`span`,{className:`font-semibold text-xs sm:text-sm`,children:U.start.toLocaleDateString(void 0,{month:`long`,year:`numeric`})})]}),(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsxs)(`div`,{className:`flex bg-muted rounded-md p-1`,children:[(0,l.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-6 w-6`,onClick:()=>E(Math.max(15,D-10)),"aria-label":d(`gantt.toolbar.zoomOut`),children:(0,l.jsx)(c.ZoomOut,{className:`h-3 w-3`})}),(0,l.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-6 w-6`,onClick:()=>E(Math.min(120,D+10)),"aria-label":d(`gantt.toolbar.zoomIn`),children:(0,l.jsx)(c.ZoomIn,{className:`h-3 w-3`})})]}),(0,l.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:()=>k(e=>!e),"aria-label":d(O?`gantt.toolbar.showTaskList`:`gantt.toolbar.hideTaskList`),"aria-pressed":O,"data-testid":`gantt-toggle-task-list`,children:O?(0,l.jsx)(c.PanelLeft,{className:`h-4 w-4`}):(0,l.jsx)(c.PanelLeftClose,{className:`h-4 w-4`})}),(0,l.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:te,disabled:Q==null,"aria-label":d(`gantt.toolbar.jumpToToday`),"data-testid":`gantt-jump-today`,children:(0,l.jsx)(c.CalendarDays,{className:`h-4 w-4`})})]})]}),(0,l.jsxs)(`div`,{className:`flex flex-col flex-1 overflow-hidden`,children:[(0,l.jsxs)(`div`,{className:`flex border-b bg-muted/30 shrink-0 h-10 sm:h-[50px]`,children:[(0,l.jsxs)(`div`,{className:`flex items-center font-medium text-xs text-muted-foreground px-2 sm:px-4 border-r bg-card z-20 shadow-sm`,style:{width:j,minWidth:j},children:[(0,l.jsx)(`div`,{className:`flex-1 truncate`,children:d(`gantt.column.taskName`)}),M&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`w-16 sm:w-20 text-right`,children:d(`gantt.column.start`)}),(0,l.jsx)(`div`,{className:`w-16 sm:w-20 text-right`,children:d(`gantt.column.end`)})]})]}),(0,l.jsx)(`div`,{className:`flex-1 overflow-hidden`,ref:G,children:(0,l.jsx)(`div`,{className:`flex h-full`,style:{width:W.length*D},children:W.map((e,t)=>(0,l.jsxs)(`div`,{className:(0,o.cn)(`flex flex-col items-center justify-center border-r text-xs text-muted-foreground h-full`,e.isWeekend&&`bg-muted/50`),style:{width:D,minWidth:D},children:[(0,l.jsx)(`span`,{className:`font-medium text-foreground`,children:e.label}),(0,l.jsx)(`span`,{className:`text-[10px] opacity-70`,children:e.date.toLocaleDateString(void 0,{weekday:`narrow`})})]},t))})})]}),(0,l.jsxs)(`div`,{className:`flex flex-1 overflow-hidden`,children:[(0,l.jsx)(`div`,{className:`overflow-hidden border-r bg-card z-10 shadow-sm`,ref:K,style:{width:j,minWidth:j},children:e.map(e=>{let t=u&&N===e.id;return(0,l.jsxs)(`div`,{className:`group/task-row flex items-center border-b px-2 sm:px-4 hover:bg-accent/50 cursor-pointer transition-colors touch-manipulation`,style:{height:v},onClick:()=>!t&&i?.(e),onDoubleClick:()=>{u&&a&&(P(e.id),I({title:e.title,start:e.start.toLocaleDateString(`en-CA`),end:e.end.toLocaleDateString(`en-CA`),progress:String(e.progress)}))},children:[(0,l.jsxs)(`div`,{className:`flex-1 truncate font-medium text-xs sm:text-sm flex items-center gap-2`,children:[(0,l.jsx)(`div`,{className:`w-2 h-2 rounded-full shrink-0`,style:{backgroundColor:e.color||`#3b82f6`}}),t?(0,l.jsx)(`input`,{className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:F.title||``,onChange:e=>I(t=>({...t,title:e.target.value})),onKeyDown:t=>{t.key===`Enter`?(a?.(e,{title:F.title,start:new Date(F.start),end:new Date(F.end),progress:Number(F.progress)||0}),P(null)):t.key===`Escape`&&P(null)},onClick:e=>e.stopPropagation(),autoFocus:!0}):(0,l.jsxs)(`span`,{className:`flex flex-col min-w-0`,children:[(0,l.jsx)(`span`,{className:`truncate`,children:e.title}),(0,l.jsxs)(`span`,{className:`text-[10px] text-muted-foreground sm:hidden`,children:[e.start.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`}),` → `,e.end.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})]})]})]}),(0,l.jsx)(`div`,{className:`w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block`,hidden:!M,style:M?void 0:{display:`none`},children:t?(0,l.jsx)(`input`,{type:`date`,className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:F.start||``,onChange:e=>I(t=>({...t,start:e.target.value})),onClick:e=>e.stopPropagation()}):e.start.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})}),(0,l.jsx)(`div`,{className:`w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block`,hidden:!M,style:M?void 0:{display:`none`},children:t?(0,l.jsx)(`input`,{type:`date`,className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:F.end||``,onChange:e=>I(t=>({...t,end:e.target.value})),onClick:e=>e.stopPropagation()}):e.end.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})})]},e.id)})}),(0,l.jsx)(`div`,{className:`flex-1 overflow-auto bg-background/50 relative [-webkit-overflow-scrolling:touch]`,ref:e=>{q.current=e,J.current=e},onScroll:ne,onTouchStart:X,onTouchMove:Z,onTouchEnd:ee,"data-testid":`gantt-timeline`,children:(0,l.jsxs)(`div`,{className:`relative`,style:{width:W.length*D},children:[Q!=null&&(0,l.jsx)(`div`,{className:`absolute top-0 bottom-0 w-px bg-red-500/80 z-20 pointer-events-none`,style:{left:Q},"data-testid":`gantt-today-marker`,"aria-label":d(`gantt.toolbar.today`),children:(0,l.jsx)(`div`,{className:`absolute -top-2 -translate-x-1/2 left-0 text-[10px] font-semibold text-white bg-red-500 rounded-sm px-1 py-0.5 whitespace-nowrap`,children:d(`gantt.toolbar.today`)})}),(0,l.jsxs)(`div`,{className:`relative`,children:[(0,l.jsx)(`div`,{className:`absolute inset-0 flex pointer-events-none z-0`,children:W.map((e,t)=>(0,l.jsx)(`div`,{className:(0,o.cn)(`border-r h-full`,e.isWeekend&&`bg-muted/20`),style:{width:D,minWidth:D}},t))}),e.map(e=>{let t=$(e),n=L?.taskId===e.id,r=t;if(n&&L){let t=V(L);r=$({...e,start:t.start,end:t.end})}let s=!!a;return(0,l.jsxs)(`div`,{className:`relative border-b hover:bg-black/5`,style:{height:v},children:[n&&(0,l.jsx)(`div`,{className:`absolute top-1 sm:top-2 h-[calc(100%-8px)] sm:h-[calc(100%-16px)] rounded-sm border border-dashed border-primary/60 pointer-events-none`,style:{left:t.left,width:t.width,opacity:.35},"aria-hidden":`true`}),(0,l.jsxs)(`div`,{className:(0,o.cn)(`absolute top-1 sm:top-2 h-[calc(100%-8px)] sm:h-[calc(100%-16px)] rounded-sm bg-primary border border-primary-foreground/20 shadow-sm hover:brightness-110 flex items-center px-2 group select-none`,s?`cursor-grab active:cursor-grabbing`:`cursor-pointer`,n&&`ring-2 ring-primary/60 brightness-110 z-10`),style:{left:r.left,width:r.width,backgroundColor:e.color||`#3b82f6`},"data-testid":`gantt-task-bar-${e.id}`,onClick:()=>{B.current||i?.(e)},onPointerDown:s?t=>{t.button===0&&H(e,`move`,t)}:void 0,children:[s&&r.width>=14&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`absolute left-0 top-0 bottom-0 w-1.5 cursor-ew-resize hover:bg-white/40`,"data-testid":`gantt-task-resize-left-${e.id}`,onPointerDown:t=>{t.button===0&&H(e,`resize-left`,t)},onClick:e=>e.stopPropagation()}),(0,l.jsx)(`div`,{className:`absolute right-0 top-0 bottom-0 w-1.5 cursor-ew-resize hover:bg-white/40`,"data-testid":`gantt-task-resize-right-${e.id}`,onPointerDown:t=>{t.button===0&&H(e,`resize-right`,t)},onClick:e=>e.stopPropagation()})]}),e.progress>0&&(0,l.jsx)(`div`,{className:`absolute left-0 top-0 bottom-0 bg-black/20 rounded-l-sm pointer-events-none`,style:{width:`${e.progress}%`}}),(0,l.jsx)(`span`,{className:`text-[10px] text-white font-medium truncate opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none`,children:n?`${V(L).start.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})} → ${V(L).end.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})}`:`${Math.round(e.progress)}%`})]})]},e.id)}),(0,l.jsx)(`div`,{className:`absolute top-0 bottom-0 w-px bg-red-500 z-20 pointer-events-none`,style:{left:(new Date().getTime()-U.start.getTime())/(1e3*60*60*24)*D},children:(0,l.jsx)(`div`,{className:`w-2 h-2 rounded-full bg-red-500 -ml-[3px]`})})]})]})})]})]})]})}function E(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function D(e){if(e){if(typeof e==`string`){let t=e.split(` `),n=t[0],r=t[1]?.toLowerCase()===`desc`?`desc`:`asc`;return{[n]:r}}if(Array.isArray(e))return e.reduce((e,t)=>(t.field&&t.order&&(e[t.field]=t.order),e),{})}}function O(e){let t=null;if(e.startDateField&&e.endDateField)return t={startDateField:e.startDateField,endDateField:e.endDateField,titleField:e.titleField||`name`,progressField:e.progressField,dependenciesField:e.dependenciesField||e.dependencyField,colorField:e.colorField},t;if(e.gantt&&(t=e.gantt),t){let e=i.GanttConfigSchema.safeParse(t);return e.success||console.warn(`[ObjectGantt] Invalid gantt configuration:`,e.error.format()),t}return null}var k=({schema:e,dataSource:i,className:c,onTaskClick:u,onRowClick:d,...f})=>{let[p,m]=(0,t.useState)([]),[h,g]=(0,t.useState)(!0),[_,v]=(0,t.useState)(null),[y,b]=(0,t.useState)(null),x=E(e),S=(0,t.useMemo)(()=>x,[JSON.stringify(x)]),C=O(e),w=S?.provider===`value`;(0,t.useEffect)(()=>{(async()=>{try{if(g(!0),f.data&&Array.isArray(f.data)){m(f.data),g(!1);return}if(w&&S?.provider===`value`){m(S.items),g(!1);return}if(!i||typeof i.find!=`function`)throw Error(`DataSource required for object/api providers`);if(S?.provider===`object`){let t=S.object,r=(0,n.buildExpandFields)(y?.fields);m((0,n.extractRecords)(await i.find(t,{$filter:e.filter,$orderby:D(e.sort),...r.length>0?{$expand:r}:{}})))}else S?.provider===`api`&&(console.warn(`API provider not yet implemented for ObjectGantt`),m([]));g(!1)}catch(e){v(e),g(!1)}})()},[S,i,w,e.filter,e.sort,y]),(0,t.useEffect)(()=>{!w&&i&&(async()=>{try{if(!i)return;let t=S?.provider===`object`?S.object:e.objectName;if(!t)return;b(await i.getObjectSchema(t))}catch(e){console.error(`Failed to fetch object schema:`,e)}})()},[e.objectName,i,w,S]);let k=(0,t.useMemo)(()=>{if(!C||!p.length)return[];let{startDateField:e,endDateField:t,titleField:n,progressField:r,dependenciesField:i,colorField:a}=C,o=(e,t)=>{if(!t)return;let n=t.split(`.`),r=e;for(let e of n){if(r==null)return;r=r[e]}return r},c=e=>{let t=[o(e,n),e?.name,e?.title,e?.subject,e?.label,e?.account?.name,e?.opportunity?.name,e?.contact&&[e.contact.first_name,e.contact.last_name].filter(Boolean).join(` `),e?.id,e?._id];for(let e of t)if(e!=null&&String(e).trim()!==``)return String(e);return`Untitled`};return p.map((n,o)=>{let l=n[e],u=n[t],d=c(n),f=r?n[r]:0,p=i?n[i]:[],m=a?n[a]:void 0;if(!m){let e=n.status??n.state??n.priority??n.severity;if(e!=null&&e!==``){let t=(0,s.getSemanticColorName)(void 0,e);t&&(m=(0,s.getSemanticHex)(t))}}return{id:n.id||n._id||`task-${o}`,title:d,start:l?new Date(l):new Date,end:u?new Date(u):new Date,progress:Math.min(100,Math.max(0,f||0)),dependencies:Array.isArray(p)?p:[],color:m,data:n}}).filter(e=>!isNaN(e.start.getTime())&&!isNaN(e.end.getTime()))},[p,C]),A=e.navigation??{mode:`drawer`,width:`min(960px, 60vw)`},j=A.mode===`drawer`||A.mode===`modal`||A.mode===`split`||A.mode===`popover`,M=(0,r.useNavigationOverlay)({navigation:A,objectName:e.objectName,onRowClick:j?void 0:d}),N=(0,t.useCallback)(async(t,n)=>{if(!C)return;let r=S?.provider===`object`?S.object:e.objectName;if(!r||!i||typeof i.update!=`function`)return;let{startDateField:a,endDateField:o,titleField:s,progressField:c}=C,l={};if(n.start instanceof Date&&(l[a]=n.start.toISOString()),n.end instanceof Date&&(l[o]=n.end.toISOString()),typeof n.title==`string`&&s&&(l[s]=n.title),typeof n.progress==`number`&&c&&(l[c]=n.progress),Object.keys(l).length===0)return;let u=t.data?.id??t.data?._id??t.id;if(u==null)return;let d=p;m(e=>e.map(e=>String(e.id??e._id)===String(u)?{...e,...l}:e));try{await i.update(r,String(u),l)}catch(e){console.error(`[ObjectGantt] Failed to persist task update:`,e),m(d)}},[C,S,i,e.objectName,p]),[P,F]=(0,t.useState)(null),[I,L]=(0,t.useState)(!1),R=(0,t.useCallback)(e=>{F(e)},[]),z=(0,t.useCallback)(async()=>{if(!P)return;let t=S?.provider===`object`?S.object:e.objectName;if(!t||!i?.delete){F(null);return}let n=P.data?.id??P.data?._id??P.id;if(n==null){F(null);return}L(!0);let r=p;m(e=>e.filter(e=>String(e.id??e._id)!==String(n)));try{await i.delete(t,String(n)),F(null)}catch(e){console.error(`[ObjectGantt] Failed to delete:`,e),m(r),F(null)}finally{L(!1)}},[P,S,i,e.objectName,p]);return h?(0,l.jsx)(`div`,{className:c,children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,l.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading Gantt chart...`})})}):_?(0,l.jsx)(`div`,{className:c,children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,l.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,_.message]})})}):C?(0,l.jsxs)(`div`,{className:c,children:[(0,l.jsx)(`div`,{className:`h-[calc(100vh-200px)] min-h-[600px]`,children:(0,l.jsx)(T,{tasks:k,onTaskClick:e=>{M.handleClick(e.data),u?.(e.data)},onTaskUpdate:N,onTaskDelete:R,inlineEdit:!0})}),M.isOverlay&&M.isOpen&&M.selectedRecord&&(()=>{let t=S?.provider===`object`?S.object:e.objectName,n=M.selectedRecord,r=n.id??n._id;if(!t||r==null)return null;let o=C?.titleField?String(n[C.titleField]??`Task Details`):`Task Details`;return(0,l.jsx)(a.RecordDetailDrawer,{open:!0,onClose:M.close,title:o,record:n,objectName:t,recordId:r,dataSource:i,objectSchema:y,width:M.width,fullPageHref:(0,a.deriveRecordPageHref)(t,r)??void 0,onFieldSave:async(e,n)=>{i?.update&&(await i.update(t,String(r),{[e]:n}),m(t=>t.map(t=>String(t.id??t._id)===String(r)?{...t,[e]:n}:t)))},onDelete:async()=>{i?.delete&&(await i.delete(t,String(r)),m(e=>e.filter(e=>String(e.id??e._id)!==String(r))))}})})(),(0,l.jsx)(o.AlertDialog,{open:!!P,onOpenChange:e=>{!e&&!I&&F(null)},children:(0,l.jsxs)(o.AlertDialogContent,{children:[(0,l.jsxs)(o.AlertDialogHeader,{children:[(0,l.jsx)(o.AlertDialogTitle,{children:`Delete this task?`}),(0,l.jsx)(o.AlertDialogDescription,{children:P?(0,l.jsxs)(l.Fragment,{children:[`"`,P.title,`" will be permanently removed. This action cannot be undone.`]}):null})]}),(0,l.jsxs)(o.AlertDialogFooter,{children:[(0,l.jsx)(o.AlertDialogCancel,{disabled:I,children:`Cancel`}),(0,l.jsx)(o.AlertDialogAction,{onClick:e=>{e.preventDefault(),z()},disabled:I,"data-testid":`gantt-delete-confirm`,className:`bg-destructive text-destructive-foreground hover:bg-destructive/90`,children:I?`Deleting…`:`Delete`})]})]})})]}):(0,l.jsx)(`div`,{className:c,children:(0,l.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,l.jsx)(`div`,{className:`text-muted-foreground`,children:`Gantt configuration required. Please specify startDateField, endDateField, and titleField.`})})})},A=({schema:e})=>{let{dataSource:t}=(0,r.useSchemaContext)()||{};return(0,l.jsx)(k,{schema:e,dataSource:t})};n.ComponentRegistry.register(`object-gantt`,A,{namespace:`plugin-gantt`,label:`Object Gantt`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`gantt`,type:`object`,label:`Gantt Config`,description:`startDateField, endDateField, titleField, progressField, percentageField, colorField, dependenciesField`}]}),n.ComponentRegistry.register(`gantt`,A,{namespace:`view`,label:`Gantt View`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`gantt`,type:`object`,label:`Gantt Config`,description:`startDateField, endDateField, titleField, progressField, percentageField, colorField, dependenciesField`}]}),e.GanttView=T,e.ObjectGantt=k,e.ObjectGanttRenderer=A});
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@object-ui/core"),require("@object-ui/react"),require("@objectstack/spec/ui"),require("@object-ui/i18n"),require("@object-ui/plugin-detail"),require("@object-ui/components"),require("@object-ui/fields"),require("lucide-react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@object-ui/core`,`@object-ui/react`,`@objectstack/spec/ui`,`@object-ui/i18n`,`@object-ui/plugin-detail`,`@object-ui/components`,`@object-ui/fields`,`lucide-react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ObjectUIPluginGantt={},e.React,e.ObjectUICore,e.ObjectUIReact,e._objectstack_spec_ui,e._object_ui_i18n,e._object_ui_plugin_detail,e.ObjectUIComponents,e._object_ui_fields,e.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c,l,u){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var d=Object.create,f=Object.defineProperty,p=Object.getOwnPropertyDescriptor,m=Object.getOwnPropertyNames,h=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty,_=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=m(t),a=0,o=i.length,s;a<o;a++)s=i[a],!g.call(e,s)&&s!==n&&f(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=p(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:d(h(e)),_(t||!e||!e.__esModule?f(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);var v=1e3*60*60*24,y=e=>e.toISOString().slice(0,10);function b(e,t){if(t.skipWeekends){let t=e.getUTCDay();if(t===0||t===6)return!1}return!(t.holidays&&t.holidays.has(y(e)))}function x(e){let t=new Date(e);return t.setUTCHours(0,0,0,0),t}function ee(e,t){let n=x(e);for(;!b(n,t);)n=new Date(n.getTime()+v);return n.getTime()}function te(e,t,n){if(t<=e)return 0;let r=0,i=x(e),a=x(t).getTime();for(;i.getTime()<a;)b(i,n)&&r++,i=new Date(i.getTime()+v);return r}function S(e,t,n){if(t<=0)return x(e).getTime();let r=x(e),i=t;for(;i>0;)b(r,n)&&i--,r=new Date(r.getTime()+v);return r.getTime()}function C(e,t,n){if(t<=0)return x(e).getTime();let r=x(e),i=t;for(;i>0;)r=new Date(r.getTime()-v),b(r,n)&&i--;return r.getTime()}var w=e=>String(e);function T(e){return e===`ss`||e===`ff`||e===`sf`?e:`fs`}function ne(e){let t=new Set(e.map(e=>w(e.id))),n=[];for(let r of e){let e=w(r.id);for(let i of r.dependencies??[]){let r=typeof i==`object`&&!!i,a=r?i.id:i;if(a==null||a===``)continue;let o=w(a);o===e||!t.has(o)||n.push({pred:o,succ:e,type:T(r?i.type:void 0)})}}return n}function re(e){let t=new Set;for(let n of e)n.parent!=null&&n.parent!==``&&t.add(w(n.parent));return t}function E(e,t){let n=new Map,r=new Map;for(let t of e)n.set(t,0),r.set(t,[]);for(let e of t)r.get(e.pred).push(e.succ),n.set(e.succ,(n.get(e.succ)??0)+1);let i=e.filter(e=>(n.get(e)??0)===0),a=[];for(;i.length;){let e=i.shift();a.push(e);for(let t of r.get(e)??[]){let e=(n.get(t)??0)-1;n.set(t,e),e===0&&i.push(t)}}if(a.length<e.length){let t=new Set(a);for(let n of e)t.has(n)||a.push(n);return{order:a,hasCycle:!0}}return{order:a,hasCycle:!1}}function ie(e,t){let n={criticalIds:new Set,criticalEdges:new Set};if(!e.length)return n;let r=new Map;for(let n of e){let e=t?te(n.start.getTime(),n.end.getTime(),t):(n.end.getTime()-n.start.getTime())/v;r.set(w(n.id),Number.isFinite(e)&&e>0?e:0)}let i=ne(e),a=e.map(e=>w(e.id)),{order:o,hasCycle:s}=E(a,i);if(s)return n;let c=new Map,l=new Map;for(let e of a)c.set(e,[]),l.set(e,[]);for(let e of i)c.get(e.succ).push(e),l.get(e.pred).push(e);let u=new Map,d=new Map;for(let e of o){let t=0;for(let n of c.get(e)??[])t=Math.max(t,d.get(n.pred)??0);u.set(e,t),d.set(e,t+(r.get(e)??0))}let f=Math.max(0,...a.map(e=>d.get(e)??0)),p=new Map,m=new Map;for(let e=o.length-1;e>=0;e--){let t=o[e],n=l.get(t)??[],i=f;n.length&&(i=Math.min(...n.map(e=>m.get(e.succ)??f))),p.set(t,i),m.set(t,i-(r.get(t)??0))}let h=1e-6,g=new Set;for(let e of a){let t=(m.get(e)??0)-(u.get(e)??0);Math.abs(t)<=h&&g.add(e)}let _=new Set;for(let e of i)_.add(e.pred),_.add(e.succ);for(let e of[...g])!_.has(e)&&(r.get(e)??0)===0&&g.delete(e);let y=new Set;for(let e of i)!g.has(e.pred)||!g.has(e.succ)||Math.abs((d.get(e.pred)??0)-(u.get(e.succ)??0))<=h&&y.add(`${e.pred}->${e.succ}`);return{criticalIds:g,criticalEdges:y}}function ae(e,t){if(!e.length)return[];let n=ne(e),r=e.map(e=>w(e.id)),{order:i,hasCycle:a}=E(r,n);if(a)return[];let o=re(e),s=new Map;for(let t of e)s.set(w(t.id),t);let c=new Map;for(let e of r)c.set(e,[]);for(let e of n)c.get(e.succ).push(e);let l=new Map,u=new Map;for(let t of e)l.set(w(t.id),t.start.getTime()),u.set(w(t.id),t.end.getTime());for(let e of i){let n=s.get(e);if(!n)continue;let r=t?te(l.get(e),u.get(e),t):u.get(e)-l.get(e),i=n.start.getTime();for(let n of c.get(e)??[]){let e=l.get(n.pred),a=u.get(n.pred),o;switch(n.type){case`ss`:o=e;break;case`ff`:o=t?C(a,r,t):a-r;break;case`sf`:o=t?C(e,r,t):e-r;break;default:o=a;break}o>i&&(i=o)}if(!o.has(e))if(t){let n=ee(i,t);l.set(e,n),u.set(e,S(n,r,t))}else l.set(e,i),u.set(e,i+r)}let d=[];for(let t of e){let e=w(t.id);if(o.has(e))continue;let n=l.get(e),r=u.get(e);(n!==t.start.getTime()||r!==t.end.getTime())&&d.push({id:e,start:new Date(n),end:new Date(r)})}return d}var oe={"gantt.column.taskName":`Task Name`,"gantt.column.start":`Start`,"gantt.column.end":`End`,"gantt.toolbar.prevPeriod":`Previous period`,"gantt.toolbar.nextPeriod":`Next period`,"gantt.toolbar.zoomIn":`Zoom in`,"gantt.toolbar.zoomOut":`Zoom out`,"gantt.toolbar.jumpToToday":`Jump to today`,"gantt.toolbar.today":`Today`,"gantt.toolbar.thisWeek":`This week`,"gantt.toolbar.thisMonth":`This month`,"gantt.toolbar.exportPdf":`Export PDF`,"gantt.toolbar.saveLayout":`Save layout`,"gantt.toolbar.showTaskList":`Show task list`,"gantt.toolbar.hideTaskList":`Hide task list`,"gantt.toolbar.viewMode":`Timeline granularity`,"gantt.toolbar.enterFullscreen":`Enter fullscreen`,"gantt.toolbar.exitFullscreen":`Exit fullscreen`,"gantt.toolbar.criticalPath":`Highlight critical path`,"gantt.toolbar.autoSchedule":`Auto-schedule dependencies`,"gantt.toolbar.exportPng":`Export as PNG`,"gantt.toolbar.undo":`Undo`,"gantt.toolbar.redo":`Redo`,"gantt.viewMode.day":`Day`,"gantt.viewMode.week":`Week`,"gantt.viewMode.month":`Month`,"gantt.viewMode.quarter":`Quarter`,"gantt.viewMode.year":`Year`,"gantt.row.expand":`Expand`,"gantt.row.collapse":`Collapse`,"gantt.row.locate":`Locate on timeline`,"gantt.aria.taskList":`Task list`,"gantt.tooltip.days":`d`,"gantt.menu.view":`View details`,"gantt.menu.edit":`Edit inline`,"gantt.menu.delete":`Delete`,"gantt.menu.addPredecessor":`Add predecessor…`,"gantt.menu.addSuccessor":`Add successor…`,"gantt.menu.removeDependency":`Remove dependency`,"gantt.menu.noCandidates":`No available tasks`,"gantt.linkType.fs":`Finish → Start`,"gantt.linkType.ss":`Start → Start`,"gantt.linkType.ff":`Finish → Finish`,"gantt.linkType.sf":`Start → Finish`,"gantt.linkEnd.start":`start`,"gantt.linkEnd.end":`end`,"gantt.conflict.title":`Schedule conflict`,"gantt.conflict.body":`This move conflicts with dependency constraints. Auto-reschedule {count} affected task(s)?`,"gantt.conflict.confirm":`Auto-reschedule`,"gantt.conflict.cancel":`Keep as is`,"gantt.resource.header":`Resource`,"gantt.resource.peak":`Peak`,"gantt.resource.over":`overloaded`,"gantt.resource.empty":`No tasks to allocate.`,"gantt.readOnly":`Read-only`,"gantt.readOnlyHint":`Editing is disabled for this view.`};function D(e,t){let n=oe[e]||e;if(t)for(let[e,r]of Object.entries(t))n=n.replace(`{{${e}}}`,String(r));return n}function se(){try{let e=(0,r.useObjectTranslation)();return{t:(t,n)=>{let r=e.t(t,n);return typeof r==`string`&&r!==t?r:D(t,n)},language:e.language}}catch{return{t:D,language:void 0}}}function ce(e){return 110}function le(e){return e<640?140:e<1024?220:320}function ue(e){return e>=280}function de(e){return e<640?32:40}var O=[`day`,`week`,`month`,`quarter`,`year`],fe={day:1,week:7,month:30.44,quarter:91.31,year:365.25},pe=1e3*60*60*24;function k(e,t){let n=new Date(e);return n.setHours(0,0,0,0),t===`week`?n.setDate(n.getDate()-(n.getDay()+6)%7):t===`month`?n.setDate(1):t===`quarter`?n.setMonth(Math.floor(n.getMonth()/3)*3,1):t===`year`&&n.setMonth(0,1),n}function me(e,t,n){let r=e.length-1,i=0;for(;i<r&&e[i+1]<t;)i++;let a=i;for(;a<r&&e[a]<n;)a++;return{start:i,end:a}}function A(e,t,n){let r=new Date(e);if(n===`day`)r.setDate(r.getDate()+t);else if(n===`week`)r.setDate(r.getDate()+t*7);else{let e=t*(n===`month`?1:n===`quarter`?3:12),i=r.getDate();r.setDate(1),r.setMonth(r.getMonth()+e);let a=new Date(r.getFullYear(),r.getMonth()+1,0).getDate();r.setDate(Math.min(i,a))}return r}function he(e,t,n,r=2){return new Promise(i=>{let a=new Blob([e],{type:`image/svg+xml;charset=utf-8`}),o=URL.createObjectURL(a),s=new Image;s.onload=()=>{let e=document.createElement(`canvas`);e.width=t*r,e.height=n*r;let a=e.getContext(`2d`);a&&(a.fillStyle=`#ffffff`,a.fillRect(0,0,e.width,e.height),a.scale(r,r),a.drawImage(s,0,0)),URL.revokeObjectURL(o),i(e)},s.onerror=()=>{URL.revokeObjectURL(o),i(null)},s.src=o})}function ge(e,t){let n=document.createElement(`a`);n.href=URL.createObjectURL(e),n.download=t,document.body.appendChild(n),n.click(),n.remove(),setTimeout(()=>URL.revokeObjectURL(n.href),1e3)}function _e(e,t,n){let r=e=>{let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n)&255;return t},i=`q ${t} 0 0 ${n} 0 0 cm /Im0 Do Q`,a=[],o=[],s=0,c=e=>{a.push(e),s+=e.length},l=()=>{o.push(s)};c(r(`%PDF-1.3
|
|
2
|
+
%ÿÿÿÿ
|
|
3
|
+
`)),l(),c(r(`1 0 obj
|
|
4
|
+
<< /Type /Catalog /Pages 2 0 R >>
|
|
5
|
+
endobj
|
|
6
|
+
`)),l(),c(r(`2 0 obj
|
|
7
|
+
<< /Type /Pages /Kids [3 0 R] /Count 1 >>
|
|
8
|
+
endobj
|
|
9
|
+
`)),l(),c(r(`3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${t} ${n}] /Resources << /XObject << /Im0 4 0 R >> >> /Contents 5 0 R >>\nendobj\n`)),l(),c(r(`4 0 obj\n<< /Type /XObject /Subtype /Image /Width ${t} /Height ${n} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${e.length} >>\nstream\n`)),c(e),c(r(`
|
|
10
|
+
endstream
|
|
11
|
+
endobj
|
|
12
|
+
`)),l(),c(r(`5 0 obj\n<< /Length ${i.length} >>\nstream\n${i}\nendstream\nendobj\n`));let u=s,d=`xref
|
|
13
|
+
0 6
|
|
14
|
+
0000000000 65535 f
|
|
15
|
+
`;for(let e of o)d+=`${String(e).padStart(10,`0`)} 00000 n \n`;return d+=`trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n${u}\n%%EOF\n`,c(r(d)),new Blob(a,{type:`application/pdf`})}function ve(e){let t=e.slice(e.indexOf(`,`)+1),n=atob(t),r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=n.charCodeAt(e);return r}var ye=`gantt-layout:`;function be(e){if(!e||typeof window>`u`)return null;try{let t=window.localStorage.getItem(ye+e);if(!t)return null;let n=JSON.parse(t),r=n.viewMode&&O.includes(n.viewMode)?n.viewMode:null;if(!r)return null;let i=typeof n.columnWidth==`number`&&isFinite(n.columnWidth)?n.columnWidth:null,a=typeof n.taskListWidth==`number`&&isFinite(n.taskListWidth)?n.taskListWidth:null;return{viewMode:r,columnWidth:i,taskListCollapsed:!!n.taskListCollapsed,taskListWidth:a}}catch{return null}}function xe(e,t){if(!(typeof window>`u`))try{window.localStorage.setItem(ye+e,JSON.stringify(t))}catch{}}function Se({tasks:e,viewMode:n,startDate:r,endDate:i,markers:a,onTaskClick:o,onTaskUpdate:c,onTaskDelete:d,onViewChange:f,onDependencyCreate:p,onDependencyDelete:m,onTaskReorder:h,className:g,inlineEdit:_=!1,autoSchedule:v=!1,rescheduleOnConflict:y=!1,criticalPathDefault:b=!1,workingCalendar:x,showBaselines:ee=!0,readOnly:te=!1,mobileReadOnly:S=!1,groupBy:C,ungroupedLabel:w=`Ungrouped`,defaultCollapsedDepth:T,persistLayoutKey:ne,onLayoutChange:re}){let{t:E,language:oe}=se(),D=oe||void 0,[ye,Se]=t.useState(new Date),Ce=t.useRef(null),{width:we}=(0,s.useResizeObserver)(Ce),j=we||(typeof window<`u`?window.innerWidth:1024),Te=j<640,M=te||S&&Te,N=M?void 0:c,Ee=M?void 0:d,P=M?void 0:p,De=M?void 0:m,Oe=M?void 0:h,ke=M?!1:_,Ae=M?!1:v,je=M?!1:y,F=de(j),Me=ce(j),Ne=t.useRef(void 0);Ne.current===void 0&&(Ne.current=be(ne));let Pe=Ne.current,[Fe,Ie]=t.useState(Pe?Pe.columnWidth:null),[Le,Re]=t.useState(Pe?Pe.taskListWidth??null:null),[I,ze]=t.useState(n&&O.includes(n)?n:Pe?.viewMode??`day`);t.useEffect(()=>{n&&O.includes(n)&&ze(n)},[n]);let Be=t.useRef(null),Ve=t.useRef(null),He=t.useRef(!0),[Ue,We]=t.useState(Pe?Pe.taskListCollapsed:!1),Ge=t.useRef(!1);t.useEffect(()=>{!Ge.current&&Te&&(We(!0),Ge.current=!0)},[Te]);let Ke=Math.max(160,j-200),L=Ue?0:Le==null?le(j):Math.max(160,Math.min(Le,Ke)),qe=t.useMemo(()=>{if(Fe!=null||i||e.length===0)return null;let t=r?new Date(r):new Date(Math.min(...e.map(e=>e.start.getTime()))),n=new Date(Math.max(...e.map(e=>e.end.getTime())));r||t.setDate(t.getDate()-7),n.setDate(n.getDate()+14),t=k(t,I),n.setHours(23,59,59,999);let a=Math.max(1,(n.getTime()-t.getTime())/pe),o=Math.max(0,j-L);if(o<=0)return null;let s=o/a*fe[I];if(s<=Me)return null;let c=Math.min(s,o*.6);return c>Me?c:null},[Fe,e,r,i,I,j,L,Me]),R=Fe??qe??Me,Je=R/fe[I],Ye=ue(L),[Xe,Ze]=t.useState(null),[Qe,$e]=t.useState({}),[et,tt]=t.useState(null),z=t.useMemo(()=>{if(!C)return e;let t=new Set;for(let n of e){let e=n.parent!=null&&n.parent!==``?String(n.parent):null;e&&t.add(e)}let n=new Map;for(let r of e){if(t.has(String(r.id)))continue;let e=C(r),i=e?String(e.key):`__ungrouped__`,a=e?e.label:w,o=n.get(i);o||(o={key:i,label:a,items:[]},n.set(i,o)),o.items.push(r)}let r=[];for(let e of n.values()){let t=`__group__${e.key}`,n=e.items[0];r.push({id:t,title:e.label,start:n.start,end:n.end,progress:0,type:`summary`,parent:null,data:{__group:!0}});for(let n of e.items)r.push({...n,parent:t})}return r},[C,e,w]),nt=t.useMemo(()=>{let e=new Set(z.map(e=>String(e.id))),t=new Map;for(let n of z){let r=n.parent!=null&&n.parent!==``?String(n.parent):null;if(r&&r!==String(n.id)&&e.has(r)){let e=t.get(r);e?e.push(n):t.set(r,[n])}}return t},[z]),rt=t.useMemo(()=>{let e=new Map;for(let t of z)e.set(String(t.id),t);return e},[z]),it=t.useCallback(e=>{let t=[],n=new Set,r=e=>{for(let i of nt.get(e)??[]){let e=String(i.id);n.has(e)||(n.add(e),t.push(i),r(e))}};return r(String(e)),t},[nt]),[B,at]=t.useState(null),ot=t.useRef(null);t.useEffect(()=>{ot.current=B},[B]);let st=t.useRef(!1),ct=t.useCallback(e=>{let t=pe,n=(e,t)=>tn.current?tn.current(e,t):A(e,t,I),r=new Date(e.originStart),i=new Date(e.originEnd);return e.mode===`move`?(r=n(e.originStart,e.unitDelta),i=new Date(e.originEnd.getTime()+(r.getTime()-e.originStart.getTime()))):e.mode===`resize-left`?(r=n(e.originStart,e.unitDelta),i.getTime()-r.getTime()<t&&(r=new Date(i.getTime()-t))):e.mode===`resize-right`&&(i=n(e.originEnd,e.unitDelta),i.getTime()-r.getTime()<t&&(i=new Date(r.getTime()+t))),{start:r,end:i}},[I]),lt=t.useRef(e);lt.current=e;let ut=t.useRef([]),dt=t.useRef([]),[ft,pt]=t.useState(0),V=t.useCallback(e=>{if(!N)return;let t=[];for(let{task:n,changes:r}of e){let e={},i={},a=!1;for(let t of Object.keys(r)){let o=r[t],s=n[t],c=o instanceof Date&&s instanceof Date?o.getTime()===s.getTime():o===s;e[t]=s,i[t]=o,c||(a=!0)}N(n,r),a&&t.push({taskId:String(n.id),before:e,after:i})}t.length&&(ut.current.push(t),dt.current=[],pt(e=>e+1))},[N]),[mt,ht]=t.useState(null),gt=t.useCallback(e=>{if(!je)return;let t=new Map;for(let{task:n,changes:r}of e)t.set(String(n.id),{start:r.start??n.start,end:r.end??n.end});let n=ae(lt.current.map(e=>{let n=t.get(String(e.id));return n?{...e,start:n.start,end:n.end}:e}),x).filter(e=>{let n=t.get(e.id);return!n||e.start.getTime()!==n.start.getTime()||e.end.getTime()!==n.end.getTime()});n.length&&ht(n)},[je,x]),_t=t.useCallback(()=>{if(!mt)return;let e=mt.map(e=>{let t=lt.current.find(t=>String(t.id)===e.id);return t?{task:t,changes:{start:e.start,end:e.end}}:null}).filter(Boolean);e.length&&V(e),ht(null)},[mt,V]),vt=t.useCallback((e,t)=>{if(N)for(let n of e){let e=lt.current.find(e=>String(e.id)===n.taskId);e&&N(e,t===`undo`?n.before:n.after)}},[N]),yt=t.useCallback(()=>{let e=ut.current.pop();e&&(vt(e,`undo`),dt.current.push(e),pt(e=>e+1))},[vt]),bt=t.useCallback(()=>{let e=dt.current.pop();e&&(vt(e,`redo`),ut.current.push(e),pt(e=>e+1))},[vt]),{canUndo:xt,canRedo:St}=t.useMemo(()=>({canUndo:ut.current.length>0,canRedo:dt.current.length>0}),[ft]);t.useEffect(()=>{if(!B)return;let t=e=>{let t=ot.current;if(!t)return;let n=Math.round((e.clientX-t.originClientX)/Math.max(R,1));n!==t.unitDelta&&at({...t,unitDelta:n})},n=()=>{let t=ot.current;if(t){if(t.unitDelta!==0){let n=e.find(e=>e.id===t.taskId);if(n&&N){let{start:e,end:r}=ct(t);if(t.group){let r=e.getTime()-t.originStart.getTime(),i=[n,...it(n.id)].map(e=>({task:e,changes:{start:new Date(e.start.getTime()+r),end:new Date(e.end.getTime()+r)}}));V(i),gt(i)}else{let t=[{task:n,changes:{start:e,end:r}}];V(t),gt(t)}}st.current=!0,window.setTimeout(()=>{st.current=!1},0)}at(null)}};return window.addEventListener(`pointermove`,t),window.addEventListener(`pointerup`,n),window.addEventListener(`pointercancel`,n),()=>{window.removeEventListener(`pointermove`,t),window.removeEventListener(`pointerup`,n),window.removeEventListener(`pointercancel`,n)}},[B,R,e,N,ct,it,V,gt]);let Ct=t.useCallback((e,t,n,r)=>{!N||e.data?.__group||(n.stopPropagation(),n.preventDefault(),at({taskId:e.id,mode:t,group:r?.group??!1,originStart:new Date(r?.originStart??e.start),originEnd:new Date(r?.originEnd??e.end),originClientX:n.clientX,unitDelta:0}))},[N]),[wt,Tt]=t.useState(null),Et=t.useRef(null);t.useEffect(()=>{Et.current=wt},[wt]),t.useEffect(()=>{if(!wt)return;let t=e=>{let t=Et.current;if(!t)return;let n=Math.min(100,Math.max(0,Math.round(t.originProgress+(e.clientX-t.originClientX)/Math.max(t.barWidth,1)*100)));n!==t.value&&Tt({...t,value:n})},n=()=>{let t=Et.current;if(t){if(t.value!==t.originProgress){let n=e.find(e=>e.id===t.taskId);n&&N&&V([{task:n,changes:{progress:t.value}}]),st.current=!0,window.setTimeout(()=>{st.current=!1},0)}Tt(null)}};return window.addEventListener(`pointermove`,t),window.addEventListener(`pointerup`,n),window.addEventListener(`pointercancel`,n),()=>{window.removeEventListener(`pointermove`,t),window.removeEventListener(`pointerup`,n),window.removeEventListener(`pointercancel`,n)}},[wt,e,N,V]);let Dt=t.useRef(null),[H,Ot]=t.useState(null),kt=t.useRef(null);t.useEffect(()=>{kt.current=H},[H]),t.useEffect(()=>{if(!H)return;let t=e=>{let t=Dt.current?.getBoundingClientRect();if(!t)return;let n=e.clientX-t.left,r=e.clientY-t.top;Ot(e=>e&&{...e,x:n,y:r})},n=()=>{let t=kt.current;if(t&&t.targetId!=null&&String(t.targetId)!==String(t.sourceId)&&P){let n=e.find(e=>String(e.id)===String(t.sourceId)),r=e.find(e=>String(e.id)===String(t.targetId)),i=t.targetEnd??`start`,a=`${t.sourceEnd===`end`?`f`:`s`}${i===`end`?`f`:`s`}`;n&&r&&P(n,r,a)}st.current=!0,window.setTimeout(()=>{st.current=!1},0),Ot(null)};return window.addEventListener(`pointermove`,t),window.addEventListener(`pointerup`,n),window.addEventListener(`pointercancel`,n),()=>{window.removeEventListener(`pointermove`,t),window.removeEventListener(`pointerup`,n),window.removeEventListener(`pointercancel`,n)}},[H,e,P]);let[At,jt]=t.useState(null),Mt=t.useRef(null);t.useEffect(()=>{if(!At)return;let e=e=>{Mt.current&&e.target instanceof Node&&Mt.current.contains(e.target)||jt(null)},t=e=>{e.key===`Escape`&&jt(null)};return window.addEventListener(`pointerdown`,e,!0),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e,!0),window.removeEventListener(`keydown`,t)}},[At]);let[U,Nt]=t.useState(null),Pt=t.useRef(null);t.useEffect(()=>{if(!U)return;let e=e=>{Pt.current&&e.target instanceof Node&&Pt.current.contains(e.target)||Nt(null)},t=e=>{e.key===`Escape`&&Nt(null)};return window.addEventListener(`pointerdown`,e,!0),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e,!0),window.removeEventListener(`keydown`,t)}},[U]);let[W,Ft]=t.useState(null),It=t.useRef(null);t.useEffect(()=>{if(!W)return;let e=e=>{It.current&&e.target instanceof Node&&It.current.contains(e.target)||Ft(null)},t=e=>{e.key===`Escape`&&Ft(null)};return window.addEventListener(`pointerdown`,e,!0),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e,!0),window.removeEventListener(`keydown`,t)}},[W]);let[Lt,Rt]=t.useState(null),zt=!!(o||N||P||Ee),Bt=t.useCallback((e,t)=>{t.preventDefault(),t.stopPropagation(),Rt(e.id),zt&&jt({x:t.clientX,y:t.clientY,taskId:e.id})},[zt]),Vt=t.useCallback((e,t,n,r)=>{r.preventDefault(),r.stopPropagation(),!(!P&&!De)&&Nt({x:r.clientX,y:r.clientY,sourceId:e,targetId:t,type:n})},[P,De]),[Ht,Ut]=t.useState(()=>new Set),Wt=t.useCallback(e=>{Ut(t=>{let n=new Set(t),r=String(e);return n.has(r)?n.delete(r):n.add(r),n})},[]),Gt=t.useRef(!1);t.useEffect(()=>{if(Gt.current||T==null||z.length===0)return;Gt.current=!0;let e=new Map(z.map(e=>[String(e.id),e])),t=new Set;for(let n of z){let r=n.parent!=null&&n.parent!==``?String(n.parent):null;r&&r!==String(n.id)&&e.has(r)&&t.add(r)}let n=t=>{let n=0,r=new Set([String(t.id)]),i=t.parent!=null&&t.parent!==``?e.get(String(t.parent)):void 0;for(;i&&!r.has(String(i.id));)n+=1,r.add(String(i.id)),i=i.parent!=null&&i.parent!==``?e.get(String(i.parent)):void 0;return n},r=new Set;for(let e of z){let i=String(e.id);t.has(i)&&n(e)>=T&&r.add(i)}r.size&&Ut(e=>e.size?e:r)},[T,z]);let G=t.useMemo(()=>{let e=new Set(z.map(e=>String(e.id))),t=new Map,n=[];for(let r of z){let i=r.parent!=null&&r.parent!==``?String(r.parent):null;if(i&&i!==String(r.id)&&e.has(i)){let e=t.get(i);e?e.push(r):t.set(i,[r])}else n.push(r)}let r=new Map,i=(e,n)=>{let a=String(e.id),o=r.get(a);if(o)return o;let s=t.get(a)??[],c;if(!s.length||n.has(a))c={start:e.start,end:e.end,progress:e.progress};else{n.add(a);let e=null,t=null,r=0,o=0;for(let a of s){let s=i(a,n);(!e||s.start<e)&&(e=s.start),(!t||s.end>t)&&(t=s.end);let c=Math.max(s.end.getTime()-s.start.getTime(),pe);r+=c*s.progress,o+=c}n.delete(a),c={start:e,end:t,progress:o?r/o:0}}return r.set(a,c),c},a=[],o=new Set,s=e=>{for(let n of t.get(String(e.id))??[])o.has(String(n.id))||(o.add(String(n.id)),s(n))},c=(e,n)=>{let r=String(e.id);if(o.has(r))return;o.add(r);let l=t.get(r)??[],u=l.length>0,d=u||e.type===`summary`,f=u?i(e,new Set):{start:e.start,end:e.end,progress:e.progress},p=!d&&(e.type===`milestone`||e.end.getTime()<=e.start.getTime());if(a.push({task:e,depth:n,hasChildren:u,isSummary:d,isMilestone:p,...f}),u)if(Ht.has(r))s(e);else for(let e of l)c(e,n+1)};for(let e of n)c(e,0);for(let e of z)o.has(String(e.id))||c(e,0);return a},[z,Ht]),Kt=t.useCallback(e=>{if(e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement)return;if((e.ctrlKey||e.metaKey)&&(e.key===`z`||e.key===`Z`)){e.preventDefault(),e.shiftKey?bt():yt();return}if((e.ctrlKey||e.metaKey)&&(e.key===`y`||e.key===`Y`)){e.preventDefault(),bt();return}if(!G.length)return;let t=Lt==null?-1:G.findIndex(e=>String(e.task.id)===String(Lt));if(e.key===`ArrowDown`||e.key===`ArrowUp`){e.preventDefault();let n=e.key===`ArrowDown`?Math.min(G.length-1,t+1):Math.max(0,t<=0?0:t-1);Rt(G[n].task.id);let r=X.current;if(r){let e=n*F;e<r.scrollTop?r.scrollTop=e:e+F>r.scrollTop+r.clientHeight&&(r.scrollTop=e+F-r.clientHeight)}return}if(t<0)return;let n=G[t];e.key===`Enter`?(e.preventDefault(),o?.(n.task)):e.key===`Delete`||e.key===`Backspace`?Ee&&(e.preventDefault(),Ee(n.task)):(e.key===`ArrowRight`&&n.hasChildren&&Ht.has(String(n.task.id))||e.key===`ArrowLeft`&&n.hasChildren&&!Ht.has(String(n.task.id)))&&(e.preventDefault(),Wt(n.task.id))},[G,Lt,o,Ee,Ht,Wt,F,yt,bt]),K=t.useMemo(()=>{let t=r?new Date(r):new Date,n=i?new Date(i):new Date;return!r&&e.length>0&&(t=new Date(Math.min(...e.map(e=>e.start.getTime()))),t.setDate(t.getDate()-7)),!i&&e.length>0&&(n=new Date(Math.max(...e.map(e=>e.end.getTime()))),n.setDate(n.getDate()+14)),t=k(t,I),n.setHours(23,59,59,999),{start:t,end:n}},[r,i,e,I]),qt=I===`day`&&!!x&&(!!x.skipWeekends||!!(x.holidays&&x.holidays.size)),Jt=t.useCallback(e=>{if(!x)return!0;if(x.skipWeekends){let t=e.getDay();if(t===0||t===6)return!1}if(x.holidays&&x.holidays.size){let t=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`;if(x.holidays.has(t))return!1}return!0},[x]),q=t.useMemo(()=>{let e=[],t=new Date(K.start);for(;t<=K.end;){let n=A(t,1,I);if(qt&&!Jt(t)){t=n;continue}let r=(n.getTime()-t.getTime())/pe*Je,i,a;I===`day`?(i=String(t.getDate()),a=t.toLocaleDateString(D,{weekday:`narrow`})):i=I===`week`?t.toLocaleDateString(D,{month:`numeric`,day:`numeric`}):I===`month`?t.toLocaleDateString(D,{month:`short`}):I===`quarter`?`Q${Math.floor(t.getMonth()/3)+1}`:String(t.getFullYear()),e.push({date:new Date(t),label:i,sublabel:a,isWeekend:I===`day`&&(t.getDay()===0||t.getDay()===6),width:r}),t=n}return e},[K,I,Je,D,qt,Jt]),J=t.useMemo(()=>{let e=Array(q.length+1),t=0;for(let n=0;n<q.length;n++)e[n]=t,t+=q[n].width;return e[q.length]=t,e},[q]),Yt=J[J.length-1],Xt=t.useMemo(()=>q.map(e=>e.date.getTime()),[q]),Zt=t.useMemo(()=>q.map(e=>A(e.date,1,I).getTime()-e.date.getTime()),[q,I]),Y=t.useCallback(e=>{let t=q.length;if(t===0)return 0;let n=e.getTime(),r=0,i=t-1,a=0;for(;r<=i;){let e=r+i>>1;Xt[e]<=n?(a=e,r=e+1):i=e-1}let o=Zt[a]||864e5,s=(n-Xt[a])/o;return qt&&(s=Math.max(0,Math.min(s,1))),J[a]+s*q[a].width},[q,Xt,Zt,J,qt]),Qt=t.useCallback(e=>{let t=q.length;if(t===0)return new Date(K.start);let n=0,r=t-1,i=0;for(;n<=r;){let t=n+r>>1;J[t]<=e?(i=t,n=t+1):r=t-1}let a=q[i].width||1,o=(e-J[i])/a;return new Date(Xt[i]+o*(Zt[i]||864e5))},[q,Xt,Zt,J,K]),$t=t.useCallback(e=>{let t=X.current;Ve.current==null&&t&&t.clientWidth>0&&(Ve.current=Qt(t.scrollLeft)),Be.current=Ve.current,He.current=!0,ze(e),f?.(e)},[f,Qt]);t.useLayoutEffect(()=>{let e=Be.current;if(e==null)return;Be.current=null;let t=X.current;if(!t||t.clientWidth===0)return;let n=Math.max(0,t.scrollWidth-t.clientWidth),r=Math.max(0,Math.min(Math.round(Y(k(e,I))),n));t.scrollLeft!==r&&(t.scrollLeft=r)},[I,Y]);let en=t.useCallback((e,t)=>{let n=q.length;if(n===0||t===0)return new Date(e);let r=e.getTime(),i=0,a=n-1,o=0;for(;i<=a;){let e=i+a>>1;Xt[e]<=r?(o=e,i=e+1):a=e-1}let s=Math.min(n-1,Math.max(0,o+t)),c=r-Xt[o];return new Date(Xt[s]+c)},[q,Xt]),tn=t.useRef(null);tn.current=qt?en:null;let nn=t.useMemo(()=>{let e=[],t=I===`year`?`decade`:I===`month`||I===`quarter`?`year`:`month`,n=0;for(let r of q){let i=r.date.getFullYear(),a=Math.floor(i/10)*10,o=t===`decade`?String(a):t===`year`?String(i):`${i}-${r.date.getMonth()}`,s=e[e.length-1];s&&s.key===o?s.width+=r.width:e.push({key:o,label:t===`decade`?`${a}s`:t===`year`?String(i):r.date.toLocaleDateString(D,{month:`short`,year:`numeric`}),width:r.width,offset:n}),n+=r.width}return e},[q,I,D]),rn=t.useMemo(()=>(a??[]).map((e,t)=>{let n=e.date instanceof Date?e.date:new Date(e.date);return{index:t,label:e.label,color:e.color||`hsl(var(--primary))`,left:Math.round(Y(n)),valid:!isNaN(n.getTime())&&n>=K.start&&n<=K.end}}).filter(e=>e.valid),[a,K,Y]),an=t.useRef(null),on=t.useRef(null),sn=t.useRef(null),X=t.useRef(null);t.useEffect(()=>{let e=X.current;if(!e)return;let t=()=>{He.current=!1},n=new Set([`ArrowLeft`,`ArrowRight`,`ArrowUp`,`ArrowDown`,`PageUp`,`PageDown`,`Home`,`End`,` `,`Spacebar`]),r=e=>{n.has(e.key)&&t()};return e.addEventListener(`wheel`,t,{passive:!0}),e.addEventListener(`touchstart`,t,{passive:!0}),e.addEventListener(`pointerdown`,t,{passive:!0}),e.addEventListener(`keydown`,r),()=>{e.removeEventListener(`wheel`,t),e.removeEventListener(`touchstart`,t),e.removeEventListener(`pointerdown`,t),e.removeEventListener(`keydown`,r)}},[]);let[cn,ln]=t.useState(null),un=t.useRef([]),dn=t.useRef(null),[fn,pn]=t.useState({top:0,left:0}),[mn,hn]=t.useState({width:4e3,height:600}),gn=t.useCallback(()=>{let e=X.current;if(!e)return;let t=e.clientWidth||4e3,n=e.clientHeight||600;hn(e=>e.width===t&&e.height===n?e:{width:t,height:n})},[]);t.useLayoutEffect(()=>{gn();let e=X.current;if(!e||typeof ResizeObserver>`u`)return;let t=new ResizeObserver(gn);return t.observe(e),()=>t.disconnect()},[gn]);let _n=t.useMemo(()=>me(J,fn.left-240,fn.left+mn.width+240),[J,fn.left,mn.width]),vn=t.useMemo(()=>{let e=nn.map(e=>e.offset);return e.push(Yt),e},[nn,Yt]),yn=t.useMemo(()=>me(vn,fn.left-240,fn.left+mn.width+240),[vn,fn.left,mn.width]),Z=t.useMemo(()=>({startIdx:Math.max(0,Math.floor(fn.top/F)-6),endIdx:Math.min(G.length,Math.ceil((fn.top+mn.height)/F)+6)}),[fn.top,mn.height,F,G.length]),bn=G.length*F,[xn,Sn]=t.useState(!1);t.useEffect(()=>{let e=()=>Sn(!!document.fullscreenElement);return document.addEventListener(`fullscreenchange`,e),()=>document.removeEventListener(`fullscreenchange`,e)},[]);let Cn=t.useCallback(()=>{let e=Ce.current;e&&(document.fullscreenElement?document.exitFullscreen?.():e.requestFullscreen?.())},[]),wn=t.useRef(null),Tn=t.useCallback(e=>{if(e.touches.length===2){let t=e.touches[0].clientX-e.touches[1].clientX,n=e.touches[0].clientY-e.touches[1].clientY;wn.current={baseDistance:Math.max(1,Math.sqrt(t*t+n*n)),baseColumn:R}}},[R]),En=t.useCallback(e=>{if(e.touches.length!==2||!wn.current)return;let t=e.touches[0].clientX-e.touches[1].clientX,n=e.touches[0].clientY-e.touches[1].clientY,r=Math.max(1,Math.sqrt(t*t+n*n))/wn.current.baseDistance;Ie(Math.max(15,Math.min(120,Math.round(wn.current.baseColumn*r))))},[]),Dn=t.useCallback(()=>{wn.current=null},[]),Q=t.useMemo(()=>{let e=new Date;return e<K.start||e>K.end?null:Math.round(Y(e))},[K,Y]),On=t.useCallback(()=>{if(Q==null||!X.current)return;let e=Math.max(0,Q-X.current.clientWidth/2);X.current.scrollTo({left:e,behavior:`smooth`})},[Q]),kn=t.useRef(!1);t.useEffect(()=>{if(kn.current||e.length===0)return;let t=window.requestAnimationFrame(()=>{let t=X.current;if(!t||t.clientWidth===0)return;let n=Q;if(n==null){let t=new Date(Math.min(...e.map(e=>e.start.getTime())));n=Math.round(Y(t))}t.scrollLeft=Math.max(0,n-t.clientWidth/2),kn.current=!0});return()=>window.cancelAnimationFrame(t)},[e,Q,Y]);let An=t.useCallback((e,t=`left`)=>{let n=X.current;if(!n||e<K.start||e>K.end)return!1;let r=Math.round(Y(e)),i=t===`center`?r-n.clientWidth/2:r-24;return n.scrollTo({left:Math.max(0,i),behavior:`smooth`}),!0},[K,Y]),jn=t.useCallback((e,t,n)=>{let r=X.current;if(!r)return;let i=Y(e),a=Y(t),o=Math.max(0,r.scrollWidth-r.clientWidth),s=Math.min(96,r.clientWidth*.15),c=a-i<=r.clientWidth-s?(i+a)/2-r.clientWidth/2:i-s,l=Math.max(0,Math.min(c,o));un.current.forEach(e=>window.clearTimeout(e)),un.current=[],dn.current?.(),dn.current=null,ln(null);let u=()=>{if(n==null)return;let e=window.requestAnimationFrame(()=>{ln(n),un.current.push(window.setTimeout(()=>ln(e=>e===n?null:e),1500))});dn.current=()=>window.cancelAnimationFrame(e)},d=Math.abs(r.scrollLeft-l)>2;if(r.scrollTo({left:l,behavior:`smooth`}),!d){u();return}let f=`onscrollend`in r,p=!1,m=()=>{p||(p=!0,r.removeEventListener(`scrollend`,m),u())};r.addEventListener(`scrollend`,m),un.current.push(window.setTimeout(m,f?1500:500)),dn.current=()=>r.removeEventListener(`scrollend`,m)},[Y]);t.useEffect(()=>()=>{un.current.forEach(e=>window.clearTimeout(e)),dn.current?.()},[]);let Mn=t.useCallback(()=>An(k(new Date,`week`)),[An]),Nn=t.useCallback(()=>An(k(new Date,`month`)),[An]),Pn=e=>{let t=e.currentTarget;!He.current&&t.clientWidth>0&&(Ve.current=Qt(t.scrollLeft)),an.current&&(an.current.scrollLeft=t.scrollLeft),on.current&&on.current.scrollTop!==t.scrollTop&&(on.current.scrollTop=t.scrollTop),pn(e=>e.top===t.scrollTop&&e.left===t.scrollLeft?e:{top:t.scrollTop,left:t.scrollLeft}),gn()},Fn=e=>{let t=e.currentTarget,n=X.current;n&&n.scrollTop!==t.scrollTop&&(n.scrollTop=t.scrollTop),pn(e=>e.top===t.scrollTop?e:{...e,top:t.scrollTop})},In=(e,t)=>{let n=Y(e);return{left:n,width:Math.max(Y(t)-n,Je,3)}},Ln=B?.group?B.taskId:null,Rn=t.useMemo(()=>{if(Ln==null)return null;let e=new Set([String(Ln)]);for(let t of it(Ln))e.add(String(t.id));return e},[Ln,it]),zn=t.useMemo(()=>{if(!B||B.group)return null;let e=new Set,t=new Set,n=rt.get(String(B.taskId));for(;n&&n.parent!=null&&n.parent!==``;){let r=String(n.parent);if(t.has(r)||!rt.has(r))break;t.add(r),e.add(r),n=rt.get(r)}return e.size?e:null},[B,rt]),Bn=e=>{if(B){if(Rn?.has(String(e.task.id))){let t=ct(B).start.getTime()-B.originStart.getTime();return In(new Date(e.start.getTime()+t),new Date(e.end.getTime()+t))}if(!e.isSummary&&B.taskId===e.task.id){let e=ct(B);return In(e.start,e.end)}if(e.isSummary&&zn?.has(String(e.task.id))){let t=ct(B),n=String(B.taskId),r=null,i=null;for(let a of it(e.task.id)){if((nt.get(String(a.id))??[]).length!==0)continue;let e=String(a.id)===n?t.start:a.start,o=String(a.id)===n?t.end:a.end;(!r||e<r)&&(r=e),(!i||o>i)&&(i=o)}if(r&&i)return In(r,i)}}return In(e.start,e.end)},Vn=t.useMemo(()=>{let e=new Map;G.forEach((t,n)=>e.set(String(t.task.id),n));let t=[];return G.forEach(({task:n},r)=>{for(let i of n.dependencies??[]){let a=typeof i==`object`&&!!i,o=a?i.id:i;if(o==null||o===``)continue;let s=e.get(String(o));if(s==null||s===r)continue;let c=a?i.type:void 0,l=c===`ss`||c===`ff`||c===`sf`?c:`fs`;t.push({key:`${String(o)}->${String(n.id)}:${l}`,sourceId:o,targetId:n.id,type:l,sourceIndex:s,targetIndex:r})}}),t},[G]),Hn=Math.round(F*.2),Un=F-Hn*2,Wn=Math.max(Math.round(F*.4),12),Gn=Wn*Math.SQRT2/2,Kn=Un,qn=Hn,Jn=Math.max(3,Math.round(F*.13)),Yn=F-Jn-1,Xn=`rgba(100, 116, 139, 0.35)`,Zn=`rgba(100, 116, 139, 0.6)`,Qn=e=>{let t=G[e.sourceIndex],n=G[e.targetIndex];if(!t||!n)return null;let r=Bn(t),i=Bn(n),a=e=>e.isSummary?qn+Kn/2:F/2,o=e.sourceIndex*F+a(t),s=e.targetIndex*F+a(n),c=e.type===`fs`||e.type===`ff`,l=e.type===`ff`||e.type===`sf`,u=t.isMilestone?r.left+(c?Gn:-Gn):c?r.left+r.width:r.left,d=n.isMilestone?i.left+(l?Gn:-Gn):l?i.left+i.width:i.left,f=u+(c?10:-10),p=d+(l?10:-10),m=Math.round,h=[`M ${m(u)} ${m(o)}`,`L ${m(f)} ${m(o)}`];if(l?f>=p:f<=p)h.push(`L ${m(f)} ${m(s)}`,`L ${m(d)} ${m(s)}`);else{let t=s>=o?(e.sourceIndex+1)*F:e.sourceIndex*F;h.push(`L ${m(f)} ${m(t)}`,`L ${m(p)} ${m(t)}`,`L ${m(p)} ${m(s)}`,`L ${m(d)} ${m(s)}`)}return h.join(` `)},$n=B?.taskId??et,[er,tr]=t.useState(b),nr=t.useMemo(()=>er?ie(e,x):null,[er,e,x]),rr=t.useCallback(e=>nr?.criticalIds.has(String(e))??!1,[nr]),$=`#dc2626`,ir=t.useCallback(()=>{if(!N)return;let t=ae(e,x),n=[];for(let r of t){let t=e.find(e=>String(e.id)===r.id);t&&n.push({task:t,changes:{start:r.start,end:r.end}})}V(n)},[e,N,x,V]),ar=t.useCallback(()=>{if(typeof document>`u`||!e.length)return null;let t=e=>String(e).replace(/[&<>"]/g,e=>({"&":`&`,"<":`<`,">":`>`,'"':`"`})[e]),n=Math.max(L,200),r=Math.ceil(n+Yt),i=Math.ceil(36+G.length*F),a=nr?.criticalEdges??null,o=[];o.push(`<rect x="0" y="0" width="${r}" height="${i}" fill="#ffffff"/>`),o.push(`<rect x="0" y="0" width="${r}" height="36" fill="#f8fafc"/>`),o.push(`<g transform="translate(${n},0)" font-family="sans-serif" font-size="10" fill="#475569">`),nn.forEach(e=>{o.push(`<line x1="${e.offset.toFixed(1)}" y1="0" x2="${e.offset.toFixed(1)}" y2="36" stroke="#e2e8f0"/>`),o.push(`<text x="${(e.offset+e.width/2).toFixed(1)}" y="12" text-anchor="middle" font-weight="600">${t(e.label)}</text>`)}),q.forEach((e,n)=>{let r=J[n];o.push(`<line x1="${r.toFixed(1)}" y1="18" x2="${r.toFixed(1)}" y2="${i}" stroke="#eef2f7"/>`),o.push(`<text x="${(r+e.width/2).toFixed(1)}" y="30" text-anchor="middle" fill="#1f2937">${t(e.label)}</text>`)}),o.push(`</g>`),o.push(`<line x1="0" y1="18" x2="${r}" y2="18" stroke="#e2e8f0"/>`),o.push(`<line x1="0" y1="36" x2="${r}" y2="36" stroke="#cbd5e1"/>`),o.push(`<line x1="${n}" y1="0" x2="${n}" y2="${i}" stroke="#cbd5e1"/>`),o.push(`<g transform="translate(0,36)" font-family="sans-serif" font-size="11" fill="#1f2937">`),G.forEach((e,r)=>{let i=r*F;o.push(`<line x1="0" y1="${(i+F).toFixed(1)}" x2="${n}" y2="${(i+F).toFixed(1)}" stroke="#f1f5f9"/>`);let a=8+e.depth*14,s=Math.max(4,Math.floor((n-a)/6.5)),c=e.task.title.length>s?e.task.title.slice(0,s-1)+`…`:e.task.title,l=e.isSummary?` font-weight="600"`:``;o.push(`<text x="${a}" y="${(i+F/2+4).toFixed(1)}"${l}>${t(c)}</text>`)}),o.push(`</g>`),o.push(`<g transform="translate(${n},36)" font-family="sans-serif" font-size="9">`),G.forEach((e,t)=>{let n=t*F,{left:r,width:i}=In(e.start,e.end),a=rr(e.task.id),s=a?` stroke="${$}" stroke-width="2"`:``;if(ee&&e.task.baselineStart&&e.task.baselineEnd){let t=In(e.task.baselineStart,e.task.baselineEnd);o.push(`<rect x="${t.left.toFixed(1)}" y="${(n+Yn).toFixed(1)}" width="${Math.max(2,t.width).toFixed(1)}" height="${Jn}" rx="1" fill="${Xn}" stroke="${Zn}"/>`)}if(e.isMilestone){let t=r,i=n+F/2,s=Wn/2,c=a?$:e.task.color||`#3b82f6`;o.push(`<polygon points="${t},${i-s} ${t+s},${i} ${t},${i+s} ${t-s},${i}" fill="${c}"/>`)}else if(e.isSummary){let t=e.task.color||`#64748b`;o.push(`<rect x="${r.toFixed(1)}" y="${(n+qn).toFixed(1)}" width="${i.toFixed(1)}" height="${Kn}" rx="3" fill="${t}"${s}/>`);let a=i*Math.min(100,Math.max(0,e.progress))/100;o.push(`<rect x="${r.toFixed(1)}" y="${(n+qn).toFixed(1)}" width="${a.toFixed(1)}" height="${Kn}" rx="3" fill="rgba(0,0,0,0.2)"/>`)}else{let t=e.task.color||`#3b82f6`;o.push(`<rect x="${r.toFixed(1)}" y="${(n+Hn).toFixed(1)}" width="${i.toFixed(1)}" height="${Un}" rx="3" fill="${t}"${s}/>`);let a=i*Math.min(100,Math.max(0,e.progress))/100;o.push(`<rect x="${r.toFixed(1)}" y="${(n+Hn).toFixed(1)}" width="${a.toFixed(1)}" height="${Un}" rx="3" fill="rgba(0,0,0,0.18)"/>`),i>=24&&o.push(`<text x="${(r+i/2).toFixed(1)}" y="${(n+F/2+3).toFixed(1)}" text-anchor="middle" fill="#ffffff">${Math.round(e.progress)}%</text>`)}}),Vn.forEach(e=>{let t=Qn(e);if(!t)return;let n=a?.has(`${String(e.sourceId)}->${String(e.targetId)}`)??!1,r=n?$:`#94a3b8`;o.push(`<path d="${t}" fill="none" stroke="${r}" stroke-width="${n?2:1.5}"/>`)}),Q!=null&&o.push(`<line x1="${Q.toFixed(1)}" y1="0" x2="${Q.toFixed(1)}" y2="${G.length*F}" stroke="#ef4444" stroke-width="1.5"/>`);let s=G.length*F;return rn.forEach(e=>{let n=/var\(/.test(e.color)?`#6366f1`:e.color;if(o.push(`<line x1="${e.left.toFixed(1)}" y1="0" x2="${e.left.toFixed(1)}" y2="${s}" stroke="${t(n)}" stroke-width="1.5"/>`),e.label){let r=e.label.length*6+8;o.push(`<rect x="${(e.left-r/2).toFixed(1)}" y="0" width="${r}" height="14" rx="2" fill="${t(n)}"/>`),o.push(`<text x="${e.left.toFixed(1)}" y="10" text-anchor="middle" font-size="9" font-weight="600" fill="#ffffff">${t(e.label)}</text>`)}}),o.push(`</g>`),{svg:`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${i}" viewBox="0 0 ${r} ${i}">${o.join(``)}</svg>`,W:r,H:i}},[e,G,Vn,Qn,In,rr,nr,q,J,Yt,L,F,Hn,Un,qn,Kn,Wn,Q,I,ee,Yn,Jn,Xn,Zn,rn,nn]),or=t.useCallback(async()=>{let e=ar();if(!e)return;let t=await he(e.svg,e.W,e.H);t&&t.toBlob(e=>{e&&ge(e,`gantt-${I}.png`)},`image/png`)},[ar,I]),sr=t.useCallback(async()=>{let e=ar();if(!e)return;let t=await he(e.svg,e.W,e.H);t&&ge(_e(ve(t.toDataURL(`image/jpeg`,.92)),t.width,t.height),`gantt-${I}.pdf`)},[ar,I]),[cr,lr]=t.useState(!1),ur=t.useCallback(()=>{let e={viewMode:I,columnWidth:Fe,taskListCollapsed:Ue,taskListWidth:Le};ne&&xe(ne,e),re?.(e),lr(!0)},[I,Fe,Ue,Le,ne,re]);return t.useEffect(()=>{if(!cr)return;let e=setTimeout(()=>lr(!1),1500);return()=>clearTimeout(e)},[cr]),(0,u.jsxs)(`div`,{ref:Ce,className:(0,s.cn)(`flex flex-col h-full bg-background overflow-hidden min-w-0`,g),"data-readonly":M?`true`:void 0,"data-mobile-readonly":S&&Te?`true`:void 0,children:[(0,u.jsx)(`style`,{children:`
|
|
16
|
+
.gantt-resize-handle:hover { background-color: rgba(255, 255, 255, 0.4); }
|
|
17
|
+
.gantt-bar-hover:hover { filter: brightness(1.1); }
|
|
18
|
+
.gantt-locate-btn { opacity: 0; transition: opacity 0.15s ease; }
|
|
19
|
+
.group\\/task-row:hover .gantt-locate-btn { opacity: 0.6; }
|
|
20
|
+
.gantt-locate-btn:hover, .gantt-locate-btn:focus-visible { opacity: 1; }
|
|
21
|
+
/* 定位闪烁: blink the located bar 3× with a thick ring + colored glow so
|
|
22
|
+
it's hard to miss. The ring is an outline (not box-shadow) and the glow
|
|
23
|
+
is a drop-shadow *filter* — both stay clear of the critical-path bar's
|
|
24
|
+
inline box-shadow, which they'd otherwise clobber. */
|
|
25
|
+
@keyframes gantt-flash {
|
|
26
|
+
0%, 25%, 50%, 100% {
|
|
27
|
+
outline-color: rgba(37, 99, 235, 0);
|
|
28
|
+
filter: drop-shadow(0 0 0 rgba(37, 99, 235, 0));
|
|
29
|
+
}
|
|
30
|
+
12%, 37%, 62% {
|
|
31
|
+
outline-color: rgba(37, 99, 235, 1);
|
|
32
|
+
filter: drop-shadow(0 0 9px rgba(37, 99, 235, 0.9));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
.gantt-flash {
|
|
36
|
+
outline: 3px solid transparent;
|
|
37
|
+
outline-offset: 3px;
|
|
38
|
+
border-radius: 2px;
|
|
39
|
+
animation: gantt-flash 1.5s ease-in-out;
|
|
40
|
+
}
|
|
41
|
+
@media (min-width: 640px) {
|
|
42
|
+
.gantt-sm-h50 { height: 50px; }
|
|
43
|
+
.gantt-sm-w20 { width: 80px; }
|
|
44
|
+
.gantt-sm-hidden { display: none; }
|
|
45
|
+
}
|
|
46
|
+
/* Persistent, grabbable timeline scrollbars. macOS (and iOS) default to
|
|
47
|
+
overlay scrollbars that collapse to 0px and auto-hide, so the
|
|
48
|
+
timeline's vertical scrollbar was nearly impossible to find. Defining
|
|
49
|
+
::-webkit-scrollbar opts this pane into a classic, always-visible bar
|
|
50
|
+
regardless of the OS overlay preference. The thumb gets a min size so
|
|
51
|
+
that with thousands of virtualized rows (scrollHeight in the hundreds
|
|
52
|
+
of thousands of px) it never shrinks to an un-grabbable sliver. Scoped
|
|
53
|
+
to the gantt pane so the host app's own scrollbars are untouched, and
|
|
54
|
+
themed with neutral rgba (not theme utilities, which don't always
|
|
55
|
+
reach a consuming app) so it's visible on any background. */
|
|
56
|
+
/* Firefox (and any engine without ::-webkit-scrollbar) only: the
|
|
57
|
+
standard props. We must NOT set these unconditionally — modern Chrome
|
|
58
|
+
now honors scrollbar-width and, when it's present, IGNORES the
|
|
59
|
+
::-webkit-scrollbar rule below, falling back to the 0px auto-hiding
|
|
60
|
+
overlay bar we're trying to replace. */
|
|
61
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
62
|
+
[data-testid="gantt-timeline"] {
|
|
63
|
+
scrollbar-width: thin;
|
|
64
|
+
scrollbar-color: rgba(130,130,130,0.55) transparent;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
[data-testid="gantt-timeline"]::-webkit-scrollbar {
|
|
68
|
+
width: 14px;
|
|
69
|
+
height: 14px;
|
|
70
|
+
}
|
|
71
|
+
[data-testid="gantt-timeline"]::-webkit-scrollbar-track {
|
|
72
|
+
background: transparent;
|
|
73
|
+
}
|
|
74
|
+
[data-testid="gantt-timeline"]::-webkit-scrollbar-thumb {
|
|
75
|
+
background-color: rgba(130,130,130,0.55);
|
|
76
|
+
border-radius: 8px;
|
|
77
|
+
border: 3px solid transparent;
|
|
78
|
+
background-clip: padding-box;
|
|
79
|
+
min-height: 40px;
|
|
80
|
+
min-width: 40px;
|
|
81
|
+
}
|
|
82
|
+
[data-testid="gantt-timeline"]::-webkit-scrollbar-thumb:hover {
|
|
83
|
+
background-color: rgba(110,110,110,0.85);
|
|
84
|
+
}
|
|
85
|
+
[data-testid="gantt-timeline"]::-webkit-scrollbar-corner {
|
|
86
|
+
background: transparent;
|
|
87
|
+
}
|
|
88
|
+
/* The task-list pane scrolls in lockstep with the timeline, so its own
|
|
89
|
+
vertical scrollbar (butted against the divider) was a confusing second
|
|
90
|
+
bar. Hide it — the pane stays wheel/drag-scrollable and synced. */
|
|
91
|
+
.gantt-task-list::-webkit-scrollbar { width: 0; height: 0; }
|
|
92
|
+
.gantt-task-list { scrollbar-width: none; }
|
|
93
|
+
`}),(0,u.jsxs)(`div`,{className:`flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 p-2 border-b bg-card`,children:[(0,u.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,"aria-label":E(`gantt.toolbar.prevPeriod`),children:(0,u.jsx)(l.ChevronLeft,{className:`h-4 w-4`})}),(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,"aria-label":E(`gantt.toolbar.nextPeriod`),children:(0,u.jsx)(l.ChevronRight,{className:`h-4 w-4`})}),(0,u.jsx)(`span`,{className:`font-semibold text-xs sm:text-sm`,children:K.start.toLocaleDateString(D,{month:`long`,year:`numeric`})}),M&&(0,u.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full border bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground`,"data-testid":`gantt-readonly-badge`,title:E(`gantt.readOnlyHint`),children:[(0,u.jsx)(l.Lock,{className:`h-3 w-3`}),E(`gantt.readOnly`)]})]}),(0,u.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,u.jsx)(`div`,{className:`flex bg-muted rounded-md p-1`,role:`group`,"aria-label":E(`gantt.toolbar.viewMode`),children:O.map(e=>(0,u.jsx)(s.Button,{variant:`ghost`,size:`sm`,className:(0,s.cn)(`h-6 px-1.5 sm:px-2 text-xs`,I===e&&`bg-background shadow-sm hover:bg-background`),onClick:()=>$t(e),"aria-pressed":I===e,"data-testid":`gantt-view-mode-${e}`,children:E(`gantt.viewMode.${e}`)},e))}),(0,u.jsxs)(`div`,{className:`flex bg-muted rounded-md p-1`,children:[(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-6 w-6`,onClick:()=>{if(R>15)Ie(Math.max(15,R-10));else{let e=O.indexOf(I);e<O.length-1&&($t(O[e+1]),Ie(Me))}},"aria-label":E(`gantt.toolbar.zoomOut`),children:(0,u.jsx)(l.ZoomOut,{className:`h-3 w-3`})}),(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-6 w-6`,onClick:()=>{if(R<120)Ie(Math.min(120,R+10));else{let e=O.indexOf(I);e>0&&($t(O[e-1]),Ie(Me))}},"aria-label":E(`gantt.toolbar.zoomIn`),children:(0,u.jsx)(l.ZoomIn,{className:`h-3 w-3`})})]}),(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:()=>We(e=>!e),"aria-label":E(Ue?`gantt.toolbar.showTaskList`:`gantt.toolbar.hideTaskList`),"aria-pressed":Ue,"data-testid":`gantt-toggle-task-list`,children:Ue?(0,u.jsx)(l.PanelLeft,{className:`h-4 w-4`}):(0,u.jsx)(l.PanelLeftClose,{className:`h-4 w-4`})}),(0,u.jsx)(s.Button,{variant:`ghost`,size:`sm`,className:`h-8 px-2 text-xs`,onClick:On,disabled:Q==null,"aria-label":E(`gantt.toolbar.jumpToToday`),"data-testid":`gantt-jump-today`,children:E(`gantt.toolbar.today`)}),(0,u.jsx)(s.Button,{variant:`ghost`,size:`sm`,className:`h-8 px-2 text-xs`,onClick:Mn,"aria-label":E(`gantt.toolbar.thisWeek`),"data-testid":`gantt-jump-week`,children:E(`gantt.toolbar.thisWeek`)}),(0,u.jsx)(s.Button,{variant:`ghost`,size:`sm`,className:`h-8 px-2 text-xs`,onClick:Nn,"aria-label":E(`gantt.toolbar.thisMonth`),"data-testid":`gantt-jump-month`,children:E(`gantt.toolbar.thisMonth`)}),N?(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:yt,disabled:!xt,"aria-label":E(`gantt.toolbar.undo`),"data-testid":`gantt-undo`,children:(0,u.jsx)(l.Undo2,{className:`h-4 w-4`})}),(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:bt,disabled:!St,"aria-label":E(`gantt.toolbar.redo`),"data-testid":`gantt-redo`,children:(0,u.jsx)(l.Redo2,{className:`h-4 w-4`})})]}):null,(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:()=>tr(e=>!e),"aria-label":E(`gantt.toolbar.criticalPath`),"aria-pressed":er,"data-testid":`gantt-critical-path`,style:er?{color:$}:void 0,children:(0,u.jsx)(l.Activity,{className:`h-4 w-4`})}),Ae&&N?(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:ir,"aria-label":E(`gantt.toolbar.autoSchedule`),"data-testid":`gantt-auto-schedule`,children:(0,u.jsx)(l.Wand2,{className:`h-4 w-4`})}):null,(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:or,"aria-label":E(`gantt.toolbar.exportPng`),"data-testid":`gantt-export-png`,children:(0,u.jsx)(l.Download,{className:`h-4 w-4`})}),(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:sr,"aria-label":E(`gantt.toolbar.exportPdf`),"data-testid":`gantt-export-pdf`,children:(0,u.jsx)(l.FileDown,{className:`h-4 w-4`})}),re||ne?(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:ur,"aria-label":E(`gantt.toolbar.saveLayout`),"aria-pressed":cr,"data-testid":`gantt-save-layout`,style:cr?{color:$}:void 0,children:(0,u.jsx)(l.Save,{className:`h-4 w-4`})}):null,(0,u.jsx)(s.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:Cn,"aria-label":E(xn?`gantt.toolbar.exitFullscreen`:`gantt.toolbar.enterFullscreen`),"aria-pressed":xn,"data-testid":`gantt-fullscreen`,children:xn?(0,u.jsx)(l.Minimize2,{className:`h-4 w-4`}):(0,u.jsx)(l.Maximize2,{className:`h-4 w-4`})})]})]}),(0,u.jsxs)(`div`,{className:`relative flex flex-col flex-1 overflow-hidden outline-none focus-visible:ring-1 focus-visible:ring-ring`,tabIndex:0,onKeyDown:Kt,"data-testid":`gantt-body`,children:[!Ue&&L>0&&(0,u.jsx)(`div`,{className:`absolute top-0 bottom-0 z-30 group/splitter`,style:{left:L-3,width:7,cursor:`col-resize`},"data-testid":`gantt-list-resize`,role:`separator`,"aria-orientation":`vertical`,onPointerDown:e=>{if(e.button!==0)return;e.preventDefault();let t=e.clientX,n=L,r=Math.max(160,j-200),i=e=>{Re(Math.max(160,Math.min(n+(e.clientX-t),r)))},a=()=>{window.removeEventListener(`pointermove`,i),window.removeEventListener(`pointerup`,a),window.removeEventListener(`pointercancel`,a),document.body.style.cursor=``};document.body.style.cursor=`col-resize`,window.addEventListener(`pointermove`,i),window.addEventListener(`pointerup`,a),window.addEventListener(`pointercancel`,a)},onDoubleClick:()=>Re(null),children:(0,u.jsx)(`div`,{className:`absolute inset-y-0 left-1/2 -translate-x-1/2 w-px bg-border group-hover/splitter:w-[3px] group-hover/splitter:bg-primary transition-all`})}),(0,u.jsxs)(`div`,{className:`flex border-b bg-muted/30 shrink-0 h-10 gantt-sm-h50`,children:[(0,u.jsxs)(`div`,{className:`flex items-center font-medium text-xs text-muted-foreground px-2 sm:px-4 border-r bg-card z-20 shadow-sm`,style:{width:L,minWidth:L},children:[(0,u.jsx)(`div`,{className:`flex-1 truncate`,children:E(`gantt.column.taskName`)}),Ye&&(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`div`,{className:`w-16 gantt-sm-w20 text-right`,children:E(`gantt.column.start`)}),(0,u.jsx)(`div`,{className:`w-16 gantt-sm-w20 text-right`,children:E(`gantt.column.end`)})]})]}),(0,u.jsx)(`div`,{className:`flex-1 overflow-hidden`,ref:an,children:(0,u.jsxs)(`div`,{className:`flex flex-col h-full`,style:{width:Yt},children:[(0,u.jsx)(`div`,{className:`relative border-b`,style:{height:`45%`},"data-testid":`gantt-header-groups`,children:nn.slice(yn.start,yn.end).map(e=>(0,u.jsx)(`div`,{className:`absolute top-0 bottom-0 flex items-center justify-center border-r text-[10px] font-medium text-muted-foreground overflow-hidden`,style:{left:e.offset,width:e.width},children:(0,u.jsx)(`span`,{className:`truncate px-1`,children:e.label})},e.key))}),(0,u.jsx)(`div`,{className:`relative flex-1`,"data-testid":`gantt-header-units`,children:q.slice(_n.start,_n.end).map((e,t)=>{let n=_n.start+t;return(0,u.jsxs)(`div`,{className:(0,s.cn)(`absolute top-0 bottom-0 flex items-center justify-center gap-1 border-r text-xs text-muted-foreground overflow-hidden`,e.isWeekend&&`bg-muted/50`),style:{left:J[n],width:e.width},children:[(0,u.jsx)(`span`,{className:`font-medium text-foreground truncate`,children:e.label}),e.sublabel&&R>=32&&(0,u.jsx)(`span`,{className:`text-[10px] opacity-70`,children:e.sublabel})]},n)})})]})})]}),(0,u.jsxs)(`div`,{className:`flex flex-1 overflow-hidden`,children:[(0,u.jsxs)(`div`,{className:`gantt-task-list overflow-y-auto overflow-x-hidden border-r bg-card z-10 shadow-sm`,ref:on,onScroll:Fn,style:{width:L,minWidth:L},role:`tree`,"aria-label":E(`gantt.aria.taskList`),children:[Z.startIdx>0&&(0,u.jsx)(`div`,{style:{height:Z.startIdx*F},"aria-hidden":`true`}),G.slice(Z.startIdx,Z.endIdx).map(e=>{let t=e.task,n=ke&&Xe===t.id,r=Ht.has(String(t.id)),i=Lt!=null&&String(Lt)===String(t.id);return(0,u.jsxs)(`div`,{className:(0,s.cn)(`group/task-row relative flex items-center border-b px-2 sm:px-4 hover:bg-accent/50 cursor-pointer transition-colors`,i&&`bg-accent/50`),style:{height:F,touchAction:`manipulation`},role:`treeitem`,"aria-level":e.depth+1,"aria-selected":i,"aria-expanded":e.hasChildren?!r:void 0,draggable:!!Oe&&!n&&!t.locked,onDragStart:Oe?e=>{e.dataTransfer.setData(`text/plain`,String(t.id)),e.dataTransfer.effectAllowed=`move`}:void 0,onDragOver:Oe?e=>{e.preventDefault(),e.dataTransfer.dropEffect=`move`}:void 0,onDrop:Oe?e=>{e.preventDefault();let n=e.dataTransfer.getData(`text/plain`);if(!n||n===String(t.id))return;let r=rt.get(n);r&&String(r.parent??``)===String(t.parent??``)&&Oe(r,t)}:void 0,onContextMenu:e=>Bt(t,e),onClick:()=>{Rt(t.id),n||o?.(t)},onDoubleClick:()=>{ke&&N&&!e.isSummary&&!t.locked&&(Ze(t.id),$e({title:t.title,start:t.start.toLocaleDateString(`en-CA`),end:t.end.toLocaleDateString(`en-CA`),progress:String(t.progress)}))},children:[(0,u.jsxs)(`div`,{className:`flex-1 truncate font-medium text-xs sm:text-sm flex items-center gap-2`,style:e.depth>0?{paddingLeft:e.depth*14}:void 0,children:[e.hasChildren?(0,u.jsx)(`button`,{type:`button`,className:`h-4 w-4 shrink-0 flex items-center justify-center text-muted-foreground hover:text-foreground`,style:{marginLeft:-4},onClick:e=>{e.stopPropagation(),Wt(t.id)},"aria-expanded":!r,"aria-label":E(r?`gantt.row.expand`:`gantt.row.collapse`),"data-testid":`gantt-row-toggle-${t.id}`,children:r?(0,u.jsx)(l.ChevronRight,{className:`h-3.5 w-3.5`}):(0,u.jsx)(l.ChevronDown,{className:`h-3.5 w-3.5`})}):(0,u.jsx)(`span`,{className:`w-3 shrink-0`,style:{marginLeft:-4},"aria-hidden":`true`}),(0,u.jsx)(`div`,{className:`w-2 h-2 rounded-full shrink-0`,style:{backgroundColor:t.color||`#3b82f6`}}),n?(0,u.jsx)(`input`,{className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:Qe.title||``,onChange:e=>$e(t=>({...t,title:e.target.value})),onKeyDown:e=>{e.key===`Enter`?(V([{task:t,changes:{title:Qe.title,start:new Date(Qe.start),end:new Date(Qe.end),progress:Number(Qe.progress)||0}}]),Ze(null)):e.key===`Escape`&&Ze(null)},onClick:e=>e.stopPropagation(),autoFocus:!0}):(0,u.jsxs)(`span`,{className:`flex flex-col min-w-0`,children:[(0,u.jsx)(`span`,{className:(0,s.cn)(`truncate`,e.isSummary&&`font-semibold`),children:t.title}),(0,u.jsxs)(`span`,{className:`text-[10px] text-muted-foreground gantt-sm-hidden`,children:[e.start.toLocaleDateString(D,{month:`numeric`,day:`numeric`}),` → `,e.end.toLocaleDateString(D,{month:`numeric`,day:`numeric`})]})]})]}),(0,u.jsx)(`div`,{className:`w-16 gantt-sm-w20 text-right text-xs text-muted-foreground hidden sm:block`,hidden:!Ye,style:Ye?void 0:{display:`none`},children:n?(0,u.jsx)(`input`,{type:`date`,className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:Qe.start||``,onChange:e=>$e(t=>({...t,start:e.target.value})),onClick:e=>e.stopPropagation()}):e.start.toLocaleDateString(D,{month:`numeric`,day:`numeric`})}),(0,u.jsx)(`div`,{className:`w-16 gantt-sm-w20 text-right text-xs text-muted-foreground hidden sm:block`,hidden:!Ye,style:Ye?void 0:{display:`none`},children:n?(0,u.jsx)(`input`,{type:`date`,className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:Qe.end||``,onChange:e=>$e(t=>({...t,end:e.target.value})),onClick:e=>e.stopPropagation()}):e.end.toLocaleDateString(D,{month:`numeric`,day:`numeric`})}),!n&&(0,u.jsx)(`button`,{type:`button`,title:E(`gantt.row.locate`),"aria-label":E(`gantt.row.locate`),className:`gantt-locate-btn hidden sm:block absolute top-1/2 -translate-y-1/2`,style:{right:1},onClick:t=>{t.stopPropagation(),jn(e.start,e.end,e.task.id)},children:(0,u.jsx)(l.Crosshair,{className:`w-3 h-3`})})]},t.id)}),Z.endIdx<G.length&&(0,u.jsx)(`div`,{style:{height:(G.length-Z.endIdx)*F},"aria-hidden":`true`})]}),(0,u.jsx)(`div`,{className:`flex-1 overflow-auto bg-background/50 relative [-webkit-overflow-scrolling:touch]`,ref:e=>{sn.current=e,X.current=e},onScroll:Pn,onTouchStart:Tn,onTouchMove:En,onTouchEnd:Dn,"data-testid":`gantt-timeline`,children:(0,u.jsxs)(`div`,{className:`relative`,style:{width:Yt},children:[Q!=null&&(0,u.jsx)(`div`,{className:`absolute top-0 bottom-0 w-px z-20 pointer-events-none`,style:{left:Q,backgroundColor:`rgba(239, 68, 68, 0.8)`},"data-testid":`gantt-today-marker`,"aria-label":E(`gantt.toolbar.today`),children:(0,u.jsx)(`div`,{className:`absolute -translate-x-1/2 left-0 text-[10px] font-semibold text-white rounded-sm px-1 py-0.5 whitespace-nowrap z-30`,style:{top:2,backgroundColor:`#ef4444`},children:E(`gantt.toolbar.today`)})}),rn.map(e=>(0,u.jsx)(`div`,{className:`absolute top-0 bottom-0 w-px z-20 pointer-events-none`,style:{left:e.left,backgroundColor:e.color},"data-testid":`gantt-marker-${e.index}`,"aria-label":e.label,children:e.label&&(0,u.jsx)(`div`,{className:`absolute -translate-x-1/2 left-0 text-[10px] font-semibold text-white rounded-sm px-1 py-0.5 whitespace-nowrap z-30`,style:{top:2,backgroundColor:e.color},children:e.label})},e.index)),(0,u.jsxs)(`div`,{className:`relative`,ref:Dt,children:[(0,u.jsx)(`div`,{className:`absolute inset-0 pointer-events-none`,style:{zIndex:0},children:q.slice(_n.start,_n.end).map((e,t)=>{let n=_n.start+t;return(0,u.jsx)(`div`,{className:`absolute top-0 bottom-0 border-r`,style:{left:J[n],width:e.width,backgroundColor:e.isWeekend?`hsl(var(--muted) / 0.4)`:void 0}},n)})}),Z.startIdx>0&&(0,u.jsx)(`div`,{style:{height:Z.startIdx*F},"aria-hidden":`true`}),G.slice(Z.startIdx,Z.endIdx).map(e=>{let n=e.task,r=rr(n.id),i=In(e.start,e.end),a=ee&&n.baselineStart&&n.baselineEnd?In(n.baselineStart,n.baselineEnd):null,c=a?(0,u.jsx)(`div`,{className:`absolute pointer-events-none rounded-[1px]`,style:{left:a.left,width:Math.max(2,a.width),top:Yn,height:Jn,backgroundColor:Xn,border:`1px solid ${Zn}`},"data-testid":`gantt-baseline-${n.id}`,"aria-hidden":`true`}):null,l=B?.taskId===n.id,d=Rn?.has(String(n.id))??!1,f=zn?.has(String(n.id))??!1,p=l||d||f?Bn(e):i,m=!!n.locked,h=!!N&&!e.isSummary&&!m,g=H!=null&&H.targetId!=null&&String(H.targetId)===String(n.id)&&String(H.sourceId)!==String(n.id),_=H?e=>{let t=e.currentTarget.getBoundingClientRect(),r=t.width>0&&e.clientX-t.left>t.width/2?`end`:`start`;Ot(e=>e&&String(e.sourceId)!==String(n.id)?{...e,targetId:n.id,targetEnd:r}:e)}:void 0,v=H?e=>{e.target===e.currentTarget&&Ot(e=>e&&{...e,targetId:null,targetEnd:null})}:void 0,y=Math.max(1,Math.round((e.end.getTime()-e.start.getTime())/pe)),b=et===n.id&&!B&&!wt&&!H?(0,u.jsxs)(`div`,{className:`absolute z-30 pointer-events-none rounded-md border bg-popover text-popover-foreground px-2.5 py-1.5 text-xs shadow-md whitespace-nowrap`,style:{left:Math.max(p.left+8,4),top:F-8},role:`tooltip`,"data-testid":`gantt-tooltip-${n.id}`,children:[(0,u.jsx)(`div`,{className:`font-semibold`,children:n.title}),n.fields&&n.fields.length>0?(0,u.jsx)(`div`,{style:{display:`grid`,gridTemplateColumns:`auto 1fr`,columnGap:10,rowGap:2,marginTop:4},children:n.fields.map((e,n)=>(0,u.jsxs)(t.Fragment,{children:[(0,u.jsx)(`span`,{className:`text-muted-foreground`,children:e.label}),(0,u.jsx)(`span`,{style:{fontWeight:500},children:e.value})]},n))}):(0,u.jsxs)(`div`,{className:`text-muted-foreground`,children:[e.start.toLocaleDateString(D,{month:`short`,day:`numeric`}),` → `,e.end.toLocaleDateString(D,{month:`short`,day:`numeric`}),` · `,y,E(`gantt.tooltip.days`),` · `,Math.round(e.progress),`%`]})]}):null;if(n.type===`group`)return(0,u.jsx)(`div`,{className:`relative border-b hover:bg-accent/50`,style:{height:F},onPointerMove:v,children:b},n.id);if(e.isSummary){let t=n.color||`#0d9488`;return(0,u.jsxs)(`div`,{className:`relative border-b hover:bg-accent/50`,style:{height:F},onPointerMove:v,children:[c,(0,u.jsxs)(`div`,{className:(0,s.cn)(`gantt-bar-hover absolute rounded-sm border shadow-sm flex items-center px-2 select-none`,N?`cursor-grab active:cursor-grabbing`:`cursor-pointer`,l&&`ring-2 ring-primary z-10`,cn===n.id&&`gantt-flash z-10`),style:{left:p.left,width:p.width,top:qn,height:Kn,backgroundColor:t,borderColor:r?$:`hsl(var(--primary-foreground) / 0.2)`,boxShadow:r?`0 0 0 2px ${$}`:void 0},"data-critical":r?`true`:void 0,"data-testid":`gantt-summary-bar-${n.id}`,"data-progress":Math.round(e.progress),onMouseEnter:()=>tt(n.id),onMouseLeave:()=>tt(e=>e===n.id?null:e),onPointerDown:t=>{t.button===0&&Ct(n,`move`,t,{group:!0,originStart:e.start,originEnd:e.end})},onClick:()=>{st.current||o?.(n)},onContextMenu:e=>Bt(n,e),children:[(0,u.jsx)(`div`,{className:`absolute left-0 top-0 bottom-0 pointer-events-none`,style:{width:`${Math.round(e.progress)}%`,backgroundColor:`rgba(0, 0, 0, 0.2)`,borderTopLeftRadius:`var(--radius-sm)`,borderBottomLeftRadius:`var(--radius-sm)`}}),(0,u.jsx)(`span`,{className:`relative text-[10px] text-white font-medium truncate pointer-events-none`,children:n.title})]}),l&&B&&(0,u.jsxs)(`div`,{className:`absolute z-30 pointer-events-none rounded border bg-popover text-popover-foreground px-1.5 py-0.5 text-[10px] shadow whitespace-nowrap`,style:{left:Math.max(p.left,4),top:qn+Kn+2},"data-testid":`gantt-summary-drag-chip-${n.id}`,children:[ct(B).start.toLocaleDateString(D,{month:`numeric`,day:`numeric`}),` → `,ct(B).end.toLocaleDateString(D,{month:`numeric`,day:`numeric`})]}),b]},n.id)}if(e.isMilestone){let e=Wn;return(0,u.jsxs)(`div`,{className:`relative border-b hover:bg-accent/50`,style:{height:F},onPointerMove:v,children:[c,(0,u.jsx)(`div`,{className:(0,s.cn)(`gantt-bar-hover absolute rotate-45 rounded-[2px] border shadow-sm select-none`,h?`cursor-grab active:cursor-grabbing`:`cursor-pointer`,l&&`ring-2 ring-primary z-10`,g&&`ring-2 ring-primary`,cn===n.id&&`gantt-flash z-10`),style:{left:p.left-e/2,top:(F-e)/2,width:e,height:e,backgroundColor:r?$:n.color||`#3b82f6`,borderColor:r?$:`hsl(var(--primary-foreground) / 0.2)`,boxShadow:r?`0 0 0 2px ${$}`:void 0},"data-critical":r?`true`:void 0,"data-testid":`gantt-milestone-${n.id}`,onMouseEnter:()=>tt(n.id),onMouseLeave:()=>tt(e=>e===n.id?null:e),onClick:()=>{st.current||o?.(n)},onContextMenu:e=>Bt(n,e),onPointerMove:_,onPointerDown:h?e=>{e.button===0&&Ct(n,`move`,e)}:void 0}),b]},n.id)}let x=wt&&wt.taskId===n.id?wt.value:n.progress;return(0,u.jsxs)(`div`,{className:`relative border-b hover:bg-accent/50`,style:{height:F},onPointerMove:v,onMouseEnter:()=>tt(n.id),onMouseLeave:()=>tt(e=>e===n.id?null:e),children:[l&&(0,u.jsx)(`div`,{className:`absolute rounded-sm border border-dashed pointer-events-none`,style:{left:i.left,width:i.width,top:Hn,height:Un,opacity:.35,borderColor:`hsl(var(--primary) / 0.6)`},"aria-hidden":`true`}),c,(0,u.jsxs)(`div`,{className:(0,s.cn)(`gantt-bar-hover absolute rounded-sm bg-primary border shadow-sm flex items-center px-2 group select-none`,h?`cursor-grab active:cursor-grabbing`:`cursor-pointer`,l&&`ring-2 ring-primary z-10`,g&&`ring-2 ring-primary`,cn===n.id&&`gantt-flash z-10`),style:{left:p.left,width:p.width,top:Hn,height:Un,backgroundColor:n.color||`#3b82f6`,borderColor:r?$:`hsl(var(--primary-foreground) / 0.2)`,boxShadow:r?`0 0 0 2px ${$}`:void 0},"data-critical":r?`true`:void 0,"data-testid":`gantt-task-bar-${n.id}`,onClick:()=>{st.current||o?.(n)},onContextMenu:e=>Bt(n,e),onPointerMove:_,onPointerDown:h?e=>{e.button===0&&Ct(n,`move`,e)}:void 0,children:[h&&p.width>=14&&(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`div`,{className:`gantt-resize-handle absolute left-0 top-0 bottom-0`,style:{width:6,cursor:`ew-resize`},"data-testid":`gantt-task-resize-left-${n.id}`,onPointerDown:e=>{e.button===0&&Ct(n,`resize-left`,e)},onClick:e=>e.stopPropagation()}),(0,u.jsx)(`div`,{className:`gantt-resize-handle absolute right-0 top-0 bottom-0`,style:{width:6,cursor:`ew-resize`},"data-testid":`gantt-task-resize-right-${n.id}`,onPointerDown:e=>{e.button===0&&Ct(n,`resize-right`,e)},onClick:e=>e.stopPropagation()})]}),x>0&&(0,u.jsx)(`div`,{className:`absolute left-0 top-0 bottom-0 pointer-events-none`,style:{width:`${x}%`,backgroundColor:`rgba(0, 0, 0, 0.2)`,borderTopLeftRadius:`var(--radius-sm)`,borderBottomLeftRadius:`var(--radius-sm)`}}),h&&p.width>=30&&(0,u.jsx)(`div`,{className:(0,s.cn)(`absolute bottom-0 h-1/2 w-4 -translate-x-1/2 cursor-col-resize flex items-end justify-center pb-px`,wt?.taskId===n.id?`opacity-100`:`opacity-0 group-hover:opacity-100 transition-opacity`),style:{left:`${x}%`},"data-testid":`gantt-progress-handle-${n.id}`,onPointerDown:e=>{e.button===0&&(e.stopPropagation(),e.preventDefault(),Tt({taskId:n.id,originClientX:e.clientX,originProgress:n.progress,barWidth:p.width,value:n.progress}))},onClick:e=>e.stopPropagation(),children:(0,u.jsx)(`div`,{style:{width:0,height:0,borderLeft:`5px solid transparent`,borderRight:`5px solid transparent`,borderBottom:`7px solid #fff`,filter:`drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35))`}})}),P&&!m&&[`start`,`end`].map(e=>{let t=H!=null&&String(H.sourceId)===String(n.id)&&H.sourceEnd===e,r=t||et===n.id,i=r&&H==null;return(0,u.jsx)(`div`,{className:`absolute top-1/2 -translate-y-1/2 z-20 flex items-center transition-opacity`,style:{[e===`start`?`left`:`right`]:-28,height:24,width:30,cursor:`crosshair`,opacity:+!!r,pointerEvents:i?`auto`:`none`,justifyContent:e===`start`?`flex-start`:`flex-end`,paddingLeft:e===`start`?4:0,paddingRight:e===`end`?4:0},"data-testid":`gantt-link-dot-${e}-${n.id}`,onPointerDown:t=>{if(t.button!==0)return;t.stopPropagation(),t.preventDefault();let r=Dt.current?.getBoundingClientRect();Ot({sourceId:n.id,sourceEnd:e,x:r?t.clientX-r.left:0,y:r?t.clientY-r.top:0,targetId:null,targetEnd:null})},onClick:e=>e.stopPropagation(),children:(0,u.jsx)(`div`,{className:`rounded-full`,style:{height:12,width:12,backgroundColor:`hsl(var(--background))`,border:`2px solid hsl(var(--primary))`,boxShadow:t?`0 0 0 3px hsl(var(--primary) / 0.25)`:`0 1px 2px rgba(0,0,0,0.25)`}})},e)}),(0,u.jsx)(`span`,{className:`relative text-[10px] text-white font-medium truncate pointer-events-none group-hover:opacity-0 transition-opacity`,children:n.title}),(0,u.jsx)(`span`,{className:`absolute inset-0 flex items-center px-2 text-[10px] text-white font-medium truncate opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none`,children:l?`${ct(B).start.toLocaleDateString(D,{month:`numeric`,day:`numeric`})} → ${ct(B).end.toLocaleDateString(D,{month:`numeric`,day:`numeric`})}`:`${Math.round(x)}%`})]}),b]},n.id)}),Z.endIdx<G.length&&(0,u.jsx)(`div`,{style:{height:(G.length-Z.endIdx)*F},"aria-hidden":`true`}),(Vn.length>0||H)&&(0,u.jsxs)(`svg`,{className:`absolute top-0 left-0 pointer-events-none z-10`,width:Yt,height:bn,"data-testid":`gantt-links`,"aria-hidden":`true`,children:[(0,u.jsxs)(`defs`,{children:[(0,u.jsx)(`marker`,{id:`gantt-link-arrow`,viewBox:`0 0 8 8`,refX:`7`,refY:`4`,markerWidth:`6`,markerHeight:`6`,orient:`auto`,children:(0,u.jsx)(`path`,{d:`M 0 0 L 8 4 L 0 8 z`,fill:`hsl(var(--muted-foreground))`})}),(0,u.jsx)(`marker`,{id:`gantt-link-arrow-active`,viewBox:`0 0 8 8`,refX:`7`,refY:`4`,markerWidth:`6`,markerHeight:`6`,orient:`auto`,children:(0,u.jsx)(`path`,{d:`M 0 0 L 8 4 L 0 8 z`,fill:`hsl(var(--primary))`})}),(0,u.jsx)(`marker`,{id:`gantt-link-arrow-critical`,viewBox:`0 0 8 8`,refX:`7`,refY:`4`,markerWidth:`6`,markerHeight:`6`,orient:`auto`,children:(0,u.jsx)(`path`,{d:`M 0 0 L 8 4 L 0 8 z`,fill:$})})]}),Vn.map(e=>{let n=Math.min(e.sourceIndex,e.targetIndex);if(Math.max(e.sourceIndex,e.targetIndex)<Z.startIdx-6||n>Z.endIdx+6)return null;let r=Qn(e);if(!r)return null;let i=$n!=null&&(String(e.sourceId)===String($n)||String(e.targetId)===String($n)),a=nr?.criticalEdges.has(`${String(e.sourceId)}->${String(e.targetId)}`)??!1,o=a?`gantt-link-arrow-critical`:i?`gantt-link-arrow-active`:`gantt-link-arrow`,s=!!(De||P);return(0,u.jsxs)(t.Fragment,{children:[(0,u.jsx)(`path`,{d:r,fill:`none`,stroke:a?$:i?`hsl(var(--primary))`:`hsl(var(--muted-foreground))`,strokeOpacity:a||i?1:.7,strokeWidth:a||i?2:1.5,markerEnd:`url(#${o})`,"data-testid":`gantt-link-${e.sourceId}-${e.targetId}`,"data-link-type":e.type,"data-active":i?`true`:`false`,"data-critical":a?`true`:void 0}),s&&(0,u.jsx)(`path`,{d:r,fill:`none`,stroke:`transparent`,strokeWidth:10,style:{pointerEvents:`stroke`,cursor:`context-menu`},"data-testid":`gantt-link-hit-${e.sourceId}-${e.targetId}`,onContextMenu:t=>Vt(e.sourceId,e.targetId,e.type,t)})]},e.key)}),H&&(()=>{let e=G.findIndex(e=>String(e.task.id)===String(H.sourceId));if(e<0)return null;let t=Bn(G[e]),n=G[e].isMilestone?t.left+(H.sourceEnd===`start`?-Gn:Gn):H.sourceEnd===`start`?t.left:t.left+t.width,r=e*F+F/2;return(0,u.jsx)(`path`,{d:`M ${Math.round(n)} ${Math.round(r)} L ${Math.round(H.x)} ${Math.round(H.y)}`,fill:`none`,stroke:`hsl(var(--primary))`,strokeWidth:1.5,strokeDasharray:`4 3`,"data-testid":`gantt-link-draft`})})()]}),H&&(()=>{let t=e.find(e=>String(e.id)===String(H.sourceId));if(!t)return null;let n=H.targetId==null?null:e.find(e=>String(e.id)===String(H.targetId)),r=e=>E(`gantt.linkEnd.${e}`),i=n?`${t.title} (${r(H.sourceEnd)}) → ${n.title} (${r(H.targetEnd??`start`)})`:`${t.title} (${r(H.sourceEnd)})`;return(0,u.jsx)(`div`,{className:`absolute z-30 pointer-events-none rounded-md border bg-popover text-popover-foreground px-2 py-1 text-[11px] font-medium shadow-md whitespace-nowrap`,style:{left:H.x+12,top:H.y+12},"data-testid":`gantt-link-draft-hint`,children:i})})()]})]})})]})]}),At&&(()=>{let t=e.find(e=>String(e.id)===String(At.taskId));if(!t)return null;let n=G.find(e=>String(e.task.id)===String(At.taskId)),r=`w-full text-left px-3 py-1.5 hover:bg-accent focus:bg-accent outline-none`;return(0,u.jsxs)(`div`,{ref:Mt,className:`fixed z-50 min-w-[160px] rounded-md border bg-popover text-popover-foreground shadow-md py-1 text-sm`,style:{left:At.x,top:At.y},role:`menu`,"data-testid":`gantt-context-menu`,children:[o&&(0,u.jsx)(`button`,{type:`button`,role:`menuitem`,className:r,"data-testid":`gantt-context-menu-view`,onClick:()=>{jt(null),o(t)},children:E(`gantt.menu.view`)}),ke&&N&&n&&!n.isSummary&&!t.locked&&(0,u.jsx)(`button`,{type:`button`,role:`menuitem`,className:r,"data-testid":`gantt-context-menu-edit`,onClick:()=>{jt(null),Ze(t.id),$e({title:t.title,start:t.start.toLocaleDateString(`en-CA`),end:t.end.toLocaleDateString(`en-CA`),progress:String(t.progress)})},children:E(`gantt.menu.edit`)}),P&&n&&!n.isMilestone&&!t.locked&&(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`button`,{type:`button`,role:`menuitem`,className:r,"data-testid":`gantt-context-menu-add-predecessor`,onClick:()=>{let e=At;jt(null),Ft({x:e.x,y:e.y,taskId:t.id,relation:`pred`})},children:E(`gantt.menu.addPredecessor`)}),(0,u.jsx)(`button`,{type:`button`,role:`menuitem`,className:r,"data-testid":`gantt-context-menu-add-successor`,onClick:()=>{let e=At;jt(null),Ft({x:e.x,y:e.y,taskId:t.id,relation:`succ`})},children:E(`gantt.menu.addSuccessor`)})]}),Ee&&!t.locked&&(0,u.jsx)(`button`,{type:`button`,role:`menuitem`,className:(0,s.cn)(r,`text-destructive`),"data-testid":`gantt-context-menu-delete`,onClick:()=>{jt(null),Ee(t)},children:E(`gantt.menu.delete`)})]})})(),U&&(()=>{let t=e.find(e=>String(e.id)===String(U.sourceId)),n=e.find(e=>String(e.id)===String(U.targetId));if(!t||!n)return null;let r=`w-full text-left px-3 py-1.5 hover:bg-accent focus:bg-accent outline-none`;return(0,u.jsxs)(`div`,{ref:Pt,className:`fixed z-50 min-w-[180px] rounded-md border bg-popover text-popover-foreground shadow-md py-1 text-sm`,style:{left:U.x,top:U.y},role:`menu`,"data-testid":`gantt-link-context-menu`,children:[(0,u.jsxs)(`div`,{className:`px-3 py-1 text-xs text-muted-foreground truncate`,children:[t.title,` → `,n.title]}),P&&[`fs`,`ss`,`ff`,`sf`].map(e=>(0,u.jsxs)(`button`,{type:`button`,role:`menuitemradio`,"aria-checked":U.type===e,className:(0,s.cn)(r,U.type===e&&`font-semibold`),"data-testid":`gantt-link-menu-type-${e}`,onClick:()=>{Nt(null),e!==U.type&&P(t,n,e)},children:[U.type===e?`✓ `:`\xA0\xA0`,E(`gantt.linkType.${e}`)]},e)),De&&(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(`div`,{className:`my-1 border-t`}),(0,u.jsx)(`button`,{type:`button`,role:`menuitem`,className:(0,s.cn)(r,`text-destructive`),"data-testid":`gantt-link-menu-remove`,onClick:()=>{Nt(null),De(t,n)},children:E(`gantt.menu.removeDependency`)})]})]})})(),W&&P&&(()=>{let t=e.find(e=>String(e.id)===String(W.taskId));if(!t)return null;let n=new Set(Vn.map(e=>`${String(e.sourceId)}->${String(e.targetId)}`)),r=e.filter(e=>{if(String(e.id)===String(t.id)||e.type===`summary`)return!1;let r=W.relation===`pred`?`${String(e.id)}->${String(t.id)}`:`${String(t.id)}->${String(e.id)}`;return!n.has(r)});return(0,u.jsxs)(`div`,{ref:It,className:`fixed z-50 min-w-[200px] max-h-[280px] overflow-y-auto rounded-md border bg-popover text-popover-foreground shadow-md py-1 text-sm`,style:{left:W.x,top:W.y},role:`menu`,"data-testid":`gantt-dep-picker`,children:[(0,u.jsx)(`div`,{className:`px-3 py-1 text-xs text-muted-foreground`,children:W.relation===`pred`?E(`gantt.menu.addPredecessor`):E(`gantt.menu.addSuccessor`)}),r.length===0?(0,u.jsx)(`div`,{className:`px-3 py-1.5 text-muted-foreground`,children:E(`gantt.menu.noCandidates`)}):r.map(e=>(0,u.jsx)(`button`,{type:`button`,role:`menuitem`,className:`w-full text-left px-3 py-1.5 hover:bg-accent focus:bg-accent outline-none truncate`,"data-testid":`gantt-dep-picker-option-${e.id}`,onClick:()=>{Ft(null),W.relation===`pred`?P(e,t,`fs`):P(t,e,`fs`)},children:e.title},String(e.id)))]})})(),mt&&(0,u.jsx)(`div`,{className:`fixed inset-0 z-[60] flex items-center justify-center bg-black/30`,"data-testid":`gantt-conflict-overlay`,onClick:()=>ht(null),children:(0,u.jsxs)(`div`,{className:`min-w-[280px] max-w-[360px] rounded-lg border bg-popover text-popover-foreground shadow-lg p-4`,role:`alertdialog`,"aria-modal":`true`,"data-testid":`gantt-conflict-dialog`,onClick:e=>e.stopPropagation(),children:[(0,u.jsx)(`div`,{className:`text-sm font-semibold mb-1`,"data-testid":`gantt-conflict-title`,children:E(`gantt.conflict.title`)}),(0,u.jsx)(`div`,{className:`text-sm text-muted-foreground mb-3`,children:E(`gantt.conflict.body`).replace(`{count}`,String(mt.length))}),(0,u.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,u.jsx)(`button`,{type:`button`,className:`px-3 py-1.5 text-sm rounded-md border hover:bg-accent outline-none`,"data-testid":`gantt-conflict-cancel`,onClick:()=>ht(null),children:E(`gantt.conflict.cancel`)}),(0,u.jsx)(`button`,{type:`button`,className:`px-3 py-1.5 text-sm rounded-md bg-primary text-primary-foreground hover:opacity-90 outline-none`,"data-testid":`gantt-conflict-confirm`,onClick:_t,children:E(`gantt.conflict.confirm`)})]})]})})]})}function Ce(e,t,n,r){return t.getTime()===e.getTime()?e.getTime()>=n.getTime()&&e.getTime()<r.getTime():e.getTime()<r.getTime()&&t.getTime()>n.getTime()}function we(e,t,n){let{assignee:r,effort:i,capacity:a=1,unassignedLabel:o=`Unassigned`}=n,s=e=>typeof a==`function`?a(e):a,c=e=>{let t=i?i(e):1;return Number.isFinite(t)&&t>0?t:0},l=new Map;for(let t of e){let e=r(t),n=e?String(e.key):`__unassigned__`,i=e?e.label:o,a=l.get(n);a||(a={key:n,label:i,items:[]},l.set(n,a)),a.items.push(t)}let u=[];for(let e of l.values()){let n=s(e.key),r=0,i=0,a=t.map(t=>{let a=0;for(let n of e.items)Ce(n.start,n.end,t.start,t.end)&&(a+=c(n));a>r&&(r=a);let o=a>n+1e-9;return o&&i++,{load:a,capacity:n,overloaded:o}});u.push({key:e.key,label:e.label,capacity:n,cells:a,peak:r,overloadedCount:i})}return u}var j={day:26,week:56,month:76,quarter:88,year:104},Te=48,M=34,N=180;function Ee(e,t,n){return t===`day`?String(e.getDate()):t===`week`?e.toLocaleDateString(n,{month:`numeric`,day:`numeric`}):t===`month`?e.toLocaleDateString(n,{month:`short`}):t===`year`?String(e.getFullYear()):`Q${Math.floor(e.getMonth()/3)+1}`}function P({tasks:e,assignee:n,effort:r,capacity:i=1,viewMode:a=`day`,unassignedLabel:o=`Unassigned`,className:s}){let{t:c,language:l}=se(),d=l||void 0,f=j[a],p=t.useMemo(()=>{if(!e.length)return[];let t=new Date(Math.min(...e.map(e=>e.start.getTime()))),n=new Date(Math.max(...e.map(e=>e.end.getTime()))),r=k(t,a),i=A(k(n,a),1,a),o=[],s=0;for(;r<i&&s++<4e3;){let e=A(r,1,a);o.push({date:new Date(r),col:{start:new Date(r),end:new Date(e)},label:Ee(r,a,d)}),r=e}return o},[e,a,d]),m=t.useMemo(()=>we(e,p.map(e=>e.col),{assignee:n,effort:r,capacity:i,unassignedLabel:o}),[e,p,n,r,i,o]),h=t.useMemo(()=>{let e=0;for(let t of m)e=Math.max(e,t.peak,t.capacity);return e||1},[m]),g=p.length*f;return e.length?(0,u.jsx)(`div`,{className:s,"data-testid":`resource-workload`,style:{display:`flex`,flexDirection:`column`,height:`100%`,overflow:`auto`},children:(0,u.jsxs)(`div`,{style:{display:`flex`,minWidth:N+g},children:[(0,u.jsxs)(`div`,{style:{width:N,flexShrink:0},children:[(0,u.jsx)(`div`,{style:{height:28,display:`flex`,alignItems:`center`,padding:`0 12px`,fontSize:12,fontWeight:600,borderBottom:`1px solid hsl(var(--border))`},children:c(`gantt.resource.header`)}),m.map(e=>(0,u.jsxs)(`div`,{"data-testid":`resource-row-${e.key}`,style:{height:Te,display:`flex`,flexDirection:`column`,justifyContent:`center`,padding:`0 12px`,borderBottom:`1px solid hsl(var(--border) / 0.5)`},children:[(0,u.jsx)(`span`,{style:{fontSize:13,fontWeight:500,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`},children:e.label}),(0,u.jsxs)(`span`,{"data-testid":`resource-peak-${e.key}`,"data-overloaded":e.overloadedCount>0?`true`:void 0,style:{fontSize:10,color:e.overloadedCount>0?`hsl(var(--destructive))`:`hsl(var(--muted-foreground))`},children:[c(`gantt.resource.peak`),`: `,Math.round(e.peak*100)/100,` / `,e.capacity,e.overloadedCount>0?` · ${e.overloadedCount} ${c(`gantt.resource.over`)}`:``]})]},e.key))]}),(0,u.jsxs)(`div`,{style:{flex:1},children:[(0,u.jsx)(`div`,{style:{display:`flex`,height:28,borderBottom:`1px solid hsl(var(--border))`},children:p.map((e,t)=>(0,u.jsx)(`div`,{style:{width:f,flexShrink:0,textAlign:`center`,fontSize:10,color:`hsl(var(--muted-foreground))`,borderLeft:`1px solid hsl(var(--border) / 0.4)`,display:`flex`,alignItems:`center`,justifyContent:`center`},children:e.label},t))}),m.map(e=>{let t=M*(1-Math.min(e.capacity/h,1));return(0,u.jsxs)(`div`,{style:{position:`relative`,display:`flex`,height:Te,borderBottom:`1px solid hsl(var(--border) / 0.5)`},children:[(0,u.jsx)(`div`,{"aria-hidden":`true`,style:{position:`absolute`,left:0,right:0,top:(Te-M)/2+t,borderTop:`1px dashed hsl(var(--muted-foreground) / 0.6)`,pointerEvents:`none`,zIndex:1}}),e.cells.map((t,n)=>{let r=Math.max(t.load>0?2:0,M*Math.min(t.load/h,1));return(0,u.jsx)(`div`,{"data-testid":`resource-cell-${e.key}-${n}`,"data-load":t.load,"data-overloaded":t.overloaded?`true`:void 0,title:`${p[n]?.date.toLocaleDateString(d)} — ${Math.round(t.load*100)/100} / ${t.capacity}`,style:{width:f,flexShrink:0,position:`relative`,borderLeft:`1px solid hsl(var(--border) / 0.4)`,display:`flex`,alignItems:`flex-end`,justifyContent:`center`,paddingBottom:(Te-M)/2},children:t.load>0&&(0,u.jsx)(`div`,{style:{width:f-6,height:r,borderRadius:2,backgroundColor:t.overloaded?`hsl(var(--destructive))`:`hsl(var(--primary))`,opacity:t.overloaded?.9:.75}})},n)})]},e.key)})]})]})}):(0,u.jsx)(`div`,{className:s,"data-testid":`resource-workload`,children:(0,u.jsx)(`div`,{className:`flex items-center justify-center h-40 text-sm text-muted-foreground`,children:c(`gantt.resource.empty`)})})}var De={display:`flex`,flexWrap:`wrap`,alignItems:`center`,gap:8,padding:`8px 12px`,borderBottom:`1px solid hsl(var(--border))`,background:`hsl(var(--background))`,fontSize:13},Oe={display:`inline-flex`,alignItems:`center`,gap:6,height:30,padding:`0 10px`,borderRadius:6,border:`1px solid hsl(var(--border))`,background:`hsl(var(--background))`,color:`hsl(var(--foreground))`,cursor:`pointer`,whiteSpace:`nowrap`,lineHeight:`28px`},ke={position:`absolute`,top:`calc(100% + 4px)`,left:0,zIndex:50,minWidth:200,maxHeight:320,overflowY:`auto`,padding:4,borderRadius:8,border:`1px solid hsl(var(--border))`,background:`hsl(var(--popover, var(--background)))`,color:`hsl(var(--popover-foreground, var(--foreground)))`,boxShadow:`0 8px 24px rgba(0,0,0,0.18)`},Ae={display:`flex`,alignItems:`center`,gap:8,padding:`6px 8px`,borderRadius:6,cursor:`pointer`,userSelect:`none`};function je({checked:e}){return(0,u.jsx)(`span`,{"aria-hidden":!0,style:{display:`inline-flex`,alignItems:`center`,justifyContent:`center`,width:15,height:15,flex:`0 0 auto`,borderRadius:3,border:`1px solid ${e?`hsl(var(--primary))`:`hsl(var(--border))`}`,background:e?`hsl(var(--primary))`:`transparent`,color:`hsl(var(--primary-foreground, var(--background)))`,fontSize:11,lineHeight:1},children:e?`✓`:``})}function F({filter:e,selected:n,onChange:r,labels:i}){let[a,o]=(0,t.useState)(!1),s=(0,t.useRef)(null);(0,t.useEffect)(()=>{if(!a)return;let e=e=>{s.current&&!s.current.contains(e.target)&&o(!1)},t=e=>{e.key===`Escape`&&o(!1)};return document.addEventListener(`pointerdown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`pointerdown`,e),document.removeEventListener(`keydown`,t)}},[a]);let c=new Set(n),l=n.length,d=e.options.length>0&&l===e.options.length,f=t=>{let n=new Set(c);n.has(t)?n.delete(t):n.add(t),n.size===e.options.length?r([]):r([...n])},p=()=>{r(l>0?[]:e.options.map(e=>e.value))},m=l===0?e.label:l===1?`${e.label}: ${e.options.find(e=>e.value===n[0])?.label??n[0]}`:`${e.label} · ${l}`;return(0,u.jsxs)(`div`,{ref:s,style:{position:`relative`},"data-testid":`quick-filter-${e.field}`,children:[(0,u.jsxs)(`button`,{type:`button`,style:{...Oe,borderColor:l>0?`hsl(var(--primary))`:`hsl(var(--border))`,color:l>0?`hsl(var(--primary))`:`hsl(var(--foreground))`},"aria-haspopup":`listbox`,"aria-expanded":a,"data-testid":`quick-filter-trigger-${e.field}`,onClick:()=>o(e=>!e),children:[(0,u.jsx)(`span`,{children:m}),(0,u.jsx)(`span`,{"aria-hidden":!0,style:{fontSize:10,opacity:.7},children:`▾`})]}),a&&(0,u.jsx)(`div`,{role:`listbox`,style:ke,"data-testid":`quick-filter-panel-${e.field}`,children:e.options.length===0?(0,u.jsx)(`div`,{style:{...Ae,cursor:`default`,opacity:.6},children:i.empty}):(0,u.jsxs)(u.Fragment,{children:[(0,u.jsxs)(`div`,{role:`option`,"aria-selected":d,style:{...Ae,fontWeight:600},"data-testid":`quick-filter-all-${e.field}`,onClick:()=>p(),children:[(0,u.jsx)(je,{checked:d}),(0,u.jsx)(`span`,{children:i.all})]}),(0,u.jsx)(`div`,{style:{height:1,background:`hsl(var(--border))`,margin:`2px 0`}}),e.options.map(t=>{let n=c.has(t.value);return(0,u.jsxs)(`div`,{role:`option`,"aria-selected":n,style:{...Ae,background:n?`hsl(var(--accent, var(--muted)))`:`transparent`},"data-testid":`quick-filter-option-${e.field}-${t.value}`,onClick:()=>f(t.value),children:[(0,u.jsx)(je,{checked:n}),(0,u.jsx)(`span`,{children:t.label})]},t.value)})]})})]})}var Me=({filters:e,value:t,onChange:n,onClear:r,resultCount:i,totalCount:a,labels:o,className:s})=>{if(!e.length)return null;let c=o?.all??`All`,l=o?.empty??`No options`,d=o?.clear??`Clear`,f=e.some(e=>(t[e.field]?.length??0)>0);return(0,u.jsxs)(`div`,{style:De,className:s,"data-testid":`quick-filter-bar`,children:[e.map(e=>(0,u.jsx)(F,{filter:e,selected:t[e.field]??[],onChange:t=>n(e.field,t),labels:{all:c,empty:l}},e.field)),f&&(0,u.jsx)(`button`,{type:`button`,style:{...Oe,height:28,color:`hsl(var(--muted-foreground))`},"data-testid":`quick-filter-clear`,onClick:r,children:d}),o?.resultSummary&&i!=null&&a!=null&&(0,u.jsx)(`span`,{"data-testid":`quick-filter-summary`,style:{marginLeft:`auto`,color:`hsl(var(--muted-foreground))`},children:o.resultSummary(i,a)})]})};function Ne(e){if(e==null)return;let t=String(e).toLowerCase().trim();if(t===`milestone`)return`milestone`;if(t===`group`||t===`folder`)return`group`;if(t===`summary`||t===`project`||t===`phase`)return`summary`;if(t===`task`)return`task`}var Pe={fs:`fs`,ss:`ss`,ff:`ff`,sf:`sf`,finish_to_start:`fs`,start_to_start:`ss`,finish_to_finish:`ff`,start_to_finish:`sf`,end_to_start:`fs`,end_to_end:`ff`,start_to_end:`sf`};function Fe(e){if(e==null||e===``)return[];if(typeof e==`string`)return e.split(`,`).map(e=>e.trim()).filter(Boolean);if(typeof e==`number`)return[e];if(!Array.isArray(e))return[];let t=[];for(let n of e)if(!(n==null||n===``))if(typeof n==`object`){let e=n.id??n._id??n.task??n.target;if(e==null||e===``)continue;let r=Pe[String(n.type??``).toLowerCase().replace(/-/g,`_`)];t.push(r?{id:e,type:r}:{id:e})}else t.push(n);return t}function Ie(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function Le(e){if(e){if(typeof e==`string`){let t=e.split(` `),n=t[0],r=t[1]?.toLowerCase()===`desc`?`desc`:`asc`;return{[n]:r}}if(Array.isArray(e))return e.reduce((e,t)=>(t.field&&t.order&&(e[t.field]=t.order),e),{})}}function Re(e){let t=null;if(e.startDateField&&e.endDateField)return t={startDateField:e.startDateField,endDateField:e.endDateField,titleField:e.titleField||`name`,progressField:e.progressField,dependenciesField:e.dependenciesField||e.dependencyField,colorField:e.colorField,parentField:e.parentField,typeField:e.typeField,lockField:e.lockField,defaultCollapsedDepth:e.defaultCollapsedDepth,tooltipFields:e.tooltipFields,baselineStartField:e.baselineStartField,baselineEndField:e.baselineEndField,groupByField:e.groupByField,resourceView:e.resourceView,assigneeField:e.assigneeField,effortField:e.effortField,capacity:e.capacity,quickFilters:e.quickFilters,autoZoomToFilter:e.autoZoomToFilter},t;if(e.gantt&&(t=e.gantt),t){let e=i.GanttConfigSchema.safeParse(t);return e.success||console.warn(`[ObjectGantt] Invalid gantt configuration:`,e.error.format()),t}return null}var I=({schema:e,dataSource:i,className:l,onTaskClick:d,onRowClick:f,...p})=>{let[m,h]=(0,t.useState)([]),[g,_]=(0,t.useState)(!0),[v,y]=(0,t.useState)(null),[b,x]=(0,t.useState)(null),{currency:ee}=(0,a.useLocalization)(),te=Ie(e),S=(0,t.useMemo)(()=>te,[JSON.stringify(te)]),C=Re(e),w=S?.provider===`value`;(0,t.useEffect)(()=>{(async()=>{try{if(_(!0),p.data&&Array.isArray(p.data)){h(p.data),_(!1);return}if(w&&S?.provider===`value`){h(S.items),_(!1);return}if(!i||typeof i.find!=`function`)throw Error(`DataSource required for object/api providers`);if(S?.provider===`object`){let t=S.object,r=(0,n.buildExpandFields)(b?.fields);h((0,n.extractRecords)(await i.find(t,{$filter:e.filter,$orderby:Le(e.sort),...r.length>0?{$expand:r}:{}})))}else S?.provider===`api`&&(console.warn(`API provider not yet implemented for ObjectGantt`),h([]));_(!1)}catch(e){y(e),_(!1)}})()},[S,i,w,e.filter,e.sort,b]),(0,t.useEffect)(()=>{!w&&i&&(async()=>{try{if(!i)return;let t=S?.provider===`object`?S.object:e.objectName;if(!t)return;x(await i.getObjectSchema(t))}catch(e){console.error(`Failed to fetch object schema:`,e)}})()},[e.objectName,i,w,S]);let T=(0,t.useMemo)(()=>{if(!C||!m.length)return[];let{startDateField:e,endDateField:t,titleField:n,progressField:r,dependenciesField:i,colorField:o,parentField:s,typeField:l,lockField:u,tooltipFields:d,baselineStartField:f,baselineEndField:p}=C,h=b?.fields??{},g=(e,t)=>{if(!t)return;let n=t.split(`.`),r=e;for(let e of n){if(r==null)return;r=r[e]}return r},_=e=>{let t=[g(e,n),e?.name,e?.title,e?.subject,e?.label,e?.account?.name,e?.opportunity?.name,e?.contact&&[e.contact.first_name,e.contact.last_name].filter(Boolean).join(` `),e?.id,e?._id];for(let e of t)if(e!=null&&String(e).trim()!==``)return String(e);return`Untitled`},v=(e,t)=>{if(t)return t;let n=h[e]??h[e.split(`.`)[0]];return n?.label?n.label:(0,c.humanizeLabel)(e)},y=(e,t)=>{if(e==null||e===``)return`—`;let n=h[t]??h[t.split(`.`)[0]],r=n?.type,i=n?.options;if(Array.isArray(i)&&i.length){let t=i.find(t=>String(t.value)===String(e));if(t)return t.label}switch(r){case`date`:return(0,c.formatDate)(e);case`datetime`:return(0,c.formatDateTime)(e);case`number`:case`integer`:case`float`:case`decimal`:return(0,c.formatNumber)(Number(e));case`currency`:return(0,c.formatCurrency)(Number(e),(0,a.resolveFieldCurrency)(n,ee));case`percent`:return(0,c.formatPercent)(Number(e));case`boolean`:case`checkbox`:return e?`Yes`:`No`;default:if(Array.isArray(e)){let t=e.map(e=>{if(e==null)return``;if(typeof e==`object`){let t=e;return String(t.name??t.label??t.title??t.id??``)}return String(e)}).filter(Boolean);return t.length?t.join(`, `):`—`}if(typeof e==`object`){let t=e;return String(t.name??t.label??t.title??t.id??`—`)}return String(e)}},x=e=>{if(!d||!d.length)return;let t=[];for(let n of d){let r=typeof n==`string`?n:n?.field;if(!r)continue;let i=typeof n==`object`?n.label:void 0;t.push({label:v(r,i),value:y(g(e,r),r)})}return t.length?t:void 0};return m.map((n,a)=>{let d=n[e],m=n[t],h=f?n[f]:void 0,g=p?n[p]:void 0,v=h?new Date(h):void 0,y=g?new Date(g):void 0,b=_(n),ee=r?n[r]:0,te=i?n[i]:[],S=o?n[o]:void 0;if(!S){let e=n.status??n.state??n.priority??n.severity;if(e!=null&&e!==``){let t=(0,c.getSemanticColorName)(void 0,e);t&&(S=(0,c.getSemanticHex)(t))}}return{id:n.id||n._id||`task-${a}`,title:b,start:d?new Date(d):new Date,end:m?new Date(m):new Date,progress:Math.min(100,Math.max(0,ee||0)),dependencies:Fe(te),parent:s?n[s]??null:void 0,type:l?Ne(n[l]):void 0,locked:u?!!n[u]:void 0,color:S,baselineStart:v&&!isNaN(v.getTime())?v:void 0,baselineEnd:y&&!isNaN(y.getTime())?y:void 0,fields:x(n),data:n}}).filter(e=>!isNaN(e.start.getTime())&&!isNaN(e.end.getTime()))},[m,C,b]),ne=(0,t.useMemo)(()=>{let e=C?.groupByField;if(!e)return;let t=b?.fields??{},n=(e,t)=>{if(!t)return;let n=e;for(let e of t.split(`.`)){if(n==null)return;n=n[e]}return n},r=n=>{let r=(t[e]??t[e.split(`.`)[0]])?.options;if(Array.isArray(r)&&r.length){let e=r.find(e=>String(e.value)===String(n));if(e)return e.label}if(typeof n==`object`&&n){let e=n;return String(e.name??e.label??e.title??e.id??n)}return String(n)};return t=>{let i=n(t.data,e);return i==null||i===``?null:{key:typeof i==`object`&&i?String(i.id??i._id??r(i)):i,label:r(i)}}},[C?.groupByField,b]),re=(0,t.useMemo)(()=>{let e=C?.assigneeField;if(!e)return;let t=b?.fields??{},n=(e,t)=>{if(!t)return;let n=e;for(let e of t.split(`.`)){if(n==null)return;n=n[e]}return n},r=n=>{let r=(t[e]??t[e.split(`.`)[0]])?.options;if(Array.isArray(r)&&r.length){let e=r.find(e=>String(e.value)===String(n));if(e)return e.label}if(typeof n==`object`&&n){let e=n;return String(e.name??e.label??e.title??e.id??n)}return String(n)};return t=>{let i=n(t.data,e);return i==null||i===``?null:{key:typeof i==`object`&&i?String(i.id??i._id??r(i)):i,label:r(i)}}},[C?.assigneeField,b]),E=(0,t.useMemo)(()=>{let e=C?.effortField;if(e)return t=>{let n=t.data?.[e],r=Number(n);return Number.isFinite(r)&&r>0?r:1}},[C?.effortField]),ie=(0,t.useMemo)(()=>{let t=e.skipWeekends,n=e.holidays;if(!(!t&&(!n||n.length===0)))return{skipWeekends:!!t,holidays:n&&n.length?new Set(n):void 0}},[e]),ae=(0,t.useCallback)((e,t)=>{if(!e||!t)return null;let n=e;for(let e of t.split(`.`)){if(n==null)return null;n=n[e]}if(n==null||n===``)return null;if(typeof n==`object`){let e=n;return String(e.id??e._id??e.value??e.name??``)}return String(n)},[]),oe=C?.quickFilters,[D,se]=(0,t.useState)({});(0,t.useEffect)(()=>{if(!oe?.length||!i||typeof i.find!=`function`)return;let e=b?.fields??{},t=!1;return(async()=>{let r={};for(let t of oe){if(t.options)continue;let a=e[t.field]??e[t.field.split(`.`)[0]],o=a?.type;if(o!==`lookup`&&o!==`master_detail`)continue;let s=a?.reference_to??a?.referenceTo;if(s)try{let e=(0,n.extractRecords)(await i.find(s,{$top:1e3}));r[t.field]=e.map(e=>({value:String(e.id??e._id??e.value??``),label:String(e.name??e.label??e.title??e.id??e._id??``)}))}catch(e){console.warn(`[ObjectGantt] Failed to load quick-filter options for "${t.field}":`,e)}}t||se(e=>({...e,...r}))})(),()=>{t=!0}},[JSON.stringify(oe),i,b]);let ce=(0,t.useMemo)(()=>{if(!oe?.length)return[];let e=b?.fields??{};return oe.map(t=>{let n=e[t.field]??e[t.field.split(`.`)[0]],r=t.label??n?.label??(0,c.humanizeLabel)(t.field),i=[];if(t.options?.length)i=t.options.map(e=>typeof e==`object`?{value:String(e.value),label:String(e.label??e.value)}:{value:String(e),label:String(e)});else if(Array.isArray(n?.options)&&n.options.length)i=n.options.map(e=>({value:String(e.value??e),label:String(e.label??e.value??e)}));else if(D[t.field]?.length)i=D[t.field];else{let e=new Map;for(let n of m){let r=ae(n,t.field);if(r!=null&&!e.has(r)){let i=n;for(let e of t.field.split(`.`))i=i?.[e];let a=i&&typeof i==`object`?String(i.name??i.label??i.title??r):r;e.set(r,a)}}i=[...e.entries()].map(([e,t])=>({value:e,label:t}))}return{field:t.field,label:r,options:i}})},[oe,b,D,m,ae]),[le,ue]=(0,t.useState)({}),de=(0,t.useCallback)((e,t)=>{ue(n=>({...n,[e]:t}))},[]),O=(0,t.useCallback)(()=>ue({}),[]),fe=(0,t.useMemo)(()=>{let e=Object.entries(le).filter(([,e])=>e.length>0);return e.length?T.filter(t=>e.every(([e,n])=>{let r=ae(t.data,e);return r!=null&&n.includes(r)})):T},[T,le,ae]),pe=(0,t.useMemo)(()=>{if(C?.autoZoomToFilter!==!1||!T.length)return null;let e=T[0].start.getTime(),t=T[0].end.getTime();for(let n of T)e=Math.min(e,n.start.getTime()),t=Math.max(t,n.end.getTime());return{start:new Date(e),end:new Date(t)}},[T,C?.autoZoomToFilter]),k=e.navigation??{mode:`drawer`,width:`min(960px, 60vw)`},me=k.mode===`drawer`||k.mode===`modal`||k.mode===`split`||k.mode===`popover`,A=(0,r.useNavigationOverlay)({navigation:k,objectName:e.objectName,onRowClick:me?void 0:f}),he=(0,t.useCallback)(async(t,n)=>{if(!C)return;let r=S?.provider===`object`?S.object:e.objectName;if(!r||!i||typeof i.update!=`function`)return;let{startDateField:a,endDateField:o,titleField:s,progressField:c}=C,l={};if(n.start instanceof Date&&(l[a]=n.start.toISOString()),n.end instanceof Date&&(l[o]=n.end.toISOString()),typeof n.title==`string`&&s&&(l[s]=n.title),typeof n.progress==`number`&&c&&(l[c]=n.progress),Object.keys(l).length===0)return;let u=t.data?.id??t.data?._id??t.id;if(u==null)return;let d=m;h(e=>e.map(e=>String(e.id??e._id)===String(u)?{...e,...l}:e));try{await i.update(r,String(u),l)}catch(e){console.error(`[ObjectGantt] Failed to persist task update:`,e),h(d)}},[C,S,i,e.objectName,m]),ge=(e,t)=>{let n=t.some(e=>typeof e==`object`&&e.type&&e.type!==`fs`);return!n&&typeof e==`string`?t.map(e=>String(typeof e==`object`?e.id:e)).join(`,`):n?t.map(e=>typeof e==`object`?e.type&&e.type!==`fs`?{id:e.id,type:e.type}:e.id:e):t.map(e=>typeof e==`object`?e.id:e)},_e=(0,t.useCallback)(async(t,n,r)=>{let a=C?.dependenciesField;if(!a)return;let o=S?.provider===`object`?S.object:e.objectName;if(!o||!i||typeof i.update!=`function`)return;let s=ge(n,r),c=m;h(e=>e.map(e=>String(e.id??e._id)===String(t)?{...e,[a]:s}:e));try{await i.update(o,String(t),{[a]:s})}catch(e){console.error(`[ObjectGantt] Failed to persist dependency:`,e),h(c)}},[C,S,i,e.objectName,m]),ve=(0,t.useCallback)(async(e,t,n=`fs`)=>{let r=e.data?.id??e.data?._id??e.id,i=t.data?.id??t.data?._id??t.id;if(r==null||i==null)return;let a=C?.dependenciesField;if(!a)return;let o=m.find(e=>String(e.id??e._id)===String(i))?.[a],s=Fe(o),c=e=>String(typeof e==`object`?e.id:e),l=s.find(e=>c(e)===String(r)),u=l&&typeof l==`object`?l.type??`fs`:`fs`;if(l&&u===n)return;let d=n===`fs`?r:{id:r,type:n};await _e(i,o,l?s.map(e=>c(e)===String(r)?d:e):[...s,d])},[C,m,_e]),ye=(0,t.useCallback)(async(e,t)=>{let n=e.data?.id??e.data?._id??e.id,r=t.data?.id??t.data?._id??t.id;if(n==null||r==null)return;let i=C?.dependenciesField;if(!i)return;let a=m.find(e=>String(e.id??e._id)===String(r))?.[i],o=Fe(a),s=e=>String(typeof e==`object`?e.id:e),c=o.filter(e=>s(e)!==String(n));c.length!==o.length&&await _e(r,a,c)},[C,m,_e]),[be,xe]=(0,t.useState)(null),[Ce,we]=(0,t.useState)(!1),j=(0,t.useCallback)(e=>{xe(e)},[]),Te=(0,t.useCallback)(async()=>{if(!be)return;let t=S?.provider===`object`?S.object:e.objectName;if(!t||!i?.delete){xe(null);return}let n=be.data?.id??be.data?._id??be.id;if(n==null){xe(null);return}we(!0);let r=m;h(e=>e.filter(e=>String(e.id??e._id)!==String(n)));try{await i.delete(t,String(n)),xe(null)}catch(e){console.error(`[ObjectGantt] Failed to delete:`,e),h(r),xe(null)}finally{we(!1)}},[be,S,i,e.objectName,m]);return g?(0,u.jsx)(`div`,{className:l,children:(0,u.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,u.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading Gantt chart...`})})}):v?(0,u.jsx)(`div`,{className:l,children:(0,u.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,u.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,v.message]})})}):C?(0,u.jsxs)(`div`,{className:l,children:[ce.length>0&&(0,u.jsx)(Me,{filters:ce,value:le,onChange:de,onClear:O,resultCount:fe.length,totalCount:T.length,labels:{all:`全部`,clear:`清除筛选`,empty:`无可选项`,resultSummary:(e,t)=>`显示 ${e} / ${t} 项任务`}}),(0,u.jsx)(`div`,{className:`h-[calc(100vh-200px)] min-h-[600px]`,children:C?.resourceView&&re?(0,u.jsx)(P,{tasks:fe,assignee:re,effort:E,capacity:C?.capacity??1,viewMode:e.viewMode||`day`}):(0,u.jsx)(Se,{tasks:fe,startDate:pe?.start,endDate:pe?.end,onTaskClick:e=>{A.handleClick(e.data),d?.(e.data)},onTaskUpdate:he,onTaskDelete:j,onDependencyCreate:C?.dependenciesField?ve:void 0,onDependencyDelete:C?.dependenciesField?ye:void 0,markers:e.markers,autoSchedule:!!C?.dependenciesField,rescheduleOnConflict:!!C?.dependenciesField,criticalPathDefault:!!e.criticalPath,workingCalendar:ie,showBaselines:e.showBaselines!==!1,readOnly:!!e.readOnly,mobileReadOnly:e.mobileReadOnly!==!1,persistLayoutKey:e.persistLayout===!1?void 0:`${e.objectName||(S?.provider===`object`?S.object:``)||`gantt`}:${e.viewName||`default`}`,groupBy:ne,defaultCollapsedDepth:C?.defaultCollapsedDepth,inlineEdit:!0})}),A.isOverlay&&A.isOpen&&A.selectedRecord&&(()=>{let t=S?.provider===`object`?S.object:e.objectName,n=A.selectedRecord,r=n.id??n._id;if(!t||r==null)return null;let a=C?.titleField?String(n[C.titleField]??`Task Details`):`Task Details`;return(0,u.jsx)(o.RecordDetailDrawer,{open:!0,onClose:A.close,title:a,record:n,objectName:t,recordId:r,dataSource:i,objectSchema:b,width:A.width,fullPageHref:(0,o.deriveRecordPageHref)(t,r)??void 0,onFieldSave:async(e,n)=>{i?.update&&(await i.update(t,String(r),{[e]:n}),h(t=>t.map(t=>String(t.id??t._id)===String(r)?{...t,[e]:n}:t)))},onDelete:async()=>{i?.delete&&(await i.delete(t,String(r)),h(e=>e.filter(e=>String(e.id??e._id)!==String(r))))}})})(),(0,u.jsx)(s.AlertDialog,{open:!!be,onOpenChange:e=>{!e&&!Ce&&xe(null)},children:(0,u.jsxs)(s.AlertDialogContent,{children:[(0,u.jsxs)(s.AlertDialogHeader,{children:[(0,u.jsx)(s.AlertDialogTitle,{children:`Delete this task?`}),(0,u.jsx)(s.AlertDialogDescription,{children:be?(0,u.jsxs)(u.Fragment,{children:[`"`,be.title,`" will be permanently removed. This action cannot be undone.`]}):null})]}),(0,u.jsxs)(s.AlertDialogFooter,{children:[(0,u.jsx)(s.AlertDialogCancel,{disabled:Ce,children:`Cancel`}),(0,u.jsx)(s.AlertDialogAction,{onClick:e=>{e.preventDefault(),Te()},disabled:Ce,"data-testid":`gantt-delete-confirm`,className:`bg-destructive text-destructive-foreground hover:bg-destructive/90`,children:Ce?`Deleting…`:`Delete`})]})]})})]}):(0,u.jsx)(`div`,{className:l,children:(0,u.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,u.jsx)(`div`,{className:`text-muted-foreground`,children:`Gantt configuration required. Please specify startDateField, endDateField, and titleField.`})})})},ze=({schema:e})=>{let{dataSource:t}=(0,r.useSchemaContext)()||{};return(0,u.jsx)(I,{schema:e,dataSource:t})};n.ComponentRegistry.register(`object-gantt`,ze,{namespace:`plugin-gantt`,label:`Object Gantt`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`gantt`,type:`object`,label:`Gantt Config`,description:`startDateField, endDateField, titleField, progressField, percentageField, colorField, dependenciesField`}]}),n.ComponentRegistry.register(`gantt`,ze,{namespace:`view`,label:`Gantt View`,category:`view`,inputs:[{name:`objectName`,type:`string`,label:`Object Name`,required:!0},{name:`gantt`,type:`object`,label:`Gantt Config`,description:`startDateField, endDateField, titleField, progressField, percentageField, colorField, dependenciesField`}]}),e.GanttView=Se,e.ObjectGantt=I,e.ObjectGanttRenderer=ze,e.QuickFilterBar=Me,e.ResourceWorkload=P,e.computeWorkload=we,e.normalizeDependencies=Fe,e.normalizeTaskType=Ne});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduling helpers for the Gantt — pure, side-effect-free functions over the
|
|
3
|
+
* task graph. Shared by two Phase 6 features:
|
|
4
|
+
*
|
|
5
|
+
* - `computeCriticalPath` — classic CPM (forward ES/EF + backward LS/LF
|
|
6
|
+
* passes) to find the zero-slack chain that drives the project end.
|
|
7
|
+
* - `computeProjectReschedule` — dependency-driven forward shifting: push
|
|
8
|
+
* successors later until every link constraint holds, preserving each
|
|
9
|
+
* task's duration. Tasks are only ever moved *later* (顺延), never pulled
|
|
10
|
+
* earlier, so the result is a minimal repair, not an ASAP recompute.
|
|
11
|
+
*
|
|
12
|
+
* Both treat the dependency on a task as a *predecessor* edge: if task B lists
|
|
13
|
+
* A in `dependencies`, the edge is A → B (A precedes B). Link types:
|
|
14
|
+
* fs finish→start B.start >= A.end (default)
|
|
15
|
+
* ss start →start B.start >= A.start
|
|
16
|
+
* ff finish→finish B.end >= A.end
|
|
17
|
+
* sf start →finish B.end >= A.start
|
|
18
|
+
*
|
|
19
|
+
* Summary (parent) tasks are derived rollups of their children, so they are
|
|
20
|
+
* never *moved* by the reschedule; they still act as fixed predecessor nodes
|
|
21
|
+
* using their current rolled-up dates.
|
|
22
|
+
*/
|
|
23
|
+
export type SchedLinkType = 'fs' | 'ss' | 'ff' | 'sf';
|
|
24
|
+
/**
|
|
25
|
+
* Working-calendar model. When supplied to the scheduling functions, durations
|
|
26
|
+
* are measured in *working* days and rescheduled tasks never start on a
|
|
27
|
+
* non-working day. Days are evaluated at UTC midnight granularity.
|
|
28
|
+
*/
|
|
29
|
+
export interface WorkingCalendar {
|
|
30
|
+
/** Treat Saturday/Sunday as non-working. */
|
|
31
|
+
skipWeekends?: boolean;
|
|
32
|
+
/** ISO `yyyy-mm-dd` (UTC) keys to treat as non-working (holidays). */
|
|
33
|
+
holidays?: Set<string>;
|
|
34
|
+
}
|
|
35
|
+
export interface SchedulableTask {
|
|
36
|
+
id: string | number;
|
|
37
|
+
start: Date;
|
|
38
|
+
end: Date;
|
|
39
|
+
dependencies?: Array<string | number | {
|
|
40
|
+
id: string | number;
|
|
41
|
+
type?: string;
|
|
42
|
+
}>;
|
|
43
|
+
parent?: string | number | null;
|
|
44
|
+
type?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface CriticalPathResult {
|
|
47
|
+
/** Ids of tasks on the critical path (zero slack). */
|
|
48
|
+
criticalIds: Set<string>;
|
|
49
|
+
/** Critical edges, keyed `predId->succId`. */
|
|
50
|
+
criticalEdges: Set<string>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Critical-path analysis via CPM. Durations come from each task's
|
|
54
|
+
* start/end span (in days, min 0). The forward/backward passes use
|
|
55
|
+
* finish-to-start semantics for every edge — the standard simplification for
|
|
56
|
+
* critical-path display; the four link types still all contribute edges to the
|
|
57
|
+
* longest-path graph. Returns the zero-slack task ids and the edges joining
|
|
58
|
+
* consecutive critical tasks.
|
|
59
|
+
*
|
|
60
|
+
* When a {@link WorkingCalendar} is supplied, durations are counted in working
|
|
61
|
+
* days (weekends/holidays excluded) so the longest path reflects real effort.
|
|
62
|
+
*/
|
|
63
|
+
export declare function computeCriticalPath(tasks: SchedulableTask[], cal?: WorkingCalendar): CriticalPathResult;
|
|
64
|
+
export interface RescheduleChange {
|
|
65
|
+
id: string;
|
|
66
|
+
start: Date;
|
|
67
|
+
end: Date;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Dependency-driven forward reschedule. Walks the graph in topological order
|
|
71
|
+
* and pushes each task as late as its predecessors require, preserving its
|
|
72
|
+
* duration and never moving it earlier than its current start. Summary tasks
|
|
73
|
+
* (parents) are treated as fixed rollup nodes — they constrain successors but
|
|
74
|
+
* are not themselves moved. Returns only the tasks whose dates change.
|
|
75
|
+
*
|
|
76
|
+
* When a {@link WorkingCalendar} is supplied, each task's duration is measured
|
|
77
|
+
* in working days and rescheduled tasks are snapped to start (and finish) on
|
|
78
|
+
* working days only — weekends/holidays are stepped over rather than consumed.
|
|
79
|
+
*
|
|
80
|
+
* Returns an empty array when the graph has a cycle (ambiguous ordering).
|
|
81
|
+
*/
|
|
82
|
+
export declare function computeProjectReschedule(tasks: SchedulableTask[], cal?: WorkingCalendar): RescheduleChange[];
|
|
83
|
+
//# sourceMappingURL=scheduling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduling.d.ts","sourceRoot":"","sources":["../src/scheduling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAuED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG;QAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/E,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkFD,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,8CAA8C;IAC9C,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,GAAG,CAAC,EAAE,eAAe,GAAG,kBAAkB,CAiFvG;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;CACX;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,GAAG,CAAC,EAAE,eAAe,GAAG,gBAAgB,EAAE,CAkF5G"}
|
package/dist/{packages/plugin-gantt/src/useGanttTranslation.d.ts → useGanttTranslation.d.ts}
RENAMED
|
@@ -8,15 +8,12 @@
|
|
|
8
8
|
/**
|
|
9
9
|
* Default English translations for ObjectGantt. Mirrors the
|
|
10
10
|
* createSafeTranslationHook pattern used by plugin-detail / plugin-timeline so
|
|
11
|
-
* the Gantt keeps working when rendered standalone (
|
|
11
|
+
* the Gantt keeps working when rendered standalone (unit tests, embed)
|
|
12
12
|
* without an I18nProvider on the React tree.
|
|
13
13
|
*/
|
|
14
14
|
export declare const GANTT_DEFAULT_TRANSLATIONS: Record<string, string>;
|
|
15
|
-
declare function fallback(key: string, options?: Record<string, unknown>): string;
|
|
16
15
|
export declare function useGanttTranslation(): {
|
|
17
|
-
t:
|
|
18
|
-
|
|
19
|
-
t: import('i18next').TFunction<string, undefined>;
|
|
16
|
+
t: (key: string, options?: Record<string, unknown>) => string;
|
|
17
|
+
language: string | undefined;
|
|
20
18
|
};
|
|
21
|
-
export {};
|
|
22
19
|
//# sourceMappingURL=useGanttTranslation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useGanttTranslation.d.ts","sourceRoot":"","sources":["../src/useGanttTranslation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyD7D,CAAC;AAYF,wBAAgB,mBAAmB;aAgBf,MAAM,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM;;EAYrE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Resource / workload model (资源/工作负载视图).
|
|
10
|
+
*
|
|
11
|
+
* Pure, framework-free aggregation that turns a flat task list into a
|
|
12
|
+
* per-resource, per-time-column load histogram. The renderer (ResourceWorkload)
|
|
13
|
+
* draws bars from this; keeping the math here makes it unit-testable and reused
|
|
14
|
+
* identically by the demo and ObjectGantt.
|
|
15
|
+
*
|
|
16
|
+
* Load model — for each resource R and column C:
|
|
17
|
+
* load(R,C) = Σ effort(task) over tasks assigned to R that overlap C
|
|
18
|
+
* A column is "overloaded" when its load exceeds the resource capacity. `effort`
|
|
19
|
+
* defaults to 1 (one full unit of capacity per concurrently-active task) and
|
|
20
|
+
* `capacity` defaults to 1, so out of the box the histogram simply counts
|
|
21
|
+
* concurrent tasks and flags any double-booking (load > 1) as overload.
|
|
22
|
+
*/
|
|
23
|
+
export interface WorkloadColumn {
|
|
24
|
+
/** Inclusive start of the column's time span. */
|
|
25
|
+
start: Date;
|
|
26
|
+
/** Exclusive end of the column's time span. */
|
|
27
|
+
end: Date;
|
|
28
|
+
}
|
|
29
|
+
export interface WorkloadOptions<T> {
|
|
30
|
+
/**
|
|
31
|
+
* Resource accessor — the person/team/machine a task loads. Return null to
|
|
32
|
+
* route the task into the "unassigned" bucket.
|
|
33
|
+
*/
|
|
34
|
+
assignee: (task: T) => {
|
|
35
|
+
key: string | number;
|
|
36
|
+
label: string;
|
|
37
|
+
} | null;
|
|
38
|
+
/**
|
|
39
|
+
* Capacity units a task consumes per column while active. Default 1 (a task
|
|
40
|
+
* fully occupies its resource). Use e.g. 0.5 for a half-time allocation.
|
|
41
|
+
*/
|
|
42
|
+
effort?: (task: T) => number;
|
|
43
|
+
/**
|
|
44
|
+
* Per-resource capacity ceiling. A number applies to every resource; a
|
|
45
|
+
* function can vary it per key. Default 1. Loads above this flag overload.
|
|
46
|
+
*/
|
|
47
|
+
capacity?: number | ((key: string) => number);
|
|
48
|
+
/** Label for the bucket of tasks whose `assignee` returns null. */
|
|
49
|
+
unassignedLabel?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface ResourceCell {
|
|
52
|
+
/** Summed effort of overlapping tasks in this column. */
|
|
53
|
+
load: number;
|
|
54
|
+
/** Capacity ceiling for this resource. */
|
|
55
|
+
capacity: number;
|
|
56
|
+
/** load > capacity. */
|
|
57
|
+
overloaded: boolean;
|
|
58
|
+
}
|
|
59
|
+
export interface ResourceLoad {
|
|
60
|
+
key: string;
|
|
61
|
+
label: string;
|
|
62
|
+
capacity: number;
|
|
63
|
+
cells: ResourceCell[];
|
|
64
|
+
/** Highest single-column load — drives the histogram's vertical scale. */
|
|
65
|
+
peak: number;
|
|
66
|
+
/** How many columns are overloaded — a quick "is this resource hot" badge. */
|
|
67
|
+
overloadedCount: number;
|
|
68
|
+
}
|
|
69
|
+
export declare function computeWorkload<T extends {
|
|
70
|
+
start: Date;
|
|
71
|
+
end: Date;
|
|
72
|
+
}>(tasks: T[], columns: WorkloadColumn[], opts: WorkloadOptions<T>): ResourceLoad[];
|
|
73
|
+
//# sourceMappingURL=workload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workload.d.ts","sourceRoot":"","sources":["../src/workload.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,cAAc;IAC7B,iDAAiD;IACjD,KAAK,EAAE,IAAI,CAAC;IACZ,+CAA+C;IAC/C,GAAG,EAAE,IAAI,CAAC;CACX;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC;;;OAGG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK;QAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACtE;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;IAC9C,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,eAAe,EAAE,MAAM,CAAC;CACzB;AAYD,wBAAgB,eAAe,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,EAClE,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,EAAE,cAAc,EAAE,EACzB,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,GACvB,YAAY,EAAE,CAuChB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/plugin-gantt",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Gantt chart plugin for Object UI",
|
|
@@ -24,26 +24,27 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@objectstack/spec": "^
|
|
28
|
-
"lucide-react": "^1.
|
|
29
|
-
"@object-ui/components": "
|
|
30
|
-
"@object-ui/core": "
|
|
31
|
-
"@object-ui/fields": "
|
|
32
|
-
"@object-ui/
|
|
33
|
-
"@object-ui/
|
|
34
|
-
"@object-ui/
|
|
27
|
+
"@objectstack/spec": "^10.0.0",
|
|
28
|
+
"lucide-react": "^1.21.0",
|
|
29
|
+
"@object-ui/components": "7.0.0",
|
|
30
|
+
"@object-ui/core": "7.0.0",
|
|
31
|
+
"@object-ui/fields": "7.0.0",
|
|
32
|
+
"@object-ui/i18n": "7.0.0",
|
|
33
|
+
"@object-ui/plugin-detail": "7.0.0",
|
|
34
|
+
"@object-ui/react": "7.0.0",
|
|
35
|
+
"@object-ui/types": "7.0.0"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
38
|
"react": "^18.0.0 || ^19.0.0",
|
|
38
39
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
|
-
"@types/react": "19.2.
|
|
42
|
+
"@types/react": "19.2.17",
|
|
42
43
|
"@types/react-dom": "19.2.3",
|
|
43
44
|
"@vitejs/plugin-react": "^6.0.2",
|
|
44
45
|
"typescript": "^6.0.3",
|
|
45
|
-
"vite": "^8.0.
|
|
46
|
-
"vite-plugin-dts": "^5.0.
|
|
46
|
+
"vite": "^8.0.16",
|
|
47
|
+
"vite-plugin-dts": "^5.0.2"
|
|
47
48
|
},
|
|
48
49
|
"keywords": [
|
|
49
50
|
"objectui",
|