112 lines
5.5 KiB
Python
112 lines
5.5 KiB
Python
#!/usr/bin/env python3
|
|
"""V123 - Pinning/favorites for dashboards via URL param (?pin=name1,name2)
|
|
- Zero localStorage (shareable URL, persistent via bookmark)
|
|
- Star button on each tile
|
|
- Pinned tiles render FIRST with gold border
|
|
- Counter shows "N pinned / total"
|
|
"""
|
|
path = "/var/www/html/all-ia-hub.html"
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
c = f.read()
|
|
|
|
if "V123-PINS" in c:
|
|
print("ALREADY")
|
|
exit(0)
|
|
|
|
# Modify renderDashGrid to support pins
|
|
old_render_head = """function renderDashGrid(items, cat){
|
|
/* V117-HTTP-BADGES + V119-SEARCH: search + sort */
|
|
const box = document.getElementById('dash-grid');
|
|
if (!box) return;
|
|
const search = (document.getElementById('dash-search')?.value || '').toLowerCase().trim();
|
|
const sort = document.getElementById('dash-sort')?.value || 'name';
|
|
let filtered = cat === 'all' ? items : items.filter(x => x.category === cat);"""
|
|
|
|
new_render_head = """function renderDashGrid(items, cat){
|
|
/* V117-HTTP-BADGES + V119-SEARCH + V123-PINS */
|
|
const box = document.getElementById('dash-grid');
|
|
if (!box) return;
|
|
const search = (document.getElementById('dash-search')?.value || '').toLowerCase().trim();
|
|
const sort = document.getElementById('dash-sort')?.value || 'name';
|
|
const pinned = __dashPins();
|
|
let filtered = cat === 'all' ? items : items.filter(x => x.category === cat);"""
|
|
if old_render_head in c:
|
|
c = c.replace(old_render_head, new_render_head, 1)
|
|
|
|
# Modify the sorting block to push pinned to front
|
|
old_sort = """ else filtered = filtered.slice().sort((a,b) => a.name.localeCompare(b.name));
|
|
const countEl = document.getElementById('dash-count');
|
|
if (countEl) countEl.textContent = filtered.length + ' / ' + items.length + ' tuiles';"""
|
|
|
|
new_sort = """ else filtered = filtered.slice().sort((a,b) => a.name.localeCompare(b.name));
|
|
// V123-PINS: pinned tiles first, preserving existing sort within each group
|
|
filtered = filtered.slice().sort((a,b) => {
|
|
const ap = pinned.has(a.name) ? 0 : 1;
|
|
const bp = pinned.has(b.name) ? 0 : 1;
|
|
return ap - bp;
|
|
});
|
|
const countEl = document.getElementById('dash-count');
|
|
if (countEl) countEl.textContent = filtered.length + ' / ' + items.length + ' tuiles' + (pinned.size ? ' (' + pinned.size + ' pin' + (pinned.size>1?'s':'') + ')' : '');"""
|
|
|
|
if old_sort in c:
|
|
c = c.replace(old_sort, new_sort, 1)
|
|
|
|
# Modify tile rendering to show pin button + gold border when pinned
|
|
old_tile = """'<div style=\"font-size:9px;color:var(--mu)\">'+e.name+' - '+e.size_kb+'KB</div>' +
|
|
'</a>'"""
|
|
|
|
new_tile = """'<div style=\"font-size:9px;color:var(--mu);display:flex;justify-content:space-between;align-items:center\"><span>'+e.name+' - '+e.size_kb+'KB</span>' +
|
|
'<button onclick=\"event.preventDefault();event.stopPropagation();__dashTogglePin(\\''+e.name+'\\')\" style=\"background:transparent;border:0;color:'+(pinned.has(e.name)?\"#fbbf24\":\"#555\")+';cursor:pointer;font-size:14px;padding:0 4px\" title=\"'+(pinned.has(e.name)?'Unpin':'Pin')+'\">★</button>' +
|
|
'</div>' +
|
|
'</a>'"""
|
|
if old_tile in c:
|
|
c = c.replace(old_tile, new_tile, 1)
|
|
|
|
# Modify tile style to highlight pinned with gold border + background
|
|
old_tile_style = """'<a href=\"'+e.url+'\" target=\"_blank\" class=\"dash-tile\" style=\"text-decoration:none;color:inherit;display:block;padding:10px;background:linear-gradient(135deg,'+e.color+'22,'+e.color+'11);border:1px solid '+e.color+'55;border-radius:6px;transition:transform 0.15s ease,border-color 0.15s ease,box-shadow 0.15s ease\" """
|
|
|
|
new_tile_style = """'<a href=\"'+e.url+'\" target=\"_blank\" class=\"dash-tile' + (pinned.has(e.name) ? ' pinned' : '') + '\" style=\"text-decoration:none;color:inherit;display:block;padding:10px;background:linear-gradient(135deg,'+e.color+'22,'+e.color+'11);border:1px solid ' + (pinned.has(e.name) ? '#fbbf24' : e.color+'55') + ';border-radius:6px;transition:transform 0.15s ease,border-color 0.15s ease,box-shadow 0.15s ease\" """
|
|
|
|
if old_tile_style in c:
|
|
c = c.replace(old_tile_style, new_tile_style, 1)
|
|
|
|
# Add pin management functions + URL sync before "setTimeout(() =>" (V119 listeners block)
|
|
js_marker = "setTimeout(() => {\n const btn = document.querySelector('[data-view=\"dashboards\"]');"
|
|
js_pins = """// V123-PINS: pin management via URL hash (shareable, no localStorage)
|
|
function __dashPins(){
|
|
const raw = new URLSearchParams(window.location.hash.slice(1)).get('pins') || '';
|
|
return new Set(raw.split(',').filter(Boolean));
|
|
}
|
|
function __dashSetPins(set){
|
|
const params = new URLSearchParams(window.location.hash.slice(1));
|
|
if (set.size) params.set('pins', Array.from(set).join(','));
|
|
else params.delete('pins');
|
|
const h = params.toString();
|
|
window.history.replaceState(null, '', window.location.pathname + window.location.search + (h ? '#'+h : ''));
|
|
}
|
|
function __dashTogglePin(name){
|
|
const s = __dashPins();
|
|
if (s.has(name)) s.delete(name);
|
|
else s.add(name);
|
|
__dashSetPins(s);
|
|
if (__dashData) {
|
|
const activeCat = document.querySelector('.dash-filter.on')?.getAttribute('data-cat') || 'all';
|
|
renderDashGrid(__dashData.dashboards, activeCat);
|
|
}
|
|
}
|
|
|
|
""" + js_marker
|
|
|
|
if js_marker in c:
|
|
c = c.replace(js_marker, js_pins, 1)
|
|
|
|
# Tiny CSS for pinned tiles hover intensification
|
|
style_marker = '@keyframes fadeIn{from{opacity:0.4}to{opacity:1}}'
|
|
style_new = style_marker + '\n#v-dashboards .dash-tile.pinned{box-shadow:0 0 0 1px rgba(251,191,36,0.3)}\n#v-dashboards .dash-tile.pinned:hover{box-shadow:0 4px 12px rgba(251,191,36,0.35)!important}'
|
|
if style_marker in c:
|
|
c = c.replace(style_marker, style_new, 1)
|
|
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
f.write(c)
|
|
print(f"PATCHED size={len(c)}")
|