newportsite 1.1.3
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/newportsite-1.1.3.tgz +0 -0
- package/ng-package.json +7 -0
- package/obfuscate.js +70 -0
- package/package.json +15 -0
- package/src/lib/app.component.ts +47 -0
- package/src/lib/app.routing.ts +38 -0
- package/src/lib/auth/alert.component.html +5 -0
- package/src/lib/auth/alert.component.ts +24 -0
- package/src/lib/auth/auth.component.html +1 -0
- package/src/lib/auth/auth.component.ts +10 -0
- package/src/lib/auth/auth.routes.ts +16 -0
- package/src/lib/auth/index.ts +4 -0
- package/src/lib/auth/login.component.html +87 -0
- package/src/lib/auth/login.component.ts +158 -0
- package/src/lib/auth/models/index.ts +1 -0
- package/src/lib/auth/models/user.ts +25 -0
- package/src/lib/auth/register.component.html +157 -0
- package/src/lib/auth/register.component.ts +219 -0
- package/src/lib/auth/services/alert.service.ts +47 -0
- package/src/lib/auth/services/auth.service.ts +28 -0
- package/src/lib/auth/services/index.ts +3 -0
- package/src/lib/auth/services/user.service.spec.ts +112 -0
- package/src/lib/auth/services/user.service.ts +47 -0
- package/src/lib/common/card.component.html +72 -0
- package/src/lib/common/card.component.ts +102 -0
- package/src/lib/common/commands.component.html +8 -0
- package/src/lib/common/commands.component.ts +42 -0
- package/src/lib/common/context.component.html +9 -0
- package/src/lib/common/context.component.ts +38 -0
- package/src/lib/common/grid.component.html +20 -0
- package/src/lib/common/grid.component.ts +747 -0
- package/src/lib/common/index.ts +9 -0
- package/src/lib/common/loader.component.html +5 -0
- package/src/lib/common/loader.component.ts +27 -0
- package/src/lib/common/lookup.component.html +29 -0
- package/src/lib/common/lookup.component.ts +115 -0
- package/src/lib/common/messagebox.component.html +39 -0
- package/src/lib/common/messagebox.component.ts +74 -0
- package/src/lib/common/theme-toggle.component.ts +139 -0
- package/src/lib/config.ts +62 -0
- package/src/lib/containers/default-layout/default-layout.component.html +191 -0
- package/src/lib/containers/default-layout/default-layout.component.ts +158 -0
- package/src/lib/containers/default-layout/index.ts +1 -0
- package/src/lib/containers/index.ts +1 -0
- package/src/lib/directives/component.draggable.ts +80 -0
- package/src/lib/directives/index.ts +2 -0
- package/src/lib/directives/input.directive.spec.ts +158 -0
- package/src/lib/directives/input.directive.ts +210 -0
- package/src/lib/home/dashboard/dashboard.component.html +38 -0
- package/src/lib/home/dashboard/dashboard.component.ts +50 -0
- package/src/lib/home/dashboard/index.ts +1 -0
- package/src/lib/home/index.component.html +1 -0
- package/src/lib/home/index.component.ts +10 -0
- package/src/lib/home/index.routes.ts +29 -0
- package/src/lib/home/index.ts +1 -0
- package/src/lib/home/info/index.ts +1 -0
- package/src/lib/home/info/info.component.css +476 -0
- package/src/lib/home/info/info.component.html +174 -0
- package/src/lib/home/info/info.component.ts +287 -0
- package/src/lib/home/model/article.component.html +10 -0
- package/src/lib/home/model/article.component.ts +50 -0
- package/src/lib/home/model/barchart.component.html +8 -0
- package/src/lib/home/model/barchart.component.ts +59 -0
- package/src/lib/home/model/index.ts +7 -0
- package/src/lib/home/model/itemdetail.component.html +25 -0
- package/src/lib/home/model/itemdetail.component.ts +93 -0
- package/src/lib/home/model/itemtab.component.html +25 -0
- package/src/lib/home/model/itemtab.component.ts +105 -0
- package/src/lib/home/model/model.component.html +121 -0
- package/src/lib/home/model/model.component.ts +510 -0
- package/src/lib/home/model/modeltoolbar.component.html +111 -0
- package/src/lib/home/model/modeltoolbar.component.ts +157 -0
- package/src/lib/home/model/navigation.component.html +86 -0
- package/src/lib/home/model/navigation.component.ts +247 -0
- package/src/lib/home/model/services/index.ts +1 -0
- package/src/lib/home/model/services/model.service.spec.ts +423 -0
- package/src/lib/home/model/services/model.service.ts +319 -0
- package/src/lib/home/modelsearch/index.ts +1 -0
- package/src/lib/home/modelsearch/modelsearch.component.html +124 -0
- package/src/lib/home/modelsearch/modelsearch.component.ts +453 -0
- package/src/lib/interfaces/data.interface.ts +131 -0
- package/src/lib/interfaces/index.ts +2 -0
- package/src/lib/interfaces/item.interface.ts +438 -0
- package/src/lib/players/lookup/lookup.directive.ts +6 -0
- package/src/lib/players/lookup/lookup.item.component.ts +37 -0
- package/src/lib/players/lookup/lookup.item.ts +9 -0
- package/src/lib/players/lookup/lookup.player.component.ts +59 -0
- package/src/lib/players/lookup/lookup.selector.component.ts +41 -0
- package/src/lib/players/model/model.directive.ts +6 -0
- package/src/lib/players/model/model.item.component.spec.ts +311 -0
- package/src/lib/players/model/model.item.component.ts +3457 -0
- package/src/lib/players/model/model.item.ts +9 -0
- package/src/lib/players/model/model.player.component.ts +109 -0
- package/src/lib/players/model/model.selector.component.ts +59 -0
- package/src/lib/scheduler/scheduler.component.html +13 -0
- package/src/lib/scheduler/scheduler.component.scss +6 -0
- package/src/lib/scheduler/scheduler.component.ts +296 -0
- package/src/lib/scheduler/scheduler.routes.ts +15 -0
- package/src/lib/scheduler/schedulerdialog.component.html +72 -0
- package/src/lib/scheduler/schedulerdialog.component.ts +208 -0
- package/src/lib/scheduler/services/scheduler.service.ts +133 -0
- package/src/lib/services/auth-state.service.ts +129 -0
- package/src/lib/services/auth.interceptor.spec.ts +144 -0
- package/src/lib/services/auth.interceptor.ts +44 -0
- package/src/lib/services/cache.service.spec.ts +143 -0
- package/src/lib/services/cache.service.ts +71 -0
- package/src/lib/services/global-error-handler.spec.ts +39 -0
- package/src/lib/services/global-error-handler.ts +28 -0
- package/src/lib/services/global.service.spec.ts +801 -0
- package/src/lib/services/global.service.ts +724 -0
- package/src/lib/services/message.service.ts +556 -0
- package/src/lib/services/theme.service.ts +96 -0
- package/src/lib/template/authtemplate.component.html +6 -0
- package/src/lib/template/authtemplate.component.ts +13 -0
- package/src/lib/template/basetemplate.component.html +7 -0
- package/src/lib/template/basetemplate.component.ts +13 -0
- package/src/lib/template/index.ts +3 -0
- package/src/lib/template/modeltemplate.component.html +7 -0
- package/src/lib/template/modeltemplate.component.ts +21 -0
- package/src/lib/utils/piva.spec.ts +56 -0
- package/src/lib/utils/piva.ts +29 -0
- package/src/lib/validators/email.validator.spec.ts +57 -0
- package/src/lib/validators/email.validator.ts +17 -0
- package/src/lib/validators/equalPasswords.validator.spec.ts +54 -0
- package/src/lib/validators/equalPasswords.validator.ts +17 -0
- package/src/lib/validators/index.ts +2 -0
- package/src/lib/version.ts +1 -0
- package/src/public-api.ts +64 -0
- package/src/typings.d.ts +2 -0
- package/tsconfig.lib.json +18 -0
- package/tsconfig.lib.prod.json +9 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
input,
|
|
4
|
+
output,
|
|
5
|
+
effect,
|
|
6
|
+
untracked,
|
|
7
|
+
ChangeDetectionStrategy,
|
|
8
|
+
viewChild,
|
|
9
|
+
OnInit,
|
|
10
|
+
DestroyRef,
|
|
11
|
+
inject,
|
|
12
|
+
} from '@angular/core';
|
|
13
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
14
|
+
import { ModelDirective } from './model.directive';
|
|
15
|
+
import { ModelItem } from './model.item';
|
|
16
|
+
import { ItemInterface, ItemCommandInterface } from '../../interfaces/index';
|
|
17
|
+
import { GlobalService } from '../../services/global.service';
|
|
18
|
+
|
|
19
|
+
@Component({
|
|
20
|
+
selector: 'modelplayer',
|
|
21
|
+
template: `<ng-template mdModel></ng-template>`,
|
|
22
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
23
|
+
imports: [ModelDirective],
|
|
24
|
+
})
|
|
25
|
+
export class ModelPlayerComponent implements OnInit {
|
|
26
|
+
private gsv = inject(GlobalService);
|
|
27
|
+
|
|
28
|
+
readonly model = input<ModelItem>();
|
|
29
|
+
readonly command = input<ItemCommandInterface>();
|
|
30
|
+
readonly viewList = input<boolean>();
|
|
31
|
+
readonly lookupValue = input<any>();
|
|
32
|
+
readonly dialogValue = input<any>();
|
|
33
|
+
readonly scale = input<number>();
|
|
34
|
+
|
|
35
|
+
readonly modelHost = viewChild.required(ModelDirective);
|
|
36
|
+
readonly commandsChanged = output<ItemCommandInterface[]>();
|
|
37
|
+
|
|
38
|
+
private componentRef!: any;
|
|
39
|
+
private destroyRef = inject(DestroyRef);
|
|
40
|
+
|
|
41
|
+
constructor() {
|
|
42
|
+
effect(() => {
|
|
43
|
+
const m = this.model();
|
|
44
|
+
if (!m) return;
|
|
45
|
+
this.gsv.setLoaderState(true);
|
|
46
|
+
const viewContainerRef = this.modelHost().viewContainerRef;
|
|
47
|
+
viewContainerRef.clear();
|
|
48
|
+
if (this.componentRef) {
|
|
49
|
+
this.componentRef.destroy();
|
|
50
|
+
this.componentRef = undefined;
|
|
51
|
+
}
|
|
52
|
+
this.componentRef = viewContainerRef.createComponent(m.component);
|
|
53
|
+
(this.componentRef.instance as ItemInterface).initItem?.(m.data);
|
|
54
|
+
});
|
|
55
|
+
effect(() => {
|
|
56
|
+
const cmd = this.command();
|
|
57
|
+
if (cmd && this.componentRef) {
|
|
58
|
+
(this.componentRef.instance as ItemInterface).sendCommand?.(cmd);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
effect(() => {
|
|
62
|
+
const vl = this.viewList();
|
|
63
|
+
if (vl !== undefined && this.componentRef) {
|
|
64
|
+
(this.componentRef.instance as ItemInterface).setViewList?.(vl);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
effect(() => {
|
|
68
|
+
const lv = this.lookupValue();
|
|
69
|
+
if (lv && this.componentRef) {
|
|
70
|
+
// untracked() exits the reactive context so that signal writes inside
|
|
71
|
+
// lookupResult (e.g. this._showlookup.set(false)) do not throw the
|
|
72
|
+
// "Writing to signals is not allowed in an effect" error, which would
|
|
73
|
+
// abort the call mid-way and leave showlookup=true (UI frozen).
|
|
74
|
+
untracked(() =>
|
|
75
|
+
(this.componentRef.instance as ItemInterface).lookupResult?.(lv)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
effect(() => {
|
|
80
|
+
const dv = this.dialogValue();
|
|
81
|
+
if (dv && this.componentRef) {
|
|
82
|
+
untracked(() =>
|
|
83
|
+
(this.componentRef.instance as ItemInterface).dialogResult?.(dv)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
effect(() => {
|
|
88
|
+
const s = this.scale();
|
|
89
|
+
if (s && this.componentRef) {
|
|
90
|
+
(this.componentRef.instance as ItemInterface).setScale?.(s);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Lifecycle: subscribes to toolbar command changes and re-emits them as output events. */
|
|
96
|
+
public ngOnInit() {
|
|
97
|
+
this.gsv
|
|
98
|
+
.getItemCommands()
|
|
99
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
100
|
+
.subscribe(commands => {
|
|
101
|
+
this.OnCommandChanged(commands);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Re-emits a command array change to the parent (model.component) via commandsChanged output. */
|
|
106
|
+
public OnCommandChanged(commands: ItemCommandInterface[]) {
|
|
107
|
+
this.commandsChanged.emit(commands);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChangeDetectionStrategy,
|
|
3
|
+
Component,
|
|
4
|
+
effect,
|
|
5
|
+
input,
|
|
6
|
+
output,
|
|
7
|
+
signal,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
import { ModelItemComponent } from './model.item.component';
|
|
10
|
+
import { ModelItem } from './model.item';
|
|
11
|
+
import { ItemInterface, ItemCommandInterface } from '../../interfaces/index';
|
|
12
|
+
import { ModelPlayerComponent } from './model.player.component';
|
|
13
|
+
|
|
14
|
+
@Component({
|
|
15
|
+
selector: 'modelselector',
|
|
16
|
+
template: `<modelplayer
|
|
17
|
+
[model]="modelItem()"
|
|
18
|
+
[command]="command()"
|
|
19
|
+
[viewList]="viewList()"
|
|
20
|
+
[lookupValue]="lookupValue()"
|
|
21
|
+
[dialogValue]="dialogValue()"
|
|
22
|
+
[scale]="scale()"
|
|
23
|
+
(commandsChanged)="onCommandsChanged($event)"></modelplayer>`,
|
|
24
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
25
|
+
imports: [ModelPlayerComponent],
|
|
26
|
+
})
|
|
27
|
+
export class ModelSelectorComponent {
|
|
28
|
+
currentModel = input<ItemInterface>();
|
|
29
|
+
currentCommand = input<ItemCommandInterface>();
|
|
30
|
+
viewList = input<boolean>();
|
|
31
|
+
lookupValue = input<any>();
|
|
32
|
+
dialogValue = input<any>();
|
|
33
|
+
scale = input<number>();
|
|
34
|
+
|
|
35
|
+
commandsChanged = output<ItemCommandInterface[]>();
|
|
36
|
+
|
|
37
|
+
modelItem = signal<ModelItem | null>(null);
|
|
38
|
+
command = signal<ItemCommandInterface | null>(null);
|
|
39
|
+
|
|
40
|
+
constructor() {
|
|
41
|
+
effect(() => {
|
|
42
|
+
const m = this.currentModel();
|
|
43
|
+
if (m) {
|
|
44
|
+
this.modelItem.set(new ModelItem(ModelItemComponent, m));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
effect(() => {
|
|
48
|
+
const c = this.currentCommand();
|
|
49
|
+
if (c !== undefined) {
|
|
50
|
+
this.command.set(c);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Forwards toolbar command state changes to the parent via the commandsChanged output. */
|
|
56
|
+
onCommandsChanged(commands: ItemCommandInterface[]) {
|
|
57
|
+
this.commandsChanged.emit(commands);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<full-calendar class="calendar" [options]="calendarOptions"></full-calendar>
|
|
2
|
+
<schedulerdialog
|
|
3
|
+
[hidden]="!showdialog"
|
|
4
|
+
[(show)]="showdialog"
|
|
5
|
+
[(text)]="textdialog"
|
|
6
|
+
[(title)]="titledialog"
|
|
7
|
+
(schedulerDialogResult)="dialogResult($event)"
|
|
8
|
+
[(showconfirm)]="showconfirm"
|
|
9
|
+
[(width)]="dialogWidth"
|
|
10
|
+
[(height)]="dialogHeight"
|
|
11
|
+
[(top)]="dialogTop"
|
|
12
|
+
[(left)]="dialogLeft">
|
|
13
|
+
</schedulerdialog>
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AfterViewInit,
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
OnDestroy,
|
|
6
|
+
inject,
|
|
7
|
+
DestroyRef,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
import {
|
|
10
|
+
CalendarOptions,
|
|
11
|
+
DateSelectArg,
|
|
12
|
+
EventClickArg,
|
|
13
|
+
EventApi,
|
|
14
|
+
EventAddArg,
|
|
15
|
+
EventRemoveArg,
|
|
16
|
+
EventInput,
|
|
17
|
+
} from '@fullcalendar/core';
|
|
18
|
+
import itLocale from '@fullcalendar/core/locales/it';
|
|
19
|
+
import enLocale from '@fullcalendar/core/locales/en-gb';
|
|
20
|
+
import { GlobalService, Languages } from '../services/global.service';
|
|
21
|
+
import { AppMessageService } from '../services/message.service';
|
|
22
|
+
import { SchedulerService } from './services/scheduler.service';
|
|
23
|
+
import {
|
|
24
|
+
DialogFieldInterface,
|
|
25
|
+
DialogType,
|
|
26
|
+
TransportInterface,
|
|
27
|
+
} from '../interfaces/item.interface';
|
|
28
|
+
import { SchedulerInterface } from '../interfaces/item.interface';
|
|
29
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
30
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
31
|
+
|
|
32
|
+
import dayGridPlugin from '@fullcalendar/daygrid';
|
|
33
|
+
import timeGridPlugin from '@fullcalendar/timegrid';
|
|
34
|
+
import listPlugin from '@fullcalendar/list';
|
|
35
|
+
|
|
36
|
+
import interactionPlugin from '@fullcalendar/interaction';
|
|
37
|
+
import stc from 'string-to-color';
|
|
38
|
+
import { FullCalendarModule } from '@fullcalendar/angular';
|
|
39
|
+
import { SchedulerDialogComponent } from './schedulerdialog.component';
|
|
40
|
+
|
|
41
|
+
@Component({
|
|
42
|
+
selector: 'scheduler',
|
|
43
|
+
templateUrl: './scheduler.component.html',
|
|
44
|
+
styleUrls: ['./scheduler.component.scss'],
|
|
45
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
46
|
+
imports: [FullCalendarModule, SchedulerDialogComponent],
|
|
47
|
+
})
|
|
48
|
+
export class SchedulerComponent implements AfterViewInit, OnDestroy {
|
|
49
|
+
gsv = inject(GlobalService);
|
|
50
|
+
msg = inject(AppMessageService);
|
|
51
|
+
scr = inject(SchedulerService);
|
|
52
|
+
|
|
53
|
+
public scheduler!: SchedulerInterface;
|
|
54
|
+
|
|
55
|
+
// SchedulerDialog
|
|
56
|
+
public showdialog = false;
|
|
57
|
+
public titledialog = '';
|
|
58
|
+
public textdialog = '';
|
|
59
|
+
public showconfirm = false;
|
|
60
|
+
public dialogHeight = 0;
|
|
61
|
+
public dialogWidth = 0;
|
|
62
|
+
public dialogTop = 0;
|
|
63
|
+
public dialogLeft = 0;
|
|
64
|
+
public dialogValue!: any;
|
|
65
|
+
public dialogType: DialogType = 0;
|
|
66
|
+
private destroyRef = inject(DestroyRef);
|
|
67
|
+
|
|
68
|
+
calendarOptions: CalendarOptions = {
|
|
69
|
+
headerToolbar: {
|
|
70
|
+
left: 'prev,next today',
|
|
71
|
+
center: 'title',
|
|
72
|
+
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek',
|
|
73
|
+
},
|
|
74
|
+
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
|
|
75
|
+
|
|
76
|
+
initialView: 'dayGridMonth',
|
|
77
|
+
weekends: true,
|
|
78
|
+
editable: true,
|
|
79
|
+
selectable: true,
|
|
80
|
+
selectMirror: true,
|
|
81
|
+
dayMaxEvents: true,
|
|
82
|
+
select: this.handleDateSelect.bind(this),
|
|
83
|
+
eventClick: this.handleEventClick.bind(this),
|
|
84
|
+
eventsSet: this.handleEvents.bind(this),
|
|
85
|
+
eventAdd: this.handleDateAdd.bind(this),
|
|
86
|
+
eventChange: this.handleDateChange.bind(this),
|
|
87
|
+
eventRemove: this.handleDateRemove.bind(this),
|
|
88
|
+
datesSet: this.handleDateChange.bind(this),
|
|
89
|
+
timeZone: 'Europe/Rome',
|
|
90
|
+
};
|
|
91
|
+
constructor() {
|
|
92
|
+
this.calendarOptions.locales = [this.gsv.getLng() === Languages.IT ? itLocale : enLocale];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Fetches calendar events for the given date range and updates the calendarEvents signal. */
|
|
96
|
+
public loadEvents(start: Date, end: Date) {
|
|
97
|
+
this.currentEvents = [];
|
|
98
|
+
|
|
99
|
+
this.scheduler = this.gsv.getSchedulerInterface();
|
|
100
|
+
|
|
101
|
+
this.scheduler.year = this.gsv.getYear();
|
|
102
|
+
this.scheduler.start = start;
|
|
103
|
+
this.scheduler.end = end;
|
|
104
|
+
|
|
105
|
+
this.scr
|
|
106
|
+
.getSchedulerDataRange(this.scheduler)
|
|
107
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
108
|
+
.subscribe({
|
|
109
|
+
next: async (data: TransportInterface) => {
|
|
110
|
+
let events: Array<EventInput> = new Array<EventInput>();
|
|
111
|
+
(data.dataFile as any[]).forEach((element: any) => {
|
|
112
|
+
events.push({
|
|
113
|
+
id: element.id,
|
|
114
|
+
title: element.description,
|
|
115
|
+
start: element.startdate,
|
|
116
|
+
end: element.enddate,
|
|
117
|
+
allDay: element.allday,
|
|
118
|
+
extendedProps: { assigned: element.assigned },
|
|
119
|
+
backgroundColor: stc(element.description.split('-')[0]),
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
this.calendarOptions.events = events;
|
|
123
|
+
},
|
|
124
|
+
error: () => {},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** Lifecycle: no-op — subscriptions managed by takeUntilDestroyed. */
|
|
128
|
+
public ngOnDestroy(): void {
|
|
129
|
+
// subscriptions are managed by takeUntilDestroyed
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Lifecycle: subscribes to the dialog-field channel to open the event dialog. */
|
|
133
|
+
public ngAfterViewInit() {
|
|
134
|
+
this.gsv
|
|
135
|
+
.getDialogField()
|
|
136
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
137
|
+
.subscribe(dialog => {
|
|
138
|
+
this.setDialog(dialog);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
currentEvents: EventApi[] = [];
|
|
143
|
+
|
|
144
|
+
/** Broadcasts the current dialog state (show/hide, position, tag) to GlobalService. */
|
|
145
|
+
private sendDialog() {
|
|
146
|
+
this.gsv.setDialogField({
|
|
147
|
+
showdialog: this.showdialog,
|
|
148
|
+
titledialog: this.titledialog,
|
|
149
|
+
textdialog: this.textdialog,
|
|
150
|
+
showconfirm: this.showconfirm,
|
|
151
|
+
dialogHeight: this.dialogHeight,
|
|
152
|
+
dialogWidth: this.dialogWidth,
|
|
153
|
+
dialogTop: this.dialogTop,
|
|
154
|
+
dialogLeft: this.dialogLeft,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Applies an incoming dialog state (called by the parent shell on a dialog-field event). */
|
|
159
|
+
public setDialog(dialog: DialogFieldInterface) {
|
|
160
|
+
this.showdialog = dialog.showdialog;
|
|
161
|
+
this.titledialog = dialog.titledialog;
|
|
162
|
+
this.textdialog = dialog.textdialog;
|
|
163
|
+
this.showconfirm = dialog.showconfirm;
|
|
164
|
+
this.dialogHeight = dialog.dialogHeight;
|
|
165
|
+
this.dialogWidth = dialog.dialogWidth;
|
|
166
|
+
this.dialogTop = dialog.dialogTop;
|
|
167
|
+
this.dialogLeft = dialog.dialogLeft;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Handles the dialog close result: on confirm, creates a new event via postData, or
|
|
172
|
+
* deletes an existing event via deleteItem, then reloads the visible date range.
|
|
173
|
+
*/
|
|
174
|
+
dialogResult(rsp: any) {
|
|
175
|
+
this.showdialog = false;
|
|
176
|
+
this.dialogValue = rsp;
|
|
177
|
+
this.titledialog = '';
|
|
178
|
+
this.textdialog = '';
|
|
179
|
+
this.showconfirm = false;
|
|
180
|
+
this.dialogHeight = 300;
|
|
181
|
+
this.dialogWidth = 400;
|
|
182
|
+
this.dialogTop = 200;
|
|
183
|
+
this.dialogLeft = 200;
|
|
184
|
+
|
|
185
|
+
if (rsp.value) {
|
|
186
|
+
if (rsp.tag.view === undefined) {
|
|
187
|
+
this.scheduler.id = rsp.tag.id;
|
|
188
|
+
this.scheduler.year = this.gsv.getYear();
|
|
189
|
+
this.scheduler.start = rsp.tag.start;
|
|
190
|
+
this.scheduler.end = rsp.tag.end;
|
|
191
|
+
this.scheduler.assigned = rsp.props[1];
|
|
192
|
+
this.scheduler.description = rsp.props[0];
|
|
193
|
+
this.scheduler.allday = rsp.tag.allDay;
|
|
194
|
+
this.scr.deleteItem(this.scheduler).subscribe({
|
|
195
|
+
next: (data: boolean) => {
|
|
196
|
+
if (data === true) {
|
|
197
|
+
rsp.tag.remove();
|
|
198
|
+
const calendarApi = rsp.tag._context.viewApi.calendar;
|
|
199
|
+
calendarApi.unselect();
|
|
200
|
+
calendarApi.addEvent({
|
|
201
|
+
id: rsp.tag.id,
|
|
202
|
+
title: rsp.props[0],
|
|
203
|
+
start: rsp.tag.startStr,
|
|
204
|
+
end: rsp.tag.endStr,
|
|
205
|
+
allDay: rsp.tag.allDay,
|
|
206
|
+
assigned: rsp.props[1],
|
|
207
|
+
backgroundColor: stc(rsp.props[0].split('-')[0]),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
error: () => {},
|
|
212
|
+
});
|
|
213
|
+
} else {
|
|
214
|
+
const calendarApi = rsp.tag.view.calendar;
|
|
215
|
+
calendarApi.unselect();
|
|
216
|
+
calendarApi.addEvent({
|
|
217
|
+
id: uuidv4(),
|
|
218
|
+
title: rsp.props[0],
|
|
219
|
+
start: rsp.tag.startStr,
|
|
220
|
+
end: rsp.tag.endStr,
|
|
221
|
+
allDay: rsp.tag.allDay,
|
|
222
|
+
assigned: rsp.props[1],
|
|
223
|
+
backgroundColor: stc(rsp.props[0].split('-')[0]),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
} else if (rsp.tag.view === undefined && rsp.delete) {
|
|
227
|
+
rsp.tag.remove();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Toggles the weekend-days visibility on the FullCalendar instance. */
|
|
232
|
+
handleWeekendsToggle() {
|
|
233
|
+
const { calendarOptions } = this;
|
|
234
|
+
calendarOptions.weekends = !calendarOptions.weekends;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Called by FullCalendar after an external event is dropped; logs the new event data. */
|
|
238
|
+
handleDateAdd(eventAdd: EventAddArg) {
|
|
239
|
+
this.scheduler.id = eventAdd.event.id;
|
|
240
|
+
this.scheduler.year = this.gsv.getYear();
|
|
241
|
+
this.scheduler.start = eventAdd.event.start;
|
|
242
|
+
this.scheduler.end = eventAdd.event.end;
|
|
243
|
+
this.scheduler.assigned = eventAdd.event.extendedProps.assigned;
|
|
244
|
+
this.scheduler.description = eventAdd.event.title;
|
|
245
|
+
this.scheduler.allday = eventAdd.event.allDay;
|
|
246
|
+
this.scr.postData(this.scheduler).subscribe({
|
|
247
|
+
next: () => {},
|
|
248
|
+
error: () => {},
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Called by FullCalendar after an event is dragged/resized; reloads events for the new range. */
|
|
253
|
+
handleDateChange(eventChange: any) {
|
|
254
|
+
this.loadEvents(eventChange.start, eventChange.end);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Called by FullCalendar after an event is removed; logs the removed event data. */
|
|
258
|
+
handleDateRemove(eventRemove: EventRemoveArg) {
|
|
259
|
+
this.scheduler.id = eventRemove.event.id;
|
|
260
|
+
this.scheduler.year = this.gsv.getYear();
|
|
261
|
+
this.scr.deleteItem(this.scheduler).subscribe({
|
|
262
|
+
next: () => {},
|
|
263
|
+
error: () => {},
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Called by FullCalendar on date/range selection; opens the dialog to create a new event. */
|
|
268
|
+
handleDateSelect(selectInfo: DateSelectArg) {
|
|
269
|
+
this.gsv.setDialog({ target: '', state: true, tag: selectInfo });
|
|
270
|
+
this.openDialog();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Called by FullCalendar when an existing event is clicked; opens the dialog to edit/delete. */
|
|
274
|
+
handleEventClick(clickInfo: EventClickArg) {
|
|
275
|
+
this.gsv.setDialog(null);
|
|
276
|
+
this.gsv.setDialog({ target: '', state: true, tag: clickInfo.event });
|
|
277
|
+
this.openDialog();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private openDialog() {
|
|
281
|
+
this.textdialog = '';
|
|
282
|
+
this.titledialog = this.msg.get('app.notify');
|
|
283
|
+
this.dialogHeight = 300;
|
|
284
|
+
this.dialogWidth = 400;
|
|
285
|
+
this.dialogTop = screen.height / 2 - this.dialogHeight / 2;
|
|
286
|
+
this.dialogLeft = screen.width / 2 - this.dialogWidth / 2;
|
|
287
|
+
this.showconfirm = true;
|
|
288
|
+
this.showdialog = true;
|
|
289
|
+
this.sendDialog();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** FullCalendar callback: keeps the currentEvents array in sync for template rendering. */
|
|
293
|
+
handleEvents(events: EventApi[]) {
|
|
294
|
+
this.currentEvents = events;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Routes } from '@angular/router';
|
|
2
|
+
import { SchedulerComponent } from './scheduler.component';
|
|
3
|
+
import { authGuard } from '../auth/services/auth.service';
|
|
4
|
+
|
|
5
|
+
export const SCHEDULER_ROUTES: Routes = [
|
|
6
|
+
{
|
|
7
|
+
path: '',
|
|
8
|
+
component: SchedulerComponent,
|
|
9
|
+
canActivate: [authGuard],
|
|
10
|
+
children: [
|
|
11
|
+
{ path: 'scheduler', component: SchedulerComponent },
|
|
12
|
+
{ path: '**', redirectTo: '/scheduler', pathMatch: 'full' },
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class="modal fade"
|
|
3
|
+
bsModal
|
|
4
|
+
#modal="bs-modal"
|
|
5
|
+
[ngStyle]="contextStyle()"
|
|
6
|
+
ngxModalDraggable>
|
|
7
|
+
<div class="modal-header">
|
|
8
|
+
<h6 class="modal-title">{{ title() }}</h6>
|
|
9
|
+
<button
|
|
10
|
+
type="button"
|
|
11
|
+
class="btn-close"
|
|
12
|
+
data-dismiss="modal"
|
|
13
|
+
aria-label="Close"
|
|
14
|
+
(click)="closeDetail(false)"></button>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="modal-body-60 bg-light p-2">
|
|
17
|
+
<form #form [formGroup]="profileform">
|
|
18
|
+
<div class="container">
|
|
19
|
+
<div class="row mt-2">
|
|
20
|
+
<label for="assigned" class="col-sm-3">{{
|
|
21
|
+
msg?.get('app.assigned')
|
|
22
|
+
}}</label>
|
|
23
|
+
<div class="col-sm-9">
|
|
24
|
+
<select
|
|
25
|
+
nvg
|
|
26
|
+
id="assigned"
|
|
27
|
+
tabindex="0"
|
|
28
|
+
class="field"
|
|
29
|
+
name="assigned"
|
|
30
|
+
[(ngModel)]="selected"
|
|
31
|
+
formControlName="assigned">
|
|
32
|
+
@for (c of assigneds; track c) {
|
|
33
|
+
<option value="{{ c.id }}">
|
|
34
|
+
{{ c.name }}
|
|
35
|
+
</option>
|
|
36
|
+
}
|
|
37
|
+
</select>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="row mt-2">
|
|
41
|
+
<label for="description" class="col-sm-3">{{
|
|
42
|
+
msg?.get('app.description')
|
|
43
|
+
}}</label>
|
|
44
|
+
<div class="col-sm-9">
|
|
45
|
+
<input
|
|
46
|
+
nvg
|
|
47
|
+
autocomplete="off"
|
|
48
|
+
tabindex="1"
|
|
49
|
+
id="description"
|
|
50
|
+
[attr.data-state]="0"
|
|
51
|
+
class="field"
|
|
52
|
+
type="text"
|
|
53
|
+
formControlName="description" />
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</form>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="modal-footer">
|
|
60
|
+
<button class="btn mx-2" (click)="closeAndRemove()">
|
|
61
|
+
{{ closeButtonText }}
|
|
62
|
+
</button>
|
|
63
|
+
<button
|
|
64
|
+
class="btn mx-2"
|
|
65
|
+
(click)="closeDetail(true)"
|
|
66
|
+
[hidden]="!showconfirm()"
|
|
67
|
+
type="submit"
|
|
68
|
+
[disabled]="!profileform.valid">
|
|
69
|
+
{{ msg?.get('app.confirm') }}
|
|
70
|
+
</button>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|