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:
bosiraphael
2023-11-28 18:24:18 +01:00
committed by GitHub
parent 9d3e000055
commit ade41c916d
60 changed files with 651 additions and 529 deletions

View File

@ -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();

View File

@ -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>
);
};

View File

@ -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>

View File

@ -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');

View 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 <></>;
};

View 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 <></>;
};

View File

@ -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,