Skip to content

Commit

Permalink
adds support for sinkBinding Source
Browse files Browse the repository at this point in the history
  • Loading branch information
invincibleJai committed Mar 27, 2020
1 parent c359d02 commit 198686f
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 29 deletions.
Expand Up @@ -10,7 +10,10 @@ import { FirehoseList } from '@console/dev-console/src/components/import/import-
import { eventSourceValidationSchema } from './eventSource-validation-utils';
import EventSourceForm from './EventSourceForm';
import { EventSources, EventSourceFormData } from './import-types';
import { getEventSourcesDepResource } from '../../utils/create-eventsources-utils';
import {
getEventSourcesDepResource,
getEventSourceData,
} from '../../utils/create-eventsources-utils';

interface EventSourceProps {
namespace: string;
Expand All @@ -24,12 +27,6 @@ interface StateProps {
type Props = EventSourceProps & StateProps;

const EventSource: React.FC<Props> = ({ namespace, projects, activeApplication }) => {
const eventSourceData = {
cronjobsource: {
data: '',
schedule: '',
},
};
const typeEventSource = EventSources.CronJobSource;
const initialValues: EventSourceFormData = {
project: {
Expand All @@ -44,11 +41,11 @@ const EventSource: React.FC<Props> = ({ namespace, projects, activeApplication }
},
name: '',
sink: {
knativeService: 'event-greeter',
knativeService: '',
},
type: typeEventSource,
data: {
[typeEventSource.toLowerCase()]: eventSourceData[typeEventSource.toLowerCase()],
[typeEventSource.toLowerCase()]: getEventSourceData(typeEventSource.toLowerCase()),
},
};

Expand Down
Expand Up @@ -6,6 +6,7 @@ import { Form } from '@patternfly/react-core';
import AppSection from '@console/dev-console/src/components/import/app/AppSection';
import { FirehoseList } from '@console/dev-console/src/components/import/import-types';
import CronJobSection from './event-sources/CronJobSection';
import SinkBindingSection from './event-sources/SinkBindingSection';
import SinkSection from './event-sources/SinkSection';
import { EventSources } from './import-types';
import EventSourcesSelector from './event-sources/EventSourcesSelector';
Expand All @@ -30,6 +31,7 @@ const EventSourceForm: React.FC<FormikProps<FormikValues> & OwnProps> = ({
<Form className="co-deploy-image" onSubmit={handleSubmit}>
<EventSourcesSelector eventSourceList={useEventSourceList()} />
{values.type === EventSources.CronJobSource && <CronJobSection />}
{values.type === EventSources.SinkBinding && <SinkBindingSection />}
<SinkSection namespace={namespace} />
<AppSection
project={values.project}
Expand Down
@@ -1,16 +1,30 @@
import * as React from 'react';
import { useFormikContext, FormikValues } from 'formik';
import { ItemSelectorField } from '@console/shared';
import FormSection from '@console/dev-console/src/components/import/section/FormSection';
import { NormalizedEventSources } from '../import-types';
import { getEventSourceData } from '../../../utils/create-eventsources-utils';

interface EventSourcesSelectorProps {
eventSourceList: NormalizedEventSources;
}

const EventSourcesSelector: React.FC<EventSourcesSelectorProps> = ({ eventSourceList }) => (
<FormSection title="Type" fullWidth>
<ItemSelectorField itemList={eventSourceList} name="type" />
</FormSection>
);
const EventSourcesSelector: React.FC<EventSourcesSelectorProps> = ({ eventSourceList }) => {
const { setFieldValue, setFieldTouched, validateForm } = useFormikContext<FormikValues>();
const handleItemChange = React.useCallback(
(item: string) => {
const name = `data.${item.toLowerCase()}`;
setFieldValue(name, getEventSourceData(item.toLowerCase()));
setFieldTouched(name, true);
validateForm();
},
[setFieldValue, setFieldTouched, validateForm],
);
return (
<FormSection title="Type" fullWidth>
<ItemSelectorField itemList={eventSourceList} name="type" onSelect={handleItemChange} />
</FormSection>
);
};

export default EventSourcesSelector;
@@ -0,0 +1,65 @@
import * as React from 'react';
import * as _ from 'lodash';
import { useFormikContext, FormikValues } from 'formik';
import { TextInputTypes, FormGroup } from '@patternfly/react-core';
import { InputField, getFieldId } from '@console/shared';
import { NameValueEditor } from '@console/internal/components/utils/name-value-editor';
import FormSection from '@console/dev-console/src/components/import/section/FormSection';

const SinkBindingSection: React.FC = () => {
const { values, setFieldValue } = useFormikContext<FormikValues>();
const initVal = values?.data?.sinkbinding?.subject?.selector?.matchLabels || {};
const initialValueResources = !_.isEmpty(initVal)
? _.map(initVal, (key, val) => [val, key])
: [['', '']];
const [nameValue, setNameValue] = React.useState(initialValueResources);
const handleNameValuePairs = React.useCallback(
({ nameValuePairs }) => {
let updatedNameValuePairs = {};
_.forEach(nameValuePairs, ([name, value]) => {
if (value.length) {
updatedNameValuePairs = { ...updatedNameValuePairs, [name]: value };
return updatedNameValuePairs;
}
return updatedNameValuePairs;
});
setNameValue(nameValuePairs);
setFieldValue('data.sinkbinding.subject.selector.matchLabels', updatedNameValuePairs);
},
[setFieldValue],
);
const fieldId = getFieldId(values.type, 'subject-matchLabels');
return (
<FormSection title="Subject">
<InputField
data-test-id="sinkbinding-apiversion-field"
type={TextInputTypes.text}
name="data.sinkbinding.subject.apiVersion"
label="apiVersion"
helpText="apiVersion i.e apps/v1"
required
/>
<InputField
data-test-id="sinkbinding-kind-field"
type={TextInputTypes.text}
name="data.sinkbinding.subject.kind"
label="Kind"
helpText="kind i.e Deployment"
required
/>
<FormGroup fieldId={fieldId} label="Match Labels">
<NameValueEditor
nameValuePairs={nameValue}
valueString="Value"
nameString="Name"
addString="Add Values"
readOnly={false}
allowSorting={false}
updateParentData={handleNameValuePairs}
/>
</FormGroup>
</FormSection>
);
};

export default SinkBindingSection;
Expand Up @@ -34,7 +34,7 @@ const SinkSection: React.FC<SinkSectionProps> = ({ namespace }) => {
dataSelector={['metadata', 'name']}
fullWidth
required
placeholder="Knative Service"
placeholder="Select Knative Service"
showBadge
onChange={onChange}
autocompleteFilter={autocompleteFilter}
Expand Down
@@ -0,0 +1,40 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import { InputField } from '@console/shared';
import { NameValueEditor } from '@console/internal/components/utils/name-value-editor';
import FormSection from '@console/dev-console/src/components/import/section/FormSection';
import SinkBindingSection from '../SinkBindingSection';

jest.mock('formik', () => ({
useField: jest.fn(() => [{}, {}]),
useFormikContext: jest.fn(() => ({
setFieldValue: jest.fn(),
setFieldTouched: jest.fn(),
validateForm: jest.fn(),
values: {
type: 'SinkBinding',
},
})),
getFieldId: jest.fn(),
}));
describe('SinkBindingSection', () => {
it('should render FormSection', () => {
const wrapper = shallow(<SinkBindingSection />);
expect(wrapper.find(FormSection)).toHaveLength(1);
expect(wrapper.find(FormSection).props().title).toBe('Subject');
});

it('should render NameValueEditor', () => {
const wrapper = shallow(<SinkBindingSection />);
const nameValueEditorField = wrapper.find(NameValueEditor);
expect(nameValueEditorField).toHaveLength(1);
expect(nameValueEditorField.props().nameString).toBe('Name');
expect(nameValueEditorField.props().valueString).toBe('Value');
});

it('should render InputFields', () => {
const wrapper = shallow(<SinkBindingSection />);
const inputFieldFieldItems = wrapper.find(InputField);
expect(inputFieldFieldItems).toHaveLength(2);
});
});
Expand Up @@ -10,21 +10,43 @@ const sinkServiceSchema = yup.object().shape({
knativeService: yup.string().required('Required'),
});

export const cronJobSpecSchema = yup.object().when('type', {
is: EventSources.CronJobSource,
then: yup.object().shape({
cronjobsource: yup.object().shape({
data: yup
.string()
.max(253, 'Cannot be longer than 253 characters.')
.required('Required'),
schedule: yup
.string()
.max(253, 'Cannot be longer than 253 characters.')
.required('Required'),
export const cronJobSpecSchema = yup
.object()
.when('type', {
is: EventSources.CronJobSource,
then: yup.object().shape({
cronjobsource: yup.object().shape({
data: yup
.string()
.max(253, 'Cannot be longer than 253 characters.')
.required('Required'),
schedule: yup
.string()
.max(253, 'Cannot be longer than 253 characters.')
.required('Required'),
}),
}),
}),
});
})
.when('type', {
is: EventSources.SinkBinding,
then: yup.object().shape({
sinkbinding: yup.object().shape({
subject: yup.object().shape({
selector: yup.object().shape({
matchLabels: yup.object(),
}),
apiVersion: yup
.string()
.max(253, 'Cannot be longer than 253 characters.')
.required('Required'),
kind: yup
.string()
.max(253, 'Cannot be longer than 253 characters.')
.required('Required'),
}),
}),
}),
});

export const eventSourceValidationSchema = yup.object().shape({
project: projectNameValidationSchema,
Expand Down
Expand Up @@ -62,6 +62,24 @@ export const getEventSourcesDepResource = (formData: any): K8sResourceKind => {
return eventSourceResource;
};

export const getEventSourceData = (source: string) => {
const eventSourceData = {
cronjobsource: {
data: '',
schedule: '',
},
sinkbinding: {
subject: {
apiVersion: '',
kind: '',
selector: {
matchLabels: {},
},
},
},
};
return eventSourceData[source];
};
export const useKnativeEventingAccess = (model): boolean => {
const canCreateEventSource = useAccessReview({
group: model.apiGroup,
Expand Down

0 comments on commit 198686f

Please sign in to comment.