[Workplace Search] Factor out Document-level Permissions components for re-use (#120131)

* Factor out DocumentPermissionsField component

* Factor out DocumentPermissionsCallout component
This commit is contained in:
Scotty Bollinger 2021-12-01 12:18:09 -06:00 committed by GitHub
parent 86956327de
commit 4f733acd4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 243 additions and 131 deletions

View file

@ -12,11 +12,10 @@ import React from 'react';
import { shallow } from 'enzyme';
import { EuiSwitch } from '@elastic/eui';
import { staticSourceData } from '../../source_data';
import { ConnectInstance } from './connect_instance';
import { DocumentPermissionsCallout } from './document_permissions_callout';
describe('ConnectInstance', () => {
// Needed to mock redirect window.location.replace(oauthUrl)
@ -126,13 +125,6 @@ describe('ConnectInstance', () => {
expect(setSourceSubdomainValue).toHaveBeenCalledWith(TEXT);
});
it('calls handler on click', () => {
const wrapper = shallow(<ConnectInstance {...props} />);
wrapper.find(EuiSwitch).simulate('change', { target: { checked: true } });
expect(setSourceIndexPermissionsValue).toHaveBeenCalledWith(true);
});
it('handles form submission with oauth source', () => {
jest.spyOn(window.location, 'replace').mockImplementationOnce(mockReplace);
const wrapper = shallow(<ConnectInstance {...oauthProps} />);
@ -145,23 +137,10 @@ describe('ConnectInstance', () => {
expect(mockReplace).toHaveBeenCalled();
});
it('renders doc-level permissions message when not available', () => {
const wrapper = shallow(<ConnectInstance {...props} needsPermissions={false} />);
expect(wrapper.find('FormattedMessage')).toHaveLength(1);
});
it('renders callout when not synced', () => {
setMockValues({ ...values, indexPermissionsValue: false });
const wrapper = shallow(<ConnectInstance {...props} />);
expect(wrapper.find('EuiCallOut')).toHaveLength(1);
});
it('renders documentLevelPermissionsCallout', () => {
setMockValues({ ...values, hasPlatinumLicense: false });
const wrapper = shallow(<ConnectInstance {...oauthProps} />);
expect(wrapper.find('[data-test-subj="DocumentLevelPermissionsCallout"]')).toHaveLength(1);
expect(wrapper.find(DocumentPermissionsCallout)).toHaveLength(1);
});
});

View file

@ -11,41 +11,23 @@ import { useActions, useValues } from 'kea';
import {
EuiButton,
EuiCallOut,
EuiFieldText,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiHorizontalRule,
EuiIcon,
EuiLink,
EuiPanel,
EuiSpacer,
EuiSwitch,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { LicensingLogic } from '../../../../../shared/licensing';
import { AppLogic } from '../../../../app_logic';
import { EXPLORE_PLATINUM_FEATURES_LINK } from '../../../../constants';
import { DOCUMENT_PERMISSIONS_DOCS_URL, ENT_SEARCH_LICENSE_MANAGEMENT } from '../../../../routes';
import { FeatureIds, Configuration, Features } from '../../../../types';
import { LEARN_MORE_LINK } from '../../constants';
import { AddSourceLogic } from './add_source_logic';
import {
CONNECT_WHICH_OPTION_LINK,
CONNECT_DOC_PERMISSIONS_LABEL,
CONNECT_DOC_PERMISSIONS_TITLE,
CONNECT_NEEDS_PERMISSIONS,
CONNECT_NOT_SYNCED_TITLE,
CONNECT_NOT_SYNCED_TEXT,
SOURCE_FEATURES_DOCUMENT_LEVEL_PERMISSIONS_FEATURE,
SOURCE_FEATURES_DOCUMENT_LEVEL_PERMISSIONS_TITLE,
} from './constants';
import { DocumentPermissionsCallout } from './document_permissions_callout';
import { DocumentPermissionsField } from './document_permissions_field';
import { SourceFeatures } from './source_features';
interface ConnectInstanceProps {
@ -147,94 +129,12 @@ export const ConnectInstance: React.FC<ConnectInstanceProps> = ({
</>
);
const whichDocsLink = (
<EuiLink target="_blank" href={DOCUMENT_PERMISSIONS_DOCS_URL}>
{CONNECT_WHICH_OPTION_LINK}
</EuiLink>
);
const permissionField = (
<>
<EuiPanel paddingSize="l" hasShadow={false} color="subdued">
<EuiTitle size="s">
<h1>
<strong>{CONNECT_DOC_PERMISSIONS_TITLE}</strong>
</h1>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText color="subdued" size="s">
{!needsPermissions && (
<span>
<FormattedMessage
id="xpack.enterpriseSearch.workplaceSearch.contentSource.connect.docPermissionsUnavailable.message"
defaultMessage="Document-level permissions are not yet available for this source. {link}"
values={{
link: (
<EuiLink target="_blank" href={DOCUMENT_PERMISSIONS_DOCS_URL}>
{LEARN_MORE_LINK}
</EuiLink>
),
}}
/>
</span>
)}
{needsPermissions && indexPermissionsValue && (
<span>
{CONNECT_NEEDS_PERMISSIONS}
<EuiSpacer size="s" />
{whichDocsLink}
</span>
)}
</EuiText>
{!indexPermissionsValue && (
<>
<EuiCallOut title={CONNECT_NOT_SYNCED_TITLE} color="warning">
<p>
{CONNECT_NOT_SYNCED_TEXT}
{needsPermissions && whichDocsLink}
</p>
</EuiCallOut>
</>
)}
<EuiSpacer />
<EuiSwitch
label={<strong>{CONNECT_DOC_PERMISSIONS_LABEL}</strong>}
name="index_permissions"
onChange={(e) => setSourceIndexPermissionsValue(e.target.checked)}
checked={indexPermissionsValue}
disabled={!needsPermissions}
/>
</EuiPanel>
<EuiSpacer size="xl" />
</>
);
const documentLevelPermissionsCallout = (
<>
<EuiPanel paddingSize="l" data-test-subj="DocumentLevelPermissionsCallout">
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon size="m" type="lock" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs">
<strong>{SOURCE_FEATURES_DOCUMENT_LEVEL_PERMISSIONS_TITLE}</strong>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiText size="xs">
<p>{SOURCE_FEATURES_DOCUMENT_LEVEL_PERMISSIONS_FEATURE}</p>
</EuiText>
<EuiSpacer size="s" />
<EuiText size="xs">
<EuiLink external target="_blank" href={ENT_SEARCH_LICENSE_MANAGEMENT}>
{EXPLORE_PLATINUM_FEATURES_LINK}
</EuiLink>
</EuiText>
</EuiPanel>
<EuiSpacer />
</>
<DocumentPermissionsField
needsPermissions={needsPermissions}
indexPermissionsValue={indexPermissionsValue}
setValue={setSourceIndexPermissionsValue}
/>
);
const formFields = (
@ -242,7 +142,7 @@ export const ConnectInstance: React.FC<ConnectInstanceProps> = ({
{isOrganization && hasPlatinumLicense && permissionField}
{!hasOauthRedirect && credentialsFields}
{needsSubdomain && subdomainField}
{permissionsExcluded && !hasPlatinumLicense && documentLevelPermissionsCallout}
{permissionsExcluded && !hasPlatinumLicense && <DocumentPermissionsCallout />}
<EuiFormRow>
<EuiButton color="primary" type="submit" fill isLoading={formLoading}>

View file

@ -0,0 +1,23 @@
/*
* 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 React from 'react';
import { shallow } from 'enzyme';
import { EuiPanel, EuiLink } from '@elastic/eui';
import { DocumentPermissionsCallout } from './document_permissions_callout';
describe('DocumentPermissionsCallout', () => {
it('renders', () => {
const wrapper = shallow(<DocumentPermissionsCallout />);
expect(wrapper.find(EuiPanel)).toHaveLength(1);
expect(wrapper.find(EuiLink)).toHaveLength(1);
});
});

View file

@ -0,0 +1,56 @@
/*
* 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 React from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiLink,
EuiPanel,
EuiSpacer,
EuiText,
} from '@elastic/eui';
import { EXPLORE_PLATINUM_FEATURES_LINK } from '../../../../constants';
import { ENT_SEARCH_LICENSE_MANAGEMENT } from '../../../../routes';
import {
SOURCE_FEATURES_DOCUMENT_LEVEL_PERMISSIONS_FEATURE,
SOURCE_FEATURES_DOCUMENT_LEVEL_PERMISSIONS_TITLE,
} from './constants';
export const DocumentPermissionsCallout: React.FC = () => {
return (
<>
<EuiPanel paddingSize="l" data-test-subj="DocumentLevelPermissionsCallout">
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<EuiIcon size="m" type="lock" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="xs">
<strong>{SOURCE_FEATURES_DOCUMENT_LEVEL_PERMISSIONS_TITLE}</strong>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiText size="xs">
<p>{SOURCE_FEATURES_DOCUMENT_LEVEL_PERMISSIONS_FEATURE}</p>
</EuiText>
<EuiSpacer size="s" />
<EuiText size="xs">
<EuiLink external target="_blank" href={ENT_SEARCH_LICENSE_MANAGEMENT}>
{EXPLORE_PLATINUM_FEATURES_LINK}
</EuiLink>
</EuiText>
</EuiPanel>
<EuiSpacer />
</>
);
};

View file

@ -0,0 +1,49 @@
/*
* 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 React from 'react';
import { shallow } from 'enzyme';
import { EuiCallOut, EuiPanel, EuiSwitch } from '@elastic/eui';
import { DocumentPermissionsField } from './document_permissions_field';
describe('DocumentPermissionsField', () => {
const setValue = jest.fn();
const props = {
needsPermissions: true,
indexPermissionsValue: true,
setValue,
};
it('renders', () => {
const wrapper = shallow(<DocumentPermissionsField {...props} />);
expect(wrapper.find(EuiPanel)).toHaveLength(1);
});
it('renders doc-level permissions message when not available', () => {
const wrapper = shallow(<DocumentPermissionsField {...props} needsPermissions={false} />);
expect(wrapper.find('FormattedMessage')).toHaveLength(1);
});
it('renders callout when not synced', () => {
const wrapper = shallow(<DocumentPermissionsField {...props} indexPermissionsValue={false} />);
expect(wrapper.find(EuiCallOut)).toHaveLength(1);
});
it('calls handler on click', () => {
const wrapper = shallow(<DocumentPermissionsField {...props} />);
wrapper.find(EuiSwitch).simulate('change', { target: { checked: true } });
expect(setValue).toHaveBeenCalledWith(true);
});
});

View file

@ -0,0 +1,105 @@
/*
* 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 React from 'react';
import {
EuiCallOut,
EuiLink,
EuiPanel,
EuiSpacer,
EuiSwitch,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { DOCUMENT_PERMISSIONS_DOCS_URL } from '../../../../routes';
import { LEARN_MORE_LINK } from '../../constants';
import {
CONNECT_WHICH_OPTION_LINK,
CONNECT_DOC_PERMISSIONS_LABEL,
CONNECT_DOC_PERMISSIONS_TITLE,
CONNECT_NEEDS_PERMISSIONS,
CONNECT_NOT_SYNCED_TITLE,
CONNECT_NOT_SYNCED_TEXT,
} from './constants';
interface Props {
needsPermissions: boolean;
indexPermissionsValue: boolean;
setValue(indexPermissionsValue: boolean): void;
}
export const DocumentPermissionsField: React.FC<Props> = ({
needsPermissions,
indexPermissionsValue,
setValue,
}) => {
const whichDocsLink = (
<EuiLink target="_blank" href={DOCUMENT_PERMISSIONS_DOCS_URL}>
{CONNECT_WHICH_OPTION_LINK}
</EuiLink>
);
return (
<>
<EuiPanel paddingSize="l" hasShadow={false} color="subdued">
<EuiTitle size="s">
<h1>
<strong>{CONNECT_DOC_PERMISSIONS_TITLE}</strong>
</h1>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText color="subdued" size="s">
{!needsPermissions && (
<span>
<FormattedMessage
id="xpack.enterpriseSearch.workplaceSearch.contentSource.connect.docPermissionsUnavailable.message"
defaultMessage="Document-level permissions are not yet available for this source. {link}"
values={{
link: (
<EuiLink target="_blank" href={DOCUMENT_PERMISSIONS_DOCS_URL}>
{LEARN_MORE_LINK}
</EuiLink>
),
}}
/>
</span>
)}
{needsPermissions && indexPermissionsValue && (
<span>
{CONNECT_NEEDS_PERMISSIONS}
<EuiSpacer size="s" />
{whichDocsLink}
</span>
)}
</EuiText>
{!indexPermissionsValue && (
<>
<EuiCallOut title={CONNECT_NOT_SYNCED_TITLE} color="warning">
<p>
{CONNECT_NOT_SYNCED_TEXT}
{needsPermissions && whichDocsLink}
</p>
</EuiCallOut>
</>
)}
<EuiSpacer />
<EuiSwitch
label={<strong>{CONNECT_DOC_PERMISSIONS_LABEL}</strong>}
name="index_permissions"
onChange={(e) => setValue(e.target.checked)}
checked={indexPermissionsValue}
disabled={!needsPermissions}
/>
</EuiPanel>
<EuiSpacer size="xl" />
</>
);
};