diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnDropdownMenu.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnDropdownMenu.tsx
index e08feba7a50d..ef129890ad02 100644
--- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnDropdownMenu.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnDropdownMenu.tsx
@@ -1,5 +1,5 @@
-import { useCallback, useContext, useRef } from 'react';
import styled from '@emotion/styled';
+import { useCallback, useContext, useRef } from 'react';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx
index 89ea3debc157..a730766c5ad3 100644
--- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnHeader.tsx
@@ -1,11 +1,16 @@
import styled from '@emotion/styled';
import { useContext, useState } from 'react';
-import { IconDotsVertical, Tag } from 'twenty-ui';
+import { IconDotsVertical, IconPlus, Tag } from 'twenty-ui';
+import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
+import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
import { RecordBoardColumnDropdownMenu } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnDropdownMenu';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
+import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
+import { useAddNewOpportunity } from '@/object-record/record-board/record-board-column/hooks/useAddNewOpportunity';
import { RecordBoardColumnHotkeyScope } from '@/object-record/record-board/types/BoardColumnHotkeyScope';
import { RecordBoardColumnDefinitionType } from '@/object-record/record-board/types/RecordBoardColumnDefinition';
+import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
@@ -38,11 +43,25 @@ const StyledHeaderActions = styled.div`
display: flex;
margin-left: auto;
`;
+const StyledHeaderContainer = styled.div`
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
+const StyledLeftContainer = styled.div`
+ align-items: center;
+ display: flex;
+`;
+
+const StyledRightContainer = styled.div`
+ align-items: center;
+ display: flex;
+`;
export const RecordBoardColumnHeader = () => {
const [isBoardColumnMenuOpen, setIsBoardColumnMenuOpen] = useState(false);
const [isHeaderHovered, setIsHeaderHovered] = useState(false);
-
+ const { objectMetadataItem } = useContext(RecordBoardContext);
const { columnDefinition, recordCount } = useContext(
RecordBoardColumnContext,
);
@@ -69,42 +88,75 @@ export const RecordBoardColumnHeader = () => {
const boardColumnTotal = 0;
+ const {
+ isCreatingCard,
+ handleAddNewOpportunityClick,
+ handleCancel,
+ handleEntitySelect,
+ } = useAddNewOpportunity('first');
+ const { handleAddNewCardClick } = useAddNewCard('first');
+
+ const isOpportunity =
+ objectMetadataItem.nameSingular === CoreObjectNameSingular.Opportunity;
+
+ const handleClick = isOpportunity
+ ? handleAddNewOpportunityClick
+ : () => {
+ handleAddNewCardClick();
+ };
+
return (
<>
setIsHeaderHovered(true)}
onMouseLeave={() => setIsHeaderHovered(false)}
>
-
- {!!boardColumnTotal && ${boardColumnTotal}}
- {recordCount}
- {isHeaderHovered && columnDefinition.actions.length > 0 && (
-
-
+
+
-
- )}
+ {!!boardColumnTotal && (
+ ${boardColumnTotal}
+ )}
+ {recordCount}
+
+
+ {isHeaderHovered && (
+
+ {columnDefinition.actions.length > 0 && (
+
+ )}
+
+
+
+ )}
+
+
{isBoardColumnMenuOpen && columnDefinition.actions.length > 0 && (
{
stageId={columnDefinition.id}
/>
)}
+ {isCreatingCard && (
+
+ )}
>
);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton.tsx
index 62ce7d5f5a9b..c12e0c492374 100644
--- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewButton.tsx
@@ -1,10 +1,8 @@
-import { useContext } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconPlus } from 'twenty-ui';
-import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
-import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
+import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
const StyledButton = styled.button`
align-items: center;
@@ -25,19 +23,9 @@ const StyledButton = styled.button`
export const RecordBoardColumnNewButton = () => {
const theme = useTheme();
- const { columnDefinition } = useContext(RecordBoardColumnContext);
- const { createOneRecord, selectFieldMetadataItem } =
- useContext(RecordBoardContext);
-
- const onNewClick = () => {
- createOneRecord({
- [selectFieldMetadataItem.name]: columnDefinition.value,
- position: 'last',
- });
- };
-
+ const { handleAddNewCardClick } = useAddNewCard('last');
return (
-
+
New
diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunityButton.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunityButton.tsx
index d085c69e993b..6464948dcfcc 100644
--- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunityButton.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnNewOpportunityButton.tsx
@@ -1,16 +1,10 @@
-import { useCallback, useContext, useState } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconPlus } from 'twenty-ui';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
-import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
-import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
+import { useAddNewOpportunity } from '@/object-record/record-board/record-board-column/hooks/useAddNewOpportunity';
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
-import { useEntitySelectSearch } from '@/object-record/relation-picker/hooks/useEntitySelectSearch';
-import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
-import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
-import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
const StyledButton = styled.button`
align-items: center;
@@ -30,52 +24,13 @@ const StyledButton = styled.button`
`;
export const RecordBoardColumnNewOpportunityButton = () => {
- const [isCreatingCard, setIsCreatingCard] = useState(false);
-
const theme = useTheme();
- const { columnDefinition } = useContext(RecordBoardColumnContext);
- const { createOneRecord, selectFieldMetadataItem } =
- useContext(RecordBoardContext);
-
const {
- goBackToPreviousHotkeyScope,
- setHotkeyScopeAndMemorizePreviousScope,
- } = usePreviousHotkeyScope();
-
- const { resetSearchFilter } = useEntitySelectSearch({
- relationPickerScopeId: 'relation-picker',
- });
-
- const handleEntitySelect = (company?: EntityForSelect) => {
- setIsCreatingCard(false);
- goBackToPreviousHotkeyScope();
- resetSearchFilter();
-
- if (!company) {
- return;
- }
-
- createOneRecord({
- name: company.name,
- companyId: company.id,
- position: 'last',
- [selectFieldMetadataItem.name]: columnDefinition.value,
- });
- };
-
- const handleNewClick = useCallback(() => {
- setIsCreatingCard(true);
- setHotkeyScopeAndMemorizePreviousScope(
- RelationPickerHotkeyScope.RelationPicker,
- );
- }, [setIsCreatingCard, setHotkeyScopeAndMemorizePreviousScope]);
-
- const handleCancel = () => {
- resetSearchFilter();
- goBackToPreviousHotkeyScope();
- setIsCreatingCard(false);
- };
-
+ isCreatingCard,
+ handleAddNewOpportunityClick,
+ handleCancel,
+ handleEntitySelect,
+ } = useAddNewOpportunity('last');
return (
<>
{isCreatingCard ? (
@@ -88,7 +43,7 @@ export const RecordBoardColumnNewOpportunityButton = () => {
selectedRelationRecordIds={[]}
/>
) : (
-
+
New
diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewCard.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewCard.ts
new file mode 100644
index 000000000000..24cb1e158548
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewCard.ts
@@ -0,0 +1,20 @@
+import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
+import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
+import { useContext } from 'react';
+
+export const useAddNewCard = (position: string) => {
+ const { columnDefinition } = useContext(RecordBoardColumnContext);
+ const { createOneRecord, selectFieldMetadataItem } =
+ useContext(RecordBoardContext);
+
+ const handleAddNewCardClick = () => {
+ createOneRecord({
+ [selectFieldMetadataItem.name]: columnDefinition.value,
+ position: position,
+ });
+ };
+
+ return {
+ handleAddNewCardClick,
+ };
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewOpportunity.ts b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewOpportunity.ts
new file mode 100644
index 000000000000..230eedb281fb
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/hooks/useAddNewOpportunity.ts
@@ -0,0 +1,68 @@
+import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext';
+import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
+import { useEntitySelectSearch } from '@/object-record/relation-picker/hooks/useEntitySelectSearch';
+import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
+import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
+import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
+import { useCallback, useContext, useState } from 'react';
+
+export const useAddNewOpportunity = (position: string) => {
+ const [isCreatingCard, setIsCreatingCard] = useState(false);
+
+ const { columnDefinition } = useContext(RecordBoardColumnContext);
+ const { createOneRecord, selectFieldMetadataItem } =
+ useContext(RecordBoardContext);
+
+ const {
+ goBackToPreviousHotkeyScope,
+ setHotkeyScopeAndMemorizePreviousScope,
+ } = usePreviousHotkeyScope();
+ const { resetSearchFilter } = useEntitySelectSearch({
+ relationPickerScopeId: 'relation-picker',
+ });
+
+ const handleEntitySelect = useCallback(
+ (company?: EntityForSelect) => {
+ setIsCreatingCard(false);
+ goBackToPreviousHotkeyScope();
+ resetSearchFilter();
+
+ if (company !== undefined) {
+ createOneRecord({
+ name: company.name,
+ companyId: company.id,
+ position: position,
+ [selectFieldMetadataItem.name]: columnDefinition.value,
+ });
+ }
+ },
+ [
+ columnDefinition,
+ createOneRecord,
+ goBackToPreviousHotkeyScope,
+ resetSearchFilter,
+ selectFieldMetadataItem,
+ position,
+ ],
+ );
+
+ const handleAddNewOpportunityClick = useCallback(() => {
+ setIsCreatingCard(true);
+ setHotkeyScopeAndMemorizePreviousScope(
+ RelationPickerHotkeyScope.RelationPicker,
+ );
+ }, [setHotkeyScopeAndMemorizePreviousScope]);
+
+ const handleCancel = useCallback(() => {
+ resetSearchFilter();
+ goBackToPreviousHotkeyScope();
+ setIsCreatingCard(false);
+ }, [goBackToPreviousHotkeyScope, resetSearchFilter]);
+
+ return {
+ isCreatingCard,
+ handleEntitySelect,
+ handleAddNewOpportunityClick,
+ handleCancel,
+ };
+};
diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx
index 79c0e606817c..ba3abec91e75 100644
--- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx
@@ -1,5 +1,5 @@
import { useCallback, useEffect } from 'react';
-import { useNavigate } from 'react-router-dom';
+import { useLocation, useNavigate } from 'react-router-dom';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
@@ -11,6 +11,7 @@ import { recordIndexFieldDefinitionsState } from '@/object-record/record-index/s
import { recordIndexIsCompactModeActiveState } from '@/object-record/record-index/states/recordIndexIsCompactModeActiveState';
import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState';
import { computeRecordBoardColumnDefinitionsFromObjectMetadata } from '@/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata';
+import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isDefined } from '~/utils/isDefined';
@@ -60,9 +61,21 @@ export const RecordIndexBoardDataLoaderEffect = ({
}, [recordIndexFieldDefinitions, setFieldDefinitions]);
const navigate = useNavigate();
+ const location = useLocation();
+ const setNavigationMemorizedUrl = useSetRecoilState(
+ navigationMemorizedUrlState,
+ );
+
const navigateToSelectSettings = useCallback(() => {
+ setNavigationMemorizedUrl(location.pathname + location.search);
navigate(`/settings/objects/${getObjectSlug(objectMetadataItem)}`);
- }, [navigate, objectMetadataItem]);
+ }, [
+ navigate,
+ objectMetadataItem,
+ location.pathname,
+ location.search,
+ setNavigationMemorizedUrl,
+ ]);
const { resetRecordSelection } = useRecordBoardSelection(recordBoardId);
diff --git a/packages/twenty-front/src/modules/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata.ts b/packages/twenty-front/src/modules/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata.ts
index 4abbba702a98..51b3fa1d3be9 100644
--- a/packages/twenty-front/src/modules/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata.ts
+++ b/packages/twenty-front/src/modules/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata.ts
@@ -1,4 +1,4 @@
-import { IconPencil } from 'twenty-ui';
+import { IconSettings } from 'twenty-ui';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import {
@@ -42,8 +42,8 @@ export const computeRecordBoardColumnDefinitionsFromObjectMetadata = (
actions: [
{
id: 'edit',
- label: 'Edit from settings',
- icon: IconPencil,
+ label: 'Edit from Settings',
+ icon: IconSettings,
position: 0,
callback: navigateToSelectSettings,
},
diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts
index dd1f3e330834..3d6a7fc98643 100644
--- a/packages/twenty-front/vite.config.ts
+++ b/packages/twenty-front/vite.config.ts
@@ -33,16 +33,19 @@ export default defineConfig(({ command, mode }) => {
};
if (VITE_DISABLE_TYPESCRIPT_CHECKER === 'true') {
+ // eslint-disable-next-line no-console
console.log(
`VITE_DISABLE_TYPESCRIPT_CHECKER: ${VITE_DISABLE_TYPESCRIPT_CHECKER}`,
);
}
if (VITE_DISABLE_ESLINT_CHECKER === 'true') {
+ // eslint-disable-next-line no-console
console.log(`VITE_DISABLE_ESLINT_CHECKER: ${VITE_DISABLE_ESLINT_CHECKER}`);
}
if (VITE_BUILD_SOURCEMAP === 'true') {
+ // eslint-disable-next-line no-console
console.log(`VITE_BUILD_SOURCEMAP: ${VITE_BUILD_SOURCEMAP}`);
}