Skip to content

Commit

Permalink
[Maps] saved object tagging (elastic#83197)
Browse files Browse the repository at this point in the history
* add tag selector to save modal

* save tag references onSave

* populate tags when unwrapping attributes

* tslint

* update listing page to show tags

* fix data-test-subj id in functional tests

* i18n cleanup

* tslint

* remove unused import

* use listingTable service for functional tests

* tslint and fix mvt grid layer functional test

* review feedback

* add tags to all privileges and add test user to find, delete, get, get_all, and update tests

* move functions to module scope

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
nreese and kibanamachine committed Nov 17, 2020
1 parent 7860685 commit 170f479
Show file tree
Hide file tree
Showing 27 changed files with 603 additions and 570 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export interface TableListViewProps {
listingLimit: number;
initialFilter: string;
initialPageSize: number;
noItemsFragment: JSX.Element;
noItemsFragment?: JSX.Element;
tableColumns: Array<EuiBasicTableColumn<any>>;
tableListTitle: string;
toastNotifications: ToastsStart;
Expand All @@ -73,7 +73,7 @@ export interface TableListViewProps {
/**
* Describes the content of the table. If not specified, the caption will be "This table contains {itemCount} rows."
*/
tableCaption: string;
tableCaption?: string;
searchFilters?: SearchFilterConfig[];
}

Expand Down Expand Up @@ -445,6 +445,7 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
defaultQuery: this.state.filter,
box: {
incremental: true,
'data-test-subj': 'tableListSearchBox',
},
filters: searchFilters ?? [],
};
Expand Down
4 changes: 1 addition & 3 deletions test/functional/page_objects/dashboard_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,7 @@ export function DashboardPageProvider({ getService, getPageObjects }: FtrProvide
*/
public async onDashboardLandingPage() {
log.debug(`onDashboardLandingPage`);
return await testSubjects.exists('dashboardLandingPage', {
timeout: 5000,
});
return await listingTable.onListingPage('dashboard');
}

public async expectExistsDashboardLandingPage() {
Expand Down
31 changes: 13 additions & 18 deletions test/functional/services/listing_table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,19 @@
import expect from '@kbn/expect';
import { FtrProviderContext } from '../ftr_provider_context';

type AppName = 'visualize' | 'dashboard' | 'map';

export function ListingTableProvider({ getService, getPageObjects }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const find = getService('find');
const log = getService('log');
const retry = getService('retry');
const { common, header } = getPageObjects(['common', 'header']);
const prefixMap = { visualize: 'vis', dashboard: 'dashboard' };
const prefixMap = { visualize: 'vis', dashboard: 'dashboard', map: 'map' };

/**
* This class provides functions for dashboard and visualize landing pages
*/
class ListingTable {
private async getSearchFilter() {
const searchFilter = await find.allByCssSelector('main .euiFieldSearch');
return searchFilter[0];
return await testSubjects.find('tableListSearchBox');
}

/**
Expand Down Expand Up @@ -86,9 +84,8 @@ export function ListingTableProvider({ getService, getPageObjects }: FtrProvider

/**
* Returns items count on landing page
* @param appName 'visualize' | 'dashboard'
*/
public async expectItemsCount(appName: 'visualize' | 'dashboard', count: number) {
public async expectItemsCount(appName: AppName, count: number) {
await retry.try(async () => {
const elements = await find.allByCssSelector(
`[data-test-subj^="${prefixMap[appName]}ListingTitleLink"]`
Expand Down Expand Up @@ -126,14 +123,8 @@ export function ListingTableProvider({ getService, getPageObjects }: FtrProvider

/**
* Searches for item on Landing page and retruns items count that match `ListingTitleLink-${name}` pattern
* @param appName 'visualize' | 'dashboard'
* @param name item name
*/
public async searchAndExpectItemsCount(
appName: 'visualize' | 'dashboard',
name: string,
count: number
) {
public async searchAndExpectItemsCount(appName: AppName, name: string, count: number) {
await this.searchForItemWithName(name);
await retry.try(async () => {
const links = await testSubjects.findAll(
Expand Down Expand Up @@ -165,10 +156,8 @@ export function ListingTableProvider({ getService, getPageObjects }: FtrProvider

/**
* Clicks item on Landing page by link name if it is present
* @param appName 'dashboard' | 'visualize'
* @param name item name
*/
public async clickItemLink(appName: 'dashboard' | 'visualize', name: string) {
public async clickItemLink(appName: AppName, name: string) {
await testSubjects.click(
`${prefixMap[appName]}ListingTitleLink-${name.split(' ').join('-')}`
);
Expand Down Expand Up @@ -204,6 +193,12 @@ export function ListingTableProvider({ getService, getPageObjects }: FtrProvider
}
});
}

public async onListingPage(appName: AppName) {
return await testSubjects.exists(`${appName}LandingPage`, {
timeout: 5000,
});
}
}

return new ListingTable();
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"savedObjects",
"share"
],
"optionalPlugins": ["home"],
"optionalPlugins": ["home", "savedObjectsTagging"],
"ui": true,
"server": true,
"extraPublicDirs": ["common/constants"],
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/maps/public/kibana_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const getCoreI18n = () => coreStart.i18n;
export const getSearchService = () => pluginsStart.data.search;
export const getEmbeddableService = () => pluginsStart.embeddable;
export const getNavigateToApp = () => coreStart.application.navigateToApp;
export const getSavedObjectsTagging = () => pluginsStart.savedObjectsTagging;

// xpack.maps.* kibana.yml settings from this plugin
let mapAppConfig: MapsConfigType;
Expand Down
32 changes: 19 additions & 13 deletions x-pack/plugins/maps/public/map_attribute_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { SavedObjectReference } from 'src/core/types';
import { AttributeService } from '../../../../src/plugins/embeddable/public';
import { MapSavedObjectAttributes } from '../common/map_saved_object_type';
import { MAP_SAVED_OBJECT_TYPE } from '../common/constants';
Expand All @@ -14,11 +15,9 @@ import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './
import { extractReferences, injectReferences } from '../common/migrations/references';
import { MapByValueInput, MapByReferenceInput } from './embeddable/types';

export type MapAttributeService = AttributeService<
MapSavedObjectAttributes,
MapByValueInput,
MapByReferenceInput
>;
type MapDoc = MapSavedObjectAttributes & { references?: SavedObjectReference[] };

export type MapAttributeService = AttributeService<MapDoc, MapByValueInput, MapByReferenceInput>;

let mapAttributeService: MapAttributeService | null = null;

Expand All @@ -28,30 +27,37 @@ export function getMapAttributeService(): MapAttributeService {
}

mapAttributeService = getEmbeddableService().getAttributeService<
MapSavedObjectAttributes,
MapDoc,
MapByValueInput,
MapByReferenceInput
>(MAP_SAVED_OBJECT_TYPE, {
saveMethod: async (attributes: MapSavedObjectAttributes, savedObjectId?: string) => {
const { attributes: attributesWithExtractedReferences, references } = extractReferences({
attributes,
saveMethod: async (attributes: MapDoc, savedObjectId?: string) => {
// AttributeService "attributes" contains "references" as a child.
// SavedObjectClient "attributes" uses "references" as a sibling.
// https://github.com/elastic/kibana/issues/83133
const savedObjectClientReferences = attributes.references;
const savedObjectClientAttributes = { ...attributes };
delete savedObjectClientAttributes.references;
const { attributes: updatedAttributes, references } = extractReferences({
attributes: savedObjectClientAttributes,
references: savedObjectClientReferences,
});

const savedObject = await (savedObjectId
? getSavedObjectsClient().update<MapSavedObjectAttributes>(
MAP_SAVED_OBJECT_TYPE,
savedObjectId,
attributesWithExtractedReferences,
updatedAttributes,
{ references }
)
: getSavedObjectsClient().create<MapSavedObjectAttributes>(
MAP_SAVED_OBJECT_TYPE,
attributesWithExtractedReferences,
updatedAttributes,
{ references }
));
return { id: savedObject.id };
},
unwrapMethod: async (savedObjectId: string): Promise<MapSavedObjectAttributes> => {
unwrapMethod: async (savedObjectId: string): Promise<MapDoc> => {
const savedObject = await getSavedObjectsClient().get<MapSavedObjectAttributes>(
MAP_SAVED_OBJECT_TYPE,
savedObjectId
Expand All @@ -62,7 +68,7 @@ export function getMapAttributeService(): MapAttributeService {
}

const { attributes } = injectReferences(savedObject);
return attributes;
return { ...attributes, references: savedObject.references };
},
checkForDuplicateTitle: (props: OnSaveProps) => {
return checkForDuplicateTitle(
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/maps/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
setLicensingPluginStart,
} from './licensed_features';
import { EMSSettings } from '../common/ems_settings';
import { SavedObjectTaggingPluginStart } from '../../saved_objects_tagging/public';

export interface MapsPluginSetupDependencies {
inspector: InspectorSetupContract;
Expand All @@ -86,6 +87,7 @@ export interface MapsPluginStartDependencies {
visualizations: VisualizationsStart;
savedObjects: SavedObjectsStart;
dashboard: DashboardStart;
savedObjectsTagging?: SavedObjectTaggingPluginStart;
}

/**
Expand Down
Loading

0 comments on commit 170f479

Please sign in to comment.