Skip to content

Commit 0c738d9

Browse files
feat: ✨ setting page added for basic settings
1 parent 6b92c6c commit 0c738d9

11 files changed

Lines changed: 208 additions & 29 deletions

File tree

app.py

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from flask import Flask, render_template
1+
from flask import Flask, render_template, request, flash
22
from flask_sqlalchemy import SQLAlchemy
33
import os
44
import psutil
@@ -10,15 +10,11 @@
1010
# Configure the SQLite database
1111
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///speedtest_results.db'
1212
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
13+
app.config['SECRET_KEY'] = 'secret'
1314

1415
# Initialize the database
1516
db = SQLAlchemy(app)
1617

17-
# config
18-
SPEEDTEST_COOLDOWN_IN_HOURS = 1 # in hours
19-
TIMEZONE = 'Asia/Kolkata'
20-
NUMBER_OF_SPEEDTESTS = 3
21-
2218
# Define the model for storing speed test results
2319
class SpeedTestResult(db.Model):
2420
id = db.Column(db.Integer, primary_key=True)
@@ -30,14 +26,22 @@ class SpeedTestResult(db.Model):
3026
def __repr__(self):
3127
return f'<SpeedTestResult {self.download_speed}, {self.upload_speed}, {self.ping}>'
3228

33-
# class DashoardSettings(db.Model):
34-
# id = db.Column(db.Integer, primary_key=True)
35-
# speedtest_cooldown = db.Column(db.Integer)
36-
# timezone = db.Column(db.String(50))
37-
# number_of_speedtests = db.Column(db.Integer)
29+
class DashoardSettings(db.Model):
30+
id = db.Column(db.Integer, primary_key=True)
31+
speedtest_cooldown = db.Column(db.Integer, default=1)
32+
number_of_speedtests = db.Column(db.Integer, default=1)
33+
timezone = db.Column(db.String(50), default='Asia/Kolkata')
34+
35+
def __repr__(self):
36+
return f'<DashboardSettings {self.speedtest_cooldown}, {self.timezone}, {self.number_of_speedtests}>'
3837

39-
# def __repr__(self):
40-
# return f'<DashboardSettings {self.speedtest_cooldown}, {self.timezone}, {self.number_of_speedtests}>'
38+
# initialize the database
39+
with app.app_context():
40+
db.create_all()
41+
settings = DashoardSettings.query.first()
42+
if not settings:
43+
db.session.add(DashoardSettings())
44+
db.session.commit()
4145

4246
def change_up_time_format(uptime):
4347
uptime_seconds = uptime.total_seconds()
@@ -73,8 +77,14 @@ def run_speedtest():
7377
error = {"status": "Error", "message": str(e)}
7478
return error
7579

80+
def datetimeformat(value, format='%Y-%m-%d %H:%M:%S'):
81+
return value.strftime(format)
82+
7683
@app.route('/speedtest')
7784
def speedtest():
85+
settings = DashoardSettings.query.first()
86+
SPEEDTEST_COOLDOWN_IN_HOURS = settings.speedtest_cooldown
87+
NUMBER_OF_SPEEDTESTS = settings.number_of_speedtests
7888
n_hour_ago = datetime.datetime.now() - datetime.timedelta(hours=SPEEDTEST_COOLDOWN_IN_HOURS)
7989
recent_results = SpeedTestResult.query.filter(SpeedTestResult.timestamp > n_hour_ago).all()
8090

@@ -94,11 +104,13 @@ def speedtest():
94104
return render_template('speedtest_result.html', speedtest_result=speedtest_result, source="Actual Test")
95105
else:
96106
latest_result = recent_results[-1]
97-
next_test_time = latest_result.timestamp + datetime.timedelta(hours=1)
107+
next_test_time = latest_result.timestamp + datetime.timedelta(hours=SPEEDTEST_COOLDOWN_IN_HOURS)
108+
remaining_time_for_next_test = round((next_test_time - datetime.datetime.now()).total_seconds() / 60)
98109
return render_template('speedtest_result.html',
99110
speedtest_result=latest_result,
100111
source="Database",
101-
next_test_time=next_test_time)
112+
next_test_time=next_test_time,
113+
remaining_time_for_next_test=remaining_time_for_next_test)
102114

103115
def get_system_info():
104116
print("Getting system information...")
@@ -138,12 +150,13 @@ def get_established_connections():
138150

139151
@app.route('/')
140152
def dashboard():
153+
settings = DashoardSettings.query.first()
154+
SPEEDTEST_COOLDOWN_IN_HOURS = settings.speedtest_cooldown
141155
system_info = get_system_info()
142-
143156
# Fetch the last speedtest result
144157
n_hour_ago = datetime.datetime.now() - datetime.timedelta(hours=SPEEDTEST_COOLDOWN_IN_HOURS)
145158
recent_results = SpeedTestResult.query.filter(SpeedTestResult.timestamp > n_hour_ago).all()
146-
159+
last_timestamp = datetimeformat(recent_results[-1].timestamp) if recent_results else None
147160
if recent_results:
148161
# Display the most recent result from the database
149162
latest_result = recent_results[-1]
@@ -153,7 +166,7 @@ def dashboard():
153166
'ping': latest_result.ping
154167
}
155168
source = "Database"
156-
next_test_time = latest_result.timestamp + datetime.timedelta(hours=1)
169+
next_test_time = latest_result.timestamp + datetime.timedelta(hours=SPEEDTEST_COOLDOWN_IN_HOURS)
157170
show_prompt = False
158171
remaining_time_for_next_test = round((next_test_time - datetime.datetime.now()).total_seconds() / 60)
159172
else:
@@ -165,7 +178,8 @@ def dashboard():
165178

166179
return render_template('dashboard.html', system_info=system_info,
167180
speedtest_result=speedtest_result,
168-
source=source,
181+
source=source,
182+
last_timestamp=last_timestamp,
169183
next_test_time=remaining_time_for_next_test,
170184
show_prompt=show_prompt)
171185

@@ -174,6 +188,20 @@ def cpu_usage():
174188
cpu_usage = psutil.cpu_percent(interval=1, percpu=True)
175189
return render_template('cpu_usage.html', cpu_usage=cpu_usage)
176190

191+
192+
@app.route('/settings', methods=['GET', 'POST'])
193+
def settings():
194+
# Fetch the settings from the database and update them
195+
settings = DashoardSettings.query.first()
196+
if settings:
197+
if request.method == 'POST':
198+
settings.speedtest_cooldown = int(request.form['speedtest_cooldown'])
199+
settings.number_of_speedtests = int(request.form['number_of_speedtests'])
200+
settings.timezone = request.form['timezone']
201+
db.session.commit()
202+
flash('Settings updated successfully!', 'success')
203+
return render_template('settings.html', settings=settings)
204+
177205
@app.route('/memory_usage')
178206
def memory_usage():
179207
memory_info = {

dashboard.sh

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,13 @@ export FLASK_ENV=development # or production
5454

5555
# Check if Flask app is running
5656
if ! pgrep -f "flask run --host=0.0.0.0 --port=$FLASK_PORT" > /dev/null; then
57-
# check for the latest version of the code and do a git pull
58-
git stash
59-
git pull
60-
echo "Flask app is not running. Starting..." >> "$LOG_FILE"
57+
# git pull on FLASK_APP_PATH directory
58+
current_dir=$(pwd)
59+
cd $SCRIPT_DIR
60+
git stash && git pull
61+
cd $current_dir
62+
63+
echo "Starting Flask app..." >> "$LOG_FILE"
6164
flask run --host=0.0.0.0 --port="$FLASK_PORT" &
6265
else
6366
echo "Flask app is already running." >> "$LOG_FILE"

static/css/settings.css

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
.container {
2+
max-width: 600px;
3+
margin: auto;
4+
background: white;
5+
padding: 20px;
6+
border-radius: 8px;
7+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
8+
margin-bottom: 10px;
9+
}
10+
11+
h1 {
12+
margin-bottom: 20px;
13+
font-size: 24px;
14+
}
15+
16+
.form-group {
17+
margin-bottom: 15px;
18+
}
19+
20+
.form-group label {
21+
display: block;
22+
margin-bottom: 5px;
23+
font-weight: bold;
24+
}
25+
26+
.form-group input,
27+
.form-group select {
28+
width: 100%;
29+
padding: 8px;
30+
box-sizing: border-box;
31+
}
32+
33+
.btn {
34+
background-color: #007bff;
35+
color: white;
36+
padding: 10px 15px;
37+
border: none;
38+
border-radius: 5px;
39+
cursor: pointer;
40+
}
41+
42+
.btn:hover {
43+
background-color: #0056b3;
44+
}

static/css/style.css

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
--color-ip: #03e77c; /* Bright blue for IP address */
1919
--color-cpu-usage: #ffc107; /* Yellow for CPU usage */
2020
--color-memory: #6f42c1; /* Purple for memory */
21-
--color-disk: #6c757d; /* Gray for disk */
21+
--color-disk: #6711e9; /* Gray for disk */
2222
--color-uptime: #17a2b8; /* Cyan for uptime */
2323
--color-network: #11eeee; /* Bright blue for network */
2424
--color-speedtest: #c9ef4b; /* Bright blue for speedtest */
@@ -186,13 +186,18 @@ body {
186186
}
187187

188188
.card-text {
189-
font-size: 1.125rem; /* Adjusts font size for text */
189+
font-size: 1.5rem; /* Adjusts font size for text */
190190
}
191191

192192
.btn-primary {
193193
margin-top: 1rem; /* Adds space above buttons */
194194
}
195195

196+
.fas {
197+
font-size: 1.5rem; /* Adjusts icon size */
198+
margin-right: 0.5rem; /* Adds space between icon and text */
199+
}
200+
196201
/* Responsive Styles */
197202
@media (max-width: 767.98px) {
198203
.navbar-nav .nav-link {
@@ -261,6 +266,14 @@ body {
261266
transition: background-color 0.3s ease; /* Smooth transition on hover */
262267
}
263268

269+
.cpu-core-bar:hover {
270+
background-color: var(--color-cpu); /* Red color on hover */
271+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.6); /* Slightly larger shadow */
272+
transition: background-color 0.3s ease, box-shadow 0.3s ease; /* Smooth transition */
273+
filter: brightness(1.2); /* Brighten the bar */
274+
275+
}
276+
264277
/* General Card Hover Effect */
265278
.card:hover {
266279
transform: translateY(-8px); /* Slight lift effect */
@@ -358,3 +371,24 @@ body {
358371
border-radius: 0 0 10px 10px; /* Match the card's border radius */
359372
z-index: 1; /* Ensure it's on top of the card content */
360373
}
374+
375+
footer {
376+
background-color: #343a40;
377+
color: #adb5bd;
378+
padding: 1rem 0;
379+
position: relative;
380+
width: 100%;
381+
bottom: 0;
382+
text-align: center;
383+
position: fixed;
384+
}
385+
386+
footer a {
387+
color: #ffffff;
388+
text-decoration: none;
389+
}
390+
391+
footer a:hover {
392+
color: #ced4da;
393+
text-decoration: underline;
394+
}

templates/base.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<div class="container mt-5">
1919
{% block content %}{% endblock %}
2020
</div>
21+
{% include 'ext/footer.html' %}
2122
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
2223
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
2324
<script src="{{ url_for('static', filename='js/script.js') }}"></script>

templates/dasbhboard_comp/speedtest.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ <h5 class="card-title">Perform Speed Test <i class="fas fa-clock"></i></h5>
55
{% if speedtest_result %}
66
<p class="card-text fs-4">Download Speed: {{ speedtest_result["download_speed"] }}</p>
77
<p class="card-text fs-4">Upload Speed: {{ speedtest_result["upload_speed"] }}</p>
8-
<p class="card-text fs-4">Test Last Performed: {{ next_test_time }} mins ago</p>
9-
<p class="card-text fs-4">Try again test in : {{ next_test_time }}</p>
8+
<p class="card-text fs-4">Test Last Performed: {{ last_timestamp }}</p>
9+
<p class="card-text fs-4">Try again test in : {{ next_test_time }} mins</p>
1010
{% endif %}
1111
{% if show_prompt %}
1212
<a href="{{ url_for('speedtest') }}" class="btn btn-primary">Run Speed Test</a>

templates/ext/footer.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<footer class="text-center">
2+
<p>Powered by <a href="https://www.python.org/" target="_blank">Python</a>, <a
3+
href="https://flask.palletsprojects.com/" target="_blank">Flask</a>, <a href="https://getbootstrap.com/"
4+
target="_blank">Bootstrap</a>, and <a href="https://fontawesome.com/" target="_blank">FontAwesome</a>.</p>
5+
</footer>

templates/ext/message.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{% with messages = get_flashed_messages(with_categories=true) %}
2+
{% if messages %}
3+
<div id="flash-messages">
4+
{% for category, message in messages %}
5+
<div class="alert alert-{{ category }}" role="alert">
6+
{{ message }}
7+
</div>
8+
{% endfor %}
9+
</div>
10+
{% endif %}
11+
{% endwith %}
12+
13+
<script>
14+
// Automatically remove flash messages after 5 seconds
15+
setTimeout(function () {
16+
var flashMessages = document.getElementById('flash-messages');
17+
if (flashMessages) {
18+
flashMessages.style.transition = 'opacity 0.5s ease';
19+
flashMessages.style.opacity = '0';
20+
setTimeout(function () {
21+
flashMessages.remove();
22+
}, 500); // Additional time for the fade-out effect
23+
}
24+
}, 5000); // 5 seconds delay
25+
</script>

templates/ext/navbar.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
<li class="nav-item">
2222
<a class="nav-link {% if request.endpoint == 'system_health' %}active{% endif %}" href="{{ url_for('system_health') }}">System Health</a>
2323
</li>
24+
<li class="nav-item">
25+
<a class="nav-link {% if request.endpoint == 'settings' %}active{% endif %}" href="{{ url_for('settings') }}">Settings</a>
26+
</li>
2427
</ul>
2528
</div>
2629
</nav>

templates/settings.html

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{% extends 'base.html' %}
2+
3+
{% block title %}CPU Usage Details{% endblock %}
4+
{% block extra_head %}
5+
<link rel="stylesheet" href="{{ url_for('static', filename='css/settings.css') }}">
6+
{% endblock %}
7+
{% block content %}
8+
<h1>Settings</h1>
9+
<form method="POST">
10+
{% include 'ext/message.html' %}
11+
12+
<div class="form-group">
13+
<label for="speedtest_cooldown">Speedtest Cooldown (minutes):</label>
14+
<input type="number" id="speedtest_cooldown" name="speedtest_cooldown" value="{{ settings.speedtest_cooldown }}"
15+
min="1" required>
16+
</div>
17+
<div class="form-group">
18+
<label for="number_of_speedtests">Number of Speedtests Allowed per Hour:</label>
19+
<input type="number" id="number_of_speedtests" name="number_of_speedtests"
20+
value="{{ settings.number_of_speedtests }}" min="1" required>
21+
</div>
22+
<div class="form-group">
23+
<label for="timezone">Timezone:</label>
24+
<select id="timezone" name="timezone">
25+
<option value="Asia/Kolkata" {% if settings.timezone=="Asia/Kolkata" %}selected{% endif %}>Asia/Kolkata
26+
</option>
27+
<option value="America/New_York" {% if settings.timezone=="America/New_York" %}selected{% endif %}>
28+
America/New_York</option>
29+
<option value="Europe/London" {% if settings.timezone=="Europe/London" %}selected{% endif %}>Europe/London
30+
</option>
31+
<!-- Add more timezones as needed -->
32+
</select>
33+
</div>
34+
<button type="submit" class="btn btn-primary">Save Settings</button>
35+
</form>
36+
{% endblock %}

0 commit comments

Comments
 (0)