Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26fa09541a | ||
|
|
cfbe52efc1 | ||
|
|
a267fedaef | ||
|
|
d6cb0fc78f | ||
|
|
1fbbbde1a1 | ||
|
|
08721bb810 | ||
|
|
68d2bef6ba | ||
|
|
5199cabd26 | ||
|
|
59546838ac | ||
|
|
4740163572 | ||
|
|
22af7f903e | ||
|
|
e921182575 |
2
dist/qmi-cloud/index.html
vendored
2
dist/qmi-cloud/index.html
vendored
@@ -9,5 +9,5 @@
|
||||
<link rel="stylesheet" href="styles.529f751cbb5308365172.css"></head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<script src="runtime.689ba4fd6cadb82c1ac2.js" defer></script><script src="polyfills-es5.f752a17531a45fe93c1f.js" nomodule defer></script><script src="polyfills.06ba8d1a3d9dd3a8e8b9.js" defer></script><script src="scripts.6866cf66954a0b739d41.js" defer></script><script src="main.b7d3a2d901b927013a9e.js" defer></script></body>
|
||||
<script src="runtime.689ba4fd6cadb82c1ac2.js" defer></script><script src="polyfills-es5.f752a17531a45fe93c1f.js" nomodule defer></script><script src="polyfills.06ba8d1a3d9dd3a8e8b9.js" defer></script><script src="scripts.6866cf66954a0b739d41.js" defer></script><script src="main.e4269137677fbcdfe029.js" defer></script></body>
|
||||
</html>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -83,6 +83,7 @@ services:
|
||||
- REDIS_URL=redis://redis
|
||||
- MONGO_URI=mongodb://root:example@mongo/qmicloud?authSource=admin
|
||||
- PROJECT_PATH=${PWD}
|
||||
- GIT_SCENARIOS=git::git@gitlab.com:qmi/qmi-cloud-scenarios.git
|
||||
- SSHPATH=/Users/aor/.ssh
|
||||
command: "sh -c 'npm run worker:dev'"
|
||||
volumes:
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
branch=master
|
||||
rm -fr ./az-tf-templates
|
||||
git clone -b $branch git@gitlab.com:qmi/qmi-cloud-scenarios.git ./az-tf-templates
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "qmi-cloud",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.12",
|
||||
"scripts": {
|
||||
"start": "node -r esm server/server.js",
|
||||
"dev": "nodemon -r esm server/server.js",
|
||||
|
||||
@@ -6,8 +6,8 @@ if ( myArgs.length < 3 ) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
var db = require('./mongo');
|
||||
const sendEmail = require("./send-email");
|
||||
var db = require('../mongo');
|
||||
const sendEmail = require("../send-email");
|
||||
const moment = require('moment');
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
@@ -36,7 +36,7 @@ async function postDestroy(provision) {
|
||||
}
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(json => console.log(json));
|
||||
.then(json => console.log(json));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ const RUNNING_PERIOD = myArgs[1]; //Days
|
||||
const RUNNING_LIMIT_HOURS_WARNING = 24*(RUNNING_PERIOD-1);
|
||||
const RUNNING_LIMIT_HOURS_STOP = 24*RUNNING_PERIOD;
|
||||
|
||||
var db = require('./mongo');
|
||||
const sendEmail = require("./send-email");
|
||||
var db = require('../mongo');
|
||||
const sendEmail = require("../send-email");
|
||||
const moment = require('moment');
|
||||
const azurecli = require('./azurecli');
|
||||
const azurecli = require('../azurecli');
|
||||
|
||||
function timeRunning(p) {
|
||||
let runningFromTime = p.runningFrom? new Date(p.runningFrom).getTime() : new Date(p.created).getTime();
|
||||
@@ -14,7 +14,10 @@ const userSchema = new mongoose.Schema({
|
||||
},
|
||||
displayName: String,
|
||||
upn: String,
|
||||
oid: String,
|
||||
oid: {
|
||||
type: String,
|
||||
index: true
|
||||
},
|
||||
role: {
|
||||
type: String,
|
||||
default: "user"
|
||||
|
||||
@@ -5,7 +5,8 @@ mongoose.set('useFindAndModify', false);
|
||||
|
||||
const userSchema = new mongoose.Schema({
|
||||
type: String,
|
||||
desc: String
|
||||
desc: String,
|
||||
costHour: Number
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -53,27 +53,42 @@ const getNewTimeRunning = function (provision) {
|
||||
return Math.floor(minutesFromLastRunning + timeRunning);
|
||||
};
|
||||
|
||||
const get = async (model, filter, extras, reply) => {
|
||||
var sort = extras && extras.sort? extras.sort : {created: -1};
|
||||
|
||||
|
||||
const get = async (model, filter, skip, limit, reply) => {
|
||||
var sort = {created: -1};
|
||||
try {
|
||||
var exec = model.find(filter).sort(sort);
|
||||
var totalDocs = await model.countDocuments(filter);
|
||||
|
||||
if ( extras && extras.skip ) {
|
||||
exec = exec.skip(extras.skip);
|
||||
}
|
||||
if ( extras && extras.limit ) {
|
||||
exec = exec.limit(extras.limit);
|
||||
skip = skip? parseInt(skip) : 0;
|
||||
exec = exec.skip(skip);
|
||||
|
||||
if ( limit ) {
|
||||
limit = parseInt(limit);
|
||||
exec = exec.limit(limit);
|
||||
}
|
||||
|
||||
if ( model === Provision ) {
|
||||
exec = exec.populate({ path: 'user', select: 'displayName upn'}).populate('destroy');
|
||||
}
|
||||
|
||||
if ( model === ApiKey ) {
|
||||
exec = exec.populate('user');
|
||||
}
|
||||
|
||||
const entity = await exec;
|
||||
|
||||
return {
|
||||
total: await model.countDocuments(filter),
|
||||
var out = {
|
||||
total: totalDocs,
|
||||
count: entity.length,
|
||||
results: entity
|
||||
};
|
||||
}
|
||||
if ( limit && (skip + limit) < totalDocs) {
|
||||
out.nextSkip = skip+limit;
|
||||
out.nextLimit = limit;
|
||||
}
|
||||
return out;
|
||||
|
||||
} catch (err) {
|
||||
throw boom.boomify(err)
|
||||
}
|
||||
@@ -85,6 +100,9 @@ const getById = async (model, id, reply) => {
|
||||
if ( model === Provision ) {
|
||||
exec = exec.populate({ path: 'user', select: 'displayName upn'}).populate('destroy');
|
||||
}
|
||||
if ( model === ApiKey ) {
|
||||
exec = exec.populate('user');
|
||||
}
|
||||
const entity = await exec;
|
||||
return entity;
|
||||
} catch (err) {
|
||||
@@ -98,6 +116,9 @@ const getOne = async (model, filter, reply) => {
|
||||
if ( model === Provision ) {
|
||||
exec = exec.populate('user').populate('destroy');
|
||||
}
|
||||
if ( model === ApiKey ) {
|
||||
exec = exec.populate('user');
|
||||
}
|
||||
const entity = await exec;
|
||||
return entity;
|
||||
} catch (err) {
|
||||
@@ -141,8 +162,8 @@ const del = async (model, id, reply) => {
|
||||
|
||||
function _m(model) {
|
||||
return {
|
||||
get: async (filter, extras, reply) => {
|
||||
return get(model, filter, extras, reply);
|
||||
get: async (filter, skip, limit, reply) => {
|
||||
return get(model, filter, skip, limit, reply);
|
||||
},
|
||||
getById: async (id, reply) => {
|
||||
return getById(model, id, reply);
|
||||
|
||||
@@ -82,18 +82,18 @@ passport.use(new OIDCStrategy({
|
||||
if ( !profile.oid ) {
|
||||
return done(new Error("No oid found"), null);
|
||||
}
|
||||
console.log("accessToken", accessToken);
|
||||
console.log("iss", iss);
|
||||
console.log("sub", sub);
|
||||
console.log("refreshToken", refreshToken);
|
||||
console.log("jwtClaims", jwtClaims);
|
||||
console.log("params", params);
|
||||
console.log("profile", profile);
|
||||
//console.log("accessToken", accessToken);
|
||||
//console.log("iss", iss);
|
||||
//console.log("sub", sub);
|
||||
//console.log("refreshToken", refreshToken);
|
||||
//console.log("jwtClaims", jwtClaims);
|
||||
//console.log("params", params);
|
||||
console.log("New Auth: profile", profile);
|
||||
// asynchronous verification, for effect...
|
||||
process.nextTick(function () {
|
||||
_findByOid(profile.oid, async function(err, user) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
return done(err);
|
||||
}
|
||||
if (!user) {
|
||||
// "Auto-registration"
|
||||
@@ -198,13 +198,16 @@ module.exports.init = function(app){
|
||||
};
|
||||
|
||||
async function isApiKeyAuthenticated(req) {
|
||||
if (req.query && req.query.apiKey){
|
||||
if (req.query && req.query.apiKey){
|
||||
let key = req.query.apiKey;
|
||||
var result = await db.apiKey.get({apiKey: key});
|
||||
if ( result.length > 0 ) {
|
||||
req.user = result[0].user;
|
||||
var result = await db.apiKey.getOne({"apiKey": key});
|
||||
if ( result ) {
|
||||
req.user = result.user;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return result.length > 0;
|
||||
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
|
||||
28
server/routes/api-notifications.js
Normal file
28
server/routes/api-notifications.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('../mongo');
|
||||
const passport = require('../passport');
|
||||
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /notifications:
|
||||
* get:
|
||||
* description: Get all notifications (Only admin)
|
||||
* summary: Get all notifications (Only admin)
|
||||
* produces:
|
||||
* - application/json
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Notifications
|
||||
*/
|
||||
router.get('/', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {
|
||||
try {
|
||||
const result = await db.notification.get();
|
||||
return res.json(result);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -22,28 +22,44 @@ const fs = require('fs-extra');
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* - name: extras
|
||||
* - name: skip
|
||||
* in: query
|
||||
* required: false
|
||||
* type: object
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* type: integer
|
||||
* - name: limit
|
||||
* in: query
|
||||
* required: false
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: JSON Array
|
||||
*/
|
||||
router.get('/', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {
|
||||
|
||||
|
||||
try {
|
||||
let filter = req.query.filter? JSON.parse(req.query.filter) : {};
|
||||
if ( filter.isDeleted === undefined ) {
|
||||
filter.isDeleted = false;
|
||||
}
|
||||
let extras = req.query.extras? JSON.parse(req.query.extras) : {};
|
||||
const result = await db.provision.get(filter, extras);
|
||||
return res.json(result);
|
||||
|
||||
const result = await db.provision.get(filter, req.query.skip, req.query.limit);
|
||||
|
||||
var out = {
|
||||
total: result.total,
|
||||
count: result.count
|
||||
};
|
||||
if ( result.nextSkip && result.nextLimit ) {
|
||||
out.nextUrl = new URL(req.protocol + '://' + req.get('Host') + req.baseUrl);
|
||||
if ( req.query.filter ) {
|
||||
out.nextUrl.searchParams.append("filter", req.query.filter);
|
||||
}
|
||||
out.nextUrl.searchParams.append("skip", result.nextSkip);
|
||||
out.nextUrl.searchParams.append("limit", result.nextLimit);
|
||||
}
|
||||
out.results = result.results;
|
||||
|
||||
return res.json(out);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ const routesApiScenarios = require('./routes/api-scenarios');
|
||||
const routesApiUsers = require('./routes/api-users');
|
||||
const routesApiProvisions = require('./routes/api-provisions');
|
||||
const routesApiDestroyProvisions = require('./routes/api-destroyprovisions');
|
||||
const routesApiNotifications = require('./routes/api-notifications');
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
const swaggerJsdoc = require('swagger-jsdoc');
|
||||
const cookieParser = require('cookie-parser');
|
||||
@@ -75,6 +76,7 @@ app.use("/api/v1/scenarios", routesApiScenarios);
|
||||
app.use("/api/v1/users", routesApiUsers);
|
||||
app.use("/api/v1/provisions", routesApiProvisions);
|
||||
app.use("/api/v1/destroyprovisions", routesApiDestroyProvisions);
|
||||
app.use("/api/v1/notifications", routesApiNotifications);
|
||||
|
||||
app.get('/*',(req, res, next) =>{
|
||||
if (req.originalUrl.indexOf("/api-docs") !== -1 || req.originalUrl.indexOf("/arena") !== -1 ) {
|
||||
@@ -147,6 +149,7 @@ const options = {
|
||||
'server/routes/api-users.js',
|
||||
'server/routes/api-provisions.js',
|
||||
'server/routes/api-destroyprovisions.js',
|
||||
'server/routes/api-notifications.js',
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@@ -2,10 +2,9 @@ const Docker = require('dockerode');
|
||||
const docker = new Docker({
|
||||
'socketPath': '/home/docker.sock'
|
||||
});
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const PROJECT_PATH = process.env.PROJECT_PATH;
|
||||
const DOCKERIMAGE = "qlikgear/terraform:1.0.0";
|
||||
const GIT_SCENARIOS = process.env.GIT_SCENARIOS;
|
||||
const DOCKERIMAGE = "qlikgear/terraform:1.0.1";
|
||||
const SSHPATH = process.env.SSHPATH;
|
||||
|
||||
function hook_stdout(callback) {
|
||||
@@ -60,11 +59,10 @@ function _buildExec( exec, provision ) {
|
||||
|
||||
const init = function( provMongo ) {
|
||||
|
||||
const templatePath = path.join(PROJECT_PATH, 'az-tf-templates', provMongo.scenario);
|
||||
const name = `qmi-tf-init-${provMongo._id}`;
|
||||
console.log(`Init: will spin up container: ${name}`);
|
||||
var processStream = fs.createWriteStream(provMongo.logFile, {flags:'a'});
|
||||
let exec = ['terraform', 'init', '-no-color', '-from-module=/template'];
|
||||
let exec = ['terraform', 'init', '-no-color', `-from-module=${GIT_SCENARIOS}//${provMongo.scenario}`];
|
||||
console.log('Init: exec: '+exec.join(" "));
|
||||
|
||||
return docker.run(DOCKERIMAGE, exec, processStream, {
|
||||
@@ -73,8 +71,7 @@ const init = function( provMongo ) {
|
||||
"WorkingDir": "/app",
|
||||
"HostConfig": {
|
||||
"Binds": [
|
||||
`${provMongo.path}:/app`,
|
||||
`${templatePath}:/template`
|
||||
`${provMongo.path}:/app`
|
||||
]
|
||||
}
|
||||
}).then(function(data) {
|
||||
|
||||
5
shell-utils/checkdestroy.sh
Executable file
5
shell-utils/checkdestroy.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
BASEDIR=$(dirname "$0")
|
||||
d=`date`
|
||||
echo "------ $d"
|
||||
echo "------ TYPE: $1"
|
||||
MONGO_URI=mongodb://root:example@localhost:27017/qmicloud?authSource=admin API_KEY="c229219ccdd72d11e8ea253fd3876d247e5f489c9c84922cabdfb0cc194d8ff398a8d8d6528d8241efc99add2207e0ec75122a1b2c5598cc340cbe6b7c3c0dbf" node $BASEDIR/../server/cronjobs/destroy5.js $1 $2 $3
|
||||
@@ -1,4 +1,5 @@
|
||||
BASEDIR=$(dirname "$0")
|
||||
d=`date`
|
||||
echo "------ $d"
|
||||
MONGO_URI=mongodb://root:example@localhost:27017/qmicloud?authSource=admin node $BASEDIR/stop5.js $1 $2 $3
|
||||
echo "------ TYPE: $1"
|
||||
MONGO_URI=mongodb://root:example@localhost:27017/qmicloud?authSource=admin node $BASEDIR/../server/cronjobs/stop5.js $1 $2 $3
|
||||
6
shell-utils/mongodump.sh
Executable file
6
shell-utils/mongodump.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
id=`docker ps | grep 'mongo:4.2' | awk '{ print $1 }'`
|
||||
d=$(date +%Y-%m-%d-T%H:%M:%S%z)
|
||||
|
||||
docker exec $id sh -c 'exec mongodump --uri="mongodb://root:example@mongo/qmicloud?authSource=admin" --archive' > $1/qmicloud-$d.archive
|
||||
@@ -1,12 +1,6 @@
|
||||
<ul style="margin-top: 80px;" class="nav nav-pills nav-fill">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" (click)="tabSelect($event, 'Provisions')" [ngClass]="{'active': tab === 'Provisions'}">Provisions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" (click)="tabSelect($event, 'Users')" [ngClass]="{'active': tab === 'Users'}">Users</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" (click)="tabSelect($event, 'Scenarios')" [ngClass]="{'active': tab === 'Scenarios'}">Scenarios</a>
|
||||
<li *ngFor="let item of sections; let i = index" class="nav-item">
|
||||
<a class="nav-link" (click)="tabSelect($event, item)" [ngClass]="{'active': tab === item}">{{item}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -24,4 +18,9 @@
|
||||
<!--<h1>Scenarios</h1>-->
|
||||
<table-scenarios></table-scenarios>
|
||||
</div>
|
||||
|
||||
<div *ngIf="tab === 'Notifications'">
|
||||
<!--<h1>Scenarios</h1>-->
|
||||
<table-notifications></table-notifications>
|
||||
</div>
|
||||
<qmi-alert></qmi-alert>
|
||||
|
||||
@@ -7,22 +7,18 @@ import { Component, OnInit } from '@angular/core';
|
||||
})
|
||||
export class AdminComponent implements OnInit {
|
||||
|
||||
sections = ['Provisions', 'Users', 'Scenarios', 'Notifications'];
|
||||
tab : string = 'Provisions';
|
||||
|
||||
|
||||
constructor() { }
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
|
||||
tabSelect($event, tab) {
|
||||
$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
|
||||
this.tab = tab;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { TableProvisionsAdminComponent } from './tables/table-provisions.component';
|
||||
import { TableScenariosComponent } from './tables/table-scenarios.component';
|
||||
import { TableUsersComponent } from './tables/table-users.component';
|
||||
import { TableNotificationsComponent } from './tables/table-notifications.component';
|
||||
import { AlertComponent } from './alert/alert.component';
|
||||
import { AlertService } from './services/alert.service';
|
||||
import { ModalInfoComponent } from './alert/modalinfo.component';
|
||||
@@ -60,7 +61,8 @@ export function markedOptions(): MarkedOptions {
|
||||
FilterPipe,
|
||||
FaqComponent,
|
||||
NewProvisionConfirmComponent,
|
||||
TableScenariosComponent
|
||||
TableScenariosComponent,
|
||||
TableNotificationsComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@@ -21,4 +21,8 @@ export class UsersService {
|
||||
updateUser(userId, patchData): Observable<any> {
|
||||
return this.httpClient.put(`${environment.apiVersionPath}/users/${userId}`, patchData);
|
||||
}
|
||||
|
||||
getNotifications(): Observable<any> {
|
||||
return this.httpClient.get(`${environment.apiVersionPath}/notifications`);
|
||||
}
|
||||
}
|
||||
|
||||
40
src/app/tables/table-notifications.component.html
Normal file
40
src/app/tables/table-notifications.component.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<div class="md-form">
|
||||
<input type="text" class="form-control w-25" [(ngModel)]="searchText" (keyup)="searchItems()" id="search-input2"
|
||||
mdbInput>
|
||||
<label for="search-input2">Search</label>
|
||||
</div>
|
||||
<div style="padding: 5px 0px;">
|
||||
<button *ngIf="loading" mdbBtn color="grey" outline="true" type="button" size="sm" disabled mdbWavesEffect>
|
||||
<span>Refreshing...</span>
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button *ngIf="!loading" (click)="refreshData();" mdbBtn type="button" size="sm" color="grey" outline="true" mdbWavesEffect>
|
||||
Refresh<mdb-icon fas icon="redo-alt" class="ml-1" ></mdb-icon>
|
||||
</button>
|
||||
<span *ngIf="elements && elements.length">Total: {{elements.length}}</span>
|
||||
</div>
|
||||
<table mdbTable #tableEl="mdbTable" stickyHeader="true" hover="true" class="z-depth-1 table table-sm">
|
||||
<thead class="sticky-top">
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Type</th>
|
||||
<th>Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of elements; let i = index">
|
||||
<th *ngIf="i+1 >= mdbTablePagination.firstItemIndex && i < mdbTablePagination.lastItemIndex"
|
||||
scope="row">{{item.created | date: 'MMM dd, yyyy - H:mm'}}</th>
|
||||
<th *ngIf="i+1 >= mdbTablePagination.firstItemIndex && i < mdbTablePagination.lastItemIndex"
|
||||
scope="row">{{item.type}}</th>
|
||||
<td *ngIf="i+1 >= mdbTablePagination.firstItemIndex && i < mdbTablePagination.lastItemIndex">{{item.message}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="grey lighten-5 w-100">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<mdb-table-pagination [tableEl]="tableEl" [searchDataSource]="elements"></mdb-table-pagination>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
0
src/app/tables/table-notifications.component.scss
Normal file
0
src/app/tables/table-notifications.component.scss
Normal file
82
src/app/tables/table-notifications.component.ts
Normal file
82
src/app/tables/table-notifications.component.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { MdbTablePaginationComponent, MdbTableDirective } from 'angular-bootstrap-md';
|
||||
|
||||
import { Component, OnInit, ViewChild, HostListener, AfterViewInit, ChangeDetectorRef } from '@angular/core';
|
||||
import { UsersService } from '../services/users.service';
|
||||
|
||||
@Component({
|
||||
selector: 'table-notifications',
|
||||
templateUrl: './table-notifications.component.html',
|
||||
styleUrls: ['./table-notifications.component.scss']
|
||||
})
|
||||
export class TableNotificationsComponent implements OnInit, AfterViewInit {
|
||||
|
||||
@ViewChild(MdbTablePaginationComponent, { static: true }) mdbTablePagination: MdbTablePaginationComponent;
|
||||
@ViewChild(MdbTableDirective, { static: true }) mdbTable: MdbTableDirective;
|
||||
|
||||
previous: any = [];
|
||||
searchText: string = '';
|
||||
maxVisibleItems: number = 25;
|
||||
|
||||
loading: boolean = false;
|
||||
elements = [];
|
||||
|
||||
@HostListener('input') oninput() {
|
||||
this.mdbTablePagination.searchText = this.searchText;
|
||||
}
|
||||
|
||||
constructor(private cdRef: ChangeDetectorRef, private _usersService: UsersService) {
|
||||
}
|
||||
|
||||
private _initElements(): void {
|
||||
this.mdbTable.setDataSource(this.elements);
|
||||
this.elements = this.mdbTable.getDataSource();
|
||||
this.previous = this.mdbTable.getDataSource();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
refreshData() {
|
||||
this.loading = true;
|
||||
this.searchText = "";
|
||||
var sub = this._usersService.getNotifications().subscribe( res => {
|
||||
sub.unsubscribe();
|
||||
this.elements = res.results;
|
||||
this.loading = false;
|
||||
this._initElements();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
||||
this.mdbTablePagination.setMaxVisibleItemsNumberTo(this.maxVisibleItems);
|
||||
|
||||
this.mdbTablePagination.calculateFirstItemIndex();
|
||||
this.mdbTablePagination.calculateLastItemIndex();
|
||||
this.cdRef.detectChanges();
|
||||
}
|
||||
|
||||
searchItems() {
|
||||
const prev = this.mdbTable.getDataSource();
|
||||
|
||||
if (!this.searchText) {
|
||||
this.mdbTable.setDataSource(this.previous);
|
||||
this.elements = this.mdbTable.getDataSource();
|
||||
}
|
||||
|
||||
if (this.searchText) {
|
||||
this.elements = this.mdbTable.searchLocalDataBy(this.searchText);
|
||||
this.mdbTable.setDataSource(prev);
|
||||
}
|
||||
|
||||
this.mdbTablePagination.calculateFirstItemIndex();
|
||||
this.mdbTablePagination.calculateLastItemIndex();
|
||||
|
||||
this.mdbTable.searchDataObservable(this.searchText).subscribe(() => {
|
||||
this.mdbTablePagination.calculateFirstItemIndex();
|
||||
this.mdbTablePagination.calculateLastItemIndex();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,16 @@
|
||||
<label for="search-input">Search</label>
|
||||
</div>
|
||||
|
||||
<p *ngIf="elements && elements.length">Total: {{elements.length}}</p>
|
||||
<div style="padding: 5px 0px;">
|
||||
<button *ngIf="loading" mdbBtn color="grey" outline="true" type="button" size="sm" disabled mdbWavesEffect>
|
||||
<span>Refreshing...</span>
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button *ngIf="!loading" (click)="refreshData();" mdbBtn type="button" size="sm" color="grey" outline="true" mdbWavesEffect>
|
||||
Refresh<mdb-icon fas icon="redo-alt" class="ml-1" ></mdb-icon>
|
||||
</button>
|
||||
<span *ngIf="elements && elements.length">Total: {{elements.length}}</span>
|
||||
</div>
|
||||
|
||||
<table mdbTable #tableEl="mdbTable" stickyHeader="true" hover="true" class="z-depth-1 table table-sm">
|
||||
<thead class="sticky-top">
|
||||
|
||||
@@ -15,7 +15,6 @@ import { ScenariosService } from '../services/scenarios.service';
|
||||
export class TableProvisionsAdminComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
|
||||
scenarios;
|
||||
provisions;
|
||||
subscription: Subscription;
|
||||
filter = {
|
||||
showDestroyed : false
|
||||
@@ -23,6 +22,7 @@ export class TableProvisionsAdminComponent implements OnInit, OnDestroy, AfterVi
|
||||
filterParams : any = {
|
||||
isDestroyed: false
|
||||
};
|
||||
loading: boolean = false;
|
||||
|
||||
pagingIsDisabled: Boolean = false;
|
||||
|
||||
@@ -63,10 +63,10 @@ export class TableProvisionsAdminComponent implements OnInit, OnDestroy, AfterVi
|
||||
p._scenario = this.scenarios.filter(s => s.name === p.scenario);
|
||||
this._provisionsService.timeRunning(p);
|
||||
});
|
||||
if ( !this.provisions ) {
|
||||
this.provisions = provisions;
|
||||
if ( this.elements.length === 0 ) {
|
||||
this.elements = provisions;
|
||||
} else {
|
||||
this.provisions.forEach( function(p, index, object) {
|
||||
this.elements.forEach( function(p, index, object) {
|
||||
let found = provisions.filter(a=>a._id.toString() === p._id.toString());
|
||||
if ( found.length ) {
|
||||
p.status = found[0].status;
|
||||
@@ -81,14 +81,13 @@ export class TableProvisionsAdminComponent implements OnInit, OnDestroy, AfterVi
|
||||
}.bind(this));
|
||||
|
||||
provisions.forEach(function(p) {
|
||||
let found = this.provisions.filter(a=>a._id.toString() === p._id.toString());
|
||||
let found = this.elements.filter(a=>a._id.toString() === p._id.toString());
|
||||
if (found.length === 0){
|
||||
this.provisions.unshift(p);
|
||||
this.elements.unshift(p);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
this.elements = this.provisions;
|
||||
this._initElements();
|
||||
|
||||
}
|
||||
@@ -99,9 +98,12 @@ export class TableProvisionsAdminComponent implements OnInit, OnDestroy, AfterVi
|
||||
scenariosSub.unsubscribe();
|
||||
this.scenarios = res.results;
|
||||
|
||||
this.subscription = timer(0, 8000).pipe( switchMap(() => this._provisionsService.getProvisionsAdmin(this.filterParams) ) ).subscribe(provisions => {
|
||||
/*this.subscription = timer(0, 8000).pipe( switchMap(() => this._provisionsService.getProvisionsAdmin(this.filterParams) ) ).subscribe(provisions => {
|
||||
this._process(provisions.results);
|
||||
});
|
||||
});*/
|
||||
|
||||
this.refreshData();
|
||||
|
||||
});
|
||||
|
||||
//this._initElements();
|
||||
@@ -289,11 +291,14 @@ export class TableProvisionsAdminComponent implements OnInit, OnDestroy, AfterVi
|
||||
});
|
||||
}
|
||||
|
||||
private _refresh(): void {
|
||||
this.provisions = null;
|
||||
refreshData() {
|
||||
this.elements = [];
|
||||
this.loading = true;
|
||||
this.searchText = "";
|
||||
var instantSubs = this._provisionsService.getProvisionsAdmin(this.filterParams).subscribe( provisions=>{
|
||||
instantSubs.unsubscribe();
|
||||
this._process(provisions.results);
|
||||
this.loading = false;
|
||||
this._process(provisions.results);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -302,7 +307,7 @@ export class TableProvisionsAdminComponent implements OnInit, OnDestroy, AfterVi
|
||||
if ( !this.filter.showDestroyed ) {
|
||||
this.filterParams.isDestroyed = false;
|
||||
}
|
||||
this._refresh();
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,16 @@
|
||||
mdbInput>
|
||||
<label for="search-input2">Search</label>
|
||||
</div>
|
||||
<div style="padding: 5px 0px;">
|
||||
<button *ngIf="loading" mdbBtn color="grey" outline="true" type="button" size="sm" disabled mdbWavesEffect>
|
||||
<span>Refreshing...</span>
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button *ngIf="!loading" (click)="refreshData();" mdbBtn type="button" size="sm" color="grey" outline="true" mdbWavesEffect>
|
||||
Refresh<mdb-icon fas icon="redo-alt" class="ml-1" ></mdb-icon>
|
||||
</button>
|
||||
<span *ngIf="elements && elements.length">Total: {{elements.length}}</span>
|
||||
</div>
|
||||
<table mdbTable #tableEl="mdbTable" stickyHeader="true" hover="true" class="z-depth-1 table table-sm">
|
||||
<thead class="sticky-top">
|
||||
<tr>
|
||||
|
||||
@@ -19,7 +19,7 @@ export class TableUsersComponent implements OnInit, AfterViewInit {
|
||||
maxVisibleItems: number = 25;
|
||||
|
||||
currentUser;
|
||||
|
||||
loading: boolean = false;
|
||||
elements = [];
|
||||
|
||||
@HostListener('input') oninput() {
|
||||
@@ -39,12 +39,18 @@ export class TableUsersComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
refreshData() {
|
||||
this.loading = true;
|
||||
this.searchText = "";
|
||||
var usersSub = this._usersService.getUsers().subscribe( res => {
|
||||
usersSub.unsubscribe();
|
||||
this.elements = res.results;
|
||||
this.loading = false;
|
||||
this._initElements();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
BASEDIR=$(dirname "$0")
|
||||
|
||||
branch=master
|
||||
|
||||
cd $BASEDIR/az-tf-templates
|
||||
git checkout master
|
||||
git checkout .
|
||||
git pull origin $branch
|
||||
cd $BASEDIR
|
||||
Reference in New Issue
Block a user