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/pages/admin')
-rw-r--r--app/assets/javascripts/pages/admin/abuse_reports/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/admin.js13
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue50
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue417
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/general/index.js26
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/gitpod.js24
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/index.js4
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/signup_restrictions.js31
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/utils.js21
-rw-r--r--app/assets/javascripts/pages/admin/broadcast_messages/index.js6
-rw-r--r--app/assets/javascripts/pages/admin/groups/new/index.js4
-rw-r--r--app/assets/javascripts/pages/admin/labels/edit/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/labels/index/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/labels/new/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/runners/index/index.js (renamed from app/assets/javascripts/pages/admin/runners/index.js)0
-rw-r--r--app/assets/javascripts/pages/admin/runners/show/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/services/edit/index.js6
-rw-r--r--app/assets/javascripts/pages/admin/spam_logs/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue4
-rw-r--r--app/assets/javascripts/pages/admin/users/new/index.js52
20 files changed, 575 insertions, 99 deletions
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/index.js b/app/assets/javascripts/pages/admin/abuse_reports/index.js
index 0a4311ec73a..a88d35796f7 100644
--- a/app/assets/javascripts/pages/admin/abuse_reports/index.js
+++ b/app/assets/javascripts/pages/admin/abuse_reports/index.js
@@ -1,5 +1,8 @@
+import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
import UsersSelect from '~/users_select';
import AbuseReports from './abuse_reports';
new AbuseReports(); /* eslint-disable-line no-new */
new UsersSelect(); /* eslint-disable-line no-new */
+
+document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);
diff --git a/app/assets/javascripts/pages/admin/admin.js b/app/assets/javascripts/pages/admin/admin.js
index 2732fc191be..6b7bfbf217d 100644
--- a/app/assets/javascripts/pages/admin/admin.js
+++ b/app/assets/javascripts/pages/admin/admin.js
@@ -1,16 +1,6 @@
import $ from 'jquery';
import { refreshCurrentPage } from '../../lib/utils/url_utility';
-function showDenylistType() {
- if ($('input[name="denylist_type"]:checked').val() === 'file') {
- $('.js-denylist-file').show();
- $('.js-denylist-raw').hide();
- } else {
- $('.js-denylist-file').hide();
- $('.js-denylist-raw').show();
- }
-}
-
export default function adminInit() {
$('input#user_force_random_password').on('change', function randomPasswordClick() {
const $elems = $('#user_password, #user_password_confirmation');
@@ -27,7 +17,4 @@ export default function adminInit() {
});
$('li.project_member, li.group_member').on('ajax:success', refreshCurrentPage);
-
- $("input[name='denylist_type']").on('click', showDenylistType);
- showDenylistType();
}
diff --git a/app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue
new file mode 100644
index 00000000000..2217792d7f3
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_checkbox.vue
@@ -0,0 +1,50 @@
+<script>
+import { GlFormCheckbox } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlFormCheckbox,
+ },
+ props: {
+ name: {
+ type: String,
+ required: true,
+ },
+ helpText: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ label: {
+ type: String,
+ required: true,
+ },
+ value: {
+ type: Boolean,
+ required: true,
+ },
+ dataQaSelector: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <input :name="name" type="hidden" :value="value ? '1' : '0'" data-testid="input" />
+
+ <gl-form-checkbox
+ :checked="value"
+ :data-qa-selector="dataQaSelector"
+ @input="$emit('input', $event)"
+ >
+ <span data-testid="label">{{ label }}</span>
+ <template v-if="helpText" #help>
+ <span data-testid="helpText">{{ helpText }}</span>
+ </template>
+ </gl-form-checkbox>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue
new file mode 100644
index 00000000000..9850113d4be
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue
@@ -0,0 +1,417 @@
+<script>
+import {
+ GlButton,
+ GlFormGroup,
+ GlFormInput,
+ GlFormRadio,
+ GlFormRadioGroup,
+ GlSprintf,
+ GlLink,
+ GlModal,
+} from '@gitlab/ui';
+import { toSafeInteger } from 'lodash';
+import csrf from '~/lib/utils/csrf';
+import { __, s__, sprintf } from '~/locale';
+import SignupCheckbox from './signup_checkbox.vue';
+
+const DENYLIST_TYPE_RAW = 'raw';
+const DENYLIST_TYPE_FILE = 'file';
+
+export default {
+ csrf,
+ DENYLIST_TYPE_RAW,
+ DENYLIST_TYPE_FILE,
+ components: {
+ GlButton,
+ GlFormGroup,
+ GlFormInput,
+ GlFormRadio,
+ GlFormRadioGroup,
+ GlSprintf,
+ GlLink,
+ SignupCheckbox,
+ GlModal,
+ },
+ inject: [
+ 'host',
+ 'settingsPath',
+ 'signupEnabled',
+ 'requireAdminApprovalAfterUserSignup',
+ 'sendUserConfirmationEmail',
+ 'minimumPasswordLength',
+ 'minimumPasswordLengthMin',
+ 'minimumPasswordLengthMax',
+ 'minimumPasswordLengthHelpLink',
+ 'domainAllowlistRaw',
+ 'newUserSignupsCap',
+ 'domainDenylistEnabled',
+ 'denylistTypeRawSelected',
+ 'domainDenylistRaw',
+ 'emailRestrictionsEnabled',
+ 'supportedSyntaxLinkUrl',
+ 'emailRestrictions',
+ 'afterSignUpText',
+ ],
+ data() {
+ return {
+ showModal: false,
+ form: {
+ signupEnabled: this.signupEnabled,
+ requireAdminApproval: this.requireAdminApprovalAfterUserSignup,
+ sendConfirmationEmail: this.sendUserConfirmationEmail,
+ minimumPasswordLength: this.minimumPasswordLength,
+ minimumPasswordLengthMin: this.minimumPasswordLengthMin,
+ minimumPasswordLengthMax: this.minimumPasswordLengthMax,
+ minimumPasswordLengthHelpLink: this.minimumPasswordLengthHelpLink,
+ domainAllowlistRaw: this.domainAllowlistRaw,
+ userCap: this.newUserSignupsCap,
+ domainDenylistEnabled: this.domainDenylistEnabled,
+ denylistType: this.denylistTypeRawSelected
+ ? this.$options.DENYLIST_TYPE_RAW
+ : this.$options.DENYLIST_TYPE_FILE,
+ domainDenylistRaw: this.domainDenylistRaw,
+ emailRestrictionsEnabled: this.emailRestrictionsEnabled,
+ supportedSyntaxLinkUrl: this.supportedSyntaxLinkUrl,
+ emailRestrictions: this.emailRestrictions,
+ afterSignUpText: this.afterSignUpText,
+ },
+ };
+ },
+ computed: {
+ isOldUserCapUnlimited() {
+ // User cap is set to unlimited if no value is provided in the field
+ return this.newUserSignupsCap === '';
+ },
+ isNewUserCapUnlimited() {
+ // User cap is set to unlimited if no value is provided in the field
+ return this.form.userCap === '';
+ },
+ hasUserCapChangedFromUnlimitedToLimited() {
+ return this.isOldUserCapUnlimited && !this.isNewUserCapUnlimited;
+ },
+ hasUserCapChangedFromLimitedToUnlimited() {
+ return !this.isOldUserCapUnlimited && this.isNewUserCapUnlimited;
+ },
+ hasUserCapBeenIncreased() {
+ if (this.hasUserCapChangedFromUnlimitedToLimited) {
+ return false;
+ }
+
+ const oldValueAsInteger = toSafeInteger(this.newUserSignupsCap);
+ const newValueAsInteger = toSafeInteger(this.form.userCap);
+
+ return this.hasUserCapChangedFromLimitedToUnlimited || newValueAsInteger > oldValueAsInteger;
+ },
+ canUsersBeAccidentallyApproved() {
+ const hasUserCapBeenToggledOff =
+ this.requireAdminApprovalAfterUserSignup && !this.form.requireAdminApproval;
+
+ return this.hasUserCapBeenIncreased || hasUserCapBeenToggledOff;
+ },
+ signupEnabledHelpText() {
+ const text = sprintf(
+ s__(
+ 'ApplicationSettings|When enabled, any user visiting %{host} will be able to create an account.',
+ ),
+ {
+ host: this.host,
+ },
+ );
+
+ return text;
+ },
+ requireAdminApprovalHelpText() {
+ const text = sprintf(
+ s__(
+ 'ApplicationSettings|When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by an admin before they can sign in. This setting is effective only if sign-ups are enabled.',
+ ),
+ {
+ host: this.host,
+ },
+ );
+
+ return text;
+ },
+ },
+ watch: {
+ showModal(value) {
+ if (value === true) {
+ this.$refs[this.$options.modal.id].show();
+ } else {
+ this.$refs[this.$options.modal.id].hide();
+ }
+ },
+ },
+ methods: {
+ submitButtonHandler() {
+ if (this.canUsersBeAccidentallyApproved) {
+ this.showModal = true;
+
+ return;
+ }
+
+ this.submitForm();
+ },
+ submitForm() {
+ this.$refs.form.submit();
+ },
+ modalHideHandler() {
+ this.showModal = false;
+ },
+ },
+ i18n: {
+ buttonText: s__('ApplicationSettings|Save changes'),
+ signupEnabledLabel: s__('ApplicationSettings|Sign-up enabled'),
+ requireAdminApprovalLabel: s__('ApplicationSettings|Require admin approval for new sign-ups'),
+ sendConfirmationEmailLabel: s__('ApplicationSettings|Send confirmation email on sign-up'),
+ minimumPasswordLengthLabel: s__(
+ 'ApplicationSettings|Minimum password length (number of characters)',
+ ),
+ domainAllowListLabel: s__('ApplicationSettings|Allowed domains for sign-ups'),
+ domainAllowListDescription: s__(
+ 'ApplicationSettings|ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com',
+ ),
+ userCapLabel: s__('ApplicationSettings|User cap'),
+ userCapDescription: s__(
+ 'ApplicationSettings|Once the instance reaches the user cap, any user who is added or requests access will have to be approved by an admin. Leave the field empty for unlimited.',
+ ),
+ domainDenyListGroupLabel: s__('ApplicationSettings|Domain denylist'),
+ domainDenyListLabel: s__('ApplicationSettings|Enable domain denylist for sign ups'),
+ domainDenyListTypeFileLabel: s__('ApplicationSettings|Upload denylist file'),
+ domainDenyListTypeRawLabel: s__('ApplicationSettings|Enter denylist manually'),
+ domainDenyListFileLabel: s__('ApplicationSettings|Denylist file'),
+ domainDenyListFileDescription: s__(
+ 'ApplicationSettings|Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines or commas for multiple entries.',
+ ),
+ domainDenyListListLabel: s__('ApplicationSettings|Denied domains for sign-ups'),
+ domainDenyListListDescription: s__(
+ 'ApplicationSettings|Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com',
+ ),
+ domainPlaceholder: s__('ApplicationSettings|domain.com'),
+ emailRestrictionsEnabledGroupLabel: s__('ApplicationSettings|Email restrictions'),
+ emailRestrictionsEnabledLabel: s__(
+ 'ApplicationSettings|Enable email restrictions for sign ups',
+ ),
+ emailRestrictionsGroupLabel: s__('ApplicationSettings|Email restrictions for sign-ups'),
+ afterSignUpTextGroupLabel: s__('ApplicationSettings|After sign up text'),
+ afterSignUpTextGroupDescription: s__('ApplicationSettings|Markdown enabled'),
+ },
+ modal: {
+ id: 'signup-settings-modal',
+ actionPrimary: {
+ text: s__('ApplicationSettings|Approve users'),
+ attributes: {
+ variant: 'confirm',
+ },
+ },
+ actionCancel: {
+ text: __('Cancel'),
+ },
+ title: s__('ApplicationSettings|Approve all users in the pending approval status?'),
+ text: s__(
+ 'ApplicationSettings|By making this change, you will automatically approve all users in pending approval status.',
+ ),
+ },
+};
+</script>
+
+<template>
+ <form
+ ref="form"
+ accept-charset="UTF-8"
+ data-testid="form"
+ method="post"
+ :action="settingsPath"
+ enctype="multipart/form-data"
+ >
+ <input type="hidden" name="utf8" value="✓" />
+ <input type="hidden" name="_method" value="patch" />
+ <input type="hidden" name="authenticity_token" :value="$options.csrf.token" />
+
+ <section class="gl-mb-8">
+ <signup-checkbox
+ v-model="form.signupEnabled"
+ class="gl-mb-5"
+ name="application_setting[signup_enabled]"
+ :help-text="signupEnabledHelpText"
+ :label="$options.i18n.signupEnabledLabel"
+ data-qa-selector="signup_enabled_checkbox"
+ />
+
+ <signup-checkbox
+ v-model="form.requireAdminApproval"
+ class="gl-mb-5"
+ name="application_setting[require_admin_approval_after_user_signup]"
+ :help-text="requireAdminApprovalHelpText"
+ :label="$options.i18n.requireAdminApprovalLabel"
+ data-qa-selector="require_admin_approval_after_user_signup_checkbox"
+ data-testid="require-admin-approval-checkbox"
+ />
+
+ <signup-checkbox
+ v-model="form.sendConfirmationEmail"
+ class="gl-mb-5"
+ name="application_setting[send_user_confirmation_email]"
+ :label="$options.i18n.sendConfirmationEmailLabel"
+ />
+
+ <gl-form-group
+ :label="$options.i18n.userCapLabel"
+ :description="$options.i18n.userCapDescription"
+ >
+ <gl-form-input
+ v-model="form.userCap"
+ type="text"
+ name="application_setting[new_user_signups_cap]"
+ data-testid="user-cap-input"
+ />
+ </gl-form-group>
+
+ <gl-form-group :label="$options.i18n.minimumPasswordLengthLabel">
+ <gl-form-input
+ v-model="form.minimumPasswordLength"
+ :min="form.minimumPasswordLengthMin"
+ :max="form.minimumPasswordLengthMax"
+ type="number"
+ name="application_setting[minimum_password_length]"
+ />
+
+ <gl-sprintf
+ :message="
+ s__(
+ 'ApplicationSettings|See GitLab\'s %{linkStart}Password Policy Guidelines%{linkEnd}',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="form.minimumPasswordLengthHelpLink" target="_blank">{{
+ content
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-form-group>
+
+ <gl-form-group
+ :description="$options.i18n.domainAllowListDescription"
+ :label="$options.i18n.domainAllowListLabel"
+ >
+ <textarea
+ v-model="form.domainAllowlistRaw"
+ :placeholder="$options.i18n.domainPlaceholder"
+ rows="8"
+ class="form-control gl-form-input"
+ name="application_setting[domain_allowlist_raw]"
+ ></textarea>
+ </gl-form-group>
+
+ <gl-form-group :label="$options.i18n.domainDenyListGroupLabel">
+ <signup-checkbox
+ v-model="form.domainDenylistEnabled"
+ name="application_setting[domain_denylist_enabled]"
+ :label="$options.i18n.domainDenyListLabel"
+ />
+ </gl-form-group>
+
+ <gl-form-radio-group v-model="form.denylistType" name="denylist_type" class="gl-mb-5">
+ <gl-form-radio :value="$options.DENYLIST_TYPE_FILE">{{
+ $options.i18n.domainDenyListTypeFileLabel
+ }}</gl-form-radio>
+ <gl-form-radio :value="$options.DENYLIST_TYPE_RAW">{{
+ $options.i18n.domainDenyListTypeRawLabel
+ }}</gl-form-radio>
+ </gl-form-radio-group>
+
+ <gl-form-group
+ v-if="form.denylistType === $options.DENYLIST_TYPE_FILE"
+ :description="$options.i18n.domainDenyListFileDescription"
+ :label="$options.i18n.domainDenyListFileLabel"
+ label-for="domain-denylist-file-input"
+ data-testid="domain-denylist-file-input-group"
+ >
+ <input
+ id="domain-denylist-file-input"
+ class="form-control gl-form-input"
+ type="file"
+ accept=".txt,.conf"
+ name="application_setting[domain_denylist_file]"
+ />
+ </gl-form-group>
+
+ <gl-form-group
+ v-if="form.denylistType !== $options.DENYLIST_TYPE_FILE"
+ :description="$options.i18n.domainDenyListListDescription"
+ :label="$options.i18n.domainDenyListListLabel"
+ data-testid="domain-denylist-raw-input-group"
+ >
+ <textarea
+ v-model="form.domainDenylistRaw"
+ :placeholder="$options.i18n.domainPlaceholder"
+ rows="8"
+ class="form-control gl-form-input"
+ name="application_setting[domain_denylist_raw]"
+ ></textarea>
+ </gl-form-group>
+
+ <gl-form-group :label="$options.i18n.emailRestrictionsEnabledGroupLabel">
+ <signup-checkbox
+ v-model="form.emailRestrictionsEnabled"
+ name="application_setting[email_restrictions_enabled]"
+ :label="$options.i18n.emailRestrictionsEnabledLabel"
+ />
+ </gl-form-group>
+
+ <gl-form-group :label="$options.i18n.emailRestrictionsGroupLabel">
+ <textarea
+ v-model="form.emailRestrictions"
+ rows="4"
+ class="form-control gl-form-input"
+ name="application_setting[email_restrictions]"
+ ></textarea>
+
+ <gl-sprintf
+ :message="
+ s__(
+ 'ApplicationSettings|Restricts sign-ups for email addresses that match the given regex. See the %{linkStart}supported syntax%{linkEnd} for more information.',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="form.supportedSyntaxLinkUrl" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-form-group>
+
+ <gl-form-group
+ :label="$options.i18n.afterSignUpTextGroupLabel"
+ :description="$options.i18n.afterSignUpTextGroupDescription"
+ >
+ <textarea
+ v-model="form.afterSignUpText"
+ rows="4"
+ class="form-control gl-form-input"
+ name="application_setting[after_sign_up_text]"
+ ></textarea>
+ </gl-form-group>
+ </section>
+
+ <gl-button
+ data-qa-selector="save_changes_button"
+ variant="confirm"
+ @click.prevent="submitButtonHandler"
+ >
+ {{ $options.i18n.buttonText }}
+ </gl-button>
+
+ <gl-modal
+ :ref="$options.modal.id"
+ :modal-id="$options.modal.id"
+ :action-cancel="$options.modal.actionCancel"
+ :action-primary="$options.modal.actionPrimary"
+ :title="$options.modal.title"
+ @primary="submitForm"
+ @hide="modalHideHandler"
+ >
+ {{ $options.modal.text }}
+ </gl-modal>
+ </form>
+</template>
diff --git a/app/assets/javascripts/pages/admin/application_settings/general/index.js b/app/assets/javascripts/pages/admin/application_settings/general/index.js
index eda1a9d3599..c48d99da990 100644
--- a/app/assets/javascripts/pages/admin/application_settings/general/index.js
+++ b/app/assets/javascripts/pages/admin/application_settings/general/index.js
@@ -1,27 +1,9 @@
-import Vue from 'vue';
-import IntegrationHelpText from '~/vue_shared/components/integrations_help_text.vue';
import initUserInternalRegexPlaceholder from '../account_and_limits';
+import initGitpod from '../gitpod';
+import initSignupRestrictions from '../signup_restrictions';
(() => {
initUserInternalRegexPlaceholder();
-
- const el = document.querySelector('#js-gitpod-settings-help-text');
- if (!el) {
- return;
- }
-
- const { message, messageUrl } = el.dataset;
-
- // eslint-disable-next-line no-new
- new Vue({
- el,
- render(createElement) {
- return createElement(IntegrationHelpText, {
- props: {
- message,
- messageUrl,
- },
- });
- },
- });
+ initGitpod();
+ initSignupRestrictions();
})();
diff --git a/app/assets/javascripts/pages/admin/application_settings/gitpod.js b/app/assets/javascripts/pages/admin/application_settings/gitpod.js
new file mode 100644
index 00000000000..74e46617d52
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/application_settings/gitpod.js
@@ -0,0 +1,24 @@
+import Vue from 'vue';
+import IntegrationHelpText from '~/vue_shared/components/integrations_help_text.vue';
+
+export default function initGitpod() {
+ const el = document.querySelector('#js-gitpod-settings-help-text');
+
+ if (!el) {
+ return false;
+ }
+
+ const { message, messageUrl } = el.dataset;
+
+ return new Vue({
+ el,
+ render(createElement) {
+ return createElement(IntegrationHelpText, {
+ props: {
+ message,
+ messageUrl,
+ },
+ });
+ },
+ });
+}
diff --git a/app/assets/javascripts/pages/admin/application_settings/index.js b/app/assets/javascripts/pages/admin/application_settings/index.js
index e3c6b0f6f5b..a6e3a7dc08a 100644
--- a/app/assets/javascripts/pages/admin/application_settings/index.js
+++ b/app/assets/javascripts/pages/admin/application_settings/index.js
@@ -4,9 +4,7 @@ import initSearchSettings from '~/search_settings';
import selfMonitor from '~/self_monitor';
import initSettingsPanels from '~/settings_panels';
-if (gon.features?.ciInstanceVariablesUi) {
- initVariableList('js-instance-variables');
-}
+initVariableList('js-instance-variables');
selfMonitor();
// Initialize expandable settings panels
initSettingsPanels();
diff --git a/app/assets/javascripts/pages/admin/application_settings/signup_restrictions.js b/app/assets/javascripts/pages/admin/application_settings/signup_restrictions.js
new file mode 100644
index 00000000000..70b896f6372
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/application_settings/signup_restrictions.js
@@ -0,0 +1,31 @@
+import Vue from 'vue';
+import SignupForm from './general/components/signup_form.vue';
+import { getParsedDataset } from './utils';
+
+export default function initSignupRestrictions(elementSelector = '#js-signup-form') {
+ const el = document.querySelector(elementSelector);
+
+ if (!el) {
+ return false;
+ }
+
+ const parsedDataset = getParsedDataset({
+ dataset: el.dataset,
+ booleanAttributes: [
+ 'signupEnabled',
+ 'requireAdminApprovalAfterUserSignup',
+ 'sendUserConfirmationEmail',
+ 'domainDenylistEnabled',
+ 'denylistTypeRawSelected',
+ 'emailRestrictionsEnabled',
+ ],
+ });
+
+ return new Vue({
+ el,
+ provide: {
+ ...parsedDataset,
+ },
+ render: (createElement) => createElement(SignupForm),
+ });
+}
diff --git a/app/assets/javascripts/pages/admin/application_settings/utils.js b/app/assets/javascripts/pages/admin/application_settings/utils.js
new file mode 100644
index 00000000000..5462a13d523
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/application_settings/utils.js
@@ -0,0 +1,21 @@
+import { includes } from 'lodash';
+import { parseBoolean } from '~/lib/utils/common_utils';
+
+/**
+ * Returns a new dataset that has all the values of keys indicated in
+ * booleanAttributes transformed by the parseBoolean() helper function
+ *
+ * @param {Object}
+ * @returns {Object}
+ */
+export const getParsedDataset = ({ dataset = {}, booleanAttributes = [] } = {}) => {
+ const parsedDataset = {};
+
+ Object.keys(dataset).forEach((key) => {
+ parsedDataset[key] = includes(booleanAttributes, key)
+ ? parseBoolean(dataset[key])
+ : dataset[key];
+ });
+
+ return parsedDataset;
+};
diff --git a/app/assets/javascripts/pages/admin/broadcast_messages/index.js b/app/assets/javascripts/pages/admin/broadcast_messages/index.js
index d6cc6a850eb..b7db6443658 100644
--- a/app/assets/javascripts/pages/admin/broadcast_messages/index.js
+++ b/app/assets/javascripts/pages/admin/broadcast_messages/index.js
@@ -1,3 +1,7 @@
+import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
import initBroadcastMessagesForm from './broadcast_message';
-document.addEventListener('DOMContentLoaded', initBroadcastMessagesForm);
+document.addEventListener('DOMContentLoaded', () => {
+ initBroadcastMessagesForm();
+ initDeprecatedRemoveRowBehavior();
+});
diff --git a/app/assets/javascripts/pages/admin/groups/new/index.js b/app/assets/javascripts/pages/admin/groups/new/index.js
index 94f7cfd55be..1630cfb8253 100644
--- a/app/assets/javascripts/pages/admin/groups/new/index.js
+++ b/app/assets/javascripts/pages/admin/groups/new/index.js
@@ -2,9 +2,9 @@ import initFilePickers from '~/file_pickers';
import BindInOut from '../../../../behaviors/bind_in_out';
import Group from '../../../../group';
-document.addEventListener('DOMContentLoaded', () => {
+(() => {
BindInOut.initAll();
initFilePickers();
return new Group();
-});
+})();
diff --git a/app/assets/javascripts/pages/admin/labels/edit/index.js b/app/assets/javascripts/pages/admin/labels/edit/index.js
index 5de1d4d6344..f7c25347e75 100644
--- a/app/assets/javascripts/pages/admin/labels/edit/index.js
+++ b/app/assets/javascripts/pages/admin/labels/edit/index.js
@@ -1,3 +1,3 @@
import Labels from '../../../../labels';
-document.addEventListener('DOMContentLoaded', () => new Labels());
+new Labels(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/admin/labels/index/index.js b/app/assets/javascripts/pages/admin/labels/index/index.js
new file mode 100644
index 00000000000..e5ab5d43bbf
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/labels/index/index.js
@@ -0,0 +1,3 @@
+import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
+
+document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);
diff --git a/app/assets/javascripts/pages/admin/labels/new/index.js b/app/assets/javascripts/pages/admin/labels/new/index.js
index 5de1d4d6344..f7c25347e75 100644
--- a/app/assets/javascripts/pages/admin/labels/new/index.js
+++ b/app/assets/javascripts/pages/admin/labels/new/index.js
@@ -1,3 +1,3 @@
import Labels from '../../../../labels';
-document.addEventListener('DOMContentLoaded', () => new Labels());
+new Labels(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/admin/runners/index.js b/app/assets/javascripts/pages/admin/runners/index/index.js
index 45ed3ac6bd8..45ed3ac6bd8 100644
--- a/app/assets/javascripts/pages/admin/runners/index.js
+++ b/app/assets/javascripts/pages/admin/runners/index/index.js
diff --git a/app/assets/javascripts/pages/admin/runners/show/index.js b/app/assets/javascripts/pages/admin/runners/show/index.js
new file mode 100644
index 00000000000..d1853772fda
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/runners/show/index.js
@@ -0,0 +1,3 @@
+import { initRunnerDetail } from '~/runner/runner_details';
+
+initRunnerDetail();
diff --git a/app/assets/javascripts/pages/admin/services/edit/index.js b/app/assets/javascripts/pages/admin/services/edit/index.js
index 3d692ef4dcc..b8080ddff77 100644
--- a/app/assets/javascripts/pages/admin/services/edit/index.js
+++ b/app/assets/javascripts/pages/admin/services/edit/index.js
@@ -1,6 +1,4 @@
import IntegrationSettingsForm from '~/integrations/integration_settings_form';
-document.addEventListener('DOMContentLoaded', () => {
- const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
- integrationSettingsForm.init();
-});
+const integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
+integrationSettingsForm.init();
diff --git a/app/assets/javascripts/pages/admin/spam_logs/index.js b/app/assets/javascripts/pages/admin/spam_logs/index.js
new file mode 100644
index 00000000000..e5ab5d43bbf
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/spam_logs/index.js
@@ -0,0 +1,3 @@
+import initDeprecatedRemoveRowBehavior from '~/behaviors/deprecated_remove_row_behavior';
+
+document.addEventListener('DOMContentLoaded', initDeprecatedRemoveRowBehavior);
diff --git a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
index d2b83f980d7..20407334b3f 100644
--- a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
+++ b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
@@ -119,8 +119,8 @@ export default {
<gl-button @click="onCancel">{{ s__('Cancel') }}</gl-button>
<gl-button
:disabled="!canSubmit"
- category="primary"
- variant="warning"
+ category="secondary"
+ variant="danger"
@click="onSecondaryAction"
>
{{ secondaryAction }}
diff --git a/app/assets/javascripts/pages/admin/users/new/index.js b/app/assets/javascripts/pages/admin/users/new/index.js
index 7b7d4c169ef..34c10e44f4c 100644
--- a/app/assets/javascripts/pages/admin/users/new/index.js
+++ b/app/assets/javascripts/pages/admin/users/new/index.js
@@ -1,51 +1,3 @@
-import $ from 'jquery';
+import { setupInternalUserRegexHandler } from '~/admin/users/new';
-export default class UserInternalRegexHandler {
- constructor() {
- this.regexPattern = $('[data-user-internal-regex-pattern]').data('user-internal-regex-pattern');
- if (this.regexPattern && this.regexPattern !== '') {
- this.regexOptions = $('[data-user-internal-regex-options]').data(
- 'user-internal-regex-options',
- );
- this.external = $('#user_external');
- this.warningMessage = $('#warning_external_automatically_set');
- this.addListenerToEmailField();
- this.addListenerToUserExternalCheckbox();
- }
- }
-
- addListenerToEmailField() {
- $('#user_email').on('input', (event) => {
- this.setExternalCheckbox(event.currentTarget.value);
- });
- }
-
- addListenerToUserExternalCheckbox() {
- this.external.on('click', () => {
- this.warningMessage.addClass('hidden');
- });
- }
-
- isEmailInternal(email) {
- const regex = new RegExp(this.regexPattern, this.regexOptions);
- return regex.test(email);
- }
-
- setExternalCheckbox(email) {
- const isChecked = this.external.prop('checked');
- if (this.isEmailInternal(email)) {
- if (isChecked) {
- this.external.prop('checked', false);
- this.warningMessage.removeClass('hidden');
- }
- } else if (!isChecked) {
- this.external.prop('checked', true);
- this.warningMessage.addClass('hidden');
- }
- }
-}
-
-document.addEventListener('DOMContentLoaded', () => {
- // eslint-disable-next-line
- new UserInternalRegexHandler();
-});
+setupInternalUserRegexHandler();