@memberjunction/ng-gantt 0.0.1 → 5.23.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.
@@ -0,0 +1,54 @@
1
+ import { EventEmitter, ElementRef, AfterViewInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
2
+ import { GanttItemData, GanttLinkData, GanttColumnDef, GanttItemClickedEvent, GanttItemChangedEvent } from '../models/gantt.models';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Generic Gantt chart component wrapping DHTMLX Gantt.
6
+ *
7
+ * Renders items as bars on a timeline with hierarchy, dependency arrows,
8
+ * and progress indicators. The library is loaded lazily via dynamic import.
9
+ *
10
+ * @example
11
+ * ```html
12
+ * <mj-gantt-chart
13
+ * [Items]="projectTasks"
14
+ * [Links]="taskDependencies"
15
+ * [Height]="'600px'"
16
+ * (ItemClicked)="onTaskClicked($event)">
17
+ * </mj-gantt-chart>
18
+ * ```
19
+ */
20
+ export declare class MjGanttChartComponent implements AfterViewInit, OnChanges, OnDestroy {
21
+ /** Items (bars) to render on the timeline. */
22
+ Items: GanttItemData[];
23
+ /** Dependency links (arrows) between items. */
24
+ Links: GanttLinkData[];
25
+ /** CSS height for the chart container. */
26
+ Height: string;
27
+ /** Disables drag, resize, and link editing. */
28
+ ReadOnly: boolean;
29
+ /** Show progress fill on bars. */
30
+ ShowProgress: boolean;
31
+ /** Grid column definitions. Defaults to Name, Start, Duration, Progress. */
32
+ Columns: GanttColumnDef[] | null;
33
+ /** Emitted when an item bar or grid row is clicked. */
34
+ ItemClicked: EventEmitter<GanttItemClickedEvent>;
35
+ /** Emitted when an item is changed via drag/resize (only if not ReadOnly). */
36
+ ItemChanged: EventEmitter<GanttItemChangedEvent>;
37
+ ganttContainer: ElementRef<HTMLDivElement>;
38
+ /** @internal */
39
+ loading: boolean;
40
+ private gantt;
41
+ private initialized;
42
+ ngAfterViewInit(): Promise<void>;
43
+ ngOnChanges(changes: SimpleChanges): void;
44
+ ngOnDestroy(): void;
45
+ /** Rebuilds the Gantt data from the current `Items` and `Links` inputs. */
46
+ Refresh(): void;
47
+ private initGantt;
48
+ private updateData;
49
+ private formatDate;
50
+ private mapLinkType;
51
+ static ɵfac: i0.ɵɵFactoryDeclaration<MjGanttChartComponent, never>;
52
+ static ɵcmp: i0.ɵɵComponentDeclaration<MjGanttChartComponent, "mj-gantt-chart", never, { "Items": { "alias": "Items"; "required": false; }; "Links": { "alias": "Links"; "required": false; }; "Height": { "alias": "Height"; "required": false; }; "ReadOnly": { "alias": "ReadOnly"; "required": false; }; "ShowProgress": { "alias": "ShowProgress"; "required": false; }; "Columns": { "alias": "Columns"; "required": false; }; }, { "ItemClicked": "ItemClicked"; "ItemChanged": "ItemChanged"; }, never, never, true, never>;
53
+ }
54
+ //# sourceMappingURL=gantt-chart.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gantt-chart.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/gantt-chart.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,YAAY,EAAE,UAAU,EAAa,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAA2B,MAAM,eAAe,CAAC;AAG3K,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;;AAWpI;;;;;;;;;;;;;;;GAeG;AACH,qBAsCa,qBAAsB,YAAW,aAAa,EAAE,SAAS,EAAE,SAAS;IAC7E,8CAA8C;IACrC,KAAK,EAAE,aAAa,EAAE,CAAM;IAErC,+CAA+C;IACtC,KAAK,EAAE,aAAa,EAAE,CAAM;IAErC,0CAA0C;IACjC,MAAM,SAAW;IAE1B,+CAA+C;IACtC,QAAQ,UAAQ;IAEzB,kCAAkC;IACzB,YAAY,UAAQ;IAE7B,4EAA4E;IACnE,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI,CAAQ;IAEjD,uDAAuD;IAC7C,WAAW,sCAA6C;IAElE,8EAA8E;IACpE,WAAW,sCAA6C;IAElB,cAAc,EAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAE5F,gBAAgB;IAChB,OAAO,UAAQ;IACf,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,WAAW,CAAS;IAEtB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAetC,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAUzC,WAAW,IAAI,IAAI;IAOnB,2EAA2E;IACpE,OAAO,IAAI,IAAI;IAMtB,OAAO,CAAC,SAAS;IA8DjB,OAAO,CAAC,UAAU;IAoClB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,WAAW;yCAhLV,qBAAqB;2CAArB,qBAAqB;CAyLjC"}
@@ -0,0 +1,240 @@
1
+ import { Component, Input, Output, EventEmitter, ViewChild, ChangeDetectionStrategy } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { UUIDsEqual } from '@memberjunction/global';
4
+ import * as i0 from "@angular/core";
5
+ const _c0 = ["ganttContainer"];
6
+ function MjGanttChartComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
7
+ i0.ɵɵdomElementStart(0, "div", 1);
8
+ i0.ɵɵtext(1, "Loading Gantt chart...");
9
+ i0.ɵɵdomElementEnd();
10
+ } }
11
+ /** Default grid columns if none are provided. */
12
+ const DEFAULT_COLUMNS = [
13
+ { Name: 'text', Label: 'Name', Tree: true, Width: '*' },
14
+ { Name: 'start_date', Label: 'Start', Align: 'center', Width: 90 },
15
+ { Name: 'duration', Label: 'Days', Align: 'center', Width: 60 },
16
+ { Name: 'progress', Label: '%', Align: 'center', Width: 50, Template: (obj) => Math.round((obj.progress || 0) * 100) + '%' },
17
+ ];
18
+ /**
19
+ * Generic Gantt chart component wrapping DHTMLX Gantt.
20
+ *
21
+ * Renders items as bars on a timeline with hierarchy, dependency arrows,
22
+ * and progress indicators. The library is loaded lazily via dynamic import.
23
+ *
24
+ * @example
25
+ * ```html
26
+ * <mj-gantt-chart
27
+ * [Items]="projectTasks"
28
+ * [Links]="taskDependencies"
29
+ * [Height]="'600px'"
30
+ * (ItemClicked)="onTaskClicked($event)">
31
+ * </mj-gantt-chart>
32
+ * ```
33
+ */
34
+ export class MjGanttChartComponent {
35
+ /** Items (bars) to render on the timeline. */
36
+ Items = [];
37
+ /** Dependency links (arrows) between items. */
38
+ Links = [];
39
+ /** CSS height for the chart container. */
40
+ Height = '500px';
41
+ /** Disables drag, resize, and link editing. */
42
+ ReadOnly = true;
43
+ /** Show progress fill on bars. */
44
+ ShowProgress = true;
45
+ /** Grid column definitions. Defaults to Name, Start, Duration, Progress. */
46
+ Columns = null;
47
+ /** Emitted when an item bar or grid row is clicked. */
48
+ ItemClicked = new EventEmitter();
49
+ /** Emitted when an item is changed via drag/resize (only if not ReadOnly). */
50
+ ItemChanged = new EventEmitter();
51
+ ganttContainer;
52
+ /** @internal */
53
+ loading = true;
54
+ gantt = null;
55
+ initialized = false;
56
+ async ngAfterViewInit() {
57
+ try {
58
+ const module = await import('dhtmlx-gantt');
59
+ this.gantt = module.gantt;
60
+ this.loading = false;
61
+ if (this.Items.length > 0 && this.ganttContainer) {
62
+ this.initGantt();
63
+ }
64
+ }
65
+ catch (error) {
66
+ console.error('@memberjunction/ng-gantt: Failed to load dhtmlx-gantt:', error);
67
+ this.loading = false;
68
+ }
69
+ }
70
+ ngOnChanges(changes) {
71
+ if (!this.gantt)
72
+ return;
73
+ if (this.initialized && this.ganttContainer) {
74
+ this.updateData();
75
+ }
76
+ else if (!this.initialized && this.ganttContainer && this.Items.length > 0) {
77
+ this.initGantt();
78
+ }
79
+ }
80
+ ngOnDestroy() {
81
+ if (this.initialized && this.gantt) {
82
+ this.gantt.clearAll();
83
+ this.initialized = false;
84
+ }
85
+ }
86
+ /** Rebuilds the Gantt data from the current `Items` and `Links` inputs. */
87
+ Refresh() {
88
+ if (this.initialized) {
89
+ this.updateData();
90
+ }
91
+ }
92
+ initGantt() {
93
+ const g = this.gantt;
94
+ g.clearAll();
95
+ // Configuration
96
+ g.config.date_format = '%Y-%m-%d %H:%i';
97
+ g.config.show_progress = this.ShowProgress;
98
+ g.config.show_links = true;
99
+ g.config.readonly = this.ReadOnly;
100
+ g.config.open_tree_initially = true;
101
+ g.config.fit_tasks = true;
102
+ g.config.row_height = 36;
103
+ // Grid columns
104
+ const cols = this.Columns ?? DEFAULT_COLUMNS;
105
+ g.config.columns = cols.map(c => {
106
+ const col = {
107
+ name: c.Name,
108
+ label: c.Label,
109
+ width: c.Width === '*' ? '*' : (c.Width ?? 100),
110
+ };
111
+ if (c.Align)
112
+ col.align = c.Align;
113
+ if (c.Tree)
114
+ col.tree = true;
115
+ if (c.Template)
116
+ col.template = c.Template;
117
+ return col;
118
+ });
119
+ // Initialize
120
+ g.init(this.ganttContainer.nativeElement);
121
+ this.initialized = true;
122
+ // Event: click
123
+ g.attachEvent('onTaskClick', (id) => {
124
+ const item = this.Items.find(i => UUIDsEqual(i.ID, id));
125
+ if (item) {
126
+ this.ItemClicked.emit({ Item: item });
127
+ }
128
+ return true;
129
+ });
130
+ // Event: drag/resize (only fires if not readonly)
131
+ if (!this.ReadOnly) {
132
+ g.attachEvent('onAfterTaskDrag', (id) => {
133
+ const task = g.getTask(id);
134
+ const item = this.Items.find(i => UUIDsEqual(i.ID, id));
135
+ if (item && task) {
136
+ this.ItemChanged.emit({
137
+ Item: item,
138
+ NewStartDate: task.start_date,
139
+ NewEndDate: task.end_date,
140
+ NewDuration: task.duration,
141
+ });
142
+ }
143
+ });
144
+ }
145
+ this.updateData();
146
+ // Force layout after render
147
+ setTimeout(() => g.setSizes(), 0);
148
+ }
149
+ updateData() {
150
+ if (!this.initialized || !this.gantt)
151
+ return;
152
+ const g = this.gantt;
153
+ const data = this.Items.map(item => {
154
+ const startDate = item.StartDate instanceof Date ? item.StartDate : new Date(item.StartDate);
155
+ let duration = item.Duration ?? 1;
156
+ if (item.EndDate) {
157
+ const endDate = item.EndDate instanceof Date ? item.EndDate : new Date(item.EndDate);
158
+ duration = Math.max(1, Math.ceil((endDate.getTime() - startDate.getTime()) / 86400000));
159
+ }
160
+ return {
161
+ id: item.ID,
162
+ text: item.Name,
163
+ start_date: this.formatDate(startDate),
164
+ duration,
165
+ progress: (item.Progress ?? 0) / 100,
166
+ parent: item.ParentID || 0,
167
+ open: item.Open !== false,
168
+ };
169
+ });
170
+ const links = this.Links.map(link => ({
171
+ id: link.ID,
172
+ source: link.SourceID,
173
+ target: link.TargetID,
174
+ type: this.mapLinkType(link.Type),
175
+ }));
176
+ g.clearAll();
177
+ g.parse({ data: data, links: links });
178
+ setTimeout(() => g.setSizes(), 0);
179
+ }
180
+ formatDate(d) {
181
+ const y = d.getFullYear();
182
+ const m = String(d.getMonth() + 1).padStart(2, '0');
183
+ const day = String(d.getDate()).padStart(2, '0');
184
+ return `${y}-${m}-${day} 00:00`;
185
+ }
186
+ mapLinkType(type) {
187
+ switch (type) {
188
+ case 'FS': return '0';
189
+ case 'SS': return '1';
190
+ case 'FF': return '2';
191
+ case 'SF': return '3';
192
+ default: return '0';
193
+ }
194
+ }
195
+ static ɵfac = function MjGanttChartComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MjGanttChartComponent)(); };
196
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MjGanttChartComponent, selectors: [["mj-gantt-chart"]], viewQuery: function MjGanttChartComponent_Query(rf, ctx) { if (rf & 1) {
197
+ i0.ɵɵviewQuery(_c0, 5);
198
+ } if (rf & 2) {
199
+ let _t;
200
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.ganttContainer = _t.first);
201
+ } }, inputs: { Items: "Items", Links: "Links", Height: "Height", ReadOnly: "ReadOnly", ShowProgress: "ShowProgress", Columns: "Columns" }, outputs: { ItemClicked: "ItemClicked", ItemChanged: "ItemChanged" }, features: [i0.ɵɵNgOnChangesFeature], decls: 3, vars: 5, consts: [["ganttContainer", ""], [1, "mj-gantt-loading"], [1, "mj-gantt-container"]], template: function MjGanttChartComponent_Template(rf, ctx) { if (rf & 1) {
202
+ i0.ɵɵconditionalCreate(0, MjGanttChartComponent_Conditional_0_Template, 2, 0, "div", 1);
203
+ i0.ɵɵdomElement(1, "div", 2, 0);
204
+ } if (rf & 2) {
205
+ i0.ɵɵconditional(ctx.loading ? 0 : -1);
206
+ i0.ɵɵadvance();
207
+ i0.ɵɵstyleProp("height", ctx.Height)("display", ctx.loading ? "none" : "block");
208
+ } }, dependencies: [CommonModule], styles: ["[_nghost-%COMP%] { display: block; font-family: var(--mj-font-family); }\n\n .mj-gantt-container[_ngcontent-%COMP%] {\n width: 100%;\n position: relative;\n }\n\n .mj-gantt-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--mj-space-16) var(--mj-space-5);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n }\n\n \n\n [_nghost-%COMP%] .gantt_container { font-family: var(--mj-font-family); font-size: var(--mj-text-sm); }\n [_nghost-%COMP%] .gantt_grid_scale, \n [_nghost-%COMP%] .gantt_task_scale { background: var(--mj-bg-surface-sunken); border-bottom: 1px solid var(--mj-border-default); }\n [_nghost-%COMP%] .gantt_task .gantt_task_content { font-weight: var(--mj-font-medium); }\n [_nghost-%COMP%] .gantt_row { border-bottom: 1px solid var(--mj-border-subtle); }\n [_nghost-%COMP%] .gantt_task_line { border-radius: var(--mj-radius-sm); }"], changeDetection: 0 });
209
+ }
210
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjGanttChartComponent, [{
211
+ type: Component,
212
+ args: [{ selector: 'mj-gantt-chart', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
213
+ @if (loading) {
214
+ <div class="mj-gantt-loading">Loading Gantt chart...</div>
215
+ }
216
+ <div #ganttContainer class="mj-gantt-container" [style.height]="Height"
217
+ [style.display]="loading ? 'none' : 'block'"></div>
218
+ `, styles: ["\n :host { display: block; font-family: var(--mj-font-family); }\n\n .mj-gantt-container {\n width: 100%;\n position: relative;\n }\n\n .mj-gantt-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--mj-space-16) var(--mj-space-5);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n }\n\n /* DHTMLX Gantt style overrides for a cleaner look */\n :host ::ng-deep .gantt_container { font-family: var(--mj-font-family); font-size: var(--mj-text-sm); }\n :host ::ng-deep .gantt_grid_scale,\n :host ::ng-deep .gantt_task_scale { background: var(--mj-bg-surface-sunken); border-bottom: 1px solid var(--mj-border-default); }\n :host ::ng-deep .gantt_task .gantt_task_content { font-weight: var(--mj-font-medium); }\n :host ::ng-deep .gantt_row { border-bottom: 1px solid var(--mj-border-subtle); }\n :host ::ng-deep .gantt_task_line { border-radius: var(--mj-radius-sm); }\n "] }]
219
+ }], null, { Items: [{
220
+ type: Input
221
+ }], Links: [{
222
+ type: Input
223
+ }], Height: [{
224
+ type: Input
225
+ }], ReadOnly: [{
226
+ type: Input
227
+ }], ShowProgress: [{
228
+ type: Input
229
+ }], Columns: [{
230
+ type: Input
231
+ }], ItemClicked: [{
232
+ type: Output
233
+ }], ItemChanged: [{
234
+ type: Output
235
+ }], ganttContainer: [{
236
+ type: ViewChild,
237
+ args: ['ganttContainer', { static: false }]
238
+ }] }); })();
239
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MjGanttChartComponent, { className: "MjGanttChartComponent", filePath: "src/lib/components/gantt-chart.component.ts", lineNumber: 69 }); })();
240
+ //# sourceMappingURL=gantt-chart.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gantt-chart.component.js","sourceRoot":"","sources":["../../../src/lib/components/gantt-chart.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, ElementRef, ViewChild, AfterViewInit, OnChanges, OnDestroy, SimpleChanges, ChangeDetectionStrategy } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { GanttItemData, GanttLinkData, GanttColumnDef, GanttItemClickedEvent, GanttItemChangedEvent } from '../models/gantt.models';\nimport type { GanttStatic, Task as DHTask, Link as DHLink } from 'dhtmlx-gantt';\n\n/** Default grid columns if none are provided. */\nconst DEFAULT_COLUMNS: GanttColumnDef[] = [\n { Name: 'text', Label: 'Name', Tree: true, Width: '*' },\n { Name: 'start_date', Label: 'Start', Align: 'center', Width: 90 },\n { Name: 'duration', Label: 'Days', Align: 'center', Width: 60 },\n { Name: 'progress', Label: '%', Align: 'center', Width: 50, Template: (obj: any) => Math.round((obj.progress || 0) * 100) + '%' },\n];\n\n/**\n * Generic Gantt chart component wrapping DHTMLX Gantt.\n *\n * Renders items as bars on a timeline with hierarchy, dependency arrows,\n * and progress indicators. The library is loaded lazily via dynamic import.\n *\n * @example\n * ```html\n * <mj-gantt-chart\n * [Items]=\"projectTasks\"\n * [Links]=\"taskDependencies\"\n * [Height]=\"'600px'\"\n * (ItemClicked)=\"onTaskClicked($event)\">\n * </mj-gantt-chart>\n * ```\n */\n@Component({\n selector: 'mj-gantt-chart',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (loading) {\n <div class=\"mj-gantt-loading\">Loading Gantt chart...</div>\n }\n <div #ganttContainer class=\"mj-gantt-container\" [style.height]=\"Height\"\n [style.display]=\"loading ? 'none' : 'block'\"></div>\n `,\n styles: [`\n :host { display: block; font-family: var(--mj-font-family); }\n\n .mj-gantt-container {\n width: 100%;\n position: relative;\n }\n\n .mj-gantt-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--mj-space-16) var(--mj-space-5);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n }\n\n /* DHTMLX Gantt style overrides for a cleaner look */\n :host ::ng-deep .gantt_container { font-family: var(--mj-font-family); font-size: var(--mj-text-sm); }\n :host ::ng-deep .gantt_grid_scale,\n :host ::ng-deep .gantt_task_scale { background: var(--mj-bg-surface-sunken); border-bottom: 1px solid var(--mj-border-default); }\n :host ::ng-deep .gantt_task .gantt_task_content { font-weight: var(--mj-font-medium); }\n :host ::ng-deep .gantt_row { border-bottom: 1px solid var(--mj-border-subtle); }\n :host ::ng-deep .gantt_task_line { border-radius: var(--mj-radius-sm); }\n `]\n})\nexport class MjGanttChartComponent implements AfterViewInit, OnChanges, OnDestroy {\n /** Items (bars) to render on the timeline. */\n @Input() Items: GanttItemData[] = [];\n\n /** Dependency links (arrows) between items. */\n @Input() Links: GanttLinkData[] = [];\n\n /** CSS height for the chart container. */\n @Input() Height = '500px';\n\n /** Disables drag, resize, and link editing. */\n @Input() ReadOnly = true;\n\n /** Show progress fill on bars. */\n @Input() ShowProgress = true;\n\n /** Grid column definitions. Defaults to Name, Start, Duration, Progress. */\n @Input() Columns: GanttColumnDef[] | null = null;\n\n /** Emitted when an item bar or grid row is clicked. */\n @Output() ItemClicked = new EventEmitter<GanttItemClickedEvent>();\n\n /** Emitted when an item is changed via drag/resize (only if not ReadOnly). */\n @Output() ItemChanged = new EventEmitter<GanttItemChangedEvent>();\n\n @ViewChild('ganttContainer', { static: false }) ganttContainer!: ElementRef<HTMLDivElement>;\n\n /** @internal */\n loading = true;\n private gantt: GanttStatic | null = null;\n private initialized = false;\n\n async ngAfterViewInit(): Promise<void> {\n try {\n const module = await import('dhtmlx-gantt');\n this.gantt = module.gantt;\n this.loading = false;\n\n if (this.Items.length > 0 && this.ganttContainer) {\n this.initGantt();\n }\n } catch (error) {\n console.error('@memberjunction/ng-gantt: Failed to load dhtmlx-gantt:', error);\n this.loading = false;\n }\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!this.gantt) return;\n\n if (this.initialized && this.ganttContainer) {\n this.updateData();\n } else if (!this.initialized && this.ganttContainer && this.Items.length > 0) {\n this.initGantt();\n }\n }\n\n ngOnDestroy(): void {\n if (this.initialized && this.gantt) {\n this.gantt.clearAll();\n this.initialized = false;\n }\n }\n\n /** Rebuilds the Gantt data from the current `Items` and `Links` inputs. */\n public Refresh(): void {\n if (this.initialized) {\n this.updateData();\n }\n }\n\n private initGantt(): void {\n const g = this.gantt!;\n g.clearAll();\n\n // Configuration\n g.config.date_format = '%Y-%m-%d %H:%i';\n g.config.show_progress = this.ShowProgress;\n g.config.show_links = true;\n g.config.readonly = this.ReadOnly;\n g.config.open_tree_initially = true;\n g.config.fit_tasks = true;\n g.config.row_height = 36;\n\n // Grid columns\n const cols = this.Columns ?? DEFAULT_COLUMNS;\n g.config.columns = cols.map(c => {\n const col: any = {\n name: c.Name,\n label: c.Label,\n width: c.Width === '*' ? '*' : (c.Width ?? 100),\n };\n if (c.Align) col.align = c.Align;\n if (c.Tree) col.tree = true;\n if (c.Template) col.template = c.Template;\n return col;\n });\n\n // Initialize\n g.init(this.ganttContainer.nativeElement);\n this.initialized = true;\n\n // Event: click\n g.attachEvent('onTaskClick', (id: string) => {\n const item = this.Items.find(i => UUIDsEqual(i.ID, id));\n if (item) {\n this.ItemClicked.emit({ Item: item });\n }\n return true;\n });\n\n // Event: drag/resize (only fires if not readonly)\n if (!this.ReadOnly) {\n g.attachEvent('onAfterTaskDrag', (id: string) => {\n const task = g.getTask(id);\n const item = this.Items.find(i => UUIDsEqual(i.ID, id));\n if (item && task) {\n this.ItemChanged.emit({\n Item: item,\n NewStartDate: task.start_date as unknown as Date,\n NewEndDate: task.end_date as unknown as Date,\n NewDuration: task.duration as number,\n });\n }\n });\n }\n\n this.updateData();\n\n // Force layout after render\n setTimeout(() => g.setSizes(), 0);\n }\n\n private updateData(): void {\n if (!this.initialized || !this.gantt) return;\n const g = this.gantt;\n\n const data: Partial<DHTask>[] = this.Items.map(item => {\n const startDate = item.StartDate instanceof Date ? item.StartDate : new Date(item.StartDate);\n let duration = item.Duration ?? 1;\n if (item.EndDate) {\n const endDate = item.EndDate instanceof Date ? item.EndDate : new Date(item.EndDate);\n duration = Math.max(1, Math.ceil((endDate.getTime() - startDate.getTime()) / 86400000));\n }\n\n return {\n id: item.ID,\n text: item.Name,\n start_date: this.formatDate(startDate) as any,\n duration,\n progress: (item.Progress ?? 0) / 100,\n parent: item.ParentID || 0,\n open: item.Open !== false,\n };\n });\n\n const links: Partial<DHLink>[] = this.Links.map(link => ({\n id: link.ID,\n source: link.SourceID,\n target: link.TargetID,\n type: this.mapLinkType(link.Type),\n }));\n\n g.clearAll();\n g.parse({ data: data as DHTask[], links: links as DHLink[] });\n\n setTimeout(() => g.setSizes(), 0);\n }\n\n private formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return `${y}-${m}-${day} 00:00`;\n }\n\n private mapLinkType(type?: string): string {\n switch (type) {\n case 'FS': return '0';\n case 'SS': return '1';\n case 'FF': return '2';\n case 'SF': return '3';\n default: return '0';\n }\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import * as i0 from "@angular/core";
2
+ import * as i1 from "./components/gantt-chart.component";
3
+ export declare class MjGanttModule {
4
+ static ɵfac: i0.ɵɵFactoryDeclaration<MjGanttModule, never>;
5
+ static ɵmod: i0.ɵɵNgModuleDeclaration<MjGanttModule, never, [typeof i1.MjGanttChartComponent], [typeof i1.MjGanttChartComponent]>;
6
+ static ɵinj: i0.ɵɵInjectorDeclaration<MjGanttModule>;
7
+ }
8
+ //# sourceMappingURL=gantt.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gantt.module.d.ts","sourceRoot":"","sources":["../../src/lib/gantt.module.ts"],"names":[],"mappings":";;AAGA,qBAIa,aAAa;yCAAb,aAAa;0CAAb,aAAa;0CAAb,aAAa;CAAI"}
@@ -0,0 +1,17 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { MjGanttChartComponent } from './components/gantt-chart.component';
3
+ import * as i0 from "@angular/core";
4
+ export class MjGanttModule {
5
+ static ɵfac = function MjGanttModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MjGanttModule)(); };
6
+ static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: MjGanttModule });
7
+ static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [MjGanttChartComponent] });
8
+ }
9
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MjGanttModule, [{
10
+ type: NgModule,
11
+ args: [{
12
+ imports: [MjGanttChartComponent],
13
+ exports: [MjGanttChartComponent]
14
+ }]
15
+ }], null, null); })();
16
+ (function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(MjGanttModule, { imports: [MjGanttChartComponent], exports: [MjGanttChartComponent] }); })();
17
+ //# sourceMappingURL=gantt.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gantt.module.js","sourceRoot":"","sources":["../../src/lib/gantt.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;;AAM3E,MAAM,OAAO,aAAa;uGAAb,aAAa;4DAAb,aAAa;gEAHZ,qBAAqB;;iFAGtB,aAAa;cAJzB,QAAQ;eAAC;gBACN,OAAO,EAAE,CAAC,qBAAqB,CAAC;gBAChC,OAAO,EAAE,CAAC,qBAAqB,CAAC;aACnC;;wFACY,aAAa,cAHZ,qBAAqB,aACrB,qBAAqB","sourcesContent":["import { NgModule } from '@angular/core';\nimport { MjGanttChartComponent } from './components/gantt-chart.component';\n\n@NgModule({\n imports: [MjGanttChartComponent],\n exports: [MjGanttChartComponent]\n})\nexport class MjGanttModule { }\n"]}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * A single item (bar) on the Gantt timeline.
3
+ */
4
+ export interface GanttItemData {
5
+ /** Unique identifier. */
6
+ ID: string;
7
+ /** Display name shown in the grid and on the bar. */
8
+ Name: string;
9
+ /** Start date for the bar. */
10
+ StartDate: Date;
11
+ /** End date for the bar. If omitted, `Duration` is used instead. */
12
+ EndDate?: Date;
13
+ /** Duration in days. Used when `EndDate` is not provided. */
14
+ Duration?: number;
15
+ /** Completion percentage (0–100). Rendered as a filled portion of the bar. */
16
+ Progress?: number;
17
+ /** Parent item ID for tree hierarchy. Omit for top-level items. */
18
+ ParentID?: string;
19
+ /** Whether this item's children are expanded in the tree. Default: true. */
20
+ Open?: boolean;
21
+ /** Arbitrary consumer data passed through with events. */
22
+ Data?: any;
23
+ }
24
+ /**
25
+ * A dependency link (arrow) between two Gantt items.
26
+ */
27
+ export interface GanttLinkData {
28
+ /** Unique identifier for this link. */
29
+ ID: string;
30
+ /** ID of the source (predecessor) item. */
31
+ SourceID: string;
32
+ /** ID of the target (successor) item. */
33
+ TargetID: string;
34
+ /** Dependency type. Default: `'FS'` (Finish-to-Start). */
35
+ Type?: 'FS' | 'SS' | 'FF' | 'SF';
36
+ }
37
+ /**
38
+ * Defines a column in the Gantt grid (left side).
39
+ */
40
+ export interface GanttColumnDef {
41
+ /** Internal field name used by DHTMLX (e.g. 'text', 'start_date', 'duration'). */
42
+ Name: string;
43
+ /** Display label for the column header. */
44
+ Label: string;
45
+ /** Column width in pixels. Use `'*'` for flex. */
46
+ Width?: number | string;
47
+ /** Text alignment. */
48
+ Align?: 'left' | 'center' | 'right';
49
+ /** Show as tree column (with expand/collapse). Only one column should be tree. */
50
+ Tree?: boolean;
51
+ /** Custom template function for cell rendering. Receives the DHTMLX task object. */
52
+ Template?: (item: any) => string;
53
+ }
54
+ /**
55
+ * Event emitted when an item is clicked on the Gantt chart.
56
+ */
57
+ export interface GanttItemClickedEvent {
58
+ /** The item that was clicked. */
59
+ Item: GanttItemData;
60
+ }
61
+ /**
62
+ * Event emitted when an item is changed via drag/resize (if not read-only).
63
+ */
64
+ export interface GanttItemChangedEvent {
65
+ /** The item that was changed. */
66
+ Item: GanttItemData;
67
+ /** New start date after the change. */
68
+ NewStartDate: Date;
69
+ /** New end date after the change. */
70
+ NewEndDate: Date;
71
+ /** New duration in days after the change. */
72
+ NewDuration: number;
73
+ }
74
+ //# sourceMappingURL=gantt.models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gantt.models.d.ts","sourceRoot":"","sources":["../../../src/lib/models/gantt.models.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,yBAAyB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,SAAS,EAAE,IAAI,CAAC;IAChB,oEAAoE;IACpE,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,IAAI,CAAC,EAAE,GAAG,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oFAAoF;IACpF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC,iCAAiC;IACjC,IAAI,EAAE,aAAa,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC,iCAAiC;IACjC,IAAI,EAAE,aAAa,CAAC;IACpB,uCAAuC;IACvC,YAAY,EAAE,IAAI,CAAC;IACnB,qCAAqC;IACrC,UAAU,EAAE,IAAI,CAAC;IACjB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;CACvB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gantt.models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gantt.models.js","sourceRoot":"","sources":["../../../src/lib/models/gantt.models.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A single item (bar) on the Gantt timeline.\n */\nexport interface GanttItemData {\n /** Unique identifier. */\n ID: string;\n /** Display name shown in the grid and on the bar. */\n Name: string;\n /** Start date for the bar. */\n StartDate: Date;\n /** End date for the bar. If omitted, `Duration` is used instead. */\n EndDate?: Date;\n /** Duration in days. Used when `EndDate` is not provided. */\n Duration?: number;\n /** Completion percentage (0–100). Rendered as a filled portion of the bar. */\n Progress?: number;\n /** Parent item ID for tree hierarchy. Omit for top-level items. */\n ParentID?: string;\n /** Whether this item's children are expanded in the tree. Default: true. */\n Open?: boolean;\n /** Arbitrary consumer data passed through with events. */\n Data?: any;\n}\n\n/**\n * A dependency link (arrow) between two Gantt items.\n */\nexport interface GanttLinkData {\n /** Unique identifier for this link. */\n ID: string;\n /** ID of the source (predecessor) item. */\n SourceID: string;\n /** ID of the target (successor) item. */\n TargetID: string;\n /** Dependency type. Default: `'FS'` (Finish-to-Start). */\n Type?: 'FS' | 'SS' | 'FF' | 'SF';\n}\n\n/**\n * Defines a column in the Gantt grid (left side).\n */\nexport interface GanttColumnDef {\n /** Internal field name used by DHTMLX (e.g. 'text', 'start_date', 'duration'). */\n Name: string;\n /** Display label for the column header. */\n Label: string;\n /** Column width in pixels. Use `'*'` for flex. */\n Width?: number | string;\n /** Text alignment. */\n Align?: 'left' | 'center' | 'right';\n /** Show as tree column (with expand/collapse). Only one column should be tree. */\n Tree?: boolean;\n /** Custom template function for cell rendering. Receives the DHTMLX task object. */\n Template?: (item: any) => string;\n}\n\n/**\n * Event emitted when an item is clicked on the Gantt chart.\n */\nexport interface GanttItemClickedEvent {\n /** The item that was clicked. */\n Item: GanttItemData;\n}\n\n/**\n * Event emitted when an item is changed via drag/resize (if not read-only).\n */\nexport interface GanttItemChangedEvent {\n /** The item that was changed. */\n Item: GanttItemData;\n /** New start date after the change. */\n NewStartDate: Date;\n /** New end date after the change. */\n NewEndDate: Date;\n /** New duration in days after the change. */\n NewDuration: number;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Public API Surface of @memberjunction/ng-gantt
3
+ */
4
+ export * from './lib/gantt.module';
5
+ export * from './lib/components/gantt-chart.component';
6
+ export * from './lib/models/gantt.models';
7
+ //# sourceMappingURL=public-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,oBAAoB,CAAC;AACnC,cAAc,wCAAwC,CAAC;AACvD,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Public API Surface of @memberjunction/ng-gantt
3
+ */
4
+ export * from './lib/gantt.module';
5
+ export * from './lib/components/gantt-chart.component';
6
+ export * from './lib/models/gantt.models';
7
+ //# sourceMappingURL=public-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,oBAAoB,CAAC;AACnC,cAAc,wCAAwC,CAAC;AACvD,cAAc,2BAA2B,CAAC","sourcesContent":["/**\n * Public API Surface of @memberjunction/ng-gantt\n */\nexport * from './lib/gantt.module';\nexport * from './lib/components/gantt-chart.component';\nexport * from './lib/models/gantt.models';\n"]}
package/package.json CHANGED
@@ -1,10 +1,39 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-gantt",
3
- "version": "0.0.1",
4
- "description": "OIDC trusted publishing setup package for @memberjunction/ng-gantt",
5
- "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
3
+ "version": "5.23.0",
4
+ "description": "MemberJunction: Generic Gantt chart component wrapping DHTMLX Gantt",
5
+ "main": "./dist/public-api.js",
6
+ "typings": "./dist/public-api.d.ts",
7
+ "files": [
8
+ "/dist"
9
+ ],
10
+ "scripts": {
11
+ "test": "echo \"No tests configured yet\"",
12
+ "build": "ngc",
13
+ "test:watch": "vitest"
14
+ },
15
+ "keywords": [],
16
+ "author": "",
17
+ "license": "ISC",
18
+ "devDependencies": {
19
+ "@angular/compiler": "21.1.3",
20
+ "@angular/compiler-cli": "21.1.3",
21
+ "vitest": "^4.0.18"
22
+ },
23
+ "peerDependencies": {
24
+ "@angular/common": "21.1.3",
25
+ "@angular/core": "21.1.3"
26
+ },
27
+ "dependencies": {
28
+ "@angular/common": "21.1.3",
29
+ "@angular/core": "21.1.3",
30
+ "@memberjunction/global": "5.23.0",
31
+ "dhtmlx-gantt": "^9.1.1",
32
+ "tslib": "^2.8.1"
33
+ },
34
+ "sideEffects": false,
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/MemberJunction/MJ"
38
+ }
10
39
  }
package/README.md DELETED
@@ -1,45 +0,0 @@
1
- # @memberjunction/ng-gantt
2
-
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
4
-
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
6
-
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
8
-
9
- ## Purpose
10
-
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@memberjunction/ng-gantt`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
15
-
16
- ## What is OIDC Trusted Publishing?
17
-
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
19
-
20
- ## Setup Instructions
21
-
22
- To properly configure OIDC trusted publishing for this package:
23
-
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
28
-
29
- ## DO NOT USE THIS PACKAGE
30
-
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
36
-
37
- ## More Information
38
-
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
42
-
43
- ---
44
-
45
- **Maintained for OIDC setup purposes only**