Compare commits
26 Commits
feature/ma
...
feature/ma
Author | SHA1 | Date | |
---|---|---|---|
a41811356a | |||
73a43b6e2a | |||
2287ca8ad3 | |||
877315d6e1 | |||
d5160a55fb | |||
73de67db73 | |||
f632722916 | |||
048a2a7d08 | |||
6a93eac767 | |||
2f5538fc08 | |||
4e21327d49 | |||
82670ce86b | |||
3c6ebea602 | |||
3088ccc748 | |||
2a07506005 | |||
b6d710ec67 | |||
ca9bccaf92 | |||
7067366ac1 | |||
c63c9c0b24 | |||
30a1a69451 | |||
a84a1f1c28 | |||
2236f317c6 | |||
93563aceae | |||
6800b1ee2d | |||
04433bed3e | |||
3d5b3ae14b |
28
package.json
28
package.json
@ -4,17 +4,21 @@
|
|||||||
"repository": "https://git.lahouze.org/xals/accountant",
|
"repository": "https://git.lahouze.org/xals/accountant",
|
||||||
"license": "AGPL-1.0",
|
"license": "AGPL-1.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/requirejs": "^2.1.31",
|
||||||
|
"angular2-template-loader": "^0.6.2",
|
||||||
|
"awesome-typescript-loader": "^3.2.3",
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-eslint": "^8.0.1",
|
"babel-eslint": "^8.0.1",
|
||||||
"babel-loader": "^7.1.2",
|
"babel-loader": "^7.1.2",
|
||||||
"css-loader": "^0.28.5",
|
"codelyzer": "^3.2.0",
|
||||||
|
"css-loader": "^0.28.7",
|
||||||
"ejs-loader": "^0.3.0",
|
"ejs-loader": "^0.3.0",
|
||||||
"eslint": "^4.10.0",
|
"eslint": "^4.10.0",
|
||||||
"eslint-config-angular": "^0.5.0",
|
"eslint-config-angular": "^0.5.0",
|
||||||
"eslint-config-webpack": "^1.2.5",
|
"eslint-config-webpack": "^1.2.5",
|
||||||
"eslint-loader": "^1.9.0",
|
"eslint-loader": "^1.9.0",
|
||||||
"eslint-plugin-angular": "^3.1.0",
|
"eslint-plugin-angular": "^3.1.1",
|
||||||
"eslint-plugin-html": "^3.2.0",
|
"eslint-plugin-html": "^3.2.2",
|
||||||
"eslint-plugin-jquery": "^1.2.1",
|
"eslint-plugin-jquery": "^1.2.1",
|
||||||
"eslint-plugin-promise": "^3.6.0",
|
"eslint-plugin-promise": "^3.6.0",
|
||||||
"eslint-plugin-security": "^1.4.0",
|
"eslint-plugin-security": "^1.4.0",
|
||||||
@ -30,37 +34,47 @@
|
|||||||
"loglevel": "^1.5.1",
|
"loglevel": "^1.5.1",
|
||||||
"ngtemplate-loader": "^2.0.1",
|
"ngtemplate-loader": "^2.0.1",
|
||||||
"node-sass": "^4.5.3",
|
"node-sass": "^4.5.3",
|
||||||
|
"resolve-url-loader": "^2.1.0",
|
||||||
"sass-loader": "^6.0.6",
|
"sass-loader": "^6.0.6",
|
||||||
"style-loader": "^0.19.0",
|
"style-loader": "^0.19.0",
|
||||||
"ts-loader": "^3.1.0",
|
"ts-loader": "^3.1.0",
|
||||||
"typescript": "^2.4.2",
|
"tslint": "^5.7.0",
|
||||||
|
"tslint-config-prettier": "^1.5.0",
|
||||||
|
"tslint-loader": "^3.5.3",
|
||||||
|
"typescript": "^2.5.2",
|
||||||
"url-loader": "^0.6.2",
|
"url-loader": "^0.6.2",
|
||||||
"webpack": "^3.8.1",
|
"webpack": "^3.8.1",
|
||||||
"webpack-dev-server": "^2.9.3"
|
"webpack-dev-server": "^2.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^4.4.6",
|
"@angular/animations": "^4.4.6",
|
||||||
|
"@angular/cdk": "^2.0.0-beta.10",
|
||||||
"@angular/common": "^4.4.6",
|
"@angular/common": "^4.4.6",
|
||||||
"@angular/compiler": "^4.4.6",
|
"@angular/compiler": "^4.4.6",
|
||||||
"@angular/core": "^4.4.6",
|
"@angular/core": "^4.4.6",
|
||||||
|
"@angular/flex-layout": "^2.0.0-beta.9",
|
||||||
"@angular/forms": "^4.4.6",
|
"@angular/forms": "^4.4.6",
|
||||||
"@angular/http": "^4.4.6",
|
"@angular/http": "^4.4.6",
|
||||||
|
"@angular/material": "^2.0.0-beta.10",
|
||||||
"@angular/platform-browser": "^4.4.6",
|
"@angular/platform-browser": "^4.4.6",
|
||||||
"@angular/platform-browser-dynamic": "^4.4.6",
|
"@angular/platform-browser-dynamic": "^4.4.6",
|
||||||
"@angular/router": "^4.4.6",
|
"@angular/router": "^4.4.6",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^1.0.0-beta.2",
|
"@ng-bootstrap/ng-bootstrap": "^1.0.0-beta.2",
|
||||||
"@nsalaun/ng-logger": "^2.0.2",
|
"@nsalaun/ng-logger": "^2.0.2",
|
||||||
"@types/c3": "^0.4.45",
|
"@types/c3": "^0.4.45",
|
||||||
|
"@types/jquery": "^3.2.12",
|
||||||
"@types/node": "^8.0.47",
|
"@types/node": "^8.0.47",
|
||||||
"angular2-text-mask": "^8.0.3",
|
"angular2-text-mask": "^8.0.4",
|
||||||
"base64util": "^1.0.2",
|
"base64util": "^1.0.2",
|
||||||
"bootstrap": "4.0.0-beta",
|
"bootstrap": "^4.0.0-beta",
|
||||||
"c3": "^0.4.17",
|
"c3": "^0.4.18",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"jquery": "^3.2.1",
|
"jquery": "^3.2.1",
|
||||||
|
"material-design-icons": "^3.0.1",
|
||||||
"moment": "^2.19.1",
|
"moment": "^2.19.1",
|
||||||
"ngx-toastr": "^6.5.0",
|
"ngx-toastr": "^6.5.0",
|
||||||
"reflect-metadata": "^0.1.10",
|
"reflect-metadata": "^0.1.10",
|
||||||
|
"roboto-fontface": "^0.8.0",
|
||||||
"rxjs": "^5.5.2",
|
"rxjs": "^5.5.2",
|
||||||
"zone.js": "^0.8.17"
|
"zone.js": "^0.8.17"
|
||||||
},
|
},
|
||||||
|
36
src/accounts/account.dataSource.ts
Normal file
36
src/accounts/account.dataSource.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// vim: set tw=80 ts=2 sw=2 sts=2:
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { DataSource } from '@angular/cdk/collections';
|
||||||
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
|
||||||
|
import { Account } from './account';
|
||||||
|
import { AccountBalances } from './accountBalances';
|
||||||
|
import { AccountBalancesService } from './accountBalances.service';
|
||||||
|
import { AccountService } from './account.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AccountDataSource extends DataSource<Account> {
|
||||||
|
constructor(
|
||||||
|
private accountService: AccountService,
|
||||||
|
private accountBalancesService: AccountBalancesService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(): Observable<Account[]> {
|
||||||
|
return this.accountService.query().map((accounts: Account[]) => {
|
||||||
|
for(let account of accounts) {
|
||||||
|
this.accountBalancesService
|
||||||
|
.get(account.id)
|
||||||
|
.subscribe((accountBalances: AccountBalances) => {
|
||||||
|
account.balances = accountBalances;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return accounts;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {}
|
||||||
|
}
|
@ -3,6 +3,14 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import {
|
||||||
|
MdButtonModule,
|
||||||
|
MdDialogModule,
|
||||||
|
MdIconModule,
|
||||||
|
MdInputModule,
|
||||||
|
MdListModule,
|
||||||
|
MdTableModule,
|
||||||
|
} from '@angular/material';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
@ -13,10 +21,10 @@ import { ToastrModule } from 'ngx-toastr';
|
|||||||
import { AccountService } from './account.service';
|
import { AccountService } from './account.service';
|
||||||
import { AccountBalancesService } from './accountBalances.service';
|
import { AccountBalancesService } from './accountBalances.service';
|
||||||
import { AccountListComponent } from './accountList.component';
|
import { AccountListComponent } from './accountList.component';
|
||||||
|
import { AccountDataSource } from './account.dataSource';
|
||||||
import { AccountDeleteModalComponent } from './accountDeleteModal.component';
|
import { AccountDeleteModalComponent } from './accountDeleteModal.component';
|
||||||
import { AccountEditModalComponent } from './accountEditModal.component';
|
import { AccountEditModalComponent } from './accountEditModal.component';
|
||||||
import { AccountFormComponent } from './accountForm.component';
|
import { AccountFormComponent } from './accountForm.component';
|
||||||
import { AccountRowComponent } from './accountRow.component';
|
|
||||||
import { DailyBalanceService } from './dailyBalance.service';
|
import { DailyBalanceService } from './dailyBalance.service';
|
||||||
import { AccountListState } from './account.states'
|
import { AccountListState } from './account.states'
|
||||||
|
|
||||||
@ -28,12 +36,19 @@ import { AccountListState } from './account.states'
|
|||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
AccountListState
|
AccountListState
|
||||||
]),
|
]),
|
||||||
|
MdButtonModule,
|
||||||
|
MdDialogModule,
|
||||||
|
MdIconModule,
|
||||||
|
MdInputModule,
|
||||||
|
MdListModule,
|
||||||
|
MdTableModule,
|
||||||
NgLoggerModule,
|
NgLoggerModule,
|
||||||
ToastrModule,
|
ToastrModule,
|
||||||
NgbModule
|
NgbModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
AccountService,
|
AccountService,
|
||||||
|
AccountDataSource,
|
||||||
AccountBalancesService,
|
AccountBalancesService,
|
||||||
DailyBalanceService,
|
DailyBalanceService,
|
||||||
],
|
],
|
||||||
@ -42,7 +57,6 @@ import { AccountListState } from './account.states'
|
|||||||
AccountDeleteModalComponent,
|
AccountDeleteModalComponent,
|
||||||
AccountEditModalComponent,
|
AccountEditModalComponent,
|
||||||
AccountFormComponent,
|
AccountFormComponent,
|
||||||
AccountRowComponent
|
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
AccountListComponent,
|
AccountListComponent,
|
||||||
|
@ -1,53 +1,30 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2:
|
// vim: set tw=80 ts=2 sw=2 sts=2:
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { MD_DIALOG_DATA } from '@angular/material';
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
|
|
||||||
import { Account } from './account';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'account-delete-modal',
|
selector: 'account-delete-modal',
|
||||||
template: `
|
template: `
|
||||||
<div class="modal-header">
|
<h3 md-dialog-title>Delete account #{{ data.account.id }}</h3>
|
||||||
<h3 class="modal-title" id="modal-title">{{ title() }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body" id="modal-body">
|
<md-dialog-content>
|
||||||
<p>
|
Do you really want to delete account #{{ data.account.id }} with name:<br/>
|
||||||
Do you really want to delete account #{{ account.id }} with name:<br/>
|
{{ data.account.name }}
|
||||||
{{ account.name }}
|
</md-dialog-content>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
<md-dialog-actions>
|
||||||
<button class="btn btn-danger" (click)="submit()">
|
<button md-raised-button color="warn" [md-dialog-close]="data.account">
|
||||||
Yes
|
Yes
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-default" (click)="cancel()">
|
<button md-raised-button md-dialog-close>
|
||||||
No
|
No
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</md-dialog-actions>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class AccountDeleteModalComponent {
|
export class AccountDeleteModalComponent {
|
||||||
@Input() account: Account
|
constructor(
|
||||||
|
@Inject(MD_DIALOG_DATA) private data: any
|
||||||
constructor(public activeModal: NgbActiveModal) {}
|
) {}
|
||||||
|
|
||||||
title(): string {
|
|
||||||
if(this.account.id) {
|
|
||||||
return "Account #" + this.account.id;
|
|
||||||
} else {
|
|
||||||
return "New account";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
submit(): void {
|
|
||||||
this.activeModal.close(this.account);
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel(): void {
|
|
||||||
this.activeModal.dismiss("closed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2:
|
// vim: set tw=80 ts=2 sw=2 sts=2:
|
||||||
import { Component, Input, ViewChild } from '@angular/core';
|
import { Component, Inject, ViewChild } from '@angular/core';
|
||||||
|
import { MdDialogRef, MD_DIALOG_DATA } from '@angular/material';
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
|
|
||||||
import { Account } from './account';
|
import { Account } from './account';
|
||||||
import { AccountFormComponent } from './accountForm.component';
|
import { AccountFormComponent } from './accountForm.component';
|
||||||
@ -9,33 +8,37 @@ import { AccountFormComponent } from './accountForm.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'account-edit-modal',
|
selector: 'account-edit-modal',
|
||||||
template: `
|
template: `
|
||||||
<div class="modal-header">
|
<h3 md-dialog-title>{{ title() }}</h3>
|
||||||
<h3 class="modal-title" id="modal-title">{{ title() }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body" id="modal-body">
|
<md-dialog-content>
|
||||||
<account-form [account]="account" (submit)="submit()" #accountForm="accountForm"></account-form>
|
<account-form [account]="account" (submit)="submit()" #accountForm="accountForm">
|
||||||
</div>
|
</account-form>
|
||||||
|
</md-dialog-content>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<md-dialog-actions>
|
||||||
<button class="btn btn-primary" [disabled]="!accountForm.form.valid" (click)="submit()">
|
<button md-raised-button color="primary" [disabled]="!accountForm?.form.valid" (click)="submit()">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-default" (click)="cancel()">
|
<button md-raised-button color="warn" md-dialog-close>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</md-dialog-actions>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class AccountEditModalComponent {
|
export class AccountEditModalComponent {
|
||||||
@Input() account: Account;
|
private account: Account;
|
||||||
@ViewChild('accountForm') accountForm: AccountFormComponent;
|
@ViewChild('accountForm') accountForm: AccountFormComponent;
|
||||||
|
|
||||||
constructor(private activeModal: NgbActiveModal) {}
|
constructor(
|
||||||
|
@Inject(MD_DIALOG_DATA) public data: any,
|
||||||
|
public dialogRef: MdDialogRef<AccountEditModalComponent>,
|
||||||
|
) {
|
||||||
|
this.account = data.account;
|
||||||
|
}
|
||||||
|
|
||||||
title(): string {
|
title(): string {
|
||||||
if(this.account.id) {
|
if(this.account && this.account.id) {
|
||||||
return "Account #" + this.account.id;
|
return "Account #" + this.account.id;
|
||||||
} else {
|
} else {
|
||||||
return "New account";
|
return "New account";
|
||||||
@ -48,12 +51,8 @@ export class AccountEditModalComponent {
|
|||||||
|
|
||||||
account.id = this.account.id;
|
account.id = this.account.id;
|
||||||
account.name = formModel.name;
|
account.name = formModel.name;
|
||||||
account.authorized_overdraft = formModel.authorizedOverdraft;
|
account.authorized_overdraft = -formModel.authorizedOverdraft;
|
||||||
|
|
||||||
this.activeModal.close(account);
|
this.dialogRef.close(account);
|
||||||
}
|
|
||||||
|
|
||||||
cancel(): void {
|
|
||||||
this.activeModal.dismiss("closed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,51 +8,33 @@ import { Account } from './account';
|
|||||||
selector: 'account-form',
|
selector: 'account-form',
|
||||||
exportAs: 'accountForm',
|
exportAs: 'accountForm',
|
||||||
template: `
|
template: `
|
||||||
<form novalidate
|
<form novalidate (keyup.enter)="submit()" [formGroup]="form">
|
||||||
(keyup.enter)="submit()" [formGroup]="form">
|
<md-list>
|
||||||
<div class="form-group row">
|
<md-list-item>
|
||||||
<label class="col-sm-4 control-label" for="name">
|
<md-form-field>
|
||||||
Account name
|
<input mdInput formControlName="name" placeholder="Account name">
|
||||||
</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8"
|
<md-error *ngIf="name.errors?.required">The account name is required.</md-error>
|
||||||
[class.has-danger]="name.errors">
|
</md-form-field>
|
||||||
<input class="form-control"
|
</md-list-item>
|
||||||
id="name" formControlName="name"
|
|
||||||
placeholder="Account name">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="name.errors">
|
<md-list-item>
|
||||||
<p *ngIf="name.errors.required">The account name is required.</p>
|
<md-form-field>
|
||||||
</div>
|
<span mdPrefix>-</span>
|
||||||
</div>
|
<input mdInput formControlName="authorizedOverdraft"
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 control-label" for="authorized-overdraft">
|
|
||||||
Authorized overdraft
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8"
|
|
||||||
[class.has-danger]="authorizedOverdraft.errors">
|
|
||||||
<div class="input-group">
|
|
||||||
<input class="form-control"
|
|
||||||
id="authorized-overdraft" formControlName="authorizedOverdraft"
|
|
||||||
placeholder="Authorized overdraft">
|
placeholder="Authorized overdraft">
|
||||||
|
<span mdSuffix>.00€</span>
|
||||||
|
|
||||||
<div class="input-group-addon">.00€</div>
|
<md-error *ngIf="authorizedOverdraft.errors?.required">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="authorizedOverdraft.errors">
|
|
||||||
<p *ngIf="authorizedOverdraft.errors.required">
|
|
||||||
The authorized overdraft is required.
|
The authorized overdraft is required.
|
||||||
</p>
|
</md-error>
|
||||||
|
|
||||||
<p *ngIf="authorizedOverdraft.errors.max">
|
<md-error *ngIf="authorizedOverdraft.errors?.min">
|
||||||
The authorized overdraft must be less than or equal to 0.
|
The authorized overdraft must be less than or equal to 0.
|
||||||
</p>
|
</md-error>
|
||||||
</div>
|
</md-form-field>
|
||||||
</div>
|
</md-list-item>
|
||||||
</div>
|
</md-list>
|
||||||
</form>
|
</form>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
@ -66,12 +48,12 @@ export class AccountFormComponent implements OnInit {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.form = this.formBuilder.group({
|
this.form = this.formBuilder.group({
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
authorizedOverdraft: ['', [Validators.required, Validators.max(0)]],
|
authorizedOverdraft: ['', [Validators.required, Validators.min(0)]],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.form.patchValue({
|
this.form.patchValue({
|
||||||
name: this.account.name,
|
name: this.account.name,
|
||||||
authorizedOverdraft: this.account.authorized_overdraft
|
authorizedOverdraft: -this.account.authorized_overdraft
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,87 +1,141 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2 :
|
// vim: set tw=80 ts=2 sw=2 sts=2 :
|
||||||
import { Component, Inject, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { MdDialog } from '@angular/material';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
|
||||||
import { Logger } from '@nsalaun/ng-logger';
|
import { Logger } from '@nsalaun/ng-logger';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
|
||||||
import { Account } from './account';
|
import { Account } from './account';
|
||||||
import { AccountBalances } from './accountBalances';
|
import { AccountBalances } from './accountBalances';
|
||||||
|
import { AccountDataSource } from './account.dataSource';
|
||||||
import { AccountService } from './account.service';
|
import { AccountService } from './account.service';
|
||||||
|
import { AccountDeleteModalComponent } from './accountDeleteModal.component';
|
||||||
import { AccountEditModalComponent } from './accountEditModal.component';
|
import { AccountEditModalComponent } from './accountEditModal.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'account-list',
|
selector: 'account-list',
|
||||||
template: `
|
template: `
|
||||||
<div class="row">
|
<div class="containerX">
|
||||||
<table class="table table-sm table-striped table-condensed table-hover">
|
<div class="container">
|
||||||
<thead>
|
<button md-fab color="primary" (click)="add()">
|
||||||
<tr>
|
<md-icon>add</md-icon>
|
||||||
<th>Nom du compte</th>
|
</button>
|
||||||
<th>Solde courant</th>
|
</div>
|
||||||
<th>Solde pointé</th>
|
|
||||||
<th>Découvert autorisé</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
<div class="container">
|
||||||
<tr>
|
<md-table #table [dataSource]="accounts">
|
||||||
<td colspan="5">
|
<ng-container mdColumnDef="name">
|
||||||
<button class="btn btn-success" (click)="add()">
|
<md-header-cell *mdHeaderCellDef>Nom du compte</md-header-cell>
|
||||||
Ajouter
|
<md-cell *mdCellDef="let account">
|
||||||
|
<a [routerLink]="['/account', account.id, 'operations']">
|
||||||
|
{{ account.name }}
|
||||||
|
</a>
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="current">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Solde courant</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let account">
|
||||||
|
<span
|
||||||
|
[class.warning]="account.authorized_overdraft < 0 && account.balances?.current < 0"
|
||||||
|
[class.error]="account.balances?.current < account.authorized_overdraft">
|
||||||
|
{{ account.balances?.current | currency:"EUR":true }}
|
||||||
|
</span>
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="pointed">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Solde pointé</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let account">
|
||||||
|
<span
|
||||||
|
[class.warning]="account.authorized_overdraft < 0 && account.balances?.pointed < 0"
|
||||||
|
[class.error]="account.balances?.pointed < account.authorized_overdraft">
|
||||||
|
{{ account.balances?.pointed | currency:"EUR":true }}
|
||||||
|
</span>
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="authorizedOverdraft">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Découvert autorisé</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let account">
|
||||||
|
{{ account.authorized_overdraft | currency:"EUR":true }}
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="actions">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Actions</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let account">
|
||||||
|
<!-- Edit account. -->
|
||||||
|
<button md-mini-fab color="primary"
|
||||||
|
(click)="modify(account)">
|
||||||
|
<md-icon>mode_edit</md-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr *ngFor="let account of accounts"
|
<!-- Delete account, with confirm. -->
|
||||||
[account-row]="account" (needsReload)="load()">
|
<button md-mini-fab color="warn"
|
||||||
</tr>
|
(click)="confirmDelete(account)">
|
||||||
</tbody>
|
<md-icon>delete_forever</md-icon>
|
||||||
</table>
|
</button>
|
||||||
|
|
||||||
|
<!-- Open account scheduler. -->
|
||||||
|
<button md-mini-fab
|
||||||
|
[hidden]="!account.id"
|
||||||
|
[routerLink]="['/account', account.id, 'scheduler']">
|
||||||
|
<md-icon>event</md-icon>
|
||||||
|
</button>
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<md-header-row *mdHeaderRowDef="displayedColumns"></md-header-row>
|
||||||
|
<md-row *mdRowDef="let row; columns: displayedColumns;">
|
||||||
|
</md-row>
|
||||||
|
</md-table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
export class AccountListComponent implements OnInit {
|
export class AccountListComponent {
|
||||||
accounts: Account[];
|
displayedColumns: String[] = [
|
||||||
|
'name', 'current', 'pointed', 'authorizedOverdraft', 'actions'
|
||||||
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private accounts: AccountDataSource,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
private toastrService: ToastrService,
|
private toastrService: ToastrService,
|
||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
private ngbModal: NgbModal
|
private mdDialog: MdDialog,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
// Load accounts.
|
|
||||||
this.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
load() {
|
|
||||||
this.logger.log("Load accounts.");
|
|
||||||
this.accountService.query().subscribe(accounts => {
|
|
||||||
this.accounts = accounts;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add an empty account.
|
* Add an empty account.
|
||||||
*/
|
*/
|
||||||
add() {
|
add() {
|
||||||
const modal = this.ngbModal.open(AccountEditModalComponent, {
|
this.modify(new Account());
|
||||||
size: 'lg'
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modify an account.
|
||||||
|
*/
|
||||||
|
modify(account: Account) {
|
||||||
|
let dialogRef = this.mdDialog.open(AccountEditModalComponent, {
|
||||||
|
data: {
|
||||||
|
account: account,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.componentInstance.account = new Account();
|
dialogRef.afterClosed().subscribe((account: Account) => {
|
||||||
|
if(account) {
|
||||||
modal.result.then((account: Account) => {
|
this.logger.log("Modal closed => save account", account);
|
||||||
this.logger.log("Modal closed => save account", account);
|
this.save(account);
|
||||||
this.save(account);
|
} else {
|
||||||
|
this.logger.log("Modal dismissed");
|
||||||
|
}
|
||||||
}, (reason) => function(reason) {
|
}, (reason) => function(reason) {
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save account.
|
* Save account.
|
||||||
@ -89,8 +143,6 @@ export class AccountListComponent implements OnInit {
|
|||||||
save(account) {
|
save(account) {
|
||||||
this.accountService.create(account).subscribe(account => {
|
this.accountService.create(account).subscribe(account => {
|
||||||
this.toastrService.success('Account #' + account.id + ' saved.');
|
this.toastrService.success('Account #' + account.id + ' saved.');
|
||||||
|
|
||||||
this.load();
|
|
||||||
}, result => {
|
}, result => {
|
||||||
this.logger.error('Error while saving account', account, result);
|
this.logger.error('Error while saving account', account, result);
|
||||||
|
|
||||||
@ -99,4 +151,41 @@ export class AccountListComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show a dialog to confirm account deletion.
|
||||||
|
*/
|
||||||
|
confirmDelete(account: Account) {
|
||||||
|
let dialogRef = this.mdDialog.open(AccountDeleteModalComponent, {
|
||||||
|
data: {
|
||||||
|
account: account,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((account: Account) => {
|
||||||
|
if(account) {
|
||||||
|
this.delete(account);
|
||||||
|
}
|
||||||
|
}, reason => {
|
||||||
|
this.logger.error("Delete dialog failed", reason);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete an account.
|
||||||
|
*/
|
||||||
|
delete(account: Account) {
|
||||||
|
var id = account.id;
|
||||||
|
|
||||||
|
this.accountService.delete(account).subscribe(account => {
|
||||||
|
this.toastrService.success('account #' + id + ' deleted.');
|
||||||
|
|
||||||
|
// FIXME Alexis Lahouze 2017-09-17 Remove from array.
|
||||||
|
}, function(result) {
|
||||||
|
this.toastrService.error(
|
||||||
|
'An error occurred while trying to delete account #' +
|
||||||
|
id + ':<br />' + result
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,176 +0,0 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2 :
|
|
||||||
import { CurrencyPipe } from '@angular/common';
|
|
||||||
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
|
|
||||||
|
|
||||||
import { Logger } from '@nsalaun/ng-logger';
|
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
|
||||||
|
|
||||||
import { Account } from './account';
|
|
||||||
import { AccountBalances } from './accountBalances';
|
|
||||||
import { AccountBalancesService } from './accountBalances.service';
|
|
||||||
import { AccountService } from './account.service';
|
|
||||||
import { AccountDeleteModalComponent } from './accountDeleteModal.component';
|
|
||||||
import { AccountEditModalComponent } from './accountEditModal.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'tr[account-row]',
|
|
||||||
host: {
|
|
||||||
"[id]": "account.id",
|
|
||||||
"[class.warning]": "warning",
|
|
||||||
"[class.danger]": "danger"
|
|
||||||
},
|
|
||||||
template: `
|
|
||||||
<td>
|
|
||||||
<a [routerLink]="['/account', account.id, 'operations']">{{ account.name }}</a>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<span (ngClass)="valueClass(account, accountBalances?.current)">
|
|
||||||
{{ accountBalances?.current | currency:"EUR":true }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<span (ngClass)="valueClass(account, accountBalances?.pointed)">
|
|
||||||
{{ accountBalances?.pointed | currency:"EUR":true }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>{{ account.authorized_overdraft | currency:"EUR":true }}</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<div class="btn-group btn-group-sm">
|
|
||||||
<!-- Edit account. -->
|
|
||||||
<button type="button" class="btn btn-success"
|
|
||||||
(click)="modify()">
|
|
||||||
<span class="fa fa-pencil-square-o"></span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Delete account, with confirm. -->
|
|
||||||
<button type="button" class="btn btn-secondary"
|
|
||||||
(click)="confirmDelete()">
|
|
||||||
<span class="fa fa-trash-o"></span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Open account scheduler. -->
|
|
||||||
<a class="btn btn-secondary"
|
|
||||||
[hidden]="!account.id"
|
|
||||||
[routerLink]="['/account', account.id, 'scheduler']">
|
|
||||||
<span class="fa fa-clock-o"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
export class AccountRowComponent implements OnInit {
|
|
||||||
@Input('account-row') account: Account;
|
|
||||||
@Output() needsReload: EventEmitter<void> = new EventEmitter<void>();
|
|
||||||
|
|
||||||
private accountBalances: AccountBalances;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private accountService: AccountService,
|
|
||||||
private accountBalancesService: AccountBalancesService,
|
|
||||||
private toastrService: ToastrService,
|
|
||||||
private logger: Logger,
|
|
||||||
private ngbModal: NgbModal
|
|
||||||
) {
|
|
||||||
this.logger.log("AccountRowComponent constructor");
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.logger.log(this.account);
|
|
||||||
this.accountBalancesService
|
|
||||||
.get(this.account.id)
|
|
||||||
.subscribe((accountBalances: AccountBalances) => {
|
|
||||||
this.accountBalances = accountBalances;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
get warning() {
|
|
||||||
return this.account && this.accountBalances
|
|
||||||
&& this.account.authorized_overdraft < this.accountBalances.current
|
|
||||||
&& this.accountBalances.current < 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
get error() {
|
|
||||||
return this.account && this.accountBalances
|
|
||||||
&& this.accountBalances.current < this.account.authorized_overdraft;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the class for a value compared to account authorized overdraft.
|
|
||||||
*/
|
|
||||||
valueClass(value: number) {
|
|
||||||
if (!value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value < this.account.authorized_overdraft) {
|
|
||||||
return 'text-danger';
|
|
||||||
} else if (value < 0) {
|
|
||||||
return 'text-warning';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
confirmDelete() {
|
|
||||||
const modal = this.ngbModal.open(AccountDeleteModalComponent);
|
|
||||||
|
|
||||||
modal.componentInstance.account = this.account;
|
|
||||||
|
|
||||||
modal.result.then((account: Account) => {
|
|
||||||
this.delete(account);
|
|
||||||
}, (reason) => function(reason) {
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete an account.
|
|
||||||
*/
|
|
||||||
delete(account: Account) {
|
|
||||||
var id = account.id;
|
|
||||||
|
|
||||||
this.accountService.delete(account).subscribe(account => {
|
|
||||||
this.toastrService.success('account #' + id + ' deleted.');
|
|
||||||
|
|
||||||
this.needsReload.emit();
|
|
||||||
}, function(result) {
|
|
||||||
this.toastrService.error(
|
|
||||||
'An error occurred while trying to delete account #' +
|
|
||||||
id + ':<br />' + result
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open the popup to modify the account, save it on confirm.
|
|
||||||
*/
|
|
||||||
modify() {
|
|
||||||
const modal = this.ngbModal.open(AccountEditModalComponent, {
|
|
||||||
size: 'lg'
|
|
||||||
});
|
|
||||||
|
|
||||||
modal.componentInstance.account = this.account;
|
|
||||||
|
|
||||||
modal.result.then((account: Account) => {
|
|
||||||
this.logger.log("Modal closed => save account", account);
|
|
||||||
this.save(account);
|
|
||||||
}, (reason) => function(reason) {
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
save(account: Account) {
|
|
||||||
this.accountService.update(account).subscribe((account: Account) => {
|
|
||||||
this.toastrService.success('Account #' + account.id + ' saved.');
|
|
||||||
|
|
||||||
this.needsReload.emit();
|
|
||||||
}, result => {
|
|
||||||
this.logger.error('Error while saving account', account, result);
|
|
||||||
|
|
||||||
this.toastrService.error(
|
|
||||||
'Error while saving account: ' + result.message
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
@ -4,13 +4,18 @@ import { Component } from '@angular/core';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'accountant',
|
selector: 'accountant',
|
||||||
|
styles: [ require('./main.scss').toString() ],
|
||||||
template: `
|
template: `
|
||||||
<!-- Navbar -->
|
<md-toolbar class="mat-elevation-z6" color="primary">
|
||||||
<nav class="navbar fixed-top navbar-dark bg-dark">
|
<div class="acc-toolbar">
|
||||||
<a class="navbar-brand" routerLink="/accounts"> Accountant</a>
|
<a md-button style="text-transform: uppercase"
|
||||||
</nav>
|
routerLink="/accounts">
|
||||||
|
Accountant
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</md-toolbar>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="acc-content">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
@ -3,6 +3,12 @@ import 'zone.js';
|
|||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
import {
|
||||||
|
MdButtonModule,
|
||||||
|
MdToolbarModule,
|
||||||
|
MdSidenavModule
|
||||||
|
} from '@angular/material';
|
||||||
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
@ -34,6 +40,10 @@ import { ApiBaseURL, LogLevel } from './app.config';
|
|||||||
enableTracing: true,
|
enableTracing: true,
|
||||||
useHash: true
|
useHash: true
|
||||||
}),
|
}),
|
||||||
|
FlexLayoutModule,
|
||||||
|
MdButtonModule,
|
||||||
|
MdToolbarModule,
|
||||||
|
MdSidenavModule,
|
||||||
LoginModule,
|
LoginModule,
|
||||||
NgLoggerModule.forRoot(LogLevel),
|
NgLoggerModule.forRoot(LogLevel),
|
||||||
ToastrModule.forRoot(),
|
ToastrModule.forRoot(),
|
||||||
|
@ -5,6 +5,12 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
|
import {
|
||||||
|
MdButtonModule,
|
||||||
|
MdDialogModule,
|
||||||
|
MdInputModule,
|
||||||
|
MdListModule,
|
||||||
|
} from '@angular/material';
|
||||||
|
|
||||||
import { NgLoggerModule } from '@nsalaun/ng-logger';
|
import { NgLoggerModule } from '@nsalaun/ng-logger';
|
||||||
|
|
||||||
@ -19,6 +25,10 @@ import { LoginModalComponent } from './loginModal.component';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
NgLoggerModule,
|
NgLoggerModule,
|
||||||
|
MdButtonModule,
|
||||||
|
MdDialogModule,
|
||||||
|
MdInputModule,
|
||||||
|
MdListModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
LoginService,
|
LoginService,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
|
import { MdDialog } from '@angular/material';
|
||||||
|
|
||||||
import { Observable} from 'rxjs/Rx';
|
import { Observable} from 'rxjs/Rx';
|
||||||
|
|
||||||
import * as base64 from 'base64util';
|
import * as base64 from 'base64util';
|
||||||
|
|
||||||
import { Logger } from '@nsalaun/ng-logger';
|
import { Logger } from '@nsalaun/ng-logger';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
|
|
||||||
import { Token } from './token';
|
import { Token } from './token';
|
||||||
import { LoginModalComponent } from './loginModal.component';
|
import { LoginModalComponent } from './loginModal.component';
|
||||||
@ -18,19 +18,17 @@ export class LoginService {
|
|||||||
constructor(
|
constructor(
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
private ngbModal: NgbModal,
|
private mdDialog: MdDialog,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public readonly url: string = '/api/user/login';
|
public readonly url: string = '/api/user/login';
|
||||||
|
|
||||||
login(): Observable<Token> {
|
login(): Observable<Token> {
|
||||||
let modal = this.ngbModal.open(LoginModalComponent);
|
let dialogRef = this.mdDialog.open(LoginModalComponent);
|
||||||
|
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
|
|
||||||
let observable: Observable<any> = Observable.fromPromise(modal.result);
|
return dialogRef.afterClosed().flatMap((login: Login) =>
|
||||||
|
|
||||||
return observable.flatMap((login: Login) =>
|
|
||||||
this.doLogin(login)
|
this.doLogin(login)
|
||||||
).map((token: Token): Token => {
|
).map((token: Token): Token => {
|
||||||
this.accessToken = token.access_token;
|
this.accessToken = token.access_token;
|
||||||
|
@ -9,33 +9,25 @@ import { Login } from './login';
|
|||||||
exportAs: 'loginForm',
|
exportAs: 'loginForm',
|
||||||
template: `
|
template: `
|
||||||
<form novalidate (keyup.enter)="submit()" [formGroup]="form">
|
<form novalidate (keyup.enter)="submit()" [formGroup]="form">
|
||||||
<div class="form-group row">
|
<md-list>
|
||||||
<label for="email" class="col-sm-4 control-label">Adresse email</label>
|
<md-list-item>
|
||||||
|
<md-form-field>
|
||||||
|
<input mdInput type="text"
|
||||||
|
formControlName="email" placeholder="Nom d'utilisateur">
|
||||||
|
|
||||||
<div class="col-sm-8"
|
<md-error *ngIf="email.errors?.required">The email is required.</md-error>
|
||||||
[class.has-danger]="email.errors">
|
</md-form-field>
|
||||||
<input type="text" class="form-control" id="email"
|
</md-list-item>
|
||||||
formControlName="email" placeholder="Nom d'utilisateur">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="email.errors">
|
<md-list-item>
|
||||||
<p *ngIf="email.errors.required">The email is required.</p>
|
<md-form-field>
|
||||||
</div>
|
<input mdInput type="password"
|
||||||
</div>
|
formControlName="password" placeholder="Mot de passe">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
<md-error *ngIf="password.errors?.required">The password is required.</md-error>
|
||||||
<label for="password" class="col-sm-4 control-label">Mot de passe</label>
|
</md-form-field>
|
||||||
|
</md-list-item>
|
||||||
<div class="col-sm-8"
|
</md-list>
|
||||||
[class.has-danger]="password.errors">
|
|
||||||
<input type="password" class="form-control" id="password"
|
|
||||||
formControlName="password" placeholder="Mot de passe">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="password.errors">
|
|
||||||
<p *ngIf="password.errors.required">The password is required.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2:
|
// vim: set tw=80 ts=2 sw=2 sts=2:
|
||||||
import { Component, Input, ViewChild } from '@angular/core';
|
import { Component, Input, ViewChild } from '@angular/core';
|
||||||
|
import { MdDialogRef } from '@angular/material';
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
|
|
||||||
import { Login } from './login';
|
import { Login } from './login';
|
||||||
import { LoginFormComponent } from './loginForm.component';
|
import { LoginFormComponent } from './loginForm.component';
|
||||||
@ -9,31 +8,29 @@ import { LoginFormComponent } from './loginForm.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'login-modal',
|
selector: 'login-modal',
|
||||||
template: `
|
template: `
|
||||||
<div class="modal-header">
|
<h2 md-dialog-title>Authentification requise</h2>
|
||||||
<h3 class="modal-title" id="modal-title">Authentification requise</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body" id="modal-body">
|
<md-dialog-content>
|
||||||
<login-form (submit)="submit()" #loginForm="loginForm"></login-form>
|
<login-form (submit)="submit()" #loginForm="loginForm"></login-form>
|
||||||
</div>
|
</md-dialog-content>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<md-dialog-actions>
|
||||||
<button class="btn btn-primary" [disabled]="!loginForm.form.valid" (click)="submit()">
|
<button md-button [disabled]="!loginForm.form.valid" (click)="submit()">
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-default" (click)="cancel()">
|
<button md-button md-dialog-close>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</md-dialog-actions>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class LoginModalComponent {
|
export class LoginModalComponent {
|
||||||
@ViewChild('loginForm') loginForm: LoginFormComponent;
|
@ViewChild('loginForm') loginForm: LoginFormComponent;
|
||||||
|
|
||||||
constructor(private activeModal: NgbActiveModal) {
|
constructor(
|
||||||
|
public dialogRef: MdDialogRef<LoginModalComponent>,
|
||||||
}
|
) {}
|
||||||
|
|
||||||
submit(): void {
|
submit(): void {
|
||||||
let formModel = this.loginForm.form.value;
|
let formModel = this.loginForm.form.value;
|
||||||
@ -42,10 +39,6 @@ export class LoginModalComponent {
|
|||||||
login.email = formModel.email;
|
login.email = formModel.email;
|
||||||
login.password = formModel.password;
|
login.password = formModel.password;
|
||||||
|
|
||||||
this.activeModal.close(login);
|
this.dialogRef.close(login);
|
||||||
}
|
|
||||||
|
|
||||||
cancel(): void {
|
|
||||||
this.activeModal.dismiss("closed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,97 @@
|
|||||||
|
// vim: set tw=80 ts=2 sw=2 sts=2:
|
||||||
|
|
||||||
$fa-font-path: '~font-awesome/fonts';
|
$fa-font-path: '~font-awesome/fonts';
|
||||||
|
|
||||||
@import '~font-awesome/scss/font-awesome';
|
@import '~font-awesome/scss/font-awesome';
|
||||||
|
|
||||||
@import '~bootstrap/scss/bootstrap';
|
|
||||||
|
|
||||||
@import '~c3/c3';
|
@import '~c3/c3';
|
||||||
|
|
||||||
@import '~ngx-toastr/toastr';
|
@import '~ngx-toastr/toastr';
|
||||||
|
|
||||||
|
$roboto-font-path: '~roboto-fontface/fonts/roboto/';
|
||||||
|
@import '~@angular/material/_theming';
|
||||||
|
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
|
||||||
|
|
||||||
|
@import '~material-design-icons/iconfont/material-icons.css';
|
||||||
|
|
||||||
|
/*.fixed-header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Roboto, 'Helvetica Neue', sans-serif;
|
||||||
|
|
||||||
|
// Helps fonts on OSX looks more consistent with other systems
|
||||||
|
// Isn't currently in button styles due to performance concerns
|
||||||
|
* {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.acc-content {
|
||||||
|
padding: 32px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-toolbar {
|
||||||
|
.acc-toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
md-dialog > form {
|
||||||
|
overflow: visible;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// stretch to screen size in fullscreen mode
|
||||||
|
.acc-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
.italic {
|
.italic {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stroke {
|
.stroke {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3-ygrid-line.zeroline line {
|
.c3-ygrid-line.zeroline line {
|
||||||
stroke: orange;
|
stroke: orange;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c3-ygrid-line.overdraft line {
|
.c3-ygrid-line.overdraft line {
|
||||||
stroke: #FF0000;
|
stroke: #FF0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.warning {
|
||||||
|
color: mat-color($mat-amber, A700);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-row.warning {
|
||||||
|
background-color: mat-color($mat-amber, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.error {
|
||||||
|
color: mat-color($mat-red, A700);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-row.error {
|
||||||
|
background-color: mat-color($mat-red, 100);
|
||||||
}
|
}
|
||||||
|
40
src/scheduler/schedule.dataSource.ts
Normal file
40
src/scheduler/schedule.dataSource.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// vim: set tw=80 ts=2 sw=2 sts=2:
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { DataSource } from '@angular/cdk/collections';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
|
import { Logger } from '@nsalaun/ng-logger';
|
||||||
|
|
||||||
|
import { Schedule } from './schedule';
|
||||||
|
import { ScheduleService } from './schedule.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ScheduleDataSource extends DataSource<Schedule> {
|
||||||
|
private subject: BehaviorSubject<number> = new BehaviorSubject<number>(null);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private scheduleService: ScheduleService,
|
||||||
|
private logger: Logger,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
load(accountId: number): void {
|
||||||
|
this.logger.log("In load", accountId);
|
||||||
|
this.subject.next(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(): Observable<Schedule[]> {
|
||||||
|
return this.subject.asObservable().concatMap((accountId: number) => {
|
||||||
|
this.logger.log("In connect", accountId);
|
||||||
|
|
||||||
|
if(accountId) {
|
||||||
|
return this.scheduleService.query(accountId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {}
|
||||||
|
}
|
@ -3,6 +3,14 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import {
|
||||||
|
MdButtonModule,
|
||||||
|
MdDialogModule,
|
||||||
|
MdIconModule,
|
||||||
|
MdInputModule,
|
||||||
|
MdListModule,
|
||||||
|
MdTableModule,
|
||||||
|
} from '@angular/material';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
@ -12,10 +20,10 @@ import { ToastrModule } from 'ngx-toastr';
|
|||||||
import { TextMaskModule } from 'angular2-text-mask';
|
import { TextMaskModule } from 'angular2-text-mask';
|
||||||
|
|
||||||
import { ScheduleService } from './schedule.service';
|
import { ScheduleService } from './schedule.service';
|
||||||
|
import { ScheduleDataSource } from './schedule.dataSource';
|
||||||
import { ScheduleDeleteModalComponent } from './scheduleDeleteModal.component';
|
import { ScheduleDeleteModalComponent } from './scheduleDeleteModal.component';
|
||||||
import { ScheduleEditModalComponent } from './scheduleEditModal.component';
|
import { ScheduleEditModalComponent } from './scheduleEditModal.component';
|
||||||
import { ScheduleFormComponent } from './scheduleForm.component';
|
import { ScheduleFormComponent } from './scheduleForm.component';
|
||||||
import { ScheduleRowComponent } from './scheduleRow.component';
|
|
||||||
import { ScheduleListComponent } from './scheduleList.component';
|
import { ScheduleListComponent } from './scheduleList.component';
|
||||||
import { ScheduleListState } from './schedule.states';
|
import { ScheduleListState } from './schedule.states';
|
||||||
|
|
||||||
@ -27,6 +35,12 @@ import { ScheduleListState } from './schedule.states';
|
|||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
ScheduleListState
|
ScheduleListState
|
||||||
]),
|
]),
|
||||||
|
MdButtonModule,
|
||||||
|
MdDialogModule,
|
||||||
|
MdIconModule,
|
||||||
|
MdInputModule,
|
||||||
|
MdListModule,
|
||||||
|
MdTableModule,
|
||||||
NgLoggerModule,
|
NgLoggerModule,
|
||||||
ToastrModule,
|
ToastrModule,
|
||||||
NgbModule,
|
NgbModule,
|
||||||
@ -34,13 +48,13 @@ import { ScheduleListState } from './schedule.states';
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ScheduleService,
|
ScheduleService,
|
||||||
|
ScheduleDataSource,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
ScheduleDeleteModalComponent,
|
ScheduleDeleteModalComponent,
|
||||||
ScheduleEditModalComponent,
|
ScheduleEditModalComponent,
|
||||||
ScheduleFormComponent,
|
ScheduleFormComponent,
|
||||||
ScheduleListComponent,
|
ScheduleListComponent,
|
||||||
ScheduleRowComponent
|
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
ScheduleDeleteModalComponent,
|
ScheduleDeleteModalComponent,
|
||||||
|
@ -1,49 +1,34 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2:
|
// vim: set tw=80 ts=2 sw=2 sts=2:
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { MD_DIALOG_DATA } from '@angular/material';
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
|
|
||||||
import { Schedule } from './schedule';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'schedule-delete-modal',
|
selector: 'schedule-delete-modal',
|
||||||
template: `
|
template: `
|
||||||
<div class="modal-header">
|
<h3 md-dialog-title>{{ title() }}</h3>
|
||||||
<h3 class="modal-title" id="modal-title">{{ title() }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body" id="modal-body">
|
<md-dialog-content>
|
||||||
<p>
|
Do you really want to delete schedule #{{ data.schedule.id }} with label:<br/>
|
||||||
Do you really want to delete schedule #{{ schedule.id }} with label:<br/>
|
{{ data.schedule.label }}
|
||||||
{{ schedule.label }}
|
</md-dialog-content>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
<md-dialog-actions>
|
||||||
<button class="btn btn-danger" (click)="submit()">
|
<button md-raised-button color="warn" [md-dialog-close]="data.schedule">
|
||||||
Yes
|
Yes
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-default" (click)="cancel()">
|
<button md-raised-button md-dialog-close>
|
||||||
No
|
No
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</md-dialog-actions>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class ScheduleDeleteModalComponent {
|
export class ScheduleDeleteModalComponent {
|
||||||
@Input() schedule: Schedule
|
constructor(
|
||||||
|
@Inject(MD_DIALOG_DATA) private data: any
|
||||||
constructor(public activeModal: NgbActiveModal) {}
|
) {}
|
||||||
|
|
||||||
title(): string {
|
title(): string {
|
||||||
return "Delete schedule #" + this.schedule.id;
|
return "Delete schedule #" + this.data.schedule.id;
|
||||||
}
|
|
||||||
|
|
||||||
submit(): void {
|
|
||||||
this.activeModal.close(this.schedule);
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel(): void {
|
|
||||||
this.activeModal.dismiss("closed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2:
|
// vim: set tw=80 ts=2 sw=2 sts=2:
|
||||||
import { Component, Input, ViewChild } from '@angular/core';
|
import { Component, Inject, ViewChild } from '@angular/core';
|
||||||
|
import { MdDialogRef, MD_DIALOG_DATA } from '@angular/material';
|
||||||
|
|
||||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
@ -9,32 +10,33 @@ import { ScheduleFormComponent } from './scheduleForm.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'schedule-edit-modal',
|
selector: 'schedule-edit-modal',
|
||||||
template: `
|
template: `
|
||||||
<div class="modal-header">
|
<h3 md-dialog-title>{{ title() }}</h3>
|
||||||
<h3 class="modal-title" id="modal-title">{{ title() }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body" id="modal-body">
|
<md-dialog-content>
|
||||||
<schedule-form [schedule]="schedule" (submit)="submit()" #scheduleForm="scheduleForm"></schedule-form>
|
<schedule-form [schedule]="schedule" (submit)="submit()" #scheduleForm="scheduleForm"></schedule-form>
|
||||||
</div>
|
</md-dialog-content>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<md-dialog-actions>
|
||||||
<button class="btn btn-primary" [disabled]="!scheduleForm.form.valid" (click)="submit()">
|
<button md-raised-button color="primary" [disabled]="!scheduleForm?.form.valid" (click)="submit()">
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class="btn btn-default" (click)="cancel()">
|
<button md-raised-button color="warn" md-dialog-close>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</md-dialog-actions>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class ScheduleEditModalComponent {
|
export class ScheduleEditModalComponent {
|
||||||
@Input() schedule: Schedule;
|
private schedule: Schedule;
|
||||||
@ViewChild('scheduleForm') scheduleForm: ScheduleFormComponent;
|
@ViewChild('scheduleForm') scheduleForm: ScheduleFormComponent;
|
||||||
|
|
||||||
valid: boolean = false;
|
constructor(
|
||||||
|
@Inject(MD_DIALOG_DATA) public data: any,
|
||||||
constructor(private activeModal: NgbActiveModal) {}
|
public dialogRef: MdDialogRef<ScheduleEditModalComponent>,
|
||||||
|
) {
|
||||||
|
this.schedule = data.schedule;
|
||||||
|
}
|
||||||
|
|
||||||
title(): string {
|
title(): string {
|
||||||
if(this.schedule.id) {
|
if(this.schedule.id) {
|
||||||
@ -57,10 +59,6 @@ export class ScheduleEditModalComponent {
|
|||||||
schedule.value = formModel.value;
|
schedule.value = formModel.value;
|
||||||
schedule.category = formModel.category;
|
schedule.category = formModel.category;
|
||||||
|
|
||||||
this.activeModal.close(schedule);
|
this.dialogRef.close(schedule);
|
||||||
}
|
|
||||||
|
|
||||||
cancel(): void {
|
|
||||||
this.activeModal.dismiss("closed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,115 +9,73 @@ import { Schedule } from './schedule';
|
|||||||
exportAs: 'scheduleForm',
|
exportAs: 'scheduleForm',
|
||||||
template: `
|
template: `
|
||||||
<form novalidate (keyup.enter)="submit()" [formGroup]="form">
|
<form novalidate (keyup.enter)="submit()" [formGroup]="form">
|
||||||
<div class="form-group row">
|
<md-list>
|
||||||
<label class="col-sm-4 control-label" for="start-date">Date de début (AAAA-MM-JJ)</label>
|
<md-list-item>
|
||||||
|
<md-form-field>
|
||||||
|
<input mdInput formControlName="startDate"
|
||||||
|
[textMask]="{mask: dateMask}"
|
||||||
|
placeholder="Schedule start date">
|
||||||
|
|
||||||
<div class="col-sm-8"
|
<md-error *ngIf="startDate.errors?.required">The start date is required.</md-error>
|
||||||
[class.has-danger]="startDate.errors">
|
</md-form-field>
|
||||||
<input class="form-control"
|
</md-list-item>
|
||||||
id="start-date" formControlName="startDate"
|
|
||||||
[textMask]="{mask: dateMask}"
|
|
||||||
placeholder="Schedule start date">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="startDate.errors">
|
<md-list-item>
|
||||||
<p *ngIf="startDate.errors.required">The start date is required.</p>
|
<md-form-field>
|
||||||
</div>
|
<input mdInput formControlName="stopDate"
|
||||||
</div>
|
[textMask]="{mask: dateMask}"
|
||||||
</div>
|
placeholder="Schedule stop date">
|
||||||
|
|
||||||
<div class="form-group row">
|
<md-error *ngIf="stopDate.errors?.required">The stop date is required.</md-error>
|
||||||
<label class="col-sm-4 control-label" for="stop-date">Date de fin (AAAA-MM-JJ)</label>
|
</md-form-field>
|
||||||
|
</md-list-item>
|
||||||
|
|
||||||
<div class="col-sm-8"
|
<md-list-item>
|
||||||
[class.has-danger]="stopDate.errors">
|
<md-form-field>
|
||||||
<input class="form-control"
|
<input mdInput formControlName="day"
|
||||||
id="stop-date" formControlName="stopDate"
|
type="number" placeholder="Day">
|
||||||
[textMask]="{mask: dateMask}"
|
|
||||||
placeholder="Schedule stop date">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="stopDate.errors">
|
<md-error *ngIf="day.errors?.required">The day is required.</md-error>
|
||||||
<p *ngIf="stopDate.errors.required">The stop date is required.</p>
|
<md-error *ngIf="day.errors?.min">The day must be greater than 0.</md-error>
|
||||||
</div>
|
<md-error *ngIf="day.errors?.max">The day must be less than or equal to 31.</md-error>
|
||||||
</div>
|
</md-form-field>
|
||||||
</div>
|
</md-list-item>
|
||||||
|
|
||||||
<div class="form-group row">
|
<md-list-item>
|
||||||
<label class="col-sm-4 control-label" for="day">Jour</label>
|
<md-form-field>
|
||||||
|
<input mdInput formControlName="frequency"
|
||||||
|
type="number" placeholder="Frequency">
|
||||||
|
|
||||||
<div class="col-sm-8"
|
<md-error *ngIf="frequency.errors?.required">The frequency is required.</md-error>
|
||||||
[class.has-danger]="day.errors">
|
<md-error *ngIf="frequency.errors?.min">The frequency must be positive.</md-error>
|
||||||
<input class="form-control"
|
</md-form-field>
|
||||||
id="day" formControlName="day"
|
</md-list-item>
|
||||||
type="number" placeholder="Day">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="day.errors">
|
<md-list-item>
|
||||||
<p *ngIf="day.errors.required">The day is required.</p>
|
<md-form-field>
|
||||||
<p *ngIf="day.errors.min">The day must be greater than 0.</p>
|
<input mdInput formControlName="label" placeholder="Label">
|
||||||
<p *ngIf="day.errors.max">The day must be less than or equal to 31.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
<md-error *ngIf="label.errors?.required">The label is required.</md-error>
|
||||||
<label class="col-sm-4 control-label" for="frequency">Fréquence</label>
|
</md-form-field>
|
||||||
|
</md-list-item>
|
||||||
|
|
||||||
<div class="col-sm-8"
|
<md-list-item>
|
||||||
[class.has-danger]="frequency.errors">
|
<md-form-field>
|
||||||
<input class="form-control"
|
<input mdInput formControlName="value" type="number" placeholder="Value">
|
||||||
id="frequency" formControlName="frequency"
|
|
||||||
type="number" placeholder="Frequency">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="frequency.errors">
|
<md-error *ngIf="value.errors?.required">The value is required.</md-error>
|
||||||
<p *ngIf="frequency.errors.required">The frequency is required.</p>
|
</md-form-field>
|
||||||
<p *ngIf="frequency.errors.min">The frequency must be positive.</p>
|
</md-list-item>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
<md-list-item>
|
||||||
<label class="col-sm-4 control-label" for="label">Label</label>
|
<md-form-field>
|
||||||
|
<input mdInput formControlName="category"
|
||||||
|
placeholder="Category">
|
||||||
|
|
||||||
<div class="col-sm-8"
|
<md-error *ngIf="category.errors?.required">The category is required.</md-error>
|
||||||
[class.has-danger]="label.errors">
|
</md-form-field>
|
||||||
<input class="form-control"
|
</md-list-item>
|
||||||
id="label" formControlName="label"
|
</md-list>
|
||||||
placeholder="Label">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="label.errors">
|
|
||||||
<p *ngIf="label.errors.required">The label is required.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 control-label" for="value">Montant</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8"
|
|
||||||
[class.has-danger]="value.errors">
|
|
||||||
<input class="form-control"
|
|
||||||
id="value" formControlName="value"
|
|
||||||
type="number" placeholder="Value">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="value.errors">
|
|
||||||
<p *ngIf="value.errors.required">The value is required.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 control-label" for="category">Catégorie</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8"
|
|
||||||
[class.has-danger]="category.errors">
|
|
||||||
<input class="form-control"
|
|
||||||
id="category" formControlName="category"
|
|
||||||
placeholder="Category">
|
|
||||||
|
|
||||||
<div class="help-block text-danger" *ngIf="category.errors">
|
|
||||||
<p *ngIf="category.errors.required">The category is required.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2 :
|
// vim: set tw=80 ts=2 sw=2 sts=2 :
|
||||||
import { Component, Inject, OnInit } from '@angular/core';
|
import { Component, Inject, OnInit } from '@angular/core';
|
||||||
|
import { MdDialog } from '@angular/material';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
@ -8,6 +9,8 @@ import { Logger } from '@nsalaun/ng-logger';
|
|||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
|
||||||
|
import { ScheduleDataSource } from './schedule.dataSource';
|
||||||
|
import { ScheduleDeleteModalComponent } from './scheduleDeleteModal.component';
|
||||||
import { ScheduleEditModalComponent } from './scheduleEditModal.component';
|
import { ScheduleEditModalComponent } from './scheduleEditModal.component';
|
||||||
import { ScheduleService } from './schedule.service';
|
import { ScheduleService } from './schedule.service';
|
||||||
import { Schedule } from './schedule';
|
import { Schedule } from './schedule';
|
||||||
@ -15,41 +18,95 @@ import { Schedule } from './schedule';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'schedule-list',
|
selector: 'schedule-list',
|
||||||
template: `
|
template: `
|
||||||
<div class="row">
|
<div class="containerX">
|
||||||
<table class="table table-sm table-striped table-condensed table-hover">
|
<div class="container">
|
||||||
<thead>
|
<button md-fab color="primary" (click)="add()">
|
||||||
<tr>
|
<md-icon>add</md-icon>
|
||||||
<th>Date de début</th>
|
</button>
|
||||||
<th>Date de fin</th>
|
</div>
|
||||||
<th>Jour</th>
|
|
||||||
<th>Fréq.</th>
|
|
||||||
<th>Libellé de l'opération</th>
|
|
||||||
<th>Montant</th>
|
|
||||||
<th>Catégorie</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
<div class="container">
|
||||||
<tr>
|
<md-table #table [dataSource]="schedules">
|
||||||
<td colspan="8">
|
<ng-container mdColumnDef="start_date">
|
||||||
<button class="btn btn-success" (click)="add()">
|
<md-header-cell *mdHeaderCellDef>Date de début</md-header-cell>
|
||||||
Ajouter
|
<md-cell *mdCellDef="let schedule">
|
||||||
|
{{ schedule.start_date | date: "yyyy-MM-dd" }}
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="stop_date">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Date de fin</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let schedule">
|
||||||
|
{{ schedule.stop_date | date: "yyyy-MM-dd" }}
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="day">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Jour</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let schedule">
|
||||||
|
{{ schedule.day }}
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="frequency">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Fréq.</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let schedule">
|
||||||
|
{{ schedule.frequency }}
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="label">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Libellé de l'opération</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let schedule">
|
||||||
|
{{ schedule.label }}
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="value">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Montant</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let schedule">
|
||||||
|
{{ schedule.value | currency: "EUR":true }}
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="category">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Catégorie</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let schedule">
|
||||||
|
{{ schedule.category }}
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container mdColumnDef="actions">
|
||||||
|
<md-header-cell *mdHeaderCellDef>Actions</md-header-cell>
|
||||||
|
<md-cell *mdCellDef="let schedule">
|
||||||
|
<!-- Edit operation. -->
|
||||||
|
<button md-mini-fab color="primary" (click)="modify(schedule)">
|
||||||
|
<md-icon>mode_edit</md-icon>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr *ngFor="let schedule of schedules"
|
<!-- Remove operation. -->
|
||||||
[schedule-row]="schedule" (needsReload)="load()">
|
<button md-mini-fab color="warn" [hidden]="!schedule.id"
|
||||||
</tr>
|
(click)="confirmDelete(schedule)">
|
||||||
</tbody>
|
<md-icon>delete_forever</md-icon>
|
||||||
</table>
|
</button>
|
||||||
|
</md-cell>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<md-header-row *mdHeaderRowDef="displayedColumns"></md-header-row>
|
||||||
|
<md-row *mdRowDef="let row; columns: displayedColumns;">
|
||||||
|
</md-row>
|
||||||
|
</md-table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class ScheduleListComponent implements OnInit {
|
export class ScheduleListComponent implements OnInit {
|
||||||
accountId: number;
|
private accountId: number;
|
||||||
schedules = [];
|
|
||||||
|
private displayedColumns: String[] = [
|
||||||
|
'start_date', 'stop_date', 'day', 'frequency',
|
||||||
|
'label', 'value', 'category', 'actions'
|
||||||
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private toastrService: ToastrService,
|
private toastrService: ToastrService,
|
||||||
@ -57,6 +114,8 @@ export class ScheduleListComponent implements OnInit {
|
|||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
private ngbModal: NgbModal,
|
private ngbModal: NgbModal,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
private schedules: ScheduleDataSource,
|
||||||
|
private mdDialog: MdDialog,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -66,41 +125,37 @@ export class ScheduleListComponent implements OnInit {
|
|||||||
this.load();
|
this.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Add a new operation at the beginning of th array.
|
|
||||||
*/
|
|
||||||
add() {
|
|
||||||
var schedule = new Schedule();
|
|
||||||
schedule.account_id = this.accountId;
|
|
||||||
|
|
||||||
const modal = this.ngbModal.open(ScheduleEditModalComponent, {
|
|
||||||
size: 'lg'
|
|
||||||
});
|
|
||||||
|
|
||||||
modal.componentInstance.schedule = schedule;
|
|
||||||
|
|
||||||
modal.result.then((schedule: Schedule) => {
|
|
||||||
this.save(schedule);
|
|
||||||
}, (reason) => function(reason) {
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
load() {
|
load() {
|
||||||
this.logger.log("Loading schedules for accountId", this.accountId);
|
this.logger.log("Loading schedules for accountId", this.accountId);
|
||||||
if(!this.accountId) {
|
if(!this.accountId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scheduleService.query(this.accountId)
|
this.schedules.load(this.accountId);
|
||||||
.subscribe((schedules: Schedule[]) => {
|
}
|
||||||
this.logger.log("Schedules loaded.", schedules);
|
|
||||||
this.schedules = schedules;
|
/*
|
||||||
}, (reason) => {
|
* Add a new operation at the beginning of th array.
|
||||||
this.logger.log("Got error", reason);
|
*/
|
||||||
}
|
add() {
|
||||||
);
|
this.modify(new Schedule());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
modify(schedule: Schedule) {
|
||||||
|
let dialogRef = this.mdDialog.open(ScheduleEditModalComponent, {
|
||||||
|
data: {
|
||||||
|
schedule: schedule,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((schedule: Schedule) => {
|
||||||
|
if(schedule) {
|
||||||
|
this.save(schedule);
|
||||||
|
}
|
||||||
|
}, (reason) => function(reason) {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
save(schedule: Schedule) {
|
save(schedule: Schedule) {
|
||||||
return this.scheduleService.create(schedule).subscribe((schedule: Schedule) => {
|
return this.scheduleService.create(schedule).subscribe((schedule: Schedule) => {
|
||||||
this.toastrService.success('Schedule #' + schedule.id + ' saved.');
|
this.toastrService.success('Schedule #' + schedule.id + ' saved.');
|
||||||
@ -112,4 +167,35 @@ export class ScheduleListComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
confirmDelete(schedule: Schedule) {
|
||||||
|
let dialogRef = this.mdDialog.open(ScheduleDeleteModalComponent, {
|
||||||
|
data: {
|
||||||
|
schedule: schedule,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((schedule: Schedule) => {
|
||||||
|
if(schedule) {
|
||||||
|
this.delete(schedule);
|
||||||
|
}
|
||||||
|
}, (reason) => function(reason) {
|
||||||
|
this.logger.error("Delete dialog failed", reason);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(schedule: Schedule) {
|
||||||
|
var id = schedule.id;
|
||||||
|
|
||||||
|
return this.scheduleService.delete(schedule).subscribe(() => {
|
||||||
|
this.toastrService.success('Schedule #' + id + ' deleted.');
|
||||||
|
|
||||||
|
this.load();
|
||||||
|
}, result => {
|
||||||
|
this.toastrService.error(
|
||||||
|
'An error occurred while trying to delete schedule #' + id + ':<br />'
|
||||||
|
+ result.message
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
// vim: set tw=80 ts=2 sw=2 sts=2 :
|
|
||||||
import { CurrencyPipe } from '@angular/common';
|
|
||||||
import { Component, Inject, Input, Output, EventEmitter } from '@angular/core';
|
|
||||||
|
|
||||||
import { Logger } from '@nsalaun/ng-logger';
|
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
|
||||||
|
|
||||||
import { ScheduleDeleteModalComponent } from './scheduleDeleteModal.component';
|
|
||||||
import { ScheduleEditModalComponent } from './scheduleEditModal.component';
|
|
||||||
import { ScheduleService } from './schedule.service';
|
|
||||||
import { Schedule } from './schedule';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'tr[schedule-row]',
|
|
||||||
host: {
|
|
||||||
"[id]": "schedule.id",
|
|
||||||
},
|
|
||||||
template: `
|
|
||||||
<td>{{ schedule.start_date | date: "yyyy-MM-dd" }}</td>
|
|
||||||
|
|
||||||
|
|
||||||
<td>{{ schedule.stop_date | date: "yyyy-MM-dd" }}</td>
|
|
||||||
|
|
||||||
<td>{{ schedule.day }}</td>
|
|
||||||
|
|
||||||
<td>{{ schedule.frequency }}</td>
|
|
||||||
|
|
||||||
<td>{{ schedule.label }}</td>
|
|
||||||
|
|
||||||
<td>{{ schedule.value | currency:"EUR":true }}</td>
|
|
||||||
|
|
||||||
<td>{{ schedule.category }}</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<div class="btn-group btn-group-sm">
|
|
||||||
<!-- Edit operation. -->
|
|
||||||
<button type="button" class="btn btn-success"
|
|
||||||
(click)="modify()" title="edit">
|
|
||||||
<span class="fa fa-pencil-square-o"></span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Remove operation. -->
|
|
||||||
<button type="button" class="btn btn-danger"
|
|
||||||
[hidden]="!schedule.id"
|
|
||||||
(click)="confirmDelete()"
|
|
||||||
title="remove">
|
|
||||||
<span class="fa fa-trash"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
export class ScheduleRowComponent {
|
|
||||||
@Input('schedule-row') schedule: Schedule;
|
|
||||||
@Output() needsReload: EventEmitter<void> = new EventEmitter<void>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private scheduleService: ScheduleService,
|
|
||||||
private logger: Logger,
|
|
||||||
private toastrService: ToastrService,
|
|
||||||
private ngbModal: NgbModal
|
|
||||||
) {}
|
|
||||||
|
|
||||||
save(schedule: Schedule) {
|
|
||||||
return this.scheduleService.update(schedule).subscribe((schedule: Schedule) => {
|
|
||||||
this.toastrService.success('Schedule #' + schedule.id + ' saved.');
|
|
||||||
|
|
||||||
this.needsReload.emit();
|
|
||||||
}, result => {
|
|
||||||
this.toastrService.error(
|
|
||||||
'Error while saving schedule: ' + result.message
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmDelete() {
|
|
||||||
const modal = this.ngbModal.open(ScheduleDeleteModalComponent);
|
|
||||||
|
|
||||||
modal.componentInstance.schedule = this.schedule;
|
|
||||||
|
|
||||||
modal.result.then((schedule: Schedule) => {
|
|
||||||
this.delete(schedule);
|
|
||||||
}, (reason) => function(reason) {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(schedule: Schedule) {
|
|
||||||
var id = schedule.id;
|
|
||||||
|
|
||||||
return this.scheduleService.delete(schedule).subscribe(() => {
|
|
||||||
this.toastrService.success('Schedule #' + id + ' deleted.');
|
|
||||||
|
|
||||||
this.needsReload.emit();
|
|
||||||
}, result => {
|
|
||||||
this.toastrService.error(
|
|
||||||
'An error occurred while trying to delete schedule #' + id + ':<br />'
|
|
||||||
+ result.message
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
modify() {
|
|
||||||
const modal = this.ngbModal.open(ScheduleEditModalComponent, {
|
|
||||||
size: 'lg'
|
|
||||||
});
|
|
||||||
|
|
||||||
modal.componentInstance.schedule = this.schedule;
|
|
||||||
|
|
||||||
modal.result.then((schedule: Schedule) => {
|
|
||||||
this.save(schedule);
|
|
||||||
}, (reason) => function(reason) {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,7 +15,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx', '.html'],
|
extensions: ['.js', '.ts', '.html'],
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [{
|
rules: [{
|
||||||
@ -37,7 +37,7 @@ module.exports = {
|
|||||||
}, {
|
}, {
|
||||||
// Javascript
|
// Javascript
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
test: /\.jsx?$/,
|
test: /\.js$/,
|
||||||
//include: path.resolve(__dirname, 'src'),
|
//include: path.resolve(__dirname, 'src'),
|
||||||
loader: 'eslint-loader',
|
loader: 'eslint-loader',
|
||||||
options: {
|
options: {
|
||||||
@ -60,38 +60,53 @@ module.exports = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
test: /\.jsx?$/,
|
test: /\.js$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'babel-loader'
|
loader: 'babel-loader'
|
||||||
}, {
|
}, {
|
||||||
test: /\.tsx?$/,
|
// Typescript linting
|
||||||
|
enforce: 'pre',
|
||||||
|
test: /\.ts$/,
|
||||||
|
loader: 'tslint-loader',
|
||||||
|
options: {
|
||||||
|
configuration: {
|
||||||
|
extends: [
|
||||||
|
"tslint:latest",
|
||||||
|
"codelyzer"
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
//quotemark: [true, 'single']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
configFile: 'tslint-custom.json',
|
||||||
|
emitErrors: true,
|
||||||
|
failOnHint: true,
|
||||||
|
typeCheck: true,
|
||||||
|
tsConfigFile: 'tsconfig.json',
|
||||||
|
formatter: 'verbose',
|
||||||
|
formattersDirectory: 'node_modules/tslint/lib/formatters/',
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
test: /\.ts$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'ts-loader'
|
loaders: ['awesome-typescript-loader', 'angular2-template-loader?keepUrl=true']
|
||||||
}, {
|
}, {
|
||||||
test: /\.html$/,
|
test: /\.html$/,
|
||||||
use: [
|
loader: 'raw-loader'
|
||||||
'ngtemplate-loader?relativeTo=/accountant-ui/src',
|
|
||||||
'html-loader'
|
|
||||||
]
|
|
||||||
}, {
|
|
||||||
test: /\.less$/,
|
|
||||||
use: [
|
|
||||||
'style-loader',
|
|
||||||
'css-loader',
|
|
||||||
'less-loader',
|
|
||||||
]
|
|
||||||
}, {
|
}, {
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: [
|
loaders: [
|
||||||
'style-loader',
|
'style-loader',
|
||||||
'css-loader',
|
'css-loader',
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
use: [
|
loaders: [
|
||||||
'style-loader',
|
'style-loader',
|
||||||
'css-loader',
|
'css-loader',
|
||||||
'sass-loader',
|
'sass-loader',
|
||||||
|
'resolve-url-loader',
|
||||||
|
'sass-loader?sourceMap'
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
|
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
|
||||||
|
Reference in New Issue
Block a user