Skip to content

Commit

Permalink
Fix errors and add warning on first application load
Browse files Browse the repository at this point in the history
Fixes the error that is thrown by the cluster usage dashboard if no clusters have been set up.

A workflow was also added in order to warn users on application load if they do not have any clusters set up via redux in the header component.
  • Loading branch information
FancMa01 committed Mar 27, 2024
1 parent 25e64a2 commit 54d49ea
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function ClusterUsage() {
}

// If no clusterId in url
if (clusters && !urlQueries.clusterId) {
if (clusters?.length && !urlQueries.clusterId) {
setSelectedCluster(clusters[0].id);
addQueriesToUrl({ queryName: 'clusterId', queryValue: clusters[0].id });
}
Expand Down
1 change: 1 addition & 0 deletions client-reactjs/src/components/common/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const Constants = {

CLUSTER_SELECTED: 'CLUSTER_SELECTED',
CLUSTERS_RETRIEVED: 'CLUSTERS_RETRIEVED',
NO_CLUSTERS_FOUND: 'NO_CLUSTERS_FOUND',

CONSUMERS_RETRIEVED: 'CONSUMERS_RETRIEVED',
LICENSES_RETRIEVED: 'LICENSES_RETRIEVED',
Expand Down
68 changes: 68 additions & 0 deletions client-reactjs/src/components/common/noCluster.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react';
import { Modal } from 'antd';
import { Link } from 'react-router-dom';

const NoCluster = ({ visible, setVisible, applicationId }) => {
const handleOk = () => {
setVisible(false);
};

return (
<div>
<Modal title="No Clusters Setup" open={visible} onOk={handleOk}>
<p>
It looks like you do not have any clusters set up, most of Tombolos functionalities rely on a connection to an
HPCC cluster including:
<br />
<br />
<ul>
<li>
<Link to={`/${applicationId}/Dataflow`} onClick={() => setVisible(false)}>
Workflow Management
</Link>
</li>
<li>
<Link to={`/${applicationId}/fileMonitoring`} onClick={() => setVisible(false)}>
File Monitoring
</Link>
</li>
<li>
<Link to={`/${applicationId}/clustermonitoring`} onClick={() => setVisible(false)}>
Cluster Monitoring
</Link>
</li>
<li>
<Link to={`/${applicationId}/jobmonitoring`} onClick={() => setVisible(false)}>
Job Monitoring
</Link>
</li>

<li>
<Link to={`/${applicationId}/superfileMonitoring`} onClick={() => setVisible(false)}>
Superfile Monitoring
</Link>
</li>

<li>
<Link to={`/${applicationId}/dashboard/clusterUsage`} onClick={() => setVisible(false)}>
Cluster Usage Dashboards
</Link>
</li>
<li>
<Link to={`/${applicationId}/dashboard/notifications`} onClick={() => setVisible(false)}>
Notification Dashboards
</Link>
</li>
</ul>
<br />
<Link to="/admin/clusters" onClick={() => setVisible(false)}>
Set up a cluster now
</Link>
, or go to the left navigation and select the cluster option at any time.
</p>
</Modal>
</div>
);
};

export default NoCluster;
269 changes: 151 additions & 118 deletions client-reactjs/src/components/layout/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { userActions } from '../../redux/actions/User';
import { authHeader, handleError } from '../common/AuthHeader.js';
import { hasAdminRole } from '../common/AuthUtil.js';
import Text, { i18n } from '../common/Text';
import NoCluster from '../common/noCluster.js';

class AppHeader extends Component {
pwdformRef = React.createRef();
Expand All @@ -36,6 +37,7 @@ class AppHeader extends Component {
newpassword: '',
confirmnewpassword: '',
isAboutModalVisible: false,
isClusterModalVisible: false,
language: 'EN',
};

Expand Down Expand Up @@ -145,6 +147,13 @@ class AppHeader extends Component {
this.props.dispatch(applicationActions.getAllActiveIntegrations());
}

console.log(this.props);
//if noClusters.noClusters prop is true, show the no cluster modal and dispatch action to reset the noClusters state
if (this.props.noClusters.noClusters && !this.props.noClusters.redirect) {
this.props.dispatch(applicationActions.updateNoClustersFound({ noClusters: true, redirect: true }));
this.setState({ isClusterModalVisible: true });
}

if (this.props.newApplication) {
let applications = this.state.applications;
let isNewApplicationInList =
Expand Down Expand Up @@ -344,6 +353,12 @@ class AppHeader extends Component {
});
};

setClusterModalVisible = (visible) => {
this.setState({
isClusterModalVisible: visible,
});
};

// Options for languages dropdown

render() {
Expand Down Expand Up @@ -408,133 +423,151 @@ class AppHeader extends Component {
});

return (
<div style={{ display: 'flex', alignItems: 'center', maxHeight: '100%', justifyContent: 'space-between' }}>
<div>
<Link to={'/'} style={{ marginRight: '70px' }}>
<img src={logo} alt="Tombolo logo" width="80px" height="19px" />
</Link>

<Dropdown
menu={{
items: menuItems,
onClick: (e) => {
this.handleChange(e.key);
},
}}
placement="bottom"
trigger={['click']}>
<Tooltip title="Select an Application" placement="right">
<Space
style={{
color: 'white',
border: '1px solid white',
cursor: 'pointer',
padding: '0 4px',
borderRadius: '3px',
maxHeight: '32px',
minWidth: '200px',
}}>
<AppstoreOutlined />
<span> {this.state.selected}</span>
</Space>
</Tooltip>
</Dropdown>
</div>

<div style={{ display: 'flex', alignItems: 'center' }}>
<Dropdown menu={{ items: helpMenuItems, onClick: (e) => helpMenuClick(e) }} trigger={['click']}>
<Button shape="round" style={{ marginRight: '10px' }}>
<i className="fa fa-lg fa-question-circle"></i>
<span style={{ paddingLeft: '5px' }}>
{<Text text="Help" />} <DownOutlined />
</span>
</Button>
</Dropdown>
<Dropdown
menu={{ items: actionMenuItems, onClick: (e) => this.handleUserActionMenuClick(e) }}
trigger={['click']}>
<Button shape="round">
<i className="fa fa-lg fa-user-circle"></i>
<span style={{ paddingLeft: '5px' }}>
{this.props.user.firstName + ' ' + this.props.user.lastName} <DownOutlined />
</span>
</Button>
</Dropdown>
<>{this.props.languageSwitcher}</>
</div>

<Modal
title={<Text>Change Password</Text>}
open={this.state.visible}
width="520px"
footer={[
<Button key="cancel" onClick={this.handleCancel}>
<Text>Cancel</Text>
</Button>,
<Button key="submit" onClick={this.handleOk} type="primary" loading={this.state.loading}>
<Text>Change Password</Text>
</Button>,
]}>
<Form ref={this.pwdformRef}>
<Form.Item
{...formItemLayout}
name="oldpassword"
label={<Text>Password</Text>}
rules={[{ required: true, message: 'Please enter the current password!' }]}>
<Input
type="password"
<>
<div style={{ display: 'flex', alignItems: 'center', maxHeight: '100%', justifyContent: 'space-between' }}>
<div>
<Link to={'/'} style={{ marginRight: '70px' }}>
<img src={logo} alt="Tombolo logo" width="80px" height="19px" />
</Link>

<Dropdown
menu={{
items: menuItems,
onClick: (e) => {
this.handleChange(e.key);
},
}}
placement="bottom"
trigger={['click']}>
<Tooltip title="Select an Application" placement="right">
<Space
style={{
color: 'white',
border: '1px solid white',
cursor: 'pointer',
padding: '0 4px',
borderRadius: '3px',
maxHeight: '32px',
minWidth: '200px',
}}>
<AppstoreOutlined />
<span> {this.state.selected}</span>
</Space>
</Tooltip>
</Dropdown>
</div>

<div style={{ display: 'flex', alignItems: 'center' }}>
<Dropdown menu={{ items: helpMenuItems, onClick: (e) => helpMenuClick(e) }} trigger={['click']}>
<Button shape="round" style={{ marginRight: '10px' }}>
<i className="fa fa-lg fa-question-circle"></i>
<span style={{ paddingLeft: '5px' }}>
{<Text text="Help" />} <DownOutlined />
</span>
</Button>
</Dropdown>
<Dropdown
menu={{ items: actionMenuItems, onClick: (e) => this.handleUserActionMenuClick(e) }}
trigger={['click']}>
<Button shape="round">
<i className="fa fa-lg fa-user-circle"></i>
<span style={{ paddingLeft: '5px' }}>
{this.props.user.firstName + ' ' + this.props.user.lastName} <DownOutlined />
</span>
</Button>
</Dropdown>
<>{this.props.languageSwitcher}</>
</div>

<Modal
title={<Text>Change Password</Text>}
open={this.state.visible}
width="520px"
footer={[
<Button key="cancel" onClick={this.handleCancel}>
<Text>Cancel</Text>
</Button>,
<Button key="submit" onClick={this.handleOk} type="primary" loading={this.state.loading}>
<Text>Change Password</Text>
</Button>,
]}>
<Form ref={this.pwdformRef}>
<Form.Item
{...formItemLayout}
name="oldpassword"
placeholder={i18n('Password')}
onChange={this.handleChangePasswordFieldChange}
/>
</Form.Item>

<Form.Item
{...formItemLayout}
name="newpassword"
label={<Text>New Password</Text>}
rules={[{ required: true, message: 'Please enter the new password!' }]}>
<Input
type="password"
label={<Text>Password</Text>}
rules={[{ required: true, message: 'Please enter the current password!' }]}>
<Input
type="password"
name="oldpassword"
placeholder={i18n('Password')}
onChange={this.handleChangePasswordFieldChange}
/>
</Form.Item>

<Form.Item
{...formItemLayout}
name="newpassword"
placeholder={i18n('New Password')}
onChange={this.handleChangePasswordFieldChange}
/>
</Form.Item>

<Form.Item
{...formItemLayout}
name="confirmnewpassword"
label={<Text>Confirm Password</Text>}
rules={[{ required: true, message: 'Please confirm the new password!' }]}>
<Input
type="password"
label={<Text>New Password</Text>}
rules={[{ required: true, message: 'Please enter the new password!' }]}>
<Input
type="password"
name="newpassword"
placeholder={i18n('New Password')}
onChange={this.handleChangePasswordFieldChange}
/>
</Form.Item>

<Form.Item
{...formItemLayout}
name="confirmnewpassword"
placeholder={i18n('Confirm Password')}
onChange={this.handleChangePasswordFieldChange}
/>
</Form.Item>
</Form>
</Modal>
<Modal
title="Tombolo"
open={this.state.isAboutModalVisible}
footer={[
<Button key="close" onClick={this.handleAboutClose}>
Close
</Button>,
]}>
<p className="float-left font-weight-bold">Tombolo v{process.env.REACT_APP_VERSION}</p>
</Modal>
</div>
label={<Text>Confirm Password</Text>}
rules={[{ required: true, message: 'Please confirm the new password!' }]}>
<Input
type="password"
name="confirmnewpassword"
placeholder={i18n('Confirm Password')}
onChange={this.handleChangePasswordFieldChange}
/>
</Form.Item>
</Form>
</Modal>
<Modal
title="Tombolo"
open={this.state.isAboutModalVisible}
footer={[
<Button key="close" onClick={this.handleAboutClose}>
Close
</Button>,
]}>
<p className="float-left font-weight-bold">Tombolo v{process.env.REACT_APP_VERSION}</p>
</Modal>
</div>
<NoCluster
visible={this.state.isClusterModalVisible}
setVisible={this.setClusterModalVisible}
applicationId={this.props.application?.applicationId}
/>
</>
);
}
}

function mapStateToProps(state) {
const { loggingIn, user } = state.authenticationReducer;
const { application, clusters, newApplication, updatedApplication, deletedApplicationId } = state.applicationReducer;
return { loggingIn, user, clusters, application, newApplication, updatedApplication, deletedApplicationId };
const { application, clusters, newApplication, updatedApplication, deletedApplicationId, noClusters } =
state.applicationReducer;

return {
loggingIn,
user,
clusters,
noClusters,
application,
newApplication,
updatedApplication,
deletedApplicationId,
};
}

//export default withRouter(AppHeader);
Expand Down
Loading

0 comments on commit 54d49ea

Please sign in to comment.