chore: 🤖 add user info (#2425)

* chore: 🤖 add user info
This commit is contained in:
Dharini Jeeva authored and Zhihe Li committed 2024-09-24 11:58:25 -04:00
1 parent 777380e19f
commit 0b9357e9b3
11 files changed
+289 -105

No files matched your search

@@ -17,6 +17,8 @@ failed: Failed
installed: Installed
not-running: Not Running
running: Running
authenticated: Authenticated
unauthenticated: Unauthenticated
loading:
title: Loading all items...
description: All of your {resource} are still loading. Please wait while we finish loading everything on screen.
@@ -0,0 +1,76 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<SettingsCard @header={{t 'titles.application'}} @icon='boundary'>
<:body>
<div class='app-information'>
<div>
<Hds::Text::Display>
{{t 'titles.client'}}
</Hds::Text::Display>
<Hds::Text::Body @tag='p' @weight='medium'>
{{@model.formattedDesktopVersion}}
</Hds::Text::Body>
</div>
<div>
<Hds::Text::Display>
{{t 'titles.cli'}}
</Hds::Text::Display>
<Hds::Text::Body @tag='p' @weight='medium'>
{{@model.formattedCliVersion}}
</Hds::Text::Body>
</div>
<div>
<Hds::Text::Display>
{{t 'titles.cache-daemon'}}
</Hds::Text::Display>
<Hds::Text::Body @tag='p' @weight='medium'>
{{#if @model.formattedCacheVersion}}
{{@model.formattedCacheVersion}}
<Hds::Badge
@text={{t 'states.running'}}
@icon='running'
@color='success'
/>
{{else}}
<Hds::Badge
@text={{t 'states.not-running'}}
@icon='stop-circle'
@color='neutral'
/>
{{/if}}
</Hds::Text::Body>
</div>
</div>
{{#if @model.error}}
<Hds::Alert @type='inline' @color='warning' as |A|>
<A.Title>{{t 'errors.settings-cache.title'}}</A.Title>
{{#if @model.error.message}}
<A.Description>{{@model.error.message}}</A.Description>
{{/if}}
</Hds::Alert>
{{/if}}
<Hds::Form::Select::Field
name='theme'
@width='30%'
{{on 'change' @toggle}}
as |F|
>
<F.Label>{{t 'titles.color-theme'}}</F.Label>
<F.Options>
{{#each this.themes as |theme|}}
<option
value={{theme.value}}
selected={{eq this.session.data.theme theme.value}}
>
{{t (concat 'themes.' theme.label)}}
</option>
{{/each}}
</F.Options>
</Hds::Form::Select::Field>
</:body>
</SettingsCard>
@@ -0,0 +1,30 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
const THEMES = [
{
label: 'system',
value: 'system-default-theme',
},
{
label: 'light',
value: 'light',
},
{
label: 'dark',
value: 'dark',
},
];
export default class SettingsApplicationComponent extends Component {
/**
* Returns available themes
*/
get themes() {
return THEMES;
}
}
@@ -11,6 +11,10 @@
{{@header}}
</Hds::Text::Display>
{{#if (has-block 'state')}}
{{yield to='state'}}
{{/if}}
{{#if (has-block 'action')}}
<div class='action'>
{{! this will contain buttons }}
@@ -18,11 +22,6 @@
</div>
{{/if}}
{{#if @state}}
<div class='state'>
<Hds::Badge @text={{@state}} @icon='loading' />
</div>
{{/if}}
</div>
{{#if @description}}
@@ -0,0 +1,49 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<SettingsCard @header={{t 'resources.user.title'}} @icon='user'>
<:state>
{{#if this.isAuthenticated}}
<Hds::Badge
@text={{t 'states.authenticated'}}
@icon='check'
@color='success'
/>
{{else}}
<Hds::Badge @text={{t 'states.unauthenticated'}} @color='neutral' />
{{/if}}
</:state>
<:body>
<div class='app-information'>
<div>
<Hds::Text::Display>
{{t 'resources.auth-method.title'}}
</Hds::Text::Display>
<Hds::Text::Body @tag='p' @weight='medium' data-test-auth-method>
{{this.authMethod}}
</Hds::Text::Body>
</div>
<div>
<Hds::Text::Display>
{{t 'form.username.label'}}
</Hds::Text::Display>
<Hds::Text::Body @tag='p' @weight='medium' data-test-username>
{{this.userInfo}}
</Hds::Text::Body>
</div>
</div>
</:body>
<:action>
<Hds::Button
data-test-signout-button
@text={{t 'actions.deauthenticate'}}
@color='critical'
@icon='sign-out'
@size='medium'
{{on 'click' this.invalidateSession}}
/>
</:action>
</SettingsCard>
@@ -0,0 +1,61 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
export default class SettingsUserInfoComponent extends Component {
// =services
@service session;
@service intl;
/**
* Returns the username of the current user
* @type {string}
*/
get userInfo() {
const {
data: {
authenticated: { username },
},
} = this.session;
return username;
}
/**
* Returns true if user is authenticated
* @type {boolean}
*/
get isAuthenticated() {
const { isAuthenticated } = this.session;
return isAuthenticated;
}
/**
* Returns the type of authmethod used by the user
* @type {string}
*/
get authMethod() {
const {
data: {
authenticated: { authenticator },
},
} = this.session;
const formattedAuthenticatorType = authenticator.split(':')[1];
return this.intl.t(`resources.account.types.${formattedAuthenticatorType}`);
}
// =actions
/**
* Delegates invalidation to the session service.
*/
@action
invalidateSession() {
this.session.invalidate();
}
}
@@ -4,39 +4,12 @@
*/
import Controller, { inject as controller } from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
const THEMES = [
{
label: 'system',
value: 'system-default-theme',
},
{
label: 'light',
value: 'light',
},
{
label: 'dark',
value: 'dark',
},
];
export default class ScopesScopeProjectsSettingsIndexController extends Controller {
@controller('application') application;
// Services
@service session;
// Methods
/**
* Returns available themes
*/
get themes() {
return THEMES;
}
//actions
/**
* Calls the Application controller's toggleTheme method
* @param {string} theme - "light", "dark", or nullish (system default)
+12 -2
View File
@@ -665,14 +665,17 @@ $chevron-down: url("data:image/svg+xml;utf-8,<svg viewBox='0 0 24 24' fill='%231
// Settings
.settings-card {
margin-bottom: 1rem;
.hds-card__container {
padding: 1rem;
margin-bottom: 1rem;
}
.header-and-icon {
display: flex;
align-items: center;
gap: 0.5rem;
gap: 1rem;
}
.content {
@@ -681,7 +684,14 @@ $chevron-down: url("data:image/svg+xml;utf-8,<svg viewBox='0 0 24 24' fill='%231
.app-information {
display: flex;
justify-content: space-between;
margin: 1rem 2rem 1rem 0;
> div {
flex-basis: 12rem;
}
}
.action {
margin-left: auto;
}
}
@@ -3,73 +3,5 @@
SPDX-License-Identifier: BUSL-1.1
}}
<SettingsCard @header={{t 'titles.application'}} @icon='boundary'>
<:body>
<div class='app-information'>
<div>
<Hds::Text::Display>
{{t 'titles.client'}}
</Hds::Text::Display>
<Hds::Text::Body @tag='p' @weight='medium'>
{{@model.formattedDesktopVersion}}
</Hds::Text::Body>
</div>
<div>
<Hds::Text::Display>
{{t 'titles.cli'}}
</Hds::Text::Display>
<Hds::Text::Body @tag='p' @weight='medium'>
{{@model.formattedCliVersion}}
</Hds::Text::Body>
</div>
<div>
<Hds::Text::Display>
{{t 'titles.cache-daemon'}}
</Hds::Text::Display>
<Hds::Text::Body @tag='p' @weight='medium'>
{{#if @model.formattedCacheVersion}}
{{@model.formattedCacheVersion}}
<Hds::Badge
@text={{t 'states.running'}}
@icon='running'
@color='success'
/>
{{else}}
<Hds::Badge
@text={{t 'states.not-running'}}
@icon='stop-circle'
@color='neutral'
/>
{{/if}}
</Hds::Text::Body>
</div>
</div>
{{#if @model.error}}
<Hds::Alert @type='inline' @color='warning' as |A|>
<A.Title>{{t 'errors.settings-cache.title'}}</A.Title>
{{#if @model.error.message}}
<A.Description>{{@model.error.message}}</A.Description>
{{/if}}
</Hds::Alert>
{{/if}}
<Hds::Form::Select::Field
name='theme'
@width='30%'
{{on 'change' this.toggleTheme}}
as |F|
>
<F.Label>{{t 'titles.color-theme'}}</F.Label>
<F.Options>
{{#each this.themes as |theme|}}
<option
value={{theme.value}}
selected={{eq this.session.data.theme theme.value}}
>
{{t (concat 'themes.' theme.label)}}
</option>
{{/each}}
</F.Options>
</Hds::Form::Select::Field>
</:body>
</SettingsCard>
<SettingsCard::Application @model={{@model}} @toggle={{this.toggleTheme}} />
<SettingsCard::User />
@@ -20,6 +20,8 @@ import {
import WindowMockIPC from '../../../helpers/window-mock-ipc';
import setupStubs from 'api/test-support/handlers/cache-daemon-search';
const SIGNOUT_SELECTOR = '[data-test-signout-button]';
module('Acceptance | projects | settings | index', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
@@ -130,4 +132,13 @@ module('Acceptance | projects | settings | index', function (hooks) {
assert.notOk(getRootElement().classList.contains('rose-theme-light'));
assert.notOk(getRootElement().classList.contains('rose-theme-dark'));
});
test('clicking signout button logs out the user', async function (assert) {
authenticateSession({ username: 'testuser' });
assert.expect(2);
await visit(urls.settings);
assert.ok(currentSession().isAuthenticated);
await click(SIGNOUT_SELECTOR);
assert.notOk(currentSession().isAuthenticated);
});
});
@@ -8,6 +8,10 @@ import { setupRenderingTest } from 'ember-qunit';
import { render, find } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
const USERNAME_SELECTOR = '[data-test-username]';
const AUTH_METHOD_SELECTOR = '[data-test-auth-method]';
const SIGNOUT_SELECTOR = '[data-test-signout-button]';
module('Integration | Component | settings card', function (hooks) {
setupRenderingTest(hooks);
@@ -38,4 +42,41 @@ module('Integration | Component | settings card', function (hooks) {
'This is a heading test',
);
});
test('displays userinfo card correctly', async function (assert) {
this.authMethod = 'OIDC';
this.userInfo = 'testuser';
await render(hbs`
<SettingsCard
@header='This is a heading test'
@icon='boundary'>
<:body>
<div class='app-information'>
<div>
<Hds::Text::Body @tag='p' @weight='medium' data-test-auth-method>
{{this.authMethod}}
</Hds::Text::Body>
</div>
<div>
<Hds::Text::Body @tag='p' @weight='medium' data-test-username>
{{this.userInfo}}
</Hds::Text::Body>
</div>
</div>
</:body>
<:action>
<Hds::Button
data-test-signout-button
@text='sign out'
@color='critical'
@icon='sign-out'
@size='medium'
/>
</:action>
</SettingsCard>
`);
assert.dom(AUTH_METHOD_SELECTOR).hasText('OIDC');
assert.dom(USERNAME_SELECTOR).hasText('testuser');
assert.dom(SIGNOUT_SELECTOR).hasText('sign out');
});
});