Merge branch 'release/1-3-2' of hardi/opt-cc into master
commit
ae20c7ce7d
|
@ -1,18 +1,19 @@
|
||||||
const rootRoute = '/api';
|
const rootRoute = '/api';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
account: rootRoute + '/account',
|
||||||
auth: rootRoute + '/authenticate',
|
auth: rootRoute + '/authenticate',
|
||||||
signUp: rootRoute + '/authenticate/signup',
|
|
||||||
awards: rootRoute + '/awardings',
|
awards: rootRoute + '/awardings',
|
||||||
command: rootRoute + '/cmd',
|
campaigns: rootRoute + '/campaigns',
|
||||||
cmdCreateSig: rootRoute + '/cmd/createSignature',
|
cmdCreateSig: rootRoute + '/cmd/createSignature',
|
||||||
|
command: rootRoute + '/cmd',
|
||||||
decorations: rootRoute + '/decorations',
|
decorations: rootRoute + '/decorations',
|
||||||
overview: rootRoute + '/overview',
|
overview: rootRoute + '/overview',
|
||||||
ranks: rootRoute + '/ranks',
|
ranks: rootRoute + '/ranks',
|
||||||
|
request: rootRoute + '/request',
|
||||||
signatures: '/signatures',
|
signatures: '/signatures',
|
||||||
|
signUp: rootRoute + '/authenticate/signup',
|
||||||
squads: rootRoute + '/squads',
|
squads: rootRoute + '/squads',
|
||||||
users: rootRoute + '/users',
|
users: rootRoute + '/users',
|
||||||
account: rootRoute + '/account',
|
|
||||||
request: rootRoute + '/request',
|
|
||||||
wars: rootRoute + '/wars'
|
wars: rootRoute + '/wars'
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const mongoose = require('mongoose');
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const CampaignSchema = new Schema({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
collection: 'campaign',
|
||||||
|
timestamps: {createdAt: 'timestamp'}
|
||||||
|
});
|
||||||
|
// optional more indices
|
||||||
|
CampaignSchema.index({timestamp: 1});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('Campaign', CampaignSchema);
|
|
@ -35,6 +35,10 @@ const WarSchema = new Schema({
|
||||||
get: v => Math.round(v),
|
get: v => Math.round(v),
|
||||||
set: v => Math.round(v),
|
set: v => Math.round(v),
|
||||||
default: 0
|
default: 0
|
||||||
|
},
|
||||||
|
campaign: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
ref: 'Campaign'
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
collection: 'war',
|
collection: 'war',
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const express = require('express');
|
||||||
|
const logger = require('debug')('cc:campaigns');
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('./http-codes');
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
|
||||||
|
const checkMT = require('../middleware/permission-check').checkMT;
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const CampaignModel = require('../models/campaign');
|
||||||
|
|
||||||
|
const campaigns = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
campaigns.route('/')
|
||||||
|
|
||||||
|
.post(apiAuthenticationMiddleware, checkMT, (req, res, next) => {
|
||||||
|
const campaign = new CampaignModel(req.body);
|
||||||
|
// timestamp and default are set automatically by Mongoose Schema Validation
|
||||||
|
campaign.save((err) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.wrongrequest;
|
||||||
|
err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.status(codes.created);
|
||||||
|
res.locals.items = campaign;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
campaigns.route('/:id')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
CampaignModel.findById(req.params.id, (err, item) => {
|
||||||
|
if (err) {
|
||||||
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
else if (!item) {
|
||||||
|
err = new Error("item not found");
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
res.locals.items = item;
|
||||||
|
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
|
||||||
|
campaigns.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = campaigns;
|
|
@ -18,6 +18,7 @@ const checkMT = require('../middleware/permission-check').checkMT;
|
||||||
const routerHandling = require('../middleware/router-handling');
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
// Mongoose Model using mongoDB
|
// Mongoose Model using mongoDB
|
||||||
|
const CampaignModel = require('../models/campaign');
|
||||||
const WarModel = require('../models/war');
|
const WarModel = require('../models/war');
|
||||||
const PlayerModel = require('../models/player');
|
const PlayerModel = require('../models/player');
|
||||||
|
|
||||||
|
@ -26,20 +27,37 @@ const wars = express.Router();
|
||||||
// routes **********************
|
// routes **********************
|
||||||
wars.route('/')
|
wars.route('/')
|
||||||
.get((req, res, next) => {
|
.get((req, res, next) => {
|
||||||
const filter = {};
|
let result = [];
|
||||||
WarModel.find(filter, {}, {sort: {date: 'desc'}}, (err, items) => {
|
CampaignModel.find({}, {}, {sort: {timestamp: 'desc'}}, (err, campaigns) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
err.status = codes.servererror;
|
err.status = codes.servererror;
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
if (items) {
|
if (campaigns) {
|
||||||
res.locals.items = items;
|
WarModel.find({}, {}, {sort: {date: 'desc'}}, (err, wars) => {
|
||||||
} else {
|
if (err) {
|
||||||
res.locals.items = [];
|
err.status = codes.servererror;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
if (wars) {
|
||||||
|
campaigns.forEach(campaign => {
|
||||||
|
let entry = {_id: campaign._id, title: campaign.title, wars: []};
|
||||||
|
wars.forEach((war) => {
|
||||||
|
if (String(campaign._id) === String(war.campaign)) {
|
||||||
|
entry.wars.push(war);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
result.push(entry);
|
||||||
|
});
|
||||||
|
res.locals.items = result;
|
||||||
|
}
|
||||||
|
res.locals.processed = true;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
res.locals.processed = true;
|
})
|
||||||
next();
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
|
|
||||||
.post(apiAuthenticationMiddleware, checkMT, upload.single('log'), (req, res, next) => {
|
.post(apiAuthenticationMiddleware, checkMT, upload.single('log'), (req, res, next) => {
|
||||||
|
@ -64,7 +82,6 @@ wars.route('/')
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
//TODO: combine run and clean in one script, so log file gets touched only once
|
|
||||||
exec(__dirname + '/../war-parser/run.sh ' + folderName + ' ' + war._id, (error, stdout) => {
|
exec(__dirname + '/../war-parser/run.sh ' + folderName + ' ' + war._id, (error, stdout) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
return next(error);
|
return next(error);
|
||||||
|
@ -75,7 +92,9 @@ wars.route('/')
|
||||||
}
|
}
|
||||||
let obj = JSON.parse(`${stdout}`);
|
let obj = JSON.parse(`${stdout}`);
|
||||||
for (let i = 0; i < obj.length; i++) {
|
for (let i = 0; i < obj.length; i++) {
|
||||||
if (obj[i].fraction === 'BLUFOR') {
|
if (!obj[i].fraction) {
|
||||||
|
obj.splice(i, 1);
|
||||||
|
} else if (obj[i].fraction === 'BLUFOR') {
|
||||||
war.playersBlufor++;
|
war.playersBlufor++;
|
||||||
} else {
|
} else {
|
||||||
war.playersOpfor++;
|
war.playersOpfor++;
|
||||||
|
|
|
@ -32,6 +32,7 @@ const awardingRouter = require('./routes/awardings');
|
||||||
const requestRouter = require('./routes/request');
|
const requestRouter = require('./routes/request');
|
||||||
const signatureRouter = require('./routes/signatures');
|
const signatureRouter = require('./routes/signatures');
|
||||||
const commandRouter = require('./routes/command');
|
const commandRouter = require('./routes/command');
|
||||||
|
const campaignRouter = require('./routes/campaigns');
|
||||||
const warRouter = require('./routes/wars');
|
const warRouter = require('./routes/wars');
|
||||||
|
|
||||||
// Configuration ***********************************
|
// Configuration ***********************************
|
||||||
|
@ -79,6 +80,7 @@ app.use(urls.decorations, decorationRouter);
|
||||||
app.use(urls.request, requestRouter);
|
app.use(urls.request, requestRouter);
|
||||||
app.use(urls.awards, awardingRouter);
|
app.use(urls.awards, awardingRouter);
|
||||||
app.use(urls.wars, warRouter);
|
app.use(urls.wars, warRouter);
|
||||||
|
app.use(urls.campaigns,campaignRouter);
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
"start-e2e": "npm run deploy-static && npm run e2e --prefix ./api",
|
"start-e2e": "npm run deploy-static && npm run e2e --prefix ./api",
|
||||||
"test-e2e": "npm run e2e --prefix ./static"
|
"test-e2e": "npm run e2e --prefix ./static"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uglify-js": "^3.0.26"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^3.4.0",
|
"concurrently": "^3.4.0",
|
||||||
"wait-on": "^2.0.2"
|
"wait-on": "^2.0.2"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"uglify-js": "^3.0.26"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -523,12 +523,6 @@
|
||||||
"integrity": "sha1-dMt3+2BS7a/yqJhN2v2I1BnyXKw=",
|
"integrity": "sha1-dMt3+2BS7a/yqJhN2v2I1BnyXKw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/socket.io-client": {
|
|
||||||
"version": "1.4.29",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.29.tgz",
|
|
||||||
"integrity": "sha1-+HQwcM7pMXXjbgtqd6ivc+WMyzI=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"abbrev": {
|
"abbrev": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
|
||||||
|
@ -4865,6 +4859,11 @@
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moment": {
|
||||||
|
"version": "2.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz",
|
||||||
|
"integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8="
|
||||||
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
@ -4894,6 +4893,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
|
||||||
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
|
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
|
||||||
},
|
},
|
||||||
|
"ngx-bootstrap": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-f6l1HmyQPY72bvprKd0yt1WkrEFzynbps8+OvEp4KE0beg/UYPoBXAmPyv7sOtn7grOTBUJJcMO147LEqKjW0Q==",
|
||||||
|
"requires": {
|
||||||
|
"moment": "2.18.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ngx-clipboard": {
|
"ngx-clipboard": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/ngx-clipboard/-/ngx-clipboard-8.0.2.tgz",
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
"jquery": "^3.1.0",
|
"jquery": "^3.1.0",
|
||||||
"jquery-ui": "^1.12.0",
|
"jquery-ui": "^1.12.0",
|
||||||
"jquery-ui-bundle": "^1.11.4",
|
"jquery-ui-bundle": "^1.11.4",
|
||||||
|
"ngx-bootstrap": "^1.8.1",
|
||||||
"ngx-clipboard": "^8.0.2",
|
"ngx-clipboard": "^8.0.2",
|
||||||
"rxjs": "^5.2.0",
|
"rxjs": "^5.2.0",
|
||||||
"ts-helpers": "^1.1.1",
|
"ts-helpers": "^1.1.1",
|
||||||
|
|
|
@ -35,10 +35,11 @@ import {WarService} from "./services/war-service/war.service";
|
||||||
import {DataTableModule} from "angular2-datatable";
|
import {DataTableModule} from "angular2-datatable";
|
||||||
import {NgxChartsModule} from "@swimlane/ngx-charts";
|
import {NgxChartsModule} from "@swimlane/ngx-charts";
|
||||||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||||
|
import {AccordionModule} from "ngx-bootstrap";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [BrowserModule, FormsModule, ReactiveFormsModule, appRouting, HttpModule, ClipboardModule, DataTableModule,
|
imports: [BrowserModule, FormsModule, ReactiveFormsModule, appRouting, HttpModule, ClipboardModule, DataTableModule,
|
||||||
BrowserAnimationsModule, NgxChartsModule],
|
BrowserAnimationsModule, NgxChartsModule, AccordionModule.forRoot()],
|
||||||
providers: [
|
providers: [
|
||||||
HttpClient,
|
HttpClient,
|
||||||
LoginService,
|
LoginService,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="fade-in list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
<div class="fade-in list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-8">
|
||||||
<span>
|
<span>
|
||||||
<a>{{decoration.name}}</a>
|
<a>{{decoration.name}}</a>
|
||||||
</span>
|
</span>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<small> - Sortierung: {{decoration.sortingNumber}}</small>
|
<small> - Sortierung: {{decoration.sortingNumber}}</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-4">
|
||||||
<img src="{{imageSrc}}"
|
<img src="{{imageSrc}}"
|
||||||
[style.max-height]="imgStyle.height"
|
[style.max-height]="imgStyle.height"
|
||||||
[style.max-width]="imgStyle.width"
|
[style.max-width]="imgStyle.width"
|
||||||
|
|
|
@ -11,7 +11,7 @@ export interface User {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
boardUserId?: number;
|
boardUserId?: number;
|
||||||
username?: string;
|
username?: string;
|
||||||
squad?: any; //Squad or string
|
squad?: any; //Squad or id-string
|
||||||
rank?: Rank;
|
rank?: Rank;
|
||||||
awards?: Award[];
|
awards?: Award[];
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,11 @@ export interface Player {
|
||||||
respawn?: number;
|
respawn?: number;
|
||||||
flagTouch?: number;
|
flagTouch?: number;
|
||||||
}
|
}
|
||||||
|
export interface Campaign {
|
||||||
|
_id?: string;
|
||||||
|
title?: string;
|
||||||
|
wars?: War[];
|
||||||
|
}
|
||||||
export interface War {
|
export interface War {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
@ -36,7 +41,8 @@ export interface War {
|
||||||
ptOpfor?: number;
|
ptOpfor?: number;
|
||||||
playersBlufor?: number;
|
playersBlufor?: number;
|
||||||
playersOpfor?: number;
|
playersOpfor?: number;
|
||||||
players: Player[];
|
players?: Player[];
|
||||||
|
campaign?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Squad {
|
export interface Squad {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="fade-in list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
<div class="fade-in list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-8">
|
||||||
<span>
|
<span>
|
||||||
<a>{{rank.name}}</a>
|
<a>{{rank.name}}</a>
|
||||||
</span>
|
</span>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<small> - Stufe {{rank.level}}</small>
|
<small> - Stufe {{rank.level}}</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-4">
|
||||||
<img src="{{imageSrc}}" class="rank-list-preview">
|
<img src="{{imageSrc}}" class="rank-list-preview">
|
||||||
<span (click)="delete(); $event.stopPropagation()" title="Löschen" class="glyphicon glyphicon-trash trash"></span>
|
<span (click)="delete(); $event.stopPropagation()" title="Löschen" class="glyphicon glyphicon-trash trash"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {War} from "../../models/model-interfaces";
|
import {Campaign, War} from "../../models/model-interfaces";
|
||||||
import {AppConfig} from "../../app.config";
|
import {AppConfig} from "../../app.config";
|
||||||
import {HttpClient} from "../http-client";
|
import {HttpClient} from "../http-client";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WarService {
|
export class WarService {
|
||||||
|
|
||||||
|
campaigns :Campaign[];
|
||||||
|
|
||||||
constructor(private http: HttpClient,
|
constructor(private http: HttpClient,
|
||||||
private config: AppConfig) {
|
private config: AppConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllWars() {
|
getAllCampaigns() {
|
||||||
return this.http.get(this.config.apiWarPath)
|
return this.http.get(this.config.apiWarPath)
|
||||||
.map(res => res.json())
|
.map(res => res.json())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="fade-in list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
<div class="fade-in list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-8">
|
||||||
<span>
|
<span>
|
||||||
<a>{{squad.name}}</a>
|
<a>{{squad.name}}</a>
|
||||||
</span>
|
</span>
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<small *ngIf="squad.fraction == 'BLUFOR'">NATO</small>
|
<small *ngIf="squad.fraction == 'BLUFOR'">NATO</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-4">
|
||||||
<img src="{{imageSrc}}" height="50px" class="squad-list-preview">
|
<img src="{{imageSrc}}" height="50px" class="squad-list-preview">
|
||||||
<span (click)="delete(); $event.stopPropagation()" title="Löschen" class="glyphicon glyphicon-trash trash"></span>
|
<span (click)="delete(); $event.stopPropagation()" title="Löschen" class="glyphicon glyphicon-trash trash"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
h3 {
|
|
||||||
width: 920px;
|
|
||||||
margin-left: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-container {
|
.chart-container {
|
||||||
width: 1200px;
|
width: 1200px;
|
||||||
margin-left: 5%;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
<h2>{{title}}</h2>
|
||||||
|
|
||||||
<h3>Punkte</h3>
|
<h3>Punkte</h3>
|
||||||
|
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
import {Component} from "@angular/core";
|
import {Component} from "@angular/core";
|
||||||
import {WarService} from "../../services/war-service/war.service";
|
import {WarService} from "../../services/war-service/war.service";
|
||||||
|
import {Campaign, War} from "../../models/model-interfaces";
|
||||||
|
import {WarListComponent} from "../war-list/war-list.component";
|
||||||
|
import {ActivatedRoute} from "@angular/router";
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'stats-overview',
|
selector: 'stats-overview',
|
||||||
templateUrl: './stats-overview.component.html',
|
templateUrl: './stats-overview.component.html',
|
||||||
styleUrls: ['./stats-overview.component.css']
|
styleUrls: ['./stats-overview.component.css'],
|
||||||
|
inputs: ['campaigns']
|
||||||
})
|
})
|
||||||
export class StatisticOverviewComponent {
|
export class StatisticOverviewComponent {
|
||||||
|
|
||||||
|
title = "";
|
||||||
|
|
||||||
pointData: any[] = [];
|
pointData: any[] = [];
|
||||||
playerData: any[] = [];
|
playerData: any[] = [];
|
||||||
|
|
||||||
|
@ -16,12 +22,40 @@ export class StatisticOverviewComponent {
|
||||||
domain: ['#0000FF', '#B22222']
|
domain: ['#0000FF', '#B22222']
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private warService: WarService) {
|
constructor(private route: ActivatedRoute,
|
||||||
|
private warService: WarService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.warService.getAllWars().subscribe(items => {
|
this.route.params
|
||||||
this.initChart(items);
|
.map(params => params['id'])
|
||||||
|
.subscribe((id) => {
|
||||||
|
if (this.warService.campaigns) {
|
||||||
|
this.initWars(this.warService.campaigns, id);
|
||||||
|
} else {
|
||||||
|
this.warService.getAllCampaigns().subscribe(campaigns => {
|
||||||
|
this.initWars(campaigns, id);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initWars(campaigns, id) {
|
||||||
|
|
||||||
|
let wars = [];
|
||||||
|
let itemsProcessed = 0;
|
||||||
|
campaigns = campaigns.filter(campaign => id === 'all' || campaign._id === id);
|
||||||
|
campaigns.forEach(campaign => {
|
||||||
|
if (id === 'all') {
|
||||||
|
this.title = "Gesamtübersicht"
|
||||||
|
} else {
|
||||||
|
this.title = campaign.title
|
||||||
|
}
|
||||||
|
wars = wars.concat(campaign.wars);
|
||||||
|
itemsProcessed++;
|
||||||
|
if (itemsProcessed === campaigns.length) {
|
||||||
|
this.initChart(wars);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
#left {
|
|
||||||
width: 320px;
|
|
||||||
float: left;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#right {
|
|
||||||
overflow: hidden
|
|
||||||
}
|
|
|
@ -17,7 +17,7 @@ export const statsRoutes: Routes = [{
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'overview',
|
path: 'overview/:id',
|
||||||
component: StatisticOverviewComponent,
|
component: StatisticOverviewComponent,
|
||||||
outlet: 'right'
|
outlet: 'right'
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="overview" xmlns="http://www.w3.org/1999/html">
|
<div class="overview" xmlns="http://www.w3.org/1999/html">
|
||||||
|
|
||||||
<div style="margin-left: 2%; min-height: 263px;">
|
<div style="min-height: 263px;">
|
||||||
<h2>{{war.title}} - vom {{war.date | date: 'dd.MM.yyyy'}}</h2>
|
<h2>{{war.title}} - vom {{war.date | date: 'dd.MM.yyyy'}}</h2>
|
||||||
<h3 class="pull-left">
|
<h3 class="pull-left">
|
||||||
<h4>Endpunktestand:</h4>
|
<h4>Endpunktestand:</h4>
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
<span class="text-opfor" style="font-weight: bold; margin-left: 10px;">{{war.ptOpfor}} CSAT</span>
|
<span class="text-opfor" style="font-weight: bold; margin-left: 10px;">{{war.ptOpfor}} CSAT</span>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<h3 class="pull-left" style="padding-left: 6%;">
|
<h3 class="pull-left">
|
||||||
<h4>Teilnehmer:</h4>
|
<h4>Teilnehmer:</h4>
|
||||||
<ngx-charts-pie-chart
|
<ngx-charts-pie-chart
|
||||||
[view]="[150, 150]"
|
[view]="[150, 150]"
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
</ngx-charts-pie-chart>
|
</ngx-charts-pie-chart>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div style="margin-left: 600px; margin-top:1%">
|
<div style="margin-top:1%">
|
||||||
<a class="btn btn-default" style="margin: 20px" target="_blank" href="resource/logs/{{war._id}}/clean.log">Logfile
|
<a class="btn btn-default" style="margin: 20px" target="_blank" href="resource/logs/{{war._id}}/clean.log">Logfile
|
||||||
anzeigen</a>
|
anzeigen</a>
|
||||||
<form class="form-group">
|
<form class="form-group">
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pull-left" style="margin-left: 2%">
|
<div class="pull-left" >
|
||||||
<div class="table-container scoreboard-table-container">
|
<div class="table-container scoreboard-table-container">
|
||||||
<table class="table table-hover" [mfData]="players" #mf="mfDataTable" [(mfSortBy)]="sortBy"
|
<table class="table table-hover" [mfData]="players" #mf="mfDataTable" [(mfSortBy)]="sortBy"
|
||||||
[(mfSortOrder)]="sortOrder">
|
[(mfSortOrder)]="sortOrder">
|
||||||
|
|
|
@ -6,3 +6,10 @@
|
||||||
.rank-list {
|
.rank-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host /deep/ .card-header {
|
||||||
|
background-color: slategray;
|
||||||
|
padding: 15px;
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
|
@ -5,20 +5,44 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="fade-in list-entry" style="margin-top: 30px; margin-bottom: 30px;" [ngClass]="{selected : selectedWarId == '0'}" (click)="selectOverview()">
|
<div class="fade-in list-entry" style="margin-top: 20px; margin-bottom: 20px;"
|
||||||
|
[ngClass]="{selected : selectedWarId == 'all'}" (click)="selectOverview('all')">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-9">
|
||||||
<span style="margin:auto">
|
<span style="margin:auto">
|
||||||
<a>Zusammenfassung</a>
|
<a>Gesamtübersicht</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<pjm-war-item *ngFor="let war of wars"
|
<accordion *ngFor="let campaign of campaigns">
|
||||||
[war]="war"
|
<accordion-group>
|
||||||
(warDelete)="deleteWar(war)"
|
<div accordion-heading (click)="selectOverview(campaign._id)">
|
||||||
(warSelected)="selectWar($event)"
|
{{campaign.title}}
|
||||||
[selected]="war._id == selectedWarId">
|
<span class="pull-right">▼</span>
|
||||||
</pjm-war-item>
|
</div>
|
||||||
|
|
||||||
|
<div class="fade-in list-entry" style="margin-top: -16px; margin-bottom: 10px;"
|
||||||
|
[ngClass]="{selected : selectedWarId == campaign._id}" (click)="selectOverview(campaign._id)">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-9">
|
||||||
|
<span style="margin:auto">
|
||||||
|
<a>Kampagnenübersicht</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngFor="let war of campaign.wars">
|
||||||
|
<pjm-war-item
|
||||||
|
[war]="war"
|
||||||
|
(warDelete)="deleteWar(war)"
|
||||||
|
(warSelected)="selectWar($event)"
|
||||||
|
[selected]="war._id == selectedWarId">
|
||||||
|
</pjm-war-item>
|
||||||
|
</div>
|
||||||
|
</accordion-group>
|
||||||
|
</accordion>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {Component, OnInit} from "@angular/core";
|
import {Component, OnInit} from "@angular/core";
|
||||||
import {ActivatedRoute, Router} from "@angular/router";
|
import {ActivatedRoute, Router} from "@angular/router";
|
||||||
import {War} from "../../models/model-interfaces";
|
import {Campaign, War} from "../../models/model-interfaces";
|
||||||
import {WarService} from "../../services/war-service/war.service";
|
import {WarService} from "../../services/war-service/war.service";
|
||||||
import {LoginService} from "../../services/login-service/login-service";
|
import {LoginService} from "../../services/login-service/login-service";
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ import {LoginService} from "../../services/login-service/login-service";
|
||||||
})
|
})
|
||||||
export class WarListComponent implements OnInit {
|
export class WarListComponent implements OnInit {
|
||||||
|
|
||||||
selectedWarId: string | number = '0';
|
selectedWarId: string | number = 'all';
|
||||||
|
|
||||||
wars: War[] = [];
|
campaigns: Campaign[] = [];
|
||||||
|
|
||||||
constructor(private warService: WarService,
|
constructor(private warService: WarService,
|
||||||
private loginService: LoginService,
|
private loginService: LoginService,
|
||||||
|
@ -22,9 +22,10 @@ export class WarListComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.warService.getAllWars().subscribe((items) => {
|
this.warService.getAllCampaigns().subscribe((items) => {
|
||||||
this.wars = items;
|
this.warService.campaigns = items;
|
||||||
this.router.navigate([{outlets: {'right': ['overview']}}], {relativeTo: this.route});
|
this.campaigns = items;
|
||||||
|
this.router.navigate([{outlets: {'right': ['overview', 'all']}}], {relativeTo: this.route});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,14 +34,18 @@ export class WarListComponent implements OnInit {
|
||||||
this.router.navigate([{outlets: {'right': ['new']}}], {relativeTo: this.route});
|
this.router.navigate([{outlets: {'right': ['new']}}], {relativeTo: this.route});
|
||||||
}
|
}
|
||||||
|
|
||||||
selectWar(warId: string | number) {
|
selectWar(warId) {
|
||||||
this.selectedWarId = warId;
|
if (this.selectedWarId != warId) {
|
||||||
this.router.navigate([{outlets: {'right': ['war', warId]}}], {relativeTo: this.route});
|
this.selectedWarId = warId;
|
||||||
|
this.router.navigate([{outlets: {'right': ['war', warId]}}], {relativeTo: this.route});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectOverview() {
|
selectOverview(overviewId) {
|
||||||
this.selectedWarId = '0';
|
if (this.selectedWarId != overviewId) {
|
||||||
this.router.navigate([{outlets: {'right': ['overview']}}], {relativeTo: this.route});
|
this.selectedWarId = overviewId;
|
||||||
|
this.router.navigate([{outlets: {'right': ['overview', overviewId]}}], {relativeTo: this.route});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteWar(war: War) {
|
deleteWar(war: War) {
|
||||||
|
@ -48,10 +53,11 @@ export class WarListComponent implements OnInit {
|
||||||
this.warService.deleteWar(war._id)
|
this.warService.deleteWar(war._id)
|
||||||
.subscribe((res) => {
|
.subscribe((res) => {
|
||||||
if (this.selectedWarId === war._id) {
|
if (this.selectedWarId === war._id) {
|
||||||
this.selectOverview();
|
this.selectOverview('all');
|
||||||
}
|
}
|
||||||
this.wars.splice(this.wars.indexOf(war), 1);
|
this.campaigns.splice(this.campaigns.indexOf(war), 1);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,19 @@
|
||||||
<show-error text="Punkte CSAT" path="ptopf"></show-error>
|
<show-error text="Punkte CSAT" path="ptopf"></show-error>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="campaign">Kampagne</label>
|
||||||
|
<select class="form-control"
|
||||||
|
name="campaign"
|
||||||
|
id="campaign"
|
||||||
|
[(ngModel)]="war.campaign"
|
||||||
|
required>
|
||||||
|
<option *ngFor="let campaign of warService.campaigns" [ngValue]="campaign._id">
|
||||||
|
{{campaign.title}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="log">Logfile</label>
|
<label for="log">Logfile</label>
|
||||||
<input id="log" name="log" class="ui-button form-control" type="file"
|
<input id="log" name="log" class="ui-button form-control" type="file"
|
||||||
|
|
|
@ -13,6 +13,7 @@ label {
|
||||||
.overview {
|
.overview {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 25%;
|
width: 25%;
|
||||||
|
min-width: 500px;
|
||||||
border-left: thin solid lightgrey;
|
border-left: thin solid lightgrey;
|
||||||
padding-left: 50px;
|
padding-left: 50px;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
div.list-entry, a.list-entry,
|
div.list-entry, a.list-entry,
|
||||||
div.user-list-entry, a.user-list-entry {
|
div.user-list-entry, a.user-list-entry {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
width: 475px;
|
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
border: lightgrey solid 1px;
|
border: lightgrey solid 1px;
|
||||||
cursor: cell;
|
cursor: cell;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="fade-in user-list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
<div class="fade-in user-list-entry" [ngClass]="{selected : selected}" (click)="select()">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-8">
|
||||||
<span>
|
<span>
|
||||||
<a>{{user.username}}</a>
|
<a>{{user.username}}</a>
|
||||||
</span>
|
</span>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<small *ngIf="!user.squad">ohne Squad/Fraktion</small>
|
<small *ngIf="!user.squad">ohne Squad/Fraktion</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-4">
|
||||||
<span (click)="delete(); $event.stopPropagation()" title="Löschen" class="glyphicon glyphicon-trash trash pull-right"></span>
|
<span (click)="delete(); $event.stopPropagation()" title="Löschen" class="glyphicon glyphicon-trash trash pull-right"></span>
|
||||||
<span (click)="award(); $event.stopPropagation()" title="Auszeichnungen" class="icon-award pull-right"></span>
|
<span (click)="award(); $event.stopPropagation()" title="Auszeichnungen" class="icon-award pull-right"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 4.2 KiB |
|
@ -40,16 +40,14 @@ form {
|
||||||
}
|
}
|
||||||
|
|
||||||
#left {
|
#left {
|
||||||
width:480px;
|
width: 20%;
|
||||||
|
min-width: 350px;
|
||||||
|
max-width: 450px;
|
||||||
float: left;
|
float: left;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
|
|
||||||
}
|
}
|
||||||
#right {
|
#right {
|
||||||
overflow: hidden
|
overflow: hidden;
|
||||||
}
|
padding-left: 4%;
|
||||||
|
|
||||||
.chat-button {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0px;
|
|
||||||
right: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue