hotfix for lab (#9981)
Issue: When attempting to toggle a public feature flag that didn't exist in the workspace's feature flags array, the LabService threw a FeatureFlagException with code FEATURE_FLAG_NOT_FOUND. This prevented users from enabling public feature flags for the first time in their workspace. Fix: Modified the LabService to handle non-existent public feature flags by creating them instead of throwing an error. When the flag doesn't exist, the service now saves a new feature flag record with the provided key and value, associates it with the workspace, and returns the newly created flag.
This commit is contained in:
@ -800,7 +800,7 @@ export type Mutation = {
|
|||||||
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
|
skipSyncEmailOnboardingStep: OnboardingStepSuccess;
|
||||||
track: Analytics;
|
track: Analytics;
|
||||||
updateBillingSubscription: BillingUpdateOutput;
|
updateBillingSubscription: BillingUpdateOutput;
|
||||||
updateLabPublicFeatureFlag: Scalars['Boolean'];
|
updateLabPublicFeatureFlag: FeatureFlag;
|
||||||
updateOneField: Field;
|
updateOneField: Field;
|
||||||
updateOneObject: Object;
|
updateOneObject: Object;
|
||||||
updateOneServerlessFunction: ServerlessFunction;
|
updateOneServerlessFunction: ServerlessFunction;
|
||||||
@ -2225,7 +2225,7 @@ export type UpdateLabPublicFeatureFlagMutationVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', updateLabPublicFeatureFlag: boolean };
|
export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', updateLabPublicFeatureFlag: { __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean } };
|
||||||
|
|
||||||
export type CreateOidcIdentityProviderMutationVariables = Exact<{
|
export type CreateOidcIdentityProviderMutationVariables = Exact<{
|
||||||
input: SetupOidcSsoInput;
|
input: SetupOidcSsoInput;
|
||||||
@ -3884,7 +3884,11 @@ export type GetEnvironmentVariablesGroupedLazyQueryHookResult = ReturnType<typeo
|
|||||||
export type GetEnvironmentVariablesGroupedQueryResult = Apollo.QueryResult<GetEnvironmentVariablesGroupedQuery, GetEnvironmentVariablesGroupedQueryVariables>;
|
export type GetEnvironmentVariablesGroupedQueryResult = Apollo.QueryResult<GetEnvironmentVariablesGroupedQuery, GetEnvironmentVariablesGroupedQueryVariables>;
|
||||||
export const UpdateLabPublicFeatureFlagDocument = gql`
|
export const UpdateLabPublicFeatureFlagDocument = gql`
|
||||||
mutation UpdateLabPublicFeatureFlag($input: UpdateLabPublicFeatureFlagInput!) {
|
mutation UpdateLabPublicFeatureFlag($input: UpdateLabPublicFeatureFlagInput!) {
|
||||||
updateLabPublicFeatureFlag(input: $input)
|
updateLabPublicFeatureFlag(input: $input) {
|
||||||
|
id
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export type UpdateLabPublicFeatureFlagMutationFn = Apollo.MutationFunction<UpdateLabPublicFeatureFlagMutation, UpdateLabPublicFeatureFlagMutationVariables>;
|
export type UpdateLabPublicFeatureFlagMutationFn = Apollo.MutationFunction<UpdateLabPublicFeatureFlagMutation, UpdateLabPublicFeatureFlagMutationVariables>;
|
||||||
|
|||||||
@ -4,6 +4,10 @@ export const UPDATE_LAB_PUBLIC_FEATURE_FLAG = gql`
|
|||||||
mutation UpdateLabPublicFeatureFlag(
|
mutation UpdateLabPublicFeatureFlag(
|
||||||
$input: UpdateLabPublicFeatureFlagInput!
|
$input: UpdateLabPublicFeatureFlagInput!
|
||||||
) {
|
) {
|
||||||
updateLabPublicFeatureFlag(input: $input)
|
updateLabPublicFeatureFlag(input: $input) {
|
||||||
|
id
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -15,7 +15,29 @@ export const useLabPublicFeatureFlags = () => {
|
|||||||
);
|
);
|
||||||
const labPublicFeatureFlags = useRecoilValue(labPublicFeatureFlagsState);
|
const labPublicFeatureFlags = useRecoilValue(labPublicFeatureFlagsState);
|
||||||
|
|
||||||
const [updateLabPublicFeatureFlag] = useUpdateLabPublicFeatureFlagMutation();
|
const [updateLabPublicFeatureFlag] = useUpdateLabPublicFeatureFlagMutation({
|
||||||
|
onCompleted: (data) => {
|
||||||
|
if (isDefined(currentWorkspace)) {
|
||||||
|
const updatedFlag = data.updateLabPublicFeatureFlag;
|
||||||
|
|
||||||
|
setCurrentWorkspace({
|
||||||
|
...currentWorkspace,
|
||||||
|
featureFlags: [
|
||||||
|
...(currentWorkspace.featureFlags?.filter(
|
||||||
|
(flag) => flag.key !== updatedFlag.key,
|
||||||
|
) ?? []),
|
||||||
|
{
|
||||||
|
...updatedFlag,
|
||||||
|
workspaceId: currentWorkspace.id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
setError(error.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const handleLabPublicFeatureFlagUpdate = async (
|
const handleLabPublicFeatureFlagUpdate = async (
|
||||||
publicFeatureFlag: FeatureFlagKey,
|
publicFeatureFlag: FeatureFlagKey,
|
||||||
@ -35,20 +57,8 @@ export const useLabPublicFeatureFlags = () => {
|
|||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
|
||||||
setError(error.message);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isDefined(response.data)) {
|
|
||||||
setCurrentWorkspace({
|
|
||||||
...currentWorkspace,
|
|
||||||
featureFlags: currentWorkspace.featureFlags?.map((flag) =>
|
|
||||||
flag.key === publicFeatureFlag ? { ...flag, value } : flag,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!response.data;
|
return !!response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { UseFilters, UseGuards } from '@nestjs/common';
|
|||||||
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
||||||
|
|
||||||
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
|
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
|
||||||
|
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||||
import { UpdateLabPublicFeatureFlagInput } from 'src/engine/core-modules/lab/dtos/update-lab-public-feature-flag.input';
|
import { UpdateLabPublicFeatureFlagInput } from 'src/engine/core-modules/lab/dtos/update-lab-public-feature-flag.input';
|
||||||
import { LabService } from 'src/engine/core-modules/lab/services/lab.service';
|
import { LabService } from 'src/engine/core-modules/lab/services/lab.service';
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
@ -14,13 +15,11 @@ export class LabResolver {
|
|||||||
constructor(private labService: LabService) {}
|
constructor(private labService: LabService) {}
|
||||||
|
|
||||||
@UseGuards(WorkspaceAuthGuard)
|
@UseGuards(WorkspaceAuthGuard)
|
||||||
@Mutation(() => Boolean)
|
@Mutation(() => FeatureFlag)
|
||||||
async updateLabPublicFeatureFlag(
|
async updateLabPublicFeatureFlag(
|
||||||
@Args('input') input: UpdateLabPublicFeatureFlagInput,
|
@Args('input') input: UpdateLabPublicFeatureFlagInput,
|
||||||
@AuthWorkspace() workspace: Workspace,
|
@AuthWorkspace() workspace: Workspace,
|
||||||
): Promise<boolean> {
|
): Promise<FeatureFlag> {
|
||||||
await this.labService.updateLabPublicFeatureFlag(workspace.id, input);
|
return this.labService.updateLabPublicFeatureFlag(workspace.id, input);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ export class LabService {
|
|||||||
async updateLabPublicFeatureFlag(
|
async updateLabPublicFeatureFlag(
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
payload: UpdateLabPublicFeatureFlagInput,
|
payload: UpdateLabPublicFeatureFlagInput,
|
||||||
): Promise<void> {
|
): Promise<FeatureFlag> {
|
||||||
featureFlagValidator.assertIsFeatureFlagKey(
|
featureFlagValidator.assertIsFeatureFlagKey(
|
||||||
payload.publicFeatureFlag,
|
payload.publicFeatureFlag,
|
||||||
new FeatureFlagException(
|
new FeatureFlagException(
|
||||||
@ -62,15 +62,24 @@ export class LabService {
|
|||||||
(flag) => flag.key === FeatureFlagKey[payload.publicFeatureFlag],
|
(flag) => flag.key === FeatureFlagKey[payload.publicFeatureFlag],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!existingFlag) {
|
if (existingFlag) {
|
||||||
throw new FeatureFlagException(
|
await this.featureFlagRepository.update(existingFlag.id, {
|
||||||
'Public feature flag not found',
|
value: payload.value,
|
||||||
FeatureFlagExceptionCode.FEATURE_FLAG_NOT_FOUND,
|
});
|
||||||
);
|
|
||||||
|
return { ...existingFlag, value: payload.value };
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.featureFlagRepository.update(existingFlag.id, {
|
const newFlag = await this.featureFlagRepository.save({
|
||||||
|
key: FeatureFlagKey[payload.publicFeatureFlag],
|
||||||
value: payload.value,
|
value: payload.value,
|
||||||
|
workspaceId: workspace.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
workspace.featureFlags = [...(workspace.featureFlags || []), newFlag];
|
||||||
|
|
||||||
|
await this.workspaceRepository.save(workspace);
|
||||||
|
|
||||||
|
return newFlag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user