Skip to content

Commit c046e68

Browse files
[Save Object Aggregation View] Fix for export all after scroll count response changed in PR#2656 (#2696) (#2730)
* Fix for filterSavedObjectCounts for namespaceRegistry Signed-off-by: Craig Perkins <[email protected]> * Fix saved_objects_table.test.tsx Signed-off-by: Craig Perkins <[email protected]> * Add to CHANGELOG Signed-off-by: Craig Perkins <[email protected]> * Correct reference to namespacesToInclude Signed-off-by: Craig Perkins <[email protected]> * Use filteredTypeCounts Signed-off-by: Craig Perkins <[email protected]> * Use namespaces similar to types for fetchObjects Signed-off-by: Craig Perkins <[email protected]> * Use _all to represent query for all namespaces Signed-off-by: Craig Perkins <[email protected]> * Pass all registered namespaces Signed-off-by: Craig Perkins <[email protected]> * Switch back signature of scroll_count Signed-off-by: Craig Perkins <[email protected]> * Change countOptions to options Signed-off-by: Craig Perkins <[email protected]> * Use not not instead of in Signed-off-by: Craig Perkins <[email protected]> * Filter namespaces to only include namespace that have been registered Signed-off-by: Craig Perkins <[email protected]> * Add filterQuery with tests Signed-off-by: Craig Perkins <[email protected]> * Update license headers and address review comments Signed-off-by: Craig Perkins <[email protected]> Signed-off-by: Craig Perkins <[email protected]> (cherry picked from commit d8f66d3) Co-authored-by: Craig Perkins <[email protected]>
1 parent 0cf0db9 commit c046e68

File tree

9 files changed

+112
-63
lines changed

9 files changed

+112
-63
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
3131
- [Vis Builder] Rename wizard to visBuilder in class name, type name and function name ([#2639](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2639))
3232
- [Vis Builder] Rename wizard on save modal and visualization table ([#2645](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2645))
3333
- Change save object type, wizard id and name to visBuilder #2673 ([#2673](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2673))
34-
- Add extension point in saved object management to register namespaces and show filter ([#2656](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2656))
3534
- [Multi DataSource] Update MD data source documentation link ([#2693](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2693))
35+
- [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))
36+
- [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))
3637

3738
### 🐛 Bug Fixes
3839
* [Vis Builder] Fixes auto bounds for timeseries bar chart visualization ([2401](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2401))
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { filterQuery } from './filter_query';
7+
8+
describe('filterQuery', () => {
9+
it('should return full list of allowed vals, requested values unspecified', () => {
10+
const allowedVals = ['config', 'index-pattern', 'url', 'query'];
11+
const requestedVals = undefined;
12+
13+
const expected = ['config', 'index-pattern', 'url', 'query'];
14+
expect(filterQuery(allowedVals, requestedVals)).toEqual(expected);
15+
});
16+
17+
it('should return list of all requested values, all values within allowed values', () => {
18+
const allowedVals = ['config', 'index-pattern', 'url', 'query'];
19+
const requestedVals = ['config', 'index-pattern'];
20+
21+
const expected = ['config', 'index-pattern'];
22+
expect(filterQuery(allowedVals, requestedVals)).toEqual(expected);
23+
});
24+
25+
it('should return only allowed values within requested values', () => {
26+
const allowedVals = ['config', 'index-pattern', 'url', 'query'];
27+
const requestedVals = ['config', 'index-pattern', 'forbidden'];
28+
29+
const expected = ['config', 'index-pattern'];
30+
expect(filterQuery(allowedVals, requestedVals)).toEqual(expected);
31+
});
32+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export function filterQuery(allowedVals: string[], requestedVals?: string[]): string[] {
7+
const filteredVals = requestedVals
8+
? allowedVals.filter((val) => requestedVals.includes(val))
9+
: allowedVals;
10+
return filteredVals;
11+
}

src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,18 @@
3030

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

33+
export interface SavedObjectCountOptions {
34+
typesToInclude: string[];
35+
namespacesToInclude?: string[];
36+
searchString?: string;
37+
}
38+
3339
export async function getSavedObjectCounts(
3440
http: HttpStart,
35-
typesToInclude: string[],
36-
namespacesToInclude: string[],
37-
searchString?: string
41+
options: SavedObjectCountOptions
3842
): Promise<Record<string, number>> {
3943
return await http.post<Record<string, number>>(
4044
`/api/opensearch-dashboards/management/saved_objects/scroll/counts`,
41-
{ body: JSON.stringify({ typesToInclude, namespacesToInclude, searchString }) }
45+
{ body: JSON.stringify(options) }
4246
);
4347
}

src/plugins/saved_objects_management/public/lib/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export { fetchExportByTypeAndSearch } from './fetch_export_by_type_and_search';
3232
export { fetchExportObjects } from './fetch_export_objects';
3333
export { canViewInApp } from './in_app_url';
3434
export { getRelationships } from './get_relationships';
35-
export { getSavedObjectCounts } from './get_saved_object_counts';
35+
export { getSavedObjectCounts, SavedObjectCountOptions } from './get_saved_object_counts';
3636
export { getSavedObjectLabel } from './get_saved_object_label';
3737
export { importFile } from './import_file';
3838
export { importLegacyFile } from './import_legacy_file';
@@ -56,3 +56,4 @@ export { findObjects, findObject } from './find_objects';
5656
export { extractExportDetails, SavedObjectsExportResultDetails } from './extract_export_details';
5757
export { createFieldList } from './create_field_list';
5858
export { getAllowedTypes } from './get_allowed_types';
59+
export { filterQuery } from './filter_query';

src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,12 @@ describe('SavedObjectsTable', () => {
137137
http.post.mockResolvedValue([]);
138138

139139
getSavedObjectCountsMock.mockReturnValue({
140-
'index-pattern': 0,
141-
visualization: 0,
142-
dashboard: 0,
143-
search: 0,
140+
type: {
141+
'index-pattern': 0,
142+
visualization: 0,
143+
dashboard: 0,
144+
search: 0,
145+
},
144146
});
145147

146148
defaultProps = {

src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,12 @@ import { IndexPatternsContract } from '../../../../data/public';
7171
import {
7272
parseQuery,
7373
getSavedObjectCounts,
74+
SavedObjectCountOptions,
7475
getRelationships,
7576
getSavedObjectLabel,
7677
fetchExportObjects,
7778
fetchExportByTypeAndSearch,
79+
filterQuery,
7880
findObjects,
7981
findObject,
8082
extractExportDetails,
@@ -178,43 +180,57 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
178180
}
179181

180182
fetchCounts = async () => {
181-
const { allowedTypes } = this.props;
183+
const { allowedTypes, namespaceRegistry } = this.props;
182184
const { queryText, visibleTypes, visibleNamespaces } = parseQuery(this.state.activeQuery);
183185

184-
const filteredTypes = allowedTypes.filter(
185-
(type) => !visibleTypes || visibleTypes.includes(type)
186-
);
186+
const filteredTypes = filterQuery(allowedTypes, visibleTypes);
187+
188+
const availableNamespaces = namespaceRegistry.getAll()?.map((ns) => ns.id) || [];
189+
190+
const filteredCountOptions: SavedObjectCountOptions = {
191+
typesToInclude: filteredTypes,
192+
searchString: queryText,
193+
};
194+
195+
if (availableNamespaces.length) {
196+
const filteredNamespaces = filterQuery(availableNamespaces, visibleNamespaces);
197+
filteredCountOptions.namespacesToInclude = filteredNamespaces;
198+
}
187199

188200
// These are the saved objects visible in the table.
189201
const filteredSavedObjectCounts = await getSavedObjectCounts(
190202
this.props.http,
191-
filteredTypes,
192-
visibleNamespaces,
193-
queryText
203+
filteredCountOptions
194204
);
195205

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

199-
Object.keys(filteredSavedObjectCounts).forEach((id) => {
209+
const filteredTypeCounts = filteredSavedObjectCounts.type || {};
210+
211+
Object.keys(filteredTypeCounts).forEach((id) => {
200212
// Add this type as a bulk-export option.
201213
exportAllOptions.push({
202214
id,
203-
label: `${id} (${filteredSavedObjectCounts[id] || 0})`,
215+
label: `${id} (${filteredTypeCounts[id] || 0})`,
204216
});
205217

206218
// Select it by default.
207219
exportAllSelectedOptions[id] = true;
208220
});
209221

222+
const countOptions: SavedObjectCountOptions = {
223+
typesToInclude: allowedTypes,
224+
searchString: queryText,
225+
};
226+
227+
if (availableNamespaces.length) {
228+
countOptions.namespacesToInclude = availableNamespaces;
229+
}
230+
210231
// Fetch all the saved objects that exist so we can accurately populate the counts within
211232
// the table filter dropdown.
212-
const savedObjectCounts = await getSavedObjectCounts(
213-
this.props.http,
214-
allowedTypes,
215-
[],
216-
queryText
217-
);
233+
const savedObjectCounts = await getSavedObjectCounts(this.props.http, countOptions);
218234

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

235251
debouncedFetchObjects = debounce(async () => {
236252
const { activeQuery: query, page, perPage } = this.state;
237-
const { notifications, http, allowedTypes } = this.props;
253+
const { notifications, http, allowedTypes, namespaceRegistry } = this.props;
238254
const { queryText, visibleTypes, visibleNamespaces } = parseQuery(query);
239-
const filteredTypes = allowedTypes.filter(
240-
(type) => !visibleTypes || visibleTypes.includes(type)
241-
);
255+
const filteredTypes = filterQuery(allowedTypes, visibleTypes);
242256
// "searchFields" is missing from the "findOptions" but gets injected via the API.
243257
// The API extracts the fields from each uiExports.savedObjectsManagement "defaultSearchField" attribute
244258
const findOptions: SavedObjectsFindOptions = {
@@ -247,8 +261,14 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
247261
page: page + 1,
248262
fields: ['id'],
249263
type: filteredTypes,
250-
namespaces: visibleNamespaces,
251264
};
265+
266+
const availableNamespaces = namespaceRegistry.getAll()?.map((ns) => ns.id) || [];
267+
if (availableNamespaces.length) {
268+
const filteredNamespaces = filterQuery(availableNamespaces, visibleNamespaces);
269+
findOptions.namespaces = filteredNamespaces;
270+
}
271+
252272
if (findOptions.type.length > 1) {
253273
findOptions.sortField = 'type';
254274
}
@@ -803,7 +823,7 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
803823
];
804824

805825
const availableNamespaces = namespaceRegistry.getAll() || [];
806-
if (availableNamespaces && availableNamespaces.length > 0) {
826+
if (availableNamespaces.length) {
807827
const nsCounts = savedObjectCounts.namespaces || {};
808828
const nsFilterOptions = availableNamespaces.map((ns) => {
809829
return {

src/plugins/saved_objects_management/server/routes/find.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,6 @@ export const registerFindRoute = (
6969
const managementService = await managementServicePromise;
7070
const { client } = context.core.savedObjects;
7171
const searchTypes = Array.isArray(req.query.type) ? req.query.type : [req.query.type];
72-
if ('namespaces' in req.query) {
73-
const namespacesToInclude = Array.isArray(req.query.namespaces)
74-
? req.query.namespaces
75-
: [req.query.namespaces];
76-
const searchNamespaces = [];
77-
namespacesToInclude.forEach((ns) => {
78-
if (ns == null) {
79-
searchNamespaces.push('default');
80-
} else {
81-
searchNamespaces.push(ns);
82-
}
83-
});
84-
req.query.namespaces = searchNamespaces;
85-
}
8672
const includedFields = Array.isArray(req.query.fields)
8773
? req.query.fields
8874
: [req.query.fields];

src/plugins/saved_objects_management/server/routes/scroll_count.ts

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,21 @@ export const registerScrollForCountRoute = (router: IRouter) => {
4646
},
4747
router.handleLegacyErrors(async (context, req, res) => {
4848
const { client } = context.core.savedObjects;
49-
const namespaces = [];
50-
if (req.body.namespacesToInclude && req.body.namespacesToInclude.length > 0) {
51-
req.body.namespacesToInclude.forEach((ns) => {
52-
if (ns === null) {
53-
namespaces.push('default');
54-
} else {
55-
namespaces.push(ns);
56-
}
57-
});
58-
}
49+
const counts = {
50+
type: {},
51+
};
5952

6053
const findOptions: SavedObjectsFindOptions = {
6154
type: req.body.typesToInclude,
6255
perPage: 1000,
6356
};
6457

65-
if (namespaces.length > 0) {
66-
findOptions.namespaces = namespaces;
58+
const requestHasNamespaces =
59+
Array.isArray(req.body.namespacesToInclude) && req.body.namespacesToInclude.length;
60+
61+
if (requestHasNamespaces) {
62+
counts.namespaces = {};
63+
findOptions.namespaces = req.body.namespacesToInclude;
6764
}
6865

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

7471
const objects = await findAll(client, findOptions);
7572

76-
const counts = {
77-
type: {},
78-
namespaces: {},
79-
};
80-
8173
objects.forEach((result) => {
8274
const type = result.type;
83-
if (req.body.namespacesToInclude) {
75+
if (requestHasNamespaces) {
8476
const resultNamespaces = (result.namespaces || []).flat();
8577
resultNamespaces.forEach((ns) => {
8678
if (ns === null) {

0 commit comments

Comments
 (0)