V 1.1.0 - Bearbeiten bei Liste geht, auch Löschen.
This commit is contained in:
@@ -40,7 +40,6 @@ export function getCollections() {
|
|||||||
|
|
||||||
export const update_pflux = async(sn, doc) => {
|
export const update_pflux = async(sn, doc) => {
|
||||||
try {
|
try {
|
||||||
let r = await prop_fluxCollection.findOne({_id: sn})
|
|
||||||
await prop_fluxCollection.updateOne({_id: sn},{ $set: { 'chip': doc}})
|
await prop_fluxCollection.updateOne({_id: sn},{ $set: { 'chip': doc}})
|
||||||
return {"error": null}
|
return {"error": null}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "espid2sensor",
|
"name": "espid2sensor",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"date": "2025-08-19 16:00 UTC",
|
"date": "2025-09-01 17:00 UTC",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Kleine Webapp ESP-ID <-> Sensornummer, speichern in MongoDB",
|
"description": "Kleine Webapp ESP-ID <-> Sensornummer, speichern in MongoDB",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
|
|||||||
133
public/global.js
133
public/global.js
@@ -42,35 +42,66 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
let editId = null;
|
let editId = null;
|
||||||
|
|
||||||
// Modal für Fehleranzeige
|
// Modal für Fehleranzeige
|
||||||
function showModal(message, callback) {
|
function showModal(message, showCancelButton, callback) {
|
||||||
// Vorherige Modals entfernen
|
// Remove previous modals
|
||||||
document.querySelectorAll('.custom-modal-popup').forEach(m => m.remove());
|
document.querySelectorAll('.custom-modal-popup').forEach(m => m.remove());
|
||||||
|
|
||||||
let modal = document.createElement('div');
|
let modal = document.createElement('div');
|
||||||
modal.className = 'custom-modal-popup';
|
modal.className = 'custom-modal-popup';
|
||||||
|
|
||||||
let box = document.createElement('div');
|
let box = document.createElement('div');
|
||||||
box.className = 'custom-modal-box';
|
box.className = 'custom-modal-box';
|
||||||
|
|
||||||
let msg = document.createElement('div');
|
let msg = document.createElement('div');
|
||||||
msg.className = 'custom-modal-msg';
|
msg.className = 'custom-modal-msg';
|
||||||
msg.textContent = message;
|
msg.textContent = message;
|
||||||
box.appendChild(msg);
|
box.appendChild(msg);
|
||||||
|
|
||||||
let btn = document.createElement('button');
|
let btndiv = document.createElement('div')
|
||||||
btn.className = 'custom-modal-btn';
|
btndiv.className = 'twobuttons'
|
||||||
btn.textContent = 'OK';
|
|
||||||
btn.onclick = () => {
|
// Cancel Button (only if showCancelButton is true)
|
||||||
|
if (showCancelButton) {
|
||||||
|
let btnCancel = document.createElement('button');
|
||||||
|
btnCancel.className = 'custom-modal-btn';
|
||||||
|
btnCancel.textContent = 'Abbruch';
|
||||||
|
btnCancel.onclick = () => {
|
||||||
if (modal.parentNode) {
|
if (modal.parentNode) {
|
||||||
modal.parentNode.removeChild(modal);
|
modal.parentNode.removeChild(modal);
|
||||||
}
|
}
|
||||||
if (callback) callback();
|
if (callback) callback(false); // Pass false for Cancel
|
||||||
};
|
};
|
||||||
box.appendChild(btn);
|
btndiv.appendChild(btnCancel);
|
||||||
modal.appendChild(box);
|
|
||||||
document.body.appendChild(modal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OK Button
|
||||||
|
let btnOk = document.createElement('button');
|
||||||
|
btnOk.className = 'custom-modal-btn';
|
||||||
|
btnOk.textContent = 'OK';
|
||||||
|
btnOk.onclick = () => {
|
||||||
|
if (modal.parentNode) {
|
||||||
|
modal.parentNode.removeChild(modal);
|
||||||
|
}
|
||||||
|
if (callback) callback(true); // Pass true for OK
|
||||||
|
};
|
||||||
|
|
||||||
|
btndiv.appendChild(btnOk);
|
||||||
|
box.appendChild(btndiv)
|
||||||
|
|
||||||
|
|
||||||
|
modal.appendChild(box);
|
||||||
|
document.body.appendChild(modal);
|
||||||
|
|
||||||
|
// Optional: Close modal when clicking outside
|
||||||
|
modal.onclick = (e) => {
|
||||||
|
if (e.target === modal) {
|
||||||
|
if (modal.parentNode) {
|
||||||
|
modal.parentNode.removeChild(modal);
|
||||||
|
}
|
||||||
|
if (callback) callback(false); // Treat as cancel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
// Sensornummer nur Zahlen erlauben
|
// Sensornummer nur Zahlen erlauben
|
||||||
sensorNumberInput.addEventListener('input', () => {
|
sensorNumberInput.addEventListener('input', () => {
|
||||||
sensorNumberInput.value = sensorNumberInput.value.replace(/\D/g, '');
|
sensorNumberInput.value = sensorNumberInput.value.replace(/\D/g, '');
|
||||||
@@ -99,7 +130,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
} else {
|
} else {
|
||||||
addressInput.value = '';
|
addressInput.value = '';
|
||||||
sensorNumberInput.disabled = true;
|
sensorNumberInput.disabled = true;
|
||||||
showModal('Sensor unbekannt', () => {
|
showModal('Sensor unbekannt', false, () => {
|
||||||
sensorNumberInput.disabled = false;
|
sensorNumberInput.disabled = false;
|
||||||
sensorNumberInput.focus();
|
sensorNumberInput.focus();
|
||||||
});
|
});
|
||||||
@@ -108,7 +139,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
console.error('Fehler beim Abrufen der Adresse:', err);
|
console.error('Fehler beim Abrufen der Adresse:', err);
|
||||||
addressInput.value = '';
|
addressInput.value = '';
|
||||||
sensorNumberInput.disabled = true;
|
sensorNumberInput.disabled = true;
|
||||||
showModal('Sensor unbekannt', () => {
|
showModal('Sensor unbekannt', false, () => {
|
||||||
sensorNumberInput.disabled = false;
|
sensorNumberInput.disabled = false;
|
||||||
sensorNumberInput.focus();
|
sensorNumberInput.focus();
|
||||||
});
|
});
|
||||||
@@ -141,8 +172,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = editId ? `/api/update/${editId}` : '/api/save';
|
const url = '/api/save';
|
||||||
const method = editId ? 'PUT' : 'POST';
|
const method = 'POST';
|
||||||
|
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
method,
|
method,
|
||||||
@@ -154,8 +185,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (data.error) {
|
if (data.error) {
|
||||||
resultDiv.textContent = data.error;
|
resultDiv.textContent = data.error;
|
||||||
} else {
|
} else {
|
||||||
resultDiv.textContent = editId ? 'Aktualisiert!' : 'Gespeichert!';
|
resultDiv.textContent = 'OK!';
|
||||||
clearForm();
|
setTimeout(() => {
|
||||||
|
resultDiv.textContent = ''
|
||||||
|
saveBtn.textContent = 'Speichern';
|
||||||
|
}, 5000)
|
||||||
|
clearForm(false);
|
||||||
await loadEntries();
|
await loadEntries();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -165,14 +200,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function clearForm() {
|
function clearForm(mitButton) {
|
||||||
espIdInput.value = '';
|
espIdInput.value = '';
|
||||||
sensorNumberInput.value = '';
|
sensorNumberInput.value = '';
|
||||||
nameInput.value = '';
|
nameInput.value = '';
|
||||||
descriptionInput.value = '';
|
descriptionInput.value = '';
|
||||||
addressInput.value = '';
|
addressInput.value = '';
|
||||||
editId = null;
|
editId = null;
|
||||||
saveBtn.textContent = 'Speichern';
|
if (mitButton) {
|
||||||
|
saveBtn.textContent = 'Speichern';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Globale Sortier-Variable
|
// Globale Sortier-Variable
|
||||||
@@ -193,16 +230,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
function renderTable(sortedItems) {
|
function renderTable(sortedItems) {
|
||||||
tableBody.innerHTML = '';
|
tableBody.innerHTML = '';
|
||||||
sortedItems.forEach(item => {
|
sortedItems.forEach(item => {
|
||||||
const date = new Date(item.chip.createdAt).toISOString().split('T')[0];
|
const date = new Date(item.chip.lastUpdatedAt).toISOString().split('T')[0];
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
tr.innerHTML = `
|
tr.innerHTML = `
|
||||||
<td>${item._id}</td>
|
<td id="tdSensornumber">${item._id}</td>
|
||||||
<td>${item.chip.id}</td>
|
<td>${item.chip.id}</td>
|
||||||
<td>${item.chip.name || ''}</td>
|
<td>${item.chip.name || ''}</td>
|
||||||
<td id="tdBeschreibung">${item.chip.description || ''}</td>
|
<td id="tdBeschreibung">${item.chip.description || ''}</td>
|
||||||
<td id="tdDate">${date}</td>
|
<td id="tdDate">${date}</td>
|
||||||
<td>
|
<td>
|
||||||
<button data-id="${item._id}" class="editBtn">Bearbeiten</button>
|
<div class=twobuttons>
|
||||||
|
<button data-id="${item._id}" class="editBtn">Bearbeiten</button>
|
||||||
|
<button data-id="${item._id}" class="deleteBtn">Löschen</button>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
`;
|
`;
|
||||||
tableBody.appendChild(tr);
|
tableBody.appendChild(tr);
|
||||||
@@ -219,8 +259,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
valA = a.chip.id;
|
valA = a.chip.id;
|
||||||
valB = b.chip.id;
|
valB = b.chip.id;
|
||||||
} else if (key === 'date') {
|
} else if (key === 'date') {
|
||||||
valA = new Date(a.chip.createdAt);
|
valA = new Date(a.chip.lastUpdatedAt);
|
||||||
valB = new Date(b.chip.createdAt);
|
valB = new Date(b.chip.lastUpdatedAt);
|
||||||
}
|
}
|
||||||
if (valA < valB) return asc ? -1 : 1;
|
if (valA < valB) return asc ? -1 : 1;
|
||||||
if (valA > valB) return asc ? 1 : -1;
|
if (valA > valB) return asc ? 1 : -1;
|
||||||
@@ -303,22 +343,29 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function deleteEntry(id) {
|
async function deleteEntry(id) {
|
||||||
if (!confirm('Wirklich löschen?')) return;
|
showModal('Wirklich löschen?', true, async (confirmed) => {
|
||||||
try {
|
if (confirmed) {
|
||||||
const res = await fetch(`/api/delete/${id}`, { method: 'DELETE' });
|
try {
|
||||||
const data = await res.json();
|
const res = await fetch(`/api/delete/${id}`, { method: 'DELETE' });
|
||||||
if (data.success) {
|
const data = await res.json();
|
||||||
await loadEntries();
|
if (data.success) {
|
||||||
|
await loadEntries();
|
||||||
|
resultDiv.textContent = 'Eintrag gelöscht.';
|
||||||
|
setTimeout(() => resultDiv.textContent = '', 3000);
|
||||||
|
} else {
|
||||||
|
resultDiv.textContent = 'Fehler beim Löschen.';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
resultDiv.textContent = 'Fehler beim Löschen.';
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
resultDiv.textContent = 'Fehler beim Löschen.';
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
saveBtn.addEventListener('click', saveEntry);
|
saveBtn.addEventListener('click', saveEntry);
|
||||||
refreshBtn.addEventListener('click', loadEntries);
|
refreshBtn.addEventListener('click', loadEntries);
|
||||||
|
cancelBtn.addEventListener('click', () => clearForm(true));
|
||||||
tabInput.addEventListener('click', () => showTab('input'))
|
tabInput.addEventListener('click', () => showTab('input'))
|
||||||
tabList.addEventListener('click', () => showTab('list'))
|
tabList.addEventListener('click', () => showTab('list'))
|
||||||
|
|
||||||
|
|||||||
@@ -99,21 +99,18 @@ table {
|
|||||||
|
|
||||||
th, td {
|
th, td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 8px;
|
padding: 4px;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tdDate {
|
/* Spaltenbreiten über colgroup steuern */
|
||||||
width: 8em;
|
col.col-sensornumber { width: 7em; }
|
||||||
}
|
col.col-espid {width: 6em}
|
||||||
|
col.col-bezeichnung { width: 8em; }
|
||||||
|
col.col-beschreibung{ width: 12em; }
|
||||||
|
col.col-date { width: 10em; }
|
||||||
|
col.col-aktionen { width: 18em; }
|
||||||
|
|
||||||
#tdBeschreibung {
|
|
||||||
width: 10em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tdAktionen {
|
|
||||||
width: 20em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.controls input#page,
|
.controls input#page,
|
||||||
.controls input#limit {
|
.controls input#limit {
|
||||||
@@ -163,8 +160,10 @@ button:hover {
|
|||||||
background: #0056b3;
|
background: #0056b3;
|
||||||
}
|
}
|
||||||
|
|
||||||
#saveBtn {
|
.twobuttons {
|
||||||
margin-top: 20px;
|
display:flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.error {
|
p.error {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { MongoAPIError, ObjectId } from 'mongodb';
|
|||||||
import bcrypt from 'bcrypt';
|
import bcrypt from 'bcrypt';
|
||||||
import { getCollections, update_pflux } from '../db/mongo.js';
|
import { getCollections, update_pflux } from '../db/mongo.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function registerApiRoutes(app, requireLogin) {
|
export function registerApiRoutes(app, requireLogin) {
|
||||||
const { usersCollection, prop_fluxCollection } = getCollections();
|
const { usersCollection, prop_fluxCollection } = getCollections();
|
||||||
|
|
||||||
@@ -20,7 +18,7 @@ export function registerApiRoutes(app, requireLogin) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/save', requireLogin, async (req, res) => {
|
app.post('/api/save', requireLogin, async (req, res) => {
|
||||||
let { espId, sensorNumber, name, description, address } = req.body;
|
let { espId, sensorNumber, name, description} = req.body;
|
||||||
if (!espId || !sensorNumber) {
|
if (!espId || !sensorNumber) {
|
||||||
return res.json({ error: 'ESP-ID und Sensornummer sind Pflichtfelder' });
|
return res.json({ error: 'ESP-ID und Sensornummer sind Pflichtfelder' });
|
||||||
}
|
}
|
||||||
@@ -30,7 +28,7 @@ export function registerApiRoutes(app, requireLogin) {
|
|||||||
id: espId,
|
id: espId,
|
||||||
name: name || '',
|
name: name || '',
|
||||||
description: description || '',
|
description: description || '',
|
||||||
createdAt: new Date()
|
lastUpdatedAt: new Date()
|
||||||
};
|
};
|
||||||
await update_pflux(sensorNumber, doc)
|
await update_pflux(sensorNumber, doc)
|
||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
@@ -40,24 +38,6 @@ export function registerApiRoutes(app, requireLogin) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.put('/api/update/:id', requireLogin, async (req, res) => {
|
|
||||||
const { id } = req.params;
|
|
||||||
let { espId, sensorNumber, name, description, address } = req.body;
|
|
||||||
if (!espId || !sensorNumber) {
|
|
||||||
return res.json({ error: 'ESP-ID und Sensornummer sind Pflichtfelder' });
|
|
||||||
}
|
|
||||||
sensorNumber = parseInt(sensorNumber, 10);
|
|
||||||
try {
|
|
||||||
await prop_fluxCollection.updateOne(
|
|
||||||
{ _id: new ObjectId(id) },
|
|
||||||
{ $set: { espId, sensorNumber, name, description, address } }
|
|
||||||
);
|
|
||||||
res.json({ success: true });
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
res.status(500).json({ error: 'Fehler beim Aktualisieren' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/api/list', requireLogin, async (req, res) => {
|
app.get('/api/list', requireLogin, async (req, res) => {
|
||||||
const { id } = req.query;
|
const { id } = req.query;
|
||||||
@@ -83,7 +63,7 @@ export function registerApiRoutes(app, requireLogin) {
|
|||||||
const skip = (page - 1) * limit;
|
const skip = (page - 1) * limit;
|
||||||
try {
|
try {
|
||||||
const items = await prop_fluxCollection.find({chip: {$exists: true}})
|
const items = await prop_fluxCollection.find({chip: {$exists: true}})
|
||||||
.sort({ "chip.createdAt": -1 })
|
.sort({ "chip.lastUpdatedAt": -1 })
|
||||||
.skip(skip)
|
.skip(skip)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.toArray();
|
.toArray();
|
||||||
@@ -96,7 +76,7 @@ export function registerApiRoutes(app, requireLogin) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.delete('/api/delete/:id', requireLogin, async (req, res) => {
|
app.delete('/api/delete/:id', requireLogin, async (req, res) => {
|
||||||
await prop_fluxCollection.deleteOne({ _id: new ObjectId(req.params.id) });
|
await prop_fluxCollection.deleteOne({ _id: parseInt(req.params.id) });
|
||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ describe('Server.js API', () => {
|
|||||||
return res.json({ error: 'ESP-ID und Sensornummer sind Pflichtfelder' });
|
return res.json({ error: 'ESP-ID und Sensornummer sind Pflichtfelder' });
|
||||||
}
|
}
|
||||||
sensorNumber = parseInt(sensorNumber, 10);
|
sensorNumber = parseInt(sensorNumber, 10);
|
||||||
const doc = { espId, sensorNumber, name, description, address, createdAt: new Date(), _id: String(entries.length + 1) };
|
const doc = { espId, sensorNumber, name, description, address, lastUpdatedAt: new Date(), _id: String(entries.length + 1) };
|
||||||
entries.push(doc);
|
entries.push(doc);
|
||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
});
|
});
|
||||||
@@ -115,7 +115,7 @@ describe('Server.js API', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('PUT /api/update/:id updates entry', async () => {
|
test('PUT /api/update/:id updates entry', async () => {
|
||||||
entries.push({ _id: '1', espId: 'esp1', sensorNumber: 1001, name: '', description: '', address: '', createdAt: new Date() });
|
entries.push({ _id: '1', espId: 'esp1', sensorNumber: 1001, name: '', description: '', address: '', lastUpdatedAt: new Date() });
|
||||||
const res = await request(app).put('/api/update/1').send({ espId: 'esp2', sensorNumber: '1002', name: 'Neu', description: 'Neu', address: 'Neu' });
|
const res = await request(app).put('/api/update/1').send({ espId: 'esp2', sensorNumber: '1002', name: 'Neu', description: 'Neu', address: 'Neu' });
|
||||||
expect(res.body).toHaveProperty('success', true);
|
expect(res.body).toHaveProperty('success', true);
|
||||||
expect(entries[0].espId).toBe('esp2');
|
expect(entries[0].espId).toBe('esp2');
|
||||||
@@ -127,20 +127,20 @@ describe('Server.js API', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/list returns all entries', async () => {
|
test('GET /api/list returns all entries', async () => {
|
||||||
entries.push({ _id: '1', espId: 'esp1', sensorNumber: 1001, name: '', description: '', address: '', createdAt: new Date() });
|
entries.push({ _id: '1', espId: 'esp1', sensorNumber: 1001, name: '', description: '', address: '', lastUpdatedAt: new Date() });
|
||||||
const res = await request(app).get('/api/list');
|
const res = await request(app).get('/api/list');
|
||||||
expect(res.body.length).toBe(1);
|
expect(res.body.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('GET /api/list?id returns specific entry', async () => {
|
test('GET /api/list?id returns specific entry', async () => {
|
||||||
entries.push({ _id: '1', espId: 'esp1', sensorNumber: 1001, name: '', description: '', address: '', createdAt: new Date() });
|
entries.push({ _id: '1', espId: 'esp1', sensorNumber: 1001, name: '', description: '', address: '', lastUpdatedAt: new Date() });
|
||||||
const res = await request(app).get('/api/list?id=1');
|
const res = await request(app).get('/api/list?id=1');
|
||||||
expect(res.body.length).toBe(1);
|
expect(res.body.length).toBe(1);
|
||||||
expect(res.body[0]._id).toBe('1');
|
expect(res.body[0]._id).toBe('1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('DELETE /api/delete/:id deletes entry', async () => {
|
test('DELETE /api/delete/:id deletes entry', async () => {
|
||||||
entries.push({ _id: '1', espId: 'esp1', sensorNumber: 1001, name: '', description: '', address: '', createdAt: new Date() });
|
entries.push({ _id: '1', espId: 'esp1', sensorNumber: 1001, name: '', description: '', address: '', lastUpdatedAt: new Date() });
|
||||||
const res = await request(app).delete('/api/delete/1');
|
const res = await request(app).delete('/api/delete/1');
|
||||||
expect(res.body).toHaveProperty('success', true);
|
expect(res.body).toHaveProperty('success', true);
|
||||||
expect(entries.length).toBe(0);
|
expect(entries.length).toBe(0);
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ html(lang="de")
|
|||||||
label(for="address") Anschrift:
|
label(for="address") Anschrift:
|
||||||
input#address(type="text" placeholder="Wird automatisch ausgefüllt" readonly disabled)
|
input#address(type="text" placeholder="Wird automatisch ausgefüllt" readonly disabled)
|
||||||
|
|
||||||
button#saveBtn(type="button") Speichern
|
.twobuttons
|
||||||
|
button#saveBtn(type="button") Speichern
|
||||||
|
button#cancelBtn(type="button") Abbrechen
|
||||||
div#result
|
div#result
|
||||||
|
|
||||||
// Listen-Tab
|
// Listen-Tab
|
||||||
@@ -45,6 +47,13 @@ html(lang="de")
|
|||||||
span#gzahl
|
span#gzahl
|
||||||
|
|
||||||
table#entriesTable
|
table#entriesTable
|
||||||
|
colgroup
|
||||||
|
col.col-sensornumber
|
||||||
|
col.col-espid
|
||||||
|
col.col-bezeichnung
|
||||||
|
col.col-beschreibung
|
||||||
|
col.col-date
|
||||||
|
col.col-aktionen
|
||||||
thead
|
thead
|
||||||
tr
|
tr
|
||||||
th(id="thSensorNr" data-sort="sensorNr" style="cursor:pointer") SensorNr <span id="sortArrowSensorNr">↑</span>
|
th(id="thSensorNr" data-sort="sensorNr" style="cursor:pointer") SensorNr <span id="sortArrowSensorNr">↑</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user