refactor: add ViewBar and move view components to ui/view-bar (#1495)

Closes #1494
This commit is contained in:
Thaïs
2023-09-08 11:57:16 +02:00
committed by GitHub
parent ccb57c91a3
commit df17da80fc
22 changed files with 325 additions and 376 deletions

View File

@ -1,151 +1,90 @@
import { useCallback } from 'react';
import { useRecoilValue } from 'recoil';
import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
import { DropdownRecoilScopeContext } from '@/ui/dropdown/states/recoil-scope-contexts/DropdownRecoilScopeContext';
import { TopBar } from '@/ui/top-bar/TopBar';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { FilterDropdownButton } from '@/ui/view-bar/components/FilterDropdownButton';
import { SortDropdownButton } from '@/ui/view-bar/components/SortDropdownButton';
import ViewBarDetails from '@/ui/view-bar/components/ViewBarDetails';
import { ViewBar, type ViewBarProps } from '@/ui/view-bar/components/ViewBar';
import { currentViewIdScopedState } from '@/ui/view-bar/states/currentViewIdScopedState';
import { canPersistFiltersScopedFamilySelector } from '@/ui/view-bar/states/selectors/canPersistFiltersScopedFamilySelector';
import { canPersistSortsScopedFamilySelector } from '@/ui/view-bar/states/selectors/canPersistSortsScopedFamilySelector';
import { sortsScopedState } from '@/ui/view-bar/states/sortsScopedState';
import { FiltersHotkeyScope } from '@/ui/view-bar/types/FiltersHotkeyScope';
import { SelectedSortType, SortType } from '@/ui/view-bar/types/interface';
import type { View } from '@/ui/view-bar/types/View';
import { ViewsHotkeyScope } from '@/ui/view-bar/types/ViewsHotkeyScope';
import { TableOptionsDropdown } from '../../options/components/TableOptionsDropdown';
import { TableUpdateViewButtonGroup } from '../../options/components/TableUpdateViewButtonGroup';
import { TableViewsDropdownButton } from '../../options/components/TableViewsDropdownButton';
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
import { savedTableColumnsFamilyState } from '../../states/savedTableColumnsFamilyState';
import { canPersistTableColumnsScopedFamilySelector } from '../../states/selectors/canPersistTableColumnsScopedFamilySelector';
import { tableColumnsScopedState } from '../../states/tableColumnsScopedState';
import { TableOptionsDropdownKey } from '../../types/TableOptionsDropdownKey';
import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
type OwnProps<SortField> = {
viewName: string;
availableSorts?: Array<SortType<SortField>>;
onViewsChange?: (views: View[]) => void;
onViewSubmit?: () => void;
export type TableHeaderProps<SortField> = {
onImport?: () => void;
};
} & Pick<
ViewBarProps<SortField>,
'availableSorts' | 'defaultViewName' | 'onViewsChange' | 'onViewSubmit'
>;
export function TableHeader<SortField>({
viewName,
availableSorts,
onImport,
onViewsChange,
onViewSubmit,
onImport,
}: OwnProps<SortField>) {
...props
}: TableHeaderProps<SortField>) {
const tableScopeId = useContextScopeId(TableRecoilScopeContext);
const currentViewId = useRecoilScopedValue(
currentViewIdScopedState,
TableRecoilScopeContext,
);
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
sortsScopedState,
TableRecoilScopeContext,
);
const canPersistTableColumns = useRecoilValue(
canPersistTableColumnsScopedFamilySelector([tableScopeId, currentViewId]),
);
const canPersistFilters = useRecoilValue(
canPersistFiltersScopedFamilySelector([tableScopeId, currentViewId]),
const tableColumns = useRecoilScopedValue(
tableColumnsScopedState,
TableRecoilScopeContext,
);
const setSavedTableColumns = useSetRecoilState(
savedTableColumnsFamilyState(currentViewId),
);
const canPersistSorts = useRecoilValue(
canPersistSortsScopedFamilySelector([tableScopeId, currentViewId]),
const handleViewSelect = useRecoilCallback(
({ set, snapshot }) =>
async (viewId: string) => {
const savedTableColumns = await snapshot.getPromise(
savedTableColumnsFamilyState(viewId),
);
set(tableColumnsScopedState(tableScopeId), savedTableColumns);
},
[tableScopeId],
);
const sortSelect = useCallback(
(newSort: SelectedSortType<SortField>) => {
const newSorts = updateSortOrFilterByKey(sorts, newSort);
setSorts(newSorts);
},
[setSorts, sorts],
);
const handleViewSubmit = async () => {
if (canPersistTableColumns) setSavedTableColumns(tableColumns);
const sortUnselect = useCallback(
(sortKey: string) => {
const newSorts = sorts.filter((sort) => sort.key !== sortKey);
setSorts(newSorts);
},
[setSorts, sorts],
await onViewSubmit?.();
};
const OptionsDropdownButton = useCallback(
() => (
<TableOptionsDropdown
onImport={onImport}
onViewsChange={onViewsChange}
customHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
/>
),
[onImport, onViewsChange],
);
return (
<RecoilScope SpecificContext={DropdownRecoilScopeContext}>
<TopBar
leftComponent={
<TableViewsDropdownButton
defaultViewName={viewName}
onViewsChange={onViewsChange}
HotkeyScope={ViewsHotkeyScope.ListDropdown}
/>
}
displayBottomBorder={false}
rightComponent={
<>
<FilterDropdownButton
context={TableRecoilScopeContext}
HotkeyScope={FiltersHotkeyScope.FilterDropdownButton}
isPrimaryButton
/>
<SortDropdownButton<SortField>
context={TableRecoilScopeContext}
isSortSelected={sorts.length > 0}
availableSorts={availableSorts || []}
onSortSelect={sortSelect}
HotkeyScope={FiltersHotkeyScope.FilterDropdownButton}
isPrimaryButton
/>
<TableOptionsDropdown
onImport={onImport}
onViewsChange={onViewsChange}
customHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
/>
</>
}
bottomComponent={
<ViewBarDetails
canPersistView={
canPersistTableColumns || canPersistFilters || canPersistSorts
}
context={TableRecoilScopeContext}
sorts={sorts}
onRemoveSort={sortUnselect}
onCancelClick={() => setSorts([])}
hasFilterButton
rightComponent={
<TableUpdateViewButtonGroup
onViewSubmit={onViewSubmit}
HotkeyScope={ViewsHotkeyScope.CreateDropdown}
/>
}
/>
}
<ViewBar
{...props}
canPersistViewFields={canPersistTableColumns}
onViewSelect={handleViewSelect}
onViewSubmit={handleViewSubmit}
OptionsDropdownButton={OptionsDropdownButton}
optionsDropdownKey={TableOptionsDropdownKey}
scopeContext={TableRecoilScopeContext}
/>
</RecoilScope>
);
}
function updateSortOrFilterByKey<SortOrFilter extends { key: string }>(
sorts: Readonly<SortOrFilter[]>,
newSort: SortOrFilter,
): SortOrFilter[] {
const newSorts = [...sorts];
const existingSortIndex = sorts.findIndex((sort) => sort.key === newSort.key);
if (existingSortIndex !== -1) {
newSorts[existingSortIndex] = newSort;
} else {
newSorts.push(newSort);
}
return newSorts;
}