commit
1f308ec3a5
|
@ -15,6 +15,7 @@ module.exports = {
|
||||||
request: rootRoute + '/request',
|
request: rootRoute + '/request',
|
||||||
signatures: '/signatures',
|
signatures: '/signatures',
|
||||||
signUp: rootRoute + '/authenticate/signup',
|
signUp: rootRoute + '/authenticate/signup',
|
||||||
|
slotting: rootRoute + '/slotting',
|
||||||
squads: rootRoute + '/squads',
|
squads: rootRoute + '/squads',
|
||||||
users: rootRoute + '/users',
|
users: rootRoute + '/users',
|
||||||
wars: rootRoute + '/wars',
|
wars: rootRoute + '/wars',
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,7 +10,7 @@
|
||||||
"dev": "DEBUG='cc:*' NODE_ENV=dev nodemon server.js",
|
"dev": "DEBUG='cc:*' NODE_ENV=dev nodemon server.js",
|
||||||
"eslint": "$(npm bin)/eslint",
|
"eslint": "$(npm bin)/eslint",
|
||||||
"lint": "eslint '**/*.js'",
|
"lint": "eslint '**/*.js'",
|
||||||
"test": "mocha --require ./test/config/spec_helper.js",
|
"test": "mocha --exit --require ./test/config/spec_helper.js",
|
||||||
"start-test": "DEBUG='cc:*' NODE_ENV=unitTest node server.js",
|
"start-test": "DEBUG='cc:*' NODE_ENV=unitTest node server.js",
|
||||||
"start-api-test": "rm -rf ./apib/dredd/data/tmp-resource && cp -r ./apib/dredd/data/resource ./apib/dredd/data/tmp-resource && DEBUG='cc:*' NODE_ENV=dreddTest node server.js",
|
"start-api-test": "rm -rf ./apib/dredd/data/tmp-resource && cp -r ./apib/dredd/data/resource ./apib/dredd/data/tmp-resource && DEBUG='cc:*' NODE_ENV=dreddTest node server.js",
|
||||||
"api:compile-docs": "$(npm bin)/hercule apib/dev-doc.apib -o apib/documentation.apib",
|
"api:compile-docs": "$(npm bin)/hercule apib/dev-doc.apib -o apib/documentation.apib",
|
||||||
|
@ -35,6 +35,7 @@
|
||||||
"mongoose": "^5.0.3",
|
"mongoose": "^5.0.3",
|
||||||
"morgan": "~1.6.1",
|
"morgan": "~1.6.1",
|
||||||
"multer": "^1.3.0",
|
"multer": "^1.3.0",
|
||||||
|
"node-html-parser": "^1.1.10",
|
||||||
"node-sha1": "^1.0.1",
|
"node-sha1": "^1.0.1",
|
||||||
"q": "^1.5.0",
|
"q": "^1.5.0",
|
||||||
"serve-favicon": "~2.3.0",
|
"serve-favicon": "~2.3.0",
|
||||||
|
@ -48,7 +49,7 @@
|
||||||
"eslint": "^4.18.2",
|
"eslint": "^4.18.2",
|
||||||
"eslint-config-google": "^0.9.1",
|
"eslint-config-google": "^0.9.1",
|
||||||
"hercule": "^4.1.1",
|
"hercule": "^4.1.1",
|
||||||
"mocha": "^3.5.3",
|
"mocha": "^5.2.0",
|
||||||
"mongodb-memory-server": "^1.7.3",
|
"mongodb-memory-server": "^1.7.3",
|
||||||
"nodemon": "^1.14.12"
|
"nodemon": "^1.14.12"
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@ const account = new express.Router();
|
||||||
|
|
||||||
account.route('/')
|
account.route('/')
|
||||||
.get((req, res, next) => {
|
.get((req, res, next) => {
|
||||||
AppUserModel.find({}, {}, {sort: {username: 1}}).populate('squad').exec((err, items) => {
|
AppUserModel.find({}, {}, {sort: {username: 1}})
|
||||||
|
.populate('squad')
|
||||||
|
.exec((err, items) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
err.status = codes.servererror;
|
err.status = codes.servererror;
|
||||||
return next(err);
|
return next(err);
|
||||||
|
@ -31,23 +33,35 @@ account.route('/')
|
||||||
|
|
||||||
// routes **********************
|
// routes **********************
|
||||||
account.route('/:id')
|
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) => {
|
.patch((req, res, next) => {
|
||||||
if (!req.body || (req.body._id && req.body._id !== req.params.id)) {
|
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(
|
||||||
const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' +
|
'id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + req.body._id);
|
||||||
req.body._id);
|
|
||||||
err.status = codes.notfound;
|
err.status = codes.notfound;
|
||||||
next(err);
|
return next(err);
|
||||||
return; // prevent node to process this function further after next() has finished.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// increment version manually as we do not use .save(.)
|
|
||||||
req.body.updatedAt = new Date();
|
req.body.updatedAt = new Date();
|
||||||
req.body.$inc = {__v: 1};
|
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
|
AppUserModel.findByIdAndUpdate(req.params.id, req.body, {new: true})
|
||||||
// reset attributes that are missing.
|
.populate('squad')
|
||||||
AppUserModel.findByIdAndUpdate(req.params.id, req.body, {new: true}).populate('squad').exec((err, item) => {
|
.exec((err, item) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
err.status = codes.wrongrequest;
|
err.status = codes.wrongrequest;
|
||||||
} else if (!item) {
|
} else if (!item) {
|
||||||
|
@ -68,10 +82,8 @@ account.route('/:id')
|
||||||
err = new Error('item not found');
|
err = new Error('item not found');
|
||||||
err.status = codes.notfound;
|
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;
|
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
|
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);
|
account.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
module.exports = account;
|
module.exports = account;
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const express = require('express');
|
||||||
|
const http = require('http');
|
||||||
|
const https = require('https');
|
||||||
|
const parse = require('node-html-parser').parse;
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('./http-codes');
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getHtml: REST get request returning HTML page response
|
||||||
|
* @param {object} options: http options object
|
||||||
|
* @param {function} onResult: callback to pass the results JSON object(s) back
|
||||||
|
*/
|
||||||
|
const getHtml = (options, onResult) => {
|
||||||
|
let port = (options.port === 443) ? https : http;
|
||||||
|
let req = port.request(options, (res) => {
|
||||||
|
let output = '';
|
||||||
|
res.setEncoding('utf8');
|
||||||
|
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
output += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on('end', () => {
|
||||||
|
if (res.statusCode === 301) { // follow redirect
|
||||||
|
const location = res.headers.location;
|
||||||
|
const baseUrl = ((options.port === 443) ? 'https' : 'http') + '://' + options.host;
|
||||||
|
options.path = location.replace(baseUrl, '');
|
||||||
|
getHtml(options, (status, redirectData) => {
|
||||||
|
onResult(status, redirectData);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onResult(res.statusCode, output);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
res.on('error', (err) => {
|
||||||
|
onResult(500, err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
req.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaulUserReqOptions = {
|
||||||
|
host: 'opt4.net',
|
||||||
|
port: 443,
|
||||||
|
path: '/dashboard/index.php?user/',
|
||||||
|
method: 'GET',
|
||||||
|
};
|
||||||
|
|
||||||
|
const slotting = new express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
slotting.route('/user/:id')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
const userId = req.params.id;
|
||||||
|
const options = Object.assign({}, defaulUserReqOptions);
|
||||||
|
options.path = options.path.concat(userId);
|
||||||
|
|
||||||
|
getHtml(options, (status, targetRes) => {
|
||||||
|
if (status !== codes.success) {
|
||||||
|
const err = new Error('Can not resolve user from remote service');
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const root = parse(targetRes);
|
||||||
|
const userNameEl = root.querySelector('.contentTitle');
|
||||||
|
let user = {
|
||||||
|
name: userNameEl.childNodes[0].rawText.trim(),
|
||||||
|
};
|
||||||
|
|
||||||
|
res.locals.items = user;
|
||||||
|
res.locals.processed = true;
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
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
|
||||||
|
slotting.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = slotting;
|
|
@ -9,6 +9,7 @@ const codes = require('./http-codes');
|
||||||
|
|
||||||
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
const checkHl = require('../middleware/permission-check').checkHl;
|
const checkHl = require('../middleware/permission-check').checkHl;
|
||||||
|
const checkMT = require('../middleware/permission-check').checkMT;
|
||||||
|
|
||||||
const offsetlimitMiddleware = require('../middleware/limitoffset-middleware-mongo');
|
const offsetlimitMiddleware = require('../middleware/limitoffset-middleware-mongo');
|
||||||
const filterHandlerCreator = require('../middleware/filter-handler-mongo');
|
const filterHandlerCreator = require('../middleware/filter-handler-mongo');
|
||||||
|
@ -180,7 +181,7 @@ users.route('/:id')
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
.delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => {
|
.delete(apiAuthenticationMiddleware, checkMT, (req, res, next) => {
|
||||||
UserModel.findByIdAndRemove(req.params.id, (err, item) => {
|
UserModel.findByIdAndRemove(req.params.id, (err, item) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
err.status = codes.wrongrequest;
|
err.status = codes.wrongrequest;
|
||||||
|
|
|
@ -48,6 +48,7 @@ const commandRouter = require('./routes/command');
|
||||||
const campaignRouter = require('./routes/campaigns');
|
const campaignRouter = require('./routes/campaigns');
|
||||||
const warRouter = require('./routes/wars');
|
const warRouter = require('./routes/wars');
|
||||||
const logRouter = require('./routes/logs');
|
const logRouter = require('./routes/logs');
|
||||||
|
const slottingRouter = require('./routes/slotting');
|
||||||
|
|
||||||
// Configuration ***********************************
|
// Configuration ***********************************
|
||||||
// mongoose promise setup
|
// mongoose promise setup
|
||||||
|
@ -98,6 +99,7 @@ app.use(urls.wars, warRouter);
|
||||||
app.use(urls.players, playerRouter);
|
app.use(urls.players, playerRouter);
|
||||||
app.use(urls.campaigns, campaignRouter);
|
app.use(urls.campaigns, campaignRouter);
|
||||||
app.use(urls.logs, logRouter);
|
app.use(urls.logs, logRouter);
|
||||||
|
app.use(urls.slotting, slottingRouter);
|
||||||
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
|
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
|
||||||
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
|
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "opt-cc",
|
"name": "opt-cc",
|
||||||
"version": "1.8.3",
|
"version": "1.8.4",
|
||||||
"author": "Florian Hartwich <hardi@noarch.de>",
|
"author": "Florian Hartwich <hardi@noarch.de>",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,65 +1 @@
|
||||||
<div class="overview">
|
<router-outlet></router-outlet>
|
||||||
|
|
||||||
<h2>Admin Panel</h2>
|
|
||||||
|
|
||||||
<div class="pull-left" style="margin-top:20px;">
|
|
||||||
<div class="table-container" style="width: 75%; min-width: 500px">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr class="table-head">
|
|
||||||
<th class="col-sm-1" style="border-radius: 10px 0 0 0;">Username</th>
|
|
||||||
<th class="col-sm-1">Activated</th>
|
|
||||||
<th class="col-sm-1">Secret</th>
|
|
||||||
<th class="col-sm-1">Fraktion/ Squad</th>
|
|
||||||
<th class="col-sm-1">Permission</th>
|
|
||||||
<th class="col-sm-1 text-center" style="border-radius: 0 10px 0 0;"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody *ngFor="let user of users$ | async">
|
|
||||||
<tr class="cell-outline">
|
|
||||||
<td>
|
|
||||||
{{user.username}}
|
|
||||||
</td>
|
|
||||||
<td style="font-weight: bold">
|
|
||||||
<select id="activated" name="activated" class="form-control btn dropdown-toggle"
|
|
||||||
[(ngModel)]="user.activated" (change)="updateAppUser(user)">
|
|
||||||
<option value="true">activated</option>
|
|
||||||
<option value="false">deactivated</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{user.secret}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<select class="form-control"
|
|
||||||
name="squad"
|
|
||||||
id="squad"
|
|
||||||
[(ngModel)]="user.squad"
|
|
||||||
[compareWith]="equals"
|
|
||||||
(change)="updateAppUser(user)">
|
|
||||||
<option [value]="0">Ohne Fraktion/ Squad</option>
|
|
||||||
<option *ngFor="let squad of squads" [ngValue]="squad">
|
|
||||||
{{squad.fraction == 'BLUFOR'? fraction.BLUFOR : fraction.OPFOR}}: {{squad.name}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<select id="permission" name="permission" class="form-control btn dropdown-toggle"
|
|
||||||
[(ngModel)]="user.permission" (change)="updateAppUser(user)">
|
|
||||||
<option value="0">User</option>
|
|
||||||
<option value="1">SQL</option>
|
|
||||||
<option value="2">HL</option>
|
|
||||||
<option value="3">MT</option>
|
|
||||||
<option value="4">Admin</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
|
||||||
<span class="glyphicon glyphicon-trash trash" matTooltip="Löschen" (click)="deleteUser(user)"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -1,68 +1,11 @@
|
||||||
import {Component, OnInit} from '@angular/core';
|
import {Component} 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';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'admin-panel',
|
selector: 'cc-admin-component',
|
||||||
templateUrl: './admin.component.html',
|
templateUrl: './admin.component.html',
|
||||||
styleUrls: ['./admin.component.css', '../style/overview.css']
|
styleUrls: ['./admin.component.css', '../style/overview.css']
|
||||||
})
|
})
|
||||||
export class AdminComponent implements OnInit {
|
export class AdminComponent {
|
||||||
|
constructor() {
|
||||||
users$: Observable<AppUser[]>;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,36 @@
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {AdminComponent} from './admin.component';
|
|
||||||
import {SharedModule} from '../shared.module';
|
import {SharedModule} from '../shared.module';
|
||||||
import {AppUserService} from '../services/app-user-service/app-user.service';
|
import {AppUserService} from '../services/app-user-service/app-user.service';
|
||||||
import {CommonModule} from '@angular/common';
|
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({
|
@NgModule({
|
||||||
declarations: [AdminComponent],
|
declarations: adminRoutingComponents,
|
||||||
imports: [CommonModule, SharedModule, RouterModule.forChild([{path: '', component: AdminComponent}])],
|
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
SharedModule,
|
||||||
|
adminRouterModule,
|
||||||
|
|
||||||
|
TranslateModule.forChild({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useFactory: (createTranslateLoader),
|
||||||
|
deps: [HttpClient]
|
||||||
|
},
|
||||||
|
isolate: true
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
providers: [AppUserService]
|
providers: [AppUserService]
|
||||||
})
|
})
|
||||||
export class AdminModule {
|
export class AdminModule {
|
||||||
|
static routes = adminRouterModule;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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];
|
|
@ -0,0 +1,61 @@
|
||||||
|
<form #form="ngForm" (keydown.enter)="$event.preventDefault()"
|
||||||
|
class="overview"
|
||||||
|
style="display: flex;flex-direction: column;">
|
||||||
|
<h3 *ngIf="appUser._id">{{'user.submit.headline.edit' | translate}}</h3>
|
||||||
|
<h3 *ngIf="!appUser._id">{{'user.submit.headline.new' | translate}}</h3>
|
||||||
|
|
||||||
|
<mat-form-field>
|
||||||
|
<label for="title">{{'user.submit.field.name' | translate}}</label>
|
||||||
|
<input matInput
|
||||||
|
[(ngModel)]="appUser.username"
|
||||||
|
name="title"
|
||||||
|
id="title"
|
||||||
|
required
|
||||||
|
maxlength="50"/>
|
||||||
|
<show-error displayName="{{'user.submit.field.name' | translate}}" controlPath="title"></show-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="squad">{{'user.submit.field.squad' | translate}}</label>
|
||||||
|
<select class="form-control"
|
||||||
|
name="squad"
|
||||||
|
id="squad"
|
||||||
|
[(ngModel)]="appUserSquadId">
|
||||||
|
<option [value]="null">{{'user.submit.field.squad.not.assigned' | translate}}</option>
|
||||||
|
<option *ngFor="let squad of squads" [ngValue]="squad._id">
|
||||||
|
{{squad.fraction == 'BLUFOR'? fraction.BLUFOR : fraction.OPFOR}}: {{squad.name}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<show-error displayName="{{'user.submit.field.squad' | translate}}" controlPath="squad"></show-error>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label>{{'user.submit.field.activated' | translate}}</label>
|
||||||
|
<mat-slide-toggle name="activated" [(ngModel)]="appUser.activated"></mat-slide-toggle>
|
||||||
|
|
||||||
|
<label>{{'user.submit.field.permission' | translate}}</label>
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-select name="permission" [(ngModel)]="appUser.permission">
|
||||||
|
<mat-option [value]="0">User</mat-option>
|
||||||
|
<mat-option [value]="1">SQL</mat-option>
|
||||||
|
<mat-option [value]="2">HL</mat-option>
|
||||||
|
<mat-option [value]="3">MT</mat-option>
|
||||||
|
<mat-option [value]="4">Admin</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<button id="cancel"
|
||||||
|
style="width: 50%"
|
||||||
|
(click)="cancel()"
|
||||||
|
class="btn btn-default">
|
||||||
|
{{'user.submit.button.cancel' | translate}}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button id="save"
|
||||||
|
style="width: 50%"
|
||||||
|
type="submit"
|
||||||
|
(click)="saveUser()"
|
||||||
|
class="btn btn-default"
|
||||||
|
[disabled]="!form.valid">
|
||||||
|
{{'user.submit.button.submit' | translate}}
|
||||||
|
</button>
|
||||||
|
</form>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
.icon-award {
|
||||||
|
width: 27px;
|
||||||
|
height: 42px;
|
||||||
|
display: block;
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="fade-in list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<span>
|
||||||
|
<a>{{appUser.username}}</a>
|
||||||
|
</span>
|
||||||
|
<br>
|
||||||
|
<small *ngIf="appUser.squad && appUser.squad.fraction == 'OPFOR'">{{fraction.OPFOR}} - {{appUser.squad.name}}</small>
|
||||||
|
<small *ngIf="appUser.squad && appUser.squad.fraction == 'BLUFOR'">{{fraction.BLUFOR}} - {{appUser.squad.name}}</small>
|
||||||
|
<small *ngIf="!appUser.squad">{{'users.list.item.label.no.squad' | translate}}</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<mat-icon (click)="delete(); $event.stopPropagation()" matTooltip="{{'users.list.tooltip.delete' | translate}}"
|
||||||
|
class="pull-right" style="margin-top: 8px;" svgIcon="delete"></mat-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="select-list">
|
||||||
|
<cc-app-user-item *ngFor="let user of appUsers$ | async"
|
||||||
|
[appUser]="user"
|
||||||
|
(userDelete)="deleteUser(user)"
|
||||||
|
(userSelected)="selectUser($event)"
|
||||||
|
[selected]="user._id == selectedUserId">
|
||||||
|
</cc-app-user-item>
|
||||||
|
</div>
|
|
@ -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<AppUser[]>;
|
||||||
|
|
||||||
|
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<string>, 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,8 +89,18 @@
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul class="nav navbar-nav pull-right">
|
<ul class="nav navbar-nav pull-right">
|
||||||
<li *ngIf="loginService.hasPermission(4)" routerLinkActive="active">
|
<li *ngIf="loginService.hasPermission(4)"
|
||||||
<a routerLink='{{config.adminPanelPath}}' class="link">{{'navigation.top.admin' | translate}}</a>
|
class="dropdown">
|
||||||
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||||
|
aria-expanded="false">
|
||||||
|
{{'navigation.top.admin' | translate}}
|
||||||
|
<span class="caret"></span>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li routerLinkActive="active">
|
||||||
|
<a routerLink='{{config.adminPanelAppUsersPath}}' class="link">{{'navigation.top.management.users' | translate}}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li *ngIf="loginService.isLoggedIn()" class="link" style="cursor: pointer">
|
<li *ngIf="loginService.isLoggedIn()" class="link" style="cursor: pointer">
|
||||||
<a (click)="logout()">{{'navigation.top.logout' | translate}}</a>
|
<a (click)="logout()">{{'navigation.top.logout' | translate}}</a>
|
||||||
|
@ -98,15 +108,15 @@
|
||||||
<li *ngIf="!loginService.isLoggedIn()" routerLinkActive="active">
|
<li *ngIf="!loginService.isLoggedIn()" routerLinkActive="active">
|
||||||
<a routerLink='{{config.loginPath}}' class="link">{{'navigation.top.login' | translate}}</a>
|
<a routerLink='{{config.loginPath}}' class="link">{{'navigation.top.login' | translate}}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown" *ngIf="FEATURE_LOCALIZATION_ENABLED">
|
<li class="dropdown" *ngIf="features.localization">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
|
||||||
aria-expanded="false" style="padding: 12px 12px 10px 12px;">
|
aria-expanded="false" style="padding: 12px 12px 10px 12px;">
|
||||||
<mat-icon svgIcon="{{(language === 'de') ? 'flag-de' : 'flag-gb'}}"></mat-icon>
|
<mat-icon svgIcon="flag-{{language}}"></mat-icon>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li *ngFor="let lang of languages" style="cursor: pointer">
|
<li *ngFor="let lang of languages" style="cursor: pointer">
|
||||||
<a (click)="setLanguage(lang)"><mat-icon svgIcon="{{(lang === 'de') ? 'flag-de' : 'flag-gb'}}"></mat-icon></a>
|
<a (click)="setLanguage(lang)"><mat-icon svgIcon="flag-{{lang}}"></mat-icon></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {MatIconRegistry} from '@angular/material';
|
||||||
import {SpinnerService} from './services/user-interface/spinner/spinner.service';
|
import {SpinnerService} from './services/user-interface/spinner/spinner.service';
|
||||||
import {TranslateService} from '@ngx-translate/core';
|
import {TranslateService} from '@ngx-translate/core';
|
||||||
import {SettingsService} from './services/settings.service';
|
import {SettingsService} from './services/settings.service';
|
||||||
|
import {environment} from '../environments/environment';
|
||||||
|
|
||||||
declare function require(url: string);
|
declare function require(url: string);
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ declare function require(url: string);
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
|
|
||||||
readonly FEATURE_LOCALIZATION_ENABLED = false;
|
readonly features = environment.features;
|
||||||
|
|
||||||
config = RouteConfig;
|
config = RouteConfig;
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ export class AppComponent implements OnInit {
|
||||||
'vehicleLight': 'stats/scoreboard/vehicleLight',
|
'vehicleLight': 'stats/scoreboard/vehicleLight',
|
||||||
// --------LOCALE---------
|
// --------LOCALE---------
|
||||||
'flag-de': 'locale/de',
|
'flag-de': 'locale/de',
|
||||||
'flag-gb': 'locale/gb',
|
'flag-en': 'locale/en',
|
||||||
};
|
};
|
||||||
|
|
||||||
language;
|
language;
|
||||||
|
|
|
@ -21,6 +21,7 @@ export class AppConfig {
|
||||||
|
|
||||||
export const RouteConfig = {
|
export const RouteConfig = {
|
||||||
adminPanelPath: 'admin-panel',
|
adminPanelPath: 'admin-panel',
|
||||||
|
adminPanelAppUsersPath: 'admin-panel/users',
|
||||||
managePath: 'manage',
|
managePath: 'manage',
|
||||||
manageDecorationPath: 'manage/decorations',
|
manageDecorationPath: 'manage/decorations',
|
||||||
manageRankPath: 'manage/ranks',
|
manageRankPath: 'manage/ranks',
|
||||||
|
|
|
@ -38,7 +38,8 @@ export class LoginComponent implements OnInit {
|
||||||
this.router.navigate([this.returnUrl]);
|
this.router.navigate([this.returnUrl]);
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
this.snackBarService.showError(error._body, 15000);
|
// TODO: return i18n key from backend to use translate error method
|
||||||
|
this.snackBarService.showUntranslatedError(error.error, 15000);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {Rank} from '../../../models/model-interfaces';
|
||||||
import {Fraction} from '../../../utils/fraction.enum';
|
import {Fraction} from '../../../utils/fraction.enum';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pjm-rank-item',
|
selector: 'cc-rank-item',
|
||||||
templateUrl: './rank-item.component.html',
|
templateUrl: './rank-item.component.html',
|
||||||
styleUrls: ['./rank-item.component.css', '../../../style/list-entry.css'],
|
styleUrls: ['./rank-item.component.css', '../../../style/list-entry.css'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
(executeSearch)="filterRanks()">
|
(executeSearch)="filterRanks()">
|
||||||
</cc-list-search>
|
</cc-list-search>
|
||||||
|
|
||||||
<pjm-rank-item *ngFor="let rank of ranks$ | async"
|
<cc-rank-item *ngFor="let rank of ranks$ | async"
|
||||||
[rank]="rank"
|
[rank]="rank"
|
||||||
(rankDelete)="deleteRank(rank)"
|
(rankDelete)="deleteRank(rank)"
|
||||||
(rankSelected)="selectRank($event)"
|
(rankSelected)="selectRank($event)"
|
||||||
[selected]="rank._id == selectedRankId">
|
[selected]="rank._id == selectedRankId">
|
||||||
</pjm-rank-item>
|
</cc-rank-item>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {Squad} from '../../../models/model-interfaces';
|
||||||
import {Fraction} from '../../../utils/fraction.enum';
|
import {Fraction} from '../../../utils/fraction.enum';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pjm-squad-item',
|
selector: 'cc-squad-item',
|
||||||
templateUrl: './squad-item.component.html',
|
templateUrl: './squad-item.component.html',
|
||||||
styleUrls: ['./squad-item.component.css', '../../../style/list-entry.css'],
|
styleUrls: ['./squad-item.component.css', '../../../style/list-entry.css'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
|
|
@ -12,10 +12,10 @@
|
||||||
(executeSearch)="filterSquads()">
|
(executeSearch)="filterSquads()">
|
||||||
</cc-list-search>
|
</cc-list-search>
|
||||||
|
|
||||||
<pjm-squad-item *ngFor="let squad of squads$ | async"
|
<cc-squad-item *ngFor="let squad of squads$ | async"
|
||||||
[squad]="squad"
|
[squad]="squad"
|
||||||
(squadDelete)="deleteSquad(squad)"
|
(squadDelete)="deleteSquad(squad)"
|
||||||
(squadSelected)="selectSquad($event)"
|
(squadSelected)="selectSquad($event)"
|
||||||
[selected]="squad._id == selectedSquadId">
|
[selected]="squad._id == selectedSquadId">
|
||||||
</pjm-squad-item>
|
</cc-squad-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<mat-icon (click)="delete(); $event.stopPropagation()" matTooltip="{{'users.list.tooltip.delete' | translate}}"
|
<mat-icon (click)="delete(); $event.stopPropagation()" matTooltip="{{'users.list.tooltip.delete' | translate}}"
|
||||||
|
*ngIf="loginService.hasPermission(3)"
|
||||||
class="pull-right" style="margin-top: 8px;" svgIcon="delete"></mat-icon>
|
class="pull-right" style="margin-top: 8px;" svgIcon="delete"></mat-icon>
|
||||||
<mat-icon (click)="award(); $event.stopPropagation()" matTooltip="{{'users.list.tooltip.awards' | translate}}"
|
<mat-icon (click)="award(); $event.stopPropagation()" matTooltip="{{'users.list.tooltip.awards' | translate}}"
|
||||||
class="icon-award pull-right" svgIcon="award"></mat-icon>
|
class="icon-award pull-right" svgIcon="award"></mat-icon>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core';
|
import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core';
|
||||||
import {User} from '../../../models/model-interfaces';
|
import {User} from '../../../models/model-interfaces';
|
||||||
import {Fraction} from '../../../utils/fraction.enum';
|
import {Fraction} from '../../../utils/fraction.enum';
|
||||||
|
import {LoginService} from '../../../services/app-user-service/login-service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'pjm-user-item',
|
selector: 'cc-user-item',
|
||||||
templateUrl: './user-item.component.html',
|
templateUrl: './user-item.component.html',
|
||||||
styleUrls: ['./user-item.component.css', '../../../style/list-entry.css'],
|
styleUrls: ['./user-item.component.css', '../../../style/list-entry.css'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
@ -20,7 +21,7 @@ export class UserItemComponent {
|
||||||
|
|
||||||
readonly fraction = Fraction;
|
readonly fraction = Fraction;
|
||||||
|
|
||||||
constructor() {
|
constructor(public loginService: LoginService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
select() {
|
select() {
|
||||||
|
|
|
@ -19,12 +19,12 @@
|
||||||
[infiniteScrollDistance]="scrollDistance"
|
[infiniteScrollDistance]="scrollDistance"
|
||||||
[infiniteScrollThrottle]="throttle"
|
[infiniteScrollThrottle]="throttle"
|
||||||
(scrolled)="onScrollDown()">
|
(scrolled)="onScrollDown()">
|
||||||
<pjm-user-item *ngFor="let user of users$ | async"
|
<cc-user-item *ngFor="let user of users$ | async"
|
||||||
[user]="user"
|
[user]="user"
|
||||||
(userDelete)="deleteUser(user)"
|
(userDelete)="deleteUser(user)"
|
||||||
(userSelected)="selectUser($event)"
|
(userSelected)="selectUser($event)"
|
||||||
(userAward)="awardUser($event)"
|
(userAward)="awardUser($event)"
|
||||||
[selected]="user._id == selectedUserId">
|
[selected]="user._id == selectedUserId">
|
||||||
</pjm-user-item>
|
</cc-user-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,10 +3,10 @@ import {Observable} from 'rxjs';
|
||||||
export interface AppUser {
|
export interface AppUser {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
squad?: Squad;
|
squad?: any; // Squad or id-string
|
||||||
secret?: string;
|
secret?: string;
|
||||||
activated: boolean;
|
activated?: boolean;
|
||||||
permission: number;
|
permission?: number;
|
||||||
token?: string;
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ export class AppUserService {
|
||||||
this.users$ = this.appUserStore.items$;
|
this.users$ = this.appUserStore.items$;
|
||||||
}
|
}
|
||||||
|
|
||||||
getUsers() {
|
getUsers(): Observable<AppUser[]> {
|
||||||
this.httpGateway.get<AppUser[]>(this.config.apiAppUserPath)
|
this.httpGateway.get<AppUser[]>(this.config.apiAppUserPath)
|
||||||
.do((users) => {
|
.do((users) => {
|
||||||
this.appUserStore.dispatch({type: LOAD, data: users});
|
this.appUserStore.dispatch({type: LOAD, data: users});
|
||||||
|
@ -27,7 +27,11 @@ export class AppUserService {
|
||||||
return this.users$;
|
return this.users$;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUser(user: AppUser) {
|
getAppUser(id: string): Observable<AppUser> {
|
||||||
|
return this.httpGateway.get<AppUser>(this.config.apiAppUserPath + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUser(user: AppUser): Observable<AppUser> {
|
||||||
return this.httpGateway.patch<AppUser>(this.config.apiAppUserPath + user._id, user)
|
return this.httpGateway.patch<AppUser>(this.config.apiAppUserPath + user._id, user)
|
||||||
.do(savedUser => {
|
.do(savedUser => {
|
||||||
const action = {type: EDIT, data: savedUser};
|
const action = {type: EDIT, data: savedUser};
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {Decoration} from '../../models/model-interfaces';
|
import {Decoration} from '../../models/model-interfaces';
|
||||||
import {RequestMethod, RequestOptions} from '@angular/http';
|
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {ADD, EDIT, LOAD, REMOVE, Store} from '../stores/generic-store';
|
import {ADD, EDIT, LOAD, REMOVE, Store} from '../stores/generic-store';
|
||||||
import {AppConfig} from '../../app.config';
|
import {AppConfig} from '../../app.config';
|
||||||
import {HttpGateway} from '../http-gateway';
|
import {HttpGateway, HttpMethod} from '../http-gateway';
|
||||||
import {HttpParams} from '@angular/common/http';
|
import {HttpParams} from '@angular/common/http';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -44,16 +43,16 @@ export class DecorationService {
|
||||||
*/
|
*/
|
||||||
submitDecoration(decoration: Decoration, imageFile?) {
|
submitDecoration(decoration: Decoration, imageFile?) {
|
||||||
let requestUrl = this.config.apiDecorationPath;
|
let requestUrl = this.config.apiDecorationPath;
|
||||||
let requestMethod: RequestMethod;
|
let requestMethod: HttpMethod;
|
||||||
let accessType;
|
let accessType;
|
||||||
let body;
|
let body;
|
||||||
|
|
||||||
if (decoration._id) {
|
if (decoration._id) {
|
||||||
requestUrl += decoration._id;
|
requestUrl += decoration._id;
|
||||||
requestMethod = RequestMethod.Patch;
|
requestMethod = 'PATCH';
|
||||||
accessType = EDIT;
|
accessType = EDIT;
|
||||||
} else {
|
} else {
|
||||||
requestMethod = RequestMethod.Post;
|
requestMethod = 'POST';
|
||||||
accessType = ADD;
|
accessType = ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,12 +68,7 @@ export class DecorationService {
|
||||||
body = decoration;
|
body = decoration;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = new RequestOptions({
|
return this.httpGateway.request<Decoration>(requestUrl, body, requestMethod)
|
||||||
body: body,
|
|
||||||
method: requestMethod,
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.httpGateway.request<Decoration>(requestUrl, options)
|
|
||||||
.do(savedDecoration => {
|
.do(savedDecoration => {
|
||||||
const action = {type: accessType, data: savedDecoration};
|
const action = {type: accessType, data: savedDecoration};
|
||||||
this.decorationStore.dispatch(action);
|
this.decorationStore.dispatch(action);
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {Rank} from '../../models/model-interfaces';
|
import {Rank} from '../../models/model-interfaces';
|
||||||
import {RequestMethod, RequestOptions} from '@angular/http';
|
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {ADD, EDIT, LOAD, REMOVE, Store} from '../stores/generic-store';
|
import {ADD, EDIT, LOAD, REMOVE, Store} from '../stores/generic-store';
|
||||||
import {AppConfig} from '../../app.config';
|
import {AppConfig} from '../../app.config';
|
||||||
import {HttpGateway} from '../http-gateway';
|
import {HttpGateway, HttpMethod} from '../http-gateway';
|
||||||
import {HttpParams} from '@angular/common/http';
|
import {HttpParams} from '@angular/common/http';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -44,16 +43,16 @@ export class RankService {
|
||||||
*/
|
*/
|
||||||
submitRank(rank: Rank, imageFile?): Observable<Rank> {
|
submitRank(rank: Rank, imageFile?): Observable<Rank> {
|
||||||
let requestUrl = this.config.apiRankPath;
|
let requestUrl = this.config.apiRankPath;
|
||||||
let requestMethod: RequestMethod;
|
let requestMethod: HttpMethod;
|
||||||
let accessType;
|
let accessType;
|
||||||
let body;
|
let body;
|
||||||
|
|
||||||
if (rank._id) {
|
if (rank._id) {
|
||||||
requestUrl += rank._id;
|
requestUrl += rank._id;
|
||||||
requestMethod = RequestMethod.Patch;
|
requestMethod = 'PATCH';
|
||||||
accessType = EDIT;
|
accessType = EDIT;
|
||||||
} else {
|
} else {
|
||||||
requestMethod = RequestMethod.Post;
|
requestMethod = 'POST';
|
||||||
accessType = ADD;
|
accessType = ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,12 +69,7 @@ export class RankService {
|
||||||
body = rank;
|
body = rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = new RequestOptions({
|
return this.httpGateway.request<Rank>(requestUrl, body, requestMethod)
|
||||||
body: body,
|
|
||||||
method: requestMethod
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.httpGateway.request<Rank>(requestUrl, options)
|
|
||||||
.do(savedRank => {
|
.do(savedRank => {
|
||||||
const action = {type: accessType, data: savedRank};
|
const action = {type: accessType, data: savedRank};
|
||||||
// leave some time to save image file before accessing it through list view
|
// leave some time to save image file before accessing it through list view
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {Squad} from '../../models/model-interfaces';
|
import {Squad} from '../../models/model-interfaces';
|
||||||
import {RequestMethod, RequestOptions} from '@angular/http';
|
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {ADD, EDIT, LOAD, REMOVE, Store} from '../stores/generic-store';
|
import {ADD, EDIT, LOAD, REMOVE, Store} from '../stores/generic-store';
|
||||||
import {AppConfig} from '../../app.config';
|
import {AppConfig} from '../../app.config';
|
||||||
import {HttpGateway} from '../http-gateway';
|
import {HttpGateway, HttpMethod} from '../http-gateway';
|
||||||
import {HttpParams} from '@angular/common/http';
|
import {HttpParams} from '@angular/common/http';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -42,16 +41,16 @@ export class SquadService {
|
||||||
*/
|
*/
|
||||||
submitSquad(squad: Squad, imageFile?): Observable<Squad> {
|
submitSquad(squad: Squad, imageFile?): Observable<Squad> {
|
||||||
let requestUrl = this.config.apiSquadPath;
|
let requestUrl = this.config.apiSquadPath;
|
||||||
let requestMethod: RequestMethod;
|
let requestMethod: HttpMethod;
|
||||||
let accessType;
|
let accessType;
|
||||||
let body;
|
let body;
|
||||||
|
|
||||||
if (squad._id) {
|
if (squad._id) {
|
||||||
requestUrl += squad._id;
|
requestUrl += squad._id;
|
||||||
requestMethod = RequestMethod.Patch;
|
requestMethod = 'PATCH';
|
||||||
accessType = EDIT;
|
accessType = EDIT;
|
||||||
} else {
|
} else {
|
||||||
requestMethod = RequestMethod.Post;
|
requestMethod = 'POST';
|
||||||
accessType = ADD;
|
accessType = ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,12 +66,7 @@ export class SquadService {
|
||||||
body = squad;
|
body = squad;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = new RequestOptions({
|
return this.httpGateway.request<Squad>(requestUrl, body, requestMethod)
|
||||||
body: body,
|
|
||||||
method: requestMethod
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.httpGateway.request<Squad>(requestUrl, options)
|
|
||||||
.do(savedSquad => {
|
.do(savedSquad => {
|
||||||
const action = {type: accessType, data: savedSquad};
|
const action = {type: accessType, data: savedSquad};
|
||||||
this.squadStore.dispatch(action);
|
this.squadStore.dispatch(action);
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {RequestMethod} from '@angular/http';
|
|
||||||
import {Router} from '@angular/router';
|
import {Router} from '@angular/router';
|
||||||
import {CookieService} from 'ngx-cookie-service';
|
import {CookieService} from 'ngx-cookie-service';
|
||||||
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
|
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
|
|
||||||
|
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HttpGateway {
|
export class HttpGateway {
|
||||||
|
|
||||||
|
@ -62,12 +63,16 @@ export class HttpGateway {
|
||||||
return this.http.delete(url, this.createAuthorizationHeader());
|
return this.http.delete(url, this.createAuthorizationHeader());
|
||||||
}
|
}
|
||||||
|
|
||||||
request<T>(requestUrl, options): Observable<T> {
|
request<T>(requestUrl, body, method: HttpMethod): Observable<T> {
|
||||||
if (options.method === RequestMethod.Post) {
|
switch (method) {
|
||||||
return this.post<T>(requestUrl, options.body);
|
case 'GET':
|
||||||
}
|
return this.get(requestUrl);
|
||||||
if (options.method === RequestMethod.Patch) {
|
case 'POST':
|
||||||
return this.patch<T>(requestUrl, options.body);
|
return this.post<T>(requestUrl, body);
|
||||||
|
case 'PUT':
|
||||||
|
return this.put(requestUrl, body);
|
||||||
|
case 'PATCH':
|
||||||
|
return this.patch<T>(requestUrl, body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,7 @@ import {Campaign} from '../../models/model-interfaces';
|
||||||
import {AppConfig} from '../../app.config';
|
import {AppConfig} from '../../app.config';
|
||||||
import {ADD, EDIT, LOAD, REMOVE, Store} from '../stores/generic-store';
|
import {ADD, EDIT, LOAD, REMOVE, Store} from '../stores/generic-store';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import {RequestMethod, RequestOptions} from '@angular/http';
|
import {HttpGateway, HttpMethod} from '../http-gateway';
|
||||||
import {HttpGateway} from '../http-gateway';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CampaignService {
|
export class CampaignService {
|
||||||
|
@ -33,25 +32,20 @@ export class CampaignService {
|
||||||
|
|
||||||
submitCampaign(campaign: Campaign) {
|
submitCampaign(campaign: Campaign) {
|
||||||
let requestUrl: string;
|
let requestUrl: string;
|
||||||
let requestMethod: RequestMethod;
|
let requestMethod: HttpMethod;
|
||||||
let accessType;
|
let accessType;
|
||||||
|
|
||||||
if (campaign._id) {
|
if (campaign._id) {
|
||||||
requestUrl = this.config.apiCampaignPath + '/' + campaign._id;
|
requestUrl = this.config.apiCampaignPath + '/' + campaign._id;
|
||||||
requestMethod = RequestMethod.Patch;
|
requestMethod = 'PATCH';
|
||||||
accessType = EDIT;
|
accessType = EDIT;
|
||||||
} else {
|
} else {
|
||||||
requestUrl = this.config.apiCampaignPath;
|
requestUrl = this.config.apiCampaignPath;
|
||||||
requestMethod = RequestMethod.Post;
|
requestMethod = 'POST';
|
||||||
accessType = ADD;
|
accessType = ADD;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = new RequestOptions({
|
return this.httpGateway.request<Campaign>(requestUrl, campaign, requestMethod)
|
||||||
body: campaign,
|
|
||||||
method: requestMethod
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.httpGateway.request<Campaign>(requestUrl, options)
|
|
||||||
.do(savedCampaign => {
|
.do(savedCampaign => {
|
||||||
const action = {type: accessType, data: savedCampaign};
|
const action = {type: accessType, data: savedCampaign};
|
||||||
this.campaignStore.dispatch(action);
|
this.campaignStore.dispatch(action);
|
||||||
|
|
|
@ -39,7 +39,7 @@ export class LogsService {
|
||||||
params.append('fraction', fraction);
|
params.append('fraction', fraction);
|
||||||
params.append('stabilized', stabilizedOnly ? 'true' : '');
|
params.append('stabilized', stabilizedOnly ? 'true' : '');
|
||||||
params.append('revive', reviveOnly ? 'true' : '');
|
params.append('revive', reviveOnly ? 'true' : '');
|
||||||
return this.httpGateway.get(this.config .apiLogsPath + '/' + warId + '/revive', params);
|
return this.httpGateway.get(this.config.apiLogsPath + '/' + warId + '/revive', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
getKillLogs(warId: string, shooterName = '', targetName = '', fraction = '', friendlyFireOnly = false, notFriendlyFireOnly = false) {
|
getKillLogs(warId: string, shooterName = '', targetName = '', fraction = '', friendlyFireOnly = false, notFriendlyFireOnly = false) {
|
||||||
|
|
|
@ -42,4 +42,8 @@ export class SnackBarService {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showUntranslatedError(message: string, duration?: number) {
|
||||||
|
return this.show(message, 'OK', duration, ['custom-snack-bar', 'label-danger']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ import {ShowErrorComponent} from './common/show-error/show-error.component';
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {ListFilterComponent} from './common/user-interface/list-filter/list-filter.component';
|
import {ListFilterComponent} from './common/user-interface/list-filter/list-filter.component';
|
||||||
import {SearchFieldComponent} from './common/user-interface/search-field/search-field.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 {MatButtonModule} from '@angular/material/button';
|
||||||
import {MatIconModule} from '@angular/material/icon';
|
import {MatIconModule} from '@angular/material/icon';
|
||||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
|
@ -30,6 +31,11 @@ export function createTranslateLoader(http: HttpClient) {
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
|
MatSlideToggleModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatOptionModule,
|
||||||
|
MatSelectModule,
|
||||||
|
MatInputModule,
|
||||||
|
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
|
@ -46,6 +52,11 @@ export function createTranslateLoader(http: HttpClient) {
|
||||||
MatButtonToggleModule,
|
MatButtonToggleModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
|
MatSlideToggleModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatOptionModule,
|
||||||
|
MatSelectModule,
|
||||||
|
MatInputModule,
|
||||||
ShowErrorComponent,
|
ShowErrorComponent,
|
||||||
ListFilterComponent,
|
ListFilterComponent,
|
||||||
SearchFieldComponent,
|
SearchFieldComponent,
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
|
@ -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"
|
||||||
|
}
|
Before Width: | Height: | Size: 831 B After Width: | Height: | Size: 831 B |
|
@ -1,4 +1,7 @@
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: true,
|
production: true,
|
||||||
e2eMode: false
|
e2eMode: false,
|
||||||
|
features: {
|
||||||
|
localization: false
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,5 +5,8 @@
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
e2eMode: false
|
e2eMode: false,
|
||||||
|
features: {
|
||||||
|
localization: true
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue