nope/resources/admin-shell/instanceOverview.tsx
2021-02-12 15:54:57 +01:00

219 lines
6.5 KiB
TypeScript

/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2021-02-11 08:02:28
* @modify date 2021-02-11 13:45:57
* @desc [description]
*/
import React from "react";
import { Alert, Col, Container, Row, Table } from "react-bootstrap";
import {
nopeDispatcherManager
} from "../../lib/dispatcher/nopeDispatcherManager";
import { ENopeDispatcherStatus } from "../../lib/types/nope/nopeDispatcher.interface";
import { INopeObserver } from "../../lib/types/nope/nopeObservable.interface";
import { StatusBadgeComponent } from "./generic/StatusBadge";
import { InstanceDetailsComponent, InstanceDetailsState } from "./instance/InstanceDetails";
export class InstanceOverviewComponent extends React.Component<
{ dispatcher: nopeDispatcherManager; maxItemsInRow?: 2 | 3 | 4, renderDetails?: boolean },
{ connected: boolean; instances: InstanceDetailsState[][], maxItemsInRow: number }
> {
/**
* List containing Observables
*
* @private
* @type {INopeObserver[]}
* @memberof InstanceOverviewComponent
*/
private _observer: INopeObserver[] = [];
/**
* Function, which will be used to refresh the Nodes.
*/
private _refresh() {
if (this.props.dispatcher?.getHostInfos) {
// Get the connected Flag
const connected = this.props.dispatcher.communicator.connected.getContent();
const computingNodes = this.props.dispatcher.getHostInfos();
const computingNodesAsList = Object.getOwnPropertyNames(computingNodes).map(key => computingNodes[key]);
const allInstances = this.props.dispatcher.availableInstances.getContent();
console.log(allInstances.length);
const mappingIndexToName = new Map<string,number>();
const instances: InstanceDetailsState[] = allInstances.map((item,idx) => {
mappingIndexToName.set(item.identifier,idx);
return Object.assign({
status: ENopeDispatcherStatus.HEALTHY,
dispatchers: [],
redundant: false,
}, item);
});
for (const node of computingNodesAsList){
for (const instance of node.instances){
if (mappingIndexToName.has(instance.identifier)){
// Add the Dispatcher, update the Status of the Component
instances[mappingIndexToName.get(instance.identifier)].status = Math.max(instances[mappingIndexToName.get(instance.identifier)].status, instance.status);
instances[mappingIndexToName.get(instance.identifier)].dispatchers.push(instance.dispatcher);
instances[mappingIndexToName.get(instance.identifier)].redundant = instances[mappingIndexToName.get(instance.identifier)].dispatchers.length > 1;
}
}
}
const renderingInstances: InstanceDetailsState[][] = [];
const maxItems = this.props.renderDetails
? this.props.maxItemsInRow || 2
: instances.length * 2 ;
// Function to Split the Dispatcher Array into an array containing max 3 elements.
for (let i = 0; i < instances.length; i = i + maxItems) {
renderingInstances.push(instances.slice(i, i + maxItems));
}
this.setState({
instances: renderingInstances,
connected,
maxItemsInRow: maxItems
});
}
}
/**
* Function will be called if the Item has been rendered sucessfully.
*/
public componentDidMount(): void {
if (this.props.dispatcher?.getHostInfos) {
// Subscribe to the Instances.
const _this = this;
this._observer.push(
this.props.dispatcher.availableInstances.subscribe(() => {
console.log("HERE");
_this._refresh();
})
);
this._observer.push(
this.props.dispatcher.externalDispatchers.subscribe(() => {
console.log("HERE");
_this._refresh();
})
);
this._observer.push(
this.props.dispatcher.communicator.connected.subscribe(() => {
_this._refresh();
})
);
// Render the Elements
this._refresh();
}
}
/**
* Function, that will be called before the network fails.
*/
public componentWillUnmount(): void {
// Call the unmount
for (const _observer of this._observer) {
_observer.unsubscribe();
}
}
constructor(props) {
super(props);
this.state = {
connected: false,
instances: [],
maxItemsInRow: 1
};
}
public render() {
if (this.state.connected) {
if (this.props.renderDetails) {
const sm = Math.round(12 / this.state.maxItemsInRow);
return (
<Container>
{this.state.instances.map((row, idx_01) => {
return (
<Row
key={idx_01}
style={{ paddingTop: "0.5rem", paddingBottom: "0.5rem" }}
>
{row.map((item, idx_02) => {
return (
<Col key={`${idx_01}_${idx_02}`} sm={sm}>
<InstanceDetailsComponent description={item} renderDetails={true}></InstanceDetailsComponent>
</Col>
);
})}
</Row>
);
})}
</Container>
);
}
if (this.state.instances.length > 0) {
return (
<Table striped bordered hover>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Status</th>
<th>Redundant</th>
</tr>
</thead>
<tbody>
{this.state.instances[0].map((item, idx) => (
<tr key={idx}>
<td>{item.identifier}</td>
<td><code>{item.type}</code></td>
<td>
<StatusBadgeComponent
status={item.status}
></StatusBadgeComponent>
</td>
<td>
{item.redundant.toString()}
</td>
</tr>
))}
</tbody>
</Table>
);
}
return (
<Alert variant={"warning"}>
No Instance Found <b>:'(</b>
</Alert>
);
} else {
return (
<>
<Alert variant={"danger"}>
Not able to connect to the Backend <b>:'(</b>
</Alert>
<p>
Please start a Nope-Backend with the following command:{" "}
<code>nope run -c io-server</code>
</p>
</>
);
}
}
}