diff --git a/addons/api/addon/models/session.js b/addons/api/addon/models/session.js
index 484cca9d5..0fdd24a3f 100644
--- a/addons/api/addon/models/session.js
+++ b/addons/api/addon/models/session.js
@@ -5,6 +5,8 @@ import { tracked } from '@glimmer/tracking';
import { A } from '@ember/array';
import { inject as service } from '@ember/service';
+export const statusTypes = ['active', 'pending', 'canceling', 'terminated'];
+
/**
*
*/
@@ -99,6 +101,14 @@ export default class SessionModel extends GeneratedSessionModel {
@equal('status', 'active') isActive;
@equal('status', 'pending') isPending;
+ /**
+ * True if status is an unknown string.
+ * @type {boolean}
+ */
+ get isUnknownStatus() {
+ return !statusTypes.includes(this.status);
+ }
+
/**
* @type {boolean}
*/
diff --git a/addons/api/tests/unit/models/session-test.js b/addons/api/tests/unit/models/session-test.js
index 1c53c15ac..5106ec791 100644
--- a/addons/api/tests/unit/models/session-test.js
+++ b/addons/api/tests/unit/models/session-test.js
@@ -59,4 +59,15 @@ module('Unit | Model | session', function (hooks) {
});
assert.strictEqual(model.proxy, 'localhost:12345');
});
+
+ test('it has isUnknownStatus property and returns the expected values', async function (assert) {
+ assert.expect(2);
+ const store = this.owner.lookup('service:store');
+ const modelA = store.createRecord('session', { status: 'active' });
+ const modelB = store.createRecord('session', {
+ status: 'any string',
+ });
+ assert.false(modelA.isUnknownStatus);
+ assert.true(modelB.isUnknownStatus);
+ });
});
diff --git a/addons/core/addon/components/session-status/index.hbs b/addons/core/addon/components/session-status/index.hbs
new file mode 100644
index 000000000..dd3418dbc
--- /dev/null
+++ b/addons/core/addon/components/session-status/index.hbs
@@ -0,0 +1,15 @@
+{{#if @model.isUnknownStatus}}
+
+{{else}}
+
+{{/if}}
\ No newline at end of file
diff --git a/addons/core/addon/components/session-status/index.js b/addons/core/addon/components/session-status/index.js
new file mode 100644
index 000000000..6e13639be
--- /dev/null
+++ b/addons/core/addon/components/session-status/index.js
@@ -0,0 +1,39 @@
+import Component from '@glimmer/component';
+
+const STATUS_MAPPING = {
+ //map session status to hds text color and icon style
+ //more info - https://design-system-components-hashicorp.vercel.app/components/badge
+ active: { color: 'success', icon: 'check', type: 'filled', text: 'Active' },
+ pending: { color: 'neutral', icon: 'delay', type: 'filled', text: 'Pending' },
+ canceling: {
+ color: 'warning',
+ icon: 'alert-triangle',
+ type: 'filled',
+ text: 'Canceling',
+ },
+ terminated: {
+ color: 'critical',
+ icon: 'x',
+ type: 'filled',
+ text: 'Terminated',
+ },
+};
+
+export default class SessionStatus extends Component {
+ //any status that do not belong in the mapping above, will have a neutral style with outlined badge
+ get statusBadgeColor() {
+ return STATUS_MAPPING[this.args.model.status]?.color || 'neutral';
+ }
+
+ get statusBadgeIcon() {
+ return STATUS_MAPPING[this.args.model.status]?.icon;
+ }
+
+ get statusBadgeType() {
+ return STATUS_MAPPING[this.args.model.status]?.type || 'outlined';
+ }
+
+ get statusBadgeText() {
+ return STATUS_MAPPING[this.args.model.status]?.text;
+ }
+}
diff --git a/addons/core/app/components/session-status.js b/addons/core/app/components/session-status.js
new file mode 100644
index 000000000..3da74ff69
--- /dev/null
+++ b/addons/core/app/components/session-status.js
@@ -0,0 +1 @@
+export { default } from 'core/components/session-status';
diff --git a/addons/core/tests/integration/components/session-status-test.js b/addons/core/tests/integration/components/session-status-test.js
new file mode 100644
index 000000000..201514e57
--- /dev/null
+++ b/addons/core/tests/integration/components/session-status-test.js
@@ -0,0 +1,58 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | session-status', function (hooks) {
+ setupRenderingTest(hooks);
+ test('it maps to correct text color, icon and type if it is in active status', async function (assert) {
+ assert.expect(3);
+ const store = this.owner.lookup('service:store');
+ console.log(store, 'stoeree');
+ this.model = store.createRecord('session', { status: 'active' });
+ await render(hbs``);
+ assert.ok(find('.flight-icon-check'));
+ assert.ok(find('.hds-badge--color-success'));
+ assert.ok(find('.hds-badge--type-filled'));
+ });
+
+ test('it maps to correct text color, icon and type if it is in canceling status', async function (assert) {
+ assert.expect(3);
+ const store = this.owner.lookup('service:store');
+ this.model = store.createRecord('session', { status: 'canceling' });
+ await render(hbs``);
+ assert.ok(find('.flight-icon-alert-triangle'));
+ assert.ok(find('.hds-badge--color-warning'));
+ assert.ok(find('.hds-badge--type-filled'));
+ });
+
+ test('it maps to correct text color, icon and type if it is in terminated status', async function (assert) {
+ assert.expect(3);
+ const store = this.owner.lookup('service:store');
+ this.model = store.createRecord('session', { status: 'terminated' });
+ await render(hbs``);
+ assert.ok(find('.flight-icon-x'));
+ assert.ok(find('.hds-badge--color-critical'));
+ assert.ok(find('.hds-badge--type-filled'));
+ });
+
+ test('it maps to correct text color, icon and type if it is in pending status', async function (assert) {
+ assert.expect(3);
+ const store = this.owner.lookup('service:store');
+ this.model = store.createRecord('session', { status: 'pending' });
+ await render(hbs``);
+ assert.ok(find('.flight-icon-delay'));
+ assert.ok(find('.hds-badge--color-neutral'));
+ assert.ok(find('.hds-badge--type-filled'));
+ });
+
+ test('display neutral color and outlined style when it is an unknown status', async function (assert) {
+ assert.expect(3);
+ const store = this.owner.lookup('service:store');
+ this.model = store.createRecord('session', { status: 'any string' });
+ await render(hbs``);
+ assert.notOk(find('.flight-icon'));
+ assert.ok(find('.hds-badge--color-neutral'));
+ assert.ok(find('.hds-badge--type-outlined'));
+ });
+});
diff --git a/addons/rose/app/styles/rose/_reset.scss b/addons/rose/app/styles/rose/_reset.scss
index 6a253454a..ae81ebf92 100644
--- a/addons/rose/app/styles/rose/_reset.scss
+++ b/addons/rose/app/styles/rose/_reset.scss
@@ -141,3 +141,11 @@ table {
border-collapse: collapse;
border-spacing: 0;
}
+
+// the following line is a custom addition to satisfy HDS
+// https://github.com/hashicorp/design-system/tree/main/packages/components
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
diff --git a/ui/admin/app/templates/scopes/scope/sessions/index.hbs b/ui/admin/app/templates/scopes/scope/sessions/index.hbs
index abaae4bca..ff40f0a12 100644
--- a/ui/admin/app/templates/scopes/scope/sessions/index.hbs
+++ b/ui/admin/app/templates/scopes/scope/sessions/index.hbs
@@ -97,8 +97,8 @@
{{sessionAggregate.user.id}}
{{#if sessionAggregate.user.accountName}}
-
{{sessionAggregate.user.accountName}}
+
+
{{/if}}
{{sessionAggregate.target.displayName}}
@@ -114,7 +114,7 @@
- {{sessionAggregate.session.status}}
+
{{#if sessionAggregate.session.isCancelable}}