Aggregate queries follow up (#9636)

In this PR 

- [X] Fix missing IconCheck for count all on kanban headers:
https://discord.com/channels/1130383047699738754/1319330910361096242/1319330910361096242
- [X] Fix aggregate cell height:
https://discord.com/channels/1130383047699738754/1328749516488441997/1328749516488441997
- [X] Fix aggregate bar should extend fully to the right:
https://discord.com/channels/1130383047699738754/1328750532193681569/1328750532193681569
- [X] Fix first aggregate cell should fully spread to the left:
https://discord.com/channels/1130383047699738754/1326614678788374638/1326614678788374638
This commit is contained in:
Marie
2025-01-15 15:25:10 +01:00
committed by GitHub
parent ff93fd3c74
commit f828e75b72
6 changed files with 38 additions and 22 deletions

View File

@ -7,6 +7,7 @@ import { RecordBoardColumnHeaderAggregateDropdownMenuItem } from '@/object-recor
import { aggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/aggregateOperationComponentState'; import { aggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/aggregateOperationComponentState';
import { availableFieldIdsForAggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState'; import { availableFieldIdsForAggregateOperationComponentState } from '@/object-record/record-board/record-board-column/states/availableFieldIdsForAggregateOperationComponentState';
import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel'; import { getAggregateOperationLabel } from '@/object-record/record-board/record-board-column/utils/getAggregateOperationLabel';
import { recordIndexKanbanAggregateOperationState } from '@/object-record/record-index/states/recordIndexKanbanAggregateOperationState';
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations'; import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations'; import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope'; import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
@ -17,8 +18,9 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useUpdateViewAggregate } from '@/views/hooks/useUpdateViewAggregate'; import { useUpdateViewAggregate } from '@/views/hooks/useUpdateViewAggregate';
import isEmpty from 'lodash.isempty'; import isEmpty from 'lodash.isempty';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum'; import { Key } from 'ts-key-enum';
import { IconChevronLeft } from 'twenty-ui'; import { IconCheck, IconChevronLeft } from 'twenty-ui';
export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
availableAggregations, availableAggregations,
@ -50,6 +52,10 @@ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
const { updateViewAggregate } = useUpdateViewAggregate(); const { updateViewAggregate } = useUpdateViewAggregate();
const recordIndexKanbanAggregateOperation = useRecoilValue(
recordIndexKanbanAggregateOperationState,
);
return ( return (
<> <>
<DropdownMenuHeader StartIcon={IconChevronLeft} onClick={resetContent}> <DropdownMenuHeader StartIcon={IconChevronLeft} onClick={resetContent}>
@ -95,6 +101,14 @@ export const RecordBoardColumnHeaderAggregateDropdownOptionsContent = ({
? false ? false
: true : true
} }
RightIcon={
availableAggregationOperation ===
AGGREGATE_OPERATIONS.count &&
recordIndexKanbanAggregateOperation?.operation ===
AGGREGATE_OPERATIONS.count
? IconCheck
: undefined
}
/> />
), ),
)} )}

View File

@ -15,7 +15,8 @@ const StyledTbody = styled.tbody`
z-index: 5; z-index: 5;
transition: 0.3s ease; transition: 0.3s ease;
} }
td:nth-of-type(3) { tr:not(:last-child) td:nth-of-type(3) {
// Last row is aggregate footer
position: sticky; position: sticky;
left: 43px; left: 43px;
z-index: 5; z-index: 5;

View File

@ -5,6 +5,8 @@ import { MOBILE_VIEWPORT, ThemeContext } from 'twenty-ui';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
export const RECORD_TABLE_TD_WIDTH = '32px';
const StyledTd = styled.td<{ const StyledTd = styled.td<{
zIndex?: number; zIndex?: number;
backgroundColor: string; backgroundColor: string;
@ -44,8 +46,8 @@ const StyledTd = styled.td<{
${({ freezeFirstColumns }) => ${({ freezeFirstColumns }) =>
freezeFirstColumns freezeFirstColumns
? `@media (max-width: ${MOBILE_VIEWPORT}px) { ? `@media (max-width: ${MOBILE_VIEWPORT}px) {
width: 32px; width: ${RECORD_TABLE_TD_WIDTH};
max-width: 32px; max-width: ${RECORD_TABLE_TD_WIDTH};
}` }`
: ''} : ''}
`; `;

View File

@ -30,21 +30,8 @@ const StyledTableRow = styled.tr<{
border-right-color: ${({ theme }) => theme.background.primary}; border-right-color: ${({ theme }) => theme.background.primary};
} }
&.first-columns-sticky { &.first-columns-sticky {
td:nth-of-type(1) {
position: sticky;
left: 0;
z-index: 5;
transition: 0.3s ease;
}
td:nth-of-type(2) { td:nth-of-type(2) {
position: sticky; position: sticky;
left: 11px;
z-index: 5;
transition: 0.3s ease;
}
td:nth-of-type(3) {
position: sticky;
left: 43px;
z-index: 5; z-index: 5;
transition: 0.3s ease; transition: 0.3s ease;
&::after { &::after {
@ -115,7 +102,6 @@ export const RecordTableAggregateFooter = ({
endOfTableSticky={endOfTableSticky} endOfTableSticky={endOfTableSticky}
hasHorizontalOverflow={hasHorizontalOverflow} hasHorizontalOverflow={hasHorizontalOverflow}
> >
<StyledTd />
<StyledTd /> <StyledTd />
{visibleTableColumns.map((column, index) => { {visibleTableColumns.map((column, index) => {
return ( return (
@ -133,6 +119,9 @@ export const RecordTableAggregateFooter = ({
</RecordTableColumnAggregateFooterCellContext.Provider> </RecordTableColumnAggregateFooterCellContext.Provider>
); );
})} })}
<td colSpan={visibleTableColumns.length - 1} />
<td />
<td />
</StyledTableRow> </StyledTableRow>
); );
}; };

View File

@ -11,6 +11,7 @@ const COLUMN_MIN_WIDTH = 104;
const StyledColumnFooterCell = styled.td<{ const StyledColumnFooterCell = styled.td<{
columnWidth: number; columnWidth: number;
isFirstCell?: boolean;
}>` }>`
background-color: ${({ theme }) => theme.background.primary}; background-color: ${({ theme }) => theme.background.primary};
color: ${({ theme }) => theme.font.color.tertiary}; color: ${({ theme }) => theme.font.color.tertiary};
@ -74,6 +75,8 @@ export const RecordTableAggregateFooterCell = ({
tableColumnsByKey[fieldMetadataId].size + 24, tableColumnsByKey[fieldMetadataId].size + 24,
COLUMN_MIN_WIDTH, COLUMN_MIN_WIDTH,
)} )}
colSpan={isFirstCell ? 2 : undefined}
isFirstCell={isFirstCell}
> >
<StyledColumnFootContainer> <StyledColumnFootContainer>
<RecordTableColumnFooterWithDropdown <RecordTableColumnFooterWithDropdown

View File

@ -1,4 +1,5 @@
import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector'; import { hasRecordGroupsComponentSelector } from '@/object-record/record-group/states/selectors/hasRecordGroupsComponentSelector';
import { RECORD_TABLE_TD_WIDTH } from '@/object-record/record-table/record-table-cell/components/RecordTableTd';
import { RecordTableColumnAggregateFooterCellContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterCellContext'; 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 { RecordTableColumnAggregateFooterValue } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterValue';
import { hasAggregateOperationForViewFieldFamilySelector } from '@/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector'; import { hasAggregateOperationForViewFieldFamilySelector } from '@/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector';
@ -10,7 +11,7 @@ import { useContext, useState } from 'react';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { IconChevronDown } from 'twenty-ui'; import { IconChevronDown } from 'twenty-ui';
const StyledCell = styled.div<{ isUnfolded: boolean }>` const StyledCell = styled.div<{ isUnfolded: boolean; isFirstCell: boolean }>`
align-items: center; align-items: center;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -18,11 +19,11 @@ const StyledCell = styled.div<{ isUnfolded: boolean }>`
font-weight: ${({ theme }) => theme.font.weight.medium}; font-weight: ${({ theme }) => theme.font.weight.medium};
gap: ${({ theme }) => theme.spacing(1)}; gap: ${({ theme }) => theme.spacing(1)};
height: ${({ theme }) => theme.spacing(7)}; height: ${({ theme }) => theme.spacing(8)};
justify-content: space-between; justify-content: space-between;
min-width: ${({ theme }) => theme.spacing(7)}; min-width: ${({ theme }) => theme.spacing(7)};
flex-grow: 1; flex-grow: 1;
width: 100%; max-width: 100%;
background: ${({ theme, isUnfolded }) => background: ${({ theme, isUnfolded }) =>
isUnfolded ? theme.background.transparent.light : theme.background.primary}; isUnfolded ? theme.background.transparent.light : theme.background.primary};
@ -33,6 +34,12 @@ const StyledCell = styled.div<{ isUnfolded: boolean }>`
? theme.background.transparent.medium ? theme.background.transparent.medium
: theme.background.transparent.light}; : theme.background.transparent.light};
} }
${({ isFirstCell }) =>
isFirstCell &&
`
padding-left: ${RECORD_TABLE_TD_WIDTH};
`}
`; `;
const StyledIcon = styled(IconChevronDown)` const StyledIcon = styled(IconChevronDown)`
@ -76,7 +83,7 @@ export const RecordTableColumnAggregateFooterValueCell = ({
}} }}
onMouseLeave={() => setIsHovered(false)} onMouseLeave={() => setIsHovered(false)}
> >
<StyledCell isUnfolded={isDropdownOpen}> <StyledCell isUnfolded={isDropdownOpen} isFirstCell={isFirstCell}>
{isHovered || {isHovered ||
isDropdownOpen || isDropdownOpen ||
hasAggregateOperationForViewField || hasAggregateOperationForViewField ||