Overview
This area is to serve as a reference for developing, extending or learnign about the inner workings of my take on the project.
Table of Contents
Project Structure
All of the files for this project reside within the src folder, and once running a local instance the only file you will have to open is index.html.
src/
├── Components/
│ ├── LeftPaneControl.js
│ ├── NavigationButtonControl.js
│ ├── PropertiesPaneControl.js
│ ├── RightPaneControl.js
│ └── Table.js
├── Styles/
│ ├── Layout.css
│ ├── Navigation.css
│ ├── Panes.css
│ └── Tables.css
├── Services/
│ ├── http.js
│ └── ws.js
│
├── index.html
└── index.js
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Application Entries
The base src directory houses two particulary important files.
| file | Contents |
|---|---|
| index.html | hold the application shell |
| index.js | renders and connects all of our components to the shell |
Directories
Components
Files that render, create and handle all of our logic
| file | Contents |
|---|---|
| LeftPaneControl.js | Serves as the menu to handle different queries |
| NavigationButtonControl.js | Serves as buttons and titles within the navigation bar |
| PropertiesPaneControl.js | Slideout menu that allows users to enter custom domain identifiers |
| RightPaneControl.js | Serves as the dashboard content area |
| Table.js | Holds the logic behind the dashboard data table |
Services
Javascript class files used to handle our service connections
| file | Contents |
|---|---|
| http.js | Class constructor to handle our historic queries |
| ws.js | Class constructor to handle our real time subscription |
Styles
Files that define the look and feel of the application
| file | Contents |
|---|---|
| Layout.css | These are the styles for the primary layout. |
| Navigation.css | Defines the style of our dashboard navigation bar |
| Panes.css | Defines the style of our three major layour areas |
| Tables.css | Controls the styles of our data tables |
How to use
Real Time Subscriptions
Directions
Open index.html file in your web browser.
By Default Real time queries is the first page you will see, on the left hand side you will see several options. To subscribe to a topic, press any of the buttons that appear under REAL-TIME QUERIES. After the dashboard data table will begin updating with data.
To close the websocket connection, press the Reset button.
To querie a custom point, press the Custom button, and enter the details within the slideout form. After, press the Connect button on the slideout. If you had sent a succesfull subscription point, your datatable will begin updating.
Historic Queries
Directions
Open index.html file in your web browser. By Default Real time queries is the first page you will see.
On the navigation bar click the Toggle Historic button to change to the historic query menu.
Getting data
Click any of the buttons on the side menu to preform a new query
Sorting Data
By Default the returned data will be sorted by timestamp ascending. To change that, activate the prefered sort method by clicking either of the options bellow Sorting within the left control panel.
How its made
In this section I will break down how the application was made, and the important elements within each file.
Components Breakdown
For this exercise, components are arguably the most important pieces of the puzzle. They tell our application, how to look, feel, and move. Primarily throughout the application I choose to stick to singleton class patterns, and generator functions. This allows me to move usefull data, and help maintain state in a framework barren app.
Repeated functions to avoid redundant explination
Some patters and functions are repeated within the app, as a roadmap I would refactor the project to be more dry, and write more test cases. Regaurdless bellow are some of the patterns that are standard.
Rendering Views, and attaching listeners
In most of the files you will see a pattern like bellow, it is used to asyncronously render dom elements, and then attaching listeners to said dom elements. This pattern allows us to ensure that before we try to attach a event listener, the dom is ready. I've replaced the important parts with placeholder text.
let /*Unique Name*/ = {
render: async () => {
let view = `
/*String representing dom object, and any logic within*/
`
return view
},
attach_listeners: async () => {
const /*Some Element Constant Name */ = document.getElementById(/*Some Element ID Referenced from the above render methods view */ );
/**
* Attach an event listener to the selected element
*/
/*Some Element Constant */.addEventListener(/* Listener */, () => {
/* Functions completed on listener */
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Table.js
Table.js is used to render all of our data
Includes
| Includes | Use |
|---|---|
| wsInstance | Used to render data if there exists any within the websocket instance |
Important Dom Elements
| Selector | TagName | Use |
|---|---|---|
| #data-table | table | Renderable table to hold all of our data |
| #tableBody | tbody | Targeted so that we can render, and manipulate our table rows easier |
Renderable HTML
Table.js has two two areas where it can render new html from, so it is unique in that it doesnt only hold a view, as seen in other files.
Initial Table Element
const newTable = `
<table class="fixed_header" id="data-table">
<thead>
<tr class="trHeader">
${tblObj.columns.map((column) => `\t\t\t<th class="trHeader" onclick="sortBy('${column.text}')">${column.text}</th>`).join('\n ')}
</tr>
</thead>
<tbody id="tableBody">
${tblObj.data.map((row, index) =>
`\t\t\t<tr class="trself" data-id="${index}" id="${index}">
<td>${row.id}</td> <td>${row.id}</td> <td>${index}</td>`)}
</tbody>
</table>`;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
New Table Rows
const baseRowContent = `<tr class="trself"><td>${rowItem.id}</td><td>${rowItem.timestamp}</td><td>${rowItem.value}</td></tr>`
2
3
Javascript Overview
The javascript located in Table.js is what controls the inner workings of data table.
Scattered Variables,Paramaters, and Arguments
| Variable | Use |
|---|---|
| currentTableObject | Holds the data responsible for rendering elements within the table |
| pageTitle | Title of the page table you are on |
Main Frontend Functions and Methods
| Function | Arguments | Use |
|---|---|---|
| init | none | sets up the data for the new table object and calls the render function |
| render | none | initializes the base table object |
| setPageTitle | title | sets the title of the current page |
| getPagetitle | none | gets the title of the current page |
| generateTableExtended | table, tblObj | creates the new table object |
| addRow | rowItem | accepts and object representing a table row and adds it to the table |
| switchDataSource | none | removes all elements from the table |
RightPanelControl.js
Serves as the dashboard content area
Includes
| Includes | Use |
|---|---|
| tableDataInstance | Class used to retrieve the data table, and attach it to the dom |
Important Dom Elements
| Selector | TagName | Use |
|---|---|---|
| #data-table | table | Renderable table to hold all of our data |
| #tableBody | tbody | Targeted so that we can render, and manipulate our table rows easier |
Renderable HTML
let view = `
<div id="rightPanelWrapper">
<h2>current table</h2>
<table id="dataTable">
<!-- Data Appears Here -->
</table>
</div>
`
2
3
4
5
6
7
8
Javascript Overview
The javascript located in RightPaneControl is primarily used to initialize the table singleton when the dom is ready.
PropertiesPaneControl.js
Slide out menu used for custom websocket queries
Includes
| Includes | Use |
|---|---|
| toggleSlideMenu | Used to toggle the slide out menu |
| tableDataInstance | Used to access the table data singleton instance |
| wsInstance | Used to create the custom ws connections |
Important Dom Elements
| Selector | TagName | Use |
|---|---|---|
| .customTextInput | input | User enabled text input area to send custom subscription pointId's |
| #propertyFormSubmit | button | calls the websocket class to create a new subcription |
| #propertiesCloseMenu | button | used to close the propetry menu |
Renderable HTML
let view = `
<div id="propertiesMenu" class="propertiesMenu">
<div class="propertiesMenuTitle">
Custom-Queries
</div>
<!--MARK : Property Data-->
<div class="proprtyFormContainer">
<form class="propertyForm" action="#" method="post">
<div class="propertiesPaneDescriptor">
<h4>Enter PointId </h4>
<p>single : pwr.c</p>
<p>multi : pwr.v,pwr.c </p>
<input id="customTextInput" placeholder="Enter your domain object here" required></input>
</div>
</form>
</div>
<button class="propertyFormButton connect" id="propertyFormSubmit">Connect</button>
<div>
<button id="propertiesCloseMenu" class="propertyFormButton connect">Close Panel</button>
</div>
</div>
`
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
NavigationButtonControl.js
Holds the html renderer and offers the ability to switch query menues
Includes
| Includes | Use |
|---|---|
| getMenu | gets current menu selected |
| changeMenu | changes the current menu selected |
Important Dom Elements
| Selector | TagName | Use |
|---|---|---|
| .toggleButton | li | class that helps us select our different route options for changing the menu |
Renderable HTML
let view = `
<ul id="nav_wrapper">
<li class="navLink">OpenMCT Exam - </li>
<li class="navLink toggleButton is-active" data-menu="realTime">Toggle Real-Time </li>
<li class="navLink toggleButton" data-menu="historic">Toggle Historic </li>
</ul>`
2
3
4
5
6
Main Frontend Functions and Methods
| Function | Arguments | Use |
|---|---|---|
| handleClick | event | switches our query menu by sending the event target data-menu |
LeftPaneControl.js
Handles many of the dom updating, querying and state management operations
Includes
| Includes | Use |
|---|---|
| httpInstance | Class used to call historic data |
| handleSlideShow | handle toggling the slide out menu |
| tableDataInstance | Used to access the table data singleton instance |
| wsInstance | Class used to call real time data |
Important Dom Elements
| Selector | TagName | Use |
|---|---|---|
| #wcMenu | div | wrapper for our real time menu |
| #httpMenu | div | wrapper for our historic menu |
| .httpQuery | div | wrapper for our buttons to call 'x' service |
| .wsQuery | div | wrapper for our buttons used to create new ws subscriptions |
| #toggleCustomPanel | div | wrapper for button used to toggle the slideout menu |
| #httpSetSortAscending | div | wrapper for our buttons used to sort historic data ascending |
| #httpSetDescending | div | wrapper for our buttons used to sort historic data descending |
Renderable HTML
let view = `
<div id="wcMenu" class="is-active">
<div class="leftPaneTitle" id="querylatest">
Real-Time Queries
</div>
<hr />
<div class="leftPaneControl is-active wsQuery" data-point="pwr.v,pwr.c">
Query Both
</div>
<div class="leftPaneControl wsQuery" data-point="pwr.v" >
Query Voltage
</div>
<div class="leftPaneControl wsQuery" data-point="pwr.c">
Query Current
</div>
<div class="leftPaneControl wsQuery">
Reset
</div>
<div class="leftPaneTitle">
Toggle Custom Panel
</div>
<hr />
<div class="leftPaneControl" id="toggleCustomPanel">
Custom
</div>
</div>
<div id="httpMenu">
<div class="leftPaneTitle" >
Historic Queries
</div>
<hr />
<div class="leftPaneControl is-active httpQuery" data-point="pwr.v,pwr.c">
Query Latest
</div>
<div class="leftPaneControl httpQuery" data-point="pwr.v">
Query One : A
</div>
<div class="leftPaneControl httpQuery" data-point="pwr.c">
Query One : B
</div>
<div class="leftPaneTitle">
Sorting
</div>
<hr />
<div class="leftPaneControlSort is-active-sort" id="httpSetSortAscending">
Sort Ascending
</div>
<div class="leftPaneControlSort is-active-sort" id="httpSetDescending">
Sort Descending
</div>
</div>`
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Main Frontend Functions and Methods
| Function | Arguments | Use |
|---|---|---|
| changeMenu | menuName | cancels certain connections, clears table data and handles visual appearence of elements |
| toggleSortDescending | none | sorts the historic data descending by timestamp |
| toggleSortAscending | none | sorts the historic data Ascending by timestamp |
| handleWSClick | event | sends new ws subscription messages, an ex. of a single subscription would be 'pointid' a ex of multiple new subscriptions would be 'pointidA,pointidB' |
| handleHTTPClick | event | sends new historic request, like wsclick it also uses the elements data atribute and can call multiple new at a time |
| toggleCustomMenu | none | toggles the slide out menu |
| changeMenu | menuName | handles the switching of our views, and helps maintain table data state |
Services Breakdown
For this exercise, components are arguably the most important pieces of the puzzle. They tell our application, how to look, feel, and move. Primarily throughout the application I choose to stick to singleton class patterns, and generator functions. This allows me to move usefull data, and help maintain state in a framework barren app.
ws.js
Handles all of the queries for websocket real time events
:: tip Unlike http requests to create a websocket connection the url will begin with ws or wss rather than http or https ::
Includes
| Includes | Use |
|---|---|
| tableDataInstance | Class used to retrieve the data table, and attach it to the dom |
Main Frontend Functions and Methods
| Function | Arguments | Use |
|---|---|---|
| createSocketConnection | endpoint | handles our new websocket connection lifecycle |
| handleSubscriptions | points | accepts strings of points to create new subscription messages |
| closeSocket | none | closes the current websocket connection |
http.js
Handles all of the queries for historical data
Includes
| Includes | Use |
|---|---|
| tableDataInstance | Class used to retrieve the data table, and attach it to the dom |
Main Frontend Functions and Methods
| Function | Arguments | Use |
|---|---|---|
| subtract_minutes | dt, minutes | returns a date - x minutes, 15 in our case |
| setSortValue | requestedSort | handles sorting value for results, in the case of no new http call |
| handleRequest | points | handles querying new historic data |
Styles Breakdown
For this exercise, the style files are broken up so that they coorespond to their prospective elements, and sections. There is not much to explain about them though overall the intention was to sort of have fun with building a colorful flexbox based responsive dashboard.