diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-19 15:12:07 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-19 15:12:07 +0300 |
commit | 6b19945915303e04fcca21405bca0cd94125199c (patch) | |
tree | 2ea89b55d5e419023bd25a19c5633fefa647dcfb /app | |
parent | 811f549164618e3607721eecbfd76e292555b339 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
27 files changed, 321 insertions, 62 deletions
diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js index f4a27dc7d1f..ae6e6bf02e4 100644 --- a/app/assets/javascripts/create_merge_request_dropdown.js +++ b/app/assets/javascripts/create_merge_request_dropdown.js @@ -54,6 +54,7 @@ export default class CreateMergeRequestDropdown { this.isCreatingBranch = false; this.isCreatingMergeRequest = false; this.isGettingRef = false; + this.refCancelToken = null; this.mergeRequestCreated = false; this.refDebounce = debounce((value, target) => this.getRef(value, target), 500); this.refIsValid = true; @@ -101,9 +102,18 @@ export default class CreateMergeRequestDropdown { 'click', this.onClickCreateMergeRequestButton.bind(this), ); + this.branchInput.addEventListener('input', this.onChangeInput.bind(this)); this.branchInput.addEventListener('keyup', this.onChangeInput.bind(this)); this.dropdownToggle.addEventListener('click', this.onClickSetFocusOnBranchNameInput.bind(this)); + // Detect for example when user pastes ref using the mouse + this.refInput.addEventListener('input', this.onChangeInput.bind(this)); + // Detect for example when user presses right arrow to apply the suggested ref this.refInput.addEventListener('keyup', this.onChangeInput.bind(this)); + // Detect when user clicks inside the input to apply the suggested ref + this.refInput.addEventListener('click', this.onChangeInput.bind(this)); + // Detect when user clicks outside the input to apply the suggested ref + this.refInput.addEventListener('blur', this.onChangeInput.bind(this)); + // Detect when user presses tab to apply the suggested ref this.refInput.addEventListener('keydown', CreateMergeRequestDropdown.processTab.bind(this)); } @@ -247,8 +257,12 @@ export default class CreateMergeRequestDropdown { getRef(ref, target = 'all') { if (!ref) return false; + this.refCancelToken = axios.CancelToken.source(); + return axios - .get(`${createEndpoint(this.projectPath, this.refsPath)}${encodeURIComponent(ref)}`) + .get(`${createEndpoint(this.projectPath, this.refsPath)}${encodeURIComponent(ref)}`, { + cancelToken: this.refCancelToken.token, + }) .then(({ data }) => { const branches = data[Object.keys(data)[0]]; const tags = data[Object.keys(data)[1]]; @@ -267,7 +281,10 @@ export default class CreateMergeRequestDropdown { return this.updateInputState(target, ref, result); }) - .catch(() => { + .catch((thrown) => { + if (axios.isCancel(thrown)) { + return false; + } this.unavailable(); this.disable(); createFlash({ @@ -325,14 +342,23 @@ export default class CreateMergeRequestDropdown { let target; let value; + // User changed input, cancel to prevent previous request from interfering + if (this.refCancelToken !== null) { + this.refCancelToken.cancel(); + } + if (event.target === this.branchInput) { target = 'branch'; ({ value } = this.branchInput); } else if (event.target === this.refInput) { target = 'ref'; - value = - event.target.value.slice(0, event.target.selectionStart) + - event.target.value.slice(event.target.selectionEnd); + if (event.target === document.activeElement) { + value = + event.target.value.slice(0, event.target.selectionStart) + + event.target.value.slice(event.target.selectionEnd); + } else { + value = event.target.value; + } } else { return false; } @@ -358,6 +384,7 @@ export default class CreateMergeRequestDropdown { this.enable(); this.showAvailableMessage(target); + this.refDebounce(value, target); return true; } @@ -414,7 +441,8 @@ export default class CreateMergeRequestDropdown { if (!selectedText || this.refInput.dataset.value === this.suggestedRef) return; event.preventDefault(); - window.getSelection().removeAllRanges(); + const caretPositionEnd = this.refInput.value.length; + this.refInput.setSelectionRange(caretPositionEnd, caretPositionEnd); } removeMessage(target) { diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 465f9836140..cf0d2814136 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -392,8 +392,6 @@ export default { diffsApp.instrument(); }, created() { - this.mergeRequestContainers = document.querySelectorAll('.merge-request-container'); - this.adjustView(); this.subscribeToEvents(); @@ -521,13 +519,6 @@ export default { } else { this.removeEventListeners(); } - - if (!this.isFluidLayout && this.glFeatures.mrChangesFluidLayout) { - this.mergeRequestContainers.forEach((el) => { - el.classList.toggle('limit-container-width', !this.shouldShow); - el.classList.toggle('container-limited', !this.shouldShow); - }); - } }, setEventListeners() { Mousetrap.bind(keysFor(MR_PREVIOUS_FILE_IN_DIFF), () => this.jumpToFile(-1)); diff --git a/app/assets/javascripts/pages/projects/work_items/index/index.js b/app/assets/javascripts/pages/projects/work_items/index.js index 11c257611f0..11c257611f0 100644 --- a/app/assets/javascripts/pages/projects/work_items/index/index.js +++ b/app/assets/javascripts/pages/projects/work_items/index.js diff --git a/app/assets/javascripts/project_visibility.js b/app/assets/javascripts/project_visibility.js index e3868e2925d..1b57a69d464 100644 --- a/app/assets/javascripts/project_visibility.js +++ b/app/assets/javascripts/project_visibility.js @@ -1,42 +1,58 @@ import $ from 'jquery'; +import eventHub from '~/projects/new/event_hub'; -function setVisibilityOptions(namespaceSelector) { - if (!namespaceSelector || !('selectedIndex' in namespaceSelector)) { - return; - } - const selectedNamespace = namespaceSelector.options[namespaceSelector.selectedIndex]; - const { name, visibility, visibilityLevel, showPath, editPath } = selectedNamespace.dataset; +// Values are from lib/gitlab/visibility_level.rb +const visibilityLevel = { + private: 0, + internal: 10, + public: 20, +}; +function setVisibilityOptions({ name, visibility, showPath, editPath }) { document.querySelectorAll('.visibility-level-setting .form-check').forEach((option) => { + // Don't change anything if the option is restricted by admin + if (option.classList.contains('restricted')) { + return; + } + const optionInput = option.querySelector('input[type=radio]'); - const optionValue = optionInput ? optionInput.value : 0; - const optionTitle = option.querySelector('.option-title'); - const optionName = optionTitle ? optionTitle.innerText.toLowerCase() : ''; + const optionValue = optionInput ? parseInt(optionInput.value, 10) : 0; - // don't change anything if the option is restricted by admin - if (!option.classList.contains('restricted')) { - if (visibilityLevel < optionValue) { - option.classList.add('disabled'); - optionInput.disabled = true; - const reason = option.querySelector('.option-disabled-reason'); - if (reason) { - reason.innerHTML = `This project cannot be ${optionName} because the visibility of + if (visibilityLevel[visibility] < optionValue) { + option.classList.add('disabled'); + optionInput.disabled = true; + const reason = option.querySelector('.option-disabled-reason'); + if (reason) { + const optionTitle = option.querySelector('.option-title'); + const optionName = optionTitle ? optionTitle.innerText.toLowerCase() : ''; + reason.innerHTML = `This project cannot be ${optionName} because the visibility of <a href="${showPath}">${name}</a> is ${visibility}. To make this project ${optionName}, you must first <a href="${editPath}">change the visibility</a> of the parent group.`; - } - } else { - option.classList.remove('disabled'); - optionInput.disabled = false; } + } else { + option.classList.remove('disabled'); + optionInput.disabled = false; } }); } +function handleSelect2DropdownChange(namespaceSelector) { + if (!namespaceSelector || !('selectedIndex' in namespaceSelector)) { + return; + } + const selectedNamespace = namespaceSelector.options[namespaceSelector.selectedIndex]; + setVisibilityOptions(selectedNamespace.dataset); +} + export default function initProjectVisibilitySelector() { + eventHub.$on('update-visibility', setVisibilityOptions); + const namespaceSelector = document.querySelector('select.js-select-namespace'); if (namespaceSelector) { - $('.select2.js-select-namespace').on('change', () => setVisibilityOptions(namespaceSelector)); - setVisibilityOptions(namespaceSelector); + $('.select2.js-select-namespace').on('change', () => + handleSelect2DropdownChange(namespaceSelector), + ); + handleSelect2DropdownChange(namespaceSelector); } } diff --git a/app/assets/javascripts/projects/new/components/new_project_url_select.vue b/app/assets/javascripts/projects/new/components/new_project_url_select.vue index bf44ff70562..e0ba60074af 100644 --- a/app/assets/javascripts/projects/new/components/new_project_url_select.vue +++ b/app/assets/javascripts/projects/new/components/new_project_url_select.vue @@ -6,9 +6,9 @@ import { GlDropdownItem, GlDropdownText, GlDropdownSectionHeader, - GlLoadingIcon, GlSearchBoxByType, } from '@gitlab/ui'; +import { joinPaths } from '~/lib/utils/url_utility'; import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import Tracking from '~/tracking'; @@ -24,7 +24,6 @@ export default { GlDropdownItem, GlDropdownText, GlDropdownSectionHeader, - GlLoadingIcon, GlSearchBoxByType, }, mixins: [Tracking.mixin()], @@ -103,6 +102,15 @@ export default { focusInput() { this.$refs.search.focusInput(); }, + handleDropdownItemClick(namespace) { + eventHub.$emit('update-visibility', { + name: namespace.name, + visibility: namespace.visibility, + showPath: namespace.webUrl, + editPath: joinPaths(namespace.webUrl, '-', 'edit'), + }); + this.setNamespace(namespace); + }, handleSelectTemplate(groupId) { this.groupToFilterBy = this.userGroups.find( (group) => getIdFromGraphQLId(group.id) === groupId, @@ -134,23 +142,23 @@ export default { <gl-search-box-by-type ref="search" v-model.trim="search" + :is-loading="$apollo.queries.currentUser.loading" data-qa-selector="select_namespace_dropdown_search_field" /> - <gl-loading-icon v-if="$apollo.queries.currentUser.loading" /> - <template v-else> + <template v-if="!$apollo.queries.currentUser.loading"> <template v-if="hasGroupMatches"> <gl-dropdown-section-header>{{ __('Groups') }}</gl-dropdown-section-header> <gl-dropdown-item v-for="group of filteredGroups" :key="group.id" - @click="setNamespace(group)" + @click="handleDropdownItemClick(group)" > {{ group.fullPath }} </gl-dropdown-item> </template> <template v-if="hasNamespaceMatches"> <gl-dropdown-section-header>{{ __('Users') }}</gl-dropdown-section-header> - <gl-dropdown-item @click="setNamespace(userNamespace)"> + <gl-dropdown-item @click="handleDropdownItemClick(userNamespace)"> {{ userNamespace.fullPath }} </gl-dropdown-item> </template> @@ -158,6 +166,11 @@ export default { </template> </gl-dropdown> - <input type="hidden" name="project[namespace_id]" :value="selectedNamespace.id" /> + <input + id="project_namespace_id" + type="hidden" + name="project[namespace_id]" + :value="selectedNamespace.id" + /> </gl-button-group> </template> diff --git a/app/assets/javascripts/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql b/app/assets/javascripts/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql index e16fe5dde49..74febec5a51 100644 --- a/app/assets/javascripts/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql +++ b/app/assets/javascripts/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql @@ -4,6 +4,9 @@ query searchNamespacesWhereUserCanCreateProjects($search: String) { nodes { id fullPath + name + visibility + webUrl } } namespace { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js index 562ff154001..0ea22eb7aea 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js @@ -69,8 +69,7 @@ export default { if (isScopedLabel(candidateLabel)) { const scopedKeyWithDelimiter = `${scopedLabelKey(candidateLabel)}${SCOPED_LABEL_DELIMITER}`; const currentActiveScopedLabel = state.labels.find( - ({ set, title }) => - set && title.startsWith(scopedKeyWithDelimiter) && title !== candidateLabel.title, + ({ title }) => title.startsWith(scopedKeyWithDelimiter) && title !== candidateLabel.title, ); if (currentActiveScopedLabel) { diff --git a/app/assets/javascripts/work_items/components/app.vue b/app/assets/javascripts/work_items/components/app.vue index 93de17d1e43..a14d0c32cbe 100644 --- a/app/assets/javascripts/work_items/components/app.vue +++ b/app/assets/javascripts/work_items/components/app.vue @@ -1,9 +1,5 @@ -<script> -export default { - name: 'WorkItemRoot', -}; -</script> - <template> - <div></div> + <div> + <router-view /> + </div> </template> diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js new file mode 100644 index 00000000000..b39f68abf74 --- /dev/null +++ b/app/assets/javascripts/work_items/constants.js @@ -0,0 +1,3 @@ +export const widgetTypes = { + title: 'TITLE', +}; diff --git a/app/assets/javascripts/work_items/graphql/fragmentTypes.json b/app/assets/javascripts/work_items/graphql/fragmentTypes.json new file mode 100644 index 00000000000..c048ac34ac0 --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/fragmentTypes.json @@ -0,0 +1 @@ +{"__schema":{"types":[{"kind":"INTERFACE","name":"WorkItemWidget","possibleTypes":[{"name":"TitleWidget"}]}]}} diff --git a/app/assets/javascripts/work_items/graphql/provider.js b/app/assets/javascripts/work_items/graphql/provider.js new file mode 100644 index 00000000000..dae663433a6 --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/provider.js @@ -0,0 +1,54 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; +import createDefaultClient from '~/lib/graphql'; +import workItemQuery from './work_item.query.graphql'; +import introspectionQueryResultData from './fragmentTypes.json'; + +const fragmentMatcher = new IntrospectionFragmentMatcher({ + introspectionQueryResultData, +}); + +export function createApolloProvider() { + Vue.use(VueApollo); + + const defaultClient = createDefaultClient( + {}, + { + cacheConfig: { + fragmentMatcher, + }, + assumeImmutableResults: true, + }, + ); + + defaultClient.cache.writeQuery({ + query: workItemQuery, + variables: { + id: '1', + }, + data: { + workItem: { + __typename: 'WorkItem', + id: '1', + type: 'FEATURE', + widgets: { + __typename: 'WorkItemWidgetConnection', + nodes: [ + { + __typename: 'TitleWidget', + type: 'TITLE', + enabled: true, + // eslint-disable-next-line @gitlab/require-i18n-strings + contentText: 'Test', + }, + ], + }, + }, + }, + }); + + return new VueApollo({ + defaultClient, + }); +} diff --git a/app/assets/javascripts/work_items/graphql/resolvers.js b/app/assets/javascripts/work_items/graphql/resolvers.js new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/resolvers.js diff --git a/app/assets/javascripts/work_items/graphql/typedefs.graphql b/app/assets/javascripts/work_items/graphql/typedefs.graphql index e69de29bb2d..4a6e4aeed60 100644 --- a/app/assets/javascripts/work_items/graphql/typedefs.graphql +++ b/app/assets/javascripts/work_items/graphql/typedefs.graphql @@ -0,0 +1,38 @@ +enum WorkItemType { + FEATURE +} + +enum WidgetType { + TITLE +} + +interface WorkItemWidget { + type: WidgetType! +} + +# Replicating Relay connection type for client schema +type WorkItemWidgetEdge { + cursor: String! + node: WorkItemWidget +} + +type WorkItemWidgetConnection { + edges: [WorkItemWidgetEdge] + nodes: [WorkItemWidget] + pageInfo: PageInfo! +} + +type TitleWidget implements WorkItemWidget { + type: WidgetType! + contentText: String! +} + +type WorkItem { + id: ID! + type: WorkItemType! + widgets: [WorkItemWidgetConnection] +} + +extend type Query { + workItem(id: ID!): WorkItem! +} diff --git a/app/assets/javascripts/work_items/graphql/widget.fragment.graphql b/app/assets/javascripts/work_items/graphql/widget.fragment.graphql new file mode 100644 index 00000000000..d7608c26052 --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/widget.fragment.graphql @@ -0,0 +1,3 @@ +fragment WidgetBase on WorkItemWidget { + type +} diff --git a/app/assets/javascripts/work_items/graphql/work_item.query.graphql b/app/assets/javascripts/work_items/graphql/work_item.query.graphql new file mode 100644 index 00000000000..549e4f8c65a --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/work_item.query.graphql @@ -0,0 +1,16 @@ +#import './widget.fragment.graphql' + +query WorkItem($id: ID!) { + workItem(id: $id) @client { + id + type + widgets { + nodes { + ...WidgetBase + ... on TitleWidget { + contentText + } + } + } + } +} diff --git a/app/assets/javascripts/work_items/index.js b/app/assets/javascripts/work_items/index.js index a635d43776d..7cc8a23b7b1 100644 --- a/app/assets/javascripts/work_items/index.js +++ b/app/assets/javascripts/work_items/index.js @@ -1,11 +1,15 @@ import Vue from 'vue'; import App from './components/app.vue'; +import { createRouter } from './router'; +import { createApolloProvider } from './graphql/provider'; export const initWorkItemsRoot = () => { const el = document.querySelector('#js-work-items'); return new Vue({ el, + router: createRouter(el.dataset.fullPath), + apolloProvider: createApolloProvider(), render(createElement) { return createElement(App); }, diff --git a/app/assets/javascripts/work_items/pages/work_item_root.vue b/app/assets/javascripts/work_items/pages/work_item_root.vue new file mode 100644 index 00000000000..e2ae15e0c7c --- /dev/null +++ b/app/assets/javascripts/work_items/pages/work_item_root.vue @@ -0,0 +1,44 @@ +<script> +import workItemQuery from '../graphql/work_item.query.graphql'; +import { widgetTypes } from '../constants'; + +export default { + props: { + id: { + type: String, + required: true, + }, + }, + data() { + return { + workItem: null, + }; + }, + apollo: { + workItem: { + query: workItemQuery, + variables() { + return { + id: this.id, + }; + }, + }, + }, + computed: { + titleWidgetData() { + return this.workItem?.widgets?.nodes?.find((widget) => widget.type === widgetTypes.title); + }, + }, +}; +</script> + +<template> + <section> + <!-- Title widget placeholder --> + <div> + <h2 v-if="titleWidgetData" class="title" data-testid="title"> + {{ titleWidgetData.contentText }} + </h2> + </div> + </section> +</template> diff --git a/app/assets/javascripts/work_items/router/index.js b/app/assets/javascripts/work_items/router/index.js new file mode 100644 index 00000000000..142fab8cfa6 --- /dev/null +++ b/app/assets/javascripts/work_items/router/index.js @@ -0,0 +1,14 @@ +import Vue from 'vue'; +import VueRouter from 'vue-router'; +import { joinPaths } from '~/lib/utils/url_utility'; +import { routes } from './routes'; + +Vue.use(VueRouter); + +export function createRouter(fullPath) { + return new VueRouter({ + routes, + mode: 'history', + base: joinPaths(fullPath, '-', 'work_items'), + }); +} diff --git a/app/assets/javascripts/work_items/router/routes.js b/app/assets/javascripts/work_items/router/routes.js new file mode 100644 index 00000000000..a3cf44ad4ca --- /dev/null +++ b/app/assets/javascripts/work_items/router/routes.js @@ -0,0 +1,8 @@ +export const routes = [ + { + path: '/:id', + name: 'work_item', + component: () => import('../pages/work_item_root.vue'), + props: true, + }, +]; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b22167a3952..3af1afab06e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -163,7 +163,8 @@ class ApplicationController < ActionController::Base payload[Labkit::Correlation::CorrelationId::LOG_KEY] = Labkit::Correlation::CorrelationId.current_id payload[:metadata] = @current_context - + payload[:request_urgency] = urgency&.name + payload[:target_duration_s] = urgency&.duration logged_user = auth_user if logged_user.present? payload[:user_id] = logged_user.try(:id) diff --git a/app/controllers/concerns/workhorse_authorization.rb b/app/controllers/concerns/workhorse_authorization.rb index a290ba256b6..648e6f409e6 100644 --- a/app/controllers/concerns/workhorse_authorization.rb +++ b/app/controllers/concerns/workhorse_authorization.rb @@ -38,6 +38,6 @@ module WorkhorseAuthorization end def file_extension_whitelist - ImportExportUploader::EXTENSION_WHITELIST + ImportExportUploader::EXTENSION_ALLOWLIST end end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 0041ec5135c..ef25ced8610 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -780,6 +780,10 @@ module Ci strong_memoize(:legacy_trigger) { trigger_requests.first } end + def variables_builder + @variables_builder ||= ::Gitlab::Ci::Variables::Builder.new(self) + end + def persisted_variables Gitlab::Ci::Variables::Collection.new.tap do |variables| break variables unless persisted? @@ -1254,6 +1258,12 @@ module Ci self.builds.latest.build_matchers(project) end + def predefined_vars_in_builder_enabled? + strong_memoize(:predefined_vars_in_builder_enabled) do + Feature.enabled?(:ci_predefined_vars_in_builder, project, default_enabled: :yaml) + end + end + private def add_message(severity, content) diff --git a/app/models/concerns/ci/contextable.rb b/app/models/concerns/ci/contextable.rb index 27a704c1de0..6871482f71d 100644 --- a/app/models/concerns/ci/contextable.rb +++ b/app/models/concerns/ci/contextable.rb @@ -10,8 +10,10 @@ module Ci # Variables in the environment name scope. # def scoped_variables(environment: expanded_environment_name, dependencies: true) - Gitlab::Ci::Variables::Collection.new.tap do |variables| - variables.concat(predefined_variables) + track_duration do + variables = pipeline.variables_builder.scoped_variables(self, environment: environment, dependencies: dependencies) + + variables.concat(predefined_variables) unless pipeline.predefined_vars_in_builder_enabled? variables.concat(project.predefined_variables) variables.concat(pipeline.predefined_variables) variables.concat(runner.predefined_variables) if runnable? && runner @@ -25,9 +27,23 @@ module Ci variables.concat(trigger_request.user_variables) if trigger_request variables.concat(pipeline.variables) variables.concat(pipeline.pipeline_schedule.job_variables) if pipeline.pipeline_schedule + + variables end end + def track_duration + start_time = ::Gitlab::Metrics::System.monotonic_time + result = yield + duration = ::Gitlab::Metrics::System.monotonic_time - start_time + + ::Gitlab::Ci::Pipeline::Metrics + .pipeline_builder_scoped_variables_histogram + .observe({}, duration.seconds) + + result + end + ## # Variables that do not depend on the environment name. # diff --git a/app/uploaders/bulk_imports/export_uploader.rb b/app/uploaders/bulk_imports/export_uploader.rb index 356e5ce028e..cd6e599054b 100644 --- a/app/uploaders/bulk_imports/export_uploader.rb +++ b/app/uploaders/bulk_imports/export_uploader.rb @@ -2,6 +2,6 @@ module BulkImports class ExportUploader < ImportExportUploader - EXTENSION_WHITELIST = %w[ndjson.gz].freeze + EXTENSION_ALLOWLIST = %w[ndjson.gz].freeze end end diff --git a/app/uploaders/import_export_uploader.rb b/app/uploaders/import_export_uploader.rb index 369afba2bae..7b161d72efb 100644 --- a/app/uploaders/import_export_uploader.rb +++ b/app/uploaders/import_export_uploader.rb @@ -1,14 +1,14 @@ # frozen_string_literal: true class ImportExportUploader < AttachmentUploader - EXTENSION_WHITELIST = %w[tar.gz gz].freeze + EXTENSION_ALLOWLIST = %w[tar.gz gz].freeze def self.workhorse_local_upload_path File.join(options.storage_path, 'uploads', TMP_UPLOAD_PATH) end def extension_whitelist - EXTENSION_WHITELIST + EXTENSION_ALLOWLIST end def move_to_cache diff --git a/app/views/projects/work_items/index.html.haml b/app/views/projects/work_items/index.html.haml index 052db598571..0efd7a740d3 100644 --- a/app/views/projects/work_items/index.html.haml +++ b/app/views/projects/work_items/index.html.haml @@ -1,3 +1,3 @@ - page_title s_('WorkItem|Work Items') -#js-work-items +#js-work-items{ data: { full_path: @project.full_path } } diff --git a/app/views/shared/_visibility_radios.html.haml b/app/views/shared/_visibility_radios.html.haml index f48bfcd0e72..760fe18ddec 100644 --- a/app/views/shared/_visibility_radios.html.haml +++ b/app/views/shared/_visibility_radios.html.haml @@ -10,6 +10,7 @@ = visibility_level_label(level) .option-description = visibility_level_description(level, form_model) + .option-disabled-reason .text-muted - if all_visibility_levels_restricted? |