diff --git a/app/adapters/crate.js b/app/adapters/crate.js index 5dc3b05f122..7f9059690a7 100644 --- a/app/adapters/crate.js +++ b/app/adapters/crate.js @@ -25,6 +25,18 @@ export default class CrateAdapter extends ApplicationAdapter { return `${baseUrl}/${crateName}`; } + /** Adds a `reason` query parameter to the URL, if set in the `adapterOptions`. */ + urlForDeleteRecord(id, modelName, snapshot) { + let url = super.urlForDeleteRecord(...arguments); + + let reason = snapshot.adapterOptions.reason; + if (reason) { + url += `?reason=${encodeURIComponent(reason)}`; + } + + return url; + } + groupRecordsForFindMany(store, snapshots) { let result = []; for (let i = 0; i < snapshots.length; i += BULK_REQUEST_GROUP_SIZE) { diff --git a/app/controllers/crate/delete.js b/app/controllers/crate/delete.js index 866acfa2775..cd35fa283fa 100644 --- a/app/controllers/crate/delete.js +++ b/app/controllers/crate/delete.js @@ -9,6 +9,7 @@ export default class CrateSettingsController extends Controller { @service notifications; @service router; + @tracked reason = ''; @tracked isConfirmed; @action toggleConfirmation() { @@ -16,8 +17,10 @@ export default class CrateSettingsController extends Controller { } deleteTask = task(async () => { + let { reason } = this; + try { - await this.model.destroyRecord(); + await this.model.destroyRecord({ adapterOptions: { reason } }); this.notifications.success(`Crate ${this.model.name} has been successfully deleted.`); this.router.transitionTo('index'); } catch (error) { diff --git a/app/routes/crate/delete.js b/app/routes/crate/delete.js index 5a19c5c9cd1..0e62ac3e984 100644 --- a/app/routes/crate/delete.js +++ b/app/routes/crate/delete.js @@ -20,6 +20,7 @@ export default class SettingsRoute extends AuthenticatedRoute { setupController(controller) { super.setupController(...arguments); + controller.set('reason', ''); controller.set('isConfirmed', false); } } diff --git a/app/styles/crate/delete.module.css b/app/styles/crate/delete.module.css index 6b73b90732e..5896bfb0f04 100644 --- a/app/styles/crate/delete.module.css +++ b/app/styles/crate/delete.module.css @@ -75,6 +75,15 @@ } } +.reason { + margin-bottom: var(--space-m); +} + +.reason-input { + composes: base-input from '../../styles/settings/tokens/new.module.css'; + width: 100%; +} + .confirmation { composes: warning-block; display: block; diff --git a/app/templates/crate/delete.hbs b/app/templates/crate/delete.hbs index 3b7bd08f260..6c1a9e317c8 100644 --- a/app/templates/crate/delete.hbs +++ b/app/templates/crate/delete.hbs @@ -1,5 +1,5 @@
-
+

Delete the {{@model.name}} crate?

Are you sure you want to delete the crate "{{@model.name}}"?

@@ -36,6 +36,20 @@
+
+

Reason:

+ +
+
{{/if}} - + \ No newline at end of file diff --git a/e2e/acceptance/crate-deletion.spec.ts b/e2e/acceptance/crate-deletion.spec.ts index 72386cc9961..ba349ce25fe 100644 --- a/e2e/acceptance/crate-deletion.spec.ts +++ b/e2e/acceptance/crate-deletion.spec.ts @@ -24,6 +24,7 @@ test.describe('Acceptance | crate deletion', { tag: '@acceptance' }, () => { await expect(page.locator('[data-test-title]')).toHaveText('Delete the foo crate?'); await expect(page.locator('[data-test-delete-button]')).toBeDisabled(); + await page.fill('[data-test-reason]', "I don't need this crate anymore"); await page.click('[data-test-confirmation-checkbox]'); await expect(page.locator('[data-test-delete-button]')).toBeEnabled(); diff --git a/e2e/routes/crate/delete.spec.ts b/e2e/routes/crate/delete.spec.ts index 4e67ce4a60d..5bbb99e980d 100644 --- a/e2e/routes/crate/delete.spec.ts +++ b/e2e/routes/crate/delete.spec.ts @@ -50,6 +50,7 @@ test.describe('Route: crate.delete', { tag: '@routes' }, () => { await expect(page.locator('[data-test-title]')).toHaveText('Delete the foo crate?'); await percy.snapshot(); + await page.fill('[data-test-reason]', "I don't need this crate anymore"); await expect(page.locator('[data-test-delete-button]')).toBeDisabled(); await page.click('[data-test-confirmation-checkbox]'); await expect(page.locator('[data-test-delete-button]')).toBeEnabled(); @@ -72,6 +73,7 @@ test.describe('Route: crate.delete', { tag: '@routes' }, () => { }); await page.goto('/crates/foo/delete'); + await page.fill('[data-test-reason]', "I don't need this crate anymore"); await page.click('[data-test-confirmation-checkbox]'); await page.click('[data-test-delete-button]'); await expect(page.locator('[data-test-spinner]')).toBeVisible(); @@ -90,6 +92,7 @@ test.describe('Route: crate.delete', { tag: '@routes' }, () => { }); await page.goto('/crates/foo/delete'); + await page.fill('[data-test-reason]', "I don't need this crate anymore"); await page.click('[data-test-confirmation-checkbox]'); await page.click('[data-test-delete-button]'); await expect(page).toHaveURL('/crates/foo/delete'); diff --git a/tests/acceptance/crate-deletion-test.js b/tests/acceptance/crate-deletion-test.js index 72ea46dbe50..c3664f57d9c 100644 --- a/tests/acceptance/crate-deletion-test.js +++ b/tests/acceptance/crate-deletion-test.js @@ -1,4 +1,4 @@ -import { click, currentURL } from '@ember/test-helpers'; +import { click, currentURL, fillIn } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'crates-io/tests/helpers'; @@ -29,6 +29,7 @@ module('Acceptance | crate deletion', function (hooks) { assert.dom('[data-test-title]').hasText('Delete the foo crate?'); assert.dom('[data-test-delete-button]').isDisabled(); + await fillIn('[data-test-reason]', "I don't need this crate anymore"); await click('[data-test-confirmation-checkbox]'); assert.dom('[data-test-delete-button]').isEnabled(); diff --git a/tests/routes/crate/delete-test.js b/tests/routes/crate/delete-test.js index 2cd33a67bb9..dcf232b86da 100644 --- a/tests/routes/crate/delete-test.js +++ b/tests/routes/crate/delete-test.js @@ -1,4 +1,4 @@ -import { click, currentURL, waitFor } from '@ember/test-helpers'; +import { click, currentURL, fillIn, waitFor } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { defer } from 'rsvp'; @@ -58,6 +58,7 @@ module('Route: crate.delete', function (hooks) { assert.dom('[data-test-title]').hasText('Delete the foo crate?'); await percySnapshot(assert); + await fillIn('[data-test-reason]', "I don't need this crate anymore"); assert.dom('[data-test-delete-button]').isDisabled(); await click('[data-test-confirmation-checkbox]'); assert.dom('[data-test-delete-button]').isEnabled(); @@ -79,6 +80,7 @@ module('Route: crate.delete', function (hooks) { this.server.delete('/api/v1/crates/foo', deferred.promise); await visit('/crates/foo/delete'); + await fillIn('[data-test-reason]', "I don't need this crate anymore"); await click('[data-test-confirmation-checkbox]'); let clickPromise = click('[data-test-delete-button]'); await waitFor('[data-test-spinner]'); @@ -98,6 +100,7 @@ module('Route: crate.delete', function (hooks) { this.server.delete('/api/v1/crates/foo', payload, 422); await visit('/crates/foo/delete'); + await fillIn('[data-test-reason]', "I don't need this crate anymore"); await click('[data-test-confirmation-checkbox]'); await click('[data-test-delete-button]'); assert.strictEqual(currentURL(), '/crates/foo/delete');