Skip to content

Commit

Permalink
KOGITO-9935: Extract common consumer runtime tools code to a reusable…
Browse files Browse the repository at this point in the history
… package (#2066)

Co-authored-by: Paulo Martins <[email protected]>
  • Loading branch information
caponetto and paulovmr authored Nov 27, 2023
1 parent 41c5641 commit e2e14be
Show file tree
Hide file tree
Showing 78 changed files with 1,870 additions and 2,208 deletions.
7 changes: 7 additions & 0 deletions packages/runtime-tools-gateway-api/src/gatewayApi/apis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,13 @@ export const getCustomWorkflowSchemaFromApi = async (
schema = (api as any).components.schemas[workflowName + "_input"];
}

// Components can contain the content of internal refs ($ref)
// This keeps the refs working while avoiding circular refs with the workflow itself
if (schema) {
const { [workflowName + "_input"]: _, components } = (api as any).components ?? {};
(schema as any)["components"] = components;
}

return schema ?? null;
};

Expand Down
27 changes: 27 additions & 0 deletions packages/runtime-tools-webapp-components/env/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

const { varsWithName, composeEnv } = require("@kie-tools-scripts/build-env");

module.exports = composeEnv([require("@kie-tools/root-env/env")], {
vars: varsWithName({}),
get env() {
return {};
},
});
38 changes: 38 additions & 0 deletions packages/runtime-tools-webapp-components/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

module.exports = {
globals: {
"ts-jest": {
tsconfig: "<rootDir>/tsconfig.json",
},
},
reporters: ["default", ["jest-junit", { outputFile: "./dist-tests/junit-report.xml" }]],
moduleDirectories: ["node_modules"],
moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
testRegex: "/tests/.*\\.test\\.(jsx?|tsx?)$",
transform: {
"^.+\\.jsx?$": ["babel-jest", { presets: [["@babel/env", { targets: { node: "current" } }], "@babel/react"] }],
"^.+\\.tsx?$": "ts-jest",
},
moduleNameMapper: {
"\\.(css|less|sass|scss)$": "<rootDir>/tests/__mocks__/styleMock.js",
},
setupFilesAfterEnv: ["./tests/jest.setup.ts"],
};
53 changes: 53 additions & 0 deletions packages/runtime-tools-webapp-components/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "@kie-tools/runtime-tools-webapp-components",
"version": "0.0.0",
"description": "",
"license": "Apache-2.0",
"keywords": [],
"homepage": "https://github.com/kiegroup/kie-tools",
"repository": {
"type": "git",
"url": "https://github.com/kiegroup/kie-tools.git"
},
"bugs": {
"url": "https://github.com/kiegroup/kie-tools/issues"
},
"types": "./dist/index.d.ts",
"main": "dist/index.js",
"files": [
"dist"
],
"scripts": {
"build:dev": "rimraf dist && tsc -p tsconfig.json",
"build:prod": "pnpm lint && rimraf dist && tsc -p tsconfig.json && pnpm test",
"lint": "run-script-if --bool \"$(build-env linters.run)\" --then \"kie-tools--eslint ./src\"",
"test": "run-script-if --ignore-errors \"$(build-env tests.ignoreFailures)\" --bool \"$(build-env tests.run)\" --then \"jest --silent --verbose --passWithNoTests\""
},
"dependencies": {
"@kie-tools/runtime-tools-components": "workspace:*",
"@kie-tools/runtime-tools-enveloped-components": "workspace:*",
"@kie-tools/runtime-tools-gateway-api": "workspace:*",
"@patternfly/react-core": "^4.276.6",
"apollo-cache-inmemory": "1.6.6",
"apollo-client": "2.6.10",
"apollo-link-http": "1.5.17",
"react": "^17.0.2"
},
"devDependencies": {
"@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"@babel/preset-react": "^7.16.0",
"@kie-tools/eslint": "workspace:*",
"@kie-tools/root-env": "workspace:*",
"@kie-tools/tsconfig": "workspace:*",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^11.2.6",
"@types/jest": "^26.0.23",
"@types/react": "^17.0.6",
"@types/testing-library__jest-dom": "^5.9.1",
"@types/testing-library__react": "^9.1.2",
"jest": "^26.6.3",
"rimraf": "^3.0.2",
"typescript": "^4.6.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,44 @@
* under the License.
*/

import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Card, CardBody } from "@patternfly/react-core/dist/js/components/Card";
import { PageSection } from "@patternfly/react-core/dist/js/components/Page";
import React, { useEffect, useState } from "react";
import { FormNotification, Notification } from "@kie-tools/runtime-tools-components/dist/components/FormNotification";
import {
OUIAProps,
ouiaPageTypeAndObjectId,
componentOuiaProps,
ouiaPageTypeAndObjectId,
} from "@kie-tools/runtime-tools-components/dist/ouiaTools";
import { FormNotification, Notification } from "@kie-tools/runtime-tools-components/dist/components/FormNotification";
import { useHistory } from "react-router-dom";
import CloudEventFormContainer from "../CloudEventFormContainer/CloudEventFormContainer";
import { Card, CardBody } from "@patternfly/react-core/dist/js/components/Card";
import { PageSection } from "@patternfly/react-core/dist/js/components/Page";
import { Text, TextContent, TextVariants } from "@patternfly/react-core/dist/js/components/Text";
import { CloudEventFormContainer } from "../CloudEventFormContainer/CloudEventFormContainer";

interface CloudEventFormProps {
instanceId?: string;
cloudEventSource: string;
isTriggerNewInstance: boolean;
onStartWorkflowError: (error: any) => void;
onTriggerCloudEventSuccess: () => void;
onTriggerStartCloudEventSuccess: (businessKey: string) => void;
}

export enum CloudEventPageSource {
DEFINITIONS = "definitions",
INSTANCES = "instances",
}

const CloudEventForm: React.FC<OUIAProps> = ({ ouiaId, ouiaSafe }) => {
export const CloudEventForm: React.FC<CloudEventFormProps & OUIAProps> = ({
instanceId,
isTriggerNewInstance,
cloudEventSource,
onStartWorkflowError,
onTriggerCloudEventSuccess,
onTriggerStartCloudEventSuccess,
ouiaId,
ouiaSafe,
}) => {
const [notification, setNotification] = useState<Notification>();

const history = useHistory();

const isTriggerNewInstance = useMemo(() => {
const source = (history?.location?.state as any)["source"];
return source === CloudEventPageSource.DEFINITIONS;
}, [history]);

useEffect(() => {
return ouiaPageTypeAndObjectId("trigger-cloud-event-form");
}, []);
Expand All @@ -69,12 +79,17 @@ const CloudEventForm: React.FC<OUIAProps> = ({ ouiaId, ouiaSafe }) => {
>
<Card className="Dev-ui__card-size">
<CardBody className="pf-u-h-100">
<CloudEventFormContainer isTriggerNewInstance={isTriggerNewInstance} />
<CloudEventFormContainer
instanceId={instanceId}
isTriggerNewInstance={isTriggerNewInstance}
cloudEventSource={cloudEventSource}
onStartWorkflowError={onStartWorkflowError}
onTriggerCloudEventSuccess={onTriggerCloudEventSuccess}
onTriggerStartCloudEventSuccess={onTriggerStartCloudEventSuccess}
/>
</CardBody>
</Card>
</PageSection>
</React.Fragment>
);
};

export default CloudEventForm;
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,15 @@
import React, { useMemo } from "react";
import CloudEventFormContext from "./CloudEventFormContext";
import { CloudEventFormGatewayApiImpl } from "./CloudEventFormGatewayApi";
import { useSettings } from "../../../settings/SettingsContext";
import { useEnv } from "../../../env/EnvContext";

export function CloudEventFormContextProvider(props: React.PropsWithChildren<{}>) {
const settings = useSettings();
const { env } = useEnv();
export function CloudEventFormContextProvider(
props: React.PropsWithChildren<{ proxyEndpoint?: string; kogitoServiceUrl: string }>
) {
const { proxyEndpoint, kogitoServiceUrl } = props;

const gatewayApi = useMemo(
() =>
new CloudEventFormGatewayApiImpl(
settings.runtimeTools.config.kogitoServiceUrl,
env.SERVERLESS_LOGIC_WEB_TOOLS_CORS_PROXY_URL
),
[settings, env]
() => new CloudEventFormGatewayApiImpl(kogitoServiceUrl, proxyEndpoint),
[proxyEndpoint, kogitoServiceUrl]
);

return <CloudEventFormContext.Provider value={gatewayApi}>{props.children}</CloudEventFormContext.Provider>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
* under the License.
*/

import { CloudEventRequest } from "@kie-tools/runtime-tools-gateway-api/dist/types";
import { triggerCloudEvent, triggerStartCloudEvent } from "@kie-tools/runtime-tools-gateway-api/dist/gatewayApi";
import { CloudEventRequest } from "@kie-tools/runtime-tools-gateway-api/dist/types";

export interface CloudEventFormGatewayApi {
triggerStartCloudEvent(event: CloudEventRequest): Promise<string>;
triggerCloudEvent(event: CloudEventRequest): Promise<any>;
}

export class CloudEventFormGatewayApiImpl implements CloudEventFormGatewayApi {
constructor(private readonly baseUrl: string, private readonly proxyEndpoint: string) {}
constructor(private readonly baseUrl: string, private readonly proxyEndpoint?: string) {}

async triggerStartCloudEvent(event: CloudEventRequest): Promise<string> {
const response = await triggerStartCloudEvent(event, this.baseUrl, this.proxyEndpoint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/

export { CloudEventFormGatewayApi } from "./CloudEventFormGatewayApi";
export * from "./CloudEventFormContext";
export * from "./CloudEventForm";
export { default as CloudEventFormContextProvider } from "./CloudEventFormContextProvider";
export { CloudEventFormGatewayApi } from "./CloudEventFormGatewayApi";
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 React, { useCallback } from "react";
import { componentOuiaProps, OUIAProps } from "@kie-tools/runtime-tools-components/dist/ouiaTools";
import { useCloudEventFormGatewayApi } from "../CloudEventForm";
import { EmbeddedCloudEventForm } from "@kie-tools/runtime-tools-enveloped-components/dist/cloudEventForm";
import { CloudEventRequest } from "@kie-tools/runtime-tools-gateway-api/dist/types";

interface CloudEventFormContainerProps {
instanceId?: string;
cloudEventSource: string;
isTriggerNewInstance: boolean;
onStartWorkflowError: (error: any) => void;
onTriggerCloudEventSuccess: () => void;
onTriggerStartCloudEventSuccess: (businessKey: string) => void;
}

export const CloudEventFormContainer: React.FC<CloudEventFormContainerProps & OUIAProps> = ({
instanceId,
cloudEventSource,
isTriggerNewInstance,
onStartWorkflowError,
onTriggerCloudEventSuccess,
onTriggerStartCloudEventSuccess,
ouiaId,
ouiaSafe,
}) => {
const gatewayApi = useCloudEventFormGatewayApi();

const triggerStartCloudEvent = useCallback(
(event: CloudEventRequest) => {
return gatewayApi
.triggerStartCloudEvent(event)
.then((businessKey) => {
onTriggerStartCloudEventSuccess(businessKey);
})
.catch((error) => onStartWorkflowError(error));
},
[gatewayApi, onStartWorkflowError, onTriggerStartCloudEventSuccess]
);

const triggerCloudEvent = useCallback(
(event: CloudEventRequest) => {
return gatewayApi
.triggerCloudEvent(event)
.then((_response) => {
onTriggerCloudEventSuccess();
})
.catch((error) => onStartWorkflowError(error));
},
[gatewayApi, onStartWorkflowError, onTriggerCloudEventSuccess]
);

return (
<EmbeddedCloudEventForm
{...componentOuiaProps(ouiaId, "cloud-event-form-container", ouiaSafe)}
targetOrigin={window.location.origin}
isNewInstanceEvent={isTriggerNewInstance}
defaultValues={{ cloudEventSource, instanceId }}
driver={{
triggerCloudEvent(event: CloudEventRequest): Promise<void> {
const doTrigger = isTriggerNewInstance ? triggerStartCloudEvent : triggerCloudEvent;
return doTrigger(event);
},
}}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,4 @@
* under the License.
*/

export { WorkflowListGatewayApi } from "./WorkflowListGatewayApi";
export * from "./WorkflowListContext";
export { WorkflowListContextProvider } from "./WorkflowListContextProvider";
export * from "./CloudEventFormContainer";
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@
import React, { useMemo } from "react";
import { WorkflowDefinitionListContext } from "./WorkflowDefinitionListContext";
import { WorkflowDefinitionListGatewayApiImpl } from "./WorkflowDefinitionListGatewayApi";
import { useSettings } from "../../../settings/SettingsContext";

export function WorkflowDefinitionListContextProvider(props: React.PropsWithChildren<{}>) {
const settings = useSettings();
export function WorkflowDefinitionListContextProvider(props: React.PropsWithChildren<{ kogitoServiceUrl: string }>) {
const { kogitoServiceUrl } = props;

const gatewayApiImpl = useMemo(() => {
return new WorkflowDefinitionListGatewayApiImpl(settings.runtimeTools.config.kogitoServiceUrl, "q/openapi.json");
}, [settings]);
return new WorkflowDefinitionListGatewayApiImpl(kogitoServiceUrl, "q/openapi.json");
}, [kogitoServiceUrl]);

return (
<WorkflowDefinitionListContext.Provider value={gatewayApiImpl}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
* under the License.
*/

export { WorkflowDefinitionListGatewayApi } from "./WorkflowDefinitionListGatewayApi";
export * from "./WorkflowDefinitionListContext";
export { default as WorkflowDefinitionListContextProvider } from "./WorkflowDefinitionListContextProvider";
export { WorkflowDefinitionListGatewayApi } from "./WorkflowDefinitionListGatewayApi";
Loading

0 comments on commit e2e14be

Please sign in to comment.