[UI] CC-4031: change from Action, a and button to hds::Button (#16251)

This commit is contained in:
Valeriia Ruban 2023-02-22 13:05:15 -08:00 committed by GitHub
parent 2d75b88eb3
commit d01ee172ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 1270 additions and 821 deletions

3
.changelog/16251.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
ui: update from <button> and <a> to design-system-components button <Hds::Button>
```

View File

@ -64,11 +64,11 @@
</AuthForm>
</BlockSlot>
<BlockSlot @name="actions">
<Action
{{on "click" modal.close}}
>
Continue without logging in
</Action>
<Hds::Button
@color='secondary'
@text='Continue without logging in'
{{on 'click' modal.close}}
/>
</BlockSlot>
</ModalDialog>
</:unauthorized>
@ -106,11 +106,11 @@
</AuthForm>
</BlockSlot>
<BlockSlot @name="actions">
<Action
<Hds::Button
@color='secondary'
@text='Continue without logging in'
{{on 'click' modal.close}}
>
Continue without logging in
</Action>
/>
</BlockSlot>
</ModalDialog>
<Portal @target="app-before-skip-links">

View File

@ -47,11 +47,14 @@
<dd>{{@item.ID}}</dd>
<dt>Node</dt>
<dd>
<a
href={{href-to 'dc.nodes.show' @item.Node}}
>
{{@item.Node}}
</a>
<Hds::Button
@text={{@item.Node}}
@icon='git-commit'
@href={{href-to 'dc.nodes.show' @item.Node}}
@isHrefExternal={{false}}
@size='small'
@color='tertiary'
/>
</dd>
<dt>Delay</dt>
<dd>{{duration-from @item.LockDelay}}</dd>
@ -74,30 +77,30 @@
{{#if (can 'delete session' item=@item)}}
<ConfirmationDialog @message="Are you sure you want to invalidate this Lock Session?">
<BlockSlot @name="action" as |confirm|>
<Action
<Hds::Button
@text='Invalidate Session'
@color='critical'
data-test-delete
class="type-delete"
{{on 'click' (fn confirm (fn writer.delete @item))}}
>
Invalidate Session
</Action>
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<p>
{{message}}
</p>
<Action
class="type-delete"
<Hds::ButtonSet>
<Hds::Button
@text='Confirm Invalidation'
@color='critical'
data-test-delete
{{on 'click' (fn execute)}}
>
Confirm Invalidation
</Action>
<Action
class="type-cancel"
/>
<Hds::Button
@text='Cancel'
@color='secondary'
{{on 'click' (fn cancel)}}
>
Cancel
</Action>
/>
</Hds::ButtonSet>
</BlockSlot>
</ConfirmationDialog>
{{/if}}

View File

@ -81,30 +81,30 @@ as |item index|>
@message="Are you sure you want to invalidate this session?"
>
<BlockSlot @name="action" as |confirm|>
<Action
<Hds::Button
@text='Invalidate'
@color='critical'
data-test-delete
class="type-delete"
{{on 'click' (fn confirm (fn @ondelete item))}}
>
Invalidate
</Action>
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<p>
{{message}}
</p>
<Action
class="type-delete"
<Hds::ButtonSet>
<Hds::Button
@text='Confirm Invalidate'
@color='critical'
data-test-delete
{{on 'click' (fn execute)}}
>
Confirm Invalidate
</Action>
<Action
class="type-cancel"
/>
<Hds::Button
@text='Cancel'
@color='secondary'
{{on 'click' (fn cancel)}}
>
Cancel
</Action>
/>
</Hds::ButtonSet>
</BlockSlot>
</ConfirmationDialog>
</BlockSlot>

View File

@ -85,21 +85,23 @@ as |route|>
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<Action
<li>
<Hds::Link::Standalone
@text='Documentation on Lock Sessions'
@href="{{env 'CONSUL_DOCS_URL'}}/internals/sessions.html"
@external={{true}}
>
Documentation on Lock Sessions
</Action>
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<Action
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/tutorials/consul/distributed-semaphore"
@external={{true}}
>
Take the tutorial
</Action>
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href='{{env 'CONSUL_DOCS_LEARN_URL'}}/tutorials/consul/distributed-semaphore'
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>

View File

@ -102,25 +102,29 @@
</fieldset>
{{/if}}
<div>
<Hds::ButtonSet>
{{#if (and (is "new nspace" item=item) (can "create nspaces"))}}
<Action
@type="submit"
{{disabled
(or
<Hds::Button
type="submit"
disabled={{or
(is "pristine nspace" item=item)
(state-matches state "error")
)
}}
>
Save
</Action>
@text='Save'
/>
{{else if (can "write nspace" item=item)}}
<Action @type="submit">Save</Action>
<Hds::Button
type='submit'
@text='Save'
/>
{{/if}}
<Action @type="reset" {{on "click" (fn this.onCancel item)}}>
Cancel
</Action>
<Hds::Button
type='reset'
@color='secondary'
@text='Cancel'
{{on 'click' (fn this.onCancel item)}}
/>
{{#if
(and
@ -132,13 +136,12 @@
@message="Are you sure you want to delete this Namespace?"
>
<BlockSlot @name="action" as |confirm|>
<Action
<Hds::Button
data-test-delete
class="type-delete"
@color='critical'
@text='Delete'
{{on "click" (fn confirm (fn writer.delete item))}}
>
Delete
</Action>
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<DeleteConfirmation
@ -149,7 +152,7 @@
</BlockSlot>
</ConfirmationDialog>
{{/if}}
</Hds::ButtonSet>
</div>
</StateChart>
</form>

View File

@ -49,7 +49,11 @@ as |route|>
</BlockSlot>
<BlockSlot @name="actions">
{{#if (can "create nspaces")}}
<a data-test-create href="{{href-to 'dc.nspaces.create'}}" class="type-create">Create</a>
<Hds::Button
@text='Create'
@route='dc.nspaces.create'
data-test-create
/>
{{/if}}
</BlockSlot>
<BlockSlot @name="toolbar">
@ -117,11 +121,23 @@ as |route|>
</p>
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/commands/namespace" rel="noopener noreferrer" target="_blank">Documentation on namespaces</a>
<li>
<Hds::Link::Standalone
@text='Documentation on namespaces'
@href="{{env 'CONSUL_DOCS_URL'}}/commands/namespace"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/namespaces/secure-namespaces" rel="noopener noreferrer" target="_blank">Read the guide</a>
<li>
<Hds::Link::Standalone
@text='Read the guide'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/namespaces/secure-namespaces"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -84,34 +84,37 @@ as |State Guard ChartAction dispatch state|>
</fieldset>
<div>
{{#if (and (is "new partition" item=item) (can "create partitions")) }}
<Action
@type="submit"
{{disabled (or (is "pristine partition" item=item) (state-matches state "error"))}}
>
Save
</Action>
{{else if (not readOnly)}}
<Action @type="submit">Save</Action>
{{/if}}
<Hds::ButtonSet>
<Action
@type="reset"
{{on 'click' (if @oncancel (fn @oncancel item) (fn @onsubmit item))}}
>
Cancel
</Action>
{{#if (and (is "new partition" item=item) (can "create partitions")) }}
<Hds::Button
@text='Save'
type='submit'
disabled={{or (is "pristine partition" item=item) (state-matches state "error")}}
/>
{{else if (not readOnly)}}
<Hds::Button
@text='Save'
type='submit'
/>
{{/if}}
<Hds::Button
@text='Cancel'
type='reset'
@color='secondary'
{{on 'click' (if @oncancel (fn (optional @oncancel item)) (fn (optional @onsubmit item)))}}
/>
{{#if (and (not (is "new partition" item=item)) (can "delete partition" item=item))}}
<ConfirmationDialog @message="Are you sure you want to delete this Partition?">
<BlockSlot @name="action" as |confirm|>
<Action
<Hds::Button
@text='Delete'
data-test-delete
class="type-delete"
@color='critical'
{{on 'click' (fn confirm (fn writer.delete item))}}
>
Delete
</Action>
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<DeleteConfirmation
@ -122,7 +125,7 @@ as |State Guard ChartAction dispatch state|>
</BlockSlot>
</ConfirmationDialog>
{{/if}}
</Hds::ButtonSet>
</div>
</StateChart>

View File

@ -49,13 +49,11 @@ as |route|>
</BlockSlot>
<BlockSlot @name="actions">
{{#if (can 'create partitions')}}
<a
<Hds::Button
@text='Create'
@route='dc.partitions.create'
data-test-create
class="type-create"
href="{{href-to 'dc.partitions.create'}}"
>
Create
</a>
/>
{{/if}}
</BlockSlot>
<BlockSlot @name="toolbar">

View File

@ -8,7 +8,7 @@
as |address index|
>
<li
class="px-3 h-12 hds-border-primary border-t-0 border-l-0 border-r-0 flex items-center justify-between group"
class="px-3 h-12 border-bottom-primary flex items-center justify-between group"
>
<div
class="hds-typography-display-300 text-hds-foreground-strong hds-font-weight-semibold"

View File

@ -0,0 +1,3 @@
.border-bottom-primary {
border-bottom: 1px solid var(--token-color-border-primary);
}

View File

@ -10,7 +10,7 @@
</div>
<div class="shrink-0">
<div
class="mb-2 hds-typography-body-200 hds-font-weight-semibold hds-foreground-primary"
class="hds-typography-body-200 mb-2 hds-font-weight-semibold hds-foreground-primary"
>Latest heartbeat</div>
<div class="flex items-center">
{{#if @peering.LastHeartbeat}}

View File

@ -1,10 +1,7 @@
<Action
<Hds::Button
@text='Generate token'
form={{@id}}
@type="submit"
{{disabled (or
(eq @item.Name.length 0)
)}}
type='submit'
disabled={{or (eq @item.Name.length 0)}}
...attributes
>
Generate token
</Action>
/>

View File

@ -7,15 +7,6 @@
}
}
.consul-peer-form-token-actions {
button:first-of-type {
@extend %primary-button;
}
button:last-of-type {
@extend %secondary-button;
}
}
.consul-peer-form-generate {
& {
width: 416px;

View File

@ -1,7 +1,6 @@
<Action
<Hds::Button
@text='Add peer'
form={{@id}}
@type="submit"
type='submit'
...attributes
>
Add peer
</Action>
/>

View File

@ -1,18 +1,18 @@
<div
class={{class-map
'consul-peer-form-token-actions'
}}
...attributes
>
<Action
<Hds::ButtonSet>
<Hds::Button
@text='Copy token'
@color='primary'
...attributes
{{with-copyable @token}}
>
Copy token
</Action>
<Action
/>
<Hds::Button
@text='Close'
type='reset'
@color='secondary'
{{on 'click' @onclose}}
>
Close
</Action>
/>
</Hds::ButtonSet>
</div>

View File

@ -27,11 +27,11 @@
</li>
</ol>
{{#if (not @regenerate)}}
<Action
@type="reset"
<Hds::Button
@text='Generate another token'
type='reset'
@color='secondary'
{{on "click" @onclick}}
>
Generate another token
</Action>
/>
{{/if}}

View File

@ -3,4 +3,5 @@
@import './list';
@import './search-bar';
@import './form';
@import './address/list';

View File

@ -90,13 +90,12 @@
<this.form.Actions @onclose={{this.create.close}} />
</BlockSlot>
</ModalDialog>
<Action
data-test-create
class="type-create"
<Hds::Button
@color='primary'
@text='Add peer connection'
{{on "click" (optional this.create.open)}}
>
Add peer connection
</Action>
data-test-create
/>
</BlockSlot>
<BlockSlot @name="content">
@ -194,28 +193,28 @@
</p>
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<li>
{{! what's the docs for peering?}}
<a
href="{{env
<Hds::Link::Standalone
@text='Documentation on Peers'
@href="{{env
'CONSUL_DOCS_URL'
}}/connect/cluster-peering"
rel="noopener noreferrer"
target="_blank"
>
Documentation on Peers
</a>
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a
href="{{env
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env
'CONSUL_DOCS_URL'
}}/connect/cluster-peering/create-manage-peering"
rel="noopener noreferrer"
target="_blank"
>
Take the tutorial
</a>
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -12,25 +12,27 @@
{{t "routes.dc.peers.show.addresses.empty.body" htmlSafe=true}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a
href="{{env 'CONSUL_DOCS_URL'}}/connect/cluster-peering"
rel="noopener noreferrer"
target="_blank"
>
Documentation on Peers
</a>
<li>
<Hds::Link::Standalone
@text='Documentation on Peers'
@href="{{env
'CONSUL_DOCS_URL'
}}/connect/cluster-peering"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a
href="{{env
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env
'CONSUL_DOCS_URL'
}}/connect/cluster-peering/create-manage-peering"
rel="noopener noreferrer"
target="_blank"
>
Take the tutorial
</a>
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -54,7 +54,7 @@
as |service index|
>
<li
class="px-3 h-12 hds-border-primary border-t-0 border-l-0 border-r-0"
class="px-3 h-12 border-bottom-primary"
>
<a
data-test-service-name
@ -99,27 +99,27 @@
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a
href="{{env
<li>
<Hds::Link::Standalone
@text='Documentation on Peers'
@href="{{env
'CONSUL_DOCS_URL'
}}/connect/cluster-peering"
rel="noopener noreferrer"
target="_blank"
>
Documentation on Peers
</a>
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a
href="{{env
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env
'CONSUL_DOCS_URL'
}}/connect/cluster-peering/create-manage-peering"
rel="noopener noreferrer"
target="_blank"
>
Take the tutorial
</a>
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -103,25 +103,28 @@
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a
href="{{env 'CONSUL_DOCS_URL'}}/connect/cluster-peering"
rel="noopener noreferrer"
target="_blank"
>
Documentation on Peers
</a>
<li>
{{! what's the docs for peering?}}
<Hds::Link::Standalone
@text='Documentation on Peers'
@href="{{env
'CONSUL_DOCS_URL'
}}/connect/cluster-peering"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a
href="{{env
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env
'CONSUL_DOCS_URL'
}}/connect/cluster-peering/create-manage-peering"
rel="noopener noreferrer"
target="_blank"
>
Take the tutorial
</a>
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -20,8 +20,7 @@
@extend %app-view-content;
}
%app-view-actions a,
%app-view-actions button {
%app-view-actions a {
@extend %button-compact;
}

View File

@ -109,9 +109,11 @@
</State>
</label>
</fieldset>
<Action @type='submit' disabled={{state-matches state 'loading'}}>
Log in
</Action>
<Hds::Button
type='submit'
@text='Log in'
disabled={{state-matches state 'loading'}}
/>
</form>
</TabState>

View File

@ -1,19 +1,2 @@
@import './skin';
@import './layout';
button[type='submit'],
button.type-submit,
button.type-create,
a.type-create {
@extend %primary-button;
}
// TODO: Once we move action-groups to use aria menu we can get rid of
// some of this and just use not(aria-haspopup)
button[type='reset'],
button.type-cancel {
@extend %secondary-button;
}
.with-confirmation .type-delete,
.modal-dialog .type-delete,
%app-view-content form button[type='button'].type-delete {
@extend %dangerous-button;
}

View File

@ -11,7 +11,6 @@
cursor: default;
box-shadow: none;
}
%primary-button,
%secondary-button,
%dangerous-button {
@extend %button;
@ -19,20 +18,6 @@
border-radius: var(--decor-radius-100);
box-shadow: var(--decor-elevation-300);
}
/* color */
%primary-button {
@extend %frame-blue-800;
}
%primary-button:hover:not(:disabled):not(:active),
%primary-button:focus {
@extend %frame-blue-700;
}
%primary-button:disabled {
@extend %frame-blue-600;
}
%primary-button:hover:active {
@extend %frame-blue-900;
}
/**/
%secondary-button:hover:not(:disabled):not(:active),
%secondary-button:focus {

View File

@ -1,5 +1,6 @@
%confirmation-dialog {
float: right;
justify-content: end;
width: 100%;
}
%confirmation-dialog-inline p {
margin-right: 12px;

View File

@ -15,11 +15,23 @@
</p>
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/acl/index.html" rel="noopener noreferrer" target="_blank">Read the documentation</a>
<li>
<Hds::Link::Standalone
@text='Read the documentation'
@href="{{env 'CONSUL_DOCS_URL'}}/acl/index.html"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/security-networking/production-acls" rel="noopener noreferrer" target="_blank">Follow the guide</a>
<li>
<Hds::Link::Standalone
@text='Follow the guide'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/security-networking/production-acls"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -189,13 +189,14 @@
</fieldset>
{{#if (eq (or item.Action '') '')}}
<fieldset class="permissions">
<button
<Hds::Button
@text='Add permission'
@size='small'
@color='tertiary'
@icon='plus'
data-test-create-permission
type="button"
{{on "click" (action this.openModal)}}
>
Add permission
</button>
/>
<h2>Permissions</h2>
{{#if (gt item.Permissions.length 0) }}
<Consul::Intention::Notice::Permissions />
@ -217,11 +218,23 @@
</p>
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/commands/intention" rel="noopener noreferrer" target="_blank">Documentation</a>
<li>
<Hds::Link::Standalone
@text='Documentation'
@href="{{env 'CONSUL_DOCS_URL'}}/commands/intention"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/connect" rel="noopener noreferrer" target="_blank">Read the guide</a>
<li>
<Hds::Link::Standalone
@text='Read the guide'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/connect"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>
@ -249,22 +262,20 @@
</Consul::Intention::Permission::Form>
</BlockSlot>
<BlockSlot @name="actions">
<button
type="button"
<Hds::ButtonSet>
<Hds::Button
@text='Save'
data-test-intention-permission-submit
class="type-submit"
@color='primary'
disabled={{if (not this.permissionForm.isDirty) 'disabled'}}
onclick={{queue (action this.permissionForm.submit) (action modal.close)}}
>
Save
</button>
<button
type="button"
class="type-cancel"
/>
<Hds::Button
@text='Cancel'
@color='secondary'
onclick={{queue (action this.permissionForm.reset) (action modal.close)}}
>
Cancel
</button>
/>
</Hds::ButtonSet>
</BlockSlot>
</ModalDialog>

View File

@ -80,22 +80,20 @@ as |item readonly|}}
</p>
</BlockSlot>
<BlockSlot @name="actions" as |close|>
<button
<Hds::ButtonSet>
<Hds::Button
data-test-action-warning-confirm
type="button"
class="dangerous"
@text='Set to {{capitalize newAction}}'
@color='critical'
{{on 'click' api.submit}}
>
Set to {{capitalize newAction}}
</button>
<button
/>
<Hds::Button
data-test-action-warning-cancel
type="button"
class="type-cancel"
@text='No, Cancel'
@color='secondary'
onclick={{close}}
>
No, Cancel
</button>
/>
</Hds::ButtonSet>
</BlockSlot>
</ModalDialog>
{{/let}}
@ -174,32 +172,30 @@ as |item readonly|}}
@onchange={{api.change}}
/>
<div>
<button
type="submit"
<Hds::ButtonSet>
<Hds::Button
@text='Save'
type='submit'
disabled={{or item.isInvalid api.disabled}}
>
Save
</button>
<button
/>
<Hds::Button
@text='Cancel'
@color='secondary'
type="reset"
disabled={{api.disabled}}
{{on 'click' (fn this.oncancel item)}}
>
Cancel
</button>
/>
{{#if (not api.isCreate)}}
{{#if (not-eq item.ID 'anonymous') }}
<ConfirmationDialog @message="Are you sure you want to delete this Intention?">
<BlockSlot @name="action" as |confirm|>
<button
data-test-delete
type="button"
class="type-delete"
<Hds::Button
@text='Delete'
@color='critical'
disabled={{api.disabled}}
{{on 'click' (fn confirm api.delete)}}
>
Delete
</button>
data-test-delete
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<DeleteConfirmation
@ -211,6 +207,7 @@ as |item readonly|}}
</ConfirmationDialog>
{{/if}}
{{/if}}
</Hds::ButtonSet>
</div>
</form>
{{else}}
@ -231,9 +228,12 @@ as |item readonly|}}
</p>
</notice.Body>
<notice.Footer>
<p>
<a href="{{env 'CONSUL_DOCS_URL'}}/k8s/crds" target="_blank" rel="noopener noreferrer">Learn more about CRDs</a>
</p>
<Hds::Link::Standalone
@text='Learn more about CRDs'
@href="{{env 'CONSUL_DOCS_URL'}}/k8s/crds"
@icon='docs-link'
@iconPosition='trailing'
/>
</notice.Footer>
</Notice>
{{/if}}

View File

@ -15,7 +15,13 @@ as |notice|>
</notice.Body>
<notice.Footer>
<p>
<a href="{{env 'CONSUL_DOCS_URL'}}/k8s/crds" target="_blank" rel="noopener noreferrer">Learn more about CRDs</a>
<Hds::Link::Standalone
@href="{{env 'CONSUL_DOCS_URL'}}/k8s/crds"
@text='Learn more about CRDs'
@icon="docs-link"
@iconPosition="trailing"
@size="small"
/>
</p>
</notice.Footer>
</Notice>

View File

@ -8,9 +8,13 @@ as |notice|>
</notice.Body>
<notice.Footer>
<p>
<a href="{{env 'CONSUL_DOCS_URL'}}/connect/intentions" target="_blank" rel="noopener noreferrer">
{{t "components.consul.intention.notice.permissions.footer"}}
</a>
<Hds::Link::Standalone
@text={{t "components.consul.intention.notice.permissions.footer"}}
@href="{{env 'CONSUL_DOCS_URL'}}/connect/intentions"
@icon="docs-link"
@iconPosition="trailing"
@size="small"
/>
</p>
</notice.Footer>
</Notice>

View File

@ -134,23 +134,20 @@ as |group|>
<Ref @target={{this}} @name="headerForm" @value={{headerForm}} />
</Consul::Intention::Permission::Header::Form>
<button
<Hds::ButtonSet>
<Hds::Button
data-test-add-header
type="button"
class="type-submit"
@text='Add{{if (gt (get (changeset-get changeset 'HTTP.Header') 'length') 0) ' another' ''}} header'
@color='primary'
disabled={{if (not this.headerForm.isDirty) 'disabled'}}
onclick={{action this.headerForm.submit}}
>
Add{{#if (gt (get (changeset-get changeset 'HTTP.Header') 'length') 0)}} another{{/if}} header
</button>
<button
type="button"
class="type-cancel"
/>
<Hds::Button
@text='Cancel'
@color='secondary'
onclick={{action this.headerForm.reset}}
>
Cancel
</button>
/>
</Hds::ButtonSet>
</fieldset>
</FormGroup>
</div>

View File

@ -61,27 +61,56 @@
</div>
{{/if}}
</fieldset>
<Hds::ButtonSet>
{{#if api.isCreate}}
{{#if (not disabld)}}
<button type="submit" disabled={{or api.data.isPristine api.data.isInvalid api.disabled}}>Save</button>
{{/if}}
<button type="reset" onclick={{action oncancel api.data}} disabled={{api.disabled}}>Cancel</button>
{{#if (not disabld)}}
<Hds::Button
@text='Save'
type='submit'
disabled={{or api.data.isPristine api.data.isInvalid api.disabled}}
/>
{{/if}}
<Hds::Button
@text='Cancel'
@color='secondary'
type='reset'
disabled={{api.disabled}}
onclick={{action oncancel api.data}}
/>
{{else}}
{{#if (not disabld)}}
<button type="submit" disabled={{or api.data.isInvalid api.disabled}}>Save</button>
{{/if}}
<button type="reset" onclick={{action oncancel api.data}} disabled={{api.disabled}}>Cancel</button>
{{#if (not disabld)}}
{{#if (not disabld)}}
<Hds::Button
@text='Save'
type='submit'
disabled={{or api.data.isInvalid api.disabled}}
/>
{{/if}}
<Hds::Button
@text='Cancel'
@color='secondary'
type='reset'
disabled={{api.disabled}}
onclick={{action oncancel api.data}}
/>
{{#if (not disabld)}}
<ConfirmationDialog @message="Are you sure you want to delete this key?">
<BlockSlot @name="action" as |confirm|>
<button data-test-delete type="button" class="type-delete" {{action confirm api.delete}} disabled={{api.disabled}}>Delete</button>
<Hds::Button
@text='Delete'
@color='critical'
data-test-delete
disabled={{api.disabled}}
{{on 'click' (action confirm api.delete)}}
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<DeleteConfirmation @message={{message}} @execute={{execute}} @cancel={{cancel}} />
</BlockSlot>
</ConfirmationDialog>
{{/if}}
{{/if}}
{{/if}}
</Hds::ButtonSet>
</form>
{{/let}}
</BlockSlot>

View File

@ -4,9 +4,13 @@
<h3>
{{t 'routes.dc.nodes.index.agentless.notice.header'}}
</h3>
<button type='button' aria-label='Dismiss notice' {{on 'click' this.dismissAgentlessNotice}}>
<FlightIcon @name='x' />
</button>
<Hds::Button
@color='secondary'
@text='Dismiss notice'
{{on 'click' this.dismissAgentlessNotice}}
@icon='x'
@isIconOnly={{true}}
/>
</notice.Header>
<notice.Body>
<p>
@ -14,15 +18,12 @@
</p>
</notice.Body>
<notice.Footer>
<p class='docs-link'>
<a
href='{{env "CONSUL_DOCS_DEVELOPER_URL"}}/connect/dataplane'
target='_blank'
rel='noopener noreferrer'
>
{{t 'routes.dc.nodes.index.agentless.notice.footer'}}
</a>
</p>
<Hds::Button
@color='tertiary'
@href='{{env "CONSUL_DOCS_DEVELOPER_URL"}}/connect/dataplane'
@text={{t 'routes.dc.nodes.index.agentless.notice.footer'}}
@icon='docs-link'
/>
</notice.Footer>
</Notice>
{{/if}}

View File

@ -1,7 +1,16 @@
<p>
{{message}}
</p>
<button type="button" class="type-delete" onclick={{action execute}}>
Confirm Delete
</button>
<button type="button" class="type-cancel" onclick={{action cancel}}>Cancel</button>
<Hds::ButtonSet>
<Hds::Button
@text='Confirm Delete'
data-test-delete
@color='critical'
onclick={{action execute}}
/>
<Hds::Button
@text='Cancel'
@color='secondary'
onclick={{action cancel}}
/>
</Hds::ButtonSet>

View File

@ -44,23 +44,23 @@ function.
</p>
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a
href="{{env 'CONSUL_DOCS_URL'}}/agent/kv"
rel="noopener noreferrer"
target="_blank"
>
Documentation on K/V
</a>
<li>
<Hds::Link::Standalone
@text='Documentation on namespaces'
@href="{{env 'CONSUL_DOCS_URL'}}/commands/namespace"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a
href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/kv"
rel="noopener noreferrer"
target="_blank"
>
Read the guide
</a>
<li>
<Hds::Link::Standalone
@text='Read the guide'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/namespaces/secure-namespaces"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -17,7 +17,9 @@
<div>
{{yield}}
{{#if login}}
<Action
<Hds::Button
@color='primary'
@text={{if token.AccessorID 'Log in with a different token' 'Log in'}}
data-test-empty-state-login
{{on "click" login}}
>
@ -25,12 +27,7 @@
@src={{uri 'settings://consul:token'}}
@onchange={{action (mut token) value="data"}}
/>
{{#if token.AccessorID}}
Log in with a different token
{{else}}
Log in
{{/if}}
</Action>
</Hds::Button>
{{/if}}
</div>
{{/yield-slot}}

View File

@ -16,6 +16,3 @@
%empty-state > ul > li > label > button {
@extend %empty-state-anchor;
}
%empty-state div > button {
@extend %primary-button;
}

View File

@ -27,21 +27,25 @@
</p>
</BlockSlot>
<BlockSlot @name="actions">
<li class="back-link">
<Action
<li>
<Hds::Link::Standalone
data-test-home
@href={{href-to 'index'}}
>
Go back
</Action>
@route='index'
@text='Go back'
@icon='chevron-left'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="docs-link">
<Action
<li>
<Hds::Link::Standalone
data-test-home
@text='Read the documentation'
@href="{{env 'CONSUL_DOCS_URL'}}"
@external={{true}}
>
Read the documentation
</Action>
@iconPosition='trailing'
@icon='docs-link'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>
@ -68,21 +72,23 @@
</p>
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<Action
<li>
<Hds::Link::Standalone
@text='Read the documentation'
@href="{{env 'CONSUL_DOCS_URL'}}/acl/index.html"
@external={{true}}
>
Read the documentation
</Action>
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<Action
<li>
<Hds::Link::Standalone
@text='Follow the guide'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/security-networking/production-acls"
@external={{true}}
>
Follow the guide
</Action>
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -1,6 +1,7 @@
@import './skin';
@import './layout';
%form h2 {
%form h2,
.modal-dialog-body h2 {
@extend %h200;
}
/* TODO: This is positioning the element */
@ -41,9 +42,7 @@ label span {
@extend %form-element-error;
}
// TODO: float right here is too specific, this is currently used just for the role/policy selectors
label.type-dialog {
@extend %anchor;
cursor: pointer;
.type-dialog {
float: right;
}
.type-toggle {
@ -69,6 +68,11 @@ span.label {
%main-content .type-text {
@extend %form-element;
}
%main-content .type-select > span,
%main-content .type-password > span,
%main-content label.type-text > span {
line-height: 2.2em;
}
%app-view-content form:not(.filter-bar) [role='radiogroup'],
%modal-window [role='radiogroup'] {
@extend %radio-group;

View File

@ -20,12 +20,14 @@
role="document"
>
<header class="modal-dialog-header">
<button
type="button"
<Hds::Button
data-a11y-dialog-hide
aria-label="Close dialog"
>
</button>
@text='Close dialog'
@color='secondary'
@icon='x'
@size='small'
@isIconOnly={{true}}
/>
<YieldSlot @name="header">
{{yield (hash
open=(action "open")

View File

@ -63,7 +63,5 @@
}
%modal-window > header button {
float: right;
width: 24px;
height: 24px;
margin-top: -3px;
}

View File

@ -28,7 +28,7 @@
%modal-window > header {
@extend %frame-gray-800;
}
%modal-window > header > * {
%modal-window > header > *:not(button) {
@extend %h200;
}
@ -46,17 +46,3 @@
%modal-window > header {
border-width: 1px;
}
%modal-window > header button {
cursor: pointer;
border: var(--decor-border-100);
/*%frame-gray-050??*/
background-color: rgb(var(--tone-gray-050));
border-color: rgb(var(--tone-gray-300));
border-radius: var(--decor-radius-100);
}
%modal-window > header button::before {
@extend %with-cancel-plain-icon, %as-pseudo;
margin-left: -7px;
margin-top: -3px;
}

View File

@ -49,12 +49,12 @@
{{! this belongs to the outer StateChart but we need }}
{{! to understand validation state }}
<State @matches='idle'>
<Action
{{disabled (or (lt this.partition.length 1) (state-matches state 'error'))}}
<Hds::Button
type='submit'
@text='Choose provider'
disabled={{or (lt this.partition.length 1) (state-matches state 'error')}}
{{on 'click' (fn dispatch 'LOAD')}}
>
Choose provider
</Action>
/>
</State>
</StateChart>
@ -105,10 +105,12 @@
</:option>
</OptionInput>
<Action @type='button' {{disabled @disabled}} {{on 'click' (fn @onchange item)}}>
Log in
</Action>
<Hds::Button
@color='primary'
@text='Log in'
disabled={{@disabled}}
{{on 'click' (fn @onchange item)}}
/>
{{/let}}
{{/if}}
</State>

View File

@ -3,9 +3,7 @@
%oidc-select label {
@extend %form-element;
}
%oidc-select button:not(.reset) {
@extend %primary-button;
}
%oidc-select button.reset {
@extend %anchor;
@extend %p3;

View File

@ -10,20 +10,22 @@
...attributes
>
{{yield}}
<BlockSlot @name="label">
<BlockSlot @name="label" data-test-apply-policy>
Apply an existing policy
</BlockSlot>
<BlockSlot @name="create">
{{#yield-slot name='trigger'}}
{{yield}}
{{else}}
<label
class="type-dialog"
<Hds::Button
@text='Create new policy'
@size='small'
@color='tertiary'
@icon='plus'
class='type-dialog'
data-test-policy-create
{{on "click" (action this.openModal)}}
>
<span>Create new policy</span>
</label>
/>
{{!TODO: potentially call trigger something else}}
{{!the modal has to go here so that if you provide a slot to trigger it doesn't get rendered}}
<ModalDialog
@ -48,16 +50,22 @@
/>
</BlockSlot>
<BlockSlot @name="actions" as |close|>
<button type="submit"
<Hds::ButtonSet>
<Hds::Button
type="submit"
@isLoading={{item.isSaving}}
onclick={{perform this.save item items (queue (action close) (action 'reset'))}}
disabled={{if (or item.isSaving item.isPristine item.isInvalid) 'disabled'}}
>
{{#if item.isSaving }}
<div class="progress indeterminate"></div>
{{/if}}
<span>Create and apply</span>
</button>
<button type="reset" disabled={{if item.isSaving 'disabled'}} {{action (queue (action close) (action 'reset'))}}>Cancel</button>
@text='Create and apply'
/>
<Hds::Button
type="reset"
@color="secondary"
disabled={{if item.isSaving 'disabled'}}
{{on 'click' (action (queue (action close) (action 'reset')))}}
@text='Cancel'
/>
</Hds::ButtonSet>
</BlockSlot>
</ModalDialog>
{{/yield-slot}}
@ -161,15 +169,34 @@
<div>
<ConfirmationDialog @message="Are you sure you want to remove this policy from this token?">
<BlockSlot @name="action" as |confirm|>
<button data-test-delete type="button" class="type-delete" {{action confirm 'remove' item items}}>Remove</button>
<Hds::Button
@text='Remove'
@color='critical'
@size='small'
{{action confirm 'remove' item items}}
data-test-delete
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<p>
{{message}}
</p>
<button type="button" class="type-delete" {{action execute}}>Confirm remove</button>
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
<Hds::ButtonSet>
<Hds::Button
@text='Confirm remove'
@color='critical'
@size='small'
{{action execute}}
data-test-delete
/>
<Hds::Button
@text='Cancel'
@color='secondary'
@size='small'
{{action cancel}}
data-test-delete
/>
</Hds::ButtonSet>
</BlockSlot>
</ConfirmationDialog>
</div>

View File

@ -34,9 +34,15 @@ as |modal|>
@items={{item.Policies}}
>
<BlockSlot @name="trigger">
<label for="{{name}}_state_policy" data-test-create-policy class="type-dialog">
<span>Create new policy</span>
</label>
<Hds::Button
@text='Create new policy'
@size='small'
@color='tertiary'
@icon='plus'
class='type-dialog'
data-test-create-policy
{{action 'triggerStateCheckboxChange'}}
/>
</BlockSlot>
</PolicySelector>
@ -56,27 +62,40 @@ as |modal|>
</BlockSlot>
<BlockSlot @name="actions" as |close|>
{{#if (eq state 'role')}}
<button type="submit"
<Hds::ButtonSet>
{{#if (eq state 'role')}}
<Hds::Button
type='submit'
@text='Create and apply'
@isLoading={{item.isSaving}}
onclick={{perform this.save item items (queue (action close) (action 'reset'))}}
disabled={{if (or item.isSaving item.isPristine item.isInvalid) 'disabled'}}
>
{{#if item.isSaving }}
<div class="progress indeterminate"></div>
{{/if}}
<span>Create and apply</span>
</button>
<button type="reset" disabled={{if item.isSaving 'disabled'}} {{action (queue (action close) (action 'reset'))}}>Cancel</button>
{{else}}
<button type="submit" {{action 'dispatch' 'save' (array policy item.Policies (action (mut state) 'role'))}} disabled={{if (or policy.isSaving policy.isPristine policy.isInvalid) 'disabled'}}>
{{#if policy.isSaving }}
<div class="progress indeterminate"></div>
{{/if}}
<span>Create and apply</span>
</button>
<button type="reset" disabled={{if policy.isSaving 'disabled'}} {{action (mut state) 'role'}}>Cancel</button>
{{/if}}
/>
<Hds::Button
@text='Cancel'
type='reset'
@color='secondary'
disabled={{if item.isSaving 'disabled'}}
{{on 'click' (action (queue (action close) (action 'reset')))}}
/>
{{else}}
<Hds::Button
type='submit'
@text='Create and apply'
@isLoading={{policy.isSaving}}
{{action 'dispatch' 'save' (array policy item.Policies (action (mut state) 'role'))}}
disabled={{if (or policy.isSaving policy.isPristine policy.isInvalid) 'disabled'}}
/>
<Hds::Button
@text='Cancel'
type='reset'
@color='secondary'
disabled={{if policy.isSaving 'disabled'}}
{{on 'click' (action (mut state) 'role')}}
/>
{{/if}}
</Hds::ButtonSet>
</BlockSlot>
</ModalDialog>
@ -94,12 +113,15 @@ as |modal|>
Apply an existing role
</BlockSlot>
<BlockSlot @name="create">
<label class="type-dialog"
<Hds::Button
@text='Create new role'
@size='small'
@color='tertiary'
@icon='plus'
class='type-dialog'
data-test-role-create
{{on "click" (optional this.modal.open)}}
>
<span>Create new role</span>
</label>
/>
</BlockSlot>
<BlockSlot @name="option" as |option|>
{{option.Name}}

View File

@ -42,5 +42,11 @@ export default ChildSelectorComponent.extend({
this._super(...arguments);
}
},
triggerStateCheckboxChange() {
//Triggers click event on checkbox
//The function has to be added to change the logic from <label for=''> to Hds::Button
let element = document.getElementById(`${this.name}_state_policy`);
element && element.dispatchEvent(new Event('change'));
},
},
});

View File

@ -75,7 +75,9 @@ export default Mixin.create({
// do the same as an update, or override
return this.afterUpdate(...arguments);
},
create: function (item) {
create: function (item, event) {
event.preventDefault();
return this.feedback.execute(
() => {
return this.repo.persist(item).then((item) => {
@ -88,7 +90,9 @@ export default Mixin.create({
}
);
},
update: function (item) {
update: function (item, event) {
event.preventDefault();
return this.feedback.execute(
() => {
return this.repo.persist(item).then(() => {

View File

@ -1,11 +1,11 @@
@charset 'utf-8';
/* css for hds */
@import '@hashicorp/design-system-components';
/* tailwind before all the customizations */
@import 'tailwind';
/* css for hds */
@import '@hashicorp/design-system-components';
/* all variables and custom queries including generic base variables */
@import 'variables';

View File

@ -1,8 +1,10 @@
a {
text-decoration: none;
}
td, th,
span, strong {
td,
th,
span,
strong {
color: inherit;
}
/* %typo-body */
@ -19,9 +21,7 @@ html {
hr {
background-color: rgb(var(--tone-gray-200));
}
button {
background-color: var(--transparent);
}
html {
font-size: var(--typo-size-000);
}
@ -30,7 +30,6 @@ body {
line-height: 1.5;
}
body,
button,
input,
select,
textarea {
@ -69,7 +68,9 @@ html {
html {
box-sizing: border-box;
}
*, *::before, *::after {
*,
*::before,
*::after {
box-sizing: inherit;
}
fieldset {
@ -85,8 +86,8 @@ hr {
border: none;
display: block;
}
input[type="checkbox"],
input[type="radio"] {
input[type='checkbox'],
input[type='radio'] {
vertical-align: baseline;
}
td,

View File

@ -8,9 +8,6 @@ html[data-route^='dc.acls.index'] .filter-bar {
html[data-route^='dc.acls.index'] .filter-bar [role='radiogroup'] {
@extend %expanded-single-select;
}
html[data-route^='dc.acls.tokens.edit'] header .actions button {
@extend %secondary-button;
}
@media #{$--lt-wide-form} {
html[data-route^='dc.acls.create'] main header .actions,

View File

@ -53,11 +53,3 @@ section[data-route='dc.show.license'] {
%license-route-learn-more header {
margin-bottom: 1rem; /* 16px */
}
%license-route-learn-more li {
margin-bottom: 0.25rem; /* 4px */
}
%license-route-learn-more a::before {
--icon-name: icon-docs-link;
content: '';
margin-right: 0.375rem; /* 6px */
}

View File

@ -28,16 +28,16 @@ section[data-route='dc.show.serverstatus'] {
}
%server-failure-tolerance > header {
width: 100%;
padding-bottom: 0.500rem; /* 8px */
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding-bottom: 0.5rem; /* 8px */
margin-bottom: 1rem; /* 16px */
border-bottom: var(--decor-border-100);
border-color: rgb(var(--tone-border));
}
%server-failure-tolerance > header a {
float: right;
margin-top: 4px;
font-weight: var(--typo-weight-semibold);
}
%server-failure-tolerance header em {
@extend %pill-200;
font-size: 0.812rem; /* 13px */
@ -45,7 +45,6 @@ section[data-route='dc.show.serverstatus'] {
text-transform: uppercase;
font-style: normal;
}
%server-failure-tolerance > section {
width: 50%;
@ -68,10 +67,10 @@ section[data-route='dc.show.serverstatus'] {
--icon-size: icon-800;
--icon-color: rgb(var(--tone-orange-400));
content: '';
margin-right: 0.500rem; /* 8px */
margin-right: 0.5rem; /* 8px */
}
%server-failure-tolerance section:first-of-type dl {
padding-right: 1.500rem; /* 24px */
padding-right: 1.5rem; /* 24px */
}
%server-failure-tolerance dt {
@extend %p2;
@ -98,7 +97,6 @@ section[data-route='dc.show.serverstatus'] {
margin-bottom: 18px;
}
%redundancy-zones h3 {
@extend %h300;
}
@ -136,4 +134,3 @@ section[data-route='dc.show.serverstatus'] {
vertical-align: revert;
background-color: var(--transparent);
}

View File

@ -35,7 +35,6 @@ pre code,
@extend %p1;
}
%empty-state-anchor,
.type-dialog,
%table td p,
%table td,
%healthcheck-output dl > dd,

View File

@ -102,11 +102,23 @@ as |route|>
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/security/acl/auth-methods" rel="noopener noreferrer" target="_blank">Documentation on auth methods</a>
<li>
<Hds::Link::Standalone
@text='Documentation on auth methods'
@href="{{env 'CONSUL_DOCS_URL'}}/security/acl/auth-methods"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_DOCS_API_URL'}}/acl/auth-methods.html" rel="noopener noreferrer" target="_blank">Read the API Docs</a>
<li>
<Hds::Link::Standalone
@text='Read the API Docs'
@href='{{env 'CONSUL_DOCS_API_URL'}}/acl/auth-methods.html'
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -28,20 +28,40 @@
{{/if}}
{{/if}}
<div>
{{#if (and create (can "create tokens")) }}
<Hds::ButtonSet>
{{#if (and create (can "create tokens")) }}
{{! we only need to check for an empty name here as ember munges autofocus, once we have autofocus back revisit this}}
<button type="submit" {{ action "create" item}} disabled={{if (or item.isPristine item.isInvalid (eq item.Name '')) 'disabled'}}>Save</button>
{{ else }}
<Hds::Button
@text='Save'
type='submit'
{{ on 'click' (route-action 'create' item)}}
disabled={{if (or item.isPristine item.isInvalid (eq item.Name '')) 'disabled'}}
/>
{{ else }}
{{#if (can "write policy" item=item)}}
<button
type="submit" {{ action "update" item}} disabled={{if item.isInvalid 'disabled'}}>Save</button>
<Hds::Button
@text='Save'
type='submit'
{{ on 'click' (route-action 'update' item)}}
disabled={{if item.isInvalid 'disabled'}}
/>
{{/if}}
{{/if}}
<button type="reset" {{ action "cancel" item}}>Cancel</button>
{{# if (and (not create) (can "delete policy" item=item) ) }}
{{/if}}
<Hds::Button
@text='Cancel'
@color='secondary'
type='reset'
{{ action "cancel" item}}
/>
{{# if (and (not create) (can "delete policy" item=item) ) }}
<ConfirmationDialog @message="Are you sure you want to delete this Policy?">
<BlockSlot @name="action" as |confirm|>
<button type="button" data-test-delete class="type-delete" {{action confirm 'delete' item}}>Delete</button>
<Hds::Button
@text='Delete'
@color='critical'
{{action confirm 'delete' item}}
data-test-delete
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
{{#if (gt items.length 0)}}
@ -58,7 +78,8 @@
</BlockSlot>
<BlockSlot @name="body">
<p>
This Policy is currently in use. If you choose to delete this Policy, it will be removed from the following <strong>{{items.length}} Tokens</strong>:
This Policy is currently in use. If you choose to delete this Policy, it will be removed from the
following <strong>{{items.length}} Tokens</strong>:
</p>
<TokenList @items={{items}} @target="_blank" />
<p>
@ -66,8 +87,19 @@
</p>
</BlockSlot>
<BlockSlot @name="actions" as |close|>
<button type="button" class="type-delete" {{action execute}}>Yes, Delete</button>
<button type="button" class="type-cancel" {{action close}}>Cancel</button>
<Hds::ButtonSet>
<Hds::Button
@text='Yes, Delete'
data-test-delete
@color='critical'
{{action execute}}
/>
<Hds::Button
@text='Cancel'
@color='secondary'
{{action close}}
/>
</Hds::ButtonSet>
</BlockSlot>
</ModalDialog>
{{else}}
@ -75,6 +107,7 @@
{{/if}}
</BlockSlot>
</ConfirmationDialog>
{{/if}}
{{/if}}
</Hds::ButtonSet>
</div>
</form>

View File

@ -62,7 +62,11 @@ as |route|>
</BlockSlot>
<BlockSlot @name="actions">
{{#if (can "create policies")}}
<a data-test-create href="{{href-to 'dc.acls.policies.create'}}" class="type-create">Create</a>
<Hds::Button
@text='Create'
@route='dc.acls.policies.create'
data-test-create
/>
{{/if}}
</BlockSlot>
<BlockSlot @name="toolbar">
@ -111,11 +115,23 @@ as |route|>
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/commands/acl/policy" rel="noopener noreferrer" target="_blank">Documentation on policies</a>
<li>
<Hds::Link::Standalone
@text='Documentation on policies'
@href="{{env 'CONSUL_DOCS_URL'}}/commands/acl/policy"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_LEARN_URL'}}/consul/security-networking/managing-acl-policies" rel="noopener noreferrer" target="_blank">Take the tutorial</a>
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env 'CONSUL_LEARN_URL'}}/consul/security-networking/managing-acl-policies"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -6,7 +6,7 @@
@nspace={{nspace}}
@partition={{partition}}
/>
{{#if (not create)}}
{{#if (not create)}}
<DataSource
@src={{uri '/${partition}/${nspace}/${dc}/tokens/for-role/${id}'
(hash
@ -20,26 +20,49 @@
{{#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.
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}} />
{{/if}}
</DataSource>
{{/if}}
<div>
{{#if (and create (can "create roles")) }}
{{! we only need to check for an empty name here as ember munges autofocus, once we have autofocus back revisit this}}
<button type="submit" {{ action "create" item}} disabled={{if (or item.isPristine item.isInvalid (eq item.Name '')) 'disabled'}}>Save</button>
{{ else }}
{{#if (can "write role" item=item)}}
<button type="submit" {{ action "update" item}} disabled={{if item.isInvalid 'disabled'}}>Save</button>
{{/if}}
{{/if}}
<button type="reset" {{ action "cancel" item}}>Cancel</button>
{{# if (and (not create) (can "delete role" item=item) ) }}
<div>
<Hds::ButtonSet>
{{#if (and create (can "create roles")) }}
{{! we only need to check for an empty name here as ember munges autofocus, once we have autofocus back revisit this}}
<Hds::Button
@text='Save'
type='submit'
{{ on 'click' (route-action 'create' item)}}
disabled={{or item.isPristine item.isInvalid (eq item.Name '')}}
/>
{{ else }}
{{#if (can "write role" item=item)}}
<Hds::Button
@text='Save'
type='submit'
{{ on 'click' (route-action 'update' item)}}
disabled={{item.isInvalid}}
/>
{{/if}}
{{/if}}
<Hds::Button
@text='Cancel'
@color='secondary'
type='reset'
{{ action "cancel" item}}
/>
{{# if (and (not create) (can "delete role" item=item) ) }}
<ConfirmationDialog @message="Are you sure you want to delete this Role?">
<BlockSlot @name="action" as |confirm|>
<button type="button" data-test-delete class="type-delete" {{action confirm 'delete' item}}>Delete</button>
<Hds::Button
@text='Delete'
@color='critical'
{{action confirm 'delete' item}}
data-test-delete
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
{{#if (gt items.length 0)}}
@ -54,7 +77,8 @@
</BlockSlot>
<BlockSlot @name="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>:
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>
@ -62,8 +86,19 @@
</p>
</BlockSlot>
<BlockSlot @name="actions" as |close|>
<button type="button" class="type-delete" {{action execute}}>Yes, Delete</button>
<button type="button" class="type-cancel" {{action close}}>Cancel</button>
<Hds::ButtonSet>
<Hds::Button
@text='Yes, Delete'
@color='critical'
data-test-delete
{{action execute}}
/>
<Hds::Button
@text='Cancel'
@color='secondary'
{{action close}}
/>
</Hds::ButtonSet>
</BlockSlot>
</ModalDialog>
{{else}}
@ -71,6 +106,7 @@
{{/if}}
</BlockSlot>
</ConfirmationDialog>
{{/if}}
{{/if}}
</Hds::ButtonSet>
</div>
</form>

View File

@ -56,7 +56,11 @@ as |route|>
</BlockSlot>
<BlockSlot @name="actions">
{{#if (can "create roles")}}
<a data-test-create href="{{href-to 'dc.acls.roles.create'}}" class="type-create">Create</a>
<Hds::Button
@text='Create'
@route='dc.acls.roles.create'
data-test-create
/>
{{/if}}
</BlockSlot>
<BlockSlot @name="toolbar">
@ -103,11 +107,23 @@ as |route|>
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/commands/acl/role" rel="noopener noreferrer" target="_blank">Documentation on roles</a>
<li>
<Hds::Link::Standalone
@text='Documentation on roles'
@href="{{env 'CONSUL_DOCS_URL'}}/commands/acl/role"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_DOCS_API_URL'}}/acl/roles.html" rel="noopener noreferrer" target="_blank">Read the API Docs</a>
<li>
<Hds::Link::Standalone
@text='Read the API Docs'
@href="{{env 'CONSUL_DOCS_API_URL'}}/acl/roles.html"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -1,30 +1,51 @@
<form>
{{#if (not (token/is-legacy item))}}
{{#if (not (token/is-legacy item))}}
{{partial 'dc/acls/tokens/fieldsets'}}
{{else}}
{{else}}
{{partial 'dc/acls/tokens/fieldsets-legacy'}}
{{/if}}
{{/if}}
{{!TODO: Make this into a slotted component}}
<div>
{{#if (and create (can "create tokens")) }}
<Hds::ButtonSet>
{{#if (and create (can "create tokens")) }}
{{! new tokens can be saved without you filling anything in, old tokens remain using isPristine }}
<button type="submit" {{ action "create" item}} disabled={{if (or (and (token/is-legacy item) item.isPristine) item.isInvalid) 'disabled'}}>Save</button>
{{ else }}
<Hds::Button
@text='Save'
type='submit'
{{ on 'click' (route-action 'create' item)}}
disabled={{if (or (and (token/is-legacy item) item.isPristine) item.isInvalid) 'disabled'}}
/>
{{ else }}
{{#if (can "write token" item=item)}}
<button type="submit" {{ action "update" item}} disabled={{if item.isInvalid 'disabled'}}>Save</button>
<Hds::Button
@text='Save'
type='submit'
{{ on 'click' (route-action 'update' item)}}
disabled={{if item.isInvalid 'disabled'}}
/>
{{/if}}
{{/if}}
<button type="reset" {{ action "cancel" item}}>Cancel</button>
{{# if (and (not create) (can "delete token" item=item token=token) ) }}
{{/if}}
<Hds::Button
@text='Cancel'
@color='secondary'
type='reset'
{{ action "cancel" item}}
/>
{{# if (and (not create) (can "delete token" item=item token=token) ) }}
<ConfirmationDialog @message="Are you sure you want to delete this Token?">
<BlockSlot @name="action" as |confirm|>
<button type="button" data-test-delete class="type-delete" {{action confirm 'delete' item}}>Delete</button>
<Hds::Button
@text='Delete'
@color='critical'
{{action confirm 'delete' item}}
data-test-delete
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<DeleteConfirmation @message={{message}} @execute={{execute}} @cancel={{cancel}} />
</BlockSlot>
</ConfirmationDialog>
{{/if}}
{{/if}}
</Hds::ButtonSet>
</div>
</form>

View File

@ -52,23 +52,46 @@ as |dc partition nspace item create|}}
</BlockSlot>
<BlockSlot @name="actions">
{{#if (not create)}}
<Hds::ButtonSet>
{{#if (not-eq item.AccessorID token.AccessorID)}}
<ConfirmationDialog @message="Are you sure you want to use this ACL token?">
<BlockSlot @name="action" as |confirm|>
<button data-test-use type="button" {{ action confirm 'use' item }}>Use</button>
<Hds::Button
@text='Use'
@color='secondary'
data-test-use
{{ action confirm 'use' item }}
/>
</BlockSlot>
<BlockSlot @name="dialog" as |execute cancel message|>
<p>
{{message}}
</p>
<button type="button" class="type-delete" {{action execute}}>Confirm Use</button>
<button type="button" class="type-cancel" {{action cancel}}>Cancel</button>
<Hds::ButtonSet>
<Hds::Button
@text='Confirm Use'
@color='critical'
data-test-confirm-use
{{action execute}}
/>
<Hds::Button
@text='Cancel'
@color='secondary'
{{action cancel}}
/>
</Hds::ButtonSet>
</BlockSlot>
</ConfirmationDialog>
{{/if}}
{{#if (can "duplicate token" item=item)}}
<button data-test-clone type="button" {{ action "clone" item }}>Duplicate</button>
<Hds::Button
@text='Duplicate'
@color='secondary'
data-test-clone
{{ action "clone" item }}
/>
{{/if}}
</Hds::ButtonSet>
{{/if}}
</BlockSlot>
<BlockSlot @name="content">

View File

@ -59,7 +59,11 @@ as |route|>
</BlockSlot>
<BlockSlot @name="actions">
{{#if (can "create tokens")}}
<a data-test-create href="{{href-to 'dc.acls.tokens.create'}}" class="type-create">Create</a>
<Hds::Button
@text='Create'
@route='dc.acls.tokens.create'
data-test-create
/>
{{/if}}
</BlockSlot>
<BlockSlot @name="toolbar">

View File

@ -54,7 +54,11 @@ as |route|>
</BlockSlot>
<BlockSlot @name="actions">
{{#if (can 'create intentions')}}
<a data-test-create href="{{href-to 'dc.intentions.create'}}" class="type-create">Create</a>
<Hds::Button
@text='Create'
@route='dc.intentions.create'
data-test-create
/>
{{/if}}
</BlockSlot>
<BlockSlot @name="toolbar">
@ -119,11 +123,23 @@ as |route|>
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/commands/intention" rel="noopener noreferrer" target="_blank">Documentation on intentions</a>
<li>
<Hds::Link::Standalone
@text='Documentation on intentions'
@href="{{env 'CONSUL_DOCS_URL'}}/commands/intention"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/connect" rel="noopener noreferrer" target="_blank">Take the tutorial</a>
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/connect"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -138,9 +138,18 @@ as |sort filters parent items|}}
<BlockSlot @name="actions">
{{#if (can 'create kvs')}}
{{#if (not-eq parent.Key '/') }}
<a data-test-create href="{{href-to 'dc.kv.create' parent.Key}}" class="type-create">Create</a>
<Hds::Button
@text='Create'
@isHrefExternal={{false}}
@href="{{href-to 'dc.kv.create' parent.Key}}"
data-test-create
/>
{{else}}
<a data-test-create href="{{href-to 'dc.kv.root-create'}}" class="type-create">Create</a>
<Hds::Button
@text='Create'
@route='dc.kv.root-create'
data-test-create
/>
{{/if}}
{{/if}}
</BlockSlot>
@ -191,11 +200,23 @@ as |sort filters parent items|}}
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/agent/kv" rel="noopener noreferrer" target="_blank">Documentation on K/V</a>
<li>
<Hds::Link::Standalone
@text='Documentation on K/V'
@href="{{env 'CONSUL_DOCS_URL'}}/agent/kv"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/kv" rel="noopener noreferrer" target="_blank">Take the tutorial</a>
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/kv"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -88,25 +88,27 @@
}}
</BlockSlot>
<BlockSlot @name='actions'>
<li class='docs-link'>
<a
href='{{env "CONSUL_DOCS_DEVELOPER_URL"}}/agent'
rel='noopener noreferrer'
target='_blank'
>
{{t 'routes.dc.nodes.index.empty.documentation'}}
</a>
<li>
<Hds::Button
@text={{t 'routes.dc.nodes.index.empty.documentation'}}
@href='{{env "CONSUL_DOCS_DEVELOPER_URL"}}/agent'
@color='tertiary'
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class='learn-link'>
<a
href='{{env
<li>
<Hds::Button
@text={{t 'routes.dc.nodes.index.empty.learn'}}
@href='{{env
"CONSUL_DOCS_LEARN_URL"
}}/tutorials/consul/deployment-guide?in=consul/production-deploy#configure-consul-agents'
rel='noopener noreferrer'
target='_blank'
>
{{t 'routes.dc.nodes.index.empty.learn'}}
</a>
@color='tertiary'
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -118,21 +118,23 @@ as |sort filters items partition nspace|}}
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<Action
<li>
<Hds::Link::Standalone
@text='Documentation on Services'
@href="{{env 'CONSUL_DOCS_URL'}}/commands/services"
@external={{true}}
>
Documentation on Services
</Action>
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<Action
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/services"
@external={{true}}
>
Take the tutorial
</Action>
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -58,9 +58,15 @@ as |route|>
}}
</notice.Body>
<notice.Footer>
{{t "routes.dc.services.instance.upstreams.tproxy-mode.footer"
htmlSafe=true
}}
<p>
<Hds::Link::Standalone
@text={{t "routes.dc.services.instance.upstreams.tproxy-mode.footer.text"}}
@href='{{concat (env 'CONSUL_DOCS_URL') (t "routes.dc.services.instance.upstreams.tproxy-mode.footer.link")}}'
@icon="docs-link"
@iconPosition="trailing"
@size="small"
/>
</p>
</notice.Footer>
</Notice>
{{/if}}

View File

@ -44,7 +44,11 @@ as |route|>
<div class="tab-section">
{{#if (can 'create intention for service' item=item.Service)}}
<Portal @target="app-view-actions">
<a data-test-create href={{href-to 'dc.services.show.intentions.create'}} class="type-create">Create</a>
<Hds::Button
@text='Create'
@route='dc.services.show.intentions.create'
data-test-create
/>
</Portal>
{{/if}}
{{#if (gt items.length 0) }}
@ -107,11 +111,23 @@ as |route|>
}}
</BlockSlot>
<BlockSlot @name="actions">
<li class="docs-link">
<a href="{{env 'CONSUL_DOCS_URL'}}/commands/intention" rel="noopener noreferrer" target="_blank">Documentation on intentions</a>
<li>
<Hds::Link::Standalone
@text='Documentation on intentions'
@href="{{env 'CONSUL_DOCS_URL'}}/commands/intention"
@icon='docs-link'
@iconPosition='trailing'
@size='small'
/>
</li>
<li class="learn-link">
<a href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/connect" rel="noopener noreferrer" target="_blank">Take the tutorial</a>
<li>
<Hds::Link::Standalone
@text='Take the tutorial'
@href="{{env 'CONSUL_DOCS_LEARN_URL'}}/consul/getting-started/connect"
@icon='learn-link'
@iconPosition='trailing'
@size='small'
/>
</li>
</BlockSlot>
</EmptyState>

View File

@ -137,11 +137,23 @@ as |item|}}
{{compute (fn route.t 'documentation.title')}}
</h3>
</header>
{{compute (fn route.t 'documentation.body'
(hash
htmlSafe=true
)
)}}
<div class="flex gap-1.5 flex-col">
<Hds::Link::Standalone
@text={{compute (fn route.t 'documentation.links.license-expiration.text')}}
@href='{{concat (env 'CONSUL_DOCS_URL') (compute (fn route.t 'documentation.links.license-expiration.link'))}}'
@icon='docs-link'
/>
<Hds::Link::Standalone
@text={{compute (fn route.t 'documentation.links.renewing-license.text')}}
@href='{{concat (env 'CONSUL_DOCS_URL') (compute (fn route.t 'documentation.links.renewing-license.link'))}}'
@icon='docs-link'
/>
<Hds::Link::Standalone
@text={{compute (fn route.t 'documentation.links.applying-new-license.text')}}
@href='{{concat (env 'CONSUL_DOCS_URL') (compute (fn route.t 'documentation.links.applying-new-license.link'))}}'
@icon='docs-link'
/>
</div>
</aside>
</section>

View File

@ -87,12 +87,15 @@ as |item|}}
>
<header>
{{compute (fn route.t 'tolerance.link' (hash
htmlSafe=true
))}}
<h2>
{{compute (fn route.t 'tolerance.header')}}
</h2>
<Hds::Link::Standalone
@icon='docs-link'
@iconPosition='trailing'
@text={{compute (fn route.t 'tolerance.link-text')}}
@href='{{concat (env 'CONSUL_DOCS_URL') (compute (fn route.t 'tolerance.link'))}}'
/>
</header>
<section

View File

@ -67,10 +67,10 @@
"@ember/test-helpers": "^2.2.5",
"@glimmer/component": "^1.0.4",
"@glimmer/tracking": "^1.0.4",
"@hashicorp/design-system-components": "^1.0.4",
"@hashicorp/design-system-components": "^1.6.0",
"@hashicorp/design-system-tokens": "^1.0.0",
"@hashicorp/ember-cli-api-double": "^4.0.0",
"@hashicorp/ember-flight-icons": "^3.0.0",
"@hashicorp/ember-flight-icons": "^3.0.2",
"@html-next/vertical-collection": "^4.0.0",
"@lit/reactive-element": "^1.2.1",
"@xstate/fsm": "^1.4.0",

View File

@ -21,7 +21,7 @@ Feature: dc / intentions / deleting: Deleting items with confirmations, success
---
And I click actions on the intentionList.intentions
And I click delete on the intentionList.intentions
And I click confirmDelete on the intentionList.intentions
And I click confirmInlineDelete on the intentionList.intentions
Then a DELETE request was made to "/v1/connect/intentions/exact?source=default%2Fdefault%2Fname&destination=default%2Fdefault%2Fdestination&dc=datacenter"
And "[data-notification]" has the "notification-delete" class
And "[data-notification]" has the "success" class

View File

@ -13,7 +13,7 @@ Feature: dc / kvs / deleting: Deleting items with confirmations, success and err
---
And I click actions on the kvs
And I click delete on the kvs
And I click confirmDelete on the kvs
And I click confirmInlineDelete on the kvs
Then a DELETE request was made to "/v1/kv/key-name?dc=datacenter&ns=@!namespace"
And "[data-notification]" has the "notification-delete" class
And "[data-notification]" has the "success" class

View File

@ -48,7 +48,7 @@ Feature: dc / services / show / intentions / index: Intentions per service
Scenario: I can delete intentions
And I click actions on the intentionList.intentions component
And I click delete on the intentionList.intentions component
And I click confirmDelete on the intentionList.intentions
And I click confirmInlineDelete on the intentionList.intentions
Then a DELETE request was made to "/v1/connect/intentions/exact?source=default%2Fdefault%2Fname&destination=default%2Fdefault%2Fdestination&dc=dc1"
And "[data-notification]" has the "notification-delete" class
And "[data-notification]" has the "success" class

View File

@ -12,13 +12,13 @@ module('Integration | Component | delete confirmation', function (hooks) {
await render(hbs`{{delete-confirmation}}`);
assert.dom('.type-delete').exists({ count: 1 });
assert.dom('[data-test-delete]').exists({ count: 1 });
// Template block usage:
await render(hbs`
{{#delete-confirmation}}{{/delete-confirmation}}
`);
assert.dom('.type-delete').exists({ count: 1 });
assert.dom('[data-test-delete]').exists({ count: 1 });
});
});

View File

@ -7,7 +7,8 @@ export default function (clickable) {
...obj,
...{
delete: clickable(scope + '[data-test-delete]'),
confirmDelete: clickable(scope + 'button.type-delete'),
confirmDelete: clickable(scope + '[data-test-delete]'),
confirmInlineDelete: clickable(scope + 'button.type-delete'),
},
};
};

View File

@ -4,7 +4,7 @@ export default function (visitable, submitable, deletable, cancelable, clickable
deletable({
visit: visitable(['/:dc/acls/:acl', '/:dc/acls/create']),
use: clickable('[data-test-use]'),
confirmUse: clickable('button.type-delete'),
confirmUse: clickable('[data-test-confirm-use]'),
})
),
'main'

View File

@ -13,7 +13,7 @@ export default function (
...cancelable({}, 'main form > div'),
...deletable({}, 'main form > div'),
use: clickable('[data-test-use]'),
confirmUse: clickable('button.type-delete'),
confirmUse: clickable('[data-test-confirm-use]'),
clone: clickable('[data-test-clone]'),
policies: policySelector(),
roles: roleSelector(),

View File

@ -5,8 +5,8 @@ dc:
title: Server status
unassigned: Unassigned Zones
tolerance:
link: |
<a href="{CONSUL_DOCS_URL}/architecture/improving-consul-resilience#strategies-to-increase-fault-tolerance" target="_blank" rel="noopener noreferrer">Learn how to improve fault tolerance</a>
link-text: Learn how to improve fault tolerance
link: /architecture/improving-consul-resilience#strategies-to-increase-fault-tolerance
header: Server fault tolerance
immediate:
header: Immediate
@ -34,25 +34,16 @@ dc:
</p>
documentation:
title: Learn More
body: |
<ul>
<li>
<a href="{CONSUL_DOCS_URL}/enterprise/license/faq#q-is-there-a-grace-period-when-licenses-expire" target="_blank" rel="noopener noreferrer">
License expiration
</a>
</li>
<li>
<a href="{CONSUL_DOCS_URL}/enterprise/license/faq#q-how-can-i-renew-a-license" target="_blank" rel="noopener noreferrer">
Renewing a license
</a>
</li>
<li>
<a href="{CONSUL_DOCS_LEARN_URL}/tutorials/nomad/hashicorp-enterprise-license?in=consul/enterprise" target="_blank" rel="noopener noreferrer">
Applying a new license
</a>
</li>
</ul>
links:
license-expiration:
text: License expiration
link: '/enterprise/license/faq#q-is-there-a-grace-period-when-licenses-expire'
renewing-license:
text: Renewing a license
link: '/enterprise/license/faq#q-how-can-i-renew-a-license'
applying-new-license:
text: Applying a new license
link: '/tutorials/nomad/hashicorp-enterprise-license?in=consul/enterprise'
nodes:
index:
agentless:
@ -265,10 +256,9 @@ dc:
<p>
The upstreams listed on this page have been defined in a proxy registration. There may be more upstreams, though, as "transparent" mode is enabled on this proxy.
</p>
footer: |
<p>
<a href="{CONSUL_DOCS_URL}/connect/transparent-proxy" target="_blank" rel="noopener noreferrer">Read the documentation
</p>
footer:
link: "/connect/transparent-proxy"
text: Read the documentation
empty: |
<p>
This Service Instance has no Upstreams{items, select,

View File

@ -2927,6 +2927,15 @@
ember-cli-version-checker "^5.1.2"
semver "^7.3.5"
"@embroider/addon-shim@^1.0.0":
version "1.8.4"
resolved "https://registry.yarnpkg.com/@embroider/addon-shim/-/addon-shim-1.8.4.tgz#0e7f32c5506bf0f3eb0840506e31c36c7053763c"
integrity sha512-sFhfWC0vI18KxVenmswQ/ShIvBg4juL8ubI+Q3NTSdkCTeaPQ/DIOUF6oR5DCQ8eO/TkIaw+kdG3FkTY6yNJqA==
dependencies:
"@embroider/shared-internals" "^2.0.0"
broccoli-funnel "^3.0.8"
semver "^7.3.8"
"@embroider/addon-shim@^1.5.0":
version "1.8.3"
resolved "https://registry.yarnpkg.com/@embroider/addon-shim/-/addon-shim-1.8.3.tgz#2368510b8ce42d50d02cb3289c32e260dfa34bd9"
@ -3147,6 +3156,20 @@
semver "^7.3.5"
typescript-memoize "^1.0.1"
"@embroider/shared-internals@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@embroider/shared-internals/-/shared-internals-2.0.0.tgz#d8205ec6944362aeecfbb51143db352430ced316"
integrity sha512-qZ2/xky9mWm5YC6noOa6AiAwgISEQ78YTZNv4SNu2PFgEK/H+Ha/3ddngzGSsnXkVnIHZyxIBzhxETonQYHY9g==
dependencies:
babel-import-util "^1.1.0"
ember-rfc176-data "^0.3.17"
fs-extra "^9.1.0"
js-string-escape "^1.0.1"
lodash "^4.17.21"
resolve-package-path "^4.0.1"
semver "^7.3.5"
typescript-memoize "^1.0.1"
"@embroider/util@^0.39.1 || ^0.40.0 || ^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@embroider/util/-/util-0.41.0.tgz#5324cb4742aa4ed8d613c4f88a466f73e4e6acc1"
@ -3399,19 +3422,25 @@
faker "^4.1.0"
js-yaml "^3.13.1"
"@hashicorp/design-system-components@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@hashicorp/design-system-components/-/design-system-components-1.0.4.tgz#e258cad1a41b00db3363db25bfdafaa598326b98"
integrity sha512-aaOncgPH4yDEvQuFfOa/cwAOttxwbaEdaENEl+88EOi/HLUe0mdS2HgpC96w3sWhedE/xylCgSHz0DemIj5dJQ==
"@hashicorp/design-system-components@^1.6.0":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@hashicorp/design-system-components/-/design-system-components-1.6.1.tgz#da04f1199cdce78dcf6591c3678377b87bd67424"
integrity sha512-nfuY5KLK3kQWRfrFOIEEoSSca6LwZ9Zss13glHHyAIFt/gJ1pjSpcYj2XTukdjfAvx70qwQbHPPaAUXZ00vtoA==
dependencies:
"@hashicorp/design-system-tokens" "^1.0.0"
"@hashicorp/ember-flight-icons" "^2.0.12"
ember-auto-import "^2.4.1"
"@hashicorp/design-system-tokens" "^1.4.0"
"@hashicorp/ember-flight-icons" "^3.0.2"
dialog-polyfill "^0.5.6"
ember-auto-import "^2.4.2"
ember-cached-decorator-polyfill "^0.1.4"
ember-cli-babel "^7.26.11"
ember-cli-htmlbars "^6.0.1"
ember-cli-htmlbars "^6.1.0"
ember-cli-sass "^10.0.1"
ember-composable-helpers "^4.4.1"
ember-focus-trap "^1.0.1"
ember-keyboard "^8.1.0"
ember-named-blocks-polyfill "^0.2.5"
ember-style-modifier "^0.8.0"
ember-truth-helpers "^3.0.0"
sass "^1.43.4"
"@hashicorp/design-system-tokens@^1.0.0":
@ -3419,6 +3448,11 @@
resolved "https://registry.yarnpkg.com/@hashicorp/design-system-tokens/-/design-system-tokens-1.0.0.tgz#06ab55873ef444b0958a5192db310278c6501f0b"
integrity sha512-akziX9jiHnQ8KfJA6s8l+98Ukz30C5Lw7BpSPeTduOmdOlJv1uP7w4TV0hC6VIDMDrJrxIF5Y/HnpSCdQGlxQA==
"@hashicorp/design-system-tokens@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@hashicorp/design-system-tokens/-/design-system-tokens-1.4.0.tgz#2d42bd7d9250b01f77618663b3b92004be840af7"
integrity sha512-xZI5lom+qPi5B4qUDgXcuTc+A8/NQdXXBoIfB7NUnY/GRp4kOkxNkgScPj8fvAFvUuLdiCAQhpLU54z1A/Q3cA==
"@hashicorp/ember-cli-api-double@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@hashicorp/ember-cli-api-double/-/ember-cli-api-double-4.0.0.tgz#fd6181229c589b4db93f1784d022db064c61ec76"
@ -3434,34 +3468,20 @@
pretender "^3.2.0"
recursive-readdir-sync "^1.0.6"
"@hashicorp/ember-flight-icons@^2.0.12":
version "2.0.12"
resolved "https://registry.yarnpkg.com/@hashicorp/ember-flight-icons/-/ember-flight-icons-2.0.12.tgz#788adf7a4fedc468d612d35b604255df948f4012"
integrity sha512-8fHPGaSpMkr5dLWaruwbq9INwZCi2EyTof/TR/dL8PN4UbCuY+KXNqG0lLIKNGFFTj09B1cO303m5GUfKKDGKQ==
"@hashicorp/ember-flight-icons@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@hashicorp/ember-flight-icons/-/ember-flight-icons-3.0.2.tgz#8d884c07842a6c88df18ca680d7883a59222a2ba"
integrity sha512-WomQg1hw/IHA1N9hC77WbTNazVXqu2RdRoaVCGT99NTXQ4S7Bw7vhHheR4JAgt10ksMZFI3X/bJVHxFfjUCkSQ==
dependencies:
"@hashicorp/flight-icons" "^2.10.0"
"@hashicorp/flight-icons" "^2.12.0"
ember-auto-import "^2.4.2"
ember-cli-babel "^7.26.11"
ember-cli-htmlbars "^6.0.1"
ember-cli-htmlbars "^6.1.0"
"@hashicorp/ember-flight-icons@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@hashicorp/ember-flight-icons/-/ember-flight-icons-3.0.0.tgz#fddeb8adfb036aa3573c55b7236b34172b49cba9"
integrity sha512-+QrV38Ix9dWLwMzdVcMcSmFfeSVGvWvB+3OVBq3ltOTmnoLPIAx8LT9UDZUZ1wa65ciO+a1YzLMmwWnQgX/r9Q==
dependencies:
"@hashicorp/flight-icons" "^2.11.0"
ember-auto-import "^2.4.1"
ember-cli-babel "^7.26.11"
ember-cli-htmlbars "^6.0.1"
"@hashicorp/flight-icons@^2.10.0":
version "2.10.0"
resolved "https://registry.yarnpkg.com/@hashicorp/flight-icons/-/flight-icons-2.10.0.tgz#24b03043bacda16e505200e6591dfef896ddacf1"
integrity sha512-jYUA0M6Tz+4RAudil+GW/fHbhZPcKCiIZZAguBDviqbLneMkMgPOBgbXWCGWsEQ1fJzP2cXbUaio8L0aQZPWQw==
"@hashicorp/flight-icons@^2.11.0":
version "2.11.0"
resolved "https://registry.yarnpkg.com/@hashicorp/flight-icons/-/flight-icons-2.11.0.tgz#1500be99a42ee8512e7caece4bdae60ce8790577"
integrity sha512-teFkUY2di63JZ2gsegQgS+3f5YEP+GPuycB1Z2O+weInIrL33Ds0/J+lxFCmi2vkPAeY5xOnsclHYnhU6xOSmA==
"@hashicorp/flight-icons@^2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@hashicorp/flight-icons/-/flight-icons-2.12.0.tgz#48bc21f21678668ffe9147b181a2991d8b151fc7"
integrity sha512-PhjTTHCjoq4EJirifbxLxnxXnCRf1NUAYZ1WnFW8i0yOmmax6fgjsJRPlf0VIGsR8R7isFpjuy6gJ5c7mNhE0w==
"@html-next/vertical-collection@^4.0.0":
version "4.0.0"
@ -4874,6 +4894,11 @@ babel-import-util@^1.1.0:
resolved "https://registry.yarnpkg.com/babel-import-util/-/babel-import-util-1.2.2.tgz#1027560e143a4a68b1758e71d4fadc661614e495"
integrity sha512-8HgkHWt5WawRFukO30TuaL9EiDUOdvyKtDwLma4uBNeUSDbOO0/hiPfavrOWxSS6J6TKXfukWHZ3wiqZhJ8ONQ==
babel-import-util@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/babel-import-util/-/babel-import-util-1.3.0.tgz#dc9251ea39a7747bd586c1c13b8d785a42797f8e"
integrity sha512-PPzUT17eAI18zn6ek1R3sB4Krc/MbnmT1MkZQFmyhjoaEGBVwNABhfVU9+EKcDSKrrOm9OIpGhjxukx1GCiy1g==
babel-loader@^8.0.6, babel-loader@^8.1.0:
version "8.2.2"
resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81"
@ -4950,6 +4975,13 @@ babel-plugin-ember-template-compilation@^1.0.0:
magic-string "^0.25.7"
string.prototype.matchall "^4.0.5"
babel-plugin-ember-template-compilation@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/babel-plugin-ember-template-compilation/-/babel-plugin-ember-template-compilation-2.0.0.tgz#41d895874ba6119dd461f61993c16d1154bf8a57"
integrity sha512-d+4jaB2ik0rt9TH0K9kOlKJeRBHEb373FgFMcU9ZaJL2zYuVXe19bqy+cWlLpLf1tpOBcBG9QTlFBCoImlOt1g==
dependencies:
babel-import-util "^1.3.0"
babel-plugin-filter-imports@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-4.0.0.tgz#068f8da15236a96a9602c36dc6f4a6eeca70a4f4"
@ -7717,6 +7749,11 @@ dezalgo@^1.0.0:
asap "^2.0.0"
wrappy "1"
dialog-polyfill@^0.5.6:
version "0.5.6"
resolved "https://registry.yarnpkg.com/dialog-polyfill/-/dialog-polyfill-0.5.6.tgz#7507b4c745a82fcee0fa07ce64d835979719599a"
integrity sha512-ZbVDJI9uvxPAKze6z146rmfUZjBqNEwcnFTVamQzXH+svluiV7swmVIGr7miwADgfgt1G2JQIytypM9fbyhX4w==
didyoumean@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
@ -7991,7 +8028,7 @@ ember-auto-import@^1.5.3, ember-auto-import@^1.6.0:
walk-sync "^0.3.3"
webpack "^4.43.0"
ember-auto-import@^2.2.3, ember-auto-import@^2.4.1, ember-auto-import@^2.4.2:
ember-auto-import@^2.2.3, ember-auto-import@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/ember-auto-import/-/ember-auto-import-2.4.2.tgz#d4d3bc6885a11cf124f606f5c37169bdf76e37ae"
integrity sha512-REh+1aJWpTkvN42a/ga41OuRpUsSW7UQfPr2wPtYx56o/xoSNhVBXejy7yV9ObrkN7gogz6fs2xZwih5cOwpYg==
@ -8045,6 +8082,26 @@ ember-basic-dropdown@3.0.21, ember-basic-dropdown@^3.0.16:
ember-style-modifier "^0.6.0"
ember-truth-helpers "^2.1.0 || ^3.0.0"
ember-cache-primitive-polyfill@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ember-cache-primitive-polyfill/-/ember-cache-primitive-polyfill-1.0.1.tgz#a27075443bd87e5af286c1cd8a7df24e3b9f6715"
integrity sha512-hSPcvIKarA8wad2/b6jDd/eU+OtKmi6uP+iYQbzi5TQpjsqV6b4QdRqrLk7ClSRRKBAtdTuutx+m+X+WlEd2lw==
dependencies:
ember-cli-babel "^7.22.1"
ember-cli-version-checker "^5.1.1"
ember-compatibility-helpers "^1.2.1"
silent-error "^1.1.1"
ember-cached-decorator-polyfill@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/ember-cached-decorator-polyfill/-/ember-cached-decorator-polyfill-0.1.4.tgz#f1e2c65cc78d0d9c4ac0e047e643af477eb85ace"
integrity sha512-JOK7kBCWsTVCzmCefK4nr9BACDJk0owt9oIUaVt6Q0UtQ4XeAHmoK5kQ/YtDcxQF1ZevHQFdGhsTR3JLaHNJgA==
dependencies:
"@glimmer/tracking" "^1.0.4"
ember-cache-primitive-polyfill "^1.0.1"
ember-cli-babel "^7.21.0"
ember-cli-babel-plugin-helpers "^1.1.1"
ember-can@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/ember-can/-/ember-can-4.2.0.tgz#08bfec3b2b57aad3dc6e4dc36fe9692bd1794dab"
@ -8310,6 +8367,26 @@ ember-cli-htmlbars@^6.0.1:
silent-error "^1.1.1"
walk-sync "^2.2.0"
ember-cli-htmlbars@^6.1.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-6.2.0.tgz#18ec48ee1c93f9eed862a64eb24a9d14604f1dfc"
integrity sha512-j5EGixjGau23HrqRiW/JjoAovg5UBHfjbyN7wX5ekE90knIEqUUj1z/Mo/cTx/J2VepQ2lE6HdXW9LWQ/WdMtw==
dependencies:
"@ember/edition-utils" "^1.2.0"
babel-plugin-ember-template-compilation "^2.0.0"
babel-plugin-htmlbars-inline-precompile "^5.3.0"
broccoli-debug "^0.6.5"
broccoli-persistent-filter "^3.1.2"
broccoli-plugin "^4.0.3"
ember-cli-version-checker "^5.1.2"
fs-tree-diff "^2.0.1"
hash-for-dep "^1.5.1"
heimdalljs-logger "^0.1.10"
js-string-escape "^1.0.1"
semver "^7.3.4"
silent-error "^1.1.1"
walk-sync "^2.2.0"
ember-cli-inject-live-reload@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-2.0.2.tgz#95edb543b386239d35959e5ea9579f5382976ac7"
@ -8730,6 +8807,16 @@ ember-compatibility-helpers@^1.2.5:
fs-extra "^9.1.0"
semver "^5.4.1"
ember-composable-helpers@^4.4.1:
version "4.5.0"
resolved "https://registry.yarnpkg.com/ember-composable-helpers/-/ember-composable-helpers-4.5.0.tgz#94febbdf4348e64f45f7a6f993f326e32540a61e"
integrity sha512-XjpDLyVPsLCy6kd5dIxZonOECCO6AA5sY5Hr6tYUbJg3s5ghFAiFWaNcYraYC+fL2yPJQAswwpfwGlQORUJZkw==
dependencies:
"@babel/core" "^7.0.0"
broccoli-funnel "2.0.1"
ember-cli-babel "^7.26.3"
resolve "^1.10.0"
ember-composable-helpers@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/ember-composable-helpers/-/ember-composable-helpers-5.0.0.tgz#055bab3a3e234ab2917499b1465e968c253ca885"
@ -8862,6 +8949,14 @@ ember-factory-for-polyfill@^1.3.1:
dependencies:
ember-cli-version-checker "^2.1.0"
ember-focus-trap@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ember-focus-trap/-/ember-focus-trap-1.0.1.tgz#a99565f6ce55d500b92a0965e79e3ad04219f157"
integrity sha512-ZUyq5ZkIuXp+ng9rCMkqBh36/V95PltL7iljStkma4+651xlAy3Z84L9WOu/uOJyVpNUxii8RJBbAySHV6c+RQ==
dependencies:
"@embroider/addon-shim" "^1.0.0"
focus-trap "^6.7.1"
ember-get-config@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/ember-get-config/-/ember-get-config-0.3.0.tgz#a73a1a87b48d9dde4c66a0e52ed5260b8a48cfbd"
@ -9286,6 +9381,14 @@ ember-style-modifier@^0.6.0:
ember-cli-babel "^7.21.0"
ember-modifier "^2.1.0"
ember-style-modifier@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/ember-style-modifier/-/ember-style-modifier-0.8.0.tgz#ef46b3f288e63e3d850418ea8dc6f7b12edde721"
integrity sha512-I7M+oZ+poYYOP7n521rYv7kkYZbxotL8VbtHYxLQ3tasRZYQJ21qfu3vVjydSjwyE3w7EZRgKngBoMhKSAEZnw==
dependencies:
ember-cli-babel "^7.26.6"
ember-modifier "^3.2.7"
ember-template-lint@^2.0.1:
version "2.21.0"
resolved "https://registry.yarnpkg.com/ember-template-lint/-/ember-template-lint-2.21.0.tgz#7e120abf309a8810eeed26c52377943faf15a95b"
@ -10405,6 +10508,13 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
focus-trap@^6.7.1:
version "6.9.4"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-6.9.4.tgz#436da1a1d935c48b97da63cd8f361c6f3aa16444"
integrity sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==
dependencies:
tabbable "^5.3.3"
focusable-selectors@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/focusable-selectors/-/focusable-selectors-0.3.0.tgz#0cf0c617c0f130b3d421be6787acb95b0b4936c4"
@ -15578,6 +15688,13 @@ semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
semver@^7.3.8:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
dependencies:
lru-cache "^6.0.0"
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
@ -16405,6 +16522,11 @@ sync-disk-cache@^2.0.0:
rimraf "^3.0.0"
username-sync "^1.0.2"
tabbable@^5.3.3:
version "5.3.3"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-5.3.3.tgz#aac0ff88c73b22d6c3c5a50b1586310006b47fbf"
integrity sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==
table@^6.0.9:
version "6.8.0"
resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca"