mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	 99445dbfd4
			
		
	
	99445dbfd4
	
	
	
		
			
			* Ember Engine Setup for Secrets Sync (#23653) * ember engine setup for secrets sync * Update ui/lib/sync/addon/routes.js Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> --------- Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> * Sync Mirage Setup (#23683) * adds mirage setup for sync endpoints * updates secret_name default in sync-association mirage factory * UI Secrets Sync: Ember data sync destinations (#23674) * add models * adapters * base model adapter * update test response * add sync destinations helper * finish renaming base destination model/adapter * add comment * add serializer * use normalizeItems instead * destination serializer test * add destination find method; * add conditional operand * UI Secrets Sync: Overview landing page (#23696) * add models * adapters * base model adapter * update test response * add sync destinations helper * finish renaming base destination model/adapter * add comment * add serializer * doc-link helper * add version service * landing and overview component * overview page * add tests * UI Secrets Sync: Destinations adapter add LIST (#23716) * add models * adapters * base model adapter * update test response * add sync destinations helper * finish renaming base destination model/adapter * add comment * add serializer * doc-link helper * add version service * landing and overview component * overview page * build out serializer and adapters * update mirage * fix merge conflicts * one more conflict! * pull transformQueryResponse to separate method in adapter * move data transforming all to serializer and tests * add note to paginationd ocs docs * conditionally render CTA * add lazyPaginatedQuery method to destinations route * remove partial error * Secrets Sync: Destinations create - select type (#23792) * add category to destinations * build select type page * refactor prompt config situation * routing for destinations * update select-type routing * make card width fixed * revert CTA routing change, keep shouldRenderOverview * add header for gif demo to form * cleanup scope * more scope cleanup * add test * add type selector * rename components * rename again * remove async * fix tests * fix select type rename in test * delete renamed test * fix import of general selectors * rename using component syntax * UI Secrets Sync: Create destination form and route (#23806) * add model attribute metadata * add form and save url, remove name and type from serializer * move checkbox list to form field helper * add styling to alert inline * use newly made class * fix cancel action and cleanup form * change quotes * remove checkbox action from form component * add tests * address feedback * add API error test * use create record method instead * adapter test for create record * return from find method if type is undefined * cleanup test selectors * secrets sync: refactor sync destinations helper (#23839) * refactor getter in base destination model * add getters back to model * Secrets sync UI: Destination details page (#23842) * change labels to match params * add maskedParams to base model * add details route * add details view; * update mirage * fix secrets sync link; * delete parent destination route * add copyright header * add secrets route * move sync route outside of secrets/ route * upate mirage * export to-label * finish tests * make ternary * rename header tabs * fix selector in test * Secrets Sync UI: Cleanup headers + tabs (#23873) * remove destination header component, add headers/tabs to all routes * fix header padding * move tabs + toolbar back into component... * add copyright header * add delete modal * lol revert again * add extra line after copyright header * Secrets Sync Destinations List View (#23949) * adds route and page component for sync destinations list view * filters by type first for sync destinations * adds test for store.filterData method * Update ui/app/services/store.js Co-authored-by: Kianna <30884335+kiannaquach@users.noreply.github.com> * updates nav link label for secrets sync * moves sync destinations types out of app-types * moves loading-dropdown-option component to core addon and adds to destination list item menu * change true assertion to deepEqual in sync destinations test * adds copyright header to sync-destinations type file * clear store dataset on sync destination create --------- Co-authored-by: Kianna <30884335+kiannaquach@users.noreply.github.com> * Sync Destinations Capabilities (#23953) * adds route and page component for sync destinations list view * filters by type first for sync destinations * adds test for store.filterData method * adds capabilities checks for sync destinations * removes canList from sync destinations capabilities * updates sync header tests * Update ui/tests/integration/components/sync/sync-header-test.js Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> * updates sync destination response serialization * updates sync destination serializer test * updates sync destinations page test assertions * fixes mirage sync destinations payload issue * removes commented out method in sync destination adapter * fixes inconsistencies with url generation for sync destinations delete * fixes sync destinations page test --------- Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> * Sync Associations Ember Data Setup (#24132) * adds model, adapter and serializer for sync associations * updates sync association adapter save methods to use adapterOptions to determine action * Sync Destination Secrets Route and Page Component (#24155) * renames sync destination header component and adds tests * adds destination secrets route and page component * adds setup-models helper for sync testing * moves destination details test into subdir * adds destination secrets page component tests * adds controller for destination secrets route * fixes pagination route on destination secrets view * fixes sync association updated_at assertion based on timezone * updates kv secret details external route name * updates usage of old spacing style variable after merge * use confirm action instead of contextual confirm (old) component (#24189) * UI Secrets Sync: Adds secret status to kv v2 details page (#24208) * woops! missed this styling for confirm action swap * update link to go to destination secrets * change edit to view secret from destination secrets list * add synDestination to external routes for kv engine * add sync status badge component * export from addon * splaattributes * poll sync status for kv secret details and render * move from controller to component * update name to new destinationName key * reorder list view items * add refresh button * add mirage data * change to loading static * update icons to be sync specific * change name * move button and change fetch to concurrency task * add tests to kv details * add color assertion * add copyright header * small test tweaks * Update ui/tests/integration/components/sync-status-badge-test.js * fixes test --------- Co-authored-by: Jordan Reimer <zofskeez@gmail.com> * Sync Secrets to Destination (#24247) * fixes issue with filter-input debounce and updates to spread attributes for input rather than use args * adds destination sync page component * removes unused var in sync component * adds test for manual mount path input in sync view * updates mount filtering in destinations sync page to target kv v2 * Secrets Sync Landing Page Images (#24277) * updates sync landing page to add marketing images * removes top margin from sync landing-cta * adds aria-describedby to sync landing images * UI Secrets Sync: Serialize trailing slash from destination type (#24294) * remove trailing slash from type in destination LIST response * update keys in mirage and tests * Sync Overview (#24340) * updates landing-cta image to png with matching height * adds ts definitons for sync adapters * updates sync adapters and serializers to add methods for fetching overview data * adds sync associations list handler to mirage and seeds more associations in scenario * adds table and totals cards to sync overview page * adds sync overview page component tests * fixes tests * changes lastSync key to lastUpdated for sync fetchByDestinations response * adds emdash as placeholder for lastUpdated null value in secrets by destination table * updates to handle 0 associations state for destination in overview table * Secrets Sync UI: Add loading and error substates (#24353) * add error substate * add loading substates * delete loading from secrets route * Remove is-version Helper (#24388) * removes is-version helper and injects service into components * updates sync tests using version service to new API * adds comment back for tracked property in secret detials page component * updates sync tests to use common selectors (#24397) * update capitalization to consistently be titlecase, fix breadcrumb selector * clears sync associations from store on destination sync page component destroy (#24450) * KV Suggestion Input (#24447) * updates filter-input component to conditionally show search icon * adds kv-suggestion-input component to core addon * updates destination sync page component to use KvSuggestionInput component * fixes issue in kv-suggestion-input where a partial search term was not replaced with the selected suggestion value * updates kv-suggestion-input to retain focus on suggestion click * fixes test * updates kv-suggestion-input to conditionally render label component * adds comments to kv-suggestion-input regarding trigger * moves alert banner in sync page below button set * moves inputId from getter to class property on kv-suggestion-input * Secrets Sync UI: Editing a destination (#24413) * add form field groups to sync models * update create-and-edit form to use confirmLeave and enableInput component * enable input component * add more stars * update css comments * Update ui/app/styles/helper-classes/flexbox-and-grid.scss * make attrOptions optional * remove decorator * add env variables to subtexr * add subtext to textfile * fix overviwe transition bug * remove breadcrumbs to getter * WIP adapter update * update mirage response * add update method with PATCH * add patch to application adapter * fix typo * finish tests * remove validations because could use environment variables * use getter and setter in model * move update record business to serializer * rest of logic in serializer; gp ; gp * add model validation warnings * cleanup getters * pull create/update logic into method for mirage * add test for validation warning * update KV copy * Sync Success Banner (#24491) * adds success banner to destination sync page * move submit disabled logic to getter in destination sync page * adds id and for attributes to kv mount input in sync page * hides sync success banner on submit * use Sync secrets everywhere (remove new) (#24494) * use Sync secrets everywhere (remove new) * revert test name change * Sync Destinations List Filter Bug (#24496) * fixes issues filtering destinations list * adds test * fixes Sync now action text alignment in destination secrets list * UI Secrets sync: Add purge query param to delete endpoint (#24497) * adds updated_at to mirage set association handler * adds changelog entry * add enterprise in parenthesis for changelog * addres a11y feedback --------- Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com> Co-authored-by: clairebontempo@gmail.com <clairebontempo@gmail.com> Co-authored-by: Kianna <30884335+kiannaquach@users.noreply.github.com>
		
			
				
	
	
		
			146 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * Copyright (c) HashiCorp, Inc.
 | |
|  * SPDX-License-Identifier: BUSL-1.1
 | |
|  */
 | |
| 
 | |
| import Component from '@glimmer/component';
 | |
| import { service } from '@ember/service';
 | |
| import { tracked } from '@glimmer/tracking';
 | |
| import { action } from '@ember/object';
 | |
| import { guidFor } from '@ember/object/internals';
 | |
| import { run } from '@ember/runloop';
 | |
| import { keyIsFolder, parentKeyForKey, keyWithoutParentKey } from 'core/utils/key-utils';
 | |
| 
 | |
| import type StoreService from 'vault/services/store';
 | |
| import type KvSecretMetadataModel from 'vault/models/kv/metadata';
 | |
| 
 | |
| /**
 | |
|  * @module KvSuggestionInput
 | |
|  * Input component that fetches secrets at a provided mount path and displays them as suggestions in a dropdown
 | |
|  * As the user types the result set will be filtered providing suggestions for the user to select
 | |
|  * After the input debounce wait time (500ms), if the value ends in a slash, secrets will be fetched at that path
 | |
|  * The new result set will then be displayed in the dropdown as suggestions for the newly inputted path
 | |
|  * Selecting a suggestion will append it to the input value
 | |
|  * This allows the user to build a full path to a secret for the provided mount
 | |
|  * This is useful for helping the user find deeply nested secrets given the path based policy system
 | |
|  * If the user does not have list permission they are still able to enter a path to a secret but will not see suggestions
 | |
|  * 
 | |
|  * @example
 | |
|  * <KvSuggestionInput
 | |
|     @label="Select a secret to sync"
 | |
|     @subText="Enter the full path to the secret. Suggestions will display below if permitted by policy."
 | |
|     @value={{this.secretPath}}
 | |
|     @mountPath={{this.mountPath}} // input disabled when mount path is not provided
 | |
|     @onChange={{fn (mut this.secretPath)}}
 | |
|   /> 
 | |
|  */
 | |
| 
 | |
| interface Args {
 | |
|   label: string;
 | |
|   subText?: string;
 | |
|   mountPath: string;
 | |
|   value: string;
 | |
|   onChange: CallableFunction;
 | |
| }
 | |
| 
 | |
| interface PowerSelectAPI {
 | |
|   actions: {
 | |
|     open(): void;
 | |
|     close(): void;
 | |
|   };
 | |
| }
 | |
| 
 | |
| export default class KvSuggestionInputComponent extends Component<Args> {
 | |
|   @service declare readonly store: StoreService;
 | |
| 
 | |
|   @tracked secrets: KvSecretMetadataModel[] = [];
 | |
|   powerSelectAPI: PowerSelectAPI | undefined;
 | |
|   _cachedSecrets: KvSecretMetadataModel[] = []; // cache the response for filtering purposes
 | |
|   inputId = `suggestion-input-${guidFor(this)}`; // add unique segment to id in case multiple instances of component are used on the same page
 | |
| 
 | |
|   constructor(owner: unknown, args: Args) {
 | |
|     super(owner, args);
 | |
|     if (this.args.mountPath) {
 | |
|       this.updateSuggestions();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   async fetchSecrets(isDirectory: boolean) {
 | |
|     const { mountPath } = this.args;
 | |
|     try {
 | |
|       const backend = keyIsFolder(mountPath) ? mountPath.slice(0, -1) : mountPath;
 | |
|       const parentDirectory = parentKeyForKey(this.args.value);
 | |
|       const pathToSecret = isDirectory ? this.args.value : parentDirectory;
 | |
|       const kvModels = (await this.store.query('kv/metadata', {
 | |
|         backend,
 | |
|         pathToSecret,
 | |
|       })) as unknown;
 | |
|       // this will be used to filter the existing result set when the search term changes within the same path
 | |
|       this._cachedSecrets = kvModels as KvSecretMetadataModel[];
 | |
|       return this._cachedSecrets;
 | |
|     } catch (error) {
 | |
|       console.log(error); // eslint-disable-line
 | |
|       return [];
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   filterSecrets(kvModels: KvSecretMetadataModel[] | undefined = [], isDirectory: boolean) {
 | |
|     const { value } = this.args;
 | |
|     const secretName = keyWithoutParentKey(value) || '';
 | |
|     return kvModels.filter((model) => {
 | |
|       if (!value || isDirectory) {
 | |
|         return true;
 | |
|       }
 | |
|       if (value === model.fullSecretPath) {
 | |
|         // don't show suggestion if it's currently selected
 | |
|         return false;
 | |
|       }
 | |
|       return model.path.toLowerCase().includes(secretName.toLowerCase());
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   @action
 | |
|   async updateSuggestions() {
 | |
|     const isFirstUpdate = !this._cachedSecrets.length;
 | |
|     const isDirectory = keyIsFolder(this.args.value);
 | |
|     if (!this.args.mountPath) {
 | |
|       this.secrets = [];
 | |
|     } else if (this.args.value && !isDirectory && this.secrets) {
 | |
|       // if we don't need to fetch from a new path, filter the previous result set with the updated search term
 | |
|       this.secrets = this.filterSecrets(this._cachedSecrets, isDirectory);
 | |
|     } else {
 | |
|       const kvModels = await this.fetchSecrets(isDirectory);
 | |
|       this.secrets = this.filterSecrets(kvModels, isDirectory);
 | |
|     }
 | |
|     // don't do anything on first update -- allow dropdown to open on input click
 | |
|     if (!isFirstUpdate) {
 | |
|       const action = this.secrets.length ? 'open' : 'close';
 | |
|       this.powerSelectAPI?.actions[action]();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @action
 | |
|   onInput(value: string) {
 | |
|     this.args.onChange(value);
 | |
|     this.updateSuggestions();
 | |
|   }
 | |
| 
 | |
|   @action
 | |
|   onInputClick() {
 | |
|     if (this.secrets.length) {
 | |
|       this.powerSelectAPI?.actions.open();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   @action
 | |
|   onSuggestionSelect(secret: KvSecretMetadataModel) {
 | |
|     // user may partially type a value to filter result set and then select a suggestion
 | |
|     // in this case the partially typed value must be replaced with suggestion value
 | |
|     // the fullSecretPath contains the previous selections or typed path segments
 | |
|     this.args.onChange(secret.fullSecretPath);
 | |
|     this.updateSuggestions();
 | |
|     // refocus the input after selection
 | |
|     run(() => document.getElementById(this.inputId)?.focus());
 | |
|   }
 | |
| }
 |