From 2ea663df7887ff56f5f4bdc49fc7830eac36ffd7 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Thu, 7 Dec 2017 17:29:13 +0100 Subject: [PATCH] dashfolders: New Dashboard Folder page Fixes #10083. Permissions page is just a placeholder for now. --- pkg/api/index.go | 15 ++ .../core/components/PageHeader/PageHeader.tsx | 20 +- .../manage_dashboards/manage_dashboards.html | 98 ++++++++ .../manage_dashboards/manage_dashboards.ts | 221 ++++++++++++++++++ public/app/core/components/search/search.html | 12 +- .../components/search/search_results.html | 2 +- public/app/core/core.ts | 4 +- public/app/core/routes/routes.ts | 11 +- .../specs/manage_dashboards.jest.ts} | 6 +- public/app/features/dashboard/all.ts | 4 + .../features/dashboard/dashboard_list_ctrl.ts | 207 +--------------- .../dashboard/folder_dashboards_ctrl.ts | 16 ++ .../features/dashboard/folder_page_loader.ts | 21 ++ .../dashboard/folder_permissions_ctrl.ts | 16 ++ .../dashboard/partials/dashboardList.html | 121 ---------- .../dashboard/partials/dashboard_list.html | 5 + .../dashboard/partials/folder_dashboards.html | 5 + .../partials/folder_permissions.html | 5 + 18 files changed, 447 insertions(+), 342 deletions(-) create mode 100644 public/app/core/components/manage_dashboards/manage_dashboards.html create mode 100644 public/app/core/components/manage_dashboards/manage_dashboards.ts rename public/app/{features/dashboard/specs/dashboard_list_ctrl.jest.ts => core/specs/manage_dashboards.jest.ts} (98%) create mode 100644 public/app/features/dashboard/folder_dashboards_ctrl.ts create mode 100644 public/app/features/dashboard/folder_page_loader.ts create mode 100644 public/app/features/dashboard/folder_permissions_ctrl.ts delete mode 100644 public/app/features/dashboard/partials/dashboardList.html create mode 100644 public/app/features/dashboard/partials/dashboard_list.html create mode 100644 public/app/features/dashboard/partials/folder_dashboards.html create mode 100644 public/app/features/dashboard/partials/folder_permissions.html diff --git a/pkg/api/index.go b/pkg/api/index.go index f3e7af0e4b9..1e44ef33050 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -118,6 +118,21 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) { Children: dashboardChildNavs, }) + dashboardFolderChildNavs := []*dtos.NavLink{ + {Text: "Dashboards", Id: "manage-folder-dashboards", Url: setting.AppSubUrl + "/dashboards", Icon: "fa fa-fw fa-th-large"}, + {Text: "Permissions", Id: "manage-folder-permissions", Url: setting.AppSubUrl + "/dashboards?1", Icon: "fa fa-fw fa-lock"}, + } + + data.NavTree = append(data.NavTree, &dtos.NavLink{ + Text: "Dashboards", + Id: "manage-folder", + SubTitle: "Manage folder dashboards & permissions", + Icon: "fa fa-folder-open", + Url: setting.AppSubUrl + "/", + HideFromMenu: true, + Children: dashboardFolderChildNavs, + }) + if c.IsSignedIn { profileNode := &dtos.NavLink{ Text: c.SignedInUser.Name, diff --git a/public/app/core/components/PageHeader/PageHeader.tsx b/public/app/core/components/PageHeader/PageHeader.tsx index 5371b464ec3..3ab6cac8143 100644 --- a/public/app/core/components/PageHeader/PageHeader.tsx +++ b/public/app/core/components/PageHeader/PageHeader.tsx @@ -72,6 +72,19 @@ export default class PageHeader extends React.Component { super(props); } + renderBreadcrumb(breadcrumbs) { + const breadcrumbsResult = []; + for (let i = 0; i < breadcrumbs.length; i++) { + const bc = breadcrumbs[i]; + if (bc.uri) { + breadcrumbsResult.push({bc.title}); + } else { + breadcrumbsResult.push( / {bc.title}); + } + } + return breadcrumbsResult; + } + renderHeaderTitle(main) { return (
@@ -81,7 +94,12 @@ export default class PageHeader extends React.Component {
-

{main.text}

+ {main.text &&

{main.text}

} + {main.breadcrumbs && main.breadcrumbs.length > 0 && ( +

+ {this.renderBreadcrumb(main.breadcrumbs)} +

) + } {main.subTitle &&
{main.subTitle}
} {main.subType && (
diff --git a/public/app/core/components/manage_dashboards/manage_dashboards.html b/public/app/core/components/manage_dashboards/manage_dashboards.html new file mode 100644 index 00000000000..8c5aeb0facd --- /dev/null +++ b/public/app/core/components/manage_dashboards/manage_dashboards.html @@ -0,0 +1,98 @@ +
+
+ + +
+
+ + + Dashboard + + + + Folder + +
+ +
+ Filters: + + + + {{tagName}} + + +
+ +
+
+ +
+
+ +
+
+ +
+ +
+ + +
+
+
+
+ +
+
+ +
+ +
\ No newline at end of file diff --git a/public/app/core/components/manage_dashboards/manage_dashboards.ts b/public/app/core/components/manage_dashboards/manage_dashboards.ts new file mode 100644 index 00000000000..5b74a0e50fc --- /dev/null +++ b/public/app/core/components/manage_dashboards/manage_dashboards.ts @@ -0,0 +1,221 @@ +import _ from 'lodash'; +import coreModule from 'app/core/core_module'; +import appEvents from 'app/core/app_events'; +import { SearchSrv } from 'app/core/services/search_srv'; + +export class ManageDashboardsCtrl { + public sections: any[]; + tagFilterOptions: any[]; + selectedTagFilter: any; + query: any; + navModel: any; + canDelete = false; + canMove = false; + hasFilters = false; + selectAllChecked = false; + starredFilterOptions = [{ text: 'Filter by Starred', disabled: true }, { text: 'Yes' }, { text: 'No' }]; + selectedStarredFilter: any; + folderId?: number; + + /** @ngInject */ + constructor(private backendSrv, navModelSrv, private $q, private searchSrv: SearchSrv) { + this.query = { query: '', mode: 'tree', tag: [], starred: false, skipRecent: true, skipStarred: true }; + + if (this.folderId) { + this.query.folderIds = [this.folderId]; + } + + this.selectedStarredFilter = this.starredFilterOptions[0]; + + this.getDashboards().then(() => { + this.getTags(); + }); + } + + getDashboards() { + return this.searchSrv.search(this.query).then((result) => { + return this.initDashboardList(result); + }); + } + + initDashboardList(result: any) { + this.canMove = false; + this.canDelete = false; + this.selectAllChecked = false; + this.hasFilters = this.query.query.length > 0 || this.query.tag.length > 0 || this.query.starred; + + if (!result) { + this.sections = []; + return; + } + + this.sections = result; + + for (let section of this.sections) { + section.checked = false; + + for (let dashboard of section.items) { + dashboard.checked = false; + } + } + } + + selectionChanged() { + + let selectedDashboards = 0; + + 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() { + 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(sections) { + const ids = []; + for (let s of sections) { + if (s.checked) { + ids.push(s.id); + } + } + return ids; + } + + delete() { + const selectedDashboards = this.getDashboardsToDelete(); + + appEvents.emit('confirm-modal', { + title: 'Delete', + text: `Do you want to delete the ${selectedDashboards.length} selected dashboards?`, + icon: 'fa-trash', + yesText: 'Delete', + onConfirm: () => { + const promises = []; + for (let dash of selectedDashboards) { + promises.push(this.backendSrv.delete(`/api/dashboards/${dash}`)); + } + + this.$q.all(promises).then(() => { + this.getDashboards(); + }); + } + }); + } + + 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 = this.getDashboardsToMove(); + + const template = '' + + '`'; + appEvents.emit('show-modal', { + templateHtml: template, + modalClass: 'modal--narrow', + model: { dashboards: selectedDashboards, afterSave: this.getDashboards.bind(this) } + }); + } + + getTags() { + return this.searchSrv.getDashboardTags().then((results) => { + this.tagFilterOptions = [{ term: 'Filter By Tag', disabled: true }].concat(results); + this.selectedTagFilter = this.tagFilterOptions[0]; + }); + } + + filterByTag(tag) { + if (_.indexOf(this.query.tag, tag) === -1) { + this.query.tag.push(tag); + } + + return this.getDashboards(); + } + + onQueryChange() { + return this.getDashboards(); + } + + onTagFilterChange() { + var res = this.filterByTag(this.selectedTagFilter.term); + this.selectedTagFilter = this.tagFilterOptions[0]; + return res; + } + + removeTag(tag, evt) { + this.query.tag = _.without(this.query.tag, tag); + this.getDashboards(); + if (evt) { + evt.stopPropagation(); + evt.preventDefault(); + } + } + + onStarredFilterChange() { + this.query.starred = this.selectedStarredFilter.text === 'Yes'; + return this.getDashboards(); + } + + onSelectAllChanged() { + for (let section of this.sections) { + if (!section.hideHeader) { + section.checked = this.selectAllChecked; + } + + section.items = _.map(section.items, (item) => { + item.checked = this.selectAllChecked; + return item; + }); + } + + this.selectionChanged(); + } + + clearFilters() { + this.query.query = ''; + this.query.tag = []; + this.query.starred = false; + this.getDashboards(); + } +} + +export function manageDashboardsDirective() { + return { + restrict: 'E', + templateUrl: 'public/app/core/components/manage_dashboards/manage_dashboards.html', + controller: ManageDashboardsCtrl, + bindToController: true, + controllerAs: 'ctrl', + scope: { + folderId: '=' + } + }; +} + +coreModule.directive('manageDashboards', manageDashboardsDirective); diff --git a/public/app/core/components/search/search.html b/public/app/core/components/search/search.html index c458aa51906..f9b953efcee 100644 --- a/public/app/core/components/search/search.html +++ b/public/app/core/components/search/search.html @@ -21,12 +21,12 @@
-
No dashboards matching your query were found.
- +
No dashboards matching your query were found.
+
diff --git a/public/app/core/components/search/search_results.html b/public/app/core/components/search/search_results.html index 2008910f53a..ad0aa3e6b71 100644 --- a/public/app/core/components/search/search_results.html +++ b/public/app/core/components/search/search_results.html @@ -10,7 +10,7 @@
{{::section.title}} -
+
 
diff --git a/public/app/core/core.ts b/public/app/core/core.ts index a1a93c3cdcc..b32651f418a 100644 --- a/public/app/core/core.ts +++ b/public/app/core/core.ts @@ -53,6 +53,7 @@ import {orgSwitcher} from './components/org_switcher'; import {profiler} from './profiler'; import {registerAngularDirectives} from './angular_wrappers'; import {searchResultsDirective} from './components/search/search_results'; +import {manageDashboardsDirective} from './components/manage_dashboards/manage_dashboards'; export { profiler, @@ -85,5 +86,6 @@ export { geminiScrollbar, gfPageDirective, orgSwitcher, - searchResultsDirective + searchResultsDirective, + manageDashboardsDirective }; diff --git a/public/app/core/routes/routes.ts b/public/app/core/routes/routes.ts index 87437770e0e..8b42545d334 100644 --- a/public/app/core/routes/routes.ts +++ b/public/app/core/routes/routes.ts @@ -69,13 +69,18 @@ function setupAngularRoutes($routeProvider, $locationProvider) { controllerAs: 'ctrl', }) .when('/dashboards', { - templateUrl: 'public/app/features/dashboard/partials/dashboardList.html', + templateUrl: 'public/app/features/dashboard/partials/dashboard_list.html', controller : 'DashboardListCtrl', controllerAs: 'ctrl', }) + .when('/dashboards/folder/:folderId/:type/:slug/permissions', { + templateUrl: 'public/app/features/dashboard/partials/folder_permissions.html', + controller : 'FolderPermissionsCtrl', + controllerAs: 'ctrl', + }) .when('/dashboards/folder/:folderId/:type/:slug', { - templateUrl: 'public/app/features/dashboard/partials/dashboardList.html', - controller : 'DashboardListCtrl', + templateUrl: 'public/app/features/dashboard/partials/folder_dashboards.html', + controller : 'FolderDashboardsCtrl', controllerAs: 'ctrl', }) .when('/org', { diff --git a/public/app/features/dashboard/specs/dashboard_list_ctrl.jest.ts b/public/app/core/specs/manage_dashboards.jest.ts similarity index 98% rename from public/app/features/dashboard/specs/dashboard_list_ctrl.jest.ts rename to public/app/core/specs/manage_dashboards.jest.ts index 1c13d138b6d..770679f09bf 100644 --- a/public/app/features/dashboard/specs/dashboard_list_ctrl.jest.ts +++ b/public/app/core/specs/manage_dashboards.jest.ts @@ -1,8 +1,8 @@ -import { DashboardListCtrl } from '../dashboard_list_ctrl'; +import { ManageDashboardsCtrl } from 'app/core/components/manage_dashboards/manage_dashboards'; import { SearchSrv } from 'app/core/services/search_srv'; import q from 'q'; -describe('DashboardListCtrl', () => { +describe('ManageDashboards', () => { let ctrl; describe('when browsing dashboards', () => { @@ -542,5 +542,5 @@ function createCtrlWithStubs(searchResponse: any, tags?: any) { } }; - return new DashboardListCtrl({}, { getNav: () => { } }, q, searchSrvStub, {}); + return new ManageDashboardsCtrl({}, { getNav: () => { } }, q, searchSrvStub); } diff --git a/public/app/features/dashboard/all.ts b/public/app/features/dashboard/all.ts index f2f2087a24e..a18af82215d 100644 --- a/public/app/features/dashboard/all.ts +++ b/public/app/features/dashboard/all.ts @@ -29,7 +29,11 @@ import './move_to_folder_modal/move_to_folder'; import coreModule from 'app/core/core_module'; import {DashboardListCtrl} from './dashboard_list_ctrl'; +import {FolderDashboardsCtrl} from './folder_dashboards_ctrl'; +import {FolderPermissionsCtrl} from './folder_permissions_ctrl'; import {DashboardImportCtrl} from './dashboard_import_ctrl'; coreModule.controller('DashboardListCtrl', DashboardListCtrl); +coreModule.controller('FolderDashboardsCtrl', FolderDashboardsCtrl); +coreModule.controller('FolderPermissionsCtrl', FolderPermissionsCtrl); coreModule.controller('DashboardImportCtrl', DashboardImportCtrl); diff --git a/public/app/features/dashboard/dashboard_list_ctrl.ts b/public/app/features/dashboard/dashboard_list_ctrl.ts index e2b3ee3227d..b5f5cb8e0dc 100644 --- a/public/app/features/dashboard/dashboard_list_ctrl.ts +++ b/public/app/features/dashboard/dashboard_list_ctrl.ts @@ -1,213 +1,8 @@ -import _ from 'lodash'; -import appEvents from 'app/core/app_events'; -import { SearchSrv } from 'app/core/services/search_srv'; - export class DashboardListCtrl { - public sections: any []; - tagFilterOptions: any []; - selectedTagFilter: any; - query: any; navModel: any; - canDelete = false; - canMove = false; - hasFilters = false; - selectAllChecked = false; - starredFilterOptions = [{text: 'Filter by Starred', disabled: true}, {text: 'Yes'}, {text: 'No'}]; - selectedStarredFilter: any; - folderTitle = null; /** @ngInject */ - constructor(private backendSrv, navModelSrv, private $q, private searchSrv: SearchSrv, private $routeParams) { + constructor(navModelSrv) { this.navModel = navModelSrv.getNav('dashboards', 'manage-dashboards', 0); - this.query = {query: '', mode: 'tree', tag: [], starred: false, skipRecent: true, skipStarred: true}; - - this.selectedStarredFilter = this.starredFilterOptions[0]; - - if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) { - backendSrv.getDashboard(this.$routeParams.type, this.$routeParams.slug).then(result => { - this.folderTitle = result.dashboard.title; - this.query.folderIds = [result.dashboard.id]; - - this.getDashboards().then(() => { - this.getTags(); - }); - }); - } else { - this.getDashboards().then(() => { - this.getTags(); - }); - } - } - - getDashboards() { - return this.searchSrv.search(this.query).then((result) => { - return this.initDashboardList(result); - }); - } - - initDashboardList(result: any) { - this.canMove = false; - this.canDelete = false; - this.selectAllChecked = false; - this.hasFilters = this.query.query.length > 0 || this.query.tag.length > 0 || this.query.starred; - - if (!result) { - this.sections = []; - return; - } - - this.sections = result; - - for (let section of this.sections) { - section.checked = false; - - for (let dashboard of section.items) { - dashboard.checked = false; - } - } - } - - selectionChanged() { - - let selectedDashboards = 0; - - 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() { - 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(sections) { - const ids = []; - for (let s of sections) { - if (s.checked) { - ids.push(s.id); - } - } - return ids; - } - - delete() { - const selectedDashboards = this.getDashboardsToDelete(); - - appEvents.emit('confirm-modal', { - title: 'Delete', - text: `Do you want to delete the ${selectedDashboards.length} selected dashboards?`, - icon: 'fa-trash', - yesText: 'Delete', - onConfirm: () => { - const promises = []; - for (let dash of selectedDashboards) { - promises.push(this.backendSrv.delete(`/api/dashboards/${dash}`)); - } - - this.$q.all(promises).then(() => { - this.getDashboards(); - }); - } - }); - } - - 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 = this.getDashboardsToMove(); - - const template = '' + - '`'; - appEvents.emit('show-modal', { - templateHtml: template, - modalClass: 'modal--narrow', - model: {dashboards: selectedDashboards, afterSave: this.getDashboards.bind(this)} - }); - } - - getTags() { - return this.searchSrv.getDashboardTags().then((results) => { - this.tagFilterOptions = [{ term: 'Filter By Tag', disabled: true }].concat(results); - this.selectedTagFilter = this.tagFilterOptions[0]; - }); - } - - filterByTag(tag) { - if (_.indexOf(this.query.tag, tag) === -1) { - this.query.tag.push(tag); - } - - return this.getDashboards(); - } - - onQueryChange() { - return this.getDashboards(); - } - - onTagFilterChange() { - var res = this.filterByTag(this.selectedTagFilter.term); - this.selectedTagFilter = this.tagFilterOptions[0]; - return res; - } - - removeTag(tag, evt) { - this.query.tag = _.without(this.query.tag, tag); - this.getDashboards(); - if (evt) { - evt.stopPropagation(); - evt.preventDefault(); - } - } - - onStarredFilterChange() { - this.query.starred = this.selectedStarredFilter.text === 'Yes'; - return this.getDashboards(); - } - - onSelectAllChanged() { - for (let section of this.sections) { - if (!section.hideHeader) { - section.checked = this.selectAllChecked; - } - - section.items = _.map(section.items, (item) => { - item.checked = this.selectAllChecked; - return item; - }); - } - - this.selectionChanged(); - } - - clearFilters() { - this.query.query = ''; - this.query.tag = []; - this.query.starred = false; - this.getDashboards(); } } diff --git a/public/app/features/dashboard/folder_dashboards_ctrl.ts b/public/app/features/dashboard/folder_dashboards_ctrl.ts new file mode 100644 index 00000000000..0eca6449584 --- /dev/null +++ b/public/app/features/dashboard/folder_dashboards_ctrl.ts @@ -0,0 +1,16 @@ +import {FolderPageLoader} from './folder_page_loader'; + +export class FolderDashboardsCtrl { + navModel: any; + folderId: number; + + /** @ngInject */ + constructor(private backendSrv, navModelSrv, private $routeParams) { + if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) { + this.folderId = $routeParams.folderId; + this.navModel = navModelSrv.getNav('manage-folder', 'manage-folder-dashboards', 0); + + new FolderPageLoader(this.backendSrv, this.$routeParams).load(this.navModel, this.folderId); + } + } +} diff --git a/public/app/features/dashboard/folder_page_loader.ts b/public/app/features/dashboard/folder_page_loader.ts new file mode 100644 index 00000000000..cc2d8010270 --- /dev/null +++ b/public/app/features/dashboard/folder_page_loader.ts @@ -0,0 +1,21 @@ +import _ from "lodash"; + +export class FolderPageLoader { + constructor(private backendSrv, private $routeParams) { } + + load(navModel, folderId) { + this.backendSrv.getDashboard(this.$routeParams.type, this.$routeParams.slug).then(result => { + const folderTitle = result.dashboard.title; + navModel.main.text = ''; + navModel.main.breadcrumbs = [ + { title: 'Dashboards', uri: '/dashboards' }, + { title: folderTitle } + ]; + const folderUrl = `/dashboards/folder/${folderId}/${result.meta.type}/${result.meta.slug}`; + const dashTab = _.find(navModel.main.children, { id: 'manage-folder-dashboards' }); + dashTab.url = folderUrl; + const permTab = _.find(navModel.main.children, { id: 'manage-folder-permissions' }); + permTab.url = folderUrl + '/permissions'; + }); + } +} diff --git a/public/app/features/dashboard/folder_permissions_ctrl.ts b/public/app/features/dashboard/folder_permissions_ctrl.ts new file mode 100644 index 00000000000..a7d46088ac5 --- /dev/null +++ b/public/app/features/dashboard/folder_permissions_ctrl.ts @@ -0,0 +1,16 @@ +import {FolderPageLoader} from './folder_page_loader'; + +export class FolderPermissionsCtrl { + navModel: any; + folderId: number; + + /** @ngInject */ + constructor(private backendSrv, navModelSrv, private $routeParams) { + if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) { + this.folderId = $routeParams.folderId; + this.navModel = navModelSrv.getNav('manage-folder', 'manage-folder-permissions', 0); + + new FolderPageLoader(this.backendSrv, this.$routeParams).load(this.navModel, this.folderId); + } + } +} diff --git a/public/app/features/dashboard/partials/dashboardList.html b/public/app/features/dashboard/partials/dashboardList.html deleted file mode 100644 index cecd52aa891..00000000000 --- a/public/app/features/dashboard/partials/dashboardList.html +++ /dev/null @@ -1,121 +0,0 @@ - - -
-
-
-

-  {{ctrl.folderTitle}} -

-
-
- - - - Dashboard - - - - Folder - -
- -
-
- - -
-
- - - Dashboard - - - - Folder - -
- -
- Filters: - - - - {{tagName}} - - -
- -
-
- -
-
- -
- -
- -
-
- -
- -
- - -
-
-
-
- -
-
-
diff --git a/public/app/features/dashboard/partials/dashboard_list.html b/public/app/features/dashboard/partials/dashboard_list.html new file mode 100644 index 00000000000..241d464434a --- /dev/null +++ b/public/app/features/dashboard/partials/dashboard_list.html @@ -0,0 +1,5 @@ + + +
+ +
diff --git a/public/app/features/dashboard/partials/folder_dashboards.html b/public/app/features/dashboard/partials/folder_dashboards.html new file mode 100644 index 00000000000..eeda28ad4a4 --- /dev/null +++ b/public/app/features/dashboard/partials/folder_dashboards.html @@ -0,0 +1,5 @@ + + +
+ +
\ No newline at end of file diff --git a/public/app/features/dashboard/partials/folder_permissions.html b/public/app/features/dashboard/partials/folder_permissions.html new file mode 100644 index 00000000000..ad34618457d --- /dev/null +++ b/public/app/features/dashboard/partials/folder_permissions.html @@ -0,0 +1,5 @@ + + +
+

Coming soon! Permissions will be added in Grafana 5.0 beta.

+
\ No newline at end of file