mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Search] Session feature controls (#85846)
* Use filter to bulk find * Update x-pack/plugins/data_enhanced/server/search/session/session_service.ts Co-authored-by: Lukas Olson <olson.lukas@gmail.com> * Dashboard in space test * Add warning on update failure * fix merge * Added functional test for sessions in space * snapshot * test cleanup * sub perms * test snapshots * Update tests * test * code review * snap * Added discover test * Update x-pack/plugins/data_enhanced/public/search/ui/connected_background_session_indicator/connected_background_session_indicator.tsx Co-authored-by: Anton Dosov <dosantappdev@gmail.com> Co-authored-by: Lukas Olson <olson.lukas@gmail.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Anton Dosov <dosantappdev@gmail.com>
This commit is contained in:
parent
9ed0bbddde
commit
4415e548b5
10 changed files with 262 additions and 10 deletions
|
@ -57,8 +57,35 @@ test('should show indicator in case there is an active search session', async ()
|
|||
await waitFor(() => getByTestId('backgroundSessionIndicator'));
|
||||
});
|
||||
|
||||
test('should be disabled when permissions are off', async () => {
|
||||
const state$ = new BehaviorSubject(SessionState.Loading);
|
||||
coreStart.application.currentAppId$ = new BehaviorSubject('discover');
|
||||
(coreStart.application.capabilities as any) = {
|
||||
discover: {
|
||||
storeSearchSession: false,
|
||||
},
|
||||
};
|
||||
const BackgroundSessionIndicator = createConnectedBackgroundSessionIndicator({
|
||||
sessionService: { ...sessionService, state$ },
|
||||
application: coreStart.application,
|
||||
timeFilter,
|
||||
});
|
||||
|
||||
render(<BackgroundSessionIndicator />);
|
||||
|
||||
await waitFor(() => screen.getByTestId('backgroundSessionIndicator'));
|
||||
|
||||
expect(screen.getByTestId('backgroundSessionIndicator').querySelector('button')).toBeDisabled();
|
||||
});
|
||||
|
||||
test('should be disabled during auto-refresh', async () => {
|
||||
const state$ = new BehaviorSubject(SessionState.Loading);
|
||||
coreStart.application.currentAppId$ = new BehaviorSubject('discover');
|
||||
(coreStart.application.capabilities as any) = {
|
||||
discover: {
|
||||
storeSearchSession: true,
|
||||
},
|
||||
};
|
||||
const BackgroundSessionIndicator = createConnectedBackgroundSessionIndicator({
|
||||
sessionService: { ...sessionService, state$ },
|
||||
application: coreStart.application,
|
||||
|
|
|
@ -29,12 +29,35 @@ export const createConnectedBackgroundSessionIndicator = ({
|
|||
.getRefreshIntervalUpdate$()
|
||||
.pipe(map(isAutoRefreshEnabled), distinctUntilChanged());
|
||||
|
||||
const getCapabilitiesByAppId = (
|
||||
capabilities: ApplicationStart['capabilities'],
|
||||
appId?: string
|
||||
) => {
|
||||
switch (appId) {
|
||||
case 'dashboards':
|
||||
return capabilities.dashboard;
|
||||
case 'discover':
|
||||
return capabilities.discover;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
const state = useObservable(sessionService.state$.pipe(debounceTime(500)));
|
||||
const autoRefreshEnabled = useObservable(isAutoRefreshEnabled$, isAutoRefreshEnabled());
|
||||
const appId = useObservable(application.currentAppId$, undefined);
|
||||
|
||||
let disabled = false;
|
||||
let disabledReasonText: string = '';
|
||||
|
||||
if (getCapabilitiesByAppId(application.capabilities, appId)?.storeSearchSession !== true) {
|
||||
disabled = true;
|
||||
disabledReasonText = i18n.translate('xpack.data.backgroundSessionIndicator.noCapability', {
|
||||
defaultMessage: "You don't have permissions to send to background.",
|
||||
});
|
||||
}
|
||||
|
||||
if (autoRefreshEnabled) {
|
||||
disabled = true;
|
||||
disabledReasonText = i18n.translate(
|
||||
|
|
|
@ -73,6 +73,7 @@ Array [
|
|||
"dashboard",
|
||||
"query",
|
||||
"url",
|
||||
"background-session",
|
||||
],
|
||||
"read": Array [
|
||||
"index-pattern",
|
||||
|
@ -83,7 +84,6 @@ Array [
|
|||
"lens",
|
||||
"map",
|
||||
"tag",
|
||||
"background-session",
|
||||
],
|
||||
},
|
||||
"ui": Array [
|
||||
|
@ -92,6 +92,7 @@ Array [
|
|||
"showWriteControls",
|
||||
"saveQuery",
|
||||
"createShortUrl",
|
||||
"storeSearchSession",
|
||||
],
|
||||
},
|
||||
"privilegeId": "all",
|
||||
|
@ -205,8 +206,8 @@ Array [
|
|||
"search",
|
||||
"query",
|
||||
"index-pattern",
|
||||
"background-session",
|
||||
"url",
|
||||
"background-session",
|
||||
],
|
||||
"read": Array [],
|
||||
},
|
||||
|
@ -215,6 +216,7 @@ Array [
|
|||
"save",
|
||||
"saveQuery",
|
||||
"createShortUrl",
|
||||
"storeSearchSession",
|
||||
],
|
||||
},
|
||||
"privilegeId": "all",
|
||||
|
@ -557,6 +559,7 @@ Array [
|
|||
"dashboard",
|
||||
"query",
|
||||
"url",
|
||||
"background-session",
|
||||
],
|
||||
"read": Array [
|
||||
"index-pattern",
|
||||
|
@ -567,7 +570,6 @@ Array [
|
|||
"lens",
|
||||
"map",
|
||||
"tag",
|
||||
"background-session",
|
||||
],
|
||||
},
|
||||
"ui": Array [
|
||||
|
@ -576,6 +578,7 @@ Array [
|
|||
"showWriteControls",
|
||||
"saveQuery",
|
||||
"createShortUrl",
|
||||
"storeSearchSession",
|
||||
],
|
||||
},
|
||||
"privilegeId": "all",
|
||||
|
@ -689,8 +692,8 @@ Array [
|
|||
"search",
|
||||
"query",
|
||||
"index-pattern",
|
||||
"background-session",
|
||||
"url",
|
||||
"background-session",
|
||||
],
|
||||
"read": Array [],
|
||||
},
|
||||
|
@ -699,6 +702,7 @@ Array [
|
|||
"save",
|
||||
"saveQuery",
|
||||
"createShortUrl",
|
||||
"storeSearchSession",
|
||||
],
|
||||
},
|
||||
"privilegeId": "all",
|
||||
|
|
|
@ -28,7 +28,7 @@ export const buildOSSFeatures = ({ savedObjectTypes, includeTimelion }: BuildOSS
|
|||
app: ['discover', 'kibana'],
|
||||
catalogue: ['discover'],
|
||||
savedObject: {
|
||||
all: ['search', 'query', 'index-pattern', 'background-session'],
|
||||
all: ['search', 'query', 'index-pattern'],
|
||||
read: [],
|
||||
},
|
||||
ui: ['show', 'save', 'saveQuery'],
|
||||
|
@ -71,6 +71,33 @@ export const buildOSSFeatures = ({ savedObjectTypes, includeTimelion }: BuildOSS
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n.translate('xpack.features.ossFeatures.discoverSearchSessionsFeatureName', {
|
||||
defaultMessage: 'Store Search Sessions',
|
||||
}),
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [
|
||||
{
|
||||
id: 'store_search_session',
|
||||
name: i18n.translate(
|
||||
'xpack.features.ossFeatures.discoverStoreSearchSessionsPrivilegeName',
|
||||
{
|
||||
defaultMessage: 'Store Search Sessions',
|
||||
}
|
||||
),
|
||||
includeIn: 'all',
|
||||
savedObject: {
|
||||
all: ['background-session'],
|
||||
read: [],
|
||||
},
|
||||
ui: ['storeSearchSession'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -156,7 +183,6 @@ export const buildOSSFeatures = ({ savedObjectTypes, includeTimelion }: BuildOSS
|
|||
'lens',
|
||||
'map',
|
||||
'tag',
|
||||
'background-session',
|
||||
],
|
||||
},
|
||||
ui: ['createNew', 'show', 'showWriteControls', 'saveQuery'],
|
||||
|
@ -210,6 +236,33 @@ export const buildOSSFeatures = ({ savedObjectTypes, includeTimelion }: BuildOSS
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: i18n.translate('xpack.features.ossFeatures.dashboardSearchSessionsFeatureName', {
|
||||
defaultMessage: 'Store Search Sessions',
|
||||
}),
|
||||
privilegeGroups: [
|
||||
{
|
||||
groupType: 'independent',
|
||||
privileges: [
|
||||
{
|
||||
id: 'store_search_session',
|
||||
name: i18n.translate(
|
||||
'xpack.features.ossFeatures.dashboardStoreSearchSessionsPrivilegeName',
|
||||
{
|
||||
defaultMessage: 'Store Search Sessions',
|
||||
}
|
||||
),
|
||||
includeIn: 'all',
|
||||
savedObject: {
|
||||
all: ['background-session'],
|
||||
read: [],
|
||||
},
|
||||
ui: ['storeSearchSession'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
'minimal_all',
|
||||
'minimal_read',
|
||||
'url_create',
|
||||
'store_search_session',
|
||||
];
|
||||
const trialPrivileges = await supertest
|
||||
.get('/api/security/privileges')
|
||||
|
|
|
@ -20,9 +20,23 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
// Roles are associated with these privileges, and we shouldn't be removing them in a minor version.
|
||||
const expected = {
|
||||
features: {
|
||||
discover: ['all', 'read', 'minimal_all', 'minimal_read', 'url_create'],
|
||||
discover: [
|
||||
'all',
|
||||
'read',
|
||||
'minimal_all',
|
||||
'minimal_read',
|
||||
'url_create',
|
||||
'store_search_session',
|
||||
],
|
||||
visualize: ['all', 'read', 'minimal_all', 'minimal_read', 'url_create'],
|
||||
dashboard: ['all', 'read', 'minimal_all', 'minimal_read', 'url_create'],
|
||||
dashboard: [
|
||||
'all',
|
||||
'read',
|
||||
'minimal_all',
|
||||
'minimal_read',
|
||||
'url_create',
|
||||
'store_search_session',
|
||||
],
|
||||
dev_tools: ['all', 'read'],
|
||||
advancedSettings: ['all', 'read'],
|
||||
indexPatterns: ['all', 'read'],
|
||||
|
|
|
@ -20,7 +20,10 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
reportName: 'X-Pack Background Search UI (Enabled WIP Feature)',
|
||||
},
|
||||
|
||||
testFiles: [resolve(__dirname, './tests/apps/dashboard/async_search')],
|
||||
testFiles: [
|
||||
resolve(__dirname, './tests/apps/dashboard/async_search'),
|
||||
resolve(__dirname, './tests/apps/discover'),
|
||||
],
|
||||
|
||||
kbnTestServer: {
|
||||
...xpackFunctionalConfig.get('kbnTestServer'),
|
||||
|
|
|
@ -34,7 +34,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
},
|
||||
kibana: [
|
||||
{
|
||||
base: ['all'],
|
||||
feature: {
|
||||
dashboard: ['minimal_read', 'store_search_session'],
|
||||
},
|
||||
spaces: ['another-space'],
|
||||
},
|
||||
],
|
||||
|
@ -54,6 +56,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
after(async () => {
|
||||
await security.role.delete('data_analyst');
|
||||
await security.user.delete('analyst');
|
||||
|
||||
await esArchiver.unload('dashboard/session_in_space');
|
||||
await PageObjects.security.forceLogout();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export default function ({ loadTestFile, getService }: FtrProviderContext) {
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('async search', function () {
|
||||
this.tags('ciGroup3');
|
||||
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('logstash_functional');
|
||||
await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' });
|
||||
});
|
||||
|
||||
loadTestFile(require.resolve('./sessions_in_space'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const security = getService('security');
|
||||
const inspector = getService('inspector');
|
||||
const PageObjects = getPageObjects([
|
||||
'common',
|
||||
'header',
|
||||
'discover',
|
||||
'visChart',
|
||||
'security',
|
||||
'timePicker',
|
||||
]);
|
||||
const browser = getService('browser');
|
||||
const sendToBackground = getService('sendToBackground');
|
||||
|
||||
describe('discover in space', () => {
|
||||
describe('Send to background in space', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load('dashboard/session_in_space');
|
||||
|
||||
await security.role.create('data_analyst', {
|
||||
elasticsearch: {
|
||||
indices: [{ names: ['logstash-*'], privileges: ['all'] }],
|
||||
},
|
||||
kibana: [
|
||||
{
|
||||
feature: {
|
||||
discover: ['all'],
|
||||
},
|
||||
spaces: ['another-space'],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await security.user.create('analyst', {
|
||||
password: 'analyst-password',
|
||||
roles: ['data_analyst'],
|
||||
full_name: 'test user',
|
||||
});
|
||||
|
||||
await PageObjects.security.forceLogout();
|
||||
|
||||
await PageObjects.security.login('analyst', 'analyst-password', {
|
||||
expectSpaceSelector: false,
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await security.role.delete('data_analyst');
|
||||
await security.user.delete('analyst');
|
||||
|
||||
await esArchiver.unload('dashboard/session_in_space');
|
||||
await PageObjects.security.forceLogout();
|
||||
});
|
||||
|
||||
it('Saves and restores a session', async () => {
|
||||
await PageObjects.common.navigateToApp('discover', { basePath: 's/another-space' });
|
||||
|
||||
await PageObjects.discover.selectIndexPattern('logstash-*');
|
||||
|
||||
await PageObjects.timePicker.setAbsoluteRange(
|
||||
'Sep 1, 2015 @ 00:00:00.000',
|
||||
'Oct 1, 2015 @ 00:00:00.000'
|
||||
);
|
||||
|
||||
await PageObjects.discover.waitForDocTableLoadingComplete();
|
||||
|
||||
await sendToBackground.expectState('completed');
|
||||
await sendToBackground.save();
|
||||
await sendToBackground.expectState('backgroundCompleted');
|
||||
await inspector.open();
|
||||
|
||||
const savedSessionId = await (
|
||||
await testSubjects.find('inspectorRequestSearchSessionId')
|
||||
).getAttribute('data-search-session-id');
|
||||
await inspector.close();
|
||||
|
||||
// load URL to restore a saved session
|
||||
const url = await browser.getCurrentUrl();
|
||||
const savedSessionURL = `${url}&searchSessionId=${savedSessionId}`;
|
||||
await browser.get(savedSessionURL);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.discover.waitForDocTableLoadingComplete();
|
||||
|
||||
// Check that session is restored
|
||||
await sendToBackground.expectState('restored');
|
||||
await testSubjects.missingOrFail('embeddableErrorLabel');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue