tweax
This commit is contained in:
33
.env
33
.env
@@ -1,33 +0,0 @@
|
||||
# In all environments, the following files are loaded if they exist,
|
||||
# the latter taking precedence over the former:
|
||||
#
|
||||
# * .env contains default values for the environment variables needed by the app
|
||||
# * .env.local uncommitted file with local overrides
|
||||
# * .env.$APP_ENV committed environment-specific defaults
|
||||
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
||||
#
|
||||
# Real environment variables win over .env files.
|
||||
#
|
||||
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||
# https://symfony.com/doc/current/configuration/secrets.html
|
||||
#
|
||||
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
APP_SECRET=
|
||||
APP_SHARE_DIR=var/share
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/routing ###
|
||||
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
||||
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
||||
DEFAULT_URI=http://localhost
|
||||
###< symfony/routing ###
|
||||
|
||||
# DynamoDB / JormunDB connection
|
||||
DYNAMO_REGION=us-east-1
|
||||
DYNAMO_ENDPOINT=http://45.76.2.182:8002
|
||||
DYNAMO_KEY=AKIAIOSFODNN7EXAMPLE
|
||||
DYNAMO_SECRET=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
@@ -15,10 +15,10 @@ class DynamoService
|
||||
$this->client = new DynamoDbClient([
|
||||
'region' => $_ENV['DYNAMO_REGION'] ?? 'us-east-1',
|
||||
'version' => 'latest',
|
||||
'endpoint' => $_ENV['DYNAMO_ENDPOINT'] ?? 'http://127.0.0.1:8002',
|
||||
'endpoint' => $_ENV['DYNAMO_ENDPOINT'] ?? 'https://jormun-write-through-dev.vultrlabs.dev',
|
||||
'credentials' => [
|
||||
'key' => $_ENV['DYNAMO_KEY'] ?? 'AKIAIOSFODNN7EXAMPLE',
|
||||
'secret' => $_ENV['DYNAMO_SECRET'] ?? 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
|
||||
'key' => $_ENV['DYNAMO_KEY'],
|
||||
'secret' => $_ENV['DYNAMO_SECRET'],
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
@@ -4,211 +4,213 @@
|
||||
{% block title %}{{ tableName }} — Browse · Jormun Admin{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<a href="{{ path('dashboard') }}"><i class="bi bi-house-fill"></i> Home</a>
|
||||
<span class="sep">/</span>
|
||||
<span class="current">{{ tableName }}</span>
|
||||
<span class="sep">/</span>
|
||||
<span class="current">Browse</span>
|
||||
<a href="{{ path('dashboard') }}"><i class="bi bi-house-fill"></i> Home</a>
|
||||
<span class="sep">/</span>
|
||||
<span class="current">{{ tableName }}</span>
|
||||
<span class="sep">/</span>
|
||||
<span class="current">Browse</span>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar_tables %}
|
||||
{{ macros.sidebar_table_links(tables, tableName) }}
|
||||
{{ macros.sidebar_table_links(tables, tableName) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{# Op Tabs #}
|
||||
<nav class="op-tabs">
|
||||
<a href="{{ path('table_browse', {name: tableName}) }}" class="op-tab active">
|
||||
<i class="bi bi-grid-3x3-gap"></i> Browse
|
||||
</a>
|
||||
<a href="{{ path('table_structure', {name: tableName}) }}" class="op-tab">
|
||||
<i class="bi bi-diagram-3"></i> Structure
|
||||
</a>
|
||||
<a href="{{ path('table_query', {name: tableName}) }}" class="op-tab">
|
||||
<i class="bi bi-search"></i> Query
|
||||
</a>
|
||||
<a href="{{ path('table_item_new', {name: tableName}) }}" class="op-tab">
|
||||
<i class="bi bi-plus-circle"></i> Insert
|
||||
</a>
|
||||
<span style="flex:1;"></span>
|
||||
{# Drop table — in a confirmation modal #}
|
||||
<button class="op-tab" style="color:#ef4444;" @click="showDrop = true">
|
||||
<i class="bi bi-trash3"></i> Drop Table
|
||||
</button>
|
||||
<a href="{{ path('table_browse', {name: tableName}) }}" class="op-tab active">
|
||||
<i class="bi bi-grid-3x3-gap"></i> Browse
|
||||
</a>
|
||||
<a href="{{ path('table_structure', {name: tableName}) }}" class="op-tab">
|
||||
<i class="bi bi-diagram-3"></i> Structure
|
||||
</a>
|
||||
<a href="{{ path('table_query', {name: tableName}) }}" class="op-tab">
|
||||
<i class="bi bi-search"></i> Query
|
||||
</a>
|
||||
<a href="{{ path('table_item_new', {name: tableName}) }}" class="op-tab">
|
||||
<i class="bi bi-plus-circle"></i> Insert
|
||||
</a>
|
||||
<span style="flex:1;"></span>
|
||||
{# Drop table — in a confirmation modal #}
|
||||
<button class="op-tab" style="color:#ef4444;" @click="showDrop = true">
|
||||
<i class="bi bi-trash3"></i> Drop Table
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
{# Error #}
|
||||
{% if error %}
|
||||
<div style="background:#fef2f2;border:1px solid #fca5a5;color:#991b1b;border-radius:6px;padding:0.75rem 1rem;margin-bottom:1rem;font-size:0.8rem;">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>{{ error }}
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>{{ error }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Stats row #}
|
||||
{% if not error %}
|
||||
<div class="d-flex align-items-center gap-2 mb-3 flex-wrap">
|
||||
<span class="stat-pill"><i class="bi bi-table"></i> {{ tableName }}</span>
|
||||
<span class="stat-pill"><i class="bi bi-check-circle" style="color:var(--jormun-teal);"></i> {{ (desc.TableStatus ?? 'UNKNOWN')|lower }}</span>
|
||||
<span class="stat-pill"><i class="bi bi-collection"></i> ~{{ (desc.ItemCount ?? 0)|number_format }} items</span>
|
||||
<span class="stat-pill"><i class="bi bi-eye"></i> showing {{ count }} of {{ scannedCount }} scanned</span>
|
||||
<span class="stat-pill"><i class="bi bi-table"></i> {{ tableName }}</span>
|
||||
<span class="stat-pill"><i class="bi bi-check-circle" style="color:var(--jormun-teal);"></i> {{ (desc.TableStatus ?? 'UNKNOWN')|lower }}</span>
|
||||
<span class="stat-pill"><i class="bi bi-collection"></i> ~{{ (desc.ItemCount ?? 0)|number_format }} items</span>
|
||||
<span class="stat-pill"><i class="bi bi-eye"></i> showing {{ count }} of {{ scannedCount }} scanned</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Main data card #}
|
||||
<div class="content-card" x-data="browseTable()">
|
||||
<div class="content-card-header">
|
||||
<h6><i class="bi bi-grid-3x3-gap me-1" style="color:var(--jormun-teal);"></i> Rows</h6>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<label style="font-size:0.72rem;color:#64748b;">Rows per page</label>
|
||||
<select class="jormun-select" onchange="changeLimit(this.value)" style="width:auto;">
|
||||
{% for l in [10, 25, 50, 100] %}
|
||||
<option value="{{ l }}" {% if l == limit %}selected{% endif %}>{{ l }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-card-header">
|
||||
<h6><i class="bi bi-grid-3x3-gap me-1" style="color:var(--jormun-teal);"></i> Rows</h6>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<label style="font-size:0.72rem;color:#64748b;">Rows per page</label>
|
||||
<select class="jormun-select" onchange="changeLimit(this.value)" style="width:auto;">
|
||||
{% set limit = limit is defined ? limit : 25 %}
|
||||
{% for l in [10, 25, 50, 100] %}
|
||||
<option value="{{ l }}" {% if l == limit %}selected{% endif %}>{{ l }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if items is empty %}
|
||||
<div class="empty-state">
|
||||
<i class="bi bi-inbox"></i>
|
||||
<div style="font-family:'Syne',sans-serif;font-weight:700;font-size:0.9rem;color:#374151;margin-bottom:0.3rem;">No items found</div>
|
||||
<div style="font-size:0.75rem;">This table is empty.</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="overflow-x:auto;">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:100px;">Actions</th>
|
||||
{% for col in columns %}
|
||||
<th>
|
||||
{{ col }}
|
||||
{% if keySchema.HASH is defined and keySchema.HASH.name == col %}
|
||||
<span class="type-badge" title="Partition Key">PK</span>
|
||||
{% endif %}
|
||||
{% if keySchema.RANGE is defined and keySchema.RANGE.name == col %}
|
||||
<span class="type-badge" title="Sort Key">SK</span>
|
||||
{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in items %}
|
||||
{% set itemKey = {} %}
|
||||
{% if keySchema.HASH is defined %}
|
||||
{% set itemKey = itemKey|merge({(keySchema.HASH.name): item[keySchema.HASH.name]}) %}
|
||||
{% endif %}
|
||||
{% if keySchema.RANGE is defined %}
|
||||
{% set itemKey = itemKey|merge({(keySchema.RANGE.name): item[keySchema.RANGE.name]}) %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td class="action-cell">
|
||||
<a href="{{ path('table_item_edit', {name: tableName, key: itemKey|json_encode}) }}" class="btn-sm-edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<button
|
||||
class="btn-danger-sm ms-1"
|
||||
@click="confirmDelete($el.dataset.key)"
|
||||
data-key="{{ itemKey|json_encode|e('html_attr') }}"
|
||||
>
|
||||
<i class="bi bi-trash3"></i>
|
||||
</button>
|
||||
</td>
|
||||
{% for col in columns %}
|
||||
<td class="{% if keySchema.HASH is defined and keySchema.HASH.name == col %}pk-cell{% endif %} cell-value" title="{{ item[col] is defined ? item[col]|json_encode : 'null' }}">
|
||||
{% if item[col] is defined %}
|
||||
{% set val = item[col] %}
|
||||
{% if val is iterable %}
|
||||
<span style="color:#6366f1;" title="{{ val|json_encode }}">
|
||||
<i class="bi bi-braces"></i> {{ val|json_encode|slice(0, 40) }}{% if val|json_encode|length > 40 %}…{% endif %}
|
||||
</span>
|
||||
{% else %}
|
||||
{{ val|e|slice(0, 60) }}{% if (val|e|length) > 60 %}…{% endif %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="null-val">NULL</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% if items is empty %}
|
||||
<div class="empty-state">
|
||||
<i class="bi bi-inbox"></i>
|
||||
<div style="font-family:'Syne',sans-serif;font-weight:700;font-size:0.9rem;color:#374151;margin-bottom:0.3rem;">No items found</div>
|
||||
<div style="font-size:0.75rem;">This table is empty.</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="overflow-x:auto;">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:100px;">Actions</th>
|
||||
{% for col in columns %}
|
||||
<th>
|
||||
{{ col }}
|
||||
{% if keySchema.HASH is defined and keySchema.HASH.name == col %}
|
||||
<span class="type-badge" title="Partition Key">PK</span>
|
||||
{% endif %}
|
||||
{% if keySchema.RANGE is defined and keySchema.RANGE.name == col %}
|
||||
<span class="type-badge" title="Sort Key">SK</span>
|
||||
{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in items %}
|
||||
{% set itemKey = {} %}
|
||||
{% if keySchema.HASH is defined %}
|
||||
{% set itemKey = itemKey|merge({(keySchema.HASH.name): item[keySchema.HASH.name]}) %}
|
||||
{% endif %}
|
||||
{% if keySchema.RANGE is defined %}
|
||||
{% set itemKey = itemKey|merge({(keySchema.RANGE.name): item[keySchema.RANGE.name]}) %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td class="action-cell">
|
||||
<a href="{{ path('table_item_edit', {name: tableName, key: itemKey|json_encode}) }}" class="btn-sm-edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<button
|
||||
class="btn-danger-sm ms-1"
|
||||
@click="confirmDelete($el.dataset.key)"
|
||||
data-key="{{ itemKey|json_encode|e('html_attr') }}"
|
||||
>
|
||||
<i class="bi bi-trash3"></i>
|
||||
</button>
|
||||
</td>
|
||||
{% for col in columns %}
|
||||
<td class="{% if keySchema.HASH is defined and keySchema.HASH.name == col %}pk-cell{% endif %} cell-value" title="{{ item[col] is defined ? item[col]|json_encode|e('html_attr') : 'null' }}">
|
||||
{% if item[col] is defined %}
|
||||
{% set val = item[col] %}
|
||||
{% if val is iterable %}
|
||||
<span style="color:#6366f1;" title="{{ val|json_encode|e('html_attr') }}">
|
||||
<i class="bi bi-braces"></i> {{ val|json_encode|slice(0, 40) }}{% if val|json_encode|length > 40 %}…{% endif %}
|
||||
</span>
|
||||
{% else %}
|
||||
{% set valStr = val is iterable ? val|json_encode : val|e %}
|
||||
{{ valStr|slice(0, 60) }}{% if valStr|length > 60 %}…{% endif %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="null-val">NULL</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{# Pagination #}
|
||||
<div style="padding:0.65rem 1rem;border-top:1px solid #f1f5f9;display:flex;align-items:center;gap:0.5rem;justify-content:space-between;">
|
||||
<div style="font-size:0.72rem;color:#64748b;">
|
||||
Showing {{ count }} item{{ count != 1 ? 's' : '' }}
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
{% if prevKeys is not empty %}
|
||||
{% set prevStack = prevKeys[0:(prevKeys|length - 1)] %}
|
||||
{% set prevLastKey = prevKeys|last %}
|
||||
<a href="{{ path('table_browse', {name: tableName, lastKey: prevLastKey, prevKeys: prevStack|json_encode, limit: limit}) }}" class="btn-jormun-outline">
|
||||
<i class="bi bi-chevron-left"></i> Prev
|
||||
</a>
|
||||
{% endif %}
|
||||
{# Pagination #}
|
||||
<div style="padding:0.65rem 1rem;border-top:1px solid #f1f5f9;display:flex;align-items:center;gap:0.5rem;justify-content:space-between;">
|
||||
<div style="font-size:0.72rem;color:#64748b;">
|
||||
Showing {{ count }} item{{ count != 1 ? 's' : '' }}
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
{% if prevKeys is not empty %}
|
||||
{% set prevStack = prevKeys[0:(prevKeys|length - 1)] %}
|
||||
{% set prevLastKey = prevKeys|last %}
|
||||
<a href="{{ path('table_browse', {name: tableName, lastKey: prevLastKey, prevKeys: prevStack|json_encode, limit: limit}) }}" class="btn-jormun-outline">
|
||||
<i class="bi bi-chevron-left"></i> Prev
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if nextKey %}
|
||||
{% set newPrevKeys = prevKeys %}
|
||||
{% if currentKey %}
|
||||
{% set newPrevKeys = newPrevKeys|merge([currentKey]) %}
|
||||
{% else %}
|
||||
{# first page, push empty marker #}
|
||||
{% set newPrevKeys = newPrevKeys|merge(['null']) %}
|
||||
{% endif %}
|
||||
<a href="{{ path('table_browse', {name: tableName, lastKey: nextKey, prevKeys: newPrevKeys|json_encode, limit: limit}) }}" class="btn-jormun">
|
||||
Next <i class="bi bi-chevron-right"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if nextKey %}
|
||||
{% set newPrevKeys = prevKeys %}
|
||||
{% if currentKey %}
|
||||
{% set newPrevKeys = newPrevKeys|merge([currentKey]) %}
|
||||
{% else %}
|
||||
{# first page, push empty marker #}
|
||||
{% set newPrevKeys = newPrevKeys|merge(['']) %}
|
||||
{% endif %}
|
||||
<a href="{{ path('table_browse', {name: tableName, lastKey: nextKey, prevKeys: newPrevKeys|json_encode, limit: limit}) }}" class="btn-jormun">
|
||||
Next <i class="bi bi-chevron-right"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# Delete item modal #}
|
||||
<div x-show="deleteModal" x-cloak style="position:fixed;inset:0;background:rgba(0,0,0,0.4);z-index:9000;display:flex;align-items:center;justify-content:center;" @click.self="deleteModal=false">
|
||||
<div style="background:#fff;border-radius:8px;padding:1.5rem;width:420px;max-width:90vw;" @click.stop>
|
||||
<h6 class="font-display" style="font-weight:700;margin-bottom:0.5rem;">
|
||||
<i class="bi bi-trash3-fill" style="color:#ef4444;"></i> Delete Item
|
||||
</h6>
|
||||
<p style="font-size:0.8rem;color:#64748b;margin-bottom:1rem;">This will permanently delete the item with key:</p>
|
||||
<pre style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:4px;padding:0.5rem;font-size:0.72rem;margin-bottom:1rem;" x-text="JSON.stringify(deleteKey, null, 2)"></pre>
|
||||
<div class="d-flex gap-2 justify-content-end">
|
||||
<button class="btn-jormun-outline" @click="deleteModal=false">Cancel</button>
|
||||
<form method="POST" :action="deleteAction">
|
||||
<input type="hidden" name="key" :value="JSON.stringify(deleteKey)">
|
||||
<button type="submit" class="btn-jormun" style="background:#ef4444;">
|
||||
<i class="bi bi-trash3"></i> Delete
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# Delete item modal #}
|
||||
<div x-show="deleteModal" x-cloak style="position:fixed;inset:0;background:rgba(0,0,0,0.4);z-index:9000;display:flex;align-items:center;justify-content:center;" @click.self="deleteModal=false">
|
||||
<div style="background:#fff;border-radius:8px;padding:1.5rem;width:420px;max-width:90vw;" @click.stop>
|
||||
<h6 class="font-display" style="font-weight:700;margin-bottom:0.5rem;">
|
||||
<i class="bi bi-trash3-fill" style="color:#ef4444;"></i> Delete Item
|
||||
</h6>
|
||||
<p style="font-size:0.8rem;color:#64748b;margin-bottom:1rem;">This will permanently delete the item with key:</p>
|
||||
<pre style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:4px;padding:0.5rem;font-size:0.72rem;margin-bottom:1rem;" x-text="JSON.stringify(deleteKey, null, 2)"></pre>
|
||||
<div class="d-flex gap-2 justify-content-end">
|
||||
<button class="btn-jormun-outline" @click="deleteModal=false">Cancel</button>
|
||||
<form method="POST" :action="deleteAction">
|
||||
<input type="hidden" name="key" :value="JSON.stringify(deleteKey)">
|
||||
<button type="submit" class="btn-jormun" style="background:#ef4444;">
|
||||
<i class="bi bi-trash3"></i> Delete
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Drop Table modal #}
|
||||
<div x-data="{ showDrop: false }" x-cloak>
|
||||
<div x-show="showDrop" style="position:fixed;inset:0;background:rgba(0,0,0,0.4);z-index:9000;display:flex;align-items:center;justify-content:center;" @click.self="showDrop=false">
|
||||
<div style="background:#fff;border-radius:8px;padding:1.5rem;width:400px;max-width:90vw;">
|
||||
<h6 class="font-display" style="font-weight:700;margin-bottom:0.5rem;color:#ef4444;">
|
||||
<i class="bi bi-exclamation-triangle-fill"></i> Drop Table
|
||||
</h6>
|
||||
<p style="font-size:0.8rem;color:#374151;margin-bottom:1rem;">
|
||||
Are you sure you want to drop <strong>{{ tableName }}</strong>? This action is <strong>irreversible</strong> and will delete all data.
|
||||
</p>
|
||||
<div class="d-flex gap-2 justify-content-end">
|
||||
<button class="btn-jormun-outline" @click="showDrop=false">Cancel</button>
|
||||
<form method="POST" action="{{ path('table_drop', {name: tableName}) }}">
|
||||
<button type="submit" class="btn-jormun" style="background:#ef4444;">
|
||||
<i class="bi bi-trash3-fill"></i> Drop Table
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div x-show="showDrop" style="position:fixed;inset:0;background:rgba(0,0,0,0.4);z-index:9000;display:flex;align-items:center;justify-content:center;" @click.self="showDrop=false">
|
||||
<div style="background:#fff;border-radius:8px;padding:1.5rem;width:400px;max-width:90vw;">
|
||||
<h6 class="font-display" style="font-weight:700;margin-bottom:0.5rem;color:#ef4444;">
|
||||
<i class="bi bi-exclamation-triangle-fill"></i> Drop Table
|
||||
</h6>
|
||||
<p style="font-size:0.8rem;color:#374151;margin-bottom:1rem;">
|
||||
Are you sure you want to drop <strong>{{ tableName }}</strong>? This action is <strong>irreversible</strong> and will delete all data.
|
||||
</p>
|
||||
<div class="d-flex gap-2 justify-content-end">
|
||||
<button class="btn-jormun-outline" @click="showDrop=false">Cancel</button>
|
||||
<form method="POST" action="{{ path('table_drop', {name: tableName}) }}">
|
||||
<button type="submit" class="btn-jormun" style="background:#ef4444;">
|
||||
<i class="bi bi-trash3-fill"></i> Drop Table
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -216,25 +218,25 @@
|
||||
{% block scripts %}
|
||||
<script>
|
||||
function browseTable() {
|
||||
return {
|
||||
deleteModal: false,
|
||||
deleteKey: null,
|
||||
deleteAction: '',
|
||||
return {
|
||||
deleteModal: false,
|
||||
deleteKey: null,
|
||||
deleteAction: '',
|
||||
|
||||
confirmDelete(keyJson) {
|
||||
this.deleteKey = JSON.parse(keyJson);
|
||||
this.deleteAction = '{{ path('table_item_delete', {name: tableName}) }}';
|
||||
this.deleteModal = true;
|
||||
}
|
||||
};
|
||||
confirmDelete(keyJson) {
|
||||
this.deleteKey = JSON.parse(keyJson);
|
||||
this.deleteAction = '{{ path('table_item_delete', {name: tableName}) }}';
|
||||
this.deleteModal = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function changeLimit(val) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('limit', val);
|
||||
url.searchParams.delete('lastKey');
|
||||
url.searchParams.delete('prevKeys');
|
||||
window.location.href = url.toString();
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('limit', val);
|
||||
url.searchParams.delete('lastKey');
|
||||
url.searchParams.delete('prevKeys');
|
||||
window.location.href = url.toString();
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('itemForm', () => ({
|
||||
jsonText: JSON.stringify({{ item ? item|json_encode|raw : '{}' }}, null, 2),
|
||||
jsonText: JSON.stringify(JSON.parse({{ (item is not empty) ? item|json_encode : '{}' }}), null, 2),
|
||||
jsonError: '',
|
||||
validateJson() {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user