@tiba-spark/client-shared-lib 26.3.0-206 → 26.3.0-219
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/esm2022/libraries/modules/facility/facility.service.mjs +13 -5
- package/esm2022/libraries/modules/facility/facility.state.mjs +67 -22
- package/esm2022/libraries/modules/park-manager/park-manager.state.mjs +9 -2
- package/esm2022/libraries/services/company.service.mjs +23 -3
- package/fesm2022/tiba-spark-client-shared-lib.mjs +108 -28
- package/fesm2022/tiba-spark-client-shared-lib.mjs.map +1 -1
- package/libraries/modules/facility/facility.service.d.ts.map +1 -1
- package/libraries/modules/facility/facility.state.d.ts.map +1 -1
- package/libraries/modules/park-manager/park-manager.state.d.ts.map +1 -1
- package/libraries/services/company.service.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -123416,7 +123416,12 @@ let FacilityState = class FacilityState {
|
|
|
123416
123416
|
}
|
|
123417
123417
|
onZoneChangedAction(ctx, { zone, parkId }) {
|
|
123418
123418
|
const selected = ctx.getState().selected;
|
|
123419
|
-
|
|
123419
|
+
// SPRK3-14984: ZoneChangedAction is a SignalR push, so it arrives regardless of
|
|
123420
|
+
// whether a park is selected or its zones are loaded yet.
|
|
123421
|
+
if (!selected?.zones) {
|
|
123422
|
+
return;
|
|
123423
|
+
}
|
|
123424
|
+
const zoneIndex = selected.zones.findIndex(item => item.id === zone.id && item.parkID === parkId);
|
|
123420
123425
|
zone.occupancy = zone.monthliesOccupancy + zone.transientsOccupancy;
|
|
123421
123426
|
zone.vacancy = zone.capacity - zone.occupancy;
|
|
123422
123427
|
switch (zone.rulesMode) {
|
|
@@ -123441,7 +123446,13 @@ let FacilityState = class FacilityState {
|
|
|
123441
123446
|
selected.zones = clone(selected.zones);
|
|
123442
123447
|
const facilityDictionary = ctx.getState().dictionary;
|
|
123443
123448
|
const guid = ctx.getState().guid;
|
|
123444
|
-
|
|
123449
|
+
// SPRK3-14984 (Sentry JAVASCRIPT-ANGULAR-35): dictionary defaults to {} and is
|
|
123450
|
+
// always truthy, but dictionary[guid] is undefined until the tenant is hydrated
|
|
123451
|
+
// and the park may not be under it. The selected/zones slices are still correct.
|
|
123452
|
+
const storedFacility = facilityDictionary[guid]?.[selected.id];
|
|
123453
|
+
if (storedFacility) {
|
|
123454
|
+
storedFacility.zones = selected.zones;
|
|
123455
|
+
}
|
|
123445
123456
|
ctx.patchState({
|
|
123446
123457
|
dictionary: facilityDictionary,
|
|
123447
123458
|
selected,
|
|
@@ -123492,9 +123503,17 @@ let FacilityState = class FacilityState {
|
|
|
123492
123503
|
servicesRunningStatusDictionary[guid] = servicesRunningStatus;
|
|
123493
123504
|
ctx.patchState({ servicesRunningStatusDictionary });
|
|
123494
123505
|
// Updating ParkConnectionStatus for parks
|
|
123495
|
-
if (facilityDictionary)
|
|
123506
|
+
// SPRK3-14836 (Sentry JAVASCRIPT-ANGULAR-1R): the old `if (facilityDictionary)`
|
|
123507
|
+
// guarded the outer object, which defaults to {} and always passes, while
|
|
123508
|
+
// Object.values(facilityDictionary[guid]) threw for an unhydrated tenant. The
|
|
123509
|
+
// connectionStatusDictionary slice needs its own per-guid bucket for the same reason.
|
|
123510
|
+
const parksForGuid = facilityDictionary?.[guid];
|
|
123511
|
+
if (parksForGuid) {
|
|
123496
123512
|
const connectionStatusDictionary = cloneDeep(ctx.getState().connectionStatusDictionary);
|
|
123497
|
-
|
|
123513
|
+
if (!connectionStatusDictionary[guid]) {
|
|
123514
|
+
connectionStatusDictionary[guid] = {};
|
|
123515
|
+
}
|
|
123516
|
+
const facilities = Object.values(parksForGuid);
|
|
123498
123517
|
for (const facility of facilities) {
|
|
123499
123518
|
connectionStatusDictionary[guid][facility.id] = this.globalErrorService.getParkConnectionStatus(guid, facility, servicesRunningStatus, facilityDictionary);
|
|
123500
123519
|
}
|
|
@@ -123518,6 +123537,9 @@ let FacilityState = class FacilityState {
|
|
|
123518
123537
|
}
|
|
123519
123538
|
// Updating ParkConnectionStatus for parks
|
|
123520
123539
|
const connectionStatusDictionary = cloneDeep(ctx.getState().connectionStatusDictionary);
|
|
123540
|
+
if (!connectionStatusDictionary[guid]) {
|
|
123541
|
+
connectionStatusDictionary[guid] = {};
|
|
123542
|
+
}
|
|
123521
123543
|
const servicesRunningStatusDictionary = ctx.getState().servicesRunningStatusDictionary;
|
|
123522
123544
|
const facilities = Object.values(facilityDictionary[guid]);
|
|
123523
123545
|
for (const facility of facilities) {
|
|
@@ -123623,7 +123645,11 @@ let FacilityState = class FacilityState {
|
|
|
123623
123645
|
}
|
|
123624
123646
|
}
|
|
123625
123647
|
onFacilityRemoteCommandExecutedAction(ctx, { facilityRemoteCommandEvent }) {
|
|
123626
|
-
|
|
123648
|
+
// The command-executed push can name a tenant/park this client has not loaded.
|
|
123649
|
+
const facility = ctx.getState().dictionary[facilityRemoteCommandEvent.guid]?.[facilityRemoteCommandEvent.parkId];
|
|
123650
|
+
if (!facility) {
|
|
123651
|
+
return;
|
|
123652
|
+
}
|
|
123627
123653
|
const operationTypeKey = FacilityRemoteCommandsLocalizationKey[FacilityRemoteCommandTypes$2[facilityRemoteCommandEvent.type]];
|
|
123628
123654
|
const config = {
|
|
123629
123655
|
messages: [{ value: facility.name, class: NotificationClass.body }],
|
|
@@ -123654,19 +123680,36 @@ let FacilityState = class FacilityState {
|
|
|
123654
123680
|
const facilityDictionary = ctx.getState().dictionary;
|
|
123655
123681
|
const nowMoment = moment();
|
|
123656
123682
|
if (facilitiesMap) {
|
|
123657
|
-
|
|
123658
|
-
|
|
123659
|
-
|
|
123660
|
-
|
|
123661
|
-
|
|
123662
|
-
|
|
123683
|
+
// Same class as the SPRK3-15108 guard in the else-branch below: neither the
|
|
123684
|
+
// incoming map nor the stored dictionary is guaranteed to hold this guid, and a
|
|
123685
|
+
// super-park map can name a child park the dictionary has not loaded.
|
|
123686
|
+
const storedParks = facilityDictionary[guid];
|
|
123687
|
+
facilitiesMap[guid]?.forEach(f => {
|
|
123688
|
+
const storedFacility = storedParks?.[f.id];
|
|
123689
|
+
if (!storedFacility) {
|
|
123690
|
+
return;
|
|
123691
|
+
}
|
|
123692
|
+
f.cloudId = storedFacility.cloudId;
|
|
123693
|
+
f.featurePermissions = storedFacility.featurePermissions;
|
|
123694
|
+
f.permissions = storedFacility.permissions;
|
|
123695
|
+
storedParks[f.id] = this.updateFacilityConnectivityFlags(storedFacility, f);
|
|
123663
123696
|
});
|
|
123664
123697
|
}
|
|
123665
123698
|
else {
|
|
123666
|
-
|
|
123667
|
-
|
|
123668
|
-
|
|
123669
|
-
|
|
123699
|
+
// SPRK3-15108: getFacility can resolve with an empty payload, and the dictionary may hold
|
|
123700
|
+
// no entry for this guid/facility yet. Either way there is nothing to merge, and the three
|
|
123701
|
+
// reads below used to throw (Sentry JAVASCRIPT-ANGULAR-3F) — the `if (facility)` guard
|
|
123702
|
+
// further down was added for the same class of crash but sits after the dereference.
|
|
123703
|
+
const storedFacility = facility ? facilityDictionary[guid]?.[facility.id] : null;
|
|
123704
|
+
if (!storedFacility) {
|
|
123705
|
+
return;
|
|
123706
|
+
}
|
|
123707
|
+
facility.cloudId = storedFacility.cloudId;
|
|
123708
|
+
facility.featurePermissions = storedFacility.featurePermissions;
|
|
123709
|
+
facility.permissions = storedFacility.permissions;
|
|
123710
|
+
// The guard above validated [facility.id]; parkId can differ for a super-park
|
|
123711
|
+
// child, in which case [parkId] holds nothing to merge from.
|
|
123712
|
+
facilityDictionary[guid][parkId] = this.updateFacilityConnectivityFlags(facilityDictionary[guid][parkId] ?? storedFacility, facility);
|
|
123670
123713
|
}
|
|
123671
123714
|
// Guard: a super-park facilities map may not contain the requested parkId
|
|
123672
123715
|
// (or the response may be empty). Skip the time-diff calc rather than
|
|
@@ -123675,7 +123718,7 @@ let FacilityState = class FacilityState {
|
|
|
123675
123718
|
clientServerDiffDictionary[guid] = this.getClientServerTimeDiff(facility, nowMoment);
|
|
123676
123719
|
this.patchDiffDictinaryToStore(ctx, clientServerDiffDictionary);
|
|
123677
123720
|
}
|
|
123678
|
-
this.patchFacilitiesToStore(ctx, facilityDictionary, facilityDictionary[guid][parkId], appModule);
|
|
123721
|
+
this.patchFacilitiesToStore(ctx, facilityDictionary, facilityDictionary[guid]?.[parkId], appModule);
|
|
123679
123722
|
}
|
|
123680
123723
|
updateFacilityConnectivityFlags(storedFacility, incomingFacility) {
|
|
123681
123724
|
const cloudDateTimeUtc = this.getCloudDateTimeUtc();
|
|
@@ -123688,7 +123731,7 @@ let FacilityState = class FacilityState {
|
|
|
123688
123731
|
ctx.patchState({
|
|
123689
123732
|
dictionary,
|
|
123690
123733
|
});
|
|
123691
|
-
if (appModule === AppModule$2.Cc) {
|
|
123734
|
+
if (appModule === AppModule$2.Cc && facility) {
|
|
123692
123735
|
const allowedActions = convertFeaturePermissionsToDictionary(facility.featurePermissions);
|
|
123693
123736
|
ctx.patchState({
|
|
123694
123737
|
selected: facility,
|
|
@@ -123716,10 +123759,12 @@ let FacilityState = class FacilityState {
|
|
|
123716
123759
|
}
|
|
123717
123760
|
updateServiceRunningStatusFlags(currentServicesRunningStatus, newServicesRunningStatus) {
|
|
123718
123761
|
const cloudDateTimeUtc = this.getCloudDateTimeUtc();
|
|
123719
|
-
|
|
123720
|
-
|
|
123721
|
-
newServicesRunningStatus.
|
|
123722
|
-
newServicesRunningStatus.
|
|
123762
|
+
// The caller passes servicesRunningStatusDictionary[guid], which is absent on the
|
|
123763
|
+
// first status push for a tenant -- fall back to "disconnected as of now".
|
|
123764
|
+
newServicesRunningStatus.smartParkDisconnectedTimestamp = newServicesRunningStatus.isSmartParkConnected ? null : currentServicesRunningStatus?.smartParkDisconnectedTimestamp ?? cloudDateTimeUtc;
|
|
123765
|
+
newServicesRunningStatus.smartParkCoreDisconnectedTimestamp = newServicesRunningStatus.isSmartParkCoreConnected ? null : currentServicesRunningStatus?.smartParkCoreDisconnectedTimestamp ?? cloudDateTimeUtc;
|
|
123766
|
+
newServicesRunningStatus.sparkCloudDisconnectedTimestamp = newServicesRunningStatus.isSparkCloudConnected ? null : currentServicesRunningStatus?.sparkCloudDisconnectedTimestamp ?? cloudDateTimeUtc;
|
|
123767
|
+
newServicesRunningStatus.sparkCoreDisconnectedTimestamp = newServicesRunningStatus.isSparkCoreConnected ? null : currentServicesRunningStatus?.sparkCoreDisconnectedTimestamp ?? cloudDateTimeUtc;
|
|
123723
123768
|
return newServicesRunningStatus;
|
|
123724
123769
|
}
|
|
123725
123770
|
assignFacility(storedFacility, incomingFacility) {
|
|
@@ -124699,7 +124744,14 @@ let ParkManagerState = class ParkManagerState {
|
|
|
124699
124744
|
const clonedDto = DeviceStatusDto$1.fromJS(action.deviceStatus);
|
|
124700
124745
|
clonedDto.type = devicesById[deviceId].type;
|
|
124701
124746
|
devicesById[deviceId].deviceStatus = clonedDto;
|
|
124702
|
-
|
|
124747
|
+
// SPRK3-14987 (Sentry JAVASCRIPT-ANGULAR-3A): the guard above tests byId, but
|
|
124748
|
+
// this writes byCommId -- a different map, keyed by a different, optional field.
|
|
124749
|
+
// byId is the primary index and both maps are rebuilt together in patchDevices,
|
|
124750
|
+
// so a missing secondary entry must not cost byId its fresh status.
|
|
124751
|
+
const deviceByCommId = devicesbyCommId[commID];
|
|
124752
|
+
if (deviceByCommId) {
|
|
124753
|
+
deviceByCommId.deviceStatus = clonedDto;
|
|
124754
|
+
}
|
|
124703
124755
|
ctx.patchState({
|
|
124704
124756
|
byId: cloneDeep(devicesById),
|
|
124705
124757
|
byCommId: cloneDeep(devicesbyCommId),
|
|
@@ -128370,6 +128422,11 @@ class CompanyService {
|
|
|
128370
128422
|
includeSubCompanies: includeSubCompanies,
|
|
128371
128423
|
});
|
|
128372
128424
|
const accountsFetchMethod = this.getAccountsFetchMethod(permissionType);
|
|
128425
|
+
if (!accountsFetchMethod) {
|
|
128426
|
+
return of(null).pipe(tap(_ => {
|
|
128427
|
+
this.loadingCompanySubject$.next(false);
|
|
128428
|
+
}));
|
|
128429
|
+
}
|
|
128373
128430
|
const getCompanies$ = accountsFetchMethod(guid, parkId, searchParamsDto.maxResults, searchParamsDto.searchTerm, searchParamsDto.orderBy.column, searchParamsDto.orderBy.orderDirection, companiesFilterDto);
|
|
128374
128431
|
return getCompanies$.pipe(tap(_ => {
|
|
128375
128432
|
this.loadingCompanySubject$.next(false);
|
|
@@ -128389,6 +128446,11 @@ class CompanyService {
|
|
|
128389
128446
|
subCompanyIds: subCompanyIds,
|
|
128390
128447
|
});
|
|
128391
128448
|
const subAccountsFetchMethod = this.getSubAccountsFetchMethod(permissionType);
|
|
128449
|
+
if (!subAccountsFetchMethod) {
|
|
128450
|
+
return of(null).pipe(tap(_ => {
|
|
128451
|
+
this.loadingSubCompanySubject$.next(false);
|
|
128452
|
+
}));
|
|
128453
|
+
}
|
|
128392
128454
|
getSubCompanies$ = subAccountsFetchMethod(guid, parkId, null, null, null, OrderDirection$2.None, subCompaniesWithPermissions);
|
|
128393
128455
|
return getSubCompanies$.pipe(tap(_ => {
|
|
128394
128456
|
this.loadingSubCompanySubject$.next(false);
|
|
@@ -128403,6 +128465,11 @@ class CompanyService {
|
|
|
128403
128465
|
this.loadingSubCompanySubject$.next(true);
|
|
128404
128466
|
let getSubCompanies$;
|
|
128405
128467
|
const subAccountsFetchMethod = this.getSubAccountsFetchMethod(permissionType);
|
|
128468
|
+
if (!subAccountsFetchMethod) {
|
|
128469
|
+
return of(null).pipe(tap(_ => {
|
|
128470
|
+
this.loadingSubCompanySubject$.next(false);
|
|
128471
|
+
}));
|
|
128472
|
+
}
|
|
128406
128473
|
const subCompaniesFilterDto = new SubCompaniesFilterDto({
|
|
128407
128474
|
parkId,
|
|
128408
128475
|
companyIds,
|
|
@@ -128464,11 +128531,16 @@ class CompanyService {
|
|
|
128464
128531
|
this.messageBarService.clearMessagebar('credentialWarningMessage');
|
|
128465
128532
|
}
|
|
128466
128533
|
}
|
|
128534
|
+
// Both mappings below are partial lookups over PermissionType, so a miss is a
|
|
128535
|
+
// reachable state rather than a programming error: the Reports Center binds its
|
|
128536
|
+
// company dropdowns to the selected category's permission type, and the "All
|
|
128537
|
+
// reports" category legitimately has none. Return undefined on a miss and let
|
|
128538
|
+
// the callers degrade — see SPRK3-15029.
|
|
128467
128539
|
getAccountsFetchMethod(permissionType) {
|
|
128468
|
-
return
|
|
128540
|
+
return this.accountsFetchMethodsMapping[permissionType]?.bind(this.accountRpcServiceProxy);
|
|
128469
128541
|
}
|
|
128470
128542
|
getSubAccountsFetchMethod(permissionType) {
|
|
128471
|
-
return
|
|
128543
|
+
return this.subAccountsFetchMethodsMapping[permissionType]?.bind(this.accountRpcServiceProxy);
|
|
128472
128544
|
}
|
|
128473
128545
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CompanyService, deps: [{ token: i1$2.Store }, { token: MessageBarService }, { token: i1$5.TranslateService }, { token: SmartparkService }, { token: AccountRpcServiceProxy }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
128474
128546
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CompanyService }); }
|
|
@@ -134289,7 +134361,9 @@ class FacilityService {
|
|
|
134289
134361
|
};
|
|
134290
134362
|
this.hasPermissionTypesByPark = (permissionTypes, guid, parkId) => {
|
|
134291
134363
|
const facilityDictionary = this.store.selectSnapshot(FacilityState.facilityDictionary);
|
|
134292
|
-
|
|
134364
|
+
// SPRK3-14812: the dictionary is not hydrated for every guid/park at every point
|
|
134365
|
+
// in the change-detection cycle. An unknown park grants nothing (fail closed).
|
|
134366
|
+
const featurePermissions = facilityDictionary?.[guid]?.[parkId]?.featurePermissions;
|
|
134293
134367
|
const sparkVersion = this.store.selectSnapshot(({ smartpark: { versions } }) => versions[guid]);
|
|
134294
134368
|
return permissionTypes.reduce((acc, permissionType) => {
|
|
134295
134369
|
const permissionSupportVersion = PermissionTypeSupportedVersionDictionary[permissionType];
|
|
@@ -134297,7 +134371,10 @@ class FacilityService {
|
|
|
134297
134371
|
console.warn(`Permission ${permissionType} version support is missing in PermissionTypeSupportedVersionDictionary file`);
|
|
134298
134372
|
}
|
|
134299
134373
|
const isVersionSupported = isVersionGreaterThanEqual(sparkVersion, permissionSupportVersion);
|
|
134300
|
-
|
|
134374
|
+
// isVersionGreaterThanEqual returns undefined (not false) for an unknown version
|
|
134375
|
+
// despite its declared boolean return, which leaked undefined into a dictionary
|
|
134376
|
+
// typed { [key: string]: boolean }. Coerce so the declared type holds.
|
|
134377
|
+
acc[permissionType] = !!(isVersionSupported && featurePermissions?.includes(permissionType));
|
|
134301
134378
|
return acc;
|
|
134302
134379
|
}, {});
|
|
134303
134380
|
};
|
|
@@ -134306,8 +134383,11 @@ class FacilityService {
|
|
|
134306
134383
|
let isVersionSupported = this.isVersionSupported(permissionType, guid);
|
|
134307
134384
|
if (isVersionSupported) {
|
|
134308
134385
|
const facilityDictionary = this.store.selectSnapshot(FacilityState.facilityDictionary);
|
|
134309
|
-
|
|
134310
|
-
|
|
134386
|
+
// SPRK3-14812 (Sentry JAVASCRIPT-ANGULAR-K): the optional chain sat one level too
|
|
134387
|
+
// deep -- [guid] and [parkId] were both indexed unguarded. Fail closed, which is
|
|
134388
|
+
// what the `hasPermission = false` initialiser above already promises callers.
|
|
134389
|
+
const featurePermissions = facilityDictionary?.[guid]?.[parkId]?.featurePermissions;
|
|
134390
|
+
hasPermission = !!featurePermissions?.includes(permissionType);
|
|
134311
134391
|
}
|
|
134312
134392
|
return hasPermission;
|
|
134313
134393
|
};
|