mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-12 16:35:52 +01:00
Improve issue creation form
This commit is contained in:
@@ -257,6 +257,12 @@ trait IssuesControllerBase extends ControllerBase {
|
|||||||
} getOrElse NotFound
|
} getOrElse NotFound
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ajaxPost("/:owner/:repository/issues/new/label")(collaboratorsOnly { repository =>
|
||||||
|
val labelNames = params("labelNames").split(",")
|
||||||
|
val labels = getLabels(repository.owner, repository.name).filter(x => labelNames.contains(x.labelName))
|
||||||
|
html.labellist(labels)
|
||||||
|
})
|
||||||
|
|
||||||
ajaxPost("/:owner/:repository/issues/:id/label/new")(collaboratorsOnly { repository =>
|
ajaxPost("/:owner/:repository/issues/:id/label/new")(collaboratorsOnly { repository =>
|
||||||
defining(params("id").toInt){ issueId =>
|
defining(params("id").toInt){ issueId =>
|
||||||
registerIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt)
|
registerIssueLabel(repository.owner, repository.name, issueId, params("labelId").toInt)
|
||||||
|
|||||||
@@ -11,52 +11,12 @@
|
|||||||
<br/><br/><hr style="margin-bottom: 10px;">
|
<br/><br/><hr style="margin-bottom: 10px;">
|
||||||
<form action="@url(repository)/issues/new" method="POST" validate="true">
|
<form action="@url(repository)/issues/new" method="POST" validate="true">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span9">
|
<div class="span10">
|
||||||
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
<div class="issue-avatar-image">@avatar(loginAccount.get.userName, 48)</div>
|
||||||
<div class="box issue-box">
|
<div class="box issue-box">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<span id="error-title" class="error"></span>
|
<span id="error-title" class="error"></span>
|
||||||
<input type="text" name="title" value="" placeholder="Title" style="width: 565px;" autofocus/>
|
<input type="text" name="title" value="" placeholder="Title" style="width: 565px;" autofocus/>
|
||||||
<div>
|
|
||||||
<span id="label-assigned">No one is assigned</span>
|
|
||||||
@if(hasWritePermission){
|
|
||||||
<input type="hidden" name="assignedUserName" value=""/>
|
|
||||||
@helper.html.dropdown() {
|
|
||||||
<li><a href="javascript:void(0);" class="assign" data-name=""><i class="icon-remove-circle"></i> Clear assignee</a></li>
|
|
||||||
@collaborators.map { collaborator =>
|
|
||||||
<li><a href="javascript:void(0);" class="assign" data-name="@collaborator"><i class="icon-while"></i>@avatar(collaborator, 20) @collaborator</a></li>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<div class="pull-right">
|
|
||||||
<span id="label-milestone">No milestone</span>
|
|
||||||
@if(hasWritePermission){
|
|
||||||
<input type="hidden" name="milestoneId" value=""/>
|
|
||||||
@helper.html.dropdown() {
|
|
||||||
<li><a href="javascript:void(0);" class="milestone" data-id=""><i class="icon-remove-circle"></i> Clear this milestone</a></li>
|
|
||||||
@milestones.filter(_.closedDate.isEmpty).map { milestone =>
|
|
||||||
<li>
|
|
||||||
<a href="javascript:void(0);" class="milestone" data-id="@milestone.milestoneId" data-title="@milestone.title">
|
|
||||||
<i class="icon-while"></i> @milestone.title
|
|
||||||
<div class="small" style="padding-left: 20px;">
|
|
||||||
@milestone.dueDate.map { dueDate =>
|
|
||||||
@if(isPast(dueDate)){
|
|
||||||
<i class="octicon octicon-alert" style="color:#BD2C00;"></i><span class="milestone-alert">Due by @date(dueDate)</span>
|
|
||||||
} else {
|
|
||||||
<span class="muted">Due by @date(dueDate)</span>
|
|
||||||
}
|
|
||||||
}.getOrElse {
|
|
||||||
<span class="muted">No due date</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
@helper.html.preview(
|
@helper.html.preview(
|
||||||
repository = repository,
|
repository = repository,
|
||||||
content = "",
|
content = "",
|
||||||
@@ -73,85 +33,10 @@
|
|||||||
<input type="submit" class="btn btn-success" value="Submit new issue"/>
|
<input type="submit" class="btn btn-success" value="Submit new issue"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="span3">
|
<div class="span2">
|
||||||
@if(hasWritePermission){
|
@issueinfo(None, Nil, Nil, collaborators, milestones.map(x => (x, 0, 0)), labels, hasWritePermission, repository)
|
||||||
<span class="strong">Labels</span>
|
|
||||||
<div>
|
|
||||||
<div id="label-list">
|
|
||||||
<ul class="label-list nav nav-pills nav-stacked">
|
|
||||||
@labels.map { label =>
|
|
||||||
<li>
|
|
||||||
<a href="javascript:void(0);" class="toggle-label" data-label="@label.labelName" data-bgcolor="@label.color" data-fgcolor="@label.fontColor">
|
|
||||||
<span style="background-color: #@label.color;" class="label-color"> </span>
|
|
||||||
@label.labelName
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
<input type="hidden" name="labelNames" value=""/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<script>
|
|
||||||
$(function(){
|
|
||||||
$('a.assign').click(function(){
|
|
||||||
var userName = $(this).data('name');
|
|
||||||
$('a.assign i.icon-ok').attr('class', 'icon-white');
|
|
||||||
|
|
||||||
if(userName == ''){
|
|
||||||
$('#label-assigned').text('No one will be assigned');
|
|
||||||
} else {
|
|
||||||
$('#label-assigned').html($('<span>')
|
|
||||||
.append($('<a class="username strong">').attr('href', '@path/' + userName).text(userName))
|
|
||||||
.append(' will be assigned'));
|
|
||||||
$('a.assign[data-name=' + jqSelectorEscape(userName) + '] i').attr('class', 'icon-ok');
|
|
||||||
}
|
|
||||||
$('input[name=assignedUserName]').val(userName);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('a.milestone').click(function(){
|
|
||||||
var title = $(this).data('title');
|
|
||||||
var milestoneId = $(this).data('id');
|
|
||||||
$('a.milestone i.icon-ok').attr('class', 'icon-white');
|
|
||||||
|
|
||||||
if(milestoneId == ''){
|
|
||||||
$('#label-milestone').text('No milestone');
|
|
||||||
} else {
|
|
||||||
$('#label-milestone').html($('<span class="strong">').text(title));
|
|
||||||
$('a.milestone[data-id=' + milestoneId + '] i').attr('class', 'icon-ok');
|
|
||||||
}
|
|
||||||
$('input[name=milestoneId]').val(milestoneId);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('a.toggle-label').click(function(){
|
|
||||||
if($(this).data('selected') == true){
|
|
||||||
$(this).css({
|
|
||||||
'background-color': 'white',
|
|
||||||
'color' : 'black',
|
|
||||||
'font-weight' : 'normal'
|
|
||||||
});
|
|
||||||
$(this).data('selected', false);
|
|
||||||
} else {
|
|
||||||
$(this).css({
|
|
||||||
'background-color': '#' + $(this).data('bgcolor'),
|
|
||||||
'color' : '#' + $(this).data('fgcolor'),
|
|
||||||
'font-weight' : 'bold'
|
|
||||||
});
|
|
||||||
$(this).data('selected', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
var labelNames = Array();
|
|
||||||
$('a.toggle-label').each(function(i, e){
|
|
||||||
if($(e).data('selected') == true){
|
|
||||||
labelNames.push($(e).data('label'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$('input[name=labelNames]').val(labelNames.join(','));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
@commentform(issue, true, hasWritePermission, repository)
|
@commentform(issue, true, hasWritePermission, repository)
|
||||||
</div>
|
</div>
|
||||||
<div class="span2">
|
<div class="span2">
|
||||||
@issueinfo(issue, comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
|
@issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@(issue: gitbucket.core.model.Issue,
|
@(issue: Option[gitbucket.core.model.Issue],
|
||||||
comments: List[gitbucket.core.model.Comment],
|
comments: List[gitbucket.core.model.Comment],
|
||||||
issueLabels: List[gitbucket.core.model.Label],
|
issueLabels: List[gitbucket.core.model.Label],
|
||||||
collaborators: List[String],
|
collaborators: List[String],
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
labels: List[gitbucket.core.model.Label],
|
labels: List[gitbucket.core.model.Label],
|
||||||
hasWritePermission: Boolean,
|
hasWritePermission: Boolean,
|
||||||
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
|
repository: gitbucket.core.service.RepositoryService.RepositoryInfo)(implicit context: gitbucket.core.controller.Context)
|
||||||
|
@import context._
|
||||||
@import gitbucket.core.view.helpers._
|
@import gitbucket.core.view.helpers._
|
||||||
<div style="margin-bottom: 8px;">
|
<div style="margin-bottom: 8px;">
|
||||||
<span class="muted small strong">Labels</span>
|
<span class="muted small strong">Labels</span>
|
||||||
@@ -22,6 +23,9 @@
|
|||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@if(issue.isEmpty){
|
||||||
|
<input type="hidden" name="labelNames" value=""/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -38,7 +42,10 @@
|
|||||||
@milestones.filter(_._1.closedDate.isEmpty).map { case (milestone, _, _) =>
|
@milestones.filter(_._1.closedDate.isEmpty).map { case (milestone, _, _) =>
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:void(0);" class="milestone" data-id="@milestone.milestoneId" data-title="@milestone.title">
|
<a href="javascript:void(0);" class="milestone" data-id="@milestone.milestoneId" data-title="@milestone.title">
|
||||||
@helper.html.checkicon(Some(milestone.milestoneId) == issue.milestoneId) @milestone.title
|
@issue.map { issue =>
|
||||||
|
@helper.html.checkicon(Some(milestone.milestoneId) == issue.milestoneId)
|
||||||
|
}
|
||||||
|
@milestone.title
|
||||||
<div class="small" style="padding-left: 20px;">
|
<div class="small" style="padding-left: 20px;">
|
||||||
@milestone.dueDate.map { dueDate =>
|
@milestone.dueDate.map { dueDate =>
|
||||||
@if(isPast(dueDate)){
|
@if(isPast(dueDate)){
|
||||||
@@ -58,14 +65,14 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div id="milestone-progress-area">
|
<div id="milestone-progress-area">
|
||||||
@issue.milestoneId.map { milestoneId =>
|
@issue.flatMap(_.milestoneId).map { milestoneId =>
|
||||||
@milestones.collect { case (milestone, openCount, closeCount) if(milestone.milestoneId == milestoneId) =>
|
@milestones.collect { case (milestone, openCount, closeCount) if(milestone.milestoneId == milestoneId) =>
|
||||||
@issues.milestones.html.progress(openCount + closeCount, closeCount)
|
@issues.milestones.html.progress(openCount + closeCount, closeCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<span id="label-milestone">
|
<span id="label-milestone">
|
||||||
@issue.milestoneId.map { milestoneId =>
|
@issue.flatMap(_.milestoneId).map { milestoneId =>
|
||||||
@milestones.collect { case (milestone, _, _) if(milestone.milestoneId == milestoneId) =>
|
@milestones.collect { case (milestone, _, _) if(milestone.milestoneId == milestoneId) =>
|
||||||
<span class="strong small">@milestone.title</span>
|
<span class="strong small">@milestone.title</span>
|
||||||
}
|
}
|
||||||
@@ -73,6 +80,9 @@
|
|||||||
<span class="muted small">No milestone</span>
|
<span class="muted small">No milestone</span>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
|
@if(issue.isEmpty){
|
||||||
|
<input type="hidden" name="milestoneId" value=""/>
|
||||||
|
}
|
||||||
<hr/>
|
<hr/>
|
||||||
<div style="margin-bottom: 8px;">
|
<div style="margin-bottom: 8px;">
|
||||||
<span class="muted small strong">Assignee</span>
|
<span class="muted small strong">Assignee</span>
|
||||||
@@ -83,7 +93,7 @@
|
|||||||
@collaborators.map { collaborator =>
|
@collaborators.map { collaborator =>
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:void(0);" class="assign" data-name="@collaborator">
|
<a href="javascript:void(0);" class="assign" data-name="@collaborator">
|
||||||
@helper.html.checkicon(Some(collaborator) == issue.assignedUserName)@avatar(collaborator, 20) @collaborator
|
@helper.html.checkicon(issue.exists(_.assignedUserName == collaborator))@avatar(collaborator, 20) @collaborator
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
@@ -92,39 +102,37 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<span id="label-assigned">
|
<span id="label-assigned">
|
||||||
@issue.assignedUserName.map { userName =>
|
@issue.flatMap(_.assignedUserName).map { userName =>
|
||||||
@avatar(userName, 20) @user(userName, styleClass="username strong small")
|
@avatar(userName, 20) @user(userName, styleClass="username strong small")
|
||||||
}.getOrElse{
|
}.getOrElse{
|
||||||
<span class="muted small">No one</span>
|
<span class="muted small">No one</span>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
<hr/>
|
@if(issue.isEmpty){
|
||||||
<div style="margin-bottom: 8px;">
|
<input type="hidden" name="assignedUserName" value=""/>
|
||||||
|
}
|
||||||
|
@issue.map { issue =>
|
||||||
|
<hr/>
|
||||||
|
<div style="margin-bottom: 8px;">
|
||||||
@defining((issue.openedUserName :: comments.map(_.commentedUserName)).distinct){ participants =>
|
@defining((issue.openedUserName :: comments.map(_.commentedUserName)).distinct){ participants =>
|
||||||
<div class="muted small strong">@participants.size @plural(participants.size, "participant")</div>
|
<div class="muted small strong">@participants.size @plural(participants.size, "participant")</div>
|
||||||
@participants.map { participant => @avatarLink(participant, 20, tooltip = true) }
|
@participants.map { participant =>
|
||||||
|
@avatarLink(participant, 20, tooltip = true)
|
||||||
}
|
}
|
||||||
</div>
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<script>
|
<script>
|
||||||
$(function(){
|
$(function(){
|
||||||
|
@issue.map { issue =>
|
||||||
$('a.toggle-label').click(function(){
|
$('a.toggle-label').click(function(){
|
||||||
var path, icon;
|
var path = switchLabel($(this));
|
||||||
var i = $(this).children('i');
|
|
||||||
if(i.hasClass('icon-ok')){
|
|
||||||
path = 'delete';
|
|
||||||
icon = 'icon-white';
|
|
||||||
} else {
|
|
||||||
path = 'new';
|
|
||||||
icon = 'icon-ok';
|
|
||||||
}
|
|
||||||
$.post('@url(repository)/issues/@issue.issueId/label/' + path,
|
$.post('@url(repository)/issues/@issue.issueId/label/' + path,
|
||||||
{
|
{ labelId : $(this).data('label-id') },
|
||||||
labelId : $(this).data('label-id')
|
|
||||||
},
|
|
||||||
function(data){
|
function(data){
|
||||||
i.removeClass().addClass(icon);
|
|
||||||
$('ul.label-list').empty().html(data);
|
$('ul.label-list').empty().html(data);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -132,31 +140,83 @@ $(function(){
|
|||||||
var title = $(this).data('title');
|
var title = $(this).data('title');
|
||||||
var milestoneId = $(this).data('id');
|
var milestoneId = $(this).data('id');
|
||||||
$.post('@url(repository)/issues/@issue.issueId/milestone',
|
$.post('@url(repository)/issues/@issue.issueId/milestone',
|
||||||
{
|
{ milestoneId: milestoneId },
|
||||||
milestoneId: milestoneId
|
|
||||||
},
|
|
||||||
function(data){
|
function(data){
|
||||||
console.log(data);
|
displayMilestone(title, milestoneId, data);
|
||||||
$('a.milestone i.icon-ok').attr('class', 'icon-white');
|
|
||||||
if(milestoneId == ''){
|
|
||||||
$('#label-milestone').html($('<span class="muted small">').text('No milestone'));
|
|
||||||
$('#milestone-progress-area').empty();
|
|
||||||
} else {
|
|
||||||
$('#label-milestone').html($('<span class="strong small">').text(title));
|
|
||||||
$('#milestone-progress-area').html(data);
|
|
||||||
$('a.milestone[data-id=' + milestoneId + '] i').attr('class', 'icon-ok');
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('a.assign').click(function(){
|
$('a.assign').click(function(){
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var userName = $this.data('name');
|
var userName = $this.data('name');
|
||||||
$.post('@url(repository)/issues/@issue.issueId/assign',
|
$.post('@url(repository)/issues/@issue.issueId/assign',
|
||||||
{
|
{ assignedUserName: userName },
|
||||||
assignedUserName: userName
|
|
||||||
},
|
|
||||||
function(){
|
function(){
|
||||||
|
displayAssignee($this, userName);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}.getOrElse {
|
||||||
|
$('a.toggle-label').click(function(){
|
||||||
|
switchLabel($(this));
|
||||||
|
var labelNames = Array();
|
||||||
|
$('a.toggle-label').each(function(i, e){
|
||||||
|
if($(e).children('i').hasClass('icon-ok') == true){
|
||||||
|
labelNames.push($(e).text().trim());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('input[name=labelNames]').val(labelNames.join(','));
|
||||||
|
|
||||||
|
$.post('@url(repository)/issues/new/label',
|
||||||
|
{ labelNames : labelNames.join(',') },
|
||||||
|
function(data){
|
||||||
|
$('ul.label-list').empty().html(data);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('a.milestone').click(function(){
|
||||||
|
var title = $(this).data('title');
|
||||||
|
var milestoneId = $(this).data('id');
|
||||||
|
displayMilestone(title, milestoneId);
|
||||||
|
$('input[name=milestoneId]').val(milestoneId);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('a.assign').click(function(){
|
||||||
|
var $this = $(this);
|
||||||
|
var userName = $this.data('name');
|
||||||
|
displayAssignee($this, userName);
|
||||||
|
$('input[name=assignedUserName]').val(userName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchLabel($this){
|
||||||
|
var i = $this.children('i');
|
||||||
|
if(i.hasClass('icon-ok')){
|
||||||
|
i.removeClass().addClass('icon-white');
|
||||||
|
return 'delete';
|
||||||
|
} else {
|
||||||
|
i.removeClass().addClass('icon-ok');
|
||||||
|
return 'new';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayMilestone(title, milestoneId, progress){
|
||||||
|
$('a.milestone i.icon-ok').attr('class', 'icon-white');
|
||||||
|
if(milestoneId == ''){
|
||||||
|
$('#label-milestone').html($('<span class="muted small">').text('No milestone'));
|
||||||
|
$('#milestone-progress-area').empty();
|
||||||
|
} else {
|
||||||
|
$('#label-milestone').html($('<span class="strong small">').text(title));
|
||||||
|
if(progress){
|
||||||
|
$('#milestone-progress-area').html(progress);
|
||||||
|
}
|
||||||
|
$('a.milestone[data-id=' + milestoneId + '] i').attr('class', 'icon-ok');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayAssignee($this, userName){
|
||||||
$('a.assign i.icon-ok').attr('class', 'icon-white');
|
$('a.assign i.icon-ok').attr('class', 'icon-white');
|
||||||
if(userName == ''){
|
if(userName == ''){
|
||||||
$('#label-assigned').html($('<span class="muted small">').text('No one'));
|
$('#label-assigned').html($('<span class="muted small">').text('No one'));
|
||||||
@@ -166,8 +226,6 @@ $(function(){
|
|||||||
.append($('<a class="username strong small">').attr('href', '@context.path/' + userName).text(userName));
|
.append($('<a class="username strong small">').attr('href', '@context.path/' + userName).text(userName));
|
||||||
$('a.assign[data-name=' + jqSelectorEscape(userName) + '] i').attr('class', 'icon-ok');
|
$('a.assign[data-name=' + jqSelectorEscape(userName) + '] i').attr('class', 'icon-ok');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="span2">
|
<div class="span2">
|
||||||
@issues.html.issueinfo(issue, comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
|
@issues.html.issueinfo(Some(issue), comments, issueLabels, collaborators, milestones, labels, hasWritePermission, repository)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
Reference in New Issue
Block a user