UI: Create Lease Duration card component + style updates (#8815) (#8870)

* updating components to use hds flex, removing custom css

* creating layout, updating fields to use select instead of dropdown

* conditional render, remove commented code

* adding external link

* update handlers and style

* updating general settings layout so TTL doesnt stretch other cards

* typo

Co-authored-by: Dan Rivera <dan.rivera@hashicorp.com>
This commit is contained in:
Vault Automation 2025-08-22 17:14:51 -06:00 committed by GitHub
parent 1d3b51b914
commit e9e162fbb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 162 additions and 34 deletions

View File

@ -0,0 +1,68 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<Hds::Card::Container @level="mid" @hasBorder={{true}} class="has-padding-s has-top-bottom-margin-12" ...attributes>
<Hds::Layout::Flex @align="start" @gap="16" class="has-bottom-margin-m">
<Hds::Layout::Flex @direction="column" @gap="4">
<Hds::Text::Display @size="300" @tag="h5">Lease Duration</Hds::Text::Display>
<Hds::Text::Body @size="200" @tag="p">Lease, measured by the “time-to-live” value, defines how long any secret issued
by this engine remains valid.</Hds::Text::Body>
{{! TODO: Verify what link this is supposed to be }}
<Hds::Link::Standalone
@icon="external-link"
@iconPosition="trailing"
@text="TTL in Vault docs"
@href="https://developer.hashicorp.com/vault/docs/troubleshoot/tune-lease-ttl"
/>
</Hds::Layout::Flex>
</Hds::Layout::Flex>
<Hds::Layout::Flex @direction="column" @gap="24" @isInline="true" class="has-top-padding-s has-bottom-padding-s">
<Hds::Form::Select::Field name="TTL-select" @width="150px" {{on "input" this.setTTLType}} as |F|>
<F.Label>Time-to-live (TTL)</F.Label>
<F.HelperText>Standard expiry deadline.</F.HelperText>
<F.Options>
<option value="System default" selected>System default</option>
<option value="Custom">Custom</option>
</F.Options>
</Hds::Form::Select::Field>
{{#if this.enableTTL}}
<Hds::SegmentedGroup as |SG|>
<SG.TextInput @width="100px" size="32" @value={{this.time}} name="time" {{on "input" this.setTtlTime}} />
<SG.Select @width="100px" {{on "input" this.setUnit}} as |S|>
<S.Options>
<option value="s" selected>seconds</option>
<option value="m">minutes</option>
<option value="h">hours</option>
<option value="d">days</option>
</S.Options>
</SG.Select>
</Hds::SegmentedGroup>
{{/if}}
<Hds::Form::Select::Field name="max-TTL-select" @width="150px" {{on "input" this.setMaxTTLType}} as |F|>
<F.Label>Maximum Time-to-live (TTL)</F.Label>
<F.HelperText>Maximum possible extension for expiry.</F.HelperText>
<F.Options>
<option value="System default" selected>System default</option>
<option value="Custom">Custom</option>
</F.Options>
</Hds::Form::Select::Field>
{{#if this.enableMaxTTL}}
<Hds::SegmentedGroup as |SG|>
<SG.TextInput @width="100px" size="32" @value={{this.maxTime}} name="max-time" {{on "input" this.setMaxTtlTime}} />
<SG.Select @width="100px" {{on "input" this.setMaxUnit}} as |S|>
<S.Options>
<option value="s" selected>seconds</option>
<option value="m">minutes</option>
<option value="h">hours</option>
<option value="d">days</option>
</S.Options>
</SG.Select>
</Hds::SegmentedGroup>
{{/if}}
</Hds::Layout::Flex>
</Hds::Card::Container>

View File

@ -0,0 +1,65 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { action } from '@ember/object';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { HTMLElementEvent } from 'vault/forms';
import SecretsEngineResource from 'vault/resources/secrets/engine';
interface Args {
model: SecretsEngineResource;
}
export default class LeaseDuration extends Component<Args> {
// TODO: When wiring up to parent, address variable names and usage, update onchange functions etc - reference ttl-picker.js
@tracked enableTTL = false;
@tracked enableMaxTTL = false;
@tracked time = '';
@tracked maxTime = '';
@tracked unit = 's';
@tracked maxUnit = 's';
constructor(owner: unknown, args: Args) {
super(owner, args);
}
@action
setTTLType(event: HTMLElementEvent<HTMLInputElement>) {
if (event.target.value === 'Custom') {
this.enableTTL = true;
} else {
this.enableTTL = false;
}
}
@action
setMaxTTLType(event: HTMLElementEvent<HTMLInputElement>) {
if (event.target.value === 'Custom') {
this.enableMaxTTL = true;
} else {
this.enableMaxTTL = false;
}
}
@action
setTtlTime(event: HTMLElementEvent<HTMLInputElement>) {
this.time = event.target.value;
}
@action
setMaxTtlTime(event: HTMLElementEvent<HTMLInputElement>) {
this.maxTime = event.target.value;
}
@action
setUnit(event: HTMLElementEvent<HTMLSelectElement>) {
this.unit = event.target.value;
}
@action
setMaxUnit(event: HTMLElementEvent<HTMLSelectElement>) {
this.maxUnit = event.target.value;
}
}

View File

@ -10,7 +10,7 @@
<F.Legend>Path</F.Legend>
<F.HelperText>The mount path where this secrets engine is accessible.</F.HelperText>
<F.Control>
<div class="flex column-gap-8">
<Hds::Layout::Flex @gap="8">
<Hds::Form::TextInput::Field
@value={{@model.secretsEngine.path}}
autocomplete="off"
@ -20,7 +20,7 @@
data-test-input="path"
/>
<Hds::Copy::Button @text="Copy" @isIconOnly={{true}} @targetToCopy=".path-input-text" />
</div>
</Hds::Layout::Flex>
</F.Control>
</Hds::Form::Fieldset>
@ -28,7 +28,7 @@
<F.Legend>Accessor</F.Legend>
<F.HelperText>Internal identifier used by Vault to reference this engine.</F.HelperText>
<F.Control>
<div class="flex column-gap-8">
<Hds::Layout::Flex @gap="8">
<Hds::Form::TextInput::Field
@value={{@model.secretsEngine.accessor}}
autocomplete="off"
@ -38,7 +38,7 @@
data-test-input="accessor"
/>
<Hds::Copy::Button @text="Copy" @isIconOnly={{true}} @targetToCopy=".accessor-input-text" />
</div>
</Hds::Layout::Flex>
</F.Control>
</Hds::Form::Fieldset>

View File

@ -10,7 +10,7 @@ interface Args {
model: SecretsEngineResource;
}
export default class SecurityCard extends Component<Args> {
export default class Security extends Component<Args> {
constructor(owner: unknown, args: Args) {
super(owner, args);
}

View File

@ -7,13 +7,13 @@
{{! TODO: Having this set up with flex for now, grid might be better? }}
<div class="flex gap-36 has-top-margin-l">
<div class="flex is-flex-column row-gap-8">
<Hds::Layout::Flex @direction="column" @gap="8">
<Hds::Text::Display>Engine type</Hds::Text::Display>
<Hds::Text::Display>Current version</Hds::Text::Display>
<Hds::Text::Display>Latest version</Hds::Text::Display>
</div>
</Hds::Layout::Flex>
<div class="flex is-flex-column is-flex-align-start row-gap-12">
<Hds::Layout::Flex @direction="column" @gap="12" @align="start">
<Hds::Text::Body
@tag="p"
class="hds-border-strong side-padding-4 border-radius-4"
@ -22,19 +22,20 @@
<Hds::Text::Body @tag="p">{{@model.secretsEngine.running_plugin_version}}</Hds::Text::Body>
{{! TODO: leaving as is for now to match design, but we might be removing this if we cant get latest version from some source }}
<Hds::Text::Body @tag="p">v.12.46</Hds::Text::Body>
</div>
</Hds::Layout::Flex>
</div>
<Hds::Separator />
<div>
<Hds::Text::Display @tag="h1" class="has-bottom-margin-s">Update version to:</Hds::Text::Display>
<Hds::Dropdown @listPosition="bottom-left" as |D|>
<D.ToggleButton @text="Select version" @color="secondary" />
{{! TODO: Update interactives with available versions from API }}
<D.Interactive>12.32</D.Interactive>
<D.Interactive>12.4</D.Interactive>
<D.Interactive>12.42</D.Interactive>
</Hds::Dropdown>
</div>
<Hds::Layout::Flex @isInline="true">
<Hds::Form::Select::Field name="version-select" as |F|>
<F.Label>Update version to:</F.Label>
{{! TODO: Update options with available versions from API }}
<F.Options>
<option value="">Select version</option>
<option value="12.4">12.4</option>
<option value="12.43">12.43</option>
</F.Options>
</Hds::Form::Select::Field>
</Hds::Layout::Flex>
</Hds::Card::Container>

View File

@ -19,14 +19,16 @@
Mount parameters that you can tune to fit required engine behavior.
</Hds::Text::Body>
<Hds::Layout::Flex @gap="24">
<SecretEngine::Card::Version @model={{@model}} class="is-fullwidth" />
{{! TODO: Lease duration component }}
</Hds::Layout::Flex>
<Hds::Layout::Flex @direction="row" @gap="32" @align="start">
<Hds::Layout::Flex @direction="column" @gap="8">
<SecretEngine::Card::Version @model={{@model}} class="is-fullwidth" />
<SecretEngine::Card::Metadata @model={{@model}} class="is-fullwidth" />
</Hds::Layout::Flex>
<Hds::Layout::Flex @gap="24">
<SecretEngine::Card::Metadata @model={{@model}} class="is-fullwidth" />
<SecretEngine::Card::Security @model={{@model}} class="is-fullwidth" />
<Hds::Layout::Flex @direction="column" @gap="8">
<SecretEngine::Card::LeaseDuration @model={{@model}} class="is-fullwidth" />
<SecretEngine::Card::Security @model={{@model}} class="is-fullwidth" />
</Hds::Layout::Flex>
</Hds::Layout::Flex>
<div class="field is-grouped has-top-bottom-margin-12">

View File

@ -29,14 +29,6 @@
row-gap: size_variables.$spacing-8;
}
&.row-gap-12 {
row-gap: size_variables.$spacing-12;
}
&.column-gap-8 {
column-gap: size_variables.$spacing-8;
}
&.column-gap-16 {
column-gap: size_variables.$spacing-16;
}