diff --git a/api/routes/account.js b/api/routes/account.js
index 687ae7e..0d637c4 100644
--- a/api/routes/account.js
+++ b/api/routes/account.js
@@ -15,15 +15,17 @@ const account = new express.Router();
account.route('/')
.get((req, res, next) => {
- AppUserModel.find({}, {}, {sort: {username: 1}}).populate('squad').exec((err, items) => {
- if (err) {
- err.status = codes.servererror;
- return next(err);
- }
- res.locals.items = items;
- res.locals.processed = true;
- next();
- });
+ AppUserModel.find({}, {}, {sort: {username: 1}})
+ .populate('squad')
+ .exec((err, items) => {
+ if (err) {
+ err.status = codes.servererror;
+ return next(err);
+ }
+ res.locals.items = items;
+ res.locals.processed = true;
+ next();
+ });
})
.all(
routerHandling.httpMethodNotAllowed
@@ -31,33 +33,45 @@ account.route('/')
// routes **********************
account.route('/:id')
+ .get((req, res, next) => {
+ AppUserModel.findById(req.params.id)
+ .populate('squad')
+ .exec((err, item) => {
+ if (err) {
+ err.status = codes.servererror;
+ } else if (!item) {
+ err = new Error('item not found');
+ err.status = codes.notfound;
+ }
+ res.locals.items = item;
+ next(err);
+ });
+ })
+
.patch((req, res, next) => {
if (!req.body || (req.body._id && req.body._id !== req.params.id)) {
- // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match
- const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' +
- req.body._id);
+ const err = new Error(
+ 'id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + req.body._id);
err.status = codes.notfound;
- next(err);
- return; // prevent node to process this function further after next() has finished.
+ return next(err);
}
- // increment version manually as we do not use .save(.)
req.body.updatedAt = new Date();
req.body.$inc = {__v: 1};
- // PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to
- // reset attributes that are missing.
- AppUserModel.findByIdAndUpdate(req.params.id, req.body, {new: true}).populate('squad').exec((err, item) => {
- if (err) {
- err.status = codes.wrongrequest;
- } else if (!item) {
- err = new Error('appUser not found');
- err.status = codes.notfound;
- } else {
- res.locals.items = item;
- }
- next(err);
- });
+ AppUserModel.findByIdAndUpdate(req.params.id, req.body, {new: true})
+ .populate('squad')
+ .exec((err, item) => {
+ if (err) {
+ err.status = codes.wrongrequest;
+ } else if (!item) {
+ err = new Error('appUser not found');
+ err.status = codes.notfound;
+ } else {
+ res.locals.items = item;
+ }
+ next(err);
+ });
})
.delete((req, res, next) => {
@@ -68,10 +82,8 @@ account.route('/:id')
err = new Error('item not found');
err.status = codes.notfound;
}
- // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler
- // user.use(..)
res.locals.processed = true;
- next(err); // this works because err is in normal case undefined and that is the same as no parameter
+ next(err);
});
})
@@ -79,8 +91,6 @@ account.route('/:id')
routerHandling.httpMethodNotAllowed
);
-// this middleware function can be used, if you like or remove it
-// it looks for object(s) in res.locals.items and if they exist, they are send to the client as json
account.use(routerHandling.emptyResponse);
module.exports = account;
diff --git a/static/src/app/admin/admin.component.css b/static/src/app/admin/admin.component.css
index 722fd6e..e69de29 100644
--- a/static/src/app/admin/admin.component.css
+++ b/static/src/app/admin/admin.component.css
@@ -1,27 +0,0 @@
-.overview {
- padding-bottom: 50px!important;
-}
-
-.trash {
- cursor: pointer;
-}
-
-.table {
- overflow-wrap: break-word;
- table-layout: fixed;
-}
-
-.table-container {
- margin-top: 10px;
- overflow-x: auto;
- padding: 5px;
-}
-
-.table-head {
- background: #222222;
- color: white;
-}
-
-.cell-outline {
- outline: 1px solid #D4D4D4;
-}
diff --git a/static/src/app/admin/admin.component.html b/static/src/app/admin/admin.component.html
index 441a176..0680b43 100644
--- a/static/src/app/admin/admin.component.html
+++ b/static/src/app/admin/admin.component.html
@@ -1,65 +1 @@
-
-
-
Admin Panel
-
-
-
-
-
-
- Username
- Activated
- Secret
- Fraktion/ Squad
- Permission
-
-
-
-
-
-
- {{user.username}}
-
-
-
- activated
- deactivated
-
-
-
- {{user.secret}}
-
-
-
- Ohne Fraktion/ Squad
-
- {{squad.fraction == 'BLUFOR'? fraction.BLUFOR : fraction.OPFOR}}: {{squad.name}}
-
-
-
-
-
- User
- SQL
- HL
- MT
- Admin
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/static/src/app/admin/admin.component.ts b/static/src/app/admin/admin.component.ts
index 3269428..ddc9b5f 100644
--- a/static/src/app/admin/admin.component.ts
+++ b/static/src/app/admin/admin.component.ts
@@ -1,68 +1,11 @@
-import {Component, OnInit} from '@angular/core';
-import {AppUser, Squad} from '../models/model-interfaces';
-import {Observable} from 'rxjs/Observable';
-import {AppUserService} from '../services/app-user-service/app-user.service';
-import {SquadService} from '../services/army-management/squad.service';
-import {Fraction} from '../utils/fraction.enum';
-import {SnackBarService} from '../services/user-interface/snack-bar/snack-bar.service';
+import {Component} from '@angular/core';
@Component({
- selector: 'admin-panel',
+ selector: 'cc-admin-component',
templateUrl: './admin.component.html',
styleUrls: ['./admin.component.css', '../style/overview.css']
})
-export class AdminComponent implements OnInit {
-
- users$: Observable;
-
- squads: Squad[] = [];
-
- readonly fraction = Fraction;
-
- constructor(private appUserService: AppUserService,
- private squadService: SquadService,
- private snackBarService: SnackBarService) {
- }
-
- ngOnInit() {
- this.users$ = this.appUserService.getUsers();
- this.squadService.findSquads().subscribe(squads => {
- this.squads = squads;
- });
- }
-
- updateAppUser(user) {
- const updateObject = {
- _id: user._id,
- squad: user.squad,
- activated: user.activated,
- permission: user.permission
- };
-
- if (updateObject.squad === '0') {
- updateObject.squad = null;
- }
-
- this.appUserService.updateUser(updateObject)
- .subscribe(resUser => {
- this.snackBarService.showSuccess('generic.save.success');
- });
- }
-
- deleteUser(user) {
- if (confirm('Soll der Nutzer "' + user.username + '" wirklich gelöscht werden?')) {
- this.appUserService.deleteUser(user)
- .subscribe((res) => {
- });
- }
- }
-
- /**
- * compare ngValue with ngModel to assign selected element
- */
- equals(o1: Squad, o2: Squad) {
- if (o1 && o2) {
- return o1._id === o2._id;
- }
+export class AdminComponent {
+ constructor() {
}
}
diff --git a/static/src/app/admin/admin.module.ts b/static/src/app/admin/admin.module.ts
index 7e41389..3662c5a 100644
--- a/static/src/app/admin/admin.module.ts
+++ b/static/src/app/admin/admin.module.ts
@@ -1,14 +1,36 @@
import {NgModule} from '@angular/core';
-import {AdminComponent} from './admin.component';
import {SharedModule} from '../shared.module';
import {AppUserService} from '../services/app-user-service/app-user.service';
import {CommonModule} from '@angular/common';
-import {RouterModule} from '@angular/router';
+import {adminRouterModule, adminRoutingComponents} from './admin.routing';
+import {HttpClient} from '@angular/common/http';
+import {TranslateHttpLoader} from '@ngx-translate/http-loader';
+import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
+
+export function createTranslateLoader(http: HttpClient) {
+ return new TranslateHttpLoader(http, './assets/i18n/admin/', '.json');
+}
@NgModule({
- declarations: [AdminComponent],
- imports: [CommonModule, SharedModule, RouterModule.forChild([{path: '', component: AdminComponent}])],
+ declarations: adminRoutingComponents,
+
+ imports: [
+ CommonModule,
+ SharedModule,
+ adminRouterModule,
+
+ TranslateModule.forChild({
+ loader: {
+ provide: TranslateLoader,
+ useFactory: (createTranslateLoader),
+ deps: [HttpClient]
+ },
+ isolate: true
+ })
+ ],
+
providers: [AppUserService]
})
export class AdminModule {
+ static routes = adminRouterModule;
}
diff --git a/static/src/app/admin/admin.routing.ts b/static/src/app/admin/admin.routing.ts
new file mode 100644
index 0000000..7168182
--- /dev/null
+++ b/static/src/app/admin/admin.routing.ts
@@ -0,0 +1,37 @@
+import {RouterModule, Routes} from '@angular/router';
+import {ModuleWithProviders} from '@angular/core';
+import {AdminComponent} from './admin.component';
+import {AppUserListComponent} from './user-list/app-user-list.component';
+import {EditAppUserComponent} from './edit-app-user/edit-app-user.component';
+import {AppUserItemComponent} from './user-list/app-user-item.component';
+
+export const adminRoutes: Routes = [
+ {
+ path: 'users',
+ children: [
+ {
+ path: '',
+ component: AdminComponent,
+ outlet: 'left',
+ children: [{
+ path: '',
+ component: AppUserListComponent
+ }]
+ },
+ {
+ path: 'new',
+ component: EditAppUserComponent,
+ outlet: 'right'
+ },
+ {
+ path: 'edit/:id',
+ component: EditAppUserComponent,
+ outlet: 'right'
+ }
+ ]
+ },
+];
+
+export const adminRouterModule: ModuleWithProviders = RouterModule.forChild(adminRoutes);
+
+export const adminRoutingComponents = [AdminComponent, AppUserListComponent, AppUserItemComponent, EditAppUserComponent];
diff --git a/static/src/app/admin/edit-app-user/edit-app-user.component.css b/static/src/app/admin/edit-app-user/edit-app-user.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/static/src/app/admin/edit-app-user/edit-app-user.component.html b/static/src/app/admin/edit-app-user/edit-app-user.component.html
new file mode 100644
index 0000000..ffad96a
--- /dev/null
+++ b/static/src/app/admin/edit-app-user/edit-app-user.component.html
@@ -0,0 +1,61 @@
+
diff --git a/static/src/app/admin/edit-app-user/edit-app-user.component.ts b/static/src/app/admin/edit-app-user/edit-app-user.component.ts
new file mode 100644
index 0000000..6831aa4
--- /dev/null
+++ b/static/src/app/admin/edit-app-user/edit-app-user.component.ts
@@ -0,0 +1,88 @@
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {ActivatedRoute, Router} from '@angular/router';
+import {AppUser, Rank, Squad} from '../../models/model-interfaces';
+import {SquadService} from '../../services/army-management/squad.service';
+import {Subscription} from 'rxjs/Subscription';
+import {NgForm} from '@angular/forms';
+import {Fraction} from '../../utils/fraction.enum';
+import {SnackBarService} from '../../services/user-interface/snack-bar/snack-bar.service';
+import {AppUserService} from '../../services/app-user-service/app-user.service';
+
+
+@Component({
+ templateUrl: './edit-app-user.component.html',
+ styleUrls: ['./edit-app-user.component.css', '../../style/entry-form.css', '../../style/overview.css'],
+})
+export class EditAppUserComponent implements OnInit {
+
+ @ViewChild(NgForm) form: NgForm;
+
+ subscription: Subscription;
+
+ appUser: AppUser = {};
+
+ appUserSquadId;
+
+ squads: Squad[] = [];
+
+ ranks: Rank[] = [];
+
+ ranksDisplay = 'none';
+
+ error: string;
+
+ readonly fraction = Fraction;
+
+ constructor(private router: Router,
+ private route: ActivatedRoute,
+ private appUserService: AppUserService,
+ private squadService: SquadService,
+ private snackBarService: SnackBarService) {
+ }
+
+ ngOnInit() {
+ this.subscription = this.route.params
+ .map(params => params['id'])
+ .filter(id => id !== undefined)
+ .flatMap(id => this.appUserService.getAppUser(id))
+ .subscribe(appUser => {
+ this.appUser = appUser;
+ this.appUserSquadId = appUser.squad ? appUser.squad._id : 'null';
+ });
+
+ this.squadService.findSquads().subscribe(squads => {
+ this.squads = squads;
+ });
+ }
+
+ saveUser() {
+ const updateObject: AppUser = {
+ _id: this.appUser._id,
+ username: this.appUser.username,
+ squad: this.appUserSquadId === 'null' ? null : this.appUserSquadId,
+ activated: this.appUser.activated,
+ permission: this.appUser.permission,
+ };
+
+ this.appUserService.updateUser(updateObject)
+ .subscribe(appUser => {
+ this.appUser = appUser;
+ this.appUserSquadId = appUser.squad ? appUser.squad._id : 'null';
+ this.snackBarService.showSuccess('generic.save.success');
+ });
+ }
+
+ cancel() {
+ this.router.navigate([this.appUser._id ? '../..' : '..'], {relativeTo: this.route});
+ return false;
+ }
+
+ /**
+ * compare ngValue with ngModel to assign selected element
+ */
+ equals(o1: Squad, o2: Squad) {
+ if (o1 && o2) {
+ return o1._id === o2._id;
+ }
+ }
+}
diff --git a/static/src/app/admin/user-list/app-user-item.component.css b/static/src/app/admin/user-list/app-user-item.component.css
new file mode 100644
index 0000000..458e2b3
--- /dev/null
+++ b/static/src/app/admin/user-list/app-user-item.component.css
@@ -0,0 +1,6 @@
+.icon-award {
+ width: 27px;
+ height: 42px;
+ display: block;
+ margin-right: 25px;
+}
diff --git a/static/src/app/admin/user-list/app-user-item.component.html b/static/src/app/admin/user-list/app-user-item.component.html
new file mode 100644
index 0000000..2ede66e
--- /dev/null
+++ b/static/src/app/admin/user-list/app-user-item.component.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+ {{appUser.username}}
+
+
+
{{fraction.OPFOR}} - {{appUser.squad.name}}
+
{{fraction.BLUFOR}} - {{appUser.squad.name}}
+
{{'users.list.item.label.no.squad' | translate}}
+
+
+
+
+
+
+
diff --git a/static/src/app/admin/user-list/app-user-item.component.ts b/static/src/app/admin/user-list/app-user-item.component.ts
new file mode 100644
index 0000000..8e0a708
--- /dev/null
+++ b/static/src/app/admin/user-list/app-user-item.component.ts
@@ -0,0 +1,38 @@
+import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core';
+import {AppUser} from '../../models/model-interfaces';
+import {Fraction} from '../../utils/fraction.enum';
+
+@Component({
+ selector: 'cc-app-user-item',
+ templateUrl: './app-user-item.component.html',
+ styleUrls: ['./app-user-item.component.css', '../../style/list-entry.css'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AppUserItemComponent {
+
+ @Input() appUser: AppUser;
+
+ @Input() selected: boolean;
+
+ @Output() userSelected = new EventEmitter();
+ @Output() userAward = new EventEmitter();
+ @Output() userDelete = new EventEmitter();
+
+ readonly fraction = Fraction;
+
+ constructor() {
+ }
+
+ select() {
+ this.userSelected.emit(this.appUser._id);
+ }
+
+ award() {
+ this.userAward.emit(this.appUser._id);
+ }
+
+ delete() {
+ this.userDelete.emit(this.appUser);
+ }
+}
+
diff --git a/static/src/app/admin/user-list/app-user-list.component.css b/static/src/app/admin/user-list/app-user-list.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/static/src/app/admin/user-list/app-user-list.component.html b/static/src/app/admin/user-list/app-user-list.component.html
new file mode 100644
index 0000000..fcc64cb
--- /dev/null
+++ b/static/src/app/admin/user-list/app-user-list.component.html
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/static/src/app/admin/user-list/app-user-list.component.ts b/static/src/app/admin/user-list/app-user-list.component.ts
new file mode 100644
index 0000000..9c440d5
--- /dev/null
+++ b/static/src/app/admin/user-list/app-user-list.component.ts
@@ -0,0 +1,71 @@
+import {Component} from '@angular/core';
+
+import {FormControl} from '@angular/forms';
+import {ActivatedRoute, Router} from '@angular/router';
+import {Observable} from 'rxjs/Observable';
+import {AppUser, Squad} from '../../models/model-interfaces';
+import {Fraction} from '../../utils/fraction.enum';
+import {MatButtonToggleGroup} from '@angular/material';
+import {UIHelpers} from '../../utils/global.helpers';
+import {TranslateService} from '@ngx-translate/core';
+import {AppUserService} from '../../services/app-user-service/app-user.service';
+import {SquadService} from '../../services/army-management/squad.service';
+
+@Component({
+ selector: 'cc-app-user-list',
+ templateUrl: './app-user-list.component.html',
+ styleUrls: ['./app-user-list.component.css', '../../style/select-list.css']
+})
+export class AppUserListComponent {
+
+ selectedUserId: string | number = null;
+
+ appUsers$: Observable;
+
+ readonly fraction = Fraction;
+
+ searchTerm = new FormControl();
+
+ radioModel = '';
+
+ constructor(private appUserService: AppUserService,
+ private squadService: SquadService,
+ private router: Router,
+ private route: ActivatedRoute,
+ private translate: TranslateService) {
+ this.appUsers$ = this.appUserService.getUsers();
+ }
+
+ initObservable(observables: any) {
+ Observable.merge(observables.params as Observable, observables.searchTerm)
+ .distinctUntilChanged()
+ .switchMap(query => this.filterAppUsers())
+ .subscribe();
+ }
+
+ openNewUserForm() {
+ this.selectedUserId = null;
+ this.router.navigate([{outlets: {'right': ['new']}}], {relativeTo: this.route});
+ }
+
+ selectUser(userId: string) {
+ this.selectedUserId = userId;
+ this.router.navigate([{outlets: {'right': ['edit', userId]}}], {relativeTo: this.route});
+ }
+
+ deleteUser(user: AppUser) {
+ this.translate.get('users.list.delete.confirm', {name: user.username}).subscribe((confirmQuestion) => {
+ if (confirm(confirmQuestion)) {
+ this.appUserService.deleteUser(user)
+ .subscribe((res) => {
+ });
+ }
+ });
+ }
+
+ filterAppUsers(group?: MatButtonToggleGroup) {
+ this.radioModel = UIHelpers.toggleReleaseButton(this.radioModel, group);
+ // TODO: Add filter attribute submit
+ return this.appUsers$ = this.appUserService.getUsers();
+ }
+}
diff --git a/static/src/app/app.component.html b/static/src/app/app.component.html
index 19a09f7..b370a38 100644
--- a/static/src/app/app.component.html
+++ b/static/src/app/app.component.html
@@ -89,8 +89,18 @@
-
- {{'navigation.top.admin' | translate}}
+
+
+ {{'navigation.top.admin' | translate}}
+
+
+
{{'navigation.top.logout' | translate}}
diff --git a/static/src/app/app.config.ts b/static/src/app/app.config.ts
index bf7f7ae..9f2cf84 100644
--- a/static/src/app/app.config.ts
+++ b/static/src/app/app.config.ts
@@ -21,6 +21,7 @@ export class AppConfig {
export const RouteConfig = {
adminPanelPath: 'admin-panel',
+ adminPanelAppUsersPath: 'admin-panel/users',
managePath: 'manage',
manageDecorationPath: 'manage/decorations',
manageRankPath: 'manage/ranks',
diff --git a/static/src/app/models/model-interfaces.ts b/static/src/app/models/model-interfaces.ts
index 7c3f599..cea28a5 100644
--- a/static/src/app/models/model-interfaces.ts
+++ b/static/src/app/models/model-interfaces.ts
@@ -3,10 +3,10 @@ import {Observable} from 'rxjs';
export interface AppUser {
_id?: string;
username?: string;
- squad?: Squad;
+ squad?: any; // Squad or id-string
secret?: string;
- activated: boolean;
- permission: number;
+ activated?: boolean;
+ permission?: number;
token?: string;
}
diff --git a/static/src/app/services/app-user-service/app-user.service.ts b/static/src/app/services/app-user-service/app-user.service.ts
index c3d7d09..875e720 100644
--- a/static/src/app/services/app-user-service/app-user.service.ts
+++ b/static/src/app/services/app-user-service/app-user.service.ts
@@ -17,7 +17,7 @@ export class AppUserService {
this.users$ = this.appUserStore.items$;
}
- getUsers() {
+ getUsers(): Observable {
this.httpGateway.get(this.config.apiAppUserPath)
.do((users) => {
this.appUserStore.dispatch({type: LOAD, data: users});
@@ -27,7 +27,11 @@ export class AppUserService {
return this.users$;
}
- updateUser(user: AppUser) {
+ getAppUser(id: string): Observable {
+ return this.httpGateway.get(this.config.apiAppUserPath + id);
+ }
+
+ updateUser(user: AppUser): Observable {
return this.httpGateway.patch(this.config.apiAppUserPath + user._id, user)
.do(savedUser => {
const action = {type: EDIT, data: savedUser};
diff --git a/static/src/app/shared.module.ts b/static/src/app/shared.module.ts
index 01df61b..298a752 100644
--- a/static/src/app/shared.module.ts
+++ b/static/src/app/shared.module.ts
@@ -4,7 +4,8 @@ import {ShowErrorComponent} from './common/show-error/show-error.component';
import {CommonModule} from '@angular/common';
import {ListFilterComponent} from './common/user-interface/list-filter/list-filter.component';
import {SearchFieldComponent} from './common/user-interface/search-field/search-field.component';
-import {MatButtonToggleModule, MatTooltipModule} from '@angular/material';
+import {MatButtonToggleModule, MatTooltipModule, MatSlideToggleModule, MatFormFieldModule, MatOptionModule, MatSelectModule,
+ MatInputModule} from '@angular/material';
import {MatButtonModule} from '@angular/material/button';
import {MatIconModule} from '@angular/material/icon';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
@@ -30,6 +31,11 @@ export function createTranslateLoader(http: HttpClient) {
MatButtonModule,
MatIconModule,
MatTooltipModule,
+ MatSlideToggleModule,
+ MatFormFieldModule,
+ MatOptionModule,
+ MatSelectModule,
+ MatInputModule,
TranslateModule.forRoot({
loader: {
@@ -46,6 +52,11 @@ export function createTranslateLoader(http: HttpClient) {
MatButtonToggleModule,
MatButtonModule,
MatIconModule,
+ MatSlideToggleModule,
+ MatFormFieldModule,
+ MatOptionModule,
+ MatSelectModule,
+ MatInputModule,
ShowErrorComponent,
ListFilterComponent,
SearchFieldComponent,
diff --git a/static/src/assets/i18n/admin/de.json b/static/src/assets/i18n/admin/de.json
new file mode 100644
index 0000000..0952b2e
--- /dev/null
+++ b/static/src/assets/i18n/admin/de.json
@@ -0,0 +1,25 @@
+{
+ "public.error.message.required": "{{fieldName}} ist ein Pflichtfeld",
+ "public.error.message.min.length": "{{fieldName}} muss mindestens {{boundary}} Zeichen enthalten",
+ "public.error.message.max.length": "{{fieldName}} darf maximal {{boundary}} Zeichen enthalten",
+ "public.error.message.email": "Bitte geben Sie eine gültige E-Mail Adresse an",
+ "public.error.message.no.user": "Der eingetragene Benutzer existiert nicht.",
+ "public.error.message.default": "{{fieldName}} ist nicht valide",
+ "public.common.search.button": "Suchen",
+
+ "users.list.tooltip.new": "Neuen Teilnehmer hinzufügen",
+ "users.list.tooltip.delete": "Löschen",
+ "users.list.filter.no.squad": "Ohne Squad",
+ "users.list.item.label.no.squad": "ohne Squad/Fraktion",
+ "users.list.delete.confirm": "Soll der Teilnehmer '{{name}}' wirklich gelöscht werden?",
+
+ "user.submit.headline.new": "Neuen Teilnehmer hinzufügen",
+ "user.submit.headline.edit": "Teilnehmer bearbeiten",
+ "user.submit.field.name": "Name",
+ "user.submit.field.squad": "Squad",
+ "user.submit.field.squad.not.assigned": "Ohne Fraktion/ Squad",
+ "user.submit.field.activated": "Aktiviert",
+ "user.submit.field.permission": "Zugriffsrechte",
+ "user.submit.button.submit": "Bestätigen",
+ "user.submit.button.cancel": "Abbrechen"
+}
diff --git a/static/src/assets/i18n/admin/en.json b/static/src/assets/i18n/admin/en.json
new file mode 100644
index 0000000..0952b2e
--- /dev/null
+++ b/static/src/assets/i18n/admin/en.json
@@ -0,0 +1,25 @@
+{
+ "public.error.message.required": "{{fieldName}} ist ein Pflichtfeld",
+ "public.error.message.min.length": "{{fieldName}} muss mindestens {{boundary}} Zeichen enthalten",
+ "public.error.message.max.length": "{{fieldName}} darf maximal {{boundary}} Zeichen enthalten",
+ "public.error.message.email": "Bitte geben Sie eine gültige E-Mail Adresse an",
+ "public.error.message.no.user": "Der eingetragene Benutzer existiert nicht.",
+ "public.error.message.default": "{{fieldName}} ist nicht valide",
+ "public.common.search.button": "Suchen",
+
+ "users.list.tooltip.new": "Neuen Teilnehmer hinzufügen",
+ "users.list.tooltip.delete": "Löschen",
+ "users.list.filter.no.squad": "Ohne Squad",
+ "users.list.item.label.no.squad": "ohne Squad/Fraktion",
+ "users.list.delete.confirm": "Soll der Teilnehmer '{{name}}' wirklich gelöscht werden?",
+
+ "user.submit.headline.new": "Neuen Teilnehmer hinzufügen",
+ "user.submit.headline.edit": "Teilnehmer bearbeiten",
+ "user.submit.field.name": "Name",
+ "user.submit.field.squad": "Squad",
+ "user.submit.field.squad.not.assigned": "Ohne Fraktion/ Squad",
+ "user.submit.field.activated": "Aktiviert",
+ "user.submit.field.permission": "Zugriffsrechte",
+ "user.submit.button.submit": "Bestätigen",
+ "user.submit.button.cancel": "Abbrechen"
+}