Add action dropdown descriptions
This commit is contained in:
parent
c78d3db71b
commit
9b82d49da8
|
@ -23,7 +23,7 @@
|
|||
<span *ngIf="account.mutedServerByInstance" class="badge badge-danger" i18n>Instance muted by your instance</span>
|
||||
|
||||
<my-user-moderation-dropdown
|
||||
buttonSize="small" [account]="account" [user]="user" placement="bottom-right auto"
|
||||
buttonSize="small" [account]="account" [user]="user" placement="bottom-left auto"
|
||||
(userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()"
|
||||
></my-user-moderation-dropdown>
|
||||
</div>
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceModerationInformation">Moderation information</label><my-help helpType="markdownText"></my-help>
|
||||
<div class="label-small-info">Who moderates the instance? What is the policy regarding NSFW videos? Political videos? etc</div>
|
||||
<div i18n class="label-small-info">Who moderates the instance? What is the policy regarding NSFW videos? Political videos? etc</div>
|
||||
|
||||
<my-markdown-textarea
|
||||
name="instanceModerationInformation" formControlName="moderationInformation" textareaWidth="500px" [previewColumn]="true"
|
||||
|
@ -131,7 +131,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceAdministrator">Who is behind the instance?</label>
|
||||
<div class="label-small-info">A single person? A non-profit? A company?</div>
|
||||
<div i18n class="label-small-info">A single person? A non-profit? A company?</div>
|
||||
|
||||
<my-markdown-textarea
|
||||
name="instanceAdministrator" formControlName="administrator" textareaWidth="500px" textareaHeight="75px" [previewColumn]="true"
|
||||
|
@ -143,7 +143,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceCreationReason">Why did you create this instance?</label>
|
||||
<div class="label-small-info">To share your personal videos? To open registrations and allow people to upload what they want?</div>
|
||||
<div i18n class="label-small-info">To share your personal videos? To open registrations and allow people to upload what they want?</div>
|
||||
|
||||
<textarea
|
||||
id="instanceCreationReason" formControlName="creationReason" class="small"
|
||||
|
@ -154,7 +154,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceMaintenanceLifetime">How long do you plan to maintain this instance?</label>
|
||||
<div class="label-small-info">It's important to know for users who want to register on your instance</div>
|
||||
<div i18n class="label-small-info">It's important to know for users who want to register on your instance</div>
|
||||
|
||||
<textarea
|
||||
id="instanceMaintenanceLifetime" formControlName="maintenanceLifetime" class="small"
|
||||
|
@ -165,7 +165,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceBusinessModel">How will you finance the PeerTube server?</label>
|
||||
<div class="label-small-info">With your own funds? With users donations? Advertising?</div>
|
||||
<div i18n class="label-small-info">With your own funds? With users donations? Advertising?</div>
|
||||
|
||||
<textarea
|
||||
id="instanceBusinessModel" formControlName="businessModel" class="small"
|
||||
|
@ -178,7 +178,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label i18n for="instanceHardwareInformation">What server/hardware does the instance run on?</label>
|
||||
<div class="label-small-info">2vCore 2GB RAM/or directly the link to the server you rent etc</div>
|
||||
<div i18n class="label-small-info">2vCore 2GB RAM/or directly the link to the server you rent etc</div>
|
||||
|
||||
<my-markdown-textarea
|
||||
name="instanceHardwareInformation" formControlName="hardwareInformation" textareaWidth="500px" textareaHeight="75px" [previewColumn]="true"
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
</a>
|
||||
</td>
|
||||
|
||||
<td *ngIf="!requiresEmailVerification || user.blocked; else emailWithVerificationStatus">{{ user.email }}</td>
|
||||
<td *ngIf="!requiresEmailVerification || user.blocked; else emailWithVerificationStatus" [title]="user.email">{{ user.email }}</td>
|
||||
|
||||
<ng-template #emailWithVerificationStatus>
|
||||
<td *ngIf="user.emailVerified === false; else emailVerifiedNotFalse" i18n-title title="User's email must be verified to login">
|
||||
|
@ -81,7 +81,7 @@
|
|||
|
||||
<td>{{ user.videoQuotaUsed }} / {{ user.videoQuota }}</td>
|
||||
<td>{{ user.roleLabel }}</td>
|
||||
<td>{{ user.createdAt }}</td>
|
||||
<td [title]="user.createdAt">{{ user.createdAt }}</td>
|
||||
<td class="action-cell">
|
||||
<my-user-moderation-dropdown *ngIf="!isInSelectionMode()" [user]="user" (userChanged)="onUserChanged()" (userDeleted)="onUserChanged()">
|
||||
</my-user-moderation-dropdown>
|
||||
|
|
|
@ -23,7 +23,7 @@ export class UserListComponent extends RestTable implements OnInit {
|
|||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||
|
||||
selectedUsers: User[] = []
|
||||
bulkUserActions: DropdownAction<User[]>[] = []
|
||||
bulkUserActions: DropdownAction<User[]>[][] = []
|
||||
|
||||
private serverConfig: ServerConfig
|
||||
|
||||
|
@ -54,29 +54,35 @@ export class UserListComponent extends RestTable implements OnInit {
|
|||
this.initialize()
|
||||
|
||||
this.bulkUserActions = [
|
||||
{
|
||||
label: this.i18n('Delete'),
|
||||
handler: users => this.removeUsers(users),
|
||||
isDisplayed: users => users.every(u => this.authUser.canManage(u))
|
||||
},
|
||||
{
|
||||
label: this.i18n('Ban'),
|
||||
handler: users => this.openBanUserModal(users),
|
||||
isDisplayed: users => users.every(u => this.authUser.canManage(u) && u.blocked === false)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unban'),
|
||||
handler: users => this.unbanUsers(users),
|
||||
isDisplayed: users => users.every(u => this.authUser.canManage(u) && u.blocked === true)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Set Email as Verified'),
|
||||
handler: users => this.setEmailsAsVerified(users),
|
||||
isDisplayed: users => {
|
||||
return this.requiresEmailVerification &&
|
||||
users.every(u => this.authUser.canManage(u) && !u.blocked && u.emailVerified === false)
|
||||
[
|
||||
{
|
||||
label: this.i18n('Delete'),
|
||||
description: this.i18n('Videos will be deleted, comments will be tombstoned.'),
|
||||
handler: users => this.removeUsers(users),
|
||||
isDisplayed: users => users.every(u => this.authUser.canManage(u))
|
||||
},
|
||||
{
|
||||
label: this.i18n('Ban'),
|
||||
description: this.i18n('Videos will be kept as private, comments will be kept as is.'),
|
||||
handler: users => this.openBanUserModal(users),
|
||||
isDisplayed: users => users.every(u => this.authUser.canManage(u) && u.blocked === false)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unban'),
|
||||
handler: users => this.unbanUsers(users),
|
||||
isDisplayed: users => users.every(u => this.authUser.canManage(u) && u.blocked === true)
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
label: this.i18n('Set Email as Verified'),
|
||||
handler: users => this.setEmailsAsVerified(users),
|
||||
isDisplayed: users => {
|
||||
return this.requiresEmailVerification &&
|
||||
users.every(u => this.authUser.canManage(u) && !u.blocked && u.emailVerified === false)
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="top-buttons">
|
||||
<div class="history-switch">
|
||||
<p-inputSwitch [(ngModel)]="videosHistoryEnabled" (ngModelChange)="onVideosHistoryChange()"></p-inputSwitch>
|
||||
<label i18n>Enable video history</label>
|
||||
<label i18n>Video history</label>
|
||||
</div>
|
||||
|
||||
<button class="delete-history" (click)="deleteHistory()" i18n>
|
||||
|
|
|
@ -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 { debounceTime, filter, first, map, pairwise, skip, switchMap } from 'rxjs/operators'
|
||||
import { debounceTime, filter, map, pairwise } from 'rxjs/operators'
|
||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { fromEvent } from 'rxjs'
|
||||
|
|
|
@ -15,17 +15,23 @@
|
|||
<ng-container *ngFor="let action of actions">
|
||||
<ng-container *ngIf="action.isDisplayed === undefined || action.isDisplayed(entry) === true">
|
||||
|
||||
<a *ngIf="action.linkBuilder" [ngClass]="{ 'with-icon': !!action.iconName }" class="dropdown-item" [routerLink]="action.linkBuilder(entry)">
|
||||
<ng-template #templateActionLabel let-action>
|
||||
<my-global-icon *ngIf="action.iconName" [iconName]="action.iconName" [ngClass]="'icon-' + action.iconName"></my-global-icon>
|
||||
{{ action.label }}
|
||||
<div class="d-flex flex-column">
|
||||
<span i18n>{{ action.label }}</span>
|
||||
<small class="text-muted" *ngIf="action.description">{{ action.description }}</small>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<a *ngIf="action.linkBuilder" [ngClass]="{ 'with-icon': !!action.iconName }" class="dropdown-item" [routerLink]="action.linkBuilder(entry)" [title]="action.title || ''">
|
||||
<ng-container *ngTemplateOutlet="templateActionLabel; context:{ $implicit: action }"></ng-container>
|
||||
</a>
|
||||
|
||||
<span
|
||||
*ngIf="!action.linkBuilder" [ngClass]="{ 'with-icon': !!action.iconName }" (click)="action.handler(entry)"
|
||||
class="custom-action dropdown-item" role="button"
|
||||
class="custom-action dropdown-item" role="button" [title]="action.title || ''"
|
||||
>
|
||||
<my-global-icon *ngIf="action.iconName" [iconName]="action.iconName" [ngClass]="'icon-' + action.iconName"></my-global-icon>
|
||||
{{ action.label }}
|
||||
<ng-container *ngTemplateOutlet="templateActionLabel; context:{ $implicit: action }"></ng-container>
|
||||
</span>
|
||||
|
||||
</ng-container>
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
|
||||
.dropdown-menu {
|
||||
.dropdown-item {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
color: #000 !important;
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ import { GlobalIconName } from '@app/shared/images/global-icon.component'
|
|||
export type DropdownAction<T> = {
|
||||
label?: string
|
||||
iconName?: GlobalIconName
|
||||
description?: string
|
||||
title?: string
|
||||
handler?: (a: T) => any
|
||||
linkBuilder?: (a: T) => (string | number)[]
|
||||
isDisplayed?: (a: T) => boolean
|
||||
|
|
|
@ -243,20 +243,24 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
|
|||
if (this.user && authUser.hasRight(UserRight.MANAGE_USERS) && authUser.canManage(this.user)) {
|
||||
this.userActions.push([
|
||||
{
|
||||
label: this.i18n('Edit user'),
|
||||
label: this.i18n('Edit'),
|
||||
description: this.i18n('Change quota, role, and more.'),
|
||||
linkBuilder: ({ user }) => this.getRouterUserEditLink(user)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Delete user'),
|
||||
label: this.i18n('Delete'),
|
||||
description: this.i18n('Videos will be deleted, comments will be tombstoned.'),
|
||||
handler: ({ user }) => this.removeUser(user)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Ban user'),
|
||||
label: this.i18n('Ban'),
|
||||
description: this.i18n('Videos will be kept as private, comments will be kept as is.'),
|
||||
handler: ({ user }) => this.openBanUserModal(user),
|
||||
isDisplayed: ({ user }) => !user.blocked
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unban user'),
|
||||
description: this.i18n('Allow the user to login and create videos/comments again'),
|
||||
handler: ({ user }) => this.unbanUser(user),
|
||||
isDisplayed: ({ user }) => user.blocked
|
||||
},
|
||||
|
@ -274,21 +278,25 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
|
|||
this.userActions.push([
|
||||
{
|
||||
label: this.i18n('Mute this account'),
|
||||
description: this.i18n('Hide any content from that user for you.'),
|
||||
isDisplayed: ({ account }) => account.mutedByUser === false,
|
||||
handler: ({ account }) => this.blockAccountByUser(account)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unmute this account'),
|
||||
description: this.i18n('Show back content from that user for you.'),
|
||||
isDisplayed: ({ account }) => account.mutedByUser === true,
|
||||
handler: ({ account }) => this.unblockAccountByUser(account)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Mute the instance'),
|
||||
description: this.i18n('Hide any content from that instance for you.'),
|
||||
isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === false,
|
||||
handler: ({ account }) => this.blockServerByUser(account.host)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unmute the instance'),
|
||||
description: this.i18n('Show back content from that instance for you.'),
|
||||
isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true,
|
||||
handler: ({ account }) => this.unblockServerByUser(account.host)
|
||||
}
|
||||
|
@ -301,11 +309,13 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
|
|||
instanceActions = instanceActions.concat([
|
||||
{
|
||||
label: this.i18n('Mute this account by your instance'),
|
||||
description: this.i18n('Hide any content from that user for you, your instance and its users.'),
|
||||
isDisplayed: ({ account }) => account.mutedByInstance === false,
|
||||
handler: ({ account }) => this.blockAccountByInstance(account)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unmute this account by your instance'),
|
||||
description: this.i18n('Show back content from that user for you, your instance and its users.'),
|
||||
isDisplayed: ({ account }) => account.mutedByInstance === true,
|
||||
handler: ({ account }) => this.unblockAccountByInstance(account)
|
||||
}
|
||||
|
@ -317,11 +327,13 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
|
|||
instanceActions = instanceActions.concat([
|
||||
{
|
||||
label: this.i18n('Mute the instance by your instance'),
|
||||
description: this.i18n('Hide any content from that instance for you, your instance and its users.'),
|
||||
isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === false,
|
||||
handler: ({ account }) => this.blockServerByInstance(account.host)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unmute the instance by your instance'),
|
||||
description: this.i18n('Show back content from that instance for you, your instance and its users.'),
|
||||
isDisplayed: ({ account }) => !account.userId && account.mutedServerByInstance === true,
|
||||
handler: ({ account }) => this.unblockServerByInstance(account.host)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<form novalidate [formGroup]="form" (ngSubmit)="formValidated()">
|
||||
<div class="form-group">
|
||||
<div class="form-group mb-2">
|
||||
<input type="email"
|
||||
formControlName="text"
|
||||
class="form-control"
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
<span *ngIf="isUserLoggedIn()" i18n>Subscribe with your local account</span>
|
||||
</button>
|
||||
|
||||
<button class="dropdown-item" i18n>Subscribe with a Mastodon account:</button>
|
||||
<button class="dropdown-item dropdown-item-neutral" i18n>Subscribe with a Mastodon account:</button>
|
||||
<my-remote-subscribe showHelp="true" [uri]="uri"></my-remote-subscribe>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
|
|
@ -69,6 +69,15 @@
|
|||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-item-neutral {
|
||||
cursor: default;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-header {
|
||||
|
|
|
@ -10,14 +10,7 @@
|
|||
tabindex="-1"
|
||||
class="video-miniature-name"
|
||||
[routerLink]="[ '/videos/watch', video.uuid ]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur }"
|
||||
>
|
||||
<ng-container *ngIf="displayOptions.privacyLabel">
|
||||
<span *ngIf="isUnlistedVideo()" class="badge badge-warning" i18n>Unlisted</span>
|
||||
<span *ngIf="isPrivateVideo()" class="badge badge-danger" i18n>Private</span>
|
||||
</ng-container>
|
||||
|
||||
{{ video.name }}
|
||||
</a>
|
||||
>{{ video.name }}</a>
|
||||
|
||||
<span class="video-miniature-created-at-views">
|
||||
<my-date-toggle *ngIf="displayOptions.date" [date]="video.publishedAt"></my-date-toggle>
|
||||
|
@ -26,6 +19,11 @@
|
|||
<ng-container *ngIf="displayOptions.date && displayOptions.views"> • </ng-container>
|
||||
<ng-container i18n *ngIf="displayOptions.views">{video.views, plural, =1 {1 view} other {{{ video.views | myNumberFormatter }} views}}</ng-container>
|
||||
</span>
|
||||
|
||||
<ng-container *ngIf="displayOptions.privacyLabel">
|
||||
<span *ngIf="isUnlistedVideo()" class="badge badge-warning ml-1" i18n>Unlisted</span>
|
||||
<span *ngIf="isPrivateVideo()" class="badge badge-danger ml-1" i18n>Private</span>
|
||||
</ng-container>
|
||||
</span>
|
||||
|
||||
<a tabindex="-1" *ngIf="displayOptions.by && displayOwnerAccount()" class="video-miniature-account" [routerLink]="[ '/accounts', video.byAccount ]">
|
||||
|
|
|
@ -374,6 +374,8 @@ p-tablecheckbox:hover div .ui-chkbox-box {
|
|||
}
|
||||
|
||||
p-inputswitch {
|
||||
height: 26px;
|
||||
|
||||
.ui-inputswitch-checked .ui-inputswitch-slider {
|
||||
background-color: var(--mainColor) !important;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue