@openinc/parse-server-opendash 4.0.28 → 4.0.29
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/features/openservice/schedules/calendarSync/functions/eventToSchedule.d.ts +2 -2
- package/dist/features/openservice/schedules/calendarSync/functions/eventToSchedule.js +8 -11
- package/dist/features/openservice/schedules/calendarSync/functions/scheduleToEvent.js +24 -9
- package/dist/features/openservice/schedules/calendarSync/service/CalendarManager.d.ts +21 -2
- package/dist/features/openservice/schedules/calendarSync/service/CalendarManager.js +74 -15
- package/dist/features/openservice/schedules/calendarSync/service/CalendarSyncPoller.d.ts +17 -0
- package/dist/features/openservice/schedules/calendarSync/service/CalendarSyncPoller.js +165 -0
- package/dist/features/openservice/schedules/calendarSync/service/calendarMetaHelper.d.ts +36 -0
- package/dist/features/openservice/schedules/calendarSync/service/calendarMetaHelper.js +89 -0
- package/dist/features/openservice/schedules/calendarSync/types/Event.d.ts +1 -1
- package/dist/features/openservice/schedules/initSchedulesFeature.js +2 -0
- package/dist/hooks/Maintenance_Schedule.js +18 -16
- package/dist/types/Meta_Config.d.ts +4 -3
- package/dist/types/Meta_Entry.d.ts +4 -3
- package/dist/types/custom/MetaField.d.ts +117 -0
- package/dist/types/custom/MetaField.js +21 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +4 -2
- package/package.json +1 -1
|
@@ -29,29 +29,26 @@ function eventToSchedule(event) {
|
|
|
29
29
|
? pattern.interval
|
|
30
30
|
: 1;
|
|
31
31
|
// Prefer explicit range.startDate, fallback to event.start.dateTime
|
|
32
|
-
let
|
|
32
|
+
let startDate;
|
|
33
33
|
if (range?.startDate) {
|
|
34
34
|
// range.startDate is YYYY-MM-DD
|
|
35
|
-
|
|
35
|
+
startDate = new Date(range.startDate + "T00:00:00Z");
|
|
36
36
|
}
|
|
37
37
|
else if (event.start?.dateTime) {
|
|
38
|
-
|
|
38
|
+
startDate = new Date(event.start.dateTime);
|
|
39
39
|
}
|
|
40
40
|
// For end, prefer range.endDate. If range.type === 'noEnd' leave undefined.
|
|
41
|
-
let
|
|
41
|
+
let endDate;
|
|
42
42
|
if (range?.type === "endDate" && range?.endDate) {
|
|
43
|
-
|
|
43
|
+
endDate = new Date(range.endDate + "T00:00:00Z");
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
endData = new Date(event.end.dateTime);
|
|
47
|
-
}
|
|
48
|
-
if (!startData)
|
|
45
|
+
if (!startDate)
|
|
49
46
|
return undefined;
|
|
50
47
|
return {
|
|
51
48
|
schedule_type: "timestamp",
|
|
52
49
|
timestamp: {
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
startDate,
|
|
51
|
+
endDate,
|
|
55
52
|
number: interval,
|
|
56
53
|
unit,
|
|
57
54
|
},
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.scheduleToEvent = scheduleToEvent;
|
|
7
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
4
8
|
async function scheduleToEvent(schedule) {
|
|
5
9
|
console.log("Converting Schedule to Event...");
|
|
6
10
|
try {
|
|
7
|
-
await schedule.fetchWithInclude("template"
|
|
11
|
+
await schedule.fetchWithInclude(["template"], {
|
|
12
|
+
useMasterKey: true,
|
|
13
|
+
});
|
|
8
14
|
}
|
|
9
15
|
catch (error) {
|
|
10
16
|
console.error("Error fetching template:", error);
|
|
@@ -16,19 +22,21 @@ async function scheduleToEvent(schedule) {
|
|
|
16
22
|
const end = scheduleCron?.timestamp?.endDate ?? templateCron?.timestamp?.endDate;
|
|
17
23
|
const interval = scheduleCron?.timestamp?.number ?? templateCron?.timestamp?.number;
|
|
18
24
|
const unit = scheduleCron?.timestamp?.unit ?? templateCron?.timestamp?.unit;
|
|
19
|
-
if (!start || !
|
|
25
|
+
if (!start || !interval || !unit) {
|
|
20
26
|
console.log("Insufficient data to create event from schedule.");
|
|
21
27
|
return;
|
|
22
28
|
}
|
|
29
|
+
const description = schedule.get("description");
|
|
23
30
|
const event = {
|
|
24
31
|
subject: schedule.get("title"),
|
|
32
|
+
body: { contentType: "Text", content: description ?? "" },
|
|
25
33
|
start: {
|
|
26
34
|
// for single-day/all-day events we use date-only; keep full ISO otherwise
|
|
27
35
|
dateTime: start.toISOString().slice(0, 19),
|
|
28
36
|
timeZone: "UTC",
|
|
29
37
|
},
|
|
30
38
|
end: {
|
|
31
|
-
dateTime:
|
|
39
|
+
dateTime: (0, dayjs_1.default)(start).add(1, "day").toISOString().slice(0, 19),
|
|
32
40
|
timeZone: "UTC",
|
|
33
41
|
},
|
|
34
42
|
isAllDay: true,
|
|
@@ -65,22 +73,29 @@ async function scheduleToEvent(schedule) {
|
|
|
65
73
|
pattern = null;
|
|
66
74
|
}
|
|
67
75
|
if (pattern) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
range: {
|
|
76
|
+
const range = end
|
|
77
|
+
? {
|
|
71
78
|
type: "endDate",
|
|
72
79
|
startDate: toDateOnly(start),
|
|
73
80
|
endDate: toDateOnly(end),
|
|
74
|
-
}
|
|
81
|
+
}
|
|
82
|
+
: {
|
|
83
|
+
type: "noEnd",
|
|
84
|
+
startDate: toDateOnly(start),
|
|
85
|
+
};
|
|
86
|
+
event.recurrence = {
|
|
87
|
+
pattern,
|
|
88
|
+
range,
|
|
75
89
|
};
|
|
76
|
-
// if event is all-day, set start/end to date-only values (Graph expects dates)
|
|
90
|
+
// if event is all-day, set start/end to date-only values (Graph expects dates) => always true for schedules
|
|
77
91
|
if (event.isAllDay) {
|
|
78
92
|
event.start.dateTime = toDateOnly(start);
|
|
79
93
|
// Graph's endDate in event object is exclusive for all-day events; keep as provided for recurrence range
|
|
80
94
|
// Set end to next day to represent an all-day event that begins and ends the same day
|
|
81
95
|
const endForEvent = new Date(start);
|
|
82
96
|
endForEvent.setUTCDate(endForEvent.getUTCDate() + 1);
|
|
83
|
-
event.end
|
|
97
|
+
if (event.end)
|
|
98
|
+
event.end.dateTime = toDateOnly(endForEvent);
|
|
84
99
|
}
|
|
85
100
|
}
|
|
86
101
|
console.log("Schedule converted to Event:", event);
|
|
@@ -3,7 +3,11 @@ import { GraphEvent, GraphEventResponse } from "../types/Event.js";
|
|
|
3
3
|
* Manager for calendar operations via Microsoft Graph API
|
|
4
4
|
*/
|
|
5
5
|
export declare class CalendarManager {
|
|
6
|
-
|
|
6
|
+
tenantID: string;
|
|
7
|
+
clientID: string;
|
|
8
|
+
clientSecret: string;
|
|
9
|
+
userMail: string;
|
|
10
|
+
get isValid(): true | string;
|
|
7
11
|
private getAccess;
|
|
8
12
|
/**
|
|
9
13
|
* Create a new event in the calendar
|
|
@@ -17,13 +21,14 @@ export declare class CalendarManager {
|
|
|
17
21
|
* @param event The updated event data
|
|
18
22
|
* @returns
|
|
19
23
|
*/
|
|
20
|
-
updateEvent(eventId: string, event: Partial<GraphEvent>): Promise<
|
|
24
|
+
updateEvent(eventId: string, event: Partial<GraphEvent>): Promise<GraphEventResponse | undefined>;
|
|
21
25
|
/**
|
|
22
26
|
* Delete an event from the calendar
|
|
23
27
|
* @param eventId The ID of the event to delete
|
|
24
28
|
* @returns whether the deletion was successful
|
|
25
29
|
*/
|
|
26
30
|
deleteEvent(eventId: string): Promise<boolean | undefined>;
|
|
31
|
+
fetchEvent(eventId: string): Promise<GraphEventResponse | null>;
|
|
27
32
|
/**
|
|
28
33
|
* Fetch all events in calendar
|
|
29
34
|
* @returns the list of events
|
|
@@ -31,4 +36,18 @@ export declare class CalendarManager {
|
|
|
31
36
|
fetchEvents(): Promise<{
|
|
32
37
|
value: GraphEventResponse[];
|
|
33
38
|
} | undefined>;
|
|
39
|
+
/**
|
|
40
|
+
* Fetch changed events since the last delta sync.
|
|
41
|
+
* On the first call (no deltaLink), returns all current events and a deltaLink
|
|
42
|
+
* for subsequent incremental calls.
|
|
43
|
+
* @param deltaLink token from the previous call; omit for the initial full sync
|
|
44
|
+
*/
|
|
45
|
+
fetchDelta(deltaLink?: string): Promise<{
|
|
46
|
+
events: (GraphEventResponse & {
|
|
47
|
+
"@removed"?: {
|
|
48
|
+
reason: string;
|
|
49
|
+
};
|
|
50
|
+
})[];
|
|
51
|
+
deltaLink: string;
|
|
52
|
+
} | null>;
|
|
34
53
|
}
|
|
@@ -2,26 +2,40 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CalendarManager = void 0;
|
|
4
4
|
const index_js_1 = require("../../../../config/index.js");
|
|
5
|
-
const tenantID = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_TENANT_ID");
|
|
6
|
-
const clientID = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_CLIENT_ID");
|
|
7
|
-
const clientSecret = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_CLIENT_SECRET");
|
|
8
|
-
const userMail = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_USER_EMAIL");
|
|
9
5
|
/**
|
|
10
6
|
* Manager for calendar operations via Microsoft Graph API
|
|
11
7
|
*/
|
|
12
8
|
class CalendarManager {
|
|
13
|
-
|
|
9
|
+
tenantID = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_TENANT_ID") ||
|
|
10
|
+
index_js_1.ConfigInstance.getInstance().get("OI_MICROSOFT_TENANT_ID");
|
|
11
|
+
clientID = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_CLIENT_ID") ||
|
|
12
|
+
index_js_1.ConfigInstance.getInstance().get("OI_MICROSOFT_APP_ID");
|
|
13
|
+
clientSecret = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_CLIENT_SECRET") ||
|
|
14
|
+
index_js_1.ConfigInstance.getInstance().get("OI_MICROSOFT_CLIENT_SECRET");
|
|
15
|
+
userMail = index_js_1.ConfigInstance.getInstance().get("MICROSOFT_USER_EMAIL") ||
|
|
16
|
+
index_js_1.ConfigInstance.getInstance().get("OI_MICROSOFT_USER_EMAIL");
|
|
17
|
+
get isValid() {
|
|
18
|
+
if (!this.tenantID)
|
|
19
|
+
return "Missing Microsoft Tenant ID";
|
|
20
|
+
if (!this.clientID)
|
|
21
|
+
return "Missing Microsoft Client ID";
|
|
22
|
+
if (!this.clientSecret)
|
|
23
|
+
return "Missing Microsoft Client Secret";
|
|
24
|
+
if (!this.userMail)
|
|
25
|
+
return "Missing Microsoft User Email";
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
14
28
|
async getAccess() {
|
|
15
|
-
if (
|
|
29
|
+
if (this.isValid !== true)
|
|
16
30
|
return null;
|
|
17
31
|
console.log("Getting access token...");
|
|
18
32
|
try {
|
|
19
33
|
const params = new URLSearchParams();
|
|
20
|
-
params.append("client_id", clientID);
|
|
21
|
-
params.append("client_secret", clientSecret);
|
|
34
|
+
params.append("client_id", this.clientID);
|
|
35
|
+
params.append("client_secret", this.clientSecret);
|
|
22
36
|
params.append("scope", "https://graph.microsoft.com/.default");
|
|
23
37
|
params.append("grant_type", "client_credentials");
|
|
24
|
-
const response = await fetch(`https://login.microsoftonline.com/${tenantID}/oauth2/v2.0/token`, {
|
|
38
|
+
const response = await fetch(`https://login.microsoftonline.com/${this.tenantID}/oauth2/v2.0/token`, {
|
|
25
39
|
method: "POST",
|
|
26
40
|
headers: {
|
|
27
41
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -43,12 +57,15 @@ class CalendarManager {
|
|
|
43
57
|
* @returns the created event response
|
|
44
58
|
*/
|
|
45
59
|
async createEvent(event) {
|
|
46
|
-
if (!userMail ||
|
|
60
|
+
if (!this.userMail ||
|
|
61
|
+
!this.tenantID ||
|
|
62
|
+
!this.clientID ||
|
|
63
|
+
!this.clientSecret)
|
|
47
64
|
return;
|
|
48
65
|
const accessData = await this.getAccess();
|
|
49
66
|
if (!accessData?.access_token)
|
|
50
67
|
return;
|
|
51
|
-
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events`, {
|
|
68
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events`, {
|
|
52
69
|
method: "POST",
|
|
53
70
|
headers: {
|
|
54
71
|
Authorization: `Bearer ${accessData.access_token}`,
|
|
@@ -70,7 +87,7 @@ class CalendarManager {
|
|
|
70
87
|
const accessData = await this.getAccess();
|
|
71
88
|
if (!accessData?.access_token)
|
|
72
89
|
return;
|
|
73
|
-
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events/${eventId}`, {
|
|
90
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events/${eventId}`, {
|
|
74
91
|
method: "PATCH",
|
|
75
92
|
headers: {
|
|
76
93
|
Authorization: `Bearer ${accessData.access_token}`,
|
|
@@ -78,7 +95,7 @@ class CalendarManager {
|
|
|
78
95
|
},
|
|
79
96
|
body: JSON.stringify(event),
|
|
80
97
|
});
|
|
81
|
-
const data = await res.json();
|
|
98
|
+
const data = (await res.json());
|
|
82
99
|
console.log("Event update response:", data);
|
|
83
100
|
return data;
|
|
84
101
|
}
|
|
@@ -92,7 +109,7 @@ class CalendarManager {
|
|
|
92
109
|
if (!accessData?.access_token)
|
|
93
110
|
return;
|
|
94
111
|
// on successful deletion, Microsoft Graph returns 204 No Content, so no JSON to parse
|
|
95
|
-
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events/${eventId}`, {
|
|
112
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events/${eventId}`, {
|
|
96
113
|
method: "DELETE",
|
|
97
114
|
headers: {
|
|
98
115
|
Authorization: `Bearer ${accessData.access_token}`,
|
|
@@ -101,6 +118,15 @@ class CalendarManager {
|
|
|
101
118
|
console.log("Event deletion response:", res);
|
|
102
119
|
return res.ok;
|
|
103
120
|
}
|
|
121
|
+
async fetchEvent(eventId) {
|
|
122
|
+
const accessData = await this.getAccess();
|
|
123
|
+
if (!accessData?.access_token)
|
|
124
|
+
return null;
|
|
125
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events/${eventId}`, { headers: { Authorization: `Bearer ${accessData.access_token}` } });
|
|
126
|
+
if (!res.ok)
|
|
127
|
+
return null;
|
|
128
|
+
return (await res.json());
|
|
129
|
+
}
|
|
104
130
|
/**
|
|
105
131
|
* Fetch all events in calendar
|
|
106
132
|
* @returns the list of events
|
|
@@ -109,7 +135,7 @@ class CalendarManager {
|
|
|
109
135
|
const accessData = await this.getAccess();
|
|
110
136
|
if (!accessData?.access_token)
|
|
111
137
|
return;
|
|
112
|
-
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(userMail)}/events`, {
|
|
138
|
+
const res = await fetch(`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events`, {
|
|
113
139
|
method: "GET",
|
|
114
140
|
headers: {
|
|
115
141
|
Authorization: `Bearer ${accessData.access_token}`,
|
|
@@ -119,5 +145,38 @@ class CalendarManager {
|
|
|
119
145
|
console.log("Calendar events:", data);
|
|
120
146
|
return data;
|
|
121
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Fetch changed events since the last delta sync.
|
|
150
|
+
* On the first call (no deltaLink), returns all current events and a deltaLink
|
|
151
|
+
* for subsequent incremental calls.
|
|
152
|
+
* @param deltaLink token from the previous call; omit for the initial full sync
|
|
153
|
+
*/
|
|
154
|
+
async fetchDelta(deltaLink) {
|
|
155
|
+
const accessData = await this.getAccess();
|
|
156
|
+
if (!accessData?.access_token)
|
|
157
|
+
return null;
|
|
158
|
+
const events = [];
|
|
159
|
+
let nextUrl = deltaLink || // treat empty string same as missing
|
|
160
|
+
`https://graph.microsoft.com/v1.0/users/${encodeURIComponent(this.userMail)}/events/delta`;
|
|
161
|
+
let newDeltaLink = "";
|
|
162
|
+
while (nextUrl) {
|
|
163
|
+
const res = await fetch(nextUrl, {
|
|
164
|
+
headers: { Authorization: `Bearer ${accessData.access_token}` },
|
|
165
|
+
});
|
|
166
|
+
if (!res.ok) {
|
|
167
|
+
console.error(`[CalendarManager] fetchDelta HTTP ${res.status}:`, await res.text());
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const data = (await res.json());
|
|
171
|
+
events.push(...(data.value ?? []));
|
|
172
|
+
nextUrl = data["@odata.nextLink"];
|
|
173
|
+
if (data["@odata.deltaLink"])
|
|
174
|
+
newDeltaLink = data["@odata.deltaLink"];
|
|
175
|
+
}
|
|
176
|
+
console.log("Delta fetch result:", { events, newDeltaLink });
|
|
177
|
+
if (!newDeltaLink)
|
|
178
|
+
return null;
|
|
179
|
+
return { events, deltaLink: newDeltaLink };
|
|
180
|
+
}
|
|
122
181
|
}
|
|
123
182
|
exports.CalendarManager = CalendarManager;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare class CalendarSyncPoller {
|
|
2
|
+
private manager;
|
|
3
|
+
private timer;
|
|
4
|
+
/**
|
|
5
|
+
* Start polling the Microsoft Calendar delta feed.
|
|
6
|
+
* @param intervalMs polling interval in milliseconds (default: 5 minutes)
|
|
7
|
+
*/
|
|
8
|
+
start(intervalMs?: number): void;
|
|
9
|
+
stop(): void;
|
|
10
|
+
private poll;
|
|
11
|
+
private processEvent;
|
|
12
|
+
private updateScheduleFromEvent;
|
|
13
|
+
private createScheduleFromEvent;
|
|
14
|
+
private handleDeleted;
|
|
15
|
+
private loadDeltaLink;
|
|
16
|
+
private saveDeltaLink;
|
|
17
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CalendarSyncPoller = void 0;
|
|
7
|
+
const node_1 = __importDefault(require("parse/node"));
|
|
8
|
+
const eventToSchedule_js_1 = require("../functions/eventToSchedule.js");
|
|
9
|
+
const calendarMetaHelper_js_1 = require("./calendarMetaHelper.js");
|
|
10
|
+
const CalendarManager_js_1 = require("./CalendarManager.js");
|
|
11
|
+
const index_js_1 = require("../../../../../types/index.js");
|
|
12
|
+
const DELTA_LINK_CONFIG_KEY = "microsoftCalendarDeltaLink";
|
|
13
|
+
class CalendarSyncPoller {
|
|
14
|
+
manager = new CalendarManager_js_1.CalendarManager();
|
|
15
|
+
timer = null;
|
|
16
|
+
/**
|
|
17
|
+
* Start polling the Microsoft Calendar delta feed.
|
|
18
|
+
* @param intervalMs polling interval in milliseconds (default: 5 minutes)
|
|
19
|
+
*/
|
|
20
|
+
start(intervalMs = 5 * 60 * 1000) {
|
|
21
|
+
if (this.manager.isValid !== true) {
|
|
22
|
+
console.log("[CalendarSyncPoller] Not started — missing Microsoft credentials.", this.manager.isValid);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
this.poll().catch(console.error);
|
|
26
|
+
this.timer = setInterval(() => this.poll().catch(console.error), intervalMs);
|
|
27
|
+
}
|
|
28
|
+
stop() {
|
|
29
|
+
if (this.timer)
|
|
30
|
+
clearInterval(this.timer);
|
|
31
|
+
}
|
|
32
|
+
async poll() {
|
|
33
|
+
console.log("[CalendarSyncPoller] Polling calendar delta...");
|
|
34
|
+
const deltaLink = await this.loadDeltaLink();
|
|
35
|
+
const result = await this.manager.fetchDelta(deltaLink ?? undefined);
|
|
36
|
+
if (!result) {
|
|
37
|
+
console.log("[CalendarSyncPoller] Failed to fetch calendar delta.");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
for (const event of result.events) {
|
|
41
|
+
try {
|
|
42
|
+
await this.processEvent(event);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
console.error("[CalendarSyncPoller] Error processing event:", event.id, err);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
await this.saveDeltaLink(result.deltaLink);
|
|
49
|
+
}
|
|
50
|
+
async processEvent(event) {
|
|
51
|
+
if (event["@removed"]) {
|
|
52
|
+
await this.handleDeleted(event.id);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const metaEntry = await (0, calendarMetaHelper_js_1.findCalendarMetaByEventId)(event.id);
|
|
56
|
+
if (metaEntry) {
|
|
57
|
+
const storedChangeKey = metaEntry.get("values")?.microsoftCalendarChangeKey;
|
|
58
|
+
// Skip if we caused this change (our write already stored this changeKey)
|
|
59
|
+
if (event.changeKey && storedChangeKey === event.changeKey)
|
|
60
|
+
return;
|
|
61
|
+
await this.updateScheduleFromEvent(metaEntry, event);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Delta responses omit most properties; fetch the full event before creating a schedule
|
|
65
|
+
const fullEvent = await this.manager.fetchEvent(event.id);
|
|
66
|
+
if (!fullEvent)
|
|
67
|
+
return;
|
|
68
|
+
await this.createScheduleFromEvent(fullEvent);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async updateScheduleFromEvent(metaEntry, event) {
|
|
72
|
+
const scheduleId = metaEntry.get("entryObjectId");
|
|
73
|
+
if (!scheduleId)
|
|
74
|
+
return;
|
|
75
|
+
// Delta responses omit most fields; fetch the full event for title/body/cron
|
|
76
|
+
const fullEvent = await this.manager.fetchEvent(event.id) ?? event;
|
|
77
|
+
const schedule = await new node_1.default.Query(index_js_1.Maintenance_Schedule).get(scheduleId, { useMasterKey: true });
|
|
78
|
+
if (fullEvent.subject)
|
|
79
|
+
schedule.set("title", fullEvent.subject);
|
|
80
|
+
if (fullEvent.bodyPreview)
|
|
81
|
+
schedule.set("description", fullEvent.bodyPreview);
|
|
82
|
+
const cronData = (0, eventToSchedule_js_1.eventToSchedule)(fullEvent);
|
|
83
|
+
if (cronData)
|
|
84
|
+
schedule.set("cron", cronData);
|
|
85
|
+
// useMasterKey prevents afterSaveHook from re-syncing back to calendar
|
|
86
|
+
await schedule.save(null, { useMasterKey: true });
|
|
87
|
+
if (event.changeKey) {
|
|
88
|
+
await (0, calendarMetaHelper_js_1.updateCalendarChangeKey)(metaEntry, event.changeKey, fullEvent);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async createScheduleFromEvent(event) {
|
|
92
|
+
const parsed = parseEventSubject(event.subject);
|
|
93
|
+
if (!parsed) {
|
|
94
|
+
console.log(`[CalendarSyncPoller] Skipping event "${event.subject}" (${event.id}) — subject does not match expected format: '"<source>" - <title>'.`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const source = await new node_1.default.Query(index_js_1.Source)
|
|
98
|
+
.equalTo("name", parsed.sourceName)
|
|
99
|
+
.first({ useMasterKey: true });
|
|
100
|
+
if (!source) {
|
|
101
|
+
console.log(`[CalendarSyncPoller] Skipping event "${event.subject}" (${event.id}) — no Source found with name "${parsed.sourceName}".`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const schedule = new index_js_1.Maintenance_Schedule();
|
|
105
|
+
schedule.set("title", event.subject);
|
|
106
|
+
schedule.set("source", source);
|
|
107
|
+
schedule.set("enabled", true);
|
|
108
|
+
schedule.set("tenant", source.get("tenant"));
|
|
109
|
+
if (event.bodyPreview)
|
|
110
|
+
schedule.set("description", event.bodyPreview);
|
|
111
|
+
const cronData = (0, eventToSchedule_js_1.eventToSchedule)(event);
|
|
112
|
+
if (cronData)
|
|
113
|
+
schedule.set("cron", cronData);
|
|
114
|
+
// useMasterKey prevents afterSaveHook from syncing back to calendar
|
|
115
|
+
await schedule.save(null, { useMasterKey: true });
|
|
116
|
+
await (0, calendarMetaHelper_js_1.saveCalendarMeta)(schedule.id, event.id, event.changeKey, source.get("tenant"), event);
|
|
117
|
+
console.log(`[CalendarSyncPoller] Created schedule "${event.subject}" for source "${parsed.sourceName}" from calendar event ${event.id}.`);
|
|
118
|
+
}
|
|
119
|
+
async handleDeleted(eventId) {
|
|
120
|
+
const metaEntry = await (0, calendarMetaHelper_js_1.findCalendarMetaByEventId)(eventId);
|
|
121
|
+
if (!metaEntry)
|
|
122
|
+
return;
|
|
123
|
+
const scheduleId = metaEntry.get("entryObjectId");
|
|
124
|
+
if (scheduleId) {
|
|
125
|
+
try {
|
|
126
|
+
const schedule = await new node_1.default.Query(index_js_1.Maintenance_Schedule).get(scheduleId, { useMasterKey: true });
|
|
127
|
+
// Disable rather than delete to preserve execution history
|
|
128
|
+
schedule.set("enabled", false);
|
|
129
|
+
await schedule.save(null, { useMasterKey: true });
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
console.error("[CalendarSyncPoller] Could not disable schedule for deleted event:", scheduleId, err);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
await metaEntry.destroy({ useMasterKey: true });
|
|
136
|
+
}
|
|
137
|
+
async loadDeltaLink() {
|
|
138
|
+
try {
|
|
139
|
+
const config = await node_1.default.Config.get({ useMasterKey: true });
|
|
140
|
+
return config.get(DELTA_LINK_CONFIG_KEY) || null;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async saveDeltaLink(link) {
|
|
147
|
+
await node_1.default.Config.save({ [DELTA_LINK_CONFIG_KEY]: link }, { useMasterKey: true });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.CalendarSyncPoller = CalendarSyncPoller;
|
|
151
|
+
// Parses the source name out of an Outlook-originated event subject.
|
|
152
|
+
// Expected format for externally-created events: "<source.name>" - <anything>
|
|
153
|
+
// Quotes around the source name are optional.
|
|
154
|
+
function parseEventSubject(subject) {
|
|
155
|
+
if (!subject)
|
|
156
|
+
return null;
|
|
157
|
+
const separatorIdx = subject.indexOf(" - ");
|
|
158
|
+
if (separatorIdx === -1)
|
|
159
|
+
return null;
|
|
160
|
+
const rawSource = subject.slice(0, separatorIdx).trim();
|
|
161
|
+
if (!rawSource)
|
|
162
|
+
return null;
|
|
163
|
+
const sourceName = rawSource.replace(/^"(.*)"$/, "$1");
|
|
164
|
+
return { sourceName };
|
|
165
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Meta_Entry, Tenant } from "../../../../../types/index.js";
|
|
2
|
+
import { MetaConfig } from "../../../../../types/custom/MetaField.js";
|
|
3
|
+
import { GraphEventResponse } from "../types/Event.js";
|
|
4
|
+
export declare const CALENDAR_SYNC_CONTEXT: string;
|
|
5
|
+
export interface CalendarEventSnapshot {
|
|
6
|
+
id: string;
|
|
7
|
+
subject?: string;
|
|
8
|
+
start: {
|
|
9
|
+
dateTime: string;
|
|
10
|
+
timeZone: string;
|
|
11
|
+
};
|
|
12
|
+
end: {
|
|
13
|
+
dateTime: string;
|
|
14
|
+
timeZone: string;
|
|
15
|
+
};
|
|
16
|
+
isAllDay?: boolean;
|
|
17
|
+
isCancelled?: boolean;
|
|
18
|
+
body?: {
|
|
19
|
+
contentType?: string;
|
|
20
|
+
content?: string;
|
|
21
|
+
};
|
|
22
|
+
recurrence?: GraphEventResponse["recurrence"];
|
|
23
|
+
location?: {
|
|
24
|
+
displayName?: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface CalendarMetaValues {
|
|
28
|
+
microsoftCalendarEventId: string;
|
|
29
|
+
microsoftCalendarChangeKey?: string;
|
|
30
|
+
microsoftCalendarEvent?: CalendarEventSnapshot;
|
|
31
|
+
}
|
|
32
|
+
export declare const CalendarMetaConfig: MetaConfig;
|
|
33
|
+
export declare function findCalendarMetaForSchedule(scheduleId: string): Promise<Meta_Entry | null>;
|
|
34
|
+
export declare function findCalendarMetaByEventId(eventId: string): Promise<Meta_Entry | null>;
|
|
35
|
+
export declare function saveCalendarMeta(scheduleId: string, eventId: string, changeKey?: string, tenant?: Tenant, event?: GraphEventResponse): Promise<Meta_Entry>;
|
|
36
|
+
export declare function updateCalendarChangeKey(entry: Meta_Entry, changeKey: string, event?: GraphEventResponse): Promise<void>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CalendarMetaConfig = exports.CALENDAR_SYNC_CONTEXT = void 0;
|
|
7
|
+
exports.findCalendarMetaForSchedule = findCalendarMetaForSchedule;
|
|
8
|
+
exports.findCalendarMetaByEventId = findCalendarMetaByEventId;
|
|
9
|
+
exports.saveCalendarMeta = saveCalendarMeta;
|
|
10
|
+
exports.updateCalendarChangeKey = updateCalendarChangeKey;
|
|
11
|
+
const node_1 = __importDefault(require("parse/node"));
|
|
12
|
+
const index_js_1 = require("../../../../../types/index.js");
|
|
13
|
+
exports.CALENDAR_SYNC_CONTEXT = JSON.stringify([
|
|
14
|
+
"schedule",
|
|
15
|
+
"sync",
|
|
16
|
+
"microsoft",
|
|
17
|
+
]);
|
|
18
|
+
function toEventSnapshot(event) {
|
|
19
|
+
return {
|
|
20
|
+
id: event.id,
|
|
21
|
+
subject: event.subject,
|
|
22
|
+
start: event.start,
|
|
23
|
+
end: event.end,
|
|
24
|
+
isAllDay: event.isAllDay,
|
|
25
|
+
isCancelled: event.isCancelled,
|
|
26
|
+
body: event.body
|
|
27
|
+
? { contentType: event.body.contentType, content: event.body.content }
|
|
28
|
+
: undefined,
|
|
29
|
+
recurrence: event.recurrence ?? undefined,
|
|
30
|
+
location: event.location?.displayName
|
|
31
|
+
? { displayName: event.location.displayName }
|
|
32
|
+
: undefined,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
exports.CalendarMetaConfig = {
|
|
36
|
+
fields: [
|
|
37
|
+
{
|
|
38
|
+
name: "microsoftCalendarEventId",
|
|
39
|
+
type: "string",
|
|
40
|
+
label: "Microsoft Calendar Event ID",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "microsoftCalendarChangeKey",
|
|
44
|
+
type: "string",
|
|
45
|
+
label: "Microsoft Calendar Change Key",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
async function findCalendarMetaForSchedule(scheduleId) {
|
|
50
|
+
return ((await new node_1.default.Query(index_js_1.Meta_Entry)
|
|
51
|
+
.equalTo("context", exports.CALENDAR_SYNC_CONTEXT)
|
|
52
|
+
.equalTo("entryClassName", index_js_1.Maintenance_Schedule.className)
|
|
53
|
+
.equalTo("entryObjectId", scheduleId)
|
|
54
|
+
.first({ useMasterKey: true })) ?? null);
|
|
55
|
+
}
|
|
56
|
+
async function findCalendarMetaByEventId(eventId) {
|
|
57
|
+
return ((await new node_1.default.Query(index_js_1.Meta_Entry)
|
|
58
|
+
.equalTo("context", exports.CALENDAR_SYNC_CONTEXT)
|
|
59
|
+
.equalTo("entryClassName", index_js_1.Maintenance_Schedule.className)
|
|
60
|
+
// @ts-expect-error
|
|
61
|
+
.equalTo("values.microsoftCalendarEventId", eventId)
|
|
62
|
+
.first({ useMasterKey: true })) ?? null);
|
|
63
|
+
}
|
|
64
|
+
async function saveCalendarMeta(scheduleId, eventId, changeKey, tenant, event) {
|
|
65
|
+
let entry = await findCalendarMetaForSchedule(scheduleId);
|
|
66
|
+
if (!entry) {
|
|
67
|
+
entry = new index_js_1.Meta_Entry();
|
|
68
|
+
entry.set("context", exports.CALENDAR_SYNC_CONTEXT);
|
|
69
|
+
entry.set("entryClassName", index_js_1.Maintenance_Schedule.className);
|
|
70
|
+
entry.set("entryObjectId", scheduleId);
|
|
71
|
+
entry.set("tenant", tenant);
|
|
72
|
+
entry.set("config", {});
|
|
73
|
+
}
|
|
74
|
+
const values = { microsoftCalendarEventId: eventId };
|
|
75
|
+
if (changeKey)
|
|
76
|
+
values.microsoftCalendarChangeKey = changeKey;
|
|
77
|
+
if (event)
|
|
78
|
+
values.microsoftCalendarEvent = toEventSnapshot(event);
|
|
79
|
+
entry.set("values", values);
|
|
80
|
+
return entry.save(null, { useMasterKey: true });
|
|
81
|
+
}
|
|
82
|
+
async function updateCalendarChangeKey(entry, changeKey, event) {
|
|
83
|
+
entry.set("values", {
|
|
84
|
+
...entry.get("values"),
|
|
85
|
+
microsoftCalendarChangeKey: changeKey,
|
|
86
|
+
...(event ? { microsoftCalendarEvent: toEventSnapshot(event) } : {}),
|
|
87
|
+
});
|
|
88
|
+
await entry.save(null, { useMasterKey: true });
|
|
89
|
+
}
|
|
@@ -6,8 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.initSchedulesFeature = initSchedulesFeature;
|
|
7
7
|
const node_1 = __importDefault(require("parse/node"));
|
|
8
8
|
const index_js_1 = require("../../../types/index.js");
|
|
9
|
+
const CalendarSyncPoller_js_1 = require("./calendarSync/service/CalendarSyncPoller.js");
|
|
9
10
|
async function initSchedulesFeature() {
|
|
10
11
|
updateFiinishedSchedules();
|
|
12
|
+
new CalendarSyncPoller_js_1.CalendarSyncPoller().start(1000 * 60);
|
|
11
13
|
}
|
|
12
14
|
async function updateFiinishedSchedules() {
|
|
13
15
|
const executionsToUpdate = await new node_1.default.Query(index_js_1.Maintenance_Schedule_Execution)
|
|
@@ -6,12 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.init = init;
|
|
7
7
|
const node_1 = __importDefault(require("parse/node"));
|
|
8
8
|
const scheduleToEvent_1 = require("../features/openservice/schedules/calendarSync/functions/scheduleToEvent");
|
|
9
|
+
const calendarMetaHelper_1 = require("../features/openservice/schedules/calendarSync/service/calendarMetaHelper");
|
|
9
10
|
const CalendarManager_1 = require("../features/openservice/schedules/calendarSync/service/CalendarManager");
|
|
10
11
|
const schema_1 = require("../features/schema");
|
|
11
12
|
const types_1 = require("../types");
|
|
12
13
|
async function init() {
|
|
13
14
|
(0, schema_1.beforeSaveHook)(types_1.Maintenance_Schedule, async (request) => {
|
|
14
|
-
const { object, original, user } = request;
|
|
15
15
|
await (0, schema_1.defaultHandler)(request);
|
|
16
16
|
// await defaultAclHandler(request, { allowCustomACL: true });
|
|
17
17
|
});
|
|
@@ -51,7 +51,7 @@ async function init() {
|
|
|
51
51
|
}
|
|
52
52
|
});
|
|
53
53
|
(0, schema_1.beforeDeleteHook)(types_1.Maintenance_Schedule, async (request) => {
|
|
54
|
-
const { object
|
|
54
|
+
const { object } = request;
|
|
55
55
|
const scheduleFetched = await object?.fetchWithInclude(["template", "source"], {
|
|
56
56
|
useMasterKey: true,
|
|
57
57
|
});
|
|
@@ -60,9 +60,13 @@ async function init() {
|
|
|
60
60
|
if (source)
|
|
61
61
|
template?.relation("sources").remove(source);
|
|
62
62
|
await template?.save(null, { useMasterKey: true });
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
|
|
63
|
+
const metaEntry = await (0, calendarMetaHelper_1.findCalendarMetaForSchedule)(object.id);
|
|
64
|
+
if (metaEntry) {
|
|
65
|
+
const eventId = metaEntry.get("values")?.microsoftCalendarEventId;
|
|
66
|
+
if (eventId) {
|
|
67
|
+
await new CalendarManager_1.CalendarManager().deleteEvent(eventId);
|
|
68
|
+
}
|
|
69
|
+
await metaEntry.destroy({ useMasterKey: true });
|
|
66
70
|
}
|
|
67
71
|
});
|
|
68
72
|
}
|
|
@@ -89,11 +93,14 @@ async function updateCalendarEvent(schedule) {
|
|
|
89
93
|
if (!event)
|
|
90
94
|
return;
|
|
91
95
|
const calendarManager = new CalendarManager_1.CalendarManager();
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
96
|
+
const metaEntry = await (0, calendarMetaHelper_1.findCalendarMetaForSchedule)(schedule.id);
|
|
97
|
+
const eventId = metaEntry?.get("values")?.microsoftCalendarEventId;
|
|
98
|
+
if (eventId) {
|
|
95
99
|
console.log("Updating schedule in calendar...");
|
|
96
|
-
await calendarManager.updateEvent(
|
|
100
|
+
const updatedEvent = await calendarManager.updateEvent(eventId, event);
|
|
101
|
+
if (updatedEvent?.changeKey && metaEntry) {
|
|
102
|
+
await (0, calendarMetaHelper_1.updateCalendarChangeKey)(metaEntry, updatedEvent.changeKey, updatedEvent);
|
|
103
|
+
}
|
|
97
104
|
}
|
|
98
105
|
else {
|
|
99
106
|
await addToCalendar(schedule);
|
|
@@ -110,12 +117,7 @@ async function addToCalendar(schedule) {
|
|
|
110
117
|
return;
|
|
111
118
|
const calendarManager = new CalendarManager_1.CalendarManager();
|
|
112
119
|
const createdEvent = await calendarManager.createEvent(event);
|
|
113
|
-
if (createdEvent
|
|
114
|
-
|
|
115
|
-
schedule.set("meta", {
|
|
116
|
-
...existingMeta,
|
|
117
|
-
microsoftCalendarEventId: createdEvent.id,
|
|
118
|
-
});
|
|
119
|
-
await schedule.save(null, { useMasterKey: true });
|
|
120
|
+
if (createdEvent?.id) {
|
|
121
|
+
await (0, calendarMetaHelper_1.saveCalendarMeta)(schedule.id, createdEvent.id, createdEvent.changeKey, schedule.get("tenant"), createdEvent);
|
|
120
122
|
}
|
|
121
123
|
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import Parse from "parse/node";
|
|
2
2
|
import type { Tenant } from "./Tenant";
|
|
3
|
+
import { MetaConfig } from "./custom/MetaField";
|
|
3
4
|
export interface Meta_ConfigAttributes {
|
|
4
5
|
id: string;
|
|
5
6
|
objectId: string;
|
|
6
7
|
createdAt: Date;
|
|
7
8
|
updatedAt: Date;
|
|
8
|
-
config:
|
|
9
|
+
config: MetaConfig;
|
|
9
10
|
context?: string | undefined;
|
|
10
11
|
tenant?: Tenant | undefined;
|
|
11
12
|
}
|
|
12
13
|
export declare class Meta_Config extends Parse.Object<Meta_ConfigAttributes> {
|
|
13
14
|
static className: string;
|
|
14
15
|
constructor(data?: Partial<Meta_ConfigAttributes>);
|
|
15
|
-
get config():
|
|
16
|
-
set config(value:
|
|
16
|
+
get config(): MetaConfig;
|
|
17
|
+
set config(value: MetaConfig);
|
|
17
18
|
get context(): string | undefined;
|
|
18
19
|
set context(value: string | undefined);
|
|
19
20
|
get tenant(): Tenant | undefined;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import Parse from "parse/node";
|
|
2
2
|
import type { Meta_Config } from "./Meta_Config";
|
|
3
3
|
import type { Tenant } from "./Tenant";
|
|
4
|
+
import { MetaConfig } from "./custom/MetaField";
|
|
4
5
|
export interface Meta_EntryAttributes {
|
|
5
6
|
id: string;
|
|
6
7
|
objectId: string;
|
|
7
8
|
createdAt: Date;
|
|
8
9
|
updatedAt: Date;
|
|
9
|
-
config?:
|
|
10
|
+
config?: MetaConfig | undefined;
|
|
10
11
|
context?: string | undefined;
|
|
11
12
|
entryClassName?: string | undefined;
|
|
12
13
|
entryObjectId?: string | undefined;
|
|
@@ -17,8 +18,8 @@ export interface Meta_EntryAttributes {
|
|
|
17
18
|
export declare class Meta_Entry extends Parse.Object<Meta_EntryAttributes> {
|
|
18
19
|
static className: string;
|
|
19
20
|
constructor(data?: Partial<Meta_EntryAttributes>);
|
|
20
|
-
get config():
|
|
21
|
-
set config(value:
|
|
21
|
+
get config(): MetaConfig | undefined;
|
|
22
|
+
set config(value: MetaConfig | undefined);
|
|
22
23
|
get context(): string | undefined;
|
|
23
24
|
set context(value: string | undefined);
|
|
24
25
|
get entryClassName(): string | undefined;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base properties shared by all meta field types
|
|
3
|
+
*/
|
|
4
|
+
export type MetaFieldBaseConfig = {
|
|
5
|
+
name: string;
|
|
6
|
+
label: string;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
help?: string;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
/** Default value for the field */
|
|
11
|
+
defaultValue?: any;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* String field type with optional validation
|
|
15
|
+
*/
|
|
16
|
+
export type MetaFieldString = MetaFieldBaseConfig & {
|
|
17
|
+
type: "string";
|
|
18
|
+
minLength?: number;
|
|
19
|
+
maxLength?: number;
|
|
20
|
+
pattern?: string;
|
|
21
|
+
multiline?: boolean;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Number field type with min/max constraints
|
|
25
|
+
*/
|
|
26
|
+
export type MetaFieldNumber = MetaFieldBaseConfig & {
|
|
27
|
+
type: "number";
|
|
28
|
+
min?: number;
|
|
29
|
+
max?: number;
|
|
30
|
+
step?: number;
|
|
31
|
+
unit?: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Boolean field type (checkbox/switch)
|
|
35
|
+
*/
|
|
36
|
+
export type MetaFieldBoolean = MetaFieldBaseConfig & {
|
|
37
|
+
type: "boolean";
|
|
38
|
+
defaultValue?: boolean;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Date field type with optional date range constraints
|
|
42
|
+
*/
|
|
43
|
+
export type MetaFieldDate = MetaFieldBaseConfig & {
|
|
44
|
+
type: "date";
|
|
45
|
+
minDate?: Date;
|
|
46
|
+
maxDate?: Date;
|
|
47
|
+
includeTime?: boolean;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Select field type with predefined options
|
|
51
|
+
*/
|
|
52
|
+
export type MetaFieldSelect = MetaFieldBaseConfig & {
|
|
53
|
+
type: "select";
|
|
54
|
+
options: Array<{
|
|
55
|
+
label: string;
|
|
56
|
+
value: string;
|
|
57
|
+
disabled?: boolean;
|
|
58
|
+
}>;
|
|
59
|
+
/** Optional grouping for select options */
|
|
60
|
+
groups?: Array<{
|
|
61
|
+
label: string;
|
|
62
|
+
options: Array<{
|
|
63
|
+
label: string;
|
|
64
|
+
value: string;
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
}>;
|
|
67
|
+
}>;
|
|
68
|
+
multiple?: boolean;
|
|
69
|
+
defaultValue?: string | string[];
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Parse select field type for selecting Parse objects
|
|
73
|
+
*/
|
|
74
|
+
export type MetaFieldSelectParse = MetaFieldBaseConfig & {
|
|
75
|
+
type: "select_parse";
|
|
76
|
+
className: string;
|
|
77
|
+
display?: string;
|
|
78
|
+
multiple?: boolean;
|
|
79
|
+
defaultValue?: string | string[];
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Array of all available field types
|
|
83
|
+
*/
|
|
84
|
+
export declare const META_FIELD_TYPES: readonly ["string", "number", "boolean", "date", "select", "select_parse"];
|
|
85
|
+
/**
|
|
86
|
+
* Literal type for field types derived from the array
|
|
87
|
+
*/
|
|
88
|
+
export type MetaFieldTypes = (typeof META_FIELD_TYPES)[number];
|
|
89
|
+
/**
|
|
90
|
+
* Mapped type for accessing MetaField types by their string literal
|
|
91
|
+
* @example MetaFieldMap["string"] => MetaFieldString
|
|
92
|
+
*/
|
|
93
|
+
export type MetaFieldMap = {
|
|
94
|
+
string: MetaFieldString;
|
|
95
|
+
number: MetaFieldNumber;
|
|
96
|
+
boolean: MetaFieldBoolean;
|
|
97
|
+
date: MetaFieldDate;
|
|
98
|
+
select: MetaFieldSelect;
|
|
99
|
+
select_parse: MetaFieldSelectParse;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Union type of all specific meta field types
|
|
103
|
+
*/
|
|
104
|
+
export type MetaFieldConfig = MetaFieldString | MetaFieldNumber | MetaFieldBoolean | MetaFieldDate | MetaFieldSelect | MetaFieldSelectParse;
|
|
105
|
+
/**
|
|
106
|
+
* Helper type to extract specific field type from MetaField union
|
|
107
|
+
*/
|
|
108
|
+
export type MetaFieldOfType<T extends MetaFieldTypes> = Extract<MetaFieldConfig, {
|
|
109
|
+
type: T;
|
|
110
|
+
}>;
|
|
111
|
+
/**
|
|
112
|
+
* Type guard to check if a field is of a specific type
|
|
113
|
+
*/
|
|
114
|
+
export declare function isMetaFieldType<T extends MetaFieldTypes>(field: MetaFieldConfig, type: T): field is MetaFieldOfType<T>;
|
|
115
|
+
export type MetaConfig = {
|
|
116
|
+
fields: MetaFieldConfig[];
|
|
117
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.META_FIELD_TYPES = void 0;
|
|
4
|
+
exports.isMetaFieldType = isMetaFieldType;
|
|
5
|
+
/**
|
|
6
|
+
* Array of all available field types
|
|
7
|
+
*/
|
|
8
|
+
exports.META_FIELD_TYPES = [
|
|
9
|
+
"string",
|
|
10
|
+
"number",
|
|
11
|
+
"boolean",
|
|
12
|
+
"date",
|
|
13
|
+
"select",
|
|
14
|
+
"select_parse",
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Type guard to check if a field is of a specific type
|
|
18
|
+
*/
|
|
19
|
+
function isMetaFieldType(field, type) {
|
|
20
|
+
return field.type === type;
|
|
21
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -140,6 +140,8 @@ export { Maintenance_Schedule_Step } from "./Maintenance_Schedule_Step";
|
|
|
140
140
|
export type { Maintenance_Schedule_StepAttributes } from "./Maintenance_Schedule_Step";
|
|
141
141
|
export { Maintenance_Schedule_Template } from "./Maintenance_Schedule_Template";
|
|
142
142
|
export type { Maintenance_Schedule_TemplateAttributes } from "./Maintenance_Schedule_Template";
|
|
143
|
+
export { Maintenance_SourceMeta } from "./Maintenance_SourceMeta";
|
|
144
|
+
export type { Maintenance_SourceMetaAttributes } from "./Maintenance_SourceMeta";
|
|
143
145
|
export { Maintenance_Source_File } from "./Maintenance_Source_File";
|
|
144
146
|
export type { Maintenance_Source_FileAttributes } from "./Maintenance_Source_File";
|
|
145
147
|
export { Maintenance_Ticket } from "./Maintenance_Ticket";
|
package/dist/types/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MES_OrderPlan = exports.MES_Order = exports.MES_Article = exports.Log = exports.Language = exports.Knowledge_Video = exports.Knowledge_DocumentPage = exports.Knowledge_Document = exports.Knowledge_ChatMessage = exports.Knowledge_Chat = exports.Knowledge_Category = exports.Knowledge_Article = exports.GTFS_Wheelchair_Boarding = exports.GTFS_Wheelchair_Accessible = exports.GTFS_Trip = exports.GTFS_Stop_Times = exports.GTFS_Stop = exports.GTFS_Route_Type = exports.GTFS_Route = exports.GTFS_Location_Type = exports.GTFS_Level = exports.GTFS_Direction = exports.GTFS_Calendar = exports.GTFS_Bikes_Allowed = exports.GTFS_Agency = exports.EMS_ChargePoint = exports.Documentation_Document = exports.Documentation_Config = exports.Documentation_Category = exports.Dashboard = exports.Core_Token = exports.Core_Email = exports.Contact = exports.Config = exports.Company = exports.Changelog = exports.BDE_WorkTime = exports.BDE_WorkOrder = exports.BDE_Unit = exports.BDE_Result = exports.BDE_Page = exports.BDE_ListEntry = exports.BDE_List = exports.BDE_Form = exports.BDE_Article = exports.Attachment = exports.Assets = exports.AlarmWebhook = exports.AlarmAction = exports.Alarm = void 0;
|
|
4
|
-
exports.
|
|
5
|
-
exports.WidgetPreset = exports.Widget = exports.WebPush = exports.VirtualKPI = exports.User_Setting = exports.UserData = exports.TenantTrustedDomain = exports.TenantMeta = exports.Tenant = exports.Spreadsheet_Workbook = exports.SourceMeta = exports.Source = exports.Share = exports.Report = exports.RAG_Request = exports.RAG_Questions = exports.RAG_Prompts = exports.RAG_Meta = exports.RAG_Interview = void 0;
|
|
4
|
+
exports.Push = exports.Permission = exports.OWPlcItem = exports.OWPlcDevice = exports.Notification_Setting = exports.Notification = exports.NavigationItem = exports.NavigationGroup = exports.Monitoring_Slideshow = exports.Monitoring_ReportImage = exports.Monitoring_ParseTableSensor = exports.Monitoring_Jobs = exports.Monitoring_DataHierachies = exports.Meta_Entry = exports.Meta_Config = exports.Maintenance_Ticket_Title = exports.Maintenance_Ticket_Source = exports.Maintenance_Ticket_QR_Code = exports.Maintenance_Ticket_Project = exports.Maintenance_Ticket_Material = exports.Maintenance_Ticket_Kanban_State_Current = exports.Maintenance_Ticket_Kanban_State = exports.Maintenance_Ticket_Issuecategory = exports.Maintenance_Ticket_FormConfig = exports.Maintenance_Ticket_Data = exports.Maintenance_Ticket_Assignment = exports.Maintenance_Ticket = exports.Maintenance_Source_File = exports.Maintenance_SourceMeta = exports.Maintenance_Schedule_Template = exports.Maintenance_Schedule_Step = exports.Maintenance_Schedule_Execution_Step = exports.Maintenance_Schedule_Execution = exports.Maintenance_Schedule = exports.Maintenance_Restriction = exports.Maintenance_Project = exports.Maintenance_Priority = exports.Maintenance_Order = exports.Maintenance_Message = exports.Maintenance_Media = exports.Maintenance_Kanban_State = exports.Maintenance_Item = exports.Maintenance_Issuecategory = exports.Maintenance_Frequency = exports.Maintenance_Duedate = exports.Maintenance_Downtime = exports.Mail_Groups = exports.MailTemplate = exports.ML_DataSelection = exports.MIAAS_MDSEndpoint = void 0;
|
|
5
|
+
exports.WidgetPreset = exports.Widget = exports.WebPush = exports.VirtualKPI = exports.User_Setting = exports.UserData = exports.TenantTrustedDomain = exports.TenantMeta = exports.Tenant = exports.Spreadsheet_Workbook = exports.SourceMeta = exports.Source = exports.Share = exports.Report = exports.RAG_Request = exports.RAG_Questions = exports.RAG_Prompts = exports.RAG_Meta = exports.RAG_Interview = exports.RAG_Data = void 0;
|
|
6
6
|
var Alarm_1 = require("./Alarm");
|
|
7
7
|
Object.defineProperty(exports, "Alarm", { enumerable: true, get: function () { return Alarm_1.Alarm; } });
|
|
8
8
|
var AlarmAction_1 = require("./AlarmAction");
|
|
@@ -145,6 +145,8 @@ var Maintenance_Schedule_Step_1 = require("./Maintenance_Schedule_Step");
|
|
|
145
145
|
Object.defineProperty(exports, "Maintenance_Schedule_Step", { enumerable: true, get: function () { return Maintenance_Schedule_Step_1.Maintenance_Schedule_Step; } });
|
|
146
146
|
var Maintenance_Schedule_Template_1 = require("./Maintenance_Schedule_Template");
|
|
147
147
|
Object.defineProperty(exports, "Maintenance_Schedule_Template", { enumerable: true, get: function () { return Maintenance_Schedule_Template_1.Maintenance_Schedule_Template; } });
|
|
148
|
+
var Maintenance_SourceMeta_1 = require("./Maintenance_SourceMeta");
|
|
149
|
+
Object.defineProperty(exports, "Maintenance_SourceMeta", { enumerable: true, get: function () { return Maintenance_SourceMeta_1.Maintenance_SourceMeta; } });
|
|
148
150
|
var Maintenance_Source_File_1 = require("./Maintenance_Source_File");
|
|
149
151
|
Object.defineProperty(exports, "Maintenance_Source_File", { enumerable: true, get: function () { return Maintenance_Source_File_1.Maintenance_Source_File; } });
|
|
150
152
|
var Maintenance_Ticket_1 = require("./Maintenance_Ticket");
|