-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MNES-1063: Refactoring of AASListView component (#17)
Main refactored elements: - AASListView component was split into smaller components - AasListComparisonHeader - Header on the top of the page to visualize selected AAS from the list - SelectProductType - Dropdown menu to select filter product class - AasList - Aas List - AasListTableRow - Entry row for one AAS in the table - ImageWithFallback - component ensures that a fallback icon (ShellIcon) is displayed if the image specified by src fails to load. Small refactoring to fix build.
- Loading branch information
1 parent
73966fd
commit 6d453b2
Showing
21 changed files
with
632 additions
and
497 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { | ||
Table, | ||
TableBody, | ||
TableCell, | ||
TableContainer, | ||
TableHead, | ||
TableRow, | ||
Tooltip, | ||
Typography, | ||
useTheme, | ||
} from '@mui/material'; | ||
import { FormattedMessage } from 'react-intl'; | ||
import { messages } from 'lib/i18n/localization'; | ||
import CompareArrowsIcon from '@mui/icons-material/CompareArrows'; | ||
import { AasListEntry } from 'lib/api/generated-api/clients.g'; | ||
import { AasListTableRow } from 'app/[locale]/list/_components/AasListTableRow'; | ||
|
||
type AasListProps = { | ||
shells: AasListEntry[]; | ||
tableHeaders: { label: string }[]; | ||
comparisonFeatureFlag?: boolean; | ||
selectedAasList: string[] | undefined; | ||
updateSelectedAasList: (isChecked: boolean, aasId: string | undefined) => void; | ||
}; | ||
|
||
export default function AasList(props: AasListProps) { | ||
const { shells, tableHeaders, selectedAasList, updateSelectedAasList, comparisonFeatureFlag } = props; | ||
const theme = useTheme(); | ||
const MAX_SELECTED_ITEMS = 3; | ||
|
||
/** | ||
* Decides if the current checkbox should be disabled or not. | ||
*/ | ||
const checkBoxDisabled = (aasId: string | undefined) => { | ||
if (!aasId) return false; | ||
return selectedAasList && selectedAasList.length >= MAX_SELECTED_ITEMS && !selectedAasList.includes(aasId); | ||
}; | ||
|
||
return ( | ||
<TableContainer> | ||
<Table> | ||
<TableHead> | ||
<TableRow | ||
sx={{ | ||
color: 'primary', | ||
lineHeight: '150%', | ||
letterSpacing: '0.16px', | ||
fontSize: '16px', | ||
}} | ||
> | ||
{comparisonFeatureFlag && ( | ||
<TableCell align="center" width="50px"> | ||
<Tooltip | ||
title={<FormattedMessage {...messages.mnestix.aasList.compareTooltip} />} | ||
arrow | ||
> | ||
<CompareArrowsIcon | ||
sx={{ width: '35px', height: '35px', verticalAlign: 'middle' }} | ||
/> | ||
</Tooltip> | ||
</TableCell> | ||
)} | ||
{!!tableHeaders && | ||
tableHeaders.map((header: { label: string }, index) => ( | ||
<TableCell key={index}> | ||
<Typography fontWeight="bold">{header.label}</Typography> | ||
</TableCell> | ||
))} | ||
</TableRow> | ||
</TableHead> | ||
<TableBody> | ||
{shells?.map((aasListEntry) => ( | ||
<TableRow | ||
key={aasListEntry.aasId} | ||
sx={{ | ||
'&:last-child td, &:last-child th': { border: 0 }, | ||
backgroundColor: theme.palette?.common?.white, | ||
}} | ||
data-testid={`list-row-${aasListEntry.aasId}`} | ||
> | ||
<AasListTableRow | ||
aasListEntry={aasListEntry} | ||
comparisonFeatureFlag={comparisonFeatureFlag} | ||
checkBoxDisabled={checkBoxDisabled} | ||
selectedAasList={selectedAasList} | ||
updateSelectedAasList={updateSelectedAasList} | ||
/> | ||
</TableRow> | ||
))} | ||
</TableBody> | ||
</Table> | ||
</TableContainer> | ||
); | ||
} |
50 changes: 50 additions & 0 deletions
50
src/app/[locale]/list/_components/AasListComparisonHeader.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Box, Button, IconButton, Typography } from '@mui/material'; | ||
import { FormattedMessage } from 'react-intl'; | ||
import { messages } from 'lib/i18n/localization'; | ||
import CloseIcon from '@mui/icons-material/Close'; | ||
import { useRouter } from 'next/navigation'; | ||
import { tooltipText } from 'lib/util/ToolTipText'; | ||
|
||
type CompareAasListBarType = { | ||
selectedAasList: string[] | undefined; | ||
updateSelectedAasList: (isChecked: boolean, aasId: string | undefined) => void; | ||
}; | ||
|
||
export const AasListComparisonHeader = (props: CompareAasListBarType) => { | ||
const { selectedAasList, updateSelectedAasList } = props; | ||
|
||
const navigate = useRouter(); | ||
const navigateToCompare = () => { | ||
const encodedAasList = selectedAasList?.map((aasId) => { | ||
return encodeURIComponent(aasId); | ||
}); | ||
const searchString = encodedAasList?.join('&aasId='); | ||
navigate.push(`/compare?aasId=${searchString}`); | ||
}; | ||
|
||
return ( | ||
<> | ||
<Typography marginBottom={3}> | ||
<FormattedMessage {...messages.mnestix.aasList.subtitle} /> | ||
</Typography> | ||
<Box display="flex" gap={2} alignItems="center"> | ||
{selectedAasList?.map((selectedAas) => ( | ||
<Box display="flex" flexDirection="row" alignItems="center" key={selectedAas}> | ||
<Typography data-testid={`selected-${selectedAas}`}>{tooltipText(selectedAas, 15)}</Typography> | ||
<IconButton onClick={() => updateSelectedAasList(false, selectedAas)}> | ||
<CloseIcon /> | ||
</IconButton> | ||
</Box> | ||
))} | ||
<Button | ||
variant="contained" | ||
onClick={navigateToCompare} | ||
disabled={!selectedAasList || selectedAasList.length < 1} | ||
data-testid="compare-button" | ||
> | ||
<FormattedMessage {...messages.mnestix.aasList.goToCompare} /> | ||
</Button> | ||
</Box> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { getTranslations } from 'next-intl/server'; | ||
import { Typography } from '@mui/material'; | ||
|
||
export default async function AasListHeader() { | ||
const t = await getTranslations('aas-list'); | ||
|
||
return ( | ||
<Typography variant="h2" textAlign="left" marginBottom={2}> | ||
{t('header')} | ||
</Typography> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { Box, Checkbox, Chip, Paper, TableCell, Typography } from '@mui/material'; | ||
import { ShellIcon } from 'components/custom-icons/ShellIcon'; | ||
import { FormattedMessage, useIntl } from 'react-intl'; | ||
import { messages } from 'lib/i18n/localization'; | ||
import { getProductClassId } from 'lib/util/ProductClassResolverUtil'; | ||
import LabelOffIcon from '@mui/icons-material/LabelOff'; | ||
import { AasListEntry } from 'lib/api/generated-api/clients.g'; | ||
import { encodeBase64 } from 'lib/util/Base64Util'; | ||
import { useRouter } from 'next/navigation'; | ||
import { useAasState } from 'components/contexts/CurrentAasContext'; | ||
import { useNotificationSpawner } from 'lib/hooks/UseNotificationSpawner'; | ||
import { ImageWithFallback } from './StyledImageWithFallBack'; | ||
import { ProductClassChip } from 'app/[locale]/list/_components/ProductClassChip'; | ||
import { tooltipText } from 'lib/util/ToolTipText'; | ||
|
||
type AasTableRow = { | ||
aasListEntry: AasListEntry; | ||
comparisonFeatureFlag: boolean | undefined; | ||
checkBoxDisabled: (aasId: string | undefined) => boolean | undefined; | ||
selectedAasList: string[] | undefined; | ||
updateSelectedAasList: (isChecked: boolean, aasId: string | undefined) => void; | ||
}; | ||
|
||
const tableBodyText = { | ||
lineHeight: '150%', | ||
fontSize: '16px', | ||
color: 'text.primary', | ||
}; | ||
export const AasListTableRow = (props: AasTableRow) => { | ||
const { aasListEntry, comparisonFeatureFlag, checkBoxDisabled, selectedAasList, updateSelectedAasList } = props; | ||
const navigate = useRouter(); | ||
const intl = useIntl(); | ||
const [, setAas] = useAasState(); | ||
const notificationSpawner = useNotificationSpawner(); | ||
const navigateToAas = (listEntry: AasListEntry) => { | ||
setAas(null); | ||
if (listEntry.aasId) navigate.push(`/viewer/${encodeBase64(listEntry.aasId)}`); | ||
}; | ||
|
||
const translateListText = (property: { [key: string]: string } | undefined) => { | ||
if (!property) return ''; | ||
return property[intl.locale] ?? Object.values(property)[0] ?? ''; | ||
}; | ||
|
||
const showMaxElementsNotification = () => { | ||
notificationSpawner.spawn({ | ||
message: ( | ||
<Typography variant="body2" sx={{ opacity: 0.7 }}> | ||
<FormattedMessage {...messages.mnestix.aasList.maxElementsWarning} /> | ||
</Typography> | ||
), | ||
severity: 'warning', | ||
}); | ||
}; | ||
|
||
return ( | ||
<> | ||
{comparisonFeatureFlag && ( | ||
<TableCell align="center" sx={tableBodyText}> | ||
<Box | ||
component="span" | ||
onClick={() => { | ||
if (checkBoxDisabled(aasListEntry.aasId)) showMaxElementsNotification(); | ||
}} | ||
> | ||
<Checkbox | ||
checked={!!(selectedAasList && selectedAasList.some((el) => el == aasListEntry.aasId))} | ||
disabled={checkBoxDisabled(aasListEntry.aasId)} | ||
onChange={(evt) => updateSelectedAasList(evt.target.checked, aasListEntry.aasId)} | ||
data-testid="list-checkbox" | ||
/> | ||
</Box> | ||
</TableCell> | ||
)} | ||
<TableCell component="th" scope="row" sx={tableBodyText}> | ||
<Paper | ||
onClick={() => navigateToAas(aasListEntry)} | ||
sx={{ | ||
width: '88px', | ||
height: '88px', | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
'&:hover': { | ||
boxShadow: 6, | ||
cursor: 'pointer', | ||
}, | ||
}} | ||
data-testid="list-thumbnail" | ||
> | ||
{aasListEntry.thumbnailUrl ? ( | ||
<ImageWithFallback | ||
src={aasListEntry.thumbnailUrl} | ||
alt={'Thumbnail image for: ' + aasListEntry.assetId} | ||
/> | ||
) : ( | ||
<ShellIcon fontSize="large" color="primary" /> | ||
)} | ||
</Paper> | ||
</TableCell> | ||
<TableCell align="left" sx={tableBodyText}> | ||
{translateListText(aasListEntry.manufacturerName)} | ||
</TableCell> | ||
<TableCell align="left" sx={tableBodyText}> | ||
{tooltipText(translateListText(aasListEntry.manufacturerProductDesignation), 80)} | ||
</TableCell> | ||
<TableCell align="left" sx={tableBodyText}> | ||
<Typography fontWeight="bold" sx={{ letterSpacing: '0.16px' }}> | ||
<FormattedMessage {...messages.mnestix.aasList.assetIdHeading} /> | ||
</Typography> | ||
{tooltipText(aasListEntry.assetId, 80)} <br /> | ||
<Typography fontWeight="bold" sx={{ letterSpacing: '0.16px' }}> | ||
<FormattedMessage {...messages.mnestix.aasList.aasIdHeading} /> | ||
</Typography> | ||
{tooltipText(aasListEntry.aasId, 80)} | ||
</TableCell> | ||
<TableCell align="left"> | ||
{aasListEntry.productGroup ? ( | ||
<ProductClassChip productClassId={getProductClassId(aasListEntry.productGroup)} maxChars={25} /> | ||
) : ( | ||
<Chip | ||
sx={{ paddingX: '16px', paddingY: '6px' }} | ||
color={'primary'} | ||
label={<FormattedMessage {...messages.mnestix.aasList.notAvailable} />} | ||
variant="outlined" | ||
icon={<LabelOffIcon color={'primary'} />} | ||
data-testid="product-class-chip" | ||
/> | ||
)} | ||
</TableCell> | ||
</> | ||
); | ||
}; |
Oops, something went wrong.