UI Extensions
The Docker-based Cloud CMS UI provides additional extension patterns beyond the AMD-driven mechanism for user
interface components and screens. Since Docker allows you to run on-premise, you can use these extension patterns
to influence more foundational changes to the way the application works.
Environment Variables
When the Cloud CMS user interface starts up, it looks to environment variables to tell it whether there are any
extensions available to be loaded. Extensions are stored with an extensions directory (referred to as /ext
)
which contain a JSON descriptor file and any assets.
CLOUDCMS_UI_EXT_PATH
The CLOUDCMS_UI_EXT_PATH
environment variable tells the Cloud CMS UI the location of your extensions directory.
This can be a relative path (defined relative to the root directory of the Cloud CMS UI application) or it can be
an absolute path somewhere on disk.
Examples:
CLOUDCMS_UI_EXT_PATH=~/projects/cloudcms/ui/ext
CLOUDCMS_UI_EXT_PATH=/ui/ext
CLOUDCMS_UI_EXT_PATH=./ext
CLOUDCMS_UI_EXT_REPLACE
The CLOUDCMS_UI_EXT_REPLACE
environment variable specifies whether you would like your extensions to completely
replace the out-of-the-box configurations (true
) or whether you would like them to merge/override (false
).
The default behavior is to merge/override.
Within your JSON configuration, scalar values like strings and integers are overridden.
Arrays and objects are merged.
Installing into Docker
There are two ways to introduce your extensions into Docker.
Option #1: Using a Volume Mapping
The first way is to keep your extensions on disk locally and map them into the Docker container. This is great
for development since it lets you work locally within your IDE and have your changes reflected right away inside
the container.
Here's how to do it:
Add the following environment variables to your
ui.env
file:CLOUDCMS_UI_EXT_PATH=./ext
CLOUDCMS_UI_EXT_REPLACE=trueEdit your
docker-compose.yml
file for the UI service and map a volume to your development directory:
For example:
ui:
build: ./ui
networks:
- cloudcms
depends_on:
- api
env_file:
- ./ui/ui.env
ports:
- "80:80"
volumes:
- /mydevfolder/ext:/var/app/current/ext
Note that /var/app/current
is the application root. Thus, we're mapping your local extensions files to the./ext
path relative to the application root. This is where the CLOUDCMS_UI_EXT_PATH
variable points.
Option #2: Using a Build
The second way is to copy your extensions into the ui
service's build before running. This is great for
production purposes or for deploying to Docker Machines outside of your laptop (or local computer). For example,
if you wanted to deploy to an Amazon EC2 host using Docker Machine's EC2 driver, this is the way to go.
Here's how to do it:
Add the following environment variables to your
ui.env
file:CLOUDCMS_UI_EXT_PATH=./ext
CLOUDCMS_UI_EXT_REPLACE=true
Note that this is the same as in Option #1.
- Copy your local extension directory to the UI services directory.
For example,
cp -r /mydevfolder/ext ./ui
Modify the UI service's
Dockerfile
and add the following:COPY ext /var/app/current/ext
When you now run docker-compose build --force-rm
, the UI service will be built and it will copy everything
in the UI service's ext
folder to the /var/app/current/ext
path off the application root.
At the moment, Docker Compose does not allow you to COPY contents to the Docker container from outside of the
service folder. As such, step #2 is cumbersome, but necessary. You may be able to utilize an alias or a script
to help you to run these steps in tandem as part of a build process.
Example: Arrested Development
The Cloud CMS SDK includes sample extensions that enhance the user interface to match Netflix's hit show
Arrested Development. The television show is
a lot of fun but we mostly just use it as a means to do some fun theming.
The SDK sample is available here:
[https://github.com/gitana/sdk/tree/master/ui/arrested-development-ext](https://github.com/gitana/sdk/tree/master/ui/arrested-development-ext)
We recommend cloning this repository and inspecting the files contained therein to get a sense of what is possible.
To get started, use Option #1 and do the following:
Add the following environment variables to your
ui.env
file:CLOUDCMS_UI_EXT_PATH=./ext
CLOUDCMS_UI_EXT_REPLACE=trueEdit your
docker-compose.yml
file and add:
volumes:
- /<sdkPath>/ui/arrested-development-ext:/var/app/current/ext
Where sdkPath
is the path to your SDK root directory on disk
/ext
Folder Structure
The folder structure should look like this:
custom-application.json
web
...any web assets
services
...any custom services
Any files under web
will be accessible via the /ext/<path>
URI, allowing you to includes images, custom
JavaScript, CSS and anything else you'd like.
The custom-application.json
file informs the Cloud CMS UI application dispatcher about how to render the
front splash page as well as what HTML to inject into the index.html
file that renders.
Here is an example of how the JSON can look:
{
"app": {
"title": "Cloud CMS"
},
"splash": {
"message": "One moment while the application loads...",
"logo": {
"id": "logo",
"enabled": true,
"config": {
"url": "/splash/cloudcms-splash-logo.png"
}
},
"spinner": {
"id": "spinner-three-bounce",
"enabled": true,
"config": {}
},
"quotes": [{
"quote": "It ain’t about how hard you can hit. It’s about how hard you can get hit and keep moving forward; how much you can take and keep moving forward. That’s how winning is done.",
"author": "Rocky Balboa"
}, {
"quote": "Leaders are made, they are not born. They are made by hard effort, which is the price which all of us must pay to achieve any goal that is worthwhile.",
"author": "Vince Lombardi"
}, {
"quote": "Some luck lies in not getting what you thought you wanted but getting what you have, which once you have got it you may be smart enough to see is what you would have wanted had you known.",
"author": "Garrison Keillor"
}, {
"quote": "Your work is going to fill a large part of your life, and the only way to be truly satisfied is to do what you believe is great work. And the only way to do great work is to love what you do.",
"author": "Steve Jobs"
}, {
"quote": "Usually, in the studio, you just go out and have a play over it, and see what comes, and it's usually - mostly - the first take that's the best one. And you find yourself repeating yourself thereafter.",
"author": "David Gilmour"
}, {
"quote": "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.",
"author": "Thomas Edison"
}, {
"quote": "Imagination will often carry us to worlds that never were. But without it we go nowhere.",
"author": "Carl Sagan"
}, {
"quote": "Things are never quite as scary when you've got a best friend.",
"author": "Bill Watterson"
}, {
"quote": "All we need to do is keep talking.",
"author": "Stephen Hawking"
}, {
"quote": "Actual happiness always looks pretty squalid in comparison with the overcompensations for misery.",
"author": "Aldous Huxley"
}, {
"quote": "To believe your own thought, to believe that what is true for you in your private heart is true for all men — that is genius.",
"author": "Ralph Waldo Emerson"
}, {
"quote": "Can't keep my eyes from the circling skies... tongue-tied and twisted, just an earth-bound misfit, I.",
"author": "Pink Floyd"
}]
},
"footer": {
"logo": "<a href='https://gitana.io' target='_blank'><div class='cloudcms-theme-footer'></div></a>",
"version": "<p class='cloudcms-oneteam-version-tag'></p>",
"copyright": "<p class='copyright-text'>Copyright © 2017 <a href='https://gitana.io' target='_blank'>Gitana Software, Inc.</a> | All Rights Reserved</p>"
},
"services": []
}
The app
section describes general properties about the application.
The splash
section describes how to render the initial Splash or loading page. The splash page is shown right
away while the rest of the application is loading. The application itself is AMD-based which means that it
lazy-loads modules as needed. The user is asked to wait while the initial module set loads and the splash page
is shown in the mean time.
The logo
section provides markup that appears at the bottom of the page. Essentially, the footer is comprised
of a logo on top followed by a version tag and a copyright. You simply provide HTML for these blocks or leave as
an empty string to blank out that section.
The services
section allows to describe HTML blocks that should be injected into the HTML <head>
of theindex.html
page.
Services
Services let you inject HTML into the user interface. You can do this in two places:
- within the
logo
andspinner
blocks for the Splash page - within the
services
array for the overall HTML page's `'.
Each service consists of a Handlebars template that receives a config block to render.
The following out-of-the-box services are available:
google-analytics
This renders the JavaScript code for Google Analytics.
Example:
{
"id": "google-analytics",
"enabled": true,
"config": {
"id": "UA-12345678-9",
"domain": "mydomain.com"
}
}
logo
This renders a logo image onto the page.
Example:
{
"id": "logo",
"enabled": true,
"config": {
"url": "/ext/banana-stand.png"
}
}
spinner-three-bounce
This renders a "please wait" spinner with three bouncing balls.
Example:
{
"spinner": {
"id": "spinner-three-bounce",
"enabled": true,
"config": {}
}
}
spinner-circle
This renders a "please wait" spinner with a rotating circle.
Example:
{
"spinner": {
"id": "spinner-circle",
"enabled": true,
"config": {}
}
}
css
This injects custom CSS into the page.
Example:
{
"id": "css",
"enabled": true,
"config": {
"urls": [
"/ext/custom.css"
]
}
}
favicon
This injects the markup into the page to control the favicon.
Example:
{
"id": "favicon",
"enabled": true,
"config": {
"url": "/ext/custom-favicon.png"
}
}
Build your own services
You can build your own services by adding HTML files to your extension source services
directory.
Example: audio
In the Arrested Development SDK example, we've added an audio.html
file under services
.
The file is really simple and looks like this:
<script>
var a = new Audio("");
a.play();
</script>
It uses the config.url
variable to load up an audio file and play it.
We can therefore configure our index.html
page to use it by adding a services
block like this:
{
"id": "audio",
"enabled": true,
"config": {
"url": [
"/ext/arrested-development.mp3"
]
}
}
When the Cloud CMS UI loads, the <script>
will be injected into the page and the Arrested Development
theme music will play. Odd, yes. But demonstrative of how you can extend the UI.