fleet/frontend/pages/SoftwarePage/components/PackageForm/helpers.ts
RachelElysia 1c1ebef4ef
20404: Edit packages feature (#21812)
## Issue
Cerra #20404

## Description
- Add frontend/API backend for editing software packages. GitOps will be
a separate PR.

## More
- Please see subtasks for change lists
  - #21611 
  - #21613

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files)
for more information.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [x] Manual QA for all new/changed functionality

Automated tests will follow in another PR.

---------

Co-authored-by: Ian Littman <iansltx@gmail.com>
Co-authored-by: Luke Heath <luke@fleetdm.com>
Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
Co-authored-by: Victor Lyuboslavsky <victor.lyuboslavsky@gmail.com>
2024-09-17 08:40:47 -05:00

99 lines
2.5 KiB
TypeScript

// @ts-ignore
import validateQuery from "components/forms/validators/validate_query";
import { IPackageFormData, IFormValidation } from "./PackageForm";
type IPackageFormValidatorKey = Exclude<
keyof IPackageFormData,
"installScript" | "uninstallScript"
>;
type IMessageFunc = (formData: IPackageFormData) => string;
type IValidationMessage = string | IMessageFunc;
interface IValidation {
name: string;
isValid: (formData: IPackageFormData) => boolean;
message?: IValidationMessage;
}
/** configuration defines validations for each filed in the form. It defines rules
* to determine if a field is valid, and rules for generating an error message.
*/
const FORM_VALIDATION_CONFIG: Record<
IPackageFormValidatorKey,
{ validations: IValidation[] }
> = {
software: {
validations: [
{
name: "required",
isValid: (formData) => formData.software !== null,
},
],
},
preInstallQuery: {
validations: [
{
name: "invalidQuery",
isValid: (formData) => {
const query = formData.preInstallQuery;
return (
query === undefined || query === "" || validateQuery(query).valid
);
},
message: (formData) => validateQuery(formData.preInstallQuery).error,
},
],
},
postInstallScript: {
// no validations related to postInstallScript
validations: [],
},
selfService: {
// no validations related to self service
validations: [],
},
};
const getErrorMessage = (
formData: IPackageFormData,
message?: IValidationMessage
) => {
if (message === undefined || typeof message === "string") {
return message;
}
return message(formData);
};
export const generateFormValidation = (formData: IPackageFormData) => {
const formValidation: IFormValidation = {
isValid: true,
software: {
isValid: false,
},
};
Object.keys(FORM_VALIDATION_CONFIG).forEach((key) => {
const objKey = key as keyof typeof FORM_VALIDATION_CONFIG;
const failedValidation = FORM_VALIDATION_CONFIG[objKey].validations.find(
(validation) => !validation.isValid(formData)
);
if (!failedValidation) {
formValidation[objKey] = {
isValid: true,
};
} else {
formValidation.isValid = false;
formValidation[objKey] = {
isValid: false,
message: getErrorMessage(formData, failedValidation.message),
};
}
});
return formValidation;
};
export default generateFormValidation;