mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Resurrected nikita-graf's work and added playlistType for future use
This commit is contained in:
parent
3dc3d363fd
commit
bcaaedf2ff
@ -47,6 +47,9 @@ func Register(r *macaron.Macaron) {
|
||||
r.Get("/dashboard/*", reqSignedIn, Index)
|
||||
r.Get("/dashboard-solo/*", reqSignedIn, Index)
|
||||
|
||||
r.Get("/playlists/", reqSignedIn, Index)
|
||||
r.Get("/playlists/*", reqSignedIn, Index)
|
||||
|
||||
// sign up
|
||||
r.Get("/signup", Index)
|
||||
r.Get("/api/user/signup/options", wrap(GetSignUpOptions))
|
||||
@ -169,6 +172,16 @@ func Register(r *macaron.Macaron) {
|
||||
r.Get("/tags", GetDashboardTags)
|
||||
})
|
||||
|
||||
// Playlist
|
||||
r.Group("/playlists", func() {
|
||||
r.Get("/", SearchPlaylists)
|
||||
r.Get("/:id", ValidateOrgPlaylist, GetPlaylist)
|
||||
r.Get("/:id/dashboards", ValidateOrgPlaylist, GetPlaylistDashboards)
|
||||
r.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, DeletePlaylist)
|
||||
r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistQuery{}), ValidateOrgPlaylist, UpdatePlaylist)
|
||||
r.Post("/", reqEditorRole, bind(m.CreatePlaylistQuery{}), CreatePlaylist)
|
||||
})
|
||||
|
||||
// Search
|
||||
r.Get("/search/", Search)
|
||||
|
||||
|
@ -53,6 +53,12 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
|
||||
Href: "/",
|
||||
})
|
||||
|
||||
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
|
||||
Text: "Playlists",
|
||||
Icon: "fa fa-fw fa-list",
|
||||
Href: "/playlists",
|
||||
})
|
||||
|
||||
if c.OrgRole == m.ROLE_ADMIN {
|
||||
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
|
||||
Text: "Data Sources",
|
||||
|
103
pkg/api/playlist.go
Normal file
103
pkg/api/playlist.go
Normal file
@ -0,0 +1,103 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
func ValidateOrgPlaylist(c *middleware.Context) {
|
||||
id := c.ParamsInt64(":id")
|
||||
query := m.GetPlaylistByIdQuery{Id: id}
|
||||
err := bus.Dispatch(&query)
|
||||
|
||||
if err != nil {
|
||||
c.JsonApiErr(404, "Playlist not found", err)
|
||||
return
|
||||
}
|
||||
|
||||
if query.Result.OrgId != c.OrgId {
|
||||
c.JsonApiErr(403, "You are not allowed to edit/view playlist", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func SearchPlaylists(c *middleware.Context) {
|
||||
query := c.Query("query")
|
||||
limit := c.QueryInt("limit")
|
||||
|
||||
if limit == 0 {
|
||||
limit = 1000
|
||||
}
|
||||
|
||||
searchQuery := m.PlaylistQuery{
|
||||
Title: query,
|
||||
Limit: limit,
|
||||
OrgId: c.OrgId,
|
||||
}
|
||||
|
||||
err := bus.Dispatch(&searchQuery)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Search failed", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, searchQuery.Result)
|
||||
}
|
||||
|
||||
func GetPlaylist(c *middleware.Context) {
|
||||
id := c.ParamsInt64(":id")
|
||||
cmd := m.GetPlaylistByIdQuery{Id: id}
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
c.JsonApiErr(500, "Playlist not found", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, cmd.Result)
|
||||
}
|
||||
|
||||
func GetPlaylistDashboards(c *middleware.Context) {
|
||||
id := c.ParamsInt64(":id")
|
||||
|
||||
query := m.GetPlaylistDashboardsQuery{Id: id}
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
c.JsonApiErr(500, "Playlist not found", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, query.Result)
|
||||
}
|
||||
|
||||
func DeletePlaylist(c *middleware.Context) {
|
||||
id := c.ParamsInt64(":id")
|
||||
|
||||
cmd := m.DeletePlaylistQuery{Id: id}
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
c.JsonApiErr(500, "Failed to delete playlist", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, "")
|
||||
}
|
||||
|
||||
func CreatePlaylist(c *middleware.Context, query m.CreatePlaylistQuery) {
|
||||
query.OrgId = c.OrgId
|
||||
err := bus.Dispatch(&query)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to create playlist", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, query.Result)
|
||||
}
|
||||
|
||||
func UpdatePlaylist(c *middleware.Context, query m.UpdatePlaylistQuery) {
|
||||
err := bus.Dispatch(&query)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Failed to save playlist", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, query.Result)
|
||||
}
|
79
pkg/models/playlist.go
Normal file
79
pkg/models/playlist.go
Normal file
@ -0,0 +1,79 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Typed errors
|
||||
var (
|
||||
ErrPlaylistNotFound = errors.New("Playlist not found")
|
||||
ErrPlaylistWithSameNameExists = errors.New("A playlist with the same name already exists")
|
||||
)
|
||||
|
||||
// Playlist model
|
||||
type Playlist struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
Timespan string `json:"timespan"`
|
||||
Data []int `json:"data"`
|
||||
OrgId int64 `json:"-"`
|
||||
}
|
||||
|
||||
type PlaylistDashboard struct {
|
||||
Id int64 `json:"id"`
|
||||
Slug string `json:"slug"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
func (this PlaylistDashboard) TableName() string {
|
||||
return "dashboard"
|
||||
}
|
||||
|
||||
type Playlists []*Playlist
|
||||
type PlaylistDashboards []*PlaylistDashboard
|
||||
|
||||
//
|
||||
// COMMANDS
|
||||
//
|
||||
type PlaylistQuery struct {
|
||||
Title string
|
||||
Limit int
|
||||
OrgId int64
|
||||
|
||||
Result Playlists
|
||||
}
|
||||
|
||||
type UpdatePlaylistQuery struct {
|
||||
Id int64
|
||||
Title string
|
||||
Type string
|
||||
Timespan string
|
||||
Data []int
|
||||
|
||||
Result *Playlist
|
||||
}
|
||||
|
||||
type CreatePlaylistQuery struct {
|
||||
Title string
|
||||
Type string
|
||||
Timespan string
|
||||
Data []int
|
||||
OrgId int64
|
||||
|
||||
Result *Playlist
|
||||
}
|
||||
|
||||
type GetPlaylistByIdQuery struct {
|
||||
Id int64
|
||||
Result *Playlist
|
||||
}
|
||||
|
||||
type GetPlaylistDashboardsQuery struct {
|
||||
Id int64
|
||||
Result *PlaylistDashboards
|
||||
}
|
||||
|
||||
type DeletePlaylistQuery struct {
|
||||
Id int64
|
||||
}
|
@ -19,6 +19,7 @@ func AddMigrations(mg *Migrator) {
|
||||
addDashboardSnapshotMigrations(mg)
|
||||
addQuotaMigration(mg)
|
||||
addPluginBundleMigration(mg)
|
||||
addPlaylistMigrations(mg)
|
||||
}
|
||||
|
||||
func addMigrationLogMigrations(mg *Migrator) {
|
||||
|
20
pkg/services/sqlstore/migrations/playlist_mig.go
Normal file
20
pkg/services/sqlstore/migrations/playlist_mig.go
Normal file
@ -0,0 +1,20 @@
|
||||
package migrations
|
||||
|
||||
import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
|
||||
func addPlaylistMigrations(mg *Migrator) {
|
||||
playlistV1 := Table{
|
||||
Name: "playlist",
|
||||
Columns: []*Column{
|
||||
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "data", Type: DB_Text, Nullable: false},
|
||||
{Name: "timespan", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "org_id", Type: DB_BigInt, Nullable: false},
|
||||
},
|
||||
}
|
||||
|
||||
// create table
|
||||
mg.AddMigration("create playlist table v1", NewAddTableMigration(playlistV1))
|
||||
}
|
125
pkg/services/sqlstore/playlist.go
Normal file
125
pkg/services/sqlstore/playlist.go
Normal file
@ -0,0 +1,125 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
func init() {
|
||||
bus.AddHandler("sql", CreatePlaylist)
|
||||
bus.AddHandler("sql", UpdatePlaylist)
|
||||
bus.AddHandler("sql", DeletePlaylist)
|
||||
bus.AddHandler("sql", SearchPlaylists)
|
||||
bus.AddHandler("sql", GetPlaylist)
|
||||
bus.AddHandler("sql", GetPlaylistDashboards)
|
||||
}
|
||||
|
||||
func CreatePlaylist(query *m.CreatePlaylistQuery) error {
|
||||
var err error
|
||||
|
||||
playlist := m.Playlist{
|
||||
Title: query.Title,
|
||||
Type: query.Type,
|
||||
Data: query.Data,
|
||||
Timespan: query.Timespan,
|
||||
OrgId: query.OrgId,
|
||||
}
|
||||
|
||||
_, err = x.Insert(&playlist)
|
||||
|
||||
query.Result = &playlist
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdatePlaylist(query *m.UpdatePlaylistQuery) error {
|
||||
var err error
|
||||
x.Logger.SetLevel(5)
|
||||
playlist := m.Playlist{
|
||||
Id: query.Id,
|
||||
Title: query.Title,
|
||||
Type: query.Type,
|
||||
Data: query.Data,
|
||||
Timespan: query.Timespan,
|
||||
}
|
||||
|
||||
existingPlaylist := x.Where("id = ?", query.Id).Find(m.Playlist{})
|
||||
|
||||
if existingPlaylist == nil {
|
||||
return m.ErrPlaylistNotFound
|
||||
}
|
||||
|
||||
_, err = x.Id(query.Id).Cols("id", "title", "data", "timespan").Update(&playlist)
|
||||
|
||||
query.Result = &playlist
|
||||
return err
|
||||
}
|
||||
|
||||
func GetPlaylist(query *m.GetPlaylistByIdQuery) error {
|
||||
if query.Id == 0 {
|
||||
return m.ErrCommandValidationFailed
|
||||
}
|
||||
|
||||
playlist := m.Playlist{}
|
||||
_, err := x.Id(query.Id).Get(&playlist)
|
||||
query.Result = &playlist
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func DeletePlaylist(query *m.DeletePlaylistQuery) error {
|
||||
if query.Id == 0 {
|
||||
return m.ErrCommandValidationFailed
|
||||
}
|
||||
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
var rawSql = "DELETE FROM playlist WHERE id = ?"
|
||||
_, err := sess.Exec(rawSql, query.Id)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func SearchPlaylists(query *m.PlaylistQuery) error {
|
||||
var playlists = make(m.Playlists, 0)
|
||||
|
||||
sess := x.Limit(query.Limit)
|
||||
|
||||
if query.Title != "" {
|
||||
sess.Where("title LIKE ?", query.Title)
|
||||
}
|
||||
|
||||
sess.Where("org_id = ?", query.OrgId)
|
||||
err := sess.Find(&playlists)
|
||||
query.Result = playlists
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetPlaylistDashboards(query *m.GetPlaylistDashboardsQuery) error {
|
||||
if query.Id == 0 {
|
||||
return m.ErrCommandValidationFailed
|
||||
}
|
||||
|
||||
var dashboards = make(m.PlaylistDashboards, 0)
|
||||
var playlist = m.Playlist{}
|
||||
|
||||
hasPlaylist, err := x.Id(query.Id).Get(&playlist)
|
||||
query.Result = &dashboards
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hasPlaylist || len(playlist.Data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = x.In("id", playlist.Data).Find(&dashboards)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -4,6 +4,7 @@ define([
|
||||
'./annotations/annotationsSrv',
|
||||
'./templating/templateSrv',
|
||||
'./dashboard/all',
|
||||
'./playlist/all',
|
||||
'./panel/all',
|
||||
'./profile/profileCtrl',
|
||||
'./profile/changePasswordCtrl',
|
||||
|
5
public/app/features/playlist/all.js
Normal file
5
public/app/features/playlist/all.js
Normal file
@ -0,0 +1,5 @@
|
||||
define([
|
||||
'./playlistsCtrl',
|
||||
'./playlistEditCtrl',
|
||||
'./playlistRoutes'
|
||||
], function () {});
|
@ -0,0 +1,5 @@
|
||||
<p class="text-center">Are you sure want to delete "{{ playlist.title }}" playlist?</p>
|
||||
<p class="text-center">
|
||||
<button type="button" class="btn btn-danger" ng-click="removePlaylist()">Yes</button>
|
||||
<button type="button" class="btn btn-default" ng-click="dismiss()">No</button>
|
||||
</p>
|
115
public/app/features/playlist/partials/playlist.html
Normal file
115
public/app/features/playlist/partials/playlist.html
Normal file
@ -0,0 +1,115 @@
|
||||
<topnav icon="fa fa-fw fa-list" title="Playlists"></topnav>
|
||||
|
||||
<div class="page-container" ng-form="playlistEditForm">
|
||||
<div class="page">
|
||||
<div class="row" style="margin-bottom: 10px;">
|
||||
<div>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 100px">
|
||||
<strong>Title</strong>
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" required ng-model="playlist.title" class="input-xxlarge tight-form-input last">
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 100px">
|
||||
<strong>Timespan</strong>
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" required ng-model="playlist.timespan" class="input-xxlarge tight-form-input last">
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div style="display: inline-block">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
Search
|
||||
</li>
|
||||
<li>
|
||||
<input type="text"
|
||||
class="tight-form-input input-xlarge last"
|
||||
ng-model="searchQuery"
|
||||
placeholder="dashboard title"
|
||||
ng-trim="true"
|
||||
ng-change="search()">
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<h5>Playlist dashboards</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<table class="grafana-options-table">
|
||||
<tr ng-repeat="dashboard in filteredDashboards">
|
||||
<td style="white-space: nowrap;">
|
||||
{{dashboard.title}}
|
||||
</td>
|
||||
<td style="text-align: center">
|
||||
<button class="btn btn-inverse btn-mini pull-right" ng-click="addDashboard(dashboard)">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add to playlist
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="isSearchResultsEmpty() && !isSearchQueryEmpty()">
|
||||
<td colspan="2">
|
||||
<i class="fa fa-warning"></i> No dashboards found
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="isSearchQueryEmpty() && isPlaylistEmpty()">
|
||||
<td colspan="2">
|
||||
<i class="fa fa-warning"></i> Playlist empty
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<table class="grafana-options-table">
|
||||
<tr ng-repeat="dashboard in dashboards">
|
||||
<td style="white-space: nowrap;">
|
||||
{{dashboard.title}}
|
||||
</td>
|
||||
<td style="text-align: center">
|
||||
<button class="btn btn-inverse btn-mini pull-right" ng-click="removeDashboard(dashboard)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div class="pull-left">
|
||||
<div class="tight-form">
|
||||
<button type="button"
|
||||
class="btn btn-success"
|
||||
ng-disabled="playlistEditForm.$invalid || isPlaylistEmpty()"
|
||||
ng-click="savePlaylist(playlist, dashboards)">Save</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
ng-click="backToList()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
43
public/app/features/playlist/partials/playlists.html
Normal file
43
public/app/features/playlist/partials/playlists.html
Normal file
@ -0,0 +1,43 @@
|
||||
<topnav icon="fa fa-fw fa-list" title="Playlists"></topnav>
|
||||
|
||||
<div class="page-container">
|
||||
<div class="page">
|
||||
<button type="submit" class="btn btn-success" ng-click="createPlaylist()">Create playlist</button>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div ng-if="playlists.length === 0">
|
||||
<em>No saved playlists</em>
|
||||
</div>
|
||||
|
||||
<table class="grafana-options-table" ng-if="playlists.length > 0">
|
||||
<tr>
|
||||
<td><strong>Title</strong></td>
|
||||
<td><strong>Url</strong></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr ng-repeat="playlist in playlists">
|
||||
<td style="width:1%">
|
||||
{{playlist.title}}
|
||||
</td>
|
||||
<td style="width:90%">
|
||||
<a href="{{ playlistUrl(playlist) }}">{{ playlistUrl(playlist) }}</a>
|
||||
</td>
|
||||
<td style="width: 1%">
|
||||
<a href="playlists/edit/{{playlist.id}}" class="btn btn-inverse btn-mini">
|
||||
<i class="fa fa-edit"></i>
|
||||
Edit
|
||||
</a>
|
||||
</td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="removePlaylist(playlist)" class="btn btn-danger btn-mini">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
111
public/app/features/playlist/playlistEditCtrl.js
Normal file
111
public/app/features/playlist/playlistEditCtrl.js
Normal file
@ -0,0 +1,111 @@
|
||||
define([
|
||||
'angular',
|
||||
'app/core/config',
|
||||
'lodash'
|
||||
],
|
||||
function (angular, config, _) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('PlaylistEditCtrl', function(
|
||||
playlist,
|
||||
dashboards,
|
||||
$scope,
|
||||
playlistSrv,
|
||||
backendSrv,
|
||||
$location
|
||||
) {
|
||||
$scope.search = function() {
|
||||
var query = {starred: true, limit: 10};
|
||||
|
||||
if ($scope.searchQuery) {
|
||||
query.query = $scope.searchQuery;
|
||||
query.starred = false;
|
||||
}
|
||||
|
||||
$scope.loading = true;
|
||||
|
||||
backendSrv.search(query)
|
||||
.then(function(results) {
|
||||
$scope.foundDashboards = results;
|
||||
$scope.filterFoundDashboards();
|
||||
})
|
||||
.finally(function() {
|
||||
$scope.loading = false;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.filterFoundDashboards = function() {
|
||||
$scope.filteredDashboards = _.reject($scope.foundDashboards, function(dashboard) {
|
||||
return _.findWhere(dashboards, function(listDashboard) {
|
||||
return listDashboard.id === dashboard.id;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addDashboard = function(dashboard) {
|
||||
dashboards.push(dashboard);
|
||||
$scope.filterFoundDashboards();
|
||||
};
|
||||
|
||||
$scope.removeDashboard = function(dashboard) {
|
||||
_.remove(dashboards, function(listedDashboard) {
|
||||
return dashboard === listedDashboard;
|
||||
});
|
||||
$scope.filterFoundDashboards();
|
||||
};
|
||||
|
||||
$scope.savePlaylist = function(playlist, dashboards) {
|
||||
var savePromise;
|
||||
|
||||
playlist.data = dashboards.map(function(dashboard) {
|
||||
return dashboard.id;
|
||||
});
|
||||
|
||||
// Hardcoding playlist type for this iteration
|
||||
playlist.type = "dashboards";
|
||||
|
||||
savePromise = playlist.id
|
||||
? backendSrv.put('/api/playlists/' + playlist.id, playlist)
|
||||
: backendSrv.post('/api/playlists', playlist);
|
||||
|
||||
savePromise
|
||||
.then(function() {
|
||||
$scope.appEvent('alert-success', ['Playlist saved', '']);
|
||||
$location.path('/playlists');
|
||||
}, function() {
|
||||
$scope.appEvent('alert-success', ['Unable to save playlist', '']);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.isPlaylistEmpty = function() {
|
||||
return !dashboards.length;
|
||||
};
|
||||
|
||||
$scope.isSearchResultsEmpty = function() {
|
||||
return !$scope.foundDashboards.length;
|
||||
};
|
||||
|
||||
$scope.isSearchQueryEmpty = function() {
|
||||
return $scope.searchQuery === '';
|
||||
};
|
||||
|
||||
$scope.backToList = function() {
|
||||
$location.path('/playlists');
|
||||
};
|
||||
|
||||
$scope.isLoading = function() {
|
||||
return $scope.loading;
|
||||
};
|
||||
|
||||
$scope.playlist = playlist;
|
||||
$scope.dashboards = dashboards;
|
||||
$scope.timespan = config.playlist_timespan;
|
||||
$scope.filteredDashboards = [];
|
||||
$scope.foundDashboards = [];
|
||||
$scope.searchQuery = '';
|
||||
$scope.loading = false;
|
||||
$scope.search();
|
||||
});
|
||||
});
|
73
public/app/features/playlist/playlistRoutes.js
Normal file
73
public/app/features/playlist/playlistRoutes.js
Normal file
@ -0,0 +1,73 @@
|
||||
define([
|
||||
'angular',
|
||||
'app/core/config',
|
||||
'lodash'
|
||||
],
|
||||
function (angular, config, _) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.routes');
|
||||
|
||||
module.config(function($routeProvider) {
|
||||
$routeProvider
|
||||
.when('/playlists', {
|
||||
templateUrl: 'app/features/playlist/partials/playlists.html',
|
||||
controller : 'PlaylistsCtrl',
|
||||
resolve: {
|
||||
playlists: function (backendSrv) {
|
||||
return backendSrv.get('/api/playlists');
|
||||
}
|
||||
}
|
||||
})
|
||||
.when('/playlists/create', {
|
||||
templateUrl: 'app/features/playlist/partials/playlist.html',
|
||||
controller : 'PlaylistEditCtrl',
|
||||
resolve: {
|
||||
playlist: function() {
|
||||
return {
|
||||
timespan: '1m'
|
||||
};
|
||||
},
|
||||
dashboards: function() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
})
|
||||
.when('/playlists/edit/:id', {
|
||||
templateUrl: 'app/features/playlist/partials/playlist.html',
|
||||
controller : 'PlaylistEditCtrl',
|
||||
resolve: {
|
||||
playlist: function(backendSrv, $route) {
|
||||
var playlistId = $route.current.params.id;
|
||||
|
||||
return backendSrv.get('/api/playlists/' + playlistId);
|
||||
},
|
||||
dashboards: function(backendSrv, $route) {
|
||||
var playlistId = $route.current.params.id;
|
||||
|
||||
return backendSrv.get('/api/playlists/' + playlistId + '/dashboards');
|
||||
}
|
||||
}
|
||||
})
|
||||
.when('/playlists/play/:id', {
|
||||
templateUrl: 'app/partials/dashboard.html',
|
||||
controller : 'LoadDashboardCtrl',
|
||||
resolve: {
|
||||
init: function(backendSrv, playlistSrv, $route) {
|
||||
var playlistId = $route.current.params.id;
|
||||
|
||||
return backendSrv.get('/api/playlists/' + playlistId)
|
||||
.then(function(playlist) {
|
||||
return backendSrv.get('/api/playlists/' + playlistId + '/dashboards')
|
||||
.then(function(dashboards) {
|
||||
_.each(dashboards, function(dashboard) {
|
||||
dashboard.uri = 'db/' + dashboard.slug;
|
||||
});
|
||||
playlistSrv.start(dashboards, playlist.timespan);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
49
public/app/features/playlist/playlistsCtrl.js
Normal file
49
public/app/features/playlist/playlistsCtrl.js
Normal file
@ -0,0 +1,49 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash'
|
||||
],
|
||||
function (angular, _) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('PlaylistsCtrl', function(
|
||||
playlists,
|
||||
$scope,
|
||||
$location,
|
||||
backendSrv
|
||||
) {
|
||||
$scope.playlists = playlists;
|
||||
|
||||
$scope.playlistUrl = function(playlist) {
|
||||
return '/playlists/play/' + playlist.id;
|
||||
};
|
||||
|
||||
$scope.removePlaylist = function(playlist) {
|
||||
var modalScope = $scope.$new(true);
|
||||
|
||||
modalScope.playlist = playlist;
|
||||
modalScope.removePlaylist = function() {
|
||||
modalScope.dismiss();
|
||||
_.remove(playlists, {id: playlist.id});
|
||||
|
||||
backendSrv.delete('/api/playlists/' + playlist.id)
|
||||
.then(function() {
|
||||
$scope.appEvent('alert-success', ['Playlist deleted', '']);
|
||||
}, function() {
|
||||
$scope.appEvent('alert-error', ['Unable to delete playlist', '']);
|
||||
playlists.push(playlist);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.appEvent('show-modal', {
|
||||
src: './app/features/playlist/partials/playlist-remove.html',
|
||||
scope: modalScope
|
||||
});
|
||||
};
|
||||
|
||||
$scope.createPlaylist = function() {
|
||||
$location.path('/playlists/create');
|
||||
};
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user