Add new Record board shell (#3609)

* Add new Record board shell

* Fix
This commit is contained in:
Charles Bochet 2024-01-24 17:47:04 +01:00 committed by GitHub
parent 8ffd958a3c
commit afbb87ae12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 301 additions and 28 deletions

View File

@ -0,0 +1,68 @@
import { useRef } from 'react';
import styled from '@emotion/styled';
import { DragDropContext } from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
import { RecordBoardColumn } from '@/object-record/record-board/record-board-column/components/RecordBoardColumn';
import { RecordBoardScope } from '@/object-record/record-board/scopes/RecordBoardScope';
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
export type RecordBoardProps = {
recordBoardId: string;
};
const StyledContainer = styled.div`
border-top: 1px solid ${({ theme }) => theme.border.color.light};
display: flex;
flex: 1;
flex-direction: row;
margin-left: ${({ theme }) => theme.spacing(2)};
margin-right: ${({ theme }) => theme.spacing(2)};
`;
const StyledWrapper = styled.div`
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
position: relative;
width: 100%;
`;
const StyledBoardHeader = styled.div`
position: relative;
z-index: 1;
`;
export const RecordBoard = ({ recordBoardId }: RecordBoardProps) => {
const boardRef = useRef<HTMLDivElement>(null);
return (
<RecordBoardScope
recordBoardScopeId={recordBoardId}
onColumnsChange={() => {}}
onFieldsChange={() => {}}
>
<StyledWrapper>
<StyledBoardHeader />
<ScrollWrapper>
<StyledContainer ref={boardRef}>
<DragDropContext onDragEnd={() => {}}>
{[].map((column) => (
<RecordBoardColumn
key={'a'}
recordBoardColumnId={'a'}
columnDefinition={column}
/>
))}
</DragDropContext>
</StyledContainer>
</ScrollWrapper>
<DragSelect
dragSelectable={boardRef}
onDragSelectionChange={() => {}}
/>
</StyledWrapper>
</RecordBoardScope>
);
};

View File

@ -0,0 +1,11 @@
import { createContext } from 'react';
import { BoardColumnDefinition } from '@/object-record/record-board-deprecated/types/BoardColumnDefinition';
type RecordBoardColumnContextProps = {
id: string;
columnDefinition: BoardColumnDefinition;
};
export const RecordBoardColumnContext =
createContext<RecordBoardColumnContextProps | null>(null);

View File

@ -0,0 +1,59 @@
import styled from '@emotion/styled';
import { Droppable } from '@hello-pangea/dnd';
import { RecordBoardColumnContext } from '@/object-record/record-board/contexts/RecordBoardColumnContext';
import { RecordBoardColumnCardsContainer } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer';
import { BoardCardIdContext } from '@/object-record/record-board-deprecated/contexts/BoardCardIdContext';
import { BoardColumnDefinition } from '@/object-record/record-board-deprecated/types/BoardColumnDefinition';
const StyledColumn = styled.div<{ isFirstColumn: boolean }>`
background-color: ${({ theme }) => theme.background.primary};
border-left: 1px solid
${({ theme, isFirstColumn }) =>
isFirstColumn ? 'none' : theme.border.color.light};
display: flex;
flex-direction: column;
max-width: 200px;
min-width: 200px;
padding: ${({ theme }) => theme.spacing(2)};
position: relative;
`;
type RecordBoardColumnProps = {
recordBoardColumnId: string;
columnDefinition: BoardColumnDefinition;
};
export const RecordBoardColumn = ({
recordBoardColumnId,
columnDefinition,
}: RecordBoardColumnProps) => {
const isFirstColumn = columnDefinition.position === 0;
return (
<RecordBoardColumnContext.Provider
value={{
id: recordBoardColumnId,
columnDefinition: columnDefinition,
}}
>
<Droppable droppableId={recordBoardColumnId}>
{(droppableProvided) => (
<StyledColumn isFirstColumn={isFirstColumn}>
<RecordBoardColumnCardsContainer
droppableProvided={droppableProvided}
>
{[].map((cardId, _index) => (
<BoardCardIdContext.Provider
value={cardId}
key={cardId}
></BoardCardIdContext.Provider>
))}
</RecordBoardColumnCardsContainer>
</StyledColumn>
)}
</Droppable>
</RecordBoardColumnContext.Provider>
);
};

View File

@ -0,0 +1,34 @@
import React from 'react';
import styled from '@emotion/styled';
import { DroppableProvided } from '@hello-pangea/dnd';
const StyledPlaceholder = styled.div`
min-height: 1px;
`;
const StyledColumnCardsContainer = styled.div`
display: flex;
flex: 1;
flex-direction: column;
`;
type RecordBoardColumnCardsContainerProps = {
children: React.ReactNode;
droppableProvided: DroppableProvided;
};
export const RecordBoardColumnCardsContainer = ({
children,
droppableProvided,
}: RecordBoardColumnCardsContainerProps) => {
return (
<StyledColumnCardsContainer
ref={droppableProvided?.innerRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...droppableProvided?.droppableProps}
>
{children}
<StyledPlaceholder>{droppableProvided?.placeholder}</StyledPlaceholder>
</StyledColumnCardsContainer>
);
};

View File

@ -0,0 +1,32 @@
import { ReactNode } from 'react';
import { FieldDefinition } from '@/object-record/field/types/FieldDefinition';
import { FieldMetadata } from '@/object-record/field/types/FieldMetadata';
import { RecordBoardScopeInternalContext } from '@/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext';
import { RecordBoardColumnDefinition } from '@/object-record/record-board/types/RecordBoardColumnDefinition';
type RecordBoardScopeProps = {
children: ReactNode;
recordBoardScopeId: string;
onFieldsChange: (fields: FieldDefinition<FieldMetadata>[]) => void;
onColumnsChange: (column: RecordBoardColumnDefinition[]) => void;
};
export const RecordBoardScope = ({
children,
recordBoardScopeId,
onColumnsChange,
onFieldsChange,
}: RecordBoardScopeProps) => {
return (
<RecordBoardScopeInternalContext.Provider
value={{
scopeId: recordBoardScopeId,
onColumnsChange,
onFieldsChange,
}}
>
{children}
</RecordBoardScopeInternalContext.Provider>
);
};

View File

@ -0,0 +1,13 @@
import { FieldDefinition } from '@/object-record/field/types/FieldDefinition';
import { FieldMetadata } from '@/object-record/field/types/FieldMetadata';
import { RecordBoardColumnDefinition } from '@/object-record/record-board/types/RecordBoardColumnDefinition';
import { StateScopeMapKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/StateScopeMapKey';
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
type RecordBoardDeprecatedScopeInternalContextProps = StateScopeMapKey & {
onFieldsChange: (fields: FieldDefinition<FieldMetadata>[]) => void;
onColumnsChange: (column: RecordBoardColumnDefinition[]) => void;
};
export const RecordBoardScopeInternalContext =
createScopeInternalContext<RecordBoardDeprecatedScopeInternalContextProps>();

View File

@ -0,0 +1,8 @@
import { ThemeColor } from '@/ui/theme/constants/colors';
export type RecordBoardColumnDefinition = {
id: string;
title: string;
position: number;
colorCode?: ThemeColor;
};

View File

@ -0,0 +1,14 @@
import { RecordBoard } from '@/object-record/record-board/components/RecordBoard';
type RecordIndexBoardContainerProps = {
recordBoardId: string;
viewBarId: string;
objectNamePlural: string;
createRecord: () => Promise<void>;
};
export const RecordIndexBoardContainer = ({
recordBoardId,
}: RecordIndexBoardContainerProps) => {
return <RecordBoard recordBoardId={recordBoardId}></RecordBoard>;
};

View File

@ -0,0 +1,11 @@
type RecordIndexBoardContainerEffectProps = {
objectNamePlural: string;
recordBoardId: string;
viewBarId: string;
};
export const RecordIndexBoardContainerEffect = (
_props: RecordIndexBoardContainerEffectProps,
) => {
return <></>;
};

View File

@ -5,8 +5,10 @@ import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCom
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { RecordIndexBoardContainer } from '@/object-record/record-index/components/RecordIndexBoardContainer';
import { RecordIndexTableContainer } from '@/object-record/record-index/components/RecordIndexTableContainer';
import { RecordIndexViewInitEffect } from '@/object-record/record-index/components/RecordIndexViewInitEffect';
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
import { RecordIndexViewBarEffect } from '@/object-record/record-index/components/RecordIndexViewBarEffect';
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown';
@ -22,6 +24,7 @@ const StyledContainer = styled.div`
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
overflow: auto;
padding-left: ${({ theme }) => theme.table.horizontalCellPadding};
`;
@ -98,19 +101,41 @@ export const RecordIndexContainer = ({
setRecordIndexViewType(viewType);
}}
/>
<RecordIndexViewBarEffect
objectNamePlural={objectNamePlural}
viewBarId={recordIndexId}
/>
</SpreadsheetImportProvider>
{recordIndexViewType === ViewType.Table && (
<RecordIndexTableContainer
recordTableId={recordIndexId}
viewBarId={recordIndexId}
objectNamePlural={objectNamePlural}
createRecord={createRecord}
/>
<>
<RecordIndexTableContainer
recordTableId={recordIndexId}
viewBarId={recordIndexId}
objectNamePlural={objectNamePlural}
createRecord={createRecord}
/>
<RecordIndexTableContainerEffect
objectNamePlural={objectNamePlural}
recordTableId={recordIndexId}
viewBarId={recordIndexId}
/>
</>
)}
{recordIndexViewType === ViewType.Kanban && (
<>
<RecordIndexBoardContainer
recordBoardId={recordIndexId}
viewBarId={recordIndexId}
objectNamePlural={objectNamePlural}
createRecord={createRecord}
/>
<RecordIndexTableContainerEffect
objectNamePlural={objectNamePlural}
recordTableId={recordIndexId}
viewBarId={recordIndexId}
/>
</>
)}
<RecordIndexViewInitEffect
objectNamePlural={objectNamePlural}
viewBarId={recordIndexId}
/>
</StyledContainer>
);
};

View File

@ -1,7 +1,6 @@
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { RecordUpdateHookParams } from '@/object-record/field/contexts/FieldContext';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { RecordTableEffect } from '@/object-record/record-index/components/RecordTableEffect';
import { RecordTableActionBar } from '@/object-record/record-table/action-bar/components/RecordTableActionBar';
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
import { RecordTableContextMenu } from '@/object-record/record-table/context-menu/components/RecordTableContextMenu';
@ -36,11 +35,6 @@ export const RecordIndexTableContainer = ({
return (
<>
<RecordTableEffect
objectNamePlural={objectNamePlural}
recordTableId={recordTableId}
viewBarId={viewBarId}
/>
<RecordTableWithWrappers
recordTableId={recordTableId}
objectNamePlural={objectNamePlural}

View File

@ -8,15 +8,17 @@ import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTabl
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
import { useViewBar } from '@/views/hooks/useViewBar';
export const RecordTableEffect = ({
objectNamePlural,
recordTableId,
viewBarId,
}: {
type RecordIndexTableContainerEffectProps = {
objectNamePlural: string;
recordTableId: string;
viewBarId: string;
}) => {
};
export const RecordIndexTableContainerEffect = ({
objectNamePlural,
recordTableId,
viewBarId,
}: RecordIndexTableContainerEffectProps) => {
const {
setAvailableTableColumns,
setOnEntityCountChange,

View File

@ -5,13 +5,15 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { useViewBar } from '@/views/hooks/useViewBar';
export const RecordIndexViewInitEffect = ({
objectNamePlural,
viewBarId,
}: {
type RecordIndexViewBarEffectProps = {
objectNamePlural: string;
viewBarId: string;
}) => {
};
export const RecordIndexViewBarEffect = ({
objectNamePlural,
viewBarId,
}: RecordIndexViewBarEffectProps) => {
const { objectNameSingular } = useObjectNameSingularFromPlural({
objectNamePlural,
});