From d00dc28dd73ad9dd419d5a5ac6ac747cefbc6e8b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 10 Jul 2019 18:30:27 +0200 Subject: [PATCH] WIP plugins: list installed plugins in client --- client/src/app/+admin/admin-routing.module.ts | 4 +- client/src/app/+admin/admin.component.html | 4 ++ client/src/app/+admin/admin.component.ts | 4 ++ client/src/app/+admin/admin.module.ts | 15 +++- client/src/app/+admin/plugins/index.ts | 1 + .../plugin-list-installed.component.html | 13 ++++ .../plugin-list-installed.component.scss | 8 +++ .../plugin-list-installed.component.ts | 72 +++++++++++++++++++ .../plugin-search.component.html | 0 .../plugin-search.component.scss | 2 + .../plugin-search/plugin-search.component.ts | 30 ++++++++ .../plugin-show-installed.component.html | 0 .../plugin-show-installed.component.scss | 2 + .../plugin-show-installed.component.ts | 14 ++++ .../app/+admin/plugins/plugins.component.html | 11 +++ .../app/+admin/plugins/plugins.component.scss | 7 ++ .../app/+admin/plugins/plugins.component.ts | 8 +++ .../src/app/+admin/plugins/plugins.routes.ts | 53 ++++++++++++++ .../plugins/shared/plugin-api.service.ts | 50 +++++++++++++ client/src/app/core/plugins/plugin.service.ts | 2 +- client/src/app/core/theme/theme.service.ts | 5 ++ server/controllers/api/index.ts | 4 +- 22 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 client/src/app/+admin/plugins/index.ts create mode 100644 client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html create mode 100644 client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.scss create mode 100644 client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts create mode 100644 client/src/app/+admin/plugins/plugin-search/plugin-search.component.html create mode 100644 client/src/app/+admin/plugins/plugin-search/plugin-search.component.scss create mode 100644 client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts create mode 100644 client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.html create mode 100644 client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.scss create mode 100644 client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts create mode 100644 client/src/app/+admin/plugins/plugins.component.html create mode 100644 client/src/app/+admin/plugins/plugins.component.scss create mode 100644 client/src/app/+admin/plugins/plugins.component.ts create mode 100644 client/src/app/+admin/plugins/plugins.routes.ts create mode 100644 client/src/app/+admin/plugins/shared/plugin-api.service.ts diff --git a/client/src/app/+admin/admin-routing.module.ts b/client/src/app/+admin/admin-routing.module.ts index 215da1e4f..79c57221b 100644 --- a/client/src/app/+admin/admin-routing.module.ts +++ b/client/src/app/+admin/admin-routing.module.ts @@ -9,6 +9,7 @@ import { FollowsRoutes } from './follows' import { UsersRoutes } from './users' import { ModerationRoutes } from '@app/+admin/moderation/moderation.routes' import { SystemRoutes } from '@app/+admin/system' +import { PluginsRoutes } from '@app/+admin/plugins/plugins.routes' const adminRoutes: Routes = [ { @@ -26,7 +27,8 @@ const adminRoutes: Routes = [ ...UsersRoutes, ...ModerationRoutes, ...SystemRoutes, - ...ConfigRoutes + ...ConfigRoutes, + ...PluginsRoutes ] } ] diff --git a/client/src/app/+admin/admin.component.html b/client/src/app/+admin/admin.component.html index 98f45a7d1..9a3d90c18 100644 --- a/client/src/app/+admin/admin.component.html +++ b/client/src/app/+admin/admin.component.html @@ -16,6 +16,10 @@ Configuration + + Plugins/Themes + + System diff --git a/client/src/app/+admin/admin.component.ts b/client/src/app/+admin/admin.component.ts index 408de4837..b23999d40 100644 --- a/client/src/app/+admin/admin.component.ts +++ b/client/src/app/+admin/admin.component.ts @@ -28,6 +28,10 @@ export class AdminComponent { return this.auth.getUser().hasRight(UserRight.MANAGE_CONFIGURATION) } + hasPluginsRight () { + return this.auth.getUser().hasRight(UserRight.MANAGE_PLUGINS) + } + hasLogsRight () { return this.auth.getUser().hasRight(UserRight.MANAGE_LOGS) } diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index 9ab883f60..256b7e1f5 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts @@ -21,11 +21,18 @@ import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } f import { JobsComponent } from '@app/+admin/system/jobs/jobs.component' import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+admin/system' import { DebugComponent, DebugService } from '@app/+admin/system/debug' +import { PluginsComponent } from '@app/+admin/plugins/plugins.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 { PluginShowInstalledComponent } from '@app/+admin/plugins/plugin-show-installed/plugin-show-installed.component' +import { SelectButtonModule } from 'primeng/primeng' +import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' @NgModule({ imports: [ AdminRoutingModule, TableModule, + SelectButtonModule, SharedModule ], @@ -52,6 +59,11 @@ import { DebugComponent, DebugService } from '@app/+admin/system/debug' InstanceServerBlocklistComponent, InstanceAccountBlocklistComponent, + PluginsComponent, + PluginListInstalledComponent, + PluginSearchComponent, + PluginShowInstalledComponent, + SystemComponent, JobsComponent, LogsComponent, @@ -70,7 +82,8 @@ import { DebugComponent, DebugService } from '@app/+admin/system/debug' JobService, LogsService, DebugService, - ConfigService + ConfigService, + PluginApiService ] }) export class AdminModule { } diff --git a/client/src/app/+admin/plugins/index.ts b/client/src/app/+admin/plugins/index.ts new file mode 100644 index 000000000..b75a94556 --- /dev/null +++ b/client/src/app/+admin/plugins/index.ts @@ -0,0 +1 @@ +export * from './plugins.component' diff --git a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html new file mode 100644 index 000000000..6bb8bcd75 --- /dev/null +++ b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.html @@ -0,0 +1,13 @@ +
+ +
+ +
+ {{ getNoResultMessage() }} +
+ +
+
+ {{ plugin.name }} +
+
diff --git a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.scss b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.scss new file mode 100644 index 000000000..9e98fcd34 --- /dev/null +++ b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.scss @@ -0,0 +1,8 @@ +@import '_variables'; +@import '_mixins'; + +.toggle-plugin-type { + display: flex; + justify-content: center; + margin-bottom: 30px; +} diff --git a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts new file mode 100644 index 000000000..9745bc36b --- /dev/null +++ b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts @@ -0,0 +1,72 @@ +import { Component, OnInit } from '@angular/core' +import { PluginType } from '@shared/models/plugins/plugin.type' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' +import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model' +import { Notifier } from '@app/core' +import { PeerTubePlugin } from '@shared/models/plugins/peertube-plugin.model' + +@Component({ + selector: 'my-plugin-list-installed', + templateUrl: './plugin-list-installed.component.html', + styleUrls: [ './plugin-list-installed.component.scss' ] +}) +export class PluginListInstalledComponent implements OnInit { + pluginTypeOptions: { label: string, value: PluginType }[] = [] + pluginType: PluginType = PluginType.PLUGIN + + pagination: ComponentPagination = { + currentPage: 1, + itemsPerPage: 10 + } + sort = 'name' + + plugins: PeerTubePlugin[] = [] + + constructor ( + private i18n: I18n, + private pluginService: PluginApiService, + private notifier: Notifier + ) { + this.pluginTypeOptions = this.pluginService.getPluginTypeOptions() + } + + ngOnInit () { + this.reloadPlugins() + } + + reloadPlugins () { + this.pagination.currentPage = 1 + this.plugins = [] + + this.loadMorePlugins() + } + + loadMorePlugins () { + this.pluginService.getPlugins(this.pluginType, this.pagination, this.sort) + .subscribe( + res => { + this.plugins = this.plugins.concat(res.data) + this.pagination.totalItems = res.total + }, + + err => this.notifier.error(err.message) + ) + } + + onNearOfBottom () { + if (!hasMoreItems(this.pagination)) return + + this.pagination.currentPage += 1 + + this.loadMorePlugins() + } + + getNoResultMessage () { + if (this.pluginType === PluginType.PLUGIN) { + return this.i18n('You don\'t have plugins installed yet.') + } + + return this.i18n('You don\'t have themes installed yet.') + } +} diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.html new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.scss b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.scss new file mode 100644 index 000000000..5e6774739 --- /dev/null +++ b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.scss @@ -0,0 +1,2 @@ +@import '_variables'; +@import '_mixins'; diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts new file mode 100644 index 000000000..db1f91f3d --- /dev/null +++ b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts @@ -0,0 +1,30 @@ +import { Component, OnInit, ViewChild } from '@angular/core' +import { Notifier } from '@app/core' +import { SortMeta } from 'primeng/components/common/sortmeta' +import { ConfirmService, ServerService } from '../../../core' +import { RestPagination, RestTable, UserService } from '../../../shared' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { User } from '../../../../../../shared' +import { UserBanModalComponent } from '@app/shared/moderation' +import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' +import { PluginType } from '@shared/models/plugins/plugin.type' +import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' + +@Component({ + selector: 'my-plugin-search', + templateUrl: './plugin-search.component.html', + styleUrls: [ './plugin-search.component.scss' ] +}) +export class PluginSearchComponent implements OnInit { + pluginTypeOptions: { label: string, value: PluginType }[] = [] + + constructor ( + private i18n: I18n, + private pluginService: PluginApiService + ) { + this.pluginTypeOptions = this.pluginService.getPluginTypeOptions() + } + + ngOnInit () { + } +} diff --git a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.html b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.html new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.scss b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.scss new file mode 100644 index 000000000..5e6774739 --- /dev/null +++ b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.scss @@ -0,0 +1,2 @@ +@import '_variables'; +@import '_mixins'; diff --git a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts new file mode 100644 index 000000000..f65599532 --- /dev/null +++ b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts @@ -0,0 +1,14 @@ +import { Component, OnInit } from '@angular/core' + +@Component({ + selector: 'my-plugin-show-installed', + templateUrl: './plugin-show-installed.component.html', + styleUrls: [ './plugin-show-installed.component.scss' ] +}) +export class PluginShowInstalledComponent implements OnInit { + + ngOnInit () { + + } + +} diff --git a/client/src/app/+admin/plugins/plugins.component.html b/client/src/app/+admin/plugins/plugins.component.html new file mode 100644 index 000000000..3dc4939da --- /dev/null +++ b/client/src/app/+admin/plugins/plugins.component.html @@ -0,0 +1,11 @@ +
+
Plugins/Themes
+ +
+ Installed + + Search +
+
+ + diff --git a/client/src/app/+admin/plugins/plugins.component.scss b/client/src/app/+admin/plugins/plugins.component.scss new file mode 100644 index 000000000..9f61bcf7a --- /dev/null +++ b/client/src/app/+admin/plugins/plugins.component.scss @@ -0,0 +1,7 @@ +@import '_variables'; +@import '_mixins'; + +.form-sub-title { + flex-grow: 0; + margin-right: 30px; +} diff --git a/client/src/app/+admin/plugins/plugins.component.ts b/client/src/app/+admin/plugins/plugins.component.ts new file mode 100644 index 000000000..6ec6fa4a1 --- /dev/null +++ b/client/src/app/+admin/plugins/plugins.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core' + +@Component({ + templateUrl: './plugins.component.html', + styleUrls: [ './plugins.component.scss' ] +}) +export class PluginsComponent { +} diff --git a/client/src/app/+admin/plugins/plugins.routes.ts b/client/src/app/+admin/plugins/plugins.routes.ts new file mode 100644 index 000000000..58b5534fb --- /dev/null +++ b/client/src/app/+admin/plugins/plugins.routes.ts @@ -0,0 +1,53 @@ +import { Routes } from '@angular/router' + +import { UserRightGuard } from '../../core' +import { UserRight } from '../../../../../shared' +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 { PluginShowInstalledComponent } from '@app/+admin/plugins/plugin-show-installed/plugin-show-installed.component' +import { PluginsComponent } from '@app/+admin/plugins/plugins.component' + +export const PluginsRoutes: Routes = [ + { + path: 'plugins', + component: PluginsComponent, + canActivate: [ UserRightGuard ], + data: { + userRight: UserRight.MANAGE_PLUGINS + }, + children: [ + { + path: '', + redirectTo: 'list-installed', + pathMatch: 'full' + }, + { + path: 'list-installed', + component: PluginListInstalledComponent, + data: { + meta: { + title: 'List installed plugins' + } + } + }, + { + path: 'search', + component: PluginSearchComponent, + data: { + meta: { + title: 'Search plugins' + } + } + }, + { + path: 'show/:name', + component: PluginShowInstalledComponent, + data: { + meta: { + title: 'Show plugin' + } + } + } + ] + } +] diff --git a/client/src/app/+admin/plugins/shared/plugin-api.service.ts b/client/src/app/+admin/plugins/shared/plugin-api.service.ts new file mode 100644 index 000000000..bfc2b918f --- /dev/null +++ b/client/src/app/+admin/plugins/shared/plugin-api.service.ts @@ -0,0 +1,50 @@ +import { catchError } from 'rxjs/operators' +import { HttpClient, HttpParams } from '@angular/common/http' +import { Injectable } from '@angular/core' +import { environment } from '../../../../environments/environment' +import { RestExtractor, RestService } from '../../../shared' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { PluginType } from '@shared/models/plugins/plugin.type' +import { ComponentPagination } from '@app/shared/rest/component-pagination.model' +import { ResultList } from '@shared/models' +import { PeerTubePlugin } from '@shared/models/plugins/peertube-plugin.model' + +@Injectable() +export class PluginApiService { + private static BASE_APPLICATION_URL = environment.apiUrl + '/api/v1/plugins' + + constructor ( + private authHttp: HttpClient, + private restExtractor: RestExtractor, + private restService: RestService, + private i18n: I18n + ) { } + + getPluginTypeOptions () { + return [ + { + label: this.i18n('Plugin'), + value: PluginType.PLUGIN + }, + { + label: this.i18n('Theme'), + value: PluginType.THEME + } + ] + } + + getPlugins ( + type: PluginType, + componentPagination: ComponentPagination, + sort: string + ) { + const pagination = this.restService.componentPaginationToRestPagination(componentPagination) + + let params = new HttpParams() + params = this.restService.addRestGetParams(params, pagination, sort) + params = params.append('type', type.toString()) + + return this.authHttp.get>(PluginApiService.BASE_APPLICATION_URL, { params }) + .pipe(catchError(res => this.restExtractor.handleError(res))) + } +} diff --git a/client/src/app/core/plugins/plugin.service.ts b/client/src/app/core/plugins/plugin.service.ts index 4abe9ee8d..86bde2d02 100644 --- a/client/src/app/core/plugins/plugin.service.ts +++ b/client/src/app/core/plugins/plugin.service.ts @@ -5,7 +5,7 @@ import { ServerService } from '@app/core/server/server.service' import { ClientScript } from '@shared/models/plugins/plugin-package-json.model' import { PluginScope } from '@shared/models/plugins/plugin-scope.type' import { environment } from '../../../environments/environment' -import { RegisterHookOptions } from '@shared/models/plugins/register.model' +import { RegisterHookOptions } from '@shared/models/plugins/register-hook.model' import { ReplaySubject } from 'rxjs' import { first, shareReplay } from 'rxjs/operators' diff --git a/client/src/app/core/theme/theme.service.ts b/client/src/app/core/theme/theme.service.ts index ad59c203b..76199d1cc 100644 --- a/client/src/app/core/theme/theme.service.ts +++ b/client/src/app/core/theme/theme.service.ts @@ -83,6 +83,7 @@ export class ThemeService { console.log('Enabling %s theme.', currentTheme) this.loadTheme(currentTheme) + const theme = this.getTheme(currentTheme) if (theme) { console.log('Adding scripts of theme %s.', currentTheme) @@ -95,6 +96,10 @@ export class ThemeService { } private listenUserTheme () { + if (!this.auth.isLoggedIn()) { + this.updateCurrentTheme() + } + this.auth.userInformationLoaded .subscribe(() => this.updateCurrentTheme()) } diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index 0876283a2..6138a32de 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts @@ -14,7 +14,7 @@ import { searchRouter } from './search' import { overviewsRouter } from './overviews' import { videoPlaylistRouter } from './video-playlist' import { CONFIG } from '../../initializers/config' -import { pluginsRouter } from '../plugins' +import { pluginRouter } from './plugins' const apiRouter = express.Router() @@ -43,7 +43,7 @@ apiRouter.use('/videos', videosRouter) apiRouter.use('/jobs', jobsRouter) apiRouter.use('/search', searchRouter) apiRouter.use('/overviews', overviewsRouter) -apiRouter.use('/plugins', pluginsRouter) +apiRouter.use('/plugins', pluginRouter) apiRouter.use('/ping', pong) apiRouter.use('/*', badRequest) -- 2.41.0