Skip to content
Snippets Groups Projects
Commit 85457c94 authored by Ulf Seltmann's avatar Ulf Seltmann
Browse files

added angular2 frontend framework for admin interface

parent c3b727e1
No related merge requests found
Showing
with 5417 additions and 181 deletions
/node_modules
/lib/*
/data/*
\ No newline at end of file
/dist/*
/public/*
/data/*
/.git*
/docker-compose.yml
/data
/.vscode
/docs
/mkdocs.yml
/tsconfig.json
/webpack.*.js
/src
\ No newline at end of file
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "attach",
"port": 9222,
"name": "Attach to Chrome",
"url": "http://localhost:3000/admin/",
"webRoot": "${workspaceRoot}"
},
{
"name": "Docker: Attach to Node",
"type": "node",
......
# decap
# dacap
*Dynamic And Compressing Api Proxy* is a service which lets you proxy arbitrary API-Endpoints which are by themself to slow to be used in production environments. All cached Responses are held in memory, so be sure to provide enough.
## requirements
* node >= v8.2.1
* npm >= v5.3.0
## file a bug
Dynamic and compressing api proxy
# register new endpoint
......
site_name: DynamicAndCompressingApiCache
site_name: dacap
This diff is collapsed.
{
"name": "decap",
"name": "dacap",
"version": "1.0.0",
"description": "proxies,compresses and caches api-requests",
"main": "lib/index.js",
"main": "dist/index.js",
"directories": {
"test": "test"
},
"scripts": {
"prepublish": "tsc",
"start": "node lib/index.js",
"webpack-watch": "webpack --config webpack.dev.js --watch",
"start": "node dist/index.js",
"tsc": "tsc",
"inspect": "tsc-watch --onSuccess 'node --inspect=0.0.0.0:9229 lib/index.js'",
"inspect-brk": "tsc-watch --onSuccess 'node --inspect-brk=0.0.0.0:9229 lib/index.js'",
"test": "mocha test"
"inspect-watch": "tsc-watch --sourceMap --onSuccess 'node --inspect=0.0.0.0:9229 dist/index.js'",
"inspect-brk-watch": "tsc-watch --onSuccess 'node --inspect-brk=0.0.0.0:9229 dist/index.js'",
"test": "mocha test",
"build": "rm -rf dist public && tsc --declaration && webpack --config webpack.prod.js"
},
"author": "Ulf Seltmann <ulf.seltmann@uni-leipzig.de>",
"license": "GPL-2.0",
"dependencies": {
"@types/node-cache": "^4.1.0",
"@angular/common": "^4.3.5",
"@angular/compiler": "^4.3.5",
"@angular/core": "^4.3.5",
"@angular/forms": "^4.3.5",
"@angular/http": "^4.3.5",
"@angular/platform-browser": "^4.3.5",
"@angular/platform-browser-dynamic": "^4.3.5",
"@angular/router": "^4.3.5",
"body-parser": "^1.17.2",
"compression": "^1.7.0",
"core-js": "^2.5.0",
"debug": "^3.0.0",
"express": "^4.15.4",
"node-cache": "^4.1.4",
"node-cache": "^4.1.5",
"q": "^1.5.0",
"request": "^2.81.0"
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-proxy-loader": "^0.3.5",
"request": "^2.81.0",
"rxjs": "^5.4.3",
"zone.js": "^0.8.16"
},
"devDependencies": {
"@types/body-parser": "^1.16.5",
"@types/compression": "0.0.33",
"@types/debug": "0.0.30",
"@types/express": "^4.0.36",
"@types/node": "^8.0.20",
"@types/node-cache": "^4.1.0",
"@types/react": "^16.0.2",
"@types/react-dom": "^15.5.3",
"@types/request": "^2.0.1",
"angular2-template-loader": "^0.6.2",
"awesome-typescript-loader": "^3.2.3",
"bootstrap": "^3.3.7",
"css-loader": "^0.28.5",
"eslint": "^4.4.1",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"html-loader": "^0.5.1",
"html-webpack-plugin": "^2.30.1",
"jquery": "^3.2.1",
"source-map-loader": "^0.2.1",
"style-loader": "^0.18.2",
"tsc-watch": "^1.0.7",
"typescript": "^2.4.2"
"typescript": "^2.4.2",
"webpack": "^3.5.5",
"webpack-merge": "^4.1.0"
}
}
<div class="container">
<div class="panel panel-success">
<div class="panel-heading">
<h3>Add new Cache</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<label for="api-endpoint">Api-Endpoint:</label>
<div class="input-group">
<input id="api-endpoint" type="text" class="form-control" size="200" [(ngModel)]="apiEndPoint">
</div>
</div>
<div class="col-md-6">
<label for="cache-name">Cache-Name</label>
<div class="input-group">
<span class="input-group-addon" id="basic-addon3">{{proxyUrl}}</span>
<input id="cache-name" type="text" class="form-control" aria-describedby="basic-addon3" [(ngModel)]="name">
<div class="input-group-btn">
<button type="button" class="btn btn-primary" (click)="submit()">Add</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
import { Component, Output, EventEmitter } from '@angular/core';
import { CacheService } from './cache.service';
import { Cache } from './cache';
@Component({
selector: 'add-cache',
templateUrl: './add-cache.component.html'
})
export class AddCacheComponent {
name: string;
apiEndPoint: string;
proxyUrl: string;
@Output() onAdd: EventEmitter<Cache> = new EventEmitter();
constructor(private cacheService: CacheService) { }
submit() {
this.cacheService.addCache(this.name, { apiEndPoint: this.apiEndPoint, cacheOptions: {} }).then((cache) => {
this.onAdd.emit(cache);
})
}
}
\ No newline at end of file
<div class="jumbotron">
<div class="container">
<h1>Admin Interface</h1>
<p>shows all cache caches available.</p>
</div>
</div>
<add-cache (onAdd)="addCache($event)"></add-cache>
<div class="container">
<cache *ngFor="let item of caches" [data]="item" (onDelete)="removeCache($event)"></cache>
</div>
\ No newline at end of file
import { Component, OnInit, enableProdMode } from '@angular/core';
import { Cache } from './cache';
import { CacheService } from './cache.service';
@Component({
selector: 'app',
templateUrl: './app.component.html',
providers: [
CacheService
]
})
export class AppComponent implements OnInit {
caches: Cache[];
constructor(private cacheService: CacheService) { }
ngOnInit(): void {
this.cacheService.getCaches().then((result) => {
this.caches = result;
})
}
addCache(cache: Cache) {
this.caches.push(cache);
}
removeCache(name: string) {
this.caches = this.caches.filter((value) => {
return value.name !== name;
})
}
}
\ No newline at end of file
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { AddCacheComponent } from './add-cache.component';
import { CacheComponent } from './cache.component';
import { CacheDetailsComponent } from './cache-details.component';
import { CacheOptionsComponent } from './cache-options.component';
import { CacheStatsComponent } from './cache-stats.component';
import { KeysPipe } from './keys.pipe';
@NgModule({
imports: [
BrowserModule,
FormsModule,
HttpClientModule
],
declarations: [
AppComponent,
AddCacheComponent,
CacheComponent,
CacheDetailsComponent,
CacheOptionsComponent,
CacheStatsComponent,
KeysPipe
],
bootstrap: [AppComponent]
})
export class AppModule { }
\ No newline at end of file
<div class="panel panel-info">
<div class="panel-heading">
<h4>Cache Details</h4>
</div>
<div class="panel-body">
<div class="row" *ngFor="let item of cache">
<div class="col-md-12">
<div class="row">
<div class="col-md-10">
<label><code>{{item.hash}}</code></label>
</div>
<div class="col-md-1">
<button type="button" class="btn btn-primary btn-xs pull-right" (click)="refresh(item.hash)">Refresh Value</button>
</div>
<div class="col-md-1">
<button type="button" class="btn btn-danger btn-xs pull-right" (click)="delete(item.hash)">Delete Value</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tr>
<th class="text-nowrap" scope="row">Time-To-Live:</th>
<td>{{item.ttl | date:"HH:mm:ss - yyyy-MM-dd"}}</td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Path-Element:</th>
<td><a href="{{proxyEndPoint}}{{item.uriPath}}" target="_blank">{{item.uriPath}}</a></td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Content-Type:</th>
<td>{{item.contentType}}</td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Size:</th>
<td>{{item.size}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
import { Component, Input } from '@angular/core';
import { CacheService } from './cache.service';
import { CacheComponent } from './cache.component';
import { CacheDetails } from './cache';
@Component({
selector: 'cache-details',
templateUrl: './cache-details.component.html'
})
export class CacheDetailsComponent {
@Input() cache: CacheDetails[];
@Input() name: string
@Input() proxyEndPoint: string;
constructor(private cacheService: CacheService, private cacheComponent: CacheComponent) { }
delete(hash: string) {
this.cacheService.deleteValue(this.name, hash).then(() => {
this.cache = this.cache.filter((item) => {
return item.hash !== hash;
});
});
}
refresh(hash: string) {
this.cacheService.refreshValue(this.name, hash).then((data) => {
this.cache = this.cache.map((value) => {
return (value.hash === hash) ? data : value;
});
});
}
}
\ No newline at end of file
import { Component, Input } from '@angular/core';
import { CacheOptions } from './cache';
@Component({
selector: 'cache-options',
template: `
<label>Cache Options:</label>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tr *ngFor="let item of data | keys">
<th class="text-nowrap" scope="row">{{item.key}}</th>
<td>{{item.value}}</td>
</tr>
</table>
</div>
`
})
export class CacheOptionsComponent {
@Input() data: CacheOptions
}
\ No newline at end of file
import { Component, Input } from '@angular/core';
import { CacheStats } from './cache';
@Component({
selector: 'cache-stats',
template: `
<label>Cache Stats:</label>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<tr *ngFor="let item of data | keys">
<th class="text-nowrap" scope="row">{{item.key}}</th>
<td>{{item.value}}</td>
</tr>
</table>
</div>
`
})
export class CacheStatsComponent {
@Input() data: CacheStats
}
\ No newline at end of file
<div class="panel panel-primary">
<div class="panel-heading">
<h1>
{{data.name}}
<div class="btn-group pull-right">
<button type="button" class="btn btn-danger" (click)="delete()">Delete Cache</button>
</div>
<div class="btn-group pull-right">
<button type="button" class="btn btn-warning" (click)="flush()">Flush Values</button>
</div>
</h1>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<label>API-Endpoint:</label>
<pre>{{data.apiEndPoint}}</pre>
</div>
<div class="col-md-6">
<label>Proxy-Endpoint:</label>
<pre>{{data.proxyEndPoint}}</pre>
</div>
</div>
<div class="row">
<div class="col-md-6">
<cache-options [data]="data.cacheOptions"></cache-options>
</div>
<div class="col-md-6">
<cache-stats [data]="data.cacheStats"></cache-stats>
</div>
</div>
<div class="row">
<div class="col-md-12">
<cache-details [cache]="data.cache" [proxyEndPoint]="data.proxyEndPoint" [name]="data.name"></cache-details>
</div>
</div>
</div>
</div>
\ No newline at end of file
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { CacheService } from './cache.service';
import { AppComponent } from './app.component';
import { Cache } from './cache';
@Component({
selector: 'cache',
templateUrl: './cache.component.html'
})
export class CacheComponent {
@Input() data: Cache;
@Output() onDelete: EventEmitter<string> = new EventEmitter();
constructor(private cacheService: CacheService, private appComponent: AppComponent) { }
@Output()
delete() {
this.cacheService.deleteCache(this.data.name).then(() => {
this.onDelete.emit(this.data.name)
});
}
flush() {
this.cacheService.flushCache(this.data.name).then((data) => {
this.data = data;
});
}
}
\ No newline at end of file
import { Component, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Cache } from './cache';
import { CacheDetails } from './cache';
@Injectable()
export class CacheService {
constructor(private http: HttpClient) { }
getCaches(): Promise<Cache[]> {
return new Promise<Cache[]>((resolve, reject) => {
this.http.get('/api/list/cache').subscribe(resolve.bind(this));
});
}
addCache(name: string, params: { apiEndPoint: string, cacheOptions: { [key: string]: string } }): Promise<Cache> {
return new Promise<Cache>((resolve, reject) => {
this.http.post(`/api/add/cache/${name}`, params).subscribe(resolve.bind(this));
})
}
deleteCache(name: string): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
this.http.get(`/api/delete/cache/${name}`).subscribe(resolve.bind(this));
});
}
flushCache(name: string): Promise<Cache> {
return new Promise<Cache>((resolve, reject) => {
this.http.get(`/api/flush/cache/${name}`).subscribe(resolve.bind(this));
});
}
deleteValue(name: string, hash: string): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
this.http.get(`/api/delete/cache/${name}/key/${hash}`).subscribe(resolve.bind(this));
});
}
refreshValue(name: string, hash: string): Promise<CacheDetails> {
return new Promise<CacheDetails>((resolve, reject) => {
this.http.get(`/api/refresh/cache/${name}/key/${hash}`).subscribe(resolve.bind(this));
});
}
}
\ No newline at end of file
export class Cache {
name: string;
apiEndPoint: string;
proxyEndPoint: string;
cacheOptions: CacheOptions;
cacheStats: CacheStats;
cache: CacheDetails[];
}
export class CacheOptions {
forceString: boolean;
objectValueSize: number;
arrayValueSize: number;
stdTTL: number;
checkPeriod: number;
useClones: boolean;
errorOnMissing: boolean;
deleteOnExpire: boolean;
}
export class CacheStats {
hits: number;
misses: number;
keys: number;
ksize: number;
vsize: number;
}
export class CacheDetails {
hash: string;
ttl: number;
uriPath: string;
contentType: string;
size: number;
}
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment