Added group permissions. Added some global styles. Made groups rely on services' data.
This commit is contained in:
parent
d19c5445d6
commit
9de4424736
@ -1,5 +1,5 @@
|
|||||||
<main>
|
<main>
|
||||||
@for (action of actions; track $index) {
|
@for (action of actions; track action.name) {
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="container"
|
class="container"
|
||||||
(click)="modify(action)">
|
(click)="modify(action)">
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<mat-select-trigger>
|
<mat-select-trigger>
|
||||||
<mat-icon matPrefix>filter_list</mat-icon> {{filter.name}}
|
<mat-icon matPrefix>filter_list</mat-icon> {{filter.name}}
|
||||||
</mat-select-trigger>
|
</mat-select-trigger>
|
||||||
@for (item of filters; track $index) {
|
@for (item of filters; track item.name) {
|
||||||
<mat-option value="{{$index}}">{{item.name}}</mat-option>
|
<mat-option value="{{$index}}">{{item.name}}</mat-option>
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
@ -19,6 +19,7 @@ import PolicyResolver from './shared/resolvers/policy-resolver';
|
|||||||
import { GroupsComponent } from './groups/groups/groups.component';
|
import { GroupsComponent } from './groups/groups/groups.component';
|
||||||
import { GroupPageComponent } from './groups/group-page/group-page.component';
|
import { GroupPageComponent } from './groups/group-page/group-page.component';
|
||||||
import GroupChatterResolver from './shared/resolvers/group-chatter-resolver';
|
import GroupChatterResolver from './shared/resolvers/group-chatter-resolver';
|
||||||
|
import PermissionResolver from './shared/resolvers/permission-resolver';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{
|
{
|
||||||
@ -27,7 +28,6 @@ export const routes: Routes = [
|
|||||||
canActivate: [AuthUserGuard],
|
canActivate: [AuthUserGuard],
|
||||||
resolve: {
|
resolve: {
|
||||||
groups: GroupResolver,
|
groups: GroupResolver,
|
||||||
chatters: GroupChatterResolver,
|
|
||||||
policies: PolicyResolver,
|
policies: PolicyResolver,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -39,6 +39,7 @@ export const routes: Routes = [
|
|||||||
groups: GroupResolver,
|
groups: GroupResolver,
|
||||||
chatters: GroupChatterResolver,
|
chatters: GroupChatterResolver,
|
||||||
policies: PolicyResolver,
|
policies: PolicyResolver,
|
||||||
|
permissions: PermissionResolver,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -49,6 +50,7 @@ export const routes: Routes = [
|
|||||||
groups: GroupResolver,
|
groups: GroupResolver,
|
||||||
chatters: GroupChatterResolver,
|
chatters: GroupChatterResolver,
|
||||||
policies: PolicyResolver,
|
policies: PolicyResolver,
|
||||||
|
permissions: PermissionResolver,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,24 +1,28 @@
|
|||||||
<article>
|
<article>
|
||||||
<section class="title">{{item().group.name}}
|
<section class="title">{{group().name}}
|
||||||
@if (special) {
|
@if (special) {
|
||||||
<small class="tag">auto-generated</small>
|
<small class="tag">auto-generated</small>
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
<section class="">
|
<section class="">
|
||||||
{{item().group.priority}}
|
{{group().priority}}
|
||||||
<small class="muted block">priority</small>
|
<small class="muted block">priority</small>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
@if (special) {
|
@if (special) {
|
||||||
<p class="muted">Unknown</p>
|
<p class="muted">Unknown</p>
|
||||||
} @else {
|
} @else {
|
||||||
{{item().chatters.length}}
|
{{chatters().length}}
|
||||||
<small class="muted block">user{{item().chatters.length == 1 ? '' : 's'}}</small>
|
<small class="muted block">user{{chatters().length == 1 ? '' : 's'}}</small>
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
{{item().policies.length}}
|
{{permissions().length}}
|
||||||
<small class="muted block">polic{{item().chatters.length == 1 ? 'y' : 'ies'}}</small>
|
<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>
|
||||||
<section>
|
<section>
|
||||||
<button mat-button
|
<button mat-button
|
||||||
|
@ -7,6 +7,7 @@ import { Policy } from '../../shared/models/policy';
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { GroupChatter } from '../../shared/models/group-chatter';
|
import { GroupChatter } from '../../shared/models/group-chatter';
|
||||||
import { SpecialGroups } from '../../shared/utils/groups';
|
import { SpecialGroups } from '../../shared/utils/groups';
|
||||||
|
import { Permission } from '../../shared/models/permission';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'group-item',
|
selector: 'group-item',
|
||||||
@ -21,12 +22,15 @@ import { SpecialGroups } from '../../shared/utils/groups';
|
|||||||
})
|
})
|
||||||
export class GroupItemComponent implements OnInit {
|
export class GroupItemComponent implements OnInit {
|
||||||
readonly router = inject(Router);
|
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 = '';
|
link: string = '';
|
||||||
special: boolean = true;
|
special: boolean = true;
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.special = SpecialGroups.includes(this.item().group.name);
|
this.special = SpecialGroups.includes(this.group().name);
|
||||||
this.link = 'groups/' + this.item().group.id;
|
this.link = 'groups/' + this.group().id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<ul>
|
<ul>
|
||||||
@for (group of groups; track $index) {
|
@for (group of groups; track group.id) {
|
||||||
<li>
|
<li>
|
||||||
<group-item [item]="group" />
|
<group-item [group]="group"
|
||||||
|
[chatters]="getChattersByGroup(group.id)"
|
||||||
|
[permissions]="getPermissionsByGroup(group.id)"
|
||||||
|
[policies]="getPoliciesByGroup(group.id)" />
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</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 { Group } from '../../shared/models/group';
|
||||||
import { GroupItemComponent } from "../group-item/group-item.component";
|
import { GroupItemComponent } from "../group-item/group-item.component";
|
||||||
import { Policy } from '../../shared/models/policy';
|
import { Policy } from '../../shared/models/policy';
|
||||||
import { GroupChatter } from '../../shared/models/group-chatter';
|
import { GroupChatter } from '../../shared/models/group-chatter';
|
||||||
|
import { Permission } from '../../shared/models/permission';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'group-list',
|
selector: 'group-list',
|
||||||
@ -12,25 +13,35 @@ import { GroupChatter } from '../../shared/models/group-chatter';
|
|||||||
styleUrl: './group-list.component.scss'
|
styleUrl: './group-list.component.scss'
|
||||||
})
|
})
|
||||||
export class GroupListComponent {
|
export class GroupListComponent {
|
||||||
private _groups: { group: Group, chatters: GroupChatter[], policies: Policy[] }[] = [];
|
_groups = input.required<Group[]>({ alias: 'groups' });
|
||||||
private _filter: (item: { group: Group, chatters: GroupChatter[], policies: Policy[] }) => boolean = _ => true;
|
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;
|
return this._filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input({ alias: 'filter', required: false })
|
@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;
|
this._filter = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get groups() {
|
get groups() {
|
||||||
return this._groups.filter(this._filter);
|
return this._groups().filter(g => this._filter(g));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input({ alias: 'groups', required: true })
|
getChattersByGroup(groupId: string) {
|
||||||
set groups(value: { group: Group, chatters: GroupChatter[], policies: Policy[] }[]) {
|
return this.chatters().filter(c => c.group_id == groupId);
|
||||||
this._groups = value;
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
<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>
|
||||||
<mat-expansion-panel-header>
|
<mat-expansion-panel-header>
|
||||||
<mat-panel-title>Policies</mat-panel-title>
|
<mat-panel-title>Policies</mat-panel-title>
|
||||||
@ -43,7 +55,7 @@
|
|||||||
</article>
|
</article>
|
||||||
<article class="right">
|
<article class="right">
|
||||||
<button mat-raised-button
|
<button mat-raised-button
|
||||||
class="delete"
|
class="danger"
|
||||||
(click)="delete()">
|
(click)="delete()">
|
||||||
<mat-icon>delete</mat-icon>Delete this group.
|
<mat-icon>delete</mat-icon>Delete this group.
|
||||||
</button>
|
</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 { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Group } from '../../shared/models/group';
|
import { Group } from '../../shared/models/group';
|
||||||
import { Policy } from '../../shared/models/policy';
|
import { Policy } from '../../shared/models/policy';
|
||||||
@ -15,6 +15,12 @@ import { HermesClientService } from '../../hermes-client.service';
|
|||||||
import { GroupChatter } from '../../shared/models/group-chatter';
|
import { GroupChatter } from '../../shared/models/group-chatter';
|
||||||
import { TwitchUsersModule } from "../../twitch-users/twitch-users.module";
|
import { TwitchUsersModule } from "../../twitch-users/twitch-users.module";
|
||||||
import { SpecialGroups } from '../../shared/utils/groups';
|
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({
|
@Component({
|
||||||
imports: [
|
imports: [
|
||||||
@ -29,30 +35,42 @@ import { SpecialGroups } from '../../shared/utils/groups';
|
|||||||
PolicyTableComponent,
|
PolicyTableComponent,
|
||||||
PolicyTableComponent,
|
PolicyTableComponent,
|
||||||
TwitchUsersModule,
|
TwitchUsersModule,
|
||||||
|
PermissionListComponent
|
||||||
],
|
],
|
||||||
templateUrl: './group-page.component.html',
|
templateUrl: './group-page.component.html',
|
||||||
styleUrl: './group-page.component.scss'
|
styleUrl: './group-page.component.scss'
|
||||||
})
|
})
|
||||||
export class GroupPageComponent {
|
export class GroupPageComponent implements OnDestroy {
|
||||||
private readonly _router = inject(Router);
|
private readonly _router = inject(Router);
|
||||||
private readonly _route = inject(ActivatedRoute);
|
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 readonly _client = inject(HermesClientService);
|
||||||
private _group: Group | undefined;
|
private _group: Group | undefined;
|
||||||
private _chatters: GroupChatter[];
|
private _chatters: GroupChatter[];
|
||||||
private _policies: Policy[];
|
private _policies: Policy[];
|
||||||
|
private _permissions: Permission[];
|
||||||
|
|
||||||
|
isSpecialGroup: boolean;
|
||||||
|
_groups: Group[];
|
||||||
|
|
||||||
|
private readonly subscriptions: (Subscription | undefined)[] = [];
|
||||||
|
|
||||||
isSpecialGroup = false;
|
|
||||||
groups: Group[] = [];
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.isSpecialGroup = false
|
||||||
|
this._groups = [];
|
||||||
this._chatters = [];
|
this._chatters = [];
|
||||||
|
this._permissions = [];
|
||||||
this._policies = [];
|
this._policies = [];
|
||||||
|
|
||||||
this._route.params.subscribe((p: any) => {
|
this._route.params.subscribe((params: any) => {
|
||||||
const group_id = p.id;
|
// Fetch the group id from the query params.
|
||||||
|
const group_id = params['id'];
|
||||||
|
|
||||||
this._route.data.subscribe(async (data: any) => {
|
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);
|
const group = this.groups.find((g: Group) => g.id == group_id);
|
||||||
|
|
||||||
if (!group) {
|
if (!group) {
|
||||||
@ -62,29 +80,88 @@ export class GroupPageComponent {
|
|||||||
|
|
||||||
this._group = group;
|
this._group = group;
|
||||||
this.isSpecialGroup = SpecialGroups.includes(this.group!.name);
|
this.isSpecialGroup = SpecialGroups.includes(this.group!.name);
|
||||||
this._chatters = [...data['chatters'].filter((c: GroupChatter) => c.group_id == group_id)];
|
this._chatters = data['chatters'];
|
||||||
this._policies = [...data['policies'].filter((p: Policy) => p.group_id == group_id)];
|
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() {
|
get group() {
|
||||||
return this._group;
|
return this._group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get groups() {
|
||||||
|
return this._groups;
|
||||||
|
}
|
||||||
|
|
||||||
get chatters() {
|
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() {
|
get policies() {
|
||||||
return this._policies;
|
if (!this._group) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return this._policies.filter((p: Policy) => p.group_id == this._group!.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
if (!this.group)
|
if (!this.group)
|
||||||
return;
|
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']));
|
.subscribe(async () => await this._router.navigate(['groups']));
|
||||||
this._client.deleteGroup(this.group.id);
|
this._client.deleteGroup(this.group.id);
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,7 @@
|
|||||||
}
|
}
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
<group-list class="groups"
|
<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 { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { ActivatedRoute, RouterModule } from '@angular/router';
|
import { ActivatedRoute, RouterModule } from '@angular/router';
|
||||||
@ -13,6 +13,10 @@ import { MatMenuModule } from '@angular/material/menu';
|
|||||||
import { HermesClientService } from '../../hermes-client.service';
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
import { GroupChatter } from '../../shared/models/group-chatter';
|
import { GroupChatter } from '../../shared/models/group-chatter';
|
||||||
import { SpecialGroups } from '../../shared/utils/groups';
|
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({
|
@Component({
|
||||||
selector: 'groups',
|
selector: 'groups',
|
||||||
@ -27,100 +31,108 @@ import { SpecialGroups } from '../../shared/utils/groups';
|
|||||||
templateUrl: './groups.component.html',
|
templateUrl: './groups.component.html',
|
||||||
styleUrl: './groups.component.scss'
|
styleUrl: './groups.component.scss'
|
||||||
})
|
})
|
||||||
export class GroupsComponent {
|
export class GroupsComponent implements OnDestroy {
|
||||||
private readonly _groupService = inject(GroupService);
|
|
||||||
private readonly _client = inject(HermesClientService);
|
private readonly _client = inject(HermesClientService);
|
||||||
private readonly _route = inject(ActivatedRoute);
|
private readonly _route = inject(ActivatedRoute);
|
||||||
private readonly _dialog = inject(MatDialog);
|
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;
|
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() {
|
constructor() {
|
||||||
this._route.data.subscribe(payload => {
|
this._route.data.subscribe(payload => {
|
||||||
const groups = payload['groups'];
|
this._groups = payload['groups'];
|
||||||
const chatters = payload['chatters'];
|
this._chatters = payload['chatters'];
|
||||||
const policies = payload['policies'];
|
this._permissions = payload['permissions'];
|
||||||
const elements: { group: Group, chatters: GroupChatter[], policies: Policy[] }[] = [];
|
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.items = elements;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this._groupService.createGroup$?.subscribe(d => {
|
this.subscriptions.push(this._permissionService.delete$?.subscribe(d => {
|
||||||
if (d.error || !d.data || d.request.nounce != null && d.request.nounce.startsWith(this._client.session_id))
|
if (d.error) {
|
||||||
return;
|
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 => {
|
this._permissionService.fetch().subscribe(permissions => this._permissions = permissions);
|
||||||
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;
|
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 => {
|
this._groupService.fetch().subscribe(data => this._groups = data.groups);
|
||||||
if (d.error || d.request.nounce != null && d.request.nounce.startsWith(this._client.session_id))
|
}));
|
||||||
|
|
||||||
|
this.subscriptions.push(this._groupService.deleteChatter$?.subscribe(d => {
|
||||||
|
if (d.error) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.items = this.items.filter(r => r.group.id != d.request.data.id);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 groups() {
|
||||||
|
return this._groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
get chatters() {
|
||||||
|
return this._chatters;
|
||||||
|
}
|
||||||
|
|
||||||
|
get permissions() {
|
||||||
|
return this._permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
get policies() {
|
||||||
|
return this._policies;
|
||||||
|
}
|
||||||
|
|
||||||
openDialog(groupName: string): void {
|
openDialog(groupName: string): void {
|
||||||
const group = { id: '', user_id: '', name: groupName, priority: 0 };
|
if (this.opened) {
|
||||||
const dialogRef = this._dialog.open(GroupItemEditComponent, {
|
|
||||||
data: { group, isSpecial: groupName.length > 0 },
|
|
||||||
});
|
|
||||||
|
|
||||||
const isNewGroup = group.id.length <= 0;
|
|
||||||
dialogRef.afterClosed().subscribe((result: Group | undefined) => {
|
|
||||||
if (!result)
|
|
||||||
return;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.opened = true;
|
||||||
|
const dialogRef = this._dialog.open(GroupItemEditComponent, {
|
||||||
|
data: { group: { id: '', user_id: '', name: groupName, priority: 0 }, isSpecial: groupName.length > 0 },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((result: Group | undefined) => this.opened = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
compare(a: Group, b: Group) {
|
compare(a: Group, b: Group) {
|
||||||
return a.name.localeCompare(b.name);
|
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
exists(groupName: string) {
|
exists(groupName: string) {
|
||||||
return this.items.some(g => g.group.name == groupName);
|
return this._groups.some(g => g.name == groupName);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -112,6 +112,17 @@ export class HermesClientService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public createGroupPermission(groupId: string, path: string, allow: boolean | null) {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "create_group_permission",
|
||||||
|
data: { group: groupId, path, allow },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public createPolicy(groupId: string, path: string, usage: number, timespan: number) {
|
public createPolicy(groupId: string, path: string, usage: number, timespan: number) {
|
||||||
if (!this.logged_in)
|
if (!this.logged_in)
|
||||||
return;
|
return;
|
||||||
@ -119,9 +130,7 @@ export class HermesClientService {
|
|||||||
this.send(3, {
|
this.send(3, {
|
||||||
request_id: null,
|
request_id: null,
|
||||||
type: "create_policy",
|
type: "create_policy",
|
||||||
data: {
|
data: { groupId, path, count: usage, span: timespan },
|
||||||
groupId, path, count: usage, span: timespan
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +192,17 @@ export class HermesClientService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public deleteGroupPermission(id: string) {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "delete_group_permission",
|
||||||
|
data: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public deletePolicy(id: string) {
|
public deletePolicy(id: string) {
|
||||||
if (!this.logged_in)
|
if (!this.logged_in)
|
||||||
return;
|
return;
|
||||||
@ -252,13 +272,13 @@ export class HermesClientService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public fetchPermissionsAndGroups() {
|
public fetchPermissions() {
|
||||||
if (!this.logged_in)
|
if (!this.logged_in)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.send(3, {
|
this.send(3, {
|
||||||
request_id: null,
|
request_id: null,
|
||||||
type: "get_permissions",
|
type: "get_group_permissions",
|
||||||
data: null,
|
data: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -331,6 +351,17 @@ export class HermesClientService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public updateGroupPermission(id: string, groupId: string, path: string, allow: boolean | null) {
|
||||||
|
if (!this.logged_in)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.send(3, {
|
||||||
|
request_id: null,
|
||||||
|
type: "update_group_permission",
|
||||||
|
data: { id, group: groupId, path, allow },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public updatePolicy(id: string, groupId: string, path: string, usage: number, timespan: number) {
|
public updatePolicy(id: string, groupId: string, path: string, usage: number, timespan: number) {
|
||||||
if (!this.logged_in)
|
if (!this.logged_in)
|
||||||
return;
|
return;
|
||||||
@ -338,9 +369,7 @@ export class HermesClientService {
|
|||||||
this.send(3, {
|
this.send(3, {
|
||||||
request_id: null,
|
request_id: null,
|
||||||
type: "update_policy",
|
type: "update_policy",
|
||||||
data: {
|
data: { id, groupId, path, count: usage, span: timespan },
|
||||||
id, groupId, path, count: usage, span: timespan
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
<mat-card>
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title-group>
|
||||||
|
<mat-card-title>{{data.isNew ? "Add" : "Edit"}} Group Permission</mat-card-title>
|
||||||
|
@if (data.group) {
|
||||||
|
<mat-card-subtitle>in {{data.group.name}}</mat-card-subtitle>
|
||||||
|
}
|
||||||
|
</mat-card-title-group>
|
||||||
|
</mat-card-header>
|
||||||
|
|
||||||
|
<mat-card-content>
|
||||||
|
<policy-dropdown [control]="pathControl" />
|
||||||
|
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>Permission</mat-label>
|
||||||
|
<mat-select matInput
|
||||||
|
[formControl]="stateControl">
|
||||||
|
@for (item of states; track $index) {
|
||||||
|
<mat-option [value]="item.value">{{item.label}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-card-content>
|
||||||
|
|
||||||
|
<mat-card-actions class="actions">
|
||||||
|
<button mat-raised-button
|
||||||
|
(click)="dialogRef.close()">Cancel</button>
|
||||||
|
|
||||||
|
<button mat-raised-button
|
||||||
|
disabled="{{pathControl.invalid || waitForResponse}}"
|
||||||
|
(click)="submit()">{{data.isNew ? "Add" : "Save"}}</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
|
||||||
|
@if (responseError) {
|
||||||
|
<mat-card-footer>
|
||||||
|
<small class="error below">{{responseError}}</small>
|
||||||
|
</mat-card-footer>
|
||||||
|
}
|
||||||
|
</mat-card>
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PermissionItemEditComponent } from './permission-item-edit.component';
|
||||||
|
|
||||||
|
describe('PermissionItemEditComponent', () => {
|
||||||
|
let component: PermissionItemEditComponent;
|
||||||
|
let fixture: ComponentFixture<PermissionItemEditComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [PermissionItemEditComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(PermissionItemEditComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,99 @@
|
|||||||
|
import { Component, inject, OnInit } from '@angular/core';
|
||||||
|
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
|
import { Group } from '../../shared/models/group';
|
||||||
|
import { Permission } from '../../shared/models/permission';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { PolicyDropdownComponent } from "../../policies/policy-dropdown/policy-dropdown.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'permission-item-edit',
|
||||||
|
imports: [
|
||||||
|
MatButtonModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatSelectModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
PolicyDropdownComponent,
|
||||||
|
],
|
||||||
|
templateUrl: './permission-item-edit.component.html',
|
||||||
|
styleUrl: './permission-item-edit.component.scss'
|
||||||
|
})
|
||||||
|
export class PermissionItemEditComponent implements OnInit {
|
||||||
|
private readonly client = inject(HermesClientService);
|
||||||
|
readonly data = inject<{ permission: Permission, group: Group, groups: Group[], isNew: boolean }>(MAT_DIALOG_DATA);
|
||||||
|
readonly dialogRef = inject(MatDialogRef<PermissionItemEditComponent>);
|
||||||
|
|
||||||
|
readonly pathControl = new FormControl('', [Validators.required]);
|
||||||
|
readonly stateControl = new FormControl<boolean | null>(null, [Validators.required]);
|
||||||
|
private form = new FormGroup({
|
||||||
|
path: this.pathControl,
|
||||||
|
state: this.stateControl,
|
||||||
|
});
|
||||||
|
|
||||||
|
readonly states: { label: string, value: boolean | null }[] = [
|
||||||
|
{
|
||||||
|
label: 'Allow', value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Deny', value: false
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
responseError: string | undefined;
|
||||||
|
waitForResponse = false;
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.pathControl.setValue(this.data.permission.path);
|
||||||
|
this.stateControl.setValue(this.data.permission.allow);
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
if (this.form.invalid || this.waitForResponse) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.waitForResponse = true;
|
||||||
|
this.responseError = undefined;
|
||||||
|
|
||||||
|
if (this.data.isNew) {
|
||||||
|
this.client.first((d: any) => d.op == 4 && d.d.request.type == 'create_group_permission' && d.d.request.data.path == this.pathControl.value)
|
||||||
|
.subscribe({
|
||||||
|
next: (d) => {
|
||||||
|
console.log('sdifhsdiofs data', d);
|
||||||
|
if (d.d.error) {
|
||||||
|
this.responseError = d.d.error;
|
||||||
|
} else {
|
||||||
|
this.dialogRef.close(d.d.data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: () => this.responseError = 'Something went wrong.',
|
||||||
|
complete: () => this.waitForResponse = false,
|
||||||
|
});
|
||||||
|
this.client.createGroupPermission(this.data.group.id, this.pathControl.value!, this.stateControl.value);
|
||||||
|
} else {
|
||||||
|
this.client.first((d: any) => d.op == 4 && d.d.request.type == 'update_group_permission' && d.d.request.data.id == this.data.permission.id)
|
||||||
|
.subscribe({
|
||||||
|
next: (d) => {
|
||||||
|
if (d.d.error) {
|
||||||
|
this.responseError = d.d.error;
|
||||||
|
} else {
|
||||||
|
this.dialogRef.close(d.d.data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: () => this.responseError = 'Something went wrong.',
|
||||||
|
complete: () => this.waitForResponse = false,
|
||||||
|
});
|
||||||
|
this.client.updateGroupPermission(this.data.permission.id, this.data.group.id, this.pathControl.value!, this.stateControl.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<section [class.enabled]="permission.allow == true"
|
||||||
|
[class.disabled]="permission.allow == false"
|
||||||
|
[class.inherited]="permission.allow == null">
|
||||||
|
<p>{{permission.path}}</p>
|
||||||
|
<div class="right">
|
||||||
|
<button mat-button
|
||||||
|
class="neutral"
|
||||||
|
[disabled]="opened || waitForResponse"
|
||||||
|
(click)="edit()">
|
||||||
|
<mat-icon>edit</mat-icon>Edit
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button mat-button
|
||||||
|
class="danger"
|
||||||
|
[disabled]="opened || waitForResponse"
|
||||||
|
(click)="delete()">
|
||||||
|
<mat-icon>delete</mat-icon>Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
@ -0,0 +1,39 @@
|
|||||||
|
section {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enabled {
|
||||||
|
border: 0.5em solid rgb(41, 255, 41);
|
||||||
|
border-top: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
border: 0.5em solid rgb(255, 41, 41);
|
||||||
|
border-top: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inherited {
|
||||||
|
border: 0.5em solid rgb(255, 255, 255);
|
||||||
|
border-top: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
float: right;
|
||||||
|
display: inline;
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right .mat-mdc-button {
|
||||||
|
align-items: center;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PermissionItemComponent } from './permission-item.component';
|
||||||
|
|
||||||
|
describe('PermissionItemComponent', () => {
|
||||||
|
let component: PermissionItemComponent;
|
||||||
|
let fixture: ComponentFixture<PermissionItemComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [PermissionItemComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(PermissionItemComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,79 @@
|
|||||||
|
import { Component, inject, Input } from '@angular/core';
|
||||||
|
import { Permission } from '../../shared/models/permission';
|
||||||
|
import { Group } from '../../shared/models/group';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
|
import EventService from '../../shared/services/EventService';
|
||||||
|
import { PermissionItemEditComponent } from '../permission-item-edit/permission-item-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'permission-item',
|
||||||
|
imports: [
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule,
|
||||||
|
],
|
||||||
|
templateUrl: './permission-item.component.html',
|
||||||
|
styleUrl: './permission-item.component.scss'
|
||||||
|
})
|
||||||
|
export class PermissionItemComponent {
|
||||||
|
@Input({ required: true }) permission: Permission = { id: '', group_id: '', user_id: '', path: '', allow: null };
|
||||||
|
@Input({ required: true }) group: Group | undefined;
|
||||||
|
|
||||||
|
readonly dialog = inject(MatDialog);
|
||||||
|
readonly client = inject(HermesClientService);
|
||||||
|
readonly events = inject(EventService);
|
||||||
|
|
||||||
|
responseError: string | undefined;
|
||||||
|
waitForResponse = false;
|
||||||
|
opened = false;
|
||||||
|
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
if (this.opened || this.waitForResponse) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.waitForResponse = true;
|
||||||
|
this.responseError = undefined;
|
||||||
|
|
||||||
|
const permissionId = this.permission.id;
|
||||||
|
|
||||||
|
this.client.first((d: any) => d.op == 4 && d.d.request.type == 'delete_group_permission' && d.d.request.data.id == permissionId)
|
||||||
|
.subscribe({
|
||||||
|
next: (d) => {
|
||||||
|
if (d.d.error) {
|
||||||
|
this.responseError = d.d.error;
|
||||||
|
} else {
|
||||||
|
this.events.emit('delete_group_permission', permissionId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: () => this.responseError = 'Something went wrong.',
|
||||||
|
complete: () => this.waitForResponse = false,
|
||||||
|
});
|
||||||
|
this.client.deleteGroupPermission(this.permission.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
edit() {
|
||||||
|
if (this.opened || this.waitForResponse) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.opened = true;
|
||||||
|
|
||||||
|
const dialogRef = this.dialog.open(PermissionItemEditComponent, {
|
||||||
|
data: { permission: this.permission, group: this.group, groups: [], isNew: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((permission: Permission) => {
|
||||||
|
this.opened = false;
|
||||||
|
if (!permission)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.permission.group_id = permission.group_id;
|
||||||
|
this.permission.path = permission.path;
|
||||||
|
this.permission.allow = permission.allow;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
<ul>
|
||||||
|
<li class="header">
|
||||||
|
<mat-form-field appearance="outline"
|
||||||
|
subscriptSizing="dynamic">
|
||||||
|
<mat-label>Filter</mat-label>
|
||||||
|
<input matInput
|
||||||
|
placeholder="Filter group permissions"
|
||||||
|
[formControl]="searchControl" />
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<button mat-icon-button
|
||||||
|
(click)="add()">
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
@for (permission of permissions; track permission.id) {
|
||||||
|
<li>
|
||||||
|
<permission-item [permission]="permission"
|
||||||
|
[group]="group || getGroupById(permission.group_id)" />
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
@if (!permissions.length) {
|
||||||
|
@if (searchControl.value) {
|
||||||
|
<p class="notice">No permission matches the filter.</p>
|
||||||
|
} @else {
|
||||||
|
<p class="notice">This group has no permissions. Cannot do anything.</p>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ul>
|
@ -0,0 +1,38 @@
|
|||||||
|
@use '@angular/material' as mat;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@include mat.all-component-densities(-5);
|
||||||
|
|
||||||
|
@include mat.form-field-overrides((
|
||||||
|
outlined-outline-color: rgb(167, 88, 199),
|
||||||
|
outlined-focus-label-text-color: rgb(155, 57, 194),
|
||||||
|
outlined-focus-outline-color: rgb(155, 57, 194),
|
||||||
|
));
|
||||||
|
|
||||||
|
background-color: rgb(202, 68, 255);
|
||||||
|
border-radius: 15px;
|
||||||
|
margin: 0 0;
|
||||||
|
padding: 0;
|
||||||
|
max-width: 500px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
background-color: rgb(240, 165, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li.header {
|
||||||
|
background-color: rgb(215, 115, 255);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul .notice {
|
||||||
|
text-align: center;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PermissionListComponent } from './permission-list.component';
|
||||||
|
|
||||||
|
describe('PermissionListComponent', () => {
|
||||||
|
let component: PermissionListComponent;
|
||||||
|
let fixture: ComponentFixture<PermissionListComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [PermissionListComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(PermissionListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,65 @@
|
|||||||
|
import { Component, inject, Input } from '@angular/core';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { containsLettersInOrder } from '../../shared/utils/string-compare';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
|
import { Group } from '../../shared/models/group';
|
||||||
|
import EventService from '../../shared/services/EventService';
|
||||||
|
import { PermissionItemComponent } from '../permission-item/permission-item.component';
|
||||||
|
import { Permission } from '../../shared/models/permission';
|
||||||
|
import { PermissionItemEditComponent } from '../permission-item-edit/permission-item-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'permission-list',
|
||||||
|
imports: [
|
||||||
|
MatButtonModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatInputModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
PermissionItemComponent,
|
||||||
|
],
|
||||||
|
templateUrl: './permission-list.component.html',
|
||||||
|
styleUrl: './permission-list.component.scss'
|
||||||
|
})
|
||||||
|
export class PermissionListComponent {
|
||||||
|
@Input({ required: true }) groups: Group[] = [];
|
||||||
|
@Input({ alias: 'permissions', required: true }) _permissions: Permission[] = [];
|
||||||
|
@Input() group: Group | undefined;
|
||||||
|
|
||||||
|
readonly dialog = inject(MatDialog);
|
||||||
|
readonly client = inject(HermesClientService);
|
||||||
|
readonly events = inject(EventService);
|
||||||
|
readonly searchControl = new FormControl<string>('');
|
||||||
|
|
||||||
|
opened = false;
|
||||||
|
|
||||||
|
|
||||||
|
add() {
|
||||||
|
if (!this.group || this.opened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.opened = true;
|
||||||
|
|
||||||
|
const groupId = this.group.id;
|
||||||
|
|
||||||
|
const dialogRef = this.dialog.open(PermissionItemEditComponent, {
|
||||||
|
data: { permission: { id: '', user_id: '', group_id: groupId, path: '', allow: null }, group: this.group, groups: [], isNew: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((permission: Permission) => this.opened = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
get permissions() {
|
||||||
|
return this._permissions.filter(p => containsLettersInOrder(p.path, this.searchControl.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroupById(groupId: string) {
|
||||||
|
return this.groups.find(g => g.id == groupId);
|
||||||
|
}
|
||||||
|
}
|
12
src/app/permissions/permissions.module.ts
Normal file
12
src/app/permissions/permissions.module.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [
|
||||||
|
CommonModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class PermissionsModule { }
|
@ -25,7 +25,7 @@ const Policies = [
|
|||||||
{ path: "tts.commands.version", description: "To use !version command" },
|
{ path: "tts.commands.version", description: "To use !version command" },
|
||||||
{ path: "tts.commands.voice", description: "To use !voice command" },
|
{ path: "tts.commands.voice", description: "To use !voice command" },
|
||||||
{ path: "tts.commands.voice.admin", description: "To use !voice command on others" },
|
{ path: "tts.commands.voice.admin", description: "To use !voice command on others" },
|
||||||
]
|
];
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'policy-dropdown',
|
selector: 'policy-dropdown',
|
||||||
@ -42,7 +42,7 @@ const Policies = [
|
|||||||
})
|
})
|
||||||
export class PolicyDropdownComponent {
|
export class PolicyDropdownComponent {
|
||||||
@Input() policy: string | null = '';
|
@Input() policy: string | null = '';
|
||||||
policyControl = new FormControl('', [Validators.required]);
|
@Input({ alias: 'control' }) policyControl = new FormControl('', [Validators.required]);
|
||||||
filteredPolicies: Observable<string[]>;
|
filteredPolicies: Observable<string[]>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -45,9 +45,10 @@
|
|||||||
<td mat-cell
|
<td mat-cell
|
||||||
*matCellDef="let policy">
|
*matCellDef="let policy">
|
||||||
<button mat-button
|
<button mat-button
|
||||||
|
class="neutral"
|
||||||
(click)="edit(policy)"><mat-icon>edit</mat-icon>Edit</button>
|
(click)="edit(policy)"><mat-icon>edit</mat-icon>Edit</button>
|
||||||
<button mat-button
|
<button mat-button
|
||||||
class="delete"
|
class="danger"
|
||||||
(click)="delete(policy)"><mat-icon>delete</mat-icon>Delete</button>
|
(click)="delete(policy)"><mat-icon>delete</mat-icon>Delete</button>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
7
src/app/shared/models/permission.ts
Normal file
7
src/app/shared/models/permission.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export interface Permission {
|
||||||
|
id: string;
|
||||||
|
user_id: string;
|
||||||
|
group_id: string;
|
||||||
|
path: string;
|
||||||
|
allow: boolean | null;
|
||||||
|
}
|
14
src/app/shared/resolvers/permission-resolver.ts
Normal file
14
src/app/shared/resolvers/permission-resolver.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { Permission } from '../models/permission';
|
||||||
|
import { PermissionService } from '../services/permission.service';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export default class PermissionResolver implements Resolve<Permission[]> {
|
||||||
|
constructor(private service: PermissionService) { }
|
||||||
|
|
||||||
|
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Permission[]> {
|
||||||
|
return this.service.fetch();
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@ export default class GroupService {
|
|||||||
chatter.group_id = d.data.group_id;
|
chatter.group_id = d.data.group_id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.deleteChatter$?.subscribe(d => this.chatters = this.chatters.filter(r => r.group_id != d.request.data.group_id && r.chatter_id != d.request.data.chatter_id));
|
this.deleteChatter$?.subscribe(d => this.chatters = this.chatters.filter(r => r.group_id != d.request.data.group && r.chatter_id != d.request.data.chatter));
|
||||||
|
|
||||||
this.events.listen('tts_logoff', () => {
|
this.events.listen('tts_logoff', () => {
|
||||||
this.groups = [];
|
this.groups = [];
|
||||||
|
16
src/app/shared/services/permission.service.spec.ts
Normal file
16
src/app/shared/services/permission.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PermissionService } from './permission.service';
|
||||||
|
|
||||||
|
describe('PermissionService', () => {
|
||||||
|
let service: PermissionService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(PermissionService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
72
src/app/shared/services/permission.service.ts
Normal file
72
src/app/shared/services/permission.service.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { inject, Injectable } from '@angular/core';
|
||||||
|
import { HermesClientService } from '../../hermes-client.service';
|
||||||
|
import EventService from './EventService';
|
||||||
|
import { Permission } from '../models/permission';
|
||||||
|
import { map, Observable, of } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class PermissionService {
|
||||||
|
private readonly client = inject(HermesClientService);
|
||||||
|
private readonly events = inject(EventService);
|
||||||
|
private data: Permission[] = [];
|
||||||
|
private loaded = false;
|
||||||
|
create$: Observable<any> | undefined;
|
||||||
|
update$: Observable<any> | undefined;
|
||||||
|
delete$: Observable<any> | undefined;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.create$ = this.client.filterByRequestType('create_group_permission');
|
||||||
|
this.update$ = this.client.filterByRequestType('update_group_permission');
|
||||||
|
this.delete$ = this.client.filterByRequestType('delete_group_permission');
|
||||||
|
|
||||||
|
this.create$?.subscribe(d => {
|
||||||
|
if (d.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data.push(d.data);
|
||||||
|
});
|
||||||
|
this.update$?.subscribe(d => {
|
||||||
|
if (d.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const permission = this.data.find(p => p.id == d.data.id);
|
||||||
|
if (permission) {
|
||||||
|
permission.group_id = d.data.group_id;
|
||||||
|
permission.path = d.data.path;
|
||||||
|
permission.allow = d.data.allow;
|
||||||
|
permission.user_id = d.data.user_id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.delete$?.subscribe(d => {
|
||||||
|
if (d.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data = this.data.filter(r => r.id != d.request.data.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.events.listen('tts_logoff', () => {
|
||||||
|
this.data = [];
|
||||||
|
this.loaded = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fetch() {
|
||||||
|
if (this.loaded) {
|
||||||
|
return of(this.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const $ = this.client.first(d => d.d.request.type == 'get_group_permissions')!.pipe(map(d => d.d.data));
|
||||||
|
$.subscribe(d => {
|
||||||
|
this.data = d;
|
||||||
|
this.loaded = true;
|
||||||
|
});
|
||||||
|
this.client.fetchPermissions();
|
||||||
|
return $;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
export function containsLettersInOrder(value: string, inside: string): boolean {
|
export function containsLettersInOrder(value: string | null, inside: string | null): boolean {
|
||||||
|
if (!inside)
|
||||||
|
return true;
|
||||||
|
if (!value)
|
||||||
|
return false;
|
||||||
return containsLettersInOrderInternal(value, inside, 0, 0);
|
return containsLettersInOrderInternal(value, inside, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ export class TwitchUserItemAddComponent implements OnInit {
|
|||||||
error: () => this.responseError = 'Something went wrong.',
|
error: () => this.responseError = 'Something went wrong.',
|
||||||
complete: () => this.waitForResponse = false,
|
complete: () => this.waitForResponse = false,
|
||||||
});
|
});
|
||||||
this.client.createGroupChatter(this.data.group.id, response.user.id, response.user.login)
|
this.client.createGroupChatter(this.data.group.id, response.user.id, response.user.login);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<button mat-icon-button
|
<button mat-icon-button
|
||||||
|
[disabled]="waitForResponse"
|
||||||
(click)="delete()">
|
(click)="delete()">
|
||||||
<mat-icon>remove</mat-icon>
|
<mat-icon>remove</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
@ -21,18 +21,28 @@ export class TwitchUserItemComponent {
|
|||||||
|
|
||||||
private readonly _client = inject(HermesClientService);
|
private readonly _client = inject(HermesClientService);
|
||||||
private readonly _events = inject(EventService);
|
private readonly _events = inject(EventService);
|
||||||
private _deleted = false;
|
|
||||||
|
waitForResponse = false;
|
||||||
|
responseError: string | undefined;
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
if (this._deleted)
|
if (this.waitForResponse)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._deleted = true;
|
this.waitForResponse = true;
|
||||||
|
this.responseError = undefined;
|
||||||
|
|
||||||
this._client.first(d => d.d.request.type == 'delete_group_chatter' && d.d.request.data.group == this.user.group_id && d.d.request.data.chatter == this.user.chatter_id)
|
this._client.first(d => d.d.request.type == 'delete_group_chatter' && d.d.request.data.group == this.user.group_id && d.d.request.data.chatter == this.user.chatter_id)
|
||||||
.subscribe(async (response) => {
|
.subscribe({
|
||||||
console.log('delete group chatter', response)
|
next: (d) => {
|
||||||
|
if (d.d.error) {
|
||||||
|
this.responseError = d.d.error;
|
||||||
|
} else {
|
||||||
this._events.emit('delete_group_chatter', this.user);
|
this._events.emit('delete_group_chatter', this.user);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: () => this.responseError = 'Something went wrong.',
|
||||||
|
complete: () => this.waitForResponse = false,
|
||||||
});
|
});
|
||||||
this._client.deleteGroupChatter(this.user.group_id, this.user.chatter_id.toString());
|
this._client.deleteGroupChatter(this.user.group_id, this.user.chatter_id.toString());
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,8 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
|||||||
import { containsLettersInOrder } from '../../shared/utils/string-compare';
|
import { containsLettersInOrder } from '../../shared/utils/string-compare';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { HermesClientService } from '../../hermes-client.service';
|
|
||||||
import { Group } from '../../shared/models/group';
|
import { Group } from '../../shared/models/group';
|
||||||
import { TwitchUserItemAddComponent } from '../twitch-user-item-add/twitch-user-item-add.component';
|
import { TwitchUserItemAddComponent } from '../twitch-user-item-add/twitch-user-item-add.component';
|
||||||
import EventService from '../../shared/services/EventService';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'twitch-user-list',
|
selector: 'twitch-user-list',
|
||||||
@ -31,17 +29,10 @@ export class TwitchUserListComponent {
|
|||||||
@Input() group: Group | undefined;
|
@Input() group: Group | undefined;
|
||||||
|
|
||||||
readonly dialog = inject(MatDialog);
|
readonly dialog = inject(MatDialog);
|
||||||
readonly client = inject(HermesClientService);
|
|
||||||
readonly events = inject(EventService);
|
|
||||||
readonly searchControl: FormControl = new FormControl('');
|
readonly searchControl: FormControl = new FormControl('');
|
||||||
|
|
||||||
opened = false;
|
opened = false;
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.events.listen('delete_group_chatter', (chatter: GroupChatter) => {
|
|
||||||
this.twitchUsers.splice(this.twitchUsers.findIndex(c => c.group_id == chatter.group_id && c.chatter_id == chatter.chatter_id), 1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get users(): GroupChatter[] {
|
get users(): GroupChatter[] {
|
||||||
return this.twitchUsers.filter(u => containsLettersInOrder(u.chatter_label, this.searchControl.value));
|
return this.twitchUsers.filter(u => containsLettersInOrder(u.chatter_label, this.searchControl.value));
|
||||||
@ -57,12 +48,6 @@ export class TwitchUserListComponent {
|
|||||||
data: { username: this.searchControl.value, group: this.group },
|
data: { username: this.searchControl.value, group: this.group },
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe((chatter: GroupChatter) => {
|
dialogRef.afterClosed().subscribe((chatter: GroupChatter) => this.opened = false);
|
||||||
this.opened = false;
|
|
||||||
if (!chatter)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.twitchUsers.push(chatter);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
|
||||||
|
@use '@angular/material' as mat;
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -35,3 +37,44 @@ body {
|
|||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
background: rgb(122, 122, 122);
|
background: rgb(122, 122, 122);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mat-small {
|
||||||
|
@include mat.all-component-densities(-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-large {
|
||||||
|
@include mat.all-component-densities(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm {
|
||||||
|
@include mat.button-overrides((text-state-layer-color: rgb(52, 255, 62),
|
||||||
|
text-label-text-color: rgb(71, 218, 78),
|
||||||
|
text-disabled-label-text-color: rgb(71, 218, 78),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
.neutral {
|
||||||
|
@include mat.button-overrides((text-state-layer-color: rgb(64, 141, 255),
|
||||||
|
text-label-text-color: rgb(52, 106, 255),
|
||||||
|
text-disabled-label-text-color: rgb(52, 106, 255),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
@include mat.button-overrides((text-state-layer-color: rgb(255, 172, 63),
|
||||||
|
text-label-text-color: rgb(255, 145, 19),
|
||||||
|
text-disabled-label-text-color: rgb(255, 145, 19),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger {
|
||||||
|
@include mat.button-overrides((text-state-layer-color: rgb(255, 48, 48),
|
||||||
|
text-label-text-color: rgb(255, 52, 52),
|
||||||
|
text-disabled-label-text-color: rgb(255, 52, 52),
|
||||||
|
filled-label-text-color: rgb(255, 52, 52),
|
||||||
|
outlined-label-text-color: rgb(255, 52, 52),
|
||||||
|
protected-label-text-color: rgb(255, 52, 52),
|
||||||
|
protected-state-layer-color: rgb(255, 75, 75),
|
||||||
|
protected-ripple-color: rgb(255, 154, 154),
|
||||||
|
));
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user