Add action dropdown descriptions

This commit is contained in:
Rigel Kent 2020-01-15 19:25:51 +01:00 committed by Chocobozzz
parent c78d3db71b
commit 9b82d49da8
15 changed files with 88 additions and 52 deletions

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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,13 +54,16 @@ export class UserListComponent extends RestTable implements OnInit {
this.initialize()
this.bulkUserActions = [
[
{
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)
},
@ -68,7 +71,9 @@ export class UserListComponent extends RestTable implements OnInit {
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),
@ -78,6 +83,7 @@ export class UserListComponent extends RestTable implements OnInit {
}
}
]
]
}
openBanUserModal (users: User[]) {

View File

@ -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>

View File

@ -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'

View File

@ -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>

View File

@ -52,6 +52,7 @@
.dropdown-menu {
.dropdown-item {
display: flex;
cursor: pointer;
color: #000 !important;

View File

@ -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

View File

@ -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)
}

View File

@ -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"

View File

@ -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>

View File

@ -69,6 +69,15 @@
button {
cursor: pointer;
}
.dropdown-item-neutral {
cursor: default;
&:hover,
&:focus {
background-color: inherit;
}
}
}
.dropdown-header {

View File

@ -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 ]">

View File

@ -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;
}