Skip to content

Commit

Permalink
extend resourceDropdown to showbadges and fixes review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
invincibleJai committed Mar 24, 2020
1 parent 77d5387 commit 3112220
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 149 deletions.
@@ -1,8 +1,33 @@
import * as _ from 'lodash';
import * as React from 'react';
import * as fuzzy from 'fuzzysearch';
import { Dropdown, FirehoseResult, LoadingInline } from '@console/internal/components/utils';
import { K8sResourceKind } from '@console/internal/module/k8s';
import {
Dropdown,
FirehoseResult,
LoadingInline,
ResourceIcon,
} from '@console/internal/components/utils';
import {
K8sResourceKind,
referenceForModel,
K8sKind,
modelFor,
referenceFor,
} from '@console/internal/module/k8s';

type DropdownItemProps = {
model: K8sKind;
name: string;
};

const DropdownItem: React.FC<DropdownItemProps> = ({ model, name }) => (
<span className="co-resource-item">
<span>
<ResourceIcon kind={referenceForModel(model)} />
</span>
<span className="co-truncate show co-nowrap small">{name}</span>
</span>
);

interface State {
items: {};
Expand Down Expand Up @@ -39,6 +64,8 @@ interface ResourceDropdownProps {
resourceFilter?: (resource: K8sResourceKind) => boolean;
onChange?: (key: string, name?: string, isListEmpty?: boolean) => void;
onLoad?: (items: { [key: string]: string }) => void;
showBadge?: boolean;
autocompleteFilter?: (strText: string, item: object) => boolean;
}

class ResourceDropdown extends React.Component<ResourceDropdownProps, State> {
Expand All @@ -55,7 +82,16 @@ class ResourceDropdown extends React.Component<ResourceDropdownProps, State> {
}

UNSAFE_componentWillReceiveProps(nextProps: ResourceDropdownProps) {
const { loaded, loadError, autoSelect, selectedKey, placeholder, onLoad } = nextProps;
const {
loaded,
loadError,
autoSelect,
selectedKey,
placeholder,
onLoad,
title,
actionItems,
} = nextProps;

if (!loaded) {
this.setState({ title: <LoadingInline /> });
Expand All @@ -76,6 +112,12 @@ class ResourceDropdown extends React.Component<ResourceDropdownProps, State> {
}

const resourceList = this.getDropdownList({ ...this.props, ...nextProps }, true);
// set placeholder as title if resourceList is empty no actionItems are there
if (loaded && _.isEmpty(resourceList) && !actionItems && placeholder && !title) {
this.setState({
title: <span className="btn-dropdown__item--placeholder">{placeholder}</span>,
});
}
this.setState({ items: resourceList });
if (nextProps.loaded && onLoad) {
onLoad(resourceList);
Expand All @@ -100,6 +142,7 @@ class ResourceDropdown extends React.Component<ResourceDropdownProps, State> {
dataSelector,
transformLabel,
allSelectorItem,
showBadge = false,
}: ResourceDropdownProps,
updateSelection: boolean,
) => {
Expand All @@ -115,7 +158,17 @@ class ResourceDropdown extends React.Component<ResourceDropdownProps, State> {
dataValue = _.get(resource, dataSelector);
}
if (dataValue) {
acc[dataValue] = transformLabel ? transformLabel(resource) : dataValue;
if (showBadge) {
acc[dataValue] = (
<DropdownItem
key={resource.metadata.uid}
model={modelFor(referenceFor(resource))}
name={dataValue}
/>
);
} else {
acc[dataValue] = transformLabel ? transformLabel(resource) : dataValue;
}
}
return acc;
},
Expand Down Expand Up @@ -180,7 +233,7 @@ class ResourceDropdown extends React.Component<ResourceDropdownProps, State> {
menuClassName={this.props.menuClassName}
buttonClassName={this.props.buttonClassName}
titlePrefix={this.props.titlePrefix}
autocompleteFilter={fuzzy}
autocompleteFilter={this.props.autocompleteFilter || fuzzy}
actionItems={this.props.actionItems}
items={this.state.items}
onChange={this.onChange}
Expand Down
Expand Up @@ -12,8 +12,11 @@ import { useFormikValidationFix } from '../../hooks';
export interface ResourceDropdownFieldProps extends DropdownFieldProps {
dataSelector: string[] | number[] | symbol[];
resources: FirehoseResource[];
showBadge?: boolean;
onLoad?: (items: { [key: string]: string }) => void;
resourceFilter?: (resource: K8sResourceKind) => boolean;
autoSelect?: boolean;
placeholder?: string;
}
const ResourceDropdownField: React.FC<ResourceDropdownFieldProps> = ({
label,
Expand Down
Expand Up @@ -44,7 +44,7 @@ export interface DropdownFieldProps extends FieldProps {
title?: React.ReactNode;
fullWidth?: boolean;
disabled?: boolean;
autocompleteFilter?: (text: string, item: object, key: string) => boolean;
autocompleteFilter?: (text: string, item: object, key?: string) => boolean;
onChange?: (value: string) => void;
}

Expand Down
Expand Up @@ -2,18 +2,16 @@ import * as React from 'react';
import * as _ from 'lodash';
import { useField, useFormikContext, FormikValues } from 'formik';
import { LoadingInline } from '@console/internal/components/utils';
import { FormGroup, Alert } from '@patternfly/react-core';
import { StarIcon } from '@patternfly/react-icons';
import { FormGroup } from '@patternfly/react-core';
import { getFieldId } from '@console/shared';
import SelectorCard from './SelectorCard';
import './ItemSelectorField.scss';

interface Item {
name: string;
title: string;
displayName: string;
displayName?: string;
iconUrl?: string;
[x: string]: any;
}

interface NormalizedItem {
Expand All @@ -23,35 +21,32 @@ interface NormalizedItem {
interface ItemSelectorFieldProps {
itemList: NormalizedItem;
name: string;
label?: string;
loadingItems?: boolean;
isRecommending?: boolean;
recommended?: string;
couldNotRecommend?: boolean;
label?: string;
onSelect?: (name: string) => void;
}

const ItemSelectorField: React.FC<ItemSelectorFieldProps> = ({
itemList,
name,
label,
loadingItems,
isRecommending,
recommended,
couldNotRecommend,
onSelect,
label,
}) => {
const [selected, { error: selectedError, touched: selectedTouched }] = useField(name);
const { setFieldValue, setFieldTouched, validateForm } = useFormikContext<FormikValues>();
const itemCount = _.keys(itemList).length;

const handleItemChange = React.useCallback(
(image: string) => {
setFieldValue(name, image);
(item: string) => {
setFieldValue(name, item);
setFieldTouched(name, true);
validateForm();
onSelect && onSelect(item);
},
[name, setFieldValue, setFieldTouched, validateForm],
[name, setFieldValue, setFieldTouched, validateForm, onSelect],
);

React.useEffect(() => {
Expand All @@ -68,40 +63,18 @@ const ItemSelectorField: React.FC<ItemSelectorFieldProps> = ({
return null;
}

const fieldId = getFieldId(name, 'selector');
const fieldId = getFieldId(name, 'itemselector');
const isValid = !(selectedTouched && selectedError);
const errorMessage = !isValid ? selectedError : '';

return (
<FormGroup
fieldId={fieldId}
label={label}
helperTextInvalid={errorMessage}
isValid={isValid}
label={label}
isRequired
>
{isRecommending && (
<>
<LoadingInline /> Detecting recommended {label}...
</>
)}
{recommended && (
<>
<Alert variant="success" title="Builder image(s) detected." isInline>
Recommended {label} are represented by{' '}
<StarIcon style={{ color: 'var(--pf-global--primary-color--100)' }} /> icon.
</Alert>
<br />
</>
)}
{couldNotRecommend && (
<>
<Alert variant="warning" title="Unable to detect the builder image." isInline>
Select the most appropriate one from the list to continue.
</Alert>
<br />
</>
)}
{loadingItems ? (
<LoadingInline />
) : (
Expand All @@ -115,7 +88,7 @@ const ItemSelectorField: React.FC<ItemSelectorFieldProps> = ({
displayName={item.displayName}
selected={selected.value === item.name}
recommended={recommended === item.name}
onChange={onSelect || handleItemChange}
onChange={handleItemChange}
/>
))}
</div>
Expand Down
Expand Up @@ -8,8 +8,8 @@ interface SelectorCardProps {
title: string;
iconUrl: string;
name: string;
displayName: string;
selected: boolean;
displayName?: string;
selected?: boolean;
recommended?: boolean;
onChange: (name: string) => void;
}
Expand All @@ -33,7 +33,7 @@ const SelectorCard: React.FC<SelectorCardProps> = ({
onClick={() => onChange(name)}
>
<CardHeader>
<img className="odc-selector-card__icon" src={iconUrl} alt={displayName} />
<img className="odc-selector-card__icon" src={iconUrl} alt={displayName ?? title} />
</CardHeader>
<CardBody>
<span className="odc-selector-card__title">{title}</span>
Expand Down
6 changes: 2 additions & 4 deletions frontend/packages/dev-console/src/components/EmptyState.tsx
Expand Up @@ -124,10 +124,8 @@ const ODCEmptyState: React.FC<Props> = ({
<GalleryItem key="gallery-eventsource">
<CatalogTile
className="odc-empty-state__tile"
onClick={(e: React.SyntheticEvent) =>
navigateTo(e, `/event-source?preselected-ns=${activeNamespace}`)
}
href={`/event-source?preselected-ns=${activeNamespace}`}
onClick={(e: React.SyntheticEvent) => navigateTo(e, `/event-source`)}
href={`/event-source`}
title="Event Source"
iconClass="pficon-help"
description="Create an event source and sink it to Knative service"
Expand Down
@@ -1,8 +1,11 @@
import * as React from 'react';
import * as _ from 'lodash';
import { useFormikContext, FormikValues } from 'formik';
import { LoadingInline } from '@console/internal/components/utils';
import { FormGroup, Alert } from '@patternfly/react-core';
import { StarIcon } from '@patternfly/react-icons';
import { getFieldId, ItemSelectorField } from '@console/shared';
import { NormalizedBuilderImages } from '../../../utils/imagestream-utils';
import { ItemSelectorField } from '@console/shared';

export interface BuilderImageSelectorProps {
loadingImageStream: boolean;
Expand All @@ -14,7 +17,6 @@ const BuilderImageSelector: React.FC<BuilderImageSelectorProps> = ({
builderImages,
}) => {
const { values, setFieldValue, setFieldTouched } = useFormikContext<FormikValues>();
const { isRecommending, recommended, couldNotRecommend } = values?.image;

React.useEffect(() => {
if (values.image.selected) {
Expand All @@ -26,16 +28,39 @@ const BuilderImageSelector: React.FC<BuilderImageSelectorProps> = ({
}
}, [values.image.selected, setFieldValue, setFieldTouched, builderImages]);

const fieldId = getFieldId('image.name', 'selector');

return (
<ItemSelectorField
itemList={builderImages}
name="image.selected"
label="builder images"
loadingItems={loadingImageStream}
isRecommending={isRecommending}
recommended={recommended}
couldNotRecommend={couldNotRecommend}
/>
<FormGroup fieldId={fieldId} label="Builder Image">
{values.image.isRecommending && (
<>
<LoadingInline /> Detecting recommended builder images...
</>
)}
{values.image.recommended && (
<>
<Alert variant="success" title="Builder image(s) detected." isInline>
Recommended builder images are represented by{' '}
<StarIcon style={{ color: 'var(--pf-global--primary-color--100)' }} /> icon.
</Alert>
<br />
</>
)}
{values.image.couldNotRecommend && (
<>
<Alert variant="warning" title="Unable to detect the builder image." isInline>
Select the most appropriate one from the list to continue.
</Alert>
<br />
</>
)}
<ItemSelectorField
itemList={builderImages}
name="image.selected"
loadingItems={loadingImageStream}
recommended={values.image.recommended}
/>
</FormGroup>
);
};

Expand Down
Expand Up @@ -15,7 +15,6 @@ import { getEventSourcesDepResource } from '../../utils/create-eventsources-util
interface EventSourceProps {
namespace: string;
projects?: FirehoseList;
ksservices?: FirehoseList[];
}

interface StateProps {
Expand All @@ -24,7 +23,7 @@ interface StateProps {

type Props = EventSourceProps & StateProps;

const EventSource: React.FC<Props> = ({ namespace, projects, activeApplication, ksservices }) => {
const EventSource: React.FC<Props> = ({ namespace, projects, activeApplication }) => {
const eventSourceData = {
cronjobsource: {
data: '',
Expand Down Expand Up @@ -81,7 +80,7 @@ const EventSource: React.FC<Props> = ({ namespace, projects, activeApplication,
onReset={history.goBack}
validationSchema={eventSourceValidationSchema}
>
{(props) => <EventSourceForm {...props} projects={projects} services={ksservices} />}
{(props) => <EventSourceForm {...props} namespace={namespace} projects={projects} />}
</Formik>
);
};
Expand Down

0 comments on commit 3112220

Please sign in to comment.