Spaces:
Running
Running
feat: make request inspector table headers sortable
Browse files- index.html +23 -4
- style.css +31 -0
index.html
CHANGED
@@ -472,6 +472,8 @@
|
|
472 |
let allRows = []; // Store all fetched rows globally
|
473 |
let currentFilteredRows = []; // Store currently filtered rows
|
474 |
let uniqueModels = [];
|
|
|
|
|
475 |
const rowsPerFetch = 100; // How many rows to fetch per API call
|
476 |
|
477 |
// Plotly layout defaults (same as before)
|
@@ -925,10 +927,27 @@
|
|
925 |
|
926 |
document.getElementById('request-table-title').textContent = `Request Inspector (${rows.length} requests shown)`;
|
927 |
|
928 |
-
// Create Header
|
929 |
-
|
930 |
-
|
931 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
932 |
|
933 |
// Create Body Rows
|
934 |
rows.forEach((row, index) => { // Use index within the *filtered* array
|
|
|
472 |
let allRows = []; // Store all fetched rows globally
|
473 |
let currentFilteredRows = []; // Store currently filtered rows
|
474 |
let uniqueModels = [];
|
475 |
+
let currentSortKey = null; // Track current sort column
|
476 |
+
let currentSortDirection = 'asc'; // Track current sort direction ('asc' or 'desc')
|
477 |
const rowsPerFetch = 100; // How many rows to fetch per API call
|
478 |
|
479 |
// Plotly layout defaults (same as before)
|
|
|
927 |
|
928 |
document.getElementById('request-table-title').textContent = `Request Inspector (${rows.length} requests shown)`;
|
929 |
|
930 |
+
// Create Header (only if it doesn't exist)
|
931 |
+
if (tableHead.rows.length === 0) {
|
932 |
+
const headerRow = tableHead.insertRow();
|
933 |
+
const headers = [
|
934 |
+
{ text: 'Provider', key: 'provider_name', sortable: true },
|
935 |
+
{ text: 'Model', key: 'model_id', sortable: true },
|
936 |
+
{ text: 'Status', key: 'response_status_code', sortable: true },
|
937 |
+
{ text: 'Duration (ms)', key: 'duration_ms', sortable: true },
|
938 |
+
{ text: 'Error', key: 'error_message', sortable: true }, // Sort by presence of error msg
|
939 |
+
{ text: 'Action', key: null, sortable: false }
|
940 |
+
];
|
941 |
+
headers.forEach(header => {
|
942 |
+
const th = document.createElement('th');
|
943 |
+
th.textContent = header.text;
|
944 |
+
if (header.sortable) {
|
945 |
+
th.classList.add('sortable-header');
|
946 |
+
th.dataset.sortKey = header.key;
|
947 |
+
}
|
948 |
+
headerRow.appendChild(th);
|
949 |
+
});
|
950 |
+
}
|
951 |
|
952 |
// Create Body Rows
|
953 |
rows.forEach((row, index) => { // Use index within the *filtered* array
|
style.css
CHANGED
@@ -27,6 +27,37 @@ p {
|
|
27 |
margin-bottom: 0;
|
28 |
}
|
29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
/* Spinner Styles */
|
31 |
#loading {
|
32 |
display: flex;
|
|
|
27 |
margin-bottom: 0;
|
28 |
}
|
29 |
|
30 |
+
/* Sortable Table Header Styles */
|
31 |
+
.sortable-header {
|
32 |
+
cursor: pointer;
|
33 |
+
position: relative; /* Needed for pseudo-element positioning */
|
34 |
+
padding-right: 20px; /* Make space for the arrow */
|
35 |
+
}
|
36 |
+
.sortable-header::after {
|
37 |
+
content: '';
|
38 |
+
position: absolute;
|
39 |
+
right: 8px;
|
40 |
+
top: 50%;
|
41 |
+
transform: translateY(-50%);
|
42 |
+
width: 0;
|
43 |
+
height: 0;
|
44 |
+
border-left: 5px solid transparent;
|
45 |
+
border-right: 5px solid transparent;
|
46 |
+
opacity: 0.4; /* Dim by default */
|
47 |
+
}
|
48 |
+
.sortable-header:hover::after {
|
49 |
+
opacity: 0.7; /* Slightly brighter on hover */
|
50 |
+
}
|
51 |
+
.sortable-header.sort-asc::after {
|
52 |
+
border-bottom: 5px solid var(--text-color); /* Arrow pointing up */
|
53 |
+
opacity: 1;
|
54 |
+
}
|
55 |
+
.sortable-header.sort-desc::after {
|
56 |
+
border-top: 5px solid var(--text-color); /* Arrow pointing down */
|
57 |
+
opacity: 1;
|
58 |
+
}
|
59 |
+
|
60 |
+
|
61 |
/* Spinner Styles */
|
62 |
#loading {
|
63 |
display: flex;
|