mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	Secrets Sync UI: Refactor vercel-project destination to expect array from server (#24628)
* fix vercel project to expect array from server * add test * use reduce function!
This commit is contained in:
		| @@ -47,8 +47,9 @@ export default class SyncDestinationsVercelProjectModel extends SyncDestinationM | ||||
|   }) | ||||
|   teamId; | ||||
|  | ||||
|   // comma separated string, updated as array using deploymentEnvironmentsArray | ||||
|   @attr({ | ||||
|   // commaString transforms param from the server's array type | ||||
|   // to a comma string so changedAttributes() will track changes | ||||
|   @attr('commaString', { | ||||
|     subText: 'Deployment environments where the environment variables are available.', | ||||
|     editType: 'checkboxList', | ||||
|     possibleValues: ['development', 'preview', 'production'], | ||||
| @@ -56,9 +57,8 @@ export default class SyncDestinationsVercelProjectModel extends SyncDestinationM | ||||
|   }) | ||||
|   deploymentEnvironments; | ||||
|  | ||||
|   // Instead of using the 'array' attr transform, we keep deploymentEnvironments a string to leverage Ember's changedAttributes() | ||||
|   // which only tracks updates to string types. However, arrays are easier for managing multi-option selection so | ||||
|   // the fieldValue is used to get/set the deploymentEnvironments attribute to/from an array | ||||
|   // Arrays are easier for managing multi-option selection | ||||
|   // these get/set the deploymentEnvironments attribute via arrays | ||||
|   get deploymentEnvironmentsArray() { | ||||
|     // if undefined or an empty string, return empty array | ||||
|     return !this.deploymentEnvironments ? [] : this.deploymentEnvironments.split(','); | ||||
|   | ||||
| @@ -12,17 +12,15 @@ export default class SyncDestinationSerializer extends ApplicationSerializer { | ||||
|   }; | ||||
|  | ||||
|   serialize(snapshot) { | ||||
|     // special serialization only for PATCH requests | ||||
|     if (snapshot.isNew) return super.serialize(snapshot); | ||||
|     const data = super.serialize(snapshot); | ||||
|     if (snapshot.isNew) return data; | ||||
|  | ||||
|     // only send changed values | ||||
|     const data = {}; | ||||
|     for (const attr in snapshot.changedAttributes()) { | ||||
|       // first array element is the old value | ||||
|       const [, newValue] = snapshot.changedAttributes()[attr]; | ||||
|       data[decamelize(attr)] = newValue; | ||||
|     } | ||||
|     return data; | ||||
|     // only send changed parameters for PATCH requests | ||||
|     const changedKeys = Object.keys(snapshot.changedAttributes()).map((key) => decamelize(key)); | ||||
|     return changedKeys.reduce((payload, key) => { | ||||
|       payload[key] = data[key]; | ||||
|       return payload; | ||||
|     }, {}); | ||||
|   } | ||||
|  | ||||
|   // interrupt application's normalizeItems, which is called in normalizeResponse by application serializer | ||||
|   | ||||
							
								
								
									
										27
									
								
								ui/app/transforms/comma-string.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								ui/app/transforms/comma-string.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| /** | ||||
|  * Copyright (c) HashiCorp, Inc. | ||||
|  * SPDX-License-Identifier: BUSL-1.1 | ||||
|  */ | ||||
|  | ||||
| import Transform from '@ember-data/serializer/transform'; | ||||
|  | ||||
| /** | ||||
|  * transforms array types from the server to a comma separated string | ||||
|  * useful when using changedAttributes() in the serializer to track attribute changes for PATCH requests | ||||
|  * because arrays are not trackable and strings are! | ||||
|  */ | ||||
| export default class CommaString extends Transform { | ||||
|   deserialize(serialized) { | ||||
|     if (Array.isArray(serialized)) { | ||||
|       return serialized.join(','); | ||||
|     } | ||||
|     return serialized; | ||||
|   } | ||||
|  | ||||
|   serialize(deserialized) { | ||||
|     if (typeof deserialized === 'string') { | ||||
|       return deserialized.split(','); | ||||
|     } | ||||
|     return deserialized; | ||||
|   } | ||||
| } | ||||
| @@ -41,6 +41,6 @@ export default Factory.extend({ | ||||
|     access_token: '*****', | ||||
|     project_id: 'prj_12345', | ||||
|     team_id: 'team_12345', | ||||
|     deployment_environments: 'development,preview', // 'production' is also an option, but left out for testing to assert form changes value | ||||
|     deployment_environments: ['development', 'preview'], // 'production' is also an option, but left out for testing to assert form changes value | ||||
|   }), | ||||
| }); | ||||
|   | ||||
| @@ -212,6 +212,16 @@ module('Integration | Component | sync | Secrets::Page::Destinations::CreateAndE | ||||
|     gh: ['accessToken'], | ||||
|     'vercel-project': ['accessToken', 'teamId', 'deploymentEnvironments'], | ||||
|   }; | ||||
|   const EXPECTED_VALUE = (key) => { | ||||
|     switch (key) { | ||||
|       case 'deployment_environments': | ||||
|         return ['production']; | ||||
|       default: | ||||
|         // for all string type parameters | ||||
|         return `new-${key}-value`; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   for (const destination of SYNC_DESTINATIONS) { | ||||
|     const { type, maskedParams } = destination; | ||||
|     module(`edit destination: ${type}`, function (hooks) { | ||||
| @@ -237,9 +247,7 @@ module('Integration | Component | sync | Secrets::Page::Destinations::CreateAndE | ||||
|           const expectedKeys = editable.map((k) => decamelize(k)); | ||||
|           assert.propEqual(payloadKeys, expectedKeys, `${type} payload only contains editable attrs`); | ||||
|           expectedKeys.forEach((key) => { | ||||
|             // deploymentEnvironment field fixed possible options | ||||
|             const expectedValue = key === 'deployment_environments' ? 'production' : `new-${key}-value`; | ||||
|             assert.strictEqual(payload[key], expectedValue, `destination: ${type} updates key: ${key}`); | ||||
|             assert.deepEqual(payload[key], EXPECTED_VALUE(key), `destination: ${type} updates key: ${key}`); | ||||
|           }); | ||||
|           return { payload }; | ||||
|         }); | ||||
|   | ||||
							
								
								
									
										40
									
								
								ui/tests/unit/transforms/comma-string-test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								ui/tests/unit/transforms/comma-string-test.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| /** | ||||
|  * Copyright (c) HashiCorp, Inc. | ||||
|  * SPDX-License-Identifier: BUSL-1.1 | ||||
|  */ | ||||
|  | ||||
| import { module, test } from 'qunit'; | ||||
| import { setupTest } from 'vault/tests/helpers'; | ||||
|  | ||||
| module('Unit | Transform | comma string', function (hooks) { | ||||
|   setupTest(hooks); | ||||
|  | ||||
|   hooks.beforeEach(function () { | ||||
|     this.transform = this.owner.lookup('transform:comma-string'); | ||||
|   }); | ||||
|  | ||||
|   test('it serializes correctly for API', function (assert) { | ||||
|     const serialized = this.transform.serialize('one,two,three'); | ||||
|     assert.propEqual(serialized, ['one', 'two', 'three'], 'it serializes from string to array'); | ||||
|     assert.propEqual( | ||||
|       this.transform.serialize(['not a string']), | ||||
|       ['not a string'], | ||||
|       'it returns original value if not a string' | ||||
|     ); | ||||
|     assert.propEqual( | ||||
|       this.transform.serialize('no commas'), | ||||
|       ['no commas'], | ||||
|       'it splits a string without commas' | ||||
|     ); | ||||
|   }); | ||||
|  | ||||
|   test('it deserializes correctly from API', function (assert) { | ||||
|     const deserialized = this.transform.deserialize(['one', 'two', 'three']); | ||||
|     assert.strictEqual(deserialized, 'one,two,three', 'it deserializes from array to string'); | ||||
|     assert.strictEqual( | ||||
|       this.transform.deserialize('not an array'), | ||||
|       'not an array', | ||||
|       'it returns original value if not an array' | ||||
|     ); | ||||
|   }); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user
	 claire bontempo
					claire bontempo