Giter Club home page Giter Club logo

malhar-angular-dashboard's Introduction

angular-dashboard

![Gitter](https://badges.gitter.im/Join Chat.svg)

Build Status

Generic AngularJS component/directive providing dashboard/widgets functionality.

Features:

  • Adding/removing widgets

  • Widgets are instantiated dynamically (from corresponding directive or template)

  • Widgets drag and drop (with jQuery UI Sortable)

  • Horizontal and vertical widgets resize

  • Fluid layout (widgets can have percentage-based width, or have width set in any other unit)

  • Any directive or template can be a widget

  • Connecting widgets to real-time data (WebSocket, REST, etc.)

  • Changing widget data source dynamically (from widget options)

  • Saving widgets state to local storage

  • Multiple Dashboard Layouts

Contributing

This project welcomes new contributors.

You acknowledge that your submissions to DataTorrent on this repository are made pursuant the terms of the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html) and constitute "Contributions," as defined therein, and you represent and warrant that you have the right and authority to do so.

When adding new javascript files, please prepend the Apache v2.0 license header, which can be found in CONTRIBUTING.md file.

Examples

Simple demo (minimum dependencies) [source code]

Advanced demo (charts, visualization, data sources, etc.) [source code]

UI Console (very complex application; REST, WebSocket and Socket.IO data sources; dashboard customization; etc.) [source code]

Widget Library using the dashboard [source code]

AngularJS Dashboard

Build

Project is built with Gulp.

   $ npm install -g gulp
   $ gulp

Requirements

  • AngularJS
  • Underscore.js
  • jQuery
  • jQuery UI
  • Angular UI Sortable
  • Angular Bootstrap

Example of including dependencies from CDN here

Getting Started

See demo (several widgets) for a quick start.

Running demo.

   $ bower install
   $ gulp build:demo
   $ gulp serve

Application will be available at http://localhost:3000/

download

With bower:

bower install malhar-angular-dashboard

For legacy reasons, this bower module is also registered as angular-ui-dashboard.

Manually:

Download the zip of this repo and use the files in the dist folder.

include

Load dist/malhar-angular-dashboard.js and dist/malhar-angular-dashboard.css in your html:

<link rel="stylesheet" href="bower_components/malhar-angular-dashboard/dist/malhar-angular-dashboard.css">
<script src="bower_components/malhar-angular-dashboard/dist/malhar-angular-dashboard.js"></script>

Also be sure to add it to your apps dependency list:

angular.module('yourApp', [
  // other dependencies
  'ui.dashboard'
]);

Controller Scope vs. DataModel

Widgets inherit controller scope (so normally different widgets will have bindings to different controller scope properties).

DataModel has direct access to widget scope, each widget has separate instance of DataModel.

Controller Scope vs. DataModel

Usage

Include the dashboard directive on the element you wish to place widgets in:

<div dashboard="dashboardOptions"></div>

Custom Template

It is possible to use your own template for the dashboard and widget markup (replacing dashboard/dashboard.html). To do so, include a template-url attribute on the element to become dashboard:

<div dashboard="dashboardOptions" template-url="path/to/my-template.html"></div>

dashboardOptions

dashboardOptions in the above html is required and should be an object available on the current scope. The options on said object are as follows:

key type default value required description
widgetDefinitions Array n/a yes List of Widget Definition Objects. See below for available options on those.
defaultWidgets Array n/a yes List of objects where an object is { name: [NAME_OF_WIDGET_DEFINITION] }. TODO: Allow just list of names.
widgetButtons Boolean true no Display buttons for adding and removing widgets.
storage Object null no If defined, this object should implement three methods: setItem, getItem, and removeItem. See the Persistence section below.
storageId String null no (yes if storage is defined) This is used as the first parameter passed to the three storage methods above. See the Persistence section below.
storageHash String '' no This is used to validate/invalidate loaded state. See the Persistence section below.
stringifyStorage Boolean true no If set to true, the dashboard state will be converted to a JSON string before being passed to storage.setItem. Likewise, it will be passed through JSON.parse after being retrieved from storage.getItem. See the Persistence section below.
explicitSave Boolean false no The dashboard will not automatically save to storage for every change. Saves must instead be called explicitly using the saveDashboard method that is attached to the option event upon initialization.
sortableOptions Object n/a no Allows to specify the various sortable options of the underlying jQuery UI Sortable.
hideWidgetSettings Boolean false no If true, the cog button in the top right corner of each widget will not be present.
hideWidgetClose Boolean false no If true, the "x" button in the top right corner of each widget will not be present.
settingsModalOptions Object see below no The options object to be passed to the $uibModal service for widget settings. See the Custom Widget Settings section below.
onSettingsClose Function see below no The success callback for when a widget settings dialog is closed by the user. See the Custom Widget Settings section below.
onSettingsDismiss Function see below no The error callback for when a widget settings dialog is dismissed by the user. See the Custom Widget Settings section below.

Upon instantiation, this options object is endowed with a few API methods for use by outside code: addWidget, loadWidgets, saveDashboard and loadDashboard.

Widget Definition Objects

You can think of Widget Definition Objects as a class and the widgets on the page as instances of those classes. The options for a Widget Definition Object are:

key type default value required description
name String n/a true Name of Widget Definition Object. If no templateUrl, template, or directive are on the Widget Definition Object, this is assumed to be a directive name. In other words, the directive attribute is set to this value.
title String n/a false Default title of widget instances
attrs Object n/a false Map of attributes to add to the markup of the widget. Changes to these will be stored when using the storage option
templateUrl String n/a false URL of template to use for widget content
template String n/a false String template (ignored if templateUrl is present)
directive String n/a false HTML-injectable directive name (eg. "ng-show")
dataModelType Function or String n/a false Constructor for the dataModel object, which provides data to the widget (see below for more information).
dataModelOptions Object n/a false Arbitrary values to supply to the dataModel. Available on dataModel instance as this.dataModelOptions. Serializable values in this object will also be saved if storage is being used (see the Persistence section below).
dataModelArgs Object n/a false Object to be passed to data model constructor function. This object is not serialized by default and if defined should be present in widget definitions.
dataAttrName String n/a false Name of attribute to bind widgetData model
storageHash String n/a false This is analogous to the storageHash option on the dashboard, except at a widget-level instead of a dashboard-wide level. This can be helpful if you would only like to invalidate stored state of one widget at a time instead of all widgets.
settingsModalOptions Object see below no Overrides same-named option in dashboard options for this widget. See the Custom Widget Settings section below.
size Object n/a false Widget size, e.g { width: '50%', minWidth: '27%', height: '250px' }
style Object n/a false Widget style, e.g { float: 'right' }
enableVerticalResize Boolean true false Option to enable/disable vertical resize. Should be provided in "widgetDefinitions" since it is not serialized by default.
onSettingsClose Function see below no Overrides same-named option in dashboard options for this widget. See the Custom Widget Settings section below.
onSettingsDismiss Function see below no Overrides same-named option in dashboard options for this widget. See the Custom Widget Settings section below.
serialize Function see below no Define this to override how this widget gets saved to storage. See persistence section below.

As of v1.0.0, you can also add arbitrary data to your WDOs and this data will be copied to your widget. Keep in mind though, that if you want to SAVE some of this arbitrary info with storage, you will need to implement your own serialize method that includes this (see the persistence section below).

Widget Resize

Widgets width and height is controlled with size attribute (serialized by default). Width can be both unit and percentage based.

Example

      {
        name: 'fluid',
        directive: 'wt-fluid',
        size: {
          width: '50%',
          minWidth: '27%',
          height: '250px'
        }
      }

Widgets can be resized both horizontally and vertically and size is serialized.

When widget is resized 'widgetResized' event is broadcasted to the widget scope.

dataModelType

The best way to provide data to a widget is to specify a dataModelType in the Widget Definition Object (above). This function is used as a constructor whenever a new widget is instantiated on the page. If dataModelType is a string it will be looked up with $injector (it should be valid AngularJS provider/factory/service). In most cases data model should implement the following methods: init, and destroy. Please see widget directive file for implementation details.

setup

This function is called once when a widget is instantiated. It takes two arguments: (1) the instance of the WidgetModel constructor that corresponds to the widget instance, and (2) the scope of the widget.

init

This function is called once when a widget is instantiated. This function does not take any arguments.

destroy

This function is called when the widget is removed from the dashboard. It does not take any arguments. It should be used to clean up any listeners that may otherwise hang around, e.g. unsubscribing to a WebSocket topic or RESTful endpoint.

It is recommended to prototypically extend from the WidgetDataModel constructor, which implements the setup function. Take a look at the code here.

Here is an example way to extend from WidgetDataModel:

angular.module('myApp')
  // Inject other services like $http here, if necessary:
  .factory('MyDataModel', ['WidgetDataModel', function (WidgetDataModel) {
      function MyDataModel() {}
      MyDataModel.prototype = Object.create(WidgetDataModel.prototype);
      MyDataModel.prototype.init = function() {
        // My custom data model setup, like subscribing
        // to WebSocket or starting a REST call interval
      }
      MyDataModel.prototype.destroy = function() {
        // My custom data model teardown, like unsubscribing
        // to WebSocket or clearing a setInterval
      }
      return MyDataModel;
    }]);

Persistence

This dashboard component offers a means to save the state of the user's dashboard. Specifically, the dashboard can automatically save:

  • instantiated widgets
  • size of widgets (width and height)
  • order that widgets are displayed
  • widget titles
  • any serializable data stored in dataModelOptions if the widget instance has a ds (instantiated dataModelType)

There are four options you can specify in the dashboardOptions object relating to persistence:

storage (Object)

This object will be used by the dashboard to save its state. It should implement the following three methods:

  • storage.getItem(String key) This method will be used to attempt to retrieve previous dashboard state. It can return either a string or a promise. "promise" in this context simply means an object that has a then function that takes a successCallback and errorCallback as its first and second arguments. This follows the most common promise interface (it works with angular's $q promise, jQuery's $.Deferred() promise, and many others).
  • storage.setItem(String key, String value) This method is assumed to store value in a way that will be accessible later via the getItem method above.
  • storage.removeItem(String key) This method is assumed to remove items set with the setItem method above.

storageId (String)

This string will be used as the key argument in the three methods on the storage object, outlined above. This allows for multiple dashboard instances to exist with storage on a single page and site. This is required in order for storage to work.

storageHash (String)

This string will be stored along with the dashboard state. Then later, when state is loaded, the loaded value will be compared to the value passed to dashboardOptions. If the values are different, the item in storage will be assumed to be invalid and removeItem will be called to clear it out. This is so that if you as the developer makes changes that are not backwards compatible with previous dashboard configurations, you can simply change the storageHash and not have to worry about strange behavior due to stale dashboard state. This is optional but is highly recommended.

stringifyStorage (Boolean)

By default (stringifyStorage=true), the dashboard will convert its state (a JavaScript Object) to a string using JSON.stringify before passing it to storage.setItem. Additionally, the dashboard will assume that storage.getItem will return a JSON string and try to parse it with JSON.parse. This works with window.localStorage nicely, since objects cannot be used as value in localStorage.setItem(key, value). However, if you are implementing your own storage and would not like this stringification business, set stringifyStorage to false.

There are also two options you can specify on WDOs that relate to persistence:

storageHash (String)

Analogous to the storageHash option on the dashboard, except at a widget-level instead of a dashboard-wide level. This can be helpful if you would only like to invalidate stored state of one widget at a time instead of all widgets.

serialize (Function)

This function will determine how the state of the widget gets saved. It takes no arguments and should return a JSON.stringifyable object. The default implementation is as follows:

serialize: function() {
  return _.pick(this, ['title', 'name', 'style', 'size', 'dataModelOptions', 'attrs', 'storageHash']);
}

See _.pick for more details. The most common use-case for this would be to add another key to this list, or remove a key.

Custom Widget Settings

Unless the hideWidgetSettings option is set to true on the dashboard options, each widget by default has a "cog" button in the top right corner that, when clicked, opens up a "modal" (dialog box) with information about the widget and controls to change the title. As of this writing, the default functionality is very minimal; only the widget's title can be changed from this modal. In many cases, you will want to replace and extend the default functionality. In rarer cases, you may even want to override the functionality for a specific widget class. Both of these use-cases are possible using this module.

Principles

To understand how these overrides work, it is beneficial to understand what's happening behind the scenes (if you are looking in the code, the relevant snippet is located in src/directives/dashboard.js, in the method openWidgetSettings). The widget settings modal uses a service called $uibModal from the angular-bootstrap project. Specifically, the dashboard calls $uibModal.open(options) where options is an object containing (ehem) options for the $uibModal service to use. The relevant options for understanding widget settings are:

  • templateUrl: Should point to the template to be used to build the modal markup. The default in this dashboard is template/widget-settings-template.html.
  • controller: A string that points to a registered angular controller. This controller handles the behaviors in the modal. The default in this dashboard is WidgetSettingsCtrl, located at src/controllers/widgetSettingsCtrl.js.
  • resolve: An object where key is an injectable name and value is a function that returns the injected value in the controller. In the case of this dashboard, this property is always set to resolve the widget model so it can be injected into the $uibModal controller.

For a full list of options, visit the angular-bootstrap website and scroll to the $uibModal service section.

When the user is done viewing the modal, it is either dismissed (the user presses "cancel", meaning he wants to discard any changes made) or it is closed (the user presses "ok", meaning he wants to save his changes). These two outcomes are handled by a $uibModalInstance promise that is either resolved or rejected (for information on promises, see the angular documentation).

Overriding Widget Settings for Every Widget

To override the options object that gets passed to $uibModal.open(options) for all widgets (i.e. you want to provide a different default templateUrl and/or controller for all widget settings), you may assign an options object to the settingsModalOptions key in your dashboard options:

// ... in your controller 
$scope.myDashboardOptions = {
  widgetDefinitions: myWidgetDefinitions,
  defaultWidgets: myDefaultWidgets,
  settingsModalOptions: {
    templateUrl: 'my/custom/widgetSettingsTemplate.html',
    controller: 'MyCustomWidgetSettingsCtrl' // defined elsewhere,
    // other $uibModal.open options can go here, eg:
    // backdrop: false,
    // keyboard: false
  }
};

NOTE: The resolve object gets provided to the $uibModal options by the dashboard, and contains only the widget instance as widget. If you put resolve in settingsModalOptions it will be ignored.

To override the callbacks that get passed to the $uibModalInstance promise, assign functions to the onSettingsClose and onSettingsDismiss keys on your dashboard options:

// ... in your controller 
$scope.myDashboardOptions = {
  widgetDefinitions: myWidgetDefinitions,
  defaultWidgets: myDefaultWidgets,
  settingsModalOptions: {
    templateUrl: 'my/custom/widgetSettingsTemplate.html',
    controller: 'MyCustomWidgetSettingsCtrl'
  },
  onSettingsClose: function(resultFromModal, widgetModel, dashboardScope) {
    // do something to update widgetModel, like the default implementation:
    jQuery.extend(true, widget, result);
  },
  onSettingsDismiss: function(reasonForDismissal, dashboardScope) {
    // probably do nothing here, since the user pressed cancel
  }
};

Overriding Widget Settings for a Specific Widget Definition

Overriding widget settings for a specific widget is almost exactly like overriding the default for the entire dashboard, except that you place settingsModalOptions, onSettingsClose, and onSettingsDismiss onto the Widget Definition Object itself:

// ... in your controller 
$scope.myDashboardOptions = {
  widgetDefinitions: [
    {
      name: 'myAwesomeWidget',
      template: '<div>hello {{widget.title}}</div>',
      settingsModalOptions: {
        templateUrl: 'my/custom/widgetSettingsTemplate.html',
        controller: 'MyCustomWidgetSettingsCtrl'
      },
      onSettingsClose: function(resultFromModal, widgetModel, dashboardScope) {
        // do something to update widgetModel, like the default implementation:
        jQuery.extend(true, widget, result);
      },
      onSettingsDismiss: function(reasonForDismissal, dashboardScope) {
        // probably do nothing here, since the user pressed cancel
      }
    }
  ],
  defaultWidgets: myDefaultWidgets
};

Dashboard Layouts

One common requirement for user-customizable dashboards is the ability to have multiple layouts consisting of the same set of widget definitions. This sounds more confusing than it is, so the best way to understand it is to take a look at the layouts demo. You can also see this demo by running gulp serve and navigating to /#/layouts (or /#/layouts/explicit-saving, behavior when options.explicitSave is true). This is achieved by using the dashboard-layouts directive:

<div dashboard-layouts="layoutOptions"></div>

layoutOptions

The layoutOptions object passed to dashboard-layouts tries to mirror dashboardOptions as closely as possible:

key type default value required description
widgetDefinitions Array n/a yes Same as in dashboardOptions
lockDefaultLayouts Boolean false no true to lock default layouts (prevent from removing and renaming), layout lock can also be controlled with locked layout property
defaultLayouts Array n/a yes List of objects where an object is { title: [STRING_LAYOUT_TITLE], active: [BOOLEAN_ACTIVE_STATE], locked: [BOOLEAN], defaultWidgets: [ARRAY_DEFAULT_WIDGETS], widgetDefinitions: [ARRAY_OF_WIDGET_DEFS] }. Note that defaultWidgets is the same as in dashboardOptions. Also note that the widgetDefinitions array is optional on individual default layouts. By default, layouts will use the widgetDefintions from the dashboardLayouts options object. See issue #83.
widgetButtons Boolean true no Same as in dashboardOptions
storage Object null no Same as in dashboardOptions, only the saved objects look like: { layouts: [...], states: {...}, storageHash: '' }
storageId String null no (yes if storage is defined) This is used as the first parameter passed to the three storage methods setItem, getItem, removeItem. See the Persistence section above.
storageHash String '' no Same as in dashboardOptions
stringifyStorage Boolean true no Same as in dashboardOptions
explicitSave Boolean false no Same as in dashboardOptions
sortableOptions Object n/a no Same as in 'dashboardOptions'

As with dashboardOptions, layoutOptions gets endowed with the methods addWidget, loadWidgets, saveDashboard and loadDashboard. These will be applied to the currently active dashboard layout. Additionally, a method called saveLayouts is attached to the layoutOptions object. This method will save the state of the layouts explicitly.

Links

malhar-angular-widgets Widget library (widgets, data models, WebSocket, etc.)

malhar-dashboard-webapp Demo using this dashboard and widget library

Node.js Software platform built on JavaScript runtime

AngularJS JavaScript framework

ui-sortable AngularJS UI Sortable

jQuery UI Sortable jQuery UI Sortable plugin (reordering with drag and drop)

Bower Package manager for the web

Grunt JavaScript task runner

Gulp Streaming build system

malhar-angular-dashboard's People

Contributors

andyperlitch avatar awashbrook avatar bufke avatar cincodenada avatar dean-dt avatar gitter-badger avatar jessicawangdt avatar joebordes avatar mruocco avatar nickholub avatar pablohess avatar peyao avatar sjoerdmulder avatar stickystyle avatar timojuonoja avatar vianvio avatar wvary avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

malhar-angular-dashboard's Issues

Option for widget style

Hello, I just started looking into this project, it seems well done.

I'm looking for an option to set a custom class on the widget div

<div class="dashboard-widget-area">
    <div ng-repeat="widget in widgets" ng-style="widget.style" class="widget-container" widget>
        <div class="widget panel panel-default __here I want to add my own classes__">

The reason being I want to have different themes (colors) for certain widgets.

Do you think it'll be possible?

Widget improvements: instantiation, persistent vs transient state, setting defaults

Hi all,

After several weeks of using this in a real-life project, I have noticed that there are several shortcomings with the current way in which widgets are instantiated, saved, etc. Here are a few things I am thinking about specifically:

More Flexible WDOs

Problem: Currently, when a widget is instantiated using a Widget Definition Object, it picks a hard-coded set of keys to copy. This is pretty rigid and does not allow client code to supply arbitrary data to WDOs that get inherited by instances of those widgets.

Solution: Perform a more generic extend/copy process when instantiating widgets. This will allow for arbitrary data to be passed to the widget instance from WDOs.

Persistent vs. Transient Properties

Problem: There is no way to specify which properties are persistent (should be saved) and which are transient (should not be saved). It is true that this could potentially be handled by a custom storage service, but this is a lot of work for a pretty common customization. This goes for built-in WDO properties. For example, some users have requested that dataModelOptions gets persisted while others have requested that it does not (same for attrs).

Solution: Allow a mechanism for specifying which properties are persistent and which are transient. It should be possible to do this on a per-widget basis as well as dashboard-wide. Perhaps something like this on WDOs:

var myWidgetDefinitions = [
  {
    title: 'default title',
    name: 'name-of-widget',
    directive: 'my-cool-widget',
    dataModelType: MyDataModel,
    dataModelOptions: {
      iAmPersistent: 'value',
      iAmTransient: 'other value'
    },
    attrs: {
      'some-attr': 'someValue'
    },

    // Specify which are transient and which are persistent:
    // Mirrors structure of widget: a "true" value means persist
    persist: {
      title: true,

      // Specify persistence of deep locations
      dataModelOptions: {
        iAmPersistent: true
      },

      // if a location that is an object, all values
      // in that object will inherit that choice.
      // So in this case, no attrs will be saved:
      attrs: false
    }
  }
]

Setting dashboard-wide persist options could look like this on dashboard options:

scope.options = {

  // ... other dashboard options ...

  persistWidgetAttributes: {
    title: true,
    dataModelOptions: {
      iAmPersistent: true
    },
    attrs: false
  }
}

Overriding defaults for ALL instances of dashboard in app

(Ok, this one isn't really widget-related, but I'm on a roll here...)
Problem: A user cannot set the default dashboard options for all instances of dashboard in their apps. Meaning that if you use the same settings for storage and explicitSave, you have to keep putting those options in your dashboard option objects.

Solution (maybe): AFAIK, there is no provider that can be used in .config() blocks for directives. So I am thinking we can add a simple provider/service to the module that holds default options, and can be configured using a config block. The directive will then use this service to provide default options.

I would LOVE to hear feedback from anyone using this module in a non-trivial way.

@awashbrook, @sjoerdmulder, @ceterumnet, @eduardonunesp, @NickPadilla, @hfiedler

optionsTemplateUrl

Hello,

I would like to know where I could add the variable 'optionsTemplateUrl'.

thank you

Widget Options

Hello,

I wanted to know how I can associate my Widget X, to a template Y that will be displayed in the dialog 'Widget Options', I tried, but it still does not work.
I always instead "No edit template specified for this widget ({{}} widget.name)." '

Thank you to explain to me in details, I am still a beginner or give me an example.

Thank you in advance.

Allow for defaultWidgets to be array of strings (as names of the widgets)

Currently you have to specify default widgets like this:

var defaultWidgets = [
  { name: 'My First Widget' },
  { name: 'My Second Widget' }
];

And you should be able to do something like this:

var defaultWidgets = [
  'My First Widget',
  'My Second Widget'
];

You should also be able to mix the two:
And you should be able to do something like this:

var defaultWidgets = [
  'My First Widget',
  { name: 'My Second Widget' }
];

Not possible to have options for individual widgets

As per https://github.com/nickholub/angular-ui-dashboard/blob/master/src/directives/dashboard.js, we seem to be invited to setup our own custom options for a each particular type of Widget Model, rather than using the default ability which is to optionsTemplateUrl, which is for entire dashboard only. However editModalOptions is never set in demo this or sister project.

So below is setting default options when no others were set...

        scope.openWidgetDialog = function (widget) {
          var options = widget.editModalOptions;

          // use default options when none are supplied by widget
          if (!options) {
            options = {
              templateUrl: 'template/widget-template.html',
              resolve: {
                widget: function () {
                  return widget;
                },
                optionsTemplateUrl: function () {
                  return scope.options.optionsTemplateUrl;
                }
              },
              controller: 'WidgetDialogCtrl'
            };
          }
          var modalInstance = $modal.open(options);   

Working on graphite integration and need ability to modify data source for each widget, so have taken the liberty of setting editModalOptions in the constructor for my angular service similar to https://github.com/nickholub/angular-dashboard-app/blob/master/app/scripts/services/datamodel.js.

Once I began setting options for my individual widgets, noticed that all dataModelOptions were attempting to update simultaneously after edit attempt due to bug in Widget Model https://github.com/nickholub/angular-ui-dashboard/blob/master/src/models/widgetModel.js.

Root cause appears to be shallow rather than deep clone of Widget Model, leading to WM Class dataModelOptions being referenced from ALL WM instances!

angular.module('ui.dashboard')
  .factory('WidgetModel', function () {
    // constructor for widget model instances
    function WidgetModel(Class, overrides) {
      overrides = overrides || {};
      angular.extend(this, {
        title: 'Widget',
        name: Class.name,
        attrs: Class.attrs,
        dataAttrName: Class.dataAttrName,
        dataTypes: Class.dataTypes,
        dataModelType: Class.dataModelType,
        dataModelOptions: Class.dataModelOptions,
        style: Class.style
      }, overrides);
      this.style = this.style || { width: '33%' };
      this.setWidth(this.style.width);

Have addressed the issue locally and got my graphite dashboard working. Will raise a pull request accordingly.

Many thanks.

Allow stringifying/parsing storage items to be optional

Right now, it is assumed that items passed to storage.setItem should be passed through JSON.stringify and items returned by storage.getItem will be a string that should be passed through JSON.parse. This should not be an assumption by the dashboard, but rather a parameter in dashboardOptions.

Support live editing of individual widget directive attributes

One of our most important goals for our project is to encourage creation of dashboards by non-developers. We will have a palette of WDO's from which user can instantiate new types of widgets from and configure using widget options/settings dialog. Must be possible to save individual widget configuration and layout on the dash and to persist to backend data store!

Widget configuration includes directive attributes and data source options (#5).

We want to set reasonable defaults for directive attributes in the WDO, eg. here for nvd3-stacked-area-chart

      isArea: true,   
      height: 400,
      showXAxis: true,
      showYAxis: true,
      xAxisTickFormat: 'xAxisTickFormat()',
      interactive: true,
      useInteractiveGuideline: true,
      tooltips: true,
      showLegend: true,        
      showControls: true,        
      color: "colorFunction()",
      forcey: '[0,2]'

We want to be able to enable a generic editing of the attributes set on each widget, just like editing properties in an IDE. Unlike many property dialogs though, we do not intend to support adding new properties, the general idea is we declare reasonable defaults for those attributes is safe to change on the fly.

Ideally we would provide basic validation which respects the type of each attribute (at least distinguishing boolean, strings, longs and doubles), which is why we have not specified everything as strings in the json definition above.

This should be something that can be enabled at the dashboard level along with other Dashboard Options.

This requirement was first discussed as (4) in #2. Working on a pull request. This may fit within the scope of your other enhancement for generic settings dialog (#11).

Improve widget settings dialog

image

There are several things to improve regarding the widget settings dialog:

  • rename and document optionsTemplateUrl for custom widget options in the dialog. Possible names for replacement: dialogTemplateUrl, settingsTemplateUrl
  • add option to provide direct string, eg dialogTemplate/settingsTemplate
  • remove default message "No edit template specified for this widget ({{widget.name}})."

Support continuous saving, rather than incremental

Dashboards are continuously saved today: no "save" button, only "clear" and "revert to defaults".

This is a key UX decision and one with ramifications (how do we provide rollback capability, and does one need to provide full version control...which is why, say, google docs users can thrive without an "undo" button!

This issue is merely to flag this design assumption and potential ramifications of this as our modus operandi!

Few minor issues to flag:

  1. "revert to default" reverts to last saved dashboard (which is always exactly what we see on the screen!) and not the WDO defaults - raising PR
  2. "clear" ing widgets does not save automatically, breaking this model
  3. Deleting a widget initiates save, but Adding widget save was commented out

Loading Definitions After Link

Hi,

Love this dashboard but I need to use it in a slightly different way to what is shown in the examples.

My widget definitions are saved in a database which I access through a service. I do not get hold of the definitions until after the dashboard has loaded. The definitions for the dashboard seem to be initialized when the link function is called on the directive.

Is there any way to supply the definitions to the dashboard after the directive has loaded?

Thanks,

Conor

Very interested in your project, a few questions?

Hey Nick,

Seems we have similar interests in angular and node charting and dashboard technologies. We first glanced at your project soon after you unveiled back in January, and thought it must be too young! Well having checked out the competition back again with renewed interest and have forked your demo project: https://github.com/awashbrook/angular-dashboard-app

Have spend the entire week digesting the code from both projects and very much appreciate your team starting to commit some documentation, which is helping me figure out the delicate separation of concerns between widgets and data models.

Have a few questions:

  1. Looking at operational rather than business dashboards. Are you interested in integrating with with graphite?

  2. Strategically we are set on d3. So far using Rickshaw, but keeping an open mind for nvd3 after seeing your work. Intrigued to find project the directive project so active:https://github.com/cmaurer/angularjs-nvd3-directives. Any strong feelings for either solution?

  3. Are you planning to support basic websockets at the framework level, with meteor optional for those wiling to take the plunge?

  4. Reconfiguring widgets is key for us. So far the topics options dialog is disabled in the demo for the meteor dashboard etc. Hoping to create my own to allow custom selector for browsing graphite metrics soon. However, the design today support modifying only the widget dataModelOptions. We also believe the ability to edit rendering attributes is very import charts (nvd3 has a tons of options!!). What do you think?

Thanks very much for your time and for contributing such a fantastic piece of work.Let me know if you would be interested in more external collaboration on this project in the future?

Error running grunt demo

Hello for all. When I attempt command grunt demo these error message are appeared

Running "connect:livereload" (connect) task
Warning: Object function createServer() {
  function app(req, res, next){ app.handle(req, res, next); }
  merge(app, proto);
  merge(app, EventEmitter.prototype);
  app.route = '/';
  app.stack = [];
  return app;
} has no method 'static' Use --force to continue.

Aborted due to warnings.

How can I fix it?

saveDashboard should not be called on load

Currently it is called by proxy when the handleStateLoad method calls resetWidgetsToDefault, which in turn calls save. While calling resetWidgetsToDefault should trigger a save, this should not occur on initial load.

Dynamic Module Loading with RequireJS

Hello!

Thanks again for this really cool project! We are looking to dynamically load files/modules when a gadget is loaded. This way we don't load everything every time the page loads, only the gadgets that are 'default' and/or saved to local storage. I am wondering at what point should I look to hook in to?

In a perfect world I'd like to add a new widget def field that is something to effect of 'require' and then provide the module we should load. Or provide a callback option that allows us to do the load before adding the widget to the DOM - passing in the 'require' field to the callback. This way we don't create another dependency for your project.

Any ideas or thoughts would be greatly appreciated!

Saving additional widget settings to local storage

Hello,

I have a question regarding the newest version of dashboard directive. What I want to make is that I have additional settings properties defined for a specific widget. What I did till now is:

  • set settingsModalOptions for a widget definition and define new templateUrl
  • this templateUrl points to a copy of widget-settings-template.html with some additional fields defined

Now the problem is that when modal button OK is pressed, these custom fields are not stored into browser's local storage (that's is expected if I take a look at the code in the DasboardState save method). So, my questions are:

  • how do I properly implement saving of custom fields into the same local storage object for a specific widget?
  • how to use this value later in my custom directive as let's say additional filter on the template?

Thank you in advance! Regards.

Non-serializable properties of dataModelOptions get lost after saving to storage

Basically if a WDO looks like this:

// ...
{
    name: 'someName',
    dataModelType: MyDataType,
    dataModelOptions: {
        serializable: 'im a string',
        unserializable: function notSerializable() {}
    }
},
// ...

the unserializable property is no longer present after future loads from storage. We should decide if this is intended behavior or if unserializable attributes of dataModelOptions should be put into WDOs from storage.

Update Angular-UI-Sortable Dependency Version

UI Sortable dependency is old enough compared to project that it's using Angular 1.0 not anything in the 1.2x train. This can be resolved of course via bower, but the dependency should be updated.

Multiple layouts/configurations

Hello,

I stumbled across your project a few weeks ago. It has been very useful in my current project of developing a dashboard with dynamic widgets. I recently just grabbed the latest with the local storage enhancements and it works great. Thanks for providing a great dashboard solution for Angular. I have one question:

1)What is the proper way to save multiple widget configurations inside the dashboard? For instance: I would like to have a set of generic layouts that can be selected from a UI input. A step further would be able to build these layouts. Any advice would be greatly appreciated, because I feel as though I am working against the framework with my implementation.

Widgets to Support Fullscreen Mode

Widgets to support full screen mode.

Want something similar to full screen edit mode "Zen Mode" in github. Although obviously Zen mode takes away distractions, whereas we imagine people wanting to quickly zoom into widget chart, maxing out available space in browser window...in fact gmail fullscreen for composing introduced over last year may be the best user experience to kep in mind!

We may be able to leverage jquery fullscreen, here is one tutorial: http://tutorialzine.com/2012/02/enhance-your-website-fullscreen-api/

Full screen icon would naturally be offered next to existing gear icon for editing.

Resize widgets in x and y direction

This may be a feature request, but if one has a chart it is often desirable to resize both in x and y direction. Say one has a single "banner" chart at the top which is 100% width and 300px high. Then follows two smaller 50% width chart widgets below the banner chart. How would that work with the existing implementation? Can it be done? All 3 widgets would use the same widget template but with different options.

How to load and update dataModelType inside directive

Hi,

I have a project that needs to change some parameters inside the dataModelType, when user changes the params in the widgets. How is the best way to not load dataModelType in widget init and controls that inside my widget. I tested the following code without success.

.directive('wtVolumetry', function ($interval, VolumetryDataModel) {
  return {
    restrict: 'A',
    replace: true,
    templateUrl: 'template/widgets/topN/topN.html',
    scope: {
      data: '=',
    },
    controller: function ($scope) {
      var ds; // data source

      var setDataSource = function() {
        if (!$scope.$parent.widget.dataModelType) {
          ds = new VolumetryDataModel();
          $scope.$parent.widget.dataModel = ds;
          ds.setup($scope.$parent.widget, $scope);
          ds.init();
          $scope.$parent.widget.dataModelType = VolumetryDataModel
          $scope.$on('$destroy', ds.destroy.bind(ds));
        }
      }

     $scope.gridOptions = {
        data: 'items',
        enableRowSelection: true,
        enableColumnResize: true,
        columnDefs: [
          { field: 'name', displayName: 'Calls' },
          { field: 'value', displayName: 'Qty'}
        ]
      };

      $scope.hourInit = "0:00";
      $scope.hourEnd = "23:00";
      setDataSource();
    },
    link: function postLink(scope) {
      scope.$watch('data', function (data) {
        if (data) {
          scope.items = _.sortBy(data, function (item) {
            return (-item.value);
          });
        }
      });
    }
  };
})

[Question] Widgets with same dataModel but different parameters

Hello,

I start to use the dashboard and it's really great and powerful ! I'm new with Angular and feel a little bit lost in the best way to achieve what sounds simple to me : i have a custom widget, i will create a dataModel to feed the widget but i would like to be able to instantiate the widget with some parameters that will be pushed to the dataModel
For example my sensor widget will request data from my DB. The 1st instance will display data for sensor1, the 2nd for sensor2, etc.
Is there any way to achieve that without breaking your project ? ;-)

Auto adjust grid width when resize widget

When my widget is resized the columns of my grid only resize after receive a click at grid header. How to implement a event to make my grid receive that "resize".

My grid options

      $scope.gridOptions = {
        data: 'items',
        enableRowSelection: true,
        enableColumnResize: true,
        columnDefs: [
          { field: 'name', displayName: 'Calls' , width: '*', cellClass: 'grid-align'},
          { field: 'value', displayName: 'Numbers', width: '*',  cellClass: 'grid-align'}
        ]
      };

Widget Progress Bar

I'd like to implement a progress bar in the widget I'm developing based on the Malhar framework.
Does one already exist?

Saving widget attributes when modified with a button inside widget

Hey guys,

First of all, thanks you guys, you are doing a great job. I am currently developing a dashboard based on your solution which is really really awesome and am experiencing a little issue.

I have a widget used tu monitor the activities of a software user.

productionwidget

As you can see on the picture, the user can choose for each monitored activity the monitored period so as the representation style(Table or graph).

The selects and the buttons modify directly the widget attributes, for instance "widget.attrs.myArchivingsPeriod" or "widget.attrs.myArchivingsRepresentationTypeIsTable".

An example of modifying code, this is the case of the select:

When declaring my widget:

{
        name: 'My production monitoring',
        title: 'Mon suivi production',
        directive: 'wt-my-production-monitoring',
        attrs: {
          myArchivingsPeriod: '1day',
          myRestoresPeriod: '1day',
          myArchivingsRepresentationTypeIsTable:'true',
          myRestoresRepresentationTypeIsTable:'true'
        },
        style: {
          width: '50%'
        }
      }

In my directive:

$scope.periods = ['1day', '7days', '30days', '90days', '1year'];

In my widget view(actually written in JADE):

select.col-xs-6.col-sm-6.col-md-6.col-lg-6(name="archivingsPeriod" ng-model="widget.attrs.myArchivingsPeriod" ng-change="updateMyArchivings()" ng-options="period for period in periods")

After doing some testing, I have reached the conclusion that these attributes changes are only persisted to localStorage if I change the size, position or title of the widget.
I guess that widget attributes persistence to localStorage works perfectly using widgets options, but would it be hard to fix this issue?

Thanks in advance and keep the good work up!

Cheers,

Harald

Reason for not using jQuery UI Resizable

Hello,

I was wondering why, if for any particular reason, the dashboard widgets do not use the jQuery UI Resizable plugin? The requirements for this project already include the jQuery UI project for the sortable - could we not include the Resizable as well? This would give us both height and width resizing out of the box. I have integrated it into my project, with a small effort. We can add a resizable configuration attribute so that users can easily configure it.

If your interested in using this kind of functionality I can spend a bit of time creating a feature branch and adding in the functionality. Shouldn't take long at all, but wanted to check in before proceeding in case there is a reason for not including it.

Thanks!

bower install problem

Hi when I try to install dashboard with bower I get this error


bower install angular-ui-dashboard
bower angular-ui-dashboard#*    cached git://github.com/nickholub/angular-ui-dashboard.git#0.1.0
bower angular-ui-dashboard#*  validate 0.1.0 against git://github.com/nickholub/angular-ui-dashboard.git#*
bower jquery-ui#~1.10.3     not-cached git://github.com/components/jqueryui.git#~1.10.3
bower jquery-ui#~1.10.3        resolve git://github.com/components/jqueryui.git#~1.10.3
bower angular#~1.2.6            cached git://github.com/angular/bower-angular.git#1.2.16
bower angular#~1.2.6          validate 1.2.16 against git://github.com/angular/bower-angular.git#~1.2.6
bower underscore#~1.5.2         cached git://github.com/jashkenas/underscore.git#1.5.2
bower underscore#~1.5.2       validate 1.5.2 against git://github.com/jashkenas/underscore.git#~1.5.2
bower angular-bootstrap#0.9.0   cached git://github.com/angular-ui/bootstrap-bower.git#0.9.0
bower angular-bootstrap#0.9.0 validate 0.9.0 against git://github.com/angular-ui/bootstrap-bower.git#0.9.0
bower angular-ui-sortable#~0.10.0           cached git://github.com/angular-ui/ui-sortable.git#0.10.1
bower angular-ui-sortable#~0.10.0         validate 0.10.1 against git://github.com/angular-ui/ui-sortable.git#~0.10.0
bower jquery-ui#~1.10.3                   download https://github.com/components/jqueryui/archive/1.10.4.tar.gz
bower angular#>=1                           cached git://github.com/angular/bower-angular.git#1.2.16
bower angular#>=1                         validate 1.2.16 against git://github.com/angular/bower-angular.git#>=1
bower jquery-ui#>= 1.9                  not-cached git://github.com/components/jqueryui.git#>= 1.9
bower jquery-ui#>= 1.9                     resolve git://github.com/components/jqueryui.git#>= 1.9
bower jquery-ui#>= 1.9                    download https://github.com/components/jqueryui/archive/1.10.4.tar.gz
bower angular#~1.0.x                        cached git://github.com/angular/bower-angular.git#1.0.8
bower angular#~1.0.x                      validate 1.0.8 against git://github.com/angular/bower-angular.git#~1.0.x
bower jquery-ui#~1.10.3                    extract archive.tar.gz
bower jquery-ui#>= 1.9                     extract archive.tar.gz

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: ENOSPC, write

when I tried to install or update other bower components there is no problem.

I did some actions and jquery-ui cause the problem.

About different widgetDefinitions for each layout (tabs)

Good Afternoon,

I was reviewing the current documentation and I notice that the layouts have the restriction of set a define default widgets for al the layouts.

https://github.com/DataTorrent/malhar-angular-dashboard#widget-definition-objects
Dashboard Layouts
One common requirement for user-customizable dashboards is the ability to have multiple layouts consisting of the same set of widget definitions.

Currently, I need to have exactly the opposite and I want to specific set of default widgets for each layout.
I know that the layouts properties are defined in

.controller('LayoutsDemoExplicitSaveCtrl', function($scope, widgetDefinitions, defaultWidgets, LayoutStorage, $interval) {
$scope.layoutOptions = {
storageId: 'demo-layouts-explicit-save',
storage: localStorage,
storageHash: 'fs4df4d51',
widgetDefinitions: widgetDefinitions,
defaultWidgets: defaultWidgets,
explicitSave: true,
defaultLayouts: [
{ title: 'Layout 1', active: true , defaultWidgets: defaultWidgets1 },
{ title: 'Layout 2', active: false, defaultWidgets: defaultWidgets2 },
{ title: 'Layout 3', active: false, defaultWidgets: defaultWidgets3 }
]
};

It is possible to pass the widgetDefinitions for each layout as well as the defaultwidgets?

It is possible to achieve this kind of functionality in any customized way?

Thank you for the hard work.

Regards,

Gabriel Acosta

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.