2422 refactor scope components to improve dev experience (#2736)
* move scope inside record table * fix imports * update mock * recordTable scope done * RecordTable done * fix board * fix typo * wip * filter is working * sort is working * Tasks working * Fix according to PR --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -9,7 +9,7 @@ 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 { useViewBar } from '@/views/hooks/useViewBar';
|
||||
|
||||
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
|
||||
|
||||
@ -29,7 +29,7 @@ export const UpdateViewButtonGroup = ({
|
||||
onViewEditModeChange,
|
||||
}: UpdateViewButtonGroupProps) => {
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
const { updateCurrentView, setViewEditMode } = useView();
|
||||
const { updateCurrentView, setViewEditMode } = useViewBar();
|
||||
const { canPersistFiltersSelector, canPersistSortsSelector } =
|
||||
useViewScopedStates();
|
||||
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { TopBar } from '@/ui/layout/top-bar/TopBar';
|
||||
import { ObjectFilterDropdownButton } from '@/ui/object/object-filter-dropdown/components/ObjectFilterDropdownButton';
|
||||
import { ObjectFilterDropdownScope } from '@/ui/object/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
|
||||
import { FiltersHotkeyScope } from '@/ui/object/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
import { ObjectSortDropdownButton } from '@/ui/object/object-sort-dropdown/components/ObjectSortDropdownButton';
|
||||
import { ObjectSortDropdownScope } from '@/ui/object/object-sort-dropdown/scopes/ObjectSortDropdownScope';
|
||||
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
||||
import { ViewBarSortEffect } from '@/views/components/ViewBarSortEffect';
|
||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||
import { ViewScope } from '@/views/scopes/ViewScope';
|
||||
import { ViewField } from '@/views/types/ViewField';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { ViewSort } from '@/views/types/ViewSort';
|
||||
|
||||
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
|
||||
import { useView } from '../hooks/useView';
|
||||
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
||||
|
||||
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
||||
@ -19,82 +21,91 @@ import { ViewBarEffect } from './ViewBarEffect';
|
||||
import { ViewsDropdownButton } from './ViewsDropdownButton';
|
||||
|
||||
export type ViewBarProps = {
|
||||
viewBarId: string;
|
||||
className?: string;
|
||||
optionsDropdownButton: ReactNode;
|
||||
optionsDropdownScopeId: string;
|
||||
onViewSortsChange?: (sorts: ViewSort[]) => void | Promise<void>;
|
||||
onViewFiltersChange?: (filters: ViewFilter[]) => void | Promise<void>;
|
||||
onViewFieldsChange?: (fields: ViewField[]) => void | Promise<void>;
|
||||
};
|
||||
|
||||
export const ViewBar = ({
|
||||
viewBarId,
|
||||
className,
|
||||
optionsDropdownButton,
|
||||
optionsDropdownScopeId,
|
||||
onViewFieldsChange,
|
||||
onViewFiltersChange,
|
||||
onViewSortsChange,
|
||||
}: ViewBarProps) => {
|
||||
const { openDropdown: openOptionsDropdownButton } = useDropdown({
|
||||
dropdownScopeId: optionsDropdownScopeId,
|
||||
});
|
||||
const { upsertViewSort, upsertViewFilter } = useView();
|
||||
const { upsertViewSort, upsertViewFilter } = useViewBar({
|
||||
viewBarId: viewBarId,
|
||||
});
|
||||
|
||||
const { availableFilterDefinitionsState, availableSortDefinitionsState } =
|
||||
useViewScopedStates();
|
||||
|
||||
const availableFilterDefinitions = useRecoilValue(
|
||||
availableFilterDefinitionsState,
|
||||
);
|
||||
const availableSortDefinitions = useRecoilValue(
|
||||
availableSortDefinitionsState,
|
||||
);
|
||||
const filterDropdownId = 'view-filter';
|
||||
const sortDropdownId = 'view-sort';
|
||||
|
||||
return (
|
||||
<ObjectFilterDropdownScope
|
||||
filterScopeId="view-filter"
|
||||
availableFilterDefinitions={availableFilterDefinitions}
|
||||
onFilterSelect={upsertViewFilter}
|
||||
<ViewScope
|
||||
viewScopeId={viewBarId}
|
||||
onViewFieldsChange={onViewFieldsChange}
|
||||
onViewFiltersChange={onViewFiltersChange}
|
||||
onViewSortsChange={onViewSortsChange}
|
||||
>
|
||||
<ObjectSortDropdownScope
|
||||
sortScopeId="view-sort"
|
||||
availableSortDefinitions={availableSortDefinitions}
|
||||
<ViewBarEffect />
|
||||
<ViewBarFilterEffect
|
||||
filterDropdownId={filterDropdownId}
|
||||
onFilterSelect={upsertViewFilter}
|
||||
/>
|
||||
<ViewBarSortEffect
|
||||
sortDropdownId={sortDropdownId}
|
||||
onSortSelect={upsertViewSort}
|
||||
>
|
||||
<ViewBarEffect />
|
||||
<TopBar
|
||||
className={className}
|
||||
leftComponent={
|
||||
<ViewsDropdownButton
|
||||
onViewEditModeChange={openOptionsDropdownButton}
|
||||
hotkeyScope={{ scope: ViewsHotkeyScope.ListDropdown }}
|
||||
optionsDropdownScopeId={optionsDropdownScopeId}
|
||||
/>
|
||||
|
||||
<TopBar
|
||||
className={className}
|
||||
leftComponent={
|
||||
<ViewsDropdownButton
|
||||
onViewEditModeChange={openOptionsDropdownButton}
|
||||
hotkeyScope={{ scope: ViewsHotkeyScope.ListDropdown }}
|
||||
optionsDropdownScopeId={optionsDropdownScopeId}
|
||||
/>
|
||||
}
|
||||
displayBottomBorder={false}
|
||||
rightComponent={
|
||||
<>
|
||||
<ObjectFilterDropdownButton
|
||||
filterDropdownId={filterDropdownId}
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
displayBottomBorder={false}
|
||||
rightComponent={
|
||||
<>
|
||||
<ObjectFilterDropdownButton
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
|
||||
}}
|
||||
/>
|
||||
<ObjectSortDropdownButton
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectSortDropdownButton,
|
||||
}}
|
||||
isPrimaryButton
|
||||
/>
|
||||
{optionsDropdownButton}
|
||||
</>
|
||||
}
|
||||
bottomComponent={
|
||||
<ViewBarDetails
|
||||
hasFilterButton
|
||||
rightComponent={
|
||||
<UpdateViewButtonGroup
|
||||
onViewEditModeChange={openOptionsDropdownButton}
|
||||
hotkeyScope={ViewsHotkeyScope.CreateDropdown}
|
||||
/>
|
||||
}
|
||||
<ObjectSortDropdownButton
|
||||
sortDropdownId={sortDropdownId}
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectSortDropdownButton,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</ObjectSortDropdownScope>
|
||||
</ObjectFilterDropdownScope>
|
||||
{optionsDropdownButton}
|
||||
</>
|
||||
}
|
||||
bottomComponent={
|
||||
<ViewBarDetails
|
||||
filterDropdownId={filterDropdownId}
|
||||
hasFilterButton
|
||||
rightComponent={
|
||||
<UpdateViewButtonGroup
|
||||
onViewEditModeChange={openOptionsDropdownButton}
|
||||
hotkeyScope={ViewsHotkeyScope.CreateDropdown}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</ViewScope>
|
||||
);
|
||||
};
|
||||
|
||||
@ -6,15 +6,16 @@ import { IconArrowDown, IconArrowUp } from '@/ui/display/icon/index';
|
||||
import { useLazyLoadIcons } from '@/ui/input/hooks/useLazyLoadIcons';
|
||||
import { AddObjectFilterFromDetailsButton } from '@/ui/object/object-filter-dropdown/components/AddObjectFilterFromDetailsButton';
|
||||
import { getOperandLabelShort } from '@/ui/object/object-filter-dropdown/utils/getOperandLabel';
|
||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||
|
||||
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
|
||||
import { useView } from '../hooks/useView';
|
||||
|
||||
import SortOrFilterChip from './SortOrFilterChip';
|
||||
|
||||
export type ViewBarDetailsProps = {
|
||||
hasFilterButton?: boolean;
|
||||
rightComponent?: ReactNode;
|
||||
filterDropdownId?: string;
|
||||
};
|
||||
|
||||
const StyledBar = styled.div`
|
||||
@ -88,6 +89,7 @@ const StyledAddFilterContainer = styled.div`
|
||||
export const ViewBarDetails = ({
|
||||
hasFilterButton = false,
|
||||
rightComponent,
|
||||
filterDropdownId,
|
||||
}: ViewBarDetailsProps) => {
|
||||
const {
|
||||
currentViewSortsState,
|
||||
@ -104,7 +106,7 @@ export const ViewBarDetails = ({
|
||||
const canPersistSorts = useRecoilValue(canPersistSortsSelector);
|
||||
const isViewBarExpanded = useRecoilValue(isViewBarExpandedState);
|
||||
|
||||
const { resetViewBar, removeViewSort, removeViewFilter } = useView();
|
||||
const { resetViewBar, removeViewSort, removeViewFilter } = useViewBar();
|
||||
|
||||
const canPersistView = canPersistFilters || canPersistSorts;
|
||||
|
||||
@ -161,7 +163,9 @@ export const ViewBarDetails = ({
|
||||
</StyledChipcontainer>
|
||||
{hasFilterButton && (
|
||||
<StyledAddFilterContainer>
|
||||
<AddObjectFilterFromDetailsButton />
|
||||
<AddObjectFilterFromDetailsButton
|
||||
filterDropdownId={filterDropdownId}
|
||||
/>
|
||||
</StyledAddFilterContainer>
|
||||
)}
|
||||
</StyledFilterContainer>
|
||||
|
||||
@ -5,11 +5,11 @@ import { useRecoilCallback, useRecoilValue } from 'recoil';
|
||||
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
|
||||
import { PaginatedObjectTypeResults } from '@/object-record/types/PaginatedObjectTypeResults';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
|
||||
import { useView } from '../hooks/useView';
|
||||
import { getViewScopedStatesFromSnapshot } from '../utils/getViewScopedStatesFromSnapshot';
|
||||
|
||||
export const ViewBarEffect = () => {
|
||||
@ -20,7 +20,7 @@ export const ViewBarEffect = () => {
|
||||
loadViewFields,
|
||||
loadViewFilters,
|
||||
loadViewSorts,
|
||||
} = useView();
|
||||
} = useViewBar();
|
||||
|
||||
const [searchParams] = useSearchParams();
|
||||
const currentViewIdFromUrl = searchParams.get('view');
|
||||
|
||||
41
front/src/modules/views/components/ViewBarFilterEffect.tsx
Normal file
41
front/src/modules/views/components/ViewBarFilterEffect.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useFilterDropdown } from '@/ui/object/object-filter-dropdown/hooks/useFilterDropdown';
|
||||
import { Filter } from '@/ui/object/object-filter-dropdown/types/Filter';
|
||||
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
|
||||
|
||||
type ViewBarFilterEffectProps = {
|
||||
filterDropdownId: string;
|
||||
onFilterSelect?: ((filter: Filter) => void) | undefined;
|
||||
};
|
||||
|
||||
export const ViewBarFilterEffect = ({
|
||||
filterDropdownId,
|
||||
onFilterSelect,
|
||||
}: ViewBarFilterEffectProps) => {
|
||||
const { availableFilterDefinitionsState } = useViewScopedStates();
|
||||
|
||||
const availableFilterDefinitions = useRecoilValue(
|
||||
availableFilterDefinitionsState,
|
||||
);
|
||||
const { setAvailableFilterDefinitions, setOnFilterSelect } =
|
||||
useFilterDropdown({ filterDropdownId: filterDropdownId });
|
||||
|
||||
useEffect(() => {
|
||||
if (availableFilterDefinitions) {
|
||||
setAvailableFilterDefinitions(availableFilterDefinitions);
|
||||
}
|
||||
|
||||
if (onFilterSelect) {
|
||||
setOnFilterSelect(() => onFilterSelect);
|
||||
}
|
||||
}, [
|
||||
availableFilterDefinitions,
|
||||
onFilterSelect,
|
||||
setAvailableFilterDefinitions,
|
||||
setOnFilterSelect,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
42
front/src/modules/views/components/ViewBarSortEffect.tsx
Normal file
42
front/src/modules/views/components/ViewBarSortEffect.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useSortDropdown } from '@/ui/object/object-sort-dropdown/hooks/useSortDropdown';
|
||||
import { Sort } from '@/ui/object/object-sort-dropdown/types/Sort';
|
||||
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
|
||||
|
||||
type ViewBarSortEffectProps = {
|
||||
sortDropdownId: string;
|
||||
onSortSelect?: ((sort: Sort) => void) | undefined;
|
||||
};
|
||||
|
||||
export const ViewBarSortEffect = ({
|
||||
sortDropdownId,
|
||||
onSortSelect,
|
||||
}: ViewBarSortEffectProps) => {
|
||||
const { availableSortDefinitionsState } = useViewScopedStates();
|
||||
|
||||
const availableSortDefinitions = useRecoilValue(
|
||||
availableSortDefinitionsState,
|
||||
);
|
||||
|
||||
const { setAvailableSortDefinitions, setOnSortSelect } = useSortDropdown({
|
||||
sortDropdownId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (availableSortDefinitions) {
|
||||
setAvailableSortDefinitions(availableSortDefinitions);
|
||||
}
|
||||
if (onSortSelect) {
|
||||
setOnSortSelect(() => onSortSelect);
|
||||
}
|
||||
}, [
|
||||
availableSortDefinitions,
|
||||
onSortSelect,
|
||||
setAvailableSortDefinitions,
|
||||
setOnSortSelect,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -19,11 +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 { useViewBar } from '@/views/hooks/useViewBar';
|
||||
import { assertNotNull } from '~/utils/assert';
|
||||
|
||||
import { ViewsDropdownId } from '../constants/ViewsDropdownId';
|
||||
import { useViewScopedStates } from '../hooks/internal/useViewScopedStates';
|
||||
import { useView } from '../hooks/useView';
|
||||
|
||||
const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
|
||||
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||
@ -68,7 +68,7 @@ export const ViewsDropdownButton = ({
|
||||
optionsDropdownScopeId,
|
||||
}: ViewsDropdownButtonProps) => {
|
||||
const theme = useTheme();
|
||||
const { removeView, changeViewInUrl } = useView();
|
||||
const { removeView, changeViewInUrl } = useViewBar();
|
||||
|
||||
const { viewsState, currentViewSelector, entityCountInCurrentViewState } =
|
||||
useViewScopedStates();
|
||||
@ -79,7 +79,7 @@ export const ViewsDropdownButton = ({
|
||||
entityCountInCurrentViewState,
|
||||
);
|
||||
|
||||
const { setViewEditMode, setCurrentViewId, loadView } = useView();
|
||||
const { setViewEditMode, setCurrentViewId, loadView } = useViewBar();
|
||||
|
||||
const {
|
||||
isDropdownOpen: isViewsDropdownOpen,
|
||||
|
||||
Reference in New Issue
Block a user