mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
DifferentialRevisionView
This commit is contained in:
parent
9f1659b4c4
commit
7b9c4c5f61
23 changed files with 2195 additions and 19 deletions
|
@ -82,7 +82,23 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'differential-core-view-css' =>
|
||||
array(
|
||||
'path' => '/res/f750b85d/rsrc/css/application/differential/core.css',
|
||||
'path' => '/res/525d1a12/rsrc/css/application/differential/core.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
),
|
||||
'differential-revision-detail-css' =>
|
||||
array(
|
||||
'path' => '/res/11a36dad/rsrc/css/application/differential/revision-detail.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
),
|
||||
'differential-revision-history-css' =>
|
||||
array(
|
||||
'path' => '/res/755f3da3/rsrc/css/application/differential/revision-history.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -90,7 +106,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'differential-table-of-contents-css' =>
|
||||
array(
|
||||
'path' => '/res/ebf6641c/rsrc/css/application/differential/table-of-contents.css',
|
||||
'path' => '/res/a4a7b2b5/rsrc/css/application/differential/table-of-contents.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
|
|
@ -86,11 +86,14 @@ phutil_register_library_map(array(
|
|||
'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest',
|
||||
'DifferentialRevision' => 'applications/differential/storage/revision',
|
||||
'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem',
|
||||
'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail',
|
||||
'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit',
|
||||
'DifferentialRevisionEditor' => 'applications/differential/editor/revision',
|
||||
'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist',
|
||||
'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
|
||||
'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus',
|
||||
'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
|
||||
'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
|
||||
'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus',
|
||||
'Javelin' => 'infratructure/javelin/api',
|
||||
'LiskDAO' => 'storage/lisk/dao',
|
||||
|
@ -232,8 +235,11 @@ phutil_register_library_map(array(
|
|||
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
|
||||
'DifferentialReviewRequestMail' => 'DifferentialMail',
|
||||
'DifferentialRevision' => 'DifferentialDAO',
|
||||
'DifferentialRevisionDetailView' => 'AphrontView',
|
||||
'DifferentialRevisionEditController' => 'DifferentialController',
|
||||
'DifferentialRevisionListController' => 'DifferentialController',
|
||||
'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
|
||||
'DifferentialRevisionViewController' => 'DifferentialController',
|
||||
'PhabricatorAuthController' => 'PhabricatorController',
|
||||
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
|
||||
'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
|
||||
|
|
|
@ -77,6 +77,8 @@ class AphrontDefaultApplicationConfiguration
|
|||
),
|
||||
'/api/(?<method>[^/]+)$' => 'PhabricatorConduitAPIController',
|
||||
|
||||
|
||||
'/D(?<id>\d+)' => 'DifferentialRevisionViewController',
|
||||
'/differential/' => array(
|
||||
'$' => 'DifferentialRevisionListController',
|
||||
'filter/(?<filter>\w+)/$' => 'DifferentialRevisionListController',
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/404');
|
||||
phutil_require_module('phabricator', 'applications/differential/constants/revisionstatus');
|
||||
phutil_require_module('phabricator', 'applications/differential/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/differential/storage/revision');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/changesetlistview');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/difftableofcontents');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/revisiondetail');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/revisionupdatehistory');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DifferentialRevisionViewController.php');
|
|
@ -51,6 +51,15 @@ class DifferentialRevision extends DifferentialDAO {
|
|||
return PhabricatorPHID::generateNewPHID('DREV');
|
||||
}
|
||||
|
||||
public function loadDiffs() {
|
||||
if (!$this->getID()) {
|
||||
return array();
|
||||
}
|
||||
return id(new DifferentialDiff())->loadAllWhere(
|
||||
'revisionID = %d',
|
||||
$this->getID());
|
||||
}
|
||||
|
||||
public function loadRelationships() {
|
||||
if (!$this->getID()) {
|
||||
$this->relationships = array();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/differential/storage/base');
|
||||
phutil_require_module('phabricator', 'applications/differential/storage/diff');
|
||||
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
|
|
|
@ -26,6 +26,8 @@ final class DifferentialDiffTableOfContentsView extends AphrontView {
|
|||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
require_celerity_resource('differential-core-view-css');
|
||||
require_celerity_resource('differential-table-of-contents-css');
|
||||
|
||||
$rows = array();
|
||||
|
@ -112,7 +114,7 @@ final class DifferentialDiffTableOfContentsView extends AphrontView {
|
|||
}
|
||||
|
||||
return
|
||||
'<div class="differential-toc">'.
|
||||
'<div class="differential-toc differential-panel">'.
|
||||
'<h1>Table of Contents</h1>'.
|
||||
'<table>'.
|
||||
implode("\n", $rows).
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DifferentialRevisionDetailView extends AphrontView {
|
||||
|
||||
private $revision;
|
||||
private $properties;
|
||||
private $actions;
|
||||
|
||||
public function setRevision($revision) {
|
||||
$this->revision = $revision;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setProperties(array $properties) {
|
||||
$this->properties = $properties;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setActions(array $actions) {
|
||||
$this->actions = $actions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
require_celerity_resource('differential-core-view-css');
|
||||
require_celerity_resource('differential-revision-detail-css');
|
||||
|
||||
$revision = $this->revision;
|
||||
|
||||
$rows = array();
|
||||
foreach ($this->properties as $key => $field) {
|
||||
$rows[] =
|
||||
'<tr>'.
|
||||
'<th>'.phutil_escape_html($key).':</th>'.
|
||||
'<td>'.$field.'</td>'.
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
$properties =
|
||||
'<table class="differential-revision-properties">'.
|
||||
implode("\n", $rows).
|
||||
'</table>';
|
||||
|
||||
$actions = array();
|
||||
foreach ($this->actions as $action) {
|
||||
if (empty($action['href'])) {
|
||||
$tag = 'span';
|
||||
} else {
|
||||
$tag = 'a';
|
||||
}
|
||||
$actions[] = phutil_render_tag(
|
||||
$tag,
|
||||
array(
|
||||
'href' => idx($action, 'href'),
|
||||
'class' => idx($action, 'class'),
|
||||
),
|
||||
phutil_escape_html($action['name']));
|
||||
}
|
||||
$actions = implode("\n", $actions);
|
||||
|
||||
return
|
||||
'<div class="differential-revision-detail differential-panel">'.
|
||||
'<div class="differential-revision-actions">'.
|
||||
$actions.
|
||||
'</div>'.
|
||||
'<div class="differential-revision-detail-core">'.
|
||||
'<h1>'.phutil_escape_html($revision->getTitle()).'</h1>'.
|
||||
$properties.
|
||||
'</div>'.
|
||||
'<div style="clear: both;"></div>'.
|
||||
'</div>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'infratructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DifferentialRevisionDetailView.php');
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
|
||||
private $diffs = array();
|
||||
|
||||
public function setDiffs($diffs) {
|
||||
$this->diffs = $diffs;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
require_celerity_resource('differential-core-view-css');
|
||||
require_celerity_resource('differential-revision-history-css');
|
||||
|
||||
$data = array(
|
||||
array(
|
||||
'name' => 'Base',
|
||||
'id' => null,
|
||||
'desc' => 'Base',
|
||||
'old' => false,
|
||||
'new' => false,
|
||||
'age' => null,
|
||||
'lint' => null,
|
||||
'unit' => null,
|
||||
),
|
||||
);
|
||||
|
||||
$seq = 0;
|
||||
foreach ($this->diffs as $diff) {
|
||||
$data[] = array(
|
||||
'name' => 'Diff '.(++$seq),
|
||||
'id' => $diff->getID(),
|
||||
'desc' => 'TODO',//$diff->getDescription(),
|
||||
'old' => false,
|
||||
'new' => false,
|
||||
'age' => $diff->getDateCreated(),
|
||||
'lint' => $diff->getLintStatus(),
|
||||
'unit' => $diff->getUnitStatus(),
|
||||
);
|
||||
}
|
||||
|
||||
$idx = 0;
|
||||
$rows = array();
|
||||
foreach ($data as $row) {
|
||||
|
||||
$name = phutil_escape_html($row['name']);
|
||||
$id = phutil_escape_html($row['id']);
|
||||
|
||||
$lint = '*';
|
||||
$unit = '*';
|
||||
$old = '<input type="radio" name="old" />';
|
||||
$new = '<input type="radio" name="new" />';
|
||||
|
||||
$desc = 'TODO';
|
||||
$age = '-';
|
||||
|
||||
if (++$idx % 2) {
|
||||
$class = ' class="alt"';
|
||||
} else {
|
||||
$class = null;
|
||||
}
|
||||
|
||||
$rows[] =
|
||||
'<tr'.$class.'>'.
|
||||
'<td class="revhistory-name">'.$name.'</td>'.
|
||||
'<td class="revhistory-id">'.$id.'</td>'.
|
||||
'<td class="revhistory-desc">'.$desc.'</td>'.
|
||||
'<td class="revhistory-age">'.$age.'</td>'.
|
||||
'<td class="revhistory-star">'.$lint.'</td>'.
|
||||
'<td class="revhistory-star">'.$unit.'</td>'.
|
||||
'<td class="revhistory-old">'.$old.'</td>'.
|
||||
'<td class="revhistory-new">'.$new.'</td>'.
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
$select = '<select><option>Ignore All</option></select>';
|
||||
|
||||
return
|
||||
'<div class="differential-revision-history differential-panel">'.
|
||||
'<h1>Revision Update History</h1>'.
|
||||
'<form>'.
|
||||
'<table class="differential-revision-history-table">'.
|
||||
'<tr>'.
|
||||
'<th>Diff</th>'.
|
||||
'<th>ID</th>'.
|
||||
'<th>Description</th>'.
|
||||
'<th>Age</th>'.
|
||||
'<th>Lint</th>'.
|
||||
'<th>Unit</th>'.
|
||||
'</tr>'.
|
||||
implode("\n", $rows).
|
||||
'<tr>'.
|
||||
'<td colspan="8" class="diff-differ-submit">'.
|
||||
'<label>Whitespace Changes: '.$select.'</label>'.
|
||||
'<button class="disabled"
|
||||
disabled="disabled">Show Diff</button>'.
|
||||
'</td>'.
|
||||
'</tr>'.
|
||||
'</table>'.
|
||||
'</form>'.
|
||||
'</div>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'infratructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
|
||||
|
||||
phutil_require_source('DifferentialRevisionUpdateHistoryView.php');
|
|
@ -69,6 +69,13 @@ class PhabricatorObjectHandle {
|
|||
return $this->email;
|
||||
}
|
||||
|
||||
|
||||
public function renderLink() {
|
||||
return phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $this->getURI(),
|
||||
),
|
||||
phutil_escape_html($this->getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,5 +6,7 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorObjectHandle.php');
|
||||
|
|
|
@ -7,3 +7,17 @@
|
|||
max-width: 1162px;
|
||||
}
|
||||
|
||||
.differential-panel {
|
||||
margin: 25px 0;
|
||||
max-width: 1118px;
|
||||
border: 1px solid #666622;
|
||||
background: #efefdf;
|
||||
padding: 15px 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.differential-panel h1 {
|
||||
border-bottom: 1px solid #aaaa99;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* @provides differential-revision-detail-css
|
||||
*/
|
||||
|
||||
.differential-revision-properties {
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.differential-revision-properties tt {
|
||||
letter-spacing: 1.1px;
|
||||
}
|
||||
|
||||
.differential-revision-properties th {
|
||||
font-weight: bold;
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
padding: 3px 4px 3px 3px;
|
||||
color: #333333;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.differential-revision-properties td {
|
||||
padding: 3px 2px;
|
||||
}
|
||||
|
||||
.differential-revision-actions {
|
||||
float: right;
|
||||
width: 250px;
|
||||
background: #cfcfbf;
|
||||
border: 1px solid #666622;
|
||||
border-width: 0px 0px 1px 1px;
|
||||
margin: -15px -20px 1em 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.differential-revision-detail-core {
|
||||
margin-right: 265px;
|
||||
}
|
||||
|
||||
.differential-revision-actions a,
|
||||
.differential-revision-actions span {
|
||||
background-position: 8px center;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
padding: 4px 4px 4px 32px;
|
||||
}
|
||||
|
||||
.differential-revision-actions span.unavailable {
|
||||
color: #666666;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.differential-revision-actions .subscribe-rem {
|
||||
background-image: url(/rsrc/image/icon/unsubscribe.png);
|
||||
}
|
||||
|
||||
.differential-revision-actions .revision-edit {
|
||||
background-image: url(/rsrc/image/icon/tango/edit.png);
|
||||
}
|
||||
|
||||
.differential-revision-actions .revision-edit {
|
||||
background-image: url(/rsrc/image/icon/tango/edit.png);
|
||||
}
|
||||
|
||||
.differential-revision-actions .transcripts-metamta {
|
||||
background-image: url(/rsrc/image/icon/tango/log.png);
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* @provides differential-revision-history-css
|
||||
*/
|
||||
|
||||
.differential-revision-history-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 1px;
|
||||
}
|
||||
|
||||
.differential-revision-history-table th {
|
||||
padding: 0 .5em;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.differential-revision-history-table tr.alt {
|
||||
background: #ddddcc;
|
||||
}
|
||||
|
||||
|
||||
.differential-revision-history-table td.revhistory-desc {
|
||||
width: 100%;
|
||||
white-space: normal;
|
||||
padding-left: .5em;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.revhistory-name {
|
||||
font-weight: bold;
|
||||
padding-right: .5em;
|
||||
padding-left: .5em;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.revhistory-age {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.revhistory-old,
|
||||
.differential-revision-history-table td.revhistory-new {
|
||||
padding: 0em 1.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.revhistory-old {
|
||||
background: #f9d0d0;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.revhistory-old-now {
|
||||
background: #ffaaaa;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.revhistory-new {
|
||||
background: #d0ffd0;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.revhistory-new-now {
|
||||
background: #aaffaa;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.revhistory-star {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.differential-revision-history-table td.diff-differ-submit {
|
||||
text-align: right;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.diff-differ-submit button {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.differential-revision-history-table td.diff-differ-submit label {
|
||||
font-weight: bold;
|
||||
padding-right: .25em;
|
||||
color: #444444;
|
||||
}
|
|
@ -2,15 +2,6 @@
|
|||
* @provides differential-table-of-contents-css
|
||||
*/
|
||||
|
||||
.differential-toc {
|
||||
margin: 25px 0;
|
||||
max-width: 1118px;
|
||||
border: 1px solid #666622;
|
||||
background: #efefdf;
|
||||
padding: 15px 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.differential-toc-meta {
|
||||
color: #666666;
|
||||
padding-left: 1em;
|
||||
|
@ -32,9 +23,3 @@
|
|||
.differential-toc-file {
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.differential-toc h1 {
|
||||
border-bottom: 1px solid #aaaa99;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
|
BIN
webroot/rsrc/image/icon/subscribe.png
Normal file
BIN
webroot/rsrc/image/icon/subscribe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 282 B |
3
webroot/rsrc/image/icon/tango/README
Normal file
3
webroot/rsrc/image/icon/tango/README
Normal file
|
@ -0,0 +1,3 @@
|
|||
These icons come from the Tango Desktop Project:
|
||||
|
||||
http://tango.freedesktop.org/
|
BIN
webroot/rsrc/image/icon/tango/edit.png
Normal file
BIN
webroot/rsrc/image/icon/tango/edit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 574 B |
BIN
webroot/rsrc/image/icon/tango/log.png
Normal file
BIN
webroot/rsrc/image/icon/tango/log.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 333 B |
BIN
webroot/rsrc/image/icon/unsubscribe.png
Normal file
BIN
webroot/rsrc/image/icon/unsubscribe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 182 B |
Loading…
Reference in a new issue