mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: add stale property on toggle (#619)
This commit is contained in:
		
							parent
							
								
									e4faf3022c
								
							
						
					
					
						commit
						83dda55172
					
				| @ -20,6 +20,7 @@ This endpoint is the one all admin ui should use to fetch all available feature | ||||
|       "description": "lorem ipsum", | ||||
|       "type": "release", | ||||
|       "enabled": false, | ||||
|       "stale": false, | ||||
|       "strategies": [ | ||||
|         { | ||||
|           "name": "default", | ||||
| @ -41,6 +42,7 @@ This endpoint is the one all admin ui should use to fetch all available feature | ||||
|       "name": "Feature.B", | ||||
|       "description": "lorem ipsum", | ||||
|       "enabled": true, | ||||
|       "stale": false, | ||||
|       "strategies": [ | ||||
|         { | ||||
|           "name": "ActiveForUserWithId", | ||||
| @ -71,6 +73,7 @@ Used to fetch details about a specific featureToggle. This is mostly provded to | ||||
|   "description": "lorem ipsum..", | ||||
|   "type": "release", | ||||
|   "enabled": false, | ||||
|   "stale": false, | ||||
|   "strategies": [ | ||||
|     { | ||||
|       "name": "default", | ||||
| @ -93,6 +96,7 @@ Used to fetch details about a specific featureToggle. This is mostly provded to | ||||
|   "description": "lorem ipsum..", | ||||
|   "type": "release", | ||||
|   "enabled": false, | ||||
|   "stale": false, | ||||
|   "strategies": [ | ||||
|     { | ||||
|       "name": "default", | ||||
| @ -123,6 +127,7 @@ Returns 200-respose if the feature toggle was created successfully. | ||||
|   "description": "lorem ipsum..", | ||||
|   "type": "release", | ||||
|   "enabled": false, | ||||
|   "stale": false, | ||||
|   "strategies": [ | ||||
|     { | ||||
|       "name": "default", | ||||
| @ -189,6 +194,65 @@ None | ||||
|   "description": "lorem ipsum..", | ||||
|   "type": "release", | ||||
|   "enabled": false, | ||||
|   "stale": false, | ||||
|   "strategies": [ | ||||
|     { | ||||
|       "name": "default", | ||||
|       "parameters": {} | ||||
|     } | ||||
|   ], | ||||
|   "variants": [] | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Mark a Feature Toggle as "stale" | ||||
| 
 | ||||
| `POST: http://unleash.host.com/api/admin/features/:featureName/stale/on` | ||||
| 
 | ||||
| Used to mark a feature toggle as stale (deprecated). The :featureName must match an existing Feature Toggle. Returns 200-response if the feature toggle was enabled successfully. | ||||
| 
 | ||||
| **Body** | ||||
| 
 | ||||
| None | ||||
| 
 | ||||
| **Example response:** | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "name": "Feature.A", | ||||
|   "description": "lorem ipsum..", | ||||
|   "type": "release", | ||||
|   "enabled": true, | ||||
|   "stale": true, | ||||
|   "strategies": [ | ||||
|     { | ||||
|       "name": "default", | ||||
|       "parameters": {} | ||||
|     } | ||||
|   ], | ||||
|   "variants": [] | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Mark a Feature Toggle as "active" | ||||
| 
 | ||||
| `POST: http://unleash.host.com/api/admin/features/:featureName/stale/off` | ||||
| 
 | ||||
| Used to mark a feature toggle active (remove stale marking). The :featureName must match an existing Feature Toggle. Returns 200-response if the feature toggle was disabled successfully. | ||||
| 
 | ||||
| **Body** | ||||
| 
 | ||||
| None | ||||
| 
 | ||||
| **Example response:** | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "name": "Feature.A", | ||||
|   "description": "lorem ipsum..", | ||||
|   "type": "release", | ||||
|   "enabled": false, | ||||
|   "stale": false, | ||||
|   "strategies": [ | ||||
|     { | ||||
|       "name": "default", | ||||
| @ -218,6 +282,7 @@ Used to fetch list of archived feature toggles | ||||
|       "description": "lorem ipsum", | ||||
|       "type": "release", | ||||
|       "enabled": false, | ||||
|       "stale": false, | ||||
|       "strategies": [ | ||||
|         { | ||||
|           "name": "default", | ||||
|  | ||||
| @ -29,6 +29,7 @@ This endpoint should never return anything besides a valid _20X or 304-response_ | ||||
|       "description": "lorem ipsum", | ||||
|       "type": "release", | ||||
|       "enabled": false, | ||||
|       "stale": false, | ||||
|       "strategies": [ | ||||
|         { | ||||
|           "name": "default", | ||||
| @ -43,6 +44,7 @@ This endpoint should never return anything besides a valid _20X or 304-response_ | ||||
|       "type": "killswitch", | ||||
|       "description": "lorem ipsum", | ||||
|       "enabled": true, | ||||
|       "stale": false, | ||||
|       "strategies": [ | ||||
|         { | ||||
|           "name": "ActiveForUserWithId", | ||||
| @ -80,6 +82,7 @@ Used to fetch details about a specific feature toggle. This is mainly provided t | ||||
|   "description": "lorem ipsum..", | ||||
|   "type": "release", | ||||
|   "enabled": false, | ||||
|   "stale": false, | ||||
|   "strategies": [ | ||||
|     { | ||||
|       "name": "default", | ||||
|  | ||||
| @ -15,6 +15,7 @@ const FEATURE_COLUMNS = [ | ||||
|     'description', | ||||
|     'type', | ||||
|     'enabled', | ||||
|     'stale', | ||||
|     'strategies', | ||||
|     'variants', | ||||
|     'created_at', | ||||
| @ -100,6 +101,7 @@ class FeatureToggleStore { | ||||
|             description: row.description, | ||||
|             type: row.type, | ||||
|             enabled: row.enabled > 0, | ||||
|             stale: row.stale, | ||||
|             strategies: row.strategies, | ||||
|             variants: row.variants, | ||||
|             createdAt: row.created_at, | ||||
| @ -112,6 +114,7 @@ class FeatureToggleStore { | ||||
|             description: data.description, | ||||
|             type: data.type, | ||||
|             enabled: data.enabled ? 1 : 0, | ||||
|             stale: data.stale, | ||||
|             archived: data.archived ? 1 : 0, | ||||
|             strategies: JSON.stringify(data.strategies), | ||||
|             variants: data.variants ? JSON.stringify(data.variants) : null, | ||||
|  | ||||
| @ -54,6 +54,7 @@ const featureShema = joi | ||||
|     .keys({ | ||||
|         name: nameType, | ||||
|         enabled: joi.boolean().default(false), | ||||
|         stale: joi.boolean().default(false), | ||||
|         type: joi.string().default('release'), | ||||
|         description: joi | ||||
|             .string() | ||||
|  | ||||
| @ -19,6 +19,7 @@ test('should be valid toggle name', t => { | ||||
|         name: 'app.name', | ||||
|         type: 'release', | ||||
|         enabled: false, | ||||
|         stale: false, | ||||
|         strategies: [{ name: 'default' }], | ||||
|     }; | ||||
| 
 | ||||
| @ -31,6 +32,7 @@ test('should strip extra variant fields', t => { | ||||
|         name: 'app.name', | ||||
|         type: 'release', | ||||
|         enabled: false, | ||||
|         stale: false, | ||||
|         strategies: [{ name: 'default' }], | ||||
|         variants: [ | ||||
|             { | ||||
| @ -51,6 +53,7 @@ test('should allow weightType=fix', t => { | ||||
|         name: 'app.name', | ||||
|         type: 'release', | ||||
|         enabled: false, | ||||
|         stale: false, | ||||
|         strategies: [{ name: 'default' }], | ||||
|         variants: [ | ||||
|             { | ||||
| @ -70,6 +73,7 @@ test('should disallow weightType=unknown', t => { | ||||
|         name: 'app.name', | ||||
|         type: 'release', | ||||
|         enabled: false, | ||||
|         stale: false, | ||||
|         strategies: [{ name: 'default' }], | ||||
|         variants: [ | ||||
|             { | ||||
| @ -92,6 +96,7 @@ test('should be possible to define variant overrides', t => { | ||||
|         name: 'app.name', | ||||
|         type: 'release', | ||||
|         enabled: false, | ||||
|         stale: false, | ||||
|         strategies: [{ name: 'default' }], | ||||
|         variants: [ | ||||
|             { | ||||
| @ -119,6 +124,7 @@ test('variant overrides must have corect shape', async t => { | ||||
|         name: 'app.name', | ||||
|         type: 'release', | ||||
|         enabled: false, | ||||
|         stale: false, | ||||
|         strategies: [{ name: 'default' }], | ||||
|         variants: [ | ||||
|             { | ||||
| @ -147,6 +153,7 @@ test('should keep constraints', t => { | ||||
|         name: 'app.constraints', | ||||
|         type: 'release', | ||||
|         enabled: false, | ||||
|         stale: false, | ||||
|         strategies: [ | ||||
|             { | ||||
|                 name: 'default', | ||||
|  | ||||
| @ -35,6 +35,8 @@ class FeatureController extends Controller { | ||||
|         this.post('/:featureName/toggle', this.toggle, UPDATE_FEATURE); | ||||
|         this.post('/:featureName/toggle/on', this.toggleOn, UPDATE_FEATURE); | ||||
|         this.post('/:featureName/toggle/off', this.toggleOff, UPDATE_FEATURE); | ||||
|         this.post('/:featureName/stale/on', this.staleOn, UPDATE_FEATURE); | ||||
|         this.post('/:featureName/stale/off', this.staleOff, UPDATE_FEATURE); | ||||
|     } | ||||
| 
 | ||||
|     async getAllToggles(req, res) { | ||||
| @ -126,21 +128,29 @@ class FeatureController extends Controller { | ||||
|             const name = req.params.featureName; | ||||
|             const feature = await this.featureToggleStore.getFeature(name); | ||||
|             const enabled = !feature.enabled; | ||||
|             this._toggle(enabled, req, res); | ||||
|             this._updateField('enabled', enabled, req, res); | ||||
|         } catch (error) { | ||||
|             handleErrors(res, this.logger, error); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async toggleOn(req, res) { | ||||
|         this._toggle(true, req, res); | ||||
|         this._updateField('enabled', true, req, res); | ||||
|     } | ||||
| 
 | ||||
|     async toggleOff(req, res) { | ||||
|         this._toggle(false, req, res); | ||||
|         this._updateField('enabled', false, req, res); | ||||
|     } | ||||
| 
 | ||||
|     async _toggle(enabled, req, res) { | ||||
|     async staleOn(req, res) { | ||||
|         this._updateField('stale', true, req, res); | ||||
|     } | ||||
| 
 | ||||
|     async staleOff(req, res) { | ||||
|         this._updateField('stale', false, req, res); | ||||
|     } | ||||
| 
 | ||||
|     async _updateField(field, value, req, res) { | ||||
|         const { featureName } = req.params; | ||||
|         const userName = extractUser(req); | ||||
| 
 | ||||
| @ -149,7 +159,7 @@ class FeatureController extends Controller { | ||||
|                 featureName, | ||||
|             ); | ||||
| 
 | ||||
|             feature.enabled = enabled; | ||||
|             feature[field] = value; | ||||
|             await this.eventStore.store({ | ||||
|                 type: FEATURE_UPDATED, | ||||
|                 createdBy: userName, | ||||
|  | ||||
							
								
								
									
										17
									
								
								migrations/20200806091734-add-stale-flag-to-features.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								migrations/20200806091734-add-stale-flag-to-features.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| exports.up = function(db, cb) { | ||||
|     return db.addColumn( | ||||
|         'features', | ||||
|         'stale', | ||||
|         { | ||||
|             type: 'boolean', | ||||
|             defaultValue: false, | ||||
|         }, | ||||
|         cb, | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| exports.down = function(db, cb) { | ||||
|     return db.removeColumn('features', 'stale', cb); | ||||
| }; | ||||
| @ -87,7 +87,7 @@ | ||||
|     "prom-client": "^12.0.0", | ||||
|     "response-time": "^2.3.2", | ||||
|     "serve-favicon": "^2.5.0", | ||||
|     "unleash-frontend": "3.4.1-0", | ||||
|     "unleash-frontend": "3.5.0-0", | ||||
|     "yargs": "^15.1.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|  | ||||
| @ -5616,10 +5616,10 @@ universalify@^0.1.0: | ||||
|   resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" | ||||
|   integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== | ||||
| 
 | ||||
| unleash-frontend@3.4.1-0: | ||||
|   version "3.4.1-0" | ||||
|   resolved "https://registry.yarnpkg.com/unleash-frontend/-/unleash-frontend-3.4.1-0.tgz#480731a753059ad4b38c98b9a5f014eaa44d912b" | ||||
|   integrity sha512-skx+SlOFPHcrrQlY5UhNV6stxblUNaB0mGbZfbh7CdIuWMs1Y+KxVoorTqDaHV0zhyxKQvngzZOd696VnMxA4w== | ||||
| unleash-frontend@3.5.0-0: | ||||
|   version "3.5.0-0" | ||||
|   resolved "https://registry.yarnpkg.com/unleash-frontend/-/unleash-frontend-3.5.0-0.tgz#e3d3da3e3e8aad03195190cc913f3d2293672305" | ||||
|   integrity sha512-S+myY4sQZH3Mx3Q/RsKngee1WSX4ndffqup+oQxLsoKQSNiKwtjiA1KnGugeM+SNLIUVgi+b+3JPKWXxkEjw4g== | ||||
| 
 | ||||
| unpipe@1.0.0, unpipe@~1.0.0: | ||||
|   version "1.0.0" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user