starting admin work
This commit is contained in:
@ -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
|
||||||
|
28
migrations/versions/19e2a1b15b5e_auto_migrate.py
Normal file
28
migrations/versions/19e2a1b15b5e_auto_migrate.py
Normal 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 ###
|
28
migrations/versions/85b7ca21ec19_auto_migrate.py
Normal file
28
migrations/versions/85b7ca21ec19_auto_migrate.py
Normal 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 ###
|
28
migrations/versions/8c1e8db7b3cb_auto_migrate.py
Normal file
28
migrations/versions/8c1e8db7b3cb_auto_migrate.py
Normal 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 ###
|
@ -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 doesn’t reset it #}
|
{# preserve current view so Apply doesn’t 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>
|
||||||
|
Reference in New Issue
Block a user