Merge "de-angularize the Key Pairs table"
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
|
||||
from urllib import parse
|
||||
|
||||
from django.template.loader import render_to_string
|
||||
from django import urls
|
||||
from django.utils.text import format_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -117,8 +118,54 @@ class KeypairsFilterAction(tables.FilterAction):
|
||||
if query in keypair.name.lower()]
|
||||
|
||||
|
||||
def get_chevron_id(table, datum):
|
||||
"""Generate a unique chevron ID for expandable key pair rows.
|
||||
|
||||
This function ensures consistent ID generation between the chevron toggle
|
||||
column and the expandable detail row. The ID is based on the table name
|
||||
and the unique object identifier for the datum.
|
||||
|
||||
Args:
|
||||
table: The DataTable instance (provides table.name and get_object_id())
|
||||
datum: The key pair object (passed to get_object_id())
|
||||
|
||||
Returns:
|
||||
str: Unique chevron ID "{table_name}_chevron_{object_id}"
|
||||
|
||||
Example:
|
||||
For a keypair named "test1" in the "keypairs" table:
|
||||
Returns "keypairs_chevron_test1"
|
||||
"""
|
||||
object_id = table.get_object_id(datum)
|
||||
return "%s_chevron_%s" % (table.name, object_id)
|
||||
|
||||
|
||||
class ExpandableKeyPairRow(tables.Row):
|
||||
"""Custom row class for expandable key pair rows."""
|
||||
|
||||
def render(self):
|
||||
chevron_id = get_chevron_id(self.table, self.datum)
|
||||
return render_to_string("key_pairs/expandable_row.html",
|
||||
{"row": self, "chevron_id": chevron_id})
|
||||
|
||||
|
||||
class ExpandableKeyPairColumn(tables.Column):
|
||||
"""Column that renders a chevron toggle for expandable rows."""
|
||||
|
||||
def get_data(self, datum):
|
||||
chevron_id = get_chevron_id(self.table, datum)
|
||||
return render_to_string(
|
||||
"key_pairs/_chevron_column.html",
|
||||
{"chevron_id": chevron_id}
|
||||
)
|
||||
|
||||
|
||||
class KeyPairsTable(tables.DataTable):
|
||||
detail_link = "horizon:project:key_pairs:detail"
|
||||
chevron = ExpandableKeyPairColumn("chevron",
|
||||
verbose_name="",
|
||||
sortable=False,
|
||||
classes=['chevron_column'])
|
||||
name = tables.Column("name", verbose_name=_("Key Pair Name"),
|
||||
link=detail_link)
|
||||
key_type = tables.Column("type", verbose_name=_("Key Pair Type"))
|
||||
@@ -130,6 +177,8 @@ class KeyPairsTable(tables.DataTable):
|
||||
class Meta(object):
|
||||
name = "keypairs"
|
||||
verbose_name = _("Key Pairs")
|
||||
row_class = ExpandableKeyPairRow
|
||||
template = 'key_pairs/_keypairs_table.html'
|
||||
table_actions = (CreateLinkNG, ImportKeyPair, DeleteKeyPairs,
|
||||
KeypairsFilterAction,)
|
||||
row_actions = (DeleteKeyPairs,)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{% load i18n %}
|
||||
<a role="button"
|
||||
class="chevron-toggle collapsed"
|
||||
data-toggle="collapse"
|
||||
data-target="#{{ chevron_id }}"
|
||||
aria-expanded="false"
|
||||
aria-controls="{{ chevron_id }}"
|
||||
aria-label="{% trans 'Toggle key pair details' %}">
|
||||
<span class="fa fa-chevron-right"></span>
|
||||
</a>
|
||||
@@ -0,0 +1,61 @@
|
||||
{# Include the original data table template #}
|
||||
{% include "horizon/common/_data_table.html" %}
|
||||
|
||||
{# Add custom CSS for key pair chevron functionality #}
|
||||
<style>
|
||||
/* 5 columns total (Chevron, Name, Type, Fingerprint, Actions) */
|
||||
|
||||
/* Force first TWO columns (Chevron, Name) to shrink to content using 1% trick */
|
||||
table#keypairs th:nth-child(1),
|
||||
table#keypairs td:nth-child(1),
|
||||
table#keypairs th:nth-child(2),
|
||||
table#keypairs td:nth-child(2) {
|
||||
width: 1%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Type column - moderate space */
|
||||
table#keypairs th:nth-child(3),
|
||||
table#keypairs td:nth-child(3) {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
/* Fingerprint column - flexible space */
|
||||
table#keypairs th:nth-child(4),
|
||||
table#keypairs td:nth-child(4) {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
/* Actions column - remaining space */
|
||||
table#keypairs th:nth-child(5),
|
||||
table#keypairs td:nth-child(5) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Chevron rotation for key pair expandable rows
|
||||
Uses Bootstrap's automatic .collapsed class management */
|
||||
a.chevron-toggle {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a.chevron-toggle>span {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
/* Rotate chevron 90 degrees when row is expanded (not collapsed) */
|
||||
a.chevron-toggle:not(.collapsed)>span {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* Remove padding from detail row cells to eliminate gap when collapsed */
|
||||
.table>tbody>tr.keypair-detail-row>td {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
margin-top: -1px; /* Get rid of the double horizontal line when collapsed */
|
||||
}
|
||||
|
||||
/* Add margin inner content when expanded */
|
||||
.table>tbody>tr.keypair-detail-row>td div.keypair-details {
|
||||
margin: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,26 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% include "horizon/common/_data_table_row.html" %}
|
||||
{# Detail row - shows key pair information #}
|
||||
<tr class="keypair-detail-row">
|
||||
<td colspan="{{ row.cells|length }}">
|
||||
<div id="{{ chevron_id }}" class="collapse">
|
||||
<div class="keypair-details">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Key Pair Name" %}</dt>
|
||||
<dd>{{ row.datum.name }}</dd>
|
||||
|
||||
<dt>{% trans "Key Pair Type" %}</dt>
|
||||
<dd>{{ row.datum.type|default:"ssh" }}</dd>
|
||||
|
||||
<dt>{% trans "Fingerprint" %}</dt>
|
||||
<dd>{{ row.datum.fingerprint }}</dd>
|
||||
|
||||
<dt>{% trans "Public Key" %}</dt>
|
||||
<dd><pre style="word-break: break-all; white-space: pre-wrap; max-width: 100%; overflow-wrap: break-word;">{{ row.datum.public_key|default:"N/A" }}</pre></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
Reference in New Issue
Block a user