diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-15 21:10:06 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-15 21:10:06 +0300 |
commit | b07852468f800d751ddecc9e327119d7295f538e (patch) | |
tree | d1169f95ea3725d609c796a1ca87d5766646852c /app | |
parent | 0ff373dc416216d02760c7c162ee23382eb1f4a3 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
13 files changed, 149 insertions, 20 deletions
diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js b/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js index 23f4190c2d0..4fcaa1b55fc 100644 --- a/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js +++ b/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js @@ -1,8 +1,11 @@ import axios from '~/lib/utils/axios_utils'; import createDefaultClient from '~/lib/graphql'; +import { s__ } from '~/locale'; +import createFlash from '~/flash'; import { STATUSES } from '../../constants'; import availableNamespacesQuery from './queries/available_namespaces.query.graphql'; import { SourceGroupsManager } from './services/source_groups_manager'; +import { StatusPoller } from './services/status_poller'; export const clientTypenames = { BulkImportSourceGroup: 'ClientBulkImportSourceGroup', @@ -10,6 +13,8 @@ export const clientTypenames = { }; export function createResolvers({ endpoints }) { + let statusPoller; + return { Query: { async bulkImportSourceGroups(_, __, { client }) { @@ -57,6 +62,30 @@ export function createResolvers({ endpoints }) { const groupManager = new SourceGroupsManager({ client }); const group = groupManager.findById(sourceGroupId); groupManager.setImportStatus(group, STATUSES.SCHEDULING); + try { + await axios.post(endpoints.createBulkImport, { + bulk_import: [ + { + source_type: 'group_entity', + source_full_path: group.full_path, + destination_namespace: group.import_target.target_namespace, + destination_name: group.import_target.new_name, + }, + ], + }); + groupManager.setImportStatus(group, STATUSES.STARTED); + if (!statusPoller) { + statusPoller = new StatusPoller({ client, interval: 3000 }); + statusPoller.startPolling(); + } + } catch (e) { + createFlash({ + message: s__('BulkImport|Importing the group failed'), + }); + + groupManager.setImportStatus(group, STATUSES.NONE); + throw e; + } }, }, }; diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js b/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js new file mode 100644 index 00000000000..5d2922b0ba8 --- /dev/null +++ b/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js @@ -0,0 +1,68 @@ +import gql from 'graphql-tag'; +import createFlash from '~/flash'; +import { s__ } from '~/locale'; +import bulkImportSourceGroupsQuery from '../queries/bulk_import_source_groups.query.graphql'; +import { STATUSES } from '../../../constants'; +import { SourceGroupsManager } from './source_groups_manager'; + +const groupId = i => `group${i}`; + +function generateGroupsQuery(groups) { + return gql`{ + ${groups + .map( + (g, idx) => + `${groupId(idx)}: group(fullPath: "${g.import_target.target_namespace}/${ + g.import_target.new_name + }") { id }`, + ) + .join('\n')} + }`; +} + +export class StatusPoller { + constructor({ client, interval }) { + this.client = client; + this.interval = interval; + this.timeoutId = null; + this.groupManager = new SourceGroupsManager({ client }); + } + + startPolling() { + if (this.timeoutId) { + return; + } + + this.checkPendingImports(); + } + + stopPolling() { + clearTimeout(this.timeoutId); + this.timeoutId = null; + } + + async checkPendingImports() { + try { + const { bulkImportSourceGroups } = this.client.readQuery({ + query: bulkImportSourceGroupsQuery, + }); + const groupsInProgress = bulkImportSourceGroups.filter(g => g.status === STATUSES.STARTED); + if (groupsInProgress.length) { + const { data: results } = await this.client.query({ + query: generateGroupsQuery(groupsInProgress), + fetchPolicy: 'no-cache', + }); + const completedGroups = groupsInProgress.filter((_, idx) => Boolean(results[groupId(idx)])); + completedGroups.forEach(group => { + this.groupManager.setImportStatus(group, STATUSES.FINISHED); + }); + } + } catch (e) { + createFlash({ + message: s__('BulkImport|Update of import statuses with realtime changes failed'), + }); + } finally { + this.timeoutId = setTimeout(() => this.checkPendingImports(), this.interval); + } + } +} diff --git a/app/assets/javascripts/lib/utils/keycodes.js b/app/assets/javascripts/lib/utils/keycodes.js index 618266f7a09..6f5cd7460f8 100644 --- a/app/assets/javascripts/lib/utils/keycodes.js +++ b/app/assets/javascripts/lib/utils/keycodes.js @@ -2,6 +2,7 @@ // See: https://gitlab.com/gitlab-org/gitlab/-/issues/216102 export const BACKSPACE_KEY_CODE = 8; +export const TAB_KEY_CODE = 9; export const ENTER_KEY_CODE = 13; export const ESC_KEY_CODE = 27; export const UP_KEY_CODE = 38; diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql index 149cb256ced..d65d9892260 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql @@ -1,11 +1,11 @@ -#import "~/pipelines/graphql/queries/pipeline_stages.fragment.graphql" +#import "~/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql" query getCiConfigData($content: String!) { ciConfig(content: $content) { errors status stages { - ...PipelineStagesData + ...PipelineStagesConnection } } } diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue index b1c52ffa920..8a57c9b1970 100644 --- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue +++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue @@ -10,6 +10,7 @@ import TextEditor from './components/text_editor.vue'; import commitCiFileMutation from './graphql/mutations/commit_ci_file.mutation.graphql'; import getBlobContent from './graphql/queries/blob_content.graphql'; import getCiConfigData from './graphql/queries/ci_config.graphql'; +import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils'; const MR_SOURCE_BRANCH = 'merge_request[source_branch]'; const MR_TARGET_BRANCH = 'merge_request[target_branch]'; @@ -99,7 +100,11 @@ export default { }; }, update(data) { - return data?.ciConfig ?? {}; + const { ciConfigData } = data || {}; + const stageNodes = ciConfigData?.stages?.nodes || []; + const stages = unwrapStagesWithNeeds(stageNodes); + + return { ...ciConfigData, stages }; }, error() { this.reportFailure(LOAD_FAILURE_UNKNOWN); diff --git a/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages.fragment.graphql b/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages.fragment.graphql deleted file mode 100644 index 0aef2fdfd7f..00000000000 --- a/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages.fragment.graphql +++ /dev/null @@ -1,12 +0,0 @@ -fragment PipelineStagesData on CiConfigStage { - name - groups { - name - jobs { - name - needs { - name - } - } - } -} diff --git a/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql b/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql new file mode 100644 index 00000000000..1da4fa0a72b --- /dev/null +++ b/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql @@ -0,0 +1,20 @@ +fragment PipelineStagesConnection on CiConfigStageConnection { + nodes { + name + groups { + nodes { + name + jobs { + nodes { + name + needs { + nodes { + name + } + } + } + } + } + } + } +} diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue index fb61c13983f..1ad0ca36bf8 100644 --- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue +++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue @@ -1,5 +1,5 @@ <script> -import Tribute from 'tributejs'; +import Tribute from '@gitlab/tributejs'; import { GfmAutocompleteType, tributeConfig, @@ -29,6 +29,10 @@ export default { config() { return this.autocompleteTypes.map(type => ({ ...tributeConfig[type].config, + loadingItemTemplate: `<span class="gl-spinner gl-vertical-align-text-bottom gl-ml-3 gl-mr-2"></span>${__( + 'Loading', + )}`, + requireLeadingSpace: true, values: this.getValues(type), })); }, diff --git a/app/models/ci/build_dependencies.rb b/app/models/ci/build_dependencies.rb index 2c6a9a63bdb..a6abeb517c1 100644 --- a/app/models/ci/build_dependencies.rb +++ b/app/models/ci/build_dependencies.rb @@ -143,7 +143,7 @@ module Ci def specified_cross_pipeline_dependencies strong_memoize(:specified_cross_pipeline_dependencies) do - next [] unless Feature.enabled?(:ci_cross_pipeline_artifacts_download, processable.project, default_enabled: false) + next [] unless Feature.enabled?(:ci_cross_pipeline_artifacts_download, processable.project, default_enabled: true) specified_cross_dependencies.select { |dep| dep[:pipeline] && dep[:artifacts] } end diff --git a/app/models/user.rb b/app/models/user.rb index f1c7644901a..c735f20b92c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1493,6 +1493,10 @@ class User < ApplicationRecord !solo_owned_groups.present? end + def can_remove_self? + true + end + def ci_owned_runners @ci_owned_runners ||= begin project_runners = Ci::RunnerProject diff --git a/app/services/jira/requests/base.rb b/app/services/jira/requests/base.rb index 4ed8df0f235..098aae9284c 100644 --- a/app/services/jira/requests/base.rb +++ b/app/services/jira/requests/base.rb @@ -18,14 +18,19 @@ module Jira request end + # We have to add the context_path here because the Jira client is not taking it into account def base_api_url - "/rest/api/#{api_version}" + "#{context_path}/rest/api/#{api_version}" end private attr_reader :jira_service, :project + def context_path + client.options[:context_path].to_s + end + # override this method in the specific request class implementation if a differnt API version is required def api_version JIRA_API_VERSION diff --git a/app/views/import/bulk_imports/status.html.haml b/app/views/import/bulk_imports/status.html.haml index 80b96a25ebb..6757c32d1e1 100644 --- a/app/views/import/bulk_imports/status.html.haml +++ b/app/views/import/bulk_imports/status.html.haml @@ -3,9 +3,9 @@ - breadcrumb_title _('Import groups') %h1.gl-my-0.gl-py-4.gl-font-size-h1.gl-border-solid.gl-border-gray-200.gl-border-0.gl-border-b-1 - = s_('ImportGroups|Import groups from GitLab') + = s_('BulkImport|Import groups from GitLab') %p.gl-my-0.gl-py-5.gl-border-solid.gl-border-gray-200.gl-border-0.gl-border-b-1 - = s_('ImportGroups|Importing groups from %{link}').html_safe % { link: external_link(@source_url, @source_url) } + = s_('BulkImport|Importing groups from %{link}').html_safe % { link: external_link(@source_url, @source_url) } #import-groups-mount-element{ data: { status_path: status_import_bulk_imports_path(format: :json), available_namespaces_path: import_available_namespaces_path(format: :json), diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index fe00420c86c..ca64c5f57b3 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -79,6 +79,11 @@ %strong= current_user.solo_owned_groups.map(&:name).join(', ') %p = s_('Profiles|You must transfer ownership or delete these groups before you can delete your account.') + - elsif !current_user.can_remove_self? + %p + = s_('Profiles|GitLab is unable to verify your identity automatically.') + %p + = s_('Profiles|Please email %{data_request} to begin the account deletion process.').html_safe % { data_request: mail_to('personal-data-request@gitlab.com') } - else %p = s_("Profiles|You don't have access to delete this user.") |