Skip to content

Commit 47427e8

Browse files
committed
feat: add plugin list
1 parent 5209f0b commit 47427e8

File tree

17 files changed

+692
-30
lines changed

17 files changed

+692
-30
lines changed

src/Assets/Icon/ic-lego-block.svg

Lines changed: 20 additions & 0 deletions
Loading

src/Assets/Icon/ic-visibility-on.svg

Lines changed: 20 additions & 0 deletions
Loading

src/Common/Constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ export const ROUTES = {
9393
MODULE_CONFIGURED: 'module/config',
9494
RESOURCE_HISTORY_DEPLOYMENT: 'resource/history/deployment',
9595
PLUGIN_GLOBAL_DETAIL: 'plugin/global/detail',
96+
PLUGIN_GLOBAL_LIST_V2: 'plugin/global/list/v2',
97+
PLUGIN_GLOBAL_LIST_TAGS: 'plugin/global/list/tags',
9698
}
9799

98100
export enum KEY_VALUE {

src/Shared/Components/CICDHistory/Sidebar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
FetchIdDataStatus,
3131
} from './types'
3232
import { getCustomOptionSelectionStyle } from '../ReactSelect'
33-
import DetectBottom from './DetectBottom'
33+
import { DetectBottom } from '../DetectBottom'
3434
import {
3535
ConditionalWrap,
3636
DATE_TIME_FORMATS,

src/Shared/Components/CICDHistory/DetectBottom.tsx renamed to src/Shared/Components/DetectBottom/DetectBottom.component.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
import { useEffect, useRef } from 'react'
1818
import { useIntersection } from '../../Helpers'
1919

20-
const DetectBottom = ({ callback }: { callback: () => void }) => {
20+
interface DetectBottomProps {
21+
callback: () => void
22+
}
23+
24+
const DetectBottom = ({ callback }: DetectBottomProps) => {
2125
const target = useRef<HTMLSpanElement>(null)
2226
const intersected = useIntersection(target, {
2327
rootMargin: '0px',
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as DetectBottom } from './DetectBottom.component'
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Checkbox, CHECKBOX_VALUE, noop } from '../../../Common'
2+
import { ImageWithFallback } from '../ImageWithFallback'
3+
import { PluginCardProps } from './types'
4+
import { ReactComponent as ICLegoBlock } from '../../../Assets/Icon/ic-lego-block.svg'
5+
6+
const PluginCard = ({
7+
isSelectable,
8+
pluginDataStore,
9+
handlePluginSelection,
10+
parentPluginId,
11+
isSelected,
12+
}: PluginCardProps) => {
13+
const latestPluginId = pluginDataStore.parentPluginStore[parentPluginId].latestVersionId
14+
const { icon, name, description, tags, pluginVersion, updatedBy } =
15+
pluginDataStore.pluginVersionStore[latestPluginId]
16+
17+
const handleSelection = () => {
18+
handlePluginSelection(parentPluginId)
19+
}
20+
21+
return (
22+
<div className="p-12 flexbox dc__gap-16 dc__tab-focus" role="button" tabIndex={0} onClick={handleSelection}>
23+
{isSelectable ? (
24+
<div className="dc__no-shrink icon-dim-40 p-8">
25+
<Checkbox
26+
isChecked={isSelected}
27+
onChange={noop}
28+
rootClassName="icon-dim-40 p-8 w-100 mb-0 dc__no-shrink"
29+
value={CHECKBOX_VALUE.CHECKED}
30+
/>
31+
</div>
32+
) : (
33+
// TODO: Test multiple cards with fallback since has if in LegoBlock
34+
<ImageWithFallback
35+
fallbackImage={<ICLegoBlock className="dc__no-shrink icon-dim-40" />}
36+
imageProps={{
37+
src: icon,
38+
alt: `${name} logo`,
39+
width: 40,
40+
height: 40,
41+
className: 'p-4 dc__no-shrink',
42+
}}
43+
/>
44+
)}
45+
46+
<div className="flexbox-col dc__gap-12">
47+
<div className="flexbox-col dc__gap-8">
48+
<div className="flexbox-col dc__gap-4">
49+
<h4 className="m-0 dc__truncate--clamp-3 cn-9 fs-13 fw-6 lh-20">
50+
{name}
51+
52+
{!isSelectable && (
53+
<span className="dc__truncate--clamp-3 cn-7 fs-12 fw-4 lh-20">({pluginVersion})</span>
54+
)}
55+
</h4>
56+
57+
<span className="dc__truncate cn-7 fs-12 fw-4 lh-16">By {updatedBy || 'Devtron'}</span>
58+
</div>
59+
60+
{/* Plugin description */}
61+
{description && <p className="m-0 cn-7 fs-12 fw-4 lh-16 dc__truncate--clamp-3">{description}</p>}
62+
</div>
63+
64+
{/* Tag container */}
65+
<div className="flexbox dc__gap-6 flex-wrap">
66+
{tags.map((tag) => (
67+
<div className="flexbox px-6 br-4 bcn-1 dc__align-items-center dc__mxw-160" key={tag}>
68+
<span className="dc__mxw-160 dc__truncate cn-8 fs-11 fw-4 lh-20">{tag}</span>
69+
</div>
70+
))}
71+
</div>
72+
</div>
73+
</div>
74+
)
75+
}
76+
77+
export default PluginCard
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { useState } from 'react'
2+
import { PluginListProps } from './types'
3+
import { DetectBottom } from '../DetectBottom'
4+
import { GenericEmptyState, GenericFilterEmptyState, showError } from '../../../Common'
5+
import { getPluginStoreData } from './service'
6+
import PluginCard from './PluginCard'
7+
8+
const PluginList = ({
9+
pluginDataStore,
10+
pluginList,
11+
totalCount,
12+
handleDataUpdateForPluginResponse,
13+
filters: { selectedTags, searchKey, showSelectedPlugins },
14+
handlePluginSelection,
15+
selectedPluginsMap,
16+
isSelectable,
17+
handleClearFilters,
18+
}: PluginListProps) => {
19+
const [isLoadingMorePlugins, setIsLoadingMorePlugins] = useState<boolean>(false)
20+
const handleLoadMore = async () => {
21+
setIsLoadingMorePlugins(true)
22+
try {
23+
const pluginDataResponse = await getPluginStoreData({
24+
searchKey,
25+
offset: pluginList.length,
26+
selectedTags,
27+
appId: undefined,
28+
})
29+
30+
handleDataUpdateForPluginResponse(pluginDataResponse)
31+
} catch (error) {
32+
showError(error)
33+
} finally {
34+
setIsLoadingMorePlugins(false)
35+
}
36+
}
37+
38+
if (!pluginList.length) {
39+
if (!!searchKey || !selectedTags.length) {
40+
return <GenericFilterEmptyState handleClearFilters={handleClearFilters} />
41+
}
42+
43+
// Not going to happen but still handling in case of any issue that might arise
44+
return (
45+
<GenericEmptyState title="No plugins found" subTitle="We are unable to locate any plugin in our system" />
46+
)
47+
}
48+
49+
// selectedPluginsMap should always be present if s
50+
if (showSelectedPlugins) {
51+
return (
52+
<>
53+
{Object.keys(selectedPluginsMap).map((pluginId) => (
54+
<PluginCard
55+
key={pluginId}
56+
parentPluginId={+pluginId}
57+
isSelectable={isSelectable}
58+
pluginDataStore={pluginDataStore}
59+
handlePluginSelection={handlePluginSelection}
60+
isSelected
61+
/>
62+
))}
63+
</>
64+
)
65+
}
66+
67+
return (
68+
<>
69+
{pluginList.map((plugin) => (
70+
<PluginCard
71+
key={plugin.parentPluginId}
72+
parentPluginId={plugin.parentPluginId}
73+
isSelectable={isSelectable}
74+
pluginDataStore={pluginDataStore}
75+
handlePluginSelection={handlePluginSelection}
76+
isSelected={!!selectedPluginsMap[plugin.parentPluginId]}
77+
/>
78+
))}
79+
80+
{totalCount > pluginList.length && !isLoadingMorePlugins && <DetectBottom callback={handleLoadMore} />}
81+
</>
82+
)
83+
}
84+
85+
export default PluginList

0 commit comments

Comments
 (0)