@memberjunction/ng-gantt 0.0.1 → 5.24.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/dist/lib/components/gantt-chart.component.d.ts +54 -0
- package/dist/lib/components/gantt-chart.component.d.ts.map +1 -0
- package/dist/lib/components/gantt-chart.component.js +240 -0
- package/dist/lib/components/gantt-chart.component.js.map +1 -0
- package/dist/lib/gantt.module.d.ts +8 -0
- package/dist/lib/gantt.module.d.ts.map +1 -0
- package/dist/lib/gantt.module.js +17 -0
- package/dist/lib/gantt.module.js.map +1 -0
- package/dist/lib/models/gantt.models.d.ts +74 -0
- package/dist/lib/models/gantt.models.d.ts.map +1 -0
- package/dist/lib/models/gantt.models.js +2 -0
- package/dist/lib/models/gantt.models.js.map +1 -0
- package/dist/public-api.d.ts +7 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +7 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +36 -7
- package/README.md +0 -45
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
]
|
|
3
|
+
"version": "5.24.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.24.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**
|