Skip to content

Commit

Permalink
[Workplace Search] Migrate Objects and assets from Source settings to…
Browse files Browse the repository at this point in the history
… Synchronization section (#113982)

* Rename method

We have to set the source from the sync logic file and this naming makes more sense

* Wire up Enable Synchronization toggle

* Remove sync controls from source settings

* Refactor to pass in contentSource as prop

Because we have a child logic file, SynchronizationLogic, we have to pass the content source into it for reading its values from SourceLogic. There are 3 ways to do this:

1. Access the source directly at SourceLogic.values.contentSource
  - This how we normally do it. The problem here is that SourceLogic is not mounted when the default values are set in the reducers. This caused the UI to break and I could not find a way to safely mount SourceLogic before this logic file needed it.

2. Use the connect property and connect to Sourcelogic to access contentSource
  - This actually worked great but our test helper does not work well with it and after an hour or so trying to make it work, I punted and decided to go with #3 below.

3. Pass the contentSource as a prop
  - This works great and is easy to test. The only drawback is that all other components that use the SynchronizationLogic file have to also pass in the content source. This commit does just that.

* Add logic for Objects and assets view

* Add content to Objects and assets view

* Add fallback for `nextStart` that is in the past

This is slightly beyond the scope of this PR but trying to make the final PR more manageable.

There is an edge case where a running job lists the nextStart in the past if it is is running. After a lengthy Slack convo, it was decided to catch these in the UI and show a fallback string instead of something like “Next run 3 hours ago”

* reduce -> map

From previous PR feedback

* Fix casing on i18n ID
  • Loading branch information
scottybollinger authored Oct 5, 2021
1 parent 5a8782b commit 43588b5
Show file tree
Hide file tree
Showing 20 changed files with 563 additions and 243 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,84 +105,6 @@ 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,8 +17,6 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiSpacer,
EuiSwitch,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

Expand Down Expand Up @@ -51,12 +49,6 @@ 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 @@ -70,22 +62,7 @@ export const SourceSettings: React.FC = () => {
const { getSourceConfigData } = useActions(AddSourceLogic);

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

Expand All @@ -109,11 +86,6 @@ 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 @@ -130,18 +102,6 @@ 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 @@ -221,58 +181,6 @@ 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 @@ -10,7 +10,6 @@ import React from 'react';
import {
EuiButton,
EuiComboBox,
EuiComboBoxOptionOption,
EuiDatePicker,
EuiFlexGroup,
EuiFlexItem,
Expand Down Expand Up @@ -81,13 +80,10 @@ const syncOptions = [
},
];

const dayPickerOptions = DAYS_OF_WEEK_VALUES.reduce((options, day) => {
options.push({
label: DAYS_OF_WEEK_LABELS[day.toUpperCase() as keyof typeof DAYS_OF_WEEK_LABELS],
value: day,
});
return options;
}, [] as Array<EuiComboBoxOptionOption<string>>);
const dayPickerOptions = DAYS_OF_WEEK_VALUES.map((day) => ({
label: DAYS_OF_WEEK_LABELS[day.toUpperCase() as keyof typeof DAYS_OF_WEEK_LABELS],
value: day,
}));

export const BlockedWindowItem: React.FC<Props> = ({ blockedWindow }) => {
const handleSyncTypeChange = () => '#TODO';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import '../../../../../__mocks__/shallow_useeffect.mock';
import { setMockActions, setMockValues } from '../../../../../__mocks__/kea_logic';
import { fullContentSources } from '../../../../__mocks__/content_sources.mock';
import { blockedWindow } from './__mocks__/syncronization.mock';

import React from 'react';
Expand All @@ -25,6 +26,7 @@ describe('BlockedWindows', () => {
};
const mockValues = {
blockedWindows: [blockedWindow],
contentSource: fullContentSources[0],
};

beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import { EuiButton, EuiEmptyPrompt, EuiSpacer } from '@elastic/eui';

import { ADD_LABEL } from '../../../../constants';
import { BLOCKED_EMPTY_STATE_TITLE, BLOCKED_EMPTY_STATE_DESCRIPTION } from '../../constants';
import { SourceLogic } from '../../source_logic';

import { BlockedWindowItem } from './blocked_window_item';
import { SynchronizationLogic } from './synchronization_logic';

export const BlockedWindows: React.FC = () => {
const { blockedWindows } = useValues(SynchronizationLogic);
const { addBlockedWindow } = useActions(SynchronizationLogic);
const { contentSource } = useValues(SourceLogic);
const { blockedWindows } = useValues(SynchronizationLogic({ contentSource }));
const { addBlockedWindow } = useActions(SynchronizationLogic({ contentSource }));

const hasBlockedWindows = blockedWindows.length > 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import '../../../../../__mocks__/shallow_useeffect.mock';
import { setMockActions, setMockValues } from '../../../../../__mocks__/kea_logic';
import { fullContentSources } from '../../../../__mocks__/content_sources.mock';

import React from 'react';

Expand All @@ -23,7 +24,9 @@ describe('Frequency', () => {
const mockActions = {
handleSelectedTabChanged,
};
const mockValues = {};
const mockValues = {
contentSource: fullContentSources[0],
};

beforeEach(() => {
setMockActions(mockActions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import React from 'react';

import { useActions } from 'kea';
import { useActions, useValues } from 'kea';

import {
EuiButton,
Expand All @@ -31,6 +31,7 @@ import {
DIFFERENT_SYNC_TYPES_LINK_LABEL,
SYNC_BEST_PRACTICES_LINK_LABEL,
} from '../../constants';
import { SourceLogic } from '../../source_logic';
import { SourceLayout } from '../source_layout';

import { BlockedWindows } from './blocked_window_tab';
Expand All @@ -42,7 +43,8 @@ interface FrequencyProps {
}

export const Frequency: React.FC<FrequencyProps> = ({ tabId }) => {
const { handleSelectedTabChanged } = useActions(SynchronizationLogic);
const { contentSource } = useValues(SourceLogic);
const { handleSelectedTabChanged } = useActions(SynchronizationLogic({ contentSource }));

const tabs = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,24 @@
import React from 'react';

import { shallow } from 'enzyme';
import moment from 'moment';

import { EuiFieldNumber, EuiSuperSelect } from '@elastic/eui';

import { FrequencyItem } from './frequency_item';

describe('FrequencyItem', () => {
const estimate = {
duration: 'PT3D',
nextStart: '2021-09-27T21:39:24+00:00',
lastRun: '2021-09-25T21:39:24+00:00',
};

const props = {
label: 'Item',
description: 'My item',
duration: 'PT2D',
estimate: {
duration: 'PT3D',
nextStart: '2021-09-27T21:39:24+00:00',
lastRun: '2021-09-25T21:39:24+00:00',
},
estimate,
};

it('renders', () => {
Expand Down Expand Up @@ -60,5 +63,25 @@ describe('FrequencyItem', () => {
expect(wrapper.find(EuiFieldNumber).prop('value')).toEqual(1);
expect(wrapper.find(EuiSuperSelect).prop('valueOfSelected')).toEqual('minutes');
});

it('handles "nextStart" that is in past', () => {
const wrapper = shallow(<FrequencyItem {...props} />);

expect(
(wrapper.find('[data-test-subj="nextStartSummary"]').prop('values') as any)!.nextStartTime
).toEqual('as soon as the currently running job finishes');
});

it('handles "nextStart" that is in future', () => {
const estimateWithPastNextStart = {
...estimate,
nextStart: moment().add(2, 'days').format(),
};
const wrapper = shallow(<FrequencyItem {...props} estimate={estimateWithPastNextStart} />);

expect(
(wrapper.find('[data-test-subj="nextStartSummary"]').prop('values') as any)!.nextStartTime
).toEqual('in 2 days');
});
});
});
Loading

0 comments on commit 43588b5

Please sign in to comment.