add invites
This commit is contained in:
parent
3e02cbb353
commit
c8a10eb73c
@ -23,6 +23,7 @@ import {UserComponent} from './pages/user/user.component'
|
|||||||
import {JitsiComponent} from './pages/jitsi/jitsi.component'
|
import {JitsiComponent} from './pages/jitsi/jitsi.component'
|
||||||
import {AliasesComponent} from './pages/account/aliases/aliases.component';
|
import {AliasesComponent} from './pages/account/aliases/aliases.component';
|
||||||
import {DomainsComponent} from './pages/account/domains/domains.component';
|
import {DomainsComponent} from './pages/account/domains/domains.component';
|
||||||
|
import {InvitesComponent} from './pages/invites/invites.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{path: '', redirectTo: "/services", pathMatch: 'full'},
|
{path: '', redirectTo: "/services", pathMatch: 'full'},
|
||||||
@ -50,6 +51,7 @@ const routes: Routes = [
|
|||||||
{path: 'register', component: RegisterComponent, canActivate: [AnonymousGuard]},
|
{path: 'register', component: RegisterComponent, canActivate: [AnonymousGuard]},
|
||||||
{path: 'tokens', component: TokensComponent, canActivate: [AuthGuard]},
|
{path: 'tokens', component: TokensComponent, canActivate: [AuthGuard]},
|
||||||
{path: 'jitsi', component: JitsiComponent, canActivate: [AuthenticatedGuard]},
|
{path: 'jitsi', component: JitsiComponent, canActivate: [AuthenticatedGuard]},
|
||||||
|
{path: 'invites/:quota', component: InvitesComponent, canActivate: [AuthenticatedGuard]},
|
||||||
{path: 'unavailable', component: UnavailableComponent},
|
{path: 'unavailable', component: UnavailableComponent},
|
||||||
{path: 'p/:username', component: UserComponent, canActivate: [AuthUpdateGuard]},
|
{path: 'p/:username', component: UserComponent, canActivate: [AuthUpdateGuard]},
|
||||||
{path: '**', component: NotfoundComponent, pathMatch: 'full', canActivate: [AuthUpdateGuard]},
|
{path: '**', component: NotfoundComponent, pathMatch: 'full', canActivate: [AuthUpdateGuard]},
|
||||||
|
@ -19,6 +19,7 @@ import {LoginTotpComponent} from './pages/login-totp/login-totp.component';
|
|||||||
import {FormLoginComponent} from './pages/form-login/form-login.component';
|
import {FormLoginComponent} from './pages/form-login/form-login.component';
|
||||||
import {FormLoginTotpComponent} from './pages/form-login-totp/form-login-totp.component';
|
import {FormLoginTotpComponent} from './pages/form-login-totp/form-login-totp.component';
|
||||||
import {TokensComponent} from './pages/tokens/tokens.component';
|
import {TokensComponent} from './pages/tokens/tokens.component';
|
||||||
|
import {InvitesComponent} from './pages/invites/invites.component';
|
||||||
import {PermissionsComponent} from './ui/permissions/permissions.component';
|
import {PermissionsComponent} from './ui/permissions/permissions.component';
|
||||||
import {ProfileFieldDialog, ProfileFieldsComponent, ProfileFieldBlob} from './ui/profilefields/profilefields.component';
|
import {ProfileFieldDialog, ProfileFieldsComponent, ProfileFieldBlob} from './ui/profilefields/profilefields.component';
|
||||||
import {QuotasComponent} from './ui/quotas/quotas.component';
|
import {QuotasComponent} from './ui/quotas/quotas.component';
|
||||||
@ -70,6 +71,7 @@ export class XhrInterceptor implements HttpInterceptor {
|
|||||||
FormLoginComponent,
|
FormLoginComponent,
|
||||||
FormLoginTotpComponent,
|
FormLoginTotpComponent,
|
||||||
TokensComponent,
|
TokensComponent,
|
||||||
|
InvitesComponent,
|
||||||
ServicesComponent,
|
ServicesComponent,
|
||||||
PermissionsComponent,
|
PermissionsComponent,
|
||||||
ProfileFieldsComponent, ProfileFieldDialog, ProfileFieldBlob,
|
ProfileFieldsComponent, ProfileFieldDialog, ProfileFieldBlob,
|
||||||
|
63
src/app/pages/invites/invites.component.html
Normal file
63
src/app/pages/invites/invites.component.html
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<h3>{{'invites' | i18n}}</h3>
|
||||||
|
|
||||||
|
<table mat-table matSort [dataSource]="invites">
|
||||||
|
|
||||||
|
<ng-container matColumnDef="starts">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'invite.starts' | i18n}} </th>
|
||||||
|
<td mat-cell *matCellDef="let invite"> {{ invite.starts | date:datetimeformat}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="expires">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'invite.expires' | i18n}} </th>
|
||||||
|
<td mat-cell *matCellDef="let invite"> {{ invite.expires | date:datetimeformat}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
|
||||||
|
<ng-container matColumnDef="link">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'invite.link' | i18n}} </th>
|
||||||
|
<td mat-cell *matCellDef="let invite"> <a href="{{ invite.codeLink}}" target="_blank" mat-button color="accent">
|
||||||
|
{{
|
||||||
|
invite.code}}</a> </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="note">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'invite.note' | i18n}} </th>
|
||||||
|
<td mat-cell *matCellDef="let invite"> {{ invite.note}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="inviteColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let myRowData; columns: inviteColumns"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-card>
|
||||||
|
<mat-card-content>
|
||||||
|
<p>{{'invites.info' | i18n}}</p>
|
||||||
|
<p *ngIf="!inviteQuota">{{'invites.noQuota' | i18n}}</p>
|
||||||
|
<div *ngIf="inviteQuota">
|
||||||
|
<p>{{'invites.left' | i18n:inviteQuota}}</p>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
<mat-card-actions>
|
||||||
|
<button *ngIf="inviteQuota && !working" mat-raised-button color="primary" (click)="create()">
|
||||||
|
{{'invite.create' | i18n}}
|
||||||
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
||||||
|
|
||||||
|
<div *ngIf="others && others.content">
|
||||||
|
<h4>{{'invites.others' | i18n}}</h4>
|
||||||
|
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput [formControl]="searchFormControl" placeholder="{{'invites.search' | i18n}}">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<table mat-table matSort [dataSource]="others.content">
|
||||||
|
<ng-container matColumnDef="note">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'invite.note' | i18n}} </th>
|
||||||
|
<td mat-cell *matCellDef="let invite"> {{ invite.note}} </td>
|
||||||
|
</ng-container>
|
||||||
|
<tr mat-header-row *matHeaderRowDef="otherColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let myRowData; columns: otherColumns"></tr>
|
||||||
|
</table>
|
||||||
|
<mat-paginator [pageSizeOptions]="pageSizeOptions" [length]="others.totalElements" [pageSize]="others.size" (page)="updateOthers($event)" showFirstLastButtons></mat-paginator>
|
||||||
|
</div>
|
3
src/app/pages/invites/invites.component.scss
Normal file
3
src/app/pages/invites/invites.component.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mat-form-field {
|
||||||
|
display: block;
|
||||||
|
}
|
25
src/app/pages/invites/invites.component.spec.ts
Normal file
25
src/app/pages/invites/invites.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { InvitesComponent } from './invites.component';
|
||||||
|
|
||||||
|
describe('InvitesComponent', () => {
|
||||||
|
let component: InvitesComponent;
|
||||||
|
let fixture: ComponentFixture<InvitesComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ InvitesComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(InvitesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
99
src/app/pages/invites/invites.component.ts
Normal file
99
src/app/pages/invites/invites.component.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import {Component, OnInit, ViewChild} from '@angular/core';
|
||||||
|
|
||||||
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
|
import {PageEvent} from '@angular/material/paginator';
|
||||||
|
|
||||||
|
import {AuthService} from '../../services/auth.service';
|
||||||
|
import {I18nService} from '../../services/i18n.service';
|
||||||
|
import {QuotaService} from '../../services/quota.service';
|
||||||
|
import {InviteService} from '../../services/invites.service';
|
||||||
|
import {FormControl} from '@angular/forms';
|
||||||
|
import {debounceTime} from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-invites',
|
||||||
|
templateUrl: './invites.component.html',
|
||||||
|
styleUrls: ['./invites.component.scss']
|
||||||
|
})
|
||||||
|
export class InvitesComponent implements OnInit {
|
||||||
|
|
||||||
|
quota: string;
|
||||||
|
invites: any[];
|
||||||
|
others: any;
|
||||||
|
inviteQuota: number = 0;
|
||||||
|
success: boolean;
|
||||||
|
working: boolean;
|
||||||
|
datetimeformat: string;
|
||||||
|
pageSizeOptions: number[] = [5, 10, 25, 50];
|
||||||
|
searchFormControl = new FormControl();
|
||||||
|
|
||||||
|
inviteColumns = ["starts", "expires", "link", "note"];
|
||||||
|
otherColumns = ["note"];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private authService: AuthService,
|
||||||
|
private inviteService: InviteService,
|
||||||
|
private i18n: I18nService,
|
||||||
|
private quotaService: QuotaService,
|
||||||
|
private router: Router,
|
||||||
|
private route: ActivatedRoute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
this.datetimeformat = this.i18n.get('format.datetime', []);
|
||||||
|
this.quota = this.route.snapshot.paramMap.get('quota');
|
||||||
|
this.searchFormControl.valueChanges.pipe(debounceTime(500)).subscribe(value => {
|
||||||
|
|
||||||
|
this.inviteService.getOthersPages(this.quota, 0, this.others.size, value).subscribe((data: any) => {
|
||||||
|
this.others = data;
|
||||||
|
}, (error) => {})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update(): void {
|
||||||
|
this.inviteQuota = 0;
|
||||||
|
this.quotaService.quotas().subscribe((data: any) => {
|
||||||
|
for(let quota of data) {
|
||||||
|
if(quota.name == "invite_" + this.quota) {
|
||||||
|
this.inviteQuota = quota.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.inviteService.get(this.quota).subscribe((data: any) => {
|
||||||
|
this.invites = data;
|
||||||
|
})
|
||||||
|
|
||||||
|
this.inviteService.getOthers(this.quota).subscribe((data: any) => {
|
||||||
|
this.others = data;
|
||||||
|
}, (error) => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
create(): void {
|
||||||
|
this.working = true;
|
||||||
|
|
||||||
|
|
||||||
|
this.inviteService.create(this.quota, {}).subscribe(response => {
|
||||||
|
this.update();
|
||||||
|
this.working = false;
|
||||||
|
}, (error) => {
|
||||||
|
this.working = false;
|
||||||
|
if(error.status == 409) {
|
||||||
|
let errors = {};
|
||||||
|
for(let code of error.error) {
|
||||||
|
errors[code.field] = errors[code.field] || {};
|
||||||
|
errors[code.field][code.code] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOthers(event: PageEvent) {
|
||||||
|
this.inviteService.getOthersPages(this.quota, event.pageIndex, event.pageSize, "").subscribe((data: any) => {
|
||||||
|
this.others = data;
|
||||||
|
}, (error) => {})
|
||||||
|
}
|
||||||
|
}
|
@ -2,24 +2,34 @@
|
|||||||
|
|
||||||
<p *ngIf="!services || services.length == 0">{{'services.empty' | i18n}}</p>
|
<p *ngIf="!services || services.length == 0">{{'services.empty' | i18n}}</p>
|
||||||
|
|
||||||
<div fxLayout="row wrap" fxLayoutGap="16px grid">
|
|
||||||
<div fxFlex="33.33%" fxFlex.sm="50%" fxFlex.xs="100%" *ngFor="let service of services">
|
<table *ngIf="services && services.length > 0" mat-table matSort [dataSource]="services" (matSortChange)="sortData($event)" matSortActive="name" matSortDirection="desc">
|
||||||
<mat-card>
|
|
||||||
<mat-card-header>
|
<ng-container matColumnDef="icon">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> </th>
|
||||||
|
<td mat-cell *matCellDef="let service">
|
||||||
<mat-icon>{{'services.' + service.name + '.icon' | i18n}}</mat-icon>
|
<mat-icon>{{'services.' + service.name + '.icon' | i18n}}</mat-icon>
|
||||||
<mat-card-title>{{'services.' + service.name + '.title' | i18n}}</mat-card-title>
|
</td>
|
||||||
<mat-card-subtitle>{{'services.' + service.name + '.subtitle' | i18n}}</mat-card-subtitle>
|
</ng-container>
|
||||||
</mat-card-header>
|
|
||||||
<mat-card-content>
|
|
||||||
<p>
|
<ng-container matColumnDef="name">
|
||||||
{{ 'services.' + service.name + '.text' | i18n}}
|
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'service.name' | i18n}} </th>
|
||||||
</p>
|
<td mat-cell *matCellDef="let service" class="text-center">
|
||||||
</mat-card-content>
|
<a href="{{service.url}}" [target]="service.sameSite ? '_self' : '_blank'" mat-button color="accent">
|
||||||
<mat-card-actions>
|
<strong>{{'services.' + service.name + '.title' | i18n}}</strong>
|
||||||
<a href="{{service.url}}" [target]="service.sameSite ? '_self' : '_blank'" mat-raised-button
|
<mat-icon *ngIf="!service.sameSite" inline="true">
|
||||||
color="accent">{{'services.goto' | i18n}} <mat-icon *ngIf="!service.sameSite" inline="true">
|
open_in_new</mat-icon>
|
||||||
open_in_new</mat-icon></a>
|
</a>
|
||||||
</mat-card-actions>
|
<div><small>{{'services.' + service.name + '.subtitle' | i18n}}</small></div>
|
||||||
</mat-card>
|
</td>
|
||||||
</div>
|
</ng-container>
|
||||||
</div>
|
|
||||||
|
<ng-container matColumnDef="text">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'service.text' | i18n}} </th>
|
||||||
|
<td mat-cell *matCellDef="let service">{{ 'services.' + service.name + '.text' | i18n}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="serviceColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let myRowData; columns: serviceColumns"></tr>
|
||||||
|
</table>
|
@ -1,5 +1,7 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
|
import {Sort} from '@angular/material/sort';
|
||||||
import {ServiceService} from '../../services/service.service';
|
import {ServiceService} from '../../services/service.service';
|
||||||
|
import {I18nService} from '../../services/i18n.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-services',
|
selector: 'app-services',
|
||||||
@ -9,13 +11,34 @@ import { ServiceService } from '../../services/service.service';
|
|||||||
export class ServicesComponent implements OnInit {
|
export class ServicesComponent implements OnInit {
|
||||||
|
|
||||||
services = [];
|
services = [];
|
||||||
|
serviceColumns = ["icon", "name", "text"];
|
||||||
|
|
||||||
constructor(private serviceService: ServiceService) { }
|
constructor(private serviceService: ServiceService, private i18n: I18nService) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.serviceService.services().subscribe((data: any) => {
|
this.serviceService.services().subscribe((data: any) => {
|
||||||
this.services = data;
|
this.services = data;
|
||||||
|
this.sortData({"active": "name", "direction": "desc"});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sortData(sort: Sort) {
|
||||||
|
const data = this.services.slice();
|
||||||
|
if(!sort.active || sort.direction === '') {
|
||||||
|
this.services = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.services = data.sort((a, b) => {
|
||||||
|
const isAsc = sort.direction === 'asc';
|
||||||
|
switch(sort.active) {
|
||||||
|
case 'name': return this.compare(this.i18n.get('services.' + a.name + '.title', []), this.i18n.get('services.' + b.name + '.title', []), isAsc);
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
compare(a: number | string | String, b: number | string | String, isAsc: boolean) {
|
||||||
|
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
35
src/app/services/invites.service.ts
Normal file
35
src/app/services/invites.service.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
|
||||||
|
import {environment} from '../../environments/environment';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class InviteService {
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {
|
||||||
|
}
|
||||||
|
|
||||||
|
get(quota: string) {
|
||||||
|
return this.http.get(environment.apiUrl + "/invites" + (quota ? "?quota=" + quota : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getOthers(quota: string) {
|
||||||
|
return this.http.get(environment.apiUrl + "/invites/" + quota + "/others");
|
||||||
|
}
|
||||||
|
|
||||||
|
getOthersPages(quota: string, page : number, size : number, search : string) {
|
||||||
|
return this.http.get(environment.apiUrl + "/invites/" + quota + "/others?page=" + page + "&size=" + size + "&search=" + search);
|
||||||
|
}
|
||||||
|
|
||||||
|
create(quota: string, invite: any) {
|
||||||
|
return this.http.post(environment.apiUrl + "/invites/" + quota, invite);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(invite: any) {
|
||||||
|
return this.http.post(environment.apiUrl + "/invites", invite);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
<table mat-table matSort [dataSource]="profileFields" (matSortChange)="sortData($event)" matSortActive="index"
|
<table mat-table matSort [dataSource]="profileFields" (matSortChange)="sortData($event)" matSortActive="index" matSortDirection="asc">
|
||||||
matSortDirection="asc">
|
|
||||||
|
|
||||||
<ng-container matColumnDef="name">
|
<ng-container matColumnDef="name">
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'profileField.name' | i18n}} </th>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'profileField.name' | i18n}} </th>
|
||||||
@ -15,11 +14,9 @@
|
|||||||
<span *ngSwitchCase="'DATETIME'">{{profileField.value | date:datetimeformat}}</span>
|
<span *ngSwitchCase="'DATETIME'">{{profileField.value | date:datetimeformat}}</span>
|
||||||
<span *ngSwitchCase="'TIME'">{{profileField.value | date:timeformat}}</span>
|
<span *ngSwitchCase="'TIME'">{{profileField.value | date:timeformat}}</span>
|
||||||
<a *ngSwitchCase="'URL'" class="accent" href="{{profileField.value}}">{{profileField.value}}</a>
|
<a *ngSwitchCase="'URL'" class="accent" href="{{profileField.value}}">{{profileField.value}}</a>
|
||||||
<a *ngSwitchCase="'EMAIL'" class="accent"
|
<a *ngSwitchCase="'EMAIL'" class="accent" href="mailto:{{profileField.value}}">{{profileField.value}}</a>
|
||||||
href="mailto:{{profileField.value}}">{{profileField.value}}</a>
|
|
||||||
<span *ngSwitchCase="'NUMBER'">{{profileField.value}}</span>
|
<span *ngSwitchCase="'NUMBER'">{{profileField.value}}</span>
|
||||||
<button *ngSwitchCase="'BLOB'" mat-raised-buttonu
|
<button *ngSwitchCase="'BLOB'" mat-raised-button (click)="openBlob(profileField)">{{'profileField.openBlob' | i18n}}</button>
|
||||||
(click)="openBlob(profileField)">{{'profileField.openBlob' | i18n}}</button>
|
|
||||||
<mat-slide-toggle *ngSwitchCase="'BOOL'" [checked]="profileField.value == 'true'" disabled>
|
<mat-slide-toggle *ngSwitchCase="'BOOL'" [checked]="profileField.value == 'true'" disabled>
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,6 +27,21 @@
|
|||||||
"info": {
|
"info": {
|
||||||
".": "Info"
|
".": "Info"
|
||||||
},
|
},
|
||||||
|
"invite": {
|
||||||
|
".": "Einleidung",
|
||||||
|
"create": "Einladung erstellen",
|
||||||
|
"expires": "Gültig bis",
|
||||||
|
"link": "Link",
|
||||||
|
"note": "Notiz",
|
||||||
|
"starts": "Gültig ab"
|
||||||
|
},
|
||||||
|
"invites": {
|
||||||
|
".": "Einladungen",
|
||||||
|
"info": "Hier kannst du neue Einladungen erstellen. Um die Einladung zu bearbeiten klicke einfach auf den Link. Wenn du authoriziert bist, kannst du dort direkt den persönlichen Einladungstext bearbeiten oder eine Notiz hinzufügen.",
|
||||||
|
"left": "Du kannst noch {0} Einladungen erstellen.",
|
||||||
|
"others": "Einladungen anderer Mitglieder",
|
||||||
|
"search": "Suche"
|
||||||
|
},
|
||||||
"jitsi": {
|
"jitsi": {
|
||||||
"rooms": {
|
"rooms": {
|
||||||
".": "Jitsi Räume",
|
".": "Jitsi Räume",
|
||||||
@ -286,6 +301,10 @@
|
|||||||
"support": "Support",
|
"support": "Support",
|
||||||
"text": "Zurzeit scheint der Dienst nicht erreichbar zu sein. Wenn diese Meldung länger besteht, melde dich beim Support!"
|
"text": "Zurzeit scheint der Dienst nicht erreichbar zu sein. Wenn diese Meldung länger besteht, melde dich beim Support!"
|
||||||
},
|
},
|
||||||
|
"service": {
|
||||||
|
"name": "Name",
|
||||||
|
"text": "Beschreibung"
|
||||||
|
},
|
||||||
"services": {
|
"services": {
|
||||||
".": "Dienste",
|
".": "Dienste",
|
||||||
"alias_creation": {
|
"alias_creation": {
|
||||||
@ -302,6 +321,12 @@
|
|||||||
"title": "Gitea"
|
"title": "Gitea"
|
||||||
},
|
},
|
||||||
"goto": "Zum Dienst",
|
"goto": "Zum Dienst",
|
||||||
|
"invite_partey": {
|
||||||
|
"icon": "cake",
|
||||||
|
"subtitle": "Einladung zur Partey",
|
||||||
|
"text": "Hier kannst du Einladungen für die Eröffnungs-Partey erstellen.",
|
||||||
|
"title": "Partey-Einladung"
|
||||||
|
},
|
||||||
"jitsi": {
|
"jitsi": {
|
||||||
"icon": "video_call",
|
"icon": "video_call",
|
||||||
"subtitle": "Video Konferenzen",
|
"subtitle": "Video Konferenzen",
|
||||||
@ -320,6 +345,12 @@
|
|||||||
"text": "mit anderen Austauschen, sich Informieren oder einfach quatschen.",
|
"text": "mit anderen Austauschen, sich Informieren oder einfach quatschen.",
|
||||||
"title": "Matrix"
|
"title": "Matrix"
|
||||||
},
|
},
|
||||||
|
"monitoring": {
|
||||||
|
"icon": "check",
|
||||||
|
"subtitle": "System Status",
|
||||||
|
"text": "Status und Perfomance der aktuellen Systeme",
|
||||||
|
"title": "Monitoring"
|
||||||
|
},
|
||||||
"nextcloud": {
|
"nextcloud": {
|
||||||
"icon": "cloud",
|
"icon": "cloud",
|
||||||
"subtitle": "Cloud Plattform",
|
"subtitle": "Cloud Plattform",
|
||||||
|
@ -27,6 +27,21 @@
|
|||||||
"info": {
|
"info": {
|
||||||
".": "Info"
|
".": "Info"
|
||||||
},
|
},
|
||||||
|
"invite": {
|
||||||
|
".": "Invite",
|
||||||
|
"create": "Create Invite",
|
||||||
|
"expires": "Expires",
|
||||||
|
"link": "Link",
|
||||||
|
"note": "Note",
|
||||||
|
"starts": "Starts"
|
||||||
|
},
|
||||||
|
"invites": {
|
||||||
|
".": "Invites",
|
||||||
|
"info": "You can create new invites here. To edit an invite like adding a note or change the personal invite message just click on the invite link. If you are authorized, you can change the texts directly on the invite page.",
|
||||||
|
"left": "You have {0} invites left.",
|
||||||
|
"others": "Other's invites",
|
||||||
|
"search": "Search"
|
||||||
|
},
|
||||||
"jitsi": {
|
"jitsi": {
|
||||||
"rooms": {
|
"rooms": {
|
||||||
".": "Jitsi Rooms",
|
".": "Jitsi Rooms",
|
||||||
@ -273,6 +288,10 @@
|
|||||||
"support": "Support",
|
"support": "Support",
|
||||||
"text": "The service seems currently unavailable. If this message appears over a longer period, please contact our support!"
|
"text": "The service seems currently unavailable. If this message appears over a longer period, please contact our support!"
|
||||||
},
|
},
|
||||||
|
"service": {
|
||||||
|
"name": "Name",
|
||||||
|
"text": "Description"
|
||||||
|
},
|
||||||
"services": {
|
"services": {
|
||||||
".": "Services",
|
".": "Services",
|
||||||
"alias_creation": {
|
"alias_creation": {
|
||||||
@ -289,6 +308,12 @@
|
|||||||
"title": "Gitea"
|
"title": "Gitea"
|
||||||
},
|
},
|
||||||
"goto": "To service",
|
"goto": "To service",
|
||||||
|
"invite_partey": {
|
||||||
|
"icon": "cake",
|
||||||
|
"subtitle": "Invite to Partey",
|
||||||
|
"text": "Create Invites for Opening Partey.",
|
||||||
|
"title": "Partey-Invites"
|
||||||
|
},
|
||||||
"jitsi": {
|
"jitsi": {
|
||||||
"icon": "video_call",
|
"icon": "video_call",
|
||||||
"subtitle": "Video conferencing",
|
"subtitle": "Video conferencing",
|
||||||
@ -307,6 +332,12 @@
|
|||||||
"text": "talk, exchange, discuss with others",
|
"text": "talk, exchange, discuss with others",
|
||||||
"title": "Matrix"
|
"title": "Matrix"
|
||||||
},
|
},
|
||||||
|
"monitoring": {
|
||||||
|
"icon": "check",
|
||||||
|
"subtitle": "System Status",
|
||||||
|
"text": "Status and perfomance of current systems",
|
||||||
|
"title": "Monitoring"
|
||||||
|
},
|
||||||
"nextcloud": {
|
"nextcloud": {
|
||||||
"icon": "cloud",
|
"icon": "cloud",
|
||||||
"subtitle": "Cloud service",
|
"subtitle": "Cloud service",
|
||||||
|
Loading…
Reference in New Issue
Block a user