Skip to content

Commit dbeb081

Browse files
committed
NCL-8934 Update Search and creatable select usages
1 parent 2e862d2 commit dbeb081

File tree

6 files changed

+148
-133
lines changed

6 files changed

+148
-133
lines changed

src/common/constants.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AxiosRequestConfig } from 'axios';
1+
import { AxiosHeaders, AxiosRequestConfig } from 'axios';
22

33
export const PageTitles = {
44
projects: 'Projects',
@@ -97,3 +97,17 @@ export const MESSAGE_WAIT_AND_REFRESH = 'Wait 5 minutes and try to refresh your
9797

9898
// PNC URL base
9999
export const URL_BASE_PATH = '/pnc-web';
100+
101+
export const dummyPaginatedAxiosResponse = {
102+
data: {
103+
content: [],
104+
total: 0,
105+
page: 0,
106+
pageSize: 0,
107+
},
108+
status: 200,
109+
statusText: 'OK',
110+
headers: {},
111+
config: { headers: new AxiosHeaders() },
112+
request: {},
113+
};

src/components/BuildConfigCreateEditPage/BuildConfigCreateEditPage.tsx

Lines changed: 70 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@ import {
1515
TextContent,
1616
TextInput,
1717
} from '@patternfly/react-core';
18-
import { SelectOption as SelectOptionPF } from '@patternfly/react-core/deprecated';
1918
import { ExclamationTriangleIcon, ExternalLinkAltIcon } from '@patternfly/react-icons';
2019
import { CheckIcon } from '@patternfly/react-icons';
2120
import { Operation } from 'fast-json-patch';
22-
import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
21+
import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2322
import { Link, useNavigate, useParams } from 'react-router';
2423

2524
import { BuildConfiguration, Environment, Product, ProductVersion, SCMRepository, SCMRepositoryPage } from 'pnc-api-types-ts';
@@ -28,7 +27,7 @@ import { PncError } from 'common/PncError';
2827
import { breadcrumbData } from 'common/breadcrumbData';
2928
import { buildConfigEntityAttributes } from 'common/buildConfigEntityAttributes';
3029
import { buildTypeData } from 'common/buildTypeData';
31-
import { ButtonTitles, EntityTitles, PageTitles } from 'common/constants';
30+
import { ButtonTitles, EntityTitles, PageTitles, dummyPaginatedAxiosResponse } from 'common/constants';
3231
import { productEntityAttributes } from 'common/productEntityAttributes';
3332
import { scmRepositoryEntityAttributes } from 'common/scmRepositoryEntityAttributes';
3433
import { BuildConfigCreationResponseCustomized } from 'common/types';
@@ -45,7 +44,6 @@ import { ActionConfirmModal } from 'components/ActionConfirmModal/ActionConfirmM
4544
import { ConfigsAddList } from 'components/ConfigsEditList/ConfigsAddList';
4645
import { ConfigsChangesList } from 'components/ConfigsEditList/ConfigsChangesList';
4746
import { ContentBox } from 'components/ContentBox/ContentBox';
48-
import { CreatableSelect } from 'components/CreatableSelect/CreatableSelect';
4947
import { ExpandableSection } from 'components/ExpandableSection/ExpandableSection';
5048
import { FormInput } from 'components/FormInput/FormInput';
5149
import { FormInputHelperText } from 'components/FormInputHelperText/FormInputHelperText';
@@ -63,6 +61,7 @@ import { Toolbar } from 'components/Toolbar/Toolbar';
6361
import { ToolbarItem } from 'components/Toolbar/ToolbarItem';
6462
import { TooltipSimple } from 'components/TooltipSimple/TooltipSimple';
6563
import { TooltipWrapper } from 'components/TooltipWrapper/TooltipWrapper';
64+
import { TypeaheadSelect } from 'components/TypeaheadSelect/TypeaheadSelect';
6665

6766
import * as buildConfigApi from 'services/buildConfigApi';
6867
import * as environmentApi from 'services/environmentApi';
@@ -306,7 +305,9 @@ export const BuildConfigCreateEditPage = ({ isEditPage = false }: IBuildConfigCr
306305

307306
const fetchProductVersions = useCallback(
308307
(requestConfig = {}) => {
309-
return selectedProduct ? productApi.getProductVersions({ id: selectedProduct.id }, requestConfig) : Promise.resolve([]);
308+
return selectedProduct
309+
? productApi.getProductVersions({ id: selectedProduct.id }, requestConfig)
310+
: Promise.resolve(dummyPaginatedAxiosResponse);
310311
},
311312
[selectedProduct]
312313
);
@@ -481,15 +482,15 @@ export const BuildConfigCreateEditPage = ({ isEditPage = false }: IBuildConfigCr
481482

482483
const productSearchSelect = (
483484
<SearchSelect
484-
selectedItem={selectedProduct?.name}
485-
onSelect={(event, _, product: Product) => {
485+
selectedValue={selectedProduct?.name}
486+
onSelect={(_, product) => {
486487
setSelectedProduct(product);
487-
productVersionRegisterObject.onChange(event, '');
488+
productVersionRegisterObject.onChange(undefined, '');
488489
setSelectedProductVersion(undefined);
489490
}}
490-
onClear={(event) => {
491+
onClear={() => {
491492
setSelectedProduct(undefined);
492-
productVersionRegisterObject.onChange(event, '');
493+
productVersionRegisterObject.onChange(undefined, '');
493494
setSelectedProductVersion(undefined);
494495
}}
495496
fetchCallback={productApi.getProducts}
@@ -503,19 +504,19 @@ export const BuildConfigCreateEditPage = ({ isEditPage = false }: IBuildConfigCr
503504
{...productVersionRegisterObject}
504505
render={({ value, validated, onChange }) => (
505506
<SearchSelect
506-
selectedItem={value}
507-
validated={validated}
508-
onSelect={(event, _, productVersion: ProductVersion) => {
509-
onChange(event, productVersion.version);
507+
selectedValue={value}
508+
onSelect={(_, productVersion) => {
509+
onChange(undefined, productVersion?.version || '');
510510
setSelectedProductVersion(productVersion);
511511
}}
512-
onClear={(event) => {
513-
onChange(event, '');
512+
onClear={() => {
513+
onChange(undefined, '');
514514
setSelectedProductVersion(undefined);
515515
}}
516516
fetchCallback={fetchProductVersions}
517517
titleAttribute="version"
518518
placeholderText="Select Version"
519+
validated={validated}
519520
isDisabled={!selectedProduct}
520521
/>
521522
)}
@@ -561,26 +562,29 @@ export const BuildConfigCreateEditPage = ({ isEditPage = false }: IBuildConfigCr
561562
{...register<string>(buildConfigEntityAttributes.environment.id, fieldConfigs.environment)}
562563
render={({ value, validated, onChange }) => (
563564
<SearchSelect
564-
selectedItem={value}
565-
validated={validated}
566-
onSelect={(event, _, environment: Environment) => {
567-
onChange(event, environment.description!);
565+
selectedValue={value}
566+
onSelect={(_, environment) => {
567+
onChange(undefined, environment?.description || '');
568568
setSelectedEnvironment(environment);
569569
}}
570-
onClear={(event) => {
571-
onChange(event, '');
570+
onClear={() => {
571+
onChange(undefined, '');
572572
setSelectedEnvironment(undefined);
573573
}}
574574
fetchCallback={fetchEnvironments}
575575
titleAttribute="description"
576-
placeholderText="Select Environment"
577-
getCustomDescription={(environment: Environment) =>
576+
getCustomDescription={(environment) =>
578577
environment.deprecated ? (
579-
<Icon status="warning">
580-
<ExclamationTriangleIcon /> DEPRECATED
581-
</Icon>
578+
<>
579+
<Icon status="warning">
580+
<ExclamationTriangleIcon />
581+
</Icon>{' '}
582+
DEPRECATED
583+
</>
582584
) : null
583585
}
586+
placeholderText="Select Environment"
587+
validated={validated}
584588
/>
585589
)}
586590
/>
@@ -714,19 +718,19 @@ export const BuildConfigCreateEditPage = ({ isEditPage = false }: IBuildConfigCr
714718
{...register<string>(scmRepositoryEntityAttributes.scmUrl.id, fieldConfigs.scmUrl)}
715719
render={({ value, validated, onChange }) => (
716720
<SearchSelect
717-
selectedItem={value}
718-
validated={validated}
719-
onSelect={(event, _, scmRepository: SCMRepository) => {
720-
onChange(event, scmRepository.internalUrl!);
721+
selectedValue={value}
722+
onSelect={(_, scmRepository) => {
723+
onChange(undefined, scmRepository?.internalUrl || '');
721724
setSelectedScmRepository(scmRepository);
722725
}}
723-
onClear={(event) => {
724-
onChange(event, '');
726+
onClear={() => {
727+
onChange(undefined, '');
725728
setSelectedScmRepository(undefined);
726729
}}
727730
fetchCallback={scmRepositoryApi.getScmRepositories}
728731
titleAttribute="internalUrl"
729732
placeholderText="Select SCM Repository"
733+
validated={validated}
730734
/>
731735
)}
732736
/>
@@ -857,53 +861,45 @@ export const BuildConfigCreateEditPage = ({ isEditPage = false }: IBuildConfigCr
857861
<ServiceContainerLoading {...serviceContainerParameters} title="Build parameters" variant="inline">
858862
<InputGroup>
859863
<InputGroupItem isFill>
860-
<CreatableSelect
861-
onSelect={(_, selection) => {
862-
if (selection) {
863-
setSelectedBuildParamOption(selection as string);
864-
setBuildParamData({
865-
...buildParamData,
866-
[selection as string]: {
867-
value: '',
868-
},
869-
});
870-
setIsBuildParamSelectOpen(false);
871-
}
872-
}}
873-
onCreateOption={(newOption) => {
874-
setSelectedBuildParamOption(undefined);
875-
setBuildParamOptions([...buildParamOptions, { title: newOption }]);
864+
<TypeaheadSelect
865+
isMenuOpen={isBuildParamSelectOpen}
866+
onMenuToggle={setIsBuildParamSelectOpen}
867+
selectedValue={selectedBuildParamOption}
868+
onSelect={(selection) => {
869+
setSelectedBuildParamOption(selection);
876870
setBuildParamData({
877871
...buildParamData,
878-
[newOption]: {
872+
[selection as string]: {
879873
value: '',
880874
},
881875
});
882-
setIsBuildParamSelectOpen(false);
883876
}}
884-
onToggle={(_, value) => setIsBuildParamSelectOpen(value)}
885-
selectedItem={selectedBuildParamOption}
886-
isOpen={isBuildParamSelectOpen}
887-
placeholderText="Select Parameter or type a new one"
877+
onCreateOption={(newOption) => {
878+
setBuildParamOptions([...buildParamOptions, { title: newOption }]);
879+
}}
888880
creatableOptionText="Create custom Parameter"
889-
width="40%"
890-
dropdownDirection="up"
891-
>
892-
{buildParamOptions.map((option, index) => (
893-
<SelectOptionPF
894-
key={index}
895-
value={option.title}
896-
description={
897-
option.title === 'ALIGNMENT_PARAMETERS' ? (
898-
<i>Once selected, more detailed information will be displayed.</i>
899-
) : (
900-
option.description
901-
)
902-
}
903-
isDisabled={!!buildParamData[option.title]}
904-
/>
905-
))}
906-
</CreatableSelect>
881+
onClear={() => {
882+
setSelectedBuildParamOption('');
883+
}}
884+
placeholderText="Select Parameter or type a new one"
885+
selectOptions={useMemo(
886+
() =>
887+
buildParamOptions.map((option) => {
888+
return {
889+
value: option.title,
890+
children: option.title,
891+
isDisabled: !!buildParamData[option.title],
892+
description:
893+
option.title === 'ALIGNMENT_PARAMETERS' ? (
894+
<i>Once selected, more detailed information will be displayed.</i>
895+
) : (
896+
option.description
897+
),
898+
};
899+
}),
900+
[buildParamOptions, buildParamData]
901+
)}
902+
/>
907903
</InputGroupItem>
908904
</InputGroup>
909905
</ServiceContainerLoading>
@@ -920,6 +916,7 @@ export const BuildConfigCreateEditPage = ({ isEditPage = false }: IBuildConfigCr
920916
<TooltipWrapper tooltip="Remove the parameter">
921917
<RemoveItemButton
922918
onRemove={() => {
919+
setSelectedBuildParamOption('');
923920
setBuildParamData(Object.fromEntries(Object.entries(buildParamData).filter(([k]) => k !== key)));
924921
unregister(key);
925922
}}

src/components/DemoPage/DemoPage.tsx

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { ActionGroup, Button, Flex, FlexItem, Form, FormGroup, TextArea, TextInput } from '@patternfly/react-core';
2-
import { Select, SelectOption, SelectOptionObject, SelectVariant } from '@patternfly/react-core/deprecated';
32
import { QuestionCircleIcon } from '@patternfly/react-icons';
43
import { AxiosRequestConfig } from 'axios';
5-
import { MutableRefObject, useCallback, useEffect, useRef, useState } from 'react';
4+
import { MutableRefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';
65

76
import { Build, GroupBuild } from 'pnc-api-types-ts';
87

@@ -31,6 +30,7 @@ import { ScmRepositoryLink } from 'components/ScmRepositoryLink/ScmRepositoryLin
3130
import { ScmRepositoryUrl } from 'components/ScmRepositoryUrl/ScmRepositoryUrl';
3231
import { SearchSelect } from 'components/SearchSelect/SearchSelect';
3332
import { TooltipWrapper } from 'components/TooltipWrapper/TooltipWrapper';
33+
import { TypeaheadSelect } from 'components/TypeaheadSelect/TypeaheadSelect';
3434

3535
import * as buildApi from 'services/buildApi';
3636
import * as groupBuildApi from 'services/groupBuildApi';
@@ -182,6 +182,8 @@ const DEPENDENCY_TREE_ROOT_GROUP_BUILD: GroupBuild = {
182182
},
183183
};
184184

185+
const defaultSelectOptions = [{ value: 'Build' }, { value: 'Option' }, { value: 'Project' }, { value: 'Version' }];
186+
185187
export const DemoPage = () => {
186188
useTitle('Demo Page');
187189

@@ -234,7 +236,14 @@ export const DemoPage = () => {
234236
});
235237
};
236238

237-
const selectOptions = [{ value: 'Build' }, { value: 'Option' }, { value: 'Project' }, { value: 'Version' }];
239+
const selectOptions = useMemo(
240+
() =>
241+
defaultSelectOptions.map((option) => ({
242+
value: option.value,
243+
children: option.value,
244+
})),
245+
[]
246+
);
238247

239248
const [isSelectOpen, setIsSelectOpen] = useState<boolean>(false);
240249

@@ -244,10 +253,10 @@ export const DemoPage = () => {
244253
<FlexItem>
245254
<ContentBox title="SearchSelect" padding>
246255
<SearchSelect
247-
selectedItem={searchSelectValue}
248-
onSelect={(_event, selection: string | SelectOptionObject) => {
256+
selectedValue={searchSelectValue}
257+
onSelect={(selection) => {
249258
console.log(`SEARCH SELECT> selected ${selection}`);
250-
setSearchSelectValue(selection as string);
259+
setSearchSelectValue(selection);
251260
}}
252261
onClear={() => {
253262
console.log('SEARCH SELECT> cleared');
@@ -311,30 +320,20 @@ export const DemoPage = () => {
311320
<FormInput<string>
312321
{...register<string>('selectA', fieldConfigs.selectA)}
313322
render={({ value, onChange, validated }) => (
314-
<Select
315-
id="selectA"
316-
variant={SelectVariant.typeahead}
317-
placeholderText="Select an option"
318-
typeAheadAriaLabel="Select an option"
319-
isOpen={isSelectOpen}
320-
selections={value}
321-
validated={validated}
322-
onToggle={(_, isOpen) => {
323-
setIsSelectOpen(isOpen);
323+
<TypeaheadSelect
324+
selectOptions={selectOptions}
325+
isMenuOpen={isSelectOpen}
326+
onMenuToggle={setIsSelectOpen}
327+
selectedValue={value}
328+
onSelect={(selection) => {
329+
onChange(undefined, selection);
324330
}}
325-
onSelect={(event, selection) => {
326-
onChange(event, selection as string);
327-
setIsSelectOpen(false);
331+
onClear={() => {
332+
onChange(undefined, '');
328333
}}
329-
onClear={(event) => {
330-
onChange(event, '');
331-
setIsSelectOpen(false);
332-
}}
333-
>
334-
{selectOptions.map((option: any, index: any) => (
335-
<SelectOption key={index} value={option.value} />
336-
))}
337-
</Select>
334+
validated={validated}
335+
placeholderText="Select an option"
336+
/>
338337
)}
339338
/>
340339
<FormInputHelperText variant="error">{getFieldErrors('selectA')}</FormInputHelperText>

0 commit comments

Comments
 (0)