Commit 54d39e51 authored by Paul Gascou-Vaillancourt's avatar Paul Gascou-Vaillancourt Committed by Natalia Tepluhina

Add edit and view results links to on-demand scans list

parent 5c65060d
...@@ -980,6 +980,14 @@ on-demand scans list. ...@@ -980,6 +980,14 @@ on-demand scans list.
To retry a scan that failed or succeeded with warnings, select **Retry** (**{retry}**) in the To retry a scan that failed or succeeded with warnings, select **Retry** (**{retry}**) in the
on-demand scans list. on-demand scans list.
#### View an on-demand scan's results
To view a finished scan's results, select **View results** in the on-demand scans list.
#### Edit an on-demand scan
To edit an on-demand scan's settings, select **Edit** (**{pencil}**) in the **Scheduled** tab.
### Run an on-demand DAST scan ### Run an on-demand DAST scan
Prerequisites: Prerequisites:
......
...@@ -39,10 +39,12 @@ export default { ...@@ -39,10 +39,12 @@ export default {
<template> <template>
<span> <span>
<gl-button <gl-button
v-bind="$attrs"
:id="buttonId" :id="buttonId"
:aria-label="label" :aria-label="label"
:loading="isLoading" :loading="isLoading"
:icon="actionType" :icon="actionType"
size="small"
@click="onClick" @click="onClick"
/> />
<gl-tooltip ref="tooltip" :target="buttonId" placement="top" triggers="hover" noninteractive> <gl-tooltip ref="tooltip" :target="buttonId" placement="top" triggers="hover" noninteractive>
......
<script> <script>
import { GlButton } from '@gitlab/ui';
import pipelineCancelMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql'; import pipelineCancelMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql';
import pipelineRetryMutation from '~/pipelines/graphql/mutations/retry_pipeline.mutation.graphql'; import pipelineRetryMutation from '~/pipelines/graphql/mutations/retry_pipeline.mutation.graphql';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
...@@ -7,6 +8,7 @@ import { ...@@ -7,6 +8,7 @@ import {
PIPELINES_GROUP_PENDING, PIPELINES_GROUP_PENDING,
PIPELINES_GROUP_SUCCESS_WITH_WARNINGS, PIPELINES_GROUP_SUCCESS_WITH_WARNINGS,
PIPELINES_GROUP_FAILED, PIPELINES_GROUP_FAILED,
PIPELINES_GROUP_SUCCESS,
} from '../constants'; } from '../constants';
import ActionButton from './action_button.vue'; import ActionButton from './action_button.vue';
...@@ -18,6 +20,7 @@ export const retryError = s__('OnDemandScans|The scan could not be retried.'); ...@@ -18,6 +20,7 @@ export const retryError = s__('OnDemandScans|The scan could not be retried.');
export default { export default {
components: { components: {
GlButton,
ActionButton, ActionButton,
}, },
props: { props: {
...@@ -43,6 +46,12 @@ export default { ...@@ -43,6 +46,12 @@ export default {
this.scan?.detailedStatus?.group, this.scan?.detailedStatus?.group,
); );
}, },
isEditable() {
return Boolean(this.scan.editPath);
},
hasResults() {
return this.isRetryable || this.scan?.detailedStatus?.group === PIPELINES_GROUP_SUCCESS;
},
}, },
watch: { watch: {
'scan.detailedStatus.group': function detailedStatusGroupWatcher() { 'scan.detailedStatus.group': function detailedStatusGroupWatcher() {
...@@ -98,12 +107,22 @@ export default { ...@@ -98,12 +107,22 @@ export default {
cancelError, cancelError,
retry: __('Retry'), retry: __('Retry'),
retryError, retryError,
edit: __('Edit'),
viewResults: s__('OnDemandScans|View results'),
}, },
}; };
</script> </script>
<template> <template>
<div class="gl-text-right"> <div class="gl-display-flex gl-justify-content-end">
<gl-button
v-if="hasResults"
data-testid="view-scan-results-button"
size="small"
:href="scan.path"
>
{{ $options.i18n.viewResults }}
</gl-button>
<ActionButton <ActionButton
v-if="isCancellable" v-if="isCancellable"
data-testid="cancel-scan-button" data-testid="cancel-scan-button"
...@@ -114,11 +133,19 @@ export default { ...@@ -114,11 +133,19 @@ export default {
/> />
<ActionButton <ActionButton
v-if="isRetryable" v-if="isRetryable"
class="gl-ml-3"
data-testid="retry-scan-button" data-testid="retry-scan-button"
action-type="retry" action-type="retry"
:label="$options.i18n.retry" :label="$options.i18n.retry"
:is-loading="isRetrying" :is-loading="isRetrying"
@click="retryPipeline" @click="retryPipeline"
/> />
<ActionButton
v-if="isEditable"
data-testid="edit-scan-button"
action-type="pencil"
:label="$options.i18n.edit"
:href="scan.editPath"
/>
</div> </div>
</template> </template>
...@@ -146,7 +146,7 @@ export default { ...@@ -146,7 +146,7 @@ export default {
{ {
label: '', label: '',
key: 'actions', key: 'actions',
columnClass: 'gl-w-13', columnClass: 'gl-w-15',
}, },
].map((field) => ({ ].map((field) => ({
...field, ...field,
......
...@@ -23,6 +23,7 @@ export const PIPELINES_GROUP_RUNNING = 'running'; ...@@ -23,6 +23,7 @@ export const PIPELINES_GROUP_RUNNING = 'running';
export const PIPELINES_GROUP_PENDING = 'pending'; export const PIPELINES_GROUP_PENDING = 'pending';
export const PIPELINES_GROUP_SUCCESS_WITH_WARNINGS = 'success-with-warnings'; export const PIPELINES_GROUP_SUCCESS_WITH_WARNINGS = 'success-with-warnings';
export const PIPELINES_GROUP_FAILED = 'success-with-warnings'; export const PIPELINES_GROUP_FAILED = 'success-with-warnings';
export const PIPELINES_GROUP_SUCCESS = 'success';
const STATUS_COLUMN = { const STATUS_COLUMN = {
label: __('Status'), label: __('Status'),
......
...@@ -2,10 +2,14 @@ ...@@ -2,10 +2,14 @@
exports[`Actions doesn't render anything if the scan status is not supported 1`] = ` exports[`Actions doesn't render anything if the scan status is not supported 1`] = `
<div <div
class="gl-text-right" class="gl-display-flex gl-justify-content-end"
> >
<!----> <!---->
<!----> <!---->
<!---->
<!---->
</div> </div>
`; `;
...@@ -39,6 +39,7 @@ describe('ActionButton', () => { ...@@ -39,6 +39,7 @@ describe('ActionButton', () => {
it('sets the label on the button and in the tooltip', () => { it('sets the label on the button and in the tooltip', () => {
createComponent(); createComponent();
expect(findButton().attributes('aria-label')).toBe(label); expect(findButton().attributes('aria-label')).toBe(label);
expect(findTooltip().text()).toBe(label); expect(findTooltip().text()).toBe(label);
}); });
...@@ -63,4 +64,13 @@ describe('ActionButton', () => { ...@@ -63,4 +64,13 @@ describe('ActionButton', () => {
expect(findButton().props('loading')).toBe(true); expect(findButton().props('loading')).toBe(true);
}); });
it('passes attributes down to the button', () => {
const href = '/edit/path';
createComponent({
href,
});
expect(findButton().attributes('href')).toBe(href);
});
}); });
...@@ -6,6 +6,7 @@ import { ...@@ -6,6 +6,7 @@ import {
PIPELINES_GROUP_PENDING, PIPELINES_GROUP_PENDING,
PIPELINES_GROUP_SUCCESS_WITH_WARNINGS, PIPELINES_GROUP_SUCCESS_WITH_WARNINGS,
PIPELINES_GROUP_FAILED, PIPELINES_GROUP_FAILED,
PIPELINES_GROUP_SUCCESS,
} from 'ee/on_demand_scans/constants'; } from 'ee/on_demand_scans/constants';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import pipelineCancelMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql'; import pipelineCancelMutation from '~/pipelines/graphql/mutations/cancel_pipeline.mutation.graphql';
...@@ -22,11 +23,17 @@ const scanFactory = (group) => ({ ...@@ -22,11 +23,17 @@ const scanFactory = (group) => ({
detailedStatus: { detailedStatus: {
group, group,
}, },
path: '/pipelines/1',
}); });
const runningScan = scanFactory(PIPELINES_GROUP_RUNNING); const runningScan = scanFactory(PIPELINES_GROUP_RUNNING);
const pendingScan = scanFactory(PIPELINES_GROUP_PENDING); const pendingScan = scanFactory(PIPELINES_GROUP_PENDING);
const successWithWarningsScan = scanFactory(PIPELINES_GROUP_SUCCESS_WITH_WARNINGS); const successWithWarningsScan = scanFactory(PIPELINES_GROUP_SUCCESS_WITH_WARNINGS);
const failedScan = scanFactory(PIPELINES_GROUP_FAILED); const failedScan = scanFactory(PIPELINES_GROUP_FAILED);
const succeededScan = scanFactory(PIPELINES_GROUP_SUCCESS);
const scheduledScan = {
id: mockPipelineId,
editPath: '/edit/1',
};
// Error messages // Error messages
const errorAsDataMessage = 'Error as data'; const errorAsDataMessage = 'Error as data';
...@@ -39,6 +46,8 @@ describe('Actions', () => { ...@@ -39,6 +46,8 @@ describe('Actions', () => {
// Finders // Finders
const findCancelScanButton = () => wrapper.findByTestId('cancel-scan-button'); const findCancelScanButton = () => wrapper.findByTestId('cancel-scan-button');
const findRetryScanButton = () => wrapper.findByTestId('retry-scan-button'); const findRetryScanButton = () => wrapper.findByTestId('retry-scan-button');
const findEditScanButton = () => wrapper.findByTestId('edit-scan-button');
const findViewScanResultsButton = () => wrapper.findByTestId('view-scan-results-button');
// Helpers // Helpers
const createMockApolloProvider = (mutation, handler) => { const createMockApolloProvider = (mutation, handler) => {
...@@ -139,4 +148,25 @@ describe('Actions', () => { ...@@ -139,4 +148,25 @@ describe('Actions', () => {
}); });
}); });
}); });
it('renders an edit link for scheduled scans', () => {
createComponent(scheduledScan);
const editButton = findEditScanButton();
expect(editButton.exists()).toBe(true);
expect(editButton.attributes('href')).toBe(scheduledScan.editPath);
});
it.each`
scanStatus | scan
${'success with warnings'} | ${successWithWarningsScan}
${'failed'} | ${failedScan}
${'succeeded'} | ${succeededScan}
`('renders a "View results" button for $scanStatus scans', ({ scan }) => {
createComponent(scan);
const viewScanResultsButton = findViewScanResultsButton();
expect(viewScanResultsButton.exists()).toBe(true);
expect(viewScanResultsButton.attributes('href')).toBe(scan.path);
});
}); });
...@@ -24508,6 +24508,9 @@ msgstr "" ...@@ -24508,6 +24508,9 @@ msgstr ""
msgid "OnDemandScans|Use existing site profile" msgid "OnDemandScans|Use existing site profile"
msgstr "" msgstr ""
msgid "OnDemandScans|View results"
msgstr ""
msgid "OnDemandScans|You must create a repository within your project to run an on-demand scan." msgid "OnDemandScans|You must create a repository within your project to run an on-demand scan."
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment