starting admin work

This commit is contained in:
2025-06-28 02:55:17 -05:00
parent 13d56066ab
commit adbb3250ad
11 changed files with 205 additions and 89 deletions

View File

@ -26,6 +26,8 @@ services:
timeout: 3s timeout: 3s
retries: 3 retries: 3
start_period: 30s start_period: 30s
networks:
- appnet
db: db:
image: mysql:8 image: mysql:8
@ -39,12 +41,18 @@ services:
- "42000:3306" - "42000:3306"
volumes: volumes:
- ./mysql_data:/var/lib/mysql - ./mysql_data:/var/lib/mysql
entrypoint: ["sh", "-c", "mkdir -p /var/lib/mysql && chown -R 1000:998 /var/lib/mysql && chmod -R 770 /var/lib/mysql && exec docker-entrypoint.sh mysqld"] entrypoint: >
sh -c "mkdir -p /var/lib/mysql &&
chown -R 1000:998 /var/lib/mysql &&
chmod -R 770 /var/lib/mysql &&
exec docker-entrypoint.sh mysqld"
healthcheck: healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 5 retries: 5
networks:
- appnet
adminer: adminer:
image: adminer image: adminer
@ -55,6 +63,8 @@ services:
- ADMINER_DEFAULT_SERVER=db - ADMINER_DEFAULT_SERVER=db
depends_on: depends_on:
- db - db
networks:
- appnet
neo4j: neo4j:
image: neo4j:5.18 image: neo4j:5.18
@ -66,6 +76,12 @@ services:
- NEO4J_AUTH=neo4j/your_secure_password - NEO4J_AUTH=neo4j/your_secure_password
volumes: volumes:
- neo4j_data:/data - neo4j_data:/data
networks:
- appnet
volumes: volumes:
neo4j_data: neo4j_data:
networks:
appnet:
driver: bridge

View File

@ -0,0 +1,28 @@
"""auto-migrate
Revision ID: 19e2a1b15b5e
Revises: f00a9585a348
Create Date: 2025-06-27 22:59:54.162560
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '19e2a1b15b5e'
down_revision = 'f00a9585a348'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -0,0 +1,28 @@
"""auto-migrate
Revision ID: 85b7ca21ec19
Revises: 8c1e8db7b3cb
Create Date: 2025-06-27 23:34:04.669553
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '85b7ca21ec19'
down_revision = '8c1e8db7b3cb'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@ -0,0 +1,28 @@
"""auto-migrate
Revision ID: 8c1e8db7b3cb
Revises: 19e2a1b15b5e
Create Date: 2025-06-27 23:21:19.031362
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '8c1e8db7b3cb'
down_revision = '19e2a1b15b5e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

BIN
nip.zip

Binary file not shown.

View File

@ -16,107 +16,123 @@
<h2 class="mb-4">View Entries</h2> <h2 class="mb-4">View Entries</h2>
{# ── Import / Export, Stats, Filters & View Toggle ─────────────────────── #} {# ── Import / Export / Stats & Filters / View Toggle ───────────────────── #}
<div class="mb-3 d-flex flex-wrap justify-content-between align-items-center"> <div class="mb-3 d-flex flex-wrap justify-content-between align-items-start">
<!-- Left: import/export & stats toggle --> {# LEFT: Import/Export + Stats toggles #}
<div class="d-flex align-items-center mb-2"> <div class="btn-toolbar mb-2" role="toolbar">
<button class="btn btn-primary me-2" data-bs-toggle="modal" data-bs-target="#importModal"> <div class="btn-group me-2" role="group">
Import CSV <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#importModal">
</button> Import CSV
<a href="{{ url_for('utility.export_data') }}" class="btn btn-secondary me-2"> </button>
Export My Data </div>
</a>
<button <div class="btn-group me-2" role="group">
class="btn btn-secondary me-2 d-inline-block d-md-none" <a href="{{ url_for('utility.export_data') }}" class="btn btn-secondary">
data-bs-toggle="modal" Export My Data
data-bs-target="#statsModal"> </a>
Stats <button
</button> class="btn btn-secondary d-inline-block d-md-none"
<button data-bs-toggle="modal"
class="btn btn-secondary me-2 d-none d-md-inline-block" data-bs-target="#statsModal">
data-bs-toggle="collapse" Stats
data-bs-target="#statsBox" </button>
aria-expanded="false" <button
aria-controls="statsBox" class="btn btn-secondary d-none d-md-inline-block"
id="statsToggle"> data-bs-toggle="collapse"
Stats <i class="bi bi-chevron-down"></i> data-bs-target="#statsBox"
</button> aria-expanded="false"
aria-controls="statsBox"
id="statsToggle">
Stats <i class="bi bi-chevron-down"></i>
</button>
</div>
</div> </div>
<!-- Right: filter form + view toggle --> {# RIGHT: filter form + view toggle #}
<form <form
method="get" method="get"
action="{{ url_for('plant.index') }}" action="{{ url_for('plant.index') }}"
class="d-flex flex-wrap align-items-center mb-2" class="row gx-2 gy-2 align-items-center mb-2"
> >
<div class="input-group me-2" style="min-width:200px;"> <div class="col-auto">
<span class="input-group-text">Search</span> <div class="input-group">
<input <span class="input-group-text">Search</span>
type="search" <input
name="q" type="search"
value="{{ q }}" name="q"
class="form-control" value="{{ q }}"
placeholder="by name…" class="form-control"
/> placeholder="by name…"
/>
</div>
</div> </div>
<select <div class="col-auto">
name="type" <select
class="form-select me-2" name="type"
style="min-width:140px;" class="form-select"
onchange="this.form.submit()" style="min-width:140px;"
> onchange="this.form.submit()"
<option value="">All Types</option> >
{% for t in plant_types %} <option value="">All Types</option>
<option {% for t in plant_types %}
value="{{ t|lower }}" <option
{% if t|lower == type_filter %}selected{% endif %} value="{{ t|lower }}"
>{{ t }}</option> {% if t|lower == type_filter %}selected{% endif %}
{% endfor %} >{{ t }}</option>
</select> {% endfor %}
</select>
</div>
<select <div class="col-auto">
name="per_page" <select
class="form-select me-2" name="per_page"
style="min-width:140px;" class="form-select"
onchange="this.form.submit()" style="min-width:140px;"
> onchange="this.form.submit()"
{% for size in [6,12,18,24] %} >
<option value="{{ size }}" {% if per_page == size %}selected{% endif %}> {% for size in [6,12,18,24] %}
{{ size }} per page <option value="{{ size }}" {% if per_page == size %}selected{% endif %}>
</option> {{ size }} per page
{% endfor %} </option>
</select> {% endfor %}
</select>
</div>
{# keep the current view so Apply doesnt reset it #} {# preserve current view so Apply doesnt reset it #}
<input type="hidden" name="view" value="{{ view_mode }}" /> <input type="hidden" name="view" value="{{ view_mode }}" />
<button type="submit" class="btn btn-primary me-2">Apply</button> <div class="col-auto">
<button type="submit" class="btn btn-primary">Apply</button>
</div>
<div class="btn-group" role="group" aria-label="View mode"> <div class="col-auto">
<a <div class="btn-group" role="group" aria-label="View mode">
href="{{ url_for('plant.index', <a
page=pagination.page, href="{{ url_for('plant.index',
per_page=per_page, page=pagination.page,
q=q, per_page=per_page,
type=type_filter, q=q,
view='grid' type=type_filter,
) }}" view='grid') }}"
class="btn btn-outline-secondary {% if view_mode=='grid' %}active{% endif %}" class="btn btn-outline-secondary {% if view_mode=='grid' %}active{% endif %}"
title="Card View" title="Card View"
><i class="bi bi-grid-3x3-gap-fill"></i></a> >
<i class="bi bi-grid-3x3-gap-fill"></i>
<a </a>
href="{{ url_for('plant.index', <a
page=pagination.page, href="{{ url_for('plant.index',
per_page=per_page, page=pagination.page,
q=q, per_page=per_page,
type=type_filter, q=q,
view='list' type=type_filter,
) }}" view='list') }}"
class="btn btn-outline-secondary {% if view_mode=='list' %}active{% endif %}" class="btn btn-outline-secondary {% if view_mode=='list' %}active{% endif %}"
title="List View" title="List View"
><i class="bi bi-list-ul"></i></a> >
<i class="bi bi-list-ul"></i>
</a>
</div>
</div> </div>
</form> </form>
</div> </div>