chore: remove completed migration feature flags and upgrade commands <= 1.18 (#19074)
## Summary - Remove 3 completed migration feature flags: `IS_ATTACHMENT_MIGRATED`, `IS_NOTE_TARGET_MIGRATED`, `IS_TASK_TARGET_MIGRATED` — these were already enabled by default for all new workspaces via `DEFAULT_FEATURE_FLAGS` - Delete all upgrade command directories for versions <= 1.18 (`1-16/`, `1-17/`, `1-18/`) along with their module registrations, removing ~6,600 lines of dead migration code - Simplify frontend utility functions (`getActivityTargetObjectFieldIdName`, `getActivityTargetsFilter`, `getActivityTargetFieldNameForObject`, `generateActivityTargetMorphFieldKeys`, `findActivitiesOperationSignatureFactory`) by removing the `isMorphRelation` parameter and always using the morph relation path - Remove feature flag checks from 7 frontend hooks/components that were gating attachment and activity target behavior behind the removed flags - Simplify `buildDefaultRelationFlatFieldMetadatasForCustomObject` server util to always treat attachment, noteTarget, and taskTarget as morph relations without checking feature flags
This commit is contained in:
@@ -3,17 +3,9 @@ import { type ActivityTargetableObject } from '@/activities/types/ActivityTarget
|
||||
import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useAttachments = (targetableObject: ActivityTargetableObject) => {
|
||||
const isAttachmentMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_ATTACHMENT_MIGRATED,
|
||||
);
|
||||
|
||||
const targetableObjectFieldIdName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: targetableObject.targetObjectNameSingular,
|
||||
isMorphRelation: isAttachmentMigrated,
|
||||
});
|
||||
|
||||
const { records: attachments, loading } = useFindManyRecords<Attachment>({
|
||||
|
||||
@@ -4,12 +4,10 @@ import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivi
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useApolloClient, useMutation } from '@apollo/client/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
FieldMetadataType,
|
||||
UploadFilesFieldFileDocument,
|
||||
} from '~/generated-metadata/graphql';
|
||||
@@ -19,10 +17,6 @@ export const useUploadAttachmentFile = () => {
|
||||
const [uploadFilesFieldFile] = useMutation(UploadFilesFieldFileDocument, {
|
||||
client: apolloClient,
|
||||
});
|
||||
const isAttachmentMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_ATTACHMENT_MIGRATED,
|
||||
);
|
||||
|
||||
const { objectMetadataItem: attachmentMetadata } = useObjectMetadataItem({
|
||||
objectNameSingular: CoreObjectNameSingular.Attachment,
|
||||
});
|
||||
@@ -58,7 +52,6 @@ export const useUploadAttachmentFile = () => {
|
||||
|
||||
const targetableObjectFieldIdName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: targetableObject.targetObjectNameSingular,
|
||||
isMorphRelation: isAttachmentMigrated,
|
||||
});
|
||||
|
||||
const attachmentToCreate = {
|
||||
|
||||
+2
-10
@@ -6,7 +6,6 @@ import { type RecordGqlOperationSignatureFactory } from '@/object-record/graphql
|
||||
type FindActivitiesOperationSignatureFactory = {
|
||||
objectMetadataItems: EnrichedObjectMetadataItem[];
|
||||
objectNameSingular: CoreObjectNameSingular;
|
||||
isMorphRelation: boolean;
|
||||
};
|
||||
|
||||
export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatureFactory<
|
||||
@@ -14,7 +13,6 @@ export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatur
|
||||
> = ({
|
||||
objectMetadataItems,
|
||||
objectNameSingular,
|
||||
isMorphRelation,
|
||||
}: FindActivitiesOperationSignatureFactory) => {
|
||||
const body = {
|
||||
bodyV2: {
|
||||
@@ -67,10 +65,7 @@ export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatur
|
||||
deletedAt: true,
|
||||
note: true,
|
||||
noteId: true,
|
||||
...generateActivityTargetMorphFieldKeys(
|
||||
objectMetadataItems,
|
||||
isMorphRelation,
|
||||
),
|
||||
...generateActivityTargetMorphFieldKeys(objectMetadataItems),
|
||||
},
|
||||
}
|
||||
: {
|
||||
@@ -82,10 +77,7 @@ export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatur
|
||||
deletedAt: true,
|
||||
task: true,
|
||||
taskId: true,
|
||||
...generateActivityTargetMorphFieldKeys(
|
||||
objectMetadataItems,
|
||||
isMorphRelation,
|
||||
),
|
||||
...generateActivityTargetMorphFieldKeys(objectMetadataItems),
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
+2
-19
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
CoreObjectNameSingular,
|
||||
type CoreObjectNameSingular,
|
||||
type RecordGqlOperationOrderBy,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
@@ -12,9 +12,6 @@ import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMeta
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useActivityTargetsForTargetableObjects = ({
|
||||
objectNameSingular,
|
||||
@@ -37,22 +34,8 @@ export const useActivityTargetsForTargetableObjects = ({
|
||||
const objectMetadataItems = useAtomStateValue<EnrichedObjectMetadataItem[]>(
|
||||
objectMetadataItemsSelector,
|
||||
);
|
||||
const isNoteTargetMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_NOTE_TARGET_MIGRATED,
|
||||
);
|
||||
const isTaskTargetMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_TASK_TARGET_MIGRATED,
|
||||
);
|
||||
const isMorphRelation =
|
||||
objectNameSingular === CoreObjectNameSingular.Task
|
||||
? isTaskTargetMigrated
|
||||
: isNoteTargetMigrated;
|
||||
|
||||
const activityTargetsFilter = getActivityTargetsFilter({
|
||||
targetableObjects: targetableObjects,
|
||||
activityObjectNameSingular: objectNameSingular,
|
||||
objectMetadataItems,
|
||||
isMorphRelation,
|
||||
targetableObjects,
|
||||
});
|
||||
|
||||
const FIND_ACTIVITY_TARGETS_OPERATION_SIGNATURE =
|
||||
|
||||
+1
-13
@@ -7,15 +7,13 @@ import { type TaskTarget } from '@/activities/types/TaskTarget';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { type CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
|
||||
import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache';
|
||||
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
import { sortByAscString } from '~/utils/array/sortByAscString';
|
||||
|
||||
export const usePrepareFindManyActivitiesQuery = ({
|
||||
@@ -35,12 +33,6 @@ export const usePrepareFindManyActivitiesQuery = ({
|
||||
const cache = useApolloCoreClient().cache;
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
const isNoteTargetMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_NOTE_TARGET_MIGRATED,
|
||||
);
|
||||
const isTaskTargetMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_TASK_TARGET_MIGRATED,
|
||||
);
|
||||
|
||||
const { upsertFindManyRecordsQueryInCache: upsertFindManyActivitiesInCache } =
|
||||
useUpsertFindManyRecordsQueryInCache({
|
||||
@@ -124,10 +116,6 @@ export const usePrepareFindManyActivitiesQuery = ({
|
||||
findActivitiesOperationSignatureFactory({
|
||||
objectNameSingular: activityObjectNameSingular,
|
||||
objectMetadataItems,
|
||||
isMorphRelation:
|
||||
activityObjectNameSingular === CoreObjectNameSingular.Task
|
||||
? isTaskTargetMigrated
|
||||
: isNoteTargetMigrated,
|
||||
});
|
||||
|
||||
upsertFindManyActivitiesInCache({
|
||||
|
||||
-15
@@ -11,12 +11,10 @@ import { searchRecordStoreFamilyState } from '@/object-record/record-picker/mult
|
||||
import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
type UpdateActivityTargetFromCellProps = {
|
||||
recordPickerInstanceId: string;
|
||||
@@ -54,17 +52,6 @@ export const useUpdateActivityTargetFromCell = ({
|
||||
? activityObjectNameSingular
|
||||
: joinObjectNameSingular,
|
||||
});
|
||||
const isNoteTargetMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_NOTE_TARGET_MIGRATED,
|
||||
);
|
||||
const isTaskTargetMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_TASK_TARGET_MIGRATED,
|
||||
);
|
||||
const isMorphRelation =
|
||||
activityObjectNameSingular === CoreObjectNameSingular.Task
|
||||
? isTaskTargetMigrated
|
||||
: isNoteTargetMigrated;
|
||||
|
||||
const store = useStore();
|
||||
const setRecordStore = useSetAtomFamilyState(
|
||||
recordStoreFamilyState,
|
||||
@@ -96,7 +83,6 @@ export const useUpdateActivityTargetFromCell = ({
|
||||
activityObjectNameSingular,
|
||||
targetObjectMetadataId: morphItem.objectMetadataId,
|
||||
objectMetadataItems,
|
||||
isMorphRelation,
|
||||
});
|
||||
|
||||
if (!isDefined(targetFieldName)) {
|
||||
@@ -211,7 +197,6 @@ export const useUpdateActivityTargetFromCell = ({
|
||||
activityObjectNameSingular,
|
||||
createOneActivityTarget,
|
||||
deleteOneActivityTarget,
|
||||
isMorphRelation,
|
||||
setRecordStore,
|
||||
],
|
||||
);
|
||||
|
||||
-3
@@ -3,7 +3,6 @@ import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/Enriche
|
||||
|
||||
export const generateActivityTargetMorphFieldKeys = (
|
||||
objectMetadataItems: EnrichedObjectMetadataItem[],
|
||||
isMorphRelation: boolean,
|
||||
) => {
|
||||
const targetableObjectMetadataItems = objectMetadataItems.filter(
|
||||
(objectMetadataItem) =>
|
||||
@@ -14,7 +13,6 @@ export const generateActivityTargetMorphFieldKeys = (
|
||||
targetableObjectMetadataItems.map((objectMetadataItem) => {
|
||||
const targetFieldIdName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: objectMetadataItem.nameSingular,
|
||||
isMorphRelation,
|
||||
});
|
||||
|
||||
return [targetFieldIdName.replace(/Id$/, ''), true];
|
||||
@@ -25,7 +23,6 @@ export const generateActivityTargetMorphFieldKeys = (
|
||||
targetableObjectMetadataItems.map((objectMetadataItem) => {
|
||||
const targetFieldIdName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: objectMetadataItem.nameSingular,
|
||||
isMorphRelation,
|
||||
});
|
||||
|
||||
return [targetFieldIdName, true];
|
||||
|
||||
+7
-13
@@ -9,14 +9,12 @@ type GetActivityTargetFieldNameForObjectArgs = {
|
||||
| CoreObjectNameSingular.Task;
|
||||
targetObjectMetadataId: string;
|
||||
objectMetadataItems: EnrichedObjectMetadataItem[];
|
||||
isMorphRelation?: boolean;
|
||||
};
|
||||
|
||||
export const getActivityTargetFieldNameForObject = ({
|
||||
activityObjectNameSingular,
|
||||
targetObjectMetadataId,
|
||||
objectMetadataItems,
|
||||
isMorphRelation = false,
|
||||
}: GetActivityTargetFieldNameForObjectArgs): string | undefined => {
|
||||
const activityTargetObjectNameSingular =
|
||||
activityObjectNameSingular === CoreObjectNameSingular.Task
|
||||
@@ -36,17 +34,13 @@ export const getActivityTargetFieldNameForObject = ({
|
||||
(objectMetadataItem) => objectMetadataItem.id === targetObjectMetadataId,
|
||||
);
|
||||
|
||||
if (isMorphRelation && isDefined(targetObjectMetadataItem)) {
|
||||
const fieldIdName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: targetObjectMetadataItem.nameSingular,
|
||||
isMorphRelation: true,
|
||||
});
|
||||
|
||||
return fieldIdName.replace(/Id$/, '');
|
||||
if (!isDefined(targetObjectMetadataItem)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return activityTargetObjectMetadata.fields.find(
|
||||
(field) =>
|
||||
field.relation?.targetObjectMetadata.id === targetObjectMetadataId,
|
||||
)?.name;
|
||||
const fieldIdName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: targetObjectMetadataItem.nameSingular,
|
||||
});
|
||||
|
||||
return fieldIdName.replace(/Id$/, '');
|
||||
};
|
||||
|
||||
+1
-7
@@ -2,14 +2,8 @@ import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
export const getActivityTargetObjectFieldIdName = ({
|
||||
nameSingular,
|
||||
isMorphRelation = false,
|
||||
}: {
|
||||
nameSingular: string;
|
||||
isMorphRelation?: boolean;
|
||||
}) => {
|
||||
if (isMorphRelation) {
|
||||
return `target${capitalize(nameSingular)}Id`;
|
||||
}
|
||||
|
||||
return `${nameSingular}Id`;
|
||||
return `target${capitalize(nameSingular)}Id`;
|
||||
};
|
||||
|
||||
@@ -1,58 +1,21 @@
|
||||
import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getActivityTargetsFilter = ({
|
||||
targetableObjects,
|
||||
activityObjectNameSingular,
|
||||
objectMetadataItems,
|
||||
isMorphRelation = false,
|
||||
}: {
|
||||
targetableObjects: ActivityTargetableObject[];
|
||||
activityObjectNameSingular:
|
||||
| CoreObjectNameSingular.Note
|
||||
| CoreObjectNameSingular.Task;
|
||||
objectMetadataItems: EnrichedObjectMetadataItem[];
|
||||
isMorphRelation?: boolean;
|
||||
targetableObjects: Pick<
|
||||
ActivityTargetableObject,
|
||||
'id' | 'targetObjectNameSingular'
|
||||
>[];
|
||||
}) => {
|
||||
const activityTargetObjectNameSingular =
|
||||
activityObjectNameSingular === CoreObjectNameSingular.Task
|
||||
? CoreObjectNameSingular.TaskTarget
|
||||
: CoreObjectNameSingular.NoteTarget;
|
||||
|
||||
const activityTargetObjectMetadata = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.nameSingular === activityTargetObjectNameSingular,
|
||||
);
|
||||
|
||||
const findManyActivityTargetsQueryFilter = Object.fromEntries(
|
||||
targetableObjects
|
||||
.map((targetableObject) => {
|
||||
const targetObjectMetadataItem = objectMetadataItems.find(
|
||||
(item) =>
|
||||
item.nameSingular === targetableObject.targetObjectNameSingular,
|
||||
);
|
||||
|
||||
if (!isDefined(targetObjectMetadataItem)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const joinColumnName = isMorphRelation
|
||||
? getActivityTargetObjectFieldIdName({
|
||||
nameSingular: targetObjectMetadataItem.nameSingular,
|
||||
isMorphRelation: true,
|
||||
})
|
||||
: activityTargetObjectMetadata?.fields.find(
|
||||
(field) =>
|
||||
field.relation?.targetObjectMetadata.id ===
|
||||
targetObjectMetadataItem.id,
|
||||
)?.settings?.joinColumnName;
|
||||
|
||||
if (!isDefined(joinColumnName)) {
|
||||
return undefined;
|
||||
}
|
||||
const joinColumnName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: targetableObject.targetObjectNameSingular,
|
||||
});
|
||||
|
||||
return [
|
||||
joinColumnName,
|
||||
|
||||
-7
@@ -23,7 +23,6 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush
|
||||
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import '@blocknote/core/fonts/inter.css';
|
||||
import '@blocknote/mantine/style.css';
|
||||
@@ -32,7 +31,6 @@ import '@blocknote/react/style.css';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
|
||||
type RichTextFieldEditorProps = {
|
||||
recordId: string;
|
||||
@@ -82,13 +80,8 @@ export const RichTextFieldEditor = ({
|
||||
|
||||
const focusId = `${recordId}-${fieldName}`;
|
||||
|
||||
const isAttachmentMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_ATTACHMENT_MIGRATED,
|
||||
);
|
||||
|
||||
const attachmentTargetFieldIdName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: objectNameSingular,
|
||||
isMorphRelation: isAttachmentMigrated,
|
||||
});
|
||||
|
||||
const { records: attachments } = useFindManyRecords<Attachment>({
|
||||
|
||||
-6
@@ -11,11 +11,9 @@ import { StandaloneRichTextEditorContent } from '@/page-layout/widgets/standalon
|
||||
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { styled } from '@linaria/react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
FeatureFlagKey,
|
||||
PageLayoutType,
|
||||
type StandaloneRichTextConfiguration,
|
||||
} from '~/generated-metadata/graphql';
|
||||
@@ -47,15 +45,11 @@ export const StandaloneRichTextWidget = ({
|
||||
);
|
||||
|
||||
const { targetRecordIdentifier, layoutType } = useLayoutRenderingContext();
|
||||
const isAttachmentMigrated = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IS_ATTACHMENT_MIGRATED,
|
||||
);
|
||||
|
||||
const isDashboard = layoutType === PageLayoutType.DASHBOARD;
|
||||
const dashboardId = isDashboard ? targetRecordIdentifier?.id : undefined;
|
||||
const attachmentTargetFieldIdName = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: CoreObjectNameSingular.Dashboard,
|
||||
isMorphRelation: isAttachmentMigrated,
|
||||
});
|
||||
|
||||
const configuration = widget.configuration as
|
||||
|
||||
Reference in New Issue
Block a user