Skip to content

Commit

Permalink
Merge pull request #2476 from govuk-one-login/pyic-7304
Browse files Browse the repository at this point in the history
PYIC-7304: add journeyContext visualisation
  • Loading branch information
thebauSoftwire authored Sep 24, 2024
2 parents 609b9f6 + a4f0b40 commit 2a6b35b
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 140 deletions.
121 changes: 121 additions & 0 deletions journey-map/public/helpers.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const addDefinitionOptions = (definition, disabledOptions, featureFlagOptions) => {
Object.entries(definition.checkIfDisabled || {}).forEach(([opt, def]) => {
if (!disabledOptions.includes(opt)) {
disabledOptions.push(opt);
}
addDefinitionOptions(def, disabledOptions, featureFlagOptions);
});
Object.entries(definition.checkFeatureFlag || {}).forEach(([opt, def]) => {
if (!featureFlagOptions.includes(opt)) {
featureFlagOptions.push(opt);
}
addDefinitionOptions(def, disabledOptions, featureFlagOptions);
});
};

// Traverse the journey map to collect the available 'disabled' and 'featureFlag' options
export const getOptions = (journeyMaps, nestedJourneys) => {
const disabledOptions = ['ticf'];
const featureFlagOptions = [];

const states = [
...Object.values(journeyMaps)
.flatMap(journeyMap => Object.values(journeyMap.states)),
...Object.values(nestedJourneys)
.flatMap(nestedJourney => Object.values(nestedJourney.nestedJourneyStates)),
];

states.forEach((definition) => {
const events = definition.events || definition.exitEvents || {};
Object.values(events).forEach((def) => {
addDefinitionOptions(def, disabledOptions, featureFlagOptions);
});
});

Object.values(nestedJourneys).forEach(nestedJourney => {
Object.values(nestedJourney.entryEvents).forEach((def) => {
addDefinitionOptions(def, disabledOptions, featureFlagOptions);
});
});

disabledOptions.sort();
featureFlagOptions.sort();

return { disabledOptions, featureFlagOptions };
};

export const resolveEventTargets = (definition, formData, resolvedEventTargets) => {
const resolvedTargets = resolvedEventTargets || [];

// Look for an override for disabled CRIs
const disabledCris = formData.getAll('disabledCri');
const disabledResolution = Object.keys(definition.checkIfDisabled || {}).find((k) => disabledCris.includes(k));
if (disabledResolution) {
return resolveEventTargets(
{...definition.checkIfDisabled[disabledResolution], journeyContext: definition.journeyContext},
formData,
resolvedTargets);
}

Object.keys(definition.checkJourneyContext || {}).forEach(journeyContext => {
const targets = resolveEventTargets(
{...definition.checkJourneyContext[journeyContext], journeyContext: journeyContext},
formData)
resolvedTargets.push(...targets);
})

// Look for an override for feature flags
const featureFlags = formData.getAll('featureFlag');
const featureFlagResolution = Object.keys(definition.checkFeatureFlag || {}).find((k) => featureFlags.includes(k));
if (featureFlagResolution) {
return resolveEventTargets(
{...definition.checkFeatureFlag[featureFlagResolution], journeyContext: definition.journeyContext},
formData,
resolvedTargets);
}

return [...resolvedTargets, definition];
}

const addJourneyContextFromDefinition = (definition, journeyContexts) => {
Object.entries(definition.checkIfDisabled || {}).forEach(([_, def]) => {
addJourneyContextFromDefinition(def, journeyContexts);
})

Object.entries(definition.checkJourneyContext || {}).forEach(([ctx, def]) => {
if (!journeyContexts.includes(ctx)) {
journeyContexts.push(ctx);
}
addJourneyContextFromDefinition(def, journeyContexts);
})

Object.entries(definition.checkFeatureFlag || {}).forEach(([_, def]) => {
addJourneyContextFromDefinition(def, journeyContexts);
})
}

export const getJourneyContexts = (journeyStates) => {
const checkedJourneyContexts = [];
Object.values(journeyStates).forEach((definition) => {
const events = definition.events || definition.exitEvents || {};
Object.values(events).forEach((def) => {
addJourneyContextFromDefinition(def, checkedJourneyContexts);
});
});
return checkedJourneyContexts;
}

export const getNestedJourneyStates = (nestedJourney) => ({
...nestedJourney.nestedJourneyStates,
// Create an entry state for each entry event
...Object.fromEntries(
Object.entries(nestedJourney.entryEvents)
.map(([event, def]) => [
`entry_${event}`.toUpperCase(),
{
entryEvent: event,
events: { [event]: def }
}
]),
),
});
1 change: 1 addition & 0 deletions journey-map/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ <h2>Options</h2>
<div id="nodeInfo">
<h2 id="journeyName"></h2>
<p id="journeyDesc"></p>
<div id="journeyContextsList"></div>
<hr />
<h3 id="nodeTitle"></h3>
<pre id="nodeDef"></pre>
Expand Down
33 changes: 30 additions & 3 deletions journey-map/public/index.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
import svgPanZoom from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
import yaml from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
import { getOptions, render } from './render.mjs';
import { render } from './render.mjs';
import { getJourneyContexts, getNestedJourneyStates, getOptions } from "./helpers.mjs";

const DEFAULT_JOURNEY_TYPE = 'INITIAL_JOURNEY_SELECTION';
const NESTED_JOURNEY_TYPE_SEARCH_PARAM = 'nestedJourneyType';
Expand Down Expand Up @@ -208,6 +209,26 @@ const setupOtherOptions = () => {
}
}

const displayJourneyContextInfo = (ctxOptions) => {
journeyContextsList.innerText = '';
const ctxHeader = document.createElement('h3');
ctxHeader.innerText = "Journey Contexts"
journeyContextsList.append(ctxHeader);

const ctxDesc = document.createElement('p');
ctxDesc.innerText = "This journey checks for the following contexts:"
journeyContextsList.append(ctxDesc);

const list = document.createElement('ul');
list.setAttribute("class", "journeyCtxList")
journeyContextsList.append(list);
ctxOptions.forEach(ctx => {
const bulletPoint = document.createElement('li');
bulletPoint.innerText = ctx;
list.append(bulletPoint)
});
}

const updateView = async () => {
const formData = new FormData(form);
const selectedNestedJourney = new URLSearchParams(window.location.search).get(NESTED_JOURNEY_TYPE_SEARCH_PARAM);
Expand All @@ -219,14 +240,20 @@ const updateView = async () => {
journeyDesc.innerText = nestedJourneys[selectedNestedJourney].description;
} else {
journeyName.innerText = journeyMaps[selectedJourney].name || 'Details';

const desc = journeyMaps[selectedJourney].description;

journeySelect.value = selectedJourney;
journeyDesc.innerText = desc || '';
}

return renderSvg(selectedJourney, selectedNestedJourney, formData);
const ctxOptions = getJourneyContexts(selectedNestedJourney ? getNestedJourneyStates(nestedJourneys[selectedNestedJourney]) : journeyMaps[selectedJourney].states);
if (ctxOptions.length > 0) {
displayJourneyContextInfo(ctxOptions);
} else {
journeyContextsList.innerText = '';
}

await renderSvg(selectedJourney, selectedNestedJourney, formData);
};

// Render the journey map SVG
Expand Down
Loading

0 comments on commit 2a6b35b

Please sign in to comment.