From 358830b68a0887bd739ad4d28869f5e16a47c809 Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Fri, 16 Aug 2024 18:39:45 +0530 Subject: [PATCH 001/103] feat(card): fix catalog card Signed-off-by: Sudhanshu Dasgupta --- src/custom/CustomCatalog/custom-card.tsx | 267 ++++++++++++++++++ src/custom/CustomCatalog/index.tsx | 3 + src/custom/CustomCatalog/style.tsx | 342 +++++++++++++++++++++++ src/custom/index.tsx | 2 + 4 files changed, 614 insertions(+) create mode 100644 src/custom/CustomCatalog/custom-card.tsx create mode 100644 src/custom/CustomCatalog/index.tsx create mode 100644 src/custom/CustomCatalog/style.tsx diff --git a/src/custom/CustomCatalog/custom-card.tsx b/src/custom/CustomCatalog/custom-card.tsx new file mode 100644 index 000000000..a73d1b090 --- /dev/null +++ b/src/custom/CustomCatalog/custom-card.tsx @@ -0,0 +1,267 @@ +import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; +import { Avatar, Box, Typography, styled } from '@mui/material'; +import React from 'react'; +import { Grid } from '../../base'; +import { CloneIcon, CommunityClassIcon, OfficialClassIcon, OpenIcon, ShareIcon } from '../../icons'; +import VerificationClassIcon from '../../icons/ContentClassIcons/VerificationClassIcon'; +import DeploymentsIcon from '../../icons/Deployments/DeploymentsIcon'; +import { DownloadIcon } from '../../icons/Download'; +import { + CardBack, + CardFront, + DateText, + DateType, + DesignAuthorName, + DesignCard, + DesignDetailsDiv, + DesignInnerCard, + DesignName, + DesignType, + MetricsContainerFront, + MetricsCount, + MetricsDiv, + ProfileSection, + StyledClassWrapper, + StyledInnerClassWrapper, + TechnologiesSection, + VersionTag +} from './style'; + +export const DesignCardUrl = styled('a')(() => ({ + textDecoration: 'none' +})); + +interface Pattern { + name: string; + download_count: number; + clone_count: number; + view_count: number; + deployment_count: number; + share_count: number; + userData?: { + version?: string; + avatarUrl?: string; + userName?: string; + technologies?: string[]; + updatedAt?: string; + }; + catalog_data?: { + content_class?: string; + imageURL?: string; + }; + visibility: string; + updated_at: Date; +} + +type CatalogCardProps = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + pattern: Pattern; + patternType: string; + cardLink: string; + cardHeight: string; + cardWidth: string; + cardStyles: React.CSSProperties; + type: string; + version?: string; + avatarUrl: string; + userName: string; + technologies: string[]; + updatedAt: string; + shouldFlip?: boolean; + cardTechnologies?: boolean; + isDetailed?: boolean; + cardAvatarUrl?: boolean; + date?: boolean; + cardVersion?: boolean; + UserName?: string; + children?: React.ReactNode; +}; + +export const ClassToIconMap = { + community: , + official: , + verified: +}; + +const ClassWrap = ({ catalogClassName }: { catalogClassName: string }) => { + if (!catalogClassName) return <>; + + return ( + + + {catalogClassName} + + + ); +}; + +const CustomCatalogCard: React.FC = ({ + pattern, + patternType, + cardHeight, + cardWidth, + cardStyles, + cardLink, + shouldFlip, + isDetailed, + cardAvatarUrl, + cardTechnologies, + date, + cardVersion, + avatarUrl, + UserName, + children +}) => { + const outerStyles = { + height: cardHeight, + width: cardWidth, + ...cardStyles + }; + + return ( + + + + + {isDetailed && ( + <> + + {patternType} + + + {pattern.name} + + + )} + +
+ {children} +
+
+ {isDetailed && ( + + + + {pattern.download_count} + + + + {pattern.clone_count} + + + + {pattern.view_count} + + + + {pattern.deployment_count} + + + + {pattern.share_count} + + + )} +
+ {shouldFlip && ( + + {cardAvatarUrl && ( + + + {UserName} + + )} + + + {cardTechnologies && ( + + + Technologies + + + Kubernetes + + + )} + + + {date && ( + + + +
+ + Updated At +
+ + {' '} + {new Date(pattern.updated_at.toString().slice(0, 10)).toLocaleDateString( + 'en-US', + { + day: 'numeric', + month: 'long', + year: 'numeric' + } + )} + +
+
+
+ )} + + {cardVersion && ( + + v{cardVersion} + + )} +
+ )} +
+
+
+ ); +}; + +export default CustomCatalogCard; diff --git a/src/custom/CustomCatalog/index.tsx b/src/custom/CustomCatalog/index.tsx new file mode 100644 index 000000000..09adbc5cc --- /dev/null +++ b/src/custom/CustomCatalog/index.tsx @@ -0,0 +1,3 @@ +import CustomCatalogCard from './custom-card'; + +export { CustomCatalogCard }; diff --git a/src/custom/CustomCatalog/style.tsx b/src/custom/CustomCatalog/style.tsx new file mode 100644 index 000000000..ee81ec55c --- /dev/null +++ b/src/custom/CustomCatalog/style.tsx @@ -0,0 +1,342 @@ +import { styled, Typography } from '@mui/material'; + +type DesignCardProps = { + outerStyles: React.CSSProperties; + shouldFlip?: boolean; + isDetailed?: boolean; +}; +type DesignCardDivProps = { + shouldFlip?: boolean; + isDetailed?: boolean; +}; +type MetricsProps = { + isDetailed?: boolean; +}; +type CatalogProps = { + isCatalog?: boolean; +}; +type StyledInnerClassWrapperProps = { + catalogClassName: string; +}; +export const StyledClassWrapper = styled('div')(() => ({ + width: '85px', + height: '88px', + overflow: 'hidden', + position: 'absolute', + top: '-3px', + left: '-3px' +})); + +export const StyledInnerClassWrapper = styled('div')(({ + catalogClassName +}) => { + const mapToColor: Record = { + community: 'rgba(122,132,142,.8)', + official: '#EBC017', + verified: '#00B39F' + }; + return { + font: 'bold 10px sans-serif', + WebkitTransform: 'rotate(-45deg)', + textAlign: 'center', + transform: 'rotate(-45deg)', + position: 'relative', + padding: '4px 0', + top: '15px', + left: '-30px', + width: '120px', + display: 'flex', + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: mapToColor[catalogClassName], + color: '#fff' + }; +}); + +export const DesignCard = styled('div')( + ({ shouldFlip, isDetailed, outerStyles, theme }) => ({ + position: 'relative', + borderRadius: '1rem', + textAlign: 'center', + transformStyle: 'preserve-3d', + display: 'block', + perspective: '1000px', + transition: 'all .9s ease-out', + ...(shouldFlip && { + '&:hover': { + cursor: 'pointer', + '& .innerCard': { + transform: 'rotateY(180deg)' + } + } + }), + ...(isDetailed && { + [theme.breakpoints.down('lg')]: { + height: '18.75rem' + } + }), + ...outerStyles + }) +); + +export const DesignInnerCard = styled('div')(({ shouldFlip, isDetailed }) => ({ + position: 'relative', + width: '100%', + height: '100%', + textAlign: 'center', + transition: 'transform 0.6s', + ...(shouldFlip && { + transformOrigin: '50% 50%', + transformStyle: 'preserve-3d' + }), + ...(isDetailed && { + boxShadow: '0 4px 8px 0 rgba(0,0,0,0.2)', + borderRadius: '0.9375rem' + }) +})); + +export const DesignType = styled('span')(({ theme }) => ({ + position: 'absolute', + top: '0', + right: '0', + minWidth: '3rem', + padding: '0 0.75rem', + fontSize: '0.875rem', + textTransform: 'capitalize', + background: theme.palette.background.brand?.default, + color: theme.palette.text.inverse, + borderRadius: '0 1rem 0 2rem' +})); +export const MetricsCount = styled('p')(({ theme }) => ({ + fontSize: '1rem', + textTransform: 'capitalize', + margin: '0rem', + lineHeight: '1.5', + textAlign: 'center', + color: theme.palette.text.secondary, + fontWeight: '600' +})); +export const DesignName = styled(Typography)(({ theme }) => ({ + fontWeight: 'bold', + textTransform: 'capitalize', + color: theme.palette.text.default, + fontSize: '1.125rem', + marginTop: '2rem', + padding: '0rem 1rem', // "0rem 1.5rem" + position: 'relative', + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + textAlign: 'center', + width: '100%' +})); +export const MetricsContainerFront = styled('div')(({ isDetailed }) => ({ + display: 'flex', + justifyContent: 'space-around', + // borderTop: "0.851px solid #C9DBE3", + fontSize: '0.2rem', + color: 'rgba(26, 26, 26, .8)', + // margin: "-0.8rem 0.7rem 0", + padding: '0.9rem 0.1rem', + background: '#E7EFF3', + ...(isDetailed && { + position: 'absolute', + bottom: '0px' + }), + ...(!isDetailed && { + marginTop: '1.2rem' + }), + borderRadius: '0 0 0.9375rem 0.9375rem', + width: '100%' +})); + +export const MetricsDiv = styled('div')(() => ({ + display: 'flex', + alignItems: 'center', + gap: '4px', + fontSize: '0.2rem', + color: 'rgba(26, 26, 26, .8)', + margin: '0rem', + padding: '0.1rem' +})); +export const DesignDetailsDiv = styled('div')(() => ({ + height: 'max-content', + display: 'flex', + marginTop: '-1rem', + flexDirection: 'column', + padding: '0rem 1rem', + justifyContent: 'start', + alignItems: 'start', + ['@media (max-width:1200px)']: { + height: 'max-content' + } +})); + +export const ImageWrapper = styled('div')(({ theme }) => ({ + background: theme.palette.mode === 'light' ? 'rgba(231, 239, 243, 0.40)' : '#212121', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + padding: '0.5rem', + width: '100%', + borderRadius: '0.5rem' +})); + +export const VersionTag = styled('div')(({ theme }) => ({ + display: 'inline-block', + backgroundColor: theme.palette.background.supplementary, + color: theme.palette.text.constant?.white, + borderRadius: '4px', + fontSize: '0.75rem', + fontWeight: 'bold', + margin: '5px 0', + padding: '2px 5px', + maxWidth: 'fit-content' +})); + +export const FlipCard = styled('div')(() => ({ + perspective: '1000px', + '&:hover .flipper': { + transform: 'rotateY(-180deg)' + } +})); + +export const Flipper = styled('div')(() => ({ + transition: '0.6s', + transformStyle: 'preserve-3d', + position: 'relative' +})); + +export const Face = styled('div')(() => ({ + backfaceVisibility: 'hidden', + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%' +})); + +export const FrontFace = styled(Face)(() => ({ + zIndex: 2, + transform: 'rotateY(0deg)' +})); + +export const BackFace = styled('div')(() => ({ + transform: 'rotateY(-180deg)', + color: '#fff', + display: 'inline-flex', + flexDirection: 'column', + padding: '16px', + height: '100%', + width: '100%', + position: 'relative', + bottom: 0, + left: 0, + backfaceVisibility: 'hidden' +})); + +export const BackFaceContent = styled('div')(({ theme }) => ({ + position: 'absolute', + background: `linear-gradient(to bottom right, black 40%, ${theme.palette.background.brand?.default})`, + width: '100%', + top: 0, + left: 0, + display: 'flex', + flexDirection: 'column', + alignItems: 'left', + padding: '16px', + boxShadow: `2px 2px 3px 0px black`, + borderRadius: '1rem' +})); + +export const ProfileSection = styled('div')({ + display: 'flex', + alignItems: 'center', + marginBottom: '16px' +}); + +export const TechnologiesSection = styled('div')(({ theme }) => ({ + backgroundColor: 'rgba(255, 255, 255, 0.25)', + padding: theme.spacing(1), + borderRadius: theme.shape.borderRadius, + marginBottom: '16px' +})); + +export const UpdatedSection = styled('div')({ + display: 'flex', + alignItems: 'center', + color: '#fff', + margin: '20px 0' +}); + +export const CardBack = styled('div')(({ isCatalog }) => ({ + boxShadow: `2px 2px 3px 0px rgba(26, 26, 26, 1)`, + position: 'absolute', + width: '100%', + height: '100%', + WebkitBackfaceVisibility: 'hidden', + borderRadius: '0.9375rem', + backfaceVisibility: 'hidden', + color: 'white', + transform: 'rotateY(180deg)', + ...(isCatalog && { + background: + 'linear-gradient(335deg, rgba(0, 179, 159, 0.80) -13.6%, rgba(0, 0, 0, 0.68) 66.8%), radial-gradient(3970.04% 147.22% at 47.5% 100%, #000 0%, #395357 100%)' + }), + ...(!isCatalog && { + background: 'linear-gradient(250deg, #477e96 0%, #00b39f 35%, rgb(60, 73, 79) 100%)' + }) +})); + +export const CardFront = styled('div')(({ shouldFlip, isDetailed, theme }) => ({ + ...(shouldFlip && { + position: 'absolute', + boxShadow: `2px 2px 3px 0px ${theme.palette.background.brand?.default}`, + background: `linear-gradient(to left bottom, #EBEFF1, #f4f5f7, #f7f7f9, white, white, white, white, white, white, #f7f7f9, #f4f5f7, #EBEFF1);` + }), + ...(isDetailed && { + boxShadow: `2px 2px 3px 0px ${theme.palette.background.brand?.default}`, + background: `linear-gradient(to left bottom, #EBEFF1, #f4f5f7, #f7f7f9, white, white, white, white, white, white, #f7f7f9, #f4f5f7, #EBEFF1);` + }), + width: '100%', + height: '100%', + WebkitBackfaceVisibility: 'hidden', + borderRadius: '0.9375rem', + backfaceVisibility: 'hidden' +})); + +export const DateText = styled('div')(() => ({ + fontSize: '0.875rem', + textTransform: 'capitalize', + color: '#eee', + margin: '0rem', + padding: '0.1rem', + fontWeight: '400', + lineHeight: '1.5' +})); + +export const DateType = styled('p')(() => ({ + fontSize: '0.876rem', + margin: '0rem', + lineHeight: '1.5', + fontWeight: '400', + color: '#eee' +})); + +export const DesignAuthorName = styled('div')(() => ({ + height: 'max-content', + display: 'flex', + margin: '0', + flexDirection: 'column', + padding: '0rem 1rem', + justifyContent: 'start', + alignItems: 'start', + fontWeight: '400', + textAlign: 'right', + color: '#E7EFF3', + textTransform: 'capitalize', + ['@media (max-width:1200px)']: { + height: 'max-content' + } +})); diff --git a/src/custom/index.tsx b/src/custom/index.tsx index b2fd178a7..24b20882d 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -3,6 +3,7 @@ import { BookmarkNotification } from './BookmarkNotification'; import CatalogFilter, { CatalogFilterProps } from './CatalogFilter/CatalogFilter'; import { ChapterCard } from './ChapterCard'; import { ConnectionChip } from './ConnectionChip'; +import { CustomCatalogCard } from './CustomCatalog'; import { CustomColumn, CustomColumnVisibilityControl, @@ -57,6 +58,7 @@ export { CatalogFilter, ChapterCard, ConnectionChip, + CustomCatalogCard, CustomColumnVisibilityControl, CustomDialog, CustomImage, From 65ef6303f61fbd3c3767c9ca53bf28bdf1ae8f46 Mon Sep 17 00:00:00 2001 From: Yash sharma <71271069+Yashsharma1911@users.noreply.github.com> Date: Wed, 4 Sep 2024 19:03:57 +0530 Subject: [PATCH 002/103] Update publish modal schema Signed-off-by: Yash sharma <71271069+Yashsharma1911@users.noreply.github.com> --- src/schemas/publishCatalogItem/schema.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/schemas/publishCatalogItem/schema.tsx b/src/schemas/publishCatalogItem/schema.tsx index 9219fc2bc..6c9b5ea3a 100644 --- a/src/schemas/publishCatalogItem/schema.tsx +++ b/src/schemas/publishCatalogItem/schema.tsx @@ -24,14 +24,16 @@ const publishCatalogItemSchema = { description: 'Specific stipulations to consider and known behaviors to be aware of when using this design.', format: 'textarea', - 'x-rjsf-grid-area': 12 + 'x-rjsf-grid-area': 12, + "x-encode-in-uri": true }, pattern_info: { type: 'string', title: 'Description', description: 'Purpose of the design along with its intended and unintended uses.', format: 'textarea', - 'x-rjsf-grid-area': 12 + 'x-rjsf-grid-area': 12, + "x-encode-in-uri": true }, type: { type: 'string', From 98b8a81700bf6e0d307e5631bcf6dcbfa8c9821f Mon Sep 17 00:00:00 2001 From: Sumitsh28 Date: Fri, 4 Oct 2024 20:22:50 +0530 Subject: [PATCH 003/103] feat(Tooltip): add box shadow to Tooltip component Signed-off-by: Sumitsh28 --- src/custom/CustomTooltip/customTooltip.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/custom/CustomTooltip/customTooltip.tsx b/src/custom/CustomTooltip/customTooltip.tsx index ac5f4c523..7287c152e 100644 --- a/src/custom/CustomTooltip/customTooltip.tsx +++ b/src/custom/CustomTooltip/customTooltip.tsx @@ -34,7 +34,9 @@ function CustomTooltip({ fontSize: fontSize || (variant === 'standard' ? '1rem' : '0.75rem'), fontWeight: { fontWeight }, borderRadius: '0.5rem', - padding: variant === 'standard' ? '0.9rem' : '0.5rem 0.75rem' + padding: variant === 'standard' ? '0.9rem' : '0.5rem 0.75rem', + boxShadow: + 'rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px' } }, popper: { From c4ee39aca36469c9880585a7525f7664de24a002 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 9 Oct 2024 11:57:54 +0530 Subject: [PATCH 004/103] chore: create style for catalog filter Signed-off-by: Amit Amrutiya --- src/custom/CatalogFilterSection/style.tsx | 85 +++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/custom/CatalogFilterSection/style.tsx diff --git a/src/custom/CatalogFilterSection/style.tsx b/src/custom/CatalogFilterSection/style.tsx new file mode 100644 index 000000000..f8452e6ec --- /dev/null +++ b/src/custom/CatalogFilterSection/style.tsx @@ -0,0 +1,85 @@ +import { styled } from '@mui/material/styles'; +import { Box, Button, InputAdornment, ListItemButton } from '../../base'; +import { CARIBBEAN_GREEN, CHINESE_SILVER, CULTURED, DARK_SLATE_GRAY, KEPPEL } from '../../theme'; +import { StyleProps } from './CatalogFilterSidebar'; + +export const FiltersCardDiv = styled(Box)<{ styleProps: StyleProps }>(({ styleProps }) => ({ + padding: '1rem', + borderRadius: '1rem', + width: '100%', + gap: '0.5rem', + boxShadow: '0px 2px 10px rgba(0, 0, 0, 0.2)', + display: 'flex', + flexDirection: 'column', + height: 'fit-content', + backgroundColor: styleProps.backgroundColor, + ['@media (max-width:900px)']: { + display: 'none' + } +})); + +export const FilterDrawerDiv = styled('div')(() => ({ + display: 'none', + ['@media (max-width:899px)']: { + display: 'block' + } +})); + +export const LabelDiv = styled('div')(() => ({ + display: 'flex', + justifyContent: 'space-around', + alignItems: 'center' +})); + +export const FilterButton = styled(Button)(() => ({ + backgroundColor: KEPPEL, + '&:hover': { + backgroundColor: CARIBBEAN_GREEN + }, + height: '3.5rem', + ['@media (max-width:450px)']: { + minWidth: '0px' + } +})); + +export const FiltersDrawerHeader = styled(Box)(() => ({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '0.5rem 1rem', + backgroundColor: DARK_SLATE_GRAY, + height: '10vh', + boxShadow: '0px 4px 4px rgba(0, 179, 159, 0.4)', + marginBottom: '0.625rem' +})); + +export const CheckBoxButton = styled(ListItemButton)(() => ({ + padding: '0.25rem 2rem', + borderBottom: '1px solid', + borderBottomColor: CHINESE_SILVER +})); + +export const FilterTitleButton = styled(ListItemButton)(() => ({ + backgroundColor: CULTURED, + borderRadius: '0.5rem', + marginTop: 2, + display: 'flex', + justifyContent: 'space-between' +})); + +export const InputAdornmentEnd = styled(InputAdornment)(() => ({ + borderLeft: `1px solid ${CHINESE_SILVER}`, + height: '30px', + paddingLeft: '10px', + '@media (max-width: 590px)': { + paddingLeft: '0px' + } +})); + +export const FilterText = styled('span')(() => ({ + marginLeft: '0.5rem', + display: 'block', + '@media (max-width: 853px)': { + display: 'none' + } +})); From bbbdafce2b8cb6bf2ec2c0832d883950f7f76273 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 9 Oct 2024 11:58:31 +0530 Subject: [PATCH 005/103] chore: create catalog filter sidebar Signed-off-by: Amit Amrutiya --- .../CatalogFilterSidebar.tsx | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx new file mode 100644 index 000000000..6b357085e --- /dev/null +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx @@ -0,0 +1,123 @@ +import FilterAltIcon from '@mui/icons-material/FilterAlt'; +import { useCallback, useState } from 'react'; +import { Box, Drawer, Typography } from '../../base'; +import { CloseIcon } from '../../icons'; +import { CULTURED, DARK_SLATE_GRAY, WHITE } from '../../theme'; +import { CloseBtn } from '../Modal'; +import CatalogFilterSidebarState from './CatalogFilterSidebarState'; +import { + FilterButton, + FilterDrawerDiv, + FilterText, + FiltersCardDiv, + FiltersDrawerHeader +} from './style'; + +export interface FilterOption { + value: string; + label: string; + totalCount?: number; + description?: string; + Icon?: React.ComponentType<{ + width: string; + height: string; + }>; +} + +export interface FilterList { + filterKey: string; + sectionDisplayName?: string; + options: FilterOption[]; + defaultOpen?: boolean; + isMultiSelect?: boolean; +} + +export interface CatalogFilterSidebarProps { + setData: (callback: (prevFilters: FilterValues) => FilterValues) => void; + lists: FilterList[]; + value?: FilterValues; +} + +export type FilterValues = Record; + +export interface StyleProps { + backgroundColor?: string; + sectionTitleBackgroundColor?: string; +} + +/** + * @function CatalogFilterSidebar + * @description A functional component that renders the filter sidebar. + * @param {Array} value - The data to be filtered. + * @param {Function} setData - A function to set the filtered data. + * @param {Array} lists - An array of filter sections and it's options lists. + */ +const CatalogFilterSidebar: React.FC = ({ + lists, + setData, + value = {} +}) => { + const [openDrawer, setOpenDrawer] = useState(false); + + const handleDrawerOpen = useCallback(() => { + setOpenDrawer(true); + }, []); + + const handleDrawerClose = useCallback(() => { + setOpenDrawer(false); + }, []); + + const styleProps: StyleProps = { + backgroundColor: WHITE, + sectionTitleBackgroundColor: CULTURED + }; + + return ( + <> + + + + + + + Filters + + + + + + + Filters + + + + + + + + + + + + + + ); +}; + +export default CatalogFilterSidebar; From 623fd121d8359e34cca8463956a9695ce37a5176 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 9 Oct 2024 11:58:44 +0530 Subject: [PATCH 006/103] chore: create catalog filter sidebar state component Signed-off-by: Amit Amrutiya --- .../CatalogFilterSidebarState.tsx | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx new file mode 100644 index 000000000..ea92e3a1b --- /dev/null +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx @@ -0,0 +1,97 @@ +import { useCallback, useState } from 'react'; +import { + CatalogFilterSidebarProps, + FilterList, + FilterValues, + StyleProps +} from './CatalogFilterSidebar'; +import FilterSection from './FilterSection'; +/** + * @component CatalogFilterSidebarState + * @description A functional component that manages the filter state. + * @param {Array} lists - An array of filter sections and its options lists. + * @param {Function} onApplyFilters - A function to apply the filters. + * @param {Object} value - The selected filters. + * @param {Object} styleProps - The style properties for the component. + */ +const CatalogFilterSidebarState: React.FC<{ + lists: FilterList[]; + onApplyFilters: CatalogFilterSidebarProps['setData']; + value: FilterValues; + styleProps: StyleProps; +}> = ({ lists, onApplyFilters, value, styleProps }) => { + // Generate initial state with all sections open by default + const [openSections, setOpenSections] = useState>(() => { + const initialOpenSections: Record = {}; + lists.forEach((list) => { + initialOpenSections[list.filterKey] = !!list.defaultOpen; + }); + return initialOpenSections; + }); + + /** + * @function handleSectionToggle + * @description Handles the section toggle event. + * @param {string} filterKey - The name of the filter section. + */ + const handleSectionToggle = useCallback((filterKey: string) => { + setOpenSections((prevOpenSections) => ({ + ...prevOpenSections, + [filterKey]: !prevOpenSections[filterKey] + })); + }, []); + + /** + * @function handleCheckboxChange + * @description Handles the checkbox change event. + * @param {string} filterKey - The name of the filter section. + * @param {string} value - The value of the checkbox. + * @param {boolean} checked - The checked state of the checkbox. + */ + const handleCheckboxChange = useCallback( + (filterKey: string, value: string, checked: boolean) => { + onApplyFilters((prevFilters) => { + const updatedFilters = { ...prevFilters }; + const filterList = lists.find((list) => list.filterKey === filterKey); + + // default is multi select + if (filterList?.isMultiSelect !== false) { + let currentValues = updatedFilters[filterKey] as string[] | undefined; + + if (!Array.isArray(currentValues)) { + currentValues = currentValues ? [currentValues as string] : []; // convert to array; + } + + updatedFilters[filterKey] = checked + ? [...currentValues, value] + : currentValues.filter((item) => item !== value); + } else { + updatedFilters[filterKey] = checked ? value : ''; + } + + return updatedFilters; + }); + }, + [lists, onApplyFilters] + ); + + return ( + <> + {lists.map((list) => ( + + ))} + + ); +}; + +export default CatalogFilterSidebarState; From 79989ffafa17f17450579d36b22846d70f91bc89 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 9 Oct 2024 11:58:58 +0530 Subject: [PATCH 007/103] chore: create catalog filter section component Signed-off-by: Amit Amrutiya --- .../CatalogFilterSection/FilterSection.tsx | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/custom/CatalogFilterSection/FilterSection.tsx diff --git a/src/custom/CatalogFilterSection/FilterSection.tsx b/src/custom/CatalogFilterSection/FilterSection.tsx new file mode 100644 index 000000000..af937876f --- /dev/null +++ b/src/custom/CatalogFilterSection/FilterSection.tsx @@ -0,0 +1,142 @@ +import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import { useCallback, useState } from 'react'; +import { + Box, + Checkbox, + Collapse, + InputAdornment, + List, + OutlinedInput, + Stack, + Typography +} from '../../base'; +import { SearchIcon } from '../../icons'; +import { InfoTooltip } from '../CustomTooltip'; +import { FilterOption, FilterValues, StyleProps } from './CatalogFilterSidebar'; +import { FilterTitleButton, InputAdornmentEnd } from './style'; + +interface FilterSectionProps { + filterKey: string; + sectionDisplayName?: string; + options: FilterOption[]; + filters: FilterValues; + openSections: Record; + onCheckboxChange: (filterKey: string, value: string, checked: boolean) => void; + onSectionToggle: (filterKey: string) => void; + styleProps: StyleProps; +} + +/** + * @component FilterSection + * @description A functional component that renders a filter section. + * @param {string} filterKey - The key of the filter section. + * @param {string} sectionDisplayName - The title of the filter section. + * @param {Array} options - The available options for the filter section. + * @param {Object} filters - The selected filters. + * @param {Object} openSections - The open/closed state of the filter sections. + * @param {Function} onCheckboxChange - A function to handle checkbox change event. + * @param {Function} onSectionToggle - A function to handle section toggle event. + * @param {Object} styleProps - The style properties for the component. + */ +const FilterSection: React.FC = ({ + filterKey, + sectionDisplayName, + options, + filters, + openSections, + onCheckboxChange, + onSectionToggle, + styleProps +}) => { + const [searchQuery, setSearchQuery] = useState(''); + + const handleTextFieldChange = useCallback((e: React.ChangeEvent) => { + setSearchQuery(e.target.value); + }, []); + + const showSearch = options.length > 10; + const searchedOptions = searchQuery + ? options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())) + : options; + + return ( + <> + onSectionToggle(filterKey)} + style={{ backgroundColor: styleProps.sectionTitleBackgroundColor }} + > + + {(sectionDisplayName || filterKey).toUpperCase()} + + {openSections[filterKey] ? : } + + + + {showSearch && ( + + + + + } + endAdornment={ + + Total: {searchedOptions.length} + + } + /> + + )} + {searchedOptions.map((option, index) => ( + + + onCheckboxChange(filterKey, option.value, e.target.checked)} + value={option.value} + /> + + {option.Icon && } + + {option.label} + + + {option.totalCount !== undefined && `(${option.totalCount || 0})`} + {option.description && ( + + )} + + + ))} + + + + ); +}; + +export default FilterSection; From 05fc8905c85efd0ab13e4e60bef82733c2d337cc Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 9 Oct 2024 11:59:43 +0530 Subject: [PATCH 008/103] chore: export catalog filter section Signed-off-by: Amit Amrutiya --- src/custom/CatalogFilterSection/index.tsx | 3 +++ src/custom/index.tsx | 1 + 2 files changed, 4 insertions(+) create mode 100644 src/custom/CatalogFilterSection/index.tsx diff --git a/src/custom/CatalogFilterSection/index.tsx b/src/custom/CatalogFilterSection/index.tsx new file mode 100644 index 000000000..bab5baf47 --- /dev/null +++ b/src/custom/CatalogFilterSection/index.tsx @@ -0,0 +1,3 @@ +import CatalogFilterSidebar from './CatalogFilterSidebar'; + +export { CatalogFilterSidebar }; diff --git a/src/custom/index.tsx b/src/custom/index.tsx index 45c772aab..8c57e1a92 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -43,6 +43,7 @@ import { TransferList } from './TransferModal/TransferList'; import { TransferListProps } from './TransferModal/TransferList/TransferList'; import UniversalFilter, { UniversalFilterProps } from './UniversalFilter'; export { CatalogCard } from './CatalogCard'; +export { CatalogFilterSidebar } from './CatalogFilterSection'; export { StyledChartDialog } from './ChartDialog'; export { LearningContent } from './LearningContent'; export { Note } from './Note'; From c21df77e265a555db5c9eb3a3f0a27a45385b235 Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Wed, 9 Oct 2024 19:31:32 +0530 Subject: [PATCH 009/103] feat(revamp): card Signed-off-by: Sudhanshu Dasgupta --- src/custom/CustomCatalog/custom-card.tsx | 140 ++++++++++++++++++----- src/custom/CustomCatalog/style.tsx | 43 ++++++- 2 files changed, 147 insertions(+), 36 deletions(-) diff --git a/src/custom/CustomCatalog/custom-card.tsx b/src/custom/CustomCatalog/custom-card.tsx index a73d1b090..53ff8414e 100644 --- a/src/custom/CustomCatalog/custom-card.tsx +++ b/src/custom/CustomCatalog/custom-card.tsx @@ -1,11 +1,12 @@ import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; -import { Avatar, Box, Typography, styled } from '@mui/material'; -import React from 'react'; +import { Avatar, Typography, styled } from '@mui/material'; +import React, { useEffect, useState } from 'react'; import { Grid } from '../../base'; import { CloneIcon, CommunityClassIcon, OfficialClassIcon, OpenIcon, ShareIcon } from '../../icons'; import VerificationClassIcon from '../../icons/ContentClassIcons/VerificationClassIcon'; import DeploymentsIcon from '../../icons/Deployments/DeploymentsIcon'; import { DownloadIcon } from '../../icons/Download'; +import { CustomTooltip } from '../CustomTooltip'; import { CardBack, CardFront, @@ -20,10 +21,12 @@ import { MetricsContainerFront, MetricsCount, MetricsDiv, + NoTechnologyText, ProfileSection, StyledClassWrapper, StyledInnerClassWrapper, TechnologiesSection, + TechnologyText, VersionTag } from './style'; @@ -48,6 +51,7 @@ interface Pattern { catalog_data?: { content_class?: string; imageURL?: string; + compatibility?: string[]; }; visibility: string; updated_at: Date; @@ -64,6 +68,7 @@ type CatalogCardProps = { type: string; version?: string; avatarUrl: string; + compatibility: string[]; userName: string; technologies: string[]; updatedAt: string; @@ -74,7 +79,10 @@ type CatalogCardProps = { date?: boolean; cardVersion?: boolean; UserName?: string; - children?: React.ReactNode; + children?: React.ReactNode; // catalogImage + TechnologyComponent?: React.ReactNode; + basePath?: string; // path of meshmodel img stored + getHostUrl?: () => string; }; export const ClassToIconMap = { @@ -104,13 +112,13 @@ const CustomCatalogCard: React.FC = ({ cardLink, shouldFlip, isDetailed, - cardAvatarUrl, cardTechnologies, - date, cardVersion, avatarUrl, UserName, - children + children, + basePath, + getHostUrl }) => { const outerStyles = { height: cardHeight, @@ -118,6 +126,47 @@ const CustomCatalogCard: React.FC = ({ ...cardStyles }; + const technologies = pattern.catalog_data?.compatibility || []; // an array + const techlimit = 5; + const [availableTechnologies, setAvailableTechnologies] = useState([]); + const checkImageUrlValidity = async (url: string, appendHostUrl = true) => { + return new Promise((resolve) => { + const img = new Image(); + // Only append host if the URL does not start with "http" or "https" + if (appendHostUrl && !url.startsWith('http')) { + img.src = (getHostUrl ? getHostUrl() : '') + url; + } else { + img.src = url; + } + img.onload = () => { + // Check if the image loaded successfully + resolve(true); + }; + + img.onerror = () => { + // Handle the case where the image could not be loaded + resolve(false); + }; + }); + }; + + const handleImage = async () => { + const validSvgPaths = []; + for (const technology of technologies) { + const svgIconPath = `${basePath}/${technology.toLowerCase()}/icons/color/${technology.toLowerCase()}-color.svg`; + const isSvgPathValid = await checkImageUrlValidity(svgIconPath as string); + if (isSvgPathValid) { + validSvgPaths.push(technology); + } + } + + setAvailableTechnologies(validSvgPaths); + }; + useEffect(() => { + handleImage(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( @@ -181,39 +230,70 @@ const CustomCatalogCard: React.FC = ({ {shouldFlip && ( - {cardAvatarUrl && ( - - - {UserName} - - )} + + + {UserName} + {cardTechnologies && ( - Technologies + - Technologies - - - Kubernetes - + {technologies.length < 1 || availableTechnologies.length < 1 ? ( + No technologies + ) : ( + <> + {availableTechnologies.slice(0, techlimit).map((technology, index) => { + const svgPath = + (getHostUrl ? getHostUrl() : '') + + `${basePath}/${technology.toLowerCase()}/icons/color/${technology.toLowerCase()}-color.svg`; + return ( + + + {technology.toLowerCase()} + + + ); + })} + {availableTechnologies.length > techlimit && ( + + +{availableTechnologies.length - techlimit} + + )} + + )} + )} - {date && ( - + {isDetailed && ( + ({ left: '-3px' })); +export const TechnologyText = styled('div')(() => ({ + color: '#eee', + fontSize: '0.875rem', + lineHeight: '1.5', + fontWeight: '600', + borderBottom: '1px solid rgba(231, 239, 243, 0.40)' +})); + +export const NoTechnologyText = styled('div')(() => ({ + color: '#eee', + overflow: 'hidden', + fontSize: '14px', + lineHeight: '24px', + fontWeight: '400', + marginTop: '.8rem' +})); + export const StyledInnerClassWrapper = styled('div')(({ catalogClassName }) => { @@ -251,16 +268,30 @@ export const BackFaceContent = styled('div')(({ theme }) => ({ })); export const ProfileSection = styled('div')({ + height: 'max-content', display: 'flex', + marginTop: '1.2rem', + flexDirection: 'row', + padding: '0rem 1rem', + justifyContent: 'flex-start', alignItems: 'center', - marginBottom: '16px' + ['@media (max-width:1200px)']: { + height: 'max-content' + } }); -export const TechnologiesSection = styled('div')(({ theme }) => ({ - backgroundColor: 'rgba(255, 255, 255, 0.25)', - padding: theme.spacing(1), - borderRadius: theme.shape.borderRadius, - marginBottom: '16px' +export const TechnologiesSection = styled('div')(() => ({ + marginBottom: '16px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + width: '100%', + gap: '1rem', + alignItems: 'flex-start', + background: 'rgba(231, 239, 243, 0.40)', + borderRadius: '0.25rem', + padding: '0.5rem 1rem', + alignSelf: 'stretch' })); export const UpdatedSection = styled('div')({ From cdb37758b866b93834ae2d38813a5cc692b4ae86 Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Wed, 9 Oct 2024 19:33:31 +0530 Subject: [PATCH 010/103] fix(lint): linting Signed-off-by: Sudhanshu Dasgupta --- src/custom/CustomCatalog/custom-card.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/custom/CustomCatalog/custom-card.tsx b/src/custom/CustomCatalog/custom-card.tsx index 53ff8414e..06ee8018d 100644 --- a/src/custom/CustomCatalog/custom-card.tsx +++ b/src/custom/CustomCatalog/custom-card.tsx @@ -58,7 +58,6 @@ interface Pattern { } type CatalogCardProps = { - // eslint-disable-next-line @typescript-eslint/no-explicit-any pattern: Pattern; patternType: string; cardLink: string; From e08a79f26af30cfb2dbe92d7c77ec9106d7919b4 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 9 Oct 2024 21:31:01 +0530 Subject: [PATCH 011/103] chore: use token for all of the theme text Signed-off-by: Amit Amrutiya --- .../CatalogFilterSidebar.tsx | 18 ++++++++------- .../CatalogFilterSidebarState.tsx | 1 + src/custom/CatalogFilterSection/style.tsx | 23 +++++++++---------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx index 6b357085e..8cc176221 100644 --- a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx @@ -1,8 +1,8 @@ import FilterAltIcon from '@mui/icons-material/FilterAlt'; +import { useTheme } from '@mui/material/styles'; import { useCallback, useState } from 'react'; import { Box, Drawer, Typography } from '../../base'; import { CloseIcon } from '../../icons'; -import { CULTURED, DARK_SLATE_GRAY, WHITE } from '../../theme'; import { CloseBtn } from '../Modal'; import CatalogFilterSidebarState from './CatalogFilterSidebarState'; import { @@ -50,13 +50,14 @@ export interface StyleProps { * @description A functional component that renders the filter sidebar. * @param {Array} value - The data to be filtered. * @param {Function} setData - A function to set the filtered data. - * @param {Array} lists - An array of filter sections and it's options lists. + * @param {Array} lists - An array of filter sections and its options lists. */ const CatalogFilterSidebar: React.FC = ({ lists, setData, value = {} }) => { + const theme = useTheme(); // Get the current theme const [openDrawer, setOpenDrawer] = useState(false); const handleDrawerOpen = useCallback(() => { @@ -68,8 +69,8 @@ const CatalogFilterSidebar: React.FC = ({ }, []); const styleProps: StyleProps = { - backgroundColor: WHITE, - sectionTitleBackgroundColor: CULTURED + backgroundColor: theme.palette.background.default, + sectionTitleBackgroundColor: theme.palette.background.surfaces }; return ( @@ -84,14 +85,14 @@ const CatalogFilterSidebar: React.FC = ({ - + Filters - + Filters @@ -102,7 +103,7 @@ const CatalogFilterSidebar: React.FC = ({ style={{ height: '75vh', overflowY: 'auto', - background: WHITE + background: theme.palette.background.default }} > = ({ styleProps={styleProps} /> - + + {/* Use theme-aware color */} diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx index ea92e3a1b..76b0d72d3 100644 --- a/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx @@ -6,6 +6,7 @@ import { StyleProps } from './CatalogFilterSidebar'; import FilterSection from './FilterSection'; + /** * @component CatalogFilterSidebarState * @description A functional component that manages the filter state. diff --git a/src/custom/CatalogFilterSection/style.tsx b/src/custom/CatalogFilterSection/style.tsx index f8452e6ec..d722a0c3a 100644 --- a/src/custom/CatalogFilterSection/style.tsx +++ b/src/custom/CatalogFilterSection/style.tsx @@ -1,6 +1,5 @@ import { styled } from '@mui/material/styles'; import { Box, Button, InputAdornment, ListItemButton } from '../../base'; -import { CARIBBEAN_GREEN, CHINESE_SILVER, CULTURED, DARK_SLATE_GRAY, KEPPEL } from '../../theme'; import { StyleProps } from './CatalogFilterSidebar'; export const FiltersCardDiv = styled(Box)<{ styleProps: StyleProps }>(({ styleProps }) => ({ @@ -31,10 +30,10 @@ export const LabelDiv = styled('div')(() => ({ alignItems: 'center' })); -export const FilterButton = styled(Button)(() => ({ - backgroundColor: KEPPEL, +export const FilterButton = styled(Button)(({ theme }) => ({ + backgroundColor: theme.palette.primary.brand?.default, '&:hover': { - backgroundColor: CARIBBEAN_GREEN + backgroundColor: theme.palette.background.default }, height: '3.5rem', ['@media (max-width:450px)']: { @@ -42,33 +41,33 @@ export const FilterButton = styled(Button)(() => ({ } })); -export const FiltersDrawerHeader = styled(Box)(() => ({ +export const FiltersDrawerHeader = styled(Box)(({ theme }) => ({ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '0.5rem 1rem', - backgroundColor: DARK_SLATE_GRAY, + backgroundColor: theme.palette.border.strong, height: '10vh', boxShadow: '0px 4px 4px rgba(0, 179, 159, 0.4)', marginBottom: '0.625rem' })); -export const CheckBoxButton = styled(ListItemButton)(() => ({ +export const CheckBoxButton = styled(ListItemButton)(({ theme }) => ({ padding: '0.25rem 2rem', borderBottom: '1px solid', - borderBottomColor: CHINESE_SILVER + borderBottomColor: theme.palette.text.disabled })); -export const FilterTitleButton = styled(ListItemButton)(() => ({ - backgroundColor: CULTURED, +export const FilterTitleButton = styled(ListItemButton)(({ theme }) => ({ + backgroundColor: theme.palette.background.surfaces, borderRadius: '0.5rem', marginTop: 2, display: 'flex', justifyContent: 'space-between' })); -export const InputAdornmentEnd = styled(InputAdornment)(() => ({ - borderLeft: `1px solid ${CHINESE_SILVER}`, +export const InputAdornmentEnd = styled(InputAdornment)(({ theme }) => ({ + borderLeft: `1px solid ${theme.palette.text.disabled}`, height: '30px', paddingLeft: '10px', '@media (max-width: 590px)': { From 7d5c9c6a2fc8da8b6b90f3b9df1c0b079a612117 Mon Sep 17 00:00:00 2001 From: jerensl <54782057+jerensl@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:35:15 +0800 Subject: [PATCH 012/103] refactor: make the link tag optional on learning card Signed-off-by: jerensl <54782057+jerensl@users.noreply.github.com> --- src/custom/LearningCard/LearningCard.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/custom/LearningCard/LearningCard.tsx b/src/custom/LearningCard/LearningCard.tsx index 9ef01a1ce..0797c6cc4 100644 --- a/src/custom/LearningCard/LearningCard.tsx +++ b/src/custom/LearningCard/LearningCard.tsx @@ -25,11 +25,19 @@ interface Tutorial { interface Props { tutorial: Tutorial; - path: string; + path?: string; courseCount: number; courseType: string; } +const OptionalLink: React.PropsWithChildren<{path?: string}> = ({ path, children }) => { + if (!path) { + return <>{children} + } + + return {children} +} + const LearningCard: React.FC = ({ tutorial, path, courseCount, courseType }) => { return ( @@ -57,7 +65,7 @@ const LearningCard: React.FC = ({ tutorial, path, courseCount, courseType ) : ( - +
@@ -88,7 +96,7 @@ const LearningCard: React.FC = ({ tutorial, path, courseCount, courseType
-
+ )}
); From 16c528e1e9ef685fbf9929ef7afce9b3f8a8b43b Mon Sep 17 00:00:00 2001 From: jerensl <54782057+jerensl@users.noreply.github.com> Date: Thu, 10 Oct 2024 20:17:12 +0800 Subject: [PATCH 013/103] chore(academy): fix prettier error Signed-off-by: jerensl <54782057+jerensl@users.noreply.github.com> --- src/custom/LearningCard/LearningCard.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/custom/LearningCard/LearningCard.tsx b/src/custom/LearningCard/LearningCard.tsx index 0797c6cc4..39e72e617 100644 --- a/src/custom/LearningCard/LearningCard.tsx +++ b/src/custom/LearningCard/LearningCard.tsx @@ -30,13 +30,13 @@ interface Props { courseType: string; } -const OptionalLink: React.PropsWithChildren<{path?: string}> = ({ path, children }) => { +const OptionalLink: React.PropsWithChildren<{ path?: string }> = ({ path, children }) => { if (!path) { - return <>{children} + return <>{children}; } - - return {children} -} + + return {children}; +}; const LearningCard: React.FC = ({ tutorial, path, courseCount, courseType }) => { return ( From f50c66416ea6cd852384df363946e50502298345 Mon Sep 17 00:00:00 2001 From: jerensl <54782057+jerensl@users.noreply.github.com> Date: Thu, 10 Oct 2024 20:36:05 +0800 Subject: [PATCH 014/103] refactor(academy): fix typescript error Signed-off-by: jerensl <54782057+jerensl@users.noreply.github.com> --- src/custom/LearningCard/LearningCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/custom/LearningCard/LearningCard.tsx b/src/custom/LearningCard/LearningCard.tsx index 39e72e617..910e6ea19 100644 --- a/src/custom/LearningCard/LearningCard.tsx +++ b/src/custom/LearningCard/LearningCard.tsx @@ -30,7 +30,7 @@ interface Props { courseType: string; } -const OptionalLink: React.PropsWithChildren<{ path?: string }> = ({ path, children }) => { +const OptionalLink: React.FC> = ({ path, children }) => { if (!path) { return <>{children}; } @@ -65,7 +65,7 @@ const LearningCard: React.FC = ({ tutorial, path, courseCount, courseType ) : ( - +
From 7224e57f3f56ea33b714e6b9d9a8565a1f2bb0a8 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Thu, 10 Oct 2024 23:07:07 +0530 Subject: [PATCH 015/103] fix: some of the styling in custom catalog card Signed-off-by: Amit Amrutiya --- src/custom/CustomCatalog/custom-card.tsx | 24 ++++++++++++++++------ src/custom/CustomCatalog/style.tsx | 26 +++++++++++++++++++++++- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/custom/CustomCatalog/custom-card.tsx b/src/custom/CustomCatalog/custom-card.tsx index 06ee8018d..c90d78f83 100644 --- a/src/custom/CustomCatalog/custom-card.tsx +++ b/src/custom/CustomCatalog/custom-card.tsx @@ -1,5 +1,5 @@ import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; -import { Avatar, Typography, styled } from '@mui/material'; +import { Avatar, styled } from '@mui/material'; import React, { useEffect, useState } from 'react'; import { Grid } from '../../base'; import { CloneIcon, CommunityClassIcon, OfficialClassIcon, OpenIcon, ShareIcon } from '../../icons'; @@ -27,7 +27,8 @@ import { StyledInnerClassWrapper, TechnologiesSection, TechnologyText, - VersionTag + VersionDiv, + VersionText } from './style'; export const DesignCardUrl = styled('a')(() => ({ @@ -166,6 +167,18 @@ const CustomCatalogCard: React.FC = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + if (!shouldFlip) { + return ( + + + + {children} + + + + ); + } + return ( @@ -329,11 +342,10 @@ const CustomCatalogCard: React.FC = ({ )} - {cardVersion && ( - - v{cardVersion} - + + v{cardVersion} + )} )} diff --git a/src/custom/CustomCatalog/style.tsx b/src/custom/CustomCatalog/style.tsx index d8a0ce98a..863caa418 100644 --- a/src/custom/CustomCatalog/style.tsx +++ b/src/custom/CustomCatalog/style.tsx @@ -212,6 +212,31 @@ export const VersionTag = styled('div')(({ theme }) => ({ maxWidth: 'fit-content' })); +export const VersionDiv = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + gap: '4px', + fontSize: '0.75', + color: theme.palette.text.constant?.white, + position: 'absolute', + bottom: '16px', + left: '16px', + borderRadius: '4px', + background: theme.palette.background.supplementary, + justifyContent: 'center' +})); + +export const VersionText = styled('p')(({ theme }) => ({ + fontSize: '0.75rem', + margin: '0', + padding: '0.25rem .5rem', + lineHeight: '1.5', + textTransform: 'lowercase', + fontWeight: '600', + borderRadius: '4.05px', + color: theme.palette.text.constant?.white +})); + export const FlipCard = styled('div')(() => ({ perspective: '1000px', '&:hover .flipper': { @@ -281,7 +306,6 @@ export const ProfileSection = styled('div')({ }); export const TechnologiesSection = styled('div')(() => ({ - marginBottom: '16px', display: 'flex', flexDirection: 'column', justifyContent: 'center', From a42050630bcf83de026c4429472e61ad2302e22b Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Fri, 11 Oct 2024 00:02:42 +0530 Subject: [PATCH 016/103] feat: refactor StyledSearchBar component and add search icon Signed-off-by: Amit Amrutiya --- .../StyledSearchBar/StyledSearchBar.tsx | 73 ++++++++++--------- src/custom/StyledSearchBar/style.tsx | 21 ++++++ 2 files changed, 61 insertions(+), 33 deletions(-) create mode 100644 src/custom/StyledSearchBar/style.tsx diff --git a/src/custom/StyledSearchBar/StyledSearchBar.tsx b/src/custom/StyledSearchBar/StyledSearchBar.tsx index d543bf520..2e2799bdb 100644 --- a/src/custom/StyledSearchBar/StyledSearchBar.tsx +++ b/src/custom/StyledSearchBar/StyledSearchBar.tsx @@ -1,51 +1,58 @@ +import { SxProps, Theme, useTheme } from '@mui/material'; import React from 'react'; -import { Box } from '../../base/Box'; -import { InputAdornment } from '../../base/Input'; -import { TextField } from '../../base/TextField'; +import { InputAdornment } from '../../base'; +import { SearchIcon } from '../../icons'; +import { InputAdornmentEnd, StyledSearchInput } from './style'; interface SearchBarProps { onChange?: (event: React.ChangeEvent) => void; value?: string; width?: string; - label: string; + label?: string; + placeholder?: string; + sx?: SxProps; endAdornment?: React.ReactNode; } +/** + * StyledSearchBar component renders a search input field with customizable properties. + * + * @param {Object} props - The component props. + * @param {function} [props.onChange] - Function to handle the change event when the search input value changes. + * @param {string} [props.value] - The current value of the search input. + * @param {string} [props.label] - The label for the search input. + * @param {string} [props.placeholder] - The placeholder text for the search input. + * @param {Object} [props.sx] - The style object for the search input. + * @param {React.ReactNode} [props.endAdornment] - The element to display at the end of the search input. + * + * @returns {JSX.Element} The rendered StyledSearchBar component. + */ function StyledSearchBar({ onChange, value, - width, label, - endAdornment, - ...props + sx, + placeholder, + endAdornment }: SearchBarProps): JSX.Element { + const theme = useTheme(); + return ( - - :not(style)': { width } - }} - {...props} - > - {endAdornment} - }} - /> - - + + + + } + endAdornment={{endAdornment}} + /> ); } diff --git a/src/custom/StyledSearchBar/style.tsx b/src/custom/StyledSearchBar/style.tsx new file mode 100644 index 000000000..92ce4187b --- /dev/null +++ b/src/custom/StyledSearchBar/style.tsx @@ -0,0 +1,21 @@ +import { styled } from '@mui/material'; +import { InputAdornment, OutlinedInput } from '../../base'; + +export const StyledSearchInput = styled(OutlinedInput)(({ style }) => ({ + width: '100%', + '@media (max-width: 590px)': { + marginLeft: '0.25rem', + paddingLeft: '0.25rem' + }, + display: 'flex', + ...style +})); + +export const InputAdornmentEnd = styled(InputAdornment)(({ theme }) => ({ + borderLeft: `1px solid ${theme.palette.border.normal}`, + height: '30px', + paddingLeft: '10px', + '@media (max-width: 590px)': { + paddingLeft: '0px' + } +})); From f6239ce202f5dd5201ab40e063a6d60c3dbe2c5a Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 13 Oct 2024 15:37:29 +0530 Subject: [PATCH 017/103] chore: filter section search styling Signed-off-by: Amit Amrutiya --- .../CatalogFilterSidebar.tsx | 17 ++++++++-- .../CatalogFilterSection/FilterSection.tsx | 32 ++++--------------- src/custom/CatalogFilterSection/style.tsx | 11 ++----- 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx index 8cc176221..d020d3412 100644 --- a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx @@ -3,6 +3,7 @@ import { useTheme } from '@mui/material/styles'; import { useCallback, useState } from 'react'; import { Box, Drawer, Typography } from '../../base'; import { CloseIcon } from '../../icons'; +import { darkTeal } from '../../theme'; import { CloseBtn } from '../Modal'; import CatalogFilterSidebarState from './CatalogFilterSidebarState'; import { @@ -69,8 +70,12 @@ const CatalogFilterSidebar: React.FC = ({ }, []); const styleProps: StyleProps = { - backgroundColor: theme.palette.background.default, - sectionTitleBackgroundColor: theme.palette.background.surfaces + backgroundColor: + theme.palette.mode === 'light' + ? theme.palette.background.default + : theme.palette.background.secondary, + sectionTitleBackgroundColor: + theme.palette.mode === 'light' ? theme.palette.background.surfaces : darkTeal.main }; return ( @@ -89,7 +94,13 @@ const CatalogFilterSidebar: React.FC = ({ Filters - + diff --git a/src/custom/CatalogFilterSection/FilterSection.tsx b/src/custom/CatalogFilterSection/FilterSection.tsx index af937876f..3f90a5eef 100644 --- a/src/custom/CatalogFilterSection/FilterSection.tsx +++ b/src/custom/CatalogFilterSection/FilterSection.tsx @@ -1,20 +1,11 @@ import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { useCallback, useState } from 'react'; -import { - Box, - Checkbox, - Collapse, - InputAdornment, - List, - OutlinedInput, - Stack, - Typography -} from '../../base'; -import { SearchIcon } from '../../icons'; +import { Box, Checkbox, Collapse, List, Stack, Typography } from '../../base'; import { InfoTooltip } from '../CustomTooltip'; +import { StyledSearchBar } from '../StyledSearchBar'; import { FilterOption, FilterValues, StyleProps } from './CatalogFilterSidebar'; -import { FilterTitleButton, InputAdornmentEnd } from './style'; +import { EndAdornmentText, FilterTitleButton } from './style'; interface FilterSectionProps { filterKey: string; @@ -81,22 +72,13 @@ const FilterSection: React.FC = ({ }} > {showSearch && ( - - + - - - } + placeholder="Search" endAdornment={ - - Total: {searchedOptions.length} - + Total : {searchedOptions.length ?? 0} } /> diff --git a/src/custom/CatalogFilterSection/style.tsx b/src/custom/CatalogFilterSection/style.tsx index d722a0c3a..a7694c57f 100644 --- a/src/custom/CatalogFilterSection/style.tsx +++ b/src/custom/CatalogFilterSection/style.tsx @@ -1,5 +1,5 @@ import { styled } from '@mui/material/styles'; -import { Box, Button, InputAdornment, ListItemButton } from '../../base'; +import { Box, Button, ListItemButton } from '../../base'; import { StyleProps } from './CatalogFilterSidebar'; export const FiltersCardDiv = styled(Box)<{ styleProps: StyleProps }>(({ styleProps }) => ({ @@ -66,13 +66,8 @@ export const FilterTitleButton = styled(ListItemButton)(({ theme }) => ({ justifyContent: 'space-between' })); -export const InputAdornmentEnd = styled(InputAdornment)(({ theme }) => ({ - borderLeft: `1px solid ${theme.palette.text.disabled}`, - height: '30px', - paddingLeft: '10px', - '@media (max-width: 590px)': { - paddingLeft: '0px' - } +export const EndAdornmentText = styled('p')(({ theme }) => ({ + color: theme.palette.text.tertiary })); export const FilterText = styled('span')(() => ({ From a230f760f0106a7ea86ae5bf929aa47f3c7cfe42 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 15 Oct 2024 15:38:16 +0530 Subject: [PATCH 018/103] feat: remove unwanted props and make catalogCard more generic Signed-off-by: Amit Amrutiya --- .../CatalogFilterSection/FilterSection.tsx | 2 +- src/custom/CustomCatalog/custom-card.tsx | 337 +++++++++--------- 2 files changed, 170 insertions(+), 169 deletions(-) diff --git a/src/custom/CatalogFilterSection/FilterSection.tsx b/src/custom/CatalogFilterSection/FilterSection.tsx index 3f90a5eef..2777fa38b 100644 --- a/src/custom/CatalogFilterSection/FilterSection.tsx +++ b/src/custom/CatalogFilterSection/FilterSection.tsx @@ -72,7 +72,7 @@ const FilterSection: React.FC = ({ }} > {showSearch && ( - + string; + onCardClick?: () => void; }; export const ClassToIconMap = { @@ -109,7 +106,6 @@ const CustomCatalogCard: React.FC = ({ cardHeight, cardWidth, cardStyles, - cardLink, shouldFlip, isDetailed, cardTechnologies, @@ -118,7 +114,9 @@ const CustomCatalogCard: React.FC = ({ UserName, children, basePath, - getHostUrl + subBasePath, + getHostUrl, + onCardClick }) => { const outerStyles = { height: cardHeight, @@ -153,7 +151,7 @@ const CustomCatalogCard: React.FC = ({ const handleImage = async () => { const validSvgPaths = []; for (const technology of technologies) { - const svgIconPath = `${basePath}/${technology.toLowerCase()}/icons/color/${technology.toLowerCase()}-color.svg`; + const svgIconPath = `${basePath}/${technology.toLowerCase()}/${subBasePath}/${technology.toLowerCase()}-color.svg`; const isSvgPathValid = await checkImageUrlValidity(svgIconPath as string); if (isSvgPathValid) { validSvgPaths.push(technology); @@ -180,178 +178,181 @@ const CustomCatalogCard: React.FC = ({ } return ( - - - - - {isDetailed && ( - <> - - {patternType} + + + + {isDetailed && ( + <> + + {patternType} - - {pattern.name} - - - )} - -
- {children} -
-
- {isDetailed && ( - - - - {pattern.download_count} - - - - {pattern.clone_count} - - - - {pattern.view_count} - - - - {pattern.deployment_count} - - - - {pattern.share_count} - - - )} -
- {shouldFlip && ( - - - - {UserName} - + {pattern.name} + + + )} + +
+ {children} +
+
+ {isDetailed && ( + + + + {pattern.download_count} + + + + {pattern.clone_count} + + + + {pattern.view_count} + + + + {pattern.deployment_count} + + + + {pattern.share_count} + + + )} +
+ {shouldFlip && ( + + + + {UserName} + - - {cardTechnologies && ( - - Technologies - - {technologies.length < 1 || availableTechnologies.length < 1 ? ( - No technologies - ) : ( - <> - {availableTechnologies.slice(0, techlimit).map((technology, index) => { - const svgPath = - (getHostUrl ? getHostUrl() : '') + - `${basePath}/${technology.toLowerCase()}/icons/color/${technology.toLowerCase()}-color.svg`; - return ( - - - {technology.toLowerCase()} - - - ); - })} - {availableTechnologies.length > techlimit && ( - - +{availableTechnologies.length - techlimit} + + {cardTechnologies && ( + + Technologies + + {technologies.length < 1 || availableTechnologies.length < 1 ? ( + No technologies + ) : ( + <> + {availableTechnologies.slice(0, techlimit).map((technology, index) => { + const svgPath = + (getHostUrl ? getHostUrl() : '') + + `${basePath}/${technology.toLowerCase()}/${subBasePath}/${technology.toLowerCase()}-color.svg`; + return ( + + + {technology.toLowerCase()} + - )} - - )} - - - )} - + ); + })} + {availableTechnologies.length > techlimit && ( + + +{availableTechnologies.length - techlimit} + + )} + + )} + + + )} + - {isDetailed && ( - - - + + +
-
- - Updated At -
- - {' '} - {new Date(pattern.updated_at.toString().slice(0, 10)).toLocaleDateString( - 'en-US', - { - day: 'numeric', - month: 'long', - year: 'numeric' - } - )} - - + + Updated At +
+ + {' '} + {new Date(pattern.updated_at.toString().slice(0, 10)).toLocaleDateString( + 'en-US', + { + day: 'numeric', + month: 'long', + year: 'numeric' + } + )} +
-
- )} - {cardVersion && ( - - v{cardVersion} - - )} -
- )} -
-
-
+ + + )} + {cardVersion && ( + + v{cardVersion} + + )} + + )} + +
); }; From 7e0eedc1a873ba81c4cc96af46a39e5799dfa6c0 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Fri, 11 Oct 2024 18:51:48 +0530 Subject: [PATCH 019/103] feat: update border color of the search that in cloud Signed-off-by: Amit Amrutiya --- src/custom/StyledSearchBar/style.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/custom/StyledSearchBar/style.tsx b/src/custom/StyledSearchBar/style.tsx index 92ce4187b..f316bc652 100644 --- a/src/custom/StyledSearchBar/style.tsx +++ b/src/custom/StyledSearchBar/style.tsx @@ -1,18 +1,19 @@ import { styled } from '@mui/material'; import { InputAdornment, OutlinedInput } from '../../base'; -export const StyledSearchInput = styled(OutlinedInput)(({ style }) => ({ +export const StyledSearchInput = styled(OutlinedInput)(({ style, theme }) => ({ width: '100%', '@media (max-width: 590px)': { marginLeft: '0.25rem', paddingLeft: '0.25rem' }, display: 'flex', + backgroundColor: theme.palette.background.surfaces, ...style })); export const InputAdornmentEnd = styled(InputAdornment)(({ theme }) => ({ - borderLeft: `1px solid ${theme.palette.border.normal}`, + borderLeft: `1px solid ${theme.palette.background.tertiary}`, height: '30px', paddingLeft: '10px', '@media (max-width: 590px)': { From d47458f720311afaa3f16d6d823043bbe9752b8a Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 16 Oct 2024 17:56:07 +0530 Subject: [PATCH 020/103] feat: add new skeleton component Signed-off-by: Amit Amrutiya --- src/base/Skeleton/Skeleton.tsx | 7 +++++++ src/base/Skeleton/index.tsx | 5 +++++ src/base/index.tsx | 1 + 3 files changed, 13 insertions(+) create mode 100644 src/base/Skeleton/Skeleton.tsx create mode 100644 src/base/Skeleton/index.tsx diff --git a/src/base/Skeleton/Skeleton.tsx b/src/base/Skeleton/Skeleton.tsx new file mode 100644 index 000000000..da7150074 --- /dev/null +++ b/src/base/Skeleton/Skeleton.tsx @@ -0,0 +1,7 @@ +import { Skeleton as MuiSkeleton, type SkeletonProps as MuiSkeletonProps } from '@mui/material'; + +export function Skeleton(props: MuiSkeletonProps): JSX.Element { + return ; +} + +export default Skeleton; diff --git a/src/base/Skeleton/index.tsx b/src/base/Skeleton/index.tsx new file mode 100644 index 000000000..190aa18c9 --- /dev/null +++ b/src/base/Skeleton/index.tsx @@ -0,0 +1,5 @@ +import { SkeletonProps } from '@mui/material'; +import Skeleton from './Skeleton'; + +export { Skeleton }; +export type { SkeletonProps }; diff --git a/src/base/index.tsx b/src/base/index.tsx index 0f7d8850f..e2e44121f 100644 --- a/src/base/index.tsx +++ b/src/base/index.tsx @@ -55,6 +55,7 @@ export * from './Paper'; export * from './Popper'; export * from './RadioGroup'; export * from './Select'; +export * from './Skeleton'; export * from './Slide'; export * from './Stack'; export * from './Switch'; From 1920b061f6bff584acd932334bb2d331acd36087 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 16 Oct 2024 17:59:25 +0530 Subject: [PATCH 021/103] chore: update filter theme in mobile devices Signed-off-by: Amit Amrutiya --- src/custom/CatalogCard/CatalogCard.tsx | 86 +++++++++---------- .../CatalogFilterSidebar.tsx | 12 ++- src/custom/CatalogFilterSection/style.tsx | 9 +- 3 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/custom/CatalogCard/CatalogCard.tsx b/src/custom/CatalogCard/CatalogCard.tsx index 16622404a..a038e925f 100644 --- a/src/custom/CatalogCard/CatalogCard.tsx +++ b/src/custom/CatalogCard/CatalogCard.tsx @@ -33,7 +33,6 @@ type CatalogCardProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any pattern: any; patternType: string; - cardLink: string; cardHeight: string; cardWidth: string; cardStyles: React.CSSProperties; @@ -64,7 +63,6 @@ const CatalogCard: React.FC = ({ cardHeight, cardWidth, cardStyles, - cardLink, onCardClick }) => { const outerStyles = { @@ -73,49 +71,47 @@ const CatalogCard: React.FC = ({ ...cardStyles }; return ( - - - - - {patternType} - - - {pattern.name} - - - - - - - - - {pattern.download_count} - - - - {pattern.clone_count} - - - - {pattern.view_count} - - - - {pattern.deployment_count} - - - - {pattern.share_count} - - - - - + + + + {patternType} + + + {pattern.name} + + + + + + + + + {pattern.download_count} + + + + {pattern.clone_count} + + + + {pattern.view_count} + + + + {pattern.deployment_count} + + + + {pattern.share_count} + + + + ); }; diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx index d020d3412..9b9291581 100644 --- a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx @@ -4,6 +4,7 @@ import { useCallback, useState } from 'react'; import { Box, Drawer, Typography } from '../../base'; import { CloseIcon } from '../../icons'; import { darkTeal } from '../../theme'; +import { SLIGHT_BLUE } from '../../theme/colors/colors'; import { CloseBtn } from '../Modal'; import CatalogFilterSidebarState from './CatalogFilterSidebarState'; import { @@ -103,7 +104,11 @@ const CatalogFilterSidebar: React.FC = ({ > - + Filters @@ -114,7 +119,7 @@ const CatalogFilterSidebar: React.FC = ({ style={{ height: '75vh', overflowY: 'auto', - background: theme.palette.background.default + background: theme.palette.background.surfaces }} > = ({ styleProps={styleProps} /> - - {/* Use theme-aware color */} + diff --git a/src/custom/CatalogFilterSection/style.tsx b/src/custom/CatalogFilterSection/style.tsx index a7694c57f..a6c1b983d 100644 --- a/src/custom/CatalogFilterSection/style.tsx +++ b/src/custom/CatalogFilterSection/style.tsx @@ -1,5 +1,6 @@ import { styled } from '@mui/material/styles'; import { Box, Button, ListItemButton } from '../../base'; +import { SLIGHT_BLUE } from '../../theme/colors/colors'; import { StyleProps } from './CatalogFilterSidebar'; export const FiltersCardDiv = styled(Box)<{ styleProps: StyleProps }>(({ styleProps }) => ({ @@ -41,15 +42,13 @@ export const FilterButton = styled(Button)(({ theme }) => ({ } })); -export const FiltersDrawerHeader = styled(Box)(({ theme }) => ({ +export const FiltersDrawerHeader = styled(Box)(() => ({ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '0.5rem 1rem', - backgroundColor: theme.palette.border.strong, - height: '10vh', - boxShadow: '0px 4px 4px rgba(0, 179, 159, 0.4)', - marginBottom: '0.625rem' + backgroundColor: SLIGHT_BLUE, + height: '10vh' })); export const CheckBoxButton = styled(ListItemButton)(({ theme }) => ({ From afc3aa5e3f0f4c27114aff17597dfeda6c613b28 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 16 Oct 2024 18:00:54 +0530 Subject: [PATCH 022/103] feat: add deboncing on the search bar Signed-off-by: Amit Amrutiya --- .../StyledSearchBar/StyledSearchBar.tsx | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/custom/StyledSearchBar/StyledSearchBar.tsx b/src/custom/StyledSearchBar/StyledSearchBar.tsx index 2e2799bdb..f3dcce72f 100644 --- a/src/custom/StyledSearchBar/StyledSearchBar.tsx +++ b/src/custom/StyledSearchBar/StyledSearchBar.tsx @@ -1,5 +1,6 @@ import { SxProps, Theme, useTheme } from '@mui/material'; -import React from 'react'; +import { debounce } from 'lodash'; +import React, { useCallback, useState } from 'react'; import { InputAdornment } from '../../base'; import { SearchIcon } from '../../icons'; import { InputAdornmentEnd, StyledSearchInput } from './style'; @@ -36,14 +37,31 @@ function StyledSearchBar({ endAdornment }: SearchBarProps): JSX.Element { const theme = useTheme(); + const [inputValue, setInputValue] = useState(value); + + const debouncedOnChange = useCallback( + (event: React.ChangeEvent) => { + debounce(() => { + if (onChange) { + onChange(event); + } + }, 300)(); + }, + [onChange] + ); + + const handleChange = (event: React.ChangeEvent) => { + setInputValue(event.target.value); + debouncedOnChange(event); + }; return ( Date: Wed, 16 Oct 2024 18:01:10 +0530 Subject: [PATCH 023/103] feat: add new meshery filter icon Signed-off-by: Amit Amrutiya --- src/icons/MesheryFilter/MesheryFilterIcon.tsx | 32 +++++++++++++++++++ src/icons/MesheryFilter/index.tsx | 1 + src/icons/index.ts | 1 + 3 files changed, 34 insertions(+) create mode 100644 src/icons/MesheryFilter/MesheryFilterIcon.tsx create mode 100644 src/icons/MesheryFilter/index.tsx diff --git a/src/icons/MesheryFilter/MesheryFilterIcon.tsx b/src/icons/MesheryFilter/MesheryFilterIcon.tsx new file mode 100644 index 000000000..ac9ee4da4 --- /dev/null +++ b/src/icons/MesheryFilter/MesheryFilterIcon.tsx @@ -0,0 +1,32 @@ +import { FC } from 'react'; +import { DEFAULT_HEIGHT, DEFAULT_WIDTH } from '../../constants/constants'; +import { CustomIconProps } from '../types'; + +const MesheryFilterIcon: FC = ({ + width = DEFAULT_WIDTH, + height = DEFAULT_HEIGHT, + primaryFill = '#654ff0', + secondaryFill = '#ffffff', + ...props +}) => { + return ( + + + + + ); +}; + +export default MesheryFilterIcon; diff --git a/src/icons/MesheryFilter/index.tsx b/src/icons/MesheryFilter/index.tsx new file mode 100644 index 000000000..c6a3c59e4 --- /dev/null +++ b/src/icons/MesheryFilter/index.tsx @@ -0,0 +1 @@ +export { default as MesheryFilterIcon } from './MesheryFilterIcon'; diff --git a/src/icons/index.ts b/src/icons/index.ts index 6a8b44302..2a8522ad1 100644 --- a/src/icons/index.ts +++ b/src/icons/index.ts @@ -55,6 +55,7 @@ export * from './Kubernetes'; export * from './LeftAngledArrow'; export * from './LeftArrow'; export * from './Menu'; +export * from './MesheryFilter'; export * from './MesheryOperator'; export * from './Open'; export * from './PanTool'; From 7a53c92df8da8d89544d5352578619e65033719b Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 16 Oct 2024 23:25:12 +0530 Subject: [PATCH 024/103] fix: catalog dialogue font family issue Signed-off-by: Amit Amrutiya --- .../CatalogFilterSidebar.tsx | 21 +++++++++++++------ .../CatalogFilterSection/FilterSection.tsx | 8 ++++--- src/custom/CatalogFilterSection/style.tsx | 3 ++- src/custom/CustomCatalog/custom-card.tsx | 11 +--------- src/custom/CustomCatalog/style.tsx | 11 ++++++---- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx index 9b9291581..1fd35bd57 100644 --- a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx @@ -38,6 +38,7 @@ export interface CatalogFilterSidebarProps { setData: (callback: (prevFilters: FilterValues) => FilterValues) => void; lists: FilterList[]; value?: FilterValues; + styleProps?: StyleProps; } export type FilterValues = Record; @@ -45,6 +46,7 @@ export type FilterValues = Record; export interface StyleProps { backgroundColor?: string; sectionTitleBackgroundColor?: string; + fontFamily?: string; } /** @@ -57,7 +59,8 @@ export interface StyleProps { const CatalogFilterSidebar: React.FC = ({ lists, setData, - value = {} + value = {}, + styleProps }) => { const theme = useTheme(); // Get the current theme const [openDrawer, setOpenDrawer] = useState(false); @@ -70,23 +73,29 @@ const CatalogFilterSidebar: React.FC = ({ setOpenDrawer(false); }, []); - const styleProps: StyleProps = { + const defaultStyleProps: StyleProps = { backgroundColor: theme.palette.mode === 'light' ? theme.palette.background.default : theme.palette.background.secondary, sectionTitleBackgroundColor: - theme.palette.mode === 'light' ? theme.palette.background.surfaces : darkTeal.main + theme.palette.mode === 'light' ? theme.palette.background.surfaces : darkTeal.main, + fontFamily: theme.typography.fontFamily + }; + + const appliedStyleProps = { + ...defaultStyleProps, + ...styleProps }; return ( <> - + @@ -126,7 +135,7 @@ const CatalogFilterSidebar: React.FC = ({ lists={lists} onApplyFilters={setData} value={value} - styleProps={styleProps} + styleProps={appliedStyleProps} /> diff --git a/src/custom/CatalogFilterSection/FilterSection.tsx b/src/custom/CatalogFilterSection/FilterSection.tsx index 2777fa38b..0696a6ed1 100644 --- a/src/custom/CatalogFilterSection/FilterSection.tsx +++ b/src/custom/CatalogFilterSection/FilterSection.tsx @@ -55,9 +55,11 @@ const FilterSection: React.FC = ({ <> onSectionToggle(filterKey)} - style={{ backgroundColor: styleProps.sectionTitleBackgroundColor }} + style={{ + backgroundColor: styleProps.sectionTitleBackgroundColor + }} > - + {(sectionDisplayName || filterKey).toUpperCase()} {openSections[filterKey] ? : } @@ -105,7 +107,7 @@ const FilterSection: React.FC = ({ {option.Icon && } - {option.label} + {option.label} {option.totalCount !== undefined && `(${option.totalCount || 0})`} diff --git a/src/custom/CatalogFilterSection/style.tsx b/src/custom/CatalogFilterSection/style.tsx index a6c1b983d..105a244ca 100644 --- a/src/custom/CatalogFilterSection/style.tsx +++ b/src/custom/CatalogFilterSection/style.tsx @@ -15,7 +15,8 @@ export const FiltersCardDiv = styled(Box)<{ styleProps: StyleProps }>(({ stylePr backgroundColor: styleProps.backgroundColor, ['@media (max-width:900px)']: { display: 'none' - } + }, + fontFamily: styleProps.fontFamily })); export const FilterDrawerDiv = styled('div')(() => ({ diff --git a/src/custom/CustomCatalog/custom-card.tsx b/src/custom/CustomCatalog/custom-card.tsx index 1f8351924..004f5079f 100644 --- a/src/custom/CustomCatalog/custom-card.tsx +++ b/src/custom/CustomCatalog/custom-card.tsx @@ -190,16 +190,7 @@ const CustomCatalogCard: React.FC = ({ <> {patternType} - - - {pattern.name} - + {pattern.name} )} diff --git a/src/custom/CustomCatalog/style.tsx b/src/custom/CustomCatalog/style.tsx index 863caa418..7e89b1905 100644 --- a/src/custom/CustomCatalog/style.tsx +++ b/src/custom/CustomCatalog/style.tsx @@ -134,20 +134,23 @@ export const MetricsCount = styled('p')(({ theme }) => ({ color: theme.palette.text.secondary, fontWeight: '600' })); -export const DesignName = styled(Typography)(({ theme }) => ({ +export const DesignName = styled(Typography)(() => ({ fontWeight: 'bold', textTransform: 'capitalize', - color: theme.palette.text.default, + color: '#000D12', fontSize: '1.125rem', marginTop: '2rem', - padding: '0rem 1rem', // "0rem 1.5rem" + padding: '0rem 1rem', position: 'relative', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', textAlign: 'center', - width: '100%' + width: '100%', + margin: '3rem 0 1.59rem 0', + fontFamily: 'inherit' })); + export const MetricsContainerFront = styled('div')(({ isDetailed }) => ({ display: 'flex', justifyContent: 'space-around', From 6710d9bc551a56aba8737ef02a9e045362ec2055 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Thu, 17 Oct 2024 14:38:25 +0530 Subject: [PATCH 025/103] feat: add new image and catalog empty card Signed-off-by: Amit Amrutiya --- .../CustomCatalog/CatalogCardDesignLogo.tsx | 95 +++++++++++++++++++ .../{custom-card.tsx => CustomCard.tsx} | 1 + src/custom/CustomCatalog/EmptyStateCard.tsx | 16 ++++ src/custom/CustomCatalog/index.tsx | 6 +- src/custom/CustomCatalog/style.tsx | 27 ++++++ src/custom/index.tsx | 4 +- src/icons/EmptyStyle/EmptyStyleIcon.tsx | 31 ++++++ src/icons/EmptyStyle/index.tsx | 1 + 8 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 src/custom/CustomCatalog/CatalogCardDesignLogo.tsx rename src/custom/CustomCatalog/{custom-card.tsx => CustomCard.tsx} (99%) create mode 100644 src/custom/CustomCatalog/EmptyStateCard.tsx create mode 100644 src/icons/EmptyStyle/EmptyStyleIcon.tsx create mode 100644 src/icons/EmptyStyle/index.tsx diff --git a/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx b/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx new file mode 100644 index 000000000..3fb392471 --- /dev/null +++ b/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx @@ -0,0 +1,95 @@ +import React, { useState } from 'react'; +import { Dialog } from '../../base'; +import { DesignIcon, MesheryFilterIcon } from '../../icons'; + +interface CatalogCardDesignLogoProps { + zoomEffect?: boolean; + imgURL?: string[]; + type: { type: string }; + width: string; + height: string; + style?: React.CSSProperties; +} + +const CatalogCardDesignLogo: React.FC = ({ + zoomEffect = false, + imgURL, + type, + width, + height, + style = {} +}) => { + const [imgError, setImgError] = useState(false); + const [isZoomed, setIsZoomed] = useState(false); + + const handleZoomClick = () => { + if (zoomEffect) { + setIsZoomed(true); + } + }; + + const handleZoomClose = () => { + setIsZoomed(false); + }; + + const SvgComponent: React.FC<{ type: { type: string } }> = ({ type }) => { + return type.type === 'filter' ? ( + + ) : ( + + ); + }; + + return ( + <> + {imgURL && imgURL.length > 0 ? ( +
+ {!imgError ? ( + <> + Design SnapShot setImgError(true)} + style={{ + cursor: 'pointer', + width: '100%', + height: '100%', + objectFit: 'cover' + }} + /> + + Zoomed Design SnapShot + + + ) : ( + + )} +
+ ) : ( + + )} + + ); +}; + +export default CatalogCardDesignLogo; diff --git a/src/custom/CustomCatalog/custom-card.tsx b/src/custom/CustomCatalog/CustomCard.tsx similarity index 99% rename from src/custom/CustomCatalog/custom-card.tsx rename to src/custom/CustomCatalog/CustomCard.tsx index 004f5079f..bce7b078c 100644 --- a/src/custom/CustomCatalog/custom-card.tsx +++ b/src/custom/CustomCatalog/CustomCard.tsx @@ -160,6 +160,7 @@ const CustomCatalogCard: React.FC = ({ setAvailableTechnologies(validSvgPaths); }; + useEffect(() => { handleImage(); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/custom/CustomCatalog/EmptyStateCard.tsx b/src/custom/CustomCatalog/EmptyStateCard.tsx new file mode 100644 index 000000000..756392f5f --- /dev/null +++ b/src/custom/CustomCatalog/EmptyStateCard.tsx @@ -0,0 +1,16 @@ +import { useTheme } from '@mui/material'; +import { FC } from 'react'; +import { EmptyStyleIcon } from '../../icons/EmptyStyle'; +import { CatalogEmptyStateDiv } from './style'; + +const EmptyStateCard: FC = () => { + const theme = useTheme(); + return ( + + +

No match found

+
+ ); +}; + +export default EmptyStateCard; diff --git a/src/custom/CustomCatalog/index.tsx b/src/custom/CustomCatalog/index.tsx index 09adbc5cc..be7c47128 100644 --- a/src/custom/CustomCatalog/index.tsx +++ b/src/custom/CustomCatalog/index.tsx @@ -1,3 +1,5 @@ -import CustomCatalogCard from './custom-card'; +import CatalogCardDesignLogo from './CatalogCardDesignLogo'; +import CustomCatalogCard from './CustomCard'; +import EmptyStateCard from './EmptyStateCard'; -export { CustomCatalogCard }; +export { CatalogCardDesignLogo, CustomCatalogCard, EmptyStateCard }; diff --git a/src/custom/CustomCatalog/style.tsx b/src/custom/CustomCatalog/style.tsx index 7e89b1905..3be4029d3 100644 --- a/src/custom/CustomCatalog/style.tsx +++ b/src/custom/CustomCatalog/style.tsx @@ -398,3 +398,30 @@ export const DesignAuthorName = styled('div')(() => ({ height: 'max-content' } })); + +export const CatalogEmptyStateDiv = styled('div')(({ theme }) => ({ + backgroundColor: theme.palette.common.white, + textAlign: 'center', + borderRadius: '1rem', + width: '15rem', + height: '18rem', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + [theme.breakpoints.down('lg')]: { + height: '18.75rem' + } +})); + +export const EmptyStateDiv = styled('div')(({ theme }) => ({ + backgroundColor: theme.palette.common.white, + textAlign: 'center', + borderRadius: '1rem', + width: '100%', + padding: '1.5rem', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center' +})); diff --git a/src/custom/index.tsx b/src/custom/index.tsx index 9a9ddd655..dca38c0a4 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -3,7 +3,7 @@ import { BookmarkNotification } from './BookmarkNotification'; import CatalogFilter, { CatalogFilterProps } from './CatalogFilter/CatalogFilter'; import { ChapterCard } from './ChapterCard'; import { ConnectionChip } from './ConnectionChip'; -import { CustomCatalogCard } from './CustomCatalog'; +import { CatalogCardDesignLogo, CustomCatalogCard, EmptyStateCard } from './CustomCatalog'; import { CustomColumn, CustomColumnVisibilityControl, @@ -58,6 +58,7 @@ export { Terminal } from './Terminal'; export { ActionButton, BookmarkNotification, + CatalogCardDesignLogo, CatalogFilter, ChapterCard, ConnectionChip, @@ -68,6 +69,7 @@ export { CustomTooltip, DataTableEllipsisMenu, EmptyState, + EmptyStateCard, ErrorBoundary, Fallback, FeedbackButton, diff --git a/src/icons/EmptyStyle/EmptyStyleIcon.tsx b/src/icons/EmptyStyle/EmptyStyleIcon.tsx new file mode 100644 index 000000000..dcd90aae1 --- /dev/null +++ b/src/icons/EmptyStyle/EmptyStyleIcon.tsx @@ -0,0 +1,31 @@ +import { CSSProperties, FC } from 'react'; + +interface EmptyStyleIconProps { + width?: string; + height?: string; + fill?: string; + style?: CSSProperties; + onClick?: () => void; +} + +const EmptyStyleIcon: FC = ({ + width = '24px', + height = '24px', + fill, + style = {}, + onClick = () => {} +}) => ( + + + +); + +export default EmptyStyleIcon; diff --git a/src/icons/EmptyStyle/index.tsx b/src/icons/EmptyStyle/index.tsx new file mode 100644 index 000000000..97ba77dd5 --- /dev/null +++ b/src/icons/EmptyStyle/index.tsx @@ -0,0 +1 @@ +export { default as EmptyStyleIcon } from './EmptyStyleIcon'; From fea30c19b470aa45ccf6db533aa885cba2d1a9ed Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Thu, 17 Oct 2024 18:18:52 +0530 Subject: [PATCH 026/103] fix(markdown): notifications Signed-off-by: Sudhanshu Dasgupta --- src/custom/Markdown/index.tsx | 25 +++++++++++++++++++++++++ src/custom/Markdown/style.tsx | 9 +++++++++ src/custom/index.tsx | 4 ++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/custom/Markdown/index.tsx b/src/custom/Markdown/index.tsx index 92cbb5fd2..cc0c8ee9b 100644 --- a/src/custom/Markdown/index.tsx +++ b/src/custom/Markdown/index.tsx @@ -2,6 +2,7 @@ import ReactMarkdown from 'react-markdown'; import rehypeRaw from 'rehype-raw'; import remarkGfm from 'remark-gfm'; import { + BasicAnchorMarkdown, StyledMarkdown, StyledMarkdownBlockquote, StyledMarkdownH1, @@ -97,3 +98,27 @@ export const RenderMarkdownTooltip: React.FC = ({ content } ); }; + +// Markdown support for notifications markdown content +export const BasicMarkdown: React.FC = ({ content }) => { + return ( + ( + { + window.open(props.href, '_blank'); + e.stopPropagation(); + }} + as="a" + > + {props.children} + + ) + }} + > + {content} + + ); +}; diff --git a/src/custom/Markdown/style.tsx b/src/custom/Markdown/style.tsx index aab1940ce..9c54d8e1d 100644 --- a/src/custom/Markdown/style.tsx +++ b/src/custom/Markdown/style.tsx @@ -10,6 +10,15 @@ export const StyledMarkdown = styled('a')(({ theme }) => ({ cursor: 'pointer' })); +// anchor style for notifications markdown content +export const BasicAnchorMarkdown = styled('a')(() => ({ + textDecoration: 'none', + '&:hover': { + textDecoration: 'underline' + }, + cursor: 'pointer' +})); + export const StyledMarkdownP = styled('p')(({ theme }) => ({ color: theme.palette.text.default, marginBlock: '0px', diff --git a/src/custom/index.tsx b/src/custom/index.tsx index 9a9ddd655..1fc4eea32 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -31,7 +31,7 @@ import { useWindowDimensions } from './Helpers/Dimension'; import { useNotificationHandler } from './Helpers/Notification'; import { ColView, updateVisibleColumns } from './Helpers/ResponsiveColumns/responsive-coulmns.tsx'; import { LearningCard } from './LearningCard'; -import { RenderMarkdown } from './Markdown'; +import { BasicMarkdown, RenderMarkdown } from './Markdown'; import { ModalCard } from './ModalCard'; import PopperListener, { IPopperListener } from './PopperListener'; import PromptComponent from './Prompt'; @@ -108,7 +108,7 @@ export { // Markdown export { StyledMarkdown } from './Markdown/style'; -export { RenderMarkdown }; +export { BasicMarkdown, RenderMarkdown }; // Stepper export { CustomizedStepper, useStepper } from './Stepper'; From ff936b4b0949eec4fa0c0b3edc419e094ba5020e Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Thu, 17 Oct 2024 18:59:34 +0530 Subject: [PATCH 027/103] feat: make sistent card dark mode compitable Signed-off-by: Amit Amrutiya --- src/custom/CustomCatalog/CustomCard.tsx | 44 +++---- src/custom/CustomCatalog/EmptyStateCard.tsx | 4 +- src/custom/CustomCatalog/style.tsx | 120 ++++++++++-------- .../ContentClassIcons/CommunityClassIcon.tsx | 16 +-- 4 files changed, 96 insertions(+), 88 deletions(-) diff --git a/src/custom/CustomCatalog/CustomCard.tsx b/src/custom/CustomCatalog/CustomCard.tsx index bce7b078c..1dd995c06 100644 --- a/src/custom/CustomCatalog/CustomCard.tsx +++ b/src/custom/CustomCatalog/CustomCard.tsx @@ -1,11 +1,13 @@ import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; -import { Avatar, styled } from '@mui/material'; +import { Avatar, styled, useTheme } from '@mui/material'; import React, { useEffect, useState } from 'react'; import { Grid } from '../../base'; import { CloneIcon, CommunityClassIcon, OfficialClassIcon, OpenIcon, ShareIcon } from '../../icons'; import VerificationClassIcon from '../../icons/ContentClassIcons/VerificationClassIcon'; import DeploymentsIcon from '../../icons/Deployments/DeploymentsIcon'; import { DownloadIcon } from '../../icons/Download'; +import { DARK_TEAL } from '../../theme'; +import { SNOW_WHITE } from '../../theme/colors/colors'; import { CustomTooltip } from '../CustomTooltip'; import { CardBack, @@ -123,6 +125,7 @@ const CustomCatalogCard: React.FC = ({ width: cardWidth, ...cardStyles }; + const theme = useTheme(); const technologies = pattern.catalog_data?.compatibility || []; // an array const techlimit = 5; @@ -197,7 +200,8 @@ const CustomCatalogCard: React.FC = ({
= ({ {isDetailed && ( - - - {pattern.download_count} - - - - {pattern.clone_count} - - - - {pattern.view_count} - - - - {pattern.deployment_count} - - - - {pattern.share_count} - + {[ + { Icon: DownloadIcon, count: pattern.download_count }, + { Icon: CloneIcon, count: pattern.clone_count }, + { Icon: OpenIcon, count: pattern.view_count }, + { Icon: DeploymentsIcon, count: pattern.deployment_count }, + { Icon: ShareIcon, count: pattern.share_count } + ].map(({ Icon, count }, index) => ( + + + {count} + + ))} )} diff --git a/src/custom/CustomCatalog/EmptyStateCard.tsx b/src/custom/CustomCatalog/EmptyStateCard.tsx index 756392f5f..21d746a5f 100644 --- a/src/custom/CustomCatalog/EmptyStateCard.tsx +++ b/src/custom/CustomCatalog/EmptyStateCard.tsx @@ -7,8 +7,8 @@ const EmptyStateCard: FC = () => { const theme = useTheme(); return ( - -

No match found

+ +

No match found

); }; diff --git a/src/custom/CustomCatalog/style.tsx b/src/custom/CustomCatalog/style.tsx index 3be4029d3..a49cbebb2 100644 --- a/src/custom/CustomCatalog/style.tsx +++ b/src/custom/CustomCatalog/style.tsx @@ -1,4 +1,6 @@ import { styled, Typography } from '@mui/material'; +import { accentGrey, DARK_PRIMARY_COLOR, GRAY97, slateGray, WHITESMOKE } from '../../theme'; +import { charcoal, DARK_TEAL, SNOW_WHITE } from '../../theme/colors/colors'; type DesignCardProps = { outerStyles: React.CSSProperties; @@ -45,12 +47,13 @@ export const NoTechnologyText = styled('div')(() => ({ })); export const StyledInnerClassWrapper = styled('div')(({ - catalogClassName + catalogClassName, + theme }) => { const mapToColor: Record = { - community: 'rgba(122,132,142,.8)', - official: '#EBC017', - verified: '#00B39F' + community: slateGray.main, + official: theme.palette.background.cta?.default || '#EBC017', + verified: theme.palette.background.brand?.default || '#00B39F' }; return { font: 'bold 10px sans-serif', @@ -67,7 +70,7 @@ export const StyledInnerClassWrapper = styled('div') ({ fontSize: '0.875rem', textTransform: 'capitalize', background: theme.palette.background.brand?.default, - color: theme.palette.text.inverse, + color: theme.palette.background.constant?.white, borderRadius: '0 1rem 0 2rem' })); export const MetricsCount = styled('p')(({ theme }) => ({ @@ -131,13 +134,13 @@ export const MetricsCount = styled('p')(({ theme }) => ({ margin: '0rem', lineHeight: '1.5', textAlign: 'center', - color: theme.palette.text.secondary, + color: theme.palette.mode === 'light' ? DARK_TEAL : SNOW_WHITE, fontWeight: '600' })); -export const DesignName = styled(Typography)(() => ({ +export const DesignName = styled(Typography)(({ theme }) => ({ fontWeight: 'bold', textTransform: 'capitalize', - color: '#000D12', + color: theme.palette.text.default, fontSize: '1.125rem', marginTop: '2rem', padding: '0rem 1rem', @@ -151,15 +154,13 @@ export const DesignName = styled(Typography)(() => ({ fontFamily: 'inherit' })); -export const MetricsContainerFront = styled('div')(({ isDetailed }) => ({ +export const MetricsContainerFront = styled('div')(({ isDetailed, theme }) => ({ display: 'flex', justifyContent: 'space-around', - // borderTop: "0.851px solid #C9DBE3", fontSize: '0.2rem', - color: 'rgba(26, 26, 26, .8)', - // margin: "-0.8rem 0.7rem 0", + color: theme.palette.mode === 'light' ? 'rgba(26, 26, 26, .8)' : theme.palette.text.default, padding: '0.9rem 0.1rem', - background: '#E7EFF3', + background: theme.palette.mode === 'light' ? '#E7EFF3' : DARK_TEAL, ...(isDetailed && { position: 'absolute', bottom: '0px' @@ -194,7 +195,7 @@ export const DesignDetailsDiv = styled('div')(() => ({ })); export const ImageWrapper = styled('div')(({ theme }) => ({ - background: theme.palette.mode === 'light' ? 'rgba(231, 239, 243, 0.40)' : '#212121', + background: theme.palette.background.surfaces, display: 'flex', alignItems: 'center', justifyContent: 'center', @@ -347,22 +348,34 @@ export const CardBack = styled('div')(({ isCatalog }) => ({ }) })); -export const CardFront = styled('div')(({ shouldFlip, isDetailed, theme }) => ({ - ...(shouldFlip && { - position: 'absolute', - boxShadow: `2px 2px 3px 0px ${theme.palette.background.brand?.default}`, - background: `linear-gradient(to left bottom, #EBEFF1, #f4f5f7, #f7f7f9, white, white, white, white, white, white, #f7f7f9, #f4f5f7, #EBEFF1);` - }), - ...(isDetailed && { - boxShadow: `2px 2px 3px 0px ${theme.palette.background.brand?.default}`, - background: `linear-gradient(to left bottom, #EBEFF1, #f4f5f7, #f7f7f9, white, white, white, white, white, white, #f7f7f9, #f4f5f7, #EBEFF1);` - }), - width: '100%', - height: '100%', - WebkitBackfaceVisibility: 'hidden', - borderRadius: '0.9375rem', - backfaceVisibility: 'hidden' -})); +const getBackground = (isLightMode: boolean) => { + const lightGradient = `linear-gradient(to left bottom, ${WHITESMOKE}, ${GRAY97},white, white, white, white, white, white, white,white, $, ${WHITESMOKE}, ${GRAY97})`; + const darkGradient = `linear-gradient(to right top, ${DARK_PRIMARY_COLOR}, ${accentGrey[30]}, ${accentGrey[20]}, ${accentGrey[10]}, ${accentGrey[10]}, ${accentGrey[10]}, ${accentGrey[10]}, ${accentGrey[10]}, ${accentGrey[10]}, ${charcoal[20]}, ${charcoal[10]}, black)`; + + return isLightMode ? lightGradient : darkGradient; +}; +export const CardFront = styled('div')(({ shouldFlip, isDetailed, theme }) => { + const isLightMode = theme.palette.mode === 'light'; + const background = getBackground(isLightMode); + const boxShadow = `2px 2px 3px 0px ${theme.palette.background.brand?.default}`; + + return { + ...(shouldFlip && { + position: 'absolute', + boxShadow, + background + }), + ...(isDetailed && { + boxShadow, + background + }), + width: '100%', + height: '100%', + WebkitBackfaceVisibility: 'hidden', + borderRadius: '0.9375rem', + backfaceVisibility: 'hidden' + }; +}); export const DateText = styled('div')(() => ({ fontSize: '0.875rem', @@ -399,29 +412,24 @@ export const DesignAuthorName = styled('div')(() => ({ } })); -export const CatalogEmptyStateDiv = styled('div')(({ theme }) => ({ - backgroundColor: theme.palette.common.white, - textAlign: 'center', - borderRadius: '1rem', - width: '15rem', - height: '18rem', - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - [theme.breakpoints.down('lg')]: { - height: '18.75rem' - } -})); +export const CatalogEmptyStateDiv = styled('div')(({ theme }) => { + const isLightMode = theme.palette.mode === 'light'; + const background = getBackground(isLightMode); + const boxShadow = `2px 2px 3px 0px ${theme.palette.background.brand?.default}`; -export const EmptyStateDiv = styled('div')(({ theme }) => ({ - backgroundColor: theme.palette.common.white, - textAlign: 'center', - borderRadius: '1rem', - width: '100%', - padding: '1.5rem', - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center' -})); + return { + background: background, + boxShadow: boxShadow, + textAlign: 'center', + borderRadius: '1rem', + width: '15rem', + height: '18rem', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + [theme.breakpoints.down('lg')]: { + height: '18.75rem' + } + }; +}); diff --git a/src/icons/ContentClassIcons/CommunityClassIcon.tsx b/src/icons/ContentClassIcons/CommunityClassIcon.tsx index ad000fc1e..393c609bd 100644 --- a/src/icons/ContentClassIcons/CommunityClassIcon.tsx +++ b/src/icons/ContentClassIcons/CommunityClassIcon.tsx @@ -3,8 +3,8 @@ import { CustomIconProps } from '../types'; export const CommunityClassIcon: FC = ({ width = '16', height = '13', - secondaryFill = '#293B43', - primaryFill = '#647176', + fill = '#293B43', + secondaryFill = '#647176', style = {} }) => ( = ({ > ); From f5be8f842e94e5a42cffa2dc3f75ba465e28a934 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Fri, 18 Oct 2024 10:14:19 +0530 Subject: [PATCH 028/103] feat: add getversion and js-yaml library Signed-off-by: Amit Amrutiya --- package-lock.json | 7 +-- package.json | 1 + src/custom/CustomCatalog/CustomCard.tsx | 63 ++++++----------------- src/custom/CustomCatalog/Helper.ts | 68 +++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 53 deletions(-) create mode 100644 src/custom/CustomCatalog/Helper.ts diff --git a/package-lock.json b/package-lock.json index c491f76b2..bc6df6462 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "@layer5/sistent", "version": "0.14.11", "dependencies": { + "js-yaml": "^4.1.0", "lodash": "^4.17.21" }, "devDependencies": { @@ -3707,7 +3708,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/aria-query": { @@ -8782,7 +8782,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -16792,8 +16791,7 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "aria-query": { "version": "5.1.3", @@ -20310,7 +20308,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "requires": { "argparse": "^2.0.1" } diff --git a/package.json b/package.json index 5d21feaac..7361e195f 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,7 @@ "access": "public" }, "dependencies": { + "js-yaml": "^4.1.0", "lodash": "^4.17.21" } } diff --git a/src/custom/CustomCatalog/CustomCard.tsx b/src/custom/CustomCatalog/CustomCard.tsx index 1dd995c06..92517aa77 100644 --- a/src/custom/CustomCatalog/CustomCard.tsx +++ b/src/custom/CustomCatalog/CustomCard.tsx @@ -1,14 +1,15 @@ import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; -import { Avatar, styled, useTheme } from '@mui/material'; +import { Avatar, styled } from '@mui/material'; import React, { useEffect, useState } from 'react'; import { Grid } from '../../base'; import { CloneIcon, CommunityClassIcon, OfficialClassIcon, OpenIcon, ShareIcon } from '../../icons'; import VerificationClassIcon from '../../icons/ContentClassIcons/VerificationClassIcon'; import DeploymentsIcon from '../../icons/Deployments/DeploymentsIcon'; import { DownloadIcon } from '../../icons/Download'; -import { DARK_TEAL } from '../../theme'; +import { DARK_TEAL, useTheme } from '../../theme'; import { SNOW_WHITE } from '../../theme/colors/colors'; import { CustomTooltip } from '../CustomTooltip'; +import { getVersion, handleImage } from './Helper'; import { CardBack, CardFront, @@ -37,7 +38,10 @@ export const DesignCardUrl = styled('a')(() => ({ textDecoration: 'none' })); -interface Pattern { +export interface Pattern { + id: string; + user_id: string; + pattern_file: string; name: string; download_count: number; clone_count: number; @@ -53,8 +57,10 @@ interface Pattern { }; catalog_data?: { content_class?: string; - imageURL?: string; + imageURL?: string[]; compatibility?: string[]; + published_version?: string; + type?: string; }; visibility: string; updated_at: Date; @@ -63,21 +69,15 @@ interface Pattern { type CatalogCardProps = { pattern: Pattern; patternType: string; - cardLink: string; cardHeight: string; cardWidth: string; cardStyles: React.CSSProperties; - version?: string; avatarUrl: string; shouldFlip?: boolean; cardTechnologies?: boolean; isDetailed?: boolean; - cardAvatarUrl?: boolean; - date?: boolean; - cardVersion?: boolean; UserName?: string; children?: React.ReactNode; // catalogImage - TechnologyComponent?: React.ReactNode; basePath?: string; // path of meshmodel img stored subBasePath?: string; // path of meshmodel img stored getHostUrl?: () => string; @@ -111,7 +111,6 @@ const CustomCatalogCard: React.FC = ({ shouldFlip, isDetailed, cardTechnologies, - cardVersion, avatarUrl, UserName, children, @@ -127,45 +126,13 @@ const CustomCatalogCard: React.FC = ({ }; const theme = useTheme(); - const technologies = pattern.catalog_data?.compatibility || []; // an array + const technologies = pattern.catalog_data?.compatibility || []; const techlimit = 5; const [availableTechnologies, setAvailableTechnologies] = useState([]); - const checkImageUrlValidity = async (url: string, appendHostUrl = true) => { - return new Promise((resolve) => { - const img = new Image(); - // Only append host if the URL does not start with "http" or "https" - if (appendHostUrl && !url.startsWith('http')) { - img.src = (getHostUrl ? getHostUrl() : '') + url; - } else { - img.src = url; - } - img.onload = () => { - // Check if the image loaded successfully - resolve(true); - }; - - img.onerror = () => { - // Handle the case where the image could not be loaded - resolve(false); - }; - }); - }; - - const handleImage = async () => { - const validSvgPaths = []; - for (const technology of technologies) { - const svgIconPath = `${basePath}/${technology.toLowerCase()}/${subBasePath}/${technology.toLowerCase()}-color.svg`; - const isSvgPathValid = await checkImageUrlValidity(svgIconPath as string); - if (isSvgPathValid) { - validSvgPaths.push(technology); - } - } - - setAvailableTechnologies(validSvgPaths); - }; + const version = getVersion(pattern); useEffect(() => { - handleImage(); + handleImage(technologies, basePath, subBasePath, setAvailableTechnologies); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -336,9 +303,9 @@ const CustomCatalogCard: React.FC = ({ )} - {cardVersion && ( + {version && ( - v{cardVersion} + v{version} )} diff --git a/src/custom/CustomCatalog/Helper.ts b/src/custom/CustomCatalog/Helper.ts new file mode 100644 index 000000000..10bbc4e31 --- /dev/null +++ b/src/custom/CustomCatalog/Helper.ts @@ -0,0 +1,68 @@ +import jsyaml from 'js-yaml'; +import { Pattern } from './CustomCard'; + +const checkImageUrlValidity = async ( + url: string, + appendHostUrl = true, + getHostUrl?: () => string +): Promise => { + return new Promise((resolve) => { + const img = new Image(); + // Only append host if the URL does not start with "http" or "https" + if (appendHostUrl && !url.startsWith('http')) { + img.src = (getHostUrl ? getHostUrl() : '') + url; + } else { + img.src = url; + } + img.onload = () => { + // Check if the image loaded successfully + resolve(true); + }; + + img.onerror = () => { + // Handle the case where the image could not be loaded + resolve(false); + }; + }); +}; + +const getValidSvgPaths = async ( + technologies: string[], + basePath: string, + subBasePath: string +): Promise => { + const validSvgPaths: string[] = []; + for (const technology of technologies) { + const svgIconPath = `${basePath}/${technology.toLowerCase()}/${subBasePath}/${technology.toLowerCase()}-color.svg`; + const isSvgPathValid = await checkImageUrlValidity(svgIconPath as string); + if (isSvgPathValid) { + validSvgPaths.push(technology); + } + } + return validSvgPaths; +}; + +export const handleImage = async ( + technologies: string[], + basePath: string = '', + subBasePath: string = '', + setAvailableTechnologies: (technologies: string[]) => void +) => { + const validSvgPaths = await getValidSvgPaths(technologies, basePath, subBasePath); + setAvailableTechnologies(validSvgPaths); +}; + +export const DEFAULT_DESIGN_VERSION = '0.0.0'; + +export const getVersion = (design: Pattern) => { + if (design.visibility === 'published') { + return design?.catalog_data?.published_version || DEFAULT_DESIGN_VERSION; + } + try { + const patternFile = jsyaml.load(design.pattern_file); + return patternFile?.version || DEFAULT_DESIGN_VERSION; + } catch (e) { + console.error(e); + return DEFAULT_DESIGN_VERSION; + } +}; From 4bc1b009e0e47d52557341872c1efdad30ddb7fb Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Fri, 18 Oct 2024 10:14:51 +0530 Subject: [PATCH 029/103] chore: fix the useTheme name import from mui to sistent path Signed-off-by: Amit Amrutiya --- src/custom/CustomCatalog/EmptyStateCard.tsx | 2 +- .../CustomColumnVisibilityControl.tsx | 2 +- src/custom/Prompt/promt-component.tsx | 2 +- src/custom/SearchBar.tsx | 3 ++- src/custom/Stepper/index.tsx | 3 ++- src/custom/StyledSearchBar/StyledSearchBar.tsx | 3 ++- src/custom/UniversalFilter.tsx | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/custom/CustomCatalog/EmptyStateCard.tsx b/src/custom/CustomCatalog/EmptyStateCard.tsx index 21d746a5f..014b0a551 100644 --- a/src/custom/CustomCatalog/EmptyStateCard.tsx +++ b/src/custom/CustomCatalog/EmptyStateCard.tsx @@ -1,6 +1,6 @@ -import { useTheme } from '@mui/material'; import { FC } from 'react'; import { EmptyStyleIcon } from '../../icons/EmptyStyle'; +import { useTheme } from '../../theme'; import { CatalogEmptyStateDiv } from './style'; const EmptyStateCard: FC = () => { diff --git a/src/custom/CustomColumnVisibilityControl/CustomColumnVisibilityControl.tsx b/src/custom/CustomColumnVisibilityControl/CustomColumnVisibilityControl.tsx index faf616459..36bfc06b2 100644 --- a/src/custom/CustomColumnVisibilityControl/CustomColumnVisibilityControl.tsx +++ b/src/custom/CustomColumnVisibilityControl/CustomColumnVisibilityControl.tsx @@ -1,4 +1,3 @@ -import { useTheme } from '@mui/material'; import React from 'react'; import { Box } from '../../base/Box'; import { Card } from '../../base/Card'; @@ -6,6 +5,7 @@ import { Checkbox } from '../../base/Checkbox'; import { ClickAwayListener } from '../../base/ClickAwayListener'; import { FormControlLabel } from '../../base/FormControlLabel'; import { ColumnIcon } from '../../icons'; +import { useTheme } from '../../theme'; import PopperListener from '../PopperListener'; import TooltipIcon from '../TooltipIcon'; diff --git a/src/custom/Prompt/promt-component.tsx b/src/custom/Prompt/promt-component.tsx index 871303671..9d1cba780 100644 --- a/src/custom/Prompt/promt-component.tsx +++ b/src/custom/Prompt/promt-component.tsx @@ -1,6 +1,6 @@ -import { useTheme } from '@mui/material'; import { forwardRef, useImperativeHandle, useRef, useState } from 'react'; import { Typography } from '../../base'; +import { useTheme } from '../../theme'; import { Modal, ModalBody, ModalButtonPrimary, ModalButtonSecondary, ModalFooter } from '../Modal'; import { ActionComponent, Subtitle } from './style'; diff --git a/src/custom/SearchBar.tsx b/src/custom/SearchBar.tsx index db72eaf44..8b7f27344 100644 --- a/src/custom/SearchBar.tsx +++ b/src/custom/SearchBar.tsx @@ -1,11 +1,12 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { outlinedInputClasses } from '@mui/material/OutlinedInput'; -import { Theme, ThemeProvider, createTheme, useTheme } from '@mui/material/styles'; +import { Theme, ThemeProvider, createTheme } from '@mui/material/styles'; import debounce from 'lodash/debounce'; import React, { useCallback } from 'react'; import { ClickAwayListener } from '../base/ClickAwayListener'; import { TextField } from '../base/TextField'; import { CloseIcon, SearchIcon } from '../icons'; +import { useTheme } from '../theme'; import TooltipIcon from './TooltipIcon'; const customTheme = (theme: Theme) => diff --git a/src/custom/Stepper/index.tsx b/src/custom/Stepper/index.tsx index e993341db..5fd4107f5 100644 --- a/src/custom/Stepper/index.tsx +++ b/src/custom/Stepper/index.tsx @@ -1,9 +1,10 @@ -import { Box, Stack, Step, StepConnector, StepLabel, Stepper, useTheme } from '@mui/material'; +import { Box, Stack, Step, StepConnector, StepLabel, Stepper } from '@mui/material'; import { stepConnectorClasses } from '@mui/material/StepConnector'; import { StepIconProps } from '@mui/material/StepIcon'; import { styled } from '@mui/system'; import React, { useMemo, useState } from 'react'; import { IconProps } from '../../icons/types'; +import { useTheme } from '../../theme'; interface ColorlibStepIconPropsI extends StepIconProps { icons: React.ComponentType[]; diff --git a/src/custom/StyledSearchBar/StyledSearchBar.tsx b/src/custom/StyledSearchBar/StyledSearchBar.tsx index f3dcce72f..165f72c2d 100644 --- a/src/custom/StyledSearchBar/StyledSearchBar.tsx +++ b/src/custom/StyledSearchBar/StyledSearchBar.tsx @@ -1,8 +1,9 @@ -import { SxProps, Theme, useTheme } from '@mui/material'; +import { SxProps, Theme } from '@mui/material'; import { debounce } from 'lodash'; import React, { useCallback, useState } from 'react'; import { InputAdornment } from '../../base'; import { SearchIcon } from '../../icons'; +import { useTheme } from '../../theme'; import { InputAdornmentEnd, StyledSearchInput } from './style'; interface SearchBarProps { diff --git a/src/custom/UniversalFilter.tsx b/src/custom/UniversalFilter.tsx index 1df8dbabd..02a8213fd 100644 --- a/src/custom/UniversalFilter.tsx +++ b/src/custom/UniversalFilter.tsx @@ -1,4 +1,3 @@ -import { useTheme } from '@mui/material'; import { SelectChangeEvent } from '@mui/material/Select'; import React from 'react'; import { Button } from '../base/Button'; @@ -8,6 +7,7 @@ import { MenuItem } from '../base/MenuItem'; import { Paper } from '../base/Paper'; import { Select } from '../base/Select'; import { FilterIcon } from '../icons'; +import { useTheme } from '../theme'; import PopperListener from './PopperListener'; import TooltipIcon from './TooltipIcon'; From 1a572138d09d981e6d3800f6da2e5021cb76b7e1 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Fri, 18 Oct 2024 13:57:20 +0530 Subject: [PATCH 030/103] fix: debouncing Signed-off-by: Amit Amrutiya --- .../StyledSearchBar/StyledSearchBar.tsx | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/custom/StyledSearchBar/StyledSearchBar.tsx b/src/custom/StyledSearchBar/StyledSearchBar.tsx index 165f72c2d..da529de62 100644 --- a/src/custom/StyledSearchBar/StyledSearchBar.tsx +++ b/src/custom/StyledSearchBar/StyledSearchBar.tsx @@ -1,6 +1,6 @@ import { SxProps, Theme } from '@mui/material'; import { debounce } from 'lodash'; -import React, { useCallback, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { InputAdornment } from '../../base'; import { SearchIcon } from '../../icons'; import { useTheme } from '../../theme'; @@ -14,6 +14,7 @@ interface SearchBarProps { placeholder?: string; sx?: SxProps; endAdornment?: React.ReactNode; + debounceTime?: number; } /** @@ -26,6 +27,7 @@ interface SearchBarProps { * @param {string} [props.placeholder] - The placeholder text for the search input. * @param {Object} [props.sx] - The style object for the search input. * @param {React.ReactNode} [props.endAdornment] - The element to display at the end of the search input. + * @param {number} [props.debounceTime] - The debounce time for the input change handler. * * @returns {JSX.Element} The rendered StyledSearchBar component. */ @@ -35,25 +37,40 @@ function StyledSearchBar({ label, sx, placeholder, - endAdornment + endAdornment, + debounceTime = 300 }: SearchBarProps): JSX.Element { const theme = useTheme(); - const [inputValue, setInputValue] = useState(value); + const [inputValue, setInputValue] = useState(value ?? ''); - const debouncedOnChange = useCallback( - (event: React.ChangeEvent) => { - debounce(() => { - if (onChange) { - onChange(event); - } - }, 300)(); - }, - [onChange] - ); + useEffect(() => { + if (value !== undefined && value !== inputValue) { + setInputValue(value); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [value]); + + useEffect(() => { + const handler = debounce((newValue: string) => { + if (onChange) { + const syntheticEvent = { + target: { value: newValue }, + persist: () => {} + } as React.ChangeEvent; + + onChange(syntheticEvent); + } + }, debounceTime); + + handler(inputValue); + + return () => { + handler.cancel(); + }; + }, [inputValue, onChange, debounceTime]); const handleChange = (event: React.ChangeEvent) => { setInputValue(event.target.value); - debouncedOnChange(event); }; return ( From 31ef2a5b16013f7f7c1474fdc9f6591754af484c Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Fri, 18 Oct 2024 18:03:31 +0530 Subject: [PATCH 031/103] feat: Refactor import paths in EmptyStateCard and style.tsx Signed-off-by: Amit Amrutiya --- src/custom/CustomCatalog/EmptyStateCard.tsx | 2 +- src/custom/CustomCatalog/style.tsx | 2 +- src/icons/index.ts | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/custom/CustomCatalog/EmptyStateCard.tsx b/src/custom/CustomCatalog/EmptyStateCard.tsx index 014b0a551..256b193d3 100644 --- a/src/custom/CustomCatalog/EmptyStateCard.tsx +++ b/src/custom/CustomCatalog/EmptyStateCard.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { EmptyStyleIcon } from '../../icons/EmptyStyle'; +import { EmptyStyleIcon } from '../../icons'; import { useTheme } from '../../theme'; import { CatalogEmptyStateDiv } from './style'; diff --git a/src/custom/CustomCatalog/style.tsx b/src/custom/CustomCatalog/style.tsx index a49cbebb2..38fb80054 100644 --- a/src/custom/CustomCatalog/style.tsx +++ b/src/custom/CustomCatalog/style.tsx @@ -349,7 +349,7 @@ export const CardBack = styled('div')(({ isCatalog }) => ({ })); const getBackground = (isLightMode: boolean) => { - const lightGradient = `linear-gradient(to left bottom, ${WHITESMOKE}, ${GRAY97},white, white, white, white, white, white, white,white, $, ${WHITESMOKE}, ${GRAY97})`; + const lightGradient = `linear-gradient(to left bottom, ${WHITESMOKE}, ${GRAY97},white, white, white, white, white, white, white, white, ${WHITESMOKE}, ${GRAY97})`; const darkGradient = `linear-gradient(to right top, ${DARK_PRIMARY_COLOR}, ${accentGrey[30]}, ${accentGrey[20]}, ${accentGrey[10]}, ${accentGrey[10]}, ${accentGrey[10]}, ${accentGrey[10]}, ${accentGrey[10]}, ${accentGrey[10]}, ${charcoal[20]}, ${charcoal[10]}, black)`; return isLightMode ? lightGradient : darkGradient; diff --git a/src/icons/index.ts b/src/icons/index.ts index 2a8522ad1..24daa8d79 100644 --- a/src/icons/index.ts +++ b/src/icons/index.ts @@ -45,6 +45,7 @@ export * from './Design'; export * from './Done'; export * from './Download'; export * from './Edit'; +export * from './EmptyStyle'; export * from './Environment'; export * from './ExternalLink'; export * from './Feedback'; From bc56366295de2d4c2d7611328b35e23ee3bd1e8d Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 20 Oct 2024 13:13:23 +0530 Subject: [PATCH 032/103] fix: debouncing not working on empty string Signed-off-by: Amit Amrutiya --- src/custom/CatalogFilterSection/index.tsx | 3 +- .../StyledSearchBar/StyledSearchBar.tsx | 49 ++++++++++++------- src/custom/index.tsx | 1 + 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/custom/CatalogFilterSection/index.tsx b/src/custom/CatalogFilterSection/index.tsx index bab5baf47..a79660b97 100644 --- a/src/custom/CatalogFilterSection/index.tsx +++ b/src/custom/CatalogFilterSection/index.tsx @@ -1,3 +1,4 @@ -import CatalogFilterSidebar from './CatalogFilterSidebar'; +import CatalogFilterSidebar, { FilterList } from './CatalogFilterSidebar'; export { CatalogFilterSidebar }; +export type { FilterList }; diff --git a/src/custom/StyledSearchBar/StyledSearchBar.tsx b/src/custom/StyledSearchBar/StyledSearchBar.tsx index da529de62..b8a3fe643 100644 --- a/src/custom/StyledSearchBar/StyledSearchBar.tsx +++ b/src/custom/StyledSearchBar/StyledSearchBar.tsx @@ -1,6 +1,6 @@ import { SxProps, Theme } from '@mui/material'; import { debounce } from 'lodash'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { InputAdornment } from '../../base'; import { SearchIcon } from '../../icons'; import { useTheme } from '../../theme'; @@ -33,7 +33,7 @@ interface SearchBarProps { */ function StyledSearchBar({ onChange, - value, + value = '', label, sx, placeholder, @@ -41,36 +41,47 @@ function StyledSearchBar({ debounceTime = 300 }: SearchBarProps): JSX.Element { const theme = useTheme(); - const [inputValue, setInputValue] = useState(value ?? ''); + const [inputValue, setInputValue] = useState(value); + // Update local state when controlled value changes useEffect(() => { - if (value !== undefined && value !== inputValue) { + if (value !== inputValue) { setInputValue(value); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [value]); - useEffect(() => { - const handler = debounce((newValue: string) => { - if (onChange) { - const syntheticEvent = { - target: { value: newValue }, - persist: () => {} - } as React.ChangeEvent; + // Create synthetic event helper + const createSyntheticEvent = (value: string): React.ChangeEvent => + ({ + target: { value }, + persist: () => {} + }) as React.ChangeEvent; - onChange(syntheticEvent); - } - }, debounceTime); + // Memoize the debounced handler + const debouncedOnChange = useMemo( + () => + debounce((newValue: string) => { + onChange?.(createSyntheticEvent(newValue)); + }, debounceTime), + [onChange, debounceTime] + ); - handler(inputValue); + useEffect(() => { + if (!onChange) return; + if (inputValue === '') { + onChange(createSyntheticEvent(inputValue)); + } else { + debouncedOnChange(inputValue); + } return () => { - handler.cancel(); + debouncedOnChange.cancel(); }; - }, [inputValue, onChange, debounceTime]); + }, [inputValue, onChange, debouncedOnChange]); const handleChange = (event: React.ChangeEvent) => { - setInputValue(event.target.value); + const newValue = event.target.value; + setInputValue(newValue); }; return ( diff --git a/src/custom/index.tsx b/src/custom/index.tsx index ca9ba32b9..a7505ea50 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -45,6 +45,7 @@ import { TransferListProps } from './TransferModal/TransferList/TransferList'; import UniversalFilter, { UniversalFilterProps } from './UniversalFilter'; export { CatalogCard } from './CatalogCard'; export { CatalogFilterSidebar } from './CatalogFilterSection'; +export type { FilterList } from './CatalogFilterSection'; export { StyledChartDialog } from './ChartDialog'; export { LearningContent } from './LearningContent'; export { NavigationNavbar } from './NavigationNavbar'; From 2f3626d53348b10e5363c738f5e685af6e055fb3 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 20 Oct 2024 13:19:12 +0530 Subject: [PATCH 033/103] feat: add new expand and collapse all icons Signed-off-by: Amit Amrutiya --- src/icons/CollapseAll/CollapseAllIcon.tsx | 44 +++++++++++++++++++++++ src/icons/CollapseAll/index.tsx | 1 + src/icons/ExpandAll/ExpandAllIcon.tsx | 44 +++++++++++++++++++++++ src/icons/ExpandAll/index.tsx | 1 + src/icons/index.ts | 2 ++ 5 files changed, 92 insertions(+) create mode 100644 src/icons/CollapseAll/CollapseAllIcon.tsx create mode 100644 src/icons/CollapseAll/index.tsx create mode 100644 src/icons/ExpandAll/ExpandAllIcon.tsx create mode 100644 src/icons/ExpandAll/index.tsx diff --git a/src/icons/CollapseAll/CollapseAllIcon.tsx b/src/icons/CollapseAll/CollapseAllIcon.tsx new file mode 100644 index 000000000..66afdc313 --- /dev/null +++ b/src/icons/CollapseAll/CollapseAllIcon.tsx @@ -0,0 +1,44 @@ +import React from 'react'; + +interface CollapsAllIconProps { + height?: string; + width?: string; + fill?: string; + strokeWidth?: string; + style?: React.CSSProperties; +} + +const CollapsAllIcon: React.FC = ({ + height = '24', + width = '24', + fill = 'none', + strokeWidth = '2', + style +}) => ( + + + + +); + +export default CollapsAllIcon; diff --git a/src/icons/CollapseAll/index.tsx b/src/icons/CollapseAll/index.tsx new file mode 100644 index 000000000..23bdaea21 --- /dev/null +++ b/src/icons/CollapseAll/index.tsx @@ -0,0 +1 @@ +export { default as CollapseAll } from './CollapseAllIcon'; diff --git a/src/icons/ExpandAll/ExpandAllIcon.tsx b/src/icons/ExpandAll/ExpandAllIcon.tsx new file mode 100644 index 000000000..a74a4703a --- /dev/null +++ b/src/icons/ExpandAll/ExpandAllIcon.tsx @@ -0,0 +1,44 @@ +import React from 'react'; + +interface ExpandAllProps { + height?: string; + width?: string; + fill?: string; + strokeWidth?: string; + style?: React.CSSProperties; +} + +const ExpandAll: React.FC = ({ + height = '24', + width = '24', + fill = 'none', + strokeWidth = '2', + style +}) => ( + + + + +); + +export default ExpandAll; diff --git a/src/icons/ExpandAll/index.tsx b/src/icons/ExpandAll/index.tsx new file mode 100644 index 000000000..3e4fc19d9 --- /dev/null +++ b/src/icons/ExpandAll/index.tsx @@ -0,0 +1 @@ +export { default as ExpandAll } from './ExpandAllIcon'; diff --git a/src/icons/index.ts b/src/icons/index.ts index 24daa8d79..c7bf87e66 100644 --- a/src/icons/index.ts +++ b/src/icons/index.ts @@ -9,6 +9,7 @@ export * from './Circle'; export * from './Clone'; export * from './Close'; export * from './Cloud'; +export * from './CollapseAll'; export * from './Column'; export * from './Component'; export * from './Configuration'; @@ -25,6 +26,7 @@ export * from './Designer'; export * from './Detail'; export * from './DropDownIcon'; export * from './Error'; +export * from './ExpandAll'; export * from './Favorite'; export * from './Filter'; export * from './Fullscreen'; From dc6add6c539cf5362365c77902a3f49ce9fcf2ef Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 20 Oct 2024 19:26:48 +0530 Subject: [PATCH 034/103] chore: change icon name Signed-off-by: Amit Amrutiya --- src/icons/CollapseAll/index.tsx | 2 +- src/icons/ExpandAll/ExpandAllIcon.tsx | 6 +++--- src/icons/ExpandAll/index.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/icons/CollapseAll/index.tsx b/src/icons/CollapseAll/index.tsx index 23bdaea21..dd1fa97d4 100644 --- a/src/icons/CollapseAll/index.tsx +++ b/src/icons/CollapseAll/index.tsx @@ -1 +1 @@ -export { default as CollapseAll } from './CollapseAllIcon'; +export { default as CollapseAllIcon } from './CollapseAllIcon'; diff --git a/src/icons/ExpandAll/ExpandAllIcon.tsx b/src/icons/ExpandAll/ExpandAllIcon.tsx index a74a4703a..d9e790048 100644 --- a/src/icons/ExpandAll/ExpandAllIcon.tsx +++ b/src/icons/ExpandAll/ExpandAllIcon.tsx @@ -1,6 +1,6 @@ import React from 'react'; -interface ExpandAllProps { +interface ExpandAllIconProps { height?: string; width?: string; fill?: string; @@ -8,7 +8,7 @@ interface ExpandAllProps { style?: React.CSSProperties; } -const ExpandAll: React.FC = ({ +const ExpandAllIcon: React.FC = ({ height = '24', width = '24', fill = 'none', @@ -41,4 +41,4 @@ const ExpandAll: React.FC = ({ ); -export default ExpandAll; +export default ExpandAllIcon; diff --git a/src/icons/ExpandAll/index.tsx b/src/icons/ExpandAll/index.tsx index 3e4fc19d9..0f9a8c8f9 100644 --- a/src/icons/ExpandAll/index.tsx +++ b/src/icons/ExpandAll/index.tsx @@ -1 +1 @@ -export { default as ExpandAll } from './ExpandAllIcon'; +export { default as ExpandAllIcon } from './ExpandAllIcon'; From 1149a324332805023acd957212f721bec1df543a Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sat, 19 Oct 2024 19:28:31 +0530 Subject: [PATCH 035/103] fix: lint failed issue Signed-off-by: Amit Amrutiya --- src/custom/StyledSearchBar/StyledSearchBar.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/custom/StyledSearchBar/StyledSearchBar.tsx b/src/custom/StyledSearchBar/StyledSearchBar.tsx index b8a3fe643..b608789c7 100644 --- a/src/custom/StyledSearchBar/StyledSearchBar.tsx +++ b/src/custom/StyledSearchBar/StyledSearchBar.tsx @@ -48,6 +48,7 @@ function StyledSearchBar({ if (value !== inputValue) { setInputValue(value); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [value]); // Create synthetic event helper From acdc57396db0487d5670ca1a8571fdfc93c2456b Mon Sep 17 00:00:00 2001 From: jerensl <54782057+jerensl@users.noreply.github.com> Date: Mon, 21 Oct 2024 19:18:56 +0800 Subject: [PATCH 036/103] ci: auto bump version for meshery, extensions and cloud Signed-off-by: jerensl <54782057+jerensl@users.noreply.github.com> --- .github/workflows/bump-meshery-version.yml | 127 +++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 .github/workflows/bump-meshery-version.yml diff --git a/.github/workflows/bump-meshery-version.yml b/.github/workflows/bump-meshery-version.yml new file mode 100644 index 000000000..9f7feb221 --- /dev/null +++ b/.github/workflows/bump-meshery-version.yml @@ -0,0 +1,127 @@ +name: Bump Meshery, Meshery Extensions and Meshery Cloud + +on: + release: + types: [published] + +jobs: + bump-meshery: + runs-on: ubuntu-latest + steps: + - name: Checkout Meshery code + uses: actions/checkout@v4 + with: + repository: meshery/meshery + fetch-depth: 1 + token: ${{ secrets.RELEASEDRAFTER_PAT }} + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: "npm" + cache-dependency-path: '**/package-lock.json' + - name: Make changes to pull request + working-directory: ui + run: npm install @layer5/sistent@latest + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.RELEASEDRAFTER_PAT }} + commit-message: Bump sistent ${{ github.event.release.tag_name }} dependencies + committer: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + author: "l5io" + signoff: true + branch: bump-sistent-bot + delete-branch: true + title: '[Chore]: Bump ${{ github.event.release.name }}' + add-paths: | + ui/package.json + ui/package-lock.json + body: | + Update sistent ${{ github.event.release.tag_name }} + - Updated with *today's* date + - Auto-generated by [l5io][1] + + [1]: https://github.com/l5io + assignees: l5io + draft: false + bump-meshery-extensions: + runs-on: ubuntu-latest + steps: + - name: Checkout Meshery Extensions code + uses: actions/checkout@v4 + with: + repository: layer5labs/meshery-extensions + fetch-depth: 1 + token: ${{ secrets.RELEASEDRAFTER_PAT }} + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: "npm" + cache-dependency-path: '**/package-lock.json' + - name: Make changes to pull request + working-directory: meshmap + run: npm install @layer5/sistent@latest + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.RELEASEDRAFTER_PAT }} + commit-message: Bump sistent ${{ github.event.release.tag_name }} dependencies + committer: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + author: "l5io" + signoff: true + branch: bump-sistent-bot + delete-branch: true + title: '[Chore]: Bump ${{ github.event.release.name }}' + add-paths: | + meshmap/package.json + meshmap/package-lock.json + body: | + Update sistent ${{ github.event.release.tag_name }} + - Updated with *today's* date + - Auto-generated by [l5io][1] + + [1]: https://github.com/l5io + assignees: l5io + draft: false + bump-meshery-cloud: + runs-on: ubuntu-latest + steps: + - name: Checkout Meshery Extensions code + uses: actions/checkout@v4 + with: + repository: layer5io/meshery-cloud + fetch-depth: 1 + token: ${{ secrets.RELEASEDRAFTER_PAT }} + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: "npm" + cache-dependency-path: '**/package-lock.json' + - name: Make changes to pull request + working-directory: ui + run: npm install @layer5/sistent@latest + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.RELEASEDRAFTER_PAT }} + commit-message: Bump sistent ${{ github.event.release.tag_name }} dependencies + committer: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + author: "l5io" + signoff: true + branch: bump-sistent-bot + delete-branch: true + title: '[Chore]: Bump ${{ github.event.release.name }}' + add-paths: | + ui/package.json + ui/package-lock.json + body: | + Update sistent ${{ github.event.release.tag_name }} + - Updated with *today's* date + - Auto-generated by [l5io][1] + + [1]: https://github.com/l5io + assignees: l5io + draft: false \ No newline at end of file From a99f4e2db53168ce77a2e0fb7ef370b1d4c815d8 Mon Sep 17 00:00:00 2001 From: Jerens Lensun <54782057+jerensl@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:45:35 +0800 Subject: [PATCH 037/103] Update .github/workflows/bump-meshery-version.yml Co-authored-by: Lee Calcote Signed-off-by: Jerens Lensun <54782057+jerensl@users.noreply.github.com> --- .github/workflows/bump-meshery-version.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/bump-meshery-version.yml b/.github/workflows/bump-meshery-version.yml index 9f7feb221..8699d7b45 100644 --- a/.github/workflows/bump-meshery-version.yml +++ b/.github/workflows/bump-meshery-version.yml @@ -118,10 +118,8 @@ jobs: ui/package.json ui/package-lock.json body: | - Update sistent ${{ github.event.release.tag_name }} - - Updated with *today's* date - - Auto-generated by [l5io][1] - - [1]: https://github.com/l5io + Update to Sistent ${{ github.event.release.tag_name }} + + _This pull request has been auto-generated by [l5io](http://github.com/l5io)_ assignees: l5io draft: false \ No newline at end of file From 9311d0416d68ad007f38bb3ee1bd4807fc4058a7 Mon Sep 17 00:00:00 2001 From: jerensl <54782057+jerensl@users.noreply.github.com> Date: Tue, 22 Oct 2024 13:50:30 +0800 Subject: [PATCH 038/103] ci: apply the comment body to all repo Signed-off-by: jerensl <54782057+jerensl@users.noreply.github.com> --- .github/workflows/bump-meshery-version.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/bump-meshery-version.yml b/.github/workflows/bump-meshery-version.yml index 8699d7b45..99e5c52dd 100644 --- a/.github/workflows/bump-meshery-version.yml +++ b/.github/workflows/bump-meshery-version.yml @@ -38,11 +38,9 @@ jobs: ui/package.json ui/package-lock.json body: | - Update sistent ${{ github.event.release.tag_name }} - - Updated with *today's* date - - Auto-generated by [l5io][1] - - [1]: https://github.com/l5io + Update to Sistent ${{ github.event.release.tag_name }} + + _This pull request has been auto-generated by [l5io](http://github.com/l5io)_ assignees: l5io draft: false bump-meshery-extensions: @@ -78,11 +76,9 @@ jobs: meshmap/package.json meshmap/package-lock.json body: | - Update sistent ${{ github.event.release.tag_name }} - - Updated with *today's* date - - Auto-generated by [l5io][1] - - [1]: https://github.com/l5io + Update to Sistent ${{ github.event.release.tag_name }} + + _This pull request has been auto-generated by [l5io](http://github.com/l5io)_ assignees: l5io draft: false bump-meshery-cloud: From bc878c85ae53e5c2b8a29bd77f28a68384f9682b Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 23 Oct 2024 15:09:32 +0530 Subject: [PATCH 039/103] feat: make navigation navbar more generic to use Signed-off-by: Amit Amrutiya --- .../NavigationNavbar/navigationNavbar.tsx | 98 ++++++++++--------- src/custom/NavigationNavbar/style.tsx | 7 +- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/src/custom/NavigationNavbar/navigationNavbar.tsx b/src/custom/NavigationNavbar/navigationNavbar.tsx index 6d5f83df5..2ae99e7f1 100644 --- a/src/custom/NavigationNavbar/navigationNavbar.tsx +++ b/src/custom/NavigationNavbar/navigationNavbar.tsx @@ -1,5 +1,6 @@ import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import { ListItemTextProps, MenuListProps } from '@mui/material'; import React, { MouseEvent, useState } from 'react'; import { Collapse, Divider, ListItemText, MenuItem } from '../../base'; import { IconWrapper, MenuItemList, MenuItemSubList, MenuListStyle, SubIconWrapper } from './style'; @@ -14,13 +15,18 @@ type NavigationItem = { addDivider?: boolean; }; -type NavigationNavbarProps = { +interface NavigationNavbarProps { navigationItems: NavigationItem[]; -}; + MenuListProps?: Omit; + ListItemTextProps?: Omit; +} -const NavigationNavbar: React.FC = ({ navigationItems }) => { +const NavigationNavbar: React.FC = ({ + navigationItems, + MenuListProps = {}, + ListItemTextProps = {} +}) => { const [openSectionId, setOpenSectionId] = useState(null); - const toggleSectionOpen = (sectionId: string, event: MouseEvent) => { event.stopPropagation(); setOpenSectionId((currentOpenSectionId) => @@ -28,50 +34,52 @@ const NavigationNavbar: React.FC = ({ navigationItems }) ); }; - const NavigationNavbarItems = () => { - return navigationItems.map((item) => { - const isOpen = openSectionId === item.id; - const permission = item.permission ?? true; - const addDivider = item.addDivider ?? false; + return ( + + {navigationItems.map((item) => { + const isOpen = openSectionId === item.id; + const permission = item.permission ?? true; + const addDivider = item.addDivider ?? false; - return ( - - - - {item.icon} - - + return ( + + + + {item.icon && {item.icon}} + + + {item.subItems && ( + + {isOpen ? ( + toggleSectionOpen(item.id, e)} /> + ) : ( + toggleSectionOpen(item.id, e)} /> + )} + + )} + {item.subItems && ( - - {isOpen ? ( - toggleSectionOpen(item.id, e)} /> - ) : ( - toggleSectionOpen(item.id, e)} /> - )} - + + {item.subItems.map((subItem) => ( + + + {subItem.icon && {subItem.icon}} + + + + ))} + )} - - - {item.subItems && ( - - {item.subItems.map((subItem) => ( - - - {subItem.icon} - - - - ))} - - )} - - {addDivider && } - - ); - }); - }; - - return {NavigationNavbarItems()}; + {addDivider && } + + ); + })} + + ); }; export default NavigationNavbar; diff --git a/src/custom/NavigationNavbar/style.tsx b/src/custom/NavigationNavbar/style.tsx index d6cd54f1e..c7f0f6998 100644 --- a/src/custom/NavigationNavbar/style.tsx +++ b/src/custom/NavigationNavbar/style.tsx @@ -7,8 +7,6 @@ export const ListItemStyle = styled('div')(({ theme }) => ({ })); export const MenuListStyle = styled(MenuList)({ - minHeight: '31rem', - width: '13rem', overflowY: 'auto', scrollbarWidth: 'none', '&::-webkit-scrollbar': { @@ -18,7 +16,7 @@ export const MenuListStyle = styled(MenuList)({ export const MenuItemList = styled(ListItem)(() => ({ pointerEvents: 'auto', - margin: '0.5rem 0rem 0.5rem 0.5rem', + margin: '0.5rem 0rem 0.5rem 0rem', fontSize: '0.1rem', padding: '0' })); @@ -30,7 +28,8 @@ export const MenuItemSubList = styled(ListItem)(() => ({ })); export const IconWrapper = styled('div')({ - marginRight: '0.75rem' + marginRight: '0.75rem', + marginLeft: '0.5rem' }); export const SubIconWrapper = styled('div')({ From 061ed513dbf8e7d7aca56f9c92e5b700c514fb95 Mon Sep 17 00:00:00 2001 From: NISHANT SINGH <151461374+NishantSinghhhhh@users.noreply.github.com> Date: Wed, 23 Oct 2024 22:45:00 +0530 Subject: [PATCH 040/103] Changed the Add icon code that was present in MenuIcon.tsx with MenuIcon Signed-off-by: NISHANT SINGH <151461374+NishantSinghhhhh@users.noreply.github.com> --- src/icons/Menu/MenuIcon.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/icons/Menu/MenuIcon.tsx b/src/icons/Menu/MenuIcon.tsx index 5a1fcc2e7..101ab13f8 100644 --- a/src/icons/Menu/MenuIcon.tsx +++ b/src/icons/Menu/MenuIcon.tsx @@ -1,7 +1,7 @@ import { DEFAULT_FILL_NONE, DEFAULT_HEIGHT, DEFAULT_WIDTH } from '../../constants/constants'; import { IconProps } from '../types'; -export const AddIcon = ({ +export const MenuIcon = ({ width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT, fill = DEFAULT_FILL_NONE, @@ -13,7 +13,7 @@ export const AddIcon = ({ height={height} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" - data-testid="add-icon-svg" + data-testid="menu-icon-svg" {...props} > @@ -21,4 +21,4 @@ export const AddIcon = ({ ); }; -export default AddIcon; +export default MenuIcon; From d32eaaf7fd6a7ba0ed3b752cd82f55e7f540b051 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Thu, 24 Oct 2024 18:54:20 +0530 Subject: [PATCH 041/103] chore: styling of search and filter for make consistent with the cloud Signed-off-by: Amit Amrutiya --- src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx | 5 ++++- src/custom/CatalogFilterSection/style.tsx | 2 +- src/custom/StyledSearchBar/style.tsx | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx index 1fd35bd57..965af08b6 100644 --- a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx @@ -100,7 +100,10 @@ const CatalogFilterSidebar: React.FC = ({ - + Filters diff --git a/src/custom/CatalogFilterSection/style.tsx b/src/custom/CatalogFilterSection/style.tsx index 105a244ca..32e74de60 100644 --- a/src/custom/CatalogFilterSection/style.tsx +++ b/src/custom/CatalogFilterSection/style.tsx @@ -37,7 +37,7 @@ export const FilterButton = styled(Button)(({ theme }) => ({ '&:hover': { backgroundColor: theme.palette.background.default }, - height: '3.5rem', + height: '3.75rem', ['@media (max-width:450px)']: { minWidth: '0px' } diff --git a/src/custom/StyledSearchBar/style.tsx b/src/custom/StyledSearchBar/style.tsx index f316bc652..9f7026721 100644 --- a/src/custom/StyledSearchBar/style.tsx +++ b/src/custom/StyledSearchBar/style.tsx @@ -8,7 +8,8 @@ export const StyledSearchInput = styled(OutlinedInput)(({ style, theme }) => ({ paddingLeft: '0.25rem' }, display: 'flex', - backgroundColor: theme.palette.background.surfaces, + backgroundColor: + theme.palette.mode === 'light' ? theme.palette.common.white : theme.palette.background.surfaces, ...style })); From 0227adaeaf2bd41211203b71621a0e85755d3042 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Fri, 25 Oct 2024 11:59:41 +0530 Subject: [PATCH 042/103] feat: add component in the filter sidbar state Signed-off-by: Amit Amrutiya --- .../CatalogFilterSidebar.tsx | 14 +- .../CatalogFilterSidebarState.tsx | 47 ++++--- .../CatalogFilterSection/FilterSection.tsx | 120 ++++++++++-------- src/custom/CatalogFilterSection/index.tsx | 4 +- src/custom/index.tsx | 2 +- 5 files changed, 112 insertions(+), 75 deletions(-) diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx index 965af08b6..c3e36e9ce 100644 --- a/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebar.tsx @@ -29,14 +29,24 @@ export interface FilterOption { export interface FilterList { filterKey: string; sectionDisplayName?: string; - options: FilterOption[]; defaultOpen?: boolean; isMultiSelect?: boolean; + options?: FilterOption[]; + customComponent?: React.ComponentType; } +type FilterListWithOptions = FilterList & { options: FilterOption[]; customComponent?: never }; + +type FilterListWithCustomComponent = FilterList & { + customComponent: React.ComponentType; + options?: never; +}; + +export type FilterListType = FilterListWithOptions | FilterListWithCustomComponent; + export interface CatalogFilterSidebarProps { setData: (callback: (prevFilters: FilterValues) => FilterValues) => void; - lists: FilterList[]; + lists: FilterListType[]; value?: FilterValues; styleProps?: StyleProps; } diff --git a/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx b/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx index 76b0d72d3..1d2bb51ba 100644 --- a/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx +++ b/src/custom/CatalogFilterSection/CatalogFilterSidebarState.tsx @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react'; import { CatalogFilterSidebarProps, - FilterList, + FilterListType, FilterValues, StyleProps } from './CatalogFilterSidebar'; @@ -16,7 +16,7 @@ import FilterSection from './FilterSection'; * @param {Object} styleProps - The style properties for the component. */ const CatalogFilterSidebarState: React.FC<{ - lists: FilterList[]; + lists: FilterListType[]; onApplyFilters: CatalogFilterSidebarProps['setData']; value: FilterValues; styleProps: StyleProps; @@ -78,19 +78,36 @@ const CatalogFilterSidebarState: React.FC<{ return ( <> - {lists.map((list) => ( - - ))} + {lists.map((list) => { + if (list.customComponent) { + return ( + + ); + } + + return ( + + ); + })} ); }; diff --git a/src/custom/CatalogFilterSection/FilterSection.tsx b/src/custom/CatalogFilterSection/FilterSection.tsx index 0696a6ed1..4be5eddbd 100644 --- a/src/custom/CatalogFilterSection/FilterSection.tsx +++ b/src/custom/CatalogFilterSection/FilterSection.tsx @@ -10,12 +10,13 @@ import { EndAdornmentText, FilterTitleButton } from './style'; interface FilterSectionProps { filterKey: string; sectionDisplayName?: string; - options: FilterOption[]; + options?: FilterOption[]; filters: FilterValues; openSections: Record; - onCheckboxChange: (filterKey: string, value: string, checked: boolean) => void; + onCheckboxChange?: (filterKey: string, value: string, checked: boolean) => void; onSectionToggle: (filterKey: string) => void; styleProps: StyleProps; + customComponent?: React.ComponentType; } /** @@ -33,12 +34,13 @@ interface FilterSectionProps { const FilterSection: React.FC = ({ filterKey, sectionDisplayName, - options, + options = [], filters, openSections, onCheckboxChange, onSectionToggle, - styleProps + styleProps, + customComponent: CustomComponent }) => { const [searchQuery, setSearchQuery] = useState(''); @@ -47,9 +49,10 @@ const FilterSection: React.FC = ({ }, []); const showSearch = options.length > 10; - const searchedOptions = searchQuery - ? options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())) - : options; + const searchedOptions = + searchQuery && options.length + ? options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())) + : options; return ( <> @@ -65,59 +68,66 @@ const FilterSection: React.FC = ({ {openSections[filterKey] ? : } - - {showSearch && ( - - Total : {searchedOptions.length ?? 0} - } - /> - - )} - {searchedOptions.map((option, index) => ( - - - + ) : ( + + {showSearch && ( + + Total : {searchedOptions.length ?? 0} } - onChange={(e) => onCheckboxChange(filterKey, option.value, e.target.checked)} - value={option.value} /> + + )} + {searchedOptions.map((option, index) => ( + + + + onCheckboxChange && + onCheckboxChange(filterKey, option.value, e.target.checked) + } + value={option.value} + /> - {option.Icon && } + {option.Icon && } - {option.label} + {option.label} + + + {option.totalCount !== undefined && `(${option.totalCount || 0})`} + {option.description && ( + + )} + - - {option.totalCount !== undefined && `(${option.totalCount || 0})`} - {option.description && ( - - )} - - - ))} - + ))} + + )} ); diff --git a/src/custom/CatalogFilterSection/index.tsx b/src/custom/CatalogFilterSection/index.tsx index a79660b97..5fb7338c4 100644 --- a/src/custom/CatalogFilterSection/index.tsx +++ b/src/custom/CatalogFilterSection/index.tsx @@ -1,4 +1,4 @@ -import CatalogFilterSidebar, { FilterList } from './CatalogFilterSidebar'; +import CatalogFilterSidebar, { FilterListType } from './CatalogFilterSidebar'; export { CatalogFilterSidebar }; -export type { FilterList }; +export type { FilterListType }; diff --git a/src/custom/index.tsx b/src/custom/index.tsx index a7505ea50..ae5e6f82e 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -45,7 +45,7 @@ import { TransferListProps } from './TransferModal/TransferList/TransferList'; import UniversalFilter, { UniversalFilterProps } from './UniversalFilter'; export { CatalogCard } from './CatalogCard'; export { CatalogFilterSidebar } from './CatalogFilterSection'; -export type { FilterList } from './CatalogFilterSection'; +export type { FilterListType } from './CatalogFilterSection'; export { StyledChartDialog } from './ChartDialog'; export { LearningContent } from './LearningContent'; export { NavigationNavbar } from './NavigationNavbar'; From 0479be5f2159779178811fa38255903a598f3820 Mon Sep 17 00:00:00 2001 From: jerensl <54782057+jerensl@users.noreply.github.com> Date: Fri, 25 Oct 2024 06:59:20 +0000 Subject: [PATCH 043/103] Bump xstate v5.18.2 dependencies Signed-off-by: l5io --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc6df6462..bee091161 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,7 +59,7 @@ "mui-datatables": "*", "react": ">=17", "react-dom": ">=17", - "xstate": "^5.13.0" + "xstate": "^5.18.2" }, "peerDependenciesMeta": { "@emotion/react": { @@ -14149,9 +14149,9 @@ "dev": true }, "node_modules/xstate": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/xstate/-/xstate-5.13.0.tgz", - "integrity": "sha512-Z0om784N5u8sAzUvQJBa32jiTCIGGF/2ZsmKkerQEqeeUktAeOMK20FIHFUMywC4GcAkNksSvaeX7lwoRNXPEQ==", + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-5.18.2.tgz", + "integrity": "sha512-hab5VOe29D0agy8/7dH1lGw+7kilRQyXwpaChoMu4fe6rDP+nsHYhDYKfS2O4iXE7myA98TW6qMEudj/8NXEkA==", "peer": true, "funding": { "type": "opencollective", @@ -23942,9 +23942,9 @@ "dev": true }, "xstate": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/xstate/-/xstate-5.13.0.tgz", - "integrity": "sha512-Z0om784N5u8sAzUvQJBa32jiTCIGGF/2ZsmKkerQEqeeUktAeOMK20FIHFUMywC4GcAkNksSvaeX7lwoRNXPEQ==", + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-5.18.2.tgz", + "integrity": "sha512-hab5VOe29D0agy8/7dH1lGw+7kilRQyXwpaChoMu4fe6rDP+nsHYhDYKfS2O4iXE7myA98TW6qMEudj/8NXEkA==", "peer": true }, "y18n": { diff --git a/package.json b/package.json index 7361e195f..55ac382ab 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "mui-datatables": "*", "react": ">=17", "react-dom": ">=17", - "xstate": "^5.13.0" + "xstate": "^5.18.2" }, "peerDependenciesMeta": { "lodash": { From 530a9946b4e932fc0afc9c0f3b402b4a9805b8ef Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Fri, 25 Oct 2024 13:35:29 +0530 Subject: [PATCH 044/103] chore: update catalog icon Signed-off-by: Amit Amrutiya --- src/icons/CatalogIcon/CatalogIcon.tsx | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/icons/CatalogIcon/CatalogIcon.tsx b/src/icons/CatalogIcon/CatalogIcon.tsx index 6129d27a2..12771597e 100644 --- a/src/icons/CatalogIcon/CatalogIcon.tsx +++ b/src/icons/CatalogIcon/CatalogIcon.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { DEFAULT_HEIGHT, DEFAULT_WIDTH } from '../../constants/constants'; -import { CARIBBEAN_GREEN, DARK_SLATE_GRAY, KEPPEL, WHITE, useTheme } from '../../theme'; +import { CARIBBEAN_GREEN, DARK_SLATE_GRAY, KEPPEL, useTheme } from '../../theme'; import { IconProps } from '../types'; type CatalogIconProps = { @@ -14,13 +14,11 @@ export const CatalogIcon: FC = ({ height = DEFAULT_HEIGHT, primaryFill, secondaryFill, - tertiaryFill = WHITE, style = {}, ...props }) => { const theme = useTheme(); const themeMode = theme?.palette?.mode ?? 'light'; - const themePrimaryFill = primaryFill ?? (themeMode === 'dark' ? KEPPEL : DARK_SLATE_GRAY); const themeSecondaryFill = secondaryFill ?? (themeMode === 'dark' ? CARIBBEAN_GREEN : KEPPEL); @@ -34,29 +32,24 @@ export const CatalogIcon: FC = ({ {...props} > + - ); From 272e369c4486e537e5b556e323963d4972c11a87 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sat, 26 Oct 2024 10:35:34 +0530 Subject: [PATCH 045/103] chore: update the gradient for the modal header diff for the dark and light mode Signed-off-by: Amit Amrutiya --- src/custom/Modal/index.tsx | 14 ++++++++++---- src/theme/colors/colors.ts | 10 ++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/custom/Modal/index.tsx b/src/custom/Modal/index.tsx index 5bcfc3276..f551c8d5d 100644 --- a/src/custom/Modal/index.tsx +++ b/src/custom/Modal/index.tsx @@ -4,6 +4,7 @@ import { Box, Dialog, IconButton, Paper, Typography } from '../../base'; import { ContainedButton, OutlinedButton, TextButton } from '../../base/Button/Button'; import { iconLarge, iconMedium } from '../../constants/iconsSizes'; import { CloseIcon, InfoCircleIcon } from '../../icons'; +import { darkModalGradient, lightModalGradient } from '../../theme/colors/colors'; import { CustomTooltip } from '../CustomTooltip'; interface ModalProps extends DialogProps { @@ -54,8 +55,8 @@ const StyledDialog = styled(Dialog)` } `; -export const ModalStyledHeader = styled('div')(() => ({ - background: 'linear-gradient(90deg, #3B687B 0%, #507D90 100%)', +export const ModalStyledHeader = styled('div')(({ theme }) => ({ + background: theme.palette.mode === 'light' ? lightModalGradient.header : darkModalGradient.header, color: '#eee', display: 'flex', justifyContent: 'space-between', @@ -108,7 +109,11 @@ const StyledFooter = styled('div', { shouldForwardProp: (prop) => prop !== 'variant' })(({ theme, variant, hasHelpText }) => ({ background: - variant == 'filled' ? 'linear-gradient(90deg, #3B687B 0%, #507D90 100%)' : 'transparent', + variant === 'filled' + ? theme.palette.mode === 'light' + ? lightModalGradient.fotter + : darkModalGradient.fotter + : 'transparent', display: 'flex', alignItems: 'center', justifyContent: hasHelpText ? 'space-between' : 'end', @@ -116,7 +121,8 @@ const StyledFooter = styled('div', { gap: '1rem', '&& .InfoCircleIcon': { - color: variant == 'filled' ? theme.palette.common.white : theme.palette.background.info?.default + color: + variant === 'filled' ? theme.palette.common.white : theme.palette.background.info?.default } })); diff --git a/src/theme/colors/colors.ts b/src/theme/colors/colors.ts index 24a60e708..107bc4f36 100644 --- a/src/theme/colors/colors.ts +++ b/src/theme/colors/colors.ts @@ -7,6 +7,7 @@ export const KEPPEL = '#00B39F'; export const DARK_KEPPEL = '#00A18F'; export const CARIBBEAN_GREEN = '#00D3A9'; export const TEAL_BLUE = '#477E96'; +export const DARK_TEAL_BLUE = '#3B687B'; export const CHARCOAL = '#3C494F'; export const BLACK = '#000000'; export const MIDNIGHT_BLACK = '#111111'; @@ -324,6 +325,15 @@ export const buttonDelete = { hover: redDelete.light }; +export const darkModalGradient = { + header: `linear-gradient(90deg, ${charcoal[30]} 0%, ${accentGrey[30]} 100%)`, + fotter: `linear-gradient(90deg, ${accentGrey[30]} 0%, ${charcoal[30]} 100%)` +}; + +export const lightModalGradient = { + header: `linear-gradient(90deg, ${TEAL_BLUE} 0%, ${DARK_TEAL_BLUE} 100%)`, + fotter: `linear-gradient(90deg, ${DARK_TEAL_BLUE} 0%, ${TEAL_BLUE} 100%)` +}; /** * Notification Colors */ From 7e371ba15b0ab9d54dfb315bd0753f138a790f4c Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 27 Oct 2024 18:53:06 +0530 Subject: [PATCH 046/103] feat: add new react-share dependenci Signed-off-by: Amit Amrutiya --- package-lock.json | 82 ++++++++++++++++++++++++++++++++++++++++++++++- package.json | 3 +- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bee091161..0034a3902 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "0.14.11", "dependencies": { "js-yaml": "^4.1.0", - "lodash": "^4.17.21" + "lodash": "^4.17.21", + "react-share": "^5.1.0" }, "devDependencies": { "@commitlint/cli": "^17.7.2", @@ -4411,6 +4412,12 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -8893,6 +8900,29 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", + "integrity": "sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==", + "dependencies": { + "debug": "^2.1.3" + } + }, + "node_modules/jsonp/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/jsonp/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -11623,6 +11653,19 @@ } } }, + "node_modules/react-share": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-share/-/react-share-5.1.0.tgz", + "integrity": "sha512-OvyfMtj/0UzH1wi90OdHhZVJ6WUC/+IeWvBwppeZozwIGyAjQgyR0QXlHOrxVHVECqnGvcpBaFTXVrqouTieaw==", + "license": "MIT", + "dependencies": { + "classnames": "^2.3.2", + "jsonp": "^0.2.1" + }, + "peerDependencies": { + "react": "^17 || ^18" + } + }, "node_modules/react-sortable-tree-patch-react-17": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/react-sortable-tree-patch-react-17/-/react-sortable-tree-patch-react-17-2.9.0.tgz", @@ -17258,6 +17301,11 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -20386,6 +20434,29 @@ "universalify": "^2.0.0" } }, + "jsonp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz", + "integrity": "sha512-pfog5gdDxPdV4eP7Kg87M8/bHgshlZ5pybl+yKxAnCZ5O7lCIn7Ixydj03wOlnDQesky2BPyA91SQ+5Y/mNwzw==", + "requires": { + "debug": "^2.1.3" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -22192,6 +22263,15 @@ "use-sync-external-store": "^1.0.0" } }, + "react-share": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-share/-/react-share-5.1.0.tgz", + "integrity": "sha512-OvyfMtj/0UzH1wi90OdHhZVJ6WUC/+IeWvBwppeZozwIGyAjQgyR0QXlHOrxVHVECqnGvcpBaFTXVrqouTieaw==", + "requires": { + "classnames": "^2.3.2", + "jsonp": "^0.2.1" + } + }, "react-sortable-tree-patch-react-17": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/react-sortable-tree-patch-react-17/-/react-sortable-tree-patch-react-17-2.9.0.tgz", diff --git a/package.json b/package.json index 55ac382ab..04cee394a 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,7 @@ }, "dependencies": { "js-yaml": "^4.1.0", - "lodash": "^4.17.21" + "lodash": "^4.17.21", + "react-share": "^5.1.0" } } From 00810e9a6afb2d7a3a50c3d7295b2cbe416c4c78 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 27 Oct 2024 18:53:23 +0530 Subject: [PATCH 047/103] feat: Add helper functions and types for CatalogDetail component Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/helper.ts | 75 ++++++++++++++++++++++++++++++ src/custom/CatalogDetail/types.ts | 50 ++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/custom/CatalogDetail/helper.ts create mode 100644 src/custom/CatalogDetail/types.ts diff --git a/src/custom/CatalogDetail/helper.ts b/src/custom/CatalogDetail/helper.ts new file mode 100644 index 000000000..a46311c41 --- /dev/null +++ b/src/custom/CatalogDetail/helper.ts @@ -0,0 +1,75 @@ +import jsyaml from 'js-yaml'; +import { CommunityClassIcon, OfficialClassIcon, VerificationClassIcon } from '../../icons'; +import { ContentClassType } from './types'; + +export const downloadYaml = (filteredData: string, itemName: string): void => { + const yamlData = Array.isArray(filteredData) + ? jsyaml.dump(filteredData.find((item) => item.name === itemName)) + : filteredData; + const blob = new Blob([yamlData], { type: 'application/yaml' }); + const url = URL.createObjectURL(blob); + const element = document.createElement('a'); + element.href = url; + element.download = `${itemName}.yaml`; + // document.body.appendChild(element); // Required for this to work in FireFox + element.click(); + URL.revokeObjectURL(url); +}; + +export function slugify(str: string): string { + if (!str) return str; + str = str.replace(/^\s+|\s+$/g, ''); // trim leading/trailing whitespace + str = str.toLowerCase(); + + // remove accents, swap ñ for n, etc + const from = 'àáäâèéëêìíïîòóöôùúüûñç·/_,:;'; + const to = 'aaaaeeeeiiiioooouuuunc------'; + for (let i = 0, l = from.length; i < l; i++) { + str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i)); + } + + str = str + .replace(/[^a-z0-9 -]/g, '') // remove invalid chars + .replace(/\s+/g, '-') // collapse whitespace and replace by - + .replace(/-+/g, '-'); // collapse dashes + + return str; +} + +export const downloadFilter = (id: string, name: string): void => { + const dataUri = `${process.env.API_ENDPOINT_PREFIX}/api/content/filters/download/${id}`; + + // Add the .wasm extension to the filename + const fileNameWithExtension = name + '.wasm'; + + const linkElement = document.createElement('a'); + linkElement.setAttribute('href', dataUri); + linkElement.setAttribute('download', fileNameWithExtension); + linkElement.click(); + linkElement.remove(); +}; + +export const CONTENT_CLASS: ContentClassType = { + community: { + icon: CommunityClassIcon + }, + official: { + icon: OfficialClassIcon + }, + verified: { + icon: VerificationClassIcon + } +}; + +export const formatToTitleCase = (value: string): string => { + if (typeof value === 'string') { + return value.substring(0, 1).toUpperCase().concat('', value.substring(1).toLowerCase()); + } + return ''; +}; + +export const formatDate = (date: Date) => { + const options = { year: 'numeric', month: 'short', day: 'numeric' }; + const formattedDate = new Date(date).toLocaleDateString('en-US', options); + return formattedDate; +}; diff --git a/src/custom/CatalogDetail/types.ts b/src/custom/CatalogDetail/types.ts new file mode 100644 index 000000000..40d8b2d38 --- /dev/null +++ b/src/custom/CatalogDetail/types.ts @@ -0,0 +1,50 @@ +export interface User { + id: string; + first_name: string; + last_name: string; +} + +export interface FilteredAcademyData { + 'learning-path'?: string[]; + challenge?: string[]; + challenges?: string[]; +} + +export interface Class { + class: string; + description: string; +} + +export interface Theme { + palette: { + background: { + secondary: string; + inverse: string; + cta: { + default: string; + }; + }; + icon: { + default: string; + secondary: string; + }; + }; +} + +export const RESOURCE_TYPES = { + DESIGNS: 'design', + FILTERS: 'filter', + VIEWS: 'view' +}; + +export type ContentClassType = { + community: { + icon: React.ComponentType; + }; + official: { + icon: React.ComponentType; + }; + verified: { + icon: React.ComponentType; + }; +}; From 47eb5da1a415757e01f882eee6c29722d97166bd Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 27 Oct 2024 18:54:15 +0530 Subject: [PATCH 048/103] feat: Add styles and components for CatalogDetail page Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/index.tsx | 31 ++++ src/custom/CatalogDetail/style.tsx | 252 +++++++++++++++++++++++++++++ src/custom/index.tsx | 1 + 3 files changed, 284 insertions(+) create mode 100644 src/custom/CatalogDetail/index.tsx create mode 100644 src/custom/CatalogDetail/style.tsx diff --git a/src/custom/CatalogDetail/index.tsx b/src/custom/CatalogDetail/index.tsx new file mode 100644 index 000000000..87a3d0208 --- /dev/null +++ b/src/custom/CatalogDetail/index.tsx @@ -0,0 +1,31 @@ +import ActionButtons from './ActionButton'; +import CaveatsSection from './CaveatsSection'; +import ChallengesSection from './ChallengesSection'; +import CollapsibleSection from './CollapsibleSection'; +import LearningSection from './LearningSection'; +import LeftPanel from './LeftPanel'; +import MetricsDisplay from './MetricsDisplay'; +import OverviewSection from './OverviewSection'; +import PatternInfo from './PatternInfo'; +import RelatedDesigns from './RelatedDesigns'; +import RightPanel from './RightPanel'; +import SocialSharePopper from './SocialSharePopper'; +import TechnologySection from './TechnologySection'; +import UserInfo from './UserInfo'; + +export { + ActionButtons, + CaveatsSection, + ChallengesSection, + CollapsibleSection, + LearningSection, + LeftPanel, + MetricsDisplay, + OverviewSection, + PatternInfo, + RelatedDesigns, + RightPanel, + SocialSharePopper, + TechnologySection, + UserInfo +}; diff --git a/src/custom/CatalogDetail/style.tsx b/src/custom/CatalogDetail/style.tsx new file mode 100644 index 000000000..19e91d765 --- /dev/null +++ b/src/custom/CatalogDetail/style.tsx @@ -0,0 +1,252 @@ +import { ListItemButton, Paper, Typography } from '../../base'; +import { styled } from '../../theme'; +import { Theme } from './types'; + +export const StyledActionWrapper = styled(Paper)(() => ({ + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + justifyContent: 'center', + width: '100%', + margin: '0', + marginTop: '1rem', + display: 'flex', + flexDirection: 'column', + gap: '1rem', + padding: '0.6rem', + alignItems: 'center' +})); + +export const LinkUrl = styled('a')(() => ({ + textDecoration: 'none' +})); + +interface ActionButtonProps { + disabled?: boolean; + theme?: Theme; +} + +export const ActionButton = styled('div')(({ disabled = false, theme }) => ({ + cursor: disabled ? 'not-allowed' : 'pointer', + opacity: disabled ? '0.5' : '1', + textAlign: 'center', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + borderRadius: '0.5rem', + backgroundColor: theme.palette.background.brand?.default, + padding: '0.5rem', + color: theme.palette.text.inverse, + gap: '0.625rem', + flex: '1' +})); + +export const ContentDetailsText = styled(Typography)(({ theme }) => ({ + fontSize: '1rem', + color: theme.palette.text.default, + ['@media (min-width:1200px)']: { + fontSize: '1.3rem' + } +})); + +export const ContentHeading = styled('div')(() => ({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', + marginBottom: '1rem' +})); + +export const CaveatsContainer = styled('div')(({ theme }) => ({ + width: '100%', + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + backgroundColor: theme.palette.background.default, + textAlign: 'left', + justifyContent: 'start', + alignItems: 'start', + display: 'flex', + flexWrap: 'wrap', + flexDirection: 'column', + padding: '1.5rem', + marginTop: '1.5rem', + borderRadius: '0.4rem', + overflowWrap: 'anywhere' +})); + +interface LabelDivProps { + clickable?: boolean; +} + +export const LabelDiv = styled('div')(({ theme, clickable }) => ({ + display: 'flex', + justifyContent: 'start', + alignItems: 'center', + padding: '0.5rem 1.5rem', + width: '100%', + borderBottom: `1px solid ${theme.palette.border.default}`, + [' @media (min-width: 600px) and (max-width: 800px)']: { + padding: '0.5rem' + }, + ...(clickable && { + '&:hover': { + backgroundColor: theme.palette.background.hover + }, + cursor: 'pointer' + }) +})); + +export const SideContainer = styled('div')(({ theme }) => ({ + width: '100%', + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + backgroundColor: theme.palette.background.default, + justifyContent: 'start', + alignItems: 'start', + display: 'flex', + flexDirection: 'column', + padding: '0.5rem', + borderRadius: '0.4rem' +})); + +export const SideTitleButton = styled(ListItemButton)(({ theme }) => ({ + backgroundColor: theme.palette.background.surfaces, + borderRadius: '0.5rem', + marginTop: 2, + width: '100%', + [' @media (min-width: 600px) and (max-width: 800px)']: { + padding: '0.5rem' + } +})); + +export const ContentDetailsPoints = styled(Typography)(() => ({ + fontSize: '.9rem', + fontWeight: 'bold', + lineHeight: '1.5rem', + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + gap: '1rem' +})); + +export const MetricsSection = styled('div')(() => ({ + padding: '1.1rem', + marginTop: '0.5rem', + display: 'flex', + borderTop: '0.5px solid #3C494F', + justifyContent: 'center', + gap: '1.7rem', + flexWrap: 'wrap', + ['@media (max-width:1200px)']: { + justifyContent: 'flex-start' + } +})); + +export const MetricsContainer = styled('div')(() => ({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + [' @media (min-width: 280px) and (max-width: 700px)']: { + flexBasis: '35%' + }, + [' @media (max-width: 280px)']: { + flexBasis: '10%' + } +})); +export const MetricsType = styled('div')(({ theme }) => ({ + display: 'flex', + fontSize: '16px', + fontWeight: '400', + letterSpacing: '0.15px', + lineHeight: '1.5', + textTransform: 'lowercase', + color: theme.palette.background.supplementary, + [' @media (max-width: 285px)']: { + fontSize: '0.86rem' + } +})); +export const MetricsData = styled('div')(({ theme }) => ({ + color: theme.palette.background.supplementary, + fontSize: '1.2rem', + fontWeight: 'bold', + lineHeight: '1.5' +})); + +export const OverviewContainer = styled('div')(({ theme }) => ({ + width: '100%', + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + backgroundColor: theme.palette.background.default, + textAlign: 'left', + justifyContent: 'start', + alignItems: 'start', + display: 'flex', + flexWrap: 'wrap', + flexDirection: 'column', + padding: '1.5rem', + borderRadius: '0.4rem' +})); + +export const DesignHeading = styled('h1')(({ theme }) => ({ + textAlign: 'left', + margin: '0rem 0rem 2rem 0rem', + color: theme.palette.text.default, + textTransform: 'capitalize', + fontWeight: '300', + flex: '1' +})); + +export const ContentRow = styled('div')(() => ({ + padding: '0.5rem 0', + overflowWrap: 'anywhere' +})); + +export const ShowToggleBtn = styled('span')(({ theme }) => ({ + color: theme.palette.background.brand?.default, + cursor: 'pointer', + fontSize: '1rem', + fontWeight: 'normal', + marginLeft: '0.25rem' +})); + +export const AdditionalContainer = styled('div')(({ theme }) => ({ + width: '100%', + boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.2)', + backgroundColor: theme.palette.background.default, + textAlign: 'left', + justifyContent: 'center', + alignItems: 'center', + display: 'flex', + flexWrap: 'wrap', + flexDirection: 'column', + padding: '1.5rem', + paddingBottom: '2rem', + marginTop: '1.5rem', + borderRadius: '0.4rem' +})); + +export const DesignCardContainer = styled('div')(() => ({ + display: 'flex', + flexWrap: 'wrap', + flex: '0 0 75%', + gap: '2rem', + justifyContent: 'space-around', + height: 'fit-content' +})); + +export const CopyShareIconWrapper = styled(ContentHeading)(() => ({ + justifyContent: 'flex-end', + gap: '1rem', + width: 'fit-content' +})); + +export const VisibilityChip = styled('div')(() => ({ + borderRadius: '0.5rem', + border: '1px solid gray', + padding: '0.2rem 0.5rem', + textTransform: 'capitalize', + color: '#1a1a1acc', + width: 'fit-content' +})); + +export const RedirectLink = styled('a')(({ theme }) => ({ + color: theme.palette.background.brand?.default, + textDecoration: 'none', + cursor: 'pointer' +})); diff --git a/src/custom/index.tsx b/src/custom/index.tsx index a7505ea50..14e2b14ab 100644 --- a/src/custom/index.tsx +++ b/src/custom/index.tsx @@ -130,5 +130,6 @@ export type { UniversalFilterProps }; +export * from './CatalogDetail'; export * from './Dialog'; export * from './permissions'; From f0022cbff6adf0a31be7f52283584139d236d10b Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Sun, 27 Oct 2024 18:54:41 +0530 Subject: [PATCH 049/103] refactor: Refactor CustomCatalog/CustomCard component Signed-off-by: Amit Amrutiya --- src/custom/CustomCatalog/CustomCard.tsx | 30 +++++++++++++++---------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/custom/CustomCatalog/CustomCard.tsx b/src/custom/CustomCatalog/CustomCard.tsx index 92517aa77..db62959b8 100644 --- a/src/custom/CustomCatalog/CustomCard.tsx +++ b/src/custom/CustomCatalog/CustomCard.tsx @@ -1,12 +1,11 @@ import CalendarMonthIcon from '@mui/icons-material/CalendarMonth'; -import { Avatar, styled } from '@mui/material'; import React, { useEffect, useState } from 'react'; -import { Grid } from '../../base'; +import { Avatar, Grid } from '../../base'; import { CloneIcon, CommunityClassIcon, OfficialClassIcon, OpenIcon, ShareIcon } from '../../icons'; import VerificationClassIcon from '../../icons/ContentClassIcons/VerificationClassIcon'; import DeploymentsIcon from '../../icons/Deployments/DeploymentsIcon'; import { DownloadIcon } from '../../icons/Download'; -import { DARK_TEAL, useTheme } from '../../theme'; +import { DARK_TEAL, styled, useTheme } from '../../theme'; import { SNOW_WHITE } from '../../theme/colors/colors'; import { CustomTooltip } from '../CustomTooltip'; import { getVersion, handleImage } from './Helper'; @@ -42,6 +41,10 @@ export interface Pattern { id: string; user_id: string; pattern_file: string; + user: { + first_name: string; + last_name: string; + }; name: string; download_count: number; clone_count: number; @@ -61,18 +64,21 @@ export interface Pattern { compatibility?: string[]; published_version?: string; type?: string; + pattern_info?: string; + pattern_caveats?: string; }; visibility: string; updated_at: Date; + created_at: Date; } type CatalogCardProps = { pattern: Pattern; patternType: string; - cardHeight: string; - cardWidth: string; - cardStyles: React.CSSProperties; - avatarUrl: string; + cardHeight?: string; + cardWidth?: string; + cardStyles?: React.CSSProperties; + avatarUrl?: string; shouldFlip?: boolean; cardTechnologies?: boolean; isDetailed?: boolean; @@ -105,12 +111,12 @@ const ClassWrap = ({ catalogClassName }: { catalogClassName: string }) => { const CustomCatalogCard: React.FC = ({ pattern, patternType, - cardHeight, - cardWidth, + cardHeight = '18rem', + cardWidth = '15rem', cardStyles, - shouldFlip, - isDetailed, - cardTechnologies, + shouldFlip = true, + isDetailed = true, + cardTechnologies = true, avatarUrl, UserName, children, From c89b1275bbacdbbb2f82faf34442d01923f59ce9 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Mon, 28 Oct 2024 18:55:37 +0530 Subject: [PATCH 050/103] feat: create leftpanel components of catalog detail Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/ActionButton.tsx | 116 ++++++++++++++++++ src/custom/CatalogDetail/CaveatsSection.tsx | 30 +++++ .../CatalogDetail/ChallengesSection.tsx | 71 +++++++++++ .../CatalogDetail/CollapsibleSection.tsx | 61 +++++++++ src/custom/CatalogDetail/ContentClassInfo.tsx | 48 ++++++++ src/custom/CatalogDetail/LearningSection.tsx | 70 +++++++++++ src/custom/CatalogDetail/LeftPanel.tsx | 101 +++++++++++++++ 7 files changed, 497 insertions(+) create mode 100644 src/custom/CatalogDetail/ActionButton.tsx create mode 100644 src/custom/CatalogDetail/CaveatsSection.tsx create mode 100644 src/custom/CatalogDetail/ChallengesSection.tsx create mode 100644 src/custom/CatalogDetail/CollapsibleSection.tsx create mode 100644 src/custom/CatalogDetail/ContentClassInfo.tsx create mode 100644 src/custom/CatalogDetail/LearningSection.tsx create mode 100644 src/custom/CatalogDetail/LeftPanel.tsx diff --git a/src/custom/CatalogDetail/ActionButton.tsx b/src/custom/CatalogDetail/ActionButton.tsx new file mode 100644 index 000000000..808835277 --- /dev/null +++ b/src/custom/CatalogDetail/ActionButton.tsx @@ -0,0 +1,116 @@ +import _ from 'lodash'; +import React from 'react'; +import { CircularProgress } from '../../base'; +import Download from '../../icons/Download/Download'; +import { charcoal } from '../../theme'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import CopyIcon from './Icons/CopyIcon'; +import KanvasIcon from './Icons/Kanvas'; +import { downloadFilter, downloadYaml, slugify } from './helper'; +import { ActionButton, LinkUrl, StyledActionWrapper } from './style'; +import { RESOURCE_TYPES } from './types'; + +interface ActionButtonsProps { + actionItems: boolean; + details: Pattern; + type: string; + cardId: string; + isCloneLoading: boolean; + handleClone: (name: string, id: string) => void; + mode: string; + isCloneDisabled: boolean; +} + +const ActionButtons: React.FC = ({ + actionItems, + details, + type, + cardId, + isCloneLoading, + handleClone, + mode, + isCloneDisabled +}) => { + const cleanedType = type.replace('my-', '').replace(/s$/, ''); + const resourcePlaygroundType = Object.values({ + ..._.omit(RESOURCE_TYPES, ['FILTERS']), + CATALOG: 'catalog' + }).includes(cleanedType) + ? cleanedType + : 'design'; + return ( + + {actionItems && ( +
+ + cleanedType === RESOURCE_TYPES.FILTERS + ? downloadFilter(details.id, details.name) + : downloadYaml(details.pattern_file, details.name) + } + > + + Download + + + {cleanedType !== RESOURCE_TYPES.FILTERS && ( + handleClone(details?.name, details?.id)} + disabled={isCloneDisabled} + > + {isCloneLoading ? ( + + ) : ( + <> + + Clone + + )} + + )} +
+ )} + + + + Open in Playground + + +
+ ); +}; + +export default ActionButtons; diff --git a/src/custom/CatalogDetail/CaveatsSection.tsx b/src/custom/CatalogDetail/CaveatsSection.tsx new file mode 100644 index 000000000..71697a3d1 --- /dev/null +++ b/src/custom/CatalogDetail/CaveatsSection.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import { RenderMarkdown } from '../Markdown'; +import { ContentDetailsText } from '../Typography'; +import { CaveatsContainer, ContentHeading } from './style'; + +interface CaveatsSectionProps { + details: Pattern; +} + +const CaveatsSection: React.FC = ({ details }) => { + return ( + + +

CAVEATS AND CONSIDERATIONS

+
+ {details?.catalog_data?.pattern_caveats ? ( + + + + ) : ( + No caveats registered + )} +
+ ); +}; + +export default CaveatsSection; diff --git a/src/custom/CatalogDetail/ChallengesSection.tsx b/src/custom/CatalogDetail/ChallengesSection.tsx new file mode 100644 index 000000000..5110607b6 --- /dev/null +++ b/src/custom/CatalogDetail/ChallengesSection.tsx @@ -0,0 +1,71 @@ +import { useEffect, useState } from 'react'; +import { ListItemIcon } from '../../base'; +import { useTheme } from '../../theme'; +import CollapsibleSection from './CollapsibleSection'; +import ChallengesIcon from './Icons/ChallengesIcon'; +import { slugify } from './helper'; +import { LabelDiv } from './style'; +import { FilteredAcademyData } from './types'; + +interface ChallengesSectionProps { + filteredAcademyData: FilteredAcademyData; +} + +const ChallengesSection: React.FC = ({ filteredAcademyData }) => { + const theme = useTheme(); + const [openChallenges, setOpenChallenges] = useState(false); + const [autoUpdate, setAutoUpdate] = useState(true); + + useEffect(() => { + if (autoUpdate) { + setOpenChallenges((filteredAcademyData?.['challenges'] ?? []).length > 0); + } + }, [filteredAcademyData, autoUpdate]); + + const toggleOpenChallenges = () => { + setOpenChallenges((prev) => !prev); + setAutoUpdate(false); + }; + + const navigateToChallenge = (item: string) => { + window.location.href = `/academy/challenges/${slugify('' + item)}`; + }; + + const renderChallengeItem = (item: string, index: number) => ( + navigateToChallenge(item)}> + + + + {item} + + ); + + return ( + <> +
+ + + ); +}; + +export default ChallengesSection; diff --git a/src/custom/CatalogDetail/CollapsibleSection.tsx b/src/custom/CatalogDetail/CollapsibleSection.tsx new file mode 100644 index 000000000..24739f486 --- /dev/null +++ b/src/custom/CatalogDetail/CollapsibleSection.tsx @@ -0,0 +1,61 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import { Collapse, List, ListItemText } from '@mui/material'; +import { InfoTooltip } from '../CustomTooltip'; +import { SideContainer, SideTitleButton } from './style'; + +interface CollapsibleSectionProps { + title: string; + isOpen: boolean; + onToggle: () => void; + items: any[]; + renderItem: (item: any, index: number) => React.ReactNode; + emptyState: string; + tooltip: string; +} + +const CollapsibleSection: React.FC = ({ + title, + isOpen, + onToggle, + items, + renderItem, + emptyState, + tooltip +}) => { + return ( + + + + + {isOpen ? : } + + + {items && items.length > 0 ? ( + + {items?.map(renderItem)} + + ) : ( + + )} + + + ); +}; + +export default CollapsibleSection; diff --git a/src/custom/CatalogDetail/ContentClassInfo.tsx b/src/custom/CatalogDetail/ContentClassInfo.tsx new file mode 100644 index 000000000..5f2174993 --- /dev/null +++ b/src/custom/CatalogDetail/ContentClassInfo.tsx @@ -0,0 +1,48 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import { InfoTooltip } from '../CustomTooltip'; +import { ContentDetailsPoints, ContentDetailsText } from '../Typography'; +import { CONTENT_CLASS, formatToTitleCase } from './helper'; +import { Class } from './types'; + +interface ContentClassInfoProps { + contentClass: string; + classes: Class[]; +} + +const ClassIcon: React.FC<{ className: string }> = ({ className }) => { + const Icon = CONTENT_CLASS[className]?.icon; + return Icon ? : null; +}; + +const ContentClassInfo: React.FC = ({ contentClass, classes }) => { + const classDescription = (className: string): string | undefined => { + const classObj = classes && classes.find((classObj) => classObj.class === className); + return classObj?.description; + }; + + return ( +
+ + CLASS + + + + + {formatToTitleCase(contentClass)} + +
+ ); +}; + +export default ContentClassInfo; diff --git a/src/custom/CatalogDetail/LearningSection.tsx b/src/custom/CatalogDetail/LearningSection.tsx new file mode 100644 index 000000000..2763b2c37 --- /dev/null +++ b/src/custom/CatalogDetail/LearningSection.tsx @@ -0,0 +1,70 @@ +import React, { useEffect, useState } from 'react'; +import { ListItemIcon } from '../../base'; +import { useTheme } from '../../theme'; +import CollapsibleSection from './CollapsibleSection'; +import LearningIcon from './Icons/LearningIcon'; +import { slugify } from './helper'; +import { LabelDiv } from './style'; +import { FilteredAcademyData } from './types'; + +interface LearningSectionProps { + filteredAcademyData: FilteredAcademyData; +} + +const LearningSection: React.FC = ({ filteredAcademyData }) => { + const theme = useTheme(); + const [openLearning, setOpenLearning] = useState(false); + const [autoUpdate, setAutoUpdate] = useState(true); + + useEffect(() => { + if (autoUpdate) { + setOpenLearning(Boolean((filteredAcademyData?.['learning-path'] ?? []).length > 0)); + } + }, [filteredAcademyData, autoUpdate]); + + const toggleOpenLearning = (): void => { + setOpenLearning((prev) => !prev); + setAutoUpdate(false); + }; + + const navigateToLearningPath = (item: string): void => { + window.location.href = `/academy/learning-paths/${slugify('' + item)}`; + }; + + const renderLearningItem = (item: string, index: number) => ( + navigateToLearningPath(item)}> + + + + {item} + + ); + + return ( + <> +
+ + + ); +}; + +export default LearningSection; diff --git a/src/custom/CatalogDetail/LeftPanel.tsx b/src/custom/CatalogDetail/LeftPanel.tsx new file mode 100644 index 000000000..af1ac1602 --- /dev/null +++ b/src/custom/CatalogDetail/LeftPanel.tsx @@ -0,0 +1,101 @@ +import { useTheme } from '../../theme'; +import { CatalogCardDesignLogo, CustomCatalogCard } from '../CustomCatalog'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import ActionButtons from './ActionButton'; +import ChallengesSection from './ChallengesSection'; +import LearningSection from './LearningSection'; +import TechnologySection from './TechnologySection'; +import { FilteredAcademyData } from './types'; + +interface LeftPanelProps { + details: Pattern; + type: string; + cardId?: string; + actionItems?: boolean; + isCloneLoading: boolean; + handleClone: (name: string, id: string) => void; + showTechnologies?: boolean; + openTechnologies: boolean; + availableTechnologies: string[]; + handleOpenTechnologies: () => void; + mode: string; + filteredAcademyData: FilteredAcademyData; + isCloneDisabled: boolean; + technologySVGPath: string; + technologySVGSubpath: string; + fontFamily?: string; +} + +const LeftPanel: React.FC = ({ + details, + type, + cardId = details.id, + actionItems = true, + isCloneLoading, + handleClone, + showTechnologies = true, + openTechnologies, + availableTechnologies, + handleOpenTechnologies, + mode, + filteredAcademyData, + isCloneDisabled, + technologySVGPath, + technologySVGSubpath, + fontFamily +}) => { + const theme = useTheme(); + return ( +
+ + + + + {showTechnologies && ( + + )} + + +
+ ); +}; + +export default LeftPanel; From 76b032147ea21c826e0edb8d20e2a614c1fc073e Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Mon, 28 Oct 2024 18:56:07 +0530 Subject: [PATCH 051/103] feat: create rightpanel components of catalog detail Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/MetricsDisplay.tsx | 38 +++++++ src/custom/CatalogDetail/OverviewSection.tsx | 105 ++++++++++++++++++ src/custom/CatalogDetail/PatternInfo.tsx | 45 ++++++++ src/custom/CatalogDetail/RelatedDesigns.tsx | 47 ++++++++ src/custom/CatalogDetail/RightPanel.tsx | 73 ++++++++++++ .../CatalogDetail/SocialSharePopper.tsx | 103 +++++++++++++++++ .../CatalogDetail/TechnologySection.tsx | 60 ++++++++++ src/custom/CatalogDetail/UserInfo.tsx | 42 +++++++ 8 files changed, 513 insertions(+) create mode 100644 src/custom/CatalogDetail/MetricsDisplay.tsx create mode 100644 src/custom/CatalogDetail/OverviewSection.tsx create mode 100644 src/custom/CatalogDetail/PatternInfo.tsx create mode 100644 src/custom/CatalogDetail/RelatedDesigns.tsx create mode 100644 src/custom/CatalogDetail/RightPanel.tsx create mode 100644 src/custom/CatalogDetail/SocialSharePopper.tsx create mode 100644 src/custom/CatalogDetail/TechnologySection.tsx create mode 100644 src/custom/CatalogDetail/UserInfo.tsx diff --git a/src/custom/CatalogDetail/MetricsDisplay.tsx b/src/custom/CatalogDetail/MetricsDisplay.tsx new file mode 100644 index 000000000..85cf7ec42 --- /dev/null +++ b/src/custom/CatalogDetail/MetricsDisplay.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { Grid } from '../../base'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import { MetricsContainer, MetricsData, MetricsSection, MetricsType } from './style'; + +interface MetricItem { + label: string; + value: number; +} + +interface MetricsDisplayProps { + details: Pattern; +} + +const MetricsDisplay: React.FC = ({ details }) => { + const metrics: MetricItem[] = [ + { label: 'Opens', value: details.view_count }, + { label: 'Downloads', value: details.download_count }, + { label: 'Deploys', value: details.deployment_count }, + { label: 'Clones', value: details.clone_count }, + { label: 'Shares', value: details.share_count } + ]; + + return ( + + + {metrics.map((metric) => ( + + {metric.value} + {metric.label} + + ))} + + + ); +}; + +export default MetricsDisplay; diff --git a/src/custom/CatalogDetail/OverviewSection.tsx b/src/custom/CatalogDetail/OverviewSection.tsx new file mode 100644 index 000000000..756d2f7f2 --- /dev/null +++ b/src/custom/CatalogDetail/OverviewSection.tsx @@ -0,0 +1,105 @@ +import { Grid } from '@mui/material'; +import React from 'react'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import ContentClassInfo from './ContentClassInfo'; +import MetricsDisplay from './MetricsDisplay'; +import PatternInfo from './PatternInfo'; +import SocialSharePopper from './SocialSharePopper'; +import UserInfo from './UserInfo'; +import { ContentRow, DesignHeading, OverviewContainer } from './style'; +import { Class } from './types'; + +interface OverviewSectionProps { + details: Pattern; + type: string; + cardId: string; + handleClick: (event: React.MouseEvent) => void; + title: string; + id: string; + anchorEl: HTMLElement | null; + handleClose: () => void; + getUrl: (type: string, id: string) => string; + showContentDetails: boolean; + ViewsComponent?: React.ReactNode; + showVersion: boolean; + classes: Class[]; + handleCopyUrl: (type: string, name: string, id: string) => void; +} + +const OverviewSection: React.FC = ({ + details, + type, + cardId, + handleClick, + title, + id, + anchorEl, + handleClose, + getUrl, + showContentDetails, + ViewsComponent, + showVersion, + classes, + handleCopyUrl +}) => { + return ( + +
+ {details?.name} + +
+ + + + + {details?.catalog_data?.content_class && ( + + + + )} + + + + + + {showContentDetails ? ( + +

WHAT DOES THIS DESIGN DO?

+ {details?.catalog_data?.pattern_info ? ( + + ) : ( +
No description available
+ )} +
+ ) : ( + ViewsComponent + )} +
+ {!(type === 'view' || type === 'filter') && } +
+
+ ); +}; + +export default OverviewSection; diff --git a/src/custom/CatalogDetail/PatternInfo.tsx b/src/custom/CatalogDetail/PatternInfo.tsx new file mode 100644 index 000000000..6371ddcd7 --- /dev/null +++ b/src/custom/CatalogDetail/PatternInfo.tsx @@ -0,0 +1,45 @@ +import React, { useState } from 'react'; +import { RenderMarkdown } from '../Markdown'; +import { ShowToggleBtn } from './style'; + +interface PatternInfoProps { + text: string; + redirect?: boolean; + id?: string; +} + +const PatternInfo: React.FC = ({ text, redirect, id }) => { + const [isExpanded, setIsExpanded] = useState(false); + + const toggleExpand = () => { + setIsExpanded(!isExpanded); + }; + + const handleRedirect = () => { + if (id) { + window.location.href = `/catalog/content/design/${id}`; + } + }; + + return ( +
+ {isExpanded ? ( +
+ + show less +
+ ) : ( +
+ + {text.length > (redirect ? 400 : 500) && ( + + ...show more + + )} +
+ )} +
+ ); +}; + +export default PatternInfo; diff --git a/src/custom/CatalogDetail/RelatedDesigns.tsx b/src/custom/CatalogDetail/RelatedDesigns.tsx new file mode 100644 index 000000000..5b000b86f --- /dev/null +++ b/src/custom/CatalogDetail/RelatedDesigns.tsx @@ -0,0 +1,47 @@ +import { CatalogCardDesignLogo } from '../CustomCatalog'; +import CustomCatalogCard, { Pattern } from '../CustomCatalog/CustomCard'; +import { formatToTitleCase } from './helper'; +import { AdditionalContainer, ContentHeading, DesignCardContainer } from './style'; + +export interface PatternsPerUser { + patterns: Pattern[]; +} + +interface RelatedDesignsProps { + details: Pattern; + type: string; + patternsPerUser: PatternsPerUser; +} + +const RelatedDesigns: React.FC = ({ details, type, patternsPerUser }) => { + const filteredPatternsPerUser = patternsPerUser?.patterns?.filter( + (pattern) => pattern.id !== details.id + ); + + if (!filteredPatternsPerUser?.length) return null; + + return ( + + +

+ Other published design by {formatToTitleCase(details.user.first_name)} +

+
+ + {filteredPatternsPerUser.map((pattern, index) => ( + + + + ))} + +
+ ); +}; + +export default RelatedDesigns; diff --git a/src/custom/CatalogDetail/RightPanel.tsx b/src/custom/CatalogDetail/RightPanel.tsx new file mode 100644 index 000000000..4d3c0609d --- /dev/null +++ b/src/custom/CatalogDetail/RightPanel.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import CaveatsSection from './CaveatsSection'; +import OverviewSection from './OverviewSection'; +import RelatedDesigns, { PatternsPerUser } from './RelatedDesigns'; +import { Class } from './types'; + +interface RightPanelProps { + details: Pattern; + type: string; + cardId: string; + handleClick: (event: React.MouseEvent) => void; + title: string; + id?: string; + anchorEl: HTMLElement | null; + handleClose: () => void; + getUrl: (type: string, id: string) => string; + showContentDetails: boolean; + ViewsComponent?: React.ReactNode; + showVersion: boolean; + showCaveats: boolean; + classes: Class[]; + patternsPerUser: PatternsPerUser; + handleCopyUrl: (type: string, name: string, id: string) => void; + fontFamily?: string; +} + +const RightPanel: React.FC = ({ + details, + type, + cardId, + handleClick, + title, + id = '', + anchorEl, + handleClose, + getUrl, + showContentDetails, + ViewsComponent, + showVersion, + showCaveats, + classes, + patternsPerUser, + handleCopyUrl, + fontFamily +}) => { + const cleanedType = type.replace('my-', '').replace(/s$/, ''); + + return ( +
+ + {showCaveats && } + +
+ ); +}; + +export default RightPanel; diff --git a/src/custom/CatalogDetail/SocialSharePopper.tsx b/src/custom/CatalogDetail/SocialSharePopper.tsx new file mode 100644 index 000000000..ae3bf24be --- /dev/null +++ b/src/custom/CatalogDetail/SocialSharePopper.tsx @@ -0,0 +1,103 @@ +import { + ClickAwayListener, + Fade, + IconButton, + Paper, + Popper, + Tooltip, + useTheme +} from '@mui/material'; +import React from 'react'; +import { FacebookShareButton, LinkedinShareButton, TwitterShareButton } from 'react-share'; +import { ShareIcon } from '../../icons'; +import { Pattern } from '../CustomCatalog/CustomCard'; +import ChainIcon from './Icons/ChainIcon'; +import { FacebookIcon, LinkedinIcon, TwitterIcon } from './Icons/SocialMediaIcon'; +import { CopyShareIconWrapper, VisibilityChip } from './style'; + +interface SocialSharePopperProps { + details: Pattern; + type: string; + cardId: string; + handleClick: (event: React.MouseEvent) => void; + title: string; + id: string; + anchorEl: HTMLElement | null; + handleClose: () => void; + getUrl: (type: string, id: string) => string; + handleCopyUrl: (type: string, name: string, id: string) => void; +} + +const SocialSharePopper: React.FC = ({ + details, + type, + cardId, + handleClick, + title, + id, + anchorEl, + handleClose, + getUrl, + handleCopyUrl +}) => { + const cleanedType = type.replace('my-', '').replace(/s$/, ''); + const theme = useTheme(); + return ( + + + {details?.visibility} + + {details?.visibility !== 'private' && ( + + handleCopyUrl(cleanedType, details?.name, details?.id)} + > + + + + )} + {(details?.visibility === 'published' || details?.visibility === 'public') && ( + <> + + + + + + + {({ TransitionProps }) => ( + + + + + + + + + + + + + + + + )} + + + )} + + ); +}; + +export default SocialSharePopper; diff --git a/src/custom/CatalogDetail/TechnologySection.tsx b/src/custom/CatalogDetail/TechnologySection.tsx new file mode 100644 index 000000000..2bddd5961 --- /dev/null +++ b/src/custom/CatalogDetail/TechnologySection.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { ListItemIcon } from '../../base'; +import { useTheme } from '../../theme'; +import CollapsibleSection from './CollapsibleSection'; +import { LabelDiv } from './style'; + +interface TechnologySectionProps { + availableTechnologies: string[]; + openTechnologies: boolean; + handleOpenTechnologies: () => void; + technologySVGPath: string; + technologySVGSubpath: string; +} + +const TechnologySection: React.FC = ({ + availableTechnologies, + openTechnologies, + handleOpenTechnologies, + technologySVGPath, + technologySVGSubpath +}) => { + const theme = useTheme(); + + const renderTechnologyItem = (item: string, index: number) => { + const svg_path = `${technologySVGPath}/${item.toLowerCase()}/${technologySVGSubpath}/${item.toLowerCase()}-color.svg`; + return ( + + + technology icon + + {item} + + ); + }; + + return ( + <> +
+ + + ); +}; + +export default TechnologySection; diff --git a/src/custom/CatalogDetail/UserInfo.tsx b/src/custom/CatalogDetail/UserInfo.tsx new file mode 100644 index 000000000..6a2222491 --- /dev/null +++ b/src/custom/CatalogDetail/UserInfo.tsx @@ -0,0 +1,42 @@ +import { Pattern } from '../CustomCatalog/CustomCard'; +import { getVersion } from '../CustomCatalog/Helper'; +import { formatDate } from './helper'; +import { ContentDetailsPoints, ContentDetailsText, ContentRow, RedirectLink } from './style'; + +interface UserInfoProps { + details: Pattern; + showVersion?: boolean; +} + +const UserInfo: React.FC = ({ details, showVersion = true }) => { + return ( + <> + + CREATED BY + + + + {details.user.first_name} {details?.user?.last_name} + + + + + + CREATED AT + {formatDate(details?.created_at)} + + + UPDATED AT + {formatDate(details?.updated_at)} + + {showVersion && ( + + VERSION + {getVersion(details)} + + )} + + ); +}; + +export default UserInfo; From 17abeaee9c21dd1209f29b07fc155e65f54bb766 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Mon, 28 Oct 2024 19:18:25 +0530 Subject: [PATCH 052/103] feat: add new icons for detail component Signed-off-by: Amit Amrutiya --- src/icons/Chain/ChainIcon.tsx | 24 +++++++++++ src/icons/Chain/index.ts | 1 + src/icons/Challenges/ChallengesIcon.tsx | 56 +++++++++++++++++++++++++ src/icons/Challenges/index.ts | 1 + src/icons/Copy/CopyIcon.tsx | 26 ++++++++++++ src/icons/Copy/index.ts | 1 + src/icons/Kanvas/KanvasIcon.tsx | 43 +++++++++++++++++++ src/icons/Kanvas/index.ts | 1 + src/icons/Learning/LearningIcon.tsx | 43 +++++++++++++++++++ src/icons/Learning/index.ts | 1 + src/icons/Share/ShareLineIcon.tsx | 32 ++++++++++++++ src/icons/Share/index.tsx | 3 +- src/icons/SocialMedial/FacebookIcon.tsx | 51 ++++++++++++++++++++++ src/icons/SocialMedial/LinkedinIcon.tsx | 51 ++++++++++++++++++++++ src/icons/SocialMedial/TwitterIcon.tsx | 51 ++++++++++++++++++++++ src/icons/SocialMedial/index.ts | 5 +++ src/icons/SocialMedial/types.ts | 6 +++ src/icons/index.ts | 5 +++ 18 files changed, 400 insertions(+), 1 deletion(-) create mode 100644 src/icons/Chain/ChainIcon.tsx create mode 100644 src/icons/Chain/index.ts create mode 100644 src/icons/Challenges/ChallengesIcon.tsx create mode 100644 src/icons/Challenges/index.ts create mode 100644 src/icons/Copy/CopyIcon.tsx create mode 100644 src/icons/Kanvas/KanvasIcon.tsx create mode 100644 src/icons/Kanvas/index.ts create mode 100644 src/icons/Learning/LearningIcon.tsx create mode 100644 src/icons/Learning/index.ts create mode 100644 src/icons/Share/ShareLineIcon.tsx create mode 100644 src/icons/SocialMedial/FacebookIcon.tsx create mode 100644 src/icons/SocialMedial/LinkedinIcon.tsx create mode 100644 src/icons/SocialMedial/TwitterIcon.tsx create mode 100644 src/icons/SocialMedial/index.ts create mode 100644 src/icons/SocialMedial/types.ts diff --git a/src/icons/Chain/ChainIcon.tsx b/src/icons/Chain/ChainIcon.tsx new file mode 100644 index 000000000..727bfa386 --- /dev/null +++ b/src/icons/Chain/ChainIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +interface ChainIconProps { + width: string; + height: string; + fill?: string; + style?: React.CSSProperties; + secondaryFill?: string; +} + +const ChainIcon: React.FC = ({ width, height, style, fill = '#3C494F' }) => ( + + + +); + +export default ChainIcon; diff --git a/src/icons/Chain/index.ts b/src/icons/Chain/index.ts new file mode 100644 index 000000000..043710db5 --- /dev/null +++ b/src/icons/Chain/index.ts @@ -0,0 +1 @@ +export { default as ChainIcon } from './ChainIcon'; diff --git a/src/icons/Challenges/ChallengesIcon.tsx b/src/icons/Challenges/ChallengesIcon.tsx new file mode 100644 index 000000000..94b9b7b7a --- /dev/null +++ b/src/icons/Challenges/ChallengesIcon.tsx @@ -0,0 +1,56 @@ +import React from 'react'; + +interface ChallengesIconProps { + width?: string; + height?: string; + primaryFill?: string; + brandFill?: string; + secondaryFill?: string; + style?: React.CSSProperties; +} + +const ChallengesIcon: React.FC = ({ + width = '32px', + height = '32px', + primaryFill = '#B1B9BC', + brandFill = '#00B39F', + secondaryFill = '#51636B', + style = {} +}) => ( + + + + + + + + + + +); + +export default ChallengesIcon; diff --git a/src/icons/Challenges/index.ts b/src/icons/Challenges/index.ts new file mode 100644 index 000000000..e9cf9c6d5 --- /dev/null +++ b/src/icons/Challenges/index.ts @@ -0,0 +1 @@ +export { default as ChallengesIcon } from './ChallengesIcon'; diff --git a/src/icons/Copy/CopyIcon.tsx b/src/icons/Copy/CopyIcon.tsx new file mode 100644 index 000000000..e5edf8895 --- /dev/null +++ b/src/icons/Copy/CopyIcon.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +interface CopyIconProps { + width: number; + height: number; + fill?: string; + style?: React.CSSProperties; + secondaryFill?: string; +} + +const CopyIcon: React.FC = ({ width, height, fill = 'white', style }) => ( + + + + + +); + +export default CopyIcon; diff --git a/src/icons/Copy/index.ts b/src/icons/Copy/index.ts index 48fc57203..cd7aaba8a 100644 --- a/src/icons/Copy/index.ts +++ b/src/icons/Copy/index.ts @@ -1 +1,2 @@ +export { default as CopyIcon } from './CopyIcon'; export { default as CopyLinkIcon } from './CopyLinkIcon'; diff --git a/src/icons/Kanvas/KanvasIcon.tsx b/src/icons/Kanvas/KanvasIcon.tsx new file mode 100644 index 000000000..affe38816 --- /dev/null +++ b/src/icons/Kanvas/KanvasIcon.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +interface KanvasIconProps { + width: number; + height: number; + fill?: string; + style?: React.CSSProperties; + primaryFill?: string; + secondaryFill?: string; +} + +const KanvasIcon: React.FC = ({ + width, + height, + fill, + style, + primaryFill = 'white' +}) => ( + + + + + + + + + + + + + + +); + +export default KanvasIcon; diff --git a/src/icons/Kanvas/index.ts b/src/icons/Kanvas/index.ts new file mode 100644 index 000000000..3d2dcdd5c --- /dev/null +++ b/src/icons/Kanvas/index.ts @@ -0,0 +1 @@ +export { default as KanvasIcon } from './KanvasIcon'; diff --git a/src/icons/Learning/LearningIcon.tsx b/src/icons/Learning/LearningIcon.tsx new file mode 100644 index 000000000..cf485d448 --- /dev/null +++ b/src/icons/Learning/LearningIcon.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +interface LearningIconProps { + width?: string; + height?: string; + primaryFill?: string; + secondaryFill?: string; + style?: React.CSSProperties; +} + +const LearningIcon: React.FC = ({ + width = '32px', + height = '32px', + primaryFill = '#FDFDFD', + secondaryFill = '#FDFDFD', + style = {} +}) => ( + + + + +); + +export default LearningIcon; diff --git a/src/icons/Learning/index.ts b/src/icons/Learning/index.ts new file mode 100644 index 000000000..4849b25e4 --- /dev/null +++ b/src/icons/Learning/index.ts @@ -0,0 +1 @@ +export { default as LearningIcon } from './LearningIcon'; diff --git a/src/icons/Share/ShareLineIcon.tsx b/src/icons/Share/ShareLineIcon.tsx new file mode 100644 index 000000000..6a4c6fd3a --- /dev/null +++ b/src/icons/Share/ShareLineIcon.tsx @@ -0,0 +1,32 @@ +import React from 'react'; + +interface ShareLineIconProps { + width: string; + height: string; + fill?: string; + style?: React.CSSProperties; + secondaryFill?: string; +} + +const ShareLineIcon: React.FC = ({ + width, + height, + style, + fill = '#3C494F' +}) => ( + + + +); + +export default ShareLineIcon; diff --git a/src/icons/Share/index.tsx b/src/icons/Share/index.tsx index 182307123..5abf944db 100644 --- a/src/icons/Share/index.tsx +++ b/src/icons/Share/index.tsx @@ -1,2 +1,3 @@ import ShareIcon from './ShareIcon'; -export { ShareIcon }; +import ShareLineIcon from './ShareLineIcon'; +export { ShareIcon, ShareLineIcon }; diff --git a/src/icons/SocialMedial/FacebookIcon.tsx b/src/icons/SocialMedial/FacebookIcon.tsx new file mode 100644 index 000000000..0fcf1ea65 --- /dev/null +++ b/src/icons/SocialMedial/FacebookIcon.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { IconProps } from './types'; + +const FacebookIcon: React.FC = ({ width = 40, height = 40 }) => ( + + + + + + + + + + + + + + + + + +); + +export default FacebookIcon; diff --git a/src/icons/SocialMedial/LinkedinIcon.tsx b/src/icons/SocialMedial/LinkedinIcon.tsx new file mode 100644 index 000000000..5ca0d4948 --- /dev/null +++ b/src/icons/SocialMedial/LinkedinIcon.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { IconProps } from './types'; + +const LinkedinIcon: React.FC = ({ width = 40, height = 40 }) => ( + + + + + + + + + + + + + + + + + +); + +export default LinkedinIcon; diff --git a/src/icons/SocialMedial/TwitterIcon.tsx b/src/icons/SocialMedial/TwitterIcon.tsx new file mode 100644 index 000000000..df8172d42 --- /dev/null +++ b/src/icons/SocialMedial/TwitterIcon.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import { IconProps } from './types'; + +const TwitterIcon: React.FC = ({ width = 40, height = 40 }) => ( + + + + + + + + + + + + + + + + + +); + +export default TwitterIcon; diff --git a/src/icons/SocialMedial/index.ts b/src/icons/SocialMedial/index.ts new file mode 100644 index 000000000..1b3be9b14 --- /dev/null +++ b/src/icons/SocialMedial/index.ts @@ -0,0 +1,5 @@ +import FacebookIcon from './FacebookIcon'; +import LinkedinIcon from './LinkedinIcon'; +import TwitterIcon from './TwitterIcon'; + +export { FacebookIcon, LinkedinIcon, TwitterIcon }; diff --git a/src/icons/SocialMedial/types.ts b/src/icons/SocialMedial/types.ts new file mode 100644 index 000000000..f1505e285 --- /dev/null +++ b/src/icons/SocialMedial/types.ts @@ -0,0 +1,6 @@ +export interface IconProps { + width?: number; + height?: number; + fill?: string; + style?: React.CSSProperties; +} diff --git a/src/icons/index.ts b/src/icons/index.ts index c7bf87e66..e280c8992 100644 --- a/src/icons/index.ts +++ b/src/icons/index.ts @@ -40,6 +40,8 @@ export * from './Mesh'; // export { default as ModifiedApplicationFileIcon } from "./ModifiedApplicationFileIcon"; // export { default as OriginalApplicationFileIcon } from "./OriginalApplicationFileIcon"; export * from './Calender'; +export * from './Chain'; +export * from './Challenges'; export * from './ChevronLeft'; export * from './ContentClassIcons'; export * from './Deployments'; @@ -54,7 +56,9 @@ export * from './Feedback'; export * from './HelpIcon'; export * from './Idea'; export * from './InfoOutlined'; +export * from './Kanvas'; export * from './Kubernetes'; +export * from './Learning'; export * from './LeftAngledArrow'; export * from './LeftArrow'; export * from './Menu'; @@ -79,6 +83,7 @@ export * from './Screenshot'; export * from './Search'; export * from './Settings'; export * from './Share'; +export * from './SocialMedial'; export * from './Star'; export * from './Success'; export * from './TerminalIcon'; From 4ff52d6fa41fb5cb40e6f75e64c2cb3ad514ae19 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Mon, 28 Oct 2024 19:19:01 +0530 Subject: [PATCH 053/103] chore: update import path and use sistent component Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/ActionButton.tsx | 3 +-- src/custom/CatalogDetail/ChallengesSection.tsx | 2 +- src/custom/CatalogDetail/CollapsibleSection.tsx | 2 +- src/custom/CatalogDetail/ContentClassInfo.tsx | 2 +- src/custom/CatalogDetail/LearningSection.tsx | 2 +- src/custom/CatalogDetail/OverviewSection.tsx | 2 +- src/custom/CatalogDetail/SocialSharePopper.tsx | 16 ++++------------ 7 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/custom/CatalogDetail/ActionButton.tsx b/src/custom/CatalogDetail/ActionButton.tsx index 808835277..e7a9806d7 100644 --- a/src/custom/CatalogDetail/ActionButton.tsx +++ b/src/custom/CatalogDetail/ActionButton.tsx @@ -1,11 +1,10 @@ import _ from 'lodash'; import React from 'react'; import { CircularProgress } from '../../base'; +import { CopyIcon, KanvasIcon } from '../../icons'; import Download from '../../icons/Download/Download'; import { charcoal } from '../../theme'; import { Pattern } from '../CustomCatalog/CustomCard'; -import CopyIcon from './Icons/CopyIcon'; -import KanvasIcon from './Icons/Kanvas'; import { downloadFilter, downloadYaml, slugify } from './helper'; import { ActionButton, LinkUrl, StyledActionWrapper } from './style'; import { RESOURCE_TYPES } from './types'; diff --git a/src/custom/CatalogDetail/ChallengesSection.tsx b/src/custom/CatalogDetail/ChallengesSection.tsx index 5110607b6..7bec37c9f 100644 --- a/src/custom/CatalogDetail/ChallengesSection.tsx +++ b/src/custom/CatalogDetail/ChallengesSection.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from 'react'; import { ListItemIcon } from '../../base'; +import { ChallengesIcon } from '../../icons'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; -import ChallengesIcon from './Icons/ChallengesIcon'; import { slugify } from './helper'; import { LabelDiv } from './style'; import { FilteredAcademyData } from './types'; diff --git a/src/custom/CatalogDetail/CollapsibleSection.tsx b/src/custom/CatalogDetail/CollapsibleSection.tsx index 24739f486..49c417947 100644 --- a/src/custom/CatalogDetail/CollapsibleSection.tsx +++ b/src/custom/CatalogDetail/CollapsibleSection.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import { Collapse, List, ListItemText } from '@mui/material'; +import { Collapse, List, ListItemText } from '../../base'; import { InfoTooltip } from '../CustomTooltip'; import { SideContainer, SideTitleButton } from './style'; diff --git a/src/custom/CatalogDetail/ContentClassInfo.tsx b/src/custom/CatalogDetail/ContentClassInfo.tsx index 5f2174993..5a9b871e2 100644 --- a/src/custom/CatalogDetail/ContentClassInfo.tsx +++ b/src/custom/CatalogDetail/ContentClassInfo.tsx @@ -1,5 +1,5 @@ -import { Box } from '@mui/material'; import React from 'react'; +import { Box } from '../../base'; import { InfoTooltip } from '../CustomTooltip'; import { ContentDetailsPoints, ContentDetailsText } from '../Typography'; import { CONTENT_CLASS, formatToTitleCase } from './helper'; diff --git a/src/custom/CatalogDetail/LearningSection.tsx b/src/custom/CatalogDetail/LearningSection.tsx index 2763b2c37..ffc003c72 100644 --- a/src/custom/CatalogDetail/LearningSection.tsx +++ b/src/custom/CatalogDetail/LearningSection.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useState } from 'react'; import { ListItemIcon } from '../../base'; +import { LearningIcon } from '../../icons'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; -import LearningIcon from './Icons/LearningIcon'; import { slugify } from './helper'; import { LabelDiv } from './style'; import { FilteredAcademyData } from './types'; diff --git a/src/custom/CatalogDetail/OverviewSection.tsx b/src/custom/CatalogDetail/OverviewSection.tsx index 756d2f7f2..a933226f7 100644 --- a/src/custom/CatalogDetail/OverviewSection.tsx +++ b/src/custom/CatalogDetail/OverviewSection.tsx @@ -1,5 +1,5 @@ -import { Grid } from '@mui/material'; import React from 'react'; +import { Grid } from '../../base'; import { Pattern } from '../CustomCatalog/CustomCard'; import ContentClassInfo from './ContentClassInfo'; import MetricsDisplay from './MetricsDisplay'; diff --git a/src/custom/CatalogDetail/SocialSharePopper.tsx b/src/custom/CatalogDetail/SocialSharePopper.tsx index ae3bf24be..ad6ae2cf3 100644 --- a/src/custom/CatalogDetail/SocialSharePopper.tsx +++ b/src/custom/CatalogDetail/SocialSharePopper.tsx @@ -1,18 +1,10 @@ -import { - ClickAwayListener, - Fade, - IconButton, - Paper, - Popper, - Tooltip, - useTheme -} from '@mui/material'; +import { Fade } from '@mui/material'; import React from 'react'; import { FacebookShareButton, LinkedinShareButton, TwitterShareButton } from 'react-share'; -import { ShareIcon } from '../../icons'; +import { ClickAwayListener, IconButton, Paper, Popper, Tooltip } from '../../base'; +import { ChainIcon, FacebookIcon, LinkedinIcon, ShareIcon, TwitterIcon } from '../../icons'; +import { useTheme } from '../../theme'; import { Pattern } from '../CustomCatalog/CustomCard'; -import ChainIcon from './Icons/ChainIcon'; -import { FacebookIcon, LinkedinIcon, TwitterIcon } from './Icons/SocialMediaIcon'; import { CopyShareIconWrapper, VisibilityChip } from './style'; interface SocialSharePopperProps { From ad776d945e53530b0967e62aa342cb3002e8991b Mon Sep 17 00:00:00 2001 From: aabidsofi19 Date: Tue, 29 Oct 2024 03:25:20 +0530 Subject: [PATCH 054/103] update secondary background token Signed-off-by: aabidsofi19 --- src/theme/palette.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/theme/palette.ts b/src/theme/palette.ts index 062246e03..cba6b52b4 100644 --- a/src/theme/palette.ts +++ b/src/theme/palette.ts @@ -307,7 +307,7 @@ export const lightModePalette: PaletteOptions = { export const darkModePalette: PaletteOptions = { background: { default: Colors.charcoal[10], - secondary: Colors.accentGrey[10], + secondary: Colors.accentGrey[20], tertiary: Colors.accentGrey[30], hover: Colors.charcoal[20], supplementary: Colors.accentGrey[40], From 98b56ac23cd1d88bc717a711c28b65d6b3544eaa Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Tue, 29 Oct 2024 06:34:59 +0530 Subject: [PATCH 055/103] fix(error): boundary Signed-off-by: Sudhanshu Dasgupta --- src/custom/ErrorBoundary/ErrorBoundary.tsx | 53 ++++++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/custom/ErrorBoundary/ErrorBoundary.tsx b/src/custom/ErrorBoundary/ErrorBoundary.tsx index 513453070..6858e896d 100644 --- a/src/custom/ErrorBoundary/ErrorBoundary.tsx +++ b/src/custom/ErrorBoundary/ErrorBoundary.tsx @@ -20,6 +20,8 @@ const StyledLink = styled(Link)(({ theme }) => ({ })); const CodeMessage = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', backgroundColor: theme.palette.background.code, color: theme.palette.text.tertiary, padding: '.85rem', @@ -30,14 +32,25 @@ const CodeMessage = styled('div')(({ theme }) => ({ interface FallbackComponentProps extends FallbackProps { resetErrorBoundary: () => void; children?: React.ReactNode; + pageUrl?: string; + timestamp?: string; } export function Fallback({ error, children }: FallbackComponentProps): JSX.Element { + const pageUrl = window.location.href; + const timestamp = new Date().toLocaleString(); return (

Uh-oh!😔 Please pardon the mesh.

- {(error as Error).message} + + Error: + {(error as Error).message} + +
+ URL: {pageUrl} +
+ Logged at: {timestamp}
We apologize for the inconvenience. The issue may be on our end. If troubleshooting doesn't @@ -56,18 +69,50 @@ export function Fallback({ error, children }: FallbackComponentProps): JSX.Eleme } const reportError = (error: Error, info: React.ErrorInfo): void => { + const pageUrl = window.location.href; + const timestamp = new Date().toLocaleString(); // This is where you'd send the error to Sentry, etc - console.log('Error Caught Inside Boundary --reportError', error, 'Info', info); + console.log( + 'Error Caught Inside Boundary --reportError', + error, + 'Info', + info, + 'Page URL:', + pageUrl, + 'Timestamp:', + timestamp + ); }; interface ErrorBoundaryProps { customFallback?: React.ComponentType; children: React.ReactNode; + onErrorCaught?: (error: string) => void; } -export const ErrorBoundary: React.FC = ({ customFallback, children }) => { +export const ErrorBoundary: React.FC = ({ + customFallback, + children, + onErrorCaught +}) => { + const pageUrl = window.location.href; + const timestamp = new Date().toLocaleString(); + + const handleError = (error: Error, info: React.ErrorInfo) => { + // Pass error message to onErrorCaught + onErrorCaught?.(error.message); + reportError(error, info); + }; + return ( - + + } + onError={handleError} + > {children} ); From 63b3a06875c88d13f46cda5f3df8fef0a743bcb2 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:51:17 +0530 Subject: [PATCH 056/103] chore: udpate font-family Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/CaveatsSection.tsx | 2 +- src/custom/CatalogDetail/ContentClassInfo.tsx | 45 ++++++++++++++----- src/custom/CatalogDetail/style.tsx | 11 +++-- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/custom/CatalogDetail/CaveatsSection.tsx b/src/custom/CatalogDetail/CaveatsSection.tsx index 71697a3d1..489be4133 100644 --- a/src/custom/CatalogDetail/CaveatsSection.tsx +++ b/src/custom/CatalogDetail/CaveatsSection.tsx @@ -15,7 +15,7 @@ const CaveatsSection: React.FC = ({ details }) => {

CAVEATS AND CONSIDERATIONS

{details?.catalog_data?.pattern_caveats ? ( - + diff --git a/src/custom/CatalogDetail/ContentClassInfo.tsx b/src/custom/CatalogDetail/ContentClassInfo.tsx index 5a9b871e2..effd24378 100644 --- a/src/custom/CatalogDetail/ContentClassInfo.tsx +++ b/src/custom/CatalogDetail/ContentClassInfo.tsx @@ -1,33 +1,55 @@ import React from 'react'; import { Box } from '../../base'; +import { CommunityClassIcon, OfficialClassIcon, VerificationClassIcon } from '../../icons'; +import { KEPPEL, useTheme } from '../../theme'; import { InfoTooltip } from '../CustomTooltip'; import { ContentDetailsPoints, ContentDetailsText } from '../Typography'; -import { CONTENT_CLASS, formatToTitleCase } from './helper'; -import { Class } from './types'; +import { formatToTitleCase } from './helper'; +import { Class, ContentClassType } from './types'; interface ContentClassInfoProps { contentClass: string; classes: Class[]; } -const ClassIcon: React.FC<{ className: string }> = ({ className }) => { - const Icon = CONTENT_CLASS[className]?.icon; - return Icon ? : null; -}; - const ContentClassInfo: React.FC = ({ contentClass, classes }) => { - const classDescription = (className: string): string | undefined => { + const _classDescription = (className: string): string | undefined => { const classObj = classes && classes.find((classObj) => classObj.class === className); return classObj?.description; }; + const theme = useTheme(); + + const CONTENT_CLASS: ContentClassType = { + community: { + icon: CommunityClassIcon, + color: theme.palette.icon.secondary + }, + official: { + icon: OfficialClassIcon, + color: '#EBC017' + }, + verified: { + icon: VerificationClassIcon, + color: theme.palette.primary.brand?.default || KEPPEL + } + } as const; + + const ClassIcon: React.FC<{ className: string }> = ({ className }) => { + const Icon = CONTENT_CLASS[className]?.icon; + const fill = CONTENT_CLASS[className]?.color; + return Icon ? : null; + }; + return (
- CLASS + + CLASS + @@ -35,7 +57,8 @@ const ContentClassInfo: React.FC = ({ contentClass, class style={{ display: 'flex', alignItems: 'center', - gap: '0.4rem' + gap: '0.4rem', + fontFamily: 'inherit' }} > diff --git a/src/custom/CatalogDetail/style.tsx b/src/custom/CatalogDetail/style.tsx index 19e91d765..f35b8140a 100644 --- a/src/custom/CatalogDetail/style.tsx +++ b/src/custom/CatalogDetail/style.tsx @@ -1,4 +1,4 @@ -import { ListItemButton, Paper, Typography } from '../../base'; +import { Link, ListItemButton, Paper, Typography } from '../../base'; import { styled } from '../../theme'; import { Theme } from './types'; @@ -40,6 +40,7 @@ export const ActionButton = styled('div')(({ disabled = false })); export const ContentDetailsText = styled(Typography)(({ theme }) => ({ + fontFamily: 'inherit', fontSize: '1rem', color: theme.palette.text.default, ['@media (min-width:1200px)']: { @@ -122,7 +123,8 @@ export const ContentDetailsPoints = styled(Typography)(() => ({ display: 'flex', flexDirection: 'row', alignItems: 'center', - gap: '1rem' + gap: '1rem', + fontFamily: 'inherit' })); export const MetricsSection = styled('div')(() => ({ @@ -194,7 +196,8 @@ export const DesignHeading = styled('h1')(({ theme }) => ({ export const ContentRow = styled('div')(() => ({ padding: '0.5rem 0', - overflowWrap: 'anywhere' + overflowWrap: 'anywhere', + fontFamily: 'inherit' })); export const ShowToggleBtn = styled('span')(({ theme }) => ({ @@ -245,7 +248,7 @@ export const VisibilityChip = styled('div')(() => ({ width: 'fit-content' })); -export const RedirectLink = styled('a')(({ theme }) => ({ +export const RedirectLink = styled(Link)(({ theme }) => ({ color: theme.palette.background.brand?.default, textDecoration: 'none', cursor: 'pointer' From 166bc6ec3eeca6343395cdd0b5f0d7e394c18fc8 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:52:00 +0530 Subject: [PATCH 057/103] feat: remove any and add types Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/helper.ts | 14 -------------- src/custom/CatalogDetail/types.ts | 9 +++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/custom/CatalogDetail/helper.ts b/src/custom/CatalogDetail/helper.ts index a46311c41..2d6601f77 100644 --- a/src/custom/CatalogDetail/helper.ts +++ b/src/custom/CatalogDetail/helper.ts @@ -1,6 +1,4 @@ import jsyaml from 'js-yaml'; -import { CommunityClassIcon, OfficialClassIcon, VerificationClassIcon } from '../../icons'; -import { ContentClassType } from './types'; export const downloadYaml = (filteredData: string, itemName: string): void => { const yamlData = Array.isArray(filteredData) @@ -49,18 +47,6 @@ export const downloadFilter = (id: string, name: string): void => { linkElement.remove(); }; -export const CONTENT_CLASS: ContentClassType = { - community: { - icon: CommunityClassIcon - }, - official: { - icon: OfficialClassIcon - }, - verified: { - icon: VerificationClassIcon - } -}; - export const formatToTitleCase = (value: string): string => { if (typeof value === 'string') { return value.substring(0, 1).toUpperCase().concat('', value.substring(1).toLowerCase()); diff --git a/src/custom/CatalogDetail/types.ts b/src/custom/CatalogDetail/types.ts index 40d8b2d38..1cd2adc78 100644 --- a/src/custom/CatalogDetail/types.ts +++ b/src/custom/CatalogDetail/types.ts @@ -40,11 +40,20 @@ export const RESOURCE_TYPES = { export type ContentClassType = { community: { icon: React.ComponentType; + color: string; }; official: { icon: React.ComponentType; + color: string; }; verified: { icon: React.ComponentType; + color: string; }; }; + +export type UserProfile = { + first_name: string; + last_name: string; + avatar_url: string; +}; From 88cf288b62121af0204d2f43a2c217cc116743c4 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:52:54 +0530 Subject: [PATCH 058/103] chore: some of the props and update funtions Signed-off-by: Amit Amrutiya --- .../CatalogDetail/ChallengesSection.tsx | 33 +++++++++-------- src/custom/CatalogDetail/LearningSection.tsx | 31 ++++++++-------- src/custom/CatalogDetail/OverviewSection.tsx | 26 ++++++-------- src/custom/CatalogDetail/RelatedDesigns.tsx | 28 ++++++++++++--- src/custom/CatalogDetail/RightPanel.tsx | 36 ++++++++++--------- 5 files changed, 89 insertions(+), 65 deletions(-) diff --git a/src/custom/CatalogDetail/ChallengesSection.tsx b/src/custom/CatalogDetail/ChallengesSection.tsx index 7bec37c9f..77028a2f0 100644 --- a/src/custom/CatalogDetail/ChallengesSection.tsx +++ b/src/custom/CatalogDetail/ChallengesSection.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { ListItemIcon } from '../../base'; +import { Link, ListItemIcon } from '../../base'; import { ChallengesIcon } from '../../icons'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; @@ -27,21 +27,24 @@ const ChallengesSection: React.FC = ({ filteredAcademyDa setAutoUpdate(false); }; - const navigateToChallenge = (item: string) => { - window.location.href = `/academy/challenges/${slugify('' + item)}`; - }; - const renderChallengeItem = (item: string, index: number) => ( - navigateToChallenge(item)}> - - - - {item} - + + + + + + {item} + + ); return ( diff --git a/src/custom/CatalogDetail/LearningSection.tsx b/src/custom/CatalogDetail/LearningSection.tsx index ffc003c72..d6e308075 100644 --- a/src/custom/CatalogDetail/LearningSection.tsx +++ b/src/custom/CatalogDetail/LearningSection.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { ListItemIcon } from '../../base'; +import { Link, ListItemIcon } from '../../base'; import { LearningIcon } from '../../icons'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; @@ -27,20 +27,23 @@ const LearningSection: React.FC = ({ filteredAcademyData } setAutoUpdate(false); }; - const navigateToLearningPath = (item: string): void => { - window.location.href = `/academy/learning-paths/${slugify('' + item)}`; - }; - const renderLearningItem = (item: string, index: number) => ( - navigateToLearningPath(item)}> - - - - {item} - + + + + + + {item} + + ); return ( diff --git a/src/custom/CatalogDetail/OverviewSection.tsx b/src/custom/CatalogDetail/OverviewSection.tsx index a933226f7..4d842bde7 100644 --- a/src/custom/CatalogDetail/OverviewSection.tsx +++ b/src/custom/CatalogDetail/OverviewSection.tsx @@ -13,34 +13,31 @@ interface OverviewSectionProps { details: Pattern; type: string; cardId: string; - handleClick: (event: React.MouseEvent) => void; title: string; - id: string; - anchorEl: HTMLElement | null; - handleClose: () => void; getUrl: (type: string, id: string) => string; showContentDetails: boolean; ViewsComponent?: React.ReactNode; showVersion: boolean; classes: Class[]; handleCopyUrl: (type: string, name: string, id: string) => void; + fontFamily?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + userProfile?: any; } const OverviewSection: React.FC = ({ details, type, cardId, - handleClick, title, - id, - anchorEl, - handleClose, getUrl, showContentDetails, ViewsComponent, showVersion, classes, - handleCopyUrl + handleCopyUrl, + fontFamily, + userProfile }) => { return ( @@ -49,7 +46,8 @@ const OverviewSection: React.FC = ({ display: 'flex', flexDirection: 'row', width: '100%', - flexWrap: 'wrap' + flexWrap: 'wrap', + fontFamily: fontFamily || 'inherit' }} > {details?.name} @@ -57,11 +55,7 @@ const OverviewSection: React.FC = ({ details={details} type={type} cardId={cardId} - handleClick={handleClick} title={title} - id={id} - anchorEl={anchorEl} - handleClose={handleClose} getUrl={getUrl} handleCopyUrl={handleCopyUrl} /> @@ -69,7 +63,7 @@ const OverviewSection: React.FC = ({ - + {details?.catalog_data?.content_class && ( = ({ /> )} - + diff --git a/src/custom/CatalogDetail/RelatedDesigns.tsx b/src/custom/CatalogDetail/RelatedDesigns.tsx index 5b000b86f..0d5ff5682 100644 --- a/src/custom/CatalogDetail/RelatedDesigns.tsx +++ b/src/custom/CatalogDetail/RelatedDesigns.tsx @@ -2,6 +2,7 @@ import { CatalogCardDesignLogo } from '../CustomCatalog'; import CustomCatalogCard, { Pattern } from '../CustomCatalog/CustomCard'; import { formatToTitleCase } from './helper'; import { AdditionalContainer, ContentHeading, DesignCardContainer } from './style'; +import { UserProfile } from './types'; export interface PatternsPerUser { patterns: Pattern[]; @@ -11,9 +12,17 @@ interface RelatedDesignsProps { details: Pattern; type: string; patternsPerUser: PatternsPerUser; + onSuggestedPatternClick: (pattern: Pattern) => void; + userProfile?: UserProfile; } -const RelatedDesigns: React.FC = ({ details, type, patternsPerUser }) => { +const RelatedDesigns: React.FC = ({ + details, + type, + patternsPerUser, + onSuggestedPatternClick, + userProfile +}) => { const filteredPatternsPerUser = patternsPerUser?.patterns?.filter( (pattern) => pattern.id !== details.id ); @@ -24,15 +33,26 @@ const RelatedDesigns: React.FC = ({ details, type, patterns

- Other published design by {formatToTitleCase(details.user.first_name)} + Other published design by + {formatToTitleCase(userProfile?.first_name ?? '')}

{filteredPatternsPerUser.map((pattern, index) => ( - + onSuggestedPatternClick(pattern)} + UserName={`${userProfile?.first_name ?? ''} ${userProfile?.last_name ?? ''}`} + avatarUrl={userProfile?.avatar_url} + basePath="/static/img/meshmodels" + subBasePath="color" + cardTechnologies={true} + > void; + cardId?: string; title: string; - id?: string; - anchorEl: HTMLElement | null; - handleClose: () => void; getUrl: (type: string, id: string) => string; showContentDetails: boolean; ViewsComponent?: React.ReactNode; @@ -21,19 +17,18 @@ interface RightPanelProps { showCaveats: boolean; classes: Class[]; patternsPerUser: PatternsPerUser; + onSuggestedPatternClick: (pattern: Pattern) => void; handleCopyUrl: (type: string, name: string, id: string) => void; fontFamily?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + useGetUserProfileByIdQuery: any; } const RightPanel: React.FC = ({ details, type, - cardId, - handleClick, + cardId = details.id, title, - id = '', - anchorEl, - handleClose, getUrl, showContentDetails, ViewsComponent, @@ -41,10 +36,15 @@ const RightPanel: React.FC = ({ showCaveats, classes, patternsPerUser, + onSuggestedPatternClick, handleCopyUrl, - fontFamily + fontFamily, + useGetUserProfileByIdQuery }) => { const cleanedType = type.replace('my-', '').replace(/s$/, ''); + const { data: userProfile } = useGetUserProfileByIdQuery({ + id: details.user_id + }); return (
@@ -52,20 +52,24 @@ const RightPanel: React.FC = ({ details={details} type={cleanedType} cardId={cardId} - handleClick={handleClick} title={title} - id={id} - anchorEl={anchorEl} - handleClose={handleClose} getUrl={getUrl} showContentDetails={showContentDetails} ViewsComponent={ViewsComponent} showVersion={showVersion} classes={classes} handleCopyUrl={handleCopyUrl} + fontFamily={fontFamily} + userProfile={userProfile} /> {showCaveats && } - +
); }; From fb42a654b756f141a18d17794ca00eff870f995e Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:53:20 +0530 Subject: [PATCH 059/103] style: update stying based on catalog modal Signed-off-by: Amit Amrutiya --- .../CatalogDetail/SocialSharePopper.tsx | 158 +++++++++++------- src/custom/CatalogDetail/UserInfo.tsx | 12 +- .../CustomCatalog/CatalogCardDesignLogo.tsx | 2 +- src/custom/CustomCatalog/CustomCard.tsx | 2 +- src/custom/Markdown/style.tsx | 3 +- 5 files changed, 107 insertions(+), 70 deletions(-) diff --git a/src/custom/CatalogDetail/SocialSharePopper.tsx b/src/custom/CatalogDetail/SocialSharePopper.tsx index ad6ae2cf3..3c24b32d8 100644 --- a/src/custom/CatalogDetail/SocialSharePopper.tsx +++ b/src/custom/CatalogDetail/SocialSharePopper.tsx @@ -1,21 +1,17 @@ -import { Fade } from '@mui/material'; -import React from 'react'; +import { Box, IconButton, Menu, MenuItem, Tooltip } from '@mui/material'; +import React, { useState } from 'react'; import { FacebookShareButton, LinkedinShareButton, TwitterShareButton } from 'react-share'; -import { ClickAwayListener, IconButton, Paper, Popper, Tooltip } from '../../base'; import { ChainIcon, FacebookIcon, LinkedinIcon, ShareIcon, TwitterIcon } from '../../icons'; import { useTheme } from '../../theme'; import { Pattern } from '../CustomCatalog/CustomCard'; +import { ErrorBoundary } from '../ErrorBoundary'; import { CopyShareIconWrapper, VisibilityChip } from './style'; interface SocialSharePopperProps { details: Pattern; type: string; cardId: string; - handleClick: (event: React.MouseEvent) => void; title: string; - id: string; - anchorEl: HTMLElement | null; - handleClose: () => void; getUrl: (type: string, id: string) => string; handleCopyUrl: (type: string, name: string, id: string) => void; } @@ -24,71 +20,105 @@ const SocialSharePopper: React.FC = ({ details, type, cardId, - handleClick, title, - id, - anchorEl, - handleClose, getUrl, handleCopyUrl }) => { - const cleanedType = type.replace('my-', '').replace(/s$/, ''); const theme = useTheme(); + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const cleanedType = type.replace('my-', '').replace(/s$/, ''); + return ( - - - {details?.visibility} - - {details?.visibility !== 'private' && ( - - handleCopyUrl(cleanedType, details?.name, details?.id)} - > - - - - )} - {(details?.visibility === 'published' || details?.visibility === 'public') && ( - <> - - - + + + + {details?.visibility} + + + {details?.visibility !== 'private' && ( + + handleCopyUrl(cleanedType, details?.name, details?.id)} + > + - - {({ TransitionProps }) => ( - - - - - - - - - - - - - - - - )} - - - )} - + )} + + {(details?.visibility === 'published' || details?.visibility === 'public') && ( + <> + + + + + + + + + + + + + + + + + + + + + + + )} + + ); }; diff --git a/src/custom/CatalogDetail/UserInfo.tsx b/src/custom/CatalogDetail/UserInfo.tsx index 6a2222491..602433086 100644 --- a/src/custom/CatalogDetail/UserInfo.tsx +++ b/src/custom/CatalogDetail/UserInfo.tsx @@ -2,21 +2,27 @@ import { Pattern } from '../CustomCatalog/CustomCard'; import { getVersion } from '../CustomCatalog/Helper'; import { formatDate } from './helper'; import { ContentDetailsPoints, ContentDetailsText, ContentRow, RedirectLink } from './style'; +import { UserProfile } from './types'; interface UserInfoProps { details: Pattern; showVersion?: boolean; + userProfile?: UserProfile; } -const UserInfo: React.FC = ({ details, showVersion = true }) => { +const UserInfo: React.FC = ({ details, showVersion = true, userProfile }) => { return ( <> CREATED BY - + - {details.user.first_name} {details?.user?.last_name} + {userProfile?.first_name} {userProfile?.last_name} diff --git a/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx b/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx index 3fb392471..30e3473f4 100644 --- a/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx +++ b/src/custom/CustomCatalog/CatalogCardDesignLogo.tsx @@ -43,7 +43,7 @@ const CatalogCardDesignLogo: React.FC = ({ return ( <> {imgURL && imgURL.length > 0 ? ( -
+
{!imgError ? ( <> = ({ {isDetailed && ( - + ({ export const StyledMarkdownP = styled('p')(({ theme }) => ({ color: theme.palette.text.default, marginBlock: '0px', - ...theme.typography.textB1Regular + ...theme.typography.textB1Regular, + fontFamily: 'inherit' })); export const StyledMarkdownTooltipP = styled('p')(({ theme }) => ({ From 904713fbe64cc2b3a994434b263ae85a3557b150 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 17:53:44 +0530 Subject: [PATCH 060/103] chore: add new copy icon Signed-off-by: Amit Amrutiya --- src/icons/Copy/CopyIcon.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/icons/Copy/CopyIcon.tsx b/src/icons/Copy/CopyIcon.tsx index e5edf8895..89424292c 100644 --- a/src/icons/Copy/CopyIcon.tsx +++ b/src/icons/Copy/CopyIcon.tsx @@ -10,16 +10,14 @@ interface CopyIconProps { const CopyIcon: React.FC = ({ width, height, fill = 'white', style }) => ( - - - + ); From d3090d7a0697526841d635b588f103ee0aac323d Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 29 Oct 2024 22:09:01 +0530 Subject: [PATCH 061/103] feat: update styling Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/LeftPanel.tsx | 11 ++-------- src/custom/CatalogDetail/RelatedDesigns.tsx | 3 +-- .../CatalogDetail/TechnologySection.tsx | 18 ++++++++--------- src/custom/CatalogDetail/style.tsx | 2 +- src/custom/CustomCatalog/CustomCard.tsx | 7 ++++++- src/custom/CustomCatalog/Helper.ts | 20 ++++++++++++------- src/custom/Typography/index.tsx | 2 +- 7 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/custom/CatalogDetail/LeftPanel.tsx b/src/custom/CatalogDetail/LeftPanel.tsx index af1ac1602..2bb7fbb37 100644 --- a/src/custom/CatalogDetail/LeftPanel.tsx +++ b/src/custom/CatalogDetail/LeftPanel.tsx @@ -15,9 +15,6 @@ interface LeftPanelProps { isCloneLoading: boolean; handleClone: (name: string, id: string) => void; showTechnologies?: boolean; - openTechnologies: boolean; - availableTechnologies: string[]; - handleOpenTechnologies: () => void; mode: string; filteredAcademyData: FilteredAcademyData; isCloneDisabled: boolean; @@ -34,9 +31,6 @@ const LeftPanel: React.FC = ({ isCloneLoading, handleClone, showTechnologies = true, - openTechnologies, - availableTechnologies, - handleOpenTechnologies, mode, filteredAcademyData, isCloneDisabled, @@ -45,6 +39,7 @@ const LeftPanel: React.FC = ({ fontFamily }) => { const theme = useTheme(); + return (
= ({ /> {showTechnologies && ( )} diff --git a/src/custom/CatalogDetail/RelatedDesigns.tsx b/src/custom/CatalogDetail/RelatedDesigns.tsx index 0d5ff5682..fdf8cedf3 100644 --- a/src/custom/CatalogDetail/RelatedDesigns.tsx +++ b/src/custom/CatalogDetail/RelatedDesigns.tsx @@ -33,8 +33,7 @@ const RelatedDesigns: React.FC = ({

- Other published design by - {formatToTitleCase(userProfile?.first_name ?? '')} + Other published design by {formatToTitleCase(userProfile?.first_name ?? '')}

diff --git a/src/custom/CatalogDetail/TechnologySection.tsx b/src/custom/CatalogDetail/TechnologySection.tsx index 2bddd5961..f4cda831f 100644 --- a/src/custom/CatalogDetail/TechnologySection.tsx +++ b/src/custom/CatalogDetail/TechnologySection.tsx @@ -1,24 +1,22 @@ -import React from 'react'; +import React, { useState } from 'react'; import { ListItemIcon } from '../../base'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; import { LabelDiv } from './style'; interface TechnologySectionProps { - availableTechnologies: string[]; - openTechnologies: boolean; - handleOpenTechnologies: () => void; + technologies: string[]; technologySVGPath: string; technologySVGSubpath: string; } const TechnologySection: React.FC = ({ - availableTechnologies, - openTechnologies, - handleOpenTechnologies, technologySVGPath, - technologySVGSubpath + technologySVGSubpath, + technologies }) => { + const [openTechnologies, setOpenTechnologies] = useState(true); + const theme = useTheme(); const renderTechnologyItem = (item: string, index: number) => { @@ -47,8 +45,8 @@ const TechnologySection: React.FC = ({ setOpenTechnologies((prev) => !prev)} + items={technologies} renderItem={renderTechnologyItem} emptyState={'No technologies assigned to this design'} tooltip={'Technologies used in this design'} diff --git a/src/custom/CatalogDetail/style.tsx b/src/custom/CatalogDetail/style.tsx index f35b8140a..5d6320255 100644 --- a/src/custom/CatalogDetail/style.tsx +++ b/src/custom/CatalogDetail/style.tsx @@ -44,7 +44,7 @@ export const ContentDetailsText = styled(Typography)(({ theme }) => ({ fontSize: '1rem', color: theme.palette.text.default, ['@media (min-width:1200px)']: { - fontSize: '1.3rem' + fontSize: '1' } })); diff --git a/src/custom/CustomCatalog/CustomCard.tsx b/src/custom/CustomCatalog/CustomCard.tsx index 7366d313b..0a1057550 100644 --- a/src/custom/CustomCatalog/CustomCard.tsx +++ b/src/custom/CustomCatalog/CustomCard.tsx @@ -138,7 +138,12 @@ const CustomCatalogCard: React.FC = ({ const version = getVersion(pattern); useEffect(() => { - handleImage(technologies, basePath, subBasePath, setAvailableTechnologies); + handleImage({ + technologies, + basePath, + subBasePath, + setAvailableTechnologies + }); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/custom/CustomCatalog/Helper.ts b/src/custom/CustomCatalog/Helper.ts index 10bbc4e31..02c5d0c54 100644 --- a/src/custom/CustomCatalog/Helper.ts +++ b/src/custom/CustomCatalog/Helper.ts @@ -42,16 +42,22 @@ const getValidSvgPaths = async ( return validSvgPaths; }; -export const handleImage = async ( - technologies: string[], - basePath: string = '', - subBasePath: string = '', - setAvailableTechnologies: (technologies: string[]) => void -) => { +interface HandleImageProps { + technologies: string[]; + basePath?: string; + subBasePath?: string; + setAvailableTechnologies: (technologies: string[]) => void; +} + +export const handleImage = async ({ + technologies, + basePath = '', + subBasePath = '', + setAvailableTechnologies +}: HandleImageProps) => { const validSvgPaths = await getValidSvgPaths(technologies, basePath, subBasePath); setAvailableTechnologies(validSvgPaths); }; - export const DEFAULT_DESIGN_VERSION = '0.0.0'; export const getVersion = (design: Pattern) => { diff --git a/src/custom/Typography/index.tsx b/src/custom/Typography/index.tsx index 2f03bb473..011112891 100644 --- a/src/custom/Typography/index.tsx +++ b/src/custom/Typography/index.tsx @@ -140,7 +140,7 @@ export const ContentDetailsPoints = styled(TextB3Regular)(({ theme }) => ({ export const ContentDetailsText = styled(TextB1Regular)(({ theme }) => ({ ...commonTypographyStyles(theme), ['@media (min-width:1200px)']: { - fontSize: '1.3rem' + fontSize: '1' } })); From 1c010efa294123d489ceefa41633aa82432a4bbd Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Wed, 30 Oct 2024 10:12:24 +0530 Subject: [PATCH 062/103] feat: show only valid svgs Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/RightPanel.tsx | 4 +-- .../CatalogDetail/TechnologySection.tsx | 28 ++++++++++++++++--- src/custom/CatalogDetail/UserInfo.tsx | 2 +- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/custom/CatalogDetail/RightPanel.tsx b/src/custom/CatalogDetail/RightPanel.tsx index 78e47625e..0c3c8a4d5 100644 --- a/src/custom/CatalogDetail/RightPanel.tsx +++ b/src/custom/CatalogDetail/RightPanel.tsx @@ -17,11 +17,11 @@ interface RightPanelProps { showCaveats: boolean; classes: Class[]; patternsPerUser: PatternsPerUser; - onSuggestedPatternClick: (pattern: Pattern) => void; handleCopyUrl: (type: string, name: string, id: string) => void; - fontFamily?: string; + onSuggestedPatternClick: (pattern: Pattern) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any useGetUserProfileByIdQuery: any; + fontFamily?: string; } const RightPanel: React.FC = ({ diff --git a/src/custom/CatalogDetail/TechnologySection.tsx b/src/custom/CatalogDetail/TechnologySection.tsx index f4cda831f..4018c6255 100644 --- a/src/custom/CatalogDetail/TechnologySection.tsx +++ b/src/custom/CatalogDetail/TechnologySection.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { ListItemIcon } from '../../base'; import { useTheme } from '../../theme'; import CollapsibleSection from './CollapsibleSection'; @@ -16,15 +16,35 @@ const TechnologySection: React.FC = ({ technologies }) => { const [openTechnologies, setOpenTechnologies] = useState(true); - + const [validTechnologies, setValidTechnologies] = useState([]); const theme = useTheme(); + useEffect(() => { + // Function to check if SVG exists + const validateTechnologies = async () => { + const validTechs = await Promise.all( + technologies.map(async (tech) => { + const svg_path = `/${technologySVGPath}/${tech.toLowerCase()}/${technologySVGSubpath}/${tech.toLowerCase()}-color.svg`; + try { + const response = await fetch(svg_path); + return response.ok ? tech : null; + } catch { + return null; + } + }) + ); + setValidTechnologies(validTechs.filter((tech): tech is string => tech !== null)); + }; + + validateTechnologies(); + }, [technologies, technologySVGPath, technologySVGSubpath]); + const renderTechnologyItem = (item: string, index: number) => { const svg_path = `${technologySVGPath}/${item.toLowerCase()}/${technologySVGSubpath}/${item.toLowerCase()}-color.svg`; return ( - technology icon + {`${item} {item} @@ -46,7 +66,7 @@ const TechnologySection: React.FC = ({ title="TECHNOLOGY" isOpen={openTechnologies} onToggle={() => setOpenTechnologies((prev) => !prev)} - items={technologies} + items={validTechnologies} renderItem={renderTechnologyItem} emptyState={'No technologies assigned to this design'} tooltip={'Technologies used in this design'} diff --git a/src/custom/CatalogDetail/UserInfo.tsx b/src/custom/CatalogDetail/UserInfo.tsx index 602433086..86029f960 100644 --- a/src/custom/CatalogDetail/UserInfo.tsx +++ b/src/custom/CatalogDetail/UserInfo.tsx @@ -21,7 +21,7 @@ const UserInfo: React.FC = ({ details, showVersion = true, userPr target="_blank" rel="noopener noreferrer" > - + {userProfile?.first_name} {userProfile?.last_name} From e96dfe0122d6796f1a09ccc56d6328599bb7d52f Mon Sep 17 00:00:00 2001 From: Antonette Caldwell <134739862+nebula-aac@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:38:09 +0000 Subject: [PATCH 063/103] ci: remove storybook workflow Signed-off-by: Antonette Caldwell <134739862+nebula-aac@users.noreply.github.com> --- .github/workflows/storybook-deploy.yml | 40 -------------------------- 1 file changed, 40 deletions(-) delete mode 100644 .github/workflows/storybook-deploy.yml diff --git a/.github/workflows/storybook-deploy.yml b/.github/workflows/storybook-deploy.yml deleted file mode 100644 index 0e3c5c523..000000000 --- a/.github/workflows/storybook-deploy.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Deploy Storybook - -on: - push: - branches: - - "*" - pull_request: - branches: - - "*" - -jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16, 18, 20] - - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Set up Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: npm install - - - name: Build Storybook - run: | - cd apps/design-system - npm install - npm build-storybook - - - name: Deploy Storybook - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./storybook-static From fee2542123bcd5c105717eee00d714a354d7b57e Mon Sep 17 00:00:00 2001 From: Aditya Mohan Date: Wed, 30 Oct 2024 12:44:40 -0400 Subject: [PATCH 064/103] feat: update WorkspaceIcon to support opacity and fill colors Signed-off-by: Aditya Mohan --- src/icons/Workspace/WorkspaceIcon.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/icons/Workspace/WorkspaceIcon.tsx b/src/icons/Workspace/WorkspaceIcon.tsx index 8b6966356..9695cb33d 100644 --- a/src/icons/Workspace/WorkspaceIcon.tsx +++ b/src/icons/Workspace/WorkspaceIcon.tsx @@ -1,11 +1,13 @@ import { DEFAULT_HEIGHT, DEFAULT_WIDTH, KEPPEL_GREEN_FILL } from '../../constants/constants'; -import { IconProps } from '../types'; +import { CustomIconProps } from '../types'; export const WorkspaceIcon = ({ width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT, + secondaryFill = KEPPEL_GREEN_FILL, + opacity = 0.8, ...props -}: IconProps): JSX.Element => { +}: CustomIconProps): JSX.Element => { return ( ); From 240567aa5985c57531ae2862648435831ea5d4b2 Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Thu, 31 Oct 2024 19:26:15 +0530 Subject: [PATCH 065/103] feat: pass props for visible of open in playground button Signed-off-by: Amit Amrutiya --- src/custom/CatalogDetail/ActionButton.tsx | 48 +++++++++++---------- src/custom/CatalogDetail/LeftPanel.tsx | 5 ++- src/custom/CatalogDetail/RelatedDesigns.tsx | 10 +++-- src/custom/CatalogDetail/RightPanel.tsx | 8 +++- src/custom/CatalogDetail/UserInfo.tsx | 2 +- 5 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/custom/CatalogDetail/ActionButton.tsx b/src/custom/CatalogDetail/ActionButton.tsx index e7a9806d7..ed7ce790f 100644 --- a/src/custom/CatalogDetail/ActionButton.tsx +++ b/src/custom/CatalogDetail/ActionButton.tsx @@ -18,6 +18,7 @@ interface ActionButtonsProps { handleClone: (name: string, id: string) => void; mode: string; isCloneDisabled: boolean; + showOpenPlaygroundButton: boolean; } const ActionButtons: React.FC = ({ @@ -28,7 +29,8 @@ const ActionButtons: React.FC = ({ isCloneLoading, handleClone, mode, - isCloneDisabled + isCloneDisabled, + showOpenPlaygroundButton }) => { const cleanedType = type.replace('my-', '').replace(/s$/, ''); const resourcePlaygroundType = Object.values({ @@ -51,7 +53,7 @@ const ActionButtons: React.FC = ({ = ({ )}
)} - - - - Open in Playground - - + + + Open in Playground + + + )} ); }; diff --git a/src/custom/CatalogDetail/LeftPanel.tsx b/src/custom/CatalogDetail/LeftPanel.tsx index 2bb7fbb37..30d006072 100644 --- a/src/custom/CatalogDetail/LeftPanel.tsx +++ b/src/custom/CatalogDetail/LeftPanel.tsx @@ -21,6 +21,7 @@ interface LeftPanelProps { technologySVGPath: string; technologySVGSubpath: string; fontFamily?: string; + showOpenPlaygroundButton?: boolean; } const LeftPanel: React.FC = ({ @@ -36,7 +37,8 @@ const LeftPanel: React.FC = ({ isCloneDisabled, technologySVGPath, technologySVGSubpath, - fontFamily + fontFamily, + showOpenPlaygroundButton = true }) => { const theme = useTheme(); @@ -77,6 +79,7 @@ const LeftPanel: React.FC = ({ handleClone={handleClone} mode={mode} isCloneDisabled={isCloneDisabled} + showOpenPlaygroundButton={showOpenPlaygroundButton} /> {showTechnologies && ( void; userProfile?: UserProfile; + technologySVGPath: string; + technologySVGSubpath: string; } const RelatedDesigns: React.FC = ({ @@ -21,7 +23,9 @@ const RelatedDesigns: React.FC = ({ type, patternsPerUser, onSuggestedPatternClick, - userProfile + userProfile, + technologySVGPath, + technologySVGSubpath }) => { const filteredPatternsPerUser = patternsPerUser?.patterns?.filter( (pattern) => pattern.id !== details.id @@ -45,8 +49,8 @@ const RelatedDesigns: React.FC = ({ onCardClick={() => onSuggestedPatternClick(pattern)} UserName={`${userProfile?.first_name ?? ''} ${userProfile?.last_name ?? ''}`} avatarUrl={userProfile?.avatar_url} - basePath="/static/img/meshmodels" - subBasePath="color" + basePath={technologySVGPath} + subBasePath={technologySVGSubpath} cardTechnologies={true} > = ({ @@ -39,7 +41,9 @@ const RightPanel: React.FC = ({ onSuggestedPatternClick, handleCopyUrl, fontFamily, - useGetUserProfileByIdQuery + useGetUserProfileByIdQuery, + technologySVGPath, + technologySVGSubpath }) => { const cleanedType = type.replace('my-', '').replace(/s$/, ''); const { data: userProfile } = useGetUserProfileByIdQuery({ @@ -69,6 +73,8 @@ const RightPanel: React.FC = ({ patternsPerUser={patternsPerUser} onSuggestedPatternClick={onSuggestedPatternClick} userProfile={userProfile} + technologySVGPath={technologySVGPath} + technologySVGSubpath={technologySVGSubpath} />
); diff --git a/src/custom/CatalogDetail/UserInfo.tsx b/src/custom/CatalogDetail/UserInfo.tsx index 86029f960..602433086 100644 --- a/src/custom/CatalogDetail/UserInfo.tsx +++ b/src/custom/CatalogDetail/UserInfo.tsx @@ -21,7 +21,7 @@ const UserInfo: React.FC = ({ details, showVersion = true, userPr target="_blank" rel="noopener noreferrer" > - + {userProfile?.first_name} {userProfile?.last_name} From 6a810d12977de2f7aa9073ef97c77dd8dcefbcbc Mon Sep 17 00:00:00 2001 From: Lee Calcote Date: Thu, 31 Oct 2024 10:28:49 -0500 Subject: [PATCH 066/103] [CI] Fix "author" parameter format in create-pull-request workflow Signed-off-by: Lee Calcote --- .github/workflows/bump-meshery-version.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/bump-meshery-version.yml b/.github/workflows/bump-meshery-version.yml index 99e5c52dd..ab48cd36e 100644 --- a/.github/workflows/bump-meshery-version.yml +++ b/.github/workflows/bump-meshery-version.yml @@ -29,7 +29,7 @@ jobs: token: ${{ secrets.RELEASEDRAFTER_PAT }} commit-message: Bump sistent ${{ github.event.release.tag_name }} dependencies committer: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> - author: "l5io" + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> signoff: true branch: bump-sistent-bot delete-branch: true @@ -67,7 +67,7 @@ jobs: token: ${{ secrets.RELEASEDRAFTER_PAT }} commit-message: Bump sistent ${{ github.event.release.tag_name }} dependencies committer: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> - author: "l5io" + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> signoff: true branch: bump-sistent-bot delete-branch: true @@ -105,7 +105,7 @@ jobs: token: ${{ secrets.RELEASEDRAFTER_PAT }} commit-message: Bump sistent ${{ github.event.release.tag_name }} dependencies committer: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> - author: "l5io" + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> signoff: true branch: bump-sistent-bot delete-branch: true @@ -118,4 +118,4 @@ jobs: _This pull request has been auto-generated by [l5io](http://github.com/l5io)_ assignees: l5io - draft: false \ No newline at end of file + draft: false From 48885ccc75a6d88dd8078db4dbaf98142e45a630 Mon Sep 17 00:00:00 2001 From: Yash sharma <71271069+Yashsharma1911@users.noreply.github.com> Date: Fri, 1 Nov 2024 17:14:01 +0000 Subject: [PATCH 067/103] fix: fix prettier issue Signed-off-by: Yash sharma <71271069+Yashsharma1911@users.noreply.github.com> --- src/schemas/publishCatalogItem/schema.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/schemas/publishCatalogItem/schema.tsx b/src/schemas/publishCatalogItem/schema.tsx index 6c9b5ea3a..06295112f 100644 --- a/src/schemas/publishCatalogItem/schema.tsx +++ b/src/schemas/publishCatalogItem/schema.tsx @@ -25,7 +25,7 @@ const publishCatalogItemSchema = { 'Specific stipulations to consider and known behaviors to be aware of when using this design.', format: 'textarea', 'x-rjsf-grid-area': 12, - "x-encode-in-uri": true + 'x-encode-in-uri': true }, pattern_info: { type: 'string', @@ -33,7 +33,7 @@ const publishCatalogItemSchema = { description: 'Purpose of the design along with its intended and unintended uses.', format: 'textarea', 'x-rjsf-grid-area': 12, - "x-encode-in-uri": true + 'x-encode-in-uri': true }, type: { type: 'string', From d5c394e5839e2a9b6a0f80b00055849b8a20605b Mon Sep 17 00:00:00 2001 From: Yash sharma <71271069+Yashsharma1911@users.noreply.github.com> Date: Fri, 1 Nov 2024 18:34:48 +0000 Subject: [PATCH 068/103] fix: reorder the fields Signed-off-by: Yash sharma <71271069+Yashsharma1911@users.noreply.github.com> --- src/schemas/publishCatalogItem/uiSchema.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schemas/publishCatalogItem/uiSchema.tsx b/src/schemas/publishCatalogItem/uiSchema.tsx index 646098bdf..2e2e9f695 100644 --- a/src/schemas/publishCatalogItem/uiSchema.tsx +++ b/src/schemas/publishCatalogItem/uiSchema.tsx @@ -1,5 +1,5 @@ const publishCatalogItemUiSchema = { - 'ui:order': ['type', 'compatibility', 'pattern_caveats', 'pattern_info'] + 'ui:order': ['type', 'compatibility', 'pattern_info', 'pattern_caveats'] }; export default publishCatalogItemUiSchema; From cd01819c31d7ed00bdb6966f442015309a15aca2 Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Sat, 2 Nov 2024 16:52:04 +0530 Subject: [PATCH 069/103] feat(catalog): unpublish action Signed-off-by: Sudhanshu Dasgupta --- src/custom/CatalogDetail/ActionButton.tsx | 29 ++++++++++++++++++++--- src/custom/CatalogDetail/style.tsx | 16 +++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/custom/CatalogDetail/ActionButton.tsx b/src/custom/CatalogDetail/ActionButton.tsx index ed7ce790f..8d000e1d2 100644 --- a/src/custom/CatalogDetail/ActionButton.tsx +++ b/src/custom/CatalogDetail/ActionButton.tsx @@ -1,12 +1,12 @@ import _ from 'lodash'; import React from 'react'; import { CircularProgress } from '../../base'; -import { CopyIcon, KanvasIcon } from '../../icons'; +import { CopyIcon, KanvasIcon, PublishIcon } from '../../icons'; import Download from '../../icons/Download/Download'; import { charcoal } from '../../theme'; import { Pattern } from '../CustomCatalog/CustomCard'; import { downloadFilter, downloadYaml, slugify } from './helper'; -import { ActionButton, LinkUrl, StyledActionWrapper } from './style'; +import { ActionButton, LinkUrl, StyledActionWrapper, UnpublishAction } from './style'; import { RESOURCE_TYPES } from './types'; interface ActionButtonsProps { @@ -17,8 +17,10 @@ interface ActionButtonsProps { isCloneLoading: boolean; handleClone: (name: string, id: string) => void; mode: string; + handleUnpublish?: () => void; isCloneDisabled: boolean; showOpenPlaygroundButton: boolean; + showUnpublishAction: boolean; } const ActionButtons: React.FC = ({ @@ -30,7 +32,9 @@ const ActionButtons: React.FC = ({ handleClone, mode, isCloneDisabled, - showOpenPlaygroundButton + showOpenPlaygroundButton, + showUnpublishAction, + handleUnpublish }) => { const cleanedType = type.replace('my-', '').replace(/s$/, ''); const resourcePlaygroundType = Object.values({ @@ -112,6 +116,25 @@ const ActionButtons: React.FC = ({ )} + {showUnpublishAction && ( + + + + Unpublish + + + )} ); }; diff --git a/src/custom/CatalogDetail/style.tsx b/src/custom/CatalogDetail/style.tsx index 5d6320255..818674924 100644 --- a/src/custom/CatalogDetail/style.tsx +++ b/src/custom/CatalogDetail/style.tsx @@ -39,6 +39,22 @@ export const ActionButton = styled('div')(({ disabled = false flex: '1' })); +export const UnpublishAction = styled('div')(({ disabled = false, theme }) => ({ + cursor: disabled ? 'not-allowed' : 'pointer', + opacity: disabled ? '0.5' : '1', + textAlign: 'center', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + borderRadius: '0.5rem', + backgroundColor: 'transparent', + border: theme.palette.border.default, + padding: '0.5rem', + color: theme.palette.text.default, + gap: '0.625rem', + flex: '1' +})); + export const ContentDetailsText = styled(Typography)(({ theme }) => ({ fontFamily: 'inherit', fontSize: '1rem', From b30a3245e9a3b362bf54b515abe3b7a4cff8cdc5 Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Mon, 4 Nov 2024 07:20:48 +0530 Subject: [PATCH 070/103] fix(check): add missing props Signed-off-by: Sudhanshu Dasgupta --- src/custom/CatalogDetail/ActionButton.tsx | 26 +++++++++-------------- src/custom/CatalogDetail/LeftPanel.tsx | 6 ++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/custom/CatalogDetail/ActionButton.tsx b/src/custom/CatalogDetail/ActionButton.tsx index 8d000e1d2..1cd4ff662 100644 --- a/src/custom/CatalogDetail/ActionButton.tsx +++ b/src/custom/CatalogDetail/ActionButton.tsx @@ -17,7 +17,7 @@ interface ActionButtonsProps { isCloneLoading: boolean; handleClone: (name: string, id: string) => void; mode: string; - handleUnpublish?: () => void; + handleUnpublish: () => void; isCloneDisabled: boolean; showOpenPlaygroundButton: boolean; showUnpublishAction: boolean; @@ -117,23 +117,17 @@ const ActionButtons: React.FC = ({ )} {showUnpublishAction && ( - - - - Unpublish - - + + Unpublish + )} ); diff --git a/src/custom/CatalogDetail/LeftPanel.tsx b/src/custom/CatalogDetail/LeftPanel.tsx index 30d006072..70ed50d20 100644 --- a/src/custom/CatalogDetail/LeftPanel.tsx +++ b/src/custom/CatalogDetail/LeftPanel.tsx @@ -22,6 +22,8 @@ interface LeftPanelProps { technologySVGSubpath: string; fontFamily?: string; showOpenPlaygroundButton?: boolean; + handleUnpublish: () => void; + showUnpublishAction?: boolean; } const LeftPanel: React.FC = ({ @@ -31,6 +33,7 @@ const LeftPanel: React.FC = ({ actionItems = true, isCloneLoading, handleClone, + handleUnpublish, showTechnologies = true, mode, filteredAcademyData, @@ -38,6 +41,7 @@ const LeftPanel: React.FC = ({ technologySVGPath, technologySVGSubpath, fontFamily, + showUnpublishAction = false, showOpenPlaygroundButton = true }) => { const theme = useTheme(); @@ -77,6 +81,8 @@ const LeftPanel: React.FC = ({ cardId={cardId} isCloneLoading={isCloneLoading} handleClone={handleClone} + showUnpublishAction={showUnpublishAction} + handleUnpublish={handleUnpublish} mode={mode} isCloneDisabled={isCloneDisabled} showOpenPlaygroundButton={showOpenPlaygroundButton} From 1f4fce9bbb79b514f3394daff2c11adf0f5dcc9b Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Mon, 4 Nov 2024 10:25:22 +0530 Subject: [PATCH 071/103] fix(style): add border Signed-off-by: Sudhanshu Dasgupta --- src/custom/CatalogDetail/style.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/custom/CatalogDetail/style.tsx b/src/custom/CatalogDetail/style.tsx index 818674924..672137aaa 100644 --- a/src/custom/CatalogDetail/style.tsx +++ b/src/custom/CatalogDetail/style.tsx @@ -48,7 +48,7 @@ export const UnpublishAction = styled('div')(({ disabled = fa alignItems: 'center', borderRadius: '0.5rem', backgroundColor: 'transparent', - border: theme.palette.border.default, + border: `1px solid ${theme.palette.border.normal}`, padding: '0.5rem', color: theme.palette.text.default, gap: '0.625rem', From a07edba3ac757853603a3217e4436fbc82efc656 Mon Sep 17 00:00:00 2001 From: Sudhanshu Dasgupta Date: Mon, 4 Nov 2024 16:56:16 +0530 Subject: [PATCH 072/103] fix(error): rm unwanted and add version Signed-off-by: Sudhanshu Dasgupta --- src/custom/ErrorBoundary/ErrorBoundary.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/custom/ErrorBoundary/ErrorBoundary.tsx b/src/custom/ErrorBoundary/ErrorBoundary.tsx index 6858e896d..a47c3e8cb 100644 --- a/src/custom/ErrorBoundary/ErrorBoundary.tsx +++ b/src/custom/ErrorBoundary/ErrorBoundary.tsx @@ -34,11 +34,16 @@ interface FallbackComponentProps extends FallbackProps { children?: React.ReactNode; pageUrl?: string; timestamp?: string; + showPackageInfo?: boolean; + version?: string; } -export function Fallback({ error, children }: FallbackComponentProps): JSX.Element { - const pageUrl = window.location.href; - const timestamp = new Date().toLocaleString(); +export function Fallback({ + error, + children, + showPackageInfo, + version +}: FallbackComponentProps): JSX.Element { return (

Uh-oh!😔 Please pardon the mesh.

@@ -48,9 +53,11 @@ export function Fallback({ error, children }: FallbackComponentProps): JSX.Eleme {(error as Error).message}
- URL: {pageUrl} -
- Logged at: {timestamp} + {showPackageInfo && ( + <> + Version: {version} + + )} We apologize for the inconvenience. The issue may be on our end. If troubleshooting doesn't From 19f56f194f869a4a02e2f6943ef5a794e666d52c Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 5 Nov 2024 12:38:51 +0530 Subject: [PATCH 073/103] feat: create user serach field component Signed-off-by: Amit Amrutiya --- .../UserSearchField/UserSearchFieldInput.tsx | 325 ++++++++++++++++++ src/custom/UserSearchField/index.ts | 3 + 2 files changed, 328 insertions(+) create mode 100644 src/custom/UserSearchField/UserSearchFieldInput.tsx create mode 100644 src/custom/UserSearchField/index.ts diff --git a/src/custom/UserSearchField/UserSearchFieldInput.tsx b/src/custom/UserSearchField/UserSearchFieldInput.tsx new file mode 100644 index 000000000..cbced2b89 --- /dev/null +++ b/src/custom/UserSearchField/UserSearchFieldInput.tsx @@ -0,0 +1,325 @@ +import { Autocomplete, AutocompleteRenderInputParams } from '@mui/material'; +import { debounce } from 'lodash'; +import React, { SyntheticEvent, useMemo, useState } from 'react'; +import { + Avatar, + Box, + Checkbox, + Chip, + CircularProgress, + FormControlLabel, + FormGroup, + Grid, + TextField, + Tooltip, + Typography +} from '../../base'; +import { iconSmall } from '../../constants/iconsSizes'; +import { CloseIcon, PersonIcon } from '../../icons'; + +interface User { + user_id: string; + first_name: string; + last_name: string; + email: string; + avatar_url?: string; + deleted_at?: { Valid: boolean }; + deleted?: boolean; +} + +interface UserSearchFieldProps { + usersData: User[]; + setUsersData: React.Dispatch>; + label?: string; + setDisableSave?: (disable: boolean) => void; + handleNotifyPref?: () => void; + notifyUpdate?: boolean; + isCreate?: boolean; + searchType?: string; + disabled?: boolean; + org_id?: string; + currentUserData: User; + searchedUsers: User[]; + isUserSearchLoading: boolean; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + fetchSearchedUsers: any; + usersSearch: string; + setUsersSearch: React.Dispatch>; +} + +const UserSearchField: React.FC = ({ + usersData, + setUsersData, + label, + setDisableSave, + handleNotifyPref, + notifyUpdate, + isCreate, + searchType, + disabled = false, + currentUserData, + searchedUsers, + isUserSearchLoading, + fetchSearchedUsers, + usersSearch, + setUsersSearch +}) => { + const [error, setError] = useState(''); + const [inputValue, setInputValue] = useState(''); + const [open, setOpen] = useState(false); + const [showAllUsers, setShowAllUsers] = useState(false); + const [hasInitialFocus, setHasInitialFocus] = useState(true); + // Combine current user with search results + const displayOptions = useMemo(() => { + if (!searchedUsers) return []; + + // Filter out current user from search results + const filteredResults = searchedUsers.filter( + (user: User) => user.user_id !== currentUserData?.user_id + ); + // Show only current user on initial focus + if (hasInitialFocus && !usersSearch && currentUserData) { + return [currentUserData]; + } + // If there's no search query, add current user at the top + if (!usersSearch && currentUserData) { + return [currentUserData, ...filteredResults]; + } + return filteredResults; + }, [searchedUsers, currentUserData, usersSearch, hasInitialFocus]); + + const fetchSuggestions = debounce((value: string) => { + setHasInitialFocus(false); + setUsersSearch(value); + fetchSearchedUsers(); + }, 300); + + const handleDelete = (email: string) => { + const usersDataSet = new Set(usersData); + usersDataSet.forEach((avatarObj: User) => { + if (avatarObj.email === email) { + usersDataSet.delete(avatarObj); + } + }); + setUsersData(Array.from(usersDataSet)); + if (setDisableSave) { + setDisableSave(false); + } + }; + + const handleAdd = (event: SyntheticEvent, value: User) => { + if (!value) return; + + setUsersData((prevData: User[]) => { + prevData = prevData || []; + const isDuplicate = prevData?.some((user) => user.user_id === value.user_id); + const isDeleted = value.deleted_at?.Valid === true; + + if (isDuplicate || isDeleted) { + setError(isDuplicate ? 'User already selected' : 'User does not exist'); + return prevData; + } + + setError(''); + return [...prevData, value]; + }); + + // Reset UI state after updating users + setInputValue(''); + setOpen(false); + setUsersSearch(''); + + if (setDisableSave) { + setDisableSave(false); + } + }; + + const handleInputChange = (event: SyntheticEvent, value: string) => { + if (value === '') { + setOpen(true); + setUsersSearch(''); + setHasInitialFocus(true); + } else { + const encodedValue = encodeURIComponent(value); + fetchSuggestions(encodedValue); + setError(''); + setOpen(true); + } + }; + + const handleFocus = () => { + setOpen(true); + if (!usersSearch) { + setHasInitialFocus(true); + } + }; + + const handleBlur = () => { + setOpen(false); + setUsersSearch(''); + // Reset initial focus state when field is blurred + setHasInitialFocus(true); + }; + + return ( + <> + x} + options={displayOptions} + disableClearable + includeInputInList + filterSelectedOptions + disableListWrap + disabled={disabled} + open={open} + loading={isUserSearchLoading} + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + value={inputValue} + getOptionLabel={() => ''} + noOptionsText={isUserSearchLoading ? 'Loading...' : 'No users found'} + onChange={handleAdd} + onInputChange={handleInputChange} + isOptionEqualToValue={(option: User, value: User) => option.user_id === value.user_id} + clearOnBlur + onFocus={handleFocus} + onBlur={handleBlur} + renderInput={(params: AutocompleteRenderInputParams) => ( + + {isUserSearchLoading ? : null} + + ) + }} + /> + )} + renderOption={(props, option: User) => ( +
  • + + + + + {option.avatar_url ? '' : } + + + + + {option.deleted ? ( + + {option.email} (deleted) + + ) : ( + <> + + {option.first_name} {option.last_name} + + + {option.email} + + + )} + + +
  • + )} + /> + + {/* TODO: Remove dependancy of this checkbox in this component, it should be defined on parent component. We should keep this component reusable and should not add checkbox specific to some component */} + {!isCreate && ( + +
    + + } + label={`Notify ${searchType} of membership change`} + /> +
    +
    + )} + 0 ? '0.5rem' : '' + }} + > + {!showAllUsers && usersData?.length > 0 && ( + + {usersData[usersData.length - 1]?.avatar_url + ? '' + : usersData[usersData.length - 1]?.first_name?.charAt(0)} + + } + label={usersData[usersData.length - 1]?.email} + size="small" + onDelete={() => handleDelete(usersData[usersData.length - 1]?.email)} + deleteIcon={ + + + + } + /> + )} + {showAllUsers && + usersData?.map((avatarObj: User) => ( + + {avatarObj.avatar_url ? '' : avatarObj.first_name?.charAt(0)} + + } + label={avatarObj.email} + size="small" + onDelete={() => handleDelete(avatarObj.email)} + deleteIcon={ + + + + } + /> + ))} + {usersData?.length > 1 && ( + setShowAllUsers(!showAllUsers)} + sx={{ + cursor: 'pointer', + color: 'white', + fontWeight: '600', + '&:hover': { + color: 'black' + } + }} + > + {showAllUsers ? '(hide)' : `(+${usersData.length - 1})`} + + )} + + + ); +}; + +export default UserSearchField; diff --git a/src/custom/UserSearchField/index.ts b/src/custom/UserSearchField/index.ts new file mode 100644 index 000000000..7cf9a5ea5 --- /dev/null +++ b/src/custom/UserSearchField/index.ts @@ -0,0 +1,3 @@ +import UserSearchField from './UserSearchFieldInput'; + +export { UserSearchField }; From 42783be2869ba86d9650637faa2580f6f20d0bdb Mon Sep 17 00:00:00 2001 From: Amit Amrutiya Date: Tue, 5 Nov 2024 12:39:22 +0530 Subject: [PATCH 074/103] feat: add InputFieldSearch component for user search functionality Signed-off-by: Amit Amrutiya --- .../InputSearchField/InputSearchField.tsx | 189 ++++++++++++++++++ src/custom/InputSearchField/index.ts | 3 + src/custom/index.tsx | 2 + 3 files changed, 194 insertions(+) create mode 100644 src/custom/InputSearchField/InputSearchField.tsx create mode 100644 src/custom/InputSearchField/index.ts diff --git a/src/custom/InputSearchField/InputSearchField.tsx b/src/custom/InputSearchField/InputSearchField.tsx new file mode 100644 index 000000000..80d1b5103 --- /dev/null +++ b/src/custom/InputSearchField/InputSearchField.tsx @@ -0,0 +1,189 @@ +import { Autocomplete } from '@mui/material'; +import React, { useEffect, useRef, useState } from 'react'; +import { Box, Chip, Grid, TextField, Tooltip, Typography } from '../../base'; +import { iconLarge, iconSmall } from '../../constants/iconsSizes'; +import { CloseIcon, OrgIcon } from '../../icons'; + +interface Option { + id: string; + name: string; +} + +interface InputFieldSearchProps { + defaultData?: Option[]; + label?: string; + fetchSuggestions: (value: string) => void; + setFilterData: (data: Option[]) => void; + isLoading: boolean; + type: string; + disabled?: boolean; +} + +const InputFieldSearch: React.FC = ({ + defaultData = [], + label, + fetchSuggestions, + setFilterData, + isLoading, + type, + disabled +}) => { + const [data, setData] = useState([]); + const [error, setError] = useState(''); + const [inputValue, setInputValue] = useState(''); + const [open, setOpen] = useState(false); + const [showAllUsers, setShowAllUsers] = useState(false); + const [selectedOption, setSelectedOption] = useState