From 8daff73ba21df0976c53cb8750919f8b4db5cb80 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 20 Nov 2017 18:15:59 +0100 Subject: [PATCH] dashlist: started fixing js/css after design changes --- public/app/core/services/search_srv.ts | 3 +- .../features/dashboard/dashboard_list_ctrl.ts | 124 ++++---- .../move_to_folder_modal/move_to_folder.ts | 2 +- .../dashboard/partials/dashboardList.html | 123 +++++--- .../specs/dashboard_list_ctrl.jest.ts | 275 +++++++++++++----- 5 files changed, 342 insertions(+), 185 deletions(-) diff --git a/public/app/core/services/search_srv.ts b/public/app/core/services/search_srv.ts index 6aa7e441d18..4b32c2735bf 100644 --- a/public/app/core/services/search_srv.ts +++ b/public/app/core/services/search_srv.ts @@ -24,6 +24,7 @@ export class SearchSrv { items: [], icon: 'fa fa-folder', score: _.keys(sections).length, + uri: hit.uri }; } } @@ -34,7 +35,7 @@ export class SearchSrv { items: [], icon: 'fa fa-folder-open', score: _.keys(sections).length, - expanded: true, + expanded: true }; for (let hit of results) { diff --git a/public/app/features/dashboard/dashboard_list_ctrl.ts b/public/app/features/dashboard/dashboard_list_ctrl.ts index 7ee7312fecc..032e8d7ffa0 100644 --- a/public/app/features/dashboard/dashboard_list_ctrl.ts +++ b/public/app/features/dashboard/dashboard_list_ctrl.ts @@ -1,101 +1,74 @@ import _ from 'lodash'; import appEvents from 'app/core/app_events'; +import { SearchSrv } from 'app/core/services/search_srv'; export class DashboardListCtrl { - public dashboards: any []; + public sections: any []; + tags: any []; query: any; navModel: any; canDelete = false; canMove = false; /** @ngInject */ - constructor(private backendSrv, navModelSrv, private $q) { + constructor(private backendSrv, navModelSrv, private $q, private searchSrv: SearchSrv) { this.navModel = navModelSrv.getNav('dashboards', 'dashboards'); this.query = {query: '', mode: 'tree', tag: []}; + this.getDashboards(); + // this.getDashboards().then(() => { + // this.getTags(); + // }); } getDashboards() { - return this.backendSrv.search(this.query).then((result) => { + return this.searchSrv.browse().then((result) => { - this.dashboards = this.groupDashboardsInFolders(result); + this.sections = result; - for (let dash of this.dashboards) { - dash.checked = false; - } - }); - } + for (let section of this.sections) { + section.checked = false; - groupDashboardsInFolders(results) { - let byId = _.groupBy(results, 'id'); - let byFolderId = _.groupBy(results, 'folderId'); - let finalList = []; - - // add missing parent folders - _.each(results, (hit, index) => { - if (hit.folderId && !byId[hit.folderId]) { - const folder = { - id: hit.folderId, - uri: `db/${hit.folderSlug}`, - title: hit.folderTitle, - type: 'dash-folder' - }; - byId[hit.folderId] = folder; - results.splice(index, 0, folder); - } - }); - - // group by folder - for (let hit of results) { - if (hit.folderId) { - hit.type = "dash-child"; - } else { - finalList.push(hit); - } - - hit.url = 'dashboard/' + hit.uri; - - if (hit.type === 'dash-folder') { - if (!byFolderId[hit.id]) { - continue; - } - - for (let child of byFolderId[hit.id]) { - finalList.push(child); + for (let dashboard of section.items) { + dashboard.checked = false; } } - } - - return finalList; + }); } selectionChanged() { - const selected = _.filter(this.dashboards, {checked: true}).length; - this.canDelete = selected > 0; - const selectedDashboards = _.filter(this.dashboards, (o) => { - return o.checked && (o.type === 'dash-db' || o.type === 'dash-child'); - }).length; + let selectedDashboards = 0; - const selectedFolders = _.filter(this.dashboards, {checked: true, type: 'dash-folder'}).length; + for (let section of this.sections) { + selectedDashboards += _.filter(section.items, {checked: true}).length; + } + + const selectedFolders = _.filter(this.sections, {checked: true}).length; this.canMove = selectedDashboards > 0 && selectedFolders === 0; + this.canDelete = selectedDashboards > 0 || selectedFolders > 0; } getDashboardsToDelete() { - const selectedFolderIds = this.getFolderIds(this.dashboards); - return _.filter(this.dashboards, o => { - return o.checked && ( - o.type !== 'dash-child' || - (o.type === 'dash-child' && !_.includes(selectedFolderIds, o.folderId)) - ); - }); + let selectedDashboards = []; + + for (const section of this.sections) { + if (section.checked) { + selectedDashboards.push(section.uri); + } else { + const selected = _.filter(section.items, {checked: true}); + selectedDashboards.push(... _.map(selected, 'uri')); + } + } + + return selectedDashboards; } - getFolderIds(dashboards) { + getFolderIds(sections) { const ids = []; - for (let dash of dashboards) { - if (dash.type === 'dash-folder') { - ids.push(dash.id); + for (let s of sections) { + if (s.checked) { + ids.push(s.id); } } return ids; @@ -112,7 +85,7 @@ export class DashboardListCtrl { onConfirm: () => { const promises = []; for (let dash of selectedDashboards) { - promises.push(this.backendSrv.delete(`/api/dashboards/${dash.uri}`)); + promises.push(this.backendSrv.delete(`/api/dashboards/${dash}`)); } this.$q.all(promises).then(() => { @@ -122,8 +95,19 @@ export class DashboardListCtrl { }); } + getDashboardsToMove() { + let selectedDashboards = []; + + for (const section of this.sections) { + const selected = _.filter(section.items, {checked: true}); + selectedDashboards.push(... _.map(selected, 'uri')); + } + + return selectedDashboards; + } + moveTo() { - const selectedDashboards = _.filter(this.dashboards, {checked: true}); + const selectedDashboards = this.getDashboardsToMove(); const template = '' + @@ -135,6 +119,12 @@ export class DashboardListCtrl { }); } + // getTags() { + // return this.backendSrv.get('/api/dashboards/tags').then((results) => { + // this.tags = results; + // }); + // } + filterByTag(tag, evt) { this.query.tag.push(tag); this.getDashboards(); diff --git a/public/app/features/dashboard/move_to_folder_modal/move_to_folder.ts b/public/app/features/dashboard/move_to_folder_modal/move_to_folder.ts index df7b49c2f00..ce110b3e2a2 100644 --- a/public/app/features/dashboard/move_to_folder_modal/move_to_folder.ts +++ b/public/app/features/dashboard/move_to_folder_modal/move_to_folder.ts @@ -18,7 +18,7 @@ export class MoveToFolderCtrl { save() { const promises = []; for (let dash of this.dashboards) { - const promise = this.backendSrv.get('/api/dashboards/' + dash.uri).then(fullDash => { + const promise = this.backendSrv.get('/api/dashboards/' + dash).then(fullDash => { const model = new DashboardModel(fullDash.dashboard, fullDash.meta); model.folderId = this.folder.id; model.meta.folderId = this.folder.id; diff --git a/public/app/features/dashboard/partials/dashboardList.html b/public/app/features/dashboard/partials/dashboardList.html index 313ec2337b7..104861af637 100644 --- a/public/app/features/dashboard/partials/dashboardList.html +++ b/public/app/features/dashboard/partials/dashboardList.html @@ -15,26 +15,25 @@ diff --git a/public/app/features/dashboard/specs/dashboard_list_ctrl.jest.ts b/public/app/features/dashboard/specs/dashboard_list_ctrl.jest.ts index c4cd538b6ac..ea1e1d6ea00 100644 --- a/public/app/features/dashboard/specs/dashboard_list_ctrl.jest.ts +++ b/public/app/features/dashboard/specs/dashboard_list_ctrl.jest.ts @@ -1,76 +1,63 @@ import {DashboardListCtrl} from '../dashboard_list_ctrl'; +import { SearchSrv } from 'app/core/services/search_srv'; import q from 'q'; describe('DashboardListCtrl', () => { let ctrl; - describe('when fetching dashboards', () => { - describe('and dashboard has parent that is not in search result', () => { - beforeEach(() => { - const response = [ - { - id: 399, - title: "Dashboard Test", - uri: "db/dashboard-test", - type: "dash-db", - tags: [], - isStarred: false, - folderId: 410, - folderTitle: "afolder", - folderSlug: "afolder" - } - ]; - - ctrl = new DashboardListCtrl({search: () => q.resolve(response)}, {getNav: () => {}}, q); - return ctrl.getDashboards(); - }); - - it('should add the missing parent folder to the result', () => { - expect(ctrl.dashboards.length).toEqual(2); - expect(ctrl.dashboards[0].id).toEqual(410); - expect(ctrl.dashboards[1].id).toEqual(399); - }); - }); - + describe('when browsing dashboards', () => { beforeEach(() => { const response = [ { id: 410, title: "afolder", - uri: "db/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 }, { - id: 3, - title: "something else", + id: 0, + title: "Root", + icon: 'fa fa-folder-open', uri: "db/something-else", type: "dash-db", + items: [ + { + id: 500, + title: "Dashboard Test", + url: "dashboard/db/dashboard-test", + icon: 'fa fa-folder', + tags: [], + isStarred: false + } + ], tags: [], isStarred: false, - }, - { - id: 399, - title: "Dashboard Test", - uri: "db/dashboard-test", - type: "dash-db", - tags: [], - isStarred: false, - folderId: 410, - folderTitle: "afolder", - folderSlug: "afolder" } ]; - ctrl = new DashboardListCtrl({search: () => q.resolve(response)}, {getNav: () => {}}, null); + ctrl = createCtrlWithStubs(response); return ctrl.getDashboards(); }); - it('should group them in folders', () => { - expect(ctrl.dashboards.length).toEqual(3); - expect(ctrl.dashboards[0].id).toEqual(410); - expect(ctrl.dashboards[1].id).toEqual(399); - expect(ctrl.dashboards[2].id).toEqual(3); + it('should set checked to false on all sections and children', () => { + expect(ctrl.sections.length).toEqual(2); + expect(ctrl.sections[0].checked).toEqual(false); + expect(ctrl.sections[0].items[0].checked).toEqual(false); + expect(ctrl.sections[1].checked).toEqual(false); + expect(ctrl.sections[1].items[0].checked).toEqual(false); }); }); @@ -78,14 +65,26 @@ describe('DashboardListCtrl', () => { let ctrl; beforeEach(() => { - ctrl = new DashboardListCtrl({search: () => q.resolve([])}, {getNav: () => {}}, null); + ctrl = createCtrlWithStubs([]); }); describe('and no dashboards are selected', () => { beforeEach(() => { - ctrl.dashboards = [ - {id: 1, type: 'dash-folder'}, - {id: 2, type: 'dash-db'} + ctrl.sections = [ + { + id: 1, + items: [ + { id: 2, checked: false } + ], + checked: false + }, + { + id: 0, + items: [ + { id: 3, checked: false } + ], + checked: false + } ]; ctrl.selectionChanged(); }); @@ -101,9 +100,23 @@ describe('DashboardListCtrl', () => { describe('and one dashboard in root is selected', () => { beforeEach(() => { - ctrl.dashboards = [ - {id: 1, type: 'dash-folder'}, - {id: 2, type: 'dash-db', checked: true} + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [ + { id: 2, checked: false } + ], + checked: false + }, + { + id: 0, + title: 'Root', + items: [ + { id: 3, checked: true } + ], + checked: false + } ]; ctrl.selectionChanged(); }); @@ -119,10 +132,25 @@ describe('DashboardListCtrl', () => { describe('and one child dashboard is selected', () => { beforeEach(() => { - ctrl.dashboards = [ - {id: 1, type: 'dash-folder'}, - {id: 2, type: 'dash-child', checked: true} + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [ + { id: 2, checked: true } + ], + checked: false + }, + { + id: 0, + title: 'Root', + items: [ + { id: 3, checked: false } + ], + checked: false + } ]; + ctrl.selectionChanged(); }); @@ -137,10 +165,25 @@ describe('DashboardListCtrl', () => { describe('and one child dashboard and one dashboard is selected', () => { beforeEach(() => { - ctrl.dashboards = [ - {id: 1, type: 'dash-folder'}, - {id: 2, type: 'dash-child', checked: true} + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [ + { id: 2, checked: true } + ], + checked: false + }, + { + id: 0, + title: 'Root', + items: [ + { id: 3, checked: true } + ], + checked: false + } ]; + ctrl.selectionChanged(); }); @@ -155,10 +198,33 @@ describe('DashboardListCtrl', () => { describe('and one child dashboard and one folder is selected', () => { beforeEach(() => { - ctrl.dashboards = [ - {id: 1, type: 'dash-folder', checked: true}, - {id: 2, type: 'dash-child', checked: true} + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [ + { id: 2, checked: false } + ], + checked: true + }, + { + id: 3, + title: 'folder', + items: [ + { id: 4, checked: true } + ], + checked: false + }, + { + id: 0, + title: 'Root', + items: [ + { id: 3, checked: false } + ], + checked: false + } ]; + ctrl.selectionChanged(); }); @@ -174,19 +240,86 @@ describe('DashboardListCtrl', () => { describe('when deleting dashboards', () => { beforeEach(() => { - ctrl = new DashboardListCtrl({search: () => q.resolve([])}, {getNav: () => {}}, q); - ctrl.dashboards = [ - {id: 1, type: 'dash-folder', checked: true}, - {id: 2, type: 'dash-child', checked: true, folderId: 1}, - {id: 3, type: 'dash-db', checked: true} + ctrl = createCtrlWithStubs([]); + + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [ + { id: 2, checked: true, uri: 'dash' } + ], + checked: true, + uri: 'folder' + }, + { + id: 0, + title: 'Root', + items: [ + { id: 3, checked: true, uri: 'dash-2' } + ], + checked: false + } ]; }); it('should filter out children if parent is selected', () => { const toBeDeleted = ctrl.getDashboardsToDelete(); expect(toBeDeleted.length).toEqual(2); - expect(toBeDeleted[0].id).toEqual(1); - expect(toBeDeleted[1].id).toEqual(3); + expect(toBeDeleted[0]).toEqual('folder'); + expect(toBeDeleted[1]).toEqual('dash-2'); + }); + }); + + describe('when moving dashboards', () => { + beforeEach(() => { + ctrl = createCtrlWithStubs([]); + + ctrl.sections = [ + { + id: 1, + title: 'folder', + items: [ + { id: 2, checked: true, uri: 'dash' } + ], + checked: false, + uri: 'folder' + }, + { + id: 0, + title: 'Root', + items: [ + { id: 3, checked: true, uri: 'dash-2' } + ], + checked: false + } + ]; + }); + + it('should get selected dashboards', () => { + const toBeMove = ctrl.getDashboardsToMove(); + expect(toBeMove.length).toEqual(2); + expect(toBeMove[0]).toEqual('dash'); + expect(toBeMove[1]).toEqual('dash-2'); }); }); }); + +function createCtrlWithStubs(response: any) { + const searchSrvStub = { + browse: () => { + return q.resolve(response); + }, + search: (options: any) => { + return q.resolve(response); + }, + toggleFolder: (section) => { + return q.resolve(response); + }, + getDashboardTags: () => { + return q.resolve([]); + } + }; + + return new DashboardListCtrl({}, {getNav: () => {}}, q, searchSrvStub); +}