Compare commits

..

9 Commits

Author SHA1 Message Date
markusro c08bdc3384 moved settings from devel to production 2026-04-14 13:46:51 +02:00
markusro d481b8ee0e Merge pull request 'container' (#2) from container into main
Reviewed-on: #2
2026-04-14 11:03:48 +00:00
markusro 945ad3baf8 Merge branch 'main' into container 2026-04-14 11:03:36 +00:00
markusro b4f39381e3 Moved to uv packaging 2026-04-14 13:02:01 +02:00
markusro a953bce90e fixed permissions for db.sqlite3 2026-04-14 11:43:35 +02:00
mhjenbaz ed23bd8868 update 2026-04-14 10:59:40 +02:00
mhjenbaz 7eb26ad173 update 2026-04-14 10:54:01 +02:00
mhjenbaz c453f617e8 update 2026-04-14 10:52:49 +02:00
markusro 0b979cfada Initial container build 2026-04-14 08:40:14 +02:00
12 changed files with 298 additions and 102 deletions
+4
View File
@@ -0,0 +1,4 @@
venv
.venv
__pycache__
.idea
+63
View File
@@ -0,0 +1,63 @@
# Use the official Python runtime image
FROM python:3.13-alpine
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
RUN apk add --no-cache sqlite
# Set the working directory inside the container
WORKDIR /app
# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
ARG UID=10001
RUN adduser \
--disabled-password \
--shell "/sbin/nologin" \
--uid "${UID}" \
appuser
# Set environment variables
## Python
# Prevents Python from writing pyc files to disk
ENV PYTHONDONTWRITEBYTECODE=1
# Prevents Python from buffering stdout and stderr
ENV PYTHONUNBUFFERED=1
# Ignore pip warning about running as root
ENV PIP_ROOT_USER_ACTION=ignore
## uv
# Enable bytecode compilation
ENV UV_COMPILE_BYTECODE=1
# Copy from the cache instead of linking since it's a mounted volume
ENV UV_LINK_MODE=copy
# Disable development dependencies
ENV UV_NO_DEV=1
# copy project settings
COPY pyproject.toml uv.lock /app/
# Install the project's dependencies using the lockfile and settings
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-install-project
RUN chown appuser:appuser /app
# Copy the Django project files to the container
COPY --chown=appuser:appuser excel_mimic /app/excel_mimic
COPY --chown=appuser:appuser sheets /app/sheets
COPY --chown=appuser:appuser manage.py db.sqlite3 /app/
# Expose the Django port
EXPOSE 8000
# Switch to the non-privileged user to run the application.
USER appuser
# Allow all hosts
ENV DJANGO_ALLOWED_HOSTS=*
# Run Djangos development server
CMD ["uv", "run", "manage.py", "runserver", "0.0.0.0:8000"]
+11
View File
@@ -1,3 +1,14 @@
# Build new container
podman build . -t he-database
podman tag he-database gitea.pkm.physik.tu-darmstadt.de/markusro/he-database:latest
podman push gitea.pkm.physik.tu-darmstadt.de/markusro/he-database:latest
# Run and update container
Also check documentation from [RedHat](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux_atomic_host/7/html/managing_containers/running_containers_as_systemd_services_with_podman).
podman pull gitea.pkm.physik.tu-darmstadt.de/markusro/he-database:latest
podman run --replace --detach --name he-database -p 8000:8000 he-database:latest
# Create DB Schema in chartdb.io # Create DB Schema in chartdb.io
1. go to https://app.chartdb.io 1. go to https://app.chartdb.io
BIN
View File
Binary file not shown.
+2 -2
View File
@@ -23,9 +23,9 @@ BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'django-insecure-qsqw7#kmvlyc1ou5emdh8^_bqnvp+hui(4w#1yy4ui82+p=%p*' SECRET_KEY = 'django-insecure-qsqw7#kmvlyc1ou5emdh8^_bqnvp+hui(4w#1yy4ui82+p=%p*'
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = False
ALLOWED_HOSTS = [] ALLOWED_HOSTS = ["*"]
# Application definition # Application definition
+9
View File
@@ -0,0 +1,9 @@
[project]
name = "he-database"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"django==6.0.4",
]
+1 -1
View File
@@ -146,7 +146,7 @@
<body> <body>
<a href="{% url 'clients_list' %}" class="btn btn-outline-primary"> <a href="{% url 'clients_list' %}" class="btn btn-outline-primary">
&#8678; Go to Clients &#8678; Zur Startseite
</a> </a>
<h2>Betriebskosten</h2> <h2>Betriebskosten</h2>
+9 -9
View File
@@ -8,7 +8,7 @@
{% csrf_token %} {% csrf_token %}
<h3>Allgemeines 6-Monats-Intervall</h3> <h3>Allgemeines 6-Monats-Intervall</h3>
<label>Year:</label> <label>Jahr:</label>
<select name="year"> <select name="year">
{% for y in available_years %} {% for y in available_years %}
<option value="{{ y }}" {% if y == interval_year %}selected{% endif %}> <option value="{{ y }}" {% if y == interval_year %}selected{% endif %}>
@@ -17,7 +17,7 @@
{% endfor %} {% endfor %}
</select> </select>
<label>Start Month:</label> <label>Startmonat:</label>
<select name="start_month"> <select name="start_month">
<option value="1" {% if interval_start_month == 1 %}selected{% endif %}>01</option> <option value="1" {% if interval_start_month == 1 %}selected{% endif %}>01</option>
<option value="2" {% if interval_start_month == 2 %}selected{% endif %}>02</option> <option value="2" {% if interval_start_month == 2 %}selected{% endif %}>02</option>
@@ -33,13 +33,13 @@
<option value="12" {% if interval_start_month == 12 %}selected{% endif %}>12</option> <option value="12" {% if interval_start_month == 12 %}selected{% endif %}>12</option>
</select> </select>
<button type="submit">Apply Interval</button> <button type="submit">Intervall anwenden</button>
</form> </form>
<!-- Year Filter --> <!-- Year Filter -->
<div class="year-filter"> <div class="year-filter">
<label for="year-select">Year:</label> <label for="year-select">Jahr:</label>
<select id="year-select" onchange="window.location.href='?year='+this.value"> <select id="year-select" onchange="window.location.href='?year='+this.value">
{% for year in available_years %} {% for year in available_years %}
<option value="{{ year }}" {% if year == current_year %}selected{% endif %}> <option value="{{ year }}" {% if year == current_year %}selected{% endif %}>
@@ -73,7 +73,7 @@
</tr> </tr>
{% endfor %} {% endfor %}
<tr class="total"> <tr class="total">
<td><strong>Σ (all clients, selected 6-month interval)</strong></td> <td><strong>Σ (alle Kunden, ausgewähltes 6-Monats-Intervall)</strong></td>
{% for month in months %} {% for month in months %}
<td>-</td> <td>-</td>
@@ -86,12 +86,12 @@
<!-- Navigation Buttons --> <!-- Navigation Buttons -->
<div class="navigation-buttons"> <div class="navigation-buttons">
<a href="{% url 'table_one' %}" class="nav-button">Go to Helium Input</a> <a href="{% url 'table_one' %}" class="nav-button">Heliumrückgabe</a>
<a href="{% url 'table_two' %}" class="nav-button">Go to Helium Output</a> <a href="{% url 'table_two' %}" class="nav-button">Heliumausgabe</a>
<a href="/admin/" class="nav-button admin-button">Go to Admin Panel</a> <a href="/admin/" class="nav-button admin-button">Admin</a>
<a href="{% url 'betriebskosten_list' %}" class="nav-button">Betriebskosten</a> <a href="{% url 'betriebskosten_list' %}" class="nav-button">Betriebskosten</a>
<a href="{% url 'monthly_sheet' year=2024 month=1 %}" class="nav-button">Monthly Sheets</a> <a href="{% url 'monthly_sheet' year=2024 month=1 %}" class="nav-button">Monatsbilanz</a>
<a href="{% url 'halfyear_balance' %}" class="nav-button">Halbjahres Bilanz</a> <a href="{% url 'halfyear_balance' %}" class="nav-button">Halbjahres Bilanz</a>
<!-- ✅ NEW --> <!-- ✅ NEW -->
+92 -38
View File
@@ -4,27 +4,43 @@
<div class="spreadsheet-container"> <div class="spreadsheet-container">
<!-- Navigation Header --> <!-- Navigation Header -->
<div class="sheet-navigation"> <div class="sheet-navigation">
{# Previous month link #} <div class="nav-left">
{% with pm=prev_month %} <a href="{% url 'clients_list' %}" class="main-page-link">🏠 Hauptseite</a>
{% if pm.year and pm.month %}
<a href="{% url 'monthly_sheet' pm.year pm.month %}">← Previous</a>
{% else %}
<span class="disabled-link">← Previous</span>
{% endif %}
{% endwith %}
<h2>{{ year }} - {{ month_name }} (Sheet {{ month }}/6)</h2> {% with pm=prev_month %}
{% if pm.year and pm.month %}
<a href="{% url 'monthly_sheet' pm.year pm.month %}">← Vorherigen Monat</a>
{% else %}
<span class="disabled-link">← Vorherigen Monat</span>
{% endif %}
{% endwith %}
</div>
{# Next month link #} <div class="nav-center">
{% with nm=next_month %} <h2>{{ year }} - {{ month_name }} (Sheet {{ month }}/6)</h2>
{% if nm.year and nm.month %} </div>
<a href="{% url 'monthly_sheet' nm.year nm.month %}">Next →</a>
{% else %}
<span class="disabled-link">Next →</span>
{% endif %}
{% endwith %}
<a href="{% url 'summary_sheet' year month %}">Go to Summary</a> <div class="nav-right">
{% with nm=next_month %}
{% if nm.year and nm.month %}
<a href="{% url 'monthly_sheet' nm.year nm.month %}">Nächsten Monat →</a>
{% else %}
<span class="disabled-link">Nächsten Monat →</span>
{% endif %}
{% endwith %}
<div class="sheet-jump-box">
<label for="jump-year">Jahr:</label>
<input type="number" id="jump-year" min="2000" max="2100" value="{{ year }}">
<label for="jump-month">Monat:</label>
<input type="number" id="jump-month" min="1" max="12" value="{{ month }}">
<button type="button" id="jump-sheet-btn" class="btn btn-primary">Anwenden</button>
</div>
</div>
</div> </div>
<!-- Top Tables Container --> <!-- Top Tables Container -->
@@ -32,11 +48,11 @@
<div class="top-tables"> <div class="top-tables">
<!-- Left Table (18 rows × clients) --> <!-- Left Table (18 rows × clients) -->
<div class="table-container top-left-table"> <div class="table-container top-left-table">
<h3>Table 1: Top Left</h3> <h3>Table 1: Oben Links</h3>
<table class="spreadsheet-table"> <table class="spreadsheet-table">
<thead> <thead>
<tr> <tr>
<th>Row Label</th> <th>Zeilenbezeichnung</th>
{% for header in top_left_headers %} {% for header in top_left_headers %}
<th>{{ header }}</th> <th>{{ header }}</th>
{% endfor %} {% endfor %}
@@ -129,11 +145,11 @@
<!-- Right Table (24 rows × 6 clients) --> <!-- Right Table (24 rows × 6 clients) -->
<!-- Update the top-right table section in monthly_sheet.html --> <!-- Update the top-right table section in monthly_sheet.html -->
<div class="table-container top-right-table"> <div class="table-container top-right-table">
<h3>Table 2: Top Right</h3> <h3>Table 2: Oben Rechts</h3>
<table class="spreadsheet-table"> <table class="spreadsheet-table">
<thead> <thead>
<tr> <tr>
<th>Row Label</th> <th>Zeilenbezeichnung</th>
{% for header in top_right_headers %} {% for header in top_right_headers %}
<th>{{ header }}</th> <th>{{ header }}</th>
{% endfor %} {% endfor %}
@@ -236,11 +252,11 @@
</table> </table>
</div> </div>
<div class="table-container overall-summary-table"> <div class="table-container overall-summary-table">
<h3>Gesamtsumme (Top Left + Top Right)</h3> <h3>Gesamtsumme (Oben Links+Rechts)</h3>
<table class="spreadsheet-table"> <table class="spreadsheet-table">
<thead> <thead>
<tr> <tr>
<th>Row Label</th> <th>Zeilenbezeichnung</th>
<th>Σ</th> <th>Σ</th>
</tr> </tr>
</thead> </thead>
@@ -264,7 +280,7 @@
<!-- Bottom Tables --> <!-- Bottom Tables -->
<div class="bottom-tables"> <div class="bottom-tables">
<div class="table-container bottom-table-1"> <div class="table-container bottom-table-1">
<h3>Bottom Table 1 Gasspeicher</h3> <h3>Untere Tabelle 1 Gasspeicher</h3>
@@ -373,7 +389,7 @@
<div class="table-container bottom-table-2"> <div class="table-container bottom-table-2">
<h3>Bottom Table 2 Verbraucherbestand L-He</h3> <h3>Untere Tabelle 2 Verbraucherbestand L-He</h3>
<table class="spreadsheet-table"> <table class="spreadsheet-table">
<tbody> <tbody>
@@ -450,7 +466,7 @@
</div> </div>
<div class="table-container bottom-table-3"> <div class="table-container bottom-table-3">
<h3>Bottom Table 3 Bilanz</h3> <h3>Untere Tabelle 3 Bilanz</h3>
<table class="spreadsheet-table"> <table class="spreadsheet-table">
<thead> <thead>
@@ -621,17 +637,7 @@
</div> </div>
<!-- Save Button -->
<div class="action-bar">
<button id="save-all-btn" class="btn btn-primary">Save All Cells</button>
<div id="save-status"></div>
<div class="legend">
<small>
<span style="background-color: #d1ecf1; padding: 2px 5px;">Saved cells</span>
<span style="background-color: #d4edda; padding: 2px 5px;">Calculated cells</span>
</small>
</div>
</div>
</div> </div>
<!-- Hidden form for cell data --> <!-- Hidden form for cell data -->
@@ -645,16 +651,48 @@
padding: 20px; padding: 20px;
} }
.nav-left,
.nav-center,
.nav-right {
display: flex;
align-items: center;
gap: 12px;
}
.nav-center h2 {
margin: 0;
}
.main-page-link {
font-weight: bold;
text-decoration: none;
color: #007bff;
}
.sheet-jump-box {
display: flex;
align-items: center;
gap: 8px;
margin-left: 10px;
}
.sheet-jump-box input {
width: 80px;
padding: 6px;
}
.sheet-navigation { .sheet-navigation {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
gap: 20px;
margin-bottom: 20px; margin-bottom: 20px;
padding: 10px; padding: 10px;
background-color: #f8f9fa; background-color: #f8f9fa;
border-radius: 5px; border-radius: 5px;
flex-wrap: wrap;
} }
.sheet-navigation h2 { .sheet-navigation h2 {
margin: 0; margin: 0;
} }
@@ -821,6 +859,22 @@
<script> <script>
$(document).ready(function() { $(document).ready(function() {
$('#jump-sheet-btn').on('click', function() {
const year = parseInt($('#jump-year').val(), 10);
const month = parseInt($('#jump-month').val(), 10);
if (isNaN(year) || isNaN(month)) {
alert('Bitte Jahr und Monat eingeben.');
return;
}
if (month < 1 || month > 12) {
alert('Monat muss zwischen 1 und 12 liegen.');
return;
}
window.location.href = '/sheet/' + year + '/' + month + '/';
});
// ---------- Helpers ---------- // ---------- Helpers ----------
+25 -25
View File
@@ -286,21 +286,21 @@
<!-- This link should ONLY wrap the text below --> <!-- This link should ONLY wrap the text below -->
<a href="{% url 'clients_list' %}" class="btn btn-outline-primary"> <a href="{% url 'clients_list' %}" class="btn btn-outline-primary">
&#8678; Go to Clients &#8678; Zur Startseite
</a> </a>
<!-- 6-Month overview card (OUTSIDE any <a>) --> <!-- 6-Month overview card (OUTSIDE any <a>) -->
<div class="overview-card"> <div class="overview-card">
<div class="overview-title">Helium Input 6 Month Overview</div> <div class="overview-title">Heliumrückgabe Überblick über 6 Monate</div>
{% if overview %} {% if overview %}
<div class="overview-subtitle"> <div class="overview-subtitle">
Period: Interval
<strong> <strong>
{{ overview.start_month }}/{{ overview.start_year }} {{ overview.start_month }}/{{ overview.start_year }}
{{ overview.end_month }}/{{ overview.end_year }} {{ overview.end_month }}/{{ overview.end_year }}
</strong> </strong>
(selected on the main page) (ausgewählt am Start Seite)
</div> </div>
<table class="overview-table"> <table class="overview-table">
@@ -310,7 +310,7 @@
{% for g in overview.groups %} {% for g in overview.groups %}
<th>{{ g.label }}</th> <th>{{ g.label }}</th>
{% endfor %} {% endfor %}
<th>Month total</th> <th>Monat total</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -342,7 +342,7 @@
<h2>Helium Input</h2> <h2>Helium Input</h2>
<div class="table-container"> <div class="table-container">
<button class="add-row-btn" id="add-row-one">Add Row</button> <button class="add-row-btn" id="add-row-one">Eingabe hinzufügen</button>
<table id="table-one"> <table id="table-one">
<colgroup> <colgroup>
<col style="width: 3%"> <!-- # --> <col style="width: 3%"> <!-- # -->
@@ -367,7 +367,7 @@
<th>#</th> <th>#</th>
<th>ID</th> <th>ID</th>
<th>Institute</th> <th>Institute</th>
<th>Client</th> <th>Kunde</th>
<th>Druck</th> <th>Druck</th>
<th>Reinheit</th> <th>Reinheit</th>
<th>Druckkorrektur</th> <th>Druckkorrektur</th>
@@ -377,8 +377,8 @@
<th>L-He</th> <th>L-He</th>
<th>L-He zus.</th> <th>L-He zus.</th>
<th>L-He ges.</th> <th>L-He ges.</th>
<th>Date</th> <th>Datum</th>
<th>Month</th> <th>Monat</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
@@ -409,8 +409,8 @@
{% endif %} {% endif %}
</td> </td>
<td class="actions"> <td class="actions">
<button class="edit-btn-one">Edit</button> <button class="edit-btn-one">Bearbeiten</button>
<button class="delete-btn-one">Delete</button> <button class="delete-btn-one">Löschen</button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@@ -522,7 +522,7 @@
<!-- Client Selection --> <!-- Client Selection -->
<label for="edit-client-id">Kunde:</label> <label for="edit-client-id">Kunde:</label>
<select id="edit-client-id" disabled> <select id="edit-client-id" disabled>
<option value="">Select Institute first</option> <option value="">Institut erstmal auswählen</option>
{% for client in clients %} {% for client in clients %}
<option value="{{ client.id }}" data-institute="{{ client.institute.id }}">{{ client.name }}</option> <option value="{{ client.id }}" data-institute="{{ client.institute.id }}">{{ client.name }}</option>
{% endfor %} {% endfor %}
@@ -708,19 +708,19 @@
const instituteId = $('#add-institute-id').val(); const instituteId = $('#add-institute-id').val();
if (!instituteId) { if (!instituteId) {
alert('Please select an institute'); alert('Institut erstmal auswählen');
return; return;
} }
if (!clientId) { if (!clientId) {
alert('Please select a client'); alert('Kunde erstmal auswählen');
return; return;
} }
// Validate date first // Validate date first
let dateInput = $('#add-date').val(); let dateInput = $('#add-date').val();
if (!dateInput) { if (!dateInput) {
alert('Please select a date'); alert('Datum erstmal auswählen');
return; return;
} }
@@ -732,17 +732,17 @@
let gesFlaschInhalt = parseFloat($('#add-constant-300').val()) || 300.0; let gesFlaschInhalt = parseFloat($('#add-constant-300').val()) || 300.0;
if (isNaN(pressure) || pressure < 0) { if (isNaN(pressure) || pressure < 0) {
alert('Please enter a valid pressure value'); alert('Bitte geben Sie einen gültigen Druckwert ein.');
return; return;
} }
if (isNaN(purity) || purity < 0 || purity > 100) { if (isNaN(purity) || purity < 0 || purity > 100) {
alert('Please enter a valid purity value (0-100)'); alert('Bitte geben Sie einen gültigen Reinheitswert ein (0-100).');
return; return;
} }
if (isNaN(druckkorrektur) || druckkorrektur < 0) { if (isNaN(druckkorrektur) || druckkorrektur < 0) {
alert('Please enter a valid Druckkorrektur value'); alert('Bitte geben Sie einen gültigen Druckkorrekturwert ein');
return; return;
} }
@@ -875,12 +875,12 @@
const instituteId = $('#edit-institute-id').val(); const instituteId = $('#edit-institute-id').val();
if (!instituteId) { if (!instituteId) {
alert('Please select an institute'); alert('Institut erstmal auswählen');
return; return;
} }
if (!clientId) { if (!clientId) {
alert('Please select a client'); alert('Kunde erstmal auswählen');
return; return;
} }
@@ -892,17 +892,17 @@
let gesFlaschInhalt = parseFloat($('#edit-constant-300').val()) || 300.0; let gesFlaschInhalt = parseFloat($('#edit-constant-300').val()) || 300.0;
if (isNaN(pressure) || pressure < 0) { if (isNaN(pressure) || pressure < 0) {
alert('Please enter a valid pressure value'); alert('Bitte geben Sie einen gültigen Druckwert ein.');
return; return;
} }
if (isNaN(purity) || purity < 0 || purity > 100) { if (isNaN(purity) || purity < 0 || purity > 100) {
alert('Please enter a valid purity value (0-100)'); alert('Bitte geben Sie einen gültigen Reinheitswert ein (0-100).');
return; return;
} }
if (isNaN(druckkorrektur) || druckkorrektur < 0) { if (isNaN(druckkorrektur) || druckkorrektur < 0) {
alert('Please enter a valid Druckkorrektur value'); alert('Bitte geben Sie einen gültigen Druckkorrekturwert ein');
return; return;
} }
@@ -937,7 +937,7 @@
// Validate inputs // Validate inputs
if (!formData.date) { if (!formData.date) {
alert('Please select a date'); alert('Bitte wählen Sie ein Datum.');
return; return;
} }
@@ -993,7 +993,7 @@
} }
}, },
error: function () { error: function () {
alert('Failed to delete entry. Please try again.'); alert('Eintrag konnte nicht gelöscht werden. Bitte versuchen Sie es erneut.');
} }
}); });
}); });
+27 -27
View File
@@ -190,28 +190,28 @@
<div class="d-flex justify-content-start mb-2"> <div class="d-flex justify-content-start mb-2">
<!-- "Go to Clients" button at top-left --> <!-- "Go to Clients" button at top-left -->
<a href="{% url 'clients_list' %}" class="btn btn-outline-primary"> <a href="{% url 'clients_list' %}" class="btn btn-outline-primary">
&#8678; Go to Clients &#8678; Zur Startseite
</a> </a>
</div> </div>
<h2>LHe Dewar Output</h2> <h2>LHe Dewar Output</h2>
<div class="table-container"> <div class="table-container">
<button class="add-row-btn" id="add-row-two">Add Output</button> <button class="add-row-btn" id="add-row-two">Eingabe hinzufügen</button>
<table id="table-two"> <table id="table-two">
<thead> <thead>
<tr> <tr>
<th>#</th> <th>#</th>
<th>ID</th> <th>ID</th>
<th>Institute</th> <th>Institut</th>
<th>Client</th> <th>Kunde</th>
<th>Date</th> <th>Datum</th>
<th>Warm</th> <th>Warm</th>
<th>LHe Delivery</th> <th>LHe Anlieferung</th>
<th>Vor</th> <th>Vor</th>
<th>Nach</th> <th>Nach</th>
<th>LHe Output</th> <th>LHe Ausgabe</th>
<th>Notes</th> <th>Notizen</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
@@ -230,8 +230,8 @@
<td>{% if entry.lhe_output is not None %}{{ entry.lhe_output|floatformat:1 }}{% endif %}</td> <td>{% if entry.lhe_output is not None %}{{ entry.lhe_output|floatformat:1 }}{% endif %}</td>
<td>{{ entry.notes }}</td> <td>{{ entry.notes }}</td>
<td class="actions"> <td class="actions">
<button class="edit-btn-two">Edit</button> <button class="edit-btn-two">Bearbeiten</button>
<button class="delete-btn-two">Delete</button> <button class="delete-btn-two">Löschen</button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@@ -245,24 +245,24 @@
<h3>LHe Dewar Output</h3> <h3>LHe Dewar Output</h3>
<!-- Institute Selection --> <!-- Institute Selection -->
<label for="add-institute-id">Institute:</label> <label for="add-institute-id">Institut:</label>
<select id="add-institute-id"> <select id="add-institute-id">
<option value="">Select Institute</option> <option value="">Institut auswählen</option>
{% for institute in institutes %} {% for institute in institutes %}
<option value="{{ institute.id }}">{{ institute.name }}</option> <option value="{{ institute.id }}">{{ institute.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
<!-- Client Selection (will be populated based on institute) --> <!-- Client Selection (will be populated based on institute) -->
<label for="add-client-id">Client:</label> <label for="add-client-id">Kunde:</label>
<select id="add-client-id" disabled> <select id="add-client-id" disabled>
<option value="">Select Institute first</option> <option value="">Institut erstaml auswählen</option>
{% for client in clients %} {% for client in clients %}
<option value="{{ client.id }}" data-institute="{{ client.institute.id }}">{{ client.name }}</option> <option value="{{ client.id }}" data-institute="{{ client.institute.id }}">{{ client.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
<label for="add-date">Date:</label> <label for="add-date">Datum:</label>
<input type="date" id="add-date"> <input type="date" id="add-date">
<!-- Changed from checkbox to number input --> <!-- Changed from checkbox to number input -->
@@ -273,7 +273,7 @@
<div class="input-with-label"> <div class="input-with-label">
<label for="add-lhe-delivery">LHe Anlieferung:</label> <label for="add-lhe-delivery">LHe Anlieferung:</label>
<input type="text" id="add-lhe-delivery" placeholder="Enter delivery amount"> <input type="text" id="add-lhe-delivery" placeholder="Wert eingeben">
</div> </div>
<div class="input-with-label"> <div class="input-with-label">
@@ -291,8 +291,8 @@
<input type="number" id="add-lhe-output" readonly> <input type="number" id="add-lhe-output" readonly>
</div> </div>
<label for="add-notes">Notes:</label> <label for="add-notes">Notizen:</label>
<textarea id="add-notes" placeholder="Additional notes"></textarea> <textarea id="add-notes" placeholder="Notizen"></textarea>
<div class="popup-buttons"> <div class="popup-buttons">
<button class="save-btn" id="save-add-two">Save</button> <button class="save-btn" id="save-add-two">Save</button>
@@ -310,16 +310,16 @@
<!-- Institute Selection --> <!-- Institute Selection -->
<label for="edit-institute-id">Institute:</label> <label for="edit-institute-id">Institute:</label>
<select id="edit-institute-id"> <select id="edit-institute-id">
<option value="">Select Institute</option> <option value="">Institut Auswälen</option>
{% for institute in institutes %} {% for institute in institutes %}
<option value="{{ institute.id }}">{{ institute.name }}</option> <option value="{{ institute.id }}">{{ institute.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
<!-- Client Selection (will be populated based on institute) --> <!-- Client Selection (will be populated based on institute) -->
<label for="edit-client-id">Client:</label> <label for="edit-client-id">Kunde:</label>
<select id="edit-client-id" disabled> <select id="edit-client-id" disabled>
<option value="">Select Institute first</option> <option value="">Institut erstmal Auswälen</option>
{% for client in clients %} {% for client in clients %}
<option value="{{ client.id }}" data-institute="{{ client.institute.id }}">{{ client.name }}</option> <option value="{{ client.id }}" data-institute="{{ client.institute.id }}">{{ client.name }}</option>
{% endfor %} {% endfor %}
@@ -336,7 +336,7 @@
<div class="input-with-label"> <div class="input-with-label">
<label for="edit-lhe-delivery">LHe Anlieferung:</label> <label for="edit-lhe-delivery">LHe Anlieferung:</label>
<input type="text" id="edit-lhe-delivery" placeholder="Enter delivery amount"> <input type="text" id="edit-lhe-delivery" placeholder="Wert eingeben">
</div> </div>
<div class="input-with-label"> <div class="input-with-label">
@@ -399,7 +399,7 @@
function filterClients(instituteId, targetSelect, allOptions) { function filterClients(instituteId, targetSelect, allOptions) {
if (!instituteId) { if (!instituteId) {
// Show only the default option if no institute selected // Show only the default option if no institute selected
targetSelect.html('<option value="">Select Institute first</option>'); targetSelect.html('<option value="">erstmal Institut auswählen</option>');
targetSelect.prop('disabled', true); targetSelect.prop('disabled', true);
} else { } else {
// Restore all options first // Restore all options first
@@ -412,7 +412,7 @@
targetSelect.find('option').hide(); targetSelect.find('option').hide();
// Always show the "Select Client" option // Always show the "Select Client" option
targetSelect.find('option[value=""]').show().text('Select Client'); targetSelect.find('option[value=""]').show().text('Kunde Auswählen');
// Show only clients from selected institute // Show only clients from selected institute
const clientsFromInstitute = targetSelect.find(`option[data-institute="${instituteId}"]`); const clientsFromInstitute = targetSelect.find(`option[data-institute="${instituteId}"]`);
@@ -473,7 +473,7 @@
$('#add-row-two').on('click', function () { $('#add-row-two').on('click', function () {
// Reset form // Reset form
$('#add-institute-id').val(''); $('#add-institute-id').val('');
$('#add-client-id').html('<option value="">Select Institute first</option>'); $('#add-client-id').html('<option value="">Erstaml institut auswählen</option>');
$('#add-client-id').prop('disabled', true); $('#add-client-id').prop('disabled', true);
$('#add-date').val(''); $('#add-date').val('');
$('#add-is-warm').val('0'); $('#add-is-warm').val('0');
@@ -645,12 +645,12 @@
const instituteId = $('#edit-institute-id').val(); const instituteId = $('#edit-institute-id').val();
if (!instituteId) { if (!instituteId) {
alert('Please select an institute'); alert('Institut erstmal auswählen');
return; return;
} }
if (!clientId) { if (!clientId) {
alert('Please select a client'); alert('Kunde erstmal auswählen');
return; return;
} }
Generated
+55
View File
@@ -0,0 +1,55 @@
version = 1
revision = 3
requires-python = ">=3.12"
[[package]]
name = "asgiref"
version = "3.11.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/63/40/f03da1264ae8f7cfdbf9146542e5e7e8100a4c66ab48e791df9a03d3f6c0/asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce", size = 38550, upload-time = "2026-02-03T13:30:14.33Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" },
]
[[package]]
name = "django"
version = "6.0.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/60/b9/4155091ad1788b38563bd77a7258c0834e8c12a7f56f6975deaf54f8b61d/django-6.0.4.tar.gz", hash = "sha256:8cfa2572b3f2768b2e84983cf3c4811877a01edb64e817986ec5d60751c113ac", size = 10907407, upload-time = "2026-04-07T13:55:44.961Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/47/3d61d611609764aa71a37f7037b870e7bfb22937366974c4fd46cada7bab/django-6.0.4-py3-none-any.whl", hash = "sha256:14359c809fc16e8f81fd2b59d7d348e4d2d799da6840b10522b6edf7b8afc1da", size = 8368342, upload-time = "2026-04-07T13:55:37.999Z" },
]
[[package]]
name = "he-database"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "django" },
]
[package.metadata]
requires-dist = [{ name = "django", specifier = "==6.0.4" }]
[[package]]
name = "sqlparse"
version = "0.5.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" },
]
[[package]]
name = "tzdata"
version = "2026.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639, upload-time = "2026-04-03T11:25:22.002Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952, upload-time = "2026-04-03T11:25:20.313Z" },
]