Replace sign-in mocked metadata with hardcoded BackgroundMock (#20308)
## Summary When the user is logged out, we render the auth modal on top of a sample table to make the empty page feel alive. So far this was achieved by **loading a full set of mocked object / field / view / navigation-menu metadata into the runtime metadata store** and then mounting the real `RecordTable` and `AppNavigationDrawer` behind the modal. This had a few downsides: - Significant bundle weight pulled in for unauthenticated users (mocked GraphQL fixtures + the real `RecordTable` virtualization stack). - Plenty of code paths that had to know about the "showAuthModal" case (`useRecordIndexTableQuery`, `useTriggerInitialRecordTableDataLoad`, `MainContextStoreProvider`, `IsMinimalMetadataReadyEffect`...). - Any change to metadata-store internals or to the record-table runtime risked breaking the logged-out background. This PR replaces the entire flow with a small, self-contained `BackgroundMock` component tree that **does not consume any metadata** and **does not load any mocked metadata at runtime**. ### What changed - New module under `sign-in-background-mock`: - `BackgroundMockPage` + `BackgroundMockViewBar` + `BackgroundMockTable` + `BackgroundMockTableRow` render a hardcoded "Companies" table that visually mirrors the real one. - `BackgroundMockNavigationDrawer` renders a hardcoded sidebar with People / Companies / Opportunities / Tasks / Notes (with their standard colors). - Hardcoded constants in `BackgroundMockCompanies.ts`, `BackgroundMockColumns.ts`, `BackgroundMockNavigationItems.ts`. - `MinimalMetadataLoadEffect` no longer calls `loadMockedMetadataAtomic` for unauthenticated users — it just doesn't load anything. - `IsMinimalMetadataReadyEffect` now reports ready immediately when there is no access token pair, so the skeleton loader doesn't hang waiting for metadata that will never come. - `MainContextStoreProvider`, `useRecordIndexTableQuery`, and `useTriggerInitialRecordTableDataLoad` drop their `showAuthModal` branches — the real `RecordTable` is no longer mounted behind the modal. - `DefaultLayout` and `NotFound` now lazily load `BackgroundMockPage` / `BackgroundMockNavigationDrawer` instead of the deleted `SignInBackgroundMockPage` / `SignInAppNavigationDrawerMock`. - Removed: `SignInBackgroundMockPage`, `SignInBackgroundMockContainer`, `SignInBackgroundMockContainerEffect`, `SignInAppNavigationDrawerMock`, `SignInBackgroundMockColumnDefinitions`, `SignInBackgroundMockCompanies`, `SignInBackgroundMockViewFields`. `useLoadMockedMetadata` and `preloadMockedMetadata` are kept on purpose: Storybook decorators (`ObjectMetadataItemsDecorator`, `WorkflowStepDecorator`) still rely on the mocked metadata fixtures, but **production** unauthenticated runtime no longer touches them. ### Visual parity Side-by-side at 1440×900 on `/sign-in`: **Before** (loads mocked metadata + real RecordTable):  **After** (purely hardcoded BackgroundMock):  ## Test plan - [ ] `npx nx typecheck twenty-front` ✅ (passes locally) - [ ] `npx nx lint:diff-with-main twenty-front` ✅ (oxlint + prettier clean) - [ ] `npx jest useRecordIndexTableQuery` ✅ - [ ] Manually verify `/sign-in` renders the table + nav drawer behind the modal - [ ] Manually verify `/not-found` still renders the background - [ ] Verify CI: storybook, unit tests, e2e tests
This commit is contained in:
+2
-11
@@ -3,7 +3,6 @@ import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage';
|
||||
import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView';
|
||||
import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector';
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { viewsSelector } from '@/views/states/selectors/viewsSelector';
|
||||
@@ -38,8 +37,6 @@ const getViewId = (
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const SIGN_IN_BACKGROUND_OBJECT_NAME_PLURAL = 'companies';
|
||||
|
||||
export const MainContextStoreProvider = () => {
|
||||
const location = useLocation();
|
||||
const isRecordIndexPage = isMatchingLocation(
|
||||
@@ -49,15 +46,10 @@ export const MainContextStoreProvider = () => {
|
||||
const isRecordShowPage = isMatchingLocation(location, AppPath.RecordShowPage);
|
||||
const isStandalonePage = isMatchingLocation(location, AppPath.PageLayoutPage);
|
||||
const isSettingsPage = useIsSettingsPage();
|
||||
const showAuthModal = useShowAuthModal();
|
||||
|
||||
const objectNamePluralFromParams = useParams().objectNamePlural ?? '';
|
||||
const objectNamePlural = useParams().objectNamePlural ?? '';
|
||||
const objectNameSingular = useParams().objectNameSingular ?? '';
|
||||
|
||||
const objectNamePlural = showAuthModal
|
||||
? SIGN_IN_BACKGROUND_OBJECT_NAME_PLURAL
|
||||
: objectNamePluralFromParams;
|
||||
|
||||
const [searchParams] = useSearchParams();
|
||||
const viewIdQueryParamRaw = searchParams.get('viewId');
|
||||
|
||||
@@ -120,8 +112,7 @@ export const MainContextStoreProvider = () => {
|
||||
(isRecordIndexPage ||
|
||||
isRecordShowPage ||
|
||||
isStandalonePage ||
|
||||
isSettingsPage ||
|
||||
showAuthModal) &&
|
||||
isSettingsPage) &&
|
||||
metadataStore.status === 'up-to-date';
|
||||
|
||||
if (!shouldComputeContextStore) {
|
||||
|
||||
+8
-5
@@ -28,21 +28,24 @@ export const IsMinimalMetadataReadyEffect = () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasAccessTokenPair) {
|
||||
setIsMinimalMetadataReady(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const hasActiveWorkspace = isWorkspaceActiveOrSuspended(currentWorkspace);
|
||||
|
||||
const areObjectsLoaded = metadataStore.status === 'up-to-date';
|
||||
const areViewsLoaded = metadataStoreViews.status === 'up-to-date';
|
||||
|
||||
const isReady = !areObjectsLoaded
|
||||
? false
|
||||
: !hasAccessTokenPair ||
|
||||
(isDefined(currentUser) && (!hasActiveWorkspace || areViewsLoaded));
|
||||
|
||||
if (!areObjectsLoaded) {
|
||||
setIsMinimalMetadataReady(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const isReady =
|
||||
isDefined(currentUser) && (!hasActiveWorkspace || areViewsLoaded);
|
||||
|
||||
if (isReady) {
|
||||
setIsMinimalMetadataReady(true);
|
||||
}
|
||||
|
||||
+10
-42
@@ -2,70 +2,41 @@ import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadedState';
|
||||
import { useLoadMinimalMetadata } from '@/metadata-store/hooks/useLoadMinimalMetadata';
|
||||
import { useLoadMockedMetadata } from '@/metadata-store/hooks/useLoadMockedMetadata';
|
||||
import { useLoadStaleMetadataEntities } from '@/metadata-store/hooks/useLoadStaleMetadataEntities';
|
||||
import { metadataLoadedVersionState } from '@/metadata-store/states/metadataLoadedVersionState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace';
|
||||
|
||||
type LoadedState = 'none' | 'mocked' | 'real';
|
||||
|
||||
const computeDesiredLoadState = (
|
||||
hasAccessTokenPair: boolean,
|
||||
isActiveWorkspace: boolean,
|
||||
): LoadedState => {
|
||||
if (hasAccessTokenPair && isActiveWorkspace) {
|
||||
return 'real';
|
||||
}
|
||||
|
||||
return 'mocked';
|
||||
};
|
||||
|
||||
export const MinimalMetadataLoadEffect = () => {
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const isCurrentUserLoaded = useAtomStateValue(isCurrentUserLoadedState);
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const metadataLoadedVersion = useAtomStateValue(metadataLoadedVersionState);
|
||||
const [lastMetadataLoadData, setLastMetadataLoadData] = useState<{
|
||||
state: LoadedState;
|
||||
version: number;
|
||||
}>({ state: 'none', version: -1 });
|
||||
const [lastLoadedVersion, setLastLoadedVersion] = useState<number>(-1);
|
||||
|
||||
const { loadMinimalMetadata } = useLoadMinimalMetadata();
|
||||
const { loadMockedMetadataAtomic } = useLoadMockedMetadata();
|
||||
const { loadStaleMetadataEntities } = useLoadStaleMetadataEntities();
|
||||
|
||||
const isActiveWorkspace = isWorkspaceActiveOrSuspended(currentWorkspace);
|
||||
|
||||
const desiredLoadState = computeDesiredLoadState(
|
||||
hasAccessTokenPair,
|
||||
isActiveWorkspace,
|
||||
);
|
||||
const shouldLoadRealMetadata = hasAccessTokenPair && isActiveWorkspace;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isCurrentUserLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
const versionChanged =
|
||||
metadataLoadedVersion !== lastMetadataLoadData.version;
|
||||
|
||||
if (!versionChanged && lastMetadataLoadData.state === desiredLoadState) {
|
||||
if (!shouldLoadRealMetadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLastMetadataLoadData({
|
||||
state: desiredLoadState,
|
||||
version: metadataLoadedVersion,
|
||||
});
|
||||
if (metadataLoadedVersion === lastLoadedVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLastLoadedVersion(metadataLoadedVersion);
|
||||
|
||||
const performLoad = async () => {
|
||||
if (desiredLoadState === 'mocked') {
|
||||
await loadMockedMetadataAtomic();
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await loadMinimalMetadata();
|
||||
|
||||
if (result?.staleEntityKeys && result.staleEntityKeys.length > 0) {
|
||||
@@ -76,13 +47,10 @@ export const MinimalMetadataLoadEffect = () => {
|
||||
performLoad();
|
||||
}, [
|
||||
isCurrentUserLoaded,
|
||||
hasAccessTokenPair,
|
||||
isActiveWorkspace,
|
||||
desiredLoadState,
|
||||
lastMetadataLoadData,
|
||||
shouldLoadRealMetadata,
|
||||
lastLoadedVersion,
|
||||
metadataLoadedVersion,
|
||||
loadMinimalMetadata,
|
||||
loadMockedMetadataAtomic,
|
||||
loadStaleMetadataEntities,
|
||||
]);
|
||||
|
||||
|
||||
+2
-7
@@ -2,12 +2,8 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useRelevantRecordsGqlFields } from '@/object-record/record-field/hooks/useRelevantRecordsGqlFields';
|
||||
import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams';
|
||||
import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies';
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
|
||||
export const useRecordIndexTableQuery = (objectNameSingular: string) => {
|
||||
const showAuthModal = useShowAuthModal();
|
||||
|
||||
const params = useFindManyRecordIndexTableParams(objectNameSingular);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
@@ -28,12 +24,11 @@ export const useRecordIndexTableQuery = (objectNameSingular: string) => {
|
||||
} = useFindManyRecords({
|
||||
...params,
|
||||
recordGqlFields,
|
||||
skip: showAuthModal,
|
||||
});
|
||||
|
||||
return {
|
||||
records: showAuthModal ? SIGN_IN_BACKGROUND_MOCK_COMPANIES : records,
|
||||
loading: showAuthModal ? false : loading,
|
||||
records,
|
||||
loading,
|
||||
hasNextPage,
|
||||
queryIdentifier,
|
||||
totalCount,
|
||||
|
||||
+26
-36
@@ -30,8 +30,6 @@ import { recordIdByRealIndexComponentState } from '@/object-record/record-table/
|
||||
import { scrollAtRealIndexComponentState } from '@/object-record/record-table/virtualization/states/scrollAtRealIndexComponentState';
|
||||
import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies';
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
import { useAtomComponentFamilyStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateCallbackState';
|
||||
import { useAtomComponentSelectorCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorCallbackState';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
@@ -41,8 +39,6 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
export const useTriggerInitialRecordTableDataLoad = () => {
|
||||
const { recordTableId, objectNameSingular } = useRecordTableContextOrThrow();
|
||||
|
||||
const showAuthModal = useShowAuthModal();
|
||||
|
||||
const { findManyRecordsLazy } =
|
||||
useRecordIndexTableLazyQuery(objectNameSingular);
|
||||
|
||||
@@ -155,40 +151,35 @@ export const useTriggerInitialRecordTableDataLoad = () => {
|
||||
let records: ObjectRecord[] | null = null;
|
||||
let totalCount = 0;
|
||||
|
||||
if (showAuthModal) {
|
||||
records = SIGN_IN_BACKGROUND_MOCK_COMPANIES;
|
||||
totalCount = SIGN_IN_BACKGROUND_MOCK_COMPANIES.length;
|
||||
} else {
|
||||
const newRecordIdByRealIndex = new Map(
|
||||
store.get(recordIdByRealIndexCallbackState),
|
||||
);
|
||||
const newDataLoadingStatusByRealIndex = new Map(
|
||||
store.get(dataLoadingStatusByRealIndexCallbackState),
|
||||
);
|
||||
const newRecordIdByRealIndex = new Map(
|
||||
store.get(recordIdByRealIndexCallbackState),
|
||||
);
|
||||
const newDataLoadingStatusByRealIndex = new Map(
|
||||
store.get(dataLoadingStatusByRealIndexCallbackState),
|
||||
);
|
||||
|
||||
for (const [realIndex] of currentRecordIds.entries()) {
|
||||
newDataLoadingStatusByRealIndex.set(realIndex, 'not-loaded');
|
||||
newRecordIdByRealIndex.delete(realIndex);
|
||||
}
|
||||
|
||||
store.set(recordIdByRealIndexCallbackState, newRecordIdByRealIndex);
|
||||
store.set(
|
||||
dataLoadingStatusByRealIndexCallbackState,
|
||||
newDataLoadingStatusByRealIndex,
|
||||
);
|
||||
|
||||
store.set(
|
||||
recordIndexRecordIdsByGroupFamilyState(NO_RECORD_GROUP_FAMILY_KEY),
|
||||
[],
|
||||
);
|
||||
|
||||
const { records: findManyRecords, totalCount: findManyTotalCount } =
|
||||
await findManyRecordsLazy();
|
||||
|
||||
records = findManyRecords;
|
||||
totalCount = findManyTotalCount;
|
||||
for (const [realIndex] of currentRecordIds.entries()) {
|
||||
newDataLoadingStatusByRealIndex.set(realIndex, 'not-loaded');
|
||||
newRecordIdByRealIndex.delete(realIndex);
|
||||
}
|
||||
|
||||
store.set(recordIdByRealIndexCallbackState, newRecordIdByRealIndex);
|
||||
store.set(
|
||||
dataLoadingStatusByRealIndexCallbackState,
|
||||
newDataLoadingStatusByRealIndex,
|
||||
);
|
||||
|
||||
store.set(
|
||||
recordIndexRecordIdsByGroupFamilyState(NO_RECORD_GROUP_FAMILY_KEY),
|
||||
[],
|
||||
);
|
||||
|
||||
const { records: findManyRecords, totalCount: findManyTotalCount } =
|
||||
await findManyRecordsLazy();
|
||||
|
||||
records = findManyRecords;
|
||||
totalCount = findManyTotalCount;
|
||||
|
||||
store.set(totalNumberOfRecordsToVirtualizeCallbackState, totalCount);
|
||||
|
||||
if (isDefined(records)) {
|
||||
@@ -230,7 +221,6 @@ export const useTriggerInitialRecordTableDataLoad = () => {
|
||||
recordIndexAllRecordIds,
|
||||
recordIndexRecordIdsByGroupFamilyState,
|
||||
store,
|
||||
showAuthModal,
|
||||
dataPagesLoadedCallbackState,
|
||||
isRecordTableInitialLoading,
|
||||
lastScrollPositionCallbackState,
|
||||
|
||||
+35
-26
@@ -1,11 +1,3 @@
|
||||
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
||||
|
||||
import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems';
|
||||
import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector';
|
||||
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
||||
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
|
||||
import { DEFAULT_WORKSPACE_NAME } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceName';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { styled } from '@linaria/react';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { SettingsPath } from 'twenty-shared/types';
|
||||
@@ -13,28 +5,27 @@ import { getSettingsPath } from 'twenty-shared/utils';
|
||||
import { IconSearch, IconSettings } from 'twenty-ui/display';
|
||||
import { getOsControlSymbol, useIsMobile } from 'twenty-ui/utilities';
|
||||
|
||||
import { BACKGROUND_MOCK_OTHER_ITEMS } from '@/sign-in-background-mock/constants/BackgroundMockOtherItems';
|
||||
import { BACKGROUND_MOCK_WORKSPACE_ITEMS } from '@/sign-in-background-mock/constants/BackgroundMockNavigationItems';
|
||||
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
||||
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
||||
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
|
||||
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
|
||||
import { DEFAULT_WORKSPACE_NAME } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceName';
|
||||
|
||||
const StyledMainSectionWrapper = styled.div`
|
||||
min-height: fit-content;
|
||||
`;
|
||||
|
||||
const WORKSPACE_FAVORITES = [
|
||||
'person',
|
||||
'company',
|
||||
'opportunity',
|
||||
'task',
|
||||
'note',
|
||||
];
|
||||
|
||||
export type SignInAppNavigationDrawerMockProps = {
|
||||
export type BackgroundMockNavigationDrawerProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const SignInAppNavigationDrawerMock = ({
|
||||
export const BackgroundMockNavigationDrawer = ({
|
||||
className,
|
||||
}: SignInAppNavigationDrawerMockProps) => {
|
||||
}: BackgroundMockNavigationDrawerProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
const { t } = useLingui();
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsSelector);
|
||||
|
||||
return (
|
||||
<NavigationDrawer className={className} title={DEFAULT_WORKSPACE_NAME}>
|
||||
@@ -56,12 +47,30 @@ export const SignInAppNavigationDrawerMock = ({
|
||||
</NavigationDrawerSection>
|
||||
</StyledMainSectionWrapper>
|
||||
)}
|
||||
<NavigationDrawerSectionForObjectMetadataItems
|
||||
sectionTitle={t`Workspace`}
|
||||
objectMetadataItems={objectMetadataItems.filter((item) =>
|
||||
WORKSPACE_FAVORITES.includes(item.nameSingular),
|
||||
)}
|
||||
/>
|
||||
<NavigationDrawerSection>
|
||||
<NavigationDrawerSectionTitle label={t`Workspace`} />
|
||||
{BACKGROUND_MOCK_WORKSPACE_ITEMS.map((item, index) => (
|
||||
<NavigationDrawerItem
|
||||
key={item.label}
|
||||
label={item.label}
|
||||
Icon={item.Icon}
|
||||
iconColor={item.color}
|
||||
active={index === 0}
|
||||
onClick={() => {}}
|
||||
/>
|
||||
))}
|
||||
</NavigationDrawerSection>
|
||||
<NavigationDrawerSection>
|
||||
<NavigationDrawerSectionTitle label={t`Other`} />
|
||||
{BACKGROUND_MOCK_OTHER_ITEMS.map((item) => (
|
||||
<NavigationDrawerItem
|
||||
key={item.label}
|
||||
label={item.label}
|
||||
Icon={item.Icon}
|
||||
onClick={() => {}}
|
||||
/>
|
||||
))}
|
||||
</NavigationDrawerSection>
|
||||
</NavigationDrawer>
|
||||
);
|
||||
};
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
IconBuildingSkyscraper,
|
||||
IconDotsVertical,
|
||||
IconLayoutSidebarRight,
|
||||
IconPlus,
|
||||
TintedIconTile,
|
||||
} from 'twenty-ui/display';
|
||||
import { Button, LightIconButton } from 'twenty-ui/input';
|
||||
|
||||
import { BackgroundMockTable } from '@/sign-in-background-mock/components/BackgroundMockTable';
|
||||
import { BackgroundMockViewBar } from '@/sign-in-background-mock/components/BackgroundMockViewBar';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||
import { PageHeader } from '@/ui/layout/page/components/PageHeader';
|
||||
|
||||
const StyledTableContainer = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const BackgroundMockPage = () => {
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageHeader
|
||||
title={t`Companies`}
|
||||
Icon={() => (
|
||||
<TintedIconTile Icon={IconBuildingSkyscraper} color="blue" />
|
||||
)}
|
||||
>
|
||||
<Button
|
||||
Icon={IconPlus}
|
||||
title={t`New Company`}
|
||||
variant="primary"
|
||||
accent="default"
|
||||
size="small"
|
||||
/>
|
||||
<LightIconButton
|
||||
Icon={IconDotsVertical}
|
||||
accent="tertiary"
|
||||
size="small"
|
||||
/>
|
||||
<Button
|
||||
Icon={IconLayoutSidebarRight}
|
||||
variant="secondary"
|
||||
accent="default"
|
||||
size="small"
|
||||
/>
|
||||
</PageHeader>
|
||||
<PageBody>
|
||||
<StyledTableContainer>
|
||||
<BackgroundMockViewBar />
|
||||
<BackgroundMockTable />
|
||||
</StyledTableContainer>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { BackgroundMockTableRow } from '@/sign-in-background-mock/components/BackgroundMockTableRow';
|
||||
import { BACKGROUND_MOCK_COLUMNS } from '@/sign-in-background-mock/constants/BackgroundMockColumns';
|
||||
import { BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/BackgroundMockCompanies';
|
||||
import { BACKGROUND_MOCK_TABLE_DIMENSIONS } from '@/sign-in-background-mock/constants/BackgroundMockTableDimensions';
|
||||
import {
|
||||
IconChevronDown,
|
||||
IconPlus,
|
||||
OverflowingTextWithTooltip,
|
||||
useIcons,
|
||||
} from 'twenty-ui/display';
|
||||
import { Checkbox } from 'twenty-ui/input';
|
||||
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledTableWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledTable = styled.div`
|
||||
background: ${themeCssVariables.background.primary};
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
font-size: ${themeCssVariables.font.size.md};
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const StyledHeaderRow = styled.div`
|
||||
background: ${themeCssVariables.background.primary};
|
||||
display: flex;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
`;
|
||||
|
||||
const StyledDragHandleColumn = styled.div`
|
||||
background: ${themeCssVariables.background.primary};
|
||||
flex-shrink: 0;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.dragHandleColumnWidth}px;
|
||||
`;
|
||||
|
||||
const StyledCheckboxHeaderColumn = styled.div`
|
||||
align-items: center;
|
||||
background: ${themeCssVariables.background.primary};
|
||||
border-bottom: 1px solid ${themeCssVariables.border.color.light};
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
justify-content: center;
|
||||
padding-right: ${themeCssVariables.spacing[1]};
|
||||
width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.checkboxColumnWidth}px;
|
||||
`;
|
||||
|
||||
const StyledHeaderCell = styled.div<{ width: number }>`
|
||||
align-items: center;
|
||||
background: ${themeCssVariables.background.primary};
|
||||
border-bottom: 1px solid ${themeCssVariables.border.color.light};
|
||||
border-right: 1px solid ${themeCssVariables.border.color.light};
|
||||
box-sizing: border-box;
|
||||
color: ${themeCssVariables.font.color.tertiary};
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
font-weight: ${themeCssVariables.font.weight.medium};
|
||||
gap: ${themeCssVariables.spacing[1]};
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
overflow: hidden;
|
||||
padding: 0 ${themeCssVariables.spacing[2]};
|
||||
width: ${({ width }) => width}px;
|
||||
`;
|
||||
|
||||
const StyledHeaderLabel = styled.span`
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
const StyledAddColumnHeaderCell = styled.div`
|
||||
align-items: center;
|
||||
background: ${themeCssVariables.background.primary};
|
||||
border-bottom: 1px solid ${themeCssVariables.border.color.light};
|
||||
box-sizing: border-box;
|
||||
color: ${themeCssVariables.font.color.tertiary};
|
||||
display: flex;
|
||||
flex: 1;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
min-width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.addColumnButtonWidth}px;
|
||||
`;
|
||||
|
||||
const StyledAddColumnIconWrapper = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
justify-content: center;
|
||||
width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.addColumnButtonWidth}px;
|
||||
`;
|
||||
|
||||
const StyledTableBody = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
|
||||
const StyledFooterRow = styled.div`
|
||||
display: flex;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
`;
|
||||
|
||||
const StyledFooterCheckboxColumn = styled.div`
|
||||
flex-shrink: 0;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.checkboxColumnWidth}px;
|
||||
`;
|
||||
|
||||
const StyledFooterCell = styled.div<{ width: number }>`
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
color: ${themeCssVariables.font.color.tertiary};
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
font-weight: ${themeCssVariables.font.weight.medium};
|
||||
gap: ${themeCssVariables.spacing[1]};
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
justify-content: space-between;
|
||||
overflow: hidden;
|
||||
padding: 0 ${themeCssVariables.spacing[2]};
|
||||
white-space: nowrap;
|
||||
width: ${({ width }) => width}px;
|
||||
`;
|
||||
|
||||
const StyledFooterLabel = styled.div`
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
`;
|
||||
|
||||
const StyledFooterValue = styled.span`
|
||||
color: ${themeCssVariables.font.color.primary};
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
|
||||
const StyledLastEmptyCell = styled.div`
|
||||
flex: 1;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
min-width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.addColumnButtonWidth}px;
|
||||
`;
|
||||
|
||||
export const BackgroundMockTable = () => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
return (
|
||||
<StyledTableWrapper>
|
||||
<StyledTable>
|
||||
<StyledHeaderRow>
|
||||
<StyledDragHandleColumn />
|
||||
<StyledCheckboxHeaderColumn>
|
||||
<Checkbox hoverable checked={false} />
|
||||
</StyledCheckboxHeaderColumn>
|
||||
{BACKGROUND_MOCK_COLUMNS.map((column) => {
|
||||
const Icon = getIcon(column.iconName);
|
||||
return (
|
||||
<StyledHeaderCell key={column.label} width={column.width}>
|
||||
{Icon !== undefined && (
|
||||
<Icon
|
||||
size={theme.icon.size.md}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
)}
|
||||
<StyledHeaderLabel>{column.label}</StyledHeaderLabel>
|
||||
</StyledHeaderCell>
|
||||
);
|
||||
})}
|
||||
<StyledAddColumnHeaderCell>
|
||||
<StyledAddColumnIconWrapper>
|
||||
<IconPlus
|
||||
size={theme.icon.size.sm}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
</StyledAddColumnIconWrapper>
|
||||
</StyledAddColumnHeaderCell>
|
||||
</StyledHeaderRow>
|
||||
<StyledTableBody>
|
||||
{BACKGROUND_MOCK_COMPANIES.map((company) => (
|
||||
<BackgroundMockTableRow key={company.id} company={company} />
|
||||
))}
|
||||
</StyledTableBody>
|
||||
<StyledFooterRow>
|
||||
<StyledDragHandleColumn />
|
||||
<StyledFooterCheckboxColumn />
|
||||
<StyledFooterCell width={BACKGROUND_MOCK_COLUMNS[0].width}>
|
||||
<StyledFooterLabel>
|
||||
<OverflowingTextWithTooltip text="Calculate" />
|
||||
</StyledFooterLabel>
|
||||
<IconChevronDown
|
||||
size={theme.icon.size.sm}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
</StyledFooterCell>
|
||||
<StyledFooterCell width={BACKGROUND_MOCK_COLUMNS[1].width}>
|
||||
<StyledFooterLabel>
|
||||
<OverflowingTextWithTooltip text="Count all" />
|
||||
</StyledFooterLabel>
|
||||
<StyledFooterValue>599</StyledFooterValue>
|
||||
</StyledFooterCell>
|
||||
<StyledFooterCell width={BACKGROUND_MOCK_COLUMNS[2].width} />
|
||||
<StyledFooterCell width={BACKGROUND_MOCK_COLUMNS[3].width} />
|
||||
<StyledFooterCell width={BACKGROUND_MOCK_COLUMNS[4].width} />
|
||||
<StyledFooterCell width={BACKGROUND_MOCK_COLUMNS[5].width}>
|
||||
<StyledFooterLabel>
|
||||
<OverflowingTextWithTooltip text="Max of Employees" />
|
||||
</StyledFooterLabel>
|
||||
<StyledFooterValue>284,571</StyledFooterValue>
|
||||
</StyledFooterCell>
|
||||
<StyledFooterCell width={BACKGROUND_MOCK_COLUMNS[6].width}>
|
||||
<StyledFooterLabel>
|
||||
<OverflowingTextWithTooltip text="Not empty of Address" />
|
||||
</StyledFooterLabel>
|
||||
<StyledFooterValue>599</StyledFooterValue>
|
||||
</StyledFooterCell>
|
||||
<StyledLastEmptyCell />
|
||||
</StyledFooterRow>
|
||||
</StyledTable>
|
||||
</StyledTableWrapper>
|
||||
);
|
||||
};
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { type BackgroundMockCompany } from '@/sign-in-background-mock/constants/BackgroundMockCompanies';
|
||||
import { BACKGROUND_MOCK_COLUMN_WIDTHS } from '@/sign-in-background-mock/constants/BackgroundMockColumnWidths';
|
||||
import { BACKGROUND_MOCK_TABLE_DIMENSIONS } from '@/sign-in-background-mock/constants/BackgroundMockTableDimensions';
|
||||
import { Avatar, IconLink } from 'twenty-ui/display';
|
||||
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { Chip, ChipAccent, ChipSize, ChipVariant } from 'twenty-ui/components';
|
||||
import { Checkbox } from 'twenty-ui/input';
|
||||
import { getLogoUrlFromDomainName } from 'twenty-shared/utils';
|
||||
|
||||
const StyledRow = styled.div`
|
||||
display: flex;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
`;
|
||||
|
||||
const StyledDragHandleColumn = styled.div`
|
||||
flex-shrink: 0;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.dragHandleColumnWidth}px;
|
||||
`;
|
||||
|
||||
const StyledCheckboxColumn = styled.div`
|
||||
align-items: center;
|
||||
border-bottom: 1px solid ${themeCssVariables.border.color.light};
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
justify-content: center;
|
||||
padding-right: ${themeCssVariables.spacing[1]};
|
||||
width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.checkboxColumnWidth}px;
|
||||
`;
|
||||
|
||||
const StyledCell = styled.div<{ width: number }>`
|
||||
align-items: center;
|
||||
border-bottom: 1px solid ${themeCssVariables.border.color.light};
|
||||
border-right: 1px solid ${themeCssVariables.border.color.light};
|
||||
box-sizing: border-box;
|
||||
color: ${themeCssVariables.font.color.primary};
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
overflow: hidden;
|
||||
padding-left: ${themeCssVariables.spacing[2]};
|
||||
white-space: nowrap;
|
||||
width: ${({ width }) => width}px;
|
||||
`;
|
||||
|
||||
const StyledTruncated = styled.span`
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
const StyledMutedText = styled.span`
|
||||
color: ${themeCssVariables.font.color.tertiary};
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
`;
|
||||
|
||||
const StyledLastEmptyCell = styled.div`
|
||||
border-bottom: 1px solid ${themeCssVariables.border.color.light};
|
||||
flex: 1;
|
||||
height: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.rowHeight}px;
|
||||
min-width: ${BACKGROUND_MOCK_TABLE_DIMENSIONS.addColumnButtonWidth}px;
|
||||
`;
|
||||
|
||||
type BackgroundMockTableRowProps = {
|
||||
company: BackgroundMockCompany;
|
||||
};
|
||||
|
||||
const formatNumber = (value: number) => value.toLocaleString('en-US');
|
||||
|
||||
const PersonChip = ({ fullName }: { fullName: string | null }) => {
|
||||
if (fullName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Chip
|
||||
label={fullName}
|
||||
size={ChipSize.Small}
|
||||
variant={ChipVariant.Transparent}
|
||||
accent={ChipAccent.TextPrimary}
|
||||
clickable={false}
|
||||
leftComponent={
|
||||
<Avatar
|
||||
type="rounded"
|
||||
placeholder={fullName}
|
||||
placeholderColorSeed={fullName}
|
||||
size="md"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const BackgroundMockTableRow = ({
|
||||
company,
|
||||
}: BackgroundMockTableRowProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
const logoUrl = getLogoUrlFromDomainName(company.domainName);
|
||||
|
||||
return (
|
||||
<StyledRow>
|
||||
<StyledDragHandleColumn />
|
||||
<StyledCheckboxColumn>
|
||||
<Checkbox hoverable checked={false} />
|
||||
</StyledCheckboxColumn>
|
||||
<StyledCell width={BACKGROUND_MOCK_COLUMN_WIDTHS.Name}>
|
||||
<Chip
|
||||
label={company.name}
|
||||
size={ChipSize.Small}
|
||||
variant={ChipVariant.Transparent}
|
||||
accent={ChipAccent.TextPrimary}
|
||||
clickable={false}
|
||||
leftComponent={
|
||||
<Avatar
|
||||
type="squared"
|
||||
avatarUrl={logoUrl}
|
||||
placeholder={company.name}
|
||||
placeholderColorSeed={company.id}
|
||||
size="md"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</StyledCell>
|
||||
<StyledCell width={BACKGROUND_MOCK_COLUMN_WIDTHS.Domain}>
|
||||
<Chip
|
||||
label={company.domainName}
|
||||
size={ChipSize.Small}
|
||||
variant={ChipVariant.Transparent}
|
||||
accent={ChipAccent.TextSecondary}
|
||||
clickable={false}
|
||||
leftComponent={
|
||||
<IconLink
|
||||
size={theme.icon.size.sm}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
color={theme.font.color.tertiary}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</StyledCell>
|
||||
<StyledCell width={BACKGROUND_MOCK_COLUMN_WIDTHS['Created by']}>
|
||||
<PersonChip fullName={company.createdBy} />
|
||||
</StyledCell>
|
||||
<StyledCell width={BACKGROUND_MOCK_COLUMN_WIDTHS['Account Owner']}>
|
||||
<PersonChip fullName={company.accountOwner} />
|
||||
</StyledCell>
|
||||
<StyledCell width={BACKGROUND_MOCK_COLUMN_WIDTHS['Creation date']}>
|
||||
<StyledMutedText>{company.creationDate}</StyledMutedText>
|
||||
</StyledCell>
|
||||
<StyledCell width={BACKGROUND_MOCK_COLUMN_WIDTHS.Employees}>
|
||||
<StyledTruncated>{formatNumber(company.employees)}</StyledTruncated>
|
||||
</StyledCell>
|
||||
<StyledCell width={BACKGROUND_MOCK_COLUMN_WIDTHS.Address}>
|
||||
<StyledTruncated>{company.address}</StyledTruncated>
|
||||
</StyledCell>
|
||||
<StyledLastEmptyCell />
|
||||
</StyledRow>
|
||||
);
|
||||
};
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
import { styled } from '@linaria/react';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { TopBar } from '@/ui/layout/top-bar/components/TopBar';
|
||||
import {
|
||||
IconBuildingSkyscraper,
|
||||
IconChevronDown,
|
||||
TintedIconTile,
|
||||
} from 'twenty-ui/display';
|
||||
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
const StyledViewPicker = styled.div`
|
||||
align-items: center;
|
||||
color: ${themeCssVariables.font.color.secondary};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
font-weight: ${themeCssVariables.font.weight.medium};
|
||||
gap: ${themeCssVariables.spacing[1]};
|
||||
height: 100%;
|
||||
padding: 0 ${themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
const StyledViewPickerCount = styled.span`
|
||||
color: ${themeCssVariables.font.color.tertiary};
|
||||
`;
|
||||
|
||||
const StyledRightAction = styled.div`
|
||||
align-items: center;
|
||||
color: ${themeCssVariables.font.color.tertiary};
|
||||
display: flex;
|
||||
font-weight: ${themeCssVariables.font.weight.regular};
|
||||
height: 100%;
|
||||
padding: 0 ${themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
export const BackgroundMockViewBar = () => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
return (
|
||||
<TopBar
|
||||
leftComponent={
|
||||
<StyledViewPicker>
|
||||
<TintedIconTile Icon={IconBuildingSkyscraper} color="blue" />
|
||||
<span>All Companies</span>
|
||||
<StyledViewPickerCount>· 599</StyledViewPickerCount>
|
||||
<IconChevronDown
|
||||
size={theme.icon.size.sm}
|
||||
stroke={theme.icon.stroke.sm}
|
||||
/>
|
||||
</StyledViewPicker>
|
||||
}
|
||||
rightComponent={
|
||||
<>
|
||||
<StyledRightAction>Filter</StyledRightAction>
|
||||
<StyledRightAction>Sort</StyledRightAction>
|
||||
<StyledRightAction>Options</StyledRightAction>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
import { styled } from '@linaria/react';
|
||||
|
||||
import { CommandMenuComponentInstanceContext } from '@/command-menu/states/contexts/CommandMenuComponentInstanceContext';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||
import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates';
|
||||
import { RecordTableWithWrappers } from '@/object-record/record-table/components/RecordTableWithWrappers';
|
||||
import { SignInBackgroundMockContainerEffect } from '@/sign-in-background-mock/components/SignInBackgroundMockContainerEffect';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { ViewBar } from '@/views/components/ViewBar';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
export const SignInBackgroundMockContainer = () => {
|
||||
const objectNamePlural = 'companies';
|
||||
const objectNameSingular = 'company';
|
||||
const recordIndexId = 'sign-up-mock-record-table-id';
|
||||
const viewBarId = 'companies-mock';
|
||||
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsSelector);
|
||||
|
||||
const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
);
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.id === contextStoreCurrentObjectMetadataItemId,
|
||||
);
|
||||
|
||||
const {
|
||||
fieldDefinitionByFieldMetadataItemId,
|
||||
fieldMetadataItemByFieldMetadataItemId,
|
||||
labelIdentifierFieldMetadataItem,
|
||||
recordFieldByFieldMetadataItemId,
|
||||
} = useRecordIndexFieldMetadataDerivedStates(
|
||||
objectMetadataItem,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<RecordIndexContextProvider
|
||||
value={{
|
||||
objectPermissionsByObjectMetadataId: {},
|
||||
recordIndexId,
|
||||
viewBarInstanceId: recordIndexId,
|
||||
objectNamePlural,
|
||||
objectNameSingular,
|
||||
objectMetadataItem: objectMetadataItem ?? objectMetadataItems[0],
|
||||
onIndexRecordsLoaded: () => {},
|
||||
indexIdentifierUrl: () => '',
|
||||
fieldDefinitionByFieldMetadataItemId,
|
||||
fieldMetadataItemByFieldMetadataItemId,
|
||||
labelIdentifierFieldMetadataItem,
|
||||
recordFieldByFieldMetadataItemId,
|
||||
}}
|
||||
>
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
<RecordComponentInstanceContextsWrapper
|
||||
componentInstanceId={recordIndexId}
|
||||
>
|
||||
<ContextStoreComponentInstanceContext.Provider
|
||||
value={{
|
||||
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
}}
|
||||
>
|
||||
<SignInBackgroundMockContainerEffect
|
||||
objectNamePlural={objectNamePlural}
|
||||
recordTableId={recordIndexId}
|
||||
viewId={viewBarId}
|
||||
/>
|
||||
<CommandMenuComponentInstanceContext.Provider
|
||||
value={{ instanceId: recordIndexId }}
|
||||
>
|
||||
{isDefined(objectMetadataItem) && (
|
||||
<>
|
||||
<ViewBar
|
||||
viewBarId={viewBarId}
|
||||
optionsDropdownButton={<></>}
|
||||
isReadOnly
|
||||
/>
|
||||
|
||||
<RecordTableWithWrappers
|
||||
objectNameSingular={objectNameSingular}
|
||||
recordTableId={recordIndexId}
|
||||
viewBarId={viewBarId}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</CommandMenuComponentInstanceContext.Provider>
|
||||
</ContextStoreComponentInstanceContext.Provider>
|
||||
</RecordComponentInstanceContextsWrapper>
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordIndexContextProvider>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS } from '@/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions';
|
||||
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
|
||||
import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useInitViewBar } from '@/views/hooks/useInitViewBar';
|
||||
|
||||
type SignInBackgroundMockContainerEffectProps = {
|
||||
objectNamePlural: string;
|
||||
recordTableId: string;
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
export const SignInBackgroundMockContainerEffect = ({
|
||||
objectNamePlural,
|
||||
recordTableId,
|
||||
viewId,
|
||||
}: SignInBackgroundMockContainerEffectProps) => {
|
||||
const [
|
||||
contextStoreCurrentObjectMetadataItemId,
|
||||
setContextStoreCurrentObjectMetadataItemId,
|
||||
] = useAtomComponentState(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
);
|
||||
|
||||
const setCurrentRecordFields = useSetAtomComponentState(
|
||||
currentRecordFieldsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const objectMetadataItem = useAtomFamilySelectorValue(
|
||||
objectMetadataItemFamilySelector,
|
||||
{ objectName: objectNamePlural, objectNameType: 'plural' },
|
||||
);
|
||||
|
||||
const { setAvailableFieldDefinitions, setViewObjectMetadataId } =
|
||||
useInitViewBar(viewId);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDefined(objectMetadataItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setViewObjectMetadataId?.(objectMetadataItem.id);
|
||||
|
||||
setAvailableFieldDefinitions?.(SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS);
|
||||
|
||||
const recordFields = SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS.filter(
|
||||
(fieldDefinition) => fieldDefinition.fieldMetadataId !== '',
|
||||
).map(
|
||||
(columnDefinitionMock) =>
|
||||
({
|
||||
fieldMetadataItemId: columnDefinitionMock.fieldMetadataId,
|
||||
id: columnDefinitionMock.fieldMetadataId,
|
||||
isVisible: columnDefinitionMock.isVisible,
|
||||
position: columnDefinitionMock.position,
|
||||
size: columnDefinitionMock.size,
|
||||
}) satisfies RecordField as RecordField,
|
||||
);
|
||||
|
||||
setCurrentRecordFields(recordFields);
|
||||
|
||||
if (contextStoreCurrentObjectMetadataItemId !== objectMetadataItem.id) {
|
||||
setContextStoreCurrentObjectMetadataItemId(objectMetadataItem.id);
|
||||
}
|
||||
}, [
|
||||
setViewObjectMetadataId,
|
||||
setAvailableFieldDefinitions,
|
||||
objectMetadataItem,
|
||||
recordTableId,
|
||||
setContextStoreCurrentObjectMetadataItemId,
|
||||
contextStoreCurrentObjectMetadataItemId,
|
||||
setCurrentRecordFields,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { styled } from '@linaria/react';
|
||||
|
||||
import { SignInBackgroundMockContainer } from '@/sign-in-background-mock/components/SignInBackgroundMockContainer';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/components/PageContainer';
|
||||
import { PageHeader } from '@/ui/layout/page/components/PageHeader';
|
||||
import { IconBuildingSkyscraper } from 'twenty-ui/display';
|
||||
|
||||
const StyledTableContainer = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const SignInBackgroundMockPage = () => {
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageHeader title={t`Companies`} Icon={IconBuildingSkyscraper} />
|
||||
<PageBody>
|
||||
<StyledTableContainer>
|
||||
<SignInBackgroundMockContainer />
|
||||
</StyledTableContainer>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
export const BACKGROUND_MOCK_COLUMN_WIDTHS = {
|
||||
Name: 180,
|
||||
Domain: 130,
|
||||
'Created by': 130,
|
||||
'Account Owner': 130,
|
||||
'Creation date': 130,
|
||||
Employees: 110,
|
||||
Address: 200,
|
||||
} as const;
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import { BACKGROUND_MOCK_COLUMN_WIDTHS } from '@/sign-in-background-mock/constants/BackgroundMockColumnWidths';
|
||||
|
||||
export type BackgroundMockColumn = {
|
||||
label: keyof typeof BACKGROUND_MOCK_COLUMN_WIDTHS;
|
||||
iconName: string;
|
||||
width: number;
|
||||
};
|
||||
|
||||
export const BACKGROUND_MOCK_COLUMNS = [
|
||||
{
|
||||
label: 'Name',
|
||||
iconName: 'IconBuildingSkyscraper',
|
||||
width: BACKGROUND_MOCK_COLUMN_WIDTHS.Name,
|
||||
},
|
||||
{
|
||||
label: 'Domain',
|
||||
iconName: 'IconLink',
|
||||
width: BACKGROUND_MOCK_COLUMN_WIDTHS.Domain,
|
||||
},
|
||||
{
|
||||
label: 'Created by',
|
||||
iconName: 'IconUserCircle',
|
||||
width: BACKGROUND_MOCK_COLUMN_WIDTHS['Created by'],
|
||||
},
|
||||
{
|
||||
label: 'Account Owner',
|
||||
iconName: 'IconUserCircle',
|
||||
width: BACKGROUND_MOCK_COLUMN_WIDTHS['Account Owner'],
|
||||
},
|
||||
{
|
||||
label: 'Creation date',
|
||||
iconName: 'IconCalendar',
|
||||
width: BACKGROUND_MOCK_COLUMN_WIDTHS['Creation date'],
|
||||
},
|
||||
{
|
||||
label: 'Employees',
|
||||
iconName: 'IconUsers',
|
||||
width: BACKGROUND_MOCK_COLUMN_WIDTHS.Employees,
|
||||
},
|
||||
{
|
||||
label: 'Address',
|
||||
iconName: 'IconMap',
|
||||
width: BACKGROUND_MOCK_COLUMN_WIDTHS.Address,
|
||||
},
|
||||
] satisfies BackgroundMockColumn[];
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
export type BackgroundMockCompany = {
|
||||
id: string;
|
||||
name: string;
|
||||
domainName: string;
|
||||
createdBy: string | null;
|
||||
accountOwner: string | null;
|
||||
creationDate: string;
|
||||
employees: number;
|
||||
address: string;
|
||||
};
|
||||
|
||||
export const BACKGROUND_MOCK_COMPANIES = [
|
||||
{
|
||||
id: 'google',
|
||||
name: 'Google',
|
||||
domainName: 'goo.gle',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 284571,
|
||||
address: 'Mountain View',
|
||||
},
|
||||
{
|
||||
id: 'microsoft',
|
||||
name: 'Microsoft',
|
||||
domainName: 'microsoft.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Jony Ive',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 226067,
|
||||
address: 'Redmond',
|
||||
},
|
||||
{
|
||||
id: 'meta',
|
||||
name: 'Meta',
|
||||
domainName: 'metacareers.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 119511,
|
||||
address: 'Menlo Park',
|
||||
},
|
||||
{
|
||||
id: 'slb',
|
||||
name: 'SLB',
|
||||
domainName: 'slb.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 113151,
|
||||
address: 'Houston',
|
||||
},
|
||||
{
|
||||
id: 'cisco',
|
||||
name: 'Cisco',
|
||||
domainName: 'cisco.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 99625,
|
||||
address: 'San Jose',
|
||||
},
|
||||
{
|
||||
id: 'uber',
|
||||
name: 'Uber',
|
||||
domainName: 'uber.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Tim Apple',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 90545,
|
||||
address: 'San Francisco',
|
||||
},
|
||||
{
|
||||
id: 'salesforce',
|
||||
name: 'Salesforce',
|
||||
domainName: 'salesforce.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 71322,
|
||||
address: 'San Francisco',
|
||||
},
|
||||
{
|
||||
id: 'amdocs',
|
||||
name: 'Amdocs',
|
||||
domainName: 'amdocs.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Jony Ive',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 35731,
|
||||
address: 'Chesterfield',
|
||||
},
|
||||
{
|
||||
id: 'vmware',
|
||||
name: 'VMware',
|
||||
domainName: 'vmware.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 34759,
|
||||
address: 'Palo Alto',
|
||||
},
|
||||
{
|
||||
id: 'globallogic',
|
||||
name: 'GlobalLogic',
|
||||
domainName: 'globallogic.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Jony Ive',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 24461,
|
||||
address: 'Santa Clara',
|
||||
},
|
||||
{
|
||||
id: 'servicenow',
|
||||
name: 'ServiceNow',
|
||||
domainName: 'servicenow.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Tim Apple',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 24104,
|
||||
address: 'Santa Clara',
|
||||
},
|
||||
{
|
||||
id: 'ssctech',
|
||||
name: 'SS&C Technologies',
|
||||
domainName: 'ssctech.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 20311,
|
||||
address: 'Windsor',
|
||||
},
|
||||
{
|
||||
id: 'workday',
|
||||
name: 'Workday',
|
||||
domainName: 'workday.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Jony Ive',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 20036,
|
||||
address: 'Pleasanton',
|
||||
},
|
||||
{
|
||||
id: 'redhat',
|
||||
name: 'Red Hat',
|
||||
domainName: 'redhat.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 19945,
|
||||
address: 'Raleigh',
|
||||
},
|
||||
{
|
||||
id: 'netsuite',
|
||||
name: 'NetSuite',
|
||||
domainName: 'netsuite.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Jony Ive',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 19269,
|
||||
address: 'Austin',
|
||||
},
|
||||
{
|
||||
id: 'synopsys',
|
||||
name: 'Synopsys Inc',
|
||||
domainName: 'synopsys.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Jony Ive',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 18061,
|
||||
address: 'Sunnyvale',
|
||||
},
|
||||
{
|
||||
id: 'siemens',
|
||||
name: 'Siemens Digital Industries',
|
||||
domainName: 'sw.siemens.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Tim Apple',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 17262,
|
||||
address: 'Plano',
|
||||
},
|
||||
{
|
||||
id: 'sas',
|
||||
name: 'SAS',
|
||||
domainName: 'sas.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 16287,
|
||||
address: 'Cary',
|
||||
},
|
||||
{
|
||||
id: 'intuit',
|
||||
name: 'Intuit',
|
||||
domainName: 'intuit.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Jony Ive',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 15851,
|
||||
address: 'Mountain View',
|
||||
},
|
||||
{
|
||||
id: 'broadcom',
|
||||
name: 'Broadcom Software',
|
||||
domainName: 'broadcom.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Phil Schiller',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 15127,
|
||||
address: 'San Jose',
|
||||
},
|
||||
{
|
||||
id: 'autodesk',
|
||||
name: 'Autodesk',
|
||||
domainName: 'autodesk.com',
|
||||
createdBy: 'Tim Apple',
|
||||
accountOwner: 'Jony Ive',
|
||||
creationDate: 'about 13 hours ago',
|
||||
employees: 14593,
|
||||
address: 'San Francisco',
|
||||
},
|
||||
] satisfies BackgroundMockCompany[];
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
IconBuildingSkyscraper,
|
||||
IconCalendarEvent,
|
||||
IconCheckbox,
|
||||
type IconComponent,
|
||||
IconFileText,
|
||||
IconHeart,
|
||||
IconLayoutDashboard,
|
||||
IconNotes,
|
||||
IconRocket,
|
||||
IconStar,
|
||||
IconTargetArrow,
|
||||
IconUser,
|
||||
IconUserCircle,
|
||||
} from 'twenty-ui/display';
|
||||
import { type ThemeColor } from 'twenty-ui/theme';
|
||||
|
||||
export type BackgroundMockNavigationItem = {
|
||||
label: string;
|
||||
Icon: IconComponent;
|
||||
color: ThemeColor;
|
||||
};
|
||||
|
||||
export const BACKGROUND_MOCK_WORKSPACE_ITEMS = [
|
||||
{ label: 'Companies', Icon: IconBuildingSkyscraper, color: 'blue' },
|
||||
{ label: 'People', Icon: IconUser, color: 'blue' },
|
||||
{ label: 'Opportunities', Icon: IconTargetArrow, color: 'red' },
|
||||
{ label: 'Tasks', Icon: IconCheckbox, color: 'turquoise' },
|
||||
{ label: 'Notes', Icon: IconNotes, color: 'turquoise' },
|
||||
{ label: 'Dashboards', Icon: IconLayoutDashboard, color: 'orange' },
|
||||
{ label: 'Workflows', Icon: IconRocket, color: 'pink' },
|
||||
{ label: 'Rockets', Icon: IconRocket, color: 'sky' },
|
||||
{ label: 'Pets', Icon: IconHeart, color: 'orange' },
|
||||
{ label: 'Survey results', Icon: IconStar, color: 'yellow' },
|
||||
{ label: 'Employment Histories', Icon: IconUserCircle, color: 'green' },
|
||||
{ label: 'Pet Care Agreements', Icon: IconFileText, color: 'purple' },
|
||||
{ label: 'Star History', Icon: IconCalendarEvent, color: 'red' },
|
||||
] satisfies BackgroundMockNavigationItem[];
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { IconFileText, IconSettings } from 'twenty-ui/display';
|
||||
|
||||
import { type BackgroundMockNavigationItem } from '@/sign-in-background-mock/constants/BackgroundMockNavigationItems';
|
||||
|
||||
export const BACKGROUND_MOCK_OTHER_ITEMS = [
|
||||
{ label: 'Settings', Icon: IconSettings, color: 'gray' },
|
||||
{ label: 'Documentation', Icon: IconFileText, color: 'gray' },
|
||||
] satisfies BackgroundMockNavigationItem[];
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export const BACKGROUND_MOCK_TABLE_DIMENSIONS = {
|
||||
rowHeight: 32,
|
||||
dragHandleColumnWidth: 12,
|
||||
checkboxColumnWidth: 28,
|
||||
addColumnButtonWidth: 32,
|
||||
} as const;
|
||||
-302
@@ -1,302 +0,0 @@
|
||||
/* oxlint-disable twenty/max-consts-per-file */
|
||||
import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { type ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||
import { findByProperty } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType, RelationType } from '~/generated-metadata/graphql';
|
||||
import { getMockObjectMetadataItemOrThrow } from '~/testing/utils/getMockObjectMetadataItemOrThrow';
|
||||
|
||||
const COMPANY_MOCK_OBJECT = getMockObjectMetadataItemOrThrow('company');
|
||||
|
||||
export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = (
|
||||
[
|
||||
{
|
||||
position: 0,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'name'))?.id ??
|
||||
'',
|
||||
label: 'Name',
|
||||
size: 100,
|
||||
type: FieldMetadataType.TEXT,
|
||||
metadata: {
|
||||
fieldName: 'name',
|
||||
placeHolder: 'Name',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconBuildingSkyscraper',
|
||||
isVisible: true,
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
position: 1,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'domainName'))
|
||||
?.id ?? '',
|
||||
label: 'Domain Name',
|
||||
size: 100,
|
||||
type: FieldMetadataType.LINKS,
|
||||
metadata: {
|
||||
fieldName: 'domainName',
|
||||
placeHolder: 'Domain Name',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconLink',
|
||||
isVisible: true,
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
position: 2,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'employees'))
|
||||
?.id ?? '',
|
||||
label: 'Employees',
|
||||
size: 100,
|
||||
type: FieldMetadataType.NUMBER,
|
||||
metadata: {
|
||||
fieldName: 'employees',
|
||||
placeHolder: 'Employees',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconUsers',
|
||||
isVisible: true,
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
position: 3,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'people'))?.id ??
|
||||
'',
|
||||
label: 'People',
|
||||
size: 100,
|
||||
type: FieldMetadataType.RELATION,
|
||||
metadata: {
|
||||
fieldName: 'people',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconUsers',
|
||||
isVisible: true,
|
||||
defaultValue: [],
|
||||
},
|
||||
{
|
||||
position: 4,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'address'))
|
||||
?.id ?? '',
|
||||
label: 'Address',
|
||||
size: 100,
|
||||
type: FieldMetadataType.ADDRESS,
|
||||
metadata: {
|
||||
fieldName: 'address',
|
||||
placeHolder: 'Address',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconMap',
|
||||
isVisible: true,
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
position: 5,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'accountOwner'))
|
||||
?.id ?? '',
|
||||
label: 'Account Owner',
|
||||
size: 100,
|
||||
type: FieldMetadataType.RELATION,
|
||||
metadata: {
|
||||
fieldName: 'accountOwner',
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
relationObjectMetadataNameSingular: 'workspaceMember',
|
||||
relationObjectMetadataNamePlural: 'workspaceMembers',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconUserCircle',
|
||||
isVisible: true,
|
||||
defaultValue: null,
|
||||
},
|
||||
{
|
||||
position: 6,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'attachments'))
|
||||
?.id ?? '',
|
||||
label: 'Attachments',
|
||||
size: 100,
|
||||
type: FieldMetadataType.RELATION,
|
||||
metadata: {
|
||||
fieldName: 'attachments',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconFileImport',
|
||||
isVisible: true,
|
||||
defaultValue: [],
|
||||
},
|
||||
{
|
||||
position: 7,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'createdAt'))
|
||||
?.id ?? '',
|
||||
label: 'Creation date',
|
||||
size: 100,
|
||||
type: FieldMetadataType.DATE_TIME,
|
||||
metadata: {
|
||||
fieldName: 'createdAt',
|
||||
placeHolder: 'Creation date',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconCalendar',
|
||||
isVisible: true,
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
position: 8,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(
|
||||
findByProperty('name', 'idealCustomerProfile'),
|
||||
)?.id ?? '',
|
||||
label: 'ICP',
|
||||
size: 100,
|
||||
type: FieldMetadataType.BOOLEAN,
|
||||
metadata: {
|
||||
fieldName: 'idealCustomerProfile',
|
||||
placeHolder: 'ICP',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconTarget',
|
||||
isVisible: true,
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
position: 9,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'linkedinLink'))
|
||||
?.id ?? '',
|
||||
label: 'Linkedin',
|
||||
size: 100,
|
||||
type: FieldMetadataType.LINKS,
|
||||
metadata: {
|
||||
fieldName: 'linkedinLink',
|
||||
placeHolder: 'Linkedin',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconBrandLinkedin',
|
||||
isVisible: true,
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
position: 10,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'opportunities'))
|
||||
?.id ?? '',
|
||||
label: 'Opportunities',
|
||||
size: 100,
|
||||
type: FieldMetadataType.RELATION,
|
||||
metadata: {
|
||||
fieldName: 'opportunities',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconTargetArrow',
|
||||
isVisible: true,
|
||||
defaultValue: [],
|
||||
},
|
||||
{
|
||||
position: 11,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'xLink'))?.id ??
|
||||
'',
|
||||
label: 'X',
|
||||
size: 100,
|
||||
type: FieldMetadataType.LINKS,
|
||||
metadata: {
|
||||
fieldName: 'xLink',
|
||||
placeHolder: 'X',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconBrandX',
|
||||
isVisible: true,
|
||||
defaultValue: '',
|
||||
},
|
||||
{
|
||||
position: 12,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(
|
||||
findByProperty('name', 'activityTargets'),
|
||||
)?.id ?? '',
|
||||
label: 'Activities',
|
||||
size: 100,
|
||||
type: FieldMetadataType.RELATION,
|
||||
metadata: {
|
||||
fieldName: 'activityTargets',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconCheckbox',
|
||||
isVisible: true,
|
||||
defaultValue: [],
|
||||
},
|
||||
{
|
||||
position: 13,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(
|
||||
findByProperty('name', 'annualRecurringRevenue'),
|
||||
)?.id ?? '',
|
||||
label: 'ARR',
|
||||
size: 100,
|
||||
type: FieldMetadataType.CURRENCY,
|
||||
metadata: {
|
||||
fieldName: 'annualRecurringRevenue',
|
||||
placeHolder: 'ARR',
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconMoneybag',
|
||||
isVisible: true,
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
position: 14,
|
||||
fieldMetadataId:
|
||||
COMPANY_MOCK_OBJECT.fields.find(findByProperty('name', 'favorites'))
|
||||
?.id ?? '',
|
||||
label: 'Favorites',
|
||||
size: 100,
|
||||
type: FieldMetadataType.RELATION,
|
||||
metadata: {
|
||||
fieldName: 'favorites',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
relationObjectMetadataNameSingular: '',
|
||||
relationObjectMetadataNamePlural: '',
|
||||
objectMetadataNameSingular: 'company',
|
||||
},
|
||||
iconName: 'IconHeart',
|
||||
isVisible: true,
|
||||
defaultValue: [],
|
||||
},
|
||||
] satisfies ColumnDefinition<FieldMetadata>[]
|
||||
).filter(filterAvailableTableColumns);
|
||||
-1385
File diff suppressed because it is too large
Load Diff
-78
@@ -1,78 +0,0 @@
|
||||
import { type ViewField } from '@/views/types/ViewField';
|
||||
|
||||
export const SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS = [
|
||||
{
|
||||
id: '5168be09-f200-40f5-9e04-29d607de06e5',
|
||||
fieldMetadataId: '20202020-7fbd-41ad-b64d-25a15ff62f04',
|
||||
size: 150,
|
||||
createdAt: '2023-11-23T15:38:03.706Z',
|
||||
viewId: '20202020-2441-4424-8163-4002c523d415',
|
||||
position: 4,
|
||||
isVisible: true,
|
||||
updatedAt: '2023-11-23T15:38:03.706Z',
|
||||
},
|
||||
{
|
||||
id: '5ece850b-76fd-4135-9b99-06d49cad14ae',
|
||||
fieldMetadataId: '20202020-a61d-4b78-b998-3fd88b4f73a1',
|
||||
size: 170,
|
||||
createdAt: '2023-11-23T15:38:03.706Z',
|
||||
viewId: '20202020-2441-4424-8163-4002c523d415',
|
||||
position: 5,
|
||||
isVisible: true,
|
||||
updatedAt: '2023-11-23T15:38:03.706Z',
|
||||
},
|
||||
{
|
||||
id: '604dbdbb-df01-4e47-921b-f9963109f912',
|
||||
fieldMetadataId: '20202020-0739-495d-8e70-c0807f6b2268',
|
||||
size: 150,
|
||||
createdAt: '2023-11-23T15:38:03.706Z',
|
||||
viewId: '20202020-2441-4424-8163-4002c523d415',
|
||||
position: 2,
|
||||
isVisible: true,
|
||||
updatedAt: '2023-11-23T15:38:03.706Z',
|
||||
},
|
||||
{
|
||||
id: '7cbc36c8-37c6-4561-8c46-ddb316ddd121',
|
||||
fieldMetadataId: '20202020-4dc2-47c9-bb15-6e6f19ba9e46',
|
||||
size: 150,
|
||||
createdAt: '2023-11-23T15:38:03.706Z',
|
||||
viewId: '20202020-2441-4424-8163-4002c523d415',
|
||||
position: 3,
|
||||
isVisible: true,
|
||||
updatedAt: '2023-11-23T15:38:03.706Z',
|
||||
},
|
||||
{
|
||||
id: 'a7d19be3-1ce9-479b-9453-2930a381e07c',
|
||||
fieldMetadataId: '20202020-5e4e-4007-a630-8a2617914889',
|
||||
size: 100,
|
||||
createdAt: '2023-11-23T15:38:03.706Z',
|
||||
viewId: '20202020-2441-4424-8163-4002c523d415',
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
updatedAt: '2023-11-23T15:38:03.706Z',
|
||||
},
|
||||
{
|
||||
id: 'cafacdc8-cbfc-4545-8242-94787f144ace',
|
||||
fieldMetadataId: 'REPLACE_ME',
|
||||
size: 180,
|
||||
createdAt: '2023-11-23T15:38:03.706Z',
|
||||
viewId: '20202020-2441-4424-8163-4002c523d415',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
updatedAt: '2023-11-23T15:38:03.706Z',
|
||||
},
|
||||
{
|
||||
id: 'f0cc50c9-b9b6-405b-a1c0-23f7698ea731',
|
||||
fieldMetadataId: '20202020-ad10-4117-a039-3f04b7a5f939',
|
||||
size: 170,
|
||||
createdAt: '2023-11-23T15:38:03.706Z',
|
||||
viewId: '20202020-2441-4424-8163-4002c523d415',
|
||||
position: 6,
|
||||
isVisible: true,
|
||||
updatedAt: '2023-11-23T15:38:03.706Z',
|
||||
},
|
||||
] as (ViewField & {
|
||||
createdAt: string;
|
||||
viewId: string;
|
||||
updatedAt: string;
|
||||
})[];
|
||||
@@ -11,12 +11,12 @@ import { MobileNavigationBar } from '@/navigation/components/MobileNavigationBar
|
||||
import { PageDragDropProvider } from '@/navigation-menu-item/display/dnd/providers/PageDragDropProvider';
|
||||
import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage';
|
||||
import { OBJECT_SETTINGS_WIDTH } from '@/settings/data-model/constants/ObjectSettings';
|
||||
import { SignInAppNavigationDrawerMock } from '@/sign-in-background-mock/components/SignInAppNavigationDrawerMock';
|
||||
import { BackgroundMockNavigationDrawer } from '@/sign-in-background-mock/components/BackgroundMockNavigationDrawer';
|
||||
import { Suspense, lazy, useContext } from 'react';
|
||||
|
||||
const SignInBackgroundMockPage = lazy(() =>
|
||||
import('@/sign-in-background-mock/components/SignInBackgroundMockPage').then(
|
||||
(module) => ({ default: module.SignInBackgroundMockPage }),
|
||||
const BackgroundMockPage = lazy(() =>
|
||||
import('@/sign-in-background-mock/components/BackgroundMockPage').then(
|
||||
(module) => ({ default: module.BackgroundMockPage }),
|
||||
),
|
||||
);
|
||||
import { useShowFullscreen } from '@/ui/layout/fullscreen/hooks/useShowFullscreen';
|
||||
@@ -95,7 +95,7 @@ export const DefaultLayout = () => {
|
||||
{!showAuthModal && <KeyboardShortcutMenu />}
|
||||
{showAuthModal ? (
|
||||
<StyledNavigationDrawerWrapper>
|
||||
<SignInAppNavigationDrawerMock />
|
||||
<BackgroundMockNavigationDrawer />
|
||||
</StyledNavigationDrawerWrapper>
|
||||
) : useShowFullScreen ? null : (
|
||||
<StyledNavigationDrawerWrapper>
|
||||
@@ -106,7 +106,7 @@ export const DefaultLayout = () => {
|
||||
<>
|
||||
<StyledMainContainer>
|
||||
<Suspense fallback={null}>
|
||||
<SignInBackgroundMockPage />
|
||||
<BackgroundMockPage />
|
||||
</Suspense>
|
||||
</StyledMainContainer>
|
||||
<AnimatePresence mode="wait">
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { lazy, Suspense } from 'react';
|
||||
|
||||
const SignInBackgroundMockPage = lazy(() =>
|
||||
import('@/sign-in-background-mock/components/SignInBackgroundMockPage').then(
|
||||
(module) => ({ default: module.SignInBackgroundMockPage }),
|
||||
const BackgroundMockPage = lazy(() =>
|
||||
import('@/sign-in-background-mock/components/BackgroundMockPage').then(
|
||||
(module) => ({ default: module.BackgroundMockPage }),
|
||||
),
|
||||
);
|
||||
import { AppPath } from 'twenty-shared/types';
|
||||
@@ -69,7 +69,7 @@ export const NotFound = () => {
|
||||
</AnimatedPlaceholderErrorContainer>
|
||||
</StyledBackDrop>
|
||||
<Suspense fallback={null}>
|
||||
<SignInBackgroundMockPage />
|
||||
<BackgroundMockPage />
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { useLoadMockedMetadata } from '@/metadata-store/hooks/useLoadMockedMetadata';
|
||||
import { isMinimalMetadataReadyState } from '@/metadata-store/states/isMinimalMetadataReadyState';
|
||||
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const MockedMetadataLoadEffect = () => {
|
||||
const { loadMockedMetadataAtomic } = useLoadMockedMetadata();
|
||||
const metadataStore = useAtomFamilyStateValue(
|
||||
metadataStoreState,
|
||||
'objectMetadataItems',
|
||||
);
|
||||
const setIsMinimalMetadataReady = useSetAtomState(
|
||||
isMinimalMetadataReadyState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
void loadMockedMetadataAtomic();
|
||||
}, [loadMockedMetadataAtomic]);
|
||||
|
||||
useEffect(() => {
|
||||
if (metadataStore.status === 'up-to-date') {
|
||||
setIsMinimalMetadataReady(true);
|
||||
} else {
|
||||
setIsMinimalMetadataReady(false);
|
||||
}
|
||||
}, [metadataStore.status, setIsMinimalMetadataReady]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -16,8 +16,7 @@ import { ApolloCoreClientMockedProvider } from '@/object-metadata/hooks/__mocks_
|
||||
import { DefaultLayout } from '@/ui/layout/page/components/DefaultLayout';
|
||||
import { MinimalMetadataGater } from '@/metadata-store/components/MinimalMetadataGater';
|
||||
import { UserMetadataProviderInitialEffect } from '@/metadata-store/effect-components/UserMetadataProviderInitialEffect';
|
||||
import { IsMinimalMetadataReadyEffect } from '@/metadata-store/effect-components/IsMinimalMetadataReadyEffect';
|
||||
import { MinimalMetadataLoadEffect } from '@/metadata-store/effect-components/MinimalMetadataLoadEffect';
|
||||
import { MockedMetadataLoadEffect } from '~/testing/decorators/MockedMetadataLoadEffect';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useState } from 'react';
|
||||
import { ClientConfigProvider } from '~/modules/client-config/components/ClientConfigProvider';
|
||||
@@ -87,8 +86,7 @@ const Providers = () => {
|
||||
<ClientConfigProviderEffect />
|
||||
<ClientConfigProvider>
|
||||
<UserMetadataProviderInitialEffect />
|
||||
<MinimalMetadataLoadEffect />
|
||||
<IsMinimalMetadataReadyEffect />
|
||||
<MockedMetadataLoadEffect />
|
||||
<WorkspaceProviderEffect />
|
||||
<MinimalMetadataGater>
|
||||
<ApolloCoreClientMockedProvider>
|
||||
|
||||
Reference in New Issue
Block a user