Add calendar field metadata id to view table (#14478)
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -529,6 +529,7 @@ export type ConnectionParametersOutput = {
|
||||
export type CoreView = {
|
||||
__typename?: 'CoreView';
|
||||
anyFieldFilterValue?: Maybe<Scalars['String']>;
|
||||
calendarFieldMetadataId?: Maybe<Scalars['UUID']>;
|
||||
calendarLayout?: Maybe<ViewCalendarLayout>;
|
||||
createdAt: Scalars['DateTime'];
|
||||
deletedAt?: Maybe<Scalars['DateTime']>;
|
||||
@@ -773,6 +774,7 @@ export type CreateViewGroupInput = {
|
||||
|
||||
export type CreateViewInput = {
|
||||
anyFieldFilterValue?: InputMaybe<Scalars['String']>;
|
||||
calendarFieldMetadataId?: InputMaybe<Scalars['UUID']>;
|
||||
calendarLayout?: InputMaybe<ViewCalendarLayout>;
|
||||
icon: Scalars['String'];
|
||||
id?: InputMaybe<Scalars['UUID']>;
|
||||
@@ -3495,6 +3497,7 @@ export type UpdateViewGroupInput = {
|
||||
|
||||
export type UpdateViewInput = {
|
||||
anyFieldFilterValue?: InputMaybe<Scalars['String']>;
|
||||
calendarFieldMetadataId?: InputMaybe<Scalars['UUID']>;
|
||||
calendarLayout?: InputMaybe<ViewCalendarLayout>;
|
||||
icon?: InputMaybe<Scalars['String']>;
|
||||
id?: InputMaybe<Scalars['UUID']>;
|
||||
@@ -3951,7 +3954,7 @@ export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: an
|
||||
|
||||
export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any };
|
||||
|
||||
export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> };
|
||||
export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> };
|
||||
|
||||
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any };
|
||||
|
||||
@@ -3962,7 +3965,7 @@ export type CreateCoreViewMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } };
|
||||
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } };
|
||||
|
||||
export type CreateCoreViewFieldMutationVariables = Exact<{
|
||||
input: CreateViewFieldInput;
|
||||
@@ -4089,7 +4092,7 @@ export type UpdateCoreViewMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } };
|
||||
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } };
|
||||
|
||||
export type UpdateCoreViewFieldMutationVariables = Exact<{
|
||||
input: UpdateViewFieldInput;
|
||||
@@ -4170,14 +4173,14 @@ export type FindManyCoreViewsQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> }> };
|
||||
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> }> };
|
||||
|
||||
export type FindOneCoreViewQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } | null };
|
||||
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, fieldMetadataId: any, isVisible: boolean, fieldValue: string, position: number, viewId: any }> } | null };
|
||||
|
||||
export type FindOneCoreViewFieldQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
@@ -4281,6 +4284,8 @@ export const ViewFragmentFragmentDoc = gql`
|
||||
kanbanAggregateOperation
|
||||
kanbanAggregateOperationFieldMetadataId
|
||||
anyFieldFilterValue
|
||||
calendarFieldMetadataId
|
||||
calendarLayout
|
||||
viewFields {
|
||||
...ViewFieldFragment
|
||||
}
|
||||
|
||||
+17
-4
@@ -17,6 +17,7 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||
import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar';
|
||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
@@ -62,7 +63,8 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
||||
const { setAndPersistViewType } = useSetViewTypeFromLayoutOptionsMenu();
|
||||
const { availableFieldsForKanban, navigateToSelectSettings } =
|
||||
useGetAvailableFieldsForKanban();
|
||||
|
||||
const { availableFieldsForCalendar, navigateToDateFieldSettings } =
|
||||
useGetAvailableFieldsForCalendar();
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const handleSelectKanbanViewType = async () => {
|
||||
@@ -78,6 +80,19 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectCalendarViewType = async () => {
|
||||
if (isDefaultView) {
|
||||
return;
|
||||
}
|
||||
if (availableFieldsForCalendar.length === 0) {
|
||||
navigateToDateFieldSettings();
|
||||
closeDropdown(dropdownId);
|
||||
}
|
||||
if (currentView?.type !== ViewType.Calendar) {
|
||||
await setAndPersistViewType(ViewType.Calendar);
|
||||
}
|
||||
};
|
||||
|
||||
const isDefaultView = currentView?.key === 'INDEX';
|
||||
const nbsp = '\u00A0';
|
||||
|
||||
@@ -148,9 +163,7 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
||||
text={t`Calendar`}
|
||||
selected={currentView?.type === ViewType.Calendar}
|
||||
focused={selectedItemId === ViewType.Calendar}
|
||||
onClick={() => {
|
||||
setAndPersistViewType(ViewType.Calendar);
|
||||
}}
|
||||
onClick={handleSelectCalendarViewType}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
)}
|
||||
|
||||
+13
@@ -12,6 +12,7 @@ import { type ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { convertViewTypeToCore } from '@/views/utils/convertViewTypeToCore';
|
||||
import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar';
|
||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||
import { useCallback } from 'react';
|
||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||
@@ -29,6 +30,8 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
|
||||
const { createViewGroupRecords } = usePersistViewGroupRecords();
|
||||
|
||||
const { availableFieldsForCalendar } = useGetAvailableFieldsForCalendar();
|
||||
|
||||
const createViewGroupAssociatedWithKanbanField = useCallback(
|
||||
async (randomFieldForKanban: string, currentViewId: string) => {
|
||||
const viewGroupsToCreate =
|
||||
@@ -149,6 +152,12 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
return await updateCurrentView(updateCurrentViewParams);
|
||||
}
|
||||
case ViewType.Calendar: {
|
||||
if (availableFieldsForCalendar.length === 0) {
|
||||
throw new Error('No date fields for calendar');
|
||||
}
|
||||
|
||||
const calendarFieldMetadataId = availableFieldsForCalendar[0].id;
|
||||
|
||||
setRecordIndexViewType(viewType);
|
||||
set(coreViewsState, [
|
||||
...existingCoreViews.filter(
|
||||
@@ -158,6 +167,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
...currentCoreView,
|
||||
type: convertViewTypeToCore(viewType),
|
||||
calendarLayout: ViewCalendarLayout.MONTH,
|
||||
calendarFieldMetadataId,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -166,6 +176,8 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
viewTypeIconMapping(viewType).displayName;
|
||||
}
|
||||
updateCurrentViewParams.calendarLayout = ViewCalendarLayout.MONTH;
|
||||
updateCurrentViewParams.calendarFieldMetadataId =
|
||||
calendarFieldMetadataId;
|
||||
return await updateCurrentView(updateCurrentViewParams);
|
||||
}
|
||||
default: {
|
||||
@@ -180,6 +192,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
setRecordIndexViewType,
|
||||
createViewGroupAssociatedWithKanbanField,
|
||||
loadRecordIndexStates,
|
||||
availableFieldsForCalendar,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ export const VIEW_FRAGMENT = gql`
|
||||
kanbanAggregateOperation
|
||||
kanbanAggregateOperationFieldMetadataId
|
||||
anyFieldFilterValue
|
||||
calendarFieldMetadataId
|
||||
calendarLayout
|
||||
viewFields {
|
||||
...ViewFieldFragment
|
||||
}
|
||||
|
||||
@@ -80,11 +80,17 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
name,
|
||||
icon,
|
||||
kanbanFieldMetadataId,
|
||||
calendarFieldMetadataId,
|
||||
type,
|
||||
}: Partial<
|
||||
Pick<
|
||||
GraphQLView,
|
||||
'id' | 'name' | 'icon' | 'kanbanFieldMetadataId' | 'type'
|
||||
| 'id'
|
||||
| 'name'
|
||||
| 'icon'
|
||||
| 'kanbanFieldMetadataId'
|
||||
| 'calendarFieldMetadataId'
|
||||
| 'type'
|
||||
>
|
||||
>,
|
||||
shouldCopyFiltersAndSortsAndAggregate?: boolean,
|
||||
@@ -138,6 +144,10 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
viewType === ViewType.Calendar
|
||||
? ViewCalendarLayout.MONTH
|
||||
: undefined,
|
||||
calendarFieldMetadataId:
|
||||
viewType === ViewType.Calendar
|
||||
? calendarFieldMetadataId
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -32,4 +32,5 @@ export type GraphQLView = {
|
||||
icon: string;
|
||||
anyFieldFilterValue?: string | null;
|
||||
calendarLayout?: ViewCalendarLayout | null;
|
||||
calendarFieldMetadataId?: string | null;
|
||||
};
|
||||
|
||||
@@ -37,6 +37,11 @@ export const convertUpdateViewInputToCore = (
|
||||
...(convertedKey && { key: convertedKey }),
|
||||
...(convertedOpenRecordIn && { openRecordIn: convertedOpenRecordIn }),
|
||||
...(convertedType && { type: convertedType }),
|
||||
...(view.calendarLayout && { calendarLayout: view.calendarLayout }),
|
||||
...(isDefined(view.calendarLayout) && {
|
||||
calendarLayout: view.calendarLayout,
|
||||
}),
|
||||
...(isDefined(view.calendarFieldMetadataId) && {
|
||||
calendarFieldMetadataId: view.calendarFieldMetadataId,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
+43
-3
@@ -20,13 +20,16 @@ import { ViewPickerCreateButton } from '@/views/view-picker/components/ViewPicke
|
||||
import { ViewPickerIconAndNameContainer } from '@/views/view-picker/components/ViewPickerIconAndNameContainer';
|
||||
import { ViewPickerSaveButtonContainer } from '@/views/view-picker/components/ViewPickerSaveButtonContainer';
|
||||
import { ViewPickerSelectContainer } from '@/views/view-picker/components/ViewPickerSelectContainer';
|
||||
import { VIEW_PICKER_CALENDAR_FIELD_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerCalendarFieldDropdownId';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerKanbanFieldDropdownId';
|
||||
import { VIEW_PICKER_TYPE_SELECT_OPTIONS } from '@/views/view-picker/constants/ViewPickerTypeSelectOptions';
|
||||
import { VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerViewTypeDropdownId';
|
||||
import { useCreateViewFromCurrentState } from '@/views/view-picker/hooks/useCreateViewFromCurrentState';
|
||||
import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar';
|
||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { viewPickerCalendarFieldMetadataIdComponentState } from '@/views/view-picker/states/viewPickerCalendarFieldMetadataIdComponentState';
|
||||
import { viewPickerInputNameComponentState } from '@/views/view-picker/states/viewPickerInputNameComponentState';
|
||||
import { viewPickerIsDirtyComponentState } from '@/views/view-picker/states/viewPickerIsDirtyComponentState';
|
||||
import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states/viewPickerIsPersistingComponentState';
|
||||
@@ -39,7 +42,7 @@ import { useMemo, useState } from 'react';
|
||||
import { IconX } from 'twenty-ui/display';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
|
||||
const StyledNoKanbanFieldAvailableContainer = styled.div`
|
||||
const StyledFieldAvailableContainer = styled.div`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
display: flex;
|
||||
margin: ${({ theme }) => theme.spacing(1, 2)};
|
||||
@@ -76,6 +79,11 @@ export const ViewPickerContentCreateMode = () => {
|
||||
const [viewPickerKanbanFieldMetadataId, setViewPickerKanbanFieldMetadataId] =
|
||||
useRecoilComponentState(viewPickerKanbanFieldMetadataIdComponentState);
|
||||
|
||||
const [
|
||||
viewPickerCalendarFieldMetadataId,
|
||||
setViewPickerCalendarFieldMetadataId,
|
||||
] = useRecoilComponentState(viewPickerCalendarFieldMetadataIdComponentState);
|
||||
|
||||
const [viewPickerType, setViewPickerType] = useRecoilComponentState(
|
||||
viewPickerTypeComponentState,
|
||||
);
|
||||
@@ -84,6 +92,7 @@ export const ViewPickerContentCreateMode = () => {
|
||||
|
||||
const { availableFieldsForKanban } = useGetAvailableFieldsForKanban();
|
||||
|
||||
const { availableFieldsForCalendar } = useGetAvailableFieldsForCalendar();
|
||||
const featureFlags = useFeatureFlagsMap();
|
||||
|
||||
const hasCalendarViewEnabled =
|
||||
@@ -117,6 +126,7 @@ export const ViewPickerContentCreateMode = () => {
|
||||
createViewFromCurrentState,
|
||||
viewPickerType,
|
||||
availableFieldsForKanban,
|
||||
availableFieldsForCalendar,
|
||||
],
|
||||
});
|
||||
|
||||
@@ -207,10 +217,40 @@ export const ViewPickerContentCreateMode = () => {
|
||||
/>
|
||||
</ViewPickerSelectContainer>
|
||||
{availableFieldsForKanban.length === 0 && (
|
||||
<StyledNoKanbanFieldAvailableContainer>
|
||||
<StyledFieldAvailableContainer>
|
||||
Set up a Select field on {objectMetadataItem.labelPlural} to
|
||||
create a Kanban
|
||||
</StyledNoKanbanFieldAvailableContainer>
|
||||
</StyledFieldAvailableContainer>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{viewPickerType === ViewType.Calendar && (
|
||||
<>
|
||||
<ViewPickerSelectContainer>
|
||||
<Select
|
||||
label={t`Date field`}
|
||||
fullWidth
|
||||
value={viewPickerCalendarFieldMetadataId}
|
||||
onChange={(value) => {
|
||||
setViewPickerIsDirty(true);
|
||||
setViewPickerCalendarFieldMetadataId(value);
|
||||
}}
|
||||
options={
|
||||
availableFieldsForCalendar.length > 0
|
||||
? availableFieldsForCalendar.map((field) => ({
|
||||
value: field.id,
|
||||
label: field.label,
|
||||
}))
|
||||
: [{ value: '', label: t`No Date field` }]
|
||||
}
|
||||
dropdownId={VIEW_PICKER_CALENDAR_FIELD_DROPDOWN_ID}
|
||||
/>
|
||||
</ViewPickerSelectContainer>
|
||||
{availableFieldsForCalendar.length === 0 && (
|
||||
<StyledFieldAvailableContainer>
|
||||
Set up a Date field on {objectMetadataItem.labelPlural} to
|
||||
create a Calendar
|
||||
</StyledFieldAvailableContainer>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export const VIEW_PICKER_CALENDAR_FIELD_DROPDOWN_ID =
|
||||
'view-picker-calendar-field';
|
||||
+12
-1
@@ -3,6 +3,7 @@ import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { useChangeView } from '@/views/hooks/useChangeView';
|
||||
import { useCreateViewFromCurrentView } from '@/views/hooks/useCreateViewFromCurrentView';
|
||||
import { useCloseAndResetViewPicker } from '@/views/view-picker/hooks/useCloseAndResetViewPicker';
|
||||
import { viewPickerCalendarFieldMetadataIdComponentState } from '@/views/view-picker/states/viewPickerCalendarFieldMetadataIdComponentState';
|
||||
import { viewPickerInputNameComponentState } from '@/views/view-picker/states/viewPickerInputNameComponentState';
|
||||
import { viewPickerIsDirtyComponentState } from '@/views/view-picker/states/viewPickerIsDirtyComponentState';
|
||||
import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states/viewPickerIsPersistingComponentState';
|
||||
@@ -33,6 +34,11 @@ export const useCreateViewFromCurrentState = () => {
|
||||
viewPickerKanbanFieldMetadataIdComponentState,
|
||||
);
|
||||
|
||||
const viewPickerCalendarFieldMetadataIdCallbackState =
|
||||
useRecoilComponentCallbackState(
|
||||
viewPickerCalendarFieldMetadataIdComponentState,
|
||||
);
|
||||
|
||||
const viewPickerIsPersistingCallbackState = useRecoilComponentCallbackState(
|
||||
viewPickerIsPersistingComponentState,
|
||||
);
|
||||
@@ -64,7 +70,10 @@ export const useCreateViewFromCurrentState = () => {
|
||||
snapshot,
|
||||
viewPickerKanbanFieldMetadataIdCallbackState,
|
||||
);
|
||||
|
||||
const calendarFieldMetadataId = getSnapshotValue(
|
||||
snapshot,
|
||||
viewPickerCalendarFieldMetadataIdCallbackState,
|
||||
);
|
||||
const viewPickerMode = getSnapshotValue(
|
||||
snapshot,
|
||||
viewPickerModeCallbackState,
|
||||
@@ -82,6 +91,7 @@ export const useCreateViewFromCurrentState = () => {
|
||||
icon: iconKey,
|
||||
type,
|
||||
kanbanFieldMetadataId,
|
||||
calendarFieldMetadataId,
|
||||
},
|
||||
shouldCopyFiltersAndSortsAndAggregate,
|
||||
);
|
||||
@@ -99,6 +109,7 @@ export const useCreateViewFromCurrentState = () => {
|
||||
viewPickerIsDirtyCallbackState,
|
||||
viewPickerIsPersistingCallbackState,
|
||||
viewPickerKanbanFieldMetadataIdCallbackState,
|
||||
viewPickerCalendarFieldMetadataIdCallbackState,
|
||||
viewPickerSelectedIconCallbackState,
|
||||
viewPickerTypeCallbackState,
|
||||
viewPickerModeCallbackState,
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
||||
import { SettingsPath } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||
|
||||
export const useGetAvailableFieldsForCalendar = () => {
|
||||
const viewObjectMetadataId = useRecoilComponentValue(
|
||||
viewObjectMetadataIdComponentState,
|
||||
);
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
const setNavigationMemorizedUrl = useSetRecoilState(
|
||||
navigationMemorizedUrlState,
|
||||
);
|
||||
const location = useLocation();
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadata) => objectMetadata.id === viewObjectMetadataId,
|
||||
);
|
||||
|
||||
const availableFieldsForCalendar =
|
||||
objectMetadataItem?.readableFields.filter(
|
||||
(field) =>
|
||||
field.type === FieldMetadataType.DATE ||
|
||||
field.type === FieldMetadataType.DATE_TIME,
|
||||
) ?? [];
|
||||
|
||||
const navigate = useNavigateSettings();
|
||||
|
||||
const navigateToDateFieldSettings = useCallback(() => {
|
||||
setNavigationMemorizedUrl(location.pathname + location.search);
|
||||
|
||||
if (isDefined(objectMetadataItem?.namePlural)) {
|
||||
navigate(
|
||||
SettingsPath.ObjectNewFieldConfigure,
|
||||
{
|
||||
objectNamePlural: objectMetadataItem.namePlural,
|
||||
},
|
||||
{
|
||||
fieldType: FieldMetadataType.DATE,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
navigate(SettingsPath.Objects);
|
||||
}
|
||||
}, [
|
||||
setNavigationMemorizedUrl,
|
||||
location.pathname,
|
||||
location.search,
|
||||
objectMetadataItem,
|
||||
navigate,
|
||||
]);
|
||||
|
||||
return {
|
||||
availableFieldsForCalendar,
|
||||
navigateToDateFieldSettings,
|
||||
};
|
||||
};
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
|
||||
export const viewPickerCalendarFieldMetadataIdComponentState =
|
||||
createComponentState<string>({
|
||||
key: 'viewPickerCalendarFieldMetadataIdComponentState',
|
||||
defaultValue: '',
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
});
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { type MigrationInterface, type QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddCalendarFieldMetadataIdToViewTable1757864696439
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'AddCalendarFieldMetadataIdToViewTable1757864696439';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" DROP CONSTRAINT "CHK_VIEW_CALENDAR_LAYOUT_NOT_NULL_WHEN_TYPE_CALENDAR"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" ADD "calendarFieldMetadataId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" ADD CONSTRAINT "CHK_VIEW_CALENDAR_INTEGRITY" CHECK (("type" != 'CALENDAR' OR ("calendarLayout" IS NOT NULL AND "calendarFieldMetadataId" IS NOT NULL)))`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" DROP CONSTRAINT "CHK_VIEW_CALENDAR_INTEGRITY"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" DROP COLUMN "calendarFieldMetadataId"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."view" ADD CONSTRAINT "CHK_VIEW_CALENDAR_LAYOUT_NOT_NULL_WHEN_TYPE_CALENDAR" CHECK (((type <> 'CALENDAR'::core.view_type_enum) OR ("calendarLayout" IS NOT NULL)))`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -50,4 +50,7 @@ export class CreateViewInput {
|
||||
|
||||
@Field(() => ViewCalendarLayout, { nullable: true })
|
||||
calendarLayout?: ViewCalendarLayout;
|
||||
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
calendarFieldMetadataId?: string;
|
||||
}
|
||||
|
||||
@@ -44,4 +44,7 @@ export class UpdateViewInput {
|
||||
|
||||
@Field(() => ViewCalendarLayout, { nullable: true })
|
||||
calendarLayout?: ViewCalendarLayout;
|
||||
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
calendarFieldMetadataId?: string;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,9 @@ export class ViewDTO {
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
kanbanAggregateOperationFieldMetadataId?: string | null;
|
||||
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
calendarFieldMetadataId?: string | null;
|
||||
|
||||
@Field(() => UUIDScalarType, { nullable: false })
|
||||
workspaceId: string;
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
|
||||
'objectMetadataId',
|
||||
])
|
||||
@Check(
|
||||
'CHK_VIEW_CALENDAR_LAYOUT_NOT_NULL_WHEN_TYPE_CALENDAR',
|
||||
`("type" != 'CALENDAR' OR "calendarLayout" IS NOT NULL)`,
|
||||
'CHK_VIEW_CALENDAR_INTEGRITY',
|
||||
`("type" != 'CALENDAR' OR ("calendarLayout" IS NOT NULL AND "calendarFieldMetadataId" IS NOT NULL))`,
|
||||
)
|
||||
export class ViewEntity extends SyncableEntity implements Required<ViewEntity> {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
@@ -108,6 +108,9 @@ export class ViewEntity extends SyncableEntity implements Required<ViewEntity> {
|
||||
})
|
||||
calendarLayout: ViewCalendarLayout | null;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
calendarFieldMetadataId: string | null;
|
||||
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
workspaceId: string;
|
||||
|
||||
|
||||
+1
@@ -33,5 +33,6 @@ export const fromPartialFlatViewToFlatViewWithDefault = (
|
||||
universalIdentifier: partialFlatView.universalIdentifier ?? viewId,
|
||||
viewFieldIds: partialFlatView.viewFieldIds ?? [],
|
||||
calendarLayout: partialFlatView.calendarLayout ?? null,
|
||||
calendarFieldMetadataId: partialFlatView.calendarFieldMetadataId ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user