diff --git a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx
index d4aec39dc..1657e1e44 100644
--- a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx
+++ b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx
@@ -25,7 +25,6 @@ export const HooksCompanyBoardEffect = () => {
setAvailableFilters,
setAvailableSorts,
setEntityCountInCurrentView,
- setCurrentViewId,
} = useView();
const { currentViewFilters } = useViewInternalStates();
@@ -106,10 +105,6 @@ export const HooksCompanyBoardEffect = () => {
useEffect(() => {
if (!loading && pipeline && pipelineProgresses && companiesData) {
- const viewId = searchParams.get('view');
- if (viewId) {
- //setCurrentViewId(viewId);
- }
setActionBarEntries();
setContextMenuEntries();
updateCompanyBoard(pipeline, pipelineProgresses, companiesData.companies);
@@ -125,7 +120,6 @@ export const HooksCompanyBoardEffect = () => {
setContextMenuEntries,
searchParams,
setEntityCountInCurrentView,
- setCurrentViewId,
]);
return <>>;
diff --git a/front/src/modules/companies/table/components/CompanyTable.tsx b/front/src/modules/companies/table/components/CompanyTable.tsx
index b4d4ec670..ccc70cc9c 100644
--- a/front/src/modules/companies/table/components/CompanyTable.tsx
+++ b/front/src/modules/companies/table/components/CompanyTable.tsx
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
import { getCompaniesOptimisticEffectDefinition } from '@/companies/graphql/optimistic-effect-definitions/getCompaniesOptimisticEffectDefinition';
import { useCompanyTableActionBarEntries } from '@/companies/hooks/useCompanyTableActionBarEntries';
import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries';
+import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
import { DataTable } from '@/ui/data/data-table/components/DataTable';
import { DataTableEffect } from '@/ui/data/data-table/components/DataTableEffect';
import { TableContext } from '@/ui/data/data-table/contexts/TableContext';
@@ -66,6 +67,9 @@ export const CompanyTable = () => {
});
};
+ const { openCompanySpreadsheetImport: onImport } =
+ useSpreadsheetCompanyImport();
+
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
@@ -92,7 +96,7 @@ export const CompanyTable = () => {
}
+ optionsDropdownButton={}
optionsDropdownScopeId="table-dropdown-option"
/>
diff --git a/front/src/modules/people/constants/peopleAvailableColumnDefinitions.tsx b/front/src/modules/people/constants/peopleAvailableFieldDefinitions.tsx
similarity index 98%
rename from front/src/modules/people/constants/peopleAvailableColumnDefinitions.tsx
rename to front/src/modules/people/constants/peopleAvailableFieldDefinitions.tsx
index 03288e5c6..2dbbc7066 100644
--- a/front/src/modules/people/constants/peopleAvailableColumnDefinitions.tsx
+++ b/front/src/modules/people/constants/peopleAvailableFieldDefinitions.tsx
@@ -24,7 +24,7 @@ import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { Company } from '~/generated/graphql';
import { getLogoUrlFromDomainName } from '~/utils';
-export const peopleAvailableColumnDefinitions: ColumnDefinition[] =
+export const peopleAvailableFieldDefinitions: ColumnDefinition[] =
[
{
key: 'displayName',
diff --git a/front/src/modules/people/table/components/PeopleTable.tsx b/front/src/modules/people/table/components/PeopleTable.tsx
index 3c0dcfbaf..62d4e0492 100644
--- a/front/src/modules/people/table/components/PeopleTable.tsx
+++ b/front/src/modules/people/table/components/PeopleTable.tsx
@@ -1,52 +1,86 @@
+import styled from '@emotion/styled';
+
import { getPeopleOptimisticEffectDefinition } from '@/people/graphql/optimistic-effect-definitions/getPeopleOptimisticEffectDefinition';
import { usePersonTableContextMenuEntries } from '@/people/hooks/usePeopleTableContextMenuEntries';
import { usePersonTableActionBarEntries } from '@/people/hooks/usePersonTableActionBarEntries';
+import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
import { DataTable } from '@/ui/data/data-table/components/DataTable';
import { DataTableEffect } from '@/ui/data/data-table/components/DataTableEffect';
import { TableContext } from '@/ui/data/data-table/contexts/TableContext';
import { useUpsertDataTableItem } from '@/ui/data/data-table/hooks/useUpsertDataTableItem';
-import { SortScope } from '@/ui/data/sort/scopes/SortScope';
+import { TableOptionsDropdown } from '@/ui/data/data-table/options/components/TableOptionsDropdown';
+import { ViewBar } from '@/views/components/ViewBar';
+import { ViewBarEffect } from '@/views/components/ViewBarEffect';
+import { useViewFields } from '@/views/hooks/internal/useViewFields';
+import { useView } from '@/views/hooks/useView';
import { ViewScope } from '@/views/scopes/ViewScope';
import {
UpdateOnePersonMutationVariables,
useGetPeopleQuery,
useUpdateOnePersonMutation,
} from '~/generated/graphql';
-import { peopleFilters } from '~/pages/people/people-filters';
+import { peopleAvailableFilters } from '~/pages/people/people-filters';
import { peopleAvailableSorts } from '~/pages/people/people-sorts';
+import PersonTableEffect from './PersonTableEffect';
+
export const PeopleTable = () => {
+ const tableViewScopeId = 'person-table';
+
const [updateEntityMutation] = useUpdateOnePersonMutation();
const upsertDataTableItem = useUpsertDataTableItem();
- const tableViewScopeId = 'people-table';
+ const { persistViewFields } = useViewFields(tableViewScopeId);
+ const { setCurrentViewFields } = useView({ viewScopeId: tableViewScopeId });
const { setContextMenuEntries } = usePersonTableContextMenuEntries();
const { setActionBarEntries } = usePersonTableActionBarEntries();
+ const { openPersonSpreadsheetImport: onImport } =
+ useSpreadsheetPersonImport();
+
+ const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: auto;
+ `;
+
return (
-
-
+ {}}
+ onViewSortsChange={() => {}}
+ onViewFiltersChange={() => {}}
+ >
+
{
- // eslint-disable-next-line no-console
- console.log('persist columns');
+ onColumnsChange: (columns) => {
+ setCurrentViewFields?.(columns);
+ persistViewFields(columns);
},
}}
>
+
+
+ }
+ optionsDropdownScopeId="table-dropdown-option"
+ />
+
+
-
{
}
/>
-
+
);
};
diff --git a/front/src/modules/people/table/components/PersonTableEffect.tsx b/front/src/modules/people/table/components/PersonTableEffect.tsx
new file mode 100644
index 000000000..5f8c66801
--- /dev/null
+++ b/front/src/modules/people/table/components/PersonTableEffect.tsx
@@ -0,0 +1,91 @@
+import { useEffect } from 'react';
+
+import { peopleAvailableFieldDefinitions } from '@/people/constants/peopleAvailableFieldDefinitions';
+import { availableTableColumnsScopedState } from '@/ui/data/data-table/states/availableTableColumnsScopedState';
+import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
+import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState';
+import { tableFiltersScopedState } from '@/ui/data/data-table/states/tableFiltersScopedState';
+import { tableSortsScopedState } from '@/ui/data/data-table/states/tableSortsScopedState';
+import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
+import { useView } from '@/views/hooks/useView';
+import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
+import { ViewType } from '~/generated/graphql';
+import { peopleAvailableFilters } from '~/pages/people/people-filters';
+import { peopleAvailableSorts } from '~/pages/people/people-sorts';
+
+const PeopleTableEffect = () => {
+ const {
+ setAvailableSorts,
+ setAvailableFilters,
+ setAvailableFields,
+ setViewType,
+ setViewObjectId,
+ } = useView();
+ const { currentViewFields, currentViewSorts, currentViewFilters } =
+ useViewInternalStates();
+
+ const [, setTableColumns] = useRecoilScopedState(
+ tableColumnsScopedState,
+ TableRecoilScopeContext,
+ );
+
+ const [, setTableSorts] = useRecoilScopedState(
+ tableSortsScopedState,
+ TableRecoilScopeContext,
+ );
+
+ const [, setTableFilters] = useRecoilScopedState(
+ tableFiltersScopedState,
+ TableRecoilScopeContext,
+ );
+
+ const [, setAvailableTableColumns] = useRecoilScopedState(
+ availableTableColumnsScopedState,
+ TableRecoilScopeContext,
+ );
+
+ useEffect(() => {
+ setAvailableSorts?.(peopleAvailableSorts);
+ setAvailableFilters?.(peopleAvailableFilters);
+ setAvailableFields?.(peopleAvailableFieldDefinitions);
+ setViewObjectId?.('person');
+ setViewType?.(ViewType.Table);
+
+ setAvailableTableColumns(peopleAvailableFieldDefinitions);
+ }, [
+ setAvailableFields,
+ setAvailableFilters,
+ setAvailableSorts,
+ setAvailableTableColumns,
+ setTableColumns,
+ setViewObjectId,
+ setViewType,
+ ]);
+ useEffect(() => {
+ if (currentViewFields) {
+ setTableColumns([...currentViewFields].sort((a, b) => a.index - b.index));
+ }
+ }, [currentViewFields, setTableColumns]);
+
+ useEffect(() => {
+ if (currentViewSorts) {
+ setTableSorts(currentViewSorts);
+ }
+ }, [currentViewFields, currentViewSorts, setTableColumns, setTableSorts]);
+
+ useEffect(() => {
+ if (currentViewFilters) {
+ setTableFilters(currentViewFilters);
+ }
+ }, [
+ currentViewFields,
+ currentViewFilters,
+ setTableColumns,
+ setTableFilters,
+ setTableSorts,
+ ]);
+
+ return <>>;
+};
+
+export default PeopleTableEffect;
diff --git a/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx b/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx
index 91c24c9ab..950c7a3e6 100644
--- a/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx
+++ b/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx
@@ -73,18 +73,9 @@ export const DataTableEffect = ({
const [searchParams] = useSearchParams();
useEffect(() => {
- const viewId = searchParams.get('view');
- if (viewId) {
- //setCurrentViewId(viewId);
- }
setActionBarEntries?.();
setContextMenuEntries?.();
- }, [
- searchParams,
- setActionBarEntries,
- setContextMenuEntries,
- setCurrentViewId,
- ]);
+ }, [searchParams, setActionBarEntries, setContextMenuEntries]);
return <>>;
};
diff --git a/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdown.tsx b/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdown.tsx
index a327deb45..23e7d4738 100644
--- a/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdown.tsx
+++ b/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdown.tsx
@@ -8,7 +8,11 @@ import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
import { TableOptionsDropdownButton } from './TableOptionsDropdownButton';
import { TableOptionsDropdownContent } from './TableOptionsDropdownContent';
-export const TableOptionsDropdown = () => {
+export const TableOptionsDropdown = ({
+ onImport,
+}: {
+ onImport?: () => void;
+}) => {
const { setViewEditMode } = useView();
return (
@@ -17,7 +21,7 @@ export const TableOptionsDropdown = () => {
clickableComponent={}
dropdownHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
dropdownOffset={{ y: 8 }}
- dropdownComponents={}
+ dropdownComponents={}
onClickOutside={() => setViewEditMode('none')}
/>
diff --git a/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdownContent.tsx b/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdownContent.tsx
index c5c54d13d..b33e8db45 100644
--- a/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdownContent.tsx
+++ b/front/src/modules/ui/data/data-table/options/components/TableOptionsDropdownContent.tsx
@@ -2,7 +2,7 @@ import { useCallback, useRef, useState } from 'react';
import { OnDragEndResponder } from '@hello-pangea/dnd';
import { Key } from 'ts-key-enum';
-import { IconChevronLeft, IconTag } from '@/ui/display/icon';
+import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
@@ -23,7 +23,11 @@ import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
type TableOptionsMenu = 'fields';
-export const TableOptionsDropdownContent = () => {
+export const TableOptionsDropdownContent = ({
+ onImport,
+}: {
+ onImport?: () => void;
+}) => {
const { setViewEditMode, handleViewNameSubmit } = useView();
const { viewEditMode, currentView } = useViewInternalStates();
@@ -104,13 +108,7 @@ export const TableOptionsDropdownContent = () => {
? 'View name'
: ''
}
- defaultValue={
- viewEditMode === 'create'
- ? ''
- : viewEditMode === 'edit'
- ? currentView?.name
- : ''
- }
+ defaultValue={viewEditMode === 'create' ? '' : currentView?.name}
/>
@@ -119,13 +117,13 @@ export const TableOptionsDropdownContent = () => {
LeftIcon={IconTag}
text="Fields"
/>
- {/*onImport && (
+ {onImport && (
- )*/}
+ )}
>
)}
diff --git a/front/src/modules/views/components/ViewBarEffect.tsx b/front/src/modules/views/components/ViewBarEffect.tsx
index 7f7205a5c..151c10079 100644
--- a/front/src/modules/views/components/ViewBarEffect.tsx
+++ b/front/src/modules/views/components/ViewBarEffect.tsx
@@ -1,3 +1,5 @@
+import { useEffect } from 'react';
+import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback } from 'recoil';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
@@ -35,9 +37,12 @@ export const ViewBarEffect = () => {
setSavedViewFilters,
currentViewId,
setViews,
+ changeView,
setCurrentViewId,
} = useView();
+ const [searchParams] = useSearchParams();
+
const { viewType, viewObjectId } = useViewInternalStates(viewScopeId);
useGetViewFieldsQuery({
@@ -112,7 +117,7 @@ export const ViewBarEffect = () => {
if (!nextViews.length) return;
- if (!currentViewId) return setCurrentViewId(nextViews[0].id);
+ if (!currentViewId) return changeView(nextViews[0].id);
}),
});
@@ -214,5 +219,12 @@ export const ViewBarEffect = () => {
}),
});
+ const currentViewIdFromUrl = searchParams.get('view');
+
+ useEffect(() => {
+ if (!currentViewIdFromUrl) return;
+ setCurrentViewId(currentViewIdFromUrl);
+ }, [currentViewIdFromUrl, setCurrentViewId]);
+
return <>>;
};
diff --git a/front/src/modules/views/components/ViewsDropdownButton.tsx b/front/src/modules/views/components/ViewsDropdownButton.tsx
index afb530efd..f7a2e8ef9 100644
--- a/front/src/modules/views/components/ViewsDropdownButton.tsx
+++ b/front/src/modules/views/components/ViewsDropdownButton.tsx
@@ -67,15 +67,10 @@ export const ViewsDropdownButton = ({
onViewEditModeChange,
}: ViewsDropdownButtonProps) => {
const theme = useTheme();
- const { scopeId, removeView, currentViewId } = useView();
+ const { scopeId, removeView, currentViewId, changeView } = useView();
- const {
- views,
- currentView,
- setViewEditMode,
- setCurrentViewId,
- entityCountInCurrentView,
- } = useViewInternalStates(scopeId, currentViewId);
+ const { views, currentView, setViewEditMode, entityCountInCurrentView } =
+ useViewInternalStates(scopeId, currentViewId);
const {
isDropdownOpen: isViewsDropdownOpen,
@@ -90,11 +85,11 @@ export const ViewsDropdownButton = ({
const handleViewSelect = useRecoilCallback(
() => async (viewId: string) => {
- setCurrentViewId(viewId);
+ changeView(viewId);
closeViewsDropdown();
},
- [setCurrentViewId, closeViewsDropdown],
+ [changeView, closeViewsDropdown],
);
const handleAddViewButtonClick = () => {
@@ -109,7 +104,7 @@ export const ViewsDropdownButton = ({
viewId: string,
) => {
event.stopPropagation();
- setCurrentViewId(viewId);
+ changeView(viewId);
setViewEditMode('edit');
onViewEditModeChange?.();
closeViewsDropdown();
diff --git a/front/src/modules/views/hooks/internal/useViewFields.ts b/front/src/modules/views/hooks/internal/useViewFields.ts
index b8d16d282..987521d25 100644
--- a/front/src/modules/views/hooks/internal/useViewFields.ts
+++ b/front/src/modules/views/hooks/internal/useViewFields.ts
@@ -1,16 +1,14 @@
-import { getOperationName } from '@apollo/client/utilities';
+import { useApolloClient } from '@apollo/client';
import { useRecoilCallback } from 'recoil';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
-import { GET_VIEW_FIELDS } from '@/views/graphql/queries/getViewFields';
-import { GET_VIEWS } from '@/views/graphql/queries/getViews';
import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState';
import { savedViewFieldByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFieldByKeyScopedFamilySelector';
import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState';
import {
- useCreateViewFieldsMutation,
- useUpdateViewFieldMutation,
+ CreateViewFieldsDocument,
+ UpdateViewFieldDocument,
} from '~/generated/graphql';
export const toViewFieldInput = (
@@ -26,8 +24,7 @@ export const toViewFieldInput = (
});
export const useViewFields = (viewScopeId: string) => {
- const [createViewFieldsMutation] = useCreateViewFieldsMutation();
- const [updateViewFieldMutation] = useUpdateViewFieldMutation();
+ const apolloClient = useApolloClient();
const persistViewFields = useRecoilCallback(
({ snapshot }) =>
@@ -63,14 +60,14 @@ export const useViewFields = (viewScopeId: string) => {
return;
}
- return createViewFieldsMutation({
+ return apolloClient.mutate({
+ mutation: CreateViewFieldsDocument,
variables: {
data: viewFieldsToCreate.map((viewField) => ({
...toViewFieldInput(objectId, viewField),
viewId: viewId ?? currentViewId,
})),
},
- refetchQueries: [getOperationName(GET_VIEW_FIELDS) ?? ''],
});
};
@@ -83,7 +80,8 @@ export const useViewFields = (viewScopeId: string) => {
return Promise.all(
viewFieldsToUpdate.map((viewField) =>
- updateViewFieldMutation({
+ apolloClient.mutate({
+ mutation: UpdateViewFieldDocument,
variables: {
data: {
isVisible: viewField.isVisible,
@@ -97,7 +95,6 @@ export const useViewFields = (viewScopeId: string) => {
},
},
},
- refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
}),
),
);
diff --git a/front/src/modules/views/hooks/useView.ts b/front/src/modules/views/hooks/useView.ts
index 444c792f7..0616b5c2a 100644
--- a/front/src/modules/views/hooks/useView.ts
+++ b/front/src/modules/views/hooks/useView.ts
@@ -1,3 +1,4 @@
+import { useCallback } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback } from 'recoil';
import { v4 } from 'uuid';
@@ -62,6 +63,13 @@ export const useView = (props?: UseViewProps) => {
useViews(scopeId);
const [_, setSearchParams] = useSearchParams();
+ const changeView = useCallback(
+ (viewId: string) => {
+ setSearchParams({ view: viewId });
+ },
+ [setSearchParams],
+ );
+
const resetViewBar = useRecoilCallback(({ snapshot }) => () => {
const savedViewFilters = snapshot
.getLoadable(
@@ -148,19 +156,17 @@ export const useView = (props?: UseViewProps) => {
await persistViewFields(currentViewFields, newViewId);
await persistViewFilters(newViewId);
await persistViewSorts(newViewId);
- setCurrentViewId(newViewId);
- setSearchParams({ view: newViewId });
+ changeView(newViewId);
},
[
+ changeView,
currentViewId,
internalCreateView,
persistViewFields,
persistViewFilters,
persistViewSorts,
scopeId,
- setCurrentViewId,
- setSearchParams,
],
);
@@ -203,9 +209,9 @@ export const useView = (props?: UseViewProps) => {
)
.getValue();
- const isCreateMode = viewEditMode === 'create';
+ const isCreateModeOrEditMode = viewEditMode === 'create' || 'edit';
- if (isCreateMode && name && currentViewFields) {
+ if (isCreateModeOrEditMode && name && currentViewFields) {
await createView(name);
set(savedTableColumnsFamilyState(currentViewId), currentViewFields);
}
@@ -244,5 +250,6 @@ export const useView = (props?: UseViewProps) => {
setSavedViewFields,
persistViewFields,
+ changeView,
};
};
diff --git a/front/src/pages/people/people-filters.tsx b/front/src/pages/people/people-filters.tsx
index 7383e9ba8..82cf6e20c 100644
--- a/front/src/pages/people/people-filters.tsx
+++ b/front/src/pages/people/people-filters.tsx
@@ -10,7 +10,7 @@ import {
} from '@/ui/display/icon/index';
import { Person } from '~/generated/graphql';
-export const peopleFilters: FilterDefinitionByEntity[] = [
+export const peopleAvailableFilters: FilterDefinitionByEntity[] = [
{
key: 'firstName',
label: 'First name',
diff --git a/front/src/testing/mock-data/people.ts b/front/src/testing/mock-data/people.ts
index 5f481d7ed..63dfae3e3 100644
--- a/front/src/testing/mock-data/people.ts
+++ b/front/src/testing/mock-data/people.ts
@@ -1,4 +1,4 @@
-import { peopleAvailableColumnDefinitions } from '@/people/constants/peopleAvailableColumnDefinitions';
+import { peopleAvailableFieldDefinitions } from '@/people/constants/peopleAvailableFieldDefinitions';
import {
Company,
Person,
@@ -146,7 +146,7 @@ export const mockedPersonTableViews: View[] = [
},
];
-export const mockedPersonTableColumns = peopleAvailableColumnDefinitions.map<
+export const mockedPersonTableColumns = peopleAvailableFieldDefinitions.map<
Omit
>((viewFieldDefinition) => ({
__typename: 'ViewField',