Its in there but its ugly and no charts yet

This commit is contained in:
Nile Walker 2021-01-27 14:22:01 -05:00
parent 3e7cdb9fa2
commit 2186c75c6f
28 changed files with 4796 additions and 2200 deletions

6058
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -36,8 +36,11 @@
"@ngx-formly/core": "^5.8.0",
"@ngx-formly/material": "^5.8.0",
"bwip-js": "^2.0.11",
"chart.js": "^2.9.4",
"chartjs-plugin-datalabels": "^0.7.0",
"code-128-encoder": "^3.1.1",
"lodash.isequal": "^4.5.0",
"ng2-charts": "^2.4.2",
"ngx-qrcode-svg": "^2.0.0",
"rfdc": "^1.1.4",
"rxjs": "~6.6.3",
@ -46,7 +49,7 @@
"zone.js": "~0.10.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.1001.2",
"@angular-devkit/build-angular": "^0.1101.1",
"@angular/cli": "^10.1.2",
"@angular/compiler-cli": "~11.0.0-next.2",
"@angular/language-service": "~11.0.0-next.2",

View File

@ -6,6 +6,9 @@ import {PrintComponent} from './print/print.component';
import {SampleComponent} from './sample/sample.component';
import {SettingsComponent} from './settings/settings.component';
import {MultipleLabelsComponent} from './multiple-labels/multiple-labels.component';
import { DepositsComponent } from './deposits/deposits.component';
import { GraphsComponent } from './graphs/graphs.component';
import { ImportedFilesComponent} from './imported-files/imported-files.component'
export const routes: Routes = [
{
@ -13,6 +16,21 @@ export const routes: Routes = [
pathMatch: 'full',
component: SampleComponent
},
{
path: 'deposits',
pathMatch: 'full',
component: DepositsComponent
},
{
path: 'dashboard',
pathMatch: 'full',
component: GraphsComponent
},
{
path: 'imports',
pathMatch: 'full',
component: ImportedFilesComponent
},
{
path: 'sample',
pathMatch: 'full',

View File

@ -1,6 +1,8 @@
import {Component, Inject} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {AppEnvironment} from './models/appEnvironment.interface';
import { Component, Inject, OnInit} from '@angular/core';
import { Title } from '@angular/platform-browser';
import { AppEnvironment } from './models/appEnvironment.interface';
declare var jQuery: any;
@Component({
selector: 'app-root',
@ -8,7 +10,7 @@ import {AppEnvironment} from './models/appEnvironment.interface';
styleUrls: ['./app.component.scss']
})
export class AppComponent {
export class AppComponent implements OnInit {
loading: boolean;
constructor(
@ -18,7 +20,13 @@ export class AppComponent {
this.titleService.setTitle(this.environment.title);
}
ngOnInit() {
(function ($) {
$("#menu-toggle").click(function () {
$("#wrapper").toggleClass("toggled");
});
})(jQuery);
}
reload() {
this.loading = true;
setTimeout(() => this.loading = false, 300);

View File

@ -32,11 +32,22 @@ import {PrintLayoutComponent} from './print-layout/print-layout.component';
import {PrintComponent} from './print/print.component';
import {SampleComponent} from './sample/sample.component';
import {ApiService} from './services/api.service';
import {GraphService} from './services/graph.service';
import {CacheService} from './services/cache.service';
import {SettingsService} from './services/settings.service';
import {SettingsComponent} from './settings/settings.component';
import {MultipleLabelsComponent} from './multiple-labels/multiple-labels.component';
import {RectangleDatamatrixRectangularComponent} from './label-layout/formats/rectangle-datamatrix-rectangular/rectangle-datamatrix-rectangular.component';
import { BrowserModule } from '@angular/platform-browser';
import { DepositsComponent } from './deposits/deposits.component';
import { ImportedFilesComponent } from './imported-files/imported-files.component';
import { GraphsComponent } from './graphs/graphs.component';
import { ChartsModule } from 'ng2-charts';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule, DateAdapter } from '@angular/material/core';
import {MatPaginatorModule} from '@angular/material/paginator';
import { CustomDateAdapter } from './custom-date-adapter';
/**
* This function is used internal to get a string instance of the `<base href="" />` value from `index.html`.
@ -72,8 +83,15 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
RectangleDatamatrixRectangularComponent,
SampleComponent,
SettingsComponent,
DepositsComponent,
GraphsComponent,
ImportedFilesComponent
],
imports: [
MatPaginatorModule,
MatNativeDateModule,
BrowserModule,
ChartsModule,
BrowserAnimationsModule,
FlexLayoutModule,
FormlyModule,
@ -81,6 +99,7 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
HttpClientModule,
MatButtonModule,
MatCardModule,
MatDatepickerModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
@ -94,8 +113,11 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
],
providers: [
ApiService,
GraphService,
CacheService,
SettingsService,
SettingsService,
MatDatepickerModule,
{provide: DateAdapter, useClass: CustomDateAdapter },
{provide: 'APP_ENVIRONMENT', useClass: ThisEnvironment},
{provide: APP_BASE_HREF, useFactory: getBaseHref, deps: [PlatformLocation]},
{provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: {appearance: 'outline'}},

View File

@ -0,0 +1,11 @@
import { NativeDateAdapter } from '@angular/material/core';
/** Adapts the native JS Date for use with cdk-based components that work with dates. */
export class CustomDateAdapter extends NativeDateAdapter {
getFirstDayOfWeek(): number {
return 1;
}
}

View File

View File

@ -0,0 +1,57 @@
<div class="container-fluid mt--7">
<div class="card">
<div class="card-header">
<h3 class="mb-0">Inventory Deposits</h3>
</div>
<div class="card-body">
<h5 class="card-title">(Total Inventory - Total Prints) since first_deposit | safe: samples_since | safe Strips
Remaining</h5>
<div class="justify-content-center">
<div class="table-responsive">
<!-- Projects table -->
<table class="table align-items-center table-flush">
<thead>
<tr>
<th>Date Added</th>
<th>Amount</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input matInput [(ngModel)]="date_temp" [value] = "date_temp" [matDatepicker]="picker">
<mat-datepicker #picker></mat-datepicker>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
</td>
<td><input [(ngModel)]="newDeposit.amount" name="amount"></td>
<td><input [(ngModel)]="newDeposit.notes" name="notes">
<button type="submit" (click)="addDeposit()">Submit</button>
</td>
</tr>
<tr *ngFor="let deposit of depositList">
<td>{{deposit.date_added | date : 'full' }}</td>
<td>{{deposit.amount}}</td>
<td>{{deposit.notes}}</td>
</tr>
</tbody>
</table>
</div>
<mat-paginator #paginator [length]="100000" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions"
(page)="updatePage($event)">
</mat-paginator>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DepositsComponent } from './deposits.component';
describe('DepositsComponent', () => {
let component: DepositsComponent;
let fixture: ComponentFixture<DepositsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DepositsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DepositsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,46 @@
import { Component, OnInit } from '@angular/core';
import { PageEvent } from '@angular/material/paginator'
import { ApiService } from '../services/api.service';
import { InventoryDeposit } from "../models/deposit.interface";
@Component({
selector: 'app-deposits',
templateUrl: './deposits.component.html',
styleUrls: ['./deposits.component.css']
})
export class DepositsComponent implements OnInit {
depositList: InventoryDeposit[] = [];
newDeposit: InventoryDeposit = {
amount: 0,
date_added: "",
notes: ''
};
date_temp = new Date(Date.now());
constructor(
private depositService: ApiService) {
}
addDeposit(): void {
this.newDeposit.date_added = this.date_temp.toLocaleDateString();
this.depositService.addDeposit(this.newDeposit).subscribe(deposit => this.depositList.push(deposit))
}
current_page: number = 0;
pageSize: number = 10;
pageSizeOptions: number[] = [10,20,50,100];
updatePage(event: PageEvent) {
this.current_page = event.pageIndex;
this.depositService.getDeposits(this.current_page).subscribe(searchResult => this.depositList = searchResult);
}
ngOnInit(): void {
this.depositService.getDeposits(0).subscribe(searchResult => this.depositList = searchResult);
}
}

View File

@ -0,0 +1,3 @@
.card{
display: flex;
}

View File

@ -0,0 +1,209 @@
<div class="container-fluid mt--7">
<div class="row mb-4">
<div class="col-xl-2">
<div class="card card-stats mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Total Samples within<br> {{form.start_date | date}}
-
{{form.end_date | date}}</h5>
<span id="card_1" class="h2 font-weight-bold">{{topBarData[0]}}</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-2">
<div class="card card-stats mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Total Samples within <br> {{start_date_1 | date}}
-
{{end_date_1 | date}}</h5>
<span id="card_1" class="h2 font-weight-bold mb-0">{{topBarData[1]}}</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-2">
<div class="card card-stats mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Total Samples within <br> {{start_date_2 | date}}
-
{{end_date_2 | date}}</h5>
<span id="card_1" class="h2 font-weight-bold mb-0">{{topBarData[2]}}</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3">
<div class="card card-stats mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Email Notifications within <br> {{form.start_date |
date}} - {{form.end_date | date}}</h5>
<span id="card_1" class="h2 font-weight-bold mb-0"><span
style="color:green">{{topBarData[3]}}</span>/<span style="color:red">{{topBarData[4]}}</span></span>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 ">
<div class="card card-stats mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">Text Notifications within <br> {{form.start_date |
date}} - {{form.end_date | date}}</h5>
<span id="card_1" class="h2 font-weight-bold mb-0"><span
style="color:green">{{topBarData[5]}}</span>/<span style="color:red">{{topBarData[6]}}</span></span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col mb-3">
<div class="card">
<div class="card-header">
<h3 class="mb-3 ">{{ChartName}}</h3>
</div>
<div style="display: block">
<canvas baseChart [datasets]="dailyChartsData" [labels]="dailyChartLabels" [options]="barChartOptions"
[legend]="true" chartType="bar" (chartClick)="chartClicked($event)">
</canvas>
</div>
</div>
</div>
<div class="col mb-3">
<div class="card ">
<div class="card-header">
<div class=row>
<h3 class="mb-3 col ">Search</h3>
<button (click)="searchToday()" class="btn btn-sm btn-primary col mr-3">Today</button>
<button (click)="searchAll()" class="btn btn-sm btn-primary col mr-3">All</button>
<button (click)="updateGraphData()" class="btn btn-sm btn-primary col ">Run</button>
</div>
</div>
<div class="col">
<div class="form-group row">
<label for="range" class="col mt-3 mr-3">Search Range</label>
<mat-form-field>
<mat-date-range-input [rangePicker]="picker">
<input matStartDate [(ngModel)]="start_date">
<input matEndDate [(ngModel)]="end_date">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
</mat-form-field>
</div>
<div class="form-group row ">
<label for="location" class="col mt-3 mr-3">Location ID(s)</label>
<textarea class="form-control col mr-3 mt-3" id="location" [(ngModel)]="form.location" rows="2"></textarea>
</div>
<div class="form-group row ">
<label for="student" class="col mt-3 mr-3">Student ID(s)</label>
<textarea class="form-control col mr-3 mt-3" id="student" [(ngModel)]="form.student_id" rows="2"></textarea>
</div>
<div class="form-group row ">
<label for="compute" class="col mt-3 mr-3">Compute ID(s)</label>
<textarea class="form-control col mr-3 mt-3" id="compute" [(ngModel)]="form.compute_id" rows="2"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col mb-3 ">
<div class="card ">
<div class="card-header">
<h3 class="mb-3 ">Average Count By Weekday For {{form.start_date | date}} - {{form.end_date | date}}</h3>
</div>
<div style="display: block">
<canvas baseChart [datasets]="weekdayChartsData" [labels]="weekdayChartLabels" [options]="barChartOptions"
[legend]=false chartType="horizontalBar">
</canvas>
</div>
</div>
</div>
<div class="col mb-3">
<div class="card">
<div class="card-header">
<h3 class="mb-3">Average Count By Hour For {{form.start_date | date}} - {{form.end_date | date}}</h3>
</div>
<div style="display: block">
<canvas baseChart [datasets]="hourlyChartsData" [labels]="hourlyChartLabels" [options]="barChartOptions"
[legend]=false chartType="horizontalBar">
</canvas>
</div>
</div>
</div>
</div>
<div class="card row ">
<div class="card-header">
<h3 class="mb-0">Records to be processed </h3>
</div>
<div class="table-responsive">
<table class="table align-items-center table-flush">
<thead>
<tr>
<th>Barcode </th>
<th>Date</th>
<th>Location</th>
<th>IDs</th>
<th>Contacts</th>
<th>Notifications</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let sample of searchResult">
<td>{{sample.barcode}}</td>
<td>{{sample.date| date :"medium"}}</td>
<td>Location: {{sample.location}}<br>Station: {{sample.station}}</td>
<td>Compute ID: {{sample.compute_id}}<br>Student ID: {{sample.student_id}}</td>
<td>Phone: {{sample.phone}}<br>Email: {{sample.email}}</td>
</tr>
</tbody>
</table>
</div>
<mat-paginator #paginator [length]="topBarData[0]" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions"
(page)="updatePage($event)">
</mat-paginator>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GraphsComponent } from './graphs.component';
describe('GraphsComponent', () => {
let component: GraphsComponent;
let fixture: ComponentFixture<GraphsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ GraphsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(GraphsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,224 @@
import { Component, OnInit } from '@angular/core';
import { ChartOptions, ChartType, ChartDataSets } from 'chart.js';
import { Label } from 'ng2-charts';
import { GraphService } from '../services/graph.service'
import { Sample } from '../models/sample.interface'
import { SearchForm } from '../models/search_form'
import {PageEvent} from '@angular/material/paginator'
import * as pluginDataLabels from 'chartjs-plugin-datalabels';
@Component({
selector: 'app-graphs',
templateUrl: './graphs.component.html',
styleUrls: ['./graphs.component.css']
})
export class GraphsComponent implements OnInit {
constructor(private graphService: GraphService) { }
topBarData: Array<number> = [0, 0, 0, 0, 0, 0, 0];
ChartName: String = "Location Activity";
dailyChartLabels: Label[] = [];
weekdayChartLabels: Label[] = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
hourlyChartLabels: Label[] = ["1 AM", "2 AM", "3 AM", "4 AM", "5 AM", "6 AM", "7 AM", "8 AM", "9 AM", "10 AM", "11 AM", "12 AM", "1 PM", "2 PM", "3 PM", "4 PM", "5 PM", "6 PM", "7 PM", "8 PM", "9 PM", "10 PM", "11 PM", "12 PM"];
dailyChartsData: ChartDataSets[] = [];
hourlyChartsData: ChartDataSets[] = [];
weekdayChartsData: ChartDataSets[] = [];
barChartPlugins = [pluginDataLabels];
barChartOptions: ChartOptions = {
responsive: true,
// We use these empty structures as placeholders for dynamic theming.
scales: {
xAxes: [{
ticks: {
beginAtZero: true
},
stacked: true
}],
yAxes: [{
ticks: {
beginAtZero: true
},
stacked: true
}]
},
legend: {
onClick: (e, i) => {
this.form.location = String(i.text);
this.updateGraphData();
}
},
plugins: {
datalabels: {
rotation: -45,
anchor: 'end',
align: 'end',
formatter: (value: any, ctx: any) => {
let datasets = ctx.chart.data.datasets;
if (datasets.indexOf(ctx.dataset) === datasets.length - 1) {
let sum = 0;
datasets.map((dataset: any) => {
sum += dataset.data[ctx.dataIndex];
});
return sum;
} else {
return '';
}
}
}
}, layout: {
padding: {
left: 0,
right: 20,
top: 30,
bottom: 0
}
}
};
arrayOne(n: number): any[] {
return Array(n);
}
tempData: JSON = <JSON>{};
searchResult: Sample[] = [];
start_date: Date = new Date();
end_date: Date = new Date();
start_date_1: string = "";
end_date_1: string = "";
start_date_2: string = "";
end_date_2: string = "";
current_page: number = 0;
pageSize: number = 10;
pageSizeOptions: number[] = [10,20,50,100];
updatePage(event: PageEvent) {
this.current_page = event.pageIndex;
this.graphService.getRawSearchData(this.form, this.current_page).subscribe(searchResult => this.searchResult = searchResult);
}
form: SearchForm = {
start_date: "",
end_date: "",
student_id: "",
location: "",
compute_id: "",
include_tests: false
};
searchToday(): void {
this.start_date = new Date();
this.end_date = new Date();
this.updateGraphData();
}
searchAll(): void {
this.start_date = new Date(2020,9,5);
this.end_date = new Date();
this.updateGraphData();
}
updateGraphData(): void {
if (this.form.location.trim().split(" ").length == 1) {
this.ChartName = "Total Samples per Station @ Location " + this.form.location;
} else {
this.ChartName = "Total Samples per Location";
}
if (this.form.location.trim() == "") {
this.ChartName = "Total Samples per Location";
}
this.form.start_date = this.start_date.toLocaleDateString();
this.form.end_date = this.end_date.toLocaleDateString();
var date = new Date();
var date_2 = new Date();
date.setDate(this.start_date.getDate() - 7);
this.start_date_1 = date.toLocaleDateString();
date_2.setDate(this.end_date.getDate() - 7);
this.end_date_1 = date_2.toLocaleDateString();
date.setDate(date.getDate() - 7);
this.start_date_2 = date.toLocaleDateString();
date_2.setDate(date_2.getDate() - 7);
this.end_date_2 = date_2.toLocaleDateString();
var temp = new Date(this.start_date.getTime());
this.dailyChartLabels = [];
while (true) {
this.dailyChartLabels.push(temp.toLocaleDateString());
if (temp.toLocaleDateString() == this.end_date.toLocaleDateString()) {
break;
} else {
temp.setDate(temp.getDate() + 1);
}
}
this.graphService.getDayData(this.form).subscribe(tempData => {
this.tempData = tempData;
this.dailyChartsData = [];
Object.entries(this.tempData).forEach(([loc_or_stat_name, totals]) => {
this.dailyChartsData.push({ data: totals, label: loc_or_stat_name, stack: 'a' })
});
});
this.graphService.getWeekdayData(this.form).subscribe(tempData => {
this.tempData = tempData;
this.weekdayChartsData = [];
Object.entries(this.tempData).forEach(([loc_or_stat_name, totals]) => {
this.weekdayChartsData.push({ data: totals, label: loc_or_stat_name, stack: 'a' })
});
});
this.graphService.getHourData(this.form).subscribe(tempData => {
this.tempData = tempData;
this.hourlyChartsData = [];
Object.entries(this.tempData).forEach(([loc_or_stat_name, totals]) => {
this.hourlyChartsData.push({ data: totals, label: loc_or_stat_name, stack: 'c' })
});
});
this.graphService.getTopBarData(this.form).subscribe(tempData => {
this.topBarData = tempData;
});
this.graphService.getRawSearchData(this.form, 0).subscribe(searchResult => this.searchResult = searchResult);
}
ngOnInit(): void {
var end_date = new Date();
var start_date = new Date();
this.form.start_date = start_date.toLocaleDateString();
this.form.end_date = end_date.toLocaleDateString();
this.updateGraphData();
}
chartClicked(e: any): void {
if (e.active.length > 0) {
const chart = e.active[0]._chart;
const activePoints = chart.getElementAtEvent(e.event);
if (activePoints.length > 0) {
// get the internal index of slice in pie chart
const clickedElementIndex = activePoints[0]._index;
const label = chart.data.labels[clickedElementIndex];
// get value by index
const value = chart.data.datasets[0].data[clickedElementIndex];
console.log(clickedElementIndex, label, value)
// this.updateGraphData();
}
}
}
}

View File

@ -0,0 +1,28 @@
<div class="container-fluid mt--7">
<div class="card">
<div class="card-header">
<h3 class="mb-0">The following files were imported from IVY</h3>
</div>
<div class="card-body">
<div class="justify-content-center">
<div class="table-responsive">
<table class="table align-items-center table-flush">
<thead><tr><th>Date Added</th><th>File Name</th><th>Sample Count</th></tr></thead>
<tbody>
<tr *ngFor="let file of fileList">
<td>{{file.date_added | date : 'medium'}}</td>
<td>{{file.file_name}}</td>
<td>{{file.sample_count}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<mat-paginator #paginator [length]="100000" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions"
(page)="updatePage($event)">
</mat-paginator>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ImportedFilesComponent } from './imported-files.component';
describe('ImportedFilesComponent', () => {
let component: ImportedFilesComponent;
let fixture: ComponentFixture<ImportedFilesComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ImportedFilesComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ImportedFilesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,32 @@
import { Component, OnInit } from '@angular/core';
import { ApiService } from '../services/api.service';
import {PageEvent} from '@angular/material/paginator'
import { IvyFile } from '../models/ivyfile.interface';
@Component({
selector: 'app-imported-files',
templateUrl: './imported-files.component.html',
styleUrls: ['./imported-files.component.css']
})
export class ImportedFilesComponent implements OnInit {
fileList: IvyFile[] = [];
constructor(private fileService: ApiService) { }
ngOnInit(): void {
this.fileService.getFiles(0).subscribe(fileList => this.fileList = fileList);
}
current_page: number = 0;
pageSize: number = 10;
pageSizeOptions: number[] = [10,20,50,100];
updatePage(event: PageEvent) {
this.current_page = event.pageIndex;
this.fileService.getFiles(this.current_page).subscribe(fileList => this.fileList = fileList);
}
}

View File

@ -0,0 +1,5 @@
export interface InventoryDeposit {
amount: number;
notes: string;
date_added: string;
}

View File

@ -0,0 +1,5 @@
export interface IvyFile {
sample_count: number;
file_name: string;
date_added: Date;
}

View File

@ -1,8 +1,11 @@
export interface Sample {
barcode: string;
date: Date;
student_id: string;
initials?: string;
date: Date;
location: string;
station?: string;
computing_id?: string;
}
phone?: string;
email?: string;
}

View File

@ -0,0 +1,8 @@
export interface SearchForm{
start_date: string;
end_date: string;
student_id : string;
location : string;
compute_id : string;
include_tests : boolean;
}

View File

@ -1,12 +1,15 @@
import {APP_BASE_HREF} from '@angular/common';
import {HttpClient} from '@angular/common/http';
import {Inject, Injectable} from '@angular/core';
import {Router} from '@angular/router';
import {Observable, throwError} from 'rxjs';
import {catchError, timeout} from 'rxjs/operators';
import {ApiError} from '../models/apiError.interface';
import {AppEnvironment} from '../models/appEnvironment.interface';
import {Sample} from '../models/sample.interface';
import { APP_BASE_HREF } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, throwError } from 'rxjs';
import { catchError, timeout } from 'rxjs/operators';
import { ApiError } from '../models/apiError.interface';
import { AppEnvironment } from '../models/appEnvironment.interface';
import { Sample } from '../models/sample.interface';
import { InventoryDeposit } from '../models/deposit.interface';
import { IvyFile } from '../models/ivyfile.interface';
import { HttpClient, HttpParams } from '@angular/common/http';
@Injectable({
@ -16,6 +19,8 @@ export class ApiService {
apiRoot: string;
endpoints = {
sample: '/sample',
deposit: '/deposit',
ivy_file: '/ivy_file',
};
constructor(
@ -29,7 +34,38 @@ export class ApiService {
/** Get the string value from a given URL */
getStringFromUrl(url: string): Observable<string> {
return this.httpClient
.get(url, {responseType: 'text'})
.get(url, { responseType: 'text' })
.pipe(catchError(err => this._handleError(err)));
}
/** */
getDeposits(page: Number): Observable<InventoryDeposit[]> {
let param = new HttpParams().set("page", String(page));
const url = this.apiRoot + this.endpoints.deposit;
return this.httpClient
.get<InventoryDeposit[]>(url, { params: param })
.pipe(timeout(1000), catchError(err => this._handleError(err)))
.pipe(catchError(err => this._handleError(err)));
}
/** */
addDeposit(deposit: InventoryDeposit): Observable<InventoryDeposit> {
const url = this.apiRoot + this.endpoints.deposit;
return this.httpClient
.post<InventoryDeposit>(url, deposit)
.pipe(timeout(1000), catchError(err => this._handleError(err)))
.pipe(catchError(err => this._handleError(err)));
}
/** */
getFiles(page: Number): Observable<IvyFile[]> {
let params = new HttpParams().set("page", String(page));
const url = this.apiRoot + this.endpoints.ivy_file;
return this.httpClient
.get<IvyFile[]>(url, { params: params })
.pipe(timeout(1000), catchError(err => this._handleError(err)))
.pipe(catchError(err => this._handleError(err)));
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { GraphService } from './graph.service';
describe('GraphService', () => {
let service: GraphService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(GraphService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,84 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { APP_BASE_HREF } from '@angular/common';
import { Observable, throwError } from 'rxjs';
import { catchError, timeout } from 'rxjs/operators';
import { ApiError } from '../models/apiError.interface';
import { AppEnvironment } from '../models/appEnvironment.interface';
import { HttpParams } from '@angular/common/http';
import { Sample } from '../models/sample.interface';
import { SearchForm } from '../models/search_form';
@Injectable({
providedIn: 'root'
})
export class GraphService {
apiRoot: string;
constructor(@Inject('APP_ENVIRONMENT') private environment: AppEnvironment,
@Inject(APP_BASE_HREF) public baseHref: string,
private httpClient: HttpClient,
) {
this.apiRoot = environment.api;
}
getRawSearchData(form: SearchForm, page: Number): Observable<Sample[]> {
var params = this.createParams(form);
params = params.set("page", String(page));
return this.httpClient
.get<Sample[]>(this.apiRoot + `/dashboard/search`, { params: params })
.pipe(timeout(1000), catchError(err => this._handleError(err)))
.pipe(catchError(err => this._handleError(err)));
}
getTopBarData(form: SearchForm): Observable<number[]> {
// let params = new HttpParams().set("start_date", form.start_date).set("end_date", form.end_date);
return this.httpClient
.get<number[]>(this.apiRoot + '/dashboard/tob_bar', { params: this.createParams(form) })
.pipe(timeout(1000), catchError(err => this._handleError(err)))
.pipe(catchError(err => this._handleError(err)));
}
getDayData(form: SearchForm): Observable<JSON> {
return this.httpClient
.get<JSON>(this.apiRoot + "/dashboard/day", { params: this.createParams(form) })
.pipe(timeout(1000), catchError(err => this._handleError(err)))
.pipe(catchError(err => this._handleError(err)));
}
getWeekdayData(form: SearchForm): Observable<JSON> {
return this.httpClient
.get<JSON>(this.apiRoot + "/dashboard/weekday", { params: this.createParams(form) })
.pipe(timeout(1000), catchError(err => this._handleError(err)))
.pipe(catchError(err => this._handleError(err)));
}
getHourData(form: SearchForm): Observable<JSON> {
return this.httpClient
.get<JSON>(this.apiRoot + "/dashboard/hour", { params: this.createParams(form) })
.pipe(timeout(1000), catchError(err => this._handleError(err)))
.pipe(catchError(err => this._handleError(err)));
}
createParams(form: SearchForm): HttpParams {
let params = new HttpParams()
.set("start_date", form.start_date)
.set("end_date", form.end_date)
.set("student_id", form.student_id)
.set("compute_id", form.compute_id)
.set("location", form.location)
return params;
}
private _handleError(error: ApiError): Observable<never> {
return throwError(error.message || 'Could not complete your request; please try again later.');
}
/** Log a HeroService message with the MessageService */
private log(message: string) {
console.log(message);
}
}

View File

@ -1,5 +1,6 @@
import {Injectable} from '@angular/core';
import createClone from 'rfdc';
//https://github.com/visjs/vis-network/issues/67
import * as createClone from 'rfdc';
import {BehaviorSubject} from 'rxjs';
import serializeJs from 'serialize-javascript';
import {defaultOptions} from '../config/defaults';

View File

@ -8,8 +8,7 @@ import {AppDefaults} from '../models/appDefaults.interface';
import {LabelLayout} from '../models/labelLayout.interface';
import {Sample} from '../models/sample.interface';
import {SettingsService} from '../services/settings.service';
import createClone from 'rfdc';
import * as createClone from 'rfdc';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',

View File

@ -23,4 +23,5 @@
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}