Skip to content

Commit

Permalink
chore: moved environment state parsing to actions to ease testing setup
Browse files Browse the repository at this point in the history
+ aligned UI accordingly

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
  • Loading branch information
mzedel committed Dec 6, 2022
1 parent 000d242 commit 729904e
Show file tree
Hide file tree
Showing 12 changed files with 253 additions and 159 deletions.
92 changes: 83 additions & 9 deletions src/js/actions/appActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,37 @@ import Cookies from 'universal-cookie';
import GeneralApi from '../api/general-api';
import { getToken } from '../auth';
import {
SET_ENVIRONMENT_DATA,
SET_FEATURES,
SET_FIRST_LOGIN_AFTER_SIGNUP,
SET_OFFLINE_THRESHOLD,
SET_SEARCH_STATE,
SET_SNACKBAR,
SET_VERSION_INFORMATION,
TIMEOUTS
} from '../constants/appConstants';
import { DEVICE_STATES } from '../constants/deviceConstants';
import { DEPLOYMENT_STATES } from '../constants/deploymentConstants';
import { SET_SHOW_HELP } from '../constants/userConstants';
import { DEVICE_STATES } from '../constants/deviceConstants';
import { onboardingSteps } from '../constants/onboardingConstants';
import { customSort, deepCompare, extractErrorMessage, preformatWithRequestID } from '../helpers';
import { SET_SHOW_HELP } from '../constants/userConstants';
import { customSort, deepCompare, extractErrorMessage, preformatWithRequestID, stringToBoolean } from '../helpers';
import { getCurrentUser, getOfflineThresholdSettings, getUserSettings as getUserSettingsSelector } from '../selectors';
import { getOnboardingComponentFor } from '../utils/onboardingmanager';
import { getDeploymentsByStatus } from './deploymentActions';
import {
getDeviceAttributes,
getDeviceById,
getDevicesByStatus,
getDeviceLimit,
getDevicesByStatus,
getDynamicGroups,
getGroups,
setDeviceListState,
searchDevices
searchDevices,
setDeviceListState
} from './deviceActions';
import { getDeploymentsByStatus } from './deploymentActions';
import { getReleases } from './releaseActions';
import { saveUserSettings, getGlobalSettings, getRoles, saveGlobalSettings, getUserSettings } from './userActions';
import { setDemoArtifactPort, setOnboardingComplete } from './onboardingActions';
import { getIntegrations, getUserOrganization } from './organizationActions';
import { getReleases } from './releaseActions';
import { getGlobalSettings, getRoles, getUserSettings, saveGlobalSettings, saveUserSettings } from './userActions';

const cookies = new Cookies();

Expand All @@ -43,8 +46,79 @@ export const commonErrorHandler = (err, errorContext, dispatch, fallback, mightB
return Promise.reject(err);
};

const getComparisonCompatibleVersion = version => (isNaN(version.charAt(0)) && version !== 'next' ? 'master' : version);

export const parseEnvironmentInfo = () => (dispatch, getState) => {
const state = getState();
let onboardingComplete = state.onboarding.complete || !!JSON.parse(window.localStorage.getItem('onboardingComplete'));
let demoArtifactPort = 85;
let environmentData = {};
let environmentFeatures = {};
let versionInfo = {};
if (mender_environment) {
const {
features = {},
demoArtifactPort: port,
disableOnboarding,
hostAddress,
hostedAnnouncement,
integrationVersion,
isDemoMode,
menderVersion,
menderArtifactVersion,
metaMenderVersion,
recaptchaSiteKey,
services = {},
stripeAPIKey,
trackerCode
} = mender_environment;
onboardingComplete = stringToBoolean(features.isEnterprise) || stringToBoolean(disableOnboarding) || onboardingComplete;
demoArtifactPort = port || demoArtifactPort;
environmentData = {
hostedAnnouncement: hostedAnnouncement || state.app.hostedAnnouncement,
hostAddress: hostAddress || state.app.hostAddress,
recaptchaSiteKey: recaptchaSiteKey || state.app.recaptchaSiteKey,
stripeAPIKey: stripeAPIKey || state.app.stripeAPIKey,
trackerCode: trackerCode || state.app.trackerCode
};
environmentFeatures = {
hasAddons: stringToBoolean(features.hasAddons),
hasAuditlogs: stringToBoolean(features.hasAuditlogs),
hasMultitenancy: stringToBoolean(features.hasMultitenancy),
hasDeviceConfig: stringToBoolean(features.hasDeviceConfig),
hasDeviceConnect: stringToBoolean(features.hasDeviceConnect),
hasMonitor: stringToBoolean(features.hasMonitor),
hasReporting: stringToBoolean(features.hasReporting),
isHosted: stringToBoolean(features.isHosted) || window.location.hostname.includes('hosted.mender.io'),
isEnterprise: stringToBoolean(features.isEnterprise),
isDemoMode: stringToBoolean(isDemoMode || features.isDemoMode)
};
versionInfo = {
docs: isNaN(integrationVersion.charAt(0)) ? '' : integrationVersion.split('.').slice(0, 2).join('.'),
remainder: {
Integration: getComparisonCompatibleVersion(integrationVersion),
'Mender-Client': getComparisonCompatibleVersion(menderVersion),
'Mender-Artifact': menderArtifactVersion,
'Meta-Mender': metaMenderVersion,
Deployments: services.deploymentsVersion,
Deviceauth: services.deviceauthVersion,
Inventory: services.inventoryVersion,
GUI: services.guiVersion
}
};
}
return Promise.all([
dispatch(setOnboardingComplete(onboardingComplete)),
dispatch(setDemoArtifactPort(demoArtifactPort)),
dispatch({ type: SET_FEATURES, value: environmentFeatures }),
dispatch({ type: SET_VERSION_INFORMATION, docsVersion: versionInfo.docs, value: versionInfo.remainder }),
dispatch({ type: SET_ENVIRONMENT_DATA, value: environmentData })
]);
};

export const initializeAppData = () => (dispatch, getState) => {
let tasks = [
dispatch(parseEnvironmentInfo()),
dispatch(getUserSettings()),
dispatch(getGlobalSettings()),
dispatch(getDeviceAttributes()),
Expand Down
51 changes: 36 additions & 15 deletions src/js/actions/appActions.test.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { inventoryDevice } from '../../../tests/__mocks__/deviceHandlers';
import { defaultState, receivedPermissionSets, receivedRoles } from '../../../tests/mockData';
import { inventoryDevice } from '../../../tests/__mocks__/deviceHandlers';

import {
commonErrorHandler,
getLatestReleaseInfo,
initializeAppData,
setSearchState,
setSnackbar,
setFirstLoginAfterSignup,
setOfflineThreshold,
setVersionInfo
} from './appActions';
import { tenantDataDivergedMessage } from './organizationActions';
import {
SET_ANNOUNCEMENT,
SET_ENVIRONMENT_DATA,
SET_FEATURES,
SET_FIRST_LOGIN_AFTER_SIGNUP,
SET_OFFLINE_THRESHOLD,
SET_SEARCH_STATE,
Expand Down Expand Up @@ -45,10 +36,21 @@ import {
SET_REJECTED_DEVICES,
UNGROUPED_GROUP
} from '../constants/deviceConstants';
import { RECEIVE_RELEASES, SET_RELEASES_LIST_STATE } from '../constants/releaseConstants';
import { SET_ONBOARDING_ARTIFACT_INCLUDED } from '../constants/onboardingConstants';
import { SET_DEMO_ARTIFACT_PORT, SET_ONBOARDING_ARTIFACT_INCLUDED, SET_ONBOARDING_COMPLETE } from '../constants/onboardingConstants';
import { RECEIVE_EXTERNAL_DEVICE_INTEGRATIONS, SET_ORGANIZATION } from '../constants/organizationConstants';
import { RECEIVED_PERMISSION_SETS, RECEIVED_ROLES, SET_SHOW_HELP, SET_GLOBAL_SETTINGS, SET_USER_SETTINGS } from '../constants/userConstants';
import { RECEIVE_RELEASES, SET_RELEASES_LIST_STATE } from '../constants/releaseConstants';
import { RECEIVED_PERMISSION_SETS, RECEIVED_ROLES, SET_GLOBAL_SETTINGS, SET_SHOW_HELP, SET_USER_SETTINGS } from '../constants/userConstants';
import {
commonErrorHandler,
getLatestReleaseInfo,
initializeAppData,
setFirstLoginAfterSignup,
setOfflineThreshold,
setSearchState,
setSnackbar,
setVersionInfo
} from './appActions';
import { tenantDataDivergedMessage } from './organizationActions';

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
Expand Down Expand Up @@ -80,6 +82,7 @@ describe('app actions', () => {
});

it('should try to get all required app information', async () => {
window.localStorage.getItem.mockReturnValueOnce('false');
const attributeReducer = (accu, item) => {
if (item.scope === 'inventory') {
accu[item.name] = item.value;
Expand All @@ -98,6 +101,24 @@ describe('app actions', () => {
// eslint-disable-next-line no-unused-vars
const { attributes, ...expectedDevice } = defaultState.devices.byId.a1;
const expectedActions = [
{ type: SET_ONBOARDING_COMPLETE, complete: false },
{ type: SET_DEMO_ARTIFACT_PORT, port: undefined },
{ type: SET_FEATURES, value: { ...defaultState.app.features, hasMultitenancy: true } },
{
type: SET_VERSION_INFORMATION,
docsVersion: '',
value: {
Deployments: '1.2.3',
Deviceauth: null,
GUI: undefined,
Integration: 'master',
Inventory: null,
'Mender-Artifact': undefined,
'Mender-Client': 'next',
'Meta-Mender': 'saas-123.34'
}
},
{ type: SET_ENVIRONMENT_DATA, value: { hostAddress: null, hostedAnnouncement: '', stripeAPIKey: '', trackerCode: '' } },
{ type: SET_FIRST_LOGIN_AFTER_SIGNUP, firstLoginAfterSignup: false },
{ type: SET_USER_SETTINGS, settings: { ...defaultState.users.userSettings } },
{ type: SET_GLOBAL_SETTINGS, settings: { ...defaultState.users.globalSettings } },
Expand Down
15 changes: 9 additions & 6 deletions src/js/actions/onboardingActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@ import Cookies from 'universal-cookie';
import { DEVICE_STATES } from '../constants/deviceConstants';
import {
onboardingSteps as onboardingStepNames,
SET_ONBOARDING_PROGRESS,
SET_SHOW_ONBOARDING_HELP,
SET_ONBOARDING_DEVICE_TYPE,
SET_DEMO_ARTIFACT_PORT,
SET_ONBOARDING_APPROACH,
SET_ONBOARDING_ARTIFACT_INCLUDED,
SET_ONBOARDING_COMPLETE,
SET_ONBOARDING_DEVICE_TYPE,
SET_ONBOARDING_PROGRESS,
SET_SHOW_CREATE_ARTIFACT,
SET_SHOW_ONBOARDING_HELP_DIALOG,
SET_ONBOARDING_COMPLETE
SET_SHOW_ONBOARDING_HELP,
SET_SHOW_ONBOARDING_HELP_DIALOG
} from '../constants/onboardingConstants';
import { SET_SHOW_HELP } from '../constants/userConstants';

import { applyOnboardingFallbacks, onboardingSteps } from '../utils/onboardingmanager';
import { getDemoDeviceAddress } from '../helpers';
import { getUserCapabilities, getUserSettings } from '../selectors';
import Tracking from '../tracking';
import { applyOnboardingFallbacks, onboardingSteps } from '../utils/onboardingmanager';
import { saveUserSettings } from './userActions';

const cookies = new Cookies();
Expand Down Expand Up @@ -123,6 +124,8 @@ export const setShowCreateArtifactDialog = show => dispatch => dispatch({ type:

export const setShowDismissOnboardingTipsDialog = show => dispatch => dispatch({ type: SET_SHOW_ONBOARDING_HELP_DIALOG, show });

export const setDemoArtifactPort = port => dispatch => dispatch({ type: SET_DEMO_ARTIFACT_PORT, value: port });

export const setOnboardingComplete = val => dispatch =>
Promise.resolve(dispatch({ type: SET_ONBOARDING_COMPLETE, complete: val })).then(() => {
if (val) {
Expand Down
35 changes: 23 additions & 12 deletions src/js/actions/onboardingActions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { defaultState } from '../../../tests/mockData';

import * as OnboardingConstants from '../constants/onboardingConstants';
import * as UserConstants from '../constants/userConstants';
import { onboardingSteps } from '../utils/onboardingmanager';
import {
advanceOnboarding,
getOnboardingState,
Expand All @@ -13,13 +16,20 @@ import {
setShowDismissOnboardingTipsDialog,
setShowOnboardingHelp
} from './onboardingActions';
import { onboardingSteps } from '../utils/onboardingmanager';
import * as OnboardingConstants from '../constants/onboardingConstants';
import * as UserConstants from '../constants/userConstants';

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

const defaultOnboardingState = {
approach: null,
artifactIncluded: null,
demoArtifactPort: 85,
deviceType: null,
showConnectDeviceDialog: false,
showTips: null,
something: 'here'
};

describe('onboarding actions', () => {
it('should pass on onboarding completion', async () => {
const store = mockStore({ ...defaultState });
Expand All @@ -34,11 +44,9 @@ describe('onboarding actions', () => {
settings: {
...defaultState.users.userSettings,
onboarding: {
...defaultOnboardingState,
complete: true,
demoArtifactPort: 85,
progress: 'onboarding-finished-notification',
showConnectDeviceDialog: false,
something: 'here'
progress: 'onboarding-finished-notification'
}
}
}
Expand Down Expand Up @@ -143,10 +151,9 @@ describe('onboarding actions', () => {
settings: {
columnSelection: [],
onboarding: {
...defaultOnboardingState,
complete: false,
demoArtifactPort: 85,
progress: stepNames[1],
showConnectDeviceDialog: false,
something: 'here'
}
}
Expand Down Expand Up @@ -182,7 +189,11 @@ describe('onboarding actions', () => {
settings: {
...defaultState.users.userSettings,
columnSelection: [],
onboarding: { complete: true, demoArtifactPort: 85, progress: 'onboarding-canceled', showConnectDeviceDialog: false, something: 'here' }
onboarding: {
...defaultOnboardingState,
complete: true,
progress: 'onboarding-canceled'
}
}
}
];
Expand All @@ -198,7 +209,7 @@ describe('onboarding actions', () => {
{ type: OnboardingConstants.SET_ONBOARDING_COMPLETE, complete: false },
{ type: OnboardingConstants.SET_ONBOARDING_DEVICE_TYPE, value: ['raspberrypi4'] },
{ type: OnboardingConstants.SET_ONBOARDING_APPROACH, value: 'physical' },
{ type: OnboardingConstants.SET_ONBOARDING_ARTIFACT_INCLUDED, value: undefined },
{ type: OnboardingConstants.SET_ONBOARDING_ARTIFACT_INCLUDED, value: null },
{ type: OnboardingConstants.SET_SHOW_ONBOARDING_HELP, show: true },
{ type: OnboardingConstants.SET_ONBOARDING_PROGRESS, value: 'application-update-reminder-tip' },
{ type: OnboardingConstants.SET_SHOW_CREATE_ARTIFACT, show: false },
Expand All @@ -210,7 +221,7 @@ describe('onboarding actions', () => {
onboarding: {
address: 'http://192.168.10.141:85',
approach: 'physical',
artifactIncluded: undefined,
artifactIncluded: null,
complete: false,
deviceType: ['raspberrypi4'],
progress: 'application-update-reminder-tip',
Expand Down
Loading

0 comments on commit 729904e

Please sign in to comment.