Fix glitch at aggregate operation update (#9253)
Before: https://github.com/user-attachments/assets/6e76b19c-b99c-4870-9c93-b75e7cf86103 After: https://github.com/user-attachments/assets/b5827d3e-5891-4204-bf91-6fa4504f30d3 Isolated the value change in a separate component to avoid re-renders of the parent component that has the down chevron. Also added a context at foot cell-level to centralize viewFieldId and fieldMetadataId that were queried in children components calling heavy hooks.
This commit is contained in:
@ -2,6 +2,7 @@ import styled from '@emotion/styled';
|
|||||||
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
import { MOBILE_VIEWPORT } from 'twenty-ui';
|
||||||
|
|
||||||
import { RecordTableAggregateFooterCell } from '@/object-record/record-table/record-table-footer/components/RecordTableAggregateFooterCell';
|
import { RecordTableAggregateFooterCell } from '@/object-record/record-table/record-table-footer/components/RecordTableAggregateFooterCell';
|
||||||
|
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext';
|
||||||
import { FIRST_TH_WIDTH } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
import { FIRST_TH_WIDTH } from '@/object-record/record-table/record-table-header/components/RecordTableHeader';
|
||||||
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
@ -90,12 +91,18 @@ export const RecordTableAggregateFooter = ({
|
|||||||
<StyledTh />
|
<StyledTh />
|
||||||
<StyledTh />
|
<StyledTh />
|
||||||
{visibleTableColumns.map((column, index) => (
|
{visibleTableColumns.map((column, index) => (
|
||||||
<RecordTableAggregateFooterCell
|
<RecordTableColumnAggregateFooterCellContext.Provider
|
||||||
key={`${column.fieldMetadataId}${currentRecordGroupId ? '-' + currentRecordGroupId : ''}`}
|
key={`${column.fieldMetadataId}${currentRecordGroupId ? '-' + currentRecordGroupId : ''}`}
|
||||||
column={column}
|
value={{
|
||||||
currentRecordGroupId={currentRecordGroupId}
|
viewFieldId: column.viewFieldId || '',
|
||||||
isFirstCell={index === 0}
|
fieldMetadataId: column.fieldMetadataId,
|
||||||
/>
|
}}
|
||||||
|
>
|
||||||
|
<RecordTableAggregateFooterCell
|
||||||
|
currentRecordGroupId={currentRecordGroupId}
|
||||||
|
isFirstCell={index === 0}
|
||||||
|
/>
|
||||||
|
</RecordTableColumnAggregateFooterCellContext.Provider>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
</StyledTableFoot>
|
</StyledTableFoot>
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useMemo } from 'react';
|
import { useContext, useMemo } from 'react';
|
||||||
|
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext';
|
||||||
import { RecordTableColumnFooterWithDropdown } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterWithDropdown';
|
import { RecordTableColumnFooterWithDropdown } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterWithDropdown';
|
||||||
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
import { tableColumnsComponentState } from '@/object-record/record-table/states/tableColumnsComponentState';
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
|
import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
|
||||||
|
|
||||||
@ -12,20 +11,19 @@ const COLUMN_MIN_WIDTH = 104;
|
|||||||
|
|
||||||
const StyledColumnFooterCell = styled.th<{
|
const StyledColumnFooterCell = styled.th<{
|
||||||
columnWidth: number;
|
columnWidth: number;
|
||||||
isResizing?: boolean;
|
|
||||||
}>`
|
}>`
|
||||||
color: ${({ theme }) => theme.font.color.tertiary};
|
|
||||||
padding: 0;
|
|
||||||
text-align: left;
|
|
||||||
transition: 0.3s ease;
|
|
||||||
|
|
||||||
background-color: ${({ theme }) => theme.background.primary};
|
background-color: ${({ theme }) => theme.background.primary};
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
${({ columnWidth }) => `
|
${({ columnWidth }) => `
|
||||||
min-width: ${columnWidth}px;
|
min-width: ${columnWidth}px;
|
||||||
width: ${columnWidth}px;
|
width: ${columnWidth}px;
|
||||||
`}
|
`}
|
||||||
position: relative;
|
text-align: left;
|
||||||
user-select: none;
|
transition: 0.3s ease;
|
||||||
${({ theme }) => {
|
${({ theme }) => {
|
||||||
return `
|
return `
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -36,23 +34,14 @@ const StyledColumnFooterCell = styled.th<{
|
|||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
}};
|
}};
|
||||||
${({ isResizing, theme }) => {
|
|
||||||
if (isResizing === true) {
|
|
||||||
return `&:after {
|
|
||||||
background-color: ${theme.color.blue};
|
|
||||||
bottom: 0;
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
right: -1px;
|
|
||||||
top: 0;
|
|
||||||
width: 2px;
|
|
||||||
}`;
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
|
|
||||||
// TODO: refactor this, each component should own its CSS
|
user-select: none;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
*::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledColumnFootContainer = styled.div`
|
const StyledColumnFootContainer = styled.div`
|
||||||
@ -62,11 +51,9 @@ const StyledColumnFootContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const RecordTableAggregateFooterCell = ({
|
export const RecordTableAggregateFooterCell = ({
|
||||||
column,
|
|
||||||
isFirstCell = false,
|
isFirstCell = false,
|
||||||
currentRecordGroupId,
|
currentRecordGroupId,
|
||||||
}: {
|
}: {
|
||||||
column: ColumnDefinition<FieldMetadata>;
|
|
||||||
isFirstCell?: boolean;
|
isFirstCell?: boolean;
|
||||||
currentRecordGroupId?: string;
|
currentRecordGroupId?: string;
|
||||||
}) => {
|
}) => {
|
||||||
@ -76,18 +63,19 @@ export const RecordTableAggregateFooterCell = ({
|
|||||||
mapArrayToObject(tableColumns, ({ fieldMetadataId }) => fieldMetadataId),
|
mapArrayToObject(tableColumns, ({ fieldMetadataId }) => fieldMetadataId),
|
||||||
[tableColumns],
|
[tableColumns],
|
||||||
);
|
);
|
||||||
|
const { fieldMetadataId } = useContext(
|
||||||
|
RecordTableColumnAggregateFooterCellContext,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledColumnFooterCell
|
<StyledColumnFooterCell
|
||||||
key={column.fieldMetadataId}
|
|
||||||
columnWidth={Math.max(
|
columnWidth={Math.max(
|
||||||
tableColumnsByKey[column.fieldMetadataId].size + 24,
|
tableColumnsByKey[fieldMetadataId].size + 24,
|
||||||
COLUMN_MIN_WIDTH,
|
COLUMN_MIN_WIDTH,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<StyledColumnFootContainer>
|
<StyledColumnFootContainer>
|
||||||
<RecordTableColumnFooterWithDropdown
|
<RecordTableColumnFooterWithDropdown
|
||||||
column={column}
|
|
||||||
currentRecordGroupId={currentRecordGroupId}
|
currentRecordGroupId={currentRecordGroupId}
|
||||||
isFirstCell={isFirstCell}
|
isFirstCell={isFirstCell}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
|
||||||
|
export type RecordTableColumnAggregateFooterCellValue = {
|
||||||
|
viewFieldId: string;
|
||||||
|
fieldMetadataId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecordTableColumnAggregateFooterCellContext =
|
||||||
|
createContext<RecordTableColumnAggregateFooterCellValue>(
|
||||||
|
{} as RecordTableColumnAggregateFooterCellValue,
|
||||||
|
);
|
||||||
@ -1,23 +1,6 @@
|
|||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useAggregateRecordsForRecordTableColumnFooter } from '@/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useState } from 'react';
|
import { isDefined } from 'twenty-ui';
|
||||||
import { IconChevronDown, isDefined } from 'twenty-ui';
|
|
||||||
|
|
||||||
const StyledCell = styled.div`
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-shrink: 0;
|
|
||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
|
||||||
|
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
|
||||||
height: ${({ theme }) => theme.spacing(7)};
|
|
||||||
justify-content: space-between;
|
|
||||||
min-width: ${({ theme }) => theme.spacing(7)};
|
|
||||||
flex-grow: 1;
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledText = styled.span`
|
const StyledText = styled.span`
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -54,56 +37,34 @@ const StyledValue = styled.div`
|
|||||||
flex: 1 0 0;
|
flex: 1 0 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledIcon = styled(IconChevronDown)`
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
height: 20px;
|
|
||||||
justify-content: center;
|
|
||||||
flex-grow: 0;
|
|
||||||
padding-right: ${({ theme }) => theme.spacing(2)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const RecordTableColumnAggregateFooterValue = ({
|
export const RecordTableColumnAggregateFooterValue = ({
|
||||||
dropdownId,
|
dropdownId,
|
||||||
aggregateValue,
|
fieldMetadataId,
|
||||||
aggregateLabel,
|
|
||||||
isFirstCell,
|
|
||||||
}: {
|
}: {
|
||||||
dropdownId: string;
|
dropdownId: string;
|
||||||
isFirstCell: boolean;
|
fieldMetadataId: string;
|
||||||
aggregateValue?: string | number | null;
|
|
||||||
aggregateLabel?: string;
|
|
||||||
}) => {
|
}) => {
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
|
||||||
const { isDropdownOpen } = useDropdown(dropdownId);
|
|
||||||
const sanitizedId = `tooltip-${dropdownId.replace(/[^a-zA-Z0-9-_]/g, '-')}`;
|
const sanitizedId = `tooltip-${dropdownId.replace(/[^a-zA-Z0-9-_]/g, '-')}`;
|
||||||
const theme = useTheme();
|
|
||||||
const shouldShowValue =
|
const { aggregateValue, aggregateLabel, isLoading } =
|
||||||
isHovered || isDropdownOpen || isDefined(aggregateValue) || isFirstCell;
|
useAggregateRecordsForRecordTableColumnFooter(fieldMetadataId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<>
|
||||||
onMouseEnter={() => {
|
{isDefined(aggregateValue) || isLoading ? (
|
||||||
setIsHovered(true);
|
<StyledValueContainer>
|
||||||
}}
|
{isLoading ? (
|
||||||
onMouseLeave={() => setIsHovered(false)}
|
<></>
|
||||||
>
|
) : (
|
||||||
<StyledCell>
|
<>
|
||||||
{shouldShowValue ? (
|
<StyledLabel>{aggregateLabel}</StyledLabel>
|
||||||
<>
|
<StyledValue>{aggregateValue}</StyledValue>
|
||||||
{isDefined(aggregateValue) ? (
|
</>
|
||||||
<StyledValueContainer>
|
)}
|
||||||
<StyledLabel>{aggregateLabel}</StyledLabel>
|
</StyledValueContainer>
|
||||||
<StyledValue>{aggregateValue}</StyledValue>
|
) : (
|
||||||
</StyledValueContainer>
|
<StyledText id={sanitizedId}>Calculate</StyledText>
|
||||||
) : (
|
)}
|
||||||
<StyledText id={sanitizedId}>Calculate</StyledText>
|
</>
|
||||||
)}
|
|
||||||
<StyledIcon fontWeight={'light'} size={theme.icon.size.sm} />
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</StyledCell>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,80 @@
|
|||||||
|
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext';
|
||||||
|
import { RecordTableColumnAggregateFooterValue } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValue';
|
||||||
|
import { hasAggregateOperationForViewFieldFamilySelector } from '@/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector';
|
||||||
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useContext, useState } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { IconChevronDown } from 'twenty-ui';
|
||||||
|
|
||||||
|
const StyledCell = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
|
|
||||||
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
height: ${({ theme }) => theme.spacing(7)};
|
||||||
|
justify-content: space-between;
|
||||||
|
min-width: ${({ theme }) => theme.spacing(7)};
|
||||||
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledIcon = styled(IconChevronDown)`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-grow: 0;
|
||||||
|
padding-right: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const RecordTableColumnAggregateFooterValueCell = ({
|
||||||
|
dropdownId,
|
||||||
|
isFirstCell,
|
||||||
|
}: {
|
||||||
|
dropdownId: string;
|
||||||
|
isFirstCell: boolean;
|
||||||
|
}) => {
|
||||||
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
const { isDropdownOpen } = useDropdown(dropdownId);
|
||||||
|
const theme = useTheme();
|
||||||
|
const { viewFieldId, fieldMetadataId } = useContext(
|
||||||
|
RecordTableColumnAggregateFooterCellContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasAggregateOperationForViewField = useRecoilValue(
|
||||||
|
hasAggregateOperationForViewFieldFamilySelector({
|
||||||
|
viewFieldId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onMouseEnter={() => {
|
||||||
|
setIsHovered(true);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => setIsHovered(false)}
|
||||||
|
>
|
||||||
|
<StyledCell>
|
||||||
|
{isHovered ||
|
||||||
|
isDropdownOpen ||
|
||||||
|
hasAggregateOperationForViewField ||
|
||||||
|
isFirstCell ? (
|
||||||
|
<>
|
||||||
|
<RecordTableColumnAggregateFooterValue
|
||||||
|
fieldMetadataId={fieldMetadataId}
|
||||||
|
dropdownId={dropdownId}
|
||||||
|
/>
|
||||||
|
<StyledIcon fontWeight={'light'} size={theme.icon.size.sm} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</StyledCell>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,29 +1,29 @@
|
|||||||
import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId';
|
import { useCurrentContentId } from '@/dropdown/hooks/useCurrentContentId';
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext';
|
||||||
import { RecordTableColumnAggregateFooterDropdownContent } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent';
|
import { RecordTableColumnAggregateFooterDropdownContent } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContent';
|
||||||
import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContext';
|
import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContext';
|
||||||
import { RecordTableColumnAggregateFooterValue } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValue';
|
import { RecordTableColumnAggregateFooterValueCell } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValueCell';
|
||||||
import { useAggregateRecordsForRecordTableColumnFooter } from '@/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter';
|
|
||||||
import { RecordTableFooterAggregateContentId } from '@/object-record/record-table/record-table-footer/types/RecordTableFooterAggregateContentId';
|
import { RecordTableFooterAggregateContentId } from '@/object-record/record-table/record-table-footer/types/RecordTableFooterAggregateContentId';
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { useToggleScrollWrapper } from '@/ui/utilities/scroll/hooks/useToggleScrollWrapper';
|
import { useToggleScrollWrapper } from '@/ui/utilities/scroll/hooks/useToggleScrollWrapper';
|
||||||
import { useCallback } from 'react';
|
import { useCallback, useContext } from 'react';
|
||||||
|
|
||||||
type RecordTableColumnFooterWithDropdownProps = {
|
type RecordTableColumnFooterWithDropdownProps = {
|
||||||
column: ColumnDefinition<FieldMetadata>;
|
|
||||||
isFirstCell: boolean;
|
isFirstCell: boolean;
|
||||||
currentRecordGroupId?: string;
|
currentRecordGroupId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RecordTableColumnFooterWithDropdown = ({
|
export const RecordTableColumnFooterWithDropdown = ({
|
||||||
column,
|
|
||||||
currentRecordGroupId,
|
currentRecordGroupId,
|
||||||
isFirstCell,
|
isFirstCell,
|
||||||
}: RecordTableColumnFooterWithDropdownProps) => {
|
}: RecordTableColumnFooterWithDropdownProps) => {
|
||||||
const { currentContentId, handleContentChange, handleResetContent } =
|
const { currentContentId, handleContentChange, handleResetContent } =
|
||||||
useCurrentContentId<RecordTableFooterAggregateContentId>();
|
useCurrentContentId<RecordTableFooterAggregateContentId>();
|
||||||
|
|
||||||
|
const { fieldMetadataId } = useContext(
|
||||||
|
RecordTableColumnAggregateFooterCellContext,
|
||||||
|
);
|
||||||
|
|
||||||
const { toggleScrollXWrapper, toggleScrollYWrapper } =
|
const { toggleScrollXWrapper, toggleScrollYWrapper } =
|
||||||
useToggleScrollWrapper();
|
useToggleScrollWrapper();
|
||||||
|
|
||||||
@ -38,12 +38,9 @@ export const RecordTableColumnFooterWithDropdown = ({
|
|||||||
toggleScrollYWrapper(true);
|
toggleScrollYWrapper(true);
|
||||||
}, [handleResetContent, toggleScrollXWrapper, toggleScrollYWrapper]);
|
}, [handleResetContent, toggleScrollXWrapper, toggleScrollYWrapper]);
|
||||||
|
|
||||||
const { aggregateValue, aggregateLabel } =
|
|
||||||
useAggregateRecordsForRecordTableColumnFooter(column.fieldMetadataId);
|
|
||||||
|
|
||||||
const dropdownId = currentRecordGroupId
|
const dropdownId = currentRecordGroupId
|
||||||
? `${column.fieldMetadataId}-footer-${currentRecordGroupId}`
|
? `${fieldMetadataId}-footer-${currentRecordGroupId}`
|
||||||
: `${column.fieldMetadataId}-footer`;
|
: `${fieldMetadataId}-footer`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
@ -51,9 +48,7 @@ export const RecordTableColumnFooterWithDropdown = ({
|
|||||||
onClose={handleDropdownClose}
|
onClose={handleDropdownClose}
|
||||||
dropdownId={dropdownId}
|
dropdownId={dropdownId}
|
||||||
clickableComponent={
|
clickableComponent={
|
||||||
<RecordTableColumnAggregateFooterValue
|
<RecordTableColumnAggregateFooterValueCell
|
||||||
aggregateLabel={aggregateLabel}
|
|
||||||
aggregateValue={aggregateValue}
|
|
||||||
dropdownId={dropdownId}
|
dropdownId={dropdownId}
|
||||||
isFirstCell={isFirstCell}
|
isFirstCell={isFirstCell}
|
||||||
/>
|
/>
|
||||||
@ -65,7 +60,7 @@ export const RecordTableColumnFooterWithDropdown = ({
|
|||||||
onContentChange: handleContentChange,
|
onContentChange: handleContentChange,
|
||||||
resetContent: handleResetContent,
|
resetContent: handleResetContent,
|
||||||
dropdownId: dropdownId,
|
dropdownId: dropdownId,
|
||||||
fieldMetadataId: column.fieldMetadataId,
|
fieldMetadataId: fieldMetadataId,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordTableColumnAggregateFooterDropdownContent />
|
<RecordTableColumnAggregateFooterDropdownContent />
|
||||||
|
|||||||
@ -6,9 +6,10 @@ import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useReco
|
|||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||||
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState';
|
||||||
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
|
||||||
|
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext';
|
||||||
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { useContext } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
@ -21,7 +22,6 @@ export const useAggregateRecordsForRecordTableColumnFooter = (
|
|||||||
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
const { objectMetadataItem } = useRecordTableContextOrThrow();
|
||||||
const { recordGroupFilter } = useRecordGroupFilter(objectMetadataItem.fields);
|
const { recordGroupFilter } = useRecordGroupFilter(objectMetadataItem.fields);
|
||||||
|
|
||||||
const { currentViewWithSavedFiltersAndSorts } = useGetCurrentView();
|
|
||||||
const recordIndexViewFilterGroups = useRecoilValue(
|
const recordIndexViewFilterGroups = useRecoilValue(
|
||||||
recordIndexViewFilterGroupsState,
|
recordIndexViewFilterGroupsState,
|
||||||
);
|
);
|
||||||
@ -37,13 +37,11 @@ export const useAggregateRecordsForRecordTableColumnFooter = (
|
|||||||
recordIndexViewFilterGroups,
|
recordIndexViewFilterGroups,
|
||||||
);
|
);
|
||||||
|
|
||||||
const viewFieldId =
|
const { viewFieldId } = useContext(
|
||||||
currentViewWithSavedFiltersAndSorts?.viewFields?.find(
|
RecordTableColumnAggregateFooterCellContext,
|
||||||
(viewField) => viewField.fieldMetadataId === fieldMetadataId,
|
);
|
||||||
)?.id ?? '';
|
|
||||||
|
|
||||||
const aggregateOperationForViewField = useRecoilValue(
|
const aggregateOperationForViewField = useRecoilValue(
|
||||||
viewFieldAggregateOperationState({ viewFieldId: viewFieldId }),
|
viewFieldAggregateOperationState({ viewFieldId }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const fieldName = objectMetadataItem.fields.find(
|
const fieldName = objectMetadataItem.fields.find(
|
||||||
@ -57,7 +55,7 @@ export const useAggregateRecordsForRecordTableColumnFooter = (
|
|||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const { data } = useAggregateRecords({
|
const { data, loading } = useAggregateRecords({
|
||||||
objectNameSingular: objectMetadataItem.nameSingular,
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
recordGqlFieldsAggregate,
|
recordGqlFieldsAggregate,
|
||||||
filter: { ...requestFilters, ...recordGroupFilter },
|
filter: { ...requestFilters, ...recordGroupFilter },
|
||||||
@ -75,5 +73,6 @@ export const useAggregateRecordsForRecordTableColumnFooter = (
|
|||||||
return {
|
return {
|
||||||
aggregateValue: value,
|
aggregateValue: value,
|
||||||
aggregateLabel: isDefined(value) ? label : undefined,
|
aggregateLabel: isDefined(value) ? label : undefined,
|
||||||
|
isLoading: loading,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||||
|
import { selectorFamily } from 'recoil';
|
||||||
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
|
export const hasAggregateOperationForViewFieldFamilySelector = selectorFamily<
|
||||||
|
boolean,
|
||||||
|
{ viewFieldId: string }
|
||||||
|
>({
|
||||||
|
key: 'hasAggregateOperationForViewField',
|
||||||
|
get:
|
||||||
|
({ viewFieldId }) =>
|
||||||
|
({ get }) => {
|
||||||
|
const aggregateOperation = get(
|
||||||
|
viewFieldAggregateOperationState({
|
||||||
|
viewFieldId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return isDefined(aggregateOperation);
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user