mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Lots of work on search and dashboard loading, trying to generalize concepts and code, #960
This commit is contained in:
parent
a40299b4dc
commit
b3be51f17f
@ -100,6 +100,7 @@ func Register(r *macaron.Macaron) {
|
||||
r.Group("/dashboards", func() {
|
||||
r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
|
||||
r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), PostDashboard)
|
||||
r.Get("/file/:file", GetDashboardFromJsonFile)
|
||||
r.Get("/home", GetHomeDashboard)
|
||||
})
|
||||
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/metrics"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/search"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
@ -48,7 +49,7 @@ func GetDashboard(c *middleware.Context) {
|
||||
dash := query.Result
|
||||
dto := dtos.DashboardFullWithMeta{
|
||||
Dashboard: dash.Data,
|
||||
Meta: dtos.DashboardMeta{IsStarred: isStarred, Slug: slug},
|
||||
Meta: dtos.DashboardMeta{IsStarred: isStarred, Slug: slug, Type: m.DashTypeDB},
|
||||
}
|
||||
|
||||
c.JSON(200, dto)
|
||||
@ -118,3 +119,19 @@ func GetHomeDashboard(c *middleware.Context) {
|
||||
|
||||
c.JSON(200, &dash)
|
||||
}
|
||||
|
||||
func GetDashboardFromJsonFile(c *middleware.Context) {
|
||||
file := c.Params(":file")
|
||||
|
||||
dashboard := search.GetDashboardFromJsonIndex(file)
|
||||
if dashboard == nil {
|
||||
c.JsonApiErr(404, "Dashboard not found", nil)
|
||||
return
|
||||
}
|
||||
|
||||
dash := dtos.DashboardFullWithMeta{Dashboard: dashboard.Data}
|
||||
dash.Meta.Type = m.DashTypeJson
|
||||
dash.Meta.CanSave = false
|
||||
|
||||
c.JSON(200, &dash)
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ type DashboardMeta struct {
|
||||
IsStarred bool `json:"isStarred,omitempty"`
|
||||
IsHome bool `json:"isHome,omitempty"`
|
||||
IsSnapshot bool `json:"isSnapshot,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
CanSave bool `json:"canSave"`
|
||||
Slug string `json:"slug"`
|
||||
Expires time.Time `json:"expires"`
|
||||
Created time.Time `json:"created"`
|
||||
|
@ -15,6 +15,12 @@ var (
|
||||
ErrDashboardVersionMismatch = errors.New("The dashboard has been changed by someone else")
|
||||
)
|
||||
|
||||
var (
|
||||
DashTypeJson = "file"
|
||||
DashTypeDB = "db"
|
||||
DashTypeScript = "script"
|
||||
)
|
||||
|
||||
// Dashboard model
|
||||
type Dashboard struct {
|
||||
Id int64
|
||||
|
@ -9,7 +9,8 @@ type SearchResult struct {
|
||||
type DashboardSearchHit struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Slug string `json:"slug"`
|
||||
Uri string `json:"uri"`
|
||||
Type string `json:"type"`
|
||||
Tags []string `json:"tags"`
|
||||
IsStarred bool `json:"isStarred"`
|
||||
}
|
||||
|
@ -17,11 +17,10 @@ type JsonDashIndex struct {
|
||||
}
|
||||
|
||||
type JsonDashIndexItem struct {
|
||||
Title string
|
||||
TitleLower string
|
||||
Tags []string
|
||||
TagsCsv string
|
||||
FilePath string
|
||||
Path string
|
||||
Dashboard *m.Dashboard
|
||||
}
|
||||
|
||||
func NewJsonDashIndex(path string, orgIds string) *JsonDashIndex {
|
||||
@ -40,9 +39,9 @@ func (index *JsonDashIndex) Search(query *Query) ([]*m.DashboardSearchHit, error
|
||||
for _, item := range index.items {
|
||||
if strings.Contains(item.TitleLower, query.Title) {
|
||||
results = append(results, &m.DashboardSearchHit{
|
||||
Title: item.Title,
|
||||
Tags: item.Tags,
|
||||
Slug: item.FilePath,
|
||||
Title: item.Dashboard.Title,
|
||||
Tags: item.Dashboard.GetTags(),
|
||||
Uri: "file/" + item.Path,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -50,6 +49,16 @@ func (index *JsonDashIndex) Search(query *Query) ([]*m.DashboardSearchHit, error
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (index *JsonDashIndex) GetDashboard(path string) *m.Dashboard {
|
||||
for _, item := range index.items {
|
||||
if item.Path == path {
|
||||
return item.Dashboard
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (index *JsonDashIndex) updateIndex() error {
|
||||
log.Info("Updating JSON dashboard index, path: %v", index.path)
|
||||
|
||||
@ -102,13 +111,13 @@ func loadDashboardFromFile(filename string) (*JsonDashIndexItem, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dash := m.NewDashboardFromJson(data)
|
||||
stat, _ := os.Stat(filename)
|
||||
|
||||
item := &JsonDashIndexItem{}
|
||||
item.Title = dash.Title
|
||||
item.TitleLower = strings.ToLower(item.Title)
|
||||
item.Tags = dash.GetTags()
|
||||
item.TagsCsv = strings.Join(item.Tags, ",")
|
||||
item.Dashboard = m.NewDashboardFromJson(data)
|
||||
item.TitleLower = strings.ToLower(item.Dashboard.Title)
|
||||
item.TagsCsv = strings.Join(item.Dashboard.GetTags(), ",")
|
||||
item.Path = stat.Name()
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
@ -87,3 +87,10 @@ func setIsStarredFlagOnSearchResults(userId int64, hits []*m.DashboardSearchHit)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDashboardFromJsonIndex(filename string) *m.Dashboard {
|
||||
if jsonDashIndex == nil {
|
||||
return nil
|
||||
}
|
||||
return jsonDashIndex.GetDashboard(filename)
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ func SearchDashboards(query *m.SearchDashboardsQuery) error {
|
||||
hit = &m.DashboardSearchHit{
|
||||
Id: item.Id,
|
||||
Title: item.Title,
|
||||
Slug: item.Slug,
|
||||
Uri: "db/" + item.Slug,
|
||||
Tags: []string{},
|
||||
}
|
||||
query.Result = append(query.Result, hit)
|
||||
|
@ -70,7 +70,7 @@ function (angular, _, config) {
|
||||
$scope.resultCount = results.tagsOnly ? results.tags.length : results.dashboards.length;
|
||||
$scope.results.tags = results.tags;
|
||||
$scope.results.dashboards = _.map(results.dashboards, function(dash) {
|
||||
dash.url = 'dashboard/db/' + dash.slug;
|
||||
dash.url = 'dashboard/' + dash.uri;
|
||||
return dash;
|
||||
});
|
||||
|
||||
|
@ -22,6 +22,7 @@ function (angular, _, kbn, $) {
|
||||
};
|
||||
|
||||
this.setTimeRenderStart = function(scope) {
|
||||
scope.timing = scope.timing || {};
|
||||
scope.timing.renderStart = new Date().getTime();
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<grafana-panel>
|
||||
<div class="dashlist">
|
||||
<div class="dashlist-item" ng-repeat="dash in dashList">
|
||||
<a class="dashlist-link" href="dashboard/db/{{dash.slug}}">
|
||||
<a class="dashlist-link" href="dashboard/{{dash.uri}}">
|
||||
<span class="dashlist-title">
|
||||
{{dash.title}}
|
||||
</span>
|
||||
|
@ -12,22 +12,7 @@ define([
|
||||
$routeProvider
|
||||
.when('/', {
|
||||
templateUrl: 'app/partials/dashboard.html',
|
||||
controller : 'DashFromDBCtrl',
|
||||
reloadOnSearch: false,
|
||||
})
|
||||
.when('/dashboard/db/:slug', {
|
||||
templateUrl: 'app/partials/dashboard.html',
|
||||
controller : 'DashFromDBCtrl',
|
||||
reloadOnSearch: false,
|
||||
})
|
||||
.when('/dashboard/file/:jsonFile', {
|
||||
templateUrl: 'app/partials/dashboard.html',
|
||||
controller : 'DashFromFileCtrl',
|
||||
reloadOnSearch: false,
|
||||
})
|
||||
.when('/dashboard/script/:jsFile', {
|
||||
templateUrl: 'app/partials/dashboard.html',
|
||||
controller : 'DashFromScriptCtrl',
|
||||
controller : 'LoadDashboardCtrl',
|
||||
reloadOnSearch: false,
|
||||
})
|
||||
.when('/dashboard/import/:file', {
|
||||
@ -35,9 +20,10 @@ define([
|
||||
controller : 'DashFromImportCtrl',
|
||||
reloadOnSearch: false,
|
||||
})
|
||||
.when('/dashboard/snapshot/:key', {
|
||||
.when('/dashboard/:type/:slug', {
|
||||
templateUrl: 'app/partials/dashboard.html',
|
||||
controller : 'DashFromSnapshotCtrl',
|
||||
controller : 'LoadDashboardCtrl',
|
||||
reloadOnSearch: false,
|
||||
})
|
||||
.when('/dashboard/solo/db/:slug', {
|
||||
templateUrl: 'app/features/panel/partials/soloPanel.html',
|
||||
|
@ -10,12 +10,14 @@ function (angular, _, kbn, moment, $) {
|
||||
|
||||
var module = angular.module('grafana.routes');
|
||||
|
||||
module.controller('DashFromDBCtrl', function($scope, $routeParams, backendSrv) {
|
||||
module.controller('LoadDashboardCtrl', function(
|
||||
$scope, $routeParams, backendSrv, dashboardSrv, datasourceSrv, $http, $q, $timeout, contextSrv) {
|
||||
|
||||
function dashboardLoadFailed(title) {
|
||||
$scope.initDashboard({meta: {}, dashboard: {title: title}}, $scope);
|
||||
}
|
||||
|
||||
// Home dashboard
|
||||
if (!$routeParams.slug) {
|
||||
backendSrv.get('/api/dashboards/home').then(function(result) {
|
||||
var meta = result.meta;
|
||||
@ -24,90 +26,10 @@ function (angular, _, kbn, moment, $) {
|
||||
},function() {
|
||||
dashboardLoadFailed('Not found');
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return backendSrv.getDashboard($routeParams.slug).then(function(result) {
|
||||
$scope.initDashboard(result, $scope);
|
||||
}, function() {
|
||||
dashboardLoadFailed('Not found');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
module.controller('DashFromSnapshotCtrl', function($scope, $routeParams, backendSrv, contextSrv) {
|
||||
//don't show the sidemenu in snapshots.
|
||||
contextSrv.sidemenu = false;
|
||||
backendSrv.get('/api/snapshots/' + $routeParams.key).then(function(result) {
|
||||
$scope.initDashboard(result, $scope);
|
||||
}, function() {
|
||||
$scope.initDashboard({
|
||||
meta: {
|
||||
isSnapshot: true,
|
||||
canSave: false,
|
||||
canEdit: false,
|
||||
},
|
||||
dashboard: {
|
||||
title: 'Snapshot not found'
|
||||
}
|
||||
}, $scope);
|
||||
});
|
||||
});
|
||||
|
||||
module.controller('DashFromImportCtrl', function($scope, $location, alertSrv) {
|
||||
if (!window.grafanaImportDashboard) {
|
||||
alertSrv.set('Not found', 'Cannot reload page with unsaved imported dashboard', 'warning', 7000);
|
||||
$location.path('');
|
||||
return;
|
||||
}
|
||||
$scope.initDashboard({
|
||||
meta: { canShare: false, canStar: false },
|
||||
dashboard: window.grafanaImportDashboard
|
||||
}, $scope);
|
||||
});
|
||||
|
||||
module.controller('NewDashboardCtrl', function($scope) {
|
||||
$scope.initDashboard({
|
||||
meta: { canStar: false, canShare: false },
|
||||
dashboard: {
|
||||
title: "New dashboard",
|
||||
rows: [{ height: '250px', panels:[] }]
|
||||
},
|
||||
}, $scope);
|
||||
});
|
||||
|
||||
module.controller('DashFromFileCtrl', function($scope, $rootScope, $http, $routeParams) {
|
||||
|
||||
var file_load = function(file) {
|
||||
return $http({
|
||||
url: "public/dashboards/"+file.replace(/\.(?!json)/,"/")+'?' + new Date().getTime(),
|
||||
method: "GET",
|
||||
transformResponse: function(response) {
|
||||
return angular.fromJson(response);
|
||||
}
|
||||
}).then(function(result) {
|
||||
if(!result) {
|
||||
return false;
|
||||
}
|
||||
return result.data;
|
||||
},function() {
|
||||
$scope.appEvent('alert-error', ["Dashboard load failed", "Could not load "+file+". Please make sure it exists"]);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
file_load($routeParams.jsonFile).then(function(result) {
|
||||
$scope.initDashboard({
|
||||
meta: { canSave: false, canDelete: false },
|
||||
dashboard: result
|
||||
}, $scope);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
module.controller('DashFromScriptCtrl', function($scope, $rootScope, $http, $routeParams, $q, dashboardSrv, datasourceSrv, $timeout) {
|
||||
|
||||
// Scripted dashboards
|
||||
var execute_script = function(result) {
|
||||
var services = {
|
||||
dashboardSrv: dashboardSrv,
|
||||
@ -145,13 +67,58 @@ function (angular, _, kbn, moment, $) {
|
||||
});
|
||||
};
|
||||
|
||||
script_load($routeParams.jsFile).then(function(result) {
|
||||
$scope.initDashboard({
|
||||
meta: {fromScript: true, canDelete: false, canSave: false},
|
||||
dashboard: result.data
|
||||
}, $scope);
|
||||
function loadScriptedDashboard() {
|
||||
script_load($routeParams.slug).then(function(result) {
|
||||
$scope.initDashboard({
|
||||
meta: {fromScript: true, canDelete: false, canSave: false},
|
||||
dashboard: result.data
|
||||
}, $scope);
|
||||
});
|
||||
}
|
||||
|
||||
if ($routeParams.type === 'script') {
|
||||
loadScriptedDashboard();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($routeParams.type === 'snapshot') {
|
||||
contextSrv.sidemenu = false;
|
||||
backendSrv.get('/api/snapshots/' + $routeParams.slug).then(function(result) {
|
||||
$scope.initDashboard(result, $scope);
|
||||
}, function() {
|
||||
$scope.initDashboard({meta:{isSnapshot: true, canSave: false, canEdit: false}, dashboard: {title: 'Snapshot not found'}}, $scope);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return backendSrv.getDashboard($routeParams.type, $routeParams.slug).then(function(result) {
|
||||
$scope.initDashboard(result, $scope);
|
||||
}, function() {
|
||||
dashboardLoadFailed('Not found');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
module.controller('DashFromImportCtrl', function($scope, $location, alertSrv) {
|
||||
if (!window.grafanaImportDashboard) {
|
||||
alertSrv.set('Not found', 'Cannot reload page with unsaved imported dashboard', 'warning', 7000);
|
||||
$location.path('');
|
||||
return;
|
||||
}
|
||||
$scope.initDashboard({
|
||||
meta: { canShare: false, canStar: false },
|
||||
dashboard: window.grafanaImportDashboard
|
||||
}, $scope);
|
||||
});
|
||||
|
||||
module.controller('NewDashboardCtrl', function($scope) {
|
||||
$scope.initDashboard({
|
||||
meta: { canStar: false, canShare: false },
|
||||
dashboard: {
|
||||
title: "New dashboard",
|
||||
rows: [{ height: '250px', panels:[] }]
|
||||
},
|
||||
}, $scope);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -119,8 +119,8 @@ function (angular, _, config) {
|
||||
return this.get('/api/search', query);
|
||||
};
|
||||
|
||||
this.getDashboard = function(slug) {
|
||||
return this.get('/api/dashboards/db/' + slug);
|
||||
this.getDashboard = function(type, slug) {
|
||||
return this.get('/api/dashboards/' + type + '/' + slug);
|
||||
};
|
||||
|
||||
this.saveDashboard = function(dash, options) {
|
||||
|
@ -1,53 +0,0 @@
|
||||
{
|
||||
"title": "New Dashboard",
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"rows": [
|
||||
{
|
||||
"title": "Row1",
|
||||
"height": "250px",
|
||||
"editable": true,
|
||||
"collapse": false,
|
||||
"panels": []
|
||||
}
|
||||
],
|
||||
"editable": true,
|
||||
"style": "dark",
|
||||
"nav": [
|
||||
{
|
||||
"type": "timepicker",
|
||||
"enable": true,
|
||||
"status": "Stable",
|
||||
"time_options": [
|
||||
"5m",
|
||||
"15m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"24h",
|
||||
"2d",
|
||||
"7d",
|
||||
"30d"
|
||||
],
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"now": true
|
||||
}
|
||||
],
|
||||
"refresh": false
|
||||
}
|
Loading…
Reference in New Issue
Block a user