b11f77df2a
## PR Description - Uses `expr-eval` to enable front components (SDK plugins) to define conditional availability as declarative expressions. - Moves shared types and constants to `twenty-shared` - Introduces a `conditionalAvailabilityExpression` field on `CommandMenuItemEntity`, allowing command menu items to store an `expr-eval` compatible expression string that is evaluated against a CommandMenuContext to determine if the item should be shown. - Creates an esbuild transform plugin `conditional-availability-transform-plugin` in `twenty-sdk` that converts TypeScript conditional availability expressions into `expr-eval` compatible syntax at build time, so SDK developers can write natural TS expressions that get transformed to evaluable strings. - Removes deprecated `forceRegisteredActionsByKey` state and its usage. - Creates `useCommandMenuContext` hook that builds the full `CommandMenuContext` object from React state, which is then passed to `useCommandMenuItemFrontComponentActions` for evaluating conditional availability expressions.
119 lines
4.2 KiB
TypeScript
119 lines
4.2 KiB
TypeScript
import { useCallback } from 'react';
|
|
import { useStore } from 'jotai';
|
|
import { isNonEmptyArray } from '@sniptt/guards';
|
|
|
|
import { type ActivityForEditor } from '@/activities/types/ActivityForEditor';
|
|
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
|
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
|
import { type CoreObjectNameSingular } from 'twenty-shared/types';
|
|
import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords';
|
|
import { modifyRecordFromCache } from '@/object-record/cache/utils/modifyRecordFromCache';
|
|
import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords';
|
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
|
|
|
import { createOneActivityOperationSignatureFactory } from '@/activities/graphql/operation-signatures/factories/createOneActivityOperationSignatureFactory';
|
|
import { type NoteTarget } from '@/activities/types/NoteTarget';
|
|
import { type TaskTarget } from '@/activities/types/TaskTarget';
|
|
import { getJoinObjectNameSingular } from '@/activities/utils/getJoinObjectNameSingular';
|
|
import { capitalize } from 'twenty-shared/utils';
|
|
|
|
export const useCreateActivityInDB = ({
|
|
activityObjectNameSingular,
|
|
}: {
|
|
activityObjectNameSingular:
|
|
| CoreObjectNameSingular.Task
|
|
| CoreObjectNameSingular.Note;
|
|
}) => {
|
|
const createOneActivityOperationSignature =
|
|
createOneActivityOperationSignatureFactory({
|
|
objectNameSingular: activityObjectNameSingular,
|
|
});
|
|
|
|
const { createOneRecord: createOneActivity } = useCreateOneRecord({
|
|
objectNameSingular: activityObjectNameSingular,
|
|
recordGqlFields: createOneActivityOperationSignature.fields,
|
|
shouldMatchRootQueryFilter: true,
|
|
});
|
|
|
|
const { createManyRecords: createManyActivityTargets } = useCreateManyRecords<
|
|
TaskTarget | NoteTarget
|
|
>({
|
|
objectNameSingular: getJoinObjectNameSingular(activityObjectNameSingular),
|
|
shouldMatchRootQueryFilter: true,
|
|
});
|
|
|
|
const { objectMetadataItems } = useObjectMetadataItems();
|
|
|
|
const { objectMetadataItem: objectMetadataItemActivityTarget } =
|
|
useObjectMetadataItem({
|
|
objectNameSingular: getJoinObjectNameSingular(activityObjectNameSingular),
|
|
});
|
|
|
|
const { objectMetadataItem: objectMetadataItemActivity } =
|
|
useObjectMetadataItem({
|
|
objectNameSingular: activityObjectNameSingular,
|
|
});
|
|
|
|
const cache = useApolloCoreClient().cache;
|
|
const store = useStore();
|
|
|
|
const createActivityInDB = useCallback(
|
|
async (activityToCreate: ActivityForEditor) => {
|
|
const createdActivity = await createOneActivity?.({
|
|
...activityToCreate,
|
|
updatedAt: new Date().toISOString(),
|
|
});
|
|
|
|
const activityTargetsToCreate =
|
|
activityToCreate.noteTargets ?? activityToCreate.taskTargets ?? [];
|
|
|
|
if (isNonEmptyArray(activityTargetsToCreate)) {
|
|
await createManyActivityTargets({
|
|
recordsToCreate: activityTargetsToCreate,
|
|
});
|
|
}
|
|
|
|
const activityTargetsConnection = getRecordConnectionFromRecords({
|
|
objectMetadataItems,
|
|
objectMetadataItem: objectMetadataItemActivityTarget,
|
|
records: activityTargetsToCreate.map((activityTarget) => ({
|
|
...activityTarget,
|
|
__typename: capitalize(objectMetadataItemActivityTarget.nameSingular),
|
|
})),
|
|
withPageInfo: false,
|
|
computeReferences: true,
|
|
isRootLevel: false,
|
|
});
|
|
|
|
modifyRecordFromCache({
|
|
recordId: createdActivity.id,
|
|
cache,
|
|
fieldModifiers: {
|
|
activityTargets: () => activityTargetsConnection,
|
|
},
|
|
objectMetadataItem: objectMetadataItemActivity,
|
|
});
|
|
|
|
store.set(recordStoreFamilyState.atomFamily(createdActivity.id), {
|
|
...createdActivity,
|
|
activityTargets: activityTargetsToCreate,
|
|
});
|
|
},
|
|
[
|
|
store,
|
|
cache,
|
|
createManyActivityTargets,
|
|
createOneActivity,
|
|
objectMetadataItemActivity,
|
|
objectMetadataItemActivityTarget,
|
|
objectMetadataItems,
|
|
],
|
|
);
|
|
|
|
return {
|
|
createActivityInDB,
|
|
};
|
|
};
|