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

[Backport 2.4] [Save Object Aggregation View] Fix for export all after scroll count response changed in PR#2656 #2733

Merged
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Vis Builder] Rename wizard to visBuilder in class name, type name and function name ([#2639](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2639))
- [Vis Builder] Rename wizard on save modal and visualization table ([#2645](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2645))
- 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))
- [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
* [Vis Builder] Fixes auto bounds for timeseries bar chart visualization ([2401](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2401))
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