Skip to content

Commit a05b64a

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent 0abf7c0 commit a05b64a

File tree

66 files changed

+1247
-1005
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1247
-1005
lines changed

.eslint_todo/vue-no-unused-properties.mjs

-1
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,6 @@ export default {
385385
'app/assets/javascripts/work_items/components/notes/work_item_note_body.vue',
386386
'app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue',
387387
'app/assets/javascripts/work_items/components/shared/work_item_token_input.vue',
388-
'app/assets/javascripts/work_items/components/work_item_actions.vue',
389388
'app/assets/javascripts/work_items/components/work_item_assignees.vue',
390389
'app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue',
391390
'app/assets/javascripts/work_items/components/work_item_change_type_modal.vue',

.gitlab/ci/rails.gitlab-ci.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,7 @@ rspec:undercoverage:
594594
stage: post-test
595595
needs: ["rspec:coverage"]
596596
script:
597-
- apt install -y jq
598-
- if [[ $(curl "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}" | jq ".labels" | grep "pipeline:skip-undercoverage") ]]; then
597+
- if [[ ",${CI_MERGE_REQUEST_LABELS}," == *",pipeline:skip-undercoverage,"* ]]; then
599598
echo "The 'pipeline:skip-undercoverage' label is set on the MR, exiting early.";
600599
exit 0;
601600
else

app/assets/javascripts/ci/ci_variable_list/components/ci_variable_drawer.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ export default {
662662
/>
663663
<p
664664
v-if="variable.key.length > 0 && !isKeyValid"
665-
class="gl-mb-0 gl-border-none !gl-pb-0 !gl-pt-3 gl-text-red-500"
665+
class="gl-mb-0 gl-border-none !gl-pb-0 !gl-pt-3 gl-text-danger"
666666
>
667667
{{ $options.i18n.keyFeedback }}
668668
</p>

app/assets/javascripts/lib/utils/datetime/timeago_utility.js

+102-60
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as timeago from 'timeago.js';
22
import { newDate } from '~/lib/utils/datetime/date_calculation_utility';
33
import { DEFAULT_DATE_TIME_FORMAT, localeDateFormat } from '~/lib/utils/datetime/locale_dateformat';
4-
import { languageCode, s__ } from '~/locale';
4+
import { languageCode, getPluralFormIndex, s__, n__ } from '~/locale';
55

66
/**
77
* Timeago uses underscores instead of dashes to separate language from country code.
@@ -10,64 +10,104 @@ import { languageCode, s__ } from '~/locale';
1010
*/
1111
export const timeagoLanguageCode = languageCode().replace(/-/g, '_');
1212

13+
const i18n = {
14+
justNow: s__('Timeago|just now'),
15+
rightNow: s__('Timeago|right now'),
16+
secondsAgoPlural: (n) => n__('Timeago|1 second ago', 'Timeago|%s seconds ago', n),
17+
secondsRemainingPlural: (n) =>
18+
n__('Timeago|1 second remaining', 'Timeago|%s seconds remaining', n),
19+
inSecondsPlural: (n) => n__('Timeago|in 1 second', 'Timeago|in %s seconds', n),
20+
durationSecondsPlural: (n) => n__('Duration|1 second', 'Duration|%s seconds', n),
21+
minutesAgoPlural: (n) => n__('Timeago|1 minute ago', 'Timeago|%s minutes ago', n),
22+
minutesRemainingPlural: (n) =>
23+
n__('Timeago|1 minute remaining', 'Timeago|%s minutes remaining', n),
24+
inMinutesPlural: (n) => n__('Timeago|in 1 minute', 'Timeago|in %s minutes', n),
25+
durationMinutesPlural: (n) => n__('Duration|1 minute', 'Duration|%s minutes', n),
26+
hoursAgoPlural: (n) => n__('Timeago|1 hour ago', 'Timeago|%s hours ago', n),
27+
hoursRemainingPlural: (n) => n__('Timeago|1 hour remaining', 'Timeago|%s hours remaining', n),
28+
inHoursPlural: (n) => n__('Timeago|in 1 hour', 'Timeago|in %s hours', n),
29+
durationHoursPlural: (n) => n__('Duration|1 hour', 'Duration|%s hours', n),
30+
daysAgoPlural: (n) => n__('Timeago|1 day ago', 'Timeago|%s days ago', n),
31+
daysRemainingPlural: (n) => n__('Timeago|1 day remaining', 'Timeago|%s days remaining', n),
32+
inDaysPlural: (n) => n__('Timeago|in 1 day', 'Timeago|in %s days', n),
33+
durationDaysPlural: (n) => n__('Duration|1 day', 'Duration|%s days', n),
34+
weeksAgoPlural: (n) => n__('Timeago|1 week ago', 'Timeago|%s weeks ago', n),
35+
weeksRemainingPlural: (n) => n__('Timeago|1 week remaining', 'Timeago|%s weeks remaining', n),
36+
inWeeksPlural: (n) => n__('Timeago|in 1 week', 'Timeago|in %s weeks', n),
37+
durationWeeksPlural: (n) => n__('Duration|1 week', 'Duration|%s weeks', n),
38+
monthsAgoPlural: (n) => n__('Timeago|1 month ago', 'Timeago|%s months ago', n),
39+
monthsRemainingPlural: (n) => n__('Timeago|1 month remaining', 'Timeago|%s months remaining', n),
40+
inMonthsPlural: (n) => n__('Timeago|in 1 month', 'Timeago|in %s months', n),
41+
durationMonthsPlural: (n) => n__('Duration|1 month', 'Duration|%s months', n),
42+
yearsAgoPlural: (n) => n__('Timeago|1 year ago', 'Timeago|%s years ago', n),
43+
yearsRemainingPlural: (n) => n__('Timeago|1 year remaining', 'Timeago|%s years remaining', n),
44+
inYearsPlural: (n) => n__('Timeago|in 1 year', 'Timeago|in %s years', n),
45+
durationYearsPlural: (n) => n__('Duration|1 year', 'Duration|%s years', n),
46+
pastDue: s__('Timeago|Past due'),
47+
};
48+
1349
/**
1450
* Registers timeago locales
1551
*/
1652
const memoizedLocaleRemaining = () => {
1753
const cache = [];
1854

19-
const timeAgoLocaleRemaining = [
20-
() => [s__('Timeago|just now'), s__('Timeago|right now')],
21-
() => [s__('Timeago|just now'), s__('Timeago|%s seconds remaining')],
22-
() => [s__('Timeago|1 minute ago'), s__('Timeago|1 minute remaining')],
23-
() => [s__('Timeago|%s minutes ago'), s__('Timeago|%s minutes remaining')],
24-
() => [s__('Timeago|1 hour ago'), s__('Timeago|1 hour remaining')],
25-
() => [s__('Timeago|%s hours ago'), s__('Timeago|%s hours remaining')],
26-
() => [s__('Timeago|1 day ago'), s__('Timeago|1 day remaining')],
27-
() => [s__('Timeago|%s days ago'), s__('Timeago|%s days remaining')],
28-
() => [s__('Timeago|1 week ago'), s__('Timeago|1 week remaining')],
29-
() => [s__('Timeago|%s weeks ago'), s__('Timeago|%s weeks remaining')],
30-
() => [s__('Timeago|1 month ago'), s__('Timeago|1 month remaining')],
31-
() => [s__('Timeago|%s months ago'), s__('Timeago|%s months remaining')],
32-
() => [s__('Timeago|1 year ago'), s__('Timeago|1 year remaining')],
33-
() => [s__('Timeago|%s years ago'), s__('Timeago|%s years remaining')],
55+
const locales = [
56+
() => [i18n.justNow, i18n.rightNow],
57+
(n) => [i18n.secondsAgoPlural(n), i18n.secondsRemainingPlural(n)],
58+
() => [i18n.minutesAgoPlural(1), i18n.minutesRemainingPlural(1)],
59+
(n) => [i18n.minutesAgoPlural(n), i18n.minutesRemainingPlural(n)],
60+
() => [i18n.hoursAgoPlural(1), i18n.hoursRemainingPlural(1)],
61+
(n) => [i18n.hoursAgoPlural(n), i18n.hoursRemainingPlural(n)],
62+
() => [i18n.daysAgoPlural(1), i18n.daysRemainingPlural(1)],
63+
(n) => [i18n.daysAgoPlural(n), i18n.daysRemainingPlural(n)],
64+
() => [i18n.weeksAgoPlural(1), i18n.weeksRemainingPlural(1)],
65+
(n) => [i18n.weeksAgoPlural(n), i18n.weeksRemainingPlural(n)],
66+
() => [i18n.monthsAgoPlural(1), i18n.monthsRemainingPlural(1)],
67+
(n) => [i18n.monthsAgoPlural(n), i18n.monthsRemainingPlural(n)],
68+
() => [i18n.yearsAgoPlural(1), i18n.yearsRemainingPlural(1)],
69+
(n) => [i18n.yearsAgoPlural(n), i18n.yearsRemainingPlural(n)],
3470
];
3571

3672
return (number, index) => {
37-
if (cache[index]) {
38-
return cache[index];
73+
const form = getPluralFormIndex(number);
74+
const cacheKey = `${index}-${form}`;
75+
if (!cache[cacheKey]) {
76+
cache[cacheKey] = locales[index] && locales[index](number);
3977
}
40-
cache[index] = timeAgoLocaleRemaining[index] && timeAgoLocaleRemaining[index]();
41-
return cache[index];
78+
79+
return cache[cacheKey];
4280
};
4381
};
4482

4583
const memoizedLocale = () => {
4684
const cache = [];
4785

48-
const timeAgoLocale = [
49-
() => [s__('Timeago|just now'), s__('Timeago|right now')],
50-
() => [s__('Timeago|just now'), s__('Timeago|in %s seconds')],
51-
() => [s__('Timeago|1 minute ago'), s__('Timeago|in 1 minute')],
52-
() => [s__('Timeago|%s minutes ago'), s__('Timeago|in %s minutes')],
53-
() => [s__('Timeago|1 hour ago'), s__('Timeago|in 1 hour')],
54-
() => [s__('Timeago|%s hours ago'), s__('Timeago|in %s hours')],
55-
() => [s__('Timeago|1 day ago'), s__('Timeago|in 1 day')],
56-
() => [s__('Timeago|%s days ago'), s__('Timeago|in %s days')],
57-
() => [s__('Timeago|1 week ago'), s__('Timeago|in 1 week')],
58-
() => [s__('Timeago|%s weeks ago'), s__('Timeago|in %s weeks')],
59-
() => [s__('Timeago|1 month ago'), s__('Timeago|in 1 month')],
60-
() => [s__('Timeago|%s months ago'), s__('Timeago|in %s months')],
61-
() => [s__('Timeago|1 year ago'), s__('Timeago|in 1 year')],
62-
() => [s__('Timeago|%s years ago'), s__('Timeago|in %s years')],
86+
const locales = [
87+
() => [i18n.justNow, i18n.rightNow],
88+
(n) => [i18n.secondsAgoPlural(n), i18n.inSecondsPlural(n)],
89+
() => [i18n.minutesAgoPlural(1), i18n.inMinutesPlural(1)],
90+
(n) => [i18n.minutesAgoPlural(n), i18n.inMinutesPlural(n)],
91+
() => [i18n.hoursAgoPlural(1), i18n.inHoursPlural(1)],
92+
(n) => [i18n.hoursAgoPlural(n), i18n.inHoursPlural(n)],
93+
() => [i18n.daysAgoPlural(1), i18n.inDaysPlural(1)],
94+
(n) => [i18n.daysAgoPlural(n), i18n.inDaysPlural(n)],
95+
() => [i18n.weeksAgoPlural(1), i18n.inWeeksPlural(1)],
96+
(n) => [i18n.weeksAgoPlural(n), i18n.inWeeksPlural(n)],
97+
() => [i18n.monthsAgoPlural(1), i18n.inMonthsPlural(1)],
98+
(n) => [i18n.monthsAgoPlural(n), i18n.inMonthsPlural(n)],
99+
() => [i18n.yearsAgoPlural(1), i18n.inYearsPlural(1)],
100+
(n) => [i18n.yearsAgoPlural(n), i18n.inYearsPlural(n)],
63101
];
64102

65103
return (number, index) => {
66-
if (cache[index]) {
67-
return cache[index];
104+
const form = getPluralFormIndex(number);
105+
const cacheKey = `${index}-${form}`;
106+
if (!cache[cacheKey]) {
107+
cache[cacheKey] = locales[index] && locales[index](number);
68108
}
69-
cache[index] = timeAgoLocale[index] && timeAgoLocale[index]();
70-
return cache[index];
109+
110+
return cache[cacheKey];
71111
};
72112
};
73113

@@ -77,29 +117,31 @@ const memoizedLocale = () => {
77117
const memoizedLocaleDuration = () => {
78118
const cache = [];
79119

80-
const durations = [
81-
() => [s__('Duration|%s seconds')],
82-
() => [s__('Duration|%s seconds')],
83-
() => [s__('Duration|1 minute')],
84-
() => [s__('Duration|%s minutes')],
85-
() => [s__('Duration|1 hour')],
86-
() => [s__('Duration|%s hours')],
87-
() => [s__('Duration|1 day')],
88-
() => [s__('Duration|%s days')],
89-
() => [s__('Duration|1 week')],
90-
() => [s__('Duration|%s weeks')],
91-
() => [s__('Duration|1 month')],
92-
() => [s__('Duration|%s months')],
93-
() => [s__('Duration|1 year')],
94-
() => [s__('Duration|%s years')],
120+
const locales = [
121+
(n) => [i18n.durationSecondsPlural(n)],
122+
(n) => [i18n.durationSecondsPlural(n)],
123+
() => [i18n.durationMinutesPlural(1)],
124+
(n) => [i18n.durationMinutesPlural(n)],
125+
() => [i18n.durationHoursPlural(1)],
126+
(n) => [i18n.durationHoursPlural(n)],
127+
() => [i18n.durationDaysPlural(1)],
128+
(n) => [i18n.durationDaysPlural(n)],
129+
() => [i18n.durationWeeksPlural(1)],
130+
(n) => [i18n.durationWeeksPlural(n)],
131+
() => [i18n.durationMonthsPlural(1)],
132+
(n) => [i18n.durationMonthsPlural(n)],
133+
() => [i18n.durationYearsPlural(1)],
134+
(n) => [i18n.durationYearsPlural(n)],
95135
];
96136

97-
return (_, index) => {
98-
if (cache[index]) {
99-
return cache[index];
137+
return (number, index) => {
138+
const form = getPluralFormIndex(number);
139+
const cacheKey = `${index}-${form}`;
140+
if (!cache[cacheKey]) {
141+
cache[cacheKey] = locales[index] && locales[index](number);
100142
}
101-
cache[index] = durations[index] && durations[index]();
102-
return cache[index];
143+
144+
return cache[cacheKey];
103145
};
104146
};
105147

@@ -147,7 +189,7 @@ export const timeFor = (time, expiredLabel) => {
147189
return '';
148190
}
149191
if (new Date(time) < new Date()) {
150-
return expiredLabel || s__('Timeago|Past due');
192+
return expiredLabel || i18n.pastDue;
151193
}
152194
return timeago.format(time, `${timeagoLanguageCode}-remaining`).trim();
153195
};

app/assets/javascripts/locale/index.js

+16
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,21 @@ const ngettext = (text, pluralText, count) => {
4444
return translated[translated.length - 1];
4545
};
4646

47+
/**
48+
* Get the plural form index for a number.
49+
*
50+
* @param {number} number - The number to get the plural form for
51+
* @returns {number} The plural form index for the number
52+
*/
53+
54+
const getPluralFormIndex = (number) => {
55+
const pluralFormFunc = Jed.PF.compile(
56+
locale.options.locale_data[locale.options.domain][''].plural_forms,
57+
);
58+
59+
return pluralFormFunc(number);
60+
};
61+
4762
/**
4863
* Translate context based text.
4964
* @example
@@ -130,6 +145,7 @@ function formatNumber(value, options = {}, langCode = languageCode()) {
130145
export { languageCode };
131146
export { gettext as __ };
132147
export { ngettext as n__ };
148+
export { getPluralFormIndex };
133149
export { pgettext as s__ };
134150
export { sprintf };
135151
export { createDateTimeFormat };

app/assets/javascripts/super_sidebar/components/super_sidebar.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export default {
200200
<div ref="overlay" class="super-sidebar-overlay" @click="collapseSidebar"></div>
201201
<gl-button
202202
v-if="sidebarData.is_logged_in"
203-
class="super-sidebar-skip-to gl-sr-only !gl-fixed gl-left-0 gl-m-3 focus:gl-not-sr-only"
203+
class="super-sidebar-skip-to gl-sr-only !gl-fixed gl-left-0 !gl-m-3 !gl-px-4 focus:gl-not-sr-only"
204204
data-testid="super-sidebar-skip-to"
205205
href="#content-body"
206206
variant="confirm"

0 commit comments

Comments
 (0)