Skip to content
Snippets Groups Projects
Commit b46180ea authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

fixes #49

parent 50b19258
No related branches found
No related tags found
1 merge request!9fixes #49
......@@ -90,6 +90,10 @@ final class TracToGitlabPlugin extends TracToGitlab\Plugin implements StandardPl
'merge-requests',
new Navigation(_('Merge Requests'), PluginEngine::getURL($this, [], 'mergerequests'))
);
$navigation->addSubNavigation(
'labels',
new Navigation(_('Verwendete Labels'), PluginEngine::getURL($this, [], 'labels'))
);
$navigation->addSubNavigation(
'cg-members',
new Navigation(_('Übersicht Zuständigkeiten'), PluginEngine::getURL($this, [], 'cgmembers'))
......
export default {
data: () => ({
sort: {
by: 'name',
asc: true,
},
needle: '',
}),
components: {
gitlabLabel: {
template: '#label-template',
props: {
label: {
type: Object,
required: true,
},
},
computed: {
isScoped() {
return this.label.name.includes('::');
},
name() {
return this.isScoped ? this.label.name.split('::').slice(0, -1).join('::') : this.label.name;
},
scope() {
return this.isScoped ? this.label.name.split('::').at(-1) : null;
},
style() {
return {
'--label-background-color': this.label.color,
'--label-text-color': this.label.text_color,
};
},
link() {
const url = new URL('/studip/studip/-/issues', 'https://gitlab.studip.de');
url.searchParams.append('label_name[]', this.label.name);
return url.toString();
},
},
},
},
methods: {
sortClass(column) {
if (this.sort.by !== column) {
return '';
}
return {
sortasc: this.sort.asc,
sortdesc: !this.sort.asc,
};
},
selectSort(column) {
if (this.sort.by === column) {
this.sort.asc = !this.sort.asc;
} else {
this.sort.by = column;
this.sort.asc = true;
}
}
},
computed: {
sortedLabels () {
const dirFactor = this.sort.asc ? 1 : -1;
return this.labels
.filter(label => {
return this.needle.trim().length === 0
|| label.name.toLowerCase().includes(this.needle.toLowerCase())
|| label.description?.toLowerCase().includes(this.needle.toLowerCase());
})
.sort((a, b) => {
if (this.sort.by === 'name') {
return dirFactor * a.name.localeCompare(b.name);
}
if (this.sort.by === 'description') {
return dirFactor * (a.description ?? '').localeCompare(b.description ?? '');
}
if (this.sort.by === 'count') {
return dirFactor * (a.count - b.count);
}
throw new Error('Invalid sorting defined');
});
},
},
};
(function ($, STUDIP) {
'use strict';
const lookup = {
'#labels-list-app': () => import('./apps/labels.js'),
};
STUDIP.ready(() => {
Object.entries(lookup).forEach(([selector, appLoader]) => {
const node = document.querySelector(selector);
if (!node) {
return;
}
const vueAppData = node.dataset.vueAppData ? JSON.parse(node.dataset.vueAppData) : {};
Promise.all([
STUDIP.loadChunk('vue'),
appLoader()
]).then(([{ createApp }, { default: app }]) => {
let originalData = {};
if (app.data !== undefined) {
originalData = app.data instanceof Function ? app.data() : app.data;
}
app.data = () => ({
...originalData,
...vueAppData
});
createApp(app).$mount(node);
})
});
});
var searchTimeout = null;
var lastRequestController = null;
......
......@@ -30,3 +30,42 @@ td.filter-match {
#dashboard table.default td {
vertical-align: top;
}
#labels-list-app {
* {
box-sizing: border-box;
}
.label {
align-items: center;
background-color: var(--label-background-color);
border-radius: 0.75rem;
border: 2px solid var(--label-background-color);
color: var(--label-text-color);
display: inline-flex;
line-height: 1;
max-width: 100%;
overflow: hidden;
position: relative;
white-space: nowrap;
}
.label-link {
color: inherit;
display: flex;
font-size: 0.75rem;
line-height: 1rem;
overflow: hidden;
}
.label-text {
padding: 0.25rem 0.5rem;
}
.label-scoped {
.label-text {
padding-right: 0.25rem;
}
.label-text-scoped {
background-color: var(--white);
color: var(--black);
padding: 0.25rem 0.5rem 0.25rem 0.25rem;
}
}
}
......@@ -8,12 +8,17 @@
],
"require": {
"fguillot/json-rpc": "^1.2",
"m4tthumphrey/php-gitlab-api": "^11.4",
"m4tthumphrey/php-gitlab-api": "^11.12.0",
"guzzlehttp/guzzle": "^7.2",
"http-interop/http-factory-guzzle": "^1.0",
"erusev/parsedown": "^1.7",
"ext-json": "*",
"pimple/pimple": "^3.4",
"ext-curl": "*"
},
"config": {
"allow-plugins": {
"php-http/discovery": true
}
}
}
This diff is collapsed.
<?php
final class LabelsController extends \TracToGitlab\GitlabController
{
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
PageLayout::setTitle(_('Verwendete Labels'));
$this->activateNavigation('labels');
}
public function index_action()
{
$data = $this->readFromCache('labels', true);
if ($data === false) {
$this->labels = $this->fetchLabels();
$this->writeToCache('labels', $this->labels);
} else {
$this->labels = $data['data'];
}
}
private function fetchLabels(): array
{
$labels = $this->gitlabPager->fetchAll(
$this->gitlab->projects(),
'labels',
[
$this->gitlabProjectId,
['with_counts' => true]
]
);
usort($labels, function ($a, $b) {
return strnatcasecmp($a['name'], $b['name']);
});
return $labels;
}
}
......@@ -4,3 +4,4 @@ pluginclassname=StudipReleasesPlugin
origin=UOL
version=1.4.4
studipMinVersion=5.0
localedomain=trac2gitlab
<?php
/**
* @var array $labels
* @var callable $_
*/
?>
<?php
$vueData = [
'labels' => array_map(
function (array $label): array {
return [
'id' => $label['id'],
'name' => $label['name'],
'description' => $label['description'],
'description_html' => $label['description_html'],
'color' => $label['color'],
'text_color' => $label['text_color'],
'count' => $label['open_issues_count'] + $label['closed_issues_count'],
];
},
$labels
),
];
?>
<script type="text/x-template" id="label-template">
<span class="label" :class="{'label-scoped': isScoped}" :style="style">
<a :href="link" target="_blank" class="label-link">
<span class="label-text">
{{ name }}
</span>
<span v-if="scope" class="label-text-scoped">
{{ scope }}
</span>
</a>
</span>
</script>
<div id="labels-list-app" data-vue-app-data="<?= htmlReady(json_encode($vueData)) ?>">
<table class="default">
<thead>
<tr class="sortable">
<th :class="sortClass('name')">
<button class="as-link" @click="selectSort('name')">
<?= $_('Label') ?>
</button>
</th>
<th :class="sortClass('description')">
<button class="as-link" @click="selectSort('description')">
<?= $_('Beschreibung') ?>
</button>
</th>
<th :class="sortClass('count')">
<button class="as-link" @click="selectSort('count')">
#
</button>
</th>
</tr>
</thead>
<tbody>
<tr v-if="sortedLabels.length === 0">
<td colspan="3" style="text-align: center">
<?= $_('Keine Labels passen zum Suchbegriff.') ?>
</td>
</tr>
<tr v-for="label in sortedLabels" :key="`label-${label.id}`">
<td>
<gitlab-label :label="label"></gitlab-label>
</td>
<td v-html="label.description_html">{{ label.description }}</td>
<td>{{ label.count }}</td>
</tr>
</tbody>
</table>
<mounting-portal mount-to="#sidebar" append>
<div class="sidebar-widget sidebar-search">
<div class="sidebar-widget-header">
<?= $_('Suche') ?>
<span v-if="sortedLabels.length < labels.length">
({{ $gettextInterpolate(
$gettext('%{ matching } von %{ total }'),
{
matching: sortedLabels.length,
total: labels.length,
}
) }})
</span>
</div>
<div class="sidebar-widget-content">
<form action="#" @submit.prevent>
<ul class="needles">
<li>
<div class="input-group files-search">
<input type="text" v-model.trim="needle" placeholder="<?= _('Suchbegriff') ?>">
<button class="submit-search" type="submit" title="<?= _('Suche auführen') ?>">
<?= Icon::create('search')->asImg(20) ?>
</button>
</div>
</li>
</ul>
</form>
</div>
</div>
</mounting-portal>
</div>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment