Skip to content

Commit c9039fb

Browse files
authored
Merge pull request #150 from headlamp-k8s/ui-app-catalog
app-catalog: Fix UI bugs
2 parents 9843400 + 7348e58 commit c9039fb

File tree

2 files changed

+134
-83
lines changed

2 files changed

+134
-83
lines changed

app-catalog/src/components/charts/Details.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ export default function ChartDetails() {
5252
title={chartName}
5353
actions={[
5454
<Button
55-
style={{
55+
sx={{
5656
backgroundColor: '#000',
5757
color: 'white',
5858
textTransform: 'none',
59+
'&:hover': {
60+
background: '#605e5c',
61+
},
5962
}}
6063
onClick={() => {
6164
setOpenEditor(true);
@@ -77,14 +80,16 @@ export default function ChartDetails() {
7780
name: 'Name',
7881
value: (
7982
<Box display="flex" alignItems="center">
80-
<Box mr={1}>
81-
<img
82-
src={`https://artifacthub.io/image/${chart.logo_image_id}`}
83-
width="25"
84-
height="25"
85-
alt={chart.name}
86-
/>
87-
</Box>
83+
{chart.logo_image_id && (
84+
<Box mr={1}>
85+
<img
86+
src={`https://artifacthub.io/image/${chart.logo_image_id}`}
87+
width="25"
88+
height="25"
89+
alt={chart.name}
90+
/>
91+
</Box>
92+
)}
8893
<Box>{chart.name}</Box>
8994
</Box>
9095
),

app-catalog/src/components/charts/List.tsx

Lines changed: 120 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
Typography,
2020
} from '@mui/material';
2121
import { Autocomplete, Pagination } from '@mui/material';
22-
import { useEffect, useState } from 'react';
22+
import { useEffect, useRef, useState } from 'react';
2323
//import { jsonToYAML, yamlToJSON } from '../../helpers';
2424
import { fetchChartsFromArtifact } from '../../api/charts';
2525
//import { createRelease } from '../../api/releases';
@@ -38,6 +38,99 @@ const useStoreConfig = store.useConfig();
3838

3939
export const PAGE_OFFSET_COUNT_FOR_CHARTS = 9;
4040

41+
interface SearchProps {
42+
search: string;
43+
setSearch: React.Dispatch<React.SetStateAction<string>>;
44+
}
45+
46+
function Search({
47+
search,
48+
setSearch
49+
}: SearchProps) {
50+
const [inputValue, setInputValue] = useState(search);
51+
const timeoutRef = useRef<NodeJS.Timeout>();
52+
53+
useEffect(() => {
54+
if (timeoutRef.current) {
55+
clearTimeout(timeoutRef.current);
56+
}
57+
58+
timeoutRef.current = setTimeout(() => {
59+
setSearch(inputValue);
60+
}, 300);
61+
62+
return () => {
63+
if (timeoutRef.current) {
64+
clearTimeout(timeoutRef.current);
65+
}
66+
};
67+
}, [inputValue, setSearch]);
68+
69+
return (
70+
<TextField
71+
sx={{
72+
width: '20vw',
73+
margin: '0 1rem',
74+
}}
75+
id="outlined-basic"
76+
label="Search"
77+
value={inputValue}
78+
onChange={event => {
79+
setInputValue(event.target.value);
80+
}}
81+
/>
82+
);
83+
}
84+
85+
interface CategoryForChartsProps {
86+
helmChartCategoryList: { title: string; value: number }[];
87+
chartCategory: { title: string; value: number };
88+
setChartCategory: React.Dispatch<React.SetStateAction<{ title: string; value: number }>>;
89+
}
90+
91+
function CategoryForCharts({
92+
helmChartCategoryList,
93+
chartCategory,
94+
setChartCategory
95+
}: CategoryForChartsProps) {
96+
return (
97+
<Autocomplete
98+
sx={{
99+
width: '20vw',
100+
}}
101+
options={helmChartCategoryList}
102+
getOptionLabel={option => option?.title ?? helmChartCategoryList[0].title}
103+
defaultValue={helmChartCategoryList[0]}
104+
value={chartCategory}
105+
onChange={(event, newValue) => {
106+
// @ts-ignore
107+
setChartCategory((oldValue) => {
108+
if ((newValue?.value ?? helmChartCategoryList[0].value) === oldValue.value) {
109+
return oldValue;
110+
}
111+
return newValue ?? helmChartCategoryList[0];
112+
});
113+
}}
114+
renderInput={params => {
115+
if (process.env.NODE_ENV === 'test') {
116+
// To keep the ids stable under test.
117+
params.id = params.id ? params.id.replace(/[0-9]/g, '') : params.id;
118+
params.inputProps.id = params.inputProps.id
119+
? params.inputProps.id.replace(/[0-9]/g, '')
120+
: params.inputProps.id;
121+
params.InputLabelProps.id = params.InputLabelProps.id
122+
? params.InputLabelProps.id.replace(/[0-9]/g, '')
123+
: params.InputLabelProps.id;
124+
// params.InputLabelProps.htmlFor = params.InputLabelProps.htmlFor
125+
// ? params.InputLabelProps.htmlFor.replace(/[0-9]/g, '')
126+
// : params.InputLabelProps.htmlFor;
127+
}
128+
return <TextField {...params} label="Categories" placeholder="Favorites" />;
129+
}}
130+
/>
131+
);
132+
}
133+
41134
export function ChartsList({ fetchCharts = fetchChartsFromArtifact }) {
42135
const helmChartCategoryList = [
43136
{ title: 'All', value: 0 },
@@ -71,8 +164,6 @@ export function ChartsList({ fetchCharts = fetchChartsFromArtifact }) {
71164
// note: When the page changes, we fetch the charts, this will run as a reaction to the previous useEffect
72165
useEffect(
73166
function fetchChartsOnPageChange() {
74-
setCharts(null);
75-
76167
store.set({ showOnlyVerified: showOnlyVerified });
77168

78169
async function fetchData() {
@@ -91,65 +182,6 @@ export function ChartsList({ fetchCharts = fetchChartsFromArtifact }) {
91182
[page, chartCategory, search, showOnlyVerified]
92183
);
93184

94-
function Search() {
95-
return (
96-
<TextField
97-
sx={{
98-
width: '20vw',
99-
margin: '0 1rem',
100-
}}
101-
id="outlined-basic"
102-
label="Search"
103-
value={search}
104-
// @todo: Find a better way to handle search autofocus
105-
// eslint-disable-next-line jsx-a11y/no-autofocus
106-
autoFocus
107-
onChange={event => {
108-
setSearch(event.target.value);
109-
}}
110-
/>
111-
);
112-
}
113-
114-
function CategoryForCharts() {
115-
return (
116-
<Autocomplete
117-
sx={{
118-
width: '20vw',
119-
}}
120-
options={helmChartCategoryList}
121-
getOptionLabel={option => option?.title ?? helmChartCategoryList[0].title}
122-
defaultValue={helmChartCategoryList[0]}
123-
value={chartCategory}
124-
onChange={(event, newValue) => {
125-
// @ts-ignore
126-
setChartCategory((oldValue) => {
127-
if ((newValue?.value ?? helmChartCategoryList[0].value) === oldValue.value) {
128-
return oldValue;
129-
}
130-
return newValue ?? helmChartCategoryList[0];
131-
});
132-
}}
133-
renderInput={params => {
134-
if (process.env.NODE_ENV === 'test') {
135-
// To keep the ids stable under test.
136-
params.id = params.id ? params.id.replace(/[0-9]/g, '') : params.id;
137-
params.inputProps.id = params.inputProps.id
138-
? params.inputProps.id.replace(/[0-9]/g, '')
139-
: params.inputProps.id;
140-
params.InputLabelProps.id = params.InputLabelProps.id
141-
? params.InputLabelProps.id.replace(/[0-9]/g, '')
142-
: params.InputLabelProps.id;
143-
// params.InputLabelProps.htmlFor = params.InputLabelProps.htmlFor
144-
// ? params.InputLabelProps.htmlFor.replace(/[0-9]/g, '')
145-
// : params.InputLabelProps.htmlFor;
146-
}
147-
return <TextField {...params} label="Categories" placeholder="Favorites" />;
148-
}}
149-
/>
150-
);
151-
}
152-
153185
return (
154186
<>
155187
<EditorDialog
@@ -160,7 +192,14 @@ export function ChartsList({ fetchCharts = fetchChartsFromArtifact }) {
160192
<SectionHeader
161193
title="Applications"
162194
titleSideActions={[<SettingsLink />]}
163-
actions={[<Search />, <CategoryForCharts />]}
195+
actions={[
196+
<Search search={search} setSearch={setSearch} />,
197+
<CategoryForCharts
198+
helmChartCategoryList={helmChartCategoryList}
199+
chartCategory={chartCategory}
200+
setChartCategory={setChartCategory}
201+
/>,
202+
]}
164203
/>
165204
<Box>
166205
{!charts ? (
@@ -207,20 +246,24 @@ export function ChartsList({ fetchCharts = fetchChartsFromArtifact }) {
207246
justifyContent="space-between"
208247
marginTop="15px"
209248
>
210-
<CardMedia
211-
image={`https://artifacthub.io/image/${chart.logo_image_id}`}
212-
alt={`${chart.name} logo`}
213-
sx={{
214-
width: '60px',
215-
margin: '1rem',
216-
alignSelf: 'flex-start',
217-
}}
218-
component="img"
219-
/>
249+
{chart.logo_image_id && (
250+
<CardMedia
251+
image={`https://artifacthub.io/image/${chart.logo_image_id}`}
252+
alt={`${chart.name} logo`}
253+
sx={{
254+
width: '60px',
255+
height: '60px',
256+
margin: '1rem',
257+
alignSelf: 'flex-start',
258+
objectFit: 'contain',
259+
}}
260+
component="img"
261+
/>
262+
)}
220263
<Box
221264
display="flex"
222265
alignItems="center"
223-
justifyContent="space-around"
266+
marginLeft="auto"
224267
marginRight="10px"
225268
>
226269
{(chart.cncf || chart.repository.cncf) && (
@@ -325,6 +368,9 @@ export function ChartsList({ fetchCharts = fetchChartsFromArtifact }) {
325368
backgroundColor: '#000',
326369
color: 'white',
327370
textTransform: 'none',
371+
'&:hover': {
372+
background: '#605e5c',
373+
},
328374
}}
329375
onClick={() => {
330376
setSelectedChartForInstall(chart);

0 commit comments

Comments
 (0)