diff --git a/Makefile b/Makefile index 1ed64e35..c9562eb7 100644 --- a/Makefile +++ b/Makefile @@ -310,6 +310,9 @@ run-client: ## Start Glances in client mode (RPC) run-browser: ## Start Glances in browser mode (RPC) $(PYTHON) -m glances -C $(CONF) --browser +run-web-browser: ## Start Web Central Browser + $(PYTHON) -m glances -C $(CONF) -w --browser + run-issue: ## Start Glances in issue mode $(PYTHON) -m glances -C $(CONF) --issue diff --git a/glances/outputs/glances_restful_api.py b/glances/outputs/glances_restful_api.py index 654f601b..2b349b69 100644 --- a/glances/outputs/glances_restful_api.py +++ b/glances/outputs/glances_restful_api.py @@ -231,6 +231,7 @@ class GlancesRestfulApi: f'{plugin_path}/limits': self._api_limits, f'{plugin_path}/views': self._api_views, f'{plugin_path}/{{item}}': self._api_item, + f'{plugin_path}/{{item}}/views': self._api_item_views, f'{plugin_path}/{{item}}/history': self._api_item_history, f'{plugin_path}/{{item}}/history/{{nb}}': self._api_item_history, f'{plugin_path}/{{item}}/description': self._api_item_description, @@ -610,6 +611,30 @@ class GlancesRestfulApi: return GlancesJSONResponse(ret) + def _api_item_views(self, plugin: str, item: str): + """Glances API RESTful implementation. + + Return the JSON view representation of the couple plugin/item + HTTP/200 if OK + HTTP/400 if plugin is not found + HTTP/404 if others error + """ + self._check_if_plugin_available(plugin) + + # Update the stat + self.__update_stats() + + try: + # Get the RAW value of the stat views + ret = self.stats.get_plugin(plugin).get_views().get(item) + except Exception as e: + raise HTTPException( + status.HTTP_404_NOT_FOUND, + f"Cannot get item {item} in plugin view {plugin} ({str(e)})", + ) + + return GlancesJSONResponse(ret) + def _api_item_history(self, plugin: str, item: str, nb: int = 0): """Glances API RESTful implementation. diff --git a/glances/outputs/static/css/custom.scss b/glances/outputs/static/css/custom.scss index ff05c9d7..a4439a48 100644 --- a/glances/outputs/static/css/custom.scss +++ b/glances/outputs/static/css/custom.scss @@ -18,7 +18,7 @@ @import "../node_modules/bootstrap/scss/functions"; // // 2. Include any default variable overrides here -// $bg-color: black; +// $body-bg: black; // // 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets) @import "../node_modules/bootstrap/scss/variables"; diff --git a/glances/outputs/static/css/style.scss b/glances/outputs/static/css/style.scss index 53429f66..178a726e 100644 --- a/glances/outputs/static/css/style.scss +++ b/glances/outputs/static/css/style.scss @@ -12,16 +12,14 @@ $glances-fonts-size: 14px; :root { --bs-body-bg: $glances-bg; --bs-body-color: $glances-fg; - --bs-link-hover-color: $glances-link-hover-color; --bs-body-font-size: $glances-fonts-size; } -#app { - font-family: $glances-fonts; -} - -#browser { +body { + background-color: $glances-bg; + color: $glances-fg; font-family: $glances-fonts; + font-size: $glances-fonts-size; } .title { @@ -73,6 +71,11 @@ $glances-fonts-size: 14px; color: #EE6600 !important; font-weight: bold !important; } +.error_log { + background-color: #EE6600 !important; + color: white !important; + font-weight: bold !important; +} // Table @@ -112,6 +115,10 @@ $glances-fonts-size: 14px; white-space: nowrap; } +.table-hover tbody tr:hover td { + background: $glances-link-hover-color; +} + // Separator .separator { diff --git a/glances/outputs/static/js/Browser.vue b/glances/outputs/static/js/Browser.vue index b77fd237..e636adc7 100644 --- a/glances/outputs/static/js/Browser.vue +++ b/glances/outputs/static/js/Browser.vue @@ -33,7 +33,8 @@
u?F(t,i,o,!0,!1,p):_(e,r,n,i,o,a,s,l,p)},P=(t,e,r,n,i,o,a,s,l)=>{let c=0;const u=e.length;let p=t.length-1,d=u-1;for(;c<=p&&c<=d;){const n=t[c],u=e[c]=l?Mu(e[c]):Du(e[c]);if(!Eu(n,u))break;f(n,u,r,null,i,o,a,s,l),c++}for(;c<=p&&c<=d;){const n=t[p],c=e[d]=l?Mu(e[d]):Du(e[d]);if(!Eu(n,c))break;f(n,c,r,null,i,o,a,s,l),p--,d--}if(c>p){if(c<=d){const t=d+1,p=td)for(;c<=p;)M(t[c],i,o,!0),c++;else{const m=c,h=c,g=new Map;for(c=h;c<=d;c++){const t=e[c]=l?Mu(e[c]):Du(e[c]);null!=t.key&&g.set(t.key,c)}let b,v=0;const y=d-h+1;let x=!1,w=0;const _=new Array(y);for(c=0;c {{ servers }} u?F(t,i,o,!0,!1,p):_(e,r,n,i,o,a,s,l,p)},P=(t,e,r,n,i,o,a,s,l)=>{let c=0;const u=e.length;let p=t.length-1,d=u-1;for(;c<=p&&c<=d;){const n=t[c],u=e[c]=l?Mu(e[c]):Du(e[c]);if(!Eu(n,u))break;f(n,u,r,null,i,o,a,s,l),c++}for(;c<=p&&c<=d;){const n=t[p],c=e[d]=l?Mu(e[d]):Du(e[d]);if(!Eu(n,c))break;f(n,c,r,null,i,o,a,s,l),p--,d--}if(c>p){if(c<=d){const t=d+1,p=td)for(;c<=p;)M(t[c],i,o,!0),c++;else{const m=c,h=c,g=new Map;for(c=h;c<=d;c++){const t=e[c]=l?Mu(e[c]):Du(e[c]);null!=t.key&&g.set(t.key,c)}let b,v=0;const y=d-h+1;let x=!1,w=0;const _=new Array(y);for(c=0;c {{ servers }}
");return md()(r)}function wd(t,e){return new Intl.NumberFormat(void 0,"number"==typeof e?{maximumFractionDigits:e}:e).format(t)}function _d(t){for(var e=0,r=0;r
");return md()(r)}function wd(t,e){return new Intl.NumberFormat(void 0,"number"==typeof e?{maximumFractionDigits:e}:e).format(t)}function _d(t){for(var e=0,r=0;r=a?l:l*("desc"==r[n]?-1:1)}return t.index-e.index}(t,e,r)}))}function Gn(t,e,r){for(var n=-1,i=e.length,o={};++n-1;)a!==t&&Qt.call(a,l,1),Qt.call(t,l,1);return t}function Kn(t,e){for(var r=t?e.length:0,n=r-1;r--;){var i=e[r];if(r==n||i!==o){var o=i;xo(i)?Qt.call(t,i,1):di(t,i)}}return t}function Xn(t,e){return t+ge(_r()*(e-t+1))}function Qn(t,e){var r="";if(!t||e<1||e>f)return r;do{e%2&&(r+=t),(e=ge(e/2))&&(t+=t)}while(e);return r}function Zn(t,e){return Po(To(t,e,il),t+"")}function Yn(t){return Zr(Fa(t))}function Jn(t,e){var r=Fa(t);return Mo(r,ln(e,0,r.length))}function ti(t,e,r,n){if(!ea(t))return t;for(var o=-1,s=(e=xi(e,t)).length,a=s-1,l=t;null!=l&&++oo?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var s=n(o);++i=a?l:l*("desc"==r[n]?-1:1)}return t.index-e.index}(t,e,r)}))}function Gn(t,e,r){for(var n=-1,i=e.length,o={};++n-1;)a!==t&&Qt.call(a,l,1),Qt.call(t,l,1);return t}function Kn(t,e){for(var r=t?e.length:0,n=r-1;r--;){var i=e[r];if(r==n||i!==o){var o=i;xo(i)?Qt.call(t,i,1):di(t,i)}}return t}function Xn(t,e){return t+ge(_r()*(e-t+1))}function Qn(t,e){var r="";if(!t||e<1||e>f)return r;do{e%2&&(r+=t),(e=ge(e/2))&&(t+=t)}while(e);return r}function Zn(t,e){return Po(To(t,e,il),t+"")}function Yn(t){return Zr(Fa(t))}function Jn(t,e){var r=Fa(t);return Mo(r,ln(e,0,r.length))}function ti(t,e,r,n){if(!ea(t))return t;for(var o=-1,s=(e=xi(e,t)).length,a=s-1,l=t;null!=l&&++oo?0:o+e),(r=r>o?o:r)<0&&(r+=o),o=e>r?0:r-e>>>0,e>>>=0;for(var s=n(o);++it?tp(t)?lp(t)||t.proxy:Cc(t.parent):null,Tc=$o(Object.create(null),{$:t=>t,$el:t=>t.vnode.el,$data:t=>t.data,$props:t=>t.props,$attrs:t=>t.attrs,$slots:t=>t.slots,$refs:t=>t.refs,$parent:t=>Cc(t.parent),$root:t=>Cc(t.root),$emit:t=>t.emit,$options:t=>Mc(t),$forceUpdate:t=>t.f||(t.f=()=>fl(t.update)),$nextTick:t=>t.n||(t.n=ml.bind(t.proxy)),$watch:t=>Bl.bind(t)}),Oc=(t,e)=>t!==Po&&!t.__isScriptSetup&&zo(t,e),Ic={get({_:t},e){const{ctx:r,setupState:n,data:i,props:o,accessCache:s,type:a,appContext:l}=t;let c;if("$"!==e[0]){const a=s[e];if(void 0!==a)switch(a){case 1:return n[e];case 2:return i[e];case 4:return r[e];case 3:return o[e]}else{if(Oc(n,e))return s[e]=1,n[e];if(i!==Po&&zo(i,e))return s[e]=2,i[e];if((c=t.propsOptions[0])&&zo(c,e))return s[e]=3,o[e];if(r!==Po&&zo(r,e))return s[e]=4,r[e];Lc&&(s[e]=0)}}const u=Tc[e];let p,d;return u?("$attrs"===e&&Ks(t,0,e),u(t)):(p=a.__cssModules)&&(p=p[e])?p:r!==Po&&zo(r,e)?(s[e]=4,r[e]):(d=l.config.globalProperties,zo(d,e)?d[e]:void 0)},set({_:t},e,r){const{data:n,setupState:i,ctx:o}=t;return Oc(i,e)?(i[e]=r,!0):n!==Po&&zo(n,e)?(n[e]=r,!0):!zo(t.props,e)&&(("$"!==e[0]||!(e.slice(1)in t))&&(o[e]=r,!0))},has({_:{data:t,setupState:e,accessCache:r,ctx:n,appContext:i,propsOptions:o}},s){let a;return!!r[s]||t!==Po&&zo(t,s)||Oc(e,s)||(a=o[0])&&zo(a,s)||zo(n,s)||zo(Tc,s)||zo(i.config.globalProperties,s)},defineProperty(t,e,r){return null!=r.get?t._.accessCache[e]=0:zo(r,"value")&&this.set(t,e,r.value,null),Reflect.defineProperty(t,e,r)}};function jc(t){return Ho(t)?t.reduce(((t,e)=>(t[e]=null,t)),{}):t}let Lc=!0;function Pc(t){const e=Mc(t),r=t.proxy,n=t.ctx;Lc=!1,e.beforeCreate&&Nc(e.beforeCreate,t,"bc");const{data:i,computed:o,methods:s,watch:a,provide:l,inject:c,created:u,beforeMount:p,mounted:d,beforeUpdate:m,updated:f,activated:h,deactivated:g,beforeDestroy:b,beforeUnmount:y,destroyed:v,unmounted:x,render:w,renderTracked:_,renderTriggered:k,errorCaptured:A,serverPrefetch:S,expose:E,inheritAttrs:C,components:T,directives:O,filters:I}=e;if(c&&function(t,e){Ho(t)&&(t=$c(t));for(const r in t){const n=t[r];let i;i=Qo(n)?"default"in n?Kc(n.from||r,n.default,!0):Kc(n.from||r):Kc(n),Qa(i)?Object.defineProperty(e,r,{enumerable:!0,configurable:!0,get:()=>i.value,set:t=>i.value=t}):e[r]=i}}(c,n,null),s)for(const t in s){const e=s[t];Wo(e)&&(n[t]=e.bind(r))}if(i){0;const e=i.call(r,r);0,Qo(e)&&(t.data=Ra(e))}if(Lc=!0,o)for(const t in o){const e=o[t],i=Wo(e)?e.bind(r,r):Wo(e.get)?e.get.bind(r,r):Do;0;const s=!Wo(e)&&Wo(e.set)?e.set.bind(r):Do,a=pp({get:i,set:s});Object.defineProperty(n,t,{enumerable:!0,configurable:!0,get:()=>a.value,set:t=>a.value=t})}if(a)for(const t in a)Dc(a[t],n,r,t);if(l){const t=Wo(l)?l.call(r):l;Reflect.ownKeys(t).forEach((e=>{!function(t,e){if(Wu){let r=Wu.provides;const n=Wu.parent&&Wu.parent.provides;n===r&&(r=Wu.provides=Object.create(n)),r[t]=e}else 0}(e,t[e])}))}function j(t,e){Ho(e)?e.forEach((e=>t(e.bind(r)))):e&&t(e.bind(r))}if(u&&Nc(u,t,"c"),j(pc,p),j(dc,d),j(mc,m),j(fc,f),j(nc,h),j(ic,g),j(xc,A),j(vc,_),j(yc,k),j(hc,y),j(gc,x),j(bc,S),Ho(E))if(E.length){const e=t.exposed||(t.exposed={});E.forEach((t=>{Object.defineProperty(e,t,{get:()=>r[t],set:e=>r[t]=e})}))}else t.exposed||(t.exposed={});w&&t.render===Do&&(t.render=w),null!=C&&(t.inheritAttrs=C),T&&(t.components=T),O&&(t.directives=O)}function Nc(t,e,r){rl(Ho(t)?t.map((t=>t.bind(e.proxy))):t.bind(e.proxy),e,r)}function Dc(t,e,r,n){const i=n.includes(".")?$l(r,n):()=>r[n];if(Ko(t)){const r=e[t];Wo(r)&&Rl(i,r)}else if(Wo(t))Rl(i,t.bind(r));else if(Qo(t))if(Ho(t))t.forEach((t=>Dc(t,e,r,n)));else{const n=Wo(t.handler)?t.handler.bind(r):e[t.handler];Wo(n)&&Rl(i,n,t)}else 0}function Mc(t){const e=t.type,{mixins:r,extends:n}=e,{mixins:i,optionsCache:o,config:{optionMergeStrategies:s}}=t.appContext,a=o.get(e);let l;return a?l=a:i.length||r||n?(l={},i.length&&i.forEach((t=>Rc(l,t,s,!0))),Rc(l,e,s)):l=e,Qo(e)&&o.set(e,l),l}function Rc(t,e,r,n=!1){const{mixins:i,extends:o}=e;o&&Rc(t,o,r,!0),i&&i.forEach((e=>Rc(t,e,r,!0)));for(const i in e)if(n&&"expose"===i);else{const n=qc[i]||r&&r[i];t[i]=n?n(t[i],e[i]):e[i]}return t}const qc={data:Bc,props:zc,emits:zc,methods:Uc,computed:Uc,beforeCreate:Fc,created:Fc,beforeMount:Fc,mounted:Fc,beforeUpdate:Fc,updated:Fc,beforeDestroy:Fc,beforeUnmount:Fc,destroyed:Fc,unmounted:Fc,activated:Fc,deactivated:Fc,errorCaptured:Fc,serverPrefetch:Fc,components:Uc,directives:Uc,watch:function(t,e){if(!t)return e;if(!e)return t;const r=$o(Object.create(null),t);for(const n in e)r[n]=Fc(t[n],e[n]);return r},provide:Bc,inject:function(t,e){return Uc($c(t),$c(e))}};function Bc(t,e){return e?t?function(){return $o(Wo(t)?t.call(this,this):t,Wo(e)?e.call(this,this):e)}:e:t}function $c(t){if(Ho(t)){const e={};for(let r=0;r