-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add ODP Schema validation example for FileTypes to publish checks #3373
Changes from all commits
22e027d
510c879
126b7eb
bea485c
f0a1e4f
29e1704
a64b9fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import { getValidSchemaValues } from "@opensystemslab/planx-core"; | ||
import { | ||
ComponentType, | ||
Edges, | ||
|
@@ -6,6 +7,7 @@ | |
} from "@opensystemslab/planx-core/types"; | ||
import * as jsondiffpatch from "jsondiffpatch"; | ||
import intersection from "lodash/intersection"; | ||
import countBy from "lodash/countBy"; | ||
|
||
import { dataMerged, getMostRecentPublishedFlow } from "../../../helpers"; | ||
import { | ||
|
@@ -23,7 +25,7 @@ | |
|
||
type ValidationResponse = { | ||
title: string; | ||
status: "Pass" | "Fail" | "Not applicable"; | ||
status: "Pass" | "Fail" | "Warn" | "Not applicable"; | ||
message: string; | ||
}; | ||
|
||
|
@@ -55,16 +57,20 @@ | |
const validationChecks = []; | ||
const sections = validateSections(flattenedFlow); | ||
const inviteToPay = validateInviteToPay(flattenedFlow); | ||
validationChecks.push(sections, inviteToPay); | ||
const fileTypes = validateFileTypes(flattenedFlow); | ||
validationChecks.push(sections, inviteToPay, fileTypes); | ||
|
||
// Sort validation checks by status: Fail, Pass, Not applicable | ||
const applicableChecks = validationChecks | ||
.filter((v) => v.status !== "Not applicable") | ||
.sort((a, b) => a.status.localeCompare(b.status)); | ||
// Arrange list of validation checks in order of status: Fail, Warn, Pass, Not applicable | ||
const failingChecks = validationChecks.filter((v) => v.status == "Fail"); | ||
const warningChecks = validationChecks.filter((v) => v.status === "Warn"); | ||
const passingChecks = validationChecks.filter((v) => v.status === "Pass"); | ||
const notApplicableChecks = validationChecks.filter( | ||
(v) => v.status === "Not applicable", | ||
); | ||
const sortedValidationChecks = applicableChecks.concat(notApplicableChecks); | ||
const sortedValidationChecks = failingChecks | ||
.concat(warningChecks) | ||
.concat(passingChecks) | ||
.concat(notApplicableChecks); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Anyone have a more clever suggestion for how to sort in a custom order by "status" ? This is explicit and easy-to-read, but a bit lengthy and I feel like there's probably some cool one-liner I'm missing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I can think of a few ways!
I think it would then just be If we hit browser compatibility issues here we could import Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah just realised we're in the API here on Node 18 - I don't think Lodash or |
||
|
||
return { | ||
alteredNodes, | ||
|
@@ -193,9 +199,8 @@ | |
}; | ||
|
||
const inviteToPayEnabled = (flowGraph: FlowGraph): boolean => { | ||
const payNodes = Object.entries(flowGraph).filter( | ||
(entry): entry is [string, Node] => | ||
isComponentType(entry, ComponentType.Pay), | ||
const payNodes = Object.entries(flowGraph).filter((entry) => | ||
isComponentType(entry, ComponentType.Pay), | ||
); | ||
const payNodeStatuses = payNodes.map( | ||
([_nodeId, node]) => node?.data?.allowInviteToPay, | ||
|
@@ -206,4 +211,68 @@ | |
); | ||
}; | ||
|
||
const validateFileTypes = (flowGraph: FlowGraph): ValidationResponse => { | ||
// Get all passport variables set by FileUpload and/or FileUploadAndLabel | ||
const allFileFns = [ | ||
...getFileUploadNodeFns(flowGraph), | ||
...getFileUploadAndLabelNodeFns(flowGraph), | ||
]; | ||
if (allFileFns.length < 1) { | ||
return { | ||
title: "File types", | ||
status: "Not applicable", | ||
message: "Your flow is not using FileUpload or UploadAndLabel", | ||
}; | ||
} | ||
|
||
// Get all file types supported by current release of ODP Schema & compare | ||
const validFileTypes = getValidSchemaValues("FileType"); | ||
const invalidFileFns: string[] = []; | ||
allFileFns.forEach((fn) => { | ||
if (!validFileTypes?.includes(fn)) { | ||
invalidFileFns.push(fn); | ||
} | ||
}); | ||
if (invalidFileFns.length > 0) { | ||
// Get unique fns with count of occurances | ||
const countInvalidFileFns = countBy(invalidFileFns); | ||
const summarisedInvalidFileFns: string[] = []; | ||
Object.entries(countInvalidFileFns).map(([k, v]: [string, number]) => { | ||
summarisedInvalidFileFns.push(`${k} (${v})`); | ||
}); | ||
return { | ||
title: "File types", | ||
status: "Warn", | ||
message: `Your FileUpload or UploadAndLabel are setting data fields that are not supported by the current release of the ODP Schema: ${summarisedInvalidFileFns.join(", ")}`, | ||
}; | ||
} | ||
|
||
return { | ||
title: "File types", | ||
status: "Pass", | ||
message: | ||
"Files collected via FileUpload or UploadAndLabel are all supported by the ODP Schema", | ||
}; | ||
}; | ||
|
||
const getFileUploadNodeFns = (flowGraph: FlowGraph): string[] => { | ||
const fileUploadNodes = Object.entries(flowGraph).filter((entry) => | ||
isComponentType(entry, ComponentType.FileUpload), | ||
); | ||
return fileUploadNodes.map(([_nodeId, node]) => node.data?.fn as string); | ||
}; | ||
|
||
const getFileUploadAndLabelNodeFns = (flowGraph: FlowGraph): string[] => { | ||
// Exclude Upload & Label nodes used in "info-only" mode with a hidden dropzone | ||
const uploadAndLabelNodes = Object.entries(flowGraph).filter( | ||
(entry) => | ||
isComponentType(entry, ComponentType.FileUploadAndLabel) && | ||
entry[1].data?.hideDropZone !== true, | ||
); | ||
const uploadAndLabelFileTypes = uploadAndLabelNodes | ||
.map(([_nodeId, node]: [string, Node]) => node.data?.fileTypes) | ||
.flat(); | ||
return uploadAndLabelFileTypes?.map((file: any) => file?.fn as string); | ||
jessicamcinchak marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
export { validateAndDiffFlow }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was expecting to see this change also picked up in
docs.yaml
, but it looks like we've missed adding in thevalidationChecks
property.Happy for this to be picked up here, or in a follow up PR 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for spotting this, Swagger docs now updated ✅