summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/ci/runner/components/registration
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/ci/runner/components/registration')
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_dropdown.vue92
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_token.vue49
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue141
3 files changed, 282 insertions, 0 deletions
diff --git a/app/assets/javascripts/ci/runner/components/registration/registration_dropdown.vue b/app/assets/javascripts/ci/runner/components/registration/registration_dropdown.vue
new file mode 100644
index 00000000000..212ad5fa5a0
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_dropdown.vue
@@ -0,0 +1,92 @@
+<script>
+import { 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',
+ ),
+ },
+ components: {
+ 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,
+ };
+ },
+ 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() {
+ 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
+ ref="runnerInstructionsModal"
+ :registration-token="currentRegistrationToken"
+ data-testid="runner-instructions-modal"
+ />
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
+ <gl-dropdown-form class="gl-p-4!">
+ <registration-token input-id="token-value" :value="currentRegistrationToken" />
+ </gl-dropdown-form>
+ <gl-dropdown-divider />
+ <registration-token-reset-dropdown-item :type="type" @tokenReset="onTokenReset" />
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/registration/registration_token.vue b/app/assets/javascripts/ci/runner/components/registration/registration_token.vue
new file mode 100644
index 00000000000..6b4e6a929b7
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_token.vue
@@ -0,0 +1,49 @@
+<script>
+import { s__ } from '~/locale';
+import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
+
+export default {
+ components: {
+ InputCopyToggleVisibility,
+ },
+ i18n: {
+ registrationToken: s__('Runners|Registration token'),
+ },
+ props: {
+ inputId: {
+ type: String,
+ required: true,
+ },
+ value: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ formInputGroupProps() {
+ return {
+ id: this.inputId,
+ };
+ },
+ },
+ methods: {
+ onCopy() {
+ // value already in the clipboard, simply notify the user
+ this.$toast?.show(s__('Runners|Registration token copied!'));
+ },
+ },
+ I18N_COPY_BUTTON_TITLE: s__('Runners|Copy registration token'),
+};
+</script>
+<template>
+ <input-copy-toggle-visibility
+ class="gl-m-0"
+ :value="value"
+ :label="$options.i18n.registrationToken"
+ :label-for="inputId"
+ :copy-button-title="$options.I18N_COPY_BUTTON_TITLE"
+ :form-input-group-props="formInputGroupProps"
+ @copy="onCopy"
+ />
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue b/app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue
new file mode 100644
index 00000000000..6740065e860
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue
@@ -0,0 +1,141 @@
+<script>
+import { GlDropdownItem, GlLoadingIcon, GlModal, GlModalDirective } from '@gitlab/ui';
+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 '~/ci/runner/graphql/list/runners_registration_token_reset.mutation.graphql';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants';
+
+const i18n = {
+ modalAction: s__('Runners|Reset token'),
+ modalCancel: __('Cancel'),
+ modalCopy: __('Are you sure you want to reset the registration token?'),
+ modalTitle: __('Reset registration token'),
+};
+
+export default {
+ name: 'RunnerRegistrationTokenReset',
+ i18n,
+ components: {
+ GlDropdownItem,
+ GlLoadingIcon,
+ GlModal,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ inject: {
+ groupId: {
+ default: null,
+ },
+ projectId: {
+ default: null,
+ },
+ },
+ modalId: 'token-reset-modal',
+ 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;
+ }
+ },
+ actionPrimary() {
+ return {
+ text: i18n.modalAction,
+ attributes: [{ variant: 'danger' }],
+ };
+ },
+ actionSecondary() {
+ return {
+ text: i18n.modalCancel,
+ attributes: [{ variant: 'default' }],
+ };
+ },
+ },
+ methods: {
+ handleModalPrimary() {
+ this.resetToken();
+ },
+ async resetToken() {
+ 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;
+
+ createAlert({ message });
+ captureException({ error, component: this.$options.name });
+ },
+ onSuccess(token) {
+ this.$toast?.show(s__('Runners|New registration token generated!'));
+ this.$emit('tokenReset', token);
+ },
+ },
+};
+</script>
+<template>
+ <gl-dropdown-item v-gl-modal="$options.modalId">
+ {{ __('Reset registration token') }}
+ <gl-modal
+ size="sm"
+ :modal-id="$options.modalId"
+ :action-primary="actionPrimary"
+ :action-secondary="actionSecondary"
+ :title="$options.i18n.modalTitle"
+ @primary="handleModalPrimary"
+ >
+ <p>{{ $options.i18n.modalCopy }}</p>
+ </gl-modal>
+ <gl-loading-icon v-if="loading" inline />
+ </gl-dropdown-item>
+</template>