mirror of
https://github.com/dmduran12/pymc_console-dist.git
synced 2026-08-08 18:03:00 +02:00
Release v0.7.2
Automated sync from private repository. Built with obfuscation enabled.
This commit is contained in:
Vendored
+1
-1
@@ -1 +1 @@
|
||||
0.7.1
|
||||
0.7.2
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{j as e}from"./index-D3k5VxbW.js";import{b as o,c as t}from"./recharts-bmHCCfxU.js";const l={hero:{mobile:12},feature:{mobile:12,md:6,lg:4},standard:{mobile:12,sm:6,lg:4,xl:3},compact:{mobile:6,lg:3},widget:{mobile:6,sm:4,md:3,lg:2},auto:{mobile:12}},a={hero:"bento-row-hero",feature:"bento-row-feature",standard:"bento-row-standard",compact:"bento-row-compact",widget:"bento-row-widget",auto:"bento-row-auto"};function n({template:n,children:s,className:r,gap:c}){const i=l[n],d=a[n],b="none"===c?"gap-0":"sm"===c?"bento-gap-sm":"lg"===c?"bento-gap-lg":"bento-gap",g=o.Children.map(s,t=>o.isValidElement(t)?t.type===m?t:e.jsx(m,{span:i.mobile,sm:i.sm,md:i.md,lg:i.lg,xl:i.xl,children:t}):t);return e.jsx("div",{className:t("bento-row",d,b,r),children:g})}function s(e,o=""){const t=o?`${o}:`:"";return"full"===e?`${t}col-span-full`:"auto"===e?`${t}col-auto`:1.5===e?`${t}bento-col-1-5`:`${t}bento-col-${e}`}function m({children:o,span:l,sm:a,md:n,lg:m,xl:r,className:c}){const i=t("bento-cell",s(l),a&&s(a,"sm"),n&&s(n,"md"),m&&s(m,"lg"),r&&s(r,"xl"),c);return e.jsx("div",{className:i,children:o})}export{m as C,n as R};
|
||||
import{j as e}from"./index-CV7v97nI.js";import{b as o,c as t}from"./recharts-bmHCCfxU.js";const l={hero:{mobile:12},feature:{mobile:12,md:6,lg:4},standard:{mobile:12,sm:6,lg:4,xl:3},compact:{mobile:6,lg:3},widget:{mobile:6,sm:4,md:3,lg:2},auto:{mobile:12}},a={hero:"bento-row-hero",feature:"bento-row-feature",standard:"bento-row-standard",compact:"bento-row-compact",widget:"bento-row-widget",auto:"bento-row-auto"};function n({template:n,children:s,className:r,gap:c}){const i=l[n],d=a[n],b="none"===c?"gap-0":"sm"===c?"bento-gap-sm":"lg"===c?"bento-gap-lg":"bento-gap",g=o.Children.map(s,t=>o.isValidElement(t)?t.type===m?t:e.jsx(m,{span:i.mobile,sm:i.sm,md:i.md,lg:i.lg,xl:i.xl,children:t}):t);return e.jsx("div",{className:t("bento-row",d,b,r),children:g})}function s(e,o=""){const t=o?`${o}:`:"";return"full"===e?`${t}col-span-full`:"auto"===e?`${t}col-auto`:1.5===e?`${t}bento-col-1-5`:`${t}bento-col-${e}`}function m({children:o,span:l,sm:a,md:n,lg:m,xl:r,className:c}){const i=t("bento-cell",s(l),a&&s(a,"sm"),n&&s(n,"md"),m&&s(m,"lg"),r&&s(r,"xl"),c);return e.jsx("div",{className:i,children:o})}export{m as C,n as R};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{c as e,j as t}from"./index-D3k5VxbW.js";import{b as o,c as n}from"./recharts-bmHCCfxU.js";const s=e("check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]),a=e("copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]),r=e("map-pin",[["path",{d:"M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0",key:"1r0f0z"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}]]);function c({hash:e,prefixLength:r=8,suffixLength:c=6,full:i=!1,className:l,size:p="md"}){const[d,u]=o.useState(!1),[x,h]=o.useState(!1),y=o.useRef(null),m=o.useCallback(t=>{t.preventDefault(),t.stopPropagation(),y.current&&clearTimeout(y.current),function(e){if("undefined"!=typeof window&&(window.isSecureContext||"https:"===window.location.protocol||"localhost"===window.location.hostname)&&navigator.clipboard&&"function"==typeof navigator.clipboard.writeText)return navigator.clipboard.writeText(e).catch(()=>{}),!0;try{const t=window.scrollX,o=window.scrollY,n=document.createElement("textarea");n.value=e,n.style.position="fixed",n.style.left="-9999px",n.style.top="-9999px",n.style.opacity="0",n.style.pointerEvents="none",n.setAttribute("readonly",""),document.body.appendChild(n),n.focus({preventScroll:!0}),n.select(),n.setSelectionRange(0,e.length);const s=document.execCommand("copy");return document.body.removeChild(n),window.scrollTo(t,o),s}catch(t){return!1}}(e),u(!0),y.current=setTimeout(()=>u(!1),2e3)},[e]),w=i||e.length<=r+c+3?e:`${e.slice(0,r)}…${e.slice(-c)}`,f={xs:"text-[9px] px-1 py-0.5 gap-0.5",sm:"text-[10px] px-1.5 py-0.5 gap-1",md:"text-xs px-2 py-1 gap-1.5"}[p];return t.jsxs("button",{type:"button",onClick:m,onMouseEnter:()=>h(!0),onMouseLeave:()=>h(!1),className:n("inline-flex items-center font-mono rounded-md transition-all duration-200","bg-bg-subtle/80 hover:bg-bg-elevated border border-border-subtle hover:border-border-strong","cursor-pointer select-none",f,l),title:`Click to copy: ${e}`,"aria-label":`Copy hash ${e}`,children:[t.jsx("span",{className:n("transition-colors duration-200",d?"text-accent-success":"text-text-secondary"),children:w}),t.jsx("span",{className:n("flex items-center justify-center transition-all duration-200","xs"===p?"w-2.5 h-2.5":"sm"===p?"w-3 h-3":"w-3.5 h-3.5"),children:d?t.jsx(s,{className:n("text-accent-success","xs"===p?"w-2 h-2":"sm"===p?"w-2.5 h-2.5":"w-3 h-3")}):t.jsx(a,{className:n("transition-opacity duration-200",x?"opacity-70":"opacity-40","xs"===p?"w-2 h-2":"sm"===p?"w-2.5 h-2.5":"w-3 h-3")})})]})}export{a as C,c as H,r as M,s as a};
|
||||
import{c as e,j as t}from"./index-CV7v97nI.js";import{b as o,c as n}from"./recharts-bmHCCfxU.js";const s=e("check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]),a=e("copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]),r=e("map-pin",[["path",{d:"M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0",key:"1r0f0z"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}]]);function c({hash:e,prefixLength:r=8,suffixLength:c=6,full:i=!1,className:l,size:p="md"}){const[d,u]=o.useState(!1),[x,h]=o.useState(!1),y=o.useRef(null),m=o.useCallback(t=>{t.preventDefault(),t.stopPropagation(),y.current&&clearTimeout(y.current),function(e){if("undefined"!=typeof window&&(window.isSecureContext||"https:"===window.location.protocol||"localhost"===window.location.hostname)&&navigator.clipboard&&"function"==typeof navigator.clipboard.writeText)return navigator.clipboard.writeText(e).catch(()=>{}),!0;try{const t=window.scrollX,o=window.scrollY,n=document.createElement("textarea");n.value=e,n.style.position="fixed",n.style.left="-9999px",n.style.top="-9999px",n.style.opacity="0",n.style.pointerEvents="none",n.setAttribute("readonly",""),document.body.appendChild(n),n.focus({preventScroll:!0}),n.select(),n.setSelectionRange(0,e.length);const s=document.execCommand("copy");return document.body.removeChild(n),window.scrollTo(t,o),s}catch(t){return!1}}(e),u(!0),y.current=setTimeout(()=>u(!1),2e3)},[e]),w=i||e.length<=r+c+3?e:`${e.slice(0,r)}…${e.slice(-c)}`,f={xs:"text-[9px] px-1 py-0.5 gap-0.5",sm:"text-[10px] px-1.5 py-0.5 gap-1",md:"text-xs px-2 py-1 gap-1.5"}[p];return t.jsxs("button",{type:"button",onClick:m,onMouseEnter:()=>h(!0),onMouseLeave:()=>h(!1),className:n("inline-flex items-center font-mono rounded-md transition-all duration-200","bg-bg-subtle/80 hover:bg-bg-elevated border border-border-subtle hover:border-border-strong","cursor-pointer select-none",f,l),title:`Click to copy: ${e}`,"aria-label":`Copy hash ${e}`,children:[t.jsx("span",{className:n("transition-colors duration-200",d?"text-accent-success":"text-text-secondary"),children:w}),t.jsx("span",{className:n("flex items-center justify-center transition-all duration-200","xs"===p?"w-2.5 h-2.5":"sm"===p?"w-3 h-3":"w-3.5 h-3.5"),children:d?t.jsx(s,{className:n("text-accent-success","xs"===p?"w-2 h-2":"sm"===p?"w-2.5 h-2.5":"w-3 h-3")}):t.jsx(a,{className:n("transition-opacity duration-200",x?"opacity-70":"opacity-40","xs"===p?"w-2 h-2":"sm"===p?"w-2.5 h-2.5":"w-3 h-3")})})]})}export{a as C,c as H,r as M,s as a};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{j as e}from"./index-D3k5VxbW.js";import{c as s}from"./recharts-bmHCCfxU.js";function a({children:a,className:l}){return e.jsx("div",{className:s("section-gap",l),children:a})}function l({title:s,icon:a,controls:l,subtitle:c}){return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("h1",{className:"type-title text-text-primary flex items-center gap-3",children:[a&&e.jsx("span",{className:"w-6 h-6 text-accent-primary flex-shrink-0",children:a}),s]}),l&&e.jsx("div",{className:"flex items-center gap-2 sm:gap-3",children:l})]}),c&&e.jsx("div",{children:c})]})}const c={sm:"card-sm",md:"card-md",lg:"card-lg",hero:"card-hero",auto:"card-auto"};function t({children:a,size:l,compact:t,noPadding:r,className:i,style:n,onClick:d}){return e.jsx("div",{className:s("glass-card h-full flex flex-col",!r&&(t?"card-padding-sm":"card-padding"),l&&c[l],i),style:n,onClick:d,children:a})}function r({icon:a,title:l,badge:c,subtitle:t,actions:r,iconColor:i="text-accent-primary",largeTitle:n=!1,listHeader:d=!1}){return e.jsxs("div",{className:s("flex flex-col gap-1 flex-shrink-0",d?"px-4 py-3 border-b border-border-subtle bg-bg-elevated/20":"mb-3"),children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[a&&e.jsx("span",{className:s("icon-md",i),children:a}),e.jsx("span",{className:n?"type-subheading text-text-primary":"type-micro",children:l}),c&&e.jsx("span",{className:"pill-tag",children:c})]}),r&&e.jsx("div",{className:"flex items-center gap-2 flex-wrap",children:r})]}),t&&e.jsx("p",{className:"type-label text-text-muted ml-7",children:t})]})}export{t as C,a as P,l as a,r as b};
|
||||
import{j as e}from"./index-CV7v97nI.js";import{c as s}from"./recharts-bmHCCfxU.js";function a({children:a,className:l}){return e.jsx("div",{className:s("section-gap",l),children:a})}function l({title:s,icon:a,controls:l,subtitle:c}){return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxs("h1",{className:"type-title text-text-primary flex items-center gap-3",children:[a&&e.jsx("span",{className:"w-6 h-6 text-accent-primary flex-shrink-0",children:a}),s]}),l&&e.jsx("div",{className:"flex items-center gap-2 sm:gap-3",children:l})]}),c&&e.jsx("div",{children:c})]})}const c={sm:"card-sm",md:"card-md",lg:"card-lg",hero:"card-hero",auto:"card-auto"};function t({children:a,size:l,compact:t,noPadding:r,className:i,style:n,onClick:d}){return e.jsx("div",{className:s("glass-card h-full flex flex-col",!r&&(t?"card-padding-sm":"card-padding"),l&&c[l],i),style:n,onClick:d,children:a})}function r({icon:a,title:l,badge:c,subtitle:t,actions:r,iconColor:i="text-accent-primary",largeTitle:n=!1,listHeader:d=!1}){return e.jsxs("div",{className:s("flex flex-col gap-1 flex-shrink-0",d?"px-4 py-3 border-b border-border-subtle bg-bg-elevated/20":"mb-3"),children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[a&&e.jsx("span",{className:s("icon-md",i),children:a}),e.jsx("span",{className:n?"type-subheading text-text-primary":"type-micro",children:l}),c&&e.jsx("span",{className:"pill-tag",children:c})]}),r&&e.jsx("div",{className:"flex items-center gap-2 flex-wrap",children:r})]}),t&&e.jsx("p",{className:"type-label text-text-muted ml-7",children:t})]})}export{t as C,a as P,l as a,r as b};
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{j as e}from"./index-D3k5VxbW.js";import{b as t}from"./recharts-bmHCCfxU.js";import{M as o,S as n,L as r,a as i,P as s}from"./maplibre-gl-Dk-KchcY.js";import"./maplibre-gl-CFO9X1Ek.js";const a="#4F46E5",l="#F9D26F",d="#B49DFF",c="#39D98A",u="#B49DFF";function p(e,t,o,n=!1,r=!1,i=!1){let s;s=r?c:i?u:e?a:t?"#6366F1":o?"transparent":l;const p=e||t||!o||r||i;return`<div style="\n width: 14px;\n height: 14px;\n background: ${s};\n border-radius: 50%;\n border: ${p?0:5}px solid ${p?"transparent":"#4338CA"};\n box-sizing: border-box;\n transition: box-shadow 0.15s ease;\n ${n?`box-shadow: 0 0 0 3px ${d}40, 0 0 8px ${d}60;`:""}\n "></div>`}const m={id:"path-line",type:"line",paint:{"line-color":"#3B3F4A","line-width":2,"line-opacity":.7},layout:{"line-cap":"round","line-join":"round"}};function x({resolvedPath:d,localNode:x,hubNodes:h=[],hoveredHopIndex:f,onHoverHop:b}){const g=t.useRef(null),y=t.useMemo(()=>new Set(h),[h]),[j,k]=t.useState(null),{positions:v,markers:C,pathLineGeoJSON:N}=t.useMemo(()=>{const e=[],t=[],o=[];d.hops.forEach((n,r)=>{const i=n.candidates.filter(e=>{return t=e.latitude,o=e.longitude,0!==t||0!==o;var t,o});if(0===i.length)return;const s=[...i].sort((e,t)=>t.probability-e.probability)[0];o.push([s.longitude,s.latitude]);const a=!0===n.isSource,l=!0===n.isDestination;i.forEach((o,s)=>{const d=[o.latitude,o.longitude];e.push(d);const c=0===s;t.push({position:d,prefix:n.prefix,confidence:n.confidence,candidateCount:i.length,hopIndex:r,candidate:o,isHub:y.has(o.hash),isPrimary:c,isSource:a,isDestination:l})})});const n={type:"FeatureCollection",features:o.length>=2?[{type:"Feature",properties:{},geometry:{type:"LineString",coordinates:o}}]:[]};return{positions:e,markers:t,pathLineGeoJSON:n}},[d,y]),{center:S,zoom:F}=t.useMemo(()=>{if(0===v.length)return x?{center:[x.longitude,x.latitude],zoom:10}:{center:[0,0],zoom:2};let e=1/0,t=-1/0,o=1/0,n=-1/0;for(const[c,u]of v)c<e&&(e=c),c>t&&(t=c),u<o&&(o=u),u>n&&(n=u);const r=(e+t)/2,i=(o+n)/2,s=t-e,a=n-o,l=Math.max(s,a);let d;return d=l<.01?15:l<.05?13:l<.1?12:l<.5?10:l<1?9:l<5?7:5,{center:[i,r],zoom:d}},[v,x]);t.useEffect(()=>{if(!g.current||v.length<2)return;let e=1/0,t=-1/0,o=1/0,n=-1/0;for(const[r,i]of v)r<e&&(e=r),r>t&&(t=r),i<o&&(o=i),i>n&&(n=i);g.current.fitBounds([[o,e],[n,t]],{padding:30,maxZoom:16,duration:0})},[v]);const L=t.useCallback(e=>{k({longitude:e.position[1],latitude:e.position[0],marker:e})},[]);return 0===v.length?e.jsx("div",{className:"h-[200px] flex items-center justify-center text-text-muted text-sm bg-bg-elevated",children:"No mappable path data"}):e.jsxs(o,{ref:g,initialViewState:{longitude:S[0],latitude:S[1],zoom:F},style:{height:"200px",width:"100%"},mapStyle:"https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",attributionControl:!1,children:[N.features.length>0&&e.jsx(n,{id:"path-line-source",type:"geojson",data:N,children:e.jsx(r,{...m})}),C.map(t=>{const o=f===t.hopIndex;return e.jsx(i,{longitude:t.position[1],latitude:t.position[0],anchor:"center",onClick:()=>L(t),children:e.jsx("div",{style:{cursor:"pointer",opacity:t.isPrimary?1:.5},onMouseEnter:()=>null==b?void 0:b(t.hopIndex),onMouseLeave:()=>null==b?void 0:b(null),dangerouslySetInnerHTML:{__html:p(t.candidate.isLocal||!1,t.isHub,t.isPrimary,o,t.isSource,t.isDestination)}})},`${t.hopIndex}-${t.candidate.hash}`)}),j&&e.jsx(s,{longitude:j.longitude,latitude:j.latitude,anchor:"bottom",offset:[0,-12],closeOnClick:!1,onClose:()=>k(null),className:"maplibre-popup",children:e.jsxs("div",{className:"text-xs",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-semibold",children:j.marker.candidate.name}),j.marker.isSource&&e.jsx("span",{className:"px-1 py-0.5 text-[8px] font-bold rounded",style:{backgroundColor:c,color:"#000"},children:"SRC"}),j.marker.isDestination&&e.jsx("span",{className:"px-1 py-0.5 text-[8px] font-bold rounded",style:{backgroundColor:u,color:"#000"},children:"DST"}),j.marker.isHub&&e.jsx("span",{className:"px-1 py-0.5 text-[8px] font-bold rounded",style:{backgroundColor:"#FBBF24",color:"#000"},children:"HUB"}),j.marker.candidate.isLocal&&e.jsx("span",{className:"px-1 py-0.5 text-[8px] font-bold rounded",style:{backgroundColor:a,color:"#fff"},children:"LOCAL"})]}),e.jsxs("div",{className:"text-text-muted font-mono text-[10px]",children:[j.marker.prefix," • ",j.marker.candidate.hash.slice(0,10),"..."]}),!j.marker.isPrimary&&j.marker.candidateCount>1&&e.jsxs("div",{style:{color:l},children:["Alternative (",(100*j.marker.candidate.probability).toFixed(0),"%)"]}),j.marker.isPrimary&&j.marker.candidateCount>1&&e.jsxs("div",{className:"text-text-muted",children:[j.marker.candidateCount," candidates"]})]})})]})}export{x as default};
|
||||
import{j as e}from"./index-CV7v97nI.js";import{b as t}from"./recharts-bmHCCfxU.js";import{M as o,S as n,L as r,a as i,P as s}from"./maplibre-gl-DPqA1aeF.js";import"./maplibre-gl-CFO9X1Ek.js";const a="#4F46E5",l="#F9D26F",d="#B49DFF",c="#39D98A",u="#B49DFF";function p(e,t,o,n=!1,r=!1,i=!1){let s;s=r?c:i?u:e?a:t?"#6366F1":o?"transparent":l;const p=e||t||!o||r||i;return`<div style="\n width: 14px;\n height: 14px;\n background: ${s};\n border-radius: 50%;\n border: ${p?0:5}px solid ${p?"transparent":"#4338CA"};\n box-sizing: border-box;\n transition: box-shadow 0.15s ease;\n ${n?`box-shadow: 0 0 0 3px ${d}40, 0 0 8px ${d}60;`:""}\n "></div>`}const m={id:"path-line",type:"line",paint:{"line-color":"#3B3F4A","line-width":2,"line-opacity":.7},layout:{"line-cap":"round","line-join":"round"}};function x({resolvedPath:d,localNode:x,hubNodes:h=[],hoveredHopIndex:f,onHoverHop:b}){const g=t.useRef(null),y=t.useMemo(()=>new Set(h),[h]),[j,k]=t.useState(null),{positions:v,markers:C,pathLineGeoJSON:N}=t.useMemo(()=>{const e=[],t=[],o=[];d.hops.forEach((n,r)=>{const i=n.candidates.filter(e=>{return t=e.latitude,o=e.longitude,0!==t||0!==o;var t,o});if(0===i.length)return;const s=[...i].sort((e,t)=>t.probability-e.probability)[0];o.push([s.longitude,s.latitude]);const a=!0===n.isSource,l=!0===n.isDestination;i.forEach((o,s)=>{const d=[o.latitude,o.longitude];e.push(d);const c=0===s;t.push({position:d,prefix:n.prefix,confidence:n.confidence,candidateCount:i.length,hopIndex:r,candidate:o,isHub:y.has(o.hash),isPrimary:c,isSource:a,isDestination:l})})});const n={type:"FeatureCollection",features:o.length>=2?[{type:"Feature",properties:{},geometry:{type:"LineString",coordinates:o}}]:[]};return{positions:e,markers:t,pathLineGeoJSON:n}},[d,y]),{center:S,zoom:F}=t.useMemo(()=>{if(0===v.length)return x?{center:[x.longitude,x.latitude],zoom:10}:{center:[0,0],zoom:2};let e=1/0,t=-1/0,o=1/0,n=-1/0;for(const[c,u]of v)c<e&&(e=c),c>t&&(t=c),u<o&&(o=u),u>n&&(n=u);const r=(e+t)/2,i=(o+n)/2,s=t-e,a=n-o,l=Math.max(s,a);let d;return d=l<.01?15:l<.05?13:l<.1?12:l<.5?10:l<1?9:l<5?7:5,{center:[i,r],zoom:d}},[v,x]);t.useEffect(()=>{if(!g.current||v.length<2)return;let e=1/0,t=-1/0,o=1/0,n=-1/0;for(const[r,i]of v)r<e&&(e=r),r>t&&(t=r),i<o&&(o=i),i>n&&(n=i);g.current.fitBounds([[o,e],[n,t]],{padding:30,maxZoom:16,duration:0})},[v]);const L=t.useCallback(e=>{k({longitude:e.position[1],latitude:e.position[0],marker:e})},[]);return 0===v.length?e.jsx("div",{className:"h-[200px] flex items-center justify-center text-text-muted text-sm bg-bg-elevated",children:"No mappable path data"}):e.jsxs(o,{ref:g,initialViewState:{longitude:S[0],latitude:S[1],zoom:F},style:{height:"200px",width:"100%"},mapStyle:"https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",attributionControl:!1,children:[N.features.length>0&&e.jsx(n,{id:"path-line-source",type:"geojson",data:N,children:e.jsx(r,{...m})}),C.map(t=>{const o=f===t.hopIndex;return e.jsx(i,{longitude:t.position[1],latitude:t.position[0],anchor:"center",onClick:()=>L(t),children:e.jsx("div",{style:{cursor:"pointer",opacity:t.isPrimary?1:.5},onMouseEnter:()=>null==b?void 0:b(t.hopIndex),onMouseLeave:()=>null==b?void 0:b(null),dangerouslySetInnerHTML:{__html:p(t.candidate.isLocal||!1,t.isHub,t.isPrimary,o,t.isSource,t.isDestination)}})},`${t.hopIndex}-${t.candidate.hash}`)}),j&&e.jsx(s,{longitude:j.longitude,latitude:j.latitude,anchor:"bottom",offset:[0,-12],closeOnClick:!1,onClose:()=>k(null),className:"maplibre-popup",children:e.jsxs("div",{className:"text-xs",children:[e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"font-semibold",children:j.marker.candidate.name}),j.marker.isSource&&e.jsx("span",{className:"px-1 py-0.5 text-[8px] font-bold rounded",style:{backgroundColor:c,color:"#000"},children:"SRC"}),j.marker.isDestination&&e.jsx("span",{className:"px-1 py-0.5 text-[8px] font-bold rounded",style:{backgroundColor:u,color:"#000"},children:"DST"}),j.marker.isHub&&e.jsx("span",{className:"px-1 py-0.5 text-[8px] font-bold rounded",style:{backgroundColor:"#FBBF24",color:"#000"},children:"HUB"}),j.marker.candidate.isLocal&&e.jsx("span",{className:"px-1 py-0.5 text-[8px] font-bold rounded",style:{backgroundColor:a,color:"#fff"},children:"LOCAL"})]}),e.jsxs("div",{className:"text-text-muted font-mono text-[10px]",children:[j.marker.prefix," • ",j.marker.candidate.hash.slice(0,10),"..."]}),!j.marker.isPrimary&&j.marker.candidateCount>1&&e.jsxs("div",{style:{color:l},children:["Alternative (",(100*j.marker.candidate.probability).toFixed(0),"%)"]}),j.marker.isPrimary&&j.marker.candidateCount>1&&e.jsxs("div",{className:"text-text-muted",children:[j.marker.candidateCount," candidates"]})]})})]})}export{x as default};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{c as e,j as t}from"./index-D3k5VxbW.js";import{c as s,b as a}from"./recharts-bmHCCfxU.js";const n=e("signal-high",[["path",{d:"M2 20h.01",key:"4haj6o"}],["path",{d:"M7 20v-4",key:"j294jx"}],["path",{d:"M12 20v-8",key:"i3yub9"}],["path",{d:"M17 20V8",key:"1tkaf5"}]]),r=e("signal-low",[["path",{d:"M2 20h.01",key:"4haj6o"}],["path",{d:"M7 20v-4",key:"j294jx"}]]),c=e("signal-medium",[["path",{d:"M2 20h.01",key:"4haj6o"}],["path",{d:"M7 20v-4",key:"j294jx"}],["path",{d:"M12 20v-8",key:"i3yub9"}]]),o=e("signal-zero",[["path",{d:"M2 20h.01",key:"4haj6o"}]]),i=e("signal",[["path",{d:"M2 20h.01",key:"4haj6o"}],["path",{d:"M7 20v-4",key:"j294jx"}],["path",{d:"M12 20v-8",key:"i3yub9"}],["path",{d:"M17 20V8",key:"1tkaf5"}],["path",{d:"M22 4v16",key:"sih9yq"}]]);function d(e){return e>=-90?"excellent":e>=-100?"good":e>=-110?"fair":e>=-120?"weak":"poor"}function l(e,t){if(!t)return"bg-white/10";switch(e){case"excellent":return"bg-accent-success";case"good":return"bg-[#71F8E5]";case"fair":return"bg-[#F9D26F]";case"weak":return"bg-[#FB923C]";case"poor":return"bg-accent-danger";default:return"bg-white/20"}}function x({rssi:e,className:a="w-4 h-4"}){const l=d(e),x=function(e){switch(e){case"excellent":return"text-accent-success";case"good":return"text-[#71F8E5]";case"fair":return"text-[#F9D26F]";case"weak":return"text-[#FB923C]";case"poor":return"text-accent-danger";default:return"text-text-muted"}}(l),h=s(x,a);switch(l){case"excellent":return t.jsx(i,{className:h});case"good":return t.jsx(n,{className:h});case"fair":return t.jsx(c,{className:h});case"weak":return t.jsx(r,{className:h});default:return t.jsx(o,{className:h})}}const h=a.memo(function({rssi:e,snr:a,compact:n=!1,showValues:r=!0}){const c=d(e),o={excellent:4,good:3,fair:2,weak:1,poor:0}[c];return n?t.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[r&&t.jsx("span",{className:"text-[10px] font-mono text-text-secondary",children:e}),t.jsx("div",{className:"flex items-end gap-[2px] h-3",children:Array.from({length:4}).map((e,a)=>t.jsx("div",{className:s("w-[3px] rounded-[1px] transition-colors",l(c,a<o)),style:{height:(a+1)/4*100+"%"}},a))})]}):t.jsxs("div",{className:"flex items-center justify-end gap-2",children:[r&&t.jsxs("div",{className:"flex flex-col items-end",children:[t.jsxs("span",{className:"text-xs font-mono text-text-secondary leading-tight",children:[e," dBm"]}),void 0!==a&&t.jsxs("span",{className:"text-[10px] font-mono text-text-muted leading-tight",children:[a.toFixed(1)," dB"]})]}),t.jsx("div",{className:"flex items-end gap-[2px] h-3.5",children:Array.from({length:4}).map((e,a)=>t.jsx("div",{className:s("w-[3px] rounded-[1px] transition-colors",l(c,a<o)),style:{height:(a+1)/4*100+"%"}},a))})]})});function u(e){const t=d(e);return t.charAt(0).toUpperCase()+t.slice(1)}export{h as S,x as a,u as g};
|
||||
import{c as e,j as t}from"./index-CV7v97nI.js";import{c as s,b as a}from"./recharts-bmHCCfxU.js";const n=e("signal-high",[["path",{d:"M2 20h.01",key:"4haj6o"}],["path",{d:"M7 20v-4",key:"j294jx"}],["path",{d:"M12 20v-8",key:"i3yub9"}],["path",{d:"M17 20V8",key:"1tkaf5"}]]),r=e("signal-low",[["path",{d:"M2 20h.01",key:"4haj6o"}],["path",{d:"M7 20v-4",key:"j294jx"}]]),c=e("signal-medium",[["path",{d:"M2 20h.01",key:"4haj6o"}],["path",{d:"M7 20v-4",key:"j294jx"}],["path",{d:"M12 20v-8",key:"i3yub9"}]]),o=e("signal-zero",[["path",{d:"M2 20h.01",key:"4haj6o"}]]),i=e("signal",[["path",{d:"M2 20h.01",key:"4haj6o"}],["path",{d:"M7 20v-4",key:"j294jx"}],["path",{d:"M12 20v-8",key:"i3yub9"}],["path",{d:"M17 20V8",key:"1tkaf5"}],["path",{d:"M22 4v16",key:"sih9yq"}]]);function d(e){return e>=-90?"excellent":e>=-100?"good":e>=-110?"fair":e>=-120?"weak":"poor"}function l(e,t){if(!t)return"bg-white/10";switch(e){case"excellent":return"bg-accent-success";case"good":return"bg-[#71F8E5]";case"fair":return"bg-[#F9D26F]";case"weak":return"bg-[#FB923C]";case"poor":return"bg-accent-danger";default:return"bg-white/20"}}function x({rssi:e,className:a="w-4 h-4"}){const l=d(e),x=function(e){switch(e){case"excellent":return"text-accent-success";case"good":return"text-[#71F8E5]";case"fair":return"text-[#F9D26F]";case"weak":return"text-[#FB923C]";case"poor":return"text-accent-danger";default:return"text-text-muted"}}(l),h=s(x,a);switch(l){case"excellent":return t.jsx(i,{className:h});case"good":return t.jsx(n,{className:h});case"fair":return t.jsx(c,{className:h});case"weak":return t.jsx(r,{className:h});default:return t.jsx(o,{className:h})}}const h=a.memo(function({rssi:e,snr:a,compact:n=!1,showValues:r=!0}){const c=d(e),o={excellent:4,good:3,fair:2,weak:1,poor:0}[c];return n?t.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[r&&t.jsx("span",{className:"text-[10px] font-mono text-text-secondary",children:e}),t.jsx("div",{className:"flex items-end gap-[2px] h-3",children:Array.from({length:4}).map((e,a)=>t.jsx("div",{className:s("w-[3px] rounded-[1px] transition-colors",l(c,a<o)),style:{height:(a+1)/4*100+"%"}},a))})]}):t.jsxs("div",{className:"flex items-center justify-end gap-2",children:[r&&t.jsxs("div",{className:"flex flex-col items-end",children:[t.jsxs("span",{className:"text-xs font-mono text-text-secondary leading-tight",children:[e," dBm"]}),void 0!==a&&t.jsxs("span",{className:"text-[10px] font-mono text-text-muted leading-tight",children:[a.toFixed(1)," dB"]})]}),t.jsx("div",{className:"flex items-end gap-[2px] h-3.5",children:Array.from({length:4}).map((e,a)=>t.jsx("div",{className:s("w-[3px] rounded-[1px] transition-colors",l(c,a<o)),style:{height:(a+1)/4*100+"%"}},a))})]})});function u(e){const t=d(e);return t.charAt(0).toUpperCase()+t.slice(1)}export{h as S,x as a,u as g};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{b as e}from"./recharts-bmHCCfxU.js";import{j as t}from"./index-D3k5VxbW.js";function o(t,o){const[s,r]=e.useState(t);return e.useEffect(()=>{const e=setTimeout(()=>r(t),o);return()=>clearTimeout(e)},[t,o]),s}const s=e.memo(function({ranges:e,selectedIndex:o,onSelect:s}){return t.jsx("div",{className:"toggle-group flex-shrink-0 overflow-x-auto",children:e.map((e,r)=>t.jsx("button",{onClick:()=>s(r),className:"toggle-group-item "+(o===r?"active":""),children:e.label},e.label))})});export{s as T,o as u};
|
||||
import{b as e}from"./recharts-bmHCCfxU.js";import{j as t}from"./index-CV7v97nI.js";function o(t,o){const[s,r]=e.useState(t);return e.useEffect(()=>{const e=setTimeout(()=>r(t),o);return()=>clearTimeout(e)},[t,o]),s}const s=e.memo(function({ranges:e,selectedIndex:o,onSelect:s}){return t.jsx("div",{className:"toggle-group flex-shrink-0 overflow-x-auto",children:e.map((e,r)=>t.jsx("button",{onClick:()=>s(r),className:"toggle-group-item "+(o===r?"active":""),children:e.label},e.label))})});export{s as T,o as u};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{c as a}from"./index-D3k5VxbW.js";const t=a("activity",[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]]);export{t as A};
|
||||
import{c as a}from"./index-CV7v97nI.js";const t=a("activity",[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]]);export{t as A};
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{c}from"./index-CV7v97nI.js";const r=c("circle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);export{r as C};
|
||||
-1
@@ -1 +0,0 @@
|
||||
import{c}from"./index-D3k5VxbW.js";const r=c("circle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);export{r as C};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{c as a}from"./index-D3k5VxbW.js";const s=a("house",[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"r6nss1"}]]);export{s as H};
|
||||
import{c as a}from"./index-CV7v97nI.js";const s=a("house",[["path",{d:"M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8",key:"5wwlr5"}],["path",{d:"M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",key:"r6nss1"}]]);export{s as H};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{c as e}from"./index-D3k5VxbW.js";const c=e("info",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]]);export{c as I};
|
||||
import{c as e}from"./index-CV7v97nI.js";const c=e("info",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]]);export{c as I};
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{c as a}from"./index-D3k5VxbW.js";const e=a("loader-circle",[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]]);export{e as L};
|
||||
import{c as a}from"./index-CV7v97nI.js";const e=a("loader-circle",[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]]);export{e as L};
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{c as a}from"./index-D3k5VxbW.js";const e=a("refresh-cw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);export{e as R};
|
||||
import{c as a}from"./index-CV7v97nI.js";const e=a("refresh-cw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);export{e as R};
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{c as t}from"./index-D3k5VxbW.js";const e=t("network",[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]]),h=t("trending-up",[["path",{d:"M16 7h6v6",key:"box55l"}],["path",{d:"m22 7-8.5 8.5-5-5L2 17",key:"1t1m79"}]]);export{e as N,h as T};
|
||||
import{c as t}from"./index-CV7v97nI.js";const e=t("network",[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]]),h=t("trending-up",[["path",{d:"M16 7h6v6",key:"box55l"}],["path",{d:"m22 7-8.5 8.5-5-5L2 17",key:"1t1m79"}]]);export{e as N,h as T};
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{c as a}from"./index-D3k5VxbW.js";const e=a("triangle-alert",[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]]);export{e as T};
|
||||
import{c as a}from"./index-CV7v97nI.js";const e=a("triangle-alert",[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]]);export{e as T};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{c as a}from"./index-D3k5VxbW.js";const e=a("users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]]);export{e as U};
|
||||
import{c as a}from"./index-CV7v97nI.js";const e=a("users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]]);export{e as U};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{c as a}from"./index-D3k5VxbW.js";const t=a("minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]),d=a("trending-down",[["path",{d:"M16 17h6v-6",key:"t6n2it"}],["path",{d:"m22 17-8.5-8.5-5 5L2 7",key:"x473p"}]]),h=a("zap",[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]]);export{t as M,d as T,h as Z};
|
||||
import{c as a}from"./index-CV7v97nI.js";const t=a("minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]),d=a("trending-down",[["path",{d:"M16 17h6v-6",key:"t6n2it"}],["path",{d:"m22 17-8.5-8.5-5 5L2 7",key:"x473p"}]]),h=a("zap",[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]]);export{t as M,d as T,h as Z};
|
||||
Vendored
+2
-2
@@ -38,10 +38,10 @@
|
||||
--font-data: 'JetBrains Mono', 'SF Mono', Monaco, monospace;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/index-D3k5VxbW.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-CV7v97nI.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/maplibre-gl-CFO9X1Ek.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/recharts-bmHCCfxU.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Cy8Uf58w.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Bmz50KcY.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pymc_console",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.2",
|
||||
"description": "Vite + React Dashboard for pyMC_Repeater",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -902,11 +902,10 @@ do_install() {
|
||||
|
||||
# Apply patches to /opt/pymc_repeater (the installed location, not the clone)
|
||||
print_info "Patching installed files..."
|
||||
patch_api_endpoints "$INSTALL_DIR" # PATCH 1: Radio config API endpoint
|
||||
# PATCH 1 & 5 removed - merged upstream in PR #36 (feat/identity branch)
|
||||
patch_logging_section "$INSTALL_DIR" # PATCH 2: Ensure logging section exists
|
||||
patch_log_level_api "$INSTALL_DIR" # PATCH 3: Log level toggle API
|
||||
patch_mesh_cli "$INSTALL_DIR" # PATCH 4: MeshCore CLI parity
|
||||
patch_stats_api "$INSTALL_DIR" # PATCH 5: Extend stats API with MeshCore config
|
||||
patch_private_key_api "$INSTALL_DIR" # PATCH 6: Private key get/set API
|
||||
|
||||
# =========================================================================
|
||||
@@ -2273,22 +2272,20 @@ run_upstream_installer() {
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# UPSTREAM PATCHES
|
||||
# PATCH REGISTRY
|
||||
# ============================================================================
|
||||
# These patches modify pyMC_Repeater to support pymc_console features.
|
||||
# They are applied during install/upgrade and should be converted to a
|
||||
# clean PR for https://github.com/rightup/pyMC_Repeater once stable.
|
||||
# Core patches that enhance pyMC_Repeater with pyMC Console features.
|
||||
# These patches are candidates for upstream PR submission.
|
||||
#
|
||||
# PATCH REGISTRY:
|
||||
# ---------------
|
||||
# 1. patch_api_endpoints (api_endpoints.py)
|
||||
# - Adds POST /api/update_radio_config endpoint
|
||||
# - Allows web UI to update radio settings and save to config.yaml
|
||||
# - PR Status: Pending
|
||||
# REMOVED (Merged Upstream in PR #36 - feat/identity branch):
|
||||
# - patch_api_endpoints - /api/update_radio_config endpoint
|
||||
# - patch_stats_api - Extended /api/stats with max_flood_hops, advert_interval_minutes, rx_delay_base
|
||||
#
|
||||
# Remaining Patches:
|
||||
#
|
||||
# 2. patch_logging_section (main.py)
|
||||
# - Ensures config['logging'] exists before setting level from --log-level
|
||||
# - Prevents KeyError when config.yaml lacks 'logging' section (affects DEBUG arg)
|
||||
# - Ensures config['logging'] exists before setting level from --log-level arg
|
||||
# - Fixes KeyError when service starts with --log-level DEBUG
|
||||
# - PR Status: Pending
|
||||
#
|
||||
# 3. patch_log_level_api (api_endpoints.py)
|
||||
@@ -2302,10 +2299,11 @@ run_upstream_installer() {
|
||||
# - Implemented via external Python patch script (patches/mesh_cli_enhancements.py)
|
||||
# - PR Status: Pending
|
||||
#
|
||||
# 5. patch_stats_api (engine.py)
|
||||
# - Extends /api/stats config with MeshCore CLI-accessible values
|
||||
# - Adds: max_flood_hops, advert_interval_minutes, rx_delay_base to config.repeater
|
||||
# - Enables Terminal `get flood.max`, `get advert.interval`, `get rxdelay` commands
|
||||
# 6. patch_private_key_api (mesh_cli.py)
|
||||
# - Adds get/set prv.key for private key management via Terminal
|
||||
# - Stores key in config['mesh']['identity_key']
|
||||
# - PR Status: Pending
|
||||
#
|
||||
# - PR Status: Pending
|
||||
#
|
||||
# NOTE: patch_static_file_serving was removed in v0.4.0 (SPA migration).
|
||||
@@ -2324,286 +2322,20 @@ run_upstream_installer() {
|
||||
# ============================================================================
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# PATCH 1: Radio Configuration API Endpoint
|
||||
# PATCH 1: Radio Configuration API Endpoint [REMOVED - MERGED UPSTREAM PR #36]
|
||||
# ------------------------------------------------------------------------------
|
||||
# File: repeater/web/api_endpoints.py
|
||||
# Purpose: Allow web UI to update radio settings without SSH/CLI
|
||||
# Changes:
|
||||
# - Add POST /api/update_radio_config endpoint
|
||||
# - Accepts: frequency_mhz, bandwidth_khz, spreading_factor, coding_rate, tx_power
|
||||
# - Validates input ranges (SF 5-12, CR 5-8, power 2-22 dBm)
|
||||
# - Saves to config.yaml via existing _save_config_to_file()
|
||||
# - Returns restart_required: true (live radio update not yet supported)
|
||||
# This patch was merged upstream in PR #36 to the feat/identity branch.
|
||||
# The patch is preserved below (commented out) for reference and for users
|
||||
# who may still be on main/dev branches before the PR is merged there.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Patch removed - see PR #36: https://github.com/rightup/pyMC_Repeater/pull/36
|
||||
patch_api_endpoints() {
|
||||
local target_dir="${1:-$CLONE_DIR}"
|
||||
local api_file="$target_dir/repeater/web/api_endpoints.py"
|
||||
|
||||
if [ ! -f "$api_file" ]; then
|
||||
print_warning "api_endpoints.py not found, skipping patch"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Patch version - increment when patch content changes
|
||||
local PATCH_VERSION="5" # v1: radio only, v2: +delay settings, v3: TX power 30dBm, v4: +repeater config, v5: live updates
|
||||
|
||||
# Check if current version is already applied
|
||||
if grep -q "PYMC_CONSOLE_PATCH_V${PATCH_VERSION}" "$api_file" 2>/dev/null; then
|
||||
print_info "API endpoints patch v${PATCH_VERSION} already applied"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove any existing patch (versioned or legacy) before applying new one
|
||||
if grep -q 'def update_radio_config' "$api_file" 2>/dev/null; then
|
||||
local old_ver="legacy"
|
||||
if grep -q 'PYMC_CONSOLE_PATCH_V' "$api_file" 2>/dev/null; then
|
||||
old_ver=$(grep -o 'PYMC_CONSOLE_PATCH_V[0-9]*' "$api_file" | head -1 | sed 's/PYMC_CONSOLE_PATCH_V//')
|
||||
fi
|
||||
print_info "Upgrading API patch v${old_ver} → v${PATCH_VERSION}..."
|
||||
python3 << REMOVEPATCH
|
||||
import re
|
||||
with open("$api_file", 'r') as f:
|
||||
content = f.read()
|
||||
# Remove update_radio_config method entirely (handles both versioned and legacy)
|
||||
pattern = r'\n( # PYMC_CONSOLE_PATCH[^\n]*\n)? @cherrypy\.expose\n @cherrypy\.tools\.json_out\(\)\n @cherrypy\.tools\.json_in\(\)\n def update_radio_config\(self\):.*?return self\._error\(str\(e\)\)'
|
||||
content = re.sub(pattern, '', content, flags=re.DOTALL)
|
||||
with open("$api_file", 'w') as f:
|
||||
f.write(content)
|
||||
print("Removed old patch")
|
||||
REMOVEPATCH
|
||||
fi
|
||||
|
||||
# Use Python to add the endpoint (note: no quotes around PATCHEOF to allow variable expansion)
|
||||
python3 << PATCHEOF
|
||||
import re
|
||||
|
||||
api_file = "$api_file"
|
||||
|
||||
with open(api_file, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Add update_radio_config endpoint after save_cad_settings
|
||||
update_radio_config_code = '''
|
||||
|
||||
# PYMC_CONSOLE_PATCH_V5 - Radio, delay, and repeater config API with live updates
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
@cherrypy.tools.json_in()
|
||||
def update_radio_config(self):
|
||||
"""Update radio configuration and save to config.yaml
|
||||
|
||||
POST /api/update_radio_config
|
||||
Body: {
|
||||
"frequency_mhz": 906.875,
|
||||
"bandwidth_khz": 250,
|
||||
"spreading_factor": 10,
|
||||
"coding_rate": 5,
|
||||
"tx_power": 22
|
||||
}
|
||||
|
||||
Returns: {"success": true, "data": {"applied": [...], "persisted": true, "restart_required": true}}
|
||||
"""
|
||||
try:
|
||||
self._require_post()
|
||||
data = cherrypy.request.json or {}
|
||||
|
||||
if not data:
|
||||
return self._error("No configuration provided")
|
||||
|
||||
applied = []
|
||||
|
||||
# Ensure radio config section exists
|
||||
if "radio" not in self.config:
|
||||
self.config["radio"] = {}
|
||||
|
||||
# Update frequency (convert MHz to Hz for storage)
|
||||
if "frequency_mhz" in data:
|
||||
freq_hz = int(float(data["frequency_mhz"]) * 1_000_000)
|
||||
self.config["radio"]["frequency"] = freq_hz
|
||||
applied.append(f"frequency={data['frequency_mhz']}MHz")
|
||||
|
||||
# Update bandwidth (convert kHz to Hz for storage)
|
||||
if "bandwidth_khz" in data:
|
||||
bw_hz = int(float(data["bandwidth_khz"]) * 1000)
|
||||
self.config["radio"]["bandwidth"] = bw_hz
|
||||
applied.append(f"bandwidth={data['bandwidth_khz']}kHz")
|
||||
|
||||
# Update spreading factor
|
||||
if "spreading_factor" in data:
|
||||
sf = int(data["spreading_factor"])
|
||||
if sf < 5 or sf > 12:
|
||||
return self._error("Spreading factor must be 5-12")
|
||||
self.config["radio"]["spreading_factor"] = sf
|
||||
applied.append(f"SF={sf}")
|
||||
|
||||
# Update coding rate
|
||||
if "coding_rate" in data:
|
||||
cr = int(data["coding_rate"])
|
||||
if cr < 5 or cr > 8:
|
||||
return self._error("Coding rate must be 5-8 (4/5 to 4/8)")
|
||||
self.config["radio"]["coding_rate"] = cr
|
||||
applied.append(f"CR=4/{cr}")
|
||||
|
||||
# Update TX power (up to 30 dBm for high-power radios like E22-900M30S)
|
||||
if "tx_power" in data:
|
||||
power = int(data["tx_power"])
|
||||
if power < 2 or power > 30:
|
||||
return self._error("TX power must be 2-30 dBm")
|
||||
self.config["radio"]["tx_power"] = power
|
||||
applied.append(f"power={power}dBm")
|
||||
|
||||
# Ensure delays config section exists
|
||||
if "delays" not in self.config:
|
||||
self.config["delays"] = {}
|
||||
|
||||
# Update TX delay factor (af/txdelay)
|
||||
if "tx_delay_factor" in data:
|
||||
tdf = float(data["tx_delay_factor"])
|
||||
if tdf < 0.0 or tdf > 5.0:
|
||||
return self._error("TX delay factor must be 0.0-5.0")
|
||||
self.config["delays"]["tx_delay_factor"] = tdf
|
||||
applied.append(f"txdelay={tdf}")
|
||||
|
||||
# Update direct TX delay factor
|
||||
if "direct_tx_delay_factor" in data:
|
||||
dtdf = float(data["direct_tx_delay_factor"])
|
||||
if dtdf < 0.0 or dtdf > 5.0:
|
||||
return self._error("Direct TX delay factor must be 0.0-5.0")
|
||||
self.config["delays"]["direct_tx_delay_factor"] = dtdf
|
||||
applied.append(f"direct.txdelay={dtdf}")
|
||||
|
||||
# Update RX delay base
|
||||
if "rx_delay_base" in data:
|
||||
rxd = float(data["rx_delay_base"])
|
||||
if rxd < 0.0:
|
||||
return self._error("RX delay cannot be negative")
|
||||
self.config["delays"]["rx_delay_base"] = rxd
|
||||
applied.append(f"rxdelay={rxd}")
|
||||
|
||||
# Ensure repeater config section exists
|
||||
if "repeater" not in self.config:
|
||||
self.config["repeater"] = {}
|
||||
|
||||
# Update node name
|
||||
if "node_name" in data:
|
||||
name = str(data["node_name"]).strip()
|
||||
if not name:
|
||||
return self._error("Node name cannot be empty")
|
||||
self.config["repeater"]["node_name"] = name
|
||||
applied.append(f"name={name}")
|
||||
|
||||
# Update latitude
|
||||
if "latitude" in data:
|
||||
lat = float(data["latitude"])
|
||||
if lat < -90 or lat > 90:
|
||||
return self._error("Latitude must be -90 to 90")
|
||||
self.config["repeater"]["latitude"] = lat
|
||||
applied.append(f"lat={lat}")
|
||||
|
||||
# Update longitude
|
||||
if "longitude" in data:
|
||||
lon = float(data["longitude"])
|
||||
if lon < -180 or lon > 180:
|
||||
return self._error("Longitude must be -180 to 180")
|
||||
self.config["repeater"]["longitude"] = lon
|
||||
applied.append(f"lon={lon}")
|
||||
|
||||
# Update max flood hops
|
||||
if "max_flood_hops" in data:
|
||||
hops = int(data["max_flood_hops"])
|
||||
if hops < 0 or hops > 64:
|
||||
return self._error("Max flood hops must be 0-64")
|
||||
self.config["repeater"]["max_flood_hops"] = hops
|
||||
applied.append(f"flood.max={hops}")
|
||||
|
||||
# Update flood advert interval (hours)
|
||||
if "flood_advert_interval_hours" in data:
|
||||
hours = int(data["flood_advert_interval_hours"])
|
||||
if hours != 0 and (hours < 3 or hours > 48):
|
||||
return self._error("Flood advert interval must be 0 (off) or 3-48 hours")
|
||||
self.config["repeater"]["send_advert_interval_hours"] = hours
|
||||
applied.append(f"flood.advert.interval={hours}h")
|
||||
|
||||
# Update local advert interval (minutes)
|
||||
if "advert_interval_minutes" in data:
|
||||
mins = int(data["advert_interval_minutes"])
|
||||
if mins != 0 and (mins < 1 or mins > 10080):
|
||||
return self._error("Advert interval must be 0 (off) or 1-10080 minutes")
|
||||
self.config["repeater"]["advert_interval_minutes"] = mins
|
||||
applied.append(f"advert.interval={mins}m")
|
||||
|
||||
if not applied:
|
||||
return self._error("No valid settings provided")
|
||||
|
||||
# Save to config file
|
||||
config_path = getattr(self, '_config_path', '/etc/pymc_repeater/config.yaml')
|
||||
self._save_config_to_file(config_path)
|
||||
|
||||
# Live update: Also update daemon's in-memory config for immediate effect
|
||||
live_updated = False
|
||||
if self.daemon_instance and hasattr(self.daemon_instance, 'config'):
|
||||
try:
|
||||
daemon_config = self.daemon_instance.config
|
||||
|
||||
# Update repeater section in daemon config
|
||||
if 'repeater' not in daemon_config:
|
||||
daemon_config['repeater'] = {}
|
||||
for key in ['node_name', 'latitude', 'longitude', 'max_flood_hops',
|
||||
'advert_interval_minutes', 'send_advert_interval_hours']:
|
||||
if key in self.config.get('repeater', {}):
|
||||
daemon_config['repeater'][key] = self.config['repeater'][key]
|
||||
|
||||
# Update delays section in daemon config
|
||||
if 'delays' not in daemon_config:
|
||||
daemon_config['delays'] = {}
|
||||
for key in ['tx_delay_factor', 'direct_tx_delay_factor', 'rx_delay_base']:
|
||||
if key in self.config.get('delays', {}):
|
||||
daemon_config['delays'][key] = self.config['delays'][key]
|
||||
|
||||
live_updated = True
|
||||
logger.info("Live updated daemon config")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not live update daemon config: {e}")
|
||||
|
||||
logger.info(f"Radio config updated: {', '.join(applied)}")
|
||||
|
||||
return self._success({
|
||||
"applied": applied,
|
||||
"persisted": True,
|
||||
"live_update": live_updated,
|
||||
"restart_required": not live_updated,
|
||||
"message": "Settings applied immediately." if live_updated else "Settings saved. Restart service to apply changes."
|
||||
})
|
||||
|
||||
except cherrypy.HTTPError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating radio config: {e}")
|
||||
return self._error(str(e))
|
||||
'''
|
||||
|
||||
# Find the save_cad_settings method and insert after it
|
||||
# Look for the end of save_cad_settings (the except block)
|
||||
pattern = r'( def save_cad_settings\(self\):.*?return self\._error\(e\))'
|
||||
match = re.search(pattern, content, re.DOTALL)
|
||||
|
||||
if match:
|
||||
insert_pos = match.end()
|
||||
content = content[:insert_pos] + update_radio_config_code + content[insert_pos:]
|
||||
|
||||
with open(api_file, 'w') as f:
|
||||
f.write(content)
|
||||
print("Patched api_endpoints.py with update_radio_config")
|
||||
else:
|
||||
print("Could not find insertion point for update_radio_config")
|
||||
PATCHEOF
|
||||
|
||||
# Verify patch was applied
|
||||
if grep -q 'def update_radio_config' "$api_file" 2>/dev/null; then
|
||||
print_success "Patched api_endpoints.py with update_radio_config"
|
||||
else
|
||||
print_warning "API patch may not have applied correctly"
|
||||
fi
|
||||
# DISABLED: This patch was merged upstream in PR #36 (feat/identity branch)
|
||||
# See: https://github.com/rightup/pyMC_Repeater/pull/36
|
||||
# The /api/update_radio_config endpoint is now part of upstream pyMC_Repeater
|
||||
print_info "API endpoints patch skipped (merged upstream in PR #36)"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -2847,46 +2579,18 @@ patch_mesh_cli() {
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# PATCH 5: Stats API Extension (engine.py)
|
||||
# PATCH 5: Stats API Extension [REMOVED - MERGED UPSTREAM PR #36]
|
||||
# ------------------------------------------------------------------------------
|
||||
# File: repeater/engine.py
|
||||
# Purpose: Expose additional config values in /api/stats for Terminal CLI
|
||||
# Changes:
|
||||
# - Add max_flood_hops to config.repeater (for 'get flood.max')
|
||||
# - Add advert_interval_minutes to config.repeater (for 'get advert.interval')
|
||||
# - Add rx_delay_base to config.delays (for 'get rxdelay')
|
||||
# PR Status: Pending upstream submission
|
||||
# This patch was merged upstream in PR #36 to the feat/identity branch.
|
||||
# The /api/stats endpoint now includes max_flood_hops, advert_interval_minutes,
|
||||
# and rx_delay_base in the response.
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Patch removed - see PR #36: https://github.com/rightup/pyMC_Repeater/pull/36
|
||||
patch_stats_api() {
|
||||
local target_dir="${1:-$CLONE_DIR}"
|
||||
local engine_file="$target_dir/repeater/engine.py"
|
||||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
local patch_script="$script_dir/patches/stats_api_extension.py"
|
||||
|
||||
if [ ! -f "$engine_file" ]; then
|
||||
print_warning "engine.py not found, skipping stats API patch"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if already patched
|
||||
if grep -q 'PYMC_CONSOLE_STATS_PATCH' "$engine_file" 2>/dev/null; then
|
||||
print_info "Stats API patch already applied"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if patch script exists
|
||||
if [ ! -f "$patch_script" ]; then
|
||||
print_warning "Patch script not found: $patch_script"
|
||||
print_info "Skipping stats API extension"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Run the Python patch script
|
||||
if python3 "$patch_script" "$engine_file" 2>/dev/null; then
|
||||
print_success "Applied stats API extension patch"
|
||||
else
|
||||
print_warning "Stats API patch may not have applied correctly"
|
||||
fi
|
||||
# Patch disabled - merged upstream in PR #36 (feat/identity branch)
|
||||
print_info "Stats API patch skipped (merged upstream in PR #36)"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user