summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/404.html29
-rw-r--r--src/app.html456
-rw-r--r--src/favicon.icobin99678 -> 0 bytes
-rw-r--r--src/humans.txt27
-rw-r--r--src/img/app/coolingitem.pngbin2853 -> 0 bytes
-rw-r--r--src/img/app/loading.gifbin36550 -> 0 bytes
-rw-r--r--src/img/app/node-cpu.pngbin4062 -> 0 bytes
-rw-r--r--src/img/app/node-gpu.pngbin2227 -> 0 bytes
-rw-r--r--src/img/app/node-memory.pngbin1980 -> 0 bytes
-rw-r--r--src/img/app/node-network.pngbin3058 -> 0 bytes
-rw-r--r--src/img/app/node-storage.pngbin4038 -> 0 bytes
-rw-r--r--src/img/app/psu.pngbin1523 -> 0 bytes
-rw-r--r--src/img/app/rack-energy.pngbin893 -> 0 bytes
-rw-r--r--src/img/app/rack-space.pngbin957 -> 0 bytes
-rw-r--r--src/img/datacenter-drawing.pngbin219576 -> 0 bytes
-rw-r--r--src/img/email-icon.pngbin14761 -> 0 bytes
-rw-r--r--src/img/favicon.pngbin2788 -> 0 bytes
-rw-r--r--src/img/github-icon.pngbin6441 -> 0 bytes
-rw-r--r--src/img/logo.pngbin2825 -> 0 bytes
-rw-r--r--src/img/opendc-splash.pngbin304805 -> 0 bytes
-rw-r--r--src/img/portraits/aiosup.pngbin111629 -> 0 bytes
-rw-r--r--src/img/portraits/gandreadis.pngbin118477 -> 0 bytes
-rw-r--r--src/img/portraits/loverweel.pngbin107768 -> 0 bytes
-rw-r--r--src/img/portraits/mbijman.pngbin111670 -> 0 bytes
-rw-r--r--src/img/stakeholders/Developer.pngbin11411 -> 0 bytes
-rw-r--r--src/img/stakeholders/Manager.pngbin9946 -> 0 bytes
-rw-r--r--src/img/stakeholders/Researcher.pngbin10984 -> 0 bytes
-rw-r--r--src/img/stakeholders/Sales.pngbin10074 -> 0 bytes
-rw-r--r--src/img/stakeholders/Student.pngbin12960 -> 0 bytes
-rw-r--r--src/img/technologies/arrow.pngbin2153 -> 0 bytes
-rw-r--r--src/img/technologies/cogs-icon.pngbin11500 -> 0 bytes
-rw-r--r--src/img/technologies/database-icon.pngbin7848 -> 0 bytes
-rw-r--r--src/img/technologies/webserver-icon.pngbin5762 -> 0 bytes
-rw-r--r--src/img/technologies/www-icon.pngbin11205 -> 0 bytes
-rw-r--r--src/img/tudelfticon.pngbin4387 -> 0 bytes
-rw-r--r--src/index.html413
-rw-r--r--src/navbar.html18
-rw-r--r--src/profile.html62
-rw-r--r--src/projects.html93
-rw-r--r--src/robots.txt4
-rw-r--r--src/scripts/colors.ts43
-rw-r--r--src/scripts/controllers/connection/api.ts1738
-rw-r--r--src/scripts/controllers/connection/cache.ts85
-rw-r--r--src/scripts/controllers/connection/socket.ts76
-rw-r--r--src/scripts/controllers/mapcontroller.ts520
-rw-r--r--src/scripts/controllers/modes/building.ts113
-rw-r--r--src/scripts/controllers/modes/node.ts297
-rw-r--r--src/scripts/controllers/modes/object.ts296
-rw-r--r--src/scripts/controllers/modes/room.ts382
-rw-r--r--src/scripts/controllers/scaleindicator.ts45
-rw-r--r--src/scripts/controllers/simulation/chart.ts241
-rw-r--r--src/scripts/controllers/simulation/statecache.ts321
-rw-r--r--src/scripts/controllers/simulation/taskview.ts64
-rw-r--r--src/scripts/controllers/simulation/timeline.ts161
-rw-r--r--src/scripts/controllers/simulationcontroller.ts586
-rw-r--r--src/scripts/definitions.ts318
-rw-r--r--src/scripts/error404.entry.ts26
-rw-r--r--src/scripts/main.entry.ts69
-rw-r--r--src/scripts/profile.entry.ts40
-rw-r--r--src/scripts/projects.entry.ts651
-rw-r--r--src/scripts/serverconnection.ts59
-rw-r--r--src/scripts/splash.entry.ts157
-rw-r--r--src/scripts/tests/util.spec.ts326
-rw-r--r--src/scripts/user-authentication.ts65
-rw-r--r--src/scripts/util.ts613
-rw-r--r--src/scripts/views/layers/dcobject.ts250
-rw-r--r--src/scripts/views/layers/dcprogressbar.ts99
-rw-r--r--src/scripts/views/layers/gray.ts145
-rw-r--r--src/scripts/views/layers/grid.ts59
-rw-r--r--src/scripts/views/layers/hover.ts129
-rw-r--r--src/scripts/views/layers/layer.ts8
-rw-r--r--src/scripts/views/layers/room.ts177
-rw-r--r--src/scripts/views/layers/roomtext.ts68
-rw-r--r--src/scripts/views/layers/wall.ts62
-rw-r--r--src/scripts/views/mapview.ts373
-rw-r--r--src/styles/404.less147
-rw-r--r--src/styles/main.less1196
-rw-r--r--src/styles/navbar.less158
-rw-r--r--src/styles/profile.less22
-rw-r--r--src/styles/projects.less391
-rw-r--r--src/styles/splash.less440
-rw-r--r--src/unit-tests.html15
82 files changed, 0 insertions, 12133 deletions
diff --git a/src/404.html b/src/404.html
deleted file mode 100644
index 10f79525..00000000
--- a/src/404.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <title>404 Error | OpenDC</title>
-
- <link href="styles/404.css" rel="stylesheet" type="text/css">
-
- <!-- Favicon -->
- <link href="img/logo.png" rel="icon">
-</head>
-<body>
-<div class="terminal-window">
- <div class="terminal-header">Terminal -- bash</div>
- <div class="terminal-body">
- <div class="segfault">$ status <br>
- opendc[4264]: segfault at 0000051497be459d1 err 12 in libopendc.9.0.4<br>
- opendc[4269]: segfault at 000004234855fc2db err 3 in libopendc.9.0.4<br>
- opendc[4270]: STDERR Page does not exist
- </div>
- <div class="code-block"></div>
- <div class="sub-title">Got lost?<span class="cursor">_</span></div>
- <a class="home-btn" href="SERVER_BASE_URL">GET ME BACK TO OPENDC</a>
- </div>
-</div>
-
-<script src="scripts/error404.entry.js"></script>
-</body>
-</html>
diff --git a/src/app.html b/src/app.html
deleted file mode 100644
index 5b669910..00000000
--- a/src/app.html
+++ /dev/null
@@ -1,456 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta name="google-signin-client_id" content="OAUTH_CLIENT_ID">
-
- <title>OpenDC</title>
-
- <link href="bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
- <link href="bower_components/c3/c3.min.css" rel="stylesheet">
-
- <link href="styles/navbar.css" rel="stylesheet" type="text/css">
- <link href="styles/main.css" rel="stylesheet" type="text/css">
-
- <link href="img/logo.png" rel="icon">
-</head>
-<body>
-<!-- build:include navbar.html -->
-<!-- /build -->
-<div class="app-content">
- <!-- The main map canvas (the dimensions given are fallbacks, for when dynamic resizing doesn't work)-->
- <canvas id="main-canvas" width="800" height="600">
- Sorry, but it seems your browser does not support the HTML5 canvas.
- </canvas>
-
- <div class="side-menu-container right-middle-side">
- <div class="menu-container level-menu hidden" id="node-menu">
- <div class="menu-header-bar">
- Node
- <button class="menu-exit btn btn-default btn-circle">
- <i class="glyphicon glyphicon-remove"></i>
- </button>
- <button class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body construction">
- <ul class="nav nav-tabs">
- <li class="active">
- <a data-toggle="tab" href="#cpu-tab">
- <img src="img/app/node-cpu.png" alt="CPU tab">
- </a>
- </li>
- <li>
- <a data-toggle="tab" href="#gpu-tab">
- <img src="img/app/node-gpu.png" alt="GPU tab">
- </a>
- </li>
- <li>
- <a data-toggle="tab" href="#memory-tab">
- <img src="img/app/node-memory.png" alt="Memory unit tab">
- </a>
- </li>
- <li>
- <a data-toggle="tab" href="#storage-tab">
- <img src="img/app/node-storage.png" alt="Storage unit tab">
- </a>
- </li>
- <li>
- <a data-toggle="tab" href="#network-tab">
- <img src="img/app/node-network.png" alt="Network unit tab">
- </a>
- </li>
- </ul>
- <div class="tab-content">
- <div id="cpu-tab" class="tab-pane fade in active">
- <h3>CPUs</h3>
- <h4>Add a new CPU</h4>
- <div class="unit-add-input input-group" id="add-cpu-form">
- <select class="form-control" title="Generation">
- <!-- Populated at runtime with a list of available units -->
- </select>
- <span class="input-group-btn"><button class="btn btn-default add-unit">Add</button></span>
- </div>
- <div class="panel-group" id="cpu-accordion">
- <!-- Populated at runtime with CPU info -->
- </div>
- </div>
- <div id="gpu-tab" class="tab-pane fade">
- <h3>GPUs</h3>
- <h4>Add a new GPU</h4>
- <div class="unit-add-input input-group" id="add-gpu-form">
- <select class="form-control" title="Generation">
- <!-- Populated at runtime with a list of available units -->
- </select>
- <span class="input-group-btn"><button class="btn btn-default add-unit">Add</button></span>
- </div>
- <div class="panel-group" id="gpu-accordion">
- <!-- Populated at runtime with GPU info -->
- </div>
- </div>
- <div id="memory-tab" class="tab-pane fade">
- <h3>Memory Units</h3>
- <h4>Add a new memory unit</h4>
- <div class="unit-add-input input-group" id="add-memory-form">
- <select class="form-control" title="Generation">
- <!-- Populated at runtime with a list of available units -->
- </select>
- <span class="input-group-btn"><button class="btn btn-default add-unit">Add</button></span>
- </div>
- <div class="panel-group" id="memory-accordion">
- <!-- Populated at runtime with memory info -->
- </div>
- </div>
- <div id="storage-tab" class="tab-pane fade">
- <h3>Storage Units</h3>
- <h4>Add a new storage unit</h4>
- <div class="unit-add-input input-group" id="add-storage-form">
- <select class="form-control" title="Generation">
- <!-- Populated at runtime with a list of available units -->
- </select>
- <span class="input-group-btn"><button class="btn btn-default add-unit">Add</button></span>
- </div>
- <div class="panel-group" id="storage-accordion">
- <!-- Populated at runtime with storage info -->
- </div>
- </div>
- <div id="network-tab" class="tab-pane fade">
- <h3>Network cards</h3>
- <div>This machine has a standard, industry-grade network unit</div>
- </div>
- </div>
- </div>
- <div class="menu-body simulation">
- <div id="machine-statistics-chart"></div>
- </div>
- </div>
- </div>
-
- <div class="side-menu-container right-side">
- <div class="menu-container level-menu" id="building-menu">
- <div class="menu-header-bar">
- Building
- <button type="button" class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body construction">
- <div class="btn btn-primary btn-block" id="room-construction">
- Construct new room
- </div>
- <div class="btn btn-default btn-block" id="room-construction-cancel">
- Cancel
- </div>
- </div>
- <div class="menu-body simulation">
- <div class="building-stats-list">
- <!-- Populated at runtime with dynamic simulation stats -->
- </div>
- </div>
- </div>
-
- <div class="menu-container level-menu hidden" id="room-menu">
- <div class="menu-header-bar">
- Room
- <button type="button" class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body construction">
- <div class="input-group">
- <input type="text" class="form-control" id="room-name-input" placeholder="Room name...">
- <span class="input-group-btn"><button class="btn btn-default" id="room-name-save"
- type="button">Save</button></span>
- </div>
- <div class="input-group">
- <div class="input-group-addon">Room type:</div>
- <select class="form-control" title="Room Type" id="roomtype-select">
- <!-- Populated at runtime with all available room types -->
- </select>
- </div>
- <label id="add-objects-label">Add objects:</label>
- <div class="dc-component-container hidden" id="add-rack-btn" data-active="false">
- <div class="dc-component dc-rack"></div>
- <div class="dc-component-label">Rack</div>
- </div>
- <div class="dc-component-container hidden" id="add-psu-btn" data-active="false">
- <div class="dc-component dc-psu"></div>
- <div class="dc-component-label">Power Supply Unit</div>
- </div>
- <div class="dc-component-container hidden" id="add-cooling-item-btn" data-active="false">
- <div class="dc-component dc-cooling-item"></div>
- <div class="dc-component-label">Cooling Item</div>
- </div>
- <label class="hidden" id="no-objects-info">
- No objects are allowed in this type of room. <br>
- Change the room type to be able to add elements.
- </label>
- <div class="btn btn-danger btn-block" id="room-deletion">
- Delete this room
- </div>
- </div>
- <div class="menu-body simulation">
- <h3 id="room-name-field"></h3>
- <h5 id="room-type-field"></h5>
- <div class="room-stats-list">
- <!-- Populated at runtime, with simulation stats per rack -->
- </div>
- </div>
- </div>
-
- <div class="menu-container level-menu hidden" id="object-menu">
- <div id="rack-sub-menu" class="object-sub-menu">
- <div class="menu-header-bar">
- Rack
- <button class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body construction">
- <div class="input-group">
- <input type="text" class="form-control" id="rack-name-input" placeholder="Rack name...">
- <span class="input-group-btn"><button class="btn btn-default" id="rack-name-save"
- type="button">Save</button></span>
- </div>
- <div class="node-list-container">
- <!-- Populated at runtime with node data -->
- </div>
- <div class="btn btn-danger btn-block" id="rack-deletion">
- Delete this rack
- </div>
- </div>
- <div class="menu-body simulation">
- <div class="node-list-container">
- <!-- Populated at runtime with node simulation stats -->
- </div>
- </div>
- </div>
- <div id="psu-sub-menu" class="object-sub-menu">
- <div class="menu-header-bar">
- Power Supply Unit
- <button class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body construction">
- <div class="btn btn-danger btn-block" id="psu-deletion">
- Delete this PSU
- </div>
- </div>
- <div class="menu-body simulation">
- </div>
- </div>
- <div id="cooling-item-sub-menu" class="object-sub-menu">
- <div class="menu-header-bar">
- Cooling Item
- <button class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body construction">
- <div class="btn btn-danger btn-block" id="cooling-item-deletion">
- Delete this cooling item
- </div>
- </div>
- <div class="menu-body simulation">
- </div>
- </div>
- </div>
- <div class="menu-container hidden" id="statistics-menu">
- <div class="menu-header-bar">
- Statistics
- <button type="button" class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body simulation">
- <div id="statistics-chart"></div>
- </div>
- </div>
- </div>
-
- <div class="side-menu-container left-side">
- <div class="mode-switch" data-selected="construction" role="group" aria-label="Mode switch">
- <div id="construction-mode-switch">Construction</div>
- <div id="simulation-mode-switch">Simulation</div>
- </div>
- <div id="save-version-btn" data-saved="true">Save version</div>
- <div class="menu-container hidden" id="experiment-menu">
- <div class="menu-header-bar">
- Experiment
- <button type="button" class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body simulation">
- <p><strong>Name:</strong> <span id="experiment-menu-name">Name</span></p>
- <p><strong>Path:</strong> <span id="experiment-menu-path">Path</span></p>
- <p><strong>Trace:</strong> <span id="experiment-menu-trace">Trace</span></p>
- <p><strong>Scheduler:</strong> <span id="experiment-menu-scheduler">Scheduler</span></p>
- <div id="change-experiment-btn" class="btn btn-default btn-block">Change experiment</div>
- </div>
- </div>
- <div class="menu-container hidden" id="tasks-menu">
- <div class="menu-header-bar">
- Tasks
- <button type="button" class="menu-collapse btn btn-default btn-circle">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- </div>
- <div class="menu-body simulation">
- <div class="task-list">
- <!-- Populated at runtime with a number of task elements -->
- </div>
- </div>
- </div>
- </div>
-
- <div class="tool-panel">
- <button type="button" class="btn btn-default btn-circle" id="zoom-plus" title="Zoom in">
- <i class="glyphicon glyphicon-plus"></i>
- </button>
- <button type="button" class="btn btn-default btn-circle" id="zoom-minus" title="Zoom out">
- <i class="glyphicon glyphicon-minus"></i>
- </button>
- <button type="button" class="btn btn-success btn-circle export-canvas" title="Export Canvas to PNG Image">
- <i class="glyphicon glyphicon-camera"></i>
- </button>
- </div>
-
- <!-- Map indicators -->
- <div class="indicators">
- <div class="scale-indicator">
- 0.5m
- </div>
- <div class="color-indicator hidden">
- <div class="intensity-labels">
- <div>0</div>
- <div>25</div>
- <div>50</div>
- <div>75</div>
- <div>100</div>
- </div>
- <div class="intensity-colors">
- <div class="intensity-low"></div>
- <div class="intensity-mid-low"></div>
- <div class="intensity-mid-high"></div>
- <div class="intensity-high"></div>
- </div>
- </div>
- </div>
-
- <!-- Timeline bar, for simulation playback -->
- <div class="timeline-bar">
- <div class="timeline-container hidden">
- <div class="labels">
- <div class="start-time-label">00:00:00</div>
- <div class="end-time-label">00:00:00</div>
- </div>
- <div class="controls">
- <div class="play-btn glyphicon glyphicon-play"><img src="img/app/loading.gif"></div>
- <div class="timeline">
- <div class="cache-section"></div>
- <div class="time-marker"></div>
- </div>
- </div>
- </div>
- </div>
-
- <!-- Informational Balloon Popup -->
- <div class="info-balloon">
- <span></span>Test Info
- </div>
-
- <!-- Overlay for DC loading process -->
- <div class="loading-overlay">
- <div class="loading-overlay-content">
- <img src="img/logo.png">
- <div class="loading-text">
- <h3>Loading your project...</h3>
- <p class="muted">Fetching the DC</p>
- </div>
- </div>
- </div>
-</div>
-
-<div class="modal fade" id="confirm-delete" tabindex="-1" role="dialog" aria-labelledby="confirm-delete-header">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
- aria-hidden="true">&times;</span></button>
- <h4 class="modal-title" id="confirm-delete-header">Confirm delete</h4>
- </div>
- <div class="modal-body">
- Are you sure you want to delete this item?
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
- <button type="button" class="btn btn-danger confirm">Delete</button>
- </div>
- </div>
- </div>
-</div>
-
-<div class="window-overlay">
- <div class="experiments-window" id="experiments-window">
- <div class="window-close glyphicon glyphicon-remove"></div>
- <div class="window-body">
- <div class="window-heading">Experiments</div>
- <form class="form-inline experiment-add-form">
- <div class="form-group">
- <label for="new-experiment-name-input">Name</label>
- <input type="text" class="form-control" id="new-experiment-name-input"
- placeholder="Experiment name">
- <label for="new-experiment-path-select">Path</label>
- <select class="form-control" id="new-experiment-path-select">
- </select>
- </div>
- <div class="form-group">
- <label for="new-experiment-trace-select">Trace</label>
- <select class="form-control" id="new-experiment-trace-select">
- </select>
- <label for="new-experiment-scheduler-select">Scheduler</label>
- <select class="form-control" id="new-experiment-scheduler-select">
- </select>
- <div class="btn btn-default" id="new-experiment-btn">Save &amp; Launch</div>
- </div>
- </form>
- <strong class="experiments-table-label">Previous Experiments</strong>
- <div class="experiment-list">
- <div class="list-head">
- <div>Name</div>
- <div>Path</div>
- <div>Trace</div>
- <div>Scheduler</div>
- <div></div>
- </div>
- <div class="list-body">
- </div>
- </div>
- <div class="no-experiments-alert alert alert-info">
- <span class="glyphicon glyphicon-info-sign"></span>
- <strong>No experiments here yet...</strong> Add some with the form above!
- </div>
- <div class="experiment-name-alert alert alert-danger" role="alert">
- <strong>Warning:</strong> Your experiment needs a name!
- </div>
- </div>
- </div>
-</div>
-
-<!-- Bower dependencies that cannot be included via the module system -->
-<script src="bower_components/EaselJS/lib/easeljs-0.8.2.min.js"></script>
-<script src="bower_components/TweenJS/lib/tweenjs-0.6.2.min.js"></script>
-<script src="bower_components/PreloadJS/lib/preloadjs-0.6.2.min.js"></script>
-
-<script src="scripts/main.entry.js"></script>
-
-<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
-
-<!-- Google API -->
-<script src="https://apis.google.com/js/platform.js?onload=gapiSigninButton" async defer></script>
-
-</body>
-</html>
diff --git a/src/favicon.ico b/src/favicon.ico
deleted file mode 100644
index c2f40a0d..00000000
--- a/src/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/src/humans.txt b/src/humans.txt
deleted file mode 100644
index 652f9cd2..00000000
--- a/src/humans.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-/* TEAM */
-Benevolent Dictator for Life: Alexandru Iosup.
-Site: http://www.ds.ewi.tudelft.nl/~iosup/
-Twitter: aiosup.
-Location: Delft, Netherlands.
-
-Backend Engineer: Leon Overweel.
-Site: http://leonoverweel.com/
-Twitter: layon_overwhale.
-Location: Delft, Netherlands.
-
-Frontend Engineer: Georgios Andreadis.
-Site: https://github.com/gandreadis
-Location: Delft, Netherlands.
-
-Simulation Engineer: Matthijs Bijman.
-Site: https://github.com/MDBijman
-Location: Delft, Netherlands.
-
-/* THANKS */
-Executive Producer: Vincent van Beek.
-Executive Producer: Tim Hegeman.
-
-/* SITE */
-Standards: HTML5, CSS3, ES5
-Components: jQuery, Bootstrap, CreateJS, c3.js
-Software: WebStorm, Vim, Visual Studio \ No newline at end of file
diff --git a/src/img/app/coolingitem.png b/src/img/app/coolingitem.png
deleted file mode 100644
index 16c18be0..00000000
--- a/src/img/app/coolingitem.png
+++ /dev/null
Binary files differ
diff --git a/src/img/app/loading.gif b/src/img/app/loading.gif
deleted file mode 100644
index c6394822..00000000
--- a/src/img/app/loading.gif
+++ /dev/null
Binary files differ
diff --git a/src/img/app/node-cpu.png b/src/img/app/node-cpu.png
deleted file mode 100644
index 07cfbd31..00000000
--- a/src/img/app/node-cpu.png
+++ /dev/null
Binary files differ
diff --git a/src/img/app/node-gpu.png b/src/img/app/node-gpu.png
deleted file mode 100644
index 55d4fb05..00000000
--- a/src/img/app/node-gpu.png
+++ /dev/null
Binary files differ
diff --git a/src/img/app/node-memory.png b/src/img/app/node-memory.png
deleted file mode 100644
index 36e8a44e..00000000
--- a/src/img/app/node-memory.png
+++ /dev/null
Binary files differ
diff --git a/src/img/app/node-network.png b/src/img/app/node-network.png
deleted file mode 100644
index 795e173b..00000000
--- a/src/img/app/node-network.png
+++ /dev/null
Binary files differ
diff --git a/src/img/app/node-storage.png b/src/img/app/node-storage.png
deleted file mode 100644
index 7a39cb6f..00000000
--- a/src/img/app/node-storage.png
+++ /dev/null
Binary files differ
diff --git a/src/img/app/psu.png b/src/img/app/psu.png
deleted file mode 100644
index 471af6ee..00000000
--- a/src/img/app/psu.png
+++ /dev/null
Binary files differ
diff --git a/src/img/app/rack-energy.png b/src/img/app/rack-energy.png
deleted file mode 100644
index 1088c61b..00000000
--- a/src/img/app/rack-energy.png
+++ /dev/null
Binary files differ
diff --git a/src/img/app/rack-space.png b/src/img/app/rack-space.png
deleted file mode 100644
index 387d7ea6..00000000
--- a/src/img/app/rack-space.png
+++ /dev/null
Binary files differ
diff --git a/src/img/datacenter-drawing.png b/src/img/datacenter-drawing.png
deleted file mode 100644
index 401168e3..00000000
--- a/src/img/datacenter-drawing.png
+++ /dev/null
Binary files differ
diff --git a/src/img/email-icon.png b/src/img/email-icon.png
deleted file mode 100644
index ced9e175..00000000
--- a/src/img/email-icon.png
+++ /dev/null
Binary files differ
diff --git a/src/img/favicon.png b/src/img/favicon.png
deleted file mode 100644
index 85d74964..00000000
--- a/src/img/favicon.png
+++ /dev/null
Binary files differ
diff --git a/src/img/github-icon.png b/src/img/github-icon.png
deleted file mode 100644
index 1e221600..00000000
--- a/src/img/github-icon.png
+++ /dev/null
Binary files differ
diff --git a/src/img/logo.png b/src/img/logo.png
deleted file mode 100644
index d743038b..00000000
--- a/src/img/logo.png
+++ /dev/null
Binary files differ
diff --git a/src/img/opendc-splash.png b/src/img/opendc-splash.png
deleted file mode 100644
index 99fd8658..00000000
--- a/src/img/opendc-splash.png
+++ /dev/null
Binary files differ
diff --git a/src/img/portraits/aiosup.png b/src/img/portraits/aiosup.png
deleted file mode 100644
index 30de349c..00000000
--- a/src/img/portraits/aiosup.png
+++ /dev/null
Binary files differ
diff --git a/src/img/portraits/gandreadis.png b/src/img/portraits/gandreadis.png
deleted file mode 100644
index 403870fa..00000000
--- a/src/img/portraits/gandreadis.png
+++ /dev/null
Binary files differ
diff --git a/src/img/portraits/loverweel.png b/src/img/portraits/loverweel.png
deleted file mode 100644
index d12a9e86..00000000
--- a/src/img/portraits/loverweel.png
+++ /dev/null
Binary files differ
diff --git a/src/img/portraits/mbijman.png b/src/img/portraits/mbijman.png
deleted file mode 100644
index decf9fdd..00000000
--- a/src/img/portraits/mbijman.png
+++ /dev/null
Binary files differ
diff --git a/src/img/stakeholders/Developer.png b/src/img/stakeholders/Developer.png
deleted file mode 100644
index d2638e6c..00000000
--- a/src/img/stakeholders/Developer.png
+++ /dev/null
Binary files differ
diff --git a/src/img/stakeholders/Manager.png b/src/img/stakeholders/Manager.png
deleted file mode 100644
index 92db7459..00000000
--- a/src/img/stakeholders/Manager.png
+++ /dev/null
Binary files differ
diff --git a/src/img/stakeholders/Researcher.png b/src/img/stakeholders/Researcher.png
deleted file mode 100644
index d87edd39..00000000
--- a/src/img/stakeholders/Researcher.png
+++ /dev/null
Binary files differ
diff --git a/src/img/stakeholders/Sales.png b/src/img/stakeholders/Sales.png
deleted file mode 100644
index 5b7c3a72..00000000
--- a/src/img/stakeholders/Sales.png
+++ /dev/null
Binary files differ
diff --git a/src/img/stakeholders/Student.png b/src/img/stakeholders/Student.png
deleted file mode 100644
index a4900303..00000000
--- a/src/img/stakeholders/Student.png
+++ /dev/null
Binary files differ
diff --git a/src/img/technologies/arrow.png b/src/img/technologies/arrow.png
deleted file mode 100644
index 374f78bf..00000000
--- a/src/img/technologies/arrow.png
+++ /dev/null
Binary files differ
diff --git a/src/img/technologies/cogs-icon.png b/src/img/technologies/cogs-icon.png
deleted file mode 100644
index d19e1c20..00000000
--- a/src/img/technologies/cogs-icon.png
+++ /dev/null
Binary files differ
diff --git a/src/img/technologies/database-icon.png b/src/img/technologies/database-icon.png
deleted file mode 100644
index 26738e76..00000000
--- a/src/img/technologies/database-icon.png
+++ /dev/null
Binary files differ
diff --git a/src/img/technologies/webserver-icon.png b/src/img/technologies/webserver-icon.png
deleted file mode 100644
index c627106e..00000000
--- a/src/img/technologies/webserver-icon.png
+++ /dev/null
Binary files differ
diff --git a/src/img/technologies/www-icon.png b/src/img/technologies/www-icon.png
deleted file mode 100644
index e69a54f2..00000000
--- a/src/img/technologies/www-icon.png
+++ /dev/null
Binary files differ
diff --git a/src/img/tudelfticon.png b/src/img/tudelfticon.png
deleted file mode 100644
index a7a2d56a..00000000
--- a/src/img/tudelfticon.png
+++ /dev/null
Binary files differ
diff --git a/src/index.html b/src/index.html
deleted file mode 100644
index c3df0c02..00000000
--- a/src/index.html
+++ /dev/null
@@ -1,413 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <title>OpenDC</title>
-
- <meta name="description" content="Collaborative Datacenter Simulation and Exploration for Everybody">
- <meta name="author" content="Alexandru Iosup, Leon Overweel, Georgios Andreadis, Matthijs Bijman">
- <meta name="keywords" content="OpenDC, Datacenter, Simulation, Simulator, Collaborative, Distributed, Cluster">
-
- <!-- OpenGraph meta tags -->
- <meta property="og:title" content="OpenDC: Collaborative Datacenter Simulation and Exploration for Everybody">
- <meta property="og:type" content="website">
- <meta property="og:image" content="SERVER_BASE_URL/img/opendc-splash.png">
- <meta property="og:url" content="SERVER_BASE_URL">
- <meta property="og:description"
- content="OpenDC provides collaborative online datacenter modeling, diverse and effective datacenter
- simulation, and exploratory datacenter performance feedback.">
- <meta property="og:locale" content="en_US">
-
- <!-- Google Sign-in -->
- <meta name="google-signin-client_id" content="OAUTH_CLIENT_ID">
-
- <!-- Set viewport -->
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
-
- <!-- Style sheets -->
- <link href="bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
- <link href="styles/splash.css" rel="stylesheet">
-
- <!-- Favicon -->
- <link href="img/logo.png" rel="icon">
-
- <!-- humans.txt -->
- <link type="text/plain" rel="author" href="humans.txt">
-</head>
-<body id="page-top" data-spy="scroll" data-target=".navbar-fixed-top">
-
-<div class="body-wrapper">
-
- <nav class="navbar navbar-inverse navbar-fixed-top navbar-transparent" role="navigation">
- <div class="container">
- <div class="navbar-header page-scroll">
- <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
- <span class="sr-only">Toggle navigation</span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- <a class="navbar-brand page-scroll" href="#page-top">
- <img src="img/logo.png" alt="OpenDC Logo">
- </a>
- </div>
-
- <div class="collapse navbar-collapse">
- <ul class="nav navbar-nav">
- <li class="hidden">
- <a class="page-scroll" href="#page-top"></a>
- </li>
- <li>
- <a class="page-scroll" href="#stakeholders">Stakeholders</a>
- </li>
- <li>
- <a class="page-scroll" href="#modeling">Modeling</a>
- </li>
- <li>
- <a class="page-scroll" href="#simulation">Simulation</a>
- </li>
- <li>
- <a class="page-scroll" href="#technologies">Technologies</a>
- </li>
- <li>
- <a class="page-scroll" href="#team">Team</a>
- </li>
- <li>
- <a class="page-scroll" href="#contact">Contact</a>
- </li>
- </ul>
- <div id="google-signin" class="navbar-right"></div>
- <div class="logged-in navbar-right">
- <a class="projects-btn" href="projects">My Projects</a>
- <a class="sign-out glyphicon glyphicon-off" title="Sign out" href="javascript:void(0)"></a>
- </div>
- </div>
-
- </div>
- </nav>
-
- <section class="header-section">
- <div class="container">
- <div class="jumbotron">
- <h1>Open<span class="dc">DC</span></h1>
- <h2>
- Collaborative Datacenter Simulation and Exploration for Everybody
- </h2>
- </div>
- </div>
- </section>
-
- <section id="intro" class="intro-section">
- <div class="container">
- <div class="row">
- <div class="row pitch-container">
- <div class="col-lg-4 col-md-4 col-sm-4 col-xs-8
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-2 pitch-column">
- <h3>The datacenter (DC) industry...</h3>
- <ul class="info-points">
- <li>Is worth over $15 bn, and growing</li>
- <li>Has many hard-to-grasp concepts</li>
- <li>Needs to become accessible to many</li>
- </ul>
- </div>
- <div class="col-lg-4 col-md-4 col-sm-4 col-xs-8
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-2">
- <img src="img/datacenter-drawing.png" class="col-lg-12 col-md-12 col-sm-12 col-xs-12 dc-image"
- alt="Schematic top-down view on a datacenter">
- <p class="col-lg-12 col-md-12 col-sm-12 col-xs-12 img-source">Image source:
- <a href="http://www.dolphinhosts.co.uk/wp-content/uploads/2013/07/data-centers.gif">
- http://www.dolphinhosts.co.uk/wp-content/uploads/2013/07/data-centers.gif
- </a>
- </p>
- </div>
- <div class="col-lg-4 col-md-4 col-sm-4 col-xs-8
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-2 pitch-column">
- <h3>OpenDC provides...</h3>
- <ul class="info-points">
- <li>Collaborative online DC modeling</li>
- <li>Diverse and effective DC simulation</li>
- <li>Exploratory DC performance feedback</li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <section id="stakeholders" class="stakeholder-section content-section">
- <div class="container">
- <div class="row">
- <div class="col-lg-10 col-md-10 col-sm-10 col-xs-12 col-lg-offset-1 col-md-offset-1 col-sm-offset-1 col-xs-offset-0">
- <h1>Stakeholders</h1>
- <div class="row stakeholder-container">
- <div class="col-lg-4 col-md-4 col-sm-6 col-xs-12">
- <img src="img/stakeholders/Manager.png" class="col-lg-4 col-md-4 col-sm-4 col-xs-2"
- alt="Managers">
- <div class="col-lg-8 col-md-8 col-sm-8 col-xs-10">
- <h3>Managers</h3>
- <p>Seeing is deciding</p>
- </div>
- </div>
- <div class="col-lg-4 col-md-4 col-sm-6 col-xs-12">
- <img src="img/stakeholders/Sales.png" class="col-lg-4 col-md-4 col-sm-4 col-xs-2"
- alt="Sales">
- <div class="col-lg-8 col-md-8 col-sm-8 col-xs-10">
- <h3>Sales</h3>
- <p>Demo concepts</p>
- </div>
- </div>
- <div class="col-lg-4 col-md-4 col-sm-6 col-xs-12">
- <img src="img/stakeholders/Developer.png" class="col-lg-4 col-md-4 col-sm-4 col-xs-2"
- alt="DevOps">
- <div class="col-lg-8 col-md-8 col-sm-8 col-xs-10">
- <h3>DevOps</h3>
- <p>Develop & tune</p>
- </div>
- </div>
- <div class="col-lg-4 col-md-4 col-sm-6 col-xs-12 col-lg-offset-2 col-md-offset-2 col-sm-offset-0 col-xs-offset-0">
- <img src="img/stakeholders/Researcher.png" class="col-lg-4 col-md-4 col-sm-4 col-xs-2"
- alt="Researchers">
- <div class="col-lg-8 col-md-8 col-sm-8 col-xs-10">
- <h3>Researchers</h3>
- <p>Understand & design</p>
- </div>
- </div>
- <div class="col-lg-4 col-md-4 col-sm-6 col-xs-12 col-md-offset-0 col-sm-offset-3 col-xs-offset-0">
- <img src="img/stakeholders/Student.png" class="col-lg-4 col-md-4 col-sm-4 col-xs-2"
- alt="Students">
- <div class="col-lg-8 col-md-8 col-sm-8 col-xs-10">
- <h3>Students</h3>
- <p>Grasp complex concepts</p>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <section id="modeling" class="modeling-section content-section">
- <div class="container">
- <div class="row">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h1>Datacenter Modeling</h1>
- <div class="row">
- <div class="col-lg-5 col-md-5 col-sm-5 col-xs-12 text-left">
- <strong class="info-points">Collaboratively...</strong>
- <ul class="info-points key-points">
- <li>Model DC layout, and room locations and types</li>
- <li>Place racks in rooms and nodes in racks</li>
- <li>Add real-world CPU, GPU, memory, storage and network units to each node</li>
- <li>Select from diverse scheduling policies</li>
- </ul>
- </div>
-
-
- <div class="col-lg-7 col-md-7 col-sm-7 col-xs-12">
- <img src="https://github.com/atlarge-research/opendc/raw/master/images/opendc-frontend-construction.PNG" class="col-lg-12 col-md-12 col-sm-12 col-xs-10
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-1"
- alt="Mockup of the datacenter construction interface">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 img-caption">
- Mockup of the datacenter construction interface
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <section id="simulation" class="simulation-section content-section">
- <div class="container">
- <div class="row">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h1>Datacenter Simulation</h1>
- <div class="row simulation-building-row">
- <div class="col-lg-5 col-md-5 col-sm-5 col-xs-12 text-left">
- <strong class="info-points">Working with OpenDC:</strong>
- <ul class="info-points key-points">
- <li>Seamlessly switch between construction and simulation modes
- <li>Choose one of several predefined workloads (Big Data, Bag of Tasks,
- Hadoop, etc.)
- <li>Play, pause, and skip around the informative simulation timeline
- <li>Visualize and demo live
- </ul>
- </div>
- <div class="col-lg-7 col-md-7 col-sm-7 col-xs-12">
- <img src="https://github.com/atlarge-research/opendc/raw/master/images/opendc-frontend-simulation.PNG" class="col-lg-12 col-md-12 col-sm-12 col-xs-10
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-1"
- alt="Mockup of the datacenter simulation interface at room level">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 img-caption">
- Mockup of the datacenter simulation interface at room level
- </div>
- </div>
- </div>
- <div class="row">
- <div class="col-lg-5 col-md-5 col-sm-5 col-xs-12 text-left">
- <strong class="info-points">Key features:</strong>
- <ul class="info-points key-points">
- <li>Live load or power use metrics on building, room, and rack levels
- <li>Diverse scenarios from common operation to model-based failures
- <li>Retrospective performance review of datacenter simulations
- <li>Compare resource management practices
- </ul>
- </div>
- <div class="col-lg-7 col-md-7 col-sm-7 col-xs-12">
- <img src="https://github.com/atlarge-research/opendc/raw/master/images/opendc-frontend-simulation-zoom.PNG" class="col-lg-12 col-md-12 col-sm-12 col-xs-10
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-1"
- alt="Mockup of the same simulation at node level">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 img-caption">
- Mockup of the same simulation at node level
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <section id="technologies" class="technologies-section content-section">
- <div class="container">
- <div class="row">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h1>Technologies</h1>
- <div class="tech-rows row col-lg-6 col-md-6 col-sm-12 col-xs-12
- col-lg-offset-3 col-md-offset-3 col-sm-offset-0 col-xs-offset-0">
- <div class="browser-tech tech-row row">
- <img src="img/technologies/www-icon.png" class="col-lg-2 col-md-2 col-sm-2 col-xs-2"
- alt="Web browser">
- <div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 text-left">
- <h3>Browser</h3>
- <p class="info-points">HTML5 canvas, CreateJS, TypeScript, SocketIO</p>
- </div>
- </div>
- <div class="server-tech tech-row row">
- <img src="img/technologies/webserver-icon.png" class="col-lg-2 col-md-2 col-sm-2 col-xs-2"
- alt="Web Server">
- <div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 text-left">
- <h3>Web Server</h3>
- <p class="info-points">Python, Flask, FlaskSocketIO, OpenAPI</p>
- </div>
- </div>
- <div class="database-tech tech-row row">
- <img src="img/technologies/database-icon.png" class="col-lg-2 col-md-2 col-sm-2 col-xs-2"
- alt="Database">
- <div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 text-left">
- <h3>Database</h3>
- <p class="info-points">SQLite</p>
- </div>
- </div>
- <div class="simulator-tech tech-row row">
- <img src="img/technologies/cogs-icon.png" class="col-lg-2 col-md-2 col-sm-2 col-xs-2"
- alt="Simulator">
- <div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 text-left">
- <h3>Simulator</h3>
- <p class="info-points">C++</p>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <section id="team" class="team-section content-section">
- <div class="container">
- <div class="row">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h1 class="col-lg-12 col-md-12 col-sm-12 col-xs-12 row">The Team</h1>
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 row">
- <div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
- <img src="img/portraits/aiosup.png" class="col-lg-12 col-md-12 col-sm-12 col-xs-6
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-3">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h3>Prof. dr. ir. Alexandru Iosup</h3>
- <div class="team-member-description">
- Project Lead
- </div>
- </div>
- </div>
- <div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
- <img src="img/portraits/loverweel.png" class="col-lg-12 col-md-12 col-sm-12 col-xs-6
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-3">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h3>Leon Overweel</h3>
- <div class="team-member-description">
- Product Lead and Software Engineer responsible for the web server, database, and
- API
- specification
- </div>
- </div>
- </div>
- <div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
- <img src="img/portraits/gandreadis.png" class="col-lg-12 col-md-12 col-sm-12 col-xs-6
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-3">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h3>Georgios Andreadis</h3>
- <div class="team-member-description">
- Software Engineer responsible for the frontend web application and splash page
- </div>
- </div>
- </div>
- <div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
- <img src="img/portraits/mbijman.png" class="col-lg-12 col-md-12 col-sm-12 col-xs-6
- col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-3">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h3>Matthijs Bijman</h3>
- <div class="team-member-description">
- Software Engineer responsible for the datacenter simulator
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <section id="contact" class="contact-section content-section">
- <div class="container">
- <div class="row">
- <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
- <h1>Contact</h1>
- <div class="row">
- <img src="img/tudelfticon.png" class="col-lg-2 col-md-2 col-sm-3 col-xs-6
- col-lg-offset-4 col-md-offset-4 col-sm-offset-3 col-xs-offset-3 tudelft-icon"
- alt="TU Delft Logo">
- <div class="col-lg-4 col-md-5 col-sm-6 col-xs-10 col-lg-offset-0 col-md-offset-0 col-sm-offset-0 col-xs-offset-1 text-left">
- <div class="row vcenter">
- <img src="img/email-icon.png" class="col-lg-2 col-md-2 col-sm-2 col-xs-2"
- alt="Email Icon">
- <div class="info-points col-lg-10 col-md-10 col-sm-10 col-xs-10">
- <a href="mailto:opendc@atlarge-research.com">opendc@atlarge-research.com</a>
- </div>
- </div>
- <div class="row vcenter">
- <img src="img/github-icon.png" class="col-lg-2 col-md-2 col-sm-2 col-xs-2"
- alt="Github Icon">
- <div class="info-points col-lg-10 col-md-10 col-sm-10 col-xs-10">
- <a href="https://github.com/atlarge-research/opendc">atlarge-research/opendc</a>
- </div>
- </div>
- </div>
- </div>
- <div class="atlarge-footer row">
- A project by the <a href="http://atlarge-research.com"><strong>@Large Research Group</strong></a>.
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <script src="scripts/splash.entry.js"></script>
-
- <!-- Bower dependencies -->
- <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
-
- <!-- Google API -->
- <script src="https://apis.google.com/js/platform.js?onload=renderButton" async defer></script>
-
-</div>
-
-</body>
-</html>
diff --git a/src/navbar.html b/src/navbar.html
deleted file mode 100644
index 92c79000..00000000
--- a/src/navbar.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<nav class="top-navbar">
- <a class="opendc-brand" href="/">
- <img src="img/logo.png" alt="OpenDC Logo">
- <div class="opendc-title">Open<strong>DC</strong></div>
- </a>
- <div class="navigation navbar-button-group">
- <a class="projects" title="Projects" href="projects">Projects</a>
- </div>
- <div class="user navbar-button-group">
- <a class="support glyphicon glyphicon-question-sign" title="Support"
- href="mailto:opendc.tudelft@gmail.com?Subject=OpenDC%20Support"></a>
- <a class="username" title="My Profile" href="profile">Profile</a>
- <a class="sign-out glyphicon glyphicon-off" title="Sign out" href="javascript:void(0)"></a>
- </div>
-
- <!--Hidden Google signin button for authentication-->
- <div id="google-signin" class="navbar-right"></div>
-</nav> \ No newline at end of file
diff --git a/src/profile.html b/src/profile.html
deleted file mode 100644
index 1cdb560b..00000000
--- a/src/profile.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta name="google-signin-client_id" content="OAUTH_CLIENT_ID">
-
- <title>OpenDC - Profile</title>
-
- <link href="bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
-
- <link href="styles/navbar.css" rel="stylesheet">
- <link href="styles/profile.css" rel="stylesheet">
-
- <link href="img/logo.png" rel="icon">
-</head>
-<body>
-<!-- build:include navbar.html -->
-<!-- /build -->
-<div class="content">
- <div class="main-body profile-page">
- <h2>Profile Settings</h2>
- <div id="delete-account" class="btn btn-danger">Delete my account on OpenDC</div>
- <div class="delete-info">This does not delete your Google account, it simply disconnects it from the OpenDC app
- and deletes any datacenter info that is associated with you (simulation projects you own, and any
- authorizations you may have on other projects).
- </div>
- <div class="account-delete-alert alert alert-danger" role="alert">
- <strong>Oops!</strong> Something went wrong while attempting to delete your account, here is the message:
- <code></code>
- </div>
- </div>
-</div>
-
-<div class="modal fade" id="confirm-delete-account" tabindex="-1" role="dialog" aria-labelledby="confirm-delete-header">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
- aria-hidden="true">&times;</span></button>
- <h4 class="modal-title" id="confirm-delete-header">Confirm account deletion</h4>
- </div>
- <div class="modal-body">
- Are you really sure you want us to delete your account? This action <strong>can not</strong> be undone.
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
- <button type="button" class="btn btn-danger confirm">Delete my account</button>
- </div>
- </div>
- </div>
-</div>
-
-<script src="scripts/profile.entry.js"></script>
-
-<!-- Bower dependencies -->
-<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
-
-<!-- Google API -->
-<script src="https://apis.google.com/js/platform.js?onload=gapiSigninButton" async defer></script>
-
-</body>
-</html>
diff --git a/src/projects.html b/src/projects.html
deleted file mode 100644
index 6c5effb7..00000000
--- a/src/projects.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta name="google-signin-client_id" content="OAUTH_CLIENT_ID">
-
- <title>OpenDC - Projects</title>
-
- <link href="bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
-
- <link href="styles/navbar.css" rel="stylesheet">
- <link href="styles/projects.css" rel="stylesheet">
-
- <link href="img/logo.png" rel="icon">
-</head>
-<body>
-
-<!-- build:include navbar.html -->
-<!-- /build -->
-
-<div class="content">
- <div class="main-body">
- <div class="filter-menu">
- <div class="project-filters">
- <div class="all-projects active">All Projects</div>
- <div class="my-projects">My Projects</div>
- <div class="shared-projects">Projects shared with me</div>
- </div>
- </div>
- <div class="no-projects-alert alert alert-info">
- <span class="glyphicon glyphicon-info-sign"></span>
- <strong>No projects here yet...</strong> Add some with the 'New Project' button!
- </div>
- <div class="project-list">
- <div class="list-head">
- <div>Project name</div>
- <div>Last edited</div>
- <div>Access rights</div>
- </div>
- <div class="list-body">
- </div>
- </div>
- <div class="new-project-btn"><span class="glyphicon glyphicon-plus"></span> New Project</div>
- </div>
-</div>
-
-<div class="window-overlay">
- <div class="projects-window">
- <div class="window-close glyphicon glyphicon-remove"></div>
- <div class="window-body">
- <div class="window-heading">Edit project</div>
- <form class="form-inline project-name-form">
- <div class="form-group">
- <label for="newProjectNameInput">Name</label>
- <input type="text" class="form-control" id="newProjectNameInput" placeholder="Project name">
- <div class="btn btn-default">Save</div>
- </div>
- </form>
- <strong class="participants-table-label">Participants</strong>
- <div class="participants-table">
- </div>
- <form class="form-inline participant-add-form">
- <div class="form-group">
- <label for="participantAddInput" class="glyphicon glyphicon-plus"></label>
- <input type="email" class="form-control" id="participantAddInput"
- placeholder="Add a participant (by email)">
- <div class="btn btn-default">Add</div>
- </div>
- </form>
- <div class="participant-email-alert alert alert-danger" role="alert">
- <strong>Warning:</strong> We couldn't find that email in our database. Misspelled something?
- </div>
- <div class="project-name-alert alert alert-danger" role="alert">
- <strong>Warning:</strong> Your project needs a name!
- </div>
- </div>
- <div class="window-footer">
- <div class="project-open-btn btn btn-primary pull-left">Open</div>
- <div class="project-create-open-btn btn btn-primary pull-left">Create & Open</div>
- <div class="project-create-btn btn btn-info pull-left">Create</div>
- <div class="project-delete-btn btn btn-danger pull-right">Delete</div>
- <div class="project-cancel-btn btn btn-default pull-right">Cancel</div>
- </div>
- </div>
-</div>
-
-<script src="scripts/projects.entry.js"></script>
-
-<!-- Google API -->
-<script src="https://apis.google.com/js/platform.js?onload=gapiSigninButton" async defer></script>
-
-</body>
-</html>
diff --git a/src/robots.txt b/src/robots.txt
deleted file mode 100644
index 2329e38e..00000000
--- a/src/robots.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-User-agent: *
-Disallow: /app.html
-Disallow: /profile.html
-Disallow: /projects.html \ No newline at end of file
diff --git a/src/scripts/colors.ts b/src/scripts/colors.ts
deleted file mode 100644
index 559b7ee3..00000000
--- a/src/scripts/colors.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Class serving as a color palette for the application.
- */
-export class Colors {
- public static GRID_COLOR = "rgba(0, 0, 0, 0.5)";
-
- public static WALL_COLOR = "rgba(0, 0, 0, 1)";
-
- public static ROOM_DEFAULT = "rgba(150, 150, 150, 1)";
- public static ROOM_SELECTED = "rgba(51, 153, 255, 1)";
- public static ROOM_HOVER_VALID = "rgba(51, 153, 255, 0.5)";
- public static ROOM_HOVER_INVALID = "rgba(255, 102, 0, 0.5)";
- public static ROOM_NAME_COLOR = "rgba(245, 245, 245, 1)";
- public static ROOM_TYPE_COLOR = "rgba(245, 245, 245, 1)";
-
- public static RACK_BACKGROUND = "rgba(170, 170, 170, 1)";
- public static RACK_BORDER = "rgba(0, 0, 0, 1)";
- public static RACK_SPACE_BAR_BACKGROUND = "rgba(222, 235, 247, 1)";
- public static RACK_SPACE_BAR_FILL = "rgba(91, 155, 213, 1)";
- public static RACK_ENERGY_BAR_BACKGROUND = "rgba(255, 242, 204, 1)";
- public static RACK_ENERGY_BAR_FILL = "rgba(255, 192, 0, 1)";
-
- public static COOLING_ITEM_BACKGROUND = "rgba(40, 50, 230, 1)";
- public static COOLING_ITEM_BORDER = "rgba(0, 0, 0, 1)";
-
- public static PSU_BACKGROUND = "rgba(230, 50, 60, 1)";
- public static PSU_BORDER = "rgba(0, 0, 0, 1)";
-
- public static GRAYED_OUT_AREA = "rgba(0, 0, 0, 0.6)";
-
- public static INFO_BALLOON_INFO = "rgba(40, 50, 230, 1)";
- public static INFO_BALLOON_WARNING = "rgba(230, 60, 70, 1)";
-
- public static INFO_BALLOON_MAP = {
- "info": Colors.INFO_BALLOON_INFO,
- "warning": Colors.INFO_BALLOON_WARNING
- };
-
- public static SIM_LOW = "rgba(197, 224, 180, 1)";
- public static SIM_MID_LOW = "rgba(255, 230, 153, 1)";
- public static SIM_MID_HIGH = "rgba(248, 203, 173, 1)";
- public static SIM_HIGH = "rgba(249, 165, 165, 1)";
-}
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());
- });
- }
- });
- }
-}
diff --git a/src/scripts/definitions.ts b/src/scripts/definitions.ts
deleted file mode 100644
index e187af09..00000000
--- a/src/scripts/definitions.ts
+++ /dev/null
@@ -1,318 +0,0 @@
-/**
- * JSON Specification of the data model.
- *
- * Represents the data model after populating it (based on the DB ideas retrieved from the backend). Unpopulated
- * objects end with 'Stub'.
- */
-
-// Webpack require declaration
-//declare var require: {
-// <T>(path: string): T;
- // (paths: string[], callback: (...modules: any[]) => void): void;
- //ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
-//};
-
-// Meta-constructs
-interface IDateTime {
- year: number;
- month: number;
- day: number;
- hour: number;
- minute: number;
- second: number;
-}
-
-interface IGridPosition {
- x: number;
- y: number;
-}
-
-interface IBounds {
- min: number[];
- center: number[];
- max: number[];
-}
-
-interface IRoomNamePos {
- topLeft: IGridPosition;
- length: number;
-}
-
-interface IRoomWall {
- startPos: number[];
- horizontal: boolean;
- length: number;
-}
-
-interface TilePositionObject {
- position: IGridPosition;
- tileObject: createjs.Shape;
-}
-
-type IRoomTypeMap = { [key: string]: string[]; };
-
-interface ITickState {
- tick: number;
- roomStates: IRoomState[];
- rackStates: IRackState[];
- machineStates: IMachineState[];
- taskStates: ITaskState[];
-}
-
-// Communication
-interface IRequest {
- id?: number;
- path: string;
- method: string;
- parameters: {
- body: any;
- path: any;
- query: any;
- };
- token?: string;
-}
-
-interface IResponse {
- id?: number;
- status: {
- code: number;
- description?: string;
- };
- content: any;
-}
-
-// Simulation
-interface ISimulation {
- id: number;
- name: string;
- paths?: IPath[];
- experiments?: IExperiment[];
- datetimeCreated: string;
- datetimeCreatedParsed?: IDateTime;
- datetimeLastEdited: string;
- datetimeLastEditedParsed?: IDateTime;
-}
-
-interface ISection {
- id: number;
- startTick: number;
- simulationId: number;
- datacenterId: number;
- datacenter?: IDatacenter;
-}
-
-interface IPath {
- id: number;
- simulationId: number;
- sections?: ISection[];
- name: string;
- datetimeCreated: string;
-}
-
-interface ITrace {
- id: number;
- name: string;
- tasks?: ITask[];
-}
-
-interface IScheduler {
- name: string;
-}
-
-interface ITask {
- id: number;
- traceId: number;
- queueEntryTick: number;
- startTick?: number;
- finishedTick?: number;
- totalFlopCount: number;
-}
-
-interface IExperiment {
- id: number;
- simulationId: number;
- pathId: number;
- traceId: number;
- trace?: ITrace;
- schedulerName: string;
- name: string;
-}
-
-// Authorization
-interface IAuthorization {
- userId: number;
- user?: IUser;
- simulationId: number;
- simulation?: ISimulation;
- authorizationLevel: string;
-}
-
-interface IUser {
- id: number;
- googleId: number;
- email: string;
- givenName: string;
- familyName: string;
-}
-
-// DC Layout
-interface IDatacenter {
- id: number;
- rooms?: IRoom[];
-}
-
-interface IRoom {
- id: number;
- datacenterId: number;
- name: string;
- roomType: string;
- tiles?: ITile[];
-}
-
-interface ITile {
- id: number;
- roomId: number;
- objectId?: number;
- objectType?: string;
- object?: IDCObject;
- position: IGridPosition;
-}
-
-// State
-interface IMachineState {
- id: number;
- machineId: number;
- machine?: IMachine;
- experimentId: number;
- tick: number;
- temperatureC: number;
- inUseMemoryMb: number;
- loadFraction: number;
-}
-
-interface IRackState {
- id: number;
- rackId: number;
- rack?: IRack;
- experimentId: number;
- tick: number;
- temperatureC: number;
- inUseMemoryMb: number;
- loadFraction: number;
-}
-
-interface IRoomState {
- id: number;
- roomId: number;
- room?: IRoom;
- experimentId: number;
- tick: number;
- temperatureC: number;
- inUseMemoryMb: number;
- loadFraction: number;
-}
-
-interface ITaskState {
- id: number;
- taskId: number;
- task?: ITask;
- experimentId: number;
- tick: number;
- flopsLeft: number;
-}
-
-// Generalization of a datacenter object
-type IDCObject = IRack | ICoolingItem | IPSU;
-
-interface IRack {
- id: number;
- objectType?: string;
- name: string;
- capacity: number;
- powerCapacityW: number;
- machines?: IMachine[];
-}
-
-interface ICoolingItem {
- id: number;
- objectType?: string;
- energyConsumptionW: number;
- type: string;
- failureModelId: number;
- failureModel?: IFailureModel;
-}
-
-interface IPSU {
- id: number;
- objectType?: string;
- energyKwh: number;
- type: string;
- failureModelId: number;
- failureModel?: IFailureModel;
-}
-
-// Machine
-interface IMachine {
- id: number;
- rackId: number;
- position: number;
- tags: string[];
- cpuIds: number[];
- cpus?: ICPU[];
- gpuIds: number[];
- gpus?: IGPU[];
- memoryIds: number[];
- memories?: IMemory[];
- storageIds: number[];
- storages?: IPermanentStorage[];
-}
-
-interface IProcessingUnit {
- id: number;
- manufacturer: string;
- family: string;
- generation: string;
- model: string;
- clockRateMhz: number;
- numberOfCores: number;
- energyConsumptionW: number;
- failureModelId: number;
- failureModel?: IFailureModel;
-}
-
-interface ICPU extends IProcessingUnit {
-
-}
-
-interface IGPU extends IProcessingUnit {
-
-}
-
-interface IStorageUnit {
- id: number;
- manufacturer: string;
- family: string;
- generation: string;
- model: string;
- speedMbPerS: number;
- sizeMb: number;
- energyConsumptionW: number;
- failureModelId: number;
- failureModel?: IFailureModel;
-}
-
-interface IMemory extends IStorageUnit {
-
-}
-
-interface IPermanentStorage extends IStorageUnit {
-
-}
-
-type INodeUnit = IProcessingUnit & IStorageUnit;
-
-interface IFailureModel {
- id: number;
- name: string;
- rate: number;
-}
diff --git a/src/scripts/error404.entry.ts b/src/scripts/error404.entry.ts
deleted file mode 100644
index 477a46c0..00000000
--- a/src/scripts/error404.entry.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-///<reference path="../../typings/globals/jquery/index.d.ts" />
-import * as $ from "jquery";
-
-
-$(document).ready(() => {
- const text =
- " oo oooo oo <br>" +
- " oo oo oo oo <br>" +
- " oo oo oo oo <br>" +
- " oooooo oo oo oooooo <br>" +
- " oo oo oo oo <br>" +
- " oo oooo oo <br>";
- const charList = text.split('');
-
- const binaryString = "01001111011100000110010101101110010001000100001100100001";
-
- let binaryIndex = 0;
- for (let i = 0; i < charList.length; i++) {
- if (charList[i] === "o") {
- charList[i] = binaryString[binaryIndex];
- binaryIndex++;
- }
- }
-
- $(".code-block").html(charList.join(""));
-});
diff --git a/src/scripts/main.entry.ts b/src/scripts/main.entry.ts
deleted file mode 100644
index 84726ed4..00000000
--- a/src/scripts/main.entry.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-///<reference path="../../typings/index.d.ts" />
-///<reference path="./views/mapview.ts" />
-import * as $ from "jquery";
-import {MapView} from "./views/mapview";
-import {APIController} from "./controllers/connection/api";
-window["$"] = $;
-require("jquery-mousewheel");
-window["jQuery"] = $;
-
-require("./user-authentication");
-
-
-$(document).ready(function () {
- new Display(); //tslint:disable-line:no-unused-expression
-});
-
-
-/**
- * Class responsible for launching the main view.
- */
-class Display {
- private stage: createjs.Stage;
- private view: MapView;
-
-
- /**
- * Adjusts the canvas size to fit the window's initial dimensions (full expansion).
- */
- private static fitCanvasSize() {
- const canvas = $("#main-canvas");
- const parent = canvas.parent();
- parent.height($(window).height() - 50);
- canvas.attr("width", parent.width());
- canvas.attr("height", parent.height());
- }
-
- constructor() {
- // Check whether project has been selected before going to the app page
- if (localStorage.getItem("simulationId") === null) {
- window.location.replace("projects");
- return;
- }
-
- Display.fitCanvasSize();
- this.stage = new createjs.Stage("main-canvas");
-
- new APIController((api: APIController) => {
- api.getSimulation(parseInt(localStorage.getItem("simulationId")))
- .then((simulationData: ISimulation) => {
- if (simulationData.name !== "") {
- document.title = simulationData.name + " | OpenDC";
- }
-
- api.getPathsBySimulation(simulationData.id)
- .then((pathData: IPath[]) => {
- simulationData.paths = pathData;
- }).then(() => {
- return api.getExperimentsBySimulation(simulationData.id);
- }).then((experimentData: IExperiment[]) => {
- $(".loading-overlay").hide();
-
- simulationData.experiments = experimentData;
- this.view = new MapView(simulationData, this.stage);
- });
- });
- });
-
- }
-}
diff --git a/src/scripts/profile.entry.ts b/src/scripts/profile.entry.ts
deleted file mode 100644
index 0cb77f50..00000000
--- a/src/scripts/profile.entry.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-///<reference path="../../typings/index.d.ts" />
-import * as $ from "jquery";
-import {APIController} from "./controllers/connection/api";
-import {removeUserInfo} from "./user-authentication";
-window["jQuery"] = $;
-
-
-$(document).ready(() => {
- const api = new APIController(() => {
- });
-
- $("#delete-account").on("click", () => {
- const modalDialog = <any>$("#confirm-delete-account");
-
- // Function called on delete confirmation
- const callback = () => {
- api.deleteUser(parseInt(localStorage.getItem("userId"))).then(() => {
- removeUserInfo();
- gapi.auth2.getAuthInstance().signOut().then(() => {
- window.location.href = "/";
- });
- }, (reason: any) => {
- modalDialog.find("button.confirm").off();
- modalDialog.modal("hide");
-
- const alert = $(".account-delete-alert");
- alert.find("code").text(reason.code + ": " + reason.description);
-
- alert.slideDown(200);
-
- setTimeout(() => {
- alert.slideUp(200);
- }, 5000);
- });
- };
-
- modalDialog.find("button.confirm").on("click", callback);
- modalDialog.modal("show");
- });
-});
diff --git a/src/scripts/projects.entry.ts b/src/scripts/projects.entry.ts
deleted file mode 100644
index daa0e2d6..00000000
--- a/src/scripts/projects.entry.ts
+++ /dev/null
@@ -1,651 +0,0 @@
-///<reference path="../../typings/globals/jquery/index.d.ts" />
-import * as $ from "jquery";
-import {APIController} from "./controllers/connection/api";
-import {Util} from "./util";
-window["jQuery"] = $;
-
-require("./user-authentication");
-
-
-$(document).ready(() => {
- let api;
- new APIController((apiInstance: APIController) => {
- api = apiInstance;
- api.getAuthorizationsByUser(parseInt(localStorage.getItem("userId"))).then((data: any) => {
- const projectsController = new ProjectsController(data, api);
- new WindowController(projectsController, api);
- });
- });
-});
-
-
-/**
- * Controller class responsible for rendering the authorization list views and handling interactions with them.
- */
-class ProjectsController {
- public static authIconMap = {
- "OWN": "glyphicon-home",
- "EDIT": "glyphicon-pencil",
- "VIEW": "glyphicon-eye-open"
- };
-
- public currentUserId: number;
- public authorizations: IAuthorization[];
- public authorizationsFiltered: IAuthorization[];
- public windowController: WindowController;
-
- private api: APIController;
-
-
- /**
- * 'Opens' a project, by putting the relevant simulation ID into local storage and referring to the app page.
- *
- * @param authorization The user's authorization belonging to the project to be opened
- */
- public static openProject(authorization: IAuthorization): void {
- localStorage.setItem("simulationId", authorization.simulationId.toString());
- localStorage.setItem("simulationAuthLevel", authorization.authorizationLevel);
- window.location.href = "app";
- }
-
- /**
- * Converts a list of authorizations into DOM objects, and adds them to the main list body of the page.
- *
- * @param list The list of authorizations to be displayed
- */
- public static populateList(list: IAuthorization[]): void {
- const body = $(".project-list .list-body");
- body.empty();
-
- list.forEach((element: IAuthorization) => {
- body.append(
- $('<div class="project-row">').append(
- $('<div>').text(element.simulation.name),
- $('<div>').text(Util.formatDateTime(element.simulation.datetimeLastEditedParsed)),
- $('<div>').append($('<span class="glyphicon">')
- .addClass(this.authIconMap[element.authorizationLevel]),
- Util.toSentenceCase(element.authorizationLevel)
- )
- ).attr("data-id", element.simulationId)
- );
- });
- };
-
- /**
- * Filters an authorization list based on what authorization level is required.
- *
- * Leaves the original list intact.
- *
- * @param list The authorization list to be filtered
- * @param ownedByUser Whether only authorizations should be included that are owned by the user, or whether only
- * authorizations should be included that the user has no ownership over
- * @returns {IAuthorization[]} A filtered list of authorizations
- */
- public static filterList(list: IAuthorization[], ownedByUser: boolean): IAuthorization[] {
- const resultList: IAuthorization[] = [];
-
- list.forEach((element: IAuthorization) => {
- if (element.authorizationLevel === "OWN") {
- if (ownedByUser) {
- resultList.push(element);
- }
- } else {
- if (!ownedByUser) {
- resultList.push(element);
- }
- }
- });
-
- return resultList;
- };
-
- /**
- * Activates a certain filter heading button, while deactivating the rest.
- *
- * @param target The event target to activate
- */
- private static activateFilterViewButton(target: JQuery): void {
- target.addClass("active");
- target.siblings().removeClass("active");
- };
-
- constructor(authorizations: IAuthorization[], api: APIController) {
- this.currentUserId = parseInt(localStorage.getItem("userId"));
- this.authorizations = authorizations;
- this.authorizationsFiltered = authorizations;
- this.api = api;
-
- this.updateNoProjectsAlert();
-
- this.handleFilterClick();
-
- // Show a project view upon clicking on a simulation row
- $("body").on("click", ".project-row", (event: JQueryEventObject) => {
- this.displayProjectView($(event.target));
- });
- }
-
- /**
- * Update the list of authorizations, by fetching them from the server and reloading the list.
- *
- * Goes to the 'All Projects' page after this refresh.
- */
- public updateAuthorizations(): void {
- this.api.getAuthorizationsByUser(this.currentUserId).then((data: any) => {
- this.authorizations = data;
- this.authorizationsFiltered = this.authorizations;
-
- this.updateNoProjectsAlert();
-
- this.goToAllProjects();
- });
- }
-
- /**
- * Show (or hide) the 'No projects here' alert in the list view, based on whether there are projects present.
- */
- private updateNoProjectsAlert(): void {
- if (this.authorizationsFiltered.length === 0) {
- $(".no-projects-alert").show();
- $(".project-list").hide();
- } else {
- $(".no-projects-alert").hide();
- $(".project-list").show();
- }
- }
-
- /**
- * Displays a project view with authorizations and entry buttons, inline within the table.
- *
- * @param target The element that was clicked on to launch this view
- */
- private displayProjectView(target: JQuery): void {
- const closestRow = target.closest(".project-row");
- const activeElement = $(".project-row.active");
-
- // Disable previously selected row elements and remove any project-views, to have only one view open at a time
- if (activeElement.length > 0) {
- const view = $(".project-view").first();
-
- view.slideUp(200, () => {
- activeElement.removeClass("active");
- view.remove();
- });
-
- if (closestRow.is(activeElement)) {
- return;
- }
- }
-
- const simulationId = parseInt(closestRow.attr("data-id"), 10);
-
- // Generate a list of participants of this project
- this.api.getAuthorizationsBySimulation(simulationId).then((data: any) => {
- const simAuthorizations = data;
- const participants = [];
-
- Util.sortAuthorizations(simAuthorizations);
-
- // For each participant of this simulation, include his/her name along with an icon of their authorization
- // level in the list
- simAuthorizations.forEach((authorization: IAuthorization) => {
- const authorizationString = ' (<span class="glyphicon ' +
- ProjectsController.authIconMap[authorization.authorizationLevel] + '"></span>)';
- if (authorization.userId === this.currentUserId) {
- participants.push(
- 'You' + authorizationString
- );
- } else {
- participants.push(
- authorization.user.givenName + ' ' + authorization.user.familyName + authorizationString
- );
- }
- });
-
- // Generate a project view component with participants and relevant actions
- const object = $('<div class="project-view">').append(
- $('<div class="participants">').append(
- $('<strong>').text("Participants"),
- $('<div>').html(participants.join(", "))
- ),
- $('<div class="access-buttons">').append(
- $('<div class="inline-btn edit">').text("Edit"),
- $('<div class="inline-btn open">').text("Open")
- )
- ).hide();
-
- closestRow.after(object);
-
- // Hide the 'edit' button for non-owners and -editors
- const currentAuth = this.authorizationsFiltered[closestRow.index(".project-row")];
- if (currentAuth.authorizationLevel !== "OWN") {
- $(".project-view .inline-btn.edit").hide();
- }
-
- object.find(".edit").click(() => {
- this.windowController.showEditProjectWindow(simAuthorizations);
- });
-
- object.find(".open").click(() => {
- ProjectsController.openProject(currentAuth);
- });
-
- closestRow.addClass("active");
- object.slideDown(200);
- });
- }
-
- /**
- * Controls the filtered authorization list, based on clicks from the side menu.
- */
- private handleFilterClick(): void {
- $(".all-projects").on("click", () => {
- this.goToAllProjects();
- });
-
- $(".my-projects").on("click", () => {
- this.goToMyProjects();
- });
-
- $(".shared-projects").on("click", () => {
- this.goToSharedProjects();
- });
-
- this.goToAllProjects();
- }
-
- /**
- * Show a list containing all projects (regardless of the authorization level the user has over them).
- */
- private goToAllProjects(): void {
- this.authorizationsFiltered = this.authorizations;
- ProjectsController.populateList(this.authorizations);
- this.updateNoProjectsAlert();
-
- ProjectsController.activateFilterViewButton($(".all-projects"));
- }
-
- /**
- * Show a list containing only projects that the user owns.
- */
- private goToMyProjects(): void {
- this.authorizationsFiltered = ProjectsController.filterList(this.authorizations, true);
- ProjectsController.populateList(this.authorizationsFiltered);
- this.updateNoProjectsAlert();
-
- ProjectsController.activateFilterViewButton($(".my-projects"));
- }
-
- /**
- * Show a list containing only projects that the user does not own (but can edit or view).
- */
- private goToSharedProjects(): void {
- this.authorizationsFiltered = ProjectsController.filterList(this.authorizations, false);
- ProjectsController.populateList(this.authorizationsFiltered);
- this.updateNoProjectsAlert();
-
- ProjectsController.activateFilterViewButton($(".shared-projects"));
- }
-}
-
-
-/**
- * Controller class responsible for rendering the project add/edit window and handle user interaction with it.
- */
-class WindowController {
- private projectsController: ProjectsController;
- private windowOverlay: JQuery;
- private window: JQuery;
- private table: JQuery;
- private closeCallback: () => any;
- private simAuthorizations: IAuthorization[];
- private simulationId: number;
- private editMode: boolean;
- private api: APIController;
-
-
- constructor(projectsController: ProjectsController, api: APIController) {
- this.projectsController = projectsController;
- this.windowOverlay = $(".window-overlay");
- this.window = $(".projects-window");
- this.table = $(".participants-table");
- this.projectsController.windowController = this;
- this.simAuthorizations = [];
- this.editMode = false;
- this.api = api;
-
- $(".window-footer .btn").hide();
-
- $(".participant-add-form").submit((event: JQueryEventObject) => {
- event.preventDefault();
- $(".participant-add-form .btn").trigger("click");
- });
-
- $(".project-name-form").submit((event: JQueryEventObject) => {
- event.preventDefault();
- $(".project-name-form .btn").trigger("click");
- });
-
- // Clean-up actions to occur after every window-close
- this.closeCallback = () => {
- this.table.empty();
- $(".project-name-form .btn").off();
- $(".participant-add-form .btn").off();
- $(".window-footer .btn").hide().off();
- $(".participant-email-alert").hide();
- $(".participant-level div").removeClass("active").off();
- this.table.off("click", ".participant-remove div");
-
- $(".project-name-form input").val("");
- $(".participant-add-form input").val("");
-
- if (this.editMode) {
- this.projectsController.updateAuthorizations();
- }
- };
-
- $(".new-project-btn").click(() => {
- this.showAddProjectWindow();
- });
-
- // Stop click events on the window from closing it indirectly
- this.window.click((event: JQueryEventObject) => {
- event.stopPropagation();
- });
-
- $(".window-close, .window-overlay").click(() => {
- this.closeWindow();
- });
- }
-
- /**
- * Displays a window for project edits (used for adding participants and changing the name).
- *
- * @param authorizations The authorizations of the simulation project to be edited.
- */
- public showEditProjectWindow(authorizations: IAuthorization[]): void {
- this.editMode = true;
- this.simAuthorizations = [];
- this.simulationId = authorizations[0].simulation.id;
-
- // Filter out the user's authorization from the authorization list (not to be displayed in the list)
- authorizations.forEach((authorization: IAuthorization) => {
- if (authorization.userId !== this.projectsController.currentUserId) {
- this.simAuthorizations.push(authorization);
- }
- });
-
- $(".window .window-heading").text("Edit project");
-
- $(".project-name-form input").val(authorizations[0].simulation.name);
-
- $(".project-name-form .btn").css("display", "inline-block").click(() => {
- const nameInput = $(".project-name-form input").text();
- if (nameInput !== "") {
- authorizations[0].simulation.name = nameInput;
- this.api.updateSimulation(authorizations[0].simulation);
- }
- });
-
- $(".project-open-btn").show().click(() => {
- ProjectsController.openProject({
- userId: this.projectsController.currentUserId,
- simulationId: this.simulationId,
- authorizationLevel: "OWN"
- });
- });
-
- $(".project-delete-btn").show().click(() => {
- this.api.deleteSimulation(authorizations[0].simulationId).then(() => {
- this.projectsController.updateAuthorizations();
- this.closeWindow();
- });
- });
-
- $(".participant-add-form .btn").click(() => {
- this.handleParticipantAdd((userId: number) => {
- this.api.addAuthorization({
- userId: userId,
- simulationId: authorizations[0].simulationId,
- authorizationLevel: "VIEW"
- });
- });
- });
-
- this.table.on("click", ".participant-level div", (event: JQueryEventObject) => {
- this.handleParticipantLevelChange(event, (authorization: IAuthorization) => {
- this.api.updateAuthorization(authorization);
- });
- });
-
- this.table.on("click", ".participant-remove div", (event: JQueryEventObject) => {
- this.handleParticipantDelete(event, (authorization) => {
- this.api.deleteAuthorization(authorization);
- });
- });
-
- this.populateParticipantList();
-
- this.windowOverlay.fadeIn(200);
- }
-
- /**
- * Shows a window to be used for creating a new project.
- */
- public showAddProjectWindow(): void {
- this.editMode = false;
- this.simAuthorizations = [];
-
- $(".project-name-form .btn").hide();
-
- $(".window .window-heading").text("Create a project");
-
- $(".project-create-open-btn").show().click(() => {
- if ($(".project-name-form input").val() === "") {
- this.showAlert(".project-name-alert");
- return;
- }
- this.createSimulation((simulationId: number) => {
- ProjectsController.openProject({
- userId: this.projectsController.currentUserId,
- simulationId,
- authorizationLevel: "OWN"
- });
- });
- });
-
- $(".project-create-btn").show().click(() => {
- if ($(".project-name-form input").val() === "") {
- this.showAlert(".project-name-alert");
- return;
- }
- this.createSimulation(() => {
- this.projectsController.updateAuthorizations();
- this.closeWindow();
- });
- });
-
- $(".project-cancel-btn").show().click(() => {
- this.closeWindow();
- });
-
- this.table.empty();
-
- $(".project-name-form input").val("");
- $(".participant-add-form input").val("");
-
- $(".participant-add-form .btn").click(() => {
- this.handleParticipantAdd(() => {
- });
- });
-
- this.table.on("click", ".participant-level div", (event: JQueryEventObject) => {
- this.handleParticipantLevelChange(event, () => {
- });
- });
-
- this.table.on("click", ".participant-remove div", (event: JQueryEventObject) => {
- this.handleParticipantDelete(event, () => {
- });
- });
-
- this.windowOverlay.fadeIn(200);
- }
-
- /**
- * Creates a new simulation with the current name input and all currently present authorizations added in the
- * project 'add' window.
- *
- * @param callback The function to be called when this operation has succeeded
- */
- private createSimulation(callback: (simulationId: number) => any): void {
- this.api.addSimulation({
- id: -1,
- name: $(".project-name-form input").text(),
- datetimeCreated: Util.getCurrentDateTime(),
- datetimeLastEdited: Util.getCurrentDateTime()
- }).then((data: any) => {
- let asyncCounter = this.simAuthorizations.length;
- this.simAuthorizations.forEach((authorization: IAuthorization) => {
- authorization.simulationId = data.id;
- this.api.addAuthorization(authorization).then((data: any) => {
- asyncCounter--;
-
- if (asyncCounter <= 0) {
- callback(data.id);
- }
- });
- });
- if (this.simAuthorizations.length === 0) {
- callback(data.id);
- }
- });
- }
-
- /**
- * Displays an alert of the given class name, to disappear again after a certain pre-defined timeout.
- *
- * @param name A selector that uniquely identifies the alert body to be shown.
- */
- private showAlert(name): void {
- const alert = $(name);
- alert.slideDown(200);
-
- setTimeout(() => {
- alert.slideUp(200);
- }, 5000);
- }
-
- /**
- * Closes the window with a transition, and calls the relevant callback after that transition has ended.
- */
- private closeWindow(): void {
- this.windowOverlay.fadeOut(200, () => {
- this.closeCallback();
- });
- }
-
- /**
- * Handles the click on an authorization icon in the project window authorization list.
- *
- * @param event The JQuery click event
- * @param callback The function to be called after the authorization was changed
- */
- private handleParticipantLevelChange(event: JQueryEventObject,
- callback: (authorization: IAuthorization) => any): void {
- $(event.target).closest(".participant-level").find("div").removeClass("active");
- $(event.target).addClass("active");
-
- const affectedRow = $(event.target).closest(".participant-row");
-
- for (let level in ProjectsController.authIconMap) {
- if (!ProjectsController.authIconMap.hasOwnProperty(level)) {
- continue;
- }
- if ($(event.target).is("." + ProjectsController.authIconMap[level])) {
- this.simAuthorizations[affectedRow.index()].authorizationLevel = level;
- callback(this.simAuthorizations[affectedRow.index()]);
- break;
- }
- }
- }
-
- /**
- * Handles the event where a user seeks to add a participant.
- *
- * @param callback The function to be called if the participant could be found and can be added.
- */
- private handleParticipantAdd(callback: (userId: number) => any): void {
- const inputForm = $(".participant-add-form input");
- this.api.getUserByEmail(inputForm.text()).then((data: any) => {
- let insert = true;
- for (let i = 0; i < this.simAuthorizations.length; i++) {
- if (this.simAuthorizations[i].userId === data.id) {
- insert = false;
- }
- }
-
- const simulationId = this.editMode ? this.simulationId : -1;
- if (data.id !== this.projectsController.currentUserId && insert) {
- this.simAuthorizations.push({
- userId: data.id,
- user: data,
- simulationId: simulationId,
- authorizationLevel: "VIEW"
- });
- callback(data.id);
- Util.sortAuthorizations(this.simAuthorizations);
- this.populateParticipantList();
- }
-
- // Clear input field after submission
- inputForm.val("");
- }, (reason: any) => {
- if (reason.code === 404) {
- this.showAlert(".participant-email-alert");
- }
- });
- }
-
- /**
- * Handles click events on the 'remove' icon next to each participant.
- *
- * @param event The JQuery click event
- * @param callback The function to be executed on removal of the participant from the internal list
- */
- private handleParticipantDelete(event: JQueryEventObject, callback: (authorization: IAuthorization) => any): void {
- const affectedRow = $(event.target).closest(".participant-row");
- const index = affectedRow.index();
- const authorization = this.simAuthorizations[index];
- this.simAuthorizations.splice(index, 1);
- this.populateParticipantList();
- callback(authorization);
- }
-
- /**
- * Populates the list of participants in the project edit window with all current authorizations.
- */
- private populateParticipantList(): void {
- this.table.empty();
-
- this.simAuthorizations.forEach((authorization: IAuthorization) => {
- this.table.append(
- '<div class="participant-row">' +
- ' <div class="participant-name">' + authorization.user.givenName + ' ' +
- authorization.user.familyName + '</div>' +
- ' <div class="participant-level">' +
- ' <div class="participant-level-view glyphicon glyphicon-eye-open ' +
- (authorization.authorizationLevel === "VIEW" ? 'active' : '') + '"></div>' +
- ' <div class="participant-level-edit glyphicon glyphicon-pencil ' +
- (authorization.authorizationLevel === "EDIT" ? 'active' : '') + '"></div>' +
- ' <div class="participant-level-own glyphicon glyphicon-home ' +
- (authorization.authorizationLevel === "OWN" ? 'active' : '') + '"></div>' +
- ' </div>' +
- ' <div class="participant-remove">' +
- ' <div class="glyphicon glyphicon-remove"></div>' +
- ' </div>' +
- '</div>'
- );
- });
- }
-}
diff --git a/src/scripts/serverconnection.ts b/src/scripts/serverconnection.ts
deleted file mode 100644
index e5cbf48a..00000000
--- a/src/scripts/serverconnection.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import {SocketController} from "./controllers/connection/socket";
-
-
-export class ServerConnection {
- private static _socketControllerInstance: SocketController;
-
-
- public static connect(onConnect: () => any): void {
- this._socketControllerInstance = new SocketController(onConnect);
- }
-
- public static send(request: IRequest): Promise<any> {
- return new Promise((resolve, reject) => {
- const checkUnimplemented = ServerConnection.interceptUnimplementedEndpoint(request);
- if (checkUnimplemented) {
- resolve(checkUnimplemented.content);
- return;
- }
-
- this._socketControllerInstance.sendRequest(request, (response: IResponse) => {
- if (response.status.code === 200) {
- ServerConnection.convertFlatToNestedPositionData(response.content, resolve);
- } else {
- reject(response.status);
- }
- });
- })
- }
-
- public static convertFlatToNestedPositionData(responseContent, resolve): void {
- const nestPositionCoords = (content: any) => {
- if (content["positionX"] !== undefined) {
- content["position"] = {
- x: content["positionX"],
- y: content["positionY"]
- };
- }
- };
-
- if (responseContent instanceof Array) {
- responseContent.forEach(nestPositionCoords);
- } else {
- nestPositionCoords(responseContent);
- }
-
- resolve(responseContent);
- }
-
- /**
- * Intercepts endpoints that are still unimplemented and responds with mock data.
- *
- * @param request The request
- * @returns {any} A response, or null if the endpoint is not on the list of unimplemented ones.
- */
- public static interceptUnimplementedEndpoint(request: IRequest): IResponse {
- // Endpoints that are unimplemented can be intercepted here
- return null;
- }
-}
diff --git a/src/scripts/splash.entry.ts b/src/scripts/splash.entry.ts
deleted file mode 100644
index 6abd9518..00000000
--- a/src/scripts/splash.entry.ts
+++ /dev/null
@@ -1,157 +0,0 @@
-///<reference path="../../typings/index.d.ts" />
-///<reference path="./definitions.ts" />
-import * as $ from "jquery";
-import {APIController} from "./controllers/connection/api";
-window["jQuery"] = $;
-require("jquery.easing");
-
-
-// Variable to check whether user actively logged in by clicking the login button
-let hasClickedLogin = false;
-
-
-$(document).ready(() => {
- /**
- * jQuery for page scrolling feature
- */
- $('a.page-scroll').bind('click', function (event) {
- const $anchor = $(this);
- $('html, body').stop().animate({
- scrollTop: $($anchor.attr('href')).offset().top
- }, 1000, 'easeInOutExpo', () => {
- if ($anchor.attr('href') === "#page-top") {
- location.hash = '';
- } else {
- location.hash = $anchor.attr('href');
- }
- });
- event.preventDefault();
- });
-
- const checkScrollState = () => {
- const startY = 100;
-
- if ($(window).scrollTop() > startY || window.innerWidth < 768) {
- $('.navbar').removeClass("navbar-transparent");
- } else {
- $('.navbar').addClass("navbar-transparent");
- }
- };
-
- $(window).on("scroll load resize", function () {
- checkScrollState();
- });
-
- checkScrollState();
-
- const googleSigninBtn = $("#google-signin");
- googleSigninBtn.click(() => {
- hasClickedLogin = true;
- });
-
- /**
- * Display appropriate user buttons
- */
- if (localStorage.getItem("googleToken") !== null) {
- googleSigninBtn.hide();
- $(".navbar .logged-in").css("display", "inline-block");
- $(".logged-in .sign-out").click(() => {
- const auth2 = gapi.auth2.getAuthInstance();
-
- auth2.signOut().then(() => {
- // Remove session storage items
- localStorage.removeItem("googleToken");
- localStorage.removeItem("googleTokenExpiration");
- localStorage.removeItem("googleName");
- localStorage.removeItem("googleEmail");
- localStorage.removeItem("userId");
- localStorage.removeItem("simulationId");
-
- location.reload();
- });
- });
-
- // Check whether Google auth. token has expired and signin again if necessary
- const currentTime = (new Date()).getTime();
- if (parseInt(localStorage.getItem("googleTokenExpiration")) - currentTime <= 0) {
- gapi.auth2.getAuthInstance().signIn().then(() => {
- const authResponse = gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse();
- localStorage.setItem("googleToken", authResponse.id_token);
- const expirationTime = (new Date()).getTime() / 1000 + parseInt(authResponse.expires_in) - 5;
- localStorage.setItem("googleTokenExpiration", expirationTime.toString());
- });
- }
- }
-});
-
-/**
- * Google signin button
- */
-window["renderButton"] = () => {
- gapi.signin2.render('google-signin', {
- 'scope': 'profile email',
- 'width': 100,
- 'height': 30,
- 'longtitle': false,
- 'theme': 'dark',
- 'onsuccess': (googleUser) => {
- let api;
- new APIController((apiInstance: APIController) => {
- api = apiInstance;
- const email = googleUser.getBasicProfile().getEmail();
-
- const getUser = (userId: number) => {
- const reload = localStorage.getItem("userId") === null;
-
- localStorage.setItem("userId", userId.toString());
-
- // Redirect to the projects page
- if (hasClickedLogin) {
- window.location.href = "projects";
- } else if (reload) {
- window.location.reload();
- }
-
- };
-
- // Send the token to the server
- const id_token = googleUser.getAuthResponse().id_token;
- // Calculate token expiration time (in seconds since epoch)
- const expirationTime = (new Date()).getTime() / 1000 + googleUser.getAuthResponse().expires_in - 5;
-
- $.post('SERVER_BASE_URL/tokensignin', {
- idtoken: id_token
- }, (data: any) => {
- // Save user information in session storage for later use on other pages
- localStorage.setItem("googleToken", id_token);
- localStorage.setItem("googleTokenExpiration", expirationTime.toString());
- localStorage.setItem("googleName", googleUser.getBasicProfile().getGivenName() + " " +
- googleUser.getBasicProfile().getFamilyName());
- localStorage.setItem("googleEmail", email);
-
- if (data.isNewUser === true) {
- api.addUser({
- id: -1,
- email,
- googleId: googleUser.getBasicProfile().getId(),
- givenName: googleUser.getBasicProfile().getGivenName(),
- familyName: googleUser.getBasicProfile().getFamilyName()
- }).then((userData: any) => {
- getUser(userData.id);
- });
- } else {
- getUser(data.userId);
- }
- });
- });
- },
- 'onfailure': () => {
- console.log("Oops, something went wrong with your Google signin... Try again?");
- }
- });
-};
-
-// Set the language of the GAuth button to be English
-window["___gcfg"] = {
- lang: 'en'
-};
diff --git a/src/scripts/tests/util.spec.ts b/src/scripts/tests/util.spec.ts
deleted file mode 100644
index 74d62dfa..00000000
--- a/src/scripts/tests/util.spec.ts
+++ /dev/null
@@ -1,326 +0,0 @@
-///<reference path="../util.ts" />
-///<reference path="../../../typings/globals/jasmine/index.d.ts" />
-import {Util} from "../util";
-
-
-class TestUtils {
- /**
- * Checks whether the two (three-dimensional) wall lists are equivalent in content.
- *
- * This is a set-compare method, meaning that the order of the elements does not matter, but that they are present
- * in both arrays.
- *
- * Example of such a list: [[[1, 1], [2, 1]], [[3, 1], [0, 0]]]
- *
- * @param list1 The first list
- * @param list2 The second list
- */
- public static wallListEquals(list1: IRoomWall[], list2: IRoomWall[]): void {
- let current, found, counter;
-
- counter = 0;
- while (list1.length > 0) {
- current = list1.pop();
- found = false;
- list2.forEach((e: IRoomWall) => {
- if (current.startPos[0] === e.startPos[0] && current.startPos[1] === e.startPos[1] &&
- current.horizontal === e.horizontal && current.length === e.length) {
- counter++;
- found = true;
- }
- });
- if (!found) {
- fail();
- }
- }
- expect(list2.length).toEqual(counter);
- }
-
- /**
- * Does the same as wallList3DEquals, only for two lists of tiles.
- *
- * @param expected
- * @param actual
- */
- public static positionListEquals(expected: IGridPosition[], actual: IGridPosition[]): void {
- let current, found;
- let counter = 0;
-
- while (expected.length > 0) {
- current = expected.pop();
- found = false;
- actual.forEach((e) => {
- if (current.x === e.x && current.y === e.y) {
- counter++;
- found = true;
- }
- });
- if (!found) {
- fail();
- }
- }
-
- expect(actual.length).toEqual(counter);
- }
-
- public static boundsEquals(actual: IBounds, expected: IBounds): void {
- expect(actual.min[0]).toBe(expected.min[0]);
- expect(actual.min[1]).toBe(expected.min[1]);
- expect(actual.center[0]).toBe(expected.center[0]);
- expect(actual.center[1]).toBe(expected.center[1]);
- expect(actual.max[0]).toBe(expected.max[0]);
- expect(actual.max[1]).toBe(expected.max[1]);
- }
-}
-
-describe("Deriving wall locations", () => {
- it("should generate walls around a single tile", () => {
- let room = {
- id: -1,
- datacenterId: -1,
- name: "testroom",
- roomType: "none",
- tiles: [{
- id: -1,
- roomId: -1,
- position: {x: 1, y: 1}
- }]
- };
-
- let result = Util.deriveWallLocations([
- room
- ]);
- let expected: IRoomWall[] = [
- {
- startPos: [1, 1],
- horizontal: false,
- length: 1
- },
- {
- startPos: [2, 1],
- horizontal: false,
- length: 1
- },
- {
- startPos: [1, 1],
- horizontal: true,
- length: 1
- },
- {
- startPos: [1, 2],
- horizontal: true,
- length: 1
- }
- ];
-
- TestUtils.wallListEquals(expected, result);
- }
- );
-
- it("should generate walls around two tiles connected by an edge", () => {
- let room = {
- id: -1,
- datacenterId: -1,
- name: "testroom",
- roomType: "none",
- tiles: [
- {
- id: -1,
- roomId: -1,
- position: {x: 1, y: 1}
- }, {
- id: -1,
- roomId: -1,
- position: {x: 1, y: 2}
- }
- ]
- };
-
- let result = Util.deriveWallLocations([
- room
- ]);
- let expected: IRoomWall[] = [
- {
- startPos: [1, 1],
- horizontal: false,
- length: 2
- },
- {
- startPos: [2, 1],
- horizontal: false,
- length: 2
- },
- {
- startPos: [1, 1],
- horizontal: true,
- length: 1
- },
- {
- startPos: [1, 3],
- horizontal: true,
- length: 1
- }
- ];
-
- TestUtils.wallListEquals(expected, result);
- }
- );
-
- it("should generate walls around two independent rooms with one tile each", () => {
- let room1 = {
- id: -1,
- datacenterId: -1,
- name: "testroom",
- roomType: "none",
- tiles: [
- {
- id: -1,
- roomId: -1,
- position: {x: 1, y: 1}
- }
- ]
- };
-
- let room2 = {
- id: -1,
- datacenterId: -1,
- name: "testroom",
- roomType: "none",
- tiles: [{
- id: -1,
- roomId: -1,
- position: {x: 1, y: 3}
- }
- ]
- };
-
- let result = Util.deriveWallLocations([
- room1, room2
- ]);
- let expected: IRoomWall[] = [
- {
- startPos: [1, 1],
- horizontal: false,
- length: 1
- },
- {
- startPos: [1, 3],
- horizontal: false,
- length: 1
- },
- {
- startPos: [2, 1],
- horizontal: false,
- length: 1
- },
- {
- startPos: [2, 3],
- horizontal: false,
- length: 1
- },
- {
- startPos: [1, 1],
- horizontal: true,
- length: 1
- },
- {
- startPos: [1, 2],
- horizontal: true,
- length: 1
- },
- {
- startPos: [1, 3],
- horizontal: true,
- length: 1
- },
- {
- startPos: [1, 4],
- horizontal: true,
- length: 1
- }
- ];
-
- TestUtils.wallListEquals(expected, result);
- }
- );
-});
-
-describe("Deriving valid next tile positions", () => {
- it("should derive correctly 4 valid tile positions around 1 selected tile with no other rooms", () => {
- let result = Util.deriveValidNextTilePositions([], [{
- id: -1,
- roomId: -1,
- position: {x: 1, y: 1}
- }]);
- let expected = [
- {x: 1, y: 0}, {x: 2, y: 1}, {x: 1, y: 2}, {x: 0, y: 1}
- ];
-
- TestUtils.positionListEquals(expected, result);
- });
-
- it("should derive correctly 6 valid tile positions around 2 selected tiles with no other rooms", () => {
- let result = Util.deriveValidNextTilePositions([], [{
- id: -1,
- roomId: -1,
- position: {x: 1, y: 1}
- }, {
- id: -1,
- roomId: -1,
- position: {x: 2, y: 1}
- }]);
- let expected = [
- {x: 1, y: 0}, {x: 2, y: 0}, {x: 3, y: 1}, {x: 1, y: 2}, {x: 2, y: 2}, {x: 0, y: 1}
- ];
-
- TestUtils.positionListEquals(expected, result);
- });
-
- it("should derive correctly 3 valid tile positions around 1 selected tiles with 1 adjacent room", () => {
- let room = {
- id: -1,
- datacenterId: -1,
- name: "testroom",
- roomType: "none",
- tiles: [{
- id: -1,
- roomId: -1,
- position: {x: 0, y: 1}
- }]
- };
- let result = Util.deriveValidNextTilePositions([room], [{
- id: -1,
- roomId: -1,
- position: {x: 1, y: 1}
- }]);
- let expected = [
- {x: 1, y: 0}, {x: 2, y: 1}, {x: 1, y: 2}
- ];
-
- TestUtils.positionListEquals(expected, result);
- });
-});
-
-describe("Calculating the bounds and average point of a list of rooms", () => {
- it("should calculate correctly the bounds of a 1-tile room", () => {
- let room = {
- id: -1,
- datacenterId: -1,
- name: "testroom",
- roomType: "none",
- tiles: [{
- id: -1,
- roomId: -1,
- position: {x: 1, y: 1}
- }]
- };
- let result = Util.calculateRoomListBounds([room]);
- let expected = {
- min: [1, 1],
- center: [1.5, 1.5],
- max: [2, 2]
- };
-
- TestUtils.boundsEquals(result, expected);
- });
-});
diff --git a/src/scripts/user-authentication.ts b/src/scripts/user-authentication.ts
deleted file mode 100644
index e9d13091..00000000
--- a/src/scripts/user-authentication.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-///<reference path="../../typings/index.d.ts" />
-import * as $ from "jquery";
-
-
-// Redirect the user to the splash page, if not signed in
-if (localStorage.getItem("googleToken") === null) {
- window.location.replace("/");
-}
-
-// Set the username in the navbar
-$("nav .user .username").text(localStorage.getItem("googleName"));
-
-
-// Set the language of the GAuth button to be English
-window["___gcfg"] = {
- lang: 'en'
-};
-
-/**
- * Google signin button.
- */
-window["gapiSigninButton"] = () => {
- gapi.signin2.render('google-signin', {
- 'scope': 'profile email',
- 'onsuccess': (googleUser) => {
- const auth2 = gapi.auth2.getAuthInstance();
-
- // Handle signout click
- $("nav .user .sign-out").click(() => {
- removeUserInfo();
- auth2.signOut().then(() => {
- window.location.href = "/";
- });
- });
-
- // Check if the token has expired
- const currentTime = (new Date()).getTime() / 1000;
-
- if (parseInt(localStorage.getItem("googleTokenExpiration")) - currentTime <= 0) {
- auth2.signIn().then(() => {
- localStorage.setItem("googleToken", googleUser.getAuthResponse().id_token);
- const expirationTime = (new Date()).getTime() / 1000 + parseInt(googleUser.getAuthResponse().expires_in) - 5;
- localStorage.setItem("googleTokenExpiration", expirationTime.toString());
- });
- }
- },
- 'onfailure': () => {
- window.location.href = "/";
- console.log("Oops, something went wrong with your Google signin... Try again?");
- }
- });
-};
-
-
-/**
- * Removes session storage items.
- */
-export function removeUserInfo() {
- localStorage.removeItem("googleToken");
- localStorage.removeItem("googleTokenExpiration");
- localStorage.removeItem("googleName");
- localStorage.removeItem("googleEmail");
- localStorage.removeItem("userId");
- localStorage.removeItem("simulationId");
-}
diff --git a/src/scripts/util.ts b/src/scripts/util.ts
deleted file mode 100644
index d3a2ea58..00000000
--- a/src/scripts/util.ts
+++ /dev/null
@@ -1,613 +0,0 @@
-///<reference path="definitions.ts" />
-import {Colors} from "./colors";
-
-
-export enum IntensityLevel {
- LOW,
- MID_LOW,
- MID_HIGH,
- HIGH
-}
-
-
-export class Util {
- private static authorizationLevels = [
- "OWN", "EDIT", "VIEW"
- ];
-
-
- /**
- * Derives the wall locations given a list of rooms.
- *
- * Does so by computing an outline around all tiles in the rooms.
- */
- public static deriveWallLocations(rooms: IRoom[]): IRoomWall[] {
- const verticalWalls = {};
- const horizontalWalls = {};
- let doInsert;
- rooms.forEach((room: IRoom) => {
- room.tiles.forEach((tile: ITile) => {
- const x = tile.position.x, y = tile.position.y;
- for (let dX = -1; dX <= 1; dX++) {
- for (let dY = -1; dY <= 1; dY++) {
- if (Math.abs(dX) === Math.abs(dY)) {
- continue;
- }
-
- doInsert = true;
- room.tiles.forEach((otherTile: ITile) => {
- if (otherTile.position.x === x + dX && otherTile.position.y === y + dY) {
- doInsert = false;
- }
- });
-
- if (doInsert) {
- if (dX === -1) {
- if (verticalWalls[x] === undefined) {
- verticalWalls[x] = [];
- }
- if (verticalWalls[x].indexOf(y) === -1) {
- verticalWalls[x].push(y);
- }
- } else if (dX === 1) {
- if (verticalWalls[x + 1] === undefined) {
- verticalWalls[x + 1] = [];
- }
- if (verticalWalls[x + 1].indexOf(y) === -1) {
- verticalWalls[x + 1].push(y);
- }
- } else if (dY === -1) {
- if (horizontalWalls[y] === undefined) {
- horizontalWalls[y] = [];
- }
- if (horizontalWalls[y].indexOf(x) === -1) {
- horizontalWalls[y].push(x);
- }
- } else if (dY === 1) {
- if (horizontalWalls[y + 1] === undefined) {
- horizontalWalls[y + 1] = [];
- }
- if (horizontalWalls[y + 1].indexOf(x) === -1) {
- horizontalWalls[y + 1].push(x);
- }
- }
- }
- }
- }
- });
- });
-
- const result: IRoomWall[] = [];
- const walls = [verticalWalls, horizontalWalls];
- for (let i = 0; i < 2; i++) {
- const wallList = walls[i];
- for (let a in wallList) {
- if (!wallList.hasOwnProperty(a)) {
- return;
- }
-
- wallList[a].sort((a: number, b: number) => {
- return a - b;
- });
-
- let startPos = wallList[a][0];
- const positionArray = (i === 1 ? <number[]>[startPos, parseInt(a)] : <number[]>[parseInt(a), startPos]);
-
- if (wallList[a].length === 1) {
- result.push({
- startPos: positionArray,
- horizontal: i === 1,
- length: 1
- });
- } else {
- let consecutiveCount = 1;
- for (let b = 0; b < wallList[a].length - 1; b++) {
- if (b + 1 === wallList[a].length - 1) {
- if (wallList[a][b + 1] - wallList[a][b] > 1) {
- result.push({
- startPos: (i === 1 ? <number[]>[startPos, parseInt(a)] : <number[]>[parseInt(a), startPos]),
- horizontal: i === 1,
- length: consecutiveCount
- });
- consecutiveCount = 0;
- startPos = wallList[a][b + 1];
- }
- result.push({
- startPos: (i === 1 ? <number[]>[startPos, parseInt(a)] : <number[]>[parseInt(a), startPos]),
- horizontal: i === 1,
- length: consecutiveCount + 1
- });
- break;
- } else if (wallList[a][b + 1] - wallList[a][b] > 1) {
- result.push({
- startPos: (i === 1 ? <number[]>[startPos, parseInt(a)] : <number[]>[parseInt(a), startPos]),
- horizontal: i === 1,
- length: consecutiveCount
- });
- startPos = wallList[a][b + 1];
- consecutiveCount = 0;
- }
- consecutiveCount++;
- }
- }
- }
- }
-
- return result;
- }
-
- /**
- * Generates a list of all valid tile positions around the currently selected room under construction.
- *
- * @param rooms The rooms that already exist in the model
- * @param selectedTiles The tiles that the user has already selected to form a new room
- * @returns {Array} A 2D list of tile positions that are valid next tile choices.
- */
- public static deriveValidNextTilePositions(rooms: IRoom[], selectedTiles: ITile[]): IGridPosition[] {
- const result = [], newPosition = {x: 0, y: 0};
- let isSurroundingTile;
-
- selectedTiles.forEach((tile: ITile) => {
- const x = tile.position.x, y = tile.position.y;
- for (let dX = -1; dX <= 1; dX++) {
- for (let dY = -1; dY <= 1; dY++) {
- if (Math.abs(dX) === Math.abs(dY)) {
- continue;
- }
-
- newPosition.x = x + dX;
- newPosition.y = y + dY;
-
- isSurroundingTile = true;
- selectedTiles.forEach((otherTile: ITile) => {
- if (otherTile.position.x === newPosition.x && otherTile.position.y === newPosition.y) {
- isSurroundingTile = false;
- }
- });
-
- if (isSurroundingTile && !Util.checkRoomCollision(rooms, newPosition)) {
- result.push({x: newPosition.x, y: newPosition.y});
- }
- }
- }
- });
-
- return result;
- }
-
- /**
- * Determines whether a position is contained in a list of tiles.
- *
- * @param list A list of tiles
- * @param position A position
- * @returns {boolean} Whether the list contains the position
- */
- public static tileListContainsPosition(list: ITile[], position: IGridPosition): boolean {
- return Util.tileListPositionIndexOf(list, position) !== -1;
- }
-
- /**
- * Determines the index of a position in a list of tiles.
- *
- * @param list A list of tiles
- * @param position A position
- * @returns {number} Index of the position in the list of tiles, -1 if not found
- */
- public static tileListPositionIndexOf(list: ITile[], position: IGridPosition): number {
- let index = -1;
-
- for (let i = 0; i < list.length; i++) {
- const element = list[i];
- if (position.x === element.position.x && position.y === element.position.y) {
- index = i;
- break;
- }
- }
-
- return index;
- }
-
- /**
- * Determines whether a position is contained in a list of positions.
- *
- * @param list A list of positions
- * @param position A position
- * @returns {boolean} Whether the list contains the position
- */
- public static positionListContainsPosition(list: IGridPosition[], position: IGridPosition): boolean {
- return Util.positionListPositionIndexOf(list, position) !== -1;
- }
-
- /**
- * Determines the index of a position in a list of positions.
- *
- * @param list A list of positions
- * @param position A position
- * @returns {number} Index of the position in the list of tiles, -1 if not found
- */
- public static positionListPositionIndexOf(list: IGridPosition[], position: IGridPosition): number {
- let index = -1;
-
- for (let i = 0; i < list.length; i++) {
- const element = list[i];
- if (position.x === element.x && position.y === element.y) {
- index = i;
- break;
- }
- }
-
- return index;
- }
-
- /**
- * Determines the index of a room that is colliding with a given grid tile.
- *
- * Returns -1 if no collision is found.
- *
- * @param rooms An array of Room objects that should be checked for collisions
- * @param position A position
- * @returns {number} The index of the room in the rooms list if found, else -1
- */
- public static roomCollisionIndexOf(rooms: IRoom[], position: IGridPosition): number {
- let index = -1;
-
- for (let i = 0; i < rooms.length; i++) {
- const room = rooms[i];
- if (Util.tileListContainsPosition(room.tiles, position)) {
- index = i;
- break;
- }
- }
-
- return index;
- }
-
- /**
- * Checks whether a tile location collides with an existing room.
- *
- * @param rooms A list of rooms to be analyzed
- * @param position A position
- * @returns {boolean} Whether the tile lies in an existing room
- */
- public static checkRoomCollision(rooms: IRoom[], position: IGridPosition): boolean {
- return Util.roomCollisionIndexOf(rooms, position) !== -1;
- }
-
- /**
- * Calculates the minimum, center, and maximum of a list of rooms in stage coordinates.
- *
- * This center is calculated by averaging the most outlying tiles of all rooms.
- *
- * @param rooms The rooms to be analyzed
- * @returns {IBounds} The coordinates of the minimum, center, and maximum
- */
- public static calculateRoomListBounds(rooms: IRoom[]): IBounds {
- const min = [Number.MAX_VALUE, Number.MAX_VALUE];
- const max = [-1, -1];
-
- rooms.forEach((room: IRoom) => {
- room.tiles.forEach((tile: ITile) => {
- if (tile.position.x < min[0]) {
- min[0] = tile.position.x;
- }
- if (tile.position.y < min[1]) {
- min[1] = tile.position.y;
- }
-
- if (tile.position.x > max[0]) {
- max[0] = tile.position.x;
- }
- if (tile.position.y > max[1]) {
- max[1] = tile.position.y;
- }
- });
- });
-
- max[0]++;
- max[1]++;
-
- const gridCenter = [min[0] + (max[0] - min[0]) / 2.0, min[1] + (max[1] - min[1]) / 2.0];
-
- return {
- min: min,
- center: gridCenter,
- max: max
- };
- }
-
- /**
- * Does the same as 'calculateRoomListBounds', only for one room.
- *
- * @param room The room to be analyzed
- * @returns {IBounds} The coordinates of the minimum, center, and maximum
- */
- public static calculateRoomBounds(room: IRoom): IBounds {
- return Util.calculateRoomListBounds([room]);
- }
-
- public static calculateRoomNamePosition(room: IRoom): IRoomNamePos {
- const result: IRoomNamePos = {
- topLeft: {x: 0, y: 0},
- length: 0
- };
-
- // Look for the top-most tile y-coordinate
- let topMin = Number.MAX_VALUE;
- room.tiles.forEach((tile: ITile) => {
- if (tile.position.y < topMin) {
- topMin = tile.position.y;
- }
- });
-
- // If there is no tile at the top, meaning that the room has no tiles, exit
- if (topMin === Number.MAX_VALUE) {
- return null;
- }
-
- // Find the left-most tile at the top and the length of its adjacent tiles to the right
- const topTilePositions: number[] = [];
- room.tiles.forEach((tile: ITile) => {
- if (tile.position.y === topMin) {
- topTilePositions.push(tile.position.x);
- }
- });
- topTilePositions.sort();
- const leftMin = topTilePositions[0];
- let length = 0;
-
- while (length < topTilePositions.length && topTilePositions[length] - leftMin === length) {
- length++;
- }
-
- result.topLeft.x = leftMin;
- result.topLeft.y = topMin;
- result.length = length;
-
- return result;
- }
-
- /**
- * Analyzes an array of objects and calculates its fill ratio, by looking at the number of elements != null and
- * comparing that number to the array length.
- *
- * @param inputList The list to be analyzed
- * @returns {number} A fill ratio (between 0 and 1), representing the relative amount of objects != null in the list
- */
- public static getFillRatio(inputList: any[]): number {
- let numNulls = 0;
-
- if (inputList.length === 0) {
- return 0;
- }
-
- inputList.forEach((element: any) => {
- if (element == null) {
- numNulls++;
- }
- });
-
- return (inputList.length - numNulls) / inputList.length;
- }
-
- /**
- * Calculates the energy consumption ration of the given rack.
- *
- * @param rack The rack of which the power consumption should be analyzed
- * @returns {number} The energy consumption ratio
- */
- public static getEnergyRatio(rack: IRack): number {
- let energySum = 0;
-
- rack.machines.forEach((machine: IMachine) => {
- if (machine === null) {
- return;
- }
-
- let machineConsumption = 0;
-
- let nodeUnitList: INodeUnit[] = <INodeUnit[]>machine.cpus.concat(machine.gpus);
- nodeUnitList = nodeUnitList.concat(<INodeUnit[]>machine.memories);
- nodeUnitList = nodeUnitList.concat(<INodeUnit[]>machine.storages);
- nodeUnitList.forEach((unit: INodeUnit) => {
- machineConsumption += unit.energyConsumptionW;
- });
-
- energySum += machineConsumption;
- });
-
- return energySum / rack.powerCapacityW;
- }
-
- /**
- * Parses date-time expresses of the form YYYY-MM-DDTHH:MM:SS and returns a parsed object.
- *
- * @param input A string expressing a date and a time, in the above mentioned format
- * @returns {IDateTime} A DateTime object with the parsed date and time information as content
- */
- public static parseDateTime(input: string): IDateTime {
- const output: IDateTime = {
- year: 0,
- month: 0,
- day: 0,
- hour: 0,
- minute: 0,
- second: 0
- };
-
- const dateAndTime = input.split("T");
- const dateComponents = dateAndTime[0].split("-");
- output.year = parseInt(dateComponents[0], 10);
- output.month = parseInt(dateComponents[1], 10);
- output.day = parseInt(dateComponents[2], 10);
-
- const timeComponents = dateAndTime[1].split(":");
- output.hour = parseInt(timeComponents[0], 10);
- output.minute = parseInt(timeComponents[1], 10);
- output.second = parseInt(timeComponents[2], 10);
-
- return output;
- }
-
- public static formatDateTime(input: IDateTime) {
- let date;
- const currentDate = new Date();
-
- date = Util.addPaddingToTwo(input.day) + "/" +
- Util.addPaddingToTwo(input.month) + "/" +
- Util.addPaddingToTwo(input.year);
-
- if (input.year === currentDate.getFullYear() &&
- input.month === currentDate.getMonth() + 1) {
- if (input.day === currentDate.getDate()) {
- date = "Today";
- } else if (input.day === currentDate.getDate() - 1) {
- date = "Yesterday";
- }
- }
-
- return date + ", " +
- Util.addPaddingToTwo(input.hour) + ":" +
- Util.addPaddingToTwo(input.minute);
- }
-
- public static getCurrentDateTime(): string {
- const currentDate = new Date();
- return currentDate.getFullYear() + "-" + Util.addPaddingToTwo(currentDate.getMonth() + 1) + "-" +
- Util.addPaddingToTwo(currentDate.getDate()) + "T" + Util.addPaddingToTwo(currentDate.getHours()) + ":" +
- Util.addPaddingToTwo(currentDate.getMinutes()) + ":" + Util.addPaddingToTwo(currentDate.getSeconds());
- }
-
- /**
- * Removes all populated object properties from a given object, and returns a copy without them.
- *
- * An exception of such an object property is made in the case of a position object (of type GridPosition), which
- * is copied over as well.
- *
- * Does not manipulate the original object in any way, except if your object has quantum-like properties, which
- * change upon inspection. In such a case, I'm afraid that this method can do little for you.
- *
- * @param object The input object
- * @returns {any} A copy of the object without any populated properties (of type object).
- */
- public static packageForSending(object: any) {
- const result: any = {};
- for (let prop in object) {
- if (object.hasOwnProperty(prop)) {
- if (typeof object[prop] !== "object") {
- result[prop] = object[prop];
- } else {
- if (object[prop] instanceof Array) {
- if (object[prop].length === 0 || !(object[prop][0] instanceof Object)) {
- result[prop] = [];
- for (let i = 0; i < object[prop].length; i++) {
- result[prop][i] = object[prop][i];
- }
- }
- }
- if (object[prop] != null && object[prop].hasOwnProperty("x") && object[prop].hasOwnProperty("y")) {
- result["positionX"] = object[prop].x;
- result["positionY"] = object[prop].y;
- }
- }
- }
- }
- return result;
- }
-
- public static addPaddingToTwo(integer: number): string {
- if (integer < 10) {
- return "0" + integer.toString();
- } else {
- return integer.toString();
- }
- }
-
- public static convertSecondsToFormattedTime(seconds: number): string {
- let hour = Math.floor(seconds / 3600);
- let minute = Math.floor(seconds / 60) % 60;
- let second = seconds % 60;
-
- hour = isNaN(hour) ? 0 : hour;
- minute = isNaN(minute) ? 0 : minute;
- second = isNaN(second) ? 0 : second;
-
- return this.addPaddingToTwo(hour) + ":" +
- this.addPaddingToTwo(minute) + ":" +
- this.addPaddingToTwo(second);
- }
-
- public static determineLoadIntensityLevel(loadFraction: number): IntensityLevel {
- if (loadFraction < 0.25) {
- return IntensityLevel.LOW;
- } else if (loadFraction < 0.5) {
- return IntensityLevel.MID_LOW;
- } else if (loadFraction < 0.75) {
- return IntensityLevel.MID_HIGH;
- } else {
- return IntensityLevel.HIGH;
- }
- }
-
- public static convertIntensityToColor(intensityLevel: IntensityLevel): string {
- if (intensityLevel === IntensityLevel.LOW) {
- return Colors.SIM_LOW;
- } else if (intensityLevel === IntensityLevel.MID_LOW) {
- return Colors.SIM_MID_LOW;
- } else if (intensityLevel === IntensityLevel.MID_HIGH) {
- return Colors.SIM_MID_HIGH;
- } else if (intensityLevel === IntensityLevel.HIGH) {
- return Colors.SIM_HIGH;
- }
- }
-
- /**
- * Gives the sentence-cased alternative for a given string.
- *
- * @example Input: TEST, Output: Test
- *
- * @param input The input string
- * @returns {any} The sentence-cased string
- */
- public static toSentenceCase(input: string): string {
- if (input === undefined || input === null) {
- return undefined;
- }
- if (input.length === 0) {
- return "";
- }
-
- return input[0].toUpperCase() + input.substr(1).toLowerCase();
- }
-
- /**
- * Sort a list of authorizations based on the levels of authorizations.
- *
- * @param list The list to be sorted (in-place)
- */
- public static sortAuthorizations(list: IAuthorization[]): void {
- list.sort((a: IAuthorization, b: IAuthorization): number => {
- return this.authorizationLevels.indexOf(a.authorizationLevel) -
- this.authorizationLevels.indexOf(b.authorizationLevel);
- });
- }
-
- /**
- * Returns an array containing all numbers of a range from 0 to x (including x).
- */
- public static range(x: number): number[] {
- return Array.apply(null, Array(x + 1)).map((_, i) => {
- return i.toString();
- })
- }
-
- /**
- * Returns an array containing all numbers of a range from 0 to x (including x).
- */
- public static timeRange(x: number): Date[] {
- return Util.range(x).map((tick: number) => {
- const t = new Date(1970, 0, 1); // Epoch
- t.setSeconds(tick);
- return t;
- });
- }
-}
diff --git a/src/scripts/views/layers/dcobject.ts b/src/scripts/views/layers/dcobject.ts
deleted file mode 100644
index f883a218..00000000
--- a/src/scripts/views/layers/dcobject.ts
+++ /dev/null
@@ -1,250 +0,0 @@
-import {Colors} from "../../colors";
-import {Util, IntensityLevel} from "../../util";
-import {MapView} from "../mapview";
-import {DCProgressBar} from "./dcprogressbar";
-import {Layer} from "./layer";
-import {CELL_SIZE} from "../../controllers/mapcontroller";
-
-
-export class DCObjectLayer implements Layer {
- public static ITEM_MARGIN = CELL_SIZE / 7.0;
- public static ITEM_PADDING = CELL_SIZE / 10.0;
- public static STROKE_WIDTH = CELL_SIZE / 20.0;
- public static PROGRESS_BAR_DISTANCE = CELL_SIZE / 17.0;
- public static CONTENT_SIZE = CELL_SIZE - DCObjectLayer.ITEM_MARGIN * 2 - DCObjectLayer.ITEM_PADDING * 3;
-
- public container: createjs.Container;
- public detailedMode: boolean;
- public coloringMode: boolean;
- public intensityLevels: { [key: number]: IntensityLevel; } = {};
-
- private mapView: MapView;
- private preload: createjs.LoadQueue;
- private rackSpaceBitmap: createjs.Bitmap;
- private rackEnergyBitmap: createjs.Bitmap;
- private psuBitmap: createjs.Bitmap;
- private coolingItemBitmap: createjs.Bitmap;
-
- // This associative lookup object keeps all DC display objects with as property name the index of the global map
- // array that they are located in.
- private dcObjectMap: { [key: number]: any; };
-
-
- public static drawHoverRack(position: IGridPosition): createjs.Container {
- const result = new createjs.Container();
-
- DCObjectLayer.drawItemRectangle(
- position, Colors.RACK_BACKGROUND, Colors.RACK_BORDER, result
- );
- DCProgressBar.drawItemProgressRectangle(
- position, Colors.RACK_SPACE_BAR_BACKGROUND, result, 0, 1
- );
- DCProgressBar.drawItemProgressRectangle(
- position, Colors.RACK_ENERGY_BAR_BACKGROUND, result, 1, 1
- );
-
- return result;
- }
-
- public static drawHoverPSU(position: IGridPosition): createjs.Container {
- const result = new createjs.Container();
-
- DCObjectLayer.drawItemRectangle(
- position, Colors.PSU_BACKGROUND, Colors.PSU_BORDER, result
- );
-
- return result;
- }
-
- public static drawHoverCoolingItem(position: IGridPosition): createjs.Container {
- const result = new createjs.Container();
-
- DCObjectLayer.drawItemRectangle(
- position, Colors.COOLING_ITEM_BACKGROUND, Colors.COOLING_ITEM_BORDER, result
- );
-
- return result;
- }
-
- /**
- * Draws an object rectangle in a given grid cell, with margin around its border.
- *
- * @param position The coordinates of the grid cell in which it should be located
- * @param color The background color of the item
- * @param borderColor The border color
- * @param container The container to which it should be drawn
- * @returns {createjs.Shape} The drawn shape
- */
- private static drawItemRectangle(position: IGridPosition, color: string, borderColor: string,
- container: createjs.Container): createjs.Shape {
- const shape = new createjs.Shape();
- shape.graphics.beginStroke(borderColor);
- shape.graphics.setStrokeStyle(DCObjectLayer.STROKE_WIDTH);
- shape.graphics.beginFill(color);
- shape.graphics.drawRect(
- position.x * CELL_SIZE + DCObjectLayer.ITEM_MARGIN,
- position.y * CELL_SIZE + DCObjectLayer.ITEM_MARGIN,
- CELL_SIZE - DCObjectLayer.ITEM_MARGIN * 2,
- CELL_SIZE - DCObjectLayer.ITEM_MARGIN * 2
- );
- container.addChild(shape);
- return shape;
- }
-
- /**
- * Draws an bitmap in item format.
- *
- * @param position The coordinates of the grid cell in which it should be located
- * @param container The container to which it should be drawn
- * @param originBitmap The bitmap that should be drawn
- * @returns {createjs.Bitmap} The drawn bitmap
- */
- private static drawItemIcon(position: IGridPosition, container: createjs.Container,
- originBitmap: createjs.Bitmap): createjs.Bitmap {
- const bitmap = originBitmap.clone();
- container.addChild(bitmap);
- bitmap.x = position.x * CELL_SIZE + DCObjectLayer.ITEM_MARGIN + DCObjectLayer.ITEM_PADDING * 1.5;
- bitmap.y = position.y * CELL_SIZE + DCObjectLayer.ITEM_MARGIN + DCObjectLayer.ITEM_PADDING * 1.5;
- return bitmap;
- }
-
- constructor(mapView: MapView) {
- this.mapView = mapView;
- this.container = new createjs.Container();
-
- this.detailedMode = true;
- this.coloringMode = false;
-
- this.preload = new createjs.LoadQueue();
- this.preload.addEventListener("complete", () => {
- this.rackSpaceBitmap = new createjs.Bitmap(<HTMLImageElement>this.preload.getResult("rack-space"));
- this.rackEnergyBitmap = new createjs.Bitmap(<HTMLImageElement>this.preload.getResult("rack-energy"));
- this.psuBitmap = new createjs.Bitmap(<HTMLImageElement>this.preload.getResult("psu"));
- this.coolingItemBitmap = new createjs.Bitmap(<HTMLImageElement>this.preload.getResult("coolingitem"));
-
- // Scale the images
- this.rackSpaceBitmap.scaleX = DCProgressBar.PROGRESS_BAR_WIDTH / this.rackSpaceBitmap.image.width;
- this.rackSpaceBitmap.scaleY = DCProgressBar.PROGRESS_BAR_WIDTH / this.rackSpaceBitmap.image.height;
-
- this.rackEnergyBitmap.scaleX = DCProgressBar.PROGRESS_BAR_WIDTH / this.rackEnergyBitmap.image.width;
- this.rackEnergyBitmap.scaleY = DCProgressBar.PROGRESS_BAR_WIDTH / this.rackEnergyBitmap.image.height;
-
- this.psuBitmap.scaleX = DCObjectLayer.CONTENT_SIZE / this.psuBitmap.image.width;
- this.psuBitmap.scaleY = DCObjectLayer.CONTENT_SIZE / this.psuBitmap.image.height;
-
- this.coolingItemBitmap.scaleX = DCObjectLayer.CONTENT_SIZE / this.coolingItemBitmap.image.width;
- this.coolingItemBitmap.scaleY = DCObjectLayer.CONTENT_SIZE / this.coolingItemBitmap.image.height;
-
-
- this.populateObjectList();
- this.draw();
-
- this.mapView.updateScene = true;
- });
-
- this.preload.loadFile({id: "rack-space", src: 'img/app/rack-space.png'});
- this.preload.loadFile({id: "rack-energy", src: 'img/app/rack-energy.png'});
- this.preload.loadFile({id: "psu", src: 'img/app/psu.png'});
- this.preload.loadFile({id: "coolingitem", src: 'img/app/coolingitem.png'});
- }
-
- /**
- * Generates a list of DC objects with their associated display objects.
- */
- public populateObjectList(): void {
- this.dcObjectMap = {};
-
- this.mapView.currentDatacenter.rooms.forEach((room: IRoom) => {
- room.tiles.forEach((tile: ITile) => {
- if (tile.object !== undefined) {
- const index = tile.position.y * MapView.MAP_SIZE + tile.position.x;
-
- switch (tile.objectType) {
- case "RACK":
- this.dcObjectMap[index] = {
- spaceBar: new DCProgressBar(this.container,
- Colors.RACK_SPACE_BAR_BACKGROUND, Colors.RACK_SPACE_BAR_FILL,
- this.rackSpaceBitmap, tile.position, 0,
- Util.getFillRatio((<IRack>tile.object).machines)),
- energyBar: new DCProgressBar(this.container,
- Colors.RACK_ENERGY_BAR_BACKGROUND, Colors.RACK_ENERGY_BAR_FILL,
- this.rackEnergyBitmap, tile.position, 1,
- Util.getFillRatio((<IRack>tile.object).machines)),
- itemRect: createjs.Shape,
- tile: tile, model: tile.object, position: tile.position, type: tile.objectType
- };
-
- break;
- case "COOLING_ITEM":
- this.dcObjectMap[index] = {
- itemRect: createjs.Shape, batteryIcon: createjs.Bitmap,
- tile: tile, model: tile.object, position: tile.position, type: tile.objectType
- };
- break;
- case "PSU":
- this.dcObjectMap[index] = {
- itemRect: createjs.Shape, freezeIcon: createjs.Bitmap,
- tile: tile, model: tile.object, position: tile.position, type: tile.objectType
- };
- break;
- }
- }
- });
- });
- }
-
- public draw(): void {
- this.container.removeAllChildren();
-
- this.container.cursor = "pointer";
-
- for (let property in this.dcObjectMap) {
- if (this.dcObjectMap.hasOwnProperty(property)) {
- const currentObject = this.dcObjectMap[property];
-
- switch (currentObject.type) {
- case "RACK":
- let color = Colors.RACK_BACKGROUND;
-
- if (this.coloringMode && currentObject.tile.roomId ===
- this.mapView.mapController.roomModeController.currentRoom.id) {
- color = Util.convertIntensityToColor(this.intensityLevels[currentObject.model.id]);
- }
-
- currentObject.itemRect = DCObjectLayer.drawItemRectangle(
- currentObject.position, color, Colors.RACK_BORDER, this.container
- );
-
- if (this.detailedMode) {
- currentObject.spaceBar.fillRatio = Util.getFillRatio(currentObject.model.machines);
- currentObject.energyBar.fillRatio = Util.getEnergyRatio(currentObject.model);
-
- currentObject.spaceBar.draw();
- currentObject.energyBar.draw();
- }
- break;
- case "COOLING_ITEM":
- currentObject.itemRect = DCObjectLayer.drawItemRectangle(
- currentObject.position, Colors.COOLING_ITEM_BACKGROUND, Colors.COOLING_ITEM_BORDER,
- this.container
- );
-
- currentObject.freezeIcon = DCObjectLayer.drawItemIcon(currentObject.position, this.container,
- this.coolingItemBitmap);
- break;
- case "PSU":
- currentObject.itemRect = DCObjectLayer.drawItemRectangle(
- currentObject.position, Colors.PSU_BACKGROUND, Colors.PSU_BORDER,
- this.container
- );
-
- currentObject.batteryIcon = DCObjectLayer.drawItemIcon(currentObject.position, this.container,
- this.psuBitmap);
- break;
- }
- }
- }
-
- this.mapView.updateScene = true;
- }
-}
diff --git a/src/scripts/views/layers/dcprogressbar.ts b/src/scripts/views/layers/dcprogressbar.ts
deleted file mode 100644
index e518ead4..00000000
--- a/src/scripts/views/layers/dcprogressbar.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-import {DCObjectLayer} from "./dcobject";
-import {CELL_SIZE} from "../../controllers/mapcontroller";
-
-
-export class DCProgressBar {
- public static PROGRESS_BAR_WIDTH = CELL_SIZE / 7.0;
-
- public container: createjs.Container;
- public fillRatio: number;
-
- private backgroundRect: createjs.Shape;
- private backgroundColor: string;
- private fillRect: createjs.Shape;
- private fillColor: string;
- private bitmap: createjs.Bitmap;
- private position: IGridPosition;
- private distanceFromBottom: number;
-
-
- /**
- * Draws a progress rectangle with rounded ends.
- *
- * @param position The coordinates of the grid cell in which it should be located
- * @param color The background color of the item
- * @param container The container to which it should be drawn
- * @param distanceFromBottom The index of its vertical position, counted from the bottom (0 is the lowest position)
- * @param fractionFilled The fraction of the available horizontal space that the progress bar should take up
- * @returns {createjs.Shape} The drawn shape
- */
- public static drawItemProgressRectangle(position: IGridPosition, color: string,
- container: createjs.Container, distanceFromBottom: number,
- fractionFilled: number): createjs.Shape {
- const shape = new createjs.Shape();
- shape.graphics.beginFill(color);
- let x = position.x * CELL_SIZE + DCObjectLayer.ITEM_MARGIN + DCObjectLayer.ITEM_PADDING;
- let y = (position.y + 1) * CELL_SIZE - DCObjectLayer.ITEM_MARGIN - DCObjectLayer.ITEM_PADDING -
- DCProgressBar.PROGRESS_BAR_WIDTH - distanceFromBottom *
- (DCProgressBar.PROGRESS_BAR_WIDTH + DCObjectLayer.PROGRESS_BAR_DISTANCE);
- let width = (CELL_SIZE - (DCObjectLayer.ITEM_MARGIN + DCObjectLayer.ITEM_PADDING) * 2) * fractionFilled;
- let height;
- let radius;
-
- if (width < DCProgressBar.PROGRESS_BAR_WIDTH) {
- height = width;
- radius = width / 2;
- y += (DCProgressBar.PROGRESS_BAR_WIDTH - height) / 2;
- } else {
- height = DCProgressBar.PROGRESS_BAR_WIDTH;
- radius = DCProgressBar.PROGRESS_BAR_WIDTH / 2;
- }
-
- shape.graphics.drawRoundRect(
- x, y, width, height, radius
- );
- container.addChild(shape);
- return shape;
- }
-
- /**
- * Draws an bitmap in progressbar format.
- *
- * @param position The coordinates of the grid cell in which it should be located
- * @param container The container to which it should be drawn
- * @param originBitmap The bitmap that should be drawn
- * @param distanceFromBottom The index of its vertical position, counted from the bottom (0 is the lowest position)
- * @returns {createjs.Bitmap} The drawn bitmap
- */
- public static drawProgressbarIcon(position: IGridPosition, container: createjs.Container, originBitmap: createjs.Bitmap,
- distanceFromBottom: number): createjs.Bitmap {
- const bitmap = originBitmap.clone();
- container.addChild(bitmap);
- bitmap.x = (position.x + 0.5) * CELL_SIZE - DCProgressBar.PROGRESS_BAR_WIDTH * 0.5;
- bitmap.y = (position.y + 1) * CELL_SIZE - DCObjectLayer.ITEM_MARGIN - DCObjectLayer.ITEM_PADDING -
- DCProgressBar.PROGRESS_BAR_WIDTH - distanceFromBottom *
- (DCProgressBar.PROGRESS_BAR_WIDTH + DCObjectLayer.PROGRESS_BAR_DISTANCE);
- return bitmap;
- }
-
- constructor(container: createjs.Container, backgroundColor: string,
- fillColor: string, bitmap: createjs.Bitmap, position: IGridPosition,
- indexFromBottom: number, fillRatio: number) {
- this.container = container;
- this.backgroundColor = backgroundColor;
- this.fillColor = fillColor;
- this.bitmap = bitmap;
- this.position = position;
- this.distanceFromBottom = indexFromBottom;
- this.fillRatio = fillRatio;
- }
-
- public draw() {
- this.backgroundRect = DCProgressBar.drawItemProgressRectangle(this.position, this.backgroundColor,
- this.container, this.distanceFromBottom, 1);
- this.fillRect = DCProgressBar.drawItemProgressRectangle(this.position, this.fillColor, this.container,
- this.distanceFromBottom, this.fillRatio);
-
- DCProgressBar.drawProgressbarIcon(this.position, this.container, this.bitmap, this.distanceFromBottom);
- }
-}
diff --git a/src/scripts/views/layers/gray.ts b/src/scripts/views/layers/gray.ts
deleted file mode 100644
index 63911d19..00000000
--- a/src/scripts/views/layers/gray.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import {MapView} from "../mapview";
-import {Colors} from "../../colors";
-import {Util} from "../../util";
-import {Layer} from "./layer";
-
-
-/**
- * Class responsible for graying out non-active UI elements.
- */
-export class GrayLayer implements Layer {
- public container: createjs.Container;
- public currentRoom: IRoom;
- public currentObjectTile: ITile;
-
- private mapView: MapView;
- private grayRoomShape: createjs.Shape;
-
-
- constructor(mapView: MapView) {
- this.mapView = mapView;
- this.container = new createjs.Container();
- }
-
- /**
- * Draws grayed out areas around a currently selected room.
- *
- * @param redraw Whether this is a redraw, or an initial draw action
- */
- public draw(redraw?: boolean): void {
- if (this.currentRoom === undefined) {
- return;
- }
-
- this.container.removeAllChildren();
-
- const roomBounds = Util.calculateRoomBounds(this.currentRoom);
-
- const shape = new createjs.Shape();
- shape.graphics.beginFill(Colors.GRAYED_OUT_AREA);
- shape.cursor = "pointer";
-
- this.drawLargeRects(shape, roomBounds);
- this.drawFineGrainedRects(shape, roomBounds);
-
- this.container.addChild(shape);
- if (redraw === true) {
- shape.alpha = 1;
- } else {
- shape.alpha = 0;
- this.mapView.animate(shape, {alpha: 1});
- }
-
- if (this.grayRoomShape !== undefined && !this.grayRoomShape.visible) {
- this.grayRoomShape = undefined;
- this.drawRackLevel(redraw);
- }
-
- this.mapView.updateScene = true;
- }
-
- private drawLargeRects(shape: createjs.Shape, roomBounds: IBounds): void {
- if (roomBounds.min[0] > 0) {
- MapView.drawRectangleToShape({x: 0, y: 0}, shape, roomBounds.min[0], MapView.MAP_SIZE);
- }
- if (roomBounds.min[1] > 0) {
- MapView.drawRectangleToShape({x: roomBounds.min[0], y: 0}, shape, roomBounds.max[0] - roomBounds.min[0],
- roomBounds.min[1]);
- }
- if (roomBounds.max[0] < MapView.MAP_SIZE - 1) {
- MapView.drawRectangleToShape({x: roomBounds.max[0], y: 0}, shape, MapView.MAP_SIZE - roomBounds.max[0],
- MapView.MAP_SIZE);
- }
- if (roomBounds.max[1] < MapView.MAP_SIZE - 1) {
- MapView.drawRectangleToShape({x: roomBounds.min[0], y: roomBounds.max[1]}, shape,
- roomBounds.max[0] - roomBounds.min[0], MapView.MAP_SIZE - roomBounds.max[1]);
- }
- }
-
- private drawFineGrainedRects(shape: createjs.Shape, roomBounds: IBounds): void {
- for (let x = roomBounds.min[0]; x < roomBounds.max[0]; x++) {
- for (let y = roomBounds.min[1]; y < roomBounds.max[1]; y++) {
- if (!Util.tileListContainsPosition(this.currentRoom.tiles, {x: x, y: y})) {
- MapView.drawRectangleToShape({x: x, y: y}, shape);
- }
- }
- }
- }
-
- public drawRackLevel(redraw?: boolean): void {
- if (this.currentObjectTile === undefined) {
- return;
- }
-
- this.grayRoomShape = new createjs.Shape();
- this.grayRoomShape.graphics.beginFill(Colors.GRAYED_OUT_AREA);
- this.grayRoomShape.cursor = "pointer";
- this.grayRoomShape.alpha = 0;
-
- this.currentRoom.tiles.forEach((tile: ITile) => {
- if (this.currentObjectTile.position.x !== tile.position.x ||
- this.currentObjectTile.position.y !== tile.position.y) {
- MapView.drawRectangleToShape({x: tile.position.x, y: tile.position.y}, this.grayRoomShape);
- }
- });
-
- this.container.addChild(this.grayRoomShape);
- if (redraw === true) {
- this.grayRoomShape.alpha = 1;
- } else {
- this.grayRoomShape.alpha = 0;
- this.mapView.animate(this.grayRoomShape, {alpha: 1});
- }
- }
-
- public hideRackLevel(): void {
- if (this.currentObjectTile === undefined) {
- return;
- }
-
- this.mapView.animate(this.grayRoomShape, {
- alpha: 0, visible: false
- });
- }
-
- /**
- * Clears the container.
- */
- public clear(): void {
- this.mapView.animate(this.container, {alpha: 0}, () => {
- this.container.removeAllChildren();
- this.container.alpha = 1;
- });
- this.grayRoomShape = undefined;
- this.currentRoom = undefined;
- }
-
- /**
- * Checks whether there is already an active room with grayed out areas around it.
- *
- * @returns {boolean} Whether the room is grayed out
- */
- public isGrayedOut(): boolean {
- return this.currentRoom !== undefined;
- }
-}
diff --git a/src/scripts/views/layers/grid.ts b/src/scripts/views/layers/grid.ts
deleted file mode 100644
index 9a52b2af..00000000
--- a/src/scripts/views/layers/grid.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import {Layer} from "./layer";
-import {MapView} from "../mapview";
-import {Colors} from "../../colors";
-import {CELL_SIZE} from "../../controllers/mapcontroller";
-
-
-/**
- * Class responsible for rendering the grid.
- */
-export class GridLayer implements Layer {
- public container: createjs.Container;
- public gridPixelSize: number;
-
- private mapView: MapView;
- private gridLineWidth: number;
-
-
- constructor(mapView: MapView) {
- this.mapView = mapView;
- this.container = new createjs.Container();
-
- this.gridLineWidth = 0.5;
- this.gridPixelSize = MapView.MAP_SIZE * CELL_SIZE;
-
- this.draw();
- }
-
- /**
- * Draws the entire grid (later to be navigated around with offsets).
- */
- public draw(): void {
- this.container.removeAllChildren();
-
- let currentCellX = 0;
- let currentCellY = 0;
-
- while (currentCellX <= MapView.MAP_SIZE) {
- MapView.drawLine(
- currentCellX * CELL_SIZE, 0,
- currentCellX * CELL_SIZE, MapView.MAP_SIZE * CELL_SIZE,
- this.gridLineWidth, Colors.GRID_COLOR, this.container);
-
- currentCellX++;
- }
-
- while (currentCellY <= MapView.MAP_SIZE) {
- MapView.drawLine(
- 0, currentCellY * CELL_SIZE,
- MapView.MAP_SIZE * CELL_SIZE, currentCellY * CELL_SIZE,
- this.gridLineWidth, Colors.GRID_COLOR, this.container);
-
- currentCellY++;
- }
- }
-
- public setVisibility(value: boolean): void {
- this.container.visible = value;
- }
-} \ No newline at end of file
diff --git a/src/scripts/views/layers/hover.ts b/src/scripts/views/layers/hover.ts
deleted file mode 100644
index b9f5509c..00000000
--- a/src/scripts/views/layers/hover.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import {Layer} from "./layer";
-import {MapView} from "../mapview";
-import {Colors} from "../../colors";
-import {DCObjectLayer} from "./dcobject";
-import {CELL_SIZE} from "../../controllers/mapcontroller";
-
-
-/**
- * Class responsible for rendering the hover layer.
- */
-export class HoverLayer implements Layer {
- public container: createjs.Container;
- public hoverTilePosition: IGridPosition;
-
- private mapView: MapView;
- private hoverTile: createjs.Shape;
- private hoverRack: createjs.Container;
- private hoverPSU: createjs.Container;
- private hoverCoolingItem: createjs.Container;
-
-
- constructor(mapView: MapView) {
- this.mapView = mapView;
- this.container = new createjs.Container();
-
- this.initialDraw();
- }
-
- /**
- * Draws the hover tile to the container at its current location and with its current color.
- */
- public draw(): void {
- let color;
-
- if (this.mapView.roomLayer.checkHoverTileValidity(this.hoverTilePosition)) {
- color = Colors.ROOM_HOVER_VALID;
- } else {
- color = Colors.ROOM_HOVER_INVALID;
- }
-
- this.hoverTile.graphics.clear().beginFill(color)
- .drawRect(this.hoverTilePosition.x * CELL_SIZE, this.hoverTilePosition.y * CELL_SIZE,
- CELL_SIZE, CELL_SIZE)
- .endFill();
- if (this.hoverRack.visible) {
- this.hoverRack.x = this.hoverTilePosition.x * CELL_SIZE;
- this.hoverRack.y = this.hoverTilePosition.y * CELL_SIZE;
- } else if (this.hoverPSU.visible) {
- this.hoverPSU.x = this.hoverTilePosition.x * CELL_SIZE;
- this.hoverPSU.y = this.hoverTilePosition.y * CELL_SIZE;
- } else if (this.hoverCoolingItem.visible) {
- this.hoverCoolingItem.x = this.hoverTilePosition.x * CELL_SIZE;
- this.hoverCoolingItem.y = this.hoverTilePosition.y * CELL_SIZE;
- }
- }
-
- /**
- * Performs the initial drawing action.
- */
- public initialDraw(): void {
- this.container.removeAllChildren();
-
- this.hoverTile = new createjs.Shape();
-
- this.hoverTilePosition = {x: 0, y: 0};
-
- this.hoverTile = MapView.drawRectangle(this.hoverTilePosition, Colors.ROOM_HOVER_VALID, this.container);
- this.hoverTile.visible = false;
-
- this.hoverRack = DCObjectLayer.drawHoverRack(this.hoverTilePosition);
- this.hoverPSU = DCObjectLayer.drawHoverPSU(this.hoverTilePosition);
- this.hoverCoolingItem = DCObjectLayer.drawHoverCoolingItem(this.hoverTilePosition);
-
- this.container.addChild(this.hoverRack);
- this.container.addChild(this.hoverPSU);
- this.container.addChild(this.hoverCoolingItem);
-
- this.hoverRack.visible = false;
- this.hoverPSU.visible = false;
- this.hoverCoolingItem.visible = false;
- }
-
- /**
- * Sets the hover tile visibility to true/false.
- *
- * @param value The visibility value
- */
- public setHoverTileVisibility(value: boolean): void {
- this.hoverTile.visible = value;
- this.mapView.updateScene = true;
- }
-
- /**
- * Sets the hover item visibility to true/false.
- *
- * @param value The visibility value
- * @param type The type of the object to be shown
- */
- public setHoverItemVisibility(value: boolean, type?: string): void {
- if (value === true) {
- this.hoverTile.visible = true;
-
- this.setHoverItemVisibilities(type);
- } else {
- this.hoverTile.visible = false;
- this.hoverRack.visible = false;
- this.hoverPSU.visible = false;
- this.hoverCoolingItem.visible = false;
- }
-
- this.mapView.updateScene = true;
- }
-
- private setHoverItemVisibilities(type: string): void {
- if (type === "RACK") {
- this.hoverRack.visible = true;
- this.hoverPSU.visible = false;
- this.hoverCoolingItem.visible = false;
- } else if (type === "PSU") {
- this.hoverRack.visible = false;
- this.hoverPSU.visible = true;
- this.hoverCoolingItem.visible = false;
- } else if (type === "COOLING_ITEM") {
- this.hoverRack.visible = false;
- this.hoverPSU.visible = false;
- this.hoverCoolingItem.visible = true;
- }
- }
-} \ No newline at end of file
diff --git a/src/scripts/views/layers/layer.ts b/src/scripts/views/layers/layer.ts
deleted file mode 100644
index 5e5295ac..00000000
--- a/src/scripts/views/layers/layer.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Interface for a subview, representing a layer of the map view.
- */
-export interface Layer {
- container: createjs.Container;
-
- draw(): void;
-}
diff --git a/src/scripts/views/layers/room.ts b/src/scripts/views/layers/room.ts
deleted file mode 100644
index c1989206..00000000
--- a/src/scripts/views/layers/room.ts
+++ /dev/null
@@ -1,177 +0,0 @@
-import {InteractionLevel} from "../../controllers/mapcontroller";
-import {Util, IntensityLevel} from "../../util";
-import {Colors} from "../../colors";
-import {MapView} from "../mapview";
-import {Layer} from "./layer";
-
-
-/**
- * Class responsible for rendering the rooms.
- */
-export class RoomLayer implements Layer {
- public container: createjs.Container;
- public coloringMode: boolean;
- public selectedTiles: ITile[];
- public selectedTileObjects: TilePositionObject[];
- public intensityLevels: { [key: number]: IntensityLevel; } = {};
-
- private mapView: MapView;
- private allRoomTileObjects: TilePositionObject[];
- private validNextTilePositions: IGridPosition[];
-
-
- constructor(mapView: MapView) {
- this.mapView = mapView;
- this.container = new createjs.Container();
-
- this.allRoomTileObjects = [];
- this.selectedTiles = [];
- this.validNextTilePositions = [];
- this.selectedTileObjects = [];
- this.coloringMode = false;
-
- this.draw();
- }
-
- /**
- * Draws all rooms to the canvas.
- */
- public draw() {
- this.container.removeAllChildren();
-
- this.mapView.currentDatacenter.rooms.forEach((room: IRoom) => {
- let color = Colors.ROOM_DEFAULT;
-
- if (this.coloringMode && room.roomType === "SERVER" && this.intensityLevels[room.id] !== undefined) {
- color = Util.convertIntensityToColor(this.intensityLevels[room.id]);
- }
-
- room.tiles.forEach((tile: ITile) => {
- this.allRoomTileObjects.push({
- position: tile.position,
- tileObject: MapView.drawRectangle(tile.position, color, this.container)
- });
- });
- });
- }
-
- /**
- * Adds a newly selected tile to the list of selected tiles.
- *
- * If the tile was already selected beforehand, it is removed.
- *
- * @param tile The tile to be added
- */
- public addSelectedTile(tile: ITile): void {
- this.selectedTiles.push(tile);
-
- const tileObject = MapView.drawRectangle(tile.position, Colors.ROOM_SELECTED, this.container);
- this.selectedTileObjects.push({
- position: {x: tile.position.x, y: tile.position.y},
- tileObject: tileObject
- });
-
- this.validNextTilePositions = Util.deriveValidNextTilePositions(
- this.mapView.currentDatacenter.rooms, this.selectedTiles);
-
- this.mapView.updateScene = true;
- }
-
- /**
- * Removes a selected tile (upon being clicked on again).
- *
- * @param position The position at which a selected tile should be removed
- * @param objectIndex The index of the tile in the selectedTileObjects array
- */
- public removeSelectedTile(position: IGridPosition, objectIndex: number): void {
- const index = Util.tileListPositionIndexOf(this.selectedTiles, position);
-
- // Check whether the given position doesn't belong to an already removed tile
- if (index === -1) {
- return;
- }
-
- this.selectedTiles.splice(index, 1);
-
- this.container.removeChild(this.selectedTileObjects[objectIndex].tileObject);
- this.selectedTileObjects.splice(objectIndex, 1);
-
- this.validNextTilePositions = Util.deriveValidNextTilePositions(
- this.mapView.currentDatacenter.rooms, this.selectedTiles);
-
- this.mapView.updateScene = true;
- }
-
- /**
- * Checks whether a hovered tile is in a valid location.
- *
- * @param position The tile location to be checked
- * @returns {boolean} Whether it is a valid location
- */
- public checkHoverTileValidity(position: IGridPosition): boolean {
- if (this.mapView.mapController.interactionLevel === InteractionLevel.BUILDING) {
- if (this.selectedTiles.length === 0) {
- return !Util.checkRoomCollision(this.mapView.currentDatacenter.rooms, position);
- }
- return Util.positionListContainsPosition(this.validNextTilePositions, position);
- } else if (this.mapView.mapController.interactionLevel === InteractionLevel.ROOM) {
- let valid = false;
- this.mapView.mapController.roomModeController.currentRoom.tiles.forEach((element: ITile) => {
- if (position.x === element.position.x && position.y === element.position.y &&
- element.object === undefined) {
- valid = true;
- }
- });
- return valid;
- }
- }
-
- /**
- * Cancels room tile selection by removing all selected tiles from the scene.
- */
- public cancelRoomConstruction(): void {
- if (this.selectedTiles.length === 0) {
- return;
- }
-
- this.selectedTileObjects.forEach((tileObject: TilePositionObject) => {
- this.container.removeChild(tileObject.tileObject);
- });
-
- this.resetTileLists();
-
- this.mapView.updateScene = true;
- }
-
- /**
- * Finalizes the selected room tiles into a standard room.
- */
- public finalizeRoom(room: IRoom): void {
- if (this.selectedTiles.length === 0) {
- return;
- }
-
- this.mapView.currentDatacenter.rooms.push(room);
-
- this.resetTileLists();
-
- // Trigger a redraw
- this.draw();
- this.mapView.wallLayer.generateWalls();
- this.mapView.wallLayer.draw();
-
- this.mapView.updateScene = true;
- }
-
- private resetTileLists(): void {
- this.selectedTiles = [];
- this.validNextTilePositions = [];
- this.selectedTileObjects = [];
- }
-
- public setClickable(value: boolean): void {
- this.allRoomTileObjects.forEach((tileObj: TilePositionObject) => {
- tileObj.tileObject.cursor = value ? "pointer" : "default";
- });
- }
-}
diff --git a/src/scripts/views/layers/roomtext.ts b/src/scripts/views/layers/roomtext.ts
deleted file mode 100644
index 63fab0ed..00000000
--- a/src/scripts/views/layers/roomtext.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import {MapView} from "../mapview";
-import {Colors} from "../../colors";
-import {Util} from "../../util";
-import {Layer} from "./layer";
-import {CELL_SIZE} from "../../controllers/mapcontroller";
-
-
-export class RoomTextLayer implements Layer {
- private static TEXT_PADDING = 4;
-
- public container: createjs.Container;
-
- private mapView: MapView;
-
-
- constructor(mapView: MapView) {
- this.mapView = mapView;
- this.container = new createjs.Container();
-
- this.draw();
- }
-
- public draw(): void {
- this.container.removeAllChildren();
-
- this.mapView.currentDatacenter.rooms.forEach((room: IRoom) => {
- if (room.name !== "" && room.roomType !== "") {
- this.renderTextOverlay(room);
- }
- });
- }
-
- public setVisibility(value: boolean): void {
- this.mapView.animate(this.container, {alpha: value === true ? 1 : 0});
- }
-
- /**
- * Draws a name and type overlay over the given room.
- */
- private renderTextOverlay(room: IRoom): void {
- if (room.name === null || room.tiles.length === 0) {
- return;
- }
-
- const textPos = Util.calculateRoomNamePosition(room);
-
- const bottomY = this.renderText(room.name, "12px Arial", textPos,
- textPos.topLeft.y * CELL_SIZE + RoomTextLayer.TEXT_PADDING);
- this.renderText("Type: " + Util.toSentenceCase(room.roomType), "10px Arial", textPos, bottomY + 5);
- }
-
- private renderText(text: string, font: string, textPos: IRoomNamePos, startY: number): number {
- const name = new createjs.Text(text, font, Colors.ROOM_NAME_COLOR);
-
- if (name.getMeasuredWidth() > textPos.length * CELL_SIZE - RoomTextLayer.TEXT_PADDING * 2) {
- name.scaleX = name.scaleY = (textPos.length * CELL_SIZE - RoomTextLayer.TEXT_PADDING * 2) /
- name.getMeasuredWidth();
- }
-
- // Position the text to the top left of the selected tile
- name.x = textPos.topLeft.x * CELL_SIZE + RoomTextLayer.TEXT_PADDING;
- name.y = startY;
-
- this.container.addChild(name);
-
- return name.y + name.getMeasuredHeight() * name.scaleY;
- }
-}
diff --git a/src/scripts/views/layers/wall.ts b/src/scripts/views/layers/wall.ts
deleted file mode 100644
index 06ba4675..00000000
--- a/src/scripts/views/layers/wall.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import {Colors} from "../../colors";
-import {MapView} from "../mapview";
-import {Util} from "../../util";
-import {Layer} from "./layer";
-import {CELL_SIZE} from "../../controllers/mapcontroller";
-
-
-/**
- * Class responsible for rendering the walls.
- */
-export class WallLayer implements Layer {
- public container: createjs.Container;
-
- private mapView: MapView;
- private walls: IRoomWall[];
- private wallLineWidth: number;
-
-
- constructor(mapView: MapView) {
- this.mapView = mapView;
- this.container = new createjs.Container();
- this.wallLineWidth = CELL_SIZE / 20.0;
-
- this.generateWalls();
- this.draw();
- }
-
- /**
- * Calls the Util.deriveWallLocations function to generate the wall locations.
- */
- public generateWalls(): void {
- this.walls = Util.deriveWallLocations(this.mapView.currentDatacenter.rooms);
- }
-
- /**
- * Draws all walls to the canvas.
- */
- public draw(): void {
- this.container.removeAllChildren();
-
- // Draw walls
- this.walls.forEach((element: IRoomWall) => {
- if (element.horizontal) {
- MapView.drawLine(
- CELL_SIZE * element.startPos[0] - this.wallLineWidth / 2.0,
- CELL_SIZE * element.startPos[1],
- CELL_SIZE * (element.startPos[0] + element.length) + this.wallLineWidth / 2.0,
- CELL_SIZE * element.startPos[1],
- this.wallLineWidth, Colors.WALL_COLOR, this.container
- );
- } else {
- MapView.drawLine(
- CELL_SIZE * element.startPos[0],
- CELL_SIZE * element.startPos[1] - this.wallLineWidth / 2.0,
- CELL_SIZE * element.startPos[0],
- CELL_SIZE * (element.startPos[1] + element.length) + this.wallLineWidth / 2.0,
- this.wallLineWidth, Colors.WALL_COLOR, this.container
- );
- }
- });
- }
-} \ No newline at end of file
diff --git a/src/scripts/views/mapview.ts b/src/scripts/views/mapview.ts
deleted file mode 100644
index 50fc2e45..00000000
--- a/src/scripts/views/mapview.ts
+++ /dev/null
@@ -1,373 +0,0 @@
-///<reference path="../../../typings/globals/createjs-lib/index.d.ts" />
-///<reference path="../../../typings/globals/easeljs/index.d.ts" />
-///<reference path="../../../typings/globals/tweenjs/index.d.ts" />
-///<reference path="../../../typings/globals/preloadjs/index.d.ts" />
-///<reference path="../definitions.ts" />
-///<reference path="../controllers/mapcontroller.ts" />
-import * as $ from "jquery";
-import {Util} from "../util";
-import {MapController, CELL_SIZE} from "../controllers/mapcontroller";
-import {GridLayer} from "./layers/grid";
-import {RoomLayer} from "./layers/room";
-import {HoverLayer} from "./layers/hover";
-import {WallLayer} from "./layers/wall";
-import {DCObjectLayer} from "./layers/dcobject";
-import {GrayLayer} from "./layers/gray";
-import {RoomTextLayer} from "./layers/roomtext";
-
-
-/**
- * Class responsible for rendering the map, by delegating the rendering tasks to appropriate instances.
- */
-export class MapView {
- public static MAP_SIZE = 100;
- public static CELL_SIZE_METERS = 0.5;
- public static MIN_ZOOM = 0.5;
- public static DEFAULT_ZOOM = 2;
- public static MAX_ZOOM = 6;
- public static GAP_CORRECTION_DELTA = 0.2;
- public static ANIMATION_LENGTH = 250;
-
- // Models
- public simulation: ISimulation;
- public currentDatacenter: IDatacenter;
-
- // Controllers
- public mapController: MapController;
-
- // Canvas objects
- public stage: createjs.Stage;
- public mapContainer: createjs.Container;
-
- // Flag indicating whether the scene should be redrawn
- public updateScene: boolean;
- public animating: boolean;
-
- // Subviews
- public gridLayer: GridLayer;
- public roomLayer: RoomLayer;
- public dcObjectLayer: DCObjectLayer;
- public roomTextLayer: RoomTextLayer;
- public hoverLayer: HoverLayer;
- public wallLayer: WallLayer;
- public grayLayer: GrayLayer;
-
- // Dynamic canvas attributes
- public canvasWidth: number;
- public canvasHeight: number;
-
-
- /**
- * Draws a line from (x1, y1) to (x2, y2).
- *
- * @param x1 The x coord. of start point
- * @param y1 The y coord. of start point
- * @param x2 The x coord. of end point
- * @param y2 The y coord. of end point
- * @param lineWidth The width of the line to be drawn
- * @param color The color to be used
- * @param container The container to be drawn to
- */
- public static drawLine(x1: number, y1: number, x2: number, y2: number,
- lineWidth: number, color: string, container: createjs.Container): createjs.Shape {
- const line = new createjs.Shape();
- line.graphics.setStrokeStyle(lineWidth).beginStroke(color);
- line.graphics.moveTo(x1, y1);
- line.graphics.lineTo(x2, y2);
- container.addChild(line);
- return line;
- }
-
- /**
- * Draws a tile at the given location with the given color.
- *
- * @param position The grid coordinates of the tile
- * @param color The color with which the rectangle should be drawn
- * @param container The container to be drawn to
- * @param sizeX Optional parameter specifying the width of the tile to be drawn (in grid units)
- * @param sizeY Optional parameter specifying the height of the tile to be drawn (in grid units)
- */
- public static drawRectangle(position: IGridPosition, color: string, container: createjs.Container,
- sizeX?: number, sizeY?: number): createjs.Shape {
- const tile = new createjs.Shape();
- tile.graphics.setStrokeStyle(0);
- tile.graphics.beginFill(color);
- tile.graphics.drawRect(
- position.x * CELL_SIZE - MapView.GAP_CORRECTION_DELTA,
- position.y * CELL_SIZE - MapView.GAP_CORRECTION_DELTA,
- CELL_SIZE * (sizeX === undefined ? 1 : sizeX) + MapView.GAP_CORRECTION_DELTA * 2,
- CELL_SIZE * (sizeY === undefined ? 1 : sizeY) + MapView.GAP_CORRECTION_DELTA * 2
- );
- container.addChild(tile);
- return tile;
- }
-
- /**
- * Draws a tile at the given location with the given color, and add it to the given shape object.
- *
- * The fill color must be set beforehand, in order to not set it repeatedly and produce unwanted transparent overlap
- * artifacts.
- *
- * @param position The grid coordinates of the tile
- * @param shape The shape to be drawn to
- * @param sizeX Optional parameter specifying the width of the tile to be drawn (in grid units)
- * @param sizeY Optional parameter specifying the height of the tile to be drawn (in grid units)
- */
- public static drawRectangleToShape(position: IGridPosition, shape: createjs.Shape,
- sizeX?: number, sizeY?: number) {
- shape.graphics.drawRect(
- position.x * CELL_SIZE - MapView.GAP_CORRECTION_DELTA,
- position.y * CELL_SIZE - MapView.GAP_CORRECTION_DELTA,
- CELL_SIZE * (sizeX === undefined ? 1 : sizeX) + MapView.GAP_CORRECTION_DELTA * 2,
- CELL_SIZE * (sizeY === undefined ? 1 : sizeY) + MapView.GAP_CORRECTION_DELTA * 2
- );
- }
-
- constructor(simulation: ISimulation, stage: createjs.Stage) {
- this.simulation = simulation;
- const path = this.simulation.paths[this.simulation.paths.length - 1];
- this.currentDatacenter = path.sections[path.sections.length - 1].datacenter;
-
- this.stage = stage;
-
- console.log("THE DATA", simulation);
-
- const canvas = $("#main-canvas");
- this.canvasWidth = canvas.width();
- this.canvasHeight = canvas.height();
-
- this.mapContainer = new createjs.Container();
-
- this.initializeLayers();
-
- this.drawMap();
- this.updateScene = true;
- this.animating = false;
-
- this.mapController = new MapController(this);
-
- // Zoom DC to fit, if rooms are present
- if (this.currentDatacenter.rooms.length > 0) {
- this.zoomOutOnDC();
- }
-
- // Checks at every rendering tick whether the scene has changed, and updates accordingly
- createjs.Ticker.addEventListener("tick", (event: createjs.TickerEvent) => {
- if (this.updateScene || this.animating) {
- if (this.mapController.isInHoverMode()) {
- this.hoverLayer.draw();
- }
-
- this.updateScene = false;
- this.stage.update(event);
- }
- });
- }
-
- private initializeLayers(): void {
- this.gridLayer = new GridLayer(this);
- this.roomLayer = new RoomLayer(this);
- this.dcObjectLayer = new DCObjectLayer(this);
- this.roomTextLayer = new RoomTextLayer(this);
- this.hoverLayer = new HoverLayer(this);
- this.wallLayer = new WallLayer(this);
- this.grayLayer = new GrayLayer(this);
- }
-
- /**
- * Triggers a redraw and re-population action on all layers.
- */
- public redrawMap(): void {
- this.gridLayer.draw();
- this.roomLayer.draw();
- this.dcObjectLayer.populateObjectList();
- this.dcObjectLayer.draw();
- this.roomTextLayer.draw();
- this.hoverLayer.initialDraw();
- this.wallLayer.generateWalls();
- this.wallLayer.draw();
- this.grayLayer.draw(true);
- this.updateScene = true;
- }
-
- /**
- * Zooms in on a given position with a given amount.
- *
- * @param position The position that should appear centered after the zoom action
- * @param amount The amount of zooming that should be performed
- */
- public zoom(position: number[], amount: number): void {
- const newZoom = this.mapContainer.scaleX + 0.01 * amount;
-
- // Check whether zooming too far in / out
- if (newZoom > MapView.MAX_ZOOM ||
- newZoom < MapView.MIN_ZOOM) {
- return;
- }
-
- // Calculate position difference if zoomed, in order to later compensate for this
- // unwanted movement
- const oldPosition = [
- position[0] - this.mapContainer.x, position[1] - this.mapContainer.y
- ];
- const newPosition = [
- (oldPosition[0] / this.mapContainer.scaleX) * newZoom,
- (oldPosition[1] / this.mapContainer.scaleX) * newZoom
- ];
- const positionDelta = [
- newPosition[0] - oldPosition[0], newPosition[1] - oldPosition[1]
- ];
-
- // Apply the transformation operation to keep the selected position static
- const newX = this.mapContainer.x - positionDelta[0];
- const newY = this.mapContainer.y - positionDelta[1];
-
- const finalPos = this.mapController.checkCanvasMovement(newX, newY, newZoom);
-
- if (!this.animating) {
- this.animate(this.mapContainer, {
- scaleX: newZoom, scaleY: newZoom,
- x: finalPos.x, y: finalPos.y
- });
- }
- }
-
- /**
- * Adjusts the viewing scale to fully display a selected room and center it in view.
- *
- * @param room The room to be centered
- * @param redraw Optional argument specifying whether this is a scene redraw
- */
- public zoomInOnRoom(room: IRoom, redraw?: boolean): void {
- this.zoomInOnRooms([room]);
-
- if (redraw === undefined || redraw === false) {
- if (!this.grayLayer.isGrayedOut()) {
- this.grayLayer.currentRoom = room;
- this.grayLayer.draw();
- }
- }
-
- this.updateScene = true;
- }
-
- /**
- * Zooms out to global building view.
- */
- public zoomOutOnDC(): void {
- this.grayLayer.clear();
-
- if (this.currentDatacenter.rooms.length > 0) {
- this.zoomInOnRooms(this.currentDatacenter.rooms);
- }
-
- this.updateScene = true;
- }
-
- /**
- * Fits a given list of rooms to view, by scaling the viewport appropriately and moving the mapContainer.
- *
- * @param rooms The array of rooms to be viewed
- */
- private zoomInOnRooms(rooms: IRoom[]): void {
- const bounds = Util.calculateRoomListBounds(rooms);
- const newScale = this.calculateNewScale(bounds);
-
- // Coordinates of the center of the room, relative to the global origin of the map
- const roomCenterCoords = [
- bounds.center[0] * CELL_SIZE * newScale,
- bounds.center[1] * CELL_SIZE * newScale
- ];
- // Coordinates of the center of the stage (the visible part of the canvas), relative to the global map origin
- const stageCenterCoords = [
- -this.mapContainer.x + this.canvasWidth / 2,
- -this.mapContainer.y + this.canvasHeight / 2
- ];
-
- const newX = this.mapContainer.x - roomCenterCoords[0] + stageCenterCoords[0];
- const newY = this.mapContainer.y - roomCenterCoords[1] + stageCenterCoords[1];
-
- const newPosition = this.mapController.checkCanvasMovement(newX, newY, newScale);
-
- this.animate(this.mapContainer, {
- scaleX: newScale, scaleY: newScale,
- x: newPosition.x, y: newPosition.y
- });
- }
-
- private calculateNewScale(bounds: IBounds): number {
- const viewPadding = 30;
- const sideMenuWidth = 350;
-
- const width = bounds.max[0] - bounds.min[0];
- const height = bounds.max[1] - bounds.min[1];
-
- const scaleX = (this.canvasWidth - 2 * sideMenuWidth) / (width * CELL_SIZE + 2 * viewPadding);
- const scaleY = this.canvasHeight / (height * CELL_SIZE + 2 * viewPadding);
-
- let newScale = Math.min(scaleX, scaleY);
-
- if (this.mapContainer.scaleX > MapView.MAX_ZOOM) {
- newScale = MapView.MAX_ZOOM;
- } else if (this.mapContainer.scaleX < MapView.MIN_ZOOM) {
- newScale = MapView.MIN_ZOOM;
- }
-
- return newScale;
- }
-
- /**
- * Draws all tiles contained in the MapModel.
- */
- private drawMap(): void {
- // Create and draw the container for the entire map
- const gridPixelSize = CELL_SIZE * MapView.MAP_SIZE;
-
- // Add a white background to the entire container
- const background = new createjs.Shape();
- background.graphics.beginFill("#fff");
- background.graphics.drawRect(0, 0,
- gridPixelSize, gridPixelSize);
- this.mapContainer.addChild(background);
-
- this.stage.addChild(this.mapContainer);
-
- // Set the map container to a default offset and zoom state (overridden if rooms are present)
- this.mapContainer.x = -50;
- this.mapContainer.y = -50;
- this.mapContainer.scaleX = this.mapContainer.scaleY = MapView.DEFAULT_ZOOM;
-
- this.addLayerContainers();
- }
-
- private addLayerContainers(): void {
- this.mapContainer.addChild(this.gridLayer.container);
- this.mapContainer.addChild(this.roomLayer.container);
- this.mapContainer.addChild(this.dcObjectLayer.container);
- this.mapContainer.addChild(this.roomTextLayer.container);
- this.mapContainer.addChild(this.hoverLayer.container);
- this.mapContainer.addChild(this.wallLayer.container);
- this.mapContainer.addChild(this.grayLayer.container);
- }
-
- /**
- * Wrapper function for TweenJS animate functionality.
- *
- * @param target What to animate
- * @param properties Properties to be passed on to TweenJS
- * @param callback To be called when animation ready
- */
- public animate(target: any, properties: any, callback?: () => any): void {
- this.animating = true;
- createjs.Tween.get(target)
- .to(properties, MapView.ANIMATION_LENGTH, createjs.Ease.getPowInOut(4))
- .call(() => {
- this.animating = false;
- this.updateScene = true;
-
- if (callback !== undefined) {
- callback();
- }
- });
- }
-}
diff --git a/src/styles/404.less b/src/styles/404.less
deleted file mode 100644
index 8842b621..00000000
--- a/src/styles/404.less
+++ /dev/null
@@ -1,147 +0,0 @@
-html, body {
- padding: 0;
- margin: 0;
- width: 100%;
- height: 100%;
-
- background-image: linear-gradient(135deg, #00678a, #008fbf, #00A6D6);
-}
-
-.terminal-window {
- width: 600px;
- height: 400px;
- display: block;
-
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
-
- margin: auto;
-
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- cursor: default;
-
- overflow: hidden;
-
- box-shadow: 5px 5px 20px #444444;
-}
-
-.terminal-header {
- font-family: monospace;
- background: #cccccc;
- color: #444444;
- height: 30px;
- line-height: 30px;
- padding-left: 10px;
-
- border-top-left-radius: 7px;
- border-top-right-radius: 7px;
-}
-
-.terminal-body {
- font-family: monospace;
- text-align: center;
- background-color: #333333;
- color: #eeeeee;
- padding: 10px;
-
- height: 100%;
-}
-
-.segfault {
- text-align: left;
-}
-
-.cursor {
- -webkit-animation: 1s blink step-end infinite;
- -moz-animation: 1s blink step-end infinite;
- -ms-animation: 1s blink step-end infinite;
- -o-animation: 1s blink step-end infinite;
- animation: 1s blink step-end infinite;
-}
-
-.code-block {
- white-space: pre-wrap;
-
- margin-top: 60px;
-}
-
-.sub-title {
- margin-top: 20px;
-}
-
-.home-btn {
- margin-top: 10px;
- padding: 5px;
- display: inline-block;
- border: 1px solid #eeeeee;
- color: #eeeeee;
- text-decoration: none;
- cursor: pointer;
-
- -webkit-transition: all 200ms;
- -moz-transition: all 200ms;
- -ms-transition: all 200ms;
- -o-transition: all 200ms;
- transition: all 200ms;
-}
-
-.home-btn:hover {
- background: #eeeeee;
- color: #333333;
-}
-
-.home-btn:active {
- background: #333333;
- color: #eeeeee;
-}
-
-@keyframes blink {
- from, to {
- color: #eeeeee;
- }
- 50% {
- color: #333333;
- }
-}
-
-@-moz-keyframes blink {
- from, to {
- color: #eeeeee;
- }
- 50% {
- color: #333333;
- }
-}
-
-@-webkit-keyframes blink {
- from, to {
- color: #eeeeee;
- }
- 50% {
- color: #333333;
- }
-}
-
-@-ms-keyframes blink {
- from, to {
- color: #eeeeee;
- }
- 50% {
- color: #333333;
- }
-}
-
-@-o-keyframes blink {
- from, to {
- color: #eeeeee;
- }
- 50% {
- color: #333333;
- }
-} \ No newline at end of file
diff --git a/src/styles/main.less b/src/styles/main.less
deleted file mode 100644
index ee7e56aa..00000000
--- a/src/styles/main.less
+++ /dev/null
@@ -1,1196 +0,0 @@
-/* Colors */
-@gray-dark: #aaa;
-@gray-semi-dark: #bbb;
-@gray-semi-light: #ccc;
-@gray-light: #ddd;
-@gray-very-light: #eee;
-@blue: #00A6D6;
-@blue-dark: #0087b5;
-@blue-very-dark: #006182;
-@blue-light: #deebf7;
-
-/* Sizes, Margins and Paddings*/
-@document-padding: 20px;
-@inter-element-margin: 5px;
-@standard-border-radius: 5px;
-@side-menu-width: 350px;
-@color-indicator-width: 140px;
-
-@global-padding: 30px;
-@transition-length: 150ms;
-@side-bar-width: 250px;
-@navbar-height: 50px;
-
-html, body {
- width: 100%;
- height: 100%;
- margin: 0;
-
- font-family: Helvetica, Verdana, sans-serif;
-
- overflow: hidden;
-
- background: #eee;
-}
-
-a:hover {
- text-decoration: none;
-}
-
-#main-canvas {
- float: left;
-}
-
-.app-content {
- position: relative;
- width: 100%;
- height: 100%;
-
- z-index: 1;
-}
-
-/* Mixin for cross-platform prevention of user-text-selection */
-.user-select-def {
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-/* Mixin for cross-platform transitions */
-.transition-def(@property, @time) {
- -webkit-transition: @property @time;
- -moz-transition: @property @time;
- -ms-transition: @property @time;
- -o-transition: @property @time;
- transition: @property @time;
-}
-
-/* Mixin for cross-platform border-radius properties */
-.border-radius-def(@length) {
- -webkit-border-radius: @length;
- -moz-border-radius: @length;
- border-radius: @length;
-}
-
-/* General Button Abstractions */
-.clickable {
- cursor: pointer;
- .user-select-def;
-}
-
-.button {
- text-align: center;
- padding: 5px;
-
- background-color: @gray-semi-dark;
-
- .border-radius-def(@standard-border-radius);
- .clickable;
-
- .transition-def(all, 200ms);
-}
-
-.button:hover {
- background-color: @gray-semi-light;
-}
-
-.button:active {
- background-color: @gray-dark;
-}
-
-/* Container for menu panels */
-.side-menu-container {
- display: inline-block;
- position: absolute;
- top: @document-padding;
- width: @side-menu-width;
- height: calc(100% - @document-padding);
- margin-top: 10px;
-
- pointer-events: none;
-}
-
-.left-side {
- left: @document-padding;
-}
-
-.right-side {
- right: @document-padding;
-}
-
-.right-middle-side {
- right: @document-padding * 2 + @side-menu-width;
-}
-
-/* Collapsible menu panel */
-.menu-container {
- margin-bottom: 10px;
- border: 1px solid @gray-dark;
-
- -webkit-border-radius: @standard-border-radius;
- -moz-border-radius: @standard-border-radius;
- border-radius: @standard-border-radius;
-
- overflow: hidden;
- pointer-events: all;
-}
-
-.menu-header-bar {
- display: block;
- padding: 5px;
-
- font-weight: bold;
-
- background-color: @gray-semi-light;
- border-bottom-width: 0;
-}
-
-.menu-body {
- display: block;
- padding: 10px 5px;
-
- background-color: @gray-very-light;
-
- .dropdown {
- margin: @inter-element-margin 0;
- display: inline-block;
- }
-
- .dropdown-label {
- display: inline-block;
- margin-right: 10px;
- }
-}
-
-.menu-body.simulation {
- display: none;
-}
-
-.side-menu-container .menu-collapse, .side-menu-container .menu-exit {
- display: inline-block;
- float: right;
- width: 20px;
- height: 20px;
-
- text-align: center;
- line-height: 20px;
- padding: 0;
- font-size: 9pt;
-
- color: #777;
-}
-
-#room-menu {
- .input-group {
- margin-bottom: 5px;
- }
-
- label {
- margin-top: 10px;
- }
-}
-
-#room-construction-cancel {
- display: none;
-}
-
-/* DC components */
-.dc-component-container {
- .border-radius-def(@standard-border-radius);
-
- margin-bottom: @inter-element-margin;
- padding: 10px;
-
- cursor: pointer;
-
- .transition-def(background-color, 150ms);
-
- .dc-component {
- display: inline-block;
- width: 50px;
- height: 50px;
- float: left;
-
- border: 4px solid #000;
- }
-
- .dc-component-label {
- display: inline-block;
- padding-left: 20px;
- line-height: 50px;
- font-size: 1.3em;
- }
-}
-
-.dc-component-container:hover {
- background-color: @gray-semi-dark;
-}
-
-.dc-component-container:active {
- background-color: @blue-dark;
-}
-
-.dc-component-container[data-active="true"] {
- background-color: @blue;
-}
-
-/* DC Object colors */
-.dc-rack {
- background-color: rgb(170, 170, 170);
-}
-
-.dc-psu {
- background-color: rgb(230, 50, 60);
-}
-
-.dc-cooling-item {
- background-color: rgb(40, 50, 230);
-}
-
-/* Rack menu */
-.node-list-container {
- border: 2px solid #000000;
- overflow: auto;
- max-height: 300px;
-
- margin: @inter-element-margin 0;
- padding: 0;
- @node-height: 50px;
-
- .node-element {
- position: relative;
-
- @img-size: 34px;
- height: @node-height;
- cursor: hand;
-
- background-color: @gray-semi-light;
-
- .node-element-btn {
- display: inline-block;
- float: left;
- width: 40px;
- height: @node-height - 1px;
-
- color: #000;
-
- line-height: @node-height - 1px;
- text-align: center;
- }
-
- .node-element-btn:hover {
- text-decoration: none;
- }
-
- .node-element-content {
- @element-padding-top: 2px;
- @element-padding-left: 12px;
- @img-margin: 7px;
-
- position: relative;
-
- display: inline-flex;
- overflow: hidden;
- margin: 5px;
- padding: @element-padding-top @element-padding-left;
-
- border: 1px solid #000;
- background: #eeeeee;
-
- img {
- width: @img-size;
- height: @img-size;
- }
-
- img:not(:last-of-type) {
- margin-right: @img-margin;
- }
-
- .icon-overlay {
- position: absolute;
- top: @element-padding-top;
- width: @img-size;
- height: @img-size;
-
- background: #eeeeee;
- opacity: 0.6;
- }
-
- .overlay-cpu {
- left: @element-padding-left;
- }
-
- .overlay-gpu {
- left: @element-padding-left + @img-size + @img-margin;
- }
-
- .overlay-memory {
- left: @element-padding-left + (@img-size + @img-margin) * 2;
- }
-
- .overlay-storage {
- left: @element-padding-left + (@img-size + @img-margin) * 3;
- }
-
- .overlay-network {
- left: @element-padding-left + (@img-size + @img-margin) * 4;
- }
- }
-
- .node-element-number {
- display: inline-block;
- float: right;
- width: 30px;
- height: 100%;
-
- line-height: 50px;
- text-align: right;
- padding-right: 10px;
- }
- }
-
- .node-element:not(:last-of-type) {
- border-bottom: 1px solid #666;
- }
-
- .node-element:last-of-type .node-element-content {
- margin-bottom: 0;
- }
-
- .node-element-overlay {
- position: absolute;
- top: 0;
- left: 0;
-
- width: 100%;
- height: @node-height;
-
- background: #eeeeee;
- opacity: 0.6;
-
- z-index: 100;
- }
-}
-
-#node-menu {
- .nav-tabs {
- li.active, li.active a {
- background-color: @gray-very-light;
- }
-
- img {
- width: 30px;
- height: 30px;
- }
- }
-
- .tab-content {
- overflow: hidden;
-
- .panel-heading .accordion-toggle:after {
- //noinspection CssNoGenericFontName
- font-family: 'Glyphicons Halflings';
- content: "\e114";
- float: right;
- color: grey;
- }
-
- .panel-heading .accordion-toggle.collapsed:after {
- content: "\e080";
- }
- }
-
- .remove-unit:hover {
- text-decoration: none;
- }
-
- .unit-add-input {
- margin-bottom: 10px;
- }
-
- .spec-table td {
- height: 40px;
- line-height: 40px;
- padding: 0 10px;
- }
-
- .spec-table tr td:first-child {
- width: 50px;
- text-align: right;
- }
-
- .spec-table tr td:nth-child(2) {
- width: 200px;
- }
-
- .spec-table tr td:nth-child(3) {
- width: 50px;
- }
-}
-
-/* Tasks menu */
-#tasks-menu .menu-body {
- overflow-y: auto;
- max-height: 350px;
-}
-
-#tasks-menu .menu-body .task-element {
- height: 70px;
-
- .task-icon {
- @icon-size: 35px;
-
- display: inline-block;
- position: relative;
- float: left;
-
- top: 13px;
- left: 10px;
-
- width: @icon-size;
- height: @icon-size;
- font-size: @icon-size;
-
- }
-
- .task-info {
- display: inline-block;
- width: 270px;
- float: right;
-
- .task-time {
- display: block;
- }
-
- .progress {
- margin-bottom: 0;
- }
-
- .task-flops {
- display: block;
- }
- }
-
- &:not(:last-child) {
- border-bottom: 1px solid #bbb;
- margin-bottom: 10px;
- }
-}
-
-#statistics-chart, #machine-statistics-chart {
- display: block;
- height: 200px;
- margin-right: 15px;
-}
-
-/* Container for Zooming buttons */
-.tool-panel {
- display: inline-block;
- position: absolute;
- bottom: @document-padding;
- left: @document-padding;
-
- z-index: 1000;
-}
-
-.btn-circle {
- width: 30px;
- height: 30px;
- text-align: center;
- padding: 6px 0;
- font-size: 12px;
- line-height: 1.428571429;
- border-radius: 15px;
-
- border-color: @gray-dark;
-}
-
-/* Indicators*/
-.indicators {
- display: inline-block;
- position: absolute;
- bottom: @document-padding;
- right: @document-padding;
-}
-
-/* Scale indicator */
-.scale-indicator {
- display: inline-block;
- width: 100px;
- height: 18px;
- line-height: 18px;
-
- text-align: right;
-
- border-top-width: 0;
- border-right-width: 0;
- border-bottom: 2px solid #000;
- border-left: 2px solid #000;
-
- .user-select-def;
-}
-
-/* Color indicator */
-.color-indicator {
- @color-indicator-padding: 7px;
- @element-width: (@color-indicator-width - @color-indicator-padding * 2) / 4;
-
- display: inline-block;
- position: relative;
- top: 5px;
- margin-left: 15px;
- cursor: pointer;
- padding: @color-indicator-padding;
- .border-radius-def(@standard-border-radius);
- .transition-def(background, @transition-length);
- z-index: 100;
-
- width: @color-indicator-width;
-
- &:hover {
- background: rgba(127, 127, 127, 0.5);
- }
-
- .intensity-labels {
- height: 20px;
- line-height: 20px;
-
- font-size: 8pt;
-
- div {
- display: inline-block;
- width: @element-width;
- margin-right: -3px;
-
- text-align: center;
- }
-
- div:first-of-type {
- width: @element-width / 2;
- text-align: left;
- }
-
- div:last-of-type {
- width: @element-width / 2;
- text-align: right;
- }
- }
-
- .intensity-colors {
- height: 15px;
-
- div {
- display: inline-block;
- width: @element-width + 1;
- height: 100%;
- margin-right: -5px;
- border: 1px solid #444;
- }
-
- .intensity-low {
- border-top-left-radius: 4px;
- border-bottom-left-radius: 4px;
- background: rgba(197, 224, 180, 1);
- }
-
- .intensity-mid-low {
- background: rgba(255, 230, 153, 1);
- }
-
- .intensity-mid-high {
- background: rgba(248, 203, 173, 1);
- }
-
- .intensity-high {
- border-top-right-radius: 4px;
- border-bottom-right-radius: 4px;
- background: rgba(249, 165, 165, 1);
- }
- }
-}
-
-@global-control-height: 40px;
-
-/* Mode switch */
-.mode-switch {
- display: block;
- width: 100%;
- height: @global-control-height;
- line-height: @global-control-height;
-
- margin-bottom: 10px;
- pointer-events: all;
-
- background-color: #fff;
- border: 1px solid @gray-dark;
- .border-radius-def(@standard-border-radius);
- overflow: hidden;
-
- div {
- display: inline-block;
- width: 50%;
- height: 100%;
- text-align: center;
-
- font-size: 1.2em;
- .clickable;
- }
-
- div:first-child {
- float: left;
- }
-
- div:last-child {
- float: right;
- }
-}
-
-#save-version-btn {
- width: 50%;
- height: @global-control-height;
- line-height: @global-control-height;
- text-align: center;
- margin-bottom: 10px;
- font-size: 1.2em;
- color: #fff;
-
- .clickable;
- pointer-events: all;
- .border-radius-def(@standard-border-radius);
-}
-
-#save-version-btn[data-saved="true"] {
- background-color: #4dba31;
-
- &:hover {
- background: #3b8e25;
- }
-}
-
-#save-version-btn[data-saved="false"] {
- background-color: #d69931;
-
- &:hover {
- background: #af7b2d;
- }
-}
-
-.mode-switch[data-selected="construction"] {
- #construction-mode-switch {
- background: @blue;
- color: #fff;
- }
-
- #construction-mode-switch:hover {
- background: @blue-dark;
- }
-
- #simulation-mode-switch {
- background: #fff;
- color: #000;
- }
-
- #simulation-mode-switch:hover {
- background: #eee;
- }
-}
-
-.mode-switch[data-selected="simulation"] {
- #construction-mode-switch {
- background: #fff;
- color: #000;
- }
-
- #construction-mode-switch:hover {
- background: #eee;
- }
-
- #simulation-mode-switch {
- background: @blue;
- color: #fff;
- }
-
- #simulation-mode-switch:hover {
- background: @blue-dark;
- }
-}
-
-#experiment-menu h2 {
- margin-top: 0;
- font-size: 12pt;
-}
-
-/* Timeline controls */
-.timeline-bar {
- display: block;
- position: absolute;
- left: 0;
- bottom: @document-padding;
- width: 100%;
- text-align: center;
-}
-
-.timeline-container {
- @container-size: 500px;
- @play-btn-size: 40px;
- @border-width: 1px;
- @timeline-border: @border-width solid @gray-semi-dark;
-
- display: inline-block;
- margin: 0 auto;
- text-align: left;
-
- width: @container-size;
-
- .labels {
- display: block;
- height: 25px;
- line-height: 25px;
-
- div {
- display: inline-block;
- }
-
- .start-time-label {
- margin-left: @play-btn-size - @border-width;
- padding-left: 4px;
- }
-
- .end-time-label {
- padding-right: 4px;
- float: right;
- }
- }
-
- .controls {
- display: flex;
- border: @timeline-border;
- overflow: hidden;
-
- // Fix for border-radius overflow in Chrome/Webkit
- -webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
-
- .border-radius-def(@standard-border-radius);
-
- .play-btn {
- width: @play-btn-size;
- height: @play-btn-size + @border-width;
- line-height: @play-btn-size + @border-width;
- text-align: center;
- float: left;
-
- margin-top: -@border-width;
-
- font-size: 16pt;
- background: #333;
- color: #eee;
-
- .transition-def(background, @transition-length);
-
- .user-select-def;
- .clickable;
-
- // Loading icon
- img {
- display: none;
- position: relative;
- width: 70%;
- height: 70%;
- margin-top: -10px;
- }
- }
-
- .play-btn::before {
- position: relative;
- top: -1px;
- left: 1px;
- }
-
- .play-btn:hover {
- background: #656565;
- }
-
- .play-btn:active {
- background: #000;
- }
-
- .timeline {
- position: relative;
- flex: 1;
- height: @play-btn-size;
- line-height: @play-btn-size;
- float: right;
-
- background: @blue-light;
-
- z-index: 500;
-
- div {
- .transition-def(all, @transition-length);
- }
-
- .time-marker {
- position: absolute;
- top: 0;
- left: 0;
-
- width: 6px;
- height: 100%;
-
- background: @blue-very-dark;
-
- .border-radius-def(2px);
-
- z-index: 503;
- }
-
- .section-marker {
- position: absolute;
- top: 0;
- left: 0;
-
- width: 3px;
- height: 100%;
-
- background: #222222;
-
- z-index: 504;
- }
-
- .cache-section {
- position: absolute;
- top: 0;
- left: 0;
-
- width: 0;
- height: 100%;
-
- background: @blue;
-
- z-index: 501;
- }
-
- .task-indicator {
- display: inline-block;
- position: absolute;
- bottom: 0;
- width: 10px;
- height: 10px;
-
- border: 1px solid #000;
-
- z-index: 502;
- }
-
- .task-queued {
- background: #fff340;
- }
-
- .task-started {
- background: #ff72a0;
- }
-
- .task-finished {
- background: #c036ff;
- }
- }
- }
-}
-
-/* Informational message container, for communicating events to the user */
-.info-balloon {
- display: none;
- position: absolute;
- bottom: @document-padding;
- right: @document-padding;
-
- padding-left: 15px;
- padding-right: 15px;
-
- height: 30px;
- line-height: 30px;
-
- background: @blue;
- color: #fff;
-
- .border-radius-def(15px);
-
- span {
- line-height: 30px;
- margin-right: 10px;
- }
-}
-
-/* Loading overlay, shown during setup */
-.loading-overlay {
- z-index: 1000;
- position: absolute;
- width: 100%;
- height: 100%;
-
- background: rgba(0, 124, 159, 0.7);
-
- .loading-overlay-content {
- text-align: center;
- display: inline-block;
-
- width: 300px;
- height: 200px;
-
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
-
- margin: auto;
-
- img {
- position: relative;
- bottom: -10px;
-
- animation: bounce 3s ease infinite;
- }
-
- .loading-text {
- padding: 3px 10px;
- background-color: #eeeeee;
- .border-radius-def(@standard-border-radius);
- }
- }
-}
-
-@keyframes bounce {
- 0% {
- bottom: -10px;
- }
- 50% {
- bottom: 40px;
- }
- 100% {
- bottom: -10px;
- }
-}
-
-/* Experiments */
-.experiment-list {
- display: block;
- font-size: 12pt;
- border: 0;
-
- .list-head, .list-body .experiment-row {
- display: block;
- position: relative;
- }
-
- .list-head div, .list-body .project-row div {
- padding: 0 10px;
- display: inline-block;
- }
-
- .list-head {
- font-weight: bold;
- }
-
- .list-body {
- max-height: 200px;
- overflow-y: auto;
- overflow-x: hidden;
- }
-
- .experiment-row {
- background: #f8f8f8;
- border: 1px solid #b6b6b6;
- height: 40px;
- line-height: 40px;
- clear: both;
-
- .transition-def(background, @transition-length);
- .clickable;
- }
-
- .experiment-row:hover {
- background: #fff;
- }
-
- .experiment-row:active {
- background: #cccccc;
- }
-
- .experiment-row:not(:first-of-type) {
- margin-top: -1px;
- }
-
- // Sizing of table columns
- .experiment-row, .list-head {
- div {
- display: inline-block;
- width: 20%;
-
- padding-left: 5px;
- margin-right: -4px; // Address default margin between inline-blocks
- }
-
- div:last-of-type {
- text-align: right;
- padding-right: 10px;
- }
- }
-}
-
-.no-experiments-alert {
- display: none;
- position: relative;
- padding-left: 50px;
- span {
- position: absolute;
- top: 11px;
- left: 10px;
- bottom: 10px;
- font-size: 20pt;
- }
-}
-
-.window-overlay {
- display: none;
- position: absolute;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
-
- background: rgba(0, 0, 0, 0.5);
-
- z-index: 5000;
-}
-
-.experiments-window {
- width: 80%;
- height: 80%;
-
- position: absolute;
- left: 0;
- top: 0;
- bottom: 0;
- right: 0;
- margin: auto;
-
- overflow: hidden;
-
- .window-body {
- width: 100%;
- height: 500px;
-
- padding: 10px;
-
- background: rgba(230, 230, 230, 0.9);
-
- .border-radius-def(5px);
-
- .window-heading {
- font-size: 20pt;
- color: #000000;
-
- .user-select-def;
-
- font-weight: bold;
-
- padding-left: 5px;
- }
-
- .experiment-add-form {
- margin: 20px;
-
- input, select {
- width: 200px;
- }
-
- label {
- width: 80px;
- text-align: right;
-
- .user-select-def;
- }
- }
-
- .experiments-table-label {
- display: block;
- padding-left: 20px;
- margin-bottom: 5px;
-
- font-size: 18px;
-
- .user-select-def;
- }
-
- .experiment-name-alert {
- position: absolute;
- bottom: 0;
- left: 20px;
- display: none;
- }
- }
-
- .window-footer {
- width: 100%;
- height: 60px;
-
- background: rgba(56, 56, 56, 0.9);
-
- padding: 12px 10px;
-
- .btn.pull-left {
- margin-right: 5px;
- }
-
- .btn.pull-right {
- margin-left: 5px;
- }
- }
-}
-
-.window-close {
- display: inline-block;
- font-size: 16pt;
- position: absolute;
- top: 10px;
- right: 10px;
- cursor: pointer;
- color: #888888;
-}
-
-/* Internal page */
-/* Main content body (side-menu and main-body) */
-.content {
- position: relative;
- top: -@navbar-height;
- width: 100%;
- height: 100%;
- padding-top: @navbar-height;
- z-index: 1;
-}
-
-/* Content body */
-.main-body {
- position: relative;
- display: block;
- margin: auto;
- width: 900px;
- max-width: 900px;
- height: 100%;
- padding: 40px;
-
- border-left: 1px solid #bbb;
- border-right: 1px solid #bbb;
- background: #f7f7f7;
-
- h2 {
- font-weight: bold;
- margin: 10px 0 20px 0;
- }
-}
-
-.modal {
- z-index: 10000;
-}
diff --git a/src/styles/navbar.less b/src/styles/navbar.less
deleted file mode 100644
index 3eba0982..00000000
--- a/src/styles/navbar.less
+++ /dev/null
@@ -1,158 +0,0 @@
-@import "main.less";
-
-/* Navbar */
-.top-navbar {
- @navbar-padding: 10px;
-
- position: relative;
- display: block;
- width: 100%;
- height: @navbar-height;
-
- color: #eee;
- background: #343434;
-
- z-index: 100;
-
- -webkit-box-shadow: -10px 8px 3px 12px #000;
- -moz-box-shadow: -10px 8px 3px 12px #000;
- box-shadow: -10px -10px 3px 12px #000;
-
- .opendc-brand {
- display: inline-block;
- float: left;
- margin-left: @global-padding;
-
- padding: 0 10px;
-
- cursor: pointer;
- color: #eee;
- height: 100%;
-
- .transition-def(background, @transition-length);
-
- img {
- display: inline-block;
- float: left;
- margin: @navbar-padding 0;
-
- width: @navbar-height - @navbar-padding * 2;
- height: @navbar-height - @navbar-padding * 2;
- vertical-align: middle;
- }
-
- .opendc-title {
- display: inline-block;
- float: right;
- margin-left: 20px;
-
- font-size: 16pt;
- line-height: @navbar-height;
- }
- }
-
- .opendc-brand:hover {
- background: @blue;
- }
-
- .opendc-brand:active {
- background: @blue-dark;
- }
-
- .navbar-button-group {
- display: inline-block;
- height: 100%;
-
- a {
- display: inline-block;
- line-height: @navbar-height;
- text-align: center;
- color: #eee;
-
- border-left: 1px solid #464646;
-
- .clickable;
- .transition-def(background, @transition-length);
- }
-
- a:last-of-type {
- border-right: 1px solid #464646;
- }
- }
-
- .navigation {
- margin-left: 30px;
-
- .projects {
- float: left;
- padding: 0 20px;
-
- font-size: 12pt;
- }
-
- .projects:hover {
- background: #606060;
- }
-
- .projects:active {
- background: #161616;
- }
- }
-
- .user {
- float: right;
- margin-right: @global-padding;
-
- .support {
- float: left;
- margin-top: -1px;
-
- width: @navbar-height;
-
- font-size: 14pt;
- }
-
- .support:hover {
- background: #41a0cd;
- }
-
- .support:active {
- background: #307798;
- }
-
- .username {
- float: left;
- padding: 0 20px;
-
- font-size: 12pt;
- }
-
- .username:hover {
- background: #4eae44;
- }
-
- .username:active {
- background: #2d6527;
- }
-
- .sign-out {
- float: right;
- margin-top: -1px;
- width: @navbar-height;
-
- font-size: 14pt;
- }
-
- .sign-out:hover {
- background: #e3474d;
- }
-
- .sign-out:active {
- background: #a73438;
- }
- }
-}
-
-#google-signin {
- display: none;
-}
diff --git a/src/styles/profile.less b/src/styles/profile.less
deleted file mode 100644
index 40bf49f8..00000000
--- a/src/styles/profile.less
+++ /dev/null
@@ -1,22 +0,0 @@
-@import "main.less";
-
-.main-body.profile-page {
- text-align: center;
-
- :not(.btn) {
- text-align: left;
- }
-}
-
-#delete-account {
- margin: 10px 0;
-}
-
-.delete-info {
- color: #999999;
- padding: 0 80px;
-}
-
-.account-delete-alert {
- display: none;
-} \ No newline at end of file
diff --git a/src/styles/projects.less b/src/styles/projects.less
deleted file mode 100644
index 926ea8ec..00000000
--- a/src/styles/projects.less
+++ /dev/null
@@ -1,391 +0,0 @@
-@import "main.less";
-
-/* Buttons */
-.new-project-btn {
- @button-height: 35px;
-
- display: inline-block;
- position: absolute;
- bottom: 40px;
- right: 40px;
- padding: 0 20px;
- height: @button-height;
- line-height: @button-height;
- font-size: 12pt;
-
- background: #679436;
- color: #eee;
- border: 1px solid #507830;
-
- .border-radius-def(@standard-border-radius);
- .clickable;
- .transition-def(all, @transition-length);
-}
-
-.new-project-btn:hover {
- background: #73ac45;
-}
-
-.new-project-btn:active {
- background: #5c8835;
-}
-
-/* Side menu */
-.filter-menu {
- display: block;
-
- background: #0761b1;
- border: 1px solid #06326b;
- color: #eee;
-
- text-align: center;
-
- .border-radius-def(@standard-border-radius);
- overflow: hidden;
-
- margin-bottom: 20px;
-
- .project-filters {
- display: block;
- overflow: hidden;
- margin-left: -2px;
-
- div {
- display: inline-block;
- width: 33.3%;
- margin-right: -4px;
- padding: 10px @global-padding;
-
- font-size: 12pt;
- border-right: 1px solid #06326b;
-
- .clickable;
- .transition-def(background, @transition-length);
- }
-
- div:last-of-type {
- border: 0;
- }
-
- div:hover {
- background: #0c60bf;
- }
-
- div:active, div.active {
- background: #073d7d;
- }
- }
-}
-
-/* Message shown when no projects present */
-.no-projects-alert {
- display: none;
- position: relative;
- padding-left: 50px;
- span {
- position: absolute;
- top: 11px;
- left: 10px;
- bottom: 10px;
- font-size: 20pt;
- }
-}
-
-/* List of simulation projects */
-.project-list {
- display: block;
- font-size: 12pt;
- border: 0;
-
- .list-head, .list-body .project-row {
- display: block;
- position: relative;
- }
-
- .list-head div, .list-body .project-row div {
- padding: 0 10px;
- display: inline-block;
- }
-
- .list-head {
- font-weight: bold;
-
- div {
- margin-right: -4px; // Address default margin between inline-blocks
- }
- }
-
- .project-row {
- background: #f8f8f8;
- border: 1px solid #b6b6b6;
- height: 40px;
- line-height: 40px;
- clear: both;
-
- .transition-def(background, @transition-length);
- .clickable;
- }
-
- .project-row:hover {
- background: #fff;
- }
-
- .project-row:active {
- background: #cccccc;
- }
-
- .project-row:not(:first-of-type) {
- margin-top: -1px;
- }
-
- // Sizing of table columns
- .project-row, .list-head {
- div:first-of-type {
- width: 50%;
- }
-
- div:nth-of-type(2) {
- width: 30%;
- }
-
- div:last-of-type {
- width: 20%;
-
- span {
- margin-right: 10px;
- }
- }
- }
-
- .project-row.active {
- border-bottom: 0;
- background: #3442b1;
- color: #eee;
- }
-
- .project-row.active::before {
- //noinspection CssNoGenericFontName
- font-family: 'Glyphicons Halflings';
- content: "\2212";
- font-size: 14pt;
- position: absolute;
- top: 0;
- right: 10px;
- }
-
- .project-view {
- padding: 10px;
- overflow: hidden;
- border: 1px solid #b6b6b6;
- border-top: 0;
-
- background: #3442b1;
- color: #eee;
-
- .participants {
- display: inline-block;
- float: left;
- }
-
- .access-buttons {
- display: inline-block;
- float: right;
-
- .inline-btn {
- margin-left: 10px;
- }
-
- .open {
- background: #e38829;
- }
-
- .open:hover {
- background: #ff992e;
- }
-
- .open:active {
- background: #ba6f21;
- }
-
- .edit {
- background: #2c3897;
- }
-
- .edit:hover {
- background: #3a4ac8;
- }
-
- .edit:active {
- background: #242d7a;
- }
- }
- }
-}
-
-.inline-btn {
- display: inline-block;
- height: 30px;
- line-height: 30px;
- font-size: 10pt;
- width: 70px;
-
- text-transform: uppercase;
- text-align: center;
-
- color: #eee;
-
- .clickable;
- .transition-def(background, @transition-length);
-}
-
-.projects-window {
- width: 600px;
- height: 400px;
-
- position: absolute;
- left: 0;
- top: 0;
- bottom: 0;
- right: 0;
- margin: auto;
-
- .border-radius-def(5px);
- overflow: hidden;
-
- .window-body {
- width: 100%;
- height: 340px;
-
- padding: 10px;
-
- background: rgba(230, 230, 230, 0.9);
-
- .window-heading {
- font-size: 20pt;
- color: #000000;
-
- .user-select-def;
-
- font-weight: bold;
-
- padding-left: 5px;
- }
-
- .project-name-form, .participant-add-form {
- margin: 20px;
-
- input {
- width: 300px;
- }
-
- label {
- padding-right: 5px;
- width: 40px;
- text-align: right;
-
- .user-select-def;
- }
- }
-
- .participants-table-label {
- display: block;
- padding-left: 20px;
- margin-bottom: 5px;
-
- .user-select-def;
- }
-
- .participants-table {
- background: #ffffff;
- .border-radius-def(5px);
-
- margin: 0 20px;
-
- max-height: 135px;
- overflow: auto;
-
- .participant-row {
- height: 40px;
- line-height: 40px;
-
- div {
- display: inline-block;
- margin-right: -4px; // Address default margin between inline-blocks
- }
-
- .participant-name {
- padding-left: 10px;
- width: 60%;
- }
-
- .participant-level {
- width: 30%;
-
- .user-select-def;
-
- div {
- display: inline-block;
-
- width: 25px;
- height: 25px;
-
- padding: 5px;
-
- margin-right: 3px;
-
- cursor: pointer;
-
- .border-radius-def(5px);
- .transition-def(all, @transition-length);
- }
-
- div.active, div:hover {
- background-color: #415973;
- color: #eeeeee;
- }
- }
-
- .participant-remove {
- position: relative;
- width: 10%;
- text-align: right;
- padding-right: 10px;
- }
-
- .participant-remove div {
- top: 2px;
- right: 5px;
- cursor: pointer;
- }
- }
- }
-
- .participant-add-form {
- margin-top: 10px;
- }
-
- .participant-email-alert, .project-name-alert {
- position: absolute;
- bottom: 0;
- left: 20px;
- display: none;
- }
- }
-
- .window-footer {
- width: 100%;
- height: 60px;
-
- background: rgba(56, 56, 56, 0.9);
-
- padding: 12px 10px;
-
- .btn.pull-left {
- margin-right: 5px;
- }
-
- .btn.pull-right {
- margin-left: 5px;
- }
- }
-}
diff --git a/src/styles/splash.less b/src/styles/splash.less
deleted file mode 100644
index c462aa43..00000000
--- a/src/styles/splash.less
+++ /dev/null
@@ -1,440 +0,0 @@
-@screen-sm: 768px;
-@screen-md: 992px;
-@screen-lg: 1200px;
-
-html, body {
- width: 100%;
- height: 100%;
- margin: 0;
-}
-
-/* Fix for the white space appearing otherwise on the right of the page, on mobile */
-.body-wrapper {
- overflow-x: hidden;
- overflow-y: hidden;
-}
-
-/* NAVBAR */
-@media screen and (min-width: @screen-sm) {
- .navbar {
- padding: 20px 0;
- -webkit-transition: background 200ms ease-in-out, padding 200ms ease-in-out;
- -moz-transition: background 200ms ease-in-out, padding 200ms ease-in-out;
- transition: background 200ms ease-in-out, padding 200ms ease-in-out;
- }
-
- .top-nav-collapse {
- padding: 0;
- }
-}
-
-.navbar {
- text-transform: uppercase;
-}
-
-.navbar-transparent {
- background: transparent;
- border: none;
-
- .collapse li a, .projects-btn {
- color: #eee;
- }
-}
-
-.navbar-toggle {
- margin-right: 30px;
-}
-
-.navbar-fixed-top {
- padding: 0;
-}
-
-.navbar .logged-in {
- display: none;
-}
-
-.sign-out {
- padding: 10px;
- width: 40px;
- margin-top: 5px;
- margin-left: 5px;
-
- font-size: 14pt;
- color: #eeeeee;
-
- -webkit-border-radius: 25px;
- -moz-border-radius: 25px;
- border-radius: 25px;
-
- -webkit-transition: background 200ms;
- -moz-transition: background 200ms;
- -ms-transition: background 200ms;
- -o-transition: background 200ms;
- transition: background 200ms;
-}
-
-.sign-out:hover {
- background: #e3474d;
- color: #eeeeee;
-}
-
-.sign-out:active {
- background: #a73438;
-}
-
-.projects-btn {
- position: relative;
- top: -4px;
- color: #eee;
-}
-
-.projects-btn:hover {
- color: #fff;
-}
-
-a.navbar-brand {
- width: 40px;
- height: 40px;
- padding: 0;
- margin-right: 5px;
- margin-top: 5px;
-
- -webkit-border-radius: 20px;
- -moz-border-radius: 20px;
- border-radius: 20px;
-
- -webkit-transition: background-color 200ms ease-in-out;
- -moz-transition: background-color 200ms ease-in-out;
- -ms-transition: background-color 200ms ease-in-out;
- -o-transition: background-color 200ms ease-in-out;
- transition: background-color 200ms ease-in-out;
-}
-
-a.navbar-brand:hover {
- background: #eee !important;
-}
-
-a.navbar-brand:active, a.navbar-brand:visited, .active a.navbar-brand {
- background: #ccc !important;
-}
-
-.navbar-brand > img {
- padding: 5px;
- margin: 0;
- width: auto;
- height: 100%;
-}
-
-@media screen and (max-width: @screen-sm) {
- .navbar-brand {
- margin-left: 15px;
- }
-}
-
-#google-signin {
- margin-top: 10px;
- margin-bottom: 10px;
-}
-
-/* GENERAL CONTENT RULES */
-a {
- text-decoration: none;
-}
-
-a:hover {
- text-decoration: none;
-}
-
-.content-section {
- padding-top: 50px;
- padding-bottom: 150px;
- text-align: center;
-}
-
-.img-caption {
- margin-top: 10px;
- color: #666;
-}
-
-@media screen and (min-width: @screen-sm) and (max-width: @screen-md) {
- .content-section h1 {
- font-size: 2em;
- margin-bottom: 40px;
- }
-
- .content-section h3 {
- font-size: 1.5em;
- }
-}
-
-@media screen and (min-width: @screen-md) and (max-width: @screen-lg) {
- .content-section h1 {
- font-size: 3em;
- margin-bottom: 40px;
- }
-
- .content-section h3 {
- font-size: 1.8em;
- }
-}
-
-@media screen and (min-width: @screen-lg) {
- .content-section h1 {
- font-size: 3em;
- margin-bottom: 40px;
- }
-}
-
-.info-points {
- font-size: 1.2em;
-}
-
-@media screen and (min-width: @screen-sm) and (max-width: @screen-md) {
- .info-points {
- font-size: 1em;
- }
-}
-
-@media screen and (min-width: @screen-md) and (max-width: @screen-lg) {
- .info-points {
- font-size: 1.1em;
- }
-}
-
-.atlarge-footer {
- color: #dddddd;
-}
-
-.pitch-column {
- text-align: left;
-}
-
-.jumbotron ul, .content-section ul {
- list-style: none;
- padding-left: 25px;
-}
-
-.jumbotron ul li, .content-section ul li {
- display: block;
-}
-
-.jumbotron ul li:before, .content-section ul li:before {
- content: "\e080";
- font-family: 'Glyphicons Halflings', monospace;
- font-size: 10px;
- float: left;
- margin-top: 6px;
- margin-left: -17px;
- color: #aaa;
-}
-
-/* CONTENT SECTION COLORS */
-.intro-section {
- background-color: #fff;
-}
-
-.stakeholder-section {
- background-color: #f2f2f2;
-}
-
-.modeling-section {
- background-color: #fff;
-}
-
-.simulation-section {
- background-color: #f2f2f2;
-}
-
-.technologies-section {
- background-color: #fff;
-}
-
-.team-section {
- background-color: #f2f2f2;
-}
-
-.contact-section {
- background-color: #444;
-}
-
-/* HEADING SECTION */
-.header-section {
- background-image: linear-gradient(135deg, #1c2e48, #005bbf, #00c5d6);
-}
-
-.jumbotron {
- margin: 140px 0 120px 0;
- background-color: inherit;
-}
-
-.jumbotron h1 {
- color: #eee;
-}
-
-.jumbotron h1 .dc {
- color: #eee;
- font-weight: bold;
-}
-
-.jumbotron h2 {
- margin-top: 50px;
- color: #eee;
-
-}
-
-/* INTRO SECTION*/
-.intro-section {
- padding-top: 0;
- padding-bottom: 50px;
- text-align: center;
-}
-
-.pitch-container {
- margin-top: 50px;
-}
-
-p.img-source {
- font-size: 0.6em;
- position: relative;
- top: 20px;
-}
-
-@media screen and (max-width: @screen-sm) {
- p.img-source {
- top: 0;
- }
-}
-
-/* STAKEHOLDERS */
-@media screen and (max-width: @screen-sm) {
- .stakeholder-section img {
- position: relative;
- top: 15px;
- }
-}
-
-@media screen and (min-width: @screen-sm) and (max-width: @screen-md) {
- .stakeholder-section img {
- position: relative;
- top: 5px;
- }
-
- .stakeholder-section h3 {
- font-size: 1.5em;
- }
-}
-
-@media screen and (min-width: @screen-md) and (max-width: @screen-lg) {
- .stakeholder-section img {
- position: relative;
- top: 15px;
- }
-
- .stakeholder-section h3 {
- font-size: 1.7em;
- }
-}
-
-.stakeholder-container div {
- text-align: left;
-}
-
-/* MOCKUPS */
-.construction-container {
- margin-top: 20px;
- margin-bottom: 60px;
-}
-
-.simulation-container > div:first-child {
- margin-bottom: 30px;
-}
-
-.img-construction-building {
- margin-top: 10px;
-}
-
-.modeling-section img, .simulation-section img {
- outline: 2px solid #3f3f3f;
- padding-right: 0;
- padding-left: 0;
-}
-
-.simulation-building-row {
- margin-bottom: 40px;
-}
-
-.key-points {
- padding-right: 50px;
-}
-
-/* TECHNOLOGIES */
-.web-flow {
- font-size: 4em;
-}
-
-.technologies-section {
- h3 {
- margin-top: 0;
- }
-
- .tech-row {
- padding: 15px;
-
- -webkit-border-radius: 10px;
- -moz-border-radius: 10px;
- border-radius: 10px;
-
- margin-bottom: 10px;
- }
-
- .browser-tech {
- background-color: #82d0e7;
- }
-
- .server-tech {
- background-color: #edd667;
- }
-
- .database-tech {
- background-color: #ed9c67;
- }
-
- .simulator-tech {
- background-color: #49d65f;
- }
-}
-
-.technology-arrow {
- margin-bottom: 20px;
- margin-top: 15px;
-}
-
-/* TEAM */
-.team-member-description {
- margin-bottom: 30px;
-}
-
-/* CONTACT */
-.contact-section {
- margin-bottom: -5px; // Fixes an unwanted margin that appeared when adding the sign-in button to the nav
-
- h1 {
- color: #ddd;
- }
-
- .names {
- color: #ddd;
- }
-
- a {
- color: #ddd;
- }
-
- a:hover {
- color: #fff;
- }
-}
-
-.tudelft-icon {
- margin-bottom: 10px;
-} \ No newline at end of file
diff --git a/src/unit-tests.html b/src/unit-tests.html
deleted file mode 100644
index 877bda6d..00000000
--- a/src/unit-tests.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<!--suppress HtmlUnknownTarget -->
-<html>
-<head>
- <meta http-equiv="content-type" content="text/html;charset=utf-8">
- <title>OpenDC Unit Tests</title>
- <link rel="stylesheet" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
- <script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
- <script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
- <script src="../node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
-</head>
-<body>
-<script src="scripts/test.entry.js"></script>
-</body>
-</html> \ No newline at end of file