Add alert and hide upload view when no upload is possible (#2966)
* Add alert and hide upload view when no upload is possible * Add about instance link to alert * Hide videos and imports links when no upload is possible * Correct curly spacing lint * Put logic canUpload to User model + add isHidden param to to-menu-dropdown * Use canSeeVideoLinks from user model * Rename and change logic canUpload to isUploadDisabled * Use isDisplayed() method intead of isHidden value * Refactor client and check videos count using quota Co-authored-by: kimsible <kimsible@users.noreply.github.com> Co-authored-by: Chocobozzz <me@florianbigard.com>
This commit is contained in:
parent
0579dee3b2
commit
dfe3f7b72e
|
@ -74,12 +74,24 @@ export class AdminComponent implements OnInit {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasUsersRight()) this.menuEntries.push({ label: this.i18n('Users'), routerLink: '/admin/users' })
|
if (this.hasUsersRight()) {
|
||||||
|
this.menuEntries.push({ label: this.i18n('Users'), routerLink: '/admin/users' })
|
||||||
|
}
|
||||||
|
|
||||||
if (this.hasServerFollowRight()) this.menuEntries.push(federationItems)
|
if (this.hasServerFollowRight()) this.menuEntries.push(federationItems)
|
||||||
if (this.hasAbusesRight() || this.hasVideoBlocklistRight()) this.menuEntries.push(moderationItems)
|
if (this.hasAbusesRight() || this.hasVideoBlocklistRight()) this.menuEntries.push(moderationItems)
|
||||||
if (this.hasConfigRight()) this.menuEntries.push({ label: this.i18n('Configuration'), routerLink: '/admin/config' })
|
|
||||||
if (this.hasPluginsRight()) this.menuEntries.push({ label: this.i18n('Plugins/Themes'), routerLink: '/admin/plugins' })
|
if (this.hasConfigRight()) {
|
||||||
if (this.hasJobsRight() || this.hasLogsRight() || this.hasDebugRight()) this.menuEntries.push({ label: this.i18n('System'), routerLink: '/admin/system' })
|
this.menuEntries.push({ label: this.i18n('Configuration'), routerLink: '/admin/config' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hasPluginsRight()) {
|
||||||
|
this.menuEntries.push({ label: this.i18n('Plugins/Themes'), routerLink: '/admin/plugins' })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hasJobsRight() || this.hasLogsRight() || this.hasDebugRight()) {
|
||||||
|
this.menuEntries.push({ label: this.i18n('System'), routerLink: '/admin/system' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasUsersRight () {
|
hasUsersRight () {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Component, OnInit } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
import { ServerService } from '@app/core'
|
import { AuthService, ServerService, AuthUser } from '@app/core'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { ServerConfig } from '@shared/models'
|
import { ServerConfig } from '@shared/models'
|
||||||
import { TopMenuDropdownParam } from '../shared/shared-main/misc/top-menu-dropdown.component'
|
import { TopMenuDropdownParam } from '../shared/shared-main/misc/top-menu-dropdown.component'
|
||||||
|
@ -11,11 +11,13 @@ import { TopMenuDropdownParam } from '../shared/shared-main/misc/top-menu-dropdo
|
||||||
})
|
})
|
||||||
export class MyAccountComponent implements OnInit {
|
export class MyAccountComponent implements OnInit {
|
||||||
menuEntries: TopMenuDropdownParam[] = []
|
menuEntries: TopMenuDropdownParam[] = []
|
||||||
|
user: AuthUser
|
||||||
|
|
||||||
private serverConfig: ServerConfig
|
private serverConfig: ServerConfig
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private serverService: ServerService,
|
private serverService: ServerService,
|
||||||
|
private authService: AuthService,
|
||||||
private i18n: I18n
|
private i18n: I18n
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
@ -24,6 +26,20 @@ export class MyAccountComponent implements OnInit {
|
||||||
this.serverService.getConfig()
|
this.serverService.getConfig()
|
||||||
.subscribe(config => this.serverConfig = config)
|
.subscribe(config => this.serverConfig = config)
|
||||||
|
|
||||||
|
this.user = this.authService.getUser()
|
||||||
|
|
||||||
|
this.authService.userInformationLoaded.subscribe(
|
||||||
|
() => this.buildMenu()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
isVideoImportEnabled () {
|
||||||
|
const importConfig = this.serverConfig.import.videos
|
||||||
|
|
||||||
|
return importConfig.http.enabled || importConfig.torrent.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildMenu () {
|
||||||
const libraryEntries: TopMenuDropdownParam = {
|
const libraryEntries: TopMenuDropdownParam = {
|
||||||
label: this.i18n('My library'),
|
label: this.i18n('My library'),
|
||||||
children: [
|
children: [
|
||||||
|
@ -35,7 +51,8 @@ export class MyAccountComponent implements OnInit {
|
||||||
{
|
{
|
||||||
label: this.i18n('My videos'),
|
label: this.i18n('My videos'),
|
||||||
routerLink: '/my-account/videos',
|
routerLink: '/my-account/videos',
|
||||||
iconName: 'videos'
|
iconName: 'videos',
|
||||||
|
isDisplayed: () => this.user.canSeeVideosLink
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.i18n('My playlists'),
|
label: this.i18n('My playlists'),
|
||||||
|
@ -45,7 +62,7 @@ export class MyAccountComponent implements OnInit {
|
||||||
{
|
{
|
||||||
label: this.i18n('My subscriptions'),
|
label: this.i18n('My subscriptions'),
|
||||||
routerLink: '/my-account/subscriptions',
|
routerLink: '/my-account/subscriptions',
|
||||||
iconName: 'subscriptions'
|
iconName: 'inbox-full'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.i18n('My history'),
|
label: this.i18n('My history'),
|
||||||
|
@ -59,7 +76,8 @@ export class MyAccountComponent implements OnInit {
|
||||||
libraryEntries.children.push({
|
libraryEntries.children.push({
|
||||||
label: 'My imports',
|
label: 'My imports',
|
||||||
routerLink: '/my-account/video-imports',
|
routerLink: '/my-account/video-imports',
|
||||||
iconName: 'cloud-download'
|
iconName: 'cloud-download',
|
||||||
|
isDisplayed: () => this.user.canSeeVideosLink
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,11 +115,4 @@ export class MyAccountComponent implements OnInit {
|
||||||
miscEntries
|
miscEntries
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
isVideoImportEnabled () {
|
|
||||||
const importConfig = this.serverConfig.import.videos
|
|
||||||
|
|
||||||
return importConfig.http.enabled || importConfig.torrent.enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
<div class="margin-content">
|
<div *ngIf="user.isUploadDisabled()" class="no-upload">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<div i18n>Sorry, the upload feature is disabled for your account. If you want to add videos, an admin must unlock your quota.</div>
|
||||||
|
<a i18n routerLink="/about/instance" class="about-link">Read instance rules for help</a>
|
||||||
|
</div>
|
||||||
|
<img src="/client/assets/images/mascot/defeated.svg" alt="defeated mascot">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="!user.isUploadDisabled()" class="margin-content">
|
||||||
<div class="alert alert-warning" *ngIf="isRootUser()" i18n>
|
<div class="alert alert-warning" *ngIf="isRootUser()" i18n>
|
||||||
We recommend you to not use the <strong>root</strong> user to publish your videos, since it's the super-admin account of your instance.
|
We recommend you to not use the <strong>root</strong> user to publish your videos, since it's the super-admin account of your instance.
|
||||||
<br />
|
<br />
|
||||||
|
@ -45,4 +53,4 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div [ngbNavOutlet]="nav"></div>
|
<div [ngbNavOutlet]="nav"></div>
|
||||||
</div>
|
</div>
|
|
@ -6,6 +6,34 @@ $border-type: solid;
|
||||||
$border-color: #EAEAEA;
|
$border-color: #EAEAEA;
|
||||||
$nav-link-height: 40px;
|
$nav-link-height: 40px;
|
||||||
|
|
||||||
|
.no-upload {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.about-link {
|
||||||
|
@include peertube-button-link;
|
||||||
|
@include orange-button;
|
||||||
|
|
||||||
|
height: fit-content;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 75px;
|
||||||
|
width: 220px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-height: 600px) {
|
||||||
|
img {
|
||||||
|
margin-top: 5px;
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.margin-content {
|
.margin-content {
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
|
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
|
||||||
import { AuthService, CanComponentDeactivate, ServerService, User } from '@app/core'
|
import { AuthService, AuthUser, CanComponentDeactivate, ServerService } from '@app/core'
|
||||||
import { ServerConfig } from '@shared/models'
|
import { ServerConfig } from '@shared/models'
|
||||||
import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component'
|
import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component'
|
||||||
import { VideoImportUrlComponent } from './video-add-components/video-import-url.component'
|
import { VideoImportUrlComponent } from './video-add-components/video-import-url.component'
|
||||||
|
@ -15,7 +15,7 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
|
||||||
@ViewChild('videoImportUrl') videoImportUrl: VideoImportUrlComponent
|
@ViewChild('videoImportUrl') videoImportUrl: VideoImportUrlComponent
|
||||||
@ViewChild('videoImportTorrent') videoImportTorrent: VideoImportTorrentComponent
|
@ViewChild('videoImportTorrent') videoImportTorrent: VideoImportTorrentComponent
|
||||||
|
|
||||||
user: User = null
|
user: AuthUser = null
|
||||||
|
|
||||||
secondStepType: 'upload' | 'import-url' | 'import-torrent'
|
secondStepType: 'upload' | 'import-url' | 'import-torrent'
|
||||||
videoName: string
|
videoName: string
|
||||||
|
@ -37,6 +37,8 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
|
||||||
|
|
||||||
this.serverService.getConfig()
|
this.serverService.getConfig()
|
||||||
.subscribe(config => this.serverConfig = config)
|
.subscribe(config => this.serverConfig = config)
|
||||||
|
|
||||||
|
this.user = this.auth.getUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
onFirstStepDone (type: 'upload' | 'import-url' | 'import-torrent', videoName: string) {
|
onFirstStepDone (type: 'upload' | 'import-url' | 'import-torrent', videoName: string) {
|
||||||
|
@ -80,6 +82,6 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
isRootUser () {
|
isRootUser () {
|
||||||
return this.auth.getUser().username === 'root'
|
return this.user.username === 'root'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { Observable, of } from 'rxjs'
|
||||||
|
import { map } from 'rxjs/operators'
|
||||||
import { User } from '@app/core/users/user.model'
|
import { User } from '@app/core/users/user.model'
|
||||||
import { peertubeLocalStorage } from '@app/helpers/peertube-web-storage'
|
import { peertubeLocalStorage } from '@app/helpers/peertube-web-storage'
|
||||||
import {
|
import {
|
||||||
|
@ -7,7 +9,8 @@ import {
|
||||||
NSFWPolicyType,
|
NSFWPolicyType,
|
||||||
User as ServerUserModel,
|
User as ServerUserModel,
|
||||||
UserRight,
|
UserRight,
|
||||||
UserRole
|
UserRole,
|
||||||
|
UserVideoQuota
|
||||||
} from '@shared/models'
|
} from '@shared/models'
|
||||||
|
|
||||||
export type TokenOptions = {
|
export type TokenOptions = {
|
||||||
|
@ -74,6 +77,8 @@ export class AuthUser extends User implements ServerMyUserModel {
|
||||||
tokens: Tokens
|
tokens: Tokens
|
||||||
specialPlaylists: MyUserSpecialPlaylist[]
|
specialPlaylists: MyUserSpecialPlaylist[]
|
||||||
|
|
||||||
|
canSeeVideosLink = true
|
||||||
|
|
||||||
static load () {
|
static load () {
|
||||||
const usernameLocalStorage = peertubeLocalStorage.getItem(this.KEYS.USERNAME)
|
const usernameLocalStorage = peertubeLocalStorage.getItem(this.KEYS.USERNAME)
|
||||||
if (usernameLocalStorage) {
|
if (usernameLocalStorage) {
|
||||||
|
@ -150,4 +155,26 @@ export class AuthUser extends User implements ServerMyUserModel {
|
||||||
peertubeLocalStorage.setItem(AuthUser.KEYS.AUTO_PLAY_VIDEO, JSON.stringify(this.autoPlayVideo))
|
peertubeLocalStorage.setItem(AuthUser.KEYS.AUTO_PLAY_VIDEO, JSON.stringify(this.autoPlayVideo))
|
||||||
this.tokens.save()
|
this.tokens.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
computeCanSeeVideosLink (quotaObservable: Observable<UserVideoQuota>): Observable<boolean> {
|
||||||
|
if (!this.isUploadDisabled()) {
|
||||||
|
this.canSeeVideosLink = true
|
||||||
|
return of(this.canSeeVideosLink)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user has videos
|
||||||
|
return quotaObservable.pipe(
|
||||||
|
map(({ videoQuotaUsed }) => {
|
||||||
|
if (videoQuotaUsed !== 0) {
|
||||||
|
// User already uploaded videos, so it can see the link
|
||||||
|
this.canSeeVideosLink = true
|
||||||
|
} else {
|
||||||
|
// No videos, no upload so the user don't need to see the videos link
|
||||||
|
this.canSeeVideosLink = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.canSeeVideosLink
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,4 +149,8 @@ export class User implements UserServerModel {
|
||||||
updateAccountAvatar (newAccountAvatar: Avatar) {
|
updateAccountAvatar (newAccountAvatar: Avatar) {
|
||||||
this.account.updateAvatar(newAccountAvatar)
|
this.account.updateAvatar(newAccountAvatar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isUploadDisabled () {
|
||||||
|
return this.videoQuota === 0 || this.videoQuotaDaily === 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
<div *ngIf="isLoggedIn" class="panel-block">
|
<div *ngIf="isLoggedIn" class="panel-block">
|
||||||
<div i18n class="block-title">MY LIBRARY</div>
|
<div i18n class="block-title">MY LIBRARY</div>
|
||||||
|
|
||||||
<a routerLink="/my-account/videos" routerLinkActive="active">
|
<a *ngIf="user.canSeeVideosLink" routerLink="/my-account/videos" routerLinkActive="active">
|
||||||
<my-global-icon iconName="videos" aria-hidden="true"></my-global-icon>
|
<my-global-icon iconName="videos" aria-hidden="true"></my-global-icon>
|
||||||
<ng-container i18n>Videos</ng-container>
|
<ng-container i18n>Videos</ng-container>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
import { HotkeysService } from 'angular2-hotkeys'
|
import { HotkeysService } from 'angular2-hotkeys'
|
||||||
|
import * as debug from 'debug'
|
||||||
|
import { switchMap } from 'rxjs/operators'
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core'
|
import { Component, OnInit, ViewChild } from '@angular/core'
|
||||||
import { AuthService, AuthStatus, RedirectService, ScreenService, ServerService, User, UserService } from '@app/core'
|
import { AuthService, AuthStatus, AuthUser, RedirectService, ScreenService, ServerService, UserService } from '@app/core'
|
||||||
import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
|
import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
|
||||||
import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
|
import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { ServerConfig, UserRight, VideoConstant } from '@shared/models'
|
import { ServerConfig, UserRight, VideoConstant } from '@shared/models'
|
||||||
|
|
||||||
|
const logger = debug('peertube:menu:MenuComponent')
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-menu',
|
selector: 'my-menu',
|
||||||
templateUrl: './menu.component.html',
|
templateUrl: './menu.component.html',
|
||||||
styleUrls: [ './menu.component.scss' ]
|
styleUrls: ['./menu.component.scss']
|
||||||
})
|
})
|
||||||
export class MenuComponent implements OnInit {
|
export class MenuComponent implements OnInit {
|
||||||
@ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent
|
@ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent
|
||||||
@ViewChild('quickSettingsModal', { static: true }) quickSettingsModal: QuickSettingsModalComponent
|
@ViewChild('quickSettingsModal', { static: true }) quickSettingsModal: QuickSettingsModalComponent
|
||||||
|
|
||||||
user: User
|
user: AuthUser
|
||||||
isLoggedIn: boolean
|
isLoggedIn: boolean
|
||||||
|
|
||||||
userHasAdminAccess = false
|
userHasAdminAccess = false
|
||||||
|
@ -25,7 +29,7 @@ export class MenuComponent implements OnInit {
|
||||||
|
|
||||||
private languages: VideoConstant<string>[] = []
|
private languages: VideoConstant<string>[] = []
|
||||||
private serverConfig: ServerConfig
|
private serverConfig: ServerConfig
|
||||||
private routesPerRight: { [ role in UserRight ]?: string } = {
|
private routesPerRight: { [role in UserRight]?: string } = {
|
||||||
[UserRight.MANAGE_USERS]: '/admin/users',
|
[UserRight.MANAGE_USERS]: '/admin/users',
|
||||||
[UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
|
[UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
|
||||||
[UserRight.MANAGE_ABUSES]: '/admin/moderation/abuses',
|
[UserRight.MANAGE_ABUSES]: '/admin/moderation/abuses',
|
||||||
|
@ -62,21 +66,30 @@ export class MenuComponent implements OnInit {
|
||||||
.subscribe(config => this.serverConfig = config)
|
.subscribe(config => this.serverConfig = config)
|
||||||
|
|
||||||
this.isLoggedIn = this.authService.isLoggedIn()
|
this.isLoggedIn = this.authService.isLoggedIn()
|
||||||
if (this.isLoggedIn === true) this.user = this.authService.getUser()
|
if (this.isLoggedIn === true) {
|
||||||
this.computeIsUserHasAdminAccess()
|
this.user = this.authService.getUser()
|
||||||
|
this.computeVideosLink()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.computeAdminAccess()
|
||||||
|
|
||||||
this.authService.loginChangedSource.subscribe(
|
this.authService.loginChangedSource.subscribe(
|
||||||
status => {
|
status => {
|
||||||
if (status === AuthStatus.LoggedIn) {
|
if (status === AuthStatus.LoggedIn) {
|
||||||
this.isLoggedIn = true
|
this.isLoggedIn = true
|
||||||
this.user = this.authService.getUser()
|
this.user = this.authService.getUser()
|
||||||
this.computeIsUserHasAdminAccess()
|
|
||||||
console.log('Logged in.')
|
this.computeAdminAccess()
|
||||||
|
this.computeVideosLink()
|
||||||
|
|
||||||
|
logger('Logged in.')
|
||||||
} else if (status === AuthStatus.LoggedOut) {
|
} else if (status === AuthStatus.LoggedOut) {
|
||||||
this.isLoggedIn = false
|
this.isLoggedIn = false
|
||||||
this.user = undefined
|
this.user = undefined
|
||||||
this.computeIsUserHasAdminAccess()
|
|
||||||
console.log('Logged out.')
|
this.computeAdminAccess()
|
||||||
|
|
||||||
|
logger('Logged out.')
|
||||||
} else {
|
} else {
|
||||||
console.error('Unknown auth status: ' + status)
|
console.error('Unknown auth status: ' + status)
|
||||||
}
|
}
|
||||||
|
@ -84,15 +97,15 @@ export class MenuComponent implements OnInit {
|
||||||
)
|
)
|
||||||
|
|
||||||
this.hotkeysService.cheatSheetToggle
|
this.hotkeysService.cheatSheetToggle
|
||||||
.subscribe(isOpen => this.helpVisible = isOpen)
|
.subscribe(isOpen => this.helpVisible = isOpen)
|
||||||
|
|
||||||
this.serverService.getVideoLanguages()
|
this.serverService.getVideoLanguages()
|
||||||
.subscribe(languages => {
|
.subscribe(languages => {
|
||||||
this.languages = languages
|
this.languages = languages
|
||||||
|
|
||||||
this.authService.userInformationLoaded
|
this.authService.userInformationLoaded
|
||||||
.subscribe(() => this.buildUserLanguages())
|
.subscribe(() => this.buildUserLanguages())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
get language () {
|
get language () {
|
||||||
|
@ -116,7 +129,7 @@ export class MenuComponent implements OnInit {
|
||||||
|
|
||||||
isRegistrationAllowed () {
|
isRegistrationAllowed () {
|
||||||
return this.serverConfig.signup.allowed &&
|
return this.serverConfig.signup.allowed &&
|
||||||
this.serverConfig.signup.allowedForCurrentIP
|
this.serverConfig.signup.allowedForCurrentIP
|
||||||
}
|
}
|
||||||
|
|
||||||
getFirstAdminRightAvailable () {
|
getFirstAdminRightAvailable () {
|
||||||
|
@ -172,7 +185,7 @@ export class MenuComponent implements OnInit {
|
||||||
this.user.webTorrentEnabled = !this.user.webTorrentEnabled
|
this.user.webTorrentEnabled = !this.user.webTorrentEnabled
|
||||||
|
|
||||||
this.userService.updateMyProfile({ webTorrentEnabled: this.user.webTorrentEnabled })
|
this.userService.updateMyProfile({ webTorrentEnabled: this.user.webTorrentEnabled })
|
||||||
.subscribe(() => this.authService.refreshUserInformation())
|
.subscribe(() => this.authService.refreshUserInformation())
|
||||||
}
|
}
|
||||||
|
|
||||||
langForLocale (localeId: string) {
|
langForLocale (localeId: string) {
|
||||||
|
@ -188,18 +201,28 @@ export class MenuComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.user.videoLanguages) {
|
if (!this.user.videoLanguages) {
|
||||||
this.videoLanguages = [ this.i18n('any language') ]
|
this.videoLanguages = [this.i18n('any language')]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.videoLanguages = this.user.videoLanguages
|
this.videoLanguages = this.user.videoLanguages
|
||||||
.map(locale => this.langForLocale(locale))
|
.map(locale => this.langForLocale(locale))
|
||||||
.map(value => value === undefined ? '?' : value)
|
.map(value => value === undefined ? '?' : value)
|
||||||
}
|
}
|
||||||
|
|
||||||
private computeIsUserHasAdminAccess () {
|
private computeAdminAccess () {
|
||||||
const right = this.getFirstAdminRightAvailable()
|
const right = this.getFirstAdminRightAvailable()
|
||||||
|
|
||||||
this.userHasAdminAccess = right !== undefined
|
this.userHasAdminAccess = right !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private computeVideosLink () {
|
||||||
|
this.authService.userInformationLoaded
|
||||||
|
.pipe(
|
||||||
|
switchMap(() => this.user.computeCanSeeVideosLink(this.userService.getMyVideoQuotaUsed()))
|
||||||
|
).subscribe(res => {
|
||||||
|
if (res === true) logger('User can see videos link.')
|
||||||
|
else logger('User cannot see videos link.')
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<div class="sub-menu" [ngClass]="{ 'no-scroll': isModalOpened }">
|
<div class="sub-menu" [ngClass]="{ 'no-scroll': isModalOpened }">
|
||||||
<ng-container *ngFor="let menuEntry of menuEntries; index as id">
|
<ng-container *ngFor="let menuEntry of menuEntries; index as id">
|
||||||
|
|
||||||
<a *ngIf="menuEntry.routerLink" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page title-page-settings">{{ menuEntry.label }}</a>
|
<a *ngIf="menuEntry.routerLink && isDisplayed(menuEntry)" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page title-page-settings">{{ menuEntry.label }}</a>
|
||||||
|
|
||||||
<div *ngIf="!menuEntry.routerLink" ngbDropdown class="parent-entry"
|
<div *ngIf="!menuEntry.routerLink && isDisplayed(menuEntry)" ngbDropdown class="parent-entry"
|
||||||
#dropdown="ngbDropdown" autoClose="outside">
|
#dropdown="ngbDropdown" autoClose="outside">
|
||||||
<span
|
<span
|
||||||
*ngIf="isInSmallView"
|
*ngIf="isInSmallView"
|
||||||
|
@ -25,11 +25,15 @@
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div ngbDropdownMenu>
|
<div ngbDropdownMenu>
|
||||||
<a *ngFor="let menuChild of menuEntry.children" class="dropdown-item" [ngClass]="{ icon: hasIcons, active: suffixLabels[menuEntry.label] === menuChild.label }" [routerLink]="menuChild.routerLink">
|
<ng-container *ngFor="let menuChild of menuEntry.children">
|
||||||
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>
|
<a *ngIf="isDisplayed(menuChild)" class="dropdown-item"
|
||||||
|
[ngClass]="{ icon: hasIcons, active: suffixLabels[menuEntry.label] === menuChild.label }"
|
||||||
|
[routerLink]="menuChild.routerLink">
|
||||||
|
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>
|
||||||
|
|
||||||
{{ menuChild.label }}
|
{{ menuChild.label }}
|
||||||
</a>
|
</a>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -39,13 +43,15 @@
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<ng-container *ngFor="let menuEntry of menuEntries; index as id">
|
<ng-container *ngFor="let menuEntry of menuEntries; index as id">
|
||||||
<div [ngClass]="{ hidden: id !== currentMenuEntryIndex }">
|
<div [ngClass]="{ hidden: id !== currentMenuEntryIndex }">
|
||||||
<a *ngFor="let menuChild of menuEntry.children"
|
<ng-container *ngFor="let menuChild of menuEntry.children">
|
||||||
[ngClass]="{ icon: hasIcons }"
|
<a *ngIf="isDisplayed(menuChild)"
|
||||||
[routerLink]="menuChild.routerLink" routerLinkActive="active" (click)="dismissOtherModals()">
|
[ngClass]="{ icon: hasIcons }"
|
||||||
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>
|
[routerLink]="menuChild.routerLink" routerLinkActive="active" (click)="dismissOtherModals()">
|
||||||
|
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>
|
||||||
|
|
||||||
{{ menuChild.label }}
|
{{ menuChild.label }}
|
||||||
</a>
|
</a>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,12 +9,14 @@ import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
export type TopMenuDropdownParam = {
|
export type TopMenuDropdownParam = {
|
||||||
label: string
|
label: string
|
||||||
routerLink?: string
|
routerLink?: string
|
||||||
|
isDisplayed?: () => boolean // Default: () => true
|
||||||
|
|
||||||
children?: {
|
children?: {
|
||||||
label: string
|
label: string
|
||||||
routerLink: string
|
routerLink: string
|
||||||
|
|
||||||
iconName?: GlobalIconName
|
iconName?: GlobalIconName
|
||||||
|
|
||||||
|
isDisplayed?: () => boolean // Default: () => true
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +94,12 @@ export class TopMenuDropdownComponent implements OnInit, OnDestroy {
|
||||||
this.modalService.dismissAll()
|
this.modalService.dismissAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isDisplayed (obj: { isDisplayed?: () => boolean }) {
|
||||||
|
if (typeof obj.isDisplayed !== 'function') return true
|
||||||
|
|
||||||
|
return obj.isDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
private updateChildLabels (path: string) {
|
private updateChildLabels (path: string) {
|
||||||
this.suffixLabels = {}
|
this.suffixLabels = {}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user