From 5e5d4112cde551c5cb23df8ed0a7e04d0ed40a5e Mon Sep 17 00:00:00 2001 From: olaszakos Date: Wed, 15 Jan 2025 15:52:50 +0100 Subject: [PATCH 1/2] feat(wallet): requesters can cancel their requests --- .../requests/OpenRequestOverlay.vue | 1 + .../requests/PolicyRuleResultView.vue | 4 +- .../requests/RequestDetailView.spec.ts | 90 +++++++++++++++++++ .../components/requests/RequestDetailView.vue | 20 ++++- .../components/requests/RequestDialog.spec.ts | 29 ++++++ .../src/components/requests/RequestDialog.vue | 57 +++++++++--- apps/wallet/src/locales/en.locale.ts | 1 + apps/wallet/src/locales/fr.locale.ts | 1 + apps/wallet/src/locales/pt.locale.ts | 1 + apps/wallet/src/services/station.service.ts | 11 +++ 10 files changed, 202 insertions(+), 13 deletions(-) diff --git a/apps/wallet/src/components/requests/OpenRequestOverlay.vue b/apps/wallet/src/components/requests/OpenRequestOverlay.vue index e54d8e645..fe20c8704 100644 --- a/apps/wallet/src/components/requests/OpenRequestOverlay.vue +++ b/apps/wallet/src/components/requests/OpenRequestOverlay.vue @@ -4,6 +4,7 @@ v-model:open="open" :request-id="requestId" @approved="open = false" + @cancelled="open = false" @request-changed="updateRequestId" /> diff --git a/apps/wallet/src/components/requests/PolicyRuleResultView.vue b/apps/wallet/src/components/requests/PolicyRuleResultView.vue index 86a86f013..76d18f733 100644 --- a/apps/wallet/src/components/requests/PolicyRuleResultView.vue +++ b/apps/wallet/src/components/requests/PolicyRuleResultView.vue @@ -180,11 +180,13 @@ function getApprovalSummary(approverIds: string[], status: EvaluationStatus): st n: approvals, m: rejections, }); - } else { + } else if (variantIs(status, 'Pending')) { append = i18n.t('requests.evaluation.approval_summary_pending', { n: approvals, m: rejections, }); + } else { + unreachable(status); } return append; diff --git a/apps/wallet/src/components/requests/RequestDetailView.spec.ts b/apps/wallet/src/components/requests/RequestDetailView.spec.ts index a6dc9a6eb..564920a51 100644 --- a/apps/wallet/src/components/requests/RequestDetailView.spec.ts +++ b/apps/wallet/src/components/requests/RequestDetailView.spec.ts @@ -2,6 +2,8 @@ import { describe, expect, it } from 'vitest'; import { mount } from '~/test.utils'; import RequestDetailView from './RequestDetailView.vue'; import { variantIs } from '~/utils/helper.utils'; +import { useStationStore } from '~/stores/station.store'; +import { flushPromises } from '@vue/test-utils'; type RequestDetailViewProps = InstanceType['$props']; @@ -192,6 +194,52 @@ const failedProps: RequestDetailViewProps = { }, }; +const cancelledProps: RequestDetailViewProps = { + details: { + can_approve: false, + requester_name: 'requester', + approvers: [ + { id: 'approver-1-id', name: '' }, + { id: 'approver-2-id', name: '' }, + ], + }, + request: { + status: { Cancelled: { reason: ['cancellation reason'] } }, + approvals: [ + { + approver_id: 'approver-1-id', + status: { Approved: null }, + decided_at: '', + status_reason: [], + }, + { + approver_id: 'approver-2-id', + status: { Rejected: null }, + decided_at: '', + status_reason: ['Test comment'], + }, + ], + operation: { + AddUser: { + user: [], + input: { + groups: [], + identities: [], + name: 'test', + status: { Active: null }, + }, + }, + }, + created_at: '', + id: '', + execution_plan: { Immediate: null }, + expiration_dt: '', + requested_by: 'approver-1-id', + summary: [], + title: '', + }, +}; + describe('RequestDetailView', () => { it('renders properly', () => { const wrapper = mount(RequestDetailView, { @@ -312,4 +360,46 @@ describe('RequestDetailView', () => { expect(wrapper.find('[data-test-id="request-acceptance-rules"]').exists()).toBeTruthy(); }); + + it('shows a cancel button for cancellable requests', async () => { + const wrapper = mount(RequestDetailView, { + props: pendingProps, + }); + const station = useStationStore(); + station.$patch({ + user: { id: 'requester-id' }, + }); + await flushPromises(); + expect(wrapper.find('[data-test-id="request-details-cancel"]').exists()).toBeTruthy(); + + await wrapper.find('[data-test-id="request-details-cancel"]').trigger('click'); + expect(wrapper.emitted().cancel).toBeTruthy(); + }); + + it("shows doesn't show cancel button for cancelled requests", async () => { + const wrapper = mount(RequestDetailView, { + props: cancelledProps, + }); + const station = useStationStore(); + station.$patch({ + user: { id: 'requester-id' }, + }); + + await flushPromises(); + + expect(wrapper.find('[data-test-id="request-details-cancel"]').exists()).toBeFalsy(); + }); + + it("shows doesn't show cancel button for non-requester", async () => { + const wrapper = mount(RequestDetailView, { + props: pendingProps, + }); + const station = useStationStore(); + station.$patch({ + user: { id: 'not-requester-id' }, + }); + + await flushPromises(); + expect(wrapper.find('[data-test-id="request-details-cancel"]').exists()).toBeFalsy(); + }); }); diff --git a/apps/wallet/src/components/requests/RequestDetailView.vue b/apps/wallet/src/components/requests/RequestDetailView.vue index 36579a216..1e271758a 100644 --- a/apps/wallet/src/components/requests/RequestDetailView.vue +++ b/apps/wallet/src/components/requests/RequestDetailView.vue @@ -73,7 +73,7 @@ hide-details rows="1" auto-grow - :readonly="props.loading || !props.details.can_approve" + :readonly="props.loading || (!props.details.can_approve && !canCancel)" /> @@ -173,6 +173,17 @@ :class="{ 'mt-8': props.details.can_approve }" />
+ + {{ $t('terms.cancel_request') }} + +