-
Notifications
You must be signed in to change notification settings - Fork 33
Migrate asciicinema component from hashicorp/ember-asciinema-player repo #3102
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
base: main
Are you sure you want to change the base?
Changes from 7 commits
9a0770c
c05d632
2a1a510
7438c86
97ebed5
ac2a713
4bc0231
793146e
8cc310e
10c5bd2
bcd46e3
4eb5977
e5e4714
aa7468a
d11706d
47f7442
5571801
88fcfbe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| {{! | ||
| Copyright (c) HashiCorp, Inc. | ||
| SPDX-License-Identifier: MPL-2.0 | ||
| }} | ||
|
|
||
| <div | ||
| class='heap-player' | ||
| ...attributes | ||
| {{did-insert this.initializePlayer}} | ||
| {{will-destroy this.destroyPlayer}} | ||
|
||
| > | ||
|
|
||
| </div> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| /** | ||
| * Copyright (c) HashiCorp, Inc. | ||
| * SPDX-License-Identifier: MPL-2.0 | ||
| */ | ||
|
|
||
| import Component from '@glimmer/component'; | ||
| import { tracked } from '@glimmer/tracking'; | ||
| import { action } from '@ember/object'; | ||
| import { later } from '@ember/runloop'; | ||
| import * as AsciinemaPlayer from 'asciinema-player'; | ||
|
|
||
| export default class HeapPlayerComponent extends Component { | ||
| // =properties | ||
|
|
||
| /** | ||
| * @type {?AsciinemaPlayer} | ||
| */ | ||
| @tracked player = null; | ||
|
|
||
| /** | ||
| * | ||
| */ | ||
| initialized = false; | ||
|
|
||
| /** | ||
| * Options of the underlying AsciinemaPlayer supported by this component, | ||
| * which may be passed as named arguments to the player. | ||
| * @type {string[]} | ||
| * @see https://github.com/asciinema/asciinema-player#options | ||
| */ | ||
| supportedOptions = new Array( | ||
| 'autoPlay', | ||
| 'loop', | ||
| 'startAt', | ||
| 'speed', | ||
| 'idleTimeLimit', | ||
| 'theme', | ||
| 'poster', | ||
| 'fit', | ||
| 'controls', | ||
| 'markers', | ||
| 'pauseOnMarkers', | ||
| ); | ||
|
|
||
| /** | ||
| * An object of options where each possible key from `supportOptions` is | ||
| * included if and only if its associated value was passed to the component | ||
| * as an argument. | ||
| * | ||
| * E.g. `@autoPlay={{true}} @fit='both'` results in | ||
| * the options object `{autoPlay: true, fit: 'both'}`. | ||
| * @type {object} | ||
| * @see https://github.com/asciinema/asciinema-player#options | ||
| */ | ||
| get options() { | ||
| return this.supportedOptions.reduce( | ||
| (obj, key) => { | ||
| return this.args?.[key] !== undefined | ||
| ? { ...obj, [key]: this.args[key] } | ||
| : obj | ||
| }, | ||
| {} | ||
| ); | ||
| } | ||
|
|
||
| // =methods | ||
|
|
||
| /** | ||
| * Initializes the asciinema player within the current element. | ||
| * @param {object|string} | ||
| * source - URL or object passed through to AsciinemaPlayer.create(source). | ||
| * @param {Element} | ||
| * containerElement - DOM element passed from the did-insert modifier. | ||
| * @returns {AsciinemaPlayer} | ||
| */ | ||
| create(source, containerElement, options) { | ||
| // cleanup previous player, if any | ||
| this.dispose(); | ||
| // initialize a new AsciinemaPlayer | ||
| this.player = | ||
| AsciinemaPlayer.create(source, containerElement, options); | ||
| return this.player; | ||
| } | ||
|
|
||
| /** | ||
| * Calls asciinema-player's `dispose()` method to destroy the player and | ||
| * cleanup the DOM. Unsets this component's `player` property. | ||
| */ | ||
| dispose() { | ||
| this.player?.dispose(); | ||
| this.player = null; | ||
| } | ||
|
|
||
| // =actions | ||
|
|
||
| /** | ||
| * Creates an AsciinemaPlayer within the passed `containerElement`. | ||
| */ | ||
| @action | ||
| initializePlayer(containerElement) { | ||
| const { data } = this.args; | ||
| this.create({ data }, containerElement, this.options); | ||
| } | ||
|
|
||
| /** | ||
| * Destroys the currently initialized AsciinemaPlayer, if any. | ||
| */ | ||
| @action | ||
| destroyPlayer() { | ||
| later(() => this.dispose(), 250); | ||
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,7 @@ | |
| }, | ||
| "dependencies": { | ||
| "@babel/runtime": "7.27.6", | ||
| "asciinema-player": "3.4.0", | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| "ember-named-blocks-polyfill": "^0.2.5", | ||
| "lodash": "^4.17.21", | ||
| "uuid": "^11.0.3" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /** | ||
| * Copyright (c) HashiCorp, Inc. | ||
| * SPDX-License-Identifier: MPL-2.0 | ||
| */ | ||
|
|
||
| import { module, test } from 'qunit'; | ||
| import { render, waitUntil } from '@ember/test-helpers'; | ||
| import { setupRenderingTest } from 'admin/tests/helpers'; | ||
| import { hbs } from 'ember-cli-htmlbars'; | ||
|
|
||
| module( | ||
| 'Integration | Component | session-recording/player/asciinema-player', | ||
| function (hooks) { | ||
| setupRenderingTest(hooks); | ||
|
|
||
| test('it renders', async function (assert) { | ||
| assert.expect(1); | ||
|
|
||
| const asciicast = await fetch('/session.cast'); | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In our app we have the same cast file as this test was using in the repo, it's just under a different filename |
||
| const asciicastContent = await asciicast.text(); | ||
| this.set('data', asciicastContent); | ||
|
|
||
| await render( | ||
| hbs`<SessionRecording::Player::AsciinemaPlayer @data={{this.data}} @poster='npt:1:30' />`, | ||
| ); | ||
| // AsciinemaPlayer does not come with a "ready" event, and its | ||
| // initialization is async. Therefore tests must `waitUntil` the expected | ||
| // DOM state is reached. | ||
| await waitUntil(() => | ||
| assert | ||
| .dom('.ap-player') | ||
| .hasAnyText('ember-asciinema-player git:(main*)'), | ||
| ); | ||
| }); | ||
| }, | ||
| ); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We previously had to lock in on this version because we relied on specific internal DOM structure and classes that changed after
3.4.0. With this PR we can remove this but still need to ensure that our dependency brought in within admin UI is3.4.0. When we upgrade to a newer version we'll have make sure our additional css styles still apply