@object-ui/plugin-gantt 17.5.0 → 17.6.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 +218 -0
- package/README.md +353 -119
- package/dist/GanttView.d.ts +41 -36
- package/dist/GanttView.d.ts.map +1 -1
- package/dist/ObjectGantt.d.ts +2 -2
- package/dist/ObjectGantt.d.ts.map +1 -1
- package/dist/QuickFilterBar.d.ts +16 -4
- package/dist/QuickFilterBar.d.ts.map +1 -1
- package/dist/ResourceWorkload.d.ts +1 -1
- package/dist/index.js +495 -502
- package/dist/index.umd.cjs +11 -10
- package/dist/scheduling.d.ts +7 -7
- package/dist/shifts.d.ts +16 -13
- package/dist/shifts.d.ts.map +1 -1
- package/dist/workload.d.ts +1 -1
- package/package.json +11 -11
- package/dist/tsconfig.tsbuildinfo +0 -1
package/README.md
CHANGED
|
@@ -66,8 +66,11 @@ to opt in:
|
|
|
66
66
|
<GanttView
|
|
67
67
|
tasks={tasks}
|
|
68
68
|
onTaskUpdate={(task, { start, end }) => {
|
|
69
|
-
//
|
|
70
|
-
//
|
|
69
|
+
// `changes` is a Partial<Pick<GanttTask, 'title' | 'start' | 'end' | 'progress'>>:
|
|
70
|
+
// only the keys the edit actually touched are present. A bar drag/resize
|
|
71
|
+
// sends start + end, but the progress grip sends just { progress } — so
|
|
72
|
+
// guard, or a progress drag writes both dates back as undefined.
|
|
73
|
+
if (!start || !end) return;
|
|
71
74
|
save(task.id, { start, end });
|
|
72
75
|
}}
|
|
73
76
|
/>
|
|
@@ -87,30 +90,95 @@ pnpm add @object-ui/plugin-gantt
|
|
|
87
90
|
// In your app entry point (e.g., App.tsx or main.tsx)
|
|
88
91
|
import '@object-ui/plugin-gantt';
|
|
89
92
|
|
|
90
|
-
// Now you can use gantt types in your schemas
|
|
93
|
+
// Now you can use gantt types in your schemas.
|
|
94
|
+
// The gantt is RECORD-DRIVEN: it names a data source and the fields to read.
|
|
95
|
+
// It does not take a task array — see "Schema API" below.
|
|
91
96
|
const schema = {
|
|
92
97
|
type: 'gantt',
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
end: '2024-01-05',
|
|
99
|
-
progress: 100
|
|
100
|
-
}
|
|
101
|
-
]
|
|
98
|
+
objectName: 'project_tasks',
|
|
99
|
+
titleField: 'name',
|
|
100
|
+
startDateField: 'start_date',
|
|
101
|
+
endDateField: 'end_date',
|
|
102
|
+
progressField: 'completion_percentage'
|
|
102
103
|
};
|
|
103
104
|
```
|
|
104
105
|
|
|
105
|
-
###
|
|
106
|
+
### What the side-effect import registers
|
|
107
|
+
|
|
108
|
+
Registration is *only* a side effect of importing the package — the single
|
|
109
|
+
`import '@object-ui/plugin-gantt'` above is the whole of it. There is no
|
|
110
|
+
components map to iterate over: importing the entry point runs the
|
|
111
|
+
`ComponentRegistry.register(...)` calls at the bottom of `src/index.tsx`, which
|
|
112
|
+
claim these schema types:
|
|
113
|
+
|
|
114
|
+
| Schema `type` | Namespaced key | Renderer |
|
|
115
|
+
| --- | --- | --- |
|
|
116
|
+
| `object-gantt` | `plugin-gantt:object-gantt` | `ObjectGanttRenderer` |
|
|
117
|
+
| `gantt` | `view:gantt` | `ObjectGanttRenderer` |
|
|
118
|
+
|
|
119
|
+
Both spellings resolve — `register` stores the namespaced key *and* a bare-`type`
|
|
120
|
+
fallback. Both keys declare the same two inputs: `objectName` (required) and the
|
|
121
|
+
`gantt` configuration object.
|
|
122
|
+
|
|
123
|
+
`ObjectGanttRenderer` is a thin wrapper: it pulls `dataSource` off the renderer
|
|
124
|
+
context and hands the schema to `ObjectGantt`.
|
|
125
|
+
|
|
126
|
+
### Public exports
|
|
127
|
+
|
|
128
|
+
The package exports components, helpers and their types — not a registry map:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import {
|
|
132
|
+
ObjectGantt, // ObjectQL-integrated gantt: loads records, writes back edits
|
|
133
|
+
ObjectGanttRenderer, // the registered renderer for `object-gantt` / `gantt`
|
|
134
|
+
GanttView, // the standalone timeline component
|
|
135
|
+
QuickFilterBar, // the toolbar's quick-filter dropdowns
|
|
136
|
+
ResourceWorkload, // resource × period workload grid
|
|
137
|
+
normalizeDependencies, // raw dependency-field value -> GanttDependency[]
|
|
138
|
+
normalizeTaskType, // raw type-field value -> GanttTaskType
|
|
139
|
+
normalizeShiftSegments, // raw timeSegments config -> NormShiftSegments
|
|
140
|
+
parseHHMM,
|
|
141
|
+
shiftDayStart,
|
|
142
|
+
bandAt,
|
|
143
|
+
computeWorkload,
|
|
144
|
+
} from '@object-ui/plugin-gantt';
|
|
145
|
+
|
|
146
|
+
import type {
|
|
147
|
+
ObjectGanttProps,
|
|
148
|
+
GanttViewProps,
|
|
149
|
+
GanttTask,
|
|
150
|
+
GanttTaskType,
|
|
151
|
+
GanttViewMode,
|
|
152
|
+
GanttDependency,
|
|
153
|
+
GanttDependencyObject,
|
|
154
|
+
GanttLinkType,
|
|
155
|
+
GanttMarker,
|
|
156
|
+
QuickFilterDef,
|
|
157
|
+
QuickFilterBarProps,
|
|
158
|
+
QuickFilterField,
|
|
159
|
+
QuickFilterOption,
|
|
160
|
+
QuickFilterLabels,
|
|
161
|
+
ShiftSegmentsConfig,
|
|
162
|
+
ShiftBandConfig,
|
|
163
|
+
NormShiftSegments,
|
|
164
|
+
NormShiftBand,
|
|
165
|
+
ResourceWorkloadProps,
|
|
166
|
+
WorkloadColumn,
|
|
167
|
+
WorkloadOptions,
|
|
168
|
+
ResourceCell,
|
|
169
|
+
ResourceLoad,
|
|
170
|
+
} from '@object-ui/plugin-gantt';
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
To serve the gantt under a registry key of your own, register the exported
|
|
174
|
+
renderer under that key:
|
|
106
175
|
|
|
107
176
|
```typescript
|
|
108
|
-
import { ganttComponents } from '@object-ui/plugin-gantt';
|
|
109
177
|
import { ComponentRegistry } from '@object-ui/core';
|
|
178
|
+
import { ObjectGanttRenderer } from '@object-ui/plugin-gantt';
|
|
110
179
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
ComponentRegistry.register(type, component);
|
|
180
|
+
ComponentRegistry.register('my-gantt', ObjectGanttRenderer, {
|
|
181
|
+
namespace: 'my-app',
|
|
114
182
|
});
|
|
115
183
|
```
|
|
116
184
|
|
|
@@ -118,109 +186,218 @@ Object.entries(ganttComponents).forEach(([type, component]) => {
|
|
|
118
186
|
|
|
119
187
|
### Gantt Chart
|
|
120
188
|
|
|
121
|
-
|
|
189
|
+
The gantt node is **record-driven**: it names *where records come from* and
|
|
190
|
+
*which fields* carry the schedule. It does not carry a task array — the task
|
|
191
|
+
objects further down this page are the component's runtime shape, produced by
|
|
192
|
+
`ObjectGantt` from each record.
|
|
193
|
+
|
|
194
|
+
`ObjectGantt` decides what to render from exactly two reads
|
|
195
|
+
(`src/ObjectGantt.tsx`):
|
|
196
|
+
|
|
197
|
+
**1. Where the records come from — `getDataConfig`.** The first of these three
|
|
198
|
+
that is present wins; if none is present there is no data config at all and the
|
|
199
|
+
chart renders empty:
|
|
122
200
|
|
|
123
201
|
```typescript
|
|
124
202
|
{
|
|
125
203
|
type: 'gantt',
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
className?: string
|
|
204
|
+
|
|
205
|
+
// Pick ONE of the three:
|
|
206
|
+
objectName: 'project_tasks', // load through the host DataSource
|
|
207
|
+
// data: { provider: 'value', items: [ /* records */ ] }, // inline records
|
|
208
|
+
// staticData: [ /* records */ ], // shorthand for the above
|
|
132
209
|
}
|
|
133
210
|
```
|
|
134
211
|
|
|
212
|
+
`data` is the spec's `ViewData` union — `{ provider: 'object', object }`,
|
|
213
|
+
`{ provider: 'value', items }`, `{ provider: 'api', read, write }` or
|
|
214
|
+
`{ provider: 'schema', schemaId }`.
|
|
215
|
+
|
|
216
|
+
**2. How the fields map — `getGanttConfig`.** Two spellings, checked in order.
|
|
217
|
+
Top-level keys are used **only when `startDateField` and `endDateField` are both
|
|
218
|
+
present**; otherwise the whole `gantt` block is read instead:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
{
|
|
222
|
+
type: 'gantt',
|
|
223
|
+
objectName: 'project_tasks',
|
|
224
|
+
|
|
225
|
+
// (a) flat spelling — requires BOTH date fields to be taken
|
|
226
|
+
startDateField: 'start_date',
|
|
227
|
+
endDateField: 'end_date',
|
|
228
|
+
titleField: 'name', // defaults to 'name'
|
|
229
|
+
progressField: 'completion_percentage',
|
|
230
|
+
dependenciesField: 'dependent_task_ids',
|
|
231
|
+
colorField: 'bar_color',
|
|
232
|
+
parentField: 'parent_task',
|
|
233
|
+
typeField: 'task_kind',
|
|
234
|
+
viewMode: 'week', // 'day'|'week'|'month'|'quarter'|'year'
|
|
235
|
+
|
|
236
|
+
// (b) …or the same configuration as one block:
|
|
237
|
+
// gantt: { startDateField: 'start_date', endDateField: 'end_date', … }
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`viewMode` is real authoring surface (`ObjectGanttSchema`, derived from the
|
|
242
|
+
spec's `GanttConfigSchema.viewMode`) and is honoured by **both** renderer
|
|
243
|
+
branches — the timeline and the resource-workload grid. It reaches the renderer
|
|
244
|
+
through `getGanttConfig`, so it only takes effect alongside a taken gantt
|
|
245
|
+
config: as a top-level key it needs `startDateField` + `endDateField` beside it,
|
|
246
|
+
or it can sit inside the `gantt` block. Omitting it is meaningful — a persisted
|
|
247
|
+
layout then seeds the granularity before the renderer's `'day'` fallback.
|
|
248
|
+
|
|
249
|
+
#### Keys this page used to teach that the renderer never reads
|
|
250
|
+
|
|
251
|
+
Earlier revisions of this README showed a task-array schema. Those keys have no
|
|
252
|
+
read site anywhere in `src/` — a schema built from them renders an **empty
|
|
253
|
+
chart with no diagnostic**, because `type: 'gantt'` *is* a registered type, so
|
|
254
|
+
the node mounts and simply finds nothing to draw:
|
|
255
|
+
|
|
256
|
+
| Key shown before | Status | Use instead |
|
|
257
|
+
| --- | --- | --- |
|
|
258
|
+
| `tasks` | never read off the schema | `objectName` / `data` / `staticData` |
|
|
259
|
+
| `object` | never read | `objectName` |
|
|
260
|
+
| `nameField` | never read | `titleField` |
|
|
261
|
+
| `startField` | never read | `startDateField` |
|
|
262
|
+
| `endField` | never read | `endDateField` |
|
|
263
|
+
| `fields: { name, start, end, … }` | never read | the flat `*Field` keys, or the `gantt` block |
|
|
264
|
+
| `onTaskClick`, `onTaskUpdate` | never read *off the schema* | React props on `<ObjectGantt>` / `<GanttView>` — functions do not belong in serializable metadata |
|
|
265
|
+
| `className` | never read off the schema | a React prop on `<ObjectGantt>` |
|
|
266
|
+
|
|
267
|
+
Keys that **are** read but only through a cast, so they are easy to miss when
|
|
268
|
+
grepping — all of them genuine, all optional: `readOnly` (disables every edit
|
|
269
|
+
path — drag/resize/inline/delete/link/undo), `mobileReadOnly`, `markers`,
|
|
270
|
+
`navigation`, `skipWeekends`, `holidays`, `criticalPath`, `showBaselines`,
|
|
271
|
+
`persistLayout` / `viewName`, `label`.
|
|
272
|
+
|
|
135
273
|
### Task Structure
|
|
136
274
|
|
|
275
|
+
`GanttTask` is the **component's runtime** task — what `<GanttView>` renders and
|
|
276
|
+
what `ObjectGantt` produces from each record. Dates are real `Date` objects and
|
|
277
|
+
the label field is `title` (`src/GanttView.tsx`):
|
|
278
|
+
|
|
137
279
|
```typescript
|
|
138
280
|
interface GanttTask {
|
|
139
|
-
id: string;
|
|
140
|
-
|
|
141
|
-
start:
|
|
142
|
-
end:
|
|
143
|
-
progress: number;
|
|
144
|
-
dependencies?:
|
|
145
|
-
|
|
146
|
-
|
|
281
|
+
id: string | number;
|
|
282
|
+
title: string;
|
|
283
|
+
start: Date;
|
|
284
|
+
end: Date;
|
|
285
|
+
progress: number; // 0-100
|
|
286
|
+
dependencies?: GanttDependency[]; // predecessor id, optionally with a link type
|
|
287
|
+
parent?: string | number | null; // builds the hierarchy; unknown ids render as roots
|
|
288
|
+
type?: GanttTaskType; // 'task' | 'summary' | 'milestone' | 'group'
|
|
289
|
+
color?: string; // bar fill — any CSS color, e.g. '#3b82f6'
|
|
290
|
+
borderColor?: string; // alert outline, fill untouched
|
|
291
|
+
locked?: boolean; // view-only row (still clickable)
|
|
292
|
+
baselineStart?: Date; // planned-vs-actual reference bar
|
|
293
|
+
baselineEnd?: Date;
|
|
294
|
+
data?: any; // the source record behind the row
|
|
147
295
|
}
|
|
148
296
|
```
|
|
149
297
|
|
|
298
|
+
A few more optional fields (`fields` for tooltip rows, `hasOwnDates`) are
|
|
299
|
+
populated by `ObjectGantt` itself — see `GanttTask` in `src/GanttView.tsx` for
|
|
300
|
+
the full declaration.
|
|
301
|
+
|
|
150
302
|
## Examples
|
|
151
303
|
|
|
152
304
|
### Basic Gantt Chart
|
|
153
305
|
|
|
306
|
+
Inline records, no backend — `data.items` carries the records and the `*Field`
|
|
307
|
+
keys say which of their fields the chart reads. Note that the record field
|
|
308
|
+
names are yours; only the `*Field` keys are fixed vocabulary.
|
|
309
|
+
|
|
154
310
|
```typescript
|
|
155
311
|
const schema = {
|
|
156
312
|
type: 'gantt',
|
|
157
313
|
viewMode: 'week',
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
314
|
+
startDateField: 'start',
|
|
315
|
+
endDateField: 'end',
|
|
316
|
+
titleField: 'name',
|
|
317
|
+
progressField: 'progress',
|
|
318
|
+
dependenciesField: 'dependencies',
|
|
319
|
+
colorField: 'color',
|
|
320
|
+
data: {
|
|
321
|
+
provider: 'value',
|
|
322
|
+
items: [
|
|
323
|
+
{
|
|
324
|
+
id: '1',
|
|
325
|
+
name: 'Project Planning',
|
|
326
|
+
start: '2024-01-01',
|
|
327
|
+
end: '2024-01-07',
|
|
328
|
+
progress: 100,
|
|
329
|
+
// bar fill goes straight into an inline `backgroundColor` —
|
|
330
|
+
// it must be a CSS color, NOT a Tailwind class
|
|
331
|
+
color: '#3b82f6'
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
id: '2',
|
|
335
|
+
name: 'Design Phase',
|
|
336
|
+
start: '2024-01-08',
|
|
337
|
+
end: '2024-01-21',
|
|
338
|
+
progress: 75,
|
|
339
|
+
dependencies: ['1'],
|
|
340
|
+
color: '#a855f7'
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
id: '3',
|
|
344
|
+
name: 'Development',
|
|
345
|
+
start: '2024-01-22',
|
|
346
|
+
end: '2024-02-15',
|
|
347
|
+
progress: 30,
|
|
348
|
+
dependencies: ['2'],
|
|
349
|
+
color: '#22c55e'
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
id: '4',
|
|
353
|
+
name: 'Testing',
|
|
354
|
+
start: '2024-02-16',
|
|
355
|
+
end: '2024-02-28',
|
|
356
|
+
progress: 0,
|
|
357
|
+
dependencies: ['3'],
|
|
358
|
+
color: '#f97316'
|
|
359
|
+
}
|
|
360
|
+
]
|
|
361
|
+
}
|
|
195
362
|
};
|
|
196
363
|
```
|
|
197
364
|
|
|
198
365
|
### Interactive Gantt
|
|
199
366
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
367
|
+
Callbacks are **not** schema keys — the schema is serializable metadata, and a
|
|
368
|
+
function cannot survive it. Through the registered `gantt` / `object-gantt`
|
|
369
|
+
types the whole CRUD lifecycle is already wired to the host `DataSource`
|
|
370
|
+
(create/edit/drag/delete/detail drawer), so there is usually nothing to pass.
|
|
371
|
+
When you render the component yourself, hand the callbacks in as React props:
|
|
372
|
+
|
|
373
|
+
```tsx
|
|
374
|
+
import { ObjectGantt } from '@object-ui/plugin-gantt';
|
|
375
|
+
|
|
376
|
+
<ObjectGantt
|
|
377
|
+
schema={{
|
|
378
|
+
type: 'gantt',
|
|
379
|
+
objectName: 'project_tasks',
|
|
380
|
+
startDateField: 'start_date',
|
|
381
|
+
endDateField: 'end_date',
|
|
382
|
+
titleField: 'name',
|
|
383
|
+
}}
|
|
384
|
+
dataSource={dataSource}
|
|
385
|
+
onTaskClick={(record) => console.log('Task clicked:', record)}
|
|
386
|
+
/>
|
|
213
387
|
```
|
|
214
388
|
|
|
389
|
+
To turn editing off from the metadata instead, set `readOnly: true` on the
|
|
390
|
+
schema — that one *is* read.
|
|
391
|
+
|
|
215
392
|
### With ObjectQL Integration
|
|
216
393
|
|
|
217
394
|
```typescript
|
|
218
395
|
const schema = {
|
|
219
396
|
type: 'object-gantt',
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
397
|
+
objectName: 'project_tasks',
|
|
398
|
+
titleField: 'name',
|
|
399
|
+
startDateField: 'start_date',
|
|
400
|
+
endDateField: 'end_date',
|
|
224
401
|
progressField: 'completion_percentage',
|
|
225
402
|
dependenciesField: 'dependent_task_ids'
|
|
226
403
|
};
|
|
@@ -234,6 +411,7 @@ The Gantt chart renders one timeline column per unit of the active scale:
|
|
|
234
411
|
- **week** - one column per week (starting Monday)
|
|
235
412
|
- **month** - one column per calendar month
|
|
236
413
|
- **quarter** - one column per quarter (Q1–Q4)
|
|
414
|
+
- **year** - one column per year (decade band above)
|
|
237
415
|
|
|
238
416
|
A two-row header shows the grouping above the units (months above days/weeks,
|
|
239
417
|
years above months/quarters). The toolbar's segmented control switches scales
|
|
@@ -243,11 +421,17 @@ Drag snapping follows the active scale: bars snap to days in day view, weeks
|
|
|
243
421
|
in week view, and whole calendar months/quarters (duration preserved) in the
|
|
244
422
|
coarse views.
|
|
245
423
|
|
|
424
|
+
Set the initial scale with `viewMode`. It is read through the gantt config, so
|
|
425
|
+
it needs the field mapping beside it (or a `gantt` block of its own):
|
|
426
|
+
|
|
246
427
|
```typescript
|
|
247
428
|
const schema = {
|
|
248
429
|
type: 'gantt',
|
|
249
430
|
viewMode: 'month',
|
|
250
|
-
|
|
431
|
+
objectName: 'project_tasks',
|
|
432
|
+
startDateField: 'start_date',
|
|
433
|
+
endDateField: 'end_date',
|
|
434
|
+
titleField: 'name'
|
|
251
435
|
};
|
|
252
436
|
```
|
|
253
437
|
|
|
@@ -266,12 +450,19 @@ Zero-duration tasks (`end <= start`) — or tasks whose `type` is
|
|
|
266
450
|
can be dragged to move but not resized; dependency arrows anchor at the
|
|
267
451
|
diamond center.
|
|
268
452
|
|
|
453
|
+
These are runtime `GanttTask` objects (what `<GanttView>` takes directly) —
|
|
454
|
+
dates are real `Date`s and the label field is `title`. Coming from records
|
|
455
|
+
instead, the same tree is configured with `parentField` / `typeField`.
|
|
456
|
+
|
|
269
457
|
```typescript
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
{ id: '
|
|
458
|
+
import type { GanttTask } from '@object-ui/plugin-gantt';
|
|
459
|
+
|
|
460
|
+
const tasks: GanttTask[] = [
|
|
461
|
+
// summary (has children) — its span and progress are rolled up
|
|
462
|
+
{ id: 'phase1', title: 'Phase 1', start: new Date('2024-06-01'), end: new Date('2024-06-30'), progress: 0 },
|
|
463
|
+
{ id: 't1', title: 'Design', parent: 'phase1', start: new Date('2024-06-01'), end: new Date('2024-06-14'), progress: 80 },
|
|
464
|
+
{ id: 't2', title: 'Build', parent: 'phase1', start: new Date('2024-06-15'), end: new Date('2024-06-30'), progress: 20 },
|
|
465
|
+
{ id: 'launch', title: 'Launch', type: 'milestone', start: new Date('2024-07-01'), end: new Date('2024-07-01'), progress: 0 },
|
|
275
466
|
];
|
|
276
467
|
```
|
|
277
468
|
|
|
@@ -329,33 +520,38 @@ Through the schema, pass the same array as `markers` on the gantt node.
|
|
|
329
520
|
Link tasks to show dependencies:
|
|
330
521
|
|
|
331
522
|
```typescript
|
|
332
|
-
|
|
523
|
+
import type { GanttTask } from '@object-ui/plugin-gantt';
|
|
524
|
+
|
|
525
|
+
const tasks: GanttTask[] = [
|
|
333
526
|
{
|
|
334
527
|
id: 'task-1',
|
|
335
|
-
|
|
336
|
-
start: '2024-01-01',
|
|
337
|
-
end: '2024-01-10',
|
|
528
|
+
title: 'Foundation',
|
|
529
|
+
start: new Date('2024-01-01'),
|
|
530
|
+
end: new Date('2024-01-10'),
|
|
338
531
|
progress: 100
|
|
339
532
|
},
|
|
340
533
|
{
|
|
341
534
|
id: 'task-2',
|
|
342
|
-
|
|
343
|
-
start: '2024-01-11',
|
|
344
|
-
end: '2024-01-25',
|
|
535
|
+
title: 'Building',
|
|
536
|
+
start: new Date('2024-01-11'),
|
|
537
|
+
end: new Date('2024-01-25'),
|
|
345
538
|
progress: 50,
|
|
346
539
|
dependencies: ['task-1'] // Depends on task-1
|
|
347
540
|
},
|
|
348
541
|
{
|
|
349
542
|
id: 'task-3',
|
|
350
|
-
|
|
351
|
-
start: '2024-01-26',
|
|
352
|
-
end: '2024-02-05',
|
|
543
|
+
title: 'Finishing',
|
|
544
|
+
start: new Date('2024-01-26'),
|
|
545
|
+
end: new Date('2024-02-05'),
|
|
353
546
|
progress: 0,
|
|
354
547
|
dependencies: ['task-2'] // Depends on task-2
|
|
355
548
|
}
|
|
356
549
|
];
|
|
357
550
|
```
|
|
358
551
|
|
|
552
|
+
Through a data source the same links come from `dependenciesField` on the
|
|
553
|
+
schema, and the tree/label fields from `parentField` / `titleField`.
|
|
554
|
+
|
|
359
555
|
Dependencies render as arrows from the predecessor bar to the dependent bar.
|
|
360
556
|
Arrows follow bars live while dragging, and hovering a bar highlights its links.
|
|
361
557
|
|
|
@@ -380,8 +576,13 @@ be a CSV string (`"task1, task2"`), an array of ids, or an array of objects —
|
|
|
380
576
|
|
|
381
577
|
## Integration with Data Sources
|
|
382
578
|
|
|
383
|
-
|
|
579
|
+
The adapter is **not** a schema key — it reaches the renderer through the
|
|
580
|
+
renderer context (or as an explicit `dataSource` prop), while the schema names
|
|
581
|
+
the object and the fields:
|
|
582
|
+
|
|
583
|
+
```tsx
|
|
384
584
|
import { createObjectStackAdapter } from '@object-ui/data-objectstack';
|
|
585
|
+
import { ObjectGantt } from '@object-ui/plugin-gantt';
|
|
385
586
|
|
|
386
587
|
const dataSource = createObjectStackAdapter({
|
|
387
588
|
baseUrl: 'https://api.example.com',
|
|
@@ -390,38 +591,71 @@ const dataSource = createObjectStackAdapter({
|
|
|
390
591
|
|
|
391
592
|
const schema = {
|
|
392
593
|
type: 'object-gantt',
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
end: 'end_date',
|
|
399
|
-
progress: 'progress_percent'
|
|
400
|
-
}
|
|
594
|
+
objectName: 'tasks',
|
|
595
|
+
titleField: 'task_name',
|
|
596
|
+
startDateField: 'start_date',
|
|
597
|
+
endDateField: 'end_date',
|
|
598
|
+
progressField: 'progress_percent'
|
|
401
599
|
};
|
|
600
|
+
|
|
601
|
+
<ObjectGantt schema={schema} dataSource={dataSource} />
|
|
402
602
|
```
|
|
403
603
|
|
|
604
|
+
⚠️ A `dataSource` key **on the schema node** is a different thing with the same
|
|
605
|
+
name: it is the spec's `PageComponentSchema.dataSource` *binding* —
|
|
606
|
+
`{ object, view?, filter?, sort?, limit? }`, a declarative reference resolved
|
|
607
|
+
against the host — **not** an adapter instance. The renderer guards against the
|
|
608
|
+
confusion explicitly, so putting a live adapter there does not wire anything up.
|
|
609
|
+
|
|
404
610
|
## TypeScript Support
|
|
405
611
|
|
|
612
|
+
Two different vocabularies, two different packages — don't mix them up.
|
|
613
|
+
|
|
614
|
+
**The component's runtime types** come from this package. Use them when you
|
|
615
|
+
render `<GanttView>` (or `ObjectGantt`) yourself in React:
|
|
616
|
+
|
|
406
617
|
```typescript
|
|
407
|
-
import type {
|
|
618
|
+
import type { GanttTask, GanttViewProps } from '@object-ui/plugin-gantt';
|
|
408
619
|
|
|
409
620
|
const task: GanttTask = {
|
|
410
621
|
id: '1',
|
|
411
|
-
|
|
412
|
-
start: '2024-01-01',
|
|
413
|
-
end: '2024-01-10',
|
|
622
|
+
title: 'My Task',
|
|
623
|
+
start: new Date('2024-01-01'),
|
|
624
|
+
end: new Date('2024-01-10'),
|
|
414
625
|
progress: 50,
|
|
415
|
-
dependencies: []
|
|
626
|
+
dependencies: [],
|
|
416
627
|
};
|
|
417
628
|
|
|
418
|
-
const
|
|
419
|
-
|
|
629
|
+
const props: GanttViewProps = {
|
|
630
|
+
tasks: [task],
|
|
420
631
|
viewMode: 'week',
|
|
421
|
-
tasks: [task]
|
|
422
632
|
};
|
|
423
633
|
```
|
|
424
634
|
|
|
635
|
+
**The authored (JSON metadata) types** live in `@object-ui/types` — this package
|
|
636
|
+
imports them and does not re-export them. There is no `GanttSchema`; the
|
|
637
|
+
component schema is `ObjectGanttSchema`, and it is **record-driven**: it names an
|
|
638
|
+
object and the fields to read, it does not carry a task array.
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
import type { ObjectGanttSchema } from '@object-ui/types';
|
|
642
|
+
|
|
643
|
+
const gantt: ObjectGanttSchema = {
|
|
644
|
+
type: 'object-gantt',
|
|
645
|
+
objectName: 'project_tasks',
|
|
646
|
+
titleField: 'name',
|
|
647
|
+
startDateField: 'start_date',
|
|
648
|
+
endDateField: 'end_date',
|
|
649
|
+
progressField: 'completion_percentage',
|
|
650
|
+
dependencyField: 'dependent_task_ids',
|
|
651
|
+
};
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
For a list view served under the `gantt` view type, the same configuration is a
|
|
655
|
+
`gantt` block on `ListViewSchema` (typed by `GanttConfig`, also from
|
|
656
|
+
`@object-ui/types`) rather than top-level keys — `ObjectGantt` reads either
|
|
657
|
+
spelling.
|
|
658
|
+
|
|
425
659
|
## Links
|
|
426
660
|
|
|
427
661
|
- 📚 [Documentation](https://www.objectui.org/docs/plugins/plugin-gantt)
|