signalk-siparu 0.2.4 → 0.2.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalk-siparu",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Kept aboard, proven ashore. An impartial, timestamped record of every voyage: position, wind, depth and logbook, written on the boat and readable from anywhere. A read-only Signal K plugin with a built-in dashboard.",
5
5
  "keywords": [
6
6
  "signalk-node-server-plugin",
@@ -19,6 +19,7 @@ export interface LiveStatus {
19
19
  lastFrameTs: number | null;
20
20
  failures: number;
21
21
  rejected: boolean;
22
+ unentitled: boolean;
22
23
  lastError: string | null;
23
24
  }
24
25
  export interface LiveDeps {
@@ -66,6 +67,7 @@ export declare class LiveUplink {
66
67
  private lastFrameTs;
67
68
  private lastSog;
68
69
  private rejected;
70
+ private unentitled;
69
71
  private lastError;
70
72
  private readonly fixedFrameMs;
71
73
  private readonly pingEveryMs;
@@ -14,7 +14,9 @@ const STAND_OFF_MS = 15 * 60_000;
14
14
  const UNPAIRED_RECHECK_MS = 60_000;
15
15
  const CLOSE_UNKNOWN_TOKEN = 1008;
16
16
  const CLOSE_REPLACED = 1012;
17
+ const CLOSE_PLAN_REQUIRED = 4403;
17
18
  const REFUSED_UNKNOWN_TOKEN = 401;
19
+ const REFUSED_PLAN_REQUIRED = 403;
18
20
  const HANDSHAKE_TIMEOUT_MS = 15_000;
19
21
  class LiveUplink {
20
22
  deps;
@@ -30,6 +32,7 @@ class LiveUplink {
30
32
  lastFrameTs = null;
31
33
  lastSog = null;
32
34
  rejected = false;
35
+ unentitled = false;
33
36
  lastError = null;
34
37
  fixedFrameMs;
35
38
  pingEveryMs;
@@ -71,12 +74,14 @@ class LiveUplink {
71
74
  lastFrameTs: this.lastFrameTs,
72
75
  failures: this.failures,
73
76
  rejected: this.rejected,
77
+ unentitled: this.unentitled,
74
78
  lastError: this.lastError
75
79
  };
76
80
  }
77
81
  reset() {
78
82
  this.failures = 0;
79
83
  this.rejected = false;
84
+ this.unentitled = false;
80
85
  this.lastError = null;
81
86
  this.lastFrameTs = null;
82
87
  if (this.stopped)
@@ -116,6 +121,7 @@ class LiveUplink {
116
121
  this.connected = true;
117
122
  this.failures = 0;
118
123
  this.rejected = false;
124
+ this.unentitled = false;
119
125
  this.lastError = null;
120
126
  this.awaitingPong = false;
121
127
  this.sendFrame(gen);
@@ -171,7 +177,11 @@ class LiveUplink {
171
177
  if (gen !== this.gen)
172
178
  return;
173
179
  this.kill(sock);
174
- this.closed(gen, status === REFUSED_UNKNOWN_TOKEN ? CLOSE_UNKNOWN_TOKEN : 1006);
180
+ this.closed(gen, status === REFUSED_UNKNOWN_TOKEN
181
+ ? CLOSE_UNKNOWN_TOKEN
182
+ : status === REFUSED_PLAN_REQUIRED
183
+ ? CLOSE_PLAN_REQUIRED
184
+ : 1006);
175
185
  });
176
186
  }
177
187
  kill(sock) {
@@ -413,6 +423,14 @@ class LiveUplink {
413
423
  this.redial(STAND_OFF_MS);
414
424
  return;
415
425
  }
426
+ if (code === CLOSE_PLAN_REQUIRED) {
427
+ this.unentitled = true;
428
+ this.lastError =
429
+ 'Remote watching is not active on this account. She is recording as usual, and starts sending again when it is.';
430
+ this.deps.debug(`live uplink: ${this.lastError}`);
431
+ this.redial(STAND_OFF_MS);
432
+ return;
433
+ }
416
434
  if (code === CLOSE_REPLACED) {
417
435
  this.lastError = 'Another copy of this boat is connected to Siparu.';
418
436
  this.deps.debug(`live uplink: ${this.lastError}`);
@@ -3,12 +3,15 @@ export interface UplinkStatus {
3
3
  lastSentTs: number | null;
4
4
  failures: number;
5
5
  rejected: boolean;
6
+ unentitled: boolean;
6
7
  lastError: string | null;
7
8
  }
8
9
  export declare function reportedStatus(socket: {
9
10
  connected: boolean;
10
11
  lastFrameTs: number | null;
11
12
  rejected?: boolean;
13
+ unentitled?: boolean;
14
+ lastError?: string | null;
12
15
  } | null | undefined, post: UplinkStatus | null): UplinkStatus | null;
13
16
  export interface UplinkDeps {
14
17
  relayUrl: string;
@@ -26,6 +29,7 @@ export declare class Uplink {
26
29
  private lastSentTs;
27
30
  private failures;
28
31
  private rejected;
32
+ private unentitled;
29
33
  private lastError;
30
34
  constructor(deps: UplinkDeps);
31
35
  start(): void;
@@ -4,13 +4,29 @@ exports.Uplink = void 0;
4
4
  exports.reportedStatus = reportedStatus;
5
5
  function reportedStatus(socket, post) {
6
6
  if (socket?.connected) {
7
- return { lastSentTs: socket.lastFrameTs, failures: 0, rejected: false, lastError: null };
7
+ return {
8
+ lastSentTs: socket.lastFrameTs,
9
+ failures: 0,
10
+ rejected: false,
11
+ unentitled: false,
12
+ lastError: null
13
+ };
14
+ }
15
+ if (socket?.unentitled) {
16
+ return {
17
+ lastSentTs: socket.lastFrameTs,
18
+ failures: 0,
19
+ rejected: false,
20
+ unentitled: true,
21
+ lastError: socket.lastError ?? 'Remote watching is not active on this account.'
22
+ };
8
23
  }
9
24
  if (socket?.rejected) {
10
25
  return {
11
26
  lastSentTs: socket.lastFrameTs,
12
27
  failures: 0,
13
28
  rejected: true,
29
+ unentitled: false,
14
30
  lastError: 'Siparu no longer recognises this boat. Pair her again.'
15
31
  };
16
32
  }
@@ -28,6 +44,7 @@ class Uplink {
28
44
  lastSentTs = null;
29
45
  failures = 0;
30
46
  rejected = false;
47
+ unentitled = false;
31
48
  lastError = null;
32
49
  constructor(deps) {
33
50
  this.deps = deps;
@@ -53,6 +70,7 @@ class Uplink {
53
70
  lastSentTs: this.lastSentTs,
54
71
  failures: this.failures,
55
72
  rejected: this.rejected,
73
+ unentitled: this.unentitled,
56
74
  lastError: this.lastError
57
75
  };
58
76
  }
@@ -60,6 +78,7 @@ class Uplink {
60
78
  this.lastSentTs = null;
61
79
  this.failures = 0;
62
80
  this.rejected = false;
81
+ this.unentitled = false;
63
82
  this.lastError = null;
64
83
  }
65
84
  schedule(delayMs) {
@@ -109,14 +128,18 @@ class Uplink {
109
128
  this.lastSentTs = Date.now();
110
129
  this.failures = 0;
111
130
  this.rejected = false;
131
+ this.unentitled = false;
112
132
  this.lastError = null;
113
133
  return;
114
134
  }
115
135
  this.failures++;
116
136
  this.rejected = res.status === 401;
137
+ this.unentitled = res.status === 403;
117
138
  this.lastError = this.rejected
118
139
  ? 'Siparu no longer recognises this boat. Pair her again.'
119
- : `Relay refused the frame (${res.status}).`;
140
+ : this.unentitled
141
+ ? 'Remote watching is not active on this account. She is recording as usual, and starts sending again when it is.'
142
+ : `Relay refused the frame (${res.status}).`;
120
143
  this.deps.debug(`uplink: ${this.lastError}`);
121
144
  }
122
145
  catch (e) {
@@ -1 +1 @@
1
- import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{_ as t,c as n,g as r,i,l as a,n as o,o as s,p as c,s as l,t as u,u as d,y as f}from"./index-RgGUQ86M.js";import{t as p}from"./visibleInterval-CFxPzgzx.js";var m=e(f(),1),h={"1m":1,"1h":60,"6h":360,"1d":1440},g={"1m":60,"1h":48,"6h":40,"1d":30},_=15e3;function v(){let[e,t]=(0,m.useState)(`1h`),[n,i]=(0,m.useState)(0),[a,o]=(0,m.useState)(!1),[s,c]=(0,m.useState)([]),[l,u]=(0,m.useState)(null),[d,f]=(0,m.useState)(!1),v=h[e],y=g[e]+n*g[e],b=(0,m.useCallback)(e=>{t(e),i(0),c([]),o(!1)},[]),x=(0,m.useCallback)(async()=>{f(!0),u(null);try{let e=y+1,t=await r.logbook.snapshots({bucket:v,limit:e,order:`desc`});o(t.length>y),c(t.slice(0,y))}catch(e){u(e.message)}finally{f(!1)}},[v,y]);return(0,m.useEffect)(()=>{x();let e=p(x,_);return()=>e()},[x]),{granularity:e,changeGran:b,snaps:s,err:l,busy:d,hasMore:a,loadMore:(0,m.useCallback)(()=>i(e=>e+1),[])}}function y(){let[e,t]=(0,m.useState)(o()),[n,i]=(0,m.useState)([]),[a,s]=(0,m.useState)(null),[l,d]=(0,m.useState)(!1),f=(0,m.useRef)(!0),h=c(6e4),g=o(new Date(h)),v=(0,m.useMemo)(()=>u(e),[e]),y=v+24*36e5,b=e===g;(0,m.useEffect)(()=>{f.current&&e!==g&&t(g)},[g,e]);let x=(0,m.useCallback)(e=>{f.current=e===o(),t(e)},[]),S=(0,m.useCallback)(async()=>{d(!0),s(null);try{let e=await r.logbook.snapshots({from:v,to:y,limit:5e3,order:`desc`,bucket:60});i(e)}catch(e){s(e.message)}finally{d(!1)}},[v,y]);return(0,m.useEffect)(()=>{if(S(),!b)return;let e=p(S,_);return()=>e()},[S,b]),{dateStr:e,setDateStr:x,dayStart:v,isToday:b,snaps:n,err:a,busy:l,prevDay:(0,m.useCallback)(()=>x(o(new Date(v-864e5))),[v,x]),nextDay:(0,m.useCallback)(()=>x(o(new Date(v+864e5))),[v,x]),goToday:(0,m.useCallback)(()=>x(o()),[x])}}var b=t(),x=[`1m`,`1h`,`6h`,`1d`],S={"1m":`Last hour`,"1h":`Last 2 days`,"6h":`Last 10 days`,"1d":`Last month`};function C(){let[e,t]=(0,m.useState)(`live`),[n,r]=(0,m.useState)(()=>localStorage.getItem(`lb:windUnit`)||`kn`),i={mode:e,setMode:t,windUnit:n,toggleWind:()=>r(e=>{let t=e===`kn`?`bft`:`kn`;return localStorage.setItem(`lb:windUnit`,t),t})};return(0,b.jsx)(`div`,{className:`lb`,children:e===`live`?(0,b.jsx)(E,{...i}):(0,b.jsx)(D,{...i})})}function w({mode:e,setMode:t}){return(0,b.jsxs)(`div`,{className:`seg`,children:[(0,b.jsx)(`button`,{className:e===`live`?`on`:``,onClick:()=>t(`live`),children:`Live`}),(0,b.jsx)(`button`,{className:e===`day`?`on`:``,onClick:()=>t(`day`),children:`Day`})]})}function T({windUnit:e,toggleWind:t}){return(0,b.jsxs)(`div`,{className:`lb-cols`,children:[(0,b.jsx)(`span`,{children:`UTC`}),(0,b.jsx)(`span`,{children:`SOG`}),(0,b.jsx)(`span`,{children:`HDG`}),(0,b.jsx)(`span`,{className:`tap`,onClick:t,title:`Tap: knots ⇄ Beaufort`,children:e===`kn`?`TWS`:`BFT`}),(0,b.jsx)(`span`,{children:`BARO`}),(0,b.jsx)(`span`,{children:`DEP`})]})}function E({mode:e,setMode:t,windUnit:n,toggleWind:r}){let{granularity:i,changeGran:a,snaps:o,err:s,busy:c,hasMore:l,loadMore:u}=v();return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`lb-ctrl`,children:[(0,b.jsx)(w,{mode:e,setMode:t}),(0,b.jsx)(`div`,{className:`seg`,children:x.map(e=>(0,b.jsx)(`button`,{className:i===e?`on`:``,onClick:()=>a(e),children:e},e))}),(0,b.jsx)(`span`,{className:`lb-count`,children:o.length})]}),(0,b.jsx)(T,{windUnit:n,toggleWind:r}),(0,b.jsxs)(`div`,{className:`lb-day`,children:[(0,b.jsx)(`span`,{children:S[i]}),(0,b.jsx)(`b`,{children:o.length})]}),s&&(0,b.jsx)(`div`,{className:`lb-err`,children:s}),(0,b.jsx)(O,{snaps:o,windUnit:n,footer:l?(0,b.jsx)(`button`,{className:`lb-more`,onClick:u,disabled:c,children:c?`Loading…`:`Load ${g[i]} more`}):null})]})}function D({mode:e,setMode:t,windUnit:n,toggleWind:r}){let{dateStr:i,setDateStr:a,isToday:s,snaps:c,err:l,busy:u,prevDay:d,nextDay:f,goToday:p}=y(),m=s?`Today · ${new Date(i).toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`,timeZone:`UTC`})}`:new Date(i).toLocaleDateString(`en-GB`,{weekday:`short`,day:`2-digit`,month:`short`,timeZone:`UTC`}).replace(/,/g,``);return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`lb-ctrl`,children:[(0,b.jsx)(w,{mode:e,setMode:t}),(0,b.jsxs)(`div`,{className:`lb-date`,children:[(0,b.jsx)(`button`,{onClick:d,"aria-label":`Previous day`,children:`‹`}),(0,b.jsx)(`input`,{type:`date`,className:`dt`,value:i,max:o(),onChange:e=>a(e.target.value),style:{border:`1.5px solid var(--rule)`,background:`var(--cell)`,color:`var(--text)`,fontFamily:`var(--sp-font)`,fontSize:12,padding:`5px 7px`}}),(0,b.jsx)(`button`,{onClick:f,disabled:s,"aria-label":`Next day`,children:`›`}),(0,b.jsx)(`button`,{onClick:p,disabled:s,children:`Now`})]})]}),(0,b.jsx)(T,{windUnit:n,toggleWind:r}),(0,b.jsxs)(`div`,{className:`lb-day`,children:[(0,b.jsx)(`span`,{children:m}),(0,b.jsx)(`b`,{children:c.length})]}),l&&(0,b.jsx)(`div`,{className:`lb-err`,children:l}),!u&&c.length===0?(0,b.jsxs)(`div`,{className:`sp-empty`,children:[(0,b.jsx)(`div`,{className:`em-t`,children:`No snapshots`}),(0,b.jsx)(`div`,{className:`em-s`,children:`No telemetry was logged for this day.`})]}):(0,b.jsx)(O,{snaps:c,windUnit:n,footer:null})]})}function O({snaps:e,footer:t,windUnit:n}){return(0,b.jsxs)(`div`,{className:`lb-rows`,children:[e.map(e=>(0,b.jsx)(k,{s:e,windUnit:n},e.ts)),t]})}function k({s:e,windUnit:t}){let r=new Date(e.ts),o=e=>String(e).padStart(2,`0`),c=d(e.sog),u=a(e.heading_true??e.heading_mag),f=l(e.wind_speed_true),p=f===null?`·`:String(t===`kn`?Math.round(f):s(f)??`·`),m=n(e.air_pressure_pa);return(0,b.jsxs)(`div`,{className:`lb-row`,children:[(0,b.jsxs)(`span`,{className:`tm`,children:[o(r.getUTCHours()),`:`,o(r.getUTCMinutes())]}),(0,b.jsx)(`span`,{className:`v`,children:i(c,1)}),(0,b.jsx)(`span`,{className:`v`,children:u===null?`·`:Math.round(u)+`°`}),(0,b.jsx)(`span`,{className:`v`,children:p}),(0,b.jsx)(`span`,{className:`v dim`,children:m===null?`·`:Math.round(m)}),(0,b.jsx)(`span`,{className:`v`,children:e.depth===null?`·`:e.depth.toFixed(1)})]})}function A(){return(0,b.jsx)(C,{})}export{A as default};
1
+ import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{_ as t,c as n,g as r,i,l as a,n as o,o as s,p as c,s as l,t as u,u as d,y as f}from"./index-C_sXr_1m.js";import{t as p}from"./visibleInterval-CFxPzgzx.js";var m=e(f(),1),h={"1m":1,"1h":60,"6h":360,"1d":1440},g={"1m":60,"1h":48,"6h":40,"1d":30},_=15e3;function v(){let[e,t]=(0,m.useState)(`1h`),[n,i]=(0,m.useState)(0),[a,o]=(0,m.useState)(!1),[s,c]=(0,m.useState)([]),[l,u]=(0,m.useState)(null),[d,f]=(0,m.useState)(!1),v=h[e],y=g[e]+n*g[e],b=(0,m.useCallback)(e=>{t(e),i(0),c([]),o(!1)},[]),x=(0,m.useCallback)(async()=>{f(!0),u(null);try{let e=y+1,t=await r.logbook.snapshots({bucket:v,limit:e,order:`desc`});o(t.length>y),c(t.slice(0,y))}catch(e){u(e.message)}finally{f(!1)}},[v,y]);return(0,m.useEffect)(()=>{x();let e=p(x,_);return()=>e()},[x]),{granularity:e,changeGran:b,snaps:s,err:l,busy:d,hasMore:a,loadMore:(0,m.useCallback)(()=>i(e=>e+1),[])}}function y(){let[e,t]=(0,m.useState)(o()),[n,i]=(0,m.useState)([]),[a,s]=(0,m.useState)(null),[l,d]=(0,m.useState)(!1),f=(0,m.useRef)(!0),h=c(6e4),g=o(new Date(h)),v=(0,m.useMemo)(()=>u(e),[e]),y=v+24*36e5,b=e===g;(0,m.useEffect)(()=>{f.current&&e!==g&&t(g)},[g,e]);let x=(0,m.useCallback)(e=>{f.current=e===o(),t(e)},[]),S=(0,m.useCallback)(async()=>{d(!0),s(null);try{let e=await r.logbook.snapshots({from:v,to:y,limit:5e3,order:`desc`,bucket:60});i(e)}catch(e){s(e.message)}finally{d(!1)}},[v,y]);return(0,m.useEffect)(()=>{if(S(),!b)return;let e=p(S,_);return()=>e()},[S,b]),{dateStr:e,setDateStr:x,dayStart:v,isToday:b,snaps:n,err:a,busy:l,prevDay:(0,m.useCallback)(()=>x(o(new Date(v-864e5))),[v,x]),nextDay:(0,m.useCallback)(()=>x(o(new Date(v+864e5))),[v,x]),goToday:(0,m.useCallback)(()=>x(o()),[x])}}var b=t(),x=[`1m`,`1h`,`6h`,`1d`],S={"1m":`Last hour`,"1h":`Last 2 days`,"6h":`Last 10 days`,"1d":`Last month`};function C(){let[e,t]=(0,m.useState)(`live`),[n,r]=(0,m.useState)(()=>localStorage.getItem(`lb:windUnit`)||`kn`),i={mode:e,setMode:t,windUnit:n,toggleWind:()=>r(e=>{let t=e===`kn`?`bft`:`kn`;return localStorage.setItem(`lb:windUnit`,t),t})};return(0,b.jsx)(`div`,{className:`lb`,children:e===`live`?(0,b.jsx)(E,{...i}):(0,b.jsx)(D,{...i})})}function w({mode:e,setMode:t}){return(0,b.jsxs)(`div`,{className:`seg`,children:[(0,b.jsx)(`button`,{className:e===`live`?`on`:``,onClick:()=>t(`live`),children:`Live`}),(0,b.jsx)(`button`,{className:e===`day`?`on`:``,onClick:()=>t(`day`),children:`Day`})]})}function T({windUnit:e,toggleWind:t}){return(0,b.jsxs)(`div`,{className:`lb-cols`,children:[(0,b.jsx)(`span`,{children:`UTC`}),(0,b.jsx)(`span`,{children:`SOG`}),(0,b.jsx)(`span`,{children:`HDG`}),(0,b.jsx)(`span`,{className:`tap`,onClick:t,title:`Tap: knots ⇄ Beaufort`,children:e===`kn`?`TWS`:`BFT`}),(0,b.jsx)(`span`,{children:`BARO`}),(0,b.jsx)(`span`,{children:`DEP`})]})}function E({mode:e,setMode:t,windUnit:n,toggleWind:r}){let{granularity:i,changeGran:a,snaps:o,err:s,busy:c,hasMore:l,loadMore:u}=v();return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`lb-ctrl`,children:[(0,b.jsx)(w,{mode:e,setMode:t}),(0,b.jsx)(`div`,{className:`seg`,children:x.map(e=>(0,b.jsx)(`button`,{className:i===e?`on`:``,onClick:()=>a(e),children:e},e))}),(0,b.jsx)(`span`,{className:`lb-count`,children:o.length})]}),(0,b.jsx)(T,{windUnit:n,toggleWind:r}),(0,b.jsxs)(`div`,{className:`lb-day`,children:[(0,b.jsx)(`span`,{children:S[i]}),(0,b.jsx)(`b`,{children:o.length})]}),s&&(0,b.jsx)(`div`,{className:`lb-err`,children:s}),(0,b.jsx)(O,{snaps:o,windUnit:n,footer:l?(0,b.jsx)(`button`,{className:`lb-more`,onClick:u,disabled:c,children:c?`Loading…`:`Load ${g[i]} more`}):null})]})}function D({mode:e,setMode:t,windUnit:n,toggleWind:r}){let{dateStr:i,setDateStr:a,isToday:s,snaps:c,err:l,busy:u,prevDay:d,nextDay:f,goToday:p}=y(),m=s?`Today · ${new Date(i).toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`,timeZone:`UTC`})}`:new Date(i).toLocaleDateString(`en-GB`,{weekday:`short`,day:`2-digit`,month:`short`,timeZone:`UTC`}).replace(/,/g,``);return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`lb-ctrl`,children:[(0,b.jsx)(w,{mode:e,setMode:t}),(0,b.jsxs)(`div`,{className:`lb-date`,children:[(0,b.jsx)(`button`,{onClick:d,"aria-label":`Previous day`,children:`‹`}),(0,b.jsx)(`input`,{type:`date`,className:`dt`,value:i,max:o(),onChange:e=>a(e.target.value),style:{border:`1.5px solid var(--rule)`,background:`var(--cell)`,color:`var(--text)`,fontFamily:`var(--sp-font)`,fontSize:12,padding:`5px 7px`}}),(0,b.jsx)(`button`,{onClick:f,disabled:s,"aria-label":`Next day`,children:`›`}),(0,b.jsx)(`button`,{onClick:p,disabled:s,children:`Now`})]})]}),(0,b.jsx)(T,{windUnit:n,toggleWind:r}),(0,b.jsxs)(`div`,{className:`lb-day`,children:[(0,b.jsx)(`span`,{children:m}),(0,b.jsx)(`b`,{children:c.length})]}),l&&(0,b.jsx)(`div`,{className:`lb-err`,children:l}),!u&&c.length===0?(0,b.jsxs)(`div`,{className:`sp-empty`,children:[(0,b.jsx)(`div`,{className:`em-t`,children:`No snapshots`}),(0,b.jsx)(`div`,{className:`em-s`,children:`No telemetry was logged for this day.`})]}):(0,b.jsx)(O,{snaps:c,windUnit:n,footer:null})]})}function O({snaps:e,footer:t,windUnit:n}){return(0,b.jsxs)(`div`,{className:`lb-rows`,children:[e.map(e=>(0,b.jsx)(k,{s:e,windUnit:n},e.ts)),t]})}function k({s:e,windUnit:t}){let r=new Date(e.ts),o=e=>String(e).padStart(2,`0`),c=d(e.sog),u=a(e.heading_true??e.heading_mag),f=l(e.wind_speed_true),p=f===null?`·`:String(t===`kn`?Math.round(f):s(f)??`·`),m=n(e.air_pressure_pa);return(0,b.jsxs)(`div`,{className:`lb-row`,children:[(0,b.jsxs)(`span`,{className:`tm`,children:[o(r.getUTCHours()),`:`,o(r.getUTCMinutes())]}),(0,b.jsx)(`span`,{className:`v`,children:i(c,1)}),(0,b.jsx)(`span`,{className:`v`,children:u===null?`·`:Math.round(u)+`°`}),(0,b.jsx)(`span`,{className:`v`,children:p}),(0,b.jsx)(`span`,{className:`v dim`,children:m===null?`·`:Math.round(m)}),(0,b.jsx)(`span`,{className:`v`,children:e.depth===null?`·`:e.depth.toFixed(1)})]})}function A(){return(0,b.jsx)(C,{})}export{A as default};
@@ -1,4 +1,4 @@
1
- import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{_ as t,a as n,d as r,g as i,i as a,l as o,r as s,u as c,y as l}from"./index-RgGUQ86M.js";import{t as u}from"./visibleInterval-CFxPzgzx.js";import{a as d,i as f,n as p,o as m,r as h,s as g,t as _}from"./style-Bk78SX0A.js";var v=e(l(),1),y={fill:`#ffb938`,stroke:`#b38326`,glow:`rgba(255,185,56,0.65)`,dot:`#050706`};function b(e,t=y){let n=t.fill,r=t.stroke;return e===null||Number.isNaN(e)?`
1
+ import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{_ as t,a as n,d as r,g as i,i as a,l as o,r as s,u as c,y as l}from"./index-C_sXr_1m.js";import{t as u}from"./visibleInterval-CFxPzgzx.js";import{a as d,i as f,n as p,o as m,r as h,s as g,t as _}from"./style-DroXqNI8.js";var v=e(l(),1),y={fill:`#ffb938`,stroke:`#b38326`,glow:`rgba(255,185,56,0.65)`,dot:`#050706`};function b(e,t=y){let n=t.fill,r=t.stroke;return e===null||Number.isNaN(e)?`
2
2
  <div style="
3
3
  width: 14px; height: 14px;
4
4
  background: ${n};
@@ -0,0 +1,5 @@
1
+ import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{_ as t,f as n,g as r,h as i,i as a,m as o,r as s,v as c,y as l}from"./index-C_sXr_1m.js";import{a as u,i as d,n as f,o as p,s as m,t as h}from"./style-DroXqNI8.js";var g=e(l(),1),_=[{mode:`total_l`,label:`Litres`},{mode:`total_usgal`,label:`US gallons`},{mode:`total_impgal`,label:`Imp gallons`},{mode:`per_nm`,label:`Litres / nm`},{mode:`nm_per_l`,label:`nm / L`},{mode:`per_hour`,label:`Litres / hour`}],v=.26417205,y=.21996923,b=1e-6;function x(e,t,n){return`${e.toFixed(n)} ${t}`}function S(e,t,n,r){if(e===null||!Number.isFinite(e))return null;switch(r){case`total_l`:return x(e,`L`,+(e<100));case`total_usgal`:return x(e*v,`US gal`,1);case`total_impgal`:return x(e*y,`Imp gal`,1);case`per_nm`:return t>b?x(e/t,`L/nm`,2):null;case`nm_per_l`:return e>b?x(t/e,`nm/L`,2):null;case`per_hour`:return n>b?x(e/n,`L/h`,1):null}}function C(e){if(e===null)return``;let t=String(e);return/[",\n\r]/.test(t)?`"${t.replace(/"/g,`""`)}"`:t}function w(e){if(!(e>0))return``;let t=Math.round(e*60),n=Math.floor(t/60),r=t%60;return n>0?`${n}h ${r}m`:`${r}m`}var T=e=>e===null?null:new Date(e).toISOString(),E=[`id`,`start_utc`,`end_utc`,`duration`,`from`,`to`,`distance_nm`,`hours_underway`,`avg_sog_kn`,`max_sog_kn`,`fuel_used_l`,`start_lat`,`start_lon`,`end_lat`,`end_lon`];function D(e){let t=[...e].sort((e,t)=>e.start_ts-t.start_ts),n=[E.join(`,`)];for(let e of t)n.push([e.id,T(e.start_ts),T(e.end_ts),w(e.hours_underway),e.start_port,e.end_port,e.distance_nm,e.hours_underway,e.avg_sog_kn,e.max_sog_kn,e.fuel_used_l,e.start_lat,e.start_lon,e.end_lat,e.end_lon].map(C).join(`,`));return n.join(`\r
2
+ `)+`\r
3
+ `}function O(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`)}function k(e){let t=new Date(e.start_ts).toISOString().slice(0,10);return!e.start_port&&!e.end_port?`Voyage ${e.id} ${t}`:`${t} ${e.start_port??`?`} to ${e.end_port??`?`}`}function A(e,t){let n=O(k(e)),r=t.map(e=>` <trkpt lat="${e.lat}" lon="${e.lon}"><time>${new Date(e.ts).toISOString()}</time></trkpt>`).join(`
4
+ `);return[`<?xml version="1.0" encoding="UTF-8"?>`,`<gpx version="1.1" creator="Siparu" xmlns="http://www.topografix.com/GPX/1/1">`,` <metadata>`,` <name>${n}</name>`,` <time>${new Date(e.start_ts).toISOString()}</time>`,` </metadata>`,` <trk>`,` <name>${n}</name>`,` <trkseg>`,r,` </trkseg>`,` </trk>`,`</gpx>`,``].join(`
5
+ `)}function j(e,t,n){let r=URL.createObjectURL(new Blob([n],{type:`${t};charset=utf-8`})),i=document.createElement(`a`);i.href=r,i.download=e,i.rel=`noopener`,document.body.appendChild(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),0)}function M(e,t,n){let r=new Date(t),i=e=>String(e).padStart(2,`0`);return`${e}-${r.getUTCFullYear()}${i(r.getUTCMonth()+1)}${i(r.getUTCDate())}.${n}`}var N=`Could not load voyage data`;function P(e){return e instanceof i?e.detail||N:e instanceof DOMException&&e.name===`TimeoutError`?`She did not answer in time`:N}function F(e=0){let{data:t}=n(r.voyage.current,6e4,[e],`voyage:current`),[i,a]=(0,g.useState)(null),[o,s]=(0,g.useState)([]),[c,l]=(0,g.useState)(!0),[u,d]=(0,g.useState)(null);return(0,g.useEffect)(()=>{let e=!1;return(async()=>{try{let[t,n]=await Promise.all([r.voyage.stats(),r.voyage.list(50)]);e||(a(t),s(n),d(null))}catch(t){e||d(P(t))}finally{e||l(!1)}})(),()=>{e=!0}},[e]),{current:t??null,stats:i,list:o,loading:c,err:u}}var I=e(m(),1),L=t();function R(){return document.documentElement.dataset.theme===`day`?`day`:`night`}function z(e,t){let n=document.createElement(`div`);return n.style.cssText=`width:10px;height:10px;border-radius:50%;border:2px solid ${e};background:${t?e:`transparent`};`,n}function B({track:e}){let t=(0,g.useRef)(null),n=(0,g.useRef)(null);return(0,g.useEffect)(()=>{if(!t.current||n.current)return;let r=t.current,i=document.documentElement,a=getComputedStyle(i).getPropertyValue(`--accent`).trim()||`#e5484d`,o=!1,s=null,c=null;return(async()=>{u();let t=await p();if(o)return;let l=()=>d(R(),t,{track:{color:a,width:3}}),m=e.filter(e=>e.lat!==null&&e.lon!==null).map(e=>[e.lon,e.lat]);s=new I.default.Map({container:r,style:l(),center:[7.42,43.7],zoom:9,attributionControl:{compact:!1,customAttribution:h},dragRotate:!1,pitchWithRotate:!1}),s.touchZoomRotate.disableRotation(),n.current=s;let g=()=>{if(!s)return;let e=s.getSource(f);e&&m.length>=2&&e.setData({type:`FeatureCollection`,features:[{type:`Feature`,properties:{},geometry:{type:`LineString`,coordinates:m}}]})};if(s.on(`style.load`,g),g(),m.length>=2){new I.default.Marker({element:z(a,!1),anchor:`center`}).setLngLat(m[0]).addTo(s),new I.default.Marker({element:z(a,!0),anchor:`center`}).setLngLat(m[m.length-1]).addTo(s);let e=new I.default.LngLatBounds;for(let t of m)e.extend(t);s.fitBounds(e,{padding:22,maxZoom:15,animate:!1})}c=new MutationObserver(()=>{s?.setStyle(l()),g()}),c.observe(i,{attributes:!0,attributeFilter:[`data-theme`]})})(),()=>{o=!0,c?.disconnect(),s?.remove(),n.current=null}},[e]),(0,L.jsx)(`div`,{ref:t,className:`vy-map`})}var V=e(c(),1);function H(e){let t=e.match(/^propulsion\.([^.]+)\.fuel\.rate$/),n=t?t[1]:e;return n.charAt(0).toUpperCase()+n.slice(1)}function U(e){let t=new Set(e.available);return e.selected.filter(e=>!t.has(e))}function W(e){return e.available.length>1||e.selected.length>0}function G(e){return[...e.available.map(e=>({path:e,reporting:!0})),...U(e).map(e=>({path:e,reporting:!1}))]}function K(e){let t=U(e);return t.length===0||t.length<e.selected.length?null:`No fuel counted: ${t.map(H).join(`, `)} is selected but not reporting a rate.`}function q(e){let t=U(e);return t.length>0&&t.length===e.selected.length?`${t.length===1?H(t[0]):`${t.length} engines`} · not reporting`:e.selected.length===0?`All`:e.selected.length===1?H(e.selected[0]):`${e.selected.length} engines`}function J({view:e,onClose:t,onApplied:n}){let[a,s]=(0,g.useState)(()=>new Set(e.selected)),[c,l]=(0,g.useState)(!1),[u,d]=(0,g.useState)(null),f=(0,g.useRef)(null),p=e=>{d(null),s(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},m=async()=>{let e=[...a].sort();l(!0),d(null);try{await r.config.setFuelPaths(e);let t=e.join(`,`);for(let e=0;e<12;e++){await new Promise(e=>setTimeout(e,700));try{if([...(await r.config.fuelPaths()).selected].sort().join(`,`)===t)break}catch{}}n(),f.current?.()}catch(e){e instanceof i?d(e.code===`security_off`?`Signal K security is off, so the fuel source is locked. Add an admin user in Signal K.`:e.detail||`Could not apply the change`):d(e instanceof Error?e.message:`Could not apply the change`),l(!1)}},h=K(e),_=document.querySelector(`.swiss.sp-screen`)??document.body;return(0,V.createPortal)((0,L.jsxs)(o,{title:`Fuel source`,eyebrow:`voyage fuel`,onClose:t,closeRef:f,footer:(0,L.jsx)(`button`,{type:`button`,className:`fs-apply`,onClick:m,disabled:c,children:c?`Applying…`:`Apply`}),children:[(0,L.jsx)(`p`,{className:`fs-note`,children:`Which engines count toward voyage fuel. With none selected, every reporting engine is summed.`}),h&&(0,L.jsx)(`div`,{className:`fs-quiet`,children:h}),(0,L.jsx)(`div`,{className:`fs-list`,role:`group`,"aria-label":`Fuel-rate sources`,children:G(e).map(({path:e,reporting:t})=>{let n=a.has(e);return(0,L.jsxs)(`button`,{type:`button`,className:`fs-row${n?` on`:``}${t?``:` off-air`}`,role:`checkbox`,"aria-checked":n,onClick:()=>p(e),disabled:c,children:[(0,L.jsxs)(`span`,{className:`fs-name`,children:[H(e),!t&&(0,L.jsx)(`span`,{className:`fs-tag`,children:` not reporting`})]}),(0,L.jsx)(`span`,{className:`fs-path`,children:e})]},e)})}),u&&(0,L.jsx)(`div`,{className:`fs-err`,children:u})]}),_)}var Y=`siparu.fuelMode`;function ee(){let e=localStorage.getItem(Y);return _.some(t=>t.mode===e)?e:`total_l`}var te=[{k:`today`,label:`Today`},{k:`yesterday`,label:`Yesterday`},{k:`rolling_7d`,label:`7 days`},{k:`season`,label:`Season`}],X={not_found:`That passage is no longer in the log.`,no_previous:`There is no earlier passage to join this one to.`,voyage_open:`This passage is still being recorded. It can be edited once it ends.`,nothing_to_undo:`This passage was not joined by hand.`,admin_required:`Sign in to Signal K as an administrator to edit the log.`,security_off:`Signal K security is off, so the log is locked. Add an admin user in Signal K.`};function Z(e){if(e===null||e<=0)return`·`;let t=Math.round(e*60),n=Math.floor(t/60),r=t%60;return n>0?`${n}h ${r}m`:`${r}m`}function Q(e){return new Date(e).toLocaleDateString(`en-GB`,{day:`2-digit`,month:`short`})}function $(e){let t=new Date(e),n=e=>String(e).padStart(2,`0`);return`${n(t.getHours())}:${n(t.getMinutes())}`}function ne(e){return!e.start_port&&!e.end_port?null:e.end_ts===null?e.start_port?`${e.start_port} →`:null:`${e.start_port??`·`} → ${e.end_port??`·`}`}function re(){let[e,t]=(0,g.useState)(0),n=F(e),[a,o]=(0,g.useState)(`today`),[s,c]=(0,g.useState)(null),[l,u]=(0,g.useState)({}),[d,f]=(0,g.useState)(ee),[p,m]=(0,g.useState)(null),[h,_]=(0,g.useState)(!1),[v,y]=(0,g.useState)(null),[b,x]=(0,g.useState)([]),[S,C]=(0,g.useState)(null);(0,g.useEffect)(()=>{localStorage.setItem(Y,d)},[d]),(0,g.useEffect)(()=>{let e=!0;return r.health().then(t=>{e&&y(t.boat_name)}).catch(()=>{}),()=>{e=!1}},[]),(0,g.useEffect)(()=>{let e=!0;return r.voyage.edits().then(t=>{e&&x(t.merged)}).catch(()=>{}),()=>{e=!1}},[e]),(0,g.useEffect)(()=>{let e=!1;return r.config.fuelPaths().then(t=>!e&&m(t)).catch(()=>{}),()=>{e=!0}},[e]);let w=!!p&&W(p),T=p?K(p):null,E=n.current&&n.current.end_ts===null?n.current:null,O=async e=>{if(s===e){c(null);return}if(c(e),!l[e])try{let t=await r.voyage.track(e);u(n=>({...n,[e]:t}))}catch{}},k=n.stats?.[a]??null,A=async e=>{C(null);try{let n=await e();if(!n.ok){C(X[n.error??``]??`That edit could not be made.`);return}c(null),u({}),t(e=>e+1)}catch(e){e instanceof i?C(X[e.code??``]??(e.detail||`That edit could not be made.`)):C(`The boat did not answer.`)}};return(0,L.jsxs)(`div`,{className:`vy`,children:[(0,L.jsxs)(`div`,{className:`vy-print-hd`,"aria-hidden":`true`,children:[(0,L.jsx)(`span`,{className:`b`,children:v??`Passage record`}),(0,L.jsx)(`span`,{className:`d`,children:new Date().toISOString().slice(0,10)})]}),E&&(0,L.jsx)(ie,{v:E}),(0,L.jsx)(`div`,{className:`vy-seg seg`,role:`group`,"aria-label":`Stats window`,children:te.map(e=>(0,L.jsx)(`button`,{className:a===e.k?`on`:``,onClick:()=>o(e.k),children:e.label},e.k))}),(0,L.jsx)(ae,{roll:k,loading:n.loading}),(0,L.jsxs)(`div`,{className:`vy-hd`,children:[(0,L.jsxs)(`span`,{className:`vy-hd-l`,children:[`Voyages `,(0,L.jsx)(`b`,{children:n.list.length})]}),(0,L.jsxs)(`span`,{className:`vy-hd-acts`,children:[w&&(0,L.jsxs)(`button`,{type:`button`,className:`vy-fuelsrc`,onClick:()=>_(!0),children:[`Fuel · `,q(p)]}),n.list.length>0&&(0,L.jsx)(`button`,{type:`button`,className:`vy-fuelsrc`,onClick:()=>j(M(`siparu-voyages`,Date.now(),`csv`),`text/csv`,D(n.list)),children:`CSV`}),n.list.length>0&&(0,L.jsx)(`button`,{type:`button`,className:`vy-fuelsrc`,onClick:()=>window.print(),children:`Print`})]})]}),n.err?(0,L.jsx)(`div`,{className:`vy-err`,children:n.err}):!n.loading&&n.list.length===0?(0,L.jsxs)(`div`,{className:`sp-empty`,children:[(0,L.jsx)(`div`,{className:`em-t`,children:`No voyages yet`}),(0,L.jsx)(`div`,{className:`em-s`,children:`Passages appear here once the boat gets under way.`})]}):(0,L.jsx)(`div`,{className:`vy-list`,children:n.list.map((e,t)=>(0,L.jsx)(oe,{v:e,prev:n.list[t+1],wasJoined:b.includes(e.id),open:s===e.id,track:l[e.id],fuelNotice:T,fuelMode:d,onFuelMode:f,onToggle:()=>O(e.id),onMerge:()=>A(()=>r.voyage.mergePrevious(e.id)),onUndoMerge:()=>A(()=>r.voyage.undoMerge(e.id)),editErr:s===e.id?S:null},e.id))}),h&&p&&(0,L.jsx)(J,{view:p,onClose:()=>_(!1),onApplied:()=>t(e=>e+1)})]})}function ie({v:e}){return(0,L.jsxs)(`div`,{className:`vy-active`,children:[(0,L.jsxs)(`div`,{className:`vy-active-hd`,children:[(0,L.jsx)(`span`,{className:`vy-pulse`,"aria-hidden":`true`}),`Under way`,e.start_port?` · from ${e.start_port}`:``,` · since `,$(e.start_ts)]}),(0,L.jsxs)(`div`,{className:`vy-active-grid`,children:[(0,L.jsxs)(`div`,{className:`vy-a-hero`,children:[(0,L.jsxs)(`div`,{className:`t`,children:[`Distance · `,(0,L.jsx)(`span`,{className:`sub`,children:`nm`})]}),(0,L.jsx)(`div`,{className:`n`,children:a(e.distance_nm,1)})]}),(0,L.jsxs)(`div`,{className:`vy-a-cell`,children:[(0,L.jsxs)(`div`,{className:`t`,children:[`Underway · `,(0,L.jsx)(`span`,{className:`sub`,children:`time`})]}),(0,L.jsx)(`div`,{className:`v`,children:Z(e.hours_underway)})]}),(0,L.jsxs)(`div`,{className:`vy-a-cell`,children:[(0,L.jsx)(`div`,{className:`t`,children:`Avg SOG`}),(0,L.jsx)(`div`,{className:`v`,children:e.avg_sog_kn===null?`·`:(0,L.jsxs)(L.Fragment,{children:[e.avg_sog_kn.toFixed(1),(0,L.jsx)(`span`,{className:`u`,children:`kn`})]})})]})]})]})}function ae({roll:e,loading:t}){let n=t?``:`·`;return(0,L.jsxs)(`div`,{className:`vy-cards`,children:[(0,L.jsxs)(`div`,{className:`c vy-hero`,children:[(0,L.jsxs)(`div`,{className:`t`,children:[`Distance · `,(0,L.jsx)(`span`,{className:`sub`,children:`nm`})]}),(0,L.jsx)(`div`,{className:`n${t?` skel`:``}`,children:t?`128.4`:e?a(e.distance_nm,1):n})]}),(0,L.jsxs)(`div`,{className:`c`,children:[(0,L.jsxs)(`div`,{className:`t`,children:[`Underway · `,(0,L.jsx)(`span`,{className:`sub`,children:`time`})]}),(0,L.jsx)(`div`,{className:`v`,children:e?Z(e.hours_underway):n})]}),(0,L.jsxs)(`div`,{className:`c`,children:[(0,L.jsx)(`div`,{className:`t`,children:`Avg SOG`}),(0,L.jsx)(`div`,{className:`v`,children:e?.avg_sog_kn==null?n:(0,L.jsxs)(L.Fragment,{children:[e.avg_sog_kn.toFixed(1),(0,L.jsx)(`span`,{className:`u`,children:`kn`})]})})]}),(0,L.jsxs)(`div`,{className:`c`,children:[(0,L.jsx)(`div`,{className:`t`,children:`Max SOG`}),(0,L.jsx)(`div`,{className:`v`,children:e?.max_sog_kn==null?n:(0,L.jsxs)(L.Fragment,{children:[e.max_sog_kn.toFixed(1),(0,L.jsx)(`span`,{className:`u`,children:`kn`})]})})]})]})}function oe({v:e,prev:t,wasJoined:n,open:r,track:i,fuelNotice:o,fuelMode:c,onFuelMode:l,onToggle:u,onMerge:d,onUndoMerge:f,editErr:p}){let m=e.end_ts===null,h=S(e.fuel_used_l,e.distance_nm,e.hours_underway,c),g=m?`${$(e.start_ts)} →`:`${$(e.start_ts)}-${$(e.end_ts)}`,v=e.avg_sog_kn===null?`·`:`${e.avg_sog_kn.toFixed(1)} kn`,y=ne(e);return(0,L.jsxs)(`div`,{className:`vy-rowwrap${r?` open`:``}`,children:[(0,L.jsxs)(`button`,{className:`vy-row`,onClick:u,"aria-expanded":r,children:[(0,L.jsxs)(`div`,{className:`vy-row-top`,children:[(0,L.jsx)(`span`,{className:`vy-date`,children:Q(e.start_ts)}),m&&(0,L.jsx)(`span`,{className:`vy-badge`,children:`Under way`}),(0,L.jsxs)(`span`,{className:`vy-dist`,children:[a(e.distance_nm,1),(0,L.jsx)(`span`,{className:`vy-unit`,children:`nm`})]})]}),y&&(0,L.jsx)(`div`,{className:`vy-route`,children:y}),(0,L.jsxs)(`div`,{className:`vy-row-sub`,children:[g,` · `,Z(e.hours_underway),` · `,v]})]}),r&&(0,L.jsxs)(`div`,{className:`vy-detail`,children:[i&&i.length>=2?(0,L.jsx)(B,{track:i}):(0,L.jsx)(`div`,{className:`vy-track-empty`,children:i?`Track too short to plot`:`Loading track…`}),(0,L.jsxs)(`div`,{className:`vy-meta`,children:[(0,L.jsxs)(`div`,{className:`vy-m`,children:[(0,L.jsx)(`span`,{className:`k`,children:`From`}),e.start_port&&(0,L.jsx)(`span`,{className:`val`,children:e.start_port}),(0,L.jsxs)(`span`,{className:e.start_port?`coord`:`val`,children:[s(e.start_lat,[`N`,`S`],2),` · `,s(e.start_lon,[`E`,`W`],2)]})]}),(0,L.jsxs)(`div`,{className:`vy-m`,children:[(0,L.jsx)(`span`,{className:`k`,children:`To`}),m?(0,L.jsx)(`span`,{className:`val`,children:`-`}):(0,L.jsxs)(L.Fragment,{children:[e.end_port&&(0,L.jsx)(`span`,{className:`val`,children:e.end_port}),(0,L.jsxs)(`span`,{className:e.end_port?`coord`:`val`,children:[s(e.end_lat,[`N`,`S`],2),` · `,s(e.end_lon,[`E`,`W`],2)]})]})]}),(0,L.jsxs)(`div`,{className:`vy-m`,children:[(0,L.jsx)(`span`,{className:`k`,children:`Avg SOG`}),(0,L.jsx)(`span`,{className:`val`,children:e.avg_sog_kn===null?`·`:`${e.avg_sog_kn.toFixed(1)} kn`})]}),(0,L.jsxs)(`div`,{className:`vy-m`,children:[(0,L.jsx)(`span`,{className:`k`,children:`Max SOG`}),(0,L.jsx)(`span`,{className:`val`,children:e.max_sog_kn===null?`·`:`${e.max_sog_kn.toFixed(1)} kn`})]}),e.fuel_used_l===null&&o&&(0,L.jsxs)(`div`,{className:`vy-m vy-m-fuel`,children:[(0,L.jsx)(`span`,{className:`k`,children:`Fuel`}),(0,L.jsx)(`span`,{className:`val vy-fuel-quiet`,children:o})]}),e.fuel_used_l!==null&&(0,L.jsxs)(`div`,{className:`vy-m vy-m-fuel`,children:[(0,L.jsx)(`span`,{className:`k`,children:`Fuel`}),(0,L.jsx)(`span`,{className:`val`,children:h??`·`}),(0,L.jsx)(`select`,{className:`vy-fuel-sel`,value:c,"aria-label":`Fuel unit`,onChange:e=>l(e.target.value),children:_.map(e=>(0,L.jsx)(`option`,{value:e.mode,children:e.label},e.mode))})]}),i&&i.length>0&&(0,L.jsxs)(`div`,{className:`vy-m vy-m-track`,children:[(0,L.jsx)(`span`,{className:`k`,children:`Track`}),(0,L.jsxs)(`button`,{type:`button`,className:`vy-fuelsrc`,onClick:()=>j(M(`siparu-voyage-${e.id}`,e.start_ts,`gpx`),`application/gpx+xml`,A(e,i)),children:[`GPX · `,i.length,` fixes`]})]}),!m&&(n||t)&&(0,L.jsxs)(`div`,{className:`vy-m vy-m-edit`,children:[(0,L.jsx)(`span`,{className:`k`,children:`Passage`}),n?(0,L.jsx)(`button`,{type:`button`,className:`vy-fuelsrc`,onClick:f,children:`Separate again`}):(0,L.jsxs)(`button`,{type:`button`,className:`vy-fuelsrc`,onClick:d,children:[`Join to `,$(t.start_ts),t.end_ts===null?``:`-${$(t.end_ts)}`,` · `,Q(t.start_ts)]})]}),p&&(0,L.jsx)(`div`,{className:`vy-m vy-m-editerr`,children:p})]})]})]})}function se(){return(0,L.jsx)(re,{})}export{se as default};