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)
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user