mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 09:42:25 +00:00
UI: Update flight icons (#24823)
This commit is contained in:
3
changelog/24823.txt
Normal file
3
changelog/24823.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:change
|
||||
ui: Update icons to use Flight icons where available.
|
||||
```
|
||||
@@ -16,7 +16,7 @@
|
||||
@disabled={{if type.requiredFeature (not (has-feature type.requiredFeature)) false}}
|
||||
data-test-mount-type={{type.type}}
|
||||
>
|
||||
<Icon @name={{or type.glyph type.type}} @size="24" class="has-bottom-margin-xs" />
|
||||
<Icon @name={{type.glyph}} @size="24" class="has-bottom-margin-xs" />
|
||||
<Hds::Text::Body @tag="h3" @size="300">
|
||||
{{type.displayName}}
|
||||
</Hds::Text::Body>
|
||||
|
||||
@@ -16,7 +16,12 @@ export default class MfaMethodCreateController extends Controller {
|
||||
@service router;
|
||||
|
||||
queryParams = ['type'];
|
||||
methodNames = ['TOTP', 'Duo', 'Okta', 'PingID'];
|
||||
methods = [
|
||||
{ name: 'TOTP', icon: 'history' },
|
||||
{ name: 'Duo', icon: 'duo' },
|
||||
{ name: 'Okta', icon: 'okta-color' },
|
||||
{ name: 'PingID', icon: 'pingid' },
|
||||
];
|
||||
|
||||
@tracked type = null;
|
||||
@tracked method = null;
|
||||
|
||||
@@ -28,6 +28,7 @@ const MOUNTABLE_AUTH_METHODS = [
|
||||
value: 'approle',
|
||||
type: 'approle',
|
||||
category: 'generic',
|
||||
glyph: 'cpu',
|
||||
},
|
||||
{
|
||||
displayName: 'AWS',
|
||||
@@ -61,14 +62,14 @@ const MOUNTABLE_AUTH_METHODS = [
|
||||
displayName: 'JWT',
|
||||
value: 'jwt',
|
||||
type: 'jwt',
|
||||
glyph: 'auth',
|
||||
glyph: 'jwt',
|
||||
category: 'generic',
|
||||
},
|
||||
{
|
||||
displayName: 'OIDC',
|
||||
value: 'oidc',
|
||||
type: 'oidc',
|
||||
glyph: 'auth',
|
||||
glyph: 'openid-color',
|
||||
category: 'generic',
|
||||
},
|
||||
{
|
||||
@@ -82,7 +83,7 @@ const MOUNTABLE_AUTH_METHODS = [
|
||||
displayName: 'LDAP',
|
||||
value: 'ldap',
|
||||
type: 'ldap',
|
||||
glyph: 'auth',
|
||||
glyph: 'folder-users',
|
||||
category: 'infra',
|
||||
},
|
||||
{
|
||||
@@ -96,7 +97,7 @@ const MOUNTABLE_AUTH_METHODS = [
|
||||
displayName: 'RADIUS',
|
||||
value: 'radius',
|
||||
type: 'radius',
|
||||
glyph: 'auth',
|
||||
glyph: 'mainframe',
|
||||
category: 'infra',
|
||||
},
|
||||
{
|
||||
@@ -104,6 +105,7 @@ const MOUNTABLE_AUTH_METHODS = [
|
||||
value: 'cert',
|
||||
type: 'cert',
|
||||
category: 'generic',
|
||||
glyph: 'certificate',
|
||||
},
|
||||
{
|
||||
displayName: 'Username & Password',
|
||||
|
||||
@@ -19,6 +19,7 @@ const ENTERPRISE_SECRET_ENGINES = [
|
||||
type: 'transform',
|
||||
category: 'generic',
|
||||
requiredFeature: 'Transform Secrets Engine',
|
||||
glyph: 'transform-data',
|
||||
},
|
||||
{
|
||||
displayName: 'Key Management',
|
||||
@@ -59,6 +60,7 @@ const MOUNTABLE_SECRET_ENGINES = [
|
||||
displayName: 'Databases',
|
||||
type: 'database',
|
||||
category: 'infra',
|
||||
glyph: 'database',
|
||||
},
|
||||
{
|
||||
displayName: 'Google Cloud',
|
||||
@@ -95,6 +97,7 @@ const MOUNTABLE_SECRET_ENGINES = [
|
||||
{
|
||||
displayName: 'RabbitMQ',
|
||||
type: 'rabbitmq',
|
||||
glyph: 'rabbitmq-color',
|
||||
category: 'infra',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ import fieldToAttrs, { expandAttributeMeta } from 'vault/utils/field-to-attrs';
|
||||
import apiPath from 'vault/utils/api-path';
|
||||
import attachCapabilities from 'vault/lib/attach-capabilities';
|
||||
import { withModelValidations } from 'vault/decorators/model-validations';
|
||||
import { allMethods } from 'vault/helpers/mountable-auth-methods';
|
||||
|
||||
const validations = {
|
||||
path: [
|
||||
@@ -42,6 +43,11 @@ const ModelExport = AuthMethodModel.extend({
|
||||
methodType: computed('type', function () {
|
||||
return this.type.replace(/^ns_/, '');
|
||||
}),
|
||||
icon: computed('methodType', function () {
|
||||
const authMethods = allMethods().find((backend) => backend.type === this.methodType);
|
||||
|
||||
return authMethods?.glyph || 'users';
|
||||
}),
|
||||
description: attr('string', {
|
||||
editType: 'textarea',
|
||||
}),
|
||||
|
||||
@@ -168,6 +168,15 @@ export default class MfaMethod extends Model {
|
||||
return this.type === 'totp' ? this.type.toUpperCase() : capitalize(this.type);
|
||||
}
|
||||
|
||||
get icon() {
|
||||
switch (this.type) {
|
||||
case 'totp':
|
||||
return 'history';
|
||||
default:
|
||||
return this.type;
|
||||
}
|
||||
}
|
||||
|
||||
get formFields() {
|
||||
return [...METHOD_PROPS.common, ...METHOD_PROPS[this.type]];
|
||||
}
|
||||
|
||||
@@ -15,7 +15,13 @@ const DOMAIN_STRINGS = {
|
||||
'auth0.com': 'Auth0',
|
||||
};
|
||||
|
||||
const PROVIDER_WITH_LOGO = ['GitHub', 'GitLab', 'Google', 'Okta', 'Auth0'];
|
||||
const PROVIDER_WITH_LOGO = {
|
||||
GitHub: 'github',
|
||||
GitLab: 'gitlab',
|
||||
Google: 'google',
|
||||
Okta: 'okta',
|
||||
Auth0: 'auth0',
|
||||
};
|
||||
|
||||
export { DOMAIN_STRINGS, PROVIDER_WITH_LOGO };
|
||||
|
||||
@@ -30,6 +36,6 @@ export default class RoleJwtModel extends Model {
|
||||
|
||||
get providerIcon() {
|
||||
const { providerName } = this;
|
||||
return PROVIDER_WITH_LOGO.includes(providerName) ? providerName.toLowerCase() : null;
|
||||
return PROVIDER_WITH_LOGO[providerName] || null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,14 +123,9 @@ export default class SecretEngineModel extends Model {
|
||||
}
|
||||
|
||||
get icon() {
|
||||
const defaultIcon = this.engineType || 'secrets';
|
||||
return (
|
||||
{
|
||||
keymgmt: 'key',
|
||||
kmip: 'secrets',
|
||||
ldap: 'folder-users',
|
||||
}[this.engineType] || defaultIcon
|
||||
);
|
||||
const engineData = allEngines().find((engine) => engine.type === this.engineType);
|
||||
|
||||
return engineData?.glyph || 'lock';
|
||||
}
|
||||
|
||||
get engineType() {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left">
|
||||
<div class="is-flex-row">
|
||||
<Icon @size="24" @name={{@model.type}} class="has-text-grey" data-test-mfa-method-list-icon={{@model.type}} />
|
||||
<Icon @size="24" @name={{@model.icon}} class="has-text-grey" data-test-mfa-method-list-icon={{@model.type}} />
|
||||
<div>
|
||||
<span class="has-text-weight-semibold has-text-black">
|
||||
{{@model.name}}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<h1 class="title is-3 title-with-icon" data-test-mount-form-header="true">
|
||||
{{#if this.showEnable}}
|
||||
{{#let (find-by "type" @mountModel.type @mountTypes) as |typeInfo|}}
|
||||
<Icon @name={{or typeInfo.glyph typeInfo.type}} @size="24" class="has-text-grey-light" />
|
||||
<Icon @name={{typeInfo.glyph}} @size="24" class="has-text-grey-light" />
|
||||
{{#if (eq @mountType "secret")}}
|
||||
{{concat "Enable " typeInfo.displayName " Secrets Engine"}}
|
||||
{{else}}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Vault Web UI" @glyph="tour" @selectProgress={{this.selectProgress}}>
|
||||
<WizardContent @headerText="Vault Web UI" @glyph="guide" @selectProgress={{this.selectProgress}}>
|
||||
<h2 class="title is-6">
|
||||
Choosing where to go
|
||||
</h2>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Authentication" @glyph="tour">
|
||||
<WizardContent @headerText="Authentication" @glyph="guide">
|
||||
<WizardSection @headerText="Authenticate to Vault" @docText="Learn: Initialization" @docPath="/docs/concepts/tokens.html">
|
||||
<p>
|
||||
Vault is unsealed, but we still need to authenticate using the Initial Root Token that was generated. We recommend
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Initialization" @glyph="tour">
|
||||
<WizardContent @headerText="Initialization" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Saving your keys"
|
||||
@docText="Learn: Initialization"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Initialization" @glyph="tour">
|
||||
<WizardContent @headerText="Initialization" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Setting up your root keys"
|
||||
@docText="Learn: Initialization"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Initialization" @glyph="tour">
|
||||
<WizardContent @headerText="Initialization" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Unsealing your vault"
|
||||
@docText="Learn: Initialization"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText={{capitalize this.currentMachine}} @glyph="tour">
|
||||
<WizardContent @headerText={{capitalize this.currentMachine}} @glyph="guide">
|
||||
{{component
|
||||
this.stepComponent
|
||||
mountSubtype=this.mountSubtype
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Policies" @glyph="tour">
|
||||
<WizardContent @headerText="Policies" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Creating a policy"
|
||||
@docText="Docs: Policies"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Policies" @glyph="tour">
|
||||
<WizardContent @headerText="Policies" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Deleting your policy"
|
||||
@docText="Docs: Policies"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Policies" @glyph="tour">
|
||||
<WizardContent @headerText="Policies" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Your new policy"
|
||||
@docText="Docs: Policies"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Policies" @glyph="tour">
|
||||
<WizardContent @headerText="Policies" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Choosing a policy type"
|
||||
@docText="Docs: Policies"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Policies" @glyph="tour">
|
||||
<WizardContent @headerText="Policies" @glyph="guide">
|
||||
<WizardSection @headerText="Other kinds of policies" @docText="Docs: Policies" @docPath="/docs/concepts/policies.html">
|
||||
<p>
|
||||
Good! Now you're ready to go writing your own policies. We only explored ACL policies, but there are two other types of
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Replication" @glyph="tour">
|
||||
<WizardContent @headerText="Replication" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Setting up Replication"
|
||||
@docText="Docs: Replication"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Tools" @glyph="tour">
|
||||
<WizardContent @headerText="Tools" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Information about your data"
|
||||
@docText="API: Lookup Data"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Tools" @glyph="tour">
|
||||
<WizardContent @headerText="Tools" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Lookup wrapped data"
|
||||
@docText="API: Lookup Data"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Tools" @glyph="tour">
|
||||
<WizardContent @headerText="Tools" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Rewrapping your data"
|
||||
@docText="API: Rewrap Data"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Tools" @glyph="tour">
|
||||
<WizardContent @headerText="Tools" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Your rewrapped data"
|
||||
@docText="API: Rewrap Data"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Tools" @glyph="tour">
|
||||
<WizardContent @headerText="Tools" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Unwrapping your data"
|
||||
@docText="API: Unwrap Data"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Tools" @glyph="tour">
|
||||
<WizardContent @headerText="Tools" @glyph="guide">
|
||||
<WizardSection @headerText="Your unwrapped data" @docText="API: Unwrap Data" @docPath="/api/system/wrapping-unwrap.html">
|
||||
<p>
|
||||
Here you can see that your data survived intact. These tools are mostly handy for applications to use, but if you ever
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Tools" @glyph="tour">
|
||||
<WizardContent @headerText="Tools" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Wrapping data"
|
||||
@docText="API: Wrap Data"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
~}}
|
||||
|
||||
{{! template-lint-disable quotes }}
|
||||
<WizardContent @headerText="Tools" @glyph="tour">
|
||||
<WizardContent @headerText="Tools" @glyph="guide">
|
||||
<WizardSection
|
||||
@headerText="Copying your wrapped token"
|
||||
@docText="API: Wrap Data"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Thanks for taking the tour!" @glyph="tour" @class="collapsed">
|
||||
<WizardContent @headerText="Thanks for taking the tour!" @glyph="guide" @class="collapsed">
|
||||
<p>
|
||||
We hope you enjoyed using Vault. You can get back to the guide in the user menu in the upper right.
|
||||
</p>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Welcome to Vault" @glyph="tour" @class="collapsed" @hidePopup={{true}}>
|
||||
<WizardContent @headerText="Welcome to Vault" @glyph="guide" @class="collapsed" @hidePopup={{true}}>
|
||||
<Hds::Button @text="Close" @icon="x" @isIconOnly={{true}} @color="secondary" {{on "click" (action @onDismiss)}} />
|
||||
<p>Want a tour? Our helpful guide will introduce you to the Vault Web UI.</p>
|
||||
<div class="box wizard-divider-box">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
SPDX-License-Identifier: BUSL-1.1
|
||||
~}}
|
||||
|
||||
<WizardContent @headerText="Vault Web UI Guide" @glyph="tour" @class="collapsed" @hidePopup={{true}}>
|
||||
<WizardContent @headerText="Vault Web UI Guide" @glyph="guide" @class="collapsed" @hidePopup={{true}}>
|
||||
<Hds::Button @text="Close" @icon="x" @isIconOnly={{true}} @color="secondary" {{on "click" (action @onDismiss)}} />
|
||||
<p>Feel free to explore Vault. Click below to get back to the guide or close this window.</p>
|
||||
<div class="box wizard-divider-box">
|
||||
|
||||
@@ -56,14 +56,7 @@
|
||||
<div class="level-left">
|
||||
<div>
|
||||
<Hds::TooltipButton @text={{method.methodType}} aria-label="Type of auth mount">
|
||||
<Icon
|
||||
@name={{if
|
||||
(or (find-by "type" method.methodType (mountable-auth-methods)) (eq method.methodType "token"))
|
||||
method.methodType
|
||||
"auth"
|
||||
}}
|
||||
class="has-text-grey-light"
|
||||
/>
|
||||
<Icon @name={{method.icon}} class="has-text-grey-light" />
|
||||
</Hds::TooltipButton>
|
||||
<span data-test-path data-test-id={{method.id}} class="has-text-weight-semibold has-text-black">
|
||||
{{method.path}}
|
||||
|
||||
@@ -51,22 +51,21 @@
|
||||
<DocLink @path="/vault/api-docs/secret/identity/mfa">Learn more.</DocLink>
|
||||
</p>
|
||||
<div class="is-flex-row has-top-margin-xl">
|
||||
{{#each this.methodNames as |methodName|}}
|
||||
{{#each this.methods as |method|}}
|
||||
<RadioCard
|
||||
@value={{lowercase methodName}}
|
||||
@value={{lowercase method.name}}
|
||||
@groupValue={{this.type}}
|
||||
@onChange={{this.onTypeSelect}}
|
||||
data-test-radio-card={{lowercase methodName}}
|
||||
data-test-radio-card={{lowercase method.name}}
|
||||
>
|
||||
<div class="radio-card-row is-flex-v-centered">
|
||||
<div>
|
||||
<Icon
|
||||
@name={{if (eq methodName "Okta") "okta-color" (lowercase methodName)}}
|
||||
@size="24"
|
||||
class={{if (eq methodName "TOTP") "has-text-grey"}}
|
||||
/>
|
||||
<p class="has-text-weight-semibold has-text-center {{if (eq methodName 'Okta') 'has-top-margin-xs'}}">
|
||||
{{methodName}}
|
||||
<Icon @name={{method.icon}} @size="24" class={{if (eq method.name "TOTP") "has-text-grey"}} />
|
||||
<p
|
||||
class="has-text-weight-semibold has-text-center
|
||||
{{if (or (eq method.name 'Okta') (eq method.name 'TOTP')) 'has-top-margin-xs'}}"
|
||||
>
|
||||
{{method.name}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</p.top>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
<Icon @size="24" @name={{this.model.method.type}} />
|
||||
<Icon @size="24" @name={{this.model.method.icon}} />
|
||||
{{this.model.method.name}}
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
|
||||
@@ -23,7 +23,7 @@ const appConfig = {
|
||||
//optimize: false,
|
||||
//paths: [],
|
||||
optimizer: {},
|
||||
sourceDirs: ['node_modules/@hashicorp/structure-icons/dist', 'public'],
|
||||
sourceDirs: ['public'],
|
||||
rootURL: '/ui/',
|
||||
},
|
||||
fingerprint: {
|
||||
@@ -91,8 +91,5 @@ module.exports = function (defaults) {
|
||||
|
||||
app.import('app/styles/bulma/bulma-radio-checkbox.css');
|
||||
|
||||
app.import('node_modules/@hashicorp/structure-icons/dist/loading.css');
|
||||
app.import('node_modules/@hashicorp/structure-icons/dist/run.css');
|
||||
|
||||
return app.toTree();
|
||||
};
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
~}}
|
||||
|
||||
{{#if this.isFlightIcon}}
|
||||
<FlightIcon @name={{this.name}} @size={{this.size}} @stretched={{@stretched}} ...attributes />
|
||||
<FlightIcon @name={{@name}} @size={{this.size}} @stretched={{@stretched}} ...attributes />
|
||||
{{else}}
|
||||
<span class="hs-icon {{this.hsIconClass}}" aria-hidden="true" ...attributes>
|
||||
{{svg-jar this.name}}
|
||||
{{svg-jar @name}}
|
||||
</span>
|
||||
{{/if}}
|
||||
@@ -10,15 +10,16 @@ const flightIconNames = flightIconMap.assets.mapBy('iconName').uniq();
|
||||
|
||||
/**
|
||||
* @module Icon
|
||||
* `Icon` components are glyphs used to indicate important information.
|
||||
* `Icon` components are used to display an icon.
|
||||
*
|
||||
* Flight icon documentation at https://flight-hashicorp.vercel.app/
|
||||
* Flight icon documentation at https://helios.hashicorp.design/icons/usage-guidelines?tab=code#how-to-use-icons
|
||||
* Flight icon library at https://helios.hashicorp.design/icons/library
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* <Icon @name="cancel-square-outline" @size="24" />
|
||||
* <Icon @name="x-square" @size="24" />
|
||||
* ```
|
||||
* @param {string} name=null - The name of the SVG to render inline.
|
||||
* @param {string} name - The name of the SVG to render inline. Required.
|
||||
* @param {string} [size=16] - size for flight icon, can be 16 or 24
|
||||
*
|
||||
*/
|
||||
@@ -27,19 +28,16 @@ export default class Icon extends Component {
|
||||
constructor(owner, args) {
|
||||
super(owner, args);
|
||||
assert('Icon component size argument must be either "16" or "24"', ['16', '24'].includes(this.size));
|
||||
assert('Icon name argument must be provided', this.args.name);
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this.args.size || '16';
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.args.name || null;
|
||||
}
|
||||
|
||||
// favor flight icon set and fall back to structure icons if not found
|
||||
get isFlightIcon() {
|
||||
return this.name ? flightIconNames.includes(this.name) : false;
|
||||
return this.args.name ? flightIconNames.includes(this.args.name) : false;
|
||||
}
|
||||
|
||||
get hsIconClass() {
|
||||
|
||||
@@ -35,10 +35,13 @@ export default Component.extend({
|
||||
|
||||
actions: {
|
||||
iconClass(model, field) {
|
||||
return this.trueOrFalseString(model, field, 'icon-true', 'icon-false');
|
||||
return this.trueOrFalseString(model, field, 'hds-foreground-success', 'hds-foreground-faint');
|
||||
},
|
||||
iconGlyph(model, field) {
|
||||
return this.trueOrFalseString(model, field, 'check-circle-outline', 'cancel-square-outline');
|
||||
return this.trueOrFalseString(model, field, 'check-circle', 'x-square');
|
||||
},
|
||||
operationEnabled(model, field) {
|
||||
return this.trueOrFalseString(model, field, 'Enabled', 'Disabled');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</p.top>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
<Icon @name="secrets" @size="24" class="has-text-grey-light" />
|
||||
<Icon @name="lock" @size="24" class="has-text-grey-light" />
|
||||
{{this.secretMountPath.currentPath}}
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div>
|
||||
{{#each fieldsInGroup as |field|}}
|
||||
<Icon
|
||||
aria-hidden="true"
|
||||
aria-label={{compute (action "operationEnabled") this.model field}}
|
||||
class={{compute (action "iconClass") this.model field}}
|
||||
@name={{compute (action "iconGlyph") this.model field}}
|
||||
/>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</p.top>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
<Icon @name="secrets" @size="24" class="has-text-grey-light" />
|
||||
<Icon @name="lock" @size="24" class="has-text-grey-light" />
|
||||
Configure KMIP Secrets Engine
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3" data-test-header-title>
|
||||
{{#if @mountName}}
|
||||
<Icon @name="kv" @size="24" class="has-text-grey-light" />
|
||||
<Icon @name="key-values" @size="24" class="has-text-grey-light" />
|
||||
{{@mountName}}
|
||||
<span class="tag">version 2</span>
|
||||
{{else}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</p.top>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
<Icon @name="pki" @size="24" class="has-text-grey-light" />
|
||||
<Icon @name="certificate" @size="24" class="has-text-grey-light" />
|
||||
Configure Automatic Tidy
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</p.top>
|
||||
<p.levelLeft>
|
||||
<h1 class="title is-3">
|
||||
<Icon @name="pki" @size="24" class="has-text-grey-light" />
|
||||
<Icon @name="certificate" @size="24" class="has-text-grey-light" />
|
||||
Manual Tidy
|
||||
</h1>
|
||||
</p.levelLeft>
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
"@ember/test-waiters": "^3.0.0",
|
||||
"@glimmer/component": "^1.1.2",
|
||||
"@glimmer/tracking": "^1.1.2",
|
||||
"@hashicorp/structure-icons": "^1.3.0",
|
||||
"@icholy/duration": "^5.1.0",
|
||||
"@tsconfig/ember": "^1.0.1",
|
||||
"@types/ember": "^4.0.2",
|
||||
@@ -251,8 +250,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@hashicorp/design-system-components": "^3.3.0",
|
||||
"@hashicorp/ember-flight-icons": "^4.0.4",
|
||||
"@hashicorp/design-system-components": "^3.4.0",
|
||||
"@hashicorp/ember-flight-icons": "^4.0.5",
|
||||
"handlebars": "4.7.7",
|
||||
"highlight.js": "^10.4.1",
|
||||
"node-notifier": "^8.0.1",
|
||||
|
||||
@@ -40,11 +40,7 @@ module('Integration | Component | confirm-action', function (hooks) {
|
||||
'hds-modal hds-modal--size-small hds-modal--color-critical has-text-left',
|
||||
'renders critical modal color by default'
|
||||
);
|
||||
assert.strictEqual(
|
||||
find(SELECTORS.confirm).className,
|
||||
'hds-button hds-button--size-medium hds-button--color-critical',
|
||||
'renders critical confirm button'
|
||||
);
|
||||
assert.dom(SELECTORS.confirm).hasClass('hds-button--color-critical', 'renders critical confirm button');
|
||||
assert.dom(SELECTORS.title).hasText('Are you sure?', 'renders default title');
|
||||
assert
|
||||
.dom(SELECTORS.message)
|
||||
@@ -142,23 +138,10 @@ module('Integration | Component | confirm-action', function (hooks) {
|
||||
/>
|
||||
`);
|
||||
|
||||
// hasClass assertion wasn't working so this is the workaround
|
||||
assert.strictEqual(
|
||||
find(SELECTORS.modalToggle).className,
|
||||
'hds-button hds-button--size-medium hds-button--color-secondary',
|
||||
'renders @buttonColor classes'
|
||||
);
|
||||
assert.dom(SELECTORS.modalToggle).hasClass('hds-button--color-secondary', 'renders @buttonColor classes');
|
||||
await click(SELECTORS.modalToggle);
|
||||
assert.strictEqual(
|
||||
find('#confirm-action-modal').className,
|
||||
'hds-modal hds-modal--size-small hds-modal--color-warning has-text-left',
|
||||
'renders warning modal'
|
||||
);
|
||||
assert.strictEqual(
|
||||
find(SELECTORS.confirm).className,
|
||||
'hds-button hds-button--size-medium hds-button--color-primary',
|
||||
'renders primary confirm button'
|
||||
);
|
||||
assert.dom('#confirm-action-modal').hasClass('hds-modal--color-warning', 'renders warning modal');
|
||||
assert.dom(SELECTORS.confirm).hasClass('hds-button--color-primary', 'renders primary confirm button');
|
||||
assert.dom(SELECTORS.title).hasText('Do this?', 'renders passed title');
|
||||
assert.dom(SELECTORS.message).hasText('Are you really, really sure?', 'renders passed body text');
|
||||
assert.dom(SELECTORS.confirm).hasText('Confirm');
|
||||
|
||||
@@ -134,7 +134,7 @@ module('Integration | Component | dashboard/secrets-engines-card', function (hoo
|
||||
test('it adds disabled css styling to unsupported secret engines', async function (assert) {
|
||||
await this.renderComponent();
|
||||
assert.dom('[data-test-secrets-engines-row="nomad"] [data-test-view]').doesNotExist();
|
||||
assert.dom('[data-test-icon="nomad"]').hasClass('has-text-grey');
|
||||
assert.dom('[data-test-secrets-engines-row="nomad"] [data-test-secret-path]').hasClass('has-text-grey');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,24 +13,28 @@ module('Integration | Component | icon', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
await render(hbs`<Icon class="i-con" />`);
|
||||
await render(hbs`<Icon @name="vault-color" class="i-con" />`);
|
||||
assert.dom('.i-con').exists('renders');
|
||||
|
||||
// non-flight icon
|
||||
await render(hbs`<Icon @name="vault-logo" />`);
|
||||
assert.dom('.vault-logo').exists('inlines the SVG');
|
||||
assert.dom('.hs-icon').hasClass('hs-icon-l', 'Default hs class applied');
|
||||
|
||||
await render(hbs`<Icon class="ah" aria-hidden="true" />`);
|
||||
await render(hbs`<Icon @name="vault-color" class="ah" aria-hidden="true" />`);
|
||||
assert.dom('.ah').hasAttribute('aria-hidden', 'true', 'renders aria-hidden');
|
||||
|
||||
await render(hbs`<Icon class="al" aria-label="Testing" />`);
|
||||
await render(hbs`<Icon @name="vault-color" class="al" aria-label="Testing" />`);
|
||||
assert.dom('.al').hasAttribute('aria-label', 'Testing', 'renders aria-label');
|
||||
|
||||
// non-flight icon
|
||||
await render(hbs`<Icon @name="vault-logo" @size="24"/>`);
|
||||
assert.dom('.hs-icon').hasClass('hs-icon-xlm', 'adds the larger size class');
|
||||
});
|
||||
|
||||
test('it throws error when size attribute is invalid', async function (assert) {
|
||||
const promise = waitForError();
|
||||
render(hbs`<Icon @name="vault-logo" @size="12"/>`);
|
||||
render(hbs`<Icon @name="vault-color" @size="12"/>`);
|
||||
const err = await promise;
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
@@ -39,8 +43,19 @@ module('Integration | Component | icon', function (hooks) {
|
||||
);
|
||||
});
|
||||
|
||||
test('it throws error when name attribute is not passed', async function (assert) {
|
||||
const promise = waitForError();
|
||||
render(hbs`<Icon />`);
|
||||
const err = await promise;
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
'Assertion Failed: Icon name argument must be provided',
|
||||
'Error is thrown when name not provided'
|
||||
);
|
||||
});
|
||||
|
||||
test('it should render FlightIcon', async function (assert) {
|
||||
assert.expect(4);
|
||||
assert.expect(3);
|
||||
|
||||
await render(hbs`<Icon @name="x" />`);
|
||||
assert.dom('.flight-icon').exists('FlightIcon renders when provided name of icon in set');
|
||||
@@ -48,14 +63,5 @@ module('Integration | Component | icon', function (hooks) {
|
||||
|
||||
await render(hbs`<Icon @name="x" @size="24" />`);
|
||||
assert.dom('.flight-icon').hasAttribute('width', '24', 'Size applied to svg');
|
||||
|
||||
const promise = waitForError();
|
||||
render(hbs`<Icon @name="x" @size="12"/>`);
|
||||
const err = await promise;
|
||||
assert.strictEqual(
|
||||
err.message,
|
||||
'Assertion Failed: Icon component size argument must be either "16" or "24"',
|
||||
'Error is thrown when supported size is not provided'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ module('Integration | Component | kubernetes | Page::Configuration', function (h
|
||||
|
||||
test('it should render tab page header, config cta and mount config', async function (assert) {
|
||||
await this.renderComponent();
|
||||
assert.dom('.title svg').hasClass('flight-icon-kubernetes', 'Kubernetes icon renders in title');
|
||||
assert.dom('.title svg').hasClass('flight-icon-kubernetes-color', 'Kubernetes icon renders in title');
|
||||
assert.dom('.title').hasText('kubernetes-test', 'Mount path renders in title');
|
||||
assert
|
||||
.dom('[data-test-toolbar-config-action]')
|
||||
|
||||
@@ -50,7 +50,7 @@ module('Integration | Component | kubernetes | Page::Roles', function (hooks) {
|
||||
test('it should render tab page header and config cta', async function (assert) {
|
||||
this.promptConfig = true;
|
||||
await this.renderComponent();
|
||||
assert.dom('.title svg').hasClass('flight-icon-kubernetes', 'Kubernetes icon renders in title');
|
||||
assert.dom('.title svg').hasClass('flight-icon-kubernetes-color', 'Kubernetes icon renders in title');
|
||||
assert.dom('.title').hasText('kubernetes-test', 'Mount path renders in title');
|
||||
assert
|
||||
.dom('[data-test-toolbar-roles-action]')
|
||||
|
||||
@@ -47,7 +47,7 @@ module('Integration | Component | kubernetes | TabPageHeader', function (hooks)
|
||||
});
|
||||
assert
|
||||
.dom('[data-test-header-title] svg')
|
||||
.hasClass('flight-icon-kubernetes', 'Correct icon renders in title');
|
||||
.hasClass('flight-icon-kubernetes-color', 'Correct icon renders in title');
|
||||
assert.dom('[data-test-header-title]').hasText(this.mount, 'Mount path renders in title');
|
||||
});
|
||||
|
||||
|
||||
@@ -71,7 +71,9 @@ module('Integration | Component | kv | kv-page-header', function (hooks) {
|
||||
assert
|
||||
.dom('[data-test-header-title]')
|
||||
.hasText(`${this.backend} version 2`, 'Mount path and version tag render for title.');
|
||||
assert.dom('[data-test-header-title] span').hasClass('hs-icon', 'An icon renders next to title.');
|
||||
assert
|
||||
.dom('[data-test-header-title] [data-test-icon="key-values"]')
|
||||
.exists('An icon renders next to title.');
|
||||
});
|
||||
|
||||
test('it renders tabs', async function (assert) {
|
||||
|
||||
@@ -33,7 +33,9 @@ module('Integration | Component | pki page header test', function (hooks) {
|
||||
await render(hbs`<PkiPageHeader @backend={{this.model}} />`, {
|
||||
owner: this.engine,
|
||||
});
|
||||
assert.dom('[data-test-header-title] span').hasClass('hs-icon', 'Correct icon renders in title');
|
||||
assert
|
||||
.dom('[data-test-header-title] [data-test-icon="certificate"]')
|
||||
.exists('Correct icon renders in title');
|
||||
assert.dom('[data-test-header-title]').hasText(this.mount, 'Mount path renders in title');
|
||||
});
|
||||
|
||||
|
||||
@@ -79,11 +79,11 @@ module('Integration | Component | replication-secondary-card', function (hooks)
|
||||
assert.dom('[data-test-empty-state]').exists('shows empty state');
|
||||
});
|
||||
|
||||
test('it renders tooltip with check-circle-outline when state is stream-wals', async function (assert) {
|
||||
test('it renders tooltip with check-circle when state is stream-wals', async function (assert) {
|
||||
await render(
|
||||
hbs`<ReplicationSecondaryCard @replicationDetails={{this.replicationDetails}} @title={{this.title}} />`
|
||||
);
|
||||
assert.dom('[data-test-glyph]').hasClass('has-text-success', `shows success icon`);
|
||||
assert.dom('[data-test-icon="check-circle"]').hasClass('has-text-success', `shows success icon`);
|
||||
});
|
||||
|
||||
test('it renders hasErrorMessage when state is idle', async function (assert) {
|
||||
|
||||
@@ -37,7 +37,7 @@ module('Unit | Model | role-jwt', function (hooks) {
|
||||
const expectedName = DOMAIN_STRINGS[domain];
|
||||
assert.strictEqual(model.providerName, expectedName, `computes providerName: ${expectedName}`);
|
||||
let expectedIcon = null;
|
||||
if (PROVIDER_WITH_LOGO.includes(expectedName)) {
|
||||
if (PROVIDER_WITH_LOGO[expectedName]) {
|
||||
expectedIcon = expectedName.toLowerCase();
|
||||
}
|
||||
assert.strictEqual(model.providerIcon, expectedIcon, `computes providerIcon: ${domain}`);
|
||||
|
||||
@@ -282,19 +282,19 @@ module('Unit | Model | secret-engine', function (hooks) {
|
||||
});
|
||||
|
||||
module('icon', function () {
|
||||
test('returns secrets if no engineType', function (assert) {
|
||||
test('returns default icon if no engineType', function (assert) {
|
||||
assert.expect(1);
|
||||
const model = this.store.createRecord('secret-engine', {
|
||||
type: '',
|
||||
});
|
||||
assert.strictEqual(model.icon, 'secrets');
|
||||
assert.strictEqual(model.icon, 'lock', 'uses default icon');
|
||||
});
|
||||
test('returns secrets if kmip', function (assert) {
|
||||
test('returns default icon if kmip', function (assert) {
|
||||
assert.expect(1);
|
||||
const model = this.store.createRecord('secret-engine', {
|
||||
type: 'kmip',
|
||||
});
|
||||
assert.strictEqual(model.icon, 'secrets');
|
||||
assert.strictEqual(model.icon, 'lock');
|
||||
});
|
||||
test('returns key if keymgmt', function (assert) {
|
||||
assert.expect(1);
|
||||
@@ -303,12 +303,12 @@ module('Unit | Model | secret-engine', function (hooks) {
|
||||
});
|
||||
assert.strictEqual(model.icon, 'key');
|
||||
});
|
||||
test('returns engineType by default', function (assert) {
|
||||
test('returns default when engine type is not in list of mountable engines', function (assert) {
|
||||
assert.expect(1);
|
||||
const model = this.store.createRecord('secret-engine', {
|
||||
type: 'ducks',
|
||||
});
|
||||
assert.strictEqual(model.icon, 'ducks');
|
||||
assert.strictEqual(model.icon, 'lock');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
40
ui/yarn.lock
40
ui/yarn.lock
@@ -6204,15 +6204,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@hashicorp/design-system-components@npm:^3.3.0":
|
||||
version: 3.3.0
|
||||
resolution: "@hashicorp/design-system-components@npm:3.3.0"
|
||||
"@hashicorp/design-system-components@npm:^3.4.0":
|
||||
version: 3.4.0
|
||||
resolution: "@hashicorp/design-system-components@npm:3.4.0"
|
||||
dependencies:
|
||||
"@ember/render-modifiers": ^2.0.5
|
||||
"@ember/string": ^3.1.1
|
||||
"@ember/test-waiters": ^3.1.0
|
||||
"@hashicorp/design-system-tokens": ^1.9.0
|
||||
"@hashicorp/ember-flight-icons": ^4.0.4
|
||||
"@hashicorp/ember-flight-icons": ^4.0.5
|
||||
dialog-polyfill: ^0.5.6
|
||||
ember-a11y-refocus: ^3.0.2
|
||||
ember-auto-import: ^2.6.3
|
||||
@@ -6230,7 +6230,7 @@ __metadata:
|
||||
prismjs: ^1.29.0
|
||||
sass: ^1.69.5
|
||||
tippy.js: ^6.3.7
|
||||
checksum: 47b3262ec9a31e03110309c80833e1b504baa126851106328b0f5668b7c4f312116e35a9f876aedea80ed71de7a32ee8b530498a947adc8f1fe3db8102a6a227
|
||||
checksum: a206648f67d84849069264a25dd32cd6af0608853018925400958f89c1b590b037408ab38e616c9f8ba9bcc08955c50820c80f5a137164023f30858e472a9008
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6241,30 +6241,23 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@hashicorp/ember-flight-icons@npm:^4.0.4":
|
||||
version: 4.0.4
|
||||
resolution: "@hashicorp/ember-flight-icons@npm:4.0.4"
|
||||
"@hashicorp/ember-flight-icons@npm:^4.0.5":
|
||||
version: 4.0.5
|
||||
resolution: "@hashicorp/ember-flight-icons@npm:4.0.5"
|
||||
dependencies:
|
||||
"@hashicorp/flight-icons": ^2.23.0
|
||||
"@hashicorp/flight-icons": ^2.24.0
|
||||
ember-auto-import: ^2.6.3
|
||||
ember-cli-babel: ^8.2.0
|
||||
ember-cli-htmlbars: ^6.3.0
|
||||
ember-get-config: ^2.1.1
|
||||
checksum: fb0a0f26feb80d1dc663b6fd4e1b6849b8c93e4607f8d790f2fa646cee96b4f3df339951b8adddbf85c39052c72fdf54fc4b910baf2fd64c188d660635c8ba73
|
||||
checksum: 68ed79595fdb7ed2cd9c33260c14f780a358eee9952f228897051f5994daa9e2a366b8f5c9992a2511c9ea0a79a5fefb1ac4e1068707bb8115708f3a91b60af6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@hashicorp/flight-icons@npm:^2.23.0":
|
||||
version: 2.23.0
|
||||
resolution: "@hashicorp/flight-icons@npm:2.23.0"
|
||||
checksum: 0a216a868244bcb3220e13061e5353fd16a0296c1aa9f7444ba2a7148e78532698e7c36a1318573b8ec7fe0283c68c93e7bfbd79a19eb24b2f0006ab78d3b191
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@hashicorp/structure-icons@npm:^1.3.0":
|
||||
version: 1.8.1
|
||||
resolution: "@hashicorp/structure-icons@npm:1.8.1"
|
||||
checksum: 578afba4c884a32c196e87cfa22f66482faf0bd9ccf78591e8d16dedec1eff60e95d90858b0607e7a0136922c551f5649bcfc4d6557b27e2688f2c78434c12cd
|
||||
"@hashicorp/flight-icons@npm:^2.24.0":
|
||||
version: 2.24.0
|
||||
resolution: "@hashicorp/flight-icons@npm:2.24.0"
|
||||
checksum: f226e4e4aed2256680a0fd29bfeac215dc9a224f8ce7b532a64cc30917a2739d34e50e84f70d40b05193e5cb2fbbb603b7870d4a0da09c6335c7f94bfb6e18df
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -27849,9 +27842,8 @@ __metadata:
|
||||
"@ember/test-waiters": ^3.0.0
|
||||
"@glimmer/component": ^1.1.2
|
||||
"@glimmer/tracking": ^1.1.2
|
||||
"@hashicorp/design-system-components": ^3.3.0
|
||||
"@hashicorp/ember-flight-icons": ^4.0.4
|
||||
"@hashicorp/structure-icons": ^1.3.0
|
||||
"@hashicorp/design-system-components": ^3.4.0
|
||||
"@hashicorp/ember-flight-icons": ^4.0.5
|
||||
"@icholy/duration": ^5.1.0
|
||||
"@tsconfig/ember": ^1.0.1
|
||||
"@types/ember": ^4.0.2
|
||||
|
||||
Reference in New Issue
Block a user