diff options
| author | Georgios Andreadis <g.andreadis@student.tudelft.nl> | 2017-09-23 09:48:38 +0200 |
|---|---|---|
| committer | Georgios Andreadis <g.andreadis@student.tudelft.nl> | 2017-09-23 09:48:38 +0200 |
| commit | 09596c3c5a6a2a44675f170106bb38746229e02a (patch) | |
| tree | 763d1b710dc5f2fcab920ac6ab2c555cee4d6342 /src/scripts/controllers | |
| parent | 057952b0bacc6e963c74bb1bbebbcccd6174a75c (diff) | |
Remove old frontend
Diffstat (limited to 'src/scripts/controllers')
| -rw-r--r-- | src/scripts/controllers/connection/api.ts | 1738 | ||||
| -rw-r--r-- | src/scripts/controllers/connection/cache.ts | 85 | ||||
| -rw-r--r-- | src/scripts/controllers/connection/socket.ts | 76 | ||||
| -rw-r--r-- | src/scripts/controllers/mapcontroller.ts | 520 | ||||
| -rw-r--r-- | src/scripts/controllers/modes/building.ts | 113 | ||||
| -rw-r--r-- | src/scripts/controllers/modes/node.ts | 297 | ||||
| -rw-r--r-- | src/scripts/controllers/modes/object.ts | 296 | ||||
| -rw-r--r-- | src/scripts/controllers/modes/room.ts | 382 | ||||
| -rw-r--r-- | src/scripts/controllers/scaleindicator.ts | 45 | ||||
| -rw-r--r-- | src/scripts/controllers/simulation/chart.ts | 241 | ||||
| -rw-r--r-- | src/scripts/controllers/simulation/statecache.ts | 321 | ||||
| -rw-r--r-- | src/scripts/controllers/simulation/taskview.ts | 64 | ||||
| -rw-r--r-- | src/scripts/controllers/simulation/timeline.ts | 161 | ||||
| -rw-r--r-- | src/scripts/controllers/simulationcontroller.ts | 586 |
14 files changed, 0 insertions, 4925 deletions
diff --git a/src/scripts/controllers/connection/api.ts b/src/scripts/controllers/connection/api.ts deleted file mode 100644 index 1a1c122f..00000000 --- a/src/scripts/controllers/connection/api.ts +++ /dev/null @@ -1,1738 +0,0 @@ -///<reference path="../../definitions.ts" /> -///<reference path="../../../../typings/index.d.ts" /> -import {Util} from "../../util"; -import {ServerConnection} from "../../serverconnection"; - - -export class APIController { - constructor(onConnect: (api: APIController) => any) { - ServerConnection.connect(() => { - onConnect(this); - }); - } - - - /// - // PATH: /users - /// - - // METHOD: GET - public getUserByEmail(email: string): Promise<IUser> { - return ServerConnection.send({ - path: "/users", - method: "GET", - parameters: { - body: {}, - path: {}, - query: { - email - } - } - }); - } - - // METHOD: POST - public addUser(user: IUser): Promise<IUser> { - return ServerConnection.send({ - path: "/users", - method: "POST", - parameters: { - body: { - user: user - }, - path: {}, - query: {} - } - }); - } - - /// - // PATH: /users/{id} - /// - - // METHOD: GET - public getUser(userId: number): Promise<IUser> { - return ServerConnection.send({ - path: "/users/{userId}", - method: "GET", - parameters: { - body: {}, - path: { - userId - }, - query: {} - } - }); - } - - // METHOD: PUT - public updateUser(userId: number, user: IUser): Promise<IUser> { - return ServerConnection.send({ - path: "/users/{userId}", - method: "PUT", - parameters: { - body: { - user: { - givenName: user.givenName, - familyName: user.familyName - } - }, - path: { - userId - }, - query: {} - } - }); - } - - // METHOD: DELETE - public deleteUser(userId: number): Promise<IUser> { - return ServerConnection.send({ - path: "/users/{userId}", - method: "DELETE", - parameters: { - body: {}, - path: { - userId - }, - query: {} - } - }); - } - - /// - // PATH: /users/{userId}/authorizations - /// - - // METHOD: GET - public getAuthorizationsByUser(userId: number): Promise<IAuthorization[]> { - let authorizations = []; - return ServerConnection.send({ - path: "/users/{userId}/authorizations", - method: "GET", - parameters: { - body: {}, - path: { - userId - }, - query: {} - } - }).then((data: any) => { - authorizations = data; - return this.getUser(userId); - }).then((userData: any) => { - const promises = []; - authorizations.forEach((authorization: IAuthorization) => { - authorization.user = userData; - promises.push(this.getSimulation(authorization.simulationId).then((simulationData: any) => { - authorization.simulation = simulationData; - })); - }); - return Promise.all(promises); - }).then((data: any) => { - return authorizations; - }); - } - - /// - // PATH: /simulations - /// - - // METHOD: POST - public addSimulation(simulation: ISimulation): Promise<ISimulation> { - return ServerConnection.send({ - path: "/simulations", - method: "POST", - parameters: { - body: { - simulation: Util.packageForSending(simulation) - }, - path: {}, - query: {} - } - }).then((data: any) => { - this.parseSimulationTimestamps(data); - return data; - }); - } - - /// - // PATH: /simulations/{simulationId} - /// - - // METHOD: GET - public getSimulation(simulationId: number): Promise<ISimulation> { - return ServerConnection.send({ - path: "/simulations/{simulationId}", - method: "GET", - parameters: { - body: {}, - path: { - simulationId - }, - query: {} - } - }).then((data: any) => { - this.parseSimulationTimestamps(data); - return data; - }); - } - - // METHOD: PUT - public updateSimulation(simulation: ISimulation): Promise<ISimulation> { - return ServerConnection.send({ - path: "/simulations/{simulationId}", - method: "PUT", - parameters: { - body: { - simulation: Util.packageForSending(simulation) - }, - path: { - simulationId: simulation.id - }, - query: {} - } - }).then((data: any) => { - this.parseSimulationTimestamps(data); - return data; - }); - } - - // METHOD: DELETE - public deleteSimulation(simulationId: number): Promise<ISimulation> { - return ServerConnection.send({ - path: "/simulations/{simulationId}", - method: "DELETE", - parameters: { - body: {}, - path: { - simulationId - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/authorizations - /// - - // METHOD: GET - public getAuthorizationsBySimulation(simulationId: number): Promise<IAuthorization[]> { - let authorizations = []; - return ServerConnection.send({ - path: "/simulations/{simulationId}/authorizations", - method: "GET", - parameters: { - body: {}, - path: { - simulationId - }, - query: {} - } - }).then((data: any) => { - authorizations = data; - return this.getSimulation(simulationId); - }).then((simulationData: any) => { - const promises = []; - authorizations.forEach((authorization: IAuthorization) => { - authorization.simulation = simulationData; - promises.push(this.getUser(authorization.userId).then((userData: any) => { - authorization.user = userData; - })); - }); - return Promise.all(promises); - }).then((data: any) => { - return authorizations; - }); - } - - /// - // PATH: /simulations/{simulationId}/authorizations/{userId} - /// - - // METHOD: GET - // Not needed - - // METHOD: POST - public addAuthorization(authorization: IAuthorization): Promise<IAuthorization> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/authorizations/{userId}", - method: "POST", - parameters: { - body: { - authorization: { - authorizationLevel: authorization.authorizationLevel - } - }, - path: { - simulationId: authorization.simulationId, - userId: authorization.userId - }, - query: {} - } - }); - } - - // METHOD: PUT - public updateAuthorization(authorization: IAuthorization): Promise<IAuthorization> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/authorizations/{userId}", - method: "PUT", - parameters: { - body: { - authorization: { - authorizationLevel: authorization.authorizationLevel - } - }, - path: { - simulationId: authorization.simulationId, - userId: authorization.userId - }, - query: {} - } - }); - } - - // METHOD: DELETE - public deleteAuthorization(authorization: IAuthorization): Promise<IAuthorization> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/authorizations/{userId}", - method: "DELETE", - parameters: { - body: {}, - path: { - simulationId: authorization.simulationId, - userId: authorization.userId - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId} - /// - - // METHOD: GET - public getDatacenter(simulationId: number, datacenterId: number): Promise<IDatacenter> { - let datacenter; - - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - datacenterId - }, - query: {} - } - }).then((data: any) => { - datacenter = data; - - return this.getRoomsByDatacenter(simulationId, datacenterId); - }).then((data: any) => { - datacenter.rooms = data; - return datacenter; - }); - } - - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms - /// - - // METHOD: GET - public getRoomsByDatacenter(simulationId: number, datacenterId: number): Promise<IRoom[]> { - let rooms; - - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - datacenterId - }, - query: {} - } - }).then((data: any) => { - rooms = data; - - const promises = []; - rooms.forEach((room: IRoom) => { - promises.push(this.loadRoomTiles(simulationId, datacenterId, room)); - }); - return Promise.all(promises).then((data: any) => { - return rooms; - }); - }); - } - - // METHOD: POST - public addRoomToDatacenter(simulationId: number, datacenterId: number): Promise<IRoom> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms", - method: "POST", - parameters: { - body: { - room: { - id: -1, - datacenterId, - roomType: "SERVER" - } - }, - path: { - simulationId, - datacenterId - }, - query: {} - } - }).then((data: any) => { - data.tiles = []; - return data; - }); - } - - /// - // PATH: /room-types - /// - - // METHOD: GET - public getAllRoomTypes(): Promise<string[]> { - return ServerConnection.send({ - path: "/room-types", - method: "GET", - parameters: { - body: {}, - path: {}, - query: {} - } - }).then((data: any) => { - const result = []; - data.forEach((roomType: any) => { - result.push(roomType.name); - }); - return result; - }); - } - - /// - // PATH: /room-types/{name}/allowed-objects - /// - - // METHOD: GET - public getAllowedObjectsByRoomType(name: string): Promise<string[]> { - return ServerConnection.send({ - path: "/room-types/{name}/allowed-objects", - method: "GET", - parameters: { - body: {}, - path: { - name - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId} - /// - - // METHOD: GET - public getRoom(simulationId: number, datacenterId: number, roomId: number): Promise<IRoom> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId - }, - query: {} - } - }).then((data: any) => { - return this.loadRoomTiles(simulationId, datacenterId, data); - }); - } - - // METHOD: PUT - public updateRoom(simulationId: number, datacenterId: number, room: IRoom): Promise<IRoom> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}", - method: "PUT", - parameters: { - body: { - room: Util.packageForSending(room) - }, - path: { - simulationId, - datacenterId, - roomId: room.id - }, - query: {} - } - }).then((data: any) => { - return this.loadRoomTiles(simulationId, datacenterId, data); - }); - } - - // METHOD: DELETE - public deleteRoom(simulationId: number, datacenterId: number, roomId: number): Promise<IRoom> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}", - method: "DELETE", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles - /// - - // METHOD: GET - public getTilesByRoom(simulationId: number, datacenterId: number, roomId: number): Promise<ITile[]> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId - }, - query: {} - } - }).then((data: any) => { - const promises = data.map((item) => { - return this.loadTileObject(simulationId, datacenterId, roomId, item); - }); - - return Promise.all(promises).then(() => { - return data; - }) - }); - } - - // METHOD: POST - public addTileToRoom(simulationId: number, datacenterId: number, roomId: number, tile: ITile): Promise<ITile> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles", - method: "POST", - parameters: { - body: { - tile: Util.packageForSending(tile) - }, - path: { - simulationId, - datacenterId, - roomId - }, - query: {} - } - }).then((data: any) => { - return this.loadTileObject(simulationId, datacenterId, roomId, data); - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId} - /// - - // METHOD: GET - // Not needed (yet) - - // METHOD: DELETE - public deleteTile(simulationId: number, datacenterId: number, roomId: number, tileId: number): Promise<ITile> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}", - method: "DELETE", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/cooling-item - /// - - // METHOD: GET - public getCoolingItem(simulationId: number, datacenterId: number, roomId: number, - tileId: number): Promise<ICoolingItem> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/cooling-item", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - return this.loadFailureModel(data); - }); - } - - // METHOD: POST - public addCoolingItem(simulationId: number, datacenterId: number, roomId: number, tileId: number, - coolingItem: ICoolingItem): Promise<ICoolingItem> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/cooling-item", - method: "POST", - parameters: { - body: { - coolingItem: Util.packageForSending(coolingItem) - }, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - return this.loadFailureModel(data); - }); - } - - // METHOD: PUT - // Not needed (yet) - - // METHOD: DELETE - public deleteCoolingItem(simulationId: number, datacenterId: number, roomId: number, - tileId: number): Promise<ICoolingItem> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/cooling-item", - method: "DELETE", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/psu - /// - - // METHOD: GET - public getPSU(simulationId: number, datacenterId: number, roomId: number, tileId: number): Promise<IPSU> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/psu", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - return this.loadFailureModel(data); - }); - } - - // METHOD: POST - public addPSU(simulationId: number, datacenterId: number, roomId: number, tileId: number, - psu: IPSU): Promise<IPSU> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/psu", - method: "POST", - parameters: { - body: { - psu: Util.packageForSending(psu) - }, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - return this.loadFailureModel(data); - }); - } - - // METHOD: PUT - // Not needed (yet) - - // METHOD: DELETE - public deletePSU(simulationId: number, datacenterId: number, roomId: number, - tileId: number): Promise<IPSU> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/psu", - method: "DELETE", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack - /// - - // METHOD: GET - public getRack(simulationId: number, datacenterId: number, roomId: number, - tileId: number): Promise<IRack> { - let rack = {}; - - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - rack = data; - return this.getMachinesByRack(simulationId, datacenterId, roomId, tileId); - }).then((machines: any) => { - const promises = machines.map((machine) => { - return this.loadMachineUnits(machine); - }); - - - return Promise.all(promises).then(() => { - rack["machines"] = []; - - machines.forEach((machine: IMachine) => { - rack["machines"][machine.position] = machine; - }); - - for (let i = 0; i < rack["capacity"]; i++) { - if (rack["machines"][i] === undefined) { - rack["machines"][i] = null; - } - } - - return <IRack>rack; - }); - }); - } - - // METHOD: POST - public addRack(simulationId: number, datacenterId: number, roomId: number, - tileId: number, rack: IRack): Promise<IRack> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack", - method: "POST", - parameters: { - body: { - rack: Util.packageForSending(rack) - }, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - data.machines = []; - - for (let i = 0; i < data.capacity; i++) { - data.machines.push(null); - } - - return data; - }); - } - - // METHOD: PUT - public updateRack(simulationId: number, datacenterId: number, roomId: number, - tileId: number, rack: IRack): Promise<IRack> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack", - method: "PUT", - parameters: { - body: { - rack - }, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - data.machines = rack.machines; - - return data; - }); - } - - // METHOD: DELETE - public deleteRack(simulationId: number, datacenterId: number, roomId: number, - tileId: number): Promise<IRack> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack", - method: "DELETE", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack/machines - /// - - // METHOD: GET - public getMachinesByRack(simulationId: number, datacenterId: number, roomId: number, - tileId: number): Promise<IMachine[]> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack/machines", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - const promises = data.map((machine) => { - return this.loadMachineUnits(machine); - }); - - return Promise.all(promises).then(() => { - return data; - }); - }); - } - - // METHOD: POST - public addMachineToRack(simulationId: number, datacenterId: number, roomId: number, - tileId: number, machine: IMachine): Promise<IMachine> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack/machines", - method: "POST", - parameters: { - body: { - machine: Util.packageForSending(machine) - }, - path: { - simulationId, - datacenterId, - roomId, - tileId - }, - query: {} - } - }).then((data: any) => { - return this.loadMachineUnits(data); - }); - } - - /// - // PATH: /simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack/machines/{position} - /// - - // METHOD: GET - // Not needed (yet) - - // METHOD: PUT - public updateMachine(simulationId: number, datacenterId: number, roomId: number, - tileId: number, machine: IMachine): Promise<IMachine> { - machine["tags"] = []; - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack/machines/{position}", - method: "PUT", - parameters: { - body: { - machine: Util.packageForSending(machine) - }, - path: { - simulationId, - datacenterId, - roomId, - tileId, - position: machine.position - }, - query: {} - } - }).then((data: any) => { - return this.loadMachineUnits(data); - }); - } - - // METHOD: DELETE - public deleteMachine(simulationId: number, datacenterId: number, roomId: number, - tileId: number, position: number): Promise<any> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/datacenters/{datacenterId}/rooms/{roomId}/tiles/{tileId}/rack/machines/{position}", - method: "DELETE", - parameters: { - body: {}, - path: { - simulationId, - datacenterId, - roomId, - tileId, - position - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/experiments - /// - - // METHOD: GET - public getExperimentsBySimulation(simulationId: number): Promise<IExperiment[]> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments", - method: "GET", - parameters: { - body: {}, - path: { - simulationId - }, - query: {} - } - }).then((data: any) => { - const promises = data.map((item: any) => { - return this.getTrace(item.traceId).then((traceData: any) => { - item.trace = traceData; - }); - }); - return Promise.all(promises).then(() => { - return data; - }); - }); - } - - // METHOD: POST - public addExperimentToSimulation(simulationId: number, experiment: IExperiment): Promise<IExperiment> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments", - method: "POST", - parameters: { - body: { - experiment: Util.packageForSending(experiment) - }, - path: { - simulationId - }, - query: {} - } - }).then((data: any) => { - return this.getTrace(data.traceId).then((traceData: any) => { - data.trace = traceData; - - return data; - }); - }); - } - - /// - // PATH: /simulations/{simulationId}/experiments/{experimentId} - /// - - // METHOD: GET - // Not needed (yet) - - // METHOD: PUT - public updateExperiment(experiment: IExperiment): Promise<IExperiment> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments/{experimentId}", - method: "PUT", - parameters: { - body: { - experiment: Util.packageForSending(experiment) - }, - path: { - experimentId: experiment.id, - simulationId: experiment.simulationId - }, - query: {} - } - }).then((data: any) => { - return this.getTrace(data.traceId).then((traceData: any) => { - data.trace = traceData; - - return data; - }); - }); - } - - // METHOD: DELETE - public deleteExperiment(simulationId: number, experimentId: number): Promise<any> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments/{experimentId}", - method: "DELETE", - parameters: { - body: {}, - path: { - experimentId, - simulationId - }, - query: {} - } - }); - } - - /// - // PATH: /simulations/{simulationId}/experiments/{experimentId}/last-simulated-tick - /// - - // METHOD: GET - public getLastSimulatedTickByExperiment(simulationId: number, experimentId: number): Promise<number> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments/{experimentId}/last-simulated-tick", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - experimentId - }, - query: {} - } - }).then((data: any) => { - return data.lastSimulatedTick; - }); - } - - /// - // PATH: /simulations/{simulationId}/experiments/{experimentId}/machine-states - /// - - // METHOD: GET - public getMachineStates(simulationId: number, experimentId: number, machines: {[keys: number]: IMachine}, - tick?: number): Promise<IMachineState[]> { - let query; - if (tick !== undefined) { - query = {tick}; - } else { - query = {}; - } - - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments/{experimentId}/machine-states", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - experimentId - }, - query - } - }).then((data: any) => { - data.forEach((item: any) => { - item.machine = machines[item.machineId]; - }); - - return data; - }); - } - - /// - // PATH: /simulations/{simulationId}/experiments/{experimentId}/rack-states - /// - - // METHOD: GET - public getRackStates(simulationId: number, experimentId: number, racks: {[keys: number]: IRack}, - tick?: number): Promise<IRackState[]> { - let query; - if (tick !== undefined) { - query = {tick}; - } else { - query = {}; - } - - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments/{experimentId}/rack-states", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - experimentId - }, - query: query - } - }).then((data: any) => { - data.forEach((item: any) => { - item.rack = racks[item.rackId]; - }); - - return data; - }); - } - - /// - // PATH: /simulations/{simulationId}/experiments/{experimentId}/room-states - /// - - // METHOD: GET - public getRoomStates(simulationId: number, experimentId: number, rooms: {[keys: number]: IRoom}, - tick?: number): Promise<IRoomState[]> { - let query; - if (tick !== undefined) { - query = {tick}; - } else { - query = {}; - } - - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments/{experimentId}/room-states", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - experimentId - }, - query - } - }).then((data: any) => { - data.forEach((item: any) => { - item.room = rooms[item.roomId]; - }); - - return data; - }); - } - - /// - // PATH: /simulations/{simulationId}/experiments/{experimentId}/task-states - /// - - // METHOD: GET - public getTaskStates(simulationId: number, experimentId: number, tasks: {[keys: number]: ITask}, - tick?: number): Promise<ITaskState[]> { - let query; - if (tick === undefined) { - query = {tick}; - } else { - query = {}; - } - - return ServerConnection.send({ - path: "/simulations/{simulationId}/experiments/{experimentId}/task-states", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - experimentId - }, - query - } - }).then((data: any) => { - data.forEach((item: any) => { - item.task = tasks[item.taskId]; - }); - - return data; - }); - } - - /// - // PATH: /simulations/{simulationId}/paths - /// - - // METHOD: GET - public getPathsBySimulation(simulationId: number): Promise<IPath[]> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/paths", - method: "GET", - parameters: { - body: {}, - path: { - simulationId - }, - query: {} - } - }).then((data: any) => { - const promises = data.map((item: any) => { - return this.getSectionsByPath(simulationId, item.id).then((sectionsData: any) => { - item.sections = sectionsData; - }); - }); - return Promise.all(promises).then(() => { - return data; - }); - }); - } - - /// - // PATH: /simulations/{simulationId}/paths/{pathId} - /// - - // METHOD: GET - public getPath(simulationId: number, pathId: number): Promise<IPath> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/paths/{pathId}", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - pathId - }, - query: {} - } - }).then((data: any) => { - return this.getSectionsByPath(simulationId, pathId).then((sectionsData: any) => { - data.sections = sectionsData; - return data; - }); - }); - } - - /// - // PATH: /simulations/{simulationId}/paths/{pathId}/branches - /// - - // METHOD: GET - public getBranchesByPath(simulationId: number, pathId: number): Promise<IPath[]> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/paths/{pathId}/branches", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - pathId - }, - query: {} - } - }).then((data: any) => { - const promises = data.map((item: any) => { - return this.getSectionsByPath(simulationId, item.id).then((sectionsData: any) => { - item.sections = sectionsData; - }); - }); - return Promise.all(promises).then(() => { - return data; - }); - }); - } - - // METHOD: POST - public branchFromPath(simulationId: number, pathId: number, startTick: number): Promise<IPath> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/paths/{pathId}/branches", - method: "POST", - parameters: { - body: { - section: { - startTick - } - }, - path: { - simulationId, - pathId - }, - query: {} - } - }).then((data: any) => { - return this.getSectionsByPath(simulationId, data.id).then((sectionsData: any) => { - data.sections = sectionsData; - return data; - }); - }); - } - - /// - // PATH: /simulations/{simulationId}/paths/{pathId}/sections - /// - - // METHOD: GET - public getSectionsByPath(simulationId: number, pathId: number): Promise<IPath[]> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/paths/{pathId}/sections", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - pathId - }, - query: {} - } - }).then((data: any) => { - const promises = data.map((path: ISection) => { - return this.getDatacenter(simulationId, path.datacenterId).then((datacenter: any) => { - path.datacenter = datacenter; - }); - }); - return Promise.all(promises).then(() => { - return data; - }); - }); - } - - /// - // PATH: /simulations/{simulationId}/paths/{pathId}/sections/{sectionId} - /// - - // METHOD: GET - public getSection(simulationId: number, pathId: number, sectionId: number): Promise<ISection> { - return ServerConnection.send({ - path: "/simulations/{simulationId}/paths/{pathId}/sections/{sectionId}", - method: "GET", - parameters: { - body: {}, - path: { - simulationId, - pathId, - sectionId - }, - query: {} - } - }).then((data: any) => { - return this.getDatacenter(simulationId, data.datacenterId).then((datacenter: any) => { - data.datacenter = datacenter; - return data; - }); - }); - } - - /// - // PATH: /specifications/psus - /// - - // METHOD: GET - public getAllPSUSpecs(): Promise<IPSU[]> { - let psus; - return ServerConnection.send({ - path: "/specifications/psus", - method: "GET", - parameters: { - body: {}, - path: {}, - query: {} - } - }).then((data: any) => { - psus = data; - - const promises = []; - data.forEach((psu: IPSU) => { - promises.push(this.getFailureModel(psu.failureModelId)); - }); - return Promise.all(promises); - }).then((data: any) => { - return psus; - }); - } - - /// - // PATH: /specifications/psus/{id} - /// - - // METHOD: GET - public getPSUSpec(id: number): Promise<IPSU> { - let psu; - - return ServerConnection.send({ - path: "/specifications/psus/{id}", - method: "GET", - parameters: { - body: {}, - path: { - id - }, - query: {} - } - }).then((data: any) => { - psu = data; - return this.getFailureModel(data.failureModelId); - }).then((data: any) => { - psu.failureModel = data; - return psu; - }); - } - - /// - // PATH: /specifications/cooling-items - /// - - // METHOD: GET - public getAllCoolingItemSpecs(): Promise<ICoolingItem[]> { - let coolingItems; - - return ServerConnection.send({ - path: "/specifications/cooling-items", - method: "GET", - parameters: { - body: {}, - path: {}, - query: {} - } - }).then((data: any) => { - coolingItems = data; - - const promises = []; - data.forEach((item: ICoolingItem) => { - promises.push(this.getFailureModel(item.failureModelId)); - }); - return Promise.all(promises); - }).then((data: any) => { - return coolingItems; - }); - } - - /// - // PATH: /specifications/cooling-items/{id} - /// - - // METHOD: GET - public getCoolingItemSpec(id: number): Promise<IPSU> { - let coolingItem; - - return ServerConnection.send({ - path: "/specifications/cooling-items/{id}", - method: "GET", - parameters: { - body: {}, - path: { - id - }, - query: {} - } - }).then((data: any) => { - coolingItem = data; - return this.getFailureModel(data.failureModelId); - }).then((data: any) => { - coolingItem.failureModel = data; - return coolingItem; - }); - } - - /// - // PATH: /schedulers - /// - - // METHOD: GET - public getAllSchedulers(): Promise<IScheduler[]> { - return ServerConnection.send({ - path: "/schedulers", - method: "GET", - parameters: { - body: {}, - path: {}, - query: {} - } - }); - } - - /// - // PATH: /traces - /// - - // METHOD: GET - public getAllTraces(): Promise<ITrace[]> { - return ServerConnection.send({ - path: "/traces", - method: "GET", - parameters: { - body: {}, - path: {}, - query: {} - } - }); - } - - /// - // PATH: /traces/{traceId} - /// - - // METHOD: GET - public getTrace(traceId: number): Promise<ITrace> { - let trace; - - return ServerConnection.send({ - path: "/traces/{traceId}", - method: "GET", - parameters: { - body: {}, - path: { - traceId - }, - query: {} - } - }).then((data: any) => { - trace = data; - return this.getTasksByTrace(traceId); - }).then((data: any) => { - trace.tasks = data; - return trace; - }); - } - - /// - // PATH: /traces/{traceId}/tasks - /// - - // METHOD: GET - public getTasksByTrace(traceId: number): Promise<ITask[]> { - return ServerConnection.send({ - path: "/traces/{traceId}/tasks", - method: "GET", - parameters: { - body: {}, - path: { - traceId - }, - query: {} - } - }); - } - - /// - // PATH: /specifications/failure-models - /// - - // METHOD: GET - public getAllFailureModels(): Promise<IFailureModel[]> { - return ServerConnection.send({ - path: "/specifications/failure-models", - method: "GET", - parameters: { - body: {}, - path: {}, - query: {} - } - }); - } - - /// - // PATH: /specifications/failure-models/{id} - /// - - // METHOD: GET - public getFailureModel(id: number): Promise<IFailureModel> { - return ServerConnection.send({ - path: "/specifications/failure-models/{id}", - method: "GET", - parameters: { - body: {}, - path: { - id - }, - query: {} - } - }); - } - - /// - // PATH: /specifications/[units] - /// - - // METHOD: GET - public getAllSpecificationsOfType(typePlural: string): Promise<INodeUnit> { - let specs: any; - return ServerConnection.send({ - path: "/specifications/" + typePlural, - method: "GET", - parameters: { - body: {}, - path: {}, - query: {} - } - }).then((data: any) => { - specs = data; - - const promises = []; - data.forEach((unit: INodeUnit) => { - promises.push(this.getFailureModel(unit.failureModelId)); - }); - return Promise.all(promises); - }).then((data: any) => { - return specs; - }); - } - - /// - // PATH: /specifications/[units]/{id} - /// - - // METHOD: GET - public getSpecificationOfType(typePlural: string, id: number): Promise<INodeUnit> { - let spec; - - return ServerConnection.send({ - path: "/specifications/" + typePlural + "/{id}", - method: "GET", - parameters: { - body: {}, - path: { - id - }, - query: {} - } - }).then((data: any) => { - spec = data; - return this.getFailureModel(data.failureModelId); - }).then((data: any) => { - spec.failureModel = data; - return spec; - }); - } - - - /// - // HELPER METHODS - /// - - private loadRoomTiles(simulationId: number, datacenterId: number, room: IRoom): Promise<IRoom> { - return this.getTilesByRoom(simulationId, datacenterId, room.id).then((data: any) => { - room.tiles = data; - return room; - }); - } - - private loadTileObject(simulationId: number, datacenterId: number, roomId: number, tile: ITile): Promise<ITile> { - let promise; - - switch (tile.objectType) { - case "RACK": - promise = this.getRack(simulationId, datacenterId, roomId, tile.id).then((data: IRack) => { - tile.object = data; - }); - break; - case "PSU": - promise = this.getPSU(simulationId, datacenterId, roomId, tile.id).then((data: IPSU) => { - tile.object = data; - }); - break; - case "COOLING_ITEM": - promise = this.getCoolingItem(simulationId, datacenterId, roomId, tile.id).then((data: ICoolingItem) => { - tile.object = data; - }); - break; - default: - promise = new Promise((resolve, reject) => { - resolve(undefined); - }); - } - - return promise.then(() => { - return tile; - }) - } - - private parseSimulationTimestamps(simulation: ISimulation): void { - simulation.datetimeCreatedParsed = Util.parseDateTime(simulation.datetimeCreated); - simulation.datetimeLastEditedParsed = Util.parseDateTime(simulation.datetimeLastEdited); - } - - private loadFailureModel(data: any): Promise<any> { - return this.getFailureModel(data.failureModelId).then((failureModel: IFailureModel) => { - data.failureModel = failureModel; - return data; - }); - } - - private loadUnitsOfType(idListName: string, objectListName: string, machine: IMachine): Promise<IMachine> { - machine[objectListName] = []; - - const promises = machine[idListName].map((item) => { - return this.getSpecificationOfType(objectListName, item).then((data) => { - machine[objectListName].push(data); - }); - }); - - return Promise.all(promises).then(() => { - return machine; - }) - } - - private loadMachineUnits(machine: IMachine): Promise<IMachine> { - const listNames = [ - { - idListName: "cpuIds", - objectListName: "cpus" - }, { - idListName: "gpuIds", - objectListName: "gpus" - }, { - idListName: "memoryIds", - objectListName: "memories" - }, { - idListName: "storageIds", - objectListName: "storages" - } - ]; - - const promises = listNames.map((item: any) => { - return this.loadUnitsOfType(item.idListName, item.objectListName, machine); - }); - - return Promise.all(promises).then(() => { - return machine; - }); - } -} diff --git a/src/scripts/controllers/connection/cache.ts b/src/scripts/controllers/connection/cache.ts deleted file mode 100644 index c1c47c2d..00000000 --- a/src/scripts/controllers/connection/cache.ts +++ /dev/null @@ -1,85 +0,0 @@ -export enum CacheStatus { - MISS, - FETCHING, - HIT, - NOT_CACHABLE -} - - -interface ICachableObject { - status: CacheStatus; - object: any; - callbacks: any[]; -} - - -export class CacheController { - private static CACHABLE_ROUTES = [ - "/specifications/psus/{id}", - "/specifications/cooling-items/{id}", - "/specifications/cpus/{id}", - "/specifications/gpus/{id}", - "/specifications/memories/{id}", - "/specifications/storages/{id}", - "/specifications/failure-models/{id}", - ]; - - // Maps every route name to a map of IDs => objects - private routeCaches: { [keys: string]: { [keys: number]: ICachableObject } }; - - - constructor() { - this.routeCaches = {}; - - CacheController.CACHABLE_ROUTES.forEach((routeName: string) => { - this.routeCaches[routeName] = {}; - }) - } - - public checkCache(request: IRequest): CacheStatus { - if (request.method === "GET" && CacheController.CACHABLE_ROUTES.indexOf(request.path) !== -1) { - if (this.routeCaches[request.path][request.parameters.path["id"]] === undefined) { - this.routeCaches[request.path][request.parameters.path["id"]] = { - status: CacheStatus.MISS, - object: null, - callbacks: [] - }; - return CacheStatus.MISS; - } else { - return this.routeCaches[request.path][request.parameters.path["id"]].status; - } - } else { - return CacheStatus.NOT_CACHABLE; - } - } - - public fetchFromCache(request: IRequest): any { - return this.routeCaches[request.path][request.parameters.path["id"]].object; - } - - public setToFetching(request: IRequest): void { - this.routeCaches[request.path][request.parameters.path["id"]].status = CacheStatus.FETCHING; - } - - public onFetch(request: IRequest, response: IResponse): any { - const pathWithoutVersion = request.path.replace(/\/v\d+/, ""); - this.routeCaches[pathWithoutVersion][request.parameters.path["id"]].status = CacheStatus.HIT; - this.routeCaches[pathWithoutVersion][request.parameters.path["id"]].object = response.content; - - this.routeCaches[pathWithoutVersion][request.parameters.path["id"]].callbacks.forEach((callback) => { - callback({ - status: { - code: 200 - }, - content: response.content, - id: request.id - }); - }); - - this.routeCaches[pathWithoutVersion][request.parameters.path["id"]].callbacks = []; - } - - public registerCallback(request: IRequest, callback): any { - this.routeCaches[request.path][request.parameters.path["id"]].callbacks.push(callback); - } -} diff --git a/src/scripts/controllers/connection/socket.ts b/src/scripts/controllers/connection/socket.ts deleted file mode 100644 index 91a0f9e4..00000000 --- a/src/scripts/controllers/connection/socket.ts +++ /dev/null @@ -1,76 +0,0 @@ -import {CacheController, CacheStatus} from "./cache"; -import * as io from "socket.io-client"; - - -export class SocketController { - private static id = 1; - private _socket: SocketIOClient.Socket; - private _cacheController: CacheController; - - // Mapping from request IDs to their registered callbacks - private callbacks: { [keys: number]: (response: IResponse) => any }; - - - constructor(onConnect: () => any) { - this.callbacks = {}; - this._cacheController = new CacheController(); - - this._socket = io.connect('SERVER_BASE_URL'); - this._socket.on('connect', onConnect); - - this._socket.on('response', (jsonResponse: string) => { - const response: IResponse = JSON.parse(jsonResponse); - console.log("Response, ID:", response.id, response); - this.callbacks[response.id](response); - delete this.callbacks[response.id]; - }); - } - - /** - * Sends a request to the server socket and registers the callback to be triggered on response. - * - * @param request The request instance to be sent - * @param callback A function to be called with the response object once the socket has received a response - */ - public sendRequest(request: IRequest, callback: (response: IResponse) => any): void { - // Check local cache, in case request is for cachable GET route - const cacheStatus = this._cacheController.checkCache(request); - - if (cacheStatus === CacheStatus.HIT) { - callback({ - status: { - code: 200 - }, - content: this._cacheController.fetchFromCache(request), - id: -1 - }); - } else if (cacheStatus === CacheStatus.FETCHING) { - this._cacheController.registerCallback(request, callback); - } else if (cacheStatus === CacheStatus.MISS || cacheStatus === CacheStatus.NOT_CACHABLE) { - if (!this._socket.connected) { - console.error("Socket not connected, sending request failed"); - } - - if (cacheStatus === CacheStatus.MISS) { - this._cacheController.setToFetching(request); - - this.callbacks[SocketController.id] = (response: IResponse) => { - this._cacheController.onFetch(request, response); - callback(response); - }; - } else { - this.callbacks[SocketController.id] = callback; - } - - // Setup request object - request.id = SocketController.id; - request.token = localStorage.getItem("googleToken"); - request.path = "/v1" + request.path; - - console.log("Request, ID:", request.id, request); - this._socket.emit("request", request); - - SocketController.id++; - } - } -} diff --git a/src/scripts/controllers/mapcontroller.ts b/src/scripts/controllers/mapcontroller.ts deleted file mode 100644 index 4ad1b20b..00000000 --- a/src/scripts/controllers/mapcontroller.ts +++ /dev/null @@ -1,520 +0,0 @@ -///<reference path="../../../typings/index.d.ts" /> -///<reference path="../views/mapview.ts" /> -import * as $ from "jquery"; -import {Colors} from "../colors"; -import {Util} from "../util"; -import {SimulationController} from "./simulationcontroller"; -import {MapView} from "../views/mapview"; -import {APIController} from "./connection/api"; -import {BuildingModeController} from "./modes/building"; -import {RoomModeController, RoomInteractionMode} from "./modes/room"; -import {ObjectModeController} from "./modes/object"; -import {NodeModeController} from "./modes/node"; -import {ScaleIndicatorController} from "./scaleindicator"; - -export const CELL_SIZE = 50; - - -export enum AppMode { - CONSTRUCTION, - SIMULATION -} - - -/** - * The current level of datacenter hierarchy that is selected - */ -export enum InteractionLevel { - BUILDING, - ROOM, - OBJECT, - NODE -} - - -/** - * Possible states that the application can be in, in terms of interaction - */ -export enum InteractionMode { - DEFAULT, - SELECT_ROOM -} - - -/** - * Class responsible for handling user input in the map. - */ -export class MapController { - public stage: createjs.Stage; - public mapView: MapView; - - public appMode: AppMode; - public interactionLevel: InteractionLevel; - public interactionMode: InteractionMode; - - public buildingModeController: BuildingModeController; - public roomModeController: RoomModeController; - public objectModeController: ObjectModeController; - public nodeModeController: NodeModeController; - - public simulationController: SimulationController; - public api: APIController; - private scaleIndicatorController: ScaleIndicatorController; - - private canvas: JQuery; - private gridDragging: boolean; - - private infoTimeOut: any; - // Current mouse coordinates on the stage canvas (mainly for zooming purposes) - private currentStageMouseX: number; - - private currentStageMouseY: number; - // Keep start coordinates relative to the grid to compute dragging offset later - private gridDragBeginX: number; - - private gridDragBeginY: number; - // Keep start coordinates on stage to compute delta values - private stageDragBeginX: number; - private stageDragBeginY: number; - - private MAX_DELTA = 5; - - - /** - * Hides all side menus except for the active one. - * - * @param activeMenu An identifier (e.g. #room-menu) for the menu container - */ - public static hideAndShowMenus(activeMenu: string): void { - $(".menu-container.level-menu").each((index: number, elem: Element) => { - if ($(elem).is(activeMenu)) { - $(elem).removeClass("hidden"); - } else { - $(elem).addClass("hidden"); - } - }); - } - - constructor(mapView: MapView) { - this.mapView = mapView; - this.stage = this.mapView.stage; - - new APIController((apiInstance: APIController) => { - this.api = apiInstance; - - this.buildingModeController = new BuildingModeController(this); - this.roomModeController = new RoomModeController(this); - this.objectModeController = new ObjectModeController(this); - this.nodeModeController = new NodeModeController(this); - this.simulationController = new SimulationController(this); - - this.scaleIndicatorController = new ScaleIndicatorController(this); - - this.canvas = $("#main-canvas"); - - $(window).on("resize", () => { - this.onWindowResize(); - }); - - this.gridDragging = false; - - this.appMode = AppMode.CONSTRUCTION; - this.interactionLevel = InteractionLevel.BUILDING; - this.interactionMode = InteractionMode.DEFAULT; - - this.setAllMenuModes(); - - this.setupMapInteractionHandlers(); - this.setupEventListeners(); - this.buildingModeController.setupEventListeners(); - this.roomModeController.setupEventListeners(); - this.objectModeController.setupEventListeners(); - this.nodeModeController.setupEventListeners(); - - this.scaleIndicatorController.init($(".scale-indicator")); - this.scaleIndicatorController.update(); - - this.mapView.roomLayer.setClickable(true); - - this.matchUserAuthLevel(); - }); - } - - /** - * Hides and shows the menu bodies corresponding to the current mode (construction or simulation). - */ - public setAllMenuModes(): void { - $(".menu-body" + (this.appMode === AppMode.CONSTRUCTION ? ".construction" : ".simulation")).show(); - $(".menu-body" + (this.appMode === AppMode.CONSTRUCTION ? ".simulation" : ".construction")).hide(); - } - - /** - * Checks whether the mapContainer is still within its legal bounds. - * - * Resets, if necessary, to the most similar still legal position. - */ - public checkAndResetCanvasMovement(): void { - if (this.mapView.mapContainer.x + this.mapView.gridLayer.gridPixelSize * - this.mapView.mapContainer.scaleX < this.mapView.canvasWidth) { - this.mapView.mapContainer.x = this.mapView.canvasWidth - this.mapView.gridLayer.gridPixelSize * - this.mapView.mapContainer.scaleX; - } - if (this.mapView.mapContainer.x > 0) { - this.mapView.mapContainer.x = 0; - } - if (this.mapView.mapContainer.y + this.mapView.gridLayer.gridPixelSize * - this.mapView.mapContainer.scaleX < this.mapView.canvasHeight) { - this.mapView.mapContainer.y = this.mapView.canvasHeight - this.mapView.gridLayer.gridPixelSize * - this.mapView.mapContainer.scaleX; - } - if (this.mapView.mapContainer.y > 0) { - this.mapView.mapContainer.y = 0; - } - } - - /** - * Checks whether the mapContainer is still within its legal bounds and generates corrections if needed. - * - * Does not change the x and y coordinates, only returns. - */ - public checkCanvasMovement(x: number, y: number, scale: number): IGridPosition { - const result: IGridPosition = {x: x, y: y}; - if (x + this.mapView.gridLayer.gridPixelSize * scale < this.mapView.canvasWidth) { - result.x = this.mapView.canvasWidth - this.mapView.gridLayer.gridPixelSize * - this.mapView.mapContainer.scaleX; - } - if (x > 0) { - result.x = 0; - } - if (y + this.mapView.gridLayer.gridPixelSize * scale < this.mapView.canvasHeight) { - result.y = this.mapView.canvasHeight - this.mapView.gridLayer.gridPixelSize * - this.mapView.mapContainer.scaleX; - } - if (y > 0) { - result.y = 0; - } - - return result; - } - - /** - * Checks whether the current interaction mode is a hover mode (meaning that there is a hover item present). - * - * @returns {boolean} Whether it is in hover mode. - */ - public isInHoverMode(): boolean { - return this.roomModeController !== undefined && - (this.interactionMode === InteractionMode.SELECT_ROOM || - this.roomModeController.roomInteractionMode === RoomInteractionMode.ADD_RACK || - this.roomModeController.roomInteractionMode === RoomInteractionMode.ADD_PSU || - this.roomModeController.roomInteractionMode === RoomInteractionMode.ADD_COOLING_ITEM); - } - - public static showConfirmDeleteDialog(itemType: string, onConfirm: () => void): void { - const modalDialog = <any>$("#confirm-delete"); - modalDialog.find(".modal-body").text("Are you sure you want to delete this " + itemType + "?"); - - const callback = () => { - onConfirm(); - modalDialog.modal("hide"); - modalDialog.find("button.confirm").first().off("click"); - $(document).off("keypress"); - }; - - $(document).on("keypress", (event: JQueryEventObject) => { - if (event.which === 13) { - callback(); - } else if (event.which === 27) { - modalDialog.modal("hide"); - $(document).off("keypress"); - modalDialog.find("button.confirm").first().off("click"); - } - }); - modalDialog.find("button.confirm").first().on("click", callback); - modalDialog.modal("show"); - } - - /** - * Shows an informational popup in a corner of the screen, communicating a certain event. - * - * @param message The message to be displayed in the body of the popup - * @param type The severity of the message; Currently supported: "info" and "warning" - */ - public showInfoBalloon(message: string, type: string): void { - const balloon = $(".info-balloon"); - balloon.html('<span></span>' + message); - const callback = () => { - balloon.fadeOut(300); - - this.infoTimeOut = undefined; - }; - const DISPLAY_TIME = 3000; - - const balloonIcon = balloon.find("span").first(); - balloonIcon.removeClass(); - - balloon.css("background", Colors.INFO_BALLOON_MAP[type]); - balloonIcon.addClass("glyphicon"); - if (type === "info") { - balloonIcon.addClass("glyphicon-info-sign"); - } else if (type === "warning") { - balloonIcon.addClass("glyphicon-exclamation-sign"); - } - - if (this.infoTimeOut === undefined) { - balloon.fadeIn(300); - this.infoTimeOut = setTimeout(callback, DISPLAY_TIME); - } else { - clearTimeout(this.infoTimeOut); - this.infoTimeOut = setTimeout(callback, DISPLAY_TIME); - } - } - - private setupMapInteractionHandlers(): void { - this.stage.enableMouseOver(20); - - // Listen for mouse movement events to update hover positions - this.stage.on("stagemousemove", (event: createjs.MouseEvent) => { - this.currentStageMouseX = event.stageX; - this.currentStageMouseY = event.stageY; - - const gridPos = this.convertScreenCoordsToGridCoords([event.stageX, event.stageY]); - const tileX = gridPos.x; - const tileY = gridPos.y; - - // Check whether the coordinates of the hover location have changed since the last draw - if (this.mapView.hoverLayer.hoverTilePosition.x !== tileX) { - this.mapView.hoverLayer.hoverTilePosition.x = tileX; - this.mapView.updateScene = true; - } - if (this.mapView.hoverLayer.hoverTilePosition.y !== tileY) { - this.mapView.hoverLayer.hoverTilePosition.y = tileY; - this.mapView.updateScene = true; - } - }); - - // Handle mousedown interaction - this.stage.on("mousedown", (e: createjs.MouseEvent) => { - this.stageDragBeginX = e.stageX; - this.stageDragBeginY = e.stageY; - }); - - // Handle map dragging interaction - // Drag begin and progress handlers - this.mapView.mapContainer.on("pressmove", (e: createjs.MouseEvent) => { - if (!this.gridDragging) { - this.gridDragBeginX = e.stageX - this.mapView.mapContainer.x; - this.gridDragBeginY = e.stageY - this.mapView.mapContainer.y; - this.stageDragBeginX = e.stageX; - this.stageDragBeginY = e.stageY; - this.gridDragging = true; - } else { - this.mapView.mapContainer.x = e.stageX - this.gridDragBeginX; - this.mapView.mapContainer.y = e.stageY - this.gridDragBeginY; - - this.checkAndResetCanvasMovement(); - - this.mapView.updateScene = true; - } - }); - - // Drag exit handlers - this.mapView.mapContainer.on("pressup", (e: createjs.MouseEvent) => { - if (this.gridDragging) { - this.gridDragging = false; - } - - if (Math.abs(e.stageX - this.stageDragBeginX) < this.MAX_DELTA && - Math.abs(e.stageY - this.stageDragBeginY) < this.MAX_DELTA) { - this.handleCanvasMouseClick(e.stageX, e.stageY); - } - }); - - // Disable an ongoing drag action if the mouse leaves the canvas - this.mapView.stage.on("mouseleave", () => { - if (this.gridDragging) { - this.gridDragging = false; - } - }); - - // Relay scroll events to the MapView zoom handler - $("#main-canvas").on("mousewheel", (event: JQueryEventObject) => { - const originalEvent = (<any>event.originalEvent); - this.mapView.zoom([this.currentStageMouseX, this.currentStageMouseY], -0.7 * originalEvent.deltaY); - this.scaleIndicatorController.update(); - }); - } - - /** - * Connects clickable UI elements to their respective event listeners. - */ - private setupEventListeners(): void { - // Zooming elements - $("#zoom-plus").on("click", () => { - this.mapView.zoom([ - this.mapView.canvasWidth / 2, - this.mapView.canvasHeight / 2 - ], 20); - }); - $("#zoom-minus").on("click", () => { - this.mapView.zoom([ - this.mapView.canvasWidth / 2, - this.mapView.canvasHeight / 2 - ], -20); - }); - - $(".export-canvas").click(() => { - this.exportCanvasToImage(); - }); - - // Menu panels - $(".menu-header-bar .menu-collapse").on("click", (event: JQueryEventObject) => { - const container = $(event.target).closest(".menu-container"); - if (this.appMode === AppMode.CONSTRUCTION) { - container.children(".menu-body.construction").first().slideToggle(300); - } else if (this.appMode === AppMode.SIMULATION) { - container.children(".menu-body.simulation").first().slideToggle(300); - } - - }); - - // Menu close button - $(".menu-header-bar .menu-exit").on("click", (event: JQueryEventObject) => { - const nearestMenuContainer = $(event.target).closest(".menu-container"); - if (nearestMenuContainer.is("#node-menu")) { - this.interactionLevel = InteractionLevel.OBJECT; - $(".node-element-overlay").addClass("hidden"); - } - nearestMenuContainer.addClass("hidden"); - }); - - // Handler for the construction mode switch - $("#construction-mode-switch").on("click", () => { - this.simulationController.exitMode(); - }); - - // Handler for the simulation mode switch - $("#simulation-mode-switch").on("click", () => { - this.simulationController.enterMode(); - }); - - // Handler for the version-save button - $("#save-version-btn").on("click", (event: JQueryEventObject) => { - const target = $(event.target); - - target.attr("data-saved", "false"); - const lastPath = this.mapView.simulation.paths[this.mapView.simulation.paths.length - 1]; - this.api.branchFromPath( - this.mapView.simulation.id, lastPath.id, lastPath.sections[lastPath.sections.length - 1].startTick + 1 - ).then((data: IPath) => { - this.mapView.simulation.paths.push(data); - this.mapView.currentDatacenter = data.sections[data.sections.length - 1].datacenter; - target.attr("data-saved", "true"); - }); - }); - - $(document).on("keydown", (event: JQueryKeyEventObject) => { - if ($(event.target).is('input')) { - return; - } - - if (event.which === 83) { - this.simulationController.enterMode(); - } else if (event.which === 67) { - this.simulationController.exitMode(); - } else if (event.which == 32) { - if (this.appMode === AppMode.SIMULATION) { - this.simulationController.timelineController.togglePlayback(); - } - } - }); - } - - /** - * Handles a simple mouse click (without drag) on the canvas. - * - * @param stageX The x coordinate of the location in pixels on the stage - * @param stageY The y coordinate of the location in pixels on the stage - */ - private handleCanvasMouseClick(stageX: number, stageY: number): void { - const gridPos = this.convertScreenCoordsToGridCoords([stageX, stageY]); - - if (this.interactionLevel === InteractionLevel.BUILDING) { - if (this.interactionMode === InteractionMode.DEFAULT) { - const roomIndex = Util.roomCollisionIndexOf(this.mapView.currentDatacenter.rooms, gridPos); - - if (roomIndex !== -1) { - this.interactionLevel = InteractionLevel.ROOM; - this.roomModeController.enterMode(this.mapView.currentDatacenter.rooms[roomIndex]); - } - } else if (this.interactionMode === InteractionMode.SELECT_ROOM) { - if (this.mapView.roomLayer.checkHoverTileValidity(gridPos)) { - this.buildingModeController.addSelectedTile(this.mapView.hoverLayer.hoverTilePosition); - } else if (Util.tileListContainsPosition(this.mapView.roomLayer.selectedTiles, gridPos)) { - this.buildingModeController.removeSelectedTile(this.mapView.hoverLayer.hoverTilePosition); - } - } - } else if (this.interactionLevel === InteractionLevel.ROOM) { - this.roomModeController.handleCanvasMouseClick(gridPos); - } else if (this.interactionLevel === InteractionLevel.OBJECT) { - if (gridPos.x !== this.mapView.grayLayer.currentObjectTile.position.x || - gridPos.y !== this.mapView.grayLayer.currentObjectTile.position.y) { - this.objectModeController.goToRoomMode(); - } - } else if (this.interactionLevel === InteractionLevel.NODE) { - this.interactionLevel = InteractionLevel.OBJECT; - this.nodeModeController.goToObjectMode(); - } - } - - /** - * Takes screen (stage) coordinates and returns the grid cell position they belong to. - * - * @param stagePosition The raw x and y coordinates of the wanted position - * @returns {Array} The corresponding grid cell coordinates - */ - private convertScreenCoordsToGridCoords(stagePosition: number[]): IGridPosition { - const result = {x: 0, y: 0}; - result.x = Math.floor((stagePosition[0] - this.mapView.mapContainer.x) / - (this.mapView.mapContainer.scaleX * CELL_SIZE)); - result.y = Math.floor((stagePosition[1] - this.mapView.mapContainer.y) / - (this.mapView.mapContainer.scaleY * CELL_SIZE)); - return result; - } - - /** - * Adjusts the canvas size to fit the window perfectly. - */ - private onWindowResize() { - const parent = this.canvas.parent(".app-content"); - parent.height($(window).height() - 50); - this.canvas.attr("width", parent.width()); - this.canvas.attr("height", parent.height()); - this.mapView.canvasWidth = parent.width(); - this.mapView.canvasHeight = parent.height(); - - if (this.interactionLevel === InteractionLevel.BUILDING) { - this.mapView.zoomOutOnDC(); - } else if (this.interactionLevel === InteractionLevel.ROOM) { - this.mapView.zoomInOnRoom(this.roomModeController.currentRoom); - } else { - this.mapView.zoomInOnRoom(this.roomModeController.currentRoom, true); - } - - this.mapView.updateScene = true; - } - - private matchUserAuthLevel() { - const authLevel = localStorage.getItem("simulationAuthLevel"); - if (authLevel === "VIEW") { - $(".side-menu-container.right-middle-side, .side-menu-container.right-side").hide(); - } - } - - private exportCanvasToImage() { - const canvasData = (<HTMLCanvasElement>this.canvas.get(0)).toDataURL("image/png"); - const newWindow = window.open('about:blank', 'OpenDC Canvas Export'); - newWindow.document.write("<img src='" + canvasData + "' alt='Canvas Image Export'/>"); - newWindow.document.title = "OpenDC Canvas Export"; - } -} diff --git a/src/scripts/controllers/modes/building.ts b/src/scripts/controllers/modes/building.ts deleted file mode 100644 index 217f5935..00000000 --- a/src/scripts/controllers/modes/building.ts +++ /dev/null @@ -1,113 +0,0 @@ -import {InteractionMode, MapController} from "../mapcontroller"; -import {MapView} from "../../views/mapview"; -import * as $ from "jquery"; - - -/** - * Class responsible for handling building mode interactions. - */ -export class BuildingModeController { - public newRoomId: number; - - private mapController: MapController; - private mapView: MapView; - - - constructor(mapController: MapController) { - this.mapController = mapController; - this.mapView = this.mapController.mapView; - } - - /** - * Connects all DOM event listeners to their respective element targets. - */ - public setupEventListeners() { - const resetConstructionButtons = () => { - this.mapController.interactionMode = InteractionMode.DEFAULT; - this.mapView.hoverLayer.setHoverTileVisibility(false); - $("#room-construction").text("Construct new room"); - $("#room-construction-cancel").slideToggle(300); - }; - - // Room construction button - $("#room-construction").on("click", (event: JQueryEventObject) => { - if (this.mapController.interactionMode === InteractionMode.DEFAULT) { - this.mapController.interactionMode = InteractionMode.SELECT_ROOM; - this.mapView.hoverLayer.setHoverTileVisibility(true); - this.mapController.api.addRoomToDatacenter(this.mapView.simulation.id, - this.mapView.currentDatacenter.id).then((room: IRoom) => { - this.newRoomId = room.id; - }); - $(event.target).text("Finalize room"); - $("#room-construction-cancel").slideToggle(300); - } else if (this.mapController.interactionMode === InteractionMode.SELECT_ROOM) { - resetConstructionButtons(); - this.finalizeRoom(); - } - }); - - // Cancel button for room construction - $("#room-construction-cancel").on("click", () => { - resetConstructionButtons(); - this.cancelRoomConstruction(); - }); - } - - /** - * Cancels room construction and deletes the temporary room created previously. - */ - public cancelRoomConstruction() { - this.mapController.api.deleteRoom(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.newRoomId).then(() => { - this.mapView.roomLayer.cancelRoomConstruction(); - }); - } - - /** - * Finalizes room construction by triggering a redraw of the room layer with the new room added. - */ - public finalizeRoom() { - this.mapController.api.getRoom(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.newRoomId).then((room: IRoom) => { - this.mapView.roomLayer.finalizeRoom(room); - }); - } - - /** - * Adds a newly selected tile to the list of selected tiles. - * - * @param position The new tile position to be added - */ - public addSelectedTile(position: IGridPosition): void { - const tile = { - id: -1, - roomId: this.newRoomId, - position: {x: position.x, y: position.y} - }; - this.mapController.api.addTileToRoom(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.newRoomId, tile).then((tile: ITile) => { - this.mapView.roomLayer.addSelectedTile(tile); - }); - } - - /** - * Removes a previously selected tile. - * - * @param position The position of the tile to be removed - */ - public removeSelectedTile(position: IGridPosition): void { - let objectIndex = -1; - - for (let i = 0; i < this.mapView.roomLayer.selectedTileObjects.length; i++) { - const tile = this.mapView.roomLayer.selectedTileObjects[i]; - if (tile.position.x === position.x && tile.position.y === position.y) { - objectIndex = i; - } - } - this.mapController.api.deleteTile(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.newRoomId, - this.mapView.roomLayer.selectedTileObjects[objectIndex].tileObject.id).then(() => { - this.mapView.roomLayer.removeSelectedTile(position, objectIndex); - }); - } -} diff --git a/src/scripts/controllers/modes/node.ts b/src/scripts/controllers/modes/node.ts deleted file mode 100644 index cef61bba..00000000 --- a/src/scripts/controllers/modes/node.ts +++ /dev/null @@ -1,297 +0,0 @@ -import {MapController, AppMode, InteractionLevel} from "../mapcontroller"; -import {MapView} from "../../views/mapview"; -import * as $ from "jquery"; - - -/** - * Class responsible for rendering node mode and handling UI interactions within it. - */ -export class NodeModeController { - public currentMachine: IMachine; - - private mapController: MapController; - private mapView: MapView; - - - constructor(mapController: MapController) { - this.mapController = mapController; - this.mapView = this.mapController.mapView; - - this.loadAddDropdowns(); - } - - /** - * Moves the UI model into node mode. - * - * @param machine The machine that was selected in rack mode - */ - public enterMode(machine: IMachine): void { - this.currentMachine = machine; - this.populateUnitLists(); - $("#node-menu").removeClass("hidden"); - - if (this.mapController.appMode === AppMode.SIMULATION) { - this.mapController.simulationController.transitionFromRackToNode(); - } - } - - /** - * Performs cleanup and closing actions before allowing transferal to rack mode. - */ - public goToObjectMode(): void { - $("#node-menu").addClass("hidden"); - $(".node-element-overlay").addClass("hidden"); - this.currentMachine = undefined; - this.mapController.interactionLevel = InteractionLevel.OBJECT; - - if (this.mapController.appMode === AppMode.SIMULATION) { - this.mapController.simulationController.transitionFromNodeToRack(); - } - } - - /** - * Connects all DOM event listeners to their respective element targets. - */ - public setupEventListeners(): void { - const nodeMenu = $("#node-menu"); - - nodeMenu.find(".panel-group").on("click", ".remove-unit", (event: JQueryEventObject) => { - MapController.showConfirmDeleteDialog("unit", () => { - const index = $(event.target).closest(".panel").index(); - - if (index === -1) { - return; - } - - const closestTabPane = $(event.target).closest(".panel-group"); - - let objectList, idList; - if (closestTabPane.is("#cpu-accordion")) { - objectList = this.currentMachine.cpus; - idList = this.currentMachine.cpuIds; - } else if (closestTabPane.is("#gpu-accordion")) { - objectList = this.currentMachine.gpus; - idList = this.currentMachine.gpuIds; - } else if (closestTabPane.is("#memory-accordion")) { - objectList = this.currentMachine.memories; - idList = this.currentMachine.memoryIds; - } else if (closestTabPane.is("#storage-accordion")) { - objectList = this.currentMachine.storages; - idList = this.currentMachine.storageIds; - } - - idList.splice(idList.indexOf(objectList[index]).id, 1); - objectList.splice(index, 1); - - this.mapController.api.updateMachine(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.mapController.roomModeController.currentRoom.id, - this.mapController.objectModeController.currentObjectTile.id, this.currentMachine).then( - () => { - this.populateUnitLists(); - this.mapController.objectModeController.updateNodeComponentOverlays(); - }); - }); - }); - - nodeMenu.find(".add-unit").on("click", (event: JQueryEventObject) => { - const dropdown = $(event.target).closest(".input-group-btn").siblings("select").first(); - - const closestTabPane = $(event.target).closest(".input-group").siblings(".panel-group").first(); - let objectList, idList, typePlural; - if (closestTabPane.is("#cpu-accordion")) { - objectList = this.currentMachine.cpus; - idList = this.currentMachine.cpuIds; - typePlural = "cpus"; - } else if (closestTabPane.is("#gpu-accordion")) { - objectList = this.currentMachine.gpus; - idList = this.currentMachine.gpuIds; - typePlural = "gpus"; - } else if (closestTabPane.is("#memory-accordion")) { - objectList = this.currentMachine.memories; - idList = this.currentMachine.memoryIds; - typePlural = "memories"; - } else if (closestTabPane.is("#storage-accordion")) { - objectList = this.currentMachine.storages; - idList = this.currentMachine.storageIds; - typePlural = "storages"; - } - - if (idList.length + 1 > 4) { - this.mapController.showInfoBalloon("Machine has only 4 slots", "warning"); - return; - } - - const id = parseInt(dropdown.val()); - idList.push(id); - this.mapController.api.getSpecificationOfType(typePlural, id).then((spec: INodeUnit) => { - objectList.push(spec); - - this.mapController.api.updateMachine(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.mapController.roomModeController.currentRoom.id, - this.mapController.objectModeController.currentObjectTile.id, this.currentMachine).then( - () => { - this.populateUnitLists(); - this.mapController.objectModeController.updateNodeComponentOverlays(); - }); - }); - }); - } - - /** - * Populates the "add" dropdowns with all available unit options. - */ - private loadAddDropdowns(): void { - const unitTypes = [ - "cpus", "gpus", "memories", "storages" - ]; - const dropdowns = [ - $("#add-cpu-form").find("select"), - $("#add-gpu-form").find("select"), - $("#add-memory-form").find("select"), - $("#add-storage-form").find("select"), - ]; - - unitTypes.forEach((type: string, index: number) => { - this.mapController.api.getAllSpecificationsOfType(type).then((data: any) => { - data.forEach((option: INodeUnit) => { - dropdowns[index].append($("<option>").val(option.id).text(option.manufacturer + " " + option.family + - " " + option.model + " (" + option.generation + ")")); - }); - }); - }); - } - - /** - * Generates and inserts dynamically HTML code concerning all units of a machine. - */ - private populateUnitLists(): void { - // Contains the skeleton of a unit element and inserts the given data into it - const generatePanel = (type: string, index: number, list: any, specSection: string): string => { - return '<div class="panel panel-default">' + - ' <div class="panel-heading">' + - ' <h4 class="panel-title">' + - ' <a class="glyphicon glyphicon-remove remove-unit" href="javascript:void(0)"></a>' + - ' <a class="accordion-toggle collapsed" data-toggle="collapse" data-parent="#' + type + '-accordion"' + - ' href="#' + type + '-' + index + '">' + - list[index].manufacturer + ' ' + list[index].family + ' ' + list[index].model + - ' </a>' + - ' </h4>' + - ' </div>' + - ' <div id="' + type + '-' + index + '" class="panel-collapse collapse">' + - ' <table class="spec-table">' + - ' <tbody>' + - specSection + - ' </tbody>' + - ' </table>' + - ' </div>' + - '</div>'; - }; - - // Generates the structure of the specification list of a processing unit - const generateProcessingUnitHtml = (element: IProcessingUnit) => { - return ' <tr>' + - ' <td class="glyphicon glyphicon-tasks"></td>' + - ' <td>Number of Cores</td>' + - ' <td>' + element.numberOfCores + '</td>' + - ' </tr>' + - ' <tr>' + - ' <td class="glyphicon glyphicon-dashboard"></td>' + - ' <td>Clockspeed (MHz)</td>' + - ' <td>' + element.clockRateMhz + '</td>' + - ' </tr>' + - ' <tr>' + - ' <td class="glyphicon glyphicon-flash"></td>' + - ' <td>Energy Consumption (W)</td>' + - ' <td>' + element.energyConsumptionW + '</td>' + - ' </tr>' + - ' <tr>' + - ' <td class="glyphicon glyphicon-alert"></td>' + - ' <td>Failure Rate (%)</td>' + - ' <td>' + element.failureModel.rate + '</td>' + - ' </tr>'; - }; - - // Generates the structure of the spec list of a storage unit - const generateStorageUnitHtml = (element: IStorageUnit) => { - return ' <tr>' + - ' <td class="glyphicon glyphicon-floppy-disk"></td>' + - ' <td>Size (Mb)</td>' + - ' <td>' + element.sizeMb + '</td>' + - ' </tr>' + - ' <tr>' + - ' <td class="glyphicon glyphicon-dashboard"></td>' + - ' <td>Speed (Mb/s)</td>' + - ' <td>' + element.speedMbPerS + '</td>' + - ' </tr>' + - ' <tr>' + - ' <td class="glyphicon glyphicon-flash"></td>' + - ' <td>Energy Consumption (W)</td>' + - ' <td>' + element.energyConsumptionW + '</td>' + - ' </tr>' + - ' <tr>' + - ' <td class="glyphicon glyphicon-alert"></td>' + - ' <td>Failure Rate (%)</td>' + - ' <td>' + element.failureModel.rate + '</td>' + - ' </tr>'; - }; - - // Inserts a "No units" message into the container of the given unit type - const addNoUnitsMessage = (type: string) => { - $("#" + type + "-accordion").append("<p>There are currently no units present here. " + - "<em>Add some with the dropdown below!</em></p>"); - }; - - let container = $("#cpu-accordion"); - container.children().remove(".panel"); - container.children().remove("p"); - - if (this.currentMachine.cpus.length === 0) { - addNoUnitsMessage("cpu"); - } else { - this.currentMachine.cpus.forEach((element: ICPU, i: number) => { - const specSection = generateProcessingUnitHtml(element); - const content = generatePanel("cpu", i, this.currentMachine.cpus, specSection); - container.append(content); - }); - } - - container = $("#gpu-accordion"); - container.children().remove(".panel"); - container.children().remove("p"); - if (this.currentMachine.gpus.length === 0) { - addNoUnitsMessage("gpu"); - } else { - this.currentMachine.gpus.forEach((element: IGPU, i: number) => { - const specSection = generateProcessingUnitHtml(element); - const content = generatePanel("gpu", i, this.currentMachine.gpus, specSection); - container.append(content); - }); - } - - container = $("#memory-accordion"); - container.children().remove(".panel"); - container.children().remove("p"); - if (this.currentMachine.memories.length === 0) { - addNoUnitsMessage("memory"); - } else { - this.currentMachine.memories.forEach((element: IMemory, i: number) => { - const specSection = generateStorageUnitHtml(element); - const content = generatePanel("memory", i, this.currentMachine.memories, specSection); - container.append(content); - }); - } - - container = $("#storage-accordion"); - container.children().remove(".panel"); - container.children().remove("p"); - if (this.currentMachine.storages.length === 0) { - addNoUnitsMessage("storage"); - } else { - this.currentMachine.storages.forEach((element: IMemory, i: number) => { - const specSection = generateStorageUnitHtml(element); - const content = generatePanel("storage", i, this.currentMachine.storages, specSection); - container.append(content); - }); - } - } -} diff --git a/src/scripts/controllers/modes/object.ts b/src/scripts/controllers/modes/object.ts deleted file mode 100644 index bc358d71..00000000 --- a/src/scripts/controllers/modes/object.ts +++ /dev/null @@ -1,296 +0,0 @@ -import {AppMode, InteractionLevel, MapController} from "../mapcontroller"; -import {MapView} from "../../views/mapview"; -import * as $ from "jquery"; - - -/** - * Class responsible for rendering object mode and handling its UI interactions. - */ -export class ObjectModeController { - public currentObject: IDCObject; - public objectType: string; - public currentRack: IRack; - public currentPSU: IPSU; - public currentCoolingItem: ICoolingItem; - public currentObjectTile: ITile; - - private mapController: MapController; - private mapView: MapView; - - - constructor(mapController: MapController) { - this.mapController = mapController; - this.mapView = this.mapController.mapView; - } - - /** - * Performs the necessary setup actions and enters object mode. - * - * @param tile A reference to the tile containing the rack that was selected. - */ - public enterMode(tile: ITile) { - this.currentObjectTile = tile; - this.mapView.grayLayer.currentObjectTile = tile; - this.currentObject = tile.object; - this.objectType = tile.objectType; - - // Show the corresponding sub-menu of object mode - $(".object-sub-menu").hide(); - - switch (this.objectType) { - case "RACK": - $("#rack-sub-menu").show(); - this.currentRack = <IRack>this.currentObject; - $("#rack-name-input").val(this.currentRack.name); - this.populateNodeList(); - - break; - - case "PSU": - $("#psu-sub-menu").show(); - this.currentPSU = <IPSU>this.currentObject; - - break; - - case "COOLING_ITEM": - $("#cooling-item-sub-menu").show(); - this.currentCoolingItem = <ICoolingItem>this.currentObject; - - break; - } - - this.mapView.grayLayer.drawRackLevel(); - MapController.hideAndShowMenus("#object-menu"); - this.scrollToBottom(); - - if (this.mapController.appMode === AppMode.SIMULATION) { - this.mapController.simulationController.transitionFromRoomToRack(); - } - } - - /** - * Leaves object mode and transfers to room mode. - */ - public goToRoomMode() { - this.mapController.interactionLevel = InteractionLevel.ROOM; - this.mapView.grayLayer.hideRackLevel(); - MapController.hideAndShowMenus("#room-menu"); - this.mapController.roomModeController.enterMode(this.mapController.roomModeController.currentRoom); - - if (this.mapController.appMode === AppMode.SIMULATION) { - this.mapController.simulationController.transitionFromRackToRoom(); - } - } - - /** - * Connects all DOM event listeners to their respective element targets. - */ - public setupEventListeners() { - // Handler for saving a new rack name - $("#rack-name-save").on("click", () => { - this.currentRack.name = $("#rack-name-input").text(); - this.mapController.api.updateRack(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.mapController.roomModeController.currentRoom.id, - this.mapController.objectModeController.currentObjectTile.id, this.currentRack).then( - () => { - this.mapController.showInfoBalloon("Rack name saved", "info"); - }); - }); - - const nodeListContainer = $(".node-list-container"); - - // Handler for the 'add' button of each machine slot of the rack - nodeListContainer.on("click", ".add-node", (event: JQueryEventObject) => { - // Convert the DOM element index to a JS array index - const index = this.currentRack.machines.length - $(event.target).closest(".node-element").index() - 1; - - // Insert an empty machine at the selected position - this.mapController.api.addMachineToRack(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.mapController.roomModeController.currentRoom.id, - this.mapController.objectModeController.currentObjectTile.id, { - id: -1, - rackId: this.currentRack.id, - position: index, - tags: [], - cpuIds: [], - gpuIds: [], - memoryIds: [], - storageIds: [] - }).then((data: IMachine) => { - this.currentRack.machines[index] = data; - this.populateNodeList(); - this.mapView.dcObjectLayer.draw(); - }); - - event.stopPropagation(); - }); - - // Handler for the 'remove' button of each machine slot of the rack - nodeListContainer.on("click", ".remove-node", (event: JQueryEventObject) => { - const target = $(event.target); - MapController.showConfirmDeleteDialog("machine", () => { - // Convert the DOM element index to a JS array index - const index = this.currentRack.machines.length - target.closest(".node-element").index() - 1; - - this.mapController.api.deleteMachine(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.mapController.roomModeController.currentRoom.id, - this.mapController.objectModeController.currentObjectTile.id, - index).then(() => { - this.currentRack.machines[index] = null; - this.populateNodeList(); - this.mapView.dcObjectLayer.draw(); - }); - }); - event.stopPropagation(); - }); - - // Handler for every node element, triggering node mode - nodeListContainer.on("click", ".node-element", (event: JQueryEventObject) => { - const domIndex = $(event.target).closest(".node-element").index(); - const index = this.currentRack.machines.length - domIndex - 1; - const machine = this.currentRack.machines[index]; - - if (machine != null) { - this.mapController.interactionLevel = InteractionLevel.NODE; - - // Gray out the other nodes - $(event.target).closest(".node-list-container").children(".node-element").each((nodeIndex: number, element: Element) => { - if (nodeIndex !== domIndex) { - $(element).children(".node-element-overlay").removeClass("hidden"); - } else { - $(element).children(".node-element-overlay").addClass("hidden"); - } - }); - - this.mapController.nodeModeController.enterMode(machine); - } - }); - - // Handler for rack deletion button - $("#rack-deletion").on("click", () => { - MapController.showConfirmDeleteDialog("rack", () => { - this.mapController.api.deleteRack(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.mapController.roomModeController.currentRoom.id, - this.mapController.objectModeController.currentObjectTile.id).then(() => { - this.currentObjectTile.object = undefined; - this.currentObjectTile.objectType = undefined; - this.currentObjectTile.objectId = undefined; - this.mapView.redrawMap(); - this.goToRoomMode(); - }); - }); - }); - - // Handler for PSU deletion button - $("#psu-deletion").on("click", () => { - MapController.showConfirmDeleteDialog("PSU", () => { - this.mapController.api.deletePSU(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.mapController.roomModeController.currentRoom.id, - this.mapController.objectModeController.currentObjectTile.id).then(() => { - this.mapView.redrawMap(); - this.goToRoomMode(); - }); - this.currentObjectTile.object = undefined; - this.currentObjectTile.objectType = undefined; - this.currentObjectTile.objectId = undefined; - }); - }); - - // Handler for Cooling Item deletion button - $("#cooling-item-deletion").on("click", () => { - MapController.showConfirmDeleteDialog("cooling item", () => { - this.mapController.api.deleteCoolingItem(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.mapController.roomModeController.currentRoom.id, - this.mapController.objectModeController.currentObjectTile.id).then(() => { - this.mapView.redrawMap(); - this.goToRoomMode(); - }); - this.currentObjectTile.object = undefined; - this.currentObjectTile.objectType = undefined; - this.currentObjectTile.objectId = undefined; - }); - }); - } - - public updateNodeComponentOverlays(): void { - if (this.currentRack === undefined || this.currentRack.machines === undefined) { - return; - } - - for (let i = 0; i < this.currentRack.machines.length; i++) { - if (this.currentRack.machines[i] === null) { - continue; - } - - const container = this.mapController.appMode === AppMode.CONSTRUCTION ? ".construction" : ".simulation"; - const element = $(container + " .node-element").eq(this.currentRack.machines.length - i - 1); - if (this.currentRack.machines[i].cpus.length !== 0) { - element.find(".overlay-cpu").addClass("hidden"); - } else { - element.find(".overlay-cpu").removeClass("hidden"); - } - if (this.currentRack.machines[i].gpus.length !== 0) { - element.find(".overlay-gpu").addClass("hidden"); - } else { - element.find(".overlay-gpu").removeClass("hidden"); - } - if (this.currentRack.machines[i].memories.length !== 0) { - element.find(".overlay-memory").addClass("hidden"); - } else { - element.find(".overlay-memory").removeClass("hidden"); - } - if (this.currentRack.machines[i].storages.length !== 0) { - element.find(".overlay-storage").addClass("hidden"); - } else { - element.find(".overlay-storage").removeClass("hidden"); - } - } - } - - /** - * Dynamically generates and inserts HTML code for every node in the current rack. - */ - private populateNodeList(): void { - const container = $(".node-list-container"); - - // Remove any previously present node elements - container.children().remove(".node-element"); - - for (let i = 0; i < this.currentRack.machines.length; i++) { - // Depending on whether the current machine slot is filled, allow removing or adding a new machine by adding - // the appropriate button next to the machine slot - const type = (this.currentRack.machines[i] == null ? "glyphicon-plus add-node" : "glyphicon-remove remove-node"); - let content = - '<div class="node-element" data-id="' + (this.currentRack.machines[i] === null ? - "" : this.currentRack.machines[i].id) + '">' + - ' <div class="node-element-overlay hidden"></div>' + - ' <a class="node-element-btn glyphicon ' + type + '" href="javascript:void(0)"></a>' + - ' <div class="node-element-number">' + (i + 1) + '</div>'; - if (this.currentRack.machines[i] !== null) { - content += - '<div class="node-element-content">' + - ' <img src="img/app/node-cpu.png">' + - ' <img src="img/app/node-gpu.png">' + - ' <img src="img/app/node-memory.png">' + - ' <img src="img/app/node-storage.png">' + - ' <img src="img/app/node-network.png">' + - ' <div class="icon-overlay overlay-cpu hidden"></div>' + - ' <div class="icon-overlay overlay-gpu hidden"></div>' + - ' <div class="icon-overlay overlay-memory hidden"></div>' + - ' <div class="icon-overlay overlay-storage hidden"></div>' + - ' <div class="icon-overlay overlay-network"></div>' + - '</div>'; - } - content += '</div>'; - // Insert the generated machine slot into the DOM - container.prepend(content); - } - - this.updateNodeComponentOverlays(); - } - - private scrollToBottom(): void { - const scrollContainer = $('.node-list-container'); - scrollContainer.scrollTop(scrollContainer[0].scrollHeight); - } -} diff --git a/src/scripts/controllers/modes/room.ts b/src/scripts/controllers/modes/room.ts deleted file mode 100644 index dc7f4a41..00000000 --- a/src/scripts/controllers/modes/room.ts +++ /dev/null @@ -1,382 +0,0 @@ -import {Util} from "../../util"; -import {AppMode, InteractionLevel, MapController} from "../mapcontroller"; -import {MapView} from "../../views/mapview"; -import * as $ from "jquery"; - - -export enum RoomInteractionMode { - DEFAULT, - ADD_RACK, - ADD_PSU, - ADD_COOLING_ITEM -} - - -export class RoomModeController { - public currentRoom: IRoom; - public roomInteractionMode: RoomInteractionMode; - - private mapController: MapController; - private mapView: MapView; - private roomTypes: string[]; - private roomTypeMap: IRoomTypeMap; - private availablePSUs: IPSU[]; - private availableCoolingItems: ICoolingItem[]; - - - constructor(mapController: MapController) { - this.mapController = mapController; - this.mapView = this.mapController.mapView; - - this.mapController.api.getAllRoomTypes().then((roomTypes: string[]) => { - this.roomTypes = roomTypes; - this.roomTypeMap = {}; - - this.roomTypes.forEach((type: string) => { - this.mapController.api.getAllowedObjectsByRoomType(type).then((objects: string[]) => { - this.roomTypeMap[type] = objects; - }); - }); - - this.populateRoomTypeDropdown(); - }); - - // this.mapController.api.getAllPSUSpecs().then((specs: IPSU[]) => { - // this.availablePSUs = specs; - // }); - // - // this.mapController.api.getAllCoolingItemSpecs().then((specs: ICoolingItem[]) => { - // this.availableCoolingItems = specs; - // }); - - this.roomInteractionMode = RoomInteractionMode.DEFAULT; - } - - public enterMode(room: IRoom) { - this.currentRoom = room; - this.roomInteractionMode = RoomInteractionMode.DEFAULT; - - this.mapView.roomTextLayer.setVisibility(false); - - this.mapView.zoomInOnRoom(this.currentRoom); - $("#room-name-input").val(this.currentRoom.name); - MapController.hideAndShowMenus("#room-menu"); - - // Pre-select the type of the current room in the dropdown - const roomTypeDropdown = $("#roomtype-select"); - roomTypeDropdown.find('option').prop("selected", "false"); - const roomTypeIndex = this.roomTypes.indexOf(this.currentRoom.roomType); - if (roomTypeIndex !== -1) { - roomTypeDropdown.find('option[value="' + roomTypeIndex + '"]').prop("selected", "true"); - } else { - roomTypeDropdown.val([]); - } - - this.populateAllowedObjectTypes(); - - this.mapView.roomLayer.setClickable(false); - - if (this.mapController.appMode === AppMode.SIMULATION) { - this.mapController.simulationController.transitionFromBuildingToRoom(); - } - } - - public goToBuildingMode() { - this.mapController.interactionLevel = InteractionLevel.BUILDING; - - if (this.roomInteractionMode !== RoomInteractionMode.DEFAULT) { - this.roomInteractionMode = RoomInteractionMode.DEFAULT; - this.mapView.hoverLayer.setHoverItemVisibility(false); - $("#add-rack-btn").attr("data-active", "false"); - $("#add-psu-btn").attr("data-active", "false"); - $("#add-cooling-item-btn").attr("data-active", "false"); - } - - this.mapView.roomTextLayer.setVisibility(true); - - this.mapView.zoomOutOnDC(); - MapController.hideAndShowMenus("#building-menu"); - - this.mapView.roomLayer.setClickable(true); - - if (this.mapController.appMode === AppMode.SIMULATION) { - this.mapController.simulationController.transitionFromRoomToBuilding(); - } - } - - public setupEventListeners(): void { - // Component buttons - const addRackBtn = $("#add-rack-btn"); - const addPSUBtn = $("#add-psu-btn"); - const addCoolingItemBtn = $("#add-cooling-item-btn"); - - const roomTypeDropdown = $("#roomtype-select"); - - addRackBtn.on("click", () => { - this.handleItemClick("RACK"); - }); - addPSUBtn.on("click", () => { - this.handleItemClick("PSU"); - }); - addCoolingItemBtn.on("click", () => { - this.handleItemClick("COOLING_ITEM"); - }); - - // Handler for saving a new room name - $("#room-name-save").on("click", () => { - this.currentRoom.name = $("#room-name-input").text(); - this.mapController.api.updateRoom(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.currentRoom).then(() => { - this.mapView.roomTextLayer.draw(); - this.mapController.showInfoBalloon("Room name saved", "info"); - }); - }); - - // Handler for room deletion button - $("#room-deletion").on("click", () => { - MapController.showConfirmDeleteDialog("room", () => { - this.mapController.api.deleteRoom(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.currentRoom.id).then(() => { - const roomIndex = this.mapView.currentDatacenter.rooms.indexOf(this.currentRoom); - this.mapView.currentDatacenter.rooms.splice(roomIndex, 1); - - this.mapView.redrawMap(); - this.goToBuildingMode(); - }); - }); - }); - - // Handler for the room type dropdown component - roomTypeDropdown.on("change", () => { - const newRoomType = this.roomTypes[roomTypeDropdown.val()]; - if (!this.checkRoomTypeLegality(newRoomType)) { - roomTypeDropdown.val(this.roomTypes.indexOf(this.currentRoom.roomType)); - this.mapController.showInfoBalloon("Room type couldn't be changed, illegal objects", "warning"); - return; - } - - this.currentRoom.roomType = newRoomType; - this.mapController.api.updateRoom(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.currentRoom).then(() => { - this.populateAllowedObjectTypes(); - this.mapView.roomTextLayer.draw(); - this.mapController.showInfoBalloon("Room type changed", "info"); - }); - }); - } - - public handleCanvasMouseClick(gridPos: IGridPosition): void { - if (this.roomInteractionMode === RoomInteractionMode.DEFAULT) { - const tileIndex = Util.tileListPositionIndexOf(this.currentRoom.tiles, gridPos); - - if (tileIndex !== -1) { - const tile = this.currentRoom.tiles[tileIndex]; - - if (tile.object !== undefined) { - this.mapController.interactionLevel = InteractionLevel.OBJECT; - this.mapController.objectModeController.enterMode(tile); - } - } else { - this.goToBuildingMode(); - } - } else if (this.roomInteractionMode === RoomInteractionMode.ADD_RACK) { - this.addObject(this.mapView.hoverLayer.hoverTilePosition, "RACK"); - - } else if (this.roomInteractionMode === RoomInteractionMode.ADD_PSU) { - this.addObject(this.mapView.hoverLayer.hoverTilePosition, "PSU"); - - } else if (this.roomInteractionMode === RoomInteractionMode.ADD_COOLING_ITEM) { - this.addObject(this.mapView.hoverLayer.hoverTilePosition, "COOLING_ITEM"); - - } - } - - private handleItemClick(type: string): void { - const addRackBtn = $("#add-rack-btn"); - const addPSUBtn = $("#add-psu-btn"); - const addCoolingItemBtn = $("#add-cooling-item-btn"); - const allObjectContainers = $(".dc-component-container"); - const objectTypes = [ - { - type: "RACK", - mode: RoomInteractionMode.ADD_RACK, - btn: addRackBtn - }, - { - type: "PSU", - mode: RoomInteractionMode.ADD_PSU, - btn: addPSUBtn - }, - { - type: "COOLING_ITEM", - mode: RoomInteractionMode.ADD_COOLING_ITEM, - btn: addCoolingItemBtn - } - ]; - - allObjectContainers.attr("data-active", "false"); - - if (this.roomInteractionMode === RoomInteractionMode.DEFAULT) { - this.mapView.hoverLayer.setHoverItemVisibility(true, type); - - if (type === "RACK") { - this.roomInteractionMode = RoomInteractionMode.ADD_RACK; - addRackBtn.attr("data-active", "true"); - } else if (type === "PSU") { - this.roomInteractionMode = RoomInteractionMode.ADD_PSU; - addPSUBtn.attr("data-active", "true"); - } else if (type === "COOLING_ITEM") { - this.roomInteractionMode = RoomInteractionMode.ADD_COOLING_ITEM; - addCoolingItemBtn.attr("data-active", "true"); - } - - return; - } - - let changed = false; - objectTypes.forEach((objectType: any, index: number) => { - if (this.roomInteractionMode === objectType.mode) { - if (changed) { - return; - } - if (type === objectType.type) { - this.roomInteractionMode = RoomInteractionMode.DEFAULT; - this.mapView.hoverLayer.setHoverItemVisibility(false); - objectType.btn.attr("data-active", "false"); - } else { - objectTypes.forEach((otherObjectType, otherIndex: number) => { - if (index !== otherIndex) { - if (type === otherObjectType.type) { - this.mapView.hoverLayer.setHoverItemVisibility(true, type); - otherObjectType.btn.attr("data-active", "true"); - this.roomInteractionMode = otherObjectType.mode; - } - } - }); - } - changed = true; - } - }); - } - - private addObject(position: IGridPosition, type: string): void { - if (!this.mapView.roomLayer.checkHoverTileValidity(position)) { - return; - } - - const tileList = this.mapView.mapController.roomModeController.currentRoom.tiles; - - for (let i = 0; i < tileList.length; i++) { - if (tileList[i].position.x === position.x && tileList[i].position.y === position.y) { - if (type === "RACK") { - this.mapController.api.addRack(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.currentRoom.id, tileList[i].id, { - id: -1, - objectType: "RACK", - name: "", - capacity: 42, - powerCapacityW: 5000 - }).then((rack: IRack) => { - tileList[i].object = rack; - tileList[i].objectId = rack.id; - tileList[i].objectType = type; - this.mapView.dcObjectLayer.populateObjectList(); - this.mapView.dcObjectLayer.draw(); - - this.mapView.updateScene = true; - }); - } else if (type === "PSU") { - this.mapController.api.addPSU(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.currentRoom.id, tileList[i].id, this.availablePSUs[0]) - .then((psu: IPSU) => { - tileList[i].object = psu; - tileList[i].objectId = psu.id; - tileList[i].objectType = type; - this.mapView.dcObjectLayer.populateObjectList(); - this.mapView.dcObjectLayer.draw(); - - this.mapView.updateScene = true; - }); - } else if (type === "COOLING_ITEM") { - this.mapController.api.addCoolingItem(this.mapView.simulation.id, - this.mapView.currentDatacenter.id, this.currentRoom.id, tileList[i].id, - this.availableCoolingItems[0]).then((coolingItem: ICoolingItem) => { - tileList[i].object = coolingItem; - tileList[i].objectId = coolingItem.id; - tileList[i].objectType = type; - this.mapView.dcObjectLayer.populateObjectList(); - this.mapView.dcObjectLayer.draw(); - - this.mapView.updateScene = true; - }); - } - - break; - } - } - } - - /** - * Populates the room-type dropdown element with all available room types - */ - private populateRoomTypeDropdown(): void { - const dropdown = $("#roomtype-select"); - - this.roomTypes.forEach((type: string, index: number) => { - dropdown.append($('<option>').text(Util.toSentenceCase(type)).val(index)); - }); - } - - /** - * Loads all object types that are allowed in the current room into the menu. - */ - private populateAllowedObjectTypes(): void { - const addObjectsLabel = $("#add-objects-label"); - const noObjectsInfo = $("#no-objects-info"); - const allowedObjectTypes = this.roomTypeMap[this.currentRoom.roomType]; - - $(".dc-component-container").addClass("hidden"); - - if (allowedObjectTypes === undefined || allowedObjectTypes === null || allowedObjectTypes.length === 0) { - addObjectsLabel.addClass("hidden"); - noObjectsInfo.removeClass("hidden"); - - return; - } - - addObjectsLabel.removeClass("hidden"); - noObjectsInfo.addClass("hidden"); - allowedObjectTypes.forEach((type: string) => { - switch (type) { - case "RACK": - $("#add-rack-btn").removeClass("hidden"); - break; - case "PSU": - $("#add-psu-btn").removeClass("hidden"); - break; - case "COOLING_ITEM": - $("#add-cooling-item-btn").removeClass("hidden"); - break; - } - }); - } - - /** - * Checks whether a given room type can be assigned to the current room based on units already present. - * - * @param newRoomType The new room type to be validated - * @returns {boolean} Whether it is allowed to change the room's type to the new type - */ - private checkRoomTypeLegality(newRoomType: string): boolean { - let legality = true; - - this.currentRoom.tiles.forEach((tile: ITile) => { - if (tile.objectType !== undefined && tile.objectType !== null && tile.objectType !== "" && - this.roomTypeMap[newRoomType].indexOf(tile.objectType) === -1) { - legality = false; - } - }); - - return legality; - } -} diff --git a/src/scripts/controllers/scaleindicator.ts b/src/scripts/controllers/scaleindicator.ts deleted file mode 100644 index 789f2cc7..00000000 --- a/src/scripts/controllers/scaleindicator.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {MapController, CELL_SIZE} from "./mapcontroller"; -import {MapView} from "../views/mapview"; - - -export class ScaleIndicatorController { - private static MIN_WIDTH = 50; - private static MAX_WIDTH = 100; - - private mapController: MapController; - private mapView: MapView; - - private jqueryObject: JQuery; - private currentDivisor: number; - - - constructor(mapController: MapController) { - this.mapController = mapController; - this.mapView = mapController.mapView; - } - - public init(jqueryObject: JQuery): void { - this.jqueryObject = jqueryObject; - this.currentDivisor = 1; - } - - public update(): void { - const currentZoom = this.mapView.mapContainer.scaleX; - let newWidth; - do { - newWidth = (currentZoom * CELL_SIZE) / this.currentDivisor; - - if (newWidth < ScaleIndicatorController.MIN_WIDTH) { - this.currentDivisor /= 2; - } else if (newWidth > ScaleIndicatorController.MAX_WIDTH) { - this.currentDivisor *= 2; - } else { - break; - } - } while (true); - - - this.jqueryObject.text(MapView.CELL_SIZE_METERS / this.currentDivisor + "m"); - this.jqueryObject.width(newWidth); - } -} diff --git a/src/scripts/controllers/simulation/chart.ts b/src/scripts/controllers/simulation/chart.ts deleted file mode 100644 index 1b67934b..00000000 --- a/src/scripts/controllers/simulation/chart.ts +++ /dev/null @@ -1,241 +0,0 @@ -import * as c3 from "c3"; -import {InteractionLevel, MapController} from "../mapcontroller"; -import {ColorRepresentation, SimulationController} from "../simulationcontroller"; -import {Util} from "../../util"; - - -export interface IStateColumn { - loadFractions: string[] | number[]; - inUseMemoryMb: string[] | number[]; - temperatureC: string[] | number[]; -} - - -export class ChartController { - public roomSeries: { [key: number]: IStateColumn }; - public rackSeries: { [key: number]: IStateColumn }; - public machineSeries: { [key: number]: IStateColumn }; - public chart: c3.ChartAPI; - public machineChart: c3.ChartAPI; - - private simulationController: SimulationController; - private mapController: MapController; - private chartData: (string | number)[][]; - private xSeries: (string | number)[]; - private names: { [key: string]: string }; - - - constructor(simulationController: SimulationController) { - this.simulationController = simulationController; - this.mapController = simulationController.mapController; - } - - public setup(): void { - this.names = {}; - - this.roomSeries = {}; - this.rackSeries = {}; - this.machineSeries = {}; - - this.simulationController.sections.forEach((simulationSection: ISection) => { - simulationSection.datacenter.rooms.forEach((room: IRoom) => { - if (room.roomType === "SERVER" && this.roomSeries[room.id] === undefined) { - this.names["ro" + room.id] = (room.name === "" || room.name === undefined) ? - "Unnamed room" : room.name; - - this.roomSeries[room.id] = { - loadFractions: ["ro" + room.id], - inUseMemoryMb: ["ro" + room.id], - temperatureC: ["ro" + room.id] - }; - } - - room.tiles.forEach((tile: ITile) => { - if (tile.object !== undefined && tile.objectType === "RACK" && this.rackSeries[tile.objectId] === undefined) { - const objectName = (<IRack>tile.object).name; - this.names["ra" + tile.objectId] = objectName === "" || objectName === undefined ? - "Unnamed rack" : objectName; - - this.rackSeries[tile.objectId] = { - loadFractions: ["ra" + tile.objectId], - inUseMemoryMb: ["ra" + tile.objectId], - temperatureC: ["ra" + tile.objectId] - }; - - (<IRack>tile.object).machines.forEach((machine: IMachine) => { - if (machine === null || this.machineSeries[machine.id] !== undefined) { - return; - } - - this.names["ma" + machine.id] = "Machine at position " + (machine.position + 1).toString(); - - this.machineSeries[machine.id] = { - loadFractions: ["ma" + machine.id], - inUseMemoryMb: ["ma" + machine.id], - temperatureC: ["ma" + machine.id] - }; - }); - } - }); - }); - }); - - - this.xSeries = ["time"]; - this.chartData = [this.xSeries]; - - this.chart = this.chartSetup("#statistics-chart"); - this.machineChart = this.chartSetup("#machine-statistics-chart"); - } - - public chartSetup(chartId: string): c3.ChartAPI { - return c3.generate({ - bindto: chartId, - data: { - // xFormat: '%S', - x: "time", - columns: this.chartData, - names: this.names - }, - axis: { - x: { - type: "timeseries", - tick: { - format: function (time: Date) { - let formattedTime = time.getSeconds() + "s"; - - if (time.getMinutes() > 0) { - formattedTime = time.getMinutes() + "m" + formattedTime; - } - if (time.getHours() > 0) { - formattedTime = time.getHours() + "h" + formattedTime; - } - - return formattedTime; - }, - culling: { - max: 5 - }, - count: 8 - }, - padding: { - left: 0, - right: 10 - } - }, - y: { - min: 0, - max: 1, - padding: { - top: 0, - bottom: 0 - }, - tick: { - format: function (d) { - return (Math.round(d * 100) / 100).toString(); - } - } - } - } - }); - } - - public update(): void { - this.xSeries = (<(number|string)[]>["time"]).concat(<any[]> Util.timeRange(this.simulationController.currentTick)); - - this.chartData = [this.xSeries]; - - let prefix = ""; - let machineId = -1; - if (this.mapController.interactionLevel === InteractionLevel.BUILDING) { - for (let roomId in this.roomSeries) { - if (this.roomSeries.hasOwnProperty(roomId)) { - if (this.simulationController.colorRepresentation === ColorRepresentation.LOAD) { - this.chartData.push(this.roomSeries[roomId].loadFractions); - } - } - } - prefix = "ro"; - } else if (this.mapController.interactionLevel === InteractionLevel.ROOM) { - for (let rackId in this.rackSeries) { - if (this.rackSeries.hasOwnProperty(rackId) && - this.simulationController.rackToRoomMap[rackId] === - this.mapController.roomModeController.currentRoom.id) { - if (this.simulationController.colorRepresentation === ColorRepresentation.LOAD) { - this.chartData.push(this.rackSeries[rackId].loadFractions); - } - } - } - prefix = "ra"; - } else if (this.mapController.interactionLevel === InteractionLevel.NODE) { - if (this.simulationController.colorRepresentation === ColorRepresentation.LOAD) { - this.chartData.push( - this.machineSeries[this.mapController.nodeModeController.currentMachine.id].loadFractions - ); - } - prefix = "ma"; - machineId = this.mapController.nodeModeController.currentMachine.id; - } - - const unloads: string[] = []; - for (let id in this.names) { - if (this.names.hasOwnProperty(id)) { - if (machineId === -1) { - if (id.substr(0, 2) !== prefix || - (this.mapController.interactionLevel === InteractionLevel.ROOM && - this.simulationController.rackToRoomMap[parseInt(id.substr(2))] !== - this.mapController.roomModeController.currentRoom.id)) { - unloads.push(id); - } - } - else { - if (id !== prefix + machineId) { - unloads.push(id); - } - } - } - } - - let targetChart: c3.ChartAPI; - if (this.mapController.interactionLevel === InteractionLevel.NODE) { - targetChart = this.machineChart; - } else { - targetChart = this.chart; - } - - targetChart.load({ - columns: this.chartData, - unload: unloads - }); - - } - - public tickUpdated(tick: number): void { - const roomStates: IRoomState[] = this.simulationController.stateCache.stateList[tick].roomStates; - roomStates.forEach((roomState: IRoomState) => { - ChartController.insertAtIndex(this.roomSeries[roomState.roomId].loadFractions, tick + 1, roomState.loadFraction); - }); - - const rackStates: IRackState[] = this.simulationController.stateCache.stateList[tick].rackStates; - rackStates.forEach((rackState: IRackState) => { - ChartController.insertAtIndex(this.rackSeries[rackState.rackId].loadFractions, tick + 1, rackState.loadFraction); - }); - - const machineStates: IMachineState[] = this.simulationController.stateCache.stateList[tick].machineStates; - machineStates.forEach((machineState: IMachineState) => { - ChartController.insertAtIndex(this.machineSeries[machineState.machineId].loadFractions, tick + 1, machineState.loadFraction); - }); - } - - private static insertAtIndex(list: any[], index: number, data: any): void { - if (index > list.length) { - let i = list.length; - while (i < index) { - list[i] = null; - i++; - } - } - - list[index] = data; - } -} diff --git a/src/scripts/controllers/simulation/statecache.ts b/src/scripts/controllers/simulation/statecache.ts deleted file mode 100644 index 0a7767fa..00000000 --- a/src/scripts/controllers/simulation/statecache.ts +++ /dev/null @@ -1,321 +0,0 @@ -import {SimulationController} from "../simulationcontroller"; - - -export class StateCache { - public static CACHE_INTERVAL = 10000; - private static PREFERRED_CACHE_ADVANCE = 5; - - public stateList: {[key: number]: ITickState}; - public lastCachedTick: number; - public cacheBlock: boolean; - - private simulationController: SimulationController; - private intervalId: any; - private caching: boolean; - - // Item caches - private machineCache: {[keys: number]: IMachine}; - private rackCache: {[keys: number]: IRack}; - private roomCache: {[keys: number]: IRoom}; - private taskCache: {[keys: number]: ITask}; - - - constructor(simulationController: SimulationController) { - this.stateList = {}; - this.lastCachedTick = 0; - this.cacheBlock = true; - this.simulationController = simulationController; - this.caching = false; - } - - public startCaching(): void { - this.machineCache = {}; - this.rackCache = {}; - this.roomCache = {}; - this.taskCache = {}; - - this.simulationController.mapView.currentDatacenter.rooms.forEach((room: IRoom) => { - this.addRoomToCache(room); - }); - this.simulationController.currentExperiment.trace.tasks.forEach((task: ITask) => { - this.taskCache[task.id] = task; - }); - - this.caching = true; - - this.cache(); - this.intervalId = setInterval(() => { - this.cache(); - }, StateCache.CACHE_INTERVAL); - } - - private addRoomToCache(room: IRoom) { - this.roomCache[room.id] = room; - - room.tiles.forEach((tile: ITile) => { - if (tile.objectType === "RACK") { - this.rackCache[tile.objectId] = <IRack>tile.object; - - (<IRack> tile.object).machines.forEach((machine: IMachine) => { - if (machine !== null) { - this.machineCache[machine.id] = machine; - } - }); - } - }); - } - - public stopCaching(): void { - if (this.caching) { - this.caching = false; - clearInterval(this.intervalId); - } - } - - private cache(): void { - const tick = this.lastCachedTick + 1; - - this.updateLastTick().then(() => { - // Check if end of simulated region has been reached - if (this.lastCachedTick > this.simulationController.lastSimulatedTick) { - return; - } - - this.fetchAllAvailableStates().then((data) => { - this.stateList = data; - - // Determine last cached tick - const ticks = Object.keys(this.stateList).sort((a, b) => { - return parseInt(a) - parseInt(b); - }); - if (ticks.length > 0) { - this.lastCachedTick = parseInt(ticks[ticks.length - 1]); - } - - for (let i = 1; i <= this.lastCachedTick; i++) { - this.updateTasksForNewTick(i); - - // Update chart cache - this.simulationController.chartController.tickUpdated(i); - } - - if (!this.cacheBlock && this.lastCachedTick - this.simulationController.currentTick <= 0) { - this.cacheBlock = true; - return; - } - - if (this.cacheBlock) { - if (this.lastCachedTick - this.simulationController.currentTick >= StateCache.PREFERRED_CACHE_ADVANCE) { - this.cacheBlock = false; - } - } - }); - }); - } - - private updateTasksForNewTick(tick: number): void { - const taskIDsInTick = []; - - this.stateList[tick].taskStates.forEach((taskState: ITaskState) => { - taskIDsInTick.push(taskState.taskId); - if (this.stateList[tick - 1] !== undefined) { - let previousFlops = 0; - const previousStates = this.stateList[tick - 1].taskStates; - - for (let i = 0; i < previousStates.length; i++) { - if (previousStates[i].taskId === taskState.taskId) { - previousFlops = previousStates[i].flopsLeft; - break; - } - } - - if (previousFlops > 0 && taskState.flopsLeft === 0) { - taskState.task.finishedTick = tick; - } - } - }); - - // Generate pseudo-task-states for tasks that haven't started yet or have already finished - const traceTasks = this.simulationController.currentExperiment.trace.tasks; - if (taskIDsInTick.length !== traceTasks.length) { - traceTasks - .filter((task: ITask) => { - return taskIDsInTick.indexOf(task.id) === -1; - }) - .forEach((task: ITask) => { - const flopStateCount = task.startTick >= tick ? task.totalFlopCount : 0; - - this.stateList[tick].taskStates.push({ - id: -1, - taskId: task.id, - task: task, - experimentId: this.simulationController.currentExperiment.id, - tick, - flopsLeft: flopStateCount - }); - }); - } - - this.stateList[tick].taskStates.sort((a: ITaskState, b: ITaskState) => { - return a.task.startTick - b.task.startTick; - }); - } - - private updateLastTick(): Promise<void> { - return this.simulationController.mapController.api.getLastSimulatedTickByExperiment( - this.simulationController.simulation.id, this.simulationController.currentExperiment.id).then((data) => { - this.simulationController.lastSimulatedTick = data; - }); - } - - private fetchAllAvailableStates(): Promise<{[key: number]: ITickState}> { - let machineStates, rackStates, roomStates, taskStates; - const promises = []; - - promises.push( - this.simulationController.mapController.api.getMachineStates( - this.simulationController.mapView.simulation.id, this.simulationController.currentExperiment.id, - this.machineCache - ).then((states: IMachineState[]) => { - machineStates = states; - }) - ); - - promises.push( - this.simulationController.mapController.api.getRackStates( - this.simulationController.mapView.simulation.id, this.simulationController.currentExperiment.id, - this.rackCache - ).then((states: IRackState[]) => { - rackStates = states; - }) - ); - - promises.push( - this.simulationController.mapController.api.getRoomStates( - this.simulationController.mapView.simulation.id, this.simulationController.currentExperiment.id, - this.roomCache - ).then((states: IRoomState[]) => { - roomStates = states; - }) - ); - - promises.push( - this.simulationController.mapController.api.getTaskStates( - this.simulationController.mapView.simulation.id, this.simulationController.currentExperiment.id, - this.taskCache - ).then((states: ITaskState[]) => { - taskStates = states; - }) - ); - - return Promise.all(promises).then(() => { - const tickStates: {[key: number]: ITickState} = {}; - - machineStates.forEach((machineState: IMachineState) => { - if (tickStates[machineState.tick] === undefined) { - tickStates[machineState.tick] = { - tick: machineState.tick, - machineStates: [machineState], - rackStates: [], - roomStates: [], - taskStates: [] - }; - } else { - tickStates[machineState.tick].machineStates.push(machineState); - } - }); - rackStates.forEach((rackState: IRackState) => { - if (tickStates[rackState.tick] === undefined) { - tickStates[rackState.tick] = { - tick: rackState.tick, - machineStates: [], - rackStates: [rackState], - roomStates: [], - taskStates: [] - }; - } else { - tickStates[rackState.tick].rackStates.push(rackState); - } - }); - roomStates.forEach((roomState: IRoomState) => { - if (tickStates[roomState.tick] === undefined) { - tickStates[roomState.tick] = { - tick: roomState.tick, - machineStates: [], - rackStates: [], - roomStates: [roomState], - taskStates: [] - }; - } else { - tickStates[roomState.tick].roomStates.push(roomState); - } - }); - taskStates.forEach((taskState: ITaskState) => { - if (tickStates[taskState.tick] === undefined) { - tickStates[taskState.tick] = { - tick: taskState.tick, - machineStates: [], - rackStates: [], - roomStates: [], - taskStates: [taskState] - }; - } else { - tickStates[taskState.tick].taskStates.push(taskState); - } - }); - - return tickStates; - }); - } - - private fetchAllStatesOfTick(tick: number): Promise<ITickState> { - const tickState: ITickState = { - tick, - machineStates: [], - rackStates: [], - roomStates: [], - taskStates: [] - }; - const promises = []; - - promises.push( - this.simulationController.mapController.api.getMachineStates( - this.simulationController.mapView.simulation.id, this.simulationController.currentExperiment.id, - this.machineCache, tick - ).then((states: IMachineState[]) => { - tickState.machineStates = states; - }) - ); - - promises.push( - this.simulationController.mapController.api.getRackStates( - this.simulationController.mapView.simulation.id, this.simulationController.currentExperiment.id, - this.rackCache, tick - ).then((states: IRackState[]) => { - tickState.rackStates = states; - }) - ); - - promises.push( - this.simulationController.mapController.api.getRoomStates( - this.simulationController.mapView.simulation.id, this.simulationController.currentExperiment.id, - this.roomCache, tick - ).then((states: IRoomState[]) => { - tickState.roomStates = states; - }) - ); - - promises.push( - this.simulationController.mapController.api.getTaskStates( - this.simulationController.mapView.simulation.id, this.simulationController.currentExperiment.id, - this.taskCache, tick - ).then((states: ITaskState[]) => { - tickState.taskStates = states; - }) - ); - - return Promise.all(promises).then(() => { - return tickState; - }); - } -} diff --git a/src/scripts/controllers/simulation/taskview.ts b/src/scripts/controllers/simulation/taskview.ts deleted file mode 100644 index d989e103..00000000 --- a/src/scripts/controllers/simulation/taskview.ts +++ /dev/null @@ -1,64 +0,0 @@ -import * as $ from "jquery"; -import {SimulationController} from "../simulationcontroller"; -import {Util} from "../../util"; - - -export class TaskViewController { - private simulationController: SimulationController; - - - constructor(simulationController: SimulationController) { - this.simulationController = simulationController; - } - - /** - * Populates and displays the list of tasks with their current state. - */ - public update() { - const container = $(".task-list"); - container.children().remove(".task-element"); - - this.simulationController.stateCache.stateList[this.simulationController.currentTick].taskStates - .forEach((taskState: ITaskState) => { - const html = this.generateTaskElementHTML(taskState); - container.append(html); - }); - } - - private generateTaskElementHTML(taskState: ITaskState) { - let iconType, timeInfo; - - if (taskState.task.startTick > this.simulationController.currentTick) { - iconType = "glyphicon-time"; - timeInfo = "Not started yet"; - } else if (taskState.task.startTick <= this.simulationController.currentTick && taskState.flopsLeft > 0) { - iconType = "glyphicon-refresh"; - timeInfo = "Started at " + Util.convertSecondsToFormattedTime(taskState.task.startTick); - } else if (taskState.flopsLeft === 0) { - iconType = "glyphicon-ok"; - timeInfo = "Started at " + Util.convertSecondsToFormattedTime(taskState.task.startTick); - } - - // Calculate progression ratio - const progress = 1 - (taskState.flopsLeft / taskState.task.totalFlopCount); - - // Generate completion text - const flopsCompleted = taskState.task.totalFlopCount - taskState.flopsLeft; - const completionInfo = "Completed: " + flopsCompleted + " / " + taskState.task.totalFlopCount + " FLOPS"; - - return '<div class="task-element">' + - ' <div class="task-icon glyphicon ' + iconType + '"></div>' + - ' <div class="task-info">' + - ' <div class="task-time">' + timeInfo + - ' </div>' + - ' <div class="progress">' + - ' <div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="' + - progress * 100 + '%"' + - ' aria-valuemin="0" aria-valuemax="100" style="width: ' + progress * 100 + '%">' + - ' </div>' + - ' </div>' + - ' <div class="task-flops">' + completionInfo + '</div>' + - ' </div>' + - '</div>'; - } -} diff --git a/src/scripts/controllers/simulation/timeline.ts b/src/scripts/controllers/simulation/timeline.ts deleted file mode 100644 index ec3d8cb4..00000000 --- a/src/scripts/controllers/simulation/timeline.ts +++ /dev/null @@ -1,161 +0,0 @@ -import {SimulationController} from "../simulationcontroller"; -import {Util} from "../../util"; -import * as $ from "jquery"; - - -export class TimelineController { - private simulationController: SimulationController; - private startLabel: JQuery; - private endLabel: JQuery; - private playButton: JQuery; - private loadingIcon: JQuery; - private cacheSection: JQuery; - private timeMarker: JQuery; - private timeline: JQuery; - private timeUnitFraction: number; - private timeMarkerWidth: number; - private timelineWidth: number; - - - constructor(simulationController: SimulationController) { - this.simulationController = simulationController; - this.startLabel = $(".timeline-container .labels .start-time-label"); - this.endLabel = $(".timeline-container .labels .end-time-label"); - this.playButton = $(".timeline-container .play-btn"); - this.loadingIcon = this.playButton.find("img"); - this.cacheSection = $(".timeline-container .timeline .cache-section"); - this.timeMarker = $(".timeline-container .timeline .time-marker"); - this.timeline = $(".timeline-container .timeline"); - this.timeMarkerWidth = this.timeMarker.width(); - this.timelineWidth = this.timeline.width(); - } - - public togglePlayback(): void { - if (this.simulationController.stateCache.cacheBlock) { - this.simulationController.playing = false; - return; - } - this.simulationController.playing = !this.simulationController.playing; - this.setButtonIcon(); - } - - public setupListeners(): void { - this.playButton.on("click", () => { - this.togglePlayback(); - }); - - $(".timeline-container .timeline").on("click", (event: JQueryEventObject) => { - const parentOffset = $(event.target).closest(".timeline").offset(); - const clickX = event.pageX - parentOffset.left; - - let newTick = Math.round(clickX / (this.timelineWidth * this.timeUnitFraction)); - - if (newTick > this.simulationController.stateCache.lastCachedTick) { - newTick = this.simulationController.stateCache.lastCachedTick; - } - this.simulationController.currentTick = newTick; - this.simulationController.checkCurrentSimulationSection(); - this.simulationController.update(); - }); - } - - public setButtonIcon(): void { - if (this.simulationController.playing && !this.playButton.hasClass("glyphicon-pause")) { - this.playButton.removeClass("glyphicon-play").addClass("glyphicon-pause"); - } else if (!this.simulationController.playing && !this.playButton.hasClass("glyphicon-play")) { - this.playButton.removeClass("glyphicon-pause").addClass("glyphicon-play"); - } - } - - public update(): void { - this.timeUnitFraction = 1 / (this.simulationController.lastSimulatedTick + 1); - this.timelineWidth = $(".timeline-container .timeline").width(); - - this.updateTimeLabels(); - - this.cacheSection.css("width", this.calculateTickPosition(this.simulationController.stateCache.lastCachedTick)); - this.timeMarker.css("left", this.calculateTickPosition(this.simulationController.currentTick)); - - this.updateTaskIndicators(); - this.updateSectionMarkers(); - - if (this.simulationController.stateCache.cacheBlock) { - this.playButton.removeClass("glyphicon-pause").removeClass("glyphicon-play"); - this.loadingIcon.show(); - } else { - this.loadingIcon.hide(); - this.setButtonIcon(); - } - } - - private updateTimeLabels(): void { - this.startLabel.text(Util.convertSecondsToFormattedTime(this.simulationController.currentTick)); - this.endLabel.text(Util.convertSecondsToFormattedTime(this.simulationController.lastSimulatedTick)); - } - - private updateSectionMarkers(): void { - $(".section-marker").remove(); - - this.simulationController.sections.forEach((simulationSection: ISection) => { - if (simulationSection.startTick === 0) { - return; - } - - this.timeline.append( - $('<div class="section-marker">') - .css("left", this.calculateTickPosition(simulationSection.startTick)) - ); - }); - } - - private updateTaskIndicators(): void { - $(".task-indicator").remove(); - - const tickStateTypes = { - "queueEntryTick": "task-queued", - "startTick": "task-started", - "finishedTick": "task-finished" - }; - - if (this.simulationController.stateCache.lastCachedTick === -1) { - return; - } - - const indicatorCountList = new Array(this.simulationController.stateCache.lastCachedTick); - let indicator; - this.simulationController.currentExperiment.trace.tasks.forEach((task: ITask) => { - for (let tickStateType in tickStateTypes) { - if (!tickStateTypes.hasOwnProperty(tickStateType)) { - continue; - } - - if (task[tickStateType] !== undefined && - task[tickStateType] <= this.simulationController.stateCache.lastCachedTick) { - - let bottomOffset; - if (indicatorCountList[task[tickStateType]] === undefined) { - indicatorCountList[task[tickStateType]] = 1; - bottomOffset = 0; - } else { - bottomOffset = indicatorCountList[task[tickStateType]] * 10; - indicatorCountList[task[tickStateType]]++; - } - indicator = $('<div class="task-indicator ' + tickStateTypes[tickStateType] + '">') - .css("left", this.calculateTickPosition(task[tickStateType])) - .css("bottom", bottomOffset); - this.timeline.append(indicator); - } - } - }); - } - - private calculateTickPosition(tick: number): string { - let correction = 0; - if (this.timeUnitFraction * this.timelineWidth > this.timeMarkerWidth) { - correction = (this.timeUnitFraction * this.timelineWidth - this.timeMarkerWidth) * - ((tick - 1) / this.simulationController.lastSimulatedTick); - } - - return (100 * (this.timeUnitFraction * (tick - 1) + correction / this.timelineWidth)) + "%"; - } -} diff --git a/src/scripts/controllers/simulationcontroller.ts b/src/scripts/controllers/simulationcontroller.ts deleted file mode 100644 index 1185087d..00000000 --- a/src/scripts/controllers/simulationcontroller.ts +++ /dev/null @@ -1,586 +0,0 @@ -///<reference path="../../../typings/index.d.ts" /> -///<reference path="mapcontroller.ts" /> -import * as $ from "jquery"; -import {MapView} from "../views/mapview"; -import {AppMode, InteractionLevel, MapController} from "./mapcontroller"; -import {Util} from "../util"; -import {StateCache} from "./simulation/statecache"; -import {ChartController} from "./simulation/chart"; -import {TaskViewController} from "./simulation/taskview"; -import {TimelineController} from "./simulation/timeline"; - - -export enum ColorRepresentation { - LOAD, - TEMPERATURE, - MEMORY -} - - -export class SimulationController { - public mapView: MapView; - public mapController: MapController; - - public playing: boolean; - public currentTick: number; - public stateCache: StateCache; - public lastSimulatedTick: number; - public simulation: ISimulation; - public experiments: IExperiment[]; - public currentExperiment: IExperiment; - public currentPath: IPath; - public sections: ISection[]; - public currentSection: ISection; - public experimentSelectionMode: boolean; - public traces: ITrace[]; - public schedulers: IScheduler[]; - public sectionIndex: number; - public chartController: ChartController; - public timelineController: TimelineController; - - public colorRepresentation: ColorRepresentation; - public rackToRoomMap: {[key: number]: number;}; - - private taskViewController: TaskViewController; - private tickerId: any; - - - public static showOrHideSimComponents(visibility: boolean): void { - if (visibility) { - $("#statistics-menu").removeClass("hidden"); - $("#experiment-menu").removeClass("hidden"); - $("#tasks-menu").removeClass("hidden"); - $(".timeline-container").removeClass("hidden"); - } else { - $("#statistics-menu").addClass("hidden"); - $("#experiment-menu").addClass("hidden"); - $("#tasks-menu").addClass("hidden"); - $(".timeline-container").addClass("hidden"); - } - } - - constructor(mapController: MapController) { - this.mapController = mapController; - this.mapView = this.mapController.mapView; - this.simulation = this.mapController.mapView.simulation; - this.experiments = this.simulation.experiments; - this.taskViewController = new TaskViewController(this); - this.timelineController = new TimelineController(this); - this.chartController = new ChartController(this); - - this.timelineController.setupListeners(); - this.experimentSelectionMode = true; - this.sectionIndex = 0; - - this.currentTick = 1; - this.playing = false; - this.stateCache = new StateCache(this); - this.colorRepresentation = ColorRepresentation.LOAD; - - this.traces = []; - this.schedulers = []; - - this.mapController.api.getAllTraces().then((data) => { - this.traces = data; - }); - - this.mapController.api.getAllSchedulers().then((data) => { - this.schedulers = data; - }); - } - - public enterMode() { - this.experimentSelectionMode = true; - - if (this.mapController.interactionLevel === InteractionLevel.BUILDING) { - this.mapView.roomLayer.coloringMode = true; - this.mapView.dcObjectLayer.coloringMode = false; - } else if (this.mapController.interactionLevel === InteractionLevel.ROOM || - this.mapController.interactionLevel === InteractionLevel.OBJECT) { - this.mapView.roomLayer.coloringMode = false; - this.mapView.dcObjectLayer.coloringMode = true; - } else if (this.mapController.interactionLevel === InteractionLevel.NODE) { - this.mapController.nodeModeController.goToObjectMode(); - } - - this.mapController.appMode = AppMode.SIMULATION; - this.mapView.dcObjectLayer.detailedMode = false; - this.mapView.gridLayer.setVisibility(false); - this.mapView.updateScene = true; - - this.mapController.setAllMenuModes(); - SimulationController.showOrHideSimComponents(true); - $(".mode-switch").attr("data-selected", "simulation"); - $("#save-version-btn").hide(); - $(".color-indicator").removeClass("hidden"); - - $("#change-experiment-btn").click(() => { - this.playing = false; - this.stateCache.stopCaching(); - this.timelineController.update(); - this.showExperimentsDialog(); - }); - - this.setupColorMenu(); - this.showExperimentsDialog(); - } - - private launchSimulation(): void { - this.onSimulationSectionChange(); - - this.chartController.setup(); - - this.stateCache.startCaching(); - - this.tickerId = setInterval(() => { - this.simulationTick(); - }, 1000); - } - - private onSimulationSectionChange(): void { - this.currentSection = this.currentPath.sections[this.sectionIndex]; - this.mapView.currentDatacenter = this.currentSection.datacenter; - - // Generate a map of all rack IDs in relation to their room IDs for use in room stats - this.rackToRoomMap = {}; - this.currentSection.datacenter.rooms.forEach((room: IRoom) => { - room.tiles.forEach((tile: ITile) => { - if (tile.object !== undefined && tile.objectType === "RACK") { - this.rackToRoomMap[tile.objectId] = room.id; - } - }); - }); - - if (this.mapController.interactionLevel === InteractionLevel.NODE) { - this.mapController.nodeModeController.goToObjectMode(); - } - if (this.mapController.interactionLevel === InteractionLevel.OBJECT) { - this.mapController.objectModeController.goToRoomMode(); - } - if (this.mapController.interactionLevel === InteractionLevel.ROOM) { - this.mapController.roomModeController.goToBuildingMode(); - } - - this.mapView.redrawMap(); - - this.mapView.zoomOutOnDC(); - } - - public exitMode() { - this.closeExperimentsDialog(); - - this.mapController.appMode = AppMode.CONSTRUCTION; - this.mapView.dcObjectLayer.detailedMode = true; - this.mapView.gridLayer.setVisibility(true); - this.mapView.redrawMap(); - - this.stateCache.stopCaching(); - this.playing = false; - - this.mapController.setAllMenuModes(); - SimulationController.showOrHideSimComponents(false); - - this.setColors(); - $(".color-indicator").addClass("hidden")["popover"]("hide").off(); - $(".mode-switch").attr("data-selected", "construction"); - $("#save-version-btn").show(); - - clearInterval(this.tickerId); - } - - public update() { - if (this.stateCache.cacheBlock) { - return; - } - - this.setColors(); - this.updateBuildingStats(); - this.updateRoomStats(); - this.chartController.update(); - this.taskViewController.update(); - } - - public simulationTick(): void { - this.timelineController.update(); - - if (this.currentTick > this.lastSimulatedTick) { - this.currentTick = this.lastSimulatedTick; - this.playing = false; - this.timelineController.setButtonIcon(); - } - - if (this.playing) { - this.checkCurrentSimulationSection(); - this.update(); - - if (!this.stateCache.cacheBlock) { - this.currentTick++; - } - } - } - - public checkCurrentSimulationSection(): void { - for (let i = this.sections.length - 1; i >= 0; i--) { - if (this.currentTick >= this.sections[i].startTick) { - if (this.sectionIndex !== i) { - this.sectionIndex = i; - this.onSimulationSectionChange(); - } - break; - } - } - } - - public transitionFromBuildingToRoom(): void { - this.mapView.roomLayer.coloringMode = false; - this.mapView.dcObjectLayer.coloringMode = true; - - this.setColors(); - this.updateRoomStats(); - this.chartController.update(); - } - - public transitionFromRoomToBuilding(): void { - this.mapView.roomLayer.coloringMode = true; - this.mapView.dcObjectLayer.coloringMode = false; - - this.setColors(); - this.updateBuildingStats(); - this.chartController.update(); - } - - public transitionFromRoomToRack(): void { - this.setColors(); - $("#statistics-menu").addClass("hidden"); - this.chartController.update(); - } - - public transitionFromRackToRoom(): void { - this.setColors(); - $("#statistics-menu").removeClass("hidden"); - } - - public transitionFromRackToNode(): void { - this.chartController.update(); - } - - public transitionFromNodeToRack(): void { - } - - private showExperimentsDialog(): void { - $(".experiment-name-alert").hide(); - - this.populateExperimentsList(); - this.populateDropdowns(); - - $(".experiment-row").click((event: JQueryEventObject) => { - if ($(event.target).hasClass("remove-experiment")) { - return; - } - - const row = $(event.target).closest(".experiment-row"); - this.prepareAndLaunchExperiment(this.experiments[row.index()]); - }); - - $(".experiment-list .list-body").on("click", ".remove-experiment", (event: JQueryEventObject) => { - event.stopPropagation(); - const affectedRow = $(event.target).closest(".experiment-row"); - const index = affectedRow.index(); - const affectedExperiment = this.experiments[index]; - - MapController.showConfirmDeleteDialog("experiment", () => { - this.mapController.api.deleteExperiment(affectedExperiment.simulationId, affectedExperiment.id) - .then(() => { - this.experiments.splice(index, 1); - this.populateExperimentsList(); - }); - }); - }); - - let newExperimentBtn = $("#new-experiment-btn"); - // Remove previously added event handlers - newExperimentBtn.off(); - - newExperimentBtn.click(() => { - const nameInput = $("#new-experiment-name-input"); - if (nameInput.val() === "") { - $(".experiment-name-alert").show(); - return; - } else { - $(".experiment-name-alert").hide(); - } - - const newExperiment: IExperiment = { - id: -1, - name: nameInput.text(), - pathId: parseInt($("#new-experiment-path-select").val()), - schedulerName: $("#new-experiment-scheduler-select").val(), - traceId: parseInt($("#new-experiment-trace-select").val()), - simulationId: this.simulation.id - }; - - this.mapController.api.addExperimentToSimulation(this.simulation.id, newExperiment) - .then((data: IExperiment) => { - this.simulation.experiments.push(data); - this.prepareAndLaunchExperiment(data); - }); - }); - - $(".window-close").click(() => { - this.exitMode(); - }); - - $(".window-overlay").fadeIn(200); - } - - private prepareAndLaunchExperiment(experiment: IExperiment): void { - this.prepareSimulationData(experiment); - this.launchSimulation(); - this.closeExperimentsDialog(); - } - - private prepareSimulationData(experiment: IExperiment): void { - this.currentExperiment = experiment; - this.currentPath = this.getPathById(this.currentExperiment.pathId); - this.sections = this.currentPath.sections; - this.sectionIndex = 0; - this.currentTick = 1; - this.playing = false; - this.stateCache = new StateCache(this); - this.colorRepresentation = ColorRepresentation.LOAD; - - this.sections.sort((a: ISection, b: ISection) => { - return a.startTick - b.startTick; - }); - - $("#experiment-menu-name").text(experiment.name); - $("#experiment-menu-path").text(SimulationController.getPathName(this.currentPath)); - $("#experiment-menu-scheduler").text(experiment.schedulerName); - $("#experiment-menu-trace").text(experiment.trace.name); - } - - private closeExperimentsDialog(): void { - $(".window-overlay").fadeOut(200); - $(".window-overlay input").val(""); - } - - private populateDropdowns(): void { - const pathDropdown = $("#new-experiment-path-select"); - const traceDropdown = $("#new-experiment-trace-select"); - const schedulerDropdown = $("#new-experiment-scheduler-select"); - - pathDropdown.empty(); - for (let i = 0; i < this.simulation.paths.length; i++) { - pathDropdown.append( - $("<option>").text(SimulationController.getPathName(this.simulation.paths[i])) - .val(this.simulation.paths[i].id) - ); - } - - traceDropdown.empty(); - for (let i = 0; i < this.traces.length; i++) { - traceDropdown.append( - $("<option>").text(this.traces[i].name) - .val(this.traces[i].id) - ); - } - - schedulerDropdown.empty(); - for (let i = 0; i < this.schedulers.length; i++) { - schedulerDropdown.append( - $("<option>").text(this.schedulers[i].name) - .val(this.schedulers[i].name) - ); - } - } - - /** - * Populates the list of experiments. - */ - private populateExperimentsList(): void { - const table = $(".experiment-list .list-body"); - table.empty(); - - console.log("EXPERIMENT", this.experiments); - console.log("SIMULATION", this.simulation); - - if (this.experiments.length === 0) { - $(".experiment-list").hide(); - $(".no-experiments-alert").show(); - } else { - $(".no-experiments-alert").hide(); - this.experiments.forEach((experiment: IExperiment) => { - table.append( - '<div class="experiment-row">' + - ' <div>' + experiment.name + '</div>' + - ' <div>' + this.getPathNameById(experiment.pathId) + '</div>' + - ' <div>' + experiment.trace.name + '</div>' + - ' <div>' + experiment.schedulerName + '</div>' + - ' <div class="remove-experiment glyphicon glyphicon-remove"></div>' + - '</div>' - ); - }); - } - } - - private getPathNameById(id: number): string { - for (let i = 0; i < this.simulation.paths.length; i++) { - if (id === this.simulation.paths[i].id) { - return SimulationController.getPathName(this.simulation.paths[i]); - } - } - } - - private getPathById(id: number): IPath { - for (let i = 0; i < this.simulation.paths.length; i++) { - if (id === this.simulation.paths[i].id) { - return this.simulation.paths[i]; - } - } - } - - private static getPathName(path: IPath): string { - if (path.name === null) { - return "Path " + path.id; - } else { - return path.name; - } - } - - private setColors() { - if (this.mapController.appMode === AppMode.SIMULATION) { - if (this.mapController.interactionLevel === InteractionLevel.BUILDING) { - this.mapView.roomLayer.intensityLevels = {}; - - this.stateCache.stateList[this.currentTick].roomStates.forEach((roomState: IRoomState) => { - if (this.colorRepresentation === ColorRepresentation.LOAD) { - this.mapView.roomLayer.intensityLevels[roomState.roomId] = - Util.determineLoadIntensityLevel(roomState.loadFraction); - } - }); - - this.mapView.roomLayer.draw(); - this.mapView.dcObjectLayer.draw(); - } else if (this.mapController.interactionLevel === InteractionLevel.ROOM || - this.mapController.interactionLevel === InteractionLevel.OBJECT) { - this.mapView.dcObjectLayer.intensityLevels = {}; - - this.stateCache.stateList[this.currentTick].rackStates.forEach((rackState: IRackState) => { - if (this.colorRepresentation === ColorRepresentation.LOAD) { - this.mapView.dcObjectLayer.intensityLevels[rackState.rackId] = - Util.determineLoadIntensityLevel(rackState.loadFraction); - } - }); - - this.mapView.roomLayer.draw(); - this.mapView.dcObjectLayer.draw(); - } - - if (this.mapController.interactionLevel === InteractionLevel.OBJECT || - this.mapController.interactionLevel === InteractionLevel.NODE) { - this.stateCache.stateList[this.currentTick].machineStates.forEach((machineState: IMachineState) => { - let element = $('.node-element[data-id="' + machineState.machineId + '"] .node-element-content'); - element.css("background-color", Util.convertIntensityToColor( - Util.determineLoadIntensityLevel(machineState.loadFraction) - )); - - // Color all transparent icon overlays, as well - element = $('.node-element[data-id="' + machineState.machineId + '"] .icon-overlay'); - element.css("background-color", Util.convertIntensityToColor( - Util.determineLoadIntensityLevel(machineState.loadFraction) - )); - }); - } - } else { - this.mapView.roomLayer.coloringMode = false; - this.mapView.dcObjectLayer.coloringMode = false; - - this.mapView.roomLayer.draw(); - this.mapView.dcObjectLayer.draw(); - } - } - - /** - * Populates the building simulation menu with dynamic statistics concerning the state of all rooms in the building. - */ - private updateBuildingStats(): void { - if (this.mapController.interactionLevel !== InteractionLevel.BUILDING) { - return; - } - - const container = $(".building-stats-list"); - - container.children().remove("div"); - - this.stateCache.stateList[this.currentTick].roomStates.forEach((roomState: IRoomState) => { - if (this.colorRepresentation === ColorRepresentation.LOAD && roomState.room !== undefined) { - const html = '<div>' + - ' <h4>' + roomState.room.name + '</h4>' + - ' <p>Load: ' + Math.round(roomState.loadFraction * 100) + '%</p>' + - '</div>'; - container.append(html); - } - }); - - } - - /** - * Populates the room simulation menu with dynamic statistics concerning the state of all racks in the room. - */ - private updateRoomStats(): void { - if (this.mapController.interactionLevel !== InteractionLevel.ROOM) { - return; - } - - $("#room-name-field").text(this.mapController.roomModeController.currentRoom.name); - $("#room-type-field").text(this.mapController.roomModeController.currentRoom.roomType); - - const container = $(".room-stats-list"); - - container.children().remove("div"); - - this.stateCache.stateList[this.currentTick].rackStates.forEach((rackState: IRackState) => { - if (this.rackToRoomMap[rackState.rackId] !== this.mapController.roomModeController.currentRoom.id) { - return; - } - if (this.colorRepresentation === ColorRepresentation.LOAD) { - const html = '<div>' + - ' <h4>' + rackState.rack.name + '</h4>' + - ' <p>Load: ' + Math.round(rackState.loadFraction * 100) + '%</p>' + - '</div>'; - container.append(html); - } - }); - } - - private setupColorMenu(): void { - const html = - '<select class="form-control" title="Color Representation" id="color-representation-select">' + - ' <option value="1" selected>Load</option>' + - ' <option value="2">Power use</option>' + - '</select>'; - - const indicator = $(".color-indicator"); - indicator["popover"]({ - animation: true, - content: html, - html: true, - placement: "top", - title: "Colors represent:", - trigger: "manual" - }); - indicator.click(() => { - //noinspection JSJQueryEfficiency // suppressed for dynamic element insertion - if ($("#color-representation-select").length) { - indicator["popover"]("hide"); - } else { - indicator["popover"]("show"); - - const selectElement = $("#color-representation-select"); - selectElement.change(() => { - console.log(selectElement.val()); - }); - } - }); - } -} |
