Current section
43 Versions
Jump to
Current section
43 Versions
Compare versions
12
files changed
+181
additions
-42
deletions
| @@ -1,5 +1,10 @@ | |
| 1 1 | # CHANGELOG |
| 2 2 | |
| 3 | + ## v0.8.5 (2024-11-14) |
| 4 | + |
| 5 | + * Provide a mechanism for user extensible LiveView hooks |
| 6 | + * Add Erlang/OTP 27 Process label support |
| 7 | + |
| 3 8 | ## v0.8.4 (2024-06-21) |
| 4 9 | |
| 5 10 | * Add immutable directive to cache-control header |
| @@ -34,7 +34,7 @@ The dashboard also works across nodes. If your nodes are connected via Distribut | |
| 34 34 | |
| 35 35 | ## Installation |
| 36 36 | |
| 37 | - To start using LiveDashboard, you will need three steps: |
| 37 | + The LiveDashboard is built on top of LiveView. Both LiveView and LiveDashboard ship by default as part of Phoenix. But if you skipped them, you can LiveDashboard in three steps: |
| 38 38 | |
| 39 39 | 1. Add the `phoenix_live_dashboard` dependency |
| 40 40 | 2. Configure LiveView |
| @@ -54,12 +54,7 @@ end | |
| 54 54 | |
| 55 55 | ### 2. Configure LiveView |
| 56 56 | |
| 57 | - The LiveDashboard is built on top of LiveView. If LiveView is already installed in your app, feel free to skip this section. |
| 58 | - |
| 59 | - If you plan to use LiveView in your application in the future, we recommend you to follow [the official installation instructions](https://hexdocs.pm/phoenix_live_view/installation.html). |
| 60 | - This guide only covers the minimum steps necessary for the LiveDashboard itself to run. |
| 61 | - |
| 62 | - First, update your endpoint's configuration to include a signing salt. You can generate a signing salt by running `mix phx.gen.secret 32` (note Phoenix v1.5+ apps already have this configuration): |
| 57 | + First, update your endpoint's configuration to include a signing salt: |
| 63 58 | |
| 64 59 | ```elixir |
| 65 60 | # config/config.exs |
| @@ -98,7 +93,27 @@ This is all. Run `mix phx.server` and access the "/dashboard" to configure the n | |
| 98 93 | |
| 99 94 | ### Extra: Add dashboard access on all environments (including production) |
| 100 95 | |
| 101 | - If you want to use the LiveDashboard in production, you should put it behind some authentication and allow only admins to access it. If your application does not have an admins-only section yet, you can use `Plug.BasicAuth` to set up some basic authentication as long as you are also using SSL (which you should anyway): |
| 96 | + If you want to use the LiveDashboard in production, you should put authentication in front of it. For example, if you use `mix phx.gen.auth` to generate an Admin resource, you could use the following code: |
| 97 | + |
| 98 | + ```elixir |
| 99 | + # lib/my_app_web/router.ex |
| 100 | + use MyAppWeb, :router |
| 101 | + import Phoenix.LiveDashboard.Router |
| 102 | + |
| 103 | + ... |
| 104 | + |
| 105 | + pipeline :admins_only do |
| 106 | + plug :fetch_current_admin |
| 107 | + plug :require_authenticated_admin |
| 108 | + end |
| 109 | + |
| 110 | + scope "/" do |
| 111 | + pipe_through [:browser, :admins_only] |
| 112 | + live_dashboard "/dashboard" |
| 113 | + end |
| 114 | + ``` |
| 115 | + |
| 116 | + If you'd rather have some quick and dirty HTTP Authentication, the following code can be used as a starting point: |
| 102 117 | |
| 103 118 | ```elixir |
| 104 119 | # lib/my_app_web/router.ex |
| @@ -125,28 +140,6 @@ end | |
| 125 140 | |
| 126 141 | If you are running your application behind a proxy or a webserver, you also have to make sure they are configured for allowing WebSocket upgrades. For example, [here is an article](https://web.archive.org/web/20171104012240/https://dennisreimann.de/articles/phoenix-nginx-config.html) on how to configure Nginx with Phoenix and WebSockets. |
| 127 142 | |
| 128 | - Finally, you will also want to configure your `config/prod.exs` and use your domain name under the `check_origin` configuration: |
| 129 | - |
| 130 | - check_origin: ["//myapp.com"] |
| 131 | - |
| 132 | - Then you should be good to go! |
| 133 | - |
| 134 | - ## Using from the command line with PLDS |
| 135 | - |
| 136 | - It's possible to use the LiveDashboard without having to add it as a dependency of your |
| 137 | - application, or when you don't have Phoenix installed. [`PLDS`](https://hexdocs.pm/plds) is a command |
| 138 | - line tool that provides a standalone version of LiveDashboard with some batteries included. |
| 139 | - |
| 140 | - You can install it with: |
| 141 | - |
| 142 | - $ mix escript.install hex plds |
| 143 | - |
| 144 | - And connect to a running node with: |
| 145 | - |
| 146 | - $ plds server --connect mynode --open |
| 147 | - |
| 148 | - For more details, please check the [PLDS documentation](https://hexdocs.pm/plds). |
| 149 | - |
| 150 143 | <!-- MDOC !--> |
| 151 144 | |
| 152 145 | ## Contributing |
unknowndist/css/app.css
File is too large to be displayed (100 KB limit).
| @@ -12,6 +12,6 @@ | |
| 12 12 | {h}:{mm}{aa}`,null,1],[.001,":{ss}.{fff}",` |
| 13 13 | {M}/{D}/{YY} {h}:{mm}{aa}`,null,` |
| 14 14 | {M}/{D} {h}:{mm}{aa}`,null,` |
| 15 | - {h}:{mm}{aa}`,null,1]]}),rr=e=>({show:!0,size:70,space:15,...ou(e)}),ln={width:100,height:300},or={sync:{key:"metrics-live"}};function au(e,t){let n=!1;return()=>{n||(requestAnimationFrame(e),n=!0,setTimeout(()=>{n=!1},t))}}var nn=(e,t=0)=>({...Ol.at(t),...ru(e),label:e.label,spanGaps:!0,points:{show:!1}}),ar=e=>e.slice(0).map(({data:t})=>t);function uu({y:e,z:t},n){this.datasets[0].data.push(t);let s=this.datasets[1].data[this.datasets[1].data.length-1]||0,r=n.call(this,e,s);this.datasets[1].data.push(r)}var ts=e=>e.reduceRight((t,n)=>n!=null&&t==null?n:t,null);function cu({x:e,y:t,z:n},s){let r=this.datasets.findIndex(({key:f})=>e===f);r===-1&&(r=this.datasets.push({key:e,data:Array(this.datasets[0].data.length).fill(null)})-1,this.chart.addSeries(nn({label:e,unit:this.options.unit},r-1),r)),this.datasets=this.datasets.map((f,c)=>(c===0?f.data.push(n):c===r?f.data.push(s.call(this,t,ts(f.data)||0)):f.data.push(null),f))}var ur=({pruneThreshold:e=1e3})=>e,_l=class{static __projections(){return{counter:(t,n)=>n+1,last_value:t=>t,sum:(t,n)=>n+t}}static getConfig(t){return{class:t.kind,title:t.title,width:t.width,height:t.height,cursor:or,series:[{...sr()},nn(t,0)],scales:{x:{min:t.now-60,max:t.now},y:{min:0,max:1}},axes:[ir(),rr(t)]}}static initialData(){return[[],[]]}constructor(t,n){this.__callback=this.constructor.__projections()[n.metric],this.chart=t,this.datasets=[{key:"|x|",data:[]}],this.options=n,this.pruneThreshold=ur(n),n.tagged?(this.chart.delSeries(1),this.__handler=cu):(this.datasets.push({key:n.label,data:[]}),this.__handler=uu)}handleMeasurements(t){t.forEach(s=>this.__handler.call(this,s,this.__callback)),this.datasets[0].data.length>=this.pruneThreshold&&(this.datasets=this.datasets.map(({data:s,...r})=>({data:s.slice(-this.pruneThreshold),...r}))),this.chart.setData(ar(this.datasets))}},yl=class{constructor(t,n){let s=this.constructor.getConfig(t);s.series[1].values=this.__seriesValues.bind(this),this.datasets=[{key:"|x|",data:[]}],this.chart=new Se(s,this.constructor.initialData(t),n),this.pruneThreshold=ur(t),this.options=t,t.tagged?(this.chart.delSeries(1),this.__handler=this.handleTaggedMeasurement.bind(this)):(this.datasets.push(this.constructor.newDataset(t.label)),this.__handler=this.handleMeasurement.bind(this))}handleMeasurements(t){t.forEach(n=>this.__handler(n)),this.__maybePruneDatasets(),this.chart.setData(ar(this.datasets))}handleTaggedMeasurement(t){let n=this.findOrCreateSeries(t.x);this.handleMeasurement(t,n)}handleMeasurement(t,n=1){let{z:s}=t;this.datasets=this.datasets.map((r,f)=>(r.key==="|x|"?r.data.push(s):f===n?this.pushToDataset(r,t):this.pushToDataset(r,null),r))}findOrCreateSeries(t){let n=this.datasets.findIndex(({key:s})=>t===s);if(n===-1){n=this.datasets.push(this.constructor.newDataset(t,this.datasets[0].data.length))-1;let s={values:this.__seriesValues.bind(this),...nn({label:t},n-1)};this.chart.addSeries(s,n)}return n}pushToDataset(t,n){if(n===null){t.data.push(null),t.agg.avg.push(null),t.agg.max.push(null),t.agg.min.push(null);return}let{y:s}=n;return t.agg.count++,t.agg.total+=s,t.data.push(s),(t.last.min===null||s<t.last.min)&&(t.last.min=s),t.agg.min.push(t.last.min),(t.last.max===null||s>t.last.max)&&(t.last.max=s),t.agg.max.push(t.last.max),t.agg.avg.push(t.agg.total/t.agg.count),t}__maybePruneDatasets(){if(this.datasets[0].data.length>this.pruneThreshold){let n=-this.pruneThreshold;this.datasets=this.datasets.map(({key:s,data:r,agg:f})=>{let c=r.slice(n);if(!f)return{key:s,data:c};let{avg:m,count:d,max:g,min:_,total:y}=f,u=_.slice(n),w=g.slice(n);return{key:s,data:c,agg:{avg:m.slice(n),count:d,min:u,max:w,total:y},last:{min:ts(u),max:ts(w)}}})}}__seriesValues(t,n,s){let r=this.datasets[n];if(r&&r.data&&r.data[s]){let{agg:{avg:f,max:c,min:m},data:d}=r;return{Value:d[s].toFixed(3),Min:m[s].toFixed(3),Max:c[s].toFixed(3),Avg:f[s].toFixed(3)}}else return{Value:"--",Min:"--",Max:"--",Avg:"--"}}static initialData(){return[[],[]]}static getConfig(t){return{class:t.kind,title:t.title,width:t.width,height:t.height,cursor:or,series:[{...sr()},nn(t,0)],scales:{x:{min:t.now-60,max:t.now},y:{min:0,max:1}},axes:[ir(),rr(t)]}}static newDataset(t,n=0){let s=n>0?Array(n).fill(null):[];return{key:t,data:[...s],agg:{avg:[...s],count:0,max:[...s],min:[...s],total:0},last:{max:null,min:null}}}},nr={counter:_l,last_value:_l,sum:_l,summary:yl,distribution:tn},ls=class{constructor(t,n){if(n.metric){if(n.metric&&!nr[n.metric])throw new TypeError(`No metric defined for type ${n.metric}`)}else throw new TypeError("No metric type was provided");let s=nr[n.metric];s===yl?(this.metric=new yl(n,t),this.uplotChart=this.metric.chart):(this.uplotChart=new Se(s.getConfig(n),s.initialData(n),t),this.metric=new s(this.uplotChart,n));let r=typeof n.refreshInterval<"u";this._isBufferingData=r,this._buffer=[],this._timer=r?setInterval(this._flushToChart.bind(this),+n.refreshInterval):null}clearTimers(){clearInterval(this._timer)}resize(t){this.uplotChart.setSize({width:Math.max(t.width,ln.width),height:ln.height})}pushData(t){if(!t.length)return;(this._isBufferingData?this._pushToBuffer:this._pushToChart).call(this,t)}_pushToBuffer(t){this._buffer=this._buffer.concat(t)}_pushToChart(t){this.metric.handleMeasurements(t)}_flushToChart(){let t=this._flushBuffer();!t.length||this._pushToChart(t)}_flushBuffer(){if(this._buffer&&!this._buffer.length)return[];let t=this._buffer;return this._buffer=[],t.reduce((n,s)=>n.concat(s),[])}},fu={mounted(){let e=this.el.parentElement.querySelector(".chart"),t=e.getBoundingClientRect(),n=Object.assign({},e.dataset,{tagged:e.dataset.tags&&e.dataset.tags!==""||!1,width:Math.max(t.width,ln.width),height:ln.height,now:new Date/1e3,refreshInterval:1e3});this.chart=new ls(e,n),window.addEventListener("resize",au(()=>{let s=e.getBoundingClientRect();this.chart.resize(s)}))},updated(){let e=Array.from(this.el.children||[]).map(({dataset:{x:t,y:n,z:s}})=>({x:t,y:+n,z:+s/1e6}));e.length>0&&this.chart.pushData(e)},destroyed(){this.chart.clearTimers()}},cr=fu;var hu=e=>{let t=`${e.key}=${e.value};path=/`;window.location.protocol==="https:"&&(t+=";samesite=strict"),e.domain&&(t+=`;domain=${e.domain}`),document.cookie=t},du=e=>{let t="Thu, 01 Jan 1970 00:00:00 GMT";document.cookie=`${e.key}=; expires=${t}`},pu=e=>e.el.hasAttribute("data-cookie-enabled"),mu=e=>({key:e.el.getAttribute("data-cookie-key"),value:e.el.getAttribute("data-cookie-value"),domain:e.el.getAttribute("data-cookie-domain")}),gu={updated(){let e=mu(this);du(e),pu(this)&&hu(e)}},fr=gu;var wu=e=>{if(!navigator.clipboard)e.select(),e.setSelectionRange(0,99999),document.execCommand("copy");else{let t=e.value;navigator.clipboard.writeText(t)}},Su={mounted(){this.el.querySelector(".btn-primary").addEventListener("click",e=>{let t=this.el.querySelector("textarea");wu(t);let n=this.el.querySelector(".copy-indicator");n.setAttribute("data-enabled","false"),n.offsetWidth,n.setAttribute("data-enabled","true")})}},hr=Su;var vu={updated(){if(this.el.querySelector(".logger-autoscroll-checkbox").checked){let e=this.el.querySelector("#logger-messages");e.scrollTop=e.scrollHeight}}},dr=vu;var mr=".progress-bar, .color-bar-legend-entry",sn,pr=e=>{e.querySelectorAll(mr).forEach(t=>{if(sn){let n=t.getAttribute("data-name")!==sn;t.setAttribute("data-muted",n)}else t.removeAttribute("data-muted")})},_u={mounted(){this.el.setAttribute("data-highlight-enabled","true"),this.el.querySelectorAll(mr).forEach(e=>e.addEventListener("click",t=>{let n=t.currentTarget.getAttribute("data-name");sn=n===sn?null:n,pr(this.el)}))},updated(){this.el.setAttribute("data-highlight-enabled","true"),pr(this.el)}},gr=_u;var wr="_refresh_data";function Sr(e,t){let n=JSON.stringify(e),s=xu(n);bu(wr,s,t,15768e4)}function rn(){let e=yu(wr);if(e){let t=ku(e);return JSON.parse(t)}else return null}function yu(e){let t=document.cookie.split("; ").find(n=>n.startsWith(`${e}=`));return t?t.replace(`${e}=`,""):null}function bu(e,t,n,s){let r=`${e}=${t};max-age=${s};path=${n}`;document.cookie=r}function xu(e){return btoa(unescape(encodeURIComponent(e)))}function ku(e){return decodeURIComponent(escape(atob(e)))}var Mu={updated(){let e=rn()||{};e[this.el.dataset.page]=this.el.value,Sr(e,this.el.dataset.dashboardMountPath)}},vr=Mu;var Tu={PhxChartComponent:cr,PhxRequestLoggerCookie:fr,PhxRequestLoggerQueryParameter:hr,PhxRequestLoggerMessages:dr,PhxColorBarHighlight:gr,PhxRememberRefresh:vr},Du=document.querySelector("html").getAttribute("phx-socket")||"/live",Cu=document.querySelector("meta[name='csrf-token']").getAttribute("content"),is=new LiveView.LiveSocket(Du,Phoenix.Socket,{hooks:Tu,params:e=>({_csrf_token:Cu,refresh_data:rn()})}),zt=is.socket,Eu=zt.onConnError,ns=!0;zt.onOpen(()=>{ns=!1});zt.onConnError=(...e)=>{ns?(ns=!1,zt.disconnect(null,3e3),zt.transport=Phoenix.LongPoll,zt.connect()):Eu.apply(zt,e)};window.addEventListener("phx:page-loading-start",e=>ss.default.start());window.addEventListener("phx:page-loading-stop",e=>ss.default.done());is.connect();window.liveSocket=is;})(); |
| 15 | + {h}:{mm}{aa}`,null,1]]}),rr=e=>({show:!0,size:70,space:15,...ou(e)}),ln={width:100,height:300},or={sync:{key:"metrics-live"}};function au(e,t){let n=!1;return()=>{n||(requestAnimationFrame(e),n=!0,setTimeout(()=>{n=!1},t))}}var nn=(e,t=0)=>({...Ol.at(t),...ru(e),label:e.label,spanGaps:!0,points:{show:!1}}),ar=e=>e.slice(0).map(({data:t})=>t);function uu({y:e,z:t},n){this.datasets[0].data.push(t);let s=this.datasets[1].data[this.datasets[1].data.length-1]||0,r=n.call(this,e,s);this.datasets[1].data.push(r)}var ts=e=>e.reduceRight((t,n)=>n!=null&&t==null?n:t,null);function cu({x:e,y:t,z:n},s){let r=this.datasets.findIndex(({key:f})=>e===f);r===-1&&(r=this.datasets.push({key:e,data:Array(this.datasets[0].data.length).fill(null)})-1,this.chart.addSeries(nn({label:e,unit:this.options.unit},r-1),r)),this.datasets=this.datasets.map((f,c)=>(c===0?f.data.push(n):c===r?f.data.push(s.call(this,t,ts(f.data)||0)):f.data.push(null),f))}var ur=({pruneThreshold:e=1e3})=>e,_l=class{static __projections(){return{counter:(t,n)=>n+1,last_value:t=>t,sum:(t,n)=>n+t}}static getConfig(t){return{class:t.kind,title:t.title,width:t.width,height:t.height,cursor:or,series:[{...sr()},nn(t,0)],scales:{x:{min:t.now-60,max:t.now},y:{min:0,max:1}},axes:[ir(),rr(t)]}}static initialData(){return[[],[]]}constructor(t,n){this.__callback=this.constructor.__projections()[n.metric],this.chart=t,this.datasets=[{key:"|x|",data:[]}],this.options=n,this.pruneThreshold=ur(n),n.tagged?(this.chart.delSeries(1),this.__handler=cu):(this.datasets.push({key:n.label,data:[]}),this.__handler=uu)}handleMeasurements(t){t.forEach(s=>this.__handler.call(this,s,this.__callback)),this.datasets[0].data.length>=this.pruneThreshold&&(this.datasets=this.datasets.map(({data:s,...r})=>({data:s.slice(-this.pruneThreshold),...r}))),this.chart.setData(ar(this.datasets))}},yl=class{constructor(t,n){let s=this.constructor.getConfig(t);s.series[1].values=this.__seriesValues.bind(this),this.datasets=[{key:"|x|",data:[]}],this.chart=new Se(s,this.constructor.initialData(t),n),this.pruneThreshold=ur(t),this.options=t,t.tagged?(this.chart.delSeries(1),this.__handler=this.handleTaggedMeasurement.bind(this)):(this.datasets.push(this.constructor.newDataset(t.label)),this.__handler=this.handleMeasurement.bind(this))}handleMeasurements(t){t.forEach(n=>this.__handler(n)),this.__maybePruneDatasets(),this.chart.setData(ar(this.datasets))}handleTaggedMeasurement(t){let n=this.findOrCreateSeries(t.x);this.handleMeasurement(t,n)}handleMeasurement(t,n=1){let{z:s}=t;this.datasets=this.datasets.map((r,f)=>(r.key==="|x|"?r.data.push(s):f===n?this.pushToDataset(r,t):this.pushToDataset(r,null),r))}findOrCreateSeries(t){let n=this.datasets.findIndex(({key:s})=>t===s);if(n===-1){n=this.datasets.push(this.constructor.newDataset(t,this.datasets[0].data.length))-1;let s={values:this.__seriesValues.bind(this),...nn({label:t},n-1)};this.chart.addSeries(s,n)}return n}pushToDataset(t,n){if(n===null){t.data.push(null),t.agg.avg.push(null),t.agg.max.push(null),t.agg.min.push(null);return}let{y:s}=n;return t.agg.count++,t.agg.total+=s,t.data.push(s),(t.last.min===null||s<t.last.min)&&(t.last.min=s),t.agg.min.push(t.last.min),(t.last.max===null||s>t.last.max)&&(t.last.max=s),t.agg.max.push(t.last.max),t.agg.avg.push(t.agg.total/t.agg.count),t}__maybePruneDatasets(){if(this.datasets[0].data.length>this.pruneThreshold){let n=-this.pruneThreshold;this.datasets=this.datasets.map(({key:s,data:r,agg:f})=>{let c=r.slice(n);if(!f)return{key:s,data:c};let{avg:m,count:d,max:g,min:_,total:y}=f,u=_.slice(n),w=g.slice(n);return{key:s,data:c,agg:{avg:m.slice(n),count:d,min:u,max:w,total:y},last:{min:ts(u),max:ts(w)}}})}}__seriesValues(t,n,s){let r=this.datasets[n];if(r&&r.data&&r.data[s]){let{agg:{avg:f,max:c,min:m},data:d}=r;return{Value:d[s].toFixed(3),Min:m[s].toFixed(3),Max:c[s].toFixed(3),Avg:f[s].toFixed(3)}}else return{Value:"--",Min:"--",Max:"--",Avg:"--"}}static initialData(){return[[],[]]}static getConfig(t){return{class:t.kind,title:t.title,width:t.width,height:t.height,cursor:or,series:[{...sr()},nn(t,0)],scales:{x:{min:t.now-60,max:t.now},y:{min:0,max:1}},axes:[ir(),rr(t)]}}static newDataset(t,n=0){let s=n>0?Array(n).fill(null):[];return{key:t,data:[...s],agg:{avg:[...s],count:0,max:[...s],min:[...s],total:0},last:{max:null,min:null}}}},nr={counter:_l,last_value:_l,sum:_l,summary:yl,distribution:tn},ls=class{constructor(t,n){if(n.metric){if(n.metric&&!nr[n.metric])throw new TypeError(`No metric defined for type ${n.metric}`)}else throw new TypeError("No metric type was provided");let s=nr[n.metric];s===yl?(this.metric=new yl(n,t),this.uplotChart=this.metric.chart):(this.uplotChart=new Se(s.getConfig(n),s.initialData(n),t),this.metric=new s(this.uplotChart,n));let r=typeof n.refreshInterval<"u";this._isBufferingData=r,this._buffer=[],this._timer=r?setInterval(this._flushToChart.bind(this),+n.refreshInterval):null}clearTimers(){clearInterval(this._timer)}resize(t){this.uplotChart.setSize({width:Math.max(t.width,ln.width),height:ln.height})}pushData(t){if(!t.length)return;(this._isBufferingData?this._pushToBuffer:this._pushToChart).call(this,t)}_pushToBuffer(t){this._buffer=this._buffer.concat(t)}_pushToChart(t){this.metric.handleMeasurements(t)}_flushToChart(){let t=this._flushBuffer();!t.length||this._pushToChart(t)}_flushBuffer(){if(this._buffer&&!this._buffer.length)return[];let t=this._buffer;return this._buffer=[],t.reduce((n,s)=>n.concat(s),[])}},fu={mounted(){let e=this.el.parentElement.querySelector(".chart"),t=e.getBoundingClientRect(),n=Object.assign({},e.dataset,{tagged:e.dataset.tags&&e.dataset.tags!==""||!1,width:Math.max(t.width,ln.width),height:ln.height,now:new Date/1e3,refreshInterval:1e3});this.chart=new ls(e,n),window.addEventListener("resize",au(()=>{let s=e.getBoundingClientRect();this.chart.resize(s)}))},updated(){let e=Array.from(this.el.children||[]).map(({dataset:{x:t,y:n,z:s}})=>({x:t,y:+n,z:+s/1e6}));e.length>0&&this.chart.pushData(e)},destroyed(){this.chart.clearTimers()}},cr=fu;var hu=e=>{let t=`${e.key}=${e.value};path=/`;window.location.protocol==="https:"&&(t+=";samesite=strict"),e.domain&&(t+=`;domain=${e.domain}`),document.cookie=t},du=e=>{let t="Thu, 01 Jan 1970 00:00:00 GMT";document.cookie=`${e.key}=; expires=${t}`},pu=e=>e.el.hasAttribute("data-cookie-enabled"),mu=e=>({key:e.el.getAttribute("data-cookie-key"),value:e.el.getAttribute("data-cookie-value"),domain:e.el.getAttribute("data-cookie-domain")}),gu={updated(){let e=mu(this);du(e),pu(this)&&hu(e)}},fr=gu;var wu=e=>{if(!navigator.clipboard)e.select(),e.setSelectionRange(0,99999),document.execCommand("copy");else{let t=e.value;navigator.clipboard.writeText(t)}},Su={mounted(){this.el.querySelector(".btn-primary").addEventListener("click",e=>{let t=this.el.querySelector("textarea");wu(t);let n=this.el.querySelector(".copy-indicator");n.setAttribute("data-enabled","false"),n.offsetWidth,n.setAttribute("data-enabled","true")})}},hr=Su;var vu={updated(){if(this.el.querySelector(".logger-autoscroll-checkbox").checked){let e=this.el.querySelector("#logger-messages");e.scrollTop=e.scrollHeight}}},dr=vu;var mr=".progress-bar, .color-bar-legend-entry",sn,pr=e=>{e.querySelectorAll(mr).forEach(t=>{if(sn){let n=t.getAttribute("data-name")!==sn;t.setAttribute("data-muted",n)}else t.removeAttribute("data-muted")})},_u={mounted(){this.el.setAttribute("data-highlight-enabled","true"),this.el.querySelectorAll(mr).forEach(e=>e.addEventListener("click",t=>{let n=t.currentTarget.getAttribute("data-name");sn=n===sn?null:n,pr(this.el)}))},updated(){this.el.setAttribute("data-highlight-enabled","true"),pr(this.el)}},gr=_u;var wr="_refresh_data";function Sr(e,t){let n=JSON.stringify(e),s=xu(n);bu(wr,s,t,15768e4)}function rn(){let e=yu(wr);if(e){let t=ku(e);return JSON.parse(t)}else return null}function yu(e){let t=document.cookie.split("; ").find(n=>n.startsWith(`${e}=`));return t?t.replace(`${e}=`,""):null}function bu(e,t,n,s){let r=`${e}=${t};max-age=${s};path=${n}`;document.cookie=r}function xu(e){return btoa(unescape(encodeURIComponent(e)))}function ku(e){return decodeURIComponent(escape(atob(e)))}var Mu={updated(){let e=rn()||{};e[this.el.dataset.page]=this.el.value,Sr(e,this.el.dataset.dashboardMountPath)}},vr=Mu;var Tu={PhxChartComponent:cr,PhxRequestLoggerCookie:fr,PhxRequestLoggerQueryParameter:hr,PhxRequestLoggerMessages:dr,PhxColorBarHighlight:gr,PhxRememberRefresh:vr},Du=document.querySelector("html").getAttribute("phx-socket")||"/live",Cu=document.querySelector("meta[name='csrf-token']").getAttribute("content"),is=new LiveView.LiveSocket(Du,Phoenix.Socket,{hooks:{...Tu,...window.LiveDashboard.customHooks},params:e=>({_csrf_token:Cu,refresh_data:rn()})}),zt=is.socket,Eu=zt.onConnError,ns=!0;zt.onOpen(()=>{ns=!1});zt.onConnError=(...e)=>{ns?(ns=!1,zt.disconnect(null,3e3),zt.transport=Phoenix.LongPoll,zt.connect()):Eu.apply(zt,e)};window.addEventListener("phx:page-loading-start",e=>ss.default.start());window.addEventListener("phx:page-loading-stop",e=>ss.default.done());is.connect();window.liveSocket=is;})(); |
| 16 16 | /* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress |
| 17 17 | * @license MIT */ |
unknowndist/js/app.js.map
File is too large to be displayed (100 KB limit).
Loading more files…