@sprucelabs/spruce-calendar-components 25.6.4 → 25.6.6
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/build/__tests__/support/CalendarToolBeltStateMachineTestFactory.d.ts +7 -1
- package/build/__tests__/support/CalendarToolBeltStateMachineTestFactory.js +12 -8
- package/build/__tests__/support/SpyEventManager.d.ts +2 -1
- package/build/__tests__/support/SpyEventManager.js +3 -0
- package/build/calendar/CalendarEventManager.d.ts +10 -2
- package/build/calendar/CalendarEventManager.js +71 -14
- package/build/esm/__tests__/support/CalendarToolBeltStateMachineTestFactory.d.ts +7 -1
- package/build/esm/__tests__/support/CalendarToolBeltStateMachineTestFactory.js +12 -8
- package/build/esm/__tests__/support/SpyEventManager.d.ts +2 -1
- package/build/esm/__tests__/support/SpyEventManager.js +3 -0
- package/build/esm/calendar/CalendarEventManager.d.ts +10 -2
- package/build/esm/calendar/CalendarEventManager.js +91 -26
- package/build/esm/skillViewControllers/Root.svc.js +1 -0
- package/build/esm/stores/isEqual.d.ts +1 -0
- package/build/esm/stores/isEqual.js +29 -0
- package/build/esm/toolBelt/states/AbstractCalendarEventToolBeltState.js +1 -1
- package/build/skillViewControllers/Root.svc.js +1 -0
- package/build/stores/isEqual.d.ts +1 -0
- package/build/stores/isEqual.js +32 -0
- package/build/toolBelt/states/AbstractCalendarEventToolBeltState.js +1 -1
- package/package.json +5 -1
|
@@ -2,11 +2,17 @@ import { SpruceSchemas } from '@sprucelabs/calendar-utils';
|
|
|
2
2
|
import { ToolBeltViewController } from '@sprucelabs/heartwood-view-controllers';
|
|
3
3
|
import { ViewFixture } from '@sprucelabs/spruce-test-fixtures';
|
|
4
4
|
import CalendarViewController from '../../calendar/Calendar.vc';
|
|
5
|
+
import CalendarEventManager, { CalendarEventManagerOptions, EventManagerCalendarVc } from '../../calendar/CalendarEventManager';
|
|
6
|
+
import { PeopleManagerCalendarVc } from '../../calendar/CalendarPeopleManager';
|
|
5
7
|
import { GetScheduleOptions, RemoteEventStore } from '../../stores/RemoteEventStore';
|
|
6
8
|
import { Calendar, CalendarToolBeltStateMachine, UpdateEvent } from '../../types/calendar.types';
|
|
7
9
|
import SpyEventManager from './SpyEventManager';
|
|
8
10
|
export default class CalendarToolBeltStateMachineTestFactory {
|
|
9
|
-
static StateMachine(views: ViewFixture
|
|
11
|
+
static StateMachine(views: ViewFixture, options?: {
|
|
12
|
+
calendarVc?: EventManagerCalendarVc & PeopleManagerCalendarVc;
|
|
13
|
+
shouldUpdateCalendarOnContextUpdates?: boolean;
|
|
14
|
+
EventManagerClass?: new (options: CalendarEventManagerOptions) => CalendarEventManager;
|
|
15
|
+
}): Promise<{
|
|
10
16
|
stateMachine: CalendarToolBeltStateMachine;
|
|
11
17
|
toolBeltVc: ToolBeltViewController;
|
|
12
18
|
calendarVc: CalendarViewController;
|
|
@@ -14,7 +14,8 @@ const draftGenerator_1 = __importDefault(require("../../utilities/draftGenerator
|
|
|
14
14
|
const SpyEventManager_1 = __importDefault(require("./SpyEventManager"));
|
|
15
15
|
const SpyPeopleManager_1 = __importDefault(require("./SpyPeopleManager"));
|
|
16
16
|
class CalendarToolBeltStateMachineTestFactory {
|
|
17
|
-
static async StateMachine(views) {
|
|
17
|
+
static async StateMachine(views, options) {
|
|
18
|
+
const { EventManagerClass, calendarVc: passedCalendarVc, shouldUpdateCalendarOnContextUpdates = true, } = options !== null && options !== void 0 ? options : {};
|
|
18
19
|
const factory = views.getFactory();
|
|
19
20
|
if (!factory.hasController('calendar.calendar')) {
|
|
20
21
|
factory.mixinControllers({
|
|
@@ -24,7 +25,7 @@ class CalendarToolBeltStateMachineTestFactory {
|
|
|
24
25
|
}
|
|
25
26
|
const toolBeltVc = views.Controller('toolBelt', {});
|
|
26
27
|
const event = heartwood_view_controllers_1.calendarSeeder.generateEventValues();
|
|
27
|
-
const calendarVc = views.Controller('calendar.calendar', {
|
|
28
|
+
const calendarVc = passedCalendarVc !== null && passedCalendarVc !== void 0 ? passedCalendarVc : views.Controller('calendar.calendar', {
|
|
28
29
|
onAddDraftEvent: () => { },
|
|
29
30
|
onEventSwapped(draft, saved) {
|
|
30
31
|
return events.silentlySwapEvent(draft.id, saved);
|
|
@@ -35,13 +36,12 @@ class CalendarToolBeltStateMachineTestFactory {
|
|
|
35
36
|
vcFactory: views.getFactory(),
|
|
36
37
|
toolBeltVc,
|
|
37
38
|
connectToApi: async () => spruce_test_fixtures_1.fake.getClient(),
|
|
38
|
-
context: Object.assign(Object.assign({}, views.getRouter().buildLoadOptions()), { event,
|
|
39
|
-
calendarVc, cancelEvent: () => { } }),
|
|
39
|
+
context: Object.assign(Object.assign({}, views.getRouter().buildLoadOptions()), { event, calendarVc: calendarVc, cancelEvent: () => { } }),
|
|
40
40
|
});
|
|
41
41
|
const connectToApi = async () => spruce_test_fixtures_1.fake.getClient();
|
|
42
42
|
const preferences = new FakeRemotePreferences({ connectToApi });
|
|
43
43
|
const remoteEventsStore = new FakeRemoteEventStore();
|
|
44
|
-
const events = new SpyEventManager_1.default({
|
|
44
|
+
const events = new (EventManagerClass !== null && EventManagerClass !== void 0 ? EventManagerClass : SpyEventManager_1.default)({
|
|
45
45
|
calendarVc,
|
|
46
46
|
sm,
|
|
47
47
|
dates: calendar_utils_1.dateUtil,
|
|
@@ -63,9 +63,13 @@ class CalendarToolBeltStateMachineTestFactory {
|
|
|
63
63
|
getVisibleEvents: () => [],
|
|
64
64
|
});
|
|
65
65
|
await sm.updateContext({ events, people });
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
if (shouldUpdateCalendarOnContextUpdates) {
|
|
67
|
+
// await sm.on('did-update-context', () => {
|
|
68
|
+
// calendarVc.updateEvent(event.id, {
|
|
69
|
+
// ...sm.getContext().event,
|
|
70
|
+
// })
|
|
71
|
+
// })
|
|
72
|
+
}
|
|
69
73
|
//@ts-ignore
|
|
70
74
|
return { stateMachine: sm, toolBeltVc, calendarVc, events };
|
|
71
75
|
}
|
|
@@ -7,7 +7,8 @@ export default class SpyEventManager extends CalendarEventManager {
|
|
|
7
7
|
wereShiftsRefreshed: boolean;
|
|
8
8
|
getShouldIgnoreNextContextUpdate(): boolean;
|
|
9
9
|
constructor(options: SpyEventManagerOptions);
|
|
10
|
-
|
|
10
|
+
refreshShifts(): void;
|
|
11
|
+
generateShifts(): import("@sprucelabs/spruce-core-schemas").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CalendarShift[];
|
|
11
12
|
getRemoteEventsStore(): SpyRemoteEventStore;
|
|
12
13
|
getStateMachine(): import("../../types/calendar.types").CalendarToolBeltStateMachine<CalendarToolBeltContext>;
|
|
13
14
|
getPreferences(): SpyRemotePreferencesStore;
|
|
@@ -20,14 +20,19 @@ export default class CalendarEventManager {
|
|
|
20
20
|
protected shouldUpdateAllEventsGoingForward?: boolean;
|
|
21
21
|
protected prefs: RemotePreferencesStore;
|
|
22
22
|
private calendars;
|
|
23
|
-
private shouldUpdateContextOnNextSave;
|
|
24
23
|
private isLoaded;
|
|
25
24
|
protected updateContext?: UpdateCalendarToolBeltContextHandler<CalendarToolBeltContext>;
|
|
25
|
+
private updateOperations;
|
|
26
|
+
private isRunningUpdateQueue;
|
|
27
|
+
private updateQueuePromise?;
|
|
26
28
|
protected get calendarIds(): string[];
|
|
27
29
|
protected get visibleCalendarIds(): string[];
|
|
28
30
|
constructor(options: CalendarEventManagerOptions);
|
|
29
31
|
replaceEventsInRange(events: CalendarEvent[], startMs: number, endMs: number): void;
|
|
30
32
|
protected refreshShifts(): void;
|
|
33
|
+
private doShiftsMatchWhatIsInCalendar;
|
|
34
|
+
private generateShiftKeys;
|
|
35
|
+
protected generateShifts(): import("@sprucelabs/calendar-utils").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CalendarShift[];
|
|
31
36
|
private isCalendarSelected;
|
|
32
37
|
private doesCalenderExist;
|
|
33
38
|
getEvents(): CalendarEvent[];
|
|
@@ -49,6 +54,9 @@ export default class CalendarEventManager {
|
|
|
49
54
|
makeCalendarVisible(calendarId: string): Promise<void>;
|
|
50
55
|
makeCalendarHidden(calendarId: string): Promise<void>;
|
|
51
56
|
updateEvent(id: string, updates: UpdateEventOptions): void;
|
|
57
|
+
waitForPendingOperations(): Promise<void>;
|
|
58
|
+
private startUpdateQueue;
|
|
59
|
+
private _updateEvent;
|
|
52
60
|
private calculateDifferences;
|
|
53
61
|
loadEvents(startDate: number, endDate: number, peopleIds: string[]): Promise<import("@sprucelabs/calendar-utils").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CalendarEvent[]>;
|
|
54
62
|
setCalendarVisibility(calendarId: string, shouldBeVisible: boolean): Promise<void>;
|
|
@@ -95,7 +103,7 @@ export default class CalendarEventManager {
|
|
|
95
103
|
setCurrentDate(dateMs: number): Promise<void>;
|
|
96
104
|
private handleDidUpdateContext;
|
|
97
105
|
protected saveEvent(event: SavedEvent): Promise<void>;
|
|
98
|
-
private
|
|
106
|
+
private clearRepeatingStrategyOptions;
|
|
99
107
|
getIsLoaded(): boolean;
|
|
100
108
|
hasEvent(id: string): boolean;
|
|
101
109
|
optionallyAskForUpdateRepeatingStrategy(event: UpdateEvent, action?: RepeatingUpdateAction): Promise<boolean>;
|
|
@@ -34,8 +34,9 @@ class CalendarEventManager {
|
|
|
34
34
|
this.hasVcForEventTypeBeenLoaded = {};
|
|
35
35
|
this.shouldIgnoreNextContextUpdate = false;
|
|
36
36
|
this.calendars = [];
|
|
37
|
-
this.shouldUpdateContextOnNextSave = true;
|
|
38
37
|
this.isLoaded = false;
|
|
38
|
+
this.updateOperations = [];
|
|
39
|
+
this.isRunningUpdateQueue = false;
|
|
39
40
|
const { calendarVc, events, remoteVc, sm, askForUpdateStrategy, preferences, } = (0, schema_1.assertOptions)(options, [
|
|
40
41
|
'calendarVc',
|
|
41
42
|
'events',
|
|
@@ -60,9 +61,29 @@ class CalendarEventManager {
|
|
|
60
61
|
this.refreshShifts();
|
|
61
62
|
}
|
|
62
63
|
refreshShifts() {
|
|
64
|
+
const shifts = this.generateShifts();
|
|
65
|
+
const areSame = this.doShiftsMatchWhatIsInCalendar(shifts);
|
|
66
|
+
if (areSame) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
this.calendarVc.setShifts([...shifts]);
|
|
70
|
+
}
|
|
71
|
+
doShiftsMatchWhatIsInCalendar(shifts) {
|
|
72
|
+
var _a;
|
|
73
|
+
const currentShifts = this.generateShiftKeys((_a = this.calendarVc.getShifts()) !== null && _a !== void 0 ? _a : []);
|
|
74
|
+
const newShifts = this.generateShiftKeys(shifts);
|
|
75
|
+
const areShiftsTheSame = newShifts === currentShifts;
|
|
76
|
+
return areShiftsTheSame;
|
|
77
|
+
}
|
|
78
|
+
generateShiftKeys(shifts) {
|
|
79
|
+
return shifts
|
|
80
|
+
.map((s) => `${s.id}-${s.startDateTimeMs}-${s.endDateTimeMs}`)
|
|
81
|
+
.join('-');
|
|
82
|
+
}
|
|
83
|
+
generateShifts() {
|
|
63
84
|
const inclusiveEvents = this.allEvents.filter((e) => this.inclusiveCalendarIds.indexOf(e.calendarId) > -1);
|
|
64
85
|
const shifts = calendarShiftGenerator_1.default.generateFromEvents(inclusiveEvents);
|
|
65
|
-
|
|
86
|
+
return shifts;
|
|
66
87
|
}
|
|
67
88
|
isCalendarSelected(calendarId) {
|
|
68
89
|
return this.visibleCalendarIds.indexOf(calendarId) > -1;
|
|
@@ -159,7 +180,7 @@ class CalendarEventManager {
|
|
|
159
180
|
console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
|
|
160
181
|
this.calendarVc.addEvent(Object.assign(Object.assign({}, event), { error: err }));
|
|
161
182
|
}
|
|
162
|
-
this.
|
|
183
|
+
this.clearRepeatingStrategyOptions();
|
|
163
184
|
}
|
|
164
185
|
async makeCalendarVisible(calendarId) {
|
|
165
186
|
this.assertValidCalendarId(calendarId);
|
|
@@ -176,27 +197,54 @@ class CalendarEventManager {
|
|
|
176
197
|
await this.prefs.setVisibleCalendarIds(visibleCalendarIds);
|
|
177
198
|
}
|
|
178
199
|
updateEvent(id, updates) {
|
|
179
|
-
|
|
200
|
+
const operation = new UpdateOperation({
|
|
201
|
+
id,
|
|
202
|
+
updates,
|
|
203
|
+
onComplete: this._updateEvent.bind(this),
|
|
204
|
+
});
|
|
205
|
+
this.updateOperations.push(operation);
|
|
206
|
+
this.clearRepeatingStrategyOptions();
|
|
207
|
+
this.updateQueuePromise = this.startUpdateQueue();
|
|
208
|
+
}
|
|
209
|
+
async waitForPendingOperations() {
|
|
210
|
+
await this.updateQueuePromise;
|
|
211
|
+
}
|
|
212
|
+
async startUpdateQueue() {
|
|
213
|
+
if (this.isRunningUpdateQueue) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this.isRunningUpdateQueue = true;
|
|
217
|
+
let next;
|
|
218
|
+
while ((next = this.updateOperations.shift())) {
|
|
219
|
+
await next.execute();
|
|
220
|
+
}
|
|
221
|
+
this.isRunningUpdateQueue = false;
|
|
222
|
+
}
|
|
223
|
+
async _updateEvent(id, updates) {
|
|
224
|
+
var _a, _b;
|
|
180
225
|
const { shouldPersist } = updates, rest = __rest(updates, ["shouldPersist"]);
|
|
181
226
|
const { isTheSame, isTheSameWithoutBusy } = this.calculateDifferences(id, updates);
|
|
182
227
|
if (isTheSame) {
|
|
183
228
|
return;
|
|
184
229
|
}
|
|
185
|
-
|
|
230
|
+
try {
|
|
231
|
+
this.calendarVc.updateEvent(id, Object.assign(Object.assign({}, rest), { shouldPersist }));
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
186
237
|
const idx = this.allEvents.findIndex((e) => e.id === id);
|
|
187
238
|
this.allEvents[idx] = Object.assign(Object.assign({}, this.allEvents[idx]), rest);
|
|
188
239
|
if (isTheSameWithoutBusy) {
|
|
189
240
|
return;
|
|
190
241
|
}
|
|
191
242
|
this.refreshShifts();
|
|
192
|
-
if (this.
|
|
193
|
-
((_a = this.sm.getContext().event) === null || _a === void 0 ? void 0 : _a.id) === id) {
|
|
243
|
+
if (((_b = this.sm.getContext().event) === null || _b === void 0 ? void 0 : _b.id) === id) {
|
|
194
244
|
this.shouldIgnoreNextContextUpdate = true;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
});
|
|
245
|
+
await this.updateEventInContext(rest);
|
|
246
|
+
this.shouldIgnoreNextContextUpdate = false;
|
|
198
247
|
}
|
|
199
|
-
this.shouldUpdateContextOnNextSave = true;
|
|
200
248
|
}
|
|
201
249
|
calculateDifferences(id, updates) {
|
|
202
250
|
const match = this.allEvents.find((e) => e.id === id);
|
|
@@ -335,7 +383,6 @@ class CalendarEventManager {
|
|
|
335
383
|
}
|
|
336
384
|
const { event } = this.sm.getContext();
|
|
337
385
|
if (event === null || event === void 0 ? void 0 : event.id) {
|
|
338
|
-
this.shouldUpdateContextOnNextSave = false;
|
|
339
386
|
await this.saveEvent(event);
|
|
340
387
|
}
|
|
341
388
|
}
|
|
@@ -347,9 +394,8 @@ class CalendarEventManager {
|
|
|
347
394
|
catch (err) {
|
|
348
395
|
console.error('Updating event in context from root failed because:\n\n', err);
|
|
349
396
|
}
|
|
350
|
-
this.clearPersistRepeatingOptions();
|
|
351
397
|
}
|
|
352
|
-
|
|
398
|
+
clearRepeatingStrategyOptions() {
|
|
353
399
|
this.dateToUpdate = undefined;
|
|
354
400
|
this.shouldUpdateAllEventsGoingForward = undefined;
|
|
355
401
|
}
|
|
@@ -387,3 +433,14 @@ class CalendarEventManager {
|
|
|
387
433
|
}
|
|
388
434
|
}
|
|
389
435
|
exports.default = CalendarEventManager;
|
|
436
|
+
class UpdateOperation {
|
|
437
|
+
constructor(options) {
|
|
438
|
+
const { id, updates, onComplete } = options;
|
|
439
|
+
this.id = id;
|
|
440
|
+
this.updates = updates;
|
|
441
|
+
this.onComplete = onComplete;
|
|
442
|
+
}
|
|
443
|
+
async execute() {
|
|
444
|
+
await this.onComplete(this.id, this.updates);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
@@ -2,11 +2,17 @@ import { SpruceSchemas } from '@sprucelabs/calendar-utils';
|
|
|
2
2
|
import { ToolBeltViewController } from '@sprucelabs/heartwood-view-controllers';
|
|
3
3
|
import { ViewFixture } from '@sprucelabs/spruce-test-fixtures';
|
|
4
4
|
import CalendarViewController from '../../calendar/Calendar.vc';
|
|
5
|
+
import CalendarEventManager, { CalendarEventManagerOptions, EventManagerCalendarVc } from '../../calendar/CalendarEventManager';
|
|
6
|
+
import { PeopleManagerCalendarVc } from '../../calendar/CalendarPeopleManager';
|
|
5
7
|
import { GetScheduleOptions, RemoteEventStore } from '../../stores/RemoteEventStore';
|
|
6
8
|
import { Calendar, CalendarToolBeltStateMachine, UpdateEvent } from '../../types/calendar.types';
|
|
7
9
|
import SpyEventManager from './SpyEventManager';
|
|
8
10
|
export default class CalendarToolBeltStateMachineTestFactory {
|
|
9
|
-
static StateMachine(views: ViewFixture
|
|
11
|
+
static StateMachine(views: ViewFixture, options?: {
|
|
12
|
+
calendarVc?: EventManagerCalendarVc & PeopleManagerCalendarVc;
|
|
13
|
+
shouldUpdateCalendarOnContextUpdates?: boolean;
|
|
14
|
+
EventManagerClass?: new (options: CalendarEventManagerOptions) => CalendarEventManager;
|
|
15
|
+
}): Promise<{
|
|
10
16
|
stateMachine: CalendarToolBeltStateMachine;
|
|
11
17
|
toolBeltVc: ToolBeltViewController;
|
|
12
18
|
calendarVc: CalendarViewController;
|
|
@@ -17,8 +17,9 @@ import draftEventGenerator from '../../utilities/draftGenerator.js';
|
|
|
17
17
|
import SpyEventManager from './SpyEventManager.js';
|
|
18
18
|
import SpyPeopleManager from './SpyPeopleManager.js';
|
|
19
19
|
export default class CalendarToolBeltStateMachineTestFactory {
|
|
20
|
-
static StateMachine(views) {
|
|
20
|
+
static StateMachine(views, options) {
|
|
21
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
const { EventManagerClass, calendarVc: passedCalendarVc, shouldUpdateCalendarOnContextUpdates = true, } = options !== null && options !== void 0 ? options : {};
|
|
22
23
|
const factory = views.getFactory();
|
|
23
24
|
if (!factory.hasController('calendar.calendar')) {
|
|
24
25
|
factory.mixinControllers({
|
|
@@ -28,7 +29,7 @@ export default class CalendarToolBeltStateMachineTestFactory {
|
|
|
28
29
|
}
|
|
29
30
|
const toolBeltVc = views.Controller('toolBelt', {});
|
|
30
31
|
const event = calendarSeeder.generateEventValues();
|
|
31
|
-
const calendarVc = views.Controller('calendar.calendar', {
|
|
32
|
+
const calendarVc = passedCalendarVc !== null && passedCalendarVc !== void 0 ? passedCalendarVc : views.Controller('calendar.calendar', {
|
|
32
33
|
onAddDraftEvent: () => { },
|
|
33
34
|
onEventSwapped(draft, saved) {
|
|
34
35
|
return events.silentlySwapEvent(draft.id, saved);
|
|
@@ -39,13 +40,12 @@ export default class CalendarToolBeltStateMachineTestFactory {
|
|
|
39
40
|
vcFactory: views.getFactory(),
|
|
40
41
|
toolBeltVc,
|
|
41
42
|
connectToApi: () => __awaiter(this, void 0, void 0, function* () { return fake.getClient(); }),
|
|
42
|
-
context: Object.assign(Object.assign({}, views.getRouter().buildLoadOptions()), { event,
|
|
43
|
-
calendarVc, cancelEvent: () => { } }),
|
|
43
|
+
context: Object.assign(Object.assign({}, views.getRouter().buildLoadOptions()), { event, calendarVc: calendarVc, cancelEvent: () => { } }),
|
|
44
44
|
});
|
|
45
45
|
const connectToApi = () => __awaiter(this, void 0, void 0, function* () { return fake.getClient(); });
|
|
46
46
|
const preferences = new FakeRemotePreferences({ connectToApi });
|
|
47
47
|
const remoteEventsStore = new FakeRemoteEventStore();
|
|
48
|
-
const events = new SpyEventManager({
|
|
48
|
+
const events = new (EventManagerClass !== null && EventManagerClass !== void 0 ? EventManagerClass : SpyEventManager)({
|
|
49
49
|
calendarVc,
|
|
50
50
|
sm,
|
|
51
51
|
dates: dateUtil,
|
|
@@ -67,9 +67,13 @@ export default class CalendarToolBeltStateMachineTestFactory {
|
|
|
67
67
|
getVisibleEvents: () => [],
|
|
68
68
|
});
|
|
69
69
|
yield sm.updateContext({ events, people });
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
if (shouldUpdateCalendarOnContextUpdates) {
|
|
71
|
+
// await sm.on('did-update-context', () => {
|
|
72
|
+
// calendarVc.updateEvent(event.id, {
|
|
73
|
+
// ...sm.getContext().event,
|
|
74
|
+
// })
|
|
75
|
+
// })
|
|
76
|
+
}
|
|
73
77
|
//@ts-ignore
|
|
74
78
|
return { stateMachine: sm, toolBeltVc, calendarVc, events };
|
|
75
79
|
});
|
|
@@ -7,7 +7,8 @@ export default class SpyEventManager extends CalendarEventManager {
|
|
|
7
7
|
wereShiftsRefreshed: boolean;
|
|
8
8
|
getShouldIgnoreNextContextUpdate(): boolean;
|
|
9
9
|
constructor(options: SpyEventManagerOptions);
|
|
10
|
-
|
|
10
|
+
refreshShifts(): void;
|
|
11
|
+
generateShifts(): import("@sprucelabs/spruce-core-schemas").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CalendarShift[];
|
|
11
12
|
getRemoteEventsStore(): SpyRemoteEventStore;
|
|
12
13
|
getStateMachine(): import("../../types/calendar.types").CalendarToolBeltStateMachine<CalendarToolBeltContext>;
|
|
13
14
|
getPreferences(): SpyRemotePreferencesStore;
|
|
@@ -20,6 +20,9 @@ export default class SpyEventManager extends CalendarEventManager {
|
|
|
20
20
|
this.wereShiftsRefreshed = true;
|
|
21
21
|
return super.refreshShifts();
|
|
22
22
|
}
|
|
23
|
+
generateShifts() {
|
|
24
|
+
return super.generateShifts();
|
|
25
|
+
}
|
|
23
26
|
getRemoteEventsStore() {
|
|
24
27
|
return this.events;
|
|
25
28
|
}
|
|
@@ -20,14 +20,19 @@ export default class CalendarEventManager {
|
|
|
20
20
|
protected shouldUpdateAllEventsGoingForward?: boolean;
|
|
21
21
|
protected prefs: RemotePreferencesStore;
|
|
22
22
|
private calendars;
|
|
23
|
-
private shouldUpdateContextOnNextSave;
|
|
24
23
|
private isLoaded;
|
|
25
24
|
protected updateContext?: UpdateCalendarToolBeltContextHandler<CalendarToolBeltContext>;
|
|
25
|
+
private updateOperations;
|
|
26
|
+
private isRunningUpdateQueue;
|
|
27
|
+
private updateQueuePromise?;
|
|
26
28
|
protected get calendarIds(): string[];
|
|
27
29
|
protected get visibleCalendarIds(): string[];
|
|
28
30
|
constructor(options: CalendarEventManagerOptions);
|
|
29
31
|
replaceEventsInRange(events: CalendarEvent[], startMs: number, endMs: number): void;
|
|
30
32
|
protected refreshShifts(): void;
|
|
33
|
+
private doShiftsMatchWhatIsInCalendar;
|
|
34
|
+
private generateShiftKeys;
|
|
35
|
+
protected generateShifts(): import("@sprucelabs/calendar-utils").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CalendarShift[];
|
|
31
36
|
private isCalendarSelected;
|
|
32
37
|
private doesCalenderExist;
|
|
33
38
|
getEvents(): CalendarEvent[];
|
|
@@ -49,6 +54,9 @@ export default class CalendarEventManager {
|
|
|
49
54
|
makeCalendarVisible(calendarId: string): Promise<void>;
|
|
50
55
|
makeCalendarHidden(calendarId: string): Promise<void>;
|
|
51
56
|
updateEvent(id: string, updates: UpdateEventOptions): void;
|
|
57
|
+
waitForPendingOperations(): Promise<void>;
|
|
58
|
+
private startUpdateQueue;
|
|
59
|
+
private _updateEvent;
|
|
52
60
|
private calculateDifferences;
|
|
53
61
|
loadEvents(startDate: number, endDate: number, peopleIds: string[]): Promise<import("@sprucelabs/calendar-utils").SpruceSchemas.HeartwoodViewControllers.v2021_02_11.CalendarEvent[]>;
|
|
54
62
|
setCalendarVisibility(calendarId: string, shouldBeVisible: boolean): Promise<void>;
|
|
@@ -95,7 +103,7 @@ export default class CalendarEventManager {
|
|
|
95
103
|
setCurrentDate(dateMs: number): Promise<void>;
|
|
96
104
|
private handleDidUpdateContext;
|
|
97
105
|
protected saveEvent(event: SavedEvent): Promise<void>;
|
|
98
|
-
private
|
|
106
|
+
private clearRepeatingStrategyOptions;
|
|
99
107
|
getIsLoaded(): boolean;
|
|
100
108
|
hasEvent(id: string): boolean;
|
|
101
109
|
optionallyAskForUpdateRepeatingStrategy(event: UpdateEvent, action?: RepeatingUpdateAction): Promise<boolean>;
|
|
@@ -38,8 +38,9 @@ export default class CalendarEventManager {
|
|
|
38
38
|
this.hasVcForEventTypeBeenLoaded = {};
|
|
39
39
|
this.shouldIgnoreNextContextUpdate = false;
|
|
40
40
|
this.calendars = [];
|
|
41
|
-
this.shouldUpdateContextOnNextSave = true;
|
|
42
41
|
this.isLoaded = false;
|
|
42
|
+
this.updateOperations = [];
|
|
43
|
+
this.isRunningUpdateQueue = false;
|
|
43
44
|
const { calendarVc, events, remoteVc, sm, askForUpdateStrategy, preferences, } = assertOptions(options, [
|
|
44
45
|
'calendarVc',
|
|
45
46
|
'events',
|
|
@@ -64,9 +65,29 @@ export default class CalendarEventManager {
|
|
|
64
65
|
this.refreshShifts();
|
|
65
66
|
}
|
|
66
67
|
refreshShifts() {
|
|
68
|
+
const shifts = this.generateShifts();
|
|
69
|
+
const areSame = this.doShiftsMatchWhatIsInCalendar(shifts);
|
|
70
|
+
if (areSame) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this.calendarVc.setShifts([...shifts]);
|
|
74
|
+
}
|
|
75
|
+
doShiftsMatchWhatIsInCalendar(shifts) {
|
|
76
|
+
var _a;
|
|
77
|
+
const currentShifts = this.generateShiftKeys((_a = this.calendarVc.getShifts()) !== null && _a !== void 0 ? _a : []);
|
|
78
|
+
const newShifts = this.generateShiftKeys(shifts);
|
|
79
|
+
const areShiftsTheSame = newShifts === currentShifts;
|
|
80
|
+
return areShiftsTheSame;
|
|
81
|
+
}
|
|
82
|
+
generateShiftKeys(shifts) {
|
|
83
|
+
return shifts
|
|
84
|
+
.map((s) => `${s.id}-${s.startDateTimeMs}-${s.endDateTimeMs}`)
|
|
85
|
+
.join('-');
|
|
86
|
+
}
|
|
87
|
+
generateShifts() {
|
|
67
88
|
const inclusiveEvents = this.allEvents.filter((e) => this.inclusiveCalendarIds.indexOf(e.calendarId) > -1);
|
|
68
89
|
const shifts = calendarShiftGenerator.generateFromEvents(inclusiveEvents);
|
|
69
|
-
|
|
90
|
+
return shifts;
|
|
70
91
|
}
|
|
71
92
|
isCalendarSelected(calendarId) {
|
|
72
93
|
return this.visibleCalendarIds.indexOf(calendarId) > -1;
|
|
@@ -174,7 +195,7 @@ export default class CalendarEventManager {
|
|
|
174
195
|
console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
|
|
175
196
|
this.calendarVc.addEvent(Object.assign(Object.assign({}, event), { error: err }));
|
|
176
197
|
}
|
|
177
|
-
this.
|
|
198
|
+
this.clearRepeatingStrategyOptions();
|
|
178
199
|
});
|
|
179
200
|
}
|
|
180
201
|
makeCalendarVisible(calendarId) {
|
|
@@ -196,27 +217,60 @@ export default class CalendarEventManager {
|
|
|
196
217
|
});
|
|
197
218
|
}
|
|
198
219
|
updateEvent(id, updates) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
this.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
220
|
+
const operation = new UpdateOperation({
|
|
221
|
+
id,
|
|
222
|
+
updates,
|
|
223
|
+
onComplete: this._updateEvent.bind(this),
|
|
224
|
+
});
|
|
225
|
+
this.updateOperations.push(operation);
|
|
226
|
+
this.clearRepeatingStrategyOptions();
|
|
227
|
+
this.updateQueuePromise = this.startUpdateQueue();
|
|
228
|
+
}
|
|
229
|
+
waitForPendingOperations() {
|
|
230
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
231
|
+
yield this.updateQueuePromise;
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
startUpdateQueue() {
|
|
235
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
236
|
+
if (this.isRunningUpdateQueue) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
this.isRunningUpdateQueue = true;
|
|
240
|
+
let next;
|
|
241
|
+
while ((next = this.updateOperations.shift())) {
|
|
242
|
+
yield next.execute();
|
|
243
|
+
}
|
|
244
|
+
this.isRunningUpdateQueue = false;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
_updateEvent(id, updates) {
|
|
248
|
+
var _a, _b;
|
|
249
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
250
|
+
const { shouldPersist } = updates, rest = __rest(updates, ["shouldPersist"]);
|
|
251
|
+
const { isTheSame, isTheSameWithoutBusy } = this.calculateDifferences(id, updates);
|
|
252
|
+
if (isTheSame) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
this.calendarVc.updateEvent(id, Object.assign(Object.assign({}, rest), { shouldPersist }));
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
console.error((_a = err.stack) !== null && _a !== void 0 ? _a : err.message);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const idx = this.allEvents.findIndex((e) => e.id === id);
|
|
263
|
+
this.allEvents[idx] = Object.assign(Object.assign({}, this.allEvents[idx]), rest);
|
|
264
|
+
if (isTheSameWithoutBusy) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
this.refreshShifts();
|
|
268
|
+
if (((_b = this.sm.getContext().event) === null || _b === void 0 ? void 0 : _b.id) === id) {
|
|
269
|
+
this.shouldIgnoreNextContextUpdate = true;
|
|
270
|
+
yield this.updateEventInContext(rest);
|
|
216
271
|
this.shouldIgnoreNextContextUpdate = false;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
this.shouldUpdateContextOnNextSave = true;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
220
274
|
}
|
|
221
275
|
calculateDifferences(id, updates) {
|
|
222
276
|
const match = this.allEvents.find((e) => e.id === id);
|
|
@@ -378,7 +432,6 @@ export default class CalendarEventManager {
|
|
|
378
432
|
}
|
|
379
433
|
const { event } = this.sm.getContext();
|
|
380
434
|
if (event === null || event === void 0 ? void 0 : event.id) {
|
|
381
|
-
this.shouldUpdateContextOnNextSave = false;
|
|
382
435
|
yield this.saveEvent(event);
|
|
383
436
|
}
|
|
384
437
|
});
|
|
@@ -392,10 +445,9 @@ export default class CalendarEventManager {
|
|
|
392
445
|
catch (err) {
|
|
393
446
|
console.error('Updating event in context from root failed because:\n\n', err);
|
|
394
447
|
}
|
|
395
|
-
this.clearPersistRepeatingOptions();
|
|
396
448
|
});
|
|
397
449
|
}
|
|
398
|
-
|
|
450
|
+
clearRepeatingStrategyOptions() {
|
|
399
451
|
this.dateToUpdate = undefined;
|
|
400
452
|
this.shouldUpdateAllEventsGoingForward = undefined;
|
|
401
453
|
}
|
|
@@ -434,3 +486,16 @@ export default class CalendarEventManager {
|
|
|
434
486
|
});
|
|
435
487
|
}
|
|
436
488
|
}
|
|
489
|
+
class UpdateOperation {
|
|
490
|
+
constructor(options) {
|
|
491
|
+
const { id, updates, onComplete } = options;
|
|
492
|
+
this.id = id;
|
|
493
|
+
this.updates = updates;
|
|
494
|
+
this.onComplete = onComplete;
|
|
495
|
+
}
|
|
496
|
+
execute() {
|
|
497
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
498
|
+
yield this.onComplete(this.id, this.updates);
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function isEqual(a: any, b: any): boolean;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default function isEqual(a, b) {
|
|
2
|
+
if (a === b) {
|
|
3
|
+
return true;
|
|
4
|
+
}
|
|
5
|
+
if (a instanceof Date && b instanceof Date) {
|
|
6
|
+
return a.getTime() === b.getTime();
|
|
7
|
+
}
|
|
8
|
+
if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) {
|
|
9
|
+
return a === b;
|
|
10
|
+
}
|
|
11
|
+
if (a.prototype !== b.prototype) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
a = removeUndefinedAndNullFields(Object.assign({}, a));
|
|
15
|
+
b = removeUndefinedAndNullFields(Object.assign({}, b));
|
|
16
|
+
const keys = Object.keys(a);
|
|
17
|
+
if (keys.length !== Object.keys(b).length) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return keys.every((k) => isEqual(a[k], b[k]));
|
|
21
|
+
}
|
|
22
|
+
function removeUndefinedAndNullFields(obj) {
|
|
23
|
+
for (const key in obj) {
|
|
24
|
+
if (obj[key] === undefined || obj[key] === null) {
|
|
25
|
+
delete obj[key];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return obj;
|
|
29
|
+
}
|
|
@@ -36,7 +36,7 @@ export default class AbstractCalendarEventToolBeltState {
|
|
|
36
36
|
position: 'bottom',
|
|
37
37
|
});
|
|
38
38
|
this.handleDidUpdateContext = this.handleDidUpdateContext.bind(this);
|
|
39
|
-
|
|
39
|
+
void this.sm.on('did-update-context', this.handleDidUpdateContext);
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
getIsLoaded() {
|
|
@@ -150,6 +150,7 @@ class RootSkillViewController extends heartwood_view_controllers_1.AbstractSkill
|
|
|
150
150
|
this.loadEventsPromise,
|
|
151
151
|
this.sm.waitForContextUpdate(),
|
|
152
152
|
this.calendarVc.waitForPendingSaves(),
|
|
153
|
+
this.events.waitForPendingOperations(),
|
|
153
154
|
]);
|
|
154
155
|
}
|
|
155
156
|
async handleSelectCalendar(calendar) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function isEqual(a: any, b: any): boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function isEqual(a, b) {
|
|
4
|
+
if (a === b) {
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
if (a instanceof Date && b instanceof Date) {
|
|
8
|
+
return a.getTime() === b.getTime();
|
|
9
|
+
}
|
|
10
|
+
if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) {
|
|
11
|
+
return a === b;
|
|
12
|
+
}
|
|
13
|
+
if (a.prototype !== b.prototype) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
a = removeUndefinedAndNullFields(Object.assign({}, a));
|
|
17
|
+
b = removeUndefinedAndNullFields(Object.assign({}, b));
|
|
18
|
+
const keys = Object.keys(a);
|
|
19
|
+
if (keys.length !== Object.keys(b).length) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return keys.every((k) => isEqual(a[k], b[k]));
|
|
23
|
+
}
|
|
24
|
+
exports.default = isEqual;
|
|
25
|
+
function removeUndefinedAndNullFields(obj) {
|
|
26
|
+
for (const key in obj) {
|
|
27
|
+
if (obj[key] === undefined || obj[key] === null) {
|
|
28
|
+
delete obj[key];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return obj;
|
|
32
|
+
}
|
|
@@ -31,7 +31,7 @@ class AbstractCalendarEventToolBeltState {
|
|
|
31
31
|
position: 'bottom',
|
|
32
32
|
});
|
|
33
33
|
this.handleDidUpdateContext = this.handleDidUpdateContext.bind(this);
|
|
34
|
-
|
|
34
|
+
void this.sm.on('did-update-context', this.handleDidUpdateContext);
|
|
35
35
|
}
|
|
36
36
|
getIsLoaded() {
|
|
37
37
|
return this.isLoaded;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sprucelabs/spruce-calendar-components",
|
|
3
3
|
"description": "Calendar components for working with calendars and Sprucebot.",
|
|
4
|
-
"version": "25.6.
|
|
4
|
+
"version": "25.6.6",
|
|
5
5
|
"skill": {
|
|
6
6
|
"namespace": "calendar"
|
|
7
7
|
},
|
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
"build/constants.d.ts",
|
|
63
63
|
"build/esm/constants.js",
|
|
64
64
|
"build/esm/constants.d.ts",
|
|
65
|
+
"build/stores/isEqual.js",
|
|
66
|
+
"build/stores/isEqual.d.ts",
|
|
67
|
+
"build/esm/stores/isEqual.js",
|
|
68
|
+
"build/esm/stores/isEqual.d.ts",
|
|
65
69
|
"build/index-components.js",
|
|
66
70
|
"build/index-components.d.ts",
|
|
67
71
|
"build/esm/index-components.js",
|