diff --git a/ui/app/adapters/transform.js b/ui/app/adapters/transform.js index ffc6f3820164..e1c2ad888b70 100644 --- a/ui/app/adapters/transform.js +++ b/ui/app/adapters/transform.js @@ -28,7 +28,7 @@ export default ApplicationAdapter.extend({ deleteRecord(store, type, snapshot) { const { id } = snapshot; - return this.ajax(this.urlForRole(snapshot.record.get('backend'), id), 'DELETE'); + return this.ajax(this.urlForTransformations(snapshot.record.get('backend'), id), 'DELETE'); }, pathForType() { @@ -63,9 +63,10 @@ export default ApplicationAdapter.extend({ const { id, backend } = query; let zeroAddressAjax = resolve(); const queryAjax = this.ajax(this.urlForTransformations(backend, id), 'GET', this.optionsForQuery(id)); - if (!id) { - zeroAddressAjax = this.findAllZeroAddress(store, query); - } + // TODO: come back to why you need this, carry over. + // if (!id) { + // zeroAddressAjax = this.findAllZeroAddress(store, query); + // } return allSettled([queryAjax, zeroAddressAjax]).then(results => { // query result 404d, so throw the adapterError diff --git a/ui/app/components/role-edit.js b/ui/app/components/role-edit.js index 88270bc367d6..f2f27cc93ac5 100644 --- a/ui/app/components/role-edit.js +++ b/ui/app/components/role-edit.js @@ -89,7 +89,7 @@ export default Component.extend(FocusOnInsertMixin, { createOrUpdate(type, event) { event.preventDefault(); - const modelId = this.get('model.id') || this.get('model.name'); //ARG TODO this is not okay + const modelId = this.get('model.id') || this.get('model.name'); // ARG TODO this is not okay // prevent from submitting if there's no key // maybe do something fancier later if (type === 'create' && isBlank(modelId)) { diff --git a/ui/app/components/transform-show-transformation.js b/ui/app/components/transform-show-transformation.js new file mode 100644 index 000000000000..d15a8a29f2e1 --- /dev/null +++ b/ui/app/components/transform-show-transformation.js @@ -0,0 +1,8 @@ +import RoleEdit from './role-edit'; + +export default RoleEdit.extend({ + init() { + this._super(...arguments); + this.set('backendType', 'transform'); + }, +}); diff --git a/ui/app/helpers/options-for-backend.js b/ui/app/helpers/options-for-backend.js index ff7f72735fad..68bd08c47ba4 100644 --- a/ui/app/helpers/options-for-backend.js +++ b/ui/app/helpers/options-for-backend.js @@ -59,7 +59,7 @@ const SECRET_BACKENDS = { transform: { displayName: 'Transformation', navigateTree: false, - listItemPartial: 'partials/secret-list/item', + listItemPartial: 'partials/secret-list/transform-transformation-item', tabs: [ { name: 'transformations', diff --git a/ui/app/models/transform.js b/ui/app/models/transform.js index 77360af2582b..d8637656f81a 100644 --- a/ui/app/models/transform.js +++ b/ui/app/models/transform.js @@ -1,8 +1,8 @@ -import { alias } from '@ember/object/computed'; import { computed } from '@ember/object'; import DS from 'ember-data'; -import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities'; +import { apiPath } from 'vault/macros/lazy-capabilities'; import { expandAttributeMeta } from 'vault/utils/field-to-attrs'; +import attachCapabilities from 'vault/lib/attach-capabilities'; const { attr } = DS; @@ -35,11 +35,10 @@ const TWEAK_SOURCE = [ }, ]; -export default DS.Model.extend({ +const Model = DS.Model.extend({ // TODO: for now, commenting out openApi info, but keeping here just in case we end up using it. // useOpenAPI: true, // getHelpUrl: function(backend) { - // console.log(backend, 'Backend'); // return `/v1/${backend}?help=1`; // }, name: attr('string', { @@ -55,15 +54,6 @@ export default DS.Model.extend({ subText: 'Vault provides two types of transformations: Format Preserving Encryption (FPE) is reversible, while Masking is not.', }), - template: attr('stringArray', { - label: 'Template', // TODO: make this required for making a transformation - subLabel: 'Template Name', - subText: - 'Templates allow Vault to determine what and how to capture the value to be transformed. Type to use an existing template or create a new one.', - editType: 'searchSelect', - fallbackComponent: 'string-list', - models: ['transform/template'], - }), tweak_source: attr('string', { defaultValue: 'supplied', label: 'Tweak source', @@ -71,35 +61,42 @@ export default DS.Model.extend({ subText: `A tweak value is used when performing FPE transformations. This can be supplied, generated, or internal.`, // TODO: I do not include the link here. Need to figure out the best way to approach this. }), masking_character: attr('string', { + defaultValue: '*', label: 'Masking character', subText: 'Specify which character you’d like to mask your data.', }), - allowed_roles: attr('stringArray', { + template: attr('string', { + editType: 'searchSelect', + fallbackComponent: 'string-list', + label: 'Template', // TODO: make this required for making a transformation + models: ['transform/template'], + subLabel: 'Template Name', + subText: + 'Templates allow Vault to determine what and how to capture the value to be transformed. Type to use an existing template or create a new one.', + }), + templates: attr('array'), // TODO: remove once BE changes the returned property to a singular template on the GET request. + allowed_roles: attr('string', { label: 'Allowed roles', editType: 'searchSelect', fallbackComponent: 'string-list', models: ['transform/role'], subText: 'Search for an existing role, type a new role to create it, or use a wildcard (*).', }), - transformAttrs: computed(function() { + transformAttrs: computed('type', function() { // TODO: group them into sections/groups. Right now, we don't different between required and not required as we do by hiding options. // will default to design mocks on how to handle as it will likely be a different pattern using client-side validation, which we have not done before - return ['name', 'type', 'template', 'tweak_source', 'masking_characters', 'allowed_roles']; + if (this.type === 'masking') { + return ['name', 'type', 'masking_character', 'template', 'templates', 'allowed_roles']; + } + return ['name', 'type', 'tweak_source', 'template', 'templates', 'allowed_roles']; }), transformFieldAttrs: computed('transformAttrs', function() { return expandAttributeMeta(this, this.get('transformAttrs')); }), - updatePath: lazyCapabilities(apiPath`${'backend'}/transforms/${'id'}`, 'backend', 'id'), - canDelete: alias('updatePath.canDelete'), - canEdit: alias('updatePath.canUpdate'), - canRead: alias('updatePath.canRead'), - - generatePath: lazyCapabilities(apiPath`${'backend'}/creds/${'id'}`, 'backend', 'id'), - canGenerate: alias('generatePath.canUpdate'), - - signPath: lazyCapabilities(apiPath`${'backend'}/sign/${'id'}`, 'backend', 'id'), - canSign: alias('signPath.canUpdate'), + // zeroAddressPath: lazyCapabilities(apiPath`${'backend'}/config/zeroaddress`, 'backend'), + // canEditZeroAddress: alias('zeroAddressPath.canUpdate'), +}); - zeroAddressPath: lazyCapabilities(apiPath`${'backend'}/config/zeroaddress`, 'backend'), - canEditZeroAddress: alias('zeroAddressPath.canUpdate'), +export default attachCapabilities(Model, { + updatePath: apiPath`transform/transformation/${'id'}`, }); diff --git a/ui/app/serializers/transform.js b/ui/app/serializers/transform.js new file mode 100644 index 000000000000..a466cc4d5df9 --- /dev/null +++ b/ui/app/serializers/transform.js @@ -0,0 +1,11 @@ +import ApplicationSerializer from './application'; + +export default ApplicationSerializer.extend({ + normalizeResponse(store, primaryModelClass, payload, id, requestType) { + if (payload.data.masking_character) { + payload.data.masking_character = String.fromCharCode(payload.data.masking_character); + } + // TODO: the BE is working on a ticket to amend these response, so revisit. + return this._super(store, primaryModelClass, payload, id, requestType); + }, +}); diff --git a/ui/app/styles/components/transform-edit.scss b/ui/app/styles/components/transform-edit.scss new file mode 100644 index 000000000000..57400100420a --- /dev/null +++ b/ui/app/styles/components/transform-edit.scss @@ -0,0 +1,8 @@ +.copy-text { + background: $ui-gray-010; + + & > code { + color: $ui-gray-800; + padding: 14px; + } +} diff --git a/ui/app/styles/core.scss b/ui/app/styles/core.scss index 62d76be84129..2e684cfd7df8 100644 --- a/ui/app/styles/core.scss +++ b/ui/app/styles/core.scss @@ -103,6 +103,7 @@ @import './components/token-expire-warning'; @import './components/toolbar'; @import './components/tool-tip'; +@import './components/transform-edit.scss'; @import './components/transit-card'; @import './components/ttl-picker2'; @import './components/unseal-warning'; diff --git a/ui/app/styles/core/forms.scss b/ui/app/styles/core/forms.scss index 113576c374da..074ae263c9b9 100644 --- a/ui/app/styles/core/forms.scss +++ b/ui/app/styles/core/forms.scss @@ -21,7 +21,7 @@ label { .b-checkbox .is-label { color: $grey-darker; display: inline-block; - font-size: $size-small; + font-size: $body-size; font-weight: $font-weight-bold; &:not(:last-child) { @@ -73,6 +73,7 @@ label { .sub-text { color: $grey; margin-bottom: 0.25rem; + font-size: $size-8; } .input, .textarea, diff --git a/ui/app/styles/core/helpers.scss b/ui/app/styles/core/helpers.scss index ecc7bd6ad1da..a9c76e02f2e9 100644 --- a/ui/app/styles/core/helpers.scss +++ b/ui/app/styles/core/helpers.scss @@ -168,6 +168,10 @@ .has-top-margin-xl { margin-top: $spacing-xl; } +.has-border-bottom-light { + border-radius: 0; + border-bottom: 1px solid $grey-light; +} .has-border-danger { border: 1px solid $danger; } diff --git a/ui/app/templates/components/transform-edit-form.hbs b/ui/app/templates/components/transform-edit-form.hbs index f693b79aa7d9..a35e16c68245 100644 --- a/ui/app/templates/components/transform-edit-form.hbs +++ b/ui/app/templates/components/transform-edit-form.hbs @@ -10,7 +10,6 @@ @model={{model}} /> {{/each}} -
@@ -21,7 +20,7 @@ data-test-role-ssh-create=true > {{#if (eq mode 'create')}} - Create role + Create transformation {{else if (eq mode 'edit')}} Save {{/if}} diff --git a/ui/app/templates/components/transform-show-transformation.hbs b/ui/app/templates/components/transform-show-transformation.hbs new file mode 100644 index 000000000000..3b31cd8273c6 --- /dev/null +++ b/ui/app/templates/components/transform-show-transformation.hbs @@ -0,0 +1,48 @@ +
+ {{#each model.transformFieldAttrs as |attr|}} + {{#if (eq attr.type "object")}} + {{info-table-row label=(capitalize (or attr.options.label (humanize (dasherize attr.name)))) value=(stringify (get model attr.name))}} + {{else}} + {{info-table-row label=(capitalize (or attr.options.label (humanize (dasherize attr.name)))) value=(get model attr.name)}} + {{/if}} + {{/each}} +
+ +
+ + {{!-- ARG TODO make these components? --}} +
+

Encode

+
+ + To test the encoding capability of your transformation, use the following command. It will output an encoded_value. + +
+
+ {{#let "vault write transform/encode/payments value=" as |copyEncodeCommand|}} + vault write transform/encode/payments value=<enter your value here> + + + + {{/let}} +
+
+
+

Decode

+
+ + To test decoding capability of your transformation, use the encoded_value in the following command. It should return your original input. + +
+
+ {{#let "vault write transform/decode/payments value=" as |copyDecodeCommand|}} + vault write transform/decode/payments value=<enter your value here> + + + + {{/let}} +
+
+
diff --git a/ui/app/templates/components/transformation-edit.hbs b/ui/app/templates/components/transformation-edit.hbs index aaef3777369c..1ae25afd377a 100644 --- a/ui/app/templates/components/transformation-edit.hbs +++ b/ui/app/templates/components/transformation-edit.hbs @@ -15,7 +15,7 @@ {{else if (eq mode 'edit')}} Edit Transformation {{else}} - SSH role {{model.id}} + Transformation {{model.id}} {{/if}} @@ -24,55 +24,39 @@ {{#if (eq mode "show")}} - {{#if (eq model.keyType "otp")}} - - Generate Credential - - {{else}} - - Sign Keys - - {{/if}} + {{!-- TODO: update these actions, show delete grey out if not allowed --}} {{#if (or model.canUpdate model.canDelete)}}
{{/if}} {{#if model.canDelete}} + {{!-- TODO only allow deletion when not in use by a role --}} - Delete role + Delete transformation {{/if}} - {{#if (or model.canUpdate model.canDelete)}} + {{#if model.canUpdate }} - Edit role + Edit transformation {{/if}} {{/if}} - -{{!-- TODO: keeping here for now to remind us what other component we need to add --}} -{{!-- TODO: not following partial pattern in Transform, this comes from SSH --}} -{{!-- {{#if (or (eq mode 'edit') (eq mode 'create'))}} - {{partial 'partials/role-ssh/form'}} +{{#if (or (eq mode 'edit') (eq mode 'create'))}} + {{else}} - {{partial 'partials/role-ssh/show'}} -{{/if}} --}} + +{{/if}} diff --git a/ui/app/templates/partials/secret-list/transform-transformation-item.hbs b/ui/app/templates/partials/secret-list/transform-transformation-item.hbs new file mode 100644 index 000000000000..94ccc1f8981c --- /dev/null +++ b/ui/app/templates/partials/secret-list/transform-transformation-item.hbs @@ -0,0 +1,60 @@ +{{!-- TODO do not let click if !canRead --}} +{{#linked-block + "vault.cluster.secrets.backend.show" + item.id + class="list-item-row" + data-test-secret-link=item.id + encode=true + queryParams=(secret-query-params backendModel.type) +}} +
+
+ + + {{if (eq item.id ' ') '(self)' (or item.keyWithoutParent item.id)}} + +
+
+ + + +
+
+{{/linked-block}}