Skip to content

Commit

Permalink
[DT-1051] Add identity and reason to Terminate in the UI (#1399)
Browse files Browse the repository at this point in the history
* Fix extra space if there is no user defined reason

* Add Web UI reason to terminate and reset on workflow

* Add identity to terminate workflow

* Remove workflow and use workflows namespace instead

* Refactor reason and placeholder into utils with tests

* Fix batch cancel toast translation

* Add identity to terminateWorkflows
  • Loading branch information
laurakwhit authored Jun 2, 2023
1 parent 6a149d5 commit b320645
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 41 deletions.
16 changes: 14 additions & 2 deletions src/lib/components/workflow-actions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
signalWorkflow,
terminateWorkflow,
} from '$lib/services/workflow-service';
import { authUser } from '$lib/stores/auth-user';
import { formatReason } from '$lib/utilities/workflow-actions';
import { Action } from '$lib/models/workflow-actions';
import { writeActionsAreAllowed } from '$lib/utilities/write-actions-are-allowed';
import { ResetReapplyType } from '$lib/models/workflow-actions';
Expand Down Expand Up @@ -90,7 +93,12 @@
terminateWorkflow({
workflow,
namespace,
reason,
reason: formatReason({
action: Action.Terminate,
reason,
email: $authUser.email,
}),
identity: $authUser.email,
})
.then(handleSuccessfulTermination)
.catch(handleTerminationError);
Expand Down Expand Up @@ -153,7 +161,11 @@
workflowId: workflow.id,
runId: workflow.runId,
eventId: resetId,
reason: resetReason,
reason: formatReason({
action: Action.Reset,
reason: resetReason,
email: $authUser.email,
}),
resetReapplyType,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
<script lang="ts" context="module">
export enum Action {
Terminate,
Cancel,
}
</script>

<script lang="ts">
import { createEventDispatcher } from 'svelte';
import Modal from '$lib/holocene/modal.svelte';
Expand All @@ -13,6 +6,8 @@
import { allSelected } from '$lib/pages/workflows-with-new-search.svelte';
import { translate } from '$lib/i18n/translate';
import Translate from '$lib/i18n/translate.svelte';
import { formatReason, getPlacholder } from '$lib/utilities/workflow-actions';
import { Action } from '$lib/models/workflow-actions';
export let action: Action;
export let actionableWorkflowsLength: number;
Expand All @@ -32,31 +27,14 @@
? translate('workflows', 'cancel')
: translate('workflows', 'terminate');
$: pastTenseActionText =
action === Action.Cancel
? translate('workflows', 'canceled')
: translate('workflows', 'terminated');
$: placeholder = getPlacholder(action, $authUser.email);
let placeholder: string;
$: {
if ($authUser.email) {
placeholder = translate(
'workflows',
'batch-operation-confirmation-placeholder-by-email',
{ action: pastTenseActionText, email: $authUser.email },
);
} else {
placeholder = translate(
'workflows',
'batch-operation-confirmation-placeholder',
{ action: pastTenseActionText },
);
}
}
let reason: string = '';
const handleConfirmModal = () => {
dispatch('confirm', { reason: [reason.trim(), placeholder].join(' ') });
dispatch('confirm', {
reason: formatReason({ action, reason, email: $authUser.email }),
});
};
const handleCancelModal = () => {
Expand Down
7 changes: 4 additions & 3 deletions src/lib/i18n/locales/en/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export const Strings = {
cancel: 'Cancel',
reason: 'Reason',
'batch-operation-modal-title': '{{action}} Workflows',
'batch-operation-confirmation-placeholder': '{{action}} from the Web UI',
'batch-operation-confirmation-placeholder-by-email':
'workflow-action-reason-placeholder': '{{action}} from the Web UI',
'workflow-action-reason-placeholder-with-email':
'{{action}} from the Web UI by {{email}}',
'batch-operation-confirmation-all':
'Are you sure you want to {{action}} all workflows matching the following query? This action cannot be undone.',
Expand All @@ -32,7 +32,7 @@ export const Strings = {
'batch-cancel-all-success':
'The batch $t(cancel) request is processing in the background.',
'batch-terminate-success': 'Successfully $t(terminated) {{count}} workflows.',
'batch-cancel-success': 'Successfully $(canceled) {{count}} workflows.',
'batch-cancel-success': 'Successfully $t(canceled) {{count}} workflows.',
'configure-workflows': 'Configure Workflow List',
'configure-workflows-description':
'Add (<1></1>), re-arrange (<2></2>), and remove (<3></3>), Workflow Headings to personalize the Workflow List Table.',
Expand All @@ -46,6 +46,7 @@ export const Strings = {
terminated: 'Terminated',
canceled: 'Canceled',
paused: 'Paused',
reset: 'Reset',
'n-selected': '{{count, number}} selected',
'all-selected': 'All {{count, number}} selected.',
'select-all': 'select all {{count, number}}',
Expand Down
6 changes: 6 additions & 0 deletions src/lib/models/workflow-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ export enum ResetReapplyType {
Signal = 1,
None = 2,
}

export enum Action {
Cancel,
Reset,
Terminate,
}
5 changes: 2 additions & 3 deletions src/lib/pages/workflows-with-new-search.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,8 @@
bulkTerminateByIDs,
} from '$lib/services/batch-service';
import { updateQueryParameters } from '$lib/utilities/update-query-parameters';
import BatchOperationConfirmationModal, {
Action,
} from '$lib/components/workflow/batch-operation-confirmation-modal.svelte';
import BatchOperationConfirmationModal from '$lib/components/workflow/batch-operation-confirmation-modal.svelte';
import { Action } from '$lib/models/workflow-actions';
import { supportsAdvancedVisibility } from '$lib/stores/advanced-visibility';
import { toaster } from '$lib/stores/toaster';
import WorkflowsSummaryConfigurableTable from '$lib/components/workflow/workflows-summary-configurable-table.svelte';
Expand Down
4 changes: 3 additions & 1 deletion src/lib/services/batch-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { requestFromAPI } from '$lib/utilities/request-from-api';
import { routeForApi } from '$lib/utilities/route-for-api';
import { isVersionNewer } from '$lib/utilities/version-check';
import { temporalVersion } from '$lib/stores/versions';
import { getAuthUser } from '$lib/stores/auth-user';

import type {
StartBatchOperationRequest,
Expand Down Expand Up @@ -152,12 +153,13 @@ async function terminateWorkflows({
}: CreateBatchOperationOptions): Promise<string> {
const route = routeForApi('batch-operations', { namespace });
const jobId = uuidv4();
const identity = getAuthUser().email;

const body: StartBatchOperationRequest = {
jobId,
namespace,
reason,
terminationOperation: {},
terminationOperation: { ...(identity && { identity }) },
...(query && { visibilityQuery: query }),
...(executions && { executions }),
};
Expand Down
7 changes: 6 additions & 1 deletion src/lib/services/workflow-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type TerminateWorkflowOptions = {
workflow: WorkflowExecution;
namespace: string;
reason: string;
identity?: string;
};

export type ResetWorkflowOptions = {
Expand Down Expand Up @@ -244,14 +245,18 @@ export async function terminateWorkflow({
workflow,
namespace,
reason,
identity,
}: TerminateWorkflowOptions): Promise<null> {
const route = routeForApi('workflow.terminate', {
namespace,
workflowId: workflow.id,
runId: workflow.runId,
});
return await requestFromAPI<null>(route, {
options: { method: 'POST', body: stringifyWithBigInt({ reason }) },
options: {
method: 'POST',
body: stringifyWithBigInt({ reason, ...(identity && { identity }) }),
},
notifyOnError: false,
});
}
Expand Down
112 changes: 112 additions & 0 deletions src/lib/utilities/workflow-actions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { describe, it, expect } from 'vitest';
import { Action } from '../models/workflow-actions';
import { getPlacholder, formatReason } from './workflow-actions';

describe('getPlacholder', () => {
describe('without an authorized user', () => {
it('should return the correct placeholder', () => {
expect(getPlacholder(Action.Cancel)).toEqual('Canceled from the Web UI');
expect(getPlacholder(Action.Reset)).toEqual('Reset from the Web UI');
expect(getPlacholder(Action.Terminate)).toEqual(
'Terminated from the Web UI',
);
});
});

describe('with authorized user', () => {
it('should return the correct placeholder', () => {
expect(getPlacholder(Action.Cancel, '[email protected]')).toEqual(
'Canceled from the Web UI by [email protected]',
);
expect(getPlacholder(Action.Reset, '[email protected]')).toEqual(
'Reset from the Web UI by [email protected]',
);
expect(getPlacholder(Action.Terminate, '[email protected]')).toEqual(
'Terminated from the Web UI by [email protected]',
);
});
});
});

describe('formatReason', () => {
describe('without an authorized user', () => {
it('should return the reason with the placeholder', () => {
expect(
formatReason({ action: Action.Cancel, reason: 'Testing' }),
).toEqual('Testing Canceled from the Web UI');
expect(formatReason({ action: Action.Reset, reason: 'Testing' })).toEqual(
'Testing Reset from the Web UI',
);
expect(
formatReason({ action: Action.Terminate, reason: 'Testing' }),
).toEqual('Testing Terminated from the Web UI');
});
});

it('should return the placeholder if there is no reason', () => {
const reason = '';
expect(formatReason({ action: Action.Cancel, reason })).toEqual(
'Canceled from the Web UI',
);
expect(formatReason({ action: Action.Reset, reason })).toEqual(
'Reset from the Web UI',
);
expect(formatReason({ action: Action.Terminate, reason })).toEqual(
'Terminated from the Web UI',
);
});

describe('with an authorized user', () => {
it('should return the reason with the placeholder', () => {
const reason = 'Testing';

expect(
formatReason({
action: Action.Cancel,
reason,
email: '[email protected]',
}),
).toEqual('Testing Canceled from the Web UI by [email protected]');
expect(
formatReason({
action: Action.Reset,
reason,
email: '[email protected]',
}),
).toEqual('Testing Reset from the Web UI by [email protected]');
expect(
formatReason({
action: Action.Terminate,
reason,
email: '[email protected]',
}),
).toEqual('Testing Terminated from the Web UI by [email protected]');
});

it('should return the placeholder if there is no reason', () => {
const reason = '';

expect(
formatReason({
action: Action.Cancel,
reason,
email: '[email protected]',
}),
).toEqual('Canceled from the Web UI by [email protected]');
expect(
formatReason({
action: Action.Reset,
reason,
email: '[email protected]',
}),
).toEqual('Reset from the Web UI by [email protected]');
expect(
formatReason({
action: Action.Terminate,
reason,
email: '[email protected]',
}),
).toEqual('Terminated from the Web UI by [email protected]');
});
});
});
50 changes: 50 additions & 0 deletions src/lib/utilities/workflow-actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { translate } from '$lib/i18n/translate';
import { Action } from '$lib/models/workflow-actions';

type PastActionText = 'terminated' | 'reset' | 'canceled';

function unhandledAction(action: never) {
console.error('Unhandled action:', action);
}

const getPastTenseActionText = (action: Action): PastActionText => {
switch (action) {
case Action.Cancel:
return 'canceled';
case Action.Reset:
return 'reset';
case Action.Terminate:
return 'terminated';
default:
unhandledAction(action);
}
};

export const getPlacholder = (action: Action, email?: string): string => {
const translatedAction = translate(
'workflows',
getPastTenseActionText(action),
);

return email
? translate('workflows', 'workflow-action-reason-placeholder-with-email', {
action: translatedAction,
email,
})
: translate('workflows', 'workflow-action-reason-placeholder', {
action: translatedAction,
});
};

export const formatReason = ({
action,
reason,
email,
}: {
action: Action;
reason: string;
email?: string;
}) => {
const placeholder = getPlacholder(action, email);
return reason ? [reason.trim(), placeholder].join(' ') : placeholder;
};
7 changes: 4 additions & 3 deletions static/i18n/locales/en/workflows.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"cancel": "Cancel",
"reason": "Reason",
"batch-operation-modal-title": "{{action}} Workflows",
"batch-operation-confirmation-placeholder": "{{action}} from the Web UI",
"batch-operation-confirmation-placeholder-by-email": "{{action}} from the Web UI by {{email}}",
"workflow-action-reason-placeholder": "{{action}} from the Web UI",
"workflow-action-reason-placeholder-with-email": "{{action}} from the Web UI by {{email}}",
"batch-operation-confirmation-all": "Are you sure you want to {{action}} all workflows matching the following query? This action cannot be undone.",
"batch-operation-count-disclaimer": "Note: The actual count of workflows that will be affected is the total number of running workflows matching this query at the time of clicking \"{{action}}\".",
"batch-cancel-confirmation_one": "Are you sure you want to cancel {{count, number}} running workflow?",
Expand All @@ -19,7 +19,7 @@
"batch-terminate-all-success": "The batch $t(terminate) request is processing in the background.",
"batch-cancel-all-success": "The batch $t(cancel) request is processing in the background.",
"batch-terminate-success": "Successfully $t(terminated) {{count}} workflows.",
"batch-cancel-success": "Successfully $(canceled) {{count}} workflows.",
"batch-cancel-success": "Successfully $t(canceled) {{count}} workflows.",
"configure-workflows": "Configure Workflow List",
"configure-workflows-description": "Add (<1></1>), re-arrange (<2></2>), and remove (<3></3>), Workflow Headings to personalize the Workflow List Table.",
"all-statuses": "All Statuses",
Expand All @@ -32,6 +32,7 @@
"terminated": "Terminated",
"canceled": "Canceled",
"paused": "Paused",
"reset": "Reset",
"n-selected": "{{count, number}} selected",
"all-selected": "All {{count, number}} selected.",
"select-all": "select all {{count, number}}",
Expand Down

0 comments on commit b320645

Please sign in to comment.