1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 16:51:11 +03:00

Updates UI CONTRIBUTING for 3.3

* Fixes links in CONTRIBUTING.md
* Moves CONTRIBUTING and UI design files to ui/client/src/network-ui
* Adds README.md for network_ui/designs
* Updates design
This commit is contained in:
Ben Thomasson 2018-03-14 13:07:53 -04:00
parent f8d83638b0
commit 8d28748451
No known key found for this signature in database
GPG Key ID: 5818EF4CC895D5F5
44 changed files with 202 additions and 329 deletions

View File

@ -1,161 +1,9 @@
Finite State Machine Designs
============================
This directory contains the finite state machine designs that were used to
generate the skeleton of the javascript implementations and can be used to
check that the implementations still match the designs.
The design files in this directory are used in the database schema designer tool.
* [models.png](models.png) - An image of the database schema design for network UI.
* [models.yml](models.yml) - Provides the main schema design for the network UI project.
* [api.yml](api.yml) - Provides additional meta-data for the API.
**Machine Readable FSM Schema**
The machine readable FSM schema contains three top-level elements: `name`, `states`, and `transitions`.
* The `name` element is a string.
* The `states` element contains a list of `state` elements which have attributes `id`, `label`, and `x`, and `y`.
* The `transitions` element contains a list of `transition` elements which have attributes `from_state`, `to_state`, and `label`.
**Design Diagrams**
The diagrams below are visual representations of the finite state machine designs in this directory.
The equivalent machine readable representations are linked as well.
---
**Null FSM**
* See: null.yml
The null FSM is an FSM that ignores all events.
![Null FSM](null.png)
---
**Button FSM**
* See: button.yml
The button FSM describes how a button works. The key insight here is that a button is not
clicked if the mouse is not over the button on both the `MouseDown` and `MouseUp` events. Moving
the mouse off the button before `MouseUp` is not a click.
![Button FSM](button.png)
---
**Buttons FSM**
* See: buttons.yml
The buttons FSM distributes events to the buttons which each have their own FSM.
![Buttons FSM](buttons.png)
---
**Device Detail FSM**
* See: device_detail.yml
The device detail FSM describes interactions when zoomed into a device.
![Device Detail FSM](device_detail.png)
---
**Group FSM**
* See: group.yml
The group FSM describes how to organize multiple devices together in a group.
![Group FSM](group.png)
---
**Hot Keys FSM**
* See: hotkeys.yml
The hot keys FSM handles key events and generates new events like `NewLink` to implement
hot keys.
![Hot Keys FSM](hotkeys.png)
---
**Link FSM**
* See: link.yml
The link FSM connects two devices together with a link.
![Link](link.png)
---
**Mode FSM**
* See: mode.yml
The mode FSM controls the overall mode of the network UI application.
![Mode](mode.png)
---
**Move FSM**
* See: move.yml
The move FSM controls placement of devices as well as editing the device labels.
![Move](move.png)
---
**Rack FSM**
* See: rack.yml
The rack FSM controls organizing devices into a special group called a rack.
![Rack](rack.png)
---
**Site FSM**
* See: site.yml
The site FSM controls organizing devices into a special group called a site.
![Site](site.png)
---
**Stream FSM**
* See: stream.yml
The stream FSM controls how streams are defined between devices.
![Stream](stream.png)
---
**Time FSM**
* See: time.yml
The time FSM controls undo/redo functionality of the network UI.
![Time](time.png)
---
**Toolbox FSM**
* See: toolbox.yml
The toolbox FSM controls the drag-and-drop toolboxes and allow placement of new devices, applications,
racks, and sites onto the canvas.
![Toolbox](toolbox.png)
---
**View FSM**
* See: view.yml
The view FSM controls the panning and scaling of the the virtual canvas through clicking-and-dragging
of the background and scrolling the mousewheel.
![View](view.png)
![Models](models.png)

View File

@ -1,7 +1,6 @@
models:
- name: Device
api: true
v1_end_point: /network_ui/api/v1/device/
v2_end_point: /api/v2/canvas/device/
topology_id_query: topology_id
v2_lookup_field: host_id
@ -17,7 +16,6 @@ models:
topology_id: topology_id
- name: Link
api: true
v1_end_point: /network_ui/api/v1/link/
v2_end_point: /api/v2/canvas/link/
topology_id_query: from_device__topology_id
create_transform:
@ -29,7 +27,6 @@ models:
to_interface__id: to_interface_id
- name: Interface
api: true
v1_end_point: /network_ui/api/v1/interface/
v2_end_point: /api/v2/canvas/interface/
topology_id_query: device__topology_id
create_transform:
@ -38,39 +35,31 @@ models:
device__id: device_id
- name: Group
api: true
v1_end_point: /network_ui/api/v1/group/
v2_end_point: /api/v2/canvas/group/
topology_id_query: topology_id
- name: GroupDevice
api: true
v1_end_point: /network_ui/api/v1/groupdevice/
v2_end_point: /api/v2/canvas/groupdevice/
topology_id_query: group__topology_id
- name: Topology
api: true
v1_end_point: /network_ui/api/v1/topology/
v2_end_point: /api/v2/canvas/topology/
topology_id_query: topology_id
- name: TopologyInventory
api: true
v1_end_point: /network_ui/api/v1/topologyinventory/
v2_end_point: /api/v2/canvas/topologyinventory/
topology_id_query: topology_id
- name: Toolbox
api: true
v1_end_point: /network_ui/api/v1/toolbox/
v2_end_point: /api/v2/canvas/toolbox/
- name: ToolboxItem
api: true
v1_end_point: /network_ui/api/v1/toolboxitem/
v2_end_point: /api/v2/canvas/toolboxitem/
- name: Stream
api: true
v1_end_point: /network_ui/api/v1/stream/
v2_end_point: /api/v2/canvas/stream/
topology_id_query: from_device__topology_id
- name: Process
api: true
v1_end_point: /network_ui/api/v1/process/
v2_end_point: /api/v2/canvas/process/
topology_id_query: device__topology_id

View File

@ -1,49 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Usage:
merge_yaml [options] <a> <b>
Options:
-h, --help Show this page
--debug Show debug logging
--verbose Show verbose logging
"""
from docopt import docopt
import logging
import sys
import yaml
logger = logging.getLogger('merge_yaml')
def main(args=None):
if args is None:
args = sys.argv[1:]
parsed_args = docopt(__doc__, args)
if parsed_args['--debug']:
logging.basicConfig(level=logging.DEBUG)
elif parsed_args['--verbose']:
logging.basicConfig(level=logging.INFO)
else:
logging.basicConfig(level=logging.WARNING)
with open(parsed_args['<a>']) as f:
a = yaml.load(f.read())
with open(parsed_args['<b>']) as f:
b = yaml.load(f.read())
a_models = {x['name']: x for x in a.get('models', [])}
for model in b.get('models', []):
for key, value in model.iteritems():
a_models[model['name']][key] = value
print (yaml.safe_dump(a, default_flow_style=False))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 KiB

View File

@ -13,7 +13,6 @@ models:
x: x
y: y
display: name
end_point: /network_ui/api/v1/device/
fields:
- name: device_id
pk: true
@ -45,7 +44,6 @@ models:
type: IntegerField
name: Device
topology_id_query: topology_id
v1_end_point: /network_ui/api/v1/device/
v2_end_point: /api/v2/canvas/device/
v2_lookup_field: host_id
x: 348
@ -89,13 +87,11 @@ models:
type: CharField
name: Link
topology_id_query: from_device__topology_id
v1_end_point: /network_ui/api/v1/link/
v2_end_point: /api/v2/canvas/link/
x: 837
y: 10
- api: true
display: name
end_point: /network_ui/api/v1/topology/
fields:
- name: topology_id
pk: true
@ -123,7 +119,6 @@ models:
type: IntegerField
name: Topology
topology_id_query: topology_id
v1_end_point: /network_ui/api/v1/topology/
v2_end_point: /api/v2/canvas/topology/
x: 111
y: 127
@ -177,7 +172,6 @@ models:
id: id
name: name
display: name
end_point: /network_ui/api/v1/interface/
fields:
- name: interface_id
pk: true
@ -193,12 +187,10 @@ models:
type: IntegerField
name: Interface
topology_id_query: device__topology_id
v1_end_point: /network_ui/api/v1/interface/
v2_end_point: /api/v2/canvas/interface/
x: 1157
y: 337
- api: true
end_point: /network_ui/api/v1/group/
fields:
- name: group_id
pk: true
@ -228,12 +220,10 @@ models:
type: IntegerField
name: Group
topology_id_query: topology_id
v1_end_point: /network_ui/api/v1/group/
v2_end_point: /api/v2/canvas/group/
x: 407
y: -379
- api: true
end_point: /network_ui/api/v1/groupdevice/
fields:
- name: group_device_id
pk: true
@ -248,67 +238,10 @@ models:
type: ForeignKey
name: GroupDevice
topology_id_query: group__topology_id
v1_end_point: /network_ui/api/v1/groupdevice/
v2_end_point: /api/v2/canvas/groupdevice/
x: 739
y: -234
- fields:
- name: data_binding_id
pk: true
type: AutoField
- name: column
type: IntegerField
- name: row
type: IntegerField
- len: 200
name: table
type: CharField
- name: primary_key_id
type: IntegerField
- len: 200
name: field
type: CharField
- name: data_type
ref: DataType
ref_field: data_type_id
type: ForeignKey
- name: sheet
ref: DataSheet
ref_field: data_sheet_id
type: ForeignKey
name: DataBinding
x: -515
y: -370
- fields:
- name: data_type_id
pk: true
type: AutoField
- len: 200
name: type_name
type: CharField
name: DataType
x: -782
y: -172
- fields:
- name: data_sheet_id
pk: true
type: AutoField
- len: 200
name: name
type: CharField
- name: topology
ref: Topology
ref_field: topology_id
type: ForeignKey
- name: client
ref: Client
ref_field: client_id
type: ForeignKey
name: DataSheet
x: -207
y: -282
- api: true
end_point: /network_ui/api/v1/stream/
fields:
- name: stream_id
pk: true
@ -333,12 +266,10 @@ models:
type: IntegerField
name: Stream
topology_id_query: from_device__topology_id
v1_end_point: /network_ui/api/v1/stream/
v2_end_point: /api/v2/canvas/stream/
x: 709
y: 527
- api: true
end_point: /network_ui/api/v1/process/
fields:
- name: process_id
pk: true
@ -358,12 +289,10 @@ models:
type: IntegerField
name: Process
topology_id_query: device__topology_id
v1_end_point: /network_ui/api/v1/process/
v2_end_point: /api/v2/canvas/process/
x: 654
y: 778
- api: true
end_point: /network_ui/api/v1/toolbox/
fields:
- name: toolbox_id
pk: true
@ -372,12 +301,10 @@ models:
name: name
type: CharField
name: Toolbox
v1_end_point: /network_ui/api/v1/toolbox/
v2_end_point: /api/v2/canvas/toolbox/
x: 179
y: 644
- api: true
end_point: /network_ui/api/v1/toolboxitem/
fields:
- name: toolbox_item_id
pk: true
@ -389,7 +316,6 @@ models:
- name: data
type: TextField
name: ToolboxItem
v1_end_point: /network_ui/api/v1/toolboxitem/
v2_end_point: /api/v2/canvas/toolboxitem/
x: 391
y: 645
@ -423,7 +349,6 @@ models:
x: -872
y: 507
- api: true
end_point: /network_ui/api/v1/topologyinventory/
fields:
- name: topology_inventory_id
pk: true
@ -436,7 +361,6 @@ models:
type: IntegerField
name: TopologyInventory
topology_id_query: topology_id
v1_end_point: /network_ui/api/v1/topologyinventory/
v2_end_point: /api/v2/canvas/topologyinventory/
x: -226
y: -19

View File

@ -54,14 +54,14 @@ of on-screen elements.
AngularJS directives are used in the networking UI application using the element
matching style and the `templateUrl` option to include a template. A majority of
the directives are defined in `src/network.ui.app.js`.
the directives are defined in `network.ui.app.js`.
* See: [src/network.ui.app.js](src/network.ui.app.js)
* See: [network.ui.app.js](network.ui.app.js)
```
.directive('awxNetDeviceDetail', deviceDetail.deviceDetail)
```
* See: [src/device.detail.directive.js](src/device.detail.directive.js)
* See: [device.detail.directive.js](device.detail.directive.js)
```
function deviceDetail () {
return { restrict: 'A', templateUrl: '/static/network_ui/widgets/device_detail.html' };
@ -77,19 +77,19 @@ The templates can be found in `/widgets`. Child
scopes are created for sub-templates using the `ng-repeat` directive.
In this example the `awx-net-link` directive expects a Link model to be
passed to it. The Link model is defined in the `src/models.js` file.
passed to it. The Link model is defined in the `models.js` file.
* See: [src/link.directive.js](src/link.directive.js)
* See: [widgets/link.html](widgets/link.html)
* See: [link.directive.js](link.directive.js)
* See: [link.partial.svg](link.partial.svg)
* See: [widgets/network_ui.html](widgets/network_ui.html)
* See: [network_ui.html](network_ui.partial.svg)
```
<g ng-repeat="link in links">
<g awx-net-link></g>
</g>
```
* See: [src/models.js](src/models.js)
* See: [models.js](models.js)
```
function Link(id, from_device, to_device, from_interface, to_interface) {
this.id = id;
@ -108,7 +108,7 @@ function Link(id, from_device, to_device, from_interface, to_interface) {
The following example sets the toolbox.selected_item value to the variable
item which the directives used in the child scope expect to be set.
* See: [widgets/inventory_toolbox.html](widgets/inventory_toolbox.html)
* See: [inventory_toolbox.html](inventory_toolbox.partial.svg)
```
<g ng-repeat="item in [toolbox.selected_item]">
```
@ -133,7 +133,7 @@ positioned within the outer most SVG element. The browser is not involved with
layout of the elements within the SVG. Each "widget" in the network UI needs
to track or calculate its own position on the SVG canvas. The z-level of the
elements are determined by the draw order on the canvas which is defined
in `widgets/network_ui.html`. Elements drawn first will be hidden behind
in `network_ui.partial.svg`. Elements drawn first will be hidden behind
elements drawn later.
@ -212,7 +212,7 @@ to define the width of lines and curves. The attributes `font-family` and `font-
are used to set the font for text elements in SVG. The network UI uses the Less
CSS compiler and BEM naming conventions to simplify and organize CSS.
* See: [src/style.less](src/style.less)
* See: [style.less](style.less)
* See: <http://lesscss.org/>
* See: <http://getbem.com/introduction/>
@ -230,7 +230,7 @@ to the appropriate object.
The following code captures all the mouse movements, mouse clicks, mouse wheel,
and touch events and sends them to the corresponding network UI controller functions.
* See: [widgets/network_ui.html](widgets/network_ui.html#L3)
* See: [network_ui.partial.svg](network_ui.partial.svg#L3)
```
<svg id="frame" class="NetworkUI"
@ -252,7 +252,7 @@ and touch events and sends them to the corresponding network UI controller funct
Key events are captured by the following code:
* See: [src/network.ui.controller.js](src/network.ui.controller.js)
* See: [network.ui.controller.js](network.ui.controller.js)
```
$document.bind("keydown", $scope.onKeyDown);
@ -305,10 +305,10 @@ the connecting operation. Finally in the `Connected` state the FSM changes to
for free using the `start` event so that the user can connect another set of devices.
* See: [designs/link.yml](designs/link.yml)
* See: [src/link.js](src/link.js)
* See: [link.js](link.js)
The link FSM diagram has an equivalent machine readable representation in `designs/link.yml`. This
representation is useful for comparing the current implementation in `src/link.js` to the design to see if they
representation is useful for comparing the current implementation in `link.js` to the design to see if they
are out-of-sync. If they are out-of-sync either the design or the implementation can be updated depending
on if you are changing the design or implementation first.
@ -327,7 +327,7 @@ the system and what that event handler should do.
Use `tools/fsm_generate_diffs.py` to generate the new skeleton code:
```
./tools/fsm_generate_diffs.py designs/link.yml ./src/link.js
./tools/fsm_generate_diffs.py designs/link.yml ./link.js
```
This will print out code for additional states or transitions needed in the implementation.
@ -350,7 +350,7 @@ Use `./extract.js` and `tools/fsm-diff` to compare the implementation to the des
and add any additional transitions to the FSM design.
```
./extract.js ./src/link.js > ./extracted/link.yml
./extract.js link.js > ./extracted/link.yml
./tools/fsm-diff designs/link.yml extracted/link.yml
```
@ -383,10 +383,10 @@ flyweight and singleton patterns. This means that the state objects store no
information on themselves and that there is only one instance of each state
class. All states should provide a `start` and `end` function which will be
called when a FSM state is entered and exited respectively. Subclassing
[fsm.State](src/fsm.js#L36) will provide empty `start` and `end` functions that
[fsm.State](fsm.js#L36) will provide empty `start` and `end` functions that
can be overridden as necessary.
* See: [src/fsm.js](src/fsm.js#L2)
* See: [fsm.js](fsm.js#L2)
The state variable is stored on another object called an FSMController (which
should not be confused with an AngularJS controller). The FSMController holds
@ -400,7 +400,7 @@ in the event handlers. In the network UI often the `scope` is a reference
to the network UI AngularJS controller's scope. In the case of a button
the scope is a reference to the `Button` model.
* See: [src/models.js](src/models.js#302)
* See: [models.js](models.js#302)
The following code creates a new instance of `FSMController` using the
`Button` model as the scope and the `button.Start` state as the initial
@ -410,7 +410,7 @@ state.
this.fsm = new fsm.FSMController(this, button.Start, null);
```
* See: [src/link.js](src/link.js#L40)
* See: [link.js](link.js#L40)
This code block defines the `_Selecting` class in ES5 style and uses the
`inherits` NPM module to define that the class is a subclass of `_State`. We
@ -430,7 +430,7 @@ also create a single instance (a singleton) of this class named `Selecting`.
After all the states are defined the event handlers for those state classes can be defined.
We do this to prevent forward references in the file.
* See: [src/link.js](src/link.js#L134)
* See: [link.js](link.js#L134)
In this code we define an event handler for the `MouseUp` event on the `Selecting` state. This
code should select a single device if the mouse is over that device. It should store
@ -478,9 +478,9 @@ the system to another. Models may be unpacked or serialized into messages that
are sent to other FSMControllers in the client or sent over a websocket to the
server.
* See: [src/models.js](src/models.js)
* See: [models.js](models.js)
The models defined in [src/models.js](src/models.js) are:
The models defined in [models.js](models.js) are:
* Device - a networking device i.e. a router, a switch, or a host
* Interface - a networking interface
@ -501,9 +501,9 @@ Message types define the structure of the data that is passed between the server
and the client and between different parts of the client. This provides a known and
well defined data structure that can be counted up on the code.
* See: [src/messages.js](src/messages.js)
* See: [messages.js](messages.js)
The messages defined are [src/messages.js](src/messages.js):
The messages defined are [messages.js](messages.js):
* DeviceMove - Device has changed x,y position
* DeviceCreate - A device was created
@ -564,7 +564,7 @@ events from the web browser are passed to the `first_channel` where they are
passed along the chain of FSMControllers until they reach the end with
`NullChannel` or they are handled and the models are updated.
* See: [src/network.ui.controller.js](src/network.ui.controller.js#L115)
* See: [network.ui.controller.js](network.ui.controller.js#L115)
The order (from first to last) of message handling is:
@ -616,7 +616,7 @@ For a widget named `new widget` do this:
This example follows development of the inventory toolbox widget.
* Add a template in `widgets` for the new widget with name [widgets/inventory_toolbox.html](widgets/inventory_toolbox.html)
* Add a template in `widgets` for the new widget with name [inventory_toolbox.partial.svg](inventory_toolbox.partial.svg)
```
<!-- Copyright (c) 2017 Red Hat, Inc. -->
@ -632,7 +632,7 @@ This example follows development of the inventory toolbox widget.
</g> <!-- ng-if toolbox.enabled -->
```
* Add a directive that loads that template in `src` with name [src/inventory.toolbox.directive.js](src/inventory.toolbox.directive.js)
* Add a directive that loads that template in `src/network-ui` with name [inventory.toolbox.directive.js](inventory.toolbox.directive.js)
```
/* Copyright (c) 2017 Red Hat, Inc. */
@ -644,7 +644,7 @@ This example follows development of the inventory toolbox widget.
```
* Register the directive with the network UI application in [src/network.ui.app.js](src/network.ui.app.js#L61) using name `awxNetInventoryToolbox`
* Register the directive with the network UI application in [network.ui.app.js](network.ui.app.js#L61) using name `awxNetInventoryToolbox`
```
...
@ -654,7 +654,7 @@ This example follows development of the inventory toolbox widget.
...
```
* Add a tag that loads the directive into an existing template in `widgets` in [widgets/network_ui.html](widgets/network_ui.html#L94)
* Add a tag that loads the directive into an existing template in `src/network-ui` in [network_ui.partial.svg](network_ui.partial.svg#L94)
```
<g awx-net-inventory-toolbox></g>
@ -733,10 +733,10 @@ This example follows development of the inventory toolbox widget.
to_state: Dropping
```
* Create a new empty FSM implementation file in `src` named `src/toolbox.fsm.js`
* Create a new empty FSM implementation file in `src/network-ui` named `toolbox.fsm.js`
```
touch src/toolbox.fsm.js
touch toolbox.fsm.js
```
* Use the `./tools/fsm_generate_diffs.py` tool to generate the skeleton for the new FSM implementation
@ -938,7 +938,7 @@ This example follows development of the inventory toolbox widget.
```
* Decide if you need any new messages to communicate between the UI and the server or between pieces of the UI.
If so, add them to [src/messages.js](src/messages.js#L251)
If so, add them to [messages.js](messages.js#L251)
```
function PasteDevice(device) {
@ -949,9 +949,9 @@ This example follows development of the inventory toolbox widget.
* Write the logic in the event handlers to update the models, send any messages, and change states according to the design.
See: [src/toolbox.fsm.js](src/toolbox.fsm.js)
See: [toolbox.fsm.js](toolbox.fsm.js)
* Add the FSM implementation to a FSMController in [src/network.ui.controller.js](src/network.ui.controller.js#L145)
* Add the FSM implementation to a FSMController in [network.ui.controller.js](network.ui.controller.js#L145)
```
$scope.inventory_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.app_toolbox_controller);

View File

@ -0,0 +1,161 @@
Finite State Machine Designs
============================
This directory contains the finite state machine designs that were used to
generate the skeleton of the javascript implementations and can be used to
check that the implementations still match the designs.
**Machine Readable FSM Schema**
The machine readable FSM schema contains three top-level elements: `name`, `states`, and `transitions`.
* The `name` element is a string.
* The `states` element contains a list of `state` elements which have attributes `id`, `label`, and `x`, and `y`.
* The `transitions` element contains a list of `transition` elements which have attributes `from_state`, `to_state`, and `label`.
**Design Diagrams**
The diagrams below are visual representations of the finite state machine designs in this directory.
The equivalent machine readable representations are linked as well.
---
**Null FSM**
* See: null.yml
The null FSM is an FSM that ignores all events.
![Null FSM](null.png)
---
**Button FSM**
* See: button.yml
The button FSM describes how a button works. The key insight here is that a button is not
clicked if the mouse is not over the button on both the `MouseDown` and `MouseUp` events. Moving
the mouse off the button before `MouseUp` is not a click.
![Button FSM](button.png)
---
**Buttons FSM**
* See: buttons.yml
The buttons FSM distributes events to the buttons which each have their own FSM.
![Buttons FSM](buttons.png)
---
**Device Detail FSM**
* See: device_detail.yml
The device detail FSM describes interactions when zoomed into a device.
![Device Detail FSM](device_detail.png)
---
**Group FSM**
* See: group.yml
The group FSM describes how to organize multiple devices together in a group.
![Group FSM](group.png)
---
**Hot Keys FSM**
* See: hotkeys.yml
The hot keys FSM handles key events and generates new events like `NewLink` to implement
hot keys.
![Hot Keys FSM](hotkeys.png)
---
**Link FSM**
* See: link.yml
The link FSM connects two devices together with a link.
![Link](link.png)
---
**Mode FSM**
* See: mode.yml
The mode FSM controls the overall mode of the network UI application.
![Mode](mode.png)
---
**Move FSM**
* See: move.yml
The move FSM controls placement of devices as well as editing the device labels.
![Move](move.png)
---
**Rack FSM**
* See: rack.yml
The rack FSM controls organizing devices into a special group called a rack.
![Rack](rack.png)
---
**Site FSM**
* See: site.yml
The site FSM controls organizing devices into a special group called a site.
![Site](site.png)
---
**Stream FSM**
* See: stream.yml
The stream FSM controls how streams are defined between devices.
![Stream](stream.png)
---
**Time FSM**
* See: time.yml
The time FSM controls undo/redo functionality of the network UI.
![Time](time.png)
---
**Toolbox FSM**
* See: toolbox.yml
The toolbox FSM controls the drag-and-drop toolboxes and allow placement of new devices, applications,
racks, and sites onto the canvas.
![Toolbox](toolbox.png)
---
**View FSM**
* See: view.yml
The view FSM controls the panning and scaling of the the virtual canvas through clicking-and-dragging
of the background and scrolling the mousewheel.
![View](view.png)

View File

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 161 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 271 KiB

After

Width:  |  Height:  |  Size: 271 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View File

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB