<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>
<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"
<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"
<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"
<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"
<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"
<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"
</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">
<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>
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
selectedUsers: User[] = []
- bulkUserActions: DropdownAction<User[]>[] = []
+ bulkUserActions: DropdownAction<User[]>[][] = []
private serverConfig: ServerConfig
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)
+ }
+ }
+ ]
]
}
<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>
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'
<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>
.dropdown-menu {
.dropdown-item {
+ display: flex;
cursor: pointer;
color: #000 !important;
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
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
},
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)
}
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)
}
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)
}
<form novalidate [formGroup]="form" (ngSubmit)="formValidated()">
- <div class="form-group">
+ <div class="form-group mb-2">
<input type="email"
formControlName="text"
class="form-control"
<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>
button {
cursor: pointer;
}
+
+ .dropdown-item-neutral {
+ cursor: default;
+
+ &:hover,
+ &:focus {
+ background-color: inherit;
+ }
+ }
}
.dropdown-header {
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>
<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 ]">
}
p-inputswitch {
+ height: 26px;
+
.ui-inputswitch-checked .ui-inputswitch-slider {
background-color: var(--mainColor) !important;
}