Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/config/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const config: JestConfigWithTsJest = {
"^.+\\.[cm]?[jt]sx?$": "ts-jest",
},
transformIgnorePatterns: [
"node_modules/(?!(keycloak-js|react-error-boundary)/)", // process esm only modules
"node_modules/(?!(keycloak-js|react-error-boundary|lodash-es)/)", // process esm only modules
],

// Code to set up the testing framework before each test file in the suite is executed
Expand Down
4 changes: 3 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"immer": "^10.2.0",
"js-yaml": "^4.1.0",
"keycloak-js": "^26.1.0",
"lodash-es": "^4.17.21",
"monaco-editor": "^0.52.2",
"radash": "^12.1.0",
"react": "^18.3.1",
Expand All @@ -68,6 +69,7 @@
"@types/file-saver": "^2.0.7",
"@types/jest": "^29.5.4",
"@types/js-yaml": "^4.0.9",
"@types/lodash-es": "^4.17.12",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/react-measure": "^2.0.12",
Expand All @@ -80,10 +82,10 @@
"css-minimizer-webpack-plugin": "^7.0.2",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"html-webpack-plugin": "^5.6.3",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-resolve": "^29.7.0",
"jest-watch-typeahead": "^2.2.2",
"jest": "^29.7.0",
"mini-css-extract-plugin": "^2.8.1",
"monaco-editor-webpack-plugin": "^7.1.1",
"msw": "^1.2.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,38 +61,10 @@ const RemoveButton = ({
);
};

/*
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"names": {
"description": "Application names. Each may be a glob expression.",
"items": {
"minLength": 1,
"type": "string"
},
"minItems": 0,
"type": "array"
},
"spaces": {
"description": "Space names.",
"items": {
"minLength": 1,
"type": "string"
},
"minItems": 1,
"type": "array"
}
},
"required": ["spaces"],
"title": "CloudFoundry Discover Filter",
"type": "object"
}
*/

interface FormValues {
names: { value: string }[];
organizations: { value: string }[];
spaces: { value: string }[];
names: { value: string }[];
}

const stringsToFormValue = (values?: string[]) =>
Expand All @@ -108,40 +80,40 @@ export interface FilterInputCloudFoundryProps {
}

/**
* Inputs for CloudFoundry discover applications filter. This is based on the json schema.
* Inputs for CloudFoundry discover applications filter.
*
* This is based on the JSON schema for the Cloud Foundry discovery filter as defined in
* {@link ./validate-cloudfoundry-schema.tsx}.
*/
export const FilterInputCloudFoundry: React.FC<
FilterInputCloudFoundryProps
> = ({ id, values, onDocumentChanged }) => {
const validationSchema = yup.object().shape({
names: yup
.array()
.of(
yup.object().shape({
value: yup
.string()
.min(1, "Name must be at least 1 character")
.trim(),
})
)
.min(0),
spaces: yup
.array()
.of(
yup.object().shape({
value: yup
.string()
.min(1, "Space must be at least 1 character")
.trim(),
})
)
.min(1),
organizations: yup.array().of(
yup.object().shape({
value: yup
.string()
.min(1, "Organization name must be at least 1 character")
.trim(),
})
),
spaces: yup.array().of(
yup.object().shape({
value: yup.string().min(1, "Space must be at least 1 character").trim(),
})
),
names: yup.array().of(
yup.object().shape({
value: yup.string().min(1, "Name must be at least 1 character").trim(),
})
),
});

const form = useForm<FormValues>({
defaultValues: {
names: stringsToFormValue(values?.names as string[]),
organizations: stringsToFormValue(values?.organizations as string[]),
spaces: stringsToFormValue(values?.spaces as string[]),
names: stringsToFormValue(values?.names as string[]),
},
resolver: yupResolver(validationSchema),
mode: "all",
Expand All @@ -154,8 +126,9 @@ export const FilterInputCloudFoundry: React.FC<
formState: { values: true },
callback: ({ values }) => {
const asDocument = {
names: formValueToStrings(values.names),
organizations: formValueToStrings(values.organizations),
spaces: formValueToStrings(values.spaces),
names: formValueToStrings(values.names),
};
onDocumentChanged(asDocument);
},
Expand All @@ -168,12 +141,13 @@ export const FilterInputCloudFoundry: React.FC<
<StackItem>
<StringFieldsGroup
control={form.control}
groupTitle="Names"
groupDescription="Enter application name (glob expressions allowed)"
fieldName="names"
addLabel="Add a name"
removeLabel="Remove this name"
emptyMessage="No application names specified"
groupTitle="Organizations"
groupDescription="Enter organization name"
fieldName="organizations"
addLabel="Add an organization"
removeLabel="Remove this organization"
emptyMessage="No organizations specified"
isRequired={false}
/>
</StackItem>

Expand All @@ -185,8 +159,21 @@ export const FilterInputCloudFoundry: React.FC<
fieldName="spaces"
addLabel="Add a space"
removeLabel="Remove this space"
emptyMessage="No spaces specified (at least one space is required)"
isRequired={true}
emptyMessage="No spaces specified"
isRequired={false}
/>
</StackItem>

<StackItem>
<StringFieldsGroup
control={form.control}
groupTitle="Names"
groupDescription="Enter application name (glob expressions allowed)"
fieldName="names"
addLabel="Add a name"
removeLabel="Remove this name"
emptyMessage="No application names specified"
isRequired={false}
/>
</StackItem>
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useFetchPlatformDiscoveryFilterSchema } from "@app/queries/schemas";
import { wrapAsEvent } from "@app/utils/utils";

import { FilterInputCloudFoundry } from "./filter-input-cloudfoundry";
import { useCloudFoundryCheck } from "./validate-cloudfoundry-schema";

interface FiltersFormValues {
filterRequired: boolean;
Expand Down Expand Up @@ -106,6 +107,11 @@ export const FilterInput: React.FC<{

useFilterStateChangeHandler(form, onFiltersChanged);

const shouldUseCloudFoundryInput = useCloudFoundryCheck(
platform,
filtersSchema
);

return (
<div>
<TextContent style={{ marginBottom: "var(--pf-v5-global--spacer--lg)" }}>
Expand Down Expand Up @@ -140,7 +146,7 @@ export const FilterInput: React.FC<{
})}
fieldId="document"
renderInput={({ field: { value, name, onChange } }) =>
platform.kind === "cloudfoundry" ? (
shouldUseCloudFoundryInput ? (
<FilterInputCloudFoundry
key={platform.kind}
id={name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,21 @@ export const ReviewInputCloudFoundry: React.FC<
return <EmptyTextMessage message="No filter values to display" />;
}

const names = (values.names as string[]) ?? [];
const organizations = (values.organizations as string[]) ?? [];
const spaces = (values.spaces as string[]) ?? [];
const names = (values.names as string[]) ?? [];

return (
<DescriptionList isHorizontal isCompact id={id}>
<DescriptionListGroup>
<DescriptionListTerm>Names</DescriptionListTerm>
<DescriptionListTerm>Organizations</DescriptionListTerm>
<DescriptionListDescription>
{names.length === 0 ? (
<EmptyTextMessage message="No names specified" />
{organizations.length === 0 ? (
<EmptyTextMessage message="No organizations specified" />
) : (
<List isPlain>
{names.map((name) => (
<ListItem key={name}>{name}</ListItem>
{organizations.map((organization) => (
<ListItem key={organization}>{organization}</ListItem>
))}
</List>
)}
Expand All @@ -60,6 +61,21 @@ export const ReviewInputCloudFoundry: React.FC<
)}
</DescriptionListDescription>
</DescriptionListGroup>

<DescriptionListGroup>
<DescriptionListTerm>Names</DescriptionListTerm>
<DescriptionListDescription>
{names.length === 0 ? (
<EmptyTextMessage message="No names specified" />
) : (
<List isPlain>
{names.map((name) => (
<ListItem key={name}>{name}</ListItem>
))}
</List>
)}
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { usePlatformKindList } from "@app/hooks/usePlatformKindList";

import { FilterState } from "./filter-input";
import { ReviewInputCloudFoundry } from "./review-input-cloudfoundry";
import { useCloudFoundryCheck } from "./validate-cloudfoundry-schema";

export const Review: React.FC<{
platform: SourcePlatform;
Expand All @@ -27,6 +28,11 @@ export const Review: React.FC<{
const showFilters =
filters.filterRequired && filters.schema && filters.document;

const shouldUseCloudFoundryReview = useCloudFoundryCheck(
platform,
filters.schema
);

return (
<div>
<TextContent style={{ marginBottom: "var(--pf-v5-global--spacer--lg)" }}>
Expand Down Expand Up @@ -82,7 +88,7 @@ export const Review: React.FC<{
padding: "16px",
}}
>
{platform.kind === "cloudfoundry" ? (
{shouldUseCloudFoundryReview ? (
<ReviewInputCloudFoundry
id="platform-discovery-filters-review"
values={filters.document}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as React from "react";

import {
JsonSchemaObject,
SourcePlatform,
TargetedSchema,
} from "@app/api/models";
import { validatorGenerator } from "@app/utils/json-schema";

/**
* The schema that is implemented by `FilterInputCloudFoundry`.
*/
const SUPPORTED_SCHEMA: JsonSchemaObject = {
$schema: "https://json-schema.org/draft/2020-12/schema",
properties: {
organizations: {
description: "Organization names.",
items: {
minLength: 1,
type: "string",
},
type: "array",
},
spaces: {
description: "Space names.",
items: {
minLength: 1,
type: "string",
},
type: "array",
},
names: {
description: "Application names. Each may be a glob expression.",
items: {
minLength: 1,
type: "string",
},
type: "array",
},
},
type: "object",
};

/**
* Check the given schema and return if it is functionally equivalent to the schema used
* to build CloudFoundry forms.
*/
export const validateCloudFoundrySchema = validatorGenerator(SUPPORTED_SCHEMA);

export const useCloudFoundryCheck = (
platform: SourcePlatform,
schema?: TargetedSchema
) => {
return React.useMemo(() => {
return (
platform.kind === "cloudfoundry" &&
schema &&
validateCloudFoundrySchema(schema.definition)
);
}, [platform.kind, schema]);
};
Loading
Loading