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-12979] Dashboard Landing Page #21057

Merged
merged 61 commits into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
8b39203
UI: VAULT-16941 Initial dashboard route set up (#21051)
kiannaquach Jun 7, 2023
7f9f1ed
UI: VAULT-17007 Add Dashboard to the sidenav (#21058)
kiannaquach Jun 7, 2023
81daea3
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jun 12, 2023
fc91c3b
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jun 13, 2023
edb7dca
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jun 16, 2023
9854ff4
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jun 20, 2023
0a284c6
UI: VAULT-17008 Dashboard Secrets Engines Card (#21360)
kiannaquach Jun 20, 2023
efb7fec
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jun 21, 2023
65649e1
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jun 29, 2023
0941d34
UI: VAULT-17026 Dashboard Learn More Card (#21387)
kiannaquach Jul 5, 2023
8618de9
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 5, 2023
a610eb2
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 5, 2023
bf5f074
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 5, 2023
29adadc
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 5, 2023
58b9d46
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 6, 2023
8b4fc35
UI: [VAULT-17365, VAULT-17613, VAULT-17614] Dashboard Secrets Engine …
kiannaquach Jul 6, 2023
87f6f1d
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 7, 2023
76f5ee4
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 10, 2023
facdd64
UI: Dashboard version title + configuration details (#21674)
kiannaquach Jul 13, 2023
9f4321f
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 13, 2023
edb0883
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 14, 2023
8b4b1f2
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 14, 2023
34f0c24
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 17, 2023
e73887a
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 17, 2023
59cfa2c
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 17, 2023
b4658a9
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 17, 2023
c6826a6
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 18, 2023
37f850e
UI: Update links to navigate back to dashboard + Add badges (#21864)
kiannaquach Jul 18, 2023
8f8fbf8
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 20, 2023
84cefc3
Fix merge conflict
kiannaquach Jul 20, 2023
a6b1e46
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 24, 2023
9ca8f0a
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Jul 25, 2023
55ff338
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 1, 2023
b52949e
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 1, 2023
0da565c
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 3, 2023
69e86c9
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 3, 2023
00a358e
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 4, 2023
cf558ab
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 7, 2023
a9603f6
UI: [VAULT-17035 VAULT-17038 VAULT-17039] Dashboard Quick Actions car…
kiannaquach Aug 8, 2023
7cd6fd7
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 8, 2023
6f8e5b6
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 9, 2023
b1e9b57
UI: [VAULT-18794] add survey link dashboard (#22262)
kiannaquach Aug 9, 2023
455cc65
UI: [VAULT-17055] Cleanup TODOs, make sure sidebar tests are up-to-da…
kiannaquach Aug 10, 2023
9d189cd
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 15, 2023
49ecc8b
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 15, 2023
95d415a
UI: [VAULT-17041] Client count card (#22323)
kiannaquach Aug 15, 2023
f69153c
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 17, 2023
0c0e1aa
UI: [VAULT-17044] Replication card (#22354)
kiannaquach Aug 17, 2023
60bd75b
UI: [VAULT-19160 VAULT-19159] Dashboard card order, minor cleanup tas…
kiannaquach Aug 18, 2023
7f0c9cb
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 18, 2023
f46fed2
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 23, 2023
bc77db7
UI: dashboard acceptance tests for quick actions, client count, repli…
kiannaquach Aug 24, 2023
b32962c
Add changelog
kiannaquach Aug 24, 2023
a83c3c1
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 24, 2023
1403c35
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 24, 2023
23c4ea2
Address feedback!
kiannaquach Aug 24, 2023
b51e40e
Fix learn more test since we are now hiding adp link
kiannaquach Aug 24, 2023
ace83bb
Merge branch 'main' into ui/landing-page-dashboard
kiannaquach Aug 24, 2023
a2b8b80
Update links to not use hds
kiannaquach Aug 24, 2023
5bed8a4
Fix styling after link update
kiannaquach Aug 24, 2023
0f235dd
Add more styling to learn more links
kiannaquach Aug 24, 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/21057.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
**Dashboard UI**: Dashboard is now available in the UI as the new landing page.
```
63 changes: 63 additions & 0 deletions ui/app/components/dashboard/client-count-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import Component from '@glimmer/component';
import getStorage from 'vault/lib/token-storage';
import timestamp from 'core/utils/timestamp';
import { task } from 'ember-concurrency';
import { waitFor } from '@ember/test-waiters';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';

/**
* @module DashboardClientCountCard
* DashboardClientCountCard component are used to display total and new client count information
*
* @example
* ```js
* <Dashboard::ClientCountCard @license={{@model.license}} />
* ```
* @param {object} license - license object passed from the parent
*/

export default class DashboardClientCountCard extends Component {
@service store;

@tracked activityData = null;
@tracked clientConfig = null;
@tracked updatedAt = timestamp.now().toISOString();

constructor() {
super(...arguments);
this.fetchClientActivity.perform();
this.clientConfig = this.store.queryRecord('clients/config', {}).catch(() => {});
}

get currentMonthActivityTotalCount() {
return this.activityData?.byMonth?.lastObject?.new_clients.clients;
}

get licenseStartTime() {
return this.args.license.startTime || getStorage().getItem('vault:ui-inputted-start-date') || null;
}

@task
@waitFor
*fetchClientActivity(e) {
if (e) e.preventDefault();
this.updatedAt = timestamp.now().toISOString();
// only make the network request if we have a start_time
if (!this.licenseStartTime) return {};
try {
this.activityData = yield this.store.queryRecord('clients/activity', {
start_time: { timestamp: this.licenseStartTime },
end_time: { timestamp: this.updatedAt },
});
this.noActivityData = this.activityData.activity.id === 'no-data' ? true : false;
} catch (error) {
this.error = error;
}
}
}
44 changes: 44 additions & 0 deletions ui/app/components/dashboard/learn-more-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import Component from '@glimmer/component';

/**
* @module DashboardLearnMoreCard
* DashboardLearnMoreCard component are used to display external links
*
* @example
* ```js
* <DashboardLearnMoreCard />
* ```
*/

export default class DashboardLearnMoreCard extends Component {
get learnMoreLinks() {
return [
{
link: '/vault/tutorials/secrets-management',
icon: 'docs-link',
title: 'Secrets Management',
},
{
link: '/vault/tutorials/monitoring',
icon: 'docs-link',
title: 'Monitor & Troubleshooting',
},
{
link: '/vault/tutorials/adp/transform',
icon: 'learn-link',
title: 'Advanced Data Protection: Transform engine',
requiredFeature: 'Transform Secrets Engine',
},
{
link: '/vault/tutorials/secrets-management/pki-engine',
icon: 'learn-link',
title: 'Build your own Certificate Authority (CA)',
},
];
}
}
147 changes: 147 additions & 0 deletions ui/app/components/dashboard/quick-actions-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/**
* 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
* <Dashboard::QuickActionsCard @secretsEngines={{@model.secretsEngines}} />
* ```
*/

const QUICK_ACTION_ENGINES = ['pki', 'kv', 'database'];

export default class DashboardQuickActionsCard extends Component {
@service router;

@tracked selectedEngine;
@tracked selectedAction;
@tracked paramValue;

get actionOptions() {
switch (this.selectedEngine.type) {
case `kv version ${this.selectedEngine?.version}`:
return ['Find KV secrets'];
case 'database':
return ['Generate credentials for database'];
case 'pki':
return ['Issue certificate', 'View certificate', 'View issuer'];
default:
return [];
}
}

get searchSelectParams() {
switch (this.selectedAction) {
case 'Find KV secrets':
return {
title: 'Secret path',
subText: 'Path of the secret you want to read, including the mount. E.g., secret/data/foo.',
buttonText: 'Read secrets',
// check kv version to figure out which model to use
model: this.selectedEngine.version === 2 ? 'secret-v2' : 'secret',
route: 'vault.cluster.secrets.backend.show',
};
case 'Generate credentials for database':
return {
title: 'Role to use',
buttonText: 'Generate credentials',
model: 'database/role',
route: 'vault.cluster.secrets.backend.credentials',
};
case 'Issue certificate':
return {
title: 'Role to use',
placeholder: 'Type to find a role',
buttonText: 'Issue leaf certificate',
model: 'pki/role',
route: 'vault.cluster.secrets.backend.pki.roles.role.generate',
};
case 'View certificate':
return {
title: 'Certificate serial number',
placeholder: '33:a3:...',
buttonText: 'View certificate',
model: 'pki/certificate/base',
route: 'vault.cluster.secrets.backend.pki.certificates.certificate.details',
};
case 'View issuer':
return {
title: 'Issuer',
placeholder: 'Type issuer name or ID',
buttonText: 'View issuer',
model: 'pki/issuer',
nameKey: 'issuerName',
route: 'vault.cluster.secrets.backend.pki.issuers.issuer.details',
};
default:
return {
placeholder: 'Please select an action above',
buttonText: 'Select an action',
model: '',
};
}
}

get filteredSecretEngines() {
return this.args.secretsEngines.filter((engine) => QUICK_ACTION_ENGINES.includes(engine.type));
}

get mountOptions() {
return this.filteredSecretEngines.map((engine) => {
let { id, type, version } = engine;
if (type === 'kv') type = `kv version ${version}`;

return { name: id, type, id, version };
});
}

@action
handleSearchEngineSelect([selection]) {
this.selectedEngine = selection;
// reset tracked properties
this.selectedAction = null;
this.paramValue = null;
}

@action
setSelectedAction(selectedAction) {
this.selectedAction = selectedAction;
this.paramValue = null;
}

@action
handleActionSelect(val) {
if (Array.isArray(val)) {
this.paramValue = val[0];
} else {
this.paramValue = val;
}
}

@action
navigateToPage() {
let searchSelectParamRoute = this.searchSelectParams.route;

// kv has a special use case where if the paramValue ends in a '/' you should
// link to different route
if (this.selectedEngine.type === 'kv') {
searchSelectParamRoute =
this.paramValue && this.paramValue?.endsWith('/')
? 'vault.cluster.secrets.backend.list'
: 'vault.cluster.secrets.backend.show';
}

this.router.transitionTo(searchSelectParamRoute, this.selectedEngine.id, this.paramValue);
}
}
27 changes: 27 additions & 0 deletions ui/app/components/dashboard/secrets-engines-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import Component from '@glimmer/component';

/**
* @module DashboardSecretsEnginesCard
* DashboardSecretsEnginesCard component are used to display 5 secrets engines to the user.
*
* @example
* ```js
* <DashboardSecretsEnginesCard @secretsEngines={{@model.secretsEngines}} />
* ```
* @param {array} secretsEngines - list of secrets engines
*/

export default class DashboardSecretsEnginesCard extends Component {
get filteredSecretsEngines() {
const filteredEngines = this.args.secretsEngines.filter(
(secretEngine) => secretEngine.shouldIncludeInList
);

return filteredEngines.slice(0, 5);
}
}
27 changes: 27 additions & 0 deletions ui/app/components/dashboard/vault-configuration-details-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import Component from '@glimmer/component';

/**
* @module DashboardVaultConfigurationCard
* DashboardVaultConfigurationCard component are used to display vault configuration.
*
* @example
* ```js
* <DashboardVaultConfigurationCard @vaultConfiguration={{@model.vaultConfiguration}} />
* ```
* @param {object} vaultConfiguration - object of vault configuration key/values
*/

export default class DashboardSecretsEnginesCard extends Component {
get tlsDisabled() {
const tlsDisableConfig = this.args.vaultConfiguration?.listeners.find((listener) => {
if (listener.config && listener.config.tls_disable) return listener.config.tls_disable;
});

return tlsDisableConfig?.config.tls_disable ? 'Enabled' : 'Disabled';
}
}
34 changes: 34 additions & 0 deletions ui/app/components/dashboard/vault-version-title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import Component from '@glimmer/component';
import { inject as service } from '@ember/service';

/**
* @module DashboardVaultVersionTitle
* DashboardVaultVersionTitle component are use to display the vault version title and the badges
*
* @example
* ```js
* <Dashboard::VaultVersionTitle />
* ```
*/

export default class DashboardVaultVersionTitle extends Component {
@service version;
@service namespace;

get versionHeader() {
return this.version.isEnterprise
? `Vault v${this.version.version.slice(0, this.version.version.indexOf('+'))}`
: `Vault v${this.version.version}`;
}

get namespaceDisplay() {
if (this.namespace.inRootNamespace) return 'root';
const parts = this.namespace.path?.split('/');
return parts[parts.length - 1];
}
}
4 changes: 2 additions & 2 deletions ui/app/components/namespace-link.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ export default Component.extend({
window.location.hostname +
(window.location.port ? ':' + window.location.port : '');

if (!this.normalizedNamespace) return `${origin}/ui/vault/secrets`;
if (!this.normalizedNamespace) return `${origin}/ui/vault/dashboard`;
// The full URL/origin is required so that the page is reloaded.
return `${origin}/ui/vault/secrets?namespace=${encodeURIComponent(this.normalizedNamespace)}`;
return `${origin}/ui/vault/dashboard?namespace=${encodeURIComponent(this.normalizedNamespace)}`;
},
});
2 changes: 1 addition & 1 deletion ui/app/components/sidebar/frame.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<:logo>
<Hds::SideNav::Header::HomeLink
@icon="vault"
@route="vault.cluster"
@route="vault.cluster.dashboard"
@model={{this.currentCluster.cluster.name}}
@ariaLabel="home link"
data-test-sidebar-logo
Expand Down
1 change: 1 addition & 0 deletions ui/app/components/sidebar/nav/cluster.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Hds::SideNav::Portal @ariaLabel="Cluster Navigation Links" data-test-sidebar-nav-panel="Cluster" as |Nav|>
<Nav.Title data-test-sidebar-nav-heading="Vault">Vault</Nav.Title>

<Nav.Link @route="vault.cluster.dashboard" @text="Dashboard" data-test-sidebar-nav-link="Dashboard" />
<Nav.Link
@route="vault.cluster.secrets"
@current-when="vault.cluster.secrets vault.cluster.settings.mount-secret-backend vault.cluster.settings.configure-secret-backend"
Expand Down
Loading