Extract additional routes in to shared renderer factory

This commit is contained in:
2026-04-09 13:56:17 +01:00
parent c264830934
commit 96946ed205
7 changed files with 293 additions and 88 deletions
+2 -1
View File
@@ -32,7 +32,7 @@ RELAYPATH = "ar-hc-lz-pedw-test-uks-01"
CRMURL = "ts-pedw.crm11.dynamics.com" CRMURL = "ts-pedw.crm11.dynamics.com"
CRMURL_VERSION = "v9.2" CRMURL_VERSION = "v9.2"
# # //New PreProd # //New PreProd
# CLIENT_ID = ab6c4678-b31a-4eb3-b429-e039120e488a # CLIENT_ID = ab6c4678-b31a-4eb3-b429-e039120e488a
# CLIENT_SECRET = VWY8Q~9EtRzGXpd8Xs~5OS1fej2IyVJ8JgTMncw3 # CLIENT_SECRET = VWY8Q~9EtRzGXpd8Xs~5OS1fej2IyVJ8JgTMncw3
# RELAY_ROOT = https://ar-ns-lz-pedw-ppe-uks-01.servicebus.windows.net/ar-hc-lz-pedw-ppe-uks-01/ # RELAY_ROOT = https://ar-ns-lz-pedw-ppe-uks-01.servicebus.windows.net/ar-hc-lz-pedw-ppe-uks-01/
@@ -271,3 +271,4 @@ HIDEERRORLOGS = false
SHOWSIPS = true SHOWSIPS = true
ALLOWED_IPS=::1,203.0.113.42,198.51.100.17 ALLOWED_IPS=::1,203.0.113.42,198.51.100.17
UPLOAD_BATCH_COUNT = 5
+1
View File
@@ -59,3 +59,4 @@ GUARDRAILS.md
ai-prompts/ ai-prompts/
workflows/ workflows/
AI_CONTEXT.md AI_CONTEXT.md
pages/baracuda.min.html
+18 -73
View File
@@ -21,7 +21,8 @@ import {
createSimpleRouteRenderers, createSimpleRouteRenderers,
createSimpleLinkTextPairRenderers, createSimpleLinkTextPairRenderers,
createSimpleMyPortalRouteRenderers, createSimpleMyPortalRouteRenderers,
createCaseDetailRouteRenderers createCaseDetailRouteRenderers,
createDetailAndAccountRouteRenderers
} from "../lib/routing/breadcrumbRendererFactories"; } from "../lib/routing/breadcrumbRendererFactories";
const Breadcrumbs = (props) => { const Breadcrumbs = (props) => {
@@ -259,11 +260,26 @@ const Breadcrumbs = (props) => {
renderMyPortalCrumb renderMyPortalCrumb
}); });
const detailAndAccountRouteRenderersByPath =
createDetailAndAccountRouteRenderers({
t,
router,
isWelsh,
cyMyPortalHref,
currentReference,
caseReferenceDisplay,
renderMyPortalCrumb,
renderLinkCrumb,
renderCaseReferenceCrumb,
renderDnsCaseReferenceCrumbs
});
const mappedRouteRendererMaps = buildBreadcrumbRendererMaps({ const mappedRouteRendererMaps = buildBreadcrumbRendererMaps({
simpleRouteRenderersByPath, simpleRouteRenderersByPath,
simpleLinkTextPairRenderersByPath, simpleLinkTextPairRenderersByPath,
simpleMyPortalRouteRenderersByPath, simpleMyPortalRouteRenderersByPath,
caseDetailRouteRenderersByPath caseDetailRouteRenderersByPath,
detailAndAccountRouteRenderersByPath
}); });
const staticTextCrumbLabel = getStaticTextCrumbLabel(pathname); const staticTextCrumbLabel = getStaticTextCrumbLabel(pathname);
@@ -398,33 +414,6 @@ const Breadcrumbs = (props) => {
</> </>
)} )}
{isPath("/myportal/dnsdetails") && (
<>
{renderMyPortalCrumb()}
{renderLinkCrumb(
"/myportal/dnsapplications",
t("dnsCommon:service-name")
)}
{renderCaseReferenceCrumb(currentReference)}
</>
)}
{isPath("/myportal/dns/[developmentName]") && (
<>
{renderLinkCrumb(
isWelsh
? `${router.locale}/fymhorth`
: "/myportal",
t("common:breadcrumb-my-portal")
)}
{renderLinkCrumb(
"/myportal/dnsapplications",
t("dnsCommon:service-name")
)}
{renderCaseReferenceCrumb(caseReferenceDisplay)}
</>
)}
{isPath("/case") && ( {isPath("/case") && (
<> <>
{renderLinkCrumb( {renderLinkCrumb(
@@ -471,50 +460,6 @@ const Breadcrumbs = (props) => {
</> </>
)} )}
{isPath("/account/personaldetails") && (
<>
{renderLinkCrumb(
cyMyPortalHref,
t("common:breadcrumb-my-portal")
)}
<li className="govuk-breadcrumbs__list-item">
{t("account:account-title")}
</li>
</>
)}
{isPath("/account/changepassword") && (
<>
{renderLinkCrumb(
cyMyPortalHref,
t("common:breadcrumb-my-portal")
)}
<li className="govuk-breadcrumbs__list-item">
Update your password
</li>
</>
)}
{isPath("/dnsdetails") &&
renderDnsCaseReferenceCrumbs(currentReference)}
{isPath("/dns/[developmentName]") &&
renderDnsCaseReferenceCrumbs(caseReferenceDisplay)}
{isPath("/dns/application-view") && (
<>
{renderLinkCrumb(
isWelsh
? `${router.locale}/dns/applications`
: "/dns/applications",
t("dnsApplicationView:page-parent-title")
)}
<li className="govuk-breadcrumbs__list-item">
TWA - Morlais Demonstration Zone
</li>
</>
)}
{staticTextCrumbLabel && {staticTextCrumbLabel &&
renderTextCrumb(staticTextCrumbLabel)} renderTextCrumb(staticTextCrumbLabel)}
</ol> </ol>
@@ -236,3 +236,79 @@ export const createCaseDetailRouteRenderers = ({
); );
} }
}); });
export const createDetailAndAccountRouteRenderers = ({
t,
router,
isWelsh,
cyMyPortalHref,
currentReference,
caseReferenceDisplay,
renderMyPortalCrumb,
renderLinkCrumb,
renderCaseReferenceCrumb,
renderDnsCaseReferenceCrumbs
}) => ({
"/myportal/dnsdetails": () => (
<>
{renderMyPortalCrumb()}
{renderLinkCrumb(
"/myportal/dnsapplications",
t("dnsCommon:service-name")
)}
{renderCaseReferenceCrumb(currentReference)}
</>
),
"/myportal/dns/[developmentName]": () => (
<>
{renderMyPortalCrumb()}
{renderLinkCrumb(
"/myportal/dnsapplications",
t("dnsCommon:service-name")
)}
{renderCaseReferenceCrumb(caseReferenceDisplay)}
</>
),
"/dnsdetails": () => renderDnsCaseReferenceCrumbs(currentReference),
"/dns/[developmentName]": () =>
renderDnsCaseReferenceCrumbs(caseReferenceDisplay),
"/dns/application-view": () => (
<>
{renderLinkCrumb(
isWelsh
? `/${router.locale}/dns/applications`
: "/dns/applications",
t("dnsApplicationView:page-parent-title")
)}
{renderLinkCrumb(
isWelsh
? `/${router.locale}/dnsapplications`
: "/dnsapplications",
t("dnsCommon:service-name")
)}
{renderCaseReferenceCrumb("TWA - Morlais Demonstration Zone")}
</>
),
"/account/personaldetails": () => (
<>
{renderLinkCrumb(cyMyPortalHref, t("common:breadcrumb-my-portal"))}
<li className="govuk-breadcrumbs__list-item">
{t("account:account-title")}
</li>
</>
),
"/account/changepassword": () => (
<>
{renderLinkCrumb(cyMyPortalHref, t("common:breadcrumb-my-portal"))}
<li className="govuk-breadcrumbs__list-item">
Update your password
</li>
</>
)
});
+4 -2
View File
@@ -16,12 +16,14 @@ const buildBreadcrumbRendererMaps = ({
simpleRouteRenderersByPath, simpleRouteRenderersByPath,
simpleLinkTextPairRenderersByPath, simpleLinkTextPairRenderersByPath,
simpleMyPortalRouteRenderersByPath, simpleMyPortalRouteRenderersByPath,
caseDetailRouteRenderersByPath caseDetailRouteRenderersByPath,
detailAndAccountRouteRenderersByPath
}) => [ }) => [
simpleRouteRenderersByPath, simpleRouteRenderersByPath,
simpleLinkTextPairRenderersByPath, simpleLinkTextPairRenderersByPath,
simpleMyPortalRouteRenderersByPath, simpleMyPortalRouteRenderersByPath,
caseDetailRouteRenderersByPath caseDetailRouteRenderersByPath,
detailAndAccountRouteRenderersByPath
]; ];
module.exports = { module.exports = {
@@ -57,15 +57,23 @@ test("buildBreadcrumbRendererMaps returns grouped maps in explicit precedence or
const simpleMyPortalRouteRenderersByPath = { const simpleMyPortalRouteRenderersByPath = {
"/gamma": () => "gamma" "/gamma": () => "gamma"
}; };
const caseDetailRouteRenderersByPath = {
"/delta": () => "delta"
};
const detailAndAccountRouteRenderersByPath = {
"/epsilon": () => "epsilon"
};
const result = buildBreadcrumbRendererMaps({ const result = buildBreadcrumbRendererMaps({
simpleRouteRenderersByPath, simpleRouteRenderersByPath,
simpleLinkTextPairRenderersByPath, simpleLinkTextPairRenderersByPath,
simpleMyPortalRouteRenderersByPath simpleMyPortalRouteRenderersByPath,
caseDetailRouteRenderersByPath,
detailAndAccountRouteRenderersByPath
}); });
assert.ok(Array.isArray(result), "Expected grouped maps array"); assert.ok(Array.isArray(result), "Expected grouped maps array");
assert.strictEqual(result.length, 3, "Expected three grouped route maps"); assert.strictEqual(result.length, 5, "Expected five grouped route maps");
assert.strictEqual( assert.strictEqual(
result[0], result[0],
simpleRouteRenderersByPath, simpleRouteRenderersByPath,
@@ -81,6 +89,16 @@ test("buildBreadcrumbRendererMaps returns grouped maps in explicit precedence or
simpleMyPortalRouteRenderersByPath, simpleMyPortalRouteRenderersByPath,
"Expected my-portal route renderers third" "Expected my-portal route renderers third"
); );
assert.strictEqual(
result[3],
caseDetailRouteRenderersByPath,
"Expected case detail route renderers fourth"
);
assert.strictEqual(
result[4],
detailAndAccountRouteRenderersByPath,
"Expected detail and account route renderers fifth"
);
}); });
test("resolveMappedRouteRenderer returns renderer from first matching grouped map", () => { test("resolveMappedRouteRenderer returns renderer from first matching grouped map", () => {
@@ -97,7 +115,9 @@ test("resolveMappedRouteRenderer returns renderer from first matching grouped ma
simpleLinkTextPairRenderersByPath: { simpleLinkTextPairRenderersByPath: {
"/known": secondRenderer "/known": secondRenderer
}, },
simpleMyPortalRouteRenderersByPath: {} simpleMyPortalRouteRenderersByPath: {},
caseDetailRouteRenderersByPath: {},
detailAndAccountRouteRenderersByPath: {}
}); });
const result = resolveMappedRouteRenderer("/known", maps); const result = resolveMappedRouteRenderer("/known", maps);
@@ -113,21 +133,23 @@ test("resolveMappedRouteRenderer returns renderer from later grouped map when ea
const { buildBreadcrumbRendererMaps, resolveMappedRouteRenderer } = const { buildBreadcrumbRendererMaps, resolveMappedRouteRenderer } =
loadHelpers(); loadHelpers();
const myPortalRenderer = () => "myportal"; const detailRenderer = () => "detail";
const maps = buildBreadcrumbRendererMaps({ const maps = buildBreadcrumbRendererMaps({
simpleRouteRenderersByPath: {}, simpleRouteRenderersByPath: {},
simpleLinkTextPairRenderersByPath: {}, simpleLinkTextPairRenderersByPath: {},
simpleMyPortalRouteRenderersByPath: { simpleMyPortalRouteRenderersByPath: {},
"/myportal/searchresults": myPortalRenderer caseDetailRouteRenderersByPath: {},
detailAndAccountRouteRenderersByPath: {
"/account/personaldetails": detailRenderer
} }
}); });
const result = resolveMappedRouteRenderer("/myportal/searchresults", maps); const result = resolveMappedRouteRenderer("/account/personaldetails", maps);
assert.strictEqual( assert.strictEqual(
result, result,
myPortalRenderer, detailRenderer,
"Expected resolver to return matching renderer from later grouped map" "Expected resolver to return matching renderer from later grouped map"
); );
}); });
@@ -141,7 +163,9 @@ test("resolveMappedRouteRenderer returns null for unmapped path", () => {
"/known": () => "known" "/known": () => "known"
}, },
simpleLinkTextPairRenderersByPath: {}, simpleLinkTextPairRenderersByPath: {},
simpleMyPortalRouteRenderersByPath: {} simpleMyPortalRouteRenderersByPath: {},
caseDetailRouteRenderersByPath: {},
detailAndAccountRouteRenderersByPath: {}
}); });
const result = resolveMappedRouteRenderer("/unknown", maps); const result = resolveMappedRouteRenderer("/unknown", maps);
@@ -36,6 +36,18 @@ test("breadcrumbs/factory module includes expected mapped route definitions", as
"Expected my-portal route renderer factory export" "Expected my-portal route renderer factory export"
); );
assert.strictEqual(
source.includes("export const createCaseDetailRouteRenderers ="),
true,
"Expected case detail route renderer factory export"
);
assert.strictEqual(
source.includes("export const createDetailAndAccountRouteRenderers ="),
true,
"Expected detail and account route renderer factory export"
);
assert.strictEqual( assert.strictEqual(
source.includes('"/addresssearchresults": () => ('), source.includes('"/addresssearchresults": () => ('),
true, true,
@@ -71,6 +83,60 @@ test("breadcrumbs/factory module includes expected mapped route definitions", as
true, true,
"Expected /myportal/addresssearchresults to be mapped in createSimpleMyPortalRouteRenderers" "Expected /myportal/addresssearchresults to be mapped in createSimpleMyPortalRouteRenderers"
); );
assert.strictEqual(
source.includes('"/case/[ticketnumber]": () =>'),
true,
"Expected /case/[ticketnumber] to be mapped in createCaseDetailRouteRenderers"
);
assert.strictEqual(
source.includes('"/myportal/case/[ticketnumber]": () =>'),
true,
"Expected /myportal/case/[ticketnumber] to be mapped in createCaseDetailRouteRenderers"
);
assert.strictEqual(
source.includes('"/myportal/dnsdetails": () =>'),
true,
"Expected /myportal/dnsdetails to be mapped in createDetailAndAccountRouteRenderers"
);
assert.strictEqual(
source.includes('"/myportal/dns/[developmentName]": () =>'),
true,
"Expected /myportal/dns/[developmentName] to be mapped in createDetailAndAccountRouteRenderers"
);
assert.strictEqual(
source.includes('"/dnsdetails": () =>'),
true,
"Expected /dnsdetails to be mapped in createDetailAndAccountRouteRenderers"
);
assert.strictEqual(
source.includes('"/dns/[developmentName]": () =>'),
true,
"Expected /dns/[developmentName] to be mapped in createDetailAndAccountRouteRenderers"
);
assert.strictEqual(
source.includes('"/dns/application-view": () =>'),
true,
"Expected /dns/application-view to be mapped in createDetailAndAccountRouteRenderers"
);
assert.strictEqual(
source.includes('"/account/personaldetails": () =>'),
true,
"Expected /account/personaldetails to be mapped in createDetailAndAccountRouteRenderers"
);
assert.strictEqual(
source.includes('"/account/changepassword": () =>'),
true,
"Expected /account/changepassword to be mapped in createDetailAndAccountRouteRenderers"
);
}); });
test("breadcrumbs/component composes mapped routes via imported factories and shared resolver", async () => { test("breadcrumbs/component composes mapped routes via imported factories and shared resolver", async () => {
@@ -106,6 +172,18 @@ test("breadcrumbs/component composes mapped routes via imported factories and sh
"Expected breadcrumbs to reference createSimpleMyPortalRouteRenderers" "Expected breadcrumbs to reference createSimpleMyPortalRouteRenderers"
); );
assert.strictEqual(
/createCaseDetailRouteRenderers/.test(source),
true,
"Expected breadcrumbs to reference createCaseDetailRouteRenderers"
);
assert.strictEqual(
/createDetailAndAccountRouteRenderers/.test(source),
true,
"Expected breadcrumbs to reference createDetailAndAccountRouteRenderers"
);
assert.strictEqual( assert.strictEqual(
/const\s+simpleRouteRenderersByPath\s*=\s*createSimpleRouteRenderers\s*\(/.test( /const\s+simpleRouteRenderersByPath\s*=\s*createSimpleRouteRenderers\s*\(/.test(
source source
@@ -130,6 +208,22 @@ test("breadcrumbs/component composes mapped routes via imported factories and sh
"Expected breadcrumbs to build my-portal route renderers from factory" "Expected breadcrumbs to build my-portal route renderers from factory"
); );
assert.strictEqual(
/const\s+caseDetailRouteRenderersByPath\s*=\s*createCaseDetailRouteRenderers\s*\(/.test(
source
),
true,
"Expected breadcrumbs to build case detail route renderers from factory"
);
assert.strictEqual(
/const\s+detailAndAccountRouteRenderersByPath\s*=\s*createDetailAndAccountRouteRenderers\s*\(/.test(
source
),
true,
"Expected breadcrumbs to build detail and account route renderers from factory"
);
assert.strictEqual( assert.strictEqual(
/const\s+mappedRouteRendererMaps\s*=\s*buildBreadcrumbRendererMaps\s*\(/.test( /const\s+mappedRouteRendererMaps\s*=\s*buildBreadcrumbRendererMaps\s*\(/.test(
source source
@@ -179,6 +273,60 @@ test("breadcrumbs/component composes mapped routes via imported factories and sh
false, false,
"Expected /myportal/addresssearchresults explicit branch to be removed after mapping" "Expected /myportal/addresssearchresults explicit branch to be removed after mapping"
); );
assert.strictEqual(
source.includes('isPath("/case/[ticketnumber]")'),
false,
"Expected /case/[ticketnumber] explicit branch to be removed after mapping"
);
assert.strictEqual(
source.includes('isPath("/myportal/case/[ticketnumber]")'),
false,
"Expected /myportal/case/[ticketnumber] explicit branch to be removed after mapping"
);
assert.strictEqual(
source.includes('isPath("/myportal/dnsdetails")'),
false,
"Expected /myportal/dnsdetails explicit branch to be removed after mapping"
);
assert.strictEqual(
source.includes('isPath("/myportal/dns/[developmentName]")'),
false,
"Expected /myportal/dns/[developmentName] explicit branch to be removed after mapping"
);
assert.strictEqual(
source.includes('isPath("/dnsdetails")'),
false,
"Expected /dnsdetails explicit branch to be removed after mapping"
);
assert.strictEqual(
source.includes('isPath("/dns/[developmentName]")'),
false,
"Expected /dns/[developmentName] explicit branch to be removed after mapping"
);
assert.strictEqual(
source.includes('isPath("/dns/application-view")'),
false,
"Expected /dns/application-view explicit branch to be removed after mapping"
);
assert.strictEqual(
source.includes('isPath("/account/personaldetails")'),
false,
"Expected /account/personaldetails explicit branch to be removed after mapping"
);
assert.strictEqual(
source.includes('isPath("/account/changepassword")'),
false,
"Expected /account/changepassword explicit branch to be removed after mapping"
);
}); });
test("breadcrumbs/map builder preserves route map ordering", async () => { test("breadcrumbs/map builder preserves route map ordering", async () => {
@@ -196,7 +344,7 @@ test("breadcrumbs/map builder preserves route map ordering", async () => {
const mapBuilderSlice = source.slice( const mapBuilderSlice = source.slice(
mapBuilderCallIndex, mapBuilderCallIndex,
mapBuilderCallIndex + 500 mapBuilderCallIndex + 700
); );
const simpleRouteOrderIndex = mapBuilderSlice.indexOf( const simpleRouteOrderIndex = mapBuilderSlice.indexOf(
@@ -208,13 +356,21 @@ test("breadcrumbs/map builder preserves route map ordering", async () => {
const simpleMyPortalOrderIndex = mapBuilderSlice.indexOf( const simpleMyPortalOrderIndex = mapBuilderSlice.indexOf(
"simpleMyPortalRouteRenderersByPath" "simpleMyPortalRouteRenderersByPath"
); );
const caseDetailOrderIndex = mapBuilderSlice.indexOf(
"caseDetailRouteRenderersByPath"
);
const detailAndAccountOrderIndex = mapBuilderSlice.indexOf(
"detailAndAccountRouteRenderersByPath"
);
assert.strictEqual( assert.strictEqual(
simpleRouteOrderIndex >= 0 && simpleRouteOrderIndex >= 0 &&
simpleLinkTextPairOrderIndex > simpleRouteOrderIndex && simpleLinkTextPairOrderIndex > simpleRouteOrderIndex &&
simpleMyPortalOrderIndex > simpleLinkTextPairOrderIndex, simpleMyPortalOrderIndex > simpleLinkTextPairOrderIndex &&
caseDetailOrderIndex > simpleMyPortalOrderIndex &&
detailAndAccountOrderIndex > caseDetailOrderIndex,
true, true,
"Expected map builder call to preserve explicit route-map ordering (simple -> link-text -> myportal)" "Expected map builder call to preserve explicit route-map ordering (simple -> link-text -> myportal -> case detail -> detail/account)"
); );
}); });