From cace5e8ff1f766b8098e35adc94abc4402aeb2a9 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 18 Oct 2022 21:09:37 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../javascripts/graphql_shared/issuable_client.js | 26 +++ app/assets/javascripts/groups/components/app.vue | 8 +- .../javascripts/groups/components/groups.vue | 20 +- .../groups/components/overview_tabs.vue | 17 +- app/assets/javascripts/groups/constants.js | 2 - app/assets/javascripts/ide/index.js | 4 +- app/assets/javascripts/ide/init_gitlab_web_ide.js | 3 +- .../new_user_map/components/user_select.vue | 95 ++++++++ .../pages/import/fogbugz/new_user_map/index.js | 20 +- .../sidebar/components/sidebar_dropdown_widget.vue | 6 +- app/assets/javascripts/sidebar/constants.js | 7 + app/assets/javascripts/users_select/index.js | 3 +- .../components/extensions/telemetry.js | 2 +- .../webhooks/components/form_url_app.vue | 73 +++++- .../webhooks/components/form_url_mask_item.vue | 37 ++- app/assets/javascripts/webhooks/index.js | 9 +- .../work_items/components/work_item_detail.vue | 17 ++ .../work_items/components/work_item_milestone.vue | 248 +++++++++++++++++++++ app/assets/javascripts/work_items/constants.js | 1 + .../work_items/graphql/typedefs.graphql | 15 ++ .../work_items/graphql/work_item.query.graphql | 11 + .../stylesheets/page_bundles/work_items.scss | 3 +- app/controllers/ide_controller.rb | 3 +- app/controllers/profiles/preferences_controller.rb | 3 +- app/graphql/types/environment_type.rb | 2 +- app/helpers/hooks_helper.rb | 7 + app/helpers/ide_helper.rb | 32 ++- app/models/application_setting.rb | 7 + app/models/ci/pipeline.rb | 6 +- .../clusters/agents/implicit_authorization.rb | 2 +- app/models/user.rb | 1 + app/models/user_preference.rb | 1 + app/presenters/ci/build_runner_presenter.rb | 4 +- .../bulk_imports/uploads_export_service.rb | 5 +- app/services/ci/generate_kubeconfig_service.rb | 12 +- .../_account_and_limit.html.haml | 6 +- app/views/import/fogbugz/new_user_map.html.haml | 30 ++- app/views/shared/web_hooks/_form.html.haml | 2 +- 38 files changed, 666 insertions(+), 84 deletions(-) create mode 100644 app/assets/javascripts/pages/import/fogbugz/new_user_map/components/user_select.vue create mode 100644 app/assets/javascripts/work_items/components/work_item_milestone.vue (limited to 'app') diff --git a/app/assets/javascripts/graphql_shared/issuable_client.js b/app/assets/javascripts/graphql_shared/issuable_client.js index 3849bd0289d..3b737dfff33 100644 --- a/app/assets/javascripts/graphql_shared/issuable_client.js +++ b/app/assets/javascripts/graphql_shared/issuable_client.js @@ -4,10 +4,14 @@ import { concatPagination } from '@apollo/client/utilities'; import getIssueStateQuery from '~/issues/show/queries/get_issue_state.query.graphql'; import createDefaultClient from '~/lib/graphql'; import typeDefs from '~/work_items/graphql/typedefs.graphql'; +import { WIDGET_TYPE_MILESTONE } from '~/work_items/constants'; export const temporaryConfig = { typeDefs, cacheConfig: { + possibleTypes: { + LocalWorkItemWidget: ['LocalWorkItemMilestone'], + }, typePolicies: { Project: { fields: { @@ -18,6 +22,28 @@ export const temporaryConfig = { }, WorkItem: { fields: { + mockWidgets: { + read(widgets) { + return ( + widgets || [ + { + __typename: 'LocalWorkItemMilestone', + type: WIDGET_TYPE_MILESTONE, + nodes: [ + { + dueDate: null, + expired: false, + id: 'gid://gitlab/Milestone/30', + title: 'v4.0', + // eslint-disable-next-line @gitlab/require-i18n-strings + __typename: 'Milestone', + }, + ], + }, + ] + ); + }, + }, widgets: { merge(existing = [], incoming) { if (existing.length === 0) { diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue index d74cb2d8175..15f5a3518a5 100644 --- a/app/assets/javascripts/groups/components/app.vue +++ b/app/assets/javascripts/groups/components/app.vue @@ -51,7 +51,6 @@ export default { isModalVisible: false, isLoading: true, isSearchEmpty: false, - searchEmptyMessage: '', targetGroup: null, targetParentGroup: null, showEmptyState: false, @@ -88,10 +87,6 @@ export default { }, }, created() { - this.searchEmptyMessage = this.hideProjects - ? COMMON_STR.GROUP_SEARCH_EMPTY - : COMMON_STR.GROUP_PROJECT_SEARCH_EMPTY; - eventHub.$on(`${this.action}fetchPage`, this.fetchPage); eventHub.$on(`${this.action}toggleChildren`, this.toggleChildren); eventHub.$on(`${this.action}showLeaveGroupModal`, this.showLeaveGroupModal); @@ -259,7 +254,7 @@ export default { const hasGroups = groups && groups.length > 0; if (this.renderEmptyState) { - this.isSearchEmpty = this.filterGroupsBy !== null && !hasGroups; + this.isSearchEmpty = fromSearch && !hasGroups; } else { this.isSearchEmpty = !hasGroups; } @@ -294,7 +289,6 @@ export default { v-else :groups="groups" :search-empty="isSearchEmpty" - :search-empty-message="searchEmptyMessage" :page-info="pageInfo" :action="action" /> diff --git a/app/assets/javascripts/groups/components/groups.vue b/app/assets/javascripts/groups/components/groups.vue index 3a05c308a2a..43aa0753082 100644 --- a/app/assets/javascripts/groups/components/groups.vue +++ b/app/assets/javascripts/groups/components/groups.vue @@ -1,11 +1,18 @@ + diff --git a/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js b/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js index 86b80a0ba5b..ef549f20cf3 100644 --- a/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js +++ b/app/assets/javascripts/pages/import/fogbugz/new_user_map/index.js @@ -1,3 +1,19 @@ -import UsersSelect from '~/users_select'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import UserSelect from './components/user_select.vue'; -new UsersSelect(); // eslint-disable-line no-new +Vue.use(VueApollo); + +const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), +}); + +Array.from(document.querySelectorAll('.js-gitlab-user')).forEach( + (node) => + new Vue({ + el: node, + apolloProvider, + render: (h) => h(UserSelect, { props: { name: node.dataset.name } }), + }), +); diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue index 7126d69c8c6..c33b1468ca4 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue @@ -25,6 +25,8 @@ import { Tracking, IssuableAttributeState, IssuableAttributeType, + LocalizedIssuableAttributeType, + IssuableAttributeTypeKeyMap, issuableAttributesQueries, noAttributeId, defaultEpicSort, @@ -229,7 +231,9 @@ export default { return timeFor(this.currentAttribute?.dueDate); }, i18n() { - return dropdowni18nText(this.issuableAttribute, this.issuableType); + const localizedAttribute = + LocalizedIssuableAttributeType[IssuableAttributeTypeKeyMap[this.issuableAttribute]]; + return dropdowni18nText(localizedAttribute, this.issuableType); }, isEpic() { // MV to EE https://gitlab.com/gitlab-org/gitlab/-/issues/345311 diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js index 60cb4cff727..6248bcb8e2d 100644 --- a/app/assets/javascripts/sidebar/constants.js +++ b/app/assets/javascripts/sidebar/constants.js @@ -1,3 +1,4 @@ +import { invert } from 'lodash'; import { s__, __, sprintf } from '~/locale'; import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql'; import userSearchQuery from '~/graphql_shared/queries/users_search.query.graphql'; @@ -251,6 +252,12 @@ export const IssuableAttributeType = { Milestone: 'milestone', }; +export const LocalizedIssuableAttributeType = { + Milestone: s__('Issuable|milestone'), +}; + +export const IssuableAttributeTypeKeyMap = invert(IssuableAttributeType); + export const IssuableAttributeState = { [IssuableAttributeType.Milestone]: 'active', }; diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js index 5963568a00b..bd425bdc2a8 100644 --- a/app/assets/javascripts/users_select/index.js +++ b/app/assets/javascripts/users_select/index.js @@ -819,13 +819,14 @@ UsersSelect.prototype.renderRow = function ( const tooltipAttributes = tooltip ? `data-container="body" data-placement="left" data-title="${tooltip}"` : ''; + const dataUserSuggested = user.suggested ? `data-user-suggested=${user.suggested}` : ''; const name = user?.availability && isUserBusy(user.availability) ? sprintf(__('%{name} (Busy)'), { name: user.name }) : user.name; return ` -
  • +
  • ${this.renderRowAvatar(issuableType, user, img)} diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js index d67ff11f297..e3f87c08ad4 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/telemetry.js @@ -28,7 +28,7 @@ const nonStandardEvents = { }, counter: {}, }, - testReport: { + testSummary: { uniqueUser: { expand: ['i_testing_summary_widget_total'], }, diff --git a/app/assets/javascripts/webhooks/components/form_url_app.vue b/app/assets/javascripts/webhooks/components/form_url_app.vue index 62d6c03bbb3..5ec16d4ba15 100644 --- a/app/assets/javascripts/webhooks/components/form_url_app.vue +++ b/app/assets/javascripts/webhooks/components/form_url_app.vue @@ -1,5 +1,6 @@ diff --git a/app/assets/javascripts/webhooks/index.js b/app/assets/javascripts/webhooks/index.js index bfa33560fa5..1b2b33e44c1 100644 --- a/app/assets/javascripts/webhooks/index.js +++ b/app/assets/javascripts/webhooks/index.js @@ -8,11 +8,18 @@ export default () => { return null; } + const { url: initialUrl, urlVariables } = el.dataset; + return new Vue({ el, name: 'WebhookFormRoot', render(createElement) { - return createElement(FormUrlApp, {}); + return createElement(FormUrlApp, { + props: { + initialUrl, + initialUrlVariables: urlVariables ? JSON.parse(urlVariables) : undefined, + }, + }); }, }); }; diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index cf0aafc2eb0..af9b8c6101a 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -23,6 +23,7 @@ import { WIDGET_TYPE_WEIGHT, WIDGET_TYPE_HIERARCHY, WORK_ITEM_VIEWED_STORAGE_KEY, + WIDGET_TYPE_MILESTONE, WIDGET_TYPE_ITERATION, } from '../constants'; @@ -40,6 +41,7 @@ import WorkItemDescription from './work_item_description.vue'; import WorkItemDueDate from './work_item_due_date.vue'; import WorkItemAssignees from './work_item_assignees.vue'; import WorkItemLabels from './work_item_labels.vue'; +import WorkItemMilestone from './work_item_milestone.vue'; import WorkItemInformation from './work_item_information.vue'; export default { @@ -67,6 +69,7 @@ export default { LocalStorageSync, WorkItemTypeIcon, WorkItemIteration: () => import('ee_component/work_items/components/work_item_iteration.vue'), + WorkItemMilestone, }, mixins: [glFeatureFlagMixin()], props: { @@ -208,6 +211,9 @@ export default { workItemIteration() { return this.isWidgetPresent(WIDGET_TYPE_ITERATION); }, + workItemMilestone() { + return this.workItem?.mockWidgets?.find((widget) => widget.type === WIDGET_TYPE_MILESTONE); + }, }, beforeDestroy() { /** make sure that if the user has not even dismissed the alert , @@ -411,6 +417,17 @@ export default { :work-item-type="workItemType" @error="updateError = $event" /> + +import { + GlFormGroup, + GlDropdown, + GlDropdownItem, + GlDropdownDivider, + GlSkeletonLoader, + GlSearchBoxByType, + GlDropdownText, +} from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; +import { debounce } from 'lodash'; +import Tracking from '~/tracking'; +import { s__ } from '~/locale'; +import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; +import projectMilestonesQuery from '~/sidebar/queries/project_milestones.query.graphql'; +import localUpdateWorkItemMutation from '../graphql/local_update_work_item.mutation.graphql'; +import { + I18N_WORK_ITEM_ERROR_UPDATING, + sprintfWorkItem, + TRACKING_CATEGORY_SHOW, +} from '../constants'; + +const noMilestoneId = 'no-milestone-id'; + +export default { + i18n: { + MILESTONE: s__('WorkItem|Milestone'), + NONE: s__('WorkItem|None'), + MILESTONE_PLACEHOLDER: s__('WorkItem|Add to milestone'), + NO_MATCHING_RESULTS: s__('WorkItem|No matching results'), + NO_MILESTONE: s__('WorkItem|No milestone'), + MILESTONE_FETCH_ERROR: s__( + 'WorkItem|Something went wrong while fetching milestones. Please try again.', + ), + }, + components: { + GlFormGroup, + GlDropdown, + GlDropdownItem, + GlDropdownDivider, + GlSkeletonLoader, + GlSearchBoxByType, + GlDropdownText, + }, + mixins: [Tracking.mixin()], + props: { + workItemId: { + type: String, + required: true, + }, + workItemMilestone: { + type: Object, + required: false, + default: () => {}, + }, + workItemType: { + type: String, + required: false, + default: '', + }, + canUpdate: { + type: Boolean, + required: false, + default: false, + }, + fullPath: { + type: String, + required: true, + }, + }, + data() { + return { + localMilestone: this.workItemMilestone, + searchTerm: '', + shouldFetch: false, + updateInProgress: false, + isFocused: false, + milestones: [], + }; + }, + computed: { + tracking() { + return { + category: TRACKING_CATEGORY_SHOW, + label: 'item_milestone', + property: `type_${this.workItemType}`, + }; + }, + emptyPlaceholder() { + return this.canUpdate ? this.$options.i18n.MILESTONE_PLACEHOLDER : this.$options.i18n.NONE; + }, + dropdownText() { + return this.localMilestone?.title || this.emptyPlaceholder; + }, + isLoadingMilestones() { + return this.$apollo.queries.milestones.loading; + }, + isNoMilestone() { + return this.localMilestone?.id === noMilestoneId || !this.localMilestone?.id; + }, + dropdownClasses() { + return { + 'gl-text-gray-500!': this.canUpdate && this.isNoMilestone, + 'is-not-focused': !this.isFocused, + }; + }, + }, + created() { + this.debouncedSearchKeyUpdate = debounce(this.setSearchKey, DEFAULT_DEBOUNCE_AND_THROTTLE_MS); + }, + apollo: { + milestones: { + query: projectMilestonesQuery, + variables() { + return { + fullPath: this.fullPath, + title: this.searchTerm, + first: 20, + }; + }, + skip() { + return !this.shouldFetch; + }, + update(data) { + return data?.workspace?.attributes?.nodes || []; + }, + error() { + this.$emit('error', this.i18n.MILESTONE_FETCH_ERROR); + }, + }, + }, + methods: { + handleMilestoneClick(milestone) { + this.localMilestone = milestone; + }, + onDropdownShown() { + this.$refs.search.focusInput(); + this.shouldFetch = true; + this.isFocused = true; + }, + onDropdownHide() { + this.isFocused = false; + this.searchTerm = ''; + this.shouldFetch = false; + this.updateMilestone(); + }, + setSearchKey(value) { + this.searchTerm = value; + }, + isMilestoneChecked(milestone) { + return this.localMilestone?.id === milestone?.id; + }, + updateMilestone() { + if (this.workItemMilestone?.id === this.localMilestone?.id) { + return; + } + + this.track('updated_milestone'); + this.updateInProgress = true; + this.$apollo + .mutate({ + mutation: localUpdateWorkItemMutation, + variables: { + input: { + id: this.workItemId, + milestone: { + milestoneId: this.localMilestone?.id, + }, + }, + }, + }) + .then(({ data }) => { + if (data.workItemUpdate.errors.length) { + throw new Error(data.workItemUpdate.errors.join('\n')); + } + }) + .catch((error) => { + const msg = sprintfWorkItem(I18N_WORK_ITEM_ERROR_UPDATING, this.workItemType); + this.$emit('error', msg); + Sentry.captureException(error); + }) + .finally(() => { + this.updateInProgress = false; + }); + }, + }, +}; + + + diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js index 0d426299408..7737c535650 100644 --- a/app/assets/javascripts/work_items/constants.js +++ b/app/assets/javascripts/work_items/constants.js @@ -17,6 +17,7 @@ export const WIDGET_TYPE_LABELS = 'LABELS'; export const WIDGET_TYPE_START_AND_DUE_DATE = 'START_AND_DUE_DATE'; export const WIDGET_TYPE_WEIGHT = 'WEIGHT'; export const WIDGET_TYPE_HIERARCHY = 'HIERARCHY'; +export const WIDGET_TYPE_MILESTONE = 'MILESTONE'; export const WIDGET_TYPE_ITERATION = 'ITERATION'; export const WORK_ITEM_VIEWED_STORAGE_KEY = 'gl-show-work-item-banner'; diff --git a/app/assets/javascripts/work_items/graphql/typedefs.graphql b/app/assets/javascripts/work_items/graphql/typedefs.graphql index d3712da1329..36779dfe11e 100644 --- a/app/assets/javascripts/work_items/graphql/typedefs.graphql +++ b/app/assets/javascripts/work_items/graphql/typedefs.graphql @@ -1,5 +1,6 @@ enum LocalWidgetType { ASSIGNEES + MILESTONE } interface LocalWorkItemWidget { @@ -11,6 +12,15 @@ type LocalWorkItemAssignees implements LocalWorkItemWidget { nodes: [UserCore] } +type LocalWorkItemMilestone implements LocalWorkItemWidget { + type: LocalWidgetType! + nodes: [Milestone!] +} + +extend type WorkItem { + mockWidgets: [LocalWorkItemWidget] +} + input LocalUserInput { id: ID! name: String @@ -19,9 +29,14 @@ input LocalUserInput { avatarUrl: String } +input LocalMilestoneInput { + milestoneId: ID! +} + input LocalUpdateWorkItemInput { id: WorkItemID! assignees: [LocalUserInput!] + milestone: LocalMilestoneInput! } type LocalWorkItemPayload { diff --git a/app/assets/javascripts/work_items/graphql/work_item.query.graphql b/app/assets/javascripts/work_items/graphql/work_item.query.graphql index 3b46fed97ec..fa0ab56df75 100644 --- a/app/assets/javascripts/work_items/graphql/work_item.query.graphql +++ b/app/assets/javascripts/work_items/graphql/work_item.query.graphql @@ -3,5 +3,16 @@ query workItem($id: WorkItemID!) { workItem(id: $id) { ...WorkItem + mockWidgets @client { + ... on LocalWorkItemMilestone { + type + nodes { + id + title + expired + dueDate + } + } + } } } diff --git a/app/assets/stylesheets/page_bundles/work_items.scss b/app/assets/stylesheets/page_bundles/work_items.scss index 7a5cc72ceb8..820a1a0b53e 100644 --- a/app/assets/stylesheets/page_bundles/work_items.scss +++ b/app/assets/stylesheets/page_bundles/work_items.scss @@ -64,7 +64,7 @@ } } -.work-item-iteration { +.work-item-dropdown { .gl-dropdown-toggle { background: none !important; @@ -82,4 +82,3 @@ } } } - diff --git a/app/controllers/ide_controller.rb b/app/controllers/ide_controller.rb index ebd958822ed..fcf6871d137 100644 --- a/app/controllers/ide_controller.rb +++ b/app/controllers/ide_controller.rb @@ -11,7 +11,6 @@ class IdeController < ApplicationController push_frontend_feature_flag(:build_service_proxy) push_frontend_feature_flag(:schema_linting) push_frontend_feature_flag(:reject_unsigned_commits_by_gitlab) - push_frontend_feature_flag(:vscode_web_ide, current_user) define_index_vars end @@ -27,7 +26,7 @@ class IdeController < ApplicationController namespace: project&.namespace, user: current_user) end - render layout: 'fullscreen', locals: { minimal: Feature.enabled?(:vscode_web_ide, current_user) } + render layout: 'fullscreen', locals: { minimal: helpers.use_new_web_ide? } end private diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb index c0360d10392..a57c87bf691 100644 --- a/app/controllers/profiles/preferences_controller.rb +++ b/app/controllers/profiles/preferences_controller.rb @@ -56,7 +56,8 @@ class Profiles::PreferencesController < Profiles::ApplicationController :gitpod_enabled, :render_whitespace_in_code, :markdown_surround_selection, - :markdown_automatic_lists + :markdown_automatic_lists, + :use_legacy_web_ide ] end end diff --git a/app/graphql/types/environment_type.rb b/app/graphql/types/environment_type.rb index 2484081a828..dd2286d333d 100644 --- a/app/graphql/types/environment_type.rb +++ b/app/graphql/types/environment_type.rb @@ -57,7 +57,7 @@ module Types field :deployments, Types::DeploymentType.connection_type, null: true, - description: 'Deployments of the environment. This field can only be resolved for one project in any single request.', + description: 'Deployments of the environment. This field can only be resolved for one environment in any single request.', resolver: Resolvers::DeploymentsResolver do extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 end diff --git a/app/helpers/hooks_helper.rb b/app/helpers/hooks_helper.rb index 1e50033e0e0..e050ccc0e40 100644 --- a/app/helpers/hooks_helper.rb +++ b/app/helpers/hooks_helper.rb @@ -1,6 +1,13 @@ # frozen_string_literal: true module HooksHelper + def webhook_form_data(hook) + { + url: hook.url, + url_variables: nil + } + end + def link_to_test_hook(hook, trigger) path = test_hook_path(hook, trigger) trigger_human_name = trigger.to_s.tr('_', ' ').camelize diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb index ec1327cf7ae..5b3ca25b5af 100644 --- a/app/helpers/ide_helper.rb +++ b/app/helpers/ide_helper.rb @@ -2,6 +2,32 @@ module IdeHelper def ide_data + { + 'can-use-new-web-ide' => can_use_new_web_ide?.to_s, + 'use-new-web-ide' => use_new_web_ide?.to_s, + 'user-preferences-path' => profile_preferences_path, + 'branch-name' => @branch + }.merge(use_new_web_ide? ? new_ide_data : legacy_ide_data) + end + + def can_use_new_web_ide? + Feature.enabled?(:vscode_web_ide, current_user) + end + + def use_new_web_ide? + can_use_new_web_ide? && !current_user.use_legacy_web_ide + end + + private + + def new_ide_data + { + 'project-path' => @project&.path_with_namespace, + 'csp-nonce' => content_security_policy_nonce + } + end + + def legacy_ide_data { 'empty-state-svg-path' => image_path('illustrations/multi_file_editor_empty.svg'), 'no-changes-state-svg-path' => image_path('illustrations/multi-editor_no_changes_empty.svg'), @@ -13,7 +39,6 @@ module IdeHelper 'clientside-preview-enabled': Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?.to_s, 'render-whitespace-in-code': current_user.render_whitespace_in_code.to_s, 'codesandbox-bundler-url': Gitlab::CurrentSettings.web_ide_clientside_preview_bundler_url, - 'branch-name' => @branch, 'default-branch' => @project && @project.default_branch, 'file-path' => @path, 'merge-request' => @merge_request, @@ -24,13 +49,10 @@ module IdeHelper 'web-terminal-svg-path' => image_path('illustrations/web-ide_promotion.svg'), 'web-terminal-help-path' => help_page_path('user/project/web_ide/index.md', anchor: 'interactive-web-terminals-for-the-web-ide'), 'web-terminal-config-help-path' => help_page_path('user/project/web_ide/index.md', anchor: 'web-ide-configuration-file'), - 'web-terminal-runners-help-path' => help_page_path('user/project/web_ide/index.md', anchor: 'runner-configuration'), - 'csp-nonce' => content_security_policy_nonce + 'web-terminal-runners-help-path' => help_page_path('user/project/web_ide/index.md', anchor: 'runner-configuration') } end - private - def convert_to_project_entity_json(project) return unless project diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index f83aa79b461..361b1a8dca9 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -410,6 +410,13 @@ class ApplicationSetting < ApplicationRecord allow_nil: false, inclusion: { in: [true, false], message: N_('must be a boolean value') } + # rubocop:disable Cop/StaticTranslationDefinition + validates :deactivate_dormant_users_period, + presence: true, + numericality: { only_integer: true, greater_than_or_equal_to: 90, message: _("'%{value}' days of inactivity must be greater than or equal to 90") }, + if: :deactivate_dormant_users? + # rubocop:enable Cop/StaticTranslationDefinition + Gitlab::SSHPublicKey.supported_types.each do |type| validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type } end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 4287c0b7884..950e0a583bc 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -1364,9 +1364,9 @@ module Ci self.builds.latest.build_matchers(project) end - def authorized_cluster_agents - strong_memoize(:authorized_cluster_agents) do - ::Clusters::AgentAuthorizationsFinder.new(project).execute.map(&:agent) + def cluster_agent_authorizations + strong_memoize(:cluster_agent_authorizations) do + ::Clusters::AgentAuthorizationsFinder.new(project).execute end end diff --git a/app/models/clusters/agents/implicit_authorization.rb b/app/models/clusters/agents/implicit_authorization.rb index 9f7f653ed65..a365ccdc568 100644 --- a/app/models/clusters/agents/implicit_authorization.rb +++ b/app/models/clusters/agents/implicit_authorization.rb @@ -16,7 +16,7 @@ module Clusters end def config - nil + {} end end end diff --git a/app/models/user.rb b/app/models/user.rb index b36b00fcbaf..6d198fc755b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -354,6 +354,7 @@ class User < ApplicationRecord :markdown_automatic_lists, :markdown_automatic_lists=, :diffs_deletion_color, :diffs_deletion_color=, :diffs_addition_color, :diffs_addition_color=, + :use_legacy_web_ide, :use_legacy_web_ide=, to: :user_preference delegate :path, to: :namespace, allow_nil: true, prefix: true diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb index b8f30413404..c6ebd550daf 100644 --- a/app/models/user_preference.rb +++ b/app/models/user_preference.rb @@ -22,6 +22,7 @@ class UserPreference < ApplicationRecord validates :diffs_deletion_color, :diffs_addition_color, format: { with: ColorsHelper::HEX_COLOR_PATTERN }, allow_blank: true + validates :use_legacy_web_ide, allow_nil: false, inclusion: { in: [true, false] } ignore_columns :experience_level, remove_with: '14.10', remove_after: '2021-03-22' diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb index 71a05ef2c72..706608e3029 100644 --- a/app/presenters/ci/build_runner_presenter.rb +++ b/app/presenters/ci/build_runner_presenter.rb @@ -34,7 +34,9 @@ module Ci def runner_variables stop_expanding_file_vars = ::Feature.enabled?(:ci_stop_expanding_file_vars_for_runners, project) - variables.sort_and_expand_all(keep_undefined: true, expand_file_vars: !stop_expanding_file_vars).to_runner_variables + variables + .sort_and_expand_all(keep_undefined: true, expand_file_vars: !stop_expanding_file_vars, project: project) + .to_runner_variables end def refspecs diff --git a/app/services/bulk_imports/uploads_export_service.rb b/app/services/bulk_imports/uploads_export_service.rb index 7f5ee7b8624..315590bea31 100644 --- a/app/services/bulk_imports/uploads_export_service.rb +++ b/app/services/bulk_imports/uploads_export_service.rb @@ -22,8 +22,9 @@ module BulkImports subdir_path = export_subdir_path(upload) mkdir_p(subdir_path) download_or_copy_upload(uploader, File.join(subdir_path, uploader.filename)) - rescue Errno::ENAMETOOLONG => e - # Do not fail entire export process if downloaded file has filename that exceeds 255 characters. + rescue StandardError => e + # Do not fail entire project export if something goes wrong during file download + # (e.g. downloaded file has filename that exceeds 255 characters). # Ignore raised exception, skip such upload, log the error and keep going with the export instead. Gitlab::ErrorTracking.log_exception(e, portable_id: portable.id, portable_class: portable.class.name, upload_id: upload.id) end diff --git a/app/services/ci/generate_kubeconfig_service.rb b/app/services/ci/generate_kubeconfig_service.rb index 894ab8e8505..347bc99dbf5 100644 --- a/app/services/ci/generate_kubeconfig_service.rb +++ b/app/services/ci/generate_kubeconfig_service.rb @@ -14,7 +14,8 @@ module Ci url: Gitlab::Kas.tunnel_url ) - agents.each do |agent| + agent_authorizations.each do |authorization| + agent = authorization.agent user = user_name(agent) template.add_user( @@ -24,6 +25,7 @@ module Ci template.add_context( name: context_name(agent), + namespace: context_namespace(authorization), cluster: cluster_name, user: user ) @@ -36,8 +38,8 @@ module Ci attr_reader :pipeline, :token, :template - def agents - pipeline.authorized_cluster_agents + def agent_authorizations + pipeline.cluster_agent_authorizations end def cluster_name @@ -52,6 +54,10 @@ module Ci [agent.project.full_path, agent.name].join(delimiter) end + def context_namespace(authorization) + authorization.config['default_namespace'] + end + def agent_token(agent) ['ci', agent.id, token].join(delimiter) end diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml index b08a549148d..c091a2180c5 100644 --- a/app/views/admin/application_settings/_account_and_limit.html.haml +++ b/app/views/admin/application_settings/_account_and_limit.html.haml @@ -54,10 +54,10 @@ - dormant_users_help_link_start = ''.html_safe % { url: dormant_users_help_link } = f.gitlab_ui_checkbox_component :deactivate_dormant_users, _('Deactivate dormant users after a period of inactivity'), help_text: _('Users can reactivate their account by signing in. %{link_start}Learn more.%{link_end}').html_safe % { link_start: dormant_users_help_link_start, link_end: ''.html_safe } .form-group - = f.label :deactivate_dormant_users_period, _('Period of inactivity (days)'), class: 'label-light' - = f.number_field :deactivate_dormant_users_period, class: 'form-control gl-form-input', min: '1' + = f.label :deactivate_dormant_users_period, _('Days of inactivity before deactivation'), class: 'label-light' + = f.number_field :deactivate_dormant_users_period, class: 'form-control gl-form-input', min: '90', step: '1' .form-text.text-muted - = _('Period of inactivity before deactivation.') + = _('Must be 90 days or more.') .form-group = f.label :personal_access_token_prefix, _('Personal Access Token prefix'), class: 'label-light' diff --git a/app/views/import/fogbugz/new_user_map.html.haml b/app/views/import/fogbugz/new_user_map.html.haml index 28836055e0e..9d4c0f62134 100644 --- a/app/views/import/fogbugz/new_user_map.html.haml +++ b/app/views/import/fogbugz/new_user_map.html.haml @@ -23,23 +23,21 @@ %p = html_escape(_('Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. "By %{link_open}@johnsmith%{link_close}"). It will also associate and/or assign these issues and comments with the selected user.')) % { link_open: ''.html_safe, link_close: ''.html_safe } - .table-holder - %table.table - %thead + %table.table + %thead + %tr + %th= _("ID") + %th= _("Name") + %th= _("Email") + %th= _("GitLab User") + %tbody + - @user_map.each do |id, user| %tr - %th= _("ID") - %th= _("Name") - %th= _("Email") - %th= _("GitLab User") - %tbody - - @user_map.each do |id, user| - %tr - %td= id - %td= text_field_tag "users[#{id}][name]", user[:name], class: 'form-control' - %td= text_field_tag "users[#{id}][email]", user[:email], class: 'form-control' - %td - = users_select_tag("users[#{id}][gitlab_user]", class: 'custom-form-control', - scope: :all, email_user: true, selected: user[:gitlab_user]) + %td= id + %td= text_field_tag "users[#{id}][name]", user[:name], class: 'form-control gl-form-input' + %td= text_field_tag "users[#{id}][email]", user[:email], class: 'form-control gl-form-input' + %td + .js-gitlab-user{ data: { name: "users[#{id}][gitlab_user]" } } .form-actions = submit_tag _('Continue to the next step'), class: 'gl-button btn btn-confirm' diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml index 549436ccabf..c95e63bdc83 100644 --- a/app/views/shared/web_hooks/_form.html.haml +++ b/app/views/shared/web_hooks/_form.html.haml @@ -1,7 +1,7 @@ = form_errors(hook) - if Feature.enabled?(:webhook_form_mask_url) - .js-vue-webhook-form + .js-vue-webhook-form{ data: webhook_form_data(hook) } - else .form-group = form.label :url, s_('Webhooks|URL'), class: 'label-bold' -- cgit v1.2.1