Serverseitige Filterung für Listen-Endpunkte und Einzelabrufe in Listen-Komponenten
Server: Die list-Endpunkte für Kontakt, Projekt, Kontaktadresse und CallLog akzeptieren nun einen optionalen Query-Parameter (kunden_id bzw. projekt_id) und filtern im ORM-Query. Neue Migration V01.05 legt Indizes auf den FK-Spalten an. Client: Die fetch-Funktionen erhalten einen optionalen Parent-ID-Parameter. Die Listen-Komponenten übergeben die Parent-ID aus den Route-Params an den Server und laden nur noch benötigte Daten. Statt kompletter Eltern-Listen wird per fetchXxxById ein einzelner Datensatz für die Namensauflösung geladen. Die CallLog-Bearbeitungsmaske behält ihre ungesfilterten Dropdown-Abrufe. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
1 parent
e9a2f48ede
commit
93827dde0f
15 files changed
+189
-141
No files matched your search
@@ -5,7 +5,7 @@ import {Select, iSelect, iSelectOption} from "./widgets/select"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iCallLog, fetchCallLogs, fetchCallLogById, createCallLogREST, updateCallLogREST} from "../models/call_log"
|
||||
import {iKunde, fetchKunden} from "../models/kunde"
|
||||
import {iProjekt, fetchProjekte} from "../models/projekt"
|
||||
import {iProjekt, fetchProjekte, fetchProjektById} from "../models/projekt"
|
||||
import {iKontaktadresse, fetchKontaktadressen} from "../models/kontaktadresse"
|
||||
|
||||
// Aktualisierungsintervall für die Dauer-Anzeige in Millisekunden.
|
||||
@@ -15,10 +15,11 @@ export const call_log_liste: m.ClosureComponent = (vnode) => {
|
||||
let treenodes: iTreenode[] = []
|
||||
let selectedNode: iTreenode | null = null
|
||||
let filterProjektId: number | null = null
|
||||
// Projektname für die Überschrift, asynchron aufgelöst.
|
||||
// Projektname für die Überschrift, asynchron per fetchProjektById
|
||||
// aufgelöst. kunden_name wird ebenfalls aus dem Projekt bezogen,
|
||||
// da es nicht in den Route-Params enthalten ist.
|
||||
let projektName: string = ""
|
||||
// Projektliste asynchron laden, für Projektauflösung beim Neuanlegen.
|
||||
let projektListe: iProjekt[] = []
|
||||
let kundenName: string = ""
|
||||
|
||||
const handleRowMarked = (node: iTreenode) => {
|
||||
selectedNode = node
|
||||
@@ -41,12 +42,9 @@ export const call_log_liste: m.ClosureComponent = (vnode) => {
|
||||
erledigt: false
|
||||
}
|
||||
if (filterProjektId !== null) {
|
||||
const projekt = projektListe.find((p: iProjekt) => p.id === filterProjektId)
|
||||
if (projekt) {
|
||||
params.projekt_id = projekt.id
|
||||
params.projekt_name = projekt.projektname
|
||||
params.kunden_name = projekt.kunden_name
|
||||
}
|
||||
params.projekt_id = filterProjektId
|
||||
params.projekt_name = projektName
|
||||
params.kunden_name = kundenName
|
||||
}
|
||||
m.route.set("/call_log", params)
|
||||
}
|
||||
@@ -94,24 +92,22 @@ export const call_log_liste: m.ClosureComponent = (vnode) => {
|
||||
filterProjektId = null
|
||||
projektName = ""
|
||||
}
|
||||
// Gesprächsnotizen asynchron vom Server laden.
|
||||
fetchCallLogs().then((result) => {
|
||||
let filtered = result
|
||||
if (filterProjektId !== null) {
|
||||
filtered = result.filter((l: iCallLog) => l.projekt_id === filterProjektId)
|
||||
}
|
||||
treenodes = filtered.map((log: iCallLog) => new Treenode(log, true, []))
|
||||
// Gesprächsnotizen asynchron vom Server laden. Die Filterung
|
||||
// nach projekt_id erfolgt serverseitig, sofern ein Filter
|
||||
// gesetzt ist.
|
||||
fetchCallLogs(filterProjektId !== null ? filterProjektId : undefined).then((result) => {
|
||||
treenodes = result.map((log: iCallLog) => new Treenode(log, true, []))
|
||||
})
|
||||
// Projektliste asynchron laden, für Projektnamen-Auflösung.
|
||||
fetchProjekte().then((result) => {
|
||||
projektListe = result
|
||||
if (filterProjektId !== null && projektName === "") {
|
||||
const projekt = projektListe.find((p: iProjekt) => p.id === filterProjektId)
|
||||
if (projekt) {
|
||||
// Projektnamen und Kundennamen asynchron auflösen, falls
|
||||
// nicht in den Route-Params enthalten.
|
||||
if (filterProjektId !== null) {
|
||||
fetchProjektById(filterProjektId).then((projekt: iProjekt) => {
|
||||
if (projektName === "") {
|
||||
projektName = projekt.projektname
|
||||
}
|
||||
}
|
||||
})
|
||||
kundenName = projekt.kunden_name
|
||||
})
|
||||
}
|
||||
},
|
||||
view: (vnode) => {
|
||||
return m("div.w3-container.w3-auto", {
|
||||
|
||||
@@ -3,18 +3,15 @@ import {Form, iForm} from "./widgets/form"
|
||||
import { Input, iInput, Textarea, iTextarea} from "./widgets/inputs"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iKontakt, fetchKontakte, fetchKontaktById, createKontaktREST, updateKontaktREST} from "../models/kontakt"
|
||||
import {iKunde, fetchKunden} from "../models/kunde"
|
||||
import {iKunde, fetchKundeById} from "../models/kunde"
|
||||
|
||||
export const kontaktliste: m.ClosureComponent = (vnode) => {
|
||||
let treenodes: iTreenode[] = []
|
||||
let selectedNode: iTreenode | null = null
|
||||
let filterKundenId: number | null = null
|
||||
// Kundenname für die Überschrift, asynchron aus der Kundenliste
|
||||
// aufgelöst.
|
||||
// Kundenname für die Überschrift, asynchron per fetchKundeById
|
||||
// aufgelöst, falls nicht in den Route-Params enthalten.
|
||||
let kundenName: string = ""
|
||||
// Kundenliste asynchron vom Server laden, für die Kundenauflösung
|
||||
// beim Anlegen eines neuen Kontakts.
|
||||
let kundenListe: iKunde[] = []
|
||||
|
||||
const handleRowMarked = (node: iTreenode) => {
|
||||
selectedNode = node
|
||||
@@ -24,11 +21,8 @@ export const kontaktliste: m.ClosureComponent = (vnode) => {
|
||||
const params: any = {id: -1}
|
||||
// Nur bei kundengefilterter Liste den Kunden vorbelegen.
|
||||
if (filterKundenId !== null) {
|
||||
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
|
||||
if (kunde) {
|
||||
params.kunden_id = kunde.id
|
||||
params.kunden_name = kunde.name
|
||||
}
|
||||
params.kunden_id = filterKundenId
|
||||
params.kunden_name = kundenName
|
||||
}
|
||||
m.route.set("/kontakt", params)
|
||||
}
|
||||
@@ -71,27 +65,17 @@ export const kontaktliste: m.ClosureComponent = (vnode) => {
|
||||
filterKundenId = null
|
||||
kundenName = ""
|
||||
}
|
||||
// Kontakte asynchron vom Server laden. m.request löst nach
|
||||
// Promise-Auflösung automatisch ein Redraw aus.
|
||||
fetchKontakte().then((result) => {
|
||||
let filtered = result
|
||||
if (filterKundenId !== null) {
|
||||
filtered = result.filter((k: iKontakt) => k.kunden_id === filterKundenId)
|
||||
}
|
||||
treenodes = filtered.map((kontakt: iKontakt) => new Treenode(kontakt, true, []))
|
||||
})
|
||||
// Kundenliste asynchron vom Server laden.
|
||||
fetchKunden().then((result) => {
|
||||
kundenListe = result
|
||||
// Fallback: Falls kunden_name nicht in den Route-Params
|
||||
// enthalten war, aus der Kundenliste auflösen.
|
||||
if (filterKundenId !== null && kundenName === "") {
|
||||
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
|
||||
if (kunde) {
|
||||
kundenName = kunde.name
|
||||
}
|
||||
}
|
||||
// Kontakte asynchron vom Server laden. Die Filterung nach
|
||||
// kunden_id erfolgt serverseitig, sofern ein Filter gesetzt ist.
|
||||
fetchKontakte(filterKundenId !== null ? filterKundenId : undefined).then((result) => {
|
||||
treenodes = result.map((kontakt: iKontakt) => new Treenode(kontakt, true, []))
|
||||
})
|
||||
// Kundennamen asynchron auflösen, falls nicht in Route-Params.
|
||||
if (filterKundenId !== null && kundenName === "") {
|
||||
fetchKundeById(filterKundenId).then((kunde: iKunde) => {
|
||||
kundenName = kunde.name
|
||||
})
|
||||
}
|
||||
},
|
||||
view: (vnode) => {
|
||||
return m("div.w3-container.w3-auto", {
|
||||
|
||||
@@ -3,18 +3,15 @@ import {Form, iForm} from "./widgets/form"
|
||||
import { Input, iInput, Textarea, iTextarea} from "./widgets/inputs"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iKontaktadresse, fetchKontaktadressen, fetchKontaktadresseById, createKontaktadresseREST, updateKontaktadresseREST} from "../models/kontaktadresse"
|
||||
import {iProjekt, fetchProjekte} from "../models/projekt"
|
||||
import {iProjekt, fetchProjektById} from "../models/projekt"
|
||||
|
||||
export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
|
||||
let treenodes: iTreenode[] = []
|
||||
let selectedNode: iTreenode | null = null
|
||||
let filterProjektId: number | null = null
|
||||
// Projektname für die Überschrift, asynchron aus der Projektliste
|
||||
// aufgelöst.
|
||||
// Projektname für die Überschrift, asynchron per fetchProjektById
|
||||
// aufgelöst, falls nicht in den Route-Params enthalten.
|
||||
let projektName: string = ""
|
||||
// Projektliste asynchron vom Server laden, für die Projektauflösung
|
||||
// beim Anlegen einer neuen Kontaktadresse.
|
||||
let projektListe: iProjekt[] = []
|
||||
|
||||
const handleRowMarked = (node: iTreenode) => {
|
||||
selectedNode = node
|
||||
@@ -23,11 +20,8 @@ export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
|
||||
const addKontaktadresseRoute = () => {
|
||||
const params: any = {id: -1}
|
||||
if (filterProjektId !== null) {
|
||||
const projekt = projektListe.find((p: iProjekt) => p.id === filterProjektId)
|
||||
if (projekt) {
|
||||
params.projekt_id = projekt.id
|
||||
params.projekt_name = projekt.projektname
|
||||
}
|
||||
params.projekt_id = filterProjektId
|
||||
params.projekt_name = projektName
|
||||
}
|
||||
m.route.set("/kontaktadresse", params)
|
||||
}
|
||||
@@ -97,24 +91,18 @@ export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
|
||||
filterProjektId = null
|
||||
projektName = ""
|
||||
}
|
||||
// Kontaktadressen asynchron vom Server laden.
|
||||
fetchKontaktadressen().then((result) => {
|
||||
let filtered = result
|
||||
if (filterProjektId !== null) {
|
||||
filtered = result.filter((k: iKontaktadresse) => k.projekt_id === filterProjektId)
|
||||
}
|
||||
treenodes = filtered.map((kontaktadresse: iKontaktadresse) => new Treenode(kontaktadresse, true, []))
|
||||
})
|
||||
// Projektliste asynchron vom Server laden.
|
||||
fetchProjekte().then((result) => {
|
||||
projektListe = result
|
||||
if (filterProjektId !== null && projektName === "") {
|
||||
const projekt = projektListe.find((p: iProjekt) => p.id === filterProjektId)
|
||||
if (projekt) {
|
||||
projektName = projekt.projektname
|
||||
}
|
||||
}
|
||||
// Kontaktadressen asynchron vom Server laden. Die Filterung
|
||||
// nach projekt_id erfolgt serverseitig, sofern ein Filter
|
||||
// gesetzt ist.
|
||||
fetchKontaktadressen(filterProjektId !== null ? filterProjektId : undefined).then((result) => {
|
||||
treenodes = result.map((kontaktadresse: iKontaktadresse) => new Treenode(kontaktadresse, true, []))
|
||||
})
|
||||
// Projektnamen asynchron auflösen, falls nicht in Route-Params.
|
||||
if (filterProjektId !== null && projektName === "") {
|
||||
fetchProjektById(filterProjektId).then((projekt: iProjekt) => {
|
||||
projektName = projekt.projektname
|
||||
})
|
||||
}
|
||||
},
|
||||
view: (vnode) => {
|
||||
return m("div.w3-container.w3-auto", {
|
||||
|
||||
@@ -3,18 +3,15 @@ import {Form, iForm} from "./widgets/form"
|
||||
import { Input, iInput} from "./widgets/inputs"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iProjekt, fetchProjekte, fetchProjektById, createProjektREST, updateProjektREST} from "../models/projekt"
|
||||
import {iKunde, fetchKunden} from "../models/kunde"
|
||||
import {iKunde, fetchKundeById} from "../models/kunde"
|
||||
|
||||
export const projektliste: m.ClosureComponent = (vnode) => {
|
||||
let treenodes: iTreenode[] = []
|
||||
let selectedNode: iTreenode | null = null
|
||||
let filterKundenId: number | null = null
|
||||
// Kundenname für die Überschrift, asynchron aus der Kundenliste
|
||||
// aufgelöst.
|
||||
// Kundenname für die Überschrift, asynchron per fetchKundeById
|
||||
// aufgelöst, falls nicht in den Route-Params enthalten.
|
||||
let kundenName: string = ""
|
||||
// Kundenliste asynchron vom Server laden, für die Kundenauflösung
|
||||
// beim Anlegen eines neuen Projekts.
|
||||
let kundenListe: iKunde[] = []
|
||||
|
||||
const handleRowMarked = (node: iTreenode) => {
|
||||
selectedNode = node
|
||||
@@ -24,11 +21,8 @@ export const projektliste: m.ClosureComponent = (vnode) => {
|
||||
const params: any = {id: -1}
|
||||
// Nur bei kundengefilterter Liste den Kunden vorbelegen.
|
||||
if (filterKundenId !== null) {
|
||||
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
|
||||
if (kunde) {
|
||||
params.kunden_id = kunde.id
|
||||
params.kunden_name = kunde.name
|
||||
}
|
||||
params.kunden_id = filterKundenId
|
||||
params.kunden_name = kundenName
|
||||
}
|
||||
m.route.set("/projekt", params)
|
||||
}
|
||||
@@ -108,24 +102,17 @@ export const projektliste: m.ClosureComponent = (vnode) => {
|
||||
filterKundenId = null
|
||||
kundenName = ""
|
||||
}
|
||||
// Projekte asynchron vom Server laden.
|
||||
fetchProjekte().then((result) => {
|
||||
let filtered = result
|
||||
if (filterKundenId !== null) {
|
||||
filtered = result.filter((p: iProjekt) => p.kunden_id === filterKundenId)
|
||||
}
|
||||
treenodes = filtered.map((projekt: iProjekt) => new Treenode(projekt, true, []))
|
||||
})
|
||||
// Kundenliste asynchron vom Server laden.
|
||||
fetchKunden().then((result) => {
|
||||
kundenListe = result
|
||||
if (filterKundenId !== null && kundenName === "") {
|
||||
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
|
||||
if (kunde) {
|
||||
kundenName = kunde.name
|
||||
}
|
||||
}
|
||||
// Projekte asynchron vom Server laden. Die Filterung nach
|
||||
// kunden_id erfolgt serverseitig, sofern ein Filter gesetzt ist.
|
||||
fetchProjekte(filterKundenId !== null ? filterKundenId : undefined).then((result) => {
|
||||
treenodes = result.map((projekt: iProjekt) => new Treenode(projekt, true, []))
|
||||
})
|
||||
// Kundennamen asynchron auflösen, falls nicht in Route-Params.
|
||||
if (filterKundenId !== null && kundenName === "") {
|
||||
fetchKundeById(filterKundenId).then((kunde: iKunde) => {
|
||||
kundenName = kunde.name
|
||||
})
|
||||
}
|
||||
},
|
||||
view: (vnode) => {
|
||||
return m("div.w3-container.w3-auto", {
|
||||
|
||||
Reference in new issue
Block a user