Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cluster managment front end UI #66

Merged
merged 21 commits into from
Jul 8, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tornjak-frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import "bootstrap/dist/css/bootstrap.min.css";
import { BrowserRouter as Router, Route } from "react-router-dom";
import NavigationBar from "./components/navbar";
import SelectServer from "./components/select-server";
import ClusterList from "./components/cluster-list";
import ClusterManagement from "./components/cluster-management";
import AgentList from "./components/agent-list";
import CreateJoinToken from "./components/agent-create-join-token";
import EntryList from "./components/entry-list";
Expand All @@ -27,10 +29,12 @@ function App() {
<SelectServer />
<br />
<Route path="/" exact component={AgentList} />
<Route path="/clusters" exact component={ClusterList} />
<Route path="/agents" exact component={AgentList} />
<Route path="/entries" exact component={EntryList} />
<Route path="/entry/create" exact component={EntryCreate} />
<Route path="/agent/createjointoken" exact component={CreateJoinToken} />
<Route path="/cluster/clustermanagement" exact component={ClusterManagement} />
<Route path="/tornjak/serverinfo" exact component={TornjakServerInfo} />
<Route path="/server/manage" exact component={ServerManagement} />
<br /><br /><br />
Expand Down
4 changes: 2 additions & 2 deletions tornjak-frontend/src/components/agent-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import IsManager from './is_manager';
import Table from "tables/agents-list-table";
import { selectors, workloadSelectors} from './selector-info';
import { selectors, workloadSelectors} from '../data/data';
import TornjakApi from './tornjak-api-helpers';
import {
serverSelectedFunc,
Expand Down Expand Up @@ -92,7 +92,7 @@ class AgentList extends Component {
render() {
return (
<div>
<h3>Agent List</h3>
<h3>Agents List</h3>
{this.props.globalErrorMessage !== "OK" &&
<div className="alert-primary" role="alert">
<pre>
Expand Down
327 changes: 327 additions & 0 deletions tornjak-frontend/src/components/cluster-create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import axios from 'axios';
import { Dropdown, TextInput, MultiSelect, TextArea } from 'carbon-components-react';
import GetApiServerUri from './helpers';
import IsManager from './is_manager';
import TornjakApi from './tornjak-api-helpers';
import { clusterType } from '../data/data';
import './style.css';
import {
clusterTypeInfoFunc,
serverSelectedFunc,
selectorInfoFunc,
agentsListUpdateFunc,
tornjakMessageFunc,
tornjakServerInfoUpdateFunc,
serverInfoUpdateFunc
} from 'redux/actions';

class ClusterCreate extends Component {
constructor(props) {
super(props);
this.TornjakApi = new TornjakApi();
this.onChangeClusterName = this.onChangeClusterName.bind(this);
this.onChangeClusterType = this.onChangeClusterType.bind(this);
this.onChangeManualClusterType = this.onChangeManualClusterType.bind(this);
this.onChangeClusterDomainName = this.onChangeClusterDomainName.bind(this);
this.onChangeClusterManagedBy = this.onChangeClusterManagedBy.bind(this);
this.onChangeAgentsList = this.onChangeAgentsList.bind(this);
this.onSubmit = this.onSubmit.bind(this);

this.state = {
clusterName: "",
clusterType: "",
clusterDomainName: "",
clusterManagedBy: "",
clusterAgentsList: "",
clusterTypeList: this.props.clusterTypeList,
clusterTypeManualEntryOption: "----Select this option and Enter Custom Cluster Type Below----",
clusterTypeManualEntry: false,
message: "",
statusOK: "",
successJsonMessege: "",
selectedServer: "",
agentsList: this.props.agentsList,
agentsListDisplay: "Select Agents",
assignedAgentsListDisplay: "",
}
}

componentDidMount() {
this.props.clusterTypeInfoFunc(clusterType); //set cluster type info
if (IsManager) {
if (this.props.globalServerSelected !== "" && (this.props.globalErrorMessage === "OK" || this.props.globalErrorMessage === "")) {
this.TornjakApi.populateAgentsUpdate(this.props.globalServerSelected, this.props.agentsListUpdateFunc, this.props.tornjakMessageFunc);
this.TornjakApi.populateTornjakServerInfo(this.props.globalServerSelected, this.props.tornjakServerInfoUpdateFunc, this.props.tornjakMessageFunc);
this.setState({ selectedServer: this.props.globalServerSelected });
}
} else {
this.TornjakApi.populateLocalAgentsUpdate(this.props.agentsListUpdateFunc, this.props.tornjakMessageFunc);
this.TornjakApi.populateLocalTornjakServerInfo(this.props.tornjakServerInfoUpdateFunc, this.props.tornjakMessageFunc);
this.TornjakApi.populateServerInfo(this.props.globalTornjakServerInfo, this.props.serverInfoUpdateFunc);
}
}

componentDidUpdate(prevProps, prevState) {
if (IsManager) {
if (prevProps.globalServerSelected !== this.props.globalServerSelected) {
this.setState({ selectedServer: this.props.globalServerSelected });
}
}
}

onChangeAgentsList = selected => {
var sid = selected.selectedItems, agents = "", agentsDisplay = "", assignedAgentsDisplay = "";
let localAgentsIdList = [];
for (let i = 0; i < sid.length; i++) {
localAgentsIdList[i] = sid[i].label;
}
agents = localAgentsIdList;
agentsDisplay = localAgentsIdList.toString();
assignedAgentsDisplay = localAgentsIdList.join("\n");
if (agentsDisplay.length === 0) {
agentsDisplay = "Select Agents"
}
this.setState({
clusterAgentsList: agents,
agentsListDisplay: agentsDisplay,
assignedAgentsListDisplay: assignedAgentsDisplay,
});
}
mamy-CS marked this conversation as resolved.
Show resolved Hide resolved

onChangeClusterName(e) {
var sid = e.target.value;
this.setState({
clusterName: sid
});
return
}

onChangeClusterType = selected => {
var sid = selected.selectedItem;
if (sid === this.state.clusterTypeManualEntryOption) {
this.setState({
clusterTypeManualEntry: true,
clusterType: sid,
});
} else {
this.setState({
clusterType: sid,
clusterTypeManualEntry: false
});
}
return
}

onChangeManualClusterType(e) {
var sid = e.target.value;
this.setState({
clusterType: sid
});
return
mamy-CS marked this conversation as resolved.
Show resolved Hide resolved
}

onChangeClusterDomainName(e) {
var sid = e.target.value;
this.setState({
clusterDomainName: sid
});
return
}

onChangeClusterManagedBy(e) {
var sid = e.target.value;
this.setState({
clusterManagedBy: sid
});
return
}

getApiEntryCreateEndpoint() {
if (!IsManager) {
return GetApiServerUri('/api/tornjak/cluster/create')
mamy-CS marked this conversation as resolved.
Show resolved Hide resolved
} else if (IsManager && this.state.selectedServer !== "") {
return GetApiServerUri('/manager-api/tornjak/cluster/create') + "/" + this.state.selectedServer
mamy-CS marked this conversation as resolved.
Show resolved Hide resolved
} else {
this.setState({ message: "Error: No server selected" })
return ""
}
}

onSubmit(e) {
e.preventDefault();

if (this.state.clusterName.length === 0) {
this.setState({ message: "ERROR: Cluster Name Can Not Be Empty - Enter Cluster Name" });
return
}

if (this.state.clusterType.length === 0) {
this.setState({ message: "ERROR: Cluster Type Can Not Be Empty - Choose/ Enter Cluster Type" });
return
}

var cjtData = {
"cluster": {
"name": this.state.clusterName,
"platformType": this.state.clusterType,
"domainName": this.state.clusterDomainName,
"managedBy": this.state.clusterManagedBy,
"agentsList": this.state.clusterAgentsList
}
}

let endpoint = this.getApiEntryCreateEndpoint();
if (endpoint === "") {
return
mamy-CS marked this conversation as resolved.
Show resolved Hide resolved
}
axios.post(endpoint, cjtData)
.then(
res => this.setState({
message: "Requst:" + JSON.stringify(cjtData, null, ' ') + "\n\nSuccess:" + JSON.stringify(res.data, null, ' '),
statusOK: "OK",
successJsonMessege: res.data.results[0].status.message
mamy-CS marked this conversation as resolved.
Show resolved Hide resolved
})
)
.catch(
err => this.setState({
message: "ERROR:" + err,
statusOK: "ERROR"
})
)
}
render() {
const ClusterType = this.props.clusterTypeList;
return (
<div>
<div className="cluster-create">
<div className="create-create-title">
<h3>Create Cluster</h3>
</div>
<form onSubmit={this.onSubmit}>
{IsManager}
mamy-CS marked this conversation as resolved.
Show resolved Hide resolved
<br /><br />
<div className="entry-form">
<div className="clustername-input-field">
<TextInput
aria-required="true"
helperText="i.e. exampleabc"
id="clusterNameInputField"
invalidText="A valid value is required - refer to helper text below"
labelText="Cluster Name [*required]"
placeholder="Enter CLUSTER NAME"
onChange={this.onChangeClusterName}
required />
</div>
<div className="clustertype-drop-down">
<Dropdown
aria-required="true"
ariaLabel="clustertype-drop-down"
id="clustertype-drop-down"
items={ClusterType}
label="Select Cluster Type"
titleText="Cluster Type [*required]"
onChange={this.onChangeClusterType}
required />
<p className="cluster-helper">i.e. Kubernetes, VMs...</p>
</div>
{this.state.clusterTypeManualEntry === true &&
<div className="clustertype-manual-input-field">
<TextInput
helperText="i.e. Kubernetes, VMs..."
id="clusterTypeManualInputField"
invalidText="A valid value is required - refer to helper text below"
labelText="Cluster Type - Manual Entry"
placeholder="Enter Cluster Type"
onChange={(e) => {
this.onChangeManualClusterType(e);
}}
/>
</div>}
<div className="cluster-domain-name-input-field">
<TextInput
helperText="i.e. example.org"
id="clusterDomainNameInputField"
invalidText="A valid value is required - refer to helper text below"
labelText="Cluster Domain Name/ URL"
placeholder="Enter CLUSTER DOMAIN NAME/ URL"
onChange={this.onChangeClusterDomainName}
/>
</div>
<div className="cluster-managed-by-input-field">
<TextInput
helperText="i.e. person-A"
id="clusterNameInputField"
invalidText="A valid value is required - refer to helper text below"
labelText="Cluster Managed By"
placeholder="Enter CLUSTER MANAGED BY"
onChange={this.onChangeClusterManagedBy}
/>
</div>
<div className="agents-multiselect">
<MultiSelect.Filterable
titleText="Assign Agents To Cluster"
helperText="i.e. spiffe://example.org/agent/myagent1..."
placeholder={this.state.agentsListDisplay}
ariaLabel="selectors-multiselect"
id="selectors-multiselect"
items={this.props.agentsList}
mamy-CS marked this conversation as resolved.
Show resolved Hide resolved
label={this.state.agentsListDisplay}
onChange={this.onChangeAgentsList}
/>
</div>
<div className="selectors-textArea">
<TextArea
cols={50}
helperText="i.e. spiffe://example.org/agent/myagent1..."
id="selectors-textArea"
invalidText="A valid value is required"
labelText="Assigned Agents"
placeholder="Assigned agents will be populated here - Refer to Assign Agents To Cluster"
defaultValue={this.state.assignedAgentsListDisplay}
rows={8}
disabled
/>
</div>
<div className="form-group">
<input type="submit" value="Create Cluster" className="btn btn-primary" />
</div>
<div>
{this.state.statusOK === "OK" && this.state.successJsonMessege === "OK" &&
<p className="success-message">--ENTRY SUCCESSFULLY CREATED--</p>
}
{(this.state.statusOK === "ERROR" || (this.state.successJsonMessege !== "OK" && this.state.successJsonMessege !== "")) &&
<p className="failed-message">--ENTRY CREATION FAILED--</p>
}
</div>
<div className="alert-primary" role="alert">
<pre>
{this.state.message}
</pre>
</div>
</div>
</form>
</div>
</div>
)
}
}


const mapStateToProps = (state) => ({
globalClusterTypeInfo: state.clusters.globalClusterTypeInfo,
globalServerSelected: state.servers.globalServerSelected,
globalSelectorInfo: state.servers.globalSelectorInfo,
globalAgentsList: state.agents.globalAgentsList,
globalServerInfo: state.servers.globalServerInfo,
globalTornjakServerInfo: state.servers.globalTornjakServerInfo,
globalErrorMessage: state.tornjak.globalErrorMessage,
globalWorkloadSelectorInfo: state.servers.globalWorkloadSelectorInfo,
globalAgentsWorkLoadAttestorInfo: state.agents.globalAgentsWorkLoadAttestorInfo,
})

export default connect(
mapStateToProps,
{ clusterTypeInfoFunc, serverSelectedFunc, selectorInfoFunc, agentsListUpdateFunc, tornjakMessageFunc, tornjakServerInfoUpdateFunc, serverInfoUpdateFunc }
)(ClusterCreate)
Loading