diff --git a/package.json b/package.json index eb2206dfcf21..1e66bbfbd290 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "bugs": { "url": "http://github.com/opensearch-project/OpenSearch-Dashboards/issues" }, + "packageManager": "yarn@1.22.19", "opensearchDashboards": { "clean": { "extraPatterns": [ @@ -158,6 +159,9 @@ "JSONStream": "1.3.5", "abortcontroller-polyfill": "^1.4.0", "ajv": "^8.11.0", + "angular": "^1.8.2", + "angular-elastic": "^2.5.1", + "angular-sanitize": "^1.8.0", "bluebird": "3.5.5", "chalk": "^4.1.0", "chokidar": "^3.4.2", @@ -259,6 +263,8 @@ "@testing-library/jest-dom": "^5.16.2", "@testing-library/react": "^12.1.2", "@testing-library/react-hooks": "^7.0.2", + "@types/angular": "^1.8.4", + "@types/angular-mocks": "^1.7.1", "@types/archiver": "^5.3.1", "@types/babel__core": "^7.1.17", "@types/bluebird": "^3.1.1", @@ -339,6 +345,10 @@ "@types/zen-observable": "^0.8.0", "@typescript-eslint/eslint-plugin": "^3.10.0", "@typescript-eslint/parser": "^3.10.0", + "angular-aria": "^1.8.0", + "angular-mocks": "^1.8.2", + "angular-recursion": "^1.0.5", + "angular-route": "^1.8.0", "archiver": "^5.3.0", "axe-core": "^4.0.2", "babel-eslint": "^10.0.3", @@ -415,6 +425,7 @@ "ms-chromium-edge-driver": "^0.4.3", "murmurhash3js": "3.0.1", "mutation-observer": "^1.0.3", + "ngreact": "^0.5.1", "nock": "12.0.3", "node-stream-zip": "^1.15.0", "normalize-path": "^3.0.0", @@ -466,4 +477,4 @@ "node": ">=14.20.1 <19", "yarn": "^1.22.10" } -} \ No newline at end of file +} diff --git a/src/plugins/discover/public/application/components/data_grid/data_grid_table.tsx b/src/plugins/discover/public/application/components/data_grid/data_grid_table.tsx index 596e0b97ae07..701b3e296c0f 100644 --- a/src/plugins/discover/public/application/components/data_grid/data_grid_table.tsx +++ b/src/plugins/discover/public/application/components/data_grid/data_grid_table.tsx @@ -32,6 +32,7 @@ export interface DataGridTableProps { services: DiscoverServices; isToolbarVisible?: boolean; isContextView?: boolean; + isLoading?: boolean; } export const DataGridTable = ({ @@ -47,6 +48,7 @@ export const DataGridTable = ({ displayTimeColumn, isToolbarVisible = true, isContextView = false, + isLoading = false, }: DataGridTableProps) => { const [inspectedHit, setInspectedHit] = useState(); const rowCount = useMemo(() => (rows ? rows.length : 0), [rows]); @@ -166,7 +168,7 @@ export const DataGridTable = ({ indexPattern, }} > - <> +
{table} @@ -183,7 +185,7 @@ export const DataGridTable = ({ onClose={() => setInspectedHit(undefined)} /> )} - +
); }; diff --git a/src/plugins/discover/public/embeddable/search_embeddable_component.tsx b/src/plugins/discover/public/embeddable/search_embeddable_component.tsx index c9a08844e9a0..f019d75db116 100644 --- a/src/plugins/discover/public/embeddable/search_embeddable_component.tsx +++ b/src/plugins/discover/public/embeddable/search_embeddable_component.tsx @@ -42,7 +42,12 @@ export function SearchEmbeddableComponent({ searchProps }: SearchEmbeddableProps return ( - + {discoverEmbeddableProps.totalHitCount !== 0 ? ( diff --git a/test/functional/apps/dashboard/dashboard_state.js b/test/functional/apps/dashboard/dashboard_state.js index ed39d5e42680..edb2002624f5 100644 --- a/test/functional/apps/dashboard/dashboard_state.js +++ b/test/functional/apps/dashboard/dashboard_state.js @@ -90,8 +90,11 @@ export default function ({ getService, getPageObjects }) { expect(colorChoiceRetained).to.be(true); }); - // the following three tests are skipped because of save search save window bug: - // https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4698 + // TODO: Revert the following changes on the following 3 saved search tests + // once issue https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5071 is resolved. + // The issue causes the previously saved object to not load automatically when navigating back to discover from the dashboard. + // Currently, we need to re-open the saved search in discover. + // The expected behavior is for the saved object to persist and load as it did in previous versions of discover. it('Saved search with no changes will update when the saved object changes', async () => { await PageObjects.dashboard.gotoDashboardLandingPage(); @@ -111,11 +114,12 @@ export default function ({ getService, getPageObjects }) { expect(inViewMode).to.be(true); await PageObjects.header.clickDiscover(); - // Add load save search here since discover link won't take it to the save search link for - // the legacy discover plugin + // add load save search here since discover link won't take it to the save search link await PageObjects.discover.loadSavedSearch('my search'); + await PageObjects.timePicker.setHistoricalDataRange(); + await PageObjects.discover.clickFieldListItemAdd('agent'); - await PageObjects.discover.saveSearch('my search'); + await PageObjects.discover.saveSearch('my search', false); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.header.clickDashboard(); @@ -133,9 +137,9 @@ export default function ({ getService, getPageObjects }) { await PageObjects.dashboard.saveDashboard('Has local edits'); await PageObjects.header.clickDiscover(); - // Add load save search here since discover link won't take it to the save search link for - // the legacy discover plugin + // add load save search here since discover link won't take it to the save search link await PageObjects.discover.loadSavedSearch('my search'); + await PageObjects.timePicker.setHistoricalDataRange(); await PageObjects.discover.clickFieldListItemAdd('clientip'); await PageObjects.discover.saveSearch('my search'); await PageObjects.header.waitUntilLoadingHasFinished(); @@ -152,9 +156,10 @@ export default function ({ getService, getPageObjects }) { const currentQuery = await queryBar.getQueryString(); expect(currentQuery).to.equal(''); const currentUrl = await browser.getCurrentUrl(); - const newUrl = currentUrl.replace('query:%27%27', 'query:%27abc12345678910%27'); - // Don't add the timestamp to the url or it will cause a hard refresh and we want to test a - // soft refresh. + + // due to previous re-open saved search, history is changed. + // query is in both _g and _a. We need to change query in _a. + const newUrl = currentUrl.replace(/query:%27%27/g, 'query:%27abc12345678910%27'); await browser.get(newUrl.toString(), false); await PageObjects.header.waitUntilLoadingHasFinished(); diff --git a/test/functional/apps/dashboard/dashboard_time_picker.js b/test/functional/apps/dashboard/dashboard_time_picker.js index 5c97872cdb7e..b1e57fbe8e5e 100644 --- a/test/functional/apps/dashboard/dashboard_time_picker.js +++ b/test/functional/apps/dashboard/dashboard_time_picker.js @@ -67,14 +67,15 @@ export default function ({ getService, getPageObjects }) { name: 'saved search', fields: ['bytes', 'agent'], }); - await dashboardExpect.docTableFieldCount(150); + // Current data grid loads 100 rows per page by default with inspect button and time range + await dashboardExpect.dataGridTableCellCount(400); // Set to time range with no data await PageObjects.timePicker.setAbsoluteRange( 'Jan 1, 2000 @ 00:00:00.000', 'Jan 1, 2000 @ 01:00:00.000' ); - await dashboardExpect.docTableFieldCount(0); + await dashboardExpect.dataGridTableCellCount(0); }); it('Timepicker start, end, interval values are set by url', async () => { diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 395980d6c742..aa8635dc8289 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -42,6 +42,7 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider const defaultFindTimeout = config.get('timeouts.find'); const opensearchChart = getService('opensearchChart'); const docTable = getService('docTable'); + const dataGridTable = getService('dataGrid'); /* * This page is left unchanged since some of the other selenium tests, ex. dashboard tests, visualization tests @@ -104,7 +105,7 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider } public async getColumnHeaders() { - return await docTable.getHeaderFields('embeddedSavedSearchDocTable'); + return await dataGridTable.getHeaderFields(); } public async openLoadSavedSearchPanel() { @@ -353,9 +354,8 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider await header.waitUntilLoadingHasFinished(); } - public async removeHeaderColumn(name: string) { - await testSubjects.moveMouseTo(`docTableHeader-${name}`); - await testSubjects.click(`docTableRemoveHeader-${name}`); + public async removeHeaderColumn(columnName: string) { + await dataGridTable.clickRemoveColumn(columnName); } public async openSidebarFieldFilter() { diff --git a/test/functional/services/dashboard/expectations.ts b/test/functional/services/dashboard/expectations.ts index ab6eaed8a9bc..4bdf355eb049 100644 --- a/test/functional/services/dashboard/expectations.ts +++ b/test/functional/services/dashboard/expectations.ts @@ -69,10 +69,10 @@ export function DashboardExpectProvider({ getService, getPageObjects }: FtrProvi }); } - async docTableFieldCount(expectedCount: number) { - log.debug(`DashboardExpect.docTableFieldCount(${expectedCount})`); + async dataGridTableCellCount(expectedCount: number) { + log.debug(`DashboardExpect.dataGridTableCellCount(${expectedCount})`); await retry.try(async () => { - const docTableCells = await testSubjects.findAll('docTableField', findTimeout); + const docTableCells = await testSubjects.findAll('dataGridRowCell', findTimeout); expect(docTableCells.length).to.be(expectedCount); }); } diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index e5f66fbc67c4..c41733a1481f 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -37,6 +37,7 @@ interface TabbedGridData { export function DataGridProvider({ getService }: FtrProviderContext) { const find = getService('find'); + const testSubjects = getService('testSubjects'); class DataGrid { async getDataGridTableData(): Promise { @@ -66,6 +67,35 @@ export function DataGridProvider({ getService }: FtrProviderContext) { rows, }; } + + /** + * Retrieves the header fields of the data grid. + * + * @returns {Promise} An array containing names of the header fields. + */ + async getHeaderFields(): Promise { + const headerNames = []; + // Locate header cells, ignoring the inspect document button column + const headerCells = await find.allByCssSelector( + '.euiDataGridHeaderCell__button > .euiDataGridHeaderCell__content' + ); + + for (const cell of headerCells) { + const headerName = await cell.getAttribute('textContent'); + headerNames.push(headerName.trim()); + } + return Promise.resolve(headerNames); + } + + /** + * Clicks to remove a specified column from the data grid. + * + * @param {string} columnName - The name of the column to be removed. + */ + async clickRemoveColumn(columnName: string) { + await testSubjects.click(`dataGridHeaderCell-${columnName}`); + await find.clickByButtonText('Remove column'); + } } return new DataGrid(); diff --git a/yarn.lock b/yarn.lock index 98c4cd2b4219..476371b7d448 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2770,9 +2770,9 @@ defer-to-connect "^2.0.0" "@testim/chrome-version@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.3.tgz#fbb68696899d7b8c1b9b891eded9c04fe2cd5529" - integrity sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A== + version "1.1.4" + resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.4.tgz#86e04e677cd6c05fa230dd15ac223fa72d1d7090" + integrity sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g== "@testing-library/dom@^8.0.0", "@testing-library/dom@^8.11.3": version "8.12.0" @@ -2838,6 +2838,18 @@ resolved "https://registry.yarnpkg.com/@tsd/typescript/-/typescript-4.7.4.tgz#f1e4e6c3099a174a0cb7aa51cf53f34f6494e528" integrity sha512-jbtC+RgKZ9Kk65zuRZbKLTACf+tvFW4Rfq0JEMXrlmV3P3yme+Hm+pnb5fJRyt61SjIitcrC810wj7+1tgsEmg== +"@types/angular-mocks@^1.7.1": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@types/angular-mocks/-/angular-mocks-1.7.2.tgz#bc442ca0b143a4ed711337cdf9bfcf575f3aaa64" + integrity sha512-mNaIhct+eo9JOlivKTG4fntyoBMM9Q0QBjS2Fx+SE8hd8NvqsDdivJQMHTFNXs/lTadXkwzrRizEgrUJcUha9g== + dependencies: + "@types/angular" "*" + +"@types/angular@*", "@types/angular@^1.8.4": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.8.6.tgz#faeb6c734dd64ef60bbd41edf3d32d2f9c9956bf" + integrity sha512-2ub0NF1vSSZ1iHp20xyGwQyc4+QScuWnE5o2sKqh6KQ5Z4rImd8GX4E2hvgKfa6yLigzugYnZo5dFz2ogGcLCg== + "@types/archiver@^5.3.1": version "5.3.1" resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.1.tgz#02991e940a03dd1a32678fead4b4ca03d0e387ca" @@ -4380,6 +4392,43 @@ ajv@^8.0.1, ajv@^8.11.0, ajv@^8.6.2: require-from-string "^2.0.2" uri-js "^4.2.2" +angular-aria@^1.8.0: + version "1.8.3" + resolved "https://registry.yarnpkg.com/angular-aria/-/angular-aria-1.8.3.tgz#b387ebca9569eb557855abb283a09c2d0457e779" + integrity sha512-qTXclmTW/KGw5JNKKQPcCKKq6hCBZ39jYINmLgMsjUHBAoxULaMRRTaRj/L2VTOjKvK5f9enkx+EUqRqzXDSFQ== + +angular-elastic@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/angular-elastic/-/angular-elastic-2.5.1.tgz#e938ab1bd8c76415b8ca6514b15fe3593a5df535" + integrity sha512-N18+Xyp2th/TT6RNCCrPwYt00XAfTQqp0tgvEmibBH4FI5BYWiq2RV65jj56ZxYhrJy0eb7zq3gK3RmBB+Me7Q== + dependencies: + angular ">=1.0.6" + +angular-mocks@^1.8.2: + version "1.8.3" + resolved "https://registry.yarnpkg.com/angular-mocks/-/angular-mocks-1.8.3.tgz#c0dd05e5c3fc014e07af6289b23f0e817d7a4724" + integrity sha512-vqsT6zwu80cZ8RY7qRQBZuy6Fq5X7/N5hkV9LzNT0c8b546rw4ErGK6muW1u2JnDKYa7+jJuaGM702bWir4HGw== + +angular-recursion@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/angular-recursion/-/angular-recursion-1.0.5.tgz#cd405428a0bf55faf52eaa7988c1fe69cd930543" + integrity sha512-4GX8nwTmtavtAadWs7viaWnfNZbr/SxlCnDdfyfR+asnF4IuUusQFDcdqFN8h5tZ1M3BRG21QIxRgD9n5efq+Q== + +angular-route@^1.8.0: + version "1.8.3" + resolved "https://registry.yarnpkg.com/angular-route/-/angular-route-1.8.3.tgz#f24a700ebd462454ca83a8b765df55c87a4edde1" + integrity sha512-kpIcRmDR2+o1FxDVVYy8Rvfab86/7LDbOgTRb9T+X9ewPQiBRuDEnZtM3oJYBiQLvAXDYTJXHV48n/bGE9Mv2g== + +angular-sanitize@^1.8.0: + version "1.8.3" + resolved "https://registry.yarnpkg.com/angular-sanitize/-/angular-sanitize-1.8.3.tgz#51378e990e78c7ecc1fb31cd68655aff690a3bf1" + integrity sha512-2rxdqzlUVafUeWOwvY/FtyWk1pFTyCtzreeiTytG9m4smpuAEKaIJAjYeVwWsoV+nlTOcgpwV4W1OCmR+BQbUg== + +angular@>=1.0.6, angular@^1.8.2: + version "1.8.3" + resolved "https://registry.yarnpkg.com/angular/-/angular-1.8.3.tgz#851ad75d5163c105a7e329555ef70c90aa706894" + integrity sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw== + ansi-colors@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" @@ -4880,9 +4929,9 @@ axios@^0.27.2: form-data "^4.0.0" axios@^1.1.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.0.tgz#1cb65bd75162c70e9f8d118a905126c4a201d383" - integrity sha512-zT7wZyNYu3N5Bu0wuZ6QccIf93Qk1eV8LOewxgjOZFd2DenOs98cJ7+Y6703d0wkaXGY6/nZd4EweJaHz9uzQw== + version "1.5.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267" + integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -6099,9 +6148,9 @@ compare-versions@3.5.1: integrity sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg== compare-versions@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-5.0.1.tgz#14c6008436d994c3787aba38d4087fabe858555e" - integrity sha512-v8Au3l0b+Nwkp4G142JcgJFh1/TUhdxut7wzD1Nq1dyp5oa3tXaqb03EXOAB6jS4gMlalkjAUPZBMiAfKUixHQ== + version "5.0.3" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-5.0.3.tgz#a9b34fea217472650ef4a2651d905f42c28ebfd7" + integrity sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A== complex.js@^2.1.1: version "2.1.1" @@ -8770,11 +8819,16 @@ focus-lock@^0.10.2: dependencies: tslib "^2.0.3" -follow-redirects@^1.14.9, follow-redirects@^1.15.0: +follow-redirects@^1.14.9: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.15.0: + version "1.15.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" + integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== + font-awesome@4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" @@ -13047,6 +13101,11 @@ next-tick@1, next-tick@^1.1.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== +ngreact@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/ngreact/-/ngreact-0.5.2.tgz#d48180b578b186ad70861a3de9ba508b3f22b2ae" + integrity sha512-FCQGtTkDrnI3ywhvK9wUf7C6SYfqKDdRW+cPvy358GFe3AnA4rfvWisDVUQyf5YwNr439ito9xUuuEv80QXhSQ== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"