Skip to content

Commit

Permalink
remove search button and search status/result for deploy image
Browse files Browse the repository at this point in the history
add validated text

show field required when searchTerm is empty

create scss file  for image search component,  use patternfly validatedOption enum

add data-test-id to ImageSearch component
  • Loading branch information
sahil143 committed Feb 13, 2020
1 parent a80edeb commit 2374d49
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 267 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const InputField: React.FC<InputFieldProps> = ({
helpText,
required,
onChange,
validated,
helpTextInvalid,
...props
}) => {
const [field, { touched, error }] = useField(props.name);
Expand All @@ -20,16 +22,17 @@ const InputField: React.FC<InputFieldProps> = ({
fieldId={fieldId}
label={label}
helperText={helpText}
helperTextInvalid={errorMessage}
isValid={isValid}
helperTextInvalid={errorMessage || helpTextInvalid}
validated={validated}
isRequired={required}
>
<TextInput
{...field}
{...props}
id={fieldId}
isValid={isValid}
isRequired={required}
isValid={isValid}
validated={validated}
aria-describedby={`${fieldId}-helper`}
value={field.value || ''}
onChange={(value, event) => {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { TextInputTypes } from '@patternfly/react-core';
import { TextInputTypes, ValidatedOptions } from '@patternfly/react-core';

export interface FieldProps {
name: string;
label?: string;
helpText?: React.ReactNode;
helpTextInvalid?: React.ReactNode;
required?: boolean;
style?: React.CSSProperties;
isReadOnly?: boolean;
disableDeleteRow?: boolean;
disableAddRow?: boolean;
className?: string;
isDisabled?: boolean;
validated?: ValidatedOptions;
}

export interface InputFieldProps extends FieldProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ export { default as DropdownField } from './DropdownField';
export { default as DroppableFileInputField } from './DroppableFileInputField';
export { default as EnvironmentField } from './EnvironmentField';
export { default as InputField } from './InputField';
export { default as InputSearchField } from './InputSearchField';
export { default as MultiColumnField } from './multi-column-field/MultiColumnField';
export { default as NSDropdownField } from './NSDropdownField';
export { default as NumberSpinnerField } from './NumberSpinnerField';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.odc-imagesearch-helptextinvalid {
color: var(--pf-global--danger-color--200);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,97 +3,139 @@ import * as _ from 'lodash';
import { k8sCreate } from '@console/internal/module/k8s';
import { ImageStreamImportsModel } from '@console/internal/models';
import { useFormikContext, FormikValues } from 'formik';
import { TextInputTypes, Alert, AlertActionCloseButton, Button } from '@patternfly/react-core';
import {
TextInputTypes,
Alert,
AlertActionCloseButton,
Button,
ValidatedOptions,
} from '@patternfly/react-core';
import { SecretTypeAbstraction } from '@console/internal/components/secrets/create-secret';
import { InputSearchField } from '@console/shared';
import { InputField } from '@console/shared';
import { getSuggestedName, getPorts, makePortName } from '../../../utils/imagestream-utils';
import { secretModalLauncher } from '../CreateSecretModal';
import { LoadingInline } from '@console/internal/components/utils';
import { CheckCircleIcon, ExclamationCircleIcon } from '@patternfly/react-icons';

const ImageSearch: React.FC = () => {
const { values, setFieldValue, dirty } = useFormikContext<FormikValues>();
const [newImageSecret, setNewImageSecret] = React.useState('');
const [alertVisible, shouldHideAlert] = React.useState(true);
const [validated, setValidated] = React.useState<ValidatedOptions>(ValidatedOptions.default);
const namespace = values.project.name;

const handleSearch = React.useCallback(
(searchTerm: string) => {
const importImage = {
kind: 'ImageStreamImport',
apiVersion: 'image.openshift.io/v1',
metadata: {
name: 'newapp',
namespace: values.project.name,
},
spec: {
import: false,
images: [
{
from: {
kind: 'DockerImage',
name: _.trim(searchTerm),
},
const handleSearch = React.useCallback(() => {
const searchTermImage = values.searchTerm;
setFieldValue('isSearchingForImage', true);
setValidated(ValidatedOptions.default);
const importImage = {
kind: 'ImageStreamImport',
apiVersion: 'image.openshift.io/v1',
metadata: {
name: 'newapp',
namespace: values.project.name,
},
spec: {
import: false,
images: [
{
from: {
kind: 'DockerImage',
name: _.trim(searchTermImage),
},
],
},
status: {},
};
},
],
},
status: {},
};

k8sCreate(ImageStreamImportsModel, importImage)
.then((imageStreamImport) => {
const status = _.get(imageStreamImport, 'status.images[0].status');
if (status.status === 'Success') {
const name = _.get(imageStreamImport, 'spec.images[0].from.name');
const image = _.get(imageStreamImport, 'status.images[0].image');
const tag = _.get(imageStreamImport, 'status.images[0].tag');
const isi = { name, image, tag, status };
const ports = getPorts(isi);
setFieldValue('isSearchingForImage', false);
setFieldValue('isi.name', name);
setFieldValue('isi.image', image);
setFieldValue('isi.tag', tag);
setFieldValue('isi.status', status);
setFieldValue('isi.ports', ports);
setFieldValue('image.ports', ports);
setFieldValue('image.tag', tag);
!values.name && setFieldValue('name', getSuggestedName(name));
!values.application.name &&
setFieldValue('application.name', `${getSuggestedName(name)}-app`);
// set default port value
const targetPort = _.head(ports);
targetPort && setFieldValue('route.targetPort', makePortName(targetPort));
} else {
setFieldValue('isSearchingForImage', false);
setFieldValue('isi', {});
setFieldValue('isi.status', status.message);
setFieldValue('route.targetPort', null);
}
})
.catch((error) => {
setFieldValue('isi', {});
setFieldValue('isi.status', error.message);
k8sCreate(ImageStreamImportsModel, importImage)
.then((imageStreamImport) => {
const status = _.get(imageStreamImport, 'status.images[0].status');
if (status.status === 'Success') {
const name = _.get(imageStreamImport, 'spec.images[0].from.name');
const image = _.get(imageStreamImport, 'status.images[0].image');
const tag = _.get(imageStreamImport, 'status.images[0].tag');
const isi = { name, image, tag, status };
const ports = getPorts(isi);
setFieldValue('isSearchingForImage', false);
});
},
[setFieldValue, values.application.name, values.name, values.project.name],
);
setFieldValue('isi.name', name);
setFieldValue('isi.image', image);
setFieldValue('isi.tag', tag);
setFieldValue('isi.status', status);
setFieldValue('isi.ports', ports);
setFieldValue('image.ports', ports);
setFieldValue('image.tag', tag);
!values.name && setFieldValue('name', getSuggestedName(name));
!values.application.name &&
setFieldValue('application.name', `${getSuggestedName(name)}-app`);
// set default port value
const targetPort = _.head(ports);
targetPort && setFieldValue('route.targetPort', makePortName(targetPort));
setValidated(ValidatedOptions.success);
} else {
setFieldValue('isSearchingForImage', false);
setFieldValue('isi', {});
setFieldValue('isi.status', status.message);
setFieldValue('route.targetPort', null);
setValidated(ValidatedOptions.error);
}
})
.catch((error) => {
setFieldValue('isi', {});
setFieldValue('isi.status', error.message);
setFieldValue('isSearchingForImage', false);
setValidated(ValidatedOptions.error);
});
}, [setFieldValue, values.application.name, values.name, values.project.name, values.searchTerm]);

const handleSave = (name: string) => {
setNewImageSecret(name);
values.searchTerm && handleSearch(values.searchTerm);
values.searchTerm && handleSearch();
};

const getHelpText = () => {
if (values.isSearchingForImage) {
return (
<span style={{ fontWeight: 'bold' }}>
<LoadingInline />
</span>
);
}
if (!values.isSearchingForImage && validated === ValidatedOptions.success) {
return (
<span style={{ fontWeight: 'bold', color: 'var(--pf-global--success-color--200)' }}>
<CheckCircleIcon /> Validated
</span>
);
}

return '';
};

const helpTextInvalid = validated === ValidatedOptions.error && (
<span className="odc-imagesearch-helptextinvalid">
<ExclamationCircleIcon />
&nbsp;
{values.searchTerm === '' ? 'Required' : values.isi.status}
</span>
);

React.useEffect(() => {
!dirty && values.searchTerm && handleSearch(values.searchTerm);
!dirty && values.searchTerm && handleSearch();
}, [dirty, handleSearch, values.searchTerm]);

return (
<>
<InputSearchField
<InputField
type={TextInputTypes.text}
data-test-id="deploy-image-search-term"
name="searchTerm"
label="Image Name"
onSearch={handleSearch}
placeholder="Enter an image name"
helpText={getHelpText()}
helpTextInvalid={helpTextInvalid}
validated={validated}
onBlur={handleSearch}
data-test-id="deploy-image-search-term"
required
/>
<div className="help-block" id="image-name-help">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import FormSection from '../section/FormSection';
import { imageRegistryType } from '../../../utils/imagestream-utils';
import ImageStream from './ImageStream';
import ImageSearch from './ImageSearch';
import SearchStatus from './SearchStatus';
import SearchResults from './SearchResults';

const ImageSearchSection: React.FC = () => {
const { values, setFieldValue, initialValues } = useFormikContext<FormikValues>();
Expand Down Expand Up @@ -49,8 +47,6 @@ const ImageSearchSection: React.FC = () => {
},
]}
/>
<SearchStatus />
<SearchResults />
</FormSection>
);
};
Expand Down

0 comments on commit 2374d49

Please sign in to comment.