Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Consul::Role::Fieldsets

HDS-native fieldset component for the Role create/edit form. Mirrors `Consul::Token::Fieldsets`.

Renders:
- **Role ID** `Hds::Form::MaskedInput::Field` with copy button (edit mode only)
- **Name** `Hds::Form::TextInput::Field` with helper text and inline error
- **Description** `Hds::Form::Textarea::Field` (optional)
- `Hds::Separator`
- **Policies** `PolicySelector` inside a `<fieldset id="policies">`

## Usage

```hbs
<Consul::Role::Fieldsets
@item={{item}}
@create={{create}}
@onChange={{action 'change'}}
@dc={{dc}}
@nspace={{nspace}}
@partition={{partition}}
/>
```

## Arguments

| Arg | Type | Required | Description |
|---|---:|:---:|---|
| `@item` | object | yes | Role model / changeset. |
| `@create` | boolean | no | True when rendering the create flow (hides Role ID field). |
| `@onChange` | function | no | Handler forwarded to Name/Description inputs. |
| `@dc` | string | no | Datacenter id passed to `PolicySelector`. |
| `@nspace` | string | no | Namespace passed to `PolicySelector`. |
| `@partition` | string | no | Partition passed to `PolicySelector`. |

## See

- Template: ./index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}

<fieldset
disabled={{if (not (can "write role" item=@item)) "disabled"}}
>
{{#unless @create}}
<Hds::Form::MaskedInput::Field
readonly
@isContentMasked={{false}}
@hasCopyButton={{true}}
@value={{@item.ID}}
as |F|
>
<F.Label>Role ID</F.Label>
</Hds::Form::MaskedInput::Field>
{{/unless}}

<Hds::Form::TextInput::Field
@value={{@item.Name}}
name="role[Name]"
@isInvalid={{if @item.error.Name true false}}
{{on "input" @onChange}}
as |F|
>
<F.Label>Name</F.Label>
<F.HelperText>
Maximum 256 characters. May only include letters (uppercase and/or lowercase) and/or numbers. Must be unique.
</F.HelperText>
{{#if @item.error.Name}}
<F.Error>{{@item.error.Name.validation}}</F.Error>
{{/if}}
</Hds::Form::TextInput::Field>

<Hds::Form::Textarea::Field
@value={{@item.Description}}
name="role[Description]"
@isOptional={{true}}
{{on "input" @onChange}}
as |F|
>
<F.Label>Description</F.Label>
</Hds::Form::Textarea::Field>
</fieldset>

<Hds::Separator />

<fieldset id="policies">
<PolicySelector
@showHeader={{true}}
@disabled={{not (can "write role" item=@item)}}
@dc={{@dc}}
@partition={{@partition}}
@nspace={{@nspace}}
@items={{@item.Policies}}
/>
</fieldset>
132 changes: 68 additions & 64 deletions ui/packages/consul-ui/app/components/consul/role/form/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
SPDX-License-Identifier: BUSL-1.1
}}

<form>
<RoleForm
@form={{@form}}
<form class="consul-role-form">
<Consul::Role::Fieldsets
@item={{@item}}
@create={{@create}}
@onChange={{@onChange}}
@dc={{@dc}}
@nspace={{@nspace}}
@partition={{@partition}}
/>

{{#if (not @create)}}
<DataSource
@src={{uri '/${partition}/${nspace}/${dc}/tokens/for-role/${id}'
Expand All @@ -23,16 +25,23 @@
}}
as |loader|>
{{#if (gt loader.data.length 0)}}
<h2>Where is this role used?</h2>
<p>
We're only able to show information for the primary datacenter and the current datacenter. This list may not
show every case where this role is applied.
</p>
<TokenList @caption="Tokens" @items={{loader.data}} />
<div class="consul-role-form__used-by">
<Hds::Separator />
<div class="consul-role-form__usage">
<Hds::Text::Display @size="300" @tag="h2">Where is this role used?</Hds::Text::Display>
<Hds::Text::Body @size="200" @tag="p">
We're only able to show information for the primary datacenter and the current datacenter. This list may not
show every case where this role is applied.
</Hds::Text::Body>
<Hds::Form::Label @controlId="tokens-table">Tokens</Hds::Form::Label>
<TokenList @caption="Tokens" @items={{loader.data}} />
</div>
</div>
{{/if}}
</DataSource>
{{/if}}
<div>

<div class="consul-role-form__actions">
<Hds::ButtonSet>
{{#if (and @create (can "create roles")) }}
<Hds::Button
Expand All @@ -57,60 +66,55 @@
type='reset'
{{on 'click' @onCancel}}
/>
</Hds::ButtonSet>

{{# if (and (not @create) (can "delete role" item=@item) ) }}
<ConfirmationDialog @message="Are you sure you want to delete this Role?">
<:action as |confirm|>
<Hds::Button
@text='Delete'
{{#if (and (not @create) (can "delete role" item=@item))}}
<ConfirmationDialog @message="Are you sure you want to delete this Role?">
<:action as |confirm|>
<Hds::Button
@text='Delete'
@color='critical'
{{on 'click' confirm}}
data-test-delete
/>
</:action>
<:dialog as |execute cancel message|>
{{#if (gt @items.length 0)}}
<Hds::Modal
@color='critical'
{{on 'click' confirm}}
data-test-delete
/>
</:action>
<:dialog as |execute cancel message|>
{{#if (gt @items.length 0)}}
<ModalDialog
@onclose={{cancel}}
@aria={{hash
label="Role in Use"
}}
>
<:header>
<h2>Role in Use</h2>
</:header>
<:body>
<p>
This Role is currently in use. If you choose to delete this Role, it will be removed from the
following <strong>{{@items.length}} Tokens</strong>:
</p>
<TokenList @items={{@items}} @target="_blank" />
<p>
This action cannot be undone. {{message}}
</p>
</:body>
<:actions as |close|>
<Hds::ButtonSet>
<Hds::Button
@text='Yes, Delete'
@color='critical'
data-test-delete
{{on 'click' (queue execute (fn @onDelete @item))}}
/>
<Hds::Button
@text='Cancel'
@color='secondary'
{{on 'click' close}}
/>
</Hds::ButtonSet>
</:actions>
</ModalDialog>
{{else}}
<DeleteConfirmation @message={{message}} @execute={{queue execute (fn @onDelete @item)}} @cancel={{cancel}} />
{{/if}}
</:dialog>
</ConfirmationDialog>
{{/if}}
</Hds::ButtonSet>
@onClose={{cancel}}
as |M|
>
<M.Header @icon='alert-diamond'>Role in Use</M.Header>
<M.Body>
<p>
This Role is currently in use. If you choose to delete this Role, it will be removed from the
following <strong>{{@items.length}} Tokens</strong>:
</p>
<TokenList @items={{@items}} @target="_blank" />
<p>This action cannot be undone. {{message}}</p>
</M.Body>
<M.Footer as |F|>
<Hds::ButtonSet>
<Hds::Button
@text='Yes, Delete'
@color='critical'
data-test-delete
{{on 'click' (queue execute (fn @onDelete @item))}}
/>
<Hds::Button
@text='Cancel'
@color='secondary'
{{on 'click' F.close}}
/>
</Hds::ButtonSet>
</M.Footer>
</Hds::Modal>
{{else}}
<DeleteConfirmation @message={{message}} @execute={{queue execute (fn @onDelete @item)}} @cancel={{cancel}} />
{{/if}}
</:dialog>
</ConfirmationDialog>
{{/if}}
</div>
</form>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

// Role create/edit form layout.
// Mirrors the token form pattern: flex column with 32px gap between each
// top-level child (fieldsets, separators, button row). The separators
// themselves carry their built-in margins reset to zero so the gap is
// the sole source of vertical rhythm.
.consul-role-form {
display: flex;
flex-direction: column;
// 32px between every top-level section (fieldsets, separator, usage block, actions).
gap: 32px;

// Reset HDS separator margins so the form gap is the sole source of spacing.
> .hds-separator {
margin-top: 0;
margin-bottom: 0;
}

// Fields fieldset and policies fieldset: stack HDS form fields with 24px gap.
> fieldset {
border: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 24px;
}

// Wrapper that groups the separator + usage block as one flex child so the
// form gap only fires once above this section.
&__used-by {
display: flex;
flex-direction: column;
gap: 24px;

// Reset HDS separator margins so gap is the sole source of spacing.
> .hds-separator {
margin-top: 0;
margin-bottom: 0;
}
}

// "Where is this role used?" section: heading + body text + label + table stacked at 8px.
&__usage {
display: flex;
flex-direction: column;
gap: 8px;
}

// Actions row: Save/Cancel on the left, Delete on the right.
&__actions {
display: flex;
justify-content: space-between;
align-items: center;
}
}
53 changes: 43 additions & 10 deletions ui/packages/consul-ui/app/components/consul/role/list/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,48 @@
@ariaLabel="Roles"
>
<:row as |item B|>
{{! ---- Role name ---- }}
{{! ---- Name ---- }}
<B.Td>
<span class="consul-role-list__name">
<a
data-test-role={{item.Name}}
data-test-name
href={{href-to 'dc.acls.roles.edit' item.ID}}
>{{item.Name}}</a>
<Consul::Token::Ruleset::List @item={{item}} />
<a
class="consul-role-list__name"
data-test-role={{item.Name}}
data-test-name
href={{href-to 'dc.acls.roles.edit' item.ID}}
>{{item.Name}}</a>
</B.Td>

{{! ---- Identities (ServiceIdentities + NodeIdentities) ---- }}
<B.Td>
<span class="consul-role-list__badges" data-test-identities>
{{#each item.ServiceIdentities as |identity|}}
<Hds::Badge
@text={{identity.ServiceName}}
@color="neutral"
@type="filled"
@size="small"
/>
{{/each}}
{{#each item.NodeIdentities as |identity|}}
<Hds::Badge
@text={{identity.NodeName}}
@color="neutral"
@type="filled"
@size="small"
/>
{{/each}}
</span>
</B.Td>

{{! ---- Rules (Policies) ---- }}
<B.Td>
<span class="consul-role-list__badges" data-test-rules>
{{#each item.Policies as |policy|}}
<Consul::Acl::RulesetBadge
@item={{policy}}
@type={{policy/typeof policy}}
data-test-policy
/>
{{/each}}
</span>
</B.Td>

Expand Down Expand Up @@ -57,8 +90,8 @@
</Consul::DataTable>

{{#if this.itemToDelete}}
<Hds::Modal id="confirm-modal" @color="warning" @onClose={{this.cancelDelete}} as |M|>
<M.Header @icon="alert-triangle">Confirm delete</M.Header>
<Hds::Modal id="confirm-modal" @color="critical" @onClose={{this.cancelDelete}} as |M|>
<M.Header @icon="trash">Confirm delete</M.Header>
<M.Body>
<p>Are you sure you want to delete this role?</p>
</M.Body>
Expand Down
Loading
Loading