Skip to content

Commit

Permalink
feat(ImportForm): add base form including the source and component se…
Browse files Browse the repository at this point in the history
…ction
  • Loading branch information
sahil143 authored and rohitkrai03 committed May 28, 2024
1 parent 5715421 commit 7165f52
Show file tree
Hide file tree
Showing 20 changed files with 380 additions and 17 deletions.
10 changes: 3 additions & 7 deletions src/components/ApplicationDetails/ApplicationHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,9 @@ export const ApplicationHeader: React.FC<
<ApplicationThumbnail application={application} />
</FlexItem>
<FlexItem alignSelf={{ default: 'alignSelfCenter' }}>
<Flex>
<FlexItem>
<Text component="h1" data-test="details__title">
{application?.spec?.displayName || ''}
</Text>
</FlexItem>
</Flex>
<Text component="h1" data-test="details__title">
{application?.spec?.displayName || ''}
</Text>
</FlexItem>
</Flex>
);
Expand Down
9 changes: 6 additions & 3 deletions src/components/ApplicationDetails/ApplicationThumbnail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ const getThumbnailFromApplication = (application: ApplicationKind) => {
};

export const ApplicationThumbnail: React.FC<
React.PropsWithChildren<{ application: ApplicationKind }>
> = ({ application }) => {
const icon = getThumbnailFromApplication(application);
React.PropsWithChildren<{ application?: ApplicationKind; annotationValue?: number }>
> = ({ application, annotationValue }) => {
const icon =
annotationValue !== undefined
? ICONS[annotationValue]
: getThumbnailFromApplication(application);
return (
<img style={{ height: '70px', verticalAlign: 'top' }} src={icon} alt="Application thumbnail" />
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as React from 'react';
import { Flex, FlexItem, FormSection } from '@patternfly/react-core';
import { useFormikContext } from 'formik';
import { ApplicationThumbnail } from '../../ApplicationDetails/ApplicationThumbnail';
import { InputField } from '../components/InputField';
import { ImportFormValues } from '../type';

const ApplicationSection: React.FunctionComponent<React.PropsWithChildren<unknown>> = () => {
const {
values: { inAppContext },
} = useFormikContext<ImportFormValues>();

return (
<Flex>
<FlexItem>
<ApplicationThumbnail annotationValue={0} />
</FlexItem>
<FlexItem flex={{ default: 'flex_1' }}>
<FormSection>
<InputField
name="application"
label="Application name"
placeholder="Enter name"
isDisabled={inAppContext}
required
dataTest="app-name-field"
className="hac-input-field"
/>
</FormSection>
</FlexItem>
</Flex>
);
};

export default ApplicationSection;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { useField, useFormikContext } from 'formik';
import ApplicationSection from '../ApplicationSection';
import '@testing-library/jest-dom';

jest.mock('formik', () => ({
useFormikContext: jest.fn(),
useField: jest.fn(),
}));

const useFormikContextMock = useFormikContext as jest.Mock;
const useFieldMock = useField as jest.Mock;

describe('ApplicationSection', () => {
it('should disable input field if in app context', () => {
const setValue = jest.fn();
const setTouched = jest.fn();
useFieldMock.mockReturnValue([{}, { value: '', touched: false }, { setValue, setTouched }]);

useFormikContextMock.mockReturnValue({ values: { inAppContext: true } });
render(<ApplicationSection />);
screen.getByText('Name');
expect(screen.getByPlaceholderText('Enter name')).toBeDisabled();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from 'react';
import { Text, TextContent, TextVariants } from '@patternfly/react-core';
import { InputField } from '../components/InputField';
import { SourceSection } from './SourceSection';

export const ComponentSection = () => {
return (
<>
<TextContent>
<Text component={TextVariants.h3}>Component details</Text>
<Text component={TextVariants.p}>
A component is an image built from source code repository.
</Text>
</TextContent>
<SourceSection />
<InputField name="componentName" label="Component name" required />
</>
);
};
32 changes: 32 additions & 0 deletions src/components/ImportForm_new/ComponentSection/GitOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import { ExpandableSection } from '@patternfly/react-core';
import HelpPopover from '../../HelpPopover';
import { InputField } from '../components/InputField';

const GitOptions: React.FC<React.PropsWithChildren<unknown>> = () => {
return (
<ExpandableSection
toggleTextExpanded="Hide advanced Git options"
toggleTextCollapsed="Show advanced Git options"
>
<InputField
name="source.git.revision"
label="Git reference"
// helperText="Optional branch, tag or commit."
data-test="git-reference"
/>

<InputField
name="source.git.context"
label="Context directory"
// helperText="Optional subdirectory for the application source code."
data-test="context-dir"
labelIcon={
<HelpPopover bodyContent="Make sure this path is correct. You might get an error if your build context folder is your root directory but your Dockerfile is in a subdirectory of that folder." />
}
/>
</ExpandableSection>
);
};

export default GitOptions;
24 changes: 24 additions & 0 deletions src/components/ImportForm_new/ComponentSection/SourceSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react';
import { FormSection } from '@patternfly/react-core';
import { InputField } from '../components/InputField';
import GitOptions from './GitOptions';

export const SourceSection = () => {
return (
<FormSection>
<InputField
name="source.git.url"
label="Git repository url"
placeholder="Enter your source"
// onChange={debouncedHandleSourceChange}
// validated={validated}
// helpText={helpText}
// helpTextInvalid={helpTextInvalid}
required
data-test="enter-source"
/>

<GitOptions />
</FormSection>
);
};
8 changes: 8 additions & 0 deletions src/components/ImportForm_new/GitImportActions.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.git-import-actions {
&__sticky {
position: fixed;
bottom: 0;
width: 100%;
padding-top: var(--pf-v5-global--spacer--lg);
}
}
62 changes: 62 additions & 0 deletions src/components/ImportForm_new/GitImportActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as React from 'react';
import {
ActionList,
ActionListItem,
Button,
PageSection,
PageSectionVariants,
} from '@patternfly/react-core';
import classNames from 'classnames';
import { useFormikContext } from 'formik';
import type { ImportFormValues } from './type';

import './GitImportActions.scss';

const GitImportActions: React.FunctionComponent = () => {
const {
values: { inAppContext, showComponent },
isValid,
dirty,
isSubmitting,
setFieldValue,
} = useFormikContext<ImportFormValues>();

const handleComponent = React.useCallback(() => {
setFieldValue('showComponent', true);
}, [setFieldValue]);

return (
<PageSection
className={classNames({ 'git-import-actions__sticky': showComponent })}
variant={PageSectionVariants.light}
hasShadowTop={showComponent}
component="footer"
>
<ActionList>
<ActionListItem>
<Button
type="submit"
isDisabled={!isValid || !dirty || isSubmitting}
isLoading={isSubmitting}
>
{inAppContext ? 'Add component' : 'Create application'}
</Button>
</ActionListItem>
{!showComponent ? (
<ActionListItem>
<Button variant="secondary" onClick={handleComponent}>
Add a component
</Button>
</ActionListItem>
) : null}
<ActionListItem>
<Button variant="link" type="reset">
Cancel
</Button>
</ActionListItem>
</ActionList>
</PageSection>
);
};

export default GitImportActions;
40 changes: 40 additions & 0 deletions src/components/ImportForm_new/GitImportForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from 'react';
import { Form, PageSection } from '@patternfly/react-core';
import { Formik } from 'formik';
import ApplicationSection from './ApplicationSection/ApplicationSection';
import { ComponentSection } from './ComponentSection/ComponentSection';
import GitImportActions from './GitImportActions';
import { PipelineSection } from './PipelineSection/PipelineSection';
import { ImportFormValues } from './type';

export const GitImportForm: React.FC<{ applicationName: string }> = ({ applicationName }) => {
const initialValues: ImportFormValues = {
application: applicationName || '',
inAppContext: !!applicationName,
showComponent: !!applicationName,
};

const handleSubmit = React.useCallback(() => {}, []);
const handleReset = React.useCallback(() => {}, []);

return (
<Formik<ImportFormValues>
initialValues={initialValues}
onSubmit={handleSubmit}
onReset={handleReset}
>
{(formikProps) => {
return (
<Form onSubmit={formikProps.handleSubmit} onReset={formikProps.handleReset}>
<PageSection>
<ApplicationSection />
<ComponentSection />
<PipelineSection />
</PageSection>
<GitImportActions />
</Form>
);
}}
</Formik>
);
};
20 changes: 20 additions & 0 deletions src/components/ImportForm_new/ImportForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as React from 'react';
import { PageSection, PageSectionVariants } from '@patternfly/react-core';
import { useApplicationBreadcrumbs } from '../../utils/breadcrumb-utils';
import PageLayout from '../PageLayout/PageLayout';
import { GitImportForm } from './GitImportForm';

export const ImportForm: React.FC<{ applicationName: string }> = ({ applicationName }) => {
const applicationBreadcrumbs = useApplicationBreadcrumbs(applicationName);
return (
<PageLayout
breadcrumbs={[...applicationBreadcrumbs, { path: '#', name: 'Create an application' }]}
title="Create an application"
description="An application is one or more components that run together."
>
<PageSection variant={PageSectionVariants.light} padding={{ default: 'noPadding' }}>
<GitImportForm applicationName={applicationName} />
</PageSection>
</PageLayout>
);
};
33 changes: 33 additions & 0 deletions src/components/ImportForm_new/PipelineSection/PipelineSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import { useFormikContext } from 'formik';
import { DropdownField } from '../../../shared';
// import { usePipelineTemplates } from './usePipelineTemplate';

export const PipelineSection: React.FunctionComponent = () => {
// const [pipelines, loaded] = usePipelineTemplates();
const { setFieldValue, setFieldTouched } = useFormikContext();

const setValues = React.useCallback(
(type) => {
setFieldValue('pipeline', type);
setFieldTouched('pipeline', true);
},
[setFieldValue, setFieldTouched],
);

// console.log('#################', pipelines, loaded);

return (
<DropdownField
name="pipeline"
label="Pipelines"
data-testid="secret-type-selector"
items={[]}
title="Select a Pipeline"
onChange={setValues}
isDisabled={false}
fullWidth
required
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import { K8sResourceCommon, k8sGetResource } from '@openshift/dynamic-plugin-sdk-utils';
import { ConfigMapModel } from '../../../models';

export const usePipelineTemplates = () => {
const [data, setdata] = React.useState<K8sResourceCommon>();
const [loaded, setLoaded] = React.useState(false);

React.useEffect(() => {
let isMounted = true;
const fetchData = async () => {
try {
const res = await k8sGetResource({
model: ConfigMapModel,
queryOptions: { ns: 'build-service', name: 'build-pipeline-config' },
});
if (isMounted) {
setdata(res);
setLoaded(true);
}
} catch (e) {
// eslint-disable-next-line no-console
console.warn('Error while fetching ConfigMap', e);
if (isMounted) {
setdata(undefined);
setLoaded(false);
}
}
};
fetchData();
return () => {
isMounted = false;
};
}, []);

return [data, loaded];
};
5 changes: 5 additions & 0 deletions src/components/ImportForm_new/components/InputField.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.import-flow {
&__input {
max-width: 750px;
}
}
7 changes: 7 additions & 0 deletions src/components/ImportForm_new/components/InputField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';
// use Input field from 'formik-pf'
import { InputField as FpfInput } from '../../../shared';

export const InputField: React.FunctionComponent<React.ComponentProps<typeof FpfInput>> = (
props,
) => <FpfInput {...props} className="import-flow__input" />;
Loading

0 comments on commit 7165f52

Please sign in to comment.