Skip to content

Commit

Permalink
Only show minutes as monitor interval plus do not show Zip Url browse…
Browse files Browse the repository at this point in the history
…r monitor source type for monitor management (for tech preview).

elastic/uptime#427
elastic/uptime#428
  • Loading branch information
awahab07 committed Jan 6, 2022
1 parent 43202f6 commit 9d5936f
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import 'jest-canvas-mock';
import React from 'react';
import { fireEvent, screen, waitFor } from '@testing-library/react';
import { render } from '../../../lib/helper/rtl_helpers';
import { IPolicyConfigContextProvider } from '../contexts/policy_config_context';
import { SourceField, defaultValues } from './source_field';
import { BrowserSimpleFieldsContextProvider } from '../contexts';
import { BrowserSimpleFieldsContextProvider, PolicyConfigContextProvider } from '../contexts';

jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({
...jest.requireActual('@elastic/eui/lib/services/accessibility/html_id_generator'),
Expand Down Expand Up @@ -43,11 +44,15 @@ jest.mock('../../../../../../../src/plugins/kibana_react/public', () => {
const onChange = jest.fn();

describe('<SourceField />', () => {
const WrappedComponent = () => {
const WrappedComponent = ({
isZipUrlSourceEnabled,
}: Omit<IPolicyConfigContextProvider, 'children'>) => {
return (
<BrowserSimpleFieldsContextProvider>
<SourceField onChange={onChange} />
</BrowserSimpleFieldsContextProvider>
<PolicyConfigContextProvider isZipUrlSourceEnabled={isZipUrlSourceEnabled}>
<BrowserSimpleFieldsContextProvider>
<SourceField onChange={onChange} />
</BrowserSimpleFieldsContextProvider>
</PolicyConfigContextProvider>
);
};

Expand All @@ -66,4 +71,16 @@ describe('<SourceField />', () => {
expect(onChange).toBeCalledWith({ ...defaultValues, zipUrl });
});
});

it('shows ZipUrl source type by default', async () => {
render(<WrappedComponent />);

expect(screen.getByTestId('syntheticsSourceTab__zipUrl')).toBeInTheDocument();
});

it('does not show ZipUrl source type when isZipUrlSourceEnabled = false', async () => {
render(<WrappedComponent isZipUrlSourceEnabled={false} />);

expect(screen.queryByTestId('syntheticsSourceTab__zipUrl')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import {
EuiTabbedContent,
EuiTabbedContentTab,
EuiFormRow,
EuiFieldText,
EuiFieldPassword,
Expand All @@ -18,6 +19,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { usePolicyConfigContext } from '../contexts';
import { OptionalLabel } from '../optional_label';
import { CodeEditor } from '../code_editor';
import { ScriptRecorderFields } from './script_recorder_fields';
Expand Down Expand Up @@ -59,18 +61,21 @@ export const defaultValues = {
fileName: '',
};

const getDefaultTab = (defaultConfig: SourceConfig) => {
const getDefaultTab = (defaultConfig: SourceConfig, isZipUrlSourceEnabled = true) => {
if (defaultConfig.inlineScript && defaultConfig.isGeneratedScript) {
return SourceType.SCRIPT_RECORDER;
} else if (defaultConfig.inlineScript) {
return SourceType.INLINE;
}

return SourceType.ZIP;
return isZipUrlSourceEnabled ? SourceType.ZIP : SourceType.INLINE;
};

export const SourceField = ({ onChange, defaultConfig = defaultValues }: Props) => {
const [sourceType, setSourceType] = useState<SourceType>(getDefaultTab(defaultConfig));
const { isZipUrlSourceEnabled } = usePolicyConfigContext();
const [sourceType, setSourceType] = useState<SourceType>(
getDefaultTab(defaultConfig, isZipUrlSourceEnabled)
);
const [config, setConfig] = useState<SourceConfig>(defaultConfig);

useEffect(() => {
Expand All @@ -84,9 +89,10 @@ export const SourceField = ({ onChange, defaultConfig = defaultValues }: Props)
/>
);

const tabs = [
const zipUrlSourceTabId = 'syntheticsBrowserZipURLConfig';
const allTabs = [
{
id: 'syntheticsBrowserZipURLConfig',
id: zipUrlSourceTabId,
name: zipUrlLabel,
'data-test-subj': `syntheticsSourceTab__zipUrl`,
content: (
Expand Down Expand Up @@ -329,6 +335,10 @@ export const SourceField = ({ onChange, defaultConfig = defaultValues }: Props)
},
];

const tabs = isZipUrlSourceEnabled
? allTabs
: allTabs.filter((tab: EuiTabbedContentTab) => tab.id !== zipUrlSourceTabId);

return (
<EuiTabbedContent
tabs={tabs}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import React, { createContext, useContext, useMemo, useState } from 'react';
import { ServiceLocations } from '../../../../common/runtime_types/monitor_management';
import { ScheduleUnit, ServiceLocations } from '../../../../common/runtime_types';
import { DataStream } from '../types';

interface IPolicyConfigContext {
Expand All @@ -19,13 +19,15 @@ interface IPolicyConfigContext {
defaultMonitorType: DataStream;
isTLSEnabled?: boolean;
isZipUrlTLSEnabled?: boolean;
isZipUrlSourceEnabled?: boolean;
defaultIsTLSEnabled?: boolean;
defaultIsZipUrlTLSEnabled?: boolean;
isEditable?: boolean;
defaultName?: string;
name?: string;
defaultLocations?: ServiceLocations;
locations?: ServiceLocations;
allowedScheduleUnits?: ScheduleUnit[];
}

export interface IPolicyConfigContextProvider {
Expand All @@ -36,6 +38,8 @@ export interface IPolicyConfigContextProvider {
defaultName?: string;
defaultLocations?: ServiceLocations;
isEditable?: boolean;
isZipUrlSourceEnabled?: boolean;
allowedScheduleUnits?: ScheduleUnit[];
}

export const initialValue = DataStream.HTTP;
Expand Down Expand Up @@ -65,6 +69,8 @@ const defaultContext: IPolicyConfigContext = {
defaultName: '',
defaultLocations: [],
isEditable: false,
isZipUrlSourceEnabled: true,
allowedScheduleUnits: [ScheduleUnit.MINUTES, ScheduleUnit.SECONDS],
};

export const PolicyConfigContext = createContext(defaultContext);
Expand All @@ -77,6 +83,8 @@ export function PolicyConfigContextProvider<ExtraFields = unknown>({
defaultName = '',
defaultLocations = [],
isEditable = false,
isZipUrlSourceEnabled = true,
allowedScheduleUnits = [ScheduleUnit.MINUTES, ScheduleUnit.SECONDS],
}: IPolicyConfigContextProvider) {
const [monitorType, setMonitorType] = useState<DataStream>(defaultMonitorType);
const [name, setName] = useState<string>(defaultName);
Expand All @@ -102,11 +110,14 @@ export function PolicyConfigContextProvider<ExtraFields = unknown>({
defaultLocations,
locations,
setLocations,
};
isZipUrlSourceEnabled,
allowedScheduleUnits,
} as IPolicyConfigContext;
}, [
monitorType,
defaultMonitorType,
isTLSEnabled,
isZipUrlSourceEnabled,
isZipUrlTLSEnabled,
defaultIsTLSEnabled,
defaultIsZipUrlTLSEnabled,
Expand All @@ -115,6 +126,7 @@ export function PolicyConfigContextProvider<ExtraFields = unknown>({
defaultName,
locations,
defaultLocations,
allowedScheduleUnits,
]);

return <PolicyConfigContext.Provider value={value} children={children} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,80 @@
* 2.0.
*/

import { waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React, { useState } from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import { render } from '../../lib/helper/rtl_helpers';
import { PolicyConfigContextProvider } from './contexts';
import { IPolicyConfigContextProvider } from './contexts/policy_config_context';
import { ScheduleField } from './schedule_field';
import { ScheduleUnit } from './types';

describe('<ScheduleField/>', () => {
const number = '1';
const unit = ScheduleUnit.MINUTES;
const WrappedComponent = () => {
const WrappedComponent = ({
allowedScheduleUnits,
}: Omit<IPolicyConfigContextProvider, 'children'>) => {
const [config, setConfig] = useState({
number,
unit,
});

return (
<ScheduleField
number={config.number}
unit={config.unit}
onChange={(value) => setConfig(value)}
/>
<PolicyConfigContextProvider allowedScheduleUnits={allowedScheduleUnits}>
<ScheduleField
number={config.number}
unit={config.unit}
onChange={(value) => setConfig(value)}
/>
</PolicyConfigContextProvider>
);
};

it('hanles schedule', () => {
it('shows all options by default (allowedScheduleUnits is not provided)', () => {
const { getByText } = render(<WrappedComponent />);
expect(getByText('Minutes')).toBeInTheDocument();
expect(getByText('Seconds')).toBeInTheDocument();
});

it('shows only Minutes when allowedScheduleUnits = [ScheduleUnit.Minutes])', () => {
const { queryByText } = render(
<WrappedComponent allowedScheduleUnits={[ScheduleUnit.MINUTES]} />
);
expect(queryByText('Minutes')).toBeInTheDocument();
expect(queryByText('Seconds')).not.toBeInTheDocument();
});

it('shows only Seconds when allowedScheduleUnits = [ScheduleUnit.Seconds])', () => {
const { queryByText } = render(
<WrappedComponent allowedScheduleUnits={[ScheduleUnit.SECONDS]} />
);
expect(queryByText('Minutes')).not.toBeInTheDocument();
expect(queryByText('Seconds')).toBeInTheDocument();
});

it('only accepts whole number when allowedScheduleUnits = [ScheduleUnit.Minutes])', async () => {
const { getByTestId } = render(
<WrappedComponent allowedScheduleUnits={[ScheduleUnit.MINUTES]} />
);
const input = getByTestId('scheduleFieldInput') as HTMLInputElement;
const select = getByTestId('scheduleFieldSelect') as HTMLInputElement;
expect(input.value).toBe(number);
expect(select.value).toBe(ScheduleUnit.MINUTES);

userEvent.clear(input);
userEvent.type(input, '1.5');

// Click away to cause blur on input
userEvent.click(select);

await waitFor(() => {
expect(input.value).toBe('2');
});
});

it('handles schedule', () => {
const { getByText, getByTestId } = render(<WrappedComponent />);
const input = getByTestId('scheduleFieldInput') as HTMLInputElement;
const select = getByTestId('scheduleFieldSelect') as HTMLInputElement;
Expand All @@ -38,7 +87,7 @@ describe('<ScheduleField/>', () => {
expect(getByText('Minutes')).toBeInTheDocument();
});

it('hanles on change', async () => {
it('handles on change', async () => {
const { getByText, getByTestId } = render(<WrappedComponent />);
const input = getByTestId('scheduleFieldInput') as HTMLInputElement;
const select = getByTestId('scheduleFieldSelect') as HTMLInputElement;
Expand All @@ -47,13 +96,14 @@ describe('<ScheduleField/>', () => {
expect(input.value).toBe(number);
expect(select.value).toBe(unit);

fireEvent.change(input, { target: { value: newNumber } });
userEvent.clear(input);
userEvent.type(input, newNumber);

await waitFor(() => {
expect(input.value).toBe(newNumber);
});

fireEvent.change(select, { target: { value: newUnit } });
userEvent.selectOptions(select, newUnit);

await waitFor(() => {
expect(select.value).toBe(newUnit);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
* 2.0.
*/

import React from 'react';
import { i18n } from '@kbn/i18n';

import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { usePolicyConfigContext } from './contexts';
import { ConfigKey, MonitorFields, ScheduleUnit } from './types';

interface Props {
Expand All @@ -18,6 +18,14 @@ interface Props {
}

export const ScheduleField = ({ number, onChange, unit }: Props) => {
const { allowedScheduleUnits } = usePolicyConfigContext();
const options = !allowedScheduleUnits?.length
? allOptions
: allOptions.filter((opt) => allowedScheduleUnits.includes(opt.value));

// When only minutes are allowed, don't allow user to input fractional value
const allowedStep = options.length === 1 && options[0].value === ScheduleUnit.MINUTES ? 1 : 'any';

return (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
Expand All @@ -30,13 +38,20 @@ export const ScheduleField = ({ number, onChange, unit }: Props) => {
)}
id="syntheticsFleetScheduleField--number"
data-test-subj="scheduleFieldInput"
step={'any'}
step={allowedStep}
min={1}
value={number}
onChange={(event) => {
const updatedNumber = event.target.value;
onChange({ number: updatedNumber, unit });
}}
onBlur={(event) => {
// Enforce whole number
if (allowedStep === 1) {
const updatedNumber = `${Math.ceil(+event.target.value)}`;
onChange({ number: updatedNumber, unit });
}
}}
/>
</EuiFlexItem>
<EuiFlexItem>
Expand All @@ -61,7 +76,7 @@ export const ScheduleField = ({ number, onChange, unit }: Props) => {
);
};

const options = [
const allOptions = [
{
text: i18n.translate('xpack.uptime.createPackagePolicy.stepConfigure.scheduleField.seconds', {
defaultMessage: 'Seconds',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
*/

import React, { useMemo } from 'react';
import { ConfigKey, MonitorFields, TLSFields, DataStream } from '../../../common/runtime_types';
import {
ConfigKey,
MonitorFields,
TLSFields,
DataStream,
ScheduleUnit,
} from '../../../common/runtime_types';
import { useTrackPageview } from '../../../../observability/public';
import { SyntheticsProviders } from '../fleet_package/contexts';
import { PolicyConfig } from '../fleet_package/types';
Expand Down Expand Up @@ -71,6 +77,8 @@ export const EditMonitorConfig = ({ monitor }: Props) => {
defaultName: defaultConfig?.name || '', // TODO - figure out typing concerns for name
defaultLocations: defaultConfig.locations,
isEditable: true,
isZipUrlSourceEnabled: false,
allowedScheduleUnits: [ScheduleUnit.MINUTES],
}}
httpDefaultValues={fullDefaultConfig[DataStream.HTTP]}
tcpDefaultValues={fullDefaultConfig[DataStream.TCP]}
Expand Down
Loading

0 comments on commit 9d5936f

Please sign in to comment.