From 1d6ada1201ca6fe37a82926e7463ef4629fad1f4 Mon Sep 17 00:00:00 2001 From: Dominik Dzienia Date: Thu, 23 Jan 2020 09:50:21 +0100 Subject: [PATCH] Database size plugin - pill that displays current mongoDB database size --- README.md | 18 ++ assets/fonts/Nightscout Plugin Icons.json | 87 ++++++ assets/fonts/README.md | 28 ++ assets/fonts/pluginicons-v1.0/Read Me.txt | 7 + .../pluginicons-v1.0/demo-files/demo.css | 152 +++++++++++ .../fonts/pluginicons-v1.0/demo-files/demo.js | 30 ++ assets/fonts/pluginicons-v1.0/demo.html | 52 ++++ .../pluginicons-v1.0/fonts/pluginicons.eot | Bin 0 -> 1512 bytes .../pluginicons-v1.0/fonts/pluginicons.svg | 11 + .../pluginicons-v1.0/fonts/pluginicons.ttf | Bin 0 -> 1332 bytes .../pluginicons-v1.0/fonts/pluginicons.woff | Bin 0 -> 1408 bytes assets/fonts/pluginicons-v1.0/selection.json | 1 + assets/fonts/pluginicons-v1.0/style.css | 30 ++ lib/client/receiveddata.js | 3 + lib/data/dataloader.js | 18 ++ lib/data/ddata.js | 2 + lib/language.js | 28 +- lib/plugins/dbsize.js | 160 +++++++++++ lib/plugins/index.js | 1 + static/css/main.css | 23 +- tests/dbsize.test.js | 257 ++++++++++++++++++ 21 files changed, 906 insertions(+), 2 deletions(-) create mode 100644 assets/fonts/Nightscout Plugin Icons.json create mode 100644 assets/fonts/README.md create mode 100644 assets/fonts/pluginicons-v1.0/Read Me.txt create mode 100644 assets/fonts/pluginicons-v1.0/demo-files/demo.css create mode 100644 assets/fonts/pluginicons-v1.0/demo-files/demo.js create mode 100644 assets/fonts/pluginicons-v1.0/demo.html create mode 100644 assets/fonts/pluginicons-v1.0/fonts/pluginicons.eot create mode 100644 assets/fonts/pluginicons-v1.0/fonts/pluginicons.svg create mode 100644 assets/fonts/pluginicons-v1.0/fonts/pluginicons.ttf create mode 100644 assets/fonts/pluginicons-v1.0/fonts/pluginicons.woff create mode 100644 assets/fonts/pluginicons-v1.0/selection.json create mode 100644 assets/fonts/pluginicons-v1.0/style.css create mode 100644 lib/plugins/dbsize.js create mode 100644 tests/dbsize.test.js diff --git a/README.md b/README.md index 8586e0b5a3b..f59e6f7facc 100644 --- a/README.md +++ b/README.md @@ -524,6 +524,24 @@ For remote overrides, the following extended settings must be configured: Enabled [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) so other websites can make request to your Nightscout site, uses these extended settings: * `CORS_ALLOW_ORIGIN` (`*`) - The list of sites that are allow to make requests +##### `dbsize` (Database Size) + Show size of Nightscout Database, as a percentage of declared available space or in MiB. + + Many deployments of Nightscout use free tier of MongoDB on Heroku, which is limited in size. After some time, as volume of stored data grows, it may happen that this limit is reached and system is unable to store new data. This plugin provides pill that indicates size of Database and shows (when configured) alarms regarding reaching space limit. + + **IMPORTANT:** This plugin can only check how much space database already takes, _but cannot infer_ max size available on server for it. To have correct alarms and realistic percentage, `DBSIZE_MAX` need to be properly set - according to your mongoDB hosting configuration. + + **NOTE:** It may happen that new data cannot be saved to database (due to size limits) even when this plugin reports that storage is not 100% full. MongoDB pre-allocate data in advance, and database file is always made bigger than total real data size. To avoid premature alarms, this plugin refers to data size instead of file size, but sets warning thresholds low. It may happen, that file size of database will take 100% of allowed space but there will be plenty of place inside to store the data. But it may also happen, with file size is at its max, that data size will be ~70% of file size, and there will be no place left. That may happen because data inside file is fragmented and free space _holes_ are too small for new entries. In such case calling `db.repairDatabase()` on mongoDB is recommended to compact and repack data (currently only doable with third-party mongoDB tools, but action is planned to be added in _Admin Tools_ section in future releases). + + All sizes are expressed as integers, in _Mebibytes_ `1 MiB == 1024 KiB == 1024*1024 B` + + * `ENABLE` - `dbsize` should be added to the list of plugins, for example: `ENABLE="dbsize"`. + * `DBSIZE_MAX` (`496`) - Maximal allowed size of database on your mongoDB server, default value is for standard Heroku mongoDB free tier + * `DBSIZE_WARN` (`300`) - Size threshold to show first warning about size, when database reach this size - pill will show size in yellow. Recommended ~60% of `DBSIZE_MAX` + * `DBSIZE_URGENT` (`370`) - When database reach this size, it is urgent to do backup and clean up old data, pill turns red. Recommended ~75% of `DBSIZE_MAX` + * `DBSIZE_ENABLE_ALERTS` (`false`) - Set to `true` to enable notifications about database size. + * `DBSIZE_IN_MIB` (`false`) - Set to `true` to display size of database in MiB-s instead of default percentage. + #### Extended Settings Some plugins support additional configuration using extra environment variables. These are prefixed with the name of the plugin and a `_`. For example setting `MYPLUGIN_EXAMPLE_VALUE=1234` would make `extendedSettings.exampleValue` available to the `MYPLUGIN` plugin. diff --git a/assets/fonts/Nightscout Plugin Icons.json b/assets/fonts/Nightscout Plugin Icons.json new file mode 100644 index 00000000000..65874c15679 --- /dev/null +++ b/assets/fonts/Nightscout Plugin Icons.json @@ -0,0 +1,87 @@ +{ + "metadata": { + "name": "Nightscout Plugin Icons", + "lastOpened": 0, + "created": 1580075608590 + }, + "iconSets": [ + { + "selection": [ + { + "order": 2, + "id": 0, + "name": "database", + "prevSize": 32, + "code": 59649, + "tempChar": "" + } + ], + "id": 2, + "metadata": { + "name": "Plugin Icons", + "importSize": { + "width": 16, + "height": 18 + } + }, + "height": 1024, + "prevSize": 32, + "icons": [ + { + "id": 0, + "paths": [ + "M455.111 0c-251.449 0-455.111 101.831-455.111 227.556s203.662 227.556 455.111 227.556 455.111-101.831 455.111-227.556-203.662-227.556-455.111-227.556zM0 341.333v170.667c0 125.724 203.662 227.556 455.111 227.556s455.111-101.831 455.111-227.556v-170.667c0 125.724-203.662 227.556-455.111 227.556s-455.111-101.831-455.111-227.556zM0 625.778v170.667c0 125.724 203.662 227.556 455.111 227.556s455.111-101.831 455.111-227.556v-170.667c0 125.724-203.662 227.556-455.111 227.556s-455.111-101.831-455.111-227.556z" + ], + "attrs": [ + {} + ], + "width": 910, + "isMulticolor": false, + "isMulticolor2": false, + "grid": 0, + "tags": [ + "plugins" + ] + } + ], + "invisible": false, + "colorThemes": [] + } + ], + "preferences": { + "showGlyphs": true, + "showQuickUse": true, + "showQuickUse2": true, + "showSVGs": true, + "fontPref": { + "prefix": "plugicon-", + "metadata": { + "fontFamily": "pluginicons", + "majorVersion": 1, + "minorVersion": 0 + }, + "metrics": { + "emSize": 1024, + "baseline": 6.25, + "whitespace": 50 + }, + "embed": false, + "showSelector": false, + "showMetrics": false, + "showMetadata": false, + "showVersion": false + }, + "imagePref": { + "prefix": "icon-", + "png": true, + "useClassSelector": true, + "color": 0, + "bgColor": 16777215, + "classSelector": ".icon" + }, + "historySize": 50, + "showCodes": true, + "gridSize": 16 + }, + "uid": -1 +} \ No newline at end of file diff --git a/assets/fonts/README.md b/assets/fonts/README.md new file mode 100644 index 00000000000..c3e38aa08bd --- /dev/null +++ b/assets/fonts/README.md @@ -0,0 +1,28 @@ +How to upgrade icons in icon-fonts on Nightscout +================================================ + +This guide is fol developers regarding how to add new icon to Nightscout. + +Nightscout use icon fonts to render icons. Each icon is glyph (like - letter, or more like emoji character) inside custom made font file. +That way we have nice, vector icons, that are small, scalable, looks good on each platform, and are easy to embed inside CSS. + +To extend existing icon set.: + +1. Prepare minimalist, black & white icon in SVG tool of choice, and optimize it (you can use Inkscape) to be small in size and render good at small sizes. +2. Use https://icomoon.io/app and import accompanied JSON project file +3. Add SVG as new glyph. Remember to take care to set proper character code and CSS name +4. Save new version of JSON project file and store in this folder +5. Generate font, download zip file and unpack into this folder (update existing files) +6. Update `statc/css/main.css` file + * In section of `@font-face` with `font-family: 'pluginicons'` + * update part after `data:application/font-woff;charset=utf-8;base64,` with Base64-encoded content of previously generated WOFF font. + * update part after `data:application/font-svg;charset=utf-8;base64,` with Base64-encoded content of previously generated CSS font and + * copy/update all entries `.plugicon-****:before { content: "****"; }` from generated font `style.css` into `statc/css/main.css` + +Hints +----- + +* You can find many useful online tools to encode file into Base64, like: https://base64.guru/converter/encode/file +* Do not split Base64 output - it should be one LONG line +* Since update process is **manual** and generated fonts & updated CSS sections are **binary** - try to avoid **git merge conflicts** by speaking with other developers if you plan to add new icon +* When in doubt - check `git log` and reach last contributor for guidelines :) diff --git a/assets/fonts/pluginicons-v1.0/Read Me.txt b/assets/fonts/pluginicons-v1.0/Read Me.txt new file mode 100644 index 00000000000..8491652f880 --- /dev/null +++ b/assets/fonts/pluginicons-v1.0/Read Me.txt @@ -0,0 +1,7 @@ +Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. + +To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/#docs/local-fonts + +You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. + +You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection. diff --git a/assets/fonts/pluginicons-v1.0/demo-files/demo.css b/assets/fonts/pluginicons-v1.0/demo-files/demo.css new file mode 100644 index 00000000000..39b8991da78 --- /dev/null +++ b/assets/fonts/pluginicons-v1.0/demo-files/demo.css @@ -0,0 +1,152 @@ +body { + padding: 0; + margin: 0; + font-family: sans-serif; + font-size: 1em; + line-height: 1.5; + color: #555; + background: #fff; +} +h1 { + font-size: 1.5em; + font-weight: normal; +} +small { + font-size: .66666667em; +} +a { + color: #e74c3c; + text-decoration: none; +} +a:hover, a:focus { + box-shadow: 0 1px #e74c3c; +} +.bshadow0, input { + box-shadow: inset 0 -2px #e7e7e7; +} +input:hover { + box-shadow: inset 0 -2px #ccc; +} +input, fieldset { + font-family: sans-serif; + font-size: 1em; + margin: 0; + padding: 0; + border: 0; +} +input { + color: inherit; + line-height: 1.5; + height: 1.5em; + padding: .25em 0; +} +input:focus { + outline: none; + box-shadow: inset 0 -2px #449fdb; +} +.glyph { + font-size: 16px; + width: 15em; + padding-bottom: 1em; + margin-right: 4em; + margin-bottom: 1em; + float: left; + overflow: hidden; +} +.liga { + width: 80%; + width: calc(100% - 2.5em); +} +.talign-right { + text-align: right; +} +.talign-center { + text-align: center; +} +.bgc1 { + background: #f1f1f1; +} +.fgc1 { + color: #999; +} +.fgc0 { + color: #000; +} +p { + margin-top: 1em; + margin-bottom: 1em; +} +.mvm { + margin-top: .75em; + margin-bottom: .75em; +} +.mtn { + margin-top: 0; +} +.mtl, .mal { + margin-top: 1.5em; +} +.mbl, .mal { + margin-bottom: 1.5em; +} +.mal, .mhl { + margin-left: 1.5em; + margin-right: 1.5em; +} +.mhmm { + margin-left: 1em; + margin-right: 1em; +} +.mls { + margin-left: .25em; +} +.ptl { + padding-top: 1.5em; +} +.pbs, .pvs { + padding-bottom: .25em; +} +.pvs, .pts { + padding-top: .25em; +} +.unit { + float: left; +} +.unitRight { + float: right; +} +.size1of2 { + width: 50%; +} +.size1of1 { + width: 100%; +} +.clearfix:before, .clearfix:after { + content: " "; + display: table; +} +.clearfix:after { + clear: both; +} +.hidden-true { + display: none; +} +.textbox0 { + width: 3em; + background: #f1f1f1; + padding: .25em .5em; + line-height: 1.5; + height: 1.5em; +} +#testDrive { + display: block; + padding-top: 24px; + line-height: 1.5; +} +.fs0 { + font-size: 16px; +} +.fs1 { + font-size: 32px; +} + diff --git a/assets/fonts/pluginicons-v1.0/demo-files/demo.js b/assets/fonts/pluginicons-v1.0/demo-files/demo.js new file mode 100644 index 00000000000..6f45f1c409c --- /dev/null +++ b/assets/fonts/pluginicons-v1.0/demo-files/demo.js @@ -0,0 +1,30 @@ +if (!('boxShadow' in document.body.style)) { + document.body.setAttribute('class', 'noBoxShadow'); +} + +document.body.addEventListener("click", function(e) { + var target = e.target; + if (target.tagName === "INPUT" && + target.getAttribute('class').indexOf('liga') === -1) { + target.select(); + } +}); + +(function() { + var fontSize = document.getElementById('fontSize'), + testDrive = document.getElementById('testDrive'), + testText = document.getElementById('testText'); + function updateTest() { + testDrive.innerHTML = testText.value || String.fromCharCode(160); + if (window.icomoonLiga) { + window.icomoonLiga(testDrive); + } + } + function updateSize() { + testDrive.style.fontSize = fontSize.value + 'px'; + } + fontSize.addEventListener('change', updateSize, false); + testText.addEventListener('input', updateTest, false); + testText.addEventListener('change', updateTest, false); + updateSize(); +}()); diff --git a/assets/fonts/pluginicons-v1.0/demo.html b/assets/fonts/pluginicons-v1.0/demo.html new file mode 100644 index 00000000000..10326a8e23e --- /dev/null +++ b/assets/fonts/pluginicons-v1.0/demo.html @@ -0,0 +1,52 @@ + + + + + IcoMoon Demo + + + + + +
+

Font Name: pluginicons (Glyphs: 1)

+
+
+

Grid Size: Unknown

+
+
+ + plugicon-database +
+
+ + +
+
+ liga: + +
+
+
+ + +
+

Font Test Drive

+ + +
  +
+
+ +
+

Generated by IcoMoon

+
+ + + + diff --git a/assets/fonts/pluginicons-v1.0/fonts/pluginicons.eot b/assets/fonts/pluginicons-v1.0/fonts/pluginicons.eot new file mode 100644 index 0000000000000000000000000000000000000000..470178d0f2c5652b29e9bb3aecc43a0454986264 GIT binary patch literal 1512 zcmah}O-vI}5T3W&Qd&rnO>Gk)WQ9g-L)!AM1{z`lN+OZ4NTM;wQr6O>-EI1lK;YoP zi!nhGPTV;`;*l8i(34y|8NKL{i^Q9Wi5IBf+g+rq2$Q^>Z@&5F?d#6#d~*}^VKEZO zX^hqxXYNfpd9Jl=V|R4!?;KH(@|2}Ar71%?R*DSxB7}aLA`N^Qd6f!af;0oBfNaK8 z$<$3TN|>4d?SdpfKm$D^krMZncu$k$`T^!0)?6y5=0guYzJRC|@pM`(=HV|P=Dt3i zU49zyx7|U!gmrgOQx`(hd!LDf3i1PsAUu=ed&IvGhZl3DCGQ##iG066)<~&zo!%hk z$85~0OL_9rW5h#On|EUG2V%7*tI)94^b?O;d8JJDy-_ZE-k0HDc5=f6^3Zde7s21Qu?u+9#%|!NHm(Cs+1N){Xpi41 zmlsSB84C*-2`_Cdf}gOl3wX=MZs0B(*8%G`_E8^w%4f^zjGjpudhzV3GouxX8AF%5 zV~Mjz&4oK$D45dH<*Zt8&bAAy#tgkAr!`$Gs3mPdo?n*7Q^tg0=rI~IM`4L%j7kl^ hmk&slO7IKd=4lzvadWIrK*@(|3|%s3Ol=#T_&0JO=5+u7 literal 0 HcmV?d00001 diff --git a/assets/fonts/pluginicons-v1.0/fonts/pluginicons.svg b/assets/fonts/pluginicons-v1.0/fonts/pluginicons.svg new file mode 100644 index 00000000000..2a563386881 --- /dev/null +++ b/assets/fonts/pluginicons-v1.0/fonts/pluginicons.svg @@ -0,0 +1,11 @@ + + + +Generated by IcoMoon + + + + + + + \ No newline at end of file diff --git a/assets/fonts/pluginicons-v1.0/fonts/pluginicons.ttf b/assets/fonts/pluginicons-v1.0/fonts/pluginicons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a44b5a4ae87eb468a268d92567bdfb92d2f241c4 GIT binary patch literal 1332 zcmah|O-vI}5dL1br4&e!O{IwtQlSyskhc7*frglfav&NONi+soN?n??yG>gX2pl|k zF(zo@i907qJQ9N*dXkGLqZd7LGTux~yg>cl?h;EhFwN_H^UXK2v+uoy0MLx5P>{N- zB?nqn?@u!CxfU`7y%@g#={X=e8P6Jexk!J3vGk2be(gyp*maxnD%YLmtiBYU-Twl3 zs?3iplkneDJ}~~xIJ#V@tOhoTpvZoqyp_>$6>k}*7`GJk)gl6T#CVKx#MBGfmX7r; z#^l6a(JEIsC(Rdgr5z?9(;@d>2Z!R>g$E#iZPe z6N}hDK25Gp<{Yoss!n)ujeHXt;o(mp@?F%9YBjs+1dG~XSYcg#Ujac?YaQnSMz7nF zzq+$IPExBXo1D4>H}HUicl(3F-*7P$?h@hl!GY1V7#$fN>P?8=E8;XeE<(1pr`ygB zx1F692lJY?9;K~o+C1?_Pc+)Ip=n3o{-I?0e^QrMs;Zif#Zt*wd|aiC$79Jk$E{<((CoF3;H&noPXfog zyTv=pvvQ0z_Sy3wr74?rC*ml4PR0pj88wbIA%re$+Z8@Mv~LD4p_{FDLA-JM3VvlL zH_QV+p1Hh2{-%q)#9J=*5npz3198U1O}K=8d8fPqGVRPb*n=QmxL6@S?P4$Swu^nl zeJ*YwHeK9=A$%_8SB#vQ%UEU^MdYyp135}^e6&Shp39cXIm?XnCsLS07A2IKl&J{% zkwEI)4(AGHvc^hYFJXr54Nj1Uj?%eRla^VD7+Eu0(kt1e$l_XLDq~GsmYKk$Jzs?r h8f<xYO{IwtvO*)aA#M3rBMmWHqYmkDQ1%6OT~8_jbh+4a{cVeDlrBoAfo&rCrtg3H36<{G~9`I)JgIrknu&*j=;=9eFW`vASg zH5BZ;nKkqUBDo3iVXoonov≫I6}uaP{4mKV}P+C2+h)h^v2%C~s$Y-YR@v-$WPb zZ9!i`U->C~Rj8ltTYA9&_ZmI7xi+=0tQYNa1^b;l%9DX)X_vhuFOjq^eS-hOvFry8 zFhBfyVJ-C@$74kMOs>|dG$upAFz6pq1rS|;IuPTy10&DsAP-%F4dA3Ce2mn6Ry(NG zz|j$AwY{+HR)_!wMhscaVit#!h(<1p)_?n-%wZ+9s=S6(x6>86i%GkDLFQ{X8wz)_ zaN9utNQ#XN4-NLjSE$k=xxRqC>4GhuQ9|rmaLEE1EV7yxJX!bgydK!S{bC z9{yjd%ga?oNkyZ{L^L+4Kt^NHL^2vpDazs2RwBj$PlzRsIfr|jPLfl+iRx6VqO_(^ z&CidY8FcQ(_NxcYSAS8XN1W<6?OiVij&)CqziXVV5Y&jf$3=3H*XnLWFywV2j>F54 z<46E+x|23Ug_rJ$mw`vn`>JpLcNsaK^;} zI!8PFO?mua+7NNDL_vD)Vj28|i#@;_F7^WVy0`(@a&dqL=}R%cXy&Y3# zNjaqC(AtJA&lsh0&bHLPc#>wwpc0i4!XE-%s$}ku6dWohmy@?g%NvG1O zRcYI*sHR~VCB0%SsPoI}c*dTvZ7WV`vAzmcXktoBtXiiE>;kxXTE;joHaLMyzLz+z JkN@c>$Zw-6);$0K literal 0 HcmV?d00001 diff --git a/assets/fonts/pluginicons-v1.0/selection.json b/assets/fonts/pluginicons-v1.0/selection.json new file mode 100644 index 00000000000..7b2485334ad --- /dev/null +++ b/assets/fonts/pluginicons-v1.0/selection.json @@ -0,0 +1 @@ +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M455.111 0c-251.449 0-455.111 101.831-455.111 227.556s203.662 227.556 455.111 227.556 455.111-101.831 455.111-227.556-203.662-227.556-455.111-227.556zM0 341.333v170.667c0 125.724 203.662 227.556 455.111 227.556s455.111-101.831 455.111-227.556v-170.667c0 125.724-203.662 227.556-455.111 227.556s-455.111-101.831-455.111-227.556zM0 625.778v170.667c0 125.724 203.662 227.556 455.111 227.556s455.111-101.831 455.111-227.556v-170.667c0 125.724-203.662 227.556-455.111 227.556s-455.111-101.831-455.111-227.556z"],"attrs":[{}],"width":910,"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["plugins"]},"attrs":[{}],"properties":{"order":3,"id":0,"name":"database","prevSize":32,"code":59649},"setIdx":0,"setId":2,"iconIdx":0}],"height":1024,"metadata":{"name":"pluginicons"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"plugicon-","metadata":{"fontFamily":"pluginicons","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"showSelector":true,"showMetrics":true,"showMetadata":true,"showVersion":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon"},"historySize":50,"showCodes":true,"gridSize":16}} \ No newline at end of file diff --git a/assets/fonts/pluginicons-v1.0/style.css b/assets/fonts/pluginicons-v1.0/style.css new file mode 100644 index 00000000000..0a487ebc919 --- /dev/null +++ b/assets/fonts/pluginicons-v1.0/style.css @@ -0,0 +1,30 @@ +@font-face { + font-family: 'pluginicons'; + src: url('fonts/pluginicons.eot?yajd4z'); + src: url('fonts/pluginicons.eot?yajd4z#iefix') format('embedded-opentype'), + url('fonts/pluginicons.ttf?yajd4z') format('truetype'), + url('fonts/pluginicons.woff?yajd4z') format('woff'), + url('fonts/pluginicons.svg?yajd4z#pluginicons') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +[class^="plugicon-"], [class*=" plugicon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'pluginicons' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.plugicon-database:before { + content: "\e901"; +} diff --git a/lib/client/receiveddata.js b/lib/client/receiveddata.js index e0adf13fb3b..c167d9463a3 100644 --- a/lib/client/receiveddata.js +++ b/lib/client/receiveddata.js @@ -128,6 +128,9 @@ function receiveDData (received, ddata, settings) { } } + if (received.dbstats && received.dbstats.fileSize) { + ddata.dbstats = received.dbstats; + } } //expose for tests diff --git a/lib/data/dataloader.js b/lib/data/dataloader.js index 1c00f998d73..b0eafdd4fe0 100644 --- a/lib/data/dataloader.js +++ b/lib/data/dataloader.js @@ -69,6 +69,7 @@ function init(env, ctx) { // clear treatments, we're going to merge from more queries ddata.treatments = []; + ddata.dbstats = {}; async.parallel([ loadEntries.bind(null, ddata, ctx) @@ -79,6 +80,7 @@ function init(env, ctx) { , loadFood.bind(null, ddata, ctx) , loadDeviceStatus.bind(null, ddata, env, ctx) , loadActivity.bind(null, ddata, ctx) + , loadDatabaseStats.bind(null, ddata, ctx) ], loadComplete); }; @@ -399,5 +401,21 @@ function loadDeviceStatus(ddata, env, ctx, callback) { }); } +function loadDatabaseStats(ddata, ctx, callback) { + ctx.store.db.stats(function mongoDone (err, result) { + if (err) { + console.log("Problem loading database stats"); + } + if (!err && result) { + ddata.dbstats = { + dataSize: result.dataSize + , indexSize: result.indexSize + , fileSize: result.fileSize + }; + } + callback(); + }); +} + module.exports = init; diff --git a/lib/data/ddata.js b/lib/data/ddata.js index 9fa470e3f16..b5226124ccf 100644 --- a/lib/data/ddata.js +++ b/lib/data/ddata.js @@ -17,6 +17,7 @@ function init () { , devicestatus: [] , food: [] , activity: [] + , dbstats: {} , lastUpdated: 0 }; @@ -51,6 +52,7 @@ function init () { results.mbgs = ddata.mbgs; results.food = ddata.food; results.treatments = ddata.treatments; + results.dbstats = ddata.dbstats; return results; diff --git a/lib/language.js b/lib/language.js index c105c5239d7..ede0a734add 100644 --- a/lib/language.js +++ b/lib/language.js @@ -15100,7 +15100,33 @@ function init() { , pl: 'Tłuszcz ogółem' ,ru: 'Всего жиров' ,he: 'כל שומנים' - } + }, + 'Database Size': { + pl: 'Rozmiar Bazy Danych' + }, + 'Database Size near its limits!': { + pl: 'Rozmiar bazy danych zbliża się do limitu!' + }, + 'Database size is %1 MiB out of %2 MiB. Please backup and clean up database!': { + pl: 'Baza danych zajmuje %1 MiB z dozwolonych %2 MiB. Proszę zrób kopię zapasową i oczyść bazę danych!' + }, + 'Database file size': { + pl: 'Rozmiar pliku bazy danych' + }, + '%1 MiB of %2 MiB (%3%)': { + pl: '%1 MiB z %2 MiB (%3%)' + }, + 'Data size': { + pl: 'Rozmiar danych' + }, + 'virtAsstDatabaseSize': { + en: '%1 MiB that is %2% of available database space' + ,pl: '%1 MiB co stanowi %2% przestrzeni dostępnej dla bazy danych' + }, + 'virtAsstTitleDatabaseSize': { + en: 'Database file size' + ,pl: 'Rozmiar pliku bazy danych' + } }; language.translations = translations; diff --git a/lib/plugins/dbsize.js b/lib/plugins/dbsize.js new file mode 100644 index 00000000000..61b933977c3 --- /dev/null +++ b/lib/plugins/dbsize.js @@ -0,0 +1,160 @@ +'use strict'; + +var _ = require('lodash'); +var levels = require('../levels'); + +function init (ctx) { + var translate = ctx.language.translate; + + var dbsize = { + name: 'dbsize' + , label: translate('Database Size') + , pluginType: 'pill-status' + , pillFlip: true + }; + + dbsize.getPrefs = function getPrefs (sbx) { + return { + warn: sbx.extendedSettings.warn ? sbx.extendedSettings.warn : 300 + , urgent: sbx.extendedSettings.urgent ? sbx.extendedSettings.urgent : 370 + , max: sbx.extendedSettings.max ? sbx.extendedSettings.max : 496 + , enableAlerts: sbx.extendedSettings.enableAlerts + , inMib: sbx.extendedSettings.inMib + }; + }; + + dbsize.setProperties = function setProperties (sbx) { + sbx.offerProperty('dbsize', function setDbsize () { + return dbsize.analyzeData(sbx); + }); + }; + + dbsize.analyzeData = function analyzeData (sbx) { + + var prefs = dbsize.getPrefs(sbx); + + var recentData = sbx.data.dbstats; + + var result = { + level: undefined + , display: prefs.inMib ? '?MiB' : '?%' + , status: undefined + }; + + var maxSize = (prefs.max > 0) ? prefs.max : 100 * 1024; + var currentSize = (recentData && recentData.fileSize ? recentData.fileSize : 0) / (1024 * 1024); + var totalDataSize = (recentData && recentData.dataSize) ? recentData.dataSize : 0; + totalDataSize += (recentData && recentData.indexSize) ? recentData.indexSize : 0; + totalDataSize /= 1024 * 1024; + + var sizePercentage = Math.floor((currentSize * 100.0) / maxSize); + var dataPercentage = Math.floor((totalDataSize * 100.0) / maxSize); + + result.dataPercentage = dataPercentage; + result.notificationLevel = levels.INFO; + result.details = { + fileSize: parseFloat(currentSize.toFixed(2)) + , maxSize: parseFloat(maxSize.toFixed(2)) + , dataSize: parseFloat(totalDataSize.toFixed(2)) + , sizePercentage: sizePercentage + }; + + if (totalDataSize >= prefs.warn && totalDataSize < prefs.urgent) { + result.notificationLevel = levels.WARN; + } else if (totalDataSize >= prefs.urgent) { + result.notificationLevel = levels.URGENT; + } + + result.display = prefs.inMib ? parseFloat(totalDataSize.toFixed(0)) + 'MiB' : dataPercentage + '%'; + result.status = levels.toStatusClass(result.notificationLevel); + + return result; + }; + + dbsize.checkNotifications = function checkNotifications (sbx) { + var prefs = dbsize.getPrefs(sbx); + + if (!prefs.enableAlerts) { return; } + + var prop = sbx.properties.dbsize; + + if (prop.dataPercentage && prop.notificationLevel && prop.notificationLevel >= levels.WARN) { + sbx.notifications.requestNotify({ + level: prop.notificationLevel + , title: levels.toDisplay(prop.notificationLevel) + ' ' + translate('Database Size near its limits!') + , message: translate("Database size is %1 MiB out of %2 MiB. Please backup and clean up database!", { + params: [prop.details.dataSize, prop.details.maxSize] + }) + , pushoverSound: 'echo' + , group: 'Database Size' + , plugin: dbsize + , debug: prop + }); + } + }; + + dbsize.updateVisualisation = function updateVisualisation (sbx) { + var prop = sbx.properties.dbsize; + + var infos = [{ + label: translate('Data size') + , value: translate('%1 MiB of %2 MiB (%3%)', { + params: [prop.details.dataSize, prop.details.maxSize, prop.dataPercentage] + }) + } + + , { + label: translate('Database file size') + , value: translate('%1 MiB of %2 MiB (%3%)', { + params: [prop.details.fileSize, prop.details.maxSize, prop.details.sizePercentage] + }) + } + ]; + + sbx.pluginBase.updatePillText(dbsize, { + value: prop && prop.display + , labelClass: 'plugicon-database' + , pillClass: prop && prop.status + , info: infos + , hide: !(prop && prop.dataPercentage && prop.dataPercentage >= 0) + }); + }; + + function virtAsstDatabaseSizeHandler (next, slots, sbx) { + if (sbx.properties.dbsize.display) { + var response = translate('virtAsstDatabaseSize', { + params: [ + sbx.properties.dbsize.details.dataSize + + + , sbx.properties.dbsize.dataPercentage + ] + }); + next(translate('virtAsstTitleDatabaseSize'), response); + } else { + next(translate('virtAsstTitleDatabaseSize'), translate('virtAsstUnknown')); + } + } + + dbsize.virtAsst = { + intentHandlers: [ + { + // for backwards compatibility + intent: 'DatabaseSize' + , intentHandler: virtAsstDatabaseSizeHandler + } + + + , { + intent: 'MetricNow' + , metrics: ['database size', 'file size', 'db size', 'data size'] + , intentHandler: virtAsstDatabaseSizeHandler + } + ] + }; + + return dbsize; + +} + +module.exports = init; diff --git a/lib/plugins/index.js b/lib/plugins/index.js index 2568b634afd..5a6cb2822da 100644 --- a/lib/plugins/index.js +++ b/lib/plugins/index.js @@ -49,6 +49,7 @@ function init (ctx) { , require('./boluscalc')(ctx) // fake plugin to show/hide , require('./profile')(ctx) // fake plugin to hold extended settings , require('./speech')(ctx) + , require('./dbsize')(ctx) ]; var serverDefaultPlugins = [ diff --git a/static/css/main.css b/static/css/main.css index 8e6882dde9d..25c6bae0f0e 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -9,7 +9,21 @@ font-style: normal; } - [class^="icon-"]:before, [class*=" icon-"]:before { +/* + Icon font for additional plugin icons. + Please read assets/fonts/README.md about update process +*/ +@font-face { + font-family: 'pluginicons'; + /* Plugin Icons font files content (from WOFF and SVG icon files, base64 encoded) */ + src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAWAAAsAAAAABTQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDxIE8mNtYXAAAAFoAAAAVAAAAFQXVdKJZ2FzcAAAAbwAAAAIAAAACAAAABBnbHlmAAABxAAAAUgAAAFIFA4eR2hlYWQAAAMMAAAANgAAADYXVLrVaGhlYQAAA0QAAAAkAAAAJAdQA8ZobXR4AAADaAAAABQAAAAUCY4AAGxvY2EAAAN8AAAADAAAAAwAKAC4bWF4cAAAA4gAAAAgAAAAIAAJAFxuYW1lAAADqAAAAbYAAAG2DBt7mXBvc3QAAAVgAAAAIAAAACAAAwAAAAMCxwGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAA6QEDwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADgAAAAKAAgAAgACAAEAIOkB//3//wAAAAAAIOkB//3//wAB/+MXAwADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAwAA/8ADjgPAABsAOgBZAAABIgcOAQcGFRQXHgEXFjMyNz4BNzY1NCcuAScmARUUFx4BFxYzMjc+ATc2PQEUBw4BBwYjIicuAScmNREVFBceARcWMzI3PgE3Nj0BFAcOAQcGIyInLgEnJjUBx15TU3skJCQke1NTXl5TU3wjJCQjfFNT/dskJHtTU15eU1N8IyQkI3xTU15eU1N7JCQkJHtTU15eU1N8IyQkI3xTU15eU1N7JCQDwBISPikpMC8pKj0SEhISPSopLzApKT4SEv6rqy8qKT4SEhISPikqL6svKik+EhISEj4pKi/+46owKSk+EhISEj4pKTCqLykqPhESEhE+KikvAAAAAAEAAAABAABgRbaTXw889QALBAAAAAAA2lO7LAAAAADaU7ssAAD/wAOOA8AAAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAAA44AAQAAAAAAAAAAAAAAAAAAAAUEAAAAAAAAAAAAAAACAAAAA44AAAAAAAAACgAUAB4ApAABAAAABQBaAAMAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEACwAAAAEAAAAAAAIABwCEAAEAAAAAAAMACwBCAAEAAAAAAAQACwCZAAEAAAAAAAUACwAhAAEAAAAAAAYACwBjAAEAAAAAAAoAGgC6AAMAAQQJAAEAFgALAAMAAQQJAAIADgCLAAMAAQQJAAMAFgBNAAMAAQQJAAQAFgCkAAMAAQQJAAUAFgAsAAMAAQQJAAYAFgBuAAMAAQQJAAoANADUcGx1Z2luaWNvbnMAcABsAHUAZwBpAG4AaQBjAG8AbgBzVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADEALgAwcGx1Z2luaWNvbnMAcABsAHUAZwBpAG4AaQBjAG8AbgBzcGx1Z2luaWNvbnMAcABsAHUAZwBpAG4AaQBjAG8AbgBzUmVndWxhcgBSAGUAZwB1AGwAYQBycGx1Z2luaWNvbnMAcABsAHUAZwBpAG4AaQBjAG8AbgBzRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format('woff'), + url(data:application/font-svg;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIiA+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+DQo8bWV0YWRhdGE+R2VuZXJhdGVkIGJ5IEljb01vb248L21ldGFkYXRhPg0KPGRlZnM+DQo8Zm9udCBpZD0icGx1Z2luaWNvbnMiIGhvcml6LWFkdi14PSIxMDI0Ij4NCjxmb250LWZhY2UgdW5pdHMtcGVyLWVtPSIxMDI0IiBhc2NlbnQ9Ijk2MCIgZGVzY2VudD0iLTY0IiAvPg0KPG1pc3NpbmctZ2x5cGggaG9yaXotYWR2LXg9IjEwMjQiIC8+DQo8Z2x5cGggdW5pY29kZT0iJiN4MjA7IiBob3Jpei1hZHYteD0iNTEyIiBkPSIiIC8+DQo8Z2x5cGggdW5pY29kZT0iJiN4ZTkwMTsiIGdseXBoLW5hbWU9ImRhdGFiYXNlIiBob3Jpei1hZHYteD0iOTEwIiBkPSJNNDU1LjExMSA5NjBjLTI1MS40NDkgMC00NTUuMTExLTEwMS44MzEtNDU1LjExMS0yMjcuNTU2czIwMy42NjItMjI3LjU1NiA0NTUuMTExLTIyNy41NTYgNDU1LjExMSAxMDEuODMxIDQ1NS4xMTEgMjI3LjU1Ni0yMDMuNjYyIDIyNy41NTYtNDU1LjExMSAyMjcuNTU2ek0wIDYxOC42Njd2LTE3MC42NjdjMC0xMjUuNzI0IDIwMy42NjItMjI3LjU1NiA0NTUuMTExLTIyNy41NTZzNDU1LjExMSAxMDEuODMxIDQ1NS4xMTEgMjI3LjU1NnYxNzAuNjY3YzAtMTI1LjcyNC0yMDMuNjYyLTIyNy41NTYtNDU1LjExMS0yMjcuNTU2cy00NTUuMTExIDEwMS44MzEtNDU1LjExMSAyMjcuNTU2ek0wIDMzNC4yMjJ2LTE3MC42NjdjMC0xMjUuNzI0IDIwMy42NjItMjI3LjU1NiA0NTUuMTExLTIyNy41NTZzNDU1LjExMSAxMDEuODMxIDQ1NS4xMTEgMjI3LjU1NnYxNzAuNjY3YzAtMTI1LjcyNC0yMDMuNjYyLTIyNy41NTYtNDU1LjExMS0yMjcuNTU2cy00NTUuMTExIDEwMS44MzEtNDU1LjExMSAyMjcuNTU2eiIgLz4NCjwvZm9udD48L2RlZnM+PC9zdmc+) format('svg'); + font-weight: normal; + font-style: normal; +} + + [class^="icon-"]:before, [class*=" icon-"]:before, + [class^="plugicon-"]:before, [class*=" plugicon-"]:before { font-family: "nsicons"; font-style: normal; font-weight: normal; @@ -43,6 +57,10 @@ /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } + +[class^="plugicon-"]:before, [class*=" plugicon-"]:before { + font-family: "pluginicons"; +} .icon-volume:before { content: '\e800'; } .icon-plus:before { content: '\e801'; } @@ -65,6 +83,9 @@ .icon-chart-line:before { content: '\f201'; } .icon-hourglass:before { content: '\f254'; } +/* Plugin Icons id-s (copy from generated icon style.css) */ +.plugicon-database:before { content: "\e901"; } + html, body { margin: 0; padding: 0; diff --git a/tests/dbsize.test.js b/tests/dbsize.test.js new file mode 100644 index 00000000000..67d416b2eae --- /dev/null +++ b/tests/dbsize.test.js @@ -0,0 +1,257 @@ +'use strict'; + +require('should'); + +describe('Database Size', function() { + + var dataInRange = { dbstats: { dataSize: 1024 * 1024 * 137, indexSize: 1024 * 1024 * 48, fileSize: 1024 * 1024 * 256 } }; + var dataWarn = { dbstats: { dataSize: 1024 * 1024 * 250, indexSize: 1024 * 1024 * 100, fileSize: 1024 * 1024 * 360 } }; + var dataUrgent = { dbstats: { dataSize: 1024 * 1024 * 300, indexSize: 1024 * 1024 * 150, fileSize: 1024 * 1024 * 496 } }; + + var env = require('../env')(); + + it('display database size in range', function(done) { + var sandbox = require('../lib/sandbox')(); + var ctx = { + settings: {} + , language: require('../lib/language')() + }; + ctx.language.set('en'); + ctx.levels = require('../lib/levels'); + + var sbx = sandbox.clientInit(ctx, Date.now(), dataInRange); + + sbx.offerProperty = function mockedOfferProperty (name, setter) { + name.should.equal('dbsize'); + var result = setter(); + result.display.should.equal('37%'); + result.status.should.equal('current'); + done(); + }; + + var dbsize = require('../lib/plugins/dbsize')(ctx); + dbsize.setProperties(sbx); + + }); + + // ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~. + + it('display database size warning', function(done) { + var sandbox = require('../lib/sandbox')(); + var ctx = { + settings: {} + , language: require('../lib/language')() + }; + ctx.language.set('en'); + ctx.levels = require('../lib/levels'); + + var sbx = sandbox.clientInit(ctx, Date.now(), dataWarn); + + sbx.offerProperty = function mockedOfferProperty (name, setter) { + name.should.equal('dbsize'); + var result = setter(); + result.display.should.equal('70%'); + result.status.should.equal('warn'); + done(); + }; + + var dbsize = require('../lib/plugins/dbsize')(ctx); + + dbsize.setProperties(sbx); + + }); + + // ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~. + + it('display database size urgent', function(done) { + var sandbox = require('../lib/sandbox')(); + var ctx = { + settings: {} + , language: require('../lib/language')() + }; + ctx.language.set('en'); + ctx.levels = require('../lib/levels'); + + var sbx = sandbox.clientInit(ctx, Date.now(), dataUrgent); + + sbx.offerProperty = function mockedOfferProperty (name, setter) { + name.should.equal('dbsize'); + var result = setter(); + result.display.should.equal('90%'); + result.status.should.equal('urgent'); + done(); + }; + + var dbsize = require('../lib/plugins/dbsize')(ctx); + dbsize.setProperties(sbx); + + }); + + // ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~. + + it('display database size warning notiffication', function(done) { + var sandbox = require('../lib/sandbox')(); + var ctx = { + settings: {} + , language: require('../lib/language')() + , notifications: require('../lib/notifications')(env, ctx) + }; + ctx.notifications.initRequests(); + ctx.language.set('en'); + ctx.levels = require('../lib/levels'); + + var sbx = sandbox.clientInit(ctx, Date.now(), dataWarn); + sbx.extendedSettings = { 'enableAlerts': 'TRUE' }; + + var dbsize = require('../lib/plugins/dbsize')(ctx); + + dbsize.setProperties(sbx); + dbsize.checkNotifications(sbx); + + var notif = ctx.notifications.findHighestAlarm('Database Size'); + notif.level.should.equal(ctx.levels.WARN); + notif.title.should.equal('Warning Database Size near its limits!'); + notif.message.should.equal('Database size is 350 MiB out of 496 MiB. Please backup and clean up database!'); + done(); + }); + + // ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~. + + it('display database size urgent notiffication', function(done) { + var sandbox = require('../lib/sandbox')(); + var ctx = { + settings: {} + , language: require('../lib/language')() + , notifications: require('../lib/notifications')(env, ctx) + }; + ctx.notifications.initRequests(); + ctx.language.set('en'); + ctx.levels = require('../lib/levels'); + + var sbx = sandbox.clientInit(ctx, Date.now(), dataUrgent); + sbx.extendedSettings = { 'enableAlerts': 'TRUE' }; + + var dbsize = require('../lib/plugins/dbsize')(ctx); + + dbsize.setProperties(sbx); + dbsize.checkNotifications(sbx); + + var notif = ctx.notifications.findHighestAlarm('Database Size'); + notif.level.should.equal(ctx.levels.URGENT); + notif.title.should.equal('Urgent Database Size near its limits!'); + notif.message.should.equal('Database size is 450 MiB out of 496 MiB. Please backup and clean up database!'); + done(); + }); + + // ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~. + + it('set a pill to the database size in percent', function(done) { + var ctx = { + settings: {} + , pluginBase: { + updatePillText: function mockedUpdatePillText (plugin, options) { + options.value.should.equal('90%'); + options.labelClass.should.equal('plugicon-database'); + options.pillClass.should.equal('urgent'); + done(); + } + } + , language: require('../lib/language')() + }; + ctx.language.set('en'); + + var sandbox = require('../lib/sandbox')(); + var sbx = sandbox.clientInit(ctx, Date.now(), dataUrgent); + var dbsize = require('../lib/plugins/dbsize')(ctx); + dbsize.setProperties(sbx); + dbsize.updateVisualisation(sbx); + + }); + + // ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~. + + it('set a pill to the database size in MiB', function(done) { + var ctx = { + settings: { + extendedSettings: { + empty: false + , dbsize: { + inMib: true + } + } + } + , pluginBase: { + updatePillText: function mockedUpdatePillText (plugin, options) { + options.value.should.equal('450MiB'); + options.labelClass.should.equal('plugicon-database'); + options.pillClass.should.equal('urgent'); + done(); + } + } + , language: require('../lib/language')() + }; + ctx.language.set('en'); + + var sandbox = require('../lib/sandbox')(); + var sbx = sandbox.clientInit(ctx, Date.now(), dataUrgent); + var dbsize = require('../lib/plugins/dbsize')(ctx); + dbsize.setProperties(sbx.withExtendedSettings(dbsize)); + dbsize.updateVisualisation(sbx); + + }); + + // ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~. + + it('hide the pill if there is no info regarding database size', function(done) { + var ctx = { + settings: {} + , pluginBase: { + updatePillText: function mockedUpdatePillText (plugin, options) { + options.hide.should.equal(true); + done(); + } + } + , language: require('../lib/language')() + }; + ctx.language.set('en'); + + var sandbox = require('../lib/sandbox')(); + var sbx = sandbox.clientInit(ctx, Date.now(), {}); + var dbsize = require('../lib/plugins/dbsize')(ctx); + dbsize.setProperties(sbx); + dbsize.updateVisualisation(sbx); + }); + + // ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~. + + it('should handle virtAsst requests', function(done) { + + var ctx = { + settings: {} + , language: require('../lib/language')() + }; + ctx.language.set('en'); + + var sandbox = require('../lib/sandbox')(); + var sbx = sandbox.clientInit(ctx, Date.now(), dataUrgent); + var dbsize = require('../lib/plugins/dbsize')(ctx); + dbsize.setProperties(sbx); + + dbsize.virtAsst.intentHandlers.length.should.equal(2); + + dbsize.virtAsst.intentHandlers[0].intentHandler(function next (title, response) { + title.should.equal('Database file size'); + response.should.equal('450 MiB that is 90% of available database space'); + + dbsize.virtAsst.intentHandlers[1].intentHandler(function next (title, response) { + title.should.equal('Database file size'); + response.should.equal('450 MiB that is 90% of available database space'); + + done(); + }, [], sbx); + + }, [], sbx); + + }); + +});