@northern.tech/store 0.30.0 → 0.30.1
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/actions.cjs +21 -1130
- package/dist/actions.cjs.map +1 -1
- package/dist/actions.d.cts +212 -221
- package/dist/actions.d.ts +212 -220
- package/dist/actions.js +21 -18
- package/dist/actions.js.map +1 -1
- package/dist/api/general-api.cjs +61 -459
- package/dist/api/general-api.cjs.map +1 -1
- package/dist/api/general-api.d.cts +15 -17
- package/dist/api/general-api.d.ts +15 -17
- package/dist/api/general-api.js +56 -15
- package/dist/api/general-api.js.map +1 -1
- package/dist/api/users-api.cjs +32 -469
- package/dist/api/users-api.cjs.map +1 -1
- package/dist/api/users-api.d.cts +19 -14
- package/dist/api/users-api.d.ts +19 -13
- package/dist/api/users-api.js +30 -12
- package/dist/api/users-api.js.map +1 -1
- package/dist/appSlice/constants.cjs +190 -144
- package/dist/appSlice/constants.cjs.map +1 -1
- package/dist/appSlice/constants.d.cts +2 -159
- package/dist/appSlice/constants.d.ts +2 -159
- package/dist/appSlice/constants.js +181 -29
- package/dist/appSlice/constants.js.map +1 -1
- package/dist/appSlice/index.cjs +147 -178
- package/dist/appSlice/index.cjs.map +1 -1
- package/dist/appSlice/index.d.cts +2 -148
- package/dist/appSlice/index.d.ts +2 -148
- package/dist/appSlice/index.js +142 -18
- package/dist/appSlice/index.js.map +1 -1
- package/dist/appSlice/mocks.cjs +17 -191
- package/dist/appSlice/mocks.cjs.map +1 -1
- package/dist/appSlice/mocks.d.cts +33 -36
- package/dist/appSlice/mocks.d.ts +33 -36
- package/dist/appSlice/mocks.js +17 -25
- package/dist/appSlice/mocks.js.map +1 -1
- package/dist/appSlice/selectors.cjs +49 -91
- package/dist/appSlice/selectors.cjs.map +1 -1
- package/dist/appSlice/selectors.d.cts +216 -230
- package/dist/appSlice/selectors.d.ts +216 -230
- package/dist/appSlice/selectors.js +29 -44
- package/dist/appSlice/selectors.js.map +1 -1
- package/dist/appSlice/thunks.cjs +6 -4636
- package/dist/appSlice/thunks.d.cts +59 -62
- package/dist/appSlice/thunks.d.ts +59 -62
- package/dist/appSlice/thunks.js +2 -45
- package/dist/auth.cjs +68 -433
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +14 -14
- package/dist/auth.d.ts +14 -14
- package/dist/auth.js +65 -18
- package/dist/auth.js.map +1 -1
- package/dist/chunk-CKQMccvm.cjs +28 -0
- package/dist/commonConstants.cjs +14 -393
- package/dist/commonConstants.d.cts +2 -83
- package/dist/commonConstants.d.ts +2 -83
- package/dist/commonConstants.js +2 -33
- package/dist/commonSelectors.cjs +284 -1269
- package/dist/commonSelectors.cjs.map +1 -1
- package/dist/commonSelectors.d.cts +1623 -1416
- package/dist/commonSelectors.d.ts +1623 -1416
- package/dist/commonSelectors.js +277 -51
- package/dist/commonSelectors.js.map +1 -1
- package/dist/constants-5cdwz1iH.d.ts +160 -0
- package/dist/constants-BWEsNG5c.d.ts +28 -0
- package/dist/constants-BciiayPt.d.ts +17 -0
- package/dist/constants-C5AU0mCY.d.ts +157 -0
- package/dist/constants-CIx3fnBv.d.cts +17 -0
- package/dist/constants-CNhpIMME.d.cts +93 -0
- package/dist/constants-Cpgyuy_r.d.ts +57 -0
- package/dist/constants-D41U_jbR.d.cts +160 -0
- package/dist/constants-DK7fI3Rh.d.cts +28 -0
- package/dist/constants-DPLHhjVN.d.cts +157 -0
- package/dist/constants-DrwXHsJ1.d.ts +120 -0
- package/dist/constants-G3wymKIl.d.cts +57 -0
- package/dist/constants-MPLfugsi.d.cts +120 -0
- package/dist/constants-y2XVLQWf.d.ts +93 -0
- package/dist/constants.cjs +784 -972
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +8 -14
- package/dist/constants.d.ts +8 -14
- package/dist/constants.js +674 -232
- package/dist/constants.js.map +1 -1
- package/dist/deploymentsSlice/constants.cjs +15 -214
- package/dist/deploymentsSlice/constants.d.cts +2 -163
- package/dist/deploymentsSlice/constants.d.ts +2 -163
- package/dist/deploymentsSlice/constants.js +2 -35
- package/dist/deploymentsSlice/index.cjs +168 -302
- package/dist/deploymentsSlice/index.cjs.map +1 -1
- package/dist/deploymentsSlice/index.d.cts +2 -157
- package/dist/deploymentsSlice/index.d.ts +2 -157
- package/dist/deploymentsSlice/index.js +161 -18
- package/dist/deploymentsSlice/index.js.map +1 -1
- package/dist/deploymentsSlice/mocks.cjs +178 -433
- package/dist/deploymentsSlice/mocks.cjs.map +1 -1
- package/dist/deploymentsSlice/mocks.d.cts +176 -178
- package/dist/deploymentsSlice/mocks.d.ts +176 -178
- package/dist/deploymentsSlice/mocks.js +178 -144
- package/dist/deploymentsSlice/mocks.js.map +1 -1
- package/dist/deploymentsSlice/selectors.cjs +44 -223
- package/dist/deploymentsSlice/selectors.cjs.map +1 -1
- package/dist/deploymentsSlice/selectors.d.cts +73 -87
- package/dist/deploymentsSlice/selectors.d.ts +73 -87
- package/dist/deploymentsSlice/selectors.js +37 -25
- package/dist/deploymentsSlice/selectors.js.map +1 -1
- package/dist/deploymentsSlice/thunks.cjs +16 -4654
- package/dist/deploymentsSlice/thunks.d.cts +222 -235
- package/dist/deploymentsSlice/thunks.d.ts +222 -235
- package/dist/deploymentsSlice/thunks.js +2 -65
- package/dist/devicesSlice/constants.cjs +9 -68
- package/dist/devicesSlice/constants.d.cts +2 -37
- package/dist/devicesSlice/constants.d.ts +2 -37
- package/dist/devicesSlice/constants.js +2 -23
- package/dist/devicesSlice/index.cjs +215 -225
- package/dist/devicesSlice/index.cjs.map +1 -1
- package/dist/devicesSlice/index.d.cts +2 -202
- package/dist/devicesSlice/index.d.ts +2 -202
- package/dist/devicesSlice/index.js +209 -18
- package/dist/devicesSlice/index.js.map +1 -1
- package/dist/devicesSlice/mocks.cjs +146 -339
- package/dist/devicesSlice/mocks.cjs.map +1 -1
- package/dist/devicesSlice/mocks.d.cts +150 -148
- package/dist/devicesSlice/mocks.d.ts +150 -148
- package/dist/devicesSlice/mocks.js +145 -132
- package/dist/devicesSlice/mocks.js.map +1 -1
- package/dist/devicesSlice/selectors.cjs +145 -539
- package/dist/devicesSlice/selectors.cjs.map +1 -1
- package/dist/devicesSlice/selectors.d.cts +685 -699
- package/dist/devicesSlice/selectors.d.ts +685 -699
- package/dist/devicesSlice/selectors.js +123 -59
- package/dist/devicesSlice/selectors.js.map +1 -1
- package/dist/devicesSlice/thunks.cjs +48 -4718
- package/dist/devicesSlice/thunks.d.cts +800 -752
- package/dist/devicesSlice/thunks.d.ts +800 -752
- package/dist/devicesSlice/thunks.js +2 -129
- package/dist/index-4eaLEXy_.d.cts +152 -0
- package/dist/index-BEVkIiNa.d.cts +95 -0
- package/dist/index-BP0uAq36.d.cts +159 -0
- package/dist/index-Bwx9jEiL.d.cts +71 -0
- package/dist/index-CJkrL0oA.d.ts +64 -0
- package/dist/index-CO-py5d4.d.ts +95 -0
- package/dist/index-CTt-eIY8.d.cts +154 -0
- package/dist/index-CkwVnIqd.d.ts +159 -0
- package/dist/index-Cvkvcz4r.d.ts +115 -0
- package/dist/index-DJSlDPRX.d.ts +71 -0
- package/dist/index-DqyY6oZ3.d.ts +205 -0
- package/dist/index-DtePEQPT.d.ts +152 -0
- package/dist/index-Dv3Hfxk_.d.ts +154 -0
- package/dist/index-FyYBBeN-.d.cts +115 -0
- package/dist/index-Lz5JsJ6O.d.cts +205 -0
- package/dist/index-UPc3wvVd.d.cts +64 -0
- package/dist/liststatehook.cjs +83 -948
- package/dist/liststatehook.cjs.map +1 -1
- package/dist/liststatehook.d.cts +29 -239
- package/dist/liststatehook.d.ts +29 -239
- package/dist/liststatehook.js +77 -85
- package/dist/liststatehook.js.map +1 -1
- package/dist/locationutils.cjs +459 -916
- package/dist/locationutils.cjs.map +1 -1
- package/dist/locationutils.d.cts +244 -110
- package/dist/locationutils.d.ts +244 -110
- package/dist/locationutils.js +440 -44
- package/dist/locationutils.js.map +1 -1
- package/dist/monitorSlice/constants.cjs +0 -19
- package/dist/monitorSlice/constants.d.cts +2 -5
- package/dist/monitorSlice/constants.d.ts +2 -5
- package/dist/monitorSlice/constants.js +1 -2
- package/dist/monitorSlice/index.cjs +65 -82
- package/dist/monitorSlice/index.cjs.map +1 -1
- package/dist/monitorSlice/index.d.cts +2 -94
- package/dist/monitorSlice/index.d.ts +2 -94
- package/dist/monitorSlice/index.js +59 -18
- package/dist/monitorSlice/index.js.map +1 -1
- package/dist/monitorSlice/mocks.cjs +50 -126
- package/dist/monitorSlice/mocks.cjs.map +1 -1
- package/dist/monitorSlice/mocks.d.cts +49 -45
- package/dist/monitorSlice/mocks.d.ts +49 -45
- package/dist/monitorSlice/mocks.js +49 -62
- package/dist/monitorSlice/mocks.js.map +1 -1
- package/dist/monitorSlice/selectors.cjs +5 -29
- package/dist/monitorSlice/selectors.cjs.map +1 -1
- package/dist/monitorSlice/selectors.d.cts +10 -1
- package/dist/monitorSlice/selectors.d.ts +10 -1
- package/dist/monitorSlice/selectors.js +5 -6
- package/dist/monitorSlice/selectors.js.map +1 -1
- package/dist/monitorSlice/thunks.cjs +83 -1914
- package/dist/monitorSlice/thunks.cjs.map +1 -1
- package/dist/monitorSlice/thunks.d.cts +112 -120
- package/dist/monitorSlice/thunks.d.ts +112 -120
- package/dist/monitorSlice/thunks.js +78 -42
- package/dist/monitorSlice/thunks.js.map +1 -1
- package/dist/onboardingSlice/constants.cjs +44 -69
- package/dist/onboardingSlice/constants.cjs.map +1 -1
- package/dist/onboardingSlice/constants.d.cts +2 -26
- package/dist/onboardingSlice/constants.d.ts +2 -26
- package/dist/onboardingSlice/constants.js +43 -7
- package/dist/onboardingSlice/constants.js.map +1 -1
- package/dist/onboardingSlice/index.cjs +53 -73
- package/dist/onboardingSlice/index.cjs.map +1 -1
- package/dist/onboardingSlice/index.d.cts +2 -62
- package/dist/onboardingSlice/index.d.ts +2 -62
- package/dist/onboardingSlice/index.js +47 -13
- package/dist/onboardingSlice/index.js.map +1 -1
- package/dist/onboardingSlice/mocks.cjs +12 -81
- package/dist/onboardingSlice/mocks.cjs.map +1 -1
- package/dist/onboardingSlice/mocks.d.cts +14 -15
- package/dist/onboardingSlice/mocks.d.ts +14 -15
- package/dist/onboardingSlice/mocks.js +12 -15
- package/dist/onboardingSlice/mocks.js.map +1 -1
- package/dist/onboardingSlice/selectors.cjs +5 -29
- package/dist/onboardingSlice/selectors.cjs.map +1 -1
- package/dist/onboardingSlice/selectors.d.cts +6 -1
- package/dist/onboardingSlice/selectors.d.ts +6 -1
- package/dist/onboardingSlice/selectors.js +5 -6
- package/dist/onboardingSlice/selectors.js.map +1 -1
- package/dist/onboardingSlice/thunks.cjs +8 -4746
- package/dist/onboardingSlice/thunks.d.cts +124 -143
- package/dist/onboardingSlice/thunks.d.ts +124 -143
- package/dist/onboardingSlice/thunks.js +2 -49
- package/dist/organizationSlice/constants.cjs +11 -95
- package/dist/organizationSlice/constants.d.cts +2 -91
- package/dist/organizationSlice/constants.d.ts +2 -91
- package/dist/organizationSlice/constants.js +2 -27
- package/dist/organizationSlice/index.cjs +113 -152
- package/dist/organizationSlice/index.cjs.map +1 -1
- package/dist/organizationSlice/index.d.cts +2 -74
- package/dist/organizationSlice/index.d.ts +2 -74
- package/dist/organizationSlice/index.js +106 -18
- package/dist/organizationSlice/index.js.map +1 -1
- package/dist/organizationSlice/mocks.cjs +215 -406
- package/dist/organizationSlice/mocks.cjs.map +1 -1
- package/dist/organizationSlice/mocks.d.cts +209 -212
- package/dist/organizationSlice/mocks.d.ts +209 -212
- package/dist/organizationSlice/mocks.js +214 -184
- package/dist/organizationSlice/mocks.js.map +1 -1
- package/dist/organizationSlice/selectors.cjs +97 -474
- package/dist/organizationSlice/selectors.cjs.map +1 -1
- package/dist/organizationSlice/selectors.d.cts +381 -389
- package/dist/organizationSlice/selectors.d.ts +381 -389
- package/dist/organizationSlice/selectors.js +78 -50
- package/dist/organizationSlice/selectors.js.map +1 -1
- package/dist/organizationSlice/thunks.cjs +43 -5150
- package/dist/organizationSlice/thunks.d.cts +638 -649
- package/dist/organizationSlice/thunks.d.ts +638 -649
- package/dist/organizationSlice/thunks.js +2 -119
- package/dist/organizationSlice/types.cjs +0 -19
- package/dist/organizationSlice/types.d.cts +2 -88
- package/dist/organizationSlice/types.d.ts +2 -88
- package/dist/organizationSlice/types.js +1 -1
- package/dist/releasesSlice/constants.cjs +17 -41
- package/dist/releasesSlice/constants.cjs.map +1 -1
- package/dist/releasesSlice/constants.d.cts +2 -15
- package/dist/releasesSlice/constants.d.ts +2 -15
- package/dist/releasesSlice/constants.js +13 -14
- package/dist/releasesSlice/constants.js.map +1 -1
- package/dist/releasesSlice/index.cjs +106 -179
- package/dist/releasesSlice/index.cjs.map +1 -1
- package/dist/releasesSlice/index.d.cts +2 -113
- package/dist/releasesSlice/index.d.ts +2 -113
- package/dist/releasesSlice/index.js +100 -18
- package/dist/releasesSlice/index.js.map +1 -1
- package/dist/releasesSlice/mocks.cjs +44 -220
- package/dist/releasesSlice/mocks.cjs.map +1 -1
- package/dist/releasesSlice/mocks.d.cts +63 -61
- package/dist/releasesSlice/mocks.d.ts +63 -61
- package/dist/releasesSlice/mocks.js +43 -59
- package/dist/releasesSlice/mocks.js.map +1 -1
- package/dist/releasesSlice/selectors.cjs +44 -439
- package/dist/releasesSlice/selectors.cjs.map +1 -1
- package/dist/releasesSlice/selectors.d.cts +268 -280
- package/dist/releasesSlice/selectors.d.ts +268 -280
- package/dist/releasesSlice/selectors.js +31 -36
- package/dist/releasesSlice/selectors.js.map +1 -1
- package/dist/releasesSlice/thunks.cjs +422 -2175
- package/dist/releasesSlice/thunks.cjs.map +1 -1
- package/dist/releasesSlice/thunks.d.cts +305 -307
- package/dist/releasesSlice/thunks.d.ts +305 -307
- package/dist/releasesSlice/thunks.js +413 -65
- package/dist/releasesSlice/thunks.js.map +1 -1
- package/dist/selectors.cjs +136 -1530
- package/dist/selectors.d.cts +10 -36
- package/dist/selectors.d.ts +10 -36
- package/dist/selectors.js +10 -280
- package/dist/sockethook.cjs +140 -515
- package/dist/sockethook.cjs.map +1 -1
- package/dist/sockethook.d.cts +25 -9
- package/dist/sockethook.d.ts +25 -9
- package/dist/sockethook.js +134 -135
- package/dist/sockethook.js.map +1 -1
- package/dist/store-BQxOSRC1.d.ts +234 -0
- package/dist/store-BiIA0r0A.d.cts +234 -0
- package/dist/store.cjs +117 -1290
- package/dist/store.cjs.map +1 -1
- package/dist/store.d.cts +3 -206
- package/dist/store.d.ts +3 -206
- package/dist/store.js +110 -32
- package/dist/store.js.map +1 -1
- package/dist/storehooks.cjs +240 -5783
- package/dist/storehooks.cjs.map +1 -1
- package/dist/storehooks.d.cts +76 -4
- package/dist/storehooks.d.ts +76 -4
- package/dist/storehooks.js +229 -265
- package/dist/storehooks.js.map +1 -1
- package/dist/thunks.cjs +2614 -5918
- package/dist/thunks.cjs.map +1 -1
- package/dist/thunks.d.cts +9 -36
- package/dist/thunks.d.ts +9 -36
- package/dist/thunks.js +2439 -385
- package/dist/thunks.js.map +1 -1
- package/dist/types-B2NRQLFw.d.ts +88 -0
- package/dist/types-ClEfo0dK.d.cts +88 -0
- package/dist/useDeploymentDevice.cjs +26 -4650
- package/dist/useDeploymentDevice.cjs.map +1 -1
- package/dist/useDeploymentDevice.d.cts +4 -2
- package/dist/useDeploymentDevice.d.ts +4 -2
- package/dist/useDeploymentDevice.js +21 -60
- package/dist/useDeploymentDevice.js.map +1 -1
- package/dist/usersSlice/constants.cjs +8 -55
- package/dist/usersSlice/constants.d.cts +2 -52
- package/dist/usersSlice/constants.d.ts +2 -52
- package/dist/usersSlice/constants.js +2 -21
- package/dist/usersSlice/index.cjs +132 -172
- package/dist/usersSlice/index.cjs.map +1 -1
- package/dist/usersSlice/index.d.cts +2 -152
- package/dist/usersSlice/index.d.ts +2 -152
- package/dist/usersSlice/index.js +125 -18
- package/dist/usersSlice/index.js.map +1 -1
- package/dist/usersSlice/mocks.cjs +55 -196
- package/dist/usersSlice/mocks.cjs.map +1 -1
- package/dist/usersSlice/mocks.d.cts +68 -72
- package/dist/usersSlice/mocks.d.ts +68 -72
- package/dist/usersSlice/mocks.js +54 -46
- package/dist/usersSlice/mocks.js.map +1 -1
- package/dist/usersSlice/selectors.cjs +65 -567
- package/dist/usersSlice/selectors.cjs.map +1 -1
- package/dist/usersSlice/selectors.d.cts +364 -376
- package/dist/usersSlice/selectors.d.ts +364 -376
- package/dist/usersSlice/selectors.js +44 -50
- package/dist/usersSlice/selectors.js.map +1 -1
- package/dist/usersSlice/thunks.cjs +39 -4698
- package/dist/usersSlice/thunks.d.cts +807 -843
- package/dist/usersSlice/thunks.d.ts +807 -843
- package/dist/usersSlice/thunks.js +2 -111
- package/dist/utils-B4I595rf.d.cts +104 -0
- package/dist/utils-DNnSR4S_.d.ts +104 -0
- package/dist/utils.cjs +229 -850
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -80
- package/dist/utils.d.ts +2 -80
- package/dist/utils.js +210 -50
- package/dist/utils.js.map +1 -1
- package/package.json +11 -13
- package/dist/appSlice/thunks.cjs.map +0 -1
- package/dist/appSlice/thunks.js.map +0 -1
- package/dist/chunk-2DYA3X77.js +0 -15
- package/dist/chunk-2DYA3X77.js.map +0 -1
- package/dist/chunk-4BHM6WVX.js +0 -50
- package/dist/chunk-4BHM6WVX.js.map +0 -1
- package/dist/chunk-4UNLEL5A.js +0 -143
- package/dist/chunk-4UNLEL5A.js.map +0 -1
- package/dist/chunk-6V5IIIF7.js +0 -396
- package/dist/chunk-6V5IIIF7.js.map +0 -1
- package/dist/chunk-ARMI6SZS.js +0 -446
- package/dist/chunk-ARMI6SZS.js.map +0 -1
- package/dist/chunk-AZF4YY3P.js +0 -108
- package/dist/chunk-AZF4YY3P.js.map +0 -1
- package/dist/chunk-B5AI2YPV.js +0 -156
- package/dist/chunk-B5AI2YPV.js.map +0 -1
- package/dist/chunk-CQXDAXQF.js +0 -51
- package/dist/chunk-CQXDAXQF.js.map +0 -1
- package/dist/chunk-DBBE6D36.js +0 -115
- package/dist/chunk-DBBE6D36.js.map +0 -1
- package/dist/chunk-ECVQVQEL.js +0 -68
- package/dist/chunk-ECVQVQEL.js.map +0 -1
- package/dist/chunk-FAJ3I2UQ.js +0 -47
- package/dist/chunk-FAJ3I2UQ.js.map +0 -1
- package/dist/chunk-FCY7BUGK.js +0 -2876
- package/dist/chunk-FCY7BUGK.js.map +0 -1
- package/dist/chunk-FG37HJLC.js +0 -157
- package/dist/chunk-FG37HJLC.js.map +0 -1
- package/dist/chunk-FQAUVV6C.js +0 -246
- package/dist/chunk-FQAUVV6C.js.map +0 -1
- package/dist/chunk-HKN3RN2Z.js +0 -41
- package/dist/chunk-HKN3RN2Z.js.map +0 -1
- package/dist/chunk-HPKXWNEF.js +0 -100
- package/dist/chunk-HPKXWNEF.js.map +0 -1
- package/dist/chunk-JIS4PA3R.js +0 -7
- package/dist/chunk-JIS4PA3R.js.map +0 -1
- package/dist/chunk-JXBTIFMS.js +0 -82
- package/dist/chunk-JXBTIFMS.js.map +0 -1
- package/dist/chunk-JYPSCCT4.js +0 -58
- package/dist/chunk-JYPSCCT4.js.map +0 -1
- package/dist/chunk-L53CPHJU.js +0 -721
- package/dist/chunk-L53CPHJU.js.map +0 -1
- package/dist/chunk-MNJXEB7S.js +0 -304
- package/dist/chunk-MNJXEB7S.js.map +0 -1
- package/dist/chunk-NMAXZ3ZY.js +0 -1
- package/dist/chunk-NMAXZ3ZY.js.map +0 -1
- package/dist/chunk-NXLXPRYW.js +0 -142
- package/dist/chunk-NXLXPRYW.js.map +0 -1
- package/dist/chunk-O6VCSLNE.js +0 -59
- package/dist/chunk-O6VCSLNE.js.map +0 -1
- package/dist/chunk-PQADM3M3.js +0 -115
- package/dist/chunk-PQADM3M3.js.map +0 -1
- package/dist/chunk-SJ75YKOA.js +0 -44
- package/dist/chunk-SJ75YKOA.js.map +0 -1
- package/dist/chunk-TUPBZ6MQ.js +0 -162
- package/dist/chunk-TUPBZ6MQ.js.map +0 -1
- package/dist/chunk-XF3TZSZS.js +0 -25
- package/dist/chunk-XF3TZSZS.js.map +0 -1
- package/dist/chunk-YB3US6OT.js +0 -61
- package/dist/chunk-YB3US6OT.js.map +0 -1
- package/dist/chunk-YDDE5TIH.js +0 -204
- package/dist/chunk-YDDE5TIH.js.map +0 -1
- package/dist/chunk-YO22XLHI.js +0 -7
- package/dist/chunk-YO22XLHI.js.map +0 -1
- package/dist/chunk-Z2O6LYVP.js +0 -144
- package/dist/chunk-Z2O6LYVP.js.map +0 -1
- package/dist/chunk-ZKAH3APE.js +0 -1
- package/dist/chunk-ZKAH3APE.js.map +0 -1
- package/dist/commonConstants.cjs.map +0 -1
- package/dist/commonConstants.js.map +0 -1
- package/dist/deploymentsSlice/constants.cjs.map +0 -1
- package/dist/deploymentsSlice/constants.js.map +0 -1
- package/dist/deploymentsSlice/thunks.cjs.map +0 -1
- package/dist/deploymentsSlice/thunks.js.map +0 -1
- package/dist/devicesSlice/constants.cjs.map +0 -1
- package/dist/devicesSlice/constants.js.map +0 -1
- package/dist/devicesSlice/thunks.cjs.map +0 -1
- package/dist/devicesSlice/thunks.js.map +0 -1
- package/dist/monitorSlice/constants.cjs.map +0 -1
- package/dist/monitorSlice/constants.js.map +0 -1
- package/dist/onboardingSlice/thunks.cjs.map +0 -1
- package/dist/onboardingSlice/thunks.js.map +0 -1
- package/dist/organizationSlice/constants.cjs.map +0 -1
- package/dist/organizationSlice/constants.js.map +0 -1
- package/dist/organizationSlice/thunks.cjs.map +0 -1
- package/dist/organizationSlice/thunks.js.map +0 -1
- package/dist/organizationSlice/types.cjs.map +0 -1
- package/dist/organizationSlice/types.js.map +0 -1
- package/dist/selectors.cjs.map +0 -1
- package/dist/selectors.js.map +0 -1
- package/dist/usersSlice/constants.cjs.map +0 -1
- package/dist/usersSlice/constants.js.map +0 -1
- package/dist/usersSlice/thunks.cjs.map +0 -1
- package/dist/usersSlice/thunks.js.map +0 -1
package/dist/thunks.js
CHANGED
|
@@ -1,387 +1,2441 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
getDeviceAuth,
|
|
53
|
-
getDeviceById,
|
|
54
|
-
getDeviceConfig,
|
|
55
|
-
getDeviceConnect,
|
|
56
|
-
getDeviceDeployments,
|
|
57
|
-
getDeviceFileDownloadLink,
|
|
58
|
-
getDeviceInfo,
|
|
59
|
-
getDeviceLimits,
|
|
60
|
-
getDeviceLog,
|
|
61
|
-
getDeviceTwin,
|
|
62
|
-
getDevicesByStatus,
|
|
63
|
-
getDevicesWithAuth,
|
|
64
|
-
getDynamicGroup,
|
|
65
|
-
getDynamicGroups,
|
|
66
|
-
getGatewayDevices,
|
|
67
|
-
getGlobalSettings,
|
|
68
|
-
getGroupDevices,
|
|
69
|
-
getGroups,
|
|
70
|
-
getIntegrations,
|
|
71
|
-
getLatestReleaseInfo,
|
|
72
|
-
getOnboardingState,
|
|
73
|
-
getPermissionSets,
|
|
74
|
-
getProducts,
|
|
75
|
-
getReportDataWithoutBackendSupport,
|
|
76
|
-
getRoles,
|
|
77
|
-
getSessionDetails,
|
|
78
|
-
getSingleDeployment,
|
|
79
|
-
getSsoConfigById,
|
|
80
|
-
getSsoConfigs,
|
|
81
|
-
getSystemDevices,
|
|
82
|
-
getTargetLocation,
|
|
83
|
-
getTenants,
|
|
84
|
-
getTokens,
|
|
85
|
-
getUser,
|
|
86
|
-
getUserBilling,
|
|
87
|
-
getUserList,
|
|
88
|
-
getUserOrganization,
|
|
89
|
-
getUserSettings,
|
|
90
|
-
getUserSubscription,
|
|
91
|
-
getWebhookEvents,
|
|
92
|
-
initializeSelf,
|
|
93
|
-
loginUser,
|
|
94
|
-
logoutUser,
|
|
95
|
-
normalizeRbacRoles,
|
|
96
|
-
passwordResetComplete,
|
|
97
|
-
passwordResetStart,
|
|
98
|
-
preauthDevice,
|
|
99
|
-
removeDevicesFromGroup,
|
|
100
|
-
removeDynamicGroup,
|
|
101
|
-
removeReportsByGroupName,
|
|
102
|
-
removeRole,
|
|
103
|
-
removeStaticGroup,
|
|
104
|
-
removeTenant,
|
|
105
|
-
removeUser,
|
|
106
|
-
requestPlanChange,
|
|
107
|
-
requestPlanUpgrade,
|
|
108
|
-
resetDeviceDeployments,
|
|
109
|
-
revokeToken,
|
|
110
|
-
saveDeltaDeploymentsConfig,
|
|
111
|
-
saveGlobalSettings,
|
|
112
|
-
saveUserSettings,
|
|
113
|
-
searchDevices,
|
|
114
|
-
selectGroup,
|
|
115
|
-
sendSupportMessage,
|
|
116
|
-
setAllTooltipsReadState,
|
|
117
|
-
setAuditlogsState,
|
|
118
|
-
setDeploymentsState,
|
|
119
|
-
setDeviceConfig,
|
|
120
|
-
setDeviceListState,
|
|
121
|
-
setDeviceTags,
|
|
122
|
-
setDeviceTwin,
|
|
123
|
-
setFirstLoginAfterSignup,
|
|
124
|
-
setHideAnnouncement,
|
|
125
|
-
setOfflineThreshold,
|
|
126
|
-
setOnboardingApproach,
|
|
127
|
-
setOnboardingCanceled,
|
|
128
|
-
setOnboardingComplete,
|
|
129
|
-
setOnboardingDeviceType,
|
|
130
|
-
setSearchState,
|
|
131
|
-
setTenantsListState,
|
|
132
|
-
setTooltipReadState,
|
|
133
|
-
startCardUpdate,
|
|
134
|
-
startUpgrade,
|
|
135
|
-
storeSsoConfig,
|
|
136
|
-
submitUserFeedback,
|
|
137
|
-
switchUserOrganization,
|
|
138
|
-
tenantDataDivergedMessage,
|
|
139
|
-
transformProductResponse,
|
|
140
|
-
triggerDeviceUpdate,
|
|
141
|
-
updateDeploymentControlMap,
|
|
142
|
-
updateDeviceAuth,
|
|
143
|
-
updateDevicesAuth,
|
|
144
|
-
updateDynamicGroup,
|
|
145
|
-
updateReportData,
|
|
146
|
-
updateUserColumnSettings,
|
|
147
|
-
verify2FA,
|
|
148
|
-
verifyEmailComplete,
|
|
149
|
-
verifyEmailStart
|
|
150
|
-
} from "./chunk-FCY7BUGK.js";
|
|
151
|
-
import {
|
|
152
|
-
cancelFileUpload,
|
|
153
|
-
createArtifact,
|
|
154
|
-
editArtifact,
|
|
155
|
-
getArtifactInstallCount,
|
|
156
|
-
getArtifactUrl,
|
|
157
|
-
getDeltaGenerationJobDetails,
|
|
158
|
-
getDeltaGenerationJobs,
|
|
159
|
-
getExistingReleaseTags,
|
|
160
|
-
getRelease,
|
|
161
|
-
getReleases,
|
|
162
|
-
getUpdateTypes,
|
|
163
|
-
removeArtifact,
|
|
164
|
-
removeRelease,
|
|
165
|
-
removeReleases,
|
|
166
|
-
selectRelease,
|
|
167
|
-
setReleaseTags,
|
|
168
|
-
setReleasesListState,
|
|
169
|
-
setReleasesTags,
|
|
170
|
-
setSingleReleaseTags,
|
|
171
|
-
updateReleaseInfo,
|
|
172
|
-
uploadArtifact
|
|
173
|
-
} from "./chunk-ARMI6SZS.js";
|
|
174
|
-
import {
|
|
175
|
-
changeNotificationSetting,
|
|
176
|
-
getDeviceAlerts,
|
|
177
|
-
getDeviceMonitorConfig,
|
|
178
|
-
getIssueCountsByType,
|
|
179
|
-
getLatestDeviceAlerts
|
|
180
|
-
} from "./chunk-AZF4YY3P.js";
|
|
181
|
-
import "./chunk-NXLXPRYW.js";
|
|
182
|
-
import "./chunk-XF3TZSZS.js";
|
|
183
|
-
import "./chunk-JYPSCCT4.js";
|
|
184
|
-
import "./chunk-HKN3RN2Z.js";
|
|
185
|
-
import "./chunk-FG37HJLC.js";
|
|
186
|
-
import "./chunk-Z2O6LYVP.js";
|
|
187
|
-
import "./chunk-PQADM3M3.js";
|
|
188
|
-
import "./chunk-YB3US6OT.js";
|
|
189
|
-
import "./chunk-CQXDAXQF.js";
|
|
190
|
-
import "./chunk-YDDE5TIH.js";
|
|
191
|
-
import "./chunk-B5AI2YPV.js";
|
|
192
|
-
import "./chunk-4UNLEL5A.js";
|
|
193
|
-
import "./chunk-ECVQVQEL.js";
|
|
194
|
-
import "./chunk-6V5IIIF7.js";
|
|
195
|
-
import "./chunk-NMAXZ3ZY.js";
|
|
196
|
-
import "./chunk-MNJXEB7S.js";
|
|
197
|
-
import "./chunk-SJ75YKOA.js";
|
|
198
|
-
import "./chunk-JXBTIFMS.js";
|
|
199
|
-
import "./chunk-HPKXWNEF.js";
|
|
200
|
-
import "./chunk-YO22XLHI.js";
|
|
201
|
-
import "./chunk-JIS4PA3R.js";
|
|
202
|
-
import "./chunk-O6VCSLNE.js";
|
|
203
|
-
import "./chunk-TUPBZ6MQ.js";
|
|
204
|
-
import "./chunk-4BHM6WVX.js";
|
|
205
|
-
import "./chunk-FQAUVV6C.js";
|
|
206
|
-
import "./chunk-L53CPHJU.js";
|
|
207
|
-
import "./chunk-2DYA3X77.js";
|
|
208
|
-
import "./chunk-FAJ3I2UQ.js";
|
|
209
|
-
import "./chunk-ZKAH3APE.js";
|
|
210
|
-
import "./chunk-DBBE6D36.js";
|
|
211
|
-
export {
|
|
212
|
-
abortDeployment,
|
|
213
|
-
addDevicesToGroup,
|
|
214
|
-
addDynamicGroup,
|
|
215
|
-
addStaticGroup,
|
|
216
|
-
addTenant,
|
|
217
|
-
addUserToCurrentTenant,
|
|
218
|
-
advanceOnboarding,
|
|
219
|
-
applyDeviceConfig,
|
|
220
|
-
cancelFileUpload,
|
|
221
|
-
cancelRequest,
|
|
222
|
-
cancelUpgrade,
|
|
223
|
-
changeIntegration,
|
|
224
|
-
changeNotificationSetting,
|
|
225
|
-
changeSsoConfig,
|
|
226
|
-
checkEmailExists,
|
|
227
|
-
completeUpgrade,
|
|
228
|
-
confirmCardUpdate,
|
|
229
|
-
createArtifact,
|
|
230
|
-
createBillingProfile,
|
|
231
|
-
createDeployment,
|
|
232
|
-
createIntegration,
|
|
233
|
-
createOrganizationTrial,
|
|
234
|
-
createRole,
|
|
235
|
-
createUser,
|
|
236
|
-
decommissionDevice,
|
|
237
|
-
deleteAuthset,
|
|
238
|
-
deleteIntegration,
|
|
239
|
-
deleteSsoConfig,
|
|
240
|
-
deriveDeploymentGroup,
|
|
241
|
-
deviceFileUpload,
|
|
242
|
-
disableUser2fa,
|
|
243
|
-
downloadLicenseReport,
|
|
244
|
-
editArtifact,
|
|
245
|
-
editBillingProfile,
|
|
246
|
-
editRole,
|
|
247
|
-
editTenant,
|
|
248
|
-
editUser,
|
|
249
|
-
enableUser2fa,
|
|
250
|
-
generateDeploymentLogAnalysis,
|
|
251
|
-
generateToken,
|
|
252
|
-
get2FAQRCode,
|
|
253
|
-
getAllDeviceCounts,
|
|
254
|
-
getAllDevicesByStatus,
|
|
255
|
-
getAllDynamicGroupDevices,
|
|
256
|
-
getAllGroupDevices,
|
|
257
|
-
getArtifactInstallCount,
|
|
258
|
-
getArtifactUrl,
|
|
259
|
-
getAuditLogs,
|
|
260
|
-
getAuditLogsCsvLink,
|
|
261
|
-
getBillingPreview,
|
|
262
|
-
getCurrentCard,
|
|
263
|
-
getCurrentSubscription,
|
|
264
|
-
getDeltaGenerationJobDetails,
|
|
265
|
-
getDeltaGenerationJobs,
|
|
266
|
-
getDeploymentDevices,
|
|
267
|
-
getDeploymentsByStatus,
|
|
268
|
-
getDeploymentsConfig,
|
|
269
|
-
getDeviceAlerts,
|
|
270
|
-
getDeviceAttributes,
|
|
271
|
-
getDeviceAuth,
|
|
272
|
-
getDeviceById,
|
|
273
|
-
getDeviceConfig,
|
|
274
|
-
getDeviceConnect,
|
|
275
|
-
getDeviceDeployments,
|
|
276
|
-
getDeviceFileDownloadLink,
|
|
277
|
-
getDeviceInfo,
|
|
278
|
-
getDeviceLimits,
|
|
279
|
-
getDeviceLog,
|
|
280
|
-
getDeviceMonitorConfig,
|
|
281
|
-
getDeviceTwin,
|
|
282
|
-
getDevicesByStatus,
|
|
283
|
-
getDevicesWithAuth,
|
|
284
|
-
getDynamicGroup,
|
|
285
|
-
getDynamicGroups,
|
|
286
|
-
getExistingReleaseTags,
|
|
287
|
-
getGatewayDevices,
|
|
288
|
-
getGlobalSettings,
|
|
289
|
-
getGroupDevices,
|
|
290
|
-
getGroups,
|
|
291
|
-
getIntegrations,
|
|
292
|
-
getIssueCountsByType,
|
|
293
|
-
getLatestDeviceAlerts,
|
|
294
|
-
getLatestReleaseInfo,
|
|
295
|
-
getOnboardingState,
|
|
296
|
-
getPermissionSets,
|
|
297
|
-
getProducts,
|
|
298
|
-
getRelease,
|
|
299
|
-
getReleases,
|
|
300
|
-
getReportDataWithoutBackendSupport,
|
|
301
|
-
getRoles,
|
|
302
|
-
getSessionDetails,
|
|
303
|
-
getSingleDeployment,
|
|
304
|
-
getSsoConfigById,
|
|
305
|
-
getSsoConfigs,
|
|
306
|
-
getSystemDevices,
|
|
307
|
-
getTargetLocation,
|
|
308
|
-
getTenants,
|
|
309
|
-
getTokens,
|
|
310
|
-
getUpdateTypes,
|
|
311
|
-
getUser,
|
|
312
|
-
getUserBilling,
|
|
313
|
-
getUserList,
|
|
314
|
-
getUserOrganization,
|
|
315
|
-
getUserSettings,
|
|
316
|
-
getUserSubscription,
|
|
317
|
-
getWebhookEvents,
|
|
318
|
-
initializeSelf,
|
|
319
|
-
loginUser,
|
|
320
|
-
logoutUser,
|
|
321
|
-
normalizeRbacRoles,
|
|
322
|
-
passwordResetComplete,
|
|
323
|
-
passwordResetStart,
|
|
324
|
-
preauthDevice,
|
|
325
|
-
removeArtifact,
|
|
326
|
-
removeDevicesFromGroup,
|
|
327
|
-
removeDynamicGroup,
|
|
328
|
-
removeRelease,
|
|
329
|
-
removeReleases,
|
|
330
|
-
removeReportsByGroupName,
|
|
331
|
-
removeRole,
|
|
332
|
-
removeStaticGroup,
|
|
333
|
-
removeTenant,
|
|
334
|
-
removeUser,
|
|
335
|
-
requestPlanChange,
|
|
336
|
-
requestPlanUpgrade,
|
|
337
|
-
resetDeviceDeployments,
|
|
338
|
-
revokeToken,
|
|
339
|
-
saveDeltaDeploymentsConfig,
|
|
340
|
-
saveGlobalSettings,
|
|
341
|
-
saveUserSettings,
|
|
342
|
-
searchDevices,
|
|
343
|
-
selectGroup,
|
|
344
|
-
selectRelease,
|
|
345
|
-
sendSupportMessage,
|
|
346
|
-
setAllTooltipsReadState,
|
|
347
|
-
setAuditlogsState,
|
|
348
|
-
setDeploymentsState,
|
|
349
|
-
setDeviceConfig,
|
|
350
|
-
setDeviceListState,
|
|
351
|
-
setDeviceTags,
|
|
352
|
-
setDeviceTwin,
|
|
353
|
-
setFirstLoginAfterSignup,
|
|
354
|
-
setHideAnnouncement,
|
|
355
|
-
setOfflineThreshold,
|
|
356
|
-
setOnboardingApproach,
|
|
357
|
-
setOnboardingCanceled,
|
|
358
|
-
setOnboardingComplete,
|
|
359
|
-
setOnboardingDeviceType,
|
|
360
|
-
setReleaseTags,
|
|
361
|
-
setReleasesListState,
|
|
362
|
-
setReleasesTags,
|
|
363
|
-
setSearchState,
|
|
364
|
-
setSingleReleaseTags,
|
|
365
|
-
setTenantsListState,
|
|
366
|
-
setTooltipReadState,
|
|
367
|
-
startCardUpdate,
|
|
368
|
-
startUpgrade,
|
|
369
|
-
storeSsoConfig,
|
|
370
|
-
submitUserFeedback,
|
|
371
|
-
switchUserOrganization,
|
|
372
|
-
tenantDataDivergedMessage,
|
|
373
|
-
transformProductResponse,
|
|
374
|
-
triggerDeviceUpdate,
|
|
375
|
-
updateDeploymentControlMap,
|
|
376
|
-
updateDeviceAuth,
|
|
377
|
-
updateDevicesAuth,
|
|
378
|
-
updateDynamicGroup,
|
|
379
|
-
updateReleaseInfo,
|
|
380
|
-
updateReportData,
|
|
381
|
-
updateUserColumnSettings,
|
|
382
|
-
uploadArtifact,
|
|
383
|
-
verify2FA,
|
|
384
|
-
verifyEmailComplete,
|
|
385
|
-
verifyEmailStart
|
|
1
|
+
import { ADDONS, PLANS, locations } from "./appSlice/constants.js";
|
|
2
|
+
import { onboardingSteps, orderedOnboardingSteps } from "./onboardingSlice/constants.js";
|
|
3
|
+
import { rootfsImageVersion } from "./releasesSlice/constants.js";
|
|
4
|
+
import { ALL_DEVICE_STATES, ALL_RELEASES, APPLICATION_JSON_CONTENT_TYPE, APPLICATION_JWT_CONTENT_TYPE, DEPLOYMENT_ROUTES, DEPLOYMENT_STATES, DEPLOYMENT_TYPES, DEVICE_FILTERING_OPTIONS, DEVICE_LIST_DEFAULTS, DEVICE_STATES, EXTERNAL_PROVIDER, PermissionTypes, READ_STATES, SORTING_OPTIONS, SSO_TYPES, TENANT_LIST_DEFAULT, TIMEOUTS, UNGROUPED_GROUP, USER_LOGOUT, apiRoot, auditLogsApiUrl, defaultPermissionSets, deploymentPrototype, deploymentsApiUrl, deploymentsApiUrlV2, deviceAuthV2, deviceConfig, deviceConnect, emptyFilter, emptyRole, emptyUiPermissions, headerNames, inventoryApiUrl, inventoryApiUrlV2, iotManagerBaseURL, itemUiPermissionsReducer, maxSessionAge, rolesById, scopedPermissionAreas, settingsKeys, ssoIdpApiUrlv1, tenantadmApiUrlv1, tenantadmApiUrlv2, twoFAStates, uiPermissionsByArea, uiPermissionsById, useradmApiUrl, useradmApiUrlv2 } from "./constants.js";
|
|
5
|
+
import { actions } from "./appSlice/index.js";
|
|
6
|
+
import { actions as actions$1, sliceName as sliceName$1 } from "./deploymentsSlice/index.js";
|
|
7
|
+
import { actions as actions$2, sliceName as sliceName$2 } from "./devicesSlice/index.js";
|
|
8
|
+
import { actions as actions$3, sliceName as sliceName$3 } from "./onboardingSlice/index.js";
|
|
9
|
+
import { actions as actions$4, sliceName as sliceName$4 } from "./organizationSlice/index.js";
|
|
10
|
+
import { actions as actions$5, sliceName as sliceName$5 } from "./usersSlice/index.js";
|
|
11
|
+
import actions_default from "./actions.js";
|
|
12
|
+
import { cleanUp, getSessionInfo, setSessionInfo } from "./auth.js";
|
|
13
|
+
import { getFeatures, getHostedAnnouncement, getSearchState } from "./appSlice/selectors.js";
|
|
14
|
+
import { getDeploymentsById, getDeploymentsByStatus as getDeploymentsByStatus$1 } from "./deploymentsSlice/selectors.js";
|
|
15
|
+
import { getAcceptedDevices, getDeviceById as getDeviceById$1, getDeviceCountsByStatus, getDeviceFilters, getDeviceListState, getDeviceReports, getDevicesById, getGroupsById, getSelectedGroup } from "./devicesSlice/selectors.js";
|
|
16
|
+
import { getAuditlogState, getDeviceTwinIntegrations, getOrganization, getSpLimits, getTenantsList } from "./organizationSlice/selectors.js";
|
|
17
|
+
import { convertDeviceListStateToFilters, convertToBackendSPLimits, extractErrorMessage as extractErrorMessage$1, filtersFilter, getComparisonCompatibleVersion, mapDeviceAttributes, mapFiltersToTerms, mapTermsToFilters, mergePermissions, parseSubscriptionPreview, progress } from "./utils.js";
|
|
18
|
+
import { getCurrentUser, getGlobalSettings as getGlobalSettings$1, getIdAttribute, getOfflineThresholdSettings, getRolesById, getSelectedDeviceAttribute, getTooltipsState, getUserSettings as getUserSettings$1, getUsersById } from "./usersSlice/selectors.js";
|
|
19
|
+
import { getDeviceReportsForUser, getOnboardingState as getOnboardingState$1, getTenantCapabilities, getUserCapabilities } from "./commonSelectors.js";
|
|
20
|
+
import { commonErrorFallback, commonErrorHandler, createAppAsyncThunk } from "./store.js";
|
|
21
|
+
import Api from "./api/general-api.js";
|
|
22
|
+
import { changeNotificationSetting, getDeviceAlerts, getDeviceMonitorConfig, getIssueCountsByType, getLatestDeviceAlerts } from "./monitorSlice/thunks.js";
|
|
23
|
+
import { cancelFileUpload, createArtifact, editArtifact, getArtifactInstallCount, getArtifactUrl, getDeltaGenerationJobDetails, getDeltaGenerationJobs, getExistingReleaseTags, getRelease, getReleases, getUpdateTypes, removeArtifact, removeRelease, removeReleases, selectRelease, setReleaseTags, setReleasesListState, setReleasesTags, setSingleReleaseTags, updateReleaseInfo, uploadArtifact } from "./releasesSlice/thunks.js";
|
|
24
|
+
import Api$1 from "./api/users-api.js";
|
|
25
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
26
|
+
import { attributeDuplicateFilter, customSort, dateRangeToUnix, deepCompare, duplicateFilter, extractErrorMessage, getDemoDeviceAddress, getSnackbarMessage, isEmpty, standardizePhases } from "@northern.tech/utils/helpers";
|
|
27
|
+
import Cookies from "universal-cookie";
|
|
28
|
+
import dayjs from "dayjs";
|
|
29
|
+
import { Link } from "react-router-dom";
|
|
30
|
+
import { isCancel } from "axios";
|
|
31
|
+
import Tracking from "@northern.tech/utils/tracking";
|
|
32
|
+
import validator from "validator";
|
|
33
|
+
import pluralize from "pluralize";
|
|
34
|
+
import { v4 } from "uuid";
|
|
35
|
+
import utc from "dayjs/plugin/utc.js";
|
|
36
|
+
import hashString from "md5";
|
|
37
|
+
import { clearAllRetryTimers } from "@northern.tech/utils/retrytimer";
|
|
38
|
+
//#region src/appSlice/thunks.ts
|
|
39
|
+
const cookies$3 = new Cookies();
|
|
40
|
+
const setFirstLoginAfterSignup = createAppAsyncThunk(`app/setFirstLoginAfterSignup`, (firstLoginAfterSignup, { dispatch }) => {
|
|
41
|
+
cookies$3.set("firstLoginAfterSignup", !!firstLoginAfterSignup, {
|
|
42
|
+
maxAge: 60,
|
|
43
|
+
path: "/",
|
|
44
|
+
domain: ".mender.io",
|
|
45
|
+
sameSite: false
|
|
46
|
+
});
|
|
47
|
+
dispatch(actions.setFirstLoginAfterSignup(!!firstLoginAfterSignup));
|
|
48
|
+
});
|
|
49
|
+
const dateFunctionMap = {
|
|
50
|
+
getDays: "getDate",
|
|
51
|
+
setDays: "setDate"
|
|
386
52
|
};
|
|
53
|
+
const setOfflineThreshold = createAppAsyncThunk(`app/setOfflineThreshold`, async (_, { dispatch, getState }) => {
|
|
54
|
+
const { interval, intervalUnit } = getOfflineThresholdSettings(getState());
|
|
55
|
+
const today = /* @__PURE__ */ new Date();
|
|
56
|
+
const intervalName = `${intervalUnit.charAt(0).toUpperCase()}${intervalUnit.substring(1)}`;
|
|
57
|
+
const setter = dateFunctionMap[`set${intervalName}`] ?? `set${intervalName}`;
|
|
58
|
+
const getter = dateFunctionMap[`get${intervalName}`] ?? `get${intervalName}`;
|
|
59
|
+
today[setter](today[getter]() - interval);
|
|
60
|
+
let value;
|
|
61
|
+
try {
|
|
62
|
+
value = today.toISOString();
|
|
63
|
+
} catch {
|
|
64
|
+
dispatch(actions.setSnackbar("There was an error saving the offline threshold, please check your settings."));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
return dispatch(actions.setOfflineThreshold(value));
|
|
68
|
+
});
|
|
69
|
+
const versionRegex = /* @__PURE__ */ new RegExp(/\d+\.\d+/);
|
|
70
|
+
const getLatestRelease = (thing) => {
|
|
71
|
+
return thing[Object.keys(thing).filter((key) => versionRegex.test(key)).sort().reverse()[0]];
|
|
72
|
+
};
|
|
73
|
+
const repoKeyMap = {
|
|
74
|
+
integration: "Integration",
|
|
75
|
+
"mender-artifact": "Mender-Artifact"
|
|
76
|
+
};
|
|
77
|
+
const deductSaasState = (latestRelease, guiTags) => {
|
|
78
|
+
const latestGuiTag = guiTags.length ? guiTags[0].name : "";
|
|
79
|
+
return latestGuiTag ? latestGuiTag : latestRelease.release;
|
|
80
|
+
};
|
|
81
|
+
const getLatestReleaseInfo = createAppAsyncThunk(`app/getLatestReleaseInfo`, async (_, { dispatch, getState }) => {
|
|
82
|
+
if (!getFeatures(getState()).isHosted) return;
|
|
83
|
+
const [{ data }, { data: guiTags }] = await Promise.all([Api.get("/versions.json"), Api.get("/tags.json")]).catch((err) => {
|
|
84
|
+
console.log("init error:", extractErrorMessage(err));
|
|
85
|
+
return [{ data: {} }, { data: [] }];
|
|
86
|
+
});
|
|
87
|
+
if (!guiTags.length) return;
|
|
88
|
+
const { releases } = data;
|
|
89
|
+
const latestRelease = getLatestRelease(getLatestRelease(releases));
|
|
90
|
+
const { latestRepos, latestVersions } = latestRelease.repos.reduce((accu, item) => {
|
|
91
|
+
if (repoKeyMap[item.name]) accu.latestVersions[repoKeyMap[item.name]] = getComparisonCompatibleVersion(item.version);
|
|
92
|
+
accu.latestRepos[item.name] = getComparisonCompatibleVersion(item.version);
|
|
93
|
+
return accu;
|
|
94
|
+
}, {
|
|
95
|
+
latestVersions: { ...getState().app.versionInformation },
|
|
96
|
+
latestRepos: {}
|
|
97
|
+
});
|
|
98
|
+
const info = deductSaasState(latestRelease, guiTags);
|
|
99
|
+
return dispatch(actions.setVersionInformation({
|
|
100
|
+
...latestVersions,
|
|
101
|
+
Server: info,
|
|
102
|
+
latestRelease: {
|
|
103
|
+
releaseDate: latestRelease.release_date,
|
|
104
|
+
repos: latestRepos
|
|
105
|
+
}
|
|
106
|
+
}));
|
|
107
|
+
});
|
|
108
|
+
const setSearchState = createAppAsyncThunk(`app/setSearchState`, (searchState, { dispatch, getState }) => {
|
|
109
|
+
const currentState = getSearchState(getState());
|
|
110
|
+
const nextState = {
|
|
111
|
+
...currentState,
|
|
112
|
+
...searchState,
|
|
113
|
+
sort: {
|
|
114
|
+
...currentState.sort,
|
|
115
|
+
...searchState.sort
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const tasks = [];
|
|
119
|
+
const { isSearching: currentSearching, deviceIds: currentDevices, searchTotal: currentTotal, ...currentRequestState } = currentState;
|
|
120
|
+
const { isSearching: nextSearching, deviceIds: nextDevices, searchTotal: nextTotal, ...nextRequestState } = nextState;
|
|
121
|
+
if (nextRequestState.searchTerm && !deepCompare(currentRequestState, nextRequestState)) {
|
|
122
|
+
nextState.isSearching = true;
|
|
123
|
+
tasks.push(dispatch(searchDevices(nextState)).unwrap().then((searchResult) => dispatch(actions.setSearchState({
|
|
124
|
+
...searchResult,
|
|
125
|
+
isSearching: false
|
|
126
|
+
}))).catch(() => dispatch(actions.setSearchState({
|
|
127
|
+
isSearching: false,
|
|
128
|
+
searchTotal: 0
|
|
129
|
+
}))));
|
|
130
|
+
}
|
|
131
|
+
tasks.push(Promise.resolve(dispatch(actions.setSearchState(nextState))));
|
|
132
|
+
return Promise.all(tasks);
|
|
133
|
+
});
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/deploymentsSlice/thunks.ts
|
|
136
|
+
const { isUUID } = validator;
|
|
137
|
+
const { receivedDevice, setSnackbar: setSnackbar$3 } = actions_default;
|
|
138
|
+
const { page: defaultPage$2, perPage: defaultPerPage$2 } = DEVICE_LIST_DEFAULTS;
|
|
139
|
+
const deriveDeploymentGroup = ({ filter, group, groups = [], name }) => group || groups.length === 1 && !isUUID(name) ? groups[0] : filter?.name;
|
|
140
|
+
const transformDeployments = (deployments, deploymentsById) => deployments.sort(customSort(true, "created")).reduce((accu, item) => {
|
|
141
|
+
const filter = item.filter;
|
|
142
|
+
let deployment = {
|
|
143
|
+
...deploymentPrototype,
|
|
144
|
+
...deploymentsById[item.id],
|
|
145
|
+
...item,
|
|
146
|
+
filter: filter ? {
|
|
147
|
+
...filter,
|
|
148
|
+
name: filter.name ?? filter.id,
|
|
149
|
+
filters: mapTermsToFilters(filter.terms)
|
|
150
|
+
} : void 0,
|
|
151
|
+
name: decodeURIComponent(item.name)
|
|
152
|
+
};
|
|
153
|
+
deployment = {
|
|
154
|
+
...deployment,
|
|
155
|
+
group: deriveDeploymentGroup(deployment)
|
|
156
|
+
};
|
|
157
|
+
accu.deployments[item.id] = deployment;
|
|
158
|
+
accu.deploymentIds.push(item.id);
|
|
159
|
+
return accu;
|
|
160
|
+
}, {
|
|
161
|
+
deployments: {},
|
|
162
|
+
deploymentIds: []
|
|
163
|
+
});
|
|
164
|
+
const getDeploymentsByStatus = createAppAsyncThunk(`${sliceName$1}/getDeploymentsByStatus`, (options, { dispatch, getState }) => {
|
|
165
|
+
const { status, page = defaultPage$2, perPage = defaultPerPage$2, startDate, endDate, group, type, shouldSelect = true, sort = SORTING_OPTIONS.desc } = options;
|
|
166
|
+
const created_after = startDate ? `&created_after=${startDate}` : "";
|
|
167
|
+
const created_before = endDate ? `&created_before=${endDate}` : "";
|
|
168
|
+
const { attribute, scope } = getIdAttribute(getState());
|
|
169
|
+
const attributeHint = `&id_attribute=${attribute}&id_scope=${scope}`;
|
|
170
|
+
const search = group ? `&name=${group}${attributeHint}` : "";
|
|
171
|
+
const typeFilter = type ? `&type=${type}` : "";
|
|
172
|
+
return Api.get(`${deploymentsApiUrlV2}/deployments?status=${status}&per_page=${perPage}&page=${page}${created_after}${created_before}${search}${typeFilter}&sort=${sort}`).then((res) => {
|
|
173
|
+
const { deployments, deploymentIds } = transformDeployments(res.data, getState().deployments.byId);
|
|
174
|
+
const total = Number(res.headers[headerNames.total]);
|
|
175
|
+
const tasks = [Promise.resolve(dispatch(actions$1.receivedDeployments(deployments))), Promise.resolve(dispatch(actions$1.receivedDeploymentsForStatus({
|
|
176
|
+
deploymentIds,
|
|
177
|
+
status,
|
|
178
|
+
total: !(startDate || endDate || group || type) ? total : getState().deployments.byStatus[status].total
|
|
179
|
+
})))];
|
|
180
|
+
deploymentIds.forEach((deploymentId) => {
|
|
181
|
+
if (deployments[deploymentId].type === DEPLOYMENT_TYPES.configuration) tasks.push(dispatch(getSingleDeployment(deploymentId)).unwrap());
|
|
182
|
+
});
|
|
183
|
+
if (shouldSelect) tasks.push(Promise.resolve(dispatch(actions$1.selectDeploymentsForStatus({
|
|
184
|
+
deploymentIds,
|
|
185
|
+
status,
|
|
186
|
+
total
|
|
187
|
+
}))));
|
|
188
|
+
tasks.push(Promise.resolve({
|
|
189
|
+
deploymentIds,
|
|
190
|
+
total
|
|
191
|
+
}));
|
|
192
|
+
return Promise.all(tasks);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
const isWithinFirstMonth = (expirationDate) => {
|
|
196
|
+
if (!expirationDate) return false;
|
|
197
|
+
const endOfFirstMonth = new Date(expirationDate);
|
|
198
|
+
endOfFirstMonth.setMonth(endOfFirstMonth.getMonth() - 11);
|
|
199
|
+
return endOfFirstMonth > /* @__PURE__ */ new Date();
|
|
200
|
+
};
|
|
201
|
+
const trackDeploymentCreation = (totalDeploymentCount, hasDeployments, trial_expiration) => {
|
|
202
|
+
Tracking.event({
|
|
203
|
+
category: "deployments",
|
|
204
|
+
action: "create"
|
|
205
|
+
});
|
|
206
|
+
if (!totalDeploymentCount) {
|
|
207
|
+
if (!hasDeployments) {
|
|
208
|
+
Tracking.event({
|
|
209
|
+
category: "deployments",
|
|
210
|
+
action: "create_initial_deployment"
|
|
211
|
+
});
|
|
212
|
+
if (isWithinFirstMonth(trial_expiration)) Tracking.event({
|
|
213
|
+
category: "deployments",
|
|
214
|
+
action: "create_initial_deployment_first_month"
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
Tracking.event({
|
|
218
|
+
category: "deployments",
|
|
219
|
+
action: "create_initial_deployment_user"
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const MAX_PREVIOUS_PHASES_COUNT = 5;
|
|
224
|
+
const createDeployment = createAppAsyncThunk(`${sliceName$1}/createDeployment`, ({ newDeployment, hasNewRetryDefault = false }, { dispatch, getState }) => {
|
|
225
|
+
let request;
|
|
226
|
+
if ("filter_id" in newDeployment && newDeployment.filter_id) request = Api.post(`${deploymentsApiUrlV2}/deployments`, newDeployment);
|
|
227
|
+
else if ("group" in newDeployment && newDeployment.group) request = Api.post(`${deploymentsApiUrl}/deployments/group/${newDeployment.group}`, newDeployment);
|
|
228
|
+
else request = Api.post(`${deploymentsApiUrl}/deployments`, newDeployment);
|
|
229
|
+
const totalDeploymentCount = Object.values(getDeploymentsByStatus$1(getState())).reduce((accu, item) => accu + item.total, 0);
|
|
230
|
+
const { hasDeployments } = getGlobalSettings$1(getState());
|
|
231
|
+
const { trial_expiration } = getOrganization(getState());
|
|
232
|
+
return request.catch((err) => commonErrorHandler(err, "Error creating deployment.", dispatch)).then((data) => {
|
|
233
|
+
const lastslashindex = data.headers.location.lastIndexOf("/");
|
|
234
|
+
const deploymentId = data.headers.location.substring(lastslashindex + 1);
|
|
235
|
+
const deployment = {
|
|
236
|
+
...newDeployment,
|
|
237
|
+
id: deploymentId,
|
|
238
|
+
devices: "devices" in newDeployment && newDeployment.devices ? newDeployment.devices.map((id) => ({
|
|
239
|
+
id,
|
|
240
|
+
status: "pending"
|
|
241
|
+
})) : [],
|
|
242
|
+
statistics: { status: {} }
|
|
243
|
+
};
|
|
244
|
+
const tasks = [
|
|
245
|
+
Promise.resolve(dispatch(actions$1.createdDeployment(deployment))),
|
|
246
|
+
dispatch(getSingleDeployment(deploymentId)),
|
|
247
|
+
Promise.resolve(dispatch(setSnackbar$3({
|
|
248
|
+
message: "Deployment created successfully",
|
|
249
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
250
|
+
})))
|
|
251
|
+
];
|
|
252
|
+
trackDeploymentCreation(totalDeploymentCount, hasDeployments, trial_expiration);
|
|
253
|
+
const { canManageUsers } = getUserCapabilities(getState());
|
|
254
|
+
if (canManageUsers) {
|
|
255
|
+
const { phases, retries } = newDeployment;
|
|
256
|
+
const { previousPhases = [], retries: previousRetries = 0 } = getGlobalSettings$1(getState());
|
|
257
|
+
const newSettings = {
|
|
258
|
+
retries: hasNewRetryDefault ? retries : previousRetries,
|
|
259
|
+
hasDeployments: true
|
|
260
|
+
};
|
|
261
|
+
if (phases) {
|
|
262
|
+
const standardPhases = standardizePhases(phases);
|
|
263
|
+
const prevPhases = previousPhases.map(standardizePhases);
|
|
264
|
+
if (!prevPhases.find((previousPhaseList) => previousPhaseList.every((oldPhase) => standardPhases.find((phase) => deepCompare(phase, oldPhase))))) prevPhases.push(standardPhases);
|
|
265
|
+
newSettings.previousPhases = prevPhases.slice(-1 * MAX_PREVIOUS_PHASES_COUNT);
|
|
266
|
+
}
|
|
267
|
+
tasks.push(dispatch(saveGlobalSettings(newSettings)));
|
|
268
|
+
}
|
|
269
|
+
return Promise.all(tasks);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
const getDeploymentDevices = createAppAsyncThunk(`${sliceName$1}/getDeploymentDevices`, (options, { dispatch, getState }) => {
|
|
273
|
+
const { id, page = defaultPage$2, perPage = defaultPerPage$2 } = options;
|
|
274
|
+
return Api.get(`${deploymentsApiUrl}/deployments/${id}/devices/list?&page=${page}&per_page=${perPage}`).then((response) => {
|
|
275
|
+
const { devices: deploymentDevices = {} } = getState().deployments.byId[id] || {};
|
|
276
|
+
const devices = response.data.reduce((accu, item) => {
|
|
277
|
+
accu[item.id] = item;
|
|
278
|
+
const log = (deploymentDevices[item.id] || {}).log;
|
|
279
|
+
if (log) accu[item.id].log = log;
|
|
280
|
+
return accu;
|
|
281
|
+
}, {});
|
|
282
|
+
const selectedDeviceIds = Object.keys(devices);
|
|
283
|
+
const tasks = [Promise.resolve(dispatch(actions$1.receivedDeploymentDevices({
|
|
284
|
+
id,
|
|
285
|
+
devices,
|
|
286
|
+
selectedDeviceIds,
|
|
287
|
+
totalDeviceCount: Number(response.headers[headerNames.total])
|
|
288
|
+
})))];
|
|
289
|
+
const devicesById = getDevicesById(getState());
|
|
290
|
+
selectedDeviceIds.reduce((accu, deviceId) => {
|
|
291
|
+
const device = devicesById[deviceId];
|
|
292
|
+
if (!device || !device.identity_data || !device.attributes || Object.keys(device.attributes).length === 0) accu.push(deviceId);
|
|
293
|
+
return accu;
|
|
294
|
+
}, []).forEach((deviceId) => {
|
|
295
|
+
tasks.push(dispatch(getDeviceById(deviceId)).unwrap(), dispatch(getDeviceAuth(deviceId)).unwrap());
|
|
296
|
+
});
|
|
297
|
+
return Promise.all(tasks);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
const parseDeviceDeployment = ({ deployment: { id, artifact_name: release, status: deploymentStatus }, device: { created, deleted, id: deviceId, finished, status, log } }) => ({
|
|
301
|
+
id,
|
|
302
|
+
release,
|
|
303
|
+
created,
|
|
304
|
+
deleted,
|
|
305
|
+
deviceId,
|
|
306
|
+
finished,
|
|
307
|
+
status,
|
|
308
|
+
log,
|
|
309
|
+
route: Object.values(DEPLOYMENT_ROUTES).reduce((accu, { key, states }) => {
|
|
310
|
+
if (!accu) return states.includes(deploymentStatus) ? key : accu;
|
|
311
|
+
return accu;
|
|
312
|
+
}, "")
|
|
313
|
+
});
|
|
314
|
+
const getDeviceDeployments = createAppAsyncThunk(`${sliceName$1}/getDeviceDeployments`, (options, { dispatch }) => {
|
|
315
|
+
const { deviceId, filterSelection = [], page = defaultPage$2, perPage = defaultPerPage$2 } = options;
|
|
316
|
+
const filters = filterSelection.map((item) => `&status=${item}`).join("");
|
|
317
|
+
return Api.get(`${deploymentsApiUrl}/deployments/devices/${deviceId}?page=${page}&per_page=${perPage}${filters}`).then(({ data, headers }) => Promise.resolve(dispatch(receivedDevice({
|
|
318
|
+
id: deviceId,
|
|
319
|
+
deviceDeployments: data.map(parseDeviceDeployment),
|
|
320
|
+
deploymentsCount: Number(headers[headerNames.total])
|
|
321
|
+
})))).catch((err) => commonErrorHandler(err, "There was an error retrieving the device deployment history:", dispatch));
|
|
322
|
+
});
|
|
323
|
+
const resetDeviceDeployments = createAppAsyncThunk(`${sliceName$1}/resetDeviceDeployments`, (deviceId, { dispatch }) => Api.delete(`${deploymentsApiUrl}/deployments/devices/${deviceId}/history`).then(() => Promise.resolve(dispatch(getDeviceDeployments({ deviceId })))).catch((err) => commonErrorHandler(err, "There was an error resetting the device deployment history:", dispatch)));
|
|
324
|
+
const getSingleDeployment = createAppAsyncThunk(`${sliceName$1}/getSingleDeployment`, (id, { dispatch, getState }) => Api.get(`${deploymentsApiUrl}/deployments/${id}`).then(({ data }) => {
|
|
325
|
+
const { deployments } = transformDeployments([data], getState().deployments.byId);
|
|
326
|
+
return Promise.resolve(dispatch(actions$1.receivedDeployment(deployments[id])));
|
|
327
|
+
}));
|
|
328
|
+
const getDeviceLog = createAppAsyncThunk(`${sliceName$1}/getDeviceLog`, ({ deploymentId, deviceId }, { dispatch }) => Api.get(`${deploymentsApiUrl}/deployments/${deploymentId}/devices/${deviceId}/log`).catch((e) => {
|
|
329
|
+
console.log("no log here", e);
|
|
330
|
+
return Promise.reject();
|
|
331
|
+
}).then(({ data: log }) => Promise.all([Promise.resolve(dispatch(actions$1.receivedDeploymentDeviceLog({
|
|
332
|
+
id: deploymentId,
|
|
333
|
+
deviceId,
|
|
334
|
+
log
|
|
335
|
+
}))), Promise.resolve(log)])));
|
|
336
|
+
const abortDeployment = createAppAsyncThunk(`${sliceName$1}/abortDeployment`, (deploymentId, { dispatch, getState }) => Api.put(`${deploymentsApiUrl}/deployments/${deploymentId}/status`, { status: "aborted" }).then(() => {
|
|
337
|
+
const deploymentsByStatus = getDeploymentsByStatus$1(getState());
|
|
338
|
+
let status = DEPLOYMENT_STATES.pending;
|
|
339
|
+
let index = deploymentsByStatus.pending.deploymentIds.findIndex((id) => id === deploymentId);
|
|
340
|
+
if (index < 0) {
|
|
341
|
+
status = DEPLOYMENT_STATES.inprogress;
|
|
342
|
+
index = deploymentsByStatus.inprogress.deploymentIds.findIndex((id) => id === deploymentId);
|
|
343
|
+
}
|
|
344
|
+
const deploymentIds = [...deploymentsByStatus[status].deploymentIds.slice(0, index), ...deploymentsByStatus[status].deploymentIds.slice(index + 1)];
|
|
345
|
+
const deploymentsById = getDeploymentsById(getState());
|
|
346
|
+
const deployments = deploymentIds.reduce((accu, id) => {
|
|
347
|
+
accu[id] = deploymentsById[id];
|
|
348
|
+
return accu;
|
|
349
|
+
}, {});
|
|
350
|
+
const total = Math.max(deploymentsByStatus[status].total - 1, 0);
|
|
351
|
+
return Promise.all([
|
|
352
|
+
dispatch(actions$1.receivedDeployments(deployments)),
|
|
353
|
+
dispatch(actions$1.receivedDeploymentsForStatus({
|
|
354
|
+
deploymentIds,
|
|
355
|
+
status,
|
|
356
|
+
total
|
|
357
|
+
})),
|
|
358
|
+
dispatch(actions$1.removedDeployment(deploymentId)),
|
|
359
|
+
dispatch(setSnackbar$3("The deployment was successfully aborted"))
|
|
360
|
+
]);
|
|
361
|
+
}).catch((err) => commonErrorHandler(err, "There was an error while aborting the deployment:", dispatch)));
|
|
362
|
+
const updateDeploymentControlMap = createAppAsyncThunk(`${sliceName$1}/updateDeploymentControlMap`, ({ deploymentId, updateControlMap }, { dispatch }) => Api.patch(`${deploymentsApiUrl}/deployments/${deploymentId}`, { update_control_map: updateControlMap }).catch((err) => commonErrorHandler(err, "There was an error while updating the deployment status:", dispatch)).then(() => Promise.resolve(dispatch(getSingleDeployment(deploymentId)))));
|
|
363
|
+
const setDeploymentsState = createAppAsyncThunk(`${sliceName$1}/setDeploymentsState`, (selection, { dispatch, getState }) => {
|
|
364
|
+
const { page, perPage, ...selectionState } = selection;
|
|
365
|
+
const currentState = getState().deployments.selectionState;
|
|
366
|
+
const nextState = {
|
|
367
|
+
...currentState,
|
|
368
|
+
...selectionState,
|
|
369
|
+
...Object.keys(DEPLOYMENT_STATES).reduce((accu, item) => {
|
|
370
|
+
accu[item] = {
|
|
371
|
+
...currentState[item],
|
|
372
|
+
...selectionState[item]
|
|
373
|
+
};
|
|
374
|
+
return accu;
|
|
375
|
+
}, {}),
|
|
376
|
+
general: {
|
|
377
|
+
...currentState.general,
|
|
378
|
+
...selectionState.general
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
const tasks = [Promise.resolve(dispatch(actions$1.setDeploymentsState(nextState)))];
|
|
382
|
+
if (nextState.selectedId && currentState.selectedId !== nextState.selectedId) tasks.push(dispatch(getSingleDeployment(nextState.selectedId)));
|
|
383
|
+
return Promise.all(tasks);
|
|
384
|
+
});
|
|
385
|
+
const deltaAttributeMappings = [
|
|
386
|
+
{
|
|
387
|
+
here: "compressionLevel",
|
|
388
|
+
there: "compression_level"
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
here: "disableChecksum",
|
|
392
|
+
there: "disable_checksum"
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
here: "disableDecompression",
|
|
396
|
+
there: "disable_external_decompression"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
here: "sourceWindow",
|
|
400
|
+
there: "source_window_size"
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
here: "inputWindow",
|
|
404
|
+
there: "input_window_size"
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
here: "duplicatesWindow",
|
|
408
|
+
there: "compression_duplicates_window"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
here: "instructionBuffer",
|
|
412
|
+
there: "instruction_buffer_size"
|
|
413
|
+
}
|
|
414
|
+
];
|
|
415
|
+
const mapExternalDeltaConfig = (config = {}) => deltaAttributeMappings.reduce((accu, { here, there }) => {
|
|
416
|
+
if (config[there] !== void 0) accu[here] = config[there];
|
|
417
|
+
return accu;
|
|
418
|
+
}, {});
|
|
419
|
+
const getDeploymentsConfig = createAppAsyncThunk(`${sliceName$1}/getDeploymentsConfig`, (_, { dispatch, getState }) => Api.get(`${deploymentsApiUrl}/config`).then(({ data }) => {
|
|
420
|
+
const oldConfig = getState().deployments.config;
|
|
421
|
+
const { delta = {} } = data;
|
|
422
|
+
const { binary_delta = {}, binary_delta_limits = {} } = delta;
|
|
423
|
+
const { xdelta_args = {} } = binary_delta;
|
|
424
|
+
const { xdelta_args_limits = {} } = binary_delta_limits;
|
|
425
|
+
const config = {
|
|
426
|
+
...oldConfig,
|
|
427
|
+
hasDelta: Boolean(delta.enabled),
|
|
428
|
+
binaryDelta: {
|
|
429
|
+
...oldConfig.binaryDelta,
|
|
430
|
+
...mapExternalDeltaConfig(xdelta_args)
|
|
431
|
+
},
|
|
432
|
+
binaryDeltaLimits: {
|
|
433
|
+
...oldConfig.binaryDeltaLimits,
|
|
434
|
+
...mapExternalDeltaConfig(xdelta_args_limits)
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
return Promise.resolve(dispatch(actions$1.setDeploymentsConfig(config)));
|
|
438
|
+
}));
|
|
439
|
+
const deepClean = (source) => Object.entries(source).reduce((accu, [key, value]) => {
|
|
440
|
+
if (value !== void 0) {
|
|
441
|
+
const cleanedValue = typeof value === "object" ? deepClean(value) : value;
|
|
442
|
+
if (cleanedValue === void 0 || typeof cleanedValue === "object" && isEmpty(cleanedValue)) return accu;
|
|
443
|
+
accu = {
|
|
444
|
+
...accu ?? {},
|
|
445
|
+
[key]: cleanedValue
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
return accu;
|
|
449
|
+
}, void 0);
|
|
450
|
+
const saveDeltaDeploymentsConfig = createAppAsyncThunk(`${sliceName$1}/saveDeltaDeploymentsConfig`, (config, { dispatch, getState }) => {
|
|
451
|
+
const result = deepClean({ xdelta_args: deltaAttributeMappings.reduce((accu, { here, there }) => {
|
|
452
|
+
if (config[here] !== void 0) accu[there] = config[here];
|
|
453
|
+
return accu;
|
|
454
|
+
}, {}) });
|
|
455
|
+
if (!result) return Promise.resolve();
|
|
456
|
+
return Api.put(`${deploymentsApiUrl}/config/binary_delta`, result).catch((err) => commonErrorHandler(err, "There was a problem storing your delta artifact generation configuration.", dispatch)).then(() => {
|
|
457
|
+
const oldConfig = getState().deployments.config;
|
|
458
|
+
const newConfig = {
|
|
459
|
+
...oldConfig,
|
|
460
|
+
binaryDelta: {
|
|
461
|
+
...oldConfig.binaryDelta,
|
|
462
|
+
...config
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
return Promise.all([dispatch(actions$1.setDeploymentsConfig(newConfig)), dispatch(setSnackbar$3("Settings saved successfully"))]);
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
const generateDeploymentLogAnalysis = createAppAsyncThunk(`${sliceName$1}/generateDeploymentLogAnalysis`, ({ deploymentId, deviceId }, { dispatch, rejectWithValue }) => Api.get(`${apiRoot}/v1alpha1/deployments/deployments/${deploymentId}/devices/${deviceId}/log/explain`, { timeout: 60 * TIMEOUTS.oneSecond }).then(({ data: result }) => Promise.resolve(result)).catch((err) => {
|
|
469
|
+
if (err.response.status === 429) return rejectWithValue(err.response);
|
|
470
|
+
commonErrorHandler(err, "There was an error analysing the deployment log:", dispatch);
|
|
471
|
+
}));
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/devicesSlice/thunks.tsx
|
|
474
|
+
const { cleanUpUpload, initUpload, setSnackbar: setSnackbar$2, uploadProgress } = actions_default;
|
|
475
|
+
const { page: defaultPage$1, perPage: defaultPerPage$1 } = DEVICE_LIST_DEFAULTS;
|
|
476
|
+
const defaultAttributes = [
|
|
477
|
+
{
|
|
478
|
+
scope: "identity",
|
|
479
|
+
attribute: "status"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
scope: "inventory",
|
|
483
|
+
attribute: "artifact_name"
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
scope: "inventory",
|
|
487
|
+
attribute: "device_type"
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
scope: "inventory",
|
|
491
|
+
attribute: "mender_is_gateway"
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
scope: "inventory",
|
|
495
|
+
attribute: "mender_gateway_system_id"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
scope: "inventory",
|
|
499
|
+
attribute: rootfsImageVersion
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
scope: "monitor",
|
|
503
|
+
attribute: "alerts"
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
scope: "system",
|
|
507
|
+
attribute: "created_ts"
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
scope: "system",
|
|
511
|
+
attribute: "updated_ts"
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
scope: "system",
|
|
515
|
+
attribute: "check_in_time"
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
scope: "system",
|
|
519
|
+
attribute: "group"
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
scope: "tags",
|
|
523
|
+
attribute: "name"
|
|
524
|
+
}
|
|
525
|
+
];
|
|
526
|
+
const getGroups = createAppAsyncThunk(`${sliceName$2}/getGroups`, async (_, { dispatch, getState }) => {
|
|
527
|
+
const res = await Api.get(`${inventoryApiUrl}/groups`);
|
|
528
|
+
const state = getGroupsById(getState());
|
|
529
|
+
const dynamicGroups = Object.entries(state).reduce((accu, [id, group]) => {
|
|
530
|
+
if (group.id || group.filters?.length && id !== UNGROUPED_GROUP.id) accu[id] = group;
|
|
531
|
+
return accu;
|
|
532
|
+
}, {});
|
|
533
|
+
const groups = res.data.reduce((accu, group) => {
|
|
534
|
+
accu[group] = {
|
|
535
|
+
deviceIds: [],
|
|
536
|
+
filters: [],
|
|
537
|
+
total: 0,
|
|
538
|
+
...state[group]
|
|
539
|
+
};
|
|
540
|
+
return accu;
|
|
541
|
+
}, dynamicGroups);
|
|
542
|
+
const filters = [{
|
|
543
|
+
key: "group",
|
|
544
|
+
value: res.data,
|
|
545
|
+
operator: DEVICE_FILTERING_OPTIONS.$nin.key,
|
|
546
|
+
scope: "system"
|
|
547
|
+
}];
|
|
548
|
+
const [, devicesRetrieval] = await Promise.all([dispatch(actions$2.receivedGroups(groups)), dispatch(getDevicesByStatus({
|
|
549
|
+
filterSelection: filters,
|
|
550
|
+
group: "",
|
|
551
|
+
page: 1,
|
|
552
|
+
perPage: 1,
|
|
553
|
+
status: void 0
|
|
554
|
+
}))]);
|
|
555
|
+
const { total } = devicesRetrieval?.payload ?? {};
|
|
556
|
+
if (!total) return;
|
|
557
|
+
return dispatch(actions$2.addGroup({
|
|
558
|
+
groupName: UNGROUPED_GROUP.id,
|
|
559
|
+
group: { filters: [{
|
|
560
|
+
key: "group",
|
|
561
|
+
value: res.data,
|
|
562
|
+
operator: DEVICE_FILTERING_OPTIONS.$nin.key,
|
|
563
|
+
scope: "system"
|
|
564
|
+
}] }
|
|
565
|
+
}));
|
|
566
|
+
});
|
|
567
|
+
const addDevicesToGroup = createAppAsyncThunk(`${sliceName$2}/addDevicesToGroup`, ({ group, deviceIds, isCreation }, { dispatch }) => Api.patch(`${inventoryApiUrl}/groups/${group}/devices`, deviceIds).then(() => dispatch(actions$2.addToGroup({
|
|
568
|
+
group,
|
|
569
|
+
deviceIds
|
|
570
|
+
}))).finally(() => isCreation ? Promise.resolve(dispatch(getGroups())) : {}));
|
|
571
|
+
const removeDevicesFromGroup = createAppAsyncThunk(`${sliceName$2}/removeDevicesFromGroup`, ({ group, deviceIds }, { dispatch }) => Api.delete(`${inventoryApiUrl}/groups/${group}/devices`, deviceIds).then(() => Promise.all([dispatch(actions$2.removeFromGroup({
|
|
572
|
+
group,
|
|
573
|
+
deviceIds
|
|
574
|
+
})), dispatch(setSnackbar$2({
|
|
575
|
+
message: `The ${pluralize("devices", deviceIds.length)} ${pluralize("were", deviceIds.length)} removed from the group`,
|
|
576
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
577
|
+
}))])));
|
|
578
|
+
const getGroupNotification = (newGroup, selectedGroup) => {
|
|
579
|
+
const successMessage = "The group was updated successfully";
|
|
580
|
+
if (newGroup === selectedGroup) return {
|
|
581
|
+
message: successMessage,
|
|
582
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
583
|
+
};
|
|
584
|
+
return {
|
|
585
|
+
action: "",
|
|
586
|
+
autoHideDuration: TIMEOUTS.fiveSeconds,
|
|
587
|
+
message: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
588
|
+
successMessage,
|
|
589
|
+
" - ",
|
|
590
|
+
/* @__PURE__ */ jsx(Link, {
|
|
591
|
+
to: `/devices?inventory=group:eq:${newGroup}`,
|
|
592
|
+
children: "click here"
|
|
593
|
+
}),
|
|
594
|
+
" to see it."
|
|
595
|
+
] }),
|
|
596
|
+
preventClickToCopy: true
|
|
597
|
+
};
|
|
598
|
+
};
|
|
599
|
+
const addStaticGroup = createAppAsyncThunk(`${sliceName$2}/addStaticGroup`, ({ group, devices }, { dispatch, getState }) => Promise.resolve(dispatch(addDevicesToGroup({
|
|
600
|
+
group,
|
|
601
|
+
deviceIds: devices.map(({ id }) => id),
|
|
602
|
+
isCreation: true
|
|
603
|
+
}))).then(() => Promise.resolve(dispatch(actions$2.addGroup({
|
|
604
|
+
group: {
|
|
605
|
+
deviceIds: [],
|
|
606
|
+
total: 0,
|
|
607
|
+
filters: [],
|
|
608
|
+
...getState().devices.groups.byId[group]
|
|
609
|
+
},
|
|
610
|
+
groupName: group
|
|
611
|
+
}))).then(() => Promise.all([
|
|
612
|
+
dispatch(setDeviceListState({ setOnly: true })),
|
|
613
|
+
dispatch(getGroups()),
|
|
614
|
+
dispatch(setSnackbar$2(getGroupNotification(group, getState().devices.groups.selectedGroup)))
|
|
615
|
+
]))).catch((err) => commonErrorHandler(err, `Group could not be updated:`, dispatch)));
|
|
616
|
+
const removeReportsByGroupName = createAppAsyncThunk(`${sliceName$2}/removeReportsByGroupName`, (groupName, { dispatch, getState }) => {
|
|
617
|
+
if (!groupName) return Promise.resolve();
|
|
618
|
+
dispatch(saveUserSettings({ reports: getDeviceReportsForUser(getState()).filter((report) => report.group !== groupName) }));
|
|
619
|
+
});
|
|
620
|
+
const removeStaticGroup = createAppAsyncThunk(`${sliceName$2}/removeStaticGroup`, (groupName, { dispatch }) => Api.delete(`${inventoryApiUrl}/groups/${groupName}`).then(() => Promise.all([
|
|
621
|
+
dispatch(actions$2.removeGroup(groupName)),
|
|
622
|
+
dispatch(removeReportsByGroupName(groupName)),
|
|
623
|
+
dispatch(getGroups()),
|
|
624
|
+
dispatch(setSnackbar$2({
|
|
625
|
+
message: "Group was removed successfully",
|
|
626
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
627
|
+
}))
|
|
628
|
+
])));
|
|
629
|
+
const getDynamicGroup = createAppAsyncThunk(`${sliceName$2}/getDynamicGroupById`, (id, { dispatch }) => Api.get(`${inventoryApiUrlV2}/filters/${id}`).catch((err) => {
|
|
630
|
+
if (err.response && err.response.status === 404) throw new Error("Request failed with status code 404");
|
|
631
|
+
return commonErrorHandler(err, `Error retrieving the group: `, dispatch, commonErrorFallback);
|
|
632
|
+
}));
|
|
633
|
+
const getDynamicGroups = createAppAsyncThunk(`${sliceName$2}/getDynamicGroups`, (_, { dispatch, getState }) => Api.get(`${inventoryApiUrlV2}/filters?per_page=500`).then(({ data: filters }) => {
|
|
634
|
+
const state = getGroupsById(getState());
|
|
635
|
+
const staticGroups = Object.entries(state).reduce((accu, [id, group]) => {
|
|
636
|
+
if (!(group.id || group.filters?.length)) accu[id] = group;
|
|
637
|
+
return accu;
|
|
638
|
+
}, {});
|
|
639
|
+
const groups = (filters || []).reduce((accu, filter) => {
|
|
640
|
+
accu[filter.name] = {
|
|
641
|
+
deviceIds: [],
|
|
642
|
+
total: 0,
|
|
643
|
+
...state[filter.name],
|
|
644
|
+
id: filter.id,
|
|
645
|
+
filters: mapTermsToFilters(filter.terms)
|
|
646
|
+
};
|
|
647
|
+
return accu;
|
|
648
|
+
}, staticGroups);
|
|
649
|
+
return Promise.resolve(dispatch(actions$2.receivedGroups(groups)));
|
|
650
|
+
}).catch(() => console.log("Dynamic group retrieval failed - likely accessing a non-enterprise backend")));
|
|
651
|
+
const addDynamicGroup = createAppAsyncThunk(`${sliceName$2}/addDynamicGroup`, ({ groupName, filterPredicates }, { dispatch, getState }) => Api.post(`${inventoryApiUrlV2}/filters`, {
|
|
652
|
+
name: groupName,
|
|
653
|
+
terms: mapFiltersToTerms(filterPredicates)
|
|
654
|
+
}).then((res) => Promise.resolve(dispatch(actions$2.addGroup({
|
|
655
|
+
groupName,
|
|
656
|
+
group: {
|
|
657
|
+
id: res.headers[headerNames.location].substring(res.headers[headerNames.location].lastIndexOf("/") + 1),
|
|
658
|
+
filters: filterPredicates
|
|
659
|
+
}
|
|
660
|
+
}))).then(() => {
|
|
661
|
+
const { cleanedFilters } = getGroupFilters(groupName, getState().devices.groups);
|
|
662
|
+
return Promise.all([
|
|
663
|
+
dispatch(actions$2.setDeviceFilters(cleanedFilters)),
|
|
664
|
+
dispatch(setSnackbar$2(getGroupNotification(groupName, getState().devices.groups.selectedGroup))),
|
|
665
|
+
dispatch(getDynamicGroups())
|
|
666
|
+
]);
|
|
667
|
+
})).catch((err) => commonErrorHandler(err, `Group could not be updated:`, dispatch)));
|
|
668
|
+
const updateDynamicGroup = createAppAsyncThunk(`${sliceName$2}/updateDynamicGroup`, ({ groupName, filterPredicates }, { dispatch, getState }) => {
|
|
669
|
+
const filterId = getState().devices.groups.byId[groupName].id;
|
|
670
|
+
return Api.delete(`${inventoryApiUrlV2}/filters/${filterId}`).then(() => dispatch(addDynamicGroup({
|
|
671
|
+
groupName,
|
|
672
|
+
filterPredicates
|
|
673
|
+
})).unwrap());
|
|
674
|
+
});
|
|
675
|
+
const removeDynamicGroup = createAppAsyncThunk(`${sliceName$2}/removeDynamicGroup`, (groupName, { dispatch, getState }) => {
|
|
676
|
+
const filterId = getState().devices.groups.byId[groupName].id;
|
|
677
|
+
return Api.delete(`${inventoryApiUrlV2}/filters/${filterId}`).then(() => Promise.all([
|
|
678
|
+
dispatch(actions$2.removeGroup(groupName)),
|
|
679
|
+
dispatch(removeReportsByGroupName(groupName)),
|
|
680
|
+
dispatch(setSnackbar$2({
|
|
681
|
+
message: "Group was removed successfully",
|
|
682
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
683
|
+
}))
|
|
684
|
+
]));
|
|
685
|
+
});
|
|
686
|
+
const getGroupFilters = (group, groupsState, filters = []) => {
|
|
687
|
+
const groupName = group === UNGROUPED_GROUP.id || group === UNGROUPED_GROUP.name ? UNGROUPED_GROUP.id : group;
|
|
688
|
+
const selectedGroup = groupsState.byId[groupName];
|
|
689
|
+
const groupFilterLength = selectedGroup?.filters?.length || 0;
|
|
690
|
+
return {
|
|
691
|
+
cleanedFilters: groupFilterLength ? [...filters, ...selectedGroup.filters || []].filter(filtersFilter) : filters,
|
|
692
|
+
groupName,
|
|
693
|
+
selectedGroup,
|
|
694
|
+
groupFilterLength
|
|
695
|
+
};
|
|
696
|
+
};
|
|
697
|
+
const selectGroup = createAppAsyncThunk(`${sliceName$2}/selectGroup`, ({ group, filters = [] }, { dispatch, getState }) => {
|
|
698
|
+
const { cleanedFilters, groupName, selectedGroup, groupFilterLength } = getGroupFilters(group, getState().devices.groups, filters);
|
|
699
|
+
if (getSelectedGroup(getState()) === groupName && (filters.length === 0 && !groupFilterLength || filters.length === cleanedFilters.length)) return Promise.resolve();
|
|
700
|
+
const tasks = [];
|
|
701
|
+
if (groupFilterLength) tasks.push(Promise.resolve(dispatch(actions$2.setDeviceFilters(cleanedFilters))));
|
|
702
|
+
else {
|
|
703
|
+
tasks.push(Promise.resolve(dispatch(actions$2.setDeviceFilters(filters))));
|
|
704
|
+
tasks.push(dispatch(getGroupDevices({
|
|
705
|
+
group: groupName,
|
|
706
|
+
perPage: 1,
|
|
707
|
+
shouldIncludeAllStates: true
|
|
708
|
+
})));
|
|
709
|
+
}
|
|
710
|
+
const selectedGroupName = selectedGroup || !Object.keys(getGroupsById(getState())).length ? groupName : void 0;
|
|
711
|
+
tasks.push(Promise.resolve(dispatch(actions$2.selectGroup(selectedGroupName))));
|
|
712
|
+
return Promise.all(tasks);
|
|
713
|
+
});
|
|
714
|
+
const getEarliestTs = (dateA = "", dateB = "") => !dateA || !dateB ? dateA || dateB : dateA < dateB ? dateA : dateB;
|
|
715
|
+
const reduceReceivedDevices = (devices, ids, state, status) => devices.reduce((accu, device) => {
|
|
716
|
+
const stateDevice = getDeviceById$1(state, device.id);
|
|
717
|
+
const { attributes: storedAttributes = {}, identity_data: storedIdentity = {}, monitor: storedMonitor = {}, tags: storedTags = {}, group: storedGroup } = stateDevice;
|
|
718
|
+
const { identity, inventory, monitor, system = {}, tags } = mapDeviceAttributes(device.attributes);
|
|
719
|
+
device.tags = {
|
|
720
|
+
...storedTags,
|
|
721
|
+
...tags
|
|
722
|
+
};
|
|
723
|
+
device.group = system.group ?? storedGroup;
|
|
724
|
+
device.monitor = {
|
|
725
|
+
...storedMonitor,
|
|
726
|
+
...monitor
|
|
727
|
+
};
|
|
728
|
+
device.identity_data = {
|
|
729
|
+
...storedIdentity,
|
|
730
|
+
...identity,
|
|
731
|
+
...device.identity_data ? device.identity_data : {}
|
|
732
|
+
};
|
|
733
|
+
device.status = status ? status : device.status || identity.status;
|
|
734
|
+
device.check_in_time_rounded = system.check_in_time ?? stateDevice.check_in_time_rounded;
|
|
735
|
+
device.check_in_time_exact = device.check_in_time ?? stateDevice.check_in_time_exact;
|
|
736
|
+
device.created_ts = getEarliestTs(getEarliestTs(system.created_ts, device.created_ts), stateDevice.created_ts);
|
|
737
|
+
device.updated_ts = device.attributes ? device.updated_ts : stateDevice.updated_ts;
|
|
738
|
+
device.isNew = new Date(device.created_ts) > new Date(state.app.newThreshold);
|
|
739
|
+
device.isOffline = new Date(device.check_in_time_rounded) < new Date(state.app.offlineThreshold) || device.check_in_time_rounded === void 0;
|
|
740
|
+
device.attributes = device.attributes ? {
|
|
741
|
+
...storedAttributes,
|
|
742
|
+
...inventory
|
|
743
|
+
} : storedAttributes;
|
|
744
|
+
accu.devicesById[device.id] = {
|
|
745
|
+
...stateDevice,
|
|
746
|
+
...device
|
|
747
|
+
};
|
|
748
|
+
accu.ids.push(device.id);
|
|
749
|
+
return accu;
|
|
750
|
+
}, {
|
|
751
|
+
ids,
|
|
752
|
+
devicesById: {}
|
|
753
|
+
});
|
|
754
|
+
const getGroupDevices = createAppAsyncThunk(`${sliceName$2}/getGroupDevices`, async (options, { dispatch, getState }) => {
|
|
755
|
+
const { group, shouldIncludeAllStates, ...remainder } = options;
|
|
756
|
+
const { cleanedFilters: filterSelection } = getGroupFilters(group, getState().devices.groups);
|
|
757
|
+
const { deviceAccu, total } = await dispatch(getDevicesByStatus({
|
|
758
|
+
...remainder,
|
|
759
|
+
filterSelection,
|
|
760
|
+
group,
|
|
761
|
+
status: shouldIncludeAllStates ? void 0 : DEVICE_STATES.accepted
|
|
762
|
+
})).unwrap();
|
|
763
|
+
if (!group) return;
|
|
764
|
+
const stateGroup = getState().devices.groups.byId[group];
|
|
765
|
+
if (!stateGroup && !total && !deviceAccu.ids.length) return;
|
|
766
|
+
return dispatch(actions$2.addGroup({
|
|
767
|
+
group: {
|
|
768
|
+
deviceIds: deviceAccu.ids.length === total || stateGroup && stateGroup.deviceIds && deviceAccu.ids.length > stateGroup.deviceIds.length ? deviceAccu.ids : stateGroup.deviceIds,
|
|
769
|
+
total
|
|
770
|
+
},
|
|
771
|
+
groupName: group
|
|
772
|
+
}));
|
|
773
|
+
});
|
|
774
|
+
const getAllGroupDevices = createAppAsyncThunk(`${sliceName$2}/getAllGroupDevices`, ({ group, attribute }, { dispatch, getState }) => {
|
|
775
|
+
if (!group || !!group && (!getGroupsById(getState())[group] || getGroupsById(getState())[group].filters.length)) return Promise.resolve();
|
|
776
|
+
const { attributes, filterTerms } = prepareSearchArguments({
|
|
777
|
+
filters: [],
|
|
778
|
+
group,
|
|
779
|
+
state: getState(),
|
|
780
|
+
status: DEVICE_STATES.accepted
|
|
781
|
+
});
|
|
782
|
+
const getAllDevices = (perPage = 500, page = defaultPage$1, devices = []) => Api.post(`${inventoryApiUrlV2}/filters/search`, {
|
|
783
|
+
page,
|
|
784
|
+
per_page: perPage,
|
|
785
|
+
filters: filterTerms,
|
|
786
|
+
attributes: [...attributes, {
|
|
787
|
+
scope: "inventory",
|
|
788
|
+
attribute
|
|
789
|
+
}]
|
|
790
|
+
}).then((res) => {
|
|
791
|
+
const state = getState();
|
|
792
|
+
const deviceAccu = reduceReceivedDevices(res.data, devices, state);
|
|
793
|
+
dispatch(actions$2.receivedDevices(deviceAccu.devicesById));
|
|
794
|
+
if (Number(res.headers[headerNames.total]) > perPage * page) return getAllDevices(perPage, page + 1, deviceAccu.ids);
|
|
795
|
+
return Promise.resolve(dispatch(actions$2.addGroup({
|
|
796
|
+
group: {
|
|
797
|
+
deviceIds: deviceAccu.ids,
|
|
798
|
+
total: deviceAccu.ids.length
|
|
799
|
+
},
|
|
800
|
+
groupName: group
|
|
801
|
+
})));
|
|
802
|
+
});
|
|
803
|
+
return getAllDevices();
|
|
804
|
+
});
|
|
805
|
+
const getAllDynamicGroupDevices = createAppAsyncThunk(`${sliceName$2}/getAllDynamicGroupDevices`, ({ group, attribute }, { dispatch, getState }) => {
|
|
806
|
+
if (!!group && (!getGroupsById(getState())[group] || !getGroupsById(getState())[group].filters.length)) return Promise.resolve();
|
|
807
|
+
const { attributes, filterTerms: filters } = prepareSearchArguments({
|
|
808
|
+
filters: getState().devices.groups.byId[group].filters,
|
|
809
|
+
state: getState(),
|
|
810
|
+
status: DEVICE_STATES.accepted
|
|
811
|
+
});
|
|
812
|
+
const getAllDevices = (perPage = 500, page = defaultPage$1, devices = []) => Api.post(`${inventoryApiUrlV2}/filters/search`, {
|
|
813
|
+
page,
|
|
814
|
+
per_page: perPage,
|
|
815
|
+
filters,
|
|
816
|
+
attributes: [...attributes, {
|
|
817
|
+
scope: "inventory",
|
|
818
|
+
attribute
|
|
819
|
+
}]
|
|
820
|
+
}).then((res) => {
|
|
821
|
+
const state = getState();
|
|
822
|
+
const deviceAccu = reduceReceivedDevices(res.data, devices, state);
|
|
823
|
+
dispatch(actions$2.receivedDevices(deviceAccu.devicesById));
|
|
824
|
+
const total = Number(res.headers[headerNames.total]);
|
|
825
|
+
if (total > deviceAccu.ids.length) return getAllDevices(perPage, page + 1, deviceAccu.ids);
|
|
826
|
+
return Promise.resolve(dispatch(actions$2.addGroup({
|
|
827
|
+
group: {
|
|
828
|
+
deviceIds: deviceAccu.ids,
|
|
829
|
+
total
|
|
830
|
+
},
|
|
831
|
+
groupName: group
|
|
832
|
+
})));
|
|
833
|
+
});
|
|
834
|
+
return getAllDevices();
|
|
835
|
+
});
|
|
836
|
+
const getDeviceById = createAppAsyncThunk(`${sliceName$2}/getDeviceById`, (id, { dispatch, getState }) => Api.get(`${inventoryApiUrl}/devices/${id}`).then((res) => {
|
|
837
|
+
const device = reduceReceivedDevices([res.data], [], getState()).devicesById[id];
|
|
838
|
+
device.etag = res.headers.etag;
|
|
839
|
+
dispatch(actions$2.receivedDevice(device));
|
|
840
|
+
return Promise.resolve(device);
|
|
841
|
+
}).catch((err) => {
|
|
842
|
+
if (extractErrorMessage$1(err).includes("Not Found")) {
|
|
843
|
+
console.log(`${id} does not have any inventory information`);
|
|
844
|
+
const device = reduceReceivedDevices([{
|
|
845
|
+
id,
|
|
846
|
+
attributes: [{
|
|
847
|
+
name: "status",
|
|
848
|
+
value: "decomissioned",
|
|
849
|
+
scope: "identity"
|
|
850
|
+
}, {
|
|
851
|
+
name: "decomissioned",
|
|
852
|
+
value: "true",
|
|
853
|
+
scope: "inventory"
|
|
854
|
+
}],
|
|
855
|
+
log: false
|
|
856
|
+
}], [], getState()).devicesById[id];
|
|
857
|
+
dispatch(actions$2.receivedDevice(device));
|
|
858
|
+
}
|
|
859
|
+
}));
|
|
860
|
+
const getDeviceInfo = createAppAsyncThunk(`${sliceName$2}/getDeviceInfo`, (deviceId, { dispatch, getState }) => {
|
|
861
|
+
const device = getDeviceById$1(getState(), deviceId);
|
|
862
|
+
const { hasDeviceConfig, hasDeviceConnect, hasMonitor } = getTenantCapabilities(getState());
|
|
863
|
+
const { canConfigure } = getUserCapabilities(getState());
|
|
864
|
+
const integrations = getDeviceTwinIntegrations(getState());
|
|
865
|
+
const tasks = [
|
|
866
|
+
dispatch(getDeviceAuth(deviceId)),
|
|
867
|
+
dispatch(getDeviceById(deviceId)),
|
|
868
|
+
...integrations.map((integration) => dispatch(getDeviceTwin({
|
|
869
|
+
deviceId,
|
|
870
|
+
integration
|
|
871
|
+
})))
|
|
872
|
+
];
|
|
873
|
+
if (hasDeviceConfig && canConfigure && (device.status === DEVICE_STATES.accepted || device.status === DEVICE_STATES.preauth)) tasks.push(dispatch(getDeviceConfig(deviceId)));
|
|
874
|
+
if (device.status === DEVICE_STATES.accepted) {
|
|
875
|
+
if (hasDeviceConnect) tasks.push(dispatch(getDeviceConnect(deviceId)));
|
|
876
|
+
if (hasMonitor) {
|
|
877
|
+
tasks.push(dispatch(getLatestDeviceAlerts({ id: deviceId })));
|
|
878
|
+
tasks.push(dispatch(getDeviceMonitorConfig(deviceId)));
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return Promise.all(tasks);
|
|
882
|
+
});
|
|
883
|
+
const getAllDeviceCounts = createAppAsyncThunk(`${sliceName$2}/getAllDeviceCounts`, (_, { dispatch }) => Api.get(`${inventoryApiUrlV2}/statistics`).then(({ data }) => {
|
|
884
|
+
const { devices_by_status } = data;
|
|
885
|
+
Object.entries(devices_by_status).map(([status, countsPerTier]) => dispatch(actions$2.setDevicesCountByStatus({
|
|
886
|
+
countsPerTier,
|
|
887
|
+
status
|
|
888
|
+
})));
|
|
889
|
+
}));
|
|
890
|
+
const getDeviceLimits = createAppAsyncThunk(`${sliceName$2}/getDeviceLimit`, (_, { dispatch }) => Api.get(`${deviceAuthV2}/limits/devices`).then((res) => dispatch(actions$2.setDeviceLimits(res.data))));
|
|
891
|
+
const setDeviceListState = createAppAsyncThunk(`${sliceName$2}/setDeviceListState`, ({ shouldSelectDevices = true, forceRefresh, fetchAuth = true, ...selectionState }, { dispatch, getState }) => {
|
|
892
|
+
const currentState = getDeviceListState(getState());
|
|
893
|
+
const refreshTrigger = forceRefresh ? !currentState.refreshTrigger : selectionState.refreshTrigger;
|
|
894
|
+
const nextState = {
|
|
895
|
+
...currentState,
|
|
896
|
+
setOnly: false,
|
|
897
|
+
refreshTrigger,
|
|
898
|
+
...selectionState,
|
|
899
|
+
sort: {
|
|
900
|
+
...currentState.sort,
|
|
901
|
+
...selectionState.sort
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
const tasks = [];
|
|
905
|
+
const { isLoading: currentLoading, deviceIds: currentDevices, selection: currentSelection, ...currentRequestState } = currentState;
|
|
906
|
+
const { isLoading: nextLoading, deviceIds: nextDevices, selection: nextSelection, ...nextRequestState } = nextState;
|
|
907
|
+
if (!nextState.setOnly && !deepCompare(currentRequestState, nextRequestState)) {
|
|
908
|
+
const { direction: sortDown = SORTING_OPTIONS.desc, key: sortCol, scope: sortScope = "" } = nextState.sort ?? {};
|
|
909
|
+
const sortBy = sortCol ? [{
|
|
910
|
+
attribute: sortCol,
|
|
911
|
+
order: sortDown,
|
|
912
|
+
scope: sortScope
|
|
913
|
+
}] : void 0;
|
|
914
|
+
const applicableSelectedState = nextState.state === ALL_DEVICE_STATES ? void 0 : nextState.state;
|
|
915
|
+
nextState.isLoading = true;
|
|
916
|
+
tasks.push(dispatch(getDevicesByStatus({
|
|
917
|
+
...nextState,
|
|
918
|
+
status: applicableSelectedState,
|
|
919
|
+
sortOptions: sortBy,
|
|
920
|
+
fetchAuth
|
|
921
|
+
})).unwrap().then(({ deviceAccu, total }) => {
|
|
922
|
+
const devicesState = shouldSelectDevices ? {
|
|
923
|
+
deviceIds: deviceAccu.ids,
|
|
924
|
+
total,
|
|
925
|
+
isLoading: false
|
|
926
|
+
} : { isLoading: false };
|
|
927
|
+
return Promise.resolve(dispatch(actions$2.setDeviceListState(devicesState)));
|
|
928
|
+
}).catch(() => Promise.resolve({ isLoading: false })));
|
|
929
|
+
}
|
|
930
|
+
if (currentState.page !== nextState.page || currentState.perPage > nextState.perPage || currentState.state !== nextState.state || !deepCompare(currentState.sort, nextState.sort)) nextState.selection = [];
|
|
931
|
+
tasks.push(Promise.resolve(dispatch(actions$2.setDeviceListState(nextState))));
|
|
932
|
+
return Promise.all(tasks);
|
|
933
|
+
});
|
|
934
|
+
const getDevicesByStatus = createAppAsyncThunk(`${sliceName$2}/getDevicesByStatus`, async (options, { dispatch, getState }) => {
|
|
935
|
+
const { status, fetchAuth = true, filterSelection, group, selectedIssues = [], page = defaultPage$1, perPage = defaultPerPage$1, sortOptions = [], selectedAttributes = getSelectedDeviceAttribute(getState()) } = options;
|
|
936
|
+
const state = getState();
|
|
937
|
+
const { applicableFilters, filterTerms } = convertDeviceListStateToFilters({
|
|
938
|
+
filters: filterSelection ?? getDeviceFilters(state),
|
|
939
|
+
group: group ?? getSelectedGroup(state),
|
|
940
|
+
groups: state.devices.groups,
|
|
941
|
+
offlineThreshold: state.app.offlineThreshold,
|
|
942
|
+
selectedIssues,
|
|
943
|
+
status
|
|
944
|
+
});
|
|
945
|
+
const attributes = [
|
|
946
|
+
...defaultAttributes,
|
|
947
|
+
getIdAttribute(getState()),
|
|
948
|
+
...selectedAttributes
|
|
949
|
+
];
|
|
950
|
+
const response = await Api.post(`${inventoryApiUrlV2}/filters/search`, {
|
|
951
|
+
page,
|
|
952
|
+
per_page: perPage,
|
|
953
|
+
filters: filterTerms,
|
|
954
|
+
sort: sortOptions,
|
|
955
|
+
attributes
|
|
956
|
+
}).catch((err) => commonErrorHandler(err, `${status} devices couldn't be loaded.`, dispatch, commonErrorFallback));
|
|
957
|
+
const currentState = getState();
|
|
958
|
+
const deviceAccu = reduceReceivedDevices(response.data, [], currentState, status);
|
|
959
|
+
let total = !applicableFilters.length ? Number(response.headers[headerNames.total]) : 0;
|
|
960
|
+
if (status && currentState.devices.byStatus[status].counts.total === deviceAccu.ids.length) total = deviceAccu.ids.length;
|
|
961
|
+
const sideEffects = [Promise.resolve(dispatch(actions$2.receivedDevices(deviceAccu.devicesById)))];
|
|
962
|
+
if (status) sideEffects.push(Promise.resolve(dispatch(actions$2.setDevicesByStatus({
|
|
963
|
+
deviceIds: deviceAccu.ids,
|
|
964
|
+
status,
|
|
965
|
+
total
|
|
966
|
+
}))));
|
|
967
|
+
const receivedDevices = Object.values(deviceAccu.devicesById);
|
|
968
|
+
if (receivedDevices.length && fetchAuth) sideEffects.push(dispatch(getDevicesWithAuth(receivedDevices)));
|
|
969
|
+
await Promise.all(sideEffects);
|
|
970
|
+
return {
|
|
971
|
+
deviceAccu,
|
|
972
|
+
total: Number(response.headers[headerNames.total])
|
|
973
|
+
};
|
|
974
|
+
});
|
|
975
|
+
const getAllDevicesByStatus = createAppAsyncThunk(`${sliceName$2}/getAllDevicesByStatus`, ({ status, attribute }, { dispatch, getState }) => {
|
|
976
|
+
const attributes = [...defaultAttributes, getIdAttribute(getState())];
|
|
977
|
+
const getAllDevices = (perPage = 500, page = 1, devices = []) => Api.post(`${inventoryApiUrlV2}/filters/search`, {
|
|
978
|
+
page,
|
|
979
|
+
per_page: perPage,
|
|
980
|
+
filters: mapFiltersToTerms([{
|
|
981
|
+
key: "status",
|
|
982
|
+
value: status,
|
|
983
|
+
operator: DEVICE_FILTERING_OPTIONS.$eq.key,
|
|
984
|
+
scope: "identity"
|
|
985
|
+
}]),
|
|
986
|
+
attributes: [...attributes, {
|
|
987
|
+
scope: "inventory",
|
|
988
|
+
attribute
|
|
989
|
+
}]
|
|
990
|
+
}).then((res) => {
|
|
991
|
+
const state = getState();
|
|
992
|
+
const deviceAccu = reduceReceivedDevices(res.data, devices, state, status);
|
|
993
|
+
dispatch(actions$2.receivedDevices(deviceAccu.devicesById));
|
|
994
|
+
const total = Number(res.headers[headerNames.total]);
|
|
995
|
+
if (total > state.deployments.deploymentDeviceLimit) return Promise.resolve();
|
|
996
|
+
if (total > perPage * page) return getAllDevices(perPage, page + 1, deviceAccu.ids);
|
|
997
|
+
return Promise.resolve();
|
|
998
|
+
});
|
|
999
|
+
return getAllDevices();
|
|
1000
|
+
});
|
|
1001
|
+
const searchDevices = createAppAsyncThunk(`${sliceName$2}/searchDevices`, async (passedOptions = {}, { dispatch, getState }) => {
|
|
1002
|
+
const state = getState();
|
|
1003
|
+
const { page = defaultPage$1, searchTerm, sortOptions = [] } = {
|
|
1004
|
+
...state.app.searchState,
|
|
1005
|
+
...passedOptions
|
|
1006
|
+
};
|
|
1007
|
+
const { columnSelection = [] } = getUserSettings$1(state);
|
|
1008
|
+
const selectedAttributes = columnSelection.map((column) => ({
|
|
1009
|
+
attribute: column.key,
|
|
1010
|
+
scope: column.scope
|
|
1011
|
+
}));
|
|
1012
|
+
const attributes = attributeDuplicateFilter([
|
|
1013
|
+
...defaultAttributes,
|
|
1014
|
+
getIdAttribute(state),
|
|
1015
|
+
...selectedAttributes
|
|
1016
|
+
], "attribute");
|
|
1017
|
+
const response = await Api.post(`${inventoryApiUrlV2}/filters/search`, {
|
|
1018
|
+
page,
|
|
1019
|
+
per_page: 10,
|
|
1020
|
+
filters: [],
|
|
1021
|
+
sort: sortOptions,
|
|
1022
|
+
text: searchTerm,
|
|
1023
|
+
attributes
|
|
1024
|
+
}).catch((err) => commonErrorHandler(err, `devices couldn't be searched.`, dispatch, commonErrorFallback));
|
|
1025
|
+
const deviceAccu = reduceReceivedDevices(response.data, [], getState());
|
|
1026
|
+
dispatch(actions$2.receivedDevices(deviceAccu.devicesById));
|
|
1027
|
+
return {
|
|
1028
|
+
deviceIds: deviceAccu.ids,
|
|
1029
|
+
searchTotal: Number(response.headers[headerNames.total])
|
|
1030
|
+
};
|
|
1031
|
+
});
|
|
1032
|
+
const ATTRIBUTE_LIST_CUTOFF = 100;
|
|
1033
|
+
const attributeReducer = (attributes = []) => attributes.slice(0, ATTRIBUTE_LIST_CUTOFF).reduce((accu, { name, scope }) => {
|
|
1034
|
+
if (!accu[scope]) accu[scope] = [];
|
|
1035
|
+
accu[scope].push(name);
|
|
1036
|
+
return accu;
|
|
1037
|
+
}, {
|
|
1038
|
+
identity: [],
|
|
1039
|
+
inventory: [],
|
|
1040
|
+
system: [],
|
|
1041
|
+
tags: []
|
|
1042
|
+
});
|
|
1043
|
+
const getDeviceAttributes = createAppAsyncThunk(`${sliceName$2}/getDeviceAttributes`, (_, { dispatch }) => Api.get(`${inventoryApiUrlV2}/filters/attributes`).then(({ data }) => {
|
|
1044
|
+
const { identity: identityAttributes, inventory: inventoryAttributes, system: systemAttributes, tags: tagAttributes } = attributeReducer(data || []);
|
|
1045
|
+
return dispatch(actions$2.setFilterAttributes({
|
|
1046
|
+
identityAttributes,
|
|
1047
|
+
inventoryAttributes,
|
|
1048
|
+
systemAttributes,
|
|
1049
|
+
tagAttributes
|
|
1050
|
+
}));
|
|
1051
|
+
}));
|
|
1052
|
+
const initializeDistributionData = (report, groups, devices, totalDeviceCount) => {
|
|
1053
|
+
const { attribute, group = "", software = "" } = report;
|
|
1054
|
+
const effectiveAttribute = software ? software : attribute;
|
|
1055
|
+
const { deviceIds, total = 0 } = groups[group] || {};
|
|
1056
|
+
const distributionByAttribute = (deviceIds ? deviceIds.map((id) => devices[id]) : Object.values(devices)).reduce((accu, item) => {
|
|
1057
|
+
if (!item.attributes || item.status !== DEVICE_STATES.accepted) return accu;
|
|
1058
|
+
const attributeValue = item.attributes[effectiveAttribute];
|
|
1059
|
+
if (!accu[attributeValue]) accu[attributeValue] = 0;
|
|
1060
|
+
accu[attributeValue] = accu[attributeValue] + 1;
|
|
1061
|
+
return accu;
|
|
1062
|
+
}, {});
|
|
1063
|
+
const items = Object.entries(distributionByAttribute).sort((pairA, pairB) => pairB[1] - pairA[1]).map(([key, count]) => ({
|
|
1064
|
+
key,
|
|
1065
|
+
count
|
|
1066
|
+
}));
|
|
1067
|
+
const dataCount = items.reduce((accu, item) => accu + item.count, 0);
|
|
1068
|
+
const otherCount = (groups[group] ? total : totalDeviceCount) - dataCount;
|
|
1069
|
+
return {
|
|
1070
|
+
items,
|
|
1071
|
+
otherCount,
|
|
1072
|
+
total: otherCount + dataCount
|
|
1073
|
+
};
|
|
1074
|
+
};
|
|
1075
|
+
const updateReportData = createAppAsyncThunk(`${sliceName$2}/updateReportData`, (reportIndex, { dispatch, getState }) => {
|
|
1076
|
+
const report = getDeviceReportsForUser(getState())[reportIndex];
|
|
1077
|
+
const { group = "" } = report;
|
|
1078
|
+
const devicesById = getDevicesById(getState());
|
|
1079
|
+
const groups = getGroupsById(getState());
|
|
1080
|
+
const { accepted: acceptedDevicesCount } = getDeviceCountsByStatus(getState());
|
|
1081
|
+
const totalDeviceCount = groups[group] ? groups[group].total : acceptedDevicesCount;
|
|
1082
|
+
const newReports = [...getDeviceReports(getState())];
|
|
1083
|
+
newReports[reportIndex] = initializeDistributionData(report, groups, devicesById, totalDeviceCount);
|
|
1084
|
+
return Promise.resolve(dispatch(actions$2.setDeviceReports(newReports)));
|
|
1085
|
+
});
|
|
1086
|
+
const getReportDataWithoutBackendSupport = createAppAsyncThunk(`${sliceName$2}/getReportDataWithoutBackendSupport`, (reportIndex, { dispatch, getState }) => {
|
|
1087
|
+
const report = getDeviceReportsForUser(getState())[reportIndex];
|
|
1088
|
+
if (!report) return;
|
|
1089
|
+
const { attribute, group = "", software = "" } = report;
|
|
1090
|
+
const effectiveAttribute = software ? software : attribute;
|
|
1091
|
+
const devicesById = getDevicesById(getState());
|
|
1092
|
+
const acceptedDevices = getAcceptedDevices(getState());
|
|
1093
|
+
const { accepted: acceptedDevicesCount } = getDeviceCountsByStatus(getState());
|
|
1094
|
+
const { deviceIds = [], filters = [], total = 0 } = getGroupsById(getState())[group] || {};
|
|
1095
|
+
let groupDevicesRequest = Promise.resolve({ payload: {
|
|
1096
|
+
groupName: "",
|
|
1097
|
+
group: {
|
|
1098
|
+
deviceIds: Object.keys(devicesById),
|
|
1099
|
+
total: Object.keys(devicesById).length
|
|
1100
|
+
}
|
|
1101
|
+
} });
|
|
1102
|
+
if (group && (!(deviceIds.length && total) || deviceIds.length !== total || !deviceIds.every((id) => !!devicesById[id]))) groupDevicesRequest = filters.length ? dispatch(getAllDynamicGroupDevices({
|
|
1103
|
+
group,
|
|
1104
|
+
attribute: effectiveAttribute
|
|
1105
|
+
})).unwrap() : dispatch(getAllGroupDevices({
|
|
1106
|
+
group,
|
|
1107
|
+
attribute: effectiveAttribute
|
|
1108
|
+
})).unwrap();
|
|
1109
|
+
else if (!group && (acceptedDevices.deviceIds.length !== acceptedDevicesCount || !acceptedDevices.deviceIds.every((id) => !!devicesById[id]))) groupDevicesRequest = dispatch(getAllDevicesByStatus({
|
|
1110
|
+
status: DEVICE_STATES.accepted,
|
|
1111
|
+
attribute: effectiveAttribute
|
|
1112
|
+
})).unwrap();
|
|
1113
|
+
return groupDevicesRequest.then(() => dispatch(updateReportData(reportIndex)));
|
|
1114
|
+
});
|
|
1115
|
+
const getDeviceConnect = createAppAsyncThunk(`${sliceName$2}/getDeviceConnect`, (id, { dispatch }) => Api.get(`${deviceConnect}/devices/${id}`).then(({ data }) => Promise.all([dispatch(actions$2.receivedDevice({
|
|
1116
|
+
connect_status: data.status,
|
|
1117
|
+
connect_updated_ts: data.updated_ts,
|
|
1118
|
+
id
|
|
1119
|
+
})), Promise.resolve(data)])));
|
|
1120
|
+
const updateTypeMap = {
|
|
1121
|
+
deploymentUpdate: "check-update",
|
|
1122
|
+
inventoryUpdate: "send-inventory"
|
|
1123
|
+
};
|
|
1124
|
+
const triggerDeviceUpdate = createAppAsyncThunk(`${sliceName$2}/triggerDeviceUpdate`, async ({ id, type }, { dispatch }) => {
|
|
1125
|
+
await Api.post(`${deviceConnect}/devices/${id}/${updateTypeMap[type] ?? updateTypeMap.deploymentUpdate}`).catch((err) => commonErrorHandler(err, `The request couldn't be sent.`, dispatch));
|
|
1126
|
+
dispatch(setSnackbar$2("Request has been sent."));
|
|
1127
|
+
await new Promise((resolve) => setTimeout(resolve, TIMEOUTS.threeSeconds));
|
|
1128
|
+
return dispatch(getDeviceById(id));
|
|
1129
|
+
});
|
|
1130
|
+
const getSessionDetails = createAppAsyncThunk(`${sliceName$2}/getSessionDetails`, ({ sessionId, deviceId, userId, startDate, endDate }) => {
|
|
1131
|
+
const { start: startUnix, end: endUnix } = dateRangeToUnix(startDate, endDate);
|
|
1132
|
+
const createdAfter = startDate ? `&created_after=${startUnix}` : "";
|
|
1133
|
+
const createdBefore = endDate ? `&created_before=${endUnix}` : "";
|
|
1134
|
+
const objectSearch = `&object_id=${deviceId}`;
|
|
1135
|
+
return Api.get(`${auditLogsApiUrl}/logs?per_page=500${createdAfter}${createdBefore}&actor_id=${userId}${objectSearch}`).then(({ data: auditLogEntries }) => {
|
|
1136
|
+
const { start, end } = auditLogEntries.reduce((accu, item) => {
|
|
1137
|
+
if (item.meta?.session_id?.includes(sessionId)) {
|
|
1138
|
+
accu.start = new Date(item.action.startsWith("open") ? item.time : accu.start);
|
|
1139
|
+
accu.end = new Date(item.action.startsWith("close") ? item.time : accu.end);
|
|
1140
|
+
}
|
|
1141
|
+
return accu;
|
|
1142
|
+
}, {
|
|
1143
|
+
start: startDate || endDate,
|
|
1144
|
+
end: endDate || startDate
|
|
1145
|
+
});
|
|
1146
|
+
return Promise.resolve({
|
|
1147
|
+
start,
|
|
1148
|
+
end
|
|
1149
|
+
});
|
|
1150
|
+
});
|
|
1151
|
+
});
|
|
1152
|
+
const getDeviceFileDownloadLink = createAppAsyncThunk(`${sliceName$2}/getDeviceFileDownloadLink`, ({ deviceId, path }) => Promise.resolve(`${window.location.origin}${deviceConnect}/devices/${deviceId}/download?path=${encodeURIComponent(path)}`));
|
|
1153
|
+
const deviceFileUpload = createAppAsyncThunk(`${sliceName$2}/deviceFileUpload`, ({ deviceId, path, file }, { dispatch }) => {
|
|
1154
|
+
const formData = new FormData();
|
|
1155
|
+
formData.append("path", path);
|
|
1156
|
+
formData.append("file", file);
|
|
1157
|
+
const uploadId = v4();
|
|
1158
|
+
const cancelSource = new AbortController();
|
|
1159
|
+
return Promise.all([
|
|
1160
|
+
dispatch(setSnackbar$2("Uploading file")),
|
|
1161
|
+
dispatch(initUpload({
|
|
1162
|
+
id: uploadId,
|
|
1163
|
+
upload: {
|
|
1164
|
+
progress: 0,
|
|
1165
|
+
cancelSource
|
|
1166
|
+
}
|
|
1167
|
+
})),
|
|
1168
|
+
Api.uploadPut(`${deviceConnect}/devices/${deviceId}/upload`, formData, (e) => dispatch(uploadProgress({
|
|
1169
|
+
id: uploadId,
|
|
1170
|
+
progress: progress(e)
|
|
1171
|
+
})), cancelSource.signal)
|
|
1172
|
+
]).then(() => Promise.resolve(dispatch(setSnackbar$2({
|
|
1173
|
+
message: "Upload successful",
|
|
1174
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
1175
|
+
})))).catch((err) => {
|
|
1176
|
+
if (isCancel(err)) return dispatch(setSnackbar$2({
|
|
1177
|
+
message: "The upload has been cancelled",
|
|
1178
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
1179
|
+
}));
|
|
1180
|
+
return commonErrorHandler(err, `Error uploading file to device.`, dispatch);
|
|
1181
|
+
}).finally(() => dispatch(cleanUpUpload(uploadId)));
|
|
1182
|
+
});
|
|
1183
|
+
const getDeviceAuth = createAppAsyncThunk(`${sliceName$2}/getDeviceAuth`, async (id, { dispatch }) => {
|
|
1184
|
+
return (await dispatch(getDevicesWithAuth([{ id }])).unwrap())?.[0];
|
|
1185
|
+
});
|
|
1186
|
+
const getDevicesWithAuth = createAppAsyncThunk(`${sliceName$2}/getDevicesWithAuth`, async (devices, { dispatch, getState }) => {
|
|
1187
|
+
if (!devices.length) return [];
|
|
1188
|
+
const { data: receivedDevices } = await Api.get(`${deviceAuthV2}/devices?id=${devices.map((device) => device.id).join("&id=")}`).catch((err) => commonErrorHandler(err, `Error: ${err}`, dispatch));
|
|
1189
|
+
const { devicesById } = reduceReceivedDevices(receivedDevices, [], getState());
|
|
1190
|
+
dispatch(actions$2.receivedDevices(devicesById));
|
|
1191
|
+
return receivedDevices;
|
|
1192
|
+
});
|
|
1193
|
+
const updateDeviceAuth = createAppAsyncThunk(`${sliceName$2}/updateDeviceAuth`, ({ deviceId, authId, status }, { dispatch, getState }) => Api.put(`${deviceAuthV2}/devices/${deviceId}/auth/${authId}/status`, { status }).then(() => Promise.all([dispatch(getDeviceAuth(deviceId)), dispatch(setSnackbar$2("Device authorization status was updated successfully"))])).catch((err) => commonErrorHandler(err, "There was a problem updating the device authorization status:", dispatch)).then(() => Promise.resolve(dispatch(actions$2.maybeUpdateDevicesByStatus({
|
|
1194
|
+
deviceId,
|
|
1195
|
+
authId
|
|
1196
|
+
})))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getDeviceListState(getState()).refreshTrigger }))));
|
|
1197
|
+
const updateDevicesAuth = createAppAsyncThunk(`${sliceName$2}/updateDevicesAuth`, ({ deviceIds, status }, { dispatch, getState }) => {
|
|
1198
|
+
let devices = getDevicesById(getState());
|
|
1199
|
+
return dispatch(getDevicesWithAuth(deviceIds.reduce((accu, id) => devices[id].auth_sets ? accu : [...accu, { id }], []))).then(() => {
|
|
1200
|
+
devices = getDevicesById(getState());
|
|
1201
|
+
const deviceAuthUpdates = deviceIds.map((id) => {
|
|
1202
|
+
const device = devices[id];
|
|
1203
|
+
if (device.auth_sets && device.auth_sets.length !== 1) return Promise.reject();
|
|
1204
|
+
return dispatch(updateDeviceAuth({
|
|
1205
|
+
authId: device.auth_sets[0].id,
|
|
1206
|
+
deviceId: device.id,
|
|
1207
|
+
status
|
|
1208
|
+
})).unwrap().catch((err) => commonErrorHandler(err, "The action was stopped as there was a problem updating a device authorization status: ", dispatch, "", false));
|
|
1209
|
+
});
|
|
1210
|
+
return Promise.allSettled(deviceAuthUpdates).then((results) => {
|
|
1211
|
+
const { skipped, count } = results.reduce((accu, item) => {
|
|
1212
|
+
if (item.status === "rejected") accu.skipped = accu.skipped + 1;
|
|
1213
|
+
else accu.count = accu.count + 1;
|
|
1214
|
+
return accu;
|
|
1215
|
+
}, {
|
|
1216
|
+
skipped: 0,
|
|
1217
|
+
count: 0
|
|
1218
|
+
});
|
|
1219
|
+
return dispatch(setSnackbar$2(getSnackbarMessage(skipped, count)));
|
|
1220
|
+
});
|
|
1221
|
+
});
|
|
1222
|
+
});
|
|
1223
|
+
const deleteAuthset = createAppAsyncThunk(`${sliceName$2}/deleteAuthset`, ({ deviceId, authId }, { dispatch, getState }) => Api.delete(`${deviceAuthV2}/devices/${deviceId}/auth/${authId}`).then(() => Promise.all([dispatch(setSnackbar$2("Device authorization status was updated successfully"))])).catch((err) => commonErrorHandler(err, "There was a problem updating the device authorization status:", dispatch)).then(() => Promise.resolve(dispatch(actions$2.maybeUpdateDevicesByStatus({
|
|
1224
|
+
deviceId,
|
|
1225
|
+
authId
|
|
1226
|
+
})))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getState().devices.deviceList.refreshTrigger }))));
|
|
1227
|
+
const preauthDevice = createAppAsyncThunk(`${sliceName$2}/preauthDevice`, (authset, { dispatch, rejectWithValue }) => Api.post(`${deviceAuthV2}/devices`, authset).then(() => Promise.resolve(dispatch(setSnackbar$2({
|
|
1228
|
+
message: "Device was successfully added to the preauthorization list",
|
|
1229
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
1230
|
+
})))).catch((err) => {
|
|
1231
|
+
if (err.response.status === 409) return rejectWithValue("A device with a matching identity data set already exists");
|
|
1232
|
+
return commonErrorHandler(err, "The device could not be added:", dispatch);
|
|
1233
|
+
}));
|
|
1234
|
+
const decommissionDevice = createAppAsyncThunk(`${sliceName$2}/decommissionDevice`, ({ deviceId, authId }, { dispatch, getState }) => Api.delete(`${deviceAuthV2}/devices/${deviceId}`).then(() => Promise.resolve(dispatch(setSnackbar$2("Device was decommissioned successfully")))).catch((err) => commonErrorHandler(err, "There was a problem decommissioning the device:", dispatch)).then(() => Promise.resolve(dispatch(actions$2.maybeUpdateDevicesByStatus({
|
|
1235
|
+
deviceId,
|
|
1236
|
+
authId
|
|
1237
|
+
})))).finally(() => dispatch(setDeviceListState({ refreshTrigger: !getState().devices.deviceList.refreshTrigger }))));
|
|
1238
|
+
const getDeviceConfig = createAppAsyncThunk(`${sliceName$2}/getDeviceConfig`, (deviceId, { dispatch }) => Api.get(`${deviceConfig}/${deviceId}`).then(({ data }) => Promise.all([dispatch(actions$2.receivedDevice({
|
|
1239
|
+
id: deviceId,
|
|
1240
|
+
config: data
|
|
1241
|
+
})), Promise.resolve(data)])).catch((err) => {
|
|
1242
|
+
if (err.response?.data?.error.status_code !== 404) return commonErrorHandler(err, `There was an error retrieving the configuration for device ${deviceId}.`, dispatch, commonErrorFallback);
|
|
1243
|
+
}));
|
|
1244
|
+
const setDeviceConfig = createAppAsyncThunk(`${sliceName$2}/setDeviceConfig`, ({ deviceId, config }, { dispatch }) => Api.put(`${deviceConfig}/${deviceId}`, config).catch((err) => commonErrorHandler(err, `There was an error setting the configuration for device ${deviceId}.`, dispatch, commonErrorFallback)).then(() => Promise.resolve(dispatch(getDeviceConfig(deviceId)))));
|
|
1245
|
+
const applyDeviceConfig = createAppAsyncThunk(`${sliceName$2}/applyDeviceConfig`, ({ deviceId, configDeploymentConfiguration, isDefault, config }, { dispatch, getState }) => Api.post(`${deviceConfig}/${deviceId}/deploy`, configDeploymentConfiguration).catch((err) => commonErrorHandler(err, `There was an error deploying the configuration to device ${deviceId}.`, dispatch, commonErrorFallback)).then(({ data }) => {
|
|
1246
|
+
const device = getDeviceById$1(getState(), deviceId);
|
|
1247
|
+
const { canManageUsers } = getUserCapabilities(getState());
|
|
1248
|
+
const tasks = [Promise.resolve(dispatch(actions$2.receivedDevice({
|
|
1249
|
+
...device,
|
|
1250
|
+
config: {
|
|
1251
|
+
...device.config,
|
|
1252
|
+
deployment_id: data.deployment_id
|
|
1253
|
+
}
|
|
1254
|
+
}))), new Promise((resolve) => setTimeout(() => resolve(dispatch(getSingleDeployment(data.deployment_id))), TIMEOUTS.oneSecond))];
|
|
1255
|
+
if (isDefault && canManageUsers) {
|
|
1256
|
+
const { previous } = getGlobalSettings$1(getState()).defaultDeviceConfig ?? {};
|
|
1257
|
+
tasks.push(dispatch(saveGlobalSettings({ defaultDeviceConfig: {
|
|
1258
|
+
current: config,
|
|
1259
|
+
previous
|
|
1260
|
+
} })));
|
|
1261
|
+
}
|
|
1262
|
+
return Promise.all(tasks);
|
|
1263
|
+
}));
|
|
1264
|
+
const setDeviceTags = createAppAsyncThunk(`${sliceName$2}/setDeviceTags`, ({ deviceId, tags }, { dispatch }) => dispatch(getDeviceById(deviceId)).unwrap().then((device) => {
|
|
1265
|
+
const headers = device.etag ? { "If-Match": device.etag } : {};
|
|
1266
|
+
const tagList = Object.entries(tags).map(([name, value]) => ({
|
|
1267
|
+
name,
|
|
1268
|
+
value
|
|
1269
|
+
}));
|
|
1270
|
+
const isNameChange = tagList.some(({ name }) => name === "name");
|
|
1271
|
+
return Api.put(`${inventoryApiUrl}/devices/${deviceId}/tags`, tagList, { headers }).catch((err) => commonErrorHandler(err, `There was an error setting tags for device ${deviceId}.`, dispatch, "Please check your connection.")).then(() => Promise.all([dispatch(actions$2.receivedDevice({
|
|
1272
|
+
...device,
|
|
1273
|
+
id: deviceId,
|
|
1274
|
+
tags
|
|
1275
|
+
})), dispatch(setSnackbar$2(`Device ${tagList.length === 1 && isNameChange ? "name" : "tags"} changed`))]));
|
|
1276
|
+
}));
|
|
1277
|
+
const getDeviceTwin = createAppAsyncThunk(`${sliceName$2}/getDeviceTwin`, ({ deviceId, integration }, { dispatch, getState }) => {
|
|
1278
|
+
let providerResult = {};
|
|
1279
|
+
return Api.get(`${iotManagerBaseURL}/devices/${deviceId}/state`).then(({ data }) => {
|
|
1280
|
+
providerResult = {
|
|
1281
|
+
...data,
|
|
1282
|
+
twinError: ""
|
|
1283
|
+
};
|
|
1284
|
+
}).catch((err) => {
|
|
1285
|
+
providerResult = { twinError: `There was an error getting the ${EXTERNAL_PROVIDER[integration.provider].twinTitle.toLowerCase()} for device ${deviceId}. ${err}` };
|
|
1286
|
+
}).finally(() => {
|
|
1287
|
+
const device = getDeviceById$1(getState(), deviceId);
|
|
1288
|
+
Promise.resolve(dispatch(actions$2.receivedDevice({
|
|
1289
|
+
...device,
|
|
1290
|
+
twinsByIntegration: {
|
|
1291
|
+
...device.twinsByIntegration,
|
|
1292
|
+
...providerResult
|
|
1293
|
+
}
|
|
1294
|
+
})));
|
|
1295
|
+
});
|
|
1296
|
+
});
|
|
1297
|
+
const setDeviceTwin = createAppAsyncThunk(`${sliceName$2}/setDeviceTwin`, ({ deviceId, integration, settings }, { dispatch, getState }) => Api.put(`${iotManagerBaseURL}/devices/${deviceId}/state/${integration.id}`, { desired: settings }).catch((err) => commonErrorHandler(err, `There was an error updating the ${EXTERNAL_PROVIDER[integration.provider].twinTitle.toLowerCase()} for device ${deviceId}.`, dispatch)).then(() => {
|
|
1298
|
+
const device = getDeviceById$1(getState(), deviceId);
|
|
1299
|
+
const { twinsByIntegration = {} } = device;
|
|
1300
|
+
const { [integration.id]: currentState = {} } = twinsByIntegration;
|
|
1301
|
+
return Promise.resolve(dispatch(actions$2.receivedDevice({
|
|
1302
|
+
...device,
|
|
1303
|
+
twinsByIntegration: {
|
|
1304
|
+
...twinsByIntegration,
|
|
1305
|
+
[integration.id]: {
|
|
1306
|
+
...currentState,
|
|
1307
|
+
desired: settings
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
})));
|
|
1311
|
+
}));
|
|
1312
|
+
const prepareSearchArguments = ({ filters, group, state, status }) => {
|
|
1313
|
+
const { filterTerms } = convertDeviceListStateToFilters({
|
|
1314
|
+
filters,
|
|
1315
|
+
group,
|
|
1316
|
+
offlineThreshold: state.app.offlineThreshold,
|
|
1317
|
+
selectedIssues: [],
|
|
1318
|
+
status
|
|
1319
|
+
});
|
|
1320
|
+
const { columnSelection = [] } = getUserSettings$1(state);
|
|
1321
|
+
const selectedAttributes = columnSelection.map((column) => ({
|
|
1322
|
+
attribute: column.key,
|
|
1323
|
+
scope: column.scope
|
|
1324
|
+
}));
|
|
1325
|
+
return {
|
|
1326
|
+
attributes: [
|
|
1327
|
+
...defaultAttributes,
|
|
1328
|
+
getIdAttribute(state),
|
|
1329
|
+
...selectedAttributes
|
|
1330
|
+
],
|
|
1331
|
+
filterTerms
|
|
1332
|
+
};
|
|
1333
|
+
};
|
|
1334
|
+
const getSystemDevices = createAppAsyncThunk(`${sliceName$2}/getSystemDevices`, (options, { dispatch, getState }) => {
|
|
1335
|
+
const { id, page = defaultPage$1, perPage = defaultPerPage$1, sortOptions = [] } = options;
|
|
1336
|
+
const state = getState();
|
|
1337
|
+
const { hasFullFiltering } = getTenantCapabilities(state);
|
|
1338
|
+
if (!hasFullFiltering) return Promise.resolve();
|
|
1339
|
+
const { attributes: deviceAttributes = {} } = getDeviceById$1(state, id);
|
|
1340
|
+
const { mender_gateway_system_id = "" } = deviceAttributes;
|
|
1341
|
+
const { attributes, filterTerms } = prepareSearchArguments({
|
|
1342
|
+
filters: [{
|
|
1343
|
+
...emptyFilter,
|
|
1344
|
+
key: "mender_is_gateway",
|
|
1345
|
+
operator: DEVICE_FILTERING_OPTIONS.$ne.key,
|
|
1346
|
+
value: "true",
|
|
1347
|
+
scope: "inventory"
|
|
1348
|
+
}, {
|
|
1349
|
+
...emptyFilter,
|
|
1350
|
+
key: "mender_gateway_system_id",
|
|
1351
|
+
value: mender_gateway_system_id,
|
|
1352
|
+
scope: "inventory"
|
|
1353
|
+
}],
|
|
1354
|
+
state
|
|
1355
|
+
});
|
|
1356
|
+
return Api.post(`${inventoryApiUrlV2}/filters/search`, {
|
|
1357
|
+
page,
|
|
1358
|
+
per_page: perPage,
|
|
1359
|
+
filters: filterTerms,
|
|
1360
|
+
sort: sortOptions,
|
|
1361
|
+
attributes
|
|
1362
|
+
}).catch((err) => commonErrorHandler(err, `There was an error getting system devices device ${id}.`, dispatch, "Please check your connection.")).then(({ data, headers }) => {
|
|
1363
|
+
const state = getState();
|
|
1364
|
+
const { devicesById, ids } = reduceReceivedDevices(data, [], state);
|
|
1365
|
+
const device = {
|
|
1366
|
+
...getDeviceById$1(state, id),
|
|
1367
|
+
systemDeviceIds: ids,
|
|
1368
|
+
systemDeviceTotal: Number(headers[headerNames.total])
|
|
1369
|
+
};
|
|
1370
|
+
return Promise.resolve(dispatch(actions$2.receivedDevices({
|
|
1371
|
+
...devicesById,
|
|
1372
|
+
[id]: device
|
|
1373
|
+
})));
|
|
1374
|
+
});
|
|
1375
|
+
});
|
|
1376
|
+
const getGatewayDevices = createAppAsyncThunk(`${sliceName$2}/getGatewayDevices`, (deviceId, { dispatch, getState }) => {
|
|
1377
|
+
const state = getState();
|
|
1378
|
+
const { attributes = {} } = getDeviceById$1(state, deviceId);
|
|
1379
|
+
const { mender_gateway_system_id = "" } = attributes;
|
|
1380
|
+
const { attributes: attributeSelection, filterTerms } = prepareSearchArguments({
|
|
1381
|
+
filters: [
|
|
1382
|
+
{
|
|
1383
|
+
...emptyFilter,
|
|
1384
|
+
key: "id",
|
|
1385
|
+
operator: DEVICE_FILTERING_OPTIONS.$ne.key,
|
|
1386
|
+
value: deviceId,
|
|
1387
|
+
scope: "identity"
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
...emptyFilter,
|
|
1391
|
+
key: "mender_is_gateway",
|
|
1392
|
+
value: "true",
|
|
1393
|
+
scope: "inventory"
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
...emptyFilter,
|
|
1397
|
+
key: "mender_gateway_system_id",
|
|
1398
|
+
value: mender_gateway_system_id,
|
|
1399
|
+
scope: "inventory"
|
|
1400
|
+
}
|
|
1401
|
+
],
|
|
1402
|
+
state
|
|
1403
|
+
});
|
|
1404
|
+
return Api.post(`${inventoryApiUrlV2}/filters/search`, {
|
|
1405
|
+
page: 1,
|
|
1406
|
+
per_page: 500,
|
|
1407
|
+
filters: filterTerms,
|
|
1408
|
+
attributes: attributeSelection
|
|
1409
|
+
}).then(({ data }) => {
|
|
1410
|
+
const { ids } = reduceReceivedDevices(data, [], getState());
|
|
1411
|
+
const tasks = ids.map((deviceId) => dispatch(getDeviceInfo(deviceId)));
|
|
1412
|
+
tasks.push(Promise.resolve(dispatch(actions$2.receivedDevice({
|
|
1413
|
+
id: deviceId,
|
|
1414
|
+
gatewayIds: ids
|
|
1415
|
+
}))));
|
|
1416
|
+
return Promise.all(tasks);
|
|
1417
|
+
});
|
|
1418
|
+
});
|
|
1419
|
+
//#endregion
|
|
1420
|
+
//#region src/onboardingSlice/thunks.ts
|
|
1421
|
+
const cookies$2 = new Cookies();
|
|
1422
|
+
const determineProgress = (acceptedDevices, pendingDevices, releases, pastDeployments) => {
|
|
1423
|
+
const steps = orderedOnboardingSteps;
|
|
1424
|
+
let progress = -1;
|
|
1425
|
+
progress = pendingDevices.length > 1 ? steps.findIndex((step) => step === onboardingSteps.DEVICES_PENDING_ACCEPTING_ONBOARDING) : progress;
|
|
1426
|
+
progress = acceptedDevices.length >= 1 ? steps.findIndex((step) => step === onboardingSteps.DEVICES_ACCEPTED_ONBOARDING) : progress;
|
|
1427
|
+
progress = acceptedDevices.length > 1 && releases.length > 1 && pastDeployments.length > 1 ? steps.findIndex((step) => step === onboardingSteps.DEPLOYMENTS_PAST_COMPLETED) : progress;
|
|
1428
|
+
return steps[progress];
|
|
1429
|
+
};
|
|
1430
|
+
const deductOnboardingState = ({ devicesById, devicesByStatus, onboardingState, pastDeployments, releases, userCapabilities, userId }) => {
|
|
1431
|
+
const { canDeploy, canManageDevices, canReadDeployments, canReadDevices, canReadReleases, canUploadReleases } = userCapabilities;
|
|
1432
|
+
const userCookie = cookies$2.get(`${userId}-onboarded`);
|
|
1433
|
+
const acceptedDevices = devicesByStatus[DEVICE_STATES.accepted].deviceIds;
|
|
1434
|
+
const pendingDevices = devicesByStatus[DEVICE_STATES.pending].deviceIds;
|
|
1435
|
+
let deviceType = onboardingState.deviceType ?? [];
|
|
1436
|
+
deviceType = !deviceType.length && acceptedDevices.length && devicesById[acceptedDevices[0]].hasOwnProperty("attributes") ? devicesById[acceptedDevices[0]].attributes.device_type : deviceType;
|
|
1437
|
+
const deviceTier = acceptedDevices.length && devicesById[acceptedDevices[0]].tier;
|
|
1438
|
+
let approach = null;
|
|
1439
|
+
if (deviceType.some((type) => type.startsWith("qemu"))) approach = "virtual";
|
|
1440
|
+
else if (deviceType.some((type) => type.startsWith("esp32")) || deviceTier === "micro") approach = "mcu";
|
|
1441
|
+
else if (deviceType.length) approach = "physical";
|
|
1442
|
+
const progress = onboardingState.progress || determineProgress(acceptedDevices, pendingDevices, releases, pastDeployments);
|
|
1443
|
+
return {
|
|
1444
|
+
...onboardingState,
|
|
1445
|
+
complete: !!(Boolean(userCookie) || onboardingState.complete || acceptedDevices.length > 1 && pendingDevices.length > 0 && releases.length > 1 && pastDeployments.length > 1 || acceptedDevices.length >= 1 && releases.length >= 2 && pastDeployments.length > 2 || acceptedDevices.length >= 1 && pendingDevices.length > 0 && releases.length >= 2 && pastDeployments.length >= 2 || orderedOnboardingSteps.findIndex((step) => step === progress) >= orderedOnboardingSteps.length - 1 || onboardingState.disable || ![
|
|
1446
|
+
canDeploy,
|
|
1447
|
+
canManageDevices,
|
|
1448
|
+
canReadDeployments,
|
|
1449
|
+
canReadDevices,
|
|
1450
|
+
canReadReleases,
|
|
1451
|
+
canUploadReleases
|
|
1452
|
+
].every((i) => i)),
|
|
1453
|
+
showTips: onboardingState.showTips != null ? onboardingState.showTips : true,
|
|
1454
|
+
deviceType,
|
|
1455
|
+
approach: onboardingState.approach || approach,
|
|
1456
|
+
progress
|
|
1457
|
+
};
|
|
1458
|
+
};
|
|
1459
|
+
const getOnboardingState = createAppAsyncThunk(`${sliceName$3}/getOnboardingState`, (_, { dispatch, getState }) => {
|
|
1460
|
+
const state = getState();
|
|
1461
|
+
let onboardingState = getOnboardingState$1(state);
|
|
1462
|
+
if (!onboardingState.complete) {
|
|
1463
|
+
const userId = state.users.currentUser;
|
|
1464
|
+
onboardingState = deductOnboardingState({
|
|
1465
|
+
devicesById: state.devices.byId,
|
|
1466
|
+
devicesByStatus: state.devices.byStatus,
|
|
1467
|
+
onboardingState,
|
|
1468
|
+
pastDeployments: state.deployments.byStatus.finished.deploymentIds,
|
|
1469
|
+
releases: Object.values(state.releases.byId),
|
|
1470
|
+
userCapabilities: getUserCapabilities(state),
|
|
1471
|
+
userId
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
onboardingState.progress = onboardingState.progress || onboardingSteps.DASHBOARD_ONBOARDING_START;
|
|
1475
|
+
const demoDeviceAddress = `http://${getDemoDeviceAddress(Object.values(state.devices.byId), onboardingState.approach)}`;
|
|
1476
|
+
onboardingState.address = state.onboarding.demoArtifactPort ? `${demoDeviceAddress}:${state.onboarding.demoArtifactPort}` : demoDeviceAddress;
|
|
1477
|
+
return Promise.all([
|
|
1478
|
+
dispatch(actions$3.setOnboardingComplete(onboardingState.complete)),
|
|
1479
|
+
dispatch(actions$3.setOnboardingState(onboardingState)),
|
|
1480
|
+
dispatch(saveUserSettings({ onboarding: onboardingState }))
|
|
1481
|
+
]);
|
|
1482
|
+
});
|
|
1483
|
+
const setOnboardingDeviceType = createAppAsyncThunk(`${sliceName$3}/setOnboardingDeviceType`, (value, { dispatch }) => Promise.all([dispatch(actions$3.setOnboardingDeviceType(value)), dispatch(saveUserSettings({ onboarding: { deviceType: value } }))]));
|
|
1484
|
+
const setOnboardingApproach = createAppAsyncThunk(`${sliceName$3}/setOnboardingApproach`, (value, { dispatch }) => Promise.all([dispatch(actions$3.setOnboardingApproach(value)), dispatch(saveUserSettings({ onboarding: { approach: value } }))]));
|
|
1485
|
+
const setOnboardingComplete = createAppAsyncThunk(`${sliceName$3}/setOnboardingComplete`, (value, { dispatch }) => {
|
|
1486
|
+
const tasks = [Promise.resolve(dispatch(actions$3.setOnboardingComplete(value)))];
|
|
1487
|
+
if (value) {
|
|
1488
|
+
tasks.push(Promise.resolve(dispatch(actions$3.setShowOnboardingHelp(false))));
|
|
1489
|
+
tasks.push(Promise.resolve(dispatch(advanceOnboarding(onboardingSteps.DEPLOYMENTS_PAST_COMPLETED))));
|
|
1490
|
+
}
|
|
1491
|
+
return Promise.all(tasks);
|
|
1492
|
+
});
|
|
1493
|
+
const setOnboardingCanceled = createAppAsyncThunk(`${sliceName$3}/setOnboardingCanceled`, (_, { dispatch }) => Promise.all([
|
|
1494
|
+
Promise.resolve(dispatch(actions$3.setShowOnboardingHelp(false))),
|
|
1495
|
+
Promise.resolve(dispatch(actions$3.setShowDismissOnboardingTipsDialog(false))),
|
|
1496
|
+
Promise.resolve(dispatch(actions$3.setOnboardingComplete(true)))
|
|
1497
|
+
]).then(() => dispatch(advanceOnboarding(onboardingSteps.DEPLOYMENTS_PAST_COMPLETED_FAILURE))).then(() => Tracking.event({
|
|
1498
|
+
category: "onboarding",
|
|
1499
|
+
action: onboardingSteps.ONBOARDING_CANCELED
|
|
1500
|
+
})));
|
|
1501
|
+
const advanceOnboarding = createAppAsyncThunk(`${sliceName$3}/advanceOnboarding`, (stepId, { dispatch, getState }) => {
|
|
1502
|
+
const steps = orderedOnboardingSteps;
|
|
1503
|
+
const progress = steps.findIndex((step) => step === getState().onboarding.progress);
|
|
1504
|
+
const stepIndex = steps.findIndex((step) => step === stepId);
|
|
1505
|
+
if (progress > stepIndex || getState().onboarding.progress === null) return;
|
|
1506
|
+
const madeProgress = steps[stepIndex + 1];
|
|
1507
|
+
const state = {
|
|
1508
|
+
...getOnboardingState$1(getState()),
|
|
1509
|
+
progress: madeProgress
|
|
1510
|
+
};
|
|
1511
|
+
state.complete = stepIndex + 1 >= orderedOnboardingSteps.findIndex((step) => step === onboardingSteps.DEPLOYMENTS_PAST_COMPLETED_FAILURE) ? true : state.complete;
|
|
1512
|
+
Tracking.event({
|
|
1513
|
+
category: "onboarding",
|
|
1514
|
+
action: stepId
|
|
1515
|
+
});
|
|
1516
|
+
return Promise.all([dispatch(actions$3.setOnboardingProgress(madeProgress)), dispatch(saveUserSettings({ onboarding: state }))]);
|
|
1517
|
+
});
|
|
1518
|
+
//#endregion
|
|
1519
|
+
//#region src/organizationSlice/thunks.ts
|
|
1520
|
+
const cookies$1 = new Cookies();
|
|
1521
|
+
dayjs.extend(utc);
|
|
1522
|
+
const { setAnnouncement: setAnnouncement$1, setSnackbar: setSnackbar$1 } = actions_default;
|
|
1523
|
+
const { page: defaultPage, perPage: defaultPerPage } = DEVICE_LIST_DEFAULTS;
|
|
1524
|
+
const cancelRequest = createAppAsyncThunk(`${sliceName$4}/cancelRequest`, (reason, { dispatch, getState }) => {
|
|
1525
|
+
const { id: tenantId } = getOrganization(getState());
|
|
1526
|
+
return Api.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/cancel`, { reason }).then(() => Promise.resolve(dispatch(setSnackbar$1({
|
|
1527
|
+
message: "Deactivation request was sent successfully",
|
|
1528
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
1529
|
+
}))));
|
|
1530
|
+
});
|
|
1531
|
+
const getTierId = (tierName) => tierName.replace("mender_", "");
|
|
1532
|
+
const getProductPlans = (products) => {
|
|
1533
|
+
return {
|
|
1534
|
+
...products.reduce((plansById, product) => {
|
|
1535
|
+
const { name, prices } = product;
|
|
1536
|
+
const tierId = getTierId(name);
|
|
1537
|
+
prices.forEach((price) => {
|
|
1538
|
+
const existing = plansById[price.plan] ?? {
|
|
1539
|
+
...PLANS[price.plan],
|
|
1540
|
+
tierLimitsConstrains: {}
|
|
1541
|
+
};
|
|
1542
|
+
const tierConstraints = price.constraints ? { [tierId]: {
|
|
1543
|
+
min: price.constraints.min,
|
|
1544
|
+
max: price.constraints.max,
|
|
1545
|
+
div: price.constraints.div
|
|
1546
|
+
} } : {};
|
|
1547
|
+
plansById[price.plan] = {
|
|
1548
|
+
...existing,
|
|
1549
|
+
tierLimitsConstrains: {
|
|
1550
|
+
...existing.tierLimitsConstrains,
|
|
1551
|
+
...tierConstraints
|
|
1552
|
+
}
|
|
1553
|
+
};
|
|
1554
|
+
});
|
|
1555
|
+
return plansById;
|
|
1556
|
+
}, {}),
|
|
1557
|
+
enterprise: { ...PLANS.enterprise }
|
|
1558
|
+
};
|
|
1559
|
+
};
|
|
1560
|
+
const getProductAddons = (products) => products.reduce((accu, product) => {
|
|
1561
|
+
const { addons = [] } = product;
|
|
1562
|
+
addons.forEach((addon) => {
|
|
1563
|
+
const { name: addonName = "", prices: addonPrices = [] } = addon;
|
|
1564
|
+
const existingEligible = accu[addonName]?.eligible ?? [];
|
|
1565
|
+
const newEligible = addonPrices.map((p) => p.plan);
|
|
1566
|
+
accu[addonName] = {
|
|
1567
|
+
...ADDONS[addonName],
|
|
1568
|
+
eligible: [...new Set([
|
|
1569
|
+
...existingEligible,
|
|
1570
|
+
...newEligible,
|
|
1571
|
+
PLANS.enterprise.id
|
|
1572
|
+
])]
|
|
1573
|
+
};
|
|
1574
|
+
});
|
|
1575
|
+
return accu;
|
|
1576
|
+
}, {});
|
|
1577
|
+
const transformProductResponse = (products) => {
|
|
1578
|
+
const tiers = [];
|
|
1579
|
+
products.sort((a, b) => a.name.localeCompare(b.name)).forEach((tier) => {
|
|
1580
|
+
const addonsSupported = Object.fromEntries((tier.addons || []).map((addon) => [addon.name, addon.prices?.map((p) => p.plan)]));
|
|
1581
|
+
const addonsTransposed = tier.prices.map((price) => price.plan).reduce((acc, plan) => {
|
|
1582
|
+
acc[plan] = Object.entries(addonsSupported).filter(([, addonSupportedPlans]) => addonSupportedPlans.includes(plan)).map(([addon]) => addon);
|
|
1583
|
+
return acc;
|
|
1584
|
+
}, {});
|
|
1585
|
+
const tierId = getTierId(tier.name);
|
|
1586
|
+
tiers.push({
|
|
1587
|
+
id: tierId,
|
|
1588
|
+
title: tierId,
|
|
1589
|
+
stripeProductName: tier.name,
|
|
1590
|
+
limitConstrains: Object.fromEntries(tier.prices.map((p) => [p.plan, p.constraints])),
|
|
1591
|
+
addons: addonsSupported,
|
|
1592
|
+
addonsByPlan: addonsTransposed
|
|
1593
|
+
});
|
|
1594
|
+
});
|
|
1595
|
+
return {
|
|
1596
|
+
plans: getProductPlans(products),
|
|
1597
|
+
tiers,
|
|
1598
|
+
addons: getProductAddons(products)
|
|
1599
|
+
};
|
|
1600
|
+
};
|
|
1601
|
+
const getTargetLocation = (key) => {
|
|
1602
|
+
if (devLocations.includes(window.location.hostname)) return "";
|
|
1603
|
+
let subdomainSections = window.location.hostname.substring(0, window.location.hostname.indexOf(locations.us.location)).split(".");
|
|
1604
|
+
subdomainSections = subdomainSections.splice(0, subdomainSections.length - 1);
|
|
1605
|
+
if (!subdomainSections.find((section) => section === key)) {
|
|
1606
|
+
subdomainSections = key === locations.us.key ? subdomainSections.filter((section) => !locations[section]) : [...subdomainSections, key];
|
|
1607
|
+
return `https://${[...subdomainSections, ...locations.us.location.split(".")].join(".")}`;
|
|
1608
|
+
}
|
|
1609
|
+
return `https://${window.location.hostname}`;
|
|
1610
|
+
};
|
|
1611
|
+
const devLocations = ["localhost", "docker.mender.io"];
|
|
1612
|
+
const createOrganizationTrial = createAppAsyncThunk(`${sliceName$4}/createOrganizationTrial`, async (data, { dispatch }) => {
|
|
1613
|
+
const { key } = locations[data.location];
|
|
1614
|
+
const targetLocation = getTargetLocation(key);
|
|
1615
|
+
const target = `${targetLocation}${tenantadmApiUrlv2}/tenants/trial`;
|
|
1616
|
+
const { headers } = await Api.postUnauthorized(target, data).catch((err) => {
|
|
1617
|
+
if (err.response?.status >= 400 && err.response?.status < 500) dispatch(setSnackbar$1({
|
|
1618
|
+
message: err.response.data.error,
|
|
1619
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
1620
|
+
}));
|
|
1621
|
+
else dispatch(setSnackbar$1({
|
|
1622
|
+
message: "There was an error creating your account",
|
|
1623
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
1624
|
+
}));
|
|
1625
|
+
return Promise.reject(err);
|
|
1626
|
+
});
|
|
1627
|
+
cookies$1.remove("oauth");
|
|
1628
|
+
cookies$1.remove("externalID");
|
|
1629
|
+
cookies$1.remove("email");
|
|
1630
|
+
dispatch(setFirstLoginAfterSignup(true));
|
|
1631
|
+
return new Promise((resolve) => setTimeout(() => {
|
|
1632
|
+
window.location.assign(`${targetLocation}${headers.location || ""}`);
|
|
1633
|
+
return resolve();
|
|
1634
|
+
}, TIMEOUTS.fiveSeconds));
|
|
1635
|
+
});
|
|
1636
|
+
const startCardUpdate = createAppAsyncThunk(`${sliceName$4}/startCardUpdate`, (_, { dispatch }) => Api.post(`${tenantadmApiUrlv2}/billing/card`).then(({ data }) => {
|
|
1637
|
+
dispatch(actions$4.receiveSetupIntent(data.intent_id));
|
|
1638
|
+
return Promise.resolve(data.secret);
|
|
1639
|
+
}).catch((err) => commonErrorHandler(err, `Updating the card failed:`, dispatch)));
|
|
1640
|
+
const confirmCardUpdate = createAppAsyncThunk(`${sliceName$4}/confirmCardUpdate`, (_, { dispatch, getState }) => Api.post(`${tenantadmApiUrlv2}/billing/card/${getState().organization.intentId}/confirm`).then(() => Promise.all([dispatch(setSnackbar$1("Payment card was updated successfully")), dispatch(actions$4.receiveSetupIntent(null))])).catch((err) => commonErrorHandler(err, `Updating the card failed:`, dispatch)));
|
|
1641
|
+
const getCurrentCard = createAppAsyncThunk(`${sliceName$4}/getCurrentCard`, (_, { dispatch }) => Api.get(`${tenantadmApiUrlv2}/billing`).then((res) => {
|
|
1642
|
+
const { last4, exp_month, exp_year, brand } = res.data.card || {};
|
|
1643
|
+
return Promise.resolve(dispatch(actions$4.receiveCurrentCard({
|
|
1644
|
+
brand,
|
|
1645
|
+
last4,
|
|
1646
|
+
expiration: {
|
|
1647
|
+
month: exp_month,
|
|
1648
|
+
year: exp_year
|
|
1649
|
+
}
|
|
1650
|
+
})));
|
|
1651
|
+
}));
|
|
1652
|
+
const startUpgrade = createAppAsyncThunk(`${sliceName$4}/startUpgrade`, (tenantId, { dispatch }) => Api.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/upgrade/start`).then(({ data }) => Promise.resolve(data.secret)).catch((err) => commonErrorHandler(err, `There was an error upgrading your account:`, dispatch)));
|
|
1653
|
+
const cancelUpgrade = createAppAsyncThunk(`${sliceName$4}/cancelUpgrade`, (tenantId) => Api.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/upgrade/cancel`));
|
|
1654
|
+
const completeUpgrade = createAppAsyncThunk(`${sliceName$4}/completeUpgrade`, ({ tenantId, plan, billing_profile }, { dispatch }) => Api.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/upgrade/complete`, {
|
|
1655
|
+
plan,
|
|
1656
|
+
billing_profile
|
|
1657
|
+
}).catch((err) => commonErrorHandler(err, `There was an error upgrading your account:`, dispatch)).then(() => Promise.all([dispatch(getDeviceLimits()), dispatch(getUserOrganization())])));
|
|
1658
|
+
const prepareAuditlogQuery = ({ startDate, endDate, user: userFilter, type, detail: detailFilter, sort = { direction: SORTING_OPTIONS.desc } }) => {
|
|
1659
|
+
const userId = typeof userFilter === "object" && userFilter ? userFilter.id : userFilter;
|
|
1660
|
+
const detail = typeof detailFilter === "object" && detailFilter ? detailFilter.id : detailFilter;
|
|
1661
|
+
const { start: startUnix, end: endUnix } = dateRangeToUnix(startDate, endDate);
|
|
1662
|
+
const createdAfter = startDate ? `&created_after=${startUnix}` : "";
|
|
1663
|
+
const createdBefore = endDate ? `&created_before=${endUnix}` : "";
|
|
1664
|
+
const typeSearch = type ? `&object_type=${type.value}`.toLowerCase() : "";
|
|
1665
|
+
const userSearch = userId ? `&actor_id=${userId}` : "";
|
|
1666
|
+
const objectSearch = type && detail ? `&${type.queryParameter}=${encodeURIComponent(detail)}` : "";
|
|
1667
|
+
const { direction = SORTING_OPTIONS.desc } = sort;
|
|
1668
|
+
return `${createdAfter}${createdBefore}${userSearch}${typeSearch}${objectSearch}&sort=${direction}`;
|
|
1669
|
+
};
|
|
1670
|
+
const getAuditLogs = createAppAsyncThunk(`${sliceName$4}/getAuditLogs`, async (selectionState, { dispatch, getState }) => {
|
|
1671
|
+
const { page, perPage } = selectionState;
|
|
1672
|
+
const { hasAuditlogs } = getTenantCapabilities(getState());
|
|
1673
|
+
if (!hasAuditlogs) return;
|
|
1674
|
+
const { data, headers } = await Api.get(`${auditLogsApiUrl}/logs?page=${page}&per_page=${perPage}${prepareAuditlogQuery(selectionState)}`).catch((err) => commonErrorHandler(err, `There was an error retrieving audit logs:`, dispatch));
|
|
1675
|
+
const total = Number(headers[headerNames.total] || data.length);
|
|
1676
|
+
return dispatch(actions$4.receiveAuditLogs({
|
|
1677
|
+
events: data,
|
|
1678
|
+
total
|
|
1679
|
+
}));
|
|
1680
|
+
});
|
|
1681
|
+
const getAuditLogsCsvLink = createAppAsyncThunk(`${sliceName$4}/getAuditLogsCsvLink`, (_, { getState }) => Promise.resolve(`${window.location.origin}${auditLogsApiUrl}/logs/export?limit=20000${prepareAuditlogQuery(getAuditlogState(getState()))}`));
|
|
1682
|
+
const setAuditlogsState = createAppAsyncThunk(`${sliceName$4}/setAuditlogsState`, (selectionState, { dispatch, getState }) => {
|
|
1683
|
+
const currentState = getAuditlogState(getState());
|
|
1684
|
+
const nextState = {
|
|
1685
|
+
...currentState,
|
|
1686
|
+
...selectionState,
|
|
1687
|
+
sort: {
|
|
1688
|
+
...currentState.sort,
|
|
1689
|
+
...selectionState.sort
|
|
1690
|
+
}
|
|
1691
|
+
};
|
|
1692
|
+
const tasks = [];
|
|
1693
|
+
const { isLoading: currentLoading, selectedIssue: currentIssue, ...currentRequestState } = currentState;
|
|
1694
|
+
const { isLoading: selectionLoading, selectedIssue: selectionIssue, ...selectionRequestState } = nextState;
|
|
1695
|
+
if (!deepCompare(currentRequestState, selectionRequestState)) {
|
|
1696
|
+
nextState.isLoading = true;
|
|
1697
|
+
tasks.push(dispatch(getAuditLogs(nextState)).finally(() => dispatch(actions$4.setAuditLogState({ isLoading: false }))));
|
|
1698
|
+
}
|
|
1699
|
+
tasks.push(Promise.resolve(dispatch(actions$4.setAuditLogState(nextState))));
|
|
1700
|
+
return Promise.all(tasks);
|
|
1701
|
+
});
|
|
1702
|
+
const tenantDataDivergedMessage = "The system detected there is a change in your plan or purchased add-ons. Please log out and log in again";
|
|
1703
|
+
const addTenant = createAppAsyncThunk(`${sliceName$4}/createTenant`, (selectionState, { dispatch, getState }) => {
|
|
1704
|
+
const spLimits = getSpLimits(getState());
|
|
1705
|
+
const { deviceLimits, ...rest } = selectionState;
|
|
1706
|
+
const device_limits = convertToBackendSPLimits(deviceLimits, spLimits);
|
|
1707
|
+
return Api.post(`${tenantadmApiUrlv2}/tenants`, {
|
|
1708
|
+
...rest,
|
|
1709
|
+
device_limits
|
|
1710
|
+
}).then(() => Promise.all([dispatch(setSnackbar$1("Tenant was created successfully.")), new Promise((resolve) => setTimeout(() => resolve(dispatch(getTenants())), TIMEOUTS.oneSecond))])).catch((err) => commonErrorHandler(err, "There was an error creating tenant", dispatch, commonErrorFallback));
|
|
1711
|
+
});
|
|
1712
|
+
const tenantListRetrieval = async (config) => {
|
|
1713
|
+
const { page, perPage } = config;
|
|
1714
|
+
const params = new URLSearchParams({
|
|
1715
|
+
page,
|
|
1716
|
+
per_page: perPage,
|
|
1717
|
+
tiers: "true"
|
|
1718
|
+
}).toString();
|
|
1719
|
+
const tenantList = await Api.get(`${tenantadmApiUrlv2}/tenants?${params}`);
|
|
1720
|
+
const totalCount = tenantList.headers[headerNames.total] || TENANT_LIST_DEFAULT.perPage;
|
|
1721
|
+
return [tenantList.data, Number(totalCount)];
|
|
1722
|
+
};
|
|
1723
|
+
const getTenants = createAppAsyncThunk(`${sliceName$4}/getTenants`, async (_, { dispatch, getState }) => {
|
|
1724
|
+
const currentState = getTenantsList(getState());
|
|
1725
|
+
const [tenants, pageCount] = await tenantListRetrieval(currentState);
|
|
1726
|
+
dispatch(actions$4.setTenantListState({
|
|
1727
|
+
...currentState,
|
|
1728
|
+
total: pageCount,
|
|
1729
|
+
tenants
|
|
1730
|
+
}));
|
|
1731
|
+
});
|
|
1732
|
+
const setTenantsListState = createAppAsyncThunk(`${sliceName$4}/setTenantsListState`, async (selectionState, { dispatch, getState }) => {
|
|
1733
|
+
const currentState = getTenantsList(getState());
|
|
1734
|
+
const nextState = {
|
|
1735
|
+
...currentState,
|
|
1736
|
+
...selectionState
|
|
1737
|
+
};
|
|
1738
|
+
if (!deepCompare(currentState, selectionState)) {
|
|
1739
|
+
const [tenants, pageCount] = await tenantListRetrieval(nextState);
|
|
1740
|
+
return dispatch(actions$4.setTenantListState({
|
|
1741
|
+
...nextState,
|
|
1742
|
+
tenants,
|
|
1743
|
+
total: pageCount
|
|
1744
|
+
}));
|
|
1745
|
+
}
|
|
1746
|
+
return dispatch(actions$4.setTenantListState({ ...nextState }));
|
|
1747
|
+
});
|
|
1748
|
+
const editTenant = createAppAsyncThunk(`${sliceName$4}/editDeviceLimit`, ({ deviceLimits, id, name }, { dispatch, getState }) => {
|
|
1749
|
+
const device_limits = convertToBackendSPLimits(deviceLimits, getSpLimits(getState()));
|
|
1750
|
+
return Api.put(`${tenantadmApiUrlv2}/tenants/${id}/child`, {
|
|
1751
|
+
device_limits,
|
|
1752
|
+
name
|
|
1753
|
+
}).catch((err) => commonErrorHandler(err, `Device Limit cannot be changed`, dispatch)).then(() => Promise.all([
|
|
1754
|
+
dispatch(setSnackbar$1("Tenant was changed successfully")),
|
|
1755
|
+
dispatch(getUserOrganization()),
|
|
1756
|
+
new Promise((resolve) => setTimeout(() => resolve(dispatch(getTenants())), TIMEOUTS.oneSecond))
|
|
1757
|
+
]));
|
|
1758
|
+
});
|
|
1759
|
+
const editBillingProfile = createAppAsyncThunk(`${sliceName$4}/editBillingProfileEmail`, ({ billingProfile }, { dispatch }) => Api.patch(`${tenantadmApiUrlv2}/billing/profile`, billingProfile).catch((err) => commonErrorHandler(err, `Failed to change billing profile`, dispatch)).then(() => Promise.all([dispatch(setSnackbar$1("Billing Profile was changed successfully")), dispatch(getUserBilling())])));
|
|
1760
|
+
const createBillingProfile = createAppAsyncThunk(`${sliceName$4}/createBillingProfileEmail`, ({ billingProfile }, { dispatch }) => Api.post(`${tenantadmApiUrlv2}/billing/profile`, billingProfile).catch((err) => commonErrorHandler(err, `Failed to create billing profile`, dispatch)).then(() => Promise.all([dispatch(setSnackbar$1("Billing Profile was created successfully")), dispatch(getUserBilling())])));
|
|
1761
|
+
const removeTenant = createAppAsyncThunk(`${sliceName$4}/editDeviceLimit`, ({ id }, { dispatch }) => Api.post(`${tenantadmApiUrlv2}/tenants/${id}/remove/start`).catch((err) => commonErrorHandler(err, `There was an error removing the tenant`, dispatch)).then(() => Promise.all([
|
|
1762
|
+
dispatch(setSnackbar$1("The tenant was removed successfully")),
|
|
1763
|
+
dispatch(getUserOrganization()),
|
|
1764
|
+
new Promise((resolve) => setTimeout(() => resolve(dispatch(getTenants())), TIMEOUTS.oneSecond))
|
|
1765
|
+
])));
|
|
1766
|
+
const getUserOrganization = createAppAsyncThunk(`${sliceName$4}/getUserOrganization`, (_, { dispatch, getState }) => Api.get(`${tenantadmApiUrlv1}/user/tenant?tiers=true`).then((res) => {
|
|
1767
|
+
const { addons, plan, trial } = res.data;
|
|
1768
|
+
const { addons: currentAddons, id: currentId, plan: currentPlan, trial: currentTrial } = getOrganization(getState());
|
|
1769
|
+
const tasks = [dispatch(actions$4.setOrganization(res.data))];
|
|
1770
|
+
if (currentId && !deepCompare({
|
|
1771
|
+
addons,
|
|
1772
|
+
plan,
|
|
1773
|
+
trial
|
|
1774
|
+
}, {
|
|
1775
|
+
addons: currentAddons,
|
|
1776
|
+
plan: currentPlan,
|
|
1777
|
+
trial: currentTrial
|
|
1778
|
+
})) {
|
|
1779
|
+
const hash = hashString(tenantDataDivergedMessage);
|
|
1780
|
+
const { id: currentUserId } = getCurrentUser(getState());
|
|
1781
|
+
cookies$1.remove(`${currentUserId}${hash}`);
|
|
1782
|
+
tasks.push(dispatch(setAnnouncement$1(tenantDataDivergedMessage)));
|
|
1783
|
+
}
|
|
1784
|
+
return Promise.all(tasks);
|
|
1785
|
+
}));
|
|
1786
|
+
const getUserBilling = createAppAsyncThunk(`${sliceName$4}/getUserBilling`, (_, { dispatch }) => Api.get(`${tenantadmApiUrlv2}/billing/profile`).catch((err) => commonErrorHandler(err, "There was an error getting your billing profile:", dispatch, commonErrorFallback)).then((res) => dispatch(actions$4.setBillingProfile(res.data))));
|
|
1787
|
+
const getUserSubscription = createAppAsyncThunk(`${sliceName$4}/getUserSubscription`, async (_, { dispatch }) => {
|
|
1788
|
+
const currentSubscription = await dispatch(getCurrentSubscription()).unwrap();
|
|
1789
|
+
const currentPreview = await dispatch(getBillingPreview({ preview_mode: "next" })).unwrap();
|
|
1790
|
+
return dispatch(actions$4.setSubscription({
|
|
1791
|
+
...currentPreview,
|
|
1792
|
+
...currentSubscription
|
|
1793
|
+
}));
|
|
1794
|
+
});
|
|
1795
|
+
const getBillingPreview = createAppAsyncThunk(`${sliceName$4}/getBillingPreview`, (order, { dispatch }) => Api.post(`${tenantadmApiUrlv2}/billing/subscription/invoices/preview`, order).catch((err) => commonErrorHandler(err, "There was an error getting your billing information:", dispatch, commonErrorFallback)).then(({ data }) => order.preview_mode === "recurring" ? {
|
|
1796
|
+
items: parseSubscriptionPreview(data.lines),
|
|
1797
|
+
total: data.total
|
|
1798
|
+
} : data));
|
|
1799
|
+
const getCurrentSubscription = createAppAsyncThunk(`${sliceName$4}/getCurrentSubscription`, (_, { dispatch }) => Api.get(`${tenantadmApiUrlv2}/billing/subscription`).then((res) => res.data).catch((err) => {
|
|
1800
|
+
if (err.response && err.response.status === 404) throw new Error("Request failed with status code 404");
|
|
1801
|
+
return commonErrorHandler(err, "There was an error retrieving your current subscription", dispatch, commonErrorFallback);
|
|
1802
|
+
}));
|
|
1803
|
+
const getProducts = createAppAsyncThunk(`${sliceName$4}/getEnabledTiers`, (_, { dispatch }) => Api.get(`${tenantadmApiUrlv2}/billing/products`).catch((err) => commonErrorHandler(err, "There was an error getting Mender products:", dispatch, commonErrorFallback)).then((res) => dispatch(actions$4.setProducts(transformProductResponse(res.data)))));
|
|
1804
|
+
const requestPlanUpgrade = createAppAsyncThunk(`${sliceName$4}/requestPlanUpgrade`, (order, { dispatch }) => Api.post(`${tenantadmApiUrlv2}/billing/subscription`, order).catch((err) => commonErrorHandler(err, "There was an error sending your request", dispatch, commonErrorFallback)).then(() => Promise.all([setTimeout(() => dispatch(getDeviceLimits()), TIMEOUTS.threeSeconds), dispatch(getUserOrganization())])));
|
|
1805
|
+
const sendSupportMessage = createAppAsyncThunk(`${sliceName$4}/sendSupportMessage`, (content, { dispatch }) => Api.post(`${tenantadmApiUrlv2}/contact/support`, content).catch((err) => commonErrorHandler(err, "There was an error sending your request", dispatch, commonErrorFallback)).then(() => Promise.resolve(dispatch(setSnackbar$1({
|
|
1806
|
+
message: "Your request was sent successfully",
|
|
1807
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
1808
|
+
})))));
|
|
1809
|
+
const requestPlanChange = createAppAsyncThunk(`${sliceName$4}/requestPlanChange`, ({ content, tenantId }, { dispatch, rejectWithValue }) => Api.post(`${tenantadmApiUrlv2}/tenants/${tenantId}/plan`, content).catch(async (err) => {
|
|
1810
|
+
await commonErrorHandler(err, "There was an error sending your request", dispatch, commonErrorFallback);
|
|
1811
|
+
rejectWithValue(err);
|
|
1812
|
+
}).then(() => Promise.resolve(dispatch(setSnackbar$1({
|
|
1813
|
+
message: "Your request was sent successfully",
|
|
1814
|
+
autoHideDuration: TIMEOUTS.fiveSeconds
|
|
1815
|
+
})))));
|
|
1816
|
+
const downloadLicenseReport = createAppAsyncThunk(`${sliceName$4}/downloadLicenseReport`, (_, { dispatch }) => Api.get(`${deviceAuthV2}/license`).catch((err) => commonErrorHandler(err, "There was an error downloading the report", dispatch, commonErrorFallback)).then((res) => res.data));
|
|
1817
|
+
const createIntegration = createAppAsyncThunk(`${sliceName$4}/createIntegration`, ({ id, ...integration }, { dispatch }) => Api.post(`${iotManagerBaseURL}/integrations`, integration).catch((err) => commonErrorHandler(err, "There was an error creating the integration", dispatch, commonErrorFallback)).then(() => Promise.all([dispatch(setSnackbar$1("The integration was set up successfully")), dispatch(getIntegrations())])));
|
|
1818
|
+
const changeIntegration = createAppAsyncThunk(`${sliceName$4}/changeIntegration`, ({ id, credentials }, { dispatch }) => Api.put(`${iotManagerBaseURL}/integrations/${id}/credentials`, credentials).catch((err) => commonErrorHandler(err, "There was an error updating the integration", dispatch, commonErrorFallback)).then(() => Promise.all([dispatch(setSnackbar$1("The integration was updated successfully")), dispatch(getIntegrations())])));
|
|
1819
|
+
const deleteIntegration = createAppAsyncThunk(`${sliceName$4}/deleteIntegration`, ({ id, provider }, { dispatch, getState }) => Api.delete(`${iotManagerBaseURL}/integrations/${id}`, {}).catch((err) => commonErrorHandler(err, "There was an error removing the integration", dispatch, commonErrorFallback)).then(() => {
|
|
1820
|
+
const integrations = getState().organization.externalDeviceIntegrations.filter((item) => provider !== item.provider);
|
|
1821
|
+
return Promise.all([dispatch(setSnackbar$1("The integration was removed successfully")), dispatch(actions$4.receiveExternalDeviceIntegrations(integrations))]);
|
|
1822
|
+
}));
|
|
1823
|
+
const getIntegrations = createAppAsyncThunk(`${sliceName$4}/getIntegrations`, (_, { dispatch, getState }) => Api.get(`${iotManagerBaseURL}/integrations`).catch((err) => commonErrorHandler(err, "There was an error retrieving the integration", dispatch, commonErrorFallback)).then(({ data }) => {
|
|
1824
|
+
const existingIntegrations = getState().organization.externalDeviceIntegrations;
|
|
1825
|
+
const integrations = data.reduce((accu, item) => {
|
|
1826
|
+
const integration = {
|
|
1827
|
+
...existingIntegrations.find((integration) => item.id === integration.id) ?? {},
|
|
1828
|
+
...item
|
|
1829
|
+
};
|
|
1830
|
+
accu.push(integration);
|
|
1831
|
+
return accu;
|
|
1832
|
+
}, []);
|
|
1833
|
+
return Promise.resolve(dispatch(actions$4.receiveExternalDeviceIntegrations(integrations)));
|
|
1834
|
+
}));
|
|
1835
|
+
const getWebhookEvents = createAppAsyncThunk(`${sliceName$4}/getWebhookEvents`, (config = {}, { dispatch, getState }) => {
|
|
1836
|
+
const { isFollowUp, page = defaultPage, perPage = defaultPerPage } = config;
|
|
1837
|
+
return Api.get(`${iotManagerBaseURL}/events?page=${page}&per_page=${perPage}`).catch((err) => commonErrorHandler(err, "There was an error retrieving activity for this integration", dispatch, commonErrorFallback)).then(({ data }) => {
|
|
1838
|
+
const tasks = [Promise.resolve(dispatch(actions$4.receiveWebhookEvents({
|
|
1839
|
+
value: isFollowUp ? getState().organization.webhooks.events : data,
|
|
1840
|
+
total: (page - 1) * perPage + data.length
|
|
1841
|
+
})))];
|
|
1842
|
+
if (data.length >= perPage && !isFollowUp) tasks.push(dispatch(getWebhookEvents({
|
|
1843
|
+
isFollowUp: true,
|
|
1844
|
+
page: page + 1,
|
|
1845
|
+
perPage: 1
|
|
1846
|
+
})));
|
|
1847
|
+
return Promise.all(tasks);
|
|
1848
|
+
});
|
|
1849
|
+
});
|
|
1850
|
+
const ssoConfigActions = {
|
|
1851
|
+
create: {
|
|
1852
|
+
success: "stored",
|
|
1853
|
+
error: "storing"
|
|
1854
|
+
},
|
|
1855
|
+
edit: {
|
|
1856
|
+
success: "updated",
|
|
1857
|
+
error: "updating"
|
|
1858
|
+
},
|
|
1859
|
+
read: {
|
|
1860
|
+
success: "",
|
|
1861
|
+
error: "retrieving"
|
|
1862
|
+
},
|
|
1863
|
+
remove: {
|
|
1864
|
+
success: "removed",
|
|
1865
|
+
error: "removing"
|
|
1866
|
+
},
|
|
1867
|
+
readMultiple: {
|
|
1868
|
+
success: "",
|
|
1869
|
+
error: "retrieving"
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
const ssoConfigActionErrorHandler = (err, type) => (dispatch) => commonErrorHandler(err, `There was an error ${ssoConfigActions[type].error} the SSO configuration.`, dispatch, commonErrorFallback);
|
|
1873
|
+
const ssoConfigActionSuccessHandler = (type) => (dispatch) => dispatch(setSnackbar$1(`The SSO configuration was ${ssoConfigActions[type].success} successfully`));
|
|
1874
|
+
const storeSsoConfig = createAppAsyncThunk(`${sliceName$4}/storeSsoConfig`, ({ config, contentType }, { dispatch }) => Api.post(ssoIdpApiUrlv1, config, { headers: {
|
|
1875
|
+
"Content-Type": contentType,
|
|
1876
|
+
Accept: "application/json"
|
|
1877
|
+
} }).catch((err) => dispatch(ssoConfigActionErrorHandler(err, "create"))).then(() => Promise.all([dispatch(ssoConfigActionSuccessHandler("create")), dispatch(getSsoConfigs())])));
|
|
1878
|
+
const changeSsoConfig = createAppAsyncThunk(`${sliceName$4}/changeSsoConfig`, ({ config, contentType }, { dispatch }) => Api.put(`${ssoIdpApiUrlv1}/${config.id}`, config.config, { headers: {
|
|
1879
|
+
"Content-Type": contentType,
|
|
1880
|
+
Accept: "application/json"
|
|
1881
|
+
} }).catch((err) => dispatch(ssoConfigActionErrorHandler(err, "edit"))).then(() => Promise.all([dispatch(ssoConfigActionSuccessHandler("edit")), dispatch(getSsoConfigs())])));
|
|
1882
|
+
const deleteSsoConfig = createAppAsyncThunk(`${sliceName$4}/deleteSsoConfig`, ({ id }, { dispatch, getState }) => Api.delete(`${ssoIdpApiUrlv1}/${id}`).catch((err) => dispatch(ssoConfigActionErrorHandler(err, "remove"))).then(() => {
|
|
1883
|
+
const configs = getState().organization.ssoConfigs.filter((item) => id !== item.id);
|
|
1884
|
+
return Promise.all([dispatch(ssoConfigActionSuccessHandler("remove")), dispatch(actions$4.receiveSsoConfigs(configs))]);
|
|
1885
|
+
}));
|
|
1886
|
+
const getSsoConfigById = createAppAsyncThunk(`${sliceName$4}/getSsoConfigById`, (config, { dispatch }) => Api.get(`${ssoIdpApiUrlv1}/${config.id}`).catch((err) => dispatch(ssoConfigActionErrorHandler(err, "read"))).then(({ data, headers }) => {
|
|
1887
|
+
const sso = Object.values(SSO_TYPES).find(({ contentType }) => contentType === headers["content-type"]);
|
|
1888
|
+
return sso ? Promise.resolve({
|
|
1889
|
+
...config,
|
|
1890
|
+
config: data,
|
|
1891
|
+
type: sso.id
|
|
1892
|
+
}) : Promise.reject("Unsupported SSO config content type.");
|
|
1893
|
+
}));
|
|
1894
|
+
const getSsoConfigs = createAppAsyncThunk(`${sliceName$4}/getSsoConfigs`, (_, { dispatch }) => Api.get(ssoIdpApiUrlv1).catch((err) => dispatch(ssoConfigActionErrorHandler(err, "readMultiple"))).then(({ data }) => Promise.all(data.map((config) => dispatch(getSsoConfigById(config)).unwrap())).then((configs) => dispatch(actions$4.receiveSsoConfigs(configs))).catch((err) => commonErrorHandler(err, err, dispatch, ""))));
|
|
1895
|
+
//#endregion
|
|
1896
|
+
//#region src/usersSlice/thunks.ts
|
|
1897
|
+
const cookies = new Cookies();
|
|
1898
|
+
const { setAnnouncement, setSnackbar } = actions_default;
|
|
1899
|
+
const handleLoginError = (err, { token2fa: has2FA, password }, rejectWithValue) => () => {
|
|
1900
|
+
const is2FABackend = extractErrorMessage(err).includes("2fa");
|
|
1901
|
+
if (is2FABackend && !has2FA) return rejectWithValue({ error: "2fa code missing" });
|
|
1902
|
+
if (password === void 0) return Promise.reject();
|
|
1903
|
+
const twoFAError = is2FABackend ? " and verification code" : "";
|
|
1904
|
+
return rejectWithValue({ error: `There was a problem logging in. Please check your email${twoFAError ? "," : " and"} password${twoFAError}. If you still have problems, contact an administrator.` });
|
|
1905
|
+
};
|
|
1906
|
+
const loginUser = createAppAsyncThunk(`${sliceName$5}/loginUser`, ({ stayLoggedIn, ...userData }, { dispatch, rejectWithValue }) => Api$1.postLogin(`${useradmApiUrl}/auth/login`, {
|
|
1907
|
+
...userData,
|
|
1908
|
+
no_expiry: stayLoggedIn
|
|
1909
|
+
}).catch((err) => {
|
|
1910
|
+
cleanUp();
|
|
1911
|
+
return Promise.reject(dispatch(handleLoginError(err, userData, rejectWithValue)));
|
|
1912
|
+
}).then(({ text: token, contentType }) => {
|
|
1913
|
+
if (contentType?.includes(APPLICATION_JSON_CONTENT_TYPE)) {
|
|
1914
|
+
const { id, kind } = token;
|
|
1915
|
+
const ssoLoginUrl = SSO_TYPES[kind.split("/")[1]].getStartUrl(id);
|
|
1916
|
+
window.location.replace(ssoLoginUrl);
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
if (contentType !== APPLICATION_JWT_CONTENT_TYPE || !token) return;
|
|
1920
|
+
const now = /* @__PURE__ */ new Date();
|
|
1921
|
+
now.setSeconds(now.getSeconds() + maxSessionAge);
|
|
1922
|
+
const expiresAt = stayLoggedIn ? void 0 : now.toISOString();
|
|
1923
|
+
setSessionInfo({
|
|
1924
|
+
token,
|
|
1925
|
+
expiresAt
|
|
1926
|
+
});
|
|
1927
|
+
cookies.remove("JWT", { path: "/" });
|
|
1928
|
+
return dispatch(getUser("me")).unwrap().catch((e) => {
|
|
1929
|
+
cleanUp();
|
|
1930
|
+
return Promise.reject(dispatch(setSnackbar(extractErrorMessage(e))));
|
|
1931
|
+
}).then(() => {
|
|
1932
|
+
window.sessionStorage.removeItem("pendings-redirect");
|
|
1933
|
+
if (window.location.pathname !== "/ui/") window.location.replace("/ui/");
|
|
1934
|
+
return Promise.resolve(dispatch(actions$5.successfullyLoggedIn({
|
|
1935
|
+
expiresAt,
|
|
1936
|
+
token
|
|
1937
|
+
})));
|
|
1938
|
+
});
|
|
1939
|
+
}));
|
|
1940
|
+
const logoutUser = createAppAsyncThunk(`${sliceName$5}/logoutUser`, (_, { dispatch, getState }) => {
|
|
1941
|
+
if (Object.keys(getState().app.uploadsById).length) return Promise.reject();
|
|
1942
|
+
return Api.post(`${useradmApiUrl}/auth/logout`).finally(() => {
|
|
1943
|
+
cleanUp();
|
|
1944
|
+
clearAllRetryTimers(setSnackbar);
|
|
1945
|
+
return Promise.resolve(dispatch({ type: USER_LOGOUT }));
|
|
1946
|
+
});
|
|
1947
|
+
});
|
|
1948
|
+
const switchUserOrganization = createAppAsyncThunk(`${sliceName$5}/switchUserOrganization`, (tenantId, { getState }) => {
|
|
1949
|
+
if (Object.keys(getState().app.uploadsById).length) return Promise.reject();
|
|
1950
|
+
return Api.get(`${useradmApiUrl}/users/tenants/${tenantId}/token`).then(({ data: token }) => {
|
|
1951
|
+
window.sessionStorage.setItem("tenantChanged", "true");
|
|
1952
|
+
setSessionInfo({
|
|
1953
|
+
...getSessionInfo(),
|
|
1954
|
+
token
|
|
1955
|
+
});
|
|
1956
|
+
window.location.reload();
|
|
1957
|
+
});
|
|
1958
|
+
});
|
|
1959
|
+
const passwordResetStart = createAppAsyncThunk(`${sliceName$5}/passwordResetStart`, (email, { dispatch }) => Api.post(`${useradmApiUrl}/auth/password-reset/start`, { email }).catch((err) => commonErrorHandler(err, `The password reset request cannot be processed:`, dispatch, void 0, true)));
|
|
1960
|
+
const passwordResetComplete = createAppAsyncThunk(`${sliceName$5}/passwordResetComplete`, ({ secretHash, newPassword }, { dispatch }) => Api.post(`${useradmApiUrl}/auth/password-reset/complete`, {
|
|
1961
|
+
secret_hash: secretHash,
|
|
1962
|
+
password: newPassword
|
|
1963
|
+
}).catch((err = {}) => {
|
|
1964
|
+
const { error, response = {} } = err;
|
|
1965
|
+
let errorMsg = "";
|
|
1966
|
+
if (response.status == 400) errorMsg = "the link you are using expired or the request is not valid, please try again.";
|
|
1967
|
+
else errorMsg = error;
|
|
1968
|
+
dispatch(setSnackbar("The password reset request cannot be processed: " + errorMsg));
|
|
1969
|
+
return Promise.reject(err);
|
|
1970
|
+
}));
|
|
1971
|
+
const verifyEmailStart = createAppAsyncThunk(`${sliceName$5}/verifyEmailStart`, (_, { dispatch, getState }) => Api.post(`${useradmApiUrl}/auth/verify-email/start`, { email: getCurrentUser(getState()).email }).catch((err) => commonErrorHandler(err, "An error occured starting the email verification process:", dispatch)).finally(() => Promise.resolve(dispatch(getUser("me")))));
|
|
1972
|
+
const verifyEmailComplete = createAppAsyncThunk(`${sliceName$5}/verifyEmailComplete`, (secret_hash, { dispatch, rejectWithValue }) => Api.post(`${useradmApiUrl}/auth/verify-email/complete`, { secret_hash }).catch((err) => rejectWithValue({
|
|
1973
|
+
status: err.response?.status,
|
|
1974
|
+
data: err.response?.data
|
|
1975
|
+
})).finally(() => Promise.resolve(dispatch(getUser("me")))));
|
|
1976
|
+
const verify2FA = createAppAsyncThunk(`${sliceName$5}/verify2FA`, (tfaData, { dispatch }) => Api$1.putVerifyTFA(`${useradmApiUrl}/2faverify`, tfaData).then(() => Promise.resolve(dispatch(getUser("me")))).catch((err) => commonErrorHandler(err, "An error occured validating the verification code: failed to verify token, please try again.", dispatch, void 0, true)));
|
|
1977
|
+
const getUserList = createAppAsyncThunk(`${sliceName$5}/getUserList`, (_, { dispatch, getState }) => Api.get(`${useradmApiUrl}/users`).then((res) => {
|
|
1978
|
+
const currentUsersById = getUsersById(getState());
|
|
1979
|
+
const users = res.data.reduce((accu, item) => {
|
|
1980
|
+
accu[item.id] = {
|
|
1981
|
+
...accu[item.id],
|
|
1982
|
+
...item
|
|
1983
|
+
};
|
|
1984
|
+
return accu;
|
|
1985
|
+
}, { ...currentUsersById });
|
|
1986
|
+
return dispatch(actions$5.receivedUserList(users));
|
|
1987
|
+
}).catch((err) => commonErrorHandler(err, `Users couldn't be loaded.`, dispatch, commonErrorFallback)));
|
|
1988
|
+
const getUser = createAppAsyncThunk(`${sliceName$5}/getUser`, (id, { dispatch, rejectWithValue }) => Api.get(`${useradmApiUrl}/users/${id}`).then(({ data: user }) => Promise.all([
|
|
1989
|
+
dispatch(actions$5.receivedUser(user)),
|
|
1990
|
+
dispatch(setHideAnnouncement({
|
|
1991
|
+
shouldHide: false,
|
|
1992
|
+
userId: user.id
|
|
1993
|
+
})),
|
|
1994
|
+
dispatch(updateUserColumnSettings({ currentUserId: user.id })),
|
|
1995
|
+
user
|
|
1996
|
+
])).catch((e) => rejectWithValue(e)));
|
|
1997
|
+
const initializeSelf = createAppAsyncThunk(`${sliceName$5}/initializeSelf`, (_, { dispatch }) => dispatch(getUser("me")));
|
|
1998
|
+
const updateUserColumnSettings = createAppAsyncThunk(`${sliceName$5}/updateUserColumnSettings`, ({ columns, currentUserId }, { dispatch, getState }) => {
|
|
1999
|
+
const storageKey = `${currentUserId ?? getCurrentUser(getState()).id}-column-widths`;
|
|
2000
|
+
let customColumns = [];
|
|
2001
|
+
if (!columns) try {
|
|
2002
|
+
customColumns = JSON.parse(window.localStorage.getItem(storageKey) || "") || customColumns;
|
|
2003
|
+
} catch {}
|
|
2004
|
+
else customColumns = columns;
|
|
2005
|
+
window.localStorage.setItem(storageKey, JSON.stringify(customColumns));
|
|
2006
|
+
return Promise.resolve(dispatch(actions$5.setCustomColumns(customColumns)));
|
|
2007
|
+
});
|
|
2008
|
+
const userActions = {
|
|
2009
|
+
add: {
|
|
2010
|
+
successMessage: "The user was added successfully.",
|
|
2011
|
+
errorMessage: "adding"
|
|
2012
|
+
},
|
|
2013
|
+
create: {
|
|
2014
|
+
successMessage: "The user was created successfully.",
|
|
2015
|
+
errorMessage: "creating"
|
|
2016
|
+
},
|
|
2017
|
+
edit: {
|
|
2018
|
+
successMessage: "The user has been updated.",
|
|
2019
|
+
errorMessage: "editing"
|
|
2020
|
+
},
|
|
2021
|
+
remove: {
|
|
2022
|
+
successMessage: "The user was removed from the system.",
|
|
2023
|
+
errorMessage: "removing"
|
|
2024
|
+
}
|
|
2025
|
+
};
|
|
2026
|
+
const userActionErrorHandler = (err, type, dispatch) => commonErrorHandler(err, `There was an error ${userActions[type].errorMessage} the user.`, dispatch);
|
|
2027
|
+
const createUser = createAppAsyncThunk(`${sliceName$5}/createUser`, ({ shouldResetPassword, ...userData }, { dispatch }) => Api.post(`${useradmApiUrl}/users`, {
|
|
2028
|
+
...userData,
|
|
2029
|
+
send_reset_password: shouldResetPassword
|
|
2030
|
+
}).then(() => Promise.all([dispatch(getUserList()), dispatch(setSnackbar(userActions.create.successMessage))])).catch((err) => userActionErrorHandler(err, "create", dispatch)));
|
|
2031
|
+
const removeUser = createAppAsyncThunk(`${sliceName$5}/removeUser`, (userId, { dispatch }) => Api.delete(`${useradmApiUrl}/users/${userId}`).then(() => Promise.all([
|
|
2032
|
+
dispatch(actions$5.removedUser(userId)),
|
|
2033
|
+
dispatch(getUserList()),
|
|
2034
|
+
dispatch(setSnackbar(userActions.remove.successMessage))
|
|
2035
|
+
])).catch((err) => userActionErrorHandler(err, "remove", dispatch)));
|
|
2036
|
+
const editUser = createAppAsyncThunk(`${sliceName$5}/editUser`, ({ id, ...userData }, { dispatch, getState }) => Api.put(`${useradmApiUrl}/users/${id}`, userData).then(() => Promise.all([dispatch(actions$5.updatedUser({
|
|
2037
|
+
...userData,
|
|
2038
|
+
id: id === "me" ? getCurrentUser(getState()).id : id
|
|
2039
|
+
})), dispatch(setSnackbar(userActions.edit.successMessage))])).catch((err) => userActionErrorHandler(err, "edit", dispatch)));
|
|
2040
|
+
const checkEmailExists = createAppAsyncThunk(`${sliceName$5}/checkEmailExists`, async (email) => {
|
|
2041
|
+
return (await Api.get(`${useradmApiUrl}/users/exists?email=${encodeURIComponent(email)}`)).data.exists;
|
|
2042
|
+
});
|
|
2043
|
+
const addUserToCurrentTenant = createAppAsyncThunk(`${sliceName$5}/addUserToTenant`, (userId, { dispatch, getState }) => {
|
|
2044
|
+
const { id } = getOrganization(getState());
|
|
2045
|
+
return Api.post(`${useradmApiUrl}/users/${userId}/assign`, { tenant_ids: [id] }).catch((err) => commonErrorHandler(err, `There was an error adding the user to your organization:`, dispatch)).then(() => Promise.all([dispatch(setSnackbar(userActions.add.successMessage)), dispatch(getUserList())]));
|
|
2046
|
+
});
|
|
2047
|
+
const enableUser2fa = createAppAsyncThunk(`${sliceName$5}/enableUser2fa`, (userId = "me", { dispatch }) => Api.post(`${useradmApiUrl}/users/${userId}/2fa/enable`).catch((err) => commonErrorHandler(err, `There was an error enabling Two Factor authentication for the user.`, dispatch)).then(() => Promise.resolve(dispatch(getUser(userId)))));
|
|
2048
|
+
const disableUser2fa = createAppAsyncThunk(`${sliceName$5}/disableUser2fa`, (userId = "me", { dispatch }) => Api.post(`${useradmApiUrl}/users/${userId}/2fa/disable`).catch((err) => commonErrorHandler(err, `There was an error disabling Two Factor authentication for the user.`, dispatch)).then(() => Promise.all([dispatch(getUser(userId)), dispatch(actions$5.receivedQrCode(null))])));
|
|
2049
|
+
const mapHttpPermission = (permission) => Object.entries(uiPermissionsByArea).reduce((accu, [area, definition]) => {
|
|
2050
|
+
const endpointMatches = definition.endpoints.filter((endpoint) => endpoint.path.test(permission.value) && (endpoint.types.includes(permission.type) || permission.type === PermissionTypes.Any));
|
|
2051
|
+
if (permission.value === PermissionTypes.Any || permission.value.includes(apiRoot) && endpointMatches.length) {
|
|
2052
|
+
const collector = (endpointMatches.reduce((endpointAccu, endpoint) => [...endpointAccu, ...endpoint.uiPermissions], []) || definition.uiPermissions).reduce((permissionsAccu, uiPermission) => {
|
|
2053
|
+
if (permission.type === PermissionTypes.Any || !endpointMatches.length && uiPermission.verbs.some((verb) => verb === permission.type)) permissionsAccu.push(uiPermission.value);
|
|
2054
|
+
return permissionsAccu;
|
|
2055
|
+
}, []).filter(duplicateFilter);
|
|
2056
|
+
if (Array.isArray(accu[area])) accu[area] = [...accu[area], ...collector].filter(duplicateFilter);
|
|
2057
|
+
else accu[area] = mergePermissions(accu[area], { [scopedPermissionAreas[area].excessiveAccessSelector]: collector });
|
|
2058
|
+
}
|
|
2059
|
+
return accu;
|
|
2060
|
+
}, { ...emptyUiPermissions });
|
|
2061
|
+
const permissionActionTypes = {
|
|
2062
|
+
any: mapHttpPermission,
|
|
2063
|
+
CREATE_DEPLOYMENT: (permission) => permission.type === PermissionTypes.DeviceGroup ? {
|
|
2064
|
+
deployments: [uiPermissionsById.deploy.value],
|
|
2065
|
+
groups: { [permission.value]: [uiPermissionsById.deploy.value] }
|
|
2066
|
+
} : {},
|
|
2067
|
+
http: mapHttpPermission,
|
|
2068
|
+
REMOTE_TERMINAL: (permission) => permission.type === PermissionTypes.DeviceGroup ? { groups: { [permission.value]: [uiPermissionsById.connect.value] } } : {},
|
|
2069
|
+
VIEW_DEVICE: (permission) => permission.type === PermissionTypes.DeviceGroup ? { groups: { [permission.value]: [uiPermissionsById.read.value] } } : {}
|
|
2070
|
+
};
|
|
2071
|
+
const combinePermissions = (existingPermissions, additionalPermissions = {}) => Object.entries(additionalPermissions).reduce((accu, [name, permissions]) => {
|
|
2072
|
+
const maybeExistingPermissions = accu[name] || [];
|
|
2073
|
+
accu[name] = [...permissions, ...maybeExistingPermissions].filter(duplicateFilter);
|
|
2074
|
+
return accu;
|
|
2075
|
+
}, existingPermissions);
|
|
2076
|
+
const tryParseCustomPermission = (permission) => {
|
|
2077
|
+
const uiPermissions = permissionActionTypes[permission.action](permission.object);
|
|
2078
|
+
return {
|
|
2079
|
+
isCustom: true,
|
|
2080
|
+
permission,
|
|
2081
|
+
result: mergePermissions({ ...emptyUiPermissions }, uiPermissions)
|
|
2082
|
+
};
|
|
2083
|
+
};
|
|
2084
|
+
const customPermissionHandler = (accu, permission) => {
|
|
2085
|
+
const processor = tryParseCustomPermission(permission);
|
|
2086
|
+
return {
|
|
2087
|
+
...accu,
|
|
2088
|
+
isCustom: accu.isCustom || processor.isCustom,
|
|
2089
|
+
uiPermissions: mergePermissions(accu.uiPermissions, processor.result)
|
|
2090
|
+
};
|
|
2091
|
+
};
|
|
2092
|
+
const mapPermissionSet = (permissionSetName, names, scope, existingGroupsPermissions = {}) => {
|
|
2093
|
+
const permission = Object.values(uiPermissionsById).find((permission) => permission.permissionSets[scope] === permissionSetName)?.value;
|
|
2094
|
+
const scopedPermissions = names.reduce((accu, name) => combinePermissions(accu, { [name]: [permission] }), existingGroupsPermissions);
|
|
2095
|
+
return Object.entries(scopedPermissions).reduce((accu, [key, permissions]) => ({
|
|
2096
|
+
...accu,
|
|
2097
|
+
[key]: deriveImpliedAreaPermissions(scope, permissions)
|
|
2098
|
+
}), {});
|
|
2099
|
+
};
|
|
2100
|
+
const isEmptyPermissionSet = (permissionSet) => !Object.values(permissionSet).reduce((accu, permissions) => {
|
|
2101
|
+
if (Array.isArray(permissions)) return accu || !!permissions.length;
|
|
2102
|
+
return accu || !isEmpty(permissions);
|
|
2103
|
+
}, false);
|
|
2104
|
+
const parseRolePermissions = ({ permission_sets_with_scope = [], permissions = [] }, permissionSets) => {
|
|
2105
|
+
const preliminaryResult = permission_sets_with_scope.reduce((accu, permissionSet) => {
|
|
2106
|
+
if (!permissionSet.name) return accu;
|
|
2107
|
+
const processor = permissionSets[permissionSet.name];
|
|
2108
|
+
if (!processor) return accu;
|
|
2109
|
+
const scope = Object.keys(scopedPermissionAreas).find((scope) => uiPermissionsByArea[scope].scope === permissionSet.scope?.type);
|
|
2110
|
+
if (scope) {
|
|
2111
|
+
const result = mapPermissionSet(permissionSet.name, permissionSet.scope?.value ?? [], scope, accu.uiPermissions[scope]);
|
|
2112
|
+
return {
|
|
2113
|
+
...accu,
|
|
2114
|
+
uiPermissions: {
|
|
2115
|
+
...accu.uiPermissions,
|
|
2116
|
+
[scope]: result
|
|
2117
|
+
}
|
|
2118
|
+
};
|
|
2119
|
+
} else if (isEmptyPermissionSet(processor.result)) return processor.permissions?.reduce(customPermissionHandler, accu);
|
|
2120
|
+
return {
|
|
2121
|
+
...accu,
|
|
2122
|
+
isCustom: accu.isCustom || processor.isCustom,
|
|
2123
|
+
uiPermissions: mergePermissions(accu.uiPermissions, processor.result)
|
|
2124
|
+
};
|
|
2125
|
+
}, {
|
|
2126
|
+
isCustom: false,
|
|
2127
|
+
uiPermissions: {
|
|
2128
|
+
...emptyUiPermissions,
|
|
2129
|
+
groups: {},
|
|
2130
|
+
releases: {}
|
|
2131
|
+
}
|
|
2132
|
+
});
|
|
2133
|
+
return permissions.reduce(customPermissionHandler, preliminaryResult);
|
|
2134
|
+
};
|
|
2135
|
+
const normalizeRbacRoles = (roles, rolesById$1, permissionSets) => roles.reduce((accu, role) => {
|
|
2136
|
+
let normalizedPermissions;
|
|
2137
|
+
let isCustom = false;
|
|
2138
|
+
if (rolesById$1[role.name]) normalizedPermissions = {
|
|
2139
|
+
...rolesById$1[role.name].uiPermissions,
|
|
2140
|
+
groups: { ...rolesById$1[role.name].uiPermissions.groups },
|
|
2141
|
+
releases: { ...rolesById$1[role.name].uiPermissions.releases }
|
|
2142
|
+
};
|
|
2143
|
+
else {
|
|
2144
|
+
const result = parseRolePermissions(role, permissionSets);
|
|
2145
|
+
normalizedPermissions = result.uiPermissions;
|
|
2146
|
+
isCustom = result.isCustom;
|
|
2147
|
+
}
|
|
2148
|
+
const roleState = accu[role.name] ?? { ...emptyRole };
|
|
2149
|
+
accu[role.name] = {
|
|
2150
|
+
...roleState,
|
|
2151
|
+
...role,
|
|
2152
|
+
description: roleState.description ? roleState.description : role.description,
|
|
2153
|
+
editable: !rolesById[role.name] && !isCustom && (typeof roleState.editable !== "undefined" ? roleState.editable : true),
|
|
2154
|
+
isCustom,
|
|
2155
|
+
name: roleState.name ? roleState.name : role.name,
|
|
2156
|
+
uiPermissions: normalizedPermissions
|
|
2157
|
+
};
|
|
2158
|
+
return accu;
|
|
2159
|
+
}, { ...rolesById$1 });
|
|
2160
|
+
const getPermissionSets = createAppAsyncThunk(`${sliceName$5}/getPermissionSets`, (_, { dispatch, getState }) => Api.get(`${useradmApiUrlv2}/permission_sets?per_page=500`).then(({ data }) => {
|
|
2161
|
+
const permissionSets = data.reduce((accu, permissionSet) => {
|
|
2162
|
+
let permissionSetObject = {
|
|
2163
|
+
...accu[permissionSet.name] ?? {},
|
|
2164
|
+
...permissionSet
|
|
2165
|
+
};
|
|
2166
|
+
permissionSetObject.result = Object.values(uiPermissionsById).reduce((accu, item) => Object.entries(item.permissionSets).reduce((collector, [area, permissionSet]) => {
|
|
2167
|
+
if (scopedPermissionAreas[area]) return collector;
|
|
2168
|
+
if (permissionSet === permissionSetObject.name) collector[area] = [...collector[area], item.value].filter(duplicateFilter);
|
|
2169
|
+
return collector;
|
|
2170
|
+
}, accu), {
|
|
2171
|
+
...emptyUiPermissions,
|
|
2172
|
+
...permissionSetObject.result ?? {}
|
|
2173
|
+
});
|
|
2174
|
+
permissionSetObject = Object.values(scopedPermissionAreas).reduce((accu, { key, scopeType }) => {
|
|
2175
|
+
if (permissionSetObject.supported_scope_types?.includes(key) || permissionSetObject.supported_scope_types?.includes(scopeType)) accu.push(key);
|
|
2176
|
+
return accu;
|
|
2177
|
+
}, []).reduce((accu, scope) => {
|
|
2178
|
+
accu.result = {
|
|
2179
|
+
...accu.result,
|
|
2180
|
+
[scope]: mapPermissionSet(permissionSetObject.name, [scopedPermissionAreas[scope].excessiveAccessSelector], scope)
|
|
2181
|
+
};
|
|
2182
|
+
return accu;
|
|
2183
|
+
}, permissionSetObject);
|
|
2184
|
+
accu[permissionSet.name] = permissionSetObject;
|
|
2185
|
+
return accu;
|
|
2186
|
+
}, { ...getState().users.permissionSetsById });
|
|
2187
|
+
return Promise.all([Promise.resolve(dispatch(actions$5.receivedPermissionSets(permissionSets))), Promise.resolve(permissionSets)]);
|
|
2188
|
+
}).catch(() => console.log("Permission set retrieval failed - likely accessing a non-RBAC backend")));
|
|
2189
|
+
const getRoles = createAppAsyncThunk(`${sliceName$5}/getRoles`, async (_, { dispatch, getState }) => {
|
|
2190
|
+
try {
|
|
2191
|
+
const [{ data: roles }, permissionSetResult] = await Promise.all([Api.get(`${useradmApiUrlv2}/roles?per_page=500`), dispatch(getPermissionSets())]);
|
|
2192
|
+
const permissionSetTasks = permissionSetResult.payload;
|
|
2193
|
+
const rolesById = normalizeRbacRoles(roles, getRolesById(getState()), permissionSetTasks[permissionSetTasks.length - 1]);
|
|
2194
|
+
return dispatch(actions$5.receivedRoles(rolesById));
|
|
2195
|
+
} catch {
|
|
2196
|
+
console.log("Role retrieval failed - likely accessing a non-RBAC backend");
|
|
2197
|
+
} finally {
|
|
2198
|
+
dispatch(actions$5.finishedRoleInitialization(true));
|
|
2199
|
+
}
|
|
2200
|
+
});
|
|
2201
|
+
const deriveImpliedAreaPermissions = (area, areaPermissions, skipPermissions = []) => {
|
|
2202
|
+
const highestAreaPermissionLevelSelected = areaPermissions.reduce((highest, current) => uiPermissionsById[current].permissionLevel > highest ? uiPermissionsById[current].permissionLevel : highest, 1);
|
|
2203
|
+
return uiPermissionsByArea[area].uiPermissions.reduce((permissions, current) => {
|
|
2204
|
+
if ((current.permissionLevel < highestAreaPermissionLevelSelected || areaPermissions.includes(current.value)) && !skipPermissions.includes(current.value)) permissions.push(current.value);
|
|
2205
|
+
return permissions;
|
|
2206
|
+
}, []);
|
|
2207
|
+
};
|
|
2208
|
+
/**
|
|
2209
|
+
* transforms [{ group: "groupName", uiPermissions: ["read", "manage", "connect"] }, ...] to
|
|
2210
|
+
* [{ name: "ReadDevices", scope: { type: "DeviceGroups", value: ["groupName", ...] } }, ...]
|
|
2211
|
+
*/
|
|
2212
|
+
const transformAreaRoleDataToScopedPermissionsSets = (area, areaPermissions, excessiveAccessSelector) => {
|
|
2213
|
+
const permissionSetObject = areaPermissions.reduce((accu, { item, uiPermissions }) => {
|
|
2214
|
+
accu = deriveImpliedAreaPermissions(area, uiPermissions, scopedPermissionAreas.releases.key === area && item !== ALL_RELEASES ? [uiPermissionsById.upload.value] : []).reduce((itemPermissionAccu, impliedPermission) => {
|
|
2215
|
+
const permissionSetState = itemPermissionAccu[uiPermissionsById[impliedPermission].permissionSets[area]] ?? {
|
|
2216
|
+
type: uiPermissionsByArea[area].scope,
|
|
2217
|
+
value: []
|
|
2218
|
+
};
|
|
2219
|
+
itemPermissionAccu[uiPermissionsById[impliedPermission].permissionSets[area]] = {
|
|
2220
|
+
...permissionSetState,
|
|
2221
|
+
value: [...permissionSetState.value, item]
|
|
2222
|
+
};
|
|
2223
|
+
return itemPermissionAccu;
|
|
2224
|
+
}, accu);
|
|
2225
|
+
return accu;
|
|
2226
|
+
}, {});
|
|
2227
|
+
return Object.entries(permissionSetObject).map(([name, { value, ...scope }]) => {
|
|
2228
|
+
if (value.includes(excessiveAccessSelector)) return { name };
|
|
2229
|
+
return {
|
|
2230
|
+
name,
|
|
2231
|
+
scope: {
|
|
2232
|
+
...scope,
|
|
2233
|
+
value: value.filter(duplicateFilter)
|
|
2234
|
+
}
|
|
2235
|
+
};
|
|
2236
|
+
});
|
|
2237
|
+
};
|
|
2238
|
+
const transformRoleDataToRole = (roleData, roleState = {}) => {
|
|
2239
|
+
const role = {
|
|
2240
|
+
...roleState,
|
|
2241
|
+
...roleData
|
|
2242
|
+
};
|
|
2243
|
+
const { description = "", name, uiPermissions = emptyUiPermissions } = role;
|
|
2244
|
+
const { maybeUiPermissions, remainderKeys } = Object.entries(emptyUiPermissions).reduce((accu, [key, emptyPermissions]) => {
|
|
2245
|
+
if (!scopedPermissionAreas[key]) accu.remainderKeys.push(key);
|
|
2246
|
+
else if (uiPermissions[key]) accu.maybeUiPermissions[key] = uiPermissions[key].reduce(itemUiPermissionsReducer, emptyPermissions);
|
|
2247
|
+
return accu;
|
|
2248
|
+
}, {
|
|
2249
|
+
maybeUiPermissions: {},
|
|
2250
|
+
remainderKeys: []
|
|
2251
|
+
});
|
|
2252
|
+
const { permissionSetsWithScope, roleUiPermissions } = remainderKeys.reduce((accu, area) => {
|
|
2253
|
+
const areaPermissions = role.uiPermissions[area];
|
|
2254
|
+
if (!Array.isArray(areaPermissions)) return accu;
|
|
2255
|
+
const impliedPermissions = deriveImpliedAreaPermissions(area, areaPermissions);
|
|
2256
|
+
accu.roleUiPermissions[area] = impliedPermissions;
|
|
2257
|
+
const mappedPermissions = impliedPermissions.map((uiPermission) => ({ name: uiPermissionsById[uiPermission].permissionSets[area] }));
|
|
2258
|
+
accu.permissionSetsWithScope.push(...mappedPermissions);
|
|
2259
|
+
return accu;
|
|
2260
|
+
}, {
|
|
2261
|
+
permissionSetsWithScope: [{ name: defaultPermissionSets.Basic.name }],
|
|
2262
|
+
roleUiPermissions: {}
|
|
2263
|
+
});
|
|
2264
|
+
const scopedPermissionSets = Object.values(scopedPermissionAreas).reduce((accu, { key, excessiveAccessSelector }) => {
|
|
2265
|
+
if (!uiPermissions[key]) return accu;
|
|
2266
|
+
accu.push(...transformAreaRoleDataToScopedPermissionsSets(key, uiPermissions[key], excessiveAccessSelector));
|
|
2267
|
+
return accu;
|
|
2268
|
+
}, []);
|
|
2269
|
+
return {
|
|
2270
|
+
permissionSetsWithScope: [...permissionSetsWithScope, ...scopedPermissionSets],
|
|
2271
|
+
role: {
|
|
2272
|
+
...emptyRole,
|
|
2273
|
+
name,
|
|
2274
|
+
description: description ? description : roleState.description || "",
|
|
2275
|
+
uiPermissions: {
|
|
2276
|
+
...emptyUiPermissions,
|
|
2277
|
+
...roleUiPermissions,
|
|
2278
|
+
...maybeUiPermissions
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
};
|
|
2282
|
+
};
|
|
2283
|
+
const roleActions = {
|
|
2284
|
+
create: {
|
|
2285
|
+
successMessage: "The role was created successfully.",
|
|
2286
|
+
errorMessage: "creating"
|
|
2287
|
+
},
|
|
2288
|
+
edit: {
|
|
2289
|
+
successMessage: "The role has been updated.",
|
|
2290
|
+
errorMessage: "editing"
|
|
2291
|
+
},
|
|
2292
|
+
remove: {
|
|
2293
|
+
successMessage: "The role was deleted successfully.",
|
|
2294
|
+
errorMessage: "removing"
|
|
2295
|
+
}
|
|
2296
|
+
};
|
|
2297
|
+
const roleActionErrorHandler = (err, type, dispatch, meta) => {
|
|
2298
|
+
let errorContext = `There was an error ${roleActions[type].errorMessage} the role.`;
|
|
2299
|
+
if (meta) {
|
|
2300
|
+
const { permissionSetsCreated, name } = meta;
|
|
2301
|
+
errorContext += ` Tried to ${type} role ${name} with ${permissionSetsCreated} permission sets.`;
|
|
2302
|
+
}
|
|
2303
|
+
return commonErrorHandler(err, errorContext, dispatch);
|
|
2304
|
+
};
|
|
2305
|
+
const createRole = createAppAsyncThunk(`${sliceName$5}/createRole`, (roleData, { dispatch }) => {
|
|
2306
|
+
const { permissionSetsWithScope, role } = transformRoleDataToRole(roleData);
|
|
2307
|
+
return Api.post(`${useradmApiUrlv2}/roles`, {
|
|
2308
|
+
name: role.name,
|
|
2309
|
+
description: role.description,
|
|
2310
|
+
permission_sets_with_scope: permissionSetsWithScope
|
|
2311
|
+
}).then(() => Promise.all([
|
|
2312
|
+
dispatch(actions$5.createdRole(role)),
|
|
2313
|
+
dispatch(getRoles()),
|
|
2314
|
+
dispatch(setSnackbar(roleActions.create.successMessage))
|
|
2315
|
+
])).catch((err) => roleActionErrorHandler(err, "create", dispatch, {
|
|
2316
|
+
permissionSetsCreated: permissionSetsWithScope.length,
|
|
2317
|
+
name: role.name
|
|
2318
|
+
}));
|
|
2319
|
+
});
|
|
2320
|
+
const editRole = createAppAsyncThunk(`${sliceName$5}/editRole`, (roleData, { dispatch, getState }) => {
|
|
2321
|
+
const { permissionSetsWithScope, role } = transformRoleDataToRole(roleData, getRolesById(getState())[roleData.name]);
|
|
2322
|
+
return Api.put(`${useradmApiUrlv2}/roles/${role.name}`, {
|
|
2323
|
+
description: role.description,
|
|
2324
|
+
name: role.name,
|
|
2325
|
+
permission_sets_with_scope: permissionSetsWithScope
|
|
2326
|
+
}).then(() => Promise.all([
|
|
2327
|
+
dispatch(actions$5.createdRole(role)),
|
|
2328
|
+
dispatch(getRoles()),
|
|
2329
|
+
dispatch(setSnackbar(roleActions.edit.successMessage))
|
|
2330
|
+
])).catch((err) => roleActionErrorHandler(err, "edit", dispatch, {
|
|
2331
|
+
permissionSetsCreated: permissionSetsWithScope.length,
|
|
2332
|
+
name: role.name
|
|
2333
|
+
}));
|
|
2334
|
+
});
|
|
2335
|
+
const removeRole = createAppAsyncThunk(`${sliceName$5}/removeRole`, (roleId, { dispatch }) => Api.delete(`${useradmApiUrlv2}/roles/${roleId}`).then(() => Promise.all([
|
|
2336
|
+
dispatch(actions$5.removedRole(roleId)),
|
|
2337
|
+
dispatch(getRoles()),
|
|
2338
|
+
dispatch(setSnackbar(roleActions.remove.successMessage))
|
|
2339
|
+
])).catch((err) => roleActionErrorHandler(err, "remove", dispatch)));
|
|
2340
|
+
const getGlobalSettings = createAppAsyncThunk(`${sliceName$5}/getGlobalSettings`, async (_, { dispatch }) => {
|
|
2341
|
+
const { data: settings, headers: { etag } } = await Api.get(`${useradmApiUrl}/settings`);
|
|
2342
|
+
window.sessionStorage.setItem(settingsKeys.initialized, "true");
|
|
2343
|
+
await Promise.all([dispatch(actions$5.setGlobalSettings(settings)), dispatch(setOfflineThreshold())]);
|
|
2344
|
+
return { etag };
|
|
2345
|
+
});
|
|
2346
|
+
const saveGlobalSettings = createAppAsyncThunk(`${sliceName$5}/saveGlobalSettings`, ({ beOptimistic = false, notify = false, ...settings }, { dispatch, getState }) => {
|
|
2347
|
+
if (!window.sessionStorage.getItem(settingsKeys.initialized) && !beOptimistic) return;
|
|
2348
|
+
return dispatch(getGlobalSettings()).unwrap().then((result) => {
|
|
2349
|
+
const updatedSettings = {
|
|
2350
|
+
...getState().users.globalSettings,
|
|
2351
|
+
...settings
|
|
2352
|
+
};
|
|
2353
|
+
if (getCurrentUser(getState()).verified) updatedSettings["2fa"] = twoFAStates.enabled;
|
|
2354
|
+
else delete updatedSettings["2fa"];
|
|
2355
|
+
const tasks = [Promise.resolve(dispatch(actions$5.setGlobalSettings(updatedSettings)))];
|
|
2356
|
+
const headers = result.etag ? { "If-Match": result.etag } : {};
|
|
2357
|
+
return Api.post(`${useradmApiUrl}/settings`, updatedSettings, { headers }).then(() => {
|
|
2358
|
+
if (notify) tasks.push(Promise.resolve(dispatch(setSnackbar("Settings saved successfully"))));
|
|
2359
|
+
return Promise.all(tasks);
|
|
2360
|
+
}).catch((err) => {
|
|
2361
|
+
if (beOptimistic) return Promise.all(tasks);
|
|
2362
|
+
console.log(err);
|
|
2363
|
+
return commonErrorHandler(err, `The settings couldn't be saved.`, dispatch);
|
|
2364
|
+
});
|
|
2365
|
+
});
|
|
2366
|
+
});
|
|
2367
|
+
const getUserSettings = createAppAsyncThunk(`${sliceName$5}/getUserSettings`, async (_, { dispatch }) => {
|
|
2368
|
+
const { data: settings, headers: { etag } } = await Api.get(`${useradmApiUrl}/settings/me`);
|
|
2369
|
+
window.sessionStorage.setItem(settingsKeys.initialized, "true");
|
|
2370
|
+
dispatch(actions$5.setUserSettings(settings));
|
|
2371
|
+
return { etag };
|
|
2372
|
+
});
|
|
2373
|
+
const saveUserSettings = createAppAsyncThunk(`${sliceName$5}/saveUserSettings`, (settings = { onboarding: {} }, { dispatch, getState }) => {
|
|
2374
|
+
if (!getCurrentUser(getState()).id) return Promise.resolve();
|
|
2375
|
+
return dispatch(getUserSettings()).unwrap().then((result) => {
|
|
2376
|
+
const userSettings = getUserSettings$1(getState());
|
|
2377
|
+
const onboardingState = getOnboardingState$1(getState());
|
|
2378
|
+
const tooltipState = getTooltipsState(getState());
|
|
2379
|
+
const updatedSettings = {
|
|
2380
|
+
...userSettings,
|
|
2381
|
+
...settings,
|
|
2382
|
+
firstLoginTimestamp: userSettings.firstLoginTimestamp ?? dayjs().format(),
|
|
2383
|
+
onboarding: {
|
|
2384
|
+
...onboardingState,
|
|
2385
|
+
...settings.onboarding
|
|
2386
|
+
},
|
|
2387
|
+
tooltips: tooltipState
|
|
2388
|
+
};
|
|
2389
|
+
const headers = result.etag ? { "If-Match": result.etag } : {};
|
|
2390
|
+
return Promise.all([Promise.resolve(dispatch(actions$5.setUserSettings(updatedSettings))), Api.post(`${useradmApiUrl}/settings/me`, updatedSettings, { headers })]).catch(() => dispatch(actions$5.setUserSettings(userSettings)));
|
|
2391
|
+
});
|
|
2392
|
+
});
|
|
2393
|
+
const get2FAQRCode = createAppAsyncThunk(`${sliceName$5}/get2FAQRCode`, (_, { dispatch }) => Api.get(`${useradmApiUrl}/2faqr`).then((res) => dispatch(actions$5.receivedQrCode(res.data.qr))));
|
|
2394
|
+
const setHideAnnouncement = createAppAsyncThunk(`${sliceName$5}/setHideAnnouncement`, ({ shouldHide, userId }, { dispatch, getState }) => {
|
|
2395
|
+
const currentUserId = userId || getCurrentUser(getState()).id;
|
|
2396
|
+
const announcement = getHostedAnnouncement(getState());
|
|
2397
|
+
const hash = announcement ? hashString(announcement) : "";
|
|
2398
|
+
const announceCookie = cookies.get(`${currentUserId}${hash}`);
|
|
2399
|
+
if (shouldHide || hash.length && typeof announceCookie !== "undefined") {
|
|
2400
|
+
cookies.set(`${currentUserId}${hash}`, true, { maxAge: 604800 });
|
|
2401
|
+
dispatch(setAnnouncement(""));
|
|
2402
|
+
}
|
|
2403
|
+
});
|
|
2404
|
+
const getTokens = createAppAsyncThunk(`${sliceName$5}/getTokens`, (_, { dispatch, getState }) => Api.get(`${useradmApiUrl}/settings/tokens`).then(({ data: tokens }) => {
|
|
2405
|
+
const updatedUser = {
|
|
2406
|
+
...getCurrentUser(getState()),
|
|
2407
|
+
tokens
|
|
2408
|
+
};
|
|
2409
|
+
return Promise.resolve(dispatch(actions$5.updatedUser(updatedUser)));
|
|
2410
|
+
}));
|
|
2411
|
+
const ONE_YEAR = 31536e3;
|
|
2412
|
+
const generateToken = createAppAsyncThunk(`${sliceName$5}/generateToken`, async ({ expiresIn = ONE_YEAR, name }, { dispatch }) => {
|
|
2413
|
+
const { data: token } = await Api.post(`${useradmApiUrl}/settings/tokens`, {
|
|
2414
|
+
name,
|
|
2415
|
+
expires_in: expiresIn
|
|
2416
|
+
}).catch((err) => commonErrorHandler(err, "There was an error creating the token:", dispatch));
|
|
2417
|
+
await dispatch(getTokens());
|
|
2418
|
+
return token;
|
|
2419
|
+
});
|
|
2420
|
+
const revokeToken = createAppAsyncThunk(`${sliceName$5}/revokeToken`, (token, { dispatch }) => Api.delete(`${useradmApiUrl}/settings/tokens/${token.id}`).then(() => Promise.resolve(dispatch(getTokens()))));
|
|
2421
|
+
const setTooltipReadState = createAppAsyncThunk(`${sliceName$5}/setTooltipReadState`, async ({ persist, ...remainder }, { dispatch }) => {
|
|
2422
|
+
dispatch(actions$5.setTooltipState(remainder));
|
|
2423
|
+
if (persist) await dispatch(saveUserSettings());
|
|
2424
|
+
});
|
|
2425
|
+
const setAllTooltipsReadState = createAppAsyncThunk(`${sliceName$5}/toggleHelptips`, ({ readState = READ_STATES.read, tooltipIds }, { dispatch }) => {
|
|
2426
|
+
const updatedTips = tooltipIds.reduce((accu, id) => ({
|
|
2427
|
+
...accu,
|
|
2428
|
+
[id]: { readState }
|
|
2429
|
+
}), {});
|
|
2430
|
+
return Promise.resolve(dispatch(actions$5.setTooltipsState(updatedTips))).then(() => dispatch(saveUserSettings()));
|
|
2431
|
+
});
|
|
2432
|
+
const submitUserFeedback = createAppAsyncThunk(`${sliceName$5}/submitFeedback`, ({ formId, feedback }, { dispatch }) => Api.post(`${useradmApiUrlv2}/support/feedback/${formId}`, feedback).then(() => {
|
|
2433
|
+
if (formId === "product") {
|
|
2434
|
+
dispatch(saveUserSettings({ feedbackCollectedAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0] }));
|
|
2435
|
+
setTimeout(() => dispatch(actions$5.setShowFeedbackDialog(false)), TIMEOUTS.threeSeconds);
|
|
2436
|
+
}
|
|
2437
|
+
}));
|
|
2438
|
+
//#endregion
|
|
2439
|
+
export { abortDeployment, addDevicesToGroup, addDynamicGroup, addStaticGroup, addTenant, addUserToCurrentTenant, advanceOnboarding, applyDeviceConfig, cancelFileUpload, cancelRequest, cancelUpgrade, changeIntegration, changeNotificationSetting, changeSsoConfig, checkEmailExists, completeUpgrade, confirmCardUpdate, createArtifact, createBillingProfile, createDeployment, createIntegration, createOrganizationTrial, createRole, createUser, decommissionDevice, deleteAuthset, deleteIntegration, deleteSsoConfig, deriveDeploymentGroup, deviceFileUpload, disableUser2fa, downloadLicenseReport, editArtifact, editBillingProfile, editRole, editTenant, editUser, enableUser2fa, generateDeploymentLogAnalysis, generateToken, get2FAQRCode, getAllDeviceCounts, getAllDevicesByStatus, getAllDynamicGroupDevices, getAllGroupDevices, getArtifactInstallCount, getArtifactUrl, getAuditLogs, getAuditLogsCsvLink, getBillingPreview, getCurrentCard, getCurrentSubscription, getDeltaGenerationJobDetails, getDeltaGenerationJobs, getDeploymentDevices, getDeploymentsByStatus, getDeploymentsConfig, getDeviceAlerts, getDeviceAttributes, getDeviceAuth, getDeviceById, getDeviceConfig, getDeviceConnect, getDeviceDeployments, getDeviceFileDownloadLink, getDeviceInfo, getDeviceLimits, getDeviceLog, getDeviceMonitorConfig, getDeviceTwin, getDevicesByStatus, getDevicesWithAuth, getDynamicGroup, getDynamicGroups, getExistingReleaseTags, getGatewayDevices, getGlobalSettings, getGroupDevices, getGroups, getIntegrations, getIssueCountsByType, getLatestDeviceAlerts, getLatestReleaseInfo, getOnboardingState, getPermissionSets, getProducts, getRelease, getReleases, getReportDataWithoutBackendSupport, getRoles, getSessionDetails, getSingleDeployment, getSsoConfigById, getSsoConfigs, getSystemDevices, getTargetLocation, getTenants, getTokens, getUpdateTypes, getUser, getUserBilling, getUserList, getUserOrganization, getUserSettings, getUserSubscription, getWebhookEvents, initializeSelf, loginUser, logoutUser, normalizeRbacRoles, passwordResetComplete, passwordResetStart, preauthDevice, removeArtifact, removeDevicesFromGroup, removeDynamicGroup, removeRelease, removeReleases, removeReportsByGroupName, removeRole, removeStaticGroup, removeTenant, removeUser, requestPlanChange, requestPlanUpgrade, resetDeviceDeployments, revokeToken, saveDeltaDeploymentsConfig, saveGlobalSettings, saveUserSettings, searchDevices, selectGroup, selectRelease, sendSupportMessage, setAllTooltipsReadState, setAuditlogsState, setDeploymentsState, setDeviceConfig, setDeviceListState, setDeviceTags, setDeviceTwin, setFirstLoginAfterSignup, setHideAnnouncement, setOfflineThreshold, setOnboardingApproach, setOnboardingCanceled, setOnboardingComplete, setOnboardingDeviceType, setReleaseTags, setReleasesListState, setReleasesTags, setSearchState, setSingleReleaseTags, setTenantsListState, setTooltipReadState, startCardUpdate, startUpgrade, storeSsoConfig, submitUserFeedback, switchUserOrganization, tenantDataDivergedMessage, transformProductResponse, triggerDeviceUpdate, updateDeploymentControlMap, updateDeviceAuth, updateDevicesAuth, updateDynamicGroup, updateReleaseInfo, updateReportData, updateUserColumnSettings, uploadArtifact, verify2FA, verifyEmailComplete, verifyEmailStart };
|
|
2440
|
+
|
|
387
2441
|
//# sourceMappingURL=thunks.js.map
|