diff options
Diffstat (limited to 'client/src/app')
13 files changed, 103 insertions, 31 deletions
diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html index 166fafef0..ef5a6c648 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.html +++ b/client/src/app/+admin/users/user-list/user-list.component.html | |||
@@ -30,8 +30,9 @@ | |||
30 | <td>{{ user.roleLabel }}</td> | 30 | <td>{{ user.roleLabel }}</td> |
31 | <td>{{ user.createdAt }}</td> | 31 | <td>{{ user.createdAt }}</td> |
32 | <td class="action-cell"> | 32 | <td class="action-cell"> |
33 | <my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button> | 33 | <my-action-dropdown i18n-label label="Actions" [actions]="userActions" [entry]="user"></my-action-dropdown> |
34 | <my-delete-button (click)="removeUser(user)"></my-delete-button> | 34 | <!--<my-edit-button [routerLink]="getRouterUserEditLink(user)"></my-edit-button>--> |
35 | <!--<my-delete-button (click)="removeUser(user)"></my-delete-button>--> | ||
35 | </td> | 36 | </td> |
36 | </tr> | 37 | </tr> |
37 | </ng-template> | 38 | </ng-template> |
diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index ab25608c1..3c83859e0 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts | |||
@@ -5,6 +5,7 @@ import { ConfirmService } from '../../../core' | |||
5 | import { RestPagination, RestTable, User } from '../../../shared' | 5 | import { RestPagination, RestTable, User } from '../../../shared' |
6 | import { UserService } from '../shared' | 6 | import { UserService } from '../shared' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 7 | import { I18n } from '@ngx-translate/i18n-polyfill' |
8 | import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' | ||
8 | 9 | ||
9 | @Component({ | 10 | @Component({ |
10 | selector: 'my-user-list', | 11 | selector: 'my-user-list', |
@@ -17,6 +18,7 @@ export class UserListComponent extends RestTable implements OnInit { | |||
17 | rowsPerPage = 10 | 18 | rowsPerPage = 10 |
18 | sort: SortMeta = { field: 'createdAt', order: 1 } | 19 | sort: SortMeta = { field: 'createdAt', order: 1 } |
19 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
21 | userActions: DropdownAction<User>[] = [] | ||
20 | 22 | ||
21 | constructor ( | 23 | constructor ( |
22 | private notificationsService: NotificationsService, | 24 | private notificationsService: NotificationsService, |
@@ -25,6 +27,17 @@ export class UserListComponent extends RestTable implements OnInit { | |||
25 | private i18n: I18n | 27 | private i18n: I18n |
26 | ) { | 28 | ) { |
27 | super() | 29 | super() |
30 | |||
31 | this.userActions = [ | ||
32 | { | ||
33 | type: 'edit', | ||
34 | linkBuilder: this.getRouterUserEditLink | ||
35 | }, | ||
36 | { | ||
37 | type: 'delete', | ||
38 | handler: user => this.removeUser(user) | ||
39 | } | ||
40 | ] | ||
28 | } | 41 | } |
29 | 42 | ||
30 | ngOnInit () { | 43 | ngOnInit () { |
diff --git a/client/src/app/shared/buttons/action-dropdown.component.html b/client/src/app/shared/buttons/action-dropdown.component.html new file mode 100644 index 000000000..c87ba4c82 --- /dev/null +++ b/client/src/app/shared/buttons/action-dropdown.component.html | |||
@@ -0,0 +1,16 @@ | |||
1 | <div class="dropdown-root" dropdown container="body" dropup="true" placement="right" role="button"> | ||
2 | <div class="action-button" dropdownToggle> | ||
3 | <span class="icon icon-action"></span> | ||
4 | </div> | ||
5 | |||
6 | <ul *dropdownMenu class="dropdown-menu" id="more-menu" role="menu" aria-labelledby="single-button"> | ||
7 | <li role="menuitem" *ngFor="let action of actions"> | ||
8 | <my-delete-button *ngIf="action.type === 'delete'" [label]="action.label" (click)="action.handler(entry)"></my-delete-button> | ||
9 | <my-edit-button *ngIf="action.type === 'edit'" [label]="action.label" [routerLink]="action.linkBuilder(entry)"></my-edit-button> | ||
10 | |||
11 | <a *ngIf="action.type === 'custom'" class="dropdown-item" href="#" (click)="action.handler(entry)"> | ||
12 | <span *ngIf="action.iconClass" class="icon" [ngClass]="action.iconClass"></span> <ng-container>{{ action.label }}</ng-container> | ||
13 | </a> | ||
14 | </li> | ||
15 | </ul> | ||
16 | </div> \ No newline at end of file | ||
diff --git a/client/src/app/shared/buttons/action-dropdown.component.scss b/client/src/app/shared/buttons/action-dropdown.component.scss new file mode 100644 index 000000000..cc459b972 --- /dev/null +++ b/client/src/app/shared/buttons/action-dropdown.component.scss | |||
@@ -0,0 +1,21 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .action-button { | ||
5 | @include peertube-button; | ||
6 | @include grey-button; | ||
7 | |||
8 | &:hover, &:active, &:focus { | ||
9 | background-color: $grey-color; | ||
10 | } | ||
11 | |||
12 | display: inline-block; | ||
13 | padding: 0 10px; | ||
14 | |||
15 | .icon-action { | ||
16 | @include icon(21px); | ||
17 | |||
18 | background-image: url('../../../assets/images/video/more.svg'); | ||
19 | top: -1px; | ||
20 | } | ||
21 | } \ No newline at end of file | ||
diff --git a/client/src/app/shared/buttons/action-dropdown.component.ts b/client/src/app/shared/buttons/action-dropdown.component.ts new file mode 100644 index 000000000..407d24b80 --- /dev/null +++ b/client/src/app/shared/buttons/action-dropdown.component.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import { Component, Input } from '@angular/core' | ||
2 | |||
3 | export type DropdownAction<T> = { | ||
4 | type: 'custom' | 'delete' | 'edit' | ||
5 | label?: string | ||
6 | handler?: (T) => any | ||
7 | linkBuilder?: (T) => (string | number)[] | ||
8 | iconClass?: string | ||
9 | } | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-action-dropdown', | ||
13 | styleUrls: [ './action-dropdown.component.scss' ], | ||
14 | templateUrl: './action-dropdown.component.html' | ||
15 | }) | ||
16 | |||
17 | export class ActionDropdownComponent<T> { | ||
18 | @Input() actions: DropdownAction<T>[] = [] | ||
19 | @Input() entry: T | ||
20 | } | ||
diff --git a/client/src/app/shared/misc/button.component.scss b/client/src/app/shared/buttons/button.component.scss index 343aea207..343aea207 100644 --- a/client/src/app/shared/misc/button.component.scss +++ b/client/src/app/shared/buttons/button.component.scss | |||
diff --git a/client/src/app/shared/buttons/delete-button.component.html b/client/src/app/shared/buttons/delete-button.component.html new file mode 100644 index 000000000..792490219 --- /dev/null +++ b/client/src/app/shared/buttons/delete-button.component.html | |||
@@ -0,0 +1,6 @@ | |||
1 | <span class="action-button action-button-delete" [title]="label" role="button"> | ||
2 | <span class="icon icon-delete-grey"></span> | ||
3 | |||
4 | <span class="button-label" *ngIf="label">{{ label }}</span> | ||
5 | <span class="button-label" i18n *ngIf="!label">Delete</span> | ||
6 | </span> | ||
diff --git a/client/src/app/shared/misc/delete-button.component.ts b/client/src/app/shared/buttons/delete-button.component.ts index 2ffd98212..cd2bcccdf 100644 --- a/client/src/app/shared/misc/delete-button.component.ts +++ b/client/src/app/shared/buttons/delete-button.component.ts | |||
@@ -7,5 +7,5 @@ import { Component, Input } from '@angular/core' | |||
7 | }) | 7 | }) |
8 | 8 | ||
9 | export class DeleteButtonComponent { | 9 | export class DeleteButtonComponent { |
10 | @Input() label = 'Delete' | 10 | @Input() label: string |
11 | } | 11 | } |
diff --git a/client/src/app/shared/misc/edit-button.component.html b/client/src/app/shared/buttons/edit-button.component.html index 78fbc326e..7efc54ce7 100644 --- a/client/src/app/shared/misc/edit-button.component.html +++ b/client/src/app/shared/buttons/edit-button.component.html | |||
@@ -1,4 +1,6 @@ | |||
1 | <a class="action-button action-button-edit" [routerLink]="routerLink" title="Edit"> | 1 | <a class="action-button action-button-edit" [routerLink]="routerLink" title="Edit"> |
2 | <span class="icon icon-edit"></span> | 2 | <span class="icon icon-edit"></span> |
3 | <span i18n class="button-label">Edit</span> | 3 | |
4 | <span class="button-label" *ngIf="label">{{ label }}</span> | ||
5 | <span i18n class="button-label" *ngIf="!label">Edit</span> | ||
4 | </a> | 6 | </a> |
diff --git a/client/src/app/shared/misc/edit-button.component.ts b/client/src/app/shared/buttons/edit-button.component.ts index 201a618ec..7abaacc26 100644 --- a/client/src/app/shared/misc/edit-button.component.ts +++ b/client/src/app/shared/buttons/edit-button.component.ts | |||
@@ -7,5 +7,6 @@ import { Component, Input } from '@angular/core' | |||
7 | }) | 7 | }) |
8 | 8 | ||
9 | export class EditButtonComponent { | 9 | export class EditButtonComponent { |
10 | @Input() label: string | ||
10 | @Input() routerLink = [] | 11 | @Input() routerLink = [] |
11 | } | 12 | } |
diff --git a/client/src/app/shared/misc/delete-button.component.html b/client/src/app/shared/misc/delete-button.component.html deleted file mode 100644 index 7387d0a88..000000000 --- a/client/src/app/shared/misc/delete-button.component.html +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | <span class="action-button action-button-delete" [title]="label"> | ||
2 | <span class="icon icon-delete-grey"></span> | ||
3 | <span class="button-label">{{ label }}</span> | ||
4 | </span> | ||
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 62ce97102..94de3af9f 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -17,8 +17,8 @@ import { BytesPipe, KeysPipe, NgPipesModule } from 'ngx-pipes' | |||
17 | import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared' | 17 | import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared' |
18 | 18 | ||
19 | import { AUTH_INTERCEPTOR_PROVIDER } from './auth' | 19 | import { AUTH_INTERCEPTOR_PROVIDER } from './auth' |
20 | import { DeleteButtonComponent } from './misc/delete-button.component' | 20 | import { DeleteButtonComponent } from './buttons/delete-button.component' |
21 | import { EditButtonComponent } from './misc/edit-button.component' | 21 | import { EditButtonComponent } from './buttons/edit-button.component' |
22 | import { FromNowPipe } from './misc/from-now.pipe' | 22 | import { FromNowPipe } from './misc/from-now.pipe' |
23 | import { LoaderComponent } from './misc/loader.component' | 23 | import { LoaderComponent } from './misc/loader.component' |
24 | import { NumberFormatterPipe } from './misc/number-formatter.pipe' | 24 | import { NumberFormatterPipe } from './misc/number-formatter.pipe' |
@@ -52,6 +52,7 @@ import { VideoCaptionsValidatorsService } from '@app/shared/forms/form-validator | |||
52 | import { VideoCaptionService } from '@app/shared/video-caption' | 52 | import { VideoCaptionService } from '@app/shared/video-caption' |
53 | import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component' | 53 | import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component' |
54 | import { VideoImportService } from '@app/shared/video-import/video-import.service' | 54 | import { VideoImportService } from '@app/shared/video-import/video-import.service' |
55 | import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component' | ||
55 | 56 | ||
56 | @NgModule({ | 57 | @NgModule({ |
57 | imports: [ | 58 | imports: [ |
@@ -78,6 +79,7 @@ import { VideoImportService } from '@app/shared/video-import/video-import.servic | |||
78 | VideoFeedComponent, | 79 | VideoFeedComponent, |
79 | DeleteButtonComponent, | 80 | DeleteButtonComponent, |
80 | EditButtonComponent, | 81 | EditButtonComponent, |
82 | ActionDropdownComponent, | ||
81 | NumberFormatterPipe, | 83 | NumberFormatterPipe, |
82 | ObjectLengthPipe, | 84 | ObjectLengthPipe, |
83 | FromNowPipe, | 85 | FromNowPipe, |
@@ -110,6 +112,7 @@ import { VideoImportService } from '@app/shared/video-import/video-import.servic | |||
110 | VideoFeedComponent, | 112 | VideoFeedComponent, |
111 | DeleteButtonComponent, | 113 | DeleteButtonComponent, |
112 | EditButtonComponent, | 114 | EditButtonComponent, |
115 | ActionDropdownComponent, | ||
113 | MarkdownTextareaComponent, | 116 | MarkdownTextareaComponent, |
114 | InfiniteScrollerDirective, | 117 | InfiniteScrollerDirective, |
115 | HelpComponent, | 118 | HelpComponent, |
diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts index 581ea7859..2748001d0 100644 --- a/client/src/app/shared/users/user.model.ts +++ b/client/src/app/shared/users/user.model.ts | |||
@@ -7,7 +7,6 @@ import { | |||
7 | VideoChannel | 7 | VideoChannel |
8 | } from '../../../../../shared' | 8 | } from '../../../../../shared' |
9 | import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type' | 9 | import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type' |
10 | import { Actor } from '@app/shared/actor/actor.model' | ||
11 | import { Account } from '@app/shared/account/account.model' | 10 | import { Account } from '@app/shared/account/account.model' |
12 | import { Avatar } from '../../../../../shared/models/avatars/avatar.model' | 11 | import { Avatar } from '../../../../../shared/models/avatars/avatar.model' |
13 | 12 | ||
@@ -22,6 +21,9 @@ export type UserConstructorHash = { | |||
22 | createdAt?: Date, | 21 | createdAt?: Date, |
23 | account?: AccountServerModel, | 22 | account?: AccountServerModel, |
24 | videoChannels?: VideoChannel[] | 23 | videoChannels?: VideoChannel[] |
24 | |||
25 | blocked?: boolean | ||
26 | blockedReason?: string | ||
25 | } | 27 | } |
26 | export class User implements UserServerModel { | 28 | export class User implements UserServerModel { |
27 | id: number | 29 | id: number |
@@ -35,35 +37,26 @@ export class User implements UserServerModel { | |||
35 | videoChannels: VideoChannel[] | 37 | videoChannels: VideoChannel[] |
36 | createdAt: Date | 38 | createdAt: Date |
37 | 39 | ||
40 | blocked: boolean | ||
41 | blockedReason?: string | ||
42 | |||
38 | constructor (hash: UserConstructorHash) { | 43 | constructor (hash: UserConstructorHash) { |
39 | this.id = hash.id | 44 | this.id = hash.id |
40 | this.username = hash.username | 45 | this.username = hash.username |
41 | this.email = hash.email | 46 | this.email = hash.email |
42 | this.role = hash.role | 47 | this.role = hash.role |
43 | 48 | ||
49 | this.videoChannels = hash.videoChannels | ||
50 | this.videoQuota = hash.videoQuota | ||
51 | this.nsfwPolicy = hash.nsfwPolicy | ||
52 | this.autoPlayVideo = hash.autoPlayVideo | ||
53 | this.createdAt = hash.createdAt | ||
54 | this.blocked = hash.blocked | ||
55 | this.blockedReason = hash.blockedReason | ||
56 | |||
44 | if (hash.account !== undefined) { | 57 | if (hash.account !== undefined) { |
45 | this.account = new Account(hash.account) | 58 | this.account = new Account(hash.account) |
46 | } | 59 | } |
47 | |||
48 | if (hash.videoChannels !== undefined) { | ||
49 | this.videoChannels = hash.videoChannels | ||
50 | } | ||
51 | |||
52 | if (hash.videoQuota !== undefined) { | ||
53 | this.videoQuota = hash.videoQuota | ||
54 | } | ||
55 | |||
56 | if (hash.nsfwPolicy !== undefined) { | ||
57 | this.nsfwPolicy = hash.nsfwPolicy | ||
58 | } | ||
59 | |||
60 | if (hash.autoPlayVideo !== undefined) { | ||
61 | this.autoPlayVideo = hash.autoPlayVideo | ||
62 | } | ||
63 | |||
64 | if (hash.createdAt !== undefined) { | ||
65 | this.createdAt = hash.createdAt | ||
66 | } | ||
67 | } | 60 | } |
68 | 61 | ||
69 | get accountAvatarUrl () { | 62 | get accountAvatarUrl () { |