diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index 78c7f83640..ccf431f483 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -3128,13 +3128,6 @@ export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; } export type DeleteUserAccountMutation = { __typename?: 'Mutation', deleteUserAccount: { __typename?: 'User', id: string } }; -export type CreateViewFieldMutationVariables = Exact<{ - data: ViewFieldCreateInput; -}>; - - -export type CreateViewFieldMutation = { __typename?: 'Mutation', createOneViewField: { __typename?: 'ViewField', id: string, fieldName: string, isVisible: boolean, sizeInPx: number, index: number } }; - export type CreateViewFieldsMutationVariables = Exact<{ data: Array | ViewFieldCreateManyInput; }>; @@ -5848,43 +5841,6 @@ export function useDeleteUserAccountMutation(baseOptions?: Apollo.MutationHookOp export type DeleteUserAccountMutationHookResult = ReturnType; export type DeleteUserAccountMutationResult = Apollo.MutationResult; export type DeleteUserAccountMutationOptions = Apollo.BaseMutationOptions; -export const CreateViewFieldDocument = gql` - mutation CreateViewField($data: ViewFieldCreateInput!) { - createOneViewField(data: $data) { - id - fieldName - isVisible - sizeInPx - index - } -} - `; -export type CreateViewFieldMutationFn = Apollo.MutationFunction; - -/** - * __useCreateViewFieldMutation__ - * - * To run a mutation, you first call `useCreateViewFieldMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useCreateViewFieldMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [createViewFieldMutation, { data, loading, error }] = useCreateViewFieldMutation({ - * variables: { - * data: // value for 'data' - * }, - * }); - */ -export function useCreateViewFieldMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(CreateViewFieldDocument, options); - } -export type CreateViewFieldMutationHookResult = ReturnType; -export type CreateViewFieldMutationResult = Apollo.MutationResult; -export type CreateViewFieldMutationOptions = Apollo.BaseMutationOptions; export const CreateViewFieldsDocument = gql` mutation CreateViewFields($data: [ViewFieldCreateManyInput!]!) { createManyViewField(data: $data) { diff --git a/front/src/modules/companies/table/components/CompanyTable.tsx b/front/src/modules/companies/table/components/CompanyTable.tsx index cd5ba3d7d3..7ff19e7535 100644 --- a/front/src/modules/companies/table/components/CompanyTable.tsx +++ b/front/src/modules/companies/table/components/CompanyTable.tsx @@ -10,6 +10,7 @@ import { EntityTable } from '@/ui/table/components/EntityTable'; import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData'; import { TableContext } from '@/ui/table/states/TableContext'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; +import { useTableViewFields } from '@/views/hooks/useTableViewFields'; import { useViewSorts } from '@/views/hooks/useViewSorts'; import { currentViewIdState } from '@/views/states/currentViewIdState'; import { @@ -24,6 +25,11 @@ import { defaultOrderBy } from '../../queries'; export function CompanyTable() { const currentViewId = useRecoilValue(currentViewIdState); const orderBy = useRecoilScopedValue(sortsOrderByScopedState, TableContext); + + const { handleColumnsChange } = useTableViewFields({ + objectName: 'company', + viewFieldDefinitions: companyViewFields, + }); const { updateSorts } = useViewSorts({ availableSorts, Context: TableContext, @@ -38,18 +44,17 @@ export function CompanyTable() { return ( <> } availableSorts={availableSorts} + onColumnsChange={handleColumnsChange} onSortsUpdate={currentViewId ? updateSorts : undefined} useUpdateEntityMutation={useUpdateOneCompanyMutation} /> diff --git a/front/src/modules/companies/table/components/CompanyTableMockData.tsx b/front/src/modules/companies/table/components/CompanyTableMockData.tsx index f28c26c433..c1cc8b2bb0 100644 --- a/front/src/modules/companies/table/components/CompanyTableMockData.tsx +++ b/front/src/modules/companies/table/components/CompanyTableMockData.tsx @@ -2,32 +2,21 @@ import { useEffect } from 'react'; import { useSetRecoilState } from 'recoil'; import { useSetEntityTableData } from '@/ui/table/hooks/useSetEntityTableData'; -import { entityTableDimensionsState } from '@/ui/table/states/entityTableDimensionsState'; -import { viewFieldsState } from '@/ui/table/states/viewFieldsState'; +import { tableColumnsState } from '@/ui/table/states/tableColumnsState'; import { companyViewFields } from '../../constants/companyViewFields'; import { mockedCompaniesData } from './companies-mock-data'; export function CompanyTableMockData() { - const setEntityTableDimensions = useSetRecoilState( - entityTableDimensionsState, - ); - const setViewFieldsState = useSetRecoilState(viewFieldsState); + const setColumns = useSetRecoilState(tableColumnsState); const setEntityTableData = useSetEntityTableData(); setEntityTableData(mockedCompaniesData, []); useEffect(() => { - setViewFieldsState({ - objectName: 'company', - viewFields: companyViewFields, - }); - setEntityTableDimensions((prevState) => ({ - ...prevState, - numberOfColumns: companyViewFields.length, - })); - }, [setEntityTableDimensions, setViewFieldsState]); + setColumns(companyViewFields); + }, [setColumns]); return <>; } diff --git a/front/src/modules/people/hooks/useSetPeopleEntityTable.ts b/front/src/modules/people/hooks/useSetPeopleEntityTable.ts index aa7513e156..9ae902b141 100644 --- a/front/src/modules/people/hooks/useSetPeopleEntityTable.ts +++ b/front/src/modules/people/hooks/useSetPeopleEntityTable.ts @@ -1,17 +1,17 @@ import { useLocation } from 'react-router-dom'; import { useRecoilCallback } from 'recoil'; +import { availableFiltersScopedState } from '@/ui/filter-n-sort/states/availableFiltersScopedState'; +import { useResetTableRowSelection } from '@/ui/table/hooks/useResetTableRowSelection'; +import { isFetchingEntityTableDataState } from '@/ui/table/states/isFetchingEntityTableDataState'; +import { numberOfTableRowsState } from '@/ui/table/states/numberOfTableRowsState'; +import { TableContext } from '@/ui/table/states/TableContext'; +import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState'; import { currentPageLocationState } from '@/ui/utilities/loading-state/states/currentPageLocationState'; import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId'; import { GetPeopleQuery } from '~/generated/graphql'; +import { peopleFilters } from '~/pages/people/people-filters'; -import { peopleFilters } from '../../../pages/people/people-filters'; -import { availableFiltersScopedState } from '../../ui/filter-n-sort/states/availableFiltersScopedState'; -import { useResetTableRowSelection } from '../../ui/table/hooks/useResetTableRowSelection'; -import { entityTableDimensionsState } from '../../ui/table/states/entityTableDimensionsState'; -import { isFetchingEntityTableDataState } from '../../ui/table/states/isFetchingEntityTableDataState'; -import { TableContext } from '../../ui/table/states/TableContext'; -import { tableRowIdsState } from '../../ui/table/states/tableRowIdsState'; import { peopleCityFamilyState } from '../states/peopleCityFamilyState'; import { peopleCompanyFamilyState } from '../states/peopleCompanyFamilyState'; import { peopleCreatedAtFamilyState } from '../states/peopleCreatedAtFamilyState'; @@ -124,10 +124,7 @@ export function useSetPeopleEntityTable() { resetTableRowSelection(); - set(entityTableDimensionsState, { - numberOfColumns: 10, - numberOfRows: peopleIds.length, - }); + set(numberOfTableRowsState, peopleIds.length); set(availableFiltersScopedState(tableContextScopeId), peopleFilters); diff --git a/front/src/modules/people/table/components/PeopleTable.tsx b/front/src/modules/people/table/components/PeopleTable.tsx index 0e4bd2ba7c..8d5ee7f31b 100644 --- a/front/src/modules/people/table/components/PeopleTable.tsx +++ b/front/src/modules/people/table/components/PeopleTable.tsx @@ -10,6 +10,7 @@ import { EntityTable } from '@/ui/table/components/EntityTable'; import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData'; import { TableContext } from '@/ui/table/states/TableContext'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; +import { useTableViewFields } from '@/views/hooks/useTableViewFields'; import { useViewSorts } from '@/views/hooks/useViewSorts'; import { currentViewIdState } from '@/views/states/currentViewIdState'; import { @@ -24,6 +25,11 @@ import { defaultOrderBy } from '../../queries'; export function PeopleTable() { const currentViewId = useRecoilValue(currentViewIdState); const orderBy = useRecoilScopedValue(sortsOrderByScopedState, TableContext); + + const { handleColumnsChange } = useTableViewFields({ + objectName: 'person', + viewFieldDefinitions: peopleViewFields, + }); const { updateSorts } = useViewSorts({ availableSorts, Context: TableContext, @@ -38,18 +44,17 @@ export function PeopleTable() { return ( <> } availableSorts={availableSorts} + onColumnsChange={handleColumnsChange} onSortsUpdate={currentViewId ? updateSorts : undefined} useUpdateEntityMutation={useUpdateOnePersonMutation} /> diff --git a/front/src/modules/ui/table/components/EntityTable.tsx b/front/src/modules/ui/table/components/EntityTable.tsx index d4e4d3af38..3565c0f023 100644 --- a/front/src/modules/ui/table/components/EntityTable.tsx +++ b/front/src/modules/ui/table/components/EntityTable.tsx @@ -2,6 +2,10 @@ import { useRef } from 'react'; import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; +import type { + ViewFieldDefinition, + ViewFieldMetadata, +} from '@/ui/editable-field/types/ViewField'; import { SelectedSortType, SortType } from '@/ui/filter-n-sort/types/interface'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; @@ -90,6 +94,7 @@ type OwnProps = { viewName: string; viewIcon?: React.ReactNode; availableSorts?: Array>; + onColumnsChange?: (columns: ViewFieldDefinition[]) => void; onSortsUpdate?: (sorts: Array>) => void; onRowSelectionChange?: (rowSelection: string[]) => void; useUpdateEntityMutation: any; @@ -99,6 +104,7 @@ export function EntityTable({ viewName, viewIcon, availableSorts, + onColumnsChange, onSortsUpdate, useUpdateEntityMutation, }: OwnProps) { @@ -132,11 +138,12 @@ export function EntityTable({ viewName={viewName} viewIcon={viewIcon} availableSorts={availableSorts} + onColumnsChange={onColumnsChange} onSortsUpdate={onSortsUpdate} /> - + diff --git a/front/src/modules/ui/table/components/EntityTableColumnMenu.tsx b/front/src/modules/ui/table/components/EntityTableColumnMenu.tsx index 3afc80d99a..770789b659 100644 --- a/front/src/modules/ui/table/components/EntityTableColumnMenu.tsx +++ b/front/src/modules/ui/table/components/EntityTableColumnMenu.tsx @@ -1,6 +1,7 @@ import { cloneElement, ComponentProps, useRef } from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; import { IconButton } from '@/ui/button/components/IconButton'; import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu'; @@ -9,32 +10,27 @@ import { DropdownMenuItemsContainer } from '@/ui/dropdown/components/DropdownMen import { IconPlus } from '@/ui/icon'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; -import type { - ViewFieldDefinition, - ViewFieldMetadata, -} from '../../editable-field/types/ViewField'; +import { hiddenTableColumnsState } from '../states/tableColumnsState'; const StyledColumnMenu = styled(DropdownMenu)` font-weight: ${({ theme }) => theme.font.weight.regular}; `; type EntityTableColumnMenuProps = { - onAddViewField: ( - viewFieldDefinition: ViewFieldDefinition, - ) => void; + onAddColumn: (columnId: string) => void; onClickOutside?: () => void; - viewFieldDefinitions: ViewFieldDefinition[]; } & ComponentProps<'div'>; export const EntityTableColumnMenu = ({ - onAddViewField, + onAddColumn, onClickOutside = () => undefined, - viewFieldDefinitions, ...props }: EntityTableColumnMenuProps) => { const ref = useRef(null); const theme = useTheme(); + const hiddenColumns = useRecoilValue(hiddenTableColumnsState); + useListenClickOutside({ refs: [ref], callback: onClickOutside, @@ -43,21 +39,21 @@ export const EntityTableColumnMenu = ({ return ( - {viewFieldDefinitions.map((viewFieldDefinition) => ( + {hiddenColumns.map((column) => ( } - onClick={() => onAddViewField(viewFieldDefinition)} + onClick={() => onAddColumn(column.id)} /> } > - {viewFieldDefinition.columnIcon && - cloneElement(viewFieldDefinition.columnIcon, { + {column.columnIcon && + cloneElement(column.columnIcon, { size: theme.icon.size.md, })} - {viewFieldDefinition.columnLabel} + {column.columnLabel} ))} diff --git a/front/src/modules/ui/table/components/EntityTableHeader.tsx b/front/src/modules/ui/table/components/EntityTableHeader.tsx index e999449cc5..89b4db82f3 100644 --- a/front/src/modules/ui/table/components/EntityTableHeader.tsx +++ b/front/src/modules/ui/table/components/EntityTableHeader.tsx @@ -1,5 +1,4 @@ import { useCallback, useState } from 'react'; -import { getOperationName } from '@apollo/client/utilities'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil'; @@ -11,21 +10,14 @@ import type { } from '@/ui/editable-field/types/ViewField'; import { IconPlus } from '@/ui/icon'; import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer'; -import { GET_VIEW_FIELDS } from '@/views/queries/select'; -import { currentViewIdState } from '@/views/states/currentViewIdState'; -import { - useCreateViewFieldMutation, - useUpdateViewFieldMutation, -} from '~/generated/graphql'; -import { toViewFieldInput } from '../hooks/useLoadViewFields'; import { resizeFieldOffsetState } from '../states/resizeFieldOffsetState'; import { - addableViewFieldDefinitionsState, - columnWidthByViewFieldIdState, - viewFieldsState, - visibleViewFieldsState, -} from '../states/viewFieldsState'; + hiddenTableColumnsState, + tableColumnsByIdState, + tableColumnsState, + visibleTableColumnsState, +} from '../states/tableColumnsState'; import { ColumnHead } from './ColumnHead'; import { EntityTableColumnMenu } from './EntityTableColumnMenu'; @@ -86,17 +78,18 @@ const StyledEntityTableColumnMenu = styled(EntityTableColumnMenu)` z-index: ${({ theme }) => theme.lastLayerZIndex}; `; -export function EntityTableHeader() { +export type EntityTableHeaderProps = { + onColumnsChange?: (columns: ViewFieldDefinition[]) => void; +}; + +export function EntityTableHeader({ onColumnsChange }: EntityTableHeaderProps) { const theme = useTheme(); - const [{ objectName }, setViewFieldsState] = useRecoilState(viewFieldsState); - const currentViewId = useRecoilValue(currentViewIdState); - const viewFields = useRecoilValue(visibleViewFieldsState); - const columnWidths = useRecoilValue(columnWidthByViewFieldIdState); - const addableViewFieldDefinitions = useRecoilValue( - addableViewFieldDefinitionsState, - ); + const [columns, setColumns] = useRecoilState(tableColumnsState); const [offset, setOffset] = useRecoilState(resizeFieldOffsetState); + const columnsById = useRecoilValue(tableColumnsByIdState); + const hiddenColumns = useRecoilValue(hiddenTableColumnsState); + const visibleColumns = useRecoilValue(visibleTableColumnsState); const [initialPointerPositionX, setInitialPointerPositionX] = useState< number | null @@ -104,9 +97,6 @@ export function EntityTableHeader() { const [resizedFieldId, setResizedFieldId] = useState(null); const [isColumnMenuOpen, setIsColumnMenuOpen] = useState(false); - const [createViewFieldMutation] = useCreateViewFieldMutation(); - const [updateViewFieldMutation] = useUpdateViewFieldMutation(); - const handleResizeHandlerStart = useCallback((positionX: number) => { setInitialPointerPositionX(positionX); }, []); @@ -126,37 +116,28 @@ export function EntityTableHeader() { const nextWidth = Math.round( Math.max( - columnWidths[resizedFieldId] + + columnsById[resizedFieldId].columnSize + snapshot.getLoadable(resizeFieldOffsetState).valueOrThrow(), COLUMN_MIN_WIDTH, ), ); - if (nextWidth !== columnWidths[resizedFieldId]) { - // Optimistic update to avoid "bouncing width" visual effect on resize. - setViewFieldsState((previousState) => ({ - ...previousState, - viewFields: previousState.viewFields.map((viewField) => - viewField.id === resizedFieldId - ? { ...viewField, columnSize: nextWidth } - : viewField, - ), - })); + if (nextWidth !== columnsById[resizedFieldId].columnSize) { + const nextColumns = columns.map((column) => + column.id === resizedFieldId + ? { ...column, columnSize: nextWidth } + : column, + ); - updateViewFieldMutation({ - variables: { - data: { sizeInPx: nextWidth }, - where: { id: resizedFieldId }, - }, - refetchQueries: [getOperationName(GET_VIEW_FIELDS) ?? ''], - }); + setColumns(nextColumns); + onColumnsChange?.(nextColumns); } set(resizeFieldOffsetState, 0); setInitialPointerPositionX(null); setResizedFieldId(null); }, - [resizedFieldId, columnWidths, setResizedFieldId], + [resizedFieldId, columnsById, setResizedFieldId], ); useTrackPointer({ @@ -170,26 +151,18 @@ export function EntityTableHeader() { setIsColumnMenuOpen((previousValue) => !previousValue); }, []); - const handleAddViewField = useCallback( - (viewFieldDefinition: ViewFieldDefinition) => { + const handleAddColumn = useCallback( + (columnId: string) => { setIsColumnMenuOpen(false); - if (!objectName) return; + const nextColumns = columns.map((column) => + column.id === columnId ? { ...column, isVisible: true } : column, + ); - createViewFieldMutation({ - variables: { - data: { - ...toViewFieldInput(objectName, { - ...viewFieldDefinition, - columnOrder: viewFields.length + 1, - }), - view: { connect: { id: currentViewId } }, - }, - }, - refetchQueries: [getOperationName(GET_VIEW_FIELDS) ?? ''], - }); + setColumns(nextColumns); + onColumnsChange?.(nextColumns); }, - [createViewFieldMutation, currentViewId, objectName, viewFields.length], + [columns, onColumnsChange, setColumns], ); return ( @@ -205,31 +178,31 @@ export function EntityTableHeader() { - {viewFields.map((viewField) => ( + {visibleColumns.map((column) => ( { - setResizedFieldId(viewField.id); + setResizedFieldId(column.id); }} /> ))} - {addableViewFieldDefinitions.length > 0 && ( + {hiddenColumns.length > 0 && ( {isColumnMenuOpen && ( )} diff --git a/front/src/modules/ui/table/components/EntityTableRow.tsx b/front/src/modules/ui/table/components/EntityTableRow.tsx index c39b7f1907..b71306a9f8 100644 --- a/front/src/modules/ui/table/components/EntityTableRow.tsx +++ b/front/src/modules/ui/table/components/EntityTableRow.tsx @@ -1,8 +1,8 @@ import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; +import { visibleTableColumnsState } from '../states/tableColumnsState'; import { ViewFieldContext } from '../states/ViewFieldContext'; -import { visibleViewFieldsState } from '../states/viewFieldsState'; import { CheckboxCell } from './CheckboxCell'; import { EntityTableCell } from './EntityTableCell'; @@ -13,7 +13,7 @@ const StyledRow = styled.tr<{ selected: boolean }>` `; export function EntityTableRow({ rowId }: { rowId: string }) { - const viewFields = useRecoilValue(visibleViewFieldsState); + const columns = useRecoilValue(visibleTableColumnsState); return ( - {viewFields.map((viewField, columnIndex) => { + {columns.map((column, columnIndex) => { return ( - + ); diff --git a/front/src/modules/ui/table/components/GenericEntityTableData.tsx b/front/src/modules/ui/table/components/GenericEntityTableData.tsx index f284571479..90388589fb 100644 --- a/front/src/modules/ui/table/components/GenericEntityTableData.tsx +++ b/front/src/modules/ui/table/components/GenericEntityTableData.tsx @@ -1,34 +1,22 @@ import { defaultOrderBy } from '@/people/queries'; -import { - ViewFieldDefinition, - ViewFieldMetadata, -} from '@/ui/editable-field/types/ViewField'; import { FilterDefinition } from '@/ui/filter-n-sort/types/FilterDefinition'; import { useSetEntityTableData } from '@/ui/table/hooks/useSetEntityTableData'; -import { useLoadViewFields } from '../hooks/useLoadViewFields'; - export function GenericEntityTableData({ - objectName, useGetRequest, getRequestResultKey, orderBy = defaultOrderBy, whereFilters, - viewFieldDefinitions, filterDefinitionArray, }: { - objectName: 'company' | 'person'; useGetRequest: any; getRequestResultKey: string; orderBy?: any; whereFilters?: any; - viewFieldDefinitions: ViewFieldDefinition[]; filterDefinitionArray: FilterDefinition[]; }) { const setEntityTableData = useSetEntityTableData(); - useLoadViewFields({ objectName, viewFieldDefinitions }); - useGetRequest({ variables: { orderBy, where: whereFilters }, onCompleted: (data: any) => { diff --git a/front/src/modules/ui/table/hooks/useCurrentEntityId.ts b/front/src/modules/ui/table/hooks/useCurrentEntityId.ts index 05040206de..ae7940735d 100644 --- a/front/src/modules/ui/table/hooks/useCurrentEntityId.ts +++ b/front/src/modules/ui/table/hooks/useCurrentEntityId.ts @@ -2,11 +2,6 @@ import { useContext } from 'react'; import { RowIdContext } from '../states/RowIdContext'; -export type TableDimensions = { - numberOfColumns: number; - numberOfRows: number; -}; - export function useCurrentRowEntityId() { const currentEntityId = useContext(RowIdContext); diff --git a/front/src/modules/ui/table/hooks/useInitializeEntityTable.ts b/front/src/modules/ui/table/hooks/useInitializeEntityTable.ts index 1e7de1c14d..c16d3ef613 100644 --- a/front/src/modules/ui/table/hooks/useInitializeEntityTable.ts +++ b/front/src/modules/ui/table/hooks/useInitializeEntityTable.ts @@ -1,21 +1,12 @@ import { useEffect } from 'react'; -import { useRecoilState, useRecoilValue } from 'recoil'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; -import { entityTableDimensionsState } from '../states/entityTableDimensionsState'; +import { numberOfTableRowsState } from '../states/numberOfTableRowsState'; import { tableRowIdsState } from '../states/tableRowIdsState'; import { useResetTableRowSelection } from './useResetTableRowSelection'; -export type TableDimensions = { - numberOfColumns: number; - numberOfRows: number; -}; - -export function useInitializeEntityTable({ - numberOfColumns, -}: { - numberOfColumns: number; -}) { +export function useInitializeEntityTable() { const resetTableRowSelection = useResetTableRowSelection(); const tableRowIds = useRecoilValue(tableRowIdsState); @@ -24,12 +15,9 @@ export function useInitializeEntityTable({ resetTableRowSelection(); }, [resetTableRowSelection]); - const [, setTableDimensions] = useRecoilState(entityTableDimensionsState); + const setNumberOfTableRows = useSetRecoilState(numberOfTableRowsState); useEffect(() => { - setTableDimensions({ - numberOfColumns, - numberOfRows: tableRowIds?.length, - }); - }, [tableRowIds, numberOfColumns, setTableDimensions]); + setNumberOfTableRows(tableRowIds?.length); + }, [tableRowIds, setNumberOfTableRows]); } diff --git a/front/src/modules/ui/table/hooks/useLoadViewFields.ts b/front/src/modules/ui/table/hooks/useLoadViewFields.ts deleted file mode 100644 index f7cbb56405..0000000000 --- a/front/src/modules/ui/table/hooks/useLoadViewFields.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { getOperationName } from '@apollo/client/utilities'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; - -import type { - ViewFieldDefinition, - ViewFieldMetadata, - ViewFieldTextMetadata, -} from '@/ui/editable-field/types/ViewField'; -import { GET_VIEW_FIELDS } from '@/views/queries/select'; -import { currentViewIdState } from '@/views/states/currentViewIdState'; -import { - SortOrder, - useCreateViewFieldsMutation, - useGetViewFieldsQuery, -} from '~/generated/graphql'; - -import { entityTableDimensionsState } from '../states/entityTableDimensionsState'; -import { viewFieldsState } from '../states/viewFieldsState'; - -const DEFAULT_VIEW_FIELD_METADATA: ViewFieldTextMetadata = { - type: 'text', - placeHolder: '', - fieldName: '', -}; - -export const toViewFieldInput = ( - objectName: 'company' | 'person', - viewFieldDefinition: ViewFieldDefinition, -) => ({ - fieldName: viewFieldDefinition.columnLabel, - index: viewFieldDefinition.columnOrder, - isVisible: viewFieldDefinition.isVisible ?? true, - objectName, - sizeInPx: viewFieldDefinition.columnSize, -}); - -export const useLoadViewFields = ({ - objectName, - viewFieldDefinitions, -}: { - objectName: 'company' | 'person'; - viewFieldDefinitions: ViewFieldDefinition[]; -}) => { - const currentViewId = useRecoilValue(currentViewIdState); - const setEntityTableDimensions = useSetRecoilState( - entityTableDimensionsState, - ); - const setViewFieldsState = useSetRecoilState(viewFieldsState); - - const [createViewFieldsMutation] = useCreateViewFieldsMutation(); - - useGetViewFieldsQuery({ - variables: { - orderBy: { index: SortOrder.Asc }, - where: { - objectName: { equals: objectName }, - viewId: { equals: currentViewId ?? null }, - }, - }, - onCompleted: (data) => { - if (data.viewFields.length) { - const viewFields = data.viewFields.map< - ViewFieldDefinition - >((viewField) => ({ - ...(viewFieldDefinitions.find( - ({ columnLabel }) => viewField.fieldName === columnLabel, - ) || { metadata: DEFAULT_VIEW_FIELD_METADATA }), - id: viewField.id, - columnLabel: viewField.fieldName, - columnOrder: viewField.index, - columnSize: viewField.sizeInPx, - isVisible: viewField.isVisible, - })); - - setViewFieldsState({ objectName, viewFields }); - setEntityTableDimensions((prevState) => ({ - ...prevState, - numberOfColumns: data.viewFields.length, - })); - - return; - } - - // Populate if empty - createViewFieldsMutation({ - variables: { - data: viewFieldDefinitions.map((viewFieldDefinition) => ({ - ...toViewFieldInput(objectName, viewFieldDefinition), - viewId: currentViewId, - })), - }, - refetchQueries: [getOperationName(GET_VIEW_FIELDS) ?? ''], - }); - }, - }); -}; diff --git a/front/src/modules/ui/table/hooks/useMoveSoftFocus.ts b/front/src/modules/ui/table/hooks/useMoveSoftFocus.ts index 800bda596a..9903a1f879 100644 --- a/front/src/modules/ui/table/hooks/useMoveSoftFocus.ts +++ b/front/src/modules/ui/table/hooks/useMoveSoftFocus.ts @@ -1,8 +1,8 @@ import { useRecoilCallback } from 'recoil'; -import { numberOfTableColumnsSelectorState } from '../states/numberOfTableColumnsSelectorState'; -import { numberOfTableRowsSelectorState } from '../states/numberOfTableRowsSelectorState'; +import { numberOfTableRowsState } from '../states/numberOfTableRowsState'; import { softFocusPositionState } from '../states/softFocusPositionState'; +import { numberOfTableColumnsState } from '../states/tableColumnsState'; import { useSetSoftFocusPosition } from './useSetSoftFocusPosition'; @@ -39,7 +39,7 @@ export function useMoveSoftFocus() { .valueOrThrow(); const numberOfTableRows = snapshot - .getLoadable(numberOfTableRowsSelectorState) + .getLoadable(numberOfTableRowsState) .valueOrThrow(); let newRowNumber = softFocusPosition.row + 1; @@ -64,11 +64,11 @@ export function useMoveSoftFocus() { .valueOrThrow(); const numberOfTableColumns = snapshot - .getLoadable(numberOfTableColumnsSelectorState) + .getLoadable(numberOfTableColumnsState) .valueOrThrow(); const numberOfTableRows = snapshot - .getLoadable(numberOfTableRowsSelectorState) + .getLoadable(numberOfTableRowsState) .valueOrThrow(); const currentColumnNumber = softFocusPosition.column; @@ -112,7 +112,7 @@ export function useMoveSoftFocus() { .valueOrThrow(); const numberOfTableColumns = snapshot - .getLoadable(numberOfTableColumnsSelectorState) + .getLoadable(numberOfTableColumnsState) .valueOrThrow(); const currentColumnNumber = softFocusPosition.column; diff --git a/front/src/modules/ui/table/hooks/useSetEntityTableData.ts b/front/src/modules/ui/table/hooks/useSetEntityTableData.ts index 69765571c3..983f16837e 100644 --- a/front/src/modules/ui/table/hooks/useSetEntityTableData.ts +++ b/front/src/modules/ui/table/hooks/useSetEntityTableData.ts @@ -3,13 +3,14 @@ import { useRecoilCallback } from 'recoil'; import { availableFiltersScopedState } from '@/ui/filter-n-sort/states/availableFiltersScopedState'; import { FilterDefinition } from '@/ui/filter-n-sort/types/FilterDefinition'; import { useResetTableRowSelection } from '@/ui/table/hooks/useResetTableRowSelection'; -import { entityTableDimensionsState } from '@/ui/table/states/entityTableDimensionsState'; -import { isFetchingEntityTableDataState } from '@/ui/table/states/isFetchingEntityTableDataState'; import { TableContext } from '@/ui/table/states/TableContext'; import { tableEntitiesFamilyState } from '@/ui/table/states/tableEntitiesFamilyState'; import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState'; import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId'; +import { isFetchingEntityTableDataState } from '../states/isFetchingEntityTableDataState'; +import { numberOfTableRowsState } from '../states/numberOfTableRowsState'; + export function useSetEntityTableData() { const resetTableRowSelection = useResetTableRowSelection(); @@ -43,10 +44,7 @@ export function useSetEntityTableData() { resetTableRowSelection(); - set(entityTableDimensionsState, (prevState) => ({ - ...prevState, - numberOfRows: entityIds.length, - })); + set(numberOfTableRowsState, entityIds.length); set(availableFiltersScopedState(tableContextScopeId), filters); diff --git a/front/src/modules/views/components/OptionsDropdownButton.tsx b/front/src/modules/ui/table/options/components/TableOptionsDropdownButton.tsx similarity index 64% rename from front/src/modules/views/components/OptionsDropdownButton.tsx rename to front/src/modules/ui/table/options/components/TableOptionsDropdownButton.tsx index d574f13a6a..c5ebb98bea 100644 --- a/front/src/modules/views/components/OptionsDropdownButton.tsx +++ b/front/src/modules/ui/table/options/components/TableOptionsDropdownButton.tsx @@ -1,7 +1,6 @@ import { useCallback, useState } from 'react'; -import { getOperationName } from '@apollo/client/utilities'; import { useTheme } from '@emotion/react'; -import { useRecoilValue } from 'recoil'; +import { useRecoilState, useRecoilValue } from 'recoil'; import { IconButton } from '@/ui/button/components/IconButton'; import { DropdownMenuHeader } from '@/ui/dropdown/components/DropdownMenuHeader'; @@ -16,16 +15,15 @@ import DropdownButton from '@/ui/filter-n-sort/components/DropdownButton'; import { FiltersHotkeyScope } from '@/ui/filter-n-sort/types/FiltersHotkeyScope'; import { IconChevronLeft, IconMinus, IconPlus, IconTag } from '@/ui/icon'; import { - hiddenViewFieldsState, - visibleViewFieldsState, -} from '@/ui/table/states/viewFieldsState'; -import { useUpdateViewFieldMutation } from '~/generated/graphql'; + hiddenTableColumnsState, + tableColumnsState, + visibleTableColumnsState, +} from '@/ui/table/states/tableColumnsState'; -import { GET_VIEW_FIELDS } from '../queries/select'; +import { TableOptionsDropdownSection } from './TableOptionsDropdownSection'; -import { OptionsDropdownSection } from './OptionsDropdownSection'; - -type OptionsDropdownButtonProps = { +type TableOptionsDropdownButtonProps = { + onColumnsChange?: (columns: ViewFieldDefinition[]) => void; HotkeyScope: FiltersHotkeyScope; }; @@ -33,51 +31,52 @@ enum Option { Properties = 'Properties', } -export const OptionsDropdownButton = ({ +export const TableOptionsDropdownButton = ({ + onColumnsChange, HotkeyScope, -}: OptionsDropdownButtonProps) => { +}: TableOptionsDropdownButtonProps) => { const theme = useTheme(); const [isUnfolded, setIsUnfolded] = useState(false); const [selectedOption, setSelectedOption] = useState