Added group permissions. Added some global styles. Made groups rely on services' data.
This commit is contained in:
@ -1,24 +1,28 @@
|
||||
<article>
|
||||
<section class="title">{{item().group.name}}
|
||||
<section class="title">{{group().name}}
|
||||
@if (special) {
|
||||
<small class="tag">auto-generated</small>
|
||||
}
|
||||
</section>
|
||||
<section class="">
|
||||
{{item().group.priority}}
|
||||
{{group().priority}}
|
||||
<small class="muted block">priority</small>
|
||||
</section>
|
||||
<section>
|
||||
@if (special) {
|
||||
<p class="muted">Unknown</p>
|
||||
} @else {
|
||||
{{item().chatters.length}}
|
||||
<small class="muted block">user{{item().chatters.length == 1 ? '' : 's'}}</small>
|
||||
{{chatters().length}}
|
||||
<small class="muted block">user{{chatters().length == 1 ? '' : 's'}}</small>
|
||||
}
|
||||
</section>
|
||||
<section>
|
||||
{{item().policies.length}}
|
||||
<small class="muted block">polic{{item().chatters.length == 1 ? 'y' : 'ies'}}</small>
|
||||
{{permissions().length}}
|
||||
<small class="muted block">permission{{permissions().length == 1 ? '' : 's'}}</small>
|
||||
</section>
|
||||
<section>
|
||||
{{policies().length}}
|
||||
<small class="muted block">polic{{policies().length == 1 ? 'y' : 'ies'}}</small>
|
||||
</section>
|
||||
<section>
|
||||
<button mat-button
|
||||
|
@ -7,6 +7,7 @@ import { Policy } from '../../shared/models/policy';
|
||||
import { Router } from '@angular/router';
|
||||
import { GroupChatter } from '../../shared/models/group-chatter';
|
||||
import { SpecialGroups } from '../../shared/utils/groups';
|
||||
import { Permission } from '../../shared/models/permission';
|
||||
|
||||
@Component({
|
||||
selector: 'group-item',
|
||||
@ -21,12 +22,15 @@ import { SpecialGroups } from '../../shared/utils/groups';
|
||||
})
|
||||
export class GroupItemComponent implements OnInit {
|
||||
readonly router = inject(Router);
|
||||
item = input.required<{ group: Group, chatters: GroupChatter[], policies: Policy[] }>();
|
||||
group = input.required<Group>();
|
||||
chatters = input.required<GroupChatter[]>();
|
||||
permissions = input.required<Permission[]>();
|
||||
policies = input.required<Policy[]>();
|
||||
link: string = '';
|
||||
special: boolean = true;
|
||||
|
||||
ngOnInit() {
|
||||
this.special = SpecialGroups.includes(this.item().group.name);
|
||||
this.link = 'groups/' + this.item().group.id;
|
||||
this.special = SpecialGroups.includes(this.group().name);
|
||||
this.link = 'groups/' + this.group().id;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
<ul>
|
||||
@for (group of groups; track $index) {
|
||||
@for (group of groups; track group.id) {
|
||||
<li>
|
||||
<group-item [item]="group" />
|
||||
<group-item [group]="group"
|
||||
[chatters]="getChattersByGroup(group.id)"
|
||||
[permissions]="getPermissionsByGroup(group.id)"
|
||||
[policies]="getPoliciesByGroup(group.id)" />
|
||||
</li>
|
||||
}
|
||||
</ul>
|
@ -1,8 +1,9 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, input, Input } from '@angular/core';
|
||||
import { Group } from '../../shared/models/group';
|
||||
import { GroupItemComponent } from "../group-item/group-item.component";
|
||||
import { Policy } from '../../shared/models/policy';
|
||||
import { GroupChatter } from '../../shared/models/group-chatter';
|
||||
import { Permission } from '../../shared/models/permission';
|
||||
|
||||
@Component({
|
||||
selector: 'group-list',
|
||||
@ -12,25 +13,35 @@ import { GroupChatter } from '../../shared/models/group-chatter';
|
||||
styleUrl: './group-list.component.scss'
|
||||
})
|
||||
export class GroupListComponent {
|
||||
private _groups: { group: Group, chatters: GroupChatter[], policies: Policy[] }[] = [];
|
||||
private _filter: (item: { group: Group, chatters: GroupChatter[], policies: Policy[] }) => boolean = _ => true;
|
||||
_groups = input.required<Group[]>({ alias: 'groups' });
|
||||
chatters = input.required<GroupChatter[]>();
|
||||
permissions = input.required<Permission[]>();
|
||||
policies = input.required<Policy[]>();
|
||||
private _filter: (item: Group) => boolean = _ => true;
|
||||
|
||||
|
||||
get filter(): (item: { group: Group, chatters: GroupChatter[], policies: Policy[] }) => boolean {
|
||||
get filter(): (group: Group) => boolean {
|
||||
return this._filter;
|
||||
}
|
||||
|
||||
@Input({ alias: 'filter', required: false })
|
||||
set filter(value: (item: { group: Group, chatters: GroupChatter[], policies: Policy[] }) => boolean) {
|
||||
set filter(value: (item: Group) => boolean) {
|
||||
this._filter = value;
|
||||
}
|
||||
|
||||
get groups() {
|
||||
return this._groups.filter(this._filter);
|
||||
return this._groups().filter(g => this._filter(g));
|
||||
}
|
||||
|
||||
@Input({ alias: 'groups', required: true })
|
||||
set groups(value: { group: Group, chatters: GroupChatter[], policies: Policy[] }[]) {
|
||||
this._groups = value;
|
||||
getChattersByGroup(groupId: string) {
|
||||
return this.chatters().filter(c => c.group_id == groupId);
|
||||
}
|
||||
|
||||
getPermissionsByGroup(groupId: string) {
|
||||
return this.permissions().filter(c => c.group_id == groupId);
|
||||
}
|
||||
|
||||
getPoliciesByGroup(groupId: string) {
|
||||
return this.policies().filter(c => c.group_id == groupId);
|
||||
}
|
||||
}
|
@ -14,6 +14,18 @@
|
||||
</mat-expansion-panel>
|
||||
}
|
||||
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>Permissions</mat-panel-title>
|
||||
<mat-panel-description class="muted">
|
||||
{{permissions.length}} permission{{permissions.length == 1 ? '' : 's'}}
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
<permission-list [permissions]="permissions"
|
||||
[groups]="groups"
|
||||
[group]="group" />
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>Policies</mat-panel-title>
|
||||
@ -43,7 +55,7 @@
|
||||
</article>
|
||||
<article class="right">
|
||||
<button mat-raised-button
|
||||
class="delete"
|
||||
class="danger"
|
||||
(click)="delete()">
|
||||
<mat-icon>delete</mat-icon>Delete this group.
|
||||
</button>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import { Component, inject, OnDestroy } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Group } from '../../shared/models/group';
|
||||
import { Policy } from '../../shared/models/policy';
|
||||
@ -15,6 +15,12 @@ import { HermesClientService } from '../../hermes-client.service';
|
||||
import { GroupChatter } from '../../shared/models/group-chatter';
|
||||
import { TwitchUsersModule } from "../../twitch-users/twitch-users.module";
|
||||
import { SpecialGroups } from '../../shared/utils/groups';
|
||||
import { PermissionListComponent } from "../../permissions/permission-list/permission-list.component";
|
||||
import { Permission } from '../../shared/models/permission';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { PermissionService } from '../../shared/services/permission.service';
|
||||
import GroupService from '../../shared/services/group.service';
|
||||
import PolicyService from '../../shared/services/policy.service';
|
||||
|
||||
@Component({
|
||||
imports: [
|
||||
@ -29,30 +35,42 @@ import { SpecialGroups } from '../../shared/utils/groups';
|
||||
PolicyTableComponent,
|
||||
PolicyTableComponent,
|
||||
TwitchUsersModule,
|
||||
PermissionListComponent
|
||||
],
|
||||
templateUrl: './group-page.component.html',
|
||||
styleUrl: './group-page.component.scss'
|
||||
})
|
||||
export class GroupPageComponent {
|
||||
export class GroupPageComponent implements OnDestroy {
|
||||
private readonly _router = inject(Router);
|
||||
private readonly _route = inject(ActivatedRoute);
|
||||
private readonly _groupService = inject(GroupService);
|
||||
private readonly _permissionService = inject(PermissionService);
|
||||
private readonly _policyService = inject(PolicyService);
|
||||
private readonly _client = inject(HermesClientService);
|
||||
private _group: Group | undefined;
|
||||
private _chatters: GroupChatter[];
|
||||
private _policies: Policy[];
|
||||
private _permissions: Permission[];
|
||||
|
||||
isSpecialGroup: boolean;
|
||||
_groups: Group[];
|
||||
|
||||
private readonly subscriptions: (Subscription | undefined)[] = [];
|
||||
|
||||
isSpecialGroup = false;
|
||||
groups: Group[] = [];
|
||||
|
||||
constructor() {
|
||||
this.isSpecialGroup = false
|
||||
this._groups = [];
|
||||
this._chatters = [];
|
||||
this._permissions = [];
|
||||
this._policies = [];
|
||||
|
||||
this._route.params.subscribe((p: any) => {
|
||||
const group_id = p.id;
|
||||
this._route.params.subscribe((params: any) => {
|
||||
// Fetch the group id from the query params.
|
||||
const group_id = params['id'];
|
||||
|
||||
this._route.data.subscribe(async (data: any) => {
|
||||
this.groups = [...data['groups']];
|
||||
this._groups = data['groups'];
|
||||
const group = this.groups.find((g: Group) => g.id == group_id);
|
||||
|
||||
if (!group) {
|
||||
@ -62,29 +80,88 @@ export class GroupPageComponent {
|
||||
|
||||
this._group = group;
|
||||
this.isSpecialGroup = SpecialGroups.includes(this.group!.name);
|
||||
this._chatters = [...data['chatters'].filter((c: GroupChatter) => c.group_id == group_id)];
|
||||
this._policies = [...data['policies'].filter((p: Policy) => p.group_id == group_id)];
|
||||
this._chatters = data['chatters'];
|
||||
this._permissions = data['permissions'];
|
||||
this._policies = data['policies'];
|
||||
});
|
||||
});
|
||||
|
||||
this.subscriptions.push(this._permissionService.delete$?.subscribe(d => {
|
||||
if (d.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._permissionService.fetch().subscribe(permissions => this._permissions = permissions);
|
||||
}));
|
||||
|
||||
this.subscriptions.push(this._groupService.deleteGroup$?.subscribe(d => {
|
||||
if (d.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._groupService.fetch().subscribe(data => this._groups = data.groups);
|
||||
}));
|
||||
|
||||
this.subscriptions.push(this._groupService.deleteChatter$?.subscribe(d => {
|
||||
if (d.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._groupService.fetch().subscribe(data => this._chatters = data.chatters);
|
||||
}));
|
||||
|
||||
this.subscriptions.push(this._policyService.delete$?.subscribe(d => {
|
||||
if (d.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._policyService.fetch().subscribe(policies => this._policies = policies);
|
||||
}));
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.subscriptions) {
|
||||
for (let subscription of this.subscriptions) {
|
||||
if (subscription)
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get group() {
|
||||
return this._group;
|
||||
}
|
||||
|
||||
get groups() {
|
||||
return this._groups;
|
||||
}
|
||||
|
||||
get chatters() {
|
||||
return this._chatters;
|
||||
if (!this._group) {
|
||||
return [];
|
||||
}
|
||||
return this._chatters.filter((c: GroupChatter) => c.group_id == this._group!.id);
|
||||
}
|
||||
|
||||
get permissions() {
|
||||
if (!this._group) {
|
||||
return [];
|
||||
}
|
||||
return this._permissions.filter((p: Permission) => p.group_id == this._group!.id);
|
||||
}
|
||||
|
||||
get policies() {
|
||||
return this._policies;
|
||||
if (!this._group) {
|
||||
return [];
|
||||
}
|
||||
return this._policies.filter((p: Policy) => p.group_id == this._group!.id);
|
||||
}
|
||||
|
||||
delete() {
|
||||
if (!this.group)
|
||||
return;
|
||||
|
||||
this._client.first(d => d.d.request.type == 'delete_group' && d.d.request.data.group == this.group!.id)
|
||||
this._client.first(d => d.d.request.type == 'delete_group' && d.d.request.data.id == this.group!.id)
|
||||
.subscribe(async () => await this._router.navigate(['groups']));
|
||||
this._client.deleteGroup(this.group.id);
|
||||
}
|
||||
|
@ -14,4 +14,7 @@
|
||||
}
|
||||
</mat-menu>
|
||||
<group-list class="groups"
|
||||
[groups]="items" />
|
||||
[groups]="groups"
|
||||
[chatters]="chatters"
|
||||
[permissions]="permissions"
|
||||
[policies]="policies" />
|
@ -1,4 +1,4 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Component, inject, OnDestroy } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { ActivatedRoute, RouterModule } from '@angular/router';
|
||||
@ -13,6 +13,10 @@ import { MatMenuModule } from '@angular/material/menu';
|
||||
import { HermesClientService } from '../../hermes-client.service';
|
||||
import { GroupChatter } from '../../shared/models/group-chatter';
|
||||
import { SpecialGroups } from '../../shared/utils/groups';
|
||||
import { Permission } from '../../shared/models/permission';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { PermissionService } from '../../shared/services/permission.service';
|
||||
import PolicyService from '../../shared/services/policy.service';
|
||||
|
||||
@Component({
|
||||
selector: 'groups',
|
||||
@ -27,100 +31,108 @@ import { SpecialGroups } from '../../shared/utils/groups';
|
||||
templateUrl: './groups.component.html',
|
||||
styleUrl: './groups.component.scss'
|
||||
})
|
||||
export class GroupsComponent {
|
||||
private readonly _groupService = inject(GroupService);
|
||||
export class GroupsComponent implements OnDestroy {
|
||||
private readonly _client = inject(HermesClientService);
|
||||
private readonly _route = inject(ActivatedRoute);
|
||||
private readonly _dialog = inject(MatDialog);
|
||||
|
||||
private readonly _groupService = inject(GroupService);
|
||||
private readonly _permissionService = inject(PermissionService);
|
||||
private readonly _policyService = inject(PolicyService);
|
||||
private readonly subscriptions: (Subscription | undefined)[] = [];
|
||||
|
||||
readonly specialGroups = SpecialGroups;
|
||||
|
||||
items: { group: Group, chatters: GroupChatter[], policies: Policy[] }[] = [];
|
||||
private _groups: Group[] = [];
|
||||
private _chatters: GroupChatter[] = [];
|
||||
private _permissions: Permission[] = [];
|
||||
private _policies: Policy[] = [];
|
||||
|
||||
opened = false;
|
||||
|
||||
constructor() {
|
||||
this._route.data.subscribe(payload => {
|
||||
const groups = payload['groups'];
|
||||
const chatters = payload['chatters'];
|
||||
const policies = payload['policies'];
|
||||
const elements: { group: Group, chatters: GroupChatter[], policies: Policy[] }[] = [];
|
||||
this._groups = payload['groups'];
|
||||
this._chatters = payload['chatters'];
|
||||
this._permissions = payload['permissions'];
|
||||
this._policies = payload['policies'];
|
||||
});
|
||||
|
||||
for (let group of groups) {
|
||||
elements.push({
|
||||
group: group,
|
||||
chatters: chatters.filter((c: GroupChatter) => c.group_id == group.id),
|
||||
policies: policies.filter((p: Policy) => p.group_id == group.id),
|
||||
});
|
||||
this.subscriptions.push(this._permissionService.delete$?.subscribe(d => {
|
||||
if (d.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.items = elements;
|
||||
});
|
||||
this._permissionService.fetch().subscribe(permissions => this._permissions = permissions);
|
||||
}));
|
||||
|
||||
this._groupService.createGroup$?.subscribe(d => {
|
||||
if (d.error || !d.data || d.request.nounce != null && d.request.nounce.startsWith(this._client.session_id))
|
||||
this.subscriptions.push(this._groupService.deleteGroup$?.subscribe(d => {
|
||||
if (d.error) {
|
||||
return;
|
||||
|
||||
let index = -1;
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
const comp = this.compare(d.data, this.items[i].group);
|
||||
if (comp < 0) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.items.splice(index >= 0 ? index : this.items.length, 0, { group: d.data, chatters: [], policies: [] });
|
||||
});
|
||||
|
||||
this._groupService.updateGroup$?.subscribe(d => {
|
||||
if (d.error || !d.data || d.request.nounce != null && d.request.nounce.startsWith(this._client.session_id))
|
||||
this._groupService.fetch().subscribe(data => this._groups = data.groups);
|
||||
}));
|
||||
|
||||
this.subscriptions.push(this._groupService.deleteChatter$?.subscribe(d => {
|
||||
if (d.error) {
|
||||
return;
|
||||
|
||||
const group = this.items.find(r => r.group.id = d.data.id)?.group;
|
||||
if (group) {
|
||||
group.id = d.data.id;
|
||||
group.name = d.data.name;
|
||||
group.priority = d.data.priority;
|
||||
}
|
||||
});
|
||||
|
||||
this._groupService.deleteGroup$?.subscribe(d => {
|
||||
if (d.error || d.request.nounce != null && d.request.nounce.startsWith(this._client.session_id))
|
||||
this._groupService.fetch().subscribe(data => this._chatters = data.chatters);
|
||||
}));
|
||||
|
||||
this.subscriptions.push(this._policyService.delete$?.subscribe(d => {
|
||||
if (d.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.items = this.items.filter(r => r.group.id != d.request.data.id);
|
||||
});
|
||||
this._policyService.fetch().subscribe(policies => this._policies = policies);
|
||||
}));
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.subscriptions) {
|
||||
for (let subscription of this.subscriptions) {
|
||||
if (subscription)
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get groups() {
|
||||
return this._groups;
|
||||
}
|
||||
|
||||
get chatters() {
|
||||
return this._chatters;
|
||||
}
|
||||
|
||||
get permissions() {
|
||||
return this._permissions;
|
||||
}
|
||||
|
||||
get policies() {
|
||||
return this._policies;
|
||||
}
|
||||
|
||||
openDialog(groupName: string): void {
|
||||
const group = { id: '', user_id: '', name: groupName, priority: 0 };
|
||||
if (this.opened) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.opened = true;
|
||||
const dialogRef = this._dialog.open(GroupItemEditComponent, {
|
||||
data: { group, isSpecial: groupName.length > 0 },
|
||||
data: { group: { id: '', user_id: '', name: groupName, priority: 0 }, isSpecial: groupName.length > 0 },
|
||||
});
|
||||
|
||||
const isNewGroup = group.id.length <= 0;
|
||||
dialogRef.afterClosed().subscribe((result: Group | undefined) => {
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
|
||||
if (isNewGroup) {
|
||||
this.items.push({ group: result, chatters: [], policies: [] });
|
||||
} else {
|
||||
const same = this.items.find(i => i.group.id == group.id);
|
||||
if (same == null)
|
||||
return;
|
||||
|
||||
same.group.name = result.name;
|
||||
same.group.priority = result.priority;
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((result: Group | undefined) => this.opened = false);
|
||||
}
|
||||
|
||||
compare(a: Group, b: Group) {
|
||||
return a.name.localeCompare(b.name);
|
||||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||||
}
|
||||
|
||||
exists(groupName: string) {
|
||||
return this.items.some(g => g.group.name == groupName);
|
||||
return this._groups.some(g => g.name == groupName);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user