diff --git a/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx b/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx
index fdfe3e5cf..f878b5bd9 100644
--- a/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx
+++ b/front/src/modules/activities/tasks/components/PageAddTaskButton.tsx
@@ -1,19 +1,13 @@
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
-import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
+import { useFilter } from '@/ui/data/filter/hooks/useFilter';
import { PageAddButton } from '@/ui/layout/page/PageAddButton';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { ActivityType } from '~/generated/graphql';
export const PageAddTaskButton = () => {
+ const { selectedFilters } = useFilter();
const openCreateActivity = useOpenCreateActivityDrawer();
- const filters = useRecoilScopedValue(
- filtersScopedState,
- TasksRecoilScopeContext,
- );
-
- const assigneeIdFilter = filters.find(
+ const assigneeIdFilter = selectedFilters.find(
(filter) => filter.key === 'assigneeId',
);
diff --git a/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts b/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts
index 2f140d3f1..5aa2a8427 100644
--- a/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts
+++ b/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts
@@ -2,7 +2,7 @@ import { DateTime } from 'luxon';
import { useRecoilState } from 'recoil';
import { currentUserState } from '@/auth/states/currentUserState';
-import { turnFilterIntoWhereClause } from '@/ui/data/view-bar/utils/turnFilterIntoWhereClause';
+import { turnFilterIntoWhereClause } from '@/ui/data/filter/utils/turnFilterIntoWhereClause';
import {
ActivityType,
useGetActivitiesQuery,
diff --git a/front/src/modules/activities/tasks/hooks/useTasks.ts b/front/src/modules/activities/tasks/hooks/useTasks.ts
index fbba10c1c..7db8f20cd 100644
--- a/front/src/modules/activities/tasks/hooks/useTasks.ts
+++ b/front/src/modules/activities/tasks/hooks/useTasks.ts
@@ -1,18 +1,13 @@
import { DateTime } from 'luxon';
-import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { turnFilterIntoWhereClause } from '@/ui/data/view-bar/utils/turnFilterIntoWhereClause';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
+import { useFilter } from '@/ui/data/filter/hooks/useFilter';
+import { turnFilterIntoWhereClause } from '@/ui/data/filter/utils/turnFilterIntoWhereClause';
import { ActivityType, useGetActivitiesQuery } from '~/generated/graphql';
import { parseDate } from '~/utils/date-utils';
export const useTasks = (entity?: ActivityTargetableEntity) => {
- const [filters] = useRecoilScopedState(
- filtersScopedState,
- TasksRecoilScopeContext,
- );
+ const { selectedFilters } = useFilter();
const whereFilters = entity
? {
@@ -27,7 +22,7 @@ export const useTasks = (entity?: ActivityTargetableEntity) => {
}
: Object.assign(
{},
- ...filters.map((filter) => {
+ ...selectedFilters.map((filter) => {
return turnFilterIntoWhereClause(filter);
}),
);
@@ -40,7 +35,7 @@ export const useTasks = (entity?: ActivityTargetableEntity) => {
...whereFilters,
},
},
- skip: !entity && filters.length === 0,
+ skip: !entity && selectedFilters.length === 0,
});
const { data: incompleteTaskData } = useGetActivitiesQuery({
@@ -51,7 +46,7 @@ export const useTasks = (entity?: ActivityTargetableEntity) => {
...whereFilters,
},
},
- skip: !entity && filters.length === 0,
+ skip: !entity && selectedFilters.length === 0,
});
const todayOrPreviousTasks = incompleteTaskData?.findManyActivities.filter(
diff --git a/front/src/modules/companies/board/components/CompanyBoard.tsx b/front/src/modules/companies/board/components/CompanyBoard.tsx
index f4aa76ac3..421652dd6 100644
--- a/front/src/modules/companies/board/components/CompanyBoard.tsx
+++ b/front/src/modules/companies/board/components/CompanyBoard.tsx
@@ -1,13 +1,10 @@
import { BoardContext } from '@/companies/states/contexts/BoardContext';
-import { pipelineAvailableFieldDefinitions } from '@/pipeline/constants/pipelineAvailableFieldDefinitions';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
import {
EntityBoard,
EntityBoardProps,
} from '@/ui/layout/board/components/EntityBoard';
import { EntityBoardActionBar } from '@/ui/layout/board/components/EntityBoardActionBar';
import { EntityBoardContextMenu } from '@/ui/layout/board/components/EntityBoardContextMenu';
-import { useBoardViews } from '@/views/hooks/useBoardViews';
import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions';
import { HooksCompanyBoardEffect } from '../../components/HooksCompanyBoardEffect';
@@ -23,15 +20,6 @@ export const CompanyBoard = ({
onColumnDelete,
onEditColumnTitle,
}: CompanyBoardProps) => {
- // TODO: we can store objectId and fieldDefinitions in the ViewBarContext
- // And then use the useBoardViews web-hook wherever we need it in the board
- const { createView, deleteView, submitCurrentView, updateView } =
- useBoardViews({
- objectId: 'company',
- RecoilScopeContext: CompanyBoardRecoilScopeContext,
- fieldDefinitions: pipelineAvailableFieldDefinitions,
- });
-
return (
<>
-
-
-
+
+
diff --git a/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx b/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx
index 87cdb8046..8964c8383 100644
--- a/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx
+++ b/front/src/modules/companies/components/FilterDropdownCompanySearchSelect.tsx
@@ -1,24 +1,11 @@
-import { FilterDropdownEntitySearchSelect } from '@/ui/data/view-bar/components/FilterDropdownEntitySearchSelect';
-import { useViewBarContext } from '@/ui/data/view-bar/hooks/useViewBarContext';
-import { filterDropdownSearchInputScopedState } from '@/ui/data/view-bar/states/filterDropdownSearchInputScopedState';
-import { filterDropdownSelectedEntityIdScopedState } from '@/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
+import { FilterDropdownEntitySearchSelect } from '@/ui/data/filter/components/FilterDropdownEntitySearchSelect';
+import { useFilter } from '@/ui/data/filter/hooks/useFilter';
import { useFilteredSearchCompanyQuery } from '../hooks/useFilteredSearchCompanyQuery';
export const FilterDropdownCompanySearchSelect = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const filterDropdownSearchInput = useRecoilScopedValue(
- filterDropdownSearchInputScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [filterDropdownSelectedEntityId] = useRecoilScopedState(
- filterDropdownSelectedEntityIdScopedState,
- ViewBarRecoilScopeContext,
- );
+ const { filterDropdownSearchInput, filterDropdownSelectedEntityId } =
+ useFilter();
const usersForSelect = useFilteredSearchCompanyQuery({
searchFilter: filterDropdownSearchInput,
diff --git a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx
index cdb7eed83..c1a1ad743 100644
--- a/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx
+++ b/front/src/modules/companies/components/HooksCompanyBoardEffect.tsx
@@ -1,23 +1,13 @@
import { useEffect, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
-import { useRecoilCallback, useRecoilState } from 'recoil';
+import { useRecoilState } from 'recoil';
-import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState';
-import { availableSortsScopedState } from '@/ui/data/view-bar/states/availableSortsScopedState';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { entityCountInCurrentViewState } from '@/ui/data/view-bar/states/entityCountInCurrentViewState';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState';
-import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState';
-import { sortsOrderByScopedSelector } from '@/ui/data/view-bar/states/selectors/sortsOrderByScopedSelector';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
-import { turnFilterIntoWhereClause } from '@/ui/data/view-bar/utils/turnFilterIntoWhereClause';
+import { turnFilterIntoWhereClause } from '@/ui/data/filter/utils/turnFilterIntoWhereClause';
import { useBoardActionBarEntries } from '@/ui/layout/board/hooks/useBoardActionBarEntries';
import { useBoardContextMenuEntries } from '@/ui/layout/board/hooks/useBoardContextMenuEntries';
import { isBoardLoadedState } from '@/ui/layout/board/states/isBoardLoadedState';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
+import { useView } from '@/views/hooks/useView';
+import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
import {
Pipeline,
PipelineProgressableType,
@@ -29,35 +19,25 @@ import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBo
import { useUpdateCompanyBoardCardIds } from '../hooks/useUpdateBoardCardIds';
import { useUpdateCompanyBoard } from '../hooks/useUpdateCompanyBoardColumns';
-import { CompanyBoardRecoilScopeContext } from '../states/recoil-scope-contexts/CompanyBoardRecoilScopeContext';
export const HooksCompanyBoardEffect = () => {
- const [, setAvailableFilters] = useRecoilScopedState(
- availableFiltersScopedState,
- CompanyBoardRecoilScopeContext,
- );
+ const {
+ setAvailableFilters,
+ setAvailableSorts,
+ setEntityCountInCurrentView,
+ setCurrentViewId,
+ } = useView();
- const [, setAvailableSorts] = useRecoilScopedState(
- availableSortsScopedState,
- CompanyBoardRecoilScopeContext,
- );
-
- const [, setEntityCountInCurrentView] = useRecoilState(
- entityCountInCurrentViewState,
- );
+ const { currentViewFilters, currentViewSortsOrderBy } =
+ useViewInternalStates();
useEffect(() => {
setAvailableFilters(opportunitiesBoardOptions.filters);
- setAvailableSorts(opportunitiesBoardOptions.sorts);
- });
+ setAvailableSorts?.(opportunitiesBoardOptions.sorts);
+ }, [setAvailableFilters, setAvailableSorts]);
const [, setIsBoardLoaded] = useRecoilState(isBoardLoadedState);
- const filters = useRecoilScopedValue(
- filtersScopedState,
- CompanyBoardRecoilScopeContext,
- );
-
const updateCompanyBoard = useUpdateCompanyBoard();
const { data: pipelineData, loading: loadingGetPipelines } =
@@ -77,18 +57,14 @@ export const HooksCompanyBoardEffect = () => {
?.map((pipelineStage) => pipelineStage.id)
.flat();
- const sortsOrderBy = useRecoilScopedValue(
- sortsOrderByScopedSelector,
- CompanyBoardRecoilScopeContext,
- );
const whereFilters = useMemo(() => {
return {
AND: [
{ pipelineStageId: { in: pipelineStageIds } },
- ...filters.map(turnFilterIntoWhereClause),
+ ...(currentViewFilters?.map(turnFilterIntoWhereClause) || []),
],
};
- }, [filters, pipelineStageIds]) as any;
+ }, [currentViewFilters, pipelineStageIds]) as any;
const updateCompanyBoardCardIds = useUpdateCompanyBoardCardIds();
@@ -96,7 +72,7 @@ export const HooksCompanyBoardEffect = () => {
useGetPipelineProgressQuery({
variables: {
where: whereFilters,
- orderBy: sortsOrderBy,
+ orderBy: currentViewSortsOrderBy,
},
onCompleted: (data) => {
const pipelineProgresses = data?.findManyPipelineProgress || [];
@@ -123,30 +99,6 @@ export const HooksCompanyBoardEffect = () => {
});
const [searchParams] = useSearchParams();
- const boardRecoilScopeId = useRecoilScopeId(CompanyBoardRecoilScopeContext);
- const handleViewSelect = useRecoilCallback(
- ({ set, snapshot }) =>
- async (viewId: string) => {
- const currentView = await snapshot.getPromise(
- currentViewIdScopedState(boardRecoilScopeId),
- );
- if (currentView === viewId) {
- return;
- }
-
- const savedFilters = await snapshot.getPromise(
- savedFiltersFamilyState(viewId),
- );
- const savedSorts = await snapshot.getPromise(
- savedSortsFamilyState(viewId),
- );
-
- set(filtersScopedState(boardRecoilScopeId), savedFilters);
- set(sortsScopedState(boardRecoilScopeId), savedSorts);
- set(currentViewIdScopedState(boardRecoilScopeId), viewId);
- },
- [boardRecoilScopeId],
- );
const loading =
loadingGetPipelines || loadingGetPipelineProgress || loadingGetCompanies;
@@ -158,7 +110,7 @@ export const HooksCompanyBoardEffect = () => {
if (!loading && pipeline && pipelineProgresses && companiesData) {
const viewId = searchParams.get('view');
if (viewId) {
- handleViewSelect(viewId);
+ //setCurrentViewId(viewId);
}
setActionBarEntries();
setContextMenuEntries();
@@ -174,8 +126,8 @@ export const HooksCompanyBoardEffect = () => {
setActionBarEntries,
setContextMenuEntries,
searchParams,
- handleViewSelect,
setEntityCountInCurrentView,
+ setCurrentViewId,
]);
return <>>;
diff --git a/front/src/modules/companies/constants/companiesAvailableColumnDefinitions.tsx b/front/src/modules/companies/constants/companiesAvailableFieldDefinitions.tsx
similarity index 98%
rename from front/src/modules/companies/constants/companiesAvailableColumnDefinitions.tsx
rename to front/src/modules/companies/constants/companiesAvailableFieldDefinitions.tsx
index d034fb6aa..978807852 100644
--- a/front/src/modules/companies/constants/companiesAvailableColumnDefinitions.tsx
+++ b/front/src/modules/companies/constants/companiesAvailableFieldDefinitions.tsx
@@ -25,7 +25,7 @@ import {
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { User } from '~/generated/graphql';
-export const companiesAvailableColumnDefinitions: ColumnDefinition[] =
+export const companiesAvailableFieldDefinitions: ColumnDefinition[] =
[
{
key: 'name',
diff --git a/front/src/modules/companies/table/components/CompanyTable.tsx b/front/src/modules/companies/table/components/CompanyTable.tsx
index 453e357c6..dbe83f876 100644
--- a/front/src/modules/companies/table/components/CompanyTable.tsx
+++ b/front/src/modules/companies/table/components/CompanyTable.tsx
@@ -1,41 +1,39 @@
-import { companiesAvailableColumnDefinitions } from '@/companies/constants/companiesAvailableColumnDefinitions';
+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';
import { useUpsertDataTableItem } from '@/ui/data/data-table/hooks/useUpsertDataTableItem';
-import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
-import { useTableViews } from '@/views/hooks/useTableViews';
+import { TableOptionsDropdown } from '@/ui/data/data-table/options/components/TableOptionsDropdown';
+import { TableOptionsHotkeyScope } from '@/ui/data/data-table/types/TableOptionsHotkeyScope';
+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 {
UpdateOneCompanyMutationVariables,
useGetCompaniesQuery,
useGetWorkspaceMembersLazyQuery,
useUpdateOneCompanyMutation,
} from '~/generated/graphql';
-import { companiesFilters } from '~/pages/companies/companies-filters';
+import { companyAvailableFilters } from '~/pages/companies/companies-filters';
import { companyAvailableSorts } from '~/pages/companies/companies-sorts';
+import CompanyTableEffect from './CompanyTableEffect';
+
export const CompanyTable = () => {
+ const tableViewScopeId = 'company-table';
+
const [updateEntityMutation] = useUpdateOneCompanyMutation();
const upsertDataTableItem = useUpsertDataTableItem();
const [getWorkspaceMember] = useGetWorkspaceMembersLazyQuery();
- const {
- createView,
- deleteView,
- persistColumns,
- submitCurrentView,
- updateView,
- } = useTableViews({
- objectId: 'company',
- columnDefinitions: companiesAvailableColumnDefinitions,
- });
-
- const { openCompanySpreadsheetImport } = useSpreadsheetCompanyImport();
+ const { persistViewFields } = useViewFields(tableViewScopeId);
+ const { setCurrentViewFields } = useView({ viewScopeId: tableViewScopeId });
const { setContextMenuEntries } = useCompanyTableContextMenuEntries();
const { setActionBarEntries } = useCompanyTableActionBarEntries();
@@ -69,38 +67,61 @@ export const CompanyTable = () => {
});
};
+ const StyledContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: auto;
+ `;
+
return (
-
-
-
- updateCompany(variables)}
- />
-
-
+ {}}
+ onViewSortsChange={() => {}}
+ onViewFiltersChange={() => {}}
+ >
+
+ {
+ setCurrentViewFields?.(columns);
+ persistViewFields(columns);
+ },
+ }}
+ >
+
+
+
+ }
+ optionsDropdownScopeId="table-dropdown-option"
+ />
+
+
+
+ updateCompany(variables)}
+ />
+
+
+
);
};
diff --git a/front/src/modules/companies/table/components/CompanyTableEffect.tsx b/front/src/modules/companies/table/components/CompanyTableEffect.tsx
new file mode 100644
index 000000000..90a272988
--- /dev/null
+++ b/front/src/modules/companies/table/components/CompanyTableEffect.tsx
@@ -0,0 +1,60 @@
+import { useEffect } from 'react';
+
+import { companiesAvailableFieldDefinitions } from '@/companies/constants/companiesAvailableFieldDefinitions';
+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 { 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 { companyAvailableFilters } from '~/pages/companies/companies-filters';
+import { companyAvailableSorts } from '~/pages/companies/companies-sorts';
+
+const CompanyTableEffect = () => {
+ const {
+ setAvailableSorts,
+ setAvailableFilters,
+ setAvailableFields,
+ setViewType,
+ setViewObjectId,
+ } = useView();
+ const { currentViewFields } = useViewInternalStates();
+
+ const [, setTableColumns] = useRecoilScopedState(
+ tableColumnsScopedState,
+ TableRecoilScopeContext,
+ );
+
+ const [, setAvailableTableColumns] = useRecoilScopedState(
+ availableTableColumnsScopedState,
+ TableRecoilScopeContext,
+ );
+
+ useEffect(() => {
+ setAvailableSorts?.(companyAvailableSorts);
+ setAvailableFilters?.(companyAvailableFilters);
+ setAvailableFields?.(companiesAvailableFieldDefinitions);
+ setViewObjectId?.('company');
+ setViewType?.(ViewType.Table);
+
+ setAvailableTableColumns(companiesAvailableFieldDefinitions);
+ }, [
+ setAvailableFields,
+ setAvailableFilters,
+ setAvailableSorts,
+ setAvailableTableColumns,
+ setTableColumns,
+ setViewObjectId,
+ setViewType,
+ ]);
+ useEffect(() => {
+ if (currentViewFields) {
+ setTableColumns([...currentViewFields].sort((a, b) => a.index - b.index));
+ }
+ }, [currentViewFields, setTableColumns]);
+
+ return <>>;
+};
+
+export default CompanyTableEffect;
diff --git a/front/src/modules/companies/table/components/CompanyTableMockDataEffect.tsx b/front/src/modules/companies/table/components/CompanyTableMockDataEffect.tsx
index a2105506a..3ab251a73 100644
--- a/front/src/modules/companies/table/components/CompanyTableMockDataEffect.tsx
+++ b/front/src/modules/companies/table/components/CompanyTableMockDataEffect.tsx
@@ -1,12 +1,11 @@
import { useEffect } from 'react';
+import { companiesAvailableFieldDefinitions } from '@/companies/constants/companiesAvailableFieldDefinitions';
import { useSetDataTableData } from '@/ui/data/data-table/hooks/useSetDataTableData';
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { companiesAvailableColumnDefinitions } from '../../constants/companiesAvailableColumnDefinitions';
-
import { mockedCompaniesData } from './companies-mock-data';
export const CompanyTableMockDataEffect = () => {
@@ -19,7 +18,7 @@ export const CompanyTableMockDataEffect = () => {
useEffect(() => {
setDataTableData(mockedCompaniesData, [], []);
- setTableColumns(companiesAvailableColumnDefinitions);
+ setTableColumns(companiesAvailableFieldDefinitions);
}, [setDataTableData, setTableColumns]);
return <>>;
diff --git a/front/src/modules/companies/table/components/CompanyTableMockMode.tsx b/front/src/modules/companies/table/components/CompanyTableMockMode.tsx
index 8267a1ee1..aa09677aa 100644
--- a/front/src/modules/companies/table/components/CompanyTableMockMode.tsx
+++ b/front/src/modules/companies/table/components/CompanyTableMockMode.tsx
@@ -1,22 +1,15 @@
import { DataTable } from '@/ui/data/data-table/components/DataTable';
-import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
+import { ViewScope } from '@/views/scopes/ViewScope';
import { useUpdateOneCompanyMutation } from '~/generated/graphql';
import { CompanyTableMockDataEffect } from './CompanyTableMockDataEffect';
export const CompanyTableMockMode = () => {
return (
- <>
+
-
-
-
- >
+
+
+
);
};
diff --git a/front/src/modules/metadata/components/ObjectDataTableEffect.tsx b/front/src/modules/metadata/components/ObjectDataTableEffect.tsx
index ebe287084..13fdaddf8 100644
--- a/front/src/modules/metadata/components/ObjectDataTableEffect.tsx
+++ b/front/src/modules/metadata/components/ObjectDataTableEffect.tsx
@@ -3,12 +3,8 @@ import { useSearchParams } from 'react-router-dom';
import { useRecoilCallback } from 'recoil';
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState';
-import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
+import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState';
import { useFindManyObjects } from '../hooks/useFindManyObjects';
import { useSetObjectDataTableData } from '../hooks/useSetDataTableData';
@@ -39,22 +35,13 @@ export const ObjectDataTableEffect = ({
({ set, snapshot }) =>
async (viewId: string) => {
const currentView = await snapshot.getPromise(
- currentViewIdScopedState(tableRecoilScopeId),
+ currentViewIdScopedState({ scopeId: tableRecoilScopeId }),
);
if (currentView === viewId) {
return;
}
- const savedFilters = await snapshot.getPromise(
- savedFiltersFamilyState(viewId),
- );
- const savedSorts = await snapshot.getPromise(
- savedSortsFamilyState(viewId),
- );
-
- set(filtersScopedState(tableRecoilScopeId), savedFilters);
- set(sortsScopedState(tableRecoilScopeId), savedSorts);
- set(currentViewIdScopedState(tableRecoilScopeId), viewId);
+ set(currentViewIdScopedState({ scopeId: tableRecoilScopeId }), viewId);
},
[tableRecoilScopeId],
);
diff --git a/front/src/modules/metadata/components/ObjectTable.tsx b/front/src/modules/metadata/components/ObjectTable.tsx
index e597a02a7..e70994e5c 100644
--- a/front/src/modules/metadata/components/ObjectTable.tsx
+++ b/front/src/modules/metadata/components/ObjectTable.tsx
@@ -1,9 +1,6 @@
import { DataTable } from '@/ui/data/data-table/components/DataTable';
import { TableContext } from '@/ui/data/data-table/contexts/TableContext';
-import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
-import { useMetadataTableViews } from '../hooks/useMetadataTableViews';
import { useUpdateOneObject } from '../hooks/useUpdateOneObject';
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
@@ -12,9 +9,6 @@ import { ObjectDataTableEffect } from './ObjectDataTableEffect';
export type ObjectTableProps = MetadataObjectIdentifier;
export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
- const { createView, deleteView, submitCurrentView, updateView } =
- useMetadataTableViews();
-
const { updateOneObject } = useUpdateOneObject({
objectNamePlural,
});
@@ -44,18 +38,8 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
}}
>
-
-
-
+
+
);
};
diff --git a/front/src/modules/metadata/hooks/useCreateNewTempCustomObject.ts b/front/src/modules/metadata/hooks/useCreateNewTempCustomObject.ts
index bb1512525..127877327 100644
--- a/front/src/modules/metadata/hooks/useCreateNewTempCustomObject.ts
+++ b/front/src/modules/metadata/hooks/useCreateNewTempCustomObject.ts
@@ -6,7 +6,7 @@ import { FieldType } from '@/ui/data/field/types/FieldType';
import { IconBrandLinkedin } from '@/ui/display/icon';
import { GET_VIEW_FIELDS } from '@/views/graphql/queries/getViewFields';
import { GET_VIEWS } from '@/views/graphql/queries/getViews';
-import { toViewFieldInput } from '@/views/hooks/useTableViewFields';
+import { toViewFieldInput } from '@/views/hooks/internal/useViewFields';
import {
useCreateViewFieldsMutation,
useCreateViewMutation,
diff --git a/front/src/modules/metadata/hooks/useMetadataTableViews.ts b/front/src/modules/metadata/hooks/useMetadataTableViews.ts
deleted file mode 100644
index fef774933..000000000
--- a/front/src/modules/metadata/hooks/useMetadataTableViews.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { useSearchParams } from 'react-router-dom';
-
-import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useTableViewFields } from '@/views/hooks/useTableViewFields';
-import { useViewFilters } from '@/views/hooks/useViewFilters';
-import { useViews } from '@/views/hooks/useViews';
-import { useViewSorts } from '@/views/hooks/useViewSorts';
-import { ViewType } from '~/generated/graphql';
-
-import { useMetadataObjectInContext } from './useMetadataObjectInContext';
-
-export const useMetadataTableViews = () => {
- const { objectNamePlural, columnDefinitions } = useMetadataObjectInContext();
-
- const tableColumns = useRecoilScopedValue(
- tableColumnsScopedState,
- TableRecoilScopeContext,
- );
- const filters = useRecoilScopedValue(
- filtersScopedState,
- TableRecoilScopeContext,
- );
- const sorts = useRecoilScopedValue(sortsScopedState, TableRecoilScopeContext);
-
- const [_, setSearchParams] = useSearchParams();
-
- const handleViewCreate = async (viewId: string) => {
- await createViewFields(tableColumns, viewId);
- await createViewFilters(filters, viewId);
- await createViewSorts(sorts, viewId);
- setSearchParams({ view: viewId });
- };
-
- const objectId = objectNamePlural;
-
- const { createView, deleteView, isFetchingViews, updateView } = useViews({
- objectId,
- onViewCreate: handleViewCreate,
- type: ViewType.Table,
- RecoilScopeContext: TableRecoilScopeContext,
- });
-
- const { createViewFields, persistColumns } = useTableViewFields({
- objectId,
- columnDefinitions,
- skipFetch: isFetchingViews,
- });
-
- const createDefaultViewFields = async () => {
- await createViewFields(tableColumns);
- };
-
- const { createViewFilters, persistFilters } = useViewFilters({
- RecoilScopeContext: TableRecoilScopeContext,
- skipFetch: isFetchingViews,
- });
-
- const { createViewSorts, persistSorts } = useViewSorts({
- RecoilScopeContext: TableRecoilScopeContext,
- skipFetch: isFetchingViews,
- });
-
- const submitCurrentView = async () => {
- await persistFilters();
- await persistSorts();
- };
-
- return {
- createView,
- deleteView,
- persistColumns,
- submitCurrentView,
- updateView,
- createDefaultViewFields,
- isFetchingViews,
- };
-};
diff --git a/front/src/modules/metadata/hooks/useSetDataTableData.ts b/front/src/modules/metadata/hooks/useSetDataTableData.ts
index e983f5afc..0aae7fe38 100644
--- a/front/src/modules/metadata/hooks/useSetDataTableData.ts
+++ b/front/src/modules/metadata/hooks/useSetDataTableData.ts
@@ -6,10 +6,8 @@ import { numberOfTableRowsState } from '@/ui/data/data-table/states/numberOfTabl
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
import { tableRowIdsState } from '@/ui/data/data-table/states/tableRowIdsState';
import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState';
-import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState';
-import { availableSortsScopedState } from '@/ui/data/view-bar/states/availableSortsScopedState';
-import { entityCountInCurrentViewState } from '@/ui/data/view-bar/states/entityCountInCurrentViewState';
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
+import { availableSortsScopedState } from '@/views/states/availableSortsScopedState';
export const useSetObjectDataTableData = () => {
const resetTableRowSelection = useResetTableRowSelection();
@@ -43,11 +41,7 @@ export const useSetObjectDataTableData = () => {
set(numberOfTableRowsState, entityIds.length);
- set(entityCountInCurrentViewState, entityIds.length);
-
- set(availableFiltersScopedState(tableContextScopeId), []);
-
- set(availableSortsScopedState(tableContextScopeId), []);
+ set(availableSortsScopedState({ scopeId: tableContextScopeId }), []);
set(isFetchingDataTableDataState, false);
},
diff --git a/front/src/modules/people/components/FilterDropdownPeopleSearchSelect.tsx b/front/src/modules/people/components/FilterDropdownPeopleSearchSelect.tsx
index 4c9aebf43..82175496a 100644
--- a/front/src/modules/people/components/FilterDropdownPeopleSearchSelect.tsx
+++ b/front/src/modules/people/components/FilterDropdownPeopleSearchSelect.tsx
@@ -1,23 +1,10 @@
import { useFilteredSearchPeopleQuery } from '@/people/hooks/useFilteredSearchPeopleQuery';
-import { FilterDropdownEntitySearchSelect } from '@/ui/data/view-bar/components/FilterDropdownEntitySearchSelect';
-import { useViewBarContext } from '@/ui/data/view-bar/hooks/useViewBarContext';
-import { filterDropdownSearchInputScopedState } from '@/ui/data/view-bar/states/filterDropdownSearchInputScopedState';
-import { filterDropdownSelectedEntityIdScopedState } from '@/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
+import { FilterDropdownEntitySearchSelect } from '@/ui/data/filter/components/FilterDropdownEntitySearchSelect';
+import { useFilter } from '@/ui/data/filter/hooks/useFilter';
export const FilterDropdownPeopleSearchSelect = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const filterDropdownSearchInput = useRecoilScopedValue(
- filterDropdownSearchInputScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [filterDropdownSelectedEntityId] = useRecoilScopedState(
- filterDropdownSelectedEntityIdScopedState,
- ViewBarRecoilScopeContext,
- );
+ const { filterDropdownSearchInput, filterDropdownSelectedEntityId } =
+ useFilter();
const peopleForSelect = useFilteredSearchPeopleQuery({
searchFilter: filterDropdownSearchInput,
diff --git a/front/src/modules/people/hooks/useSetPeopleDataTable.ts b/front/src/modules/people/hooks/useSetPeopleDataTable.ts
index 048534a51..365d9d1a3 100644
--- a/front/src/modules/people/hooks/useSetPeopleDataTable.ts
+++ b/front/src/modules/people/hooks/useSetPeopleDataTable.ts
@@ -4,13 +4,9 @@ import { useRecoilCallback } from 'recoil';
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
import { isFetchingDataTableDataState } from '@/ui/data/data-table/states/isFetchingDataTableDataState';
import { numberOfTableRowsState } from '@/ui/data/data-table/states/numberOfTableRowsState';
-import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
import { tableRowIdsState } from '@/ui/data/data-table/states/tableRowIdsState';
-import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState';
import { currentPageLocationState } from '@/ui/utilities/loading-state/states/currentPageLocationState';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
import { GetPeopleQuery } from '~/generated/graphql';
-import { peopleFilters } from '~/pages/people/people-filters';
import { peopleCityFamilyState } from '../states/peopleCityFamilyState';
import { peopleCompanyFamilyState } from '../states/peopleCompanyFamilyState';
@@ -24,8 +20,6 @@ import { peoplePhoneFamilyState } from '../states/peoplePhoneFamilyState';
export const useSetPeopleDataTable = () => {
const resetTableRowSelection = useResetTableRowSelection();
- const tableContextScopeId = useRecoilScopeId(TableRecoilScopeContext);
-
const currentLocation = useLocation().pathname;
return useRecoilCallback(
@@ -126,12 +120,10 @@ export const useSetPeopleDataTable = () => {
set(numberOfTableRowsState, peopleIds.length);
- set(availableFiltersScopedState(tableContextScopeId), peopleFilters);
-
set(currentPageLocationState, currentLocation);
set(isFetchingDataTableDataState, false);
},
- [currentLocation, resetTableRowSelection, tableContextScopeId],
+ [currentLocation, resetTableRowSelection],
);
};
diff --git a/front/src/modules/people/table/components/PeopleTable.tsx b/front/src/modules/people/table/components/PeopleTable.tsx
index c056e5e98..3c0dcfbaf 100644
--- a/front/src/modules/people/table/components/PeopleTable.tsx
+++ b/front/src/modules/people/table/components/PeopleTable.tsx
@@ -1,15 +1,12 @@
-import { peopleAvailableColumnDefinitions } from '@/people/constants/peopleAvailableColumnDefinitions';
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 { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
-import { useTableViews } from '@/views/hooks/useTableViews';
+import { SortScope } from '@/ui/data/sort/scopes/SortScope';
+import { ViewScope } from '@/views/scopes/ViewScope';
import {
UpdateOnePersonMutationVariables,
useGetPeopleQuery,
@@ -21,68 +18,54 @@ import { peopleAvailableSorts } from '~/pages/people/people-sorts';
export const PeopleTable = () => {
const [updateEntityMutation] = useUpdateOnePersonMutation();
const upsertDataTableItem = useUpsertDataTableItem();
- const { openPersonSpreadsheetImport } = useSpreadsheetPersonImport();
- const {
- createView,
- deleteView,
- persistColumns,
- submitCurrentView,
- updateView,
- } = useTableViews({
- objectId: 'person',
- columnDefinitions: peopleAvailableColumnDefinitions,
- });
+ const tableViewScopeId = 'people-table';
const { setContextMenuEntries } = usePersonTableContextMenuEntries();
const { setActionBarEntries } = usePersonTableActionBarEntries();
- const handleImport = () => {
- openPersonSpreadsheetImport();
- };
-
return (
-
-
-
-
- updateEntityMutation({
+
+
+ {
+ // eslint-disable-next-line no-console
+ console.log('persist columns');
+ },
+ }}
+ >
+
+
+ {
- if (!data.updateOnePerson) {
- return;
- }
- upsertDataTableItem(data.updateOnePerson);
- },
- })
- }
- />
-
-
+ }: {
+ variables: UpdateOnePersonMutationVariables;
+ }) =>
+ updateEntityMutation({
+ variables,
+ onCompleted: (data) => {
+ if (!data.updateOnePerson) {
+ return;
+ }
+ upsertDataTableItem(data.updateOnePerson);
+ },
+ })
+ }
+ />
+
+
+
);
};
diff --git a/front/src/modules/ui/data/data-table/components/DataTable.tsx b/front/src/modules/ui/data/data-table/components/DataTable.tsx
index fc8361a35..94ec5a9d8 100644
--- a/front/src/modules/ui/data/data-table/components/DataTable.tsx
+++ b/front/src/modules/ui/data/data-table/components/DataTable.tsx
@@ -14,7 +14,6 @@ import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus';
import { useMapKeyboardToSoftFocus } from '../hooks/useMapKeyboardToSoftFocus';
import { useResetTableRowSelection } from '../hooks/useResetTableRowSelection';
import { useSetRowSelectedState } from '../hooks/useSetRowSelectedState';
-import { TableHeader } from '../table-header/components/TableHeader';
import { TableHotkeyScope } from '../types/TableHotkeyScope';
import { DataTableBody } from './DataTableBody';
@@ -123,7 +122,6 @@ export const DataTable = ({ updateEntityMutation }: DataTableProps) => {
-
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 11caa87a5..39fb2aa0f 100644
--- a/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx
+++ b/front/src/modules/ui/data/data-table/components/DataTableEffect.tsx
@@ -1,27 +1,21 @@
import { useEffect } from 'react';
import { useSearchParams } from 'react-router-dom';
import defaults from 'lodash/defaults';
-import { useRecoilCallback } from 'recoil';
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
import { OptimisticEffectDefinition } from '@/apollo/optimistic-effect/types/OptimisticEffectDefinition';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState';
-import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
-import { FilterDefinition } from '@/ui/data/view-bar/types/FilterDefinition';
-import { SortDefinition } from '@/ui/data/view-bar/types/SortDefinition';
+import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
+import { useView } from '@/views/hooks/useView';
+import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
import {
SortOrder,
useGetCompaniesQuery,
useGetPeopleQuery,
} from '~/generated/graphql';
-import { filtersWhereScopedSelector } from '../../view-bar/states/selectors/filtersWhereScopedSelector';
-import { sortsOrderByScopedSelector } from '../../view-bar/states/selectors/sortsOrderByScopedSelector';
+import { filtersWhereScopedSelector } from '../../filter/states/selectors/filtersWhereScopedSelector';
+import { SortDefinition } from '../../sort/types/SortDefinition';
import { useSetDataTableData } from '../hooks/useSetDataTableData';
import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext';
@@ -46,12 +40,10 @@ export const DataTableEffect = ({
}) => {
const setDataTableData = useSetDataTableData();
const { registerOptimisticEffect } = useOptimisticEffect();
+ const { setCurrentViewId } = useView();
+ const { currentViewSortsOrderBy } = useViewInternalStates();
- let sortsOrderBy = useRecoilScopedValue(
- sortsOrderByScopedSelector,
- TableRecoilScopeContext,
- );
- sortsOrderBy = defaults(sortsOrderBy, [
+ const sortsOrderBy = defaults(currentViewSortsOrderBy, [
{
createdAt: SortOrder.Desc,
},
@@ -76,43 +68,19 @@ export const DataTableEffect = ({
});
const [searchParams] = useSearchParams();
- const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext);
- const handleViewSelect = useRecoilCallback(
- ({ set, snapshot }) =>
- async (viewId: string) => {
- const currentView = await snapshot.getPromise(
- currentViewIdScopedState(tableRecoilScopeId),
- );
- if (currentView === viewId) {
- return;
- }
-
- const savedFilters = await snapshot.getPromise(
- savedFiltersFamilyState(viewId),
- );
- const savedSorts = await snapshot.getPromise(
- savedSortsFamilyState(viewId),
- );
-
- set(filtersScopedState(tableRecoilScopeId), savedFilters);
- set(sortsScopedState(tableRecoilScopeId), savedSorts);
- set(currentViewIdScopedState(tableRecoilScopeId), viewId);
- },
- [tableRecoilScopeId],
- );
useEffect(() => {
const viewId = searchParams.get('view');
if (viewId) {
- handleViewSelect(viewId);
+ //setCurrentViewId(viewId);
}
setActionBarEntries?.();
setContextMenuEntries?.();
}, [
- handleViewSelect,
searchParams,
setActionBarEntries,
setContextMenuEntries,
+ setCurrentViewId,
]);
return <>>;
diff --git a/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx b/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx
index 304e69162..e5e9fe829 100644
--- a/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx
+++ b/front/src/modules/ui/data/data-table/components/DataTableHeader.tsx
@@ -166,33 +166,35 @@ export const DataTableHeader = () => {
>
- {visibleTableColumns.map((column, index) => (
-
-
- columnA.index - columnB.index)
+ .map((column, index) => (
+
+
+
+
+ {
+ setResizedFieldKey(column.key);
+ }}
/>
-
- {
- setResizedFieldKey(column.key);
- }}
- />
-
- ))}
+
+ ))}
{hiddenTableColumns.length > 0 && (
diff --git a/front/src/modules/ui/data/data-table/components/DataTableRow.tsx b/front/src/modules/ui/data/data-table/components/DataTableRow.tsx
index 0515d6bc0..5600163d2 100644
--- a/front/src/modules/ui/data/data-table/components/DataTableRow.tsx
+++ b/front/src/modules/ui/data/data-table/components/DataTableRow.tsx
@@ -38,13 +38,15 @@ export const DataTableRow = forwardRef(
|
|
- {visibleTableColumns.map((column, columnIndex) => {
- return (
-
-
-
- );
- })}
+ {[...visibleTableColumns]
+ .sort((columnA, columnB) => columnA.index - columnB.index)
+ .map((column, columnIndex) => {
+ return (
+
+
+
+ );
+ })}
|
);
diff --git a/front/src/modules/views/hooks/useMoveViewColumns.ts b/front/src/modules/ui/data/data-table/hooks/useMoveViewColumns.ts
similarity index 100%
rename from front/src/modules/views/hooks/useMoveViewColumns.ts
rename to front/src/modules/ui/data/data-table/hooks/useMoveViewColumns.ts
diff --git a/front/src/modules/ui/data/data-table/hooks/useSetDataTableData.ts b/front/src/modules/ui/data/data-table/hooks/useSetDataTableData.ts
index aea4af97d..4ef19f7aa 100644
--- a/front/src/modules/ui/data/data-table/hooks/useSetDataTableData.ts
+++ b/front/src/modules/ui/data/data-table/hooks/useSetDataTableData.ts
@@ -1,13 +1,12 @@
import { useRecoilCallback } from 'recoil';
import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState';
-import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState';
-import { availableSortsScopedState } from '@/ui/data/view-bar/states/availableSortsScopedState';
-import { entityCountInCurrentViewState } from '@/ui/data/view-bar/states/entityCountInCurrentViewState';
-import { FilterDefinition } from '@/ui/data/view-bar/types/FilterDefinition';
-import { SortDefinition } from '@/ui/data/view-bar/types/SortDefinition';
+import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
+import { useView } from '@/views/hooks/useView';
+import { availableSortsScopedState } from '@/views/states/availableSortsScopedState';
+import { SortDefinition } from '../../sort/types/SortDefinition';
import { isFetchingDataTableDataState } from '../states/isFetchingDataTableDataState';
import { numberOfTableRowsState } from '../states/numberOfTableRowsState';
import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext';
@@ -17,6 +16,7 @@ import { useResetTableRowSelection } from './useResetTableRowSelection';
export const useSetDataTableData = () => {
const resetTableRowSelection = useResetTableRowSelection();
+ const { setEntityCountInCurrentView } = useView();
const tableContextScopeId = useRecoilScopeId(TableRecoilScopeContext);
@@ -51,20 +51,15 @@ export const useSetDataTableData = () => {
set(numberOfTableRowsState, entityIds.length);
- set(entityCountInCurrentViewState, entityIds.length);
+ setEntityCountInCurrentView(entityIds.length);
set(
- availableFiltersScopedState(tableContextScopeId),
- filterDefinitionArray,
- );
-
- set(
- availableSortsScopedState(tableContextScopeId),
+ availableSortsScopedState({ scopeId: tableContextScopeId }),
sortDefinitionArray,
);
set(isFetchingDataTableDataState, false);
},
- [resetTableRowSelection, tableContextScopeId],
+ [resetTableRowSelection, setEntityCountInCurrentView, tableContextScopeId],
);
};
diff --git a/front/src/modules/ui/data/data-table/hooks/useTableColumns.ts b/front/src/modules/ui/data/data-table/hooks/useTableColumns.ts
index 2aa248217..f37d8e500 100644
--- a/front/src/modules/ui/data/data-table/hooks/useTableColumns.ts
+++ b/front/src/modules/ui/data/data-table/hooks/useTableColumns.ts
@@ -1,12 +1,11 @@
import { useCallback, useContext } from 'react';
import { useSetRecoilState } from 'recoil';
+import { useMoveViewColumns } from '@/ui/data/data-table/hooks/useMoveViewColumns';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { ViewFieldForVisibility } from '@/ui/data/view-bar/types/ViewFieldForVisibility';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
+import { useView } from '@/views/hooks/useView';
+import { ViewFieldForVisibility } from '@/views/types/ViewFieldForVisibility';
import { TableContext } from '../contexts/TableContext';
import { availableTableColumnsScopedState } from '../states/availableTableColumnsScopedState';
@@ -23,10 +22,8 @@ export const useTableColumns = () => {
TableRecoilScopeContext,
);
- const currentViewId = useRecoilScopedValue(
- currentViewIdScopedState,
- TableRecoilScopeContext,
- );
+ const { currentViewId } = useView();
+
const setSavedTableColumns = useSetRecoilState(
savedTableColumnsFamilyState(currentViewId),
);
@@ -91,7 +88,10 @@ export const useTableColumns = () => {
);
const handleMoveTableColumn = useCallback(
- (direction: 'left' | 'right', column: ColumnDefinition) => {
+ async (
+ direction: 'left' | 'right',
+ column: ColumnDefinition,
+ ) => {
const currentColumnArrayIndex = tableColumns.findIndex(
(tableColumn) => tableColumn.key === column.key,
);
@@ -101,9 +101,9 @@ export const useTableColumns = () => {
tableColumns,
);
- setTableColumns(columns);
+ await handleColumnsChange(columns);
},
- [tableColumns, setTableColumns, handleColumnMove],
+ [tableColumns, handleColumnMove, handleColumnsChange],
);
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 b99cbe534..e77b1876b 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
@@ -1,9 +1,7 @@
-import { useResetRecoilState } from 'recoil';
-
-import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
+import { useView } from '@/views/hooks/useView';
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
@@ -17,7 +15,7 @@ type TableOptionsDropdownProps = {
export const TableOptionsDropdown = ({
customHotkeyScope,
}: TableOptionsDropdownProps) => {
- const resetViewEditMode = useResetRecoilState(viewEditModeState);
+ const { setViewEditMode } = useView();
return (
@@ -26,7 +24,7 @@ export const TableOptionsDropdown = ({
dropdownHotkeyScope={customHotkeyScope}
dropdownOffset={{ y: 8 }}
dropdownComponents={}
- onClickOutside={resetViewEditMode}
+ 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 e27495189..c5c54d13d 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
@@ -1,15 +1,8 @@
-import { useCallback, useContext, useRef, useState } from 'react';
+import { useCallback, useRef, useState } from 'react';
import { OnDragEndResponder } from '@hello-pangea/dnd';
-import { useRecoilCallback, useRecoilValue, useResetRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
-import { ViewFieldsVisibilityDropdownSection } from '@/ui/data/view-bar/components/ViewFieldsVisibilityDropdownSection';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
-import { useUpsertView } from '@/ui/data/view-bar/hooks/useUpsertView';
-import { currentViewScopedSelector } from '@/ui/data/view-bar/states/selectors/currentViewScopedSelector';
-import { viewsByIdScopedSelector } from '@/ui/data/view-bar/states/selectors/viewsByIdScopedSelector';
-import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
-import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon';
+import { IconChevronLeft, 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';
@@ -18,22 +11,22 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
+import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
+import { useView } from '@/views/hooks/useView';
+import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
import { useTableColumns } from '../../hooks/useTableColumns';
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
-import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState';
import { hiddenTableColumnsScopedSelector } from '../../states/selectors/hiddenTableColumnsScopedSelector';
import { visibleTableColumnsScopedSelector } from '../../states/selectors/visibleTableColumnsScopedSelector';
-import { tableColumnsScopedState } from '../../states/tableColumnsScopedState';
import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
type TableOptionsMenu = 'fields';
export const TableOptionsDropdownContent = () => {
- const scopeId = useRecoilScopeId(TableRecoilScopeContext);
+ const { setViewEditMode, handleViewNameSubmit } = useView();
+ const { viewEditMode, currentView } = useViewInternalStates();
- const { onImport } = useContext(ViewBarContext);
const { closeDropdown } = useDropdown();
const [currentMenu, setCurrentMenu] = useState(
@@ -42,12 +35,6 @@ export const TableOptionsDropdownContent = () => {
const viewEditInputRef = useRef(null);
- const currentView = useRecoilScopedValue(
- currentViewScopedSelector,
- TableRecoilScopeContext,
- );
- const viewEditMode = useRecoilValue(viewEditModeState);
- const resetViewEditMode = useResetRecoilState(viewEditModeState);
const visibleTableColumns = useRecoilScopedValue(
visibleTableColumnsScopedSelector,
TableRecoilScopeContext,
@@ -56,35 +43,13 @@ export const TableOptionsDropdownContent = () => {
hiddenTableColumnsScopedSelector,
TableRecoilScopeContext,
);
- const viewsById = useRecoilScopedValue(
- viewsByIdScopedSelector,
- TableRecoilScopeContext,
- );
const { handleColumnVisibilityChange, handleColumnReorder } =
useTableColumns();
- const { upsertView } = useUpsertView();
-
- const handleViewNameSubmit = useRecoilCallback(
- ({ set, snapshot }) =>
- async () => {
- const tableColumns = await snapshot.getPromise(
- tableColumnsScopedState(scopeId),
- );
- const isCreateMode = viewEditMode.mode === 'create';
- const name = viewEditInputRef.current?.value;
- const view = await upsertView(name);
-
- if (view && isCreateMode) {
- set(savedTableColumnsFamilyState(view.id), tableColumns);
- }
- },
- [scopeId, upsertView, viewEditMode.mode],
- );
-
const handleSelectMenu = (option: TableOptionsMenu) => {
- handleViewNameSubmit();
+ const name = viewEditInputRef.current?.value;
+ handleViewNameSubmit(name);
setCurrentMenu(option);
};
@@ -108,7 +73,6 @@ export const TableOptionsDropdownContent = () => {
useScopedHotkeys(
Key.Escape,
() => {
- resetViewEditMode();
closeDropdown();
},
TableOptionsHotkeyScope.Dropdown,
@@ -117,9 +81,10 @@ export const TableOptionsDropdownContent = () => {
useScopedHotkeys(
Key.Enter,
() => {
- handleViewNameSubmit();
+ const name = viewEditInputRef.current?.value;
+ handleViewNameSubmit(name);
resetMenu();
- resetViewEditMode();
+ setViewEditMode('none');
closeDropdown();
},
TableOptionsHotkeyScope.Dropdown,
@@ -130,16 +95,21 @@ export const TableOptionsDropdownContent = () => {
{!currentMenu && (
<>
@@ -149,13 +119,13 @@ export const TableOptionsDropdownContent = () => {
LeftIcon={IconTag}
text="Fields"
/>
- {onImport && (
+ {/*onImport && (
- )}
+ )*/}
>
)}
diff --git a/front/src/modules/ui/data/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx b/front/src/modules/ui/data/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx
deleted file mode 100644
index 0b81a898c..000000000
--- a/front/src/modules/ui/data/data-table/options/components/__stories__/TableOptionsDropdown.stories.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { Meta, StoryObj } from '@storybook/react';
-import { userEvent, within } from '@storybook/testing-library';
-
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
-import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
-import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
-
-import { TableRecoilScopeContext } from '../../../states/recoil-scope-contexts/TableRecoilScopeContext';
-import { TableOptionsDropdown } from '../TableOptionsDropdown';
-
-const meta: Meta = {
- title: 'UI/Data/DataTable/Options/TableOptionsDropdown',
- component: TableOptionsDropdown,
- decorators: [
- (Story) => (
-
-
-
-
-
- ),
- ComponentDecorator,
- ],
-};
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {
- args: {
- customHotkeyScope: { scope: 'options' },
- },
- play: async ({ canvasElement }) => {
- const canvas = within(canvasElement);
-
- const dropdownButton = canvas.getByText('Options');
-
- await userEvent.click(dropdownButton);
- },
-};
diff --git a/front/src/modules/ui/data/data-table/table-header/components/TableHeader.tsx b/front/src/modules/ui/data/data-table/table-header/components/TableHeader.tsx
deleted file mode 100644
index 37c7b4c27..000000000
--- a/front/src/modules/ui/data/data-table/table-header/components/TableHeader.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { useContext } from 'react';
-import { useSearchParams } from 'react-router-dom';
-import { useRecoilCallback } from 'recoil';
-
-import { ViewBar } from '@/ui/data/view-bar/components/ViewBar';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
-
-import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
-import { TableOptionsDropdown } from '../../options/components/TableOptionsDropdown';
-import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
-import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState';
-import { tableColumnsScopedState } from '../../states/tableColumnsScopedState';
-import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
-
-export const TableHeader = () => {
- const { onCurrentViewSubmit, ...viewBarContextProps } =
- useContext(ViewBarContext);
- const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext);
- const [_, setSearchParams] = useSearchParams();
-
- const handleViewSelect = useRecoilCallback(
- ({ set, snapshot }) =>
- async (viewId: string) => {
- const savedTableColumns = await snapshot.getPromise(
- savedTableColumnsFamilyState(viewId),
- );
- set(tableColumnsScopedState(tableRecoilScopeId), savedTableColumns);
- setSearchParams({ view: viewId });
- },
- [tableRecoilScopeId, setSearchParams],
- );
-
- return (
-
-
- }
- optionsDropdownScopeId={TableOptionsDropdownId}
- />
-
- );
-};
diff --git a/front/src/modules/ui/data/view-bar/components/AddFilterFromDetailsButton.tsx b/front/src/modules/ui/data/filter/components/AddFilterFromDetailsButton.tsx
similarity index 100%
rename from front/src/modules/ui/data/view-bar/components/AddFilterFromDetailsButton.tsx
rename to front/src/modules/ui/data/filter/components/AddFilterFromDetailsButton.tsx
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownButton.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownButton.tsx
similarity index 63%
rename from front/src/modules/ui/data/view-bar/components/FilterDropdownButton.tsx
rename to front/src/modules/ui/data/filter/components/FilterDropdownButton.tsx
index 2afbc7ead..f4ae61453 100644
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownButton.tsx
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownButton.tsx
@@ -1,8 +1,6 @@
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
+import { useFilter } from '../hooks/useFilter';
import { MultipleFiltersDropdownButton } from './MultipleFiltersDropdownButton';
import { SingleEntityFilterDropdownButton } from './SingleEntityFilterDropdownButton';
@@ -14,12 +12,7 @@ type FilterDropdownButtonProps = {
export const FilterDropdownButton = ({
hotkeyScope,
}: FilterDropdownButtonProps) => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [availableFilters] = useRecoilScopedState(
- availableFiltersScopedState,
- ViewBarRecoilScopeContext,
- );
+ const { availableFilters } = useFilter();
const hasOnlyOneEntityFilter =
availableFilters.length === 1 && availableFilters[0].type === 'entity';
diff --git a/front/src/modules/ui/data/filter/components/FilterDropdownDateSearchInput.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownDateSearchInput.tsx
new file mode 100644
index 000000000..7ec5056d1
--- /dev/null
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownDateSearchInput.tsx
@@ -0,0 +1,36 @@
+import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
+import { useUpsertFilter } from '@/views/hooks/useUpsertFilter';
+
+import { useFilter } from '../hooks/useFilter';
+
+export const FilterDropdownDateSearchInput = () => {
+ const {
+ filterDefinitionUsedInDropdown,
+ selectedOperandInDropdown,
+ setIsFilterDropdownUnfolded,
+ } = useFilter();
+
+ const upsertFilter = useUpsertFilter();
+
+ const handleChange = (date: Date) => {
+ if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return;
+
+ upsertFilter({
+ key: filterDefinitionUsedInDropdown.key,
+ type: filterDefinitionUsedInDropdown.type,
+ value: date.toISOString(),
+ operand: selectedOperandInDropdown,
+ displayValue: date.toLocaleDateString(),
+ });
+
+ setIsFilterDropdownUnfolded(false);
+ };
+
+ return (
+
+ );
+};
diff --git a/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchInput.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchInput.tsx
new file mode 100644
index 000000000..849e4f5f4
--- /dev/null
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchInput.tsx
@@ -0,0 +1,29 @@
+import { ChangeEvent } from 'react';
+
+import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
+
+import { useFilter } from '../hooks/useFilter';
+
+export const FilterDropdownEntitySearchInput = () => {
+ const {
+ filterDefinitionUsedInDropdown,
+ selectedOperandInDropdown,
+ filterDropdownSearchInput,
+ setFilterDropdownSearchInput,
+ } = useFilter();
+
+ return (
+ filterDefinitionUsedInDropdown &&
+ selectedOperandInDropdown && (
+ ) => {
+ setFilterDropdownSearchInput(event.target.value);
+ }}
+ />
+ )
+ );
+};
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchSelect.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchSelect.tsx
similarity index 70%
rename from front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchSelect.tsx
rename to front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchSelect.tsx
index e044464d2..dd668512f 100644
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchSelect.tsx
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySearchSelect.tsx
@@ -1,45 +1,30 @@
import { useEffect, useState } from 'react';
-import { useFilterCurrentlyEdited } from '@/ui/data/view-bar/hooks/useFilterCurrentlyEdited';
-import { useRemoveFilter } from '@/ui/data/view-bar/hooks/useRemoveFilter';
-import { useUpsertFilter } from '@/ui/data/view-bar/hooks/useUpsertFilter';
-import { filterDefinitionUsedInDropdownScopedState } from '@/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState';
-import { filterDropdownSelectedEntityIdScopedState } from '@/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState';
-import { selectedOperandInDropdownScopedState } from '@/ui/data/view-bar/states/selectedOperandInDropdownScopedState';
+import { useFilterCurrentlyEdited } from '@/ui/data/filter/hooks/useFilterCurrentlyEdited';
import { EntitiesForMultipleEntitySelect } from '@/ui/input/relation-picker/components/MultipleEntitySelect';
import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase';
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
+import { useRemoveFilter } from '@/views/hooks/useRemoveFilter';
+import { useUpsertFilter } from '@/views/hooks/useUpsertFilter';
import { ViewFilterOperand } from '~/generated/graphql';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
+import { useFilter } from '../hooks/useFilter';
export const FilterDropdownEntitySearchSelect = ({
entitiesForSelect,
}: {
entitiesForSelect: EntitiesForMultipleEntitySelect;
}) => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
+ const {
+ filterDropdownSelectedEntityId,
+ setFilterDropdownSelectedEntityId,
+ filterDefinitionUsedInDropdown,
+ selectedOperandInDropdown,
+ filterDropdownSearchInput,
+ } = useFilter();
const [isAllEntitySelected, setIsAllEntitySelected] = useState(false);
- const [filterDropdownSelectedEntityId, setFilterDropdownSelectedEntityId] =
- useRecoilScopedState(
- filterDropdownSelectedEntityIdScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [selectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
const upsertFilter = useUpsertFilter();
const removeFilter = useRemoveFilter();
@@ -80,11 +65,6 @@ export const FilterDropdownEntitySearchSelect = ({
}
};
- const [filterDropdownSearchInput] = useRecoilScopedState(
- filterDropdownSearchInputScopedState,
- ViewBarRecoilScopeContext,
- );
-
const isAllEntitySelectShown =
!!filterDefinitionUsedInDropdown?.selectAllLabel &&
!!filterDefinitionUsedInDropdown?.SelectAllIcon &&
diff --git a/front/src/modules/ui/data/filter/components/FilterDropdownEntitySelect.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySelect.tsx
new file mode 100644
index 000000000..5653685ef
--- /dev/null
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownEntitySelect.tsx
@@ -0,0 +1,21 @@
+import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
+import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
+
+import { useFilter } from '../hooks/useFilter';
+
+export const FilterDropdownEntitySelect = () => {
+ const { filterDefinitionUsedInDropdown } = useFilter();
+
+ if (filterDefinitionUsedInDropdown?.type !== 'entity') {
+ return null;
+ }
+
+ return (
+ <>
+
+
+ {filterDefinitionUsedInDropdown.entitySelectComponent}
+
+ >
+ );
+};
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownFilterSelect.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownFilterSelect.tsx
similarity index 50%
rename from front/src/modules/ui/data/view-bar/components/FilterDropdownFilterSelect.tsx
rename to front/src/modules/ui/data/filter/components/FilterDropdownFilterSelect.tsx
index 105dd38ce..556282495 100644
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownFilterSelect.tsx
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownFilterSelect.tsx
@@ -2,38 +2,17 @@ import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/Rela
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
-import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
+import { useFilter } from '../hooks/useFilter';
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
export const FilterDropdownFilterSelect = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [, setFilterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setSelectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setFilterDropdownSearchInput] = useRecoilScopedState(
- filterDropdownSearchInputScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const availableFilters = useRecoilScopedValue(
- availableFiltersScopedState,
- ViewBarRecoilScopeContext,
- );
+ const {
+ setFilterDefinitionUsedInDropdown,
+ setSelectedOperandInDropdown,
+ setFilterDropdownSearchInput,
+ availableFilters,
+ } = useFilter();
const setHotkeyScope = useSetHotkeyScope();
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownNumberSearchInput.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownNumberSearchInput.tsx
similarity index 54%
rename from front/src/modules/ui/data/view-bar/components/FilterDropdownNumberSearchInput.tsx
rename to front/src/modules/ui/data/filter/components/FilterDropdownNumberSearchInput.tsx
index 11cb6593f..ea8fc8585 100644
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownNumberSearchInput.tsx
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownNumberSearchInput.tsx
@@ -1,26 +1,14 @@
import { ChangeEvent } from 'react';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRemoveFilter } from '../hooks/useRemoveFilter';
-import { useUpsertFilter } from '../hooks/useUpsertFilter';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
+import { useRemoveFilter } from '../../../../views/hooks/useRemoveFilter';
+import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter';
+import { useFilter } from '../hooks/useFilter';
export const FilterDropdownNumberSearchInput = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [selectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
+ const { selectedOperandInDropdown, filterDefinitionUsedInDropdown } =
+ useFilter();
const upsertFilter = useUpsertFilter();
const removeFilter = useRemoveFilter();
diff --git a/front/src/modules/ui/data/filter/components/FilterDropdownOperandButton.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownOperandButton.tsx
new file mode 100644
index 000000000..1aa96c3a5
--- /dev/null
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownOperandButton.tsx
@@ -0,0 +1,27 @@
+import { IconChevronDown } from '@/ui/display/icon';
+import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
+
+import { useFilter } from '../hooks/useFilter';
+import { getOperandLabel } from '../utils/getOperandLabel';
+
+export const FilterDropdownOperandButton = () => {
+ const {
+ selectedOperandInDropdown,
+ setIsFilterDropdownOperandSelectUnfolded,
+ isFilterDropdownOperandSelectUnfolded,
+ } = useFilter();
+
+ if (isFilterDropdownOperandSelectUnfolded) {
+ return null;
+ }
+
+ return (
+ setIsFilterDropdownOperandSelectUnfolded(true)}
+ >
+ {getOperandLabel(selectedOperandInDropdown)}
+
+ );
+};
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandSelect.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownOperandSelect.tsx
similarity index 62%
rename from front/src/modules/ui/data/view-bar/components/FilterDropdownOperandSelect.tsx
rename to front/src/modules/ui/data/filter/components/FilterDropdownOperandSelect.tsx
index abd243504..5bfe4ef8b 100644
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandSelect.tsx
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownOperandSelect.tsx
@@ -1,42 +1,25 @@
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { ViewFilterOperand } from '~/generated/graphql';
+import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter';
+import { useFilter } from '../hooks/useFilter';
import { useFilterCurrentlyEdited } from '../hooks/useFilterCurrentlyEdited';
-import { useUpsertFilter } from '../hooks/useUpsertFilter';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState';
-import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
import { getOperandLabel } from '../utils/getOperandLabel';
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
export const FilterDropdownOperandSelect = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setSelectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
+ const {
+ filterDefinitionUsedInDropdown,
+ setSelectedOperandInDropdown,
+ isFilterDropdownOperandSelectUnfolded,
+ setIsFilterDropdownOperandSelectUnfolded,
+ } = useFilter();
const operandsForFilterType = getOperandsForFilterType(
filterDefinitionUsedInDropdown?.type,
);
- const [
- isFilterDropdownOperandSelectUnfolded,
- setIsFilterDropdownOperandSelectUnfolded,
- ] = useRecoilScopedState(
- isFilterDropdownOperandSelectUnfoldedScopedState,
- ViewBarRecoilScopeContext,
- );
-
const filterCurrentlyEdited = useFilterCurrentlyEdited();
const upsertFilter = useUpsertFilter();
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownTextSearchInput.tsx b/front/src/modules/ui/data/filter/components/FilterDropdownTextSearchInput.tsx
similarity index 53%
rename from front/src/modules/ui/data/view-bar/components/FilterDropdownTextSearchInput.tsx
rename to front/src/modules/ui/data/filter/components/FilterDropdownTextSearchInput.tsx
index fb1e0b0ef..b65cc5dc7 100644
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownTextSearchInput.tsx
+++ b/front/src/modules/ui/data/filter/components/FilterDropdownTextSearchInput.tsx
@@ -1,34 +1,19 @@
import { ChangeEvent } from 'react';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
+import { useRemoveFilter } from '../../../../views/hooks/useRemoveFilter';
+import { useUpsertFilter } from '../../../../views/hooks/useUpsertFilter';
+import { useFilter } from '../hooks/useFilter';
import { useFilterCurrentlyEdited } from '../hooks/useFilterCurrentlyEdited';
-import { useRemoveFilter } from '../hooks/useRemoveFilter';
-import { useUpsertFilter } from '../hooks/useUpsertFilter';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
-import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
export const FilterDropdownTextSearchInput = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [selectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [filterDropdownSearchInput, setFilterDropdownSearchInput] =
- useRecoilScopedState(
- filterDropdownSearchInputScopedState,
- ViewBarRecoilScopeContext,
- );
+ const {
+ filterDefinitionUsedInDropdown,
+ selectedOperandInDropdown,
+ filterDropdownSearchInput,
+ setFilterDropdownSearchInput,
+ } = useFilter();
const upsertFilter = useUpsertFilter();
const removeFilter = useRemoveFilter();
diff --git a/front/src/modules/ui/data/view-bar/components/GenericEntityFilterChip.tsx b/front/src/modules/ui/data/filter/components/GenericEntityFilterChip.tsx
similarity index 100%
rename from front/src/modules/ui/data/view-bar/components/GenericEntityFilterChip.tsx
rename to front/src/modules/ui/data/filter/components/GenericEntityFilterChip.tsx
diff --git a/front/src/modules/ui/data/filter/components/MultipleFiltersButton.tsx b/front/src/modules/ui/data/filter/components/MultipleFiltersButton.tsx
new file mode 100644
index 000000000..e00545af2
--- /dev/null
+++ b/front/src/modules/ui/data/filter/components/MultipleFiltersButton.tsx
@@ -0,0 +1,39 @@
+import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
+import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
+
+import { FilterDropdownId } from '../constants/FilterDropdownId';
+import { useFilter } from '../hooks/useFilter';
+
+export const MultipleFiltersButton = () => {
+ const {
+ setFilterDefinitionUsedInDropdown,
+ setIsFilterDropdownOperandSelectUnfolded,
+ setFilterDropdownSearchInput,
+ setSelectedOperandInDropdown,
+ } = useFilter();
+
+ const { isDropdownOpen, toggleDropdown } = useDropdown({
+ dropdownScopeId: FilterDropdownId,
+ });
+
+ const resetState = () => {
+ setIsFilterDropdownOperandSelectUnfolded(false);
+ setFilterDefinitionUsedInDropdown(null);
+ setSelectedOperandInDropdown(null);
+ setFilterDropdownSearchInput('');
+ };
+
+ const handleClick = () => {
+ toggleDropdown();
+ resetState();
+ };
+
+ return (
+
+ Filter
+
+ );
+};
diff --git a/front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownButton.tsx b/front/src/modules/ui/data/filter/components/MultipleFiltersDropdownButton.tsx
similarity index 100%
rename from front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownButton.tsx
rename to front/src/modules/ui/data/filter/components/MultipleFiltersDropdownButton.tsx
diff --git a/front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownContent.tsx b/front/src/modules/ui/data/filter/components/MultipleFiltersDropdownContent.tsx
similarity index 67%
rename from front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownContent.tsx
rename to front/src/modules/ui/data/filter/components/MultipleFiltersDropdownContent.tsx
index 0cd002eee..61ed8c50c 100644
--- a/front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownContent.tsx
+++ b/front/src/modules/ui/data/filter/components/MultipleFiltersDropdownContent.tsx
@@ -1,10 +1,6 @@
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState';
-import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
+import { useFilter } from '../hooks/useFilter';
import { FilterDropdownDateSearchInput } from './FilterDropdownDateSearchInput';
import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInput';
@@ -17,22 +13,11 @@ import { FilterDropdownTextSearchInput } from './FilterDropdownTextSearchInput';
import { MultipleFiltersDropdownFilterOnFilterChangedEffect } from './MultipleFiltersDropdownFilterOnFilterChangedEffect';
export const MultipleFiltersDropdownContent = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [isFilterDropdownOperandSelectUnfolded] = useRecoilScopedState(
- isFilterDropdownOperandSelectUnfoldedScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [selectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
+ const {
+ isFilterDropdownOperandSelectUnfolded,
+ filterDefinitionUsedInDropdown,
+ selectedOperandInDropdown,
+ } = useFilter();
return (
<>
diff --git a/front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx b/front/src/modules/ui/data/filter/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx
similarity index 100%
rename from front/src/modules/ui/data/view-bar/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx
rename to front/src/modules/ui/data/filter/components/MultipleFiltersDropdownFilterOnFilterChangedEffect.tsx
diff --git a/front/src/modules/ui/data/view-bar/components/SingleEntityFilterDropdownButton.tsx b/front/src/modules/ui/data/filter/components/SingleEntityFilterDropdownButton.tsx
similarity index 62%
rename from front/src/modules/ui/data/view-bar/components/SingleEntityFilterDropdownButton.tsx
rename to front/src/modules/ui/data/filter/components/SingleEntityFilterDropdownButton.tsx
index efa7baaf1..2b24a0051 100644
--- a/front/src/modules/ui/data/view-bar/components/SingleEntityFilterDropdownButton.tsx
+++ b/front/src/modules/ui/data/filter/components/SingleEntityFilterDropdownButton.tsx
@@ -6,14 +6,9 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { ViewFilterOperand } from '~/generated/graphql';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-import { filtersScopedState } from '../states/filtersScopedState';
-import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
+import { useFilter } from '../hooks/useFilter';
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
import { FilterDropdownEntitySearchInput } from './FilterDropdownEntitySearchInput';
@@ -25,29 +20,15 @@ export const SingleEntityFilterDropdownButton = ({
}: {
hotkeyScope: HotkeyScope;
}) => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
+ const {
+ availableFilters,
+ selectedFilters,
+ setFilterDefinitionUsedInDropdown,
+ setSelectedOperandInDropdown,
+ } = useFilter();
- const [availableFilters] = useRecoilScopedState(
- availableFiltersScopedState,
- ViewBarRecoilScopeContext,
- );
const availableFilter = availableFilters[0];
- const [filters] = useRecoilScopedState(
- filtersScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setFilterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setSelectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
React.useEffect(() => {
setFilterDefinitionUsedInDropdown(availableFilter);
const defaultOperand = getOperandsForFilterType(availableFilter?.type)[0];
@@ -67,11 +48,11 @@ export const SingleEntityFilterDropdownButton = ({
dropdownOffset={{ x: 0, y: -28 }}
clickableComponent={
- {filters[0] ? (
+ {selectedFilters[0] ? (
{
+ const scopeId = useAvailableScopeIdOrThrow(
+ FilterScopeInternalContext,
+ props?.filterScopeId,
+ );
+ const {
+ availableFilters,
+ setAvailableFilters,
+ filterDefinitionUsedInDropdown,
+ setFilterDefinitionUsedInDropdown,
+ filterDropdownSearchInput,
+ setFilterDropdownSearchInput,
+ filterDropdownSelectedEntityId,
+ setFilterDropdownSelectedEntityId,
+ isFilterDropdownOperandSelectUnfolded,
+ setIsFilterDropdownOperandSelectUnfolded,
+ isFilterDropdownUnfolded,
+ setIsFilterDropdownUnfolded,
+ selectedFilters,
+ setSelectedFilters,
+ selectedOperandInDropdown,
+ setSelectedOperandInDropdown,
+ } = useFilterStates(scopeId);
+
+ return {
+ scopeId,
+ availableFilters,
+ setAvailableFilters,
+ filterDefinitionUsedInDropdown,
+ setFilterDefinitionUsedInDropdown,
+ filterDropdownSearchInput,
+ setFilterDropdownSearchInput,
+ filterDropdownSelectedEntityId,
+ setFilterDropdownSelectedEntityId,
+ isFilterDropdownOperandSelectUnfolded,
+ setIsFilterDropdownOperandSelectUnfolded,
+ isFilterDropdownUnfolded,
+ setIsFilterDropdownUnfolded,
+ selectedFilters,
+ setSelectedFilters,
+ selectedOperandInDropdown,
+ setSelectedOperandInDropdown,
+ };
+};
diff --git a/front/src/modules/ui/data/filter/hooks/useFilterCurrentlyEdited.ts b/front/src/modules/ui/data/filter/hooks/useFilterCurrentlyEdited.ts
new file mode 100644
index 000000000..e0d4e4e5f
--- /dev/null
+++ b/front/src/modules/ui/data/filter/hooks/useFilterCurrentlyEdited.ts
@@ -0,0 +1,13 @@
+import { useMemo } from 'react';
+
+import { useFilter } from './useFilter';
+
+export const useFilterCurrentlyEdited = () => {
+ const { selectedFilters, filterDefinitionUsedInDropdown } = useFilter();
+
+ return useMemo(() => {
+ return selectedFilters?.find(
+ (filter) => filter.key === filterDefinitionUsedInDropdown?.key,
+ );
+ }, [filterDefinitionUsedInDropdown?.key, selectedFilters]);
+};
diff --git a/front/src/modules/ui/data/filter/hooks/useFilterStates.ts b/front/src/modules/ui/data/filter/hooks/useFilterStates.ts
new file mode 100644
index 000000000..6dc39a724
--- /dev/null
+++ b/front/src/modules/ui/data/filter/hooks/useFilterStates.ts
@@ -0,0 +1,64 @@
+import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
+
+import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
+import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
+import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
+import { filterDropdownSelectedEntityIdScopedState } from '../states/filterDropdownSelectedEntityIdScopedState';
+import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState';
+import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState';
+import { selectedFiltersScopedState } from '../states/selectedFiltersScopedState';
+import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
+
+export const useFilterStates = (scopeId: string) => {
+ const [availableFilters, setAvailableFilters] = useRecoilScopedStateV2(
+ availableFiltersScopedState,
+ scopeId,
+ );
+
+ const [filterDefinitionUsedInDropdown, setFilterDefinitionUsedInDropdown] =
+ useRecoilScopedStateV2(filterDefinitionUsedInDropdownScopedState, scopeId);
+
+ const [filterDropdownSearchInput, setFilterDropdownSearchInput] =
+ useRecoilScopedStateV2(filterDropdownSearchInputScopedState, scopeId);
+
+ const [filterDropdownSelectedEntityId, setFilterDropdownSelectedEntityId] =
+ useRecoilScopedStateV2(filterDropdownSelectedEntityIdScopedState, scopeId);
+
+ const [
+ isFilterDropdownOperandSelectUnfolded,
+ setIsFilterDropdownOperandSelectUnfolded,
+ ] = useRecoilScopedStateV2(
+ isFilterDropdownOperandSelectUnfoldedScopedState,
+ scopeId,
+ );
+
+ const [isFilterDropdownUnfolded, setIsFilterDropdownUnfolded] =
+ useRecoilScopedStateV2(isFilterDropdownUnfoldedScopedState, scopeId);
+
+ const [selectedFilters, setSelectedFilters] = useRecoilScopedStateV2(
+ selectedFiltersScopedState,
+ scopeId,
+ );
+
+ const [selectedOperandInDropdown, setSelectedOperandInDropdown] =
+ useRecoilScopedStateV2(selectedOperandInDropdownScopedState, scopeId);
+
+ return {
+ availableFilters,
+ setAvailableFilters,
+ filterDefinitionUsedInDropdown,
+ setFilterDefinitionUsedInDropdown,
+ filterDropdownSearchInput,
+ setFilterDropdownSearchInput,
+ filterDropdownSelectedEntityId,
+ setFilterDropdownSelectedEntityId,
+ isFilterDropdownOperandSelectUnfolded,
+ setIsFilterDropdownOperandSelectUnfolded,
+ isFilterDropdownUnfolded,
+ setIsFilterDropdownUnfolded,
+ selectedFilters,
+ setSelectedFilters,
+ selectedOperandInDropdown,
+ setSelectedOperandInDropdown,
+ };
+};
diff --git a/front/src/modules/ui/data/filter/scopes/FilterScope.tsx b/front/src/modules/ui/data/filter/scopes/FilterScope.tsx
new file mode 100644
index 000000000..594554156
--- /dev/null
+++ b/front/src/modules/ui/data/filter/scopes/FilterScope.tsx
@@ -0,0 +1,28 @@
+import { ReactNode } from 'react';
+
+import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
+
+import { FilterScopeInitEffect } from './init-effect/FilterScopeInitEffect';
+import { FilterScopeInternalContext } from './scope-internal-context/FilterScopeInternalContext';
+
+type FilterScopeProps = {
+ children: ReactNode;
+ filterScopeId: string;
+ availableFilters?: FilterDefinition[];
+};
+
+export const FilterScope = ({
+ children,
+ filterScopeId,
+ availableFilters,
+}: FilterScopeProps) => {
+ return (
+
+
+ {children}
+
+ );
+};
diff --git a/front/src/modules/ui/data/filter/scopes/init-effect/FilterScopeInitEffect.tsx b/front/src/modules/ui/data/filter/scopes/init-effect/FilterScopeInitEffect.tsx
new file mode 100644
index 000000000..1068f1797
--- /dev/null
+++ b/front/src/modules/ui/data/filter/scopes/init-effect/FilterScopeInitEffect.tsx
@@ -0,0 +1,25 @@
+import { useEffect } from 'react';
+
+import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
+
+import { useFilterStates } from '../../hooks/useFilterStates';
+
+type FilterScopeInitEffectProps = {
+ filterScopeId: string;
+ availableFilters?: FilterDefinition[];
+};
+
+export const FilterScopeInitEffect = ({
+ filterScopeId,
+ availableFilters,
+}: FilterScopeInitEffectProps) => {
+ const { setAvailableFilters } = useFilterStates(filterScopeId);
+
+ useEffect(() => {
+ if (availableFilters) {
+ setAvailableFilters(availableFilters);
+ }
+ }, [availableFilters, setAvailableFilters]);
+
+ return <>>;
+};
diff --git a/front/src/modules/ui/data/filter/scopes/scope-internal-context/FilterScopeInternalContext.ts b/front/src/modules/ui/data/filter/scopes/scope-internal-context/FilterScopeInternalContext.ts
new file mode 100644
index 000000000..e45d8d6ae
--- /dev/null
+++ b/front/src/modules/ui/data/filter/scopes/scope-internal-context/FilterScopeInternalContext.ts
@@ -0,0 +1,9 @@
+import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey';
+import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
+
+type FilterScopeInternalContextProps = ScopedStateKey & {
+ test?: string;
+};
+
+export const FilterScopeInternalContext =
+ createScopeInternalContext();
diff --git a/front/src/modules/ui/data/filter/states/availableFiltersScopedState.ts b/front/src/modules/ui/data/filter/states/availableFiltersScopedState.ts
new file mode 100644
index 000000000..9c38f3952
--- /dev/null
+++ b/front/src/modules/ui/data/filter/states/availableFiltersScopedState.ts
@@ -0,0 +1,9 @@
+import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const availableFiltersScopedState = createScopedState<
+ FilterDefinition[]
+>({
+ key: 'availableFiltersScopedState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/ui/data/filter/states/filterDefinitionUsedInDropdownScopedState.ts b/front/src/modules/ui/data/filter/states/filterDefinitionUsedInDropdownScopedState.ts
new file mode 100644
index 000000000..c848f4052
--- /dev/null
+++ b/front/src/modules/ui/data/filter/states/filterDefinitionUsedInDropdownScopedState.ts
@@ -0,0 +1,9 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+import { FilterDefinition } from '../types/FilterDefinition';
+
+export const filterDefinitionUsedInDropdownScopedState =
+ createScopedState({
+ key: 'filterDefinitionUsedInDropdownScopedState',
+ defaultValue: null,
+ });
diff --git a/front/src/modules/ui/data/filter/states/filterDropdownSearchInputScopedState.ts b/front/src/modules/ui/data/filter/states/filterDropdownSearchInputScopedState.ts
new file mode 100644
index 000000000..b81c820e5
--- /dev/null
+++ b/front/src/modules/ui/data/filter/states/filterDropdownSearchInputScopedState.ts
@@ -0,0 +1,6 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const filterDropdownSearchInputScopedState = createScopedState({
+ key: 'filterDropdownSearchInputScopedState',
+ defaultValue: '',
+});
diff --git a/front/src/modules/ui/data/filter/states/filterDropdownSelectedEntityIdScopedState.ts b/front/src/modules/ui/data/filter/states/filterDropdownSelectedEntityIdScopedState.ts
new file mode 100644
index 000000000..799c06481
--- /dev/null
+++ b/front/src/modules/ui/data/filter/states/filterDropdownSelectedEntityIdScopedState.ts
@@ -0,0 +1,8 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const filterDropdownSelectedEntityIdScopedState = createScopedState<
+ string | null
+>({
+ key: 'filterDropdownSelectedEntityIdScopedState',
+ defaultValue: null,
+});
diff --git a/front/src/modules/ui/data/filter/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts b/front/src/modules/ui/data/filter/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts
new file mode 100644
index 000000000..3bda55bdf
--- /dev/null
+++ b/front/src/modules/ui/data/filter/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts
@@ -0,0 +1,7 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const isFilterDropdownOperandSelectUnfoldedScopedState =
+ createScopedState({
+ key: 'isFilterDropdownOperandSelectUnfoldedScopedState',
+ defaultValue: false,
+ });
diff --git a/front/src/modules/ui/data/filter/states/isFilterDropdownUnfoldedScopedState.ts b/front/src/modules/ui/data/filter/states/isFilterDropdownUnfoldedScopedState.ts
new file mode 100644
index 000000000..57799a876
--- /dev/null
+++ b/front/src/modules/ui/data/filter/states/isFilterDropdownUnfoldedScopedState.ts
@@ -0,0 +1,6 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const isFilterDropdownUnfoldedScopedState = createScopedState({
+ key: 'isFilterDropdownUnfoldedScopedState',
+ defaultValue: false,
+});
diff --git a/front/src/modules/ui/data/filter/states/selectedFiltersScopedState.ts b/front/src/modules/ui/data/filter/states/selectedFiltersScopedState.ts
new file mode 100644
index 000000000..716548451
--- /dev/null
+++ b/front/src/modules/ui/data/filter/states/selectedFiltersScopedState.ts
@@ -0,0 +1,8 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+import { Filter } from '../types/Filter';
+
+export const selectedFiltersScopedState = createScopedState({
+ key: 'selectedFiltersScopedState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/ui/data/filter/states/selectedOperandInDropdownScopedState.ts b/front/src/modules/ui/data/filter/states/selectedOperandInDropdownScopedState.ts
new file mode 100644
index 000000000..ee96c8ab3
--- /dev/null
+++ b/front/src/modules/ui/data/filter/states/selectedOperandInDropdownScopedState.ts
@@ -0,0 +1,8 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+import { ViewFilterOperand } from '~/generated/graphql';
+
+export const selectedOperandInDropdownScopedState =
+ createScopedState({
+ key: 'selectedOperandInDropdownScopedState',
+ defaultValue: null,
+ });
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/filtersWhereScopedSelector.ts b/front/src/modules/ui/data/filter/states/selectors/filtersWhereScopedSelector.ts
similarity index 55%
rename from front/src/modules/ui/data/view-bar/states/selectors/filtersWhereScopedSelector.ts
rename to front/src/modules/ui/data/filter/states/selectors/filtersWhereScopedSelector.ts
index e23d517d0..a52dc4c14 100644
--- a/front/src/modules/ui/data/view-bar/states/selectors/filtersWhereScopedSelector.ts
+++ b/front/src/modules/ui/data/filter/states/selectors/filtersWhereScopedSelector.ts
@@ -1,13 +1,15 @@
import { selectorFamily } from 'recoil';
import { turnFilterIntoWhereClause } from '../../utils/turnFilterIntoWhereClause';
-import { filtersScopedState } from '../filtersScopedState';
+import { selectedFiltersScopedState } from '../selectedFiltersScopedState';
export const filtersWhereScopedSelector = selectorFamily({
key: 'filtersWhereScopedSelector',
get:
- (param: string) =>
+ (scopeId: string) =>
({ get }) => ({
- AND: get(filtersScopedState(param)).map(turnFilterIntoWhereClause),
+ AND: get(selectedFiltersScopedState({ scopeId })).map(
+ turnFilterIntoWhereClause,
+ ),
}),
});
diff --git a/front/src/modules/ui/data/view-bar/types/Filter.ts b/front/src/modules/ui/data/filter/types/Filter.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/Filter.ts
rename to front/src/modules/ui/data/filter/types/Filter.ts
diff --git a/front/src/modules/ui/data/view-bar/types/FilterDefinition.ts b/front/src/modules/ui/data/filter/types/FilterDefinition.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/FilterDefinition.ts
rename to front/src/modules/ui/data/filter/types/FilterDefinition.ts
diff --git a/front/src/modules/ui/data/view-bar/types/FilterDefinitionByEntity.ts b/front/src/modules/ui/data/filter/types/FilterDefinitionByEntity.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/FilterDefinitionByEntity.ts
rename to front/src/modules/ui/data/filter/types/FilterDefinitionByEntity.ts
diff --git a/front/src/modules/ui/data/view-bar/types/FilterOperand.ts b/front/src/modules/ui/data/filter/types/FilterOperand.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/FilterOperand.ts
rename to front/src/modules/ui/data/filter/types/FilterOperand.ts
diff --git a/front/src/modules/ui/data/view-bar/types/FilterType.ts b/front/src/modules/ui/data/filter/types/FilterType.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/FilterType.ts
rename to front/src/modules/ui/data/filter/types/FilterType.ts
diff --git a/front/src/modules/ui/data/view-bar/types/FiltersHotkeyScope.ts b/front/src/modules/ui/data/filter/types/FiltersHotkeyScope.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/FiltersHotkeyScope.ts
rename to front/src/modules/ui/data/filter/types/FiltersHotkeyScope.ts
diff --git a/front/src/modules/ui/data/view-bar/utils/getOperandLabel.ts b/front/src/modules/ui/data/filter/utils/getOperandLabel.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/utils/getOperandLabel.ts
rename to front/src/modules/ui/data/filter/utils/getOperandLabel.ts
diff --git a/front/src/modules/ui/data/view-bar/utils/getOperandsForFilterType.ts b/front/src/modules/ui/data/filter/utils/getOperandsForFilterType.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/utils/getOperandsForFilterType.ts
rename to front/src/modules/ui/data/filter/utils/getOperandsForFilterType.ts
diff --git a/front/src/modules/ui/data/view-bar/utils/turnFilterIntoWhereClause.ts b/front/src/modules/ui/data/filter/utils/turnFilterIntoWhereClause.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/utils/turnFilterIntoWhereClause.ts
rename to front/src/modules/ui/data/filter/utils/turnFilterIntoWhereClause.ts
diff --git a/front/src/modules/ui/data/view-bar/components/SortDropdownButton.tsx b/front/src/modules/ui/data/sort/components/SortDropdownButton.tsx
similarity index 74%
rename from front/src/modules/ui/data/view-bar/components/SortDropdownButton.tsx
rename to front/src/modules/ui/data/sort/components/SortDropdownButton.tsx
index 8d7e23bbf..10e59ee64 100644
--- a/front/src/modules/ui/data/view-bar/components/SortDropdownButton.tsx
+++ b/front/src/modules/ui/data/sort/components/SortDropdownButton.tsx
@@ -1,5 +1,4 @@
import { useCallback, useState } from 'react';
-import { produce } from 'immer';
import { IconChevronDown } from '@/ui/display/icon';
import { LightButton } from '@/ui/input/button/components/LightButton';
@@ -11,12 +10,9 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { SortDropdownId } from '../constants/SortDropdownId';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { availableSortsScopedState } from '../states/availableSortsScopedState';
-import { sortsScopedState } from '../states/sortsScopedState';
+import { useSort } from '../hooks/useSort';
import { SortDefinition } from '../types/SortDefinition';
import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection';
@@ -28,8 +24,6 @@ export type SortDropdownButtonProps = {
export const SortDropdownButton = ({
hotkeyScope,
}: SortDropdownButtonProps) => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
const [isSortDirectionMenuUnfolded, setIsSortDirectionMenuUnfolded] =
useState(false);
@@ -41,17 +35,7 @@ export const SortDropdownButton = ({
setSelectedSortDirection('asc');
}, []);
- const [availableSorts] = useRecoilScopedState(
- availableSortsScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [sorts, setSorts] = useRecoilScopedState(
- sortsScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const isSortSelected = sorts.length > 0;
+ const { availableSorts, onSortAdd, isSortSelected } = useSort();
const { toggleDropdown } = useDropdown({
dropdownScopeId: SortDropdownId,
@@ -64,25 +48,11 @@ export const SortDropdownButton = ({
const handleAddSort = (selectedSortDefinition: SortDefinition) => {
toggleDropdown();
-
- setSorts(
- produce(sorts, (existingSortsDraft) => {
- const foundExistingSortIndex = existingSortsDraft.findIndex(
- (existingSort) => existingSort.key === selectedSortDefinition.key,
- );
-
- if (foundExistingSortIndex !== -1) {
- existingSortsDraft[foundExistingSortIndex].direction =
- selectedSortDirection;
- } else {
- existingSortsDraft.push({
- key: selectedSortDefinition.key,
- direction: selectedSortDirection,
- definition: selectedSortDefinition,
- });
- }
- }),
- );
+ onSortAdd?.({
+ key: selectedSortDefinition.key,
+ direction: selectedSortDirection,
+ definition: selectedSortDefinition,
+ });
};
const handleDropdownButtonClose = () => {
diff --git a/front/src/modules/ui/data/view-bar/constants/SortDropdownId.ts b/front/src/modules/ui/data/sort/constants/SortDropdownId.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/constants/SortDropdownId.ts
rename to front/src/modules/ui/data/sort/constants/SortDropdownId.ts
diff --git a/front/src/modules/ui/data/sort/hooks/useSort.ts b/front/src/modules/ui/data/sort/hooks/useSort.ts
new file mode 100644
index 000000000..2559f8fcf
--- /dev/null
+++ b/front/src/modules/ui/data/sort/hooks/useSort.ts
@@ -0,0 +1,36 @@
+import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
+
+import { SortScopeInternalContext } from '../scopes/scope-internal-context/SortScopeInternalContext';
+
+import { useScopeInternalContextOrThrow } from './../../../utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContextOrThrow';
+import { useSortStates } from './useSortStates';
+
+type UseSortProps = {
+ sortScopeId?: string;
+};
+
+export const useSort = (props?: UseSortProps) => {
+ const scopeId = useAvailableScopeIdOrThrow(
+ SortScopeInternalContext,
+ props?.sortScopeId,
+ );
+ const {
+ availableSorts,
+ setAvailableSorts,
+ isSortSelected,
+ setIsSortSelected,
+ } = useSortStates(scopeId);
+
+ const { onSortAdd } = useScopeInternalContextOrThrow(
+ SortScopeInternalContext,
+ );
+
+ return {
+ onSortAdd,
+ scopeId,
+ availableSorts,
+ isSortSelected,
+ setIsSortSelected,
+ setAvailableSorts,
+ };
+};
diff --git a/front/src/modules/ui/data/sort/hooks/useSortStates.ts b/front/src/modules/ui/data/sort/hooks/useSortStates.ts
new file mode 100644
index 000000000..78d94081e
--- /dev/null
+++ b/front/src/modules/ui/data/sort/hooks/useSortStates.ts
@@ -0,0 +1,23 @@
+import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
+import { availableSortsScopedState } from '@/views/states/availableSortsScopedState';
+
+import { isSortSelectedScopedState } from '../states/isSortSelectedScopedState';
+
+export const useSortStates = (scopeId: string) => {
+ const [availableSorts, setAvailableSorts] = useRecoilScopedStateV2(
+ availableSortsScopedState,
+ scopeId,
+ );
+
+ const [isSortSelected, setIsSortSelected] = useRecoilScopedStateV2(
+ isSortSelectedScopedState,
+ scopeId,
+ );
+
+ return {
+ availableSorts,
+ setAvailableSorts,
+ isSortSelected,
+ setIsSortSelected,
+ };
+};
diff --git a/front/src/modules/ui/data/sort/scopes/SortScope.tsx b/front/src/modules/ui/data/sort/scopes/SortScope.tsx
new file mode 100644
index 000000000..0b511fd1b
--- /dev/null
+++ b/front/src/modules/ui/data/sort/scopes/SortScope.tsx
@@ -0,0 +1,33 @@
+import { ReactNode } from 'react';
+
+import { Sort } from '../types/Sort';
+import { SortDefinition } from '../types/SortDefinition';
+
+import { SortScopeInitEffect } from './init-effect/SortScopeInitEffect';
+import { SortScopeInternalContext } from './scope-internal-context/SortScopeInternalContext';
+
+type SortScopeProps = {
+ children: ReactNode;
+ sortScopeId: string;
+ availableSorts?: SortDefinition[];
+ onSortAdd?: (sort: Sort) => void | Promise;
+};
+
+export const SortScope = ({
+ children,
+ sortScopeId,
+ availableSorts,
+ onSortAdd,
+}: SortScopeProps) => {
+ return (
+
+
+ {children}
+
+ );
+};
diff --git a/front/src/modules/ui/data/sort/scopes/init-effect/SortScopeInitEffect.tsx b/front/src/modules/ui/data/sort/scopes/init-effect/SortScopeInitEffect.tsx
new file mode 100644
index 000000000..a4a41a390
--- /dev/null
+++ b/front/src/modules/ui/data/sort/scopes/init-effect/SortScopeInitEffect.tsx
@@ -0,0 +1,25 @@
+import { useEffect } from 'react';
+
+import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
+
+import { useSortStates } from '../../hooks/useSortStates';
+
+type SortScopeInitEffectProps = {
+ sortScopeId: string;
+ availableSorts?: SortDefinition[];
+};
+
+export const SortScopeInitEffect = ({
+ sortScopeId,
+ availableSorts,
+}: SortScopeInitEffectProps) => {
+ const { setAvailableSorts } = useSortStates(sortScopeId);
+
+ useEffect(() => {
+ if (availableSorts) {
+ setAvailableSorts(availableSorts);
+ }
+ }, [availableSorts, setAvailableSorts]);
+
+ return <>>;
+};
diff --git a/front/src/modules/ui/data/sort/scopes/scope-internal-context/SortScopeInternalContext.ts b/front/src/modules/ui/data/sort/scopes/scope-internal-context/SortScopeInternalContext.ts
new file mode 100644
index 000000000..d8022b55b
--- /dev/null
+++ b/front/src/modules/ui/data/sort/scopes/scope-internal-context/SortScopeInternalContext.ts
@@ -0,0 +1,13 @@
+import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey';
+import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
+
+import { Sort } from '../../types/Sort';
+import { SortDefinition } from '../../types/SortDefinition';
+
+type SortScopeInternalContextProps = ScopedStateKey & {
+ onSortAdd?: (sort: Sort) => void;
+ availableSorts?: SortDefinition[];
+};
+
+export const SortScopeInternalContext =
+ createScopeInternalContext();
diff --git a/front/src/modules/ui/data/sort/states/availableSortsScopedState.ts b/front/src/modules/ui/data/sort/states/availableSortsScopedState.ts
new file mode 100644
index 000000000..1e8354cdb
--- /dev/null
+++ b/front/src/modules/ui/data/sort/states/availableSortsScopedState.ts
@@ -0,0 +1,8 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+import { SortDefinition } from '../types/SortDefinition';
+
+export const availableSortsScopedState = createScopedState({
+ key: 'availableSortsScopedState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/ui/data/sort/states/isSortSelectedScopedState.ts b/front/src/modules/ui/data/sort/states/isSortSelectedScopedState.ts
new file mode 100644
index 000000000..b377baea8
--- /dev/null
+++ b/front/src/modules/ui/data/sort/states/isSortSelectedScopedState.ts
@@ -0,0 +1,6 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const isSortSelectedScopedState = createScopedState({
+ key: 'isSortSelectedScopedState',
+ defaultValue: false,
+});
diff --git a/front/src/modules/ui/data/view-bar/types/Sort.ts b/front/src/modules/ui/data/sort/types/Sort.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/Sort.ts
rename to front/src/modules/ui/data/sort/types/Sort.ts
diff --git a/front/src/modules/ui/data/view-bar/types/SortDefinition.ts b/front/src/modules/ui/data/sort/types/SortDefinition.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/SortDefinition.ts
rename to front/src/modules/ui/data/sort/types/SortDefinition.ts
diff --git a/front/src/modules/ui/data/view-bar/types/SortDirection.ts b/front/src/modules/ui/data/sort/types/SortDirection.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/SortDirection.ts
rename to front/src/modules/ui/data/sort/types/SortDirection.ts
diff --git a/front/src/modules/ui/data/view-bar/types/interface.ts b/front/src/modules/ui/data/sort/types/interface.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/interface.ts
rename to front/src/modules/ui/data/sort/types/interface.ts
diff --git a/front/src/modules/ui/data/view-bar/utils/helpers.ts b/front/src/modules/ui/data/sort/utils/helpers.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/utils/helpers.ts
rename to front/src/modules/ui/data/sort/utils/helpers.ts
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownDateSearchInput.tsx b/front/src/modules/ui/data/view-bar/components/FilterDropdownDateSearchInput.tsx
deleted file mode 100644
index 0541e0223..000000000
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownDateSearchInput.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { useUpsertFilter } from '@/ui/data/view-bar/hooks/useUpsertFilter';
-import { filterDefinitionUsedInDropdownScopedState } from '@/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState';
-import { selectedOperandInDropdownScopedState } from '@/ui/data/view-bar/states/selectedOperandInDropdownScopedState';
-import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { isFilterDropdownUnfoldedScopedState } from '../states/isFilterDropdownUnfoldedScopedState';
-
-export const FilterDropdownDateSearchInput = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [selectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setIsFilterDropdownUnfolded] = useRecoilScopedState(
- isFilterDropdownUnfoldedScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const upsertFilter = useUpsertFilter();
-
- const handleChange = (date: Date) => {
- if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return;
-
- upsertFilter({
- key: filterDefinitionUsedInDropdown.key,
- type: filterDefinitionUsedInDropdown.type,
- value: date.toISOString(),
- operand: selectedOperandInDropdown,
- displayValue: date.toLocaleDateString(),
- });
-
- setIsFilterDropdownUnfolded(false);
- };
-
- return (
-
- );
-};
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchInput.tsx b/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchInput.tsx
deleted file mode 100644
index d6b118b38..000000000
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySearchInput.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import { ChangeEvent } from 'react';
-
-import { filterDefinitionUsedInDropdownScopedState } from '@/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState';
-import { filterDropdownSearchInputScopedState } from '@/ui/data/view-bar/states/filterDropdownSearchInputScopedState';
-import { selectedOperandInDropdownScopedState } from '@/ui/data/view-bar/states/selectedOperandInDropdownScopedState';
-import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-
-import { useViewBarContext } from '../hooks/useViewBarContext';
-
-export const FilterDropdownEntitySearchInput = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [selectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [filterDropdownSearchInput, setFilterDropdownSearchInput] =
- useRecoilScopedState(
- filterDropdownSearchInputScopedState,
- ViewBarRecoilScopeContext,
- );
-
- return (
- filterDefinitionUsedInDropdown &&
- selectedOperandInDropdown && (
- ) => {
- setFilterDropdownSearchInput(event.target.value);
- }}
- />
- )
- );
-};
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySelect.tsx b/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySelect.tsx
deleted file mode 100644
index 4e5384dd1..000000000
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownEntitySelect.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
-import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-
-export const FilterDropdownEntitySelect = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- if (filterDefinitionUsedInDropdown?.type !== 'entity') {
- return null;
- }
-
- return (
- <>
-
-
- {filterDefinitionUsedInDropdown.entitySelectComponent}
-
- >
- );
-};
diff --git a/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandButton.tsx b/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandButton.tsx
deleted file mode 100644
index 33eb3fd77..000000000
--- a/front/src/modules/ui/data/view-bar/components/FilterDropdownOperandButton.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { IconChevronDown } from '@/ui/display/icon';
-import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState';
-import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
-import { getOperandLabel } from '../utils/getOperandLabel';
-
-export const FilterDropdownOperandButton = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [selectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [
- isFilterDropdownOperandSelectUnfolded,
- setIsFilterDropdownOperandSelectUnfolded,
- ] = useRecoilScopedState(
- isFilterDropdownOperandSelectUnfoldedScopedState,
- ViewBarRecoilScopeContext,
- );
-
- if (isFilterDropdownOperandSelectUnfolded) {
- return null;
- }
-
- return (
- setIsFilterDropdownOperandSelectUnfolded(true)}
- >
- {getOperandLabel(selectedOperandInDropdown)}
-
- );
-};
diff --git a/front/src/modules/ui/data/view-bar/components/MultipleFiltersButton.tsx b/front/src/modules/ui/data/view-bar/components/MultipleFiltersButton.tsx
deleted file mode 100644
index ad5cce81c..000000000
--- a/front/src/modules/ui/data/view-bar/components/MultipleFiltersButton.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
-import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-
-import { FilterDropdownId } from '../constants/FilterDropdownId';
-import { useViewBarContext } from '../hooks/useViewBarContext';
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-import { filterDropdownSearchInputScopedState } from '../states/filterDropdownSearchInputScopedState';
-import { isFilterDropdownOperandSelectUnfoldedScopedState } from '../states/isFilterDropdownOperandSelectUnfoldedScopedState';
-import { selectedOperandInDropdownScopedState } from '../states/selectedOperandInDropdownScopedState';
-
-export const MultipleFiltersButton = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const { isDropdownOpen, toggleDropdown } = useDropdown({
- dropdownScopeId: FilterDropdownId,
- });
-
- const [, setIsFilterDropdownOperandSelectUnfolded] = useRecoilScopedState(
- isFilterDropdownOperandSelectUnfoldedScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setFilterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setFilterDropdownSearchInput] = useRecoilScopedState(
- filterDropdownSearchInputScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [, setSelectedOperandInDropdown] = useRecoilScopedState(
- selectedOperandInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const resetState = () => {
- setIsFilterDropdownOperandSelectUnfolded(false);
- setFilterDefinitionUsedInDropdown(null);
- setSelectedOperandInDropdown(null);
- setFilterDropdownSearchInput('');
- };
-
- const handleClick = () => {
- toggleDropdown();
- resetState();
- };
-
- return (
-
- Filter
-
- );
-};
diff --git a/front/src/modules/ui/data/view-bar/components/UpdateViewButtonGroup.tsx b/front/src/modules/ui/data/view-bar/components/UpdateViewButtonGroup.tsx
deleted file mode 100644
index 443602cb9..000000000
--- a/front/src/modules/ui/data/view-bar/components/UpdateViewButtonGroup.tsx
+++ /dev/null
@@ -1,138 +0,0 @@
-import { useCallback, useContext, useState } from 'react';
-import styled from '@emotion/styled';
-import { useRecoilValue, useSetRecoilState } from 'recoil';
-import { Key } from 'ts-key-enum';
-
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState';
-import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState';
-import { canPersistFiltersScopedFamilySelector } from '@/ui/data/view-bar/states/selectors/canPersistFiltersScopedFamilySelector';
-import { canPersistSortsScopedFamilySelector } from '@/ui/data/view-bar/states/selectors/canPersistSortsScopedFamilySelector';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
-import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
-import { IconChevronDown, IconPlus } from '@/ui/display/icon';
-import { Button } from '@/ui/input/button/components/Button';
-import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup';
-import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
-import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
-import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
-
-import { ViewBarContext } from '../contexts/ViewBarContext';
-
-const StyledContainer = styled.div`
- display: inline-flex;
- margin-right: ${({ theme }) => theme.spacing(2)};
- position: relative;
-`;
-export type UpdateViewButtonGroupProps = {
- hotkeyScope: string;
- onViewEditModeChange?: () => void;
-};
-
-export const UpdateViewButtonGroup = ({
- hotkeyScope,
- onViewEditModeChange,
-}: UpdateViewButtonGroupProps) => {
- const [isDropdownOpen, setIsDropdownOpen] = useState(false);
-
- const {
- canPersistViewFields,
- onCurrentViewSubmit,
- ViewBarRecoilScopeContext,
- } = useContext(ViewBarContext);
-
- const recoilScopeId = useRecoilScopeId(ViewBarRecoilScopeContext);
-
- const currentViewId = useRecoilScopedValue(
- currentViewIdScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const filters = useRecoilScopedValue(
- filtersScopedState,
- ViewBarRecoilScopeContext,
- );
- const setSavedFilters = useSetRecoilState(
- savedFiltersFamilyState(currentViewId),
- );
- const canPersistFilters = useRecoilValue(
- canPersistFiltersScopedFamilySelector({
- recoilScopeId,
- viewId: currentViewId,
- }),
- );
-
- const sorts = useRecoilScopedValue(
- sortsScopedState,
- ViewBarRecoilScopeContext,
- );
- const setSavedSorts = useSetRecoilState(savedSortsFamilyState(currentViewId));
- const canPersistSorts = useRecoilValue(
- canPersistSortsScopedFamilySelector({
- recoilScopeId,
- viewId: currentViewId,
- }),
- );
-
- const setViewEditMode = useSetRecoilState(viewEditModeState);
-
- const canPersistView =
- currentViewId &&
- (canPersistViewFields || canPersistFilters || canPersistSorts);
-
- const handleArrowDownButtonClick = useCallback(() => {
- setIsDropdownOpen((previousIsOpen) => !previousIsOpen);
- }, []);
-
- const handleCreateViewButtonClick = useCallback(() => {
- setViewEditMode({ mode: 'create', viewId: undefined });
- onViewEditModeChange?.();
- setIsDropdownOpen(false);
- }, [setViewEditMode, onViewEditModeChange]);
-
- const handleDropdownClose = useCallback(() => {
- setIsDropdownOpen(false);
- }, []);
-
- const handleViewSubmit = async () => {
- if (canPersistFilters) setSavedFilters(filters);
- if (canPersistSorts) setSavedSorts(sorts);
-
- await onCurrentViewSubmit?.();
- };
-
- useScopedHotkeys(
- [Key.Enter, Key.Escape],
- handleDropdownClose,
- hotkeyScope,
- [],
- );
-
- if (!canPersistView) return null;
-
- return (
-
-
-
-
-
-
- {isDropdownOpen && (
-
-
-
- )}
-
- );
-};
diff --git a/front/src/modules/ui/data/view-bar/components/ViewBar.tsx b/front/src/modules/ui/data/view-bar/components/ViewBar.tsx
deleted file mode 100644
index 12ad5f3fc..000000000
--- a/front/src/modules/ui/data/view-bar/components/ViewBar.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { ReactNode } from 'react';
-
-import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
-import { TopBar } from '@/ui/layout/top-bar/TopBar';
-
-import { FiltersHotkeyScope } from '../types/FiltersHotkeyScope';
-import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
-
-import { FilterDropdownButton } from './FilterDropdownButton';
-import { SortDropdownButton } from './SortDropdownButton';
-import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
-import { ViewBarDetails } from './ViewBarDetails';
-import { ViewsDropdownButton } from './ViewsDropdownButton';
-
-export type ViewBarProps = {
- className?: string;
- optionsDropdownButton: ReactNode;
- optionsDropdownScopeId: string;
-};
-
-export const ViewBar = ({
- className,
- optionsDropdownButton,
- optionsDropdownScopeId,
-}: ViewBarProps) => {
- const { openDropdown: openOptionsDropdownButton } = useDropdown({
- dropdownScopeId: optionsDropdownScopeId,
- });
-
- return (
-
- }
- displayBottomBorder={false}
- rightComponent={
- <>
-
-
- {optionsDropdownButton}
- >
- }
- bottomComponent={
-
- }
- />
- }
- />
- );
-};
diff --git a/front/src/modules/ui/data/view-bar/contexts/ViewBarContext.ts b/front/src/modules/ui/data/view-bar/contexts/ViewBarContext.ts
deleted file mode 100644
index 4a5407fc1..000000000
--- a/front/src/modules/ui/data/view-bar/contexts/ViewBarContext.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { createContext } from 'react';
-
-import { RecoilScopeContext } from '@/types/RecoilScopeContext';
-
-import { View } from '../types/View';
-
-export const ViewBarContext = createContext<{
- canPersistViewFields?: boolean;
- defaultViewName?: string;
- onCurrentViewSubmit?: () => void | Promise;
- onViewBarReset?: () => void;
- onViewCreate?: (view: View) => void | Promise;
- onViewEdit?: (view: View) => void | Promise;
- onViewRemove?: (viewId: string) => void | Promise;
- onViewSelect?: (viewId: string) => void | Promise;
- onImport?: () => void | Promise;
- ViewBarRecoilScopeContext: RecoilScopeContext;
-}>({
- ViewBarRecoilScopeContext: createContext(null),
-});
diff --git a/front/src/modules/ui/data/view-bar/hooks/useFilterCurrentlyEdited.ts b/front/src/modules/ui/data/view-bar/hooks/useFilterCurrentlyEdited.ts
deleted file mode 100644
index e38426918..000000000
--- a/front/src/modules/ui/data/view-bar/hooks/useFilterCurrentlyEdited.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { useMemo } from 'react';
-
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-
-import { filterDefinitionUsedInDropdownScopedState } from '../states/filterDefinitionUsedInDropdownScopedState';
-import { filtersScopedState } from '../states/filtersScopedState';
-
-import { useViewBarContext } from './useViewBarContext';
-
-export const useFilterCurrentlyEdited = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [filters] = useRecoilScopedState(
- filtersScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const [filterDefinitionUsedInDropdown] = useRecoilScopedState(
- filterDefinitionUsedInDropdownScopedState,
- ViewBarRecoilScopeContext,
- );
-
- return useMemo(() => {
- return filters.find(
- (filter) => filter.key === filterDefinitionUsedInDropdown?.key,
- );
- }, [filterDefinitionUsedInDropdown, filters]);
-};
diff --git a/front/src/modules/ui/data/view-bar/hooks/useRemoveFilter.ts b/front/src/modules/ui/data/view-bar/hooks/useRemoveFilter.ts
deleted file mode 100644
index e9962e9d9..000000000
--- a/front/src/modules/ui/data/view-bar/hooks/useRemoveFilter.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { useContext } from 'react';
-
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-
-import { ViewBarContext } from '../contexts/ViewBarContext';
-import { filtersScopedState } from '../states/filtersScopedState';
-
-export const useRemoveFilter = () => {
- const { ViewBarRecoilScopeContext } = useContext(ViewBarContext);
-
- const [, setFilters] = useRecoilScopedState(
- filtersScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const removeFilter = (filterKey: string) => {
- setFilters((filters) => {
- return filters.filter((filter) => {
- return filter.key !== filterKey;
- });
- });
- };
-
- return removeFilter;
-};
diff --git a/front/src/modules/ui/data/view-bar/hooks/useRemoveView.ts b/front/src/modules/ui/data/view-bar/hooks/useRemoveView.ts
deleted file mode 100644
index 4c558b61b..000000000
--- a/front/src/modules/ui/data/view-bar/hooks/useRemoveView.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { useContext } from 'react';
-import { useRecoilCallback } from 'recoil';
-
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
-
-import { ViewBarContext } from '../contexts/ViewBarContext';
-import { currentViewIdScopedState } from '../states/currentViewIdScopedState';
-import { viewsScopedState } from '../states/viewsScopedState';
-
-export const useRemoveView = () => {
- const { onViewRemove, ViewBarRecoilScopeContext } =
- useContext(ViewBarContext);
-
- const recoilScopeId = useRecoilScopeId(ViewBarRecoilScopeContext);
-
- const removeView = useRecoilCallback(
- ({ set, snapshot }) =>
- async (viewId: string) => {
- const currentViewId = await snapshot.getPromise(
- currentViewIdScopedState(recoilScopeId),
- );
-
- if (currentViewId === viewId)
- set(currentViewIdScopedState(recoilScopeId), undefined);
-
- set(viewsScopedState(recoilScopeId), (previousViews) =>
- previousViews.filter((view) => view.id !== viewId),
- );
- await onViewRemove?.(viewId);
- },
- [onViewRemove, recoilScopeId],
- );
-
- return { removeView };
-};
diff --git a/front/src/modules/ui/data/view-bar/hooks/useUpsertView.ts b/front/src/modules/ui/data/view-bar/hooks/useUpsertView.ts
deleted file mode 100644
index 5fe2e6040..000000000
--- a/front/src/modules/ui/data/view-bar/hooks/useUpsertView.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import { useContext } from 'react';
-import { useRecoilCallback, useRecoilValue, useResetRecoilState } from 'recoil';
-import { v4 } from 'uuid';
-
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
-
-import { ViewBarContext } from '../contexts/ViewBarContext';
-import { currentViewIdScopedState } from '../states/currentViewIdScopedState';
-import { filtersScopedState } from '../states/filtersScopedState';
-import { savedFiltersFamilyState } from '../states/savedFiltersFamilyState';
-import { savedSortsFamilyState } from '../states/savedSortsFamilyState';
-import { currentViewScopedSelector } from '../states/selectors/currentViewScopedSelector';
-import { viewsByIdScopedSelector } from '../states/selectors/viewsByIdScopedSelector';
-import { sortsScopedState } from '../states/sortsScopedState';
-import { viewEditModeState } from '../states/viewEditModeState';
-import { viewsScopedState } from '../states/viewsScopedState';
-
-export const useUpsertView = () => {
- const { onViewCreate, onViewEdit, ViewBarRecoilScopeContext } =
- useContext(ViewBarContext);
- const recoilScopeId = useRecoilScopeId(ViewBarRecoilScopeContext);
-
- const filters = useRecoilScopedValue(
- filtersScopedState,
- ViewBarRecoilScopeContext,
- );
- const sorts = useRecoilScopedValue(
- sortsScopedState,
- ViewBarRecoilScopeContext,
- );
- const viewEditMode = useRecoilValue(viewEditModeState);
- const resetViewEditMode = useResetRecoilState(viewEditModeState);
-
- const upsertView = useRecoilCallback(
- ({ set, snapshot }) =>
- async (name?: string) => {
- if (!viewEditMode.mode || !name) {
- resetViewEditMode();
- return;
- }
-
- if (viewEditMode.mode === 'create') {
- const createdView = { id: v4(), name };
-
- set(savedFiltersFamilyState(createdView.id), filters);
- set(savedSortsFamilyState(createdView.id), sorts);
-
- set(viewsScopedState(recoilScopeId), (previousViews) => [
- ...previousViews,
- createdView,
- ]);
-
- await onViewCreate?.(createdView);
-
- resetViewEditMode();
-
- set(currentViewIdScopedState(recoilScopeId), createdView.id);
-
- return createdView;
- }
-
- const viewsById = await snapshot.getPromise(
- viewsByIdScopedSelector(recoilScopeId),
- );
- const currentView = await snapshot.getPromise(
- currentViewScopedSelector(recoilScopeId),
- );
-
- const viewToEdit = viewEditMode.viewId
- ? viewsById[viewEditMode.viewId]
- : currentView;
-
- if (!viewToEdit) {
- resetViewEditMode();
- return;
- }
-
- const editedView = {
- ...viewToEdit,
- name,
- };
-
- set(viewsScopedState(recoilScopeId), (previousViews) =>
- previousViews.map((previousView) =>
- previousView.id === editedView.id ? editedView : previousView,
- ),
- );
-
- await onViewEdit?.(editedView);
-
- resetViewEditMode();
-
- return editedView;
- },
- [
- filters,
- onViewCreate,
- onViewEdit,
- recoilScopeId,
- resetViewEditMode,
- sorts,
- viewEditMode.mode,
- viewEditMode.viewId,
- ],
- );
-
- return { upsertView };
-};
diff --git a/front/src/modules/ui/data/view-bar/hooks/useViewBarContext.ts b/front/src/modules/ui/data/view-bar/hooks/useViewBarContext.ts
deleted file mode 100644
index 78ef85aff..000000000
--- a/front/src/modules/ui/data/view-bar/hooks/useViewBarContext.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { useContext } from 'react';
-
-import { ViewBarContext } from '../contexts/ViewBarContext';
-
-export const useViewBarContext = () => {
- return useContext(ViewBarContext);
-};
diff --git a/front/src/modules/ui/data/view-bar/states/availableFiltersScopedState.ts b/front/src/modules/ui/data/view-bar/states/availableFiltersScopedState.ts
deleted file mode 100644
index 76e23e5b3..000000000
--- a/front/src/modules/ui/data/view-bar/states/availableFiltersScopedState.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { FilterDefinition } from '../types/FilterDefinition';
-
-export const availableFiltersScopedState = atomFamily<
- FilterDefinition[],
- string
->({
- key: 'availableFiltersScopedState',
- default: [],
-});
diff --git a/front/src/modules/ui/data/view-bar/states/availableSortsScopedState.ts b/front/src/modules/ui/data/view-bar/states/availableSortsScopedState.ts
deleted file mode 100644
index 5e89ef372..000000000
--- a/front/src/modules/ui/data/view-bar/states/availableSortsScopedState.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { SortDefinition } from '../types/SortDefinition';
-
-export const availableSortsScopedState = atomFamily({
- key: 'availableSortsScopedState',
- default: [],
-});
diff --git a/front/src/modules/ui/data/view-bar/states/currentViewIdScopedState.ts b/front/src/modules/ui/data/view-bar/states/currentViewIdScopedState.ts
deleted file mode 100644
index 1848522c2..000000000
--- a/front/src/modules/ui/data/view-bar/states/currentViewIdScopedState.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { atomFamily } from 'recoil';
-
-export const currentViewIdScopedState = atomFamily({
- key: 'currentViewIdScopedState',
- default: undefined,
-});
diff --git a/front/src/modules/ui/data/view-bar/states/entityCountInCurrentViewState.ts b/front/src/modules/ui/data/view-bar/states/entityCountInCurrentViewState.ts
deleted file mode 100644
index ea87f9267..000000000
--- a/front/src/modules/ui/data/view-bar/states/entityCountInCurrentViewState.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { atom } from 'recoil';
-
-export const entityCountInCurrentViewState = atom({
- key: 'entityCountInCurrentViewState',
- default: 0,
-});
diff --git a/front/src/modules/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState.ts b/front/src/modules/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState.ts
deleted file mode 100644
index 3b172a8c8..000000000
--- a/front/src/modules/ui/data/view-bar/states/filterDefinitionUsedInDropdownScopedState.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { FilterDefinition } from '../types/FilterDefinition';
-
-export const filterDefinitionUsedInDropdownScopedState = atomFamily<
- FilterDefinition | null,
- string
->({
- key: 'filterDefinitionUsedInDropdownScopedState',
- default: null,
-});
diff --git a/front/src/modules/ui/data/view-bar/states/filterDropdownSearchInputScopedState.ts b/front/src/modules/ui/data/view-bar/states/filterDropdownSearchInputScopedState.ts
deleted file mode 100644
index 396f2f980..000000000
--- a/front/src/modules/ui/data/view-bar/states/filterDropdownSearchInputScopedState.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { atomFamily } from 'recoil';
-
-export const filterDropdownSearchInputScopedState = atomFamily({
- key: 'filterDropdownSearchInputScopedState',
- default: '',
-});
diff --git a/front/src/modules/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState.ts b/front/src/modules/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState.ts
deleted file mode 100644
index 0ebc0cc19..000000000
--- a/front/src/modules/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { atomFamily } from 'recoil';
-
-export const filterDropdownSelectedEntityIdScopedState = atomFamily<
- string | null,
- string
->({
- key: 'filterDropdownSelectedEntityIdScopedState',
- default: null,
-});
diff --git a/front/src/modules/ui/data/view-bar/states/filtersScopedState.ts b/front/src/modules/ui/data/view-bar/states/filtersScopedState.ts
deleted file mode 100644
index ddc5f8200..000000000
--- a/front/src/modules/ui/data/view-bar/states/filtersScopedState.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { Filter } from '../types/Filter';
-
-export const filtersScopedState = atomFamily({
- key: 'filtersScopedState',
- default: [],
-});
diff --git a/front/src/modules/ui/data/view-bar/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts b/front/src/modules/ui/data/view-bar/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts
deleted file mode 100644
index 49370d862..000000000
--- a/front/src/modules/ui/data/view-bar/states/isFilterDropdownOperandSelectUnfoldedScopedState.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { atomFamily } from 'recoil';
-
-export const isFilterDropdownOperandSelectUnfoldedScopedState = atomFamily<
- boolean,
- string
->({
- key: 'isFilterDropdownOperandSelectUnfoldedScopedState',
- default: false,
-});
diff --git a/front/src/modules/ui/data/view-bar/states/isFilterDropdownUnfoldedScopedState.ts b/front/src/modules/ui/data/view-bar/states/isFilterDropdownUnfoldedScopedState.ts
deleted file mode 100644
index 477cad02e..000000000
--- a/front/src/modules/ui/data/view-bar/states/isFilterDropdownUnfoldedScopedState.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { atomFamily } from 'recoil';
-
-export const isFilterDropdownUnfoldedScopedState = atomFamily({
- key: 'isFilterDropdownUnfoldedScopedState',
- default: false,
-});
diff --git a/front/src/modules/ui/data/view-bar/states/isViewBarExpandedScopedState.ts b/front/src/modules/ui/data/view-bar/states/isViewBarExpandedScopedState.ts
deleted file mode 100644
index f91684064..000000000
--- a/front/src/modules/ui/data/view-bar/states/isViewBarExpandedScopedState.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { atomFamily } from 'recoil';
-
-export const isViewBarExpandedScopedState = atomFamily({
- key: 'isViewBarExpandedScopedState',
- default: true,
-});
diff --git a/front/src/modules/ui/data/view-bar/states/savedFiltersFamilyState.ts b/front/src/modules/ui/data/view-bar/states/savedFiltersFamilyState.ts
deleted file mode 100644
index b750e7a68..000000000
--- a/front/src/modules/ui/data/view-bar/states/savedFiltersFamilyState.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { Filter } from '../types/Filter';
-
-export const savedFiltersFamilyState = atomFamily(
- {
- key: 'savedFiltersFamilyState',
- default: [],
- },
-);
diff --git a/front/src/modules/ui/data/view-bar/states/savedSortsFamilyState.ts b/front/src/modules/ui/data/view-bar/states/savedSortsFamilyState.ts
deleted file mode 100644
index 758efc76e..000000000
--- a/front/src/modules/ui/data/view-bar/states/savedSortsFamilyState.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { Sort } from '../types/Sort';
-
-export const savedSortsFamilyState = atomFamily({
- key: 'savedSortsFamilyState',
- default: [],
-});
diff --git a/front/src/modules/ui/data/view-bar/states/selectedOperandInDropdownScopedState.ts b/front/src/modules/ui/data/view-bar/states/selectedOperandInDropdownScopedState.ts
deleted file mode 100644
index 5485d8063..000000000
--- a/front/src/modules/ui/data/view-bar/states/selectedOperandInDropdownScopedState.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { ViewFilterOperand } from '~/generated/graphql';
-
-export const selectedOperandInDropdownScopedState = atomFamily<
- ViewFilterOperand | null,
- string
->({
- key: 'selectedOperandInDropdownScopedState',
- default: null,
-});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/canPersistFiltersScopedFamilySelector.ts b/front/src/modules/ui/data/view-bar/states/selectors/canPersistFiltersScopedFamilySelector.ts
deleted file mode 100644
index 9bba37e10..000000000
--- a/front/src/modules/ui/data/view-bar/states/selectors/canPersistFiltersScopedFamilySelector.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { selectorFamily } from 'recoil';
-
-import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
-
-import { filtersScopedState } from '../filtersScopedState';
-import { savedFiltersFamilyState } from '../savedFiltersFamilyState';
-
-export const canPersistFiltersScopedFamilySelector = selectorFamily({
- key: 'canPersistFiltersScopedFamilySelector',
- get:
- ({
- recoilScopeId,
- viewId,
- }: {
- recoilScopeId: string;
- viewId: string | undefined;
- }) =>
- ({ get }) =>
- !isDeeplyEqual(
- get(savedFiltersFamilyState(viewId)),
- get(filtersScopedState(recoilScopeId)),
- ),
-});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/canPersistSortsScopedFamilySelector.ts b/front/src/modules/ui/data/view-bar/states/selectors/canPersistSortsScopedFamilySelector.ts
deleted file mode 100644
index 5a5673915..000000000
--- a/front/src/modules/ui/data/view-bar/states/selectors/canPersistSortsScopedFamilySelector.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { selectorFamily } from 'recoil';
-
-import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
-
-import { savedSortsFamilyState } from '../savedSortsFamilyState';
-import { sortsScopedState } from '../sortsScopedState';
-
-export const canPersistSortsScopedFamilySelector = selectorFamily({
- key: 'canPersistSortsScopedFamilySelector',
- get:
- ({
- recoilScopeId,
- viewId,
- }: {
- recoilScopeId: string;
- viewId: string | undefined;
- }) =>
- ({ get }) =>
- !isDeeplyEqual(
- get(savedSortsFamilyState(viewId)),
- get(sortsScopedState(recoilScopeId)),
- ),
-});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/savedFiltersByKeyFamilySelector.ts b/front/src/modules/ui/data/view-bar/states/selectors/savedFiltersByKeyFamilySelector.ts
deleted file mode 100644
index 2bb62edb2..000000000
--- a/front/src/modules/ui/data/view-bar/states/selectors/savedFiltersByKeyFamilySelector.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { selectorFamily } from 'recoil';
-
-import { Filter } from '../../types/Filter';
-import { savedFiltersFamilyState } from '../savedFiltersFamilyState';
-
-export const savedFiltersByKeyFamilySelector = selectorFamily({
- key: 'savedFiltersByKeyFamilySelector',
- get:
- (viewId: string | undefined) =>
- ({ get }) =>
- get(savedFiltersFamilyState(viewId)).reduce>(
- (result, filter) => ({ ...result, [filter.key]: filter }),
- {},
- ),
-});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/savedFiltersFamilySelector.ts b/front/src/modules/ui/data/view-bar/states/selectors/savedFiltersFamilySelector.ts
deleted file mode 100644
index af08a245c..000000000
--- a/front/src/modules/ui/data/view-bar/states/selectors/savedFiltersFamilySelector.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { selectorFamily } from 'recoil';
-
-import { savedFiltersFamilyState } from '../savedFiltersFamilyState';
-
-export const savedFiltersFamilySelector = selectorFamily({
- key: 'savedFiltersFamilySelector',
- get:
- (viewId: string | undefined) =>
- ({ get }) =>
- get(savedFiltersFamilyState(viewId)),
-});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/savedSortsByKeyFamilySelector.ts b/front/src/modules/ui/data/view-bar/states/selectors/savedSortsByKeyFamilySelector.ts
deleted file mode 100644
index 0475870a4..000000000
--- a/front/src/modules/ui/data/view-bar/states/selectors/savedSortsByKeyFamilySelector.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { selectorFamily } from 'recoil';
-
-import { Sort } from '../../types/Sort';
-import { savedSortsFamilyState } from '../savedSortsFamilyState';
-
-export const savedSortsByKeyFamilySelector = selectorFamily({
- key: 'savedSortsByKeyFamilySelector',
- get:
- (viewId: string | undefined) =>
- ({ get }) =>
- get(savedSortsFamilyState(viewId)).reduce>(
- (result, sort) => ({ ...result, [sort.key]: sort }),
- {},
- ),
-});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/savedSortsFamilySelector.ts b/front/src/modules/ui/data/view-bar/states/selectors/savedSortsFamilySelector.ts
deleted file mode 100644
index a84b890b3..000000000
--- a/front/src/modules/ui/data/view-bar/states/selectors/savedSortsFamilySelector.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { selectorFamily } from 'recoil';
-
-import { savedSortsFamilyState } from '../savedSortsFamilyState';
-
-export const savedSortsFamilySelector = selectorFamily({
- key: 'savedSortsFamilySelector',
- get:
- (viewId: string | undefined) =>
- ({ get }) =>
- get(savedSortsFamilyState(viewId)),
-});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/sortsOrderByScopedSelector.ts b/front/src/modules/ui/data/view-bar/states/selectors/sortsOrderByScopedSelector.ts
deleted file mode 100644
index a2d31fd09..000000000
--- a/front/src/modules/ui/data/view-bar/states/selectors/sortsOrderByScopedSelector.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { selectorFamily } from 'recoil';
-
-import { SortOrder } from '~/generated/graphql';
-
-import { reduceSortsToOrderBy } from '../../utils/helpers';
-import { sortsScopedState } from '../sortsScopedState';
-
-export const sortsOrderByScopedSelector = selectorFamily({
- key: 'sortsOrderByScopedSelector',
- get:
- (scopeId: string) =>
- ({ get }) => {
- const orderBy = reduceSortsToOrderBy(get(sortsScopedState(scopeId)));
- return orderBy.length ? orderBy : [{ createdAt: SortOrder.Desc }];
- },
-});
diff --git a/front/src/modules/ui/data/view-bar/states/sortsScopedState.ts b/front/src/modules/ui/data/view-bar/states/sortsScopedState.ts
deleted file mode 100644
index 4771f6ffc..000000000
--- a/front/src/modules/ui/data/view-bar/states/sortsScopedState.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { Sort } from '../types/Sort';
-
-export const sortsScopedState = atomFamily({
- key: 'sortsScopedState',
- default: [],
-});
diff --git a/front/src/modules/ui/data/view-bar/states/viewEditModeState.ts b/front/src/modules/ui/data/view-bar/states/viewEditModeState.ts
deleted file mode 100644
index 4579a8f36..000000000
--- a/front/src/modules/ui/data/view-bar/states/viewEditModeState.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { atom } from 'recoil';
-
-export const viewEditModeState = atom<{
- mode: 'create' | 'edit';
- viewId: string | undefined;
-}>({
- key: 'viewEditModeState',
- default: { mode: 'edit', viewId: undefined },
-});
diff --git a/front/src/modules/ui/data/view-bar/states/viewsScopedState.ts b/front/src/modules/ui/data/view-bar/states/viewsScopedState.ts
deleted file mode 100644
index c9906ebfd..000000000
--- a/front/src/modules/ui/data/view-bar/states/viewsScopedState.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { atomFamily } from 'recoil';
-
-import { View } from '../types/View';
-
-export const viewsScopedState = atomFamily({
- key: 'viewsScopedState',
- default: [],
-});
diff --git a/front/src/modules/ui/layout/board/components/BoardHeader.tsx b/front/src/modules/ui/layout/board/components/BoardHeader.tsx
deleted file mode 100644
index cd7d22f60..000000000
--- a/front/src/modules/ui/layout/board/components/BoardHeader.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import { useContext } from 'react';
-import { useSearchParams } from 'react-router-dom';
-import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
-
-import { BoardContext } from '@/companies/states/contexts/BoardContext';
-import { ViewBar } from '@/ui/data/view-bar/components/ViewBar';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
-
-import { boardCardFieldsScopedState } from '../states/boardCardFieldsScopedState';
-import { boardColumnsState } from '../states/boardColumnsState';
-import { savedBoardCardFieldsFamilyState } from '../states/savedBoardCardFieldsFamilyState';
-import { savedBoardColumnsState } from '../states/savedBoardColumnsState';
-import { canPersistBoardCardFieldsScopedFamilySelector } from '../states/selectors/canPersistBoardCardFieldsScopedFamilySelector';
-import { canPersistBoardColumnsSelector } from '../states/selectors/canPersistBoardColumnsSelector';
-import { BoardColumnDefinition } from '../types/BoardColumnDefinition';
-import { BoardOptionsHotkeyScope } from '../types/BoardOptionsHotkeyScope';
-import { BoardScopeIds } from '../types/enums/BoardScopeIds';
-
-import { BoardOptionsDropdown } from './BoardOptionsDropdown';
-
-export type BoardHeaderProps = {
- className?: string;
- onStageAdd?: (boardColumn: BoardColumnDefinition) => void;
-};
-
-export const BoardHeader = ({ className, onStageAdd }: BoardHeaderProps) => {
- const { onCurrentViewSubmit, ...viewBarContextProps } =
- useContext(ViewBarContext);
-
- const BoardRecoilScopeContext =
- useContext(BoardContext).BoardRecoilScopeContext;
-
- const ViewBarRecoilScopeContext =
- useContext(ViewBarContext).ViewBarRecoilScopeContext;
-
- const boardRecoilScopeId = useRecoilScopeId(BoardRecoilScopeContext);
-
- const currentViewId = useRecoilScopedValue(
- currentViewIdScopedState,
- ViewBarRecoilScopeContext,
- );
- const canPersistBoardCardFields = useRecoilValue(
- canPersistBoardCardFieldsScopedFamilySelector({
- recoilScopeId: boardRecoilScopeId,
- viewId: currentViewId,
- }),
- );
- const canPersistBoardColumns = useRecoilValue(canPersistBoardColumnsSelector);
-
- const [boardCardFields, setBoardCardFields] = useRecoilScopedState(
- boardCardFieldsScopedState,
- BoardRecoilScopeContext,
- );
- const [savedBoardCardFields, setSavedBoardCardFields] = useRecoilState(
- savedBoardCardFieldsFamilyState(currentViewId),
- );
-
- const [_, setSearchParams] = useSearchParams();
- const [boardColumns, setBoardColumns] = useRecoilState(boardColumnsState);
- const [, setSavedBoardColumns] = useRecoilState(savedBoardColumnsState);
-
- const savedBoardColumns = useRecoilValue(savedBoardColumnsState);
-
- const handleViewBarReset = () => {
- setBoardCardFields(savedBoardCardFields);
- setBoardColumns(savedBoardColumns);
- };
-
- const handleViewSelect = useRecoilCallback(
- ({ set, snapshot }) =>
- async (viewId: string) => {
- const savedBoardCardFields = await snapshot.getPromise(
- savedBoardCardFieldsFamilyState(viewId),
- );
- set(
- boardCardFieldsScopedState(boardRecoilScopeId),
- savedBoardCardFields,
- );
- setSearchParams({ view: viewId });
- },
- [boardRecoilScopeId, setSearchParams],
- );
-
- const handleCurrentViewSubmit = async () => {
- if (canPersistBoardCardFields) {
- setSavedBoardCardFields(boardCardFields);
- }
- if (canPersistBoardColumns) {
- setSavedBoardColumns(boardColumns);
- }
-
- await onCurrentViewSubmit?.();
- };
-
- const canPersistView = canPersistBoardCardFields || canPersistBoardColumns;
-
- return (
-
-
- }
- optionsDropdownScopeId={BoardScopeIds.OptionsDropdown}
- />
-
- );
-};
diff --git a/front/src/modules/ui/layout/board/components/BoardOptionsDropdown.tsx b/front/src/modules/ui/layout/board/components/BoardOptionsDropdown.tsx
index e1aa2dc91..3054d96d4 100644
--- a/front/src/modules/ui/layout/board/components/BoardOptionsDropdown.tsx
+++ b/front/src/modules/ui/layout/board/components/BoardOptionsDropdown.tsx
@@ -1,6 +1,4 @@
-import { useResetRecoilState } from 'recoil';
-
-import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
+import { useView } from '@/views/hooks/useView';
import { Dropdown } from '../../dropdown/components/Dropdown';
import { DropdownScope } from '../../dropdown/scopes/DropdownScope';
@@ -21,7 +19,7 @@ export const BoardOptionsDropdown = ({
customHotkeyScope,
onStageAdd,
}: BoardOptionsDropdownProps) => {
- const resetViewEditMode = useResetRecoilState(viewEditModeState);
+ const { setViewEditMode } = useView();
return (
@@ -34,7 +32,7 @@ export const BoardOptionsDropdown = ({
/>
}
dropdownHotkeyScope={customHotkeyScope}
- onClickOutside={resetViewEditMode}
+ onClickOutside={() => setViewEditMode('none')}
dropdownMenuWidth={170}
/>
diff --git a/front/src/modules/ui/layout/board/components/BoardOptionsDropdownContent.tsx b/front/src/modules/ui/layout/board/components/BoardOptionsDropdownContent.tsx
index bef92c89b..55b434881 100644
--- a/front/src/modules/ui/layout/board/components/BoardOptionsDropdownContent.tsx
+++ b/front/src/modules/ui/layout/board/components/BoardOptionsDropdownContent.tsx
@@ -1,19 +1,9 @@
import { useContext, useRef, useState } from 'react';
-import {
- useRecoilCallback,
- useRecoilState,
- useRecoilValue,
- useResetRecoilState,
-} from 'recoil';
+import { useRecoilCallback, useRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
import { v4 } from 'uuid';
import { BoardContext } from '@/companies/states/contexts/BoardContext';
-import { ViewFieldsVisibilityDropdownSection } from '@/ui/data/view-bar/components/ViewFieldsVisibilityDropdownSection';
-import { useUpsertView } from '@/ui/data/view-bar/hooks/useUpsertView';
-import { currentViewScopedSelector } from '@/ui/data/view-bar/states/selectors/currentViewScopedSelector';
-import { viewsByIdScopedSelector } from '@/ui/data/view-bar/states/selectors/viewsByIdScopedSelector';
-import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
import {
IconBaselineDensitySmall,
IconChevronLeft,
@@ -35,6 +25,10 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
+import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
+import { useView } from '@/views/hooks/useView';
+import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
+import { viewEditModeScopedState } from '@/views/states/viewEditModeScopedState';
import { useBoardCardFields } from '../hooks/useBoardCardFields';
import { boardCardFieldsScopedState } from '../states/boardCardFieldsScopedState';
@@ -63,6 +57,8 @@ export const BoardOptionsDropdownContent = ({
customHotkeyScope,
onStageAdd,
}: BoardOptionsDropdownContentProps) => {
+ const { setViewEditMode, createView, currentViewId } = useView();
+ const { viewEditMode, currentView } = useViewInternalStates();
const { BoardRecoilScopeContext } = useContext(BoardContext);
const boardRecoilScopeId = useRecoilScopeId(BoardRecoilScopeContext);
@@ -90,17 +86,6 @@ export const BoardOptionsDropdownContent = ({
);
const hasVisibleFields = visibleBoardCardFields.length > 0;
- const viewsById = useRecoilScopedValue(
- viewsByIdScopedSelector,
- BoardRecoilScopeContext, // TODO: replace with ViewBarRecoilScopeContext
- );
- const currentView = useRecoilScopedValue(
- currentViewScopedSelector,
- BoardRecoilScopeContext,
- );
- const viewEditMode = useRecoilValue(viewEditModeState);
- const resetViewEditMode = useResetRecoilState(viewEditModeState);
-
const handleStageSubmit = () => {
if (currentMenu !== 'stage-creation' || !stageInputRef?.current?.value)
return;
@@ -119,23 +104,28 @@ export const BoardOptionsDropdownContent = ({
onStageAdd?.(columnToCreate);
};
- const { upsertView } = useUpsertView();
-
const handleViewNameSubmit = useRecoilCallback(
({ set, snapshot }) =>
async () => {
+ const viewEditMode = snapshot
+ .getLoadable(viewEditModeScopedState({ scopeId: boardRecoilScopeId }))
+ .getValue();
+ if (!viewEditMode) {
+ return;
+ }
+
const boardCardFields = await snapshot.getPromise(
boardCardFieldsScopedState(boardRecoilScopeId),
);
- const isCreateMode = viewEditMode.mode === 'create';
+ const isCreateMode = viewEditMode === 'create';
const name = viewEditInputRef.current?.value;
- const view = await upsertView(name);
- if (view && isCreateMode) {
- set(savedBoardCardFieldsFamilyState(view.id), boardCardFields);
+ if (isCreateMode && name) {
+ await createView(name);
+ set(savedBoardCardFieldsFamilyState(currentViewId), boardCardFields);
}
},
- [boardRecoilScopeId, upsertView, viewEditMode.mode],
+ [boardRecoilScopeId, createView, currentViewId],
);
const resetMenu = () => setCurrentMenu(undefined);
@@ -152,7 +142,7 @@ export const BoardOptionsDropdownContent = ({
useScopedHotkeys(
Key.Escape,
() => {
- resetViewEditMode();
+ setViewEditMode('none');
closeDropdown();
},
customHotkeyScope.scope,
@@ -163,7 +153,6 @@ export const BoardOptionsDropdownContent = ({
() => {
handleStageSubmit();
handleViewNameSubmit();
- resetViewEditMode();
closeDropdown();
},
customHotkeyScope.scope,
@@ -173,20 +162,26 @@ export const BoardOptionsDropdownContent = ({
<>
{!currentMenu && (
<>
-
+ {viewEditMode && (
+
+ )}
{
@@ -147,7 +145,7 @@ export const EntityBoard = ({
return (boardColumns?.length ?? 0) > 0 ? (
-
+
diff --git a/front/src/modules/ui/layout/board/components/__stories__/BoardOptionsDropdown.stories.tsx b/front/src/modules/ui/layout/board/components/__stories__/BoardOptionsDropdown.stories.tsx
deleted file mode 100644
index f382f3359..000000000
--- a/front/src/modules/ui/layout/board/components/__stories__/BoardOptionsDropdown.stories.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { Meta, StoryObj } from '@storybook/react';
-import { userEvent, within } from '@storybook/testing-library';
-
-import { BoardContext } from '@/companies/states/contexts/BoardContext';
-import { CompanyBoardRecoilScopeContext } from '@/companies/states/recoil-scope-contexts/CompanyBoardRecoilScopeContext';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
-import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
-import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
-
-import { BoardOptionsDropdown } from '../BoardOptionsDropdown';
-
-const meta: Meta = {
- title: 'UI/Layout/Board/Options/BoardOptionsDropdown',
- component: BoardOptionsDropdown,
- decorators: [
- (Story, { parameters }) => (
-
-
-
-
-
- ),
- ComponentWithRecoilScopeDecorator,
- ComponentDecorator,
- ],
- parameters: {
- customRecoilScopeContext: CompanyBoardRecoilScopeContext,
- },
- args: {
- customHotkeyScope: { scope: 'scope' },
- },
-};
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {
- play: async ({ canvasElement }) => {
- const canvas = within(canvasElement);
-
- const dropdownButton = canvas.getByText('Options');
-
- await userEvent.click(dropdownButton);
- },
-};
diff --git a/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts b/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts
index 0a734d4be..33597f4d7 100644
--- a/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts
+++ b/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts
@@ -1,5 +1,5 @@
-import { ViewFieldForVisibility } from '@/ui/data/view-bar/types/ViewFieldForVisibility';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
+import { ViewFieldForVisibility } from '@/views/types/ViewFieldForVisibility';
import { boardCardFieldsScopedState } from '../states/boardCardFieldsScopedState';
diff --git a/front/src/modules/ui/layout/board/hooks/useBoardColumns.ts b/front/src/modules/ui/layout/board/hooks/useBoardColumns.ts
index 92a917eb0..b4832bd7a 100644
--- a/front/src/modules/ui/layout/board/hooks/useBoardColumns.ts
+++ b/front/src/modules/ui/layout/board/hooks/useBoardColumns.ts
@@ -1,6 +1,6 @@
import { useRecoilState } from 'recoil';
-import { useMoveViewColumns } from '@/views/hooks/useMoveViewColumns';
+import { useMoveViewColumns } from '@/ui/data/data-table/hooks/useMoveViewColumns';
import { useUpdatePipelineStageMutation } from '~/generated/graphql';
import { boardColumnsState } from '../states/boardColumnsState';
diff --git a/front/src/modules/ui/layout/board/types/BoardOptions.ts b/front/src/modules/ui/layout/board/types/BoardOptions.ts
index e4bd8bc0d..50baf36cc 100644
--- a/front/src/modules/ui/layout/board/types/BoardOptions.ts
+++ b/front/src/modules/ui/layout/board/types/BoardOptions.ts
@@ -1,7 +1,7 @@
import { ComponentType } from 'react';
-import { FilterDefinitionByEntity } from '@/ui/data/view-bar/types/FilterDefinitionByEntity';
-import { SortDefinition } from '@/ui/data/view-bar/types/SortDefinition';
+import { FilterDefinitionByEntity } from '@/ui/data/filter/types/FilterDefinitionByEntity';
+import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
import { PipelineProgress } from '~/generated/graphql';
export type BoardOptions = {
diff --git a/front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts b/front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts
index 7ddf10bc1..565a20261 100644
--- a/front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts
+++ b/front/src/modules/ui/layout/dropdown/hooks/useDropdown.ts
@@ -56,11 +56,11 @@ export const useDropdown = (props?: UseDropdownProps) => {
};
return {
+ scopeId,
isDropdownOpen: isDropdownOpen,
closeDropdown: closeDropdownButton,
toggleDropdown: toggleDropdownButton,
openDropdown: openDropdownButton,
- scopeId,
dropdownHotkeyScope,
setDropdownHotkeyScope,
dropdownWidth,
diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts
index 4e135f86b..76b4efcf2 100644
--- a/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts
+++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState.ts
@@ -10,12 +10,18 @@ export const useRecoilScopedFamilyState = <
scopedFamilyKey: ScopedFamilyStateKey,
) => RecoilState,
scopeId: string,
- familyKey: FamilyKey,
+ familyKey?: FamilyKey,
) => {
- return useRecoilState(
+ const familyState = useRecoilState(
recoilState({
scopeId,
- familyKey,
+ familyKey: familyKey || ('' as FamilyKey),
}),
);
+
+ if (!familyKey) {
+ return [undefined, undefined];
+ }
+
+ return familyState;
};
diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useSetRecoilScopedFamilyState.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useSetRecoilScopedFamilyState.ts
new file mode 100644
index 000000000..ee1a3be8e
--- /dev/null
+++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useSetRecoilScopedFamilyState.ts
@@ -0,0 +1,27 @@
+import { RecoilState, SerializableParam, useSetRecoilState } from 'recoil';
+
+import { ScopedFamilyStateKey } from '../scopes-internal/types/ScopedFamilyStateKey';
+
+export const useSetRecoilScopedFamilyState = <
+ StateType,
+ FamilyKey extends SerializableParam,
+>(
+ recoilState: (
+ scopedFamilyKey: ScopedFamilyStateKey,
+ ) => RecoilState,
+ scopeId: string,
+ familyKey?: FamilyKey,
+) => {
+ const familyState = useSetRecoilState(
+ recoilState({
+ scopeId,
+ familyKey: familyKey || ('' as FamilyKey),
+ }),
+ );
+
+ if (!familyKey) {
+ return;
+ }
+
+ return familyState;
+};
diff --git a/front/src/modules/ui/utilities/recoil-scope/hooks/useSetRecoilScopedStateV2.ts b/front/src/modules/ui/utilities/recoil-scope/hooks/useSetRecoilScopedStateV2.ts
new file mode 100644
index 000000000..fc043036f
--- /dev/null
+++ b/front/src/modules/ui/utilities/recoil-scope/hooks/useSetRecoilScopedStateV2.ts
@@ -0,0 +1,14 @@
+import { RecoilState, useSetRecoilState } from 'recoil';
+
+import { ScopedStateKey } from '../scopes-internal/types/ScopedStateKey';
+
+export const useSetRecoilScopedStateV2 = (
+ recoilState: (scopedKey: ScopedStateKey) => RecoilState,
+ scopeId: string,
+) => {
+ return useSetRecoilState(
+ recoilState({
+ scopeId,
+ }),
+ );
+};
diff --git a/front/src/modules/users/components/FilterDropdownUserSearchSelect.tsx b/front/src/modules/users/components/FilterDropdownUserSearchSelect.tsx
index b87ffa896..dc330a223 100644
--- a/front/src/modules/users/components/FilterDropdownUserSearchSelect.tsx
+++ b/front/src/modules/users/components/FilterDropdownUserSearchSelect.tsx
@@ -1,28 +1,12 @@
-import { Context } from 'react';
-
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
-import { FilterDropdownEntitySearchSelect } from '@/ui/data/view-bar/components/FilterDropdownEntitySearchSelect';
-import { filterDropdownSearchInputScopedState } from '@/ui/data/view-bar/states/filterDropdownSearchInputScopedState';
-import { filterDropdownSelectedEntityIdScopedState } from '@/ui/data/view-bar/states/filterDropdownSelectedEntityIdScopedState';
+import { FilterDropdownEntitySearchSelect } from '@/ui/data/filter/components/FilterDropdownEntitySearchSelect';
+import { useFilter } from '@/ui/data/filter/hooks/useFilter';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { useSearchUserQuery } from '~/generated/graphql';
-export const FilterDropdownUserSearchSelect = ({
- context,
-}: {
- context: Context;
-}) => {
- const filterDropdownSearchInput = useRecoilScopedValue(
- filterDropdownSearchInputScopedState,
- context,
- );
-
- const [filterDropdownSelectedEntityId] = useRecoilScopedState(
- filterDropdownSelectedEntityIdScopedState,
- context,
- );
+export const FilterDropdownUserSearchSelect = () => {
+ const { filterDropdownSearchInput, filterDropdownSelectedEntityId } =
+ useFilter();
const usersForSelect = useFilteredSearchEntityQuery({
queryHook: useSearchUserQuery,
diff --git a/front/src/modules/ui/data/view-bar/components/SortOrFilterChip.tsx b/front/src/modules/views/components/SortOrFilterChip.tsx
similarity index 100%
rename from front/src/modules/ui/data/view-bar/components/SortOrFilterChip.tsx
rename to front/src/modules/views/components/SortOrFilterChip.tsx
diff --git a/front/src/modules/views/components/UpdateViewButtonGroup.tsx b/front/src/modules/views/components/UpdateViewButtonGroup.tsx
new file mode 100644
index 000000000..f23f0ca3e
--- /dev/null
+++ b/front/src/modules/views/components/UpdateViewButtonGroup.tsx
@@ -0,0 +1,84 @@
+import { useCallback, useState } from 'react';
+import styled from '@emotion/styled';
+import { Key } from 'ts-key-enum';
+
+import { IconChevronDown, IconPlus } from '@/ui/display/icon';
+import { Button } from '@/ui/input/button/components/Button';
+import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup';
+import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
+import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
+import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
+import { useView } from '@/views/hooks/useView';
+
+import { useViewInternalStates } from '../hooks/useViewInternalStates';
+
+const StyledContainer = styled.div`
+ display: inline-flex;
+ margin-right: ${({ theme }) => theme.spacing(2)};
+ position: relative;
+`;
+export type UpdateViewButtonGroupProps = {
+ hotkeyScope: string;
+ onViewEditModeChange?: () => void;
+};
+
+export const UpdateViewButtonGroup = ({
+ hotkeyScope,
+ onViewEditModeChange,
+}: UpdateViewButtonGroupProps) => {
+ const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+ const { updateCurrentView, setViewEditMode } = useView();
+ const { canPersistFilters, canPersistSorts } = useViewInternalStates();
+
+ const canPersistView = canPersistFilters || canPersistSorts;
+
+ const handleArrowDownButtonClick = useCallback(() => {
+ setIsDropdownOpen((previousIsOpen) => !previousIsOpen);
+ }, []);
+
+ const handleCreateViewButtonClick = useCallback(() => {
+ setViewEditMode('create');
+ onViewEditModeChange?.();
+ setIsDropdownOpen(false);
+ }, [setViewEditMode, onViewEditModeChange]);
+
+ const handleDropdownClose = useCallback(() => {
+ setIsDropdownOpen(false);
+ }, []);
+
+ const handleViewSubmit = async () => {
+ await updateCurrentView?.();
+ };
+
+ useScopedHotkeys(
+ [Key.Enter, Key.Escape],
+ handleDropdownClose,
+ hotkeyScope,
+ [],
+ );
+
+ if (!canPersistView) return null;
+
+ return (
+
+
+
+
+
+
+ {isDropdownOpen && (
+
+
+
+ )}
+
+ );
+};
diff --git a/front/src/modules/views/components/ViewBar.tsx b/front/src/modules/views/components/ViewBar.tsx
new file mode 100644
index 000000000..c1408a9fc
--- /dev/null
+++ b/front/src/modules/views/components/ViewBar.tsx
@@ -0,0 +1,82 @@
+import { ReactNode } from 'react';
+
+import { FilterDropdownButton } from '@/ui/data/filter/components/FilterDropdownButton';
+import { FilterScope } from '@/ui/data/filter/scopes/FilterScope';
+import { FiltersHotkeyScope } from '@/ui/data/filter/types/FiltersHotkeyScope';
+import { SortDropdownButton } from '@/ui/data/sort/components/SortDropdownButton';
+import { SortScope } from '@/ui/data/sort/scopes/SortScope';
+import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
+import { TopBar } from '@/ui/layout/top-bar/TopBar';
+
+import { useView } from '../hooks/useView';
+import { useViewInternalStates } from '../hooks/useViewInternalStates';
+import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
+
+import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
+import { ViewBarDetails } from './ViewBarDetails';
+import { ViewsDropdownButton } from './ViewsDropdownButton';
+
+export type ViewBarProps = {
+ className?: string;
+ optionsDropdownButton: ReactNode;
+ optionsDropdownScopeId: string;
+};
+
+export const ViewBar = ({
+ className,
+ optionsDropdownButton,
+ optionsDropdownScopeId,
+}: ViewBarProps) => {
+ const { openDropdown: openOptionsDropdownButton } = useDropdown({
+ dropdownScopeId: optionsDropdownScopeId,
+ });
+ const { upsertViewSort } = useView();
+ const { availableFilters, availableSorts } = useViewInternalStates();
+
+ return (
+
+
+
+ }
+ displayBottomBorder={false}
+ rightComponent={
+ <>
+
+
+ {optionsDropdownButton}
+ >
+ }
+ bottomComponent={
+
+ }
+ />
+ }
+ />
+
+
+ );
+};
diff --git a/front/src/modules/ui/data/view-bar/components/ViewBarDetails.tsx b/front/src/modules/views/components/ViewBarDetails.tsx
similarity index 58%
rename from front/src/modules/ui/data/view-bar/components/ViewBarDetails.tsx
rename to front/src/modules/views/components/ViewBarDetails.tsx
index 61ea99d03..6a681d95e 100644
--- a/front/src/modules/ui/data/view-bar/components/ViewBarDetails.tsx
+++ b/front/src/modules/views/components/ViewBarDetails.tsx
@@ -1,26 +1,14 @@
-import { ReactNode, useContext } from 'react';
+import { ReactNode } from 'react';
import styled from '@emotion/styled';
-import { useRecoilValue } from 'recoil';
+import { AddFilterFromDropdownButton } from '@/ui/data/filter/components/AddFilterFromDetailsButton';
+import { getOperandLabelShort } from '@/ui/data/filter/utils/getOperandLabel';
import { IconArrowDown, IconArrowUp } from '@/ui/display/icon/index';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
-import { ViewBarContext } from '../contexts/ViewBarContext';
import { useRemoveFilter } from '../hooks/useRemoveFilter';
-import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
-import { currentViewIdScopedState } from '../states/currentViewIdScopedState';
-import { filtersScopedState } from '../states/filtersScopedState';
-import { isViewBarExpandedScopedState } from '../states/isViewBarExpandedScopedState';
-import { canPersistFiltersScopedFamilySelector } from '../states/selectors/canPersistFiltersScopedFamilySelector';
-import { canPersistSortsScopedFamilySelector } from '../states/selectors/canPersistSortsScopedFamilySelector';
-import { savedFiltersFamilySelector } from '../states/selectors/savedFiltersFamilySelector';
-import { savedSortsFamilySelector } from '../states/selectors/savedSortsFamilySelector';
-import { sortsScopedState } from '../states/sortsScopedState';
-import { getOperandLabelShort } from '../utils/getOperandLabel';
+import { useView } from '../hooks/useView';
+import { useViewInternalStates } from '../hooks/useViewInternalStates';
-import { AddFilterFromDropdownButton } from './AddFilterFromDetailsButton';
import SortOrFilterChip from './SortOrFilterChip';
export type ViewBarDetailsProps = {
@@ -100,59 +88,21 @@ export const ViewBarDetails = ({
hasFilterButton = false,
rightComponent,
}: ViewBarDetailsProps) => {
- const { canPersistViewFields, onViewBarReset, ViewBarRecoilScopeContext } =
- useContext(ViewBarContext);
+ const {
+ currentViewSorts,
+ setCurrentViewSorts,
+ availableFilters,
+ currentViewFilters,
+ canPersistFilters,
+ canPersistSorts,
+ isViewBarExpanded,
+ } = useViewInternalStates();
- const recoilScopeId = useRecoilScopeId(ViewBarRecoilScopeContext);
+ const { resetViewBar } = useView();
- const currentViewId = useRecoilScopedValue(
- currentViewIdScopedState,
- ViewBarRecoilScopeContext,
- );
+ const canPersistView = canPersistFilters || canPersistSorts;
- const [filters, setFilters] = useRecoilScopedState(
- filtersScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const savedFilters = useRecoilValue(
- savedFiltersFamilySelector(currentViewId),
- );
-
- const savedSorts = useRecoilValue(savedSortsFamilySelector(currentViewId));
-
- const [availableFilters] = useRecoilScopedState(
- availableFiltersScopedState,
- ViewBarRecoilScopeContext,
- );
- const canPersistFilters = useRecoilValue(
- canPersistFiltersScopedFamilySelector({
- recoilScopeId,
- viewId: currentViewId,
- }),
- );
-
- const [sorts, setSorts] = useRecoilScopedState(
- sortsScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const canPersistSorts = useRecoilValue(
- canPersistSortsScopedFamilySelector({
- recoilScopeId,
- viewId: currentViewId,
- }),
- );
-
- const canPersistView =
- canPersistViewFields || canPersistFilters || canPersistSorts;
-
- const [isViewBarExpanded] = useRecoilScopedState(
- isViewBarExpandedScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const filtersWithDefinition = filters.map((filter) => {
+ const filtersWithDefinition = currentViewFilters?.map((filter) => {
const filterDefinition = availableFilters.find((availableFilter) => {
return availableFilter.key === filter.key;
});
@@ -166,19 +116,18 @@ export const ViewBarDetails = ({
const removeFilter = useRemoveFilter();
const handleCancelClick = () => {
- onViewBarReset?.();
- setFilters(savedFilters);
- setSorts(savedSorts);
+ resetViewBar();
};
const handleSortRemove = (sortKey: string) =>
- setSorts((previousSorts) =>
+ setCurrentViewSorts?.((previousSorts) =>
previousSorts.filter((sort) => sort.key !== sortKey),
);
const shouldExpandViewBar =
canPersistView ||
- ((filtersWithDefinition.length || sorts.length) && isViewBarExpanded);
+ ((filtersWithDefinition?.length || currentViewSorts?.length) &&
+ isViewBarExpanded);
if (!shouldExpandViewBar) {
return null;
@@ -188,7 +137,7 @@ export const ViewBarDetails = ({
- {sorts.map((sort) => {
+ {currentViewSorts?.map((sort) => {
return (
);
})}
- {!!sorts.length && !!filtersWithDefinition.length && (
+ {!!currentViewSorts?.length && !!filtersWithDefinition?.length && (
)}
- {filtersWithDefinition.map((filter) => {
+ {filtersWithDefinition?.map((filter) => {
return (
{
+ const {
+ scopeId: viewScopeId,
+ setCurrentViewFields,
+ setSavedViewFields,
+ setCurrentViewSorts,
+ setSavedViewSorts,
+ setCurrentViewFilters,
+ setSavedViewFilters,
+ currentViewId,
+ setViews,
+ setCurrentViewId,
+ } = useView();
+
+ const { viewType, viewObjectId } = useViewInternalStates(viewScopeId);
+
+ useGetViewFieldsQuery({
+ skip: !currentViewId,
+ variables: {
+ orderBy: { index: SortOrder.Asc },
+ where: {
+ viewId: { equals: currentViewId },
+ },
+ },
+ onCompleted: useRecoilCallback(({ snapshot }) => async (data) => {
+ const availableFields = snapshot
+ .getLoadable(availableFieldsScopedState({ scopeId: viewScopeId }))
+ .getValue();
+
+ if (!availableFields || !currentViewId) {
+ return;
+ }
+
+ const savedViewFields = snapshot
+ .getLoadable(
+ savedViewFieldsScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: currentViewId,
+ }),
+ )
+ .getValue();
+
+ const queriedViewFields = data.viewFields
+ .map | null>((viewField) => {
+ const columnDefinition = availableFields.find(
+ ({ key }) => viewField.key === key,
+ );
+
+ return columnDefinition
+ ? {
+ ...columnDefinition,
+ key: viewField.key,
+ name: viewField.name,
+ index: viewField.index,
+ size: viewField.size ?? columnDefinition.size,
+ isVisible: viewField.isVisible,
+ }
+ : null;
+ })
+ .filter>(assertNotNull);
+
+ if (!isDeeplyEqual(savedViewFields, queriedViewFields)) {
+ setCurrentViewFields?.(queriedViewFields);
+ setSavedViewFields?.(queriedViewFields);
+ }
+ }),
+ });
+
+ useGetViewsQuery({
+ variables: {
+ where: {
+ objectId: { equals: viewObjectId },
+ type: { equals: viewType },
+ },
+ },
+ onCompleted: useRecoilCallback(({ snapshot }) => async (data) => {
+ const nextViews = data.views.map((view) => ({
+ id: view.id,
+ name: view.name,
+ }));
+ const views = snapshot
+ .getLoadable(viewsScopedState({ scopeId: viewScopeId }))
+ .getValue();
+
+ if (!isDeeplyEqual(views, nextViews)) setViews(nextViews);
+
+ if (!nextViews.length) return;
+
+ if (!currentViewId) return setCurrentViewId(nextViews[0].id);
+ }),
+ });
+
+ useGetViewSortsQuery({
+ skip: !currentViewId,
+ variables: {
+ where: {
+ viewId: { equals: currentViewId },
+ },
+ },
+ onCompleted: useRecoilCallback(({ snapshot }) => async (data) => {
+ const availableSorts = snapshot
+ .getLoadable(availableSortsScopedState({ scopeId: viewScopeId }))
+ .getValue();
+
+ if (!availableSorts || !currentViewId) {
+ return;
+ }
+
+ const savedViewSorts = snapshot
+ .getLoadable(
+ savedViewSortsScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: currentViewId,
+ }),
+ )
+ .getValue();
+
+ const queriedViewSorts = data.viewSorts
+ .map((viewSort) => {
+ const foundCorrespondingSortDefinition = availableSorts.find(
+ (sort) => sort.key === viewSort.key,
+ );
+
+ if (foundCorrespondingSortDefinition) {
+ return {
+ key: viewSort.key,
+ definition: foundCorrespondingSortDefinition,
+ direction: viewSort.direction.toLowerCase(),
+ } as Sort;
+ } else {
+ return undefined;
+ }
+ })
+ .filter((sort): sort is Sort => !!sort);
+
+ if (!isDeeplyEqual(savedViewSorts, queriedViewSorts)) {
+ setSavedViewSorts?.(queriedViewSorts);
+ setCurrentViewSorts?.(queriedViewSorts);
+ }
+ }),
+ });
+
+ useGetViewFiltersQuery({
+ skip: !currentViewId,
+ variables: {
+ where: {
+ viewId: { equals: currentViewId },
+ },
+ },
+ onCompleted: useRecoilCallback(({ snapshot }) => (data) => {
+ const availableFilters = snapshot
+ .getLoadable(availableFiltersScopedState({ scopeId: viewScopeId }))
+ .getValue();
+
+ if (!availableFilters || !currentViewId) {
+ return;
+ }
+
+ const savedViewFilters = snapshot
+ .getLoadable(
+ savedViewFiltersScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: currentViewId,
+ }),
+ )
+ .getValue();
+
+ const queriedViewFilters = data.viewFilters
+ .map(({ __typename, name: _name, ...viewFilter }) => {
+ const availableFilter = availableFilters.find(
+ (filter) => filter.key === viewFilter.key,
+ );
+
+ return availableFilter
+ ? {
+ ...viewFilter,
+ displayValue: viewFilter.displayValue ?? viewFilter.value,
+ type: availableFilter.type,
+ }
+ : undefined;
+ })
+ .filter((filter): filter is Filter => !!filter);
+
+ if (!isDeeplyEqual(savedViewFilters, queriedViewFilters)) {
+ setSavedViewFilters?.(queriedViewFilters);
+ setCurrentViewFilters?.(queriedViewFilters);
+ }
+ }),
+ });
+
+ return <>>;
+};
diff --git a/front/src/modules/ui/data/view-bar/components/ViewFieldsVisibilityDropdownSection.tsx b/front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx
similarity index 100%
rename from front/src/modules/ui/data/view-bar/components/ViewFieldsVisibilityDropdownSection.tsx
rename to front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx
diff --git a/front/src/modules/ui/data/view-bar/components/ViewsDropdownButton.tsx b/front/src/modules/views/components/ViewsDropdownButton.tsx
similarity index 61%
rename from front/src/modules/ui/data/view-bar/components/ViewsDropdownButton.tsx
rename to front/src/modules/views/components/ViewsDropdownButton.tsx
index 0cc3d4f04..c0d0623a3 100644
--- a/front/src/modules/ui/data/view-bar/components/ViewsDropdownButton.tsx
+++ b/front/src/modules/views/components/ViewsDropdownButton.tsx
@@ -1,22 +1,8 @@
-import { MouseEvent, useContext } from 'react';
+import { MouseEvent } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
-import {
- RecoilValueReadOnly,
- useRecoilCallback,
- useRecoilValue,
- useSetRecoilState,
-} from 'recoil';
+import { useRecoilCallback } from 'recoil';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { entityCountInCurrentViewState } from '@/ui/data/view-bar/states/entityCountInCurrentViewState';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState';
-import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState';
-import { currentViewScopedSelector } from '@/ui/data/view-bar/states/selectors/currentViewScopedSelector';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
-import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
-import { viewsScopedState } from '@/ui/data/view-bar/states/viewsScopedState';
import {
IconChevronDown,
IconList,
@@ -33,14 +19,11 @@ import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
import { assertNotNull } from '~/utils/assert';
import { ViewsDropdownId } from '../constants/ViewsDropdownId';
-import { ViewBarContext } from '../contexts/ViewBarContext';
-import { useRemoveView } from '../hooks/useRemoveView';
+import { useView } from '../hooks/useView';
+import { useViewInternalStates } from '../hooks/useViewInternalStates';
const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
font-weight: ${({ theme }) => theme.font.weight.regular};
@@ -83,54 +66,31 @@ export const ViewsDropdownButton = ({
onViewEditModeChange,
}: ViewsDropdownButtonProps) => {
const theme = useTheme();
+ const { scopeId, removeView, currentViewId } = useView();
- const { defaultViewName, onViewSelect, ViewBarRecoilScopeContext } =
- useContext(ViewBarContext);
-
- const recoilScopeId = useRecoilScopeId(ViewBarRecoilScopeContext);
-
- const currentView = useRecoilScopedValue(
- currentViewScopedSelector,
- ViewBarRecoilScopeContext,
- );
-
- const [views] = useRecoilScopedState(
- viewsScopedState,
- ViewBarRecoilScopeContext,
- );
-
- const entityCount = useRecoilValue(
- entityCountInCurrentViewState as RecoilValueReadOnly,
- );
+ const {
+ views,
+ currentView,
+ setViewEditMode,
+ setCurrentViewId,
+ entityCountInCurrentView,
+ } = useViewInternalStates(scopeId, currentViewId);
const { isDropdownOpen, closeDropdown } = useDropdown({
dropdownScopeId: ViewsDropdownId,
});
- const setViewEditMode = useSetRecoilState(viewEditModeState);
-
const handleViewSelect = useRecoilCallback(
- ({ set, snapshot }) =>
- async (viewId: string) => {
- await onViewSelect?.(viewId);
+ () => async (viewId: string) => {
+ setCurrentViewId(viewId);
- const savedFilters = await snapshot.getPromise(
- savedFiltersFamilyState(viewId),
- );
- const savedSorts = await snapshot.getPromise(
- savedSortsFamilyState(viewId),
- );
-
- set(filtersScopedState(recoilScopeId), savedFilters);
- set(sortsScopedState(recoilScopeId), savedSorts);
- set(currentViewIdScopedState(recoilScopeId), viewId);
- closeDropdown();
- },
- [onViewSelect, recoilScopeId, closeDropdown],
+ closeDropdown();
+ },
+ [setCurrentViewId, closeDropdown],
);
const handleAddViewButtonClick = () => {
- setViewEditMode({ mode: 'create', viewId: undefined });
+ setViewEditMode('create');
onViewEditModeChange?.();
closeDropdown();
};
@@ -140,13 +100,12 @@ export const ViewsDropdownButton = ({
viewId: string,
) => {
event.stopPropagation();
- setViewEditMode({ mode: 'edit', viewId });
+ setCurrentViewId(viewId);
+ setViewEditMode('edit');
onViewEditModeChange?.();
closeDropdown();
};
- const { removeView } = useRemoveView();
-
const handleDeleteViewButtonClick = async (
event: MouseEvent,
viewId: string,
@@ -164,11 +123,10 @@ export const ViewsDropdownButton = ({
clickableComponent={
-
- {currentView?.name || defaultViewName}
-
+ {currentView?.name}
- · {entityCount}
+ · {entityCountInCurrentView}{' '}
+
}
diff --git a/front/src/modules/ui/data/view-bar/constants/ViewsDropdownId.ts b/front/src/modules/views/constants/ViewsDropdownId.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/constants/ViewsDropdownId.ts
rename to front/src/modules/views/constants/ViewsDropdownId.ts
diff --git a/front/src/modules/views/hooks/internal/useViewFields.ts b/front/src/modules/views/hooks/internal/useViewFields.ts
new file mode 100644
index 000000000..99ede9967
--- /dev/null
+++ b/front/src/modules/views/hooks/internal/useViewFields.ts
@@ -0,0 +1,121 @@
+/* eslint-disable no-console */
+import { getOperationName } from '@apollo/client/utilities';
+import { useRecoilCallback } from 'recoil';
+
+import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
+import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
+import { currentViewIdScopedState } from '@/views/states/currentViewIdScopedState';
+import { savedViewFieldByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFieldByKeyScopedFamilySelector';
+import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState';
+import {
+ useCreateViewFieldsMutation,
+ useUpdateViewFieldMutation,
+} from '~/generated/graphql';
+
+import { GET_VIEW_FIELDS } from '../../graphql/queries/getViewFields';
+
+export const toViewFieldInput = (
+ objectId: string,
+ fieldDefinition: ColumnDefinition,
+) => ({
+ key: fieldDefinition.key,
+ name: fieldDefinition.name,
+ index: fieldDefinition.index,
+ isVisible: fieldDefinition.isVisible ?? true,
+ objectId,
+ size: fieldDefinition.size,
+});
+
+export const useViewFields = (viewScopeId: string) => {
+ const [createViewFieldsMutation] = useCreateViewFieldsMutation();
+ const [updateViewFieldMutation] = useUpdateViewFieldMutation();
+
+ const persistViewFields = useRecoilCallback(
+ ({ snapshot }) =>
+ async (viewFieldsToPersist: ColumnDefinition[]) => {
+ const currentViewId = snapshot
+ .getLoadable(currentViewIdScopedState({ scopeId: viewScopeId }))
+ .getValue();
+
+ const viewObjectId = snapshot
+ .getLoadable(viewObjectIdScopeState({ scopeId: viewScopeId }))
+ .getValue();
+
+ const savedViewFieldsByKey = snapshot
+ .getLoadable(
+ savedViewFieldByKeyScopedFamilySelector({
+ viewScopeId: viewScopeId,
+ viewId: currentViewId,
+ }),
+ )
+ .getValue();
+
+ if (!currentViewId || !savedViewFieldsByKey || !viewObjectId) {
+ return;
+ }
+ const _createViewFields = (
+ viewFieldsToCreate: ColumnDefinition[],
+ objectId: string,
+ ) => {
+ if (!currentViewId || !viewFieldsToCreate.length) {
+ return;
+ }
+
+ return createViewFieldsMutation({
+ variables: {
+ data: viewFieldsToCreate.map((viewField) => ({
+ ...toViewFieldInput(objectId, viewField),
+ viewId: currentViewId,
+ })),
+ },
+ refetchQueries: [getOperationName(GET_VIEW_FIELDS) ?? ''],
+ });
+ };
+
+ const _updateViewFields = (
+ viewFieldsToUpdate: ColumnDefinition[],
+ ) => {
+ if (!currentViewId || !viewFieldsToUpdate.length) {
+ return;
+ }
+
+ return Promise.all(
+ viewFieldsToUpdate.map((viewField) =>
+ updateViewFieldMutation({
+ variables: {
+ data: {
+ isVisible: viewField.isVisible,
+ size: viewField.size,
+ index: viewField.index,
+ },
+ where: {
+ viewId_key: { key: viewField.key, viewId: currentViewId },
+ },
+ },
+ }),
+ ),
+ );
+ };
+
+ const viewFieldsToCreate = viewFieldsToPersist.filter(
+ (viewField) => !savedViewFieldsByKey[viewField.key],
+ );
+ await _createViewFields(viewFieldsToCreate, viewObjectId);
+
+ const viewFieldsToUpdate = viewFieldsToPersist.filter(
+ (viewFieldToPersit) =>
+ savedViewFieldsByKey[viewFieldToPersit.key] &&
+ (savedViewFieldsByKey[viewFieldToPersit.key].size !==
+ viewFieldToPersit.size ||
+ savedViewFieldsByKey[viewFieldToPersit.key].index !==
+ viewFieldToPersit.index ||
+ savedViewFieldsByKey[viewFieldToPersit.key].isVisible !==
+ viewFieldToPersit.isVisible),
+ );
+
+ await _updateViewFields(viewFieldsToUpdate);
+ },
+ );
+
+ return { persistViewFields };
+};
diff --git a/front/src/modules/views/hooks/internal/useViewFilters.ts b/front/src/modules/views/hooks/internal/useViewFilters.ts
new file mode 100644
index 000000000..fe53a9afe
--- /dev/null
+++ b/front/src/modules/views/hooks/internal/useViewFilters.ts
@@ -0,0 +1,165 @@
+import { useCallback } from 'react';
+import { useRecoilCallback } from 'recoil';
+
+import { Filter } from '@/ui/data/filter/types/Filter';
+import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
+import { availableFiltersScopedState } from '@/views/states/availableFiltersScopedState';
+import { currentViewFiltersScopedFamilyState } from '@/views/states/currentViewFiltersScopedFamilyState';
+import { savedViewFiltersByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector';
+import {
+ useCreateViewFiltersMutation,
+ useDeleteViewFiltersMutation,
+ useUpdateViewFilterMutation,
+} from '~/generated/graphql';
+
+import { useViewStates } from '../useViewStates';
+
+export const useViewFilters = (viewScopeId: string) => {
+ const { currentViewId } = useViewStates(viewScopeId);
+
+ const [createViewFiltersMutation] = useCreateViewFiltersMutation();
+ const [updateViewFilterMutation] = useUpdateViewFilterMutation();
+ const [deleteViewFiltersMutation] = useDeleteViewFiltersMutation();
+
+ const _createViewFilters = useCallback(
+ (
+ filters: Filter[],
+ availableFilters: FilterDefinition[] = [],
+ viewId = currentViewId,
+ ) => {
+ if (!viewId || !filters.length) {
+ return;
+ }
+
+ if (!availableFilters) {
+ return;
+ }
+
+ return createViewFiltersMutation({
+ variables: {
+ data: filters.map((filter) => ({
+ displayValue: filter.displayValue ?? filter.value,
+ key: filter.key,
+ name:
+ availableFilters.find(({ key }) => key === filter.key)?.label ??
+ '',
+ operand: filter.operand,
+ value: filter.value,
+ viewId,
+ })),
+ },
+ });
+ },
+ [createViewFiltersMutation, currentViewId],
+ );
+
+ const _updateViewFilters = useCallback(
+ (filters: Filter[], viewId = currentViewId) => {
+ if (!viewId || !filters.length) return;
+
+ return Promise.all(
+ filters.map((filter) =>
+ updateViewFilterMutation({
+ variables: {
+ data: {
+ displayValue: filter.displayValue ?? filter.value,
+ operand: filter.operand,
+ value: filter.value,
+ },
+ where: {
+ viewId_key: { key: filter.key, viewId: viewId },
+ },
+ },
+ }),
+ ),
+ );
+ },
+ [currentViewId, updateViewFilterMutation],
+ );
+
+ const _deleteViewFilters = useCallback(
+ (filterKeys: string[], viewId = currentViewId) => {
+ if (!viewId || !filterKeys.length) return;
+
+ return deleteViewFiltersMutation({
+ variables: {
+ where: {
+ key: { in: filterKeys },
+ viewId: { equals: viewId },
+ },
+ },
+ });
+ },
+ [currentViewId, deleteViewFiltersMutation],
+ );
+
+ const persistViewFilters = useRecoilCallback(
+ ({ snapshot }) =>
+ async () => {
+ if (!currentViewId) {
+ return;
+ }
+
+ const currentViewFilters = snapshot
+ .getLoadable(
+ currentViewFiltersScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: currentViewId,
+ }),
+ )
+ .getValue();
+
+ const savedViewFiltersByKey = snapshot
+ .getLoadable(
+ savedViewFiltersByKeyScopedFamilySelector({
+ scopeId: viewScopeId,
+ viewId: currentViewId,
+ }),
+ )
+ .getValue();
+
+ if (!currentViewFilters) {
+ return;
+ }
+ if (!savedViewFiltersByKey) {
+ return;
+ }
+
+ const availableFilters = snapshot
+ .getLoadable(
+ availableFiltersScopedState({
+ scopeId: viewScopeId,
+ }),
+ )
+ .getValue();
+
+ const filtersToCreate = currentViewFilters.filter(
+ (filter) => !savedViewFiltersByKey[filter.key],
+ );
+ await _createViewFilters(filtersToCreate, availableFilters);
+
+ const filtersToUpdate = currentViewFilters.filter(
+ (filter) =>
+ savedViewFiltersByKey[filter.key] &&
+ (savedViewFiltersByKey[filter.key].operand !== filter.operand ||
+ savedViewFiltersByKey[filter.key].value !== filter.value),
+ );
+ await _updateViewFilters(filtersToUpdate);
+
+ const filterKeys = currentViewFilters.map((filter) => filter.key);
+ const filterKeysToDelete = Object.keys(savedViewFiltersByKey).filter(
+ (previousFilterKey) => !filterKeys.includes(previousFilterKey),
+ );
+ await _deleteViewFilters(filterKeysToDelete);
+ },
+ [
+ currentViewId,
+ viewScopeId,
+ _createViewFilters,
+ _updateViewFilters,
+ _deleteViewFilters,
+ ],
+ );
+
+ return { persistViewFilters };
+};
diff --git a/front/src/modules/views/hooks/internal/useViewSorts.ts b/front/src/modules/views/hooks/internal/useViewSorts.ts
new file mode 100644
index 000000000..966968edd
--- /dev/null
+++ b/front/src/modules/views/hooks/internal/useViewSorts.ts
@@ -0,0 +1,157 @@
+/* eslint-disable no-console */
+import { useCallback } from 'react';
+import { produce } from 'immer';
+import { useRecoilCallback } from 'recoil';
+
+import { Sort } from '@/ui/data/sort/types/Sort';
+import { currentViewSortsScopedFamilyState } from '@/views/states/currentViewSortsScopedFamilyState';
+import { savedViewSortsByKeyScopedFamilySelector } from '@/views/states/selectors/savedViewSortsByKeyScopedFamilySelector';
+import {
+ useCreateViewSortsMutation,
+ useDeleteViewSortsMutation,
+ useUpdateViewSortMutation,
+ ViewSortDirection,
+} from '~/generated/graphql';
+
+import { useViewStates } from '../useViewStates';
+
+export const useViewSorts = (viewScopeId: string) => {
+ const { currentViewId, setCurrentViewSorts } = useViewStates(viewScopeId);
+
+ const [createViewSortsMutation] = useCreateViewSortsMutation();
+ const [updateViewSortMutation] = useUpdateViewSortMutation();
+ const [deleteViewSortsMutation] = useDeleteViewSortsMutation();
+
+ const _createViewSorts = useCallback(
+ (sorts: Sort[], viewId = currentViewId) => {
+ if (!viewId || !sorts.length) return;
+
+ return createViewSortsMutation({
+ variables: {
+ data: sorts.map((sort) => ({
+ key: sort.key,
+ direction: sort.direction as ViewSortDirection,
+ name: sort.definition.label,
+ viewId,
+ })),
+ },
+ });
+ },
+ [createViewSortsMutation, currentViewId],
+ );
+
+ const _updateViewSorts = useCallback(
+ (sorts: Sort[]) => {
+ if (!currentViewId || !sorts.length) return;
+
+ return Promise.all(
+ sorts.map((sort) =>
+ updateViewSortMutation({
+ variables: {
+ data: {
+ direction: sort.direction as ViewSortDirection,
+ },
+ where: {
+ viewId_key: { key: sort.key, viewId: currentViewId },
+ },
+ },
+ }),
+ ),
+ );
+ },
+ [currentViewId, updateViewSortMutation],
+ );
+
+ const _deleteViewSorts = useCallback(
+ (sortKeys: string[]) => {
+ if (!currentViewId || !sortKeys.length) return;
+
+ return deleteViewSortsMutation({
+ variables: {
+ where: {
+ key: { in: sortKeys },
+ viewId: { equals: currentViewId },
+ },
+ },
+ });
+ },
+ [currentViewId, deleteViewSortsMutation],
+ );
+
+ const persistViewSorts = useRecoilCallback(
+ ({ snapshot }) =>
+ async () => {
+ if (!currentViewId) {
+ return;
+ }
+
+ const currentViewSorts = snapshot
+ .getLoadable(
+ currentViewSortsScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: currentViewId,
+ }),
+ )
+ .getValue();
+
+ const savedViewSortsByKey = snapshot
+ .getLoadable(
+ savedViewSortsByKeyScopedFamilySelector({
+ scopeId: viewScopeId,
+ viewId: currentViewId,
+ }),
+ )
+ .getValue();
+
+ if (!currentViewSorts) {
+ return;
+ }
+ if (!savedViewSortsByKey) {
+ return;
+ }
+
+ const sortsToCreate = currentViewSorts.filter(
+ (sort) => !savedViewSortsByKey[sort.key],
+ );
+ await _createViewSorts(sortsToCreate);
+
+ const sortsToUpdate = currentViewSorts.filter(
+ (sort) =>
+ savedViewSortsByKey[sort.key] &&
+ savedViewSortsByKey[sort.key].direction !== sort.direction,
+ );
+ await _updateViewSorts(sortsToUpdate);
+
+ const sortKeys = currentViewSorts.map((sort) => sort.key);
+ const sortKeysToDelete = Object.keys(savedViewSortsByKey).filter(
+ (previousSortKey) => !sortKeys.includes(previousSortKey),
+ );
+ await _deleteViewSorts(sortKeysToDelete);
+ },
+ [
+ currentViewId,
+ viewScopeId,
+ _createViewSorts,
+ _updateViewSorts,
+ _deleteViewSorts,
+ ],
+ );
+
+ const upsertViewSort = (sortToUpsert: Sort) => {
+ setCurrentViewSorts?.((sorts) => {
+ return produce(sorts, (sortsDraft) => {
+ const index = sortsDraft.findIndex(
+ (sort) => sort.key === sortToUpsert.key,
+ );
+
+ if (index === -1) {
+ sortsDraft.push(sortToUpsert);
+ } else {
+ sortsDraft[index] = sortToUpsert;
+ }
+ });
+ });
+ };
+
+ return { persistViewSorts, upsertViewSort };
+};
diff --git a/front/src/modules/views/hooks/internal/useViews.ts b/front/src/modules/views/hooks/internal/useViews.ts
new file mode 100644
index 000000000..7f0380f27
--- /dev/null
+++ b/front/src/modules/views/hooks/internal/useViews.ts
@@ -0,0 +1,67 @@
+import { getOperationName } from '@apollo/client/utilities';
+import { useRecoilCallback } from 'recoil';
+
+import { viewObjectIdScopeState } from '@/views/states/viewObjectIdScopeState';
+import { viewTypeScopedState } from '@/views/states/viewTypeScopedState';
+import { View } from '@/views/types/View';
+import {
+ useCreateViewMutation,
+ useDeleteViewMutation,
+ useUpdateViewMutation,
+} from '~/generated/graphql';
+
+import { GET_VIEWS } from '../../graphql/queries/getViews';
+
+export const useViews = (scopeId: string) => {
+ const [createViewMutation] = useCreateViewMutation();
+ const [updateViewMutation] = useUpdateViewMutation();
+ const [deleteViewMutation] = useDeleteViewMutation();
+
+ const createView = useRecoilCallback(({ snapshot }) => async (view: View) => {
+ const viewObjectId = await snapshot
+ .getLoadable(viewObjectIdScopeState({ scopeId }))
+ .getValue();
+
+ const viewType = await snapshot
+ .getLoadable(viewTypeScopedState({ scopeId }))
+ .getValue();
+
+ if (!viewObjectId || !viewType) {
+ return;
+ }
+ await createViewMutation({
+ variables: {
+ data: {
+ ...view,
+ objectId: viewObjectId,
+ type: viewType,
+ },
+ },
+ refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
+ });
+ });
+
+ const updateView = async (view: View) => {
+ await updateViewMutation({
+ variables: {
+ data: { name: view.name },
+ where: { id: view.id },
+ },
+ refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
+ });
+ };
+
+ const deleteView = async (viewId: string) => {
+ await deleteViewMutation({
+ variables: { where: { id: viewId } },
+ refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
+ });
+ };
+
+ return {
+ createView,
+ deleteView,
+ isFetchingViews: false,
+ updateView,
+ };
+};
diff --git a/front/src/modules/views/hooks/useBoardViewFields.ts b/front/src/modules/views/hooks/useBoardViewFields.ts
deleted file mode 100644
index 9172ec628..000000000
--- a/front/src/modules/views/hooks/useBoardViewFields.ts
+++ /dev/null
@@ -1,167 +0,0 @@
-import { useRecoilValue, useSetRecoilState } from 'recoil';
-
-import { RecoilScopeContext } from '@/types/RecoilScopeContext';
-import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { availableBoardCardFieldsScopedState } from '@/ui/layout/board/states/availableBoardCardFieldsScopedState';
-import { boardCardFieldsScopedState } from '@/ui/layout/board/states/boardCardFieldsScopedState';
-import { savedBoardCardFieldsFamilyState } from '@/ui/layout/board/states/savedBoardCardFieldsFamilyState';
-import { savedBoardCardFieldsByKeyFamilySelector } from '@/ui/layout/board/states/selectors/savedBoardCardFieldsByKeyFamilySelector';
-import { BoardFieldDefinition } from '@/ui/layout/board/types/BoardFieldDefinition';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import {
- SortOrder,
- useCreateViewFieldsMutation,
- useGetViewFieldsQuery,
- useUpdateViewFieldMutation,
-} from '~/generated/graphql';
-import { assertNotNull } from '~/utils/assert';
-import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
-
-const toViewFieldInput = (
- objectId: 'company' | 'person',
- columDefinition: BoardFieldDefinition,
-) => ({
- key: columDefinition.key,
- name: columDefinition.name,
- index: columDefinition.index,
- isVisible: columDefinition.isVisible ?? true,
- objectId,
-});
-
-export const useBoardViewFields = ({
- objectId,
- viewFieldDefinition,
- skipFetch,
- RecoilScopeContext,
-}: {
- objectId: 'company' | 'person';
- viewFieldDefinition: BoardFieldDefinition[];
- skipFetch?: boolean;
- RecoilScopeContext: RecoilScopeContext;
-}) => {
- const currentViewId = useRecoilScopedValue(
- currentViewIdScopedState,
- RecoilScopeContext,
- );
- const [availableBoardCardFields, setAvailableBoardCardFields] =
- useRecoilScopedState(
- availableBoardCardFieldsScopedState,
- RecoilScopeContext,
- );
- const [boardCardFields, setBoardCardFields] = useRecoilScopedState(
- boardCardFieldsScopedState,
- RecoilScopeContext,
- );
- const setSavedBoardCardFields = useSetRecoilState(
- savedBoardCardFieldsFamilyState(currentViewId),
- );
- const savedBoardCardFieldsByKey = useRecoilValue(
- savedBoardCardFieldsByKeyFamilySelector(currentViewId),
- );
-
- const [createViewFieldsMutation] = useCreateViewFieldsMutation();
- const [updateViewFieldMutation] = useUpdateViewFieldMutation();
-
- const createViewFields = (
- viewFieldDefinitions: BoardFieldDefinition[],
- viewId = currentViewId,
- ) => {
- if (!viewId || !viewFieldDefinitions.length) return;
-
- return createViewFieldsMutation({
- variables: {
- data: viewFieldDefinitions.map((field) => ({
- ...toViewFieldInput(objectId, field),
- viewId,
- })),
- },
- });
- };
-
- const updateViewFields = (
- viewFieldDefinitions: BoardFieldDefinition[],
- ) => {
- if (!currentViewId || !viewFieldDefinitions.length) return;
-
- return Promise.all(
- viewFieldDefinitions.map((field) =>
- updateViewFieldMutation({
- variables: {
- data: {
- isVisible: field.isVisible,
- },
- where: {
- viewId_key: { key: field.key, viewId: currentViewId },
- },
- },
- }),
- ),
- );
- };
-
- const { refetch } = useGetViewFieldsQuery({
- skip: !currentViewId || skipFetch,
- variables: {
- orderBy: { index: SortOrder.Asc },
- where: {
- viewId: { equals: currentViewId },
- },
- },
- onCompleted: async (data) => {
- if (!data.viewFields.length) {
- // Populate if empty
- await createViewFields(viewFieldDefinition);
- return refetch();
- }
-
- const nextFields = data.viewFields
- .map | null>((viewField) => {
- const fieldDefinition = viewFieldDefinition.find(
- ({ key }) => viewField.key === key,
- );
-
- return fieldDefinition
- ? {
- ...fieldDefinition,
- key: viewField.key,
- name: viewField.name,
- index: viewField.index,
- isVisible: viewField.isVisible,
- }
- : null;
- })
- .filter>(assertNotNull);
-
- if (!isDeeplyEqual(boardCardFields, nextFields)) {
- setSavedBoardCardFields(nextFields);
- setBoardCardFields(nextFields);
- }
-
- if (!availableBoardCardFields.length) {
- setAvailableBoardCardFields(viewFieldDefinition);
- }
- },
- });
-
- const persistCardFields = async () => {
- if (!currentViewId) return;
-
- const viewFieldsToCreate = boardCardFields.filter(
- (field) => !savedBoardCardFieldsByKey[field.key],
- );
- await createViewFields(viewFieldsToCreate);
-
- const viewFieldsToUpdate = boardCardFields.filter(
- (field) =>
- savedBoardCardFieldsByKey[field.key] &&
- savedBoardCardFieldsByKey[field.key].isVisible !== field.isVisible,
- );
- await updateViewFields(viewFieldsToUpdate);
-
- return refetch();
- };
-
- return { createViewFields, persistCardFields };
-};
diff --git a/front/src/modules/views/hooks/useBoardViews.ts b/front/src/modules/views/hooks/useBoardViews.ts
deleted file mode 100644
index 9f90283e6..000000000
--- a/front/src/modules/views/hooks/useBoardViews.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import { useSearchParams } from 'react-router-dom';
-
-import { RecoilScopeContext } from '@/types/RecoilScopeContext';
-import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
-import { useBoardColumns } from '@/ui/layout/board/hooks/useBoardColumns';
-import { boardCardFieldsScopedState } from '@/ui/layout/board/states/boardCardFieldsScopedState';
-import { BoardFieldDefinition } from '@/ui/layout/board/types/BoardFieldDefinition';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { ViewType } from '~/generated/graphql';
-
-import { useBoardViewFields } from './useBoardViewFields';
-import { useViewFilters } from './useViewFilters';
-import { useViews } from './useViews';
-import { useViewSorts } from './useViewSorts';
-
-export const useBoardViews = ({
- fieldDefinitions,
- objectId,
- RecoilScopeContext,
-}: {
- fieldDefinitions: BoardFieldDefinition[];
- objectId: 'company';
- RecoilScopeContext: RecoilScopeContext;
-}) => {
- const boardCardFields = useRecoilScopedValue(
- boardCardFieldsScopedState,
- RecoilScopeContext,
- );
- const filters = useRecoilScopedValue(filtersScopedState, RecoilScopeContext);
- const sorts = useRecoilScopedValue(sortsScopedState, RecoilScopeContext);
-
- const [_, setSearchParams] = useSearchParams();
-
- const handleViewCreate = async (viewId: string) => {
- await createViewFields(boardCardFields, viewId);
- await createViewFilters(filters, viewId);
- await createViewSorts(sorts, viewId);
- setSearchParams({ view: viewId });
- };
-
- const { createView, deleteView, isFetchingViews, updateView } = useViews({
- objectId,
- onViewCreate: handleViewCreate,
- type: ViewType.Pipeline,
- RecoilScopeContext,
- });
-
- const { createViewFields, persistCardFields } = useBoardViewFields({
- objectId,
- viewFieldDefinition: fieldDefinitions,
- skipFetch: isFetchingViews,
- RecoilScopeContext,
- });
-
- const { persistBoardColumns } = useBoardColumns();
-
- const { createViewFilters, persistFilters } = useViewFilters({
- skipFetch: isFetchingViews,
- RecoilScopeContext,
- });
-
- const { createViewSorts, persistSorts } = useViewSorts({
- skipFetch: isFetchingViews,
- RecoilScopeContext,
- });
-
- const submitCurrentView = async () => {
- await persistCardFields();
- await persistBoardColumns();
- await persistFilters();
- await persistSorts();
- };
-
- return { createView, deleteView, submitCurrentView, updateView };
-};
diff --git a/front/src/modules/views/hooks/useRemoveFilter.ts b/front/src/modules/views/hooks/useRemoveFilter.ts
new file mode 100644
index 000000000..a61abfe1b
--- /dev/null
+++ b/front/src/modules/views/hooks/useRemoveFilter.ts
@@ -0,0 +1,15 @@
+import { useView } from '@/views/hooks/useView';
+
+export const useRemoveFilter = () => {
+ const { setCurrentViewFilters } = useView();
+
+ const removeFilter = (filterKey: string) => {
+ setCurrentViewFilters?.((filters) => {
+ return filters.filter((filter) => {
+ return filter.key !== filterKey;
+ });
+ });
+ };
+
+ return removeFilter;
+};
diff --git a/front/src/modules/views/hooks/useTableViewFields.ts b/front/src/modules/views/hooks/useTableViewFields.ts
deleted file mode 100644
index 91ac2e60c..000000000
--- a/front/src/modules/views/hooks/useTableViewFields.ts
+++ /dev/null
@@ -1,183 +0,0 @@
-import { useCallback, useState } from 'react';
-import { getOperationName } from '@apollo/client/utilities';
-import { useRecoilValue, useSetRecoilState } from 'recoil';
-
-import { availableTableColumnsScopedState } from '@/ui/data/data-table/states/availableTableColumnsScopedState';
-import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { savedTableColumnsFamilyState } from '@/ui/data/data-table/states/savedTableColumnsFamilyState';
-import { savedTableColumnsByKeyFamilySelector } from '@/ui/data/data-table/states/selectors/savedTableColumnsByKeyFamilySelector';
-import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState';
-import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
-import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import {
- SortOrder,
- useCreateViewFieldsMutation,
- useGetViewFieldsQuery,
- useUpdateViewFieldMutation,
-} from '~/generated/graphql';
-import { assertNotNull } from '~/utils/assert';
-import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
-
-import { GET_VIEW_FIELDS } from '../graphql/queries/getViewFields';
-
-export const toViewFieldInput = (
- objectId: string,
- fieldDefinition: ColumnDefinition,
-) => ({
- key: fieldDefinition.key,
- name: fieldDefinition.name,
- index: fieldDefinition.index,
- isVisible: fieldDefinition.isVisible ?? true,
- objectId,
- size: fieldDefinition.size,
-});
-
-export const useTableViewFields = ({
- objectId,
- columnDefinitions,
- skipFetch,
-}: {
- objectId: string;
- columnDefinitions: ColumnDefinition[];
- skipFetch?: boolean;
-}) => {
- const currentViewId = useRecoilScopedValue(
- currentViewIdScopedState,
- TableRecoilScopeContext,
- );
- const [previousViewId, setPreviousViewId] = useState();
- const [availableTableColumns, setAvailableTableColumns] =
- useRecoilScopedState(
- availableTableColumnsScopedState,
- TableRecoilScopeContext,
- );
- const [tableColumns, setTableColumns] = useRecoilScopedState(
- tableColumnsScopedState,
- TableRecoilScopeContext,
- );
- const setSavedTableColumns = useSetRecoilState(
- savedTableColumnsFamilyState(currentViewId),
- );
- const savedTableColumnsByKey = useRecoilValue(
- savedTableColumnsByKeyFamilySelector(currentViewId),
- );
-
- const [createViewFieldsMutation] = useCreateViewFieldsMutation();
- const [updateViewFieldMutation] = useUpdateViewFieldMutation();
-
- const createViewFields = useCallback(
- (columns: ColumnDefinition[], viewId = currentViewId) => {
- if (!viewId || !columns.length) return;
-
- return createViewFieldsMutation({
- variables: {
- data: columns.map((column) => ({
- ...toViewFieldInput(objectId, column),
- viewId,
- })),
- },
- refetchQueries: [getOperationName(GET_VIEW_FIELDS) ?? ''],
- });
- },
- [createViewFieldsMutation, currentViewId, objectId],
- );
-
- const updateViewFields = useCallback(
- (columns: ColumnDefinition[]) => {
- if (!currentViewId || !columns.length) return;
-
- return Promise.all(
- columns.map((column) =>
- updateViewFieldMutation({
- variables: {
- data: {
- isVisible: column.isVisible,
- size: column.size,
- index: column.index,
- },
- where: {
- viewId_key: { key: column.key, viewId: currentViewId },
- },
- },
- }),
- ),
- );
- },
- [currentViewId, updateViewFieldMutation],
- );
-
- useGetViewFieldsQuery({
- skip: !currentViewId || skipFetch || columnDefinitions.length === 0,
- variables: {
- orderBy: { index: SortOrder.Asc },
- where: {
- viewId: { equals: currentViewId },
- },
- },
- onCompleted: async (data) => {
- if (!data.viewFields.length) {
- // Populate if empty
- return createViewFields(columnDefinitions);
- }
-
- const nextColumns = data.viewFields
- .map | null>((viewField) => {
- const columnDefinition = columnDefinitions.find(
- ({ key }) => viewField.key === key,
- );
-
- return columnDefinition
- ? {
- ...columnDefinition,
- key: viewField.key,
- name: viewField.name,
- index: viewField.index,
- size: viewField.size ?? columnDefinition.size,
- isVisible: viewField.isVisible,
- }
- : null;
- })
- .filter>(assertNotNull);
-
- setSavedTableColumns(nextColumns);
-
- if (
- previousViewId !== currentViewId &&
- !isDeeplyEqual(tableColumns, nextColumns)
- ) {
- setTableColumns(nextColumns);
- setPreviousViewId(currentViewId);
- }
-
- if (!availableTableColumns.length) {
- setAvailableTableColumns(columnDefinitions);
- }
- },
- });
-
- const persistColumns = useCallback(
- async (nextColumns: ColumnDefinition[]) => {
- if (!currentViewId) return;
-
- const viewFieldsToCreate = nextColumns.filter(
- (column) => !savedTableColumnsByKey[column.key],
- );
- await createViewFields(viewFieldsToCreate);
-
- const viewFieldsToUpdate = nextColumns.filter(
- (column) =>
- savedTableColumnsByKey[column.key] &&
- (savedTableColumnsByKey[column.key].size !== column.size ||
- savedTableColumnsByKey[column.key].index !== column.index ||
- savedTableColumnsByKey[column.key].isVisible !== column.isVisible),
- );
- await updateViewFields(viewFieldsToUpdate);
- },
- [createViewFields, currentViewId, savedTableColumnsByKey, updateViewFields],
- );
-
- return { createViewFields, persistColumns };
-};
diff --git a/front/src/modules/views/hooks/useTableViews.ts b/front/src/modules/views/hooks/useTableViews.ts
deleted file mode 100644
index 53823017c..000000000
--- a/front/src/modules/views/hooks/useTableViews.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { useSearchParams } from 'react-router-dom';
-
-import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState';
-import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
-import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import { ViewType } from '~/generated/graphql';
-
-import { useTableViewFields } from './useTableViewFields';
-import { useViewFilters } from './useViewFilters';
-import { useViews } from './useViews';
-import { useViewSorts } from './useViewSorts';
-
-export const useTableViews = ({
- objectId,
- columnDefinitions,
-}: {
- objectId: string;
- columnDefinitions: ColumnDefinition[];
-}) => {
- const tableColumns = useRecoilScopedValue(
- tableColumnsScopedState,
- TableRecoilScopeContext,
- );
- const filters = useRecoilScopedValue(
- filtersScopedState,
- TableRecoilScopeContext,
- );
- const sorts = useRecoilScopedValue(sortsScopedState, TableRecoilScopeContext);
-
- const [_, setSearchParams] = useSearchParams();
-
- const handleViewCreate = async (viewId: string) => {
- await createViewFields(tableColumns, viewId);
- await createViewFilters(filters, viewId);
- await createViewSorts(sorts, viewId);
- setSearchParams({ view: viewId });
- };
-
- const { createView, deleteView, isFetchingViews, updateView } = useViews({
- objectId,
- onViewCreate: handleViewCreate,
- type: ViewType.Table,
- RecoilScopeContext: TableRecoilScopeContext,
- });
- const { createViewFields, persistColumns } = useTableViewFields({
- objectId,
- columnDefinitions,
- skipFetch: isFetchingViews,
- });
-
- const createDefaultViewFields = async () => {
- await createViewFields(tableColumns);
- };
-
- const { createViewFilters, persistFilters } = useViewFilters({
- RecoilScopeContext: TableRecoilScopeContext,
- skipFetch: isFetchingViews,
- });
-
- const { createViewSorts, persistSorts } = useViewSorts({
- RecoilScopeContext: TableRecoilScopeContext,
- skipFetch: isFetchingViews,
- });
-
- const submitCurrentView = async () => {
- await persistFilters();
- await persistSorts();
- };
-
- return {
- createView,
- deleteView,
- persistColumns,
- submitCurrentView,
- updateView,
- createDefaultViewFields,
- isFetchingViews,
- };
-};
diff --git a/front/src/modules/ui/data/view-bar/hooks/useUpsertFilter.ts b/front/src/modules/views/hooks/useUpsertFilter.ts
similarity index 51%
rename from front/src/modules/ui/data/view-bar/hooks/useUpsertFilter.ts
rename to front/src/modules/views/hooks/useUpsertFilter.ts
index a44e6f4fd..3222c6fb5 100644
--- a/front/src/modules/ui/data/view-bar/hooks/useUpsertFilter.ts
+++ b/front/src/modules/views/hooks/useUpsertFilter.ts
@@ -1,22 +1,13 @@
import { produce } from 'immer';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-
-import { filtersScopedState } from '../states/filtersScopedState';
-import { Filter } from '../types/Filter';
-
-import { useViewBarContext } from './useViewBarContext';
+import { Filter } from '@/ui/data/filter/types/Filter';
+import { useView } from '@/views/hooks/useView';
export const useUpsertFilter = () => {
- const { ViewBarRecoilScopeContext } = useViewBarContext();
-
- const [, setFilters] = useRecoilScopedState(
- filtersScopedState,
- ViewBarRecoilScopeContext,
- );
+ const { setCurrentViewFilters } = useView();
const upsertFilter = (filterToUpsert: Filter) => {
- setFilters((filters) => {
+ setCurrentViewFilters?.((filters) => {
return produce(filters, (filtersDraft) => {
const index = filtersDraft.findIndex(
(filter) => filter.key === filterToUpsert.key,
diff --git a/front/src/modules/views/hooks/useView.ts b/front/src/modules/views/hooks/useView.ts
new file mode 100644
index 000000000..9d160681b
--- /dev/null
+++ b/front/src/modules/views/hooks/useView.ts
@@ -0,0 +1,189 @@
+import { useCallback } from 'react';
+import { useSearchParams } from 'react-router-dom';
+import { useRecoilCallback } from 'recoil';
+import { v4 } from 'uuid';
+
+import { savedTableColumnsFamilyState } from '@/ui/data/data-table/states/savedTableColumnsFamilyState';
+import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
+
+import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
+import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState';
+import { currentViewIdScopedState } from '../states/currentViewIdScopedState';
+import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState';
+import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState';
+import { viewEditModeScopedState } from '../states/viewEditModeScopedState';
+import { viewsScopedState } from '../states/viewsScopedState';
+
+import { useViewFields } from './internal/useViewFields';
+import { useViewFilters } from './internal/useViewFilters';
+import { useViews } from './internal/useViews';
+import { useViewSorts } from './internal/useViewSorts';
+import { useViewStates } from './useViewStates';
+
+type UseViewProps = {
+ viewScopeId?: string;
+};
+
+export const useView = (props?: UseViewProps) => {
+ const scopeId = useAvailableScopeIdOrThrow(
+ ViewScopeInternalContext,
+ props?.viewScopeId,
+ );
+
+ const {
+ setCurrentViewId,
+ currentViewId,
+
+ setViews,
+ setViewEditMode,
+ setViewObjectId,
+ setViewType,
+ setEntityCountInCurrentView,
+ setIsViewBarExpanded,
+
+ setAvailableSorts,
+ setCurrentViewSorts,
+ setSavedViewSorts,
+
+ setAvailableFilters,
+ setCurrentViewFilters,
+ setSavedViewFilters,
+
+ setAvailableFields,
+ setCurrentViewFields,
+ setSavedViewFields,
+ } = useViewStates(scopeId);
+
+ const { persistViewSorts, upsertViewSort } = useViewSorts(scopeId);
+ const { persistViewFilters } = useViewFilters(scopeId);
+ const { persistViewFields } = useViewFields(scopeId);
+ const { createView: internalCreateView, deleteView: internalDeleteView } =
+ useViews(scopeId);
+ const [_, setSearchParams] = useSearchParams();
+
+ const resetViewBar = useRecoilCallback(({ snapshot }) => () => {
+ const savedViewFilters = snapshot
+ .getLoadable(
+ savedViewFiltersScopedFamilyState({
+ scopeId,
+ familyKey: currentViewId || '',
+ }),
+ )
+ .getValue();
+
+ const savedViewSorts = snapshot
+ .getLoadable(
+ savedViewSortsScopedFamilyState({
+ scopeId,
+ familyKey: currentViewId || '',
+ }),
+ )
+ .getValue();
+
+ if (savedViewFilters) {
+ setCurrentViewFilters?.(savedViewFilters);
+ }
+ if (savedViewSorts) {
+ setCurrentViewSorts?.(savedViewSorts);
+ }
+ setViewEditMode?.('none');
+ setIsViewBarExpanded?.(false);
+ });
+
+ const createView = useCallback(
+ async (name: string) => {
+ const newViewId = v4();
+ await internalCreateView({ id: v4(), name });
+
+ // await persistViewFields();
+ await persistViewFilters();
+ await persistViewSorts();
+ //setCurrentViewId(newViewId);
+
+ setSearchParams({ view: newViewId });
+ },
+ [internalCreateView, persistViewFilters, persistViewSorts, setSearchParams],
+ );
+
+ const updateCurrentView = async () => {
+ await persistViewFilters();
+ await persistViewSorts();
+ };
+
+ const removeView = useRecoilCallback(
+ ({ set, snapshot }) =>
+ async (viewId: string) => {
+ const currentViewId = await snapshot.getPromise(
+ currentViewIdScopedState({ scopeId }),
+ );
+
+ if (currentViewId === viewId)
+ set(currentViewIdScopedState({ scopeId }), undefined);
+
+ set(viewsScopedState({ scopeId }), (previousViews) =>
+ previousViews.filter((view) => view.id !== viewId),
+ );
+ internalDeleteView(viewId);
+ },
+ [internalDeleteView, scopeId],
+ );
+
+ const handleViewNameSubmit = useRecoilCallback(
+ ({ snapshot, set }) =>
+ async (name?: string) => {
+ const viewEditMode = snapshot
+ .getLoadable(viewEditModeScopedState({ scopeId }))
+ .getValue();
+
+ const currentViewFields = snapshot
+ .getLoadable(
+ currentViewFieldsScopedFamilyState({
+ scopeId,
+ familyKey: currentViewId || '',
+ }),
+ )
+ .getValue();
+
+ const isCreateMode = viewEditMode === 'create';
+
+ if (isCreateMode && name && currentViewFields) {
+ await createView(name);
+ set(savedTableColumnsFamilyState(currentViewId), currentViewFields);
+ }
+ },
+ [createView, currentViewId, scopeId],
+ );
+
+ return {
+ scopeId,
+ currentViewId,
+ setCurrentViewId,
+ updateCurrentView,
+ createView,
+ removeView,
+ setIsViewBarExpanded,
+ resetViewBar,
+ handleViewNameSubmit,
+
+ setViews,
+ setViewEditMode,
+ setViewObjectId,
+ setViewType,
+ setEntityCountInCurrentView,
+
+ setAvailableSorts,
+ setCurrentViewSorts,
+ setSavedViewSorts,
+ upsertViewSort,
+
+ setAvailableFilters,
+ setCurrentViewFilters,
+ setSavedViewFilters,
+
+ setAvailableFields,
+ setCurrentViewFields,
+ setSavedViewFields,
+
+ persistViewFields,
+ };
+};
diff --git a/front/src/modules/views/hooks/useViewFilters.ts b/front/src/modules/views/hooks/useViewFilters.ts
deleted file mode 100644
index ed5563dbf..000000000
--- a/front/src/modules/views/hooks/useViewFilters.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-import { useCallback } from 'react';
-import { useRecoilState, useRecoilValue } from 'recoil';
-
-import { RecoilScopeContext } from '@/types/RecoilScopeContext';
-import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { savedFiltersFamilyState } from '@/ui/data/view-bar/states/savedFiltersFamilyState';
-import { savedFiltersByKeyFamilySelector } from '@/ui/data/view-bar/states/selectors/savedFiltersByKeyFamilySelector';
-import { Filter } from '@/ui/data/view-bar/types/Filter';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import {
- useCreateViewFiltersMutation,
- useDeleteViewFiltersMutation,
- useGetViewFiltersQuery,
- useUpdateViewFilterMutation,
-} from '~/generated/graphql';
-import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
-
-export const useViewFilters = ({
- RecoilScopeContext,
- skipFetch,
-}: {
- RecoilScopeContext: RecoilScopeContext;
- skipFetch?: boolean;
-}) => {
- const currentViewId = useRecoilScopedValue(
- currentViewIdScopedState,
- RecoilScopeContext,
- );
- const [filters, setFilters] = useRecoilScopedState(
- filtersScopedState,
- RecoilScopeContext,
- );
- const [availableFilters] = useRecoilScopedState(
- availableFiltersScopedState,
- RecoilScopeContext,
- );
- const [, setSavedFilters] = useRecoilState(
- savedFiltersFamilyState(currentViewId),
- );
- const savedFiltersByKey = useRecoilValue(
- savedFiltersByKeyFamilySelector(currentViewId),
- );
-
- const { refetch } = useGetViewFiltersQuery({
- skip: !currentViewId || skipFetch,
- variables: {
- where: {
- viewId: { equals: currentViewId },
- },
- },
- onCompleted: (data) => {
- const nextFilters = data.viewFilters
- .map(({ __typename, name: _name, ...viewFilter }) => {
- const availableFilter = availableFilters.find(
- (filter) => filter.key === viewFilter.key,
- );
-
- return availableFilter
- ? {
- ...viewFilter,
- displayValue: viewFilter.displayValue ?? viewFilter.value,
- type: availableFilter.type,
- }
- : undefined;
- })
- .filter((filter): filter is Filter => !!filter);
-
- if (!isDeeplyEqual(filters, nextFilters)) {
- setSavedFilters(nextFilters);
- setFilters(nextFilters);
- }
- },
- });
-
- const [createViewFiltersMutation] = useCreateViewFiltersMutation();
- const [updateViewFilterMutation] = useUpdateViewFilterMutation();
- const [deleteViewFiltersMutation] = useDeleteViewFiltersMutation();
-
- const createViewFilters = useCallback(
- (filters: Filter[], viewId = currentViewId) => {
- if (!viewId || !filters.length) return;
-
- return createViewFiltersMutation({
- variables: {
- data: filters.map((filter) => ({
- displayValue: filter.displayValue ?? filter.value,
- key: filter.key,
- name:
- availableFilters.find(({ key }) => key === filter.key)?.label ??
- '',
- operand: filter.operand,
- value: filter.value,
- viewId,
- })),
- },
- });
- },
- [availableFilters, createViewFiltersMutation, currentViewId],
- );
-
- const updateViewFilters = useCallback(
- (filters: Filter[]) => {
- if (!currentViewId || !filters.length) return;
-
- return Promise.all(
- filters.map((filter) =>
- updateViewFilterMutation({
- variables: {
- data: {
- displayValue: filter.displayValue ?? filter.value,
- operand: filter.operand,
- value: filter.value,
- },
- where: {
- viewId_key: { key: filter.key, viewId: currentViewId },
- },
- },
- }),
- ),
- );
- },
- [currentViewId, updateViewFilterMutation],
- );
-
- const deleteViewFilters = useCallback(
- (filterKeys: string[]) => {
- if (!currentViewId || !filterKeys.length) return;
-
- return deleteViewFiltersMutation({
- variables: {
- where: {
- key: { in: filterKeys },
- viewId: { equals: currentViewId },
- },
- },
- });
- },
- [currentViewId, deleteViewFiltersMutation],
- );
-
- const persistFilters = useCallback(async () => {
- if (!currentViewId) return;
-
- const filtersToCreate = filters.filter(
- (filter) => !savedFiltersByKey[filter.key],
- );
- await createViewFilters(filtersToCreate);
-
- const filtersToUpdate = filters.filter(
- (filter) =>
- savedFiltersByKey[filter.key] &&
- (savedFiltersByKey[filter.key].operand !== filter.operand ||
- savedFiltersByKey[filter.key].value !== filter.value),
- );
- await updateViewFilters(filtersToUpdate);
-
- const filterKeys = filters.map((filter) => filter.key);
- const filterKeysToDelete = Object.keys(savedFiltersByKey).filter(
- (previousFilterKey) => !filterKeys.includes(previousFilterKey),
- );
- await deleteViewFilters(filterKeysToDelete);
-
- return refetch();
- }, [
- currentViewId,
- filters,
- createViewFilters,
- updateViewFilters,
- savedFiltersByKey,
- deleteViewFilters,
- refetch,
- ]);
-
- return { createViewFilters, persistFilters };
-};
diff --git a/front/src/modules/views/hooks/useViewInternalStates.ts b/front/src/modules/views/hooks/useViewInternalStates.ts
new file mode 100644
index 000000000..69875d38b
--- /dev/null
+++ b/front/src/modules/views/hooks/useViewInternalStates.ts
@@ -0,0 +1,244 @@
+import { useRecoilValue } from 'recoil';
+
+import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState';
+import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
+import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
+
+import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
+import { availableFieldsScopedState } from '../states/availableFieldsScopedState';
+import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
+import { availableSortsScopedState } from '../states/availableSortsScopedState';
+import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState';
+import { currentViewFiltersScopedFamilyState } from '../states/currentViewFiltersScopedFamilyState';
+import { currentViewIdScopedState } from '../states/currentViewIdScopedState';
+import { currentViewSortsScopedFamilyState } from '../states/currentViewSortsScopedFamilyState';
+import { entityCountInCurrentViewScopedState } from '../states/entityCountInCurrentViewScopedState';
+import { isViewBarExpandedScopedState } from '../states/isViewBarExpandedScopedState';
+import { onViewFieldsChangeScopedState } from '../states/onViewFieldsChangeScopedState';
+import { onViewFiltersChangeScopedState } from '../states/onViewFiltersChangeScopedState';
+import { onViewSortsChangeScopedState } from '../states/onViewSortsChangeScopedState';
+import { savedViewFieldsScopedFamilyState } from '../states/savedViewFieldsScopedFamilyState';
+import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState';
+import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState';
+import { canPersistViewFiltersScopedFamilySelector } from '../states/selectors/canPersistViewFiltersScopedFamilySelector';
+import { canPersistViewSortsScopedFamilySelector } from '../states/selectors/canPersistViewSortsScopedFamilySelector';
+import { currentViewScopedSelector } from '../states/selectors/currentViewScopedSelector';
+import { currentViewSortsOrderByScopedFamilySelector } from '../states/selectors/currentViewSortsOrderByScopedFamilySelector';
+import { savedViewFieldByKeyScopedFamilySelector } from '../states/selectors/savedViewFieldByKeyScopedFamilySelector';
+import { savedViewFiltersByKeyScopedFamilySelector } from '../states/selectors/savedViewFiltersByKeyScopedFamilySelector';
+import { savedViewSortsByKeyScopedFamilySelector } from '../states/selectors/savedViewSortsByKeyScopedFamilySelector';
+import { viewEditModeScopedState } from '../states/viewEditModeScopedState';
+import { viewObjectIdScopeState } from '../states/viewObjectIdScopeState';
+import { viewsScopedState } from '../states/viewsScopedState';
+import { viewTypeScopedState } from '../states/viewTypeScopedState';
+
+export const useViewInternalStates = (
+ viewScopeId?: string,
+ viewId?: string,
+) => {
+ const scopeId = useAvailableScopeIdOrThrow(
+ ViewScopeInternalContext,
+ viewScopeId,
+ );
+
+ // View
+ const [currentViewId, setCurrentViewId] = useRecoilScopedStateV2(
+ currentViewIdScopedState,
+ scopeId,
+ );
+
+ const familyItemId = viewId ? viewId : currentViewId;
+
+ const currentView = useRecoilValue(currentViewScopedSelector(scopeId));
+
+ const [viewEditMode, setViewEditMode] = useRecoilScopedStateV2(
+ viewEditModeScopedState,
+ scopeId,
+ );
+
+ const [views, setViews] = useRecoilScopedStateV2(viewsScopedState, scopeId);
+
+ const [viewObjectId, setViewObjectId] = useRecoilScopedStateV2(
+ viewObjectIdScopeState,
+ scopeId,
+ );
+
+ const [viewType, setViewType] = useRecoilScopedStateV2(
+ viewTypeScopedState,
+ scopeId,
+ );
+
+ const [entityCountInCurrentView, setEntityCountInCurrentView] =
+ useRecoilScopedStateV2(entityCountInCurrentViewScopedState, scopeId);
+
+ const [isViewBarExpanded, setIsViewBarExpanded] = useRecoilScopedStateV2(
+ isViewBarExpandedScopedState,
+ scopeId,
+ );
+
+ // ViewSorts
+ const [currentViewSorts, setCurrentViewSorts] = useRecoilScopedFamilyState(
+ currentViewSortsScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const [savedViewSorts, setSavedViewSorts] = useRecoilScopedFamilyState(
+ savedViewSortsScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const savedViewSortsByKey = useRecoilValue(
+ savedViewSortsByKeyScopedFamilySelector({
+ scopeId: scopeId,
+ viewId: familyItemId,
+ }),
+ );
+
+ const [availableSorts, setAvailableSorts] = useRecoilScopedStateV2(
+ availableSortsScopedState,
+ scopeId,
+ );
+
+ const canPersistSorts = useRecoilValue(
+ canPersistViewSortsScopedFamilySelector({
+ viewScopeId: scopeId,
+ viewId: familyItemId,
+ }),
+ );
+
+ const currentViewSortsOrderBy = useRecoilValue(
+ currentViewSortsOrderByScopedFamilySelector({
+ viewScopeId: scopeId,
+ viewId: familyItemId,
+ }),
+ );
+
+ // ViewFilters
+ const [currentViewFilters, setCurrentViewFilters] =
+ useRecoilScopedFamilyState(
+ currentViewFiltersScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const [savedViewFilters, setSavedViewFilters] = useRecoilScopedFamilyState(
+ savedViewFiltersScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const savedViewFiltersByKey = useRecoilValue(
+ savedViewFiltersByKeyScopedFamilySelector({
+ scopeId: scopeId,
+ viewId: familyItemId,
+ }),
+ );
+
+ const [availableFilters, setAvailableFilters] = useRecoilScopedStateV2(
+ availableFiltersScopedState,
+ scopeId,
+ );
+
+ const canPersistFilters = useRecoilValue(
+ canPersistViewFiltersScopedFamilySelector({
+ viewScopeId: scopeId,
+ viewId: familyItemId,
+ }),
+ );
+
+ // ViewFields
+ const [availableFields, setAvailableFields] = useRecoilScopedStateV2(
+ availableFieldsScopedState,
+ scopeId,
+ );
+
+ const [currentViewFields, setCurrentViewFields] = useRecoilScopedFamilyState(
+ currentViewFieldsScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const [savedViewFields, setSavedViewFields] = useRecoilScopedFamilyState(
+ savedViewFieldsScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const savedViewFieldsByKey = useRecoilValue(
+ savedViewFieldByKeyScopedFamilySelector({
+ viewScopeId: scopeId,
+ viewId: familyItemId,
+ }),
+ );
+
+ // ViewChangeHandlers
+ const [onViewSortsChange, setOnViewSortsChange] = useRecoilScopedStateV2(
+ onViewSortsChangeScopedState,
+ scopeId,
+ );
+
+ const [onViewFiltersChange, setOnViewFiltersChange] = useRecoilScopedStateV2(
+ onViewFiltersChangeScopedState,
+ scopeId,
+ );
+
+ const [onViewFieldsChange, setOnViewFieldsChange] = useRecoilScopedStateV2(
+ onViewFieldsChangeScopedState,
+ scopeId,
+ );
+
+ return {
+ currentViewId,
+ currentView,
+ setCurrentViewId,
+ isViewBarExpanded,
+ setIsViewBarExpanded,
+
+ views,
+ setViews,
+ viewEditMode,
+ setViewEditMode,
+ viewObjectId,
+ setViewObjectId,
+ viewType,
+ setViewType,
+ entityCountInCurrentView,
+ setEntityCountInCurrentView,
+
+ availableSorts,
+ setAvailableSorts,
+ currentViewSorts,
+ setCurrentViewSorts,
+ savedViewSorts,
+ savedViewSortsByKey,
+ setSavedViewSorts,
+ canPersistSorts,
+ currentViewSortsOrderBy,
+
+ availableFilters,
+ setAvailableFilters,
+ currentViewFilters,
+ setCurrentViewFilters,
+ savedViewFilters,
+ savedViewFiltersByKey,
+ setSavedViewFilters,
+ canPersistFilters,
+
+ availableFields,
+ setAvailableFields,
+ currentViewFields,
+ savedViewFieldsByKey,
+ setCurrentViewFields,
+ savedViewFields,
+ setSavedViewFields,
+
+ onViewSortsChange,
+ setOnViewSortsChange,
+ onViewFiltersChange,
+ setOnViewFiltersChange,
+ onViewFieldsChange,
+ setOnViewFieldsChange,
+ };
+};
diff --git a/front/src/modules/views/hooks/useViewSorts.ts b/front/src/modules/views/hooks/useViewSorts.ts
deleted file mode 100644
index dcb13ae27..000000000
--- a/front/src/modules/views/hooks/useViewSorts.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-import { useCallback } from 'react';
-import { useRecoilState, useRecoilValue } from 'recoil';
-
-import { RecoilScopeContext } from '@/types/RecoilScopeContext';
-import { availableSortsScopedState } from '@/ui/data/view-bar/states/availableSortsScopedState';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { savedSortsFamilyState } from '@/ui/data/view-bar/states/savedSortsFamilyState';
-import { savedSortsByKeyFamilySelector } from '@/ui/data/view-bar/states/selectors/savedSortsByKeyFamilySelector';
-import { sortsScopedState } from '@/ui/data/view-bar/states/sortsScopedState';
-import { Sort } from '@/ui/data/view-bar/types/Sort';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
-import {
- useCreateViewSortsMutation,
- useDeleteViewSortsMutation,
- useGetViewSortsQuery,
- useUpdateViewSortMutation,
- ViewSortDirection,
-} from '~/generated/graphql';
-import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
-
-export const useViewSorts = ({
- RecoilScopeContext,
- skipFetch,
-}: {
- RecoilScopeContext: RecoilScopeContext;
- skipFetch?: boolean;
-}) => {
- const currentViewId = useRecoilScopedValue(
- currentViewIdScopedState,
- RecoilScopeContext,
- );
- const [sorts, setSorts] = useRecoilScopedState(
- sortsScopedState,
- RecoilScopeContext,
- );
- const [availableSorts] = useRecoilScopedState(
- availableSortsScopedState,
- RecoilScopeContext,
- );
- const [, setSavedSorts] = useRecoilState(
- savedSortsFamilyState(currentViewId),
- );
- const savedSortsByKey = useRecoilValue(
- savedSortsByKeyFamilySelector(currentViewId),
- );
-
- const { refetch } = useGetViewSortsQuery({
- skip: !currentViewId || skipFetch,
- variables: {
- where: {
- viewId: { equals: currentViewId },
- },
- },
- onCompleted: (data) => {
- const nextSorts = data.viewSorts
- .map((viewSort) => {
- const foundCorrespondingSortDefinition = availableSorts.find(
- (sort) => sort.key === viewSort.key,
- );
-
- if (foundCorrespondingSortDefinition) {
- return {
- key: viewSort.key,
- definition: foundCorrespondingSortDefinition,
- direction: viewSort.direction.toLowerCase(),
- } as Sort;
- } else {
- return undefined;
- }
- })
- .filter((sort): sort is Sort => !!sort);
-
- if (!isDeeplyEqual(sorts, nextSorts)) {
- setSavedSorts(nextSorts);
- setSorts(nextSorts);
- }
- },
- });
-
- const [createViewSortsMutation] = useCreateViewSortsMutation();
- const [updateViewSortMutation] = useUpdateViewSortMutation();
- const [deleteViewSortsMutation] = useDeleteViewSortsMutation();
-
- const createViewSorts = useCallback(
- (sorts: Sort[], viewId = currentViewId) => {
- if (!viewId || !sorts.length) return;
-
- return createViewSortsMutation({
- variables: {
- data: sorts.map((sort) => ({
- key: sort.key,
- direction: sort.direction as ViewSortDirection,
- name: sort.definition.label,
- viewId,
- })),
- },
- });
- },
- [createViewSortsMutation, currentViewId],
- );
-
- const updateViewSorts = useCallback(
- (sorts: Sort[]) => {
- if (!currentViewId || !sorts.length) return;
-
- return Promise.all(
- sorts.map((sort) =>
- updateViewSortMutation({
- variables: {
- data: {
- direction: sort.direction as ViewSortDirection,
- },
- where: {
- viewId_key: { key: sort.key, viewId: currentViewId },
- },
- },
- }),
- ),
- );
- },
- [currentViewId, updateViewSortMutation],
- );
-
- const deleteViewSorts = useCallback(
- (sortKeys: string[]) => {
- if (!currentViewId || !sortKeys.length) return;
-
- return deleteViewSortsMutation({
- variables: {
- where: {
- key: { in: sortKeys },
- viewId: { equals: currentViewId },
- },
- },
- });
- },
- [currentViewId, deleteViewSortsMutation],
- );
-
- const persistSorts = useCallback(async () => {
- if (!currentViewId) return;
-
- const sortsToCreate = sorts.filter((sort) => !savedSortsByKey[sort.key]);
- await createViewSorts(sortsToCreate);
-
- const sortsToUpdate = sorts.filter(
- (sort) =>
- savedSortsByKey[sort.key] &&
- savedSortsByKey[sort.key].direction !== sort.direction,
- );
- await updateViewSorts(sortsToUpdate);
-
- const sortKeys = sorts.map((sort) => sort.key);
- const sortKeysToDelete = Object.keys(savedSortsByKey).filter(
- (previousSortKey) => !sortKeys.includes(previousSortKey),
- );
- await deleteViewSorts(sortKeysToDelete);
-
- return refetch();
- }, [
- currentViewId,
- sorts,
- createViewSorts,
- updateViewSorts,
- savedSortsByKey,
- deleteViewSorts,
- refetch,
- ]);
-
- return { createViewSorts, persistSorts };
-};
diff --git a/front/src/modules/views/hooks/useViewStates.ts b/front/src/modules/views/hooks/useViewStates.ts
new file mode 100644
index 000000000..8378b92a6
--- /dev/null
+++ b/front/src/modules/views/hooks/useViewStates.ts
@@ -0,0 +1,138 @@
+import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
+import { useSetRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useSetRecoilScopedFamilyState';
+import { useSetRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useSetRecoilScopedStateV2';
+import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
+
+import { ViewScopeInternalContext } from '../scopes/scope-internal-context/ViewScopeInternalContext';
+import { availableFieldsScopedState } from '../states/availableFieldsScopedState';
+import { availableFiltersScopedState } from '../states/availableFiltersScopedState';
+import { availableSortsScopedState } from '../states/availableSortsScopedState';
+import { currentViewFieldsScopedFamilyState } from '../states/currentViewFieldsScopedFamilyState';
+import { currentViewFiltersScopedFamilyState } from '../states/currentViewFiltersScopedFamilyState';
+import { currentViewIdScopedState } from '../states/currentViewIdScopedState';
+import { currentViewSortsScopedFamilyState } from '../states/currentViewSortsScopedFamilyState';
+import { entityCountInCurrentViewScopedState } from '../states/entityCountInCurrentViewScopedState';
+import { isViewBarExpandedScopedState } from '../states/isViewBarExpandedScopedState';
+import { savedViewFieldsScopedFamilyState } from '../states/savedViewFieldsScopedFamilyState';
+import { savedViewFiltersScopedFamilyState } from '../states/savedViewFiltersScopedFamilyState';
+import { savedViewSortsScopedFamilyState } from '../states/savedViewSortsScopedFamilyState';
+import { viewEditModeScopedState } from '../states/viewEditModeScopedState';
+import { viewObjectIdScopeState } from '../states/viewObjectIdScopeState';
+import { viewsScopedState } from '../states/viewsScopedState';
+import { viewTypeScopedState } from '../states/viewTypeScopedState';
+
+export const useViewStates = (viewScopeId?: string, viewId?: string) => {
+ const scopeId = useAvailableScopeIdOrThrow(
+ ViewScopeInternalContext,
+ viewScopeId,
+ );
+ // View
+ const [currentViewId, setCurrentViewId] = useRecoilScopedStateV2(
+ currentViewIdScopedState,
+ scopeId,
+ );
+
+ const familyItemId = viewId ? viewId : currentViewId;
+
+ const setViewEditMode = useSetRecoilScopedStateV2(
+ viewEditModeScopedState,
+ scopeId,
+ );
+
+ const setViews = useSetRecoilScopedStateV2(viewsScopedState, scopeId);
+
+ const setViewObjectId = useSetRecoilScopedStateV2(
+ viewObjectIdScopeState,
+ scopeId,
+ );
+
+ const setViewType = useSetRecoilScopedStateV2(viewTypeScopedState, scopeId);
+
+ const setEntityCountInCurrentView = useSetRecoilScopedStateV2(
+ entityCountInCurrentViewScopedState,
+ scopeId,
+ );
+
+ const setIsViewBarExpanded = useSetRecoilScopedStateV2(
+ isViewBarExpandedScopedState,
+ scopeId,
+ );
+
+ // ViewSorts
+ const setCurrentViewSorts = useSetRecoilScopedFamilyState(
+ currentViewSortsScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const setSavedViewSorts = useSetRecoilScopedFamilyState(
+ savedViewSortsScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const setAvailableSorts = useSetRecoilScopedStateV2(
+ availableSortsScopedState,
+ scopeId,
+ );
+
+ // ViewFilters
+ const setCurrentViewFilters = useSetRecoilScopedFamilyState(
+ currentViewFiltersScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const setSavedViewFilters = useSetRecoilScopedFamilyState(
+ savedViewFiltersScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const setAvailableFilters = useSetRecoilScopedStateV2(
+ availableFiltersScopedState,
+ scopeId,
+ );
+
+ // ViewFields
+ const setAvailableFields = useSetRecoilScopedStateV2(
+ availableFieldsScopedState,
+ scopeId,
+ );
+
+ const setCurrentViewFields = useSetRecoilScopedFamilyState(
+ currentViewFieldsScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ const setSavedViewFields = useSetRecoilScopedFamilyState(
+ savedViewFieldsScopedFamilyState,
+ scopeId,
+ familyItemId,
+ );
+
+ return {
+ currentViewId,
+ setCurrentViewId,
+ setIsViewBarExpanded,
+
+ setViews,
+ setViewEditMode,
+ setViewObjectId,
+ setViewType,
+ setEntityCountInCurrentView,
+
+ setAvailableSorts,
+ setCurrentViewSorts,
+ setSavedViewSorts,
+
+ setAvailableFilters,
+ setCurrentViewFilters,
+ setSavedViewFilters,
+
+ setAvailableFields,
+ setCurrentViewFields,
+ setSavedViewFields,
+ };
+};
diff --git a/front/src/modules/views/hooks/useViews.ts b/front/src/modules/views/hooks/useViews.ts
deleted file mode 100644
index c84f84b2a..000000000
--- a/front/src/modules/views/hooks/useViews.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import { getOperationName } from '@apollo/client/utilities';
-
-import { RecoilScopeContext } from '@/types/RecoilScopeContext';
-import { currentViewIdScopedState } from '@/ui/data/view-bar/states/currentViewIdScopedState';
-import { viewsScopedState } from '@/ui/data/view-bar/states/viewsScopedState';
-import { View } from '@/ui/data/view-bar/types/View';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
-import {
- useCreateViewMutation,
- useDeleteViewMutation,
- useGetViewsQuery,
- useUpdateViewMutation,
- ViewType,
-} from '~/generated/graphql';
-import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
-
-import { GET_VIEWS } from '../graphql/queries/getViews';
-
-export const useViews = ({
- objectId,
- onViewCreate,
- RecoilScopeContext,
- type,
-}: {
- objectId: string;
- onViewCreate?: (viewId: string) => Promise;
- RecoilScopeContext: RecoilScopeContext;
- type: ViewType;
-}) => {
- const [currentViewId, setCurrentViewId] = useRecoilScopedState(
- currentViewIdScopedState,
- RecoilScopeContext,
- );
- const [views, setViews] = useRecoilScopedState(
- viewsScopedState,
- RecoilScopeContext,
- );
-
- const [createViewMutation] = useCreateViewMutation();
- const [updateViewMutation] = useUpdateViewMutation();
- const [deleteViewMutation] = useDeleteViewMutation();
-
- const createView = async (view: View) => {
- const { data } = await createViewMutation({
- variables: {
- data: {
- ...view,
- objectId,
- type,
- },
- },
- refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
- });
-
- if (data?.view) await onViewCreate?.(data.view.id);
- };
-
- const updateView = async (view: View) => {
- await updateViewMutation({
- variables: {
- data: { name: view.name },
- where: { id: view.id },
- },
- refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
- });
- };
-
- const deleteView = async (viewId: string) => {
- await deleteViewMutation({
- variables: { where: { id: viewId } },
- refetchQueries: [getOperationName(GET_VIEWS) ?? ''],
- });
- };
-
- const { loading } = useGetViewsQuery({
- variables: {
- where: {
- objectId: { equals: objectId },
- type: { equals: type },
- },
- },
- onCompleted: (data) => {
- const nextViews = data.views.map((view) => ({
- id: view.id,
- name: view.name,
- }));
-
- if (!isDeeplyEqual(views, nextViews)) setViews(nextViews);
-
- if (!nextViews.length) return;
-
- if (!currentViewId) return setCurrentViewId(nextViews[0].id);
- },
- });
-
- return {
- createView,
- deleteView,
- isFetchingViews: loading,
- updateView,
- };
-};
diff --git a/front/src/modules/views/scopes/ViewScope.tsx b/front/src/modules/views/scopes/ViewScope.tsx
new file mode 100644
index 000000000..936dbcec4
--- /dev/null
+++ b/front/src/modules/views/scopes/ViewScope.tsx
@@ -0,0 +1,43 @@
+import { ReactNode } from 'react';
+
+import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
+import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
+import { Filter } from '@/ui/data/filter/types/Filter';
+import { Sort } from '@/ui/data/sort/types/Sort';
+
+import { ViewScopeInitEffect } from './init-effect/ViewScopeInitEffect';
+import { ViewScopeInternalContext } from './scope-internal-context/ViewScopeInternalContext';
+
+type ViewScopeProps = {
+ children: ReactNode;
+ viewScopeId: string;
+ onViewSortsChange?: (sorts: Sort[]) => void | Promise;
+ onViewFiltersChange?: (filters: Filter[]) => void | Promise;
+ onViewFieldsChange?: (
+ fields: ColumnDefinition[],
+ ) => void | Promise;
+};
+
+export const ViewScope = ({
+ children,
+ viewScopeId,
+ onViewSortsChange,
+ onViewFiltersChange,
+ onViewFieldsChange,
+}: ViewScopeProps) => {
+ return (
+
+
+ {children}
+
+ );
+};
diff --git a/front/src/modules/views/scopes/init-effect/ViewScopeInitEffect.tsx b/front/src/modules/views/scopes/init-effect/ViewScopeInitEffect.tsx
new file mode 100644
index 000000000..f2864390b
--- /dev/null
+++ b/front/src/modules/views/scopes/init-effect/ViewScopeInitEffect.tsx
@@ -0,0 +1,46 @@
+import { useEffect } from 'react';
+
+import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
+import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
+import { Filter } from '@/ui/data/filter/types/Filter';
+import { Sort } from '@/ui/data/sort/types/Sort';
+import { useView } from '@/views/hooks/useView';
+import { useViewInternalStates } from '@/views/hooks/useViewInternalStates';
+
+type ViewScopeInitEffectProps = {
+ viewScopeId: string;
+ onViewSortsChange?: (sorts: Sort[]) => void | Promise;
+ onViewFiltersChange?: (filters: Filter[]) => void | Promise;
+ onViewFieldsChange?: (
+ fields: ColumnDefinition[],
+ ) => void | Promise;
+};
+
+export const ViewScopeInitEffect = ({
+ viewScopeId,
+ onViewSortsChange,
+ onViewFiltersChange,
+ onViewFieldsChange,
+}: ViewScopeInitEffectProps) => {
+ const { currentViewId } = useView();
+ const {
+ setOnViewSortsChange,
+ setOnViewFieldsChange,
+ setOnViewFiltersChange,
+ } = useViewInternalStates(viewScopeId, currentViewId);
+
+ useEffect(() => {
+ setOnViewSortsChange(onViewSortsChange);
+ setOnViewFiltersChange(onViewFiltersChange);
+ setOnViewFieldsChange(onViewFieldsChange);
+ }, [
+ onViewFieldsChange,
+ onViewFiltersChange,
+ onViewSortsChange,
+ setOnViewFieldsChange,
+ setOnViewFiltersChange,
+ setOnViewSortsChange,
+ ]);
+
+ return <>>;
+};
diff --git a/front/src/modules/views/scopes/scope-internal-context/ViewScopeInternalContext.ts b/front/src/modules/views/scopes/scope-internal-context/ViewScopeInternalContext.ts
new file mode 100644
index 000000000..18824dc99
--- /dev/null
+++ b/front/src/modules/views/scopes/scope-internal-context/ViewScopeInternalContext.ts
@@ -0,0 +1,7 @@
+import { ScopedStateKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/ScopedStateKey';
+import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
+
+type ViewScopeInternalContextProps = ScopedStateKey;
+
+export const ViewScopeInternalContext =
+ createScopeInternalContext();
diff --git a/front/src/modules/views/states/availableFieldsScopedState.ts b/front/src/modules/views/states/availableFieldsScopedState.ts
new file mode 100644
index 000000000..74bddf8f6
--- /dev/null
+++ b/front/src/modules/views/states/availableFieldsScopedState.ts
@@ -0,0 +1,10 @@
+import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
+import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const availableFieldsScopedState = createScopedState<
+ ColumnDefinition[]
+>({
+ key: 'availableFieldsScopedState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/availableFiltersScopedState.ts b/front/src/modules/views/states/availableFiltersScopedState.ts
new file mode 100644
index 000000000..9c38f3952
--- /dev/null
+++ b/front/src/modules/views/states/availableFiltersScopedState.ts
@@ -0,0 +1,9 @@
+import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const availableFiltersScopedState = createScopedState<
+ FilterDefinition[]
+>({
+ key: 'availableFiltersScopedState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/availableSortsScopedState.ts b/front/src/modules/views/states/availableSortsScopedState.ts
new file mode 100644
index 000000000..e5aa10d0d
--- /dev/null
+++ b/front/src/modules/views/states/availableSortsScopedState.ts
@@ -0,0 +1,7 @@
+import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const availableSortsScopedState = createScopedState({
+ key: 'availableSortsScopedState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/currentViewFieldsScopedFamilyState.ts b/front/src/modules/views/states/currentViewFieldsScopedFamilyState.ts
new file mode 100644
index 000000000..2b8ea0d5a
--- /dev/null
+++ b/front/src/modules/views/states/currentViewFieldsScopedFamilyState.ts
@@ -0,0 +1,11 @@
+import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
+import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
+import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
+
+export const currentViewFieldsScopedFamilyState = createScopedFamilyState<
+ ColumnDefinition[],
+ string
+>({
+ key: 'currentViewFieldsScopedFamilyState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/currentViewFiltersScopedFamilyState.ts b/front/src/modules/views/states/currentViewFiltersScopedFamilyState.ts
new file mode 100644
index 000000000..4e0ac6a08
--- /dev/null
+++ b/front/src/modules/views/states/currentViewFiltersScopedFamilyState.ts
@@ -0,0 +1,10 @@
+import { Filter } from '@/ui/data/filter/types/Filter';
+import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
+
+export const currentViewFiltersScopedFamilyState = createScopedFamilyState<
+ Filter[],
+ string
+>({
+ key: 'currentViewFiltersScopedFamilyState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/currentViewIdScopedState.ts b/front/src/modules/views/states/currentViewIdScopedState.ts
new file mode 100644
index 000000000..748d3c04c
--- /dev/null
+++ b/front/src/modules/views/states/currentViewIdScopedState.ts
@@ -0,0 +1,6 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const currentViewIdScopedState = createScopedState({
+ key: 'currentViewIdScopedState',
+ defaultValue: undefined,
+});
diff --git a/front/src/modules/views/states/currentViewSortsScopedFamilyState.ts b/front/src/modules/views/states/currentViewSortsScopedFamilyState.ts
new file mode 100644
index 000000000..70ef8ec8d
--- /dev/null
+++ b/front/src/modules/views/states/currentViewSortsScopedFamilyState.ts
@@ -0,0 +1,10 @@
+import { Sort } from '@/ui/data/sort/types/Sort';
+import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
+
+export const currentViewSortsScopedFamilyState = createScopedFamilyState<
+ Sort[],
+ string
+>({
+ key: 'currentViewSortsScopedFamilyState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/entityCountInCurrentViewScopedState.ts b/front/src/modules/views/states/entityCountInCurrentViewScopedState.ts
new file mode 100644
index 000000000..837cac87b
--- /dev/null
+++ b/front/src/modules/views/states/entityCountInCurrentViewScopedState.ts
@@ -0,0 +1,6 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const entityCountInCurrentViewScopedState = createScopedState({
+ key: 'entityCountInCurrentViewScopedState',
+ defaultValue: 0,
+});
diff --git a/front/src/modules/views/states/isViewBarExpandedScopedState.ts b/front/src/modules/views/states/isViewBarExpandedScopedState.ts
new file mode 100644
index 000000000..c51fd165c
--- /dev/null
+++ b/front/src/modules/views/states/isViewBarExpandedScopedState.ts
@@ -0,0 +1,6 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const isViewBarExpandedScopedState = createScopedState({
+ key: 'isViewBarExpandedScopedState',
+ defaultValue: true,
+});
diff --git a/front/src/modules/views/states/noneScopedFamilyState.ts b/front/src/modules/views/states/noneScopedFamilyState.ts
new file mode 100644
index 000000000..feeacd214
--- /dev/null
+++ b/front/src/modules/views/states/noneScopedFamilyState.ts
@@ -0,0 +1,6 @@
+import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
+
+export const noneScopedFamilyState = createScopedFamilyState({
+ key: 'noneScopedFamilyState',
+ defaultValue: null,
+});
diff --git a/front/src/modules/views/states/onViewFieldsChangeScopedState.ts b/front/src/modules/views/states/onViewFieldsChangeScopedState.ts
new file mode 100644
index 000000000..22a39235b
--- /dev/null
+++ b/front/src/modules/views/states/onViewFieldsChangeScopedState.ts
@@ -0,0 +1,11 @@
+import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
+import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const onViewFieldsChangeScopedState = createScopedState<
+ | ((fields: ColumnDefinition[]) => void | Promise)
+ | undefined
+>({
+ key: 'onViewFieldsChangeScopedState',
+ defaultValue: undefined,
+});
diff --git a/front/src/modules/views/states/onViewFiltersChangeScopedState.ts b/front/src/modules/views/states/onViewFiltersChangeScopedState.ts
new file mode 100644
index 000000000..907281cd0
--- /dev/null
+++ b/front/src/modules/views/states/onViewFiltersChangeScopedState.ts
@@ -0,0 +1,9 @@
+import { Filter } from '@/ui/data/filter/types/Filter';
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const onViewFiltersChangeScopedState = createScopedState<
+ ((filters: Filter[]) => void | Promise) | undefined
+>({
+ key: 'onViewFiltersChangeScopedState',
+ defaultValue: undefined,
+});
diff --git a/front/src/modules/views/states/onViewSortsChangeScopedState.ts b/front/src/modules/views/states/onViewSortsChangeScopedState.ts
new file mode 100644
index 000000000..348ba0d70
--- /dev/null
+++ b/front/src/modules/views/states/onViewSortsChangeScopedState.ts
@@ -0,0 +1,9 @@
+import { Sort } from '@/ui/data/sort/types/Sort';
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const onViewSortsChangeScopedState = createScopedState<
+ ((sorts: Sort[]) => void | Promise) | undefined
+>({
+ key: 'onViewSortsChangeScopedState',
+ defaultValue: undefined,
+});
diff --git a/front/src/modules/views/states/savedViewFieldsScopedFamilyState.ts b/front/src/modules/views/states/savedViewFieldsScopedFamilyState.ts
new file mode 100644
index 000000000..c666844b4
--- /dev/null
+++ b/front/src/modules/views/states/savedViewFieldsScopedFamilyState.ts
@@ -0,0 +1,11 @@
+import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
+import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
+import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
+
+export const savedViewFieldsScopedFamilyState = createScopedFamilyState<
+ ColumnDefinition[],
+ string
+>({
+ key: 'savedViewFieldsScopedFamilyState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/savedViewFiltersScopedFamilyState.ts b/front/src/modules/views/states/savedViewFiltersScopedFamilyState.ts
new file mode 100644
index 000000000..7b6d8ccd9
--- /dev/null
+++ b/front/src/modules/views/states/savedViewFiltersScopedFamilyState.ts
@@ -0,0 +1,10 @@
+import { Filter } from '@/ui/data/filter/types/Filter';
+import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
+
+export const savedViewFiltersScopedFamilyState = createScopedFamilyState<
+ Filter[],
+ string
+>({
+ key: 'savedViewFiltersScopedFamilyState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/savedViewSortsScopedFamilyState.ts b/front/src/modules/views/states/savedViewSortsScopedFamilyState.ts
new file mode 100644
index 000000000..1b20c4c23
--- /dev/null
+++ b/front/src/modules/views/states/savedViewSortsScopedFamilyState.ts
@@ -0,0 +1,10 @@
+import { Sort } from '@/ui/data/sort/types/Sort';
+import { createScopedFamilyState } from '@/ui/utilities/recoil-scope/utils/createScopedFamilyState';
+
+export const savedViewSortsScopedFamilyState = createScopedFamilyState<
+ Sort[],
+ string
+>({
+ key: 'savedViewSortsScopedFamilyState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/views/states/selectors/canPersistViewFiltersScopedFamilySelector.ts b/front/src/modules/views/states/selectors/canPersistViewFiltersScopedFamilySelector.ts
new file mode 100644
index 000000000..cd51040c6
--- /dev/null
+++ b/front/src/modules/views/states/selectors/canPersistViewFiltersScopedFamilySelector.ts
@@ -0,0 +1,31 @@
+import { selectorFamily } from 'recoil';
+
+import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
+
+import { currentViewFiltersScopedFamilyState } from '../currentViewFiltersScopedFamilyState';
+import { savedViewFiltersScopedFamilyState } from '../savedViewFiltersScopedFamilyState';
+
+export const canPersistViewFiltersScopedFamilySelector = selectorFamily({
+ key: 'canPersistFiltersScopedFamilySelector',
+ get:
+ ({ viewScopeId, viewId }: { viewScopeId: string; viewId?: string }) =>
+ ({ get }) => {
+ if (!viewId) {
+ return;
+ }
+ return !isDeeplyEqual(
+ get(
+ savedViewFiltersScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: viewId,
+ }),
+ ),
+ get(
+ currentViewFiltersScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: viewId,
+ }),
+ ),
+ );
+ },
+});
diff --git a/front/src/modules/views/states/selectors/canPersistViewSortsScopedFamilySelector.ts b/front/src/modules/views/states/selectors/canPersistViewSortsScopedFamilySelector.ts
new file mode 100644
index 000000000..37020a7d1
--- /dev/null
+++ b/front/src/modules/views/states/selectors/canPersistViewSortsScopedFamilySelector.ts
@@ -0,0 +1,31 @@
+import { selectorFamily } from 'recoil';
+
+import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
+
+import { currentViewSortsScopedFamilyState } from '../currentViewSortsScopedFamilyState';
+import { savedViewSortsScopedFamilyState } from '../savedViewSortsScopedFamilyState';
+
+export const canPersistViewSortsScopedFamilySelector = selectorFamily({
+ key: 'canPersistSortsScopedFamilySelector',
+ get:
+ ({ viewScopeId, viewId }: { viewScopeId: string; viewId?: string }) =>
+ ({ get }) => {
+ if (!viewId) {
+ return;
+ }
+ return !isDeeplyEqual(
+ get(
+ savedViewSortsScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: viewId,
+ }),
+ ),
+ get(
+ currentViewSortsScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: viewId,
+ }),
+ ),
+ );
+ },
+});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/currentViewScopedSelector.ts b/front/src/modules/views/states/selectors/currentViewScopedSelector.ts
similarity index 79%
rename from front/src/modules/ui/data/view-bar/states/selectors/currentViewScopedSelector.ts
rename to front/src/modules/views/states/selectors/currentViewScopedSelector.ts
index 82f826aa0..c1606d2c0 100644
--- a/front/src/modules/ui/data/view-bar/states/selectors/currentViewScopedSelector.ts
+++ b/front/src/modules/views/states/selectors/currentViewScopedSelector.ts
@@ -1,6 +1,7 @@
import { selectorFamily } from 'recoil';
-import { View } from '../../types/View';
+import { View } from '@/views/types/View';
+
import { currentViewIdScopedState } from '../currentViewIdScopedState';
import { viewsByIdScopedSelector } from './viewsByIdScopedSelector';
@@ -13,7 +14,7 @@ export const currentViewScopedSelector = selectorFamily<
get:
(scopeId) =>
({ get }) => {
- const currentViewId = get(currentViewIdScopedState(scopeId));
+ const currentViewId = get(currentViewIdScopedState({ scopeId: scopeId }));
return currentViewId
? get(viewsByIdScopedSelector(scopeId))[currentViewId]
: undefined;
diff --git a/front/src/modules/views/states/selectors/currentViewSortsOrderByScopedFamilySelector.ts b/front/src/modules/views/states/selectors/currentViewSortsOrderByScopedFamilySelector.ts
new file mode 100644
index 000000000..02d3c90d1
--- /dev/null
+++ b/front/src/modules/views/states/selectors/currentViewSortsOrderByScopedFamilySelector.ts
@@ -0,0 +1,26 @@
+import { selectorFamily } from 'recoil';
+
+import { reduceSortsToOrderBy } from '@/ui/data/sort/utils/helpers';
+import { SortOrder } from '~/generated/graphql';
+
+import { currentViewSortsScopedFamilyState } from '../currentViewSortsScopedFamilyState';
+
+export const currentViewSortsOrderByScopedFamilySelector = selectorFamily({
+ key: 'currentViewSortsOrderByScopedFamilySelector',
+ get:
+ ({ viewScopeId, viewId }: { viewScopeId: string; viewId?: string }) =>
+ ({ get }) => {
+ if (!viewId) {
+ return;
+ }
+ const orderBy = reduceSortsToOrderBy(
+ get(
+ currentViewSortsScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: viewId,
+ }),
+ ),
+ );
+ return orderBy.length ? orderBy : [{ createdAt: SortOrder.Desc }];
+ },
+});
diff --git a/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts b/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts
new file mode 100644
index 000000000..e4b2d15e4
--- /dev/null
+++ b/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts
@@ -0,0 +1,32 @@
+import { selectorFamily } from 'recoil';
+
+import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
+import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
+
+import { savedViewFieldsScopedFamilyState } from '../savedViewFieldsScopedFamilyState';
+
+export const savedViewFieldByKeyScopedFamilySelector = selectorFamily({
+ key: 'savedViewFieldByKeyScopedFamilySelector',
+ get:
+ ({
+ viewScopeId,
+ viewId,
+ }: {
+ viewScopeId: string;
+ viewId: string | undefined;
+ }) =>
+ ({ get }) => {
+ if (viewId === undefined) {
+ return undefined;
+ }
+ return get(
+ savedViewFieldsScopedFamilyState({
+ scopeId: viewScopeId,
+ familyKey: viewId,
+ }),
+ ).reduce>>(
+ (result, column) => ({ ...result, [column.key]: column }),
+ {},
+ );
+ },
+});
diff --git a/front/src/modules/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector.ts b/front/src/modules/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector.ts
new file mode 100644
index 000000000..33b79f6cd
--- /dev/null
+++ b/front/src/modules/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector.ts
@@ -0,0 +1,25 @@
+import { selectorFamily } from 'recoil';
+
+import { Filter } from '@/ui/data/filter/types/Filter';
+
+import { savedViewFiltersScopedFamilyState } from '../savedViewFiltersScopedFamilyState';
+
+export const savedViewFiltersByKeyScopedFamilySelector = selectorFamily({
+ key: 'savedViewFiltersByKeyScopedFamilySelector',
+ get:
+ ({ scopeId, viewId }: { scopeId: string; viewId: string | undefined }) =>
+ ({ get }) => {
+ if (viewId === undefined) {
+ return undefined;
+ }
+ return get(
+ savedViewFiltersScopedFamilyState({
+ scopeId: scopeId,
+ familyKey: viewId,
+ }),
+ ).reduce>(
+ (result, filter) => ({ ...result, [filter.key]: filter }),
+ {},
+ );
+ },
+});
diff --git a/front/src/modules/views/states/selectors/savedViewSortsByKeyScopedFamilySelector.ts b/front/src/modules/views/states/selectors/savedViewSortsByKeyScopedFamilySelector.ts
new file mode 100644
index 000000000..619dbf513
--- /dev/null
+++ b/front/src/modules/views/states/selectors/savedViewSortsByKeyScopedFamilySelector.ts
@@ -0,0 +1,25 @@
+import { selectorFamily } from 'recoil';
+
+import { Sort } from '@/ui/data/sort/types/Sort';
+
+import { savedViewSortsScopedFamilyState } from '../savedViewSortsScopedFamilyState';
+
+export const savedViewSortsByKeyScopedFamilySelector = selectorFamily({
+ key: 'savedViewSortsByKeyScopedFamilySelector',
+ get:
+ ({ scopeId, viewId }: { scopeId: string; viewId: string | undefined }) =>
+ ({ get }) => {
+ if (viewId === undefined) {
+ return undefined;
+ }
+ return get(
+ savedViewSortsScopedFamilyState({
+ scopeId: scopeId,
+ familyKey: viewId,
+ }),
+ ).reduce>(
+ (result, sort) => ({ ...result, [sort.key]: sort }),
+ {},
+ );
+ },
+});
diff --git a/front/src/modules/views/states/selectors/savedViewSortsFamilySelector.ts b/front/src/modules/views/states/selectors/savedViewSortsFamilySelector.ts
new file mode 100644
index 000000000..ee0a98353
--- /dev/null
+++ b/front/src/modules/views/states/selectors/savedViewSortsFamilySelector.ts
@@ -0,0 +1,16 @@
+import { selectorFamily } from 'recoil';
+
+import { savedViewSortsScopedFamilyState } from '../savedViewSortsScopedFamilyState';
+
+export const savedViewSortsFamilySelector = selectorFamily({
+ key: 'savedViewSortsFamilySelector',
+ get:
+ ({ scopeId, viewId }: { scopeId: string; viewId: string }) =>
+ ({ get }) =>
+ get(
+ savedViewSortsScopedFamilyState({
+ scopeId: scopeId,
+ familyKey: viewId,
+ }),
+ ),
+});
diff --git a/front/src/modules/ui/data/view-bar/states/selectors/viewsByIdScopedSelector.ts b/front/src/modules/views/states/selectors/viewsByIdScopedSelector.ts
similarity index 73%
rename from front/src/modules/ui/data/view-bar/states/selectors/viewsByIdScopedSelector.ts
rename to front/src/modules/views/states/selectors/viewsByIdScopedSelector.ts
index cd757ef91..cd15cb8dd 100644
--- a/front/src/modules/ui/data/view-bar/states/selectors/viewsByIdScopedSelector.ts
+++ b/front/src/modules/views/states/selectors/viewsByIdScopedSelector.ts
@@ -1,6 +1,7 @@
import { selectorFamily } from 'recoil';
-import { View } from '../../types/View';
+import { View } from '@/views/types/View';
+
import { viewsScopedState } from '../viewsScopedState';
export const viewsByIdScopedSelector = selectorFamily<
@@ -11,7 +12,7 @@ export const viewsByIdScopedSelector = selectorFamily<
get:
(scopeId) =>
({ get }) =>
- get(viewsScopedState(scopeId)).reduce>(
+ get(viewsScopedState({ scopeId: scopeId })).reduce>(
(result, view) => ({ ...result, [view.id]: view }),
{},
),
diff --git a/front/src/modules/views/states/viewEditModeScopedState.ts b/front/src/modules/views/states/viewEditModeScopedState.ts
new file mode 100644
index 000000000..3a3ba3abc
--- /dev/null
+++ b/front/src/modules/views/states/viewEditModeScopedState.ts
@@ -0,0 +1,8 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const viewEditModeScopedState = createScopedState<
+ 'none' | 'edit' | 'create'
+>({
+ key: 'viewEditModeScopedState',
+ defaultValue: 'none',
+});
diff --git a/front/src/modules/views/states/viewObjectIdScopeState.ts b/front/src/modules/views/states/viewObjectIdScopeState.ts
new file mode 100644
index 000000000..3303df4e5
--- /dev/null
+++ b/front/src/modules/views/states/viewObjectIdScopeState.ts
@@ -0,0 +1,6 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+export const viewObjectIdScopeState = createScopedState({
+ key: 'viewObjectIdScopeState',
+ defaultValue: undefined,
+});
diff --git a/front/src/modules/views/states/viewTypeScopedState.ts b/front/src/modules/views/states/viewTypeScopedState.ts
new file mode 100644
index 000000000..0765d99b5
--- /dev/null
+++ b/front/src/modules/views/states/viewTypeScopedState.ts
@@ -0,0 +1,7 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+import { ViewType } from '~/generated/graphql';
+
+export const viewTypeScopedState = createScopedState({
+ key: 'viewTypeScopedState',
+ defaultValue: ViewType.Table,
+});
diff --git a/front/src/modules/views/states/viewsScopedState.ts b/front/src/modules/views/states/viewsScopedState.ts
new file mode 100644
index 000000000..6ba48eb42
--- /dev/null
+++ b/front/src/modules/views/states/viewsScopedState.ts
@@ -0,0 +1,8 @@
+import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
+
+import { View } from '../types/View';
+
+export const viewsScopedState = createScopedState({
+ key: 'viewsScopedState',
+ defaultValue: [],
+});
diff --git a/front/src/modules/ui/data/view-bar/types/View.ts b/front/src/modules/views/types/View.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/View.ts
rename to front/src/modules/views/types/View.ts
diff --git a/front/src/modules/ui/data/view-bar/types/ViewFieldForVisibility.ts b/front/src/modules/views/types/ViewFieldForVisibility.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/ViewFieldForVisibility.ts
rename to front/src/modules/views/types/ViewFieldForVisibility.ts
diff --git a/front/src/modules/ui/data/view-bar/types/ViewsHotkeyScope.ts b/front/src/modules/views/types/ViewsHotkeyScope.ts
similarity index 100%
rename from front/src/modules/ui/data/view-bar/types/ViewsHotkeyScope.ts
rename to front/src/modules/views/types/ViewsHotkeyScope.ts
diff --git a/front/src/pages/companies/companies-filters.tsx b/front/src/pages/companies/companies-filters.tsx
index 3234eb81b..6c066db4f 100644
--- a/front/src/pages/companies/companies-filters.tsx
+++ b/front/src/pages/companies/companies-filters.tsx
@@ -1,5 +1,4 @@
-import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
-import { FilterDefinitionByEntity } from '@/ui/data/view-bar/types/FilterDefinitionByEntity';
+import { FilterDefinitionByEntity } from '@/ui/data/filter/types/FilterDefinitionByEntity';
import {
IconBuildingSkyscraper,
IconCalendarEvent,
@@ -11,7 +10,7 @@ import {
import { FilterDropdownUserSearchSelect } from '@/users/components/FilterDropdownUserSearchSelect';
import { Company } from '~/generated/graphql';
-export const companiesFilters: FilterDefinitionByEntity[] = [
+export const companyAvailableFilters: FilterDefinitionByEntity[] = [
{
key: 'name',
label: 'Name',
@@ -47,8 +46,6 @@ export const companiesFilters: FilterDefinitionByEntity[] = [
label: 'Account owner',
Icon: IconUser,
type: 'entity',
- entitySelectComponent: (
-
- ),
+ entitySelectComponent: ,
},
];
diff --git a/front/src/pages/companies/companies-sorts.tsx b/front/src/pages/companies/companies-sorts.tsx
index 251ba479a..bbdf7d6d7 100644
--- a/front/src/pages/companies/companies-sorts.tsx
+++ b/front/src/pages/companies/companies-sorts.tsx
@@ -1,4 +1,4 @@
-import { SortDefinition } from '@/ui/data/view-bar/types/SortDefinition';
+import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
import {
IconBuildingSkyscraper,
IconCalendarEvent,
diff --git a/front/src/pages/opportunities/opportunities-filters.tsx b/front/src/pages/opportunities/opportunities-filters.tsx
index 99e0c9ff3..719db91ed 100644
--- a/front/src/pages/opportunities/opportunities-filters.tsx
+++ b/front/src/pages/opportunities/opportunities-filters.tsx
@@ -1,5 +1,5 @@
import { FilterDropdownCompanySearchSelect } from '@/companies/components/FilterDropdownCompanySearchSelect';
-import { FilterDefinitionByEntity } from '@/ui/data/view-bar/types/FilterDefinitionByEntity';
+import { FilterDefinitionByEntity } from '@/ui/data/filter/types/FilterDefinitionByEntity';
import {
IconBuildingSkyscraper,
IconCalendarEvent,
diff --git a/front/src/pages/opportunities/opportunities-sorts.tsx b/front/src/pages/opportunities/opportunities-sorts.tsx
index 171bbe5e6..77180bb30 100644
--- a/front/src/pages/opportunities/opportunities-sorts.tsx
+++ b/front/src/pages/opportunities/opportunities-sorts.tsx
@@ -1,4 +1,4 @@
-import { SortDefinition } from '@/ui/data/view-bar/types/SortDefinition';
+import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
import { IconCalendarEvent, IconCurrencyDollar } from '@/ui/display/icon/index';
export const opportunitiesSorts: SortDefinition[] = [
diff --git a/front/src/pages/people/people-filters.tsx b/front/src/pages/people/people-filters.tsx
index 7f83e26a8..7383e9ba8 100644
--- a/front/src/pages/people/people-filters.tsx
+++ b/front/src/pages/people/people-filters.tsx
@@ -1,5 +1,5 @@
import { FilterDropdownCompanySearchSelect } from '@/companies/components/FilterDropdownCompanySearchSelect';
-import { FilterDefinitionByEntity } from '@/ui/data/view-bar/types/FilterDefinitionByEntity';
+import { FilterDefinitionByEntity } from '@/ui/data/filter/types/FilterDefinitionByEntity';
import {
IconBuildingSkyscraper,
IconCalendarEvent,
diff --git a/front/src/pages/people/people-sorts.tsx b/front/src/pages/people/people-sorts.tsx
index 95abf2a6f..0f7b9bf71 100644
--- a/front/src/pages/people/people-sorts.tsx
+++ b/front/src/pages/people/people-sorts.tsx
@@ -1,5 +1,5 @@
-import { SortDefinition } from '@/ui/data/view-bar/types/SortDefinition';
-import { SortDirection } from '@/ui/data/view-bar/types/SortDirection';
+import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
+import { SortDirection } from '@/ui/data/sort/types/SortDirection';
import {
IconBuildingSkyscraper,
IconCalendarEvent,
diff --git a/front/src/pages/tasks/Tasks.tsx b/front/src/pages/tasks/Tasks.tsx
index 63549d8b5..32ed40e19 100644
--- a/front/src/pages/tasks/Tasks.tsx
+++ b/front/src/pages/tasks/Tasks.tsx
@@ -3,8 +3,7 @@ import styled from '@emotion/styled';
import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
import { PageAddTaskButton } from '@/activities/tasks/components/PageAddTaskButton';
import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
-import { FilterDropdownButton } from '@/ui/data/view-bar/components/FilterDropdownButton';
-import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
+import { FilterDropdownButton } from '@/ui/data/filter/components/FilterDropdownButton';
import { IconArchive, IconCheck, IconCheckbox } from '@/ui/display/icon/index';
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
import { PageBody } from '@/ui/layout/page/PageBody';
@@ -53,34 +52,24 @@ export const Tasks = () => {
- {/* TODO: we should refactor filters as a standalone module ? */}
-
-
-
-
-
- }
- rightComponent={
-
- }
- />
-
-
-
+
+
+
+
+ }
+ rightComponent={
+
+ }
+ />
+
+
diff --git a/front/src/pages/tasks/TasksEffect.tsx b/front/src/pages/tasks/TasksEffect.tsx
index 5155c02e8..9837e89fa 100644
--- a/front/src/pages/tasks/TasksEffect.tsx
+++ b/front/src/pages/tasks/TasksEffect.tsx
@@ -1,26 +1,15 @@
import { useEffect } from 'react';
import { useRecoilState } from 'recoil';
-import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
import { currentUserState } from '@/auth/states/currentUserState';
-import { availableFiltersScopedState } from '@/ui/data/view-bar/states/availableFiltersScopedState';
-import { filtersScopedState } from '@/ui/data/view-bar/states/filtersScopedState';
-import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
+import { useFilter } from '@/ui/data/filter/hooks/useFilter';
import { ViewFilterOperand } from '~/generated/graphql';
import { tasksFilters } from './tasks-filters';
export const TasksEffect = () => {
const [currentUser] = useRecoilState(currentUserState);
- const [, setFilters] = useRecoilScopedState(
- filtersScopedState,
- TasksRecoilScopeContext,
- );
-
- const [, setAvailableFilters] = useRecoilScopedState(
- availableFiltersScopedState,
- TasksRecoilScopeContext,
- );
+ const { setSelectedFilters, setAvailableFilters } = useFilter();
useEffect(() => {
setAvailableFilters(tasksFilters);
@@ -28,7 +17,7 @@ export const TasksEffect = () => {
useEffect(() => {
if (currentUser) {
- setFilters([
+ setSelectedFilters([
{
key: 'assigneeId',
type: 'entity',
@@ -39,6 +28,6 @@ export const TasksEffect = () => {
},
]);
}
- }, [currentUser, setFilters]);
+ }, [currentUser, setSelectedFilters]);
return <>>;
};
diff --git a/front/src/pages/tasks/tasks-filters.tsx b/front/src/pages/tasks/tasks-filters.tsx
index 20ba7d61c..b4f6595e8 100644
--- a/front/src/pages/tasks/tasks-filters.tsx
+++ b/front/src/pages/tasks/tasks-filters.tsx
@@ -1,5 +1,4 @@
-import { TasksRecoilScopeContext } from '@/activities/states/recoil-scope-contexts/TasksRecoilScopeContext';
-import { FilterDefinitionByEntity } from '@/ui/data/view-bar/types/FilterDefinitionByEntity';
+import { FilterDefinitionByEntity } from '@/ui/data/filter/types/FilterDefinitionByEntity';
import { IconUser, IconUserCircle } from '@/ui/display/icon';
import { FilterDropdownUserSearchSelect } from '@/users/components/FilterDropdownUserSearchSelect';
import { Activity } from '~/generated/graphql';
@@ -10,9 +9,7 @@ export const tasksFilters: FilterDefinitionByEntity[] = [
label: 'Assignee',
Icon: IconUser,
type: 'entity',
- entitySelectComponent: (
-
- ),
+ entitySelectComponent: ,
selectAllLabel: 'All assignees',
SelectAllIcon: IconUserCircle,
},
diff --git a/front/src/testing/mock-data/companies.ts b/front/src/testing/mock-data/companies.ts
index 17380d7b9..3b0701ebb 100644
--- a/front/src/testing/mock-data/companies.ts
+++ b/front/src/testing/mock-data/companies.ts
@@ -1,4 +1,4 @@
-import { companiesAvailableColumnDefinitions } from '@/companies/constants/companiesAvailableColumnDefinitions';
+import { companiesAvailableFieldDefinitions } from '@/companies/constants/companiesAvailableFieldDefinitions';
import { pipelineAvailableFieldDefinitions } from '@/pipeline/constants/pipelineAvailableFieldDefinitions';
import {
Company,
@@ -192,16 +192,15 @@ export const mockedCompanyTableViews: View[] = [
},
];
-export const mockedCompanyTableColumns =
- companiesAvailableColumnDefinitions.map>(
- (viewFieldDefinition) => ({
- __typename: 'ViewField',
- name: viewFieldDefinition.name,
- index: viewFieldDefinition.index,
- isVisible: true,
- key: viewFieldDefinition.key,
- objectId: 'company',
- size: viewFieldDefinition.size,
- viewId: mockedCompanyTableViews[0].id,
- }),
- );
+export const mockedCompanyTableColumns = companiesAvailableFieldDefinitions.map<
+ Omit
+>((viewFieldDefinition) => ({
+ __typename: 'ViewField',
+ name: viewFieldDefinition.name,
+ index: viewFieldDefinition.index,
+ isVisible: true,
+ key: viewFieldDefinition.key,
+ objectId: 'company',
+ size: viewFieldDefinition.size,
+ viewId: mockedCompanyTableViews[0].id,
+}));
|