Refactor board and table options (#3700)
* Refactor board and table options * Fix * Fix
This commit is contained in:
@ -14,7 +14,6 @@ const StyledColumn = styled.div<{ isFirstColumn: boolean }>`
|
|||||||
isFirstColumn ? 'none' : theme.border.color.light};
|
isFirstColumn ? 'none' : theme.border.color.light};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: fit-content;
|
|
||||||
max-width: 200px;
|
max-width: 200px;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { useState } from 'react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
|
||||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
@ -11,13 +10,12 @@ import { RecordIndexBoardContainerEffect } from '@/object-record/record-index/co
|
|||||||
import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer';
|
import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer';
|
||||||
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
||||||
import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect';
|
import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect';
|
||||||
|
import { RecordIndexOptionsDropdown } from '@/object-record/record-index/options/components/RecordIndexOptionsDropdown';
|
||||||
|
import { RECORD_INDEX_OPTIONS_DROPDOWN_ID } from '@/object-record/record-index/options/constants/RecordIndexOptionsDropdownId';
|
||||||
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||||
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown';
|
|
||||||
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
|
||||||
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||||
import { ViewBar } from '@/views/components/ViewBar';
|
import { ViewBar } from '@/views/components/ViewBar';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
@ -66,37 +64,23 @@ export const RecordIndexContainer = ({
|
|||||||
const setRecordIndexFilters = useSetRecoilState(recordIndexFiltersState);
|
const setRecordIndexFilters = useSetRecoilState(recordIndexFiltersState);
|
||||||
const setRecordIndexSorts = useSetRecoilState(recordIndexSortsState);
|
const setRecordIndexSorts = useSetRecoilState(recordIndexSortsState);
|
||||||
|
|
||||||
const { openPersonSpreadsheetImport } = useSpreadsheetPersonImport();
|
|
||||||
const { openCompanySpreadsheetImport } = useSpreadsheetCompanyImport();
|
|
||||||
|
|
||||||
const { setTableFilters, setTableSorts, setTableColumns } = useRecordTable({
|
const { setTableFilters, setTableSorts, setTableColumns } = useRecordTable({
|
||||||
recordTableId: recordIndexId,
|
recordTableId: recordIndexId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleImport = () => {
|
|
||||||
const openImport =
|
|
||||||
objectNamePlural === 'companies'
|
|
||||||
? openCompanySpreadsheetImport
|
|
||||||
: openPersonSpreadsheetImport;
|
|
||||||
openImport();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<SpreadsheetImportProvider>
|
<SpreadsheetImportProvider>
|
||||||
<ViewBar
|
<ViewBar
|
||||||
viewBarId={recordIndexId}
|
viewBarId={recordIndexId}
|
||||||
optionsDropdownButton={
|
optionsDropdownButton={
|
||||||
<TableOptionsDropdown
|
<RecordIndexOptionsDropdown
|
||||||
recordTableId={recordIndexId}
|
recordIndexId={recordIndexId}
|
||||||
onImport={
|
objectNameSingular={objectNameSingular}
|
||||||
['companies', 'people'].includes(recordIndexId)
|
viewType={recordIndexViewType ?? ViewType.Table}
|
||||||
? handleImport
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
optionsDropdownScopeId={TableOptionsDropdownId}
|
optionsDropdownScopeId={RECORD_INDEX_OPTIONS_DROPDOWN_ID}
|
||||||
onViewFieldsChange={(viewFields) => {
|
onViewFieldsChange={(viewFields) => {
|
||||||
setTableColumns(
|
setTableColumns(
|
||||||
mapViewFieldsToColumnDefinitions(viewFields, columnDefinitions),
|
mapViewFieldsToColumnDefinitions(viewFields, columnDefinitions),
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { RecordIndexOptionsDropdownButton } from '@/object-record/record-index/options/components/RecordIndexOptionsDropdownButton';
|
||||||
|
import { RecordIndexOptionsDropdownContent } from '@/object-record/record-index/options/components/RecordIndexOptionsDropdownContent';
|
||||||
|
import { RECORD_INDEX_OPTIONS_DROPDOWN_ID } from '@/object-record/record-index/options/constants/RecordIndexOptionsDropdownId';
|
||||||
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
|
||||||
|
type RecordIndexOptionsDropdownProps = {
|
||||||
|
viewType: ViewType;
|
||||||
|
objectNameSingular: string;
|
||||||
|
recordIndexId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecordIndexOptionsDropdown = ({
|
||||||
|
recordIndexId,
|
||||||
|
objectNameSingular,
|
||||||
|
viewType,
|
||||||
|
}: RecordIndexOptionsDropdownProps) => {
|
||||||
|
const { setViewEditMode } = useViewBar();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
dropdownId={RECORD_INDEX_OPTIONS_DROPDOWN_ID}
|
||||||
|
clickableComponent={<RecordIndexOptionsDropdownButton />}
|
||||||
|
dropdownHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
|
||||||
|
dropdownOffset={{ y: 8 }}
|
||||||
|
dropdownComponents={
|
||||||
|
<RecordIndexOptionsDropdownContent
|
||||||
|
viewType={viewType}
|
||||||
|
objectNameSingular={objectNameSingular}
|
||||||
|
recordIndexId={recordIndexId}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClickOutside={() => setViewEditMode('none')}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
import { RECORD_INDEX_OPTIONS_DROPDOWN_ID } from '@/object-record/record-index/options/constants/RecordIndexOptionsDropdownId';
|
||||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
|
|
||||||
export const TableOptionsDropdownButton = () => {
|
export const RecordIndexOptionsDropdownButton = () => {
|
||||||
const { isDropdownOpen, toggleDropdown } = useDropdown(
|
const { isDropdownOpen, toggleDropdown } = useDropdown(
|
||||||
TableOptionsDropdownId,
|
RECORD_INDEX_OPTIONS_DROPDOWN_ID,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -1,10 +1,12 @@
|
|||||||
import { useCallback, useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { OnDragEndResponder } from '@hello-pangea/dnd';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
import { RECORD_INDEX_OPTIONS_DROPDOWN_ID } from '@/object-record/record-index/options/constants/RecordIndexOptionsDropdownId';
|
||||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard';
|
||||||
|
import { useRecordIndexOptionsForTable } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForTable';
|
||||||
|
import { useRecordIndexOptionsImport } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsImport';
|
||||||
|
import { TableOptionsHotkeyScope } from '@/object-record/record-table/types/TableOptionsHotkeyScope';
|
||||||
import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon';
|
import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
|
||||||
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
||||||
@ -16,69 +18,42 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|||||||
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
import { ViewFieldsVisibilityDropdownSection } from '@/views/components/ViewFieldsVisibilityDropdownSection';
|
||||||
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
|
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
|
||||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
|
||||||
import { useTableColumns } from '../../hooks/useTableColumns';
|
type RecordIndexOptionsMenu = 'fields';
|
||||||
import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
|
|
||||||
|
|
||||||
type TableOptionsMenu = 'fields';
|
type RecordIndexOptionsDropdownContentProps = {
|
||||||
|
recordIndexId: string;
|
||||||
|
objectNameSingular: string;
|
||||||
|
viewType: ViewType;
|
||||||
|
};
|
||||||
|
|
||||||
export const TableOptionsDropdownContent = ({
|
export const RecordIndexOptionsDropdownContent = ({
|
||||||
onImport,
|
viewType,
|
||||||
recordTableId,
|
recordIndexId,
|
||||||
}: {
|
objectNameSingular,
|
||||||
onImport?: () => void;
|
}: RecordIndexOptionsDropdownContentProps) => {
|
||||||
recordTableId: string;
|
const { setViewEditMode, handleViewNameSubmit } = useViewBar({
|
||||||
}) => {
|
viewBarId: recordIndexId,
|
||||||
const { setViewEditMode, handleViewNameSubmit } = useViewBar();
|
});
|
||||||
const { viewEditModeState, currentViewSelector } = useViewScopedStates();
|
const { viewEditModeState, currentViewSelector } = useViewScopedStates();
|
||||||
|
|
||||||
const viewEditMode = useRecoilValue(viewEditModeState);
|
const viewEditMode = useRecoilValue(viewEditModeState);
|
||||||
const currentView = useRecoilValue(currentViewSelector);
|
const currentView = useRecoilValue(currentViewSelector);
|
||||||
const { closeDropdown } = useDropdown(TableOptionsDropdownId);
|
const { closeDropdown } = useDropdown(RECORD_INDEX_OPTIONS_DROPDOWN_ID);
|
||||||
|
|
||||||
const [currentMenu, setCurrentMenu] = useState<TableOptionsMenu | undefined>(
|
const [currentMenu, setCurrentMenu] = useState<
|
||||||
undefined,
|
RecordIndexOptionsMenu | undefined
|
||||||
);
|
>(undefined);
|
||||||
|
|
||||||
|
const resetMenu = () => setCurrentMenu(undefined);
|
||||||
|
|
||||||
const viewEditInputRef = useRef<HTMLInputElement>(null);
|
const viewEditInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const { getHiddenTableColumnsSelector, getVisibleTableColumnsSelector } =
|
const handleSelectMenu = (option: RecordIndexOptionsMenu) => {
|
||||||
useRecordTableStates(recordTableId);
|
|
||||||
|
|
||||||
const hiddenTableColumns = useRecoilValue(getHiddenTableColumnsSelector());
|
|
||||||
const visibleTableColumns = useRecoilValue(getVisibleTableColumnsSelector());
|
|
||||||
|
|
||||||
const { handleColumnVisibilityChange, handleColumnReorder } = useTableColumns(
|
|
||||||
{ recordTableId },
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelectMenu = (option: TableOptionsMenu) => {
|
|
||||||
const name = viewEditInputRef.current?.value;
|
|
||||||
handleViewNameSubmit(name);
|
|
||||||
setCurrentMenu(option);
|
setCurrentMenu(option);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReorderField: OnDragEndResponder = useCallback(
|
|
||||||
(result) => {
|
|
||||||
if (
|
|
||||||
!result.destination ||
|
|
||||||
result.destination.index === 1 ||
|
|
||||||
result.source.index === 1
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const reorderFields = [...visibleTableColumns];
|
|
||||||
const [removed] = reorderFields.splice(result.source.index - 1, 1);
|
|
||||||
reorderFields.splice(result.destination.index - 1, 0, removed);
|
|
||||||
|
|
||||||
handleColumnReorder(reorderFields);
|
|
||||||
},
|
|
||||||
[visibleTableColumns, handleColumnReorder],
|
|
||||||
);
|
|
||||||
|
|
||||||
const resetMenu = () => setCurrentMenu(undefined);
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
[Key.Escape],
|
[Key.Escape],
|
||||||
() => {
|
() => {
|
||||||
@ -99,6 +74,41 @@ export const TableOptionsDropdownContent = ({
|
|||||||
TableOptionsHotkeyScope.Dropdown,
|
TableOptionsHotkeyScope.Dropdown,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
handleColumnVisibilityChange,
|
||||||
|
handleReorderColumns,
|
||||||
|
visibleTableColumns,
|
||||||
|
hiddenTableColumns,
|
||||||
|
} = useRecordIndexOptionsForTable(recordIndexId);
|
||||||
|
|
||||||
|
const {
|
||||||
|
visibleBoardFields,
|
||||||
|
hiddenBoardFields,
|
||||||
|
handleReorderBoardFields,
|
||||||
|
handleBoardFieldVisibilityChange,
|
||||||
|
} = useRecordIndexOptionsForBoard({
|
||||||
|
objectNameSingular,
|
||||||
|
viewBarId: recordIndexId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const visibleRecordFields =
|
||||||
|
viewType === ViewType.Kanban ? visibleBoardFields : visibleTableColumns;
|
||||||
|
|
||||||
|
const hiddenRecordFields =
|
||||||
|
viewType === ViewType.Kanban ? hiddenBoardFields : hiddenTableColumns;
|
||||||
|
|
||||||
|
const handleReorderFields =
|
||||||
|
viewType === ViewType.Kanban
|
||||||
|
? handleReorderBoardFields
|
||||||
|
: handleReorderColumns;
|
||||||
|
|
||||||
|
const handleChangeFieldVisibility =
|
||||||
|
viewType === ViewType.Kanban
|
||||||
|
? handleBoardFieldVisibilityChange
|
||||||
|
: handleColumnVisibilityChange;
|
||||||
|
|
||||||
|
const { handleImport } = useRecordIndexOptionsImport({ objectNameSingular });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!currentMenu && (
|
{!currentMenu && (
|
||||||
@ -122,9 +132,9 @@ export const TableOptionsDropdownContent = ({
|
|||||||
LeftIcon={IconTag}
|
LeftIcon={IconTag}
|
||||||
text="Fields"
|
text="Fields"
|
||||||
/>
|
/>
|
||||||
{onImport && (
|
{handleImport && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={onImport}
|
onClick={() => handleImport()}
|
||||||
LeftIcon={IconFileImport}
|
LeftIcon={IconFileImport}
|
||||||
text="Import"
|
text="Import"
|
||||||
/>
|
/>
|
||||||
@ -140,20 +150,20 @@ export const TableOptionsDropdownContent = ({
|
|||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<ViewFieldsVisibilityDropdownSection
|
<ViewFieldsVisibilityDropdownSection
|
||||||
title="Visible"
|
title="Visible"
|
||||||
fields={visibleTableColumns}
|
fields={visibleRecordFields}
|
||||||
isVisible={true}
|
isVisible={true}
|
||||||
onVisibilityChange={handleColumnVisibilityChange}
|
onVisibilityChange={handleChangeFieldVisibility}
|
||||||
isDraggable={true}
|
isDraggable={true}
|
||||||
onDragEnd={handleReorderField}
|
onDragEnd={handleReorderFields}
|
||||||
/>
|
/>
|
||||||
{hiddenTableColumns.length > 0 && (
|
{hiddenRecordFields.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<ViewFieldsVisibilityDropdownSection
|
<ViewFieldsVisibilityDropdownSection
|
||||||
title="Hidden"
|
title="Hidden"
|
||||||
fields={hiddenTableColumns}
|
fields={hiddenRecordFields}
|
||||||
isVisible={false}
|
isVisible={false}
|
||||||
onVisibilityChange={handleColumnVisibilityChange}
|
onVisibilityChange={handleChangeFieldVisibility}
|
||||||
isDraggable={false}
|
isDraggable={false}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export const RECORD_INDEX_BOARD_OPTIONS_DROPDOWN_ID =
|
||||||
|
'record-index-table-options-dropdown-id';
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export const RECORD_INDEX_OPTIONS_DROPDOWN_ID =
|
||||||
|
'record-index-options-dropdown-id';
|
||||||
@ -0,0 +1,156 @@
|
|||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { OnDragEndResponder } from '@hello-pangea/dnd';
|
||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { mapBoardFieldDefinitionsToViewFields } from '@/companies/utils/mapBoardFieldDefinitionsToViewFields';
|
||||||
|
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||||
|
import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly';
|
||||||
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/states/recordIndexFieldDefinitionsState';
|
||||||
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
|
import { useViewFields } from '@/views/hooks/internal/useViewFields';
|
||||||
|
|
||||||
|
type useRecordIndexOptionsForBoardParams = {
|
||||||
|
objectNameSingular: string;
|
||||||
|
viewBarId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRecordIndexOptionsForBoard = ({
|
||||||
|
objectNameSingular,
|
||||||
|
viewBarId,
|
||||||
|
}: useRecordIndexOptionsForBoardParams) => {
|
||||||
|
const [recordIndexFieldDefinitions, setRecordIndexFieldDefinitions] =
|
||||||
|
useRecoilState(recordIndexFieldDefinitionsState);
|
||||||
|
|
||||||
|
const { persistViewFields } = useViewFields(viewBarId);
|
||||||
|
|
||||||
|
const { objectMetadataItem } = useObjectMetadataItemOnly({
|
||||||
|
objectNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { columnDefinitions } =
|
||||||
|
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||||
|
|
||||||
|
const visibleBoardFields = useMemo(
|
||||||
|
() =>
|
||||||
|
columnDefinitions.filter((columnDefinition) => {
|
||||||
|
return recordIndexFieldDefinitions.some(
|
||||||
|
(existingRecordFieldDefinition) => {
|
||||||
|
return (
|
||||||
|
columnDefinition.fieldMetadataId ===
|
||||||
|
existingRecordFieldDefinition.fieldMetadataId &&
|
||||||
|
existingRecordFieldDefinition.isVisible
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
[columnDefinitions, recordIndexFieldDefinitions],
|
||||||
|
);
|
||||||
|
|
||||||
|
const hiddenBoardFields = useMemo(
|
||||||
|
() =>
|
||||||
|
columnDefinitions.filter((columnDefinition) => {
|
||||||
|
return !recordIndexFieldDefinitions.some(
|
||||||
|
(existingRecordFieldDefinition) => {
|
||||||
|
return (
|
||||||
|
columnDefinition.fieldMetadataId ===
|
||||||
|
existingRecordFieldDefinition.fieldMetadataId &&
|
||||||
|
existingRecordFieldDefinition.isVisible
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
[columnDefinitions, recordIndexFieldDefinitions],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleReorderBoardFields: OnDragEndResponder = useCallback(
|
||||||
|
(result) => {
|
||||||
|
if (
|
||||||
|
!result.destination ||
|
||||||
|
result.destination.index === 1 ||
|
||||||
|
result.source.index === 1
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reorderFields = [...recordIndexFieldDefinitions];
|
||||||
|
const [removed] = reorderFields.splice(result.source.index - 1, 1);
|
||||||
|
reorderFields.splice(result.destination.index - 1, 0, removed);
|
||||||
|
|
||||||
|
const updatedFields = reorderFields.map((field, index) => ({
|
||||||
|
...field,
|
||||||
|
position: index,
|
||||||
|
}));
|
||||||
|
|
||||||
|
setRecordIndexFieldDefinitions(updatedFields);
|
||||||
|
persistViewFields(mapBoardFieldDefinitionsToViewFields(updatedFields));
|
||||||
|
},
|
||||||
|
[
|
||||||
|
persistViewFields,
|
||||||
|
recordIndexFieldDefinitions,
|
||||||
|
setRecordIndexFieldDefinitions,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Todo : this seems over complex and should at least be extracted to an util with unit test.
|
||||||
|
// Let's refactor this as we introduce the new viewBar
|
||||||
|
const handleBoardFieldVisibilityChange = useCallback(
|
||||||
|
async (
|
||||||
|
updatedFieldDefinition: Omit<
|
||||||
|
ColumnDefinition<FieldMetadata>,
|
||||||
|
'size' | 'position'
|
||||||
|
>,
|
||||||
|
) => {
|
||||||
|
const isNewViewField = !recordIndexFieldDefinitions.some(
|
||||||
|
(fieldDefinition) =>
|
||||||
|
fieldDefinition.fieldMetadataId ===
|
||||||
|
updatedFieldDefinition.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
let updatedFieldsDefinitions: ColumnDefinition<FieldMetadata>[];
|
||||||
|
|
||||||
|
if (isNewViewField) {
|
||||||
|
const correspondingFieldDefinition = columnDefinitions.find(
|
||||||
|
(availableTableColumn) =>
|
||||||
|
availableTableColumn.fieldMetadataId ===
|
||||||
|
updatedFieldDefinition.fieldMetadataId,
|
||||||
|
);
|
||||||
|
if (!correspondingFieldDefinition) return;
|
||||||
|
|
||||||
|
updatedFieldsDefinitions = [
|
||||||
|
...recordIndexFieldDefinitions,
|
||||||
|
{ ...correspondingFieldDefinition, isVisible: true },
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
updatedFieldsDefinitions = recordIndexFieldDefinitions.map(
|
||||||
|
(exitingFieldDefinition) =>
|
||||||
|
exitingFieldDefinition.fieldMetadataId ===
|
||||||
|
updatedFieldDefinition.fieldMetadataId
|
||||||
|
? {
|
||||||
|
...exitingFieldDefinition,
|
||||||
|
isVisible: !updatedFieldDefinition.isVisible,
|
||||||
|
}
|
||||||
|
: exitingFieldDefinition,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setRecordIndexFieldDefinitions(updatedFieldsDefinitions);
|
||||||
|
persistViewFields(
|
||||||
|
mapBoardFieldDefinitionsToViewFields(updatedFieldsDefinitions),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[
|
||||||
|
recordIndexFieldDefinitions,
|
||||||
|
setRecordIndexFieldDefinitions,
|
||||||
|
persistViewFields,
|
||||||
|
columnDefinitions,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleReorderBoardFields,
|
||||||
|
handleBoardFieldVisibilityChange,
|
||||||
|
visibleBoardFields,
|
||||||
|
hiddenBoardFields,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import { OnDragEndResponder } from '@hello-pangea/dnd';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||||
|
import { useTableColumns } from '@/object-record/record-table/hooks/useTableColumns';
|
||||||
|
|
||||||
|
export const useRecordIndexOptionsForTable = (recordTableId: string) => {
|
||||||
|
const { getHiddenTableColumnsSelector, getVisibleTableColumnsSelector } =
|
||||||
|
useRecordTableStates(recordTableId);
|
||||||
|
|
||||||
|
const hiddenTableColumns = useRecoilValue(getHiddenTableColumnsSelector());
|
||||||
|
const visibleTableColumns = useRecoilValue(getVisibleTableColumnsSelector());
|
||||||
|
|
||||||
|
const { handleColumnVisibilityChange, handleColumnReorder } = useTableColumns(
|
||||||
|
{ recordTableId: recordTableId },
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleReorderColumns: OnDragEndResponder = useCallback(
|
||||||
|
(result) => {
|
||||||
|
if (
|
||||||
|
!result.destination ||
|
||||||
|
result.destination.index === 1 ||
|
||||||
|
result.source.index === 1
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reorderFields = [...visibleTableColumns];
|
||||||
|
const [removed] = reorderFields.splice(result.source.index - 1, 1);
|
||||||
|
reorderFields.splice(result.destination.index - 1, 0, removed);
|
||||||
|
|
||||||
|
handleColumnReorder(reorderFields);
|
||||||
|
},
|
||||||
|
[visibleTableColumns, handleColumnReorder],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleReorderColumns,
|
||||||
|
handleColumnVisibilityChange,
|
||||||
|
visibleTableColumns,
|
||||||
|
hiddenTableColumns,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
||||||
|
|
||||||
|
type useRecordIndexOptionsImportParams = {
|
||||||
|
objectNameSingular: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRecordIndexOptionsImport = ({
|
||||||
|
objectNameSingular,
|
||||||
|
}: useRecordIndexOptionsImportParams) => {
|
||||||
|
const { openPersonSpreadsheetImport } = useSpreadsheetPersonImport();
|
||||||
|
const { openCompanySpreadsheetImport } = useSpreadsheetCompanyImport();
|
||||||
|
|
||||||
|
const handleImport =
|
||||||
|
CoreObjectNameSingular.Company === objectNameSingular
|
||||||
|
? openCompanySpreadsheetImport
|
||||||
|
: CoreObjectNameSingular.Person === objectNameSingular
|
||||||
|
? openPersonSpreadsheetImport
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return { handleImport };
|
||||||
|
};
|
||||||
@ -1,2 +0,0 @@
|
|||||||
// We should either apply the constant all caps case or maybe define a more general enum to store those ids ?
|
|
||||||
export const TableOptionsDropdownId = 'table-options-dropdown-id';
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|
||||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
|
||||||
|
|
||||||
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
|
|
||||||
import { TableOptionsHotkeyScope } from '../../types/TableOptionsHotkeyScope';
|
|
||||||
|
|
||||||
import { TableOptionsDropdownButton } from './TableOptionsDropdownButton';
|
|
||||||
import { TableOptionsDropdownContent } from './TableOptionsDropdownContent';
|
|
||||||
|
|
||||||
export const TableOptionsDropdown = ({
|
|
||||||
onImport,
|
|
||||||
recordTableId,
|
|
||||||
}: {
|
|
||||||
onImport?: () => void;
|
|
||||||
recordTableId: string;
|
|
||||||
}) => {
|
|
||||||
const { setViewEditMode } = useViewBar();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
dropdownId={TableOptionsDropdownId}
|
|
||||||
clickableComponent={<TableOptionsDropdownButton />}
|
|
||||||
dropdownHotkeyScope={{ scope: TableOptionsHotkeyScope.Dropdown }}
|
|
||||||
dropdownOffset={{ y: 8 }}
|
|
||||||
dropdownComponents={
|
|
||||||
<TableOptionsDropdownContent
|
|
||||||
onImport={onImport}
|
|
||||||
recordTableId={recordTableId}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
onClickOutside={() => setViewEditMode('none')}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,10 +1,11 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { RecordIndexOptionsDropdown } from '@/object-record/record-index/options/components/RecordIndexOptionsDropdown';
|
||||||
|
import { RECORD_INDEX_OPTIONS_DROPDOWN_ID } from '@/object-record/record-index/options/constants/RecordIndexOptionsDropdownId';
|
||||||
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
||||||
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
|
||||||
import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown';
|
|
||||||
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
||||||
import { ViewBar } from '@/views/components/ViewBar';
|
import { ViewBar } from '@/views/components/ViewBar';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -16,7 +17,7 @@ const StyledContainer = styled.div`
|
|||||||
export const SignInBackgroundMockContainer = () => {
|
export const SignInBackgroundMockContainer = () => {
|
||||||
const objectNamePlural = 'companies';
|
const objectNamePlural = 'companies';
|
||||||
const objectNameSingular = 'company';
|
const objectNameSingular = 'company';
|
||||||
const recordTableId = 'sign-up-mock-record-table-id';
|
const recordIndexId = 'sign-up-mock-record-table-id';
|
||||||
const viewBarId = 'companies-mock';
|
const viewBarId = 'companies-mock';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -24,18 +25,22 @@ export const SignInBackgroundMockContainer = () => {
|
|||||||
<ViewBar
|
<ViewBar
|
||||||
viewBarId={viewBarId}
|
viewBarId={viewBarId}
|
||||||
optionsDropdownButton={
|
optionsDropdownButton={
|
||||||
<TableOptionsDropdown recordTableId={recordTableId} />
|
<RecordIndexOptionsDropdown
|
||||||
|
recordIndexId={recordIndexId}
|
||||||
|
objectNameSingular={objectNameSingular}
|
||||||
|
viewType={ViewType.Table}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
optionsDropdownScopeId={TableOptionsDropdownId}
|
optionsDropdownScopeId={RECORD_INDEX_OPTIONS_DROPDOWN_ID}
|
||||||
/>
|
/>
|
||||||
<SignInBackgroundMockContainerEffect
|
<SignInBackgroundMockContainerEffect
|
||||||
objectNamePlural={objectNamePlural}
|
objectNamePlural={objectNamePlural}
|
||||||
recordTableId={recordTableId}
|
recordTableId={recordIndexId}
|
||||||
viewId={viewBarId}
|
viewId={viewBarId}
|
||||||
/>
|
/>
|
||||||
<RecordTableWithWrappers
|
<RecordTableWithWrappers
|
||||||
objectNameSingular={objectNameSingular}
|
objectNameSingular={objectNameSingular}
|
||||||
recordTableId={recordTableId}
|
recordTableId={recordIndexId}
|
||||||
viewBarId={viewBarId}
|
viewBarId={viewBarId}
|
||||||
createRecord={async () => {}}
|
createRecord={async () => {}}
|
||||||
updateRecordMutation={() => {}}
|
updateRecordMutation={() => {}}
|
||||||
|
|||||||
Reference in New Issue
Block a user