Resolve bugs tied to record creations on table (#4011)
* Resolve bugs tied to record creations on table * Fix according to PR * Fix tests
This commit is contained in:
@ -1,6 +1,5 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
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';
|
||||||
@ -16,6 +15,7 @@ import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/s
|
|||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
||||||
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
|
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
|
||||||
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
import { recordIndexSortsState } from '@/object-record/record-index/states/recordIndexSortsState';
|
||||||
|
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
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';
|
||||||
@ -46,10 +46,9 @@ export const RecordIndexContainer = ({
|
|||||||
recordIndexId,
|
recordIndexId,
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
}: RecordIndexContainerProps) => {
|
}: RecordIndexContainerProps) => {
|
||||||
const [recordIndexViewType, setRecordIndexViewType] = useState<
|
const [recordIndexViewType, setRecordIndexViewType] = useRecoilState(
|
||||||
ViewType | undefined
|
recordIndexViewTypeState,
|
||||||
>(undefined);
|
);
|
||||||
|
|
||||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
|
||||||
|
export const recordIndexViewTypeState = atom<ViewType | undefined>({
|
||||||
|
key: 'recordIndexViewTypeState',
|
||||||
|
default: undefined,
|
||||||
|
});
|
||||||
@ -3,7 +3,6 @@ import { RecoilRoot, useRecoilValue } from 'recoil';
|
|||||||
|
|
||||||
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { EntityDeleteContext } from '@/object-record/record-table/contexts/EntityDeleteHookContext';
|
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
||||||
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext';
|
||||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
||||||
@ -23,7 +22,6 @@ jest.mock('@/ui/utilities/hotkey/hooks/useSetHotkeyScope', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const onColumnsChange = jest.fn();
|
const onColumnsChange = jest.fn();
|
||||||
const deleteEntity = jest.fn();
|
|
||||||
const scopeId = 'scopeId';
|
const scopeId = 'scopeId';
|
||||||
|
|
||||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||||
@ -44,9 +42,7 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|||||||
<RecordTableCellContext.Provider
|
<RecordTableCellContext.Provider
|
||||||
value={{ ...recordTableCell, columnIndex: 0 }}
|
value={{ ...recordTableCell, columnIndex: 0 }}
|
||||||
>
|
>
|
||||||
<EntityDeleteContext.Provider value={deleteEntity}>
|
{children}
|
||||||
{children}
|
|
||||||
</EntityDeleteContext.Provider>
|
|
||||||
</RecordTableCellContext.Provider>
|
</RecordTableCellContext.Provider>
|
||||||
</RecordTableRowContext.Provider>
|
</RecordTableRowContext.Provider>
|
||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
@ -86,6 +82,5 @@ describe('useCloseRecordTableCell', () => {
|
|||||||
expect(result.current.isDragSelectionStartEnabled()).toBe(true);
|
expect(result.current.isDragSelectionStartEnabled()).toBe(true);
|
||||||
expect(result.current.isTableCellInEditMode).toBe(false);
|
expect(result.current.isTableCellInEditMode).toBe(false);
|
||||||
expect(setHotkeyScope).toHaveBeenCalledWith('table-soft-focus');
|
expect(setHotkeyScope).toHaveBeenCalledWith('table-soft-focus');
|
||||||
expect(deleteEntity).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,59 +1,19 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
|
||||||
import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecordFieldInput';
|
|
||||||
import { EntityDeleteContext } from '@/object-record/record-table/contexts/EntityDeleteHookContext';
|
|
||||||
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
|
|
||||||
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
|
|
||||||
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
|
||||||
|
|
||||||
import { useCloseCurrentTableCellInEditMode } from '../../hooks/internal/useCloseCurrentTableCellInEditMode';
|
import { useCloseCurrentTableCellInEditMode } from '../../hooks/internal/useCloseCurrentTableCellInEditMode';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
|
|
||||||
export const useCloseRecordTableCell = () => {
|
export const useCloseRecordTableCell = () => {
|
||||||
const { getTableRowIdsState } = useRecordTableStates();
|
|
||||||
const { columnIndex } = useContext(RecordTableCellContext);
|
|
||||||
const { entityId, fieldDefinition } = useContext(FieldContext);
|
|
||||||
const deleteOneRecord = useContext(EntityDeleteContext);
|
|
||||||
|
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
const { setDragSelectionStartEnabled } = useDragSelect();
|
const { setDragSelectionStartEnabled } = useDragSelect();
|
||||||
|
|
||||||
const closeCurrentTableCellInEditMode = useCloseCurrentTableCellInEditMode();
|
const closeCurrentTableCellInEditMode = useCloseCurrentTableCellInEditMode();
|
||||||
|
|
||||||
const {
|
|
||||||
getDraftValueSelector: getFieldInputDraftValueSelector,
|
|
||||||
isDraftValueEmpty: isCurrentFieldInputValueEmpty,
|
|
||||||
} = useRecordFieldInput(
|
|
||||||
`${entityId}-${fieldDefinition?.metadata?.fieldName}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentFieldInputDraftValue = useRecoilValue(
|
|
||||||
getFieldInputDraftValueSelector(),
|
|
||||||
);
|
|
||||||
|
|
||||||
const isFirstColumnCell = columnIndex === 0;
|
|
||||||
|
|
||||||
const deleteRow = useRecoilCallback(({ snapshot }) => async () => {
|
|
||||||
const tableRowIds = getSnapshotValue(snapshot, getTableRowIdsState());
|
|
||||||
|
|
||||||
await deleteOneRecord(tableRowIds[0]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const closeTableCell = async () => {
|
const closeTableCell = async () => {
|
||||||
setDragSelectionStartEnabled(true);
|
setDragSelectionStartEnabled(true);
|
||||||
closeCurrentTableCellInEditMode();
|
closeCurrentTableCellInEditMode();
|
||||||
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
||||||
|
|
||||||
if (
|
|
||||||
isFirstColumnCell &&
|
|
||||||
isCurrentFieldInputValueEmpty(currentFieldInputDraftValue)
|
|
||||||
) {
|
|
||||||
await deleteRow();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
|
||||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer';
|
import { RecordIndexContainer } from '@/object-record/record-index/components/RecordIndexContainer';
|
||||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell';
|
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell';
|
||||||
import { useSelectedTableCellEditMode } from '@/object-record/record-table/record-table-cell/hooks/useSelectedTableCellEditMode';
|
import { useSelectedTableCellEditMode } from '@/object-record/record-table/record-table-cell/hooks/useSelectedTableCellEditMode';
|
||||||
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
|
|
||||||
import { PageAddButton } from '@/ui/layout/page/PageAddButton';
|
|
||||||
import { PageBody } from '@/ui/layout/page/PageBody';
|
import { PageBody } from '@/ui/layout/page/PageBody';
|
||||||
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
||||||
import { PageHeader } from '@/ui/layout/page/PageHeader';
|
|
||||||
import { PageHotkeysEffect } from '@/ui/layout/page/PageHotkeysEffect';
|
|
||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
|
import { RecordIndexPageHeader } from '~/pages/object-record/RecordIndexPageHeader';
|
||||||
|
|
||||||
const StyledIndexContainer = styled.div`
|
const StyledIndexContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -28,20 +24,11 @@ export const RecordIndexPage = () => {
|
|||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { findObjectMetadataItemByNamePlural } =
|
|
||||||
useObjectMetadataItemForSettings();
|
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
|
||||||
const Icon = getIcon(
|
|
||||||
findObjectMetadataItemByNamePlural(objectNamePlural)?.icon,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { createOneRecord: createOneObject } = useCreateOneRecord({
|
const { createOneRecord: createOneObject } = useCreateOneRecord({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const recordIndexId = objectNamePlural ?? '';
|
const recordIndexId = objectNamePlural ?? '';
|
||||||
|
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
|
||||||
const { setSelectedTableCellEditMode } = useSelectedTableCellEditMode({
|
const { setSelectedTableCellEditMode } = useSelectedTableCellEditMode({
|
||||||
@ -49,7 +36,9 @@ export const RecordIndexPage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleAddButtonClick = async () => {
|
const handleAddButtonClick = async () => {
|
||||||
await createOneObject?.({});
|
await createOneObject?.({
|
||||||
|
position: 0,
|
||||||
|
});
|
||||||
|
|
||||||
setSelectedTableCellEditMode(0, 0);
|
setSelectedTableCellEditMode(0, 0);
|
||||||
setHotkeyScope(DEFAULT_CELL_SCOPE.scope, DEFAULT_CELL_SCOPE.customScopes);
|
setHotkeyScope(DEFAULT_CELL_SCOPE.scope, DEFAULT_CELL_SCOPE.customScopes);
|
||||||
@ -57,15 +46,7 @@ export const RecordIndexPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<PageHeader
|
<RecordIndexPageHeader createRecord={handleAddButtonClick} />
|
||||||
title={
|
|
||||||
objectNamePlural.charAt(0).toUpperCase() + objectNamePlural.slice(1)
|
|
||||||
}
|
|
||||||
Icon={Icon}
|
|
||||||
>
|
|
||||||
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
|
|
||||||
<PageAddButton onClick={handleAddButtonClick} />
|
|
||||||
</PageHeader>
|
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<StyledIndexContainer>
|
<StyledIndexContainer>
|
||||||
<RecordIndexContainer
|
<RecordIndexContainer
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
||||||
|
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||||
|
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
|
||||||
|
import { PageAddButton } from '@/ui/layout/page/PageAddButton';
|
||||||
|
import { PageHeader } from '@/ui/layout/page/PageHeader';
|
||||||
|
import { PageHotkeysEffect } from '@/ui/layout/page/PageHotkeysEffect';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
|
type RecordIndexPageHeaderProps = {
|
||||||
|
createRecord: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RecordIndexPageHeader = ({
|
||||||
|
createRecord,
|
||||||
|
}: RecordIndexPageHeaderProps) => {
|
||||||
|
const objectNamePlural = useParams().objectNamePlural ?? '';
|
||||||
|
|
||||||
|
const { findObjectMetadataItemByNamePlural } =
|
||||||
|
useObjectMetadataItemForSettings();
|
||||||
|
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
const Icon = getIcon(
|
||||||
|
findObjectMetadataItemByNamePlural(objectNamePlural)?.icon,
|
||||||
|
);
|
||||||
|
|
||||||
|
const recordIndexViewType = useRecoilValue(recordIndexViewTypeState);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageHeader title={capitalize(objectNamePlural)} Icon={Icon}>
|
||||||
|
<PageHotkeysEffect onAddButtonClick={createRecord} />
|
||||||
|
{recordIndexViewType === ViewType.Table && (
|
||||||
|
<PageAddButton onClick={createRecord} />
|
||||||
|
)}
|
||||||
|
</PageHeader>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -12,6 +12,7 @@ export const companyPrefillData = async (
|
|||||||
'domainName',
|
'domainName',
|
||||||
'address',
|
'address',
|
||||||
'employees',
|
'employees',
|
||||||
|
'position',
|
||||||
])
|
])
|
||||||
.orIgnore()
|
.orIgnore()
|
||||||
.values([
|
.values([
|
||||||
@ -20,30 +21,35 @@ export const companyPrefillData = async (
|
|||||||
domainName: 'airbnb.com',
|
domainName: 'airbnb.com',
|
||||||
address: 'San Francisco',
|
address: 'San Francisco',
|
||||||
employees: 5000,
|
employees: 5000,
|
||||||
|
position: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Qonto',
|
name: 'Qonto',
|
||||||
domainName: 'qonto.com',
|
domainName: 'qonto.com',
|
||||||
address: 'San Francisco',
|
address: 'San Francisco',
|
||||||
employees: 800,
|
employees: 800,
|
||||||
|
position: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Stripe',
|
name: 'Stripe',
|
||||||
domainName: 'stripe.com',
|
domainName: 'stripe.com',
|
||||||
address: 'San Francisco',
|
address: 'San Francisco',
|
||||||
employees: 8000,
|
employees: 8000,
|
||||||
|
position: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Figma',
|
name: 'Figma',
|
||||||
domainName: 'figma.com',
|
domainName: 'figma.com',
|
||||||
address: 'San Francisco',
|
address: 'San Francisco',
|
||||||
employees: 800,
|
employees: 800,
|
||||||
|
position: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Notion',
|
name: 'Notion',
|
||||||
domainName: 'notion.com',
|
domainName: 'notion.com',
|
||||||
address: 'San Francisco',
|
address: 'San Francisco',
|
||||||
employees: 400,
|
employees: 400,
|
||||||
|
position: 5,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
.returning('*')
|
.returning('*')
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user