Skip to content

Commit 96e1aa7

Browse files
Merge pull request #13389 from Lucifergene/Recently-Searched
ODC-7480: Recently Searched Section in Search Resource Page Dropdown
2 parents 0a4e4b1 + ac72224 commit 96e1aa7

4 files changed

Lines changed: 142 additions & 6 deletions

File tree

frontend/public/components/_resource-dropdown.scss

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
.pf-v5-c-select__menu {
6666
min-width: 290px;
6767
@media (min-width: 480px) {
68-
min-width: 350px;
68+
min-width: 420px;
6969
}
7070
.co-resource-item__tech-dev-preview {
7171
color: red;
@@ -77,3 +77,18 @@
7777
.span--icon__right-margin {
7878
margin-right: 6px;
7979
}
80+
81+
.co-select-group-close-button {
82+
margin-left: 360px;
83+
top: 2px;
84+
z-index: 1;
85+
}
86+
87+
.co-select-group-dismissible {
88+
top: -32px;
89+
position: relative;
90+
}
91+
92+
.co-select-group-divider {
93+
margin-top: -22px !important;
94+
}

frontend/public/components/resource-dropdown.tsx

Lines changed: 123 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import { connect } from 'react-redux';
44
import { Map as ImmutableMap, Set as ImmutableSet } from 'immutable';
55
import * as classNames from 'classnames';
66
import { useTranslation } from 'react-i18next';
7-
87
import { ResourceIcon } from './utils';
98
import { K8sKind, K8sResourceKindReference, modelFor, referenceForModel } from '../module/k8s';
109
import { DiscoveryResources } from '@console/dynamic-plugin-sdk/src/api/common-types';
1110
import {
1211
Select as SelectDeprecated,
12+
SelectGroup as SelectGroupDeprecated,
1313
SelectOption as SelectOptionDeprecated,
1414
SelectVariant as SelectVariantDeprecated,
1515
} from '@patternfly/react-core/deprecated';
16+
import { useUserSettings } from '@console/shared/src';
17+
import { Divider, Tooltip } from '@patternfly/react-core';
18+
import CloseButton from '@console/shared/src/components/close-button';
19+
20+
const RECENT_SEARCH_ITEMS = 5;
1621

1722
// Blacklist known duplicate resources.
1823
const blacklistGroups = ImmutableSet([
@@ -26,12 +31,37 @@ const blacklistResources = ImmutableSet([
2631
]);
2732

2833
const ResourceListDropdown_: React.SFC<ResourceListDropdownProps> = (props) => {
29-
const { selected, onChange, allModels, groupToVersionMap, className } = props;
34+
const { selected, onChange, recentList, allModels, groupToVersionMap, className } = props;
3035
const { t } = useTranslation();
3136

3237
const [isOpen, setOpen] = React.useState(false);
38+
const [clearItems, setClearItems] = React.useState(false);
39+
40+
const [recentSelected, setRecentSelected] = useUserSettings<string>(
41+
'console.search.recentlySearched',
42+
'[]',
43+
true,
44+
);
45+
3346
const [selectedOptions, setSelectedOptions] = React.useState(selected);
3447

48+
const filterGroupVersionKind = (resourceList: string[]): string[] => {
49+
return resourceList.filter((resource) => {
50+
const parts = resource.split('~');
51+
return parts.length === 3 && parts.every((part) => part.trim() !== '');
52+
});
53+
};
54+
55+
const recentSelectedList = (data: string[] | string): string[] => {
56+
return (
57+
(data &&
58+
data !== '[]' &&
59+
data !== 'undefined' &&
60+
JSON.parse(_.isString(data) ? data : JSON.stringify(data))) ??
61+
[]
62+
);
63+
};
64+
3565
const resources = allModels
3666
.filter(({ apiGroup, apiVersion, kind, verbs }) => {
3767
// Remove blacklisted items.
@@ -65,7 +95,24 @@ const ResourceListDropdown_: React.SFC<ResourceListDropdownProps> = (props) => {
6595

6696
React.useEffect(() => {
6797
setSelectedOptions(selected);
68-
}, [selected]);
98+
!_.isEmpty(selected) &&
99+
setRecentSelected(
100+
JSON.stringify(
101+
_.union(
102+
!clearItems ? filterGroupVersionKind(selected.reverse()) : [],
103+
recentSelectedList(recentSelected),
104+
),
105+
),
106+
);
107+
// eslint-disable-next-line react-hooks/exhaustive-deps
108+
setClearItems(false);
109+
}, [selected, setRecentSelected]);
110+
111+
const onClear = () => {
112+
setSelectedOptions([]);
113+
setClearItems(true);
114+
setRecentSelected(JSON.stringify([]));
115+
};
69116

70117
const items = resources
71118
.map((model: K8sKind) => (
@@ -98,9 +145,78 @@ const ResourceListDropdown_: React.SFC<ResourceListDropdownProps> = (props) => {
98145
))
99146
.toArray();
100147

148+
const recentSearches: JSX.Element[] =
149+
!_.isEmpty(recentSelectedList(recentSelected)) &&
150+
recentSelectedList(recentSelected)
151+
.splice(0, RECENT_SEARCH_ITEMS)
152+
.map((modelRef: K8sResourceKindReference) => {
153+
const model: K8sKind = resources.find((m) => referenceForModel(m) === modelRef);
154+
if (model) {
155+
return (
156+
<SelectOptionDeprecated
157+
key={modelRef}
158+
value={modelRef}
159+
data-filter-text={`${model.abbr}${model.labelKey ? t(model.labelKey) : model.kind}`}
160+
>
161+
<span className="co-resource-item">
162+
<span className="co-resource-icon--fixed-width">
163+
<ResourceIcon kind={modelRef} />
164+
</span>
165+
<span className="co-resource-item__resource-name">
166+
<span>
167+
{model.labelKey ? t(model.labelKey) : model.kind}
168+
{model.badge && model.badge === 'Tech Preview' && (
169+
<span className="co-resource-item__tech-dev-preview">
170+
{t('public~Tech Preview')}
171+
</span>
172+
)}
173+
</span>
174+
{isDup(model.kind) && (
175+
<div className="co-resource-item__resource-api text-muted co-truncate co-nowrap small">
176+
{model.apiGroup || 'core'}/{model.apiVersion}
177+
</div>
178+
)}
179+
</span>
180+
</span>
181+
</SelectOptionDeprecated>
182+
);
183+
}
184+
return null;
185+
})
186+
.filter((item) => item !== null);
187+
188+
const renderedOptions = () => {
189+
const options: JSX.Element[] = [];
190+
if (!_.isEmpty(recentSelectedList(recentSelected)) && !!recentList) {
191+
options.push(
192+
<Tooltip position="right" content={t('public~Clear history')}>
193+
<CloseButton
194+
additionalClassName="co-select-group-close-button"
195+
dataTestID="close-icon"
196+
onClick={onClear}
197+
/>
198+
</Tooltip>,
199+
);
200+
options.push(
201+
<SelectGroupDeprecated
202+
label={t('public~Recently used')}
203+
className="co-select-group-dismissible"
204+
>
205+
{recentSearches}
206+
</SelectGroupDeprecated>,
207+
);
208+
options.push(<Divider key={3} className="co-select-group-divider" />);
209+
}
210+
options.push(<SelectGroupDeprecated>{items}</SelectGroupDeprecated>);
211+
return options;
212+
};
213+
101214
const onCustomFilter = (event: React.ChangeEvent<HTMLInputElement>) => {
102215
const filterText = event?.target.value.toLocaleLowerCase();
103-
if (filterText === null || filterText === '') {
216+
if (filterText === null || filterText === '' || filterText === undefined) {
217+
if (!_.isEmpty(recentSelectedList(recentSelected)) && !!recentList) {
218+
return renderedOptions();
219+
}
104220
return items;
105221
}
106222
return items.filter((item) => {
@@ -130,8 +246,9 @@ const ResourceListDropdown_: React.SFC<ResourceListDropdownProps> = (props) => {
130246
customBadgeText={selected.length}
131247
className={classNames('co-type-selector', className)}
132248
maxHeight="60vh"
249+
isGrouped
133250
>
134-
{items}
251+
{renderedOptions()}
135252
</SelectDeprecated>
136253
);
137254
};
@@ -148,6 +265,7 @@ export const ResourceListDropdown = connect<ResourceListDropdownStateToProps>(
148265
export type ResourceListDropdownProps = ResourceListDropdownStateToProps & {
149266
selected: K8sResourceKindReference[];
150267
onChange: (value: string) => void;
268+
recentList?: boolean;
151269
className?: string;
152270
id?: string;
153271
};

frontend/public/components/search.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ const SearchPage_: React.FC<SearchProps> = (props) => {
253253
<ResourceListDropdown
254254
selected={[...selectedItems]}
255255
onChange={updateSelectedItems}
256+
recentList={true}
256257
/>
257258
</ToolbarFilter>
258259
</ToolbarItem>

frontend/public/locales/en/public.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,8 @@
13971397
"ReplicationController details": "ReplicationController details",
13981398
"{{statusReplicas}} of {{specReplicas}} pods": "{{statusReplicas}} of {{specReplicas}} pods",
13991399
"Tech Preview": "Tech Preview",
1400+
"Clear history": "Clear history",
1401+
"Recently used": "Recently used",
14001402
"Select Resource": "Select Resource",
14011403
"Edit AppliedClusterResourceQuota": "Edit AppliedClusterResourceQuota",
14021404
"Affects pods that have an active deadline. These pods usually include builds, deployers, and jobs.": "Affects pods that have an active deadline. These pods usually include builds, deployers, and jobs.",

0 commit comments

Comments
 (0)