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 all 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
3,439 changes: 1,887 additions & 1,552 deletions tornjak-frontend/package-lock.json

Large diffs are not rendered by default.

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
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ class CreateJoinToken extends Component {
return
}
axios.post(endpoint, cjtData)
.then(res => this.setState({ message: "Requst:" + JSON.stringify(cjtData,null, ' ')+ "\n\nSuccess:" + JSON.stringify(res.data, null, ' ')}))
.then(res => this.setState({ message: "Request:" + JSON.stringify(cjtData,null, ' ')+ "\n\nSuccess:" + JSON.stringify(res.data, null, ' ')}))
.catch(err => this.setState({ message: "ERROR:" + err + (typeof (err.response) !== "undefined" ? err.response.data : "")}))
//window.location = '/';
}
Expand Down
7 changes: 3 additions & 4 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 @@ -71,7 +71,7 @@ class AgentList extends Component {
if(prevProps.globalTornjakServerInfo !== this.props.globalTornjakServerInfo)
{
this.TornjakApi.populateServerInfo(this.props.globalTornjakServerInfo, this.props.serverInfoUpdateFunc);
this.TornjakApi.refreshSelectorsState(this.props.globalServerSelected, this.props.agentworkloadSelectorInfoFunc);
this.TornjakApi.refreshLocalSelectorsState(this.props.agentworkloadSelectorInfoFunc);
}
}
}
Expand All @@ -92,15 +92,14 @@ 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>
{this.props.globalErrorMessage}
</pre>
</div>
}
{IsManager}
<br /><br />
<div className="indvidual-list-table">
<Table data={this.agentList()} id="table-1" />
Expand Down
328 changes: 328 additions & 0 deletions tornjak-frontend/src/components/cluster-create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
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: "",
selectedServer: "",
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/clusters/create')
} else if (IsManager && this.state.selectedServer !== "") {
return GetApiServerUri('/manager-api/tornjak/clusters/create') + "/" + this.state.selectedServer
} else {
this.setState({ message: "Error: No server selected" })
return ""
}
}

onSubmit(e) {
var agentsList = [];
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
}

if (this.state.clusterAgentsList !== "") {
agentsList = this.state.clusterAgentsList;
}

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

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: "Request:" + JSON.stringify(cjtData, null, ' ') + "\n\nSuccess:" + JSON.stringify(res.data, null, ' '),
statusOK: "OK",
})
)
.catch(
err => this.setState({
message: "ERROR:" + err.response.data,
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}>
<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" &&
<p className="success-message">--ENTRY SUCCESSFULLY CREATED--</p>
}
{(this.state.statusOK === "ERROR") &&
<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