mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-08 08:01:05 -05:00
Add expandable usage table with show more button
This commit is contained in:
@@ -23,6 +23,8 @@ let usageTableSortState = {
|
||||
direction: 'desc' // default descending (highest cost first)
|
||||
};
|
||||
let usageTableData = []; // Store raw data for sorting
|
||||
let usageTableExpanded = false; // Track if table is showing all rows
|
||||
const USAGE_TABLE_INITIAL_ROWS = 10;
|
||||
|
||||
const TabUsage = {
|
||||
id: 'usage',
|
||||
@@ -60,11 +62,8 @@ const TabUsage = {
|
||||
<span class="usage-progbar-percent"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="driver-usage-details" style="margin-top: 5px; font-size: 13px; cursor: pointer;">
|
||||
<div class="caret"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-right-fill" viewBox="0 0 16 16"><path d="m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z"/></svg></div>
|
||||
<span class="driver-usage-details-text disable-user-select">View usage details</span>
|
||||
</div>
|
||||
<div class="driver-usage-details-content hide-scrollbar" style="display: none;">
|
||||
<h3 style="margin:15px 0 10px 0; font-size: 14px; font-weight: 500;">Usage Details</h3>
|
||||
<div class="driver-usage-details-content visible">
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
@@ -75,20 +74,6 @@ const TabUsage = {
|
||||
update_usage_details($el_window);
|
||||
});
|
||||
|
||||
// Scoped click handler for usage details toggle
|
||||
$($el_window).on('click', '.driver-usage-details', function () {
|
||||
const $container = $(this).closest('.driver-usage');
|
||||
$container.find('.driver-usage-details-content').toggleClass('active');
|
||||
$(this).toggleClass('active');
|
||||
|
||||
// change the text of the driver-usage-details-text depending on the class
|
||||
if ( $(this).hasClass('active') ) {
|
||||
$(this).find('.driver-usage-details-text').text('Hide usage details');
|
||||
} else {
|
||||
$(this).find('.driver-usage-details-text').text('View usage details');
|
||||
}
|
||||
});
|
||||
|
||||
// Click handler for sortable table headers
|
||||
$($el_window).on('click', '.driver-usage-details-content-table th[data-sort]', function () {
|
||||
const column = $(this).data('sort');
|
||||
@@ -103,6 +88,12 @@ const TabUsage = {
|
||||
|
||||
renderUsageTable();
|
||||
});
|
||||
|
||||
// Click handler for "Show more" to expand the table
|
||||
$($el_window).on('click', '.usage-table-show-more', function () {
|
||||
usageTableExpanded = true;
|
||||
renderUsageTable();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -156,8 +147,17 @@ function renderUsageTable() {
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Determine how many rows to show
|
||||
const hasMoreRows = sortedData.length > USAGE_TABLE_INITIAL_ROWS;
|
||||
const rowsToShow = usageTableExpanded ? sortedData : sortedData.slice(0, USAGE_TABLE_INITIAL_ROWS);
|
||||
const hiddenRowCount = sortedData.length - USAGE_TABLE_INITIAL_ROWS;
|
||||
|
||||
// Build the wrapper with potential collapsed state
|
||||
const isCollapsed = hasMoreRows && !usageTableExpanded;
|
||||
let h = `<div class="usage-table-wrapper${isCollapsed ? ' collapsed' : ''}">`;
|
||||
|
||||
// Build the table
|
||||
let h = '<table class="driver-usage-details-content-table">';
|
||||
h += '<table class="driver-usage-details-content-table">';
|
||||
|
||||
h += `<thead>
|
||||
<tr>
|
||||
@@ -168,7 +168,7 @@ function renderUsageTable() {
|
||||
</thead>`;
|
||||
|
||||
h += '<tbody>';
|
||||
for ( const row of sortedData ) {
|
||||
for ( const row of rowsToShow ) {
|
||||
h += `
|
||||
<tr>
|
||||
<td>${row.resource}</td>
|
||||
@@ -179,10 +179,22 @@ function renderUsageTable() {
|
||||
h += '</tbody>';
|
||||
h += '</table>';
|
||||
|
||||
// Add "Show more" overlay if there are hidden rows
|
||||
if ( isCollapsed ) {
|
||||
h += `<div class="usage-table-fade-overlay">
|
||||
<button class="usage-table-show-more">Show ${hiddenRowCount} more</button>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
h += '</div>';
|
||||
|
||||
$('.driver-usage-details-content').html(h);
|
||||
}
|
||||
|
||||
async function update_usage_details ($el_window) {
|
||||
// Reset expanded state on refresh
|
||||
usageTableExpanded = false;
|
||||
|
||||
// Add spinning animation and record start time
|
||||
const startTime = Date.now();
|
||||
$($el_window).find('.update-usage-details-icon').css('animation', 'spin 1s linear infinite');
|
||||
|
||||
@@ -34,8 +34,8 @@ import TabUsage from './TabUsage.js';
|
||||
// Registry of all available tabs
|
||||
const tabs = [
|
||||
TabHome,
|
||||
TabApps,
|
||||
TabFiles,
|
||||
// TabApps,
|
||||
// TabFiles,
|
||||
TabUsage,
|
||||
];
|
||||
|
||||
|
||||
+55
-30
@@ -4585,56 +4585,81 @@ fieldset[name=number-code] {
|
||||
flex-direction: column;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.driver-usage-details-text{
|
||||
cursor: pointer !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
.driver-usage-details-content {
|
||||
display: none;
|
||||
margin-top: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.driver-usage-details-content.active {
|
||||
display: block !important;
|
||||
flex-grow: 1;
|
||||
overflow-y: scroll;
|
||||
.driver-usage-details-content.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.driver-usage-details{
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 25px;
|
||||
/* Usage table wrapper for collapsed/expanded states */
|
||||
.usage-table-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.driver-usage-details .caret {
|
||||
transition: transform 0.1s ease-in-out;
|
||||
margin-right: 3px;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
.usage-table-wrapper.collapsed {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Fade overlay with gradient */
|
||||
.usage-table-fade-overlay {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100px;
|
||||
background: linear-gradient(to bottom,
|
||||
rgba(255, 255, 255, 0) 0%,
|
||||
rgba(255, 255, 255, 0.85) 40%,
|
||||
rgba(255, 255, 255, 1) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
opacity: 0.6;
|
||||
margin-left: -3px;
|
||||
padding-bottom: 12px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.driver-usage-details .caret svg{
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
/* Dark theme support for fade overlay */
|
||||
html.dark-mode .usage-table-fade-overlay {
|
||||
background: linear-gradient(to bottom,
|
||||
rgba(31, 31, 31, 0) 0%,
|
||||
rgba(31, 31, 31, 0.85) 40%,
|
||||
rgba(31, 31, 31, 1) 100%);
|
||||
}
|
||||
|
||||
.driver-usage-details.active .caret {
|
||||
transform: rotate(90deg);
|
||||
margin-top: -2px;
|
||||
/* Show more button */
|
||||
.usage-table-show-more {
|
||||
pointer-events: auto;
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 20px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease, transform 0.1s ease;
|
||||
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.usage-table-show-more:hover {
|
||||
background: #2563eb;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.usage-table-show-more:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
|
||||
.driver-usage-details-content-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.usage-table-wrapper:not(.collapsed) .driver-usage-details-content-table {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user