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 {AliasesComponent} from './pages/account/aliases/aliases.component';
|
||||
import {DomainsComponent} from './pages/account/domains/domains.component';
|
||||
import {InvitesComponent} from './pages/invites/invites.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{path: '', redirectTo: "/services", pathMatch: 'full'},
|
||||
@ -50,13 +51,14 @@ const routes: Routes = [
|
||||
{path: 'register', component: RegisterComponent, canActivate: [AnonymousGuard]},
|
||||
{path: 'tokens', component: TokensComponent, canActivate: [AuthGuard]},
|
||||
{path: 'jitsi', component: JitsiComponent, canActivate: [AuthenticatedGuard]},
|
||||
{path: 'invites/:quota', component: InvitesComponent, canActivate: [AuthenticatedGuard]},
|
||||
{path: 'unavailable', component: UnavailableComponent},
|
||||
{path: 'p/:username', component: UserComponent, canActivate: [AuthUpdateGuard]},
|
||||
{path: '**', component: NotfoundComponent, pathMatch: 'full', canActivate: [AuthUpdateGuard]},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload', relativeLinkResolution: 'legacy' })],
|
||||
imports: [RouterModule.forRoot(routes, {onSameUrlNavigation: 'reload', relativeLinkResolution: 'legacy'})],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
|
@ -19,6 +19,7 @@ import {LoginTotpComponent} from './pages/login-totp/login-totp.component';
|
||||
import {FormLoginComponent} from './pages/form-login/form-login.component';
|
||||
import {FormLoginTotpComponent} from './pages/form-login-totp/form-login-totp.component';
|
||||
import {TokensComponent} from './pages/tokens/tokens.component';
|
||||
import {InvitesComponent} from './pages/invites/invites.component';
|
||||
import {PermissionsComponent} from './ui/permissions/permissions.component';
|
||||
import {ProfileFieldDialog, ProfileFieldsComponent, ProfileFieldBlob} from './ui/profilefields/profilefields.component';
|
||||
import {QuotasComponent} from './ui/quotas/quotas.component';
|
||||
@ -70,6 +71,7 @@ export class XhrInterceptor implements HttpInterceptor {
|
||||
FormLoginComponent,
|
||||
FormLoginTotpComponent,
|
||||
TokensComponent,
|
||||
InvitesComponent,
|
||||
ServicesComponent,
|
||||
PermissionsComponent,
|
||||
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>
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="16px grid">
|
||||
<div fxFlex="33.33%" fxFlex.sm="50%" fxFlex.xs="100%" *ngFor="let service of services">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
|
||||
<table *ngIf="services && services.length > 0" mat-table matSort [dataSource]="services" (matSortChange)="sortData($event)" matSortActive="name" matSortDirection="desc">
|
||||
|
||||
<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-card-title>{{'services.' + service.name + '.title' | i18n}}</mat-card-title>
|
||||
<mat-card-subtitle>{{'services.' + service.name + '.subtitle' | i18n}}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>
|
||||
{{ 'services.' + service.name + '.text' | i18n}}
|
||||
</p>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<a href="{{service.url}}" [target]="service.sameSite ? '_self' : '_blank'" mat-raised-button
|
||||
color="accent">{{'services.goto' | i18n}} <mat-icon *ngIf="!service.sameSite" inline="true">
|
||||
open_in_new</mat-icon></a>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'service.name' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let service" class="text-center">
|
||||
<a href="{{service.url}}" [target]="service.sameSite ? '_self' : '_blank'" mat-button color="accent">
|
||||
<strong>{{'services.' + service.name + '.title' | i18n}}</strong>
|
||||
<mat-icon *ngIf="!service.sameSite" inline="true">
|
||||
open_in_new</mat-icon>
|
||||
</a>
|
||||
<div><small>{{'services.' + service.name + '.subtitle' | i18n}}</small></div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<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 { ServiceService } from '../../services/service.service';
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Sort} from '@angular/material/sort';
|
||||
import {ServiceService} from '../../services/service.service';
|
||||
import {I18nService} from '../../services/i18n.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-services',
|
||||
@ -9,13 +11,34 @@ import { ServiceService } from '../../services/service.service';
|
||||
export class ServicesComponent implements OnInit {
|
||||
|
||||
services = [];
|
||||
serviceColumns = ["icon", "name", "text"];
|
||||
|
||||
constructor(private serviceService: ServiceService) { }
|
||||
constructor(private serviceService: ServiceService, private i18n: I18nService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.serviceService.services().subscribe((data: any) => {
|
||||
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"
|
||||
matSortDirection="asc">
|
||||
<table mat-table matSort [dataSource]="profileFields" (matSortChange)="sortData($event)" matSortActive="index" matSortDirection="asc">
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<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="'TIME'">{{profileField.value | date:timeformat}}</span>
|
||||
<a *ngSwitchCase="'URL'" class="accent" href="{{profileField.value}}">{{profileField.value}}</a>
|
||||
<a *ngSwitchCase="'EMAIL'" class="accent"
|
||||
href="mailto:{{profileField.value}}">{{profileField.value}}</a>
|
||||
<a *ngSwitchCase="'EMAIL'" class="accent" href="mailto:{{profileField.value}}">{{profileField.value}}</a>
|
||||
<span *ngSwitchCase="'NUMBER'">{{profileField.value}}</span>
|
||||
<button *ngSwitchCase="'BLOB'" mat-raised-buttonu
|
||||
(click)="openBlob(profileField)">{{'profileField.openBlob' | i18n}}</button>
|
||||
<button *ngSwitchCase="'BLOB'" mat-raised-button (click)="openBlob(profileField)">{{'profileField.openBlob' | i18n}}</button>
|
||||
<mat-slide-toggle *ngSwitchCase="'BOOL'" [checked]="profileField.value == 'true'" disabled>
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
@ -27,6 +27,21 @@
|
||||
"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": {
|
||||
"rooms": {
|
||||
".": "Jitsi Räume",
|
||||
@ -35,7 +50,7 @@
|
||||
"delete": "Löschen",
|
||||
"error": {
|
||||
"expires": "Ungültiges Ende.",
|
||||
"moderationStarts" : "Ungültiger Beginn Moderation. Moderation muss vor Beginn liegen.",
|
||||
"moderationStarts": "Ungültiger Beginn Moderation. Moderation muss vor Beginn liegen.",
|
||||
"room": "Bitte gebe einen anderen Namen an. Der Name ist schon vergeben oder enthält ungültige Zeichen. Erlaubt sind nur Buchstaben und Zahlen.",
|
||||
"starts": "Ungültiger Beginn."
|
||||
},
|
||||
@ -43,9 +58,9 @@
|
||||
"info": "Du kannst hier Jitsi Räume erstellen. Die Anzahl wird über eine Quota begrenzt.",
|
||||
"left": "Du kannst noch {0} Jitsi Raum/Räume erstellen.",
|
||||
"moderationUrl": "Url für Moderation",
|
||||
"moderationStarts" : "Beginn Moderation",
|
||||
"moderationStarts": "Beginn Moderation",
|
||||
"noQuota": "Deine Quota für Jitsi Räume ist leider aufgebraucht.",
|
||||
"notStarted" : "Die Konferenz hat noch nicht begonnen.",
|
||||
"notStarted": "Die Konferenz hat noch nicht begonnen.",
|
||||
"room": "Name",
|
||||
"starts": "Beginn"
|
||||
},
|
||||
@ -60,12 +75,12 @@
|
||||
".": "Via E-Mail teilen",
|
||||
"subject": "Einladung in Videokonferenz {0}"
|
||||
},
|
||||
"text" : {
|
||||
"both" : "Die Konferenz beginnt am {0} und endet am {1}.",
|
||||
"expires" : "Die Konferenz endet am {0}.",
|
||||
"intro" : "Hallo, ich möchte dich zu einer Videokonferenz einladen.",
|
||||
"outro" : "Du kannst der Konferenz unter folgendem Link beitreten:\n {0}",
|
||||
"starts" : "Die Konferenz beginnt am {0}."
|
||||
"text": {
|
||||
"both": "Die Konferenz beginnt am {0} und endet am {1}.",
|
||||
"expires": "Die Konferenz endet am {0}.",
|
||||
"intro": "Hallo, ich möchte dich zu einer Videokonferenz einladen.",
|
||||
"outro": "Du kannst der Konferenz unter folgendem Link beitreten:\n {0}",
|
||||
"starts": "Die Konferenz beginnt am {0}."
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -286,6 +301,10 @@
|
||||
"support": "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": {
|
||||
".": "Dienste",
|
||||
"alias_creation": {
|
||||
@ -302,6 +321,12 @@
|
||||
"title": "Gitea"
|
||||
},
|
||||
"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": {
|
||||
"icon": "video_call",
|
||||
"subtitle": "Video Konferenzen",
|
||||
@ -320,6 +345,12 @@
|
||||
"text": "mit anderen Austauschen, sich Informieren oder einfach quatschen.",
|
||||
"title": "Matrix"
|
||||
},
|
||||
"monitoring": {
|
||||
"icon": "check",
|
||||
"subtitle": "System Status",
|
||||
"text": "Status und Perfomance der aktuellen Systeme",
|
||||
"title": "Monitoring"
|
||||
},
|
||||
"nextcloud": {
|
||||
"icon": "cloud",
|
||||
"subtitle": "Cloud Plattform",
|
||||
|
@ -27,6 +27,21 @@
|
||||
"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": {
|
||||
"rooms": {
|
||||
".": "Jitsi Rooms",
|
||||
@ -35,17 +50,17 @@
|
||||
"delete": "Delete",
|
||||
"error": {
|
||||
"expires": "Invalid expiry.",
|
||||
"moderationStarts" : "Invalid moderation starts. Moderation have to start before conference starts",
|
||||
"moderationStarts": "Invalid moderation starts. Moderation have to start before conference starts",
|
||||
"room": "Please choose a different name. The name is already taken or contains invalid characters. Only letters and numbers are allowed.",
|
||||
"starts": "Invalid start."
|
||||
},
|
||||
"expires": "Expires",
|
||||
"info": "You can create new Jitsi Rooms here. The number is limited due to a quota.",
|
||||
"left": "You have {0} Jitsi Room(s) left.",
|
||||
"moderationStarts" : "Moderation starts",
|
||||
"moderationStarts": "Moderation starts",
|
||||
"moderationUrl": "Moderation url",
|
||||
"noQuota": "Your quota for Jitsi Rooms is depleted.",
|
||||
"notStarted" : "The conference has not started yet.",
|
||||
"notStarted": "The conference has not started yet.",
|
||||
"room": "Name",
|
||||
"starts": "Starts"
|
||||
},
|
||||
@ -273,6 +288,10 @@
|
||||
"support": "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",
|
||||
"alias_creation": {
|
||||
@ -289,6 +308,12 @@
|
||||
"title": "Gitea"
|
||||
},
|
||||
"goto": "To service",
|
||||
"invite_partey": {
|
||||
"icon": "cake",
|
||||
"subtitle": "Invite to Partey",
|
||||
"text": "Create Invites for Opening Partey.",
|
||||
"title": "Partey-Invites"
|
||||
},
|
||||
"jitsi": {
|
||||
"icon": "video_call",
|
||||
"subtitle": "Video conferencing",
|
||||
@ -307,6 +332,12 @@
|
||||
"text": "talk, exchange, discuss with others",
|
||||
"title": "Matrix"
|
||||
},
|
||||
"monitoring": {
|
||||
"icon": "check",
|
||||
"subtitle": "System Status",
|
||||
"text": "Status and perfomance of current systems",
|
||||
"title": "Monitoring"
|
||||
},
|
||||
"nextcloud": {
|
||||
"icon": "cloud",
|
||||
"subtitle": "Cloud service",
|
||||
|
Loading…
Reference in New Issue
Block a user