mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-27 13:49:10 +02:00
Merge fixes for 5.0.1 to 5.0 branch (#3646)
This commit is contained in:
parent
9f82c08ba2
commit
77dd5d6c9f
@ -23,12 +23,12 @@ describe('project overview', () => {
|
||||
after(() => {
|
||||
cy.request({
|
||||
method: 'DELETE',
|
||||
url: `${baseUrl}/api/admin/features/${featureToggleName}-A`,
|
||||
url: `${baseUrl}/api/admin/projects/default/features/${featureToggleName}-A`,
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
cy.request({
|
||||
method: 'DELETE',
|
||||
url: `${baseUrl}/api/admin/features/${featureToggleName}-B`,
|
||||
url: `${baseUrl}/api/admin/projects/default/features/${featureToggleName}-B`,
|
||||
failOnStatusCode: false,
|
||||
});
|
||||
cy.request({
|
||||
|
@ -24,7 +24,7 @@ export const createFeature_API = (
|
||||
export const deleteFeature_API = (name: string): Chainable<any> => {
|
||||
cy.request({
|
||||
method: 'DELETE',
|
||||
url: `${baseUrl}/api/admin/features/${name}`,
|
||||
url: `${baseUrl}/api/admin/projects/default/features/${name}`,
|
||||
});
|
||||
return cy.request({
|
||||
method: 'DELETE',
|
||||
|
@ -95,24 +95,18 @@ export const ArchiveTable = ({
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
...(uiConfig?.flags?.bulkOperations
|
||||
? [
|
||||
{
|
||||
id: 'Select',
|
||||
Header: ({ getToggleAllRowsSelectedProps }: any) => (
|
||||
<Checkbox {...getToggleAllRowsSelectedProps()} />
|
||||
),
|
||||
Cell: ({ row }: any) => (
|
||||
<RowSelectCell
|
||||
{...row?.getToggleRowSelectedProps?.()}
|
||||
/>
|
||||
),
|
||||
maxWidth: 50,
|
||||
disableSortBy: true,
|
||||
hideInMenu: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
id: 'Select',
|
||||
Header: ({ getToggleAllRowsSelectedProps }: any) => (
|
||||
<Checkbox {...getToggleAllRowsSelectedProps()} />
|
||||
),
|
||||
Cell: ({ row }: any) => (
|
||||
<RowSelectCell {...row?.getToggleRowSelectedProps?.()} />
|
||||
),
|
||||
maxWidth: 50,
|
||||
disableSortBy: true,
|
||||
hideInMenu: true,
|
||||
},
|
||||
{
|
||||
Header: 'Seen',
|
||||
width: 85,
|
||||
|
@ -43,12 +43,7 @@ export const ArchivedFeatureDeleteConfirm = ({
|
||||
if (deletedFeatures.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uiConfig?.flags?.bulkOperations) {
|
||||
await deleteFeatures(projectId, deletedFeatures);
|
||||
} else {
|
||||
await deleteFeature(deletedFeatures[0]);
|
||||
}
|
||||
await deleteFeatures(projectId, deletedFeatures);
|
||||
|
||||
await refetch();
|
||||
setToastData({
|
||||
|
@ -240,24 +240,18 @@ export const ProjectFeatureToggles = ({
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
...(uiConfig?.flags?.bulkOperations
|
||||
? [
|
||||
{
|
||||
id: 'Select',
|
||||
Header: ({ getToggleAllRowsSelectedProps }: any) => (
|
||||
<Checkbox {...getToggleAllRowsSelectedProps()} />
|
||||
),
|
||||
Cell: ({ row }: any) => (
|
||||
<RowSelectCell
|
||||
{...row?.getToggleRowSelectedProps?.()}
|
||||
/>
|
||||
),
|
||||
maxWidth: 50,
|
||||
disableSortBy: true,
|
||||
hideInMenu: true,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
id: 'Select',
|
||||
Header: ({ getToggleAllRowsSelectedProps }: any) => (
|
||||
<Checkbox {...getToggleAllRowsSelectedProps()} />
|
||||
),
|
||||
Cell: ({ row }: any) => (
|
||||
<RowSelectCell {...row?.getToggleRowSelectedProps?.()} />
|
||||
),
|
||||
maxWidth: 50,
|
||||
disableSortBy: true,
|
||||
hideInMenu: true,
|
||||
},
|
||||
{
|
||||
id: 'favorite',
|
||||
Header: (
|
||||
|
@ -45,7 +45,6 @@ export interface IFlags {
|
||||
crOnVariants?: boolean;
|
||||
proPlanAutoCharge?: boolean;
|
||||
notifications?: boolean;
|
||||
bulkOperations?: boolean;
|
||||
personalAccessTokensKillSwitch?: boolean;
|
||||
demo?: boolean;
|
||||
strategyTitle?: boolean;
|
||||
|
@ -67,7 +67,6 @@ exports[`should create default config 1`] = `
|
||||
},
|
||||
"flags": {
|
||||
"anonymiseEventLog": false,
|
||||
"bulkOperations": false,
|
||||
"caseInsensitiveInOperators": false,
|
||||
"cleanClientApi": false,
|
||||
"crOnVariants": false,
|
||||
@ -94,7 +93,6 @@ exports[`should create default config 1`] = `
|
||||
"flagResolver": FlagResolver {
|
||||
"experiments": {
|
||||
"anonymiseEventLog": false,
|
||||
"bulkOperations": false,
|
||||
"caseInsensitiveInOperators": false,
|
||||
"cleanClientApi": false,
|
||||
"crOnVariants": false,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import owasp from 'owasp-password-strength-test';
|
||||
import { ErrorObject } from 'ajv';
|
||||
import {
|
||||
ApiErrorSchema,
|
||||
@ -9,6 +10,7 @@ import {
|
||||
UnleashError,
|
||||
} from './api-error';
|
||||
import BadDataError from './bad-data-error';
|
||||
import OwaspValidationError from './owasp-validation-error';
|
||||
|
||||
describe('v5 deprecation: backwards compatibility', () => {
|
||||
it.each(UnleashApiErrorTypes)(
|
||||
@ -320,3 +322,14 @@ describe('OpenAPI error conversion', () => {
|
||||
expect(description.includes(illegalValue)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error serialization special cases', () => {
|
||||
it('OwaspValidationErrors: adds `validationErrors` to `details`', () => {
|
||||
const results = owasp.test('123');
|
||||
const error = new OwaspValidationError(results);
|
||||
const json = fromLegacyError(error).toJSON();
|
||||
|
||||
expect(json.details!![0].message).toBe(results.errors[0]);
|
||||
expect(json.details!![0].validationErrors).toBe(results.errors);
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { v4 as uuidV4 } from 'uuid';
|
||||
import { FromSchema } from 'json-schema-to-ts';
|
||||
import { ErrorObject } from 'ajv';
|
||||
import OwaspValidationError from './owasp-validation-error';
|
||||
|
||||
export const UnleashApiErrorTypes = [
|
||||
'ContentTypeError',
|
||||
@ -14,7 +15,6 @@ export const UnleashApiErrorTypes = [
|
||||
'NotFoundError',
|
||||
'NotImplementedError',
|
||||
'OperationDeniedError',
|
||||
'OwaspValidationError',
|
||||
'PasswordMismatch',
|
||||
'PasswordMismatchError',
|
||||
'PasswordUndefinedError',
|
||||
@ -34,6 +34,7 @@ const UnleashApiErrorTypesWithExtraData = [
|
||||
'AuthenticationRequired',
|
||||
'NoAccessError',
|
||||
'InvalidTokenError',
|
||||
'OwaspValidationError',
|
||||
] as const;
|
||||
|
||||
const AllUnleashApiErrorTypes = [
|
||||
@ -136,6 +137,15 @@ type UnleashErrorData =
|
||||
...ValidationErrorDescription[],
|
||||
];
|
||||
}
|
||||
| {
|
||||
name: 'OwaspValidationError';
|
||||
details: [
|
||||
{
|
||||
validationErrors: string[];
|
||||
message: string;
|
||||
},
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
export class UnleashError extends Error {
|
||||
@ -245,6 +255,15 @@ export const fromLegacyError = (e: Error): UnleashError => {
|
||||
});
|
||||
}
|
||||
|
||||
if (name === 'OwaspValidationError') {
|
||||
return new UnleashError({
|
||||
name,
|
||||
message:
|
||||
'Password validation failed. Refer to the `details` property.',
|
||||
details: (e as OwaspValidationError).toJSON().details,
|
||||
});
|
||||
}
|
||||
|
||||
if (name === 'AuthenticationRequired') {
|
||||
return new UnleashError({
|
||||
name,
|
||||
|
@ -14,7 +14,6 @@ import { IAuthRequest } from '../../unleash-types';
|
||||
import { OpenApiService } from '../../../services/openapi-service';
|
||||
import { emptyResponse } from '../../../openapi/util/standard-responses';
|
||||
import { BatchFeaturesSchema, createRequestSchema } from '../../../openapi';
|
||||
import NotFoundError from '../../../error/notfound-error';
|
||||
import Controller from '../../controller';
|
||||
|
||||
const PATH = '/:projectId';
|
||||
@ -105,9 +104,6 @@ export default class ProjectArchiveController extends Controller {
|
||||
req: IAuthRequest<IProjectParam, any, BatchFeaturesSchema>,
|
||||
res: Response<void>,
|
||||
): Promise<void> {
|
||||
if (!this.flagResolver.isEnabled('bulkOperations')) {
|
||||
throw new NotFoundError('Bulk operations are not enabled');
|
||||
}
|
||||
const { projectId } = req.params;
|
||||
const { features } = req.body;
|
||||
const user = extractUsername(req);
|
||||
@ -119,9 +115,6 @@ export default class ProjectArchiveController extends Controller {
|
||||
req: IAuthRequest<IProjectParam, any, BatchFeaturesSchema>,
|
||||
res: Response<void>,
|
||||
): Promise<void> {
|
||||
if (!this.flagResolver.isEnabled('bulkOperations')) {
|
||||
throw new NotFoundError('Bulk operations are not enabled');
|
||||
}
|
||||
const { projectId } = req.params;
|
||||
const { features } = req.body;
|
||||
const user = extractUsername(req);
|
||||
@ -133,10 +126,6 @@ export default class ProjectArchiveController extends Controller {
|
||||
req: IAuthRequest<IProjectParam, void, BatchFeaturesSchema>,
|
||||
res: Response,
|
||||
): Promise<void> {
|
||||
if (!this.flagResolver.isEnabled('bulkOperations')) {
|
||||
throw new NotFoundError('Bulk operations are not enabled');
|
||||
}
|
||||
|
||||
const { features } = req.body;
|
||||
const { projectId } = req.params;
|
||||
const userName = extractUsername(req);
|
||||
|
@ -40,7 +40,6 @@ import {
|
||||
} from '../../../openapi';
|
||||
import { OpenApiService, FeatureToggleService } from '../../../services';
|
||||
import { querySchema } from '../../../schema/feature-schema';
|
||||
import NotFoundError from '../../../error/notfound-error';
|
||||
import { BatchStaleSchema } from '../../../openapi/spec/batch-stale-schema';
|
||||
|
||||
interface FeatureStrategyParams {
|
||||
@ -594,10 +593,6 @@ export default class ProjectFeaturesController extends Controller {
|
||||
req: IAuthRequest<{ projectId: string }, void, BatchStaleSchema>,
|
||||
res: Response,
|
||||
): Promise<void> {
|
||||
if (!this.flagResolver.isEnabled('bulkOperations')) {
|
||||
throw new NotFoundError('Bulk operations are not enabled');
|
||||
}
|
||||
|
||||
const { features, stale } = req.body;
|
||||
const { projectId } = req.params;
|
||||
const userName = extractUsername(req);
|
||||
|
@ -24,7 +24,6 @@ import {
|
||||
import { emptyResponse } from '../../openapi/util/standard-responses';
|
||||
import FeatureTagService from 'lib/services/feature-tag-service';
|
||||
import { TagsBulkAddSchema } from '../../openapi/spec/tags-bulk-add-schema';
|
||||
import NotFoundError from '../../error/notfound-error';
|
||||
import { IFlagResolver } from '../../types';
|
||||
|
||||
const version = 1;
|
||||
@ -214,9 +213,6 @@ class TagController extends Controller {
|
||||
req: IAuthRequest<void, void, TagsBulkAddSchema>,
|
||||
res: Response<TagSchema>,
|
||||
): Promise<void> {
|
||||
if (!this.flagResolver.isEnabled('bulkOperations')) {
|
||||
throw new NotFoundError('Bulk operations are not enabled');
|
||||
}
|
||||
const { features, tags } = req.body;
|
||||
const userName = extractUsername(req);
|
||||
await this.featureTagService.updateTags(
|
||||
|
@ -49,10 +49,6 @@ const flags = {
|
||||
process.env.UNLEASH_PRO_PLAN_AUTO_CHARGE,
|
||||
false,
|
||||
),
|
||||
bulkOperations: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_BULK_OPERATIONS,
|
||||
false,
|
||||
),
|
||||
personalAccessTokensKillSwitch: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_PAT_KILL_SWITCH,
|
||||
false,
|
||||
|
@ -39,7 +39,6 @@ process.nextTick(async () => {
|
||||
anonymiseEventLog: false,
|
||||
responseTimeWithAppNameKillSwitch: false,
|
||||
newProjectOverview: true,
|
||||
bulkOperations: true,
|
||||
optimal304: true,
|
||||
optimal304Differ: false,
|
||||
},
|
||||
|
@ -15,7 +15,6 @@ beforeAll(async () => {
|
||||
experimental: {
|
||||
flags: {
|
||||
strictSchemaValidation: true,
|
||||
bulkOperations: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -89,7 +89,6 @@ beforeAll(async () => {
|
||||
experimental: {
|
||||
flags: {
|
||||
strictSchemaValidation: true,
|
||||
bulkOperations: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -11,7 +11,6 @@ beforeAll(async () => {
|
||||
experimental: {
|
||||
flags: {
|
||||
strictSchemaValidation: true,
|
||||
bulkOperations: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user