Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b13c39e02 | |||
| 38a49650a3 | |||
| 35c4ec0d44 | |||
| 791462bab0 | |||
| 78aad6733f |
@@ -1045,7 +1045,7 @@ export type CreateNavigationMenuItemInput = {
|
||||
icon?: InputMaybe<Scalars['String']>;
|
||||
link?: InputMaybe<Scalars['String']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
position?: InputMaybe<Scalars['Int']>;
|
||||
position?: InputMaybe<Scalars['Float']>;
|
||||
targetObjectMetadataId?: InputMaybe<Scalars['UUID']>;
|
||||
targetRecordId?: InputMaybe<Scalars['UUID']>;
|
||||
userWorkspaceId?: InputMaybe<Scalars['UUID']>;
|
||||
@@ -4583,7 +4583,7 @@ export type UpdateNavigationMenuItemInput = {
|
||||
icon?: InputMaybe<Scalars['String']>;
|
||||
link?: InputMaybe<Scalars['String']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
position?: InputMaybe<Scalars['Int']>;
|
||||
position?: InputMaybe<Scalars['Float']>;
|
||||
};
|
||||
|
||||
export type UpdateObjectPayload = {
|
||||
|
||||
@@ -22,8 +22,8 @@ import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFla
|
||||
import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui/display';
|
||||
import { isNavigationModifierPressed } from 'twenty-ui/utilities';
|
||||
import {
|
||||
PermissionFlagType,
|
||||
FeatureFlagKey,
|
||||
PermissionFlagType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { formatToHumanReadableDate } from '~/utils/date-utils';
|
||||
import { getFileNameAndExtension } from '~/utils/file/getFileNameAndExtension';
|
||||
@@ -96,7 +96,11 @@ export const AttachmentRow = ({
|
||||
);
|
||||
|
||||
const { name: originalFileName, extension: attachmentFileExtension } =
|
||||
getFileNameAndExtension(attachment.name);
|
||||
getFileNameAndExtension(
|
||||
isFilesFieldMigrated
|
||||
? (attachment.file?.[0]?.label as string)
|
||||
: attachment.name,
|
||||
);
|
||||
|
||||
const [attachmentFileName, setAttachmentFileName] =
|
||||
useState(originalFileName);
|
||||
@@ -206,7 +210,9 @@ export const AttachmentRow = ({
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<OverflowingTextWithTooltip text={attachment.name} />
|
||||
<OverflowingTextWithTooltip
|
||||
text={`${attachmentFileName}${attachmentFileExtension}`}
|
||||
/>
|
||||
</StyledLink>
|
||||
</StyledLinkContainer>
|
||||
)}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { type MigrationInterface, type QueryRunner } from 'typeorm';
|
||||
|
||||
export class ChangeNavigationMenuItemPositionToDoublePrecision1771499112046
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'ChangeNavigationMenuItemPositionToDoublePrecision1771499112046';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."navigationMenuItem" ALTER COLUMN "position" TYPE double precision`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."navigationMenuItem" ALTER COLUMN "position" TYPE integer`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+18
-1
@@ -12,6 +12,8 @@ import { GoogleAPIsOauthExchangeCodeForTokenStrategy } from 'src/engine/core-mod
|
||||
import { TransientTokenService } from 'src/engine/core-modules/auth/token/services/transient-token.service';
|
||||
import { setRequestExtraParams } from 'src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util';
|
||||
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@@ -27,6 +29,7 @@ export class GoogleAPIsOauthExchangeCodeForTokenGuard extends AuthGuard(
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
private readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
private readonly workspaceDomainsService: WorkspaceDomainsService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -46,7 +49,21 @@ export class GoogleAPIsOauthExchangeCodeForTokenGuard extends AuthGuard(
|
||||
);
|
||||
}
|
||||
|
||||
new GoogleAPIsOauthExchangeCodeForTokenStrategy(this.twentyConfigService);
|
||||
const { workspaceId } =
|
||||
await this.transientTokenService.verifyTransientToken(
|
||||
state.transientToken,
|
||||
);
|
||||
|
||||
const isDraftEmailEnabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_DRAFT_EMAIL_ENABLED,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
new GoogleAPIsOauthExchangeCodeForTokenStrategy(
|
||||
this.twentyConfigService,
|
||||
isDraftEmailEnabled,
|
||||
);
|
||||
|
||||
setRequestExtraParams(request, {
|
||||
transientToken: state.transientToken,
|
||||
|
||||
+13
-1
@@ -12,6 +12,8 @@ import { GoogleAPIsOauthRequestCodeStrategy } from 'src/engine/core-modules/auth
|
||||
import { TransientTokenService } from 'src/engine/core-modules/auth/token/services/transient-token.service';
|
||||
import { setRequestExtraParams } from 'src/engine/core-modules/auth/utils/google-apis-set-request-extra-params.util';
|
||||
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@@ -25,6 +27,7 @@ export class GoogleAPIsOauthRequestCodeGuard extends AuthGuard('google-apis') {
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
private readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
private readonly workspaceDomainsService: WorkspaceDomainsService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
) {
|
||||
super({
|
||||
prompt: 'select_account',
|
||||
@@ -68,7 +71,16 @@ export class GoogleAPIsOauthRequestCodeGuard extends AuthGuard('google-apis') {
|
||||
);
|
||||
}
|
||||
|
||||
new GoogleAPIsOauthRequestCodeStrategy(this.twentyConfigService);
|
||||
const isDraftEmailEnabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_DRAFT_EMAIL_ENABLED,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
new GoogleAPIsOauthRequestCodeStrategy(
|
||||
this.twentyConfigService,
|
||||
isDraftEmailEnabled,
|
||||
);
|
||||
|
||||
return (await super.canActivate(context)) as boolean;
|
||||
} catch (err) {
|
||||
|
||||
+19
-3
@@ -92,8 +92,24 @@ describe('GoogleAPIScopesService', () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should work with the current Google API scopes', () => {
|
||||
// What is currently returned by Google
|
||||
it('should work with the current Google API scopes when draft email is disabled', () => {
|
||||
const actualGoogleScopes = [
|
||||
'https://www.googleapis.com/auth/calendar.events',
|
||||
'https://www.googleapis.com/auth/gmail.readonly',
|
||||
'https://www.googleapis.com/auth/gmail.send',
|
||||
'https://www.googleapis.com/auth/profile.emails.read',
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'openid',
|
||||
];
|
||||
const expectedScopes = getGoogleApisOauthScopes(false);
|
||||
|
||||
const result = includesExpectedScopes(actualGoogleScopes, expectedScopes);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should work with the current Google API scopes when draft email is enabled', () => {
|
||||
const actualGoogleScopes = [
|
||||
'https://www.googleapis.com/auth/calendar.events',
|
||||
'https://www.googleapis.com/auth/gmail.readonly',
|
||||
@@ -104,7 +120,7 @@ describe('GoogleAPIScopesService', () => {
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'openid',
|
||||
];
|
||||
const expectedScopes = getGoogleApisOauthScopes();
|
||||
const expectedScopes = getGoogleApisOauthScopes(true);
|
||||
|
||||
const result = includesExpectedScopes(actualGoogleScopes, expectedScopes);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ export class GoogleAPIScopesService {
|
||||
|
||||
public async getScopesFromGoogleAccessTokenAndCheckIfExpectedScopesArePresent(
|
||||
accessToken: string,
|
||||
isDraftEmailEnabled = false,
|
||||
): Promise<{ scopes: string[]; isValid: boolean }> {
|
||||
try {
|
||||
const httpClient = this.secureHttpClientService.getHttpClient();
|
||||
@@ -40,7 +41,7 @@ export class GoogleAPIScopesService {
|
||||
);
|
||||
|
||||
const scopes = response.data.scope.split(' ');
|
||||
const expectedScopes = getGoogleApisOauthScopes();
|
||||
const expectedScopes = getGoogleApisOauthScopes(isDraftEmailEnabled);
|
||||
|
||||
return {
|
||||
scopes,
|
||||
|
||||
+7
@@ -10,6 +10,7 @@ import { GoogleAPIScopesService } from 'src/engine/core-modules/auth/services/go
|
||||
import { GoogleApisServiceAvailabilityService } from 'src/engine/core-modules/auth/services/google-apis-service-availability.service';
|
||||
import { GoogleAPIsService } from 'src/engine/core-modules/auth/services/google-apis.service';
|
||||
import { UpdateConnectedAccountOnReconnectService } from 'src/engine/core-modules/auth/services/update-connected-account-on-reconnect.service';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { getQueueToken } from 'src/engine/core-modules/message-queue/utils/get-queue-token.util';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
@@ -181,6 +182,12 @@ describe('GoogleAPIsService', () => {
|
||||
provide: getQueueToken(MessageQueue.calendarQueue),
|
||||
useValue: mockCalendarQueueService,
|
||||
},
|
||||
{
|
||||
provide: FeatureFlagService,
|
||||
useValue: {
|
||||
isFeatureEnabled: jest.fn().mockResolvedValue(false),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ import { CreateMessageChannelService } from 'src/engine/core-modules/auth/servic
|
||||
import { GoogleAPIScopesService } from 'src/engine/core-modules/auth/services/google-apis-scopes';
|
||||
import { GoogleApisServiceAvailabilityService } from 'src/engine/core-modules/auth/services/google-apis-service-availability.service';
|
||||
import { UpdateConnectedAccountOnReconnectService } from 'src/engine/core-modules/auth/services/update-connected-account-on-reconnect.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
@@ -63,6 +65,7 @@ export class GoogleAPIsService {
|
||||
private readonly updateConnectedAccountOnReconnectService: UpdateConnectedAccountOnReconnectService,
|
||||
private readonly googleAPIScopesService: GoogleAPIScopesService,
|
||||
private readonly googleApisServiceAvailabilityService: GoogleApisServiceAvailabilityService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
) {}
|
||||
|
||||
async refreshGoogleRefreshToken(input: {
|
||||
@@ -92,9 +95,15 @@ export class GoogleAPIsService {
|
||||
'MESSAGING_PROVIDER_GMAIL_ENABLED',
|
||||
);
|
||||
|
||||
const isDraftEmailEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_DRAFT_EMAIL_ENABLED,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const { scopes, isValid } =
|
||||
await this.googleAPIScopesService.getScopesFromGoogleAccessTokenAndCheckIfExpectedScopesArePresent(
|
||||
input.accessToken,
|
||||
isDraftEmailEnabled,
|
||||
);
|
||||
|
||||
if (!isValid) {
|
||||
|
||||
+5
-2
@@ -14,8 +14,11 @@ export abstract class GoogleAPIsOauthCommonStrategy extends PassportStrategy(
|
||||
Strategy,
|
||||
'google-apis',
|
||||
) {
|
||||
constructor(twentyConfigService: TwentyConfigService) {
|
||||
const scopes = getGoogleApisOauthScopes();
|
||||
constructor(
|
||||
twentyConfigService: TwentyConfigService,
|
||||
isDraftEmailEnabled = false,
|
||||
) {
|
||||
const scopes = getGoogleApisOauthScopes(isDraftEmailEnabled);
|
||||
|
||||
super({
|
||||
clientID: twentyConfigService.get('AUTH_GOOGLE_CLIENT_ID'),
|
||||
|
||||
+5
-2
@@ -12,8 +12,11 @@ export type GoogleAPIScopeConfig = {
|
||||
|
||||
@Injectable()
|
||||
export class GoogleAPIsOauthExchangeCodeForTokenStrategy extends GoogleAPIsOauthCommonStrategy {
|
||||
constructor(twentyConfigService: TwentyConfigService) {
|
||||
super(twentyConfigService);
|
||||
constructor(
|
||||
twentyConfigService: TwentyConfigService,
|
||||
isDraftEmailEnabled = false,
|
||||
) {
|
||||
super(twentyConfigService, isDraftEmailEnabled);
|
||||
}
|
||||
|
||||
async validate(
|
||||
|
||||
+5
-2
@@ -12,8 +12,11 @@ export type GoogleAPIScopeConfig = {
|
||||
|
||||
@Injectable()
|
||||
export class GoogleAPIsOauthRequestCodeStrategy extends GoogleAPIsOauthCommonStrategy {
|
||||
constructor(twentyConfigService: TwentyConfigService) {
|
||||
super(twentyConfigService);
|
||||
constructor(
|
||||
twentyConfigService: TwentyConfigService,
|
||||
isDraftEmailEnabled = false,
|
||||
) {
|
||||
super(twentyConfigService, isDraftEmailEnabled);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
+4
-2
@@ -1,7 +1,7 @@
|
||||
/** email, profile and openid permission can be called without the https://www.googleapis.com/auth/ prefix
|
||||
* see https://developers.google.com/identity/protocols/oauth2/scopes
|
||||
*/
|
||||
export const getGoogleApisOauthScopes = () => {
|
||||
export const getGoogleApisOauthScopes = (isDraftEmailEnabled = false) => {
|
||||
return [
|
||||
'email',
|
||||
'profile',
|
||||
@@ -9,6 +9,8 @@ export const getGoogleApisOauthScopes = () => {
|
||||
'https://www.googleapis.com/auth/calendar.events',
|
||||
'https://www.googleapis.com/auth/profile.emails.read',
|
||||
'https://www.googleapis.com/auth/gmail.send',
|
||||
'https://www.googleapis.com/auth/gmail.compose',
|
||||
...(isDraftEmailEnabled
|
||||
? ['https://www.googleapis.com/auth/gmail.compose']
|
||||
: []),
|
||||
];
|
||||
};
|
||||
|
||||
+4
-5
@@ -1,6 +1,6 @@
|
||||
import { Field, InputType, Int } from '@nestjs/graphql';
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import { IsInt, IsOptional, IsString, IsUUID, Min } from 'class-validator';
|
||||
import { IsNumber, IsOptional, IsString, IsUUID } from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@@ -46,9 +46,8 @@ export class CreateNavigationMenuItemInput {
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
folderId?: string;
|
||||
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@Field(() => Int, { nullable: true })
|
||||
@Field({ nullable: true })
|
||||
position?: number;
|
||||
}
|
||||
|
||||
+4
-6
@@ -1,13 +1,12 @@
|
||||
import { Field, InputType, Int } from '@nestjs/graphql';
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsInt,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUUID,
|
||||
Min,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
@@ -20,10 +19,9 @@ export class UpdateNavigationMenuItemInput {
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
folderId?: string | null;
|
||||
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
@Field(() => Int, { nullable: true })
|
||||
@Field({ nullable: true })
|
||||
position?: number;
|
||||
|
||||
@IsOptional()
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ export class NavigationMenuItemEntity
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
folderId: string | null;
|
||||
|
||||
@Column({ nullable: false })
|
||||
@Column({ nullable: false, type: 'double precision' })
|
||||
position: number;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
|
||||
+6
-10
@@ -177,13 +177,12 @@ export class FlatNavigationMenuItemValidatorService {
|
||||
|
||||
if (
|
||||
isDefined(flatNavigationMenuItem.position) &&
|
||||
(!Number.isInteger(flatNavigationMenuItem.position) ||
|
||||
flatNavigationMenuItem.position < 0)
|
||||
!Number.isFinite(flatNavigationMenuItem.position)
|
||||
) {
|
||||
validationResult.errors.push({
|
||||
code: NavigationMenuItemExceptionCode.INVALID_NAVIGATION_MENU_ITEM_INPUT,
|
||||
message: t`Position must be a non-negative integer`,
|
||||
userFriendlyMessage: msg`Position must be a non-negative integer`,
|
||||
message: t`Position must be a finite number`,
|
||||
userFriendlyMessage: msg`Position must be a finite number`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -307,14 +306,11 @@ export class FlatNavigationMenuItemValidatorService {
|
||||
|
||||
const positionUpdate = flatEntityUpdate.position;
|
||||
|
||||
if (
|
||||
isDefined(positionUpdate) &&
|
||||
(!Number.isInteger(positionUpdate) || positionUpdate < 0)
|
||||
) {
|
||||
if (isDefined(positionUpdate) && !Number.isFinite(positionUpdate)) {
|
||||
validationResult.errors.push({
|
||||
code: NavigationMenuItemExceptionCode.INVALID_NAVIGATION_MENU_ITEM_INPUT,
|
||||
message: t`Position must be a non-negative integer`,
|
||||
userFriendlyMessage: msg`Position must be a non-negative integer`,
|
||||
message: t`Position must be a finite number`,
|
||||
userFriendlyMessage: msg`Position must be a finite number`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,10 @@ export class MatchParticipantService<
|
||||
await participantRepository.updateMany(
|
||||
partipantsToBeUpdated.map((participant) => ({
|
||||
criteria: participant.id,
|
||||
partialEntity: participant,
|
||||
partialEntity: {
|
||||
personId: participant.personId,
|
||||
workspaceMemberId: participant.workspaceMemberId,
|
||||
},
|
||||
})),
|
||||
);
|
||||
|
||||
|
||||
-11
@@ -142,14 +142,3 @@ exports[`NavigationMenuItem creation should fail when creating with missing targ
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`NavigationMenuItem creation should fail when creating with negative position 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "NOT_FOUND",
|
||||
"subCode": "RELATION_UNIVERSAL_IDENTIFIER_NOT_FOUND",
|
||||
"userFriendlyMessage": "An error occurred.",
|
||||
},
|
||||
"message": "Could not find objectMetadata for given targetObjectMetadataId",
|
||||
"name": "NotFoundError",
|
||||
}
|
||||
`;
|
||||
|
||||
-35
@@ -71,38 +71,3 @@ exports[`NavigationMenuItem update should fail when updating with missing id 1`]
|
||||
"name": "ValidationError",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`NavigationMenuItem update should fail when updating with negative position 1`] = `
|
||||
{
|
||||
"extensions": {
|
||||
"code": "METADATA_VALIDATION_FAILED",
|
||||
"errors": {
|
||||
"navigationMenuItem": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_NAVIGATION_MENU_ITEM_INPUT",
|
||||
"message": "Position must be a non-negative integer",
|
||||
"userFriendlyMessage": "Position must be a non-negative integer",
|
||||
},
|
||||
],
|
||||
"flatEntityMinimalInformation": {
|
||||
"universalIdentifier": Any<String>,
|
||||
},
|
||||
"metadataName": "navigationMenuItem",
|
||||
"status": "fail",
|
||||
"type": "update",
|
||||
},
|
||||
],
|
||||
},
|
||||
"message": "Validation failed for 1 navigationMenuItem",
|
||||
"summary": {
|
||||
"navigationMenuItem": 1,
|
||||
"totalErrors": 1,
|
||||
},
|
||||
"userFriendlyMessage": "Metadata validation failed",
|
||||
},
|
||||
"message": "Multiple validation errors occurred while updating navigation menu item",
|
||||
"name": "GraphQLError",
|
||||
}
|
||||
`;
|
||||
|
||||
-10
@@ -86,16 +86,6 @@ const failingNavigationMenuItemCreationTestCases: EachTestingContext<TestContext
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'when creating with negative position',
|
||||
context: {
|
||||
input: {
|
||||
targetRecordId: faker.string.uuid(),
|
||||
targetObjectMetadataId: faker.string.uuid(),
|
||||
position: -1,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('NavigationMenuItem creation should fail', () => {
|
||||
|
||||
-11
@@ -130,17 +130,6 @@ describe('NavigationMenuItem update should fail', () => {
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'when updating with negative position',
|
||||
context: {
|
||||
input: (testSetup) => ({
|
||||
id: testSetup.testNavigationMenuItemId,
|
||||
update: {
|
||||
position: -1,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
it.each(eachTestingContextFilter(failingNavigationMenuItemUpdateTestCases))(
|
||||
|
||||
Reference in New Issue
Block a user