From 72c33e716fecd1826dcf645957f8669821f91ff3 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 28 May 2020 11:15:38 +0200 Subject: Support broadcast messages --- .../edit-custom-config.component.html | 55 ++++++++++++++++- .../edit-custom-config.component.scss | 6 +- .../edit-custom-config.component.ts | 6 ++ client/src/app/app.component.html | 10 +++ client/src/app/app.component.scss | 38 ++++++++++++ client/src/app/app.component.ts | 71 ++++++++++++++++++---- client/src/app/core/server/server.service.ts | 17 +++++- 7 files changed, 186 insertions(+), 17 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index 5703d5a2e..4ee573696 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html @@ -276,6 +276,58 @@ +
+
+
BROADCAST MESSAGE
+
+ Display a message on your instance +
+
+ +
+ + + +
+ +
+ +
+ +
+ +
+ +
+ +
+
{{ formErrors.broadcastMessage.level }}
+
+ +
+ + +
{{ formErrors.broadcastMessage.message }}
+
+ +
+ +
+
+
NEW USERS
@@ -801,8 +853,9 @@
+ It seems like the configuration is invalid. Please search for potential errors in the different tabs. + - It seems like the configuration is invalid. Please search for potential errors in the different tabs.
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss index 9ee960ad6..2bfa92da4 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss @@ -76,4 +76,8 @@ ngb-tabset:not(.previews) ::ng-deep { .nav-link { font-size: 105%; } -} \ No newline at end of file +} + +.submit-error { + margin-bottom: 20px; +} diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index cea314cea..6d59494c8 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts @@ -215,6 +215,12 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A indexUrl: this.customConfigValidatorsService.INDEX_URL } } + }, + broadcastMessage: { + enabled: null, + level: null, + dismissable: null, + message: null } } diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index b0d2e5050..b243c129b 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html @@ -25,6 +25,16 @@
+ +
+
+ + +
+
diff --git a/client/src/app/app.component.scss b/client/src/app/app.component.scss index 0c33dc4a1..27fd69c8d 100644 --- a/client/src/app/app.component.scss +++ b/client/src/app/app.component.scss @@ -1,5 +1,7 @@ @import '_variables'; @import '_mixins'; +@import '~bootstrap/scss/functions'; +@import '~bootstrap/scss/variables'; .peertube-container { padding-bottom: 20px; @@ -88,3 +90,39 @@ flex: 1; } } + +.broadcast-message { + min-height: 50px; + text-align: center; + margin-bottom: 0; + border-radius: 0; + display: grid; + grid-template-columns: 1fr 30px; + column-gap: 10px; + + my-global-icon { + justify-self: center; + align-self: center; + cursor: pointer; + + width: 20px; + } + + @each $color, $value in $theme-colors { + &.alert-#{$color} { + my-global-icon { + @include apply-svg-color(theme-color-level($color, $alert-color-level)); + } + } + } + + ::ng-deep { + p { + font-size: 16px; + } + + p:last-child { + margin-bottom: 0; + } + } +} diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 12c0efd8a..a464e90fa 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -4,7 +4,7 @@ import { Event, GuardsCheckStart, NavigationEnd, Router, Scroll } from '@angular import { AuthService, RedirectService, ServerService, ThemeService } from '@app/core' import { is18nPath } from '../../../shared/models/i18n' import { ScreenService } from '@app/shared/misc/screen.service' -import { filter, map, pairwise } from 'rxjs/operators' +import { filter, map, pairwise, first } from 'rxjs/operators' import { Hotkey, HotkeysService } from 'angular2-hotkeys' import { I18n } from '@ngx-translate/i18n-polyfill' import { PlatformLocation, ViewportScroller } from '@angular/common' @@ -19,6 +19,10 @@ import { ServerConfig, UserRole } from '@shared/models' import { User } from '@app/shared' import { InstanceService } from '@app/shared/instance/instance.service' import { MenuService } from './core/menu/menu.service' +import { BroadcastMessageLevel } from '@shared/models/server' +import { MarkdownService } from './shared/renderer' +import { concat } from 'rxjs' +import { peertubeLocalStorage } from './shared/misc/peertube-web-storage' @Component({ selector: 'my-app', @@ -26,11 +30,14 @@ import { MenuService } from './core/menu/menu.service' styleUrls: [ './app.component.scss' ] }) export class AppComponent implements OnInit, AfterViewInit { + private static BROADCAST_MESSAGE_KEY = 'app-broadcast-message-dismissed' + @ViewChild('welcomeModal') welcomeModal: WelcomeModalComponent @ViewChild('instanceConfigWarningModal') instanceConfigWarningModal: InstanceConfigWarningModalComponent @ViewChild('customModal') customModal: CustomModalComponent customCSS: SafeHtml + broadcastMessage: { message: string, dismissable: boolean, class: string } | null = null private serverConfig: ServerConfig @@ -50,6 +57,7 @@ export class AppComponent implements OnInit, AfterViewInit { private hooks: HooksService, private location: PlatformLocation, private modalService: NgbModal, + private markdownService: MarkdownService, public menu: MenuService ) { } @@ -81,6 +89,7 @@ export class AppComponent implements OnInit, AfterViewInit { this.initRouteEvents() this.injectJS() this.injectCSS() + this.injectBroadcastMessage() this.initHotkeys() @@ -97,6 +106,12 @@ export class AppComponent implements OnInit, AfterViewInit { return this.authService.isLoggedIn() } + hideBroadcastMessage () { + peertubeLocalStorage.setItem(AppComponent.BROADCAST_MESSAGE_KEY, this.serverConfig.broadcastMessage.message) + + this.broadcastMessage = null + } + private initRouteEvents () { let resetScroll = true const eventsObs = this.router.events @@ -165,6 +180,36 @@ export class AppComponent implements OnInit, AfterViewInit { ).subscribe(() => this.menu.isMenuDisplayed = false) // User clicked on a link in the menu, change the page } + private injectBroadcastMessage () { + concat( + this.serverService.getConfig().pipe(first()), + this.serverService.configReloaded + ).subscribe(async config => { + this.broadcastMessage = null + + const messageConfig = config.broadcastMessage + + if (messageConfig.enabled) { + // Already dismissed this message? + if (messageConfig.dismissable && localStorage.getItem(AppComponent.BROADCAST_MESSAGE_KEY) === messageConfig.message) { + return + } + + const classes: { [id in BroadcastMessageLevel]: string } = { + info: 'alert-info', + warning: 'alert-warning', + error: 'alert-danger' + } + + this.broadcastMessage = { + message: await this.markdownService.completeMarkdownToHTML(messageConfig.message), + dismissable: messageConfig.dismissable, + class: classes[messageConfig.level] + } + } + }) + } + private injectJS () { // Inject JS this.serverService.getConfig() @@ -182,17 +227,19 @@ export class AppComponent implements OnInit, AfterViewInit { private injectCSS () { // Inject CSS if modified (admin config settings) - this.serverService.configReloaded - .subscribe(() => { - const headStyle = document.querySelector('style.custom-css-style') - if (headStyle) headStyle.parentNode.removeChild(headStyle) - - // We test customCSS if the admin removed the css - if (this.customCSS || this.serverConfig.instance.customizations.css) { - const styleTag = '' - this.customCSS = this.domSanitizer.bypassSecurityTrustHtml(styleTag) - } - }) + concat( + this.serverService.getConfig().pipe(first()), + this.serverService.configReloaded + ).subscribe(config => { + const headStyle = document.querySelector('style.custom-css-style') + if (headStyle) headStyle.parentNode.removeChild(headStyle) + + // We test customCSS if the admin removed the css + if (this.customCSS || config.instance.customizations.css) { + const styleTag = '' + this.customCSS = this.domSanitizer.bypassSecurityTrustHtml(styleTag) + } + }) } private async loadPlugins () { diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index eac8f85e4..fdfbe4c02 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -21,7 +21,7 @@ export class ServerService { private static CONFIG_LOCAL_STORAGE_KEY = 'server-config' - configReloaded = new Subject() + configReloaded = new Subject() private localeObservable: Observable private videoLicensesObservable: Observable[]> @@ -139,6 +139,12 @@ export class ServerService { indexUrl: 'https://instances.joinpeertube.org' } } + }, + broadcastMessage: { + enabled: false, + message: '', + level: 'info', + dismissable: false } } @@ -162,6 +168,11 @@ export class ServerService { resetConfig () { this.configLoaded = false this.configReset = true + + // Notify config update + this.getConfig().subscribe(() => { + // empty, to fire a reset config event + }) } getConfig () { @@ -175,9 +186,9 @@ export class ServerService { this.config = config this.configLoaded = true }), - tap(() => { + tap(config => { if (this.configReset) { - this.configReloaded.next() + this.configReloaded.next(config) this.configReset = false } }), -- cgit v1.2.3