a88d1f4442
Add support for standalone pages: a new `PageLayout` type (`STANDALONE_PAGE`) that can be rendered independently at `/page/:pageLayoutId`, not tied to any record or object context. - New `STANDALONE_PAGE` page layout type - New `PAGE_LAYOUT` navigation menu item type: adds a `pageLayoutId` foreign key to `NavigationMenuItemEntity`, allowing sidebar items to link directly to standalone pages - New `GLOBAL_OBJECT_CONTEXT` command menu availability type: separates object-context-dependent commands (Create Record, Import, Export, See Deleted, Create View, Hide Deleted) from truly global ones, so standalone pages only show relevant commands - Frontend routing & rendering: adds a `/page/:pageLayoutId` route with its own page component, header, and command menu - Widget rendering refactor - Instance commands: two fast 1.22 migrations: `pageLayoutId` column + `STANDALONE_PAGE` enum, and `GLOBAL_OBJECT_CONTEXT` availability type enum - Workspace command: backfills existing command menu items from `GLOBAL` to `GLOBAL_OBJECT_CONTEXT` where appropriate - Dev seeds: adds a sample "Star History" standalone page with an iframe widget for local development
135 lines
5.6 KiB
TypeScript
135 lines
5.6 KiB
TypeScript
import { type PropsWithChildren, useContext, useEffect, useState } from 'react';
|
|
|
|
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
|
import { contextStoreCurrentPageTypeComponentState } from '@/context-store/states/contextStoreCurrentPageTypeComponentState';
|
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
|
import { contextStoreFilterGroupsComponentState } from '@/context-store/states/contextStoreFilterGroupsComponentState';
|
|
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
|
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
|
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
|
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
|
import {
|
|
type ContextStoreTargetedRecordsRule,
|
|
contextStoreTargetedRecordsRuleComponentState,
|
|
} from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
|
import { type ContextStorePageType } from 'twenty-shared/types';
|
|
import { type ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
import { type RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
|
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
|
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
|
|
|
export type JestContextStoreSetterMocks = {
|
|
contextStoreTargetedRecordsRule?: ContextStoreTargetedRecordsRule;
|
|
contextStoreNumberOfSelectedRecords?: number;
|
|
contextStoreFilters?: RecordFilter[];
|
|
contextStoreFilterGroups?: RecordFilterGroup[];
|
|
contextStoreCurrentObjectMetadataNameSingular?: string;
|
|
contextStoreCurrentViewId?: string;
|
|
contextStoreCurrentViewType?: ContextStoreViewType;
|
|
contextStoreCurrentPageType?: ContextStorePageType;
|
|
};
|
|
|
|
type JestContextStoreSetterProps =
|
|
PropsWithChildren<JestContextStoreSetterMocks>;
|
|
export const JestContextStoreSetter = ({
|
|
contextStoreCurrentViewId,
|
|
contextStoreTargetedRecordsRule = {
|
|
mode: 'selection',
|
|
selectedRecordIds: [],
|
|
},
|
|
contextStoreNumberOfSelectedRecords = 0,
|
|
contextStoreCurrentObjectMetadataNameSingular = 'company',
|
|
contextStoreFilters = [],
|
|
contextStoreFilterGroups = [],
|
|
contextStoreCurrentViewType,
|
|
contextStoreCurrentPageType,
|
|
children,
|
|
}: JestContextStoreSetterProps) => {
|
|
const contextStoreInstanceContext = useContext(
|
|
ContextStoreComponentInstanceContext,
|
|
);
|
|
const instanceId =
|
|
contextStoreInstanceContext?.instanceId ?? MAIN_CONTEXT_STORE_INSTANCE_ID;
|
|
|
|
const setContextStoreTargetedRecordsRule = useSetAtomComponentState(
|
|
contextStoreTargetedRecordsRuleComponentState,
|
|
instanceId,
|
|
);
|
|
|
|
const setContextStoreCurrentObjectMetadataItemId = useSetAtomComponentState(
|
|
contextStoreCurrentObjectMetadataItemIdComponentState,
|
|
instanceId,
|
|
);
|
|
|
|
const setContextStoreNumberOfSelectedRecords = useSetAtomComponentState(
|
|
contextStoreNumberOfSelectedRecordsComponentState,
|
|
instanceId,
|
|
);
|
|
|
|
const setContextStoreFilters = useSetAtomComponentState(
|
|
contextStoreFiltersComponentState,
|
|
instanceId,
|
|
);
|
|
|
|
const setContextStoreFilterGroups = useSetAtomComponentState(
|
|
contextStoreFilterGroupsComponentState,
|
|
instanceId,
|
|
);
|
|
|
|
const setContextStoreCurrentViewId = useSetAtomComponentState(
|
|
contextStoreCurrentViewIdComponentState,
|
|
instanceId,
|
|
);
|
|
|
|
const setContextStoreCurrentViewType = useSetAtomComponentState(
|
|
contextStoreCurrentViewTypeComponentState,
|
|
instanceId,
|
|
);
|
|
|
|
const setContextStoreCurrentPageType = useSetAtomComponentState(
|
|
contextStoreCurrentPageTypeComponentState,
|
|
instanceId,
|
|
);
|
|
|
|
const { objectMetadataItem } = useObjectMetadataItem({
|
|
objectNameSingular: contextStoreCurrentObjectMetadataNameSingular,
|
|
});
|
|
|
|
const contextStoreCurrentObjectMetadataId = objectMetadataItem.id;
|
|
|
|
const [isLoaded, setIsLoaded] = useState(false);
|
|
useEffect(() => {
|
|
setContextStoreCurrentViewId(contextStoreCurrentViewId);
|
|
setContextStoreTargetedRecordsRule(contextStoreTargetedRecordsRule);
|
|
setContextStoreCurrentObjectMetadataItemId(objectMetadataItem.id);
|
|
setContextStoreNumberOfSelectedRecords(contextStoreNumberOfSelectedRecords);
|
|
setContextStoreFilters(contextStoreFilters);
|
|
setContextStoreFilterGroups(contextStoreFilterGroups);
|
|
setContextStoreCurrentViewType(contextStoreCurrentViewType ?? null);
|
|
setContextStoreCurrentPageType(contextStoreCurrentPageType ?? null);
|
|
setIsLoaded(true);
|
|
}, [
|
|
setContextStoreTargetedRecordsRule,
|
|
setContextStoreCurrentObjectMetadataItemId,
|
|
contextStoreTargetedRecordsRule,
|
|
contextStoreCurrentObjectMetadataId,
|
|
setContextStoreNumberOfSelectedRecords,
|
|
contextStoreNumberOfSelectedRecords,
|
|
setContextStoreFilters,
|
|
contextStoreFilters,
|
|
objectMetadataItem,
|
|
setContextStoreCurrentViewId,
|
|
contextStoreCurrentViewId,
|
|
setContextStoreCurrentViewType,
|
|
contextStoreCurrentViewType,
|
|
setContextStoreCurrentPageType,
|
|
contextStoreCurrentPageType,
|
|
setContextStoreFilterGroups,
|
|
contextStoreFilterGroups,
|
|
]);
|
|
|
|
return isLoaded ? <>{children}</> : null;
|
|
};
|