mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'develop' of github.com:grafana/grafana into develop
This commit is contained in:
commit
9007e26106
@ -64,6 +64,7 @@ func (hs *HttpServer) registerRoutes() {
|
|||||||
r.Get("/dashboard-solo/snapshot/*", Index)
|
r.Get("/dashboard-solo/snapshot/*", Index)
|
||||||
r.Get("/dashboard-solo/*", reqSignedIn, Index)
|
r.Get("/dashboard-solo/*", reqSignedIn, Index)
|
||||||
r.Get("/import/dashboard", reqSignedIn, Index)
|
r.Get("/import/dashboard", reqSignedIn, Index)
|
||||||
|
r.Get("/dashboards/", reqSignedIn, Index)
|
||||||
r.Get("/dashboards/*", reqSignedIn, Index)
|
r.Get("/dashboards/*", reqSignedIn, Index)
|
||||||
|
|
||||||
r.Get("/playlists/", reqSignedIn, Index)
|
r.Get("/playlists/", reqSignedIn, Index)
|
||||||
|
@ -58,10 +58,13 @@ export class ManageDashboardsCtrl {
|
|||||||
dashboard.checked = false;
|
dashboard.checked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.folderId && this.sections.length > 0) {
|
||||||
|
this.sections[0].hideHeader = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectionChanged() {
|
selectionChanged() {
|
||||||
|
|
||||||
let selectedDashboards = 0;
|
let selectedDashboards = 0;
|
||||||
|
|
||||||
for (let section of this.sections) {
|
for (let section of this.sections) {
|
||||||
@ -69,7 +72,7 @@ export class ManageDashboardsCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectedFolders = _.filter(this.sections, { checked: true }).length;
|
const selectedFolders = _.filter(this.sections, { checked: true }).length;
|
||||||
this.canMove = selectedDashboards > 0 && selectedFolders === 0;
|
this.canMove = selectedDashboards > 0;
|
||||||
this.canDelete = selectedDashboards > 0 || selectedFolders > 0;
|
this.canDelete = selectedDashboards > 0 || selectedFolders > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,11 +80,11 @@ export class ManageDashboardsCtrl {
|
|||||||
let selectedDashboards = [];
|
let selectedDashboards = [];
|
||||||
|
|
||||||
for (const section of this.sections) {
|
for (const section of this.sections) {
|
||||||
if (section.checked) {
|
if (section.checked && section.id !== 0) {
|
||||||
selectedDashboards.push(section.uri);
|
selectedDashboards.push(section.slug);
|
||||||
} else {
|
} else {
|
||||||
const selected = _.filter(section.items, { checked: true });
|
const selected = _.filter(section.items, { checked: true });
|
||||||
selectedDashboards.push(..._.map(selected, 'uri'));
|
selectedDashboards.push(..._.map(selected, 'slug'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +112,7 @@ export class ManageDashboardsCtrl {
|
|||||||
onConfirm: () => {
|
onConfirm: () => {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (let dash of selectedDashboards) {
|
for (let dash of selectedDashboards) {
|
||||||
promises.push(this.backendSrv.delete(`/api/dashboards/${dash}`));
|
promises.push(this.backendSrv.delete(`/api/dashboards/db/${dash}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$q.all(promises).then(() => {
|
this.$q.all(promises).then(() => {
|
||||||
@ -124,7 +127,7 @@ export class ManageDashboardsCtrl {
|
|||||||
|
|
||||||
for (const section of this.sections) {
|
for (const section of this.sections) {
|
||||||
const selected = _.filter(section.items, { checked: true });
|
const selected = _.filter(section.items, { checked: true });
|
||||||
selectedDashboards.push(..._.map(selected, 'uri'));
|
selectedDashboards.push(..._.map(selected, 'slug'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectedDashboards;
|
return selectedDashboards;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import coreModule from '../../core_module';
|
import coreModule from '../../core_module';
|
||||||
|
|
||||||
export class SearchResultsCtrl {
|
export class SearchResultsCtrl {
|
||||||
@ -6,10 +6,10 @@ export class SearchResultsCtrl {
|
|||||||
onSelectionChanged: any;
|
onSelectionChanged: any;
|
||||||
onTagSelected: any;
|
onTagSelected: any;
|
||||||
onFolderExpanding: any;
|
onFolderExpanding: any;
|
||||||
|
editable: boolean;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private $location) {
|
constructor(private $location) {}
|
||||||
}
|
|
||||||
|
|
||||||
toggleFolderExpand(section) {
|
toggleFolderExpand(section) {
|
||||||
if (section.toggle) {
|
if (section.toggle) {
|
||||||
@ -17,12 +17,24 @@ export class SearchResultsCtrl {
|
|||||||
this.onFolderExpanding();
|
this.onFolderExpanding();
|
||||||
}
|
}
|
||||||
|
|
||||||
section.toggle(section);
|
section.toggle(section).then(f => {
|
||||||
|
if (this.editable && f.expanded) {
|
||||||
|
if (f.items) {
|
||||||
|
_.each(f.items, i => {
|
||||||
|
i.checked = f.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.onSelectionChanged) {
|
||||||
|
this.onSelectionChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToFolder(section, evt) {
|
navigateToFolder(section, evt) {
|
||||||
this.$location.path('/dashboards/folder/' + section.id + '/' + section.uri);
|
this.$location.path(section.url);
|
||||||
|
|
||||||
if (evt) {
|
if (evt) {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
@ -33,6 +45,12 @@ export class SearchResultsCtrl {
|
|||||||
toggleSelection(item, evt) {
|
toggleSelection(item, evt) {
|
||||||
item.checked = !item.checked;
|
item.checked = !item.checked;
|
||||||
|
|
||||||
|
if (item.items) {
|
||||||
|
_.each(item.items, i => {
|
||||||
|
i.checked = item.checked;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.onSelectionChanged) {
|
if (this.onSelectionChanged) {
|
||||||
this.onSelectionChanged();
|
this.onSelectionChanged();
|
||||||
}
|
}
|
||||||
|
@ -51,18 +51,19 @@ export class SearchSrv {
|
|||||||
store.set('search.sections.recent', this.recentIsOpen);
|
store.set('search.sections.recent', this.recentIsOpen);
|
||||||
|
|
||||||
if (!section.expanded || section.items.length) {
|
if (!section.expanded || section.items.length) {
|
||||||
return Promise.resolve();
|
return Promise.resolve(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.queryForRecentDashboards().then(result => {
|
return this.queryForRecentDashboards().then(result => {
|
||||||
section.items = result;
|
section.items = result;
|
||||||
|
return Promise.resolve(section);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private toggleStarred(section) {
|
private toggleStarred(section) {
|
||||||
this.starredIsOpen = section.expanded = !section.expanded;
|
this.starredIsOpen = section.expanded = !section.expanded;
|
||||||
store.set('search.sections.starred', this.starredIsOpen);
|
store.set('search.sections.starred', this.starredIsOpen);
|
||||||
return Promise.resolve();
|
return Promise.resolve(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getStarred(sections) {
|
private getStarred(sections) {
|
||||||
@ -134,6 +135,7 @@ export class SearchSrv {
|
|||||||
items: [],
|
items: [],
|
||||||
toggle: this.toggleFolder.bind(this),
|
toggle: this.toggleFolder.bind(this),
|
||||||
url: `dashboards/folder/${hit.id}/${hit.slug}`,
|
url: `dashboards/folder/${hit.id}/${hit.slug}`,
|
||||||
|
slug: hit.slug,
|
||||||
icon: 'fa fa-folder',
|
icon: 'fa fa-folder',
|
||||||
score: _.keys(sections).length,
|
score: _.keys(sections).length,
|
||||||
};
|
};
|
||||||
@ -152,6 +154,7 @@ export class SearchSrv {
|
|||||||
id: hit.folderId,
|
id: hit.folderId,
|
||||||
title: hit.folderTitle,
|
title: hit.folderTitle,
|
||||||
url: `dashboards/folder/${hit.folderId}/${hit.folderSlug}`,
|
url: `dashboards/folder/${hit.folderId}/${hit.folderSlug}`,
|
||||||
|
slug: hit.slug,
|
||||||
items: [],
|
items: [],
|
||||||
icon: 'fa fa-folder-open',
|
icon: 'fa fa-folder-open',
|
||||||
toggle: this.toggleFolder.bind(this),
|
toggle: this.toggleFolder.bind(this),
|
||||||
@ -181,7 +184,7 @@ export class SearchSrv {
|
|||||||
section.icon = section.expanded ? 'fa fa-folder-open' : 'fa fa-folder';
|
section.icon = section.expanded ? 'fa fa-folder-open' : 'fa fa-folder';
|
||||||
|
|
||||||
if (section.items.length) {
|
if (section.items.length) {
|
||||||
return Promise.resolve();
|
return Promise.resolve(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
let query = {
|
let query = {
|
||||||
@ -190,6 +193,7 @@ export class SearchSrv {
|
|||||||
|
|
||||||
return this.backendSrv.search(query).then(results => {
|
return this.backendSrv.search(query).then(results => {
|
||||||
section.items = _.map(results, this.transformToViewModel);
|
section.items = _.map(results, this.transformToViewModel);
|
||||||
|
return Promise.resolve(section);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,41 @@ describe('ManageDashboards', () => {
|
|||||||
expect(ctrl.sections[0].items[0].checked).toEqual(false);
|
expect(ctrl.sections[0].items[0].checked).toEqual(false);
|
||||||
expect(ctrl.sections[1].checked).toEqual(false);
|
expect(ctrl.sections[1].checked).toEqual(false);
|
||||||
expect(ctrl.sections[1].items[0].checked).toEqual(false);
|
expect(ctrl.sections[1].items[0].checked).toEqual(false);
|
||||||
|
expect(ctrl.sections[0].hideHeader).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when browsing dashboards for a folder', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const response = [
|
||||||
|
{
|
||||||
|
id: 410,
|
||||||
|
title: "afolder",
|
||||||
|
type: "dash-folder",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 399,
|
||||||
|
title: "Dashboard Test",
|
||||||
|
url: "dashboard/db/dashboard-test",
|
||||||
|
icon: 'fa fa-folder',
|
||||||
|
tags: [],
|
||||||
|
isStarred: false,
|
||||||
|
folderId: 410,
|
||||||
|
folderTitle: "afolder",
|
||||||
|
folderSlug: "afolder"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
tags: [],
|
||||||
|
isStarred: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ctrl = createCtrlWithStubs(response);
|
||||||
|
ctrl.folderId = 410;
|
||||||
|
return ctrl.getDashboards();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set hide header to true on section', () => {
|
||||||
|
expect(ctrl.sections[0].hideHeader).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -263,8 +298,8 @@ describe('ManageDashboards', () => {
|
|||||||
expect(ctrl.sections[1].items[0].checked).toBeTruthy();
|
expect(ctrl.sections[1].items[0].checked).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disable Move To button', () => {
|
it('should enable Move To button', () => {
|
||||||
expect(ctrl.canMove).toBeFalsy();
|
expect(ctrl.canMove).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should enable delete button', () => {
|
it('should enable delete button', () => {
|
||||||
@ -294,8 +329,8 @@ describe('ManageDashboards', () => {
|
|||||||
ctrl.selectionChanged();
|
ctrl.selectionChanged();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disable Move To button', () => {
|
it('should enable Move To button', () => {
|
||||||
expect(ctrl.canMove).toBeFalsy();
|
expect(ctrl.canMove).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should enable delete button', () => {
|
it('should enable delete button', () => {
|
||||||
@ -455,8 +490,8 @@ describe('ManageDashboards', () => {
|
|||||||
ctrl.selectionChanged();
|
ctrl.selectionChanged();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disable Move To button', () => {
|
it('should enable Move To button', () => {
|
||||||
expect(ctrl.canMove).toBeFalsy();
|
expect(ctrl.canMove).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should enable delete button', () => {
|
it('should enable delete button', () => {
|
||||||
@ -466,6 +501,8 @@ describe('ManageDashboards', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('when deleting dashboards', () => {
|
describe('when deleting dashboards', () => {
|
||||||
|
let toBeDeleted = [];
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ctrl = createCtrlWithStubs([]);
|
ctrl = createCtrlWithStubs([]);
|
||||||
|
|
||||||
@ -474,27 +511,47 @@ describe('ManageDashboards', () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
title: 'folder',
|
title: 'folder',
|
||||||
items: [
|
items: [
|
||||||
{ id: 2, checked: true, uri: 'dash' }
|
{ id: 2, checked: true, slug: 'folder-dash' }
|
||||||
],
|
],
|
||||||
checked: true,
|
checked: true,
|
||||||
uri: 'folder'
|
slug: 'folder'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: 'folder-2',
|
||||||
|
items: [
|
||||||
|
{ id: 3, checked: true, slug: 'folder-2-dash' }
|
||||||
|
],
|
||||||
|
checked: false,
|
||||||
|
slug: 'folder-2'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
title: 'Root',
|
title: 'Root',
|
||||||
items: [
|
items: [
|
||||||
{ id: 3, checked: true, uri: 'dash-2' }
|
{ id: 3, checked: true, slug: 'root-dash' }
|
||||||
],
|
],
|
||||||
checked: false
|
checked: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
toBeDeleted = ctrl.getDashboardsToDelete();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter out children if parent is selected', () => {
|
it('should return 3 items', () => {
|
||||||
const toBeDeleted = ctrl.getDashboardsToDelete();
|
expect(toBeDeleted.length).toEqual(3);
|
||||||
expect(toBeDeleted.length).toEqual(2);
|
});
|
||||||
|
|
||||||
|
it('should filter out children if parent is checked', () => {
|
||||||
expect(toBeDeleted[0]).toEqual('folder');
|
expect(toBeDeleted[0]).toEqual('folder');
|
||||||
expect(toBeDeleted[1]).toEqual('dash-2');
|
});
|
||||||
|
|
||||||
|
it('should not filter out children if parent not is checked', () => {
|
||||||
|
expect(toBeDeleted[1]).toEqual('folder-2-dash');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not filter out children if parent is checked and root', () => {
|
||||||
|
expect(toBeDeleted[2]).toEqual('root-dash');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -507,16 +564,16 @@ describe('ManageDashboards', () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
title: 'folder',
|
title: 'folder',
|
||||||
items: [
|
items: [
|
||||||
{ id: 2, checked: true, uri: 'dash' }
|
{ id: 2, checked: true, slug: 'dash' }
|
||||||
],
|
],
|
||||||
checked: false,
|
checked: false,
|
||||||
uri: 'folder'
|
slug: 'folder'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
title: 'Root',
|
title: 'Root',
|
||||||
items: [
|
items: [
|
||||||
{ id: 3, checked: true, uri: 'dash-2' }
|
{ id: 3, checked: true, slug: 'dash-2' }
|
||||||
],
|
],
|
||||||
checked: false
|
checked: false
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ describe('SearchResultsCtrl', () => {
|
|||||||
|
|
||||||
let folder = {
|
let folder = {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
toggle: () => {}
|
toggle: () => Promise.resolve(folder)
|
||||||
};
|
};
|
||||||
|
|
||||||
ctrl.toggleFolderExpand(folder);
|
ctrl.toggleFolderExpand(folder);
|
||||||
@ -84,7 +84,7 @@ describe('SearchResultsCtrl', () => {
|
|||||||
|
|
||||||
let folder = {
|
let folder = {
|
||||||
expanded: true,
|
expanded: true,
|
||||||
toggle: () => {}
|
toggle: () => Promise.resolve(folder)
|
||||||
};
|
};
|
||||||
|
|
||||||
ctrl.toggleFolderExpand(folder);
|
ctrl.toggleFolderExpand(folder);
|
||||||
|
@ -32,7 +32,7 @@ export class MoveToFolderCtrl {
|
|||||||
private moveDashboard(dash) {
|
private moveDashboard(dash) {
|
||||||
let deferred = this.$q.defer();
|
let deferred = this.$q.defer();
|
||||||
|
|
||||||
this.backendSrv.get('/api/dashboards/' + dash)
|
this.backendSrv.get('/api/dashboards/db/' + dash)
|
||||||
.then(fullDash => {
|
.then(fullDash => {
|
||||||
const model = new DashboardModel(fullDash.dashboard, fullDash.meta);
|
const model = new DashboardModel(fullDash.dashboard, fullDash.meta);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user