signalk-czone 0.3.0-beta.20 → 0.3.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0-beta.21
4
+
5
+ - Includes ZCF Favorites in the circuit favorites list, counts and stars by default. Browser additions and removals persist as local overrides across reloads and ZCF updates.
6
+
3
7
  ## 0.3.0-beta.20
4
8
 
5
9
  - Shows individual monitoring readings as live for three minutes, then keeps their last values dimmed with their age; distinguishes stale rows from no data (#38, thanks @superstar76).
package/README.md CHANGED
@@ -548,3 +548,7 @@ Certificate installation and app installation menus vary by device and browser.
548
548
 
549
549
  The app still needs a live Signal K connection. No offline caching or service
550
550
  worker is installed, and installing it does not grant circuit-write permission.
551
+
552
+ ### Circuit favorites
553
+
554
+ Circuits marked Favorites in the loaded ZCF appear as favorites by default. The star buttons customize favorites for the current browser: you can add other circuits or hide a ZCF favorite. These choices survive browser and server restarts and apply when the ZCF is reloaded or updated. They are stored in browser site data, do not change the ZCF, and are independent on each browser/device. Clearing site data restores the ZCF defaults.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalk-czone",
3
- "version": "0.3.0-beta.20",
3
+ "version": "0.3.0-beta.21",
4
4
  "description": "BETA: Signal K CZone monitoring and control using dynamically parsed ZCF configuration and NMEA 2000",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  "icon.png"
43
43
  ],
44
44
  "scripts": {
45
- "test": "node test/zcf.test.js && node test/zcf-fixtures.test.js && node test/circuit-state.test.js && node test/czone.test.js && node test/nmea2000.test.js && node test/control-x-plus.test.js && node test/signalk.test.js && node test/write.test.js && node test/circuit-status.test.js && node test/status-mapping-regression.test.js && node test/state.test.js && node test/config-network.test.js && node test/config-namespace.test.js && node test/monitoring.test.js && node test/sensors.test.js && node test/monitoring-plugin.test.js && node test/power-history.test.js && node test/confirm-off.test.js && node test/webapp-current.test.js && node test/webapp-auth.test.js && node test/webapp-monitoring.test.js && node test/bridge.test.js && node test/victron-switches.test.js && node test/victron-label-steady.test.js && node test/switch-pane-plugin.test.js && node test/trends.test.js && node test/inputs.test.js && node --require ./test/helpers/gx-low-space.cjs test/trends.test.js"
45
+ "test": "node test/zcf.test.js && node test/zcf-fixtures.test.js && node test/circuit-state.test.js && node test/czone.test.js && node test/nmea2000.test.js && node test/control-x-plus.test.js && node test/signalk.test.js && node test/write.test.js && node test/circuit-status.test.js && node test/status-mapping-regression.test.js && node test/state.test.js && node test/config-network.test.js && node test/config-namespace.test.js && node test/monitoring.test.js && node test/sensors.test.js && node test/monitoring-plugin.test.js && node test/power-history.test.js && node test/confirm-off.test.js && node test/webapp-current.test.js && node test/webapp-favorites.test.js && node test/webapp-auth.test.js && node test/webapp-monitoring.test.js && node test/bridge.test.js && node test/victron-switches.test.js && node test/victron-label-steady.test.js && node test/switch-pane-plugin.test.js && node test/trends.test.js && node test/inputs.test.js && node --require ./test/helpers/gx-low-space.cjs test/trends.test.js"
46
46
  },
47
47
  "dependencies": {
48
48
  "signalk-czone-zcf": "0.1.0-beta.2"
package/public/index.html CHANGED
@@ -503,6 +503,10 @@
503
503
  const favoritesKey = 'signalk-czone-circuits:favorites';
504
504
  let favorites = new Set(JSON.parse(localStorage.getItem(favoritesKey) || '[]'));
505
505
 
506
+ // ZCF favorites are defaults; browser choices can add or hide them locally.
507
+ const hiddenFavoritesKey = `${favoritesKey}:hidden`;
508
+ let hiddenFavorites = new Set(JSON.parse(localStorage.getItem(hiddenFavoritesKey) || '[]'));
509
+
506
510
  const esc = s => String(s == null ? '' : s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
507
511
  const nameKey = c => c.slug || c.name;
508
512
  const stateOf = c => c.state && c.state.state === 'ON';
@@ -513,6 +517,7 @@
513
517
  return current != null && current > 0 ? `${current.toFixed(1)} A` : null;
514
518
  };
515
519
  const categoryData = c => c.categories || { master: [], sub: [], userDefined: [] };
520
+ const isFavorite = c => !hiddenFavorites.has(nameKey(c)) && (favorites.has(nameKey(c)) || (categoryData(c).master || []).includes('Favorites'));
516
521
  const allCategories = c => [...(categoryData(c).master || []), ...(categoryData(c).sub || []), ...(categoryData(c).userDefined || [])];
517
522
  const catList = () => {
518
523
  const assigned = new Set(circuits.flatMap(allCategories).filter(c => !topLevelCategories.has(c)));
@@ -527,14 +532,17 @@
527
532
  const icon = c => MFD ? mfdIcon(c) : (categoryIcons[c] || '•');
528
533
  const color = c => categoryColors[c] || '#4bb5ff';
529
534
 
530
- function saveFavorites() { localStorage.setItem(favoritesKey, JSON.stringify([...favorites])); }
535
+ function saveFavorites() {
536
+ localStorage.setItem(favoritesKey, JSON.stringify([...favorites]));
537
+ localStorage.setItem(hiddenFavoritesKey, JSON.stringify([...hiddenFavorites]));
538
+ }
531
539
  function setView(v) { view=v; category=null; render(); if (v === 'monitor') { monitorLastFetch = 0; refreshMonitoring(); } }
532
540
  function setCategory(c) { category=c; view='category'; render(); }
533
541
  window.setView = setView; window.setCategory = setCategory;
534
542
 
535
543
  function renderNav() {
536
544
  const items = [
537
- ['all','⌂','All Circuits',circuits.length], ['inuse','●','In Use',activeCount()], ['favorites','☆','Favorites',circuits.filter(c=>favorites.has(nameKey(c))).length],
545
+ ['all','⌂','All Circuits',circuits.length], ['inuse','●','In Use',activeCount()], ['favorites','☆','Favorites',circuits.filter(isFavorite).length],
538
546
  ['ac','♆','AC',masterCount('AC')], ['dc','▣','DC',masterCount('DC')]
539
547
  ];
540
548
  if (monitor.items.length) items.push(['monitor','◔','Monitoring',monitor.items.length]);
@@ -552,7 +560,7 @@
552
560
  let list = circuits.filter(c => {
553
561
  if (c.showInCircuitList === false) return false;
554
562
  if (view==='inuse' && !stateOf(c)) return false;
555
- if (view==='favorites' && !favorites.has(nameKey(c))) return false;
563
+ if (view==='favorites' && !isFavorite(c)) return false;
556
564
  if (view==='ac' && !(categoryData(c).master || []).includes('AC')) return false;
557
565
  if (view==='dc' && !(categoryData(c).master || []).includes('DC')) return false;
558
566
  if (category && !allCategories(c).includes(category)) return false;
@@ -676,7 +684,7 @@
676
684
  }
677
685
 
678
686
  function circuitRow(c) {
679
- const on = stateOf(c), pct = percentOf(c), current = currentLabel(c), dim = !!(c.capabilities && c.capabilities.dimmer), fav = favorites.has(nameKey(c));
687
+ const on = stateOf(c), pct = percentOf(c), current = currentLabel(c), dim = !!(c.capabilities && c.capabilities.dimmer), fav = isFavorite(c);
680
688
  const p = pending.get(nameKey(c));
681
689
  const cats = subCategoryList(c).slice(0,3).map(x => `<span class="tag cat" role="img" tabindex="0" style="--cat:${color(x)}" title="${esc(x)}" aria-label="${esc(x)} category">${icon(x)}</span>`).join('');
682
690
  const disabled = p && p.kind === 'state';
@@ -1084,7 +1092,19 @@
1084
1092
  }
1085
1093
  putSignalK(signalKPath(c, 'brightness'), requested / 100, c, 'brightness', requested, previous);
1086
1094
  };
1087
- window.toggleFavorite = key => { favorites.has(key) ? favorites.delete(key) : favorites.add(key); saveFavorites(); render(); };
1095
+ window.toggleFavorite = key => {
1096
+ const circuit = circuits.find(c => nameKey(c) === key);
1097
+ if (!circuit) return;
1098
+ if (isFavorite(circuit)) {
1099
+ favorites.delete(key);
1100
+ hiddenFavorites.add(key);
1101
+ } else {
1102
+ hiddenFavorites.delete(key);
1103
+ favorites.add(key);
1104
+ }
1105
+ saveFavorites();
1106
+ render();
1107
+ };
1088
1108
 
1089
1109
  // ---- Trends ---------------------------------------------------------------
1090
1110
  // The arrow at the end of a row opens that circuit's current over time, at
@@ -1399,7 +1419,7 @@
1399
1419
  }
1400
1420
 
1401
1421
  function renderStats() {
1402
- const on=activeCount(), total=circuits.length, fav=circuits.filter(c=>favorites.has(nameKey(c))).length;
1422
+ const on=activeCount(), total=circuits.length, fav=circuits.filter(isFavorite).length;
1403
1423
  document.querySelector('#stats').innerHTML = `<div class="stat"><div class="stat-icon">⚡</div><div><strong>${total}</strong><span>Total Circuits</span></div></div><div class="stat"><div class="stat-icon">●</div><div><strong>${on}</strong><span>In Use</span></div></div><div class="stat"><div class="stat-icon">○</div><div><strong>${total-on}</strong><span>Off</span></div></div><div class="stat"><div class="stat-icon">★</div><div><strong>${fav}</strong><span>Favorites</span></div></div>`;
1404
1424
  const n2kReady = status.nmeaReady === true;
1405
1425
  const readyColor = n2kReady ? '#64e4aa' : '#ffcc77';