• Recent
    • Tags
    • Popular
    • Register
    • Login

    Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

    Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website Mango 5 Documentation Website

    How to use mangos own login to secure an AngularJS custom dashboard

    Dashboard Designer & Custom AngularJS Pages
    5
    17
    6.2k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Jared WiltshireJ
      Jared Wiltshire
      last edited by

      Hi nyoa, we added a bare-bones admin template in a folder called adminTemplate. This might be a good starting point for you. Copy the folder to overrides and rename it. You will need to change the require line at the bottom of index.html to suit whatever you renamed the folder to e.g.

      <script>require(['dashboards/myAwesomeApplication/app']);</script>
      

      Some of this info is located in the dashboards help under Basics > Create a dashboard but I think I might need to add some details.

      You will see in that folder that there are two files related to the login page, views/login.html and directives/login/login.html, you can customise these to suit your needs.

      If you want to start from scratch, the way the adminTemplate login works is as follows.

      • We use Angular UI Router 0.2.x
      • We setup states in the config block using $stateProvider
      • All dashboard states have a parent state 'dashboard' which retrieves the current user e.g.
      resolve: {
        auth: ['$rootScope', 'User', function($rootScope, User) {
          $rootScope.user = User.current();
          return $rootScope.user.$promise;
        }]
      }
      
      • We listen for an error when changing states, this occurs we can't retrieve the user in above block i.e. the user isn't logged in
      $rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
        if (error && (error.status === 401 || error.status === 403)) {
          event.preventDefault();
          $state.loginRedirect = toState;
          $state.go('login');
        }
      });
      
      • This redirects the user to the login state which displays the login.html view

      Developer at Radix IoT

      1 Reply Last reply Reply Quote 0
      • B
        Brad_GMI
        last edited by Brad_GMI

        I was able to implement this in my app by hacking up the adminTemplate to my needs.

        However, it would be nice, on logout to redirect to the dashboard login view instead of the mango automation login page. Is there a way to override the existing logout function to achieve this?

        1 Reply Last reply Reply Quote 0
        • Woody BeverleyW
          Woody Beverley
          last edited by

          If I understand your question correctly the answer is, yes. In Mango System Settings -> Dashboard Settings
          0_1463000948703_upload-01ae420b-b2ea-4758-98cc-f006e9b04c06

          Fill out the Login page field.

          -WoodyB

          1 Reply Last reply Reply Quote 0
          • Woody BeverleyW
            Woody Beverley
            last edited by

            The path to your Login page can be a little tricky. In my case I have placed my custom login page in <Mango>/overrides/web/modules/dashboards/web/public/signin.htm

            The path I use in my Dashboard Setting is /public-dashboards/signin.htm

            -WoodyB

            1 Reply Last reply Reply Quote 0
            • N
              nyoa
              last edited by nyoa

              Thank you for your fast replies. I followed Jareds advice and copied the files inside admin template to my dashboard folder at C:\Program Files\mango automation\overrides\web\modules\dashboards\web\FosfaattiFosfori

              I also copied the head part of the template index.html to my own index.html and copied the modified require to the bottom of the file. I didn't quite get it to work with just this so there must be something I missed. It would be great if a custom dashboard login example was added to the tutorials! You have been doing a great job thus far!

              Sometimes when not logged in it redirects me to the login page which is empty and sometimes the login page just loads my index data and displays it. It's quite weird.

              Here is my index.html so you can check if there is something obviously wrong. I didn't touch either of the login files other than copying.

              <!DOCTYPE html>
              <html lang="en" ma-app="maMaterialDashboards" class="no-js">
              <head>
                  <meta charset="utf-8">
                  <meta http-equiv="x-ua-compatible" content="ie=edge">
                  <title>JAMK Fosfaattianalysaattori</title>
                  <meta name="description" content="">
                  <meta name="viewport" content="width=device-width, initial-scale=1">
                  <meta name="mobile-web-app-capable" content="yes">
                  <meta name="apple-mobile-web-app-capable" content="yes">
                  
                  <link rel="icon" type="image/png" sizes="192x192" href="../img/icon192.png">
                  <link rel="icon" type="image/png" sizes="128x128" href="../img/icon128.png">
                  <link rel="apple-touch-icon" type="image/png" sizes="128x128" href="../img/icon128.png">
                  <link rel="apple-touch-icon" type="image/png" sizes="128x128" href="../img/icon128.png">
                  <link rel="manifest" href="manifest.json">
                  
              	<link rel="stylesheet" type="text/css" href="tyylit.css">
                  <link rel="stylesheet" href="/resources/angular-csp.css"></link>
                  <link rel="stylesheet" href="../vendor/angular-material/angular-material.css">
                  <link rel="stylesheet" href="../vendor/angular-loading-bar/loading-bar.css">
                  <link rel="stylesheet" href="../vendor/material-design-icons/iconfont/material-icons.css">
                  <link rel="stylesheet" href="../vendor/font-awesome/css/font-awesome.css">
                  <link rel="stylesheet" href="../vendor/mdPickers/mdPickers.css">
                  <link rel="stylesheet" href="../vendor/angular-material-data-table/md-data-table.css">
                  <link rel="stylesheet" href="styles/main.css">
              </head>
              	<body layout="column">
              		<div ng-if="appLoading">
              			<img src="images/loader.gif" alt="App loading.." style="margin-left:50%;margin-top:25%">
              		</div>
              		<div id="maincontainer" ng-cloak>
              			<header>
              				<img src="images/jamkfi_tunnus_sininen_suomi.png" alt="jamk.fi" style="width:50%;height:50%;margin-left:25%;"> 
              			</header>
              			<div id="textContainer">
              				<img src="images/header.jpg" alt="Fosfaattifosfori PO4-P [µg/l]" style="width:50%;height:50%;margin-left:25%;"> 
              			</div>
              			<div>
              			
              				<ma-get-point-value point-xid="DP_355369" point="point1"></ma-get-point-value>
              
              				<ma-point-values id="testi" point="point1" values="point1Values" from="from" to="to" rollup="AVERAGE" rollup-interval="1 minutes">
              				</ma-point-values>
              
              				<ma-serial-chart id="chartti" style="height: 500px; width: 100%" series-1-values="point1Values" series-1-point="point1" options="{chartCursor:{categoryBalloonDateFormat:'YYYY-MM-DD HH:NN'}, chartScrollbar:{oppositeAxis: false, scrollbarHeight: 40,offset: 25, graph:'DP_355369'}}">
              				</ma-serial-chart>
              				
              				<div id = "control">
              					<div id="selectorDiv" layout="row">
              						<div class="selectorContainer">
              							<md-input-container flex="33" class="no-errors-spacer timeSelector">
              							   <label>Date preset</label>
              							   <ma-date-range-picker from="from" to="to" preset="LAST_1_DAYS" update-interval="1 minutes"></ma-date-range-picker>
              							</md-input-container>
              						</div>
              						<div class="selectorContainer">
              							<md-input-container flex="33" class="no-errors-spacer timeSelector">
              							   <label>From date</label>
              							   <ma-date-picker ng-model="from"></ma-date-picker>
              							</md-input-container>
              						</div>
              						<div class="selectorContainer">
              							<md-input-container flex="33" class="no-errors-spacer timeSelector">
              								<label>To date</label>
              								<ma-date-picker ng-model="to"></ma-date-picker>
              							</md-input-container>
              						</div>
              					</div>
              					<div>
              						<div>
              							<md-button class="md-raised" ng-click="showStats=true;showData=false" ng-hide="showStats">Statistics</md-button>
              							<md-button class="md-raised" ng-click="showStats=false;showData=false" ng-show="showStats">Statistics</md-button>
              							<md-button class="md-raised" ng-click="showData=true;showStats=false" ng-hide="showData">Data</md-button>
              							<md-button class="md-raised" ng-click="showData=false;showStats=false" ng-show="showData">Data</md-button>
              						</div>
              						<div ng-controller="myCtrl">
              							<md-button class="md-raised" ng-click="testi()">Push me</md-button>
              						</div>
              						<div layout="row" ng-show="showStats" class="ng-hide">
              							<ma-point-statistics point="point1" from="from" to="to" statistics="statsObj"></ma-point-statistics>
              
              							<ma-statistics-table id="statsTable" statistics="statsObj"></ma-statistics-table>
              						</div>
              						<div layout="row" ng-show="showData" class="ng-hide">
              							<table width="100%" height="500px">
              								<thead>
              									<tr>
              										<th>Value</th>
              										<th>Time</th>
              									</tr>
              								</thead>
              								<tbody>
              									<tr ng-repeat="item in point1Values">
              										<td>{{item.value}}</td>
              										<td>{{item.timestamp | moment:'format':'lll' }}</td>
              									</tr>
              								</tbody>
              							</table>
              						</div>
              					</div>
              				</div>
              			</div>
              		</div>
              		<script src="https://rawgithub.com/eligrey/FileSaver.js/master/FileSaver.js" type="text/javascript"></script>
              		<script src="/resources/require.js"></script>
              		<script src="/resources/loaderConfig.js"></script>
              		<script src="../js/loaderConfig.js"></script>
              		<script>require(['dashboards/fosfaattifosfori/app']);</script>
              		<script type="text/javascript">require(['mango-3.0/bootstrap']);</script>
              		<script type="text/javascript">require(['dashboards/fosfaattifosfori/export']);</script>
              	</body>
              </html>
              

              I'll upload a picture of my custom dashboard directory so you can tell if I've copied the right things. Thanks for all the help!

              0_1463019045750_customdashboard.PNG

              1 Reply Last reply Reply Quote 0
              • Jared WiltshireJ
                Jared Wiltshire
                last edited by

                OK, couple of things

                • I'm not sure what export.js is doing
                • You shouldn't use 'mango-3.0/bootstrap' if you are bootstrapping your own app inside app.js
                • If the login page is coming up blank then you are probably not loading the login directive correctly inside app.js
                • You need to change the login page as per Woody's instructions above if you want to use the custom dashboard login page as the standard login page for the whole of Mango

                In short you will need to post up the contents of export.js and app.js for us to help you some more.

                Developer at Radix IoT

                1 Reply Last reply Reply Quote 0
                • N
                  nyoa
                  last edited by

                  Thank you a lot. I've used your templates for creating the dashboard so 'mango-3.0/bootstrap' was a remnant from before copying app.js over. The login page isn't required to be standard for mango so it should be for the dashboard only.

                  export.js is there for my custom directives. I'll copy it's content here

                  /**
                   * @copyright 2016 {@link http://infiniteautomation.com|Infinite Automation Systems, Inc.} All rights reserved.
                   * @author Jared Wiltshire
                   */
                  
                  define([
                      'angular',
                      'mango-3.0/maMaterialDashboards'
                  ], function(angular, maMaterialDashboards) {
                  'use strict';
                  
                  var myApp = angular.module('myApp', ['maMaterialDashboards']);
                  
                  myApp.run(['$rootScope', function($rootScope) {
                      $rootScope.pi = function() {
                          return Math.PI;
                      }
                  }]);
                  
                  myApp.directive('myCustomComponent', function() {
                      return {
                          restrict: 'E',
                          scope: {
                              name: '@'
                          },
                          template: '<span>Hello {{name}}!</span>'
                      };
                  });
                  
                  myApp.controller('myCtrl',['$scope', 
                  			$scope.exportData = function(values){
                  				$scope.list = [];
                  				for (var i = 0, len = values.length; i < len; i++) {
                  					$scope.d = new Date(values*.timestamp);
                  					$scope.list.splice(0,0,{"timestamp":$scope.d.toLocaleString(),"value":values*.value});
                  				};
                  			};
                  }]);
                  
                  angular.element(document).ready(function() {
                      angular.bootstrap(document.documentElement, ['myApp']);
                  });
                  
                  }); // define
                  

                  I haven't done any changes to app.js, although it looks like I should change the "state: 'dashboard.home'" to point to the directory I have my index.html in?

                  Here is the content of app.js

                  /**
                   * @copyright 2016 {@link http://infiniteautomation.com|Infinite Automation Systems, Inc.} All rights reserved.
                   * @author Jared Wiltshire
                   */
                  
                  define([
                      'angular',
                      './directives/menu/menuLink',
                      './directives/menu/menuToggle',
                      './directives/login/login',
                      'mango-3.0/maMaterialDashboards',
                      'mango-3.0/maAppComponents',
                      'angular-ui-router',
                      'angular-loading-bar'
                  ], function(angular, menuLink, menuToggle, login, maMaterialDashboards, maAppComponents) {
                  'use strict';
                  
                  var myAdminApp = angular.module('myAdminApp', [
                      'ui.router',
                      'angular-loading-bar',
                      'maMaterialDashboards',
                      'maAppComponents',
                      'ngMessages'
                  ]);
                  
                  myAdminApp
                      .directive('menuLink', menuLink)
                      .directive('menuToggle', menuToggle)
                      .directive('login', login);
                  
                  myAdminApp.constant('PAGES', [
                      {
                          state: 'dashboard',
                          url: '/dashboard',
                          templateUrl: 'views/dashboard/main.html',
                          resolve: {
                              auth: ['$rootScope', 'User', function($rootScope, User) {
                                  $rootScope.user = User.current();
                                  return $rootScope.user.$promise;
                              }]
                          }
                      },
                      {
                          state: 'login',
                          url: '/login',
                          templateUrl: 'views/login.html'
                      },
                      {
                          state: 'dashboard.home',
                          url: '/home',
                          templateUrl: 'views/dashboard/home.html',
                          menuTr: 'dashboards.v3.dox.home',
                          menuIcon: 'fa fa-home',
                          menuType: 'link'
                      },
                      {
                          state: 'dashboard.apiErrors',
                          url: '/api-errors',
                          templateUrl: 'views/dashboard/errors.html',
                          menuTr: 'dashboards.v3.dox.apiErrors'
                      },
                      {
                          state: 'dashboard.section1',
                          url: '/section-1',
                          menuText: 'Section 1',
                          menuIcon: 'fa fa-building',
                          menuType: 'toggle',
                          children: [
                              {
                                  state: 'dashboard.section1.page1',
                                  templateUrl: 'views/section1/page1.html',
                                  url: '/page-1',
                                  menuText: 'Page 1',
                                  menuType: 'link'
                              },
                              {
                                  state: 'dashboard.section1.page2',
                                  templateUrl: 'views/section1/page2.html',
                                  url: '/page-2',
                                  menuText: 'Page 2',
                                  menuType: 'link'
                              }
                          ]
                      },
                      {
                          state: 'dashboard.section2',
                          url: '/section-2',
                          menuText: 'Section 2',
                          menuIcon: 'fa fa-bolt',
                          menuType: 'toggle',
                          children: [
                              {
                                  state: 'dashboard.section2.page1',
                                  templateUrl: 'views/section2/page1.html',
                                  url: '/page-1',
                                  menuText: 'Page 1',
                                  menuType: 'link'
                              },
                              {
                                  state: 'dashboard.section2.page2',
                                  templateUrl: 'views/section2/page2.html',
                                  url: '/page-2',
                                  menuText: 'Page 2',
                                  menuType: 'link'
                              }
                          ]
                      }
                  ]);
                  
                  myAdminApp.config([
                      'PAGES',
                      '$stateProvider',
                      '$urlRouterProvider',
                      '$httpProvider',
                      '$mdThemingProvider',
                      '$injector',
                  function(PAGES, $stateProvider, $urlRouterProvider, $httpProvider, $mdThemingProvider, $injector) {
                  
                      $mdThemingProvider
                          .theme('default')
                          .primaryPalette('yellow')
                          .accentPalette('red');
                  
                      $httpProvider.interceptors.push('errorInterceptor');
                  
                      $urlRouterProvider.otherwise('/dashboard/home');
                      addStates(PAGES);
                      
                      function addStates(pages, parent) {
                          angular.forEach(pages, function(page, area) {
                              if (page.state) {
                                  var state = {
                                      url: page.url
                                  }
                                  
                                  if (page.menuTr) {
                                      state.menuTr = page.menuTr;
                                  }
                                  if (page.menuText) {
                                      state.menuText = page.menuText;
                                  }
                                  
                                  if (parent) {
                                      state.parentPage = parent;
                                  }
                                  
                                  if (page.templateUrl) {
                                      state.templateUrl = page.templateUrl;
                                  } else {
                                      state.template = '<div ui-view></div>';
                                      state['abstract'] = true;
                                  }
                                  
                                  if (page.resolve) {
                                      state.resolve = page.resolve;
                                  }
                                  
                                  $stateProvider.state(page.state, state);
                              }
                              
                              addStates(page.children, page);
                          });
                      }
                  }]);
                  
                  myAdminApp.run([
                      'PAGES',
                      '$rootScope',
                      '$state',
                      '$timeout',
                      '$mdSidenav',
                      '$mdColors',
                      '$MD_THEME_CSS',
                  function(PAGES, $rootScope, $state, $timeout, $mdSidenav, $mdColors, $MD_THEME_CSS) {
                      $rootScope.pages = PAGES;
                      $rootScope.Math = Math;
                      
                      // inserts a style tag to style <a> tags with accent color
                      if ($MD_THEME_CSS) {
                          var acc = $mdColors.getThemeColor('accent-500-1.0');
                          var accT = $mdColors.getThemeColor('accent-500-0.2');
                          var accD = $mdColors.getThemeColor('accent-700-1.0');
                          var styleContent =
                              'a:not(.md-button) {color: ' + acc +'; border-bottom-color: ' + accT + ';}\n' +
                              'a:not(.md-button):hover, a:not(.md-button):focus {color: ' + accD + '; border-bottom-color: ' + accD + ';}\n';
                          
                          var style = document.createElement('style');
                          style.appendChild(document.createTextNode(styleContent));
                          document.head.appendChild(style);
                      }
                  
                      $rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
                          if (error && (error.status === 401 || error.status === 403)) {
                              event.preventDefault();
                              $state.loginRedirect = toState;
                              $state.go('login');
                          }
                      });
                  
                      $rootScope.$on("$stateChangeSuccess", function(event, toState, toParams, fromState, fromParams) {
                          var crumbs = [];
                          var state = toState;
                          do {
                              if (state.menuTr) {
                                  crumbs.unshift({maTr: state.menuTr});
                              } else if (state.menuText) {
                                  crumbs.unshift({text: state.menuText});
                              }
                          } while (state = state.parentPage);
                          $rootScope.crumbs = crumbs;
                      });
                      
                      $rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams) {
                          if ($state.includes('dashboard')) {
                              $rootScope.closeMenu();
                          }
                      });
                  
                      $rootScope.closeMenu = function() {
                          $mdSidenav('left').close();
                      }
                  
                      $rootScope.openMenu = function() {
                          angular.element('#menu-button').blur();
                          $mdSidenav('left').open();
                      }
                  
                  }]);
                  
                  angular.element(document).ready(function() {
                      angular.bootstrap(document.documentElement, ['myAdminApp']);
                  });
                  
                  }); // define
                  
                  1 Reply Last reply Reply Quote 0
                  • Jared WiltshireJ
                    Jared Wiltshire
                    last edited by

                    So what you need to do is to combine the contents of export.js and app.js, at the moment you are trying to bootstrap two separate AngularJS apps on the same element (document.documentElement) which wont work.

                    Either migrate your controller to app.js and remove export.js or migrate the login stuff as per my previous post into export.js and remove app.js. Decided which way to go based on whether you wish to keep the menu and toolbar or not.

                    Developer at Radix IoT

                    1 Reply Last reply Reply Quote 0
                    • B
                      Brad_GMI
                      last edited by Brad_GMI

                      Here is my app.js if it is of any assistance:

                      /**
                       * @copyright 2016 {@link http://infiniteautomation.com|Infinite Automation Systems, Inc.} All rights reserved.
                       * @author Jared Wiltshire
                       */
                      
                      define([
                          'angular',
                          './directives/login/login',
                          'mango-3.0/maMaterialDashboards',
                          'mango-3.0/maAppComponents',
                          'angular-ui-router',
                          'angular-loading-bar'
                      ], function(angular, login, maMaterialDashboards, maAppComponents) {
                      'use strict';
                      
                      var myApp = angular.module('myApp', [
                          'ui.router',
                          'angular-loading-bar',
                          'maMaterialDashboards',
                          'maAppComponents',
                          'ngMessages'
                      ]);
                      
                      myApp
                          .directive('login', login);
                      
                      myApp.constant('PAGES', [
                          {
                              state: 'dashboard',
                              url: '/dashboard',
                              templateUrl: 'views/dashboard/main.html',
                              resolve: {
                                  auth: ['$rootScope', 'User', function($rootScope, User) {
                                      $rootScope.user = User.current();
                                      return $rootScope.user.$promise;
                                  }]
                              }
                          },
                          {
                              state: 'login',
                              url: '/login',
                              templateUrl: 'views/login.html'
                          },
                      	{
                              state: 'dashboard.home',
                              url: '/home',
                              templateUrl: 'views/dashboard/home.html'
                          }
                      ]);
                      
                      myApp.config([
                          'PAGES',
                          '$stateProvider',
                          '$urlRouterProvider',
                          '$httpProvider',
                          '$mdThemingProvider',
                          '$injector',
                      function(PAGES, $stateProvider, $urlRouterProvider, $httpProvider, $mdThemingProvider, $injector) {
                      
                          $mdThemingProvider.theme('default')
                          .dark()
                      	.primaryPalette('orange')
                          .accentPalette('light-blue')
                      	.warnPalette('blue');
                      
                          $httpProvider.interceptors.push('errorInterceptor');
                      
                          $urlRouterProvider.otherwise('/dashboard/home');
                          addStates(PAGES);
                          
                          function addStates(pages, parent) {
                              angular.forEach(pages, function(page, area) {
                                  if (page.state) {
                                      var state = {
                                          url: page.url
                                      }
                      
                                      if (parent) {
                                          state.parentPage = parent;
                                      }
                                      
                                      if (page.templateUrl) {
                                          state.templateUrl = page.templateUrl;
                                      } else {
                                          state.template = '<div ui-view></div>';
                                          state['abstract'] = true;
                                      }
                                      
                                      if (page.resolve) {
                                          state.resolve = page.resolve;
                                      }
                                      
                                      $stateProvider.state(page.state, state);
                                  }
                                  
                                  addStates(page.children, page);
                              });
                          }
                      }]);
                      
                      myApp.run([
                          'PAGES',
                          '$rootScope',
                          '$state',
                          '$timeout',
                          '$mdSidenav',
                          '$mdColors',
                          '$MD_THEME_CSS',
                      function(PAGES, $rootScope, $state, $timeout, $mdSidenav, $mdColors, $MD_THEME_CSS) {
                          $rootScope.pages = PAGES;
                          $rootScope.Math = Math;
                          
                          $rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
                              if (error && (error.status === 401 || error.status === 403)) {
                                  event.preventDefault();
                                  $state.loginRedirect = toState;
                                  $state.go('login');
                              }
                          });
                      }]);
                      
                      angular.element(document).ready(function() {
                          angular.bootstrap(document.documentElement, ['myApp']);
                      });
                      
                      }); // define
                      
                      

                      I took out all of the menu portions for the side nav and the extra pages. My dashboard is only one page at the moment.

                      N 1 Reply Last reply Reply Quote 0
                      • N
                        nyoa @Brad_GMI
                        last edited by

                        @Brad_GMI

                        Thank you a lot for your reference. I tried copying your app.js and see if it would work. It does the redirect to /#/login when the user is not logged in but the page shows my index.html for some reason. I'll upload a picture about the situation.

                        My index.html is the same it was before with the exception that the only require line I have includes the app.js.

                        0_1463067431657_customdashboard.PNG

                        1 Reply Last reply Reply Quote 0
                        • B
                          Brad_GMI
                          last edited by Brad_GMI

                          Here is how my pages are structured:

                          index.html

                          <!DOCTYPE html>
                          <html lang="en" class="no-js">
                          <head>
                              <meta charset="utf-8">
                              <meta http-equiv="x-ua-compatible" content="ie=edge">
                              <title>Demo</title>
                              <meta name="description" content="">
                              <meta name="viewport" content="width=device-width, initial-scale=1">
                              <meta name="mobile-web-app-capable" content="yes">
                              <meta name="apple-mobile-web-app-capable" content="yes">
                              
                              <link rel="icon" type="image/png" sizes="192x192" href="../img/icon192.png">
                              <link rel="icon" type="image/png" sizes="128x128" href="../img/icon128.png">
                              <link rel="apple-touch-icon" type="image/png" sizes="128x128" href="../img/icon128.png">
                              <link rel="apple-touch-icon" type="image/png" sizes="128x128" href="../img/icon128.png">
                              <link rel="manifest" href="manifest.json">
                              
                              <link rel="stylesheet" href="/resources/angular-csp.css"></link>
                              <link rel="stylesheet" href="../vendor/angular-material/angular-material.css">
                              <link rel="stylesheet" href="../vendor/angular-loading-bar/loading-bar.css">
                              <link rel="stylesheet" href="../vendor/material-design-icons/iconfont/material-icons.css">
                              <link rel="stylesheet" href="../vendor/font-awesome/css/font-awesome.css">
                              <link rel="stylesheet" href="../vendor/mdPickers/mdPickers.css">
                              <link rel="stylesheet" href="../vendor/angular-material-data-table/md-data-table.css">
                              <link rel="stylesheet" href="styles/main.css">
                          </head>
                          
                          <body layout="column">
                          	<div ng-if="appLoading" class="app-loading">
                          		<i class="fa fa-cog fa-spin"></i>
                          	</div>
                          
                              <div ui-view ng-cloak layout="column" flex></div>
                          
                              <script src="/resources/require.js"></script>
                              <script src="/resources/loaderConfig.js"></script>
                              <script src="../js/loaderConfig.js"></script>
                              <script>require(['dashboards/Demo/app']);</script>
                          </body>
                          </html>
                          

                          main.html

                          <div ui-view flex="noshrink"></div>
                          
                          

                          You could do away with the main.html if you rework the code a bit, but I expect to use it further along in my dashboard development.

                          The home.html page holds all of my dashboard content. So in order to make it work with my app.js, copy the <body> portion of your index.html into /views/dashboard/home.html and reduce the main.html to something similar to above.

                          1 Reply Last reply Reply Quote 0
                          • B
                            Brad_GMI
                            last edited by

                            Your home.html would look something like this:

                            <div id="maincontainer" ng-cloak>
                            			<header>
                            				<img src="images/jamkfi_tunnus_sininen_suomi.png" alt="jamk.fi" style="width:50%;height:50%;margin-left:25%;"> 
                            			</header>
                            			<div id="textContainer">
                            				<img src="images/header.jpg" alt="Fosfaattifosfori PO4-P [µg/l]" style="width:50%;height:50%;margin-left:25%;"> 
                            			</div>
                            			<div>
                            			
                            				<ma-get-point-value point-xid="DP_355369" point="point1"></ma-get-point-value>
                            
                            				<ma-point-values id="testi" point="point1" values="point1Values" from="from" to="to" rollup="AVERAGE" rollup-interval="1 minutes">
                            				</ma-point-values>
                            
                            				<ma-serial-chart id="chartti" style="height: 500px; width: 100%" series-1-values="point1Values" series-1-point="point1" options="{chartCursor:{categoryBalloonDateFormat:'YYYY-MM-DD HH:NN'}, chartScrollbar:{oppositeAxis: false, scrollbarHeight: 40,offset: 25, graph:'DP_355369'}}">
                            				</ma-serial-chart>
                            				
                            				<div id = "control">
                            					<div id="selectorDiv" layout="row">
                            						<div class="selectorContainer">
                            							<md-input-container flex="33" class="no-errors-spacer timeSelector">
                            							   <label>Date preset</label>
                            							   <ma-date-range-picker from="from" to="to" preset="LAST_1_DAYS" update-interval="1 minutes"></ma-date-range-picker>
                            							</md-input-container>
                            						</div>
                            						<div class="selectorContainer">
                            							<md-input-container flex="33" class="no-errors-spacer timeSelector">
                            							   <label>From date</label>
                            							   <ma-date-picker ng-model="from"></ma-date-picker>
                            							</md-input-container>
                            						</div>
                            						<div class="selectorContainer">
                            							<md-input-container flex="33" class="no-errors-spacer timeSelector">
                            								<label>To date</label>
                            								<ma-date-picker ng-model="to"></ma-date-picker>
                            							</md-input-container>
                            						</div>
                            					</div>
                            					<div>
                            						<div>
                            							<md-button class="md-raised" ng-click="showStats=true;showData=false" ng-hide="showStats">Statistics</md-button>
                            							<md-button class="md-raised" ng-click="showStats=false;showData=false" ng-show="showStats">Statistics</md-button>
                            							<md-button class="md-raised" ng-click="showData=true;showStats=false" ng-hide="showData">Data</md-button>
                            							<md-button class="md-raised" ng-click="showData=false;showStats=false" ng-show="showData">Data</md-button>
                            						</div>
                            						<div ng-controller="myCtrl">
                            							<md-button class="md-raised" ng-click="testi()">Push me</md-button>
                            						</div>
                            						<div layout="row" ng-show="showStats" class="ng-hide">
                            							<ma-point-statistics point="point1" from="from" to="to" statistics="statsObj"></ma-point-statistics>
                            
                            							<ma-statistics-table id="statsTable" statistics="statsObj"></ma-statistics-table>
                            						</div>
                            						<div layout="row" ng-show="showData" class="ng-hide">
                            							<table width="100%" height="500px">
                            								<thead>
                            									<tr>
                            										<th>Value</th>
                            										<th>Time</th>
                            									</tr>
                            								</thead>
                            								<tbody>
                            									<tr ng-repeat="item in point1Values">
                            										<td>{{item.value}}</td>
                            										<td>{{item.timestamp | moment:'format':'lll' }}</td>
                            									</tr>
                            								</tbody>
                            							</table>
                            						</div>
                            					</div>
                            				</div>
                            			</div>
                            		</div>
                            
                            1 Reply Last reply Reply Quote 0
                            • N
                              nyoa
                              last edited by

                              Thank you a lot brad! Thanks to your reference I got it working. I really can't thank you enough for sharing your experience here!

                              I also got a lot clearer idea of the new dashboard module thanks to this discussion.

                              So to summarize all the steps that a newbie like me had to take to get authentication work in my custom dashboard:

                              1. Copy the files in adminTemplate (found at {mango root}\web\modules\dashboards\web) to my custom dashboard directory
                              2. Change the content of my app.js directory to reflect brads.
                              3. Copy the html data between the <body> tags in my old index.html to home.html found in views/dasboard/ directory
                              4. Replace my old index.html file with adminTemplate index.html with the require line modified to point to my dashboard (eg. <script>require(['dashboards/fosfaattifosfori/app']);</script>)
                              5. Changed my main.html to reflect what brad posted earlier

                              I believe steps 2 and 5 aren't necessary to get the thing working, but without those I'd have the side nav and the extra pages.

                              Thank you a lot for all the help you provided!

                              1 Reply Last reply Reply Quote 0
                              • Jared WiltshireJ
                                Jared Wiltshire
                                last edited by

                                Thanks for posting up your pages and helping out Brad!

                                I've added an example for a simple "Single Page App" with a login page using UI Router to the next version of the dashboards module. You can have a look here for reference in the meantime - https://github.com/infiniteautomation/ma-dashboards/tree/master/Custom Dashboards/web/loginPageTemplate

                                Developer at Radix IoT

                                W 1 Reply Last reply Reply Quote 0
                                • W
                                  whileoneloop @Jared Wiltshire
                                  last edited by

                                  @Jared-Wiltshire the link https://github.com/infiniteautomation/ma-dashboards/tree/master/Custom Dashboards/web/loginPageTemplate isn't working atm :)

                                  1 Reply Last reply Reply Quote 0
                                  • Jared WiltshireJ
                                    Jared Wiltshire
                                    last edited by

                                    @whileoneloop the link will be https://github.com/infiniteautomation/ma-dashboards/tree/2.7.x/Custom Dashboards/web/loginPageTemplate now

                                    Developer at Radix IoT

                                    1 Reply Last reply Reply Quote 0
                                    • First post
                                      Last post