Merge pull request #338 from nahuhh/amm_table

amm: icon beside amount & consistent size of add/edit
This commit is contained in:
Gerlof van Ek
2025-07-23 23:54:09 +02:00
committed by GitHub
9 changed files with 66 additions and 69 deletions

View File

@@ -122,13 +122,13 @@ const AmmTablesManager = (function() {
<td class="py-0 px-0 text-right text-sm"> <td class="py-0 px-0 text-right text-sm">
<div class="flex items-center justify-center monospace"> <div class="flex items-center justify-center monospace">
<span class="inline-flex mr-3 ml-3 align-middle items-center justify-center w-18 h-20 rounded"> <span class="inline-flex mr-3 ml-3 align-middle items-center justify-center w-18 h-20 rounded">
<img class="h-12" src="/static/images/coins/${fromImage}" alt="${fromDisplayName}"> <img class="h-12" src="/static/images/coins/${toImage}" alt="${toDisplayName}">
</span> </span>
<svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd"></path> <path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd"></path>
</svg> </svg>
<span class="inline-flex mr-3 ml-3 align-middle items-center justify-center w-18 h-20 rounded"> <span class="inline-flex mr-3 ml-3 align-middle items-center justify-center w-18 h-20 rounded">
<img class="h-12" src="/static/images/coins/${toImage}" alt="${toDisplayName}"> <img class="h-12" src="/static/images/coins/${fromImage}" alt="${fromDisplayName}">
</span> </span>
</div> </div>
</td> </td>

View File

@@ -147,7 +147,7 @@ window.cleanup = function() {
if (exportAllButton && typeof EventManager !== 'undefined') { if (exportAllButton && typeof EventManager !== 'undefined') {
EventManager.remove(exportAllButton, 'click'); EventManager.remove(exportAllButton, 'click');
} }
if (exportSentButton && typeof EventManager !== 'undefined') { if (exportSentButton && typeof EventManager !== 'undefined') {
EventManager.remove(exportSentButton, 'click'); EventManager.remove(exportSentButton, 'click');
} }

View File

@@ -264,9 +264,9 @@ const ApiManager = (function() {
window.config.coins window.config.coins
.filter(coin => coin.usesCoinGecko) .filter(coin => coin.usesCoinGecko)
.map(coin => { .map(coin => {
return window.config.getCoinBackendId ? return window.config.getCoinBackendId ?
window.config.getCoinBackendId(coin.name) : window.config.getCoinBackendId(coin.name) :
(typeof getCoinBackendId === 'function' ? (typeof getCoinBackendId === 'function' ?
getCoinBackendId(coin.name) : coin.name.toLowerCase()); getCoinBackendId(coin.name) : coin.name.toLowerCase());
}) })
.join(',') : .join(',') :
@@ -277,7 +277,7 @@ const ApiManager = (function() {
} }
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coinList}&vs_currencies=usd&include_24hr_vol=true&include_24hr_change=true`; const url = `https://api.coingecko.com/api/v3/simple/price?ids=${coinList}&vs_currencies=usd&include_24hr_vol=true&include_24hr_change=true`;
const response = await this.makePostRequest(url, { const response = await this.makePostRequest(url, {
'User-Agent': 'Mozilla/5.0', 'User-Agent': 'Mozilla/5.0',
'Accept': 'application/json' 'Accept': 'application/json'
@@ -288,7 +288,7 @@ const ApiManager = (function() {
} }
const volumeData = {}; const volumeData = {};
Object.entries(response).forEach(([coinId, data]) => { Object.entries(response).forEach(([coinId, data]) => {
if (data && data.usd_24h_vol !== undefined) { if (data && data.usd_24h_vol !== undefined) {
volumeData[coinId] = { volumeData[coinId] = {

View File

@@ -288,11 +288,11 @@ const CleanupManager = (function() {
} }
} }
document.dispatchEvent(new CustomEvent('memoryOptimized', { document.dispatchEvent(new CustomEvent('memoryOptimized', {
detail: { detail: {
timestamp: Date.now(), timestamp: Date.now(),
maxDataSize: options.maxDataSize || 1000 maxDataSize: options.maxDataSize || 1000
} }
})); }));
log('Memory optimization complete'); log('Memory optimization complete');
@@ -311,11 +311,11 @@ const CleanupManager = (function() {
try { try {
const isDetached = !(listener.element instanceof Node) || const isDetached = !(listener.element instanceof Node) ||
!document.body.contains(listener.element) || !document.body.contains(listener.element) ||
(listener.element.classList && listener.element.classList.contains('hidden')) || (listener.element.classList && listener.element.classList.contains('hidden')) ||
(listener.element.style && listener.element.style.display === 'none'); (listener.element.style && listener.element.style.display === 'none');
if (isDetached) { if (isDetached) {
try { try {
if (listener.element instanceof Node) { if (listener.element instanceof Node) {
@@ -362,12 +362,12 @@ const CleanupManager = (function() {
log(`Error checking resource ${id}: ${e.message}`); log(`Error checking resource ${id}: ${e.message}`);
} }
}); });
resourcesForRemoval.forEach(id => { resourcesForRemoval.forEach(id => {
this.unregisterResource(id); this.unregisterResource(id);
removedResources++; removedResources++;
}); });
if (removedResources > 0) { if (removedResources > 0) {
log(`Removed ${removedResources} orphaned resources`); log(`Removed ${removedResources} orphaned resources`);
} }
@@ -408,22 +408,22 @@ const CleanupManager = (function() {
try { try {
const tooltipSelectors = [ const tooltipSelectors = [
'[role="tooltip"]', '[role="tooltip"]',
'[id^="tooltip-"]', '[id^="tooltip-"]',
'.tippy-box', '.tippy-box',
'[data-tippy-root]' '[data-tippy-root]'
]; ];
tooltipSelectors.forEach(selector => { tooltipSelectors.forEach(selector => {
try { try {
const elements = document.querySelectorAll(selector); const elements = document.querySelectorAll(selector);
elements.forEach(element => { elements.forEach(element => {
try { try {
if (!(element instanceof Element)) return; if (!(element instanceof Element)) return;
const isDetached = !element.parentElement || const isDetached = !element.parentElement ||
!document.body.contains(element.parentElement) || !document.body.contains(element.parentElement) ||
element.classList.contains('hidden') || element.classList.contains('hidden') ||
element.style.display === 'none' || element.style.display === 'none' ||

View File

@@ -11,15 +11,15 @@ const MemoryManager = (function() {
debug: false, debug: false,
protectedWebSockets: ['wsPort', 'ws_port'], protectedWebSockets: ['wsPort', 'ws_port'],
interactiveSelectors: [ interactiveSelectors: [
'tr:hover', 'tr:hover',
'[data-tippy-root]:hover', '[data-tippy-root]:hover',
'.tooltip:hover', '.tooltip:hover',
'[data-tooltip-trigger-id]:hover', '[data-tooltip-trigger-id]:hover',
'[data-tooltip-target]:hover' '[data-tooltip-target]:hover'
], ],
protectedContainers: [ protectedContainers: [
'#sent-tbody', '#sent-tbody',
'#received-tbody', '#received-tbody',
'#offers-body' '#offers-body'
] ]
}; };
@@ -74,10 +74,10 @@ const MemoryManager = (function() {
function shouldSkipCleanup() { function shouldSkipCleanup() {
if (state.isCleanupRunning) return true; if (state.isCleanupRunning) return true;
const selector = config.interactiveSelectors.join(', '); const selector = config.interactiveSelectors.join(', ');
const hoveredElements = document.querySelectorAll(selector); const hoveredElements = document.querySelectorAll(selector);
return hoveredElements.length > 0; return hoveredElements.length > 0;
} }
@@ -130,7 +130,7 @@ const MemoryManager = (function() {
disconnectedRemoved: disconnectedResult, disconnectedRemoved: disconnectedResult,
memoryBefore: startMemory ? startMemory.usedMB : null, memoryBefore: startMemory ? startMemory.usedMB : null,
memoryAfter: endMemory ? endMemory.usedMB : null, memoryAfter: endMemory ? endMemory.usedMB : null,
memorySaved: startMemory && endMemory ? memorySaved: startMemory && endMemory ?
(startMemory.usedMB - endMemory.usedMB).toFixed(2) : null (startMemory.usedMB - endMemory.usedMB).toFixed(2) : null
}; };
@@ -162,7 +162,7 @@ const MemoryManager = (function() {
tippyRoots.forEach(root => { tippyRoots.forEach(root => {
const tooltipId = root.getAttribute('data-for-tooltip-id'); const tooltipId = root.getAttribute('data-for-tooltip-id');
const trigger = tooltipId ? const trigger = tooltipId ?
document.querySelector(`[data-tooltip-trigger-id="${tooltipId}"]`) : null; document.querySelector(`[data-tooltip-trigger-id="${tooltipId}"]`) : null;
if (!trigger || !document.body.contains(trigger)) { if (!trigger || !document.body.contains(trigger)) {
@@ -228,7 +228,7 @@ const MemoryManager = (function() {
return true; return true;
} }
function checkMemoryUsage() { function checkMemoryUsage() {
const result = { const result = {
usedJSHeapSize: 0, usedJSHeapSize: 0,
@@ -288,7 +288,7 @@ const MemoryManager = (function() {
setTimeout(() => { setTimeout(() => {
processingScheduled = false; processingScheduled = false;
lastProcessTime = Date.now(); lastProcessTime = Date.now();
if (state.isCleanupRunning) { if (state.isCleanupRunning) {
return; return;
} }
@@ -298,7 +298,7 @@ const MemoryManager = (function() {
tooltipCount = document.querySelectorAll(tooltipSelectors.join(', ')).length; tooltipCount = document.querySelectorAll(tooltipSelectors.join(', ')).length;
if (tooltipCount > config.maxTooltipsThreshold && if (tooltipCount > config.maxTooltipsThreshold &&
(Date.now() - state.lastCleanupTime > config.minTimeBetweenCleanups)) { (Date.now() - state.lastCleanupTime > config.minTimeBetweenCleanups)) {
removeOrphanedTooltips(); removeOrphanedTooltips();
@@ -429,7 +429,7 @@ const MemoryManager = (function() {
return true; return true;
} }
function initialize(options = {}) { function initialize(options = {}) {
preserveTooltipFunctions(); preserveTooltipFunctions();
@@ -492,8 +492,8 @@ const MemoryManager = (function() {
const stats = getDetailedStats(); const stats = getDetailedStats();
console.group('Memory Manager Stats'); console.group('Memory Manager Stats');
console.log('Memory Usage:', stats.memory ? console.log('Memory Usage:', stats.memory ?
`${stats.memory.usedMB}MB / ${stats.memory.limitMB}MB (${stats.memory.percentUsed}%)` : `${stats.memory.usedMB}MB / ${stats.memory.limitMB}MB (${stats.memory.percentUsed}%)` :
'Not available'); 'Not available');
console.log('Total Cleanups:', stats.metrics.cleanupRuns); console.log('Total Cleanups:', stats.metrics.cleanupRuns);
console.log('Total Tooltips Removed:', stats.metrics.tooltipsRemoved); console.log('Total Tooltips Removed:', stats.metrics.tooltipsRemoved);
@@ -569,7 +569,7 @@ const MemoryManager = (function() {
})(); })();
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const isDevMode = window.location.hostname === 'localhost' || const isDevMode = window.location.hostname === 'localhost' ||
window.location.hostname === '127.0.0.1'; window.location.hostname === '127.0.0.1';
MemoryManager.initialize({ MemoryManager.initialize({

View File

@@ -185,7 +185,7 @@ const TooltipManager = (function() {
} }
} }
); );
return tippyInstance[0]; return tippyInstance[0];
} }
@@ -248,7 +248,7 @@ const TooltipManager = (function() {
this.log('Running tooltip cleanup'); this.log('Running tooltip cleanup');
try { try {
if ((window.location.pathname.includes('/offers') || window.location.pathname.includes('/bids')) && if ((window.location.pathname.includes('/offers') || window.location.pathname.includes('/bids')) &&
(document.querySelector('[data-tippy-root]:hover') || document.querySelector('[data-tooltip-trigger-id]:hover'))) { (document.querySelector('[data-tippy-root]:hover') || document.querySelector('[data-tooltip-trigger-id]:hover'))) {
console.log('Skipping tooltip cleanup - tooltip is being hovered'); console.log('Skipping tooltip cleanup - tooltip is being hovered');
return; return;
@@ -299,7 +299,7 @@ const TooltipManager = (function() {
this.log('Cleaning up all tooltips'); this.log('Cleaning up all tooltips');
try { try {
if ((window.location.pathname.includes('/offers') || window.location.pathname.includes('/bids')) && if ((window.location.pathname.includes('/offers') || window.location.pathname.includes('/bids')) &&
document.querySelector('#offers-body tr:hover')) { document.querySelector('#offers-body tr:hover')) {
this.log('Skipping all tooltips cleanup on offers/bids page with row hover'); this.log('Skipping all tooltips cleanup on offers/bids page with row hover');
return; return;
@@ -328,7 +328,7 @@ const TooltipManager = (function() {
if (!isHovered(trigger)) { if (!isHovered(trigger)) {
trigger.removeAttribute('data-tooltip-trigger-id'); trigger.removeAttribute('data-tooltip-trigger-id');
trigger.removeAttribute('aria-describedby'); trigger.removeAttribute('aria-describedby');
if (trigger._tippy) { if (trigger._tippy) {
try { try {
trigger._tippy.destroy(); trigger._tippy.destroy();
@@ -350,7 +350,7 @@ const TooltipManager = (function() {
if (!closestHoveredRow) { if (!closestHoveredRow) {
const style = window.getComputedStyle(tooltip); const style = window.getComputedStyle(tooltip);
const isVisible = style.display !== 'none' && const isVisible = style.display !== 'none' &&
style.visibility !== 'hidden' && style.visibility !== 'hidden' &&
style.opacity !== '0'; style.opacity !== '0';
@@ -372,8 +372,8 @@ const TooltipManager = (function() {
tippyElements.forEach(element => { tippyElements.forEach(element => {
const tooltipId = element.getAttribute('data-for-tooltip-id'); const tooltipId = element.getAttribute('data-for-tooltip-id');
const trigger = tooltipId ? const trigger = tooltipId ?
document.querySelector(`[data-tooltip-trigger-id="${tooltipId}"]`) : document.querySelector(`[data-tooltip-trigger-id="${tooltipId}"]`) :
null; null;
if (!trigger || !document.body.contains(trigger)) { if (!trigger || !document.body.contains(trigger)) {
@@ -489,7 +489,7 @@ const TooltipManager = (function() {
performPeriodicCleanup(force = false) { performPeriodicCleanup(force = false) {
try { try {
if ((window.location.pathname.includes('/offers') || window.location.pathname.includes('/bids')) && if ((window.location.pathname.includes('/offers') || window.location.pathname.includes('/bids')) &&
!force) { !force) {
return; return;
} }
@@ -829,7 +829,7 @@ const TooltipManager = (function() {
const manager = this.getInstance(); const manager = this.getInstance();
return manager.initializeTooltips(...args); return manager.initializeTooltips(...args);
}, },
setDebugMode: function(enabled) { setDebugMode: function(enabled) {
const manager = this.getInstance(); const manager = this.getInstance();
return manager.setDebugMode(enabled); return manager.setDebugMode(enabled);

View File

@@ -332,10 +332,10 @@ const ui = {
if (data.price_btc !== undefined && data.price_btc !== null) { if (data.price_btc !== undefined && data.price_btc !== null) {
priceBTC = data.price_btc; priceBTC = data.price_btc;
} }
else if (window.btcPriceUSD && window.btcPriceUSD > 0) { else if (window.btcPriceUSD && window.btcPriceUSD > 0) {
priceBTC = priceUSD / window.btcPriceUSD; priceBTC = priceUSD / window.btcPriceUSD;
} }
else if (app && app.btcPriceUSD && app.btcPriceUSD > 0) { else if (app && app.btcPriceUSD && app.btcPriceUSD > 0) {
priceBTC = priceUSD / app.btcPriceUSD; priceBTC = priceUSD / app.btcPriceUSD;
} }
@@ -343,7 +343,7 @@ const ui = {
priceBTC = 0; priceBTC = 0;
} }
} }
priceChange1d = data.price_change_percentage_24h || 0; priceChange1d = data.price_change_percentage_24h || 0;
volume24h = data.total_volume || 0; volume24h = data.total_volume || 0;
if (isNaN(priceUSD) || isNaN(priceBTC)) { if (isNaN(priceUSD) || isNaN(priceBTC)) {

View File

@@ -16,7 +16,7 @@
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
initBidsTabNavigation(); initBidsTabNavigation();
}); });
window.addEventListener('hashchange', handleHashChange); window.addEventListener('hashchange', handleHashChange);
window.bidsTabNavigationInitialized = false; window.bidsTabNavigationInitialized = false;
@@ -52,7 +52,7 @@
} }
const tabToActivate = localStorage.getItem('bidsTabToActivate'); const tabToActivate = localStorage.getItem('bidsTabToActivate');
if (tabToActivate) { if (tabToActivate) {
localStorage.removeItem('bidsTabToActivate'); localStorage.removeItem('bidsTabToActivate');
@@ -70,7 +70,7 @@
if (window.location.pathname !== '/bids') { if (window.location.pathname !== '/bids') {
return; return;
} }
const hash = window.location.hash; const hash = window.location.hash;
if (hash) { if (hash) {
@@ -90,22 +90,20 @@
return; return;
} }
const tabButtonId = normalizedTabId === '#all' ? 'all-tab' : const tabButtonId = normalizedTabId === '#all' ? 'all-tab' :
(normalizedTabId === '#sent' ? 'sent-tab' : 'received-tab'); (normalizedTabId === '#sent' ? 'sent-tab' : 'received-tab');
const tabButton = document.getElementById(tabButtonId); const tabButton = document.getElementById(tabButtonId);
if (!tabButton) { if (!tabButton) {
if (retryCount < 5) { if (retryCount < 5) {
setTimeout(() => { setTimeout(() => {
activateTabWithRetry(normalizedTabId, retryCount + 1); activateTabWithRetry(normalizedTabId, retryCount + 1);
}, 100); }, 100);
} else {
} }
return; return;
} }
tabButton.click(); tabButton.click();
@@ -115,7 +113,7 @@
if (tabsEl) { if (tabsEl) {
const allTabs = Array.from(tabsEl.querySelectorAll('[role="tab"]')); const allTabs = Array.from(tabsEl.querySelectorAll('[role="tab"]'));
const targetTab = allTabs.find(tab => tab.getAttribute('data-tabs-target') === normalizedTabId); const targetTab = allTabs.find(tab => tab.getAttribute('data-tabs-target') === normalizedTabId);
if (targetTab) { if (targetTab) {
allTabs.forEach(tab => { allTabs.forEach(tab => {
@@ -133,7 +131,7 @@
const allContent = document.getElementById('all'); const allContent = document.getElementById('all');
const sentContent = document.getElementById('sent'); const sentContent = document.getElementById('sent');
const receivedContent = document.getElementById('received'); const receivedContent = document.getElementById('received');
if (allContent && sentContent && receivedContent) { if (allContent && sentContent && receivedContent) {
allContent.classList.toggle('hidden', normalizedTabId !== '#all'); allContent.classList.toggle('hidden', normalizedTabId !== '#all');
sentContent.classList.toggle('hidden', normalizedTabId !== '#sent'); sentContent.classList.toggle('hidden', normalizedTabId !== '#sent');
@@ -146,7 +144,7 @@
const allPanel = document.getElementById('all'); const allPanel = document.getElementById('all');
const sentPanel = document.getElementById('sent'); const sentPanel = document.getElementById('sent');
const receivedPanel = document.getElementById('received'); const receivedPanel = document.getElementById('received');
if (allPanel && sentPanel && receivedPanel) { if (allPanel && sentPanel && receivedPanel) {
allPanel.classList.toggle('hidden', normalizedTabId !== '#all'); allPanel.classList.toggle('hidden', normalizedTabId !== '#all');
sentPanel.classList.toggle('hidden', normalizedTabId !== '#sent'); sentPanel.classList.toggle('hidden', normalizedTabId !== '#sent');
@@ -164,7 +162,7 @@
function triggerDataLoad(tabId) { function triggerDataLoad(tabId) {
setTimeout(() => { setTimeout(() => {
if (window.state) { if (window.state) {
window.state.currentTab = tabId === '#all' ? 'all' : window.state.currentTab = tabId === '#all' ? 'all' :
(tabId === '#sent' ? 'sent' : 'received'); (tabId === '#sent' ? 'sent' : 'received');
if (typeof window.updateBidsTable === 'function') { if (typeof window.updateBidsTable === 'function') {
@@ -174,9 +172,9 @@
} }
const event = new CustomEvent('tabactivated', { const event = new CustomEvent('tabactivated', {
detail: { detail: {
tabId: tabId, tabId: tabId,
type: tabId === '#all' ? 'all' : type: tabId === '#all' ? 'all' :
(tabId === '#sent' ? 'sent' : 'received') (tabId === '#sent' ? 'sent' : 'received')
} }
}); });
@@ -195,9 +193,9 @@
function navigateToTabDirectly(tabId) { function navigateToTabDirectly(tabId) {
const oldScrollPosition = window.scrollY; const oldScrollPosition = window.scrollY;
activateTabWithRetry(tabId); activateTabWithRetry(tabId);
setTimeout(function() { setTimeout(function() {
window.scrollTo(0, oldScrollPosition); window.scrollTo(0, oldScrollPosition);
}, 0); }, 0);

View File

@@ -26,7 +26,6 @@
</div> </div>
</section> </section>
<div class="xl:container mx-auto"> <div class="xl:container mx-auto">
{% include 'inc_messages.html' %} {% include 'inc_messages.html' %}
@@ -1347,7 +1346,7 @@
<div class="absolute inset-0 bg-gray-500 opacity-75 dark:bg-gray-900 dark:opacity-90"></div> <div class="absolute inset-0 bg-gray-500 opacity-75 dark:bg-gray-900 dark:opacity-90"></div>
</div> </div>
<div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg text-left overflow-visible shadow-xl transform transition-all sm:my-8 sm:align-middle lg:max-w-xl md:max-w-2xl md:w-full"> <div class="inline-block align-bottom bg-white dark:bg-gray-800 rounded-lg text-left overflow-visible shadow-xl transform transition-all sm:my-8 sm:align-middle md:max-w-2xl md:w-full">
<div class="bg-white dark:bg-gray-800 px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> <div class="bg-white dark:bg-gray-800 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start"> <div class="sm:flex sm:items-start">
<div class="mt-3 text-center sm:mt-0 sm:text-left w-full"> <div class="mt-3 text-center sm:mt-0 sm:text-left w-full">