diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 9f2fb54f8..1deee0f25 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -222,6 +222,15 @@ session-recording: title_plural: Channels session: title: Session Playback + form: + time: + label: Time + user: + label: User + target: + label: Target + duration: + label: Duration storage-bucket: title: Storage Bucket title_plural: Storage Buckets diff --git a/ui/admin/app/controllers/scopes/scope/session-recordings.js b/ui/admin/app/controllers/scopes/scope/session-recordings.js new file mode 100644 index 000000000..d9ffc7fb0 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/session-recordings.js @@ -0,0 +1,16 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeSessionRecordingsController extends Controller { + // =services + + @service intl; + + //= attributes + /** + * Translated breadcrumb + */ + get breadCrumb() { + return this.intl.t('resources.session-recording.title_plural'); + } +} diff --git a/ui/admin/app/formats.js b/ui/admin/app/formats.js index 3d6cb9a0b..197e8f054 100644 --- a/ui/admin/app/formats.js +++ b/ui/admin/app/formats.js @@ -34,6 +34,13 @@ export default { minute: 'numeric', timeZoneName: 'short', }, + mmddyyhhmm: { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: 'numeric', + minute: 'numeric', + }, }, number: { compact: { notation: 'compact' }, diff --git a/ui/admin/app/styles/app.scss b/ui/admin/app/styles/app.scss index c1bc62db0..cf263297c 100644 --- a/ui/admin/app/styles/app.scss +++ b/ui/admin/app/styles/app.scss @@ -776,3 +776,14 @@ 'sidebar'; } } + +// Session recording - List +.session-recording-list-cell-item { + display: flex; + gap: sizing.rems(xs); + + span { + display: flex; + align-items: center; + } +} diff --git a/ui/admin/app/templates/scopes/scope/session-recordings/index.hbs b/ui/admin/app/templates/scopes/scope/session-recordings/index.hbs index 5762bc212..8a7d8b86e 100644 --- a/ui/admin/app/templates/scopes/scope/session-recordings/index.hbs +++ b/ui/admin/app/templates/scopes/scope/session-recordings/index.hbs @@ -1,18 +1,71 @@ + + + +

{{t 'resources.session-recording.title_plural'}}

- {{#each @model as |recording|}} -

- - {{recording.id}} - -

- {{/each}} + {{#if @model}} + + <:body as |B|> + + + + {{format-date B.data.started_time format='mmddyyhhmm'}} + + + +
+ + {{B.data.user.name}} +
+
+ +
+ + {{B.data.target.name}} +
+
+ +
+ + + {{format-time-duration B.data.duration}} + +
+
+ + + +
+ +
+ {{/if}}
\ No newline at end of file diff --git a/ui/admin/tests/acceptance/session-recordings/list-test.js b/ui/admin/tests/acceptance/session-recordings/list-test.js new file mode 100644 index 000000000..ebeca115a --- /dev/null +++ b/ui/admin/tests/acceptance/session-recordings/list-test.js @@ -0,0 +1,62 @@ +import { module, test } from 'qunit'; +import { visit, currentURL, click } from '@ember/test-helpers'; +import { setupApplicationTest } from 'admin/tests/helpers'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +import { authenticateSession } from 'ember-simple-auth/test-support'; + +module('Acceptance | session recordings | list', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + // Selectors + const LIST_SESSION_RECORDING_BUTTON = + 'table > tbody > tr > td:last-child > a'; + + const instances = { + scopes: { + global: null, + org: null, + }, + sessionRecording: null, + }; + + const urls = { + globalScope: null, + sessionRecordings: null, + sessionRecording: null, + }; + + hooks.beforeEach(function () { + instances.scopes.global = this.server.create('scope', { id: 'global' }); + instances.scopes.org = this.server.create('scope', { + type: 'org', + scope: { id: 'global', type: 'global' }, + }); + instances.sessionRecording = this.server.create('session-recording', { + scope: instances.scopes.global, + }); + urls.globalScope = `/scopes/global`; + urls.sessionRecordings = `${urls.globalScope}/session-recordings`; + urls.sessionRecording = `${urls.sessionRecordings}/${instances.sessionRecording.id}`; + authenticateSession({}); + }); + + // TODO: When we add abilities to session-recordings this test will be refactor to account for it. + test('users can navigate to session-recordings', async function (assert) { + assert.expect(1); + // Visit session recordings + await visit(urls.sessionRecordings); + assert.strictEqual(currentURL(), urls.sessionRecordings); + }); + + // TODO: When we add abilities to session-recordings this test will be refactor to account for it. + test('user can navigate to a session recording', async function (assert) { + assert.expect(2); + // Visit session recordings + await visit(urls.sessionRecordings); + assert.dom('table').hasClass('hds-table'); + // Click a session recording and check it navigates properly + await click(LIST_SESSION_RECORDING_BUTTON); + assert.strictEqual(currentURL(), urls.sessionRecording); + }); +}); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/session-recordings-test.js b/ui/admin/tests/unit/controllers/scopes/scope/session-recordings-test.js new file mode 100644 index 000000000..94159166b --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/session-recordings-test.js @@ -0,0 +1,13 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'admin/tests/helpers'; + +module('Unit | Controller | scopes/scope/session-recordings', function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let controller = this.owner.lookup( + 'controller:scopes/scope/session-recordings' + ); + assert.ok(controller); + }); +});