Skip to content

Commit 60f024f

Browse files
authored
Merge pull request #2757 from devtron-labs/feat/chart-card-ui
feat: chart card UI
2 parents 623fb91 + 237f33a commit 60f024f

18 files changed

+461
-651
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"homepage": "/dashboard",
66
"dependencies": {
7-
"@devtron-labs/devtron-fe-common-lib": "1.15.0-pre-7",
7+
"@devtron-labs/devtron-fe-common-lib": "1.15.1-pre-1",
88
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
99
"@rjsf/core": "^5.13.3",
1010
"@rjsf/utils": "^5.13.3",

src/components/charts/ChartCard.tsx

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright (c) 2024. Devtron Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {
18+
Button,
19+
ButtonStyleType,
20+
ButtonVariantType,
21+
ComponentSizeType,
22+
handleAnalyticsEvent,
23+
Icon,
24+
ImageWithFallback,
25+
noop,
26+
stopPropagation,
27+
useMainContext,
28+
} from '@devtron-labs/devtron-fe-common-lib'
29+
30+
import { ReactComponent as ICCaretSmall } from '@Icons/ic-caret-left-small.svg'
31+
import { InteractiveCellText } from '@Components/common/helpers/InteractiveCellText/InteractiveCellText'
32+
33+
import { ReactComponent as Helm } from '../../assets/icons/ic-default-chart.svg'
34+
import { SERVER_MODE } from '../../config'
35+
import { ChartSelectProps } from './charts.types'
36+
import { renderDeprecatedWarning } from './charts.util'
37+
38+
const ChartCard = ({
39+
chart,
40+
addChart,
41+
subtractChart,
42+
selectedCount = 0,
43+
onClick,
44+
dataTestId,
45+
isListView,
46+
}: ChartSelectProps) => {
47+
const { serverMode } = useMainContext()
48+
49+
const addChartTab = (e): void => {
50+
stopPropagation(e)
51+
addChart(chart.id)
52+
handleAnalyticsEvent({ category: 'Chart store add icon', action: 'CS_BULK_DEPLOY_ADD_CHART' })
53+
}
54+
55+
const removeChartTab = (e): void => {
56+
stopPropagation(e)
57+
subtractChart(chart.id)
58+
handleAnalyticsEvent({ category: 'Chart store remove icon', action: 'CS_BULK_DEPLOY_REMOVE_CHART' })
59+
}
60+
61+
const onClickChartSelect = (): void => {
62+
onClick(chart.id)
63+
handleAnalyticsEvent({ category: 'Chart store card', action: 'CS_CHART_CARD_CLICKED' })
64+
}
65+
66+
const renderAddIcon = () => (
67+
<div className={`${selectedCount > 0 ? 'dc__visible' : 'dc__border br-6'} dc__visible-hover--child`}>
68+
<Button
69+
icon={<Icon name="ic-add" size={null} color={null} />}
70+
onClick={addChartTab}
71+
dataTestId={`chart-add-${dataTestId}`}
72+
variant={ButtonVariantType.borderLess}
73+
size={ComponentSizeType.small}
74+
style={ButtonStyleType.default}
75+
ariaLabel="Add chart to selection"
76+
/>
77+
</div>
78+
)
79+
80+
const renderRemoveIcon = () => (
81+
<Button
82+
icon={<Icon name="ic-minus" size={null} color={null} />}
83+
onClick={removeChartTab}
84+
dataTestId={`chart-remove-${dataTestId}`}
85+
variant={ButtonVariantType.borderLess}
86+
size={ComponentSizeType.small}
87+
style={ButtonStyleType.negativeGrey}
88+
showAriaLabelInTippy={selectedCount > 0}
89+
ariaLabel="Remove chart from selection"
90+
/>
91+
)
92+
const chartIconClass = 'dc__chart-grid-item__icon chart-icon-dim br-4 dc__no-shrink'
93+
94+
const renderIcon = () => (
95+
<div className="icon-wrapper">
96+
<ImageWithFallback
97+
imageProps={{
98+
height: 32,
99+
width: 32,
100+
src: chart.icon,
101+
alt: 'chart',
102+
className: chartIconClass,
103+
}}
104+
fallbackImage={<Helm className={chartIconClass} />}
105+
/>
106+
</div>
107+
)
108+
109+
const getDescriptionTruncate = () => {
110+
if (isListView) {
111+
return 'dc__truncate--clamp-4'
112+
}
113+
114+
if (chart.deprecated) return 'dc__truncate'
115+
return 'dc__truncate--clamp-2'
116+
}
117+
118+
const renderCardInfo = () => (
119+
<div className="flexbox-col flex-grow-1 dc__gap-8">
120+
<div className="flexbox-col dc__gap-2">
121+
<div className="flex left">
122+
<InteractiveCellText
123+
text={chart.name}
124+
rootClassName="fw-6 chart-grid-item__title cn-9"
125+
fontSize={14}
126+
/>
127+
<div className="chart-name__arrow dc__no-shrink flex">
128+
<ICCaretSmall className="icon-dim-16 dc__flip-180 scb-5" />
129+
</div>
130+
</div>
131+
{chart.deprecated && renderDeprecatedWarning()}
132+
</div>
133+
134+
<span className={`fw-4 fs-13 lh-20 ${getDescriptionTruncate()}`}>
135+
{chart.description || 'No description'}
136+
</span>
137+
</div>
138+
)
139+
140+
const renderFooter = () => (
141+
<div className="flex left dc__content-space dc__border-top-n1 px-20 py-16 dc__gap-6">
142+
<div className="flex dc__gap-6">
143+
<Icon name="ic-folder-color" size={16} color={null} />
144+
<InteractiveCellText
145+
text={chart.chart_name ? chart.chart_name : chart.docker_artifact_store_id}
146+
rootClassName="cn-7"
147+
fontSize={12}
148+
/>
149+
</div>
150+
<div className="fs-12 cn-7 dc__ellipsis-right__2nd-line lh-18 dc__no-shrink">v{chart.version}</div>
151+
</div>
152+
)
153+
return (
154+
<div
155+
key={chart.id}
156+
className={`chart-grid-item dc__visible-hover dc__visible-hover--parent bg__primary border__secondary-translucent cursor dc__position-rel br-8 ${isListView ? 'flexbox-col' : ''} ${selectedCount > 0 ? 'chart-grid-item--selected' : ''} `}
157+
onClick={onClick ? onClickChartSelect : noop}
158+
data-testid={`chart-card-${dataTestId}`}
159+
>
160+
<div
161+
className={`${isListView ? 'dc__grid chart-list-item dc__gap-16' : 'flexbox-col h-166 dc__gap-12'} px-20 pt-20 pb-16`}
162+
>
163+
{renderIcon()}
164+
{serverMode === SERVER_MODE.FULL && addChart && subtractChart && (
165+
<div
166+
className={`devtron-stepper ${selectedCount > 0 ? 'dc__grid devtron-stepper-grid dc__border br-6 fw-6 cursor bg__primary' : ''}`}
167+
>
168+
{selectedCount > 0 && (
169+
<>
170+
{renderRemoveIcon()}
171+
172+
<span className="devtron-stepper__item fs-13 icon-dim-20 px-4">{selectedCount}</span>
173+
</>
174+
)}
175+
176+
{renderAddIcon()}
177+
</div>
178+
)}
179+
{renderCardInfo()}
180+
</div>
181+
{renderFooter()}
182+
</div>
183+
)
184+
}
185+
186+
export default ChartCard

src/components/charts/ChartGroupUpdate.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
ToastManager,
2727
ToastVariantType,
2828
} from '@devtron-labs/devtron-fe-common-lib'
29-
import ChartSelect from './util/ChartSelect'
29+
import ChartCard from './ChartCard'
3030
import { ChartGroupEntry, Chart, ChartListType } from './charts.types'
3131
import MultiChartSummary from './MultiChartSummary'
3232
import AdvancedConfig from './AdvancedConfig'
@@ -36,7 +36,7 @@ import CreateChartGroup from './modal/CreateChartGroup'
3636
import { URLS } from '../../config'
3737
import { ReactComponent as SaveIcon } from '../../assets/icons/ic-save.svg'
3838
import ChartHeaderFilters from './ChartHeaderFilters'
39-
import { QueryParams } from './charts.util'
39+
import { QueryParams } from './constants'
4040
import ChartEmptyState from '../common/emptyState/ChartEmptyState'
4141
import { sortOptionsByLabel } from '../common'
4242

@@ -334,7 +334,7 @@ export default function ChartGroupUpdate({}) {
334334
) : !chartList.length ? (
335335
<ChartEmptyState onClickViewChartButton={handleViewAllCharts} />
336336
) : (
337-
<div className={`${!isGrid ? 'chart-list-view ' : ''}`}>
337+
<div className={`${!isGrid ? 'chart-list-view' : ''}`}>
338338
<ChartList
339339
availableCharts={state.availableCharts}
340340
addChart={addChart}
@@ -391,15 +391,14 @@ const ChartList = ({ availableCharts, selectedInstances, addChart, subtractChart
391391
return (
392392
<div className={`chart-grid bg__primary ${!isGrid ? 'list-view' : ''}`}>
393393
{[...availableCharts.values()].map((chart: Chart, idx) => (
394-
<ChartSelect
394+
<ChartCard
395395
key={chart.id}
396396
chart={chart}
397397
selectedCount={selectedInstances[chart.id]?.length}
398398
addChart={addChart}
399399
subtractChart={subtractChart}
400-
showCheckBoxOnHoverOnly={false}
401-
showDescription={!isGrid}
402-
datatestid={`${idx}`}
400+
isListView={!isGrid}
401+
dataTestId={String(idx)}
403402
/>
404403
))}
405404
</div>

src/components/charts/ChartHeaderFilters.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { CHECKBOX_VALUE, Checkbox, SearchBar, handleAnalyticsEvent } from '@devt
1818
import { useRouteMatch, useHistory, useLocation } from 'react-router-dom'
1919
import { ReactComponent as Grid } from '../../assets/icons/ic-grid-view.svg'
2020
import { ReactComponent as List } from '../../assets/icons/ic-list-view.svg'
21-
import { QueryParams } from './charts.util'
21+
import { QueryParams } from './constants'
2222
import { Accordian } from '../common/Accordian/Accordian'
2323
import { URLS } from '../../config'
2424
import { CHART_KEYS } from './constants'
@@ -37,6 +37,7 @@ const ChartHeaderFilter = ({
3737
setIsGrid,
3838
chartCategoryIds,
3939
setChartCategoryIds,
40+
chartStoreRef,
4041
}: ChartHeaderFilterProps) => {
4142
const match = useRouteMatch()
4243
const history = useHistory()
@@ -168,21 +169,27 @@ const ChartHeaderFilter = ({
168169
}
169170
}
170171

172+
const getScrollToInitial = () => {
173+
chartStoreRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
174+
}
175+
171176
const setGrid = (): void => {
172177
setIsGrid(true)
173-
handleAnalyticsEvent({category: 'Chart Store', action: 'CS_VIEW_GRID'})
178+
handleAnalyticsEvent({ category: 'Chart Store', action: 'CS_VIEW_GRID' })
179+
getScrollToInitial()
174180
}
175181

176182
const setList = (): void => {
177183
setIsGrid(false)
178-
handleAnalyticsEvent({category: 'Chart Store', action: 'CS_VIEW_LIST'})
184+
handleAnalyticsEvent({ category: 'Chart Store', action: 'CS_VIEW_LIST' })
185+
getScrollToInitial()
179186
}
180187

181188
const toggleDeprecated = (): void => {
182189
const value = (includeDeprecated + 1) % 2
183190
handleFilterChanges(value, CHART_KEYS.DEPRECATED)
184191
if (value) {
185-
handleAnalyticsEvent({category: 'Chart Store', action: 'CS_SHOW_DEPRECATED'})
192+
handleAnalyticsEvent({ category: 'Chart Store', action: 'CS_SHOW_DEPRECATED' })
186193
}
187194
}
188195

src/components/charts/MultiChartSummary.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,6 @@ const SelectedChartWidget: React.FC<SelectedChartWidget> = ({
248248
<div className="p-12 flex left" onClick={configureChart}>
249249
<div className="chart-bg">
250250
<img className="chart-icon" src={icon || ''} alt="" onError={handleImageError} />
251-
<Warning className="chart-warn" />
252251
</div>
253252
<div className="flex left column ml-18">
254253
<b className="chart-name" data-testid={`selected-chart-${index}`}>

0 commit comments

Comments
 (0)