diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1cb01152d58..e97ab145c61 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
# 3.0.0 (unrelased master branch)
-### New Features ###
+### New Features
* **Playlists**: Playlists can now be persisted and started from urls, closes [#3655](https://github.com/grafana/grafana/pull/3655)
* **Metadata**: Settings panel now shows dashboard metadata, closes [#3304](https://github.com/grafana/grafana/issues/3304)
* **InfluxDB**: Support for policy selection in query editor, closes [#2018](https://github.com/grafana/grafana/issues/2018)
@@ -10,11 +10,14 @@
**InfluxDB 0.8.x** The data source for the old version of influxdb (0.8.x) is no longer included in default builds. Can easily be installed via improved plugin system, closes #3523
**KairosDB** The data source is no longer included in default builds. Can easily be installed via improved plugin system, closes #3524
-### Enhancements ###
+### Enhancements
* **Sessions**: Support for memcached as session storage, closes [#3458](https://github.com/grafana/grafana/pull/3458)
* **mysql**: Grafana now supports ssl for mysql, closes [#3584](https://github.com/grafana/grafana/pull/3584)
* **snapshot**: Annotations are now included in snapshots, closes [#3635](https://github.com/grafana/grafana/pull/3635)
+### Bug fixes
+* **Playlist**: Fix for memory leak when running a playlist, closes [#3794](https://github.com/grafana/grafana/pull/3794)
+
# 2.6.1 (unrelased, 2.6.x branch)
### New Features
diff --git a/docs/sources/datasources/prometheus.md b/docs/sources/datasources/prometheus.md
index 61f6c0d66e8..a7959a41c51 100644
--- a/docs/sources/datasources/prometheus.md
+++ b/docs/sources/datasources/prometheus.md
@@ -51,6 +51,8 @@ Name | Description
For details of `metric names` & `label names`, and `label values`, please refer to the [Prometheus documentation](http://prometheus.io/docs/concepts/data_model/#metric-names-and-labels).
+> Note: The part of queries is incompatible with the version before 2.6, if you specify like `foo.*`, please change like `metrics(foo.*)`.
+
You can create a template variable in Grafana and have that variable filled with values from any Prometheus metric exploration query.
You can then use this variable in your Prometheus metric queries.
diff --git a/pkg/api/api_plugin.go b/pkg/api/api_plugin.go
index b14afec3a62..751c234bfe8 100644
--- a/pkg/api/api_plugin.go
+++ b/pkg/api/api_plugin.go
@@ -1,13 +1,17 @@
package api
import (
+ "bytes"
"encoding/json"
+ "fmt"
"net/http"
"net/http/httputil"
"net/url"
+ "text/template"
"gopkg.in/macaron.v1"
+ "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
@@ -34,32 +38,28 @@ func InitApiPluginRoutes(r *macaron.Macaron) {
handlers = append(handlers, middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN))
}
}
- handlers = append(handlers, ApiPlugin(route.Url))
+ handlers = append(handlers, ApiPlugin(route, plugin.IncludedInAppId))
r.Route(url, route.Method, handlers...)
log.Info("Plugin: Adding route %s", url)
}
}
}
-func ApiPlugin(routeUrl string) macaron.Handler {
+func ApiPlugin(route *plugins.ApiPluginRoute, includedInAppId string) macaron.Handler {
return func(c *middleware.Context) {
path := c.Params("*")
- //Create a HTTP header with the context in it.
- ctx, err := json.Marshal(c.SignedInUser)
- if err != nil {
- c.JsonApiErr(500, "failed to marshal context to json.", err)
- return
- }
- targetUrl, _ := url.Parse(routeUrl)
- proxy := NewApiPluginProxy(string(ctx), path, targetUrl)
+ proxy := NewApiPluginProxy(c, path, route, includedInAppId)
proxy.Transport = dataProxyTransport
proxy.ServeHTTP(c.Resp, c.Req.Request)
}
}
-func NewApiPluginProxy(ctx string, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy {
+func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins.ApiPluginRoute, includedInAppId string) *httputil.ReverseProxy {
+ targetUrl, _ := url.Parse(route.Url)
+
director := func(req *http.Request) {
+
req.URL.Scheme = targetUrl.Scheme
req.URL.Host = targetUrl.Host
req.Host = targetUrl.Host
@@ -69,7 +69,46 @@ func NewApiPluginProxy(ctx string, proxyPath string, targetUrl *url.URL) *httput
// clear cookie headers
req.Header.Del("Cookie")
req.Header.Del("Set-Cookie")
- req.Header.Add("Grafana-Context", ctx)
+
+ //Create a HTTP header with the context in it.
+ ctxJson, err := json.Marshal(ctx.SignedInUser)
+ if err != nil {
+ ctx.JsonApiErr(500, "failed to marshal context to json.", err)
+ return
+ }
+
+ req.Header.Add("Grafana-Context", string(ctxJson))
+ // add custom headers defined in the plugin config.
+ for _, header := range route.Headers {
+ var contentBuf bytes.Buffer
+ t, err := template.New("content").Parse(header.Content)
+ if err != nil {
+ ctx.JsonApiErr(500, fmt.Sprintf("could not parse header content template for header %s.", header.Name), err)
+ return
+ }
+
+ jsonData := make(map[string]interface{})
+
+ if includedInAppId != "" {
+ //lookup appSettings
+ query := m.GetAppSettingByAppIdQuery{OrgId: ctx.OrgId, AppId: includedInAppId}
+
+ if err := bus.Dispatch(&query); err != nil {
+ ctx.JsonApiErr(500, "failed to get AppSettings of includedAppId.", err)
+ return
+ }
+
+ jsonData = query.Result.JsonData
+ }
+
+ err = t.Execute(&contentBuf, jsonData)
+ if err != nil {
+ ctx.JsonApiErr(500, fmt.Sprintf("failed to execute header content template for header %s.", header.Name), err)
+ return
+ }
+ log.Debug("Adding header to proxy request. %s: %s", header.Name, contentBuf.String())
+ req.Header.Add(header.Name, contentBuf.String())
+ }
}
return &httputil.ReverseProxy{Director: director}
diff --git a/pkg/api/dtos/apps.go b/pkg/api/dtos/apps.go
index b2b33370135..d10883a26d7 100644
--- a/pkg/api/dtos/apps.go
+++ b/pkg/api/dtos/apps.go
@@ -31,6 +31,7 @@ func NewAppSettingsDto(def *plugins.AppPlugin, data *models.AppSettings) *AppSet
dto.Enabled = data.Enabled
dto.Pinned = data.Pinned
dto.Info = &def.Info
+ dto.JsonData = data.JsonData
}
return dto
diff --git a/pkg/models/app_settings.go b/pkg/models/app_settings.go
index 558946d0277..f3b60502cb0 100644
--- a/pkg/models/app_settings.go
+++ b/pkg/models/app_settings.go
@@ -1,6 +1,13 @@
package models
-import "time"
+import (
+ "errors"
+ "time"
+)
+
+var (
+ ErrAppSettingNotFound = errors.New("AppSetting not found")
+)
type AppSettings struct {
Id int64
@@ -33,3 +40,9 @@ type GetAppSettingsQuery struct {
OrgId int64
Result []*AppSettings
}
+
+type GetAppSettingByAppIdQuery struct {
+ AppId string
+ OrgId int64
+ Result *AppSettings
+}
diff --git a/pkg/plugins/api_plugin.go b/pkg/plugins/api_plugin.go
new file mode 100644
index 00000000000..efb16e696d8
--- /dev/null
+++ b/pkg/plugins/api_plugin.go
@@ -0,0 +1,38 @@
+package plugins
+
+import (
+ "encoding/json"
+
+ "github.com/grafana/grafana/pkg/models"
+)
+
+type ApiPluginRoute struct {
+ Path string `json:"path"`
+ Method string `json:"method"`
+ ReqSignedIn bool `json:"reqSignedIn"`
+ ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"`
+ ReqRole models.RoleType `json:"reqRole"`
+ Url string `json:"url"`
+ Headers []ApiPluginHeader `json:"headers"`
+}
+
+type ApiPlugin struct {
+ PluginBase
+ Routes []*ApiPluginRoute `json:"routes"`
+}
+
+type ApiPluginHeader struct {
+ Name string `json:"name"`
+ Content string `json:"content"`
+}
+
+func (app *ApiPlugin) Load(decoder *json.Decoder, pluginDir string) error {
+ if err := decoder.Decode(&app); err != nil {
+ return err
+ }
+
+ app.PluginDir = pluginDir
+
+ ApiPlugins[app.Id] = app
+ return nil
+}
diff --git a/pkg/plugins/app_plugin.go b/pkg/plugins/app_plugin.go
index 898065be8a2..d2291d487ac 100644
--- a/pkg/plugins/app_plugin.go
+++ b/pkg/plugins/app_plugin.go
@@ -59,6 +59,18 @@ func (app *AppPlugin) Load(decoder *json.Decoder, pluginDir string) error {
}
}
+ // check if we have child apiPlugins
+ for _, plugin := range ApiPlugins {
+ if strings.HasPrefix(plugin.PluginDir, app.PluginDir) {
+ plugin.IncludedInAppId = app.Id
+ app.Includes = append(app.Includes, AppIncludeInfo{
+ Name: plugin.Name,
+ Id: plugin.Id,
+ Type: plugin.Type,
+ })
+ }
+ }
+
Apps[app.Id] = app
return nil
}
diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go
index 375bdf1a52c..b302181e840 100644
--- a/pkg/plugins/models.go
+++ b/pkg/plugins/models.go
@@ -2,8 +2,6 @@ package plugins
import (
"encoding/json"
-
- "github.com/grafana/grafana/pkg/models"
)
type PluginLoader interface {
@@ -44,20 +42,6 @@ type PluginStaticRoute struct {
PluginId string
}
-type ApiPluginRoute struct {
- Path string `json:"path"`
- Method string `json:"method"`
- ReqSignedIn bool `json:"reqSignedIn"`
- ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"`
- ReqRole models.RoleType `json:"reqRole"`
- Url string `json:"url"`
-}
-
-type ApiPlugin struct {
- PluginBase
- Routes []*ApiPluginRoute `json:"routes"`
-}
-
type EnabledPlugins struct {
Panels []*PanelPlugin
DataSources map[string]*DataSourcePlugin
diff --git a/pkg/services/sqlstore/app_settings.go b/pkg/services/sqlstore/app_settings.go
index e9bfbeaa73b..7d9482e7b22 100644
--- a/pkg/services/sqlstore/app_settings.go
+++ b/pkg/services/sqlstore/app_settings.go
@@ -9,6 +9,7 @@ import (
func init() {
bus.AddHandler("sql", GetAppSettings)
+ bus.AddHandler("sql", GetAppSettingByAppId)
bus.AddHandler("sql", UpdateAppSettings)
}
@@ -19,6 +20,18 @@ func GetAppSettings(query *m.GetAppSettingsQuery) error {
return sess.Find(&query.Result)
}
+func GetAppSettingByAppId(query *m.GetAppSettingByAppIdQuery) error {
+ appSetting := m.AppSettings{OrgId: query.OrgId, AppId: query.AppId}
+ has, err := x.Get(&appSetting)
+ if err != nil {
+ return err
+ } else if has == false {
+ return m.ErrAppSettingNotFound
+ }
+ query.Result = &appSetting
+ return nil
+}
+
func UpdateAppSettings(cmd *m.UpdateAppSettingsCmd) error {
return inTransaction2(func(sess *session) error {
var app m.AppSettings
diff --git a/public/app/core/utils/file_export.ts b/public/app/core/utils/file_export.ts
new file mode 100644
index 00000000000..ad203f58495
--- /dev/null
+++ b/public/app/core/utils/file_export.ts
@@ -0,0 +1,37 @@
+///
+
+import _ from 'lodash';
+
+declare var window: any;
+
+export function exportSeriesListToCsv(seriesList) {
+ var text = 'Series;Time;Value\n';
+ _.each(seriesList, function(series) {
+ _.each(series.datapoints, function(dp) {
+ text += series.alias + ';' + new Date(dp[1]).toISOString() + ';' + dp[0] + '\n';
+ });
+ });
+ saveSaveBlob(text, 'grafana_data_export.csv');
+};
+
+export function exportTableDataToCsv(table) {
+ var text = '';
+ // add header
+ _.each(table.columns, function(column) {
+ text += column.text + ';';
+ });
+ text += '\n';
+ // process data
+ _.each(table.rows, function(row) {
+ _.each(row, function(value) {
+ text += value + ';';
+ });
+ text += '\n';
+ });
+ saveSaveBlob(text, 'grafana_data_export.csv');
+};
+
+export function saveSaveBlob(payload, fname) {
+ var blob = new Blob([payload], { type: "text/csv;charset=utf-8" });
+ window.saveAs(blob, fname);
+};
diff --git a/public/app/core/utils/kbn.js b/public/app/core/utils/kbn.js
index e323a9223e3..959de5fa42a 100644
--- a/public/app/core/utils/kbn.js
+++ b/public/app/core/utils/kbn.js
@@ -179,17 +179,6 @@ function($, _) {
.replace(/ +/g,'-');
};
- kbn.exportSeriesListToCsv = function(seriesList) {
- var text = 'Series;Time;Value\n';
- _.each(seriesList, function(series) {
- _.each(series.datapoints, function(dp) {
- text += series.alias + ';' + new Date(dp[1]).toISOString() + ';' + dp[0] + '\n';
- });
- });
- var blob = new Blob([text], { type: "text/csv;charset=utf-8" });
- window.saveAs(blob, 'grafana_data_export.csv');
- };
-
kbn.stringToJsRegex = function(str) {
if (str[0] !== '/') {
return new RegExp('^' + str + '$');
diff --git a/public/app/features/apps/partials/edit.html b/public/app/features/apps/partials/edit.html
index aae34b8b38d..20df40bd247 100644
--- a/public/app/features/apps/partials/edit.html
+++ b/public/app/features/apps/partials/edit.html
@@ -98,6 +98,8 @@
diff --git a/public/app/features/dashboard/submenu/submenu.ts b/public/app/features/dashboard/submenu/submenu.ts
index 7e304d88464..75f0778b01f 100644
--- a/public/app/features/dashboard/submenu/submenu.ts
+++ b/public/app/features/dashboard/submenu/submenu.ts
@@ -7,6 +7,7 @@ export class SubmenuCtrl {
variables: any;
dashboard: any;
+ /** @ngInject */
constructor(private $rootScope, private templateValuesSrv, private dynamicDashboardSrv) {
this.annotations = this.dashboard.templating.list;
this.variables = this.dashboard.templating.list;
diff --git a/public/app/features/dashlinks/module.js b/public/app/features/dashlinks/module.js
index b7029e6cf2d..f133290ceb2 100644
--- a/public/app/features/dashlinks/module.js
+++ b/public/app/features/dashlinks/module.js
@@ -159,7 +159,7 @@ function (angular, _) {
};
updateDashLinks();
- $rootScope.onAppEvent('dash-links-updated', updateDashLinks, $rootScope);
+ $rootScope.onAppEvent('dash-links-updated', updateDashLinks, $scope);
});
module.controller('DashLinkEditorCtrl', function($scope, $rootScope) {
diff --git a/public/app/features/playlist/partials/playlist-remove.html b/public/app/features/playlist/partials/playlist-remove.html
deleted file mode 100644
index 8474f97f8de..00000000000
--- a/public/app/features/playlist/partials/playlist-remove.html
+++ /dev/null
@@ -1,5 +0,0 @@
-Are you sure want to delete "{{playlist.title}}" playlist?
-
-
-
-
diff --git a/public/app/features/playlist/playlist_edit_ctrl.js b/public/app/features/playlist/playlist_edit_ctrl.js
index 3817ec12634..9b493c47d25 100644
--- a/public/app/features/playlist/playlist_edit_ctrl.js
+++ b/public/app/features/playlist/playlist_edit_ctrl.js
@@ -132,11 +132,11 @@ function (angular, config, _) {
};
$scope.movePlaylistItemUp = function(playlistItem) {
- $scope.moveDashboard(playlistItem, -1);
+ $scope.movePlaylistItem(playlistItem, -1);
};
$scope.movePlaylistItemDown = function(playlistItem) {
- $scope.moveDashboard(playlistItem, 1);
+ $scope.movePlaylistItem(playlistItem, 1);
};
$scope.init();
diff --git a/public/app/features/playlist/playlist_srv.ts b/public/app/features/playlist/playlist_srv.ts
index 0570a3bfc85..8c6be5edaf5 100644
--- a/public/app/features/playlist/playlist_srv.ts
+++ b/public/app/features/playlist/playlist_srv.ts
@@ -1,6 +1,7 @@
///
import angular from 'angular';
+import config from 'app/core/config';
import coreModule from '../../core/core_module';
import kbn from 'app/core/utils/kbn';
@@ -20,10 +21,9 @@ class PlaylistSrv {
var playedAllDashboards = this.index > this.dashboards.length - 1;
if (playedAllDashboards) {
- this.start(this.playlistId);
+ window.location.href = `${config.appSubUrl}/playlists/play/${this.playlistId}`;
} else {
var dash = this.dashboards[this.index];
-
this.$location.url('dashboard/' + dash.uri);
this.index++;
diff --git a/public/app/grafana.ts b/public/app/grafana.ts
index 7316a8164bc..d9ad3a449d3 100644
--- a/public/app/grafana.ts
+++ b/public/app/grafana.ts
@@ -1,6 +1,7 @@
///
import 'bootstrap';
+import 'vendor/filesaver';
import 'lodash-src';
import 'angular-strap';
import 'angular-route';
diff --git a/public/app/plugins/datasource/elasticsearch/directives.js b/public/app/plugins/datasource/elasticsearch/directives.js
deleted file mode 100644
index 3bb27885ef2..00000000000
--- a/public/app/plugins/datasource/elasticsearch/directives.js
+++ /dev/null
@@ -1,56 +0,0 @@
-define([
- 'angular',
- './bucket_agg',
- './metric_agg',
-],
-function (angular) {
- 'use strict';
-
- var module = angular.module('grafana.directives');
-
- module.directive('metricQueryEditorElasticsearch', function() {
- return {controller: 'ElasticQueryCtrl', templateUrl: 'app/plugins/datasource/elasticsearch/partials/query.editor.html'};
- });
-
- module.directive('metricQueryOptionsElasticsearch', function() {
- return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/query.options.html'};
- });
-
- module.directive('annotationsQueryEditorElasticsearch', function() {
- return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/annotations.editor.html'};
- });
-
- module.directive('elastic', function() {
- return {templateUrl: 'app/plugins/datasource/elasticsearch/partials/config.html'};
- });
-
- module.directive('elasticMetricAgg', function() {
- return {
- templateUrl: 'app/plugins/datasource/elasticsearch/partials/metric_agg.html',
- controller: 'ElasticMetricAggCtrl',
- restrict: 'E',
- scope: {
- target: "=",
- index: "=",
- onChange: "&",
- getFields: "&",
- esVersion: '='
- }
- };
- });
-
- module.directive('elasticBucketAgg', function() {
- return {
- templateUrl: 'app/plugins/datasource/elasticsearch/partials/bucket_agg.html',
- controller: 'ElasticBucketAggCtrl',
- restrict: 'E',
- scope: {
- target: "=",
- index: "=",
- onChange: "&",
- getFields: "&",
- }
- };
- });
-
-});
diff --git a/public/app/plugins/datasource/mixed/datasource.ts b/public/app/plugins/datasource/mixed/datasource.ts
index bd0628fe210..b5cea9cc5a8 100644
--- a/public/app/plugins/datasource/mixed/datasource.ts
+++ b/public/app/plugins/datasource/mixed/datasource.ts
@@ -5,6 +5,7 @@ import _ from 'lodash';
class MixedDatasource {
+ /** @ngInject */
constructor(private $q, private datasourceSrv) {
}
diff --git a/public/app/plugins/panel/graph/module.js b/public/app/plugins/panel/graph/module.js
index 47d0e4f83a3..c1039e394a3 100644
--- a/public/app/plugins/panel/graph/module.js
+++ b/public/app/plugins/panel/graph/module.js
@@ -3,13 +3,14 @@ define([
'lodash',
'moment',
'app/core/utils/kbn',
+ 'app/core/utils/file_export',
'app/core/time_series',
'app/features/panel/panel_meta',
'./seriesOverridesCtrl',
'./graph',
'./legend',
],
-function (angular, _, moment, kbn, TimeSeries, PanelMeta) {
+function (angular, _, moment, kbn, fileExport, TimeSeries, PanelMeta) {
'use strict';
/** @ngInject */
@@ -282,7 +283,7 @@ function (angular, _, moment, kbn, TimeSeries, PanelMeta) {
};
$scope.exportCsv = function() {
- kbn.exportSeriesListToCsv($scope.seriesList);
+ fileExport.exportSeriesListToCsv($scope.seriesList);
};
panelSrv.init($scope);
diff --git a/public/app/plugins/panel/table/controller.ts b/public/app/plugins/panel/table/controller.ts
index f05a36c4cdf..376f36fd84d 100644
--- a/public/app/plugins/panel/table/controller.ts
+++ b/public/app/plugins/panel/table/controller.ts
@@ -3,6 +3,7 @@
import angular from 'angular';
import _ from 'lodash';
import moment from 'moment';
+import * as FileExport from 'app/core/utils/file_export';
import PanelMeta from 'app/features/panel/panel_meta2';
import {transformDataToTable} from './transformers';
@@ -22,6 +23,7 @@ export class TablePanelCtrl {
$scope.panelMeta.addEditorTab('Options', 'app/plugins/panel/table/options.html');
$scope.panelMeta.addEditorTab('Time range', 'app/features/panel/partials/panelTime.html');
+ $scope.panelMeta.addExtendedMenuItem('Export CSV', '', 'exportCsv()');
var panelDefaults = {
targets: [{}],
@@ -124,6 +126,10 @@ export class TablePanelCtrl {
panelHelper.broadcastRender($scope, $scope.table, $scope.dataRaw);
};
+ $scope.exportCsv = function() {
+ FileExport.exportTableDataToCsv($scope.table);
+ };
+
$scope.init();
}
}
diff --git a/public/less/sidemenu.less b/public/less/sidemenu.less
index 3bb1ae393a7..61882f0e4c3 100644
--- a/public/less/sidemenu.less
+++ b/public/less/sidemenu.less
@@ -13,6 +13,7 @@
min-height: 100%;
z-index: 101;
transform: translate3d(-100%, 0, 0);
+ visibility: hidden;
a:focus {
text-decoration: none;
diff --git a/public/views/index.html b/public/views/index.html
index 2d05f414658..728cd084c88 100644
--- a/public/views/index.html
+++ b/public/views/index.html
@@ -56,8 +56,10 @@
+
+
diff --git a/symlink_git_hooks.sh b/symlink_git_hooks.sh
index 7c3b58feaca..9e272f82ed6 100755
--- a/symlink_git_hooks.sh
+++ b/symlink_git_hooks.sh
@@ -1,3 +1,5 @@
#/bin/bash
-ln -s .hooks/* .git/hooks/
+#ln -s -f .hooks/* .git/hooks/
+cd .git/hooks/
+cp --symbolic-link -f ../../.hooks/* .
diff --git a/tasks/build_task.js b/tasks/build_task.js
index d10a83d78dc..d844b661722 100644
--- a/tasks/build_task.js
+++ b/tasks/build_task.js
@@ -10,7 +10,7 @@ module.exports = function(grunt) {
'clean:release',
'copy:public_to_gen',
'typescript:build',
- // 'karma:test',
+ 'karma:test',
'phantomjs',
'css',
'htmlmin:build',
diff --git a/tasks/options/concat.js b/tasks/options/concat.js
index f62e1f09982..0c76ce98d23 100644
--- a/tasks/options/concat.js
+++ b/tasks/options/concat.js
@@ -28,8 +28,10 @@ module.exports = function(config) {
js: {
src: [
+ '<%= genDir %>/vendor/npm/es5-shim/es5-shim.js',
'<%= genDir %>/vendor/npm/es6-shim/es6-shim.js',
- '<%= genDir %>/vendor/npm/es6-promise/es6-promise.js',
+ '<%= genDir %>/vendor/npm/es6-promise/dist/es6-promise.js',
+ '<%= genDir %>/vendor/npm/systemjs/dist/system-polyfills.js',
'<%= genDir %>/vendor/npm/systemjs/dist/system.js',
'<%= genDir %>/app/system.conf.js',
'<%= genDir %>/app/boot.js',
diff --git a/vendor/phantomjs/render.js b/vendor/phantomjs/render.js
index 057d464a74c..95885a17886 100644
--- a/vendor/phantomjs/render.js
+++ b/vendor/phantomjs/render.js
@@ -1,55 +1,63 @@
-var page = require('webpage').create();
-var args = require('system').args;
-var params = {};
-var regexp = /^([^=]+)=([^$]+)/;
+(function() {
+ 'use strict';
-args.forEach(function(arg) {
- var parts = arg.match(regexp);
- if (!parts) { return; }
- params[parts[1]] = parts[2];
-});
+ var page = require('webpage').create();
+ var args = require('system').args;
+ var params = {};
+ var regexp = /^([^=]+)=([^$]+)/;
-var usage = "url= png= width= height= cookiename= sessionid= domain=";
+ args.forEach(function(arg) {
+ var parts = arg.match(regexp);
+ if (!parts) { return; }
+ params[parts[1]] = parts[2];
+ });
-if (!params.url || !params.png || !params.cookiename || ! params.sessionid || !params.domain) {
- console.log(usage);
- phantom.exit();
-}
+ var usage = "url= png= width= height= cookiename= sessionid= domain=";
-phantom.addCookie({
- 'name': params.cookiename,
- 'value': params.sessionid,
- 'domain': params.domain
-});
-
-page.viewportSize = {
- width: params.width || '800',
- height: params.height || '400'
-};
-
-var tries = 0;
-
-page.open(params.url, function (status) {
- console.log('Loading a web page: ' + params.url);
-
- function checkIsReady() {
- var canvas = page.evaluate(function() {
- var body = angular.element(document.body); // 1
- var rootScope = body.scope().$root;
- var panelsToLoad = angular.element('div.panel').length;
- return rootScope.performance.panelsRendered >= panelsToLoad;
- });
-
- if (canvas || tries === 1000) {
- page.render(params.png);
- phantom.exit();
- }
- else {
- tries++;
- setTimeout(checkIsReady, 10);
- }
+ if (!params.url || !params.png || !params.cookiename || ! params.sessionid || !params.domain) {
+ console.log(usage);
+ phantom.exit();
}
- setTimeout(checkIsReady, 200);
+ phantom.addCookie({
+ 'name': params.cookiename,
+ 'value': params.sessionid,
+ 'domain': params.domain
+ });
-});
+ page.viewportSize = {
+ width: params.width || '800',
+ height: params.height || '400'
+ };
+
+ var tries = 0;
+
+ page.open(params.url, function (status) {
+ console.log('Loading a web page: ' + params.url + ' status: ' + status);
+
+ function checkIsReady() {
+ var canvas = page.evaluate(function() {
+ if (!window.angular) { return false; }
+ var body = window.angular.element(document.body); // 1
+ if (!body.scope) { return false; }
+
+ var rootScope = body.scope();
+ if (!rootScope) {return false;}
+ if (!rootScope.performance) { return false; }
+ var panelsToLoad = window.angular.element('div.panel').length;
+ return rootScope.performance.panelsRendered >= panelsToLoad;
+ });
+
+ if (canvas || tries === 1000) {
+ page.render(params.png);
+ phantom.exit();
+ }
+ else {
+ tries++;
+ setTimeout(checkIsReady, 10);
+ }
+ }
+
+ setTimeout(checkIsReady, 200);
+ });
+})();