Skip to content

Commit

Permalink
Add Workplace Search sync controls UI (elastic#108558) (elastic#108613)
Browse files Browse the repository at this point in the history
* Wip

* Things are more broken, but closer to the end goal

* Get patch request working

* Update event type

* Other two toggles

* Force sync button

* Remove force sync button for now

* Disable the checkbox when globally disabled and introduce click to save

* Wip tests

* One test down

* Test for skipping name alert

* Linter

* Fix undefined check

* Prettier

* Apply suggestions from code review

Co-authored-by: Scotty Bollinger <[email protected]>

* Refactor some structures into interfaces

* UI tweaks

Co-authored-by: Scotty Bollinger <[email protected]>

Co-authored-by: Ross Bell <[email protected]>
Co-authored-by: Scotty Bollinger <[email protected]>
  • Loading branch information
3 people authored Aug 14, 2021
1 parent 5e1e8bd commit 324f9e9
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const contentSources = [
},
{
id: '124',
serviceType: 'jira',
serviceType: 'jira_cloud',
searchable: true,
supportedByLicense: true,
status: 'synced',
Expand All @@ -43,6 +43,24 @@ export const contentSources = [
},
];

const defaultIndexing = {
enabled: true,
defaultAction: 'include',
rules: [],
schedule: {
intervals: [],
blocked: [],
},
features: {
contentExtraction: {
enabled: true,
},
thumbnails: {
enabled: true,
},
},
};

export const fullContentSources = [
{
...contentSources[0],
Expand All @@ -66,8 +84,11 @@ export const fullContentSources = [
type: 'summary',
},
],
indexing: defaultIndexing,
groups,
custom: false,
isIndexedSource: true,
areThumbnailsConfigEnabled: true,
accessToken: '123token',
urlField: 'myLink',
titleField: 'heading',
Expand All @@ -85,7 +106,10 @@ export const fullContentSources = [
details: [],
summary: [],
groups: [],
indexing: defaultIndexing,
custom: true,
isIndexedSource: true,
areThumbnailsConfigEnabled: true,
accessToken: '123token',
urlField: 'url',
titleField: 'title',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,27 @@ interface SourceActivity {
status: string;
}

interface IndexingConfig {
enabled: boolean;
features: {
contentExtraction: {
enabled: boolean;
};
thumbnails: {
enabled: boolean;
};
};
}

export interface ContentSourceFullData extends ContentSourceDetails {
activities: SourceActivity[];
details: DescriptionList[];
summary: DocumentSummaryItem[];
groups: Group[];
indexing: IndexingConfig;
custom: boolean;
isIndexedSource: boolean;
areThumbnailsConfigEnabled: boolean;
accessToken: string;
urlField: string;
titleField: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,84 @@ describe('SourceSettings', () => {
);
});

it('handles disabling synchronization', () => {
const wrapper = shallow(<SourceSettings />);

const synchronizeSwitch = wrapper.find('[data-test-subj="SynchronizeToggle"]').first();
const event = { target: { checked: false } };
synchronizeSwitch.prop('onChange')?.(event as any);

wrapper.find('[data-test-subj="SaveSyncControlsButton"]').simulate('click');

expect(updateContentSource).toHaveBeenCalledWith(fullContentSources[0].id, {
indexing: {
enabled: false,
features: {
content_extraction: { enabled: true },
thumbnails: { enabled: true },
},
},
});
});

it('handles disabling thumbnails', () => {
const wrapper = shallow(<SourceSettings />);

const thumbnailsSwitch = wrapper.find('[data-test-subj="ThumbnailsToggle"]').first();
const event = { target: { checked: false } };
thumbnailsSwitch.prop('onChange')?.(event as any);

wrapper.find('[data-test-subj="SaveSyncControlsButton"]').simulate('click');

expect(updateContentSource).toHaveBeenCalledWith(fullContentSources[0].id, {
indexing: {
enabled: true,
features: {
content_extraction: { enabled: true },
thumbnails: { enabled: false },
},
},
});
});

it('handles disabling content extraction', () => {
const wrapper = shallow(<SourceSettings />);

const contentExtractionSwitch = wrapper
.find('[data-test-subj="ContentExtractionToggle"]')
.first();
const event = { target: { checked: false } };
contentExtractionSwitch.prop('onChange')?.(event as any);

wrapper.find('[data-test-subj="SaveSyncControlsButton"]').simulate('click');

expect(updateContentSource).toHaveBeenCalledWith(fullContentSources[0].id, {
indexing: {
enabled: true,
features: {
content_extraction: { enabled: false },
thumbnails: { enabled: true },
},
},
});
});

it('disables the thumbnails switch when globally disabled', () => {
setMockValues({
...mockValues,
contentSource: {
...fullContentSources[0],
areThumbnailsConfigEnabled: false,
},
});

const wrapper = shallow(<SourceSettings />);

const synchronizeSwitch = wrapper.find('[data-test-subj="ThumbnailsToggle"]');

expect(synchronizeSwitch.prop('disabled')).toEqual(true);
});

describe('DownloadDiagnosticsButton', () => {
it('renders for org with correct href', () => {
const wrapper = shallow(<SourceSettings />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiSpacer,
EuiSwitch,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

Expand Down Expand Up @@ -49,6 +51,12 @@ import {
SYNC_DIAGNOSTICS_TITLE,
SYNC_DIAGNOSTICS_DESCRIPTION,
SYNC_DIAGNOSTICS_BUTTON,
SYNC_MANAGEMENT_TITLE,
SYNC_MANAGEMENT_DESCRIPTION,
SYNC_MANAGEMENT_SYNCHRONIZE_LABEL,
SYNC_MANAGEMENT_THUMBNAILS_LABEL,
SYNC_MANAGEMENT_THUMBNAILS_GLOBAL_CONFIG_LABEL,
SYNC_MANAGEMENT_CONTENT_EXTRACTION_LABEL,
} from '../constants';
import { staticSourceData } from '../source_data';
import { SourceLogic } from '../source_logic';
Expand All @@ -63,7 +71,21 @@ export const SourceSettings: React.FC = () => {
const { getSourceConfigData } = useActions(AddSourceLogic);

const {
contentSource: { name, id, serviceType },
contentSource: {
name,
id,
serviceType,
custom: isCustom,
isIndexedSource,
areThumbnailsConfigEnabled,
indexing: {
enabled,
features: {
contentExtraction: { enabled: contentExtractionEnabled },
thumbnails: { enabled: thumbnailsEnabled },
},
},
},
buttonLoading,
} = useValues(SourceLogic);

Expand All @@ -88,6 +110,11 @@ export const SourceSettings: React.FC = () => {
const hideConfirm = () => setModalVisibility(false);

const showConfig = isOrganization && !isEmpty(configuredFields);
const showSyncControls = isOrganization && isIndexedSource && !isCustom;

const [synchronizeChecked, setSynchronize] = useState(enabled);
const [thumbnailsChecked, setThumbnails] = useState(thumbnailsEnabled);
const [contentExtractionChecked, setContentExtraction] = useState(contentExtractionEnabled);

const { clientId, clientSecret, publicKey, consumerKey, baseUrl } = configuredFields || {};

Expand All @@ -102,6 +129,18 @@ export const SourceSettings: React.FC = () => {
updateContentSource(id, { name: inputValue });
};

const submitSyncControls = () => {
updateContentSource(id, {
indexing: {
enabled: synchronizeChecked,
features: {
content_extraction: { enabled: contentExtractionChecked },
thumbnails: { enabled: thumbnailsChecked },
},
},
});
};

const handleSourceRemoval = () => {
/**
* The modal was just hanging while the UI waited for the server to respond.
Expand Down Expand Up @@ -180,6 +219,58 @@ export const SourceSettings: React.FC = () => {
</EuiFormRow>
</ContentSection>
)}
{showSyncControls && (
<ContentSection title={SYNC_MANAGEMENT_TITLE} description={SYNC_MANAGEMENT_DESCRIPTION}>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiSwitch
checked={synchronizeChecked}
onChange={(e) => setSynchronize(e.target.checked)}
label={SYNC_MANAGEMENT_SYNCHRONIZE_LABEL}
data-test-subj="SynchronizeToggle"
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiSwitch
checked={thumbnailsChecked}
onChange={(e) => setThumbnails(e.target.checked)}
label={
areThumbnailsConfigEnabled
? SYNC_MANAGEMENT_THUMBNAILS_LABEL
: SYNC_MANAGEMENT_THUMBNAILS_GLOBAL_CONFIG_LABEL
}
disabled={!areThumbnailsConfigEnabled}
data-test-subj="ThumbnailsToggle"
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiSwitch
checked={contentExtractionChecked}
onChange={(e) => setContentExtraction(e.target.checked)}
label={SYNC_MANAGEMENT_CONTENT_EXTRACTION_LABEL}
data-test-subj="ContentExtractionToggle"
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<EuiButton
color="primary"
onClick={submitSyncControls}
data-test-subj="SaveSyncControlsButton"
>
{SAVE_CHANGES_BUTTON}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</ContentSection>
)}
<ContentSection title={SYNC_DIAGNOSTICS_TITLE} description={SYNC_DIAGNOSTICS_DESCRIPTION}>
<EuiButton
target="_blank"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,48 @@ export const SOURCE_CONFIG_DESCRIPTION = i18n.translate(
}
);

export const SYNC_MANAGEMENT_TITLE = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSources.syncManagementTitle',
{
defaultMessage: 'Sync management',
}
);

export const SYNC_MANAGEMENT_DESCRIPTION = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSources.syncManagementDescription',
{
defaultMessage: 'Enable and disable extraction of specific content for this source.',
}
);

export const SYNC_MANAGEMENT_SYNCHRONIZE_LABEL = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSources.syncManagementSynchronizeLabel',
{
defaultMessage: 'Synchronize this source',
}
);

export const SYNC_MANAGEMENT_THUMBNAILS_LABEL = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSources.syncManagementThumbnailsLabel',
{
defaultMessage: 'Sync thumbnails',
}
);

export const SYNC_MANAGEMENT_THUMBNAILS_GLOBAL_CONFIG_LABEL = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSources.syncManagementGlobalConfigLabel',
{
defaultMessage: 'Sync thumbnails - disabled at global configuration level',
}
);

export const SYNC_MANAGEMENT_CONTENT_EXTRACTION_LABEL = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.contentSources.syncManagementContentExtractionLabel',
{
defaultMessage: 'Sync all text and content',
}
);

export const SOURCE_CONFIG_LINK = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.sources.config.link',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,21 @@ describe('SourceLogic', () => {
expect(onUpdateSourceNameSpy).toHaveBeenCalledWith(contentSource.name);
});

it('does not call onUpdateSourceName when the name is not supplied', async () => {
AppLogic.values.isOrganization = true;

const onUpdateSourceNameSpy = jest.spyOn(SourceLogic.actions, 'onUpdateSourceName');
const promise = Promise.resolve(contentSource);
http.patch.mockReturnValue(promise);
SourceLogic.actions.updateContentSource(contentSource.id, { indexing: { enabled: true } });

expect(http.patch).toHaveBeenCalledWith('/api/workplace_search/org/sources/123/settings', {
body: JSON.stringify({ content_source: { indexing: { enabled: true } } }),
});
await promise;
expect(onUpdateSourceNameSpy).not.toHaveBeenCalledWith(contentSource.name);
});

it('calls API and sets values (account)', async () => {
AppLogic.values.isOrganization = false;

Expand Down
Loading

0 comments on commit 324f9e9

Please sign in to comment.