Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-09 12:09:10 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-09 12:09:10 +0300
commit7484851b5f762fad81ddecb4735d22828e205af1 (patch)
treeb7e5da6212d2b32626b9b3d70c9089b98d05bb92 /app
parent760822a53715549c2f115370ed24a19db1b7d63a (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/boards/components/board_content_sidebar.vue6
-rw-r--r--app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue (renamed from app/assets/javascripts/boards/components/sidebar/board_sidebar_issue_title.vue)48
-rw-r--r--app/assets/javascripts/boards/constants.js11
-rw-r--r--app/assets/javascripts/boards/graphql/issue_set_title.mutation.graphql2
-rw-r--r--app/assets/javascripts/boards/stores/actions.js20
-rw-r--r--app/assets/javascripts/issue_show/components/header_actions.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_actions.vue6
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue2
-rw-r--r--app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql8
-rw-r--r--app/graphql/mutations/concerns/mutations/assignable.rb23
-rw-r--r--app/graphql/mutations/issues/set_assignees.rb13
-rw-r--r--app/models/ci/pipeline.rb4
-rw-r--r--app/models/clusters/agent.rb1
-rw-r--r--app/models/clusters/agent_token.rb4
-rw-r--r--app/models/deployment.rb16
-rw-r--r--app/services/deployments/link_merge_requests_service.rb2
-rw-r--r--app/services/merge_requests/update_assignees_service.rb34
-rw-r--r--app/views/help/index.html.haml27
-rw-r--r--app/views/jira_connect/subscriptions/index.html.haml4
-rw-r--r--app/views/jira_connect/users/show.html.haml2
-rw-r--r--app/views/profiles/show.html.haml2
-rw-r--r--app/views/shared/notes/_comment_button.html.haml2
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 } }