This is the intranet for Bergmanplast, it's based on the GUIEasy source but with customer specific additions and tweaks.
If you want to manually download and install the front end you should head over to the build directory and find a release you want to use. The builds marked with nightly and rcN are not to be used in production, only as tests. Inside the build/version folder you will find the following files:
- gui.min.css
- src-
<version>
.zip - main/index.htm.gz ← This is what you're looking for
Of these files the actual GUI Easy "engine" is compiled into the main/index.htm.gz file.
The minified css, js, and html files are the backbone of this gz:ed file. The src-<version>
.zip
is the source code of the project as it was at the time of compile. In the directory mini
you will find the minimal interface used as default fallback GUI. For a slimmer "full" version
you may use the noDash version.
If you plan on contributing to the project you need to be able to compile stuff yourself in order to bug test as close as release conditions as possible. What you need to do:
- Install Node.js, this will include npm which is what we use to compile the project.
- Install Grunt.js + dependencies (package.json, run
npm install
from the project root level) - Install Grunt Command Line Interface using your terminal/cmd, and thanks to npm it's this easy:
npm install -g grunt-cli
The compile is then done using your terminal/cmd, make sure you're in the same directory as the Gruntfile.js (this is the root of the project). Run the compile script using this command:
grunt
The script will output something like this (but much more text):
Running "buildGuiEasy" task
>> 0.0.nightly.1
Running "clean:temp" (clean) task
>> 1 path cleaned.
Running "clean:version" (clean) task
>> 0 paths cleaned.
Running "uglify:main_thread" (uglify) task
>> 1 file created 227.5 kB → 136.67 kB
Running "cssmin:target" (cssmin) task
>> 1 file created. 100.84 kB → 86.81 kB
Running "processhtml:main" (processhtml) task
Running "compress:source" (compress) task
>> Compressed 1 file
Running "compress:main" (compress) task
>> Compressed 1 file
Running "compress:mini" (compress) task
>> Compressed 1 file
Running "rename:temp" (rename) task
Renaming Directory build/temp -> build/0.0.nightly.1
Done.
Congrats, you just compiled your build from source!
If you want to just make a dirty compile you can use the command grunt test
. This
command will make a compile of your current code base. The compile script will put the
test build in the /build/0.0.0.0.0
folder and also add a timestamp to the "version".
If you do a new grunt test
the /build/0.0.0.0.0
folder will be wiped clean!
As you will find out the source code is composed by several individual JavaScript files. You need to understand that source code and release build code are two vastly different types of code. The source code base needs to be easy to overlook and "full of comments", whereas the release build should be as small as possible. This is why we use Grunt to compile the source into build code.
We use a SPA (single page application) approach for our GUI. The idea of a SPA is that the browser will never need to jump to new pages, they are all loaded from the root of the web server. The data from the unit, which is constantly updating, is the only thing that is needed to be fetch - not the html elements. This way we save a lot of computing operations of the tiny micro processor which the web server is run by.
We cannot allow us to have backwards compatibility with old web technology (as in IE11 and earlier), newer browsers are always up to date which makes it easier to create a stable GUI.
The index.html is the skeleton of the entire project. We will put all our dynamic html elements into this skeleton, thus creating the complete interface. Lets break the file down, leaving out the generic html syntax and only focusing on what makes this project a bit different compared to other projects.
<head>
<!-- build:css inline build/temp/gui.min.css -->
<link rel="stylesheet" href="src/gui_easy.css">
<!-- /build -->
<!-- build:js inline build/temp/gui.min.js -->
<script src="src/gui_easy_settings.js"></script>
...
<script src="src/gui_easy_ini.js"></script>
<!-- /build -->
</head>
The comments <!-- build:css ... -->
and <!-- build:js ... -->
ending with
<!-- /build -->
are very important for the compile script. These lines tell
the script that the files in-between the opening and closing comments should be
made into one, minified, file and copied to the temp folder. If new .js
files are
created they need to be added to the Gruntfile.js
file as well!
After the head we have the body, this is where we put all the visible elements. To
make the build up of the interface as easy as possible we have created a simple markdown
syntax based on opening and closing curly brackets {{..}}
. There's three major div
elements which you should be aware of:
This div
is only used to give the page a shadow in the top and bottom of the view,
the idea is to get a feeling that the page scrolls beneath the border.
This div
is used to throw modal messages, menus, and the boot screen. Since we want
something to be displayed on the screen until the entire page is ready to be displayed
we need to put static html here. This is where the loading animation comes in.
If the boot sequence isn't successful we still want to see something on the screen.
So we put five dots (of horror) that pulses, this would be the equivalent of Windows' blue screen of death
or Amiga's guru meditation
. In other words, not good. But still a necessity.
Here we put the boot sequence information, the boot (and post boot) are made up of the following hocus pocus:
- Helper
- Curly
- Scrubber
- Popper
- Pitcher
- Butler
- Snitch
- Tender
They are initiated in the order above which can be described as this:
Curly <--- Boot started (+ Helper initiated)
| Curly is converting {{..}} into HTML
Scrubber Scrubber is touching up the HTML
| Popper creates eventhandlers
Popper Pitcher waits for everthing to get ready,
| then starts to apply settings/theme
Pitcher <--- Boot ended
/ | \ <--- GUI is ready
Tender Butler Snitch <--- First human interaction possible
LOOP GET POST <--- The type of flow of the function
Tender continuously updates data and visual stuff
Butler gets data from the internet (1 time)
Snitch posts data to our server (1 time)
These guys are what's making the SPA run smoothly. They can be divided into four groups:
- All around (Helper)
- Builders (Curly, Scrubber, Popper, Pitcher)
- Sprinters (Butler, Snitch)
- Runner (Tender)
We like to think of this bunch as the Snap, Crackle and Pop mascots of the cereal Rice Krispies. Fun, hardworking, dudes that makes our day a bit brighter by their simple existence.
The all around Helper
is used by all the other guys, it doesn't initiate anything
on its own. It only acts on other's request.
Builders are the ones working during the boot. Curly
turn all the {{..}}
into static
html code, some curlies got curlies inside them, so Curly will run as many times as needed
to get all the code converted. Scrubber
got a pretty easy job, it makes some of the
static html code ready for the next guy in line by adding classes and tweaking some elements
etc. Popper
, on the other hand, is constantly aware by creating events and functions
that will create html on-the-fly when these events are fired. Right after that Pitcher
enters the scene and start fetching data from the unit, this guy's only a one time
sprinter and will create the data object and populate the html page with initial values.
Sprinters will get and push data from and to the internet. Butler
get (crude)
location of the client's IP address together with language etc. Snitch
is the guy telling our server
that a new unit has been installed, together with the closest city name, only used for our
internal statistics. We respect the individuals integrity and only use this to know the
fragmentation of the installations. This way we get a better understanding if we need to have full
backwards compatibility etc. etc.
Finally we have the runner, currently only one is existing, Tender
. The idea behind
these guys is that they will continuously get data to and from the unit(s).
The top navbar which contains the tabs. We have two "right" navbar elements, one for full view and one for mobile view. The "right" navbar will be on the second row if the screen isn't big enough to have the "left" and "right" side-by-side.
The wave is one of our elements we can use to notify our users about stuff, it's mainly used to display single words together with a color. As an example, if the user click "save" the wave element will cover the entire view with the text "save" in the "middle" and the color will be set to "success" (green), more on colors later. The message will only last for a second or so and then go away.
Inside this container we have multiple sub-containers with the class container, these containers corresponds to a tab with the exact same name. This will make the Popper display the correct container if a tab is clicked.
The top notifier is used to notify the user about states and errors. It can display short sentences together with a color. The user can click to close this notifier and you can also have it automatically close by setting a countdown timer.
Sticky action button in lower right corner. It floats over all elements but never goes out of view. This menu will only host shortcuts to modal menus and settings save, cancel etc.
A drawer is a menu that resides at the bottom and is accessed by clicking on the tab. The theme drawer hosts all the settings related to the look and feel of the interface.
This is where we have the information that always is displayed. The logo together with sponsors are placed here.
--scale-size: 16;
--row-size: 20;
--overflow-tab-text-size: 24;
--max-width-page-size: 1400px;
--state-of-navbar-toggle: fixed;
--button-radius-size: 1;
--button-icon-size: 0;
--main-bg-color: 52,146,226;
--main-inverted-color: 47,66,82;
--main-sunny-color: 255,209,0;
--main-info-color: 255,143,18;
--main-warning-color: 239,72,61;
--main-success-color: 0,174,65;
--main-font-color: 255,255,255;
--default-font-family: "Segoe UI",Calibri,Arial;
By setting different datasets for click etc. the Popper will automatically create events for these elements. Please refer to the source code on all different ways of doing this.
By commenting using the TODO:
syntax it's easier to find where to start digging.
Any text editor will do but officially we use WebStorm by JetBrains.
We use the following version schema (and is set in the gui_easy_settings.js file):
X.Y.Z
X = major version number: a big jump in features or refactoring of code. This is always set manually when an official new release is deployed.
Y = minor version number: any new features or updates will render at least a minor bump. This is always set manually when an official new release is deployed.
Z = revision version number: any change in source code will be followed by a bump in the revision version number. This is always set automatically each night by our robot. Official releases will always reset this number back to zero and at only very rare occasions (critical bug fix etc.) be part of a official release version.
Apart from these three levels we also have the nightly
and rc<N>
tags. These
are set if the release is made by the robot. The tag is injected into the version name
between the Y
and Z
.
The full version name exemplified:
0.0.nighlty.1
1.2.rc1.112
2.3.0
A release cycle exemplified:
1.0.0
<--- release
1.0.nightly.1
<--- working on a fix or a new major/minor release
...
1.0.nightly.123
<--- we decide that this one will be next 1.1.0
1.0.rc1.124
<--- here's the release candidate (1.0.nightly.123 code base)
1.0.rc2.125
<--- we found some stuff we wanted to change in the rc1
1.1.0
<--- we release 1.0.rc2.125 as 1.1.0
When the Gruntfile.js file is executed it will look into the source and parse the version
data. This is made possible by the opening //--GRUNT-START--
and closing //--GRUNT-END--
tags. Please observe that the ,
after the closing tag need to be on the line below
the tag for the script to function correctly.
To bump revision we have created a Grunt command called grunt bump
. You can do the following
to update the src/gui_easy_settings.js
file:
grunt bump:revision
>> 0.0.nightly.2 --> 0.0.nightly.3
>> 0.0.4 --> 0.0.nightly.5
grunt bump:minor
>> 0.0.nightly.2 --> 0.1.0
grunt bump:major
>> 0.0.nightly.2 --> 1.0.0
grunt bump:rc
>> 0.0.nightly.2 --> 0.0.rc1.3
grunt bump:dev=true
>> 0.0.2 --> 0.0.nightly.2
grunt bump:dev=false
>> 0.0.nightly.2 --> 0.0.2
>> 0.0.rc1.3 --> 0.0.3 <--- this one isn't correct
grunt bump <--- will return current version
>> 0.0.nightly.2
As seen in the second to last example, if you have a release candidate number assigned when you set the development flag to true it will still have that rc number. That being said, you should only use the dev=BOOL to quickly set the version handler to development mode if you by some chance made a mistake when you bumped. The workflow is like this.
You're doing some development and want to bump the version. By simply using the grunt bump:revision
the flag will automatically set the development flag to true. If this isn't desired (you want to push
the current revision number as a production ready version) you can then use the grunt bump:dev=false
.
Normally this isn't wanted, only major and minor releases are the ones that are released as production
ready.
Release candidates are by definition never set to the future major and/or minor level. See this example:
[grunt bump:major] 1.0.0 is already released and we want to create a new version with extra stuff
[grunt bump:revision] 1.0.nightly.1 is created and we start adding the stuff
...
[grunt bump:revision] 1.0.nightly.123 is ready to be tested by a broader user base
[grunt bump:rc] 1.0.rc1.124 is created
...
[grunt bump:rc] 1.0.rc3.126 is the version that is finally accepted
[grunt bump:minor] 1.1.0 is created and released
Another example
[grunt bump:minor] 1.1.0 is already released but we found a bug that cannot wait for next
version to be resolved
[grunt bump:revision] 1.1.nightly.1 is created and we start fixing the bug
...
[grunt bump:revision] 1.1.nightly.5 is ready to be tested by a broader user base
[grunt bump:rc] 1.1.rc1.6 is created and after testing accepted
[grunt bump:revision] 1.1.nightly.7 (since this is the one we want to release as the patched version,
so we need to remove the dev. flag)
[grunt bump:dev=false] 1.1.7 is created and released
As you can see, nightly
and rc
are only states of the code, the revision is still
the actual version together with the major and minor number. You may be used to the term
metadata or tag, anyway, they are not used as actual versions.
You need to have CORS allow cross-domain allowed for the GUI to work running from your localhost server. We use this add-on which lets you turn it on/off by the click of a button.
Full list of contributors who participated in this project.
Please refer to LICENSE.md file for details.
- All icons are sponsored by ICONS8
- Location lookup using ipapi.co
- Weather information API using weatherstack
- Screenshots using html2canvas
- Inspiration for the terminal look of the Drones come from
Terminal.css
found here