#410 #439
@ -27,3 +27,4 @@ class FeatureFlagsEnum(Enum):
|
||||
short_role_name = "ShortRoleName"
|
||||
technician_full_access = "TechnicianFullAccess"
|
||||
steam_special_offers = "SteamSpecialOffers"
|
||||
scheduled_events = "ScheduledEvents"
|
||||
|
@ -29,6 +29,7 @@ class FeatureFlagsSettings(ConfigurationModelABC):
|
||||
FeatureFlagsEnum.short_role_name.value: False, # 28.09.2023 #378
|
||||
FeatureFlagsEnum.technician_full_access.value: False, # 03.10.2023 #393
|
||||
FeatureFlagsEnum.steam_special_offers.value: False, # 11.10.2023 #188
|
||||
FeatureFlagsEnum.scheduled_events.value: False, # 14.11.2023 #410
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs: dict):
|
||||
|
@ -14,6 +14,7 @@ from bot_data.abc.data_seeder_abc import DataSeederABC
|
||||
from bot_data.abc.game_server_repository_abc import GameServerRepositoryABC
|
||||
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
|
||||
from bot_data.abc.level_repository_abc import LevelRepositoryABC
|
||||
from bot_data.abc.scheduled_event_repository_abc import ScheduledEventRepositoryABC
|
||||
from bot_data.abc.server_config_repository_abc import ServerConfigRepositoryABC
|
||||
from bot_data.abc.server_repository_abc import ServerRepositoryABC
|
||||
from bot_data.abc.short_role_name_repository_abc import ShortRoleNameRepositoryABC
|
||||
@ -45,6 +46,7 @@ from bot_data.service.client_repository_service import ClientRepositoryService
|
||||
from bot_data.service.game_server_repository_service import GameServerRepositoryService
|
||||
from bot_data.service.known_user_repository_service import KnownUserRepositoryService
|
||||
from bot_data.service.level_repository_service import LevelRepositoryService
|
||||
from bot_data.service.scheduled_event_repository_service import ScheduledEventRepositoryService
|
||||
from bot_data.service.seeder_service import SeederService
|
||||
from bot_data.service.server_config_repository_service import (
|
||||
ServerConfigRepositoryService,
|
||||
@ -115,6 +117,7 @@ class DataModule(ModuleABC):
|
||||
services.add_transient(ServerConfigRepositoryABC, ServerConfigRepositoryService)
|
||||
services.add_transient(ShortRoleNameRepositoryABC, ShortRoleNameRepositoryService)
|
||||
services.add_transient(SteamSpecialOfferRepositoryABC, SteamSpecialOfferRepositoryService)
|
||||
services.add_transient(ScheduledEventRepositoryABC, ScheduledEventRepositoryService)
|
||||
|
||||
services.add_transient(SeederService)
|
||||
services.add_transient(DataSeederABC, TechnicianConfigSeeder)
|
||||
|
34
web/src/app/models/data/scheduled_events.model.ts
Normal file
34
web/src/app/models/data/scheduled_events.model.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { DataWithHistory } from "./data.model";
|
||||
import { Server, ServerFilter } from "./server.model";
|
||||
|
||||
export enum EventType {
|
||||
stageInstance = 1,
|
||||
voice = 2,
|
||||
external = 3,
|
||||
}
|
||||
|
||||
export interface ScheduledEvent extends DataWithHistory {
|
||||
id?: number;
|
||||
interval?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
channelId?: string;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
entityType?: EventType;
|
||||
location?: string;
|
||||
server?: Server;
|
||||
}
|
||||
|
||||
export interface ScheduledEventFilter {
|
||||
id?: number;
|
||||
interval?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
channelId?: string;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
entityType?: number;
|
||||
location?: string;
|
||||
server?: ServerFilter;
|
||||
}
|
@ -173,6 +173,70 @@ export class Mutations {
|
||||
}
|
||||
`;
|
||||
|
||||
static createScheduledEvent = `
|
||||
mutation createScheduledEvent($interval: String,$name: String,$description: String,$channelId: String,$startTime: String, $endTime: String,$entityType: Int,$location: String, $serverId: ID) {
|
||||
scheduledEvent {
|
||||
createScheduledEvent(input: {
|
||||
interval: $interval,
|
||||
name: $name,
|
||||
description: $description,
|
||||
channelId: $channelId,
|
||||
startTime: $startTime,
|
||||
endTime: $endTime,
|
||||
entityType: $entityType,
|
||||
location: $location,
|
||||
serverId: $serverId}
|
||||
) {
|
||||
id
|
||||
name
|
||||
description
|
||||
attribute
|
||||
operator
|
||||
value
|
||||
server {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
static updateScheduledEvent = `
|
||||
mutation updateScheduledEvent($interval: String,$name: String,$description: String,$channelId: String,$startTime: String, $endTime: String,$entityType: Int,$location: String, $serverId: ID) {
|
||||
scheduledEvent {
|
||||
updateScheduledEvent(input: {
|
||||
interval: $interval,
|
||||
name: $name,
|
||||
description: $description,
|
||||
channelId: $channelId,
|
||||
startTime: $startTime,
|
||||
endTime: $endTime,
|
||||
entityType: $entityType,
|
||||
location: $location,
|
||||
serverId: $serverId}
|
||||
) {
|
||||
id
|
||||
name
|
||||
description
|
||||
attribute
|
||||
operator
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
static deleteScheduledEvent = `
|
||||
mutation deleteScheduledEvent($id: ID) {
|
||||
scheduledEvent {
|
||||
deleteScheduledEvent(id: $id) {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
static createShortRoleName = `
|
||||
mutation createShortRoleName($shortName: String, $roleId: String, $position: String, $serverId: ID) {
|
||||
shortRoleName {
|
||||
|
@ -229,6 +229,58 @@ export class Queries {
|
||||
}
|
||||
`;
|
||||
|
||||
static scheduledEventQuery = `
|
||||
query ScheduledEventList($serverId: ID, $filter: ScheduledEventFilter, $page: Page, $sort: Sort) {
|
||||
servers(filter: {id: $serverId}) {
|
||||
scheduledEventCount
|
||||
scheduledEvents(filter: $filter, page: $page, sort: $sort) {
|
||||
id
|
||||
interval
|
||||
name
|
||||
description
|
||||
channelId
|
||||
startTime
|
||||
endTime
|
||||
entityType
|
||||
location
|
||||
server {
|
||||
id
|
||||
name
|
||||
}
|
||||
createdAt
|
||||
modifiedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
static scheduledEventWithHistoryQuery = `
|
||||
query ScheduledEventHistory($serverId: ID, $id: ID) {
|
||||
servers(filter: {id: $serverId}) {
|
||||
scheduledEventCount
|
||||
scheduledEvents(filter: {id: $id}) {
|
||||
id
|
||||
|
||||
history {
|
||||
id
|
||||
interval
|
||||
name
|
||||
description
|
||||
channelId
|
||||
startTime
|
||||
endTime
|
||||
entityType
|
||||
location
|
||||
server
|
||||
deleted
|
||||
dateFrom
|
||||
dateTo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
static shortRoleNamePositionsQuery = `
|
||||
query {
|
||||
|
@ -9,6 +9,7 @@ import { ServerConfig } from "../config/server-config.model";
|
||||
import { ShortRoleName } from "../data/short_role_name.model";
|
||||
import { FeatureFlag } from "../config/feature-flags.model";
|
||||
import { UserWarning } from "../data/user_warning.model";
|
||||
import { ScheduledEvent } from "../data/scheduled_events.model";
|
||||
|
||||
export interface Query {
|
||||
serverCount: number;
|
||||
@ -57,6 +58,11 @@ export interface AchievementListQuery {
|
||||
achievements: Achievement[];
|
||||
}
|
||||
|
||||
export interface ScheduledEventListQuery {
|
||||
scheduledEventCount: number;
|
||||
scheduledEvents: ScheduledEvent[];
|
||||
}
|
||||
|
||||
export interface AutoRoleQuery {
|
||||
autoRoleCount: number;
|
||||
autoRoles: AutoRole[];
|
||||
|
@ -7,6 +7,7 @@ import { TechnicianConfig } from "../config/technician-config.model";
|
||||
import { ServerConfig } from "../config/server-config.model";
|
||||
import { ShortRoleName } from "../data/short_role_name.model";
|
||||
import { UserWarning } from "../data/user_warning.model";
|
||||
import { ScheduledEvent } from "../data/scheduled_events.model";
|
||||
|
||||
export interface GraphQLResult {
|
||||
data: {
|
||||
@ -71,6 +72,14 @@ export interface AchievementMutationResult {
|
||||
};
|
||||
}
|
||||
|
||||
export interface ScheduledEventMutationResult {
|
||||
scheduledEvent: {
|
||||
createScheduledEvent?: ScheduledEvent
|
||||
updateScheduledEvent?: ScheduledEvent
|
||||
deleteScheduledEvent?: ScheduledEvent
|
||||
};
|
||||
}
|
||||
|
||||
export interface ShortRoleNameMutationResult {
|
||||
shortRoleName: {
|
||||
createShortRoleName?: ShortRoleName
|
||||
|
@ -13,7 +13,7 @@ import { InputTextModule } from "primeng/inputtext";
|
||||
import { MenuModule } from "primeng/menu";
|
||||
import { PasswordModule } from "primeng/password";
|
||||
import { ProgressSpinnerModule } from "primeng/progressspinner";
|
||||
import { SortableColumn, TableModule } from "primeng/table";
|
||||
import { TableModule } from "primeng/table";
|
||||
import { ToastModule } from "primeng/toast";
|
||||
import { AuthRolePipe } from "./pipes/auth-role.pipe";
|
||||
import { IpAddressPipe } from "./pipes/ip-address.pipe";
|
||||
@ -24,18 +24,20 @@ import { InputNumberModule } from "primeng/inputnumber";
|
||||
import { ImageModule } from "primeng/image";
|
||||
import { SidebarModule } from "primeng/sidebar";
|
||||
import { HistoryBtnComponent } from "./components/history-btn/history-btn.component";
|
||||
import { DataViewModule, DataViewLayoutOptions } from "primeng/dataview";
|
||||
import { DataViewLayoutOptions, DataViewModule } from "primeng/dataview";
|
||||
import { ConfigListComponent } from "./components/config-list/config-list.component";
|
||||
import { MultiSelectModule } from "primeng/multiselect";
|
||||
import { HideableColumnComponent } from './components/hideable-column/hideable-column.component';
|
||||
import { HideableHeaderComponent } from './components/hideable-header/hideable-header.component';
|
||||
import { MultiSelectColumnsComponent } from './base/multi-select-columns/multi-select-columns.component';
|
||||
import { FeatureFlagListComponent } from './components/feature-flag-list/feature-flag-list.component';
|
||||
import { HideableColumnComponent } from "./components/hideable-column/hideable-column.component";
|
||||
import { HideableHeaderComponent } from "./components/hideable-header/hideable-header.component";
|
||||
import { MultiSelectColumnsComponent } from "./base/multi-select-columns/multi-select-columns.component";
|
||||
import { FeatureFlagListComponent } from "./components/feature-flag-list/feature-flag-list.component";
|
||||
import { InputSwitchModule } from "primeng/inputswitch";
|
||||
import { CalendarModule } from "primeng/calendar";
|
||||
import { DataImportAndExportComponent } from './components/data-import-and-export/data-import-and-export.component';
|
||||
import { DataImportAndExportComponent } from "./components/data-import-and-export/data-import-and-export.component";
|
||||
import { FileUploadModule } from "primeng/fileupload";
|
||||
import { SelectButtonModule } from "primeng/selectbutton";
|
||||
import { TabViewModule } from "primeng/tabview";
|
||||
import { RadioButtonModule } from "primeng/radiobutton";
|
||||
|
||||
|
||||
const PrimeNGModules = [
|
||||
@ -66,7 +68,9 @@ const PrimeNGModules = [
|
||||
CalendarModule,
|
||||
FileUploadModule,
|
||||
SelectButtonModule,
|
||||
]
|
||||
TabViewModule,
|
||||
RadioButtonModule
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -79,7 +83,7 @@ const PrimeNGModules = [
|
||||
HideableHeaderComponent,
|
||||
MultiSelectColumnsComponent,
|
||||
FeatureFlagListComponent,
|
||||
DataImportAndExportComponent,
|
||||
DataImportAndExportComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
@ -0,0 +1,44 @@
|
||||
<div class="edit-dialog">
|
||||
<p-dialog [header]="header" [(visible)]="visible" [modal]="true"
|
||||
[draggable]="false" [resizable]="false"
|
||||
[style]="{ width: '50vw' }">
|
||||
<form [formGroup]="inputForm">
|
||||
<p-tabView [(activeIndex)]="activeIndex">
|
||||
<p-tabPanel header="{{'view.server.scheduled_events.edit_dialog.location.tab_name' | translate}}">
|
||||
<div *ngFor="let enum of EventType | keyvalue" class="field-checkbox">
|
||||
<p-radioButton [inputId]="enum.key" [value]="enum.value" formControlName="entityType"></p-radioButton>
|
||||
<label [for]="enum.key"
|
||||
class="ml-2">{{'view.server.scheduled_events.edit_dialog.location.' + enum.key | translate}}</label>
|
||||
</div>
|
||||
</p-tabPanel>
|
||||
<p-tabPanel header="{{'view.server.scheduled_events.edit_dialog.event_info.tab_name' | translate}}">
|
||||
<p>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem
|
||||
aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
|
||||
Nemo
|
||||
enim
|
||||
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos
|
||||
qui
|
||||
ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
|
||||
</p>
|
||||
</p-tabPanel>
|
||||
</p-tabView>
|
||||
<ng-template pTemplate="footer">
|
||||
<div style="display: flex;">
|
||||
<div class="btn-wrapper" style="flex: 1;">
|
||||
<button pButton label="{{'common.back' | translate}}" class="text-btn"
|
||||
(click)="back()" [disabled]="activeIndex == 0"></button>
|
||||
</div>
|
||||
<div class="btn-wrapper">
|
||||
<button pButton label="{{'common.abort' | translate}}" class="btn danger-btn"
|
||||
(click)="visible = false"></button>
|
||||
<button *ngIf="activeIndex < 1" pButton label="{{'common.continue' | translate}}" class="btn"
|
||||
(click)="next()"></button>
|
||||
<button *ngIf="activeIndex == 1" pButton label="{{'common.save' | translate}}" class="btn"
|
||||
(click)="saveEvent()" [disabled]="!inputForm.valid"></button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</form>
|
||||
</p-dialog>
|
||||
</div>
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EditScheduledEventDialogComponent } from './edit-scheduled-event-dialog.component';
|
||||
|
||||
describe('EditScheduledEventDialogComponent', () => {
|
||||
let component: EditScheduledEventDialogComponent;
|
||||
let fixture: ComponentFixture<EditScheduledEventDialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ EditScheduledEventDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(EditScheduledEventDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,70 @@
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { EventType, ScheduledEvent } from "../../../../../../models/data/scheduled_events.model";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { FormBuilder, FormControl, Validators } from "@angular/forms";
|
||||
|
||||
@Component({
|
||||
selector: "app-edit-scheduled-event-dialog",
|
||||
templateUrl: "./edit-scheduled-event-dialog.component.html",
|
||||
styleUrls: ["./edit-scheduled-event-dialog.component.scss"]
|
||||
})
|
||||
export class EditScheduledEventDialogComponent {
|
||||
@Input() event?: ScheduledEvent;
|
||||
@Output() save = new EventEmitter<ScheduledEvent>();
|
||||
|
||||
get visible() {
|
||||
return this.event != undefined;
|
||||
}
|
||||
|
||||
set visible(val: boolean) {
|
||||
if (!val) {
|
||||
this.event = undefined;
|
||||
}
|
||||
this.visible = val;
|
||||
}
|
||||
|
||||
get header() {
|
||||
if (this.event && this.event.createdAt === "" && this.event.modifiedAt === "") {
|
||||
return this.translate.instant("view.server.scheduled_events.edit_dialog.add_header");
|
||||
} else {
|
||||
return this.translate.instant("view.server.scheduled_events.edit_dialog.edit_header");
|
||||
}
|
||||
}
|
||||
|
||||
public activeIndex: number = 0;
|
||||
public inputForm = this.fb.group({
|
||||
id: new FormControl<number | undefined>(this.event?.id),
|
||||
interval: new FormControl<string | undefined>(this.event?.interval, [Validators.required]),
|
||||
entityType: new FormControl<number | undefined>(this.event?.entityType, [Validators.required]),
|
||||
channelId: new FormControl<string | undefined>(this.event?.channelId, this.event?.entityType == EventType.voice || this.event?.entityType == EventType.stageInstance ? [Validators.required] : []),
|
||||
location: new FormControl<string | undefined>(this.event?.location, this.event?.entityType == EventType.external ? [Validators.required] : []),
|
||||
name: new FormControl<string | undefined>(this.event?.name, [Validators.required]),
|
||||
startTime: new FormControl<string | undefined>(this.event?.startTime, [Validators.required]),
|
||||
endTime: new FormControl<string | undefined>(this.event?.endTime),
|
||||
description: new FormControl<string | undefined>(this.event?.description)
|
||||
});
|
||||
|
||||
constructor(
|
||||
private translate: TranslateService,
|
||||
private fb: FormBuilder
|
||||
) {
|
||||
}
|
||||
|
||||
public saveEvent() {
|
||||
this.save.emit(this.event);
|
||||
}
|
||||
|
||||
public next() {
|
||||
this.activeIndex++;
|
||||
}
|
||||
|
||||
public back() {
|
||||
this.activeIndex--;
|
||||
}
|
||||
|
||||
protected readonly EventType = {
|
||||
stage: EventType.stageInstance,
|
||||
voice: EventType.voice,
|
||||
somewhere_else: EventType.external
|
||||
};
|
||||
}
|
@ -0,0 +1,307 @@
|
||||
<app-edit-scheduled-event-dialog [event]="editableScheduledEvent" (save)="onRowEditSave($event)"></app-edit-scheduled-event-dialog>
|
||||
|
||||
<h1>
|
||||
{{'view.server.scheduled_events.header' | translate}}
|
||||
</h1>
|
||||
<div class="content-wrapper">
|
||||
<div class="content">
|
||||
<p-table #dt [value]="scheduledEvents" [responsive]="true" responsiveLayout="stack" [breakpoint]="'720px'"
|
||||
dataKey="id" [rowHover]="true" [rows]="10"
|
||||
[rowsPerPageOptions]="[10,25,50]" [paginator]="true" [loading]="loading" [totalRecords]="totalRecords"
|
||||
[lazy]="true" (onLazyLoad)="nextPage($event)">
|
||||
|
||||
<ng-template pTemplate="caption">
|
||||
<div class="table-caption">
|
||||
<div class="table-caption-table-info">
|
||||
<div class="table-caption-text">
|
||||
<ng-container *ngIf="!loading">{{scheduledEvents.length}} {{'common.of' | translate}}
|
||||
{{dt.totalRecords}}
|
||||
</ng-container>
|
||||
{{'view.server.scheduled_events.scheduled_events' | translate}}
|
||||
</div>
|
||||
|
||||
<app-multi-select-columns [table]="name" [columns]="columns"
|
||||
[(hiddenColumns)]="hiddenColumns"></app-multi-select-columns>
|
||||
</div>
|
||||
|
||||
<div class="table-caption-btn-wrapper btn-wrapper">
|
||||
<button pButton label="{{'common.add' | translate}}" class="icon-btn btn"
|
||||
icon="pi pi-plus" (click)="addScheduledEvent(dt)"
|
||||
[disabled]="isEditingNew || !user?.isModerator && !user?.isAdmin">
|
||||
</button>
|
||||
<button pButton label="{{'common.reset_filters' | translate}}" icon="pi pi-undo"
|
||||
class="icon-btn btn" (click)="resetFilters()">
|
||||
</button>
|
||||
<app-data-import-and-export name="scheduledEvent" [(data)]="scheduledEvents"
|
||||
[callback]="callback" [validator]="validator"></app-data-import-and-export>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="header">
|
||||
<tr>
|
||||
<th hideable-th="id" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.id' | translate}}</div>
|
||||
<p-sortIcon field="id" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th hideable-th="interval" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.interval' | translate}}</div>
|
||||
<p-sortIcon field="interval" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
<th hideable-th="name" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.name' | translate}}</div>
|
||||
<p-sortIcon field="name" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
<th hideable-th="description" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.description' | translate}}</div>
|
||||
<p-sortIcon field="description" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
<th hideable-th="channel_id" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.channel_id' | translate}}</div>
|
||||
<p-sortIcon field="channelId" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
<th hideable-th="start_time" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.start_time' | translate}}</div>
|
||||
<p-sortIcon field="startTime" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
<th hideable-th="end_time" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.end_time' | translate}}</div>
|
||||
<p-sortIcon field="endTime" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
<th hideable-th="type" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.type' | translate}}</div>
|
||||
<p-sortIcon field="entityType" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
<th hideable-th="location" [parent]="this" [sortable]="true">
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.location' | translate}}</div>
|
||||
<p-sortIcon field="location" class="table-header-icon"></p-sortIcon>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th>
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.created_at' | translate}}</div>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th>
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.modified_at' | translate}}</div>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th>
|
||||
<div class="table-header-label">
|
||||
<div class="table-header-text">{{'common.actions' | translate}}</div>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th hideable-th="id" [parent]="this" class="table-header-small">
|
||||
<form [formGroup]="filterForm">
|
||||
<input type="text" pInputText formControlName="id"
|
||||
placeholder="{{'common.id' | translate}}">
|
||||
</form>
|
||||
</th>
|
||||
|
||||
<th class="table-header-small"></th>
|
||||
|
||||
<th hideable-th="name" [parent]="this">
|
||||
<form [formGroup]="filterForm">
|
||||
<input type="text" pInputText formControlName="name"
|
||||
placeholder="{{'common.name' | translate}}">
|
||||
</form>
|
||||
</th>
|
||||
|
||||
<th class="table-header-small"></th>
|
||||
<th class="table-header-small"></th>
|
||||
<th class="table-header-small"></th>
|
||||
<th class="table-header-small"></th>
|
||||
<th class="table-header-small"></th>
|
||||
<th class="table-header-small"></th>
|
||||
<th class="table-header-small-dropdown"></th>
|
||||
<th class="table-header-small-dropdown"></th>
|
||||
<th class="table-header-actions"></th>
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="body" let-scheduledEvent let-editing="editing" let-ri="rowIndex">
|
||||
<tr [pEditableRow]="scheduledEvent">
|
||||
<td hideable-td="id" [parent]="this">
|
||||
<span class="p-column-title">{{'common.id' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
{{scheduledEvent.id}}
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.id}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td hideable-td="interval" [parent]="this">
|
||||
<span class="p-column-title">{{'common.interval' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="scheduledEvent.interval">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.interval}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td hideable-td="name" [parent]="this">
|
||||
<span class="p-column-title">{{'common.name' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="scheduledEvent.name">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.name}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td hideable-td="description" [parent]="this">
|
||||
<span class="p-column-title">{{'common.description' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="scheduledEvent.description">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.description}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td hideable-td="channel_id" [parent]="this">
|
||||
<span class="p-column-title">{{'common.channel_id' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="scheduledEvent.channel_id">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.channel_id}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td hideable-td="start_time" [parent]="this">
|
||||
<span class="p-column-title">{{'common.start_time' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="scheduledEvent.start_time">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.start_time}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td hideable-td="end_time" [parent]="this">
|
||||
<span class="p-column-title">{{'common.end_time' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="scheduledEvent.end_time">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.end_time}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td hideable-td="type" [parent]="this">
|
||||
<span class="p-column-title">{{'common.type' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="scheduledEvent.type">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.type}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td hideable-td="location" [parent]="this">
|
||||
<span class="p-column-title">{{'common.location' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
<input class="table-edit-input" pInputText type="text" [(ngModel)]="scheduledEvent.location">
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.location}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="p-column-title">{{'common.created_at' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
{{scheduledEvent.createdAt | date:'dd.MM.yy HH:mm'}}
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.createdAt | date:'dd.MM.yy HH:mm'}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
<td>
|
||||
<span class="p-column-title">{{'common.modified_at' | translate}}:</span>
|
||||
<p-cellEditor>
|
||||
<ng-template pTemplate="input">
|
||||
{{scheduledEvent.modifiedAt | date:'dd.MM.yy HH:mm'}}
|
||||
</ng-template>
|
||||
<ng-template pTemplate="output">
|
||||
{{scheduledEvent.modifiedAt | date:'dd.MM.yy HH:mm'}}
|
||||
</ng-template>
|
||||
</p-cellEditor>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-wrapper">
|
||||
<app-history-btn *ngIf="!isEditingNew" [id]="scheduledEvent.id" [query]="query"
|
||||
translationKey="view.server.scheduledEvent.header"></app-history-btn>
|
||||
<button *ngIf="!editing" pButton class="btn icon-btn" icon="pi pi-pencil"
|
||||
(click)="onRowEditInit(dt, scheduledEvent, ri)"
|
||||
[disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||
<button *ngIf="!editing" pButton class="btn icon-btn danger-icon-btn" icon="pi pi-trash"
|
||||
(click)="deleteScheduledEvent(scheduledEvent)"
|
||||
[disabled]="!user || !user.isModerator && !user.isAdmin"></button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="emptymessage">
|
||||
<tr></tr>
|
||||
<tr>
|
||||
<td colspan="14">{{'common.no_entries_found' | translate}}</td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="paginatorleft">
|
||||
</ng-template>
|
||||
</p-table>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ScheduledEventsComponent } from './scheduled-events.component';
|
||||
|
||||
describe('ScheduledEventsComponent', () => {
|
||||
let component: ScheduledEventsComponent;
|
||||
let fixture: ComponentFixture<ScheduledEventsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ScheduledEventsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ScheduledEventsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,287 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormControl, FormGroup } from "@angular/forms";
|
||||
import { Page } from "../../../../../../models/graphql/filter/page.model";
|
||||
import { Sort, SortDirection } from "../../../../../../models/graphql/filter/sort.model";
|
||||
import { Subject, throwError } from "rxjs";
|
||||
import { Server } from "../../../../../../models/data/server.model";
|
||||
import { UserDTO } from "../../../../../../models/auth/auth-user.dto";
|
||||
import { LazyLoadEvent } from "primeng/api";
|
||||
import { Queries } from "../../../../../../models/graphql/queries.model";
|
||||
import { AuthService } from "../../../../../../services/auth/auth.service";
|
||||
import { SpinnerService } from "../../../../../../services/spinner/spinner.service";
|
||||
import { ToastService } from "../../../../../../services/toast/toast.service";
|
||||
import { ConfirmationDialogService } from "../../../../../../services/confirmation-dialog/confirmation-dialog.service";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { DataService } from "../../../../../../services/data/data.service";
|
||||
import { SidebarService } from "../../../../../../services/sidebar/sidebar.service";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { Query, ScheduledEventListQuery } from "../../../../../../models/graphql/query.model";
|
||||
import { catchError, debounceTime, takeUntil } from "rxjs/operators";
|
||||
import { Table } from "primeng/table";
|
||||
import { ScheduledEventMutationResult } from "../../../../../../models/graphql/result.model";
|
||||
import { Mutations } from "../../../../../../models/graphql/mutations.model";
|
||||
import { ComponentWithTable } from "../../../../../../base/component-with-table";
|
||||
import { EventType, ScheduledEvent, ScheduledEventFilter } from "../../../../../../models/data/scheduled_events.model";
|
||||
|
||||
@Component({
|
||||
selector: "app-scheduled-events",
|
||||
templateUrl: "./scheduled-events.component.html",
|
||||
styleUrls: ["./scheduled-events.component.scss"]
|
||||
})
|
||||
export class ScheduledEventsComponent extends ComponentWithTable implements OnInit, OnDestroy {
|
||||
public scheduledEvents: ScheduledEvent[] = [];
|
||||
public loading = true;
|
||||
|
||||
public filterForm!: FormGroup<{
|
||||
id: FormControl<number | null>,
|
||||
interval: FormControl<string | null>,
|
||||
name: FormControl<string | null>,
|
||||
description: FormControl<string | null>,
|
||||
channelId: FormControl<string | null>,
|
||||
startTime: FormControl<string | null>,
|
||||
endTime: FormControl<string | null>,
|
||||
entityType: FormControl<EventType | null>,
|
||||
location: FormControl<string | null>,
|
||||
}>;
|
||||
|
||||
public filter: ScheduledEventFilter = {};
|
||||
public page: Page = {
|
||||
pageSize: undefined,
|
||||
pageIndex: undefined
|
||||
};
|
||||
public sort: Sort = {
|
||||
sortColumn: undefined,
|
||||
sortDirection: undefined
|
||||
};
|
||||
|
||||
public totalRecords: number = 0;
|
||||
|
||||
private unsubscriber = new Subject<void>();
|
||||
private server: Server = {};
|
||||
public user: UserDTO | null = null;
|
||||
public query: string = Queries.scheduledEventWithHistoryQuery;
|
||||
public editableScheduledEvent?: ScheduledEvent = undefined;
|
||||
|
||||
public constructor(
|
||||
private authService: AuthService,
|
||||
private spinner: SpinnerService,
|
||||
private toastService: ToastService,
|
||||
private confirmDialog: ConfirmationDialogService,
|
||||
private fb: FormBuilder,
|
||||
private translate: TranslateService,
|
||||
private data: DataService,
|
||||
private sidebar: SidebarService,
|
||||
private route: ActivatedRoute) {
|
||||
super("ScheduledEvent", ["id", "interval", "name", "description", "channel_id", "start_time", "end_time", "type", "location"],
|
||||
(oldElement: ScheduledEvent, newElement: ScheduledEvent) => {
|
||||
return oldElement.name === newElement.name;
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.loading = true;
|
||||
this.setFilterForm();
|
||||
this.data.getServerFromRoute(this.route).then(async server => {
|
||||
this.server = server;
|
||||
let authUser = await this.authService.getLoggedInUser();
|
||||
this.user = authUser?.users?.find(u => u.server == this.server.id) ?? null;
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.unsubscriber.next();
|
||||
this.unsubscriber.complete();
|
||||
}
|
||||
|
||||
public loadNextPage(): void {
|
||||
this.data.query<ScheduledEventListQuery>(Queries.scheduledEventQuery, {
|
||||
serverId: this.server.id, filter: this.filter, page: this.page, sort: this.sort
|
||||
},
|
||||
(data: Query) => {
|
||||
return data.servers[0];
|
||||
}
|
||||
).subscribe(data => {
|
||||
this.totalRecords = data.scheduledEventCount;
|
||||
this.scheduledEvents = data.scheduledEvents;
|
||||
this.spinner.hideSpinner();
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
public setFilterForm(): void {
|
||||
this.filterForm = this.fb.group({
|
||||
id: new FormControl<number | null>(null),
|
||||
interval: new FormControl<string | null>(null),
|
||||
name: new FormControl<string | null>(null),
|
||||
description: new FormControl<string | null>(null),
|
||||
channelId: new FormControl<string | null>(null),
|
||||
startTime: new FormControl<string | null>(null),
|
||||
endTime: new FormControl<string | null>(null),
|
||||
entityType: new FormControl<EventType | null>(null),
|
||||
location: new FormControl<string | null>(null),
|
||||
});
|
||||
|
||||
this.filterForm.valueChanges.pipe(
|
||||
takeUntil(this.unsubscriber),
|
||||
debounceTime(600)
|
||||
).subscribe(changes => {
|
||||
if (changes.id) {
|
||||
this.filter.id = changes.id;
|
||||
} else {
|
||||
this.filter.id = undefined;
|
||||
}
|
||||
|
||||
if (changes.interval) {
|
||||
this.filter.interval = changes.interval;
|
||||
} else {
|
||||
this.filter.interval = undefined;
|
||||
}
|
||||
|
||||
if (changes.name) {
|
||||
this.filter.name = changes.name;
|
||||
} else {
|
||||
this.filter.name = undefined;
|
||||
}
|
||||
|
||||
if (changes.description) {
|
||||
this.filter.description = changes.description;
|
||||
} else {
|
||||
this.filter.description = undefined;
|
||||
}
|
||||
|
||||
if (changes.channelId) {
|
||||
this.filter.channelId = changes.channelId;
|
||||
} else {
|
||||
this.filter.channelId = undefined;
|
||||
}
|
||||
|
||||
if (changes.startTime) {
|
||||
this.filter.startTime = changes.startTime;
|
||||
} else {
|
||||
this.filter.startTime = undefined;
|
||||
}
|
||||
|
||||
if (changes.endTime) {
|
||||
this.filter.endTime = changes.endTime;
|
||||
} else {
|
||||
this.filter.endTime = undefined;
|
||||
}
|
||||
|
||||
if (changes.entityType) {
|
||||
this.filter.entityType = changes.entityType;
|
||||
} else {
|
||||
this.filter.entityType = undefined;
|
||||
}
|
||||
|
||||
if (changes.location) {
|
||||
this.filter.location = changes.location;
|
||||
} else {
|
||||
this.filter.location = undefined;
|
||||
}
|
||||
|
||||
if (this.page.pageSize)
|
||||
this.page.pageSize = 10;
|
||||
|
||||
if (this.page.pageIndex)
|
||||
this.page.pageIndex = 0;
|
||||
|
||||
this.loadNextPage();
|
||||
});
|
||||
}
|
||||
|
||||
public newScheduledEventTemplate: ScheduledEvent = {
|
||||
createdAt: "",
|
||||
modifiedAt: ""
|
||||
};
|
||||
|
||||
public nextPage(event: LazyLoadEvent): void {
|
||||
this.page.pageSize = event.rows ?? 0;
|
||||
if (event.first != null && event.rows != null)
|
||||
this.page.pageIndex = event.first / event.rows;
|
||||
this.sort.sortColumn = event.sortField ?? undefined;
|
||||
this.sort.sortDirection = event.sortOrder === 1 ? SortDirection.ASC : event.sortOrder === -1 ? SortDirection.DESC : SortDirection.ASC;
|
||||
|
||||
this.loadNextPage();
|
||||
}
|
||||
|
||||
public resetFilters(): void {
|
||||
this.filterForm.reset();
|
||||
}
|
||||
|
||||
public onRowEditInit(table: Table, event: ScheduledEvent, index: number): void {
|
||||
this.editableScheduledEvent = event;
|
||||
}
|
||||
|
||||
public override onRowEditSave(newScheduledEvent: ScheduledEvent): void {
|
||||
if (this.isEditingNew && JSON.stringify(newScheduledEvent) === JSON.stringify(this.newScheduledEventTemplate)) {
|
||||
this.isEditingNew = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isEditingNew) {
|
||||
this.spinner.showSpinner();
|
||||
this.data.mutation<ScheduledEventMutationResult>(Mutations.createScheduledEvent, {
|
||||
name: newScheduledEvent.name,
|
||||
serverId: this.server.id
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.isEditingNew = false;
|
||||
this.spinner.hideSpinner();
|
||||
return throwError(err);
|
||||
})).subscribe(result => {
|
||||
this.isEditingNew = false;
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.success(this.translate.instant("view.server.ScheduledEvents.message.scheduled_event_create"), this.translate.instant("view.server.ScheduledEvents.message.scheduled_event_create_d", { name: result.scheduledEvent.createScheduledEvent?.name }));
|
||||
this.loadNextPage();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.spinner.showSpinner();
|
||||
this.data.mutation<ScheduledEventMutationResult>(Mutations.updateScheduledEvent, {
|
||||
id: newScheduledEvent.id,
|
||||
name: newScheduledEvent.name,
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
return throwError(err);
|
||||
})).subscribe(_ => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.success(this.translate.instant("view.server.ScheduledEvents.message.scheduled_event_update"), this.translate.instant("view.server.ScheduledEvents.message.scheduled_event_update_d", { name: newScheduledEvent.name }));
|
||||
this.loadNextPage();
|
||||
});
|
||||
}
|
||||
|
||||
public deleteScheduledEvent(ScheduledEvent: ScheduledEvent): void {
|
||||
this.confirmDialog.confirmDialog(
|
||||
this.translate.instant("view.server.ScheduledEvents.message.scheduled_event_delete"), this.translate.instant("view.server.ScheduledEvents.message.scheduled_event_delete_q", { name: ScheduledEvent.name }),
|
||||
() => {
|
||||
this.spinner.showSpinner();
|
||||
this.data.mutation<ScheduledEventMutationResult>(Mutations.deleteScheduledEvent, {
|
||||
id: ScheduledEvent.id
|
||||
}
|
||||
).pipe(catchError(err => {
|
||||
this.spinner.hideSpinner();
|
||||
return throwError(err);
|
||||
})).subscribe(l => {
|
||||
this.spinner.hideSpinner();
|
||||
this.toastService.success(this.translate.instant("view.server.ScheduledEvents.message.scheduled_event_deleted"), this.translate.instant("view.server.ScheduledEvents.message.scheduled_event_deleted_d", { name: ScheduledEvent.name }));
|
||||
this.loadNextPage();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public addScheduledEvent(table: Table): void {
|
||||
this.editableScheduledEvent = JSON.parse(JSON.stringify(this.newScheduledEventTemplate));
|
||||
// const newScheduledEvent = JSON.parse(JSON.stringify(this.newScheduledEventTemplate));
|
||||
//
|
||||
// this.scheduledEvents = [newScheduledEvent, ...this.scheduledEvents];
|
||||
//
|
||||
// table.initRowEdit(newScheduledEvent);
|
||||
//
|
||||
// const index = this.scheduledEvents.findIndex(l => l.id == newScheduledEvent.id);
|
||||
// this.onRowEditInit(table, newScheduledEvent, index);
|
||||
//
|
||||
// this.isEditingNew = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
import { ScheduledEventsComponent } from "./components/scheduled-events/scheduled-events.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: "", component: ScheduledEventsComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class ScheduledEventsRoutingModule {
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ScheduledEventsRoutingModule } from './scheduled-events-routing.module';
|
||||
import { ScheduledEventsComponent } from "./components/scheduled-events/scheduled-events.component";
|
||||
import { SharedModule } from "../../../shared/shared.module";
|
||||
import { EditScheduledEventDialogComponent } from './components/edit-scheduled-event-dialog/edit-scheduled-event-dialog.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ScheduledEventsComponent,
|
||||
EditScheduledEventDialogComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule,
|
||||
ScheduledEventsRoutingModule
|
||||
]
|
||||
})
|
||||
export class ScheduledEventsModule { }
|
@ -19,6 +19,7 @@ const routes: Routes = [
|
||||
{ path: "levels", loadChildren: () => import("./levels/levels.module").then(m => m.LevelsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
|
||||
{ path: "achievements", loadChildren: () => import("./achievements/achievements.module").then(m => m.AchievementsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
|
||||
{ path: "short-role-names", loadChildren: () => import("./short-role-name/short-role-name.module").then(m => m.ShortRoleNameModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
|
||||
{ path: "scheduled-events", loadChildren: () => import("./scheduled-events/scheduled-events.module").then(m => m.ScheduledEventsModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Moderator } },
|
||||
{ path: "config", loadChildren: () => import("./config/config.module").then(m => m.ConfigModule), canActivate: [AuthGuard], data: { memberRole: MemberRoles.Admin } }
|
||||
];
|
||||
|
||||
|
@ -1,14 +1,8 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ShortRoleNamesComponent } from './components/short-role-names/short-role-names.component';
|
||||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { ShortRoleNamesComponent } from "./components/short-role-names/short-role-names.component";
|
||||
import { ShortRoleNameRoutingModule } from "./short-role-name-routing.module";
|
||||
import { ButtonModule } from "primeng/button";
|
||||
import { InputTextModule } from "primeng/inputtext";
|
||||
import { ReactiveFormsModule } from "@angular/forms";
|
||||
import { SharedModule } from "../../../shared/shared.module";
|
||||
import { TableModule } from "primeng/table";
|
||||
import { TranslateModule } from "@ngx-translate/core";
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
@ -18,13 +12,7 @@ import { TranslateModule } from "@ngx-translate/core";
|
||||
imports: [
|
||||
CommonModule,
|
||||
ShortRoleNameRoutingModule,
|
||||
ButtonModule,
|
||||
InputTextModule,
|
||||
ReactiveFormsModule,
|
||||
SharedModule,
|
||||
SharedModule,
|
||||
TableModule,
|
||||
TranslateModule
|
||||
]
|
||||
})
|
||||
export class ShortRoleNameModule { }
|
||||
|
@ -30,6 +30,7 @@ export class SidebarService {
|
||||
serverAutoRoles: MenuItem = {};
|
||||
serverLevels: MenuItem = {};
|
||||
serverAchievements: MenuItem = {};
|
||||
serverScheduledEvents: MenuItem = {};
|
||||
serverShortRoleNames: MenuItem = {};
|
||||
serverConfig: MenuItem = {};
|
||||
serverMenu: MenuItem = {};
|
||||
@ -110,6 +111,13 @@ export class SidebarService {
|
||||
routerLink: `server/${this.server?.id}/achievements`
|
||||
};
|
||||
|
||||
this.serverScheduledEvents = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.scheduled_events") : "",
|
||||
icon: "pi pi-calender",
|
||||
visible: true,
|
||||
routerLink: `server/${this.server?.id}/scheduled-events`
|
||||
};
|
||||
|
||||
this.serverShortRoleNames = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.short_role_names") : "",
|
||||
icon: "pi pi-list",
|
||||
@ -129,7 +137,7 @@ export class SidebarService {
|
||||
icon: "pi pi-server",
|
||||
visible: false,
|
||||
expanded: true,
|
||||
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverShortRoleNames, this.serverConfig]
|
||||
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverScheduledEvents, this.serverShortRoleNames, this.serverConfig]
|
||||
};
|
||||
this.adminConfig = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
||||
@ -205,6 +213,7 @@ export class SidebarService {
|
||||
this.serverAutoRoles.visible = isTechnicianAndFullAccessActive || this.hasFeature("AutoRoleModule") && user?.isModerator;
|
||||
this.serverLevels.visible = isTechnicianAndFullAccessActive || this.hasFeature("LevelModule") && user?.isModerator;
|
||||
this.serverAchievements.visible = isTechnicianAndFullAccessActive || this.hasFeature("AchievementsModule") && user?.isModerator;
|
||||
this.serverScheduledEvents.visible = isTechnicianAndFullAccessActive || this.hasFeature("ScheduledEvents") && user?.isModerator;
|
||||
this.serverShortRoleNames.visible = isTechnicianAndFullAccessActive || this.hasFeature("ShortRoleName") && user?.isAdmin;
|
||||
|
||||
this.serverConfig.visible = isTechnicianAndFullAccessActive || user?.isAdmin;
|
||||
|
@ -124,12 +124,14 @@
|
||||
},
|
||||
"common": {
|
||||
"404": "404 - Der Eintrag konnte nicht gefunden werden",
|
||||
"abort": "Abbrechen",
|
||||
"actions": "Aktionen",
|
||||
"active": "Aktiv",
|
||||
"add": "Hinzufügen",
|
||||
"attribute": "Attribut",
|
||||
"auth_role": "Rolle",
|
||||
"author": "Autor",
|
||||
"back": "Zurück",
|
||||
"bool_as_string": {
|
||||
"false": "Nein",
|
||||
"true": "Ja"
|
||||
@ -137,12 +139,14 @@
|
||||
"channel_id": "Kanal Id",
|
||||
"channel_name": "Kanal",
|
||||
"color": "Farbe",
|
||||
"continue": "Weiter",
|
||||
"created_at": "Erstellt am",
|
||||
"description": "Beschreibung",
|
||||
"discord_id": "Discord Id",
|
||||
"edit": "Bearbeiten",
|
||||
"email": "E-Mail",
|
||||
"emoji": "Emoji",
|
||||
"end_time": "Endzeit",
|
||||
"error": "Fehler",
|
||||
"export": "Exportieren",
|
||||
"feature_flags": "Funktionen",
|
||||
@ -176,11 +180,13 @@
|
||||
},
|
||||
"id": "Id",
|
||||
"import": "Importieren",
|
||||
"interval": "Interval",
|
||||
"joined_at": "Beigetreten am",
|
||||
"last_name": "Nachname",
|
||||
"leaved_at": "Verlassen am",
|
||||
"left_server": "Aktiv",
|
||||
"level": "Level",
|
||||
"location": "Ort",
|
||||
"message_id": "Nachricht Id",
|
||||
"min_xp": "Min. XP",
|
||||
"modified_at": "Bearbeitet am",
|
||||
@ -200,10 +206,12 @@
|
||||
"role": "Rolle",
|
||||
"rule_count": "Regeln",
|
||||
"save": "Speichern",
|
||||
"start_time": "Startzeit",
|
||||
"state": {
|
||||
"off": "Aus",
|
||||
"on": "Ein"
|
||||
},
|
||||
"type": "Typ",
|
||||
"user_warnings": "Verwarnungen",
|
||||
"users": "Benutzer",
|
||||
"value": "Wert",
|
||||
@ -538,6 +546,33 @@
|
||||
"reaction_count": "Anzahl Reaktionen",
|
||||
"xp": "XP"
|
||||
},
|
||||
"scheduled_events": {
|
||||
"edit_dialog": {
|
||||
"add_header": "Event hinzufügen",
|
||||
"edit_header": "Event bearbeiten",
|
||||
"event_info": {
|
||||
"description_input": "Erzähl den Leuten ein wenig mehr über dein Event. Markdown, neue Zeilen und Links werden unterstützt.",
|
||||
"event_topic": "Thema",
|
||||
"event_topic_input": "Worum geht es bei deinem Event?",
|
||||
"header": "Worum geht es bei deinem Event?",
|
||||
"start_date": "Startdatum",
|
||||
"start_time": "Startzeit",
|
||||
"tab_name": "Eventinformationen"
|
||||
},
|
||||
"location": {
|
||||
"header": "Wo ist dein Event?",
|
||||
"somewhere_else": "Irgendwo anders",
|
||||
"somewhere_else_input": "Ort eingeben",
|
||||
"stage": "Stage-Kanal",
|
||||
"stage_input": "Stage-Kanal auswählen",
|
||||
"tab_name": "Verzeichnis",
|
||||
"voice": "Sprachkanal",
|
||||
"voice_input": "Sprachkanal auswählen"
|
||||
}
|
||||
},
|
||||
"header": "Geplante Events",
|
||||
"scheduled_events": "Geplante Events"
|
||||
},
|
||||
"short_role_names": {
|
||||
"header": "Rollen Kürzel",
|
||||
"message": {
|
||||
|
@ -124,12 +124,14 @@
|
||||
},
|
||||
"common": {
|
||||
"404": "404 - Entry not found!",
|
||||
"abort": "Abort",
|
||||
"actions": "Actions",
|
||||
"active": "Active",
|
||||
"add": "Add",
|
||||
"attribute": "Attribute",
|
||||
"auth_role": "Role",
|
||||
"author": "Author",
|
||||
"back": "Back",
|
||||
"bool_as_string": {
|
||||
"false": "No",
|
||||
"true": "Yes"
|
||||
@ -137,6 +139,7 @@
|
||||
"channel_id": "Channel Id",
|
||||
"channel_name": "Channel",
|
||||
"color": "Color",
|
||||
"continue": "Continue",
|
||||
"created_at": "Created at",
|
||||
"description": "Description",
|
||||
"discord_id": "Discord Id",
|
||||
@ -538,6 +541,33 @@
|
||||
"reaction_count": "Reaction count",
|
||||
"xp": "XP"
|
||||
},
|
||||
"scheduled_events": {
|
||||
"edit_dialog": {
|
||||
"add_header": "Add event",
|
||||
"edit_header": "Edit event",
|
||||
"event_info": {
|
||||
"description_input": "Tell people a little more about your event. Markdown, new lines and links are supported.",
|
||||
"event_topic": "Event topic",
|
||||
"event_topic_input": "What's your event?",
|
||||
"header": "What's your event about?",
|
||||
"start_date": "Start date",
|
||||
"start_time": "Start time",
|
||||
"tab_name": "Event info"
|
||||
},
|
||||
"location": {
|
||||
"header": "Where is your event?",
|
||||
"somewhere_else": "Somewhere else",
|
||||
"somewhere_else_input": "Enter a location",
|
||||
"stage": "Stage channel",
|
||||
"stage_input": "Select a stage channel",
|
||||
"tab_name": "Location",
|
||||
"voice": "Voice channel",
|
||||
"voice_input": "Select a voice channel"
|
||||
}
|
||||
},
|
||||
"header": "Scheduled events",
|
||||
"scheduled_events": "Scheduled events"
|
||||
},
|
||||
"short_role_names": {
|
||||
"header": "Level",
|
||||
"message": {
|
||||
|
@ -635,6 +635,18 @@ footer {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.btn,
|
||||
.icon-btn,
|
||||
.text-btn,
|
||||
.danger-btn,
|
||||
.danger-icon-btn {
|
||||
span {
|
||||
transition-duration: unset !important;
|
||||
}
|
||||
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.spinner-component-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -661,6 +673,27 @@ p-inputNumber {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.edit-dialog {
|
||||
.p-dialog-content {
|
||||
padding: 0 !important;
|
||||
|
||||
.p-tabview-nav {
|
||||
justify-content: space-between;
|
||||
|
||||
li {
|
||||
width: 100%;
|
||||
|
||||
a {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
footer {
|
||||
.left,
|
||||
|
@ -552,6 +552,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.danger-btn,
|
||||
.danger-icon-btn {
|
||||
background-color: transparent !important;
|
||||
color: $primaryTextColor !important;
|
||||
@ -568,22 +569,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.danger-btn {
|
||||
background-color: $primaryErrorColor !important;
|
||||
color: $primaryErrorColor !important;
|
||||
border: 0 !important;
|
||||
|
||||
&:hover {
|
||||
background-color: $primaryErrorColor !important;
|
||||
color: $primaryTextColor !important;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.pi {
|
||||
font-size: 1.275rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.p-datatable .p-sortable-column.p-highlight,
|
||||
.p-datatable .p-sortable-column.p-highlight .p-sortable-column-icon,
|
||||
.p-datatable .p-sortable-column:not(.p-highlight):hover {
|
||||
@ -777,4 +762,26 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit-dialog {
|
||||
.p-dialog-content {
|
||||
.p-tabview {
|
||||
.p-tabview-nav li .p-tabview-nav-link:not(.p-disabled):focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.p-tabview-nav li.p-highlight .p-tabview-nav-link {
|
||||
color: $primaryHeaderColor !important;
|
||||
border-color: $primaryHeaderColor !important;
|
||||
}
|
||||
|
||||
.p-tabview-nav,
|
||||
.p-tabview-nav li .p-tabview-nav-link,
|
||||
.p-tabview-panels {
|
||||
background-color: $secondaryBackgroundColor !important;
|
||||
color: $primaryTextColor !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user