Skip to content

Commit

Permalink
[Save Object Aggregation View] Fix for export all after scroll count …
Browse files Browse the repository at this point in the history
…response changed in PR#2656 (#2696)

* Fix for filterSavedObjectCounts for namespaceRegistry

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Fix saved_objects_table.test.tsx

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Add to CHANGELOG

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Correct reference to namespacesToInclude

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Use filteredTypeCounts

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Use namespaces similar to types for fetchObjects

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Use _all to represent query for all namespaces

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Pass all registered namespaces

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Switch back signature of scroll_count

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Change countOptions to options

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Use not not instead of in

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Filter namespaces to only include namespace that have been registered

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Add filterQuery with tests

Signed-off-by: Craig Perkins <cwperx@amazon.com>

* Update license headers and address review comments

Signed-off-by: Craig Perkins <cwperx@amazon.com>

Signed-off-by: Craig Perkins <cwperx@amazon.com>
  • Loading branch information
cwperks authored Nov 2, 2022
1 parent e35384e commit d8f66d3
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 63 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Vis Builder] Rename wizard on save modal and visualization table ([#2645](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2645))
- [Vis Builder] Enable VisBuilder by default ([#2725](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2725))
- Change save object type, wizard id and name to visBuilder #2673 ([#2673](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2673))
- Add extension point in saved object management to register namespaces and show filter ([#2656](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2656))
- [Multi DataSource] Update MD data source documentation link ([#2693](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2693))
- [Save Object Aggregation View] Add extension point in saved object management to register namespaces and show filter ([#2656](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2656))
- [Save Object Aggregation View] Fix for export all after scroll count response changed in PR#2656 ([#2696](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2696))

### 🐛 Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { filterQuery } from './filter_query';

describe('filterQuery', () => {
it('should return full list of allowed vals, requested values unspecified', () => {
const allowedVals = ['config', 'index-pattern', 'url', 'query'];
const requestedVals = undefined;

const expected = ['config', 'index-pattern', 'url', 'query'];
expect(filterQuery(allowedVals, requestedVals)).toEqual(expected);
});

it('should return list of all requested values, all values within allowed values', () => {
const allowedVals = ['config', 'index-pattern', 'url', 'query'];
const requestedVals = ['config', 'index-pattern'];

const expected = ['config', 'index-pattern'];
expect(filterQuery(allowedVals, requestedVals)).toEqual(expected);
});

it('should return only allowed values within requested values', () => {
const allowedVals = ['config', 'index-pattern', 'url', 'query'];
const requestedVals = ['config', 'index-pattern', 'forbidden'];

const expected = ['config', 'index-pattern'];
expect(filterQuery(allowedVals, requestedVals)).toEqual(expected);
});
});
11 changes: 11 additions & 0 deletions src/plugins/saved_objects_management/public/lib/filter_query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export function filterQuery(allowedVals: string[], requestedVals?: string[]): string[] {
const filteredVals = requestedVals
? allowedVals.filter((val) => requestedVals.includes(val))
: allowedVals;
return filteredVals;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@

import { HttpStart } from 'src/core/public';

export interface SavedObjectCountOptions {
typesToInclude: string[];
namespacesToInclude?: string[];
searchString?: string;
}

export async function getSavedObjectCounts(
http: HttpStart,
typesToInclude: string[],
namespacesToInclude: string[],
searchString?: string
options: SavedObjectCountOptions
): Promise<Record<string, number>> {
return await http.post<Record<string, number>>(
`/api/opensearch-dashboards/management/saved_objects/scroll/counts`,
{ body: JSON.stringify({ typesToInclude, namespacesToInclude, searchString }) }
{ body: JSON.stringify(options) }
);
}
3 changes: 2 additions & 1 deletion src/plugins/saved_objects_management/public/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export { fetchExportByTypeAndSearch } from './fetch_export_by_type_and_search';
export { fetchExportObjects } from './fetch_export_objects';
export { canViewInApp } from './in_app_url';
export { getRelationships } from './get_relationships';
export { getSavedObjectCounts } from './get_saved_object_counts';
export { getSavedObjectCounts, SavedObjectCountOptions } from './get_saved_object_counts';
export { getSavedObjectLabel } from './get_saved_object_label';
export { importFile } from './import_file';
export { importLegacyFile } from './import_legacy_file';
Expand All @@ -56,3 +56,4 @@ export { findObjects, findObject } from './find_objects';
export { extractExportDetails, SavedObjectsExportResultDetails } from './extract_export_details';
export { createFieldList } from './create_field_list';
export { getAllowedTypes } from './get_allowed_types';
export { filterQuery } from './filter_query';
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,12 @@ describe('SavedObjectsTable', () => {
http.post.mockResolvedValue([]);

getSavedObjectCountsMock.mockReturnValue({
'index-pattern': 0,
visualization: 0,
dashboard: 0,
search: 0,
type: {
'index-pattern': 0,
visualization: 0,
dashboard: 0,
search: 0,
},
});

defaultProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ import { IndexPatternsContract } from '../../../../data/public';
import {
parseQuery,
getSavedObjectCounts,
SavedObjectCountOptions,
getRelationships,
getSavedObjectLabel,
fetchExportObjects,
fetchExportByTypeAndSearch,
filterQuery,
findObjects,
findObject,
extractExportDetails,
Expand Down Expand Up @@ -178,43 +180,57 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
}

fetchCounts = async () => {
const { allowedTypes } = this.props;
const { allowedTypes, namespaceRegistry } = this.props;
const { queryText, visibleTypes, visibleNamespaces } = parseQuery(this.state.activeQuery);

const filteredTypes = allowedTypes.filter(
(type) => !visibleTypes || visibleTypes.includes(type)
);
const filteredTypes = filterQuery(allowedTypes, visibleTypes);

const availableNamespaces = namespaceRegistry.getAll()?.map((ns) => ns.id) || [];

const filteredCountOptions: SavedObjectCountOptions = {
typesToInclude: filteredTypes,
searchString: queryText,
};

if (availableNamespaces.length) {
const filteredNamespaces = filterQuery(availableNamespaces, visibleNamespaces);
filteredCountOptions.namespacesToInclude = filteredNamespaces;
}

// These are the saved objects visible in the table.
const filteredSavedObjectCounts = await getSavedObjectCounts(
this.props.http,
filteredTypes,
visibleNamespaces,
queryText
filteredCountOptions
);

const exportAllOptions: ExportAllOption[] = [];
const exportAllSelectedOptions: Record<string, boolean> = {};

Object.keys(filteredSavedObjectCounts).forEach((id) => {
const filteredTypeCounts = filteredSavedObjectCounts.type || {};

Object.keys(filteredTypeCounts).forEach((id) => {
// Add this type as a bulk-export option.
exportAllOptions.push({
id,
label: `${id} (${filteredSavedObjectCounts[id] || 0})`,
label: `${id} (${filteredTypeCounts[id] || 0})`,
});

// Select it by default.
exportAllSelectedOptions[id] = true;
});

const countOptions: SavedObjectCountOptions = {
typesToInclude: allowedTypes,
searchString: queryText,
};

if (availableNamespaces.length) {
countOptions.namespacesToInclude = availableNamespaces;
}

// Fetch all the saved objects that exist so we can accurately populate the counts within
// the table filter dropdown.
const savedObjectCounts = await getSavedObjectCounts(
this.props.http,
allowedTypes,
[],
queryText
);
const savedObjectCounts = await getSavedObjectCounts(this.props.http, countOptions);

this.setState((state) => ({
...state,
Expand All @@ -234,11 +250,9 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb

debouncedFetchObjects = debounce(async () => {
const { activeQuery: query, page, perPage } = this.state;
const { notifications, http, allowedTypes } = this.props;
const { notifications, http, allowedTypes, namespaceRegistry } = this.props;
const { queryText, visibleTypes, visibleNamespaces } = parseQuery(query);
const filteredTypes = allowedTypes.filter(
(type) => !visibleTypes || visibleTypes.includes(type)
);
const filteredTypes = filterQuery(allowedTypes, visibleTypes);
// "searchFields" is missing from the "findOptions" but gets injected via the API.
// The API extracts the fields from each uiExports.savedObjectsManagement "defaultSearchField" attribute
const findOptions: SavedObjectsFindOptions = {
Expand All @@ -247,8 +261,14 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
page: page + 1,
fields: ['id'],
type: filteredTypes,
namespaces: visibleNamespaces,
};

const availableNamespaces = namespaceRegistry.getAll()?.map((ns) => ns.id) || [];
if (availableNamespaces.length) {
const filteredNamespaces = filterQuery(availableNamespaces, visibleNamespaces);
findOptions.namespaces = filteredNamespaces;
}

if (findOptions.type.length > 1) {
findOptions.sortField = 'type';
}
Expand Down Expand Up @@ -803,7 +823,7 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
];

const availableNamespaces = namespaceRegistry.getAll() || [];
if (availableNamespaces && availableNamespaces.length > 0) {
if (availableNamespaces.length) {
const nsCounts = savedObjectCounts.namespaces || {};
const nsFilterOptions = availableNamespaces.map((ns) => {
return {
Expand Down
14 changes: 0 additions & 14 deletions src/plugins/saved_objects_management/server/routes/find.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,6 @@ export const registerFindRoute = (
const managementService = await managementServicePromise;
const { client } = context.core.savedObjects;
const searchTypes = Array.isArray(req.query.type) ? req.query.type : [req.query.type];
if ('namespaces' in req.query) {
const namespacesToInclude = Array.isArray(req.query.namespaces)
? req.query.namespaces
: [req.query.namespaces];
const searchNamespaces = [];
namespacesToInclude.forEach((ns) => {
if (ns == null) {
searchNamespaces.push('default');
} else {
searchNamespaces.push(ns);
}
});
req.query.namespaces = searchNamespaces;
}
const includedFields = Array.isArray(req.query.fields)
? req.query.fields
: [req.query.fields];
Expand Down
28 changes: 10 additions & 18 deletions src/plugins/saved_objects_management/server/routes/scroll_count.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,21 @@ export const registerScrollForCountRoute = (router: IRouter) => {
},
router.handleLegacyErrors(async (context, req, res) => {
const { client } = context.core.savedObjects;
const namespaces = [];
if (req.body.namespacesToInclude && req.body.namespacesToInclude.length > 0) {
req.body.namespacesToInclude.forEach((ns) => {
if (ns === null) {
namespaces.push('default');
} else {
namespaces.push(ns);
}
});
}
const counts = {
type: {},
};

const findOptions: SavedObjectsFindOptions = {
type: req.body.typesToInclude,
perPage: 1000,
};

if (namespaces.length > 0) {
findOptions.namespaces = namespaces;
const requestHasNamespaces =
Array.isArray(req.body.namespacesToInclude) && req.body.namespacesToInclude.length;

if (requestHasNamespaces) {
counts.namespaces = {};
findOptions.namespaces = req.body.namespacesToInclude;
}

if (req.body.searchString) {
Expand All @@ -73,14 +70,9 @@ export const registerScrollForCountRoute = (router: IRouter) => {

const objects = await findAll(client, findOptions);

const counts = {
type: {},
namespaces: {},
};

objects.forEach((result) => {
const type = result.type;
if (req.body.namespacesToInclude) {
if (requestHasNamespaces) {
const resultNamespaces = (result.namespaces || []).flat();
resultNamespaces.forEach((ns) => {
if (ns === null) {
Expand Down

0 comments on commit d8f66d3

Please sign in to comment.