feat: create view from current table columns + persist view fields on… (#1308)

feat: create view from current table columns + persist view fields on Update View button click

Closes #1302, Closes #1307
This commit is contained in:
Thaïs
2023-08-25 18:21:27 +02:00
committed by GitHub
parent f520a00909
commit 432fea0ee3
27 changed files with 432 additions and 282 deletions

View File

@ -1,8 +1,4 @@
import { DropdownButton } from '@/ui/dropdown/components/DropdownButton';
import type {
ViewFieldDefinition,
ViewFieldMetadata,
} from '@/ui/editable-field/types/ViewField';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { type TableView } from '../../states/tableViewsState';
@ -11,14 +7,12 @@ import { TableOptionsDropdownButton } from './TableOptionsDropdownButton';
import { TableOptionsDropdownContent } from './TableOptionsDropdownContent';
type TableOptionsDropdownProps = {
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
onViewsChange?: (views: TableView[]) => void;
onImport?: () => void;
customHotkeyScope: HotkeyScope;
};
export function TableOptionsDropdown({
onColumnsChange,
onViewsChange,
onImport,
customHotkeyScope,
@ -30,7 +24,6 @@ export function TableOptionsDropdown({
dropdownKey="options"
dropdownComponents={
<TableOptionsDropdownContent
onColumnsChange={onColumnsChange}
onImport={onImport}
onViewsChange={onViewsChange}
/>

View File

@ -1,6 +1,6 @@
import { type FormEvent, useCallback, useRef, useState } from 'react';
import { useTheme } from '@emotion/react';
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
import { useRecoilCallback, useRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
import { v4 } from 'uuid';
@ -27,16 +27,16 @@ import {
IconPlus,
IconTag,
} from '@/ui/icon';
import {
hiddenTableColumnsState,
tableColumnsState,
visibleTableColumnsState,
} from '@/ui/table/states/tableColumnsState';
import { tableColumnsScopedState } from '@/ui/table/states/tableColumnsScopedState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
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 { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
import { savedTableColumnsScopedState } from '../../states/savedTableColumnsScopedState';
import { hiddenTableColumnsScopedSelector } from '../../states/selectors/hiddenTableColumnsScopedSelector';
import { visibleTableColumnsScopedSelector } from '../../states/selectors/visibleTableColumnsScopedSelector';
import {
currentTableViewIdState,
type TableView,
@ -49,7 +49,6 @@ import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
import { TableOptionsDropdownSection } from './TableOptionsDropdownSection';
type TableOptionsDropdownButtonProps = {
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
onViewsChange?: (views: TableView[]) => void;
onImport?: () => void;
};
@ -59,7 +58,6 @@ enum Option {
}
export function TableOptionsDropdownContent({
onColumnsChange,
onViewsChange,
onImport,
}: TableOptionsDropdownButtonProps) {
@ -75,28 +73,37 @@ export function TableOptionsDropdownContent({
const viewEditInputRef = useRef<HTMLInputElement>(null);
const [columns, setColumns] = useRecoilState(tableColumnsState);
const [viewEditMode, setViewEditMode] = useRecoilState(
tableViewEditModeState,
);
const visibleColumns = useRecoilValue(visibleTableColumnsState);
const hiddenColumns = useRecoilValue(hiddenTableColumnsState);
const [columns, setColumns] = useRecoilScopedState(
tableColumnsScopedState,
TableRecoilScopeContext,
);
const visibleColumns = useRecoilScopedValue(
visibleTableColumnsScopedSelector,
TableRecoilScopeContext,
);
const hiddenColumns = useRecoilScopedValue(
hiddenTableColumnsScopedSelector,
TableRecoilScopeContext,
);
const viewsById = useRecoilScopedValue(
tableViewsByIdState,
TableRecoilScopeContext,
);
const handleColumnVisibilityChange = useCallback(
(columnId: string, nextIsVisible: boolean) => {
async (columnId: string, nextIsVisible: boolean) => {
const nextColumns = columns.map((column) =>
column.id === columnId
? { ...column, isVisible: nextIsVisible }
: column,
);
(onColumnsChange ?? setColumns)(nextColumns);
setColumns(nextColumns);
},
[columns, onColumnsChange, setColumns],
[columns, setColumns],
);
const renderFieldActions = useCallback(
@ -144,6 +151,14 @@ export function TableOptionsDropdownContent({
const viewToCreate = { id: v4(), name };
const nextViews = [...views, viewToCreate];
const currentColumns = await snapshot.getPromise(
tableColumnsScopedState(tableScopeId),
);
set(
savedTableColumnsScopedState(viewToCreate.id),
currentColumns.map((column) => ({ ...column, id: v4() })),
);
const selectedFilters = await snapshot.getPromise(
filtersScopedState(tableScopeId),
);

View File

@ -1,7 +1,7 @@
import { useCallback, useState } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilCallback, useRecoilValue, useSetRecoilState } from 'recoil';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { Key } from 'ts-key-enum';
import { Button, ButtonSize } from '@/ui/button/components/Button';
@ -22,6 +22,9 @@ import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextS
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
import { savedTableColumnsScopedState } from '../../states/savedTableColumnsScopedState';
import { canPersistTableColumnsScopedSelector } from '../../states/selectors/canPersistTableColumnsScopedSelector';
import { tableColumnsScopedState } from '../../states/tableColumnsScopedState';
import {
currentTableViewIdState,
tableViewEditModeState,
@ -56,12 +59,38 @@ export const TableUpdateViewButtonGroup = ({
currentTableViewIdState,
TableRecoilScopeContext,
);
const currentColumns = useRecoilScopedValue(
tableColumnsScopedState,
TableRecoilScopeContext,
);
const setSavedColumns = useSetRecoilState(
savedTableColumnsScopedState(currentViewId),
);
const canPersistColumns = useRecoilValue(
canPersistTableColumnsScopedSelector([tableScopeId, currentViewId]),
);
const selectedFilters = useRecoilScopedValue(
filtersScopedState,
TableRecoilScopeContext,
);
const setSavedFilters = useSetRecoilState(
savedFiltersScopedState(currentViewId),
);
const canPersistFilters = useRecoilValue(
canPersistFiltersScopedSelector([tableScopeId, currentViewId]),
);
const selectedSorts = useRecoilScopedValue(
sortsScopedState,
TableRecoilScopeContext,
);
const setSavedSorts = useSetRecoilState(savedSortsScopedState(currentViewId));
const canPersistSorts = useRecoilValue(
canPersistSortsScopedSelector([tableScopeId, currentViewId]),
);
const setViewEditMode = useSetRecoilState(tableViewEditModeState);
const { openDropdownButton: openOptionsDropdownButton } = useDropdownButton({
@ -82,23 +111,21 @@ export const TableUpdateViewButtonGroup = ({
setIsDropdownOpen(false);
}, []);
const handleViewSubmit = useRecoilCallback(
({ set, snapshot }) =>
async () => {
await Promise.resolve(onViewSubmit?.());
const handleViewSubmit = useCallback(async () => {
await Promise.resolve(onViewSubmit?.());
const selectedFilters = await snapshot.getPromise(
filtersScopedState(tableScopeId),
);
set(savedFiltersScopedState(currentViewId), selectedFilters);
const selectedSorts = await snapshot.getPromise(
sortsScopedState(tableScopeId),
);
set(savedSortsScopedState(currentViewId), selectedSorts);
},
[currentViewId, onViewSubmit, tableScopeId],
);
setSavedColumns(currentColumns);
setSavedFilters(selectedFilters);
setSavedSorts(selectedSorts);
}, [
currentColumns,
onViewSubmit,
selectedFilters,
selectedSorts,
setSavedColumns,
setSavedFilters,
setSavedSorts,
]);
useScopedHotkeys(
[Key.Enter, Key.Escape],
@ -112,7 +139,10 @@ export const TableUpdateViewButtonGroup = ({
<ButtonGroup size={ButtonSize.Small}>
<Button
title="Update view"
disabled={!currentViewId || (!canPersistFilters && !canPersistSorts)}
disabled={
!currentViewId ||
(!canPersistColumns && !canPersistFilters && !canPersistSorts)
}
onClick={handleViewSubmit}
/>
<Button

View File

@ -33,6 +33,8 @@ import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoi
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
import { savedTableColumnsScopedState } from '../../states/savedTableColumnsScopedState';
import { tableColumnsScopedState } from '../../states/tableColumnsScopedState';
import { TableViewsHotkeyScope } from '../../types/TableViewsHotkeyScope';
const StyledBoldDropdownMenuItemsContainer = styled(
@ -95,6 +97,9 @@ export const TableViewsDropdownButton = ({
const handleViewSelect = useRecoilCallback(
({ set, snapshot }) =>
async (viewId?: string) => {
const savedColumns = await snapshot.getPromise(
savedTableColumnsScopedState(viewId),
);
const savedFilters = await snapshot.getPromise(
savedFiltersScopedState(viewId),
);
@ -102,6 +107,7 @@ export const TableViewsDropdownButton = ({
savedSortsScopedState(viewId),
);
set(tableColumnsScopedState(tableScopeId), savedColumns);
set(filtersScopedState(tableScopeId), savedFilters);
set(sortsScopedState(tableScopeId), savedSorts);
set(currentTableViewIdState(tableScopeId), viewId);