Commit d9dca72e by Torkel Ödegaard

dashboard_folders: refactoring picker and folder selection in dashboard settings & save as menu

parent 5b35a21d
......@@ -40,8 +40,8 @@ func GetDashboard(c *middleware.Context) Response {
slug := strings.ToLower(c.Params(":slug"))
query := m.GetDashboardQuery{Slug: slug, OrgId: c.OrgId}
err := bus.Dispatch(&query)
if err != nil {
if err := bus.Dispatch(&query); err != nil {
return ApiError(404, "Dashboard not found", err)
}
......@@ -70,27 +70,39 @@ func GetDashboard(c *middleware.Context) Response {
creator = getUserLogin(dash.CreatedBy)
}
meta := dtos.DashboardMeta{
IsStarred: isStarred,
Slug: slug,
Type: m.DashTypeDB,
CanStar: c.IsSignedIn,
CanSave: canSave,
CanEdit: canEdit,
Created: dash.Created,
Updated: dash.Updated,
UpdatedBy: updater,
CreatedBy: creator,
Version: dash.Version,
HasAcl: dash.HasAcl,
IsFolder: dash.IsFolder,
FolderId: dash.ParentId,
FolderTitle: "Root",
}
// lookup folder title
if dash.ParentId > 0 {
query := m.GetDashboardQuery{Id: dash.ParentId, OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Dashboard folder could not be read", err)
}
meta.FolderTitle = query.Result.Title
}
// make sure db version is in sync with json model version
dash.Data.Set("version", dash.Version)
dto := dtos.DashboardFullWithMeta{
Dashboard: dash.Data,
Meta: dtos.DashboardMeta{
IsStarred: isStarred,
Slug: slug,
Type: m.DashTypeDB,
CanStar: c.IsSignedIn,
CanSave: canSave,
CanEdit: canEdit,
Created: dash.Created,
Updated: dash.Updated,
UpdatedBy: updater,
CreatedBy: creator,
Version: dash.Version,
HasAcl: dash.HasAcl,
IsFolder: dash.IsFolder,
ParentId: dash.ParentId,
},
Meta: meta,
}
c.TimeRequest(metrics.M_Api_Dashboard_Get)
......
......@@ -7,23 +7,24 @@ import (
)
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"`
CanEdit bool `json:"canEdit"`
CanStar bool `json:"canStar"`
Slug string `json:"slug"`
Expires time.Time `json:"expires"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
UpdatedBy string `json:"updatedBy"`
CreatedBy string `json:"createdBy"`
Version int `json:"version"`
HasAcl bool `json:"hasAcl"`
IsFolder bool `json:"isFolder"`
ParentId int64 `json:"parentId"`
IsStarred bool `json:"isStarred,omitempty"`
IsHome bool `json:"isHome,omitempty"`
IsSnapshot bool `json:"isSnapshot,omitempty"`
Type string `json:"type,omitempty"`
CanSave bool `json:"canSave"`
CanEdit bool `json:"canEdit"`
CanStar bool `json:"canStar"`
Slug string `json:"slug"`
Expires time.Time `json:"expires"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
UpdatedBy string `json:"updatedBy"`
CreatedBy string `json:"createdBy"`
Version int `json:"version"`
HasAcl bool `json:"hasAcl"`
IsFolder bool `json:"isFolder"`
FolderId int64 `json:"folderId"`
FolderTitle string `json:"folderTitle"`
}
type DashboardFullWithMeta struct {
......
......@@ -197,7 +197,7 @@ export class NavModelSrv {
clickHandler: () => dashNavCtrl.showHelpModal()
});
if (this.contextSrv.isEditor) {
if (this.contextSrv.isEditor && !dashboard.meta.isFolder) {
menu.push({
title: 'Save As ...',
icon: 'fa fa-fw fa-save',
......
......@@ -128,8 +128,10 @@ export class DashboardCtrl {
$rootScope.$broadcast("refresh");
};
$scope.onFolderChange = function(parentId) {
$scope.dashboard.parentId = parentId;
$scope.onFolderChange = function(folder) {
$scope.dashboard.parentId = folder.id;
$scope.dashboard.meta.folderId = folder.id;
$scope.dashboard.meta.folderTitle= folder.title;
};
}
......
......@@ -113,17 +113,8 @@ export class DashboardSrv {
}
showSaveAsModal() {
var newScope = this.$rootScope.$new();
newScope.clone = this.dash.getSaveModelClone();
newScope.clone.editable = true;
newScope.clone.hideControls = false;
newScope.clone.meta = {};
newScope.clone.meta.parentId = this.dash.meta.parentId;
newScope.clone.meta.isFolder = this.dash.meta.isFolder;
this.$rootScope.appEvent('show-modal', {
templateHtml: '<save-dashboard-as-modal dismiss="dismiss()"></save-dashboard-as-modal>',
scope: newScope,
modalClass: 'modal--narrow'
});
}
......@@ -131,7 +122,6 @@ export class DashboardSrv {
showSaveModal() {
this.$rootScope.appEvent('show-modal', {
templateHtml: '<save-dashboard-modal dismiss="dismiss()"></save-dashboard-modal>',
scope: this.$rootScope.$new(),
modalClass: 'modal--narrow'
});
}
......
<div class="gf-form">
<label class="gf-form-label width-7">Folder</label>
<div class="dropdown">
<metric-segment segment="ctrl.selectedFolderSegment"
get-options="ctrl.getOptions()"
on-change="ctrl.folderChanged()"></metric-segment>
</div>
</div>
......@@ -6,47 +6,38 @@ import _ from 'lodash';
export class FolderPickerCtrl {
folders: Folder[];
selectedFolder: number;
selectedFolderSegment: any;
selectedOption: any;
initialTitle: string;
onChange: any;
rootFolderName: string;
labelClass: string;
/** @ngInject */
constructor(private backendSrv, private $scope, private $sce, private uiSegmentSrv) {
this.selectedFolderSegment = this.uiSegmentSrv.newSegment({value: this.rootFolderName || 'Root', selectMode: true});
this.get();
constructor(private backendSrv, private $scope, private $sce) {
if (!this.labelClass) {
this.labelClass = "width-7";
}
this.selectedOption = {text: this.initialTitle, value: null};
}
get() {
getOptions(query) {
var params = {
query: query,
type: 'dash-folder',
};
return this.backendSrv.search(params).then(result => {
this.folders = [{id: 0, title: this.rootFolderName || 'Root', type: 'dash-folder'}];
this.folders.push(...result);
if (this.selectedFolder) {
const selected = _.find(this.folders, {id: this.selectedFolder});
this.selectedFolderSegment.value = selected.title;
this.selectedFolderSegment.text = selected.title;
this.selectedFolderSegment.html = this.$sce.trustAsHtml(selected.title);
if (query === "") {
result.unshift({title: "Root", value: 0});
}
return _.map(result, item => {
return {text: item.title, value: item.id};
});
});
}
getOptions() {
return Promise.resolve(this.folders.map(folder => {
return this.uiSegmentSrv.newSegment(folder.title);
}));
}
folderChanged() {
const selected = _.find(this.folders, {title: this.selectedFolderSegment.value});
if (selected) {
this.onChange({$folderId: selected.id});
}
folderChanged(option) {
this.onChange({$folder: {id: option.value, title: option.text}});
}
}
......@@ -61,17 +52,29 @@ export interface Folder {
dashboards?: any;
}
const template = `
<div class="gf-form">
<label class="gf-form-label {{ctrl.labelClass}}">Folder</label>
<div class="dropdown">
<gf-form-dropdown model="ctrl.selectedOption"
get-options="ctrl.getOptions($query)"
on-change="ctrl.folderChanged($option)">
</gf-form-dropdown>
</div>
</div>
`;
export function folderPicker() {
return {
restrict: 'E',
templateUrl: 'public/app/features/dashboard/folder_picker/picker.html',
template: template,
controller: FolderPickerCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {
selectedFolder: "<",
initialTitle: "<",
onChange: "&",
rootFolderName: "@"
labelClass: "@",
}
};
}
......
......@@ -45,7 +45,11 @@
</div>
</div>
<folder-picker ng-if="!dashboardMeta.isFolder" selected-folder="dashboardMeta.parentId" on-change="onFolderChange($folderId)"></folder-picker>
<folder-picker ng-if="!dashboardMeta.isFolder"
initial-title="dashboardMeta.folderTitle"
on-change="onFolderChange($folder)"
label-class="width-7">
</folder-picker>
</div>
<div class="section">
......
......@@ -18,11 +18,13 @@ const template = `
<form name="ctrl.saveForm" ng-submit="ctrl.save()" class="modal-content" novalidate>
<div class="p-t-2">
<div class="gf-form">
<label class="gf-form-label">New name</label>
<label class="gf-form-label width-7">New name</label>
<input type="text" class="gf-form-input" ng-model="ctrl.clone.title" give-focus="true" required>
</div>
<div class="gf-form">
<folder-picker ng-if="!ctrl.clone.meta.isFolder" selected-folder="ctrl.clone.meta.parentId" on-change="ctrl.onFolderChange($folderId)">
<folder-picker initial-title="ctrl.folderTitle"
on-change="ctrl.onFolderChange($folder)"
label-class="width-7">
</folder-picker>
</div>
</div>
......@@ -37,6 +39,7 @@ const template = `
export class SaveDashboardAsModalCtrl {
clone: any;
folderTitle: any;
dismiss: () => void;
/** @ngInject */
......@@ -47,6 +50,7 @@ export class SaveDashboardAsModalCtrl {
this.clone.title += ' Copy';
this.clone.editable = true;
this.clone.hideControls = false;
this.folderTitle = dashboard.meta.folderTitle || 'Root';
// remove alerts
this.clone.rows.forEach(row => {
......@@ -68,8 +72,8 @@ export class SaveDashboardAsModalCtrl {
}
}
onFolderChange(parentId) {
this.clone.parentId = parentId;
onFolderChange(folder) {
this.clone.parentId = folder.id;
}
}
......
......@@ -23,8 +23,10 @@
</div>
<div class="gf-form">
<span class="gf-form-label width-6">Folder</span>
<folder-picker selected-folder="ctrl.panel.folderId" on-change="ctrl.onFolderChange" root-folder-name="All"></folder-picker>
<folder-picker initial-text="ctrl.folderTitle"
on-change="ctrl.onFolderChange($folder)"
label-class="width-6">
</folder-picker>
</div>
<div class="gf-form">
......
......@@ -10,6 +10,7 @@ class DashListCtrl extends PanelCtrl {
groups: any[];
modes: any[];
folderTitle: any;
panelDefaults = {
query: '',
......@@ -19,7 +20,7 @@ class DashListCtrl extends PanelCtrl {
search: false,
starred: true,
headings: true,
folderId: 0
folderId: 0,
};
/** @ngInject */
......@@ -65,6 +66,10 @@ class DashListCtrl extends PanelCtrl {
this.editorTabIndex = 1;
this.modes = ['starred', 'search', 'recently viewed'];
this.addEditorTab('Options', 'public/app/plugins/panel/dashlist/editor.html');
if (!this.panel.folderId) {
this.folderTitle = "All";
}
}
onRefresh() {
......@@ -126,9 +131,10 @@ class DashListCtrl extends PanelCtrl {
});
}
onFolderChange(parentId) {
this.$scope.$parent.ctrl.panel.folderId = parentId;
this.$scope.$parent.ctrl.refresh();
onFolderChange(folder) {
this.panel.folderId = folder.id;
this.panel.folderTitle = folder.title;
this.refresh();
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment