diff --git a/ui/app/models/oidc/assignment.js b/ui/app/models/oidc/assignment.js index 980c5f62d0..45cbe519cd 100644 --- a/ui/app/models/oidc/assignment.js +++ b/ui/app/models/oidc/assignment.js @@ -29,11 +29,6 @@ export default class OidcAssignmentModel extends Model { // CAPABILITIES @lazyCapabilities(apiPath`identity/oidc/assignment/${'name'}`, 'name') assignmentPath; - @lazyCapabilities(apiPath`identity/oidc/assignment`) assignmentsPath; - - get canCreate() { - return this.assignmentPath.get('canCreate'); - } get canRead() { return this.assignmentPath.get('canRead'); } @@ -43,17 +38,4 @@ export default class OidcAssignmentModel extends Model { get canDelete() { return this.assignmentPath.get('canDelete'); } - get canList() { - return this.assignmentsPath.get('canList'); - } - - @lazyCapabilities(apiPath`identity/entity`) entitiesPath; - get canListEntities() { - return this.entitiesPath.get('canList'); - } - - @lazyCapabilities(apiPath`identity/group`) groupsPath; - get canListGroups() { - return this.groupsPath.get('canList'); - } } diff --git a/ui/app/models/oidc/client.js b/ui/app/models/oidc/client.js index 89edafdcd2..7622dccde7 100644 --- a/ui/app/models/oidc/client.js +++ b/ui/app/models/oidc/client.js @@ -73,45 +73,6 @@ export default class OidcClientModel extends Model { @attr('string', { label: 'Client ID' }) clientId; @attr('string') clientSecret; - // CAPABILITIES // - @lazyCapabilities(apiPath`identity/oidc/client/${'name'}`, 'name') clientPath; - @lazyCapabilities(apiPath`identity/oidc/client`) clientsPath; - get canCreate() { - return this.clientPath.get('canCreate'); - } - get canRead() { - return this.clientPath.get('canRead'); - } - get canEdit() { - return this.clientPath.get('canUpdate'); - } - get canDelete() { - return this.clientPath.get('canDelete'); - } - get canList() { - return this.clientsPath.get('canList'); - } - - @lazyCapabilities(apiPath`identity/oidc/key`) keysPath; - get canListKeys() { - return this.keysPath.get('canList'); - } - - @lazyCapabilities(apiPath`identity/oidc/assignment/${'name'}`, 'name') assignmentPath; - @lazyCapabilities(apiPath`identity/oidc/assignment`) assignmentsPath; - get canCreateAssignments() { - return this.assignmentPath.get('canCreate'); - } - get canListAssignments() { - return this.assignmentsPath.get('canList'); - } - - // API WIP - @lazyCapabilities(apiPath`identity/oidc/${'name'}/provider`, 'backend', 'name') clientProvidersPath; - get canListProviders() { - return this.clientProvidersPath.get('canList'); - } - // TODO refactor when field-to-attrs util is refactored as decorator _attributeMeta = null; // cache initial result of expandAttributeMeta in getter and return get formFields() { @@ -131,4 +92,16 @@ export default class OidcClientModel extends Model { } return this._fieldToAttrsGroups; } + + // CAPABILITIES // + @lazyCapabilities(apiPath`identity/oidc/client/${'name'}`, 'name') clientPath; + get canRead() { + return this.clientPath.get('canRead'); + } + get canEdit() { + return this.clientPath.get('canUpdate'); + } + get canDelete() { + return this.clientPath.get('canDelete'); + } } diff --git a/ui/app/models/oidc/key.js b/ui/app/models/oidc/key.js index 843516d7e4..6c90be4860 100644 --- a/ui/app/models/oidc/key.js +++ b/ui/app/models/oidc/key.js @@ -42,10 +42,6 @@ export default class OidcKeyModel extends Model { @lazyCapabilities(apiPath`identity/oidc/key/${'name'}`, 'name') keyPath; @lazyCapabilities(apiPath`identity/oidc/key/${'name'}/rotate`, 'name') rotatePath; - @lazyCapabilities(apiPath`identity/oidc/key`) keysPath; - get canCreate() { - return this.keyPath.get('canCreate'); - } get canRead() { return this.keyPath.get('canRead'); } @@ -58,7 +54,4 @@ export default class OidcKeyModel extends Model { get canDelete() { return this.keyPath.get('canDelete'); } - get canList() { - return this.keysPath.get('canList'); - } } diff --git a/ui/app/models/oidc/provider.js b/ui/app/models/oidc/provider.js index f87efa9004..7ffa8fc6fa 100644 --- a/ui/app/models/oidc/provider.js +++ b/ui/app/models/oidc/provider.js @@ -45,11 +45,8 @@ export default class OidcProviderModel extends Model { } return this._attributeMeta; } + @lazyCapabilities(apiPath`identity/oidc/provider/${'name'}`, 'name') providerPath; - @lazyCapabilities(apiPath`identity/oidc/provider`) providersPath; - get canCreate() { - return this.providerPath.get('canCreate'); - } get canRead() { return this.providerPath.get('canRead'); } @@ -59,16 +56,4 @@ export default class OidcProviderModel extends Model { get canDelete() { return this.providerPath.get('canDelete'); } - get canList() { - return this.providersPath.get('canList'); - } - - @lazyCapabilities(apiPath`identity/oidc/client`) clientsPath; - get canListClients() { - return this.clientsPath.get('canList'); - } - @lazyCapabilities(apiPath`identity/oidc/scope`) scopesPath; - get canListScopes() { - return this.scopesPath.get('canList'); - } } diff --git a/ui/app/models/oidc/scope.js b/ui/app/models/oidc/scope.js index aed338e68d..d15ed52eeb 100644 --- a/ui/app/models/oidc/scope.js +++ b/ui/app/models/oidc/scope.js @@ -23,10 +23,6 @@ export default class OidcScopeModel extends Model { } @lazyCapabilities(apiPath`identity/oidc/scope/${'name'}`, 'name') scopePath; - @lazyCapabilities(apiPath`identity/oidc/scope`) scopesPath; - get canCreate() { - return this.scopePath.get('canCreate'); - } get canRead() { return this.scopePath.get('canRead'); } @@ -36,7 +32,4 @@ export default class OidcScopeModel extends Model { get canDelete() { return this.scopePath.get('canDelete'); } - get canList() { - return this.scopesPath.get('canList'); - } } diff --git a/ui/app/templates/components/oidc/provider-list.hbs b/ui/app/templates/components/oidc/provider-list.hbs index 9f20d8972c..94bec4b697 100644 --- a/ui/app/templates/components/oidc/provider-list.hbs +++ b/ui/app/templates/components/oidc/provider-list.hbs @@ -26,7 +26,7 @@ Details diff --git a/ui/app/templates/vault/cluster/access/oidc/assignments/assignment/details.hbs b/ui/app/templates/vault/cluster/access/oidc/assignments/assignment/details.hbs index 0197809b8f..6a9ad186d6 100644 --- a/ui/app/templates/vault/cluster/access/oidc/assignments/assignment/details.hbs +++ b/ui/app/templates/vault/cluster/access/oidc/assignments/assignment/details.hbs @@ -66,7 +66,8 @@ @value={{@model.entityIds}} @model={{@model}} @isLink={{true}} - @modelType="oidc/assignment" + @renderItemName={{true}} + @modelType="identity/entity" @itemRoute={{(array "vault.cluster.access.identity.show" "entities" "details")}} @alwaysRender={{true}} @toggleViewAll={{true}} @@ -77,7 +78,8 @@ @value={{@model.groupIds}} @model={{@model}} @isLink={{true}} - @modelType="oidc/assignment" + @renderItemName={{true}} + @modelType="identity/group" @itemRoute={{(array "vault.cluster.access.identity.show" "groups" "details")}} @alwaysRender={{true}} @doNotTruncate={{true}} diff --git a/ui/lib/core/addon/components/info-table-item-array.hbs b/ui/lib/core/addon/components/info-table-item-array.hbs index d4bd436042..5a3f1e3c7f 100644 --- a/ui/lib/core/addon/components/info-table-item-array.hbs +++ b/ui/lib/core/addon/components/info-table-item-array.hbs @@ -1,72 +1,68 @@ {{! the class linkable-item is needed for the read-more component }} -
+
{{#if @isLink}}
- - {{#each this.displayArrayTruncated as |name|}} - {{#if (is-wildcard-string name)}} - {{#let (filter-wildcard name this.allOptions) as |wildcardCount|}} - {{name}} - - includes - {{if wildcardCount wildcardCount 0}} - {{if (eq wildcardCount 1) @wildcardLabel (pluralize @wildcardLabel)}} - - {{#if (eq this.displayArrayTruncated.lastObject name)}} - - View all {{lowercase @label}}. - - {{/if}} - {{/let}} - {{else}} - {{#if (is-array this.itemRoute)}} - - {{name}} - + {{#if this.fetchComplete}} + + {{#each this.displayArrayTruncated as |item|}} + {{#if (is-wildcard-string item)}} + {{#let (filter-wildcard item this.allOptions) as |wildcardCount|}} + {{item}} + + {{if (not-eq wildcardCount undefined) (concat "includes " wildcardCount)}} + {{if (eq wildcardCount 1) @wildcardLabel (pluralize @wildcardLabel)}} + + {{#if (eq this.displayArrayTruncated.lastObject item)}} + + View all {{lowercase @label}}. + + {{/if}} + {{/let}} {{else}} - - {{name}} - - {{/if}} - {{/if}} - {{#if - (or - (and (not-eq name this.displayArrayTruncated.lastObject) this.wildcardInDisplayArray) - (not-eq name this.displayArrayTruncated.lastObject) - ) - }} - ,  - {{/if}} - {{#unless this.doNotTruncate}} - {{#if (and (eq name this.displayArrayTruncated.lastObject) (gte @displayArray.length 10))}} - {{! dec is a math helper that decrements by 5 the length of the array ex: 11-5 = "and 6 others."}} - -  and - {{dec 5 @displayArray.length}} - others.  - - {{/if}} - {{#if (and (eq name this.displayArrayTruncated.lastObject) (gte @displayArray.length 10))}} - {{#if (is-array @rootRoute)}} - - View all {{lowercase @label}}. + {{#if (is-array this.itemRoute)}} + + {{or (get this.itemNameById item) item}} {{else}} - - View all {{lowercase @label}}. + + {{or (get this.itemNameById item) item}} {{/if}} {{/if}} - {{/unless}} - {{/each}} - + {{#if (not-eq item this.displayArrayTruncated.lastObject)}} + ,  + {{/if}} + {{#unless this.doNotTruncate}} + {{#if (and (eq item this.displayArrayTruncated.lastObject) (gte @displayArray.length 10))}} + {{! dec is a math helper that decrements by 5 the length of the array ex: 11-5 = "and 6 others."}} + +  and + {{dec 5 @displayArray.length}} + others.  + + {{/if}} + {{#if (and (eq item this.displayArrayTruncated.lastObject) (gte @displayArray.length 10))}} + {{#if (is-array @rootRoute)}} + + View all {{lowercase @label}}. + + {{else}} + + View all {{lowercase @label}}. + + {{/if}} + {{/if}} + {{/unless}} + {{/each}} + + {{/if}}
{{else}} diff --git a/ui/lib/core/addon/components/info-table-item-array.js b/ui/lib/core/addon/components/info-table-item-array.js index 2c316de6ec..3c9291ec4b 100644 --- a/ui/lib/core/addon/components/info-table-item-array.js +++ b/ui/lib/core/addon/components/info-table-item-array.js @@ -1,8 +1,7 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { inject as service } from '@ember/service'; -import { task } from 'ember-concurrency'; -import { isWildcardString } from 'vault/helpers/is-wildcard-string'; +import { action } from '@ember/object'; /** * @module InfoTableItemArray @@ -30,15 +29,17 @@ import { isWildcardString } from 'vault/helpers/is-wildcard-string'; * @param {boolean} [isLink] - Indicates if the item should contain a link-to component. Only setup for arrays, but this could be changed if needed. * @param {string || array} [rootRoute="vault.cluster.secrets.backend.list-root"] - Tells what route the link should go to when selecting "view all". If the route requires more than one dynamic param, insert an array. * @param {string || array} [itemRoute=vault.cluster.secrets.backend.show] - Tells what route the link should go to when selecting the individual item. If the route requires more than one dynamic param, insert an array. - * @param {string} [modelType] - Tells which model you want data for the allOptions to be returned from. Used in conjunction with the the isLink. + * @param {string} [modelType] - Tells which model you want to query and set allOptions. Used in conjunction with the the isLink. * @param {string} [wildcardLabel] - when you want the component to return a count on the model for options returned when using a wildcard you must provide a label of the count e.g. role. Should be singular. * @param {string} [backend] - To specify which backend to point the link to. - * @param {boolean} [doNotTruncate=false] - Determines whether to show the View all "roles" link. + * @param {boolean} [doNotTruncate=false] - Determines whether to show the View all "roles" link. Otherwise uses the ReadMore component's "See More" toggle + * @param {boolean} [renderItemName=false] - If true renders the item name instead of its id */ export default class InfoTableItemArray extends Component { - @tracked allOptions = null; - @tracked wildcardInDisplayArray = false; @service store; + @tracked allOptions = null; + @tracked itemNameById; // object is only created if renderItemName=true + @tracked fetchComplete = false; get rootRoute() { return this.args.rootRoute || 'vault.cluster.secrets.backend.list-root'; @@ -62,29 +63,26 @@ export default class InfoTableItemArray extends Component { return displayArray; } - async checkWildcardInArray() { - if (!this.args.displayArray) { - return; - } - let filteredArray = await this.args.displayArray.filter((item) => isWildcardString([item])); - this.wildcardInDisplayArray = filteredArray.length > 0 ? true : false; - } - - @task *fetchOptions() { + @action async fetchOptions() { if (this.args.isLink && this.args.modelType) { - let queryOptions = {}; + let queryOptions = this.args.backend ? { backend: this.args.backend } : {}; - if (this.args.backend) { - queryOptions = { backend: this.args.backend }; + let modelRecords = await this.store.query(this.args.modelType, queryOptions).catch((err) => { + if (err.httpStatus === 404) { + return []; + } else { + return null; + } + }); + + this.allOptions = modelRecords ? modelRecords.mapBy('id') : null; + if (this.args.renderItemName && modelRecords) { + modelRecords.forEach(({ id, name }) => { + // create key/value pair { item-id: item-name } for each record + this.itemNameById = { ...this.itemNameById, [id]: name }; + }); } - - let options = yield this.store.query(this.args.modelType, queryOptions); - this.formatOptions(options); } - this.checkWildcardInArray(); - } - - formatOptions(options) { - this.allOptions = options.mapBy('id'); + this.fetchComplete = true; } } diff --git a/ui/lib/core/addon/components/info-table-row.hbs b/ui/lib/core/addon/components/info-table-row.hbs index 6e8d5e8154..0ad903dfce 100644 --- a/ui/lib/core/addon/components/info-table-row.hbs +++ b/ui/lib/core/addon/components/info-table-row.hbs @@ -74,6 +74,7 @@ @rootRoute={{@rootRoute}} @itemRoute={{@itemRoute}} @doNotTruncate={{@doNotTruncate}} + @renderItemName={{@renderItemName}} /> {{else}} {{#if @tooltipText}} diff --git a/ui/lib/core/addon/components/search-select.js b/ui/lib/core/addon/components/search-select.js index a0cd987a71..82a2c23e80 100644 --- a/ui/lib/core/addon/components/search-select.js +++ b/ui/lib/core/addon/components/search-select.js @@ -6,6 +6,7 @@ import { singularize } from 'ember-inflector'; import { resolve } from 'rsvp'; import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-utils'; import layout from '../templates/components/search-select'; +import { isWildcardString } from 'vault/helpers/is-wildcard-string'; /** * @module SearchSelect @@ -87,8 +88,9 @@ export default Component.extend({ this.set('allOptions', allOptions); // used by filter-wildcard helper let formattedOptions = this.selectedOptions.map((option) => { let matchingOption = options.findBy(this.idKey, option); - // an undefined matchingOption means a selectedOption, on edit, didn't match a model returned from the query and therefore doesn't exist - let addTooltip = matchingOption ? false : true; // add tooltip to let user know the selection can be discarded + // an undefined matchingOption means a selectedOption, on edit, didn't match a model returned from the query + // this means it is a wildcard string or no longer exists + let addTooltip = matchingOption || isWildcardString([option]) ? false : true; // add tooltip to let user know the selection can be discarded options.removeObject(matchingOption); return { id: option, diff --git a/ui/lib/core/addon/templates/components/search-select.hbs b/ui/lib/core/addon/templates/components/search-select.hbs index 00cab345eb..8948212e39 100644 --- a/ui/lib/core/addon/templates/components/search-select.hbs +++ b/ui/lib/core/addon/templates/components/search-select.hbs @@ -76,7 +76,7 @@ The item with this {{to-label this.idKey}} - no longer exists and can safely be removed. + no longer exists. {{/if}}