Skip to main content

Case View

Introduction

note

The @flowable/case package has been renamed to @flowable/work-views from version 3.12.0. If you are using an older version please check the @flowable/case 3.11 Guide.

The Custom Case View described in the Modeler Guide can be used as a Standalone React component in your own React application or using the javascript API in any web site. If you are using the Work UI, you can also easily use the Case View in a custom Flow-App.

Using the Case View as a React Component

yarn add @flowable/work-views react react-dom
note

@flowable/work-views has as peer-dependencies: react and react-dom. In case of using TypeScript, probably you'll need to install also @types/react and @types/react-dom.

caution

Since @flowable/work-views@3.15.0 the peer-dependencies: react and react-dom have been upgrated to >=18

Sample

import React, { useState } from "react";
import { FlowableCase } from "@flowable/work-views";

import "@flowable/work-views/dist/index.css";

function App() {
return (
<FlowableCase caseInstanceId="CAS-5d814e01-74d6-11ea-8ff9-865e6ca862ad" />
);
}

export default App;
note

You need to import the FlowableWorkViews css to display it correctly, e.g. import '@flowable/work-views/dist/index.css'; as shown in the sample.

The FlowableCase component needs a case instance id always in order to render, this can be passed as a property or configuration parameter or as a parameter in the query url from where the component is rendered, i.e. your-url?caseInstanceId=my-case-instance-id. The component will try first to get the caseInstanceId from the component property, otherwise it will try to get the id from the query url, if non of them are provided the component will not render.

Using the Case View with the API

The steps outlined below guide you through integrating the flowable case view in either a Vanilla JavaScript or Angular web application. If your application is built using React, please refer to the section above.

The @flowable/work-views package exports a controller function that receives the options and returns a small API to render or destroy the component.

yarn add @flowable/work-views react react-dom
note

@flowable/work-views has as peer-dependencies: react and react-dom. In case of using TypeScript, probably you'll need to install also @types/react and @types/react-dom.

caution

Since @flowable/work-views@3.15.0 the peer-dependencies: react and react-dom have been upgrated to >=18

const { flowableCaseController } = require('@flowable/work-views');

import '@flowable/work-views/dist/index.css';

const options = {
caseInstanceId: 'CAS-75dc666f-f045-11eb-8228-4a72e6dc8dbb',
container: 'root',
urlParameter: 'flw',
fullScreen: false
};

let flwController = flowableCaseController({ ...options, ...features });
flwController.render();

...

onUpdate = () => {
flwController.update({ ...updatedOptions });
}

...

onDestroyClick = () => {
flwController.destroy();
}

Case View API

Case View Options

NameTypeDescriptionOptional

caseInstanceId

string

The case instance id

Yes (Default will try to read from URL param 'caseInstanceId')

showUserProfile

boolean

It will show user avatar in the top navigation bar

Yes (Default false)

topNavigationBar

boolean

It will show the top navigation bar with the logo

Yes (Default false)

fullScreen

boolean

It will show the case view using the whole screen

Yes (Default true)

container

string

The id of the DOM node where the case view will be rendered

Yes (Default empty)

hideNavigationElements

boolean

It will hide the left hand sidebar

Yes (Default false)

showLogin

boolean

It will show the Flowable Login form when the user is not authenticated

Yes (Default false)

urlParameter

string

It uses the string as URL parameter containing the routing state

Yes (Default empty)

disableRouting

boolean

It will disable url-based navigation

Yes (Default false)

note

If caseInstanceId is not provided through component props or options, there is fallback logic to read the id from the URL parameter caseInstanceId

note

In some cases, where you want to keep multiple case view instances and navigate trough them, you might need to disable the url-based navigation for the instances that are not being currently rendered. This can be done by updating disableRouting at runtime, using controller's update method (e.g. flwController.update({ disableRouting: !isVisible })).

Controller Methods

NameParametersDescriptionReturns

render

none

It will render the case view inside the provided container

void

update

object

It will update the case view options at runtime

void

destroy

none

It will destroy the case view instance

void

Rendering the Case View in a specific node container

Now you can render the Case View in any part of your web application when using the javascript API. Using the option container in your controller will render the case view in that specific node of the DOM. By default fullScreen is internally set to true when container is not provided. If fullScreen is set to false and no container is provided then the controller won't find the right place to render the case view.

Expanded

note

Providing a container id for your custom case view only makes sense using the javascript API, if you are using the React component, this will be rendered in the parent container when fullScreen is set to false, for backwards compatibility reasons fullscreen mode is the default behaviour when using the React component.

URL Routing

The case view has its own routing, in order to not break the routing of your web application, we provide an optional parameter that will be used as a string parameter in your application URL. The url parameter you specify with the option urlParameter will contain the routing information that the case view component needs to work properly.

const options = {
caseInstanceId: "CAS-75dc666f-f045-11eb-8228-4a72e6dc8dbb",
container: "root",
urlParameter: "flw",
fullScreen: false,
};

Expanded

Using the Flowable Login screen

Sometimes it might be useful to provide the standard login screen used in the Flowable Work UI. In order to add it, an optional parameter showLogin can be provided to replace the case view component by the Flowable Login, this will be automatically displayed when no user is authenticated in Flowable.

Expanded

Case View used from a FlowApp react component

This section assumes that the user knows already how to create custom FlowApp components described in this section.

Sample

import React from "react";

import { FlowableCase } from "@flowable/work-views";

const applications: ExternalApplication[] = [
{
applicationId: "customCase",
label: "Custom Case",
icon: "suitcase/solid",
component: (props: ExternalAppComponentProps) => (
<FlowableCase caseInstanceId="CAS-2d91d028-732b-11ea-8ff9-865e6ca862ad" />
),
},
];

export default { applications };

Common connectivity issues

Sometimes you might want to route the Flowable Work requests from the Case View component based on a particular query root, for instance to use a proxy.

If that is the case, the next global variable can be set, for instance in your index.html:

<script type="text/javascript">
window.flowable = window.flowable || {};
window.flowable.endpoints = { baseUrl: "/flowable" };
</script>

Proxy sample

const express = require('express');
const proxy = require('http-proxy-middleware');

const app = express();

app.use(
'/flowable-engage',
proxy({
context: ['/flowable-engage'],
target: 'http://localhost:8090',
ws: true,
logLevel: 'info',
xfwd: true,
//secure: false,
cookiePathRewrite: {
'*': '/'
}
})
);

...

Extending the custom case view

In the Flowable Front End developer guides we explain how to customize the embedded frontend extending your own form engine components, adding custom flow-apps or implementing your custom functions.

It is possible also, following similar patters, extend the custom case view with your own form components or additionalData. The main different step is that for your own application, you will need to inject the extensions as a script in your index.html, for example:

<script src="./extensions/dist/custom.js"></script>

In the sample above extensions it's just a folder in our custom web application, with a basic frontend scaffold to build the customizations using @flowable/work-scripts and following this guide.

This is the custom Text component:

import React, { useEffect } from "react";

const Text = ({ additionalData }: { additionalData: any }) => {
useEffect(() => {
if (additionalData?.log) {
additionalData.log("it works!");
}
}, []);

return <div>hello world!</div>;
};

const text = ["text", Text];

export default text;

And this is how we are exporting our module:

import text from "./text";

const formComponents = [text];
const additionalData = {
log: (data: string) => console.log(data),
};

export default {
formComponents,
additionalData,
};

You don't need to use @flowable/work-scripts to expose your extensions into the custom case view, the important part as explained in this how-to, is that the global window.flowable.externals object is present with your custom logic.

caution

Due to the fact that React cannot be injected globally in the custom logic, the bundle created from work-scripts tries to load React from the global window. In order to facilitate this, there is a polyfill you can import to expose React globally. In an Angular app for instance you can import this into the polyfills.ts file by doing: import “@flowable/work-views/dist/react-polyfill”.

Known limitations

There is a known limitation for create-react-app projects, particularly when using commonjs (cjs) modules, that can cause runtime errors when importing some libraries, such as:

Uncaught TypeError: i(...).create is not a function

For example, this error happens when importing Axios, a @flowable/work-views dependency, which default import returns a string instead of the module content, throwing the aforementioned error.

An available workaround involves using a tool called craco that enables overriding certain create-react-app configurations. Here is a craco config file example that can solve the issue:

const path = require('path');

module.exports = {
webpack: {
configure: {
resolve: {
alias: {
axios: path.resolve('node_modules/axios/index.js'),
},
},
},
},
};

Please see this thread for further information.