This document is meant to detail the steps and rules to follow to integrate DatafariUI in a div of an existing web app. The example provided uses a simple web app hosted on an apache2 web server, but the key principles are explained so that you can transfer them to your own server technology.
If the page in which you want to include DatafariUI uses the webpack runtime (a react app or anything else) please read Bonus2 at the end of the page prior to any manipulation.
1- Decide the path to which DatafariUI will be deployed
Before starting building the app and moving files, you need to determine a root path from which the DatafariUI will be hosted, all paths under this root will belong to DatafariUI (it uses the URL to navigate through the UI and some assets need to be stored under that path to be accessed by the application).
In our example, our webapp is hosted at /otherfolder and we decided to host DatafariUI on a page under /otherfolder/testdatafariui .
2- Prepare DatafariUI for the build
We need to prepare the DatafariUI application build so that it is ready to be accessed from the desired path. We also need to configure the address of the Datafari we want to call.
Download the source code
The DatafariUI project is on GitHub, the homepage of the project is here :
https://github.com/francelabs/DatafariUI
So do a git clone of the project to download the source code.
Install Node
To build the UI you will need node and npm. Install the latest LTS version of node from their website: https://nodejs.org/en/ (packet managers are often quite behind and older versions might not work as intended).
This should also install npm as part of the installation.
Build and configure for production
Install the dependencies locally
Before building the project, you need to download all the dependencies locally using npm. To do so run the following command at the root directory of the project:
npm install
Configure Datafari for our production case
First open the .env.production file. It contains a PUBLIC_URL
variable we must change to match the root path we decided to use for the page hosting DatafariUI:
PUBLIC_URL=/otherfolder/testdatafariui
The open the src/index.js
file, we must change the window.datafariBaseURL
to match the URL of our Datafari instance (my datafari instance is hosted at 192.168.1.20 with the default settings resulting in the address https://192.168.1.20/Datafari to access it):
window.datafariBaseURL = new URL('/Datafari', "https://192.168.1.20");
The application is now ready to be built
3- Building the app and copying the required files
To build the production ready version of the app go to root folder of the project and run:
npm run build
You now have a build folder in the project folder tree.
You need to copy the folders images, locales and static from this build folder so that they can be accessed from the previously chosen root path for DatafariUI, in my case:
To build the production ready version of the app go to root folder of the project and run:
scp -r build/images build/locales build/static myuser@myserver:/var/www/html/testdatafariui
4- Including the app in the chosen page
You will need to perform two things:
Include the necessary scripts and css into the page
Add a div with the id “root” to your page
Including required scripts and css
Open the index.html file from the build folder of the datafariui project (the file is on one line, you can reformat it to help you copy the required elements). From there, identify and copy the 3 scripts elements at the end of the body and add them to the end of the body of your page. They should look something like the following:
To build the production ready version of the app go to root folder of the project and run:
<script>!function(e){function r(r){for(var n,a,i=r[0],f=r[1],l=r[2],c=0,s=[];c<i.length;c++)a=i[c],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var f=t[i];0!==o[f]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/otherfolder/testdatafariui/";var i=this["webpackJsonpdatafari-ui"]=this["webpackJsonpdatafari-ui"]||[],f=i.push.bind(i);i.push=r,i=i.slice();for(var l=0;l<i.length;l++)r(i[l]);var p=f;t()}([])</script> <script src="/otherfolder/testdatafariui/static/js/2.16c2bde8.chunk.js"></script> <script src="/otherfolder/testdatafariui/static/js/main.4936592f.chunk.js"></script>
Note that the paths of the scripts should already be correct as we configured our build to know from which path our app is accessed, here /otherfolder/testdatafariui
Also copy the two link tags at the end of the head tag, right after the title tag, to the end of the head section of your html page. They should look something like the following:
<link href="/otherfolder/testdatafariui/static/css/2.6681de71.chunk.css" rel="stylesheet"> <link href="/otherfolder/testdatafariui/static/css/main.b597b128.chunk.css" rel="stylesheet">
Including a div with the “root” id
Now add an empty div with the id “root” somewhere on your page:
DatafariUI is expecting to have access to the full width of the page, some UI elements may overflow from their containers if it is not the case. Therefore consider using a div filling the entire width of the page, or at least 90% of it in the worst cases.
<div id="root"></div>
If you want to use another id for the div, it will be explained at the end of this documentation
For reference, here is look at my html page, which is /var/www/html/testdatafariui/index.html in my case (I integrated DatafariUI into the default index page of the ubuntu installation of apache2 here, and enlarged the main div to 90% of the width of the page to have a proper render of the UI):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <!-- Modified from the Debian original for Ubuntu Last updated: 2016-11-16 See: https://launchpad.net/bugs/1288690 --> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Apache2 Ubuntu Default Page: It works</title> <style type="text/css" media="screen"> * { margin: 0px 0px 0px 0px; padding: 0px 0px 0px 0px; } body, html { padding: 3px 3px 3px 3px; background-color: #D8DBE2; font-family: Verdana, sans-serif; font-size: 11pt; text-align: center; } div.main_page { position: relative; display: table; width: 90%; margin-bottom: 3px; margin-left: auto; margin-right: auto; padding: 0px 0px 0px 0px; border-width: 2px; border-color: #212738; border-style: solid; background-color: #FFFFFF; text-align: center; } div.page_header { height: 99px; width: 100%; background-color: #F5F6F7; } div.page_header span { margin: 15px 0px 0px 50px; font-size: 180%; font-weight: bold; } div.page_header img { margin: 3px 0px 0px 40px; border: 0px 0px 0px; } div.table_of_contents { clear: left; min-width: 200px; margin: 3px 3px 3px 3px; background-color: #FFFFFF; text-align: left; } div.table_of_contents_item { clear: left; width: 100%; margin: 4px 0px 0px 0px; background-color: #FFFFFF; color: #000000; text-align: left; } div.table_of_contents_item a { margin: 6px 0px 0px 6px; } div.content_section { margin: 3px 3px 3px 3px; background-color: #FFFFFF; text-align: left; } div.content_section_text { padding: 4px 8px 4px 8px; color: #000000; font-size: 100%; } div.content_section_text pre { margin: 8px 0px 8px 0px; padding: 8px 8px 8px 8px; border-width: 1px; border-style: dotted; border-color: #000000; background-color: #F5F6F7; font-style: italic; } div.content_section_text p { margin-bottom: 6px; } div.content_section_text ul, div.content_section_text li { padding: 4px 8px 4px 16px; } div.section_header { padding: 3px 6px 3px 6px; background-color: #8E9CB2; color: #FFFFFF; font-weight: bold; font-size: 112%; text-align: center; } div.section_header_red { background-color: #CD214F; } div.section_header_grey { background-color: #9F9386; } .floating_element { position: relative; float: left; } div.table_of_contents_item a, div.content_section_text a { text-decoration: none; font-weight: bold; } div.table_of_contents_item a:link, div.table_of_contents_item a:visited, div.table_of_contents_item a:active { color: #000000; } div.table_of_contents_item a:hover { background-color: #000000; color: #FFFFFF; } div.content_section_text a:link, div.content_section_text a:visited, div.content_section_text a:active { background-color: #DCDFE6; color: #000000; } div.content_section_text a:hover { background-color: #000000; color: #DCDFE6; } div.validator { } </style> <link href="/otherfolder/testdatafariui/static/css/2.6681de71.chunk.css" rel="stylesheet"> <link href="/otherfolder/testdatafariui/static/css/main.b597b128.chunk.css" rel="stylesheet"> </head> <body> <div class="main_page"> <div class="page_header floating_element"> <img src="/icons/ubuntu-logo.png" alt="Ubuntu Logo" class="floating_element"/> <span class="floating_element"> Apache2 Ubuntu Default Page </span> </div> <!-- <div class="table_of_contents floating_element"> <div class="section_header section_header_grey"> TABLE OF CONTENTS </div> <div class="table_of_contents_item floating_element"> <a href="#about">About</a> </div> <div class="table_of_contents_item floating_element"> <a href="#changes">Changes</a> </div> <div class="table_of_contents_item floating_element"> <a href="#scope">Scope</a> </div> <div class="table_of_contents_item floating_element"> <a href="#files">Config files</a> </div> </div> --> <div class="content_section floating_element"> <div class="section_header section_header_red"> <div id="about"></div> It works! </div> <div class="content_section_text"> <p> This is the default welcome page used to test the correct operation of the Apache2 server after installation on Ubuntu systems. It is based on the equivalent page on Debian, from which the Ubuntu Apache packaging is derived. If you can read this page, it means that the Apache HTTP server installed at this site is working properly. You should <b>replace this file</b> (located at <tt>/var/www/html/index.html</tt>) before continuing to operate your HTTP server. </p> <p> If you are a normal user of this web site and don't know what this page is about, this probably means that the site is currently unavailable due to maintenance. If the problem persists, please contact the site's administrator. </p> </div> <div class="section_header"> <div id="changes"></div> Configuration Overview </div> <div class="content_section_text"> <p> Ubuntu's Apache2 default configuration is different from the upstream default configuration, and split into several files optimized for interaction with Ubuntu tools. The configuration system is <b>fully documented in /usr/share/doc/apache2/README.Debian.gz</b>. Refer to this for the full documentation. Documentation for the web server itself can be found by accessing the <a href="/manual">manual</a> if the <tt>apache2-doc</tt> package was installed on this server. </p> <p> The configuration layout for an Apache2 web server installation on Ubuntu systems is as follows: </p> <pre> /etc/apache2/ |-- apache2.conf | `-- ports.conf |-- mods-enabled | |-- *.load | `-- *.conf |-- conf-enabled | `-- *.conf |-- sites-enabled | `-- *.conf </pre> <ul> <li> <tt>apache2.conf</tt> is the main configuration file. It puts the pieces together by including all remaining configuration files when starting up the web server. </li> <li> <tt>ports.conf</tt> is always included from the main configuration file. It is used to determine the listening ports for incoming connections, and this file can be customized anytime. </li> <li> Configuration files in the <tt>mods-enabled/</tt>, <tt>conf-enabled/</tt> and <tt>sites-enabled/</tt> directories contain particular configuration snippets which manage modules, global configuration fragments, or virtual host configurations, respectively. </li> <li> They are activated by symlinking available configuration files from their respective *-available/ counterparts. These should be managed by using our helpers <tt> a2enmod, a2dismod, </tt> <tt> a2ensite, a2dissite, </tt> and <tt> a2enconf, a2disconf </tt>. See their respective man pages for detailed information. </li> <li> The binary is called apache2. Due to the use of environment variables, in the default configuration, apache2 needs to be started/stopped with <tt>/etc/init.d/apache2</tt> or <tt>apache2ctl</tt>. <b>Calling <tt>/usr/bin/apache2</tt> directly will not work</b> with the default configuration. </li> </ul> </div> <div class="section_header"> <div id="docroot"></div> Document Roots </div> <div class="content_section_text"> <p> By default, Ubuntu does not allow access through the web browser to <em>any</em> file apart of those located in <tt>/var/www</tt>, <a href="http://httpd.apache.org/docs/2.4/mod/mod_userdir.html" rel="nofollow">public_html</a> directories (when enabled) and <tt>/usr/share</tt> (for web applications). If your site is using a web document root located elsewhere (such as in <tt>/srv</tt>) you may need to whitelist your document root directory in <tt>/etc/apache2/apache2.conf</tt>. </p> <p> The default Ubuntu document root is <tt>/var/www/html</tt>. You can make your own virtual hosts under /var/www. This is different to previous releases which provides better security out of the box. </p> </div> <div class="section_header"> <div id="bugs"></div> Reporting Problems </div> <div class="content_section_text"> <p> Please use the <tt>ubuntu-bug</tt> tool to report bugs in the Apache2 package with Ubuntu. However, check <a href="https://bugs.launchpad.net/ubuntu/+source/apache2" rel="nofollow">existing bug reports</a> before reporting a new bug. </p> <p> Please report bugs specific to modules (such as PHP and others) to respective packages, not to the web server itself. </p> </div> </div> <div id="root"> </div> </div> <div class="validator"> </div> <script>!function(e){function r(r){for(var n,a,i=r[0],f=r[1],l=r[2],c=0,s=[];c<i.length;c++)a=i[c],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var f=t[i];0!==o[f]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/otherfolder/testdatafariui/";var i=this["webpackJsonpdatafari-ui"]=this["webpackJsonpdatafari-ui"]||[],f=i.push.bind(i);i.push=r,i=i.slice();for(var l=0;l<i.length;l++)r(i[l]);var p=f;t()}([])</script> <script src="/otherfolder/testdatafariui/static/js/2.16c2bde8.chunk.js"></script> <script src="/otherfolder/testdatafariui/static/js/main.4936592f.chunk.js"></script> </body> </html>
5- configuring the web server
As stated at the beginning, DatafariUI is using the URL to navigate from one UI to another (from search at /search to preview at /preview for example). However it is a single page application, therefore, any request sent to a URL under the root we chose that does not correspond to a file should be redirected to the page hosting the app. In my example case, the app is hosted by the /otherfolder/testdatafariui/index.html page and I am using apache2 so serve it. Below is the part of my apache2 configuration to achieve the required behavior:
Alias /otherfolder /var/www/html <Directory "/var/www/html"> Require all granted RewriteEngine On RewriteBase "/otherfolder/testdatafariui/" RewriteCond %{REQUEST_FILENAME} !-f RewriteRule "^" "index.html" [QSA,L] </Directory>
Files must be served in the normal way else the page won’t be able to load the js, css, images etc.
The installation is now finished and you should be able to access DatafariUI from the page hosting it:
Bonus 1: Modifying the id required for the div
Before building the datafariui project, you can edit the src/index.js
file. Within it there is this block of code:
ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') );
Change root to the id you want to use for the div and follow the rest of the procedure.
Bonus 2: The page hosting DatafariUI is a react app or it uses the WebPack runtime
DatafariUI is bootstrapped using create-react-app. The app is using the webpack runtime with the default configuration. If your application does the same, there will be a clash of names and only one application will be able to load on the page at any given time. To fix that, follow the information of this blog post: https://medium.jonasbandi.net/hosting-multiple-react-applications-on-the-same-document-c887df1a1fcd to redefine the name of the webpack runtime for one of the application and you should be good to go.