diff --git a/frontend/src/components/entry-create.tsx b/frontend/src/components/entry-create.tsx index 5870eb3b..3f732242 100644 --- a/frontend/src/components/entry-create.tsx +++ b/frontend/src/components/entry-create.tsx @@ -256,7 +256,7 @@ class CreateEntry extends Component { //user prefered option localAgentsIdList[0] = this.state.parentIdManualEntryOption; //default option - localAgentsIdList[1] = prefix + this.props.globalDebugServerInfo.svid_chain[0].id.trust_domain + "/spire/server"; + localAgentsIdList[1] = prefix + this.props.globalServerInfo.trustDomain + "/spire/server"; //agents let agentEntriesDict: { [key: string]: EntriesList[]; } | undefined = this.SpiffeHelper.getAgentsEntries(this.props.globalAgentsList, this.props.globalEntriesList) diff --git a/frontend/src/components/navbar.tsx b/frontend/src/components/navbar.tsx index 7e9aca4a..d00eb7a6 100644 --- a/frontend/src/components/navbar.tsx +++ b/frontend/src/components/navbar.tsx @@ -62,6 +62,10 @@ type NavigationBarProp = { spireDebugServerInfoUpdateFunc: (globalDebugServerInfo: DebugServerInfo) => void, // dispatches a payload for an Error Message/ Success Message of an executed function as a string and has a return type of void tornjakMessageFunc: (globalErrorMessage: string) => void, + // the selected server for manager mode + globalServerSelected: string, + // tornjak error messege + globalErrorMessage: string, } type NavigationBarState = {} @@ -89,9 +93,18 @@ class NavigationBar extends Component { } } } - this.TornjakApi.populateLocalTornjakServerInfo(this.props.tornjakServerInfoUpdateFunc, this.props.tornjakMessageFunc); - this.TornjakApi.populateLocalTornjakDebugServerInfo(this.props.spireDebugServerInfoUpdateFunc, this.props.tornjakMessageFunc); - this.TornjakApi.populateServerInfo(this.props.globalTornjakServerInfo, this.props.serverInfoUpdateFunc); + 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.populateEntriesUpdate(this.props.globalServerSelected, this.props.entriesListUpdateFunc, this.props.tornjakMessageFunc) + // this.TornjakApi.refreshSelectorsState(this.props.globalServerSelected, this.props.agentworkloadSelectorInfoFunc); + // this.setState({ selectedServer: this.props.globalServerSelected }); + } + } else { + this.TornjakApi.populateLocalTornjakServerInfo(this.props.tornjakServerInfoUpdateFunc, this.props.tornjakMessageFunc); + this.TornjakApi.populateLocalTornjakDebugServerInfo(this.props.spireDebugServerInfoUpdateFunc, this.props.tornjakMessageFunc); + this.TornjakApi.populateServerInfo(this.props.globalTornjakServerInfo, this.props.serverInfoUpdateFunc); + } } render() { @@ -152,6 +165,11 @@ class NavigationBar extends Component {
ADMIN PORTAL
} + {IsManager && +
+
MANAGER PORTAL
+
+ } {IsManager && managerNavs} @@ -188,6 +206,8 @@ const mapStateToProps = (state: RootState) => ({ globalServerInfo: state.servers.globalServerInfo, globalDebugServerInfo: state.servers.globalDebugServerInfo, globalTornjakServerInfo: state.servers.globalTornjakServerInfo, + globalServerSelected: state.servers.globalServerSelected, + globalErrorMessage: state.tornjak.globalErrorMessage, }) export default connect( diff --git a/frontend/src/components/select-server.tsx b/frontend/src/components/select-server.tsx index 197b6dc2..8bcdb201 100644 --- a/frontend/src/components/select-server.tsx +++ b/frontend/src/components/select-server.tsx @@ -4,6 +4,7 @@ import axios from 'axios'; import GetApiServerUri from './helpers'; import IsManager from './is_manager'; import TornjakApi from './tornjak-api-helpers'; +import './style.css'; import { serverSelectedFunc, @@ -17,6 +18,7 @@ import { import { RootState } from 'redux/reducers'; import { AgentsList, + ServersList, ServerInfo, TornjakServerInfo, DebugServerInfo, @@ -27,7 +29,7 @@ type SelectServerProp = { // tornjak server debug info of the selected server globalDebugServerInfo: DebugServerInfo, // dispatches a payload for the list of available servers and their basic info as array of strings and has a return type of void - serversListUpdateFunc: (globalServersList: Array) => void, + serversListUpdateFunc: (globalServersList: ServersList[]) => void, // dispatches a payload for the server selected in the redux state as a string and has a return type of void serverSelectedFunc: (globalServerSelected: string) => void, // dispatches a payload for the server trust domain and nodeAttestorPlugin and has a return type of void @@ -43,7 +45,7 @@ type SelectServerProp = { // tornjak server info of the selected server globalTornjakServerInfo: TornjakServerInfo, // list of avialable servers - globalServersList: Array, + globalServersList: ServersList[], // error/ success messege returned for a specific function globalErrorMessage: string, } @@ -134,7 +136,7 @@ class SelectServer extends Component { render() { let managerServerSelector = ( -
+
- {this.state.CAFileText} -
- ) - - const mtlsFormOptions = ( -
-
- Cert File (for mTLS): - - {this.state.certFileText} -
-
Key File (for mTLS): - - {this.state.keyFileText} -
-
- ) - - return ( -
-

Register New Server

-
-
- - -
- - -
- - -
- -
- - TLS Enabled -
- {this.state.formTLS && tlsFormOptions} - -
- - mTLS Enabled -
- {this.state.formMTLS && mtlsFormOptions} - -
-

- -
-
- -
-
-           {this.state.message}
-        
-
- - -

Server List

- - - - - - - - - - {this.serverList()} - -
Server NameAddressTLS?
- -
- ) - } -} - -const mapStateToProps = (state) => ({ - globalServersList: state.servers.globalServersList -}) - -export default connect( - mapStateToProps, - { serversListUpdateFunc } -)(ServerManagement) diff --git a/frontend/src/components/server-management.tsx b/frontend/src/components/server-management.tsx new file mode 100644 index 00000000..a0c98f29 --- /dev/null +++ b/frontend/src/components/server-management.tsx @@ -0,0 +1,382 @@ +import { Component } from 'react'; +import { connect } from 'react-redux'; +import axios from 'axios' +import GetApiServerUri from './helpers'; +import IsManager from './is_manager'; +import { + serversListUpdateFunc +} from 'redux/actions'; +import { showResponseToast } from './error-api'; +import { ServersList } from './types' +import { RootState } from 'redux/reducers'; +import { ToastContainer } from 'react-toastify'; +import { + TextInput, + Accordion, + AccordionItem, + InlineNotification +} from 'carbon-components-react'; +import Table from "tables/servers-list-table"; +import './style.css'; + +type ServerManagementProp = { + // returns the list of available servers and their basic info + serversListUpdateFunc: (globalServersList: ServersList[]) => void, + // the list of available servers and their basic info + globalServersList: ServersList[], + +} + +type ServerManagementState = { + formServerName: string, + formServerAddress: string, + formTLS: boolean, + formMTLS: boolean, + formCAData: string | null, + formCertData: string | null, + formKeyData: string | null, + CAFileText?: string, + certFileText?: string, + keyFileText?: string, + message: string, + statusOK: string, +} + +const Server = (props: { server: ServersList }) => ( + + {props.server.name} + {props.server.address} + {(props.server.mtls && "mTLS") || "None"} + {(props.server.tls && "TLS") || "None"} + +) + +class ServerManagement extends Component { + constructor(props: ServerManagementProp) { + super(props); + this.state = { + formServerName: "", + formServerAddress: "", + formTLS: false, + formMTLS: false, + formCAData: null, + formCertData: null, + formKeyData: null, + CAFileText: "", + certFileText: "", + keyFileText: "", + message: "", + statusOK: "", + }; + this.onCertFileChange = this.onCertFileChange.bind(this); + this.onCAFileChange = this.onCAFileChange.bind(this); + this.onKeyFileChange = this.onKeyFileChange.bind(this); + this.handleInputChange = this.handleInputChange.bind(this); + this.onSubmit = this.onSubmit.bind(this); + this.onChangeServerName = this.onChangeServerName.bind(this); + this.onChangeServerAddress = this.onChangeServerAddress.bind(this); + } + + componentDidMount() { + this.refreshServerState() + } + + refreshServerState() { + axios.get(GetApiServerUri("/manager-api/server/list"), { crossdomain: true }) + .then(response => { + console.log(response.data); + this.props.serversListUpdateFunc(response.data["servers"]); + }) + .catch((error) => showResponseToast(error, { caption: "Could not refresh server state." })) + } + + serverList() { + if (typeof this.props.globalServersList !== 'undefined') { + return this.props.globalServersList.map(s => { + return ; + }) + } else { + return "" + } + } + + handleInputChange(e: { target: any; }) { + const target = e.target; + const value = target.type === 'checkbox' ? target.checked : target.value; + const name = target.name; + this.setState((prevState: ServerManagementState) => ({ + ...prevState, + [name]: value + })); + } + + onChangeServerName(e: { target: { value: string; }; } | undefined): void { + if (e === undefined) { + return; + } + var sid = e.target.value; + this.setState({ + formServerName: sid, + }); + } + + onChangeServerAddress(e: { target: { value: string; }; } | undefined): void { + if (e === undefined) { + return; + } + var sid = e.target.value; + this.setState({ + formServerAddress: sid, + }); + } + + onCAFileChange = (event: React.ChangeEvent) => { + const files = event.target.files; + if (files && files[0]) { + const reader = new FileReader(); + reader.onload = (e: ProgressEvent) => { + if (e.target && e.target.result) { + const result = e.target.result; + + // Handle string and ArrayBuffer cases + if (typeof result === "string") { + this.setState({ + formCAData: Buffer.from(result).toString("base64"), + CAFileText: "CA file load success", + }); + } else if (result instanceof ArrayBuffer) { + this.setState({ + formCAData: Buffer.from(new Uint8Array(result)).toString("base64"), + CAFileText: "CA file load success", + }); + } + } + }; + reader.readAsText(files[0]); + } + }; + + onCertFileChange = (event: React.ChangeEvent) => { + const files = event.target.files; + if (files && files[0]) { + const reader = new FileReader(); + reader.onload = (e: ProgressEvent) => { + if (e.target && e.target.result) { + const result = e.target.result; + + // Handle string and ArrayBuffer cases + if (typeof result === "string") { + this.setState({ + formCertData: Buffer.from(result).toString("base64"), + certFileText: "cert file load success", + }); + } else if (result instanceof ArrayBuffer) { + this.setState({ + formCertData: Buffer.from(new Uint8Array(result)).toString("base64"), + certFileText: "cert file load success", + }); + } + } + }; + reader.readAsText(files[0]); + } + }; + + onKeyFileChange = (event: React.ChangeEvent) => { + const files = event.target.files; + if (files && files[0]) { + const reader = new FileReader(); + reader.onload = (e: ProgressEvent) => { + if (e.target && e.target.result) { + const result = e.target.result; + + // Handle string and ArrayBuffer cases + if (typeof result === "string") { + this.setState({ + formKeyData: Buffer.from(result).toString("base64"), + keyFileText: "key file load success", + }); + } else if (result instanceof ArrayBuffer) { + this.setState({ + formKeyData: Buffer.from(new Uint8Array(result)).toString("base64"), + keyFileText: "key file load success", + }); + } + } + }; + reader.readAsText(files[0]); + } + }; + + + + + onSubmit(e: { preventDefault: () => void; }) { + e.preventDefault(); + + console.log("onSubmit"); + var cjtData = { + "name": this.state.formServerName, + "address": this.state.formServerAddress, + "tls": this.state.formTLS, + "mtls": this.state.formMTLS, + "ca": this.state.formCAData, + "cert": this.state.formCertData, + "key": this.state.formKeyData, + }; + axios.post(GetApiServerUri('/manager-api/server/register'), cjtData) + .then(res => { + this.setState({ + message: "Requst:" + JSON.stringify(cjtData, null, ' ') + "\n\nSuccess:" + JSON.stringify(res.data, null, ' '), + statusOK: "OK", + }); + this.refreshServerState(); + } + ) + .catch(err => { + showResponseToast(err) + this.setState({ + message: "ERROR:" + err + (typeof (err.response) !== "undefined" ? err.response.data : ''), + statusOK: "ERROR", + }) + }) + + } + + + render() { + if (!IsManager) { + return

Only manager deployments have use of this page

+ } + + const tlsFormOptions = ( +
CA File (for (m)TLS): + + {this.state.CAFileText} +
+ ) + + const mtlsFormOptions = ( +
+
+ Cert File (for mTLS): + + {this.state.certFileText} +
+
Key File (for mTLS): + + {this.state.keyFileText} +
+
+ ) + + return ( +
+ + Register New Server } open> +
+
+
+ +
+
+ +
+
+ + TLS Enabled +
+ {this.state.formTLS && tlsFormOptions} + +
+ + mTLS Enabled +
+ {this.state.formMTLS && mtlsFormOptions} + +
+

+ +
+
+
+
+ {this.state.statusOK === "OK" && + +
+                        {this.state.message}
+                      
+
+ } + /> + } + {(this.state.statusOK === "ERROR") && + +
+                        {this.state.message}
+                      
+
+ } + /> + } +
+ + Servers List} open> + + + + + + ) + } +} + +const mapStateToProps = (state: RootState) => ({ + globalServersList: state.servers.globalServersList +}) + +export default connect( + mapStateToProps, + { serversListUpdateFunc } +)(ServerManagement) diff --git a/frontend/src/components/style.css b/frontend/src/components/style.css index c996de5b..213ffac0 100644 --- a/frontend/src/components/style.css +++ b/frontend/src/components/style.css @@ -376,6 +376,18 @@ margin-top: 7px; } +.manager-toolbar-header { + position: relative; + display: inline; + padding: 15px; + color: white; + border: 0.1px solid white; + padding: 4px; + float: right; + margin-right: 10px; + margin-top: 7px; +} + .health-check { position: relative; z-index: 3; @@ -434,3 +446,23 @@ display: inline; float: right; /* Float to the right */ } + +.tls-mtls-enabled input { + margin-right: 10px; + margin-bottom: 10px; +} + +.server-form { + margin-left: auto; + margin-right: auto; + margin-bottom: 20px; + width: 1000px; + border-width: 1px; + border-style: solid; + border-color: rgb(180, 178, 178); + padding: 30px 30px 30px 30px; +} + +.server-select-dropdown { + margin-top: 20px; +} \ No newline at end of file diff --git a/frontend/src/components/tornjak-api-helpers.tsx b/frontend/src/components/tornjak-api-helpers.tsx index 5a1d4f64..d58f1016 100644 --- a/frontend/src/components/tornjak-api-helpers.tsx +++ b/frontend/src/components/tornjak-api-helpers.tsx @@ -164,7 +164,7 @@ class TornjakApi extends Component { }) .catch((error) => { showResponseToast(error, { caption: "Could not populate local tornjak server info." }) - tornjakMessageFunc(error.response.statusText) + tornjakMessageFunc(error) }) } diff --git a/frontend/src/components/tornjak-server-info.tsx b/frontend/src/components/tornjak-server-info.tsx index 45ab2b61..47519b06 100644 --- a/frontend/src/components/tornjak-server-info.tsx +++ b/frontend/src/components/tornjak-server-info.tsx @@ -56,7 +56,7 @@ const TornjakServerInfoDisplay = (props: { tornjakServerInfo: TornjakServInfo, t

- {props.tornjakDebugInfo.svid_chain[0].id.trust_domain} + {props.tornjakServerInfo.trustDomain}

diff --git a/frontend/src/components/types.ts b/frontend/src/components/types.ts index a91caf2f..61fdec20 100644 --- a/frontend/src/components/types.ts +++ b/frontend/src/components/types.ts @@ -128,6 +128,14 @@ export interface SpireHealthCheckFreq { SpireHealthCheckFreqDisplay: string; // SPIRE health check dropdown display/ for persistence } +// servers +export interface ServersList { + name: string; // Name of Server + address: string; // url + mtls: string; // mtls + tls: string; // tls +} + // tornjak export interface StringLabels { label: string; diff --git a/frontend/src/redux/actions/index.ts b/frontend/src/redux/actions/index.ts index dc0ba4ca..3a9b2f8a 100644 --- a/frontend/src/redux/actions/index.ts +++ b/frontend/src/redux/actions/index.ts @@ -51,6 +51,7 @@ import { AgentsList, AgentsWorkLoadAttestorInfo, ClustersList, + ServersList, EntriesList, SelectorInfoLabels, ServerInfo, @@ -233,7 +234,7 @@ export function serverInfoUpdateFunc(globalServerInfo: ServerInfo): ThunkAction< // } // ] // serversListUpdateFunc returns the list of available servers and their basic info -export function serversListUpdateFunc(globalServersList: Array): ThunkAction { +export function serversListUpdateFunc(globalServersList: ServersList[]): ThunkAction { return dispatch => { dispatch({ type: GLOBAL_SERVERS_LIST, diff --git a/frontend/src/redux/actions/types.ts b/frontend/src/redux/actions/types.ts index 58b8586c..d4541e09 100644 --- a/frontend/src/redux/actions/types.ts +++ b/frontend/src/redux/actions/types.ts @@ -3,6 +3,7 @@ import { AgentsList, AgentsWorkLoadAttestorInfo, ClustersList, + ServersList, EntriesList, SelectorInfoLabels, ServerInfo, @@ -104,7 +105,7 @@ export interface ServersReducerState { globalServerSelected: string, globalServerInfo: ServerInfo, globalTornjakServerInfo: TornjakServerInfo, - globalServersList: Array, + globalServersList: ServersList[], globalSelectorInfo: SelectorInfoLabels, globalWorkloadSelectorInfo: WorkloadSelectorInfoLabels, globalSpireHealthCheck: boolean, @@ -126,7 +127,7 @@ export interface TornjakServerInfoAction extends Action { - payload: Array; + payload: ServersList[]; } export interface SelectorInfoAction extends Action { payload: SelectorInfoLabels; diff --git a/frontend/src/tables/clusters-list-table.tsx b/frontend/src/tables/clusters-list-table.tsx index 276fe130..2e81cef2 100644 --- a/frontend/src/tables/clusters-list-table.tsx +++ b/frontend/src/tables/clusters-list-table.tsx @@ -1,8 +1,6 @@ import React from "react"; import { connect } from 'react-redux'; import IsManager from 'components/is_manager'; -import GetApiServerUri from 'components/helpers'; -import axios from 'axios'; import { clustersListUpdateFunc } from 'redux/actions'; @@ -10,7 +8,6 @@ import Table from './list-table'; import { ClustersList } from "components/types"; import { DenormalizedRow } from "carbon-components-react"; import { RootState } from "redux/reducers"; -import { showResponseToast } from "components/error-api"; import TornjakApi from 'components/tornjak-api-helpers'; // ClusterListTable takes in diff --git a/frontend/src/tables/entries-list-table.tsx b/frontend/src/tables/entries-list-table.tsx index 1dd33e83..8b6f422b 100644 --- a/frontend/src/tables/entries-list-table.tsx +++ b/frontend/src/tables/entries-list-table.tsx @@ -1,8 +1,6 @@ import React from "react"; import { connect } from 'react-redux'; -import GetApiServerUri from 'components/helpers'; import IsManager from 'components/is_manager'; -import axios from 'axios' import { entriesListUpdateFunc } from 'redux/actions'; @@ -11,8 +9,6 @@ import { EntriesList } from "components/types"; import { RootState } from "redux/reducers"; import { DenormalizedRow } from "carbon-components-react"; import { saveAs } from "file-saver"; -import { showResponseToast } from "components/error-api"; -import apiEndpoints from 'components/apiConfig'; import TornjakApi from 'components/tornjak-api-helpers'; // EntriesListTable takes in diff --git a/frontend/src/tables/list-table.tsx b/frontend/src/tables/list-table.tsx index aa698768..996d82cf 100644 --- a/frontend/src/tables/list-table.tsx +++ b/frontend/src/tables/list-table.tsx @@ -20,7 +20,7 @@ const { type DataTableRenderProp = { listTableData: DataTableRow[], headerData: DataTableHeader[], - deleteEntity: (selectedRows: readonly DenormalizedRow[]) => string | void, + deleteEntity: ((selectedRows: readonly DenormalizedRow[]) => string | void) | undefined, banEntity: ((selectedRows: readonly DenormalizedRow[]) => string | void) | undefined, downloadEntity: ((selectedRows: readonly DenormalizedRow[]) => string | undefined | void) | undefined, entityType: string, diff --git a/frontend/src/tables/servers-list-table.tsx b/frontend/src/tables/servers-list-table.tsx new file mode 100644 index 00000000..f559fea7 --- /dev/null +++ b/frontend/src/tables/servers-list-table.tsx @@ -0,0 +1,160 @@ +import React from "react"; +import { connect } from 'react-redux'; +// import IsManager from 'components/is_manager'; +import { + serversListUpdateFunc +} from 'redux/actions'; +import Table from './list-table'; +import { ServersList } from "components/types"; +// import { DenormalizedRow } from "carbon-components-react"; +import { RootState } from "redux/reducers"; +import TornjakApi from 'components/tornjak-api-helpers'; + +// ServersListTable takes in +// listTableData: servers data to be rendered on table +// returns servers data inside a carbon component table with specified functions + +type ServersListTableProp = { + // dispatches a payload for list of servers with their metadata info as an array of ServersList Type and has a return type of void + serversListUpdateFunc: (globalServersList: ServersList[]) => void, + // data provided to the servers table + data: { + key: string, + props: { server: ServersList } + }[] | string | JSX.Element[], + id: string, + // list of servers with their metadata info as an array of ServersList Type + globalServersList: ServersList[], + // the selected server for manager mode + globalServerSelected: string, +} + +type ServersListTableState = { + listData: { key: string, props: { server: ServersList } }[] | ServersList[] | string | JSX.Element[], + listTableData: { + id: string; + serverName: string; + serverAddress: string; + tls: string; + mtls: string; + }[] + +} +class ServersListTable extends React.Component { + TornjakApi: TornjakApi; + constructor(props: ServersListTableProp) { + super(props); + this.TornjakApi = new TornjakApi(props); + this.state = { + listData: props.data, + listTableData: [], + }; + this.prepareTableData = this.prepareTableData.bind(this); + // this.deleteServer = this.deleteServer.bind(this); + } + + componentDidMount() { + this.prepareTableData(); + } + componentDidUpdate(prevProps: ServersListTableProp) { + if (prevProps !== this.props) { + this.setState({ + listData: this.props.globalServersList + }) + this.prepareTableData(); + } + } + + prepareTableData() { + const { data } = this.props; + let listData: { props: { server: ServersList; }; }[] | ({ key: string; props: { server: ServersList; }; } | JSX.Element)[] = []; + if (typeof (data) === "string" || data === undefined) + return + data.forEach(val => listData.push(Object.assign({}, val))); + let listtabledata: { id: string; serverName: string; serverAddress: string; tls: string; mtls: string;}[] = []; + for (let i = 0; i < listData.length; i++) { + listtabledata[i] = { id: "", serverName: "", serverAddress: "", tls: "", mtls: ""}; + listtabledata[i]["id"] = (i + 1).toString(); + listtabledata[i]["serverName"] = listData[i].props.server.name; + listtabledata[i]["serverAddress"] = listData[i].props.server.address; + listtabledata[i]["tls"] = listData[i].props.server.tls ? listData[i].props.server.tls : "None"; + listtabledata[i]["mtls"] = listData[i].props.server.mtls ? listData[i].props.server.mtls : "None"; + } + this.setState({ + listTableData: listtabledata + }) + } + + //Note: future implementation - server delete function + // keep code + // deleteServer(selectedRows: readonly DenormalizedRow[]) { + // if (!selectedRows || selectedRows.length === 0) return ""; + // let server: { name: string }[] = [], successMessage + + // for (let i = 0; i < selectedRows.length; i++) { + // server[i] = { name: selectedRows[i].cells[1].value }; + // if (IsManager) { + // successMessage = this.TornjakApi.serverDelete(this.props.globalServerSelected, { server: server[i] }, this.props.serversListUpdateFunc, this.props.globalServersList); + // } else { + // successMessage = this.TornjakApi.localServerDelete({ server: server[i] }, this.props.serversListUpdateFunc, this.props.globalServersList); + // } + // successMessage.then(function (result) { + // if (result === "SUCCESS") { + // window.alert(`CLUSTER "${server[i].name}" DELETED SUCCESSFULLY!`); + // window.location.reload(); + // } else { + // window.alert(`Error deleting server "${server[i].name}": ` + result); + // } + // return; + // }) + // } + // } + + + render() { + const { listTableData } = this.state; + const headerData = [ + { + header: '#No', + key: 'id', + }, + { + header: 'Server Name', + key: 'serverName', + }, + { + header: 'Server Address', + key: 'serverAddress', + }, + { + header: 'TLS', + key: 'tls', + }, + { + header: 'mTLS', + key: 'mtls', + } + ]; + return ( +
+
+ + ); + } +} + +const mapStateToProps = (state: RootState) => ({ + globalServerSelected: state.servers.globalServerSelected, + globalServersList: state.servers.globalServersList, +}) + +export default connect( + mapStateToProps, + { serversListUpdateFunc } +)(ServersListTable) \ No newline at end of file diff --git a/frontend/src/tables/table-toolbar.tsx b/frontend/src/tables/table-toolbar.tsx index 8e4330c9..c4446ace 100644 --- a/frontend/src/tables/table-toolbar.tsx +++ b/frontend/src/tables/table-toolbar.tsx @@ -26,7 +26,7 @@ const Auth_Server_Uri = env.REACT_APP_AUTH_SERVER_URI; // selectedRows: selectedRows from DataTable // returns the toolbar of the table for the specified entity type TableToolBarProp = { - deleteEntity: (selectedRows: readonly DenormalizedRow[]) => string | void, + deleteEntity: ((selectedRows: readonly DenormalizedRow[]) => string | void) | undefined, banEntity: ((selectedRows: readonly DenormalizedRow[]) => string | void) | undefined, downloadEntity: ((selectedRows: readonly DenormalizedRow[]) => void) | undefined, onInputChange: (event: React.SyntheticEvent) => void, @@ -60,7 +60,8 @@ class TableToolBar extends React.Component renderIcon={IoTrashOutline} iconDescription="Delete" onClick={() => { - this.props.deleteEntity(this.props.selectedRows); + if(this.props.deleteEntity !== undefined) + this.props.deleteEntity(this.props.selectedRows); this.props.getBatchActionProps().onCancel(); }} > diff --git a/go.mod b/go.mod index 76cb820c..07cdd025 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/spiffe/tornjak go 1.22 +toolchain go1.22.2 + require ( github.com/MicahParks/keyfunc/v2 v2.1.0 github.com/cenkalti/backoff/v4 v4.2.0