diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index e17a583..e4fffe7 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -8,6 +8,7 @@ import {DocumentationComponent} from './documentation/documentation.component';
import {TemplatesComponent} from './templates/templates.component';
import {SettingsComponent} from './settings/settings.component';
import {UsersComponent} from './users/users.component';
+import {ChangelogComponent} from './changelog/changelog.component';
const routes: Routes = [
@@ -17,6 +18,7 @@ const routes: Routes = [
{path: 'samples/new', component: SampleComponent, canActivate: [LoginService]},
{path: 'samples/edit/:id', component: SampleComponent, canActivate: [LoginService]},
{path: 'templates', component: TemplatesComponent, canActivate: [LoginService]},
+ {path: 'changelog', component: ChangelogComponent, canActivate: [LoginService]},
{path: 'users', component: UsersComponent, canActivate: [LoginService]},
{path: 'settings', component: SettingsComponent, canActivate: [LoginService]},
{path: 'documentation', component: DocumentationComponent},
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 43aa0c7..648446a 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -5,6 +5,7 @@
Templates
+ Changelog
Users
Documentation
@@ -32,7 +33,7 @@
Send report
-
+ DEVELOPMENT
DeFinMa
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 18590d1..79a2602 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -25,6 +25,7 @@ import { TemplatesComponent } from './templates/templates.component';
import { ParametersPipe } from './parameters.pipe';
import { SettingsComponent } from './settings/settings.component';
import { UsersComponent } from './users/users.component';
+import { ChangelogComponent } from './changelog/changelog.component';
@NgModule({
declarations: [
@@ -42,7 +43,8 @@ import { UsersComponent } from './users/users.component';
TemplatesComponent,
ParametersPipe,
SettingsComponent,
- UsersComponent
+ UsersComponent,
+ ChangelogComponent
],
imports: [
LocalStorageModule.forRoot({
diff --git a/src/app/changelog/changelog.component.html b/src/app/changelog/changelog.component.html
new file mode 100644
index 0000000..9d59d0c
--- /dev/null
+++ b/src/app/changelog/changelog.component.html
@@ -0,0 +1,35 @@
+
Changelog
+
+
+
+
+
+ Date |
+ Action |
+ Data |
+
+
+ {{entry.date}} |
+ {{entry.action}} |
+ {{entry.data | json}} |
+
+
diff --git a/src/app/changelog/changelog.component.scss b/src/app/changelog/changelog.component.scss
new file mode 100644
index 0000000..c36c6b1
--- /dev/null
+++ b/src/app/changelog/changelog.component.scss
@@ -0,0 +1,10 @@
+.header {
+
+ & > * {
+ float: left;
+ }
+
+ button {
+ float: right;
+ }
+}
diff --git a/src/app/changelog/changelog.component.spec.ts b/src/app/changelog/changelog.component.spec.ts
new file mode 100644
index 0000000..a9ebfb6
--- /dev/null
+++ b/src/app/changelog/changelog.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ChangelogComponent } from './changelog.component';
+
+describe('ChangelogComponent', () => {
+ let component: ChangelogComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ChangelogComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ChangelogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/changelog/changelog.component.ts b/src/app/changelog/changelog.component.ts
new file mode 100644
index 0000000..55da828
--- /dev/null
+++ b/src/app/changelog/changelog.component.ts
@@ -0,0 +1,32 @@
+import { Component, OnInit } from '@angular/core';
+import {ChangelogModel} from '../models/changelog.model';
+import {ApiService} from '../services/api.service';
+
+@Component({
+ selector: 'app-changelog',
+ templateUrl: './changelog.component.html',
+ styleUrls: ['./changelog.component.scss']
+})
+export class ChangelogComponent implements OnInit {
+
+ timestamp = new Date();
+ pageSize = 25;
+ changelog: ChangelogModel[] = [];
+
+ constructor(
+ private api: ApiService
+ ) { }
+
+ ngOnInit(): void {
+ this.loadChangelog();
+ }
+
+ loadChangelog(page = 0) {
+ this.api.get(`/changelog/${this.timestamp.toISOString()}/${page}/${this.pageSize}`, data => {
+ this.changelog = data.map(e => new ChangelogModel().deserialize(e));
+ this.timestamp = new Date(this.changelog[0].date);
+ console.log(this.changelog);
+ });
+ }
+
+}
diff --git a/src/app/models/changelog.model.spec.ts b/src/app/models/changelog.model.spec.ts
new file mode 100644
index 0000000..49eea17
--- /dev/null
+++ b/src/app/models/changelog.model.spec.ts
@@ -0,0 +1,7 @@
+import { ChangelogModel } from './changelog.model';
+
+describe('ChangelogModel', () => {
+ it('should create an instance', () => {
+ expect(new ChangelogModel()).toBeTruthy();
+ });
+});
diff --git a/src/app/models/changelog.model.ts b/src/app/models/changelog.model.ts
new file mode 100644
index 0000000..3ed5c21
--- /dev/null
+++ b/src/app/models/changelog.model.ts
@@ -0,0 +1,9 @@
+import {BaseModel} from './base.model';
+
+export class ChangelogModel extends BaseModel {
+ date: Date;
+ action: string;
+ collection: string;
+ conditions: {[key: string]: any};
+ data: {[key: string]: any};
+}
diff --git a/src/app/sample/sample.component.html b/src/app/sample/sample.component.html
index aae27cd..017fa35 100644
--- a/src/app/sample/sample.component.html
+++ b/src/app/sample/sample.component.html
@@ -19,16 +19,17 @@
Material properties
+ (focusout)="checkTypo($event, 'materialSuppliers', 'supplier', modalWarning)">
{{supplierInput.errors.failure}}
-
+ (focusout)="checkTypo($event, 'materialGroups', 'group', modalWarning)">
{{groupInput.errors.failure}}
@@ -44,7 +45,7 @@
-
+
-
+
-
+
{
if (!this.material.properties.material_template) {
- this.material.properties.material_template = this.d.arr.materialTemplates.filter(e => e.name === 'plastic').reverse()[0]._id;
+ this.material.properties.material_template = this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id;
}
this.loading--;
});
@@ -270,6 +270,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
}
new Promise
(resolve => {
if (this.newMaterial) { // save material first if new one exists
+ console.log(this.material);
+ this.material.numbers = this.material.numbers.filter(e => e !== '');
this.api.post('/material/new', this.material.sendFormat(), data => {
this.d.arr.materials.push(data); // add material to data
this.material = data;
@@ -348,7 +350,7 @@ export class SampleComponent implements OnInit, AfterContentChecked {
else { // no matching material found
if (this.sample.material_id !== null) { // reset previous match
this.material = new MaterialModel();
- this.material.properties.material_template = this.d.arr.materialTemplates.filter(e => e.name === 'plastic').reverse()[0]._id;
+ this.material.properties.material_template = this.d.latest.materialTemplates.find(e => e.name === 'plastic')._id;
}
this.sample.material_id = null;
}
@@ -376,9 +378,9 @@ export class SampleComponent implements OnInit, AfterContentChecked {
// add a new measurement for generated sample at index
addMeasurement(gIndex) {
this.generatedSamples[gIndex].measurements.push(
- new MeasurementModel(this.d.arr.measurementTemplates.filter(e => e.name === 'spectrum').reverse()[0]._id)
+ new MeasurementModel(this.d.latest.measurementTemplates.find(e => e.name === 'spectrum')._id)
);
- this.generatedSamples[gIndex].measurements[this.generatedSamples[gIndex].measurements.length - 1].values.device = this.defaultDevice;
+ console.log(this.d.latest.measurementTemplates.find(e => e.name === 'spectrum'));
if (!this.charts[gIndex]) { // add array if there are no charts yet
this.charts[gIndex] = [];
}
@@ -411,6 +413,8 @@ export class SampleComponent implements OnInit, AfterContentChecked {
this.addMeasurement(gIndex);
index = this.generatedSamples[gIndex].measurements.length - 1;
}
+ this.generatedSamples[gIndex].measurements[index].values.device =
+ this.generatedSamples[gIndex].measurements[mIndex].values.device;
this.generatedSamples[gIndex].measurements[index].values.filename = files[i].name;
this.generatedSamples[gIndex].measurements[index].values[parameter] =
fileReader.result.toString().split('\r\n').map(e => e.split(','));
@@ -430,12 +434,15 @@ export class SampleComponent implements OnInit, AfterContentChecked {
sample.condition.condition_template = null;
}
else {
- sample.condition.condition_template = this.d.arr.conditionTemplates[0]._id;
+ sample.condition.condition_template = this.d.latest.conditionTemplates[0]._id;
}
}
- checkTypo(list, mKey, modal: TemplateRef) {
- if (this.d.arr[list].indexOf(this.material[list]) < 0) { // entry is not in list
+ checkTypo(event, list, mKey, modal: TemplateRef) {
+ // user did not click on suggestion and entry is not in list
+ if (!(event.relatedTarget && (event.relatedTarget.className.indexOf('rb-dropdown-item') >= 0 ||
+ event.relatedTarget.className.indexOf('close-btn rb-btn rb-passive-link') >= 0)) &&
+ this.d.arr[list].indexOf(this.material[mKey]) < 0) {
this.modalText.list = mKey;
this.modalText.suggestion = this.d.arr[list] // find possible entry from list
.map(e => ({v: e, s: strCompare.sorensenDice(e, this.material[mKey])}))
diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts
index 497b643..1313baa 100644
--- a/src/app/services/data.service.ts
+++ b/src/app/services/data.service.ts
@@ -15,19 +15,20 @@ export class DataService {
) { }
private collectionMap = {
- materials: {path: '/materials?status=all', model: MaterialModel, array: true},
- materialSuppliers: {path: '/material/suppliers', model: null, array: true},
- materialGroups: {path: '/material/groups', model: null, array: true},
- materialTemplates: {path: '/template/materials', model: TemplateModel, array: true},
- measurementTemplates: {path: '/template/measurements', model: TemplateModel, array: true},
- conditionTemplates: {path: '/template/conditions', model: TemplateModel, array: true},
- sampleNotesFields: {path: '/sample/notes/fields', model: TemplateModel, array: true},
- users: {path: '/users', model: UserModel, array: true},
- user: {path: '/user', model: UserModel, array: false},
- userKey: {path: '/user/key', model: BaseModel, array: false}
+ materials: {path: '/materials?status=all', model: MaterialModel, type: 'array'},
+ materialSuppliers: {path: '/material/suppliers', model: null, type: 'array'},
+ materialGroups: {path: '/material/groups', model: null, type: 'array'},
+ materialTemplates: {path: '/template/materials', model: TemplateModel, type: 'template'},
+ measurementTemplates: {path: '/template/measurements', model: TemplateModel, type: 'template'},
+ conditionTemplates: {path: '/template/conditions', model: TemplateModel, type: 'template'},
+ sampleNotesFields: {path: '/sample/notes/fields', model: TemplateModel, type: 'array'},
+ users: {path: '/users', model: UserModel, type: 'array'},
+ user: {path: '/user', model: UserModel, type: 'string'},
+ userKey: {path: '/user/key', model: BaseModel, type: 'string'}
};
arr: {[key: string]: any[]} = {}; // array of data
+ latest: {[key: string]: any[]} = {}; // array of latest template versions
id: {[key: string]: {[id: string]: any}} = {}; // data in format _id: data
d: {[key: string]: any} = {}; // data not in array format
@@ -37,10 +38,24 @@ export class DataService {
}
else { // load data
this.api.get(this.collectionMap[collection].path, data => {
- if (this.collectionMap[collection].array) { // array data
+ if (this.collectionMap[collection].type !== 'string') { // array data
this.arr[collection] = data
.map(e => this.collectionMap[collection].model ? new this.collectionMap[collection].model().deserialize(e) : e);
this.idReload(collection);
+ if (this.collectionMap[collection].type === 'template') {
+ const tmpTemplates = {};
+ this.arr[collection].forEach(template => {
+ if (tmpTemplates[template.first_id]) { // already found another version
+ if (template.version > tmpTemplates[template.first_id].version) {
+ tmpTemplates[template.first_id] = template;
+ }
+ }
+ else {
+ tmpTemplates[template.first_id] = template;
+ }
+ });
+ this.latest[collection] = Object.values(tmpTemplates);
+ }
}
else { // not array data
this.d[collection] = new this.collectionMap[collection].model().deserialize(data);
diff --git a/src/app/services/login.service.ts b/src/app/services/login.service.ts
index bced041..05b14f3 100644
--- a/src/app/services/login.service.ts
+++ b/src/app/services/login.service.ts
@@ -11,6 +11,7 @@ export class LoginService implements CanActivate {
private pathPermissions = [
{path: 'templates', permission: 'dev'},
+ {path: 'changelog', permission: 'dev'},
{path: 'users', permission: 'admin'}
];
readonly levels = [
diff --git a/src/app/services/validation.service.ts b/src/app/services/validation.service.ts
index 070e3a5..47134e2 100644
--- a/src/app/services/validation.service.ts
+++ b/src/app/services/validation.service.ts
@@ -122,6 +122,7 @@ export class ValidationService {
const {ignore, error} = Joi.string()
.max(128)
.invalid('condition_template', 'material_template')
+ .allow('')
.pattern(/^[^.]+$/)
.required()
.messages({'string.pattern.base': 'name must not contain a dot'})
diff --git a/src/app/templates/templates.component.html b/src/app/templates/templates.component.html
index 6d71ebc..7a6b46e 100644
--- a/src/app/templates/templates.component.html
+++ b/src/app/templates/templates.component.html
@@ -55,7 +55,8 @@
Edit template
-
+
Save template
diff --git a/src/app/templates/templates.component.ts b/src/app/templates/templates.component.ts
index f858665..5782be6 100644
--- a/src/app/templates/templates.component.ts
+++ b/src/app/templates/templates.component.ts
@@ -5,6 +5,7 @@ import {animate, style, transition, trigger} from '@angular/animations';
import {ValidationService} from '../services/validation.service';
import cloneDeep from 'lodash/cloneDeep';
import omit from 'lodash/omit';
+import {DataService} from '../services/data.service';
@Component({
selector: 'app-templates',
@@ -36,7 +37,8 @@ export class TemplatesComponent implements OnInit {
constructor(
private api: ApiService,
- private validate: ValidationService
+ private validate: ValidationService,
+ public d: DataService
) { }
ngOnInit(): void {
@@ -44,8 +46,8 @@ export class TemplatesComponent implements OnInit {
}
loadTemplates() {
- this.api.get(`/template/${this.collection}s`, data => {
- this.templates = data;
+ this.d.load(this.collection + 'Templates', () => {
+ this.templates = this.d.arr[this.collection + 'Templates'];
this.templateFormat();
});
}
@@ -99,6 +101,7 @@ export class TemplatesComponent implements OnInit {
this.templates.push(data);
}
this.templateFormat();
+ this.d.idReload(this.collection + 'Templates');
});
}
else {
@@ -107,6 +110,7 @@ export class TemplatesComponent implements OnInit {
this.templates.push(data);
}
this.templateFormat();
+ this.d.idReload(this.collection + 'Templates');
});
}
}