Updating Packageloader
This commit is contained in:
parent
9a9ddc9ac9
commit
2e10d8e3ba
@ -2,7 +2,7 @@
|
||||
* @author Martin Karkowski
|
||||
* @email m.karkowski@zema.de
|
||||
* @create date 2021-02-09 11:26:58
|
||||
* @modify date 2021-02-12 08:18:03
|
||||
* @modify date 2021-02-12 15:05:05
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
ENopeDispatcherStatus,
|
||||
IDispatcherInfo
|
||||
} from "../types/nope/nopeDispatcher.interface";
|
||||
import { INopeModule } from "../types/nope/nopeModule.interface";
|
||||
import { INopeObservable } from "../types/nope/nopeObservable.interface";
|
||||
import { nopeDispatcher } from "./nopeDispatcher";
|
||||
|
||||
@ -119,6 +120,34 @@ export class nopeDispatcherManager extends nopeDispatcher {
|
||||
return Array.from(hosts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the instances of the given Type.
|
||||
*
|
||||
* @param {string} type
|
||||
* @return {*} {INopeModuleDescription[]}
|
||||
* @memberof nopeDispatcherManager
|
||||
*/
|
||||
public async getInstancesOfType<I extends INopeModule>(type:string) {
|
||||
const indentifier = this.availableInstances.getContent()
|
||||
.filter(item => item.type == type)
|
||||
.map(item => item.identifier);
|
||||
|
||||
const promises: Promise<I>[] = [];
|
||||
|
||||
for (const identifier of indentifier) {
|
||||
promises.push(this.generateInstance({
|
||||
identifier,
|
||||
type,
|
||||
params: []
|
||||
}));
|
||||
}
|
||||
|
||||
// Wait to generate all Instances.
|
||||
const result = await Promise.all(promises);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public getHostInfos(): {
|
||||
[index: string]: HostInfo
|
||||
} {
|
||||
|
@ -2,7 +2,7 @@
|
||||
* @author Martin Karkowski
|
||||
* @email m.karkowski@zema.de
|
||||
* @create date 2020-08-25 14:52:52
|
||||
* @modify date 2020-08-25 18:13:54
|
||||
* @modify date 2021-02-12 14:28:46
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
@ -10,8 +10,8 @@ declare const process: any;
|
||||
declare const setImmediate: any;
|
||||
|
||||
const _runningInNode = (
|
||||
typeof process !== 'undefined' &&
|
||||
typeof process.release !== 'undefined') && ((process as any).release.name === 'node');
|
||||
typeof process !== "undefined" &&
|
||||
typeof process.release !== "undefined") && ((process as any).release.name === "node");
|
||||
|
||||
/**
|
||||
* Function to call a function something direct async
|
||||
@ -33,3 +33,5 @@ export const callDirect = (callback: (...args) => void, ...args) => {
|
||||
};
|
||||
|
||||
export const RUNNINGINNODE = _runningInNode;
|
||||
export const RUNNINGINWINDOWS = _runningInNode ? (require("os").type() != "Linux") : false;
|
||||
export const RUNNINGINLINUX = _runningInNode ? (require("os").type() === "Linux") : false;
|
@ -2,13 +2,14 @@
|
||||
* @author Martin Karkowski
|
||||
* @email m.karkowski@zema.de
|
||||
* @create date 2018-07-01 09:10:35
|
||||
* @modify date 2020-12-02 08:57:36
|
||||
* @modify date 2021-02-12 15:53:57
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
import { Container, injectable, interfaces } from "inversify";
|
||||
import { flatten } from "lodash";
|
||||
import "reflect-metadata";
|
||||
import { promisify } from "util";
|
||||
import { arraysEqual } from "../helpers/arrayMethods";
|
||||
import { RUNNINGINNODE } from "../helpers/runtimeMethods";
|
||||
import { getNopeLogger } from "../logger/getLogger";
|
||||
@ -22,6 +23,8 @@ import {
|
||||
} from "../types/nope/nopePackage.interface";
|
||||
import { INopePackageLoader } from "../types/nope/nopePackageLoader.interface";
|
||||
|
||||
const sleep = promisify(setTimeout);
|
||||
|
||||
/**
|
||||
* Helper Class to Build an inversify Container.
|
||||
*
|
||||
@ -660,6 +663,22 @@ export class NopePackageLoader implements INopePackageLoader {
|
||||
|
||||
// Store the Function, that the instance will be disposed on leaving.
|
||||
this._disposeDefaultInstance.push(() => instance.dispose());
|
||||
|
||||
if (definition.options.identifier in this.packages[name].autostart){
|
||||
// There are autostart Tasks in the Package for the considered Instance,
|
||||
// which has been recently defined.
|
||||
try {
|
||||
const autostart = this.packages[name].autostart[definition.options.identifier];
|
||||
for (const task of autostart ){
|
||||
if (task.delay){
|
||||
await sleep(task.delay);
|
||||
}
|
||||
await instance[task.service](task.params);
|
||||
}
|
||||
} catch(e) {
|
||||
this._logger.error("Failed with autostart tasks for " + instance.identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
140
modules/host-manager/src/hostManager.module.ts
Normal file
140
modules/host-manager/src/hostManager.module.ts
Normal file
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @author Martin Karkowski
|
||||
* @email m.karkowski@zema.de
|
||||
* @create date 2021-02-12 14:21:27
|
||||
* @modify date 2021-02-12 15:24:33
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
|
||||
import { exec } from "child_process";
|
||||
import { injectable } from "inversify";
|
||||
import { wake } from "node-wol";
|
||||
import { hostname, NetworkInterfaceInfo, networkInterfaces } from "os";
|
||||
import { promisify } from "util";
|
||||
import { exportMethod, exportProperty } from "../../../lib/decorators/moduleDecorators";
|
||||
import { RUNNINGINLINUX, RUNNINGINWINDOWS } from "../../../lib/helpers/runtimeMethods";
|
||||
import { getNopeLogger } from "../../../lib/logger/getLogger";
|
||||
import { InjectableNopeBaseModule } from "../../../lib/module/BaseModule.injectable";
|
||||
import { NopeObservable } from "../../../lib/observables/nopeObservable";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
const wolAsync = promisify(wake);
|
||||
|
||||
@injectable()
|
||||
export class HostManagerModule extends InjectableNopeBaseModule {
|
||||
protected _logger = getNopeLogger("host-manager", "info");
|
||||
|
||||
@exportProperty({
|
||||
mode: "publish",
|
||||
schema: {
|
||||
description: "An Observable containing the hostname of the controlled Host.",
|
||||
type: "string"
|
||||
},
|
||||
topic: "controlledHost"
|
||||
})
|
||||
public controlledHost = new NopeObservable<string>();
|
||||
|
||||
@exportProperty({
|
||||
mode: "publish",
|
||||
schema: {
|
||||
description: "An Observable containing the used Net",
|
||||
type: "string"
|
||||
},
|
||||
topic: "networkInterfaces"
|
||||
})
|
||||
public networkInterfaces = new NopeObservable<{[index:string]: NetworkInterfaceInfo[]}>();
|
||||
|
||||
async init() {
|
||||
// Define the Author.
|
||||
this.author = {
|
||||
forename: "Martin",
|
||||
mail: "m.karkowski@zema.de",
|
||||
surename: "karkowski"
|
||||
};
|
||||
this.description =
|
||||
"The Host-Manger provides functions, to shutdow / reboot the Host.";
|
||||
this.version = {
|
||||
date: new Date("12.02.2020"),
|
||||
version: 1
|
||||
};
|
||||
|
||||
// Assign the Hostname to the Element.
|
||||
this.controlledHost.setContent(hostname());
|
||||
this.networkInterfaces.setContent(networkInterfaces());
|
||||
|
||||
await super.init();
|
||||
|
||||
const _this = this;
|
||||
|
||||
this._dispatcher.subscribedEvents.forcePublish();
|
||||
|
||||
// Singal, that the system is online
|
||||
_this._logger.info("system online");
|
||||
}
|
||||
|
||||
/**
|
||||
* Function, used to kill an Process, which is running on the Host.
|
||||
*
|
||||
* @param {number} pid
|
||||
* @memberof HostManagerModule
|
||||
*/
|
||||
@exportMethod({
|
||||
paramsHasNoCallback: true
|
||||
})
|
||||
public async killProcess(pid:number){
|
||||
if (RUNNINGINWINDOWS){
|
||||
await execAsync("taskkill /F /PID "+pid.toString());
|
||||
} else if (RUNNINGINLINUX){
|
||||
throw Error("Currently not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function, used to reboot the System
|
||||
*
|
||||
* @memberof HostManagerModule
|
||||
*/
|
||||
@exportMethod({
|
||||
paramsHasNoCallback: true
|
||||
})
|
||||
public async reboot(){
|
||||
if (RUNNINGINWINDOWS){
|
||||
this._logger.warn("Rebootin host.");
|
||||
await execAsync("shutdown -r");
|
||||
} else if (RUNNINGINLINUX){
|
||||
throw Error("Currently not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a Wake on Lan Signal to the desired MAC.
|
||||
*
|
||||
* @param {string} mac
|
||||
* @memberof HostManagerModule
|
||||
*/
|
||||
@exportMethod({
|
||||
paramsHasNoCallback: true
|
||||
})
|
||||
public async wake(mac: string){
|
||||
this._logger.info("Sending Wake-On-Lan to "+mac);
|
||||
await wolAsync(mac);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function used to shutdown a Computer.
|
||||
*
|
||||
* @memberof HostManagerModule
|
||||
*/
|
||||
@exportMethod({
|
||||
paramsHasNoCallback: true
|
||||
})
|
||||
public async shutdown(){
|
||||
if (RUNNINGINWINDOWS){
|
||||
this._logger.warn("Shutdown host.");
|
||||
await execAsync("shutdown -s");
|
||||
} else if (RUNNINGINLINUX){
|
||||
throw Error("Currently not implemented");
|
||||
}
|
||||
}
|
||||
}
|
59
modules/host-manager/src/hostManager.package.ts
Normal file
59
modules/host-manager/src/hostManager.package.ts
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @author Martin Karkowski
|
||||
* @email m.karkowski@zema.de
|
||||
* @create date 2021-02-12 14:54:53
|
||||
* @modify date 2021-02-12 15:22:40
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
|
||||
import { hostname } from "os";
|
||||
import { IPackageDescription } from "../../../lib/types/nope/nopePackage.interface";
|
||||
import { HostManagerModule } from "./hostManager.module";
|
||||
|
||||
const TYPES = {
|
||||
HostManager: Symbol.for("HostManagerModule")
|
||||
};
|
||||
|
||||
const identifier = hostname()+"-host-manager";
|
||||
const autostart: IPackageDescription<any>["autostart"] = {};
|
||||
autostart[identifier] = [
|
||||
{
|
||||
service: "shutdown",
|
||||
params: []
|
||||
}
|
||||
];
|
||||
|
||||
export const DESCRIPTION: IPackageDescription<typeof TYPES> = {
|
||||
activationHandlers: [],
|
||||
autostart: {},
|
||||
defaultInstances: [
|
||||
{
|
||||
options: {
|
||||
identifier,
|
||||
params: [],
|
||||
type: HostManagerModule.prototype.constructor.name.toString()
|
||||
},
|
||||
selector: HostManagerModule.prototype.constructor.name.toString()
|
||||
}
|
||||
],
|
||||
nameOfPackage: "hostManagerPackage",
|
||||
providedClasses: [
|
||||
{
|
||||
description: {
|
||||
name: HostManagerModule.prototype.constructor.name.toString(),
|
||||
selector: TYPES.HostManager,
|
||||
type: HostManagerModule
|
||||
},
|
||||
settings: {
|
||||
allowInstanceGeneration: true,
|
||||
maxAmountOfInstance: 1
|
||||
}
|
||||
}
|
||||
],
|
||||
providedFunctions: [],
|
||||
requiredPackages: [],
|
||||
types: TYPES
|
||||
};
|
||||
|
||||
export default DESCRIPTION;
|
5
package-lock.json
generated
5
package-lock.json
generated
@ -10116,6 +10116,11 @@
|
||||
"xml": "0.0.12"
|
||||
}
|
||||
},
|
||||
"node-wol": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-wol/-/node-wol-0.1.1.tgz",
|
||||
"integrity": "sha1-m+F/6LeZxeAKaq1ciTb0NoTl6D0="
|
||||
},
|
||||
"noop-logger": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
|
||||
|
@ -70,6 +70,7 @@
|
||||
"node-ads": "^1.5.1",
|
||||
"node-rest-client": "^3.1.0",
|
||||
"node-windows": "^1.0.0-beta.5",
|
||||
"node-wol": "^0.1.1",
|
||||
"npm": "^7.5.2",
|
||||
"npx": "^10.2.2",
|
||||
"openapi-typescript-codegen": "^0.5.3",
|
||||
|
@ -1,174 +0,0 @@
|
||||
import { faHatWizard } from "@fortawesome/free-solid-svg-icons";
|
||||
import * as React from "react";
|
||||
import { HostInfo, nopeDispatcherManager } from "../../lib/dispatcher/nopeDispatcherManager";
|
||||
import { ComputingNodeOverviewComponent } from "../../resources/admin-shell/computingNodeOverview";
|
||||
import { HostStatusComponent } from "../../resources/admin-shell/host/HostStatus";
|
||||
import { InstanceOverviewComponent } from "../../resources/admin-shell/instanceOverview";
|
||||
import DynLayout, {
|
||||
IDynamicLayoutProps
|
||||
} from "../../resources/ui/layout/dynamicLayout";
|
||||
|
||||
export interface DynLayoutProps {dispatcher: nopeDispatcherManager}
|
||||
|
||||
export interface DynLayoutState {computingNodes: HostInfo[]}
|
||||
|
||||
class TestDynLayoutComponent extends React.Component<
|
||||
DynLayoutProps,
|
||||
DynLayoutState
|
||||
> {
|
||||
|
||||
componentDidMount(): void {
|
||||
let nDispatchers = this.props.dispatcher.externalDispatchers.getContent().length;
|
||||
|
||||
const computingNodes = this.props.dispatcher.getHostInfos();
|
||||
const computingNodesAsList = Object.getOwnPropertyNames(computingNodes).map(key => computingNodes[key]);
|
||||
|
||||
this.props.dispatcher.externalDispatchers.subscribe((dispatchers) => {
|
||||
if (nDispatchers != dispatchers.length){
|
||||
nDispatchers = dispatchers.length;
|
||||
const computingNodes = this.props.dispatcher.getHostInfos();
|
||||
const computingNodesAsList = Object.getOwnPropertyNames(computingNodes).map(key => computingNodes[key]);
|
||||
|
||||
this.setState({
|
||||
computingNodes: computingNodesAsList
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({
|
||||
computingNodes: computingNodesAsList
|
||||
});
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
computingNodes: []
|
||||
};
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const cols = 15;
|
||||
|
||||
const settings: IDynamicLayoutProps<any> = {
|
||||
components: [
|
||||
{
|
||||
visible: true,
|
||||
component(props) {
|
||||
return (
|
||||
<>
|
||||
<h5>Nodes</h5>
|
||||
<hr/>
|
||||
<ComputingNodeOverviewComponent
|
||||
renderDetails={false}
|
||||
dispatcher={props.dispatcher}
|
||||
></ComputingNodeOverviewComponent>
|
||||
</>
|
||||
);
|
||||
},
|
||||
gridSettings: {
|
||||
h: 2,
|
||||
w: 10,
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
id: "NopeOverview",
|
||||
label: "NopeOverview",
|
||||
props: {
|
||||
dispatcher: this.props.dispatcher
|
||||
},
|
||||
hideable: true,
|
||||
bg: "light"
|
||||
},
|
||||
{
|
||||
visible: true,
|
||||
component(props) {
|
||||
return (
|
||||
<>
|
||||
<h5>Instances</h5>
|
||||
<hr/>
|
||||
<InstanceOverviewComponent
|
||||
dispatcher={props.dispatcher}
|
||||
renderDetails={false}
|
||||
></InstanceOverviewComponent>
|
||||
</>
|
||||
);
|
||||
},
|
||||
gridSettings: {
|
||||
h: 2,
|
||||
w: 5,
|
||||
x: 10,
|
||||
y: 0
|
||||
},
|
||||
id: "InstanceOverview",
|
||||
label: "InstanceOverview",
|
||||
props: {
|
||||
dispatcher: this.props.dispatcher
|
||||
},
|
||||
hideable: true,
|
||||
bg: "light"
|
||||
}
|
||||
],
|
||||
layoutSettings: {
|
||||
width: process.browser ? window.innerWidth : 1920,
|
||||
autoSize: false,
|
||||
preventCollision: false,
|
||||
cols,
|
||||
compactType: "horizontal"
|
||||
},
|
||||
toolbar: {
|
||||
items: [
|
||||
{
|
||||
type: "link",
|
||||
label: "docs",
|
||||
ref: "/docs",
|
||||
icon: faHatWizard
|
||||
}
|
||||
]
|
||||
},
|
||||
generateData() {
|
||||
return {
|
||||
content: "hello"
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let lineCounter = 0;
|
||||
let rowCounter = 0;
|
||||
for (const node of this.state.computingNodes){
|
||||
settings.components.push({
|
||||
component(props: {node: HostInfo, dispatcher: nopeDispatcherManager}){
|
||||
return (<HostStatusComponent
|
||||
host={props.node.name}
|
||||
renderDetails={true}
|
||||
dispatcher={props.dispatcher}
|
||||
ids={{}}
|
||||
></HostStatusComponent>);
|
||||
},
|
||||
gridSettings: {
|
||||
isResizable: true,
|
||||
x: rowCounter*5,
|
||||
y: 2+ lineCounter*3,
|
||||
h: 3,
|
||||
w: 5
|
||||
},
|
||||
id: node.name,
|
||||
label: `${node.name}-Details`,
|
||||
props: {node, dispatcher: this.props.dispatcher},
|
||||
visible: true,
|
||||
hideable: true,
|
||||
preventRenderingCard: true
|
||||
});
|
||||
|
||||
rowCounter = rowCounter + 1;
|
||||
if (rowCounter === 3){
|
||||
lineCounter = lineCounter +1;
|
||||
rowCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return React.createElement(DynLayout, settings);
|
||||
}
|
||||
}
|
||||
|
||||
export default TestDynLayoutComponent;
|
@ -6,7 +6,8 @@
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
import { faHashtag } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faHashtag, faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import React from "react";
|
||||
import {
|
||||
Alert,
|
||||
@ -114,17 +115,16 @@ class OverviewComponent extends React.Component<
|
||||
<Button
|
||||
variant="light"
|
||||
style={{ width: "100%" }}
|
||||
onClick={() => this._refreshState()}
|
||||
onClick={() => this.props.dispatcher.emitBonjour()}
|
||||
>
|
||||
Manual Refresh
|
||||
</Button>
|
||||
</Jumbotron>
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Jumbotron>
|
||||
<h1>
|
||||
<code>NoPE</code>-Nodes
|
||||
<FontAwesomeIcon icon={faInfoCircle} onClick={_ => this.setState({renderNodeDetails: !this.state.renderNodeDetails})} />{"\t"}<code>NoPE</code>-Nodes
|
||||
</h1>
|
||||
<p>
|
||||
The following <code>NoPE</code>-Nodes has been found:
|
||||
@ -149,7 +149,7 @@ class OverviewComponent extends React.Component<
|
||||
<Col>
|
||||
<Jumbotron>
|
||||
<h1>
|
||||
<code>NoPE</code>-Instances
|
||||
<FontAwesomeIcon icon={faInfoCircle} onClick={_ => this.setState({renderInstanceDetails: !this.state.renderInstanceDetails})} />{"\t"}<code>NoPE</code>-Instances
|
||||
</h1>
|
||||
<p>
|
||||
The following <code>Instances</code>-Nodes has been found:
|
||||
|
@ -73,8 +73,10 @@ export class ComputingNodeOverviewComponent extends React.Component<
|
||||
const _this = this;
|
||||
|
||||
this._observer.push(
|
||||
this.props.dispatcher.externalDispatchers.subscribe(() => {
|
||||
this.props.dispatcher.externalDispatchers.subscribe((dispatchers) => {
|
||||
if (_this.state.computingNodes.length != dispatchers.length || !_this.props.renderDetails) {
|
||||
_this._refresh();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@ -124,8 +126,10 @@ export class ComputingNodeOverviewComponent extends React.Component<
|
||||
return (
|
||||
<Col key={`${idx_01}_${idx_02}`} sm={sm}>
|
||||
<HostStatusComponent
|
||||
status={item}
|
||||
renderDispatcherDetails={true}
|
||||
host={item.name}
|
||||
dispatcher={this.props.dispatcher}
|
||||
renderDetails={true}
|
||||
ids={{}}
|
||||
></HostStatusComponent>
|
||||
</Col>
|
||||
);
|
||||
|
@ -77,6 +77,11 @@ export class InstanceDetailsComponent extends React.Component<
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const renderMethods =
|
||||
Object.getOwnPropertyNames(this.props.description.functions).length > 0;
|
||||
const renderProperties =
|
||||
Object.getOwnPropertyNames(this.props.description.properties).length > 0;
|
||||
|
||||
return (
|
||||
<Card border={this.state.variant}>
|
||||
<Card.Body>
|
||||
@ -92,7 +97,9 @@ export class InstanceDetailsComponent extends React.Component<
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Class</td>
|
||||
<td><code>{this.props.description.type}</code></td>
|
||||
<td>
|
||||
<code>{this.props.description.type}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Redundancy</td>
|
||||
@ -116,6 +123,7 @@ export class InstanceDetailsComponent extends React.Component<
|
||||
)}
|
||||
{this.state.renderDetails ? (
|
||||
<>
|
||||
{renderProperties ? (
|
||||
<tr>
|
||||
<td>Properties</td>
|
||||
<td>
|
||||
@ -131,6 +139,10 @@ export class InstanceDetailsComponent extends React.Component<
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{renderMethods ? (
|
||||
<tr>
|
||||
<td>Methods</td>
|
||||
<td>
|
||||
@ -146,6 +158,9 @@ export class InstanceDetailsComponent extends React.Component<
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
|
@ -39,6 +39,7 @@ export class InstanceOverviewComponent extends React.Component<
|
||||
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) => {
|
||||
|
||||
@ -89,8 +90,16 @@ export class InstanceOverviewComponent extends React.Component<
|
||||
// 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();
|
||||
})
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user