diff --git a/packages/twenty-front/src/hooks/useScrollRestoration.ts b/packages/twenty-front/src/hooks/useScrollRestoration.ts index 2367b2131..9ef8354f7 100644 --- a/packages/twenty-front/src/hooks/useScrollRestoration.ts +++ b/packages/twenty-front/src/hooks/useScrollRestoration.ts @@ -1,9 +1,10 @@ import { useEffect } from 'react'; -import { useLocation, useNavigation } from 'react-router-dom'; -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useNavigation } from 'react-router-dom'; -import { overlayScrollbarsState } from '@/ui/utilities/scroll/states/overlayScrollbarsState'; -import { scrollPositionState } from '@/ui/utilities/scroll/states/scrollPositionState'; +import { scrollWrapperInstanceComponentState } from '@/ui/utilities/scroll/states/scrollWrapperInstanceComponentState'; +import { scrollWrapperScrollTopComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { isDefined } from '~/utils/isDefined'; /** @@ -13,23 +14,24 @@ import { isDefined } from '~/utils/isDefined'; * not share the same scroll position. */ export const useScrollRestoration = (viewportHeight?: number) => { - const key = `scroll-position-${useLocation().key}`; const { state } = useNavigation(); - const [scrollPosition, setScrollPosition] = useRecoilState( - scrollPositionState(key), + const [scrollTop, setScrollTop] = useRecoilComponentStateV2( + scrollWrapperScrollTopComponentState, ); - const overlayScrollbars = useRecoilValue(overlayScrollbarsState); + const overlayScrollbars = useRecoilComponentValueV2( + scrollWrapperInstanceComponentState, + ); const scrollWrapper = overlayScrollbars?.elements().viewport; - const skip = isDefined(viewportHeight) && scrollPosition > viewportHeight; + const skip = isDefined(viewportHeight) && scrollTop > viewportHeight; useEffect(() => { if (state === 'loading') { - setScrollPosition(scrollWrapper?.scrollTop ?? 0); + setScrollTop(scrollWrapper?.scrollTop ?? 0); } else if (state === 'idle' && isDefined(scrollWrapper) && !skip) { - scrollWrapper.scrollTo({ top: scrollPosition }); + scrollWrapper.scrollTo({ top: scrollTop }); } - }, [key, state, scrollWrapper, skip, scrollPosition, setScrollPosition]); + }, [state, scrollWrapper, skip, scrollTop, setScrollTop]); }; diff --git a/packages/twenty-front/src/hooks/useScrollToPosition.ts b/packages/twenty-front/src/hooks/useScrollToPosition.ts index 34994c1f3..b656ca90e 100644 --- a/packages/twenty-front/src/hooks/useScrollToPosition.ts +++ b/packages/twenty-front/src/hooks/useScrollToPosition.ts @@ -1,19 +1,24 @@ -import { overlayScrollbarsState } from '@/ui/utilities/scroll/states/overlayScrollbarsState'; +import { scrollWrapperInstanceComponentState } from '@/ui/utilities/scroll/states/scrollWrapperInstanceComponentState'; +import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useRecoilCallback } from 'recoil'; export const useScrollToPosition = () => { + const scrollWrapperInstanceState = useRecoilComponentCallbackStateV2( + scrollWrapperInstanceComponentState, + ); + const scrollToPosition = useRecoilCallback( ({ snapshot }) => (scrollPositionInPx: number) => { const overlayScrollbars = snapshot - .getLoadable(overlayScrollbarsState) + .getLoadable(scrollWrapperInstanceState) .getValue(); const scrollWrapper = overlayScrollbars?.elements().viewport; scrollWrapper?.scrollTo({ top: scrollPositionInPx }); }, - [], + [scrollWrapperInstanceState], ); return { scrollToPosition }; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx index a19f0af6a..30f6bc268 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/components/EventList.tsx @@ -44,7 +44,10 @@ export const EventList = ({ events, targetableObject }: EventListProps) => { const groupedEvents = groupEventsByMonth(filteredEvents); return ( - + {groupedEvents.map((group, index) => ( { setCommandMenuSearch={setCommandMenuSearch} /> - + { )} diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx index f7fee7566..e83c3e4f5 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -194,7 +194,10 @@ export const RecordBoard = () => { - + diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardStickyHeaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardStickyHeaderEffect.tsx index 5544a7801..2f5f23fbc 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardStickyHeaderEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardStickyHeaderEffect.tsx @@ -1,9 +1,11 @@ +import { scrollWrapperScrollTopComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useEffect } from 'react'; -import { useScrollTopValue } from '@/ui/utilities/scroll/hooks/useScrollTopValue'; - export const RecordBoardStickyHeaderEffect = () => { - const scrollTop = useScrollTopValue('recordBoard'); + const scrollTop = useRecoilComponentValueV2( + scrollWrapperScrollTopComponentState, + ); // TODO: move this outside because it might cause way too many re-renders for other hooks useEffect(() => { diff --git a/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupFilter.ts b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupFilter.ts new file mode 100644 index 000000000..27b182ed8 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-group/hooks/useRecordGroupFilter.ts @@ -0,0 +1,37 @@ +import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; +import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition'; +import { useMemo } from 'react'; +import { isDefined } from 'twenty-ui'; + +export const useRecordGroupFilter = (fields: FieldMetadataItem[]) => { + const currentRecordGroupDefinition = useCurrentRecordGroupDefinition(); + + const recordGroupFilter = useMemo(() => { + if (isDefined(currentRecordGroupDefinition)) { + const fieldMetadataItem = fields.find( + (fieldMetadataItem) => + fieldMetadataItem.id === currentRecordGroupDefinition.fieldMetadataId, + ); + + if (!fieldMetadataItem) { + throw new Error( + `Field metadata item with id ${currentRecordGroupDefinition.fieldMetadataId} not found`, + ); + } + + if (!isDefined(currentRecordGroupDefinition.value)) { + return { [fieldMetadataItem.name]: { is: 'NULL' } }; + } + + return { + [fieldMetadataItem.name]: { + eq: currentRecordGroupDefinition.value, + }, + }; + } + + return {}; + }, [currentRecordGroupDefinition, fields]); + + return { recordGroupFilter }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts index e77e993ab..c05d39917 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useFindManyRecordIndexTableParams.ts @@ -2,12 +2,11 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter'; import { useCurrentRecordGroupDefinition } from '@/object-record/record-group/hooks/useCurrentRecordGroupDefinition'; +import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter'; import { tableFiltersComponentState } from '@/object-record/record-table/states/tableFiltersComponentState'; import { tableSortsComponentState } from '@/object-record/record-table/states/tableSortsComponentState'; import { tableViewFilterGroupsComponentState } from '@/object-record/record-table/states/tableViewFilterGroupsComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import { useMemo } from 'react'; -import { isDefined } from 'twenty-ui'; export const useFindManyRecordIndexTableParams = ( objectNameSingular: string, @@ -17,6 +16,10 @@ export const useFindManyRecordIndexTableParams = ( objectNameSingular, }); + const { recordGroupFilter } = useRecordGroupFilter( + objectMetadataItem?.fields, + ); + const currentRecordGroupDefinition = useCurrentRecordGroupDefinition(); const tableViewFilterGroups = useRecoilComponentValueV2( @@ -38,33 +41,6 @@ export const useFindManyRecordIndexTableParams = ( tableViewFilterGroups, ); - const recordGroupFilter = useMemo(() => { - if (isDefined(currentRecordGroupDefinition)) { - const fieldMetadataItem = objectMetadataItem?.fields.find( - (fieldMetadataItem) => - fieldMetadataItem.id === currentRecordGroupDefinition.fieldMetadataId, - ); - - if (!fieldMetadataItem) { - throw new Error( - `Field metadata item with id ${currentRecordGroupDefinition.fieldMetadataId} not found`, - ); - } - - if (!isDefined(currentRecordGroupDefinition.value)) { - return { [fieldMetadataItem.name]: { is: 'NULL' } }; - } - - return { - [fieldMetadataItem.name]: { - eq: currentRecordGroupDefinition.value, - }, - }; - } - - return {}; - }, [objectMetadataItem.fields, currentRecordGroupDefinition]); - const orderBy = turnSortsIntoOrderBy(objectMetadataItem, tableSorts); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index 4da31f56b..72d874499 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -96,7 +96,9 @@ export const RecordTable = () => { )} - {isAggregateQueryEnabled && } + {isAggregateQueryEnabled && !hasRecordGroups && ( + + )} { + const isAggregateQueryEnabled = useIsFeatureEnabled( + 'IS_AGGREGATE_QUERY_ENABLED', + ); const currentRecordGroupId = useCurrentRecordGroupId(); const allRecordIds = useRecoilComponentValueV2( @@ -57,8 +62,14 @@ export const RecordTableRecordGroupRows = () => { ); })} - + {isAggregateQueryEnabled && ( + + )} + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStickyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStickyEffect.tsx index 8bf67ac19..e4a0c684a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStickyEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStickyEffect.tsx @@ -1,12 +1,15 @@ import { useEffect } from 'react'; import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState'; -import { useScrollLeftValue } from '@/ui/utilities/scroll/hooks/useScrollLeftValue'; -import { useScrollTopValue } from '@/ui/utilities/scroll/hooks/useScrollTopValue'; +import { scrollWrapperScrollLeftComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollLeftComponentState'; +import { scrollWrapperScrollTopComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; export const RecordTableStickyEffect = () => { - const scrollTop = useScrollTopValue('recordTableWithWrappers'); + const scrollTop = useRecoilComponentValueV2( + scrollWrapperScrollTopComponentState, + ); useEffect(() => { if (scrollTop > 0) { @@ -20,7 +23,9 @@ export const RecordTableStickyEffect = () => { } }, [scrollTop]); - const scrollLeft = useScrollLeftValue('recordTableWithWrappers'); + const scrollLeft = useRecoilComponentValueV2( + scrollWrapperScrollLeftComponentState, + ); const setIsRecordTableScrolledLeft = useSetRecoilComponentStateV2( isRecordTableScrolledLeftComponentState, diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx index 927398545..30827c224 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx @@ -10,8 +10,6 @@ import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { useSaveCurrentViewFields } from '@/views/hooks/useSaveCurrentViewFields'; import { mapColumnDefinitionsToViewFields } from '@/views/utils/mapColumnDefinitionToViewField'; -import { isScrollEnabledForRecordTableState } from '@/object-record/record-table/states/isScrollEnabledForRecordTableState'; -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { RecordUpdateContext } from '../contexts/EntityUpdateMutationHookContext'; import { useRecordTable } from '../hooks/useRecordTable'; @@ -50,11 +48,6 @@ export const RecordTableWithWrappers = ({ recordTableId, viewBarId, }: RecordTableWithWrappersProps) => { - const isScrollEnabledForRecordTable = useRecoilComponentValueV2( - isScrollEnabledForRecordTableState, - recordTableId, - ); - const { resetTableRowSelection, selectAllRows, setHasUserSelectedAllRows } = useRecordTable({ recordTableId, @@ -109,9 +102,8 @@ export const RecordTableWithWrappers = ({ > diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts index 609c3f908..9cd173f5d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts @@ -53,6 +53,11 @@ export const useRecordTable = (props?: useRecordTableProps) => { recordTableId, ); + const tableColumnsState = useRecoilComponentCallbackStateV2( + tableColumnsComponentState, + recordTableId, + ); + const setAvailableTableColumns = useRecoilCallback( ({ snapshot, set }) => (columns: ColumnDefinition[]) => { @@ -69,6 +74,19 @@ export const useRecordTable = (props?: useRecordTableProps) => { [availableTableColumnsState], ); + const setTableColumns = useRecoilCallback( + ({ snapshot, set }) => + (columns: ColumnDefinition[]) => { + const tableColumns = getSnapshotValue(snapshot, tableColumnsState); + + if (isDeeplyEqual(tableColumns, columns)) { + return; + } + set(tableColumnsState, columns); + }, + [tableColumnsState], + ); + const setOnEntityCountChange = useSetRecoilComponentStateV2( onEntityCountChangeComponentState, recordTableId, @@ -89,11 +107,6 @@ export const useRecordTable = (props?: useRecordTableProps) => { recordTableId, ); - const setTableColumns = useSetRecoilComponentStateV2( - tableColumnsComponentState, - recordTableId, - ); - const setOnColumnsChange = useSetRecoilComponentStateV2( onColumnsChangeComponentState, recordTableId, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx index a822c4bd3..a9273b9ea 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx @@ -6,13 +6,15 @@ import { RecordTableTd } from '@/object-record/record-table/record-table-cell/co import { useSetCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected'; import { Checkbox } from 'twenty-ui'; +export const TABLE_CELL_CHECKBOX_MIN_WIDTH = '24px'; + const StyledContainer = styled.div` align-items: center; cursor: pointer; display: flex; height: 32px; justify-content: center; - min-width: 24px; + min-width: ${TABLE_CELL_CHECKBOX_MIN_WIDTH}; `; export const RecordTableCellCheckbox = () => { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx index 29da512d4..05632c438 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx @@ -6,12 +6,14 @@ import { RecordTableTd } from '@/object-record/record-table/record-table-cell/co import { css } from '@emotion/react'; import { IconListViewGrip } from 'twenty-ui'; +export const TABLE_CELL_GRIP_WIDTH = '16px'; + const StyledContainer = styled.div<{ isPendingRow?: boolean }>` + height: 32px; + width: ${TABLE_CELL_GRIP_WIDTH}; border-color: transparent; cursor: grab; display: flex; - height: 32px; - width: 16px; ${({ isPendingRow }) => !isPendingRow ? css` diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnFooterAggregateValue.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnFooterAggregateValue.tsx index b3b1a77fc..a306c1029 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnFooterAggregateValue.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnFooterAggregateValue.tsx @@ -50,8 +50,10 @@ export const RecordTableColumnFooterAggregateValue = ({ dropdownId, aggregateValue, aggregateLabel, + isFirstCell, }: { dropdownId: string; + isFirstCell: boolean; aggregateValue?: string | number | null; aggregateLabel?: string; }) => { @@ -66,13 +68,13 @@ export const RecordTableColumnFooterAggregateValue = ({ onMouseLeave={() => setIsHovered(false)} > - {isHovered || isDefined(aggregateValue) ? ( + {isHovered || isDefined(aggregateValue) || isFirstCell ? ( <> {aggregateValue ?? 'Calculate'} - {aggregateValue && isDefined(aggregateLabel) && ( + {isDefined(aggregateValue) && isDefined(aggregateLabel) && ( ; + dropdownId: string; }) => { - const { closeDropdown } = useDropdown(column.fieldMetadataId + '-footer'); + const { closeDropdown } = useDropdown(dropdownId); const { objectMetadataItem } = useRecordTableContextOrThrow(); const { currentViewWithSavedFiltersAndSorts } = useGetCurrentView(); @@ -67,6 +69,7 @@ export const RecordTableColumnFooterDropdown = ({ key={aggregation} onClick={() => { handleAggregationChange(aggregation); + closeDropdown(); }} text={getAggregateOperationLabel(aggregation)} /> diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnFooterWithDropdown.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnFooterWithDropdown.tsx index f66111a97..6c7cf7db1 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnFooterWithDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableColumnFooterWithDropdown.tsx @@ -2,53 +2,44 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata' import { RecordTableColumnFooterAggregateValue } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnFooterAggregateValue'; import { RecordTableColumnFooterDropdown } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnFooterDropdown'; import { useAggregateRecordsForRecordTableColumnFooter } from '@/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter'; -import { isScrollEnabledForRecordTableState } from '@/object-record/record-table/states/isScrollEnabledForRecordTableState'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; -import styled from '@emotion/styled'; +import { useToggleScrollWrapper } from '@/ui/utilities/scroll/hooks/useToggleScrollWrapper'; import { useCallback } from 'react'; type RecordTableColumnFooterWithDropdownProps = { column: ColumnDefinition; + isFirstCell: boolean; + currentRecordGroupId?: string; }; -const StyledDropdown = styled(Dropdown)` - display: flex; - flex: 1; - z-index: ${({ theme }) => theme.lastLayerZIndex}; - - transition: opacity 150ms ease-in-out; -`; - export const RecordTableColumnFooterWithDropdown = ({ column, + currentRecordGroupId, + isFirstCell, }: RecordTableColumnFooterWithDropdownProps) => { - const setIsScrollEnabledForRecordTable = useSetRecoilComponentStateV2( - isScrollEnabledForRecordTableState, - ); + const { toggleScrollXWrapper, toggleScrollYWrapper } = + useToggleScrollWrapper(); const handleDropdownOpen = useCallback(() => { - setIsScrollEnabledForRecordTable({ - enableXScroll: false, - enableYScroll: false, - }); - }, [setIsScrollEnabledForRecordTable]); + toggleScrollXWrapper(false); + toggleScrollYWrapper(false); + }, [toggleScrollXWrapper, toggleScrollYWrapper]); const handleDropdownClose = useCallback(() => { - setIsScrollEnabledForRecordTable({ - enableXScroll: true, - enableYScroll: true, - }); - }, [setIsScrollEnabledForRecordTable]); + toggleScrollXWrapper(true); + toggleScrollYWrapper(true); + }, [toggleScrollXWrapper, toggleScrollYWrapper]); const { aggregateValue, aggregateLabel } = useAggregateRecordsForRecordTableColumnFooter(column.fieldMetadataId); - const dropdownId = column.fieldMetadataId + '-footer'; + const dropdownId = currentRecordGroupId + ? `${column.fieldMetadataId}-footer-${currentRecordGroupId}` + : `${column.fieldMetadataId}-footer`; return ( - + } + dropdownComponents={ + } - dropdownComponents={} dropdownOffset={{ x: -1 }} dropdownPlacement="bottom-start" dropdownHotkeyScope={{ scope: dropdownId }} diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableFooter.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableFooter.tsx index dadd433de..b0fb27dd6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableFooter.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableFooter.tsx @@ -1,6 +1,8 @@ import styled from '@emotion/styled'; import { MOBILE_VIEWPORT } from 'twenty-ui'; +import { TABLE_CELL_CHECKBOX_MIN_WIDTH } from '@/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox'; +import { TABLE_CELL_GRIP_WIDTH } from '@/object-record/record-table/record-table-cell/components/RecordTableCellGrip'; import { RecordTableFooterCell } from '@/object-record/record-table/record-table-footer/components/RecordTableFooterCell'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; @@ -75,21 +77,33 @@ const StyledTableFoot = styled.thead` `; const StyledDiv = styled.div` - width: 30px; + width: calc(${TABLE_CELL_GRIP_WIDTH} + ${TABLE_CELL_CHECKBOX_MIN_WIDTH}); `; -export const RecordTableFooter = () => { +export const RecordTableFooter = ({ + currentRecordGroupId, +}: { + currentRecordGroupId?: string; +}) => { const visibleTableColumns = useRecoilComponentValueV2( visibleTableColumnsComponentSelector, ); return ( - + - {visibleTableColumns.map((column) => ( - + {visibleTableColumns.map((column, index) => ( + ))} diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableFooterCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableFooterCell.tsx index 74064645a..4d4e3747f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableFooterCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/components/RecordTableFooterCell.tsx @@ -63,8 +63,12 @@ const StyledColumnFootContainer = styled.div` export const RecordTableFooterCell = ({ column, + isFirstCell = false, + currentRecordGroupId, }: { column: ColumnDefinition; + isFirstCell?: boolean; + currentRecordGroupId?: string; }) => { const tableColumns = useRecoilComponentValueV2(tableColumnsComponentState); const tableColumnsByKey = useMemo( @@ -82,7 +86,11 @@ export const RecordTableFooterCell = ({ )} > - + ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx index 9fa7cd741..96bb3d7ca 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-footer/hooks/useAggregateRecordsForRecordTableColumnFooter.tsx @@ -1,6 +1,7 @@ import { useAggregateRecords } from '@/object-record/hooks/useAggregateRecords'; import { computeAggregateValueAndLabel } from '@/object-record/record-board/record-board-column/utils/computeAggregateValueAndLabel'; import { computeViewRecordGqlOperationFilter } from '@/object-record/record-filter/utils/computeViewRecordGqlOperationFilter'; +import { useRecordGroupFilter } from '@/object-record/record-group/hooks/useRecordGroupFilter'; import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState'; import { recordIndexViewFilterGroupsState } from '@/object-record/record-index/states/recordIndexViewFilterGroupsState'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; @@ -16,8 +17,9 @@ export const useAggregateRecordsForRecordTableColumnFooter = ( const isAggregateQueryEnabled = useIsFeatureEnabled( 'IS_AGGREGATE_QUERY_ENABLED', ); - const { objectMetadataItem } = useRecordTableContextOrThrow(); + const { recordGroupFilter } = useRecordGroupFilter(objectMetadataItem.fields); + const { currentViewWithSavedFiltersAndSorts } = useGetCurrentView(); const recordIndexViewFilterGroups = useRecoilValue( recordIndexViewFilterGroupsState, @@ -56,7 +58,7 @@ export const useAggregateRecordsForRecordTableColumnFooter = ( const { data } = useAggregateRecords({ objectNameSingular: objectMetadataItem.nameSingular, recordGqlFieldsAggregate, - filter: { ...requestFilters }, + filter: { ...requestFilters, ...recordGroupFilter }, skip: !isAggregateQueryEnabled || !isDefined(aggregateOperationForViewField), }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown.tsx index 473e92c79..769f57db6 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableColumnHeadWithDropdown.tsx @@ -1,8 +1,7 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; -import { isScrollEnabledForRecordTableState } from '@/object-record/record-table/states/isScrollEnabledForRecordTableState'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; +import { useToggleScrollWrapper } from '@/ui/utilities/scroll/hooks/useToggleScrollWrapper'; import styled from '@emotion/styled'; import { useCallback } from 'react'; import { RecordTableColumnHead } from './RecordTableColumnHead'; @@ -21,23 +20,18 @@ const StyledDropdown = styled(Dropdown)` export const RecordTableColumnHeadWithDropdown = ({ column, }: RecordTableColumnHeadWithDropdownProps) => { - const setIsScrollEnabledForRecordTable = useSetRecoilComponentStateV2( - isScrollEnabledForRecordTableState, - ); + const { toggleScrollXWrapper, toggleScrollYWrapper } = + useToggleScrollWrapper(); const handleDropdownOpen = useCallback(() => { - setIsScrollEnabledForRecordTable({ - enableXScroll: false, - enableYScroll: false, - }); - }, [setIsScrollEnabledForRecordTable]); + toggleScrollXWrapper(false); + toggleScrollYWrapper(false); + }, [toggleScrollXWrapper, toggleScrollYWrapper]); const handleDropdownClose = useCallback(() => { - setIsScrollEnabledForRecordTable({ - enableXScroll: true, - enableYScroll: true, - }); - }, [setIsScrollEnabledForRecordTable]); + toggleScrollXWrapper(true); + toggleScrollYWrapper(true); + }, [toggleScrollXWrapper, toggleScrollYWrapper]); return ( ({ - key: 'isScrollEnabledForRecordTableState', - defaultValue: { - enableXScroll: true, - enableYScroll: true, - }, - componentInstanceContext: RecordTableComponentInstanceContext, - }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/types/ColumnDefinition.ts b/packages/twenty-front/src/modules/object-record/record-table/types/ColumnDefinition.ts index c649dc4c1..c14b745ef 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/types/ColumnDefinition.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/types/ColumnDefinition.ts @@ -1,6 +1,5 @@ import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; -import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations'; export type ColumnDefinition = FieldDefinition & { size: number; @@ -10,5 +9,4 @@ export type ColumnDefinition = FieldDefinition & { viewFieldId?: string; isFilterable?: boolean; isSortable?: boolean; - aggregateOperation?: AGGREGATE_OPERATIONS | null; }; diff --git a/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx b/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx index 1c4f7de6b..e2c47d282 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsPageContainer.tsx @@ -30,7 +30,10 @@ export const SettingsPageContainer = ({ }: { children: ReactNode; }) => ( - + {children} ); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx index 78244082f..679fe4e2f 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuItemsContainer.tsx @@ -1,5 +1,6 @@ import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import styled from '@emotion/styled'; +import { useId } from 'react'; const StyledDropdownMenuItemsExternalContainer = styled.div<{ hasMaxHeight?: boolean; @@ -44,13 +45,18 @@ export const DropdownMenuItemsContainer = ({ className?: string; withoutScrollWrapper?: boolean; }) => { + const id = useId(); + return withoutScrollWrapper === true ? ( {hasMaxHeight ? ( - + {children} @@ -62,7 +68,10 @@ export const DropdownMenuItemsContainer = ({ )} ) : ( - + { const isMobile = useIsMobile(); return isMobile ? ( - + {children} diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx index 2e38456c4..93825d425 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx @@ -23,7 +23,10 @@ export const ShowPageActivityContainer = ({ ); return !isNewViewableRecordLoading ? ( - + ) : ( - + {children} diff --git a/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx b/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx index 289503dc0..72458d3be 100644 --- a/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx +++ b/packages/twenty-front/src/modules/ui/layout/tab/components/TabList.tsx @@ -7,8 +7,9 @@ import { TabListScope } from '@/ui/layout/tab/scopes/TabListScope'; import { TabListFromUrlOptionalEffect } from '@/ui/layout/tab/components/TabListFromUrlOptionalEffect'; import { LayoutCard } from '@/ui/layout/tab/types/LayoutCard'; -import { Tab } from './Tab'; +import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { useEffect } from 'react'; +import { Tab } from './Tab'; export type SingleTabProps = { title: string; @@ -70,26 +71,32 @@ export const TabList = ({ componentInstanceId={tabListInstanceId} tabListIds={tabs.map((tab) => tab.id)} /> - - {visibleTabs.map((tab) => ( - { - if (!behaveAsLinks) { - setActiveTabId(tab.id); - } - }} - /> - ))} - + + + {visibleTabs.map((tab) => ( + { + if (!behaveAsLinks) { + setActiveTabId(tab.id); + } + }} + /> + ))} + + ); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx b/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx index c5140f583..597ea6fcd 100644 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx @@ -2,15 +2,17 @@ import styled from '@emotion/styled'; import { OverlayScrollbars } from 'overlayscrollbars'; import { useOverlayScrollbars } from 'overlayscrollbars-react'; import { useEffect, useRef } from 'react'; -import { useSetRecoilState } from 'recoil'; import { ContextProviderName, getContextByProviderName, } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts'; -import { useScrollStates } from '@/ui/utilities/scroll/hooks/internal/useScrollStates'; -import { overlayScrollbarsState } from '@/ui/utilities/scroll/states/overlayScrollbarsState'; +import { ScrollWrapperComponentInstanceContext } from '@/ui/utilities/scroll/states/contexts/ScrollWrapperComponentInstanceContext'; +import { scrollWrapperInstanceComponentState } from '@/ui/utilities/scroll/states/scrollWrapperInstanceComponentState'; +import { scrollWrapperScrollLeftComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollLeftComponentState'; +import { scrollWrapperScrollTopComponentState } from '@/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import 'overlayscrollbars/overlayscrollbars.css'; const StyledScrollWrapper = styled.div<{ scrollHide?: boolean }>` @@ -31,41 +33,52 @@ const StyledInnerContainer = styled.div` export type ScrollWrapperProps = { children: React.ReactNode; className?: string; - enableXScroll?: boolean; - enableYScroll?: boolean; + defaultEnableXScroll?: boolean; + defaultEnableYScroll?: boolean; contextProviderName: ContextProviderName; scrollHide?: boolean; + componentInstanceId: string; }; export const ScrollWrapper = ({ + componentInstanceId, children, className, - enableXScroll = true, - enableYScroll = true, + defaultEnableXScroll = true, + defaultEnableYScroll = true, contextProviderName, scrollHide = false, }: ScrollWrapperProps) => { const scrollableRef = useRef(null); const Context = getContextByProviderName(contextProviderName); - const { scrollTopComponentState, scrollLeftComponentState } = - useScrollStates(contextProviderName); - const setScrollTop = useSetRecoilState(scrollTopComponentState); - const setScrollLeft = useSetRecoilState(scrollLeftComponentState); + const setScrollTop = useSetRecoilComponentStateV2( + scrollWrapperScrollTopComponentState, + componentInstanceId, + ); + + const setScrollLeft = useSetRecoilComponentStateV2( + scrollWrapperScrollLeftComponentState, + componentInstanceId, + ); + const handleScroll = (overlayScroll: OverlayScrollbars) => { const target = overlayScroll.elements().scrollOffsetElement; setScrollTop(target.scrollTop); setScrollLeft(target.scrollLeft); }; - const setOverlayScrollbars = useSetRecoilState(overlayScrollbarsState); + const setOverlayScrollbars = useSetRecoilComponentStateV2( + scrollWrapperInstanceComponentState, + componentInstanceId, + ); const [initialize, instance] = useOverlayScrollbars({ options: { scrollbars: { autoHide: 'scroll' }, overflow: { - x: enableXScroll ? undefined : 'hidden', - y: enableYScroll ? undefined : 'hidden', + x: defaultEnableXScroll ? undefined : 'hidden', + y: defaultEnableYScroll ? undefined : 'hidden', }, }, events: { @@ -84,19 +97,23 @@ export const ScrollWrapper = ({ }, [instance, setOverlayScrollbars]); return ( - - - {children} - - + + {children} + + + ); }; diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/internal/useScrollStates.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/internal/useScrollStates.ts deleted file mode 100644 index 769a17d49..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/internal/useScrollStates.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - ContextProviderName, - getContextByProviderName, -} from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts'; -import { scrollLeftComponentState } from '@/ui/utilities/scroll/states/scrollLeftComponentState'; -import { scrollTopComponentState } from '@/ui/utilities/scroll/states/scrollTopComponentState'; - -import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; - -import { useContext } from 'react'; - -export const useScrollStates = (contextProviderName: ContextProviderName) => { - const Context = getContextByProviderName(contextProviderName); - const context = useContext(Context); - - if (!context) { - throw new Error('Context not found'); - } - - const { id: scopeId } = context; - - return { - scrollLeftComponentState: extractComponentState( - scrollLeftComponentState, - scopeId, - ), - scrollTopComponentState: extractComponentState( - scrollTopComponentState, - scopeId, - ), - }; -}; diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollLeftValue.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollLeftValue.ts deleted file mode 100644 index e8ea24cfb..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollLeftValue.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ContextProviderName } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts'; -import { useScrollStates } from '@/ui/utilities/scroll/hooks/internal/useScrollStates'; -import { useRecoilValue } from 'recoil'; - -export const useScrollLeftValue = ( - contextProviderName: ContextProviderName, -) => { - const { scrollLeftComponentState } = useScrollStates(contextProviderName); - return useRecoilValue(scrollLeftComponentState); -}; diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollTopValue.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollTopValue.ts deleted file mode 100644 index 926d72b00..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollTopValue.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ContextProviderName } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts'; -import { useScrollStates } from '@/ui/utilities/scroll/hooks/internal/useScrollStates'; -import { useRecoilValue } from 'recoil'; - -export const useScrollTopValue = (contextProviderName: ContextProviderName) => { - const { scrollTopComponentState } = useScrollStates(contextProviderName); - return useRecoilValue(scrollTopComponentState); -}; diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useToggleScrollWrapper.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useToggleScrollWrapper.ts new file mode 100644 index 000000000..5264d50e5 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useToggleScrollWrapper.ts @@ -0,0 +1,34 @@ +import { scrollWrapperInstanceComponentState } from '@/ui/utilities/scroll/states/scrollWrapperInstanceComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; + +export const useToggleScrollWrapper = () => { + const instanceOverlay = useRecoilComponentValueV2( + scrollWrapperInstanceComponentState, + ); + + const toggleScrollXWrapper = (isEnabled: boolean) => { + if (!instanceOverlay) { + return; + } + + instanceOverlay.options({ + overflow: { + x: isEnabled ? 'scroll' : 'hidden', + }, + }); + }; + + const toggleScrollYWrapper = (isEnabled: boolean) => { + if (!instanceOverlay) { + return; + } + + instanceOverlay.options({ + overflow: { + y: isEnabled ? 'scroll' : 'hidden', + }, + }); + }; + + return { toggleScrollXWrapper, toggleScrollYWrapper }; +}; diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/states/contexts/ScrollWrapperComponentInstanceContext.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/states/contexts/ScrollWrapperComponentInstanceContext.ts new file mode 100644 index 000000000..bd57ec620 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/states/contexts/ScrollWrapperComponentInstanceContext.ts @@ -0,0 +1,4 @@ +import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext'; + +export const ScrollWrapperComponentInstanceContext = + createComponentInstanceContext(); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/states/overlayScrollbarsState.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/states/overlayScrollbarsState.ts deleted file mode 100644 index 784fc12d0..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/states/overlayScrollbarsState.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { OverlayScrollbars } from 'overlayscrollbars'; -import { createState } from 'twenty-ui'; - -export const overlayScrollbarsState = createState({ - key: 'scroll/overlayScrollbarsState', - defaultValue: null, -}); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollLeftComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollLeftComponentState.ts deleted file mode 100644 index 1e125cd27..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollLeftComponentState.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; - -export const scrollLeftComponentState = createComponentState({ - key: 'scroll/scrollLeftComponentState', - defaultValue: 0, -}); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollPositionState.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollPositionState.ts deleted file mode 100644 index 9dbd6a9ae..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollPositionState.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState'; - -export const scrollPositionState = createFamilyState({ - key: 'scroll/scrollPositionState', - defaultValue: 0, -}); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollTopComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollTopComponentState.ts deleted file mode 100644 index 2bc2365d8..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollTopComponentState.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; - -export const scrollTopComponentState = createComponentState({ - key: 'scroll/scrollTopComponentState', - defaultValue: 0, -}); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperInstanceComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperInstanceComponentState.ts new file mode 100644 index 000000000..f2069bf32 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperInstanceComponentState.ts @@ -0,0 +1,10 @@ +import { ScrollWrapperComponentInstanceContext } from '@/ui/utilities/scroll/states/contexts/ScrollWrapperComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; +import { OverlayScrollbars } from 'overlayscrollbars'; + +export const scrollWrapperInstanceComponentState = + createComponentStateV2({ + key: 'scrollWrapperInstanceComponentState', + defaultValue: null, + componentInstanceContext: ScrollWrapperComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperScrollLeftComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperScrollLeftComponentState.ts new file mode 100644 index 000000000..ecb48fe56 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperScrollLeftComponentState.ts @@ -0,0 +1,9 @@ +import { ScrollWrapperComponentInstanceContext } from '@/ui/utilities/scroll/states/contexts/ScrollWrapperComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; + +export const scrollWrapperScrollLeftComponentState = + createComponentStateV2({ + key: 'scrollWrapperScrollLeftComponentState', + defaultValue: 0, + componentInstanceContext: ScrollWrapperComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState.ts new file mode 100644 index 000000000..c8bf94431 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/states/scrollWrapperScrollTopComponentState.ts @@ -0,0 +1,9 @@ +import { ScrollWrapperComponentInstanceContext } from '@/ui/utilities/scroll/states/contexts/ScrollWrapperComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; + +export const scrollWrapperScrollTopComponentState = + createComponentStateV2({ + key: 'scrollWrapperScrollTopComponentState', + defaultValue: 0, + componentInstanceContext: ScrollWrapperComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/views/utils/mapColumnDefinitionToViewField.ts b/packages/twenty-front/src/modules/views/utils/mapColumnDefinitionToViewField.ts index 359739876..7b00889bb 100644 --- a/packages/twenty-front/src/modules/views/utils/mapColumnDefinitionToViewField.ts +++ b/packages/twenty-front/src/modules/views/utils/mapColumnDefinitionToViewField.ts @@ -14,6 +14,5 @@ export const mapColumnDefinitionsToViewFields = ( size: columnDefinition.size, isVisible: columnDefinition.isVisible ?? true, definition: columnDefinition, - aggregateOperation: columnDefinition.aggregateOperation, })); }; diff --git a/packages/twenty-front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts b/packages/twenty-front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts index 95b7b1695..1c8ef4cd3 100644 --- a/packages/twenty-front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts +++ b/packages/twenty-front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts @@ -47,7 +47,6 @@ export const mapViewFieldsToColumnDefinitions = ({ isLabelIdentifier, isVisible: isLabelIdentifier || viewField.isVisible, viewFieldId: viewField.id, - aggregateOperation: viewField.aggregateOperation, isSortable: correspondingColumnDefinition.isSortable, isFilterable: correspondingColumnDefinition.isFilterable, defaultValue: correspondingColumnDefinition.defaultValue, diff --git a/packages/twenty-front/src/pages/settings/Releases.tsx b/packages/twenty-front/src/pages/settings/Releases.tsx index 9e20f9c95..182ef9bef 100644 --- a/packages/twenty-front/src/pages/settings/Releases.tsx +++ b/packages/twenty-front/src/pages/settings/Releases.tsx @@ -118,7 +118,10 @@ export const Releases = () => { ]} > - + {releases.map((release) => (