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: [VAULT-17035 VAULT-17038 VAULT-17039] Dashboard Quick Actions card #21929

Merged
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3548b9d
VAULT-17038 VAULT-17039 wip dropdown and filtered list
kiannaquach Jul 18, 2023
49c8444
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Jul 20, 2023
79815f6
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Jul 20, 2023
70ac4df
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Jul 24, 2023
7ae1a21
Semi working quick actions
kiannaquach Jul 24, 2023
7f24e84
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Jul 25, 2023
1e2670b
Fixes some bugs
kiannaquach Jul 25, 2023
8044dd3
Fix button routes.. still needs more work to transition correctly
kiannaquach Jul 26, 2023
74ab401
Pair with Claire on getting transition to work
kiannaquach Jul 26, 2023
e37fd7b
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Aug 1, 2023
c6c8538
Add default state for quick actions
kiannaquach Aug 1, 2023
fea5a6f
Address feedback
kiannaquach Aug 1, 2023
ea759c1
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Aug 1, 2023
b26989b
Add path for kv
kiannaquach Aug 2, 2023
04d06f9
return object from search select option with engine id and type
hellobontempo Aug 3, 2023
2c6cbf2
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Aug 3, 2023
2fd9e1d
Refactor quick actions component with Claire based on her feedback
kiannaquach Aug 3, 2023
1f704e1
Address more feedback!
kiannaquach Aug 3, 2023
f3ceb8e
Remove shouldRenderName
kiannaquach Aug 4, 2023
b650599
Fix failing test!
kiannaquach Aug 4, 2023
3a51f82
Add quick actions acceptance test
kiannaquach Aug 7, 2023
e93c243
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Aug 7, 2023
2f0a734
Merge branch 'ui/landing-page-dashboard' into ui/dashboard-quick-acti…
kiannaquach Aug 7, 2023
c666969
Add consol test
kiannaquach Aug 7, 2023
eb88387
More tests
kiannaquach Aug 7, 2023
2c5bf06
Revert acceptance test to why its failing
kiannaquach Aug 7, 2023
49154fb
Put things back
kiannaquach Aug 8, 2023
426176c
Add TODO for selectors
kiannaquach Aug 8, 2023
842deea
Remove extra spaces
kiannaquach Aug 8, 2023
159e917
Remove ellipsis and update default
kiannaquach Aug 8, 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
182 changes: 182 additions & 0 deletions ui/app/components/dashboard/quick-actions-card.js
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';

/**
* @module DashboardQuickActionsCard
* DashboardQuickActionsCard component allows users to see a list of secrets engines filtered by
* kv, pki and database and perform certain actions based on the type of secret engine selected
*
* @example
* ```js
* <DashboardQuickActionsCard />
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
* ```
* @param {array}
*/

const getActionsByEngineType = (type) => {
switch (type) {
case 'kv':
return [
{
actionTitle: 'Find KV secrets',
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
actionType: 'find-kv',
},
];
case 'database':
return [
{
actionTitle: 'Generate credentials for database',
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
actionType: 'generate-credentials-db',
},
];
case 'pki':
return [
{
actionTitle: 'Issue certificate',
actionType: 'issue-certificate-pki',
},
{
actionTitle: 'View certificate',
actionType: 'view-certificate-pki',
},
{
actionTitle: 'View issuer',
actionType: 'view-issuer-pki',
},
];
}
};

const getActionParamByAction = (type) => {
switch (type) {
case 'find-kv':
return {
title: 'Secret Path',
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
subText: 'Path of the secret you want to read, including the mount. E.g., secret/data/foo.',
elementType: 'input',
buttonText: 'Read secrets',
path: 'vault.cluster.secrets',
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
};
case 'generate-credentials-db':
return {
title: 'Role to use',
elementType: 'search-select',
buttonText: 'Generate credentials',
model: 'database/role',
path: 'vault.cluster.secrets.backend.credentials',
};
case 'issue-certificate-pki':
return {
title: 'Role to use',
elementType: 'search-select',
placeholder: 'Type to find a role...',
buttonText: 'Issue leaf certificate',
model: 'pki/role',
path: 'vault.cluster.secrets.backend.pki.roles.role.generate',
};
case 'view-certificate-pki':
return {
title: 'Certificate serial number',
placeholder: '33:a3:...',
elementType: 'search-select',
buttonText: 'View certificate',
model: 'pki/certificate/base',
path: 'vault.cluster.secrets.backend.pki.certificates.certificate.details',
};
case 'view-issuer-pki':
return {
title: 'Issuer',
placeholder: 'Type issuer name or ID',
elementType: 'search-select',
buttonText: 'View issuer',
model: 'pki/issuer',
nameKey: 'issuerName',
path: 'vault.cluster.secrets.backend.pki.issuers.issuer.details',
};
}
};

export default class DashboardQuickActionsCard extends Component {
@service router;

@tracked selectedEngine;
@tracked selectedActions = [];
@tracked selectedAction;
@tracked actionParamField;
@tracked selectedEngineName;
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
@tracked value;

constructor() {
super(...arguments);

if (!this.selectedEngine) {
this.setSelectedAction();
}
}

get filteredSecretEngines() {
return this.args.secretsEngines.filter(
(secretEngine) =>
(secretEngine.shouldIncludeInList && secretEngine.type === 'pki') ||
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
secretEngine.type === 'kv' ||
secretEngine.type === 'database'
);
}

get secretsEnginesOptions() {
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
return this.filteredSecretEngines.map((filteredSecretEngine) => {
const name = filteredSecretEngine.path.replace('/', '');

return {
name,
id: `${filteredSecretEngine.type} ${name}`,
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
};
});
}

@action
handleSearchEngineSelect([selectedSearchEngines]) {
if (selectedSearchEngines?.length) {
const selectedEngine = selectedSearchEngines.split(' ');
this.selectedEngine = selectedEngine.firstObject;
this.selectedEngineName = selectedEngine[1];
this.selectedActions = getActionsByEngineType(this.selectedEngine);
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
this.setSelectedAction(this.selectedActions?.firstObject.actionType);
} else {
this.selectedEngine = selectedSearchEngines;
this.setSelectedAction();
}
}

@action
setSelectedAction(selectedAction) {
if (selectedAction) {
this.selectedAction = selectedAction;
this.actionParamField = getActionParamByAction(selectedAction);
} else {
this.selectedActions = getActionsByEngineType('kv');
this.actionParamField = getActionParamByAction('find-kv');
}
}

@action
handleSearch(val) {
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
if (Array.isArray(val)) {
this.value = val[0];
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
} else {
this.value = val;
}
}

@action
navigateToPage() {
this.router.transitionTo(this.actionParamField.path, this.selectedEngineName, this.value);
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
}
}
59 changes: 59 additions & 0 deletions ui/app/templates/components/dashboard/quick-actions-card.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<h3 class="title is-4">Quick actions</h3>

<div class="has-bottom-margin-m">
<h4 class="title is-6">Secrets engine</h4>
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
<SearchSelect
@id="secret-engines-select"
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
@options={{this.secretsEnginesOptions}}
@selectLimit="1"
@disallowNewItems={{true}}
@fallbackComponent="input-search"
@onChange={{this.handleSearchEngineSelect}}
@placeholder="Type to select a mount..."
Copy link
Contributor

@Monkeychip Monkeychip Aug 8, 2023

Choose a reason for hiding this comment

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

same comment here about ellipsis. If it's on the designs, I feel like it's worth clarifying with them if it makes sense in the cases I'm pointing out.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes sense to me! I'll remove the ellipsis for now, and ask design about it!

Copy link
Contributor Author

@kiannaquach kiannaquach Aug 8, 2023

Choose a reason for hiding this comment

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

I just realized that the PKI overview card SearchSelect placeholders use ellipsis, I will still remove for now and will clarify w/ design @Monkeychip

Screenshot 2023-08-08 at 9 09 00 AM

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah - I was under the impression that ellipses were our pattern for search select place holders

@displayInherit={{true}}
@shouldRenderName={{true}}
@nameKey={{"name"}}
class="is-marginless"
/>
</div>

<h4 class="title is-6">Action</h4>
<Select
@name="auth-method"
@options={{this.selectedActions}}
@valueAttribute="actionType"
@labelAttribute="actionTitle"
@isFullwidth={{true}}
@selectedValue={{this.selectedAction}}
@onChange={{this.setSelectedAction}}
/>

<h4 class="title is-6">{{this.actionParamField.title}}</h4>
{{#if (eq this.actionParamField.elementType "input")}}
<Input @type="text" @value={{this.value}} class="input" />
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
{{else}}
<SearchSelect
class="is-flex-1"
@selectLimit="1"
@models={{array this.actionParamField.model}}
@backend={{this.selectedEngineName}}
@placeholder={{this.actionParamField.placeholder}}
@disallowNewItems={{true}}
@onChange={{this.handleSearch}}
@fallbackComponent="input-search"
@nameKey={{this.actionParamField.nameKey}}
@shouldRenderName={{true}}
kiannaquach marked this conversation as resolved.
Show resolved Hide resolved
/>
{{/if}}

<div>
<button
type="button"
class="button is-primary has-top-margin-m"
disabled={{(not (and this.selectedAction this.selectedEngine this.value))}}
{{on "click" this.navigateToPage}}
data-test-button={{this.actionParamField.buttonText}}
>
{{this.actionParamField.buttonText}}
</button>
</div>
2 changes: 1 addition & 1 deletion ui/app/templates/vault/cluster/dashboard.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</Hds::Card::Container>

<Hds::Card::Container @hasBorder={{true}} class="has-padding-l is-flex-column is-flex-half">
<h3 class="title is-4">Quick Actions</h3>
<Dashboard::QuickActionsCard @secretsEngines={{@model.secretsEngines}} />
</Hds::Card::Container>

<Hds::Card::Container @hasBorder={{true}} class="has-padding-l is-flex-column is-flex-half">
Expand Down