Skip to content

Commit

Permalink
KOGITO-1299: added fallback UI when server unavailable
Browse files Browse the repository at this point in the history
please enter the commit message for your changes. Lines starting
  • Loading branch information
Sara4994 authored and root committed Mar 31, 2020
1 parent f0d43c1 commit 0d84b68
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ const DataListItemComponent: React.FC<IOwnProps> = ({
<DataListItemCells
dataListCells={[
<DataListCell key={1}>
<Link to={'/ProcessInstances/' + processInstanceData.id}>
<Link to={{pathname:'/ProcessInstances/Process/' + processInstanceData.id, state:{ prev: location.pathname}}}>
<div>
<strong>
<ProcessDescriptor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ const NoDataComponent = (props) => {
let prevPath;
if (props.location.state !== undefined) {
prevPath = props.location.state.prev;
} else {
prevPath = '/ProcessInstances'
}

const tempPath = prevPath.split('/');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React, { useState } from 'react';
import {
PageSection,
Bullseye,
EmptyState,
EmptyStateIcon,
EmptyStateVariant,
Button,
EmptyStateBody,
Title,
Page,
SkipToContent,
PageSidebar,
PageHeader,
Nav,
NavList,
NavItem,
Brand,
} from '@patternfly/react-core';
import {
ExclamationCircleIcon
} from '@patternfly/react-icons';
import { BrowserRouter as Router, Link } from 'react-router-dom';
import Avatar from '../../Atoms/AvatarComponent/AvatarComponent';
import PageToolbarComponent from '../../Organisms/PageToolbarComponent/PageToolbarComponent';
import managementConsoleLogo from '../../../static/managementConsoleLogo.svg';

const NoServerComponent = (props) => {
const [isNavOpen, setIsNavOpen] = useState(true);
const onNavToggle = () => {
setIsNavOpen(!isNavOpen);
};

const Header = (
<PageHeader
logo={<Brand
src={managementConsoleLogo}
alt="Management Console Logo"
/>}
toolbar={<PageToolbarComponent />}
avatar={<Avatar />}
showNavToggle
isNavOpen={isNavOpen}
onNavToggle={onNavToggle}
/>
);

const PageNav = (
<Nav aria-label="Nav" theme="dark">
<NavList>
<NavItem>
<Link to="/ProcessInstances">Process Instances</Link>
</NavItem>
<NavItem>
<Link to="/DomainExplorer">Domain Explorer</Link>
</NavItem>
</NavList>
</Nav>
);
const Sidebar = (
<PageSidebar nav={PageNav} isNavOpen={isNavOpen} theme="dark" />
);

const pageId = 'main-content-page-layout-default-nav';
const PageSkipToContent = (
<SkipToContent href={`#${pageId}`}>Skip to Content</SkipToContent>
);

return (
<>
<Router>
<Page
header={Header}
skipToContent={PageSkipToContent}
mainContainerId={pageId}
sidebar={Sidebar}
isManagedSidebar
className="kogito-management-console--dashboard-page"
>
<PageSection variant="light">
<Bullseye>
<EmptyState variant={EmptyStateVariant.full}>
<EmptyStateIcon
icon={ExclamationCircleIcon}
size="md"
color="var(--pf-global--danger-color--100)" />
<Title headingLevel="h1" size="4xl">Error connecting server</Title>
<EmptyStateBody>
The management console could not access the server to display content.
</EmptyStateBody>
<EmptyStateBody>
Try reloading the page, or contact your administrator for more information.
</EmptyStateBody>
<Button variant="primary" onClick={() => window.location.reload()}>
Refresh
              </Button>
</EmptyState>
</Bullseye>
</PageSection>
</Page>
</Router>
</>
);
};

export default NoServerComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.kogito-management-console--Server-Errors__text-color {
color: var(--pf-global--primary-color--100)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';

import {
DataToolbar,
DataToolbarContent,
DataToolbarToggleGroup,
DataToolbarGroup,
PageSection,
Breadcrumb,
BreadcrumbItem,
Card,
Bullseye,
EmptyState,
EmptyStateIcon,
EmptyStateVariant,
Button,
EmptyStateBody,
Title,
Popover, PopoverPosition,
} from '@patternfly/react-core';
import {
ExclamationCircleIcon
} from '@patternfly/react-icons';
import './ServerErrorsComponent.css';
import {useHistory} from 'react-router-dom';

const ServerErrorsComponent = (props) => {
const history = useHistory();
return (
<PageSection variant="light">
<Bullseye>
<EmptyState variant={EmptyStateVariant.full}>
<EmptyStateIcon
icon={ExclamationCircleIcon}
size="md"
color="var(--pf-global--danger-color--100)" />
<Title headingLevel="h1" size="4xl">Error fetching data</Title>
<EmptyStateBody>
An error occured while accessing data.
<Popover
headerContent={<div>Error</div>}
bodyContent={
<div>{props.message}</div>
}
>
<strong className="kogito-management-console--Server-Errors__text-color"> See more details</strong>
</Popover>
</EmptyStateBody>
<Button variant="primary" onClick={() => history.goBack()}>
Go back
              </Button>
</EmptyState>
</Bullseye>

</PageSection>
)
}

export default ServerErrorsComponent;
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface IOwnProps {
setSelected: any;
data: any;
getPicker: any;
setError: any
}

const DomainExplorerColumnPicker: React.FC<IOwnProps> = ({
Expand All @@ -37,6 +38,7 @@ const DomainExplorerColumnPicker: React.FC<IOwnProps> = ({
setSelected,
data,
getPicker,
setError
}) => {
const [isExpanded, setIsExpanded] = useState(false);
const [tempDomain, setTempDomain] = useState('');
Expand Down Expand Up @@ -122,7 +124,8 @@ const DomainExplorerColumnPicker: React.FC<IOwnProps> = ({
}
});
} catch (error) {
return error;
setError(error.message)
// return error;
}
} else {
setDisplayTable(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ const DomainExplorerTable = ({ columnFilters, tableLoading, displayTable }) => {
const ele = {
title: (
<>
<Link to={'/ProcessInstances/' + tempObj.id}>
<Link to={{pathname:'/ProcessInstances/Process/' + tempObj.id, state:{ prev: location.pathname}}}>
<strong>
<ProcessDescriptor processInstanceData={tempObj}/>
</strong>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ const ProcessDetails: React.FC<IOwnProps> = ({ data }) => {
<div>
<Link
to={
'/ProcessInstances/' +
'/ProcessInstances/Process/' +
data.ProcessInstances[0].parentProcessInstance.id
}
>
Expand All @@ -165,7 +165,7 @@ const ProcessDetails: React.FC<IOwnProps> = ({ data }) => {
{data.ProcessInstances[0].childProcessInstances.map(
(child, index) => (
<div key={child.id}>
<Link to={'/ProcessInstances/' + child.id}>
<Link to={'/ProcessInstances/Process/' + child.id}>
<Tooltip content={child.id}>
<Button variant="link" icon={<LevelDownAltIcon />}>
<ProcessDescriptor processInstanceData={child} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const Dashboard: React.FC<{}> = (props: any) => {
<Route exact path="/ProcessInstances" component={DataListContainer} />
<Route
exact
path="/ProcessInstances/:instanceID"
path="/ProcessInstances/Process/:instanceID"
component={ProcessDetailsPage}
/>
<Route
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import './DomainExplorerDashboard.css';
import DomainExplorerColumnPicker from '../../Organisms/DomainExplorerColumnPicker/DomainExplorerColumnPicker';
import DomainExplorerTable from '../../Organisms/DomainExplorerTable/DomainExplorerTable';
import PageTitleComponent from '../../Molecules/PageTitleComponent/PageTitleComponent';
import ServerErrorsComponent from '../../Molecules/ServerErrorsComponent/ServerErrorsComponent';

import {
useGetQueryTypesQuery,
Expand Down Expand Up @@ -49,6 +50,7 @@ const DomainExplorerDashboard = props => {
const [tableLoading, setTableLoading] = useState(true);
const [displayTable, setDisplayTable] = useState(false);
const [selected, setSelected] = useState([]);
const [error, setError] = useState()
const [parameters, setParameters] = useState([
{ metadata: [{ processInstances: ['id','processName', 'state', 'start', 'lastUpdate','businessKey'] }] }
]);
Expand Down Expand Up @@ -172,6 +174,7 @@ const DomainExplorerDashboard = props => {
setSelected={setSelected}
data={data}
getPicker={getPicker}
setError={setError}
/>
)}
</DataToolbarGroup>
Expand Down Expand Up @@ -215,6 +218,7 @@ const DomainExplorerDashboard = props => {
})}
</Breadcrumb>
</PageSection>
{!error ? (
<PageSection>
{renderToolbar()}

Expand All @@ -225,7 +229,7 @@ const DomainExplorerDashboard = props => {
displayTable={displayTable}
/>
</div>
</PageSection>
</PageSection>): (<ServerErrorsComponent message={error} />)}
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,32 @@ import { useGetProcessInstanceByIdQuery } from '../../../graphql/types';
import ProcessDescriptor from '../../Molecules/ProcessDescriptor/ProcessDescriptor';
import SpinnerComponent from '../../Atoms/SpinnerComponent/SpinnerComponent';
import PageTitleComponent from '../../Molecules/PageTitleComponent/PageTitleComponent';
import ServerErrorsComponent from '../../Molecules/ServerErrorsComponent/ServerErrorsComponent';

const ProcessDetailsPage = ({ match }) => {
const id = match.params.instanceID;
const ProcessDetailsPage = (props) => {
const id = props.match.params.instanceID;

const { loading, error, data } = useGetProcessInstanceByIdQuery({
variables: { id }
});

if (data) {
let prevPath;
const result = data.ProcessInstances;
if(props.location.state){
const tempPath = props.location.state.prev.split('/')
prevPath = tempPath.filter(item => item)
}
if (result.length === 0) {
return (
<Redirect
to={{
pathname: '/NoData',
state: {
prev: location.pathname,
prev: props.location.state ? props.location.state.prev : '/ProcessInstances',
title: 'Process not found',
description: `Process instance with the id ${id} not found`,
buttonText: 'Go to process instances'
buttonText: props.location.state ? `Go to ${prevPath[0].replace(/([A-Z])/g, ' $1').trim().toLowerCase()}`: 'Go to process instances'
}
}}
/>
Expand All @@ -49,6 +55,8 @@ const ProcessDetailsPage = ({ match }) => {

return (
<>
{!error ?
(<>
<PageSection variant="light">
<PageTitleComponent title="Process Details" />
{!loading ?
Expand Down Expand Up @@ -99,6 +107,7 @@ const ProcessDetailsPage = ({ match }) => {
</Card>
)}
</PageSection>
</>) : <ServerErrorsComponent message={error.message} />}
</>
);
};
Expand Down
27 changes: 24 additions & 3 deletions packages/management-console/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
import '@patternfly/patternfly/patternfly.css';
import React from 'react';
import ReactDOM from 'react-dom';
import ApolloClient from 'apollo-boost';
import { ApolloClient } from 'apollo-client';
// import ApolloClient from 'apollo-boost';
import { ApolloProvider } from 'react-apollo';
import Keycloak from 'keycloak-js';
import axios from 'axios';
import BaseComponent from './components/Templates/BaseComponent/BaseComponent';
import { HttpLink } from 'apollo-link-http';
import { onError } from 'apollo-link-error';
import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory';
import NoServerComponent from './components/Molecules/NoServerComponent/NoServerComponent';

const client = new ApolloClient({
// @ts-ignore
const httpLink = new HttpLink({ uri: window.DATA_INDEX_ENDPOINT || process.env.KOGITO_DATAINDEX_HTTP_URL, });

const logoutLink = onError(({networkError}:any) => {
if (networkError && networkError.stack === 'TypeError: Failed to fetch') {
return ReactDOM.render(
<ApolloProvider client={client}>
<NoServerComponent />
</ApolloProvider>,
document.getElementById('root')
);
}
})

const cache = new InMemoryCache();
const client: ApolloClient<NormalizedCacheObject> = new ApolloClient({
cache,
link: logoutLink.concat(httpLink),
// @ts-ignore
uri: window.DATA_INDEX_ENDPOINT || process.env.KOGITO_DATAINDEX_HTTP_URL,
request: operation => {
if (process.env.KOGITO_AUTH_ENABLED) {
const kcInfo = JSON.parse(localStorage.getItem('keycloakData'));
Expand Down

0 comments on commit 0d84b68

Please sign in to comment.