Skip to content

Commit

Permalink
Merge pull request #81 from Jank1310/80-support-or-optional-validatio…
Browse files Browse the repository at this point in the history
…n-for-enums

80 support or optional validation for enums
  • Loading branch information
Flofie committed Feb 26, 2024
2 parents 43d369a + f8f785d commit 0f78042
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 150 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[*]
quote_type = double
indent_size = 4
indent_size = 2
indent_style = space
max_line_length = 120
59 changes: 29 additions & 30 deletions app/src/app/[locale]/importer/[id]/validate/cells/SelectCell.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
Select,
SelectContent,
SelectItem,
SelectSeparator,
} from "@/components/ui/select";
import { Select, SelectContent, SelectItem, SelectSeparator } from "@/components/ui/select";
import { useFrontendFetchWithAuth } from "@/lib/frontendFetch";
import { cn } from "@/lib/utils";
import * as SelectPrimitive from "@radix-ui/react-select";
Expand All @@ -30,10 +25,7 @@ const SelectCellTrigger = React.forwardRef<
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex w-full items-center justify-between text-sm",
className
)}
className={cn("flex w-full items-center justify-between text-sm", className)}
{...props}
>
<span>{children}</span>
Expand Down Expand Up @@ -64,6 +56,8 @@ const SelectCell = ({
React.useEffect(() => {
setValue(initialValue);
}, [initialValue]);
const normalizedString = (value as string) ?? "";
const isValueEmpty = normalizedString === "";

const handleDialogSave = async (value: string) => {
if (!value) {
Expand All @@ -73,17 +67,14 @@ const SelectCell = ({
// use settimeout to get a snappier experience
setTimeout(() => onChange(value));
setValue(value);
await frontendFetch(
`/api/importer/${importerId}/columnConfig/${configKey}/validations`,
{
method: "PATCH",
body: JSON.stringify({
type: "enum",
await frontendFetch(`/api/importer/${importerId}/columnConfig/${configKey}/validations`, {
method: "PATCH",
body: JSON.stringify({
type: "enum",

values: [...new Set([...availableValues, value])],
}),
}
);
values: [...new Set([...availableValues, value])],
}),
});
onReloadConfig();
setDialogOpen(false);
};
Expand All @@ -92,27 +83,35 @@ const SelectCell = ({
<>
<Select
disabled={isReadOnly}
value={(value as string) ?? ""}
value={normalizedString === "" ? "none" : normalizedString}
onValueChange={(newValue) => {
if (value !== newValue) {
if (newValue === "$$new") {
const normalizedNewValue = newValue === "none" ? "" : newValue;
if (value !== normalizedNewValue) {
if (normalizedNewValue === "$$new") {
setDialogOpen(true);
return;
}
// use settimeout to get a snappier experience
setTimeout(() => onChange(newValue));
setTimeout(() => onChange(normalizedNewValue));
}
setValue(newValue);
}}
>
<SelectCellTrigger className="">{value}</SelectCellTrigger>
<SelectCellTrigger
className={cn({
"text-gray-400": isValueEmpty,
})}
>
{isValueEmpty ? t("validation.none") : value}
</SelectCellTrigger>
<SelectContent>
{!isRequired && <SelectItem value={"none"}>None</SelectItem>}
{!isRequired && (
<SelectItem className="text-gray-400" value={"none"}>
{t("validation.none")}
</SelectItem>
)}
{availableValues.map((selectableValue) => (
<SelectItem
value={selectableValue}
key={`enum-value-${id}-${selectableValue}`}
>
<SelectItem value={selectableValue} key={`enum-value-${id}-${selectableValue}`}>
{selectableValue}
</SelectItem>
))}
Expand Down
9 changes: 9 additions & 0 deletions app/src/app/api/importer/[slug]/ImporterDto.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CountryCode } from "libphonenumber-js";

export interface ImporterDto {
importerId: string;
config: ImporterConfig;
Expand Down Expand Up @@ -74,14 +76,21 @@ export interface ColumnValidation {
}

export interface RegexColumnValidation extends ColumnValidation {
type: "regex";
regex: string;
}

export interface EnumerationColumnValidation extends ColumnValidation {
type: "enum";
values: string[];
canAddNewValues?: boolean;
}

export interface PhoneColumnValidation extends ColumnValidation {
type: "phone";
defaultCountry?: CountryCode;
}

export interface DataMapping {
targetColumn: string | null;
sourceColumn: string;
Expand Down
1 change: 1 addition & 0 deletions app/src/i18n/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"applyingMappings": "Zuordnungen werden angewendet..."
},
"validation": {
"none": "Leer",
"title": "Daten validieren",
"btnConfirmData": "Daten bestätigen",
"numberOfErrors": "{{count}} Fehler",
Expand Down
1 change: 1 addition & 0 deletions app/src/i18n/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"applyingMappings": "Processing data..."
},
"validation": {
"none": "Empty",
"title": "Validate your data",
"btnConfirmData": "Confirm data",
"numberOfErrors": "{{count}} errors",
Expand Down
8 changes: 8 additions & 0 deletions app/temporal/src/domain/ColumnValidation.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { CountryCode } from "libphonenumber-js";
import { ValidatorType } from "./validators";

export interface ColumnValidation {
type: ValidatorType;
}

export interface RegexColumnValidation extends ColumnValidation {
type: "regex";
regex: string;
}

export interface EnumerationColumnValidation extends ColumnValidation {
type: "enum";
values: string[];
canAddNewValues?: boolean;
}

export interface PhoneColumnValidation extends ColumnValidation {
type: "phone";
defaultCountry?: CountryCode;
}
108 changes: 2 additions & 106 deletions app/temporal/src/domain/DataAnalyzer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,6 @@ describe("DataAnalyzer", () => {
},
},
},
{
_id: new ObjectId("65b39818ab8b36794717db1e"),
__sourceRowId: 4,
data: {
name: {
value: "",
messages: [],
},
},
},
{
_id: new ObjectId("65b39818ab8b36794717db1f"),
__sourceRowId: 5,
Expand Down Expand Up @@ -254,26 +244,6 @@ describe("DataAnalyzer", () => {
},
],
},
{
rowId: "65b39818ab8b36794717db1d",
column: "name",
messages: [
{
message: "value is not unique",
type: "unique",
},
],
},
{
rowId: "65b39818ab8b36794717db1e",
column: "name",
messages: [
{
message: "value is not unique",
type: "unique",
},
],
},
{
rowId: "65b39818ab8b36794717db1f",
column: "name",
Expand Down Expand Up @@ -368,16 +338,6 @@ describe("DataAnalyzer", () => {
},
],
},
{
rowId: "65b39818ab8b36794717db1d",
column: "Postleitzahl",
messages: [
{
message: "value does not match regex ^[0-9]{5}$",
type: "regex",
},
],
},
{
rowId: "65b39818ab8b36794717db1e",
column: "Postleitzahl",
Expand Down Expand Up @@ -465,16 +425,6 @@ describe("DataAnalyzer", () => {
},
],
},
{
rowId: "65b39818ab8b36794717db1e",
column: "phone",
messages: [
{
message: "value is not a valid phone number",
type: "phone",
},
],
},
]);
});

Expand Down Expand Up @@ -551,16 +501,6 @@ describe("DataAnalyzer", () => {
},
],
},
{
rowId: "65b39818ab8b36794717db1f",
column: "email",
messages: [
{
message: "value is not a valid email",
type: "email",
},
],
},
]);
});

Expand Down Expand Up @@ -624,23 +564,6 @@ describe("DataAnalyzer", () => {
message: "value is required",
type: "required",
},
{
message: "value is not unique",
type: "unique",
},

{
message: "value is not a valid phone number",
type: "phone",
},
{
message: "value is not a valid email",
type: "email",
},
{
message: "value does not match regex ^[0-9]{5}$",
type: "regex",
},
],
},
{
Expand All @@ -651,23 +574,6 @@ describe("DataAnalyzer", () => {
message: "value is required",
type: "required",
},
{
message: "value is not unique",
type: "unique",
},

{
message: "value is not a valid phone number",
type: "phone",
},
{
message: "value is not a valid email",
type: "email",
},
{
message: "value does not match regex ^[0-9]{5}$",
type: "regex",
},
],
},
{
Expand All @@ -684,7 +590,7 @@ describe("DataAnalyzer", () => {
});

it("should validate enum values", () => {
const rowsWithEmailValues = [
const rowsWithValues = [
{
_id: new ObjectId("65b39818ab8b36794717db1a"),
__sourceRowId: 0,
Expand Down Expand Up @@ -719,7 +625,7 @@ describe("DataAnalyzer", () => {
} as ColumnValidators;
const stats = {};
const result = analyzer.processDataValidations(
rowsWithEmailValues,
rowsWithValues,
validatorColumns,
stats
);
Expand All @@ -734,16 +640,6 @@ describe("DataAnalyzer", () => {
},
],
},
{
column: "department",
rowId: "65b39818ab8b36794717db1d",
messages: [
{
message: "value is not a valid enum",
type: "enum",
},
],
},
]);
});
});
Expand Down
4 changes: 4 additions & 0 deletions app/temporal/src/domain/validators/EmailValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export class EmailValidator implements Validator {
const columnsToValidate = columnConfig.map((item) => item.column);
for (const columnToValidate of columnsToValidate) {
let dataToValidate = row.data[columnToValidate].value;
const isEmptyValue = Boolean(dataToValidate) === false;
if (isEmptyValue) {
continue;
}
if (EMAIL_REGEX.test((dataToValidate as string) ?? "") === false) {
errors[columnToValidate] = {
type: "email",
Expand Down
14 changes: 8 additions & 6 deletions app/temporal/src/domain/validators/EnumValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ export class EnumValidator implements Validator {
const errors: Record<string, ValidationMessage> = {};
for (const { column, config } of columnConfigs) {
let dataToValidate = row.data[column].value;
if (!dataToValidate || typeof dataToValidate !== "string") {
errors[column] = {
type: "enum",
message: "value is not a valid enum",
};
} else if (config.values.includes(dataToValidate) === false) {
const isEmptyValue = Boolean(dataToValidate) === false;
if (isEmptyValue) {
continue;
}
const isValueInEnum =
typeof dataToValidate === "string" &&
config.values.includes(dataToValidate);
if (isValueInEnum === false) {
errors[column] = {
type: "enum",
message: "value is not a valid enum",
Expand Down
Loading

0 comments on commit 0f78042

Please sign in to comment.