Fix meeting bot CalendarEvent field visibility and editability (#21883)

- Add the meeting bot preference field to the CalendarEvent record page
fields view.
- Use a Standard-app ownership gate for record field read-only logic.
- Allow app-owned and workspace-custom fields on system objects to
follow isUIEditable and permissions.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21883?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
nitin
2026-06-22 14:54:32 +05:30
committed by GitHub
parent 584c567a7f
commit 6237598a30
17 changed files with 233 additions and 70 deletions
@@ -0,0 +1,20 @@
import { useCallback } from 'react';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { getIsMetadataItemFromStandardApplication } from '@/object-metadata/utils/getIsMetadataItemFromStandardApplication';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
export const useGetIsMetadataItemFromStandardApplication = () => {
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
const applications = currentWorkspace?.installedApplications;
return useCallback(
(metadataItem: { applicationId?: string | null }) =>
getIsMetadataItemFromStandardApplication(
metadataItem,
applications ?? [],
),
[applications],
);
};
@@ -0,0 +1,55 @@
import { getIsMetadataItemFromStandardApplication } from '@/object-metadata/utils/getIsMetadataItemFromStandardApplication';
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
describe('getIsMetadataItemFromStandardApplication', () => {
const applications = [
{
id: 'standard-application-id',
universalIdentifier: TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
},
{
id: 'workspace-custom-application-id',
universalIdentifier: 'workspace-custom-application-universal-id',
},
{
id: 'installed-application-id',
universalIdentifier: 'installed-application-universal-id',
},
];
it('should return true when metadata item belongs to the standard application', () => {
expect(
getIsMetadataItemFromStandardApplication(
{ applicationId: 'standard-application-id' },
applications,
),
).toBe(true);
});
it('should return false when metadata item belongs to the workspace custom application', () => {
expect(
getIsMetadataItemFromStandardApplication(
{ applicationId: 'workspace-custom-application-id' },
applications,
),
).toBe(false);
});
it('should return false when metadata item belongs to an installed application', () => {
expect(
getIsMetadataItemFromStandardApplication(
{ applicationId: 'installed-application-id' },
applications,
),
).toBe(false);
});
it('should return undefined when metadata item application cannot be resolved', () => {
expect(
getIsMetadataItemFromStandardApplication(
{ applicationId: 'unknown-application-id' },
applications,
),
).toBeUndefined();
});
});
@@ -0,0 +1,26 @@
import { isTwentyStandardApplication } from '@/applications/utils/isTwentyStandardApplication';
import { isDefined } from 'twenty-shared/utils';
type ApplicationLike = {
id: string;
universalIdentifier?: string | null;
};
export const getIsMetadataItemFromStandardApplication = (
metadataItem: { applicationId?: string | null },
applications: ApplicationLike[],
): boolean | undefined => {
if (!isDefined(metadataItem.applicationId)) {
return undefined;
}
const application = applications.find(
(application) => application.id === metadataItem.applicationId,
);
if (!isDefined(application) || !isDefined(application.universalIdentifier)) {
return undefined;
}
return isTwentyStandardApplication(application);
};