diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-09 12:09:10 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-04-09 12:09:10 +0300 |
commit | 7484851b5f762fad81ddecb4735d22828e205af1 (patch) | |
tree | b7e5da6212d2b32626b9b3d70c9089b98d05bb92 /app | |
parent | 760822a53715549c2f115370ed24a19db1b7d63a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
22 files changed, 153 insertions, 86 deletions
diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue index 21b14124f59..46359cc2bca 100644 --- a/app/assets/javascripts/boards/components/board_content_sidebar.vue +++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue @@ -2,11 +2,11 @@ import { GlDrawer } from '@gitlab/ui'; import { mapState, mapActions, mapGetters } from 'vuex'; import BoardSidebarDueDate from '~/boards/components/sidebar/board_sidebar_due_date.vue'; -import BoardSidebarIssueTitle from '~/boards/components/sidebar/board_sidebar_issue_title.vue'; import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue'; import BoardSidebarMilestoneSelect from '~/boards/components/sidebar/board_sidebar_milestone_select.vue'; import BoardSidebarSubscription from '~/boards/components/sidebar/board_sidebar_subscription.vue'; import BoardSidebarTimeTracker from '~/boards/components/sidebar/board_sidebar_time_tracker.vue'; +import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue'; import { ISSUABLE } from '~/boards/constants'; import { contentTop } from '~/lib/utils/common_utils'; import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue'; @@ -16,7 +16,7 @@ export default { headerHeight: `${contentTop()}px`, components: { GlDrawer, - BoardSidebarIssueTitle, + BoardSidebarTitle, SidebarAssigneesWidget, BoardSidebarTimeTracker, BoardSidebarLabelsSelect, @@ -67,7 +67,7 @@ export default { > <template #header>{{ __('Issue details') }}</template> <template #default> - <board-sidebar-issue-title /> + <board-sidebar-title /> <sidebar-assignees-widget :iid="activeBoardItem.iid" :full-path="fullPath" diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_issue_title.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue index 0aa65a30b46..b8d3107c377 100644 --- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_issue_title.vue +++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue @@ -27,12 +27,12 @@ export default { }; }, computed: { - ...mapGetters({ issue: 'activeBoardItem' }), + ...mapGetters({ item: 'activeBoardItem' }), pendingChangesStorageKey() { - return this.getPendingChangesKey(this.issue); + return this.getPendingChangesKey(this.item); }, projectPath() { - const referencePath = this.issue.referencePath || ''; + const referencePath = this.item.referencePath || ''; return referencePath.slice(0, referencePath.indexOf('#')); }, validationState() { @@ -40,29 +40,29 @@ export default { }, }, watch: { - issue: { - handler(updatedIssue, formerIssue) { - if (formerIssue?.title !== this.title) { - localStorage.setItem(this.getPendingChangesKey(formerIssue), this.title); + item: { + handler(updatedItem, formerItem) { + if (formerItem?.title !== this.title) { + localStorage.setItem(this.getPendingChangesKey(formerItem), this.title); } - this.title = updatedIssue.title; + this.title = updatedItem.title; this.setPendingState(); }, immediate: true, }, }, methods: { - ...mapActions(['setActiveIssueTitle']), - getPendingChangesKey(issue) { - if (!issue) { + ...mapActions(['setActiveItemTitle']), + getPendingChangesKey(item) { + if (!item) { return ''; } return joinPaths( window.location.pathname.slice(1), - String(issue.id), - 'issue-title-pending-changes', + String(item.id), + 'item-title-pending-changes', ); }, async setPendingState() { @@ -78,7 +78,7 @@ export default { } }, cancel() { - this.title = this.issue.title; + this.title = this.item.title; this.$refs.sidebarItem.collapse(); this.showChangesAlert = false; localStorage.removeItem(this.pendingChangesStorageKey); @@ -86,24 +86,24 @@ export default { async setTitle() { this.$refs.sidebarItem.collapse(); - if (!this.title || this.title === this.issue.title) { + if (!this.title || this.title === this.item.title) { return; } try { this.loading = true; - await this.setActiveIssueTitle({ title: this.title, projectPath: this.projectPath }); + await this.setActiveItemTitle({ title: this.title, projectPath: this.projectPath }); localStorage.removeItem(this.pendingChangesStorageKey); this.showChangesAlert = false; } catch (e) { - this.title = this.issue.title; + this.title = this.item.title; createFlash({ message: this.$options.i18n.updateTitleError }); } finally { this.loading = false; } }, handleOffClick() { - if (this.title !== this.issue.title) { + if (this.title !== this.item.title) { this.showChangesAlert = true; localStorage.setItem(this.pendingChangesStorageKey, this.title); } else { @@ -112,11 +112,11 @@ export default { }, }, i18n: { - issueTitlePlaceholder: __('Issue title'), + titlePlaceholder: __('Title'), submitButton: __('Save changes'), cancelButton: __('Cancel'), - updateTitleError: __('An error occurred when updating the issue title'), - invalidFeedback: __('An issue title is required'), + updateTitleError: __('An error occurred when updating the title'), + invalidFeedback: __('A title is required'), reviewYourChanges: __('Changes to the title have not been saved'), }, }; @@ -131,10 +131,10 @@ export default { @off-click="handleOffClick" > <template #title> - <span class="gl-font-weight-bold" data-testid="issue-title">{{ issue.title }}</span> + <span class="gl-font-weight-bold" data-testid="item-title">{{ item.title }}</span> </template> <template #collapsed> - <span class="gl-text-gray-800">{{ issue.referencePath }}</span> + <span class="gl-text-gray-800">{{ item.referencePath }}</span> </template> <gl-alert v-if="showChangesAlert" variant="warning" class="gl-mb-5" :dismissible="false"> {{ $options.i18n.reviewYourChanges }} @@ -144,7 +144,7 @@ export default { <gl-form-input v-model="title" v-autofocusonshow - :placeholder="$options.i18n.issueTitlePlaceholder" + :placeholder="$options.i18n.titlePlaceholder" :state="validationState" /> </gl-form-group> diff --git a/app/assets/javascripts/boards/constants.js b/app/assets/javascripts/boards/constants.js index 68c40d98563..ab5e5fda1d8 100644 --- a/app/assets/javascripts/boards/constants.js +++ b/app/assets/javascripts/boards/constants.js @@ -1,5 +1,7 @@ import { __ } from '~/locale'; +import updateEpicTitleMutation from '~/sidebar/queries/update_epic_title.mutation.graphql'; import boardBlockingIssuesQuery from './graphql/board_blocking_issues.query.graphql'; +import issueSetTitleMutation from './graphql/issue_set_title.mutation.graphql'; export const issuableTypes = { issue: 'issue', @@ -52,3 +54,12 @@ export const blockingIssuablesQueries = { query: boardBlockingIssuesQuery, }, }; + +export const titleQueries = { + [issuableTypes.issue]: { + mutation: issueSetTitleMutation, + }, + [issuableTypes.epic]: { + mutation: updateEpicTitleMutation, + }, +}; diff --git a/app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql b/app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql index 62e6c1352a6..6ad12d982e0 100644 --- a/app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql @@ -1,5 +1,5 @@ mutation issueSetTitle($input: UpdateIssueInput!) { - updateIssue(input: $input) { + updateIssuableTitle: updateIssue(input: $input) { issue { title } diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index 9211406d8b2..edae4c75de3 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -8,6 +8,7 @@ import { inactiveId, flashAnimationDuration, ISSUABLE, + titleQueries, } from '~/boards/constants'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import createGqClient, { fetchPolicies } from '~/lib/graphql'; @@ -33,7 +34,6 @@ import issueSetDueDateMutation from '../graphql/issue_set_due_date.mutation.grap import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql'; import issueSetMilestoneMutation from '../graphql/issue_set_milestone.mutation.graphql'; import issueSetSubscriptionMutation from '../graphql/issue_set_subscription.mutation.graphql'; -import issueSetTitleMutation from '../graphql/issue_set_title.mutation.graphql'; import listsIssuesQuery from '../graphql/lists_issues.query.graphql'; import * as types from './mutation_types'; @@ -526,27 +526,31 @@ export default { }); }, - setActiveIssueTitle: async ({ commit, getters }, input) => { - const { activeBoardItem } = getters; + setActiveItemTitle: async ({ commit, getters, state }, input) => { + const { activeBoardItem, isEpicBoard } = getters; + const { fullPath, issuableType } = state; + const workspacePath = isEpicBoard + ? { groupPath: fullPath } + : { projectPath: input.projectPath }; const { data } = await gqlClient.mutate({ - mutation: issueSetTitleMutation, + mutation: titleQueries[issuableType].mutation, variables: { input: { + ...workspacePath, iid: String(activeBoardItem.iid), - projectPath: input.projectPath, title: input.title, }, }, }); - if (data.updateIssue?.errors?.length > 0) { - throw new Error(data.updateIssue.errors); + if (data.updateIssuableTitle?.errors?.length > 0) { + throw new Error(data.updateIssuableTitle.errors); } commit(types.UPDATE_BOARD_ITEM_BY_ID, { itemId: activeBoardItem.id, prop: 'title', - value: data.updateIssue.issue.title, + value: data.updateIssuableTitle[issuableType].title, }); }, diff --git a/app/assets/javascripts/issue_show/components/header_actions.vue b/app/assets/javascripts/issue_show/components/header_actions.vue index bade2cc8399..2bddbe4faa0 100644 --- a/app/assets/javascripts/issue_show/components/header_actions.vue +++ b/app/assets/javascripts/issue_show/components/header_actions.vue @@ -25,7 +25,6 @@ export default { }, actionPrimary: { text: __('Yes, close issue'), - attributes: [{ variant: 'warning' }], }, i18n: { promoteErrorMessage: __( @@ -220,7 +219,6 @@ export default { <gl-button v-if="showToggleIssueStateButton" class="gl-display-none gl-sm-display-inline-flex!" - category="secondary" :data-qa-selector="qaSelector" :loading="isToggleStateButtonLoading" @click="toggleIssueState" diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue index 5a098bfda14..a2f5f69efb4 100644 --- a/app/assets/javascripts/notes/components/note_actions.vue +++ b/app/assets/javascripts/notes/components/note_actions.vue @@ -336,7 +336,7 @@ export default { icon="pencil" size="small" category="tertiary" - class="note-action-button js-note-edit btn btn-transparent" + class="note-action-button js-note-edit" data-qa-selector="note_edit_button" @click="onEdit" /> @@ -348,7 +348,7 @@ export default { size="small" icon="remove" category="tertiary" - class="note-action-button js-note-delete btn btn-transparent" + class="note-action-button js-note-delete" @click="onDelete" /> <div v-else-if="shouldShowActionsDropdown" class="dropdown more-actions"> @@ -359,7 +359,7 @@ export default { icon="ellipsis_v" size="small" category="tertiary" - class="note-action-button more-actions-toggle btn btn-transparent" + class="note-action-button more-actions-toggle" data-toggle="dropdown" @click="closeTooltip" /> diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 6a60e4de518..a25862a587b 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -424,7 +424,7 @@ export default { <gl-button :disabled="isDisabled" category="primary" - variant="success" + variant="confirm" data-qa-selector="reply_comment_button" class="gl-mr-3 js-vue-issue-save js-comment-button" @click="handleUpdate()" diff --git a/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql new file mode 100644 index 00000000000..317b48c142d --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql @@ -0,0 +1,8 @@ +mutation updateEpic($input: UpdateEpicInput!) { + updateIssuableTitle: updateEpic(input: $input) { + epic { + title + } + errors + } +} diff --git a/app/graphql/mutations/concerns/mutations/assignable.rb b/app/graphql/mutations/concerns/mutations/assignable.rb index eb2bc6cac2d..d3ab0a1779a 100644 --- a/app/graphql/mutations/concerns/mutations/assignable.rb +++ b/app/graphql/mutations/concerns/mutations/assignable.rb @@ -19,12 +19,9 @@ module Mutations def resolve(project_path:, iid:, assignee_usernames:, operation_mode:) resource = authorized_find!(project_path: project_path, iid: iid) + users = new_assignees(resource, assignee_usernames) - update_service_class.new( - resource.project, - current_user, - assignee_ids: assignee_ids(resource, assignee_usernames, operation_mode) - ).execute(resource) + assign!(resource, users, operation_mode) { resource.class.name.underscore.to_sym => resource, @@ -34,10 +31,20 @@ module Mutations private - def assignee_ids(resource, usernames, mode) - new = UsersFinder.new(current_user, username: usernames).execute.map(&:id) + def assign!(resource, users, operation_mode) + update_service_class.new( + resource.project, + current_user, + assignee_ids: assignee_ids(resource, users, operation_mode) + ).execute(resource) + end + + def new_assignees(resource, usernames) + UsersFinder.new(current_user, username: usernames).execute.to_a + end - transform_list(mode, resource, new) + def assignee_ids(resource, users, mode) + transform_list(mode, resource, users.map(&:id)) end def current_assignee_ids(resource) diff --git a/app/graphql/mutations/issues/set_assignees.rb b/app/graphql/mutations/issues/set_assignees.rb index a4d1c755b53..8413c89b010 100644 --- a/app/graphql/mutations/issues/set_assignees.rb +++ b/app/graphql/mutations/issues/set_assignees.rb @@ -7,6 +7,19 @@ module Mutations include Assignable + def assign!(issue, users, mode) + permitted, forbidden = users.partition { |u| u.can?(:read_issue, issue) } + + super(issue, permitted, mode) + + forbidden.each do |user| + issue.errors.add( + :assignees, + "Cannot assign #{user.to_reference} to #{issue.to_reference}" + ) + end + end + def update_service_class ::Issues::UpdateService end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 00e585abd01..0fe29f09140 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -683,7 +683,9 @@ module Ci end def has_kubernetes_active? - project.deployment_platform&.active? + strong_memoize(:has_kubernetes_active) do + project.deployment_platform&.active? + end end def freeze_period? diff --git a/app/models/clusters/agent.rb b/app/models/clusters/agent.rb index c5b9dddb1da..7c42fc28a8d 100644 --- a/app/models/clusters/agent.rb +++ b/app/models/clusters/agent.rb @@ -8,6 +8,7 @@ module Clusters belongs_to :project, class_name: '::Project' # Otherwise, it will load ::Clusters::Project has_many :agent_tokens, class_name: 'Clusters::AgentToken' + has_many :last_used_agent_tokens, -> { order_last_used_at_desc }, class_name: 'Clusters::AgentToken' scope :ordered_by_name, -> { order(:name) } scope :with_name, -> (name) { where(name: name) } diff --git a/app/models/clusters/agent_token.rb b/app/models/clusters/agent_token.rb index d42279502c5..27a3cd8d13d 100644 --- a/app/models/clusters/agent_token.rb +++ b/app/models/clusters/agent_token.rb @@ -6,7 +6,7 @@ module Clusters include TokenAuthenticatable add_authentication_token_field :token, encrypted: :required, token_generator: -> { Devise.friendly_token(50) } - cached_attr_reader :last_contacted_at + cached_attr_reader :last_used_at self.table_name = 'cluster_agent_tokens' @@ -21,6 +21,8 @@ module Clusters validates :description, length: { maximum: 1024 } validates :name, presence: true, length: { maximum: 255 } + scope :order_last_used_at_desc, -> { order(::Gitlab::Database.nulls_last_order('last_used_at', 'DESC')) } + def track_usage track_values = { last_used_at: Time.current.utc } diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 9bcc6fd90b2..0bfe6172154 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -240,18 +240,10 @@ class Deployment < ApplicationRecord def previous_deployment @previous_deployment ||= self.class.for_environment(environment_id) - .where(ref: ref) - .where.not(id: id) - .order(id: :desc) - .take - end - - def previous_environment_deployment - self.class.for_environment(environment_id) - .success - .where.not(id: self.id) - .order(id: :desc) - .take + .success + .where('id < ?', id) + .order(id: :desc) + .take end def stop_action diff --git a/app/services/deployments/link_merge_requests_service.rb b/app/services/deployments/link_merge_requests_service.rb index caddea46284..39fbef5dee2 100644 --- a/app/services/deployments/link_merge_requests_service.rb +++ b/app/services/deployments/link_merge_requests_service.rb @@ -33,7 +33,7 @@ module Deployments # meaningful way (i.e. they can't just retry the deploy themselves). return unless deployment.success? - if (prev = deployment.previous_environment_deployment) + if (prev = deployment.previous_deployment) link_merge_requests_for_range(prev.sha, deployment.sha) else # When no previous deployment is found we fall back to linking all merge diff --git a/app/services/merge_requests/update_assignees_service.rb b/app/services/merge_requests/update_assignees_service.rb index 48da8e4aed2..e2f724d1aa6 100644 --- a/app/services/merge_requests/update_assignees_service.rb +++ b/app/services/merge_requests/update_assignees_service.rb @@ -7,15 +7,20 @@ module MergeRequests # This saves a lot of queries for irrelevant things that cannot possibly # change in the execution of this service. def execute(merge_request) - return unless current_user&.can?(:update_merge_request, merge_request) + return merge_request unless current_user&.can?(:update_merge_request, merge_request) old_ids = merge_request.assignees.map(&:id) - return if old_ids.to_set == update_attrs[:assignee_ids].to_set # no-change + new_ids = new_assignee_ids(merge_request) + return merge_request if new_ids.size != update_attrs[:assignee_ids].size + return merge_request if old_ids.to_set == new_ids.to_set # no-change - merge_request.update!(**update_attrs) + attrs = update_attrs.merge(assignee_ids: new_ids) + merge_request.update!(**attrs) # Defer the more expensive operations (handle_assignee_changes) to the background MergeRequests::AssigneesChangeWorker.perform_async(merge_request.id, current_user.id, old_ids) + + merge_request end def handle_assignee_changes(merge_request, old_assignees) @@ -31,10 +36,33 @@ module MergeRequests private + def new_assignee_ids(merge_request) + # prime the cache - prevent N+1 lookup during authorization loop. + merge_request.project.team.max_member_access_for_user_ids(update_attrs[:assignee_ids]) + User.id_in(update_attrs[:assignee_ids]).map do |user| + if user.can?(:read_merge_request, merge_request) + user.id + else + merge_request.errors.add( + :assignees, + "Cannot assign #{user.to_reference} to #{merge_request.to_reference}" + ) + nil + end + end.compact + end + def assignee_ids params.fetch(:assignee_ids).first(1) end + def params + ps = super + + # allow either assignee_id or assignee_ids, preferring assignee_id if passed. + { assignee_ids: ps.key?(:assignee_id) ? Array.wrap(ps[:assignee_id]) : ps[:assignee_ids] } + end + def update_attrs @attrs ||= { updated_at: Time.current, updated_by: current_user, assignee_ids: assignee_ids } end diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 03f8539293b..a56eaaf685f 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -13,19 +13,20 @@ - unless Gitlab::CurrentSettings.help_page_hide_commercial_content? %p.slead - GitLab is open source software to collaborate on code. + = _('GitLab is open source software to collaborate on code.') %br - Manage git repositories with fine-grained access controls that keep your code secure. + = _('Manage git repositories with fine-grained access controls that keep your code secure.') %br - Perform code reviews and enhance collaboration with merge requests. + = _('Perform code reviews and enhance collaboration with merge requests.') %br - Each project can also have an issue tracker and a wiki. + = _('Each project can also have an issue tracker and a wiki.') %br - Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises. + = _('Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises.') %br - Read more about GitLab at #{link_to promo_host, promo_url, target: '_blank', rel: 'noopener noreferrer'}. + - link_to_promo = link_to(promo_host, promo_url, target: '_blank', rel: 'noopener noreferrer') + = _("Read more about GitLab at %{link_to_promo}.").html_safe % { link_to_promo: link_to_promo } -%p= link_to 'Check the current instance configuration ', help_instance_configuration_url +%p= link_to _('Check the current instance configuration '), help_instance_configuration_url %hr .row.gl-mt-3 @@ -35,15 +36,15 @@ .col-md-4 .card.links-card .card-header - Quick help + = _('Quick help') %ul.content-list - %li= link_to 'See our website for getting help', support_url + %li= link_to _('See our website for getting help'), support_url %li %button.btn-blank.btn-link.js-trigger-search-bar{ type: 'button' } - Use the search bar on the top of this page + = _('Use the search bar on the top of this page') %li %button.btn-blank.btn-link.js-trigger-shortcut{ type: 'button' } - Use shortcuts + = _('Use shortcuts') - unless Gitlab::CurrentSettings.help_page_hide_commercial_content? - %li= link_to 'Get a support subscription', 'https://about.gitlab.com/pricing/' - %li= link_to 'Compare GitLab editions', 'https://about.gitlab.com/features/#compare' + %li= link_to _('Get a support subscription'), 'https://about.gitlab.com/pricing/' + %li= link_to _('Compare GitLab editions'), 'https://about.gitlab.com/features/#compare' diff --git a/app/views/jira_connect/subscriptions/index.html.haml b/app/views/jira_connect/subscriptions/index.html.haml index c7873991010..8ce46a28252 100644 --- a/app/views/jira_connect/subscriptions/index.html.haml +++ b/app/views/jira_connect/subscriptions/index.html.haml @@ -39,13 +39,13 @@ - else .gl-text-center %h4= s_('Integrations|No linked namespaces') - %p= s_('Integrations|Namespaces are your GitLab groups and subgroups that will be linked to this Jira instance.') + %p= s_('Integrations|Namespaces are the GitLab groups and subgroups you link to this Jira instance.') %p.jira-connect-app-body.gl-mt-7.gl-font-base.gl-text-center %strong= s_('Integrations|Browser limitations') - firefox_link_url = 'https://www.mozilla.org/en-US/firefox/' - firefox_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: firefox_link_url } - = s_('Integrations|Adding a namespace currently works only in browsers that allow cross‑site cookies. Please make sure to use %{firefox_link_start}Firefox%{firefox_link_end} or enable cross‑site cookies in your browser when adding a namespace.').html_safe % { firefox_link_start: firefox_link_start, firefox_link_end: '</a>'.html_safe } + = s_('Integrations|Adding a namespace works only in browsers that allow cross‑site cookies. Use %{firefox_link_start}Firefox%{firefox_link_end}, or enable cross‑site cookies in your browser, when adding a namespace.').html_safe % { firefox_link_start: firefox_link_start, firefox_link_end: '</a>'.html_safe } = link_to _('Learn more'), 'https://gitlab.com/gitlab-org/gitlab/-/issues/284211', target: '_blank', rel: 'noopener noreferrer' = webpack_bundle_tag 'performance_bar' if performance_bar_enabled? diff --git a/app/views/jira_connect/users/show.html.haml b/app/views/jira_connect/users/show.html.haml index 2ff92ab0dc8..9cc2b41e5c8 100644 --- a/app/views/jira_connect/users/show.html.haml +++ b/app/views/jira_connect/users/show.html.haml @@ -1,6 +1,6 @@ .jira-connect-users-container.gl-text-center - user_link = link_to(current_user.to_reference, user_path(current_user), target: '_blank', rel: 'noopener noreferrer') - %h2= _('You are signed into GitLab as %{user_link}').html_safe % { user_link: user_link } + %h2= _('You are signed in to GitLab as %{user_link}').html_safe % { user_link: user_link } %p= s_('Integrations|You can now close this window and return to the GitLab for Jira application.') diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index cc5ce00669e..15544fb9c45 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -84,7 +84,7 @@ .col-lg-8 -# TODO: might need an entry in user/profile.md to describe some of these settings -# https://gitlab.com/gitlab-org/gitlab-foss/issues/60070 - %h5= ("Time zone") + %h5= _("Time zone") = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'gl-button btn js-timezone-dropdown input-lg', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } ) %input.hidden{ :type => 'hidden', :id => 'user_timezone', :name => 'user[timezone]', value: @user.timezone } .col-lg-12 diff --git a/app/views/shared/notes/_comment_button.html.haml b/app/views/shared/notes/_comment_button.html.haml index d415c64b929..1129fed9c3b 100644 --- a/app/views/shared/notes/_comment_button.html.haml +++ b/app/views/shared/notes/_comment_button.html.haml @@ -4,7 +4,7 @@ %input.btn.gl-button.btn-confirm.js-comment-button.js-comment-submit-button{ type: 'submit', value: _('Comment'), data: { qa_selector: 'comment_button' } } - if @note.can_be_discussion_note? - = button_tag type: 'button', class: 'gl-button btn dropdown-toggle btn-confirm btn-icon js-note-new-discussion js-disable-on-submit', data: { 'dropdown-trigger' => '#resolvable-comment-menu' }, 'aria-label' => _('Open comment type dropdown') do + = button_tag type: 'button', class: 'gl-button btn dropdown-toggle btn-confirm js-note-new-discussion js-disable-on-submit', data: { 'dropdown-trigger' => '#resolvable-comment-menu' }, 'aria-label' => _('Open comment type dropdown') do = sprite_icon('chevron-down') %ul#resolvable-comment-menu.dropdown-menu.dropdown-open-top{ data: { dropdown: true } } |