diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-21 03:12:56 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-21 03:12:56 +0300 |
commit | 881c9469903d5520cd1d51b47f620856f30c253e (patch) | |
tree | 968c9ca3de8dd2620a8dbecb7530e27cf88cf9ee /app/assets/javascripts/runner | |
parent | 76365117183054e95bbb2f3a6392ac333628eacf (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/runner')
9 files changed, 320 insertions, 30 deletions
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 new file mode 100644 index 00000000000..a7ae0213661 --- /dev/null +++ b/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue @@ -0,0 +1,74 @@ +<script> +import { GlTooltipDirective } from '@gitlab/ui'; +import { createAlert } from '~/flash'; +import { TYPE_CI_RUNNER } from '~/graphql_shared/constants'; +import { convertToGraphQLId } from '~/graphql_shared/utils'; +import RunnerEditButton from '../components/runner_edit_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 { captureException } from '../sentry_utils'; + +export default { + name: 'AdminRunnerShowApp', + components: { + RunnerEditButton, + RunnerHeader, + RunnerDetails, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + runnerId: { + type: String, + required: true, + }, + }, + data() { + return { + runner: null, + }; + }, + apollo: { + runner: { + query: getRunnerQuery, + variables() { + return { + id: convertToGraphQLId(TYPE_CI_RUNNER, this.runnerId), + }; + }, + error(error) { + createAlert({ message: I18N_FETCH_ERROR }); + + this.reportToSentry(error); + }, + }, + }, + computed: { + canUpdate() { + return this.runner.userPermissions?.updateRunner; + }, + }, + errorCaptured(error) { + this.reportToSentry(error); + }, + methods: { + reportToSentry(error) { + captureException({ error, component: this.$options.name }); + }, + }, +}; +</script> +<template> + <div> + <runner-header v-if="runner" :runner="runner"> + <template #actions> + <runner-edit-button v-if="canUpdate && runner.editAdminUrl" :href="runner.editAdminUrl" /> + </template> + </runner-header> + + <runner-details :runner="runner" /> + </div> +</template> diff --git a/app/assets/javascripts/runner/admin_runner_show/index.js b/app/assets/javascripts/runner/admin_runner_show/index.js new file mode 100644 index 00000000000..a781898cf8d --- /dev/null +++ b/app/assets/javascripts/runner/admin_runner_show/index.js @@ -0,0 +1,32 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import AdminRunnerShowApp from './admin_runner_show_app.vue'; + +Vue.use(VueApollo); + +export const initAdminRunnerShow = (selector = '#js-admin-runner-show') => { + const el = document.querySelector(selector); + + if (!el) { + return null; + } + + const { runnerId } = el.dataset; + + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), + }); + + return new Vue({ + el, + apolloProvider, + render(h) { + return h(AdminRunnerShowApp, { + props: { + runnerId, + }, + }); + }, + }); +}; 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 0934508c87f..19f6598c62c 100644 --- a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue +++ b/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue @@ -6,9 +6,9 @@ import runnerDeleteMutation from '~/runner/graphql/runner_delete.mutation.graphq import runnerActionsUpdateMutation from '~/runner/graphql/runner_actions_update.mutation.graphql'; import { captureException } from '~/runner/sentry_utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import RunnerEditButton from '../runner_edit_button.vue'; import RunnerDeleteModal from '../runner_delete_modal.vue'; -const I18N_EDIT = __('Edit'); const I18N_PAUSE = __('Pause'); const I18N_RESUME = __('Resume'); const I18N_DELETE = s__('Runners|Delete runner'); @@ -19,6 +19,7 @@ export default { components: { GlButton, GlButtonGroup, + RunnerEditButton, RunnerDeleteModal, }, directives: { @@ -147,7 +148,6 @@ export default { captureException({ error, component: this.$options.name }); }, }, - I18N_EDIT, I18N_DELETE, }; </script> @@ -161,14 +161,7 @@ export default { See https://gitlab.com/gitlab-org/gitlab/-/issues/334802 --> - <gl-button - v-if="canUpdate && runner.editAdminUrl" - v-gl-tooltip.hover.viewport="$options.I18N_EDIT" - :href="runner.editAdminUrl" - :aria-label="$options.I18N_EDIT" - icon="pencil" - data-testid="edit-runner" - /> + <runner-edit-button v-if="canUpdate && runner.editAdminUrl" :href="runner.editAdminUrl" /> <gl-button v-if="canUpdate" v-gl-tooltip.hover.viewport="toggleActiveTitle" diff --git a/app/assets/javascripts/runner/components/runner_detail.vue b/app/assets/javascripts/runner/components/runner_detail.vue new file mode 100644 index 00000000000..b1234818b7e --- /dev/null +++ b/app/assets/javascripts/runner/components/runner_detail.vue @@ -0,0 +1,50 @@ +<script> +import { __ } from '~/locale'; + +/** + * Usage: + * + * With a `value` prop: + * + * <runner-detail label="Field Name" :value="value" /> + * + * Or a `value` slot: + * + * <runner-detail label="Field Name"> + * <template #value> + * <strong>{{ value }}</strong> + * </template> + * </runner-detail> + * + */ +export default { + props: { + label: { + type: String, + required: true, + }, + value: { + type: String, + default: null, + required: false, + }, + emptyValue: { + type: String, + default: __('None'), + required: false, + }, + }, +}; +</script> + +<template> + <div class="gl-display-flex gl-pb-4"> + <dt class="gl-mr-2">{{ label }}</dt> + <dd class="gl-mb-0"> + <template v-if="value || $slots.value"> + <slot name="value">{{ value }}</slot> + </template> + <span v-else class="gl-text-gray-500">{{ emptyValue }}</span> + </dd> + </div> +</template> diff --git a/app/assets/javascripts/runner/components/runner_details.vue b/app/assets/javascripts/runner/components/runner_details.vue new file mode 100644 index 00000000000..56d1109f0f5 --- /dev/null +++ b/app/assets/javascripts/runner/components/runner_details.vue @@ -0,0 +1,92 @@ +<script> +import { GlTabs, GlTab, GlIntersperse } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; +import { timeIntervalInWords } from '~/lib/utils/datetime_utility'; +import { ACCESS_LEVEL_REF_PROTECTED } from '../constants'; +import RunnerDetail from './runner_detail.vue'; +import RunnerTags from './runner_tags.vue'; + +export default { + components: { + GlTabs, + GlTab, + GlIntersperse, + RunnerDetail, + RunnerTags, + TimeAgo, + }, + props: { + runner: { + type: Object, + required: false, + default: null, + }, + }, + computed: { + maximumTimeout() { + const { maximumTimeout } = this.runner; + if (typeof maximumTimeout !== 'number') { + return null; + } + return timeIntervalInWords(maximumTimeout); + }, + configTextProtected() { + if (this.runner.accessLevel === ACCESS_LEVEL_REF_PROTECTED) { + return s__('Runners|Protected'); + } + return null; + }, + configTextUntagged() { + if (this.runner.runUntagged) { + return s__('Runners|Runs untagged jobs'); + } + return null; + }, + }, + ACCESS_LEVEL_REF_PROTECTED, +}; +</script> + +<template> + <gl-tabs> + <gl-tab> + <template #title>{{ s__('Runners|Details') }}</template> + + <div v-if="runner" class="gl-py-4"> + <dl> + <runner-detail :label="s__('Runners|Description')" :value="runner.description" /> + <runner-detail + :label="s__('Runners|Last contact')" + :empty-value="s__('Runners|Never contacted')" + > + <template #value> + <time-ago v-if="runner.contactedAt" :time="runner.contactedAt" /> + </template> + </runner-detail> + <runner-detail :label="s__('Runners|Version')" :value="runner.version" /> + <runner-detail :label="s__('Runners|IP Address')" :value="runner.ipAddress" /> + <runner-detail :label="s__('Runners|Configuration')"> + <template #value> + <gl-intersperse v-if="configTextProtected || configTextUntagged"> + <span v-if="configTextProtected">{{ configTextProtected }}</span> + <span v-if="configTextUntagged">{{ configTextUntagged }}</span> + </gl-intersperse> + </template> + </runner-detail> + <runner-detail :label="s__('Runners|Maximum job timeout')" :value="maximumTimeout" /> + <runner-detail :label="s__('Runners|Tags')"> + <template #value> + <runner-tags + v-if="runner.tagList && runner.tagList.length" + class="gl-vertical-align-middle" + :tag-list="runner.tagList" + size="sm" + /> + </template> + </runner-detail> + </dl> + </div> + </gl-tab> + </gl-tabs> +</template> diff --git a/app/assets/javascripts/runner/components/runner_edit_button.vue b/app/assets/javascripts/runner/components/runner_edit_button.vue new file mode 100644 index 00000000000..b115be09e69 --- /dev/null +++ b/app/assets/javascripts/runner/components/runner_edit_button.vue @@ -0,0 +1,26 @@ +<script> +import { GlButton, GlTooltipDirective } from '@gitlab/ui'; +import { __ } from '~/locale'; + +const I18N_EDIT = __('Edit'); + +export default { + components: { + GlButton, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + I18N_EDIT, +}; +</script> + +<template> + <gl-button + v-gl-tooltip="$options.I18N_EDIT" + v-bind="$attrs" + :aria-label="$options.I18N_EDIT" + icon="pencil" + v-on="$listeners" + /> +</template> diff --git a/app/assets/javascripts/runner/components/runner_header.vue b/app/assets/javascripts/runner/components/runner_header.vue index 09f58df7bd0..295162e954a 100644 --- a/app/assets/javascripts/runner/components/runner_header.vue +++ b/app/assets/javascripts/runner/components/runner_header.vue @@ -1,19 +1,23 @@ <script> -import { GlSprintf } from '@gitlab/ui'; +import { GlIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui'; import { sprintf } from '~/locale'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { I18N_DETAILS_TITLE } from '../constants'; +import { I18N_DETAILS_TITLE, I18N_LOCKED_RUNNER_DESCRIPTION } from '../constants'; import RunnerTypeBadge from './runner_type_badge.vue'; import RunnerStatusBadge from './runner_status_badge.vue'; export default { components: { + GlIcon, GlSprintf, TimeAgo, RunnerTypeBadge, RunnerStatusBadge, }, + directives: { + GlTooltip: GlTooltipDirective, + }, props: { runner: { type: Object, @@ -29,24 +33,36 @@ export default { return sprintf(I18N_DETAILS_TITLE, { runner_id: id }); }, }, + I18N_LOCKED_RUNNER_DESCRIPTION, }; </script> <template> - <div class="gl-py-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"> - <runner-status-badge :runner="runner" /> - <runner-type-badge v-if="runner" :type="runner.runnerType" /> - <template v-if="runner.createdAt"> - <gl-sprintf :message="__('%{runner} created %{timeago}')"> - <template #runner> - <strong>{{ heading }}</strong> - </template> - <template #timeago> - <time-ago :time="runner.createdAt" /> - </template> - </gl-sprintf> - </template> - <template v-else> - <strong>{{ heading }}</strong> - </template> + <div + class="gl-display-flex gl-align-items-center gl-py-5 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100" + > + <div> + <runner-status-badge :runner="runner" /> + <runner-type-badge v-if="runner" :type="runner.runnerType" /> + <template v-if="runner.createdAt"> + <gl-sprintf :message="__('%{runner} created %{timeago}')"> + <template #runner> + <strong>{{ heading }}</strong> + <gl-icon + v-if="runner.locked" + v-gl-tooltip="$options.I18N_LOCKED_RUNNER_DESCRIPTION" + name="lock" + :aria-label="$options.I18N_LOCKED_RUNNER_DESCRIPTION" + /> + </template> + <template #timeago> + <time-ago :time="runner.createdAt" /> + </template> + </gl-sprintf> + </template> + <template v-else> + <strong>{{ heading }}</strong> + </template> + </div> + <div class="gl-ml-auto"><slot name="actions"></slot></div> </div> </template> diff --git a/app/assets/javascripts/runner/components/runner_tags.vue b/app/assets/javascripts/runner/components/runner_tags.vue index 8da5e33076f..797d2a35b2c 100644 --- a/app/assets/javascripts/runner/components/runner_tags.vue +++ b/app/assets/javascripts/runner/components/runner_tags.vue @@ -20,7 +20,7 @@ export default { }; </script> <template> - <div> + <span> <runner-tag v-for="tag in tagList" :key="tag" @@ -28,5 +28,5 @@ export default { :tag="tag" :size="size" /> - </div> + </span> </template> diff --git a/app/assets/javascripts/runner/graphql/runner_details_shared.fragment.graphql b/app/assets/javascripts/runner/graphql/runner_details_shared.fragment.graphql index 8e968343b9b..60771af51f4 100644 --- a/app/assets/javascripts/runner/graphql/runner_details_shared.fragment.graphql +++ b/app/assets/javascripts/runner/graphql/runner_details_shared.fragment.graphql @@ -11,4 +11,11 @@ fragment RunnerDetailsShared on CiRunner { tagList createdAt status(legacyMode: null) + contactedAt + version + editAdminUrl + userPermissions { + updateRunner + deleteRunner + } } |