@northern.tech/store 0.36.3 → 0.37.0

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.
Files changed (87) hide show
  1. package/dist/actions.d.cts +2 -1
  2. package/dist/actions.d.ts +2 -1
  3. package/dist/appSlice/index.cjs +1 -0
  4. package/dist/appSlice/index.cjs.map +1 -1
  5. package/dist/appSlice/index.js +1 -0
  6. package/dist/appSlice/index.js.map +1 -1
  7. package/dist/appSlice/selectors.cjs +2 -4
  8. package/dist/appSlice/selectors.cjs.map +1 -1
  9. package/dist/appSlice/selectors.d.cts +4 -51
  10. package/dist/appSlice/selectors.d.ts +4 -51
  11. package/dist/appSlice/selectors.js +3 -4
  12. package/dist/appSlice/selectors.js.map +1 -1
  13. package/dist/appSlice/thunks.d.cts +1 -1
  14. package/dist/appSlice/thunks.d.ts +1 -1
  15. package/dist/commonSelectors.d.cts +10 -2
  16. package/dist/commonSelectors.d.ts +10 -2
  17. package/dist/deploymentsSlice/selectors.d.cts +2 -2
  18. package/dist/deploymentsSlice/selectors.d.ts +2 -2
  19. package/dist/deploymentsSlice/thunks.cjs +1 -0
  20. package/dist/deploymentsSlice/thunks.d.cts +9 -4
  21. package/dist/deploymentsSlice/thunks.d.ts +9 -4
  22. package/dist/deploymentsSlice/thunks.js +2 -2
  23. package/dist/devicesSlice/index.cjs +4 -0
  24. package/dist/devicesSlice/index.cjs.map +1 -1
  25. package/dist/devicesSlice/index.d.cts +1 -1
  26. package/dist/devicesSlice/index.d.ts +1 -1
  27. package/dist/devicesSlice/index.js +4 -0
  28. package/dist/devicesSlice/index.js.map +1 -1
  29. package/dist/devicesSlice/mocks.d.cts +1 -0
  30. package/dist/devicesSlice/mocks.d.ts +1 -0
  31. package/dist/devicesSlice/selectors.cjs +2 -0
  32. package/dist/devicesSlice/selectors.cjs.map +1 -1
  33. package/dist/devicesSlice/selectors.d.cts +4 -3
  34. package/dist/devicesSlice/selectors.d.ts +4 -3
  35. package/dist/devicesSlice/selectors.js +2 -1
  36. package/dist/devicesSlice/selectors.js.map +1 -1
  37. package/dist/devicesSlice/thunks.cjs +2 -0
  38. package/dist/devicesSlice/thunks.d.cts +68 -3
  39. package/dist/devicesSlice/thunks.d.ts +68 -3
  40. package/dist/devicesSlice/thunks.js +2 -2
  41. package/dist/{index-CPdMUfRr.d.ts → index-BqJuhvO_.d.ts} +4 -1
  42. package/dist/{index-DbfM03Gj.d.cts → index-Doc_1P_Y.d.cts} +4 -1
  43. package/dist/locationutils.d.cts +1 -1
  44. package/dist/locationutils.d.ts +1 -1
  45. package/dist/monitorSlice/selectors.d.cts +1 -1
  46. package/dist/monitorSlice/selectors.d.ts +1 -1
  47. package/dist/monitorSlice/thunks.d.cts +2 -2
  48. package/dist/monitorSlice/thunks.d.ts +2 -2
  49. package/dist/onboardingSlice/selectors.d.cts +1 -1
  50. package/dist/onboardingSlice/selectors.d.ts +1 -1
  51. package/dist/onboardingSlice/thunks.d.cts +1 -1
  52. package/dist/onboardingSlice/thunks.d.ts +1 -1
  53. package/dist/organizationSlice/selectors.d.cts +2 -2
  54. package/dist/organizationSlice/selectors.d.ts +2 -2
  55. package/dist/organizationSlice/thunks.d.cts +1 -1
  56. package/dist/organizationSlice/thunks.d.ts +1 -1
  57. package/dist/releasesSlice/selectors.d.cts +2 -2
  58. package/dist/releasesSlice/selectors.d.ts +2 -2
  59. package/dist/releasesSlice/thunks.d.cts +1 -1
  60. package/dist/releasesSlice/thunks.d.ts +1 -1
  61. package/dist/selectors.cjs +1 -1
  62. package/dist/selectors.d.cts +3 -3
  63. package/dist/selectors.d.ts +3 -3
  64. package/dist/selectors.js +3 -3
  65. package/dist/{store-gkY5P9Uz.d.ts → store-BzrMxxAO.d.ts} +2 -2
  66. package/dist/{store-DBUTT4FF.d.cts → store-xV2zaXAc.d.cts} +2 -2
  67. package/dist/store.d.cts +1 -1
  68. package/dist/store.d.ts +1 -1
  69. package/dist/storehooks.cjs +1 -0
  70. package/dist/storehooks.cjs.map +1 -1
  71. package/dist/storehooks.d.cts +1 -1
  72. package/dist/storehooks.d.ts +1 -1
  73. package/dist/storehooks.js +1 -0
  74. package/dist/storehooks.js.map +1 -1
  75. package/dist/thunks.cjs +37 -1
  76. package/dist/thunks.cjs.map +1 -1
  77. package/dist/thunks.d.cts +3 -3
  78. package/dist/thunks.d.ts +3 -3
  79. package/dist/thunks.js +35 -2
  80. package/dist/thunks.js.map +1 -1
  81. package/dist/usersSlice/selectors.d.cts +2 -2
  82. package/dist/usersSlice/selectors.d.ts +2 -2
  83. package/dist/usersSlice/thunks.d.cts +1 -1
  84. package/dist/usersSlice/thunks.d.ts +1 -1
  85. package/dist/utils.d.cts +1 -1
  86. package/dist/utils.d.ts +1 -1
  87. package/package.json +1 -1
package/dist/store.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as commonErrorHandler, c as sessionReducer, d as useAppSelector, i as commonErrorFallback, l as store, n as MenderEnvironment, o as createAppAsyncThunk, p as ErrorWithResponse, r as RootState, s as getConfiguredStore, t as AppDispatch, u as useAppDispatch } from "./store-DBUTT4FF.cjs";
1
+ import { a as commonErrorHandler, c as sessionReducer, d as useAppSelector, i as commonErrorFallback, l as store, n as MenderEnvironment, o as createAppAsyncThunk, p as ErrorWithResponse, r as RootState, s as getConfiguredStore, t as AppDispatch, u as useAppDispatch } from "./store-xV2zaXAc.cjs";
2
2
  export { AppDispatch, type ErrorWithResponse, MenderEnvironment, RootState, commonErrorFallback, commonErrorHandler, createAppAsyncThunk, getConfiguredStore, sessionReducer, store, useAppDispatch, useAppSelector };
package/dist/store.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as commonErrorHandler, c as sessionReducer, d as useAppSelector, i as commonErrorFallback, l as store, n as MenderEnvironment, o as createAppAsyncThunk, p as ErrorWithResponse, r as RootState, s as getConfiguredStore, t as AppDispatch, u as useAppDispatch } from "./store-gkY5P9Uz.js";
1
+ import { a as commonErrorHandler, c as sessionReducer, d as useAppSelector, i as commonErrorFallback, l as store, n as MenderEnvironment, o as createAppAsyncThunk, p as ErrorWithResponse, r as RootState, s as getConfiguredStore, t as AppDispatch, u as useAppDispatch } from "./store-BzrMxxAO.js";
2
2
  export { AppDispatch, type ErrorWithResponse, MenderEnvironment, RootState, commonErrorFallback, commonErrorHandler, createAppAsyncThunk, getConfiguredStore, sessionReducer, store, useAppDispatch, useAppSelector };
@@ -32,6 +32,7 @@ const featureFlags = [
32
32
  "hasDeltaProgress",
33
33
  "hasDeviceConfig",
34
34
  "hasDeviceConnect",
35
+ "hasDeviceFlags",
35
36
  "hasFeedbackEnabled",
36
37
  "hasManifestsEnabled",
37
38
  "hasMonitor",
@@ -1 +1 @@
1
- {"version":3,"file":"storehooks.cjs","names":["Cookies","durationDayJs","storeActions","createAppAsyncThunk","getOnboardingStateSelector","stringToBoolean","getSessionInfo","DEVICE_STATES","getDeviceById","useAppDispatch","useAppSelector","getIsEnterprise","getFeatures","getDevicesByStatusSelector","getUserSettingsSelector","getUserCapabilities","getOfflineThresholdSettings","getGlobalSettingsSelector","getSortedFilteringAttributes","getIsServiceProvider","getUserSettings","getGlobalSettings","getUserOrganization","getRoles","getDeviceAttributes","getDeploymentsByStatus","DEPLOYMENT_STATES","getDevicesByStatus","getDynamicGroups","getGroups","getIntegrations","getReleases","getAllDeviceCounts","getDeviceLimits","saveUserSettings","timeUnits","TIMEOUTS","saveGlobalSettings","getOnboardingState"],"sources":["../src/storehooks.ts"],"sourcesContent":["// Copyright 2024 Northern.tech AS\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { extractErrorMessage } from '@northern.tech/utils/helpers';\nimport dayjs from 'dayjs';\nimport durationDayJs from 'dayjs/plugin/duration.js';\nimport Cookies from 'universal-cookie';\n\nimport storeActions from './actions';\nimport { getSessionInfo } from './auth';\nimport { DEPLOYMENT_STATES, DEVICE_STATES, TIMEOUTS, timeUnits } from './constants';\nimport type { DeviceSliceType } from './devicesSlice';\nimport {\n getDevicesByStatus as getDevicesByStatusSelector,\n getFeatures,\n getGlobalSettings as getGlobalSettingsSelector,\n getIsEnterprise,\n getIsServiceProvider,\n getOfflineThresholdSettings,\n getOnboardingState as getOnboardingStateSelector,\n getSortedFilteringAttributes,\n getUserCapabilities,\n getUserSettings as getUserSettingsSelector\n} from './selectors';\nimport { createAppAsyncThunk, useAppDispatch, useAppSelector } from './store';\nimport type { AppDispatch } from './store';\nimport {\n getAllDeviceCounts,\n getDeploymentsByStatus,\n getDeviceAttributes,\n getDeviceById,\n getDeviceLimits,\n getDevicesByStatus,\n getDynamicGroups,\n getGlobalSettings,\n getGroups,\n getIntegrations,\n getOnboardingState,\n getReleases,\n getRoles,\n getUserOrganization,\n getUserSettings,\n saveGlobalSettings,\n saveUserSettings\n} from './thunks';\nimport type { UserSettings, UserSliceType } from './usersSlice';\nimport { stringToBoolean } from './utils';\n\nconst cookies = new Cookies();\ndayjs.extend(durationDayJs);\n\nconst { setDeviceListState, setFirstLoginAfterSignup, setTooltipsState, setShowStartupNotification } = storeActions;\n\nconst featureFlags = [\n 'hasAiEnabled',\n 'hasAuditlogs',\n 'hasMultitenancy',\n 'hasDeltaProgress',\n 'hasDeviceConfig',\n 'hasDeviceConnect',\n 'hasFeedbackEnabled',\n 'hasManifestsEnabled',\n 'hasMonitor',\n 'hasMCUEnabled',\n 'isEnterprise'\n] as const;\n\nconst environmentDatas = [\n 'commit',\n 'feedbackProbability',\n 'hostAddress',\n 'hostedAnnouncement',\n 'recaptchaSiteKey',\n 'sentry',\n 'stripeAPIKey',\n 'trackerCode'\n] as const;\n\ntype VersionInfo = {\n docsVersion?: string;\n version?: string;\n};\n\ntype FeatureFlagsState = Record<string, boolean>;\n\nexport const parseEnvironmentInfo = createAppAsyncThunk(`app/parseEnvironmentInfo`, (_, { dispatch, getState }) => {\n const state = getState();\n let onboardingComplete = getOnboardingStateSelector(state).complete || !!JSON.parse(window.localStorage.getItem('onboardingComplete') ?? 'false');\n let demoArtifactPort = 85;\n let environmentData: Record<string, unknown> = {};\n let environmentFeatures: FeatureFlagsState = {};\n let versionInfo: VersionInfo = {};\n const mender_environment = window.mender_environment;\n if (mender_environment) {\n const { features = {}, demoArtifactPort: port, disableOnboarding, version } = mender_environment;\n demoArtifactPort = Number(port) || demoArtifactPort;\n const appState = state.app;\n environmentData = environmentDatas.reduce((accu, flag) => ({ ...accu, [flag]: mender_environment[flag] || appState[flag as keyof typeof appState] }), {});\n environmentFeatures = {\n ...featureFlags.reduce<FeatureFlagsState>((accu, flag) => ({ ...accu, [flag]: stringToBoolean(features[flag]) }), {}),\n isHosted: stringToBoolean(features.isHosted) || window.location.hostname.includes('hosted.mender.io')\n };\n onboardingComplete = !environmentFeatures.isHosted || stringToBoolean(disableOnboarding) || onboardingComplete;\n versionInfo = {\n docsVersion: isNaN(parseInt(version.charAt(0))) ? '' : version.split('.').slice(0, 2).join('.'),\n version\n };\n }\n return Promise.all([\n dispatch(storeActions.successfullyLoggedIn(getSessionInfo())),\n dispatch(storeActions.setOnboardingComplete(onboardingComplete)),\n dispatch(storeActions.setDemoArtifactPort(demoArtifactPort)),\n dispatch(storeActions.setFeatures(environmentFeatures)),\n dispatch(storeActions.setVersionInformation(versionInfo)),\n dispatch(storeActions.setEnvironmentData(environmentData))\n ]);\n});\n\ntype OnboardingState = {\n complete?: boolean;\n showTips?: boolean | null;\n};\n\ntype MaybeAddOnboardingTasksParams = {\n devicesByStatus: DeviceSliceType['byStatus'];\n dispatch: AppDispatch;\n onboardingState: OnboardingState;\n tasks: Promise<unknown>[];\n};\n\nconst maybeAddOnboardingTasks = ({ devicesByStatus, dispatch, onboardingState, tasks }: MaybeAddOnboardingTasksParams): Promise<unknown>[] => {\n if (!onboardingState.showTips || onboardingState.complete) {\n return tasks;\n }\n // try to retrieve full device details for onboarding devices to ensure ips etc. are available\n // we only load the first few/ 20 devices, as it is possible the onboarding is left dangling\n // and a lot of devices are present and we don't want to flood the backend for this\n return devicesByStatus[DEVICE_STATES.accepted].deviceIds.reduce<Promise<unknown>[]>((accu, id) => {\n accu.push(dispatch(getDeviceById(id)));\n return accu;\n }, tasks);\n};\n\nexport const useAppInit = (userId: string | undefined): { coreInitDone: boolean } => {\n const dispatch = useAppDispatch();\n const [coreInitDone, setCoreInitDone] = useState(false);\n const isEnterprise = useAppSelector(getIsEnterprise);\n const { hasMultitenancy, isHosted } = useAppSelector(getFeatures);\n const devicesByStatus = useAppSelector(getDevicesByStatusSelector);\n const onboardingState = useAppSelector(getOnboardingStateSelector);\n const { columnSelection = [], trackingConsentGiven: hasTrackingEnabled, tooltips = {} } = useAppSelector(getUserSettingsSelector);\n const { canManageUsers } = useAppSelector(getUserCapabilities);\n const { interval, intervalUnit } = useAppSelector(getOfflineThresholdSettings);\n const { id_attribute } = useAppSelector(getGlobalSettingsSelector);\n const { identityAttributes } = useAppSelector(getSortedFilteringAttributes);\n const isServiceProvider = useAppSelector(getIsServiceProvider);\n const coreInitRunning = useRef(false);\n const fullInitRunning = useRef(false);\n\n const retrieveCoreData = useCallback((): Promise<unknown[]> => {\n const tasks: Promise<unknown>[] = [\n dispatch(parseEnvironmentInfo()).unwrap(),\n dispatch(getUserSettings()).unwrap(),\n dispatch(getGlobalSettings()).unwrap(),\n Promise.resolve(dispatch(setFirstLoginAfterSignup(stringToBoolean(cookies.get('firstLoginAfterSignup')))))\n ];\n const multitenancy = hasMultitenancy || isHosted || isEnterprise;\n if (multitenancy) {\n tasks.push(dispatch(getUserOrganization()).unwrap());\n }\n return Promise.all(tasks);\n }, [dispatch, hasMultitenancy, isHosted, isEnterprise]);\n\n const retrieveAppData = useCallback((): Promise<unknown[] | unknown> => {\n if (isServiceProvider) {\n return Promise.resolve(dispatch(getRoles()));\n }\n const tasks: Promise<unknown>[] = [\n dispatch(getDeviceAttributes()),\n dispatch(getDeploymentsByStatus({ status: DEPLOYMENT_STATES.finished, shouldSelect: false })),\n dispatch(getDeploymentsByStatus({ status: DEPLOYMENT_STATES.inprogress })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.accepted })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.pending })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.preauth })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.rejected })),\n dispatch(getDynamicGroups()),\n dispatch(getGroups()),\n dispatch(getIntegrations()),\n dispatch(getReleases()),\n dispatch(getAllDeviceCounts()).unwrap()\n ];\n if (hasMultitenancy) {\n tasks.push(dispatch(getDeviceLimits()));\n tasks.push(dispatch(getRoles()));\n }\n return Promise.all(tasks);\n }, [dispatch, hasMultitenancy, isServiceProvider]);\n\n const interpretAppData = useCallback((): Promise<unknown[]> => {\n const settings: Partial<UserSettings> = {};\n if (cookies.get('_ga') && typeof hasTrackingEnabled === 'undefined') {\n settings.trackingConsentGiven = true;\n }\n let tasks: Promise<unknown>[] = [\n Promise.resolve(dispatch(setDeviceListState({ selectedAttributes: columnSelection.map(column => ({ attribute: column.key, scope: column.scope })) }))),\n Promise.resolve(dispatch(setTooltipsState(tooltips as UserSliceType['tooltips']['byId']))), // tooltips read state is primarily trusted from the redux store, except on app init - here user settings are the reference\n dispatch(saveUserSettings(settings)).unwrap()\n ];\n // checks if user id is set and if cookie for helptips exists for that user\n tasks = maybeAddOnboardingTasks({ devicesByStatus, dispatch, tasks, onboardingState });\n\n if (canManageUsers && intervalUnit && intervalUnit !== timeUnits.days) {\n const duration = dayjs.duration(interval, intervalUnit as keyof typeof timeUnits);\n const days = duration.asDays();\n if (days < 1) {\n tasks.push(Promise.resolve(setTimeout(() => dispatch(setShowStartupNotification(true)), TIMEOUTS.fiveSeconds)));\n } else {\n const roundedDays = Math.max(1, Math.round(days));\n tasks.push(dispatch(saveGlobalSettings({ offlineThreshold: { interval: roundedDays, intervalUnit: timeUnits.days } })));\n }\n }\n\n // the following is used as a migration and initialization of the stored identity attribute\n // changing the default device attribute to the first non-deviceId attribute, unless a stored\n // id attribute setting exists\n const identityOptions = identityAttributes.filter(attribute => !['id', 'Device ID', 'status'].includes(attribute));\n if (!id_attribute && identityOptions.length) {\n tasks.push(dispatch(saveGlobalSettings({ id_attribute: { attribute: identityOptions[0], scope: 'identity' } })));\n } else if (typeof id_attribute === 'string') {\n // Legacy migration path: id_attribute used to be a plain string\n let attribute: string = id_attribute;\n if (attribute === 'Device ID') {\n attribute = 'id';\n }\n tasks.push(dispatch(saveGlobalSettings({ id_attribute: { attribute, scope: 'identity' } })));\n }\n tasks.push(Promise.resolve(dispatch(storeActions.setAppInitDone())));\n return Promise.all(tasks);\n }, [\n columnSelection,\n dispatch,\n identityAttributes,\n hasTrackingEnabled,\n canManageUsers,\n devicesByStatus,\n id_attribute,\n interval,\n intervalUnit,\n onboardingState,\n tooltips\n ]);\n\n const initializeAppData = useCallback(\n (): Promise<unknown> =>\n retrieveAppData()\n .then(interpretAppData)\n // this is allowed to fail if no user information are available\n .catch(err => console.log(extractErrorMessage(err)))\n .then(() => dispatch(getOnboardingState())),\n [dispatch, retrieveAppData, interpretAppData]\n );\n\n useEffect(() => {\n if (!userId || coreInitRunning.current) {\n return;\n }\n coreInitRunning.current = true;\n retrieveCoreData().then(() => setCoreInitDone(true));\n }, [userId, retrieveCoreData]);\n\n useEffect(() => {\n if (fullInitRunning.current || !coreInitDone) {\n return;\n }\n fullInitRunning.current = true;\n initializeAppData();\n }, [initializeAppData, coreInitDone]);\n\n return { coreInitDone };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA4DA,MAAM,UAAU,IAAIA,iBAAAA,QAAQ;AAC5B,MAAA,QAAM,OAAOC,yBAAAA,OAAa;AAE1B,MAAM,EAAE,oBAAoB,0BAA0B,kBAAkB,+BAA+BC;AAEvG,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,mBAAmB;CACvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AASA,MAAa,uBAAuBC,cAAAA,oBAAoB,6BAA6B,GAAG,EAAE,UAAU,eAAe;CACjH,MAAM,QAAQ,SAAS;CACvB,IAAI,qBAAqBC,wBAAAA,mBAA2B,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,MAAM,OAAO,aAAa,QAAQ,oBAAoB,KAAK,OAAO;CAChJ,IAAI,mBAAmB;CACvB,IAAI,kBAA2C,CAAC;CAChD,IAAI,sBAAyC,CAAC;CAC9C,IAAI,cAA2B,CAAC;CAChC,MAAM,qBAAqB,OAAO;CAClC,IAAI,oBAAoB;EACtB,MAAM,EAAE,WAAW,CAAC,GAAG,kBAAkB,MAAM,mBAAmB,YAAY;EAC9E,mBAAmB,OAAO,IAAI,KAAK;EACnC,MAAM,WAAW,MAAM;EACvB,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU;GAAE,GAAG;IAAO,OAAO,mBAAmB,SAAS,SAAS;EAA+B,IAAI,CAAC,CAAC;EACxJ,sBAAsB;GACpB,GAAG,aAAa,QAA2B,MAAM,UAAU;IAAE,GAAG;KAAO,OAAOC,cAAAA,gBAAgB,SAAS,KAAK;GAAE,IAAI,CAAC,CAAC;GACpH,UAAUA,cAAAA,gBAAgB,SAAS,QAAQ,KAAK,OAAO,SAAS,SAAS,SAAS,kBAAkB;EACtG;EACA,qBAAqB,CAAC,oBAAoB,YAAYA,cAAAA,gBAAgB,iBAAiB,KAAK;EAC5F,cAAc;GACZ,aAAa,MAAM,SAAS,QAAQ,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG;GAC9F;EACF;CACF;CACA,OAAO,QAAQ,IAAI;EACjB,SAASH,gBAAa,qBAAqBI,aAAAA,eAAe,CAAC,CAAC;EAC5D,SAASJ,gBAAa,sBAAsB,kBAAkB,CAAC;EAC/D,SAASA,gBAAa,oBAAoB,gBAAgB,CAAC;EAC3D,SAASA,gBAAa,YAAY,mBAAmB,CAAC;EACtD,SAASA,gBAAa,sBAAsB,WAAW,CAAC;EACxD,SAASA,gBAAa,mBAAmB,eAAe,CAAC;CAC3D,CAAC;AACH,CAAC;AAcD,MAAM,2BAA2B,EAAE,iBAAiB,UAAU,iBAAiB,YAA+D;CAC5I,IAAI,CAAC,gBAAgB,YAAY,gBAAgB,UAC/C,OAAO;CAKT,OAAO,gBAAgBK,+BAAAA,cAAc,SAAS,CAAC,UAAU,QAA4B,MAAM,OAAO;EAChG,KAAK,KAAK,SAASC,eAAAA,cAAc,EAAE,CAAC,CAAC;EACrC,OAAO;CACT,GAAG,KAAK;AACV;AAEA,MAAa,cAAc,WAA0D;CACnF,MAAM,WAAWC,cAAAA,eAAe;CAChC,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,KAAK;CACtD,MAAM,eAAeC,cAAAA,eAAeC,wBAAAA,eAAe;CACnD,MAAM,EAAE,iBAAiB,aAAaD,cAAAA,eAAeE,2BAAAA,WAAW;CAChE,MAAM,kBAAkBF,cAAAA,eAAeG,+BAAAA,kBAA0B;CACjE,MAAM,kBAAkBH,cAAAA,eAAeN,wBAAAA,kBAA0B;CACjE,MAAM,EAAE,kBAAkB,CAAC,GAAG,sBAAsB,oBAAoB,WAAW,CAAC,MAAMM,cAAAA,eAAeI,6BAAAA,eAAuB;CAChI,MAAM,EAAE,mBAAmBJ,cAAAA,eAAeK,wBAAAA,mBAAmB;CAC7D,MAAM,EAAE,UAAU,iBAAiBL,cAAAA,eAAeM,6BAAAA,2BAA2B;CAC7E,MAAM,EAAE,iBAAiBN,cAAAA,eAAeO,6BAAAA,iBAAyB;CACjE,MAAM,EAAE,uBAAuBP,cAAAA,eAAeQ,+BAAAA,4BAA4B;CAC1E,MAAM,oBAAoBR,cAAAA,eAAeS,oCAAAA,oBAAoB;CAC7D,MAAM,mBAAA,GAAA,MAAA,OAAA,CAAyB,KAAK;CACpC,MAAM,mBAAA,GAAA,MAAA,OAAA,CAAyB,KAAK;CAEpC,MAAM,oBAAA,GAAA,MAAA,YAAA,OAAyD;EAC7D,MAAM,QAA4B;GAChC,SAAS,qBAAqB,CAAC,CAAC,CAAC,OAAO;GACxC,SAASC,eAAAA,gBAAgB,CAAC,CAAC,CAAC,OAAO;GACnC,SAASC,eAAAA,kBAAkB,CAAC,CAAC,CAAC,OAAO;GACrC,QAAQ,QAAQ,SAAS,yBAAyBhB,cAAAA,gBAAgB,QAAQ,IAAI,uBAAuB,CAAC,CAAC,CAAC,CAAC;EAC3G;EAEA,IADqB,mBAAmB,YAAY,cAElD,MAAM,KAAK,SAASiB,eAAAA,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC;EAErD,OAAO,QAAQ,IAAI,KAAK;CAC1B,GAAG;EAAC;EAAU;EAAiB;EAAU;CAAY,CAAC;CAEtD,MAAM,mBAAA,GAAA,MAAA,YAAA,OAAkE;EACtE,IAAI,mBACF,OAAO,QAAQ,QAAQ,SAASC,eAAAA,SAAS,CAAC,CAAC;EAE7C,MAAM,QAA4B;GAChC,SAASC,eAAAA,oBAAoB,CAAC;GAC9B,SAASC,eAAAA,uBAAuB;IAAE,QAAQC,kBAAAA,kBAAkB;IAAU,cAAc;GAAM,CAAC,CAAC;GAC5F,SAASD,eAAAA,uBAAuB,EAAE,QAAQC,kBAAAA,kBAAkB,WAAW,CAAC,CAAC;GACzE,SAASC,eAAAA,mBAAmB,EAAE,QAAQpB,+BAAAA,cAAc,SAAS,CAAC,CAAC;GAC/D,SAASoB,eAAAA,mBAAmB,EAAE,QAAQpB,+BAAAA,cAAc,QAAQ,CAAC,CAAC;GAC9D,SAASoB,eAAAA,mBAAmB,EAAE,QAAQpB,+BAAAA,cAAc,QAAQ,CAAC,CAAC;GAC9D,SAASoB,eAAAA,mBAAmB,EAAE,QAAQpB,+BAAAA,cAAc,SAAS,CAAC,CAAC;GAC/D,SAASqB,eAAAA,iBAAiB,CAAC;GAC3B,SAASC,eAAAA,UAAU,CAAC;GACpB,SAASC,eAAAA,gBAAgB,CAAC;GAC1B,SAASC,6BAAAA,YAAY,CAAC;GACtB,SAASC,eAAAA,mBAAmB,CAAC,CAAC,CAAC,OAAO;EACxC;EACA,IAAI,iBAAiB;GACnB,MAAM,KAAK,SAASC,eAAAA,gBAAgB,CAAC,CAAC;GACtC,MAAM,KAAK,SAASV,eAAAA,SAAS,CAAC,CAAC;EACjC;EACA,OAAO,QAAQ,IAAI,KAAK;CAC1B,GAAG;EAAC;EAAU;EAAiB;CAAiB,CAAC;CAEjD,MAAM,oBAAA,GAAA,MAAA,YAAA,OAAyD;EAC7D,MAAM,WAAkC,CAAC;EACzC,IAAI,QAAQ,IAAI,KAAK,KAAK,OAAO,uBAAuB,aACtD,SAAS,uBAAuB;EAElC,IAAI,QAA4B;GAC9B,QAAQ,QAAQ,SAAS,mBAAmB,EAAE,oBAAoB,gBAAgB,KAAI,YAAW;IAAE,WAAW,OAAO;IAAK,OAAO,OAAO;GAAM,EAAE,EAAE,CAAC,CAAC,CAAC;GACrJ,QAAQ,QAAQ,SAAS,iBAAiB,QAA6C,CAAC,CAAC;GACzF,SAASW,eAAAA,iBAAiB,QAAQ,CAAC,CAAC,CAAC,OAAO;EAC9C;EAEA,QAAQ,wBAAwB;GAAE;GAAiB;GAAU;GAAO;EAAgB,CAAC;EAErF,IAAI,kBAAkB,gBAAgB,iBAAiBC,kBAAAA,UAAU,MAAM;GAErE,MAAM,OADW,MAAA,QAAM,SAAS,UAAU,YACtB,CAAC,CAAC,OAAO;GAC7B,IAAI,OAAO,GACT,MAAM,KAAK,QAAQ,QAAQ,iBAAiB,SAAS,2BAA2B,IAAI,CAAC,GAAGC,kBAAAA,SAAS,WAAW,CAAC,CAAC;QACzG;IACL,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC;IAChD,MAAM,KAAK,SAASC,eAAAA,mBAAmB,EAAE,kBAAkB;KAAE,UAAU;KAAa,cAAcF,kBAAAA,UAAU;IAAK,EAAE,CAAC,CAAC,CAAC;GACxH;EACF;EAKA,MAAM,kBAAkB,mBAAmB,QAAO,cAAa,CAAC;GAAC;GAAM;GAAa;EAAQ,CAAC,CAAC,SAAS,SAAS,CAAC;EACjH,IAAI,CAAC,gBAAgB,gBAAgB,QACnC,MAAM,KAAK,SAASE,eAAAA,mBAAmB,EAAE,cAAc;GAAE,WAAW,gBAAgB;GAAI,OAAO;EAAW,EAAE,CAAC,CAAC,CAAC;OAC1G,IAAI,OAAO,iBAAiB,UAAU;GAE3C,IAAI,YAAoB;GACxB,IAAI,cAAc,aAChB,YAAY;GAEd,MAAM,KAAK,SAASA,eAAAA,mBAAmB,EAAE,cAAc;IAAE;IAAW,OAAO;GAAW,EAAE,CAAC,CAAC,CAAC;EAC7F;EACA,MAAM,KAAK,QAAQ,QAAQ,SAASnC,gBAAa,eAAe,CAAC,CAAC,CAAC;EACnE,OAAO,QAAQ,IAAI,KAAK;CAC1B,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,qBAAA,GAAA,MAAA,YAAA,OAEF,gBAAgB,CAAC,CACd,KAAK,gBAAgB,CAAC,CAEtB,OAAM,QAAO,QAAQ,KAAA,GAAA,6BAAA,oBAAA,CAAwB,GAAG,CAAC,CAAC,CAAC,CACnD,WAAW,SAASoC,eAAAA,mBAAmB,CAAC,CAAC,GAC9C;EAAC;EAAU;EAAiB;CAAgB,CAC9C;CAEA,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,UAAU,gBAAgB,SAC7B;EAEF,gBAAgB,UAAU;EAC1B,iBAAiB,CAAC,CAAC,WAAW,gBAAgB,IAAI,CAAC;CACrD,GAAG,CAAC,QAAQ,gBAAgB,CAAC;CAE7B,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,gBAAgB,WAAW,CAAC,cAC9B;EAEF,gBAAgB,UAAU;EAC1B,kBAAkB;CACpB,GAAG,CAAC,mBAAmB,YAAY,CAAC;CAEpC,OAAO,EAAE,aAAa;AACxB"}
1
+ {"version":3,"file":"storehooks.cjs","names":["Cookies","durationDayJs","storeActions","createAppAsyncThunk","getOnboardingStateSelector","stringToBoolean","getSessionInfo","DEVICE_STATES","getDeviceById","useAppDispatch","useAppSelector","getIsEnterprise","getFeatures","getDevicesByStatusSelector","getUserSettingsSelector","getUserCapabilities","getOfflineThresholdSettings","getGlobalSettingsSelector","getSortedFilteringAttributes","getIsServiceProvider","getUserSettings","getGlobalSettings","getUserOrganization","getRoles","getDeviceAttributes","getDeploymentsByStatus","DEPLOYMENT_STATES","getDevicesByStatus","getDynamicGroups","getGroups","getIntegrations","getReleases","getAllDeviceCounts","getDeviceLimits","saveUserSettings","timeUnits","TIMEOUTS","saveGlobalSettings","getOnboardingState"],"sources":["../src/storehooks.ts"],"sourcesContent":["// Copyright 2024 Northern.tech AS\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { extractErrorMessage } from '@northern.tech/utils/helpers';\nimport dayjs from 'dayjs';\nimport durationDayJs from 'dayjs/plugin/duration.js';\nimport Cookies from 'universal-cookie';\n\nimport storeActions from './actions';\nimport { getSessionInfo } from './auth';\nimport { DEPLOYMENT_STATES, DEVICE_STATES, TIMEOUTS, timeUnits } from './constants';\nimport type { DeviceSliceType } from './devicesSlice';\nimport {\n getDevicesByStatus as getDevicesByStatusSelector,\n getFeatures,\n getGlobalSettings as getGlobalSettingsSelector,\n getIsEnterprise,\n getIsServiceProvider,\n getOfflineThresholdSettings,\n getOnboardingState as getOnboardingStateSelector,\n getSortedFilteringAttributes,\n getUserCapabilities,\n getUserSettings as getUserSettingsSelector\n} from './selectors';\nimport { createAppAsyncThunk, useAppDispatch, useAppSelector } from './store';\nimport type { AppDispatch } from './store';\nimport {\n getAllDeviceCounts,\n getDeploymentsByStatus,\n getDeviceAttributes,\n getDeviceById,\n getDeviceLimits,\n getDevicesByStatus,\n getDynamicGroups,\n getGlobalSettings,\n getGroups,\n getIntegrations,\n getOnboardingState,\n getReleases,\n getRoles,\n getUserOrganization,\n getUserSettings,\n saveGlobalSettings,\n saveUserSettings\n} from './thunks';\nimport type { UserSettings, UserSliceType } from './usersSlice';\nimport { stringToBoolean } from './utils';\n\nconst cookies = new Cookies();\ndayjs.extend(durationDayJs);\n\nconst { setDeviceListState, setFirstLoginAfterSignup, setTooltipsState, setShowStartupNotification } = storeActions;\n\nconst featureFlags = [\n 'hasAiEnabled',\n 'hasAuditlogs',\n 'hasMultitenancy',\n 'hasDeltaProgress',\n 'hasDeviceConfig',\n 'hasDeviceConnect',\n 'hasDeviceFlags',\n 'hasFeedbackEnabled',\n 'hasManifestsEnabled',\n 'hasMonitor',\n 'hasMCUEnabled',\n 'isEnterprise'\n] as const;\n\nconst environmentDatas = [\n 'commit',\n 'feedbackProbability',\n 'hostAddress',\n 'hostedAnnouncement',\n 'recaptchaSiteKey',\n 'sentry',\n 'stripeAPIKey',\n 'trackerCode'\n] as const;\n\ntype VersionInfo = {\n docsVersion?: string;\n version?: string;\n};\n\ntype FeatureFlagsState = Record<string, boolean>;\n\nexport const parseEnvironmentInfo = createAppAsyncThunk(`app/parseEnvironmentInfo`, (_, { dispatch, getState }) => {\n const state = getState();\n let onboardingComplete = getOnboardingStateSelector(state).complete || !!JSON.parse(window.localStorage.getItem('onboardingComplete') ?? 'false');\n let demoArtifactPort = 85;\n let environmentData: Record<string, unknown> = {};\n let environmentFeatures: FeatureFlagsState = {};\n let versionInfo: VersionInfo = {};\n const mender_environment = window.mender_environment;\n if (mender_environment) {\n const { features = {}, demoArtifactPort: port, disableOnboarding, version } = mender_environment;\n demoArtifactPort = Number(port) || demoArtifactPort;\n const appState = state.app;\n environmentData = environmentDatas.reduce((accu, flag) => ({ ...accu, [flag]: mender_environment[flag] || appState[flag as keyof typeof appState] }), {});\n environmentFeatures = {\n ...featureFlags.reduce<FeatureFlagsState>((accu, flag) => ({ ...accu, [flag]: stringToBoolean(features[flag]) }), {}),\n isHosted: stringToBoolean(features.isHosted) || window.location.hostname.includes('hosted.mender.io')\n };\n onboardingComplete = !environmentFeatures.isHosted || stringToBoolean(disableOnboarding) || onboardingComplete;\n versionInfo = {\n docsVersion: isNaN(parseInt(version.charAt(0))) ? '' : version.split('.').slice(0, 2).join('.'),\n version\n };\n }\n return Promise.all([\n dispatch(storeActions.successfullyLoggedIn(getSessionInfo())),\n dispatch(storeActions.setOnboardingComplete(onboardingComplete)),\n dispatch(storeActions.setDemoArtifactPort(demoArtifactPort)),\n dispatch(storeActions.setFeatures(environmentFeatures)),\n dispatch(storeActions.setVersionInformation(versionInfo)),\n dispatch(storeActions.setEnvironmentData(environmentData))\n ]);\n});\n\ntype OnboardingState = {\n complete?: boolean;\n showTips?: boolean | null;\n};\n\ntype MaybeAddOnboardingTasksParams = {\n devicesByStatus: DeviceSliceType['byStatus'];\n dispatch: AppDispatch;\n onboardingState: OnboardingState;\n tasks: Promise<unknown>[];\n};\n\nconst maybeAddOnboardingTasks = ({ devicesByStatus, dispatch, onboardingState, tasks }: MaybeAddOnboardingTasksParams): Promise<unknown>[] => {\n if (!onboardingState.showTips || onboardingState.complete) {\n return tasks;\n }\n // try to retrieve full device details for onboarding devices to ensure ips etc. are available\n // we only load the first few/ 20 devices, as it is possible the onboarding is left dangling\n // and a lot of devices are present and we don't want to flood the backend for this\n return devicesByStatus[DEVICE_STATES.accepted].deviceIds.reduce<Promise<unknown>[]>((accu, id) => {\n accu.push(dispatch(getDeviceById(id)));\n return accu;\n }, tasks);\n};\n\nexport const useAppInit = (userId: string | undefined): { coreInitDone: boolean } => {\n const dispatch = useAppDispatch();\n const [coreInitDone, setCoreInitDone] = useState(false);\n const isEnterprise = useAppSelector(getIsEnterprise);\n const { hasMultitenancy, isHosted } = useAppSelector(getFeatures);\n const devicesByStatus = useAppSelector(getDevicesByStatusSelector);\n const onboardingState = useAppSelector(getOnboardingStateSelector);\n const { columnSelection = [], trackingConsentGiven: hasTrackingEnabled, tooltips = {} } = useAppSelector(getUserSettingsSelector);\n const { canManageUsers } = useAppSelector(getUserCapabilities);\n const { interval, intervalUnit } = useAppSelector(getOfflineThresholdSettings);\n const { id_attribute } = useAppSelector(getGlobalSettingsSelector);\n const { identityAttributes } = useAppSelector(getSortedFilteringAttributes);\n const isServiceProvider = useAppSelector(getIsServiceProvider);\n const coreInitRunning = useRef(false);\n const fullInitRunning = useRef(false);\n\n const retrieveCoreData = useCallback((): Promise<unknown[]> => {\n const tasks: Promise<unknown>[] = [\n dispatch(parseEnvironmentInfo()).unwrap(),\n dispatch(getUserSettings()).unwrap(),\n dispatch(getGlobalSettings()).unwrap(),\n Promise.resolve(dispatch(setFirstLoginAfterSignup(stringToBoolean(cookies.get('firstLoginAfterSignup')))))\n ];\n const multitenancy = hasMultitenancy || isHosted || isEnterprise;\n if (multitenancy) {\n tasks.push(dispatch(getUserOrganization()).unwrap());\n }\n return Promise.all(tasks);\n }, [dispatch, hasMultitenancy, isHosted, isEnterprise]);\n\n const retrieveAppData = useCallback((): Promise<unknown[] | unknown> => {\n if (isServiceProvider) {\n return Promise.resolve(dispatch(getRoles()));\n }\n const tasks: Promise<unknown>[] = [\n dispatch(getDeviceAttributes()),\n dispatch(getDeploymentsByStatus({ status: DEPLOYMENT_STATES.finished, shouldSelect: false })),\n dispatch(getDeploymentsByStatus({ status: DEPLOYMENT_STATES.inprogress })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.accepted })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.pending })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.preauth })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.rejected })),\n dispatch(getDynamicGroups()),\n dispatch(getGroups()),\n dispatch(getIntegrations()),\n dispatch(getReleases()),\n dispatch(getAllDeviceCounts()).unwrap()\n ];\n if (hasMultitenancy) {\n tasks.push(dispatch(getDeviceLimits()));\n tasks.push(dispatch(getRoles()));\n }\n return Promise.all(tasks);\n }, [dispatch, hasMultitenancy, isServiceProvider]);\n\n const interpretAppData = useCallback((): Promise<unknown[]> => {\n const settings: Partial<UserSettings> = {};\n if (cookies.get('_ga') && typeof hasTrackingEnabled === 'undefined') {\n settings.trackingConsentGiven = true;\n }\n let tasks: Promise<unknown>[] = [\n Promise.resolve(dispatch(setDeviceListState({ selectedAttributes: columnSelection.map(column => ({ attribute: column.key, scope: column.scope })) }))),\n Promise.resolve(dispatch(setTooltipsState(tooltips as UserSliceType['tooltips']['byId']))), // tooltips read state is primarily trusted from the redux store, except on app init - here user settings are the reference\n dispatch(saveUserSettings(settings)).unwrap()\n ];\n // checks if user id is set and if cookie for helptips exists for that user\n tasks = maybeAddOnboardingTasks({ devicesByStatus, dispatch, tasks, onboardingState });\n\n if (canManageUsers && intervalUnit && intervalUnit !== timeUnits.days) {\n const duration = dayjs.duration(interval, intervalUnit as keyof typeof timeUnits);\n const days = duration.asDays();\n if (days < 1) {\n tasks.push(Promise.resolve(setTimeout(() => dispatch(setShowStartupNotification(true)), TIMEOUTS.fiveSeconds)));\n } else {\n const roundedDays = Math.max(1, Math.round(days));\n tasks.push(dispatch(saveGlobalSettings({ offlineThreshold: { interval: roundedDays, intervalUnit: timeUnits.days } })));\n }\n }\n\n // the following is used as a migration and initialization of the stored identity attribute\n // changing the default device attribute to the first non-deviceId attribute, unless a stored\n // id attribute setting exists\n const identityOptions = identityAttributes.filter(attribute => !['id', 'Device ID', 'status'].includes(attribute));\n if (!id_attribute && identityOptions.length) {\n tasks.push(dispatch(saveGlobalSettings({ id_attribute: { attribute: identityOptions[0], scope: 'identity' } })));\n } else if (typeof id_attribute === 'string') {\n // Legacy migration path: id_attribute used to be a plain string\n let attribute: string = id_attribute;\n if (attribute === 'Device ID') {\n attribute = 'id';\n }\n tasks.push(dispatch(saveGlobalSettings({ id_attribute: { attribute, scope: 'identity' } })));\n }\n tasks.push(Promise.resolve(dispatch(storeActions.setAppInitDone())));\n return Promise.all(tasks);\n }, [\n columnSelection,\n dispatch,\n identityAttributes,\n hasTrackingEnabled,\n canManageUsers,\n devicesByStatus,\n id_attribute,\n interval,\n intervalUnit,\n onboardingState,\n tooltips\n ]);\n\n const initializeAppData = useCallback(\n (): Promise<unknown> =>\n retrieveAppData()\n .then(interpretAppData)\n // this is allowed to fail if no user information are available\n .catch(err => console.log(extractErrorMessage(err)))\n .then(() => dispatch(getOnboardingState())),\n [dispatch, retrieveAppData, interpretAppData]\n );\n\n useEffect(() => {\n if (!userId || coreInitRunning.current) {\n return;\n }\n coreInitRunning.current = true;\n retrieveCoreData().then(() => setCoreInitDone(true));\n }, [userId, retrieveCoreData]);\n\n useEffect(() => {\n if (fullInitRunning.current || !coreInitDone) {\n return;\n }\n fullInitRunning.current = true;\n initializeAppData();\n }, [initializeAppData, coreInitDone]);\n\n return { coreInitDone };\n};\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { i as UserSession } from "./index-CSk4ENmk.cjs";
2
- import { r as RootState, t as AppDispatch } from "./store-DBUTT4FF.cjs";
2
+ import { r as RootState, t as AppDispatch } from "./store-xV2zaXAc.cjs";
3
3
 
4
4
  //#region src/storehooks.d.ts
5
5
  declare const parseEnvironmentInfo: import("@reduxjs/toolkit").AsyncThunk<[{
@@ -1,5 +1,5 @@
1
1
  import { i as UserSession } from "./index-Cf81vLTi.js";
2
- import { r as RootState, t as AppDispatch } from "./store-gkY5P9Uz.js";
2
+ import { r as RootState, t as AppDispatch } from "./store-BzrMxxAO.js";
3
3
 
4
4
  //#region src/storehooks.d.ts
5
5
  declare const parseEnvironmentInfo: import("@reduxjs/toolkit").AsyncThunk<[{
@@ -26,6 +26,7 @@ const featureFlags = [
26
26
  "hasDeltaProgress",
27
27
  "hasDeviceConfig",
28
28
  "hasDeviceConnect",
29
+ "hasDeviceFlags",
29
30
  "hasFeedbackEnabled",
30
31
  "hasManifestsEnabled",
31
32
  "hasMonitor",
@@ -1 +1 @@
1
- {"version":3,"file":"storehooks.js","names":["storeActions","getOnboardingStateSelector","getDevicesByStatusSelector","getUserSettingsSelector","getGlobalSettingsSelector","getUserSettings","getGlobalSettings","getDevicesByStatus","getOnboardingState"],"sources":["../src/storehooks.ts"],"sourcesContent":["// Copyright 2024 Northern.tech AS\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { extractErrorMessage } from '@northern.tech/utils/helpers';\nimport dayjs from 'dayjs';\nimport durationDayJs from 'dayjs/plugin/duration.js';\nimport Cookies from 'universal-cookie';\n\nimport storeActions from './actions';\nimport { getSessionInfo } from './auth';\nimport { DEPLOYMENT_STATES, DEVICE_STATES, TIMEOUTS, timeUnits } from './constants';\nimport type { DeviceSliceType } from './devicesSlice';\nimport {\n getDevicesByStatus as getDevicesByStatusSelector,\n getFeatures,\n getGlobalSettings as getGlobalSettingsSelector,\n getIsEnterprise,\n getIsServiceProvider,\n getOfflineThresholdSettings,\n getOnboardingState as getOnboardingStateSelector,\n getSortedFilteringAttributes,\n getUserCapabilities,\n getUserSettings as getUserSettingsSelector\n} from './selectors';\nimport { createAppAsyncThunk, useAppDispatch, useAppSelector } from './store';\nimport type { AppDispatch } from './store';\nimport {\n getAllDeviceCounts,\n getDeploymentsByStatus,\n getDeviceAttributes,\n getDeviceById,\n getDeviceLimits,\n getDevicesByStatus,\n getDynamicGroups,\n getGlobalSettings,\n getGroups,\n getIntegrations,\n getOnboardingState,\n getReleases,\n getRoles,\n getUserOrganization,\n getUserSettings,\n saveGlobalSettings,\n saveUserSettings\n} from './thunks';\nimport type { UserSettings, UserSliceType } from './usersSlice';\nimport { stringToBoolean } from './utils';\n\nconst cookies = new Cookies();\ndayjs.extend(durationDayJs);\n\nconst { setDeviceListState, setFirstLoginAfterSignup, setTooltipsState, setShowStartupNotification } = storeActions;\n\nconst featureFlags = [\n 'hasAiEnabled',\n 'hasAuditlogs',\n 'hasMultitenancy',\n 'hasDeltaProgress',\n 'hasDeviceConfig',\n 'hasDeviceConnect',\n 'hasFeedbackEnabled',\n 'hasManifestsEnabled',\n 'hasMonitor',\n 'hasMCUEnabled',\n 'isEnterprise'\n] as const;\n\nconst environmentDatas = [\n 'commit',\n 'feedbackProbability',\n 'hostAddress',\n 'hostedAnnouncement',\n 'recaptchaSiteKey',\n 'sentry',\n 'stripeAPIKey',\n 'trackerCode'\n] as const;\n\ntype VersionInfo = {\n docsVersion?: string;\n version?: string;\n};\n\ntype FeatureFlagsState = Record<string, boolean>;\n\nexport const parseEnvironmentInfo = createAppAsyncThunk(`app/parseEnvironmentInfo`, (_, { dispatch, getState }) => {\n const state = getState();\n let onboardingComplete = getOnboardingStateSelector(state).complete || !!JSON.parse(window.localStorage.getItem('onboardingComplete') ?? 'false');\n let demoArtifactPort = 85;\n let environmentData: Record<string, unknown> = {};\n let environmentFeatures: FeatureFlagsState = {};\n let versionInfo: VersionInfo = {};\n const mender_environment = window.mender_environment;\n if (mender_environment) {\n const { features = {}, demoArtifactPort: port, disableOnboarding, version } = mender_environment;\n demoArtifactPort = Number(port) || demoArtifactPort;\n const appState = state.app;\n environmentData = environmentDatas.reduce((accu, flag) => ({ ...accu, [flag]: mender_environment[flag] || appState[flag as keyof typeof appState] }), {});\n environmentFeatures = {\n ...featureFlags.reduce<FeatureFlagsState>((accu, flag) => ({ ...accu, [flag]: stringToBoolean(features[flag]) }), {}),\n isHosted: stringToBoolean(features.isHosted) || window.location.hostname.includes('hosted.mender.io')\n };\n onboardingComplete = !environmentFeatures.isHosted || stringToBoolean(disableOnboarding) || onboardingComplete;\n versionInfo = {\n docsVersion: isNaN(parseInt(version.charAt(0))) ? '' : version.split('.').slice(0, 2).join('.'),\n version\n };\n }\n return Promise.all([\n dispatch(storeActions.successfullyLoggedIn(getSessionInfo())),\n dispatch(storeActions.setOnboardingComplete(onboardingComplete)),\n dispatch(storeActions.setDemoArtifactPort(demoArtifactPort)),\n dispatch(storeActions.setFeatures(environmentFeatures)),\n dispatch(storeActions.setVersionInformation(versionInfo)),\n dispatch(storeActions.setEnvironmentData(environmentData))\n ]);\n});\n\ntype OnboardingState = {\n complete?: boolean;\n showTips?: boolean | null;\n};\n\ntype MaybeAddOnboardingTasksParams = {\n devicesByStatus: DeviceSliceType['byStatus'];\n dispatch: AppDispatch;\n onboardingState: OnboardingState;\n tasks: Promise<unknown>[];\n};\n\nconst maybeAddOnboardingTasks = ({ devicesByStatus, dispatch, onboardingState, tasks }: MaybeAddOnboardingTasksParams): Promise<unknown>[] => {\n if (!onboardingState.showTips || onboardingState.complete) {\n return tasks;\n }\n // try to retrieve full device details for onboarding devices to ensure ips etc. are available\n // we only load the first few/ 20 devices, as it is possible the onboarding is left dangling\n // and a lot of devices are present and we don't want to flood the backend for this\n return devicesByStatus[DEVICE_STATES.accepted].deviceIds.reduce<Promise<unknown>[]>((accu, id) => {\n accu.push(dispatch(getDeviceById(id)));\n return accu;\n }, tasks);\n};\n\nexport const useAppInit = (userId: string | undefined): { coreInitDone: boolean } => {\n const dispatch = useAppDispatch();\n const [coreInitDone, setCoreInitDone] = useState(false);\n const isEnterprise = useAppSelector(getIsEnterprise);\n const { hasMultitenancy, isHosted } = useAppSelector(getFeatures);\n const devicesByStatus = useAppSelector(getDevicesByStatusSelector);\n const onboardingState = useAppSelector(getOnboardingStateSelector);\n const { columnSelection = [], trackingConsentGiven: hasTrackingEnabled, tooltips = {} } = useAppSelector(getUserSettingsSelector);\n const { canManageUsers } = useAppSelector(getUserCapabilities);\n const { interval, intervalUnit } = useAppSelector(getOfflineThresholdSettings);\n const { id_attribute } = useAppSelector(getGlobalSettingsSelector);\n const { identityAttributes } = useAppSelector(getSortedFilteringAttributes);\n const isServiceProvider = useAppSelector(getIsServiceProvider);\n const coreInitRunning = useRef(false);\n const fullInitRunning = useRef(false);\n\n const retrieveCoreData = useCallback((): Promise<unknown[]> => {\n const tasks: Promise<unknown>[] = [\n dispatch(parseEnvironmentInfo()).unwrap(),\n dispatch(getUserSettings()).unwrap(),\n dispatch(getGlobalSettings()).unwrap(),\n Promise.resolve(dispatch(setFirstLoginAfterSignup(stringToBoolean(cookies.get('firstLoginAfterSignup')))))\n ];\n const multitenancy = hasMultitenancy || isHosted || isEnterprise;\n if (multitenancy) {\n tasks.push(dispatch(getUserOrganization()).unwrap());\n }\n return Promise.all(tasks);\n }, [dispatch, hasMultitenancy, isHosted, isEnterprise]);\n\n const retrieveAppData = useCallback((): Promise<unknown[] | unknown> => {\n if (isServiceProvider) {\n return Promise.resolve(dispatch(getRoles()));\n }\n const tasks: Promise<unknown>[] = [\n dispatch(getDeviceAttributes()),\n dispatch(getDeploymentsByStatus({ status: DEPLOYMENT_STATES.finished, shouldSelect: false })),\n dispatch(getDeploymentsByStatus({ status: DEPLOYMENT_STATES.inprogress })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.accepted })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.pending })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.preauth })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.rejected })),\n dispatch(getDynamicGroups()),\n dispatch(getGroups()),\n dispatch(getIntegrations()),\n dispatch(getReleases()),\n dispatch(getAllDeviceCounts()).unwrap()\n ];\n if (hasMultitenancy) {\n tasks.push(dispatch(getDeviceLimits()));\n tasks.push(dispatch(getRoles()));\n }\n return Promise.all(tasks);\n }, [dispatch, hasMultitenancy, isServiceProvider]);\n\n const interpretAppData = useCallback((): Promise<unknown[]> => {\n const settings: Partial<UserSettings> = {};\n if (cookies.get('_ga') && typeof hasTrackingEnabled === 'undefined') {\n settings.trackingConsentGiven = true;\n }\n let tasks: Promise<unknown>[] = [\n Promise.resolve(dispatch(setDeviceListState({ selectedAttributes: columnSelection.map(column => ({ attribute: column.key, scope: column.scope })) }))),\n Promise.resolve(dispatch(setTooltipsState(tooltips as UserSliceType['tooltips']['byId']))), // tooltips read state is primarily trusted from the redux store, except on app init - here user settings are the reference\n dispatch(saveUserSettings(settings)).unwrap()\n ];\n // checks if user id is set and if cookie for helptips exists for that user\n tasks = maybeAddOnboardingTasks({ devicesByStatus, dispatch, tasks, onboardingState });\n\n if (canManageUsers && intervalUnit && intervalUnit !== timeUnits.days) {\n const duration = dayjs.duration(interval, intervalUnit as keyof typeof timeUnits);\n const days = duration.asDays();\n if (days < 1) {\n tasks.push(Promise.resolve(setTimeout(() => dispatch(setShowStartupNotification(true)), TIMEOUTS.fiveSeconds)));\n } else {\n const roundedDays = Math.max(1, Math.round(days));\n tasks.push(dispatch(saveGlobalSettings({ offlineThreshold: { interval: roundedDays, intervalUnit: timeUnits.days } })));\n }\n }\n\n // the following is used as a migration and initialization of the stored identity attribute\n // changing the default device attribute to the first non-deviceId attribute, unless a stored\n // id attribute setting exists\n const identityOptions = identityAttributes.filter(attribute => !['id', 'Device ID', 'status'].includes(attribute));\n if (!id_attribute && identityOptions.length) {\n tasks.push(dispatch(saveGlobalSettings({ id_attribute: { attribute: identityOptions[0], scope: 'identity' } })));\n } else if (typeof id_attribute === 'string') {\n // Legacy migration path: id_attribute used to be a plain string\n let attribute: string = id_attribute;\n if (attribute === 'Device ID') {\n attribute = 'id';\n }\n tasks.push(dispatch(saveGlobalSettings({ id_attribute: { attribute, scope: 'identity' } })));\n }\n tasks.push(Promise.resolve(dispatch(storeActions.setAppInitDone())));\n return Promise.all(tasks);\n }, [\n columnSelection,\n dispatch,\n identityAttributes,\n hasTrackingEnabled,\n canManageUsers,\n devicesByStatus,\n id_attribute,\n interval,\n intervalUnit,\n onboardingState,\n tooltips\n ]);\n\n const initializeAppData = useCallback(\n (): Promise<unknown> =>\n retrieveAppData()\n .then(interpretAppData)\n // this is allowed to fail if no user information are available\n .catch(err => console.log(extractErrorMessage(err)))\n .then(() => dispatch(getOnboardingState())),\n [dispatch, retrieveAppData, interpretAppData]\n );\n\n useEffect(() => {\n if (!userId || coreInitRunning.current) {\n return;\n }\n coreInitRunning.current = true;\n retrieveCoreData().then(() => setCoreInitDone(true));\n }, [userId, retrieveCoreData]);\n\n useEffect(() => {\n if (fullInitRunning.current || !coreInitDone) {\n return;\n }\n fullInitRunning.current = true;\n initializeAppData();\n }, [initializeAppData, coreInitDone]);\n\n return { coreInitDone };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"storehooks.js","names":["storeActions","getOnboardingStateSelector","getDevicesByStatusSelector","getUserSettingsSelector","getGlobalSettingsSelector","getUserSettings","getGlobalSettings","getDevicesByStatus","getOnboardingState"],"sources":["../src/storehooks.ts"],"sourcesContent":["// Copyright 2024 Northern.tech AS\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { extractErrorMessage } from '@northern.tech/utils/helpers';\nimport dayjs from 'dayjs';\nimport durationDayJs from 'dayjs/plugin/duration.js';\nimport Cookies from 'universal-cookie';\n\nimport storeActions from './actions';\nimport { getSessionInfo } from './auth';\nimport { DEPLOYMENT_STATES, DEVICE_STATES, TIMEOUTS, timeUnits } from './constants';\nimport type { DeviceSliceType } from './devicesSlice';\nimport {\n getDevicesByStatus as getDevicesByStatusSelector,\n getFeatures,\n getGlobalSettings as getGlobalSettingsSelector,\n getIsEnterprise,\n getIsServiceProvider,\n getOfflineThresholdSettings,\n getOnboardingState as getOnboardingStateSelector,\n getSortedFilteringAttributes,\n getUserCapabilities,\n getUserSettings as getUserSettingsSelector\n} from './selectors';\nimport { createAppAsyncThunk, useAppDispatch, useAppSelector } from './store';\nimport type { AppDispatch } from './store';\nimport {\n getAllDeviceCounts,\n getDeploymentsByStatus,\n getDeviceAttributes,\n getDeviceById,\n getDeviceLimits,\n getDevicesByStatus,\n getDynamicGroups,\n getGlobalSettings,\n getGroups,\n getIntegrations,\n getOnboardingState,\n getReleases,\n getRoles,\n getUserOrganization,\n getUserSettings,\n saveGlobalSettings,\n saveUserSettings\n} from './thunks';\nimport type { UserSettings, UserSliceType } from './usersSlice';\nimport { stringToBoolean } from './utils';\n\nconst cookies = new Cookies();\ndayjs.extend(durationDayJs);\n\nconst { setDeviceListState, setFirstLoginAfterSignup, setTooltipsState, setShowStartupNotification } = storeActions;\n\nconst featureFlags = [\n 'hasAiEnabled',\n 'hasAuditlogs',\n 'hasMultitenancy',\n 'hasDeltaProgress',\n 'hasDeviceConfig',\n 'hasDeviceConnect',\n 'hasDeviceFlags',\n 'hasFeedbackEnabled',\n 'hasManifestsEnabled',\n 'hasMonitor',\n 'hasMCUEnabled',\n 'isEnterprise'\n] as const;\n\nconst environmentDatas = [\n 'commit',\n 'feedbackProbability',\n 'hostAddress',\n 'hostedAnnouncement',\n 'recaptchaSiteKey',\n 'sentry',\n 'stripeAPIKey',\n 'trackerCode'\n] as const;\n\ntype VersionInfo = {\n docsVersion?: string;\n version?: string;\n};\n\ntype FeatureFlagsState = Record<string, boolean>;\n\nexport const parseEnvironmentInfo = createAppAsyncThunk(`app/parseEnvironmentInfo`, (_, { dispatch, getState }) => {\n const state = getState();\n let onboardingComplete = getOnboardingStateSelector(state).complete || !!JSON.parse(window.localStorage.getItem('onboardingComplete') ?? 'false');\n let demoArtifactPort = 85;\n let environmentData: Record<string, unknown> = {};\n let environmentFeatures: FeatureFlagsState = {};\n let versionInfo: VersionInfo = {};\n const mender_environment = window.mender_environment;\n if (mender_environment) {\n const { features = {}, demoArtifactPort: port, disableOnboarding, version } = mender_environment;\n demoArtifactPort = Number(port) || demoArtifactPort;\n const appState = state.app;\n environmentData = environmentDatas.reduce((accu, flag) => ({ ...accu, [flag]: mender_environment[flag] || appState[flag as keyof typeof appState] }), {});\n environmentFeatures = {\n ...featureFlags.reduce<FeatureFlagsState>((accu, flag) => ({ ...accu, [flag]: stringToBoolean(features[flag]) }), {}),\n isHosted: stringToBoolean(features.isHosted) || window.location.hostname.includes('hosted.mender.io')\n };\n onboardingComplete = !environmentFeatures.isHosted || stringToBoolean(disableOnboarding) || onboardingComplete;\n versionInfo = {\n docsVersion: isNaN(parseInt(version.charAt(0))) ? '' : version.split('.').slice(0, 2).join('.'),\n version\n };\n }\n return Promise.all([\n dispatch(storeActions.successfullyLoggedIn(getSessionInfo())),\n dispatch(storeActions.setOnboardingComplete(onboardingComplete)),\n dispatch(storeActions.setDemoArtifactPort(demoArtifactPort)),\n dispatch(storeActions.setFeatures(environmentFeatures)),\n dispatch(storeActions.setVersionInformation(versionInfo)),\n dispatch(storeActions.setEnvironmentData(environmentData))\n ]);\n});\n\ntype OnboardingState = {\n complete?: boolean;\n showTips?: boolean | null;\n};\n\ntype MaybeAddOnboardingTasksParams = {\n devicesByStatus: DeviceSliceType['byStatus'];\n dispatch: AppDispatch;\n onboardingState: OnboardingState;\n tasks: Promise<unknown>[];\n};\n\nconst maybeAddOnboardingTasks = ({ devicesByStatus, dispatch, onboardingState, tasks }: MaybeAddOnboardingTasksParams): Promise<unknown>[] => {\n if (!onboardingState.showTips || onboardingState.complete) {\n return tasks;\n }\n // try to retrieve full device details for onboarding devices to ensure ips etc. are available\n // we only load the first few/ 20 devices, as it is possible the onboarding is left dangling\n // and a lot of devices are present and we don't want to flood the backend for this\n return devicesByStatus[DEVICE_STATES.accepted].deviceIds.reduce<Promise<unknown>[]>((accu, id) => {\n accu.push(dispatch(getDeviceById(id)));\n return accu;\n }, tasks);\n};\n\nexport const useAppInit = (userId: string | undefined): { coreInitDone: boolean } => {\n const dispatch = useAppDispatch();\n const [coreInitDone, setCoreInitDone] = useState(false);\n const isEnterprise = useAppSelector(getIsEnterprise);\n const { hasMultitenancy, isHosted } = useAppSelector(getFeatures);\n const devicesByStatus = useAppSelector(getDevicesByStatusSelector);\n const onboardingState = useAppSelector(getOnboardingStateSelector);\n const { columnSelection = [], trackingConsentGiven: hasTrackingEnabled, tooltips = {} } = useAppSelector(getUserSettingsSelector);\n const { canManageUsers } = useAppSelector(getUserCapabilities);\n const { interval, intervalUnit } = useAppSelector(getOfflineThresholdSettings);\n const { id_attribute } = useAppSelector(getGlobalSettingsSelector);\n const { identityAttributes } = useAppSelector(getSortedFilteringAttributes);\n const isServiceProvider = useAppSelector(getIsServiceProvider);\n const coreInitRunning = useRef(false);\n const fullInitRunning = useRef(false);\n\n const retrieveCoreData = useCallback((): Promise<unknown[]> => {\n const tasks: Promise<unknown>[] = [\n dispatch(parseEnvironmentInfo()).unwrap(),\n dispatch(getUserSettings()).unwrap(),\n dispatch(getGlobalSettings()).unwrap(),\n Promise.resolve(dispatch(setFirstLoginAfterSignup(stringToBoolean(cookies.get('firstLoginAfterSignup')))))\n ];\n const multitenancy = hasMultitenancy || isHosted || isEnterprise;\n if (multitenancy) {\n tasks.push(dispatch(getUserOrganization()).unwrap());\n }\n return Promise.all(tasks);\n }, [dispatch, hasMultitenancy, isHosted, isEnterprise]);\n\n const retrieveAppData = useCallback((): Promise<unknown[] | unknown> => {\n if (isServiceProvider) {\n return Promise.resolve(dispatch(getRoles()));\n }\n const tasks: Promise<unknown>[] = [\n dispatch(getDeviceAttributes()),\n dispatch(getDeploymentsByStatus({ status: DEPLOYMENT_STATES.finished, shouldSelect: false })),\n dispatch(getDeploymentsByStatus({ status: DEPLOYMENT_STATES.inprogress })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.accepted })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.pending })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.preauth })),\n dispatch(getDevicesByStatus({ status: DEVICE_STATES.rejected })),\n dispatch(getDynamicGroups()),\n dispatch(getGroups()),\n dispatch(getIntegrations()),\n dispatch(getReleases()),\n dispatch(getAllDeviceCounts()).unwrap()\n ];\n if (hasMultitenancy) {\n tasks.push(dispatch(getDeviceLimits()));\n tasks.push(dispatch(getRoles()));\n }\n return Promise.all(tasks);\n }, [dispatch, hasMultitenancy, isServiceProvider]);\n\n const interpretAppData = useCallback((): Promise<unknown[]> => {\n const settings: Partial<UserSettings> = {};\n if (cookies.get('_ga') && typeof hasTrackingEnabled === 'undefined') {\n settings.trackingConsentGiven = true;\n }\n let tasks: Promise<unknown>[] = [\n Promise.resolve(dispatch(setDeviceListState({ selectedAttributes: columnSelection.map(column => ({ attribute: column.key, scope: column.scope })) }))),\n Promise.resolve(dispatch(setTooltipsState(tooltips as UserSliceType['tooltips']['byId']))), // tooltips read state is primarily trusted from the redux store, except on app init - here user settings are the reference\n dispatch(saveUserSettings(settings)).unwrap()\n ];\n // checks if user id is set and if cookie for helptips exists for that user\n tasks = maybeAddOnboardingTasks({ devicesByStatus, dispatch, tasks, onboardingState });\n\n if (canManageUsers && intervalUnit && intervalUnit !== timeUnits.days) {\n const duration = dayjs.duration(interval, intervalUnit as keyof typeof timeUnits);\n const days = duration.asDays();\n if (days < 1) {\n tasks.push(Promise.resolve(setTimeout(() => dispatch(setShowStartupNotification(true)), TIMEOUTS.fiveSeconds)));\n } else {\n const roundedDays = Math.max(1, Math.round(days));\n tasks.push(dispatch(saveGlobalSettings({ offlineThreshold: { interval: roundedDays, intervalUnit: timeUnits.days } })));\n }\n }\n\n // the following is used as a migration and initialization of the stored identity attribute\n // changing the default device attribute to the first non-deviceId attribute, unless a stored\n // id attribute setting exists\n const identityOptions = identityAttributes.filter(attribute => !['id', 'Device ID', 'status'].includes(attribute));\n if (!id_attribute && identityOptions.length) {\n tasks.push(dispatch(saveGlobalSettings({ id_attribute: { attribute: identityOptions[0], scope: 'identity' } })));\n } else if (typeof id_attribute === 'string') {\n // Legacy migration path: id_attribute used to be a plain string\n let attribute: string = id_attribute;\n if (attribute === 'Device ID') {\n attribute = 'id';\n }\n tasks.push(dispatch(saveGlobalSettings({ id_attribute: { attribute, scope: 'identity' } })));\n }\n tasks.push(Promise.resolve(dispatch(storeActions.setAppInitDone())));\n return Promise.all(tasks);\n }, [\n columnSelection,\n dispatch,\n identityAttributes,\n hasTrackingEnabled,\n canManageUsers,\n devicesByStatus,\n id_attribute,\n interval,\n intervalUnit,\n onboardingState,\n tooltips\n ]);\n\n const initializeAppData = useCallback(\n (): Promise<unknown> =>\n retrieveAppData()\n .then(interpretAppData)\n // this is allowed to fail if no user information are available\n .catch(err => console.log(extractErrorMessage(err)))\n .then(() => dispatch(getOnboardingState())),\n [dispatch, retrieveAppData, interpretAppData]\n );\n\n useEffect(() => {\n if (!userId || coreInitRunning.current) {\n return;\n }\n coreInitRunning.current = true;\n retrieveCoreData().then(() => setCoreInitDone(true));\n }, [userId, retrieveCoreData]);\n\n useEffect(() => {\n if (fullInitRunning.current || !coreInitDone) {\n return;\n }\n fullInitRunning.current = true;\n initializeAppData();\n }, [initializeAppData, coreInitDone]);\n\n return { coreInitDone };\n};\n"],"mappings":"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"}
package/dist/thunks.cjs CHANGED
@@ -108,6 +108,13 @@ const { isUUID } = validator.default;
108
108
  const { receivedDevice, setSnackbar: setSnackbar$3 } = require_actions;
109
109
  const { page: defaultPage$2, perPage: defaultPerPage$2 } = _northern_tech_utils_constants.DEVICE_LIST_DEFAULTS;
110
110
  const deriveDeploymentGroup = ({ filter, group, groups = [], name }) => group || groups.length === 1 && !isUUID(name) ? groups[0] : filter?.name;
111
+ const decodeDeploymentName = (name) => {
112
+ try {
113
+ return decodeURIComponent(name);
114
+ } catch {
115
+ return name;
116
+ }
117
+ };
111
118
  const transformDeployments = (deployments, deploymentsById) => deployments.sort((0, _northern_tech_utils_helpers.customSort)(true, "created")).reduce((accu, item) => {
112
119
  const filter = item.filter;
113
120
  let deployment = {
@@ -119,7 +126,7 @@ const transformDeployments = (deployments, deploymentsById) => deployments.sort(
119
126
  name: filter.name ?? filter.id,
120
127
  filters: require_utils.mapTermsToFilters(filter.terms)
121
128
  } : void 0,
122
- name: decodeURIComponent(item.name)
129
+ name: decodeDeploymentName(item.name)
123
130
  };
124
131
  deployment = {
125
132
  ...deployment,
@@ -891,6 +898,23 @@ const getAllDeviceCounts = require_store.createAppAsyncThunk(`${require_devicesS
891
898
  })));
892
899
  }));
893
900
  const getDeviceLimits = require_store.createAppAsyncThunk(`${require_devicesSlice_index.sliceName}/getDeviceLimit`, (_, { dispatch }) => require_api_general_api.default.get(`${_northern_tech_utils_constants.deviceAuthV2}/limits/devices`).then((res) => dispatch(require_devicesSlice_index.actions.setDeviceLimits(res.data))));
901
+ const getTestDeviceCount = require_store.createAppAsyncThunk(`${require_devicesSlice_index.sliceName}/getTestDeviceCount`, async (_, { dispatch }) => {
902
+ const res = await require_api_general_api.default.post(`${_northern_tech_utils_constants.inventoryApiUrlV2}/filters/search`, {
903
+ page: 1,
904
+ per_page: 1,
905
+ filters: [{
906
+ scope: "system",
907
+ attribute: "test_device",
908
+ type: _northern_tech_utils_constants.DEVICE_FILTERING_OPTIONS.$eq.key,
909
+ value: "true"
910
+ }],
911
+ attributes: [{
912
+ scope: "identity",
913
+ attribute: "status"
914
+ }]
915
+ }).catch((err) => require_store.commonErrorHandler(err, `Retrieving test device count failed:`, dispatch, require_store.commonErrorFallback));
916
+ return dispatch(require_devicesSlice_index.actions.setTestDeviceCount(Number(res.headers[_northern_tech_utils_constants.headerNames.total])));
917
+ });
894
918
  const setDeviceListState = require_store.createAppAsyncThunk(`${require_devicesSlice_index.sliceName}/setDeviceListState`, ({ shouldSelectDevices = true, forceRefresh, fetchAuth = true, ...selectionState }, { dispatch, getState }) => {
895
919
  const currentState = require_devicesSlice_selectors.getDeviceListState(getState());
896
920
  const refreshTrigger = forceRefresh ? !currentState.refreshTrigger : selectionState.refreshTrigger;
@@ -1283,6 +1307,15 @@ const setDeviceTags = require_store.createAppAsyncThunk(`${require_devicesSlice_
1283
1307
  tags
1284
1308
  })), dispatch(setSnackbar$2(`Device ${tagList.length === 1 && isNameChange ? "name" : "tags"} changed`))]));
1285
1309
  }));
1310
+ const setTestDeviceStatus = require_store.createAppAsyncThunk(`${require_devicesSlice_index.sliceName}/setTestDeviceStatus`, ({ deviceId, test_device }, { dispatch }) => require_api_general_api.default.put(`${_northern_tech_utils_constants.deviceAuthV2}/devices/${deviceId}/flags`, { test_device }).catch((err) => require_store.commonErrorHandler(err, `There was an error setting test status for device ${deviceId}.`, dispatch, "Please check your connection.")).then(() => Promise.all([
1311
+ dispatch(setSnackbar$2("Device updated successfully")),
1312
+ dispatch(require_devicesSlice_index.actions.receivedDevice({
1313
+ id: deviceId,
1314
+ flags: { test_device }
1315
+ })),
1316
+ dispatch(getDeviceById(deviceId)),
1317
+ dispatch(getTestDeviceCount())
1318
+ ])));
1286
1319
  const getDeviceTwin = require_store.createAppAsyncThunk(`${require_devicesSlice_index.sliceName}/getDeviceTwin`, ({ deviceId, integration }, { dispatch, getState }) => {
1287
1320
  let providerResult = {};
1288
1321
  return require_api_general_api.default.get(`${_northern_tech_utils_constants.iotManagerBaseURL}/devices/${deviceId}/state`).then(({ data }) => {
@@ -2597,6 +2630,7 @@ exports.getSsoConfigs = getSsoConfigs;
2597
2630
  exports.getSystemDevices = getSystemDevices;
2598
2631
  exports.getTargetLocation = getTargetLocation;
2599
2632
  exports.getTenants = getTenants;
2633
+ exports.getTestDeviceCount = getTestDeviceCount;
2600
2634
  exports.getTokens = getTokens;
2601
2635
  exports.getUpdateTypes = require_releasesSlice_thunks.getUpdateTypes;
2602
2636
  exports.getUser = getUser;
@@ -2659,6 +2693,7 @@ exports.setSearchState = setSearchState;
2659
2693
  exports.setSingleReleaseTags = require_releasesSlice_thunks.setSingleReleaseTags;
2660
2694
  exports.setSoftwareListState = require_releasesSlice_thunks.setSoftwareListState;
2661
2695
  exports.setTenantsListState = setTenantsListState;
2696
+ exports.setTestDeviceStatus = setTestDeviceStatus;
2662
2697
  exports.setTooltipReadState = setTooltipReadState;
2663
2698
  exports.startCardUpdate = startCardUpdate;
2664
2699
  exports.startUpgrade = startUpgrade;
@@ -2666,6 +2701,7 @@ exports.storeSsoConfig = storeSsoConfig;
2666
2701
  exports.submitUserFeedback = submitUserFeedback;
2667
2702
  exports.switchUserOrganization = switchUserOrganization;
2668
2703
  exports.tenantDataDivergedMessage = tenantDataDivergedMessage;
2704
+ exports.transformDeployments = transformDeployments;
2669
2705
  exports.transformProductResponse = transformProductResponse;
2670
2706
  exports.triggerDeviceUpdate = triggerDeviceUpdate;
2671
2707
  exports.updateDeploymentControlMap = updateDeploymentControlMap;