mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	chore!: removing userId strategy for new installations of Unleash (#9800)
This removes a strategy that was already deprecated, but only for new installations. I tested starting with an installation with this strategy being used and then updating, and I was still able to edit the strategy, so this should not impact current users. On a fresh install the strategy is no longer available. --------- Co-authored-by: Nuno Góis <github@nunogois.com>
This commit is contained in:
		
							parent
							
								
									8050f25add
								
							
						
					
					
						commit
						5019f4fcbc
					
				
							
								
								
									
										4
									
								
								frontend/cypress/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								frontend/cypress/global.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -54,10 +54,6 @@ declare namespace Cypress { | ||||
|         deleteSegment_UI(segmentName: string, id: string): Chainable; | ||||
| 
 | ||||
|         // STRATEGY
 | ||||
|         addUserIdStrategyToFeature_UI( | ||||
|             featureName: string, | ||||
|             projectName: string, | ||||
|         ): Chainable; | ||||
|         addFlexibleRolloutStrategyToFeature_UI( | ||||
|             options: AddFlexibleRolloutStrategyOptions, | ||||
|         ): Chainable; | ||||
|  | ||||
| @ -257,57 +257,6 @@ export const deleteFeatureStrategy_UI = ( | ||||
|     return cy.wait('@deleteUserStrategy'); | ||||
| }; | ||||
| 
 | ||||
| export const addUserIdStrategyToFeature_UI = ( | ||||
|     featureToggleName: string, | ||||
|     projectName: string, | ||||
| ): Chainable<any> => { | ||||
|     const project = projectName || 'default'; | ||||
|     cy.visit( | ||||
|         `/projects/${project}/features/${featureToggleName}/strategies/create?environmentId=development&strategyName=userWithId`, | ||||
|     ); | ||||
| 
 | ||||
|     if (ENTERPRISE) { | ||||
|         cy.get('[data-testid=ADD_CONSTRAINT_ID]').click(); | ||||
|         cy.get('[data-testid=CONSTRAINT_AUTOCOMPLETE_ID]') | ||||
|             .type('{downArrow}'.repeat(1)) | ||||
|             .type('{enter}'); | ||||
|         cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click(); | ||||
|     } | ||||
| 
 | ||||
|     cy.get('[data-testid=STRATEGY_INPUT_LIST]') | ||||
|         .type('user1') | ||||
|         .type('{enter}') | ||||
|         .type('user2') | ||||
|         .type('{enter}'); | ||||
|     cy.get('[data-testid=ADD_TO_STRATEGY_INPUT_LIST]').click(); | ||||
| 
 | ||||
|     cy.intercept( | ||||
|         'POST', | ||||
|         `/api/admin/projects/default/features/${featureToggleName}/environments/*/strategies`, | ||||
|         (req) => { | ||||
|             expect(req.body.name).to.equal('userWithId'); | ||||
| 
 | ||||
|             expect(req.body.parameters.userIds.length).to.equal(11); | ||||
| 
 | ||||
|             if (ENTERPRISE) { | ||||
|                 expect(req.body.constraints.length).to.equal(1); | ||||
|             } else { | ||||
|                 expect(req.body.constraints.length).to.equal(0); | ||||
|             } | ||||
| 
 | ||||
|             req.continue((res) => { | ||||
|                 strategyId = res.body.id; | ||||
|             }); | ||||
|         }, | ||||
|     ).as('addStrategyToFeature'); | ||||
| 
 | ||||
|     // this one needs to wait until the dropdown selector of stickiness is set, that's why waitForAnimations: true
 | ||||
|     cy.get(`[data-testid=STRATEGY_FORM_SUBMIT_ID]`) | ||||
|         .first() | ||||
|         .click({ waitForAnimations: true }); | ||||
|     return cy.wait('@addStrategyToFeature'); | ||||
| }; | ||||
| 
 | ||||
| export const logout_UI = (): Chainable<any> => { | ||||
|     return cy.visit('/logout'); | ||||
| }; | ||||
|  | ||||
| @ -10,7 +10,6 @@ import { | ||||
|     deleteSegment_UI, | ||||
|     deleteFeatureStrategy_UI, | ||||
|     addFlexibleRolloutStrategyToFeature_UI, | ||||
|     addUserIdStrategyToFeature_UI, | ||||
|     updateFlexibleRolloutStrategy_UI, | ||||
|     do_login, | ||||
| } from './UI.ts'; | ||||
| @ -45,10 +44,6 @@ Cypress.Commands.add('updateUserPassword_API', updateUserPassword_API); | ||||
| Cypress.Commands.add('createFeature_UI', createFeature_UI); | ||||
| Cypress.Commands.add('deleteFeatureStrategy_UI', deleteFeatureStrategy_UI); | ||||
| Cypress.Commands.add('createFeature_API', createFeature_API); | ||||
| Cypress.Commands.add( | ||||
|     'addUserIdStrategyToFeature_UI', | ||||
|     addUserIdStrategyToFeature_UI, | ||||
| ); | ||||
| Cypress.Commands.add( | ||||
|     'addFlexibleRolloutStrategyToFeature_UI', | ||||
|     addFlexibleRolloutStrategyToFeature_UI, | ||||
|  | ||||
| @ -98,17 +98,20 @@ const setupOtherRoutes = (feature: string) => { | ||||
|                 deprecated: false, | ||||
|             }, | ||||
|             { | ||||
|                 displayName: 'UserIDs', | ||||
|                 name: 'userWithId', | ||||
|                 displayName: 'Gradual rollout', | ||||
|                 name: 'flexibleRollout', | ||||
|                 editable: false, | ||||
|                 description: | ||||
|                     'Enable the feature for a specific set of userIds.', | ||||
|                     'The gradual rollout strategy allows you to gradually roll out a feature to a percentage of users.', | ||||
|                 parameters: [ | ||||
|                     { | ||||
|                         name: 'userIds', | ||||
|                         type: 'list', | ||||
|                         description: '', | ||||
|                         required: false, | ||||
|                         name: 'rollout', | ||||
|                     }, | ||||
|                     { | ||||
|                         name: 'stickiness', | ||||
|                     }, | ||||
|                     { | ||||
|                         name: 'groupId', | ||||
|                     }, | ||||
|                 ], | ||||
|                 deprecated: false, | ||||
| @ -214,12 +217,10 @@ const UnleashUiSetup: FC<{ | ||||
|     </SWRConfig> | ||||
| ); | ||||
| 
 | ||||
| const strategiesAreDisplayed = async ( | ||||
|     firstStrategy: string, | ||||
|     secondStrategy: string, | ||||
| ) => { | ||||
|     await screen.findByText(firstStrategy); | ||||
|     await screen.findByText(secondStrategy); | ||||
| const strategiesAreDisplayed = async (strategies: string[]) => { | ||||
|     for (const strategy of strategies) { | ||||
|         await screen.findByText(strategy); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| const getDeleteButtons = async () => { | ||||
| @ -299,7 +300,7 @@ test('open mode + non-project member can perform basic change request actions', | ||||
|     const featureName = 'test'; | ||||
|     featureEnvironments(featureName, [ | ||||
|         { name: 'development', strategies: [] }, | ||||
|         { name: 'production', strategies: ['userWithId'] }, | ||||
|         { name: 'production', strategies: ['flexibleRollout'] }, | ||||
|         { name: 'custom', strategies: ['default'] }, | ||||
|     ]); | ||||
|     userIsMemberOfProjects([]); | ||||
| @ -318,7 +319,7 @@ test('open mode + non-project member can perform basic change request actions', | ||||
|     ); | ||||
|     await openEnvironments(['development', 'production', 'custom']); | ||||
| 
 | ||||
|     await strategiesAreDisplayed('UserIDs', 'Standard'); | ||||
|     await strategiesAreDisplayed(['Gradual rollout', 'Standard']); | ||||
|     await deleteButtonsActiveInChangeRequestEnv(); | ||||
|     await copyButtonsActiveInOtherEnv(); | ||||
| }); | ||||
| @ -328,7 +329,7 @@ test('protected mode + project member can perform basic change request actions', | ||||
|     const featureName = 'test'; | ||||
|     featureEnvironments(featureName, [ | ||||
|         { name: 'development', strategies: [] }, | ||||
|         { name: 'production', strategies: ['userWithId'] }, | ||||
|         { name: 'production', strategies: ['flexibleRollout'] }, | ||||
|         { name: 'custom', strategies: ['default'] }, | ||||
|     ]); | ||||
|     userIsMemberOfProjects([project]); | ||||
| @ -348,7 +349,7 @@ test('protected mode + project member can perform basic change request actions', | ||||
| 
 | ||||
|     await openEnvironments(['development', 'production', 'custom']); | ||||
| 
 | ||||
|     await strategiesAreDisplayed('UserIDs', 'Standard'); | ||||
|     await strategiesAreDisplayed(['Gradual rollout', 'Standard']); | ||||
|     await deleteButtonsActiveInChangeRequestEnv(); | ||||
|     await copyButtonsActiveInOtherEnv(); | ||||
| }); | ||||
| @ -358,7 +359,7 @@ test.skip('protected mode + non-project member cannot perform basic change reque | ||||
|     const featureName = 'test'; | ||||
|     featureEnvironments(featureName, [ | ||||
|         { name: 'development', strategies: [] }, | ||||
|         { name: 'production', strategies: ['userWithId'] }, | ||||
|         { name: 'production', strategies: ['flexibleRollout'] }, | ||||
|         { name: 'custom', strategies: ['default'] }, | ||||
|     ]); | ||||
|     userIsMemberOfProjects([]); | ||||
| @ -378,7 +379,7 @@ test.skip('protected mode + non-project member cannot perform basic change reque | ||||
| 
 | ||||
|     await openEnvironments(['development', 'production', 'custom']); | ||||
| 
 | ||||
|     await strategiesAreDisplayed('UserIDs', 'Standard'); | ||||
|     await strategiesAreDisplayed(['Gradual rollout', 'Standard']); | ||||
|     await deleteButtonsInactiveInChangeRequestEnv(); | ||||
|     await copyButtonsActiveInOtherEnv(); | ||||
| }); | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| import type { IFeatureStrategy, IStrategy } from 'interfaces/strategy'; | ||||
| import DefaultStrategy from 'component/feature/StrategyTypes/DefaultStrategy/DefaultStrategy'; | ||||
| import FlexibleStrategy from 'component/feature/StrategyTypes/FlexibleStrategy/FlexibleStrategy'; | ||||
| import UserWithIdStrategy from 'component/feature/StrategyTypes/UserWithIdStrategy/UserWithId'; | ||||
| import GeneralStrategy from 'component/feature/StrategyTypes/GeneralStrategy/GeneralStrategy'; | ||||
| import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext'; | ||||
| import produce from 'immer'; | ||||
| @ -52,15 +51,6 @@ export const FeatureStrategyType = ({ | ||||
|                     errors={errors} | ||||
|                 /> | ||||
|             ); | ||||
|         case 'userWithId': | ||||
|             return ( | ||||
|                 <UserWithIdStrategy | ||||
|                     parameters={strategy.parameters ?? {}} | ||||
|                     updateParameter={updateParameter} | ||||
|                     editable={hasAccess} | ||||
|                     errors={errors} | ||||
|                 /> | ||||
|             ); | ||||
|         default: | ||||
|             return ( | ||||
|                 <GeneralStrategy | ||||
|  | ||||
| @ -1,32 +0,0 @@ | ||||
| import type { IFeatureStrategyParameters } from 'interfaces/strategy'; | ||||
| import StrategyInputList from '../StrategyInputList/StrategyInputList.tsx'; | ||||
| import { parseParameterStrings } from 'utils/parseParameter'; | ||||
| import type { IFormErrors } from 'hooks/useFormErrors'; | ||||
| 
 | ||||
| interface IUserWithIdStrategyProps { | ||||
|     parameters: IFeatureStrategyParameters; | ||||
|     updateParameter: (field: string, value: string) => void; | ||||
|     editable: boolean; | ||||
|     errors: IFormErrors; | ||||
| } | ||||
| 
 | ||||
| const UserWithIdStrategy = ({ | ||||
|     editable, | ||||
|     parameters, | ||||
|     updateParameter, | ||||
|     errors, | ||||
| }: IUserWithIdStrategyProps) => { | ||||
|     return ( | ||||
|         <div> | ||||
|             <StrategyInputList | ||||
|                 name='userIds' | ||||
|                 list={parseParameterStrings(parameters.userIds)} | ||||
|                 disabled={!editable} | ||||
|                 setConfig={updateParameter} | ||||
|                 errors={errors} | ||||
|             /> | ||||
|         </div> | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| export default UserWithIdStrategy; | ||||
| @ -3,7 +3,6 @@ import type { IReleasePlanMilestoneStrategy } from 'interfaces/releasePlans'; | ||||
| import type { IStrategy } from 'interfaces/strategy'; | ||||
| import { MilestoneStrategyTypeFlexible } from './MilestoneStrategyTypeFlexible.tsx'; | ||||
| import GeneralStrategy from 'component/feature/StrategyTypes/GeneralStrategy/GeneralStrategy'; | ||||
| import UserWithIdStrategy from 'component/feature/StrategyTypes/UserWithIdStrategy/UserWithId'; | ||||
| import DefaultStrategy from 'component/feature/StrategyTypes/DefaultStrategy/DefaultStrategy'; | ||||
| 
 | ||||
| interface IMilestoneStrategyTypeProps { | ||||
| @ -36,15 +35,6 @@ export const MilestoneStrategyType = ({ | ||||
|                     editable={true} | ||||
|                 /> | ||||
|             ); | ||||
|         case 'userWithId': | ||||
|             return ( | ||||
|                 <UserWithIdStrategy | ||||
|                     editable={true} | ||||
|                     parameters={strategy.parameters ?? {}} | ||||
|                     updateParameter={updateParameter} | ||||
|                     errors={errors} | ||||
|                 /> | ||||
|             ); | ||||
|         default: | ||||
|             return ( | ||||
|                 <GeneralStrategy | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| import type { FC, SVGProps } from 'react'; | ||||
| import { SvgIcon, useTheme } from '@mui/material'; | ||||
| import LocationOnIcon from '@mui/icons-material/LocationOn'; | ||||
| import PeopleIcon from '@mui/icons-material/People'; | ||||
| import LanguageIcon from '@mui/icons-material/Language'; | ||||
| import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew'; | ||||
| import CodeIcon from '@mui/icons-material/Code'; | ||||
| @ -28,8 +27,6 @@ export const getFeatureStrategyIcon = (strategyName?: string) => { | ||||
|             return LanguageIcon; | ||||
|         case 'flexibleRollout': | ||||
|             return RolloutSvgIcon; | ||||
|         case 'userWithId': | ||||
|             return PeopleIcon; | ||||
|         case 'applicationHostname': | ||||
|             return LocationOnIcon; | ||||
|         case 'releasePlanTemplate': | ||||
| @ -47,7 +44,6 @@ export const BuiltInStrategies = [ | ||||
|     'gradualRolloutSessionId', | ||||
|     'gradualRolloutUserId', | ||||
|     'remoteAddress', | ||||
|     'userWithId', | ||||
| ]; | ||||
| 
 | ||||
| export const GetFeatureStrategyIcon: FC<{ strategyName: string }> = ({ | ||||
| @ -66,5 +62,4 @@ export const formattedStrategyNames: Record<string, string> = { | ||||
|     gradualRolloutSessionId: 'Sessions', | ||||
|     gradualRolloutUserId: 'Users', | ||||
|     remoteAddress: 'IPs', | ||||
|     userWithId: 'UserIDs', | ||||
| }; | ||||
|  | ||||
| @ -239,11 +239,3 @@ exports[`Should format specialised text for events when strategy removed 1`] = ` | ||||
|   "url": "unleashUrl/projects/my-other-project/features/new-feature", | ||||
| } | ||||
| `; | ||||
| 
 | ||||
| exports[`Should format specialised text for events when userIds changed 1`] = ` | ||||
| { | ||||
|   "label": "Flag strategy updated", | ||||
|   "text": "*user@company.com* updated *[new-feature](unleashUrl/projects/my-other-project/features/new-feature)* in project *[my-other-project](unleashUrl/projects/my-other-project)* by updating strategy *userWithId* in *production* userIds from empty set of userIds to [a,b]; constraints from empty set of constraints to [appName is one of (x,y)]", | ||||
|   "url": "unleashUrl/projects/my-other-project/features/new-feature", | ||||
| } | ||||
| `; | ||||
|  | ||||
| @ -352,46 +352,6 @@ const testCases: [string, IEvent][] = [ | ||||
|                 }, | ||||
|             ], | ||||
|     ), | ||||
|     [ | ||||
|         'when userIds changed', | ||||
|         { | ||||
|             id: 920, | ||||
|             type: FEATURE_STRATEGY_UPDATE, | ||||
|             createdBy: 'user@company.com', | ||||
|             createdByUserId: SYSTEM_USER_ID, | ||||
|             createdAt: new Date('2022-06-01T10:03:11.549Z'), | ||||
|             data: { | ||||
|                 name: 'userWithId', | ||||
|                 constraints: [ | ||||
|                     { | ||||
|                         values: ['x', 'y'], | ||||
|                         inverted: false, | ||||
|                         operator: IN, | ||||
|                         contextName: 'appName', | ||||
|                         caseInsensitive: false, | ||||
|                     }, | ||||
|                 ], | ||||
|                 parameters: { | ||||
|                     userIds: 'a,b', | ||||
|                 }, | ||||
|                 sortOrder: 9999, | ||||
|                 id: '9a995d94-5944-4897-a82f-0f7e65c2fb3f', | ||||
|             }, | ||||
|             preData: { | ||||
|                 name: 'userWithId', | ||||
|                 constraints: [], | ||||
|                 parameters: { | ||||
|                     userIds: '', | ||||
|                 }, | ||||
|                 sortOrder: 9999, | ||||
|                 id: '9a995d94-5944-4897-a82f-0f7e65c2fb3f', | ||||
|             }, | ||||
|             tags: [], | ||||
|             featureName: 'new-feature', | ||||
|             project: 'my-other-project', | ||||
|             environment: 'production', | ||||
|         }, | ||||
|     ], | ||||
|     [ | ||||
|         'when IPs changed', | ||||
|         { | ||||
|  | ||||
| @ -135,8 +135,6 @@ export class FeatureEventFormatterMd implements FeatureEventFormatter { | ||||
|                         return this.flexibleRolloutStrategyChangeText(event); | ||||
|                     case 'default': | ||||
|                         return this.defaultStrategyChangeText(event); | ||||
|                     case 'userWithId': | ||||
|                         return this.userWithIdStrategyChangeText(event); | ||||
|                     case 'remoteAddress': | ||||
|                         return this.remoteAddressStrategyChangeText(event); | ||||
|                     case 'applicationHostname': | ||||
| @ -162,10 +160,6 @@ export class FeatureEventFormatterMd implements FeatureEventFormatter { | ||||
|         return this.listOfValuesStrategyChangeText(event, 'IPs'); | ||||
|     } | ||||
| 
 | ||||
|     private userWithIdStrategyChangeText(event: IEvent) { | ||||
|         return this.listOfValuesStrategyChangeText(event, 'userIds'); | ||||
|     } | ||||
| 
 | ||||
|     private listOfValuesStrategyChangeText( | ||||
|         event: IEvent, | ||||
|         propertyName: string, | ||||
|  | ||||
| @ -63,9 +63,9 @@ exports[`should match snapshot from /api/client/features 1`] = ` | ||||
|     }, | ||||
|   ], | ||||
|   "meta": { | ||||
|     "etag": ""61824cd0:20"", | ||||
|     "etag": ""61824cd0:19"", | ||||
|     "queryHash": "61824cd0", | ||||
|     "revisionId": 20, | ||||
|     "revisionId": 19, | ||||
|   }, | ||||
|   "query": { | ||||
|     "environment": "default", | ||||
|  | ||||
| @ -354,7 +354,10 @@ class EventStore implements IEventStore { | ||||
|                 .select(EVENT_COLUMNS) | ||||
|                 .from(TABLE) | ||||
|                 .limit(100) | ||||
|                 .orderBy('created_at', 'desc'); | ||||
|                 .orderBy([ | ||||
|                     { column: 'created_at', order: 'desc' }, | ||||
|                     { column: 'id', order: 'desc' }, | ||||
|                 ]); | ||||
|             if (query) { | ||||
|                 qB = qB.where(query); | ||||
|             } | ||||
|  | ||||
| @ -2,7 +2,6 @@ import DefaultStrategy from './default-strategy.js'; | ||||
| import GradualRolloutRandomStrategy from './gradual-rollout-random.js'; | ||||
| import GradualRolloutUserIdStrategy from './gradual-rollout-user-id.js'; | ||||
| import GradualRolloutSessionIdStrategy from './gradual-rollout-session-id.js'; | ||||
| import UserWithIdStrategy from './user-with-id-strategy.js'; | ||||
| import RemoteAddressStrategy from './remote-address-strategy.js'; | ||||
| import FlexibleRolloutStrategy from './flexible-rollout-strategy.js'; | ||||
| import type { Strategy } from './strategy.js'; | ||||
| @ -18,7 +17,6 @@ export const defaultStrategies: Array<Strategy> = [ | ||||
|     new GradualRolloutRandomStrategy(), | ||||
|     new GradualRolloutUserIdStrategy(), | ||||
|     new GradualRolloutSessionIdStrategy(), | ||||
|     new UserWithIdStrategy(), | ||||
|     new RemoteAddressStrategy(), | ||||
|     new FlexibleRolloutStrategy(), | ||||
|     new UnknownStrategy(), | ||||
|  | ||||
| @ -1,17 +0,0 @@ | ||||
| import { Strategy } from './strategy.js'; | ||||
| import type { Context } from '../context.js'; | ||||
| 
 | ||||
| export default class UserWithIdStrategy extends Strategy { | ||||
|     constructor() { | ||||
|         super('userWithId'); | ||||
|     } | ||||
| 
 | ||||
|     isEnabled(parameters: { userIds?: string }, context: Context): boolean { | ||||
|         const userIdList = parameters.userIds | ||||
|             ? parameters.userIds.split(/\s*,\s*/) | ||||
|             : []; | ||||
|         return ( | ||||
|             context.userId !== undefined && userIdList.includes(context.userId) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @ -432,13 +432,6 @@ describe('offline client', () => { | ||||
|                     stickiness: 'userId', | ||||
|                 }, | ||||
|             }, | ||||
|             { | ||||
|                 name: 'userWithId', | ||||
|                 constraints: [], | ||||
|                 parameters: { | ||||
|                     userIds: 'uoea,ueoa', | ||||
|                 }, | ||||
|             }, | ||||
|             { | ||||
|                 name: 'remoteAddress', | ||||
|                 constraints: [], | ||||
|  | ||||
| @ -48,7 +48,6 @@ test('clientApplicationSchema go-sdk request', () => { | ||||
|             "gradualRolloutSessionId", | ||||
|             "gradualRolloutUserId", | ||||
|             "remoteAddress", | ||||
|             "userWithId", | ||||
|             "flexibleRollout" | ||||
|         ], | ||||
|         "started": "2022-06-24T09:59:12.822607943+02:00", | ||||
| @ -75,7 +74,6 @@ test('clientApplicationSchema node-sdk request', () => { | ||||
|             "gradualRolloutRandom", | ||||
|             "gradualRolloutUserId", | ||||
|             "gradualRolloutSessionId", | ||||
|             "userWithId", | ||||
|             "remoteAddress", | ||||
|             "flexibleRollout" | ||||
|         ], | ||||
|  | ||||
| @ -95,14 +95,6 @@ const playgroundStrategies = (): Arbitrary<PlaygroundStrategySchema[]> => | ||||
|                 }), | ||||
|             ), | ||||
| 
 | ||||
|             playgroundStrategy( | ||||
|                 'userWithId', | ||||
|                 fc.record({ | ||||
|                     userIds: fc | ||||
|                         .uniqueArray(fc.emailAddress()) | ||||
|                         .map((ids) => ids.join(',')), | ||||
|                 }), | ||||
|             ), | ||||
|             playgroundStrategy( | ||||
|                 'remoteAddress', | ||||
|                 fc.record({ | ||||
|  | ||||
| @ -6,7 +6,6 @@ exports.up = function (db, cb) { | ||||
|     ALTER TABLE strategies ADD COLUMN sort_order integer DEFAULT 9999; | ||||
|     UPDATE strategies SET sort_order = 0 WHERE name = 'default'; | ||||
|     UPDATE strategies SET sort_order = 1 WHERE name = 'flexibleRollout'; | ||||
|     UPDATE strategies SET sort_order = 2 WHERE name = 'userWithId'; | ||||
|     UPDATE strategies SET sort_order = 3 WHERE name = 'remoteAddress'; | ||||
|     UPDATE strategies SET sort_order = 4 WHERE name = 'applicationHostname'; | ||||
|   `,
 | ||||
|  | ||||
| @ -6,7 +6,6 @@ exports.up = function (db, cb) { | ||||
|     ALTER TABLE strategies ADD COLUMN display_name text; | ||||
|     UPDATE strategies SET display_name = 'Standard', description = 'The standard strategy is strictly on / off for your entire userbase.' WHERE name = 'default'; | ||||
|     UPDATE strategies SET display_name = 'Gradual rollout', description = 'Roll out to a percentage of your userbase, and ensure that the experience is the same for the user on each visit.' WHERE name = 'flexibleRollout'; | ||||
|     UPDATE strategies SET display_name = 'UserIDs', description = 'Enable the feature for a specific set of userIds.' WHERE name = 'userWithId'; | ||||
|     UPDATE strategies SET display_name = 'IPs', description = 'Enable the feature for a specific set of IP addresses.' WHERE name = 'remoteAddress'; | ||||
|     UPDATE strategies SET display_name = 'Hosts', description = 'Enable the feature for a specific set of hostnames.' WHERE name = 'applicationHostname'; | ||||
|   `,
 | ||||
|  | ||||
| @ -9,13 +9,9 @@ exports.up = function (db, callback) { | ||||
|             and deprecated | ||||
|             and not exists (select * from feature_strategies where strategy_name = name limit 1); | ||||
| 
 | ||||
|         -- deprecate strategies on v5 | ||||
|         update strategies set deprecated = true where name in ('userWithId'); | ||||
| 
 | ||||
|         -- update strategy descriptions and sort order | ||||
|         update strategies set sort_order = 1, description = 'This strategy turns on / off for your entire userbase. Prefer using "Gradual rollout" strategy (100%=on, 0%=off).' WHERE name = 'default'; | ||||
|         update strategies set sort_order = 0 WHERE name = 'flexibleRollout'; | ||||
|         update strategies set description = 'Enable the feature for a specific set of userIds. Prefer using "Gradual rollout" strategy with user id constraints.' WHERE name = 'userWithId'; | ||||
|         `,
 | ||||
|         callback, | ||||
|     ); | ||||
|  | ||||
| @ -4,18 +4,6 @@ | ||||
|     "description": "Default on/off strategy.", | ||||
|     "parameters": [] | ||||
|   }, | ||||
|   { | ||||
|     "name": "userWithId", | ||||
|     "description": "Active for users with a userId defined in the userIds-list", | ||||
|     "parameters": [ | ||||
|       { | ||||
|         "name": "userIds", | ||||
|         "type": "list", | ||||
|         "description": "", | ||||
|         "required": false | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   { | ||||
|     "name": "applicationHostname", | ||||
|     "description": "Active for client instances with a hostName in the hostNames-list.", | ||||
|  | ||||
| @ -107,14 +107,6 @@ export const strategies = (): Arbitrary<FeatureStrategySchema[]> => | ||||
|                 }), | ||||
|             ), | ||||
| 
 | ||||
|             strategy( | ||||
|                 'userWithId', | ||||
|                 fc.record({ | ||||
|                     userIds: fc | ||||
|                         .uniqueArray(fc.emailAddress()) | ||||
|                         .map((ids) => ids.join(',')), | ||||
|                 }), | ||||
|             ), | ||||
|             strategy( | ||||
|                 'remoteAddress', | ||||
|                 fc.record({ | ||||
|  | ||||
| @ -152,26 +152,26 @@ describe.each([ | ||||
|             .expect(200); | ||||
| 
 | ||||
|         if (etagVariant.feature_enabled) { | ||||
|             expect(res.headers.etag).toBe(`"61824cd0:17:${etagVariant.name}"`); | ||||
|             expect(res.headers.etag).toBe(`"61824cd0:16:${etagVariant.name}"`); | ||||
|             expect(res.body.meta.etag).toBe( | ||||
|                 `"61824cd0:17:${etagVariant.name}"`, | ||||
|                 `"61824cd0:16:${etagVariant.name}"`, | ||||
|             ); | ||||
|         } else { | ||||
|             expect(res.headers.etag).toBe('"61824cd0:17"'); | ||||
|             expect(res.body.meta.etag).toBe('"61824cd0:17"'); | ||||
|             expect(res.headers.etag).toBe('"61824cd0:16"'); | ||||
|             expect(res.body.meta.etag).toBe('"61824cd0:16"'); | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     test(`returns ${etagVariant.feature_enabled ? 200 : 304} for pre-calculated hash${etagVariant.feature_enabled ? ' because hash changed' : ''}`, async () => { | ||||
|         const res = await app.request | ||||
|             .get('/api/client/features') | ||||
|             .set('if-none-match', '"61824cd0:17"') | ||||
|             .set('if-none-match', '"61824cd0:16"') | ||||
|             .expect(etagVariant.feature_enabled ? 200 : 304); | ||||
| 
 | ||||
|         if (etagVariant.feature_enabled) { | ||||
|             expect(res.headers.etag).toBe(`"61824cd0:17:${etagVariant.name}"`); | ||||
|             expect(res.headers.etag).toBe(`"61824cd0:16:${etagVariant.name}"`); | ||||
|             expect(res.body.meta.etag).toBe( | ||||
|                 `"61824cd0:17:${etagVariant.name}"`, | ||||
|                 `"61824cd0:16:${etagVariant.name}"`, | ||||
|             ); | ||||
|         } | ||||
|     }); | ||||
| @ -193,13 +193,13 @@ describe.each([ | ||||
|             .expect(200); | ||||
| 
 | ||||
|         if (etagVariant.feature_enabled) { | ||||
|             expect(res.headers.etag).toBe(`"61824cd0:17:${etagVariant.name}"`); | ||||
|             expect(res.headers.etag).toBe(`"61824cd0:16:${etagVariant.name}"`); | ||||
|             expect(res.body.meta.etag).toBe( | ||||
|                 `"61824cd0:17:${etagVariant.name}"`, | ||||
|                 `"61824cd0:16:${etagVariant.name}"`, | ||||
|             ); | ||||
|         } else { | ||||
|             expect(res.headers.etag).toBe('"61824cd0:17"'); | ||||
|             expect(res.body.meta.etag).toBe('"61824cd0:17"'); | ||||
|             expect(res.headers.etag).toBe('"61824cd0:16"'); | ||||
|             expect(res.body.meta.etag).toBe('"61824cd0:16"'); | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| @ -180,7 +180,6 @@ This endpoint gives insight into details about application seen per feature flag | ||||
|         "abTest", | ||||
|         "default", | ||||
|         "betaUser", | ||||
|         "userWithId", | ||||
|         "byHostName", | ||||
|         "gradualRolloutWithSessionId", | ||||
|         "gradualRollout", | ||||
|  | ||||
| @ -21,18 +21,6 @@ Used to fetch all defined strategies and their defined parameters. | ||||
|       "description": "Default on/off strategy.", | ||||
|       "parameters": [] | ||||
|     }, | ||||
|     { | ||||
|       "name": "userWithId", | ||||
|       "description": "Active for userId specified in the comma seperated 'userIds' parameter.", | ||||
|       "parameters": [ | ||||
|         { | ||||
|           "name": "userIds", | ||||
|           "type": "list", | ||||
|           "description": "List of unique userIds the feature should be active for.", | ||||
|           "required": true | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|     { | ||||
|       "name": "gradualRollout", | ||||
|       "description": "Gradual rollout to logged in users", | ||||
|  | ||||
| @ -8,6 +8,10 @@ Predefined strategy types are a legacy implementation. Please use the [default s | ||||
| 
 | ||||
| ## UserIDs | ||||
| 
 | ||||
| :::warning | ||||
| The `userWithId` strategy was removed in Unleash v7.0.0 for new installations. Instead use a gradual rollout strategy with a user ID stickiness and constraints. | ||||
| ::: | ||||
| 
 | ||||
| The `userWithId` strategy is active for users with a `userId` defined in the `userIds` list. | ||||
| 
 | ||||
| **Parameters:** | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user