notes
This commit is contained in:
@ -1320,3 +1320,80 @@ SELECT
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_notes(user, token_info):
|
||||||
|
return dbGetMany(user, token_info, {
|
||||||
|
"statement": """
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
,created_at
|
||||||
|
,tenant
|
||||||
|
,note
|
||||||
|
FROM note_t
|
||||||
|
""",
|
||||||
|
"params": ()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def insert_note(user, token_info, **args):
|
||||||
|
try:
|
||||||
|
body = args["body"]
|
||||||
|
v_created_at = body["created_at"]
|
||||||
|
v_tenant = body["tenant"]
|
||||||
|
v_note = body["note"]
|
||||||
|
return dbInsert(user, token_info, {
|
||||||
|
"statement": """
|
||||||
|
INSERT INTO note_t
|
||||||
|
(
|
||||||
|
created_at
|
||||||
|
,tenant
|
||||||
|
,note
|
||||||
|
) VALUES (
|
||||||
|
%s
|
||||||
|
,%s
|
||||||
|
,%s
|
||||||
|
)
|
||||||
|
RETURNING *
|
||||||
|
""",
|
||||||
|
"params": [
|
||||||
|
v_created_at
|
||||||
|
,v_tenant
|
||||||
|
,v_note
|
||||||
|
]
|
||||||
|
})
|
||||||
|
except KeyError as e:
|
||||||
|
logger.warning("insert_note: parameter missing: {}".format(e))
|
||||||
|
raise werkzeug.exceptions.UnprocessableEntity("parameter missing: {}".format(e))
|
||||||
|
|
||||||
|
|
||||||
|
def get_note(user, token_info, noteId=None):
|
||||||
|
return dbGetOne(user, token_info, {
|
||||||
|
"statement": """
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
,created_at
|
||||||
|
,tenant
|
||||||
|
,note
|
||||||
|
FROM note_t
|
||||||
|
WHERE id = %s
|
||||||
|
""",
|
||||||
|
"params": (noteId, )
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_note_by_tenant(user, token_info, tenantId=None):
|
||||||
|
return dbGetMany(user, token_info, {
|
||||||
|
"statement": """
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
,created_at
|
||||||
|
,tenant
|
||||||
|
,note
|
||||||
|
FROM note_t
|
||||||
|
WHERE tenant = %s
|
||||||
|
""",
|
||||||
|
"params": (tenantId, )
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@ -1256,6 +1256,87 @@ paths:
|
|||||||
$ref: '#/components/schemas/account_entry'
|
$ref: '#/components/schemas/account_entry'
|
||||||
security:
|
security:
|
||||||
- jwt: ['secret']
|
- jwt: ['secret']
|
||||||
|
/v1/notes:
|
||||||
|
get:
|
||||||
|
tags: [ "note" ]
|
||||||
|
summary: Return all normalized notes
|
||||||
|
operationId: methods.get_notes
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: notes response
|
||||||
|
content:
|
||||||
|
'application/json':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/note'
|
||||||
|
security:
|
||||||
|
- jwt: ['secret']
|
||||||
|
post:
|
||||||
|
tags: [ "note" ]
|
||||||
|
summary: Insert a note
|
||||||
|
operationId: methods.insert_note
|
||||||
|
requestBody:
|
||||||
|
description: note
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/note'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: note successfully inserted
|
||||||
|
content:
|
||||||
|
'application/json':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/note'
|
||||||
|
security:
|
||||||
|
- jwt: ['secret']
|
||||||
|
/v1/notes/{noteId}:
|
||||||
|
get:
|
||||||
|
tags: [ "note" ]
|
||||||
|
summary: Return the normalized note with given id
|
||||||
|
operationId: methods.get_note
|
||||||
|
parameters:
|
||||||
|
- name: noteId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: note response
|
||||||
|
content:
|
||||||
|
'application/json':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/note'
|
||||||
|
security:
|
||||||
|
- jwt: ['secret']
|
||||||
|
/v1/notes/tenant/{tenantId}:
|
||||||
|
get:
|
||||||
|
tags: [ "note", "tenant" ]
|
||||||
|
summary: Return note by $tenant
|
||||||
|
operationId: methods.get_note_by_tenant
|
||||||
|
parameters:
|
||||||
|
- name: tenantId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: note response
|
||||||
|
content:
|
||||||
|
'application/json':
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/note'
|
||||||
|
security:
|
||||||
|
- jwt: ['secret']
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
# ATTENTION: This file will not be parsed by Cheetah
|
# ATTENTION: This file will not be parsed by Cheetah
|
||||||
@ -1511,3 +1592,15 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
amount:
|
amount:
|
||||||
type: number
|
type: number
|
||||||
|
note:
|
||||||
|
description: note
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
tenant:
|
||||||
|
type: integer
|
||||||
|
note:
|
||||||
|
type: string
|
||||||
|
@ -117,6 +117,15 @@
|
|||||||
{ "name": "created_at", "sqltype": "timestamp", "notnull": true, "default": "now()" },
|
{ "name": "created_at", "sqltype": "timestamp", "notnull": true, "default": "now()" },
|
||||||
{ "name": "amount", "sqltype": "numeric(10,2)", "notnull": true, "selector": 0 }
|
{ "name": "amount", "sqltype": "numeric(10,2)", "notnull": true, "selector": 0 }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "note",
|
||||||
|
"immutable": true,
|
||||||
|
"columns": [
|
||||||
|
{ "name": "created_at", "sqltype": "timestamp", "notnull": true, "default": "now()" },
|
||||||
|
{ "name": "tenant", "sqltype": "integer", "notnull": true, "foreignkey": true },
|
||||||
|
{ "name": "note", "sqltype": "varchar(4096)", "notnull": true }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -104,5 +104,12 @@ CREATE TABLE account_entry_t (
|
|||||||
,amount numeric(10,2) not null
|
,amount numeric(10,2) not null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE note_t (
|
||||||
|
id serial not null primary key
|
||||||
|
,created_at timestamp not null default now()
|
||||||
|
,tenant integer not null references tenant_t (id)
|
||||||
|
,note varchar(4096) not null
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
import { Component, Input, OnInit, OnChanges, ViewChild } from '@angular/core';
|
||||||
import { MatButton } from '@angular/material/button';
|
import { MatButton } from '@angular/material/button';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { AccountEntryService, AccountService } from '../data-object-service';
|
import { AccountEntryService, AccountService } from '../data-object-service';
|
||||||
@ -82,4 +82,9 @@ export class AccountComponent implements OnInit {
|
|||||||
this.getAccount()
|
this.getAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnChanges(): void {
|
||||||
|
this.messageService.add(`AccountComponent.ngOnChanges, account: ${this.selectedAccountId}`)
|
||||||
|
this.getAccount()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@ import { MatNativeDateModule } from '@angular/material/core';
|
|||||||
import { FeeListComponent } from './fee-list/fee-list.component';
|
import { FeeListComponent } from './fee-list/fee-list.component';
|
||||||
import { FeeDetailsComponent } from './fee-details/fee-details.component';
|
import { FeeDetailsComponent } from './fee-details/fee-details.component';
|
||||||
import { MatExpansionModule } from '@angular/material/expansion';
|
import { MatExpansionModule } from '@angular/material/expansion';
|
||||||
import { AccountComponent } from './account/account.component'
|
import { AccountComponent } from './account/account.component';
|
||||||
|
import { NoteComponent } from './note/note.component'
|
||||||
|
|
||||||
registerLocaleData(localeDe)
|
registerLocaleData(localeDe)
|
||||||
|
|
||||||
@ -69,7 +70,8 @@ registerLocaleData(localeDe)
|
|||||||
OverheadAdvanceDetailsComponent,
|
OverheadAdvanceDetailsComponent,
|
||||||
FeeListComponent,
|
FeeListComponent,
|
||||||
FeeDetailsComponent,
|
FeeDetailsComponent,
|
||||||
AccountComponent
|
AccountComponent,
|
||||||
|
NoteComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -25,6 +25,7 @@ import { Tenancy } from './data-objects';
|
|||||||
import { Fee } from './data-objects';
|
import { Fee } from './data-objects';
|
||||||
import { TenancyFeeMapping } from './data-objects';
|
import { TenancyFeeMapping } from './data-objects';
|
||||||
import { AccountEntry } from './data-objects';
|
import { AccountEntry } from './data-objects';
|
||||||
|
import { Note } from './data-objects';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -452,4 +453,34 @@ export class AccountEntryService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class NoteService {
|
||||||
|
constructor(private messageService: MessageService, private http: HttpClient) { }
|
||||||
|
|
||||||
|
async getNotes(): Promise<Note[]> {
|
||||||
|
this.messageService.add(`NoteService: get data`);
|
||||||
|
return this.http.get<Note[]>(`${serviceBaseUrl}/v1/notes`).toPromise()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getNote(id: number): Promise<Note> {
|
||||||
|
this.messageService.add(`NoteService: get data for ${id}`);
|
||||||
|
return this.http.get<Note>(`${serviceBaseUrl}/v1/notes/${id}`).toPromise()
|
||||||
|
}
|
||||||
|
|
||||||
|
async postNote(item: Note): Promise<Note> {
|
||||||
|
let itemStr: string = JSON.stringify(item, undefined, 4)
|
||||||
|
this.messageService.add(`NoteService: post data for ${itemStr}`);
|
||||||
|
return this.http.post<Note>(`${serviceBaseUrl}/v1/notes`, item).toPromise()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async getNotesByTenant(id: number): Promise<Note[]> {
|
||||||
|
this.messageService.add(`NoteService: get data by Tenant ${id}`);
|
||||||
|
return this.http.get<Note[]>(`${serviceBaseUrl}/v1/notes/tenant/${id}`).toPromise()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,4 +188,17 @@ export const NULL_AccountEntry: AccountEntry = {
|
|||||||
,amount: undefined
|
,amount: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Note {
|
||||||
|
id: number
|
||||||
|
created_at: string
|
||||||
|
tenant: number
|
||||||
|
note: string
|
||||||
|
}
|
||||||
|
export const NULL_Note: Note = {
|
||||||
|
id: 0
|
||||||
|
,created_at: ''
|
||||||
|
,tenant: undefined
|
||||||
|
,note: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
40
ui/hv2-ui/src/app/note/note.component.css
Normal file
40
ui/hv2-ui/src/app/note/note.component.css
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
table {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#addEntryfield {
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#divider {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#firstblock {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#secondblock {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rightaligned {
|
||||||
|
justify-self: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.large {
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notearea {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topalign {
|
||||||
|
vertical-align: top;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
53
ui/hv2-ui/src/app/note/note.component.html
Normal file
53
ui/hv2-ui/src/app/note/note.component.html
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<mat-card class="defaultCard">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title>
|
||||||
|
Notizen
|
||||||
|
</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-accordion>
|
||||||
|
<mat-expansion-panel (opened)="collapse = true"
|
||||||
|
(closed)="collapse = false">
|
||||||
|
<mat-expansion-panel-header>
|
||||||
|
<mat-panel-title *ngIf="!collapse">
|
||||||
|
Übersicht
|
||||||
|
</mat-panel-title>
|
||||||
|
<mat-panel-description>
|
||||||
|
</mat-panel-description>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
<div id="firstBlock">
|
||||||
|
<form (ngSubmit)="addNote()">
|
||||||
|
<div>
|
||||||
|
<mat-form-field appearance="outline" class="notearea">
|
||||||
|
<mat-label>Text</mat-label>
|
||||||
|
<textarea matInput
|
||||||
|
cdkTextareaAutosize
|
||||||
|
#autosize="cdkTextareaAutosize"
|
||||||
|
cdkAutosizeMinRows="5"
|
||||||
|
cdkAutosizeMaxRows="10"
|
||||||
|
name="note" [(ngModel)]="newNote.note"></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</div><div>
|
||||||
|
<button #addNoteButton type="submit" mat-raised-button color="primary">Speichern</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="secondBlock">
|
||||||
|
<table mat-table [dataSource]="notesDataSource" #zftable>
|
||||||
|
<ng-container matColumnDef="createdAt">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Datum</th>
|
||||||
|
<td mat-cell *matCellDef="let element" class="topalign">{{element.created_at | date}}</td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="note">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>Notiz</th>
|
||||||
|
<td mat-cell *matCellDef="let element" class="topalign">{{element.note}}</td>
|
||||||
|
</ng-container>
|
||||||
|
<tr mat-header-row *matHeaderRowDef="notesDisplayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: notesDisplayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
|
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
25
ui/hv2-ui/src/app/note/note.component.spec.ts
Normal file
25
ui/hv2-ui/src/app/note/note.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { NoteComponent } from './note.component';
|
||||||
|
|
||||||
|
describe('NoteComponent', () => {
|
||||||
|
let component: NoteComponent;
|
||||||
|
let fixture: ComponentFixture<NoteComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ NoteComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(NoteComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
77
ui/hv2-ui/src/app/note/note.component.ts
Normal file
77
ui/hv2-ui/src/app/note/note.component.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { Component, Input, OnInit, OnChanges, ViewChild } from '@angular/core';
|
||||||
|
import { MatButton } from '@angular/material/button';
|
||||||
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
|
import { NoteService } from '../data-object-service';
|
||||||
|
import { Note, NULL_Note } from '../data-objects';
|
||||||
|
import { MessageService } from '../message.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-note',
|
||||||
|
templateUrl: './note.component.html',
|
||||||
|
styleUrls: ['./note.component.css']
|
||||||
|
})
|
||||||
|
export class NoteComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input() selectedTenantId: number
|
||||||
|
@ViewChild('addNoteButton') addNoteButton: MatButton
|
||||||
|
|
||||||
|
collapse: boolean = false
|
||||||
|
|
||||||
|
notes: Note[]
|
||||||
|
notesDataSource: MatTableDataSource<Note>
|
||||||
|
notesDisplayedColumns: string[] = [ "createdAt", "note" ]
|
||||||
|
|
||||||
|
newNote : Note = NULL_Note
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private noteService: NoteService,
|
||||||
|
private messageService: MessageService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
|
||||||
|
async getNotes(): Promise<void> {
|
||||||
|
try {
|
||||||
|
if (this.selectedTenantId) {
|
||||||
|
this.messageService.add(`Trying to load note for ${this.selectedTenantId}`)
|
||||||
|
this.notes = await this.noteService.getNotesByTenant(this.selectedTenantId)
|
||||||
|
this.notes.reverse()
|
||||||
|
this.messageService.add(`Notes: ${JSON.stringify(this.notes, undefined, 4)}`)
|
||||||
|
this.notesDataSource = new MatTableDataSource<Note>(this.notes)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.messageService.add(`Error in getNotes: ${JSON.stringify(err, undefined, 4)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async addNote(): Promise<void> {
|
||||||
|
try {
|
||||||
|
this.addNoteButton.disabled = true
|
||||||
|
this.newNote.tenant = this.selectedTenantId
|
||||||
|
this.newNote.created_at = new Date().toDateString()
|
||||||
|
this.messageService.add(`addNote: ${ JSON.stringify(this.newNote, undefined, 4) }`)
|
||||||
|
this.newNote = await this.noteService.postNote(this.newNote)
|
||||||
|
this.messageService.add(`New addNote created: ${this.newNote.id}`)
|
||||||
|
this.newNote = { 'tenant': this.selectedTenantId, 'note': '', 'created_at': '', 'id': 0 }
|
||||||
|
this.getNotes()
|
||||||
|
} catch (err) {
|
||||||
|
this.messageService.add(`Error in addNote: ${JSON.stringify(err, undefined, 4)}`)
|
||||||
|
} finally {
|
||||||
|
this.addNoteButton.disabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.messageService.add(`NoteComponent.ngOnInit, account: ${this.selectedTenantId}`)
|
||||||
|
this.getNotes()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(): void {
|
||||||
|
this.messageService.add(`NoteComponent.ngOnChanges, account: ${this.selectedTenantId}`)
|
||||||
|
this.getNotes()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -203,6 +203,8 @@
|
|||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|
||||||
<app-account [selectedAccountId]="tenantId"></app-account>
|
<app-note [selectedTenantId]="tenantId"></app-note>
|
||||||
|
|
||||||
|
<app-account [selectedAccountId]="tenant.account"></app-account>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
Reference in New Issue
Block a user