Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
6141fc14
Commit
6141fc14
authored
Jul 08, 2021
by
Lukas 'Eipi' Eipert
Committed by
Ezekiel Kigbo
Jul 08, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable user setting for absolute dates
parent
cd7057b8
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
180 additions
and
79 deletions
+180
-79
app/assets/javascripts/lib/utils/datetime/timeago_utility.js
app/assets/javascripts/lib/utils/datetime/timeago_utility.js
+24
-5
app/views/profiles/preferences/show.html.haml
app/views/profiles/preferences/show.html.haml
+22
-24
doc/user/profile/preferences.md
doc/user/profile/preferences.md
+24
-0
lib/gitlab/gon_helper.rb
lib/gitlab/gon_helper.rb
+2
-0
locale/gitlab.pot
locale/gitlab.pot
+4
-10
spec/frontend/lib/utils/datetime/timeago_utility_spec.js
spec/frontend/lib/utils/datetime/timeago_utility_spec.js
+104
-0
spec/frontend/lib/utils/datetime_utility_spec.js
spec/frontend/lib/utils/datetime_utility_spec.js
+0
-40
No files found.
app/assets/javascripts/lib/utils/datetime/timeago_utility.js
View file @
6141fc14
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
*
as
timeago
from
'
timeago.js
'
;
import
*
as
timeago
from
'
timeago.js
'
;
import
{
languageCode
,
s__
}
from
'
../../../locale
'
;
import
{
languageCode
,
s__
,
createDateTimeFormat
}
from
'
../../../locale
'
;
import
{
formatDate
}
from
'
./date_format_utility
'
;
import
{
formatDate
}
from
'
./date_format_utility
'
;
window
.
timeago
=
timeago
;
/**
/**
* Timeago uses underscores instead of dashes to separate language from country code.
* Timeago uses underscores instead of dashes to separate language from country code.
*
*
...
@@ -76,7 +74,26 @@ const memoizedLocale = () => {
...
@@ -76,7 +74,26 @@ const memoizedLocale = () => {
timeago
.
register
(
timeagoLanguageCode
,
memoizedLocale
());
timeago
.
register
(
timeagoLanguageCode
,
memoizedLocale
());
timeago
.
register
(
`
${
timeagoLanguageCode
}
-remaining`
,
memoizedLocaleRemaining
());
timeago
.
register
(
`
${
timeagoLanguageCode
}
-remaining`
,
memoizedLocaleRemaining
());
export
const
getTimeago
=
()
=>
timeago
;
let
memoizedFormatter
=
null
;
function
setupAbsoluteFormatter
()
{
if
(
memoizedFormatter
===
null
)
{
const
formatter
=
createDateTimeFormat
({
dateStyle
:
'
medium
'
,
timeStyle
:
'
short
'
,
});
memoizedFormatter
=
{
format
(
date
)
{
return
formatter
.
format
(
date
instanceof
Date
?
date
:
new
Date
(
date
));
},
};
}
return
memoizedFormatter
;
}
export
const
getTimeago
=
()
=>
window
.
gon
?.
time_display_relative
===
false
?
setupAbsoluteFormatter
()
:
timeago
;
/**
/**
* For the given elements, sets a tooltip with a formatted date.
* For the given elements, sets a tooltip with a formatted date.
...
@@ -84,8 +101,9 @@ export const getTimeago = () => timeago;
...
@@ -84,8 +101,9 @@ export const getTimeago = () => timeago;
* @param {Boolean} setTimeago
* @param {Boolean} setTimeago
*/
*/
export
const
localTimeAgo
=
(
$timeagoEls
,
setTimeago
=
true
)
=>
{
export
const
localTimeAgo
=
(
$timeagoEls
,
setTimeago
=
true
)
=>
{
const
{
format
}
=
getTimeago
();
$timeagoEls
.
each
((
i
,
el
)
=>
{
$timeagoEls
.
each
((
i
,
el
)
=>
{
$
(
el
).
text
(
timeago
.
format
(
$
(
el
).
attr
(
'
datetime
'
),
timeagoLanguageCode
));
$
(
el
).
text
(
format
(
$
(
el
).
attr
(
'
datetime
'
),
timeagoLanguageCode
));
});
});
if
(
!
setTimeago
)
{
if
(
!
setTimeago
)
{
...
@@ -117,6 +135,7 @@ export const timeFor = (time, expiredLabel) => {
...
@@ -117,6 +135,7 @@ export const timeFor = (time, expiredLabel) => {
return
timeago
.
format
(
time
,
`
${
timeagoLanguageCode
}
-remaining`
).
trim
();
return
timeago
.
format
(
time
,
`
${
timeagoLanguageCode
}
-remaining`
).
trim
();
};
};
window
.
timeago
=
getTimeago
();
window
.
gl
=
window
.
gl
||
{};
window
.
gl
=
window
.
gl
||
{};
window
.
gl
.
utils
=
{
window
.
gl
.
utils
=
{
...(
window
.
gl
.
utils
||
{}),
...(
window
.
gl
.
utils
||
{}),
...
...
app/views/profiles/preferences/show.html.haml
View file @
6141fc14
...
@@ -128,29 +128,27 @@
...
@@ -128,29 +128,27 @@
=
f
.
label
:first_day_of_week
,
class:
'label-bold'
do
=
f
.
label
:first_day_of_week
,
class:
'label-bold'
do
=
_
(
'First day of the week'
)
=
_
(
'First day of the week'
)
=
f
.
select
:first_day_of_week
,
first_day_of_week_choices_with_default
,
{},
class:
'select2'
=
f
.
select
:first_day_of_week
,
first_day_of_week_choices_with_default
,
{},
class:
'select2'
-
if
Feature
.
enabled?
(
:user_time_settings
)
.col-sm-12
.col-sm-12
%hr
%hr
.col-lg-4.profile-settings-sidebar
.row.js-preferences-form.js-search-settings-section
%h4
.gl-mt-0
=
s_
(
'Preferences|Time preferences'
)
.col-lg-4.profile-settings-sidebar
#time-preferences
%p
=
s_
(
'Preferences|These settings will update how dates and times are displayed for you.'
)
%h4
.gl-mt-0
=
s_
(
'Preferences|Time preferences'
)
%p
=
s_
(
'Preferences|Configure how dates and times display for you.'
)
=
succeed
'.'
do
=
link_to
_
(
'Learn more'
),
help_page_path
(
'user/profile/preferences'
,
anchor:
'time-preferences'
),
target:
'_blank'
.col-lg-8
.col-lg-8
.form-group
.form-group.form-check
%h5
=
s_
(
'Preferences|Time format'
)
=
f
.
check_box
:time_display_relative
,
class:
'form-check-input'
.checkbox-icon-inline-wrapper
=
f
.
label
:time_display_relative
,
class:
'form-check-label'
do
-
time_format_label
=
capture
do
=
s_
(
'Preferences|Display time in 24-hour format'
)
=
f
.
check_box
:time_format_in_24h
=
f
.
label
:time_format_in_24h
do
=
time_format_label
%h5
=
s_
(
'Preferences|Time display'
)
.checkbox-icon-inline-wrapper
-
time_display_label
=
capture
do
=
s_
(
'Preferences|Use relative times'
)
=
s_
(
'Preferences|Use relative times'
)
=
f
.
check_box
:time_display_relative
=
f
.
label
:time_display_relative
do
=
time_display_label
.form-text.text-muted
.form-text.text-muted
=
s_
(
'Preferences|For example: 30 mins ago.'
)
=
s_
(
'Preferences|For example: 30 minutes ago.'
)
-
if
Feature
.
enabled?
(
:user_time_settings
)
.form-group.form-check
=
f
.
check_box
:time_format_in_24h
,
class:
'form-check-input'
=
f
.
label
:time_format_in_24h
,
class:
'form-check-label'
do
=
s_
(
'Preferences|Display time in 24-hour format'
)
#js-profile-preferences-app
{
data:
data_attributes
}
#js-profile-preferences-app
{
data:
data_attributes
}
doc/user/profile/preferences.md
View file @
6141fc14
...
@@ -165,6 +165,30 @@ You can choose one of the following options as the first day of the week:
...
@@ -165,6 +165,30 @@ You can choose one of the following options as the first day of the week:
If you select
**System Default**
, the
[
instance default
](
../admin_area/settings/index.md#default-first-day-of-the-week
)
setting is used.
If you select
**System Default**
, the
[
instance default
](
../admin_area/settings/index.md#default-first-day-of-the-week
)
setting is used.
## Time preferences
### Use relative times
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65570) in GitLab 14.1.
You can select your preferred time format for the GitLab user interface:
-
Relative times, for example,
`30 minutes ago`
.
-
Absolute times, for example,
`May 18, 2021, 3:57 PM`
.
The times are formatted depending on your chosen language.
To set your time preference:
1.
On the
**Preferences**
page, go to
**Time preferences**
.
1.
Select the
**Use relative times**
checkbox to use relative times,
or clear the checkbox to use absolute times.
1.
Select
**Save changes**
.
NOTE:
This feature is experimental, and choosing absolute times might break certain layouts.
Please open an issue if you notice that using absolute times breaks a layout.
## Integrations
## Integrations
Configure your preferences with third-party services which provide enhancements to your GitLab experience.
Configure your preferences with third-party services which provide enhancements to your GitLab experience.
...
...
lib/gitlab/gon_helper.rb
View file @
6141fc14
...
@@ -33,6 +33,7 @@ module Gitlab
...
@@ -33,6 +33,7 @@ module Gitlab
gon
.
disable_animations
=
Gitlab
.
config
.
gitlab
[
'disable_animations'
]
gon
.
disable_animations
=
Gitlab
.
config
.
gitlab
[
'disable_animations'
]
gon
.
suggested_label_colors
=
LabelsHelper
.
suggested_colors
gon
.
suggested_label_colors
=
LabelsHelper
.
suggested_colors
gon
.
first_day_of_week
=
current_user
&
.
first_day_of_week
||
Gitlab
::
CurrentSettings
.
first_day_of_week
gon
.
first_day_of_week
=
current_user
&
.
first_day_of_week
||
Gitlab
::
CurrentSettings
.
first_day_of_week
gon
.
time_display_relative
=
true
gon
.
ee
=
Gitlab
.
ee?
gon
.
ee
=
Gitlab
.
ee?
gon
.
dot_com
=
Gitlab
.
com?
gon
.
dot_com
=
Gitlab
.
com?
...
@@ -41,6 +42,7 @@ module Gitlab
...
@@ -41,6 +42,7 @@ module Gitlab
gon
.
current_username
=
current_user
.
username
gon
.
current_username
=
current_user
.
username
gon
.
current_user_fullname
=
current_user
.
name
gon
.
current_user_fullname
=
current_user
.
name
gon
.
current_user_avatar_url
=
current_user
.
avatar_url
gon
.
current_user_avatar_url
=
current_user
.
avatar_url
gon
.
time_display_relative
=
current_user
.
time_display_relative
end
end
# Initialize gon.features with any flags that should be
# Initialize gon.features with any flags that should be
...
...
locale/gitlab.pot
View file @
6141fc14
...
@@ -24655,6 +24655,9 @@ msgstr ""
...
@@ -24655,6 +24655,9 @@ msgstr ""
msgid "Preferences|Choose what content you want to see on your homepage."
msgid "Preferences|Choose what content you want to see on your homepage."
msgstr ""
msgstr ""
msgid "Preferences|Configure how dates and times display for you."
msgstr ""
msgid "Preferences|Customize integrations with third party services."
msgid "Preferences|Customize integrations with third party services."
msgstr ""
msgstr ""
...
@@ -24673,7 +24676,7 @@ msgstr ""
...
@@ -24673,7 +24676,7 @@ msgstr ""
msgid "Preferences|Failed to save preferences."
msgid "Preferences|Failed to save preferences."
msgstr ""
msgstr ""
msgid "Preferences|For example: 30 mins ago."
msgid "Preferences|For example: 30 min
ute
s ago."
msgstr ""
msgstr ""
msgid "Preferences|Gitpod"
msgid "Preferences|Gitpod"
...
@@ -24721,9 +24724,6 @@ msgstr ""
...
@@ -24721,9 +24724,6 @@ msgstr ""
msgid "Preferences|Tab width"
msgid "Preferences|Tab width"
msgstr ""
msgstr ""
msgid "Preferences|These settings will update how dates and times are displayed for you."
msgstr ""
msgid "Preferences|This feature is experimental and translations are not complete yet"
msgid "Preferences|This feature is experimental and translations are not complete yet"
msgstr ""
msgstr ""
...
@@ -24733,12 +24733,6 @@ msgstr ""
...
@@ -24733,12 +24733,6 @@ msgstr ""
msgid "Preferences|This setting allows you to customize the behavior of the system layout and default views."
msgid "Preferences|This setting allows you to customize the behavior of the system layout and default views."
msgstr ""
msgstr ""
msgid "Preferences|Time display"
msgstr ""
msgid "Preferences|Time format"
msgstr ""
msgid "Preferences|Time preferences"
msgid "Preferences|Time preferences"
msgstr ""
msgstr ""
...
...
spec/frontend/lib/utils/datetime/timeago_utility_spec.js
0 → 100644
View file @
6141fc14
import
$
from
'
jquery
'
;
import
{
getTimeago
,
localTimeAgo
,
timeFor
}
from
'
~/lib/utils/datetime/timeago_utility
'
;
import
{
s__
}
from
'
~/locale
'
;
import
'
~/commons/bootstrap
'
;
describe
(
'
TimeAgo utils
'
,
()
=>
{
let
oldGon
;
afterEach
(()
=>
{
window
.
gon
=
oldGon
;
});
beforeEach
(()
=>
{
oldGon
=
window
.
gon
;
});
describe
(
'
getTimeago
'
,
()
=>
{
describe
(
'
with User Setting timeDisplayRelative: true
'
,
()
=>
{
beforeEach
(()
=>
{
window
.
gon
=
{
time_display_relative
:
true
};
});
it
.
each
([
[
new
Date
().
toISOString
(),
'
just now
'
],
[
new
Date
().
getTime
(),
'
just now
'
],
[
new
Date
(),
'
just now
'
],
[
null
,
'
just now
'
],
])(
'
formats date `%p` as `%p`
'
,
(
date
,
result
)
=>
{
expect
(
getTimeago
().
format
(
date
)).
toEqual
(
result
);
});
});
describe
(
'
with User Setting timeDisplayRelative: false
'
,
()
=>
{
beforeEach
(()
=>
{
window
.
gon
=
{
time_display_relative
:
false
};
});
it
.
each
([
[
new
Date
().
toISOString
(),
'
Jul 6, 2020, 12:00 AM
'
],
[
new
Date
(),
'
Jul 6, 2020, 12:00 AM
'
],
[
new
Date
().
getTime
(),
'
Jul 6, 2020, 12:00 AM
'
],
// Slightly different behaviour when `null` is passed :see_no_evil`
[
null
,
'
Jan 1, 1970, 12:00 AM
'
],
])(
'
formats date `%p` as `%p`
'
,
(
date
,
result
)
=>
{
expect
(
getTimeago
().
format
(
date
)).
toEqual
(
result
);
});
});
});
describe
(
'
timeFor
'
,
()
=>
{
it
(
'
returns localize `past due` when in past
'
,
()
=>
{
const
date
=
new
Date
();
date
.
setFullYear
(
date
.
getFullYear
()
-
1
);
expect
(
timeFor
(
date
)).
toBe
(
s__
(
'
Timeago|Past due
'
));
});
it
(
'
returns localized remaining time when in the future
'
,
()
=>
{
const
date
=
new
Date
();
date
.
setFullYear
(
date
.
getFullYear
()
+
1
);
// Add a day to prevent a transient error. If date is even 1 second
// short of a full year, timeFor will return '11 months remaining'
date
.
setDate
(
date
.
getDate
()
+
1
);
expect
(
timeFor
(
date
)).
toBe
(
s__
(
'
Timeago|1 year remaining
'
));
});
});
describe
(
'
localTimeAgo
'
,
()
=>
{
beforeEach
(()
=>
{
document
.
body
.
innerHTML
=
'
<time title="some time" datetime="2020-02-18T22:22:32Z">1 hour ago</time>
'
;
});
describe
.
each
`
timeDisplayRelative | text
${
true
}
|
${
'
4 months ago
'
}
${
false
}
|
${
'
Feb 18, 2020, 10:22 PM
'
}
`
(
`With User Setting timeDisplayRelative: $timeDisplayRelative`
,
({
timeDisplayRelative
,
text
})
=>
{
it
.
each
`
timeagoArg | title
${
false
}
|
${
'
some time
'
}
${
true
}
|
${
'
Feb 18, 2020 10:22pm UTC
'
}
`
(
`has content: '
${
text
}
' and tooltip: '$title' with timeagoArg = $timeagoArg`
,
({
timeagoArg
,
title
})
=>
{
window
.
gon
=
{
time_display_relative
:
timeDisplayRelative
};
const
element
=
document
.
querySelector
(
'
time
'
);
localTimeAgo
(
$
(
element
),
timeagoArg
);
jest
.
runAllTimers
();
expect
(
element
.
getAttribute
(
'
title
'
)).
toBe
(
title
);
expect
(
element
.
innerText
).
toBe
(
text
);
},
);
},
);
});
});
spec/frontend/lib/utils/datetime_utility_spec.js
View file @
6141fc14
import
$
from
'
jquery
'
;
import
timezoneMock
from
'
timezone-mock
'
;
import
timezoneMock
from
'
timezone-mock
'
;
import
*
as
datetimeUtility
from
'
~/lib/utils/datetime_utility
'
;
import
*
as
datetimeUtility
from
'
~/lib/utils/datetime_utility
'
;
import
{
__
,
s__
}
from
'
~/locale
'
;
import
{
__
,
s__
}
from
'
~/locale
'
;
import
'
~/commons/bootstrap
'
;
import
'
~/commons/bootstrap
'
;
describe
(
'
Date time utils
'
,
()
=>
{
describe
(
'
Date time utils
'
,
()
=>
{
describe
(
'
timeFor
'
,
()
=>
{
it
(
'
returns localize `past due` when in past
'
,
()
=>
{
const
date
=
new
Date
();
date
.
setFullYear
(
date
.
getFullYear
()
-
1
);
expect
(
datetimeUtility
.
timeFor
(
date
)).
toBe
(
s__
(
'
Timeago|Past due
'
));
});
it
(
'
returns localized remaining time when in the future
'
,
()
=>
{
const
date
=
new
Date
();
date
.
setFullYear
(
date
.
getFullYear
()
+
1
);
// Add a day to prevent a transient error. If date is even 1 second
// short of a full year, timeFor will return '11 months remaining'
date
.
setDate
(
date
.
getDate
()
+
1
);
expect
(
datetimeUtility
.
timeFor
(
date
)).
toBe
(
s__
(
'
Timeago|1 year remaining
'
));
});
});
describe
(
'
get localized day name
'
,
()
=>
{
describe
(
'
get localized day name
'
,
()
=>
{
it
(
'
should return Sunday
'
,
()
=>
{
it
(
'
should return Sunday
'
,
()
=>
{
const
day
=
datetimeUtility
.
getDayName
(
new
Date
(
'
07/17/2016
'
));
const
day
=
datetimeUtility
.
getDayName
(
new
Date
(
'
07/17/2016
'
));
...
@@ -870,25 +849,6 @@ describe('approximateDuration', () => {
...
@@ -870,25 +849,6 @@ describe('approximateDuration', () => {
});
});
});
});
describe
(
'
localTimeAgo
'
,
()
=>
{
beforeEach
(()
=>
{
document
.
body
.
innerHTML
=
`<time title="some time" datetime="2020-02-18T22:22:32Z">1 hour ago</time>`
;
});
it
.
each
`
timeagoArg | title
${
false
}
|
${
'
some time
'
}
${
true
}
|
${
'
Feb 18, 2020 10:22pm UTC
'
}
`
(
'
converts $seconds seconds to $approximation
'
,
({
timeagoArg
,
title
})
=>
{
const
element
=
document
.
querySelector
(
'
time
'
);
datetimeUtility
.
localTimeAgo
(
$
(
element
),
timeagoArg
);
jest
.
runAllTimers
();
expect
(
element
.
getAttribute
(
'
title
'
)).
toBe
(
title
);
});
});
describe
(
'
differenceInSeconds
'
,
()
=>
{
describe
(
'
differenceInSeconds
'
,
()
=>
{
const
startDateTime
=
new
Date
(
'
2019-07-17T00:00:00.000Z
'
);
const
startDateTime
=
new
Date
(
'
2019-07-17T00:00:00.000Z
'
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment