From 94d6710b3dc269ac25df757aba05a17c86245162 Mon Sep 17 00:00:00 2001 From: prv-proton Date: Tue, 3 Dec 2024 03:59:54 -0800 Subject: [PATCH 1/8] Feat: LCFS - Pills in AG Grid display tables #1249 --- frontend/src/utils/grid/cellRenderers.jsx | 318 ++++++++++++------ .../Admin/AdminMenu/components/Users.jsx | 15 - .../Admin/AdminMenu/components/_schema.js | 2 - .../ViewOrganization/ViewOrganization.jsx | 16 - 4 files changed, 218 insertions(+), 133 deletions(-) diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index 60ad2e761..aaea3d5dd 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -5,8 +5,8 @@ import { getAllFuelCodeStatuses, getAllOrganizationStatuses } from '@/constants/statuses' -import { Stack } from '@mui/material' import { Link, useLocation } from 'react-router-dom' +import { useState, useRef, useEffect } from 'react' export const TextRenderer = (props) => { return ( @@ -173,59 +173,6 @@ export const FuelCodeStatusTextRenderer = (props) => { ) } -export const CommonArrayRenderer = (props) => { - const location = useLocation() - const options = Array.isArray(props.value) - ? props.value - : props.value.split(',') - const chipContent = ( - - {options.map((mode) => ( - - ))} - - ) - return props.disableLink ? ( - chipContent - ) : ( - - {chipContent} - - ) -} - export const TransactionStatusRenderer = (props) => { const statusArr = [ 'Draft', @@ -321,52 +268,6 @@ export const ReportsStatusRenderer = (props) => { ) } -// if the status of the user is in-active then don't show their previously held roles -export const RoleRenderer = (props) => { - const location = useLocation() - return ( - - - - {props.data.isActive && - props.data.roles - .filter( - (r) => r.name !== roles.government && r.name !== roles.supplier - ) - .map((role) => ( - - ))}{' '} - - - - ) -} - export const RoleSpanRenderer = (props) => ( <> {props.data.roles @@ -390,3 +291,220 @@ export const RoleSpanRenderer = (props) => ( ))} ) + +const GenericChipRenderer = ({ + value, + disableLink = false, + renderChip = defaultRenderChip, + renderOverflowChip = defaultRenderOverflowChip, + chipConfig = {} +}) => { + const location = useLocation() + const containerRef = useRef(null) + const [visibleChips, setVisibleChips] = useState([]) + const [hiddenChipsCount, setHiddenChipsCount] = useState(0) + + const options = Array.isArray(value) + ? value + : value.split(',').map(item => item.trim()).filter(Boolean) + + useEffect(() => { + if (!containerRef.current) return + + const containerWidth = containerRef.current.offsetWidth + let totalWidth = 0 + const chipWidths = [] + + for (let i = 0; i < options.length; i++) { + const chipText = options[i] + const chipTextWidth = chipText.length * 6 // Assuming 6 pixels per character + const newTotalWidth = totalWidth + chipTextWidth + 32 // Add 32px for padding + + if (newTotalWidth <= containerWidth) { + chipWidths.push({ text: chipText, width: chipTextWidth + 32, ...chipConfig }) + totalWidth = newTotalWidth + } else { + // Stop and calculate remaining chips + setVisibleChips(chipWidths) + setHiddenChipsCount(options.length - chipWidths.length) + return + } + } + + // If all chips fit + setVisibleChips( + options.map((text) => ({ text, width: text.length * 6 + 32, ...chipConfig })) + ) + setHiddenChipsCount(0) + }, [chipConfig, options]) + + const chipContent = ( +
+ {visibleChips.map(renderChip)} + {renderOverflowChip(hiddenChipsCount)} +
+ ) + + return disableLink ? ( + chipContent + ) : ( + + {chipContent} + + ) +} + +// Default Render Chip Function for CommonArrayRenderer +const defaultRenderChip = (chip) => ( + + {chip.text} + +) + +// Default Overflow Chip for CommonArrayRenderer +const defaultRenderOverflowChip = (hiddenChipsCount) => + hiddenChipsCount > 0 && ( + + +{hiddenChipsCount} + + ) + +// Role Specific Render Chip Function +const roleRenderChip = (chip, isGovernmentRole = false) => ( + +) + +// Role Specific Overflow Chip +const roleRenderOverflowChip = (hiddenChipsCount, isGovernmentRole = false) => + hiddenChipsCount > 0 && ( + + +{hiddenChipsCount} + + ) + +export default GenericChipRenderer + +// Updated CommonArrayRenderer +export const CommonArrayRenderer = (props) => ( + +) + +export const RoleRenderer = (props) => { + const { value } = props + const [isGovernmentRole, setIsGovernmentRole] = useState(false) + + const filteredRoles = Array.isArray(value) + ? value + : value.split(',').map((role) => role.trim()).filter( + role => role !== roles.government && role !== roles.supplier + ) + + useEffect(() => { + setIsGovernmentRole( + Array.isArray(value) + ? value.includes(roles.government) + : value.includes(roles.government) + ) + }, [value]) + + return ( + roleRenderChip(chip, isGovernmentRole)} + renderOverflowChip={(count) => roleRenderOverflowChip(count, isGovernmentRole)} + /> + ) +} \ No newline at end of file diff --git a/frontend/src/views/Admin/AdminMenu/components/Users.jsx b/frontend/src/views/Admin/AdminMenu/components/Users.jsx index bcd65bc76..28f2e021b 100644 --- a/frontend/src/views/Admin/AdminMenu/components/Users.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/Users.jsx @@ -51,19 +51,6 @@ export const Users = () => { }) const gridRef = useRef() - const getRowHeight = useCallback((params) => { - const actualWidth = params.api.getColumn('role').getActualWidth() - return calculateRowHeight(actualWidth, params.data?.roles) - }, []) - - const onColumnResized = useCallback((params) => { - const actualWidth = params.api.getColumn('role').getActualWidth() - params.api.resetRowHeights() - params.api.forEachNode((node) => { - const rowHeight = calculateRowHeight(actualWidth, node.data?.roles) - node.setRowHeight(rowHeight) - }) - }, []) useEffect(() => { if (location.state?.message) { setAlertMessage(location.state.message) @@ -115,8 +102,6 @@ export const Users = () => { handleRowClicked={handleRowClicked} enableResetButton={false} enableCopyButton={false} - getRowHeight={getRowHeight} - onColumnResized={onColumnResized} /> diff --git a/frontend/src/views/Admin/AdminMenu/components/_schema.js b/frontend/src/views/Admin/AdminMenu/components/_schema.js index 23a63525f..7e9f3a303 100644 --- a/frontend/src/views/Admin/AdminMenu/components/_schema.js +++ b/frontend/src/views/Admin/AdminMenu/components/_schema.js @@ -28,8 +28,6 @@ export const usersColumnDefs = (t) => [ params.data.isActive ? params.data.roles.map((role) => role.name).join(', ') : '', - flex: 1, - minWidth: 300, sortable: false, suppressHeaderMenuButton: true, filterParams: { diff --git a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx index 4cc1abd8b..2bf32af03 100644 --- a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx +++ b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx @@ -75,20 +75,6 @@ export const ViewOrganization = () => { } }, []) - const getRowHeight = useCallback((params) => { - const actualWidth = params.api.getColumn('role').getActualWidth() - return calculateRowHeight(actualWidth, params.data?.roles) - }, []) - - const onColumnResized = useCallback((params) => { - const actualWidth = params.api.getColumn('role').getActualWidth() - params.api.resetRowHeights() - params.api.forEachNode((node) => { - const rowHeight = calculateRowHeight(actualWidth, node.data?.roles) - node.setRowHeight(rowHeight) - }) - }, []) - const gridOptions = { overlayNoRowsTemplate: 'No users found', includeHiddenColumnsInQuickFilter: true @@ -348,8 +334,6 @@ export const ViewOrganization = () => { handleRowClicked={handleRowClicked} enableCopyButton={false} enableResetButton={false} - getRowHeight={getRowHeight} - onColumnResized={onColumnResized} /> From 9bdace3cc3a1677c1ed8e622f912a151bbc6dcb7 Mon Sep 17 00:00:00 2001 From: prv-proton Date: Tue, 3 Dec 2024 04:15:33 -0800 Subject: [PATCH 2/8] . --- frontend/src/utils/grid/cellRenderers.jsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index aaea3d5dd..0e7d1cf46 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -7,6 +7,7 @@ import { } from '@/constants/statuses' import { Link, useLocation } from 'react-router-dom' import { useState, useRef, useEffect } from 'react' +import colors from '@/themes/base/colors' export const TextRenderer = (props) => { return ( @@ -318,13 +319,13 @@ const GenericChipRenderer = ({ for (let i = 0; i < options.length; i++) { const chipText = options[i] const chipTextWidth = chipText.length * 6 // Assuming 6 pixels per character - const newTotalWidth = totalWidth + chipTextWidth + 32 // Add 32px for padding + const newTotalWidth = totalWidth + chipTextWidth + 32 + 12 // Add 32px for padding and 12px for overflow counter chip if (newTotalWidth <= containerWidth) { chipWidths.push({ text: chipText, width: chipTextWidth + 32, ...chipConfig }) totalWidth = newTotalWidth } else { - // Stop and calculate remaining chips + // calculate remaining chips setVisibleChips(chipWidths) setHiddenChipsCount(options.length - chipWidths.length) return @@ -376,7 +377,7 @@ const defaultRenderChip = (chip) => ( justifyContent: 'center', lineHeight: '23px', padding: '0.5rem', - backgroundColor: '#606060', + backgroundColor: `${colors.input.main}`, color: '#fff', margin: '0 2px', width: `${chip.width}px`, @@ -402,7 +403,7 @@ const defaultRenderOverflowChip = (hiddenChipsCount) => backgroundColor: 'rgba(0, 0, 0, 0.08)', borderRadius: '16px', padding: '0.5rem', - color: 'rgb(49, 49, 50)', + color: `${colors.text.main}`, cursor: 'text', margin: '0 2px', fontSize: '0.8125rem', @@ -450,7 +451,7 @@ const roleRenderOverflowChip = (hiddenChipsCount, isGovernmentRole = false) => backgroundColor: isGovernmentRole ? 'rgba(0, 51, 102, 0.3)' : 'rgba(252, 186, 25, 0.3)', borderRadius: '16px', padding: '0.5rem', - color: 'rgb(49, 49, 50)', + color: `${colors.text.main}`, cursor: 'text', margin: '0 2px', fontSize: '0.8125rem', From 5e01d56cbae4308f6e24aba46ab981e90506d0e8 Mon Sep 17 00:00:00 2001 From: prv-proton Date: Tue, 3 Dec 2024 04:34:28 -0800 Subject: [PATCH 3/8] . --- frontend/src/utils/grid/cellRenderers.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index 0e7d1cf46..e8ed5381d 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -319,7 +319,7 @@ const GenericChipRenderer = ({ for (let i = 0; i < options.length; i++) { const chipText = options[i] const chipTextWidth = chipText.length * 6 // Assuming 6 pixels per character - const newTotalWidth = totalWidth + chipTextWidth + 32 + 12 // Add 32px for padding and 12px for overflow counter chip + const newTotalWidth = totalWidth + chipTextWidth + 32 + 20 // Add 32px for padding and 20px for overflow counter chip if (newTotalWidth <= containerWidth) { chipWidths.push({ text: chipText, width: chipTextWidth + 32, ...chipConfig }) From ebd3b6fd832d9d5305870a99cb164e5c89de480f Mon Sep 17 00:00:00 2001 From: prv-proton Date: Tue, 3 Dec 2024 06:23:41 -0800 Subject: [PATCH 4/8] fix re-rendering issue --- frontend/src/utils/grid/cellRenderers.jsx | 109 +++++++++++++++++----- 1 file changed, 84 insertions(+), 25 deletions(-) diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index e8ed5381d..91b1108aa 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -6,7 +6,7 @@ import { getAllOrganizationStatuses } from '@/constants/statuses' import { Link, useLocation } from 'react-router-dom' -import { useState, useRef, useEffect } from 'react' +import { useState, useRef, useEffect, useMemo, useCallback } from 'react' import colors from '@/themes/base/colors' export const TextRenderer = (props) => { @@ -298,46 +298,100 @@ const GenericChipRenderer = ({ disableLink = false, renderChip = defaultRenderChip, renderOverflowChip = defaultRenderOverflowChip, - chipConfig = {} + chipConfig = {}, + ...props }) => { const location = useLocation() + const { colDef, api } = props const containerRef = useRef(null) const [visibleChips, setVisibleChips] = useState([]) const [hiddenChipsCount, setHiddenChipsCount] = useState(0) const options = Array.isArray(value) ? value - : value.split(',').map(item => item.trim()).filter(Boolean) + : value + .split(',') + .map((item) => item.trim()) + .filter(Boolean) - useEffect(() => { - if (!containerRef.current) return + const calculateChipWidths = useCallback(() => { + if (!containerRef.current) return { visibleChips: [], hiddenChipsCount: 0 } - const containerWidth = containerRef.current.offsetWidth + const containerWidth = containerRef.current.offsetWidth || 200 // Fallback width let totalWidth = 0 const chipWidths = [] for (let i = 0; i < options.length; i++) { const chipText = options[i] - const chipTextWidth = chipText.length * 6 // Assuming 6 pixels per character - const newTotalWidth = totalWidth + chipTextWidth + 32 + 20 // Add 32px for padding and 20px for overflow counter chip + const chipTextWidth = chipText.length * 6 // Assuming 6px per character + const newTotalWidth = totalWidth + chipTextWidth + 32 + 20 // Adding 32px for padding and 20px for overflow counter chip if (newTotalWidth <= containerWidth) { - chipWidths.push({ text: chipText, width: chipTextWidth + 32, ...chipConfig }) + chipWidths.push({ + text: chipText, + width: chipTextWidth + 32, + ...chipConfig + }) totalWidth = newTotalWidth } else { - // calculate remaining chips - setVisibleChips(chipWidths) - setHiddenChipsCount(options.length - chipWidths.length) - return + return { + visibleChips: chipWidths, + hiddenChipsCount: options.length - chipWidths.length + } } } - // If all chips fit - setVisibleChips( - options.map((text) => ({ text, width: text.length * 6 + 32, ...chipConfig })) - ) - setHiddenChipsCount(0) - }, [chipConfig, options]) + return { + visibleChips: options.map((text) => ({ + text, + width: text.length * 6 + 32, + ...chipConfig + })), + hiddenChipsCount: 0 + } + }, [options]) + + // Initial render and resize handling + useEffect(() => { + // Calculate and set chips on initial render + const { visibleChips, hiddenChipsCount } = calculateChipWidths() + setVisibleChips(visibleChips) + setHiddenChipsCount(hiddenChipsCount) + + // Resize listener + const resizeObserver = new ResizeObserver(() => { + const { visibleChips, hiddenChipsCount } = calculateChipWidths() + setVisibleChips(visibleChips) + setHiddenChipsCount(hiddenChipsCount) + }) + if (containerRef.current) { + resizeObserver.observe(containerRef.current) + } + + // Column resize listener for ag-Grid + const resizeListener = (event) => { + const resizedColumn = event.column + if (resizedColumn.getColId() === colDef.field) { + const { visibleChips, hiddenChipsCount } = calculateChipWidths() + setVisibleChips(visibleChips) + setHiddenChipsCount(hiddenChipsCount) + } + } + + if (api) { + api.addEventListener('columnResized', resizeListener) + + // Cleanup + return () => { + api.removeEventListener('columnResized', resizeListener) + resizeObserver.disconnect() + } + } + + return () => { + resizeObserver.disconnect() + } + }, [value, api, colDef]) const chipContent = (
{ const filteredRoles = Array.isArray(value) ? value - : value.split(',').map((role) => role.trim()).filter( - role => role !== roles.government && role !== roles.supplier - ) + : value + .split(',') + .map((role) => role.trim()) + .filter((role) => role !== roles.government && role !== roles.supplier) useEffect(() => { setIsGovernmentRole( @@ -505,7 +562,9 @@ export const RoleRenderer = (props) => { {...props} value={filteredRoles} renderChip={(chip) => roleRenderChip(chip, isGovernmentRole)} - renderOverflowChip={(count) => roleRenderOverflowChip(count, isGovernmentRole)} + renderOverflowChip={(count) => + roleRenderOverflowChip(count, isGovernmentRole) + } /> ) -} \ No newline at end of file +} From b89fae97eeb15a5bc1802e3a582a2f951b3ce271 Mon Sep 17 00:00:00 2001 From: prv-proton Date: Tue, 3 Dec 2024 06:25:01 -0800 Subject: [PATCH 5/8] . --- frontend/src/utils/grid/cellRenderers.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index 91b1108aa..81a2d5f6b 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -529,7 +529,6 @@ const roleRenderOverflowChip = (hiddenChipsCount, isGovernmentRole = false) => export default GenericChipRenderer -// Updated CommonArrayRenderer export const CommonArrayRenderer = (props) => ( Date: Tue, 3 Dec 2024 06:25:01 -0800 Subject: [PATCH 6/8] . --- frontend/src/utils/grid/cellRenderers.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index 81a2d5f6b..2b0a7c665 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -310,9 +310,9 @@ const GenericChipRenderer = ({ const options = Array.isArray(value) ? value : value - .split(',') - .map((item) => item.trim()) - .filter(Boolean) + .split(',') + .map((item) => item.trim()) + .filter(Boolean) const calculateChipWidths = useCallback(() => { if (!containerRef.current) return { visibleChips: [], hiddenChipsCount: 0 } @@ -544,9 +544,9 @@ export const RoleRenderer = (props) => { const filteredRoles = Array.isArray(value) ? value : value - .split(',') - .map((role) => role.trim()) - .filter((role) => role !== roles.government && role !== roles.supplier) + .split(',') + .map((role) => role.trim()) + .filter((role) => role !== roles.government && role !== roles.supplier) useEffect(() => { setIsGovernmentRole( From 18e168e6686e8962270e6368793e90c37b2c79ba Mon Sep 17 00:00:00 2001 From: prv-proton Date: Tue, 3 Dec 2024 06:28:20 -0800 Subject: [PATCH 7/8] code formatting --- frontend/src/utils/grid/cellRenderers.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index 2b0a7c665..dc2a5e0e7 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import BCBadge from '@/components/BCBadge' import BCBox from '@/components/BCBox' import { roles } from '@/constants/roles' @@ -6,7 +7,7 @@ import { getAllOrganizationStatuses } from '@/constants/statuses' import { Link, useLocation } from 'react-router-dom' -import { useState, useRef, useEffect, useMemo, useCallback } from 'react' +import { useState, useRef, useEffect, useCallback } from 'react' import colors from '@/themes/base/colors' export const TextRenderer = (props) => { @@ -36,7 +37,6 @@ export const LinkRenderer = (props) => { } export const StatusRenderer = (props) => { - const location = useLocation() return ( Date: Wed, 4 Dec 2024 10:01:14 -0800 Subject: [PATCH 8/8] . --- frontend/src/utils/grid/cellRenderers.jsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index dc2a5e0e7..7563007f4 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -549,11 +549,7 @@ export const RoleRenderer = (props) => { .filter((role) => role !== roles.government && role !== roles.supplier) useEffect(() => { - setIsGovernmentRole( - Array.isArray(value) - ? value.includes(roles.government) - : value.includes(roles.government) - ) + setIsGovernmentRole(value.includes(roles.government)) }, [value]) return (