VAULT-42410 - Refactored empty state component for pki directory (#12805) (#13019)

* VAULT-42410 - refactored empty state component for pki directory

* added data-test attributes

* fixed failing tests

Co-authored-by: mohit-hashicorp <mohit.ojha@hashicorp.com>
This commit is contained in:
Vault Automation 2026-03-13 23:13:42 -04:00 committed by GitHub
parent e5e8399f7b
commit 94c5e6b68e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 181 additions and 130 deletions

View file

@ -29,13 +29,17 @@
<FormField @attr={{field}} @model={{@clusterForm}} @showHelpText={{false}} />
{{/each}}
{{else}}
<EmptyState
class="is-shadowless"
@title="You do not have permission to set this mount's the cluster config"
@message="Ask your administrator if you think you should have access to:"
>
<code>POST /{{@backend}}/config/cluster</code>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 bottom-padding-32 is-marginless" as |A|>
<A.Header
@title="You do not have permission to set this mount's the cluster config"
@titleTag="h2"
data-test-empty-state-title
/>
<A.Body @text="Ask your administrator if you think you should have access to:" data-test-empty-state-message />
<A.Footer data-test-empty-state-actions>
<code>POST /{{@backend}}/config/cluster</code>
</A.Footer>
</Hds::ApplicationState>
{{/if}}
</fieldset>
@ -48,13 +52,17 @@
<FormField @attr={{field}} @model={{@acmeForm}} @showHelpText={{false}} />
{{/each}}
{{else}}
<EmptyState
class="is-shadowless"
@title="You do not have permission to set this mount's ACME config"
@message="Ask your administrator if you think you should have access to:"
>
<code>POST /{{@backend}}/config/acme</code>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 bottom-padding-32 is-marginless" as |A|>
<A.Header
@title="You do not have permission to set this mount's ACME config"
@titleTag="h2"
data-test-empty-state-title
/>
<A.Body @text="Ask your administrator if you think you should have access to:" data-test-empty-state-message />
<A.Footer data-test-empty-state-actions>
<code>POST /{{@backend}}/config/acme</code>
</A.Footer>
</Hds::ApplicationState>
{{/if}}
</fieldset>
@ -67,13 +75,17 @@
<FormField @attr={{field}} @model={{@urlsForm}} @showHelpText={{false}} />
{{/each}}
{{else}}
<EmptyState
class="is-shadowless"
@title="You do not have permission to set this mount's URLs"
@message="Ask your administrator if you think you should have access to:"
>
<code>POST /{{@backend}}/config/urls</code>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 bottom-padding-32 is-marginless" as |A|>
<A.Header
@title="You do not have permission to set this mount's URLs"
@titleTag="h2"
data-test-empty-state-title
/>
<A.Body @text="Ask your administrator if you think you should have access to:" data-test-empty-state-message />
<A.Footer data-test-empty-state-actions>
<code>POST /{{@backend}}/config/urls</code>
</A.Footer>
</Hds::ApplicationState>
{{/if}}
</fieldset>
@ -114,12 +126,17 @@
{{/each-in}}
{{/each}}
{{else}}
<EmptyState
@title="You do not have permission to set this mount's revocation configuration"
@message="Ask your administrator if you think you should have access to:"
>
<code>POST /{{@backend}}/config/crl</code>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 bottom-padding-32 is-marginless" as |A|>
<A.Header
@title="You do not have permission to set this mount's revocation configuration"
@titleTag="h2"
data-test-empty-state-title
/>
<A.Body @text="Ask your administrator if you think you should have access to:" data-test-empty-state-message />
<A.Footer data-test-empty-state-actions>
<code>POST /{{@backend}}/config/crl</code>
</A.Footer>
</Hds::ApplicationState>
{{/if}}
</fieldset>

View file

@ -58,7 +58,10 @@
@onComplete={{transition-to "vault.cluster.secrets.backend.pki.overview"}}
/>
{{else}}
<EmptyState @title="Choose an option" @message="To see configuration options, choose your desired output above." />
<Hds::ApplicationState class="top-padding-32 bottom-padding-32 is-marginless" as |A|>
<A.Header @title="Choose an option" @titleTag="h2" data-test-empty-state-title />
<A.Body @text="To see configuration options, choose your desired output above." data-test-empty-state-message />
</Hds::ApplicationState>
<hr class="has-background-gray-100" />
<Hds::ButtonSet>
<Hds::Button @text="Done" disabled={{true}} data-test-submit />

View file

@ -125,14 +125,18 @@
{{/each}}
</:list>
<:empty>
<EmptyState @title="PKI not configured" @message={{this.notConfiguredMessage}}>
<Hds::Link::Standalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{@backend}}
/>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="PKI not configured" @titleTag="h2" data-test-empty-state-title />
<A.Body @text={{this.notConfiguredMessage}} data-test-empty-state-message />
<A.Footer data-test-empty-state-actions as |F|>
<F.LinkStandalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{@backend}}
/>
</A.Footer>
</Hds::ApplicationState>
</:empty>
</PkiPaginatedList>

View file

@ -82,18 +82,25 @@
</:list>
<:empty>
<EmptyState @title="No keys yet" @message="There are no keys in this PKI mount. You can generate or create one." />
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="No keys yet" @titleTag="h2" data-test-empty-state-title />
<A.Body @text="There are no keys in this PKI mount. You can generate or create one." data-test-empty-state-message />
</Hds::ApplicationState>
</:empty>
<:configure>
<EmptyState @title="PKI not configured" @message={{this.notConfiguredMessage}}>
<Hds::Link::Standalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{@backend}}
/>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="PKI not configured" @titleTag="h2" data-test-empty-state-title />
<A.Body @text={{this.notConfiguredMessage}} data-test-empty-state-message />
<A.Footer data-test-empty-state-actions as |F|>
<F.LinkStandalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{@backend}}
/>
</A.Footer>
</Hds::ApplicationState>
</:configure>
</PkiPaginatedList>

View file

@ -97,19 +97,23 @@
{{/each}}
{{/if}}
{{else}}
<EmptyState
@title="Tidy status unavailable"
@message="After the next tidy operation has been performed, information about the current or most recent tidy operation will display here."
>
<Hds::Button
@color="tertiary"
@icon="chevron-right"
@iconPosition="trailing"
{{on "click" (fn (mut this.tidyOptionsModal) true)}}
data-test-tidy-empty-state-configure
@text="Tidy"
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="Tidy status unavailable" @titleTag="h2" data-test-empty-state-title />
<A.Body
@text="After the next tidy operation has been performed, information about the current or most recent tidy operation will display here."
data-test-empty-state-message
/>
</EmptyState>
<A.Footer data-test-empty-state-actions as |F|>
<F.Button
@color="tertiary"
@icon="chevron-right"
@iconPosition="trailing"
{{on "click" (fn (mut this.tidyOptionsModal) true)}}
data-test-tidy-empty-state-configure
@text="Tidy"
/>
</A.Footer>
</Hds::ApplicationState>
{{/if}}
{{! TIDY OPTIONS MODAL }}

View file

@ -101,10 +101,13 @@
/>
{{/each}}
{{else}}
<EmptyState
@title="You do not have permissions to set URLs."
@message="These are not required but will need to be configured later. You can do this via the CLI or by changing your permissions and returning to this form."
/>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="You do not have permissions to set URLs." @titleTag="h2" data-test-empty-state-title />
<A.Body
@text="These are not required but will need to be configured later. You can do this via the CLI or by changing your permissions and returning to this form."
data-test-empty-state-message
/>
</Hds::ApplicationState>
{{/if}}
</fieldset>
{{/if}}

View file

@ -47,20 +47,27 @@
{{/each}}
</:list>
<:empty>
<EmptyState
@title="No certificates yet"
@message="When created, certificates will be listed here. Select a role to start generating certificates"
/>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="No certificates yet" @titleTag="h2" data-test-empty-state-title />
<A.Body
@text="When created, certificates will be listed here. Select a role to start generating certificates"
data-test-empty-state-message
/>
</Hds::ApplicationState>
</:empty>
<:configure>
<EmptyState @title="PKI not configured" @message={{this.notConfiguredMessage}}>
<Hds::Link::Standalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{this.model.parentModel.id}}
/>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="PKI not configured" @titleTag="h2" data-test-empty-state-title />
<A.Body @text={{this.notConfiguredMessage}} data-test-empty-state-message />
<A.Footer data-test-empty-state-actions as |F|>
<F.LinkStandalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{this.model.parentModel.id}}
/>
</A.Footer>
</Hds::ApplicationState>
</:configure>
</PkiPaginatedList>

View file

@ -17,13 +17,17 @@
@canListRoles={{this.model.canListRoles}}
/>
{{else}}
<EmptyState @title="PKI not configured" @message={{this.notConfiguredMessage}}>
<Hds::Link::Standalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{this.model.engine.id}}
/>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="PKI not configured" @titleTag="h2" data-test-empty-state-title />
<A.Body @text={{this.notConfiguredMessage}} data-test-empty-state-message />
<A.Footer data-test-empty-state-actions as |F|>
<F.LinkStandalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{this.model.engine.id}}
/>
</A.Footer>
</Hds::ApplicationState>
{{/if}}

View file

@ -57,20 +57,27 @@
{{/each}}
</:list>
<:empty>
<EmptyState
@title="No roles yet"
@message="When created, roles will be listed here. Create a role to start generating certificates."
/>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="No roles yet" @titleTag="h2" data-test-empty-state-title />
<A.Body
@text="When created, roles will be listed here. Create a role to start generating certificates."
data-test-empty-state-message
/>
</Hds::ApplicationState>
</:empty>
<:configure>
<EmptyState @title="PKI not configured" @message={{this.notConfiguredMessage}}>
<Hds::Link::Standalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{this.model.parentModel.id}}
/>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="PKI not configured" @titleTag="h2" data-test-empty-state-title />
<A.Body @text={{this.notConfiguredMessage}} data-test-empty-state-message />
<A.Footer data-test-empty-state-actions as |F|>
<F.LinkStandalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{this.model.parentModel.id}}
/>
</A.Footer>
</Hds::ApplicationState>
</:configure>
</PkiPaginatedList>

View file

@ -9,13 +9,17 @@
<Page::PkiTidyStatus @enabled={{this.model.autoTidyConfig.enabled}} @tidyStatus={{this.tidyStatus}} />
{{else}}
<Toolbar />
<EmptyState @title="PKI not configured" @message={{this.notConfiguredMessage}}>
<Hds::Link::Standalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{this.model.engine.id}}
/>
</EmptyState>
<Hds::ApplicationState class="top-padding-32 is-marginless" as |A|>
<A.Header @title="PKI not configured" @titleTag="h2" data-test-empty-state-title />
<A.Body @text={{this.notConfiguredMessage}} data-test-empty-state-message />
<A.Footer data-test-empty-state-actions as |F|>
<F.LinkStandalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure PKI"
@route="configuration.create"
@model={{this.model.engine.id}}
/>
</A.Footer>
</Hds::ApplicationState>
{{/if}}

View file

@ -622,16 +622,14 @@ module('Acceptance | pki workflow', function (hooks) {
await login(this.mixedConfigCapabilities);
await visit(`/vault/secrets-engines/${this.mountPath}/pki/configuration/edit`);
assert
.dom(`${PKI_CONFIG_EDIT.configEditSection} [data-test-component="empty-state"]`)
.hasText(
`You do not have permission to set this mount's the cluster config Ask your administrator if you think you should have access to: POST /${this.mountPath}/config/cluster`
);
.dom(`${PKI_CONFIG_EDIT.configEditSection} ${GENERAL.emptyStateTitle}`)
.hasText("You do not have permission to set this mount's the cluster config");
assert.dom(PKI_CONFIG_EDIT.acmeEditSection).exists();
assert.dom(PKI_CONFIG_EDIT.urlsEditSection).exists();
assert.dom(PKI_CONFIG_EDIT.crlEditSection).exists();
assert.dom(`${PKI_CONFIG_EDIT.acmeEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${PKI_CONFIG_EDIT.urlsEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${PKI_CONFIG_EDIT.crlEditSection} [data-test-component="empty-state"]`).doesNotExist();
assert.dom(`${PKI_CONFIG_EDIT.acmeEditSection} ${GENERAL.emptyStateTitle}`).doesNotExist();
assert.dom(`${PKI_CONFIG_EDIT.urlsEditSection} ${GENERAL.emptyStateTitle}`).doesNotExist();
assert.dom(`${PKI_CONFIG_EDIT.crlEditSection} ${GENERAL.emptyStateTitle}`).doesNotExist();
await click(PKI_CONFIG_EDIT.crlToggleInput('expiry'));
await click(PKI_CONFIG_EDIT.saveButton);
assert.strictEqual(currentURL(), `/vault/secrets-engines/${this.mountPath}/pki/configuration`);

View file

@ -9,6 +9,7 @@ import { click, fillIn, render } from '@ember/test-helpers';
import { setupEngine } from 'ember-engines/test-support';
import { hbs } from 'ember-cli-htmlbars';
import sinon from 'sinon';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { PKI_CONFIG_EDIT } from 'vault/tests/helpers/pki/pki-selectors';
import { configCapabilities } from 'vault/tests/helpers/pki/pki-helpers';
import PkiConfigClusterForm from 'vault/forms/secrets/pki/config/cluster';
@ -306,25 +307,17 @@ module('Integration | Component | page/pki-configuration-edit', function (hooks)
await this.renderComponent();
assert
.dom(`${PKI_CONFIG_EDIT.configEditSection} [data-test-component="empty-state"]`)
.hasText(
"You do not have permission to set this mount's the cluster config Ask your administrator if you think you should have access to: POST /pki-engine/config/cluster"
);
.dom(`${PKI_CONFIG_EDIT.configEditSection} ${GENERAL.emptyStateTitle}`)
.hasText("You do not have permission to set this mount's the cluster config");
assert
.dom(`${PKI_CONFIG_EDIT.acmeEditSection} [data-test-component="empty-state"]`)
.hasText(
"You do not have permission to set this mount's ACME config Ask your administrator if you think you should have access to: POST /pki-engine/config/acme"
);
.dom(`${PKI_CONFIG_EDIT.acmeEditSection} ${GENERAL.emptyStateTitle}`)
.hasText("You do not have permission to set this mount's ACME config");
assert
.dom(`${PKI_CONFIG_EDIT.urlsEditSection} [data-test-component="empty-state"]`)
.hasText(
"You do not have permission to set this mount's URLs Ask your administrator if you think you should have access to: POST /pki-engine/config/urls"
);
.dom(`${PKI_CONFIG_EDIT.urlsEditSection} ${GENERAL.emptyStateTitle}`)
.hasText("You do not have permission to set this mount's URLs");
assert
.dom(`${PKI_CONFIG_EDIT.crlEditSection} [data-test-component="empty-state"]`)
.hasText(
"You do not have permission to set this mount's revocation configuration Ask your administrator if you think you should have access to: POST /pki-engine/config/crl"
);
.dom(`${PKI_CONFIG_EDIT.crlEditSection} ${GENERAL.emptyStateTitle}`)
.hasText("You do not have permission to set this mount's revocation configuration");
});
test('it renders alert banner and endpoint respective error', async function (assert) {