mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			249 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			249 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import Ember from 'ember';
 | |
| import FocusOnInsertMixin from 'vault/mixins/focus-on-insert';
 | |
| import keys from 'vault/lib/keycodes';
 | |
| import KVObject from 'vault/lib/kv-object';
 | |
| 
 | |
| const LIST_ROUTE = 'vault.cluster.secrets.backend.list';
 | |
| const LIST_ROOT_ROUTE = 'vault.cluster.secrets.backend.list-root';
 | |
| const SHOW_ROUTE = 'vault.cluster.secrets.backend.show';
 | |
| const { get, computed } = Ember;
 | |
| 
 | |
| export default Ember.Component.extend(FocusOnInsertMixin, {
 | |
|   // a key model
 | |
|   key: null,
 | |
| 
 | |
|   // a value to pre-fill the key input - this is populated by the corresponding
 | |
|   // 'initialKey' queryParam
 | |
|   initialKey: null,
 | |
| 
 | |
|   // set in the route's setupController hook
 | |
|   mode: null,
 | |
| 
 | |
|   secretData: null,
 | |
| 
 | |
|   // called with a bool indicating if there's been a change in the secretData
 | |
|   onDataChange: () => {},
 | |
| 
 | |
|   // did user request advanced mode
 | |
|   preferAdvancedEdit: false,
 | |
| 
 | |
|   // use a named action here so we don't have to pass one in
 | |
|   // this will bubble to the route
 | |
|   toggleAdvancedEdit: 'toggleAdvancedEdit',
 | |
| 
 | |
|   codemirrorString: null,
 | |
| 
 | |
|   hasLintError: false,
 | |
| 
 | |
|   init() {
 | |
|     this._super(...arguments);
 | |
|     const secrets = this.get('key.secretData');
 | |
|     const data = KVObject.create({ content: [] }).fromJSON(secrets);
 | |
|     this.set('secretData', data);
 | |
|     this.set('codemirrorString', data.toJSONString());
 | |
|     if (data.isAdvanced()) {
 | |
|       this.set('preferAdvancedEdit', true);
 | |
|     }
 | |
|     this.checkRows();
 | |
|     if (this.get('mode') === 'edit') {
 | |
|       this.send('addRow');
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   willDestroyElement() {
 | |
|     const key = this.get('key');
 | |
|     if (get(key, 'isError') && !key.isDestroyed) {
 | |
|       key.rollbackAttributes();
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   partialName: Ember.computed('mode', function() {
 | |
|     return `partials/secret-form-${this.get('mode')}`;
 | |
|   }),
 | |
| 
 | |
|   routing: Ember.inject.service('-routing'),
 | |
| 
 | |
|   showPrefix: computed.or('key.initialParentKey', 'key.parentKey'),
 | |
| 
 | |
|   requestInFlight: computed.or('key.isLoading', 'key.isReloading', 'key.isSaving'),
 | |
| 
 | |
|   buttonDisabled: computed.or(
 | |
|     'requestInFlight',
 | |
|     'key.isFolder',
 | |
|     'key.isError',
 | |
|     'key.flagsIsInvalid',
 | |
|     'hasLintError'
 | |
|   ),
 | |
| 
 | |
|   basicModeDisabled: computed('secretDataIsAdvanced', 'showAdvancedMode', function() {
 | |
|     return this.get('secretDataIsAdvanced') || this.get('showAdvancedMode') === false;
 | |
|   }),
 | |
| 
 | |
|   secretDataAsJSON: computed('secretData', 'secretData.[]', function() {
 | |
|     return this.get('secretData').toJSON();
 | |
|   }),
 | |
| 
 | |
|   secretDataIsAdvanced: computed('secretData', 'secretData.[]', function() {
 | |
|     return this.get('secretData').isAdvanced();
 | |
|   }),
 | |
| 
 | |
|   hasDataChanges() {
 | |
|     const keyDataString = this.get('key.dataAsJSONString');
 | |
|     const sameData = this.get('secretData').toJSONString() === keyDataString;
 | |
|     if (sameData === false) {
 | |
|       this.set('lastChange', Date.now());
 | |
|     }
 | |
| 
 | |
|     this.get('onDataChange')(!sameData);
 | |
|   },
 | |
| 
 | |
|   showAdvancedMode: computed('preferAdvancedEdit', 'secretDataIsAdvanced', 'lastChange', function() {
 | |
|     return this.get('secretDataIsAdvanced') || this.get('preferAdvancedEdit');
 | |
|   }),
 | |
| 
 | |
|   transitionToRoute() {
 | |
|     const router = this.get('routing.router');
 | |
|     router.transitionTo.apply(router, arguments);
 | |
|   },
 | |
| 
 | |
|   bindKeys: Ember.on('didInsertElement', function() {
 | |
|     Ember.$(document).on('keyup.keyEdit', this.onEscape.bind(this));
 | |
|   }),
 | |
| 
 | |
|   unbindKeys: Ember.on('willDestroyElement', function() {
 | |
|     Ember.$(document).off('keyup.keyEdit');
 | |
|   }),
 | |
| 
 | |
|   onEscape(e) {
 | |
|     if (e.keyCode !== keys.ESC || this.get('mode') !== 'show') {
 | |
|       return;
 | |
|     }
 | |
|     const parentKey = this.get('key.parentKey');
 | |
|     if (parentKey) {
 | |
|       this.transitionToRoute(LIST_ROUTE, parentKey);
 | |
|     } else {
 | |
|       this.transitionToRoute(LIST_ROOT_ROUTE);
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   // successCallback is called in the context of the component
 | |
|   persistKey(method, successCallback, isCreate) {
 | |
|     let model = this.get('key');
 | |
|     let key = model.get('id');
 | |
| 
 | |
|     if (key.startsWith('/')) {
 | |
|       key = key.replace(/^\/+/g, '');
 | |
|       model.set('id', key);
 | |
|     }
 | |
| 
 | |
|     if (isCreate && typeof model.createRecord === 'function') {
 | |
|       // create an ember data model from the proxy
 | |
|       model = model.createRecord(model.get('backend'));
 | |
|       this.set('key', model);
 | |
|     }
 | |
| 
 | |
|     return model[method]().then(() => {
 | |
|       if (!Ember.get(model, 'isError')) {
 | |
|         successCallback(key);
 | |
|       }
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   checkRows() {
 | |
|     if (this.get('secretData').get('length') === 0) {
 | |
|       this.send('addRow');
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   actions: {
 | |
|     handleKeyDown(e) {
 | |
|       e.stopPropagation();
 | |
|       if (!(e.keyCode === keys.ENTER && e.metaKey)) {
 | |
|         return;
 | |
|       }
 | |
|       let $form = this.$('form');
 | |
|       if ($form.length) {
 | |
|         $form.submit();
 | |
|       }
 | |
|       $form = null;
 | |
|     },
 | |
| 
 | |
|     handleChange() {
 | |
|       this.set('codemirrorString', this.get('secretData').toJSONString(true));
 | |
|       this.hasDataChanges();
 | |
|     },
 | |
| 
 | |
|     createOrUpdateKey(type, event) {
 | |
|       event.preventDefault();
 | |
|       const newData = this.get('secretData').toJSON();
 | |
|       this.get('key').set('secretData', newData);
 | |
| 
 | |
|       // prevent from submitting if there's no key
 | |
|       // maybe do something fancier later
 | |
|       if (type === 'create' && Ember.isBlank(this.get('key.id'))) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       this.persistKey(
 | |
|         'save',
 | |
|         key => {
 | |
|           this.hasDataChanges();
 | |
|           this.transitionToRoute(SHOW_ROUTE, key);
 | |
|         },
 | |
|         type === 'create'
 | |
|       );
 | |
|     },
 | |
| 
 | |
|     deleteKey() {
 | |
|       this.persistKey('destroyRecord', () => {
 | |
|         this.transitionToRoute(LIST_ROOT_ROUTE);
 | |
|       });
 | |
|     },
 | |
| 
 | |
|     refresh() {
 | |
|       this.attrs.onRefresh();
 | |
|     },
 | |
| 
 | |
|     addRow() {
 | |
|       const data = this.get('secretData');
 | |
|       if (Ember.isNone(data.findBy('name', ''))) {
 | |
|         data.pushObject({ name: '', value: '' });
 | |
|         this.set('codemirrorString', data.toJSONString(true));
 | |
|       }
 | |
|       this.checkRows();
 | |
|       this.hasDataChanges();
 | |
|     },
 | |
| 
 | |
|     deleteRow(name) {
 | |
|       const data = this.get('secretData');
 | |
|       const item = data.findBy('name', name);
 | |
|       if (Ember.isBlank(item.name)) {
 | |
|         return;
 | |
|       }
 | |
|       data.removeObject(item);
 | |
|       this.checkRows();
 | |
|       this.hasDataChanges();
 | |
|       this.set('codemirrorString', data.toJSONString(true));
 | |
|       this.rerender();
 | |
|     },
 | |
| 
 | |
|     toggleAdvanced(bool) {
 | |
|       this.sendAction('toggleAdvancedEdit', bool);
 | |
|     },
 | |
| 
 | |
|     codemirrorUpdated(val, codemirror) {
 | |
|       codemirror.performLint();
 | |
|       const noErrors = codemirror.state.lint.marked.length === 0;
 | |
|       if (noErrors) {
 | |
|         this.get('secretData').fromJSONString(val);
 | |
|       }
 | |
|       this.set('hasLintError', !noErrors);
 | |
|       this.set('codemirrorString', val);
 | |
|     },
 | |
| 
 | |
|     formatJSON() {
 | |
|       this.set('codemirrorString', this.get('secretData').toJSONString(true));
 | |
|     },
 | |
|   },
 | |
| });
 | 
