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
6701c46a
Commit
6701c46a
authored
Nov 20, 2018
by
Martin Wortschack
Committed by
Phil Hughes
Nov 20, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Resolve "Further UI improvements to Profile "Overview" tab"
parent
91221cd7
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
98 additions
and
106 deletions
+98
-106
app/assets/javascripts/pages/users/user_overview_block.js
app/assets/javascripts/pages/users/user_overview_block.js
+5
-0
app/assets/javascripts/pages/users/user_tabs.js
app/assets/javascripts/pages/users/user_tabs.js
+53
-57
app/views/users/_overview.html.haml
app/views/users/_overview.html.haml
+19
-21
app/views/users/show.html.haml
app/views/users/show.html.haml
+0
-6
changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml
...52712-further-ui-improvements-to-profile-overview-tab.yml
+5
-0
locale/gitlab.pot
locale/gitlab.pot
+0
-6
spec/features/calendar_spec.rb
spec/features/calendar_spec.rb
+12
-12
spec/features/users/overview_spec.rb
spec/features/users/overview_spec.rb
+4
-4
No files found.
app/assets/javascripts/pages/users/user_overview_block.js
View file @
6701c46a
...
@@ -10,6 +10,7 @@ export default class UserOverviewBlock {
...
@@ -10,6 +10,7 @@ export default class UserOverviewBlock {
limit
:
DEFAULT_LIMIT
,
limit
:
DEFAULT_LIMIT
,
...
options
.
requestParams
,
...
options
.
requestParams
,
};
};
this
.
postRenderCallback
=
options
.
postRenderCallback
;
this
.
loadData
();
this
.
loadData
();
}
}
...
@@ -43,5 +44,9 @@ export default class UserOverviewBlock {
...
@@ -43,5 +44,9 @@ export default class UserOverviewBlock {
}
}
loadingEl
.
classList
.
add
(
'
hide
'
);
loadingEl
.
classList
.
add
(
'
hide
'
);
if
(
this
.
postRenderCallback
)
{
this
.
postRenderCallback
.
call
(
this
);
}
}
}
}
}
app/assets/javascripts/pages/users/user_tabs.js
View file @
6701c46a
...
@@ -2,7 +2,8 @@ import $ from 'jquery';
...
@@ -2,7 +2,8 @@ import $ from 'jquery';
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
Activities
from
'
~/activities
'
;
import
Activities
from
'
~/activities
'
;
import
{
localTimeAgo
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
localTimeAgo
}
from
'
~/lib/utils/datetime_utility
'
;
import
{
__
,
sprintf
}
from
'
~/locale
'
;
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
{
__
}
from
'
~/locale
'
;
import
flash
from
'
~/flash
'
;
import
flash
from
'
~/flash
'
;
import
ActivityCalendar
from
'
./activity_calendar
'
;
import
ActivityCalendar
from
'
./activity_calendar
'
;
import
UserOverviewBlock
from
'
./user_overview_block
'
;
import
UserOverviewBlock
from
'
./user_overview_block
'
;
...
@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block';
...
@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block';
* </div>
* </div>
*/
*/
const
CALENDAR_TEMPLATES
=
{
const
CALENDAR_TEMPLATE
=
`
activity
:
`
<div class="clearfix calendar">
<div class="clearfix calendar">
<div class="js-contrib-calendar"></div>
<div class="js-contrib-calendar"></div>
<div class="calendar-hint bottom-right"></div>
<div class="calendar-hint bottom-right"></div>
</div>
</div>
`
;
`
,
overview
:
`
<div class="clearfix calendar">
<div class="calendar-hint"></div>
<div class="js-contrib-calendar prepend-top-20"></div>
</div>
`
,
};
const
CALENDAR_PERIOD_6_MONTHS
=
6
;
const
CALENDAR_PERIOD_6_MONTHS
=
6
;
const
CALENDAR_PERIOD_12_MONTHS
=
12
;
const
CALENDAR_PERIOD_12_MONTHS
=
12
;
/* computation based on
* width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
* (see activity_calendar.js)
*/
const
OVERVIEW_CALENDAR_BREAKPOINT
=
918
;
export
default
class
UserTabs
{
export
default
class
UserTabs
{
constructor
({
defaultAction
,
action
,
parentEl
})
{
constructor
({
defaultAction
,
action
,
parentEl
})
{
...
@@ -105,6 +103,12 @@ export default class UserTabs {
...
@@ -105,6 +103,12 @@ export default class UserTabs {
.
off
(
'
shown.bs.tab
'
,
'
.nav-links a[data-toggle="tab"]
'
)
.
off
(
'
shown.bs.tab
'
,
'
.nav-links a[data-toggle="tab"]
'
)
.
on
(
'
shown.bs.tab
'
,
'
.nav-links a[data-toggle="tab"]
'
,
event
=>
this
.
tabShown
(
event
))
.
on
(
'
shown.bs.tab
'
,
'
.nav-links a[data-toggle="tab"]
'
,
event
=>
this
.
tabShown
(
event
))
.
on
(
'
click
'
,
'
.gl-pagination a
'
,
event
=>
this
.
changeProjectsPage
(
event
));
.
on
(
'
click
'
,
'
.gl-pagination a
'
,
event
=>
this
.
changeProjectsPage
(
event
));
window
.
addEventListener
(
'
resize
'
,
()
=>
this
.
onResize
());
}
onResize
()
{
this
.
loadActivityCalendar
();
}
}
changeProjectsPage
(
e
)
{
changeProjectsPage
(
e
)
{
...
@@ -167,8 +171,6 @@ export default class UserTabs {
...
@@ -167,8 +171,6 @@ export default class UserTabs {
return
;
return
;
}
}
this
.
loadActivityCalendar
(
'
activity
'
);
// eslint-disable-next-line no-new
// eslint-disable-next-line no-new
new
Activities
(
'
#activity
'
);
new
Activities
(
'
#activity
'
);
...
@@ -180,10 +182,10 @@ export default class UserTabs {
...
@@ -180,10 +182,10 @@ export default class UserTabs {
return
;
return
;
}
}
this
.
loadActivityCalendar
(
'
overview
'
);
this
.
loadActivityCalendar
();
UserTabs
.
renderMostRecentBlocks
(
'
#js-overview .activities-block
'
,
{
UserTabs
.
renderMostRecentBlocks
(
'
#js-overview .activities-block
'
,
{
requestParams
:
{
limit
:
5
},
requestParams
:
{
limit
:
10
},
});
});
UserTabs
.
renderMostRecentBlocks
(
'
#js-overview .projects-block
'
,
{
UserTabs
.
renderMostRecentBlocks
(
'
#js-overview .projects-block
'
,
{
requestParams
:
{
limit
:
10
,
skip_pagination
:
true
},
requestParams
:
{
limit
:
10
,
skip_pagination
:
true
},
...
@@ -198,52 +200,39 @@ export default class UserTabs {
...
@@ -198,52 +200,39 @@ export default class UserTabs {
container
,
container
,
url
:
$
(
`
${
container
}
.overview-content-list`
).
data
(
'
href
'
),
url
:
$
(
`
${
container
}
.overview-content-list`
).
data
(
'
href
'
),
...
options
,
...
options
,
postRenderCallback
:
()
=>
localTimeAgo
(
$
(
'
.js-timeago
'
,
container
)),
});
});
}
}
loadActivityCalendar
(
action
)
{
loadActivityCalendar
()
{
const
monthsAgo
=
action
===
'
overview
'
?
CALENDAR_PERIOD_6_MONTHS
:
CALENDAR_PERIOD_12_MONTHS
;
const
$calendarWrap
=
this
.
$parentEl
.
find
(
'
.tab-pane.active .user-calendar
'
);
const
$calendarWrap
=
this
.
$parentEl
.
find
(
'
.tab-pane.active .user-calendar
'
);
const
calendarPath
=
$calendarWrap
.
data
(
'
calendarPath
'
);
const
calendarPath
=
$calendarWrap
.
data
(
'
calendarPath
'
);
AjaxCache
.
retrieve
(
calendarPath
)
.
then
(
data
=>
UserTabs
.
renderActivityCalendar
(
data
,
$calendarWrap
))
.
catch
(()
=>
flash
(
__
(
'
There was an error loading users activity calendar.
'
)));
}
static
renderActivityCalendar
(
data
,
$calendarWrap
)
{
const
monthsAgo
=
UserTabs
.
getVisibleCalendarPeriod
(
$calendarWrap
);
const
calendarActivitiesPath
=
$calendarWrap
.
data
(
'
calendarActivitiesPath
'
);
const
calendarActivitiesPath
=
$calendarWrap
.
data
(
'
calendarActivitiesPath
'
);
const
utcOffset
=
$calendarWrap
.
data
(
'
utcOffset
'
);
const
utcOffset
=
$calendarWrap
.
data
(
'
utcOffset
'
);
let
utcFormatted
=
'
UTC
'
;
const
calendarHint
=
__
(
'
Issues, merge requests, pushes and comments.
'
);
if
(
utcOffset
!==
0
)
{
utcFormatted
=
`UTC
${
utcOffset
>
0
?
'
+
'
:
''
}${
utcOffset
/
3600
}
`
;
}
axios
$calendarWrap
.
html
(
CALENDAR_TEMPLATE
);
.
get
(
calendarPath
)
.
then
(({
data
})
=>
{
$calendarWrap
.
find
(
'
.calendar-hint
'
).
text
(
calendarHint
);
$calendarWrap
.
html
(
CALENDAR_TEMPLATES
[
action
]);
// eslint-disable-next-line no-new
let
calendarHint
=
''
;
new
ActivityCalendar
(
'
.tab-pane.active .js-contrib-calendar
'
,
if
(
action
===
'
activity
'
)
{
'
.tab-pane.active .user-calendar-activities
'
,
calendarHint
=
sprintf
(
data
,
__
(
calendarActivitiesPath
,
'
Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})
'
,
utcOffset
,
),
0
,
{
utcFormatted
},
monthsAgo
,
);
);
}
else
if
(
action
===
'
overview
'
)
{
calendarHint
=
__
(
'
Issues, merge requests, pushes and comments.
'
);
}
$calendarWrap
.
find
(
'
.calendar-hint
'
).
text
(
calendarHint
);
// eslint-disable-next-line no-new
new
ActivityCalendar
(
'
.tab-pane.active .js-contrib-calendar
'
,
'
.tab-pane.active .user-calendar-activities
'
,
data
,
calendarActivitiesPath
,
utcOffset
,
0
,
monthsAgo
,
);
})
.
catch
(()
=>
flash
(
__
(
'
There was an error loading users activity calendar.
'
)));
}
}
toggleLoading
(
status
)
{
toggleLoading
(
status
)
{
...
@@ -267,4 +256,11 @@ export default class UserTabs {
...
@@ -267,4 +256,11 @@ export default class UserTabs {
getCurrentAction
()
{
getCurrentAction
()
{
return
this
.
$parentEl
.
find
(
'
.nav-links a.active
'
).
data
(
'
action
'
);
return
this
.
$parentEl
.
find
(
'
.nav-links a.active
'
).
data
(
'
action
'
);
}
}
static
getVisibleCalendarPeriod
(
$calendarWrap
)
{
const
width
=
$calendarWrap
.
width
();
return
width
<
OVERVIEW_CALENDAR_BREAKPOINT
?
CALENDAR_PERIOD_6_MONTHS
:
CALENDAR_PERIOD_12_MONTHS
;
}
}
}
app/views/users/_overview.html.haml
View file @
6701c46a
.row
.col-12
.calendar-block.prepend-top-default.append-bottom-default
.user-calendar.d-none.d-sm-block
{
data:
{
calendar_path:
user_calendar_path
(
@user
,
:json
),
calendar_activities_path:
user_calendar_activities_path
,
utc_offset:
Time
.
zone
.
utc_offset
}
}
%h4
.center.light
=
spinner
nil
,
true
.user-calendar-activities.d-none.d-sm-block
.row
.row
.col-md-12.col-lg-6
.col-md-12.col-lg-6
.calendar-block
.content-block.hide-bottom-border
%h4
=
s_
(
'UserProfile|Activity'
)
.user-calendar.d-none.d-sm-block.text-left
{
data:
{
calendar_path:
user_calendar_path
(
@user
,
:json
),
calendar_activities_path:
user_calendar_activities_path
,
utc_offset:
Time
.
zone
.
utc_offset
}
}
%h4
.center.light
%i
.fa.fa-spinner.fa-spin
.user-calendar-activities.d-none.d-sm-block
-
if
can?
(
current_user
,
:read_cross_project
)
-
if
can?
(
current_user
,
:read_cross_project
)
.activities-block
.activities-block
.border-bottom.prepend-top-16
.prepend-top-16
%h5
.d-flex.align-items-center.border-bottom
=
s_
(
'UserProfile|Recent contributions'
)
%h4
.flex-grow
=
s_
(
'UserProfile|Activity'
)
=
link_to
s_
(
'UserProfile|View all'
),
user_activity_path
,
class:
"hide js-view-all"
.overview-content-list
{
data:
{
href:
user_path
}
}
.overview-content-list
{
data:
{
href:
user_path
}
}
.center.light.loading
.center.light.loading
%i
.fa.fa-spinner.fa-spin
=
spinner
nil
,
true
.prepend-top-10
=
link_to
s_
(
'UserProfile|View all'
),
user_activity_path
,
class:
"hide js-view-all"
.col-md-12.col-lg-6
.col-md-12.col-lg-6
.projects-block
.projects-block
.border-bottom.prepend-top-16
.prepend-top-16
%h4
.d-flex.align-items-center.border-bottom
=
s_
(
'UserProfile|Personal projects'
)
%h4
.flex-grow
=
s_
(
'UserProfile|Personal projects'
)
=
link_to
s_
(
'UserProfile|View all'
),
user_projects_path
,
class:
"hide js-view-all"
.overview-content-list
{
data:
{
href:
user_projects_path
}
}
.overview-content-list
{
data:
{
href:
user_projects_path
}
}
.center.light.loading
.center.light.loading
%i
.fa.fa-spinner.fa-spin
=
spinner
nil
,
true
.prepend-top-10
=
link_to
s_
(
'UserProfile|View all'
),
user_projects_path
,
class:
"hide js-view-all"
app/views/users/show.html.haml
View file @
6701c46a
...
@@ -124,12 +124,6 @@
...
@@ -124,12 +124,6 @@
-
if
profile_tab?
(
:activity
)
-
if
profile_tab?
(
:activity
)
#activity
.tab-pane
#activity
.tab-pane
.row-content-block.calendar-block.white.second-block.d-none.d-sm-block
.user-calendar
{
data:
{
calendar_path:
user_calendar_path
(
@user
,
:json
),
calendar_activities_path:
user_calendar_activities_path
,
utc_offset:
Time
.
zone
.
utc_offset
}
}
%h4
.center.light
%i
.fa.fa-spinner.fa-spin
.user-calendar-activities
-
if
can?
(
current_user
,
:read_cross_project
)
-
if
can?
(
current_user
,
:read_cross_project
)
%h4
.prepend-top-20
%h4
.prepend-top-20
=
s_
(
'UserProfile|Most Recent Activity'
)
=
s_
(
'UserProfile|Most Recent Activity'
)
...
...
changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml
0 → 100644
View file @
6701c46a
---
title
:
UI improvements to user's profile
merge_request
:
22977
author
:
type
:
other
locale/gitlab.pot
View file @
6701c46a
...
@@ -5961,9 +5961,6 @@ msgstr ""
...
@@ -5961,9 +5961,6 @@ msgstr ""
msgid "Subscribed"
msgid "Subscribed"
msgstr ""
msgstr ""
msgid "Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})"
msgstr ""
msgid "Switch branch/tag"
msgid "Switch branch/tag"
msgstr ""
msgstr ""
...
@@ -6837,9 +6834,6 @@ msgstr ""
...
@@ -6837,9 +6834,6 @@ msgstr ""
msgid "UserProfile|Personal projects"
msgid "UserProfile|Personal projects"
msgstr ""
msgstr ""
msgid "UserProfile|Recent contributions"
msgstr ""
msgid "UserProfile|Report abuse"
msgid "UserProfile|Report abuse"
msgstr ""
msgstr ""
...
...
spec/features/calendar_spec.rb
View file @
6701c46a
...
@@ -64,7 +64,7 @@ describe 'Contributions Calendar', :js do
...
@@ -64,7 +64,7 @@ describe 'Contributions Calendar', :js do
end
end
def
selected_day_activities
(
visible:
true
)
def
selected_day_activities
(
visible:
true
)
find
(
'
.tab-pane#activity
.user-calendar-activities'
,
visible:
visible
).
text
find
(
'
#js-overview
.user-calendar-activities'
,
visible:
visible
).
text
end
end
before
do
before
do
...
@@ -74,16 +74,16 @@ describe 'Contributions Calendar', :js do
...
@@ -74,16 +74,16 @@ describe 'Contributions Calendar', :js do
describe
'calendar day selection'
do
describe
'calendar day selection'
do
before
do
before
do
visit
user
.
username
visit
user
.
username
page
.
find
(
'.js-
activity
-tab a'
).
click
page
.
find
(
'.js-
overview
-tab a'
).
click
wait_for_requests
wait_for_requests
end
end
it
'displays calendar'
do
it
'displays calendar'
do
expect
(
find
(
'
.tab-pane#activity
'
)).
to
have_css
(
'.js-contrib-calendar'
)
expect
(
find
(
'
#js-overview
'
)).
to
have_css
(
'.js-contrib-calendar'
)
end
end
describe
'select calendar day'
do
describe
'select calendar day'
do
let
(
:cells
)
{
page
.
all
(
'
.tab-pane#activity
.user-contrib-cell'
)
}
let
(
:cells
)
{
page
.
all
(
'
#js-overview
.user-contrib-cell'
)
}
before
do
before
do
cells
[
0
].
click
cells
[
0
].
click
...
@@ -109,7 +109,7 @@ describe 'Contributions Calendar', :js do
...
@@ -109,7 +109,7 @@ describe 'Contributions Calendar', :js do
describe
'deselect calendar day'
do
describe
'deselect calendar day'
do
before
do
before
do
cells
[
0
].
click
cells
[
0
].
click
page
.
find
(
'.js-
activity
-tab a'
).
click
page
.
find
(
'.js-
overview
-tab a'
).
click
wait_for_requests
wait_for_requests
end
end
...
@@ -124,7 +124,7 @@ describe 'Contributions Calendar', :js do
...
@@ -124,7 +124,7 @@ describe 'Contributions Calendar', :js do
shared_context
'visit user page'
do
shared_context
'visit user page'
do
before
do
before
do
visit
user
.
username
visit
user
.
username
page
.
find
(
'.js-
activity
-tab a'
).
click
page
.
find
(
'.js-
overview
-tab a'
).
click
wait_for_requests
wait_for_requests
end
end
end
end
...
@@ -133,12 +133,12 @@ describe 'Contributions Calendar', :js do
...
@@ -133,12 +133,12 @@ describe 'Contributions Calendar', :js do
include_context
'visit user page'
include_context
'visit user page'
it
'displays calendar activity square color for 1 contribution'
do
it
'displays calendar activity square color for 1 contribution'
do
expect
(
find
(
'
.tab-pane#activity
'
)).
to
have_selector
(
get_cell_color_selector
(
contribution_count
),
count:
1
)
expect
(
find
(
'
#js-overview
'
)).
to
have_selector
(
get_cell_color_selector
(
contribution_count
),
count:
1
)
end
end
it
'displays calendar activity square on the correct date'
do
it
'displays calendar activity square on the correct date'
do
today
=
Date
.
today
.
strftime
(
date_format
)
today
=
Date
.
today
.
strftime
(
date_format
)
expect
(
find
(
'
.tab-pane#activity
'
)).
to
have_selector
(
get_cell_date_selector
(
contribution_count
,
today
),
count:
1
)
expect
(
find
(
'
#js-overview
'
)).
to
have_selector
(
get_cell_date_selector
(
contribution_count
,
today
),
count:
1
)
end
end
end
end
...
@@ -153,7 +153,7 @@ describe 'Contributions Calendar', :js do
...
@@ -153,7 +153,7 @@ describe 'Contributions Calendar', :js do
include_context
'visit user page'
include_context
'visit user page'
it
'displays calendar activity log'
do
it
'displays calendar activity log'
do
expect
(
find
(
'
.tab-pane#activity .content_
list .event-target-title'
)).
to
have_content
issue_title
expect
(
find
(
'
#js-overview .overview-content-
list .event-target-title'
)).
to
have_content
issue_title
end
end
end
end
end
end
...
@@ -185,17 +185,17 @@ describe 'Contributions Calendar', :js do
...
@@ -185,17 +185,17 @@ describe 'Contributions Calendar', :js do
include_context
'visit user page'
include_context
'visit user page'
it
'displays calendar activity squares for both days'
do
it
'displays calendar activity squares for both days'
do
expect
(
find
(
'
.tab-pane#activity
'
)).
to
have_selector
(
get_cell_color_selector
(
1
),
count:
2
)
expect
(
find
(
'
#js-overview
'
)).
to
have_selector
(
get_cell_color_selector
(
1
),
count:
2
)
end
end
it
'displays calendar activity square for yesterday'
do
it
'displays calendar activity square for yesterday'
do
yesterday
=
Date
.
yesterday
.
strftime
(
date_format
)
yesterday
=
Date
.
yesterday
.
strftime
(
date_format
)
expect
(
find
(
'
.tab-pane#activity
'
)).
to
have_selector
(
get_cell_date_selector
(
1
,
yesterday
),
count:
1
)
expect
(
find
(
'
#js-overview
'
)).
to
have_selector
(
get_cell_date_selector
(
1
,
yesterday
),
count:
1
)
end
end
it
'displays calendar activity square for today'
do
it
'displays calendar activity square for today'
do
today
=
Date
.
today
.
strftime
(
date_format
)
today
=
Date
.
today
.
strftime
(
date_format
)
expect
(
find
(
'
.tab-pane#activity
'
)).
to
have_selector
(
get_cell_date_selector
(
1
,
today
),
count:
1
)
expect
(
find
(
'
#js-overview
'
)).
to
have_selector
(
get_cell_date_selector
(
1
,
today
),
count:
1
)
end
end
end
end
end
end
...
...
spec/features/users/overview_spec.rb
View file @
6701c46a
...
@@ -54,15 +54,15 @@ describe 'Overview tab on a user profile', :js do
...
@@ -54,15 +54,15 @@ describe 'Overview tab on a user profile', :js do
end
end
end
end
describe
'user has 1
0
activities'
do
describe
'user has 1
1
activities'
do
before
do
before
do
1
0
.
times
{
push_code_contribution
}
1
1
.
times
{
push_code_contribution
}
end
end
include_context
'visit overview tab'
include_context
'visit overview tab'
it
'displays
5
entries in the list of activities'
do
it
'displays
10
entries in the list of activities'
do
expect
(
find
(
'#js-overview'
)).
to
have_selector
(
'.event-item'
,
count:
5
)
expect
(
find
(
'#js-overview'
)).
to
have_selector
(
'.event-item'
,
count:
10
)
end
end
it
'shows a link to the activity list'
do
it
'shows a link to the activity list'
do
...
...
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