index.html 119 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>EdgeVPN</title>
  8. <meta name="description" content="Edgevpn dashboard">
  9. <meta name="keywords" content="edgevpn,dashboard">
  10. <script src="/js/apexcharts.min.js"></script>
  11. <script src="/js/alpine-magic-helpers.min.js" defer></script>
  12. <script src="/js/alpine.min.js" defer></script>
  13. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  14. <style>
  15. .bg-black-alt {
  16. background:#191919;
  17. }
  18. .text-black-alt {
  19. color:#191919;
  20. }
  21. .border-black-alt {
  22. border-color: #191919;
  23. }
  24. .string { color: green; }
  25. .number { color: darkorange; }
  26. .boolean { color: blue; }
  27. .null { color: magenta; }
  28. .key { color: red; }
  29. #checkbox:checked + label .switch-ball{
  30. background-color: white;
  31. transform: translateX(24px);
  32. transition: transform 0.3s linear;
  33. }
  34. </style>
  35. <script src="/js/tailwind.min.js"></script>
  36. <script>
  37. tailwind.config = {
  38. darkMode: 'class',
  39. theme: {
  40. extend: {
  41. colors: {
  42. clifford: '#da373d',
  43. }
  44. }
  45. }
  46. }
  47. </script>
  48. </head>
  49. <body class="font-sans leading-normal tracking-normal"
  50. x-data="{page: location.hash, 'darkMode': false }"
  51. @hashchange.window="page = location.hash"
  52. x-init="
  53. darkMode = JSON.parse(localStorage.getItem('darkMode'));
  54. $watch('darkMode', value => localStorage.setItem('darkMode', JSON.stringify(value)))"
  55. x-bind:class="darkMode === true ? 'dark bg-black-alt': 'bg-white'"
  56. >
  57. <nav id="header" class="bg-slate-100 dark:bg-gray-900 fixed w-full z-10 top-0 shadow">
  58. <div class="w-full container mx-auto flex flex-wrap items-center mt-0 pt-3 pb-3 md:pb-0">
  59. <div class="w-1/2 pl-2 md:pl-0 align-text-bottom">
  60. <a class="text-gray-100 text-base xl:text-xl no-underline hover:no-underline font-bold align-top" href="#">
  61. <img src="/images/logo.png" class="object-scale-down float-left h-7 w-7"> <span class="pl-4 pt-1 md:pb-0 text-md text-slate-700 dark:text-slate-100"> EdgeVPN </span>
  62. </a>
  63. </div>
  64. <div class="w-1/2 pr-0">
  65. <div class="flex relative inline-block float-right">
  66. <!-- Dark/Light mode button-->
  67. <div >
  68. <div>
  69. <div class="dark:text-gray-100">
  70. <div class="flex items-center justify-center space-x-2">
  71. <span class="text-sm text-gray-800 dark:text-gray-500 p-2">Light</span>
  72. <label for="toggle"
  73. class="flex items-center h-5 p-1 duration-300 ease-in-out bg-gray-300 rounded-full cursor-pointer w-9 dark:bg-gray-600">
  74. <div
  75. class="w-4 h-4 duration-300 ease-in-out transform bg-white rounded-full shadow-md toggle-dot dark:translate-x-3">
  76. </div>
  77. </label>
  78. <span class="text-sm text-gray-400 dark:text-white p-2">Dark</span>
  79. <input id="toggle" type="checkbox" class="hidden" :value="darkMode" @change="darkMode = !darkMode" />
  80. </div>
  81. </div>
  82. </div>
  83. </div>
  84. <!-- END Dark/Light mode button-->
  85. <div class="block lg:hidden pr-4">
  86. <button id="nav-toggle" class="flex items-center px-3 py-2 border rounded text-gray-500 border-gray-600 hover:text-gray-100 hover:border-teal-500 appearance-none focus:outline-none">
  87. <svg class="fill-current h-3 w-3" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>Menu</title><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/></svg>
  88. </button>
  89. </div>
  90. </div>
  91. </div>
  92. <div class="w-full flex-grow lg:flex lg:items-center lg:w-auto hidden lg:block mt-2 lg:mt-0 bg-white-300 dark:bg-gray-900 z-20" id="nav-content">
  93. <ul class="list-reset lg:flex flex-1 items-center px-4 md:px-0">
  94. <li class="mr-6 my-2 md:my-0">
  95. <a href="#"
  96. x-bind:class="page === '' ? 'text-blue-400 border-blue-400 hover:border-blue-400' : 'text-gray-500 dark:hover:text-gray-100 dark:hover:border-violet-900 hover:text-gray-900 border-sky-100 dark:border-sky-900 hover:border-pink-400'"
  97. class="block py-1 md:py-3 pl-1 align-middle no-underline border-b-2">
  98. <i
  99. x-bind:class="page === '' ? 'text-blue-400' : '' "
  100. class="fas fa-home fa-fw mr-3"></i><span class="pb-1 md:pb-0 text-sm">Home</span>
  101. </a>
  102. </li>
  103. <li class="mr-6 my-2 md:my-0">
  104. <a href="#nodes"
  105. x-bind:class="page === '#nodes' ? 'text-blue-400 border-blue-400 hover:border-blue-400' : 'text-gray-500 dark:hover:text-gray-100 dark:hover:border-violet-900 hover:text-gray-900 border-sky-100 dark:border-sky-900 hover:border-pink-400'"
  106. class="block py-1 md:py-3 pl-1 align-middle no-underline border-b-2">
  107. <i
  108. x-bind:class="page === '#nodes' ? 'text-blue-400' : '' "
  109. class="fas fa-server fa-fw mr-3"></i><span class="pb-1 md:pb-0 text-sm">Nodes</span>
  110. </a>
  111. </li>
  112. <li class="mr-6 my-2 md:my-0">
  113. <a href="#dns"
  114. x-bind:class="page === '#dns' ? 'text-blue-400 border-blue-400 hover:border-blue-400' : 'text-gray-500 dark:hover:text-gray-100 dark:hover:border-violet-900 hover:text-gray-900 border-sky-100 dark:border-sky-900 hover:border-pink-400'"
  115. class="block py-1 md:py-3 pl-1 align-middle no-underline border-b-2">
  116. <i
  117. x-bind:class="page === '#dns' ? 'text-blue-400' : '' "
  118. class="fas fa-globe fa-fw mr-3"></i><span class="pb-1 md:pb-0 text-sm">DNS</span>
  119. </a>
  120. </li>
  121. <li class="mr-6 my-2 md:my-0">
  122. <a href="#blockchain"
  123. x-bind:class="page === '#blockchain' ? 'text-blue-400 border-blue-400 hover:border-blue-400' : 'text-gray-500 dark:hover:text-gray-100 dark:hover:border-violet-900 hover:text-gray-900 border-sky-100 dark:border-sky-900 hover:border-pink-400'"
  124. class="block py-1 md:py-3 pl-1 align-middle no-underline border-b-2">
  125. <i
  126. x-bind:class="page === '#blockchain' ? 'text-blue-400' : '' "
  127. class="fas fa-dice-d20 fa-fw mr-3"></i><span class="pb-1 md:pb-0 text-sm">Blockchain</span>
  128. </a>
  129. </li>
  130. <li class="mr-6 my-2 md:my-0">
  131. <a href="#services"
  132. x-bind:class="page === '#services' ? 'text-blue-400 border-blue-400 hover:border-blue-400' : 'text-gray-500 dark:hover:text-gray-100 dark:hover:border-violet-900 hover:text-gray-900 border-sky-100 dark:border-sky-900 hover:border-pink-400'"
  133. class="block py-1 md:py-3 pl-1 align-middle no-underline border-b-2">
  134. <i
  135. x-bind:class="page === '#services' ? 'text-blue-400' : '' "
  136. class="fas fa-ethernet fa-fw mr-3"></i><span class="pb-1 md:pb-0 text-sm">Services</span>
  137. </a>
  138. </li>
  139. <li class="mr-6 my-2 md:my-0">
  140. <a href="#peers"
  141. x-bind:class="page === '#peers' ? 'text-blue-400 border-blue-400 hover:border-blue-400' : 'text-gray-500 dark:hover:text-gray-100 dark:hover:border-violet-900 hover:text-gray-900 border-sky-100 dark:border-sky-900 hover:border-pink-400'"
  142. class="block py-1 md:py-3 pl-1 align-middle no-underline border-b-2">
  143. <i
  144. x-bind:class="page === '#peers' ? 'text-blue-400' : '' "
  145. class="fas fa-users fa-fw mr-3"></i><span class="pb-1 md:pb-0 text-sm">Peers</span>
  146. </a>
  147. </li>
  148. </ul>
  149. <div class="relative pull-right pl-4 pr-4 md:pr-0">
  150. </div>
  151. </div>
  152. </div>
  153. </nav>
  154. <!-- Nodes Container-->
  155. <div class="container w-full mx-auto pt-20" x-show="page === '#nodes'">
  156. <div class="px-4 md:px-0 md:mt-8 mb-20 leading-normal " >
  157. <div class="relative " >
  158. <a class="mr-2 bg-sky-300 dark:bg-sky-600 text-white p-2 rounded leading-none items-center absolute top-10 right-1 " href="https://mudler.github.io/edgevpn/docs/getting-started/api/#apimachines" target=_blank>
  159. <i class="fa-solid fa-book fa-fw pr-1"></i> Machines API Documentation
  160. </a>
  161. </div>
  162. </div>
  163. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal"
  164. x-data="machines()"
  165. x-init="$interval(updateItems, 1500)"
  166. >
  167. <!-- Notification toast -->
  168. <div
  169. x-show="open"
  170. class="w-96 p-4 rounded h-32 fixed bottom-4 right-4 transform-gpu transition-transform duration-400 ease"
  171. x-class="success ? 'bg-green-500' : 'bg-red-500'"
  172. x-transition:enter-start="opacity-0 translate-y-full"
  173. x-transition:enter-end="opacity-100 translate-y-0"
  174. x-transition:leave-start="translate-y-0"
  175. x-transition:leave="transition transform ease-in duration-300"
  176. x-transition:leave-end="opacity-0 translate-y-full"
  177. >
  178. <div class="bg-white border-gray-300 dark:border-slate-800 dark:bg-slate-900 border p-3 flex items-start shadow-lg rounded-md space-x-2">
  179. <svg class="flex-shrink-0 h-6 w-6 text-green-400" stroke="currentColor" viewBox="0 0 20 20">
  180. <path stroke-width="1" d="M10.219,1.688c-4.471,0-8.094,3.623-8.094,8.094s3.623,8.094,8.094,8.094s8.094-3.623,8.094-8.094S14.689,1.688,10.219,1.688 M10.219,17.022c-3.994,0-7.242-3.247-7.242-7.241c0-3.994,3.248-7.242,7.242-7.242c3.994,0,7.241,3.248,7.241,7.242C17.46,13.775,14.213,17.022,10.219,17.022 M15.099,7.03c-0.167-0.167-0.438-0.167-0.604,0.002L9.062,12.48l-2.269-2.277c-0.166-0.167-0.437-0.167-0.603,0c-0.166,0.166-0.168,0.437-0.002,0.603l2.573,2.578c0.079,0.08,0.188,0.125,0.3,0.125s0.222-0.045,0.303-0.125l5.736-5.751C15.268,7.466,15.265,7.196,15.099,7.03"></path>
  181. </svg>
  182. <div class="flex-1 space-y-1">
  183. <p class="text-base leading-6 font-medium text-gray-700 dark:text-gray-400" x-text="title"></p>
  184. <p class="text-sm leading-5 text-gray-600 dark:text-gray-400" x-text="message"></p>
  185. </div>
  186. <svg class="flex-shrink-0 h-5 w-5 text-gray-400 cursor-pointer" x-on:click="isShow = false" stroke="currentColor" viewBox="0 0 20 20">
  187. <path stroke-width="1.2" d="M15.898,4.045c-0.271-0.272-0.713-0.272-0.986,0l-4.71,4.711L5.493,4.045c-0.272-0.272-0.714-0.272-0.986,0s-0.272,0.714,0,0.986l4.709,4.711l-4.71,4.711c-0.272,0.271-0.272,0.713,0,0.986c0.136,0.136,0.314,0.203,0.492,0.203c0.179,0,0.357-0.067,0.493-0.203l4.711-4.711l4.71,4.711c0.137,0.136,0.314,0.203,0.494,0.203c0.178,0,0.355-0.067,0.492-0.203c0.273-0.273,0.273-0.715,0-0.986l-4.711-4.711l4.711-4.711C16.172,4.759,16.172,4.317,15.898,4.045z"></path>
  188. </svg>
  189. </div>
  190. </div>
  191. <div class="w-full mt-12 p-3 dark:bg-gray-900 border dark:border-gray-800 rounded shadow">
  192. <div class="border-b bg-white-200 dark:bg-gray-900 dark:border-gray-800 p-3">
  193. <h5 class="font-bold uppercase dark:text-gray-600">Nodes</h5>
  194. </div>
  195. <br>
  196. <div class="relative mt-1 ">
  197. <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
  198. <svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20"
  199. xmlns="http://www.w3.org/2000/svg">
  200. <path fill-rule="evenodd"
  201. d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
  202. clip-rule="evenodd"></path>
  203. </svg>
  204. </div>
  205. <input
  206. x-ref="searchField"
  207. x-model="search"
  208. x-on:click="viewPage(0)"
  209. x-on:keydown.window.prevent.slash=" viewPage(0), $refs.searchField.focus()"
  210. placeholder="Search..."
  211. type="search"
  212. class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  213. />
  214. </div>
  215. <div class="overflow-auto">
  216. <table class="min-w-full bg-white-200 dark:bg-gray-900">
  217. <thead class="bg-slate-200 dark:bg-gray-800 dark:text-white">
  218. <tr>
  219. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Address</th>
  220. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">PeerID</th>
  221. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Hostname</th>
  222. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">OS</th>
  223. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Architecture</th>
  224. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Version</th>
  225. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm"></th>
  226. </tr>
  227. </thead>
  228. <tbody class="text-black dark:text-white">
  229. <template x-for="(d, index) in filtered" :key="index">
  230. <tr
  231. x-bind:class="d.Online ? 'bg-lime-100 dark:bg-lime-800' : 'bg-stone-200 dark:bg-stone-800'"
  232. >
  233. <td x-text="d.Address" class="text-left py-3 px-4"></td>
  234. <td x-text="d.PeerID" class="text-left py-3 px-4"></td>
  235. <td x-text="d.Hostname" class="text-left py-3 px-4"></td>
  236. <td x-text="d.OS" class="text-left py-3 px-4"></td>
  237. <td x-text="d.Arch" class="text-left py-3 px-4"></td>
  238. <td x-text="d.Version" class="text-left py-3 px-4"></td>
  239. <!-- Action menu -->
  240. <td class="text-left py-3 px-4" >
  241. <button
  242. class="px-3 py-2 rounded"
  243. type="button"
  244. x-on:click="deleteItem(d.Address)"
  245. >
  246. <i class="fa-solid fa-trash-can"></i>
  247. </button>
  248. </td>
  249. </tr>
  250. </template>
  251. </tbody>
  252. </table>
  253. <!--Pagination Buttons-->
  254. <div
  255. class="w-full md:w-1/2 mx-auto py-6 flex justify-between items-center"
  256. x-show="pageCount() > 1"
  257. >
  258. <!--First Button-->
  259. <button
  260. x-on:click="viewPage(0)"
  261. :disabled="pageNumber==0"
  262. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  263. >
  264. <svg
  265. class="h-8 w-8 text-indigo-600"
  266. width="24"
  267. height="24"
  268. viewBox="0 0 24 24"
  269. fill="none"
  270. stroke="currentColor"
  271. stroke-width="2"
  272. stroke-linecap="round"
  273. stroke-linejoin="round"
  274. >
  275. <polygon points="19 20 9 12 19 4 19 20"></polygon>
  276. <line x1="5" y1="19" x2="5" y2="5"></line>
  277. </svg>
  278. </button>
  279. <!--Previous Button-->
  280. <button
  281. x-on:click="prevPage"
  282. :disabled="pageNumber==0"
  283. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  284. >
  285. <svg
  286. class="h-8 w-8 text-indigo-600"
  287. width="24"
  288. height="24"
  289. viewBox="0 0 24 24"
  290. fill="none"
  291. stroke="currentColor"
  292. stroke-width="2"
  293. stroke-linecap="round"
  294. stroke-linejoin="round"
  295. >
  296. <polyline points="15 18 9 12 15 6"></polyline>
  297. </svg>
  298. </button>
  299. <!-- Display page numbers -->
  300. <template x-for="(page,index) in pages()" :key="page">
  301. <button
  302. class="px-3 py-2 rounded"
  303. :class="{ 'bg-indigo-600 text-white font-bold' : page === pageNumber }"
  304. type="button"
  305. x-on:click="viewPage(page)"
  306. >
  307. <span x-text="page" class="dark:text-white"></span>
  308. </button>
  309. </template>
  310. <!--Next Button-->
  311. <button
  312. x-on:click="nextPage"
  313. :disabled="pageNumber >= pageCount() -1"
  314. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  315. >
  316. <svg
  317. class="h-8 w-8 text-indigo-600"
  318. width="24"
  319. height="24"
  320. viewBox="0 0 24 24"
  321. fill="none"
  322. stroke="currentColor"
  323. stroke-width="2"
  324. stroke-linecap="round"
  325. stroke-linejoin="round"
  326. >
  327. <polyline points="9 18 15 12 9 6"></polyline>
  328. </svg>
  329. </button>
  330. <!--Last Button-->
  331. <button
  332. x-on:click="viewPage(Math.ceil(total/size)-1)"
  333. :disabled="pageNumber >= pageCount() -1"
  334. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  335. >
  336. <svg
  337. class="h-8 w-8 text-indigo-600"
  338. width="24"
  339. height="24"
  340. viewBox="0 0 24 24"
  341. fill="none"
  342. stroke="currentColor"
  343. stroke-width="2"
  344. stroke-linecap="round"
  345. stroke-linejoin="round"
  346. >
  347. <polygon points="5 4 15 12 5 20 5 4"></polygon>
  348. <line x1="19" y1="5" x2="19" y2="19"></line>
  349. </svg>
  350. </button>
  351. </div>
  352. <!-- /Pagination Buttons-->
  353. </div>
  354. </div>
  355. </div>
  356. </div>
  357. <!--END Node Container-->
  358. <!-- Blockchain Container-->
  359. <div class="container w-full mx-auto pt-20" x-show="page === '#blockchain'">
  360. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal">
  361. <div class="w-full mt-12 p-3 dark:bg-gray-900 bg-white-100 border dark:border-gray-800 rounded shadow"
  362. x-data="blockchain()"
  363. x-init="$interval(updateItems, 5500)"
  364. >
  365. <div class="border-b border-gray-800 p-3">
  366. <h5 class="font-bold uppercase text-gray-600">Blockchain </h5>
  367. <h5 class="font-bold uppercase text-gray-600">
  368. <span class="mt-1 text-xs px-2 py-1 font-semibold leading-tight text-slate-700 bg-slate-100 rounded-full dark:bg-slate-700 dark:text-slate-100"><i class="fa-solid fa-hashtag fa-fw mr-3"></i> <span x-text="blockchain.Index"></span> </span>
  369. <span class="mt-1 text-xs px-2 py-1 font-semibold leading-tight text-slate-700 bg-slate-100 rounded-full dark:bg-slate-700 dark:text-slate-100"><i class="fa-solid fa-clock fa-fw mr-3"></i> <span x-text="blockchain.Timestamp"></span> </span>
  370. <span class="mt-1 text-xs px-2 py-1 font-semibold leading-tight text-slate-700 bg-slate-100 rounded-full dark:bg-slate-700 dark:text-slate-100"><i class="fa-solid fa-dice-d20 fa-fw mr-3"></i> <span x-text="blockchain.Hash"></span> </span>
  371. <span class="mt-1 text-xs px-2 py-1 font-semibold leading-tight text-slate-700 bg-slate-100 rounded-full dark:bg-slate-700 dark:text-slate-100"><i class="fa-solid fa-link fa-fw mr-3"></i> <span x-text="blockchain.PrevHash"></span> </span>
  372. </div>
  373. <section class="flex justify-center mt-10">
  374. <div class="bg-white-300 py-1 w-11/12 rounded border-b-4 border-red-400 flex dark:text-white">
  375. <pre class="overflow-auto"><code class="overflow-auto" x-html="syntaxHighlight(JSON.stringify(blockchain, null, 2))"></code></pre>
  376. </div>
  377. </section>
  378. </div>
  379. </div>
  380. </div>
  381. <!--END Blockchain Container-->
  382. <!-- DNS Container-->
  383. <div class="container w-full mx-auto pt-20" x-show="page === '#dns'">
  384. <div class="px-4 md:px-0 md:mt-8 mb-20 leading-normal " >
  385. <div class="relative " >
  386. <a class="mr-2 bg-sky-300 dark:bg-sky-600 text-white p-2 rounded leading-none items-center absolute top-10 right-1 " href="https://mudler.github.io/edgevpn/docs/concepts/overview/dns/" target=_blank>
  387. <i class="fa-solid fa-book fa-fw pr-1"></i> DNS Documentation
  388. </a>
  389. </div>
  390. </div>
  391. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal"
  392. x-data="dns()"
  393. x-init="$interval(updateItems, 1500)"
  394. >
  395. <!-- Notification toast -->
  396. <div
  397. x-show="open"
  398. class="w-96 p-4 rounded h-32 fixed bottom-4 right-4 transform-gpu transition-transform duration-400 ease"
  399. x-class="success ? 'bg-green-500' : 'bg-red-500'"
  400. x-transition:enter-start="opacity-0 translate-y-full"
  401. x-transition:enter-end="opacity-100 translate-y-0"
  402. x-transition:leave-start="translate-y-0"
  403. x-transition:leave="transition transform ease-in duration-300"
  404. x-transition:leave-end="opacity-0 translate-y-full"
  405. >
  406. <div class="bg-white border-gray-300 dark:border-slate-800 dark:bg-slate-900 border p-3 flex items-start shadow-lg rounded-md space-x-2">
  407. <svg class="flex-shrink-0 h-6 w-6 text-green-400" stroke="currentColor" viewBox="0 0 20 20">
  408. <path stroke-width="1" d="M10.219,1.688c-4.471,0-8.094,3.623-8.094,8.094s3.623,8.094,8.094,8.094s8.094-3.623,8.094-8.094S14.689,1.688,10.219,1.688 M10.219,17.022c-3.994,0-7.242-3.247-7.242-7.241c0-3.994,3.248-7.242,7.242-7.242c3.994,0,7.241,3.248,7.241,7.242C17.46,13.775,14.213,17.022,10.219,17.022 M15.099,7.03c-0.167-0.167-0.438-0.167-0.604,0.002L9.062,12.48l-2.269-2.277c-0.166-0.167-0.437-0.167-0.603,0c-0.166,0.166-0.168,0.437-0.002,0.603l2.573,2.578c0.079,0.08,0.188,0.125,0.3,0.125s0.222-0.045,0.303-0.125l5.736-5.751C15.268,7.466,15.265,7.196,15.099,7.03"></path>
  409. </svg>
  410. <div class="flex-1 space-y-1">
  411. <p class="text-base leading-6 font-medium text-gray-700 dark:text-gray-400" x-text="title"></p>
  412. <p class="text-sm leading-5 text-gray-600 dark:text-gray-400" x-text="message"></p>
  413. </div>
  414. <svg class="flex-shrink-0 h-5 w-5 text-gray-400 cursor-pointer" x-on:click="isShow = false" stroke="currentColor" viewBox="0 0 20 20">
  415. <path stroke-width="1.2" d="M15.898,4.045c-0.271-0.272-0.713-0.272-0.986,0l-4.71,4.711L5.493,4.045c-0.272-0.272-0.714-0.272-0.986,0s-0.272,0.714,0,0.986l4.709,4.711l-4.71,4.711c-0.272,0.271-0.272,0.713,0,0.986c0.136,0.136,0.314,0.203,0.492,0.203c0.179,0,0.357-0.067,0.493-0.203l4.711-4.711l4.71,4.711c0.137,0.136,0.314,0.203,0.494,0.203c0.178,0,0.355-0.067,0.492-0.203c0.273-0.273,0.273-0.715,0-0.986l-4.711-4.711l4.711-4.711C16.172,4.759,16.172,4.317,15.898,4.045z"></path>
  416. </svg>
  417. </div>
  418. </div>
  419. <div class="w-full mt-12 p-3 dark:bg-gray-900 border dark:border-gray-800 rounded shadow">
  420. <div class="border-b bg-white-200 dark:bg-gray-900 dark:border-gray-800 p-3">
  421. <h5 class="font-bold uppercase dark:text-gray-600">DNS</h5>
  422. </div>
  423. <br>
  424. <div class="relative mt-1 ">
  425. <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
  426. <svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20"
  427. xmlns="http://www.w3.org/2000/svg">
  428. <path fill-rule="evenodd"
  429. d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
  430. clip-rule="evenodd"></path>
  431. </svg>
  432. </div>
  433. <input
  434. x-ref="searchField"
  435. x-model="search"
  436. x-on:click="viewPage(0)"
  437. x-on:keydown.window.prevent.slash=" viewPage(0), $refs.searchField.focus()"
  438. placeholder="Search..."
  439. type="search"
  440. class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  441. />
  442. </div>
  443. <div class="overflow-auto">
  444. <table class="min-w-full bg-white-200 dark:bg-gray-900">
  445. <thead class="bg-slate-200 dark:bg-gray-800 dark:text-white">
  446. <tr>
  447. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Regex</th>
  448. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Records</th>
  449. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm"></th>
  450. </tr>
  451. </thead>
  452. <tbody class="text-black dark:text-white">
  453. <template x-for="(d, index) in filtered" :key="index">
  454. <tr
  455. >
  456. <td x-text="d.Regex" class="text-left py-3 px-4"></td>
  457. <td x-text="JSON.stringify(d.Records)" class="text-left py-3 px-4"></td>
  458. <!-- Action menu -->
  459. <td class="text-left py-3 px-4" >
  460. <button
  461. class="px-3 py-2 rounded"
  462. type="button"
  463. x-on:click="deleteItem(d.Regex)"
  464. >
  465. <i class="fa-solid fa-trash-can"></i>
  466. </button>
  467. </td>
  468. </tr>
  469. </template>
  470. </tbody>
  471. </table>
  472. <!--Pagination Buttons-->
  473. <div
  474. class="w-full md:w-1/2 mx-auto py-6 flex justify-between items-center"
  475. x-show="pageCount() > 1"
  476. >
  477. <!--First Button-->
  478. <button
  479. x-on:click="viewPage(0)"
  480. :disabled="pageNumber==0"
  481. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  482. >
  483. <svg
  484. class="h-8 w-8 text-indigo-600"
  485. width="24"
  486. height="24"
  487. viewBox="0 0 24 24"
  488. fill="none"
  489. stroke="currentColor"
  490. stroke-width="2"
  491. stroke-linecap="round"
  492. stroke-linejoin="round"
  493. >
  494. <polygon points="19 20 9 12 19 4 19 20"></polygon>
  495. <line x1="5" y1="19" x2="5" y2="5"></line>
  496. </svg>
  497. </button>
  498. <!--Previous Button-->
  499. <button
  500. x-on:click="prevPage"
  501. :disabled="pageNumber==0"
  502. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  503. >
  504. <svg
  505. class="h-8 w-8 text-indigo-600"
  506. width="24"
  507. height="24"
  508. viewBox="0 0 24 24"
  509. fill="none"
  510. stroke="currentColor"
  511. stroke-width="2"
  512. stroke-linecap="round"
  513. stroke-linejoin="round"
  514. >
  515. <polyline points="15 18 9 12 15 6"></polyline>
  516. </svg>
  517. </button>
  518. <!-- Display page numbers -->
  519. <template x-for="(page,index) in pages()" :key="page">
  520. <button
  521. class="px-3 py-2 rounded"
  522. :class="{ 'bg-indigo-600 text-white font-bold' : page === pageNumber }"
  523. type="button"
  524. x-on:click="viewPage(page)"
  525. >
  526. <span x-text="page" class="dark:text-white"></span>
  527. </button>
  528. </template>
  529. <!--Next Button-->
  530. <button
  531. x-on:click="nextPage"
  532. :disabled="pageNumber >= pageCount() -1"
  533. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  534. >
  535. <svg
  536. class="h-8 w-8 text-indigo-600"
  537. width="24"
  538. height="24"
  539. viewBox="0 0 24 24"
  540. fill="none"
  541. stroke="currentColor"
  542. stroke-width="2"
  543. stroke-linecap="round"
  544. stroke-linejoin="round"
  545. >
  546. <polyline points="9 18 15 12 9 6"></polyline>
  547. </svg>
  548. </button>
  549. <!--Last Button-->
  550. <button
  551. x-on:click="viewPage(Math.ceil(total/size)-1)"
  552. :disabled="pageNumber >= pageCount() -1"
  553. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  554. >
  555. <svg
  556. class="h-8 w-8 text-indigo-600"
  557. width="24"
  558. height="24"
  559. viewBox="0 0 24 24"
  560. fill="none"
  561. stroke="currentColor"
  562. stroke-width="2"
  563. stroke-linecap="round"
  564. stroke-linejoin="round"
  565. >
  566. <polygon points="5 4 15 12 5 20 5 4"></polygon>
  567. <line x1="19" y1="5" x2="19" y2="19"></line>
  568. </svg>
  569. </button>
  570. </div>
  571. <!-- /Pagination Buttons-->
  572. </div>
  573. </div>
  574. </div>
  575. </div>
  576. <!--END DNS Container-->
  577. <!-- Services Container-->
  578. <div class="container w-full mx-auto pt-20" x-show="page === '#services'">
  579. <div class="px-4 md:px-0 md:mt-8 mb-20 leading-normal " >
  580. <div class="relative " >
  581. <a class="mr-2 bg-sky-300 dark:bg-sky-600 text-white p-2 rounded leading-none items-center absolute top-10 right-1 " href="https://mudler.github.io/edgevpn/docs/concepts/overview/services/" target=_blank>
  582. <i class="fa-solid fa-book fa-fw pr-1"></i> Tunnelling Documentation
  583. </a>
  584. </div>
  585. </div>
  586. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal"
  587. x-data="services()"
  588. x-init="$interval(updateItems, 1500)"
  589. >
  590. <!-- Notification toast -->
  591. <div
  592. x-show="open"
  593. class="w-96 p-4 rounded h-32 fixed bottom-4 right-4 transform-gpu transition-transform duration-400 ease"
  594. x-class="success ? 'bg-green-500' : 'bg-red-500'"
  595. x-transition:enter-start="opacity-0 translate-y-full"
  596. x-transition:enter-end="opacity-100 translate-y-0"
  597. x-transition:leave-start="translate-y-0"
  598. x-transition:leave="transition transform ease-in duration-300"
  599. x-transition:leave-end="opacity-0 translate-y-full"
  600. >
  601. <div class="bg-white border-gray-300 dark:border-slate-800 dark:bg-slate-900 border p-3 flex items-start shadow-lg rounded-md space-x-2">
  602. <svg class="flex-shrink-0 h-6 w-6 text-green-400" stroke="currentColor" viewBox="0 0 20 20">
  603. <path stroke-width="1" d="M10.219,1.688c-4.471,0-8.094,3.623-8.094,8.094s3.623,8.094,8.094,8.094s8.094-3.623,8.094-8.094S14.689,1.688,10.219,1.688 M10.219,17.022c-3.994,0-7.242-3.247-7.242-7.241c0-3.994,3.248-7.242,7.242-7.242c3.994,0,7.241,3.248,7.241,7.242C17.46,13.775,14.213,17.022,10.219,17.022 M15.099,7.03c-0.167-0.167-0.438-0.167-0.604,0.002L9.062,12.48l-2.269-2.277c-0.166-0.167-0.437-0.167-0.603,0c-0.166,0.166-0.168,0.437-0.002,0.603l2.573,2.578c0.079,0.08,0.188,0.125,0.3,0.125s0.222-0.045,0.303-0.125l5.736-5.751C15.268,7.466,15.265,7.196,15.099,7.03"></path>
  604. </svg>
  605. <div class="flex-1 space-y-1">
  606. <p class="text-base leading-6 font-medium text-gray-700 dark:text-gray-400" x-text="title"></p>
  607. <p class="text-sm leading-5 text-gray-600 dark:text-gray-400" x-text="message"></p>
  608. </div>
  609. <svg class="flex-shrink-0 h-5 w-5 text-gray-400 cursor-pointer" x-on:click="isShow = false" stroke="currentColor" viewBox="0 0 20 20">
  610. <path stroke-width="1.2" d="M15.898,4.045c-0.271-0.272-0.713-0.272-0.986,0l-4.71,4.711L5.493,4.045c-0.272-0.272-0.714-0.272-0.986,0s-0.272,0.714,0,0.986l4.709,4.711l-4.71,4.711c-0.272,0.271-0.272,0.713,0,0.986c0.136,0.136,0.314,0.203,0.492,0.203c0.179,0,0.357-0.067,0.493-0.203l4.711-4.711l4.71,4.711c0.137,0.136,0.314,0.203,0.494,0.203c0.178,0,0.355-0.067,0.492-0.203c0.273-0.273,0.273-0.715,0-0.986l-4.711-4.711l4.711-4.711C16.172,4.759,16.172,4.317,15.898,4.045z"></path>
  611. </svg>
  612. </div>
  613. </div>
  614. <div class="w-full mt-12 p-3 dark:bg-gray-900 border dark:border-gray-800 rounded shadow">
  615. <div class="border-b bg-white-200 dark:bg-gray-900 dark:border-gray-800 p-3">
  616. <h5 class="font-bold uppercase dark:text-gray-600">TCP Tunnels</h5>
  617. </div>
  618. <br>
  619. <div class="relative mt-1 ">
  620. <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
  621. <svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20"
  622. xmlns="http://www.w3.org/2000/svg">
  623. <path fill-rule="evenodd"
  624. d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
  625. clip-rule="evenodd"></path>
  626. </svg>
  627. </div>
  628. <input
  629. x-ref="searchField"
  630. x-model="search"
  631. x-on:click="viewPage(0)"
  632. x-on:keydown.window.prevent.slash=" viewPage(0), $refs.searchField.focus()"
  633. placeholder="Search..."
  634. type="search"
  635. class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  636. />
  637. </div>
  638. <div class="overflow-auto">
  639. <table class="min-w-full bg-white-200 dark:bg-gray-900">
  640. <thead class="bg-slate-200 dark:bg-gray-800 dark:text-white">
  641. <tr>
  642. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Name</th>
  643. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">PeerID</th>
  644. </tr>
  645. </thead>
  646. <tbody class="text-black dark:text-white">
  647. <template x-for="(d, index) in filtered" :key="index">
  648. <tr
  649. >
  650. <td x-text="d.Name" class="text-left py-3 px-4"></td>
  651. <td x-text="d.PeerID" class="text-left py-3 px-4"></td>
  652. </tr>
  653. </template>
  654. </tbody>
  655. </table>
  656. <!--Pagination Buttons-->
  657. <div
  658. class="w-full md:w-1/2 mx-auto py-6 flex justify-between items-center"
  659. x-show="pageCount() > 1"
  660. >
  661. <!--First Button-->
  662. <button
  663. x-on:click="viewPage(0)"
  664. :disabled="pageNumber==0"
  665. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  666. >
  667. <svg
  668. class="h-8 w-8 text-indigo-600"
  669. width="24"
  670. height="24"
  671. viewBox="0 0 24 24"
  672. fill="none"
  673. stroke="currentColor"
  674. stroke-width="2"
  675. stroke-linecap="round"
  676. stroke-linejoin="round"
  677. >
  678. <polygon points="19 20 9 12 19 4 19 20"></polygon>
  679. <line x1="5" y1="19" x2="5" y2="5"></line>
  680. </svg>
  681. </button>
  682. <!--Previous Button-->
  683. <button
  684. x-on:click="prevPage"
  685. :disabled="pageNumber==0"
  686. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  687. >
  688. <svg
  689. class="h-8 w-8 text-indigo-600"
  690. width="24"
  691. height="24"
  692. viewBox="0 0 24 24"
  693. fill="none"
  694. stroke="currentColor"
  695. stroke-width="2"
  696. stroke-linecap="round"
  697. stroke-linejoin="round"
  698. >
  699. <polyline points="15 18 9 12 15 6"></polyline>
  700. </svg>
  701. </button>
  702. <!-- Display page numbers -->
  703. <template x-for="(page,index) in pages()" :key="page">
  704. <button
  705. class="px-3 py-2 rounded"
  706. :class="{ 'bg-indigo-600 text-white font-bold' : page === pageNumber }"
  707. type="button"
  708. x-on:click="viewPage(page)"
  709. >
  710. <span x-text="page" class="dark:text-white"></span>
  711. </button>
  712. </template>
  713. <!--Next Button-->
  714. <button
  715. x-on:click="nextPage"
  716. :disabled="pageNumber >= pageCount() -1"
  717. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  718. >
  719. <svg
  720. class="h-8 w-8 text-indigo-600"
  721. width="24"
  722. height="24"
  723. viewBox="0 0 24 24"
  724. fill="none"
  725. stroke="currentColor"
  726. stroke-width="2"
  727. stroke-linecap="round"
  728. stroke-linejoin="round"
  729. >
  730. <polyline points="9 18 15 12 9 6"></polyline>
  731. </svg>
  732. </button>
  733. <!--Last Button-->
  734. <button
  735. x-on:click="viewPage(Math.ceil(total/size)-1)"
  736. :disabled="pageNumber >= pageCount() -1"
  737. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  738. >
  739. <svg
  740. class="h-8 w-8 text-indigo-600"
  741. width="24"
  742. height="24"
  743. viewBox="0 0 24 24"
  744. fill="none"
  745. stroke="currentColor"
  746. stroke-width="2"
  747. stroke-linecap="round"
  748. stroke-linejoin="round"
  749. >
  750. <polygon points="5 4 15 12 5 20 5 4"></polygon>
  751. <line x1="19" y1="5" x2="19" y2="19"></line>
  752. </svg>
  753. </button>
  754. </div>
  755. <!-- /Pagination Buttons-->
  756. </div>
  757. </div>
  758. </div>
  759. <hr class="border-b-2 border-gray-600 my-8 mx-4">
  760. <div class="px-4 md:px-0 md:mt-8 mb-20 leading-normal " >
  761. <div class="relative " >
  762. <a class="mr-2 bg-sky-300 dark:bg-sky-600 text-white p-2 rounded leading-none items-center absolute top-10 right-1 " href="https://mudler.github.io/edgevpn/docs/concepts/overview/files/" target=_blank>
  763. <i class="fa-solid fa-book fa-fw pr-1"></i> Files Documentation
  764. </a>
  765. </div>
  766. </div>
  767. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal"
  768. x-data="files()"
  769. x-init="$interval(updateItems, 1500)"
  770. >
  771. <!-- Notification toast -->
  772. <div
  773. x-show="open"
  774. class="w-96 p-4 rounded h-32 fixed bottom-4 right-4 transform-gpu transition-transform duration-400 ease"
  775. x-class="success ? 'bg-green-500' : 'bg-red-500'"
  776. x-transition:enter-start="opacity-0 translate-y-full"
  777. x-transition:enter-end="opacity-100 translate-y-0"
  778. x-transition:leave-start="translate-y-0"
  779. x-transition:leave="transition transform ease-in duration-300"
  780. x-transition:leave-end="opacity-0 translate-y-full"
  781. >
  782. <div class="bg-white border-gray-300 dark:border-slate-800 dark:bg-slate-900 border p-3 flex items-start shadow-lg rounded-md space-x-2">
  783. <svg class="flex-shrink-0 h-6 w-6 text-green-400" stroke="currentColor" viewBox="0 0 20 20">
  784. <path stroke-width="1" d="M10.219,1.688c-4.471,0-8.094,3.623-8.094,8.094s3.623,8.094,8.094,8.094s8.094-3.623,8.094-8.094S14.689,1.688,10.219,1.688 M10.219,17.022c-3.994,0-7.242-3.247-7.242-7.241c0-3.994,3.248-7.242,7.242-7.242c3.994,0,7.241,3.248,7.241,7.242C17.46,13.775,14.213,17.022,10.219,17.022 M15.099,7.03c-0.167-0.167-0.438-0.167-0.604,0.002L9.062,12.48l-2.269-2.277c-0.166-0.167-0.437-0.167-0.603,0c-0.166,0.166-0.168,0.437-0.002,0.603l2.573,2.578c0.079,0.08,0.188,0.125,0.3,0.125s0.222-0.045,0.303-0.125l5.736-5.751C15.268,7.466,15.265,7.196,15.099,7.03"></path>
  785. </svg>
  786. <div class="flex-1 space-y-1">
  787. <p class="text-base leading-6 font-medium text-gray-700 dark:text-gray-400" x-text="title"></p>
  788. <p class="text-sm leading-5 text-gray-600 dark:text-gray-400" x-text="message"></p>
  789. </div>
  790. <svg class="flex-shrink-0 h-5 w-5 text-gray-400 cursor-pointer" x-on:click="isShow = false" stroke="currentColor" viewBox="0 0 20 20">
  791. <path stroke-width="1.2" d="M15.898,4.045c-0.271-0.272-0.713-0.272-0.986,0l-4.71,4.711L5.493,4.045c-0.272-0.272-0.714-0.272-0.986,0s-0.272,0.714,0,0.986l4.709,4.711l-4.71,4.711c-0.272,0.271-0.272,0.713,0,0.986c0.136,0.136,0.314,0.203,0.492,0.203c0.179,0,0.357-0.067,0.493-0.203l4.711-4.711l4.71,4.711c0.137,0.136,0.314,0.203,0.494,0.203c0.178,0,0.355-0.067,0.492-0.203c0.273-0.273,0.273-0.715,0-0.986l-4.711-4.711l4.711-4.711C16.172,4.759,16.172,4.317,15.898,4.045z"></path>
  792. </svg>
  793. </div>
  794. </div>
  795. <div class="w-full mt-12 p-3 dark:bg-gray-900 border dark:border-gray-800 rounded shadow">
  796. <div class="border-b bg-white-200 dark:bg-gray-900 dark:border-gray-800 p-3">
  797. <h5 class="font-bold uppercase dark:text-gray-600">Files</h5>
  798. </div>
  799. <br>
  800. <div class="relative mt-1 ">
  801. <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
  802. <svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20"
  803. xmlns="http://www.w3.org/2000/svg">
  804. <path fill-rule="evenodd"
  805. d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
  806. clip-rule="evenodd"></path>
  807. </svg>
  808. </div>
  809. <input
  810. x-ref="searchField"
  811. x-model="search"
  812. x-on:click="viewPage(0)"
  813. x-on:keydown.window.prevent.slash=" viewPage(0), $refs.searchField.focus()"
  814. placeholder="Search..."
  815. type="search"
  816. class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  817. />
  818. </div>
  819. <div class="overflow-auto">
  820. <table class="min-w-full bg-white-200 dark:bg-gray-900">
  821. <thead class="bg-slate-200 dark:bg-gray-800 dark:text-white">
  822. <tr>
  823. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Name</th>
  824. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">PeerID</th>
  825. </tr>
  826. </thead>
  827. <tbody class="text-black dark:text-white">
  828. <template x-for="(d, index) in filtered" :key="index">
  829. <tr
  830. >
  831. <td x-text="d.Name" class="text-left py-3 px-4"></td>
  832. <td x-text="d.PeerID" class="text-left py-3 px-4"></td>
  833. </tr>
  834. </template>
  835. </tbody>
  836. </table>
  837. <!--Pagination Buttons-->
  838. <div
  839. class="w-full md:w-1/2 mx-auto py-6 flex justify-between items-center"
  840. x-show="pageCount() > 1"
  841. >
  842. <!--First Button-->
  843. <button
  844. x-on:click="viewPage(0)"
  845. :disabled="pageNumber==0"
  846. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  847. >
  848. <svg
  849. class="h-8 w-8 text-indigo-600"
  850. width="24"
  851. height="24"
  852. viewBox="0 0 24 24"
  853. fill="none"
  854. stroke="currentColor"
  855. stroke-width="2"
  856. stroke-linecap="round"
  857. stroke-linejoin="round"
  858. >
  859. <polygon points="19 20 9 12 19 4 19 20"></polygon>
  860. <line x1="5" y1="19" x2="5" y2="5"></line>
  861. </svg>
  862. </button>
  863. <!--Previous Button-->
  864. <button
  865. x-on:click="prevPage"
  866. :disabled="pageNumber==0"
  867. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  868. >
  869. <svg
  870. class="h-8 w-8 text-indigo-600"
  871. width="24"
  872. height="24"
  873. viewBox="0 0 24 24"
  874. fill="none"
  875. stroke="currentColor"
  876. stroke-width="2"
  877. stroke-linecap="round"
  878. stroke-linejoin="round"
  879. >
  880. <polyline points="15 18 9 12 15 6"></polyline>
  881. </svg>
  882. </button>
  883. <!-- Display page numbers -->
  884. <template x-for="(page,index) in pages()" :key="page">
  885. <button
  886. class="px-3 py-2 rounded"
  887. :class="{ 'bg-indigo-600 text-white font-bold' : page === pageNumber }"
  888. type="button"
  889. x-on:click="viewPage(page)"
  890. >
  891. <span x-text="page" class="dark:text-white"></span>
  892. </button>
  893. </template>
  894. <!--Next Button-->
  895. <button
  896. x-on:click="nextPage"
  897. :disabled="pageNumber >= pageCount() -1"
  898. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  899. >
  900. <svg
  901. class="h-8 w-8 text-indigo-600"
  902. width="24"
  903. height="24"
  904. viewBox="0 0 24 24"
  905. fill="none"
  906. stroke="currentColor"
  907. stroke-width="2"
  908. stroke-linecap="round"
  909. stroke-linejoin="round"
  910. >
  911. <polyline points="9 18 15 12 9 6"></polyline>
  912. </svg>
  913. </button>
  914. <!--Last Button-->
  915. <button
  916. x-on:click="viewPage(Math.ceil(total/size)-1)"
  917. :disabled="pageNumber >= pageCount() -1"
  918. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  919. >
  920. <svg
  921. class="h-8 w-8 text-indigo-600"
  922. width="24"
  923. height="24"
  924. viewBox="0 0 24 24"
  925. fill="none"
  926. stroke="currentColor"
  927. stroke-width="2"
  928. stroke-linecap="round"
  929. stroke-linejoin="round"
  930. >
  931. <polygon points="5 4 15 12 5 20 5 4"></polygon>
  932. <line x1="19" y1="5" x2="19" y2="19"></line>
  933. </svg>
  934. </button>
  935. </div>
  936. <!-- /Pagination Buttons-->
  937. </div>
  938. </div>
  939. </div>
  940. </div>
  941. <!--END Services Container-->
  942. <!-- Peers Container-->
  943. <div class="container w-full mx-auto pt-20" x-show="page === '#peers'">
  944. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal"
  945. x-data="nodes()"
  946. x-init="$interval(updateItems, 1500)"
  947. >
  948. <!-- Notification toast -->
  949. <div
  950. x-show="open"
  951. class="w-96 p-4 rounded h-32 fixed bottom-4 right-4 transform-gpu transition-transform duration-400 ease"
  952. x-class="success ? 'bg-green-500' : 'bg-red-500'"
  953. x-transition:enter-start="opacity-0 translate-y-full"
  954. x-transition:enter-end="opacity-100 translate-y-0"
  955. x-transition:leave-start="translate-y-0"
  956. x-transition:leave="transition transform ease-in duration-300"
  957. x-transition:leave-end="opacity-0 translate-y-full"
  958. >
  959. <div class="bg-white border-gray-300 dark:border-slate-800 dark:bg-slate-900 border p-3 flex items-start shadow-lg rounded-md space-x-2">
  960. <svg class="flex-shrink-0 h-6 w-6 text-green-400" stroke="currentColor" viewBox="0 0 20 20">
  961. <path stroke-width="1" d="M10.219,1.688c-4.471,0-8.094,3.623-8.094,8.094s3.623,8.094,8.094,8.094s8.094-3.623,8.094-8.094S14.689,1.688,10.219,1.688 M10.219,17.022c-3.994,0-7.242-3.247-7.242-7.241c0-3.994,3.248-7.242,7.242-7.242c3.994,0,7.241,3.248,7.241,7.242C17.46,13.775,14.213,17.022,10.219,17.022 M15.099,7.03c-0.167-0.167-0.438-0.167-0.604,0.002L9.062,12.48l-2.269-2.277c-0.166-0.167-0.437-0.167-0.603,0c-0.166,0.166-0.168,0.437-0.002,0.603l2.573,2.578c0.079,0.08,0.188,0.125,0.3,0.125s0.222-0.045,0.303-0.125l5.736-5.751C15.268,7.466,15.265,7.196,15.099,7.03"></path>
  962. </svg>
  963. <div class="flex-1 space-y-1">
  964. <p class="text-base leading-6 font-medium text-gray-700 dark:text-gray-400" x-text="title"></p>
  965. <p class="text-sm leading-5 text-gray-600 dark:text-gray-400" x-text="message"></p>
  966. </div>
  967. <svg class="flex-shrink-0 h-5 w-5 text-gray-400 cursor-pointer" x-on:click="isShow = false" stroke="currentColor" viewBox="0 0 20 20">
  968. <path stroke-width="1.2" d="M15.898,4.045c-0.271-0.272-0.713-0.272-0.986,0l-4.71,4.711L5.493,4.045c-0.272-0.272-0.714-0.272-0.986,0s-0.272,0.714,0,0.986l4.709,4.711l-4.71,4.711c-0.272,0.271-0.272,0.713,0,0.986c0.136,0.136,0.314,0.203,0.492,0.203c0.179,0,0.357-0.067,0.493-0.203l4.711-4.711l4.71,4.711c0.137,0.136,0.314,0.203,0.494,0.203c0.178,0,0.355-0.067,0.492-0.203c0.273-0.273,0.273-0.715,0-0.986l-4.711-4.711l4.711-4.711C16.172,4.759,16.172,4.317,15.898,4.045z"></path>
  969. </svg>
  970. </div>
  971. </div>
  972. <div class="w-full mt-12 p-3 dark:bg-gray-900 border dark:border-gray-800 rounded shadow">
  973. <div class="border-b bg-white-200 dark:bg-gray-900 dark:border-gray-800 p-3">
  974. <h5 class="font-bold uppercase dark:text-gray-600">Nodes</h5>
  975. </div>
  976. <br>
  977. <div class="relative mt-1 ">
  978. <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
  979. <svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20"
  980. xmlns="http://www.w3.org/2000/svg">
  981. <path fill-rule="evenodd"
  982. d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
  983. clip-rule="evenodd"></path>
  984. </svg>
  985. </div>
  986. <input
  987. x-ref="searchField"
  988. x-model="search"
  989. x-on:click="viewPage(0)"
  990. x-on:keydown.window.prevent.slash=" viewPage(0), $refs.searchField.focus()"
  991. placeholder="Search..."
  992. type="search"
  993. class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  994. />
  995. </div>
  996. <div class="overflow-auto">
  997. <table class="min-w-full bg-white-200 dark:bg-gray-900">
  998. <thead class="bg-slate-200 dark:bg-gray-800 dark:text-white">
  999. <tr>
  1000. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">PeerID</th>
  1001. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Online</th>
  1002. </tr>
  1003. </thead>
  1004. <tbody class="text-black dark:text-white">
  1005. <template x-for="(d, index) in filtered" :key="index">
  1006. <tr
  1007. >
  1008. <td x-text="d.ID" class="text-left py-3 px-4"></td>
  1009. <td x-text="d.Online" class="text-left py-3 px-4"></td>
  1010. </tr>
  1011. </template>
  1012. </tbody>
  1013. </table>
  1014. <!--Pagination Buttons-->
  1015. <div
  1016. class="w-full md:w-1/2 mx-auto py-6 flex justify-between items-center"
  1017. x-show="pageCount() > 1"
  1018. >
  1019. <!--First Button-->
  1020. <button
  1021. x-on:click="viewPage(0)"
  1022. :disabled="pageNumber==0"
  1023. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  1024. >
  1025. <svg
  1026. class="h-8 w-8 text-indigo-600"
  1027. width="24"
  1028. height="24"
  1029. viewBox="0 0 24 24"
  1030. fill="none"
  1031. stroke="currentColor"
  1032. stroke-width="2"
  1033. stroke-linecap="round"
  1034. stroke-linejoin="round"
  1035. >
  1036. <polygon points="19 20 9 12 19 4 19 20"></polygon>
  1037. <line x1="5" y1="19" x2="5" y2="5"></line>
  1038. </svg>
  1039. </button>
  1040. <!--Previous Button-->
  1041. <button
  1042. x-on:click="prevPage"
  1043. :disabled="pageNumber==0"
  1044. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  1045. >
  1046. <svg
  1047. class="h-8 w-8 text-indigo-600"
  1048. width="24"
  1049. height="24"
  1050. viewBox="0 0 24 24"
  1051. fill="none"
  1052. stroke="currentColor"
  1053. stroke-width="2"
  1054. stroke-linecap="round"
  1055. stroke-linejoin="round"
  1056. >
  1057. <polyline points="15 18 9 12 15 6"></polyline>
  1058. </svg>
  1059. </button>
  1060. <!-- Display page numbers -->
  1061. <template x-for="(page,index) in pages()" :key="page">
  1062. <button
  1063. class="px-3 py-2 rounded"
  1064. :class="{ 'bg-indigo-600 text-white font-bold' : page === pageNumber }"
  1065. type="button"
  1066. x-on:click="viewPage(page)"
  1067. >
  1068. <span x-text="page" class="dark:text-white"></span>
  1069. </button>
  1070. </template>
  1071. <!--Next Button-->
  1072. <button
  1073. x-on:click="nextPage"
  1074. :disabled="pageNumber >= pageCount() -1"
  1075. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  1076. >
  1077. <svg
  1078. class="h-8 w-8 text-indigo-600"
  1079. width="24"
  1080. height="24"
  1081. viewBox="0 0 24 24"
  1082. fill="none"
  1083. stroke="currentColor"
  1084. stroke-width="2"
  1085. stroke-linecap="round"
  1086. stroke-linejoin="round"
  1087. >
  1088. <polyline points="9 18 15 12 9 6"></polyline>
  1089. </svg>
  1090. </button>
  1091. <!--Last Button-->
  1092. <button
  1093. x-on:click="viewPage(Math.ceil(total/size)-1)"
  1094. :disabled="pageNumber >= pageCount() -1"
  1095. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  1096. >
  1097. <svg
  1098. class="h-8 w-8 text-indigo-600"
  1099. width="24"
  1100. height="24"
  1101. viewBox="0 0 24 24"
  1102. fill="none"
  1103. stroke="currentColor"
  1104. stroke-width="2"
  1105. stroke-linecap="round"
  1106. stroke-linejoin="round"
  1107. >
  1108. <polygon points="5 4 15 12 5 20 5 4"></polygon>
  1109. <line x1="19" y1="5" x2="19" y2="19"></line>
  1110. </svg>
  1111. </button>
  1112. </div>
  1113. <!-- /Pagination Buttons-->
  1114. </div>
  1115. </div>
  1116. </div>
  1117. <hr class="border-b-2 border-gray-600 my-8 mx-4">
  1118. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal"
  1119. x-data="peerstore()"
  1120. x-init="$interval(updateItems, 1500)"
  1121. >
  1122. <!-- Notification toast -->
  1123. <div
  1124. x-show="open"
  1125. class="w-96 p-4 rounded h-32 fixed bottom-4 right-4 transform-gpu transition-transform duration-400 ease"
  1126. x-class="success ? 'bg-green-500' : 'bg-red-500'"
  1127. x-transition:enter-start="opacity-0 translate-y-full"
  1128. x-transition:enter-end="opacity-100 translate-y-0"
  1129. x-transition:leave-start="translate-y-0"
  1130. x-transition:leave="transition transform ease-in duration-300"
  1131. x-transition:leave-end="opacity-0 translate-y-full"
  1132. >
  1133. <div class="bg-white border-gray-300 dark:border-slate-800 dark:bg-slate-900 border p-3 flex items-start shadow-lg rounded-md space-x-2">
  1134. <svg class="flex-shrink-0 h-6 w-6 text-green-400" stroke="currentColor" viewBox="0 0 20 20">
  1135. <path stroke-width="1" d="M10.219,1.688c-4.471,0-8.094,3.623-8.094,8.094s3.623,8.094,8.094,8.094s8.094-3.623,8.094-8.094S14.689,1.688,10.219,1.688 M10.219,17.022c-3.994,0-7.242-3.247-7.242-7.241c0-3.994,3.248-7.242,7.242-7.242c3.994,0,7.241,3.248,7.241,7.242C17.46,13.775,14.213,17.022,10.219,17.022 M15.099,7.03c-0.167-0.167-0.438-0.167-0.604,0.002L9.062,12.48l-2.269-2.277c-0.166-0.167-0.437-0.167-0.603,0c-0.166,0.166-0.168,0.437-0.002,0.603l2.573,2.578c0.079,0.08,0.188,0.125,0.3,0.125s0.222-0.045,0.303-0.125l5.736-5.751C15.268,7.466,15.265,7.196,15.099,7.03"></path>
  1136. </svg>
  1137. <div class="flex-1 space-y-1">
  1138. <p class="text-base leading-6 font-medium text-gray-700 dark:text-gray-400" x-text="title"></p>
  1139. <p class="text-sm leading-5 text-gray-600 dark:text-gray-400" x-text="message"></p>
  1140. </div>
  1141. <svg class="flex-shrink-0 h-5 w-5 text-gray-400 cursor-pointer" x-on:click="isShow = false" stroke="currentColor" viewBox="0 0 20 20">
  1142. <path stroke-width="1.2" d="M15.898,4.045c-0.271-0.272-0.713-0.272-0.986,0l-4.71,4.711L5.493,4.045c-0.272-0.272-0.714-0.272-0.986,0s-0.272,0.714,0,0.986l4.709,4.711l-4.71,4.711c-0.272,0.271-0.272,0.713,0,0.986c0.136,0.136,0.314,0.203,0.492,0.203c0.179,0,0.357-0.067,0.493-0.203l4.711-4.711l4.71,4.711c0.137,0.136,0.314,0.203,0.494,0.203c0.178,0,0.355-0.067,0.492-0.203c0.273-0.273,0.273-0.715,0-0.986l-4.711-4.711l4.711-4.711C16.172,4.759,16.172,4.317,15.898,4.045z"></path>
  1143. </svg>
  1144. </div>
  1145. </div>
  1146. <div class="w-full mt-12 p-3 dark:bg-gray-900 border dark:border-gray-800 rounded shadow">
  1147. <div class="border-b bg-white-200 dark:bg-gray-900 dark:border-gray-800 p-3">
  1148. <h5 class="font-bold uppercase dark:text-gray-600">Peer store</h5>
  1149. </div>
  1150. <br>
  1151. <div class="relative mt-1 ">
  1152. <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
  1153. <svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20"
  1154. xmlns="http://www.w3.org/2000/svg">
  1155. <path fill-rule="evenodd"
  1156. d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
  1157. clip-rule="evenodd"></path>
  1158. </svg>
  1159. </div>
  1160. <input
  1161. x-ref="searchField"
  1162. x-model="search"
  1163. x-on:click="viewPage(0)"
  1164. x-on:keydown.window.prevent.slash=" viewPage(0), $refs.searchField.focus()"
  1165. placeholder="Search..."
  1166. type="search"
  1167. class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  1168. />
  1169. </div>
  1170. <div class="overflow-auto">
  1171. <table class="min-w-full bg-white-200 dark:bg-gray-900">
  1172. <thead class="bg-slate-200 dark:bg-gray-800 dark:text-white">
  1173. <tr>
  1174. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">PeerID</th>
  1175. </tr>
  1176. </thead>
  1177. <tbody class="text-black dark:text-white">
  1178. <template x-for="(d, index) in filtered" :key="index">
  1179. <tr
  1180. >
  1181. <td x-text="d.ID" class="text-left py-3 px-4"></td>
  1182. </tr>
  1183. </template>
  1184. </tbody>
  1185. </table>
  1186. <!--Pagination Buttons-->
  1187. <div
  1188. class="w-full md:w-1/2 mx-auto py-6 flex justify-between items-center"
  1189. x-show="pageCount() > 1"
  1190. >
  1191. <!--First Button-->
  1192. <button
  1193. x-on:click="viewPage(0)"
  1194. :disabled="pageNumber==0"
  1195. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  1196. >
  1197. <svg
  1198. class="h-8 w-8 text-indigo-600"
  1199. width="24"
  1200. height="24"
  1201. viewBox="0 0 24 24"
  1202. fill="none"
  1203. stroke="currentColor"
  1204. stroke-width="2"
  1205. stroke-linecap="round"
  1206. stroke-linejoin="round"
  1207. >
  1208. <polygon points="19 20 9 12 19 4 19 20"></polygon>
  1209. <line x1="5" y1="19" x2="5" y2="5"></line>
  1210. </svg>
  1211. </button>
  1212. <!--Previous Button-->
  1213. <button
  1214. x-on:click="prevPage"
  1215. :disabled="pageNumber==0"
  1216. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  1217. >
  1218. <svg
  1219. class="h-8 w-8 text-indigo-600"
  1220. width="24"
  1221. height="24"
  1222. viewBox="0 0 24 24"
  1223. fill="none"
  1224. stroke="currentColor"
  1225. stroke-width="2"
  1226. stroke-linecap="round"
  1227. stroke-linejoin="round"
  1228. >
  1229. <polyline points="15 18 9 12 15 6"></polyline>
  1230. </svg>
  1231. </button>
  1232. <!-- Display page numbers -->
  1233. <template x-for="(page,index) in pages()" :key="page">
  1234. <button
  1235. class="px-3 py-2 rounded"
  1236. :class="{ 'bg-indigo-600 text-white font-bold' : page === pageNumber }"
  1237. type="button"
  1238. x-on:click="viewPage(page)"
  1239. >
  1240. <span x-text="page" class="dark:text-white"></span>
  1241. </button>
  1242. </template>
  1243. <!--Next Button-->
  1244. <button
  1245. x-on:click="nextPage"
  1246. :disabled="pageNumber >= pageCount() -1"
  1247. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  1248. >
  1249. <svg
  1250. class="h-8 w-8 text-indigo-600"
  1251. width="24"
  1252. height="24"
  1253. viewBox="0 0 24 24"
  1254. fill="none"
  1255. stroke="currentColor"
  1256. stroke-width="2"
  1257. stroke-linecap="round"
  1258. stroke-linejoin="round"
  1259. >
  1260. <polyline points="9 18 15 12 9 6"></polyline>
  1261. </svg>
  1262. </button>
  1263. <!--Last Button-->
  1264. <button
  1265. x-on:click="viewPage(Math.ceil(total/size)-1)"
  1266. :disabled="pageNumber >= pageCount() -1"
  1267. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  1268. >
  1269. <svg
  1270. class="h-8 w-8 text-indigo-600"
  1271. width="24"
  1272. height="24"
  1273. viewBox="0 0 24 24"
  1274. fill="none"
  1275. stroke="currentColor"
  1276. stroke-width="2"
  1277. stroke-linecap="round"
  1278. stroke-linejoin="round"
  1279. >
  1280. <polygon points="5 4 15 12 5 20 5 4"></polygon>
  1281. <line x1="19" y1="5" x2="19" y2="19"></line>
  1282. </svg>
  1283. </button>
  1284. </div>
  1285. <!-- /Pagination Buttons-->
  1286. </div>
  1287. </div>
  1288. </div>
  1289. </div>
  1290. </div>
  1291. <!--END Peers Container-->
  1292. <!-- Index Container-->
  1293. <div class="container w-full mx-auto pt-20" x-show="page === ''">
  1294. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal"
  1295. x-data="summary()"
  1296. x-init="$interval(updateItems, 1500); initChart()"
  1297. >
  1298. <!--Summary Content-->
  1299. <div class="flex flex-wrap">
  1300. <div class="w-full md:w-1/2 xl:w-1/3 p-3">
  1301. <!--Metric Card-->
  1302. <div class="dark:bg-gray-900 bg-white-100 dark:border-gray-800 dark:border-gray-600 border-b-4 rounded shadow p-2">
  1303. <div class="flex flex-row items-center">
  1304. <div class="flex-shrink pr-4">
  1305. <div class="rounded p-3 bg-emerald-600"><i class="fas fa-network-wired fa-2x fa-fw fa-inverse"></i></div>
  1306. </div>
  1307. <div class="flex-1 text-right md:text-center">
  1308. <h5 class="font-bold uppercase text-gray-400">VPN Nodes</h5>
  1309. <h3 class="font-bold text-3xl text-gray-600" x-text="summary.Machines"></h3>
  1310. </div>
  1311. </div>
  1312. </div>
  1313. <!--/Metric Card-->
  1314. </div>
  1315. <div class="w-full md:w-1/2 xl:w-1/3 p-3">
  1316. <!--Metric Card-->
  1317. <div class="dark:bg-gray-900 bg-white-100 dark:border-gray-800 dark:border-gray-600 border-b-4 rounded shadow p-2">
  1318. <div class="flex flex-row items-center">
  1319. <div class="flex-shrink pr-4">
  1320. <div class="rounded p-3 bg-cyan-600"><i class="fa-solid fa-circle-nodes fa-2x fa-fw fa-inverse"></i></div>
  1321. </div>
  1322. <div class="flex-1 text-right md:text-center">
  1323. <h5 class="font-bold uppercase text-gray-400">P2P peers</h5>
  1324. <h3 class="font-bold text-3xl text-gray-600" x-text="summary.Peers"></h3>
  1325. </div>
  1326. </div>
  1327. </div>
  1328. <!--/Metric Card-->
  1329. </div>
  1330. <div class="w-full md:w-1/2 xl:w-1/3 p-3">
  1331. <!--Metric Card-->
  1332. <div class="dark:bg-gray-900 bg-white-100 dark:border-gray-800 dark:border-gray-600 border-b-4 rounded shadow p-2">
  1333. <div class="flex flex-row items-center">
  1334. <div class="flex-shrink pr-4">
  1335. <div class="rounded p-3 bg-yellow-600"><i class="fa-solid fa-box-archive fa-2x fa-fw fa-inverse"></i></div>
  1336. </div>
  1337. <div class="flex-1 text-right md:text-center">
  1338. <h5 class="font-bold uppercase text-gray-400">Files</h5>
  1339. <h3 class="font-bold text-3xl text-gray-600" x-text="summary.Files"></h3>
  1340. </div>
  1341. </div>
  1342. </div>
  1343. <!--/Metric Card-->
  1344. </div>
  1345. <div class="w-full md:w-1/2 xl:w-1/3 p-3">
  1346. <!--Metric Card-->
  1347. <div class="dark:bg-gray-900 bg-white-100 dark:border-gray-800 dark:border-gray-600 border-b-4 rounded shadow p-2">
  1348. <div class="flex flex-row items-center">
  1349. <div class="flex-shrink pr-4">
  1350. <div class="rounded p-3 bg-pink-600"><i class="fas fa-users fa-2x fa-fw fa-inverse"></i></div>
  1351. </div>
  1352. <div class="flex-1 text-right md:text-center">
  1353. <h5 class="font-bold uppercase text-gray-400">Users</h5>
  1354. <h3 class="font-bold text-3xl text-gray-600" x-text="summary.Users"></h3>
  1355. </div>
  1356. </div>
  1357. </div>
  1358. <!--/Metric Card-->
  1359. </div>
  1360. <div class="w-full md:w-1/2 xl:w-1/3 p-3">
  1361. <!--Metric Card-->
  1362. <div class="dark:bg-gray-900 bg-white-100 dark:border-gray-800 dark:border-gray-600 border-b-4 rounded shadow p-2">
  1363. <div class="flex flex-row items-center">
  1364. <div class="flex-shrink pr-4">
  1365. <div class="rounded p-3 bg-indigo-600"><i class="fas fa-dice-d20 fa-2x fa-fw fa-inverse"></i></div>
  1366. </div>
  1367. <div class="flex-1 text-right md:text-center">
  1368. <h5 class="font-bold uppercase text-gray-400">Blockchain index</h5>
  1369. <h3 class="font-bold text-3xl text-gray-600" x-text="summary.BlockChain"></h3>
  1370. </div>
  1371. </div>
  1372. </div>
  1373. <!--/Metric Card-->
  1374. </div>
  1375. <div class="w-full md:w-1/2 xl:w-1/3 p-3">
  1376. <!--Metric Card-->
  1377. <div class="dark:bg-gray-900 bg-white-100 dark:border-gray-800 dark:border-gray-600 border-b-4 rounded shadow p-2">
  1378. <div class="flex flex-row items-center">
  1379. <div class="flex-shrink pr-4">
  1380. <div class="rounded p-3 bg-sky-600"><i class="fa-solid fa-car-tunnel fa-2x fa-fw fa-inverse"></i></div>
  1381. </div>
  1382. <div class="flex-1 text-right md:text-center">
  1383. <h5 class="font-bold uppercase text-gray-400">Services</h5>
  1384. <h3 class="font-bold text-3xl text-gray-600" x-text="summary.Services"></h3>
  1385. </div>
  1386. </div>
  1387. </div>
  1388. <!--/Metric Card-->
  1389. </div>
  1390. <div class="w-full md:w-1/2 xl:w-1/3 p-3">
  1391. <!--Metric Card-->
  1392. <div class="dark:bg-gray-900 bg-white-100 dark:border-gray-800 dark:border-gray-600 border-b-4 rounded shadow p-2">
  1393. <div class="flex flex-row items-center">
  1394. <div class="flex-shrink pr-4">
  1395. <div class="rounded p-3 bg-cyan-600"><i class="fas fa-download fa-2x fa-fw fa-inverse"></i></div>
  1396. </div>
  1397. <div class="flex-1 text-right md:text-center">
  1398. <h5 class="font-bold uppercase text-gray-400">Total downloaded</h5>
  1399. <h3 class="font-bold text-3xl text-gray-600" x-text="bytesToSize(metrics.TotalIn)"></h3>
  1400. </div>
  1401. </div>
  1402. </div>
  1403. <!--/Metric Card-->
  1404. </div>
  1405. <div class="w-full md:w-1/2 xl:w-1/3 p-3 text-gray-800 ">
  1406. <div class="dark:bg-gray-900 rounded shadow dark:border-gray-600 border-b-4 ">
  1407. <div class="bg-white-200 dark:bg-gray-900 p-3">
  1408. <h5 class="font-bold float-left uppercase text-gray-400">
  1409. <span class="rounded p-1 bg-teal-600"><i class="fa-duotone fa-right-left fa-fw fa-inverse"></i></span>
  1410. Bandwidth
  1411. </h5>
  1412. <h5 class="font-bold uppercase float-right text-gray-600">
  1413. <span class="rounded p-1 bg-cyan-600"><i class="fas fa-arrow-down fa-fw fa-inverse"></i></span>
  1414. <span x-text="bytesToSize(metrics.RateIn)"></span>
  1415. <span class="rounded p-1 bg-amber-600"><i class="fas fa-arrow-up fa-fw fa-inverse"></i></span>
  1416. <span x-text="bytesToSize(metrics.RateOut)"></span>
  1417. </h5>
  1418. </div>
  1419. <br>
  1420. <div class=" relative mt-1 ">
  1421. <!-- Network stat Card-->
  1422. <div class="dark:bg-gray-900 bg-white-100 rounded shadow p-2">
  1423. <div class="flex flex-row items-center">
  1424. <div class="flex-1 text-right md:text-center">
  1425. <div x-ref="chart"></div>
  1426. </div>
  1427. </div>
  1428. </div>
  1429. <!--/Network stat Card-->
  1430. </div>
  1431. </div>
  1432. </div>
  1433. <div class="w-full md:w-1/2 xl:w-1/3 p-3">
  1434. <!--Metric Card-->
  1435. <div class="dark:bg-gray-900 bg-white-100 dark:border-gray-800 dark:border-gray-600 border-b-4 rounded shadow p-2">
  1436. <div class="flex flex-row items-center">
  1437. <div class="flex-shrink pr-4">
  1438. <div class="rounded p-3 bg-amber-600"><i class="fas fa-upload fa-2x fa-fw fa-inverse"></i></div>
  1439. </div>
  1440. <div class="flex-1 text-right md:text-center">
  1441. <h5 class="font-bold uppercase text-gray-400">Total uploaded</h5>
  1442. <h3 class="font-bold text-3xl text-gray-600" x-text="bytesToSize(metrics.TotalOut)"></h3>
  1443. </div>
  1444. </div>
  1445. </div>
  1446. <!--/Metric Card-->
  1447. </div>
  1448. <!--Divider-->
  1449. <hr class="border-b-2 border-gray-600 my-8 mx-4">
  1450. <div class="w-full px-4 md:px-0 md:mt-8 mb-16 text-gray-800 leading-normal"
  1451. x-data="users()"
  1452. x-init="$interval(updateItems, 1500)"
  1453. >
  1454. <!-- Notification toast -->
  1455. <div
  1456. x-show="open"
  1457. class="w-96 p-4 rounded h-32 fixed bottom-4 right-4 transform-gpu transition-transform duration-400 ease"
  1458. x-class="success ? 'bg-green-500' : 'bg-red-500'"
  1459. x-transition:enter-start="opacity-0 translate-y-full"
  1460. x-transition:enter-end="opacity-100 translate-y-0"
  1461. x-transition:leave-start="translate-y-0"
  1462. x-transition:leave="transition transform ease-in duration-300"
  1463. x-transition:leave-end="opacity-0 translate-y-full"
  1464. >
  1465. <div class="bg-white border-gray-300 dark:border-slate-800 dark:bg-slate-900 border p-3 flex items-start shadow-lg rounded-md space-x-2">
  1466. <svg class="flex-shrink-0 h-6 w-6 text-green-400" stroke="currentColor" viewBox="0 0 20 20">
  1467. <path stroke-width="1" d="M10.219,1.688c-4.471,0-8.094,3.623-8.094,8.094s3.623,8.094,8.094,8.094s8.094-3.623,8.094-8.094S14.689,1.688,10.219,1.688 M10.219,17.022c-3.994,0-7.242-3.247-7.242-7.241c0-3.994,3.248-7.242,7.242-7.242c3.994,0,7.241,3.248,7.241,7.242C17.46,13.775,14.213,17.022,10.219,17.022 M15.099,7.03c-0.167-0.167-0.438-0.167-0.604,0.002L9.062,12.48l-2.269-2.277c-0.166-0.167-0.437-0.167-0.603,0c-0.166,0.166-0.168,0.437-0.002,0.603l2.573,2.578c0.079,0.08,0.188,0.125,0.3,0.125s0.222-0.045,0.303-0.125l5.736-5.751C15.268,7.466,15.265,7.196,15.099,7.03"></path>
  1468. </svg>
  1469. <div class="flex-1 space-y-1">
  1470. <p class="text-base leading-6 font-medium text-gray-700 dark:text-gray-400" x-text="title"></p>
  1471. <p class="text-sm leading-5 text-gray-600 dark:text-gray-400" x-text="message"></p>
  1472. </div>
  1473. <svg class="flex-shrink-0 h-5 w-5 text-gray-400 cursor-pointer" x-on:click="isShow = false" stroke="currentColor" viewBox="0 0 20 20">
  1474. <path stroke-width="1.2" d="M15.898,4.045c-0.271-0.272-0.713-0.272-0.986,0l-4.71,4.711L5.493,4.045c-0.272-0.272-0.714-0.272-0.986,0s-0.272,0.714,0,0.986l4.709,4.711l-4.71,4.711c-0.272,0.271-0.272,0.713,0,0.986c0.136,0.136,0.314,0.203,0.492,0.203c0.179,0,0.357-0.067,0.493-0.203l4.711-4.711l4.71,4.711c0.137,0.136,0.314,0.203,0.494,0.203c0.178,0,0.355-0.067,0.492-0.203c0.273-0.273,0.273-0.715,0-0.986l-4.711-4.711l4.711-4.711C16.172,4.759,16.172,4.317,15.898,4.045z"></path>
  1475. </svg>
  1476. </div>
  1477. </div>
  1478. <div class="w-full mt-12 p-3 dark:bg-gray-900 border dark:border-gray-800 rounded shadow">
  1479. <div class="border-b bg-white-200 dark:bg-gray-900 dark:border-gray-800 p-3">
  1480. <h5 class="font-bold uppercase dark:text-gray-600">Connected users</h5>
  1481. </div>
  1482. <br>
  1483. <div class="relative mt-1 ">
  1484. <div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
  1485. <svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20"
  1486. xmlns="http://www.w3.org/2000/svg">
  1487. <path fill-rule="evenodd"
  1488. d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
  1489. clip-rule="evenodd"></path>
  1490. </svg>
  1491. </div>
  1492. <input
  1493. x-ref="searchField"
  1494. x-model="search"
  1495. x-on:click="viewPage(0)"
  1496. x-on:keydown.window.prevent.slash=" viewPage(0), $refs.searchField.focus()"
  1497. placeholder="Search..."
  1498. type="search"
  1499. class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
  1500. />
  1501. </div>
  1502. <div class="overflow-auto">
  1503. <table class="min-w-full bg-white-200 dark:bg-gray-900">
  1504. <thead class="bg-slate-200 dark:bg-gray-800 dark:text-white">
  1505. <tr>
  1506. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">PeerID</th>
  1507. <th class="w-1/3 text-left py-3 px-4 uppercase font-semibold text-sm">Time</th>
  1508. </tr>
  1509. </thead>
  1510. <tbody class="text-black dark:text-white">
  1511. <template x-for="(d, index) in filtered" :key="index">
  1512. <tr
  1513. >
  1514. <td x-text="d.PeerID" class="text-left py-3 px-4"></td>
  1515. <td x-text="d.Timestamp" class="text-left py-3 px-4"></td>
  1516. </tr>
  1517. </template>
  1518. </tbody>
  1519. </table>
  1520. <!--Pagination Buttons-->
  1521. <div
  1522. class="w-full md:w-1/2 mx-auto py-6 flex justify-between items-center"
  1523. x-show="pageCount() > 1"
  1524. >
  1525. <!--First Button-->
  1526. <button
  1527. x-on:click="viewPage(0)"
  1528. :disabled="pageNumber==0"
  1529. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  1530. >
  1531. <svg
  1532. class="h-8 w-8 text-indigo-600"
  1533. width="24"
  1534. height="24"
  1535. viewBox="0 0 24 24"
  1536. fill="none"
  1537. stroke="currentColor"
  1538. stroke-width="2"
  1539. stroke-linecap="round"
  1540. stroke-linejoin="round"
  1541. >
  1542. <polygon points="19 20 9 12 19 4 19 20"></polygon>
  1543. <line x1="5" y1="19" x2="5" y2="5"></line>
  1544. </svg>
  1545. </button>
  1546. <!--Previous Button-->
  1547. <button
  1548. x-on:click="prevPage"
  1549. :disabled="pageNumber==0"
  1550. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber==0 }"
  1551. >
  1552. <svg
  1553. class="h-8 w-8 text-indigo-600"
  1554. width="24"
  1555. height="24"
  1556. viewBox="0 0 24 24"
  1557. fill="none"
  1558. stroke="currentColor"
  1559. stroke-width="2"
  1560. stroke-linecap="round"
  1561. stroke-linejoin="round"
  1562. >
  1563. <polyline points="15 18 9 12 15 6"></polyline>
  1564. </svg>
  1565. </button>
  1566. <!-- Display page numbers -->
  1567. <template x-for="(page,index) in pages()" :key="page">
  1568. <button
  1569. class="px-3 py-2 rounded"
  1570. :class="{ 'bg-indigo-600 text-white font-bold' : page === pageNumber }"
  1571. type="button"
  1572. x-on:click="viewPage(page)"
  1573. >
  1574. <span x-text="page" class="dark:text-white"></span>
  1575. </button>
  1576. </template>
  1577. <!--Next Button-->
  1578. <button
  1579. x-on:click="nextPage"
  1580. :disabled="pageNumber >= pageCount() -1"
  1581. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  1582. >
  1583. <svg
  1584. class="h-8 w-8 text-indigo-600"
  1585. width="24"
  1586. height="24"
  1587. viewBox="0 0 24 24"
  1588. fill="none"
  1589. stroke="currentColor"
  1590. stroke-width="2"
  1591. stroke-linecap="round"
  1592. stroke-linejoin="round"
  1593. >
  1594. <polyline points="9 18 15 12 9 6"></polyline>
  1595. </svg>
  1596. </button>
  1597. <!--Last Button-->
  1598. <button
  1599. x-on:click="viewPage(Math.ceil(total/size)-1)"
  1600. :disabled="pageNumber >= pageCount() -1"
  1601. :class="{ 'disabled cursor-not-allowed text-gray-600' : pageNumber >= pageCount() -1 }"
  1602. >
  1603. <svg
  1604. class="h-8 w-8 text-indigo-600"
  1605. width="24"
  1606. height="24"
  1607. viewBox="0 0 24 24"
  1608. fill="none"
  1609. stroke="currentColor"
  1610. stroke-width="2"
  1611. stroke-linecap="round"
  1612. stroke-linejoin="round"
  1613. >
  1614. <polygon points="5 4 15 12 5 20 5 4"></polygon>
  1615. <line x1="19" y1="5" x2="19" y2="19"></line>
  1616. </svg>
  1617. </button>
  1618. </div>
  1619. <!-- /Pagination Buttons-->
  1620. </div>
  1621. </div>
  1622. </div>
  1623. <!--/ Summary Content-->
  1624. </div>
  1625. </div>
  1626. <!--END Index /container-->
  1627. <footer class="dark:bg-gray-900 border-t dark:border-gray-400 shadow">
  1628. <div class="container max-w-md mx-auto flex py-8">
  1629. <div class="w-full mx-auto flex flex-wrap">
  1630. <div class="flex w-full md:w-1/2 ">
  1631. <div class="px-8">
  1632. <h3 class="font-bold font-bold dark:text-gray-100">About</h3>
  1633. <p class="py-4 text-gray-600 text-sm">
  1634. <strong>EdgeVPN</strong> by <a href="https://github.com/mudler/edgevpn">Ettore Di Giacinto</a>.<br>
  1635. License <a href="https://github.com/mudler/edgevpn/blob/master/LICENSE">Apache v2</a>. <br>
  1636. Logo originally made by <a href="https://www.flaticon.com/authors/uniconlabs" title="Uniconlabs">Uniconlabs</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
  1637. </p>
  1638. </div>
  1639. </div>
  1640. <div class="flex w-full md:w-1/2">
  1641. <div class="px-8">
  1642. <h3 class="font-bold font-bold dark:text-gray-100">Links</h3>
  1643. <ul class="list-reset items-center text-sm pt-3">
  1644. <li>
  1645. <a class="inline-block text-gray-600 no-underline hover:text-black dark:hover:text-gray-100 hover:text-underline py-1" href="https://github.com/mudler/edgevpn" target=_blank><i class="fa-brands fa-github-alt fa-fw mr-3"></i>Github</a>
  1646. </li>
  1647. <li>
  1648. <a class="inline-block text-gray-600 no-underline hover:text-black dark:hover:text-gray-100 hover:text-underline py-1" href="https://mudler.github.io/edgevpn/docs" target=_blank><i class="fas fa-book fa-fw mr-3"></i>Documentation</a>
  1649. </li>
  1650. <li>
  1651. <a class="inline-block text-gray-600 no-underline hover:text-black dark:hover:text-gray-100 hover:text-underline py-1" href="https://github.com/mudler/edgevpn/issues/new" target=_blank><i class="fas fa-bug fa-fw mr-3"></i>Report issue</a>
  1652. </li>
  1653. </ul>
  1654. </div>
  1655. </div>
  1656. </div>
  1657. </div>
  1658. </footer>
  1659. <script>
  1660. function bytesToSize(bytes, decimals = 2) {
  1661. if (bytes === 0) return '0 Bytes';
  1662. const k = 1024;
  1663. const dm = decimals < 0 ? 0 : decimals;
  1664. const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
  1665. const i = Math.floor(Math.log(bytes) / Math.log(k));
  1666. var s = sizes[i]
  1667. if (!sizes[i]) {
  1668. s = "B"
  1669. }
  1670. return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + s;
  1671. }
  1672. function scaleSize(bytes, scale = 1, decimals = 2) {
  1673. if (bytes === 0) return '0';
  1674. const k = 1024;
  1675. const dm = decimals < 0 ? 0 : decimals;
  1676. //const i = Math.floor(Math.log(bytes) / Math.log(k));
  1677. //console.log(i)
  1678. return parseFloat((bytes / Math.pow(k, scale)).toFixed(dm));
  1679. }
  1680. const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
  1681. function calcPages(n, total, size) {
  1682. start = 1;
  1683. if (n > 5 ){
  1684. start = n - 5
  1685. }
  1686. end = Math.ceil(total / size);
  1687. if (end - n > 5 ){
  1688. end = n + 5
  1689. // Math.ceil(this.total / this.size) - 10
  1690. }
  1691. return range(start, end ,1)
  1692. }
  1693. function filter(obj, key) {
  1694. const start = obj.pageNumber * obj.size,
  1695. end = start + obj.size;
  1696. if (obj.search === "") {
  1697. obj.total = obj.data.length;
  1698. return obj.data.slice(start, end);
  1699. }
  1700. //Return the total results of the filters
  1701. obj.total = obj.data.filter((item) => {
  1702. return item[key]
  1703. .toLowerCase()
  1704. .includes(obj.search.toLowerCase());
  1705. }).length;
  1706. //Return the filtered data
  1707. return obj.data
  1708. .filter((item) => {
  1709. return item[key]
  1710. .toLowerCase()
  1711. .includes(obj.search.toLowerCase());
  1712. })
  1713. .slice(start, end);
  1714. }
  1715. function endRes(obj) {
  1716. let resultsOnPage = (obj.pageNumber + 1) * obj.size;
  1717. if (resultsOnPage <= obj.total) {
  1718. return resultsOnPage;
  1719. }
  1720. return obj.total;
  1721. }
  1722. function sortData(key, order = "asc") {
  1723. return function innerSort(a, b) {
  1724. if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
  1725. return 0;
  1726. }
  1727. const varA = typeof a[key] === "string" ? a[key].toUpperCase() : a[key];
  1728. const varB = typeof b[key] === "string" ? b[key].toUpperCase() : b[key];
  1729. let comparison = 0;
  1730. if (varA > varB) {
  1731. comparison = 1;
  1732. } else if (varA < varB) {
  1733. comparison = -1;
  1734. }
  1735. return order === "desc" ? comparison * -1 : comparison;
  1736. }
  1737. }
  1738. function machines(){
  1739. return {
  1740. data: [
  1741. ],
  1742. open: false,
  1743. title: "",
  1744. message: "",
  1745. success: false,
  1746. openToast(title, message, success) {
  1747. this.title = title
  1748. this.message = message
  1749. this.success = success
  1750. this.open = true
  1751. setTimeout(() => {
  1752. this.open = false
  1753. }, 5000)
  1754. },
  1755. deleteItem(item) {
  1756. fetch('/api/ledger/machines/'.concat("",item), {
  1757. method: 'DELETE',
  1758. });
  1759. this.openToast("Delete", "Announcing deletion to the blockchain, please wait", true);
  1760. },
  1761. updateItems() {
  1762. fetch('/api/machines')
  1763. .then(response => response.json())
  1764. .then(data => {
  1765. data.sort(sortData("Address","asc"));
  1766. this.data = data;
  1767. } )
  1768. },
  1769. search: "",
  1770. pageNumber: 0,
  1771. size: 10,
  1772. total: "",
  1773. get filtered() {return filter(this, "Address") },
  1774. //Create array of all pages (for loop to display page numbers)
  1775. pages() {
  1776. return calcPages(this.pageNumber, this.total, this.size)
  1777. },
  1778. //Next Page
  1779. nextPage() {
  1780. this.pageNumber++;
  1781. },
  1782. //Previous Page
  1783. prevPage() {
  1784. this.pageNumber--;
  1785. },
  1786. //Total number of pages
  1787. pageCount() {
  1788. return Math.ceil(this.total / this.size);
  1789. },
  1790. //Return the start range of the paginated results
  1791. startResults() {
  1792. return this.pageNumber * this.size + 1;
  1793. },
  1794. //Return the end range of the paginated results
  1795. endResults() {
  1796. return endRes(this)
  1797. },
  1798. //Link to navigate to page
  1799. viewPage(index) {
  1800. this.pageNumber = index;
  1801. },
  1802. };
  1803. }
  1804. function peerstore(){
  1805. return {
  1806. data: [
  1807. ],
  1808. open: false,
  1809. title: "",
  1810. message: "",
  1811. success: false,
  1812. openToast(title, message, success) {
  1813. this.title = title
  1814. this.message = message
  1815. this.success = success
  1816. this.open = true
  1817. setTimeout(() => {
  1818. this.open = false
  1819. }, 5000)
  1820. },
  1821. updateItems() {
  1822. fetch('/api/peerstore')
  1823. .then(response => response.json())
  1824. .then(data => {
  1825. data.sort(sortData("ID","asc"));
  1826. this.data = data;
  1827. } )
  1828. },
  1829. search: "",
  1830. pageNumber: 0,
  1831. size: 10,
  1832. total: "",
  1833. get filtered() {return filter(this, "ID") },
  1834. //Create array of all pages (for loop to display page numbers)
  1835. pages() {
  1836. return calcPages(this.pageNumber, this.total, this.size)
  1837. },
  1838. //Next Page
  1839. nextPage() {
  1840. this.pageNumber++;
  1841. },
  1842. //Previous Page
  1843. prevPage() {
  1844. this.pageNumber--;
  1845. },
  1846. //Total number of pages
  1847. pageCount() {
  1848. return Math.ceil(this.total / this.size);
  1849. },
  1850. //Return the start range of the paginated results
  1851. startResults() {
  1852. return this.pageNumber * this.size + 1;
  1853. },
  1854. //Return the end range of the paginated results
  1855. endResults() {
  1856. return endRes(this)
  1857. },
  1858. //Link to navigate to page
  1859. viewPage(index) {
  1860. this.pageNumber = index;
  1861. },
  1862. };
  1863. }
  1864. function nodes(){
  1865. return {
  1866. data: [
  1867. ],
  1868. open: false,
  1869. title: "",
  1870. message: "",
  1871. success: false,
  1872. openToast(title, message, success) {
  1873. this.title = title
  1874. this.message = message
  1875. this.success = success
  1876. this.open = true
  1877. setTimeout(() => {
  1878. this.open = false
  1879. }, 5000)
  1880. },
  1881. updateItems() {
  1882. fetch('/api/nodes')
  1883. .then(response => response.json())
  1884. .then(data => {
  1885. data.sort(sortData("ID","asc"));
  1886. this.data = data;
  1887. } )
  1888. },
  1889. search: "",
  1890. pageNumber: 0,
  1891. size: 10,
  1892. total: "",
  1893. get filtered() {return filter(this, "ID") },
  1894. //Create array of all pages (for loop to display page numbers)
  1895. pages() {
  1896. return calcPages(this.pageNumber, this.total, this.size)
  1897. },
  1898. //Next Page
  1899. nextPage() {
  1900. this.pageNumber++;
  1901. },
  1902. //Previous Page
  1903. prevPage() {
  1904. this.pageNumber--;
  1905. },
  1906. //Total number of pages
  1907. pageCount() {
  1908. return Math.ceil(this.total / this.size);
  1909. },
  1910. //Return the start range of the paginated results
  1911. startResults() {
  1912. return this.pageNumber * this.size + 1;
  1913. },
  1914. //Return the end range of the paginated results
  1915. endResults() {
  1916. return endRes(this)
  1917. },
  1918. //Link to navigate to page
  1919. viewPage(index) {
  1920. this.pageNumber = index;
  1921. },
  1922. };
  1923. }
  1924. function users(){
  1925. return {
  1926. data: [
  1927. ],
  1928. open: false,
  1929. title: "",
  1930. message: "",
  1931. success: false,
  1932. openToast(title, message, success) {
  1933. this.title = title
  1934. this.message = message
  1935. this.success = success
  1936. this.open = true
  1937. setTimeout(() => {
  1938. this.open = false
  1939. }, 5000)
  1940. },
  1941. updateItems() {
  1942. fetch('/api/users')
  1943. .then(response => response.json())
  1944. .then(data => {
  1945. data.sort(sortData("ID","asc"));
  1946. this.data = data;
  1947. } )
  1948. },
  1949. search: "",
  1950. pageNumber: 0,
  1951. size: 10,
  1952. total: "",
  1953. get filtered() {return filter(this, "ID") },
  1954. //Create array of all pages (for loop to display page numbers)
  1955. pages() {
  1956. return calcPages(this.pageNumber, this.total, this.size)
  1957. },
  1958. //Next Page
  1959. nextPage() {
  1960. this.pageNumber++;
  1961. },
  1962. //Previous Page
  1963. prevPage() {
  1964. this.pageNumber--;
  1965. },
  1966. //Total number of pages
  1967. pageCount() {
  1968. return Math.ceil(this.total / this.size);
  1969. },
  1970. //Return the start range of the paginated results
  1971. startResults() {
  1972. return this.pageNumber * this.size + 1;
  1973. },
  1974. //Return the end range of the paginated results
  1975. endResults() {
  1976. return endRes(this)
  1977. },
  1978. //Link to navigate to page
  1979. viewPage(index) {
  1980. this.pageNumber = index;
  1981. },
  1982. };
  1983. }
  1984. function dns(){
  1985. return {
  1986. data: [
  1987. ],
  1988. open: false,
  1989. title: "",
  1990. message: "",
  1991. success: false,
  1992. openToast(title, message, success) {
  1993. this.title = title
  1994. this.message = message
  1995. this.success = success
  1996. this.open = true
  1997. setTimeout(() => {
  1998. this.open = false
  1999. }, 5000)
  2000. },
  2001. deleteItem(item) {
  2002. fetch('/api/ledger/dns/'.concat("",item), {
  2003. method: 'DELETE',
  2004. });
  2005. this.openToast("Delete", "Announcing deletion to the blockchain, please wait", true);
  2006. },
  2007. updateItems() {
  2008. fetch('/api/dns')
  2009. .then(response => response.json())
  2010. .then(data => {
  2011. data.sort(sortData("Regex","asc"));
  2012. this.data = data;
  2013. } )
  2014. },
  2015. search: "",
  2016. pageNumber: 0,
  2017. size: 10,
  2018. total: "",
  2019. get filtered() {return filter(this, "Regex") },
  2020. //Create array of all pages (for loop to display page numbers)
  2021. pages() {
  2022. return calcPages(this.pageNumber, this.total, this.size)
  2023. },
  2024. //Next Page
  2025. nextPage() {
  2026. this.pageNumber++;
  2027. },
  2028. //Previous Page
  2029. prevPage() {
  2030. this.pageNumber--;
  2031. },
  2032. //Total number of pages
  2033. pageCount() {
  2034. return Math.ceil(this.total / this.size);
  2035. },
  2036. //Return the start range of the paginated results
  2037. startResults() {
  2038. return this.pageNumber * this.size + 1;
  2039. },
  2040. //Return the end range of the paginated results
  2041. endResults() {
  2042. return endRes(this)
  2043. },
  2044. //Link to navigate to page
  2045. viewPage(index) {
  2046. this.pageNumber = index;
  2047. },
  2048. };
  2049. }
  2050. function services(){
  2051. return {
  2052. data: [
  2053. ],
  2054. open: false,
  2055. title: "",
  2056. message: "",
  2057. success: false,
  2058. openToast(title, message, success) {
  2059. this.title = title
  2060. this.message = message
  2061. this.success = success
  2062. this.open = true
  2063. setTimeout(() => {
  2064. this.open = false
  2065. }, 5000)
  2066. },
  2067. updateItems() {
  2068. fetch('/api/services')
  2069. .then(response => response.json())
  2070. .then(data => {
  2071. data.sort(sortData("Name","asc"));
  2072. this.data = data;
  2073. } )
  2074. },
  2075. search: "",
  2076. pageNumber: 0,
  2077. size: 10,
  2078. total: "",
  2079. get filtered() {return filter(this, "Name") },
  2080. //Create array of all pages (for loop to display page numbers)
  2081. pages() {
  2082. return calcPages(this.pageNumber, this.total, this.size)
  2083. },
  2084. //Next Page
  2085. nextPage() {
  2086. this.pageNumber++;
  2087. },
  2088. //Previous Page
  2089. prevPage() {
  2090. this.pageNumber--;
  2091. },
  2092. //Total number of pages
  2093. pageCount() {
  2094. return Math.ceil(this.total / this.size);
  2095. },
  2096. //Return the start range of the paginated results
  2097. startResults() {
  2098. return this.pageNumber * this.size + 1;
  2099. },
  2100. //Return the end range of the paginated results
  2101. endResults() {
  2102. return endRes(this)
  2103. },
  2104. //Link to navigate to page
  2105. viewPage(index) {
  2106. this.pageNumber = index;
  2107. },
  2108. };
  2109. }
  2110. function files(){
  2111. return {
  2112. data: [
  2113. ],
  2114. open: false,
  2115. title: "",
  2116. message: "",
  2117. success: false,
  2118. openToast(title, message, success) {
  2119. this.title = title
  2120. this.message = message
  2121. this.success = success
  2122. this.open = true
  2123. setTimeout(() => {
  2124. this.open = false
  2125. }, 5000)
  2126. },
  2127. updateItems() {
  2128. fetch('/api/files')
  2129. .then(response => response.json())
  2130. .then(data => {
  2131. data.sort(sortData("Name","asc"));
  2132. this.data = data;
  2133. } )
  2134. },
  2135. search: "",
  2136. pageNumber: 0,
  2137. size: 10,
  2138. total: "",
  2139. get filtered() {return filter(this, "Name") },
  2140. //Create array of all pages (for loop to display page numbers)
  2141. pages() {
  2142. return calcPages(this.pageNumber, this.total, this.size)
  2143. },
  2144. //Next Page
  2145. nextPage() {
  2146. this.pageNumber++;
  2147. },
  2148. //Previous Page
  2149. prevPage() {
  2150. this.pageNumber--;
  2151. },
  2152. //Total number of pages
  2153. pageCount() {
  2154. return Math.ceil(this.total / this.size);
  2155. },
  2156. //Return the start range of the paginated results
  2157. startResults() {
  2158. return this.pageNumber * this.size + 1;
  2159. },
  2160. //Return the end range of the paginated results
  2161. endResults() {
  2162. return endRes(this)
  2163. },
  2164. //Link to navigate to page
  2165. viewPage(index) {
  2166. this.pageNumber = index;
  2167. },
  2168. };
  2169. }
  2170. function blockchain(){
  2171. return {
  2172. blockchain: {},
  2173. updateItems() {
  2174. fetch('/api/blockchain')
  2175. .then(response => response.json())
  2176. .then(data => this.blockchain = data )
  2177. }
  2178. };
  2179. }
  2180. function syntaxHighlight(json) {
  2181. json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  2182. return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
  2183. var cls = 'number';
  2184. if (/^"/.test(match)) {
  2185. if (/:$/.test(match)) {
  2186. cls = 'key';
  2187. } else {
  2188. cls = 'string';
  2189. }
  2190. } else if (/true|false/.test(match)) {
  2191. cls = 'boolean';
  2192. } else if (/null/.test(match)) {
  2193. cls = 'null';
  2194. }
  2195. return '<span class="' + cls + '">' + match + '</span>';
  2196. });
  2197. }
  2198. function summary(){
  2199. return {
  2200. summary: {},
  2201. chart: null,
  2202. metrics: {},
  2203. initChart() {
  2204. this.chart = new ApexCharts(this.$refs.chart, {
  2205. chart: {
  2206. type: 'area',
  2207. height: 80,
  2208. sparkline: {
  2209. enabled: true
  2210. },
  2211. dropShadow: {
  2212. enabled: true,
  2213. top: 1,
  2214. left: 1,
  2215. blur: 2,
  2216. opacity: 0.2,
  2217. }
  2218. },
  2219. dataLabels: {
  2220. enabled: false,
  2221. },
  2222. series: [
  2223. {
  2224. name: "Download",
  2225. data: [],
  2226. },
  2227. {
  2228. name: "Upload",
  2229. data: [],
  2230. },
  2231. ],
  2232. stroke: {
  2233. curve: 'smooth'
  2234. },
  2235. markers: {
  2236. size: 0
  2237. },
  2238. grid: {
  2239. padding: {
  2240. top: 20,
  2241. bottom: 10,
  2242. }
  2243. },
  2244. colors: ['#247BA0', '#FF1654' ],
  2245. noData: {
  2246. text: "Loading...",
  2247. },
  2248. xaxis: {
  2249. labels: {
  2250. show: false,
  2251. },
  2252. },
  2253. tooltip: {
  2254. x: {
  2255. show: false
  2256. },
  2257. y: {
  2258. formatter: function(value, { series, seriesIndex, dataPointIndex, w }) {
  2259. return value + ' KB/s'
  2260. }
  2261. }
  2262. }
  2263. })
  2264. this.chart.render()
  2265. },
  2266. updateItems() {
  2267. fetch('/api/summary')
  2268. .then(response => response.json())
  2269. .then(data => this.summary = data )
  2270. fetch('/api/metrics')
  2271. .then(response => response.json())
  2272. .then(data => {
  2273. this.metrics = data;
  2274. this.chart.appendData([{ data: [ scaleSize(data.RateIn) ] }, { data: [ scaleSize(data.RateOut) ] } ]);
  2275. } )
  2276. }
  2277. };
  2278. }
  2279. /*Toggle dropdown list*/
  2280. /*https://gist.github.com/slavapas/593e8e50cf4cc16ac972afcbad4f70c8*/
  2281. var navMenuDiv = document.getElementById("nav-content");
  2282. var navMenu = document.getElementById("nav-toggle");
  2283. document.onclick = check;
  2284. function check(e){
  2285. var target = (e && e.target) || (event && event.srcElement);
  2286. //Nav Menu
  2287. if (!checkParent(target, navMenuDiv)) {
  2288. // click NOT on the menu
  2289. if (checkParent(target, navMenu)) {
  2290. // click on the link
  2291. if (navMenuDiv.classList.contains("hidden")) {
  2292. navMenuDiv.classList.remove("hidden");
  2293. } else {navMenuDiv.classList.add("hidden");}
  2294. } else {
  2295. // click both outside link and outside menu, hide menu
  2296. navMenuDiv.classList.add("hidden");
  2297. }
  2298. }
  2299. }
  2300. function checkParent(t, elm) {
  2301. while(t.parentNode) {
  2302. if( t == elm ) {return true;}
  2303. t = t.parentNode;
  2304. }
  2305. return false;
  2306. }
  2307. </script>
  2308. </body>
  2309. </html>