Skip to content

Commit

Permalink
[Discover][Bug] Migrate global state from legacy URL (#6780)
Browse files Browse the repository at this point in the history
* [Discover][Bug] Migrate global state

Issue Resolve
#6766

---------

Signed-off-by: Anan Zhuang <[email protected]>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
ananzh and opensearch-changeset-bot[bot] authored Jun 4, 2024
1 parent 016dcfd commit c6820db
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 0 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/6780.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fix:
- [Discover][Bug] Migrate global state from legacy URL ([#6780](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6780))
2 changes: 2 additions & 0 deletions src/plugins/discover/public/migrate_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ export function migrateUrlState(oldPath: string, newPath = '/'): string {
indexPattern: index,
},
};
const _g = getStateFromOsdUrl<any>('_g', oldPath);

path = setStateToOsdUrl('_g', _g, { useHash: false }, path);
path = setStateToOsdUrl('_a', _a, { useHash: false }, path);
path = setStateToOsdUrl('_q', _q, { useHash: false }, path);

Expand Down
196 changes: 196 additions & 0 deletions src/plugins/discover/public/migrate_states.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { migrateUrlState } from './migrate_state';
import { setStateToOsdUrl, getStateFromOsdUrl } from '../../opensearch_dashboards_utils/public';

jest.mock('../../opensearch_dashboards_utils/public', () => ({
setStateToOsdUrl: jest.fn(),
getStateFromOsdUrl: jest.fn(),
}));

describe('migrateUrlState', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should return the new path if no matching pattern', () => {
const result = migrateUrlState('#/unknown', '/newPath');
expect(result).toBe('/newPath');
});

it('should migrate doc view', () => {
const result = migrateUrlState('#/doc/indexPattern/id', '/newPath');
expect(result).toBe('#/doc/indexPattern/id');
});

it('should migrate context view', () => {
const result = migrateUrlState('#/context/indexPattern/id', '/newPath');
expect(result).toBe('#/context/indexPattern/id');
});

it('should migrate discover view with saved search id and with global state', () => {
(getStateFromOsdUrl as jest.Mock).mockImplementation((key) => {
if (key === '_a') {
return {
columns: ['column1'],
filters: [],
index: 'indexPattern',
interval: 'auto',
query: { language: 'kuery', query: 'test' },
sort: [['field', 'desc']],
savedQuery: 'savedQueryId',
};
}
if (key === '_g') {
return {
time: { from: 'now-15m', to: 'now' },
filters: [],
refreshInterval: { pause: true, value: 0 },
};
}
return null;
});

(setStateToOsdUrl as jest.Mock).mockImplementation((key, state, options, rawUrl) => {
const query = new URLSearchParams(rawUrl.split('?')[1] || '');
query.set(key, JSON.stringify(state)); // Simplified encoding
return `${rawUrl.split('?')[0]}?${query.toString()}`;
});

const result = migrateUrlState('#/view/savedSearchId', '/newPath');
const decodedResult = decodeURIComponent(result);
const expectedPath =
'/newPath#/view/savedSearchId?_g={"time":{"from":"now-15m","to":"now"},"filters":[],"refreshInterval":{"pause":true,"value":0}}&_a={"discover":{"columns":["column1"],"interval":"auto","sort":[["field","desc"]],"savedQuery":"savedQueryId"},"metadata":{"indexPattern":"indexPattern"}}&_q={"query":{"language":"kuery","query":"test"},"filters":[]}';
expect(decodedResult).toBe(expectedPath);
});

it('should migrate discover view without saved search id and with global state', () => {
(getStateFromOsdUrl as jest.Mock).mockImplementation((key) => {
if (key === '_a') {
return {
columns: ['column1'],
filters: [],
index: 'indexPattern',
interval: 'auto',
query: { language: 'kuery', query: 'test' },
sort: [['field', 'desc']],
savedQuery: 'savedQueryId',
};
}
if (key === '_g') {
return {
time: { from: 'now-15m', to: 'now' },
filters: [],
refreshInterval: { pause: true, value: 0 },
};
}
return null;
});

const result = migrateUrlState('#/', '/newPath');
const decodedResult = decodeURIComponent(result);
const expectedPath =
'/newPath?_g={"time":{"from":"now-15m","to":"now"},"filters":[],"refreshInterval":{"pause":true,"value":0}}&_a={"discover":{"columns":["column1"],"interval":"auto","sort":[["field","desc"]],"savedQuery":"savedQueryId"},"metadata":{"indexPattern":"indexPattern"}}&_q={"query":{"language":"kuery","query":"test"},"filters":[]}';
expect(decodedResult).toBe(expectedPath);
});

it('should migrate discover view without saved search id and without global state', () => {
(getStateFromOsdUrl as jest.Mock).mockImplementation((key) => {
if (key === '_a') {
return {
columns: ['column1'],
filters: [],
index: 'indexPattern',
interval: 'auto',
query: { language: 'kuery', query: 'test' },
sort: [['field', 'desc']],
savedQuery: 'savedQueryId',
};
}
return null;
});

(setStateToOsdUrl as jest.Mock).mockImplementation((key, state, options, rawUrl) => {
const query = new URLSearchParams(rawUrl.split('?')[1] || '');
query.set(key, JSON.stringify(state)); // Simplified encoding
return `${rawUrl.split('?')[0]}?${query.toString()}`;
});

const result = migrateUrlState('#/', '/newPath');
const decodedResult = decodeURIComponent(result);
const expectedPath =
'/newPath?_g=null&_a={"discover":{"columns":["column1"],"interval":"auto","sort":[["field","desc"]],"savedQuery":"savedQueryId"},"metadata":{"indexPattern":"indexPattern"}}&_q={"query":{"language":"kuery","query":"test"},"filters":[]}';
expect(decodedResult).toBe(expectedPath);
});

it('should return the new path if appState is null', () => {
(getStateFromOsdUrl as jest.Mock).mockImplementation((key) => {
if (key === '_a') {
return null;
}
return null;
});

const result = migrateUrlState('#/view/savedSearchId', '/newPath');
expect(result).toBe('/newPath#/view/savedSearchId');
});

it('should handle missing global state to null', () => {
(getStateFromOsdUrl as jest.Mock).mockImplementation((key) => {
if (key === '_a') {
return {
columns: ['column1'],
filters: [],
index: 'indexPattern',
interval: 'auto',
query: { language: 'kuery', query: 'test' },
sort: [['field', 'desc']],
savedQuery: 'savedQueryId',
};
}
if (key === '_g') {
return null;
}
return null;
});

const result = migrateUrlState('#/view/savedSearchId', '/newPath');
const decodedResult = decodeURIComponent(result);
const expectedPath =
'/newPath#/view/savedSearchId?_g=null&_a={"discover":{"columns":["column1"],"interval":"auto","sort":[["field","desc"]],"savedQuery":"savedQueryId"},"metadata":{"indexPattern":"indexPattern"}}&_q={"query":{"language":"kuery","query":"test"},"filters":[]}';
expect(decodedResult).toBe(expectedPath);
});

it('should handle present global state', () => {
(getStateFromOsdUrl as jest.Mock).mockImplementation((key) => {
if (key === '_a') {
return {
columns: ['column1'],
filters: [],
index: 'indexPattern',
interval: 'auto',
query: { language: 'kuery', query: 'test' },
sort: [['field', 'desc']],
savedQuery: 'savedQueryId',
};
}
if (key === '_g') {
return {
time: { from: 'now-15m', to: 'now' },
filters: [],
refreshInterval: { pause: true, value: 0 },
};
}
return null;
});

const result = migrateUrlState('#/view/savedSearchId', '/newPath');
const decodedResult = decodeURIComponent(result);
const expectedPath =
'/newPath#/view/savedSearchId?_g={"time":{"from":"now-15m","to":"now"},"filters":[],"refreshInterval":{"pause":true,"value":0}}&_a={"discover":{"columns":["column1"],"interval":"auto","sort":[["field","desc"]],"savedQuery":"savedQueryId"},"metadata":{"indexPattern":"indexPattern"}}&_q={"query":{"language":"kuery","query":"test"},"filters":[]}';
expect(decodedResult).toBe(expectedPath);
});
});

0 comments on commit c6820db

Please sign in to comment.