diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-18 23:02:30 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-18 23:02:30 +0300 |
commit | 41fe97390ceddf945f3d967b8fdb3de4c66b7dea (patch) | |
tree | 9c8d89a8624828992f06d892cd2f43818ff5dcc8 /app/assets/javascripts/runner | |
parent | 0804d2dc31052fb45a1efecedc8e06ce9bc32862 (diff) |
Add latest changes from gitlab-org/gitlab@14-9-stable-eev14.9.0-rc42
Diffstat (limited to 'app/assets/javascripts/runner')
29 files changed, 290 insertions, 205 deletions
diff --git a/app/assets/javascripts/runner/admin_runner_edit/admin_runner_edit_app.vue b/app/assets/javascripts/runner/admin_runner_edit/admin_runner_edit_app.vue index 4d2ca9b0c58..c2db3b9facd 100644 --- a/app/assets/javascripts/runner/admin_runner_edit/admin_runner_edit_app.vue +++ b/app/assets/javascripts/runner/admin_runner_edit/admin_runner_edit_app.vue @@ -5,7 +5,7 @@ import { convertToGraphQLId } from '~/graphql_shared/utils'; import RunnerHeader from '../components/runner_header.vue'; import RunnerUpdateForm from '../components/runner_update_form.vue'; import { I18N_FETCH_ERROR } from '../constants'; -import getRunnerQuery from '../graphql/get_runner.query.graphql'; +import runnerQuery from '../graphql/details/runner.query.graphql'; import { captureException } from '../sentry_utils'; export default { @@ -27,7 +27,7 @@ export default { }, apollo: { runner: { - query: getRunnerQuery, + query: runnerQuery, variables() { return { id: convertToGraphQLId(TYPE_CI_RUNNER, this.runnerId), diff --git a/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue b/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue index 2795ddbbbcb..86ad912f017 100644 --- a/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue +++ b/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue @@ -8,7 +8,7 @@ import RunnerPauseButton from '../components/runner_pause_button.vue'; import RunnerHeader from '../components/runner_header.vue'; import RunnerDetails from '../components/runner_details.vue'; import { I18N_FETCH_ERROR } from '../constants'; -import getRunnerQuery from '../graphql/get_runner.query.graphql'; +import runnerQuery from '../graphql/details/runner.query.graphql'; import { captureException } from '../sentry_utils'; export default { @@ -35,7 +35,7 @@ export default { }, apollo: { runner: { - query: getRunnerQuery, + query: runnerQuery, variables() { return { id: convertToGraphQLId(TYPE_CI_RUNNER, this.runnerId), diff --git a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue index a968d4029f8..8aba91eedf7 100644 --- a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue +++ b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue @@ -12,6 +12,7 @@ import RunnerName from '../components/runner_name.vue'; import RunnerStats from '../components/stat/runner_stats.vue'; import RunnerPagination from '../components/runner_pagination.vue'; import RunnerTypeTabs from '../components/runner_type_tabs.vue'; +import RunnerActionsCell from '../components/cells/runner_actions_cell.vue'; import { statusTokenConfig } from '../components/search_tokens/status_token_config'; import { tagTokenConfig } from '../components/search_tokens/tag_token_config'; @@ -25,8 +26,8 @@ import { STATUS_STALE, I18N_FETCH_ERROR, } from '../constants'; -import getRunnersQuery from '../graphql/get_runners.query.graphql'; -import getRunnersCountQuery from '../graphql/get_runners_count.query.graphql'; +import runnersAdminQuery from '../graphql/list/admin_runners.query.graphql'; +import runnersAdminCountQuery from '../graphql/list/admin_runners_count.query.graphql'; import { fromUrlQueryToSearch, fromSearchToUrl, @@ -35,7 +36,7 @@ import { import { captureException } from '../sentry_utils'; const runnersCountSmartQuery = { - query: getRunnersCountQuery, + query: runnersAdminCountQuery, fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, update(data) { return data?.runners?.count; @@ -57,6 +58,7 @@ export default { RunnerStats, RunnerPagination, RunnerTypeTabs, + RunnerActionsCell, }, props: { registrationToken: { @@ -75,7 +77,7 @@ export default { }, apollo: { runners: { - query: getRunnersQuery, + query: runnersAdminQuery, // Runners can be updated by users directly in this list. // A "cache and network" policy prevents outdated filtered // results. @@ -187,6 +189,7 @@ export default { deep: true, handler() { // TODO Implement back button response using onpopstate + // See: https://gitlab.com/gitlab-org/gitlab/-/issues/333804 updateHistory({ url: fromSearchToUrl(this.search), title: document.title, @@ -221,6 +224,10 @@ export default { } return ''; }, + onDeleted({ message }) { + this.$root.$toast?.show(message); + this.$apollo.queries.runners.refetch(); + }, reportToSentry(error) { captureException({ error, component: this.$options.name }); }, @@ -278,6 +285,13 @@ export default { <runner-name :runner="runner" /> </gl-link> </template> + <template #runner-actions-cell="{ runner }"> + <runner-actions-cell + :runner="runner" + :edit-url="runner.editAdminUrl" + @deleted="onDeleted" + /> + </template> </runner-list> <runner-pagination v-model="search.pagination" diff --git a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue index ae9c774f2a2..c69321de001 100644 --- a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue +++ b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue @@ -1,60 +1,30 @@ <script> -import { GlButton, GlButtonGroup, GlModalDirective, GlTooltipDirective } from '@gitlab/ui'; -import { createAlert } from '~/flash'; -import { s__, sprintf } from '~/locale'; -import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphql'; -import { captureException } from '~/runner/sentry_utils'; -import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import { GlButtonGroup } from '@gitlab/ui'; import RunnerEditButton from '../runner_edit_button.vue'; import RunnerPauseButton from '../runner_pause_button.vue'; -import RunnerDeleteModal from '../runner_delete_modal.vue'; - -const I18N_DELETE = s__('Runners|Delete runner'); -const I18N_DELETED_TOAST = s__('Runners|Runner %{name} was deleted'); +import RunnerDeleteButton from '../runner_delete_button.vue'; export default { name: 'RunnerActionsCell', components: { - GlButton, GlButtonGroup, RunnerEditButton, RunnerPauseButton, - RunnerDeleteModal, - }, - directives: { - GlTooltip: GlTooltipDirective, - GlModal: GlModalDirective, + RunnerDeleteButton, }, props: { runner: { type: Object, required: true, }, + editUrl: { + type: String, + default: null, + required: false, + }, }, - data() { - return { - updating: false, - deleting: false, - }; - }, + emits: ['deleted'], computed: { - deleteTitle() { - if (this.deleting) { - // Prevent a "sticky" tooltip: If this button is disabled, - // mouseout listeners don't run leaving the tooltip stuck - return ''; - } - return I18N_DELETE; - }, - runnerId() { - return getIdFromGraphQLId(this.runner.id); - }, - runnerName() { - return `#${this.runnerId} (${this.runner.shortSha})`; - }, - runnerDeleteModalId() { - return `delete-runner-modal-${this.runnerId}`; - }, canUpdate() { return this.runner.userPermissions?.updateRunner; }, @@ -63,79 +33,17 @@ export default { }, }, methods: { - async onDelete() { - // Deleting stays "true" until this row is removed, - // should only change back if the operation fails. - this.deleting = true; - try { - const { - data: { - runnerDelete: { errors }, - }, - } = await this.$apollo.mutate({ - mutation: runnerDeleteMutation, - variables: { - input: { - id: this.runner.id, - }, - }, - awaitRefetchQueries: true, - refetchQueries: ['getRunners', 'getGroupRunners'], - }); - if (errors && errors.length) { - throw new Error(errors.join(' ')); - } else { - // Use $root to have the toast message stay after this element is removed - this.$root.$toast?.show(sprintf(I18N_DELETED_TOAST, { name: this.runnerName })); - } - } catch (e) { - this.deleting = false; - this.onError(e); - } - }, - - onError(error) { - const { message } = error; - createAlert({ message }); - - this.reportToSentry(error); - }, - reportToSentry(error) { - captureException({ error, component: this.$options.name }); + onDeleted(value) { + this.$emit('deleted', value); }, }, - I18N_DELETE, }; </script> <template> <gl-button-group> - <!-- - This button appears for administrators: those with - access to the adminUrl. More advanced permissions policies - will allow more granular permissions. - - See https://gitlab.com/gitlab-org/gitlab/-/issues/334802 - --> - <runner-edit-button v-if="canUpdate && runner.editAdminUrl" :href="runner.editAdminUrl" /> + <runner-edit-button v-if="canUpdate && editUrl" :href="editUrl" /> <runner-pause-button v-if="canUpdate" :runner="runner" :compact="true" /> - <gl-button - v-if="canDelete" - v-gl-tooltip.hover.viewport="deleteTitle" - v-gl-modal="runnerDeleteModalId" - :aria-label="deleteTitle" - icon="close" - :loading="deleting" - variant="danger" - data-testid="delete-runner" - /> - - <runner-delete-modal - v-if="canDelete" - :ref="runnerDeleteModalId" - :modal-id="runnerDeleteModalId" - :runner-name="runnerName" - @primary="onDelete" - /> + <runner-delete-button v-if="canDelete" :runner="runner" :compact="true" @deleted="onDeleted" /> </gl-button-group> </template> diff --git a/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue b/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue index 54c35e483dc..1234054c660 100644 --- a/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue +++ b/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue @@ -4,7 +4,7 @@ import { createAlert } from '~/flash'; import { TYPE_GROUP, TYPE_PROJECT } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { __, s__ } from '~/locale'; -import runnersRegistrationTokenResetMutation from '~/runner/graphql/runners_registration_token_reset.mutation.graphql'; +import runnersRegistrationTokenResetMutation from '~/runner/graphql/list/runners_registration_token_reset.mutation.graphql'; import { captureException } from '~/runner/sentry_utils'; import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants'; @@ -98,17 +98,14 @@ export default { }, onError(error) { const { message } = error; - createAlert({ message }); - this.reportToSentry(error); + createAlert({ message }); + captureException({ error, component: this.$options.name }); }, onSuccess(token) { this.$toast?.show(s__('Runners|New registration token generated!')); this.$emit('tokenReset', token); }, - reportToSentry(error) { - captureException({ error, component: this.$options.name }); - }, }, }; </script> diff --git a/app/assets/javascripts/runner/components/runner_delete_button.vue b/app/assets/javascripts/runner/components/runner_delete_button.vue new file mode 100644 index 00000000000..854c983f4da --- /dev/null +++ b/app/assets/javascripts/runner/components/runner_delete_button.vue @@ -0,0 +1,144 @@ +<script> +import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui'; +import runnerDeleteMutation from '~/runner/graphql/shared/runner_delete.mutation.graphql'; +import { createAlert } from '~/flash'; +import { sprintf } from '~/locale'; +import { captureException } from '~/runner/sentry_utils'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import { I18N_DELETE_RUNNER, I18N_DELETED_TOAST } from '../constants'; +import RunnerDeleteModal from './runner_delete_modal.vue'; + +export default { + name: 'RunnerDeleteButton', + components: { + GlButton, + RunnerDeleteModal, + }, + directives: { + GlTooltip: GlTooltipDirective, + GlModal: GlModalDirective, + }, + props: { + runner: { + type: Object, + required: true, + validator: (runner) => { + return runner?.id && runner?.shortSha; + }, + }, + compact: { + type: Boolean, + required: false, + default: false, + }, + }, + emits: ['deleted'], + data() { + return { + deleting: false, + }; + }, + computed: { + runnerId() { + return getIdFromGraphQLId(this.runner.id); + }, + runnerName() { + return `#${this.runnerId} (${this.runner.shortSha})`; + }, + runnerDeleteModalId() { + return `delete-runner-modal-${this.runnerId}`; + }, + icon() { + if (this.compact) { + return 'close'; + } + return ''; + }, + buttonContent() { + if (this.compact) { + return null; + } + return I18N_DELETE_RUNNER; + }, + buttonClass() { + // Ensure a square button is shown when compact: true. + // Without this class we will have distorted/rectangular button. + if (this.compact) { + return 'btn-icon'; + } + return null; + }, + ariaLabel() { + if (this.compact) { + return I18N_DELETE_RUNNER; + } + return null; + }, + tooltip() { + // Only show tooltip when compact. + // Also prevent a "sticky" tooltip: If this button is + // disabled, mouseout listeners don't run leaving the tooltip stuck + if (this.compact && !this.deleting) { + return I18N_DELETE_RUNNER; + } + return ''; + }, + }, + methods: { + async onDelete() { + // Deleting stays "true" until this row is removed, + // should only change back if the operation fails. + this.deleting = true; + try { + const { + data: { + runnerDelete: { errors }, + }, + } = await this.$apollo.mutate({ + mutation: runnerDeleteMutation, + variables: { + input: { + id: this.runner.id, + }, + }, + }); + if (errors && errors.length) { + throw new Error(errors.join(' ')); + } else { + this.$emit('deleted', { + message: sprintf(I18N_DELETED_TOAST, { name: this.runnerName }), + }); + } + } catch (e) { + this.deleting = false; + this.onError(e); + } + }, + onError(error) { + const { message } = error; + + createAlert({ message }); + captureException({ error, component: this.$options.name }); + }, + }, +}; +</script> + +<template> + <gl-button + v-gl-tooltip.hover.viewport="tooltip" + v-gl-modal="runnerDeleteModalId" + :aria-label="ariaLabel" + :icon="icon" + :class="buttonClass" + :loading="deleting" + variant="danger" + > + {{ buttonContent }} + <runner-delete-modal + :modal-id="runnerDeleteModalId" + :runner-name="runnerName" + @primary="onDelete" + /> + </gl-button> +</template> diff --git a/app/assets/javascripts/runner/components/runner_edit_button.vue b/app/assets/javascripts/runner/components/runner_edit_button.vue index b115be09e69..33e0acaf5c0 100644 --- a/app/assets/javascripts/runner/components/runner_edit_button.vue +++ b/app/assets/javascripts/runner/components/runner_edit_button.vue @@ -1,8 +1,6 @@ <script> import { GlButton, GlTooltipDirective } from '@gitlab/ui'; -import { __ } from '~/locale'; - -const I18N_EDIT = __('Edit'); +import { I18N_EDIT } from '../constants'; export default { components: { diff --git a/app/assets/javascripts/runner/components/runner_jobs.vue b/app/assets/javascripts/runner/components/runner_jobs.vue index c13e7e90168..eb77babcc57 100644 --- a/app/assets/javascripts/runner/components/runner_jobs.vue +++ b/app/assets/javascripts/runner/components/runner_jobs.vue @@ -1,7 +1,7 @@ <script> import { GlSkeletonLoading } from '@gitlab/ui'; import { createAlert } from '~/flash'; -import getRunnerJobsQuery from '../graphql/get_runner_jobs.query.graphql'; +import runnerJobsQuery from '../graphql/details/runner_jobs.query.graphql'; import { I18N_FETCH_ERROR, I18N_NO_JOBS_FOUND, RUNNER_DETAILS_JOBS_PAGE_SIZE } from '../constants'; import { captureException } from '../sentry_utils'; import { getPaginationVariables } from '../utils'; @@ -34,7 +34,7 @@ export default { }, apollo: { jobs: { - query: getRunnerJobsQuery, + query: runnerJobsQuery, variables() { return this.variables; }, @@ -46,7 +46,7 @@ export default { }, error(error) { createAlert({ message: I18N_FETCH_ERROR }); - this.reportToSentry(error); + captureException({ error, component: this.$options.name }); }, }, }, @@ -62,11 +62,6 @@ export default { return this.$apollo.queries.jobs.loading; }, }, - methods: { - reportToSentry(error) { - captureException({ error, component: this.$options.name }); - }, - }, I18N_NO_JOBS_FOUND, }; </script> diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/runner/components/runner_list.vue index bb36882d3ae..51749b0255f 100644 --- a/app/assets/javascripts/runner/components/runner_list.vue +++ b/app/assets/javascripts/runner/components/runner_list.vue @@ -1,22 +1,20 @@ <script> -import { GlTable, GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui'; +import { GlTableLite, GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { __, s__ } from '~/locale'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import { formatJobCount, tableField } from '../utils'; -import RunnerActionsCell from './cells/runner_actions_cell.vue'; import RunnerSummaryCell from './cells/runner_summary_cell.vue'; import RunnerStatusCell from './cells/runner_status_cell.vue'; import RunnerTags from './runner_tags.vue'; export default { components: { - GlTable, + GlTableLite, GlSkeletonLoader, TooltipOnTruncate, TimeAgo, - RunnerActionsCell, RunnerSummaryCell, RunnerTags, RunnerStatusCell, @@ -35,6 +33,16 @@ export default { required: true, }, }, + computed: { + tableClass() { + // <gl-table-lite> does not provide a busy state, add + // simple support for it. + // See http://bootstrap-vue.org/docs/components/table#table-busy-state + return { + 'gl-opacity-6': this.loading, + }; + }, + }, methods: { formatJobCount(jobCount) { return formatJobCount(jobCount); @@ -62,8 +70,9 @@ export default { </script> <template> <div> - <gl-table - :busy="loading" + <gl-table-lite + :aria-busy="loading" + :class="tableClass" :items="runners" :fields="$options.fields" :tbody-tr-attr="runnerTrAttr" @@ -72,10 +81,6 @@ export default { primary-key="id" fixed > - <template v-if="!runners.length" #table-busy> - <gl-skeleton-loader v-for="i in 4" :key="i" /> - </template> - <template #cell(status)="{ item }"> <runner-status-cell :runner="item" /> </template> @@ -114,8 +119,12 @@ export default { </template> <template #cell(actions)="{ item }"> - <runner-actions-cell :runner="item" /> + <slot name="runner-actions-cell" :runner="item"></slot> </template> - </gl-table> + </gl-table-lite> + + <template v-if="!runners.length && loading"> + <gl-skeleton-loader v-for="i in 4" :key="i" /> + </template> </div> </template> diff --git a/app/assets/javascripts/runner/components/runner_pause_button.vue b/app/assets/javascripts/runner/components/runner_pause_button.vue index a8b259f5b90..c88634bfbd9 100644 --- a/app/assets/javascripts/runner/components/runner_pause_button.vue +++ b/app/assets/javascripts/runner/components/runner_pause_button.vue @@ -1,9 +1,9 @@ <script> import { GlButton, GlTooltipDirective } from '@gitlab/ui'; -import runnerToggleActiveMutation from '~/runner/graphql/runner_toggle_active.mutation.graphql'; +import runnerToggleActiveMutation from '~/runner/graphql/shared/runner_toggle_active.mutation.graphql'; import { createAlert } from '~/flash'; import { captureException } from '~/runner/sentry_utils'; -import { I18N_PAUSE, I18N_RESUME } from '../constants'; +import { I18N_PAUSE, I18N_PAUSE_TOOLTIP, I18N_RESUME, I18N_RESUME_TOOLTIP } from '../constants'; export default { name: 'RunnerPauseButton', @@ -52,11 +52,10 @@ export default { return null; }, tooltip() { - // Only show tooltip when compact. - // Also prevent a "sticky" tooltip: If this button is - // disabled, mouseout listeners don't run leaving the tooltip stuck - if (this.compact && !this.updating) { - return this.label; + // Prevent a "sticky" tooltip: If this button is disabled, + // mouseout listeners don't run leaving the tooltip stuck + if (!this.updating) { + return this.isActive ? I18N_PAUSE_TOOLTIP : I18N_RESUME_TOOLTIP; } return ''; }, @@ -92,11 +91,8 @@ export default { }, onError(error) { const { message } = error; - createAlert({ message }); - this.reportToSentry(error); - }, - reportToSentry(error) { + createAlert({ message }); captureException({ error, component: this.$options.name }); }, }, @@ -105,7 +101,7 @@ export default { <template> <gl-button - v-gl-tooltip.hover.viewport="tooltip" + v-gl-tooltip="tooltip" v-bind="$attrs" :aria-label="ariaLabel" :icon="icon" diff --git a/app/assets/javascripts/runner/components/runner_paused_badge.vue b/app/assets/javascripts/runner/components/runner_paused_badge.vue index d1e6fa05e4d..27618290ce6 100644 --- a/app/assets/javascripts/runner/components/runner_paused_badge.vue +++ b/app/assets/javascripts/runner/components/runner_paused_badge.vue @@ -1,6 +1,6 @@ <script> import { GlBadge, GlTooltipDirective } from '@gitlab/ui'; -import { I18N_PAUSED_RUNNER_DESCRIPTION } from '../constants'; +import { I18N_PAUSED_DESCRIPTION } from '../constants'; export default { components: { @@ -9,17 +9,11 @@ export default { directives: { GlTooltip: GlTooltipDirective, }, - i18n: { - I18N_PAUSED_RUNNER_DESCRIPTION, - }, + I18N_PAUSED_DESCRIPTION, }; </script> <template> - <gl-badge - v-gl-tooltip="$options.i18n.I18N_PAUSED_RUNNER_DESCRIPTION" - variant="danger" - v-bind="$attrs" - > + <gl-badge v-gl-tooltip="$options.I18N_PAUSED_DESCRIPTION" variant="danger" v-bind="$attrs"> {{ s__('Runners|paused') }} </gl-badge> </template> diff --git a/app/assets/javascripts/runner/components/runner_projects.vue b/app/assets/javascripts/runner/components/runner_projects.vue index c4065a24ff2..f8ec29b8a24 100644 --- a/app/assets/javascripts/runner/components/runner_projects.vue +++ b/app/assets/javascripts/runner/components/runner_projects.vue @@ -2,7 +2,7 @@ import { GlSkeletonLoading } from '@gitlab/ui'; import { sprintf, formatNumber } from '~/locale'; import { createAlert } from '~/flash'; -import getRunnerProjectsQuery from '../graphql/get_runner_projects.query.graphql'; +import runnerProjectsQuery from '../graphql/details/runner_projects.query.graphql'; import { I18N_ASSIGNED_PROJECTS, I18N_NONE, @@ -41,7 +41,7 @@ export default { }, apollo: { projects: { - query: getRunnerProjectsQuery, + query: runnerProjectsQuery, variables() { return this.variables; }, @@ -55,8 +55,7 @@ export default { }, error(error) { createAlert({ message: I18N_FETCH_ERROR }); - - this.reportToSentry(error); + captureException({ error, component: this.$options.name }); }, }, }, @@ -77,11 +76,6 @@ export default { }); }, }, - methods: { - reportToSentry(error) { - captureException({ error, component: this.$options.name }); - }, - }, I18N_NONE, }; </script> diff --git a/app/assets/javascripts/runner/components/runner_update_form.vue b/app/assets/javascripts/runner/components/runner_update_form.vue index e3deb94236e..e44450a2a8d 100644 --- a/app/assets/javascripts/runner/components/runner_update_form.vue +++ b/app/assets/javascripts/runner/components/runner_update_form.vue @@ -15,7 +15,7 @@ import { createAlert, VARIANT_SUCCESS } from '~/flash'; import { __ } from '~/locale'; import { captureException } from '~/runner/sentry_utils'; import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants'; -import runnerUpdateMutation from '../graphql/runner_update.mutation.graphql'; +import runnerUpdateMutation from '../graphql/details/runner_update.mutation.graphql'; export default { name: 'RunnerUpdateForm', @@ -82,9 +82,9 @@ export default { this.onSuccess(); } catch (error) { const { message } = error; - createAlert({ message }); - this.reportToSentry(error); + createAlert({ message }); + captureException({ error, component: this.$options.name }); } finally { this.saving = false; } @@ -93,9 +93,6 @@ export default { createAlert({ message: __('Changes saved.'), variant: VARIANT_SUCCESS }); this.model = runnerToModel(this.runner); }, - reportToSentry(error) { - captureException({ error, component: this.$options.name }); - }, }, ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, diff --git a/app/assets/javascripts/runner/constants.js b/app/assets/javascripts/runner/constants.js index 1544efaaae2..bd5be2175ad 100644 --- a/app/assets/javascripts/runner/constants.js +++ b/app/assets/javascripts/runner/constants.js @@ -35,12 +35,20 @@ export const I18N_STALE_RUNNER_DESCRIPTION = s__( 'Runners|No contact from this runner in over 3 months', ); -// Active flag +// Actions +export const I18N_EDIT = __('Edit'); + export const I18N_PAUSE = __('Pause'); +export const I18N_PAUSE_TOOLTIP = s__('Runners|Pause from accepting jobs'); +export const I18N_PAUSED_DESCRIPTION = s__('Runners|Not accepting jobs'); + export const I18N_RESUME = __('Resume'); +export const I18N_RESUME_TOOLTIP = s__('Runners|Resume accepting jobs'); + +export const I18N_DELETE_RUNNER = s__('Runners|Delete runner'); +export const I18N_DELETED_TOAST = s__('Runners|Runner %{name} was deleted'); export const I18N_LOCKED_RUNNER_DESCRIPTION = s__('Runners|You cannot assign to other projects'); -export const I18N_PAUSED_RUNNER_DESCRIPTION = s__('Runners|Not available to run jobs'); // Runner details @@ -91,8 +99,8 @@ export const ACCESS_LEVEL_REF_PROTECTED = 'REF_PROTECTED'; // CiRunnerSort export const CREATED_DESC = 'CREATED_DESC'; -export const CREATED_ASC = 'CREATED_ASC'; // TODO Add this to the API -export const CONTACTED_DESC = 'CONTACTED_DESC'; // TODO Add this to the API +export const CREATED_ASC = 'CREATED_ASC'; +export const CONTACTED_DESC = 'CONTACTED_DESC'; export const CONTACTED_ASC = 'CONTACTED_ASC'; export const DEFAULT_SORT = CREATED_DESC; diff --git a/app/assets/javascripts/runner/graphql/get_runner.query.graphql b/app/assets/javascripts/runner/graphql/details/runner.query.graphql index f6ce8281c64..4792a186160 100644 --- a/app/assets/javascripts/runner/graphql/get_runner.query.graphql +++ b/app/assets/javascripts/runner/graphql/details/runner.query.graphql @@ -1,10 +1,9 @@ -#import "ee_else_ce/runner/graphql/runner_details.fragment.graphql" +#import "ee_else_ce/runner/graphql/details/runner_details.fragment.graphql" query getRunner($id: CiRunnerID!) { # We have an id in deeply nested fragment # eslint-disable-next-line @graphql-eslint/require-id-when-available runner(id: $id) { - __typename ...RunnerDetails } } diff --git a/app/assets/javascripts/runner/graphql/runner_details.fragment.graphql b/app/assets/javascripts/runner/graphql/details/runner_details.fragment.graphql index 2449ee0fc0f..2449ee0fc0f 100644 --- a/app/assets/javascripts/runner/graphql/runner_details.fragment.graphql +++ b/app/assets/javascripts/runner/graphql/details/runner_details.fragment.graphql diff --git a/app/assets/javascripts/runner/graphql/runner_details_shared.fragment.graphql b/app/assets/javascripts/runner/graphql/details/runner_details_shared.fragment.graphql index 74760bbaa07..d8c67728fac 100644 --- a/app/assets/javascripts/runner/graphql/runner_details_shared.fragment.graphql +++ b/app/assets/javascripts/runner/graphql/details/runner_details_shared.fragment.graphql @@ -1,4 +1,5 @@ fragment RunnerDetailsShared on CiRunner { + __typename id runnerType active @@ -22,7 +23,7 @@ fragment RunnerDetailsShared on CiRunner { groups { # Only a single group can be loaded here, while projects # are loaded separately using the query with pagination - # parameters `get_runner_projects.query.graphql`. + # parameters `runner_projects.query.graphql`. nodes { id avatarUrl diff --git a/app/assets/javascripts/runner/graphql/get_runner_jobs.query.graphql b/app/assets/javascripts/runner/graphql/details/runner_jobs.query.graphql index 2b1decd3ddd..2b1decd3ddd 100644 --- a/app/assets/javascripts/runner/graphql/get_runner_jobs.query.graphql +++ b/app/assets/javascripts/runner/graphql/details/runner_jobs.query.graphql diff --git a/app/assets/javascripts/runner/graphql/get_runner_projects.query.graphql b/app/assets/javascripts/runner/graphql/details/runner_projects.query.graphql index f97237b8267..f97237b8267 100644 --- a/app/assets/javascripts/runner/graphql/get_runner_projects.query.graphql +++ b/app/assets/javascripts/runner/graphql/details/runner_projects.query.graphql diff --git a/app/assets/javascripts/runner/graphql/runner_update.mutation.graphql b/app/assets/javascripts/runner/graphql/details/runner_update.mutation.graphql index 8d1b75828be..e4bf51e2c30 100644 --- a/app/assets/javascripts/runner/graphql/runner_update.mutation.graphql +++ b/app/assets/javascripts/runner/graphql/details/runner_update.mutation.graphql @@ -1,4 +1,4 @@ -#import "ee_else_ce/runner/graphql/runner_details.fragment.graphql" +#import "ee_else_ce/runner/graphql/details/runner_details.fragment.graphql" # Mutation for updates from the runner form, loads # attributes shown in the runner details. diff --git a/app/assets/javascripts/runner/graphql/get_runners.query.graphql b/app/assets/javascripts/runner/graphql/list/admin_runners.query.graphql index ed03a8c34ae..8df4c2fc65c 100644 --- a/app/assets/javascripts/runner/graphql/get_runners.query.graphql +++ b/app/assets/javascripts/runner/graphql/list/admin_runners.query.graphql @@ -1,4 +1,4 @@ -#import "~/runner/graphql/runner_node.fragment.graphql" +#import "~/runner/graphql/list/list_item.fragment.graphql" #import "~/graphql_shared/fragments/pageInfo.fragment.graphql" query getRunners( @@ -24,7 +24,7 @@ query getRunners( sort: $sort ) { nodes { - ...RunnerNode + ...ListItem adminUrl editAdminUrl } diff --git a/app/assets/javascripts/runner/graphql/get_runners_count.query.graphql b/app/assets/javascripts/runner/graphql/list/admin_runners_count.query.graphql index 181a4495cae..181a4495cae 100644 --- a/app/assets/javascripts/runner/graphql/get_runners_count.query.graphql +++ b/app/assets/javascripts/runner/graphql/list/admin_runners_count.query.graphql diff --git a/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql b/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql index 986dd16b992..b517f5e89a8 100644 --- a/app/assets/javascripts/runner/graphql/get_group_runners.query.graphql +++ b/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql @@ -1,4 +1,4 @@ -#import "~/runner/graphql/runner_node.fragment.graphql" +#import "~/runner/graphql/list/list_item.fragment.graphql" #import "~/graphql_shared/fragments/pageInfo.fragment.graphql" query getGroupRunners( @@ -27,9 +27,9 @@ query getGroupRunners( ) { edges { webUrl + editUrl node { - __typename - ...RunnerNode + ...ListItem } } pageInfo { diff --git a/app/assets/javascripts/runner/graphql/get_group_runners_count.query.graphql b/app/assets/javascripts/runner/graphql/list/group_runners_count.query.graphql index 554eb09e372..554eb09e372 100644 --- a/app/assets/javascripts/runner/graphql/get_group_runners_count.query.graphql +++ b/app/assets/javascripts/runner/graphql/list/group_runners_count.query.graphql diff --git a/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql b/app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql index fbdef817f2f..620c18c5bc0 100644 --- a/app/assets/javascripts/runner/graphql/runner_node.fragment.graphql +++ b/app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql @@ -1,4 +1,4 @@ -fragment RunnerNode on CiRunner { +fragment ListItem on CiRunner { __typename id description diff --git a/app/assets/javascripts/runner/graphql/runners_registration_token_reset.mutation.graphql b/app/assets/javascripts/runner/graphql/list/runners_registration_token_reset.mutation.graphql index 9c2797732ad..9c2797732ad 100644 --- a/app/assets/javascripts/runner/graphql/runners_registration_token_reset.mutation.graphql +++ b/app/assets/javascripts/runner/graphql/list/runners_registration_token_reset.mutation.graphql diff --git a/app/assets/javascripts/runner/graphql/runner_delete.mutation.graphql b/app/assets/javascripts/runner/graphql/shared/runner_delete.mutation.graphql index d580ea2785e..d580ea2785e 100644 --- a/app/assets/javascripts/runner/graphql/runner_delete.mutation.graphql +++ b/app/assets/javascripts/runner/graphql/shared/runner_delete.mutation.graphql diff --git a/app/assets/javascripts/runner/graphql/runner_toggle_active.mutation.graphql b/app/assets/javascripts/runner/graphql/shared/runner_toggle_active.mutation.graphql index 9b15570dbc0..9b15570dbc0 100644 --- a/app/assets/javascripts/runner/graphql/runner_toggle_active.mutation.graphql +++ b/app/assets/javascripts/runner/graphql/shared/runner_toggle_active.mutation.graphql diff --git a/app/assets/javascripts/runner/group_runners/group_runners_app.vue b/app/assets/javascripts/runner/group_runners/group_runners_app.vue index c4ee0ad4dfb..35fd7fff6d3 100644 --- a/app/assets/javascripts/runner/group_runners/group_runners_app.vue +++ b/app/assets/javascripts/runner/group_runners/group_runners_app.vue @@ -12,19 +12,20 @@ import RunnerName from '../components/runner_name.vue'; import RunnerStats from '../components/stat/runner_stats.vue'; import RunnerPagination from '../components/runner_pagination.vue'; import RunnerTypeTabs from '../components/runner_type_tabs.vue'; +import RunnerActionsCell from '../components/cells/runner_actions_cell.vue'; import { statusTokenConfig } from '../components/search_tokens/status_token_config'; import { - I18N_FETCH_ERROR, GROUP_FILTERED_SEARCH_NAMESPACE, GROUP_TYPE, PROJECT_TYPE, STATUS_ONLINE, STATUS_OFFLINE, STATUS_STALE, + I18N_FETCH_ERROR, } from '../constants'; -import getGroupRunnersQuery from '../graphql/get_group_runners.query.graphql'; -import getGroupRunnersCountQuery from '../graphql/get_group_runners_count.query.graphql'; +import groupRunnersQuery from '../graphql/list/group_runners.query.graphql'; +import groupRunnersCountQuery from '../graphql/list/group_runners_count.query.graphql'; import { fromUrlQueryToSearch, fromSearchToUrl, @@ -33,7 +34,7 @@ import { import { captureException } from '../sentry_utils'; const runnersCountSmartQuery = { - query: getGroupRunnersCountQuery, + query: groupRunnersCountQuery, fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, update(data) { return data?.group?.runners?.count; @@ -55,6 +56,7 @@ export default { RunnerStats, RunnerPagination, RunnerTypeTabs, + RunnerActionsCell, }, props: { registrationToken: { @@ -74,15 +76,15 @@ export default { return { search: fromUrlQueryToSearch(), runners: { - webUrls: [], items: [], + urlsById: {}, pageInfo: {}, }, }; }, apollo: { runners: { - query: getGroupRunnersQuery, + query: groupRunnersQuery, // Runners can be updated by users directly in this list. // A "cache and network" policy prevents outdated filtered // results. @@ -91,12 +93,23 @@ export default { return this.variables; }, update(data) { - const { runners } = data?.group || {}; + const { edges = [], pageInfo = {} } = data?.group?.runners || {}; + + const items = []; + const urlsById = {}; + + edges.forEach(({ node, webUrl, editUrl }) => { + items.push(node); + urlsById[node.id] = { + web: webUrl, + edit: editUrl, + }; + }); return { - webUrls: runners?.edges.map(({ webUrl }) => webUrl) || [], - items: runners?.edges.map(({ node }) => node) || [], - pageInfo: runners?.pageInfo || {}, + items, + urlsById, + pageInfo, }; }, error(error) { @@ -190,6 +203,7 @@ export default { deep: true, handler() { // TODO Implement back button reponse using onpopstate + // See https://gitlab.com/gitlab-org/gitlab/-/issues/333804 updateHistory({ url: fromSearchToUrl(this.search), title: document.title, @@ -221,6 +235,16 @@ export default { } return null; }, + webUrl(runner) { + return this.runners.urlsById[runner.id]?.web; + }, + editUrl(runner) { + return this.runners.urlsById[runner.id]?.edit; + }, + onDeleted({ message }) { + this.$root.$toast?.show(message); + this.$apollo.queries.runners.refetch(); + }, reportToSentry(error) { captureException({ error, component: this.$options.name }); }, @@ -272,13 +296,20 @@ export default { </div> <template v-else> <runner-list :runners="runners.items" :loading="runnersLoading"> - <template #runner-name="{ runner, index }"> - <gl-link :href="runners.webUrls[index]"> + <template #runner-name="{ runner }"> + <gl-link :href="webUrl(runner)"> <runner-name :runner="runner" /> </gl-link> </template> + <template #runner-actions-cell="{ runner }"> + <runner-actions-cell :runner="runner" :edit-url="editUrl(runner)" @deleted="onDeleted" /> + </template> </runner-list> - <runner-pagination v-model="search.pagination" :page-info="runners.pageInfo" /> + <runner-pagination + v-model="search.pagination" + class="gl-mt-3" + :page-info="runners.pageInfo" + /> </template> </div> </template> |