This is an automated email from the ASF dual-hosted git repository.
tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new e06cd98ebe4 kie-issues#1244: DMN Runner uses the JSON Schema
specification instead of the OpenAPI Schema v3.0 (#2356)
e06cd98ebe4 is described below
commit e06cd98ebe4d706bead655d4ecf0db118cdf82ec
Author: Luiz João Motta <[email protected]>
AuthorDate: Wed May 22 21:40:03 2024 -0300
kie-issues#1244: DMN Runner uses the JSON Schema specification instead of
the OpenAPI Schema v3.0 (#2356)
---
.../uniforms-patternfly/src/schemas/json-schema.ts | 5 +-
.../dev-deployment-dmn-form-webapp/package.json | 2 +
.../src/DmnDevDeploymentFormWebAppDataApi.tsx | 4 +-
.../src/DmnFormPage.tsx | 21 ++--
.../ConstraintComponents/ConstraintDate.tsx | 12 +-
.../ConstraintComponents/ConstraintTime.tsx | 84 ++++++++++----
packages/dmn-editor/src/dataTypes/Constraints.tsx | 91 +++++++--------
packages/dmn-runner/package.json | 1 +
packages/dmn-runner/src/jsonSchema.ts | 22 ++--
.../src/{jsonSchema.ts => formSchema.ts} | 4 +-
packages/extended-services-api/src/index.ts | 2 +-
packages/form-dmn/package.json | 1 +
packages/form-dmn/src/FormDmn.tsx | 4 +-
packages/form-dmn/src/FormDmnValidator.ts | 4 +-
.../src/uniforms/FormDmnJsonSchemaBridge.ts | 7 +-
packages/form-dmn/tests/FormDmn.test.tsx | 6 +-
packages/form-dmn/tests/FormDmnValidator.test.ts | 4 +-
packages/online-editor/package.json | 2 +
.../src/dmnRunner/DmnRunnerContext.tsx | 5 +-
.../src/dmnRunner/DmnRunnerContextProvider.tsx | 42 ++++---
.../online-editor/src/dmnRunner/DmnRunnerTypes.ts | 5 +-
.../src/extendedServices/ExtendedServicesClient.ts | 4 +-
packages/uniforms-patternfly/src/SelectField.tsx | 4 +-
.../uniforms-patternfly/src/SelectInputsField.tsx | 60 +++++-----
packages/unitables-dmn/package.json | 1 +
.../unitables-dmn/src/DmnUnitablesValidator.ts | 4 +-
.../src/uniforms/DmnUnitablesJsonSchemaBridge.ts | 4 +-
pnpm-lock.yaml | 124 +++++++++++++++++++--
28 files changed, 350 insertions(+), 179 deletions(-)
diff --git a/examples/uniforms-patternfly/src/schemas/json-schema.ts
b/examples/uniforms-patternfly/src/schemas/json-schema.ts
index d74a2049f15..d2e99e55434 100644
--- a/examples/uniforms-patternfly/src/schemas/json-schema.ts
+++ b/examples/uniforms-patternfly/src/schemas/json-schema.ts
@@ -27,6 +27,7 @@ function createValidator(schema: any) {
return (model: any) => {
validator(model);
if (validator.errors && validator.errors.length) {
+ console.error("VALIDATION ERROR: MODEL: ", model);
throw { details: validator.errors };
}
};
@@ -83,8 +84,8 @@ const schema = {
},
numberOfBeds: {
placeholder: "Select...",
- enum: [1, 2, 3],
- type: "number",
+ enum: [null, 0, 1, 2],
+ type: ["null", "number"],
},
},
},
diff --git a/packages/dev-deployment-dmn-form-webapp/package.json
b/packages/dev-deployment-dmn-form-webapp/package.json
index fb621bc7a15..2a89730608a 100644
--- a/packages/dev-deployment-dmn-form-webapp/package.json
+++ b/packages/dev-deployment-dmn-form-webapp/package.json
@@ -29,6 +29,7 @@
"@kie-tools/extended-services-api": "workspace:*",
"@kie-tools/form-dmn": "workspace:*",
"@kie-tools/i18n-common-dictionary": "workspace:*",
+ "@openapi-contrib/openapi-schema-to-json-schema": "^5.1.0",
"@patternfly/react-core": "^4.276.6",
"@patternfly/react-icons": "^4.93.6",
"@readme/openapi-parser": "^2.5.0",
@@ -51,6 +52,7 @@
"@testing-library/react": "^11.2.6",
"@types/jest": "^26.0.23",
"@types/jest-when": "^2.7.4",
+ "@types/json-schema": "^7.0.11",
"@types/lodash": "^4.14.168",
"@types/react": "^17.0.6",
"@types/react-dom": "^17.0.5",
diff --git
a/packages/dev-deployment-dmn-form-webapp/src/DmnDevDeploymentFormWebAppDataApi.tsx
b/packages/dev-deployment-dmn-form-webapp/src/DmnDevDeploymentFormWebAppDataApi.tsx
index 9101a19a1cb..db8a4fa18b4 100644
---
a/packages/dev-deployment-dmn-form-webapp/src/DmnDevDeploymentFormWebAppDataApi.tsx
+++
b/packages/dev-deployment-dmn-form-webapp/src/DmnDevDeploymentFormWebAppDataApi.tsx
@@ -17,7 +17,7 @@
* under the License.
*/
-import { ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
+import { ExtendedServicesFormSchema } from "@kie-tools/extended-services-api";
import OpenAPIParser from "@readme/openapi-parser";
import { routes } from "./Routes";
import { DmnFormAppProps } from "./DmnFormApp";
@@ -25,7 +25,7 @@ import * as path from "path";
export interface FormData {
modelName: string;
- schema: ExtendedServicesDmnJsonSchema;
+ schema: ExtendedServicesFormSchema;
}
export interface AppData {
diff --git a/packages/dev-deployment-dmn-form-webapp/src/DmnFormPage.tsx
b/packages/dev-deployment-dmn-form-webapp/src/DmnFormPage.tsx
index 87b025a84db..93c86771dc6 100644
--- a/packages/dev-deployment-dmn-form-webapp/src/DmnFormPage.tsx
+++ b/packages/dev-deployment-dmn-form-webapp/src/DmnFormPage.tsx
@@ -20,7 +20,7 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from
"react";
import { I18nWrapped } from "@kie-tools-core/i18n/dist/react-components";
import { FormDmn, FormDmnOutputs } from "@kie-tools/form-dmn";
-import { DecisionResult, ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
+import { DecisionResult } from "@kie-tools/extended-services-api";
import { Alert, AlertActionCloseButton } from
"@patternfly/react-core/dist/js/components/Alert";
import { EmptyState, EmptyStateBody, EmptyStateIcon } from
"@patternfly/react-core/dist/js/components/EmptyState";
import { Page, PageSection } from
"@patternfly/react-core/dist/js/components/Page";
@@ -32,9 +32,11 @@ import { DmnFormToolbar } from "./DmnFormToolbar";
import { ErrorBoundary } from "./ErrorBoundary";
import { useDmnFormI18n } from "./i18n";
import { useCancelableEffect } from
"@kie-tools-core/react-hooks/dist/useCancelableEffect";
-import { resolveReferencesAndCheckForRecursion, getDefaultValues } from
"@kie-tools/dmn-runner/dist/jsonSchema";
+import { dereferenceAndCheckForRecursion, getDefaultValues } from
"@kie-tools/dmn-runner/dist/jsonSchema";
import { extractDifferences } from "@kie-tools/dmn-runner/dist/results";
import { DmnFormAppProps } from "./DmnFormApp";
+import { openapiSchemaToJsonSchema } from
"@openapi-contrib/openapi-schema-to-json-schema";
+import type { JSONSchema4 } from "json-schema";
interface Props extends DmnFormAppProps {
formData: FormData;
@@ -54,7 +56,7 @@ export function DmnFormPage(props: Props) {
const [formOutputs, setFormOutputs] = useState<DecisionResult[]>();
const [formOutputDiffs, setFormOutputDiffs] = useState<object[]>();
const [formError, setFormError] = useState(false);
- const [jsonSchema, setJsonSchema] = useState<ExtendedServicesDmnJsonSchema |
undefined>(undefined);
+ const [jsonSchema, setJsonSchema] = useState<JSONSchema4 |
undefined>(undefined);
const [openAlert, setOpenAlert] = useState(AlertTypes.NONE);
const [pageError, setPageError] = useState<boolean>(false);
const errorBoundaryRef = useRef<ErrorBoundary>(null);
@@ -62,18 +64,21 @@ export function DmnFormPage(props: Props) {
useCancelableEffect(
useCallback(
({ canceled }) => {
- resolveReferencesAndCheckForRecursion(props.formData.schema,
canceled).then((resolvedJsonSchema) => {
- if (canceled.get()) {
+ dereferenceAndCheckForRecursion(props.formData.schema,
canceled).then((dereferencedSchema) => {
+ if (canceled.get() || !dereferencedSchema) {
return;
}
- setJsonSchema(resolvedJsonSchema);
+ const jsonSchema = openapiSchemaToJsonSchema(dereferencedSchema, {
+ definitionKeywords: ["definitions"],
+ });
+ setJsonSchema(jsonSchema);
setFormInputs((previousFormInputs) => {
- if (!resolvedJsonSchema) {
+ if (!jsonSchema) {
return {};
}
return {
- ...getDefaultValues(resolvedJsonSchema),
+ ...getDefaultValues(jsonSchema),
...previousFormInputs,
};
});
diff --git
a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.tsx
b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.tsx
index e4cb2e573e9..368f8f9ceda 100644
--- a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.tsx
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintDate.tsx
@@ -22,6 +22,7 @@ import { DatePicker } from
"@patternfly/react-core/dist/js/components/DatePicker
import "./Constraint.css";
import "./ConstraintDate.css";
import { ConstraintProps } from "./Constraint";
+import moment from "moment";
export function ConstraintDate({ value, onChange, isValid }: ConstraintProps) {
return (
@@ -32,7 +33,16 @@ export function ConstraintDate({ value, onChange, isValid }:
ConstraintProps) {
}`}
inputProps={{ className: "kie-dmn-editor--constraint-input" }}
value={value}
- onChange={(e, value) => onChange(value)}
+ onChange={(e, value) => {
+ if (moment(value, "YYYY-MM-DD", true).isValid()) {
+ onChange(value);
+ }
+ }}
+ onBlur={(e, value) => {
+ if (moment(value, "YYYY-MM-DD", true).isValid()) {
+ onChange(value);
+ }
+ }}
/>
</>
);
diff --git
a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.tsx
b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.tsx
index 346b3eb4a82..dd2a7ea481d 100644
--- a/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.tsx
+++ b/packages/dmn-editor/src/dataTypes/ConstraintComponents/ConstraintTime.tsx
@@ -26,6 +26,8 @@ import { ConstraintProps } from "./Constraint";
import { Select, SelectOption, SelectVariant } from
"@patternfly/react-core/dist/js/components/Select";
import { useDmnEditor } from "../../DmnEditorContext";
import { useInViewSelect } from "../../responsiveness/useInViewSelect";
+import { Tooltip } from "@patternfly/react-core/dist/js/components/Tooltip";
+import moment from "moment";
// Time zone list from https://www.timeanddate.com/time/zones/
const UTC_POSITEVE_TIMEZONES = [
@@ -75,11 +77,19 @@ const UTC_NEGATIVE_TIMEZONES = [
"-01:00",
];
+const TIME_REGEXP =
/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?([+|-](0[0-9]|1[0-9]|2[0-3]):[0-9][0-9])?$/;
+
export function ConstraintTime({ value, onChange, isValid }: ConstraintProps) {
const time = useMemo(() => {
+ if (value.match(TIME_REGEXP) === null) {
+ return "";
+ }
return value.includes("+") ? value.split("+")[0] : value.split("-")[0];
}, [value]);
const timezone = useMemo<string>(() => {
+ if (value.match(TIME_REGEXP) === null) {
+ return UTC_POSITEVE_TIMEZONES[0];
+ }
return value.includes("+")
? `+${value.split("+")[1]}`
: value.includes("-")
@@ -123,36 +133,62 @@ export function ConstraintTime({ value, onChange, isValid
}: ConstraintProps) {
className={`kie-dmn-editor--constraint-time
kie-dmn-editor--constraint-input ${
isValid ? "" : "kie-dmn-editor--constraint-invalid"
}`}
- inputProps={{ className: "kie-dmn-editor--constraint-input" }}
+ inputProps={{
+ className: "kie-dmn-editor--constraint-input",
+ onBlur: (e: React.FocusEvent<HTMLInputElement>) => {
+ if (moment(value, "HH:mm", true).isValid() || moment(value,
"HH:mm:ss", true).isValid()) {
+ onChangeTime(value);
+ }
+ },
+ }}
time={time}
- onChange={(e, value, hour, minute, seconds, isValid) => {
- if (isValid) {
+ onChange={(e, value) => {
+ if (moment(value, "HH:mm", true).isValid()) {
+ onChangeTime(`${value}:00`);
+ }
+ if (moment(value, "HH:mm:ss", true).isValid()) {
onChangeTime(value);
}
}}
includeSeconds={true}
/>
- <Select
- toggleRef={toggleRef}
- className={`kie-dmn-editor--constraint-time-timezone ${
- isValid ? "" : "kie-dmn-editor--constraint-time-timezone-invalid"
- }`}
- variant={SelectVariant.single}
- placeholderText="Select timezone"
- aria-label="Select timezone"
- onToggle={(isExpanded) => setSelectTimezoneOpen(isExpanded)}
- onSelect={onSelectTimezone}
- selections={timezone}
- isOpen={isSelectTimezoneOpen}
- isDisabled={false}
- isPlain={true}
- maxHeight={inViewTimezoneSelect.maxHeight}
- direction={inViewTimezoneSelect.direction}
- >
- {[...UTC_NEGATIVE_TIMEZONES, ...UTC_POSITEVE_TIMEZONES].map((timezone)
=> (
- <SelectOption key={timezone} value={timezone} />
- ))}
- </Select>
+ {time === "" ? (
+ <Tooltip content={"To tweak the timezone it's necessary to set a time
first"}>
+ <Select
+ className={"kie-dmn-editor--constraint-time-timezone"}
+ variant={SelectVariant.single}
+ onToggle={() => {}}
+ selections={UTC_POSITEVE_TIMEZONES[0]}
+ isOpen={false}
+ isDisabled={true}
+ isPlain={true}
+ >
+ {[<SelectOption key={UTC_POSITEVE_TIMEZONES[0]}
value={UTC_POSITEVE_TIMEZONES[0]} />]}
+ </Select>
+ </Tooltip>
+ ) : (
+ <Select
+ toggleRef={toggleRef}
+ className={`kie-dmn-editor--constraint-time-timezone ${
+ isValid ? "" : "kie-dmn-editor--constraint-time-timezone-invalid"
+ }`}
+ variant={SelectVariant.single}
+ placeholderText="Select timezone"
+ aria-label="Select timezone"
+ onToggle={(isExpanded) => setSelectTimezoneOpen(isExpanded)}
+ onSelect={onSelectTimezone}
+ selections={timezone}
+ isOpen={isSelectTimezoneOpen}
+ isDisabled={false}
+ isPlain={true}
+ maxHeight={inViewTimezoneSelect.maxHeight}
+ direction={inViewTimezoneSelect.direction}
+ >
+ {[...UTC_NEGATIVE_TIMEZONES,
...UTC_POSITEVE_TIMEZONES].map((timezone) => (
+ <SelectOption key={timezone} value={timezone} />
+ ))}
+ </Select>
+ )}
</div>
);
}
diff --git a/packages/dmn-editor/src/dataTypes/Constraints.tsx
b/packages/dmn-editor/src/dataTypes/Constraints.tsx
index 7df3957e40a..cc871b56179 100644
--- a/packages/dmn-editor/src/dataTypes/Constraints.tsx
+++ b/packages/dmn-editor/src/dataTypes/Constraints.tsx
@@ -151,6 +151,7 @@ export const constraintTypeHelper = (
case DmnBuiltInDataType.DateTime:
return (
moment(recoveredValue, "YYYY-MM-DDTHH:mm:ssZZ", true).isValid() ||
+ moment(recoveredValue, "YYYY-MM-DDTHH:mmZZ", true).isValid() ||
moment(recoveredValue, "YYYY-MM-DD", true).isValid() ||
value === "" ||
recoveredValue === ""
@@ -160,7 +161,12 @@ export const constraintTypeHelper = (
case DmnBuiltInDataType.Number:
return !isNaN(parseFloat(recoveredValue ?? "")) || value === "" ||
recoveredValue === "";
case DmnBuiltInDataType.Time:
- return moment(recoveredValue, "HH:mm:ssZZ", true).isValid() || value
=== "" || recoveredValue === "";
+ return (
+ moment(recoveredValue, "HH:mmZZ", true).isValid() ||
+ moment(recoveredValue, "HH:mm:ssZZ", true).isValid() ||
+ value === "" ||
+ recoveredValue === ""
+ );
case DmnBuiltInDataType.YearsMonthsDuration:
return REGEX_YEARS_MONTH_DURATION.test(recoveredValue ?? "") ||
value === "" || recoveredValue === "";
default:
@@ -633,6 +639,11 @@ export function ConstraintsFromTypeConstraintAttribute({
return;
}
+ if (!itemDefinition.typeConstraint && itemDefinition.allowedValues) {
+ itemDefinition.typeConstraint = itemDefinition.allowedValues;
+ itemDefinition.allowedValues = undefined;
+ }
+
if (itemDefinition.typeConstraint) {
itemDefinition.typeConstraint["@_kie:constraintType"] =
enumToKieConstraintType(selectedConstraint);
}
@@ -710,20 +721,26 @@ export function Constraints({
onToggleGroupChange: (selected: boolean, selectedConstraint:
ConstraintsType) => void;
onConstraintChange: (value: string | undefined, selectedConstraint:
ConstraintsType) => void;
}) {
- const [internalSelectedConstraint, setInternalSelectedConstraint] =
- useState<ConstraintsType>(selectedKieConstraintType);
+ const [internalSelectedConstraint, setInternalSelectedConstraint] =
useState<{
+ selectedConstraint: ConstraintsType;
+ itemDefinitionId: string;
+ }>({ selectedConstraint: selectedKieConstraintType, itemDefinitionId });
// Updates the `selectedConstraint` only after changing the active item
definition
// Both `internalSelectedConstraint` and `selectedKieConstraintType` should
not be coupled together
useEffect(() => {
- setInternalSelectedConstraint(selectedKieConstraintType);
- // eslint-disable-next-line
- }, [itemDefinitionId]);
+ setInternalSelectedConstraint((prev) => {
+ if (selectedKieConstraintType === ConstraintsType.NONE &&
prev.itemDefinitionId === itemDefinitionId) {
+ return prev;
+ }
+ return { selectedConstraint: selectedKieConstraintType, itemDefinitionId
};
+ });
+ }, [itemDefinitionId, selectedKieConstraintType]);
const onToggleGroupChangeInternal = useCallback(
(selected: boolean, event: React.KeyboardEvent<Element> | MouseEvent |
React.MouseEvent<any, MouseEvent>) => {
const selectedConstraint = event.currentTarget.id as ConstraintsType;
- setInternalSelectedConstraint(selectedConstraint);
+ setInternalSelectedConstraint((prev) => ({ selectedConstraint,
itemDefinitionId: prev.itemDefinitionId }));
onToggleGroupChange(selected, selectedConstraint);
},
[onToggleGroupChange]
@@ -731,9 +748,11 @@ export function Constraints({
const onConstraintChangeInternal = useCallback(
(value: string | undefined) => {
- onConstraintChange(value, internalSelectedConstraint);
+ if (constraintValue !== value) {
+ onConstraintChange(value,
internalSelectedConstraint.selectedConstraint);
+ }
},
- [onConstraintChange, internalSelectedConstraint]
+ [onConstraintChange, internalSelectedConstraint, constraintValue]
);
return (
@@ -758,10 +777,7 @@ export function Constraints({
<ToggleGroupItem
text={ConstraintsType.NONE}
buttonId={ConstraintsType.NONE}
- isSelected={
- selectedKieConstraintType === ConstraintsType.NONE &&
- internalSelectedConstraint === ConstraintsType.NONE
- }
+ isSelected={internalSelectedConstraint.selectedConstraint ===
ConstraintsType.NONE}
onChange={onToggleGroupChangeInternal}
isDisabled={isReadonly}
/>
@@ -773,30 +789,21 @@ export function Constraints({
style={{ zIndex: 10 }}
text={ConstraintsType.EXPRESSION}
buttonId={ConstraintsType.EXPRESSION}
- isSelected={
- selectedKieConstraintType === ConstraintsType.EXPRESSION ||
- internalSelectedConstraint === ConstraintsType.EXPRESSION
- }
+ isSelected={internalSelectedConstraint.selectedConstraint ===
ConstraintsType.EXPRESSION}
onChange={onToggleGroupChangeInternal}
isDisabled={isReadonly || !isConstraintEnabled.expression}
/>
<ToggleGroupItem
text={ConstraintsType.ENUMERATION}
buttonId={ConstraintsType.ENUMERATION}
- isSelected={
- selectedKieConstraintType === ConstraintsType.ENUMERATION ||
- internalSelectedConstraint === ConstraintsType.ENUMERATION
- }
+ isSelected={internalSelectedConstraint.selectedConstraint ===
ConstraintsType.ENUMERATION}
onChange={onToggleGroupChangeInternal}
isDisabled={isReadonly || !isConstraintEnabled.enumeration}
/>
<ToggleGroupItem
text={ConstraintsType.RANGE}
buttonId={ConstraintsType.RANGE}
- isSelected={
- selectedKieConstraintType === ConstraintsType.RANGE ||
- internalSelectedConstraint === ConstraintsType.RANGE
- }
+ isSelected={internalSelectedConstraint.selectedConstraint ===
ConstraintsType.RANGE}
onChange={onToggleGroupChangeInternal}
isDisabled={isReadonly || !isConstraintEnabled.range}
/>
@@ -804,8 +811,7 @@ export function Constraints({
</div>
<div style={{ paddingTop: "20px" }}>
- {(selectedKieConstraintType === ConstraintsType.ENUMERATION ||
- internalSelectedConstraint === ConstraintsType.ENUMERATION) && (
+ {internalSelectedConstraint.selectedConstraint ===
ConstraintsType.ENUMERATION && (
<ConstraintsEnum
id={itemDefinitionId}
isReadonly={isReadonly}
@@ -818,8 +824,7 @@ export function Constraints({
renderOnPropertiesPanel={renderOnPropertiesPanel}
/>
)}
- {(selectedKieConstraintType === ConstraintsType.RANGE ||
- internalSelectedConstraint === ConstraintsType.RANGE) && (
+ {internalSelectedConstraint.selectedConstraint ===
ConstraintsType.RANGE && (
<ConstraintsRange
id={itemDefinitionId}
isReadonly={isReadonly}
@@ -832,8 +837,7 @@ export function Constraints({
renderOnPropertiesPanel={renderOnPropertiesPanel}
/>
)}
- {(selectedKieConstraintType === ConstraintsType.EXPRESSION ||
- internalSelectedConstraint === ConstraintsType.EXPRESSION) && (
+ {internalSelectedConstraint.selectedConstraint ===
ConstraintsType.EXPRESSION && (
<ConstraintsExpression
id={itemDefinitionId}
isReadonly={isReadonly}
@@ -844,19 +848,18 @@ export function Constraints({
isDisabled={!isConstraintEnabled.expression}
/>
)}
- {selectedKieConstraintType === ConstraintsType.NONE &&
- internalSelectedConstraint === ConstraintsType.NONE && (
- <p
- style={{
- padding: "24px",
- background: "#eee",
- borderRadius: "10px",
- textAlign: "center",
- }}
- >
- {`All values are allowed`}
- </p>
- )}
+ {internalSelectedConstraint.selectedConstraint ===
ConstraintsType.NONE && (
+ <p
+ style={{
+ padding: "24px",
+ background: "#eee",
+ borderRadius: "10px",
+ textAlign: "center",
+ }}
+ >
+ {`All values are allowed`}
+ </p>
+ )}
</div>
</div>
)}
diff --git a/packages/dmn-runner/package.json b/packages/dmn-runner/package.json
index 0bb45c4ce82..55d4746728f 100644
--- a/packages/dmn-runner/package.json
+++ b/packages/dmn-runner/package.json
@@ -48,6 +48,7 @@
"@kie-tools/root-env": "workspace:*",
"@kie-tools/tsconfig": "workspace:*",
"@types/jest": "^26.0.23",
+ "@types/json-schema": "^7.0.11",
"@types/lodash": "^4.14.168",
"@types/react": "^17.0.6",
"@types/react-dom": "^17.0.5",
diff --git a/packages/dmn-runner/src/jsonSchema.ts
b/packages/dmn-runner/src/jsonSchema.ts
index 687ba762232..be94d9f62be 100644
--- a/packages/dmn-runner/src/jsonSchema.ts
+++ b/packages/dmn-runner/src/jsonSchema.ts
@@ -19,10 +19,7 @@
import { JSON_SCHEMA_INPUT_SET_PATH, RECURSION_KEYWORD, RECURSION_REF_KEYWORD
} from "./jsonSchemaConstants";
import { DmnAjvSchemaFormat, ValidateFunction } from "./ajv";
-import {
- ExtendedServicesDmnJsonSchema,
- DmnInputFieldProperties,
-} from "@kie-tools/extended-services-api/dist/jsonSchema";
+import { ExtendedServicesFormSchema, DmnInputFieldProperties } from
"@kie-tools/extended-services-api/dist/formSchema";
import { Holder } from "@kie-tools-core/react-hooks/dist/Holder";
import { resolveRefs, pathFromPtr } from "json-refs";
import cloneDeep from "lodash/cloneDeep";
@@ -30,6 +27,7 @@ import getObjectValueByPath from "lodash/get";
import setObjectValueByPath from "lodash/set";
import unsetObjectValueByPath from "lodash/unset";
import { X_DMN_TYPE_KEYWORD } from "./jitExecutorKeywords";
+import type { JSONSchema4 } from "json-schema";
function getFieldDefaultValue(dmnField: DmnInputFieldProperties): string |
boolean | [] | object | undefined {
if (dmnField?.type === "string" && dmnField?.format === undefined) {
@@ -53,7 +51,7 @@ function getFieldDefaultValue(dmnField:
DmnInputFieldProperties): string | boole
/**
* get default values based on the jsonSchema
*/
-export function getDefaultValues(jsonSchema: ExtendedServicesDmnJsonSchema) {
+export function getDefaultValues(jsonSchema: JSONSchema4) {
return Object.entries(getObjectValueByPath(jsonSchema,
JSON_SCHEMA_INPUT_SET_PATH) ?? {})?.reduce(
(acc, [key, field]: [string, Record<string, string>]) => {
acc[key] = getFieldDefaultValue(field);
@@ -106,16 +104,16 @@ export function
removeChangedPropertiesAndAdditionalProperties<T extends Validat
* All circular $refs are changed to "recursionRef" instead of "$ref"
* The JSON schema is resolved a second time to ensure all circular $ref were
removed.
*/
-export async function resolveReferencesAndCheckForRecursion(
- jsonSchema: ExtendedServicesDmnJsonSchema,
+export async function dereferenceAndCheckForRecursion(
+ formSchema: ExtendedServicesFormSchema,
canceled?: Holder<boolean>
-): Promise<ExtendedServicesDmnJsonSchema | undefined> {
+): Promise<ExtendedServicesFormSchema | undefined> {
try {
- const jsonSchemaCopy = cloneDeep(jsonSchema);
- const $ref = getObjectValueByPath(jsonSchemaCopy, "$ref");
- unsetObjectValueByPath(jsonSchemaCopy, "$ref");
+ const formSchemaCopy = cloneDeep(formSchema);
+ const $ref = getObjectValueByPath(formSchemaCopy, "$ref");
+ unsetObjectValueByPath(formSchemaCopy, "$ref");
- const { refs, resolved } = await resolveRefs(jsonSchemaCopy as any);
+ const { refs, resolved } = await resolveRefs(formSchemaCopy as any);
if (canceled?.get()) {
return;
}
diff --git a/packages/extended-services-api/src/jsonSchema.ts
b/packages/extended-services-api/src/formSchema.ts
similarity index 94%
rename from packages/extended-services-api/src/jsonSchema.ts
rename to packages/extended-services-api/src/formSchema.ts
index 8bbb94114c1..70ac385676f 100644
--- a/packages/extended-services-api/src/jsonSchema.ts
+++ b/packages/extended-services-api/src/formSchema.ts
@@ -51,8 +51,8 @@ export interface DmnSchemaDefitionProperties {
"x-dmn-type"?: X_DMN_TYPE | string;
}
-// JSON schema returned from extended-services /schema/form;
-export interface ExtendedServicesDmnJsonSchema {
+// OpenAPI Schema returned from extended-services /schema/form;
+export interface ExtendedServicesFormSchema {
$ref?: string;
definitions?: Record<DmnSchemaDefinitions, DmnSchemaDefitionProperties>;
}
diff --git a/packages/extended-services-api/src/index.ts
b/packages/extended-services-api/src/index.ts
index b100ebc19e5..1ba5946fe47 100644
--- a/packages/extended-services-api/src/index.ts
+++ b/packages/extended-services-api/src/index.ts
@@ -18,6 +18,6 @@
*/
export * from "./dmnResult";
-export * from "./jsonSchema";
+export * from "./formSchema";
export * from "./payload";
export * from "./validate";
diff --git a/packages/form-dmn/package.json b/packages/form-dmn/package.json
index ad4b1cc46c5..ee9e2b3a844 100644
--- a/packages/form-dmn/package.json
+++ b/packages/form-dmn/package.json
@@ -53,6 +53,7 @@
"@testing-library/react": "^11.2.6",
"@types/jest": "^26.0.23",
"@types/jest-when": "^2.7.4",
+ "@types/json-schema": "^7.0.11",
"@types/lodash": "^4.14.168",
"@types/react": "^17.0.6",
"@types/react-dom": "^17.0.5",
diff --git a/packages/form-dmn/src/FormDmn.tsx
b/packages/form-dmn/src/FormDmn.tsx
index 34955e54717..dfcea912db2 100644
--- a/packages/form-dmn/src/FormDmn.tsx
+++ b/packages/form-dmn/src/FormDmn.tsx
@@ -23,12 +23,12 @@ import { FormDmnValidator } from "./FormDmnValidator";
import { formDmnI18n } from "./i18n";
import { FormComponent, FormProps } from "@kie-tools/form/dist/FormComponent";
import { DmnAutoFieldProvider } from "@kie-tools/dmn-runner/dist/uniforms";
-import { ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
import { formDmnRunnerAutoFieldValue } from
"./uniforms/FormDmnRunnerAutoFieldValue";
+import { JSONSchema4 } from "json-schema";
export type InputRow = Record<string, any>;
-export function FormDmn(props: FormProps<InputRow,
ExtendedServicesDmnJsonSchema>) {
+export function FormDmn(props: FormProps<InputRow, JSONSchema4>) {
const i18n = useMemo(() => {
formDmnI18n.setLocale(props.locale ?? navigator.language);
return formDmnI18n.getCurrent();
diff --git a/packages/form-dmn/src/FormDmnValidator.ts
b/packages/form-dmn/src/FormDmnValidator.ts
index ccddb30015c..3c8369b9fb2 100644
--- a/packages/form-dmn/src/FormDmnValidator.ts
+++ b/packages/form-dmn/src/FormDmnValidator.ts
@@ -25,9 +25,9 @@ import {
X_DMN_ALLOWED_VALUES_KEYWORD,
X_DMN_TYPE_CONSTRAINTS_KEYWORD,
} from "@kie-tools/dmn-runner/dist/jitExecutorKeywords";
-import { ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
import { DmnRunnerAjv } from "@kie-tools/dmn-runner/dist/ajv";
import { SCHEMA_DRAFT4 } from "@kie-tools/dmn-runner/dist/jsonSchemaConstants";
+import type { JSONSchema4 } from "json-schema";
export class FormDmnValidator extends Validator {
private dmnRunnerAjv = new DmnRunnerAjv();
@@ -70,7 +70,7 @@ export class FormDmnValidator extends Validator {
};
}
- public getBridge(formSchema: ExtendedServicesDmnJsonSchema):
FormDmnJsonSchemaBridge {
+ public getBridge(formSchema: JSONSchema4): FormDmnJsonSchemaBridge {
const formDraft4 = { ...formSchema, $schema: SCHEMA_DRAFT4 };
const validator = this.createValidator(formDraft4);
return new FormDmnJsonSchemaBridge(formDraft4, validator, this.i18n as
FormDmnI18n);
diff --git a/packages/form-dmn/src/uniforms/FormDmnJsonSchemaBridge.ts
b/packages/form-dmn/src/uniforms/FormDmnJsonSchemaBridge.ts
index 1d2f0506230..d42aadae12d 100644
--- a/packages/form-dmn/src/uniforms/FormDmnJsonSchemaBridge.ts
+++ b/packages/form-dmn/src/uniforms/FormDmnJsonSchemaBridge.ts
@@ -19,8 +19,9 @@
import { FormJsonSchemaBridge } from
"@kie-tools/form/dist/uniforms/FormJsonSchemaBridge";
import { FormDmnI18n } from "../i18n";
-import { DmnInputFieldProperties, ExtendedServicesDmnJsonSchema, X_DMN_TYPE }
from "@kie-tools/extended-services-api";
+import { DmnInputFieldProperties, ExtendedServicesFormSchema, X_DMN_TYPE }
from "@kie-tools/extended-services-api";
import { DAYS_AND_TIME_DURATION_FORMAT, YEARS_AND_MONTHS_DURATION_FORMAT }
from "@kie-tools/dmn-runner/dist/dmnFormats";
+import type { JSONSchema4 } from "json-schema";
export enum Duration {
DaysAndTimeDuration,
@@ -28,9 +29,9 @@ export enum Duration {
}
export class FormDmnJsonSchemaBridge extends FormJsonSchemaBridge {
- schema: ExtendedServicesDmnJsonSchema;
+ schema: ExtendedServicesFormSchema;
- constructor(formSchema: ExtendedServicesDmnJsonSchema, validator: (model:
object) => void, i18n: FormDmnI18n) {
+ constructor(formSchema: JSONSchema4, validator: (model: object) => void,
i18n: FormDmnI18n) {
super(formSchema, validator, i18n);
this.i18n = i18n;
}
diff --git a/packages/form-dmn/tests/FormDmn.test.tsx
b/packages/form-dmn/tests/FormDmn.test.tsx
index 32ae368f6b5..80a30f3d3f4 100644
--- a/packages/form-dmn/tests/FormDmn.test.tsx
+++ b/packages/form-dmn/tests/FormDmn.test.tsx
@@ -20,11 +20,11 @@
import * as React from "react";
import { act, render } from "@testing-library/react";
import { FormDmn, InputRow } from "../src";
-import { ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
import { formDmnI18n } from "../src/i18n";
import { FormComponentProps } from "@kie-tools/form";
+import type { JSONSchema4 } from "json-schema";
-const schema: any = {
+const schema: JSONSchema4 = {
$ref: "#/definitions/InputSet",
definitions: {
InputSet: {
@@ -39,7 +39,7 @@ const schema: any = {
},
};
-const props: FormComponentProps<InputRow, ExtendedServicesDmnJsonSchema> = {
+const props: FormComponentProps<InputRow, JSONSchema4> = {
i18n: formDmnI18n.getCurrent(),
formInputs: {},
setFormInputs: jest.fn(),
diff --git a/packages/form-dmn/tests/FormDmnValidator.test.ts
b/packages/form-dmn/tests/FormDmnValidator.test.ts
index 3ef9e419be3..758aabbfffa 100644
--- a/packages/form-dmn/tests/FormDmnValidator.test.ts
+++ b/packages/form-dmn/tests/FormDmnValidator.test.ts
@@ -17,12 +17,12 @@
* under the License.
*/
-import { ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
import { FormDmnValidator } from "../src/FormDmnValidator";
import { formDmnI18n } from "../src/i18n";
import { FormDmnJsonSchemaBridge } from "../src/uniforms";
+import type { JSONSchema4 } from "json-schema";
-const schema: ExtendedServicesDmnJsonSchema = {
+const schema: JSONSchema4 = {
definitions: {
InputSet: {
type: "object",
diff --git a/packages/online-editor/package.json
b/packages/online-editor/package.json
index 4ddd298dea1..a839ff3463c 100644
--- a/packages/online-editor/package.json
+++ b/packages/online-editor/package.json
@@ -57,6 +57,7 @@
"@kie-tools/unitables-dmn": "workspace:*",
"@octokit/plugin-rest-endpoint-methods": "^5.0.1",
"@octokit/rest": "^18.5.3",
+ "@openapi-contrib/openapi-schema-to-json-schema": "^5.1.0",
"@patternfly/react-core": "^4.276.6",
"@patternfly/react-icons": "^4.93.6",
"@patternfly/react-tokens": "^4.94.6",
@@ -96,6 +97,7 @@
"@testing-library/react": "^11.2.6",
"@types/history": "^4.7.3",
"@types/js-yaml": "^4.0.5",
+ "@types/json-schema": "^7.0.11",
"@types/lodash": "^4.14.168",
"@types/react": "^17.0.6",
"@types/react-dom": "^17.0.5",
diff --git a/packages/online-editor/src/dmnRunner/DmnRunnerContext.tsx
b/packages/online-editor/src/dmnRunner/DmnRunnerContext.tsx
index 8a641233073..7812fb0ae62 100644
--- a/packages/online-editor/src/dmnRunner/DmnRunnerContext.tsx
+++ b/packages/online-editor/src/dmnRunner/DmnRunnerContext.tsx
@@ -23,8 +23,9 @@ import { DmnRunnerPersistenceJson } from
"../dmnRunnerPersistence/DmnRunnerPersi
import { DmnRunnerMode, DmnRunnerStatus } from "./DmnRunnerStatus";
import { UnitablesInputsConfigs } from "@kie-tools/unitables";
import { InputRow } from "@kie-tools/form-dmn";
-import { DecisionResult, ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
+import { DecisionResult } from "@kie-tools/extended-services-api";
import { DmnRunnerProviderAction } from "./DmnRunnerTypes";
+import type { JSONSchema4 } from "json-schema";
export interface DmnRunnerContextType {
configs: UnitablesInputsConfigs;
@@ -35,7 +36,7 @@ export interface DmnRunnerContextType {
inputs: Array<InputRow>;
isExpanded: boolean;
canBeVisualized: boolean;
- jsonSchema?: ExtendedServicesDmnJsonSchema;
+ jsonSchema?: JSONSchema4;
mode: DmnRunnerMode;
results: Array<DecisionResult[] | undefined>;
resultsDifference: Array<Array<object>>;
diff --git a/packages/online-editor/src/dmnRunner/DmnRunnerContextProvider.tsx
b/packages/online-editor/src/dmnRunner/DmnRunnerContextProvider.tsx
index 02b2e41bc07..7cb82c0e04e 100644
--- a/packages/online-editor/src/dmnRunner/DmnRunnerContextProvider.tsx
+++ b/packages/online-editor/src/dmnRunner/DmnRunnerContextProvider.tsx
@@ -35,14 +35,8 @@ import { ExtendedServicesStatus } from
"../extendedServices/ExtendedServicesStat
import { usePrevious } from "@kie-tools-core/react-hooks/dist/usePrevious";
import { useExtendedServices } from
"../extendedServices/ExtendedServicesContext";
import { InputRow } from "@kie-tools/form-dmn";
-import {
- DecisionResult,
- ExtendedServicesDmnJsonSchema,
- DmnEvaluationMessages,
- ExtendedServicesModelPayload,
-} from "@kie-tools/extended-services-api";
+import { DecisionResult, DmnEvaluationMessages, ExtendedServicesModelPayload }
from "@kie-tools/extended-services-api";
import { DmnRunnerAjv } from "@kie-tools/dmn-runner/dist/ajv";
-import { SCHEMA_DRAFT4 } from "@kie-tools/dmn-runner/dist/jsonSchemaConstants";
import { useDmnRunnerPersistence } from
"../dmnRunnerPersistence/DmnRunnerPersistenceHook";
import { DmnLanguageService } from "@kie-tools/dmn-language-service";
import { decoder } from
"@kie-tools-core/workspaces-git-fs/dist/encoderdecoder/EncoderDecoder";
@@ -72,11 +66,13 @@ import { Text, TextContent } from
"@patternfly/react-core/dist/js/components/Tex
import { ExclamationIcon } from
"@patternfly/react-icons/dist/js/icons/exclamation-icon";
import { diff } from "deep-object-diff";
import {
- resolveReferencesAndCheckForRecursion,
+ dereferenceAndCheckForRecursion,
removeChangedPropertiesAndAdditionalProperties,
getDefaultValues,
} from "@kie-tools/dmn-runner/dist/jsonSchema";
import { extractDifferencesFromArray } from
"@kie-tools/dmn-runner/dist/results";
+import { openapiSchemaToJsonSchema } from
"@openapi-contrib/openapi-schema-to-json-schema";
+import type { JSONSchema4 } from "json-schema";
interface Props {
isEditorReady?: boolean;
@@ -138,7 +134,7 @@ export function DmnRunnerContextProvider(props:
PropsWithChildren<Props>) {
// States that are in control of the DmnRunnerProvider;
const [canBeVisualized, setCanBeVisualized] = useState<boolean>(false);
const [extendedServicesError, setExtendedServicesError] =
useState<boolean>(false);
- const [jsonSchema, setJsonSchema] = useState<ExtendedServicesDmnJsonSchema |
undefined>(undefined);
+ const [jsonSchema, setJsonSchema] = useState<JSONSchema4 |
undefined>(undefined);
const [{ results, resultsDifference }, setDmnRunnerResults] = useReducer(
dmnRunnerResultsReducer,
initialDmnRunnerResults
@@ -321,6 +317,7 @@ export function DmnRunnerContextProvider(props:
PropsWithChildren<Props>) {
}
// it should exec only when the relativePath changes;
+ // eslint-disable-next-line
}, [props.workspaceFile.relativePath]);
useLayoutEffect(() => {
@@ -538,30 +535,29 @@ export function DmnRunnerContextProvider(props:
PropsWithChildren<Props>) {
if (canceled.get() || modelPayload === undefined) {
return;
}
- extendedServices.client.formSchema(modelPayload).then((jsonSchema)
=> {
+ extendedServices.client.formSchema(modelPayload).then((formSchema)
=> {
if (canceled.get()) {
return;
}
- const jsonSchemaDraft4 = {
- $schema: SCHEMA_DRAFT4,
- ...jsonSchema,
- };
-
- resolveReferencesAndCheckForRecursion(jsonSchemaDraft4, canceled)
- .then((resolvedSchema) => {
- if (canceled.get() || !resolvedSchema) {
+ dereferenceAndCheckForRecursion(formSchema, canceled)
+ .then((dereferencedOpenApiSchema) => {
+ if (canceled.get() || !dereferencedOpenApiSchema) {
return;
}
+ const jsonSchema =
openapiSchemaToJsonSchema(dereferencedOpenApiSchema, {
+ definitionKeywords: ["definitions"],
+ });
+
setJsonSchema((previousJsonSchema) => {
// Early bailout in the DMN first render;
// This prevents to set the inputs from the previous DMN
if (!previousJsonSchema) {
- return resolvedSchema;
+ return jsonSchema;
}
- const validateInputs =
dmnRunnerAjv.compile(resolvedSchema);
+ const validateInputs = dmnRunnerAjv.compile(jsonSchema);
// Add default values and delete changed data types;
setDmnRunnerPersistenceJson({
@@ -575,17 +571,17 @@ export function DmnRunnerContextProvider(props:
PropsWithChildren<Props>) {
const id = input.id;
removeChangedPropertiesAndAdditionalProperties(validateInputs, input);
input.id = id;
- return { ...getDefaultValues(resolvedSchema),
...input };
+ return { ...getDefaultValues(jsonSchema), ...input };
});
},
cancellationToken: canceled,
});
// This should be done to remove any previous errors or to
add new errors
- if (Object.keys(diff(previousJsonSchema,
resolvedSchema)).length > 0) {
+ if (Object.keys(diff(previousJsonSchema,
jsonSchema)).length > 0) {
forceDmnRunnerReRender();
}
- return resolvedSchema;
+ return jsonSchema;
});
})
.catch((err) => {
diff --git a/packages/online-editor/src/dmnRunner/DmnRunnerTypes.ts
b/packages/online-editor/src/dmnRunner/DmnRunnerTypes.ts
index 9692269c821..07e13471b54 100644
--- a/packages/online-editor/src/dmnRunner/DmnRunnerTypes.ts
+++ b/packages/online-editor/src/dmnRunner/DmnRunnerTypes.ts
@@ -17,8 +17,9 @@
* under the License.
*/
-import { DecisionResult, ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
+import { DecisionResult } from "@kie-tools/extended-services-api";
import { DmnRunnerPersistenceJson } from
"../dmnRunnerPersistence/DmnRunnerPersistenceTypes";
+import type { JSONSchema4 } from "json-schema";
export interface DmnRunnerResults {
results: Array<DecisionResult[] | undefined>;
@@ -66,6 +67,6 @@ export type DmnRunnerProviderAction =
| DmnRunnerProviderActionToggleExpanded;
export interface DmnRunnerCompanionRefreshCallback {
- jsonSchema?: ExtendedServicesDmnJsonSchema;
+ jsonSchema?: JSONSchema4;
dmnRunnerPersistenceJson?: DmnRunnerPersistenceJson;
}
diff --git
a/packages/online-editor/src/extendedServices/ExtendedServicesClient.ts
b/packages/online-editor/src/extendedServices/ExtendedServicesClient.ts
index 532774454cd..d1ba495e478 100644
--- a/packages/online-editor/src/extendedServices/ExtendedServicesClient.ts
+++ b/packages/online-editor/src/extendedServices/ExtendedServicesClient.ts
@@ -19,7 +19,7 @@
import {
ExtendedServicesDmnResult,
- ExtendedServicesDmnJsonSchema,
+ ExtendedServicesFormSchema,
ExtendedServicesValidateResponse,
ExtendedServicesModelPayload,
} from "@kie-tools/extended-services-api";
@@ -83,7 +83,7 @@ export class ExtendedServicesClient {
return await response.json();
}
- public async formSchema(payload: ExtendedServicesModelPayload):
Promise<ExtendedServicesDmnJsonSchema> {
+ public async formSchema(payload: ExtendedServicesModelPayload):
Promise<ExtendedServicesFormSchema> {
if (!this.isPayloadValid(payload)) {
return {};
}
diff --git a/packages/uniforms-patternfly/src/SelectField.tsx
b/packages/uniforms-patternfly/src/SelectField.tsx
index 0f8ca0c8f17..5e9622b857e 100644
--- a/packages/uniforms-patternfly/src/SelectField.tsx
+++ b/packages/uniforms-patternfly/src/SelectField.tsx
@@ -39,13 +39,13 @@ export type SelectCheckboxProps = FieldProps<
>;
export type SelectInputProps = FieldProps<
- string | string[],
+ string | string[] | null,
SelectProps,
{
checkboxes?: boolean;
required?: boolean;
fieldType?: typeof Array;
- onChange: (value?: string | string[] | number | number[]) => void;
+ onChange: (value?: string | string[] | number | number[] | null) => void;
placeholder?: string;
allowedValues?: (string | number)[];
disabled?: boolean;
diff --git a/packages/uniforms-patternfly/src/SelectInputsField.tsx
b/packages/uniforms-patternfly/src/SelectInputsField.tsx
index aefd5fa4bf2..0ebb33373d8 100644
--- a/packages/uniforms-patternfly/src/SelectInputsField.tsx
+++ b/packages/uniforms-patternfly/src/SelectInputsField.tsx
@@ -28,7 +28,7 @@ import {
import wrapField from "./wrapField";
import { SelectInputProps } from "./SelectField";
-type SelectFieldValue = string | string[] | number | number[];
+type SelectFieldValue = string | string[];
function isSelectOptionObject(
toBeDetermined: string | number | SelectOptionObject
@@ -36,42 +36,39 @@ function isSelectOptionObject(
return typeof toBeDetermined === "object" && !Array.isArray(toBeDetermined)
&& toBeDetermined !== null;
}
-function isSelectOptionString(toBeDetermined: string[] | number[]):
toBeDetermined is string[] {
- return (toBeDetermined.length > 0 && typeof toBeDetermined[0] === "string")
|| toBeDetermined.length === 0;
-}
-
function SelectInputsField(props: SelectInputProps) {
const [expanded, setExpanded] = useState<boolean>(false);
const [selected, setSelected] = useState<SelectFieldValue | undefined>(() =>
{
- if (!props.value) {
+ if (props.value === undefined) {
return [];
}
+ if (props.value === null) {
+ return "null";
+ }
if (Array.isArray(props.value)) {
return [...props.value];
}
return props.value;
});
- const parseInput = useCallback(
+ // Parses the selection to a string or string[]
+ // This prevents a bug where the number 0 can't be selected
+ const parseSelection = useCallback(
(selection: string | number | SelectOptionObject, fieldType: typeof
Array): SelectFieldValue => {
+ if (selection === null) {
+ return `${selection}`;
+ }
const parsedSelection = isSelectOptionObject(selection) ?
selection.toString() : selection;
if (fieldType !== Array) {
- return parsedSelection !== "" ? parsedSelection : "";
+ return parsedSelection !== "" ? `${parsedSelection}` : "";
}
if (Array.isArray(selected)) {
- if (isSelectOptionString(selected) && typeof parsedSelection ===
"string") {
- if (selected.includes(parsedSelection)) {
- return selected.filter((s) => s !== parsedSelection);
- }
- return [parsedSelection, ...selected];
- } else if (!isSelectOptionString(selected) && typeof parsedSelection
=== "number") {
- if (selected.includes(parsedSelection)) {
- return selected.filter((s) => s !== parsedSelection);
- }
- return [parsedSelection, ...selected];
+ if (selected.includes(`${parsedSelection}`)) {
+ return selected.filter((s) => s !== `${parsedSelection}`);
}
+ return [`${parsedSelection}`, ...selected];
}
return [];
},
@@ -79,18 +76,32 @@ function SelectInputsField(props: SelectInputProps) {
);
const handleSelect = useCallback(
- (event: React.MouseEvent | React.ChangeEvent, selection: string |
SelectOptionObject) => {
+ (event: React.MouseEvent | React.ChangeEvent, selection: string | number |
SelectOptionObject) => {
if (selection === props.placeholder) {
props.onChange(undefined);
setSelected([]);
} else {
- const items = parseInput(selection, props.fieldType);
- props.onChange(items);
- setSelected(items);
+ if (selection === "null") {
+ props.onChange(null);
+ setSelected("null");
+ } else {
+ const selectedItems = parseSelection(selection, props.fieldType);
+ // If the selection is a number we should convert the selectedItems
back to a number
+ const onChanged =
+ selection === null
+ ? null
+ : typeof selection === "number"
+ ? Array.isArray(selectedItems)
+ ? selectedItems.map((item) => JSON.parse(item))
+ : JSON.parse(selectedItems)
+ : selectedItems;
+ props.onChange(onChanged);
+ setSelected(selectedItems);
+ }
}
setExpanded(false);
},
- [parseInput, props]
+ [parseSelection, props]
);
const selectOptions = useMemo(() => {
@@ -103,7 +114,7 @@ function SelectInputsField(props: SelectInputProps) {
props.allowedValues?.forEach((value) =>
options.push(
<SelectOption key={value} value={value}>
- {props.transform ? props.transform(value) : value}
+ {props.transform ? props.transform(value) : `${value}`}
</SelectOption>
)
);
@@ -123,7 +134,6 @@ function SelectInputsField(props: SelectInputProps) {
selections={selected}
onToggle={(isExpanded) => setExpanded(isExpanded)}
onSelect={handleSelect}
- value={props.value || (props.fieldType === Array ? [] : undefined)}
menuAppendTo={props.menuAppendTo}
direction={props.direction}
>
diff --git a/packages/unitables-dmn/package.json
b/packages/unitables-dmn/package.json
index 5134f159eab..0e1d882a9b9 100644
--- a/packages/unitables-dmn/package.json
+++ b/packages/unitables-dmn/package.json
@@ -55,6 +55,7 @@
"@testing-library/jest-dom": "^5.16.1",
"@types/jest": "^26.0.23",
"@types/jest-when": "^2.7.4",
+ "@types/json-schema": "^7.0.11",
"@types/react": "^17.0.6",
"@types/testing-library__jest-dom": "^5.9.1",
"copyfiles": "^2.4.1",
diff --git a/packages/unitables-dmn/src/DmnUnitablesValidator.ts
b/packages/unitables-dmn/src/DmnUnitablesValidator.ts
index 4cb7066d568..714503c226f 100644
--- a/packages/unitables-dmn/src/DmnUnitablesValidator.ts
+++ b/packages/unitables-dmn/src/DmnUnitablesValidator.ts
@@ -20,10 +20,10 @@
import { DmnUnitablesJsonSchemaBridge } from
"./uniforms/DmnUnitablesJsonSchemaBridge";
import { DmnUnitablesI18n } from "./i18n";
import { DAYS_AND_TIME_DURATION_FORMAT, YEARS_AND_MONTHS_DURATION_FORMAT }
from "@kie-tools/dmn-runner/dist/dmnFormats";
-import { ExtendedServicesDmnJsonSchema } from
"@kie-tools/extended-services-api";
import { UnitablesValidator } from
"@kie-tools/unitables/dist/UnitablesValidator";
import { DmnRunnerAjv } from "@kie-tools/dmn-runner/dist/ajv";
import { SCHEMA_DRAFT4 } from "@kie-tools/dmn-runner/dist/jsonSchemaConstants";
+import type { JSONSchema4 } from "json-schema";
export class DmnUnitablesValidator extends UnitablesValidator {
protected readonly dmnRunnerAjv = new DmnRunnerAjv();
@@ -58,7 +58,7 @@ export class DmnUnitablesValidator extends UnitablesValidator
{
};
}
- public getBridge(formSchema: ExtendedServicesDmnJsonSchema):
DmnUnitablesJsonSchemaBridge {
+ public getBridge(formSchema: JSONSchema4): DmnUnitablesJsonSchemaBridge {
const formDraft4 = { ...formSchema, $schema: SCHEMA_DRAFT4 };
const validator = this.createValidator(formDraft4);
return new DmnUnitablesJsonSchemaBridge(formDraft4, validator, this.i18n);
diff --git
a/packages/unitables-dmn/src/uniforms/DmnUnitablesJsonSchemaBridge.ts
b/packages/unitables-dmn/src/uniforms/DmnUnitablesJsonSchemaBridge.ts
index bdfa03d1748..0450bc9e0a0 100644
--- a/packages/unitables-dmn/src/uniforms/DmnUnitablesJsonSchemaBridge.ts
+++ b/packages/unitables-dmn/src/uniforms/DmnUnitablesJsonSchemaBridge.ts
@@ -19,10 +19,10 @@
import { DAYS_AND_TIME_DURATION_FORMAT, YEARS_AND_MONTHS_DURATION_FORMAT }
from "@kie-tools/dmn-runner/dist/dmnFormats";
import { UnitablesJsonSchemaBridge } from "@kie-tools/unitables/dist/uniforms";
-import { DmnInputFieldProperties, ExtendedServicesDmnJsonSchema, X_DMN_TYPE }
from "@kie-tools/extended-services-api";
+import { DmnInputFieldProperties, ExtendedServicesFormSchema, X_DMN_TYPE }
from "@kie-tools/extended-services-api";
export class DmnUnitablesJsonSchemaBridge extends UnitablesJsonSchemaBridge {
- schema: ExtendedServicesDmnJsonSchema;
+ schema: ExtendedServicesFormSchema;
public getField(name: string) {
const field = super.getField(name) as DmnInputFieldProperties;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6403daf461f..6cb070d7484 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3180,6 +3180,9 @@ importers:
"@kie-tools/i18n-common-dictionary":
specifier: workspace:*
version: link:../i18n-common-dictionary
+ "@openapi-contrib/openapi-schema-to-json-schema":
+ specifier: ^5.1.0
+ version: 5.1.0
"@patternfly/react-core":
specifier: ^4.276.6
version: 4.276.6([email protected])([email protected])
@@ -3241,6 +3244,9 @@ importers:
"@types/jest-when":
specifier: ^2.7.4
version: 2.7.4
+ "@types/json-schema":
+ specifier: ^7.0.11
+ version: 7.0.15
"@types/lodash":
specifier: ^4.14.168
version: 4.14.169
@@ -3980,6 +3986,9 @@ importers:
"@types/jest":
specifier: ^26.0.23
version: 26.0.23
+ "@types/json-schema":
+ specifier: ^7.0.11
+ version: 7.0.15
"@types/lodash":
specifier: ^4.14.168
version: 4.14.169
@@ -4765,6 +4774,9 @@ importers:
"@types/jest-when":
specifier: ^2.7.4
version: 2.7.4
+ "@types/json-schema":
+ specifier: ^7.0.11
+ version: 7.0.15
"@types/lodash":
specifier: ^4.14.168
version: 4.14.169
@@ -6468,6 +6480,9 @@ importers:
"@octokit/rest":
specifier: ^18.5.3
version: 18.5.3
+ "@openapi-contrib/openapi-schema-to-json-schema":
+ specifier: ^5.1.0
+ version: 5.1.0
"@patternfly/react-core":
specifier: ^4.276.6
version: 4.276.6([email protected])([email protected])
@@ -6580,6 +6595,9 @@ importers:
"@types/js-yaml":
specifier: ^4.0.5
version: 4.0.5
+ "@types/json-schema":
+ specifier: ^7.0.11
+ version: 7.0.15
"@types/lodash":
specifier: ^4.14.168
version: 4.14.169
@@ -12139,6 +12157,9 @@ importers:
"@types/jest-when":
specifier: ^2.7.4
version: 2.7.4
+ "@types/json-schema":
+ specifier: ^7.0.11
+ version: 7.0.15
"@types/react":
specifier: ^17.0.6
version: 17.0.21
@@ -22211,6 +22232,12 @@ packages:
{ integrity:
sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==
}
dev: true
+ /@fastify/[email protected]:
+ resolution:
+ { integrity:
sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==
}
+ engines: { node: ">=14" }
+ dev: false
+
/@floating-ui/[email protected]:
resolution:
{ integrity:
sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==
}
@@ -23875,6 +23902,21 @@ packages:
engines: { node: ">=8.0" }
dev: true
+ /@openapi-contrib/[email protected]:
+ resolution:
+ { integrity:
sha512-MJnq+CxD8JAufiJoa8RK6D/8P45MEBe0teUi30TNoHRrI6MZRNgetK2Y2IfDXWGLTHMopb1d9GHonqlV2Yvztg==
}
+ engines: { node: ">=14.0.0" }
+ hasBin: true
+ dependencies:
+ "@types/json-schema": 7.0.15
+ "@types/lodash": 4.14.202
+ "@types/node": 20.12.12
+ fast-deep-equal: 3.1.3
+ lodash: 4.17.21
+ openapi-typescript: 5.4.2
+ yargs: 17.7.2
+ dev: false
+
/@patternfly/[email protected]:
resolution:
{ integrity:
sha512-HGNV26uyHSIECuhjPg/WGn0mXbAotcs6ODfhAOkfYjIgGylddgiwElxUe1rpEHV5mQJJ2rMn4OdeJIIpzRX61g==
}
@@ -26569,7 +26611,7 @@ packages:
{ integrity:
sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==
}
dependencies:
"@jsdevtools/ono": 7.1.3
- "@types/json-schema": 7.0.11
+ "@types/json-schema": 7.0.15
call-me-maybe: 1.0.2
js-yaml: 4.1.0
dev: false
@@ -29536,7 +29578,7 @@ packages:
{ integrity:
sha512-kUEPnMKrqbtpCq/KTaGFFKAcz6Ethm2EjCoKIDaCmfRBWLbFuTcOJfTlorwbnboXBzahqWLgUp1BQeKHiJzPUQ==
}
dependencies:
"@types/estree": 1.0.1
- "@types/json-schema": 7.0.11
+ "@types/json-schema": 7.0.15
dev: true
/@types/[email protected]:
@@ -29756,6 +29798,10 @@ packages:
resolution:
{ integrity:
sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
}
+ /@types/[email protected]:
+ resolution:
+ { integrity:
sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
}
+
/@types/[email protected]:
resolution:
{ integrity:
sha512-s2cfwagOQAS8o06TcwKfr9Wx11dNGbH2E9vJz1cqV+a/LOyhWNLUNd6JSRYNzvB4d29UuJX2M0Dj9vE1T8fRXw==
}
@@ -29880,6 +29926,13 @@ packages:
resolution:
{ integrity:
sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==
}
+ /@types/[email protected]:
+ resolution:
+ { integrity:
sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==
}
+ dependencies:
+ undici-types: 5.26.5
+ dev: false
+
/@types/[email protected]:
resolution:
{ integrity:
sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
}
@@ -30411,7 +30464,7 @@ packages:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
"@eslint-community/eslint-utils": 4.4.0([email protected])
- "@types/json-schema": 7.0.11
+ "@types/json-schema": 7.0.15
"@types/semver": 7.5.2
"@typescript-eslint/scope-manager": 5.62.0
"@typescript-eslint/types": 5.62.0
@@ -34213,7 +34266,6 @@ packages:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
- dev: true
/[email protected]:
resolution:
@@ -39354,6 +39406,11 @@ packages:
dependencies:
define-properties: 1.2.1
+ /[email protected]:
+ resolution:
+ { integrity:
sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==
}
+ dev: false
+
/[email protected]:
resolution:
{ integrity:
sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
}
@@ -39379,6 +39436,11 @@ packages:
slash: 4.0.0
dev: true
+ /[email protected]:
+ resolution:
+ { integrity:
sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==
}
+ dev: false
+
/[email protected]:
resolution:
{ integrity:
sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
}
@@ -43743,6 +43805,13 @@ packages:
engines: { node: ">=4.0.0" }
hasBin: true
+ /[email protected]:
+ resolution:
+ { integrity:
sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==
}
+ engines: { node: ">=10.0.0" }
+ hasBin: true
+ dev: false
+
/[email protected]:
resolution:
{ integrity:
sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
}
@@ -45119,6 +45188,20 @@ packages:
resolution:
{ integrity:
sha512-olbaNxz12R27+mTyJ/ZAFEfUruauHH27AkeQHDHRq5AF0LdNkK1SSV7EourXQDK+4aX7dv2HtyirAGK06WMAsA==
}
+ /[email protected]:
+ resolution:
+ { integrity:
sha512-tHeRv39Yh7brqJpbUntdjtUaXrTHmC4saoyTLU/0J2I8LEFQYDXRLgnmWTMiMOB2GXugJiqHa5n9sAyd6BRqiA==
}
+ engines: { node: ">= 14.0.0" }
+ hasBin: true
+ dependencies:
+ js-yaml: 4.1.0
+ mime: 3.0.0
+ prettier: 2.8.8
+ tiny-glob: 0.2.9
+ undici: 5.28.4
+ yargs-parser: 21.1.1
+ dev: false
+
/[email protected]:
resolution:
{ integrity:
sha512-9A5pqGoQk49H6Vhjb9kPgAeeECfUDF6aIICbMDL23kDLStBn1MWk3YvcZ4xWF9CsSf6XEgvRLkXy4xof/56vVw==
}
@@ -49372,7 +49455,7 @@ packages:
{ integrity:
sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
}
engines: { node: ">= 10.13.0" }
dependencies:
- "@types/json-schema": 7.0.11
+ "@types/json-schema": 7.0.15
ajv: 6.12.6
ajv-keywords: 3.5.2([email protected])
dev: true
@@ -49382,7 +49465,7 @@ packages:
{ integrity:
sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
}
engines: { node: ">= 10.13.0" }
dependencies:
- "@types/json-schema": 7.0.11
+ "@types/json-schema": 7.0.15
ajv: 6.12.6
ajv-keywords: 3.5.2([email protected])
dev: true
@@ -49392,7 +49475,7 @@ packages:
{ integrity:
sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==
}
engines: { node: ">= 12.13.0" }
dependencies:
- "@types/json-schema": 7.0.11
+ "@types/json-schema": 7.0.15
ajv: 8.12.0
ajv-formats: 2.1.1([email protected])
ajv-keywords: 5.1.0([email protected])
@@ -49403,7 +49486,7 @@ packages:
{ integrity:
sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==
}
engines: { node: ">= 12.13.0" }
dependencies:
- "@types/json-schema": 7.0.11
+ "@types/json-schema": 7.0.15
ajv: 8.12.0
ajv-formats: 2.1.1([email protected])
ajv-keywords: 5.1.0([email protected])
@@ -51270,6 +51353,14 @@ packages:
setimmediate: 1.0.5
dev: true
+ /[email protected]:
+ resolution:
+ { integrity:
sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==
}
+ dependencies:
+ globalyzer: 0.1.0
+ globrex: 0.1.2
+ dev: false
+
/[email protected]:
resolution:
{ integrity:
sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==
}
@@ -51522,7 +51613,7 @@ packages:
engines: { node: ">=10.0.0" }
hasBin: true
dependencies:
- "@types/json-schema": 7.0.11
+ "@types/json-schema": 7.0.15
commander: 9.4.1
glob: 8.0.3
json5: 2.2.1
@@ -51910,6 +52001,19 @@ packages:
resolution:
{ integrity:
sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==
}
+ /[email protected]:
+ resolution:
+ { integrity:
sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
}
+ dev: false
+
+ /[email protected]:
+ resolution:
+ { integrity:
sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==
}
+ engines: { node: ">=14.0" }
+ dependencies:
+ "@fastify/busboy": 2.1.1
+ dev: false
+
/[email protected]:
resolution:
{ integrity:
sha512-SPlDcde+AUHoFKeVlH2uBJxqVkw658I4WR2rPoygC1eRCzm3GeoP8S6xXZVJeBVOQQid8X2xUBW0N4tOvvHH3Q==
}
@@ -54111,7 +54215,6 @@ packages:
resolution:
{ integrity:
sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
}
engines: { node: ">=12" }
- dev: true
/[email protected]:
resolution:
@@ -54194,7 +54297,6 @@ packages:
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
- dev: true
/[email protected]:
resolution:
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]