192 lines
8.7 KiB
Twig
192 lines
8.7 KiB
Twig
{% extends 'base.html.twig' %}
|
|
{% import '_sidebar_tables.html.twig' as macros %}
|
|
|
|
{% block title %}{{ tableName }} — Structure · Jormun Admin{% endblock %}
|
|
|
|
{% block breadcrumbs %}
|
|
<a href="{{ path('dashboard') }}"><i class="bi bi-house-fill"></i> Home</a>
|
|
<span class="sep">/</span>
|
|
<a href="{{ path('table_browse', {name: tableName}) }}">{{ tableName }}</a>
|
|
<span class="sep">/</span>
|
|
<span class="current">Structure</span>
|
|
{% endblock %}
|
|
|
|
{% block sidebar_tables %}
|
|
{{ macros.sidebar_table_links(tables, tableName) }}
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<nav class="op-tabs">
|
|
<a href="{{ path('table_browse', {name: tableName}) }}" class="op-tab">
|
|
<i class="bi bi-grid-3x3-gap"></i> Browse
|
|
</a>
|
|
<a href="{{ path('table_structure', {name: tableName}) }}" class="op-tab active">
|
|
<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>
|
|
</nav>
|
|
|
|
{% 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 }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if desc %}
|
|
|
|
<div class="row g-3">
|
|
{# Table info #}
|
|
<div class="col-12 col-md-6">
|
|
<div class="content-card h-100">
|
|
<div class="content-card-header">
|
|
<h6><i class="bi bi-info-circle me-1" style="color:var(--jormun-teal);"></i> Table Info</h6>
|
|
</div>
|
|
<div style="padding:0.75rem 1rem;">
|
|
<table class="data-table">
|
|
<tr><td style="color:#64748b;width:40%;">Name</td><td><strong>{{ desc.TableName }}</strong></td></tr>
|
|
<tr><td style="color:#64748b;">Status</td><td><span class="status-badge {{ desc.TableStatus|lower }}">{{ desc.TableStatus }}</span></td></tr>
|
|
<tr><td style="color:#64748b;">Item Count</td><td>{{ (desc.ItemCount ?? 0)|number_format }}</td></tr>
|
|
<tr>
|
|
<td style="color:#64748b;">Size</td>
|
|
<td>
|
|
{% set bytes = desc.TableSizeBytes ?? 0 %}
|
|
{% if bytes >= 1048576 %}{{ (bytes / 1048576)|number_format(2) }} MB
|
|
{% elseif bytes >= 1024 %}{{ (bytes / 1024)|number_format(2) }} KB
|
|
{% else %}{{ bytes }} B{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr><td style="color:#64748b;">Billing Mode</td><td>{{ desc.BillingModeSummary.BillingMode ?? 'PROVISIONED' }}</td></tr>
|
|
{% if desc.CreationDateTime is defined %}
|
|
<tr><td style="color:#64748b;">Created</td><td>{{ desc.CreationDateTime|date('Y-m-d H:i:s') }}</td></tr>
|
|
{% endif %}
|
|
<tr><td style="color:#64748b;">Table ARN</td><td style="font-size:0.68rem;word-break:break-all;">{{ desc.TableArn ?? '—' }}</td></tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{# Key Schema #}
|
|
<div class="col-12 col-md-6">
|
|
<div class="content-card h-100">
|
|
<div class="content-card-header">
|
|
<h6><i class="bi bi-key me-1" style="color:var(--jormun-teal);"></i> Key Schema</h6>
|
|
</div>
|
|
<div style="padding:0.75rem 1rem;">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Attribute</th>
|
|
<th>Key Type</th>
|
|
<th>Data Type</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for key in desc.KeySchema %}
|
|
{% set attrType = 'S' %}
|
|
{% for attr in desc.AttributeDefinitions %}
|
|
{% if attr.AttributeName == key.AttributeName %}
|
|
{% set attrType = attr.AttributeType %}
|
|
{% endif %}
|
|
{% endfor %}
|
|
<tr>
|
|
<td class="pk-cell">{{ key.AttributeName }}</td>
|
|
<td>
|
|
<span class="status-badge {{ key.KeyType == 'HASH' ? 'active' : 'creating' }}">
|
|
{{ key.KeyType == 'HASH' ? 'Partition Key' : 'Sort Key' }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<span class="type-badge">
|
|
{% if attrType == 'S' %}String (S)
|
|
{% elseif attrType == 'N' %}Number (N)
|
|
{% elseif attrType == 'B' %}Binary (B)
|
|
{% else %}{{ attrType }}{% endif %}
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{# Secondary Indexes #}
|
|
{% if desc.GlobalSecondaryIndexes is defined and desc.GlobalSecondaryIndexes|length > 0 %}
|
|
<div class="col-12">
|
|
<div class="content-card">
|
|
<div class="content-card-header">
|
|
<h6><i class="bi bi-diagram-2 me-1" style="color:var(--jormun-teal);"></i> Global Secondary Indexes</h6>
|
|
</div>
|
|
<div style="overflow-x:auto;">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Index Name</th>
|
|
<th>Status</th>
|
|
<th>Partition Key</th>
|
|
<th>Sort Key</th>
|
|
<th>Projection</th>
|
|
<th>Item Count</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for gsi in desc.GlobalSecondaryIndexes %}
|
|
{% set gsiPk = null %}{% set gsiSk = null %}
|
|
{% for k in gsi.KeySchema %}
|
|
{% if k.KeyType == 'HASH' %}{% set gsiPk = k.AttributeName %}{% endif %}
|
|
{% if k.KeyType == 'RANGE' %}{% set gsiSk = k.AttributeName %}{% endif %}
|
|
{% endfor %}
|
|
<tr>
|
|
<td class="pk-cell">{{ gsi.IndexName }}</td>
|
|
<td><span class="status-badge {{ (gsi.IndexStatus ?? 'ACTIVE')|lower }}">{{ gsi.IndexStatus ?? 'ACTIVE' }}</span></td>
|
|
<td><span class="type-badge">{{ gsiPk }}</span></td>
|
|
<td>{% if gsiSk %}<span class="type-badge">{{ gsiSk }}</span>{% else %}<span class="null-val">none</span>{% endif %}</td>
|
|
<td>{{ gsi.Projection.ProjectionType ?? '—' }}</td>
|
|
<td>{{ (gsi.ItemCount ?? 0)|number_format }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if desc.LocalSecondaryIndexes is defined and desc.LocalSecondaryIndexes|length > 0 %}
|
|
<div class="col-12">
|
|
<div class="content-card">
|
|
<div class="content-card-header">
|
|
<h6><i class="bi bi-diagram-2 me-1" style="color:var(--jormun-teal);"></i> Local Secondary Indexes</h6>
|
|
</div>
|
|
<div style="overflow-x:auto;">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr><th>Index Name</th><th>Sort Key</th><th>Projection</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for lsi in desc.LocalSecondaryIndexes %}
|
|
{% set lsiSk = null %}
|
|
{% for k in lsi.KeySchema %}{% if k.KeyType == 'RANGE' %}{% set lsiSk = k.AttributeName %}{% endif %}{% endfor %}
|
|
<tr>
|
|
<td class="pk-cell">{{ lsi.IndexName }}</td>
|
|
<td><span class="type-badge">{{ lsiSk ?? '—' }}</span></td>
|
|
<td>{{ lsi.Projection.ProjectionType ?? '—' }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% endif %}
|
|
{% endblock %}
|