diff options
Diffstat (limited to 'src')
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">×</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 & 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 Binary files differdeleted file mode 100644 index c2f40a0d..00000000 --- a/src/favicon.ico +++ /dev/null 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 Binary files differdeleted file mode 100644 index 16c18be0..00000000 --- a/src/img/app/coolingitem.png +++ /dev/null diff --git a/src/img/app/loading.gif b/src/img/app/loading.gif Binary files differdeleted file mode 100644 index c6394822..00000000 --- a/src/img/app/loading.gif +++ /dev/null diff --git a/src/img/app/node-cpu.png b/src/img/app/node-cpu.png Binary files differdeleted file mode 100644 index 07cfbd31..00000000 --- a/src/img/app/node-cpu.png +++ /dev/null diff --git a/src/img/app/node-gpu.png b/src/img/app/node-gpu.png Binary files differdeleted file mode 100644 index 55d4fb05..00000000 --- a/src/img/app/node-gpu.png +++ /dev/null diff --git a/src/img/app/node-memory.png b/src/img/app/node-memory.png Binary files differdeleted file mode 100644 index 36e8a44e..00000000 --- a/src/img/app/node-memory.png +++ /dev/null diff --git a/src/img/app/node-network.png b/src/img/app/node-network.png Binary files differdeleted file mode 100644 index 795e173b..00000000 --- a/src/img/app/node-network.png +++ /dev/null diff --git a/src/img/app/node-storage.png b/src/img/app/node-storage.png Binary files differdeleted file mode 100644 index 7a39cb6f..00000000 --- a/src/img/app/node-storage.png +++ /dev/null diff --git a/src/img/app/psu.png b/src/img/app/psu.png Binary files differdeleted file mode 100644 index 471af6ee..00000000 --- a/src/img/app/psu.png +++ /dev/null diff --git a/src/img/app/rack-energy.png b/src/img/app/rack-energy.png Binary files differdeleted file mode 100644 index 1088c61b..00000000 --- a/src/img/app/rack-energy.png +++ /dev/null diff --git a/src/img/app/rack-space.png b/src/img/app/rack-space.png Binary files differdeleted file mode 100644 index 387d7ea6..00000000 --- a/src/img/app/rack-space.png +++ /dev/null diff --git a/src/img/datacenter-drawing.png b/src/img/datacenter-drawing.png Binary files differdeleted file mode 100644 index 401168e3..00000000 --- a/src/img/datacenter-drawing.png +++ /dev/null diff --git a/src/img/email-icon.png b/src/img/email-icon.png Binary files differdeleted file mode 100644 index ced9e175..00000000 --- a/src/img/email-icon.png +++ /dev/null diff --git a/src/img/favicon.png b/src/img/favicon.png Binary files differdeleted file mode 100644 index 85d74964..00000000 --- a/src/img/favicon.png +++ /dev/null diff --git a/src/img/github-icon.png b/src/img/github-icon.png Binary files differdeleted file mode 100644 index 1e221600..00000000 --- a/src/img/github-icon.png +++ /dev/null diff --git a/src/img/logo.png b/src/img/logo.png Binary files differdeleted file mode 100644 index d743038b..00000000 --- a/src/img/logo.png +++ /dev/null diff --git a/src/img/opendc-splash.png b/src/img/opendc-splash.png Binary files differdeleted file mode 100644 index 99fd8658..00000000 --- a/src/img/opendc-splash.png +++ /dev/null diff --git a/src/img/portraits/aiosup.png b/src/img/portraits/aiosup.png Binary files differdeleted file mode 100644 index 30de349c..00000000 --- a/src/img/portraits/aiosup.png +++ /dev/null diff --git a/src/img/portraits/gandreadis.png b/src/img/portraits/gandreadis.png Binary files differdeleted file mode 100644 index 403870fa..00000000 --- a/src/img/portraits/gandreadis.png +++ /dev/null diff --git a/src/img/portraits/loverweel.png b/src/img/portraits/loverweel.png Binary files differdeleted file mode 100644 index d12a9e86..00000000 --- a/src/img/portraits/loverweel.png +++ /dev/null diff --git a/src/img/portraits/mbijman.png b/src/img/portraits/mbijman.png Binary files differdeleted file mode 100644 index decf9fdd..00000000 --- a/src/img/portraits/mbijman.png +++ /dev/null diff --git a/src/img/stakeholders/Developer.png b/src/img/stakeholders/Developer.png Binary files differdeleted file mode 100644 index d2638e6c..00000000 --- a/src/img/stakeholders/Developer.png +++ /dev/null diff --git a/src/img/stakeholders/Manager.png b/src/img/stakeholders/Manager.png Binary files differdeleted file mode 100644 index 92db7459..00000000 --- a/src/img/stakeholders/Manager.png +++ /dev/null diff --git a/src/img/stakeholders/Researcher.png b/src/img/stakeholders/Researcher.png Binary files differdeleted file mode 100644 index d87edd39..00000000 --- a/src/img/stakeholders/Researcher.png +++ /dev/null diff --git a/src/img/stakeholders/Sales.png b/src/img/stakeholders/Sales.png Binary files differdeleted file mode 100644 index 5b7c3a72..00000000 --- a/src/img/stakeholders/Sales.png +++ /dev/null diff --git a/src/img/stakeholders/Student.png b/src/img/stakeholders/Student.png Binary files differdeleted file mode 100644 index a4900303..00000000 --- a/src/img/stakeholders/Student.png +++ /dev/null diff --git a/src/img/technologies/arrow.png b/src/img/technologies/arrow.png Binary files differdeleted file mode 100644 index 374f78bf..00000000 --- a/src/img/technologies/arrow.png +++ /dev/null diff --git a/src/img/technologies/cogs-icon.png b/src/img/technologies/cogs-icon.png Binary files differdeleted file mode 100644 index d19e1c20..00000000 --- a/src/img/technologies/cogs-icon.png +++ /dev/null diff --git a/src/img/technologies/database-icon.png b/src/img/technologies/database-icon.png Binary files differdeleted file mode 100644 index 26738e76..00000000 --- a/src/img/technologies/database-icon.png +++ /dev/null diff --git a/src/img/technologies/webserver-icon.png b/src/img/technologies/webserver-icon.png Binary files differdeleted file mode 100644 index c627106e..00000000 --- a/src/img/technologies/webserver-icon.png +++ /dev/null diff --git a/src/img/technologies/www-icon.png b/src/img/technologies/www-icon.png Binary files differdeleted file mode 100644 index e69a54f2..00000000 --- a/src/img/technologies/www-icon.png +++ /dev/null diff --git a/src/img/tudelfticon.png b/src/img/tudelfticon.png Binary files differdeleted file mode 100644 index a7a2d56a..00000000 --- a/src/img/tudelfticon.png +++ /dev/null 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">×</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 |
