Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: add pagination to new PKI #23193

Merged
merged 24 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
89a09a3
Create pki-paginated-list component
hashishaw Sep 20, 2023
d162fc7
Add pagination to PKI certificates
hashishaw Sep 20, 2023
34d8609
Add pagination to PKI roles
hashishaw Sep 20, 2023
4d7afe8
updates to pki-paginated-list, remove filter
hashishaw Sep 20, 2023
7e35e46
rename currentPage param to page, remove pageFilter params
hashishaw Sep 20, 2023
fa00fb7
PKI Paginated List test stub
hashishaw Sep 20, 2023
ff71561
Use correct controller for qp
hashishaw Sep 20, 2023
a7db129
clean up key list template
hashishaw Sep 20, 2023
511e999
Pagination for issuers
hashishaw Sep 20, 2023
005ce76
move actions and attrs to components
hashishaw Sep 20, 2023
ff6af41
make dashboard test use custom pki mount
hashishaw Sep 20, 2023
cd896c5
Add query option for skip cache on lazyPaginatedQuery
hashishaw Sep 20, 2023
089c806
Automatically use fresh cache on list views when page = 1
hashishaw Sep 20, 2023
522847e
Dont manually clear dataset
hashishaw Sep 20, 2023
3792dfe
fix tests
hashishaw Sep 20, 2023
77acb0b
Merge branch 'main' into ui/VAULT-20093/pki-pagination
hashishaw Sep 20, 2023
a4efdbd
Add changelog
hashishaw Sep 20, 2023
196314a
Merge branch 'main' into ui/VAULT-20093/pki-pagination
hashishaw Sep 21, 2023
9664ea1
Dont redirect after cert revoke
hashishaw Sep 21, 2023
76f4ac1
Address PR comments
hashishaw Sep 21, 2023
03799ff
fix hasConfig
hashishaw Sep 21, 2023
fe82d33
Merge branch 'main' into ui/VAULT-20093/pki-pagination
hashishaw Sep 21, 2023
e7e6f83
Merge branch 'main' into ui/VAULT-20093/pki-pagination
hashishaw Sep 21, 2023
6d79b30
fix tests
hashishaw Sep 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/23193.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
ui: Add pagination to PKI roles, keys, issuers, and certificates list pages
```
5 changes: 4 additions & 1 deletion ui/app/services/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,12 @@ export default class StoreService extends Store {
// pageFilter: a string that will be used to do a fuzzy match against the
// results, this is done pre-pagination
lazyPaginatedQuery(modelType, query, adapterOptions) {
const skipCache = query.skipCache;
// We don't want skipCache to be part of the actual query key, so remove it
delete query.skipCache;
const adapter = this.adapterFor(modelType);
const modelName = normalizeModelName(modelType);
const dataCache = this.getDataset(modelName, query);
const dataCache = skipCache ? this.clearDataset(modelName) : this.getDataset(modelName, query);
const responsePath = query.responsePath;
assert('responsePath is required', responsePath);
assert('page is required', typeof query.page === 'number');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { tracked } from '@glimmer/tracking';
import errorMessage from 'vault/utils/error-message';
import type RouterService from '@ember/routing/router-service';
import type FlashMessageService from 'vault/services/flash-messages';
import type Store from '@ember-data/store';
import type Store from 'vault/services/store';
import type VersionService from 'vault/services/version';

interface Args {
Expand Down
170 changes: 108 additions & 62 deletions ui/lib/pki/addon/components/page/pki-issuer-list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,114 @@
SPDX-License-Identifier: BUSL-1.1
~}}

{{#each @issuers as |pkiIssuer idx|}}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this inside the <:list> section, otherwise is exactly the same

<LinkedBlock class="list-item-row" @params={{array "issuers.issuer.details" pkiIssuer.id}} @linkPrefix={{@mountPoint}}>
<div class="level is-mobile">
<div class="level-left">
<div data-test-issuer-list={{pkiIssuer.id}}>
<Icon @name="certificate" class="has-text-grey-light" />
<span class="has-text-weight-semibold is-underline">
{{pkiIssuer.issuerRef}}
{{#if pkiIssuer.issuerName}}
<span class="tag has-text-grey-dark">{{pkiIssuer.id}}</span>
{{/if}}
</span>
<div class="is-flex-row has-left-margin-l has-top-margin-xs">
{{#if pkiIssuer.isDefault}}
<span class="tag has-text-grey-dark" data-test-is-default={{idx}}>default issuer</span>
{{/if}}
{{#if (not-eq pkiIssuer.isRoot undefined)}}
<span class="tag has-text-grey-dark" data-test-is-root-tag={{idx}}>{{if
pkiIssuer.isRoot
"root"
"intermediate"
}}</span>
{{/if}}
{{#if pkiIssuer.serialNumber}}
<span class="tag is-transparent has-right-margin-none" data-test-serial-number={{idx}}>
<InfoTooltip>
Serial number
</InfoTooltip>
{{pkiIssuer.serialNumber}}
<PkiPaginatedList @listRoute="issuers.index" @list={{@issuers}}>
<:actions>
<ToolbarLink @route="issuers.import" data-test-generate-issuer="import">
Import
</ToolbarLink>
<BasicDropdown @class="popup-menu" @horizontalPosition="auto-right" @verticalPosition="below" as |D|>
<D.Trigger
class={{concat "toolbar-link" (if D.isOpen " is-active")}}
@htmlTag="button"
data-test-issuer-generate-dropdown
>
Generate
<Chevron @direction="down" @isButton={{true}} />
</D.Trigger>
<D.Content @defaultClass="popup-menu-content">
<nav class="box menu" aria-label="generate options">
<ul class="menu-list">
<li class="action">
<LinkTo @route="issuers.generate-root" {{on "click" (fn this.onLinkClick D)}} data-test-generate-issuer="root">
Root
</LinkTo>
</li>
<li class="action">
<LinkTo
@route="issuers.generate-intermediate"
{{on "click" (fn this.onLinkClick D)}}
data-test-generate-issuer="intermediate"
>
Intermediate CSR
</LinkTo>
</li>
</ul>
</nav>
</D.Content>
</BasicDropdown>
</:actions>
<:list as |issuers|>
{{#each issuers as |pkiIssuer idx|}}
<LinkedBlock class="list-item-row" @params={{array "issuers.issuer.details" pkiIssuer.id}} @linkPrefix={{@mountPoint}}>
<div class="level is-mobile">
<div class="level-left">
<div data-test-issuer-list={{pkiIssuer.id}}>
<Icon @name="certificate" class="has-text-grey-light" />
<span class="has-text-weight-semibold is-underline">
{{pkiIssuer.issuerRef}}
{{#if pkiIssuer.issuerName}}
<span class="tag has-text-grey-dark">{{pkiIssuer.id}}</span>
{{/if}}
</span>
{{/if}}
{{#if pkiIssuer.parsedCertificate.common_name}}
<span class="tag is-transparent has-left-margin-none" data-test-common-name={{idx}}>
<InfoTooltip>
Common name
</InfoTooltip>
{{pkiIssuer.parsedCertificate.common_name}}
</span>
{{/if}}
<div class="is-flex-row has-left-margin-l has-top-margin-xs">
{{#if pkiIssuer.isDefault}}
<span class="tag has-text-grey-dark" data-test-is-default={{idx}}>default issuer</span>
{{/if}}
{{#if (not-eq pkiIssuer.isRoot undefined)}}
<span class="tag has-text-grey-dark" data-test-is-root-tag={{idx}}>{{if
pkiIssuer.isRoot
"root"
"intermediate"
}}</span>
{{/if}}
{{#if pkiIssuer.serialNumber}}
<span class="tag is-transparent has-right-margin-none" data-test-serial-number={{idx}}>
<InfoTooltip>
Serial number
</InfoTooltip>
{{pkiIssuer.serialNumber}}
</span>
{{/if}}
{{#if pkiIssuer.parsedCertificate.common_name}}
<span class="tag is-transparent has-left-margin-none" data-test-common-name={{idx}}>
<InfoTooltip>
Common name
</InfoTooltip>
{{pkiIssuer.parsedCertificate.common_name}}
</span>
{{/if}}
</div>
</div>
</div>
<div class="level-right is-flex is-paddingless is-marginless">
<div class="level-item">
<PopupMenu>
<nav class="menu" aria-label="issuer config options">
<ul class="menu-list">
<li data-test-popup-menu-details>
<LinkTo @route="issuers.issuer.details" @model={{pkiIssuer.id}}>
Details
</LinkTo>
</li>
<li>
<LinkTo @route="issuers.issuer.edit" @model={{pkiIssuer.id}}>
Edit
</LinkTo>
</li>
</ul>
</nav>
</PopupMenu>
</div>
</div>
</div>
</div>
<div class="level-right is-flex is-paddingless is-marginless">
<div class="level-item">
<PopupMenu>
<nav class="menu" aria-label="issuer config options">
<ul class="menu-list">
<li data-test-popup-menu-details>
<LinkTo @route="issuers.issuer.details" @model={{pkiIssuer.id}}>
Details
</LinkTo>
</li>
<li>
<LinkTo @route="issuers.issuer.edit" @model={{pkiIssuer.id}}>
Edit
</LinkTo>
</li>
</ul>
</nav>
</PopupMenu>
</div>
</div>
</div>
</LinkedBlock>
{{/each}}
</LinkedBlock>
{{/each}}
</:list>
<:empty>
<EmptyState @title="PKI not configured" @message={{this.notConfiguredMessage}}>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the empty state into here from the route template, so I needed to add a backing class for notConfiguredMessage

<LinkTo @route="configuration.create">
Configure PKI
</LinkTo>
</EmptyState>
</:empty>
</PkiPaginatedList>
29 changes: 29 additions & 0 deletions ui/lib/pki/addon/components/page/pki-issuer-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/

import { action } from '@ember/object';
import { next } from '@ember/runloop';
import Component from '@glimmer/component';
import { PKI_DEFAULT_EMPTY_STATE_MSG } from 'pki/routes/overview';
import type PkiIssuerModel from 'vault/models/pki/issuer';

interface BasicDropdown {
actions: {
close: CallableFunction;
};
}
interface Args {
issuers: PkiIssuerModel[];
mountPoint: string;
}

export default class PkiIssuerList extends Component<Args> {
notConfiguredMessage = PKI_DEFAULT_EMPTY_STATE_MSG;

// To prevent production build bug of passing D.actions to on "click": https://github.com/hashicorp/vault/pull/16983
@action onLinkClick(D: BasicDropdown) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from controller

next(() => D.actions.close());
}
}
125 changes: 68 additions & 57 deletions ui/lib/pki/addon/components/page/pki-key-list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
SPDX-License-Identifier: BUSL-1.1
~}}

<Toolbar>
<ToolbarActions>
<PkiPaginatedList @listRoute="keys.index" @list={{@keyModels}} @hasConfig={{@hasConfig}}>
<:actions>
{{#if @canImportKey}}
<ToolbarLink @route="keys.import" @type="download" data-test-pki-key-import>
Import
Expand All @@ -15,62 +15,73 @@
Generate
</ToolbarLink>
{{/if}}
</ToolbarActions>
</Toolbar>
<p class="has-padding">Below is information about the private keys used by the issuers to sign certificates. While
certificates represent a public assertion of an identity, private keys represent the private part of that identity, a
secret used to prove who they are and who they trust.</p>

{{#if @keyModels.length}}
{{#each @keyModels as |pkiKey|}}
<LinkedBlock class="list-item-row" @params={{array "keys.key.details" pkiKey.keyId}} @linkPrefix={{@mountPoint}}>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copypasta'd into <:list>

<div class="level is-mobile">
<div class="level-left">
<div>
<Icon @name="certificate" class="has-text-grey-light" />
<span class="has-text-weight-semibold is-underline" data-test-key={{if pkiKey.keyName "name" "id"}}>
{{or pkiKey.keyName pkiKey.id}}
</span>
<div class="is-flex-row has-left-margin-l has-top-margin-xs">
{{#if pkiKey.keyName}}
<span class="tag has-text-grey-dark" data-test-key="id">{{pkiKey.id}}</span>
{{/if}}
</:actions>
<:description>
<p class="has-padding">Below is information about the private keys used by the issuers to sign certificates. While
certificates represent a public assertion of an identity, private keys represent the private part of that identity, a
secret used to prove who they are and who they trust.</p>
</:description>
<:list as |keys|>
{{#each keys as |pkiKey|}}
<LinkedBlock class="list-item-row" @params={{array "keys.key.details" pkiKey.keyId}} @linkPrefix={{@mountPoint}}>
<div class="level is-mobile">
<div class="level-left">
<div>
<Icon @name="certificate" class="has-text-grey-light" />
<span class="has-text-weight-semibold is-underline" data-test-key={{if pkiKey.keyName "name" "id"}}>
{{or pkiKey.keyName pkiKey.id}}
</span>
<div class="is-flex-row has-left-margin-l has-top-margin-xs">
{{#if pkiKey.keyName}}
<span class="tag has-text-grey-dark" data-test-key="id">{{pkiKey.id}}</span>
{{/if}}
</div>
</div>
</div>
</div>
<div class="level-right is-flex is-paddingless is-marginless">
<div class="level-item">
<PopupMenu>
<nav class="menu">
<ul class="menu-list">
<li>
<LinkTo
@route="keys.key.details"
@model={{pkiKey.keyId}}
@disabled={{not @canRead}}
data-test-key-menu-link="details"
>
Details
</LinkTo>
</li>
<li>
<LinkTo
@route="keys.key.edit"
@model={{pkiKey.keyId}}
@disabled={{not @canEdit}}
data-test-key-menu-link="edit"
>
Edit
</LinkTo>
</li>
</ul>
</nav>
</PopupMenu>
<div class="level-right is-flex is-paddingless is-marginless">
<div class="level-item">
<PopupMenu>
<nav class="menu">
<ul class="menu-list">
<li>
<LinkTo
@route="keys.key.details"
@model={{pkiKey.keyId}}
@disabled={{not @canRead}}
data-test-key-menu-link="details"
>
Details
</LinkTo>
</li>
<li>
<LinkTo
@route="keys.key.edit"
@model={{pkiKey.keyId}}
@disabled={{not @canEdit}}
data-test-key-menu-link="edit"
>
Edit
</LinkTo>
</li>
</ul>
</nav>
</PopupMenu>
</div>
</div>
</div>
</div>
</LinkedBlock>
{{/each}}
{{else}}
<EmptyState @title="No keys yet" @message="There are no keys in this PKI mount. You can generate or create one." />
{{/if}}
</LinkedBlock>
{{/each}}
</:list>

<:empty>
<EmptyState @title="No keys yet" @message="There are no keys in this PKI mount. You can generate or create one." />
</:empty>

<:configure>
<EmptyState @title="PKI not configured" @message={{this.notConfiguredMessage}}>
<LinkTo @route="configuration.create">
Configure PKI
</LinkTo>
</EmptyState>
</:configure>
</PkiPaginatedList>
Loading