Skip to content

Commit

Permalink
fix: fill missing varTypes in parameter values when receiving scenarios
Browse files Browse the repository at this point in the history
Note that this commit changes the order of calls when opening a
workspace: the solution is now fetched before fetching the scenarios
  • Loading branch information
csm-thu committed Feb 16, 2024
1 parent aaa8c19 commit e08995b
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@ import { SCENARIO_ACTIONS_KEY } from '../../../commons/ScenarioConstants';
const getUserEmail = (state) => state.auth.userEmail;
const getUserId = (state) => state.auth.userId;
const getScenariosPermissionsMapping = (state) => state.application.permissionsMapping.scenario;
const getSolutionParameters = (state) => state.solution?.current?.data?.parameters;

const keepOnlyReadableScenarios = (scenarios) =>
scenarios.filter((scenario) => scenario.security.currentUserPermissions.includes(ACL_PERMISSIONS.SCENARIO.READ));

// generators function
export function* getAllScenariosData(organizationId, workspaceId) {
// yield keyword is here to milestone and save the action
const userEmail = yield select(getUserEmail);
const userId = yield select(getUserId);
const scenariosPermissionsMapping = yield select(getScenariosPermissionsMapping);
const solutionParameters = yield select(getSolutionParameters);
const { data } = yield call(Api.Scenarios.findAllScenarios, organizationId, workspaceId);

data.forEach((scenario) =>
ScenariosUtils.patchScenarioParameterValues(solutionParameters, scenario.parametersValues)
);
data.forEach((scenario) => (scenario.parametersValues = ApiUtils.formatParametersFromApi(scenario.parametersValues)));
data.forEach((scenario) =>
ScenariosUtils.patchScenarioWithCurrentUserPermissions(scenario, userEmail, userId, scenariosPermissionsMapping)
Expand All @@ -34,8 +37,6 @@ export function* getAllScenariosData(organizationId, workspaceId) {
});
}

// generators function
// Here is a watcher that takes EVERY action dispatched named GET_ALL_SCENARIOS and binds getAllScenariosData saga to it
function* findAllScenariosData() {
yield takeEvery(SCENARIO_ACTIONS_KEY.GET_ALL_SCENARIOS, getAllScenariosData);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import { dispatchSetApplicationErrorMessage } from '../../../dispatchers/app/App
const getUserEmail = (state) => state.auth.userEmail;
const getUserId = (state) => state.auth.userId;
const getScenariosPermissionsMapping = (state) => state.application.permissionsMapping.scenario;
const getSolutionParameters = (state) => state.solution?.current?.data?.parameters;

export function* fetchScenarioByIdData(action) {
try {
const userEmail = yield select(getUserEmail);
const userId = yield select(getUserId);
const scenariosPermissionsMapping = yield select(getScenariosPermissionsMapping);
const solutionParameters = yield select(getSolutionParameters);

yield put({
type: SCENARIO_ACTIONS_KEY.SET_CURRENT_SCENARIO,
status: STATUSES.LOADING,
Expand All @@ -30,6 +33,7 @@ export function* fetchScenarioByIdData(action) {
action.workspaceId,
action.scenarioId
);
ScenariosUtils.patchScenarioParameterValues(solutionParameters, data.parametersValues);
data.parametersValues = ApiUtils.formatParametersFromApi(data.parametersValues);

ScenariosUtils.patchScenarioWithCurrentUserPermissions(data, userEmail, userId, scenariosPermissionsMapping);
Expand Down
3 changes: 2 additions & 1 deletion src/state/sagas/workspace/SelectWorkspace/SelectWorkspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,10 @@ export function* selectWorkspace(action) {

yield put({ type: POWER_BI_ACTIONS_KEY.CLEAR_EMBED_INFO });

yield call(getAllScenariosData, organizationId, selectedWorkspaceId);
const solutionId = yield select(selectSolutionIdFromCurrentWorkspace);
yield call(fetchSolutionByIdData, organizationId, solutionId);

yield call(getAllScenariosData, organizationId, selectedWorkspaceId);
const scenarioList = yield select(selectScenarioList);

yield put({
Expand Down
15 changes: 15 additions & 0 deletions src/utils/ScenariosUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ const _getUserPermissionsForScenario = (scenario, userEmail, userId, permissions
return SecurityUtils.getUserPermissionsForResource(scenario.security, userEmail, permissionsMapping);
};

const patchScenarioParameterValues = (solutionParameters, parameterValues) => {
if (!Array.isArray(parameterValues) || !Array.isArray(solutionParameters)) return;

parameterValues.forEach((value) => {
if (value.varType != null || value.parameterId == null) return;

const parameterDefinition = solutionParameters.find(
(solutionParameter) => solutionParameter.id === value.parameterId
);
if (parameterDefinition) value.varType = parameterDefinition.varType;
else console.warn(`Unknown parameter value ${value.parameterId} without any varType found in scenario data`);
});
};

const patchScenarioWithCurrentUserPermissions = (scenario, userEmail, userId, permissionsMapping) => {
// scenario.security seems to be read-only, we have to create a new object to add a "currentUserPermissions" key
scenario.security = {
Expand All @@ -19,5 +33,6 @@ const patchScenarioWithCurrentUserPermissions = (scenario, userEmail, userId, pe
};

export const ScenariosUtils = {
patchScenarioParameterValues,
patchScenarioWithCurrentUserPermissions,
};
63 changes: 63 additions & 0 deletions src/utils/__test__/ScenariosUtils.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) Cosmo Tech.
// Licensed under the MIT license.
import { ScenariosUtils } from '../ScenariosUtils';

describe('patchScenarioParameterValues', () => {
test.each`
solutionParameters | parameterValues
${undefined} | ${undefined}
${undefined} | ${null}
${undefined} | ${[]}
${undefined} | ${0}
${undefined} | ${false}
${undefined} | ${''}
${undefined} | ${'foo'}
${null} | ${undefined}
${null} | ${null}
${null} | ${[]}
${null} | ${0}
${null} | ${false}
${null} | ${''}
${null} | ${'foo'}
${[]} | ${undefined}
${[]} | ${null}
${[]} | ${[]}
${[]} | ${0}
${[]} | ${false}
${[]} | ${''}
${[]} | ${'foo'}
`(
'should do nothing without error when arguments are nullish or not arrays',
({ solutionParameters, parameterValues }) => {
expect(() => ScenariosUtils.patchScenarioParameterValues(solutionParameters, parameterValues)).not.toThrow();
}
);

test('should fill missing varTypes based on solution description', () => {
const spyConsoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {});

const solutionParameters = [
{ id: 'p0', varType: 'bool' },
{ id: 'p1', varType: 'date' },
{ id: 'p3', varType: 'string' },
];
const parameterValues = [
{ parameterId: 'p0', value: 'p0' },
{ parameterId: 'p1', varType: null, value: 'p1' },
{ parameterId: 'p2', varType: null, value: 'p2' },
{ parameterId: 'p3', varType: 'string', value: 'p3' },
];
const expectedParameterValues = [
{ parameterId: 'p0', varType: 'bool', value: 'p0' },
{ parameterId: 'p1', varType: 'date', value: 'p1' },
{ parameterId: 'p2', varType: null, value: 'p2' }, // Not defined in solution
{ parameterId: 'p3', varType: 'string', value: 'p3' },
];

ScenariosUtils.patchScenarioParameterValues(solutionParameters, parameterValues);
expect(parameterValues).toStrictEqual(expectedParameterValues);
expect(spyConsoleWarn).toHaveBeenCalledTimes(1);

spyConsoleWarn.mockClear();
});
});

0 comments on commit e08995b

Please sign in to comment.