Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/runner/components/registration')
-rw-r--r--app/assets/javascripts/runner/components/registration/registration_dropdown.vue112
-rw-r--r--app/assets/javascripts/runner/components/registration/registration_token.vue83
-rw-r--r--app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue113
3 files changed, 308 insertions, 0 deletions
diff --git a/app/assets/javascripts/runner/components/registration/registration_dropdown.vue b/app/assets/javascripts/runner/components/registration/registration_dropdown.vue
new file mode 100644
index 00000000000..3fbe3c1be74
--- /dev/null
+++ b/app/assets/javascripts/runner/components/registration/registration_dropdown.vue
@@ -0,0 +1,112 @@
+<script>
+import {
+ GlFormGroup,
+ GlDropdown,
+ GlDropdownForm,
+ GlDropdownItem,
+ GlDropdownDivider,
+} from '@gitlab/ui';
+import { s__ } from '~/locale';
+import RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
+import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants';
+import RegistrationToken from './registration_token.vue';
+import RegistrationTokenResetDropdownItem from './registration_token_reset_dropdown_item.vue';
+
+export default {
+ i18n: {
+ showInstallationInstructions: s__(
+ 'Runners|Show runner installation and registration instructions',
+ ),
+ registrationToken: s__('Runners|Registration token'),
+ },
+ components: {
+ GlFormGroup,
+ GlDropdown,
+ GlDropdownForm,
+ GlDropdownItem,
+ GlDropdownDivider,
+ RegistrationToken,
+ RunnerInstructionsModal,
+ RegistrationTokenResetDropdownItem,
+ },
+ props: {
+ registrationToken: {
+ type: String,
+ required: true,
+ },
+ type: {
+ type: String,
+ required: true,
+ validator(type) {
+ return [INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE].includes(type);
+ },
+ },
+ },
+ data() {
+ return {
+ currentRegistrationToken: this.registrationToken,
+ instructionsModalOpened: false,
+ };
+ },
+ computed: {
+ dropdownText() {
+ switch (this.type) {
+ case INSTANCE_TYPE:
+ return s__('Runners|Register an instance runner');
+ case GROUP_TYPE:
+ return s__('Runners|Register a group runner');
+ case PROJECT_TYPE:
+ return s__('Runners|Register a project runner');
+ default:
+ return s__('Runners|Register a runner');
+ }
+ },
+ },
+ methods: {
+ onShowInstructionsClick() {
+ // Rendering the modal on demand, to avoid
+ // loading instructions prematurely from API.
+ this.instructionsModalOpened = true;
+
+ this.$nextTick(() => {
+ // $refs.runnerInstructionsModal is defined in
+ // the tick after the modal is rendered
+ this.$refs.runnerInstructionsModal.show();
+ });
+ },
+ onTokenReset(token) {
+ this.currentRegistrationToken = token;
+
+ this.$refs.runnerRegistrationDropdown.hide(true);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ ref="runnerRegistrationDropdown"
+ menu-class="gl-w-auto!"
+ :text="dropdownText"
+ variant="confirm"
+ v-bind="$attrs"
+ >
+ <gl-dropdown-item @click.capture.native.stop="onShowInstructionsClick">
+ {{ $options.i18n.showInstallationInstructions }}
+ <runner-instructions-modal
+ v-if="instructionsModalOpened"
+ ref="runnerInstructionsModal"
+ :registration-token="registrationToken"
+ data-testid="runner-instructions-modal"
+ />
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
+ <gl-dropdown-form class="gl-p-4!">
+ <gl-form-group class="gl-mb-0" :label="$options.i18n.registrationToken">
+ <registration-token :value="currentRegistrationToken" />
+ </gl-form-group>
+ </gl-dropdown-form>
+ <gl-dropdown-divider />
+ <registration-token-reset-dropdown-item :type="type" @tokenReset="onTokenReset" />
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/runner/components/registration/registration_token.vue b/app/assets/javascripts/runner/components/registration/registration_token.vue
new file mode 100644
index 00000000000..d54a66ff0e4
--- /dev/null
+++ b/app/assets/javascripts/runner/components/registration/registration_token.vue
@@ -0,0 +1,83 @@
+<script>
+import { GlButtonGroup, GlButton, GlTooltipDirective } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
+
+export default {
+ components: {
+ GlButtonGroup,
+ GlButton,
+ ModalCopyButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ value: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ isMasked: true,
+ };
+ },
+ computed: {
+ maskLabel() {
+ if (this.isMasked) {
+ return __('Click to reveal');
+ }
+ return __('Click to hide');
+ },
+ maskIcon() {
+ if (this.isMasked) {
+ return 'eye';
+ }
+ return 'eye-slash';
+ },
+ displayedValue() {
+ if (this.isMasked && this.value?.length) {
+ return '*'.repeat(this.value.length);
+ }
+ return this.value;
+ },
+ },
+ methods: {
+ onToggleMasked() {
+ this.isMasked = !this.isMasked;
+ },
+ onCopied() {
+ // value already in the clipboard, simply notify the user
+ this.$toast?.show(s__('Runners|Registration token copied!'));
+ },
+ },
+ i18n: {
+ copyLabel: s__('Runners|Copy registration token'),
+ },
+};
+</script>
+<template>
+ <gl-button-group>
+ <gl-button class="gl-font-monospace" data-testid="token-value" label>
+ {{ displayedValue }}
+ </gl-button>
+ <gl-button
+ v-gl-tooltip
+ :aria-label="maskLabel"
+ :title="maskLabel"
+ :icon="maskIcon"
+ class="gl-w-auto! gl-flex-shrink-0!"
+ data-testid="toggle-masked"
+ @click.stop="onToggleMasked"
+ />
+ <modal-copy-button
+ class="gl-w-auto! gl-flex-shrink-0!"
+ :aria-label="$options.i18n.copyLabel"
+ :title="$options.i18n.copyLabel"
+ :text="value"
+ @success="onCopied"
+ />
+ </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
new file mode 100644
index 00000000000..3bb15bff8d8
--- /dev/null
+++ b/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue
@@ -0,0 +1,113 @@
+<script>
+import { GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import createFlash 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 { captureException } from '~/runner/sentry_utils';
+import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants';
+
+export default {
+ name: 'RunnerRegistrationTokenReset',
+ components: {
+ GlDropdownItem,
+ GlLoadingIcon,
+ },
+ inject: {
+ groupId: {
+ default: null,
+ },
+ projectId: {
+ default: null,
+ },
+ },
+ props: {
+ type: {
+ type: String,
+ required: true,
+ validator(type) {
+ return [INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE].includes(type);
+ },
+ },
+ },
+ data() {
+ return {
+ loading: false,
+ };
+ },
+ computed: {
+ resetTokenInput() {
+ switch (this.type) {
+ case INSTANCE_TYPE:
+ return {
+ type: this.type,
+ };
+ case GROUP_TYPE:
+ return {
+ id: convertToGraphQLId(TYPE_GROUP, this.groupId),
+ type: this.type,
+ };
+ case PROJECT_TYPE:
+ return {
+ id: convertToGraphQLId(TYPE_PROJECT, this.projectId),
+ type: this.type,
+ };
+ default:
+ return null;
+ }
+ },
+ },
+ methods: {
+ async resetToken() {
+ // TODO Replace confirmation with gl-modal
+ // See: https://gitlab.com/gitlab-org/gitlab/-/issues/333810
+ // eslint-disable-next-line no-alert
+ if (!window.confirm(__('Are you sure you want to reset the registration token?'))) {
+ return;
+ }
+
+ this.loading = true;
+ try {
+ const {
+ data: {
+ runnersRegistrationTokenReset: { token, errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: runnersRegistrationTokenResetMutation,
+ variables: {
+ input: this.resetTokenInput,
+ },
+ });
+ if (errors && errors.length) {
+ throw new Error(errors.join(' '));
+ }
+ this.onSuccess(token);
+ } catch (e) {
+ this.onError(e);
+ } finally {
+ this.loading = false;
+ }
+ },
+ onError(error) {
+ const { message } = error;
+ createFlash({ message });
+
+ this.reportToSentry(error);
+ },
+ onSuccess(token) {
+ this.$toast?.show(s__('Runners|New registration token generated!'));
+ this.$emit('tokenReset', token);
+ },
+ reportToSentry(error) {
+ captureException({ error, component: this.$options.name });
+ },
+ },
+};
+</script>
+<template>
+ <gl-dropdown-item @click.capture.native.stop="resetToken">
+ {{ __('Reset registration token') }}
+ <gl-loading-icon v-if="loading" inline />
+ </gl-dropdown-item>
+</template>