Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new title query param to dashboard listing page #14760

Merged
merged 3 commits into from
Nov 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/core_plugins/kibana/public/dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { DashboardListingController } from './listing/dashboard_listing';
import { DashboardConstants, createDashboardEditUrl } from './dashboard_constants';
import { SavedObjectNotFound } from 'ui/errors';
import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { SavedObjectsClientProvider } from 'ui/saved_objects';

uiRoutes
.defaults(/dashboard/, {
Expand All @@ -20,7 +21,32 @@ uiRoutes
.when(DashboardConstants.LANDING_PAGE_PATH, {
template: dashboardListingTemplate,
controller: DashboardListingController,
controllerAs: 'listingController'
controllerAs: 'listingController',
resolve: {
dash: function ($route, Private, courier, kbnUrl) {
const savedObjectsClient = Private(SavedObjectsClientProvider);
const title = $route.current.params.title;
if (title) {
return savedObjectsClient.find({
search: `"${title}"`,
search_fields: 'title',
type: 'dashboard',
}).then(results => {
// The search isn't an exact match, lets see if we can find a single exact match to use
const matchingDashboards = results.savedObjects.filter(
dashboard => dashboard.attributes.title.toLowerCase() === title.toLowerCase());
if (matchingDashboards.length === 1) {
kbnUrl.redirect(createDashboardEditUrl(matchingDashboards[0].id));
} else {
kbnUrl.redirect(`${DashboardConstants.LANDING_PAGE_PATH}?filter="${title}"`);
}
Copy link
Contributor

@spalger spalger Nov 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you throw uiRoutes.WAIT_FOR_URL_CHANGE_TOKEN after calling kbnUrl.redirect() then the router will wait for the url change to take effect (might take a tick or two) rather than rendering the route.

throw uiRoutes.WAIT_FOR_URL_CHANGE_TOKEN;
}).catch(courier.redirectWhenMissing({
'dashboard': DashboardConstants.LANDING_PAGE_PATH
}));
}
}
}
})
.when(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {
template: dashboardTemplate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { DashboardConstants, createDashboardEditUrl } from '../dashboard_constan
import { SortableProperties } from 'ui_framework/services';
import { ConfirmationButtonTypes } from 'ui/modals';

export function DashboardListingController($injector, $scope) {
export function DashboardListingController($injector, $scope, $location) {
const $filter = $injector.get('$filter');
const confirmModal = $injector.get('confirmModal');
const Notifier = $injector.get('Notifier');
Expand Down Expand Up @@ -69,7 +69,7 @@ export function DashboardListingController($injector, $scope) {
this.isFetchingItems = false;
this.items = [];
this.pageOfItems = [];
this.filter = '';
this.filter = ($location.search()).filter || '';

this.pager = pagerFactory.create(this.items.length, 20, 1);

Expand All @@ -78,6 +78,7 @@ export function DashboardListingController($injector, $scope) {
$scope.$watch(() => this.filter, () => {
deselectAll();
fetchItems();
$location.search('filter', this.filter);
});
this.isAscending = (name) => sortableProperties.isAscendingByName(name);
this.getSortedProperty = () => sortableProperties.getSortedProperty();
Expand Down
82 changes: 81 additions & 1 deletion test/functional/apps/dashboard/_dashboard_listing.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import expect from 'expect.js';

export default function ({ getPageObjects }) {
export default function ({ getService, getPageObjects }) {
const PageObjects = getPageObjects(['dashboard', 'header', 'common']);
const remote = getService('remote');

describe('dashboard listing page', function describeIndexTests() {
const dashboardName = 'Dashboard Listing Test';
Expand Down Expand Up @@ -104,5 +105,84 @@ export default function ({ getPageObjects }) {
expect(countOfDashboards).to.equal(1);
});
});

describe('search by title', function () {
it('loads a dashboard if title matches', async function () {
const currentUrl = await remote.getCurrentUrl();
const newUrl = currentUrl + '&title=Two%20Words';
// Only works on a hard refresh.
const useTimeStamp = true;
await remote.get(newUrl.toString(), useTimeStamp);

const onDashboardLandingPage = await PageObjects.dashboard.onDashboardLandingPage();
expect(onDashboardLandingPage).to.equal(false);
});

it('title match is case insensitive', async function () {
await PageObjects.dashboard.gotoDashboardLandingPage();
const currentUrl = await remote.getCurrentUrl();
const newUrl = currentUrl + '&title=two%20words';
// Only works on a hard refresh.
const useTimeStamp = true;
await remote.get(newUrl.toString(), useTimeStamp);

const onDashboardLandingPage = await PageObjects.dashboard.onDashboardLandingPage();
expect(onDashboardLandingPage).to.equal(false);
});

it('stays on listing page if title matches no dashboards', async function () {
await PageObjects.dashboard.gotoDashboardLandingPage();
const currentUrl = await remote.getCurrentUrl();
const newUrl = currentUrl + '&title=nodashboardsnamedme';
// Only works on a hard refresh.
const useTimeStamp = true;
await remote.get(newUrl.toString(), useTimeStamp);

await PageObjects.header.waitUntilLoadingHasFinished();
const onDashboardLandingPage = await PageObjects.dashboard.onDashboardLandingPage();
expect(onDashboardLandingPage).to.equal(true);
});

it('preloads search filter bar when there is no match', async function () {
const searchFilter = await PageObjects.dashboard.getSearchFilterValue();
expect(searchFilter).to.equal('"nodashboardsnamedme"');
});

it('stays on listing page if title matches two dashboards', async function () {
await PageObjects.dashboard.clickNewDashboard();
await PageObjects.dashboard.saveDashboard('two words', { needsConfirm: true });
await PageObjects.dashboard.gotoDashboardLandingPage();
const currentUrl = await remote.getCurrentUrl();
const newUrl = currentUrl + '&title=two%20words';
// Only works on a hard refresh.
const useTimeStamp = true;
await remote.get(newUrl.toString(), useTimeStamp);

await PageObjects.header.waitUntilLoadingHasFinished();
const onDashboardLandingPage = await PageObjects.dashboard.onDashboardLandingPage();
expect(onDashboardLandingPage).to.equal(true);
});

it('preloads search filter bar when there is more than one match', async function () {
const searchFilter = await PageObjects.dashboard.getSearchFilterValue();
expect(searchFilter).to.equal('"two words"');
});

it('matches a title with many special characters', async function () {
await PageObjects.dashboard.clickNewDashboard();
await PageObjects.dashboard.saveDashboard('i am !@#$%^&*()_+~`,.<>{}[]; so special');
await PageObjects.dashboard.gotoDashboardLandingPage();
const currentUrl = await remote.getCurrentUrl();
// Need to encode that one.
const newUrl = currentUrl + '&title=i%20am%20%21%40%23%24%25%5E%26%2A%28%29_%2B~%60%2C.%3C%3E%7B%7D%5B%5D%3B%20so%20special';
// Only works on a hard refresh.
const useTimeStamp = true;
await remote.get(newUrl.toString(), useTimeStamp);

await PageObjects.header.waitUntilLoadingHasFinished();
const onDashboardLandingPage = await PageObjects.dashboard.onDashboardLandingPage();
expect(onDashboardLandingPage).to.equal(false);
});
});
});
}
11 changes: 10 additions & 1 deletion test/functional/page_objects/dashboard_page.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,15 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
/**
*
* @param dashName {String}
* @param saveOptions {{storeTimeWithDashboard: boolean, saveAsNew: boolean}}
* @param saveOptions {{storeTimeWithDashboard: boolean, saveAsNew: boolean, needsConfirm: false}}
*/
async saveDashboard(dashName, saveOptions = {}) {
await this.enterDashboardTitleAndClickSave(dashName, saveOptions);

if (saveOptions.needsConfirm) {
await PageObjects.common.clickConfirmOnModal();
}

await PageObjects.header.waitUntilLoadingHasFinished();

// verify that green message at the top of the page.
Expand Down Expand Up @@ -346,6 +350,11 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
});
}

async getSearchFilterValue() {
const searchFilter = await testSubjects.find('searchFilter');
return await searchFilter.getProperty('value');
}

async searchForDashboardWithName(dashName) {
log.debug(`searchForDashboardWithName: ${dashName}`);

Expand Down