Skip to content

Commit

Permalink
KOGITO-7671: [yard Editor] Deserialize YAML/JSON file to populate UI (#…
Browse files Browse the repository at this point in the history
…1288)

* KOGITO-7671: First draft

* KOGITO-7671: JSON / YAML deserialization added. Populated data in General and Input data

* KOGITO-7671: JSON / YAML deserialization added. Populated data in General and Input data

* KOGITO-7671: JSON / YAML deserialization added. Populated data in General and Input data

* KOGITO-7671: JSON / YAML deserialization added. Populated data in General and Input data and Element data

* KOGITO-7671: JSON / YAML deserialization added. Populated data in General and Input data

* Updated according to last repo changes

* Revert temporary pnpm version check

* Updated `pnpm-lock.yaml` file

* Revert wrong files
  • Loading branch information
yesamer authored Oct 21, 2022
1 parent eac1bb7 commit b51709e
Show file tree
Hide file tree
Showing 18 changed files with 416 additions and 96 deletions.
4 changes: 4 additions & 0 deletions packages/yard-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@
"@kie-tools-core/operating-system": "workspace:*",
"@kie-tools-core/patternfly-base": "workspace:*",
"@kie-tools-core/workspace": "workspace:*",
"@kie-tools/boxed-expression-component": "workspace:*",
"@kie-tools/i18n-common-dictionary": "workspace:*",
"@patternfly/react-core": "^4.157.3",
"@patternfly/react-icons": "^4.11.17",
"@types/js-yaml": "^4.0.5",
"csstype": "^3.0.11",
"js-yaml": "^4.1.0",
"json-schema": "^0.4.0",
"monaco-editor": "^0.33.0",
"monaco-yaml": "^4.0.0",
Expand All @@ -62,6 +65,7 @@
"@types/jest-when": "^2.7.4",
"@types/json-schema": "^7.0.11",
"@types/react": "^17.0.6",
"@types/react-dom": "^17.0.5",
"@types/testing-library__jest-dom": "^5.9.1",
"copy-webpack-plugin": "^8.1.1",
"copyfiles": "^2.4.1",
Expand Down
41 changes: 41 additions & 0 deletions packages/yard-editor/src/decision/DecisionDataTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Input } from "../model";

export const dataTypes = [
{ typeRef: "Undefined", name: "<Undefined>", isCustom: false },
{ typeRef: "Any", name: "Any", isCustom: false },
{ typeRef: "Boolean", name: "boolean", isCustom: false },
{ typeRef: "Context", name: "context", isCustom: false },
{ typeRef: "Date", name: "date", isCustom: false },
{ typeRef: "DateTime", name: "date and time", isCustom: false },
{ typeRef: "DateTimeDuration", name: "days and time duration", isCustom: false },
{ typeRef: "Number", name: "number", isCustom: false },
{ typeRef: "String", name: "string", isCustom: false },
{ typeRef: "Time", name: "time", isCustom: false },
{ typeRef: "YearsMonthsDuration", name: "years and months duration", isCustom: false },
];

export function generateDecisionTypes(input: Input[]) {
const types: { typeRef: string; name: string; isCustom: boolean }[] = [];
dataTypes.forEach((val) => types.push(Object.assign({}, val)));
input.forEach((input) => {
types.push({ typeRef: input.name, name: input.name, isCustom: true });
});

return types;
}
78 changes: 78 additions & 0 deletions packages/yard-editor/src/decision/DecisionExpressionDefinitions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Element } from "../model";
import { DecisionTableProps, LogicType } from "@kie-tools/boxed-expression-component/dist/api";
import {
Clause,
DataType,
DecisionTableRule,
ExpressionProps,
LiteralExpressionProps,
} from "@kie-tools/boxed-expression-component/dist/api";

export function generateDecisionExpressionDefinition(element: Element): ExpressionProps {
const decisionType = element.logic.type;

switch (decisionType) {
case "DecisionTable":
const inputClauses = element.logic.inputs?.map((input) => generateClause(input));
const outputClauses = element.logic.outputComponents?.map((output) => generateClause(output));
return {
annotations: [{ name: "annotation-1a", id: "111" }],
dataType: DataType.Any,
input: inputClauses,
logicType: LogicType.DecisionTable,
name: element.name,
output: outputClauses,
rules: generateDecisionTableRule(element.logic.rules!, element.logic.inputs?.length),
} as DecisionTableProps;
case "LiteralExpression":
return {
dataType: DataType.Any,
name: element.name,
logicType: LogicType.LiteralExpression,
content: element.logic.expression,
} as LiteralExpressionProps;
default:
return {};
}
}

function generateClause(clauseName: string): Clause {
return {
id: clauseName + Math.floor(Math.random() * 6) + 1,
name: clauseName,
dataType: DataType.Any,
} as Clause;
}

function generateDecisionTableRule(rules: string[][], inputLength: number | undefined): DecisionTableRule[] {
const l = inputLength ? inputLength : 0;
const decisionTableRules: DecisionTableRule[] = [];
let index = 0;
rules.map((rule) => {
decisionTableRules.push({
annotationEntries: [""],
id: index.toString(),
inputEntries: rule.slice(0, l),
outputEntries: rule.slice(l),
});
index++;
});

return decisionTableRules;
}
18 changes: 18 additions & 0 deletions packages/yard-editor/src/decision/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export * from "./DecisionDataTypes";
export * from "./DecisionExpressionDefinitions";
29 changes: 12 additions & 17 deletions packages/yard-editor/src/editor/YardEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { ChannelType, EditorTheme, StateControlCommand } from "@kie-tools-core/e
import { editor } from "monaco-editor";
import { I18nDictionariesProvider } from "@kie-tools-core/i18n/dist/react-components";
import { YardUIEditor } from "../uiEditor";
import { YardFile } from "../types";
import "./YardEditor.css";

interface Props {
Expand Down Expand Up @@ -62,16 +63,11 @@ export type YardEditorRef = {
setContent(path: string, content: string): Promise<void>;
};

type YardEditorContent = {
originalContent: string;
path: string;
};

const RefForwardingYardEditor: React.ForwardRefRenderFunction<YardEditorRef | undefined, Props> = (
props,
forwardedRef
) => {
const [initialContent, setInitialContent] = useState<YardEditorContent | undefined>(undefined);
const [file, setFile] = useState<YardFile | undefined>(undefined);
const yardTextEditorRef = useRef<YardTextEditorApi>(null);

useImperativeHandle(
Expand All @@ -80,8 +76,8 @@ const RefForwardingYardEditor: React.ForwardRefRenderFunction<YardEditorRef | un
return {
setContent: (path: string, newContent: string): Promise<void> => {
try {
setInitialContent({
originalContent: newContent,
setFile({
content: newContent,
path: path,
});
return Promise.resolve();
Expand Down Expand Up @@ -115,12 +111,12 @@ const RefForwardingYardEditor: React.ForwardRefRenderFunction<YardEditorRef | un

const setValidationErrors = useCallback(
(errors: editor.IMarker[]) => {
if (!initialContent) {
if (!file) {
return;
}
const notifications: Notification[] = errors.map((error: editor.IMarker) => ({
type: "PROBLEM",
path: initialContent.path,
path: file.path,
severity: "ERROR",
message: `${error.message}`,
position: {
Expand All @@ -130,9 +126,9 @@ const RefForwardingYardEditor: React.ForwardRefRenderFunction<YardEditorRef | un
endColumn: error.endColumn,
},
}));
props.setNotifications.apply(initialContent.path, notifications);
props.setNotifications.apply(file.path, notifications);
},
[initialContent, props.setNotifications]
[file, props.setNotifications]
);

const isVscode = useCallback(() => {
Expand Down Expand Up @@ -168,18 +164,17 @@ const RefForwardingYardEditor: React.ForwardRefRenderFunction<YardEditorRef | un

const yardTextEditor = useMemo(
() =>
initialContent && (
file && (
<YardTextEditor
channelType={props.channelType}
content={initialContent.originalContent}
fileName={initialContent.path}
file={file}
onContentChange={onContentChanged}
setValidationErrors={setValidationErrors}
ref={yardTextEditorRef}
isReadOnly={props.isReadOnly}
/>
),
[initialContent, props.channelType, onContentChanged, setValidationErrors, props.isReadOnly]
[file, props.channelType, onContentChanged, setValidationErrors, props.isReadOnly]
);

const yardUIContainer = (
Expand All @@ -189,7 +184,7 @@ const RefForwardingYardEditor: React.ForwardRefRenderFunction<YardEditorRef | un
initialLocale={navigator.language}
ctx={YardEditorI18nContext}
>
<YardUIEditor />
<YardUIEditor file={file} isReadOnly={true} />
</I18nDictionariesProvider>
);

Expand Down
6 changes: 0 additions & 6 deletions packages/yard-editor/src/editor/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@
* limitations under the License.
*/

.divider {
width: 6px;
height: auto;
display: inline-block;
}

.monaco-editor {
padding-left: 4px;
}
4 changes: 2 additions & 2 deletions packages/yard-editor/src/i18n/YardEditorI18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ import { CommonI18n } from "@kie-tools/i18n-common-dictionary";

interface YardEditorDictionary extends ReferenceDictionary {
decisionElementsTab: {
addDecisionElementsButton: string;
emptyStateTitle: string;
emptyStateBody: string;
removeDecisionElementButton: string;
tabTitle: string;
};
decisionInputsTab: {
emptyStateTitle: string;
emptyStateBody: string;
name: string;
tabTitle: string;
type: string;
};
generalTab: {
expressionLang: string;
Expand Down
4 changes: 2 additions & 2 deletions packages/yard-editor/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ import { en as en_common } from "@kie-tools/i18n-common-dictionary";
export const en: YardEditorI18n = {
...en_common,
decisionElementsTab: {
addDecisionElementsButton: "Add Element",
emptyStateBody: "Your yard file doesn't have any Decision element. Please add a new element",
emptyStateTitle: "No decision elements",
removeDecisionElementButton: "Remove Element",
tabTitle: "Decision Elements",
},
decisionInputsTab: {
emptyStateBody: "Your yard file doesn't have any Decision input. Please add a new input",
emptyStateTitle: "No decision input",
name: "Name",
tabTitle: "Decision Inputs",
type: "Type",
},
generalTab: {
expressionLang: "Expression language version",
Expand Down
48 changes: 48 additions & 0 deletions packages/yard-editor/src/model/YardModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export class YardModel {
expressionLang: string;
kind: string;
inputs: Input[];
elements: Element[];
name: string;
specVersion: string;

constructor(model: any) {
Object.assign(this, model);
}
}

export class Element {
logic: Logic;
name: string;
requirements: string[];
type: string;
}

export class Input {
name: string;
type: string;
}

export class Logic {
inputs?: string[];
expression?: string;
outputComponents?: string[];
rules?: string[][];
type: string;
}
32 changes: 32 additions & 0 deletions packages/yard-editor/src/model/YardSerializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as yaml from "js-yaml";
import { YardModel } from "./YardModel";

/**
* It deserializes content string as YardModel object
* @param {string} content The JSON or YAML yard source to deserialize
* @returns {YardModel} Resulting object representation of yard model
*/
export function deserialize(content: string): YardModel {
try {
const model = yaml.load(content);
return new YardModel(model);
} catch (e) {
throw new Error("Error during deserialize phase of yard model" + e.toString());
}
}
Loading

0 comments on commit b51709e

Please sign in to comment.