mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
- Resolves https://github.com/elastic/kibana/issues/158173
Based on PoC https://github.com/elastic/kibana/pull/166260
## Summary
This PR adds a new "Saved Query Management" privilege with 2 options:
- `All` will override any per app privilege and will allow users to save
queries from any Kibana page
- `None` will default to per app privileges (backward-compatible option)
<img width="600" alt="Screenshot 2023-09-21 at 15 26 25"
src="6d53548e
-5c5a-4d6d-a86a-1e639cb77202">
### Checklist
- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
---------
Co-authored-by: Matthias Wilhelm <matthias.wilhelm@elastic.co>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co>
123 lines
4 KiB
TypeScript
123 lines
4 KiB
TypeScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the Elastic License
|
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
|
* 2.0.
|
|
*/
|
|
|
|
import { coreMock, savedObjectsServiceMock } from '@kbn/core/server/mocks';
|
|
import { FeaturesPlugin } from './plugin';
|
|
|
|
describe('Features Plugin', () => {
|
|
let initContext: ReturnType<typeof coreMock.createPluginInitializerContext>;
|
|
let coreSetup: ReturnType<typeof coreMock.createSetup>;
|
|
let coreStart: ReturnType<typeof coreMock.createStart>;
|
|
let typeRegistry: ReturnType<typeof savedObjectsServiceMock.createTypeRegistryMock>;
|
|
|
|
beforeEach(() => {
|
|
initContext = coreMock.createPluginInitializerContext();
|
|
coreSetup = coreMock.createSetup();
|
|
coreStart = coreMock.createStart();
|
|
typeRegistry = savedObjectsServiceMock.createTypeRegistryMock();
|
|
typeRegistry.getVisibleTypes.mockReturnValue([
|
|
{
|
|
name: 'foo',
|
|
hidden: false,
|
|
mappings: { properties: {} },
|
|
namespaceType: 'single' as 'single',
|
|
},
|
|
]);
|
|
typeRegistry.getImportableAndExportableTypes.mockReturnValue([
|
|
{
|
|
name: 'hidden-importableAndExportable',
|
|
hidden: true,
|
|
mappings: { properties: {} },
|
|
namespaceType: 'single' as 'single',
|
|
},
|
|
{
|
|
name: 'not-hidden-importableAndExportable',
|
|
hidden: false,
|
|
mappings: { properties: {} },
|
|
namespaceType: 'single' as 'single',
|
|
},
|
|
]);
|
|
coreStart.savedObjects.getTypeRegistry.mockReturnValue(typeRegistry);
|
|
});
|
|
|
|
it('returns OSS + registered kibana features', async () => {
|
|
const plugin = new FeaturesPlugin(initContext);
|
|
const { registerKibanaFeature: registerFeature } = await plugin.setup(coreSetup);
|
|
registerFeature({
|
|
id: 'baz',
|
|
name: 'baz',
|
|
app: [],
|
|
category: { id: 'foo', label: 'foo' },
|
|
privileges: null,
|
|
});
|
|
|
|
const { getKibanaFeatures } = plugin.start(coreStart);
|
|
|
|
expect(getKibanaFeatures().map((f) => f.id)).toMatchInlineSnapshot(`
|
|
Array [
|
|
"baz",
|
|
"discover",
|
|
"visualize",
|
|
"dashboard",
|
|
"dev_tools",
|
|
"advancedSettings",
|
|
"indexPatterns",
|
|
"filesManagement",
|
|
"filesSharedImage",
|
|
"savedObjectsManagement",
|
|
"savedQueryManagement",
|
|
]
|
|
`);
|
|
});
|
|
|
|
it('registers kibana features with visible saved objects types and hidden saved object types that are importable and exportable', async () => {
|
|
typeRegistry.isHidden.mockReturnValueOnce(true);
|
|
typeRegistry.isHidden.mockReturnValueOnce(false);
|
|
const plugin = new FeaturesPlugin(initContext);
|
|
await plugin.setup(coreSetup);
|
|
const { getKibanaFeatures } = plugin.start(coreStart);
|
|
|
|
const soTypes =
|
|
getKibanaFeatures().find((f) => f.id === 'savedObjectsManagement')?.privileges?.all
|
|
.savedObject.all || [];
|
|
|
|
expect(soTypes.includes('foo')).toBe(true);
|
|
expect(soTypes.includes('bar')).toBe(false);
|
|
expect(soTypes.includes('hidden-importableAndExportable')).toBe(true);
|
|
expect(soTypes.includes('not-hidden-importableAndExportable')).toBe(false);
|
|
});
|
|
|
|
it('returns registered elasticsearch features', async () => {
|
|
const plugin = new FeaturesPlugin(initContext);
|
|
const { registerElasticsearchFeature } = await plugin.setup(coreSetup);
|
|
registerElasticsearchFeature({
|
|
id: 'baz',
|
|
privileges: [
|
|
{
|
|
requiredClusterPrivileges: ['all'],
|
|
ui: ['baz-ui'],
|
|
},
|
|
],
|
|
});
|
|
|
|
const { getElasticsearchFeatures } = plugin.start(coreStart);
|
|
|
|
expect(getElasticsearchFeatures().map((f) => f.id)).toMatchInlineSnapshot(`
|
|
Array [
|
|
"baz",
|
|
]
|
|
`);
|
|
});
|
|
|
|
it('registers a capabilities provider', async () => {
|
|
const plugin = new FeaturesPlugin(initContext);
|
|
await plugin.setup(coreSetup);
|
|
|
|
expect(coreSetup.capabilities.registerProvider).toHaveBeenCalledTimes(1);
|
|
expect(coreSetup.capabilities.registerProvider).toHaveBeenCalledWith(expect.any(Function));
|
|
});
|
|
});
|