mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
search: worked on search results
This commit is contained in:
@@ -15,6 +15,7 @@ type Hit struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Uri string `json:"uri"`
|
||||
Slug string `json:"slug"`
|
||||
Type HitType `json:"type"`
|
||||
Tags []string `json:"tags"`
|
||||
IsStarred bool `json:"isStarred"`
|
||||
|
||||
@@ -260,6 +260,7 @@ func makeQueryResult(query *search.FindPersistedDashboardsQuery, res []Dashboard
|
||||
Id: item.Id,
|
||||
Title: item.Title,
|
||||
Uri: "db/" + item.Slug,
|
||||
Slug: item.Slug,
|
||||
Type: getHitType(item),
|
||||
FolderId: item.FolderId,
|
||||
FolderTitle: item.FolderTitle,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div ng-repeat="section in ctrl.results" class="search-section">
|
||||
<a class="search-section__header pointer" ng-hide="section.hideHeader" ng-class="{'selected': section.selected}" ng-click="ctrl.toggleFolderExpand(section)">
|
||||
<div class="search-section__header pointer" ng-hide="section.hideHeader" ng-class="{'selected': section.selected}" ng-click="ctrl.toggleFolderExpand(section)">
|
||||
<div ng-click="ctrl.toggleSelection(section, $event)">
|
||||
<gf-form-switch
|
||||
ng-show="ctrl.editable"
|
||||
@@ -10,12 +10,12 @@
|
||||
</div>
|
||||
<i class="search-section__header__icon" ng-class="section.icon"></i>
|
||||
<span class="search-section__header__text">{{::section.title}}</span>
|
||||
<div ng-show="ctrl.editable && section.id > 0" ng-click="ctrl.navigateToFolder(section, $event)">
|
||||
<i class="fa fa-cog search-section__header__toggle"></i>
|
||||
</div>
|
||||
<a ng-show="section.url" href="{{section.url}}" class="search-section__header__link">
|
||||
<i class="fa fa-cog"></i>
|
||||
</a>
|
||||
<i class="fa fa-angle-down search-section__header__toggle" ng-show="section.expanded"></i>
|
||||
<i class="fa fa-angle-right search-section__header__toggle" ng-hide="section.expanded"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="search-section__header" ng-show="section.hideHeader"></div>
|
||||
|
||||
@@ -34,9 +34,6 @@
|
||||
</span>
|
||||
<span class="search-item__body">
|
||||
<div class="search-item__body-title">{{::item.title}}</div>
|
||||
<div class="search-item__body-sub-title" ng-show="item.folderTitle && section.hideHeader">
|
||||
{{::item.folderTitle}}
|
||||
</div>
|
||||
</span>
|
||||
<span class="search-item__tags">
|
||||
<span ng-click="ctrl.selectTag(tag, $event)" ng-repeat="tag in item.tags" tag-color-from-name="tag" class="label label-tag">
|
||||
|
||||
@@ -78,17 +78,17 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
|
||||
controller : 'CreateFolderCtrl',
|
||||
controllerAs: 'ctrl',
|
||||
})
|
||||
.when('/dashboards/folder/:folderId/:type/:slug/permissions', {
|
||||
.when('/dashboards/folder/:folderId/:slug/permissions', {
|
||||
templateUrl: 'public/app/features/dashboard/partials/folder_permissions.html',
|
||||
controller : 'FolderPermissionsCtrl',
|
||||
controllerAs: 'ctrl',
|
||||
})
|
||||
.when('/dashboards/folder/:folderId/:type/:slug/settings', {
|
||||
.when('/dashboards/folder/:folderId/:slug/settings', {
|
||||
templateUrl: 'public/app/features/dashboard/partials/folder_settings.html',
|
||||
controller : 'FolderSettingsCtrl',
|
||||
controllerAs: 'ctrl',
|
||||
})
|
||||
.when('/dashboards/folder/:folderId/:type/:slug', {
|
||||
.when('/dashboards/folder/:folderId/:slug', {
|
||||
templateUrl: 'public/app/features/dashboard/partials/folder_dashboards.html',
|
||||
controller : 'FolderDashboardsCtrl',
|
||||
controllerAs: 'ctrl',
|
||||
|
||||
@@ -84,105 +84,96 @@ export class SearchSrv {
|
||||
});
|
||||
}
|
||||
|
||||
private getDashboardsAndFolders(sections) {
|
||||
const rootFolderId = 0;
|
||||
|
||||
let query = {
|
||||
folderIds: [rootFolderId],
|
||||
};
|
||||
|
||||
return this.backendSrv.search(query).then(results => {
|
||||
for (let hit of results) {
|
||||
if (hit.type === 'dash-folder') {
|
||||
sections[hit.id] = {
|
||||
id: hit.id,
|
||||
title: hit.title,
|
||||
items: [],
|
||||
icon: 'fa fa-folder',
|
||||
score: _.keys(sections).length,
|
||||
uri: hit.uri,
|
||||
toggle: this.toggleFolder.bind(this),
|
||||
};
|
||||
}
|
||||
private transformToViewModel(hit) {
|
||||
hit.url = 'dashboard/db/' + hit.slug;
|
||||
return hit;
|
||||
}
|
||||
|
||||
sections[0] = {
|
||||
id: 0,
|
||||
title: 'Root',
|
||||
items: [],
|
||||
icon: 'fa fa-folder-open',
|
||||
score: _.keys(sections).length,
|
||||
expanded: true,
|
||||
};
|
||||
|
||||
for (let hit of results) {
|
||||
if (hit.type === 'dash-folder') {
|
||||
continue;
|
||||
}
|
||||
let section = sections[hit.folderId || 0];
|
||||
if (section) {
|
||||
section.items.push(this.transformToViewModel(hit));
|
||||
} else {
|
||||
console.log('Error: dashboard returned from browse search but not folder', hit.id, hit.folderId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private browse(options) {
|
||||
search(options) {
|
||||
let sections: any = {};
|
||||
|
||||
let promises = [];
|
||||
let query = _.clone(options);
|
||||
let hasFilters = options.query ||
|
||||
(options.tag && options.tag.length > 0) || options.starred ||
|
||||
(options.folderIds && options.folderIds.length > 0);
|
||||
|
||||
if (!options.skipRecent) {
|
||||
if (!options.skipRecent && !hasFilters) {
|
||||
promises.push(this.getRecentDashboards(sections));
|
||||
}
|
||||
|
||||
if (!options.skipStarred) {
|
||||
if (!options.skipStarred && !hasFilters) {
|
||||
promises.push(this.getStarred(sections));
|
||||
}
|
||||
|
||||
promises.push(this.getDashboardsAndFolders(sections));
|
||||
query.folderIds = query.folderIds || [];
|
||||
if (!hasFilters) {
|
||||
query.folderIds = [0];
|
||||
}
|
||||
|
||||
promises.push(this.backendSrv.search(query).then(results => {
|
||||
return this.handleSearchResult(sections, results);
|
||||
}));
|
||||
|
||||
return this.$q.all(promises).then(() => {
|
||||
return _.sortBy(_.values(sections), 'score');
|
||||
});
|
||||
}
|
||||
|
||||
private transformToViewModel(hit) {
|
||||
hit.url = 'dashboard/' + hit.uri;
|
||||
return hit;
|
||||
}
|
||||
|
||||
search(options) {
|
||||
if (!options.folderIds && !options.query && (!options.tag || options.tag.length === 0) && !options.starred) {
|
||||
return this.browse(options);
|
||||
}
|
||||
|
||||
let query = _.clone(options);
|
||||
query.folderIds = options.folderIds || [];
|
||||
query.type = 'dash-db';
|
||||
|
||||
return this.backendSrv.search(query).then(results => {
|
||||
private handleSearchResult(sections, results) {
|
||||
if (results.length === 0) {
|
||||
return results;
|
||||
return sections;
|
||||
}
|
||||
|
||||
let section = {
|
||||
hideHeader: true,
|
||||
// create folder index
|
||||
for (let hit of results) {
|
||||
if (hit.type === 'dash-folder') {
|
||||
sections[hit.id] = {
|
||||
id: hit.id,
|
||||
title: hit.title,
|
||||
expanded: false,
|
||||
items: [],
|
||||
expanded: true,
|
||||
toggle: this.toggleFolder.bind(this),
|
||||
url: `dashboards/folder/${hit.id}/${hit.slug}`,
|
||||
icon: 'fa fa-folder',
|
||||
score: _.keys(sections).length,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
for (let hit of results) {
|
||||
if (hit.type === 'dash-folder') {
|
||||
continue;
|
||||
}
|
||||
section.items.push(this.transformToViewModel(hit));
|
||||
|
||||
let section = sections[hit.folderId || 0];
|
||||
if (!section) {
|
||||
if (hit.folderId) {
|
||||
section = {
|
||||
id: hit.folderId,
|
||||
title: hit.folderTitle,
|
||||
url: `dashboards/folder/${hit.folderId}/${hit.folderSlug}`,
|
||||
items: [],
|
||||
icon: 'fa fa-folder-open',
|
||||
toggle: this.toggleFolder.bind(this),
|
||||
score: _.keys(sections).length,
|
||||
};
|
||||
} else {
|
||||
section = {
|
||||
id: 0,
|
||||
title: 'Root',
|
||||
items: [],
|
||||
icon: 'fa fa-folder-open',
|
||||
toggle: this.toggleFolder.bind(this),
|
||||
score: _.keys(sections).length,
|
||||
};
|
||||
}
|
||||
// add section
|
||||
sections[hit.folderId || 0] = section;
|
||||
}
|
||||
|
||||
return [section];
|
||||
});
|
||||
section.expanded = true;
|
||||
section.items.push(this.transformToViewModel(hit));
|
||||
}
|
||||
}
|
||||
|
||||
private toggleFolder(section) {
|
||||
|
||||
@@ -214,9 +214,8 @@ describe('SearchSrv', () => {
|
||||
expect(backendSrvMock.search.mock.calls[0][0].folderIds).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should place all results in a single section', () => {
|
||||
expect(results).toHaveLength(1);
|
||||
expect(results[0].hideHeader).toBe(true);
|
||||
it('should group results by folder', () => {
|
||||
expect(results).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,10 +6,12 @@ export class FolderDashboardsCtrl {
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv, navModelSrv, private $routeParams) {
|
||||
if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) {
|
||||
if (this.$routeParams.folderId && this.$routeParams.slug) {
|
||||
this.folderId = $routeParams.folderId;
|
||||
|
||||
new FolderPageLoader(this.backendSrv, this.$routeParams).load(this, this.folderId, 'manage-folder-dashboards');
|
||||
const loader = new FolderPageLoader(this.backendSrv, this.$routeParams);
|
||||
|
||||
loader.load(this, this.folderId, 'manage-folder-dashboards');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export class FolderPageLoader {
|
||||
icon: 'fa fa-folder-open',
|
||||
id: 'manage-folder',
|
||||
subTitle: 'Manage folder dashboards & permissions',
|
||||
url: '/fsdfds',
|
||||
url: '',
|
||||
text: '',
|
||||
breadcrumbs: [
|
||||
{ title: 'Dashboards', url: '/dashboards' },
|
||||
@@ -41,11 +41,11 @@ export class FolderPageLoader {
|
||||
}
|
||||
};
|
||||
|
||||
return this.backendSrv.getDashboard(this.$routeParams.type, this.$routeParams.slug).then(result => {
|
||||
return this.backendSrv.getDashboard('db', this.$routeParams.slug).then(result => {
|
||||
const folderTitle = result.dashboard.title;
|
||||
ctrl.navModel.main.text = '';
|
||||
ctrl.navModel.main.breadcrumbs = [
|
||||
{ title: 'Dashboards', uri: '/dashboards' },
|
||||
{ title: 'Dashboards', url: '/dashboards' },
|
||||
{ title: folderTitle }
|
||||
];
|
||||
|
||||
@@ -65,6 +65,6 @@ export class FolderPageLoader {
|
||||
}
|
||||
|
||||
createFolderUrl(folderId: number, type: string, slug: string) {
|
||||
return `/dashboards/folder/${folderId}/${type}/${slug}`;
|
||||
return `/dashboards/folder/${folderId}/${slug}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export class FolderPermissionsCtrl {
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv, navModelSrv, private $routeParams) {
|
||||
if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) {
|
||||
if (this.$routeParams.folderId && this.$routeParams.slug) {
|
||||
this.folderId = $routeParams.folderId;
|
||||
|
||||
new FolderPageLoader(this.backendSrv, this.$routeParams).load(this, this.folderId, 'manage-folder-permissions');
|
||||
|
||||
@@ -11,7 +11,7 @@ export class FolderSettingsCtrl {
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv, navModelSrv, private $routeParams, private $location) {
|
||||
if (this.$routeParams.folderId && this.$routeParams.type && this.$routeParams.slug) {
|
||||
if (this.$routeParams.folderId && this.$routeParams.slug) {
|
||||
this.folderId = $routeParams.folderId;
|
||||
|
||||
this.folderPageLoader = new FolderPageLoader(this.backendSrv, this.$routeParams);
|
||||
|
||||
@@ -65,11 +65,11 @@
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="submit" class="btn btn-success" ng-disabled="ctrl.current.readOnly" ng-click="ctrl.saveChanges()">Save</button>
|
||||
<button type="submit" class="btn btn-success" ng-disabled="ctrl.current.readOnly" ng-click="ctrl.saveChanges()">Save & Test</button>
|
||||
<button type="submit" class="btn btn-danger" ng-disabled="ctrl.current.readOnly" ng-show="!ctrl.isNew" ng-click="ctrl.delete()">
|
||||
Delete
|
||||
</button>
|
||||
<a class="btn btn-link" href="datasources">Cancel</a>
|
||||
<a class="btn btn-inverse" href="datasources">Back</a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
@@ -137,6 +137,12 @@
|
||||
&:hover, &.selected {
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.search-section__header__link {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-section__header__icon {
|
||||
@@ -154,6 +160,13 @@
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.search-section__header__link {
|
||||
padding: 2px 10px 0;
|
||||
color: $text-muted;
|
||||
opacity: 0;
|
||||
transition: opacity 150ms ease-in-out;
|
||||
}
|
||||
|
||||
.search-item {
|
||||
@include list-item();
|
||||
|
||||
@@ -181,12 +194,6 @@
|
||||
color: $list-item-link-color;
|
||||
}
|
||||
|
||||
.search-item__body-sub-title {
|
||||
color: $text-muted;
|
||||
font-size: $font-size-sm;
|
||||
line-height: 9pt;
|
||||
}
|
||||
|
||||
.search-item__icon {
|
||||
padding: 5px;
|
||||
flex: 0 0 auto;
|
||||
|
||||
Reference in New Issue
Block a user