@object-ui/plugin-gantt 4.0.6 → 4.0.8

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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # @object-ui/plugin-gantt
2
2
 
3
+ ## 4.0.8
4
+
5
+ ### Patch Changes
6
+
7
+ - @object-ui/components@4.0.8
8
+ - @object-ui/fields@4.0.8
9
+ - @object-ui/react@4.0.8
10
+ - @object-ui/plugin-detail@4.0.8
11
+ - @object-ui/types@4.0.8
12
+ - @object-ui/core@4.0.8
13
+
14
+ ## 4.0.7
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [7c9b85c]
19
+ - @object-ui/core@4.0.7
20
+ - @object-ui/react@4.0.7
21
+ - @object-ui/components@4.0.7
22
+ - @object-ui/fields@4.0.7
23
+ - @object-ui/types@4.0.7
24
+
3
25
  ## 4.0.6
4
26
 
5
27
  ### Patch Changes
package/README.md CHANGED
@@ -5,12 +5,74 @@ Gantt chart plugin for Object UI - Visualize project timelines and task dependen
5
5
  ## Features
6
6
 
7
7
  - **Gantt Charts** - Interactive Gantt chart visualization
8
+ - **Full CRUD on the timeline** - Create via toolbar quick-create dialog, edit
9
+ inline or via drag, delete via row kebab → confirmation dialog, view detail
10
+ via click → navigation overlay
11
+ - **Drag-and-drop rescheduling** - Drag a bar to move it; drag either edge to resize
12
+ start/end (snaps to whole days, persists via `dataSource.update`)
8
13
  - **Task Dependencies** - Link tasks with dependencies
9
14
  - **Timeline View** - Visualize project schedules
10
15
  - **Task Management** - Create, edit, and track tasks
11
16
  - **Responsive** - Scrollable timeline for large projects
12
17
  - **Customizable** - Tailwind CSS styling support
13
18
 
19
+ ### Create / Edit / Delete / View
20
+
21
+ When used through `ObjectGantt` (the wiring the framework uses for the
22
+ `gantt` view type) the full CRUD lifecycle is wired automatically:
23
+
24
+ - **Create** — click the toolbar "+ New Task" button. A small dialog opens
25
+ pre-filled with start/end (today → +7 days). On submit the component calls
26
+ `dataSource.create(objectName, { [titleField], [startDateField],
27
+ [endDateField], …required fields })` and optimistically inserts the new
28
+ record into the chart.
29
+ - **Edit** — drag the bar (move), drag an edge (resize), or hover the row
30
+ and pick **Edit inline** from the kebab menu to rename / change dates
31
+ inline. All paths funnel through `dataSource.update`.
32
+ - **Delete** — hover a row, open the kebab menu, choose **Delete**. A
33
+ shadcn `<AlertDialog>` asks for confirmation; on confirm `dataSource.delete`
34
+ removes the record (optimistic local removal, reverts on failure).
35
+ - **View / Edit / Delete in a side drawer** — click anywhere on a row
36
+ (or pick **View details** in the kebab) to open a right-side drawer
37
+ containing the standard `<DetailView>` from `@object-ui/plugin-detail`.
38
+ The drawer ships the same record-header chrome used everywhere else
39
+ (badges, summary chips, **Edit** + **Inline edit** buttons, and a
40
+ **…** more-actions menu with **Delete**). Edits via inline-edit save
41
+ through `dataSource.update` and merge into the local timeline state;
42
+ delete confirms via the platform standard dialog and removes the row
43
+ on success. Fields are auto-derived from the record (object schema is
44
+ fetched by `DetailView` itself when `dataSource.getObjectSchema` is
45
+ available).
46
+
47
+ Override by setting `navigation` on the schema, e.g.
48
+ `{ mode: 'page', basePath: '/console/apps/.../campaign' }` to route
49
+ to the standalone detail page instead.
50
+
51
+
52
+ ### Drag-and-drop rescheduling
53
+
54
+ When the renderer is used through `ObjectGantt` (the standard wiring used by
55
+ the framework's `gantt` view type) drag is enabled automatically: each bar
56
+ shows a grab cursor; the body drags the entire task, and the two thin edge
57
+ zones (≈6px) resize start or end. Pointer motion snaps to whole days using
58
+ the current column width. On release `ObjectGantt` issues an optimistic local
59
+ patch and a `dataSource.update(objectName, recordId, { [startDateField]: …,
60
+ [endDateField]: … })`. If the request fails the local state is reverted.
61
+
62
+ When you embed the lower-level `<GanttView>` directly, pass `onTaskUpdate`
63
+ to opt in:
64
+
65
+ ```tsx
66
+ <GanttView
67
+ tasks={tasks}
68
+ onTaskUpdate={(task, { start, end }) => {
69
+ // start/end are JS Date objects already snapped to whole days,
70
+ // and the resize-left/right cases clamp so end - start >= 1 day.
71
+ save(task.id, { start, end });
72
+ }}
73
+ />
74
+ ```
75
+
14
76
  ## Installation
15
77
 
16
78
  ```bash
package/dist/index.js CHANGED
@@ -1,35 +1,98 @@
1
1
  import * as e from "react";
2
- import { useEffect as t, useMemo as n, useState as r } from "react";
3
- import { ComponentRegistry as i, buildExpandFields as a, extractRecords as o } from "@object-ui/core";
4
- import { useNavigationOverlay as s, useSchemaContext as c } from "@object-ui/react";
5
- import { GanttConfigSchema as l } from "@objectstack/spec/ui";
6
- import { Button as u, NavigationOverlay as d, Select as f, SelectContent as p, SelectItem as m, SelectTrigger as h, SelectValue as g, cn as _, useResizeObserver as v } from "@object-ui/components";
7
- import { CalendarDays as y, ChevronLeft as b, ChevronRight as x, PanelLeft as S, PanelLeftClose as C, Plus as w, ZoomIn as T, ZoomOut as E } from "lucide-react";
8
- import { jsx as D, jsxs as O } from "react/jsx-runtime";
2
+ import { useCallback as t, useEffect as n, useMemo as r, useState as i } from "react";
3
+ import { ComponentRegistry as a, buildExpandFields as o, extractRecords as s } from "@object-ui/core";
4
+ import { useNavigationOverlay as c, useSchemaContext as l } from "@object-ui/react";
5
+ import { GanttConfigSchema as u } from "@objectstack/spec/ui";
6
+ import { RecordDetailDrawer as d, deriveRecordPageHref as f } from "@object-ui/plugin-detail";
7
+ import { AlertDialog as p, AlertDialogAction as m, AlertDialogCancel as ee, AlertDialogContent as te, AlertDialogDescription as h, AlertDialogFooter as g, AlertDialogHeader as _, AlertDialogTitle as v, Button as y, cn as b, useResizeObserver as x } from "@object-ui/components";
8
+ import { CalendarDays as S, ChevronLeft as C, ChevronRight as w, PanelLeft as T, PanelLeftClose as ne, ZoomIn as E, ZoomOut as re } from "lucide-react";
9
+ import { Fragment as D, jsx as O, jsxs as k } from "react/jsx-runtime";
9
10
  //#region src/GanttView.tsx
10
- function ee(e) {
11
+ function A(e) {
11
12
  return e < 640 ? 35 : e < 1024 ? 50 : 60;
12
13
  }
13
- function te(e) {
14
- return e < 640 ? 120 : e < 1024 ? 200 : 300;
14
+ function j(e) {
15
+ return e < 640 ? 140 : e < 1024 ? 220 : 320;
16
+ }
17
+ function M(e) {
18
+ return e >= 280;
15
19
  }
16
- function k(e) {
20
+ function N(e) {
17
21
  return e < 640 ? 32 : 40;
18
22
  }
19
- function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskClick: a, onTaskUpdate: o, onViewChange: s, onAddClick: c, className: l, inlineEdit: d = !1 }) {
20
- let [A, j] = e.useState(/* @__PURE__ */ new Date()), M = e.useRef(null), { width: N } = v(M), P = N || (typeof window < "u" ? window.innerWidth : 1024), F = P < 640, I = k(P), ne = ee(P), [re, L] = e.useState(null), R = re ?? ne, [z, B] = e.useState(!1), V = e.useRef(!1);
23
+ function P({ tasks: t, startDate: n, endDate: r, onTaskClick: i, onTaskUpdate: a, className: o, inlineEdit: s = !1 }) {
24
+ let [c, l] = e.useState(/* @__PURE__ */ new Date()), u = e.useRef(null), { width: d } = x(u), f = d || (typeof window < "u" ? window.innerWidth : 1024), p = f < 640, m = N(f), ee = A(f), [te, h] = e.useState(null), g = te ?? ee, [_, v] = e.useState(!1), P = e.useRef(!1);
21
25
  e.useEffect(() => {
22
- !V.current && F && (B(!0), V.current = !0);
23
- }, [F]);
24
- let H = z ? 0 : te(P), [U, W] = e.useState(null), [G, K] = e.useState({}), q = e.useMemo(() => {
25
- let e = r ? new Date(r) : /* @__PURE__ */ new Date(), n = i ? new Date(i) : /* @__PURE__ */ new Date();
26
- return !r && t.length > 0 && (e = new Date(Math.min(...t.map((e) => e.start.getTime()))), e.setDate(e.getDate() - 7)), !i && t.length > 0 && (n = new Date(Math.max(...t.map((e) => e.end.getTime()))), n.setDate(n.getDate() + 14)), e.setHours(0, 0, 0, 0), n.setHours(23, 59, 59, 999), {
26
+ !P.current && p && (v(!0), P.current = !0);
27
+ }, [p]);
28
+ let F = _ ? 0 : j(f), I = M(F), [L, R] = e.useState(null), [z, B] = e.useState({}), [V, H] = e.useState(null), U = e.useRef(null);
29
+ e.useEffect(() => {
30
+ U.current = V;
31
+ }, [V]);
32
+ let W = e.useRef(!1), G = e.useCallback((e) => {
33
+ let t = 1e3 * 60 * 60 * 24, n = t, r = e.dayDelta * t, i = new Date(e.originStart), a = new Date(e.originEnd);
34
+ 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))), {
35
+ start: i,
36
+ end: a
37
+ };
38
+ }, []);
39
+ e.useEffect(() => {
40
+ if (!V) return;
41
+ let e = (e) => {
42
+ let t = U.current;
43
+ if (!t) return;
44
+ let n = Math.round((e.clientX - t.originClientX) / Math.max(g, 1));
45
+ n !== t.dayDelta && H({
46
+ ...t,
47
+ dayDelta: n
48
+ });
49
+ }, n = () => {
50
+ let e = U.current;
51
+ if (e) {
52
+ if (e.dayDelta !== 0) {
53
+ let n = t.find((t) => t.id === e.taskId);
54
+ if (n && a) {
55
+ let { start: t, end: r } = G(e);
56
+ a(n, {
57
+ start: t,
58
+ end: r
59
+ });
60
+ }
61
+ W.current = !0, window.setTimeout(() => {
62
+ W.current = !1;
63
+ }, 0);
64
+ }
65
+ H(null);
66
+ }
67
+ };
68
+ return window.addEventListener("pointermove", e), window.addEventListener("pointerup", n), window.addEventListener("pointercancel", n), () => {
69
+ window.removeEventListener("pointermove", e), window.removeEventListener("pointerup", n), window.removeEventListener("pointercancel", n);
70
+ };
71
+ }, [
72
+ V,
73
+ g,
74
+ t,
75
+ a,
76
+ G
77
+ ]);
78
+ let K = e.useCallback((e, t, n) => {
79
+ a && (n.stopPropagation(), n.preventDefault(), H({
80
+ taskId: e.id,
81
+ mode: t,
82
+ originStart: new Date(e.start),
83
+ originEnd: new Date(e.end),
84
+ originClientX: n.clientX,
85
+ dayDelta: 0
86
+ }));
87
+ }, [a]), q = e.useMemo(() => {
88
+ let e = n ? new Date(n) : /* @__PURE__ */ new Date(), i = r ? new Date(r) : /* @__PURE__ */ new Date();
89
+ return !n && t.length > 0 && (e = new Date(Math.min(...t.map((e) => e.start.getTime()))), e.setDate(e.getDate() - 7)), !r && t.length > 0 && (i = new Date(Math.max(...t.map((e) => e.end.getTime()))), i.setDate(i.getDate() + 14)), e.setHours(0, 0, 0, 0), i.setHours(23, 59, 59, 999), {
27
90
  start: e,
28
- end: n
91
+ end: i
29
92
  };
30
93
  }, [
94
+ n,
31
95
  r,
32
- i,
33
96
  t
34
97
  ]), J = e.useMemo(() => {
35
98
  let e = [], t = new Date(q.start);
@@ -44,21 +107,21 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
44
107
  let t = e.touches[0].clientX - e.touches[1].clientX, n = e.touches[0].clientY - e.touches[1].clientY;
45
108
  Q.current = {
46
109
  baseDistance: Math.max(1, Math.sqrt(t * t + n * n)),
47
- baseColumn: R
110
+ baseColumn: g
48
111
  };
49
112
  }
50
- }, [R]), oe = e.useCallback((e) => {
113
+ }, [g]), oe = e.useCallback((e) => {
51
114
  if (e.touches.length !== 2 || !Q.current) return;
52
115
  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)) / Q.current.baseDistance;
53
- L(Math.max(15, Math.min(120, Math.round(Q.current.baseColumn * r))));
116
+ h(Math.max(15, Math.min(120, Math.round(Q.current.baseColumn * r))));
54
117
  }, []), se = e.useCallback(() => {
55
118
  Q.current = null;
56
119
  }, []), $ = e.useMemo(() => {
57
120
  let e = /* @__PURE__ */ new Date();
58
121
  if (e < q.start || e > q.end) return null;
59
122
  let t = (e.getTime() - q.start.getTime()) / (1440 * 60 * 1e3);
60
- return Math.round(t * R);
61
- }, [q, R]), ce = e.useCallback(() => {
123
+ return Math.round(t * g);
124
+ }, [q, g]), ce = e.useCallback(() => {
62
125
  if ($ == null || !Z.current) return;
63
126
  let e = Math.max(0, $ - Z.current.clientWidth / 2);
64
127
  Z.current.scrollTo({
@@ -69,53 +132,35 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
69
132
  Y.current && (Y.current.scrollLeft = e.currentTarget.scrollLeft), X.current && (X.current.scrollTop = e.currentTarget.scrollTop);
70
133
  }, ue = (e) => {
71
134
  q.end.getTime() - q.start.getTime();
72
- let t = R, n = 1e3 * 60 * 60 * 24, r = e.start.getTime() - q.start.getTime(), i = e.end.getTime() - e.start.getTime();
135
+ let t = g, n = 1e3 * 60 * 60 * 24, r = e.start.getTime() - q.start.getTime(), i = e.end.getTime() - e.start.getTime();
73
136
  return {
74
137
  left: r / n * t,
75
138
  width: Math.max(i / n * t, t)
76
139
  };
77
140
  };
78
- return /* @__PURE__ */ O("div", {
79
- ref: M,
80
- className: _("flex flex-col h-full bg-background border rounded-lg overflow-hidden min-w-0", l),
81
- children: [/* @__PURE__ */ O("div", {
141
+ return /* @__PURE__ */ k("div", {
142
+ ref: u,
143
+ className: b("flex flex-col h-full bg-background border rounded-lg overflow-hidden min-w-0", o),
144
+ children: [/* @__PURE__ */ k("div", {
82
145
  className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 p-2 border-b bg-card",
83
- children: [/* @__PURE__ */ O("div", {
146
+ children: [/* @__PURE__ */ k("div", {
84
147
  className: "flex items-center gap-2",
85
148
  children: [
86
- /* @__PURE__ */ O(u, {
87
- variant: "outline",
88
- size: "sm",
89
- onClick: () => c?.(),
90
- "aria-label": "Create new task",
91
- children: [
92
- /* @__PURE__ */ D(w, { className: "h-4 w-4 mr-1 sm:mr-2" }),
93
- /* @__PURE__ */ D("span", {
94
- className: "hidden sm:inline",
95
- children: "New Task"
96
- }),
97
- /* @__PURE__ */ D("span", {
98
- className: "sm:hidden",
99
- children: "New"
100
- })
101
- ]
102
- }),
103
- /* @__PURE__ */ D("div", { className: "h-4 w-px bg-border mx-1 sm:mx-2" }),
104
- /* @__PURE__ */ D(u, {
149
+ /* @__PURE__ */ O(y, {
105
150
  variant: "ghost",
106
151
  size: "icon",
107
152
  className: "h-8 w-8",
108
153
  "aria-label": "Previous period",
109
- children: /* @__PURE__ */ D(b, { className: "h-4 w-4" })
154
+ children: /* @__PURE__ */ O(C, { className: "h-4 w-4" })
110
155
  }),
111
- /* @__PURE__ */ D(u, {
156
+ /* @__PURE__ */ O(y, {
112
157
  variant: "ghost",
113
158
  size: "icon",
114
159
  className: "h-8 w-8",
115
160
  "aria-label": "Next period",
116
- children: /* @__PURE__ */ D(x, { className: "h-4 w-4" })
161
+ children: /* @__PURE__ */ O(w, { className: "h-4 w-4" })
117
162
  }),
118
- /* @__PURE__ */ D("span", {
163
+ /* @__PURE__ */ O("span", {
119
164
  className: "font-semibold text-xs sm:text-sm",
120
165
  children: q.start.toLocaleDateString(void 0, {
121
166
  month: "long",
@@ -123,63 +168,38 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
123
168
  })
124
169
  })
125
170
  ]
126
- }), /* @__PURE__ */ O("div", {
171
+ }), /* @__PURE__ */ k("div", {
127
172
  className: "flex items-center gap-2",
128
173
  children: [
129
- /* @__PURE__ */ O(f, {
130
- value: n,
131
- onValueChange: (e) => s?.(e),
132
- children: [/* @__PURE__ */ D(h, {
133
- className: "w-[100px] sm:w-[120px] h-8",
134
- children: /* @__PURE__ */ D(g, {})
135
- }), /* @__PURE__ */ O(p, { children: [
136
- /* @__PURE__ */ D(m, {
137
- value: "day",
138
- children: "Day View"
139
- }),
140
- /* @__PURE__ */ D(m, {
141
- value: "week",
142
- children: "Week View"
143
- }),
144
- /* @__PURE__ */ D(m, {
145
- value: "month",
146
- children: "Month View"
147
- }),
148
- /* @__PURE__ */ D(m, {
149
- value: "quarter",
150
- children: "Quarter View"
151
- })
152
- ] })]
153
- }),
154
- /* @__PURE__ */ O("div", {
174
+ /* @__PURE__ */ k("div", {
155
175
  className: "flex bg-muted rounded-md p-1",
156
- children: [/* @__PURE__ */ D(u, {
176
+ children: [/* @__PURE__ */ O(y, {
157
177
  variant: "ghost",
158
178
  size: "icon",
159
179
  className: "h-6 w-6",
160
- onClick: () => L(Math.max(15, R - 10)),
180
+ onClick: () => h(Math.max(15, g - 10)),
161
181
  "aria-label": "Zoom out",
162
- children: /* @__PURE__ */ D(E, { className: "h-3 w-3" })
163
- }), /* @__PURE__ */ D(u, {
182
+ children: /* @__PURE__ */ O(re, { className: "h-3 w-3" })
183
+ }), /* @__PURE__ */ O(y, {
164
184
  variant: "ghost",
165
185
  size: "icon",
166
186
  className: "h-6 w-6",
167
- onClick: () => L(Math.min(120, R + 10)),
187
+ onClick: () => h(Math.min(120, g + 10)),
168
188
  "aria-label": "Zoom in",
169
- children: /* @__PURE__ */ D(T, { className: "h-3 w-3" })
189
+ children: /* @__PURE__ */ O(E, { className: "h-3 w-3" })
170
190
  })]
171
191
  }),
172
- /* @__PURE__ */ D(u, {
192
+ /* @__PURE__ */ O(y, {
173
193
  variant: "ghost",
174
194
  size: "icon",
175
195
  className: "h-8 w-8",
176
- onClick: () => B((e) => !e),
177
- "aria-label": z ? "Show task list" : "Hide task list",
178
- "aria-pressed": z,
196
+ onClick: () => v((e) => !e),
197
+ "aria-label": _ ? "Show task list" : "Hide task list",
198
+ "aria-pressed": _,
179
199
  "data-testid": "gantt-toggle-task-list",
180
- children: D(z ? S : C, { className: "h-4 w-4" })
200
+ children: O(_ ? T : ne, { className: "h-4 w-4" })
181
201
  }),
182
- /* @__PURE__ */ D(u, {
202
+ /* @__PURE__ */ O(y, {
183
203
  variant: "ghost",
184
204
  size: "icon",
185
205
  className: "h-8 w-8",
@@ -187,73 +207,69 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
187
207
  disabled: $ == null,
188
208
  "aria-label": "Jump to today",
189
209
  "data-testid": "gantt-jump-today",
190
- children: /* @__PURE__ */ D(y, { className: "h-4 w-4" })
210
+ children: /* @__PURE__ */ O(S, { className: "h-4 w-4" })
191
211
  })
192
212
  ]
193
213
  })]
194
- }), /* @__PURE__ */ O("div", {
214
+ }), /* @__PURE__ */ k("div", {
195
215
  className: "flex flex-col flex-1 overflow-hidden",
196
- children: [/* @__PURE__ */ O("div", {
216
+ children: [/* @__PURE__ */ k("div", {
197
217
  className: "flex border-b bg-muted/30 shrink-0 h-10 sm:h-[50px]",
198
- children: [/* @__PURE__ */ O("div", {
218
+ children: [/* @__PURE__ */ k("div", {
199
219
  className: "flex items-center font-medium text-xs text-muted-foreground px-2 sm:px-4 border-r bg-card z-20 shadow-sm",
200
220
  style: {
201
- width: H,
202
- minWidth: H
221
+ width: F,
222
+ minWidth: F
203
223
  },
204
- children: [
205
- /* @__PURE__ */ D("div", {
206
- className: "flex-1",
207
- children: "Task Name"
208
- }),
209
- /* @__PURE__ */ D("div", {
210
- className: "w-16 sm:w-20 text-right hidden sm:block",
211
- children: "Start"
212
- }),
213
- /* @__PURE__ */ D("div", {
214
- className: "w-16 sm:w-20 text-right hidden sm:block",
215
- children: "End"
216
- })
217
- ]
218
- }), /* @__PURE__ */ D("div", {
224
+ children: [/* @__PURE__ */ O("div", {
225
+ className: "flex-1 truncate",
226
+ children: "Task Name"
227
+ }), I && /* @__PURE__ */ k(D, { children: [/* @__PURE__ */ O("div", {
228
+ className: "w-16 sm:w-20 text-right",
229
+ children: "Start"
230
+ }), /* @__PURE__ */ O("div", {
231
+ className: "w-16 sm:w-20 text-right",
232
+ children: "End"
233
+ })] })]
234
+ }), /* @__PURE__ */ O("div", {
219
235
  className: "flex-1 overflow-hidden",
220
236
  ref: Y,
221
- children: /* @__PURE__ */ D("div", {
237
+ children: /* @__PURE__ */ O("div", {
222
238
  className: "flex h-full",
223
- style: { width: J.length * R },
224
- children: J.map((e, t) => /* @__PURE__ */ O("div", {
225
- className: _("flex flex-col items-center justify-center border-r text-xs text-muted-foreground h-full", e.isWeekend && "bg-muted/50"),
239
+ style: { width: J.length * g },
240
+ children: J.map((e, t) => /* @__PURE__ */ k("div", {
241
+ className: b("flex flex-col items-center justify-center border-r text-xs text-muted-foreground h-full", e.isWeekend && "bg-muted/50"),
226
242
  style: {
227
- width: R,
228
- minWidth: R
243
+ width: g,
244
+ minWidth: g
229
245
  },
230
- children: [/* @__PURE__ */ D("span", {
246
+ children: [/* @__PURE__ */ O("span", {
231
247
  className: "font-medium text-foreground",
232
248
  children: e.label
233
- }), /* @__PURE__ */ D("span", {
249
+ }), /* @__PURE__ */ O("span", {
234
250
  className: "text-[10px] opacity-70",
235
251
  children: e.date.toLocaleDateString(void 0, { weekday: "narrow" })
236
252
  })]
237
253
  }, t))
238
254
  })
239
255
  })]
240
- }), /* @__PURE__ */ O("div", {
256
+ }), /* @__PURE__ */ k("div", {
241
257
  className: "flex flex-1 overflow-hidden",
242
- children: [/* @__PURE__ */ D("div", {
258
+ children: [/* @__PURE__ */ O("div", {
243
259
  className: "overflow-hidden border-r bg-card z-10 shadow-sm",
244
260
  ref: X,
245
261
  style: {
246
- width: H,
247
- minWidth: H
262
+ width: F,
263
+ minWidth: F
248
264
  },
249
265
  children: t.map((e) => {
250
- let t = d && U === e.id;
251
- return /* @__PURE__ */ O("div", {
252
- className: "flex items-center border-b px-2 sm:px-4 hover:bg-accent/50 cursor-pointer transition-colors touch-manipulation",
253
- style: { height: I },
254
- onClick: () => !t && a?.(e),
266
+ let t = s && L === e.id;
267
+ return /* @__PURE__ */ k("div", {
268
+ className: "group/task-row flex items-center border-b px-2 sm:px-4 hover:bg-accent/50 cursor-pointer transition-colors touch-manipulation",
269
+ style: { height: m },
270
+ onClick: () => !t && i?.(e),
255
271
  onDoubleClick: () => {
256
- d && o && (W(e.id), K({
272
+ s && a && (R(e.id), B({
257
273
  title: e.title,
258
274
  start: e.start.toLocaleDateString("en-CA"),
259
275
  end: e.end.toLocaleDateString("en-CA"),
@@ -261,34 +277,34 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
261
277
  }));
262
278
  },
263
279
  children: [
264
- /* @__PURE__ */ O("div", {
280
+ /* @__PURE__ */ k("div", {
265
281
  className: "flex-1 truncate font-medium text-xs sm:text-sm flex items-center gap-2",
266
- children: [/* @__PURE__ */ D("div", {
282
+ children: [/* @__PURE__ */ O("div", {
267
283
  className: "w-2 h-2 rounded-full shrink-0",
268
284
  style: { backgroundColor: e.color || "#3b82f6" }
269
- }), t ? /* @__PURE__ */ D("input", {
285
+ }), t ? /* @__PURE__ */ O("input", {
270
286
  className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
271
- value: G.title || "",
272
- onChange: (e) => K((t) => ({
287
+ value: z.title || "",
288
+ onChange: (e) => B((t) => ({
273
289
  ...t,
274
290
  title: e.target.value
275
291
  })),
276
292
  onKeyDown: (t) => {
277
- t.key === "Enter" ? (o?.(e, {
278
- title: G.title,
279
- start: new Date(G.start),
280
- end: new Date(G.end),
281
- progress: Number(G.progress) || 0
282
- }), W(null)) : t.key === "Escape" && W(null);
293
+ t.key === "Enter" ? (a?.(e, {
294
+ title: z.title,
295
+ start: new Date(z.start),
296
+ end: new Date(z.end),
297
+ progress: Number(z.progress) || 0
298
+ }), R(null)) : t.key === "Escape" && R(null);
283
299
  },
284
300
  onClick: (e) => e.stopPropagation(),
285
301
  autoFocus: !0
286
- }) : /* @__PURE__ */ O("span", {
302
+ }) : /* @__PURE__ */ k("span", {
287
303
  className: "flex flex-col min-w-0",
288
- children: [/* @__PURE__ */ D("span", {
304
+ children: [/* @__PURE__ */ O("span", {
289
305
  className: "truncate",
290
306
  children: e.title
291
- }), /* @__PURE__ */ O("span", {
307
+ }), /* @__PURE__ */ k("span", {
292
308
  className: "text-[10px] text-muted-foreground sm:hidden",
293
309
  children: [
294
310
  e.start.toLocaleDateString(void 0, {
@@ -304,13 +320,15 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
304
320
  })]
305
321
  })]
306
322
  }),
307
- /* @__PURE__ */ D("div", {
323
+ /* @__PURE__ */ O("div", {
308
324
  className: "w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block",
309
- children: t ? /* @__PURE__ */ D("input", {
325
+ hidden: !I,
326
+ style: I ? void 0 : { display: "none" },
327
+ children: t ? /* @__PURE__ */ O("input", {
310
328
  type: "date",
311
329
  className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
312
- value: G.start || "",
313
- onChange: (e) => K((t) => ({
330
+ value: z.start || "",
331
+ onChange: (e) => B((t) => ({
314
332
  ...t,
315
333
  start: e.target.value
316
334
  })),
@@ -320,13 +338,15 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
320
338
  day: "numeric"
321
339
  })
322
340
  }),
323
- /* @__PURE__ */ D("div", {
341
+ /* @__PURE__ */ O("div", {
324
342
  className: "w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block",
325
- children: t ? /* @__PURE__ */ D("input", {
343
+ hidden: !I,
344
+ style: I ? void 0 : { display: "none" },
345
+ children: t ? /* @__PURE__ */ O("input", {
326
346
  type: "date",
327
347
  className: "border rounded px-1 py-0.5 text-xs w-full bg-background",
328
- value: G.end || "",
329
- onChange: (e) => K((t) => ({
348
+ value: z.end || "",
349
+ onChange: (e) => B((t) => ({
330
350
  ...t,
331
351
  end: e.target.value
332
352
  })),
@@ -339,7 +359,7 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
339
359
  ]
340
360
  }, e.id);
341
361
  })
342
- }), /* @__PURE__ */ D("div", {
362
+ }), /* @__PURE__ */ O("div", {
343
363
  className: "flex-1 overflow-auto bg-background/50 relative [-webkit-overflow-scrolling:touch]",
344
364
  ref: (e) => {
345
365
  ie.current = e, Z.current = e;
@@ -349,58 +369,105 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
349
369
  onTouchMove: oe,
350
370
  onTouchEnd: se,
351
371
  "data-testid": "gantt-timeline",
352
- children: /* @__PURE__ */ O("div", {
372
+ children: /* @__PURE__ */ k("div", {
353
373
  className: "relative",
354
- style: { width: J.length * R },
355
- children: [$ != null && /* @__PURE__ */ D("div", {
374
+ style: { width: J.length * g },
375
+ children: [$ != null && /* @__PURE__ */ O("div", {
356
376
  className: "absolute top-0 bottom-0 w-px bg-red-500/80 z-20 pointer-events-none",
357
377
  style: { left: $ },
358
378
  "data-testid": "gantt-today-marker",
359
379
  "aria-label": "Today",
360
- children: /* @__PURE__ */ D("div", {
380
+ children: /* @__PURE__ */ O("div", {
361
381
  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",
362
382
  children: "Today"
363
383
  })
364
- }), /* @__PURE__ */ O("div", {
384
+ }), /* @__PURE__ */ k("div", {
365
385
  className: "relative",
366
386
  children: [
367
- /* @__PURE__ */ D("div", {
387
+ /* @__PURE__ */ O("div", {
368
388
  className: "absolute inset-0 flex pointer-events-none z-0",
369
- children: J.map((e, t) => /* @__PURE__ */ D("div", {
370
- className: _("border-r h-full", e.isWeekend && "bg-muted/20"),
389
+ children: J.map((e, t) => /* @__PURE__ */ O("div", {
390
+ className: b("border-r h-full", e.isWeekend && "bg-muted/20"),
371
391
  style: {
372
- width: R,
373
- minWidth: R
392
+ width: g,
393
+ minWidth: g
374
394
  }
375
395
  }, t))
376
396
  }),
377
397
  t.map((e) => {
378
- let t = ue(e);
379
- return /* @__PURE__ */ D("div", {
398
+ let t = ue(e), n = V?.taskId === e.id, r = t;
399
+ if (n && V) {
400
+ let t = G(V);
401
+ r = ue({
402
+ ...e,
403
+ start: t.start,
404
+ end: t.end
405
+ });
406
+ }
407
+ let o = !!a;
408
+ return /* @__PURE__ */ k("div", {
380
409
  className: "relative border-b hover:bg-black/5",
381
- style: { height: I },
382
- children: /* @__PURE__ */ O("div", {
383
- className: "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 cursor-pointer hover:brightness-110 flex items-center px-2 group",
410
+ style: { height: m },
411
+ children: [n && /* @__PURE__ */ O("div", {
412
+ 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",
384
413
  style: {
385
414
  left: t.left,
386
415
  width: t.width,
416
+ opacity: .35
417
+ },
418
+ "aria-hidden": "true"
419
+ }), /* @__PURE__ */ k("div", {
420
+ className: b("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", o ? "cursor-grab active:cursor-grabbing" : "cursor-pointer", n && "ring-2 ring-primary/60 brightness-110 z-10"),
421
+ style: {
422
+ left: r.left,
423
+ width: r.width,
387
424
  backgroundColor: e.color || "#3b82f6"
388
425
  },
389
- onClick: () => a?.(e),
390
- children: [e.progress > 0 && /* @__PURE__ */ D("div", {
391
- className: "absolute left-0 top-0 bottom-0 bg-black/20 rounded-l-sm",
392
- style: { width: `${e.progress}%` }
393
- }), /* @__PURE__ */ O("span", {
394
- className: "text-[10px] text-white font-medium truncate opacity-0 group-hover:opacity-100 transition-opacity",
395
- children: [Math.round(e.progress), "%"]
396
- })]
397
- })
426
+ "data-testid": `gantt-task-bar-${e.id}`,
427
+ onClick: () => {
428
+ W.current || i?.(e);
429
+ },
430
+ onPointerDown: o ? (t) => {
431
+ t.button === 0 && K(e, "move", t);
432
+ } : void 0,
433
+ children: [
434
+ o && r.width >= 14 && /* @__PURE__ */ k(D, { children: [/* @__PURE__ */ O("div", {
435
+ className: "absolute left-0 top-0 bottom-0 w-1.5 cursor-ew-resize hover:bg-white/40",
436
+ "data-testid": `gantt-task-resize-left-${e.id}`,
437
+ onPointerDown: (t) => {
438
+ t.button === 0 && K(e, "resize-left", t);
439
+ },
440
+ onClick: (e) => e.stopPropagation()
441
+ }), /* @__PURE__ */ O("div", {
442
+ className: "absolute right-0 top-0 bottom-0 w-1.5 cursor-ew-resize hover:bg-white/40",
443
+ "data-testid": `gantt-task-resize-right-${e.id}`,
444
+ onPointerDown: (t) => {
445
+ t.button === 0 && K(e, "resize-right", t);
446
+ },
447
+ onClick: (e) => e.stopPropagation()
448
+ })] }),
449
+ e.progress > 0 && /* @__PURE__ */ O("div", {
450
+ className: "absolute left-0 top-0 bottom-0 bg-black/20 rounded-l-sm pointer-events-none",
451
+ style: { width: `${e.progress}%` }
452
+ }),
453
+ /* @__PURE__ */ O("span", {
454
+ className: "text-[10px] text-white font-medium truncate opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none",
455
+ children: n ? `${G(V).start.toLocaleDateString(void 0, {
456
+ month: "numeric",
457
+ day: "numeric"
458
+ })} → ${G(V).end.toLocaleDateString(void 0, {
459
+ month: "numeric",
460
+ day: "numeric"
461
+ })}` : `${Math.round(e.progress)}%`
462
+ })
463
+ ]
464
+ })]
398
465
  }, e.id);
399
466
  }),
400
- /* @__PURE__ */ D("div", {
467
+ /* @__PURE__ */ O("div", {
401
468
  className: "absolute top-0 bottom-0 w-px bg-red-500 z-20 pointer-events-none",
402
- style: { left: ((/* @__PURE__ */ new Date()).getTime() - q.start.getTime()) / (1e3 * 60 * 60 * 24) * R },
403
- children: /* @__PURE__ */ D("div", { className: "w-2 h-2 rounded-full bg-red-500 -ml-[3px]" })
469
+ style: { left: ((/* @__PURE__ */ new Date()).getTime() - q.start.getTime()) / (1e3 * 60 * 60 * 24) * g },
470
+ children: /* @__PURE__ */ O("div", { className: "w-2 h-2 rounded-full bg-red-500 -ml-[3px]" })
404
471
  })
405
472
  ]
406
473
  })]
@@ -412,7 +479,7 @@ function A({ tasks: t, viewMode: n = "month", startDate: r, endDate: i, onTaskCl
412
479
  }
413
480
  //#endregion
414
481
  //#region src/ObjectGantt.tsx
415
- function j(e) {
482
+ function F(e) {
416
483
  return e.data ? e.data : e.staticData ? {
417
484
  provider: "value",
418
485
  items: e.staticData
@@ -421,7 +488,7 @@ function j(e) {
421
488
  object: e.objectName
422
489
  } : null;
423
490
  }
424
- function M(e) {
491
+ function I(e) {
425
492
  if (e) {
426
493
  if (typeof e == "string") {
427
494
  let t = e.split(" "), n = t[0], r = t[1]?.toLowerCase() === "desc" ? "desc" : "asc";
@@ -430,7 +497,7 @@ function M(e) {
430
497
  if (Array.isArray(e)) return e.reduce((e, t) => (t.field && t.order && (e[t.field] = t.order), e), {});
431
498
  }
432
499
  }
433
- function N(e) {
500
+ function L(e) {
434
501
  let t = null;
435
502
  if (e.startDateField && e.endDateField) return t = {
436
503
  startDateField: e.startDateField,
@@ -441,147 +508,263 @@ function N(e) {
441
508
  colorField: e.colorField
442
509
  }, t;
443
510
  if (e.gantt && (t = e.gantt), t) {
444
- let e = l.safeParse(t);
511
+ let e = u.safeParse(t);
445
512
  return e.success || console.warn("[ObjectGantt] Invalid gantt configuration:", e.error.format()), t;
446
513
  }
447
514
  return null;
448
515
  }
449
- var P = ({ schema: e, dataSource: i, className: c, onTaskClick: l, onRowClick: u, ...f }) => {
450
- let [p, m] = r([]), [h, g] = r(!0), [_, v] = r(null), [y, b] = r(null), x = j(e), S = n(() => x, [JSON.stringify(x)]), C = N(e), w = S?.provider === "value";
451
- t(() => {
516
+ var R = ({ schema: e, dataSource: a, className: l, onTaskClick: u, onRowClick: y, ...b }) => {
517
+ let [x, S] = i([]), [C, w] = i(!0), [T, ne] = i(null), [E, re] = i(null), A = F(e), j = r(() => A, [JSON.stringify(A)]), M = L(e), N = j?.provider === "value";
518
+ n(() => {
452
519
  (async () => {
453
520
  try {
454
- if (g(!0), f.data && Array.isArray(f.data)) {
455
- m(f.data), g(!1);
521
+ if (w(!0), b.data && Array.isArray(b.data)) {
522
+ S(b.data), w(!1);
456
523
  return;
457
524
  }
458
- if (w && S?.provider === "value") {
459
- m(S.items), g(!1);
525
+ if (N && j?.provider === "value") {
526
+ S(j.items), w(!1);
460
527
  return;
461
528
  }
462
- if (!i || typeof i.find != "function") throw Error("DataSource required for object/api providers");
463
- if (S?.provider === "object") {
464
- let t = S.object, n = a(y?.fields);
465
- m(o(await i.find(t, {
529
+ if (!a || typeof a.find != "function") throw Error("DataSource required for object/api providers");
530
+ if (j?.provider === "object") {
531
+ let t = j.object, n = o(E?.fields);
532
+ S(s(await a.find(t, {
466
533
  $filter: e.filter,
467
- $orderby: M(e.sort),
534
+ $orderby: I(e.sort),
468
535
  ...n.length > 0 ? { $expand: n } : {}
469
536
  })));
470
- } else S?.provider === "api" && (console.warn("API provider not yet implemented for ObjectGantt"), m([]));
471
- g(!1);
537
+ } else j?.provider === "api" && (console.warn("API provider not yet implemented for ObjectGantt"), S([]));
538
+ w(!1);
472
539
  } catch (e) {
473
- v(e), g(!1);
540
+ ne(e), w(!1);
474
541
  }
475
542
  })();
476
543
  }, [
477
- S,
478
- i,
479
- w,
544
+ j,
545
+ a,
546
+ N,
480
547
  e.filter,
481
548
  e.sort,
482
- y
483
- ]), t(() => {
484
- !w && i && (async () => {
549
+ E
550
+ ]), n(() => {
551
+ !N && a && (async () => {
485
552
  try {
486
- if (!i) return;
487
- let t = S?.provider === "object" ? S.object : e.objectName;
553
+ if (!a) return;
554
+ let t = j?.provider === "object" ? j.object : e.objectName;
488
555
  if (!t) return;
489
- b(await i.getObjectSchema(t));
556
+ re(await a.getObjectSchema(t));
490
557
  } catch (e) {
491
558
  console.error("Failed to fetch object schema:", e);
492
559
  }
493
560
  })();
494
561
  }, [
495
562
  e.objectName,
496
- i,
497
- w,
498
- S
563
+ a,
564
+ N,
565
+ j
499
566
  ]);
500
- let T = n(() => {
501
- if (!C || !p.length) return [];
502
- let { startDateField: e, endDateField: t, titleField: n, progressField: r, dependenciesField: i, colorField: a } = C;
503
- return p.map((o, s) => {
504
- let c = o[e], l = o[t], u = o[n] || "Untitled Task", d = r ? o[r] : 0, f = i ? o[i] : [], p = a ? o[a] : void 0;
567
+ let R = r(() => {
568
+ if (!M || !x.length) return [];
569
+ let { startDateField: e, endDateField: t, titleField: n, progressField: r, dependenciesField: i, colorField: a } = M, o = (e, t) => {
570
+ if (!t) return;
571
+ let n = t.split("."), r = e;
572
+ for (let e of n) {
573
+ if (r == null) return;
574
+ r = r[e];
575
+ }
576
+ return r;
577
+ }, s = (e) => {
578
+ let t = [
579
+ o(e, n),
580
+ e?.name,
581
+ e?.title,
582
+ e?.subject,
583
+ e?.label,
584
+ e?.account?.name,
585
+ e?.opportunity?.name,
586
+ e?.contact && [e.contact.first_name, e.contact.last_name].filter(Boolean).join(" "),
587
+ e?.id,
588
+ e?._id
589
+ ];
590
+ for (let e of t) if (e != null && String(e).trim() !== "") return String(e);
591
+ return "Untitled";
592
+ };
593
+ return x.map((n, o) => {
594
+ let c = n[e], l = n[t], u = s(n), d = r ? n[r] : 0, f = i ? n[i] : [], p = a ? n[a] : void 0;
505
595
  return {
506
- id: o.id || o._id || `task-${s}`,
596
+ id: n.id || n._id || `task-${o}`,
507
597
  title: u,
508
598
  start: c ? new Date(c) : /* @__PURE__ */ new Date(),
509
599
  end: l ? new Date(l) : /* @__PURE__ */ new Date(),
510
600
  progress: Math.min(100, Math.max(0, d || 0)),
511
601
  dependencies: Array.isArray(f) ? f : [],
512
602
  color: p,
513
- data: o
603
+ data: n
514
604
  };
515
605
  }).filter((e) => !isNaN(e.start.getTime()) && !isNaN(e.end.getTime()));
516
- }, [p, C]), E = s({
517
- navigation: e.navigation,
606
+ }, [x, M]), z = e.navigation ?? {
607
+ mode: "drawer",
608
+ width: "min(960px, 60vw)"
609
+ }, B = z.mode === "drawer" || z.mode === "modal" || z.mode === "split" || z.mode === "popover", V = c({
610
+ navigation: z,
518
611
  objectName: e.objectName,
519
- onRowClick: u
520
- });
521
- return h ? /* @__PURE__ */ D("div", {
522
- className: c,
523
- children: /* @__PURE__ */ D("div", {
612
+ onRowClick: B ? void 0 : y
613
+ }), H = t(async (t, n) => {
614
+ if (!M) return;
615
+ let r = j?.provider === "object" ? j.object : e.objectName;
616
+ if (!r || !a || typeof a.update != "function") return;
617
+ let { startDateField: i, endDateField: o, titleField: s, progressField: c } = M, l = {};
618
+ if (n.start instanceof Date && (l[i] = 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;
619
+ let u = t.data?.id ?? t.data?._id ?? t.id;
620
+ if (u == null) return;
621
+ let d = x;
622
+ S((e) => e.map((e) => String(e.id ?? e._id) === String(u) ? {
623
+ ...e,
624
+ ...l
625
+ } : e));
626
+ try {
627
+ await a.update(r, String(u), l);
628
+ } catch (e) {
629
+ console.error("[ObjectGantt] Failed to persist task update:", e), S(d);
630
+ }
631
+ }, [
632
+ M,
633
+ j,
634
+ a,
635
+ e.objectName,
636
+ x
637
+ ]), [U, W] = i(null), [G, K] = i(!1), q = t((e) => {
638
+ W(e);
639
+ }, []), J = t(async () => {
640
+ if (!U) return;
641
+ let t = j?.provider === "object" ? j.object : e.objectName;
642
+ if (!t || !a?.delete) {
643
+ W(null);
644
+ return;
645
+ }
646
+ let n = U.data?.id ?? U.data?._id ?? U.id;
647
+ if (n == null) {
648
+ W(null);
649
+ return;
650
+ }
651
+ K(!0);
652
+ let r = x;
653
+ S((e) => e.filter((e) => String(e.id ?? e._id) !== String(n)));
654
+ try {
655
+ await a.delete(t, String(n)), W(null);
656
+ } catch (e) {
657
+ console.error("[ObjectGantt] Failed to delete:", e), S(r), W(null);
658
+ } finally {
659
+ K(!1);
660
+ }
661
+ }, [
662
+ U,
663
+ j,
664
+ a,
665
+ e.objectName,
666
+ x
667
+ ]);
668
+ return C ? /* @__PURE__ */ O("div", {
669
+ className: l,
670
+ children: /* @__PURE__ */ O("div", {
524
671
  className: "flex items-center justify-center h-96",
525
- children: /* @__PURE__ */ D("div", {
672
+ children: /* @__PURE__ */ O("div", {
526
673
  className: "text-muted-foreground",
527
674
  children: "Loading Gantt chart..."
528
675
  })
529
676
  })
530
- }) : _ ? /* @__PURE__ */ D("div", {
531
- className: c,
532
- children: /* @__PURE__ */ D("div", {
677
+ }) : T ? /* @__PURE__ */ O("div", {
678
+ className: l,
679
+ children: /* @__PURE__ */ O("div", {
533
680
  className: "flex items-center justify-center h-96",
534
- children: /* @__PURE__ */ O("div", {
681
+ children: /* @__PURE__ */ k("div", {
535
682
  className: "text-destructive",
536
- children: ["Error: ", _.message]
683
+ children: ["Error: ", T.message]
537
684
  })
538
685
  })
539
- }) : C ? /* @__PURE__ */ O("div", {
540
- className: c,
541
- children: [/* @__PURE__ */ D("div", {
542
- className: "h-[calc(100vh-200px)] min-h-[600px]",
543
- children: /* @__PURE__ */ D(A, {
544
- tasks: T,
545
- onTaskClick: (e) => {
546
- E.handleClick(e.data), l?.(e.data);
686
+ }) : M ? /* @__PURE__ */ k("div", {
687
+ className: l,
688
+ children: [
689
+ /* @__PURE__ */ O("div", {
690
+ className: "h-[calc(100vh-200px)] min-h-[600px]",
691
+ children: /* @__PURE__ */ O(P, {
692
+ tasks: R,
693
+ onTaskClick: (e) => {
694
+ V.handleClick(e.data), u?.(e.data);
695
+ },
696
+ onTaskUpdate: H,
697
+ onTaskDelete: q,
698
+ inlineEdit: !0
699
+ })
700
+ }),
701
+ V.isOverlay && V.isOpen && V.selectedRecord && (() => {
702
+ let t = j?.provider === "object" ? j.object : e.objectName, n = V.selectedRecord, r = n.id ?? n._id;
703
+ if (!t || r == null) return null;
704
+ let i = M?.titleField ? String(n[M.titleField] ?? "Task Details") : "Task Details";
705
+ return /* @__PURE__ */ O(d, {
706
+ open: !0,
707
+ onClose: V.close,
708
+ title: i,
709
+ record: n,
710
+ objectName: t,
711
+ recordId: r,
712
+ dataSource: a,
713
+ objectSchema: E,
714
+ width: V.width,
715
+ fullPageHref: f(t, r) ?? void 0,
716
+ onFieldSave: async (e, n) => {
717
+ a?.update && (await a.update(t, String(r), { [e]: n }), S((t) => t.map((t) => String(t.id ?? t._id) === String(r) ? {
718
+ ...t,
719
+ [e]: n
720
+ } : t)));
721
+ },
722
+ onDelete: async () => {
723
+ a?.delete && (await a.delete(t, String(r)), S((e) => e.filter((e) => String(e.id ?? e._id) !== String(r))));
724
+ }
725
+ });
726
+ })(),
727
+ /* @__PURE__ */ O(p, {
728
+ open: !!U,
729
+ onOpenChange: (e) => {
730
+ !e && !G && W(null);
547
731
  },
548
- onAddClick: () => {}
549
- })
550
- }), E.isOverlay && /* @__PURE__ */ D(d, {
551
- ...E,
552
- title: "Task Details",
553
- children: (e) => /* @__PURE__ */ D("div", {
554
- className: "space-y-3",
555
- children: Object.entries(e).map(([e, t]) => /* @__PURE__ */ O("div", {
556
- className: "flex flex-col",
557
- children: [/* @__PURE__ */ D("span", {
558
- className: "text-xs font-medium text-muted-foreground uppercase tracking-wide",
559
- children: e.replace(/_/g, " ")
560
- }), /* @__PURE__ */ D("span", {
561
- className: "text-sm",
562
- children: String(t ?? "—")
563
- })]
564
- }, e))
732
+ children: /* @__PURE__ */ k(te, { children: [/* @__PURE__ */ k(_, { children: [/* @__PURE__ */ O(v, { children: "Delete this task?" }), /* @__PURE__ */ O(h, { children: U ? /* @__PURE__ */ k(D, { children: [
733
+ "\"",
734
+ U.title,
735
+ "\" will be permanently removed. This action cannot be undone."
736
+ ] }) : null })] }), /* @__PURE__ */ k(g, { children: [/* @__PURE__ */ O(ee, {
737
+ disabled: G,
738
+ children: "Cancel"
739
+ }), /* @__PURE__ */ O(m, {
740
+ onClick: (e) => {
741
+ e.preventDefault(), J();
742
+ },
743
+ disabled: G,
744
+ "data-testid": "gantt-delete-confirm",
745
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
746
+ children: G ? "Deleting…" : "Delete"
747
+ })] })] })
565
748
  })
566
- })]
567
- }) : /* @__PURE__ */ D("div", {
568
- className: c,
569
- children: /* @__PURE__ */ D("div", {
749
+ ]
750
+ }) : /* @__PURE__ */ O("div", {
751
+ className: l,
752
+ children: /* @__PURE__ */ O("div", {
570
753
  className: "flex items-center justify-center h-96",
571
- children: /* @__PURE__ */ D("div", {
754
+ children: /* @__PURE__ */ O("div", {
572
755
  className: "text-muted-foreground",
573
756
  children: "Gantt configuration required. Please specify startDateField, endDateField, and titleField."
574
757
  })
575
758
  })
576
759
  });
577
- }, F = ({ schema: e }) => {
578
- let { dataSource: t } = c() || {};
579
- return /* @__PURE__ */ D(P, {
760
+ }, z = ({ schema: e }) => {
761
+ let { dataSource: t } = l() || {};
762
+ return /* @__PURE__ */ O(R, {
580
763
  schema: e,
581
764
  dataSource: t
582
765
  });
583
766
  };
584
- i.register("object-gantt", F, {
767
+ a.register("object-gantt", z, {
585
768
  namespace: "plugin-gantt",
586
769
  label: "Object Gantt",
587
770
  category: "view",
@@ -596,7 +779,7 @@ i.register("object-gantt", F, {
596
779
  label: "Gantt Config",
597
780
  description: "startDateField, endDateField, titleField, progressField, percentageField, colorField, dependenciesField"
598
781
  }]
599
- }), i.register("gantt", F, {
782
+ }), a.register("gantt", z, {
600
783
  namespace: "view",
601
784
  label: "Gantt View",
602
785
  category: "view",
@@ -613,4 +796,4 @@ i.register("object-gantt", F, {
613
796
  }]
614
797
  });
615
798
  //#endregion
616
- export { A as GanttView, P as ObjectGantt, F as ObjectGanttRenderer };
799
+ export { P as GanttView, R as ObjectGantt, z as ObjectGanttRenderer };
@@ -1 +1 @@
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/components`),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/components`,`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.ObjectUIComponents,e.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var c=Object.create,l=Object.defineProperty,u=Object.getOwnPropertyDescriptor,d=Object.getOwnPropertyNames,f=Object.getPrototypeOf,p=Object.prototype.hasOwnProperty,m=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=d(t),a=0,o=i.length,s;a<o;a++)s=i[a],!p.call(e,s)&&s!==n&&l(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=u(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:c(f(e)),m(t||!e||!e.__esModule?l(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);function h(e){return e<640?35:e<1024?50:60}function g(e){return e<640?120:e<1024?200:300}function _(e){return e<640?32:40}function v({tasks:e,viewMode:n=`month`,startDate:r,endDate:i,onTaskClick:c,onTaskUpdate:l,onViewChange:u,onAddClick:d,className:f,inlineEdit:p=!1}){let[m,v]=t.useState(new Date),y=t.useRef(null),{width:b}=(0,a.useResizeObserver)(y),x=b||(typeof window<`u`?window.innerWidth:1024),S=x<640,C=_(x),w=h(x),[T,E]=t.useState(null),D=T??w,[O,k]=t.useState(!1),A=t.useRef(!1);t.useEffect(()=>{!A.current&&S&&(k(!0),A.current=!0)},[S]);let j=O?0:g(x),[M,N]=t.useState(null),[P,F]=t.useState({}),I=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.setHours(0,0,0,0),n.setHours(23,59,59,999),{start:t,end:n}},[r,i,e]),L=t.useMemo(()=>{let e=[],t=new Date(I.start);for(;t<=I.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},[I]),R=t.useRef(null),z=t.useRef(null),B=t.useRef(null),V=t.useRef(null),H=t.useRef(null),U=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;H.current={baseDistance:Math.max(1,Math.sqrt(t*t+n*n)),baseColumn:D}}},[D]),W=t.useCallback(e=>{if(e.touches.length!==2||!H.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))/H.current.baseDistance;E(Math.max(15,Math.min(120,Math.round(H.current.baseColumn*r))))},[]),G=t.useCallback(()=>{H.current=null},[]),K=t.useMemo(()=>{let e=new Date;if(e<I.start||e>I.end)return null;let t=(e.getTime()-I.start.getTime())/(1440*60*1e3);return Math.round(t*D)},[I,D]),q=t.useCallback(()=>{if(K==null||!V.current)return;let e=Math.max(0,K-V.current.clientWidth/2);V.current.scrollTo({left:e,behavior:`smooth`})},[K]),J=e=>{R.current&&(R.current.scrollLeft=e.currentTarget.scrollLeft),z.current&&(z.current.scrollTop=e.currentTarget.scrollTop)},Y=e=>{I.end.getTime()-I.start.getTime();let t=D,n=1e3*60*60*24,r=e.start.getTime()-I.start.getTime(),i=e.end.getTime()-e.start.getTime();return{left:r/n*t,width:Math.max(i/n*t,t)}};return(0,s.jsxs)(`div`,{ref:y,className:(0,a.cn)(`flex flex-col h-full bg-background border rounded-lg overflow-hidden min-w-0`,f),children:[(0,s.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,s.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,s.jsxs)(a.Button,{variant:`outline`,size:`sm`,onClick:()=>d?.(),"aria-label":`Create new task`,children:[(0,s.jsx)(o.Plus,{className:`h-4 w-4 mr-1 sm:mr-2`}),(0,s.jsx)(`span`,{className:`hidden sm:inline`,children:`New Task`}),(0,s.jsx)(`span`,{className:`sm:hidden`,children:`New`})]}),(0,s.jsx)(`div`,{className:`h-4 w-px bg-border mx-1 sm:mx-2`}),(0,s.jsx)(a.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,"aria-label":`Previous period`,children:(0,s.jsx)(o.ChevronLeft,{className:`h-4 w-4`})}),(0,s.jsx)(a.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,"aria-label":`Next period`,children:(0,s.jsx)(o.ChevronRight,{className:`h-4 w-4`})}),(0,s.jsx)(`span`,{className:`font-semibold text-xs sm:text-sm`,children:I.start.toLocaleDateString(void 0,{month:`long`,year:`numeric`})})]}),(0,s.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,s.jsxs)(a.Select,{value:n,onValueChange:e=>u?.(e),children:[(0,s.jsx)(a.SelectTrigger,{className:`w-[100px] sm:w-[120px] h-8`,children:(0,s.jsx)(a.SelectValue,{})}),(0,s.jsxs)(a.SelectContent,{children:[(0,s.jsx)(a.SelectItem,{value:`day`,children:`Day View`}),(0,s.jsx)(a.SelectItem,{value:`week`,children:`Week View`}),(0,s.jsx)(a.SelectItem,{value:`month`,children:`Month View`}),(0,s.jsx)(a.SelectItem,{value:`quarter`,children:`Quarter View`})]})]}),(0,s.jsxs)(`div`,{className:`flex bg-muted rounded-md p-1`,children:[(0,s.jsx)(a.Button,{variant:`ghost`,size:`icon`,className:`h-6 w-6`,onClick:()=>E(Math.max(15,D-10)),"aria-label":`Zoom out`,children:(0,s.jsx)(o.ZoomOut,{className:`h-3 w-3`})}),(0,s.jsx)(a.Button,{variant:`ghost`,size:`icon`,className:`h-6 w-6`,onClick:()=>E(Math.min(120,D+10)),"aria-label":`Zoom in`,children:(0,s.jsx)(o.ZoomIn,{className:`h-3 w-3`})})]}),(0,s.jsx)(a.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:()=>k(e=>!e),"aria-label":O?`Show task list`:`Hide task list`,"aria-pressed":O,"data-testid":`gantt-toggle-task-list`,children:O?(0,s.jsx)(o.PanelLeft,{className:`h-4 w-4`}):(0,s.jsx)(o.PanelLeftClose,{className:`h-4 w-4`})}),(0,s.jsx)(a.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:q,disabled:K==null,"aria-label":`Jump to today`,"data-testid":`gantt-jump-today`,children:(0,s.jsx)(o.CalendarDays,{className:`h-4 w-4`})})]})]}),(0,s.jsxs)(`div`,{className:`flex flex-col flex-1 overflow-hidden`,children:[(0,s.jsxs)(`div`,{className:`flex border-b bg-muted/30 shrink-0 h-10 sm:h-[50px]`,children:[(0,s.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,s.jsx)(`div`,{className:`flex-1`,children:`Task Name`}),(0,s.jsx)(`div`,{className:`w-16 sm:w-20 text-right hidden sm:block`,children:`Start`}),(0,s.jsx)(`div`,{className:`w-16 sm:w-20 text-right hidden sm:block`,children:`End`})]}),(0,s.jsx)(`div`,{className:`flex-1 overflow-hidden`,ref:R,children:(0,s.jsx)(`div`,{className:`flex h-full`,style:{width:L.length*D},children:L.map((e,t)=>(0,s.jsxs)(`div`,{className:(0,a.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,s.jsx)(`span`,{className:`font-medium text-foreground`,children:e.label}),(0,s.jsx)(`span`,{className:`text-[10px] opacity-70`,children:e.date.toLocaleDateString(void 0,{weekday:`narrow`})})]},t))})})]}),(0,s.jsxs)(`div`,{className:`flex flex-1 overflow-hidden`,children:[(0,s.jsx)(`div`,{className:`overflow-hidden border-r bg-card z-10 shadow-sm`,ref:z,style:{width:j,minWidth:j},children:e.map(e=>{let t=p&&M===e.id;return(0,s.jsxs)(`div`,{className:`flex items-center border-b px-2 sm:px-4 hover:bg-accent/50 cursor-pointer transition-colors touch-manipulation`,style:{height:C},onClick:()=>!t&&c?.(e),onDoubleClick:()=>{p&&l&&(N(e.id),F({title:e.title,start:e.start.toLocaleDateString(`en-CA`),end:e.end.toLocaleDateString(`en-CA`),progress:String(e.progress)}))},children:[(0,s.jsxs)(`div`,{className:`flex-1 truncate font-medium text-xs sm:text-sm flex items-center gap-2`,children:[(0,s.jsx)(`div`,{className:`w-2 h-2 rounded-full shrink-0`,style:{backgroundColor:e.color||`#3b82f6`}}),t?(0,s.jsx)(`input`,{className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:P.title||``,onChange:e=>F(t=>({...t,title:e.target.value})),onKeyDown:t=>{t.key===`Enter`?(l?.(e,{title:P.title,start:new Date(P.start),end:new Date(P.end),progress:Number(P.progress)||0}),N(null)):t.key===`Escape`&&N(null)},onClick:e=>e.stopPropagation(),autoFocus:!0}):(0,s.jsxs)(`span`,{className:`flex flex-col min-w-0`,children:[(0,s.jsx)(`span`,{className:`truncate`,children:e.title}),(0,s.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,s.jsx)(`div`,{className:`w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block`,children:t?(0,s.jsx)(`input`,{type:`date`,className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:P.start||``,onChange:e=>F(t=>({...t,start:e.target.value})),onClick:e=>e.stopPropagation()}):e.start.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})}),(0,s.jsx)(`div`,{className:`w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block`,children:t?(0,s.jsx)(`input`,{type:`date`,className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:P.end||``,onChange:e=>F(t=>({...t,end:e.target.value})),onClick:e=>e.stopPropagation()}):e.end.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})})]},e.id)})}),(0,s.jsx)(`div`,{className:`flex-1 overflow-auto bg-background/50 relative [-webkit-overflow-scrolling:touch]`,ref:e=>{B.current=e,V.current=e},onScroll:J,onTouchStart:U,onTouchMove:W,onTouchEnd:G,"data-testid":`gantt-timeline`,children:(0,s.jsxs)(`div`,{className:`relative`,style:{width:L.length*D},children:[K!=null&&(0,s.jsx)(`div`,{className:`absolute top-0 bottom-0 w-px bg-red-500/80 z-20 pointer-events-none`,style:{left:K},"data-testid":`gantt-today-marker`,"aria-label":`Today`,children:(0,s.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:`Today`})}),(0,s.jsxs)(`div`,{className:`relative`,children:[(0,s.jsx)(`div`,{className:`absolute inset-0 flex pointer-events-none z-0`,children:L.map((e,t)=>(0,s.jsx)(`div`,{className:(0,a.cn)(`border-r h-full`,e.isWeekend&&`bg-muted/20`),style:{width:D,minWidth:D}},t))}),e.map(e=>{let t=Y(e);return(0,s.jsx)(`div`,{className:`relative border-b hover:bg-black/5`,style:{height:C},children:(0,s.jsxs)(`div`,{className:`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 cursor-pointer hover:brightness-110 flex items-center px-2 group`,style:{left:t.left,width:t.width,backgroundColor:e.color||`#3b82f6`},onClick:()=>c?.(e),children:[e.progress>0&&(0,s.jsx)(`div`,{className:`absolute left-0 top-0 bottom-0 bg-black/20 rounded-l-sm`,style:{width:`${e.progress}%`}}),(0,s.jsxs)(`span`,{className:`text-[10px] text-white font-medium truncate opacity-0 group-hover:opacity-100 transition-opacity`,children:[Math.round(e.progress),`%`]})]})},e.id)}),(0,s.jsx)(`div`,{className:`absolute top-0 bottom-0 w-px bg-red-500 z-20 pointer-events-none`,style:{left:(new Date().getTime()-I.start.getTime())/(1e3*60*60*24)*D},children:(0,s.jsx)(`div`,{className:`w-2 h-2 rounded-full bg-red-500 -ml-[3px]`})})]})]})})]})]})]})}function y(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function b(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 x(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 S=({schema:e,dataSource:i,className:o,onTaskClick:c,onRowClick:l,...u})=>{let[d,f]=(0,t.useState)([]),[p,m]=(0,t.useState)(!0),[h,g]=(0,t.useState)(null),[_,S]=(0,t.useState)(null),C=y(e),w=(0,t.useMemo)(()=>C,[JSON.stringify(C)]),T=x(e),E=w?.provider===`value`;(0,t.useEffect)(()=>{(async()=>{try{if(m(!0),u.data&&Array.isArray(u.data)){f(u.data),m(!1);return}if(E&&w?.provider===`value`){f(w.items),m(!1);return}if(!i||typeof i.find!=`function`)throw Error(`DataSource required for object/api providers`);if(w?.provider===`object`){let t=w.object,r=(0,n.buildExpandFields)(_?.fields);f((0,n.extractRecords)(await i.find(t,{$filter:e.filter,$orderby:b(e.sort),...r.length>0?{$expand:r}:{}})))}else w?.provider===`api`&&(console.warn(`API provider not yet implemented for ObjectGantt`),f([]));m(!1)}catch(e){g(e),m(!1)}})()},[w,i,E,e.filter,e.sort,_]),(0,t.useEffect)(()=>{!E&&i&&(async()=>{try{if(!i)return;let t=w?.provider===`object`?w.object:e.objectName;if(!t)return;S(await i.getObjectSchema(t))}catch(e){console.error(`Failed to fetch object schema:`,e)}})()},[e.objectName,i,E,w]);let D=(0,t.useMemo)(()=>{if(!T||!d.length)return[];let{startDateField:e,endDateField:t,titleField:n,progressField:r,dependenciesField:i,colorField:a}=T;return d.map((o,s)=>{let c=o[e],l=o[t],u=o[n]||`Untitled Task`,d=r?o[r]:0,f=i?o[i]:[],p=a?o[a]:void 0;return{id:o.id||o._id||`task-${s}`,title:u,start:c?new Date(c):new Date,end:l?new Date(l):new Date,progress:Math.min(100,Math.max(0,d||0)),dependencies:Array.isArray(f)?f:[],color:p,data:o}}).filter(e=>!isNaN(e.start.getTime())&&!isNaN(e.end.getTime()))},[d,T]),O=(0,r.useNavigationOverlay)({navigation:e.navigation,objectName:e.objectName,onRowClick:l});return p?(0,s.jsx)(`div`,{className:o,children:(0,s.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,s.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading Gantt chart...`})})}):h?(0,s.jsx)(`div`,{className:o,children:(0,s.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,s.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,h.message]})})}):T?(0,s.jsxs)(`div`,{className:o,children:[(0,s.jsx)(`div`,{className:`h-[calc(100vh-200px)] min-h-[600px]`,children:(0,s.jsx)(v,{tasks:D,onTaskClick:e=>{O.handleClick(e.data),c?.(e.data)},onAddClick:()=>{}})}),O.isOverlay&&(0,s.jsx)(a.NavigationOverlay,{...O,title:`Task Details`,children:e=>(0,s.jsx)(`div`,{className:`space-y-3`,children:Object.entries(e).map(([e,t])=>(0,s.jsxs)(`div`,{className:`flex flex-col`,children:[(0,s.jsx)(`span`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:e.replace(/_/g,` `)}),(0,s.jsx)(`span`,{className:`text-sm`,children:String(t??`—`)})]},e))})})]}):(0,s.jsx)(`div`,{className:o,children:(0,s.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,s.jsx)(`div`,{className:`text-muted-foreground`,children:`Gantt configuration required. Please specify startDateField, endDateField, and titleField.`})})})},C=({schema:e})=>{let{dataSource:t}=(0,r.useSchemaContext)()||{};return(0,s.jsx)(S,{schema:e,dataSource:t})};n.ComponentRegistry.register(`object-gantt`,C,{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`,C,{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=v,e.ObjectGantt=S,e.ObjectGanttRenderer=C});
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(`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`,`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.LucideReact,e.react_jsx_runtime))})(this,function(e,t,n,r,i,a,o,s,c){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var l=Object.create,u=Object.defineProperty,d=Object.getOwnPropertyDescriptor,f=Object.getOwnPropertyNames,p=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,h=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=f(t),a=0,o=i.length,s;a<o;a++)s=i[a],!m.call(e,s)&&s!==n&&u(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=d(t,s))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:l(p(e)),h(t||!e||!e.__esModule?u(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);function g(e){return e<640?35:e<1024?50:60}function _(e){return e<640?140:e<1024?220:320}function v(e){return e>=280}function y(e){return e<640?32:40}function b({tasks:e,startDate:n,endDate:r,onTaskClick:i,onTaskUpdate:a,className:l,inlineEdit:u=!1}){let[d,f]=t.useState(new Date),p=t.useRef(null),{width:m}=(0,o.useResizeObserver)(p),h=m||(typeof window<`u`?window.innerWidth:1024),b=h<640,x=y(h),S=g(h),[C,w]=t.useState(null),T=C??S,[E,D]=t.useState(!1),O=t.useRef(!1);t.useEffect(()=>{!O.current&&b&&(D(!0),O.current=!0)},[b]);let k=E?0:_(h),A=v(k),[j,M]=t.useState(null),[N,P]=t.useState({}),[F,I]=t.useState(null),L=t.useRef(null);t.useEffect(()=>{L.current=F},[F]);let R=t.useRef(!1),z=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(!F)return;let t=e=>{let t=L.current;if(!t)return;let n=Math.round((e.clientX-t.originClientX)/Math.max(T,1));n!==t.dayDelta&&I({...t,dayDelta:n})},n=()=>{let t=L.current;if(t){if(t.dayDelta!==0){let n=e.find(e=>e.id===t.taskId);if(n&&a){let{start:e,end:r}=z(t);a(n,{start:e,end:r})}R.current=!0,window.setTimeout(()=>{R.current=!1},0)}I(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)}},[F,T,e,a,z]);let B=t.useCallback((e,t,n)=>{a&&(n.stopPropagation(),n.preventDefault(),I({taskId:e.id,mode:t,originStart:new Date(e.start),originEnd:new Date(e.end),originClientX:n.clientX,dayDelta:0}))},[a]),V=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]),H=t.useMemo(()=>{let e=[],t=new Date(V.start);for(;t<=V.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},[V]),U=t.useRef(null),W=t.useRef(null),G=t.useRef(null),K=t.useRef(null),q=t.useRef(null),J=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;q.current={baseDistance:Math.max(1,Math.sqrt(t*t+n*n)),baseColumn:T}}},[T]),Y=t.useCallback(e=>{if(e.touches.length!==2||!q.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))/q.current.baseDistance;w(Math.max(15,Math.min(120,Math.round(q.current.baseColumn*r))))},[]),X=t.useCallback(()=>{q.current=null},[]),Z=t.useMemo(()=>{let e=new Date;if(e<V.start||e>V.end)return null;let t=(e.getTime()-V.start.getTime())/(1440*60*1e3);return Math.round(t*T)},[V,T]),Q=t.useCallback(()=>{if(Z==null||!K.current)return;let e=Math.max(0,Z-K.current.clientWidth/2);K.current.scrollTo({left:e,behavior:`smooth`})},[Z]),ee=e=>{U.current&&(U.current.scrollLeft=e.currentTarget.scrollLeft),W.current&&(W.current.scrollTop=e.currentTarget.scrollTop)},$=e=>{V.end.getTime()-V.start.getTime();let t=T,n=1e3*60*60*24,r=e.start.getTime()-V.start.getTime(),i=e.end.getTime()-e.start.getTime();return{left:r/n*t,width:Math.max(i/n*t,t)}};return(0,c.jsxs)(`div`,{ref:p,className:(0,o.cn)(`flex flex-col h-full bg-background border rounded-lg overflow-hidden min-w-0`,l),children:[(0,c.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,c.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,c.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,"aria-label":`Previous period`,children:(0,c.jsx)(s.ChevronLeft,{className:`h-4 w-4`})}),(0,c.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,"aria-label":`Next period`,children:(0,c.jsx)(s.ChevronRight,{className:`h-4 w-4`})}),(0,c.jsx)(`span`,{className:`font-semibold text-xs sm:text-sm`,children:V.start.toLocaleDateString(void 0,{month:`long`,year:`numeric`})})]}),(0,c.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,c.jsxs)(`div`,{className:`flex bg-muted rounded-md p-1`,children:[(0,c.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-6 w-6`,onClick:()=>w(Math.max(15,T-10)),"aria-label":`Zoom out`,children:(0,c.jsx)(s.ZoomOut,{className:`h-3 w-3`})}),(0,c.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-6 w-6`,onClick:()=>w(Math.min(120,T+10)),"aria-label":`Zoom in`,children:(0,c.jsx)(s.ZoomIn,{className:`h-3 w-3`})})]}),(0,c.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:()=>D(e=>!e),"aria-label":E?`Show task list`:`Hide task list`,"aria-pressed":E,"data-testid":`gantt-toggle-task-list`,children:E?(0,c.jsx)(s.PanelLeft,{className:`h-4 w-4`}):(0,c.jsx)(s.PanelLeftClose,{className:`h-4 w-4`})}),(0,c.jsx)(o.Button,{variant:`ghost`,size:`icon`,className:`h-8 w-8`,onClick:Q,disabled:Z==null,"aria-label":`Jump to today`,"data-testid":`gantt-jump-today`,children:(0,c.jsx)(s.CalendarDays,{className:`h-4 w-4`})})]})]}),(0,c.jsxs)(`div`,{className:`flex flex-col flex-1 overflow-hidden`,children:[(0,c.jsxs)(`div`,{className:`flex border-b bg-muted/30 shrink-0 h-10 sm:h-[50px]`,children:[(0,c.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:k,minWidth:k},children:[(0,c.jsx)(`div`,{className:`flex-1 truncate`,children:`Task Name`}),A&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(`div`,{className:`w-16 sm:w-20 text-right`,children:`Start`}),(0,c.jsx)(`div`,{className:`w-16 sm:w-20 text-right`,children:`End`})]})]}),(0,c.jsx)(`div`,{className:`flex-1 overflow-hidden`,ref:U,children:(0,c.jsx)(`div`,{className:`flex h-full`,style:{width:H.length*T},children:H.map((e,t)=>(0,c.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:T,minWidth:T},children:[(0,c.jsx)(`span`,{className:`font-medium text-foreground`,children:e.label}),(0,c.jsx)(`span`,{className:`text-[10px] opacity-70`,children:e.date.toLocaleDateString(void 0,{weekday:`narrow`})})]},t))})})]}),(0,c.jsxs)(`div`,{className:`flex flex-1 overflow-hidden`,children:[(0,c.jsx)(`div`,{className:`overflow-hidden border-r bg-card z-10 shadow-sm`,ref:W,style:{width:k,minWidth:k},children:e.map(e=>{let t=u&&j===e.id;return(0,c.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:x},onClick:()=>!t&&i?.(e),onDoubleClick:()=>{u&&a&&(M(e.id),P({title:e.title,start:e.start.toLocaleDateString(`en-CA`),end:e.end.toLocaleDateString(`en-CA`),progress:String(e.progress)}))},children:[(0,c.jsxs)(`div`,{className:`flex-1 truncate font-medium text-xs sm:text-sm flex items-center gap-2`,children:[(0,c.jsx)(`div`,{className:`w-2 h-2 rounded-full shrink-0`,style:{backgroundColor:e.color||`#3b82f6`}}),t?(0,c.jsx)(`input`,{className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:N.title||``,onChange:e=>P(t=>({...t,title:e.target.value})),onKeyDown:t=>{t.key===`Enter`?(a?.(e,{title:N.title,start:new Date(N.start),end:new Date(N.end),progress:Number(N.progress)||0}),M(null)):t.key===`Escape`&&M(null)},onClick:e=>e.stopPropagation(),autoFocus:!0}):(0,c.jsxs)(`span`,{className:`flex flex-col min-w-0`,children:[(0,c.jsx)(`span`,{className:`truncate`,children:e.title}),(0,c.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,c.jsx)(`div`,{className:`w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block`,hidden:!A,style:A?void 0:{display:`none`},children:t?(0,c.jsx)(`input`,{type:`date`,className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:N.start||``,onChange:e=>P(t=>({...t,start:e.target.value})),onClick:e=>e.stopPropagation()}):e.start.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})}),(0,c.jsx)(`div`,{className:`w-16 sm:w-20 text-right text-xs text-muted-foreground hidden sm:block`,hidden:!A,style:A?void 0:{display:`none`},children:t?(0,c.jsx)(`input`,{type:`date`,className:`border rounded px-1 py-0.5 text-xs w-full bg-background`,value:N.end||``,onChange:e=>P(t=>({...t,end:e.target.value})),onClick:e=>e.stopPropagation()}):e.end.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})})]},e.id)})}),(0,c.jsx)(`div`,{className:`flex-1 overflow-auto bg-background/50 relative [-webkit-overflow-scrolling:touch]`,ref:e=>{G.current=e,K.current=e},onScroll:ee,onTouchStart:J,onTouchMove:Y,onTouchEnd:X,"data-testid":`gantt-timeline`,children:(0,c.jsxs)(`div`,{className:`relative`,style:{width:H.length*T},children:[Z!=null&&(0,c.jsx)(`div`,{className:`absolute top-0 bottom-0 w-px bg-red-500/80 z-20 pointer-events-none`,style:{left:Z},"data-testid":`gantt-today-marker`,"aria-label":`Today`,children:(0,c.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:`Today`})}),(0,c.jsxs)(`div`,{className:`relative`,children:[(0,c.jsx)(`div`,{className:`absolute inset-0 flex pointer-events-none z-0`,children:H.map((e,t)=>(0,c.jsx)(`div`,{className:(0,o.cn)(`border-r h-full`,e.isWeekend&&`bg-muted/20`),style:{width:T,minWidth:T}},t))}),e.map(e=>{let t=$(e),n=F?.taskId===e.id,r=t;if(n&&F){let t=z(F);r=$({...e,start:t.start,end:t.end})}let s=!!a;return(0,c.jsxs)(`div`,{className:`relative border-b hover:bg-black/5`,style:{height:x},children:[n&&(0,c.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,c.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:()=>{R.current||i?.(e)},onPointerDown:s?t=>{t.button===0&&B(e,`move`,t)}:void 0,children:[s&&r.width>=14&&(0,c.jsxs)(c.Fragment,{children:[(0,c.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&&B(e,`resize-left`,t)},onClick:e=>e.stopPropagation()}),(0,c.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&&B(e,`resize-right`,t)},onClick:e=>e.stopPropagation()})]}),e.progress>0&&(0,c.jsx)(`div`,{className:`absolute left-0 top-0 bottom-0 bg-black/20 rounded-l-sm pointer-events-none`,style:{width:`${e.progress}%`}}),(0,c.jsx)(`span`,{className:`text-[10px] text-white font-medium truncate opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none`,children:n?`${z(F).start.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})} → ${z(F).end.toLocaleDateString(void 0,{month:`numeric`,day:`numeric`})}`:`${Math.round(e.progress)}%`})]})]},e.id)}),(0,c.jsx)(`div`,{className:`absolute top-0 bottom-0 w-px bg-red-500 z-20 pointer-events-none`,style:{left:(new Date().getTime()-V.start.getTime())/(1e3*60*60*24)*T},children:(0,c.jsx)(`div`,{className:`w-2 h-2 rounded-full bg-red-500 -ml-[3px]`})})]})]})})]})]})]})}function x(e){return e.data?e.data:e.staticData?{provider:`value`,items:e.staticData}:e.objectName?{provider:`object`,object:e.objectName}:null}function S(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 C(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 w=({schema:e,dataSource:i,className:s,onTaskClick:l,onRowClick:u,...d})=>{let[f,p]=(0,t.useState)([]),[m,h]=(0,t.useState)(!0),[g,_]=(0,t.useState)(null),[v,y]=(0,t.useState)(null),w=x(e),T=(0,t.useMemo)(()=>w,[JSON.stringify(w)]),E=C(e),D=T?.provider===`value`;(0,t.useEffect)(()=>{(async()=>{try{if(h(!0),d.data&&Array.isArray(d.data)){p(d.data),h(!1);return}if(D&&T?.provider===`value`){p(T.items),h(!1);return}if(!i||typeof i.find!=`function`)throw Error(`DataSource required for object/api providers`);if(T?.provider===`object`){let t=T.object,r=(0,n.buildExpandFields)(v?.fields);p((0,n.extractRecords)(await i.find(t,{$filter:e.filter,$orderby:S(e.sort),...r.length>0?{$expand:r}:{}})))}else T?.provider===`api`&&(console.warn(`API provider not yet implemented for ObjectGantt`),p([]));h(!1)}catch(e){_(e),h(!1)}})()},[T,i,D,e.filter,e.sort,v]),(0,t.useEffect)(()=>{!D&&i&&(async()=>{try{if(!i)return;let t=T?.provider===`object`?T.object:e.objectName;if(!t)return;y(await i.getObjectSchema(t))}catch(e){console.error(`Failed to fetch object schema:`,e)}})()},[e.objectName,i,D,T]);let O=(0,t.useMemo)(()=>{if(!E||!f.length)return[];let{startDateField:e,endDateField:t,titleField:n,progressField:r,dependenciesField:i,colorField:a}=E,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},s=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 f.map((n,o)=>{let c=n[e],l=n[t],u=s(n),d=r?n[r]:0,f=i?n[i]:[],p=a?n[a]:void 0;return{id:n.id||n._id||`task-${o}`,title:u,start:c?new Date(c):new Date,end:l?new Date(l):new Date,progress:Math.min(100,Math.max(0,d||0)),dependencies:Array.isArray(f)?f:[],color:p,data:n}}).filter(e=>!isNaN(e.start.getTime())&&!isNaN(e.end.getTime()))},[f,E]),k=e.navigation??{mode:`drawer`,width:`min(960px, 60vw)`},A=k.mode===`drawer`||k.mode===`modal`||k.mode===`split`||k.mode===`popover`,j=(0,r.useNavigationOverlay)({navigation:k,objectName:e.objectName,onRowClick:A?void 0:u}),M=(0,t.useCallback)(async(t,n)=>{if(!E)return;let r=T?.provider===`object`?T.object:e.objectName;if(!r||!i||typeof i.update!=`function`)return;let{startDateField:a,endDateField:o,titleField:s,progressField:c}=E,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=f;p(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),p(d)}},[E,T,i,e.objectName,f]),[N,P]=(0,t.useState)(null),[F,I]=(0,t.useState)(!1),L=(0,t.useCallback)(e=>{P(e)},[]),R=(0,t.useCallback)(async()=>{if(!N)return;let t=T?.provider===`object`?T.object:e.objectName;if(!t||!i?.delete){P(null);return}let n=N.data?.id??N.data?._id??N.id;if(n==null){P(null);return}I(!0);let r=f;p(e=>e.filter(e=>String(e.id??e._id)!==String(n)));try{await i.delete(t,String(n)),P(null)}catch(e){console.error(`[ObjectGantt] Failed to delete:`,e),p(r),P(null)}finally{I(!1)}},[N,T,i,e.objectName,f]);return m?(0,c.jsx)(`div`,{className:s,children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,c.jsx)(`div`,{className:`text-muted-foreground`,children:`Loading Gantt chart...`})})}):g?(0,c.jsx)(`div`,{className:s,children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,c.jsxs)(`div`,{className:`text-destructive`,children:[`Error: `,g.message]})})}):E?(0,c.jsxs)(`div`,{className:s,children:[(0,c.jsx)(`div`,{className:`h-[calc(100vh-200px)] min-h-[600px]`,children:(0,c.jsx)(b,{tasks:O,onTaskClick:e=>{j.handleClick(e.data),l?.(e.data)},onTaskUpdate:M,onTaskDelete:L,inlineEdit:!0})}),j.isOverlay&&j.isOpen&&j.selectedRecord&&(()=>{let t=T?.provider===`object`?T.object:e.objectName,n=j.selectedRecord,r=n.id??n._id;if(!t||r==null)return null;let o=E?.titleField?String(n[E.titleField]??`Task Details`):`Task Details`;return(0,c.jsx)(a.RecordDetailDrawer,{open:!0,onClose:j.close,title:o,record:n,objectName:t,recordId:r,dataSource:i,objectSchema:v,width:j.width,fullPageHref:(0,a.deriveRecordPageHref)(t,r)??void 0,onFieldSave:async(e,n)=>{i?.update&&(await i.update(t,String(r),{[e]:n}),p(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)),p(e=>e.filter(e=>String(e.id??e._id)!==String(r))))}})})(),(0,c.jsx)(o.AlertDialog,{open:!!N,onOpenChange:e=>{!e&&!F&&P(null)},children:(0,c.jsxs)(o.AlertDialogContent,{children:[(0,c.jsxs)(o.AlertDialogHeader,{children:[(0,c.jsx)(o.AlertDialogTitle,{children:`Delete this task?`}),(0,c.jsx)(o.AlertDialogDescription,{children:N?(0,c.jsxs)(c.Fragment,{children:[`"`,N.title,`" will be permanently removed. This action cannot be undone.`]}):null})]}),(0,c.jsxs)(o.AlertDialogFooter,{children:[(0,c.jsx)(o.AlertDialogCancel,{disabled:F,children:`Cancel`}),(0,c.jsx)(o.AlertDialogAction,{onClick:e=>{e.preventDefault(),R()},disabled:F,"data-testid":`gantt-delete-confirm`,className:`bg-destructive text-destructive-foreground hover:bg-destructive/90`,children:F?`Deleting…`:`Delete`})]})]})})]}):(0,c.jsx)(`div`,{className:s,children:(0,c.jsx)(`div`,{className:`flex items-center justify-center h-96`,children:(0,c.jsx)(`div`,{className:`text-muted-foreground`,children:`Gantt configuration required. Please specify startDateField, endDateField, and titleField.`})})})},T=({schema:e})=>{let{dataSource:t}=(0,r.useSchemaContext)()||{};return(0,c.jsx)(w,{schema:e,dataSource:t})};n.ComponentRegistry.register(`object-gantt`,T,{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`,T,{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=b,e.ObjectGantt=w,e.ObjectGanttRenderer=T});
@@ -15,19 +15,29 @@ export interface GanttTask {
15
15
  data?: any;
16
16
  dependencies?: (string | number)[];
17
17
  }
18
+ /**
19
+ * @deprecated The day/week/month/quarter view-mode dropdown was removed
20
+ * because all four values rendered the same daily-column timeline.
21
+ * Kept exported only to avoid breaking downstream type imports; the
22
+ * `viewMode` / `onViewChange` props on `GanttViewProps` are no-ops.
23
+ * Re-introduce real semantics here when timeline granularity is
24
+ * implemented.
25
+ */
18
26
  export type GanttViewMode = 'day' | 'week' | 'month' | 'quarter';
19
27
  export interface GanttViewProps {
20
28
  tasks: GanttTask[];
29
+ /** @deprecated no-op — see {@link GanttViewMode} */
21
30
  viewMode?: GanttViewMode;
22
31
  startDate?: Date;
23
32
  endDate?: Date;
24
33
  onTaskClick?: (task: GanttTask) => void;
25
34
  onTaskUpdate?: (task: GanttTask, changes: Partial<Pick<GanttTask, 'title' | 'start' | 'end' | 'progress'>>) => void;
35
+ onTaskDelete?: (task: GanttTask) => void;
36
+ /** @deprecated no-op — see {@link GanttViewMode} */
26
37
  onViewChange?: (view: GanttViewMode) => void;
27
- onAddClick?: () => void;
28
38
  className?: string;
29
39
  /** Enable inline editing of task fields */
30
40
  inlineEdit?: boolean;
31
41
  }
32
- export declare function GanttView({ tasks, viewMode, startDate, endDate, onTaskClick, onTaskUpdate, onViewChange, onAddClick, className, inlineEdit, }: GanttViewProps): import("react/jsx-runtime").JSX.Element;
42
+ export declare function GanttView({ tasks, startDate, endDate, onTaskClick, onTaskUpdate, className, inlineEdit, }: GanttViewProps): import("react/jsx-runtime").JSX.Element;
33
43
  //# sourceMappingURL=GanttView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GanttView.d.ts","sourceRoot":"","sources":["../../../../src/GanttView.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAoDH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,IAAI,CAAA;IACX,GAAG,EAAE,IAAI,CAAA;IACT,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,GAAG,CAAA;IACV,YAAY,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAA;CACnC;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,SAAS,CAAC,EAAE,IAAI,CAAA;IAChB,OAAO,CAAC,EAAE,IAAI,CAAA;IACd,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACvC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,CAAC,CAAC,KAAK,IAAI,CAAA;IACnH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAkB,EAClB,SAAS,EACT,OAAO,EACP,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,SAAS,EACT,UAAkB,GACnB,EAAE,cAAc,2CAybhB"}
1
+ {"version":3,"file":"GanttView.d.ts","sourceRoot":"","sources":["../../../../src/GanttView.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAoDH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,IAAI,CAAA;IACX,GAAG,EAAE,IAAI,CAAA;IACT,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,GAAG,CAAA;IACV,YAAY,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAA;CACnC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,SAAS,CAAC,EAAE,IAAI,CAAA;IAChB,OAAO,CAAC,EAAE,IAAI,CAAA;IACd,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACvC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,CAAC,CAAC,KAAK,IAAI,CAAA;IACnH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACxC,oDAAoD;IACpD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,SAAS,EACT,OAAO,EACP,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAkB,GACnB,EAAE,cAAc,2CA6kBhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectGantt.d.ts","sourceRoot":"","sources":["../../../../src/ObjectGantt.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAuC,MAAM,OAAO,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAyB,MAAM,kBAAkB,CAAC;AAO5F,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;CAClC;AAyFD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAkMlD,CAAC"}
1
+ {"version":3,"file":"ObjectGantt.d.ts","sourceRoot":"","sources":["../../../../src/ObjectGantt.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAoD,MAAM,OAAO,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAyB,MAAM,kBAAkB,CAAC;AAiB5F,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;CAClC;AAyFD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA0XlD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/plugin-gantt",
3
- "version": "4.0.6",
3
+ "version": "4.0.8",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Gantt chart plugin for Object UI",
@@ -24,13 +24,14 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@objectstack/spec": "^4.0.4",
27
+ "@objectstack/spec": "^4.0.5",
28
28
  "lucide-react": "^1.14.0",
29
- "@object-ui/components": "4.0.6",
30
- "@object-ui/core": "4.0.6",
31
- "@object-ui/fields": "4.0.6",
32
- "@object-ui/react": "4.0.6",
33
- "@object-ui/types": "4.0.6"
29
+ "@object-ui/components": "4.0.8",
30
+ "@object-ui/core": "4.0.8",
31
+ "@object-ui/fields": "4.0.8",
32
+ "@object-ui/plugin-detail": "4.0.8",
33
+ "@object-ui/react": "4.0.8",
34
+ "@object-ui/types": "4.0.8"
34
35
  },
35
36
  "peerDependencies": {
36
37
  "react": "^18.0.0 || ^19.0.0",
@@ -41,7 +42,7 @@
41
42
  "@types/react-dom": "19.2.3",
42
43
  "@vitejs/plugin-react": "^6.0.1",
43
44
  "typescript": "^6.0.3",
44
- "vite": "^8.0.10",
45
+ "vite": "^8.0.12",
45
46
  "vite-plugin-dts": "^5.0.0"
46
47
  },
47
48
  "keywords": [