diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-12 19:26:10 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-12 19:26:10 +0300 |
commit | 6653ccc011dec86e5140a5d09ea3b2357eab6714 (patch) | |
tree | 897193f37bcd98152a0ac214f80a3c4cfe1047c5 /app/assets/javascripts/pages/projects | |
parent | bff35a05aed6a31380a73c39113808fd262c2c37 (diff) |
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc41
Diffstat (limited to 'app/assets/javascripts/pages/projects')
43 files changed, 904 insertions, 298 deletions
diff --git a/app/assets/javascripts/pages/projects/blob/edit/index.js b/app/assets/javascripts/pages/projects/blob/edit/index.js index 189053f3ed7..ed416610173 100644 --- a/app/assets/javascripts/pages/projects/blob/edit/index.js +++ b/app/assets/javascripts/pages/projects/blob/edit/index.js @@ -1,3 +1,3 @@ import initBlobBundle from '~/blob_edit/blob_bundle'; -document.addEventListener('DOMContentLoaded', initBlobBundle); +initBlobBundle(); diff --git a/app/assets/javascripts/pages/projects/blob/new/index.js b/app/assets/javascripts/pages/projects/blob/new/index.js index 189053f3ed7..ed416610173 100644 --- a/app/assets/javascripts/pages/projects/blob/new/index.js +++ b/app/assets/javascripts/pages/projects/blob/new/index.js @@ -1,3 +1,3 @@ import initBlobBundle from '~/blob_edit/blob_bundle'; -document.addEventListener('DOMContentLoaded', initBlobBundle); +initBlobBundle(); diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js index 61ff1c95a38..10bac6d60c2 100644 --- a/app/assets/javascripts/pages/projects/blob/show/index.js +++ b/app/assets/javascripts/pages/projects/blob/show/index.js @@ -7,61 +7,59 @@ import initWebIdeLink from '~/pages/projects/shared/web_ide_link'; import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue'; import '~/sourcegraph/load'; -document.addEventListener('DOMContentLoaded', () => { - new BlobViewer(); // eslint-disable-line no-new - initBlob(); +new BlobViewer(); // eslint-disable-line no-new +initBlob(); - const CommitPipelineStatusEl = document.querySelector('.js-commit-pipeline-status'); - const statusLink = document.querySelector('.commit-actions .ci-status-link'); - if (statusLink) { - statusLink.remove(); - // eslint-disable-next-line no-new - new Vue({ - el: CommitPipelineStatusEl, - components: { - commitPipelineStatus, - }, - render(createElement) { - return createElement('commit-pipeline-status', { - props: { - endpoint: CommitPipelineStatusEl.dataset.endpoint, - }, - }); - }, - }); - } +const CommitPipelineStatusEl = document.querySelector('.js-commit-pipeline-status'); +const statusLink = document.querySelector('.commit-actions .ci-status-link'); +if (statusLink) { + statusLink.remove(); + // eslint-disable-next-line no-new + new Vue({ + el: CommitPipelineStatusEl, + components: { + commitPipelineStatus, + }, + render(createElement) { + return createElement('commit-pipeline-status', { + props: { + endpoint: CommitPipelineStatusEl.dataset.endpoint, + }, + }); + }, + }); +} - initWebIdeLink({ el: document.getElementById('js-blob-web-ide-link') }); +initWebIdeLink({ el: document.getElementById('js-blob-web-ide-link') }); - GpgBadges.fetch(); +GpgBadges.fetch(); - const codeNavEl = document.getElementById('js-code-navigation'); +const codeNavEl = document.getElementById('js-code-navigation'); - if (codeNavEl) { - const { codeNavigationPath, blobPath, definitionPathPrefix } = codeNavEl.dataset; +if (codeNavEl) { + const { codeNavigationPath, blobPath, definitionPathPrefix } = codeNavEl.dataset; - // eslint-disable-next-line promise/catch-or-return - import('~/code_navigation').then((m) => - m.default({ - blobs: [{ path: blobPath, codeNavigationPath }], - definitionPathPrefix, - }), - ); - } + // eslint-disable-next-line promise/catch-or-return + import('~/code_navigation').then((m) => + m.default({ + blobs: [{ path: blobPath, codeNavigationPath }], + definitionPathPrefix, + }), + ); +} - const successPipelineEl = document.querySelector('.js-success-pipeline-modal'); +const successPipelineEl = document.querySelector('.js-success-pipeline-modal'); - if (successPipelineEl) { - // eslint-disable-next-line no-new - new Vue({ - el: successPipelineEl, - render(createElement) { - return createElement(PipelineTourSuccessModal, { - props: { - ...successPipelineEl.dataset, - }, - }); - }, - }); - } -}); +if (successPipelineEl) { + // eslint-disable-next-line no-new + new Vue({ + el: successPipelineEl, + render(createElement) { + return createElement(PipelineTourSuccessModal, { + props: { + ...successPipelineEl.dataset, + }, + }); + }, + }); +} diff --git a/app/assets/javascripts/pages/projects/boards/index.js b/app/assets/javascripts/pages/projects/boards/index.js index 3a06d0faa3e..bde0007ec6a 100644 --- a/app/assets/javascripts/pages/projects/boards/index.js +++ b/app/assets/javascripts/pages/projects/boards/index.js @@ -2,8 +2,6 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; import initBoards from '~/boards'; import UsersSelect from '~/users_select'; -document.addEventListener('DOMContentLoaded', () => { - new UsersSelect(); // eslint-disable-line no-new - new ShortcutsNavigation(); // eslint-disable-line no-new - initBoards(); -}); +new UsersSelect(); // eslint-disable-line no-new +new ShortcutsNavigation(); // eslint-disable-line no-new +initBoards(); diff --git a/app/assets/javascripts/pages/projects/branches/index/index.js b/app/assets/javascripts/pages/projects/branches/index/index.js index 623d0a10606..72861855c5a 100644 --- a/app/assets/javascripts/pages/projects/branches/index/index.js +++ b/app/assets/javascripts/pages/projects/branches/index/index.js @@ -2,8 +2,6 @@ import AjaxLoadingSpinner from '~/branches/ajax_loading_spinner'; import DeleteModal from '~/branches/branches_delete_modal'; import initDiverganceGraph from '~/branches/divergence_graph'; -document.addEventListener('DOMContentLoaded', () => { - AjaxLoadingSpinner.init(); - new DeleteModal(); // eslint-disable-line no-new - initDiverganceGraph(document.querySelector('.js-branch-list').dataset.divergingCountsEndpoint); -}); +AjaxLoadingSpinner.init(); +new DeleteModal(); // eslint-disable-line no-new +initDiverganceGraph(document.querySelector('.js-branch-list').dataset.divergingCountsEndpoint); diff --git a/app/assets/javascripts/pages/projects/branches/new/index.js b/app/assets/javascripts/pages/projects/branches/new/index.js index 13ff47d53c2..364223f1898 100644 --- a/app/assets/javascripts/pages/projects/branches/new/index.js +++ b/app/assets/javascripts/pages/projects/branches/new/index.js @@ -1,11 +1,8 @@ import $ from 'jquery'; import NewBranchForm from '~/new_branch_form'; -document.addEventListener( - 'DOMContentLoaded', - () => - new NewBranchForm( - $('.js-create-branch-form'), - JSON.parse(document.getElementById('availableRefs').innerHTML), - ), +// eslint-disable-next-line no-new +new NewBranchForm( + $('.js-create-branch-form'), + JSON.parse(document.getElementById('availableRefs').innerHTML), ); diff --git a/app/assets/javascripts/pages/projects/compare/show/index.js b/app/assets/javascripts/pages/projects/compare/show/index.js index f1cf9caa28b..549e596cb8d 100644 --- a/app/assets/javascripts/pages/projects/compare/show/index.js +++ b/app/assets/javascripts/pages/projects/compare/show/index.js @@ -1,6 +1,9 @@ import Diff from '~/diff'; import GpgBadges from '~/gpg_badges'; import initChangesDropdown from '~/init_changes_dropdown'; +import initCompareSelector from '~/projects/compare'; + +initCompareSelector(); document.addEventListener('DOMContentLoaded', () => { new Diff(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/cycle_analytics/show/index.js b/app/assets/javascripts/pages/projects/cycle_analytics/show/index.js index df58e9dd072..255d05b39be 100644 --- a/app/assets/javascripts/pages/projects/cycle_analytics/show/index.js +++ b/app/assets/javascripts/pages/projects/cycle_analytics/show/index.js @@ -1,3 +1,3 @@ -import initCycleAnalytics from '~/cycle_analytics/cycle_analytics_bundle'; +import initCycleAnalytics from '~/cycle_analytics'; document.addEventListener('DOMContentLoaded', initCycleAnalytics); diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js index bbe84322462..43fd5375222 100644 --- a/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js +++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js @@ -1,3 +1,5 @@ +/* eslint-disable no-new */ + import Vue from 'vue'; import Vuex from 'vuex'; import EditUserList from '~/user_lists/components/edit_user_list.vue'; @@ -5,15 +7,13 @@ import createStore from '~/user_lists/store/edit'; Vue.use(Vuex); -document.addEventListener('DOMContentLoaded', () => { - const el = document.getElementById('js-edit-user-list'); - const { userListsDocsPath } = el.dataset; - return new Vue({ - el, - store: createStore(el.dataset), - provide: { userListsDocsPath }, - render(h) { - return h(EditUserList, {}); - }, - }); +const el = document.getElementById('js-edit-user-list'); +const { userListsDocsPath } = el.dataset; +new Vue({ + el, + store: createStore(el.dataset), + provide: { userListsDocsPath }, + render(h) { + return h(EditUserList, {}); + }, }); diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js index 679f0af8efc..e855447d5ce 100644 --- a/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js +++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js @@ -1,3 +1,5 @@ +/* eslint-disable no-new */ + import Vue from 'vue'; import Vuex from 'vuex'; import NewUserList from '~/user_lists/components/new_user_list.vue'; @@ -5,18 +7,16 @@ import createStore from '~/user_lists/store/new'; Vue.use(Vuex); -document.addEventListener('DOMContentLoaded', () => { - const el = document.getElementById('js-new-user-list'); - const { userListsDocsPath, featureFlagsPath } = el.dataset; - return new Vue({ - el, - store: createStore(el.dataset), - provide: { - userListsDocsPath, - featureFlagsPath, - }, - render(h) { - return h(NewUserList); - }, - }); +const el = document.getElementById('js-new-user-list'); +const { userListsDocsPath, featureFlagsPath } = el.dataset; +new Vue({ + el, + store: createStore(el.dataset), + provide: { + userListsDocsPath, + featureFlagsPath, + }, + render(h) { + return h(NewUserList); + }, }); diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js index bccd9dce2ec..2dca0ea7f29 100644 --- a/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js +++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js @@ -1,18 +1,3 @@ -import Vue from 'vue'; -import Vuex from 'vuex'; -import UserList from '~/user_lists/components/user_list.vue'; -import createStore from '~/user_lists/store/show'; +import featureFlagsUserListInit from '~/projects/feature_flags_user_lists/show/index'; -Vue.use(Vuex); - -document.addEventListener('DOMContentLoaded', () => { - const el = document.getElementById('js-edit-user-list'); - return new Vue({ - el, - store: createStore(el.dataset), - render(h) { - const { emptyStatePath } = el.dataset; - return h(UserList, { props: { emptyStatePath } }); - }, - }); -}); +featureFlagsUserListInit(); diff --git a/app/assets/javascripts/pages/projects/forks/new/components/app.vue b/app/assets/javascripts/pages/projects/forks/new/components/app.vue new file mode 100644 index 00000000000..02b357d389b --- /dev/null +++ b/app/assets/javascripts/pages/projects/forks/new/components/app.vue @@ -0,0 +1,72 @@ +<script> +import ForkForm from './fork_form.vue'; + +export default { + components: { + ForkForm, + }, + props: { + forkIllustration: { + type: String, + required: true, + }, + endpoint: { + type: String, + required: true, + }, + projectFullPath: { + type: String, + required: true, + }, + projectId: { + type: String, + required: true, + }, + projectName: { + type: String, + required: true, + }, + projectPath: { + type: String, + required: true, + }, + projectDescription: { + type: String, + required: true, + }, + projectVisibility: { + type: String, + required: true, + }, + }, +}; +</script> + +<template> + <div class="row gl-mt-5"> + <div class="col-lg-3"> + <img :src="forkIllustration" /> + <h4 class="">{{ s__('ForkProject|Fork project') }}</h4> + <p> + {{ s__('ForkProject|A fork is a copy of a project.') }} + <br /> + {{ + s__( + 'ForkProject|Forking a repository allows you to make changes without affecting the original project.', + ) + }} + </p> + </div> + <div class="col-lg-9"> + <fork-form + :endpoint="endpoint" + :project-full-path="projectFullPath" + :project-id="projectId" + :project-name="projectName" + :project-path="projectPath" + :project-description="projectDescription" + :project-visibility="projectVisibility" + /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue new file mode 100644 index 00000000000..7112b23775d --- /dev/null +++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue @@ -0,0 +1,304 @@ +<script> +import { + GlIcon, + GlLink, + GlForm, + GlFormInputGroup, + GlInputGroupText, + GlFormInput, + GlFormGroup, + GlFormTextarea, + GlButton, + GlFormRadio, + GlFormRadioGroup, + GlFormSelect, +} from '@gitlab/ui'; +import { buildApiUrl } from '~/api/api_utils'; +import createFlash from '~/flash'; +import axios from '~/lib/utils/axios_utils'; +import csrf from '~/lib/utils/csrf'; +import { redirectTo } from '~/lib/utils/url_utility'; +import { s__ } from '~/locale'; + +const PRIVATE_VISIBILITY = 'private'; +const INTERNAL_VISIBILITY = 'internal'; +const PUBLIC_VISIBILITY = 'public'; + +const ALLOWED_VISIBILITY = { + private: [PRIVATE_VISIBILITY], + internal: [INTERNAL_VISIBILITY, PRIVATE_VISIBILITY], + public: [INTERNAL_VISIBILITY, PRIVATE_VISIBILITY, PUBLIC_VISIBILITY], +}; + +export default { + components: { + GlForm, + GlIcon, + GlLink, + GlButton, + GlFormInputGroup, + GlInputGroupText, + GlFormInput, + GlFormTextarea, + GlFormGroup, + GlFormRadio, + GlFormRadioGroup, + GlFormSelect, + }, + inject: { + newGroupPath: { + default: '', + }, + visibilityHelpPath: { + default: '', + }, + }, + props: { + endpoint: { + type: String, + required: true, + }, + projectFullPath: { + type: String, + required: true, + }, + projectId: { + type: String, + required: true, + }, + projectName: { + type: String, + required: true, + }, + projectPath: { + type: String, + required: true, + }, + projectDescription: { + type: String, + required: true, + }, + projectVisibility: { + type: String, + required: true, + }, + }, + data() { + return { + isSaving: false, + namespaces: [], + selectedNamespace: {}, + fork: { + name: this.projectName, + slug: this.projectPath, + description: this.projectDescription, + visibility: this.projectVisibility, + }, + }; + }, + computed: { + projectUrl() { + return `${gon.gitlab_url}/`; + }, + projectAllowedVisibility() { + return ALLOWED_VISIBILITY[this.projectVisibility]; + }, + namespaceAllowedVisibility() { + return ( + ALLOWED_VISIBILITY[this.selectedNamespace.visibility] || + ALLOWED_VISIBILITY[PUBLIC_VISIBILITY] + ); + }, + visibilityLevels() { + return [ + { + text: s__('ForkProject|Private'), + value: PRIVATE_VISIBILITY, + icon: 'lock', + help: s__('ForkProject|The project can be accessed without any authentication.'), + disabled: this.isVisibilityLevelDisabled(PRIVATE_VISIBILITY), + }, + { + text: s__('ForkProject|Internal'), + value: INTERNAL_VISIBILITY, + icon: 'shield', + help: s__('ForkProject|The project can be accessed by any logged in user.'), + disabled: this.isVisibilityLevelDisabled(INTERNAL_VISIBILITY), + }, + { + text: s__('ForkProject|Public'), + value: PUBLIC_VISIBILITY, + icon: 'earth', + help: s__( + 'ForkProject|Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group.', + ), + disabled: this.isVisibilityLevelDisabled(PUBLIC_VISIBILITY), + }, + ]; + }, + }, + watch: { + selectedNamespace(newVal) { + const { visibility } = newVal; + + if (this.projectAllowedVisibility.includes(visibility)) { + this.fork.visibility = visibility; + } + }, + }, + mounted() { + this.fetchNamespaces(); + }, + methods: { + async fetchNamespaces() { + const { data } = await axios.get(this.endpoint); + this.namespaces = data.namespaces; + }, + isVisibilityLevelDisabled(visibilityLevel) { + return !( + this.projectAllowedVisibility.includes(visibilityLevel) && + this.namespaceAllowedVisibility.includes(visibilityLevel) + ); + }, + async onSubmit() { + this.isSaving = true; + + const { projectId } = this; + const { name, slug, description, visibility } = this.fork; + const { id: namespaceId } = this.selectedNamespace; + + const postParams = { + id: projectId, + name, + namespace_id: namespaceId, + path: slug, + description, + visibility, + }; + + const forkProjectPath = `/api/:version/projects/:id/fork`; + const url = buildApiUrl(forkProjectPath).replace(':id', encodeURIComponent(this.projectId)); + + try { + const { data } = await axios.post(url, postParams); + redirectTo(data.web_url); + return; + } catch (error) { + createFlash({ message: error }); + } + }, + }, + csrf, +}; +</script> + +<template> + <gl-form method="POST" @submit.prevent="onSubmit"> + <input type="hidden" name="authenticity_token" :value="$options.csrf.token" /> + + <gl-form-group label="Project name" label-for="fork-name"> + <gl-form-input id="fork-name" v-model="fork.name" data-testid="fork-name-input" required /> + </gl-form-group> + + <div class="gl-md-display-flex"> + <div class="gl-flex-basis-half"> + <gl-form-group label="Project URL" label-for="fork-url" class="gl-md-mr-3"> + <gl-form-input-group> + <template #prepend> + <gl-input-group-text> + {{ projectUrl }} + </gl-input-group-text> + </template> + <gl-form-select + id="fork-url" + v-model="selectedNamespace" + data-testid="fork-url-input" + required + > + <template slot="first"> + <option :value="null" disabled>{{ s__('ForkProject|Select a namespace') }}</option> + </template> + <option v-for="namespace in namespaces" :key="namespace.id" :value="namespace"> + {{ namespace.name }} + </option> + </gl-form-select> + </gl-form-input-group> + </gl-form-group> + </div> + <div class="gl-flex-basis-half"> + <gl-form-group label="Project slug" label-for="fork-slug" class="gl-md-ml-3"> + <gl-form-input + id="fork-slug" + v-model="fork.slug" + data-testid="fork-slug-input" + required + /> + </gl-form-group> + </div> + </div> + + <p class="gl-mt-n5 gl-text-gray-500"> + {{ s__('ForkProject|Want to house several dependent projects under the same namespace?') }} + <gl-link :href="newGroupPath" target="_blank"> + {{ s__('ForkProject|Create a group') }} + </gl-link> + </p> + + <gl-form-group label="Project description (optional)" label-for="fork-description"> + <gl-form-textarea + id="fork-description" + v-model="fork.description" + data-testid="fork-description-textarea" + /> + </gl-form-group> + + <gl-form-group> + <label> + {{ s__('ForkProject|Visibility level') }} + <gl-link :href="visibilityHelpPath" target="_blank"> + <gl-icon name="question-o" /> + </gl-link> + </label> + <gl-form-radio-group + v-model="fork.visibility" + data-testid="fork-visibility-radio-group" + required + > + <gl-form-radio + v-for="{ text, value, icon, help, disabled } in visibilityLevels" + :key="value" + :value="value" + :disabled="disabled" + :data-testid="`radio-${value}`" + > + <div> + <gl-icon :name="icon" /> + <span>{{ text }}</span> + </div> + <template #help>{{ help }}</template> + </gl-form-radio> + </gl-form-radio-group> + </gl-form-group> + + <div class="gl-display-flex gl-justify-content-space-between gl-mt-8"> + <gl-button + type="submit" + category="primary" + variant="confirm" + data-testid="submit-button" + :loading="isSaving" + > + {{ s__('ForkProject|Fork project') }} + </gl-button> + <gl-button + type="reset" + class="gl-mr-3" + data-testid="cancel-button" + :disabled="isSaving" + :href="projectFullPath" + > + {{ s__('ForkProject|Cancel') }} + </gl-button> + </div> + </gl-form> +</template> diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue index 46d1696b88b..88f4bba5e2a 100644 --- a/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue +++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_groups_list_item.vue @@ -11,6 +11,7 @@ import { } from '@gitlab/ui'; import { VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE } from '~/groups/constants'; import csrf from '~/lib/utils/csrf'; +import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue'; export default { components: { @@ -20,6 +21,7 @@ export default { GlButton, GlTooltip, GlLink, + UserAccessRoleBadge, }, directives: { GlTooltip: GlTooltipDirective, @@ -72,7 +74,9 @@ export default { <template> <li :class="rowClass" class="group-row"> <div class="group-row-contents gl-display-flex gl-align-items-center gl-py-3 gl-pr-5"> - <div class="folder-toggle-wrap gl-mr-2 gl-display-flex gl-align-items-center"> + <div + class="folder-toggle-wrap gl-mr-3 gl-display-flex gl-align-items-center gl-text-gray-500" + > <gl-icon name="folder-o" /> </div> <gl-link @@ -84,12 +88,12 @@ export default { <div class="gl-min-w-0 gl-display-flex gl-flex-grow-1 gl-flex-shrink-1 gl-align-items-center"> <div class="gl-min-w-0 gl-flex-grow-1 flex-shrink-1"> <div class="title gl-display-flex gl-align-items-center gl-flex-wrap gl-mr-3"> - <gl-link :href="group.relative_path" class="gl-mt-3 gl-mr-3 gl-text-gray-900!">{{ - group.full_name - }}</gl-link> + <gl-link :href="group.relative_path" class="gl-mt-3 gl-mr-3 gl-text-gray-900!"> + {{ group.full_name }} + </gl-link> <gl-icon v-gl-tooltip.hover.bottom - class="gl-mr-0 gl-inline-flex gl-mt-3 text-secondary" + class="gl-display-inline-flex gl-mt-3 gl-mr-3 gl-text-gray-500" :name="visibilityIcon" :title="visibilityTooltip" /> @@ -99,11 +103,11 @@ export default { class="gl-display-none gl-sm-display-flex gl-mt-3 gl-mr-1" >{{ __('pending removal') }}</gl-badge > - <span v-if="group.permission" class="user-access-role gl-mt-3"> + <user-access-role-badge v-if="group.permission" class="gl-mt-3"> {{ group.permission }} - </span> + </user-access-role-badge> </div> - <div v-if="group.description" class="description"> + <div v-if="group.description" class="description gl-line-height-20"> <span v-safe-html="group.markdown_description"> </span> </div> </div> diff --git a/app/assets/javascripts/pages/projects/forks/new/index.js b/app/assets/javascripts/pages/projects/forks/new/index.js index a018d7e0926..372967c8a1e 100644 --- a/app/assets/javascripts/pages/projects/forks/new/index.js +++ b/app/assets/javascripts/pages/projects/forks/new/index.js @@ -1,12 +1,52 @@ import Vue from 'vue'; +import App from './components/app.vue'; import ForkGroupsList from './components/fork_groups_list.vue'; -document.addEventListener('DOMContentLoaded', () => { - const mountElement = document.getElementById('fork-groups-mount-element'); +const mountElement = document.getElementById('fork-groups-mount-element'); +if (gon.features.forkProjectForm) { + const { + forkIllustration, + endpoint, + newGroupPath, + projectFullPath, + visibilityHelpPath, + projectId, + projectName, + projectPath, + projectDescription, + projectVisibility, + } = mountElement.dataset; + + // eslint-disable-next-line no-new + new Vue({ + el: mountElement, + provide: { + newGroupPath, + visibilityHelpPath, + }, + render(h) { + return h(App, { + props: { + forkIllustration, + endpoint, + newGroupPath, + projectFullPath, + visibilityHelpPath, + projectId, + projectName, + projectPath, + projectDescription, + projectVisibility, + }, + }); + }, + }); +} else { const { endpoint } = mountElement.dataset; - return new Vue({ + // eslint-disable-next-line no-new + new Vue({ el: mountElement, render(h) { return h(ForkGroupsList, { @@ -16,4 +56,4 @@ document.addEventListener('DOMContentLoaded', () => { }); }, }); -}); +} diff --git a/app/assets/javascripts/pages/projects/imports/show/index.js b/app/assets/javascripts/pages/projects/imports/show/index.js index d5f92baf054..8397826f8eb 100644 --- a/app/assets/javascripts/pages/projects/imports/show/index.js +++ b/app/assets/javascripts/pages/projects/imports/show/index.js @@ -1,5 +1,3 @@ import ProjectImport from '~/project_import'; -document.addEventListener('DOMContentLoaded', () => { - new ProjectImport(); // eslint-disable-line no-new -}); +new ProjectImport(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/issues/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js index 525d90e162d..a3a053c3c31 100644 --- a/app/assets/javascripts/pages/projects/issues/index/index.js +++ b/app/assets/javascripts/pages/projects/issues/index/index.js @@ -2,6 +2,7 @@ import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys'; import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; +import initCsvImportExportButtons from '~/issuable/init_csv_import_export_buttons'; import initIssuableByEmail from '~/issuable/init_issuable_by_email'; import IssuableIndex from '~/issuable_index'; import initIssuablesList from '~/issues_list'; @@ -26,3 +27,4 @@ new UsersSelect(); initManualOrdering(); initIssuablesList(); initIssuableByEmail(); +initCsvImportExportButtons(); diff --git a/app/assets/javascripts/pages/projects/jobs/index/index.js b/app/assets/javascripts/pages/projects/jobs/index/index.js index 6a70d4cf26d..681d151b77f 100644 --- a/app/assets/javascripts/pages/projects/jobs/index/index.js +++ b/app/assets/javascripts/pages/projects/jobs/index/index.js @@ -1,19 +1,17 @@ import Vue from 'vue'; import GlCountdown from '~/vue_shared/components/gl_countdown.vue'; -document.addEventListener('DOMContentLoaded', () => { - const remainingTimeElements = document.querySelectorAll('.js-remaining-time'); - remainingTimeElements.forEach( - (el) => - new Vue({ - el, - render(h) { - return h(GlCountdown, { - props: { - endDateString: el.dateTime, - }, - }); - }, - }), - ); -}); +const remainingTimeElements = document.querySelectorAll('.js-remaining-time'); +remainingTimeElements.forEach( + (el) => + new Vue({ + el, + render(h) { + return h(GlCountdown, { + props: { + endDateString: el.dateTime, + }, + }); + }, + }), +); diff --git a/app/assets/javascripts/pages/projects/labels/edit/index.js b/app/assets/javascripts/pages/projects/labels/edit/index.js index 83d6ac9fd14..3b7562deed9 100644 --- a/app/assets/javascripts/pages/projects/labels/edit/index.js +++ b/app/assets/javascripts/pages/projects/labels/edit/index.js @@ -1,3 +1,3 @@ import Labels from 'ee_else_ce/labels'; -document.addEventListener('DOMContentLoaded', () => new Labels()); +new Labels(); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue index 0393793bfe1..32ca623ca45 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue @@ -1,11 +1,11 @@ <script> import { GlLink } from '@gitlab/ui'; -import { ACTION_TEXT } from '../constants'; +import { ACTION_LABELS } from '../constants'; export default { components: { GlLink }, i18n: { - ACTION_TEXT, + ACTION_LABELS, }, props: { actions: { @@ -18,9 +18,9 @@ export default { <template> <ul> <li v-for="(value, action) in actions" :key="action"> - <span v-if="value.completed">{{ $options.i18n.ACTION_TEXT[action] }}</span> + <span v-if="value.completed">{{ $options.i18n.ACTION_LABELS[action].title }}</span> <span v-else> - <gl-link :href="value.url">{{ $options.i18n.ACTION_TEXT[action] }}</gl-link> + <gl-link :href="value.url">{{ $options.i18n.ACTION_LABELS[action].title }}</gl-link> </span> </li> </ul> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue index 0393793bfe1..230054ff76e 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue @@ -1,11 +1,35 @@ <script> -import { GlLink } from '@gitlab/ui'; -import { ACTION_TEXT } from '../constants'; +import { GlProgressBar, GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import { ACTION_LABELS } from '../constants'; +import LearnGitlabInfoCard from './learn_gitlab_info_card.vue'; export default { - components: { GlLink }, + components: { LearnGitlabInfoCard, GlProgressBar, GlSprintf }, i18n: { - ACTION_TEXT, + title: s__('LearnGitLab|Learn GitLab'), + description: s__( + 'LearnGitLab|Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project.', + ), + percentageCompleted: s__(`LearnGitLab|%{percentage}%{percentSymbol} completed`), + workspace: { + title: s__('LearnGitLab|Set up your workspace'), + description: s__( + "LearnGitLab|Complete these tasks first so you can enjoy GitLab's features to their fullest:", + ), + }, + plan: { + title: s__('LearnGitLab|Plan and execute'), + description: s__( + 'LearnGitLab|Create a workflow for your new workspace, and learn how GitLab features work together:', + ), + }, + deploy: { + title: s__('LearnGitLab|Deploy'), + description: s__( + 'LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:', + ), + }, }, props: { actions: { @@ -13,15 +37,76 @@ export default { type: Object, }, }, + maxValue: Object.keys(ACTION_LABELS).length, + methods: { + infoProps(action) { + return { + ...this.actions[action], + ...ACTION_LABELS[action], + }; + }, + progressValue() { + return Object.values(this.actions).filter((a) => a.completed).length; + }, + progressPercentage() { + return Math.round((this.progressValue() / this.$options.maxValue) * 100); + }, + }, }; </script> <template> - <ul> - <li v-for="(value, action) in actions" :key="action"> - <span v-if="value.completed">{{ $options.i18n.ACTION_TEXT[action] }}</span> - <span v-else> - <gl-link :href="value.url">{{ $options.i18n.ACTION_TEXT[action] }}</gl-link> - </span> - </li> - </ul> + <div> + <div class="row"> + <div class="gl-mb-7 col-md-8 col-lg-7"> + <h1 class="gl-font-size-h1">{{ $options.i18n.title }}</h1> + <p class="gl-text-gray-700 gl-mb-0">{{ $options.i18n.description }}</p> + </div> + </div> + + <div class="gl-mb-3"> + <p class="gl-text-gray-500 gl-mb-2" data-testid="completion-percentage"> + <gl-sprintf :message="$options.i18n.percentageCompleted"> + <template #percentage>{{ progressPercentage() }}</template> + <template #percentSymbol>%</template> + </gl-sprintf> + </p> + <gl-progress-bar :value="progressValue()" :max="$options.maxValue" /> + </div> + + <h2 class="gl-font-lg gl-mb-3">{{ $options.i18n.workspace.title }}</h2> + <p class="gl-text-gray-700 gl-mb-6">{{ $options.i18n.workspace.description }}</p> + + <div class="row row-cols-2 row-cols-md-3 row-cols-lg-4"> + <div class="col gl-mb-6"><learn-gitlab-info-card v-bind="infoProps('userAdded')" /></div> + <div class="col gl-mb-6"><learn-gitlab-info-card v-bind="infoProps('gitWrite')" /></div> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('pipelineCreated')" /> + </div> + <div class="col gl-mb-6"><learn-gitlab-info-card v-bind="infoProps('trialStarted')" /></div> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('codeOwnersEnabled')" /> + </div> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('requiredMrApprovalsEnabled')" /> + </div> + </div> + + <h2 class="gl-font-lg gl-mb-3">{{ $options.i18n.plan.title }}</h2> + <p class="gl-text-gray-700 gl-mb-6">{{ $options.i18n.plan.description }}</p> + + <div class="row row-cols-2 row-cols-md-3 row-cols-lg-4"> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('mergeRequestCreated')" /> + </div> + </div> + + <h2 class="gl-font-lg gl-mb-3">{{ $options.i18n.deploy.title }}</h2> + <p class="gl-text-gray-700 gl-mb-6">{{ $options.i18n.deploy.description }}</p> + + <div class="row row-cols-2 row-cols-lg-4 g-2 g-lg-3"> + <div class="col gl-mb-6"> + <learn-gitlab-info-card v-bind="infoProps('securityScanEnabled')" /> + </div> + </div> + </div> </template> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue new file mode 100644 index 00000000000..3d2a8eed9d4 --- /dev/null +++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_info_card.vue @@ -0,0 +1,70 @@ +<script> +import { GlLink, GlCard, GlIcon } from '@gitlab/ui'; +import { s__ } from '~/locale'; + +export default { + name: 'LearnGitlabInfoCard', + components: { GlLink, GlCard, GlIcon }, + i18n: { + trial: s__('Learn GitLab|Trial only'), + }, + props: { + title: { + required: true, + type: String, + }, + description: { + required: true, + type: String, + }, + actionLabel: { + required: true, + type: String, + }, + url: { + required: true, + type: String, + }, + completed: { + required: true, + type: Boolean, + }, + svg: { + required: true, + type: String, + }, + trialRequired: { + default: false, + required: false, + type: Boolean, + }, + }, +}; +</script> +<template> + <gl-card class="gl-pt-0"> + <div class="gl-text-right gl-h-5"> + <gl-icon + v-if="completed" + name="check-circle-filled" + class="gl-text-green-500" + :size="16" + data-testid="completed-icon" + /> + <span + v-else-if="trialRequired" + class="gl-text-gray-500 gl-font-sm gl-font-style-italic" + data-testid="trial-only" + >{{ $options.i18n.trial }}</span + > + </div> + <div + class="gl-text-center gl-display-flex gl-justify-content-center gl-align-items-center gl-flex-direction-column learn-gitlab-info-card-content" + > + <img :src="svg" /> + <h6>{{ title }}</h6> + <p class="gl-font-sm gl-text-gray-700">{{ description }}</p> + <gl-link :href="url" target="_blank">{{ actionLabel }}</gl-link> + </div> + </gl-card> +</template> diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js index 8606af29785..80f04b0cf44 100644 --- a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js +++ b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js @@ -1,12 +1,50 @@ import { s__ } from '~/locale'; -export const ACTION_TEXT = { - gitWrite: s__('LearnGitLab|Create a repository'), - userAdded: s__('LearnGitLab|Invite your colleagues'), - pipelineCreated: s__('LearnGitLab|Set-up CI/CD'), - trialStarted: s__('LearnGitLab|Start a free trial of GitLab Gold'), - codeOwnersEnabled: s__('LearnGitLab|Add code owners'), - requiredMrApprovalsEnabled: s__('LearnGitLab|Enable require merge approvals'), - mergeRequestCreated: s__('LearnGitLab|Submit a merge request (MR)'), - securityScanEnabled: s__('LearnGitLab|Run a Security scan using CI/CD'), +export const ACTION_LABELS = { + gitWrite: { + title: s__('LearnGitLab|Create or import a repository'), + actionLabel: s__('LearnGitLab|Create or import a repository'), + description: s__('LearnGitLab|Create or import your first repository into your new project.'), + }, + userAdded: { + title: s__('LearnGitLab|Invite your colleagues'), + actionLabel: s__('LearnGitLab|Invite your colleagues'), + description: s__( + 'LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features.', + ), + }, + pipelineCreated: { + title: s__('LearnGitLab|Set up CI/CD'), + actionLabel: s__('LearnGitLab|Set-up CI/CD'), + description: s__('LearnGitLab|Save time by automating your integration and deployment tasks.'), + }, + trialStarted: { + title: s__('LearnGitLab|Start a free Ultimate trial'), + actionLabel: s__('LearnGitLab|Try GitLab Ultimate for free'), + description: s__('LearnGitLab|Try all GitLab features for 30 days, no credit card required.'), + }, + codeOwnersEnabled: { + title: s__('LearnGitLab|Add code owners'), + actionLabel: s__('LearnGitLab|Add code owners'), + description: s__( + 'LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths.', + ), + trialRequired: true, + }, + requiredMrApprovalsEnabled: { + title: s__('LearnGitLab|Add merge request approval'), + actionLabel: s__('LearnGitLab|Enable require merge approvals'), + description: s__('LearnGitLab|Route code reviews to the right reviewers, every time.'), + trialRequired: true, + }, + mergeRequestCreated: { + title: s__('LearnGitLab|Submit a merge request'), + actionLabel: s__('LearnGitLab|Submit a merge request (MR)'), + description: s__('LearnGitLab|Review and edit proposed changes to source code.'), + }, + securityScanEnabled: { + title: s__('LearnGitLab|Run a security scan'), + actionLabel: s__('LearnGitLab|Run a Security scan'), + description: s__('LearnGitLab|Scan your code to uncover vulnerabilities before deploying.'), + }, }; diff --git a/app/assets/javascripts/pages/projects/logs/index.js b/app/assets/javascripts/pages/projects/logs/index.js index 36747069ebb..0cff1ffc27e 100644 --- a/app/assets/javascripts/pages/projects/logs/index.js +++ b/app/assets/javascripts/pages/projects/logs/index.js @@ -1,3 +1,3 @@ import logsBundle from '~/logs'; -document.addEventListener('DOMContentLoaded', logsBundle); +logsBundle(); diff --git a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js index 399aebb0c83..ec21d8c84e0 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js +++ b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js @@ -1,7 +1,5 @@ import initMergeRequest from '~/pages/projects/merge_requests/init_merge_request'; import initCheckFormState from './check_form_state'; -document.addEventListener('DOMContentLoaded', () => { - initMergeRequest(); - initCheckFormState(); -}); +initMergeRequest(); +initCheckFormState(); diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js index 76705256fe2..d279086df7b 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js +++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js @@ -1,6 +1,7 @@ import addExtraTokensForMergeRequests from 'ee_else_ce/filtered_search/add_extra_tokens_for_merge_requests'; import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; +import initCsvImportExportButtons from '~/issuable/init_csv_import_export_buttons'; import initIssuableByEmail from '~/issuable/init_issuable_by_email'; import IssuableIndex from '~/issuable_index'; import { FILTERED_SEARCH } from '~/pages/constants'; @@ -22,3 +23,4 @@ new UsersSelect(); // eslint-disable-line no-new new ShortcutsNavigation(); // eslint-disable-line no-new initIssuableByEmail(); +initCsvImportExportButtons(); diff --git a/app/assets/javascripts/pages/projects/milestones/edit/index.js b/app/assets/javascripts/pages/projects/milestones/edit/index.js index 9a4ebf9890d..4f8514a9a1d 100644 --- a/app/assets/javascripts/pages/projects/milestones/edit/index.js +++ b/app/assets/javascripts/pages/projects/milestones/edit/index.js @@ -1,3 +1,3 @@ -import initForm from '../../../../shared/milestones/form'; +import initForm from '~/shared/milestones/form'; -document.addEventListener('DOMContentLoaded', () => initForm()); +initForm(); diff --git a/app/assets/javascripts/pages/projects/milestones/index/index.js b/app/assets/javascripts/pages/projects/milestones/index/index.js index 38789365a67..150b506b121 100644 --- a/app/assets/javascripts/pages/projects/milestones/index/index.js +++ b/app/assets/javascripts/pages/projects/milestones/index/index.js @@ -1,3 +1,3 @@ import milestones from '~/pages/milestones/shared'; -document.addEventListener('DOMContentLoaded', milestones); +milestones(); diff --git a/app/assets/javascripts/pages/projects/milestones/new/index.js b/app/assets/javascripts/pages/projects/milestones/new/index.js index 9a4ebf9890d..364b0d95d9c 100644 --- a/app/assets/javascripts/pages/projects/milestones/new/index.js +++ b/app/assets/javascripts/pages/projects/milestones/new/index.js @@ -1,3 +1,3 @@ import initForm from '../../../../shared/milestones/form'; -document.addEventListener('DOMContentLoaded', () => initForm()); +initForm(); diff --git a/app/assets/javascripts/pages/projects/milestones/show/index.js b/app/assets/javascripts/pages/projects/milestones/show/index.js index a853413e1f7..3c755e9b98c 100644 --- a/app/assets/javascripts/pages/projects/milestones/show/index.js +++ b/app/assets/javascripts/pages/projects/milestones/show/index.js @@ -1,7 +1,5 @@ import milestones from '~/pages/milestones/shared'; import initMilestonesShow from '~/pages/milestones/shared/init_milestones_show'; -document.addEventListener('DOMContentLoaded', () => { - initMilestonesShow(); - milestones(); -}); +initMilestonesShow(); +milestones(); diff --git a/app/assets/javascripts/pages/projects/new/index.js b/app/assets/javascripts/pages/projects/new/index.js index 437594fdf11..e10e2872dce 100644 --- a/app/assets/javascripts/pages/projects/new/index.js +++ b/app/assets/javascripts/pages/projects/new/index.js @@ -3,28 +3,26 @@ import { __ } from '~/locale'; import initProjectVisibilitySelector from '../../../project_visibility'; import initProjectNew from '../../../projects/project_new'; -document.addEventListener('DOMContentLoaded', () => { - initProjectVisibilitySelector(); - initProjectNew.bindEvents(); +initProjectVisibilitySelector(); +initProjectNew.bindEvents(); - import( - /* webpackChunkName: 'experiment_new_project_creation' */ '../../../projects/experiment_new_project_creation' - ) - .then((m) => { - const el = document.querySelector('.js-experiment-new-project-creation'); +import( + /* webpackChunkName: 'experiment_new_project_creation' */ '../../../projects/experiment_new_project_creation' +) + .then((m) => { + const el = document.querySelector('.js-experiment-new-project-creation'); - if (!el) { - return; - } + if (!el) { + return; + } - const config = { - hasErrors: 'hasErrors' in el.dataset, - isCiCdAvailable: 'isCiCdAvailable' in el.dataset, - newProjectGuidelines: el.dataset.newProjectGuidelines, - }; - m.default(el, config); - }) - .catch(() => { - createFlash(__('An error occurred while loading project creation UI')); - }); -}); + const config = { + hasErrors: 'hasErrors' in el.dataset, + isCiCdAvailable: 'isCiCdAvailable' in el.dataset, + newProjectGuidelines: el.dataset.newProjectGuidelines, + }; + m.default(el, config); + }) + .catch(() => { + createFlash(__('An error occurred while loading project creation UI')); + }); diff --git a/app/assets/javascripts/pages/projects/project_members/index.js b/app/assets/javascripts/pages/projects/project_members/index.js index ed11b07be4a..4aea5614bfb 100644 --- a/app/assets/javascripts/pages/projects/project_members/index.js +++ b/app/assets/javascripts/pages/projects/project_members/index.js @@ -1,11 +1,14 @@ import Vue from 'vue'; -import { deprecatedCreateFlash as flash } from '~/flash'; import groupsSelect from '~/groups_select'; +import initInviteGroupTrigger from '~/invite_members/init_invite_group_trigger'; +import initInviteMembersForm from '~/invite_members/init_invite_members_form'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; -import { __ } from '~/locale'; +import { s__ } from '~/locale'; import memberExpirationDate from '~/member_expiration_date'; -import Members from '~/members'; +import { initMembersApp } from '~/members'; +import { groupLinkRequestFormatter } from '~/members/utils'; +import { projectMemberRequestFormatter } from '~/projects/members/utils'; import UsersSelect from '~/users_select'; import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue'; @@ -29,68 +32,51 @@ memberExpirationDate('.js-access-expiration-date-groups'); mountRemoveMemberModal(); initInviteMembersModal(); initInviteMembersTrigger(); +initInviteGroupTrigger(); -new Members(); // eslint-disable-line no-new -new UsersSelect(); // eslint-disable-line no-new +// This is only used when `invite_members_group_modal` feature flag is disabled. +// This can be removed when `invite_members_group_modal` feature flag is removed. +initInviteMembersForm(); -if (window.gon.features.vueProjectMembersList) { - const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions']; +new UsersSelect(); // eslint-disable-line no-new - Promise.all([ - import('~/members/index'), - import('~/members/utils'), - import('~/projects/members/utils'), - import('~/locale'), - ]) - .then( - ([ - { initMembersApp }, - { groupLinkRequestFormatter }, - { projectMemberRequestFormatter }, - { s__ }, - ]) => { - initMembersApp(document.querySelector('.js-project-members-list'), { - tableFields: SHARED_FIELDS.concat(['source', 'granted']), - tableAttrs: { tr: { 'data-qa-selector': 'member_row' } }, - tableSortableFields: ['account', 'granted', 'maxRole', 'lastSignIn'], - requestFormatter: projectMemberRequestFormatter, - filteredSearchBar: { - show: true, - tokens: ['with_inherited_permissions'], - searchParam: 'search', - placeholder: s__('Members|Filter members'), - recentSearchesStorageKey: 'project_members', - }, - }); +const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions']; +initMembersApp(document.querySelector('.js-project-members-list'), { + tableFields: SHARED_FIELDS.concat(['source', 'granted']), + tableAttrs: { tr: { 'data-qa-selector': 'member_row' } }, + tableSortableFields: ['account', 'granted', 'maxRole', 'lastSignIn'], + requestFormatter: projectMemberRequestFormatter, + filteredSearchBar: { + show: true, + tokens: ['with_inherited_permissions'], + searchParam: 'search', + placeholder: s__('Members|Filter members'), + recentSearchesStorageKey: 'project_members', + }, +}); - initMembersApp(document.querySelector('.js-project-group-links-list'), { - tableFields: SHARED_FIELDS.concat('granted'), - tableAttrs: { - table: { 'data-qa-selector': 'groups_list' }, - tr: { 'data-qa-selector': 'group_row' }, - }, - requestFormatter: groupLinkRequestFormatter, - filteredSearchBar: { - show: true, - tokens: [], - searchParam: 'search_groups', - placeholder: s__('Members|Search groups'), - recentSearchesStorageKey: 'project_group_links', - }, - }); +initMembersApp(document.querySelector('.js-project-group-links-list'), { + tableFields: SHARED_FIELDS.concat('granted'), + tableAttrs: { + table: { 'data-qa-selector': 'groups_list' }, + tr: { 'data-qa-selector': 'group_row' }, + }, + requestFormatter: groupLinkRequestFormatter, + filteredSearchBar: { + show: true, + tokens: [], + searchParam: 'search_groups', + placeholder: s__('Members|Search groups'), + recentSearchesStorageKey: 'project_group_links', + }, +}); - initMembersApp(document.querySelector('.js-project-invited-members-list'), { - tableFields: SHARED_FIELDS.concat('invited'), - requestFormatter: projectMemberRequestFormatter, - }); +initMembersApp(document.querySelector('.js-project-invited-members-list'), { + tableFields: SHARED_FIELDS.concat('invited'), + requestFormatter: projectMemberRequestFormatter, +}); - initMembersApp(document.querySelector('.js-project-access-requests-list'), { - tableFields: SHARED_FIELDS.concat('requested'), - requestFormatter: projectMemberRequestFormatter, - }); - }, - ) - .catch(() => { - flash(__('An error occurred while loading the members, please try again.')); - }); -} +initMembersApp(document.querySelector('.js-project-access-requests-list'), { + tableFields: SHARED_FIELDS.concat('requested'), + requestFormatter: projectMemberRequestFormatter, +}); diff --git a/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js b/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js index 2fd047675b9..82856c1c8b9 100644 --- a/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js +++ b/app/assets/javascripts/pages/projects/prometheus/metrics/edit/index.js @@ -1,3 +1,3 @@ -import customMetrics from '~/custom_metrics'; +import CustomMetrics from '~/custom_metrics'; -document.addEventListener('DOMContentLoaded', customMetrics); +CustomMetrics(); diff --git a/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js b/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js index 2fd047675b9..82856c1c8b9 100644 --- a/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js +++ b/app/assets/javascripts/pages/projects/prometheus/metrics/new/index.js @@ -1,3 +1,3 @@ -import customMetrics from '~/custom_metrics'; +import CustomMetrics from '~/custom_metrics'; -document.addEventListener('DOMContentLoaded', customMetrics); +CustomMetrics(); diff --git a/app/assets/javascripts/pages/projects/settings/access_tokens/index.js b/app/assets/javascripts/pages/projects/settings/access_tokens/index.js index 22dddb72f98..dc1bb88bf4b 100644 --- a/app/assets/javascripts/pages/projects/settings/access_tokens/index.js +++ b/app/assets/javascripts/pages/projects/settings/access_tokens/index.js @@ -1,3 +1,3 @@ -import initExpiresAtField from '~/access_tokens'; +import { initExpiresAtField } from '~/access_tokens'; initExpiresAtField(); diff --git a/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js b/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js index be9259ec3ca..b7e8d4b03ac 100644 --- a/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js @@ -6,6 +6,7 @@ import initDeployFreeze from '~/deploy_freeze'; import { initInstallRunner } from '~/pages/shared/mount_runner_instructions'; import initSharedRunnersToggle from '~/projects/settings/mount_shared_runners_toggle'; import registrySettingsApp from '~/registry/settings/registry_settings_bundle'; +import initSearchSettings from '~/search_settings'; import initSettingsPanels from '~/settings_panels'; document.addEventListener('DOMContentLoaded', () => { @@ -42,4 +43,6 @@ document.addEventListener('DOMContentLoaded', () => { } initInstallRunner(); + + initSearchSettings(); }); diff --git a/app/assets/javascripts/pages/projects/settings/operations/show/index.js b/app/assets/javascripts/pages/projects/settings/operations/show/index.js index 3a46241e2eb..4a800ab150d 100644 --- a/app/assets/javascripts/pages/projects/settings/operations/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/operations/show/index.js @@ -3,6 +3,7 @@ import mountErrorTrackingForm from '~/error_tracking_settings'; import mountGrafanaIntegration from '~/grafana_integration'; import initIncidentsSettings from '~/incidents_settings'; import mountOperationSettings from '~/operation_settings'; +import initSearchSettings from '~/search_settings'; import initSettingsPanels from '~/settings_panels'; initIncidentsSettings(); @@ -13,3 +14,7 @@ if (!IS_EE) { initSettingsPanels(); } mountAlertsSettings(document.querySelector('.js-alerts-settings')); + +document.addEventListener('DOMContentLoaded', () => { + initSearchSettings(); +}); diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/index.js b/app/assets/javascripts/pages/projects/settings/repository/show/index.js index e90954c14c5..c7bcbb83051 100644 --- a/app/assets/javascripts/pages/projects/settings/repository/show/index.js +++ b/app/assets/javascripts/pages/projects/settings/repository/show/index.js @@ -1,4 +1,5 @@ import MirrorRepos from '~/mirrors/mirror_repos'; +import initSearchSettings from '~/search_settings'; import initForm from '../form'; document.addEventListener('DOMContentLoaded', () => { @@ -6,4 +7,6 @@ document.addEventListener('DOMContentLoaded', () => { const mirrorReposContainer = document.querySelector('.js-mirror-settings'); if (mirrorReposContainer) new MirrorRepos(mirrorReposContainer).init(); + + initSearchSettings(); }); diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue index 94a9bc168e5..62b565a4856 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue +++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue @@ -11,6 +11,7 @@ import { featureAccessLevelEveryone, featureAccessLevel, featureAccessLevelNone, + CVE_ID_REQUEST_BUTTON_I18N, } from '../constants'; import { toggleHiddenClassBySelector } from '../external'; import projectFeatureSetting from './project_feature_setting.vue'; @@ -19,6 +20,10 @@ import projectSettingRow from './project_setting_row.vue'; const PAGE_FEATURE_ACCESS_LEVEL = s__('ProjectSettings|Everyone'); export default { + i18n: { + ...CVE_ID_REQUEST_BUTTON_I18N, + }, + components: { projectFeatureSetting, projectSettingRow, @@ -31,6 +36,11 @@ export default { mixins: [settingsMixin, glFeatureFlagsMixin()], props: { + requestCveAvailable: { + type: Boolean, + required: false, + default: false, + }, currentSettings: { type: Object, required: true, @@ -99,6 +109,11 @@ export default { required: false, default: '', }, + cveIdRequestHelpPath: { + type: String, + required: false, + default: '', + }, registryHelpPath: { type: String, required: false, @@ -152,6 +167,7 @@ export default { requestAccessEnabled: true, highlightChangesClass: false, emailsDisabled: false, + cveIdRequestEnabled: true, featureAccessLevelEveryone, featureAccessLevelMembers, }; @@ -230,6 +246,9 @@ export default { 'ProjectSettings|View and edit files in this project. Non-project members will only have read access.', ); }, + cveIdRequestIsDisabled() { + return this.visibilityLevel !== visibilityOptions.PUBLIC; + }, }, watch: { @@ -417,6 +436,19 @@ export default { :options="featureAccessLevelOptions" name="project[project_feature_attributes][issues_access_level]" /> + <project-setting-row + v-if="requestCveAvailable" + :help-path="cveIdRequestHelpPath" + :help-text="$options.i18n.cve_request_toggle_label" + > + <gl-toggle + v-model="cveIdRequestEnabled" + class="gl-my-2" + :disabled="cveIdRequestIsDisabled" + name="project[project_setting_attributes][cve_id_request_enabled]" + data-testid="cve_id_request_toggle" + /> + </project-setting-row> </project-setting-row> <project-setting-row ref="repository-settings" @@ -613,7 +645,9 @@ export default { <project-setting-row ref="operations-settings" :label="s__('ProjectSettings|Operations')" - :help-text="s__('ProjectSettings|Environments, logs, cluster management, and more.')" + :help-text=" + s__('ProjectSettings|Configure your project resources and monitor their health.') + " > <project-feature-setting v-model="operationsAccessLevel" diff --git a/app/assets/javascripts/pages/projects/shared/permissions/constants.js b/app/assets/javascripts/pages/projects/shared/permissions/constants.js index 6771391254e..e160fdacca6 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/constants.js +++ b/app/assets/javascripts/pages/projects/shared/permissions/constants.js @@ -1,4 +1,4 @@ -import { __ } from '~/locale'; +import { s__, __ } from '~/locale'; export const visibilityOptions = { PRIVATE: 0, @@ -42,3 +42,7 @@ export const featureAccessLevelEveryone = [ featureAccessLevel.EVERYONE, featureAccessLevelDescriptions[featureAccessLevel.EVERYONE], ]; + +export const CVE_ID_REQUEST_BUTTON_I18N = { + cve_request_toggle_label: s__('CVE|Enable CVE ID requests in the issue sidebar'), +}; diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js index 0494dad6e33..a0831c7df41 100644 --- a/app/assets/javascripts/pages/projects/show/index.js +++ b/app/assets/javascripts/pages/projects/show/index.js @@ -3,20 +3,15 @@ import Activities from '~/activities'; import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; import BlobViewer from '~/blob/viewer/index'; import { initUploadForm } from '~/blob_edit/blob_bundle'; -import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; -import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import leaveByUrl from '~/namespaces/leave_by_url'; import initVueNotificationsDropdown from '~/notifications'; -import NotificationsForm from '~/notifications_form'; import initReadMore from '~/read_more'; import UserCallout from '~/user_callout'; -import notificationsDropdown from '../../../notifications_dropdown'; import Star from '../../../star'; initReadMore(); new Star(); // eslint-disable-line no-new -new NotificationsForm(); // eslint-disable-line no-new // eslint-disable-next-line no-new new UserCallout({ setCalloutPerProject: false, @@ -24,9 +19,12 @@ new UserCallout({ }); // Project show page loads different overview content based on user preferences -const treeSlider = document.getElementById('js-tree-list'); -if (treeSlider) { + +if (document.querySelector('.js-upload-blob-form')) { initUploadForm(); +} + +if (document.getElementById('js-tree-list')) { initTree(); } @@ -40,15 +38,6 @@ if (document.querySelector('.project-show-activity')) { leaveByUrl('project'); -if (gon.features?.vueNotificationDropdown) { - initVueNotificationsDropdown(); -} else { - notificationsDropdown(); -} - initVueNotificationsDropdown(); new ShortcutsNavigation(); // eslint-disable-line no-new - -initInviteMembersTrigger(); -initInviteMembersModal(); diff --git a/app/assets/javascripts/pages/projects/tags/new/index.js b/app/assets/javascripts/pages/projects/tags/new/index.js index 11a19a673b1..b071e7a45fc 100644 --- a/app/assets/javascripts/pages/projects/tags/new/index.js +++ b/app/assets/javascripts/pages/projects/tags/new/index.js @@ -3,8 +3,6 @@ import GLForm from '../../../../gl_form'; import RefSelectDropdown from '../../../../ref_select_dropdown'; import ZenMode from '../../../../zen_mode'; -document.addEventListener('DOMContentLoaded', () => { - new ZenMode(); // eslint-disable-line no-new - new GLForm($('.tag-form')); // eslint-disable-line no-new - new RefSelectDropdown($('.js-branch-select')); // eslint-disable-line no-new -}); +new ZenMode(); // eslint-disable-line no-new +new GLForm($('.tag-form')); // eslint-disable-line no-new +new RefSelectDropdown($('.js-branch-select')); // eslint-disable-line no-new diff --git a/app/assets/javascripts/pages/projects/tags/releases/index.js b/app/assets/javascripts/pages/projects/tags/releases/index.js index abdc97f62d0..cafd880b4be 100644 --- a/app/assets/javascripts/pages/projects/tags/releases/index.js +++ b/app/assets/javascripts/pages/projects/tags/releases/index.js @@ -2,7 +2,5 @@ import $ from 'jquery'; import GLForm from '~/gl_form'; import ZenMode from '~/zen_mode'; -document.addEventListener('DOMContentLoaded', () => { - new ZenMode(); // eslint-disable-line no-new - new GLForm($('.release-form')); // eslint-disable-line no-new -}); +new ZenMode(); // eslint-disable-line no-new +new GLForm($('.release-form')); // eslint-disable-line no-new |