Skip to content

Commit 99f7c37

Browse files
committed
Merge remote-tracking branch 'origin/main' into main-merge
Signed-off-by: Ashish Agrawal <ashisagr@amazon.com>
2 parents 83e2ff9 + 2322c53 commit 99f7c37

31 files changed

+1223
-261
lines changed

.github/CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
* @ananzh @kavilla @seanneumann @AMoo-Miki @ashwin-pc @joshuarrrr @abbyhu2000 @zengyan-amazon @kristenTian @zhongnansu @manasvinibs
1+
* @ananzh @kavilla @seanneumann @AMoo-Miki @ashwin-pc @joshuarrrr @abbyhu2000 @zengyan-amazon @kristenTian @zhongnansu @manasvinibs @ZilongX @Flyingliuhub

.github/workflows/cypress_workflow.yml

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ env:
1212
START_CMD: 'node ../scripts/opensearch_dashboards --dev --no-base-path --no-watch'
1313
OPENSEARCH_SNAPSHOT_CMD: 'node ../scripts/opensearch snapshot'
1414
SPEC: 'cypress/integration/core-opensearch-dashboards/opensearch-dashboards/**/*.js,'
15-
CYPRESS_ENV: 'env CYPRESS_VISBUILDER_ENABLED=true CYPRESS_DATASOURCE_MANAGEMENT_ENABLED=false'
15+
CYPRESS_BROWSER: 'chromium'
16+
CYPRESS_VISBUILDER_ENABLED: true
17+
CYPRESS_DATASOURCE_MANAGEMENT_ENABLED: false
18+
OSD_SNAPSHOT_SKIP_VERIFY_CHECKSUM: true
1619

1720
jobs:
1821
cypress-tests:
@@ -76,7 +79,7 @@ jobs:
7679
working-directory: ${{ env.FTR_PATH }}
7780
start: ${{ env.OPENSEARCH_SNAPSHOT_CMD }}, ${{ env.START_CMD }}
7881
wait-on: 'http://localhost:9200, http://localhost:5601'
79-
command: ${{ env.CYPRESS_ENV }} yarn cypress:run-without-security --browser chromium --spec ${{ env.SPEC }}
82+
command: yarn cypress:run-without-security --browser ${{ env.CYPRESS_BROWSER }} --spec ${{ env.SPEC }}
8083

8184
# Screenshots are only captured on failure, will change this once we do visual regression tests
8285
- uses: actions/upload-artifact@v3

CHANGELOG.md

+521-221
Large diffs are not rendered by default.

examples/ui_actions_explorer/public/context_menu_examples/context_menu_examples.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { PanelViewWithSharingLong } from './panel_view_with_sharing_long';
3636
import { PanelEdit } from './panel_edit';
3737
import { PanelEditWithDrilldowns } from './panel_edit_with_drilldowns';
3838
import { PanelEditWithDrilldownsAndContextActions } from './panel_edit_with_drilldowns_and_context_actions';
39+
import { PanelGroupOptionsAndContextActions } from './panel_group_options_and_context_actions';
3940

4041
export const ContextMenuExamples: React.FC = () => {
4142
return (
@@ -59,7 +60,6 @@ export const ContextMenuExamples: React.FC = () => {
5960
<PanelViewWithSharingLong />
6061
</EuiFlexItem>
6162
</EuiFlexGroup>
62-
6363
<EuiFlexGroup>
6464
<EuiFlexItem>
6565
<PanelEdit />
@@ -71,6 +71,11 @@ export const ContextMenuExamples: React.FC = () => {
7171
<PanelEditWithDrilldownsAndContextActions />
7272
</EuiFlexItem>
7373
</EuiFlexGroup>
74+
<EuiFlexGroup>
75+
<EuiFlexItem>
76+
<PanelGroupOptionsAndContextActions />
77+
</EuiFlexItem>
78+
</EuiFlexGroup>
7479
</EuiText>
7580
);
7681
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as React from 'react';
7+
import { EuiButton, EuiContextMenu, EuiPopover } from '@elastic/eui';
8+
import useAsync from 'react-use/lib/useAsync';
9+
import { buildContextMenuForActions, Action } from '../../../../src/plugins/ui_actions/public';
10+
import { sampleAction } from './util';
11+
12+
export const PanelGroupOptionsAndContextActions: React.FC = () => {
13+
const [open, setOpen] = React.useState(false);
14+
15+
const context = {};
16+
const trigger: any = 'TEST_TRIGGER';
17+
const drilldownGrouping: Action['grouping'] = [
18+
{
19+
id: 'drilldowns',
20+
getDisplayName: () => 'Uncategorized group',
21+
getIconType: () => 'popout',
22+
order: 20,
23+
},
24+
];
25+
const exampleGroup: Action['grouping'] = [
26+
{
27+
id: 'example',
28+
getDisplayName: () => 'Example group',
29+
getIconType: () => 'cloudStormy',
30+
order: 20,
31+
category: 'visAug',
32+
},
33+
];
34+
const alertingGroup: Action['grouping'] = [
35+
{
36+
id: 'alerting',
37+
getDisplayName: () => 'Alerting',
38+
getIconType: () => 'cloudStormy',
39+
order: 20,
40+
category: 'visAug',
41+
},
42+
];
43+
const anomaliesGroup: Action['grouping'] = [
44+
{
45+
id: 'anomalies',
46+
getDisplayName: () => 'Anomalies',
47+
getIconType: () => 'cloudStormy',
48+
order: 30,
49+
category: 'visAug',
50+
},
51+
];
52+
const actions = [
53+
sampleAction('test-1', 100, 'Edit visualization', 'pencil'),
54+
sampleAction('test-2', 99, 'Clone panel', 'partial'),
55+
56+
sampleAction('test-9', 10, 'Create drilldown', 'plusInCircle', drilldownGrouping),
57+
sampleAction('test-10', 9, 'Manage drilldowns', 'list', drilldownGrouping),
58+
59+
sampleAction('test-11', 10, 'Example action', 'dashboardApp', exampleGroup),
60+
sampleAction('test-11', 10, 'Alertin action 1', 'dashboardApp', alertingGroup),
61+
sampleAction('test-12', 9, 'Alertin action 2', 'dashboardApp', alertingGroup),
62+
sampleAction('test-13', 8, 'Anomalies 1', 'cloudStormy', anomaliesGroup),
63+
sampleAction('test-14', 7, 'Anomalies 2', 'link', anomaliesGroup),
64+
];
65+
66+
const panels = useAsync(() =>
67+
buildContextMenuForActions({
68+
actions: actions.map((action) => ({ action, context, trigger })),
69+
})
70+
);
71+
72+
return (
73+
<EuiPopover
74+
button={<EuiButton onClick={() => setOpen((x) => !x)}>Grouping with categories</EuiButton>}
75+
isOpen={open}
76+
panelPaddingSize="none"
77+
anchorPosition="downLeft"
78+
closePopover={() => setOpen(false)}
79+
>
80+
<EuiContextMenu initialPanelId={'mainMenu'} panels={panels.value} />
81+
</EuiPopover>
82+
);
83+
};

release-notes/opensearch-dashboards.release-notes-1.3.10.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@
1919

2020
### 🐛 Bug Fixes
2121

22-
- [TSVB] Fix the link to "serial differencing aggregation" documentation ([#3503](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3503))
23-
2422
### 📝 Documentation
2523

2624
- Update jest documentation links ([#3939](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3939))
2725

2826
### 🛠 Maintenance
2927

3028
- Add threshold to code coverage changes for project ([#4050](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4050))
31-
- Temporarily hardcode chromedriver to 112.0.0 to enable all ftr tests ([#4039]())
29+
- Temporarily hardcode chromedriver to 112.0.0 to enable all ftr tests ([#4039](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4039))
3230
- Update MAINTAINERS.md and CODEOWNERS ([#3938](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3938))
3331
- Add opensearch-dashboards-docker-dev to .gitignore ([#3781](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3781))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## Version 2.8.0 Release Notes
2+
3+
### Deprecations
4+
5+
- Remove timeline application ([#3971](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3971))
6+
7+
### 🛡 Security
8+
9+
- [CVE-2023-2251] Bump `yaml` to `2.2.2` ([#3947](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3947))
10+
11+
### 📈 Features/Enhancements
12+
13+
- [Multiple Datasource] Support Amazon OpenSearch Serverless ([#3957](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3957))
14+
- Add support for Node.js >=14.20.1 <19 ([#4071](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4071))
15+
- Bundle Node.js 14 as a fallback for operating systems that cannot run Node.js 18 ([#4151](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4151))
16+
- Enhance grouping for context menus ([#3924](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3924))
17+
18+
### 🐛 Bug Fixes
19+
20+
- [BUG] Fix bottom bar visibility using createPortal ([#3978](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3978))
21+
- [Dashboards Listing] Fix listing limit to utilize `savedObjects:listingLimit` instead of `savedObjects:perPage` ([#4021](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4021))
22+
23+
### 🚞 Infrastructure
24+
25+
- Install chrome driver for functional tests from path set by environment variable `TEST_BROWSER_BINARY_PATH`([#3997](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3997))
26+
- Add threshold to code coverage config to prevent workflow failures ([#4040](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4040))
27+
- [CI] Skip checksum verification on OpenSearch snapshot for cypress tests ([#4188](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4188))
28+
29+
### 🛠 Maintenance
30+
31+
- Use `exec` in the CLI shell scripts to prevent new process creation ([#3955](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3955))
32+
33+
## 🎉 Welcome
34+
35+
Thank you to all the first-time contributors who made this release possible: @sikhote, @SergeyMyssak!

src/core/public/plugins/plugins_service.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ function createManifest(
8484
version: 'some-version',
8585
configPath: ['path'],
8686
requiredPlugins: required,
87+
requiredOpenSearchPlugins: optional,
8788
optionalPlugins: optional,
8889
requiredBundles: [],
8990
};

src/core/server/legacy/legacy_service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ export class LegacyService implements CoreService {
275275
addClientWrapper: setupDeps.core.savedObjects.addClientWrapper,
276276
registerType: setupDeps.core.savedObjects.registerType,
277277
getImportExportObjectLimit: setupDeps.core.savedObjects.getImportExportObjectLimit,
278+
setRepositoryFactoryProvider: setupDeps.core.savedObjects.setRepositoryFactoryProvider,
278279
},
279280
status: {
280281
isStatusPageAnonymous: setupDeps.core.status.isStatusPageAnonymous,

src/core/server/plugins/discovery/plugin_manifest_parser.test.ts

+79
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,79 @@ test('return error when manifest contains unrecognized properties', async () =>
247247
});
248248
});
249249

250+
describe('requiredOpenSearchPlugins', () => {
251+
test('return error when plugin `requiredOpenSearchPlugins` is a string and not an array of string', async () => {
252+
mockReadFilePromise.mockResolvedValue(
253+
Buffer.from(
254+
JSON.stringify({
255+
id: 'id1',
256+
version: '7.0.0',
257+
server: true,
258+
requiredOpenSearchPlugins: 'abc',
259+
})
260+
)
261+
);
262+
263+
await expect(parseManifest(pluginPath, packageInfo, logger)).rejects.toMatchObject({
264+
message: `The "requiredOpenSearchPlugins" in plugin manifest for "id1" should be an array of strings. (invalid-manifest, ${pluginManifestPath})`,
265+
type: PluginDiscoveryErrorType.InvalidManifest,
266+
path: pluginManifestPath,
267+
});
268+
});
269+
270+
test('return error when `requiredOpenSearchPlugins` is not a string', async () => {
271+
mockReadFilePromise.mockResolvedValue(
272+
Buffer.from(JSON.stringify({ id: 'id2', version: '7.0.0', requiredOpenSearchPlugins: 2 }))
273+
);
274+
275+
await expect(parseManifest(pluginPath, packageInfo, logger)).rejects.toMatchObject({
276+
message: `The "requiredOpenSearchPlugins" in plugin manifest for "id2" should be an array of strings. (invalid-manifest, ${pluginManifestPath})`,
277+
type: PluginDiscoveryErrorType.InvalidManifest,
278+
path: pluginManifestPath,
279+
});
280+
});
281+
282+
test('return error when plugin requiredOpenSearchPlugins is an array that contains non-string values', async () => {
283+
mockReadFilePromise.mockResolvedValue(
284+
Buffer.from(
285+
JSON.stringify({ id: 'id3', version: '7.0.0', requiredOpenSearchPlugins: ['plugin1', 2] })
286+
)
287+
);
288+
289+
await expect(parseManifest(pluginPath, packageInfo, logger)).rejects.toMatchObject({
290+
message: `The "requiredOpenSearchPlugins" in plugin manifest for "id3" should be an array of strings. (invalid-manifest, ${pluginManifestPath})`,
291+
type: PluginDiscoveryErrorType.InvalidManifest,
292+
path: pluginManifestPath,
293+
});
294+
});
295+
296+
test('Happy path when plugin `requiredOpenSearchPlugins` is an array of string', async () => {
297+
mockReadFilePromise.mockResolvedValue(
298+
Buffer.from(
299+
JSON.stringify({
300+
id: 'id1',
301+
version: '7.0.0',
302+
server: true,
303+
requiredOpenSearchPlugins: ['plugin1', 'plugin2'],
304+
})
305+
)
306+
);
307+
308+
await expect(parseManifest(pluginPath, packageInfo, logger)).resolves.toEqual({
309+
id: 'id1',
310+
configPath: 'id_1',
311+
version: '7.0.0',
312+
opensearchDashboardsVersion: '7.0.0',
313+
optionalPlugins: [],
314+
requiredPlugins: [],
315+
requiredOpenSearchPlugins: ['plugin1', 'plugin2'],
316+
requiredBundles: [],
317+
server: true,
318+
ui: false,
319+
});
320+
});
321+
});
322+
250323
describe('configPath', () => {
251324
test('falls back to plugin id if not specified', async () => {
252325
mockReadFilePromise.mockResolvedValue(
@@ -301,6 +374,7 @@ test('set defaults for all missing optional fields', async () => {
301374
opensearchDashboardsVersion: '7.0.0',
302375
optionalPlugins: [],
303376
requiredPlugins: [],
377+
requiredOpenSearchPlugins: [],
304378
requiredBundles: [],
305379
server: true,
306380
ui: false,
@@ -317,6 +391,7 @@ test('return all set optional fields as they are in manifest', async () => {
317391
opensearchDashboardsVersion: '7.0.0',
318392
requiredPlugins: ['some-required-plugin', 'some-required-plugin-2'],
319393
optionalPlugins: ['some-optional-plugin'],
394+
requiredOpenSearchPlugins: ['test-opensearch-plugin-1', 'test-opensearch-plugin-2'],
320395
ui: true,
321396
})
322397
)
@@ -330,6 +405,7 @@ test('return all set optional fields as they are in manifest', async () => {
330405
optionalPlugins: ['some-optional-plugin'],
331406
requiredBundles: [],
332407
requiredPlugins: ['some-required-plugin', 'some-required-plugin-2'],
408+
requiredOpenSearchPlugins: ['test-opensearch-plugin-1', 'test-opensearch-plugin-2'],
333409
server: false,
334410
ui: true,
335411
});
@@ -344,6 +420,7 @@ test('return manifest when plugin expected OpenSearch Dashboards version matches
344420
version: 'some-version',
345421
opensearchDashboardsVersion: '7.0.0-alpha2',
346422
requiredPlugins: ['some-required-plugin'],
423+
requiredOpenSearchPlugins: [],
347424
server: true,
348425
})
349426
)
@@ -356,6 +433,7 @@ test('return manifest when plugin expected OpenSearch Dashboards version matches
356433
opensearchDashboardsVersion: '7.0.0-alpha2',
357434
optionalPlugins: [],
358435
requiredPlugins: ['some-required-plugin'],
436+
requiredOpenSearchPlugins: [],
359437
requiredBundles: [],
360438
server: true,
361439
ui: false,
@@ -383,6 +461,7 @@ test('return manifest when plugin expected OpenSearch Dashboards version is `ope
383461
opensearchDashboardsVersion: 'opensearchDashboards',
384462
optionalPlugins: [],
385463
requiredPlugins: ['some-required-plugin'],
464+
requiredOpenSearchPlugins: [],
386465
requiredBundles: [],
387466
server: true,
388467
ui: true,

src/core/server/plugins/discovery/plugin_manifest_parser.ts

+26
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const KNOWN_MANIFEST_FIELDS = (() => {
6161
version: true,
6262
configPath: true,
6363
requiredPlugins: true,
64+
requiredOpenSearchPlugins: true,
6465
optionalPlugins: true,
6566
ui: true,
6667
server: true,
@@ -156,6 +157,28 @@ export async function parseManifest(
156157
);
157158
}
158159

160+
if (
161+
manifest.requiredOpenSearchPlugins !== undefined &&
162+
(!Array.isArray(manifest.requiredOpenSearchPlugins) ||
163+
!manifest.requiredOpenSearchPlugins.every((plugin) => typeof plugin === 'string'))
164+
) {
165+
throw PluginDiscoveryError.invalidManifest(
166+
manifestPath,
167+
new Error(
168+
`The "requiredOpenSearchPlugins" in plugin manifest for "${manifest.id}" should be an array of strings.`
169+
)
170+
);
171+
}
172+
173+
if (
174+
Array.isArray(manifest.requiredOpenSearchPlugins) &&
175+
manifest.requiredOpenSearchPlugins.length > 0
176+
) {
177+
log.info(
178+
`Plugin ${manifest.id} has a dependency on following OpenSearch plugin(s): "${manifest.requiredOpenSearchPlugins}".`
179+
);
180+
}
181+
159182
const expectedOpenSearchDashboardsVersion =
160183
typeof manifest.opensearchDashboardsVersion === 'string' && manifest.opensearchDashboardsVersion
161184
? manifest.opensearchDashboardsVersion
@@ -198,6 +221,9 @@ export async function parseManifest(
198221
opensearchDashboardsVersion: expectedOpenSearchDashboardsVersion,
199222
configPath: manifest.configPath || snakeCase(manifest.id),
200223
requiredPlugins: Array.isArray(manifest.requiredPlugins) ? manifest.requiredPlugins : [],
224+
requiredOpenSearchPlugins: Array.isArray(manifest.requiredOpenSearchPlugins)
225+
? manifest.requiredOpenSearchPlugins
226+
: [],
201227
optionalPlugins: Array.isArray(manifest.optionalPlugins) ? manifest.optionalPlugins : [],
202228
requiredBundles: Array.isArray(manifest.requiredBundles) ? manifest.requiredBundles : [],
203229
ui: includesUiPlugin,

0 commit comments

Comments
 (0)