Refactor admin plugins

This commit is contained in:
Chocobozzz 2021-12-29 12:14:06 +01:00
parent 9744bb2ae8
commit 2accfdd8ec
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
18 changed files with 117 additions and 132 deletions

View File

@ -302,11 +302,13 @@
"defaultProject": "PeerTube", "defaultProject": "PeerTube",
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
"prefix": "app", "prefix": "my",
"style": "scss" "style": "scss",
"skipTests": true,
"flat": true
}, },
"@schematics/angular:directive": { "@schematics/angular:directive": {
"prefix": "app" "prefix": "my"
} }
} }
} }

View File

@ -1,5 +1,4 @@
import { ChartModule } from 'primeng/chart' import { ChartModule } from 'primeng/chart'
import { SelectButtonModule } from 'primeng/selectbutton'
import { TableModule } from 'primeng/table' import { TableModule } from 'primeng/table'
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { SharedAbuseListModule } from '@app/shared/shared-abuse-list' import { SharedAbuseListModule } from '@app/shared/shared-abuse-list'
@ -45,7 +44,7 @@ import {
PluginApiService, PluginApiService,
PluginCardComponent, PluginCardComponent,
PluginListInstalledComponent, PluginListInstalledComponent,
PluginsComponent, PluginNavigationComponent,
PluginSearchComponent, PluginSearchComponent,
PluginShowInstalledComponent PluginShowInstalledComponent
} from './plugins' } from './plugins'
@ -70,7 +69,6 @@ import { JobsComponent } from './system/jobs/jobs.component'
SharedTablesModule, SharedTablesModule,
TableModule, TableModule,
SelectButtonModule,
ChartModule ChartModule
], ],
@ -98,11 +96,11 @@ import { JobsComponent } from './system/jobs/jobs.component'
InstanceServerBlocklistComponent, InstanceServerBlocklistComponent,
InstanceAccountBlocklistComponent, InstanceAccountBlocklistComponent,
PluginsComponent,
PluginListInstalledComponent, PluginListInstalledComponent,
PluginSearchComponent, PluginSearchComponent,
PluginShowInstalledComponent, PluginShowInstalledComponent,
PluginCardComponent, PluginCardComponent,
PluginNavigationComponent,
JobsComponent, JobsComponent,
LogsComponent, LogsComponent,

View File

@ -1,6 +1,4 @@
export * from './plugins.component'
export * from './shared' export * from './shared'
export * from './plugin-list-installed' export * from './plugin-list-installed'
export * from './plugin-search' export * from './plugin-search'
export * from './plugin-show-installed' export * from './plugin-show-installed'

View File

@ -1,6 +1,4 @@
<div class="toggle-plugin-type"> <my-plugin-navigation [pluginType]="pluginType"></my-plugin-navigation>
<p-selectButton [options]="pluginTypeOptions" [(ngModel)]="pluginType" (ngModelChange)="reloadPlugins()"></p-selectButton>
</div>
<div class="no-results" *ngIf="pagination.totalItems === 0"> <div class="no-results" *ngIf="pagination.totalItems === 0">
{{ getNoResultMessage() }} {{ getNoResultMessage() }}

View File

@ -10,14 +10,10 @@ import { PeerTubePlugin, PluginType } from '@shared/models'
@Component({ @Component({
selector: 'my-plugin-list-installed', selector: 'my-plugin-list-installed',
templateUrl: './plugin-list-installed.component.html', templateUrl: './plugin-list-installed.component.html',
styleUrls: [ styleUrls: [ './plugin-list-installed.component.scss' ]
'../shared/toggle-plugin-type.scss',
'./plugin-list-installed.component.scss'
]
}) })
export class PluginListInstalledComponent implements OnInit { export class PluginListInstalledComponent implements OnInit {
pluginTypeOptions: { label: string, value: PluginType }[] = [] pluginType: PluginType
pluginType: PluginType = PluginType.PLUGIN
pagination: ComponentPagination = { pagination: ComponentPagination = {
currentPage: 1, currentPage: 1,
@ -39,22 +35,28 @@ export class PluginListInstalledComponent implements OnInit {
private router: Router, private router: Router,
private route: ActivatedRoute private route: ActivatedRoute
) { ) {
this.pluginTypeOptions = this.pluginApiService.getPluginTypeOptions()
} }
ngOnInit () { ngOnInit () {
const query = this.route.snapshot.queryParams if (!this.route.snapshot.queryParams['pluginType']) {
if (query['pluginType']) this.pluginType = parseInt(query['pluginType'], 10) const queryParams = { pluginType: PluginType.PLUGIN }
this.reloadPlugins() this.router.navigate([], { queryParams })
}
this.route.queryParams.subscribe(query => {
if (!query['pluginType']) return
this.pluginType = parseInt(query['pluginType'], 10)
this.reloadPlugins()
})
} }
reloadPlugins () { reloadPlugins () {
this.pagination.currentPage = 1 this.pagination.currentPage = 1
this.plugins = [] this.plugins = []
this.router.navigate([], { queryParams: { pluginType: this.pluginType } })
this.loadMorePlugins() this.loadMorePlugins()
} }

View File

@ -1,28 +1,27 @@
<div class="toggle-plugin-type"> <my-plugin-navigation [pluginType]="pluginType"></my-plugin-navigation>
<p-selectButton [options]="pluginTypeOptions" [(ngModel)]="pluginType" (ngModelChange)="reloadPlugins()"></p-selectButton>
</div>
<div class="search-bar">
<input type="text" (input)="onSearchChange($event)" i18n-placeholder placeholder="Search..." myAutofocus />
</div>
<div class="alert alert-info" i18n *ngIf="pluginInstalled"> <div class="alert alert-info" i18n *ngIf="pluginInstalled">
To load your new installed plugins or themes, refresh the page. To load your new installed plugins or themes, refresh the page.
</div> </div>
<div class="result-title" *ngIf="!isSearching"> <div class="result-and-search">
<ng-container *ngIf="!search"> <ng-container *ngIf="!search">
<my-global-icon iconName="trending" aria-hidden="true"></my-global-icon> <my-global-icon iconName="trending" aria-hidden="true"></my-global-icon>
<ng-container i18n>Popular</ng-container> <ng-container *ngIf="!isThemeSearch()" i18n>Popular plugins</ng-container>
<ng-container *ngIf="isThemeSearch()" i18n>Popular themes</ng-container>
</ng-container> </ng-container>
<ng-container *ngIf="!!search"> <ng-container *ngIf="search && !isSearching">
<my-global-icon iconName="search"></my-global-icon> <my-global-icon iconName="search"></my-global-icon>
<ng-container i18n> <ng-container i18n>
{{ pagination.totalItems }} {pagination.totalItems, plural, =1 {result} other {results}} for "{{ search }}" {{ pagination.totalItems }} {pagination.totalItems, plural, =1 {result} other {results}} for "{{ search }}"
</ng-container> </ng-container>
</ng-container> </ng-container>
<div class="search-bar">
<input type="text" (input)="onSearchChange($event)" i18n-placeholder placeholder="Search..." myAutofocus />
</div>
</div> </div>
<div class="no-results" i18n *ngIf="pagination.totalItems === 0"> <div class="no-results" i18n *ngIf="pagination.totalItems === 0">

View File

@ -1,27 +1,27 @@
@use '_variables' as *; @use '_variables' as *;
@use '_mixins' as *; @use '_mixins' as *;
.search-bar { .result-and-search {
display: flex;
justify-content: center;
margin: 30px 0;
input {
@include peertube-input-text(60%);
height: 35px;
}
}
.result-title {
font-size: 22px; font-size: 22px;
font-weight: 600; font-weight: 600;
margin-bottom: 15px; margin: 30px 0 15px;
display: flex;
my-global-icon { my-global-icon {
@include margin-right(5px); @include margin-right(5px);
} }
} }
.search-bar {
margin-left: auto;
input {
@include peertube-input-text(500px);
height: 35px;
}
}
.badge { .badge {
@include margin-left(15px); @include margin-left(15px);

View File

@ -9,14 +9,10 @@ import { PeerTubePluginIndex, PluginType } from '@shared/models'
@Component({ @Component({
selector: 'my-plugin-search', selector: 'my-plugin-search',
templateUrl: './plugin-search.component.html', templateUrl: './plugin-search.component.html',
styleUrls: [ styleUrls: [ './plugin-search.component.scss' ]
'../shared/toggle-plugin-type.scss',
'./plugin-search.component.scss'
]
}) })
export class PluginSearchComponent implements OnInit { export class PluginSearchComponent implements OnInit {
pluginTypeOptions: { label: string, value: PluginType }[] = [] pluginType: PluginType
pluginType: PluginType = PluginType.PLUGIN
pagination: ComponentPagination = { pagination: ComponentPagination = {
currentPage: 1, currentPage: 1,
@ -44,24 +40,30 @@ export class PluginSearchComponent implements OnInit {
private router: Router, private router: Router,
private route: ActivatedRoute private route: ActivatedRoute
) { ) {
this.pluginTypeOptions = this.pluginApiService.getPluginTypeOptions()
} }
ngOnInit () { ngOnInit () {
const query = this.route.snapshot.queryParams if (!this.route.snapshot.queryParams['pluginType']) {
if (query['pluginType']) this.pluginType = parseInt(query['pluginType'], 10) const queryParams = { pluginType: PluginType.PLUGIN }
this.router.navigate([], { queryParams })
}
this.route.queryParams.subscribe(query => {
if (!query['pluginType']) return
this.pluginType = parseInt(query['pluginType'], 10)
this.search = query['search'] || ''
this.reloadPlugins()
})
this.searchSubject.asObservable() this.searchSubject.asObservable()
.pipe( .pipe(
debounceTime(400), debounceTime(400),
distinctUntilChanged() distinctUntilChanged()
) )
.subscribe(search => { .subscribe(search => this.router.navigate([], { queryParams: { search }, queryParamsHandling: 'merge' }))
this.search = search
this.reloadPlugins()
})
this.reloadPlugins()
} }
onSearchChange (event: Event) { onSearchChange (event: Event) {
@ -74,8 +76,6 @@ export class PluginSearchComponent implements OnInit {
this.pagination.currentPage = 1 this.pagination.currentPage = 1
this.plugins = [] this.plugins = []
this.router.navigate([], { queryParams: { pluginType: this.pluginType } })
this.loadMorePlugins() this.loadMorePlugins()
} }

View File

@ -1,9 +0,0 @@
<div class="admin-sub-header">
<div class="admin-sub-nav">
<a i18n routerLink="list-installed" routerLinkActive="active">Installed</a>
<a i18n routerLink="search" routerLinkActive="active">Search</a>
</div>
</div>
<router-outlet></router-outlet>

View File

@ -1,7 +0,0 @@
import { Component } from '@angular/core'
@Component({
templateUrl: './plugins.component.html'
})
export class PluginsComponent {
}

View File

@ -2,14 +2,12 @@ import { Routes } from '@angular/router'
import { PluginListInstalledComponent } from '@app/+admin/plugins/plugin-list-installed/plugin-list-installed.component' import { PluginListInstalledComponent } from '@app/+admin/plugins/plugin-list-installed/plugin-list-installed.component'
import { PluginSearchComponent } from '@app/+admin/plugins/plugin-search/plugin-search.component' import { PluginSearchComponent } from '@app/+admin/plugins/plugin-search/plugin-search.component'
import { PluginShowInstalledComponent } from '@app/+admin/plugins/plugin-show-installed/plugin-show-installed.component' import { PluginShowInstalledComponent } from '@app/+admin/plugins/plugin-show-installed/plugin-show-installed.component'
import { PluginsComponent } from '@app/+admin/plugins/plugins.component'
import { UserRightGuard } from '@app/core' import { UserRightGuard } from '@app/core'
import { UserRight } from '@shared/models' import { UserRight } from '@shared/models'
export const PluginsRoutes: Routes = [ export const PluginsRoutes: Routes = [
{ {
path: 'plugins', path: 'plugins',
component: PluginsComponent,
canActivate: [ UserRightGuard ], canActivate: [ UserRightGuard ],
data: { data: {
userRight: UserRight.MANAGE_PLUGINS userRight: UserRight.MANAGE_PLUGINS

View File

@ -1,2 +1,3 @@
export * from './plugin-api.service' export * from './plugin-api.service'
export * from './plugin-card.component' export * from './plugin-card.component'
export * from './plugin-navigation.component'

View File

@ -25,19 +25,6 @@ export class PluginApiService {
private pluginService: PluginService private pluginService: PluginService
) { } ) { }
getPluginTypeOptions () {
return [
{
label: $localize`Plugins`,
value: PluginType.PLUGIN
},
{
label: $localize`Themes`,
value: PluginType.THEME
}
]
}
getPluginTypeLabel (type: PluginType) { getPluginTypeLabel (type: PluginType) {
if (type === PluginType.PLUGIN) { if (type === PluginType.PLUGIN) {
return $localize`plugin` return $localize`plugin`

View File

@ -0,0 +1,11 @@
<div class="root">
<div class="btn-group" role="group" i18n-aria-label aria-label="Navigate between installed plugins and themes or find new ones">
<a i18n routerLink="/admin/plugins/list-installed" [queryParams]="{ pluginType: pluginType }" routerLinkActive="active">Installed</a>
<a i18n routerLink="/admin/plugins/search" [queryParams]="{ pluginType: pluginType }" routerLinkActive="active">Search</a>
</div>
<div class="btn-group" role="group" i18n-aria-label aria-label="Navigate between plugins and themes">
<a [ngClass]="{ active: pluginType === 1 }" routerLink="." [queryParams]="{ pluginType: 1 }" queryParamsHandling="merge" class="">Plugins</a>
<a [ngClass]="{ active: pluginType === 2 }" routerLink="." [queryParams]="{ pluginType: 2 }" queryParamsHandling="merge" class="">Themes</a>
</div>
</div>

View File

@ -1,8 +1,11 @@
@use '_variables' as *; @use '_variables' as *;
@use '_mixins' as *; @use '_mixins' as *;
.toggle-plugin-type { .root {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin-bottom: 30px; }
.btn-group:not(:last-child) {
@include margin-right(15px);
} }

View File

@ -0,0 +1,11 @@
import { Component, Input } from '@angular/core'
import { PluginType } from '@shared/models/plugins'
@Component({
selector: 'my-plugin-navigation',
templateUrl: './plugin-navigation.component.html',
styleUrls: [ './plugin-navigation.component.scss' ]
})
export class PluginNavigationComponent {
@Input() pluginType: PluginType
}

View File

@ -261,28 +261,6 @@ my-input-toggle-hidden ::ng-deep input {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 30px; margin-bottom: 30px;
.admin-sub-nav a {
@include disable-default-a-behaviour;
font-size: 16px;
color: pvar(--mainForegroundColor);
padding: 5px 15px;
border-radius: 0.25rem;
font-weight: $font-semibold;
opacity: 0.6;
&.active {
background-color: pvar(--submenuBackgroundColor);
}
&.active,
&:hover,
&:active,
&:focus {
opacity: 1;
}
}
} }
// In tables, don't have a hover different background // In tables, don't have a hover different background
@ -402,19 +380,6 @@ ngx-loading-bar {
.admin-sub-header { .admin-sub-header {
flex-direction: column; flex-direction: column;
.admin-sub-nav {
display: block;
overflow-x: auto;
white-space: nowrap;
height: 50px;
padding: 10px 0;
width: 100%;
a {
@include margin-left(5px);
}
}
} }
my-markdown-textarea { my-markdown-textarea {

View File

@ -334,6 +334,34 @@ ngb-tooltip-window {
} }
} }
.btn-group {
font-weight: $font-semibold;
.active {
@include orange-button;
}
:not(.active) {
@include grey-button;
}
> * {
@include peertube-button-link;
box-shadow: none !important;
&:not(:first-child) {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
&:not(:last-child) {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
}
}
// input box-shadow on focus // input box-shadow on focus
.form-control { .form-control {
font-size: 15px; font-size: 15px;