Skip to content

Commit

Permalink
added frontend Features
Browse files Browse the repository at this point in the history
  • Loading branch information
Mario committed Dec 8, 2024
1 parent 63c869f commit aa78611
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 32 deletions.
21 changes: 11 additions & 10 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,19 @@
from time import time
import toml

#from read import read_topics, read_server_addr, read_qos, read_connection_timeout
#from save import save_topics, save_server_addr, save_qos, save_connection_timeout
from config import config, LOGIN_ATTEMPTS, MAX_ATTEMPTS, BLOCK_TIME, LOGIN_REQUIRED, LOGIN_PASSWORD, TELEGRAF_CONFIG, TELEGRAF_CONFIG_PATH

app = Flask(__name__)
app.secret_key = config["auth"]["secret_key"]

def update_toml(input_data):
for section, section_data in input_data.items():
if section in TELEGRAF_CONFIG:
for key, value in section_data.items():
if isinstance(value, dict):
if key in TELEGRAF_CONFIG[section]:
update_toml(TELEGRAF_CONFIG[section], {key: value})
else:
TELEGRAF_CONFIG[section][key] = value
if 'inputs' in TELEGRAF_CONFIG and 'mqtt_consumer' in TELEGRAF_CONFIG['inputs']:
for consumer in TELEGRAF_CONFIG['inputs']['mqtt_consumer']:
# Aktualisieren der Werte basierend auf der JSON-Konfiguration
for key, value in input_data.items():
if key in consumer:
consumer[key] = value

return TELEGRAF_CONFIG

# Checks if an IP is blocked
Expand Down Expand Up @@ -53,6 +50,10 @@ def require_login():
def index():
return render_template("index.html")

@app.route('/settings')
def settings():
return render_template("settings.html")

@app.route('/login', methods=['GET', 'POST'])
def login():
if not LOGIN_REQUIRED:
Expand Down
85 changes: 66 additions & 19 deletions static/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Shows Messages
// Shows status messages in the message box
function showMessage(message, type = "success") {
const messageBox = document.getElementById("message-box");
messageBox.textContent = message;
messageBox.className = `message-box ${type}`; // Typ (success, error) hinzufügen
messageBox.className = `message-box ${type}`;

// Removes message after 5 seconds
setTimeout(() => {
Expand All @@ -11,19 +11,30 @@ function showMessage(message, type = "success") {
}, 5000);
}

// Adds Topics dynamically
// Displays a loading spinner
function toggleLoadingSpinner(show) {
const spinner = document.getElementById('loading-spinner');
if (show) {
spinner.style.display = 'block';
} else {
spinner.style.display = 'none';
}
}

// Loads topics from API and populates the list
function loadTopics() {
fetch('/api/config') // API-Request for Topics
toggleLoadingSpinner(true);
fetch('/api/config') // API Request to get the config data
.then(response => response.json())
.then(data => {
const topics = data.topics || []; // When no topics are available, an empty array is returned
const topics = data[0]?.topics || []; // Fallback to empty array if no topics found
const topicsList = document.getElementById('topics-list');

// Remove all existing topics
// Clear existing topics
topicsList.innerHTML = '';

// Populate topics from API response
topics.forEach(topic => {
// Create new topic item
const topicItem = document.createElement('div');
topicItem.classList.add('topic-item');
topicItem.innerHTML = `
Expand All @@ -33,38 +44,49 @@ function loadTopics() {
topicsList.appendChild(topicItem);
});

toggleLoadingSpinner(false);
})
.catch(error => showMessage("Fehler beim Laden der Topics!", "error"));
.catch(error => {
toggleLoadingSpinner(false);
showMessage("Fehler beim Laden der Topics!", "error");
});
}

// Create new topic field
// Adds a new topic field dynamically
document.getElementById('add-topic-btn').addEventListener('click', function() {
const topicItem = document.createElement('div');
topicItem.classList.add('topic-item');
topicItem.innerHTML = '<input type="text" name="topics" value=""><button type="button" class="remove-topic-btn">-</button>';
document.getElementById('topics-list').appendChild(topicItem);
});

// Remove topic
// Removes a topic field when the '-' button is clicked
document.addEventListener('click', function(event) {
if (event.target.classList.contains('remove-topic-btn')) {
event.target.parentElement.remove();
}
});

// Send formular data
// Collects and sends the modified topics list to the API
document.getElementById('topics-form').addEventListener('submit', function(event) {
event.preventDefault(); // prevents the default form submission
event.preventDefault(); // Prevents the default form submission

// Collect all topics
// Collect topics from input fields
const topics = [];
document.querySelectorAll('input[name="topics"]').forEach(input => {
if (input.value.trim()) {
topics.push(input.value.trim());
const topic = input.value.trim();
if (topic && !topics.includes(topic)) { // Avoid duplicates
topics.push(topic);
}
});

// Send changed topics to api
if (topics.length === 0) {
showMessage("Es müssen mindestens ein Topic eingegeben werden!", "error");
return;
}

// Send topics data to the API
toggleLoadingSpinner(true);
fetch('/api/save-config', {
method: 'POST',
headers: {
Expand All @@ -74,11 +96,36 @@ document.getElementById('topics-form').addEventListener('submit', function(event
})
.then(response => response.json())
.then(data => {
toggleLoadingSpinner(false);
showMessage(data.message, "success");
loadTopics(); // Update displayed topics
loadTopics(); // Refresh the topics list after saving
})
.catch(error => showMessage("Fehler beim Speichern der Topics!", "error"));
.catch(error => {
toggleLoadingSpinner(false);
showMessage("Fehler beim Speichern der Topics!", "error");
});
});

// Handle navigation to Settings page
document.getElementById('settings-btn').addEventListener('click', function() {
window.location.href = "/settings"; // Assuming "/settings" is the path to the settings page
});

// Handle Logout
document.getElementById('logout-btn').addEventListener('click', function() {
// Assuming logout logic is handled by API or server-side session
fetch('/api/logout', {
method: 'POST',
})
.then(response => response.json())
.then(data => {
showMessage(data.message, "success");
window.location.href = "/login"; // Redirect to login page after logout
})
.catch(error => {
showMessage("Fehler beim Abmelden!", "error");
});
});

// Load topics on page load
window.onload = loadTopics;
window.onload = loadTopics;
85 changes: 85 additions & 0 deletions static/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Shows status messages in the message box
function showMessage(message, type = "success") {
const messageBox = document.getElementById("message-box");
messageBox.textContent = message;
messageBox.className = `message-box ${type}`;

// Removes message after 5 seconds
setTimeout(() => {
messageBox.textContent = "";
messageBox.className = "message-box";
}, 5000);
}

// Displays a loading spinner
function toggleLoadingSpinner(show) {
const spinner = document.getElementById('loading-spinner');
if (show) {
spinner.style.display = 'block';
} else {
spinner.style.display = 'none';
}
}

// Loads current settings from the API and populates the form
function loadSettings() {
toggleLoadingSpinner(true);
fetch('/api/config')
.then(response => response.json())
.then(data => {
const config = data[0] || {};
document.getElementById('client-id').value = config.client_id || '';
document.getElementById('connection-timeout').value = config.connection_timeout || '';
document.getElementById('data-format').value = config.data_format || 'json';
document.getElementById('insecure-skip-verify').checked = config.insecure_skip_verify || false;
document.getElementById('password').value = config.password || '';
document.getElementById('qos').value = config.qos || 0;
document.getElementById('servers').value = config.servers ? config.servers.join(', ') : '';
document.getElementById('tls-ca').value = config.tls_ca || '';
document.getElementById('username').value = config.username || '';
toggleLoadingSpinner(false);
})
.catch(error => {
toggleLoadingSpinner(false);
showMessage("Fehler beim Laden der Einstellungen!", "error");
});
}

// Send the updated settings to the API
document.getElementById('settings-form').addEventListener('submit', function(event) {
event.preventDefault(); // Prevents the default form submission

const settings = {
client_id: document.getElementById('client-id').value.trim(),
connection_timeout: document.getElementById('connection-timeout').value.trim(),
data_format: document.getElementById('data-format').value,
insecure_skip_verify: document.getElementById('insecure-skip-verify').checked,
password: document.getElementById('password').value.trim(),
qos: parseInt(document.getElementById('qos').value),
servers: document.getElementById('servers').value.split(',').map(s => s.trim()),
tls_ca: document.getElementById('tls-ca').value.trim(),
username: document.getElementById('username').value.trim()
};

// Send settings data to the API
toggleLoadingSpinner(true);
fetch('/api/save-config', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(settings)
})
.then(response => response.json())
.then(data => {
toggleLoadingSpinner(false);
showMessage(data.message, "success");
})
.catch(error => {
toggleLoadingSpinner(false);
showMessage("Fehler beim Speichern der Einstellungen!", "error");
});
});

// Load settings on page load
window.onload = loadSettings;
17 changes: 17 additions & 0 deletions static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,20 @@ button:hover {
color: #555;
font-size: 14px;
}

/* Loading Spinner */
.spinner {
width: 40px;
height: 40px;
border: 5px solid #f3f3f3;
border-top: 5px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 20px auto;
}

/* Spinner animation */
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
14 changes: 11 additions & 3 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,27 @@
<div class="container">
<h1>MQTT Topics</h1>

<!-- Area for messages -->
<!-- Message Box for status messages -->
<div id="message-box" class="message-box"></div>

<!-- Button to go to Settings page -->
<button id="settings-btn" class="nav-btn">Einstellungen</button>

<!-- Button to logout -->
<button id="logout-btn" class="nav-btn">Abmelden</button>

<form id="topics-form">
<div class="topics-list" id="topics-list">
<!-- Display Topics dynamic -->
<!-- Dynamically loaded topics will appear here -->
</div>
<button type="button" id="add-topic-btn">+ Neues Topic hinzufügen</button>
<button type="submit" class="save-btn">Speichern</button>
</form>

<!-- Loading Spinner -->
<div id="loading-spinner" class="spinner" style="display: none;"></div>
</div>

<!-- Link to Java script file -->
<script src="static/dashboard.js"></script>
</body>
</html>
61 changes: 61 additions & 0 deletions templates/settings.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Telegraf MQTT Config - Einstellungen</title>
<link rel="stylesheet" href="static/styles.css">
<link rel="icon" href="static/favicon.ico" type="image/x-icon">
</head>
<body>
<div class="container">
<h1>MQTT Konfiguration Einstellungen</h1>

<!-- Message Box for status messages -->
<div id="message-box" class="message-box"></div>

<form id="settings-form">
<label for="client-id">Client ID:</label>
<input type="text" id="client-id" name="client_id" required>

<label for="connection-timeout">Verbindungstimeout (in Sekunden):</label>
<input type="text" id="connection-timeout" name="connection_timeout" required>

<label for="data-format">Datenformat:</label>
<select id="data-format" name="data_format">
<option value="json">JSON</option>
<option value="influx">InfluxDB Line Protocol</option>
</select>

<label for="insecure-skip-verify">Insecure Skip Verify:</label>
<input type="checkbox" id="insecure-skip-verify" name="insecure_skip_verify">

<label for="password">Passwort:</label>
<input type="password" id="password" name="password" required>

<label for="qos">QoS:</label>
<select id="qos" name="qos">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>

<label for="servers">MQTT Server (Comma separated):</label>
<input type="text" id="servers" name="servers" required>

<label for="tls-ca">TLS CA Datei:</label>
<input type="text" id="tls-ca" name="tls_ca">

<label for="username">Benutzername:</label>
<input type="text" id="username" name="username" required>

<button type="submit" class="save-btn">Speichern</button>
</form>
</div>

<!-- Loading Spinner -->
<div id="loading-spinner" class="spinner" style="display: none;"></div>

<script src="static/settings.js"></script>
</body>
</html>

0 comments on commit aa78611

Please sign in to comment.