diff --git a/app/components/version-list/row.hbs b/app/components/version-list/row.hbs index 7446250208d..11ce1dcc151 100644 --- a/app/components/version-list/row.hbs +++ b/app/components/version-list/row.hbs @@ -128,6 +128,18 @@ <menu.Item> <YankButton @version={{@version}} class="button-reset" local-class="menu-button" /> </menu.Item> + <menu.Item> + <button + class="button-reset" + local-class="menu-button" + type="button" + disabled={{@version.rebuildDocsTask.isRunning}} + data-test-id="btn-rebuild-docs" + {{on 'click' (perform this.rebuildDocsTask)}} + > + Rebuild Docs + </button> + </menu.Item> </dd.Menu> </Dropdown> </PrivilegedAction> diff --git a/app/components/version-list/row.js b/app/components/version-list/row.js index 82ee537993c..15deed1253a 100644 --- a/app/components/version-list/row.js +++ b/app/components/version-list/row.js @@ -4,9 +4,12 @@ import { htmlSafe } from '@ember/template'; import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; +import { keepLatestTask } from 'ember-concurrency'; + import styles from './row.module.css'; export default class VersionRow extends Component { + @service notifications; @service session; @tracked focused = false; @@ -59,4 +62,16 @@ export default class VersionRow extends Component { @action setFocused(value) { this.focused = value; } + + rebuildDocsTask = keepLatestTask(async () => { + let { version } = this.args; + try { + await version.rebuildDocs(); + this.notifications.success('Docs rebuild task was enqueued successfully!'); + } catch (error) { + let reason = error?.errors?.[0]?.detail ?? 'Failed to equeue docs rebuild task.'; + let msg = `Error: ${reason}`; + this.notifications.error(msg); + } + }); } diff --git a/app/models/version.js b/app/models/version.js index 1a89cbf1706..c07e781e1ed 100644 --- a/app/models/version.js +++ b/app/models/version.js @@ -200,4 +200,8 @@ export default class Version extends Model { this.store.pushPayload(payload); await waitForPromise(this.releaseTracks.refreshTask.perform(this.crateName, false)); }); + + async rebuildDocs() { + return await waitForPromise(apiAction(this, { method: 'POST', path: 'rebuild_docs' })); + } } diff --git a/e2e/acceptance/versions.spec.ts b/e2e/acceptance/versions.spec.ts index c61d297a6b0..c895a34f7b6 100644 --- a/e2e/acceptance/versions.spec.ts +++ b/e2e/acceptance/versions.spec.ts @@ -68,4 +68,31 @@ test.describe('Acceptance | crate versions page', { tag: '@acceptance' }, () => await expect(v020).not.toHaveClass(/.*latest/); await expect(v020).not.toHaveClass(/.yanked/); }); + + test('triggers a rebuild for crate documentation', async ({ page, msw }) => { + let user = msw.db.user.create(); + await msw.authenticateAs(user); + + let crate = msw.db.crate.create({ name: 'nanomsg' }); + msw.db.crateOwnership.create({ crate, user }); + + msw.db.version.create({ crate, num: '0.1.0', created_at: '2017-01-01' }); + msw.db.version.create({ crate, num: '0.2.0', created_at: '2018-01-01' }); + msw.db.version.create({ crate, num: '0.3.0', created_at: '2019-01-01', rust_version: '1.69' }); + msw.db.version.create({ crate, num: '0.2.1', created_at: '2020-01-01' }); + + await page.goto('/crates/nanomsg/versions'); + await expect(page).toHaveURL('/crates/nanomsg/versions'); + + await expect(page.locator('[data-test-version]')).toHaveCount(4); + let versions = await page.locator('[data-test-version]').evaluateAll(el => el.map(it => it.dataset.testVersion)); + expect(versions).toEqual(['0.2.1', '0.3.0', '0.2.0', '0.1.0']); + + let v021 = page.locator('[data-test-version="0.2.1"]'); + await v021.locator('[data-test-actions-toggle]').click(); + await v021.getByRole('button', { name: 'Rebuild Docs' }).click(); + + let message = 'Docs rebuild task was enqueued successfully!'; + await expect(page.locator('[data-test-notification-message="success"]')).toHaveText(message); + }); }); diff --git a/tests/acceptance/versions-test.js b/tests/acceptance/versions-test.js index cff0df2e9b2..5cc09f13169 100644 --- a/tests/acceptance/versions-test.js +++ b/tests/acceptance/versions-test.js @@ -81,4 +81,29 @@ module('Acceptance | crate versions page', function (hooks) { .hasNoClass(/.*latest/) .hasNoClass(/.yanked/); }); + + test('triggers a rebuild for crate documentation', async function (assert) { + let user = this.db.user.create(); + this.authenticateAs(user); + + let crate = this.db.crate.create({ name: 'nanomsg' }); + this.db.crateOwnership.create({ crate, user }); + + this.db.version.create({ crate, num: '0.1.0', created_at: '2017-01-01' }); + this.db.version.create({ crate, num: '0.2.0', created_at: '2018-01-01' }); + this.db.version.create({ crate, num: '0.3.0', created_at: '2019-01-01', rust_version: '1.69' }); + this.db.version.create({ crate, num: '0.2.1', created_at: '2020-01-01' }); + + await visit('/crates/nanomsg/versions'); + assert.strictEqual(currentURL(), '/crates/nanomsg/versions'); + + let versions = findAll('[data-test-version]').map(it => it.dataset.testVersion); + assert.deepEqual(versions, ['0.2.1', '0.3.0', '0.2.0', '0.1.0']); + + await click('[data-test-version="0.2.1"] [data-test-actions-toggle]'); + await click('[data-test-version="0.2.1"] [data-test-id="btn-rebuild-docs"]'); + + let message = 'Docs rebuild task was enqueued successfully!'; + assert.dom('[data-test-notification-message="success"]').hasText(message); + }); });