From add06675502f320e003b3a38e3210100b4c0e7f1 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Mon, 17 Nov 2014 16:53:14 +0100 Subject: [PATCH 01/61] doc/style: add style guide, rename webfont --- .../controllers/StyleController.php | 24 +++++++++++++++---- .../views/scripts/style/guide.phtml | 13 ++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 modules/doc/application/views/scripts/style/guide.phtml diff --git a/modules/doc/application/controllers/StyleController.php b/modules/doc/application/controllers/StyleController.php index 889187efb..c28358d30 100644 --- a/modules/doc/application/controllers/StyleController.php +++ b/modules/doc/application/controllers/StyleController.php @@ -6,16 +6,32 @@ use Icinga\Web\Widget; class Doc_StyleController extends Controller { + public function guideAction() + { + $this->view->tabs = $this->tabs()->activate('guide'); + } + public function fontAction() { - $this->view->tabs = Widget::create('tabs')->add( + $this->view->tabs = $this->tabs()->activate('font'); + $confFile = Icinga::app()->getApplicationDir('fonts/fontello-ifont/config.json'); + $this->view->font = json_decode(file_get_contents($confFile)); + } + + protected function tabs() + { + return Widget::create('tabs')->add( + 'guide', + array( + 'title' => $this->translate('Style Guide'), + 'url' => 'doc/style/guide' + ) + )->add( 'fonts', array( 'title' => $this->translate('Icons'), 'url' => 'doc/style/font' ) - )->activate('fonts'); - $confFile = Icinga::app()->getApplicationDir('fonts/fontanello-ifont/config.json'); - $this->view->font = json_decode(file_get_contents($confFile)); + ); } } diff --git a/modules/doc/application/views/scripts/style/guide.phtml b/modules/doc/application/views/scripts/style/guide.phtml new file mode 100644 index 000000000..0be3d7563 --- /dev/null +++ b/modules/doc/application/views/scripts/style/guide.phtml @@ -0,0 +1,13 @@ +
+tabs ?> +

Style Guide

+
+ +
+

H1 - header

+

H2 - header

+

H3 - header

+

H4 - header

+
H5 - header
+
H6 - header
+
From 9e4cdd44701c45b3c1e8d89c2901d26567aa9994 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Mon, 17 Nov 2014 16:53:46 +0100 Subject: [PATCH 02/61] doc/configuration: link to style guide --- modules/doc/configuration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/doc/configuration.php b/modules/doc/configuration.php index 491321a79..87e5da77a 100644 --- a/modules/doc/configuration.php +++ b/modules/doc/configuration.php @@ -18,6 +18,6 @@ $section->add('Module documentations', array( 'url' => 'doc/module', )); $section->add($this->translate('Developer - Style'), array( - 'url' => 'doc/style/font', + 'url' => 'doc/style/guide', 'priority' => 200, )); From f43976a19ae96487134accc5e623e5ffffdcd05a Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Mon, 17 Nov 2014 16:54:29 +0100 Subject: [PATCH 03/61] css: centralize heading styles --- modules/doc/public/css/module.less | 8 ----- public/css/icinga/defaults.less | 42 +++++++++++++++++++++++++ public/css/icinga/layout-structure.less | 27 ---------------- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/modules/doc/public/css/module.less b/modules/doc/public/css/module.less index d6d0d2a94..376eda6fd 100644 --- a/modules/doc/public/css/module.less +++ b/modules/doc/public/css/module.less @@ -1,11 +1,3 @@ -// W3C Recommendation (except h4) -h1 { font-size: 2em !important; } -h2 { font-size: 1.5em !important; } -h3 { font-size: 1.17em !important; } -h4 { font-size: 1em !important; } -h5 { font-size: .83em !important; } -h6 { font-size: .75em !important; } - div.chapter { padding-left: 5px; } diff --git a/public/css/icinga/defaults.less b/public/css/icinga/defaults.less index 17fa67159..4c990d0e9 100644 --- a/public/css/icinga/defaults.less +++ b/public/css/icinga/defaults.less @@ -49,6 +49,48 @@ a:hover { text-decoration: underline; } +/* W3C Recommendation (except h4) */ +h1 { + font-size: 2em; + color: @colorTextDefault; + border-bottom: 2px solid @colorPetrol; +} + +h2 { + font-size: 1.5em; + color: @colorPetrol; +} + +h3 { + font-size: 1.17em; + color: @colorTextDefault; + border-bottom: 1px solid @colorPetrol; +} + +h4 { + font-size: 1em; + color: @colorPetrol; +} + +h5 { + font-size: .83em; + border-bottom: 1px solid @colorPetrol; +} + +h6 { + font-size: .75em; + color: @colorPetrol; +} + +h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { + text-decoration: none; + color: inherit; +} + +h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover { + text-decoration: underline; +} + #fontsize-calc { display: none; width: 1000em; diff --git a/public/css/icinga/layout-structure.less b/public/css/icinga/layout-structure.less index 907898d95..201f5c88a 100644 --- a/public/css/icinga/layout-structure.less +++ b/public/css/icinga/layout-structure.less @@ -124,12 +124,6 @@ html { z-index: 100; } -.controls h1 { - font-size: 1.5em; - margin-bottom: 0.2em; - border-bottom: 1px solid black; -} - .container .fake-controls { padding: 0; } @@ -152,13 +146,6 @@ html { margin-left: 1%; } -.dashboard > div.container h1, .container .content h1, .container .controls h1, .content h3 { - line-height: 2em; - font-size: 1em; - color: @colorTextDefault; - border-bottom: 2px solid @colorPetrol; -} - .content h3 { font-size: 0.9em; } @@ -167,24 +154,10 @@ html { margin-left: 1em; } -.container .controls h1 { - margin-left: 1em; - margin-right: 1em; -} - .container .controls .pagination { margin-left: 1.2em; } -.dashboard > div.container h1 a { - text-decoration: none; - color: inherit; -} - -.dashboard > div.container h1 a:hover { - text-decoration: underline; -} - .content { padding: 1em; } From 878aa81d987feb91dfb33d36c3163ef48d2eb43a Mon Sep 17 00:00:00 2001 From: Bernd Erk Date: Mon, 17 Nov 2014 15:52:04 +0100 Subject: [PATCH 04/61] Changes conf icon in menu --- library/Icinga/Web/Menu.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Web/Menu.php b/library/Icinga/Web/Menu.php index 4eae7525b..9fb74dbb8 100644 --- a/library/Icinga/Web/Menu.php +++ b/library/Icinga/Web/Menu.php @@ -212,7 +212,7 @@ class Menu implements RecursiveIterator )); $section = $this->add(t('System'), array( - 'icon' => 'conf-alt', + 'icon' => 'wrench', 'priority' => 200 )); $section->add(t('Configuration'), array( From e44086cb9f16815a6e1c1482242dc8ec441c0fb5 Mon Sep 17 00:00:00 2001 From: Bernd Erk Date: Mon, 17 Nov 2014 16:27:12 +0100 Subject: [PATCH 05/61] Fixes service and config icons --- modules/monitoring/application/controllers/ShowController.php | 4 ++-- .../application/views/scripts/command/renderform.phtml | 2 +- .../monitoring/application/views/scripts/list/comments.phtml | 2 +- .../monitoring/application/views/scripts/multi/service.phtml | 2 +- .../application/views/scripts/partials/command-form.phtml | 2 +- .../views/scripts/show/components/servicegroups.phtml | 2 +- modules/monitoring/configuration.php | 2 +- .../Monitoring/Web/Controller/MonitoredObjectController.php | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/monitoring/application/controllers/ShowController.php b/modules/monitoring/application/controllers/ShowController.php index 6c295e641..03c1d62fc 100644 --- a/modules/monitoring/application/controllers/ShowController.php +++ b/modules/monitoring/application/controllers/ShowController.php @@ -212,7 +212,7 @@ class Monitoring_ShowController extends Controller 'service', array( 'title' => 'Service', - 'icon' => 'service', + 'icon' => 'conf', 'url' => 'monitoring/show/service', 'urlParams' => $params, ) @@ -222,7 +222,7 @@ class Monitoring_ShowController extends Controller 'services', array( 'title' => 'Services', - 'icon' => 'service', + 'icon' => 'conf-alt', 'url' => 'monitoring/show/services', 'urlParams' => $params, ) diff --git a/modules/monitoring/application/views/scripts/command/renderform.phtml b/modules/monitoring/application/views/scripts/command/renderform.phtml index 0573f3420..9c8e79428 100644 --- a/modules/monitoring/application/views/scripts/command/renderform.phtml +++ b/modules/monitoring/application/views/scripts/command/renderform.phtml @@ -7,7 +7,7 @@ icon('host') ?> Host - icon('service') ?> Service + icon('conf') ?> Service diff --git a/modules/monitoring/application/views/scripts/list/comments.phtml b/modules/monitoring/application/views/scripts/list/comments.phtml index 8ab4994aa..feb5c9394 100644 --- a/modules/monitoring/application/views/scripts/list/comments.phtml +++ b/modules/monitoring/application/views/scripts/list/comments.phtml @@ -50,7 +50,7 @@ objecttype === 'service'): ?> - icon('service'); ?> href('monitoring/service/show', array( 'host' => $comment->host, 'service' => $comment->service, )); ?>"> diff --git a/modules/monitoring/application/views/scripts/multi/service.phtml b/modules/monitoring/application/views/scripts/multi/service.phtml index aede2689a..dc2e9f19e 100644 --- a/modules/monitoring/application/views/scripts/multi/service.phtml +++ b/modules/monitoring/application/views/scripts/multi/service.phtml @@ -45,7 +45,7 @@ $this->target = array( -

icon('service')?> Service Actions

+

icon('conf')?> Service Actions

diff --git a/modules/monitoring/application/views/scripts/partials/command-form.phtml b/modules/monitoring/application/views/scripts/partials/command-form.phtml index 4740f3348..16242605b 100644 --- a/modules/monitoring/application/views/scripts/partials/command-form.phtml +++ b/modules/monitoring/application/views/scripts/partials/command-form.phtml @@ -8,7 +8,7 @@ - + diff --git a/modules/monitoring/application/views/scripts/show/components/servicegroups.phtml b/modules/monitoring/application/views/scripts/show/components/servicegroups.phtml index db6aeceb9..181f194cb 100644 --- a/modules/monitoring/application/views/scripts/show/components/servicegroups.phtml +++ b/modules/monitoring/application/views/scripts/show/components/servicegroups.phtml @@ -12,7 +12,7 @@ foreach ($object->servicegroups as $name => $alias) { printf( "\n", $this->translate('Servicegroups'), - $this->icon('service'), + $this->icon('conf-alt'), implode(', ', $list) ); diff --git a/modules/monitoring/configuration.php b/modules/monitoring/configuration.php index 64d8cb2fd..bb5b646d6 100644 --- a/modules/monitoring/configuration.php +++ b/modules/monitoring/configuration.php @@ -124,7 +124,7 @@ $section->add($this->translate('Timeline'))->setUrl('monitoring/timeline'); * Reporting Section */ $section = $this->menuSection($this->translate('Reporting'), array( - 'icon' => 'chart-line', + 'icon' => 'service', 'priority' => 100 )); diff --git a/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php b/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php index c6b252d1c..82c70fc16 100644 --- a/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php +++ b/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php @@ -197,7 +197,7 @@ abstract class MonitoredObjectController extends Controller 'service', array( 'title' => 'Service', - 'icon' => 'service', + 'icon' => 'conf', 'url' => 'monitoring/service/show', 'urlParams' => $params ) @@ -207,7 +207,7 @@ abstract class MonitoredObjectController extends Controller 'services', array( 'title' => 'Services', - 'icon' => 'service', + 'icon' => 'conf-alt', 'url' => 'monitoring/show/services', 'urlParams' => $params ) From f83bcbfd2b6f7ae9a33da4a06e719e1eac88aad7 Mon Sep 17 00:00:00 2001 From: Bernd Erk Date: Mon, 17 Nov 2014 17:02:01 +0100 Subject: [PATCH 06/61] updates current font set and changes service and reporting icons --- .../fonts/fontanello-ifont/font/ifont.woff | Bin 16668 -> 0 bytes .../LICENSE.txt | 0 .../README.txt | 0 .../config.json | 72 +++++++++++++++++- .../css/animation.css | 0 .../css/ifont-codes.css | 19 ++++- .../css/ifont-embedded.css | 31 +++++--- .../css/ifont-ie7-codes.css | 19 ++++- .../css/ifont-ie7.css | 19 ++++- .../css/ifont.css | 31 +++++--- .../demo.html | 21 ++++- .../font/ifont.eot | Bin 27532 -> 29792 bytes .../font/ifont.svg | 17 ++++- .../font/ifont.ttf | Bin 27376 -> 29636 bytes .../fonts/fontello-ifont/font/ifont.woff | Bin 0 -> 18080 bytes library/Icinga/Web/StyleSheet.php | 2 +- .../controllers/ShowController.php | 4 +- .../views/scripts/list/hosts.phtml | 2 +- .../views/scripts/list/services.phtml | 2 +- .../show/components/servicegroups.phtml | 2 +- .../scripts/show/components/statusIcons.phtml | 2 +- .../views/scripts/show/history.phtml | 4 +- modules/monitoring/configuration.php | 2 +- .../Controller/MonitoredObjectController.php | 4 +- 24 files changed, 200 insertions(+), 53 deletions(-) delete mode 100644 application/fonts/fontanello-ifont/font/ifont.woff rename application/fonts/{fontanello-ifont => fontello-ifont}/LICENSE.txt (100%) rename application/fonts/{fontanello-ifont => fontello-ifont}/README.txt (100%) rename application/fonts/{fontanello-ifont => fontello-ifont}/config.json (90%) rename application/fonts/{fontanello-ifont => fontello-ifont}/css/animation.css (100%) rename application/fonts/{fontanello-ifont => fontello-ifont}/css/ifont-codes.css (87%) rename application/fonts/{fontanello-ifont => fontello-ifont}/css/ifont-embedded.css (52%) rename application/fonts/{fontanello-ifont => fontello-ifont}/css/ifont-ie7-codes.css (88%) rename application/fonts/{fontanello-ifont => fontello-ifont}/css/ifont-ie7.css (88%) rename application/fonts/{fontanello-ifont => fontello-ifont}/css/ifont.css (85%) rename application/fonts/{fontanello-ifont => fontello-ifont}/demo.html (91%) rename application/fonts/{fontanello-ifont => fontello-ifont}/font/ifont.eot (86%) rename application/fonts/{fontanello-ifont => fontello-ifont}/font/ifont.svg (88%) rename application/fonts/{fontanello-ifont => fontello-ifont}/font/ifont.ttf (86%) create mode 100644 application/fonts/fontello-ifont/font/ifont.woff diff --git a/application/fonts/fontanello-ifont/font/ifont.woff b/application/fonts/fontanello-ifont/font/ifont.woff deleted file mode 100644 index 6f08975f5b06c4a1995a8fa9bdc8a904707214ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16668 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

39%N7otxM5ailqiMPq+Y;PFOl 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 diff --git a/application/fonts/fontanello-ifont/LICENSE.txt b/application/fonts/fontello-ifont/LICENSE.txt similarity index 100% rename from application/fonts/fontanello-ifont/LICENSE.txt rename to application/fonts/fontello-ifont/LICENSE.txt diff --git a/application/fonts/fontanello-ifont/README.txt b/application/fonts/fontello-ifont/README.txt similarity index 100% rename from application/fonts/fontanello-ifont/README.txt rename to application/fonts/fontello-ifont/README.txt diff --git a/application/fonts/fontanello-ifont/config.json b/application/fonts/fontello-ifont/config.json similarity index 90% rename from application/fonts/fontanello-ifont/config.json rename to application/fonts/fontello-ifont/config.json index 6c1ea5415..6e2d2af3b 100644 --- a/application/fonts/fontanello-ifont/config.json +++ b/application/fonts/fontello-ifont/config.json @@ -48,6 +48,12 @@ "code": 59481, "src": "fontawesome" }, + { + "uid": "0d6ab6194c0eddda2b8c9cedf2ab248e", + "css": "attach", + "code": 59498, + "src": "fontawesome" + }, { "uid": "c1f1975c885aa9f3dad7810c53b82074", "css": "lock", @@ -144,6 +150,12 @@ "code": 59470, "src": "fontawesome" }, + { + "uid": "ecb97add13804c190456025e43ec003b", + "css": "keyboard", + "code": 59499, + "src": "fontawesome" + }, { "uid": "85528017f1e6053b2253785c31047f44", "css": "comment", @@ -234,15 +246,21 @@ "code": 59457, "src": "fontawesome" }, + { + "uid": "559647a6f430b3aeadbecd67194451dd", + "css": "menu", + "code": 59500, + "src": "fontawesome" + }, { "uid": "e99461abfef3923546da8d745372c995", - "css": "conf", + "css": "service", "code": 59456, "src": "fontawesome" }, { "uid": "98687378abd1faf8f6af97c254eb6cd6", - "css": "conf-alt", + "css": "services", "code": 59455, "src": "fontawesome" }, @@ -452,10 +470,16 @@ }, { "uid": "d407a4707f719b042ed2ad28d2619d7e", - "css": "service", + "css": "barchart", "code": 59420, "src": "fontawesome" }, + { + "uid": "cd4bfdae4dc89b175ff49330ce29611a", + "css": "wifi", + "code": 59501, + "src": "fontawesome" + }, { "uid": "500fc1f109021e4b1de4deda2f7ed399", "css": "host", @@ -480,6 +504,12 @@ "code": 59419, "src": "fontawesome" }, + { + "uid": "567e3e257f2cc8fba2c12bf691c9f2d8", + "css": "moon", + "code": 59502, + "src": "fontawesome" + }, { "uid": "8772331a9fec983cdb5d72902a6f9e0e", "css": "scissors", @@ -504,6 +534,24 @@ "code": 59414, "src": "fontawesome" }, + { + "uid": "266d5d9adf15a61800477a5acf9a4462", + "css": "chart-bar", + "code": 59505, + "src": "fontawesome" + }, + { + "uid": "7d1ca956f4181a023de4b9efbed92524", + "css": "chart-area", + "code": 59504, + "src": "fontawesome" + }, + { + "uid": "554ee96588a6c9ee632624cd051fe6fc", + "css": "chart-pie", + "code": 59503, + "src": "fontawesome" + }, { "uid": "ea2d9a8c51ca42b38ef0d2a07f16d9a7", "css": "chart-line", @@ -534,6 +582,18 @@ "code": 59412, "src": "fontawesome" }, + { + "uid": "0f444c61b0d2c9966016d7ddb12f5837", + "css": "beaker", + "code": 59506, + "src": "fontawesome" + }, + { + "uid": "ff70f7b3228702e0d590e60ed3b90bea", + "css": "magic", + "code": 59507, + "src": "fontawesome" + }, { "uid": "3ed68ae14e9cde775121954242a412b2", "css": "sort-name-up", @@ -558,6 +618,12 @@ "code": 59406, "src": "fontawesome" }, + { + "uid": "cda0cdcfd38f5f1d9255e722dad42012", + "css": "spinner", + "code": 59497, + "src": "fontawesome" + }, { "uid": "af95ef0ddda80a78828c62d386506433", "css": "cubes", diff --git a/application/fonts/fontanello-ifont/css/animation.css b/application/fonts/fontello-ifont/css/animation.css similarity index 100% rename from application/fonts/fontanello-ifont/css/animation.css rename to application/fonts/fontello-ifont/css/animation.css diff --git a/application/fonts/fontanello-ifont/css/ifont-codes.css b/application/fonts/fontello-ifont/css/ifont-codes.css similarity index 87% rename from application/fonts/fontanello-ifont/css/ifont-codes.css rename to application/fonts/fontello-ifont/css/ifont-codes.css index 48928d540..7bd25fd38 100644 --- a/application/fonts/fontanello-ifont/css/ifont-codes.css +++ b/application/fonts/fontello-ifont/css/ifont-codes.css @@ -27,7 +27,7 @@ .icon-globe:before { content: '\e819'; } /* '' */ .icon-cloud:before { content: '\e81a'; } /* '' */ .icon-flash:before { content: '\e81b'; } /* '' */ -.icon-service:before { content: '\e81c'; } /* '' */ +.icon-barchart:before { content: '\e81c'; } /* '' */ .icon-down-dir:before { content: '\e81d'; } /* '' */ .icon-up-dir:before { content: '\e81e'; } /* '' */ .icon-left-dir:before { content: '\e81f'; } /* '' */ @@ -62,8 +62,8 @@ .icon-calendar:before { content: '\e83c'; } /* '' */ .icon-wrench:before { content: '\e83d'; } /* '' */ .icon-sliders:before { content: '\e83e'; } /* '' */ -.icon-conf-alt:before { content: '\e83f'; } /* '' */ -.icon-conf:before { content: '\e840'; } /* '' */ +.icon-services:before { content: '\e83f'; } /* '' */ +.icon-service:before { content: '\e840'; } /* '' */ .icon-phone:before { content: '\e841'; } /* '' */ .icon-file-pdf:before { content: '\e842'; } /* '' */ .icon-file-word:before { content: '\e843'; } /* '' */ @@ -103,4 +103,15 @@ .icon-cw:before { content: '\e865'; } /* '' */ .icon-host:before { content: '\e866'; } /* '' */ .icon-thumbs-up:before { content: '\e867'; } /* '' */ -.icon-thumbs-down:before { content: '\e868'; } /* '' */ \ No newline at end of file +.icon-thumbs-down:before { content: '\e868'; } /* '' */ +.icon-spinner:before { content: '\e869'; } /* '' */ +.icon-attach:before { content: '\e86a'; } /* '' */ +.icon-keyboard:before { content: '\e86b'; } /* '' */ +.icon-menu:before { content: '\e86c'; } /* '' */ +.icon-wifi:before { content: '\e86d'; } /* '' */ +.icon-moon:before { content: '\e86e'; } /* '' */ +.icon-chart-pie:before { content: '\e86f'; } /* '' */ +.icon-chart-area:before { content: '\e870'; } /* '' */ +.icon-chart-bar:before { content: '\e871'; } /* '' */ +.icon-beaker:before { content: '\e872'; } /* '' */ +.icon-magic:before { content: '\e873'; } /* '' */ \ No newline at end of file diff --git a/application/fonts/fontanello-ifont/css/ifont-embedded.css b/application/fonts/fontello-ifont/css/ifont-embedded.css similarity index 52% rename from application/fonts/fontanello-ifont/css/ifont-embedded.css rename to application/fonts/fontello-ifont/css/ifont-embedded.css index e9100f644..593eb8bc0 100644 --- a/application/fonts/fontanello-ifont/css/ifont-embedded.css +++ b/application/fonts/fontello-ifont/css/ifont-embedded.css @@ -1,15 +1,15 @@ @font-face { font-family: 'ifont'; - src: url('../font/ifont.eot?86381425'); - src: url('../font/ifont.eot?86381425#iefix') format('embedded-opentype'), - url('../font/ifont.svg?86381425#ifont') format('svg'); + src: url('../font/ifont.eot?75097146'); + src: url('../font/ifont.eot?75097146#iefix') format('embedded-opentype'), + url('../font/ifont.svg?75097146#ifont') format('svg'); font-weight: normal; font-style: normal; } @font-face { font-family: 'ifont'; - src: url('data:application/octet-stream;base64,d09GRgABAAAAAEEcAA4AAAAAavAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABRAAAAEQAAABWPilJZmNtYXAAAAGIAAAAOgAAAUrQeRm3Y3Z0IAAAAcQAAAAKAAAACgAAAABmcGdtAAAB0AAABZQAAAtwiJCQWWdhc3AAAAdkAAAACAAAAAgAAAAQZ2x5ZgAAB2wAADMiAABSWGOGwx5oZWFkAAA6kAAAADUAAAA2BOzC6WhoZWEAADrIAAAAIAAAACQIbgTKaG10eAAAOugAAACMAAABqGu2AABsb2NhAAA7dAAAANYAAADWWp5Ghm1heHAAADxMAAAAIAAAACABIQ16bmFtZQAAPGwAAAF5AAACqcQUffhwb3N0AAA96AAAAskAAARfgjlOX3ByZXAAAEC0AAAAZQAAAHvdawOFeJxjYGTOY5zAwMrAwVTFtIeBgaEHQjM+YDBkZGJgYGJgZWbACgLSXFMYHF4wvMhgDvqfxRDFHMwwHSjMCJIDAO0EDA14nGNgYGBmgGAZBkYGEHAB8hjBfBYGDSDNBqQZGZgYGF5k/P8PUvCCAURLMELVAwEjG8OIBwDXjwcWAAAAAAAAAAAAAAAAAAB4nK1WaXMTRxCd1WHLNj6CDxI2gVnGcox2VpjLCBDG7EoW4BzylexCjl1Ldu6LT/wG/ZpekVSRb/y0vB4d2GAnVVQoSv2m9+1M9+ueXpPQksReWI+k3HwpprY2aWTnSUg3bFqO4kPZ2QspU0z+LoiCaLXUvu04JCISgap1hSWC2PfI0iTjQ48yWrYlvWpSbulJd9kaD+qt+vbT0FGO3QklNZuhQ+uRLanCqBJFMu2RkjYtw9VfSVrh5yvMfNUMJYLoJJLGm2EMj+Rn44xWGa3GdhxFkU2WG0WKRDM8iCKPslpin1wxQUD5oBlSXvk0onyEH5EVe5TTCnHJdprf9yU/6R3OvyTieouyJQf+QHZkB3unK/ki0toK46adbEehivB0fSfEI5uT6p/sUV7TaOB2RaYnzQiWyleQWPkJZfYPyWrhfMqXPBrVkoOcCFovc2Jf8g60HkdMiWsmyILujk6IoO6XnKHYY/q4+OO9XSwXIQTIOJb1jkq4EEYpYbOaJG0EOYiSskWV1HpHTJzyOi3iLWG/Tu3oS2e0Sag7MZ6th46tnKjkeDSp00ymTu2k5tGUBlFKOhM85tcBlB/RJK+2sZrEyqNpbDNjJJFQoIVzaSqIZSeWNAXRPJrRm7thmmvXokWaPFDPPXpPb26Fmzs9p+3AP2v8Z3UqpoO9MJ2eDshKfJp2uUnRun56hn8m8UPWAiqRLTbDlMVDtn4H5eVjS47CawNs957zK+h99kTIpIH4G/AeL9UpBUyFmFVQC9201rUsy9RqVotUZOq7IU0rX9ZpAk05Dn1jX8Y4/q+ZGUtMCd/vxOnZEZeeufYlyDSH3GZdj+Z1arFdgM5sz+k0y/Z9nebYfqDTPNvzOh1ha+t0lO2HOi2w/UinY2wvaEGT7jsEchGBXMAGEoGwdRAI20sIhK1CIGwXEQjbIgJhu4RA2H6MQNguIxC2l7Wsmn4qaRw7E8sARYgDoznuyGVuKldTyaUSrotGpzbkKXKrpKJ4Vv0rA/3ikTesgbVAukTW/IpJrnxUleOPrmh508S5Ao5Vf3tzXJ8TD2W/WPhT8L/amqqkV6x5ZHIVeSPQk+NE1yYVj67p8rmqR9f/i4oOa4F+A6UQC0VZlg2+mZDwUafTUA1c5RAzGzMP1/W6Zc3P4fybGCEL6H78NxQaC9yDTllJWe1gr9XXj2W5twflsCdYkmK+zOtb4YuMzEr7RWYpez7yecAVMCqVYasNXK3gzXsS85DpTfJMELcVZYOkjceZILGBYx4wb76TICRMXbWB2imcsIG8YMwp2O+EQ1RvlOVwe6F9Ho2Uf2tX7MgZFU0Q+G32Rtjrs1DyW6yBhCe/1NdAVSFNxbipgEsj5YZq8GFcrdtGMk6gr6jYDcuyig8fR9x3So5lIPlIEatHRz+tvUKd1Ln9yihu3zv9CIJBaWL+9r6Z4qCUd7WSZVZtA1O3GpVT15rDxasO3c2j7nvH2Sdy1jTddE/c9L6mVbeDg7lZEO3bHJSlTC6o68MOG6jLzaXQ6mVckt52DzAsMKDfoRUb/1f3cfg8V6oKo+NIvZ2oH6PPYgzyDzh/R/UF6OcxTLmGlOd7lxOfbtzD2TJdxV2sn+LfwKy15mbpGnBD0w2Yh6xaHbrKDXynBjo90tyO9BDwse4K8QBgE8Bi8InuWsbzKYDxfMYcH+Bz5jBoMofBFnMYbDNnDWCHOQx2mcNgjzkMvmDOOsCXzGEQModBxBwGT5gTADxlDoOvmMPga+Yw+IY59wG+ZQ6DmDkMEuYw2Nd0ayhzixd0F6htUBXowPQTFvewONRUGbK/44Vhf28Qs38wiKk/aro9pP7EC0P92SCm/mIQU3/VdGdI/Y0Xhvq7QUz9wyCmPtMvxnKZwV9GvkuFA8ouNp/z98T7B8IaQLYAAQAB//8AD3iclXwLYBzFlWC/6u/09PT8erpH0mg0H2lGHskjMZqPLMljWZYtIRsh27JjG2MMGGNkxyHEMV5iE4K9LM6yFnFIQoAASgxhWdgF2wTCZcNd4rAJyxI2e2uTvSROyGcNXAjJkhzxouZeVfdIMp9AwOru6qqueu/Vq/erV8N5OO6tP/JneC/n55q4Dm4RdyF3CfcR7pPcJGf1G3+9f+/Htl9+0fiKJb1dbc2xsFfwzG9riRiSnE5lsqVi2eoqmEEsZ91yBcvwtnpabgOn3AtO+d3aL4Q/3Z7W0/Zht56WWX08YR614oBXMzHnEa6YKVhx+673qoGtsx/OaXVuxZzO79hhYjGyA7uJg7Sd3qzttIX9L3NqSPN22p5e7Gf/3EagzLznOI7gHD3Kh3kNZ6iVUx7LpHRCcBoMKZ1MZUrFqmgV4qRQJV2FuMgbUipTRcj40KoldnTJKkELxTM9STHTvmJkpDMlp7pbY4YqHb/+kRuEPU/sHlgyOrok3j1Q7k7Vk2g8iv/MTLGn2gcn112PbcheTnrrrbcmhA5+FRfkClwvN8itRR4J9usXrx8fWlJdUEoYMpHmtwGbxUoRwYBKoSJFDHBAzCKI+JJUYRGUK4W4YAGFsljGuTOkPFSJKdIpzmTLpWLW7CpUwSpkZ5os39CzfH4/LBVyA8lMC0/2U8QGx0DQAgnETGrOD48tq5sXkNPdmURAh+mnx3eP4z84yOA/fh0sqeaXL9gwn29pSQ62CkuH3PpN/GB7+3fMevBFAqP2RQOjowNIie5ixozG6okZqFcJ0qJ7IEYme+kH4/Zv1l9PrvvaHunAv7XlYZBfPBqI+KJRcKtxrgDn6g/8JHmaEznpmMDB/DYRKhZYsNk+evcjcOs9Klxw79/DZ+512p7im8gvOS+2lQHbtshZOVvJVqyKJfNNd738yl0vv3zXKy/f9fKuL73yypdefpldOXece/hJvpF96+HxW4gkg+lgspQMdgX5SfvR0/ajcOFpeO60/QiMnYYL7Ued7ziOn4TnOB6/AwpfpZSMhPh9vzl9mlbN6TfIRTj18XDIp6kCj/0ngy7HBZNiBMcpQTAZhOfhqYH89OX5AfimfZR8ycb79OXk4enLOwYGOnjf1aev/sj05Wx0gcmaKeQjBfvOoqzx9avd7Y2mX5N4AZEv5kGKQxUq+KCDiQ9UMiQdSdCVtMzCIkgWTN70g5TqgEwFl78rQ+RIV4E8Y8RNEkoFPmMkQsSMRZclzDf/ma1d4Jcn1yZXAG8mvqaGzqpx9WzQo1qTpj6pmzAZ3eI3SLQ+Sgx/7eGWY2yZHjMTKxL4D1qt4FkVv7IiZ/0GmPpZjuHzKOKTZ/jM4/opPn3nNUb8XokwfDI6LsRCuYIPxMR7xF0PTDDGoZfWIfA8irMZmYkXXCWFJjD/BD6vauX0ZKrsexXx8UQnDf8kAjVphYMMtVCjjt8lDCPg3v/mGBUneIGm1tamOKwyXSTaHaQ4TkJcJvhv4dxIqAl6uSFuO7eLrvGP7dw0MtBXafapAkgUp3TK6CrwxUw2FcGHcESSTQq7jhjERctIp/KkVKyUMvSShyxiWrAK4XS5FCxmu6RI0GiJSNiIXwhdiGs2JZe6SqymK5LKUDp0FahQQGFhwoqN6zaPJ1OJpUsHPm9EPauWmmZ9ppDPmeSfM4PV5q2ZdGsRJkbL+fLv9xKyl4dVrQvShVhAAK/Ma5Gy8En+EiWhdHSm7P9o72+H9oGc2P0x+Gm6HVYuB7halqLWsi0+0bCCpq4aZmfTg3qib97GJG92LvTzvk3zR7dBvd1Rdx6Ml8LhLvvB8y7faUbjPe3NJwjwE7m4YS2dIM+eT9KJAnQOdEIB15BMaSk8hbTk8Zlq1jBncQNcuD9QiZtGKKBrqiIJhJNROFRKdMHL4N6ztTLS1OXylHNHWiLbLAJ2ofwRh0ZAZpDhipMnm1988Wf8Yrz/7GcvRvH2hz/8gV9jhM/qzfpZnvB4950NGxA1fhcNn/XFfWeN6O+MKCzc/sjGRZsvvdT+svuwZOPnNi66amLC3v2SkfLsU5R9APTqSRkvRZqVbafNlLpdkrZ7miOnt3lSFlsDE/xFiKvONXLt3EK6BkrzM0kzpNA1DYzrdUKhj0PYKUHKKVbeVonIzNQWqwAPH/jVwDXf/cUzO/mBX/3lez3vOrGbOIVdJ+C+zo5LMgMZkqu2XtLRaY9jMTuQyQxksXTynDqyH98OOZX05s7bo/wZ8m22ntOITYmrcmN03lYMLOwudrRlmsyAVyY4b7ikU1KclMN4p4u8bFXKKL38KLdklGHlSjnTUquCmTYzD4ZMBUGWKm+CivFkrqedtFYzH8Y/IV/ufGUBH6iP8d3JsuJtXzfi89TD2lxfK2nvztu3u23+4N7/4ULVePN3hnrh2IFvfPcbB8a+H8+xpmC6D6/9u14vaYF/59uTbSui+bZkf0utyafchwvd+08+szcY/MThrU/cPDp68xM1PfMosw/XoL4YoHqmZY75ZXWh8kAJZs0x2WrvGuGcd3hJltKzVp3FrLpI0pHdJn/GtbBK9s9LMxaYU5y1wUo55PpzqqGxsR3wzR0zIm779rj1HgVsek45F98e51wevgd5WOVSOOOjlIdX9Bea6/wiR3m4C1dhKY3LUAbDXZSIQtDBIxJE6Kk+DNPFmaaiPI0E4JEXIkxBhbHclU3LXfQe7gqTL17WKhFCAAT7P6Sjoi4fVRTfdlXZrqj4D35gP/mcLEqKpN64BBY+JyiSInr/+uNTufqb63P3Zm/Y8Cmy87p6D/GqqjS9TJKPiuIxT4TnFFVVpjl15MYCZFVJBNJ/Q8F+QVDRsCAD8Pu+vrGxvj74qD1J5/VcnAto9SPOg8XOGs4tsziL74nzuXjxNRrIUnaGCjUivA/SRJiDntchgMCDSwKNUaDLQdojf/IdOH+mt3dsrLcXrrEPkRtv7EL8RRGHckjwQ7+EjwNoR6Md+xDj5TxXRDu6s6PNIlREmai/qA7LZNHqsHCFErxksnmhXKEGLTM+Ci3IsnwQG5r8VGMu19gee+lHiYxgeAUtGjeCGzfXCfWqLijKYDOu+BbQ/gugMQfDP3r+B/BrXF1wEkvfCqnFqhFujqXMYCKmR33DqYF8f7zYsr2leKo9Nv1DYjxgfcFybP5vox2W5xajLlYeWzpQUCmsdM0YsoUQ44zIOp9Gkw81Lj6jUs0UF9FJQ/mJZkUpS63nJkhW0IamzEg9qyQ1qHk0e/a17FKNuHenImZSPXVDjd25uKps9QZ8pvLRxD5qBPn2Xeo1Y95L4dRmbywqKJfiW/v39p3bbpuAHjSaNg983BszvTtlIRrS4XVb06OGouzSwnHvJxdtMOIGHLlUjRvqpZfiQOqlR0wojmzbRnlPmvE5Hf3YwLWhxYG2RqWztckKOLqR2hpoY2bxrwUNBZhjCVpJxwfMuuWKW561FAsm6YWt9h0nSd/0Cbji1CmIm/qbm5nNw9/Lbu9Z6h8+OXRqaPrMIfbmkB9dFGBWomNkmRBgN/rKRPn41h9RPkZRZxgoH4MytcNNGYJUwNM1UwriukGAeL8naP/alGW/Oqnavw6Fo+QZizxsBexf25dZKu+dVP3gh3BgPuXTaexzPa7NVsanhXafwOZeJzjVFUS4bFqma3JRvw+VURa9KGoN4MjoNlWCbJ7XD15z70Nf3jnCb1gZ7QuElGi5r31s654t4xm+rxxV0n3Wyg32nah7gPLnpg/dvWtwcNfdH9p6tIptrb7gvD1LeiZW5PMrJnoGd+dCPZ1KaOFxGLbvoPwPW/HK8Qz/v8W5XMldyn0U/YUdV1y8piLxjA48akM6KdSiRSBLKB3QqC9naveK81BEh3UR8w6rxIqw+XM/lSwTS+VKuJw1RcnEmafGTwZnnlpHM2XaUuY/a2p3qP0t09NtY37dh6tfACHki4pEEGRVM3kQCFF9aj0vEBSuHlGSvCLayBEZ/nZeu3a70Vq0G/yaqC8hfCAuPCBAZPpJIimwWtGJRhTZfljWSQ+vyLAaV56Xp28UTSBDiVZbbu6EvvaWlN8ni7ogSfWRvohkej0+o2qIURzfpw9EBMOjyd6gaqghKvJA7G+1pYEMBP3ZkE4yvrASlFXQpGZ2PeY+a6Aqrrw+w3ynKK6Ybiqv5yca6gyfTOW1iL4fFVVplFaMPKheTVwY5XBXVgzW1ga9BJ0Fg3KMmpAReBhefwl14clDqmxfywaDg7I6+dWv0rDK9EvIU/a/MlVLLsFmmvKLgHkhbI1bZ6aaZwG0P/PVV+2DrNn6RIS8yp4el7FxMcrJb51FHnmZ2VUj3DpuK/cx7gbuJmpX7f/UDdd+eNuWi9de2N0gUHsYhbEOeVK2RJPZv9kWXEimrDP5ls1UKNt0FSyc9WwmS1+hrZgps3dxsEy5CVoc21gWkU0y6ZSMXGKiw1IFVtKBlsJWCUVlVqZDpJsAsmJEbiJIELGC48kkyvymkFB/DBoCYnBIDsv2J6sCrxCh3DEytqKzSxbK+ZGV+YyoDA6iDM2vHMmXBd6s67hgbCTfzSO3VOFT+NlQUAxMX1Ufm1+s5CJ46+qeVzc/Vm/O6+7CWyRX+UI5pLT7QfAA7CnDHUP26vWigALQDy8O2T+5HCTYZMYYNKmfeFuVZkF4oYXE6tvGGjvaO5bm8BZSxNZ5ohzsaBzLJfvM9o7G0faGBr7lBVFo9mS1C6IjsaQRHY4n7Y/HRiwjSS9wbVJGzVWvExz4xhAsbn6tvyTysgj+o+lfXEAICxO4csjLafA/4P9xoafgJ/ANdHFupyIchTedrjgwix1XLzV9C1Uo0SmyMlWyCKRMyZCLGamUF6gfg/Iqk6Kt5XI2I5fR6csTnD/JQF8XbWbZWdJUteEDTh42on+FDNIyTdd51qww38fsMovZAmsgWbQx9o6OZDmTxo5pGZ1u5IWUlJJMGRnE7AB8Ru4pWllJLmAXJbTXLfxaNmXKQcglcpwYFVPG7/DLbEYyu2hHTQhRRWri0SKQaIclbIVAZNHH7UI2Qw8A3Xi5EBeaeBqcoHK5kmLrCrmxXMJe8ILQFTPoBpcRXcTLkCLpMrJfGd/LyJE8Fd60nKXI0ZhApgPMMvaEEJuVOEHylCumRSMjmVK2RLU78wGzBWyRQmiq0GWyW8UsoyhFVyRNy7gAyoUSkoQvVzKojGi/9J8fELUIUgyfJUr1TDlDaV+WIjhFeaiwlYQ1liGZ8PCup6+55ukz390pXfcNCIHCo1zlg5Ewrn1B43HWBEFFYw0UZFVBEIgggUQUjyiIIg+KBmJMRrNPQe4gsocXUCYT/ArFn4hazdDDaN8CASJ6CIQ9+LUoqbwiyCJPJA/2JXoEkeeJKIAue/1CgMdOBYWCoeBoPMpyISTymgbYSKtr4HlFDIu8V/B5cSBJUASPsLIgiERCaKIqwiAKCIQAzDxUZTkkyB5c2ALRsUxwPRDiR88VnWYRBFUF7EHUZMIrvEc2JUlUlIBgYD/YOa/zAqiiElQJtWxRz4BKeA0XPxCEjyeyF8chisGjVU8o3miU4h3fCVHewyMEvI/olB4CVkkIBKFYyYooa0hJQhB9BomM1xBVX6JGPKjEFKQWtlY9Ps9V16wEDXzYQwSwE54CoiECIqiAIyD4Ks4RoepGoxgKXj8QD9Z5d514+cQudrF/DAqRcPoUXvSCho1QpCPOSFsgkiZKvAo4w0CxRDIDJZdEkPYoqWRBUlRZECVRo5yBlZoH6SIiEnyQ8Los4XveQ2SVl0AXVOxRRMRUQZZl8IiKrCCdeEpO5AiV53Ui4kCiIBPURH4kIkHkdWzAyzyyGsD8C5HXcA4lv4rzi2ymewwvAamegIXw8KLB8wEktKCIigBeSxcpQoKm6IIOqteQFRCR7DgRIV4VBDQDCK9SImsk4AkjUgJCoqKioPOJJA+IfpEgN3qR4gKdOd2jix5A1iR0BgUeF4pI/CqdV6QA8p+F9gXOgJ+oKnphvOD1iJRBcBKwJWVaZCz8HDHEMrIQ4CwT2xdZg/OLg/uBrgfkDYLkoJ0StG10idBWjLOQJmJMCXp0j0aEgIw26Ftv/VHo5KklLR3TmY/uaHxqK2aoRYy+C71EDDkOQsfeDdNTV94GY/3wwO51h1LZcu+4Nbzp++v3wuFtI9fF/Z7dD2wZTY/35tLBXTQG8Jb91gS8gf0nsH9DcG1cKY1yqxJ2FXO4CswzNGSeamN4VZXsH8gBxaOSnS8SUcX5v5royuNenWz+sYjUNL2+6et04AMKfLsbZMUH/6KoOhLGtsuEE2fiDrP7Uv5+bTndh0o3hL28OL+t8rZ9oHeUg065FHz3cvht5UnmjbLLybmP8g5ZZZdT79ogX3tQ+4/RJ3r5K/ub9BEG8Prc9Bn6TKJ4BfPNZ2iBL+OVq8XjSR/8mtORtiqjbc3frnky6llvzHvWi4bR6+iGfE/HZ/wXo+4HnXv8vhe+53xPnLlHAzAPtShyr+G3NfToNBYbVv+OujJxL437et3x4Uqyl/Ph9162jxA0nOGZqoUrjISHNY5FyTr08kyvC4777WKyj43tnYWdUrQKODYsVhmg2F6FTbqLhAOLE1v6T/5rZB7znRjsHmryuUNbHgcBg/87+zIE3b7M693ojavQCq3emLbRC5P25V4vfAnfbfR67RfwNTaIsX7/J9nFL2H9+mv9UpQqnlrn2C+ZwC5pR15otV9wO79bhavsS1X1YkQS5tGRvBerdOyYu3fyNbJstl+0FlPZmc7dfvm/oz3ZL2CfTu93077u9m7fiAwwzz6lqu5ITrcuvLfX4KU+pIeYjJJZt1tKBvI3Myh6KS2wA4o4eRBHOoWPCCbcozodX6zGa7G7/eQ/uTj2W++dw1tBZ7ehFJTPAZ3fH8lFeiNHWpuG4rkjRp+Ri0Rgu9GHlwgUYyYWj9jXNjZDJgYHj0RYY6yK2J8z3VjhzXyJ/NoZz+EHGWrMlHRDhsnszBTwJQM/7YnkTPMrtN/mRjj4FROH6TFxWOiJG/ZtBgLRF/lKLo4gwZEIg8n+nDEz3nocrxHHCzP82A6L9U7i+dnG0frmRvtaF27aM+zAkShScBCR2uQi3eZWUMwoKEdanbG+z+9HeURxC8/iVuPWJhobo5s5kWCFDYm0ZLjZn4tE5uH9CGLQmDuCI+cicCPFDGm7w+g15znj56A95gI3E3fdgOMtwfHaPXQ8GQ27WlSVutRZmZpptRBrE1SyjiyuyT8/WoLZDHuUIywgkSXPPv30WGC+EThredTgSizQbTC6GdQeHMOSV5dl09TPWmFaXBkMY52Jwl7WvaQZ60Ph6FndtCL005XBiIVNo+EQ+5L30Kr5AVoTmE8rPAg9mcEjynVyymPzk4ZCHD6klr6bJkCFhUM1oBsANJrlMg0NYrEcgfvEr4+php/tW8W8Y1+XdKlfhOMonNxn8cmVrN4EURG/vlKNsw0uKmuwgbRIgv8zp6BLbgvO3V//Or+K5zmLwdjeFGYwIi9l3gYKSzdwYaeEp7FBcwb2hxGylV8XA+IiSfr6GMo6JAjcN/toxNWVFFgEpgfLxLPySVHsx/bYAqUkXCVLzpM+p9bhBcf3H0Re6ArOytmFkKZhvVmF0QuldGSu+G5ku2w1FmVQR2gsnnHoGe8hb9w4NYwyfRIFxySCOXwKdcMh75wKlDZzKqgU/yDt5vY8o+f4MyQ4x4ao4ZB8G8TJc+GbPmFQ2CiIBuk7F4pzRq6NxugFn0Z60bFiGrhx0yBNTJhDKhoxcffSTDho6kNDlEEYJZCTaHfE43RO7sHZo3DUMHPhwH/MT34L52eK97E9o6Wc+vjCjly2XuEdHsqm3fyVyuz2x8weCLXMatvewMhAN0dJVUCPk8Z5UfvL+5wgyz4WbtmnKjTugoXh2579vHDof98CqVyf8dSWT4wd3tZP+nYcOnLL1d380qcicJvzFQ3pOF/to6bHPrXuysPk88/cLt1CA3mRp5ZWJ2798qGdPcLA1s9f8IktT0U4F6dH0PcPcB4uhHipjycsTUVXBXEqZoHmaKChnkmjUy8bLXQPj6cwkx912het2FC9eqww/QO4b/nG1beMAfkRi0NevYwM7Lr7kbt298PmDSP2xkJh7Jqr4L7C2K1jF1207t5rsHr3Xcfv2FOVRnbcz51DVz9Kj/MQhnkNJpp+NbrOCfe+Lw3tbzLqwcAHpRsj2PuTiuZLPEKqvMYFuCx3EcK4rpqIaIxOLBJbzNDlV6ash0CSlE5ko4mYVleZxbIqhoxvqNns/klpnaBrjh9Sy5395QnbKOTjBO7UNJ30NdJ5jJXb12WqK1asqGYgEwwOy59UhiRTygwtqEsl+Hpdr1Oa67z5QqenvhnkOl2vJ6lEXU9hbNu2baNlEqR91MXUgBrKNbYO5qPR/GDrgvZQeM3KlWukerF9wYcWNbRXG/1Nht8faQz4fPWxuhhJWLF6ny/QGPH7jSZ/rD8XW/ShyuZqM2nt2TIbM7oE5b3BJbk80qOtpSkaqM3ZrHleWwE01YOnqUGVWhwJKQWvq8pRh1nlZkU9s+rT998yRsZvfvCmtZ+oxSJef/J6kjpLLXNscQIbP7v60+Nk7NCXD2HLT6/+uOvb7jrBYqf/yk+RV7gwehIruA/T2Om2lUPFXDTI9qiDTNDPZKTRDZMw6iaJZTNVebq9Ql0pi8UYZyoqdAaLLE7FXKxzKmnAu0r37DMsQllrwFTEk4fZBsLhJ1GgnerMih4ULpoZCAhKVA6qguH3iNnOyc0XKBIqs0jCOy+fn+dNRAy/rIxuuvXQblmmOrmuzlg6SkaGjDohxJtGQJZ3HyKHpu+lUutJUz+JYzypGvb/yo34eSOgBTQt1hzTJF3R8GveP5JbczjBmygyA574hm0b4p4AylCTT9669oYXClhh+DRd77r9wdu7dJ2XeJ+BlV0nXX2Jl/3kUUZP5TFKRvJnkvGDE+LPwanmzzzMYJOOBWv+zNvhesfw7xzFyYV6lFf51Ry1wpYjLw8vrc6TAXk5LFM2rgI1x4DtHaayMgrFcoUaM2xvm+1q60DzfahrXMpk59jaVBVnqcVoFcwvdEdphHf3M9tGmuLlSt+Vh8FIhODIXxzymyQUtO+kwejA5LKFh8SAkJck8giaEHnxh/Z9E+cv2AhLFvRUh9iG3VAcOp4ZGtkG3nLs8Db33d6v+UZM6oKZI3LmkIQfBgTyKLsvte+HxpEJujXK9kYfJfsR1yzXhXN6Xnu96tpAFJE40HyFPA1PltDpZ0gi2mahzKw3Mxs06I4pIhQHsv/IdZNscPtOdpv8i/vRZjMB5S7B++S2z28Fuov4vbnA+b6214V422EX+O/ZPx/ZRnYMUyDJVsdO+yPa+ydQG/QjjH0xw9kXk11bqDbD1ChD76Lm71eosVwFi05PEBdsOlXM0OCr+9Ikn/Pa/4pK3c2JQs0OHd4Tm5YcRTVAo4SgKEdbilBuPi6phNTeLNlErRD7eTQVphymmaIMhC8es/cs2aQqXo/kkxX8DG7GrwWiCO6bTVwNl+3k20hvhku7LrOcTpOlkKRnoxJoZNNXCLUkBw1UHAXUA3NQdrJiXZThClKDDuFX1LeBTyRCJIpszEQLE3HFVYC45klI1D0CbFoCN58Dub3HgRza3x3TWh7BFPINjysuzQ1R2VrMNll+mdB9KSsZTNItKZwHCdeKScPbLW8rV2byCl3FYHU5hqvzxIykIT705qunUClTrYAXeEhV0vQZL6faY2++Srckh4stzS3Fk+XmNIKNztaFpG/7FG107qV9ukRbk39uzJXZXn3ZveU4tDRm8ZnN3WrgmhC3Lq7C9bJI1Me4dH9i8+rlg9W+nu5ysaM1lYjH6qNzc7v8iDua3vQvO+cOb7vzJcaQNP/ARD+nDHPaV9w6SqdK1wek09TUd44e/U7tCnceO3by6FF4aGrq5LFjJ2pbi/R6J3t1cmoq9EEoOTU11Xz06NHmqekTU2fppfkodE6xzqbYBmAG66amts959afIzGTrbv5etBMUtBSondBUF/JK1G6q1NImW2biKnFoQTsJstSSqhRM5t9HLGcv6KSbJAkT9n501nvRq95rjsPtWsONF1JRklhW5/F8ZQfJLU/61Vpi5Fl7v2EsROcb9lbGf2y2LN8Eh5+/lRgBKSRv2tdH6uYbKudh8p/KG36GC2gkcglyudVvLB1c3F+t5DONsbpoxFAF4Dw0JpkutczmPtHFuQhoYgy+p3ee+eKuO4Dz5vjms+nyNKkmjO1OnICDdIXSLAP9jB3ft49fb1+xj2YjBFhOQoAFA92cBB0W79tnx/uHhobdT+jrk0NDEB8enj4xNET21z6jV/vF2nc0r2HIaebkZVwjdPDn45yEENtPcI9z/0XzMn76rftuuryrLhLACaJ53jT3jcp+kc6URZ94lg6HcyY7eYsynSOcMZoDIdGtJBZnzTIdSK0havtmaE6jQ6ByBY0o+pJuqpXRsGKSD5WkhcraQquYdUn31YAGMpitzPIrsDeUlk6XGRb5qLCIN3ZJV0SF8gjrgAIUnPttJsu+fc9Py4VzvoXX3Zzxh9u724GmTLj3FxRxraSFmwTBN+CVxP6IKcmCb5uk+sLWgOCTxgSxWfHJa0QFG8pe2lAbVCWpPxyVZJ42BF/YHBB94kohGlR8EraEK1ZLaowMghhp9GpeuZ2HQb5RlVevltVGvhgAIacEgzFLIEtIzIOv3dY5hbUW3tFYU7XZ1rDJyVb/eWM7aW3CJUrW46U3l/uXKxEYPWw1tEiaEBwQCl6pr8GnSGskrSAIy/2iqLRrUdMHivz2lqrSV89aes9zWsYjvoawRhT7+6Mexa8v0glpbWgB8BahlRAs+xXPqMcT8NGauKeImrbVgiyt8gU8pAvrnK+ytEorZp2PPPiRMvsRdjrzkTITa1KRf7ehTl2ZkOg5CSf9Epm05VzezL4rbzp86DCnk3D7PszJhBHjTdK7as8qsnbXWogp8jbVG26VRP+YT5YvqKv3yEJgr6IFGqwLpYC0zBREpVX1K1tRzariNkW3Wpy2ygXReo/CB/eiBPXHzDHRLw8bgtCre7aiZHVnbg+tDcQjDQW0BCNjIPb5lBWxgCpf6dH6RKk/Luo4Zf5Ygx80mbWtq0/MlzXZGHOa+hWFNRWXxLDpBawh5+wj8SGUyWNoOyckdx+JWfB5oHvs1JWhhGGGPPN/uigF0M+OE5rIi64t0qGEjhAjUIXmJqHtSGmF//MhTfIuKHYFYs1Kb7lt+Pb2hrCqKILMQ2NTTO/0K4JqSIYhk4CSyMSBF0DP7VwBIdEryWo8ntDkQJQsDmtZntzt79RjiZig8hGjof324bZyzAqEErq/WOzWJPS/W9XWuJ9EA4o3VZ9SRMXLm3DBzpxGRB7irXFQAqTFK4VVNGAUpvNpvlWYq0c9v4G7hNvJ/QV3AxfpD+37xO6P7Lzs4otGK8kG5oIhQ8UhUkupcbNpLDSS6dZ6OMgEeTIIbMPNMmUj7UobR2AV3RwWlCuUldCWptzEtttpJj3ylw5hySoz8qYWQraY5fGBEp/uM2bS6GRU+K6AGbemQ87RhtfNsn/kB6L8D9LTZ2i2zmp4KNSYTKwKehQAvrlhReoTm9cUFBm9OCKW84qI1M4YPkWRgppPVkW0EeUm+7fxjsbWUx6ZUh1tXHnZitUgedpi/kQANuv9uQaFkOsDxej09WxUfi/ezEDmBwH5H+Q3HyF9ceulN++H5XpQaPAFgETMkC95mG6SSrrVXY8yDToWrViWXxszFa2eB3Mwe5H9W99yswC/tQqCQUyeWtaaYv9N3C8qLQs7q02yHoDZXNXZ+VlJbcxsszMfwgebj3CEpqgiyUtd1E/HZzSwIl00+4FuY2b5NO8841ddpfchcG9247phAej+OiHD6y/KfhXnxC2uXLSSuDvllcIHoNjrvfYk+L26R9TBEOzfwkd7e3/v1TUNbXLotJ/3KYKm6d7f974HHRa2/Fl0qESoYVklcpdBE0vStJitOLTQYYYAWLTk96HCA1/K9fA4w+ggCKSv7SuZ7Tsyd81bgN4CkoKXenNfzkx8+P0psL+3d4OgUkYRBH5Db+/td/f2rsd1DaIkr6dF92zKLN5daIGtpnbJyGBPMZ9x8Jc+IB848cJG92RaSZx9pqZI19vL70ODSZotR41n+1r0Se6sPc19qyofgAt+7saxVGX9rI8zOfvIaPAok83Ofngv0uBKSoNLVvT3lc9z9sQlJ9gxd0/bep9yOJgMGnFAmlQBulD9pSVZZIE619nIBtO1kB0VXF1UsNP9mPi7wnnIxQIdjGFbUxQCzxNFsQ+ebRDERyUBXlGVcrHF7kSvokTbPZT1tJtHzXYl+zDS73H7KUa7xYx27/5sbyHB6d9ohqoa5IrFKLzE1Tji9G/ygwN5EmZAXByJQdy4WK3t7UywMx0WtxBtgp6Ul6M2AYtbIyood1HFWyyenQeay5ZOUUnrGOSZcgr1P01LXUTNgWIVEjQ4ec3Tu2Ds/E6/r37N0mhTNoVlsudbcMNNv7o5m9v52YZmXkEDRSC8JvgM2QjI/nVb4KZfQeBXN5G9owdWVK+ZFysX5qf7Irw4euD2A6P2i5ce2SxcmpFFzQNEFf2ibiqxWDhXODyONZuPsD2NqxgeGdTNKWcvdwZYicGaORdWehwU+DMzQKk0i+ZcmMYOfGPLzb+6CTY5wysCaCoQReDnAnD+gc3dCIFDy0cYDC3ccqTl+eWUk5M+l2gldNFKi0hZRiFTcWhWcAKjzA5o4pnplXGzN1nIrEq1HD2wOnF8e2dh2ZpIA5E0mijF84D2iS4sHYWJ4yePT5wcGxQ1pcEjiAKPZFIaImuWFTq/cHUiuOHIwNIV4Bseh/suOLDCc54l0nMPggC8hJ3ExWgo0LprCZJ+xYEfLdmd1U016eVFiSKrgiBa53lG+EJH8aaRtlx2D+f6pw6uEVxrm9E/3Xh+2vRw/FzeqXEOFBHRQpxQm/JP0AHejwKGBAfXfH4t9JXK4bC/Lt6WW3PbunW3rZn42jay4+iO96YNKb8fXcbI3p4tC+avjSfyXjUkKT1brt7aPbziwF03jsKfINf0rj9Nqr/a7dJqgj/Br+Y0lM8DSKty0vCpNAdcLLLgb4pGNwotyUzQ2QKJBEQqYugGCd0TK1UFN1OpCk6OkmXEeZj2JDsh1NPqsW8hJz9XX1y1Y1WxntyfazyLRvDZxlws39kcIgeuEhPtCXHiRjATxdxmpTPp8czrgb99AObF+rpTqe6+mH3qgcYcms69ucZoYXzTTReOHw6oXrRZUxGvGjg8PnrzxrWdNVnh4EHz7lvDqkTejsOfAzf80weE9YNA58YModPVAcpjKPJp/LN2HL92fD7Ms2hhJstn3OPxszGBoN91+v1g+I/p5h37WBhgHw0lkKq9moUU4GF2tIETaEyYn2LnNDRcB+xsX2c8HMBhndheif7Phk7COWd20zMnXWuBjq6go3lZbjaNVJ2kZ0bg9fVmwr6T7K+dcNWkfQlz+owZZxuX/W3NiQhca5X9a/xRSM+vypMnTybM9fa1zjFdIRA8g27Renqga70mnWnvB+g0E1F9TaBsTlYRB5HFWX+BONBzrQu4KjdM88iW9Pf1xMKaQjgRCVjJIkQRmhgrmShDw5HZOBsaERbbNM5m0kk3ApsslBeyhF2TtyBdAjnr7P8b8Fr/mv4SRDyeE54Q/jVvWmJ30kgsPJ+Oe3i5QVF9GlN+5WZ4vqUoNivRypR9cIp8pGuqK9AeWBP4x8VrFjeV4XCtC/ubE04HA5tAF8JSDIWzq0DLzctk7EGByXvtg/dCvohdBMYD7TNn9jq4dtQVrdGZXBW2A62jercMdEzQ23V2FivlZC1+zJ/x2j+nmV77KmvXVrtTBs1wDUqCIvFD8Q1waJ+R8ECjF37tV+0XvchKUije2b+huykjoFDRVFE3+Hsu/sjyn02yCPGL3rlnCPNcG8KTlplf6ScoKOlPA1CbvJgX2VbDTMoOPROYQI/xzJAko/AJKSjyeCPVXV27tkJhQCC9CAcFFA5tiP/s4nt8QfQeNUU0+ExT94b+znhIQhi8aKfEVbwY/smfLZ/5LYUzfIkzuB5cQ10xn7uGWH6MMzyagLJkWCJ6tPSAAE1vLFMn4ZxGFraigaEr2KEeB6Bg+4+9Xn5zqD6maIKXR4UQXd28+6KIIjF6ITQBK/Krqzb9IUuP/LiwBcNW9ifemPe/EuPLlgVMFLL+0xtb2+Vb5rZRPdZn/TsuZbL2j6iX9nFBLoWWsPp4Z7YBiUn1UiZL94/pL0JUqLZN0IOnckqKoH1XZhuQZREREBLNNJxRbgcBCTy15obU4ecPp25Ys/ynIPzU/nrAu2xLwAwMdnoD8EPvqP2G/R/2G6Ne7ygokAFl1As9Bxb3LKGR1SU9iw9cc/PNcD423bJU00lI7RwMPBsOf+qOOz4Vzhg33EHuvt5waP6P/AUs1tuINLd8Mo3LhFmcl5RreVROMJBamMiIZ90TsWSNYb9q9hr2RyPxXONLjcMRmDTIuniOZPqbpU77h/GI/WoEX0aGG8805gCLH424OukfhWZ3zCLSaX6Kjsu/z7gWfUmFJ5SLtCr9AcA5hSCYjUZ9AKQIHX64cR+riLwfnI3sZSCI3/XSqrgDPV0vf2R7cWmaa8bOlDmWe821YcdpUY66WXw0+GpFyAXMw2BHdhJmkO62Gf5m3aRRS7gvbtnfZL9oAANmAo5deRu59Som+6nmOeaMibJeQ9tOOtZsubl0rl5BgjGZfQ4MSab2+ClTx0FW7VkFpbnjw7U0oB50w8y942Rs4Y5zYdhBcytm9BqhuXUy02tRTaA2ehgHoPFl8e2IuyeGj0EjQ+35c3Gmrtp9O9iAU+cMt/W227buiLvjvcF/lnyHC3AFHC9dr9f2r7NpdH3p9Ac9YFaYJUfTO9PUhyw7G7du4gI7e8+HTP3kJN0Rg8X4/96UKBNZtK+3r8dPxbRARPhMqDN8M0sPvk4k0Gr/3m/CyZNGAHWKYr8BzfNE4GHA/ia2nScGBBj1+6/5MPV2fr5V1Gs6fyvLO8zTvfa0OaPzkzP7nXN+TMeiR3P5OSYBMwGuMAL2z9lUpNPsRmFO+8052wVbhlgFvZ50bqZuP2WSj29nj9sdm4DRjixAu9jP5Gcp5uVdeLJzbRBD59n5xBkwWK5ESnbDYHl2jCtO4KCu3OTRdc9Niv5IIJqpj1hxWtBGcslYcVnUaJVVWb5IIcL6B+dvGM5/Dhujj8KusDReTCVCqq/TpwbA8NbnV4X9qc7mgF7wCMukgHJbqmct5+5tO3lECpdEmOu8EpvvP5kztH8mS6i9512zhG583ywqKoN+gB2+jON2svyBxZWkKlAfYiH60BXTktJ8iZIhQjdCWQ4nleCoGnE6Zank/JZGJt1SfkdtOoVsKmd+GYs2LRm68Je/XLxrbWFV30ZDe5meInnZF0IPYU3/7vHCOH46uOptFfV1idTD6vjCDDzzcGF8d3/PeDGgeW4VPTwq2kmP5i8DAFYs6h2/uaXsxypJESRCblU0fwnUNY5Of4h/iPwU/Wr3d26QzwJUPVaoSxNAkSR3ydmuKhDjwVdfffDQzmXjl11//PjZ4+TQE0/sJa+Rn75mP/TaupG+48Ad//u9zz57/8s1/Sxci/wuOjZuED0atMEj9FdtKD91ANsVlLNsMYKb3ypc+98Hh/gzhjpo3yPp0o1ntsMyegd+iUfx/Rcy0TC/4c1XyRO/01QPbSPd+NIObOK0MFXHhxE+wnI9LG4RzlWx0QorzN9DpeAa/VmrUJSpwKXOABp8qCsyTuLiub6AxXwBekyXvyL1l+0xdAJWwSGPJ9EZ6iHrBOm/X8Gl3iFI27zULzDgxgkhno+DsHSi8WUqBK79p6uZS9BzaQgcH4Hfh+/fvFYkYkkKCOtD4Xe6Cupw8Rmsd+OEDBcNcck6Z/uX5jPxIDplguvQlFyHxkODBSwrbcYly1aS+GeGrQ+AIBlkSKGP9u/wkrV1pGttoR7IV12UV8P9G9PV1GMd74fyjCsEIXjgvH6gXtupsw4Nhq/6QuWfyBfLH5AAc/NlaV64obLzKjRpl/rdcrpUoVmfdPOGGvb0zv9bJHJ69fqL3tz2zBXPLK2/aP346UhfKzFP7z9t9qDK74ucHl9/Uf1SrL3S3rB+9elIrsf86Y2nI45/8W20xx7lPOj7VrlB7kPUv1i9fMlAORXWJMe/QHFHbTLzHQZZxYhINRuTZvpBbafJovKR7qHILIcqTClOT3yn2eZUlh3Rg3JbZzeg6bYJJuaYbc/0vtwbE1V50FM3dlPB61375hcKhSZR5XVvsxc8kXXnf0k46zWz4z/aO+/a7y5dfHG6dFnCe9WF6YmF1KK7Fa48x577uABX2RuuKniykirnmvdcEMyF9t+ulj2SZEgg2tOjN8Sgrv7icLh5/uaJEfXAVVv6FzVvKYZR7tpvneDL5A322zDKY6bfQ+2+RRBsqWRClXLFohiBKJsEccuyMIj85C77/67bJezecouwZXidAF8GgxY330ouw+Laa27ZZf8osPY6GNuzJbA1MLzuLJzFov3InsuMbbS4cReb/xMom95gsinkyiaLSqM80J1rlL0WNfICZbj9gVeF65544lYBBdPx67eNLtt56IHXXiNvnLn/uef2PnTcPt63Yt1rMP4a5/rDfxQ6mO5r4nJoO9Az2G0tiVhYov5wxXEZWT4qjZ6iQcGOYJeCzpFs6HK1dqUkFoptkDK6zrQUiy3kEubNTU9qErmE/aLFlKySt9YXW97c31wGXGKe9R7PzcUWOEib29di8xfnnNUGbfr1MjN0yuVQqJa3toGdFa9yO1GWbVk+PyzxLLeCnrdFL50mLqaL5SzecO3T360hTpYRTZJGxwCFaqmYRZ1Nf5ItQ4+WzmSoyu7PumRm48h0K6tKmEqnG/TIuZNOWhfZ3x47UYZURdcNyxf3efWoamqGGgrJph7TYmT3+Uu2k4ChNqqeUHSoQYxAcvPocHnb0sUa+5WNLxoLEjGfZkbNWMdIa8NlPWtnfqoLxtCOTlyTqBTBPzAS9WWCeiDhCasa2HcSSVIkMu9if8CTaw3Fsr5mBQqRwryQ0ZbRtO620Q31lpVrhCviOd/5ubg+sMKMNI8u7uoen4lnrWe+wyL2mwaXn1+qY/QLz6FfmkXtykX2q3WUGLiOUTk7JBSdbdECozAu9FIXNZDMiBMrzfMs/jeb5eWG1hthJhN4hoDRkKJBo2oESPm8ofN3B3zyvJCqhEIeE/8LGHzcZxm6Xm6GIpyItQ+N917WkF2Rj5lhU9LVhuQC44uUjlPa4uGJnkWjm5MQERvIuhoR7efCRTXly8ZCrTlPwN+RnyeJRBMI2HeoRigRiEPGFx0Z8JfLSOn2hgVrUZINXNAcCZU7875Y2/m+XByuaMyZdVHYsJxv6/Z5M21GaN7/B/cLqJoAAHicY2BkYGAAYtlAbvV4fpuvDNzML4AiDBe6ruyB0Kt6/v/8n8mynzkYyOVgYAKJAgBNTg01AAAAeJxjYGRgYA76n8UQxcrKwPD/A8t+BqAICsgCAHeIBUF4nHVOwRGAIAwDhQFYwBU87/w5CQO4ggM4SQdwEidhAAewtBUqp49cAmnT9MmYPiMY40ZkQEzCLXDOe+QoO+ntFQ4yA2oucr69+N0tDLsy6O9UDJIRG61u20N5wHlF7+IH1iVHQzqRF5obz1/6BnWGH19y6S5UzjvUEbUbkLGf2yrK/izeWLvcuig76AAAAAAA0gESAagBvgHcAfgCCAI2Ap4DBAOqBCAEhgUQBYIF/AZ2BswHOgegB8oIIAjUCTIKDgziDRINTA3ADeAOAA4eDj4Oag6WDsIO7g8mD14PlA/MEDAQghDSETQRahGiEgwSThKgEygTchQaFGgUjhUEFVYVvBYgFogXPBeOGAYZZhoGGoIbUhvWHFIc1B1wHdQeFh6MHyIfhh/WIA4gcCDqITIheCHYIjIibCLKIwQjQiN6I9AkGCRyJK4lHCVIJYQl6iZqJqAnLidqJ5Yn6iiKKSwAAAABAAAAagH4AA8AAAAAAAIAAAAQAHMAAAA0C3AAAAAAeJx1kstOwkAYhc9wM0J0oYkbN7PRQEzKJbhhhSHCwoUJCzauCpS2pHTIdCDhBXwHH8DX8lk8nY6CC9vM9Dvnv8w/SQFc4QsCxfPIVbBAlargEs4wcFym/+S4Qh47rqKBF8c1qpnjOh7w5riBa7yzg6icU63x4VigLsqOS7gUF47L9G8dV8h3jqu4EW3HNfrPjuuYiVfHDdyLz5HaHnQcRkY2Ry3Z63T7cn6Qilac+on0dyZSOpNDuVKpCZJEeQu1iXMxDcJd4mvLdpsFOotVKrtex+pJkAbaN8Ey75jtw54xK7nSaiPHrpfcarUOFsaLjNkO2u3TMzCCwhYHaMQIEcFAokm3xW8PHXTRJ82ZIZlZZMVI4SOh42PHishGMuoh14oqpRswIyF7WHDfsOonMmUsZGXCen3iH2nGjLxjbLXkFB5nOcYnjKc2x7cnLX9nzLBn7x5dw+x8Gm1Pl/xB/s4lee88tqazoO/Z2xu6A7T5/nOPb3wUeQEAAAB4nG2T95fUNhDH93trr+29QoeQUBNCQjGQhBRqQgsBQkkoCR1ZHtu6lS0/Sb69u78eybsH/IDfW+kz82Y0o/lqBwuD2TcefP5bHQywgCEChBghQowEYyxiCctYwTZsxw7sxC7sxh7sxT58gf34El/hAA7iEA7jCI7ia3yDY/gWx/EdvscJnMQpnEaKMziLc/gBP+InnMfP+AW/4jdcwEVcwmVcwVX8jj9wDddxAzdxC3/iNv7CHdzFPfyN+3iAh3iEf/AvHuMJnuIZ/sP/eI4XeIlXeI03eIt3YMjAkYNQoEQFgdUkZ6bKFNN50BnSoV/MgpqMOGs4yaCVnQlr0XRmqVAyJ51S3dqNOFfTRiqWj7rWb8NS2JB3GZk4Z5ZlzFBYsq6kyAhLNWuXjNI2bVhNadeufDT8OUlNJWsr1dAw68rQMjMxo0JIS3qoiiLIlJqELTOWYsOFcckmLKXKKORSdXlYSHeHyDW+Jjj1naW50K4zv8WSCush0aKsZtSHqJaa8cznMXLhfk/6eE/+gEyU8zxHs6M89Ac42KbJiE1Ki07KlEm7+Im9NGdTMymDWq3RjrmnUlpsqsYyuZW/RtoKzmS0qVSdiibMpOKTuLdUZxPpW8g6mfkb80mypmTXT3JxTr6h8Zz9yOrO0rAWPKImt6KmxFimracVV8Y52ZaQW+ZoqqnhboxSOJVNzFVT+CsFHsJendhpQmmbF0kPU6XzcU+07p6KGwpPLa3b0GqnxzJXdU2NnZWJ5lbAK2bHfpn5g4ykjP3iay0za12QUI23wlYLl0G5sFGh9NS90VBTKzeSfnUhckgbNLSsDNzPLPvR9Mr57OSDFXgKKlVTIJpCBRXJdmSIaV7F7um0rWjKkaapaHLfmXuZUrjL9k25Wa5swbxj948oI1fXu8ZOP15R3kla4FNXw9jEVl2dGa/NnLw2g8F7qFBQcwAAAHicY/DewXAiKGIjI2Nf5AbGnRwMHAzJBRsZWJ02MjBoQWgOFHonAwMDJzKLmcFlowpjR2DEBoeOiI3MKS4b1UC8XRwNDIwsDh3JIREgJZFAsJGBR2sH4//WDSy9G5kYXAAH0yK4AAAA') format('woff'), - url('data:application/octet-stream;base64,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BjYGFQ4BFS4BNx4BFxYHBgcGFxQGFgGtdMZycsboyG4GerwBEgEIAwECBAMRFRMKAQwEDAMBBwYEBAoFBgQBCAEGAQQEBAIEBgEGAggJBQQFBQMBCAwBBRwHAgIBCAEOAQIHCQMEBAEEAgMBBwoCBAUNBAIUDhMECAYBAgECBQkCARMJAgQGBQYKAwgEBwUDAgYJBAYBBQkEBQMDAgUEAQ4HCw8EEAMDAQgECAEIAwEIBAQEAwMEAgQSBQMMDAEDAwIMGRsDAwgFEwUDCwQNCwEEAgYECAQJBFEyBAUCBgUDARgKAQIHBQQDBAQEAQIBAQECCgcHEgQHCQQDCAQCDgEBAgIOAgQCAg8IAwQDAgMFAQQKCgEECAQFDAcCAwgDCQcWBgYFCAgQBBQKAQIEAgYDDgMEAQoFCBEKAgICAgEFAgQBCgIDDAMCCAECCAMBAwIHCwQBAgIIFAMICgECAQQCAwUCAQIBBAECAgQYAwkDAQEBAw0CDgQCAwEEAwUCBggEAgIBCAQEBwgFBwwEBAICAgYBBQQDAgMFBwQDAhIBBAICBQwCCQICCggFCQIIBAIKCQ0JaXJRAQwBDQEEAxUBAwUCAwICAQUMCAMEBQEKAQMBAQQIBAoBBwYCCgIEAQwBAQICBAsPAQIJCgEDC3TE6sR0dMTqxHT+3QEIAgYGAQQIAwULAQwCAgQMAQoHAgMEAgQBAgYMBQYDCgEGBAEBAgICAQMDAgEDCAQCBgIDAwQFBAYHBAYICgcEBQYFDAMBAgQCAQMMCQ4DBAUHCAUDEQIDDgcGDAMBAwkCBwoDBgEOBAoEAQIFAgIGCgQHBwcBCQUIBwgDAgcDAgQCBgIEBQoDAw4CBQEBAgUEBwIBCggPAQMCAgcEAw4DAgQDBwMGBAQBAS1PBAEIBAMEBg8KAgYEBQQFDgkUCwIBBhoCARcFBAYDBRQDAxAFAgEECAUIBAELFw4FDAICBAQMCA4EDgEKCxQHCAEFAw0CAQIBEgMKBAQJBQYCAwoDAgMFDAIQCRMDAwQEBgIECgcOAQUCBAEEAgIQBQ8FAgUDAgsCCAQEAgIEGA4JDgUJAQQGAQIDAQEBBAMGBwYFAg8KAQQBAgMBAgMIBRcEAggIAwQPAgoKBQECAwQLCQUCAgICBgIKBwYFBAQEAwEECgQGAQcCAQcGBQMEAQEBBQQC/g0VVQIC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AVwBXQFeAV8BYAFhAWIBYwFkAWUBZgFnAWgBaQFqCWRhc2hib2FyZAR1c2VyBXVzZXJzAm9rBmNhbmNlbARwbHVzBW1pbnVzDGZvbGRlci1lbXB0eQhkb3dubG9hZAZ1cGxvYWQDZ2l0BWN1YmVzCGRhdGFiYXNlBWdhdWdlB3NpdGVtYXAMc29ydC1uYW1lLXVwDnNvcnQtbmFtZS1kb3duCW1lZ2FwaG9uZQNidWcFdGFza3MGZmlsdGVyA29mZgRib29rBXBhc3RlCHNjaXNzb3JzBWdsb2JlBWNsb3VkBWZsYXNoB3NlcnZpY2UIZG93bi1kaXIGdXAtZGlyCGxlZnQtZGlyCXJpZ2h0LWRpcglkb3duLW9wZW4KcmlnaHQtb3Blbgd1cC1vcGVuCWxlZnQtb3BlbgZ1cC1iaWcJcmlnaHQtYmlnCGxlZnQtYmlnCGRvd24tYmlnD3Jlc2l6ZS1mdWxsLWFsdAtyZXNpemUtZnVsbAxyZXNpemUtc21hbGwEbW92ZRFyZXNpemUtaG9yaXpvbnRhbA9yZXNpemUtdmVydGljYWwHem9vbS1pbgVibG9jawh6b29tLW91dAlsaWdodGJ1bGIFY2xvY2sJdm9sdW1lLXVwC3ZvbHVtZS1kb3duCnZvbHVtZS1vZmYEbXV0ZQNtaWMHZW5kdGltZQlzdGFydHRpbWUOY2FsZW5kYXItZW1wdHkIY2FsZW5kYXIGd3JlbmNoB3NsaWRlcnMIY29uZi1hbHQEY29uZgVwaG9uZQhmaWxlLXBkZglmaWxlLXdvcmQKZmlsZS1leGNlbAhkb2MtdGV4dAV0cmFzaA1jb21tZW50LWVtcHR5B2NvbW1lbnQEY2hhdApjaGF0LWVtcHR5BGJlbGwIYmVsbC1hbHQNYXR0ZW50aW9uLWFsdAVwcmludARlZGl0B2ZvcndhcmQFcmVwbHkJcmVwbHktYWxsA2V5ZQN0YWcEdGFncw1sb2NrLW9wZW4tYWx0CWxvY2stb3BlbgRsb2NrBGhvbWUEaW5mbwRoZWxwBnNlYXJjaAhmbGFwcGluZwZyZXdpbmQKY2hhcnQtbGluZQhiZWxsLW9mZg5iZWxsLW9mZi1lbXB0eQRwbHVnB2V5ZS1vZmYKcmVzY2hlZHVsZQJjdwRob3N0CXRodW1icy11cAt0aHVtYnMtZG93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') format('truetype'); + src: url('data:application/octet-stream;base64,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') format('woff'), + url('data:application/octet-stream;base64,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BjYGFQ4BFS4BNx4BFxYHBgcGFxQGFgGtdMZycsboyG4GerwBEgEIAwECBAMRFRMKAQwEDAMBBwYEBAoFBgQBCAEGAQQEBAIEBgEGAggJBQQFBQMBCAwBBRwHAgIBCAEOAQIHCQMEBAEEAgMBBwoCBAUNBAIUDhMECAYBAgECBQkCARMJAgQGBQYKAwgEBwUDAgYJBAYBBQkEBQMDAgUEAQ4HCw8EEAMDAQgECAEIAwEIBAQEAwMEAgQSBQMMDAEDAwIMGRsDAwgFEwUDCwQNCwEEAgYECAQJBFEyBAUCBgUDARgKAQIHBQQDBAQEAQIBAQECCgcHEgQHCQQDCAQCDgEBAgIOAgQCAg8IAwQDAgMFAQQKCgEECAQFDAcCAwgDCQcWBgYFCAgQBBQKAQIEAgYDDgMEAQoFCBEKAgICAgEFAgQBCgIDDAMCCAECCAMBAwIHCwQBAgIIFAMICgECAQQCAwUCAQIBBAECAgQYAwkDAQEBAw0CDgQCAwEEAwUCBggEAgIBCAQEBwgFBwwEBAICAgYBBQQDAgMFBwQDAhIBBAICBQwCCQICCggFCQIIBAIKCQ0JaXJRAQwBDQEEAxUBAwUCAwICAQUMCAMEBQEKAQMBAQQIBAoBBwYCCgIEAQwBAQICBAsPAQIJCgEDC3TE6sR0dMTqxHT+3QEIAgYGAQQIAwULAQwCAgQMAQoHAgMEAgQBAgYMBQYDCgEGBAEBAgICAQMDAgEDCAQCBgIDAwQFBAYHBAYICgcEBQYFDAMBAgQCAQMMCQ4DBAUHCAUDEQIDDgcGDAMBAwkCBwoDBgEOBAoEAQIFAgIGCgQHBwcBCQUIBwgDAgcDAgQCBgIEBQoDAw4CBQEBAgUEBwIBCggPAQMCAgcEAw4DAgQDBwMGBAQBAS1PBAEIBAMEBg8KAgYEBQQFDgkUCwIBBhoCARcFBAYDBRQDAxAFAgEECAUIBAELFw4FDAICBAQMCA4EDgEKCxQHCAEFAw0CAQIBEgMKBAQJBQYCAwoDAgMFDAIQCRMDAwQEBgIECgcOAQUCBAEEAgIQBQ8FAgUDAgsCCAQEAgIEGA4JDgUJAQQGAQIDAQEBBAMGBwYFAg8KAQQBAgMBAgMIBRcEAggIAwQPAgoKBQECAwQLCQUCAgICBgIKBwYFBAQEAwEECgQGAQcCAQcGBQMEAQEBBQQC/g0VVQIC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aQBmAG8AbgB0AEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AaAB0AHQAcAA6AC8ALwBmAG8AbgB0AGUAbABsAG8ALgBjAG8AbQAAAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHUAAAECAQMBBAEFAQYBBwEIAQkBCgELAQwBDQEOAQ8BEAERARIBEwEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEBIgEjASQBJQEmAScBKAEpASoBKwEsAS0BLgEvATABMQEyATMBNAE1ATYBNwE4ATkBOgE7ATwBPQE+AT8BQAFBAUIBQwFEAUUBRgFHAUgBSQFKAUsBTAFNAU4BTwFQAVEBUgFTAVQBVQFWAVcBWAFZAVoBWwFcAV0BXgFfAWABYQFiAWMBZAFlAWYBZwFoAWkBagFrAWwBbQFuAW8BcAFxAXIBcwF0AXUJZGFzaGJvYXJkBHVzZXIFdXNlcnMCb2sGY2FuY2VsBHBsdXMFbWludXMMZm9sZGVyLWVtcHR5CGRvd25sb2FkBnVwbG9hZANnaXQFY3ViZXMIZGF0YWJhc2UFZ2F1Z2UHc2l0ZW1hcAxzb3J0LW5hbWUtdXAOc29ydC1uYW1lLWRvd24JbWVnYXBob25lA2J1ZwV0YXNrcwZmaWx0ZXIDb2ZmBGJvb2sFcGFzdGUIc2Npc3NvcnMFZ2xvYmUFY2xvdWQFZmxhc2gIYmFyY2hhcnQIZG93bi1kaXIGdXAtZGlyCGxlZnQtZGlyCXJpZ2h0LWRpcglkb3duLW9wZW4KcmlnaHQtb3Blbgd1cC1vcGVuCWxlZnQtb3BlbgZ1cC1iaWcJcmlnaHQtYmlnCGxlZnQtYmlnCGRvd24tYmlnD3Jlc2l6ZS1mdWxsLWFsdAtyZXNpemUtZnVsbAxyZXNpemUtc21hbGwEbW92ZRFyZXNpemUtaG9yaXpvbnRhbA9yZXNpemUtdmVydGljYWwHem9vbS1pbgVibG9jawh6b29tLW91dAlsaWdodGJ1bGIFY2xvY2sJdm9sdW1lLXVwC3ZvbHVtZS1kb3duCnZvbHVtZS1vZmYEbXV0ZQNtaWMHZW5kdGltZQlzdGFydHRp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JSAuRyNHI2EgsAQjQrAJQysgsGBQWCCwQFFYswIgAyAbswImAxpZQkIjIEewBEOwAmIgsABQWLBAYFlmsAFjYCCwASsgiophILACQ2BkI7ADQ2FkUFiwAkNhG7ADQ2BZsAMlsAJiILAAUFiwQGBZZrABY2GwAiVGYTgjIDwjOBshICBGI0ewASsjYTghWbErARQrLbBCLLA1Ky6xKwEUKy2wQyywNishIyAgPLAEI0IjOLErARQrsARDLrArKy2wRCywABUgR7AAI0KyAAEBFRQTLrAxKi2wRSywABUgR7AAI0KyAAEBFRQTLrAxKi2wRiyxAAEUE7AyKi2wRyywNCotsEgssAAWRSMgLiBGiiNhOLErARQrLbBJLLAII0KwSCstsEossgAAQSstsEsssgABQSstsEwssgEAQSstsE0ssgEBQSstsE4ssgAAQistsE8ssgABQistsFAssgEAQistsFEssgEBQistsFIssgAAPistsFMssgABPistsFQssgEAPistsFUssgEBPistsFYssgAAQCstsFcssgABQCstsFgssgEAQCstsFkssgEBQCstsFossgAAQystsFsssgABQystsFwssgEAQystsF0ssgEBQystsF4ssgAAPystsF8ssgABPystsGAssgEAPystsGEssgEBPystsGIssDcrLrErARQrLbBjLLA3K7A7Ky2wZCywNyuwPCstsGUssAAWsDcrsD0rLbBmLLA4Ky6xKwEUKy2wZyywOCuwOystsGgssDgrsDwrLbBpLLA4K7A9Ky2waiywOSsusSsBFCstsGsssDkrsDsrLbBsLLA5K7A8Ky2wbSywOSuwPSstsG4ssDorLrErARQrLbBvLLA6K7A7Ky2wcCywOiuwPCstsHEssDorsD0rLbByLLMJBAIDRVghGyMhWUIrsAhlsAMkUHiwARUwLQBLuADIUlixAQGOWbABuQgACABjcLEABUKxAAAqsQAFQrEACCqxAAVCsQAIKrEABUK5AAAACSqxAAVCuQAAAAkqsQMARLEkAYhRWLBAiFixA2REsSYBiFFYugiAAAEEQIhjVFixAwBEWVlZWbEADCq4Af+FsASNsQIARAA=') format('truetype'); } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ @@ -17,7 +17,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'ifont'; - src: url('../font/ifont.svg?86381425#ifont') format('svg'); + src: url('../font/ifont.svg?75097146#ifont') format('svg'); } } */ @@ -80,7 +80,7 @@ .icon-globe:before { content: '\e819'; } /* '' */ .icon-cloud:before { content: '\e81a'; } /* '' */ .icon-flash:before { content: '\e81b'; } /* '' */ -.icon-service:before { content: '\e81c'; } /* '' */ +.icon-barchart:before { content: '\e81c'; } /* '' */ .icon-down-dir:before { content: '\e81d'; } /* '' */ .icon-up-dir:before { content: '\e81e'; } /* '' */ .icon-left-dir:before { content: '\e81f'; } /* '' */ @@ -115,8 +115,8 @@ .icon-calendar:before { content: '\e83c'; } /* '' */ .icon-wrench:before { content: '\e83d'; } /* '' */ .icon-sliders:before { content: '\e83e'; } /* '' */ -.icon-conf-alt:before { content: '\e83f'; } /* '' */ -.icon-conf:before { content: '\e840'; } /* '' */ +.icon-services:before { content: '\e83f'; } /* '' */ +.icon-service:before { content: '\e840'; } /* '' */ .icon-phone:before { content: '\e841'; } /* '' */ .icon-file-pdf:before { content: '\e842'; } /* '' */ .icon-file-word:before { content: '\e843'; } /* '' */ @@ -156,4 +156,15 @@ .icon-cw:before { content: '\e865'; } /* '' */ .icon-host:before { content: '\e866'; } /* '' */ .icon-thumbs-up:before { content: '\e867'; } /* '' */ -.icon-thumbs-down:before { content: '\e868'; } /* '' */ \ No newline at end of file +.icon-thumbs-down:before { content: '\e868'; } /* '' */ +.icon-spinner:before { content: '\e869'; } /* '' */ +.icon-attach:before { content: '\e86a'; } /* '' */ +.icon-keyboard:before { content: '\e86b'; } /* '' */ +.icon-menu:before { content: '\e86c'; } /* '' */ +.icon-wifi:before { content: '\e86d'; } /* '' */ +.icon-moon:before { content: '\e86e'; } /* '' */ +.icon-chart-pie:before { content: '\e86f'; } /* '' */ +.icon-chart-area:before { content: '\e870'; } /* '' */ +.icon-chart-bar:before { content: '\e871'; } /* '' */ +.icon-beaker:before { content: '\e872'; } /* '' */ +.icon-magic:before { content: '\e873'; } /* '' */ \ No newline at end of file diff --git a/application/fonts/fontanello-ifont/css/ifont-ie7-codes.css b/application/fonts/fontello-ifont/css/ifont-ie7-codes.css similarity index 88% rename from application/fonts/fontanello-ifont/css/ifont-ie7-codes.css rename to application/fonts/fontello-ifont/css/ifont-ie7-codes.css index 6f2625302..130f0e414 100644 --- a/application/fonts/fontanello-ifont/css/ifont-ie7-codes.css +++ b/application/fonts/fontello-ifont/css/ifont-ie7-codes.css @@ -27,7 +27,7 @@ .icon-globe { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-flash { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-service { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-barchart { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-down-dir { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-up-dir { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-left-dir { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -62,8 +62,8 @@ .icon-calendar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-wrench { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-sliders { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-conf-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-conf { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-services { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-service { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-phone { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-file-pdf { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-file-word { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -103,4 +103,15 @@ .icon-cw { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-host { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-thumbs-up { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-thumbs-down { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file +.icon-thumbs-down { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-spinner { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-attach { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-keyboard { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-wifi { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-moon { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-chart-pie { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-chart-area { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-chart-bar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file diff --git a/application/fonts/fontanello-ifont/css/ifont-ie7.css b/application/fonts/fontello-ifont/css/ifont-ie7.css similarity index 88% rename from application/fonts/fontanello-ifont/css/ifont-ie7.css rename to application/fonts/fontello-ifont/css/ifont-ie7.css index 750f9ef0c..4e6ee83dd 100644 --- a/application/fonts/fontanello-ifont/css/ifont-ie7.css +++ b/application/fonts/fontello-ifont/css/ifont-ie7.css @@ -38,7 +38,7 @@ .icon-globe { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-cloud { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-flash { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-service { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-barchart { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-down-dir { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-up-dir { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-left-dir { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -73,8 +73,8 @@ .icon-calendar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-wrench { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-sliders { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-conf-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-conf { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-services { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-service { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-phone { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-file-pdf { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-file-word { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } @@ -114,4 +114,15 @@ .icon-cw { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-host { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-thumbs-up { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-thumbs-down { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file +.icon-thumbs-down { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-spinner { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-attach { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-keyboard { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-wifi { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-moon { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-chart-pie { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-chart-area { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-chart-bar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file diff --git a/application/fonts/fontanello-ifont/css/ifont.css b/application/fonts/fontello-ifont/css/ifont.css similarity index 85% rename from application/fonts/fontanello-ifont/css/ifont.css rename to application/fonts/fontello-ifont/css/ifont.css index 66ddcc17b..546dffff1 100644 --- a/application/fonts/fontanello-ifont/css/ifont.css +++ b/application/fonts/fontello-ifont/css/ifont.css @@ -1,10 +1,10 @@ @font-face { font-family: 'ifont'; - src: url('../font/ifont.eot?81676749'); - src: url('../font/ifont.eot?81676749#iefix') format('embedded-opentype'), - url('../font/ifont.woff?81676749') format('woff'), - url('../font/ifont.ttf?81676749') format('truetype'), - url('../font/ifont.svg?81676749#ifont') format('svg'); + src: url('../font/ifont.eot?81587324'); + src: url('../font/ifont.eot?81587324#iefix') format('embedded-opentype'), + url('../font/ifont.woff?81587324') format('woff'), + url('../font/ifont.ttf?81587324') format('truetype'), + url('../font/ifont.svg?81587324#ifont') format('svg'); font-weight: normal; font-style: normal; } @@ -14,7 +14,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'ifont'; - src: url('../font/ifont.svg?81676749#ifont') format('svg'); + src: url('../font/ifont.svg?81587324#ifont') format('svg'); } } */ @@ -78,7 +78,7 @@ .icon-globe:before { content: '\e819'; } /* '' */ .icon-cloud:before { content: '\e81a'; } /* '' */ .icon-flash:before { content: '\e81b'; } /* '' */ -.icon-service:before { content: '\e81c'; } /* '' */ +.icon-barchart:before { content: '\e81c'; } /* '' */ .icon-down-dir:before { content: '\e81d'; } /* '' */ .icon-up-dir:before { content: '\e81e'; } /* '' */ .icon-left-dir:before { content: '\e81f'; } /* '' */ @@ -113,8 +113,8 @@ .icon-calendar:before { content: '\e83c'; } /* '' */ .icon-wrench:before { content: '\e83d'; } /* '' */ .icon-sliders:before { content: '\e83e'; } /* '' */ -.icon-conf-alt:before { content: '\e83f'; } /* '' */ -.icon-conf:before { content: '\e840'; } /* '' */ +.icon-services:before { content: '\e83f'; } /* '' */ +.icon-service:before { content: '\e840'; } /* '' */ .icon-phone:before { content: '\e841'; } /* '' */ .icon-file-pdf:before { content: '\e842'; } /* '' */ .icon-file-word:before { content: '\e843'; } /* '' */ @@ -154,4 +154,15 @@ .icon-cw:before { content: '\e865'; } /* '' */ .icon-host:before { content: '\e866'; } /* '' */ .icon-thumbs-up:before { content: '\e867'; } /* '' */ -.icon-thumbs-down:before { content: '\e868'; } /* '' */ \ No newline at end of file +.icon-thumbs-down:before { content: '\e868'; } /* '' */ +.icon-spinner:before { content: '\e869'; } /* '' */ +.icon-attach:before { content: '\e86a'; } /* '' */ +.icon-keyboard:before { content: '\e86b'; } /* '' */ +.icon-menu:before { content: '\e86c'; } /* '' */ +.icon-wifi:before { content: '\e86d'; } /* '' */ +.icon-moon:before { content: '\e86e'; } /* '' */ +.icon-chart-pie:before { content: '\e86f'; } /* '' */ +.icon-chart-area:before { content: '\e870'; } /* '' */ +.icon-chart-bar:before { content: '\e871'; } /* '' */ +.icon-beaker:before { content: '\e872'; } /* '' */ +.icon-magic:before { content: '\e873'; } /* '' */ \ No newline at end of file diff --git a/application/fonts/fontanello-ifont/demo.html b/application/fonts/fontello-ifont/demo.html similarity index 91% rename from application/fonts/fontanello-ifont/demo.html rename to application/fonts/fontello-ifont/demo.html index b9c5d327f..c9a06c6dc 100644 --- a/application/fonts/fontanello-ifont/demo.html +++ b/application/fonts/fontello-ifont/demo.html @@ -297,7 +297,7 @@ body {

icon-flash0xe81b
-
icon-service0xe81c
+
icon-barchart0xe81c
icon-down-dir0xe81d
icon-up-dir0xe81e
icon-left-dir0xe81f
@@ -348,10 +348,10 @@ body {
icon-calendar0xe83c
icon-wrench0xe83d
icon-sliders0xe83e
-
icon-conf-alt0xe83f
+
icon-services0xe83f
-
icon-conf0xe840
+
icon-service0xe840
icon-phone0xe841
icon-file-pdf0xe842
icon-file-word0xe843
@@ -412,6 +412,21 @@ body {
icon-thumbs-down0xe868
+
icon-spinner0xe869
+
icon-attach0xe86a
+
icon-keyboard0xe86b
+
+
+
icon-menu0xe86c
+
icon-wifi0xe86d
+
icon-moon0xe86e
+
icon-chart-pie0xe86f
+
+
+
icon-chart-area0xe870
+
icon-chart-bar0xe871
+
icon-beaker0xe872
+
icon-magic0xe873
diff --git a/application/fonts/fontanello-ifont/font/ifont.eot b/application/fonts/fontello-ifont/font/ifont.eot similarity index 86% rename from application/fonts/fontanello-ifont/font/ifont.eot rename to application/fonts/fontello-ifont/font/ifont.eot index b8cec1252b14496b097bd6e4754a4ce26e628cae..22e4b3011f8ff281f33728b734dd0af553b9fb70 100644 GIT binary patch delta 2655 zcma)8eN0=|6~E^``}qUn53nC317km%kJ!c#WBgDcjzJ6@nr0C=2_+O_z+ehCu5Cin z2DwX9M5{C;Ls6ox%ZQR`otBSftg19kUH`D6eMD1KF`7x6nnjHkP1U}VP5TIso%c*S zru{SP-FwgZopbIv_nvd__32OG{v%+IWC+Qn&#`_*X8!!CbHS zZT)}{Xvfwyd^BT49DieXu+xqv$Kvy6&%S{CJwghSW079Mxl!$45i#SBnUt zX9?+hEf$T8DE=n467nMI5Pu8-bwcq=JaQ}v?kyPL5jXPIL?j-~nP&fv{9bhOo#a$H^KkNw`-BW3rnr+#MU%goVBR1k zEjf6V05h|A8g@f^@eZ^?dRa$jda~;E_4QlKVa7w$#7MRgJ8_dn5+I$#94zW+ZE0$# zb5`@^r6xlGOVzcmN)zj$elJ&IVtEe)fCD6|0^pU24MYbX@LK?NQ3sVJ9hs<>tR*9J zeVd1RgZ0@zJ6md~yU8Pd*B|mz?_MwMaQJyz<*gAtJG+}`%f0|Wus1;4!tGFN@mMJD zH8h3qIuR zJZq|uMRics=<_#7ij2Ou^|>Z--|iFN3qrS&H?ZOjccvShaLev-c)%h4NLOs&bPrjF zUir`-tlhz9;mgAFt-S(#KX~)RZt;fFz$>B06`pp9Uy*F=(5~Zn{bwxV5BVLQAkN{( zZ0a%Se<ABZl$s}S! z{Rj7VwFjEK?kejxlTMwb`dXJ@Ho1V`1-@qRZlg&ef8d*S zaL()(jyDT7(T!42#YUSEj3yQ%sA@FgZri-vs-{tcUq~~n!7r5OXp2U)Xf*IZBYs`u z*WkAySXE1$x-+k~Vf%^3pOtjP2YKCvX9G?dK)UnkAoIvs{&cY1=`3e1TWW60F6Z*S zJiYj<|A8)U66fiB4`$gS??aQ5f}hi5#U6Mf7D`QW0#C4#F};M5^2_wm9A>%#v#b5U z<@i!@p@PBUG@DozZbUVfoq!v`AYZ+~mu&FQ&ZPBLORse%RT6xNf43(RLI>RQ$V!DN_LWNvL&c}uDQXst$-zpT9*`%4^O(v#0q%! zc~%b+A_OQ`!ePV$U+n=EpVcvT%qikvf&T~`tcpb(_5F^*JWiVn_Ctp|1l^~>847i9 zoHh)s`{c=!waV}rmfd^uK;4m!CM(s1**zbxe%!?(sv22cCo54Et3lluSiueam@?d5 zP=xn~p`iOhwydm7rweOUtgD{-wzDd2_@Z)W6O{6fQbd(q-E`kxC88IUy}h*mpi)we zrD)&8;Ize{nEBV6olM`E zr$_z?t*Q{y_w*068S6gV2Cd?crCL&cF$qIdWD7n2!KKAhZL1_$gP$;rD6fp8y^|mKMk2;yz+7V;UG@B4xyZudI(4gSxD*-d*Fc zmX#XRl(4u$p;}dGQUS~3yW$h@@x)iAvP2Jc_;6Q1euNGF*+?&5ZMh1K+O-C)MLVU{ z(qG`1(5~tIexp$kj4SatZ;QumbUQLe1jTET1RFi9yV7zsrq`}{wP9Zek_AC9I~ z8^m&GpcQ&l>Ew7K5lyj?OeQiMQ%^*X4^2fEs>;niaK!B#jJVkyS^*&B6oh>O+`DqG( zsQ_&4sj`@2dyhW=J6+TxDiWN*HUVN`yk}M2DrV|Dt`PGKYgtng6W42H%;E*==wgwQ z>EJOyyn%Pv5OujRaf)H$Uubem&AfHKuqgl}(2x~qPNp9j-vxkX;rkOHKEtue5>cHO zvO-jMlsVd-At)h2(WE1cE&f8l=cR+zRr_Hu?`)@)oF|&g@ipSS3mtCo12p&b;F}?u pQqk$>2ma998U diff --git a/application/fonts/fontanello-ifont/font/ifont.svg b/application/fonts/fontello-ifont/font/ifont.svg similarity index 88% rename from application/fonts/fontanello-ifont/font/ifont.svg rename to application/fonts/fontello-ifont/font/ifont.svg index 6e385b6f0..ae7e08c46 100644 --- a/application/fonts/fontanello-ifont/font/ifont.svg +++ b/application/fonts/fontello-ifont/font/ifont.svg @@ -34,7 +34,7 @@ - + @@ -69,8 +69,8 @@ - - + + @@ -111,6 +111,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/application/fonts/fontanello-ifont/font/ifont.ttf b/application/fonts/fontello-ifont/font/ifont.ttf similarity index 86% rename from application/fonts/fontanello-ifont/font/ifont.ttf rename to application/fonts/fontello-ifont/font/ifont.ttf index 470c1997afa08cfe111a09031fb2ee065ce7e069..931b3d1571a5a3be9ad3d740e661fd4703c98a4f 100644 GIT binary patch delta 2669 zcma)8eN0=|6~E^``}qUn53nDEfw7;>mu(C&#t#8;3}WEWG>yOsl#mbu22-$cjR{E_ z~y_^PZt& z+CQ`2z4x5oIrp4%?>YBgfB7LSe*zf-gb*D$Ll|=GsqPwYpla_aL_WuMXeb^@-aohV zEkd9TTj$X6v=wpujlPeab|g6(Kfkc>H1ZD!$w`hzrjm#okYC18Jvwo6B*cCzj}W>* zNZ*-QG%~FCo7h6g5!506SS*@}s1u405eOmRh{e+u1ri0Me19gG!Zfo zMDX)?q9kg1ioT7=g_p!#FmS~-7d`Y3nki$}SwX4j;dZ^#a6_{Aw0|DRwiSht=WnvT2fd~8+KwZ>9 zWl2XSDx}%cBy(-6hkApxnLj(5E2+D|BmUSQ@>B0VFKu`Dd0OtR6g`by4YYZG03g^K zpsnFHsJ3`4ly~ySi^>aWF>e{R)qLv=V+-C7EcZ z4XxFIKwlsrCOE6rZMA-!S4;~lIX1&f1+no{M$f2;pRh|B3i2ZDdlb{;*?HDfDvN5Myx!-plN1?!Z_5)6;{H9Se-eZ)C2wHG+wOE1IN`3{n^tznRMz5)mOU&v&jYgZtyjMcRO9N4F|KyZj*HCY~HeM z_;#Iw{{!EygEli?JKiqXM%PP0qE0F1wW_Bh~4m5%$1tt1Ri50V|wv+!u&FQ zbQv>UirLk^<#K!@KUcwEahgr63OAwx%TB~* z3yf;TbIRe{(eZxUJ2QLF9c`v<@n_GsrLXoJd@a?^fXC=c2fM!$h7zq&&0!tM0WLFL zcuyDzhjo;1G~{ZfI?@0}k-?w>P?vARn##8sy%vC5P}_91XZl`JapIkmF}TyZyI<^{ zUQR6W9sc@CR|$Hv_9KZX@#8*9Y^yF zV9}ds;SR?um*K_h9ZqjMgm%HtKH`cw{5~rC65y+^q{XqgxObUrm{KJ#hDgq zDvpN@(lmqcl01!%i|3IM5CqSrME)CvFXy?J&!-3U&3`31%%{>q@6Z1wmK}f5a4Gko z0Mkot2Y(1oW*lqLh}T99j`#;kaXdRpvm{#P7ZF>$^x2^Y#Z@<*tn;y}&2`VsxkK(} z+>7o9)j`?m^wN7hpHP^-^hVzb2jegSaY(=|!4#xXGY%;X~oRg$e1EN oIhoMNhN_ceQEirrq@s~c5Z$nY(a3l-rHn^L$A*@^I7)N>4ND+CH~;_u delta 393 zcmWlVKS;w+5XQetBL=nV;G&>ZbaC)s5k(MD5K#vewf=*ehBRrcO&i*vwjzpP5$RCL z?yRl>U7WOwP7d15O;Djj7r{xqJow(-``sP)@k*ameWN1~fJPj{hseTme{j5KR%cRS zt*WMCy<}VO0GeXWsk?T7IiIaxzUp)iD^X$blR5q1; zi#q)|V6DXOKvFTaQp+KmS^MB6*H$WHpN!7Sz$PygWh<>&?>oLzAZ~O20mzr6B5EKB zIpLm3;o@(Q3}=8Q$#B!Ox7_7@2djNC?8r@HKdAS4R`GKF>h*KHDL6yn5sJHs@D(`| za#>>RO~u_{&1mV}ZB=v2(HZiqsifYkBy7=3+&+Dh2<}5nX!r*h CE^Vs- diff --git a/application/fonts/fontello-ifont/font/ifont.woff b/application/fonts/fontello-ifont/font/ifont.woff new file mode 100644 index 0000000000000000000000000000000000000000..36c96a9676149aa4036de7f60237521c1020b9db GIT binary patch literal 18080 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 L00+||xBvhEcf^?- literal 0 HcmV?d00001 diff --git a/library/Icinga/Web/StyleSheet.php b/library/Icinga/Web/StyleSheet.php index ec926d992..b40b37927 100644 --- a/library/Icinga/Web/StyleSheet.php +++ b/library/Icinga/Web/StyleSheet.php @@ -25,7 +25,7 @@ class StyleSheet 'css/icinga/monitoring-colors.less', 'css/icinga/selection-toolbar.less', 'css/icinga/login.less', - '../application/fonts/fontanello-ifont/css/ifont-embedded.css', + '../application/fonts/fontello-ifont/css/ifont-embedded.css', 'css/vendor/tipsy.css' ); diff --git a/modules/monitoring/application/controllers/ShowController.php b/modules/monitoring/application/controllers/ShowController.php index 03c1d62fc..330b590eb 100644 --- a/modules/monitoring/application/controllers/ShowController.php +++ b/modules/monitoring/application/controllers/ShowController.php @@ -212,7 +212,7 @@ class Monitoring_ShowController extends Controller 'service', array( 'title' => 'Service', - 'icon' => 'conf', + 'icon' => 'service', 'url' => 'monitoring/show/service', 'urlParams' => $params, ) @@ -222,7 +222,7 @@ class Monitoring_ShowController extends Controller 'services', array( 'title' => 'Services', - 'icon' => 'conf-alt', + 'icon' => 'services', 'url' => 'monitoring/show/services', 'urlParams' => $params, ) diff --git a/modules/monitoring/application/views/scripts/list/hosts.phtml b/modules/monitoring/application/views/scripts/list/hosts.phtml index 3bbb9d085..12f9a1738 100644 --- a/modules/monitoring/application/views/scripts/list/hosts.phtml +++ b/modules/monitoring/application/views/scripts/list/hosts.phtml @@ -46,7 +46,7 @@ if ($hosts->count() === 0) { $icons = array(); if (! $host->host_handled && $host->host_state > 0){ - $icons[] = $this->icon('flash', $this->translate('Unhandled')); + $icons[] = $this->icon('attention-alt', $this->translate('Unhandled')); } if ($host->host_acknowledged) { diff --git a/modules/monitoring/application/views/scripts/list/services.phtml b/modules/monitoring/application/views/scripts/list/services.phtml index 630f738a6..7a21bf617 100644 --- a/modules/monitoring/application/views/scripts/list/services.phtml +++ b/modules/monitoring/application/views/scripts/list/services.phtml @@ -71,7 +71,7 @@ foreach ($services as $service): perfdata($service->service_perfdata, true, true) ?> service_handled && $service->service_state > 0): ?> - icon('flash', $this->translate('Unhandled')) ?> + icon('attention-alt', $this->translate('Unhandled')) ?> service_acknowledged && !$service->service_in_downtime): ?> diff --git a/modules/monitoring/application/views/scripts/show/components/servicegroups.phtml b/modules/monitoring/application/views/scripts/show/components/servicegroups.phtml index 181f194cb..50b71d839 100644 --- a/modules/monitoring/application/views/scripts/show/components/servicegroups.phtml +++ b/modules/monitoring/application/views/scripts/show/components/servicegroups.phtml @@ -12,7 +12,7 @@ foreach ($object->servicegroups as $name => $alias) { printf( "
\n", $this->translate('Servicegroups'), - $this->icon('conf-alt'), + $this->icon('services'), implode(', ', $list) ); diff --git a/modules/monitoring/application/views/scripts/show/components/statusIcons.phtml b/modules/monitoring/application/views/scripts/show/components/statusIcons.phtml index 569dcad6c..d76c07cf2 100644 --- a/modules/monitoring/application/views/scripts/show/components/statusIcons.phtml +++ b/modules/monitoring/application/views/scripts/show/components/statusIcons.phtml @@ -23,7 +23,7 @@ $obj->passive_checks_enabled = $i = array(); if (! $obj->handled && $obj->state > 0) { - $i[] = $this->icon('flash', $this->translate('Unhandled')); + $i[] = $this->icon('attention-alt', $this->translate('Unhandled')); } if ($obj->acknowledged && ! $obj->in_downtime) { diff --git a/modules/monitoring/application/views/scripts/show/history.phtml b/modules/monitoring/application/views/scripts/show/history.phtml index e9699853a..dfc1cbf0e 100644 --- a/modules/monitoring/application/views/scripts/show/history.phtml +++ b/modules/monitoring/application/views/scripts/show/history.phtml @@ -85,17 +85,17 @@ function contactsLink($match, $view) { $msg = $this->escape($event->output); break; case 'hard_state': - $icon = $isService ? 'service' : 'host'; $msg = '[ ' . $event->attempt . '/' . $event->max_attempts . ' ] ' . $this->escape($event->output); $stateClass = ( $isService ? strtolower($this->util()->getServiceStateName($event->state)) : strtolower($this->util()->getHostStateName($event->state)) ); + $icon = 'attention-alt'; $title = strtoupper($stateClass); // TODO: Should be translatable! break; case 'soft_state': - $icon = 'softstate'; + $icon = 'spinner'; $msg = '[ ' . $event->attempt . '/' . $event->max_attempts . ' ] ' . $this->escape($event->output); $stateClass = ( $isService diff --git a/modules/monitoring/configuration.php b/modules/monitoring/configuration.php index bb5b646d6..f7d876a29 100644 --- a/modules/monitoring/configuration.php +++ b/modules/monitoring/configuration.php @@ -124,7 +124,7 @@ $section->add($this->translate('Timeline'))->setUrl('monitoring/timeline'); * Reporting Section */ $section = $this->menuSection($this->translate('Reporting'), array( - 'icon' => 'service', + 'icon' => 'barchart', 'priority' => 100 )); diff --git a/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php b/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php index 82c70fc16..06ef5c7ce 100644 --- a/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php +++ b/modules/monitoring/library/Monitoring/Web/Controller/MonitoredObjectController.php @@ -197,7 +197,7 @@ abstract class MonitoredObjectController extends Controller 'service', array( 'title' => 'Service', - 'icon' => 'conf', + 'icon' => 'service', 'url' => 'monitoring/service/show', 'urlParams' => $params ) @@ -207,7 +207,7 @@ abstract class MonitoredObjectController extends Controller 'services', array( 'title' => 'Services', - 'icon' => 'conf-alt', + 'icon' => 'services', 'url' => 'monitoring/show/services', 'urlParams' => $params ) From 245c247ff37e72237774fb581c87b06f3e942e37 Mon Sep 17 00:00:00 2001 From: Bernd Erk Date: Mon, 17 Nov 2014 17:06:27 +0100 Subject: [PATCH 07/61] Changes remove icon in monitoring module to cancel icon --- application/views/scripts/config/resource.phtml | 2 +- application/views/scripts/form/reorder-authbackend.phtml | 2 +- .../monitoring/application/views/scripts/config/index.phtml | 4 ++-- .../application/views/scripts/multi/components/comments.phtml | 2 +- .../views/scripts/multi/components/downtimes.phtml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/application/views/scripts/config/resource.phtml b/application/views/scripts/config/resource.phtml index 73ce6dae3..788edcd89 100644 --- a/application/views/scripts/config/resource.phtml +++ b/application/views/scripts/config/resource.phtml @@ -22,7 +22,7 @@ diff --git a/application/views/scripts/form/reorder-authbackend.phtml b/application/views/scripts/form/reorder-authbackend.phtml index e23df8b7a..90319e0ad 100644 --- a/application/views/scripts/form/reorder-authbackend.phtml +++ b/application/views/scripts/form/reorder-authbackend.phtml @@ -16,7 +16,7 @@ @@ -60,7 +60,7 @@ diff --git a/modules/monitoring/application/views/scripts/multi/components/comments.phtml b/modules/monitoring/application/views/scripts/multi/components/comments.phtml index ff822fcc3..f0b262c9d 100644 --- a/modules/monitoring/application/views/scripts/multi/components/comments.phtml +++ b/modules/monitoring/application/views/scripts/multi/components/comments.phtml @@ -6,7 +6,7 @@ $objectName = $this->is_service ? 'Services' : 'Hosts'; - getComponents() as $component): ?> + getComponents(); ?> + - - - - + + + + + + + + +
icon('host') ?> translate('Host') ?>icon('service') ?> translate('Service') ?>icon('conf') ?> translate('Service') ?>
%s%s %s
%s%s %s
- icon('minus'); ?> + icon('cancel'); ?>
- icon('minus', $this->translate('Remove')); ?> + icon('cancel', $this->translate('Remove')); ?> diff --git a/modules/monitoring/application/views/scripts/config/index.phtml b/modules/monitoring/application/views/scripts/config/index.phtml index 370940dd2..b1729f9b1 100644 --- a/modules/monitoring/application/views/scripts/config/index.phtml +++ b/modules/monitoring/application/views/scripts/config/index.phtml @@ -28,7 +28,7 @@ - icon('minus'); ?> + icon('cancel'); ?>
- icon('minus'); ?> + icon('cancel'); ?>
translate('Comments') ?> icon('minus') + $this->icon('cancel') ?> translate('Remove Comments') ?>
icon('bell-off-empty') diff --git a/modules/monitoring/application/views/scripts/multi/components/downtimes.phtml b/modules/monitoring/application/views/scripts/multi/components/downtimes.phtml index 4a586b725..af8d841b4 100644 --- a/modules/monitoring/application/views/scripts/multi/components/downtimes.phtml +++ b/modules/monitoring/application/views/scripts/multi/components/downtimes.phtml @@ -7,7 +7,7 @@ $objectName = $this->is_service ? 'Services' : 'Hosts';
Downtimes icon('minus') ?>Remove Downtimes
+ $this->icon('cancel') ?>Remove Downtimes
icon('plug') From 66ecb2dc9f8ddd54d170240864a9fb452bb8a813 Mon Sep 17 00:00:00 2001 From: Bernd Erk Date: Mon, 17 Nov 2014 18:02:16 +0100 Subject: [PATCH 08/61] Fixes Pluginoutput --- .../views/scripts/list/hosts.phtml | 2 +- .../views/scripts/list/services.phtml | 5 +--- .../scripts/show/components/output.phtml | 3 +++ modules/monitoring/public/css/module.less | 24 ++++++++++++------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/hosts.phtml b/modules/monitoring/application/views/scripts/list/hosts.phtml index 12f9a1738..588d39712 100644 --- a/modules/monitoring/application/views/scripts/list/hosts.phtml +++ b/modules/monitoring/application/views/scripts/list/hosts.phtml @@ -7,6 +7,7 @@ if ($this->compact): ?>
tabs ?>
+ render('list/components/selectioninfo.phtml') ?> render('list/components/hostssummary.phtml') ?> translate('Sort by') ?> sortControl->render($this) ?>
@@ -14,7 +15,6 @@ if ($this->compact): ?> widget('limiter')->setMaxLimit($this->hosts->count()) ?> paginationControl($hosts, null, null, array('preserve' => $this->preserve)) ?> selectionToolbar('multi', $this->href('monitoring/hosts/show?' . $this->filter->toQueryString())) ?> -render('list/components/selectioninfo.phtml') ?>
diff --git a/modules/monitoring/application/views/scripts/list/services.phtml b/modules/monitoring/application/views/scripts/list/services.phtml index 7a21bf617..2ea125527 100644 --- a/modules/monitoring/application/views/scripts/list/services.phtml +++ b/modules/monitoring/application/views/scripts/list/services.phtml @@ -7,6 +7,7 @@ if (!$this->compact): ?>
tabs ?>
+render('list/components/selectioninfo.phtml') ?> render('list/components/servicesummary.phtml') ?>
translate('Sort by') ?> sortControl ?> @@ -18,10 +19,6 @@ if (!$this->compact): ?> widget('limiter')->setCurrentPageCount($this->services->count()) ?> paginationControl($services, null, null, array('preserve' => $this->preserve)) ?> -
diff --git a/modules/monitoring/application/views/scripts/show/components/output.phtml b/modules/monitoring/application/views/scripts/show/components/output.phtml index d482a4d66..fcae644cc 100644 --- a/modules/monitoring/application/views/scripts/show/components/output.phtml +++ b/modules/monitoring/application/views/scripts/show/components/output.phtml @@ -1,2 +1,5 @@ +
+

Pluginoutput

pluginOutput($object->output) ?> pluginOutput($object->long_output) ?> +
diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 1b2a5b67d..65150c5e2 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -20,16 +20,21 @@ p.pluginoutput { white-space: pre-wrap; } -pre.pluginoutput { - font-family: Courier; - background: #eee; - font-size: 0.7em; +div.pluginoutput { + border-right: solid 5px @colorPetrol; overflow: auto; - white-space: pre-wrap; - margin: 0em; - padding: 1em; - margin-bottom: 0.5em; color: black; + margin-bottom: 1em; + padding: 0.2em; +} + +div.pluginoutput h4 { + font-size: 0.875em; + margin: 0em; +} + +div.pluginoutput pre{ + white-space: pre-wrap; } table.objecthistory td { @@ -156,5 +161,6 @@ table.avp .customvar ul { } div.selection-info { - padding-top:1em; + padding-top:0.5em; + float: right; } From 1000b4661f70f65986a1798805f232dc089ed041 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 11 Nov 2014 11:51:18 +0100 Subject: [PATCH 09/61] AddToDashboard: Remove controller logic refs #4537 --- .../controllers/DashboardController.php | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index d357231ca..fb8da0f5a 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -80,30 +80,8 @@ class DashboardController extends ActionController 'url' => Url::fromRequest() ) )->activate('addurl'); - $form = new AddUrlForm(); - $request = $this->getRequest(); - if ($request->isPost()) { - if ($form->isValid($request->getPost()) && $form->isSubmitted()) { - $dashboard = $this->getDashboard(); - $dashboard->setComponentUrl( - $form->getValue('pane'), - $form->getValue('component'), - ltrim($form->getValue('url'), '/') - ); - - $configFile = Config::app('dashboard/dashboard')->getConfigFile(); - if ($this->writeConfiguration(new Config($dashboard->toArray()), $configFile)) { - $this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane')))); - } else { - $this->render('showConfiguration'); - return; - } - } - } else { - $form->create()->setDefault('url', htmlspecialchars_decode($request->getParam('url', ''))); - } - + $form->handleRequest(); $this->view->form = $form; } From 5f9d394bbef0fd74fcf50148ff1c9dd0b33edae7 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 11 Nov 2014 11:51:58 +0100 Subject: [PATCH 10/61] AddToDashboard: Form layout and template refa #4537 --- application/forms/Dashboard/AddUrlForm.php | 108 +++++++++++++----- .../views/scripts/dashboard/addurl.phtml | 8 +- 2 files changed, 82 insertions(+), 34 deletions(-) diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/AddUrlForm.php index 7f5a217d1..6ca5c23dd 100644 --- a/application/forms/Dashboard/AddUrlForm.php +++ b/application/forms/Dashboard/AddUrlForm.php @@ -7,6 +7,7 @@ namespace Icinga\Forms\Dashboard; use Icinga\Application\Config; use Icinga\Web\Widget\Dashboard; use Icinga\Web\Form; +use Icinga\Web\Request; /** * Form to add an url a dashboard pane @@ -23,35 +24,49 @@ class AddUrlForm extends Form } /** + * Build AddUrl form elements + * * @see Form::createElements() */ public function createElements(array $formData) { + $paneSelectionValues = $this->getDashboardPaneSelectionValues(); + $groupElements = array(); + $this->addElement( 'text', 'url', array( - 'required' => true, - 'label' => t('Url'), - 'helptext' => t('The url being loaded in the dashlet') + 'required' => true, + 'label' => t('Url'), + 'description' => + t('Enter url being loaded in the dashlet. You can paste the full URL, including filters.') + ) + ); + $this->addElement( + 'text', + 'component', + array( + 'required' => true, + 'label' => t('Dashlet Title'), + 'description' => t('Enter a title for the dashlet.') ) ); - - $paneSelectionValues = $this->getDashboardPaneSelectionValues(); if (empty($paneSelectionValues) || ((isset($formData['create_new_pane']) && $formData['create_new_pane'] != false) && (false === isset($formData['use_existing_dashboard']) || $formData['use_existing_dashboard'] != true)) ) { - $this->addElement( + $groupElements[] = $this->createElement( 'text', 'pane', array( - 'required' => true, - 'label' => t("The New Pane's Title"), - 'style' => 'display: inline-block' + 'required' => true, + 'label' => t("New Pane Title"), + 'description' => + t('Enter a title for the new pane.') ) ); - $this->addElement( // Prevent the button from being displayed again on validation errors + $groupElements[] = $this->createElement( // Prevent the button from being displayed again on validation errors 'hidden', 'create_new_pane', array( @@ -59,45 +74,62 @@ class AddUrlForm extends Form ) ); if (false === empty($paneSelectionValues)) { - $this->addElement( + $buttonExistingPane = $this->createElement( 'submit', 'use_existing_dashboard', array( - 'ignore' => true, - 'label' => t('Use An Existing Pane'), - 'style' => 'display: inline-block' + 'ignore' => true, + 'label' => t('Use An Existing Pane'), + 'description' => + t('Click on the button to add the dashlet to an existing pane on your dashboard.') ) ); + $buttonExistingPane->removeDecorator('Label'); + $groupElements[] = $buttonExistingPane; } } else { - $this->addElement( + $groupElements[] = $this->createElement( 'select', 'pane', array( 'required' => true, 'label' => t('Pane'), - 'style' => 'display: inline-block;', - 'multiOptions' => $paneSelectionValues + 'multiOptions' => $paneSelectionValues, + 'description' => + t('Select a pane you want to add the dashlet.') ) ); - $this->addElement( + $buttonNewPane = $this->createElement( 'submit', 'create_new_pane', array( - 'ignore' => true, - 'label' => t('Create A New Pane'), - 'style' => 'display: inline-block' + 'ignore' => true, + 'label' => t('Create A New Pane'), + 'description' => + t('Click on the button if you want to add the dashlet to a new pane on the dashboard.') ) ); + $buttonNewPane->removeDecorator('Label'); + $groupElements[] = $buttonNewPane; } - - $this->addElement( - 'text', - 'component', + $this->addDisplayGroup( + $groupElements, + 'pane_group', array( - 'required' => true, - 'label' => t('Title'), - 'helptext' => t('The title for the dashlet') + 'legend' => t('Pane'), + 'description' => t( + 'Decide if you want add the dashlet to an existing pane' + . ' or create a new pane. Have a look on the button below.' + ), + 'decorators' => array( + 'FormElements', + array('HtmlTag', array('tag' => 'div', 'class' => 'control-group')), + array( + 'Description', + array('tag' => 'span', 'class' => 'description', 'placement' => 'prepend') + ), + 'Fieldset' + ) ) ); } @@ -113,4 +145,24 @@ class AddUrlForm extends Form $dashboard->readConfig(Config::app('dashboard/dashboard')); return $dashboard->getPaneKeyTitleArray(); } + + /** + * Adjust preferences and persist them + * + * @see Form::onSuccess() + */ + public function onSuccess(Request $request) + { + return false; + } + + /** + * Populate data if any + * + * @see Form::onRequest() + */ + public function onRequest(Request $request) + { + + } } diff --git a/application/views/scripts/dashboard/addurl.phtml b/application/views/scripts/dashboard/addurl.phtml index c2d3f7e6c..9c41a7713 100644 --- a/application/views/scripts/dashboard/addurl.phtml +++ b/application/views/scripts/dashboard/addurl.phtml @@ -3,10 +3,6 @@
-

escape($this->translate('This feature is deactivated at the moment.')); ?>

-

- escape($this->translate('Please have a little patience, we are hard working on it, take a look at icingaweb2 issues.')); - ?> -

+

+ form; ?>
\ No newline at end of file From af799d42dc28bbce5989fbbaf134c2142d31bf42 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 11 Nov 2014 14:44:38 +0100 Subject: [PATCH 11/61] Widget/Dashboard: Cleanup object and remove unused stuff refs #4537 --- .../controllers/DashboardController.php | 79 +------ application/forms/Dashboard/AddUrlForm.php | 63 +++++- .../dashboard/show-configuration.phtml | 28 --- library/Icinga/Web/Widget/Dashboard.php | 199 +++++++----------- 4 files changed, 133 insertions(+), 236 deletions(-) delete mode 100644 application/views/scripts/dashboard/show-configuration.phtml diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index fb8da0f5a..bf94e26af 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -20,54 +20,6 @@ use Icinga\Web\Widget\Dashboard; */ class DashboardController extends ActionController { - /** - * Default configuration - */ - const DEFAULT_CONFIG = 'dashboard/dashboard'; - - /** - * Retrieve a dashboard from the provided config - * - * @param string $config The config to read the dashboard from, or 'dashboard/dashboard' if none is given - * - * @return \Icinga\Web\Widget\Dashboard - */ - private function getDashboard($config = self::DEFAULT_CONFIG) - { - $dashboard = new Dashboard(); - try { - $dashboardConfig = Config::app($config); - if (count($dashboardConfig) === 0) { - return null; - } - $dashboard->readConfig($dashboardConfig); - } catch (NotReadableError $e) { - Logger::error(new IcingaException('Cannot load dashboard configuration. An exception was thrown:', $e)); - return null; - } - return $dashboard; - } - - /** - * Remove a component from the pane identified by the 'pane' parameter - */ - public function removecomponentAction() - { - $pane = $this->_getParam('pane'); - $dashboard = $this->getDashboard(); - try { - $dashboard->removeComponent( - $pane, - $this->_getParam('component') - )->store(); - $this->redirectNow(Url::fromPath('dashboard', array('pane' => $pane))); - } catch (ConfigurationError $exc ) { - $this->_helper->viewRenderer('show_configuration'); - $this->view->exceptionMessage = $exc->getMessage(); - $this->view->iniConfigurationString = $dashboard->toIni(); - } - } - /** * Display the form for adding new components or add the new component if submitted */ @@ -93,7 +45,9 @@ class DashboardController extends ActionController */ public function indexAction() { - $dashboard = Dashboard::load(); + $dashboard = new Dashboard(); + $dashboard->setUser($this->getRequest()->getUser()); + $dashboard->load(); if (! $dashboard->hasPanes()) { $this->view->title = 'Dashboard'; @@ -103,8 +57,6 @@ class DashboardController extends ActionController $dashboard->activate($pane); } - $this->view->configPath = Config::resolvePath(self::DEFAULT_CONFIG); - if ($dashboard === null) { $this->view->title = 'Dashboard'; } else { @@ -125,29 +77,4 @@ class DashboardController extends ActionController } } } - - /** - * Store the given configuration as INI file - * - * @param Config $config The configuration to store - * @param string $target The path where to store the configuration - * - * @return bool Whether the configuartion has been successfully stored - */ - protected function writeConfiguration(Config $config, $target) - { - $writer = new IniWriter(array('config' => $config, 'filename' => $target)); - - try { - $writer->write(); - } catch (Exception $e) { - Logger::error(new ConfiguationError("Cannot write dashboard to $target", 0, $e)); - $this->view->configString = $writer->render(); - $this->view->errorMessage = $e->getMessage(); - $this->view->filePath = $target; - return false; - } - - return true; - } } diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/AddUrlForm.php index 6ca5c23dd..b881ad237 100644 --- a/application/forms/Dashboard/AddUrlForm.php +++ b/application/forms/Dashboard/AddUrlForm.php @@ -5,6 +5,7 @@ namespace Icinga\Forms\Dashboard; use Icinga\Application\Config; +use Icinga\File\Ini\IniWriter; use Icinga\Web\Widget\Dashboard; use Icinga\Web\Form; use Icinga\Web\Request; @@ -14,6 +15,13 @@ use Icinga\Web\Request; */ class AddUrlForm extends Form { + /** + * Config file name + * + * @var string + */ + private $configFile = 'dashboard/dashboard'; + /** * Initialize this form */ @@ -134,16 +142,42 @@ class AddUrlForm extends Form ); } + /** + * Create a dashboard object + * + * @return Dashboard + */ + private function createDashboard() + { + $dashboard = new Dashboard(); + $dashboard->readConfig(Config::app($this->getConfigFile())); + return $dashboard; + } + /** * Return the names and titles of the available dashboard panes as key-value array * * @return array */ - protected function getDashboardPaneSelectionValues() + private function getDashboardPaneSelectionValues() { - $dashboard = new Dashboard(); - $dashboard->readConfig(Config::app('dashboard/dashboard')); - return $dashboard->getPaneKeyTitleArray(); + return $this->createDashboard()->getPaneKeyTitleArray(); + } + + /** + * @param string $configFile + */ + public function setConfigFile($configFile) + { + $this->configFile = $configFile; + } + + /** + * @return string + */ + public function getConfigFile() + { + return $this->configFile; } /** @@ -153,6 +187,22 @@ class AddUrlForm extends Form */ public function onSuccess(Request $request) { + $dashboard = $this->createDashboard(); + $dashboard->setComponentUrl( + $this->getValue('pane'), + $this->getValue('component'), + ltrim($this->getValue('url'), '/') + ); + /* + $writer = new IniWriter( + array( + 'config' => new Config($dashboard->toArray()), + 'filename' => $dashboard->getConfig()->getConfigFile() + ) + ); + + $writer->write(); + */ return false; } @@ -163,6 +213,9 @@ class AddUrlForm extends Form */ public function onRequest(Request $request) { - + $data = array( + 'url' => $request->getParam('url') + ); + $this->populate($data); } } diff --git a/application/views/scripts/dashboard/show-configuration.phtml b/application/views/scripts/dashboard/show-configuration.phtml deleted file mode 100644 index 7cdce496c..000000000 --- a/application/views/scripts/dashboard/show-configuration.phtml +++ /dev/null @@ -1,28 +0,0 @@ -
-
-

{{WARNING_ICON}}Saving Dashboard Failed

-
-

- Your dashboard couldn't be stored (error: "exceptionMessage; ?>"). This could have one or more - of the following reasons: -

-
    -
  • You don't have permissions to write to the dashboard file
  • -
  • Something went wrong while writing the file
  • -
  • There's an application error preventing you from persisting the configuration
  • -
-
- -

- Details can be seen in your application log (if you don't have access to this file, call your administrator in this case). -
- In case you can access the configuration file (config/dashboard/dashboard.ini) by yourself, you can open it and - insert the config manually: -

-

-

-        
-escape($this->iniConfigurationString); ?>
-        
-    
-

\ No newline at end of file diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 0221e4744..0fdb61d33 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -8,6 +8,7 @@ use Icinga\Application\Icinga; use Icinga\Application\Config; use Icinga\Exception\ConfigurationError; use Icinga\Exception\ProgrammingError; +use Icinga\User; use Icinga\Web\Widget\Dashboard\Pane; use Icinga\Web\Widget\Dashboard\Component as DashboardComponent; use Icinga\Web\Url; @@ -23,13 +24,6 @@ use Icinga\Web\Url; */ class Dashboard extends AbstractWidget { - /** - * The configuration containing information about this dashboard - * - * @var Config; - */ - private $config; - /** * An array containing all panes of this dashboard * @@ -51,6 +45,11 @@ class Dashboard extends AbstractWidget */ private $tabParam = 'pane'; + /** + * @var User + */ + private $user; + /** * Set the given tab name as active. * @@ -67,24 +66,72 @@ class Dashboard extends AbstractWidget * * @return self */ - public static function load() + public function load() { - /** @var $dashboard Dashboard */ - $dashboard = new static('dashboard'); $manager = Icinga::app()->getModuleManager(); foreach ($manager->getLoadedModules() as $module) { /** @var $module \Icinga\Application\Modules\Module */ - $dashboard->mergePanes($module->getPaneItems()); + $this->mergePanes($module->getPaneItems()); } - return $dashboard; + if ($this->user !== null) { + $this->loadUserDashboards(); + } + return $this; + } + + /** + * @return bool + */ + private function loadUserDashboards() + { + $configFile = '/var/lib/icingaweb/' . $this->user->getUsername() . '/dashboard.ini'; + $config = Config::fromIni($configFile); + if (! count($config)) { + return false; + } + $panes = array(); + $components = array(); + foreach ($config as $key => $part) { + if (strpos($key, '.') === false) { + $panes[$key] = new Pane($key); + $panes[$key]->setTitle($part->title); + + } else { + list($paneName, $componentName) = explode('.', $key, 2); + $part->pane = $paneName; + $part->component = $componentName; + $components[] = $part; + } + } + foreach ($components as $componentData) { + $pane = null; + + if (array_key_exists($componentData->pane, $panes) === true) { + $pane = $panes[$componentData->pane]; + } elseif (array_key_exists($componentData->pane, $this->panes) === true) { + $pane = $this->panes[$componentData->pane]; + } else { + continue; + } + $pane->addComponent( + new DashboardComponent( + $componentData->title, + $componentData->url, + $pane + ) + ); + } + $this->mergePanes($panes); + return true; } /** * Merge panes with existing panes * - * @param array $panes - * @return $this + * @param array $panes + * + * @return $this */ public function mergePanes(array $panes) { @@ -134,23 +181,10 @@ class Dashboard extends AbstractWidget */ public function getPanes() { + return ''; return $this->panes; } - /** - * Populate this dashboard via the given configuration file - * - * @param Config $config The configuration file to populate this dashboard with - * - * @return self - */ - public function readConfig(Config $config) - { - $this->config = $config; - $this->panes = array(); - $this->loadConfigPanes(); - return $this; - } /** * Creates a new empty pane with the given title @@ -168,34 +202,6 @@ class Dashboard extends AbstractWidget return $this; } - /** - * Update or adds a new component with the given url to a pane - * - * @TODO: Should only allow component objects to be added directly as soon as we store more information - * - * @param string $pane The pane to add the component to - * @param Component|string $component The component to add or the title of the newly created component - * @param string|null $url The url to use for the component - * - * @return self - */ - public function setComponentUrl($pane, $component, $url) - { - if ($component === null && strpos($pane, '.')) { - list($pane, $component) = preg_split('~\.~', $pane, 2); - } - if (!isset($this->panes[$pane])) { - $this->createPane($pane); - } - $pane = $this->getPane($pane); - if ($pane->hasComponent($component)) { - $pane->getComponent($component)->setUrl($url); - } else { - $pane->addComponent($component, $url); - } - return $this; - } - /** * Checks if the current dashboard has any panes * @@ -206,52 +212,6 @@ class Dashboard extends AbstractWidget return ! empty($this->panes); } - /** - * Check if this dashboard has a specific pane - * - * @param $pane string The name of the pane - * @return bool - */ - public function hasPane($pane) - { - return array_key_exists($pane, $this->panes); - } - - /** - * Remove a component $component from the given pane - * - * @param string $pane The pane to remove the component from - * @param Component|string $component The component to remove or it's name - * - * @return self - */ - public function removeComponent($pane, $component) - { - if ($component === null && strpos($pane, '.')) { - list($pane, $component) = preg_split('~\.~', $pane, 2); - } - $pane = $this->getPane($pane); - if ($pane !== null) { - $pane->removeComponent($component); - } - - return $this; - } - - /** - * Return an array with pane name=>title format used for comboboxes - * - * @return array - */ - public function getPaneKeyTitleArray() - { - $list = array(); - foreach ($this->panes as $name => $pane) { - $list[$name] = $pane->getTitle(); - } - return $list; - } - /** * Add a pane object to this dashboard * @@ -319,7 +279,10 @@ class Dashboard extends AbstractWidget /** * Determine the active pane either by the selected tab or the current request * - * @return Pane The currently active pane + * @throws \Icinga\Exception\ConfigurationError + * @throws \Icinga\Exception\ProgrammingError + * + * @return Pane The currently active pane */ public function determineActivePane() { @@ -346,36 +309,18 @@ class Dashboard extends AbstractWidget } /** - * Return this dashboard's structure as array - * - * @return array + * @param \Icinga\User $user */ - public function toArray() + public function setUser($user) { - $array = array(); - foreach ($this->panes as $pane) { - $array += $pane->toArray(); - } - - return $array; + $this->user = $user; } /** - * Load all config panes from @see Dashboard::$config - * + * @return \Icinga\User */ - private function loadConfigPanes() + public function getUser() { - $items = $this->config; - foreach ($items->keys() as $key) { - $item = $this->config->get($key, false); - if (false === strstr($key, '.')) { - $this->addPane(Pane::fromIni($key, $item)); - } else { - list($paneName, $title) = explode('.', $key, 2); - $pane = $this->getPane($paneName); - $pane->addComponent(DashboardComponent::fromIni($title, $item, $pane)); - } - } + return $this->user; } } From f6a2f6515dff0a4ce5f32e299c9ce21ff8bbe0ad Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 11 Nov 2014 15:38:51 +0100 Subject: [PATCH 12/61] Dashboard: Introduce user flag widget Fix: Do not render disabled components. refs #4537 --- library/Icinga/Web/Widget/Dashboard.php | 31 ++++++++++++---- .../Icinga/Web/Widget/Dashboard/Component.php | 2 +- library/Icinga/Web/Widget/Dashboard/Pane.php | 10 ++++- .../Web/Widget/Dashboard/UserWidget.php | 37 +++++++++++++++++++ 4 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 library/Icinga/Web/Widget/Dashboard/UserWidget.php diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 0fdb61d33..866dfe3ca 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -85,8 +85,7 @@ class Dashboard extends AbstractWidget */ private function loadUserDashboards() { - $configFile = '/var/lib/icingaweb/' . $this->user->getUsername() . '/dashboard.ini'; - $config = Config::fromIni($configFile); + $config = Config::fromIni($this->getConfigFile()); if (! count($config)) { return false; } @@ -96,6 +95,7 @@ class Dashboard extends AbstractWidget if (strpos($key, '.') === false) { $panes[$key] = new Pane($key); $panes[$key]->setTitle($part->title); + $panes[$key]->setUserWidget(); } else { list($paneName, $componentName) = explode('.', $key, 2); @@ -114,15 +114,22 @@ class Dashboard extends AbstractWidget } else { continue; } - $pane->addComponent( - new DashboardComponent( - $componentData->title, - $componentData->url, - $pane - ) + $component = new DashboardComponent( + $componentData->title, + $componentData->url, + $pane ); + + if ((bool) $componentData->get('disabled', false) === true) { + $component->setDisabled(true); + } + + $component->setUserWidget(); + $pane->addComponent($component); } + $this->mergePanes($panes); + return true; } @@ -323,4 +330,12 @@ class Dashboard extends AbstractWidget { return $this->user; } + + public function getConfigFile() + { + if ($this->user === null) { + return ''; + } + return '/var/lib/icingaweb/' . $this->user->getUsername() . '/dashboard.ini'; + } } diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 6edf140f5..0017ce9e3 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -17,7 +17,7 @@ use Icinga\Exception\IcingaException; * This is the element displaying a specific view in icinga2web * */ -class Component extends AbstractWidget +class Component extends UserWidget { /** * The url of this Component diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php index 3b0e97c73..04073411a 100644 --- a/library/Icinga/Web/Widget/Dashboard/Pane.php +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -12,7 +12,7 @@ use Icinga\Exception\ConfigurationError; /** * A pane, displaying different Dashboard components */ -class Pane extends AbstractWidget +class Pane extends UserWidget { /** * The name of this pane, as defined in the ini file @@ -168,7 +168,13 @@ class Pane extends AbstractWidget */ public function render() { - return implode("\n", $this->components) . "\n"; + $components = array_filter( + $this->components, + function ($e) { + return ! $e->getDisabled(); + } + ); + return implode("\n", $components) . "\n"; } /** diff --git a/library/Icinga/Web/Widget/Dashboard/UserWidget.php b/library/Icinga/Web/Widget/Dashboard/UserWidget.php new file mode 100644 index 000000000..0b171964e --- /dev/null +++ b/library/Icinga/Web/Widget/Dashboard/UserWidget.php @@ -0,0 +1,37 @@ +userWidget = (bool) $userWidget; + } + + /** + * Getter for user widget flag + * + * @return boolean + */ + public function isUserWidget() + { + return $this->userWidget; + } +} From 979bec24a555b2e7b387fd0dd0a3ec72a168bf3e Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 11 Nov 2014 15:59:59 +0100 Subject: [PATCH 13/61] Dashboard: Write user dashboards to disk refs #4537 --- library/Icinga/Web/Widget/Dashboard.php | 39 +++++++++++++++++-- .../Icinga/Web/Widget/Dashboard/Component.php | 8 +++- library/Icinga/Web/Widget/Dashboard/Pane.php | 9 ++--- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 866dfe3ca..f8cc54625 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -8,6 +8,7 @@ use Icinga\Application\Icinga; use Icinga\Application\Config; use Icinga\Exception\ConfigurationError; use Icinga\Exception\ProgrammingError; +use Icinga\File\Ini\IniWriter; use Icinga\User; use Icinga\Web\Widget\Dashboard\Pane; use Icinga\Web\Widget\Dashboard\Component as DashboardComponent; @@ -80,6 +81,29 @@ class Dashboard extends AbstractWidget return $this; } + /** + * Write user specific dashboards to disk + */ + public function write() + { + $configFile = $this->getConfigFile(); + $output = array(); + foreach ($this->panes as $pane) { + if ($pane->isUserWidget() === true) { + $output[$pane->getName()] = $pane->toArray(); + } + foreach ($pane->getComponents() as $component) { + if ($component->isUserWidget() === true) { + $output[$pane->getName() . '.' . $component->getTitle()] = $component->toArray(); + } + } + } + + $config = new Config($output); + $writer = new IniWriter(array('config' => $config, 'filename' => $configFile)); + $writer->write(); + } + /** * @return bool */ @@ -316,21 +340,30 @@ class Dashboard extends AbstractWidget } /** - * @param \Icinga\User $user + * Setter for user object + * + * @param User $user */ - public function setUser($user) + public function setUser(User $user) { $this->user = $user; } /** - * @return \Icinga\User + * Getter for user object + * + * @return User */ public function getUser() { return $this->user; } + /** + * Get config file + * + * @return string + */ public function getConfigFile() { if ($this->user === null) { diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 0017ce9e3..17734478c 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -147,7 +147,13 @@ EOD; */ public function toArray() { - $array = array('url' => $this->url->getPath()); + $array = array( + 'url' => $this->url->getPath(), + 'title' => $this->getTitle() + ); + if ($this->getDisabled() === true) { + $array['disabled'] = 1; + } foreach ($this->url->getParams()->toArray() as $param) { $array[$param[0]] = $param[1]; } diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php index 04073411a..8119eaf66 100644 --- a/library/Icinga/Web/Widget/Dashboard/Pane.php +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -247,12 +247,9 @@ class Pane extends UserWidget */ public function toArray() { - $array = array($this->getName() => array('title' => $this->getTitle())); - foreach ($this->components as $title => $component) { - $array[$this->getName() . ".$title"] = $component->toArray(); - } - - return $array; + return array( + 'title' => $this->getTitle() + ); } /** From b679c1e7701fddfe803e364917d0e3070c43c790 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 11 Nov 2014 16:04:51 +0100 Subject: [PATCH 14/61] Dashboard: Refactor search/replace implementation refs #4537 --- .../Icinga/Web/Widget/Dashboard/Component.php | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 17734478c..46b49ebec 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -175,13 +175,25 @@ EOD; $iframeUrl = clone($url); $iframeUrl->setParam('isIframe'); - $html = str_replace('{URL}', $url, $this->template); - $html = str_replace('{IFRAME_URL}', $iframeUrl, $html); - $html = str_replace('{FULL_URL}', $url->getUrlWithout(array('view', 'limit')), $html); - $html = str_replace('{REMOVE_BTN}', $this->getRemoveForm($view), $html); - $html = str_replace('{TITLE}', $view->escape($this->getTitle()), $html); - $html = str_replace('{REMOVE}', $this->getRemoveForm(), $html); - return $html; + $searchTokens = array( + '{URL}', + '{IFRAME_URL}', + '{FULL_URL}', + '{REMOVE_BTN}', + '{TITLE}', + '{REMOVE}' + ); + + $replaceTokens = array( + $url, + $iframeUrl, + $url->getUrlWithout(array('view', 'limit')), + $this->getRemoveForm($view), + $view->escape($this->getTitle()), + $this->getRemoveForm() + ); + + return str_replace($searchTokens, $replaceTokens, $this->template); } /** From 769e8f263617d3c2930414fc0b1226f527c6b2e6 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 11 Nov 2014 16:35:35 +0100 Subject: [PATCH 15/61] Dashboard/Component: Add remove link refs #4537 --- .../controllers/DashboardController.php | 6 ++++ .../Icinga/Web/Widget/Dashboard/Component.php | 35 ++++--------------- library/Icinga/Web/Widget/Dashboard/Pane.php | 8 ++++- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index bf94e26af..fd06e62ea 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -63,6 +63,12 @@ class DashboardController extends ActionController $this->view->title = $dashboard->getActivePane()->getTitle() . ' :: Dashboard'; $this->view->tabs = $dashboard->getTabs(); + if ($this->hasParam('remove')) { + $dashboard->getActivePane()->removeComponent($this->getParam('remove')); + $dashboard->write(); + $this->redirectNow(URL::fromRequest()->remove('remove')); + } + /* Temporarily removed $this->view->tabs->add( 'Add', diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 46b49ebec..693f60bfe 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -53,7 +53,7 @@ class Component extends UserWidget private $template =<<<'EOD'
-

{REMOVE}{TITLE}

+

{TITLE} ({REMOVE})

@@ -179,7 +179,6 @@ EOD; '{URL}', '{IFRAME_URL}', '{FULL_URL}', - '{REMOVE_BTN}', '{TITLE}', '{REMOVE}' ); @@ -188,9 +187,8 @@ EOD; $url, $iframeUrl, $url->getUrlWithout(array('view', 'limit')), - $this->getRemoveForm($view), $view->escape($this->getTitle()), - $this->getRemoveForm() + $this->getRemoveLink() ); return str_replace($searchTokens, $replaceTokens, $this->template); @@ -201,32 +199,13 @@ EOD; * * @return string The html representation of the form */ - protected function getRemoveForm() + protected function getRemoveLink() { - // TODO: temporarily disabled, should point to a form asking for confirmal - return ''; - $removeUrl = Url::fromPath( - '/dashboard/removecomponent', - array( - 'pane' => $this->pane->getName(), - 'component' => $this->getTitle() - ) + return sprintf( + '%s', + Url::fromRequest(array('remove' => $this->getTitle())), + t('Remove') ); - $form = new Form(); - $form->setMethod('POST'); - $form->setAttrib('class', 'inline'); - $form->setAction($removeUrl); - $form->addElement( - new Zend_Form_Element_Button( - 'remove_pane_btn', - array( - 'class'=> 'link-like pull-right', - 'type' => 'submit', - 'label' => 'x' - ) - ) - ); - return $form; } /** diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php index 8119eaf66..26cd46e44 100644 --- a/library/Icinga/Web/Widget/Dashboard/Pane.php +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -130,7 +130,13 @@ class Pane extends UserWidget public function removeComponent($title) { if ($this->hasComponent($title)) { - unset($this->components[$title]); + $component = $this->getComponent($title); + if ($component->isUserWidget() === true) { + unset($this->components[$title]); + } else { + $component->setUserWidget(); + $component->setDisabled(true); + } } return $this; } From bec0085683558b569316218a8a49b764b2fdabb3 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Wed, 12 Nov 2014 09:22:39 +0100 Subject: [PATCH 16/61] Dashboard: Add urls to any dashboard (form) refs #4537 --- .../controllers/DashboardController.php | 7 + application/forms/Dashboard/AddUrlForm.php | 120 ++++++++++-------- library/Icinga/Web/Widget/Dashboard.php | 14 ++ 3 files changed, 87 insertions(+), 54 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index fd06e62ea..6e4dd8cc2 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -32,7 +32,14 @@ class DashboardController extends ActionController 'url' => Url::fromRequest() ) )->activate('addurl'); + $form = new AddUrlForm(); + + $dashboard = new Dashboard(); + $dashboard->setUser($this->getRequest()->getUser()); + $dashboard->load(); + $form->setDashboard($dashboard); + $form->setRedirectUrl($this->getParam('url')); $form->handleRequest(); $this->view->form = $form; } diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/AddUrlForm.php index b881ad237..f67c92a42 100644 --- a/application/forms/Dashboard/AddUrlForm.php +++ b/application/forms/Dashboard/AddUrlForm.php @@ -5,7 +5,9 @@ namespace Icinga\Forms\Dashboard; use Icinga\Application\Config; +use Icinga\Exception\ProgrammingError; use Icinga\File\Ini\IniWriter; +use Icinga\Web\Url; use Icinga\Web\Widget\Dashboard; use Icinga\Web\Form; use Icinga\Web\Request; @@ -22,6 +24,11 @@ class AddUrlForm extends Form */ private $configFile = 'dashboard/dashboard'; + /** + * @var Dashboard + */ + private $dashboard; + /** * Initialize this form */ @@ -38,7 +45,12 @@ class AddUrlForm extends Form */ public function createElements(array $formData) { - $paneSelectionValues = $this->getDashboardPaneSelectionValues(); + $paneSelectionValues = array(); + + if ($this->dashboard !== null) { + $paneSelectionValues = $this->dashboard->getPaneKeyTitleArray(); + } + $groupElements = array(); $this->addElement( @@ -142,44 +154,6 @@ class AddUrlForm extends Form ); } - /** - * Create a dashboard object - * - * @return Dashboard - */ - private function createDashboard() - { - $dashboard = new Dashboard(); - $dashboard->readConfig(Config::app($this->getConfigFile())); - return $dashboard; - } - - /** - * Return the names and titles of the available dashboard panes as key-value array - * - * @return array - */ - private function getDashboardPaneSelectionValues() - { - return $this->createDashboard()->getPaneKeyTitleArray(); - } - - /** - * @param string $configFile - */ - public function setConfigFile($configFile) - { - $this->configFile = $configFile; - } - - /** - * @return string - */ - public function getConfigFile() - { - return $this->configFile; - } - /** * Adjust preferences and persist them * @@ -187,23 +161,34 @@ class AddUrlForm extends Form */ public function onSuccess(Request $request) { - $dashboard = $this->createDashboard(); - $dashboard->setComponentUrl( - $this->getValue('pane'), + $pane = null; + + if ($this->dashboard === null) { + throw new ProgrammingError('Dashboard is not set, can not write values'); + } + + try { + $pane = $this->dashboard->getPane($this->getValue('pane')); + } catch (ProgrammingError $e) { + $pane = new Dashboard\Pane($this->getValue('pane')); + $pane->setUserWidget(); + $this->dashboard->addPane($pane); + } + + $component = new Dashboard\Component( $this->getValue('component'), - ltrim($this->getValue('url'), '/') - ); - /* - $writer = new IniWriter( - array( - 'config' => new Config($dashboard->toArray()), - 'filename' => $dashboard->getConfig()->getConfigFile() - ) + $this->getValue('url'), + $pane ); - $writer->write(); - */ - return false; + $component->setUserWidget(); + + $pane->addComponent($component); + + $this->dashboard->write(); + + + return true; } /** @@ -213,9 +198,36 @@ class AddUrlForm extends Form */ public function onRequest(Request $request) { + // TODO(mh): Im not sure if this is the right place for that + $url = $this->getValue('url'); + if (! $url) { + $url = $request->getParam('url'); + } + + if (! $url) { + return; + } + $data = array( - 'url' => $request->getParam('url') + 'url' => urldecode(Url::fromPath($url)->getPath()) ); + $this->populate($data); } + + /** + * @param Dashboard $dashboard + */ + public function setDashboard(Dashboard $dashboard) + { + $this->dashboard = $dashboard; + } + + /** + * @return Dashboard + */ + public function getDashboard() + { + return $this->dashboard; + } } diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index f8cc54625..1a049ef59 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -275,6 +275,20 @@ class Dashboard extends AbstractWidget return $this->panes[$name]; } + /** + * Return an array with pane name=>title format used for comboboxes + * + * @return array + */ + public function getPaneKeyTitleArray() + { + $list = array(); + foreach ($this->panes as $name => $pane) { + $list[$name] = $pane->getTitle(); + } + return $list; + } + /** * @see Icinga\Web\Widget::render */ From 89b36f79b2e5ab48761ce3f6fc5a292538405465 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Wed, 12 Nov 2014 12:02:05 +0100 Subject: [PATCH 17/61] Dashboard: Reenable generic add link in tab bar refs #4537 --- application/controllers/DashboardController.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 6e4dd8cc2..2c2b7d2fd 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -63,20 +63,16 @@ class DashboardController extends ActionController $pane = $this->_getParam('pane'); $dashboard->activate($pane); } - if ($dashboard === null) { $this->view->title = 'Dashboard'; } else { $this->view->title = $dashboard->getActivePane()->getTitle() . ' :: Dashboard'; $this->view->tabs = $dashboard->getTabs(); - if ($this->hasParam('remove')) { $dashboard->getActivePane()->removeComponent($this->getParam('remove')); $dashboard->write(); $this->redirectNow(URL::fromRequest()->remove('remove')); } - - /* Temporarily removed $this->view->tabs->add( 'Add', array( @@ -84,8 +80,6 @@ class DashboardController extends ActionController 'url' => Url::fromPath('dashboard/addurl') ) ); - */ - $this->view->dashboard = $dashboard; } } From 47414f352839b2cfcd34042fbdb0e885da692694 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 4 Nov 2014 16:15:06 +0100 Subject: [PATCH 18/61] Introduce Form::setOnSuccess() in favor of overriding the constructor Zend_Form uses setters for options if a respective setter method exists. It is not necessary to override the constructor for introducing new options. --- library/Icinga/Web/Form.php | 140 ++++++++++++------------------------ 1 file changed, 47 insertions(+), 93 deletions(-) diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 20484c33e..787e8dc27 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -11,7 +11,6 @@ use Zend_View_Interface; use Icinga\Application\Icinga; use Icinga\Web\Form\Decorator\NoScriptApply; use Icinga\Web\Form\Element\CsrfCounterMeasure; -use Icinga\Web\Form\FormElement; /** * Base class for forms providing CSRF protection, confirmation logic and auto submission @@ -37,13 +36,6 @@ class Form extends Zend_Form */ protected $created = false; - /** - * The request associated with this form - * - * @var Request - */ - protected $request; - /** * The callback to call instead of Form::onSuccess() * @@ -108,38 +100,31 @@ class Form extends Zend_Form * @var array */ public static $defaultElementDecorators = array( - array('ViewHelper', array('separator' => '')), - array('Errors', array('separator' => '')), - array('Description', array('tag' => 'span', 'class' => 'description', 'separator' => '')), - array('Label', array('separator' => '')), - array('HtmlTag', array('tag' => 'div', 'class' => 'element')) + 'ViewHelper', + 'Errors', + array('Description', array('tag' => 'span', 'class' => 'description')), + 'Label', + array('HtmlTag', array('tag' => 'div')) ); /** - * Create a new form + * Set a callback that is called instead of this form's onSuccess method * - * Accepts an additional option `onSuccess' which is a callback that is called instead of this - * form's method. It is called using the following signature: (Form $form). + * It is called using the following signature: (Request $request, Form $form). * - * @see Zend_Form::__construct() + * @param callable $onSuccess Callback * - * @throws LogicException In case `onSuccess' is not callable + * @return $this + * + * @throws LogicException If the callback is not callable */ - public function __construct($options = null) + public function setOnSuccess($onSuccess) { - if (is_array($options) && isset($options['onSuccess'])) { - $this->onSuccess = $options['onSuccess']; - unset($options['onSuccess']); - } elseif (isset($options->onSuccess)) { - $this->onSuccess = $options->onSuccess; - unset($options->onSuccess); - } - - if ($this->onSuccess !== null && false === is_callable($this->onSuccess)) { + if (! is_callable($onSuccess)) { throw new LogicException('The option `onSuccess\' is not callable'); } - - parent::__construct($options); + $this->onSuccess = $onSuccess; + return $this; } /** @@ -363,9 +348,11 @@ class Form extends Zend_Form * * Intended to be implemented by concrete form classes. The base implementation returns always FALSE. * + * @param Request $request The valid request used to process this form + * * @return null|bool Return FALSE in case no redirect should take place */ - public function onSuccess() + public function onSuccess(Request $request) { return false; } @@ -374,8 +361,10 @@ class Form extends Zend_Form * Perform actions when no form dependent data was sent * * Intended to be implemented by concrete form classes. + * + * @param Request $request The current request */ - public function onRequest() + public function onRequest(Request $request) { } @@ -441,8 +430,8 @@ class Form extends Zend_Form * `disableLoadDefaultDecorators' option to any other value than `true'. For loading custom element decorators use * the 'decorators' option. * - * @param string $type The type of the element - * @param string $name The name of the element + * @param string $type String element type + * @param string $name The name of the element to add * @param mixed $options The options for the element * * @return Zend_Form_Element @@ -464,20 +453,10 @@ class Form extends Zend_Form $options = array('decorators' => static::$defaultElementDecorators); } - if (($el = $this->createIcingaFormElement($type, $name, $options)) === null) { - $el = parent::createElement($type, $name, $options); - } + $el = parent::createElement($type, $name, $options); if ($el && $el->getAttrib('autosubmit')) { - $noScript = new NoScriptApply(); // Non-JS environments - $decorators = $el->getDecorators(); - $pos = array_search('Zend_Form_Decorator_ViewHelper', array_keys($decorators)) + 1; - $el->setDecorators( - array_slice($decorators, 0, $pos, true) - + array(get_class($noScript) => $noScript) - + array_slice($decorators, $pos, count($decorators) - $pos, true) - ); - + $el->addDecorator(new NoScriptApply()); // Non-JS environments $class = $el->getAttrib('class'); if (is_array($class)) { $class[] = 'autosubmit'; @@ -487,7 +466,6 @@ class Form extends Zend_Form $class .= ' autosubmit'; } $el->setAttrib('class', $class); // JS environments - unset($el->autosubmit); } @@ -555,17 +533,15 @@ class Form extends Zend_Form { if ($request === null) { $request = $this->getRequest(); - } else { - $this->request = $request; } - $formData = $this->getRequestData(); + $formData = $this->getRequestData($request); if ($this->getUidDisabled() || $this->wasSent($formData)) { $this->populate($formData); // Necessary to get isSubmitted() to work if (! $this->getSubmitLabel() || $this->isSubmitted()) { if ($this->isValid($formData) - && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $this)) - || ($this->onSuccess === null && false !== $this->onSuccess()))) { + && (($this->onSuccess !== null && false !== call_user_func($this->onSuccess, $request, $this)) + || ($this->onSuccess === null && false !== $this->onSuccess($request)))) { $this->getResponse()->redirectAndExit($this->getRedirectUrl()); } } else { @@ -573,7 +549,7 @@ class Form extends Zend_Form $this->isValidPartial($formData); } } else { - $this->onRequest(); + $this->onRequest($request); } return $request; @@ -699,19 +675,29 @@ class Form extends Zend_Form } /** - * Return the request associated with this form + * Return the request data based on this form's request method * - * Returns the global request if none has been set for this form yet. + * @param Request $request The request to fetch the data from + * + * @return array + */ + public function getRequestData(Request $request) + { + if (strtolower($request->getMethod()) === $this->getMethod()) { + return $request->{'get' . ($request->isPost() ? 'Post' : 'Query')}(); + } + + return array(); + } + + /** + * Return the current request * * @return Request */ public function getRequest() { - if ($this->request === null) { - $this->request = Icinga::app()->getFrontController()->getRequest(); - } - - return $this->request; + return Icinga::app()->getFrontController()->getRequest(); } /** @@ -724,39 +710,6 @@ class Form extends Zend_Form return Icinga::app()->getFrontController()->getResponse(); } - /** - * Return the request data based on this form's request method - * - * @return array - */ - protected function getRequestData() - { - if (strtolower($this->request->getMethod()) === $this->getMethod()) { - return $this->request->{'get' . ($this->request->isPost() ? 'Post' : 'Query')}(); - } - - return array(); - } - - /** - * Create a new element located in the Icinga Web 2 library - * - * @param string $type The type of the element - * @param string $name The name of the element - * @param mixed $options The options for the element - * - * @return NULL|FormElement NULL in case the element is not found in the Icinga Web 2 library - * - * @see Form::$defaultElementDecorators For Icinga Web 2's default element decorators. - */ - protected function createIcingaFormElement($type, $name, $options = null) - { - $className = 'Icinga\\Web\\Form\\Element\\' . ucfirst($type); - if (class_exists($className)) { - return new $className($name, $options); - } - } - /** * Render this form * @@ -770,3 +723,4 @@ class Form extends Zend_Form return parent::render($view); } } + From cbcd276b44f437c24df69c36298fcea46743cf9f Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 18 Nov 2014 09:50:10 +0100 Subject: [PATCH 19/61] Dashboard: Rewrite forms and controller [WIP] refs #4537 --- .../controllers/DashboardController.php | 143 ++++++++++++++---- .../{AddUrlForm.php => ComponentForm.php} | 104 ++++++------- .../scripts/dashboard/new-component.phtml | 8 + .../scripts/dashboard/remove-component.phtml | 8 + .../views/scripts/dashboard/settings.phtml | 47 ++++++ .../scripts/dashboard/update-component.phtml | 8 + library/Icinga/Web/Widget/Dashboard.php | 3 +- .../Icinga/Web/Widget/Dashboard/Component.php | 24 +++ .../Widget/Tabextension/DashboardSettings.php | 40 +++++ 9 files changed, 294 insertions(+), 91 deletions(-) rename application/forms/Dashboard/{AddUrlForm.php => ComponentForm.php} (75%) create mode 100644 application/views/scripts/dashboard/new-component.phtml create mode 100644 application/views/scripts/dashboard/remove-component.phtml create mode 100644 application/views/scripts/dashboard/settings.phtml create mode 100644 application/views/scripts/dashboard/update-component.phtml create mode 100644 library/Icinga/Web/Widget/Tabextension/DashboardSettings.php diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 2c2b7d2fd..14252ce22 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -2,16 +2,13 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} -use Icinga\Application\Config; use Icinga\Application\Logger; -use Icinga\Exception\ConfigurationError; -use Icinga\Exception\IcingaException; -use Icinga\Exception\NotReadableError; -use Icinga\File\Ini\IniWriter; -use Icinga\Forms\Dashboard\AddUrlForm; +use Icinga\Form\Dashboard\ComponentForm; +use Icinga\Web\Notification; use Icinga\Web\Controller\ActionController; use Icinga\Web\Url; use Icinga\Web\Widget\Dashboard; +use Icinga\Web\Widget\Tabextension\DashboardSettings; /** * Handle creation, removal and displaying of dashboards, panes and components @@ -20,26 +17,100 @@ use Icinga\Web\Widget\Dashboard; */ class DashboardController extends ActionController { + /** + * @var Dashboard; + */ + private $dashboard; + + public function init() + { + $this->dashboard = new Dashboard(); + $this->dashboard->setUser($this->getRequest()->getUser()); + $this->dashboard->load(); + } + + public function newComponentAction() + { + $form = new ComponentForm(); + $this->createTabs(); + $dashboard = new Dashboard(); + $dashboard->setUser($this->getRequest()->getUser()); + $dashboard->load(); + $form->setDashboard($dashboard); + $form->handleRequest(); + $this->view->form = $form; + } + + public function updateComponentAction() + { + $this->createTabs(); + $dashboard = $this->dashboard; + $form = new ComponentForm(); + $form->setDashboard($dashboard); + $form->setSubmitLabel(t('Update Component')); + if (! $this->_request->getParam('pane')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "pane"', + 400 + ); + } + if (! $this->_request->getParam('component')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "component"', + 400 + ); + } + $form->setOnSuccess(function (\Icinga\Web\Request $request, \Icinga\Web\Form $form) use ($dashboard) { + $pane = $dashboard->getPane($form->getValue('pane')); + try { + $component = $pane->getComponent($form->getValue('component')); + $component->setUrl($form->getValue('url')); + } catch (\Icinga\Exception\ProgrammingError $e) { + $component = new Dashboard\Component($form->getValue('component'), $form->getValue('url'), $pane); + $pane->addComponent($component); + } + $component->setUserWidget(); + // Rename component + if ($form->getValue('org_component') && $form->getValue('org_component') !== $component->getTitle()) { + $pane->removeComponent($form->getValue('org_component')); + } + $dashboard->write(); + Notification::success(t('Component updated')); + return true; + }); + $form->setRedirectUrl('dashboard/settings'); + $form->handleRequest(); + $pane = $dashboard->getPane($this->getParam('pane')); + $component = $pane->getComponent($this->getParam('component')); + $form->load($component); + + $this->view->form = $form; + } + + public function deleteComponentAction() + { + $form = new ComponentForm(); + + $this->createTabs(); + $dashboard = new Dashboard(); + $dashboard->setUser($this->getRequest()->getUser()); + $dashboard->load(); + $form->setDashboard($dashboard); + $form->handleRequest(); + $this->view->form = $form; + } + /** * Display the form for adding new components or add the new component if submitted */ public function addurlAction() { - $this->getTabs()->add( - 'addurl', - array( - 'title' => 'Add Dashboard URL', - 'url' => Url::fromRequest() - ) - )->activate('addurl'); - $form = new AddUrlForm(); $dashboard = new Dashboard(); $dashboard->setUser($this->getRequest()->getUser()); $dashboard->load(); $form->setDashboard($dashboard); - $form->setRedirectUrl($this->getParam('url')); $form->handleRequest(); $this->view->form = $form; } @@ -52,36 +123,50 @@ class DashboardController extends ActionController */ public function indexAction() { - $dashboard = new Dashboard(); - $dashboard->setUser($this->getRequest()->getUser()); - $dashboard->load(); - - if (! $dashboard->hasPanes()) { + $this->createTabs(); + if (! $this->dashboard->hasPanes()) { $this->view->title = 'Dashboard'; } else { if ($this->_getParam('pane')) { $pane = $this->_getParam('pane'); - $dashboard->activate($pane); + $this->dashboard->activate($pane); } - if ($dashboard === null) { + if ($this->dashboard === null) { $this->view->title = 'Dashboard'; } else { - $this->view->title = $dashboard->getActivePane()->getTitle() . ' :: Dashboard'; - $this->view->tabs = $dashboard->getTabs(); + $this->view->title = $this->dashboard->getActivePane()->getTitle() . ' :: Dashboard'; if ($this->hasParam('remove')) { - $dashboard->getActivePane()->removeComponent($this->getParam('remove')); - $dashboard->write(); + $this->dashboard->getActivePane()->removeComponent($this->getParam('remove')); + $this->dashboard->write(); $this->redirectNow(URL::fromRequest()->remove('remove')); } - $this->view->tabs->add( + + /* $this->view->tabs->add( 'Add', array( 'title' => '+', 'url' => Url::fromPath('dashboard/addurl') ) - ); - $this->view->dashboard = $dashboard; + ); */ + $this->view->dashboard = $this->dashboard; } } } + + /** + * Setting dialog + */ + public function settingsAction() + { + $this->createTabs(); + $this->view->dashboard = $this->dashboard; + } + + /** + * Create tab aggregation + */ + private function createTabs() + { + $this->view->tabs = $this->dashboard->getTabs()->extend(new DashboardSettings()); + } } diff --git a/application/forms/Dashboard/AddUrlForm.php b/application/forms/Dashboard/ComponentForm.php similarity index 75% rename from application/forms/Dashboard/AddUrlForm.php rename to application/forms/Dashboard/ComponentForm.php index f67c92a42..d3bcb22f2 100644 --- a/application/forms/Dashboard/AddUrlForm.php +++ b/application/forms/Dashboard/ComponentForm.php @@ -11,19 +11,13 @@ use Icinga\Web\Url; use Icinga\Web\Widget\Dashboard; use Icinga\Web\Form; use Icinga\Web\Request; +use Icinga\Web\Widget\Dashboard\Component; /** * Form to add an url a dashboard pane */ -class AddUrlForm extends Form +class ComponentForm extends Form { - /** - * Config file name - * - * @var string - */ - private $configFile = 'dashboard/dashboard'; - /** * @var Dashboard */ @@ -35,7 +29,9 @@ class AddUrlForm extends Form public function init() { $this->setName('form_dashboard_addurl'); - $this->setSubmitLabel(t('Add To Dashboard')); + if (! $this->getSubmitLabel()) { + $this->setSubmitLabel(t('Add To Dashboard')); + } } /** @@ -45,13 +41,28 @@ class AddUrlForm extends Form */ public function createElements(array $formData) { - $paneSelectionValues = array(); + $groupElements = array(); + $panes = array(); - if ($this->dashboard !== null) { - $paneSelectionValues = $this->dashboard->getPaneKeyTitleArray(); + if ($this->dashboard) { + $panes = $this->dashboard->getPaneKeyTitleArray(); } - $groupElements = array(); + $this->addElement( + 'hidden', + 'org_pane', + array( + 'required' => false + ) + ); + + $this->addElement( + 'hidden', + 'org_component', + array( + 'required' => false + ) + ); $this->addElement( 'text', @@ -72,7 +83,7 @@ class AddUrlForm extends Form 'description' => t('Enter a title for the dashlet.') ) ); - if (empty($paneSelectionValues) || + if (empty($panes) || ((isset($formData['create_new_pane']) && $formData['create_new_pane'] != false) && (false === isset($formData['use_existing_dashboard']) || $formData['use_existing_dashboard'] != true)) ) { @@ -93,7 +104,7 @@ class AddUrlForm extends Form 'value' => 1 ) ); - if (false === empty($paneSelectionValues)) { + if (false === empty($panes)) { $buttonExistingPane = $this->createElement( 'submit', 'use_existing_dashboard', @@ -114,7 +125,7 @@ class AddUrlForm extends Form array( 'required' => true, 'label' => t('Pane'), - 'multiOptions' => $paneSelectionValues, + 'multiOptions' => $panes, 'description' => t('Select a pane you want to add the dashlet.') ) @@ -161,33 +172,6 @@ class AddUrlForm extends Form */ public function onSuccess(Request $request) { - $pane = null; - - if ($this->dashboard === null) { - throw new ProgrammingError('Dashboard is not set, can not write values'); - } - - try { - $pane = $this->dashboard->getPane($this->getValue('pane')); - } catch (ProgrammingError $e) { - $pane = new Dashboard\Pane($this->getValue('pane')); - $pane->setUserWidget(); - $this->dashboard->addPane($pane); - } - - $component = new Dashboard\Component( - $this->getValue('component'), - $this->getValue('url'), - $pane - ); - - $component->setUserWidget(); - - $pane->addComponent($component); - - $this->dashboard->write(); - - return true; } @@ -198,25 +182,11 @@ class AddUrlForm extends Form */ public function onRequest(Request $request) { - // TODO(mh): Im not sure if this is the right place for that - $url = $this->getValue('url'); - if (! $url) { - $url = $request->getParam('url'); - } - - if (! $url) { - return; - } - - $data = array( - 'url' => urldecode(Url::fromPath($url)->getPath()) - ); - - $this->populate($data); + return true; } /** - * @param Dashboard $dashboard + * @param \Icinga\Web\Widget\Dashboard $dashboard */ public function setDashboard(Dashboard $dashboard) { @@ -224,10 +194,24 @@ class AddUrlForm extends Form } /** - * @return Dashboard + * @return \Icinga\Web\Widget\Dashboard */ public function getDashboard() { return $this->dashboard; } + + /** + * @param Component $component + */ + public function load(Component $component) + { + $this->populate(array( + 'pane' => $component->getPane()->getName(), + 'org_pane' => $component->getPane()->getName(), + 'component' => $component->getTitle(), + 'org_component' => $component->getTitle(), + 'url' => $component->getUrl() + )); + } } diff --git a/application/views/scripts/dashboard/new-component.phtml b/application/views/scripts/dashboard/new-component.phtml new file mode 100644 index 000000000..456d14a65 --- /dev/null +++ b/application/views/scripts/dashboard/new-component.phtml @@ -0,0 +1,8 @@ +
+ tabs ?> +
+ +
+

+ form; ?> +
\ No newline at end of file diff --git a/application/views/scripts/dashboard/remove-component.phtml b/application/views/scripts/dashboard/remove-component.phtml new file mode 100644 index 000000000..9138b95b1 --- /dev/null +++ b/application/views/scripts/dashboard/remove-component.phtml @@ -0,0 +1,8 @@ +
+ tabs ?> +
+ +
+

+ form; ?> +
\ No newline at end of file diff --git a/application/views/scripts/dashboard/settings.phtml b/application/views/scripts/dashboard/settings.phtml new file mode 100644 index 000000000..7a2e8f390 --- /dev/null +++ b/application/views/scripts/dashboard/settings.phtml @@ -0,0 +1,47 @@ + +
+ tabs ?> +
+
+

+ + + + + + + + + + dashboard->getPanes() as $pane): ?> + + + + getComponents() as $component): ?> + + + + + + + + +
+ + + +
+ getName(); ?> +
+ + getTitle(); ?> + + + getUrl(); ?> + + + icon('remove.png'); ?> + +
+
\ No newline at end of file diff --git a/application/views/scripts/dashboard/update-component.phtml b/application/views/scripts/dashboard/update-component.phtml new file mode 100644 index 000000000..0493f5613 --- /dev/null +++ b/application/views/scripts/dashboard/update-component.phtml @@ -0,0 +1,8 @@ +
+ tabs ?> +
+ +
+

+ form; ?> +
\ No newline at end of file diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 1a049ef59..1764e5cea 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -187,7 +187,7 @@ class Dashboard extends AbstractWidget */ public function getTabs() { - $url = Url::fromRequest()->getUrlWithout($this->tabParam); + $url = Url::fromPath('dashboard')->getUrlWithout($this->tabParam); if ($this->tabs === null) { $this->tabs = new Tabs(); @@ -212,7 +212,6 @@ class Dashboard extends AbstractWidget */ public function getPanes() { - return ''; return $this->panes; } diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 693f60bfe..0ab210057 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -93,6 +93,14 @@ EOD; return $this->title; } + /** + * @param string $title + */ + public function setTitle($title) + { + $this->title = $title; + } + /** * Retrieve the components url * @@ -228,4 +236,20 @@ EOD; $cmp = new Component($title, Url::fromPath($url, $parameters), $pane); return $cmp; } + + /** + * @param \Icinga\Web\Widget\Dashboard\Pane $pane + */ + public function setPane(Panel $pane) + { + $this->pane = $pane; + } + + /** + * @return \Icinga\Web\Widget\Dashboard\Pane + */ + public function getPane() + { + return $this->pane; + } } diff --git a/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php b/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php new file mode 100644 index 000000000..4242f864d --- /dev/null +++ b/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php @@ -0,0 +1,40 @@ +addAsDropdown( + 'dashboard_add', + array( + 'icon' => 'img/icons/dashboard.png', + 'title' => t('Add To Dashboard'), + 'url' => Url::fromPath('dashboard/addurl') + ) + ); + + $tabs->addAsDropdown( + 'dashboard_settings', + array( + 'icon' => 'img/icons/dashboard.png', + 'title' => t('Settings'), + 'url' => Url::fromPath('dashboard/settings') + ) + ); + } +} \ No newline at end of file From 3e58ec253030838dac328e674bd631b6d5d9fb05 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 18 Nov 2014 12:51:28 +0100 Subject: [PATCH 20/61] Dashboard: Use new controller actions refs #4537 --- .../controllers/DashboardController.php | 98 +++++++++++++------ application/forms/Dashboard/ComponentForm.php | 4 - .../scripts/dashboard/remove-component.phtml | 6 ++ .../views/scripts/dashboard/settings.phtml | 37 ++++--- .../Icinga/Web/Widget/Dashboard/Component.php | 5 +- .../Widget/Tabextension/DashboardAction.php | 2 +- .../Widget/Tabextension/DashboardSettings.php | 2 +- 7 files changed, 101 insertions(+), 53 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 14252ce22..a28e1485a 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -3,9 +3,13 @@ // {{{ICINGA_LICENSE_HEADER}}} use Icinga\Application\Logger; -use Icinga\Form\Dashboard\ComponentForm; +use Icinga\Exception\ProgrammingError; +use Icinga\Forms\ConfirmRemovalForm; +use Icinga\Forms\Dashboard\ComponentForm; +use Icinga\Web\Form; use Icinga\Web\Notification; use Icinga\Web\Controller\ActionController; +use Icinga\Web\Request; use Icinga\Web\Url; use Icinga\Web\Widget\Dashboard; use Icinga\Web\Widget\Tabextension\DashboardSettings; @@ -33,10 +37,29 @@ class DashboardController extends ActionController { $form = new ComponentForm(); $this->createTabs(); - $dashboard = new Dashboard(); - $dashboard->setUser($this->getRequest()->getUser()); - $dashboard->load(); + $dashboard = $this->dashboard; $form->setDashboard($dashboard); + if ($this->_request->getParam('url')) { + $params = $this->_request->getParams(); + $params['url'] = rawurldecode($this->_request->getParam('url')); + $form->populate($params); + } + $form->setOnSuccess(function (Request $request, Form $form) use ($dashboard) { + try { + $pane = $dashboard->getPane($form->getValue('pane')); + } catch (ProgrammingError $e) { + $pane = new Dashboard\Pane($form->getValue('pane')); + $pane->setUserWidget(); + $dashboard->addPane($pane); + } + $component = new Dashboard\Component($form->getValue('component'), $form->getValue('url'), $pane); + $component->setUserWidget(); + $pane->addComponent($component); + $dashboard->write(); + Notification::success(t('Component created')); + return true; + }); + $form->setRedirectUrl('dashboard'); $form->handleRequest(); $this->view->form = $form; } @@ -60,12 +83,12 @@ class DashboardController extends ActionController 400 ); } - $form->setOnSuccess(function (\Icinga\Web\Request $request, \Icinga\Web\Form $form) use ($dashboard) { + $form->setOnSuccess(function (Request $request, Form $form) use ($dashboard) { $pane = $dashboard->getPane($form->getValue('pane')); try { $component = $pane->getComponent($form->getValue('component')); $component->setUrl($form->getValue('url')); - } catch (\Icinga\Exception\ProgrammingError $e) { + } catch (ProgrammingError $e) { $component = new Dashboard\Component($form->getValue('component'), $form->getValue('url'), $pane); $pane->addComponent($component); } @@ -75,6 +98,7 @@ class DashboardController extends ActionController $pane->removeComponent($form->getValue('org_component')); } $dashboard->write(); + $dashboard->write(); Notification::success(t('Component updated')); return true; }); @@ -87,31 +111,42 @@ class DashboardController extends ActionController $this->view->form = $form; } - public function deleteComponentAction() + public function removeComponentAction() { - $form = new ComponentForm(); - + $form = new ConfirmRemovalForm(); $this->createTabs(); - $dashboard = new Dashboard(); - $dashboard->setUser($this->getRequest()->getUser()); - $dashboard->load(); - $form->setDashboard($dashboard); - $form->handleRequest(); - $this->view->form = $form; - } - - /** - * Display the form for adding new components or add the new component if submitted - */ - public function addurlAction() - { - $form = new AddUrlForm(); - - $dashboard = new Dashboard(); - $dashboard->setUser($this->getRequest()->getUser()); - $dashboard->load(); - $form->setDashboard($dashboard); + $dashboard = $this->dashboard; + if (! $this->_request->getParam('pane')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "pane"', + 400 + ); + } + if (! $this->_request->getParam('component')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "component"', + 400 + ); + } + $pane = $this->_request->getParam('pane'); + $component = $this->_request->getParam('component'); + $form->setOnSuccess(function (Request $request, Form $form) use ($dashboard, $component, $pane) { + try { + $pane = $dashboard->getPane($pane); + $pane->removeComponent($component); + $dashboard->write(); + Notification::success(t('Component has been removed from') . ' ' . $pane->getTitle()); + return true; + } catch (ProgrammingError $e) { + Notification::error($e->getMessage()); + return false; + } + return false; + }); + $form->setRedirectUrl('dashboard/settings'); $form->handleRequest(); + $this->view->pane = $pane; + $this->view->component = $component; $this->view->form = $form; } @@ -140,14 +175,13 @@ class DashboardController extends ActionController $this->dashboard->write(); $this->redirectNow(URL::fromRequest()->remove('remove')); } - - /* $this->view->tabs->add( + $this->view->tabs->add( 'Add', array( 'title' => '+', - 'url' => Url::fromPath('dashboard/addurl') + 'url' => Url::fromPath('dashboard/new-component') ) - ); */ + ); $this->view->dashboard = $this->dashboard; } } diff --git a/application/forms/Dashboard/ComponentForm.php b/application/forms/Dashboard/ComponentForm.php index d3bcb22f2..c62bf82fe 100644 --- a/application/forms/Dashboard/ComponentForm.php +++ b/application/forms/Dashboard/ComponentForm.php @@ -4,10 +4,6 @@ namespace Icinga\Forms\Dashboard; -use Icinga\Application\Config; -use Icinga\Exception\ProgrammingError; -use Icinga\File\Ini\IniWriter; -use Icinga\Web\Url; use Icinga\Web\Widget\Dashboard; use Icinga\Web\Form; use Icinga\Web\Request; diff --git a/application/views/scripts/dashboard/remove-component.phtml b/application/views/scripts/dashboard/remove-component.phtml index 9138b95b1..c39472771 100644 --- a/application/views/scripts/dashboard/remove-component.phtml +++ b/application/views/scripts/dashboard/remove-component.phtml @@ -4,5 +4,11 @@

+ +

+ translate('Please confirm the removal'); ?>: + pane; ?>/component; ?> +

+ form; ?>
\ No newline at end of file diff --git a/application/views/scripts/dashboard/settings.phtml b/application/views/scripts/dashboard/settings.phtml index 7a2e8f390..76a66a0d2 100644 --- a/application/views/scripts/dashboard/settings.phtml +++ b/application/views/scripts/dashboard/settings.phtml @@ -24,23 +24,32 @@ getName(); ?>
- - getTitle(); ?> - - - getUrl(); ?> - - - icon('remove.png'); ?> - + + translate('No compoments added to dashboard') ?>.
+ + getTitle(); ?> + + + getUrl(); ?> + + + icon('remove.png'); ?> + +
diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 0ab210057..5b6376d32 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -211,7 +211,10 @@ EOD; { return sprintf( '%s', - Url::fromRequest(array('remove' => $this->getTitle())), + Url::fromPath('dashboard/remove-component', array( + 'component' => $this->getTitle(), + 'pane' => $this->pane->getTitle() + )), t('Remove') ); } diff --git a/library/Icinga/Web/Widget/Tabextension/DashboardAction.php b/library/Icinga/Web/Widget/Tabextension/DashboardAction.php index a8cce1cc0..9ed5f34ef 100644 --- a/library/Icinga/Web/Widget/Tabextension/DashboardAction.php +++ b/library/Icinga/Web/Widget/Tabextension/DashboardAction.php @@ -26,7 +26,7 @@ class DashboardAction implements Tabextension array( 'icon' => 'dashboard', 'title' => 'Add To Dashboard', - 'url' => Url::fromPath('dashboard/addurl'), + 'url' => Url::fromPath('dashboard/new-component'), 'urlParams' => array( 'url' => rawurlencode(Url::fromRequest()->getRelativeUrl()) ) diff --git a/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php b/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php index 4242f864d..c30db4235 100644 --- a/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php +++ b/library/Icinga/Web/Widget/Tabextension/DashboardSettings.php @@ -24,7 +24,7 @@ class DashboardSettings implements Tabextension array( 'icon' => 'img/icons/dashboard.png', 'title' => t('Add To Dashboard'), - 'url' => Url::fromPath('dashboard/addurl') + 'url' => Url::fromPath('dashboard/new-component') ) ); From 80871313e4e9609b687c93a9f98a0da0c68d2a94 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 18 Nov 2014 16:28:04 +0100 Subject: [PATCH 21/61] Dashboard: Remove actions refs #4537 --- .../controllers/DashboardController.php | 31 ++++++++ .../views/scripts/dashboard/index.phtml | 10 +-- .../views/scripts/dashboard/remove-pane.phtml | 14 ++++ .../views/scripts/dashboard/settings.phtml | 5 ++ library/Icinga/Web/Widget/Dashboard.php | 71 +++++++++++++++++-- .../Icinga/Web/Widget/Dashboard/Component.php | 2 +- library/Icinga/Web/Widget/Dashboard/Pane.php | 39 +++++++++- 7 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 application/views/scripts/dashboard/remove-pane.phtml diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index a28e1485a..896cb6c19 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -150,6 +150,37 @@ class DashboardController extends ActionController $this->view->form = $form; } + public function removePaneAction() + { + $form = new ConfirmRemovalForm(); + $this->createTabs(); + $dashboard = $this->dashboard; + if (! $this->_request->getParam('pane')) { + throw new Zend_Controller_Action_Exception( + 'Missing parameter "pane"', + 400 + ); + } + $pane = $this->_request->getParam('pane'); + $form->setOnSuccess(function (Request $request, Form $form) use ($dashboard, $pane) { + try { + $pane = $dashboard->getPane($pane); + $dashboard->removePane($pane->getTitle()); + $dashboard->write(); + Notification::success(t('Pane has been removed') . ': ' . $pane->getTitle()); + return true; + } catch (ProgrammingError $e) { + Notification::error($e->getMessage()); + return false; + } + return false; + }); + $form->setRedirectUrl('dashboard/settings'); + $form->handleRequest(); + $this->view->pane = $pane; + $this->view->form = $form; + } + /** * Display the dashboard with the pane set in the 'pane' request parameter * diff --git a/application/views/scripts/dashboard/index.phtml b/application/views/scripts/dashboard/index.phtml index 4adad7b66..7c3724dc6 100644 --- a/application/views/scripts/dashboard/index.phtml +++ b/application/views/scripts/dashboard/index.phtml @@ -8,9 +8,11 @@

escape($this->translate('Welcome to Icinga Web!')) ?>

-

escape($this->translate('Currently there is no dashlet available. This might change once you enabled some of the available %s.')), - $this->qlink($this->translate('modules'), 'config/modules') - ) ?>

+

+ escape($this->translate('Currently there is no dashlet available. This might change once you enabled some of the available %s.')), + $this->qlink($this->translate('modules'), 'config/modules') + ) ?> +

\ No newline at end of file diff --git a/application/views/scripts/dashboard/remove-pane.phtml b/application/views/scripts/dashboard/remove-pane.phtml new file mode 100644 index 000000000..637774cab --- /dev/null +++ b/application/views/scripts/dashboard/remove-pane.phtml @@ -0,0 +1,14 @@ +
+ tabs ?> +
+ +
+

+ +

+ translate('Please confirm the removal of'); ?>: + pane; ?> +

+ + form; ?> +
\ No newline at end of file diff --git a/application/views/scripts/dashboard/settings.phtml b/application/views/scripts/dashboard/settings.phtml index 76a66a0d2..ebe0188c4 100644 --- a/application/views/scripts/dashboard/settings.phtml +++ b/application/views/scripts/dashboard/settings.phtml @@ -23,6 +23,11 @@ getName(); ?> + + + icon('remove.png'); ?> + + getComponents(); ?> diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 1764e5cea..1dc7cf4fd 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -7,7 +7,9 @@ namespace Icinga\Web\Widget; use Icinga\Application\Icinga; use Icinga\Application\Config; use Icinga\Exception\ConfigurationError; +use Icinga\Exception\NotReadableError; use Icinga\Exception\ProgrammingError; +use Icinga\Exception\SystemPermissionException; use Icinga\File\Ini\IniWriter; use Icinga\User; use Icinga\Web\Widget\Dashboard\Pane; @@ -78,6 +80,7 @@ class Dashboard extends AbstractWidget if ($this->user !== null) { $this->loadUserDashboards(); } + return $this; } @@ -117,9 +120,16 @@ class Dashboard extends AbstractWidget $components = array(); foreach ($config as $key => $part) { if (strpos($key, '.') === false) { - $panes[$key] = new Pane($key); - $panes[$key]->setTitle($part->title); + if ($this->hasPane($part->title)) { + $panes[$key] = $this->getPane($part->title); + } else { + $panes[$key] = new Pane($key); + $panes[$key]->setTitle($part->title); + } $panes[$key]->setUserWidget(); + if ((bool) $part->get('disabled', false) === true) { + $panes[$key]->setDisabled(); + } } else { list($paneName, $componentName) = explode('.', $key, 2); @@ -168,7 +178,13 @@ class Dashboard extends AbstractWidget { /** @var $pane Pane */ foreach ($panes as $pane) { - if (array_key_exists($pane->getName(), $this->panes)) { + if ($pane->getDisabled()) { + if ($this->hasPane($pane->getTitle()) === true) { + $this->removePane($pane->getTitle()); + } + continue; + } + if ($this->hasPane($pane->getTitle()) === true) { /** @var $current Pane */ $current = $this->panes[$pane->getName()]; $current->addComponents($pane->getComponents()); @@ -242,6 +258,17 @@ class Dashboard extends AbstractWidget return ! empty($this->panes); } + /** + * Check if a panel exist + * + * @param string $pane + * @return bool + */ + public function hasPane($pane) + { + return $pane && array_key_exists($pane, $this->panes); + } + /** * Add a pane object to this dashboard * @@ -255,6 +282,21 @@ class Dashboard extends AbstractWidget return $this; } + public function removePane($title) + { + if ($this->hasPane($title) === true) { + $pane = $this->getPane($title); + if ($pane->isUserWidget() === true) { + unset($this->panes[$pane->getName()]); + } else { + $pane->setDisabled(); + $pane->setUserWidget(); + } + } else { + throw new ProgrammingError('Pane not found: ' . $title); + } + } + /** * Return the pane with the provided name * @@ -296,6 +338,7 @@ class Dashboard extends AbstractWidget if (empty($this->panes)) { return ''; } + return $this->determineActivePane()->render(); } @@ -382,6 +425,26 @@ class Dashboard extends AbstractWidget if ($this->user === null) { return ''; } - return '/var/lib/icingaweb/' . $this->user->getUsername() . '/dashboard.ini'; + + $baseDir = '/var/lib/icingaweb'; + + if (! file_exists($baseDir)) { + throw new NotReadableError('Could not read: ' . $baseDir); + } + + $userDir = $baseDir . '/' . $this->user->getUsername(); + + if (! file_exists($userDir)) { + $success = @mkdir($userDir); + if (!$success) { + throw new SystemPermissionException('Could not create: ' . $userDir); + } + } + + if (! file_exists($userDir)) { + throw new NotReadableError('Could not read: ' . $userDir); + } + + return $userDir . '/dashboard.ini'; } } diff --git a/library/Icinga/Web/Widget/Dashboard/Component.php b/library/Icinga/Web/Widget/Dashboard/Component.php index 5b6376d32..ed382756b 100644 --- a/library/Icinga/Web/Widget/Dashboard/Component.php +++ b/library/Icinga/Web/Widget/Dashboard/Component.php @@ -53,7 +53,7 @@ class Component extends UserWidget private $template =<<<'EOD'
-

{TITLE} ({REMOVE})

+

{TITLE}

diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php index 26cd46e44..97b8c1031 100644 --- a/library/Icinga/Web/Widget/Dashboard/Pane.php +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -36,6 +36,13 @@ class Pane extends UserWidget */ private $components = array(); + /** + * Disabled flag of a pane + * + * @var bool + */ + private $disabled; + /** * Create a new pane * @@ -253,9 +260,15 @@ class Pane extends UserWidget */ public function toArray() { - return array( - 'title' => $this->getTitle() + $pane = array( + 'title' => $this->getTitle(), ); + + if ($this->getDisabled() === true) { + $pane['disabled'] = 1; + } + + return $pane; } /** @@ -274,4 +287,26 @@ class Pane extends UserWidget } return $pane; } + + /** + * Setter for disabled + * + * @param boolean $disabled + */ + public function setDisabled($disabled = true) + { + $this->disabled = (bool) $disabled; + } + + /** + * Getter for disabled + * + * @return boolean + */ + public function getDisabled() + { + return $this->disabled; + } + + } From f2717b6d2661d262b0db78123a1fb8f479925922 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Tue, 4 Nov 2014 16:15:06 +0100 Subject: [PATCH 22/61] Introduce Form::setOnSuccess() in favor of overriding the constructor Zend_Form uses setters for options if a respective setter method exists. It is not necessary to override the constructor for introducing new options. Conflicts: library/Icinga/Web/Form.php --- .../controllers/DashboardController.php | 22 ++++++++++++++----- application/forms/Dashboard/ComponentForm.php | 20 ----------------- library/Icinga/Web/Form.php | 20 +++++++++++++++++ library/Icinga/Web/Widget/Dashboard.php | 4 +++- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 896cb6c19..105b40762 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -44,7 +44,7 @@ class DashboardController extends ActionController $params['url'] = rawurldecode($this->_request->getParam('url')); $form->populate($params); } - $form->setOnSuccess(function (Request $request, Form $form) use ($dashboard) { + $form->setOnSuccess(function (Form $form) use ($dashboard) { try { $pane = $dashboard->getPane($form->getValue('pane')); } catch (ProgrammingError $e) { @@ -83,8 +83,14 @@ class DashboardController extends ActionController 400 ); } - $form->setOnSuccess(function (Request $request, Form $form) use ($dashboard) { - $pane = $dashboard->getPane($form->getValue('pane')); + $form->setOnSuccess(function (Form $form) use ($dashboard) { + try { + $pane = $dashboard->getPane($form->getValue('pane')); + } catch (ProgrammingError $e) { + $pane = new Dashboard\Pane($form->getValue('pane')); + $pane->setUserWidget(); + $dashboard->addPane($pane); + } try { $component = $pane->getComponent($form->getValue('component')); $component->setUrl($form->getValue('url')); @@ -97,7 +103,11 @@ class DashboardController extends ActionController if ($form->getValue('org_component') && $form->getValue('org_component') !== $component->getTitle()) { $pane->removeComponent($form->getValue('org_component')); } - $dashboard->write(); + // Move + if ($form->getValue('org_pane') && $form->getValue('org_pane') !== $pane->getTitle()) { + $oldPane = $dashboard->getPane($form->getValue('org_pane')); + $oldPane->removeComponent($component->getTitle()); + } $dashboard->write(); Notification::success(t('Component updated')); return true; @@ -130,7 +140,7 @@ class DashboardController extends ActionController } $pane = $this->_request->getParam('pane'); $component = $this->_request->getParam('component'); - $form->setOnSuccess(function (Request $request, Form $form) use ($dashboard, $component, $pane) { + $form->setOnSuccess(function (Form $form) use ($dashboard, $component, $pane) { try { $pane = $dashboard->getPane($pane); $pane->removeComponent($component); @@ -162,7 +172,7 @@ class DashboardController extends ActionController ); } $pane = $this->_request->getParam('pane'); - $form->setOnSuccess(function (Request $request, Form $form) use ($dashboard, $pane) { + $form->setOnSuccess(function (Form $form) use ($dashboard, $pane) { try { $pane = $dashboard->getPane($pane); $dashboard->removePane($pane->getTitle()); diff --git a/application/forms/Dashboard/ComponentForm.php b/application/forms/Dashboard/ComponentForm.php index c62bf82fe..54aa4c33d 100644 --- a/application/forms/Dashboard/ComponentForm.php +++ b/application/forms/Dashboard/ComponentForm.php @@ -161,26 +161,6 @@ class ComponentForm extends Form ); } - /** - * Adjust preferences and persist them - * - * @see Form::onSuccess() - */ - public function onSuccess(Request $request) - { - return true; - } - - /** - * Populate data if any - * - * @see Form::onRequest() - */ - public function onRequest(Request $request) - { - return true; - } - /** * @param \Icinga\Web\Widget\Dashboard $dashboard */ diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index 8d75a9df3..863d4f1c1 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -163,6 +163,26 @@ class Form extends Zend_Form parent::__construct($options); } + /** + * Set a callback that is called instead of this form's onSuccess method + * + * It is called using the following signature: (Request $request, Form $form). + * + * @param callable $onSuccess Callback + * + * @return $this + * + * @throws LogicException If the callback is not callable + */ + public function setOnSuccess($onSuccess) + { + if (! is_callable($onSuccess)) { + throw new LogicException('The option `onSuccess\' is not callable'); + } + $this->onSuccess = $onSuccess; + return $this; + } + /** * Set the label to use for the standard submit button * diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index 1dc7cf4fd..ccc8cf279 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -6,6 +6,7 @@ namespace Icinga\Web\Widget; use Icinga\Application\Icinga; use Icinga\Application\Config; +use Icinga\Data\ConfigObject; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotReadableError; use Icinga\Exception\ProgrammingError; @@ -102,7 +103,8 @@ class Dashboard extends AbstractWidget } } - $config = new Config($output); + $co = new ConfigObject($output); + $config = new Config($co); $writer = new IniWriter(array('config' => $config, 'filename' => $configFile)); $writer->write(); } From 6269f6695b9d1cf3110478b26a95b1f212ba5612 Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Tue, 18 Nov 2014 17:18:12 +0100 Subject: [PATCH 23/61] Add quick filter for event types to event overview Add a new filter form for event types to the eventhistoryAction and add selected to filter on post refs #7695 --- .../controllers/ListController.php | 21 +++ .../application/forms/EventOverviewForm.php | 160 ++++++++++++++++++ .../views/scripts/list/eventhistory.phtml | 3 + public/css/icinga/forms.less | 16 ++ 4 files changed, 200 insertions(+) create mode 100644 modules/monitoring/application/forms/EventOverviewForm.php diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 821b6df79..50eff1ea6 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -537,6 +537,24 @@ class Monitoring_ListController extends Controller } $this->addTitleTab('eventhistory', $this->translate('Event Overview')); + $form = new EventOverviewForm(); + $form->handleRequest($this->getRequest()); + $this->view->form = $form; + + if ($this->getRequest()->isPost()) { + // update filter string + $filters = $form->getFilter(); + $url = $this->_request->getUrl(); + $url->setQueryString($filters->toQueryString()); + if ($this->getParam('sort') !== null) { + $url->setParam('sort', $this->getParam('sort')); + } + if ($this->getParam('dir') !== null) { + $url->setParam('dir', $this->getParam('dir')); + } + return $this->redirectNow($url); + } + $query = $this->backend->select()->from('eventHistory', array( 'host_name', 'service_description', @@ -550,6 +568,9 @@ class Monitoring_ListController extends Controller 'host', 'service' )); + if ($this->getParam('state')) { + $query->applyFilter(Filter::expression('state', '=', $this->getParam('state'))); + } $this->setupSortControl(array( 'timestamp' => 'Occurence' diff --git a/modules/monitoring/application/forms/EventOverviewForm.php b/modules/monitoring/application/forms/EventOverviewForm.php new file mode 100644 index 000000000..25d268f76 --- /dev/null +++ b/modules/monitoring/application/forms/EventOverviewForm.php @@ -0,0 +1,160 @@ +setName('form_event_overview'); + $this->setDecorators(array( + 'FormElements', + array('HtmlTag', array('tag' => 'div', 'class' => 'hbox')), + 'Form' + )); + } + + /** + * @see Form::createElements() + */ + public function createElements(array $formData) + { + $decorators = array( + array('Label', array('class' => 'optional')), + 'ViewHelper', + array('HtmlTag', array('tag' => 'div', 'class' => 'hbox-item optionbox')), + ); + + $url = Url::fromRequest()->getAbsoluteUrl(); + $this->addElement( + 'checkbox', + 'statechange', + array( + 'label' => t('State Changes'), + 'class' => 'autosubmit', + 'decorators' => $decorators, + 'value' => strpos($url, $this->stateChangeFilter()->toQueryString()) === false ? 0 : 1 + ) + ); + $this->addElement( + 'checkbox', + 'downtime', + array( + 'label' => t('Downtimes'), + 'class' => 'autosubmit', + 'decorators' => $decorators, + 'value' => strpos($url, $this->downtimeFilter()->toQueryString()) === false ? 0 : 1 + ) + ); + $this->addElement( + 'checkbox', + 'comment', + array( + 'label' => t('Comments'), + 'class' => 'autosubmit', + 'decorators' => $decorators, + 'value' => strpos($url, $this->commentFilter()->toQueryString()) === false ? 0 : 1 + ) + ); + $this->addElement( + 'checkbox', + 'notification', + array( + 'label' => t('Notifications'), + 'class' => 'autosubmit', + 'decorators' => $decorators, + 'value' => strpos($url, $this->notificationFilter()->toQueryString()) === false ? 0 : 1 + ) + ); + $this->addElement( + 'checkbox', + 'flapping', + array( + 'label' => t('Flapping'), + 'class' => 'autosubmit', + 'decorators' => $decorators, + 'value' => strpos($url, $this->flappingFilter()->toQueryString()) === false ? 0 : 1 + ) + ); + } + + /** + * Return the corresponding filter-object + * + * @returns Filter + */ + public function getFilter() + { + $filters = array(); + if ($this->getValue('statechange', 1)) { + $filters[] = $this->stateChangeFilter(); + } + if ($this->getValue('comment', 1)) { + $filters[] = $this->commentFilter(); + } + if ($this->getValue('notification', 1)) { + $filters[] = $this->notificationFilter(); + } + if ($this->getValue('downtime', 1)) { + $filters[] = $this->downtimeFilter(); + } + if ($this->getValue('flapping', 1)) { + $filters[] = $this->flappingFilter(); + } + return Filter::matchAny($filters); + } + + public function stateChangeFilter() + { + return Filter::matchAny( + Filter::expression('type', '=', 'hard_state'), + Filter::expression('type', '=', 'soft_state') + ); + } + + public function commentFilter() + { + return Filter::matchAny( + Filter::expression('type', '=', 'comment'), + Filter::expression('type', '=', 'comment_deleted'), + Filter::expression('type', '=', 'dt_comment'), + Filter::expression('type', '=', 'dt_comment_deleted'), + Filter::expression('type', '=', 'ack') + ); + } + + public function notificationFilter() + { + return Filter::expression('type', '=', 'notify'); + } + + public function downtimeFilter() + { + return Filter::matchAny( + Filter::expression('type', '=', 'downtime_start'), + Filter::expression('type', '=', 'downtime_end') + ); + } + + public function flappingFilter() + { + return Filter::matchAny( + Filter::expression('type', '=', 'flapping'), + Filter::expression('type', '=', 'flapping_deleted') + ); + } +} diff --git a/modules/monitoring/application/views/scripts/list/eventhistory.phtml b/modules/monitoring/application/views/scripts/list/eventhistory.phtml index 97eda5354..62b635763 100644 --- a/modules/monitoring/application/views/scripts/list/eventhistory.phtml +++ b/modules/monitoring/application/views/scripts/list/eventhistory.phtml @@ -4,6 +4,9 @@
translate('Sort by'); ?> sortControl->render($this); ?>
+ + +
widget('limiter', array('url' => $this->url, 'max' => $this->history->count())); ?> paginationControl($history, null, null, array('preserve' => $this->preserve)); ?>
diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 2acb3d4d2..33a7fdd01 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -195,3 +195,19 @@ textarea { input, select, textarea { display: inline; } + +.optionbox { + margin-left: 0em; + margin-right: 3em; +} + +.optionbox label { + max-width: 6.5em; + text-align: left; + vertical-align: middle; + margin-right: 0em; +} + +.optionbox input { + vertical-align: middle; +} From 8c3dbb2b45b758f214752819a02c07ea785f6f71 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 18 Nov 2014 17:26:28 +0100 Subject: [PATCH 24/61] Dashbosrd: Fix tests refs #4537 --- .../Icinga/Web/Widget/DashboardTest.php | 107 +----------------- 1 file changed, 5 insertions(+), 102 deletions(-) diff --git a/test/php/library/Icinga/Web/Widget/DashboardTest.php b/test/php/library/Icinga/Web/Widget/DashboardTest.php index be11c42fe..21727480b 100644 --- a/test/php/library/Icinga/Web/Widget/DashboardTest.php +++ b/test/php/library/Icinga/Web/Widget/DashboardTest.php @@ -131,7 +131,8 @@ class DashboardTest extends BaseTestCase */ public function testLoadPaneItemsProvidedByEnabledModules() { - $dashboard = Dashboard::load(); + $dashboard = new Dashboard(); + $dashboard->load(); $this->assertCount( 1, @@ -270,71 +271,15 @@ class DashboardTest extends BaseTestCase $component2 = new Component('test2', 'test2', $pane); $pane->addComponent($component2); - $dashboard->removeComponent('test1', 'test'); - + $dashboard->getPane('test1')->removeComponent('test'); $result = $dashboard->getPane('test1')->hasComponent('test'); - $this->assertFalse( + $this->assertTrue( $result, 'Dashboard::removeComponent() could not remove component from the pane' ); } - /** - * @depends testWhetherGetPaneReturnsAPaneByName - */ - public function testWhetherRemoveComponentRemovesComponentByConcatenation() - { - $dashboard = new Dashboard(); - $dashboard->createPane('test1'); - $pane = $dashboard->getPane('test1'); - - $component = new Component('test', 'test', $pane); - $pane->addComponent($component); - - $component2 = new Component('test2', 'test2', $pane); - $pane->addComponent($component2); - - $dashboard->removeComponent('test1.test', null); - - $result = $dashboard->getPane('test1')->hasComponent('test'); - - $this->assertFalse( - $result, - 'Dashboard::removeComponent() could not remove component from the pane' - ); - } - - /** - * @depends testWhetherGetPaneReturnsAPaneByName - */ - public function testWhetherToArrayReturnsDashboardStructureAsArray() - { - $dashboard = new Dashboard(); - $dashboard->createPane('test1'); - $pane = $dashboard->getPane('test1'); - - $component = new Component('test', 'test', $pane); - $pane->addComponent($component); - - $result = $dashboard->toArray(); - - $expected = array( - 'test1' => array( - 'title' => 'test1' - ), - 'test1.test' => array( - 'url' => 'test' - ) - ); - - $this->assertEquals( - $expected, - $result, - 'Dashboard::toArray() could not return valid expectation' - ); - } - /** * @depends testWhetherGetPaneReturnsAPaneByName */ @@ -346,7 +291,7 @@ class DashboardTest extends BaseTestCase $component = new Component('test', 'test', $pane); $pane->addComponent($component); - $dashboard->setComponentUrl('test1', 'test', 'new'); + $dashboard->getPane('test1')->getComponent('test')->setUrl('new'); $this->assertEquals( 'new', @@ -355,48 +300,6 @@ class DashboardTest extends BaseTestCase ); } - /** - * @depends testWhetherGetPaneReturnsAPaneByName - */ - public function testWhetherSetComponentUrlUpdatesTheComponentUrlConcatenation() - { - $dashboard = new Dashboard(); - $dashboard->createPane('test1'); - $pane = $dashboard->getPane('test1'); - $component = new Component('test', 'test', $pane); - $pane->addComponent($component); - - $dashboard->setComponentUrl('test1.test', null, 'new'); - - $this->assertEquals( - 'new', - $component->getUrl()->getPath(), - 'Dashboard::setComponentUrl() could not return valid expectation' - ); - } - - /** - * @depends testWhetherGetPaneReturnsAPaneByName - */ - public function testWhetherSetComponentUrlUpdatesTheComponentUrlNotExistentPane() - { - $dashboard = new Dashboard(); - $dashboard->createPane('test1'); - $pane = $dashboard->getPane('test1'); - $component = new Component('test', 'test', $pane); - $pane->addComponent($component); - - $dashboard->setComponentUrl('test3.test', null, 'new'); - - $result = $dashboard->getPane('test3')->getComponent('test'); - - $this->assertEquals( - 'new', - $result->getUrl()->getPath(), - 'Dashboard::setComponentUrl() could not return valid expectation' - ); - } - /** * @expectedException \Icinga\Exception\ConfigurationError */ From 5ace5fd2dc3379a60a8c771eba00dd3aea155bd9 Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Tue, 18 Nov 2014 17:47:57 +0100 Subject: [PATCH 25/61] Dashboard: Change icons refs #4537 --- application/views/scripts/dashboard/settings.phtml | 4 ++-- library/Icinga/Web/Widget/Dashboard/Pane.php | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/application/views/scripts/dashboard/settings.phtml b/application/views/scripts/dashboard/settings.phtml index ebe0188c4..b14c236df 100644 --- a/application/views/scripts/dashboard/settings.phtml +++ b/application/views/scripts/dashboard/settings.phtml @@ -25,7 +25,7 @@ - icon('remove.png'); ?> + icon('cancel'); ?> @@ -49,7 +49,7 @@ - icon('remove.png'); ?> + icon('cancel'); ?> diff --git a/library/Icinga/Web/Widget/Dashboard/Pane.php b/library/Icinga/Web/Widget/Dashboard/Pane.php index 4773d69b7..4ba9f27dc 100644 --- a/library/Icinga/Web/Widget/Dashboard/Pane.php +++ b/library/Icinga/Web/Widget/Dashboard/Pane.php @@ -141,9 +141,11 @@ class Pane extends UserWidget if ($component->isUserWidget() === true) { unset($this->components[$title]); } else { - $component->setUserWidget(); $component->setDisabled(true); + $component->setUserWidget(); } + } else { + throw new ProgrammingError('Component does not exist: ' . $title); } return $this; } From 268dc7e4b14bf685a8fb12e5b6c3a0ce57a1896f Mon Sep 17 00:00:00 2001 From: Alexander Fuhr Date: Tue, 18 Nov 2014 18:06:36 +0100 Subject: [PATCH 26/61] Fix the add link to the resource configuration refs #7493 --- .../forms/Config/BackendConfigForm.php | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/modules/monitoring/application/forms/Config/BackendConfigForm.php b/modules/monitoring/application/forms/Config/BackendConfigForm.php index f467b8f59..4b1aa65b6 100644 --- a/modules/monitoring/application/forms/Config/BackendConfigForm.php +++ b/modules/monitoring/application/forms/Config/BackendConfigForm.php @@ -237,18 +237,28 @@ class BackendConfigForm extends ConfigForm ) ); - $resourceName = (isset($formData['resource'])) ? $formData['resource'] : $this->getValue('resource'); - if ($resourceElement) { - $resourceElement->getDecorator('Description')->setEscape(false); - $link = sprintf( - '%s', - $this->getView()->href('/icingaweb/config/editresource', array('resource' => $resourceName)), - mt('monitoring', 'Show resource configuration') - ); - $resourceElement->setDescription($resourceElement->getDescription() . ' (' . $link . ')'); + if (empty($formData)) { + $options = $resourceElement->options; + $resourceName = array_shift($options); + } else { + $resourceName = (isset($formData['resource'])) ? $formData['resource'] : $this->getValue('resource'); } $this->addElement($resourceElement); + if ($resourceElement) { + $this->addElement( + 'note', + 'resource_note', + array( + 'value' => sprintf( + '%s', + $this->getView()->href('/icingaweb/config/editresource', array('resource' => $resourceName)), + mt('monitoring', 'Show resource configuration') + ), + 'escape' => false + ) + ); + } } } From a4f4c8d27fc5219032aa18baa17ceaf3b1f5d74d Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Tue, 18 Nov 2014 19:12:53 +0100 Subject: [PATCH 27/61] Support filter editing in event history Add a FilterEditor to the eventhistory view, fix CSS layout resolves #6979 --- .../application/controllers/ListController.php | 2 +- .../views/scripts/list/eventhistory.phtml | 10 +++++++--- modules/monitoring/public/css/module.less | 16 ++++++++++++++++ public/css/icinga/forms.less | 16 ---------------- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 50eff1ea6..a58304cd6 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -541,7 +541,7 @@ class Monitoring_ListController extends Controller $form->handleRequest($this->getRequest()); $this->view->form = $form; - if ($this->getRequest()->isPost()) { + if ($this->getRequest()->isPost() && !$this->getParam('modifyFilter')) { // update filter string $filters = $form->getFilter(); $url = $this->_request->getUrl(); diff --git a/modules/monitoring/application/views/scripts/list/eventhistory.phtml b/modules/monitoring/application/views/scripts/list/eventhistory.phtml index 62b635763..6bc06e2c9 100644 --- a/modules/monitoring/application/views/scripts/list/eventhistory.phtml +++ b/modules/monitoring/application/views/scripts/list/eventhistory.phtml @@ -5,11 +5,15 @@ translate('Sort by'); ?> sortControl->render($this); ?> - -
widget('limiter', array('url' => $this->url, 'max' => $this->history->count())); ?> paginationControl($history, null, null, array('preserve' => $this->preserve)); ?> - + +

+ + +
+ filterEditor ?> +
diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 1b2a5b67d..384d1c923 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -158,3 +158,19 @@ table.avp .customvar ul { div.selection-info { padding-top:1em; } + +.optionbox { + margin-left: 0em; + margin-right: 3em; +} + +.optionbox label { + max-width: 6.5em; + text-align: left; + vertical-align: middle; + margin-right: 0em; +} + +.optionbox input { + vertical-align: middle; +} diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less index 33a7fdd01..2acb3d4d2 100644 --- a/public/css/icinga/forms.less +++ b/public/css/icinga/forms.less @@ -195,19 +195,3 @@ textarea { input, select, textarea { display: inline; } - -.optionbox { - margin-left: 0em; - margin-right: 3em; -} - -.optionbox label { - max-width: 6.5em; - text-align: left; - vertical-align: middle; - margin-right: 0em; -} - -.optionbox input { - vertical-align: middle; -} From e97f08663e2688d9cc2a37b1b3d2968df09a85fb Mon Sep 17 00:00:00 2001 From: Alexander Fuhr Date: Tue, 18 Nov 2014 19:40:22 +0100 Subject: [PATCH 28/61] Move process info and performance info overview into monitoring health The process info and the performance info overviews are now moved to monitoring health and are available both under the 'Monitoring Health' section. But this is not the final look, we should redesign it and add more relative information data and drop unused --- .../controllers/ProcessController.php | 22 +- .../views/scripts/process/info.phtml | 212 ++++++++++++++---- modules/monitoring/configuration.php | 6 +- public/css/icinga/main-content.less | 4 + public/css/icinga/monitoring-colors.less | 7 + 5 files changed, 189 insertions(+), 62 deletions(-) diff --git a/modules/monitoring/application/controllers/ProcessController.php b/modules/monitoring/application/controllers/ProcessController.php index e843d8ecd..ca879cbaa 100644 --- a/modules/monitoring/application/controllers/ProcessController.php +++ b/modules/monitoring/application/controllers/ProcessController.php @@ -23,16 +23,9 @@ class Monitoring_ProcessController extends Controller ->add( 'info', array( - 'title' => $this->translate('Process Info'), + 'title' => $this->translate('Monitoring Health'), 'url' =>'monitoring/process/info' ) - ) - ->add( - 'performance', - array( - 'title' => $this->translate('Performance Info'), - 'url' => 'monitoring/process/performance' - ) ); } @@ -41,7 +34,7 @@ class Monitoring_ProcessController extends Controller */ public function infoAction() { - $this->view->title = $this->translate('Process Info'); + $this->view->title = $this->translate('Monitoring Health'); $this->getTabs()->activate('info'); $this->setAutorefreshInterval(10); $this->view->backendName = $this->backend->getName(); @@ -80,6 +73,14 @@ class Monitoring_ProcessController extends Controller ->load($programStatus) ->handleRequest(); $this->view->toggleFeaturesForm = $toggleFeaturesForm; + + $this->view->runtimevariables = (object) $this->backend->select() + ->from('runtimevariables', array('varname', 'varvalue')) + ->getQuery()->fetchPairs(); + + $this->view->checkperformance = $this->backend->select() + ->from('runtimesummary') + ->getQuery()->fetchAll(); } /** @@ -111,6 +112,9 @@ class Monitoring_ProcessController extends Controller } } + /** + * @todo should be dropped later + */ public function performanceAction() { $this->getTabs()->activate('performance'); diff --git a/modules/monitoring/application/views/scripts/process/info.phtml b/modules/monitoring/application/views/scripts/process/info.phtml index c659544c2..33f7c557c 100644 --- a/modules/monitoring/application/views/scripts/process/info.phtml +++ b/modules/monitoring/application/views/scripts/process/info.phtml @@ -1,55 +1,171 @@ +runtimeVariables()->create($this->runtimevariables); +$cp = $this->checkPerformance()->create($this->checkperformance); + +?>
tabs ?>
- programStatus->is_currently_running === true): ?> -
- translate('%s has been up and running with PID %d since %s'), - $this->backendName, - $this->programStatus->process_id, - $this->timeSince($this->programStatus->program_start_time)) ?> +
+ +
+

translate('Feature Commands') ?>

+ toggleFeaturesForm ?> +
+ +
+

translate('Process Info') ?>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
translate('Program Start Time') ?>dateFormat()->formatDateTime($this->programStatus->program_start_time) ?>
translate('Last Status Update'); ?>timeSince($this->programStatus->status_update_time) ?> ago
translate('Last External Command Check'); ?>timeSince($this->programStatus->last_command_check) ?> ago
translate('Last Log File Rotation'); ?>programStatus->last_log_rotation + ? $this->timeSince($this->programStatus->last_log_rotation) + : $this->translate('N/A') ?>
translate('Global Service Event Handler'); ?>programStatus->global_service_event_handler + ? $this->programStatus->global_service_event_handler + : $this->translate('N/A'); ?>
translate('Global Host Event Handler'); ?>programStatus->global_host_event_handler + ? $this->programStatus->global_host_event_handler + : $this->translate('N/A'); ?>
+ programStatus->is_currently_running === true): ?> +
+ translate('%s has been up and running with PID %d since %s'), + $this->backendName, + $this->programStatus->process_id, + $this->timeSince($this->programStatus->program_start_time)) ?> +
+ +
+ translate('%s is not running'), $this->backendName) ?> +
+ +
+ +
+

translate('Performance Info') ?>

+ +

Object summaries

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
overallscheduled
+ Hosts + + total_hosts; ?> + + total_scheduled_hosts; ?> +
+ Services + + total_services; ?> + + total_scheduled_services; ?> +
+ Average services per host + + average_services_per_host); ?> + + average_scheduled_services_per_host); ?> +
+ +

Active checks

+ + + + + + + + + + + + + + + + + + + + + + + +
LatencyExecution time
+ Host Checks + host_active_count; ?>host_active_latency_avg); ?>shost_active_execution_avg); ?>s
+ Service Checks + service_active_count; ?>service_active_latency_avg); ?>sservice_active_execution_avg); ?>s
+ +

Passive checks

+ + + + + + + + + + + +
+ Host Checks + host_passive_count; ?>
+ Service Checks + service_passive_count; ?>
+
+
- -
- translate('%s is not running'), $this->backendName) ?> -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
translate('Program Start Time') ?>dateFormat()->formatDateTime($this->programStatus->program_start_time) ?>
translate('Last Status Update'); ?>timeSince($this->programStatus->status_update_time) ?> ago
translate('Last External Command Check'); ?>timeSince($this->programStatus->last_command_check) ?> ago
translate('Last Log File Rotation'); ?>programStatus->last_log_rotation - ? $this->timeSince($this->programStatus->last_log_rotation) - : $this->translate('N/A') ?>
translate('Global Service Event Handler'); ?>programStatus->global_service_event_handler - ? $this->programStatus->global_service_event_handler - : $this->translate('N/A'); ?>
translate('Global Host Event Handler'); ?>programStatus->global_host_event_handler - ? $this->programStatus->global_host_event_handler - : $this->translate('N/A'); ?>
-
- toggleFeaturesForm ?>
diff --git a/modules/monitoring/configuration.php b/modules/monitoring/configuration.php index 64d8cb2fd..485050638 100644 --- a/modules/monitoring/configuration.php +++ b/modules/monitoring/configuration.php @@ -136,14 +136,10 @@ $section->add($this->translate('Alert Summary'), array( * System Section */ $section = $this->menuSection($this->translate('System')); -$section->add($this->translate('Process Info'), array( +$section->add($this->translate('Monitoring Health'), array( 'url' => 'monitoring/process/info', 'priority' => 120 )); -$section->add($this->translate('Performance Info'), array( - 'url' => 'monitoring/process/performance', - 'priority' => 130 -)); /* * Dashboard diff --git a/public/css/icinga/main-content.less b/public/css/icinga/main-content.less index dd9c89c92..8a759f736 100644 --- a/public/css/icinga/main-content.less +++ b/public/css/icinga/main-content.less @@ -173,3 +173,7 @@ table.benchmark { .dashboard table.benchmark { font-size: 0.9em; } + +.left { + text-align: left !important; +} diff --git a/public/css/icinga/monitoring-colors.less b/public/css/icinga/monitoring-colors.less index 17a7b59fe..7beee80d0 100644 --- a/public/css/icinga/monitoring-colors.less +++ b/public/css/icinga/monitoring-colors.less @@ -311,6 +311,13 @@ a.critical { .boxview div.box h2:first-child > a:hover { } +.boxview div.box h3 { + line-height: 1.5em; + font-size: 0.9em; + color: #555; + border-bottom: 1px solid #d9d9d9; +} + /* Box body of contents */ .boxview div.box.contents { padding: 0.2em; From 4d4d19a7ef63543ee14b592205daca55ba7c853c Mon Sep 17 00:00:00 2001 From: Alexander Fuhr Date: Tue, 18 Nov 2014 19:45:58 +0100 Subject: [PATCH 29/61] Add `translate()' to untranslated stringw in monitoring health overview --- .../views/scripts/process/info.phtml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/monitoring/application/views/scripts/process/info.phtml b/modules/monitoring/application/views/scripts/process/info.phtml index 33f7c557c..02b8eeb80 100644 --- a/modules/monitoring/application/views/scripts/process/info.phtml +++ b/modules/monitoring/application/views/scripts/process/info.phtml @@ -70,19 +70,19 @@ $cp = $this->checkPerformance()->create($this->checkperformance);

translate('Performance Info') ?>

-

Object summaries

+

translate('Object summaries') ?>

- - + +
overallscheduledtranslate('overall') ?>translate('scheduled') ?>
- Hosts + translate('Hosts') ?> total_hosts; ?> @@ -94,7 +94,7 @@ $cp = $this->checkPerformance()->create($this->checkperformance);
- Services + translate('Services') ?> total_services; ?> @@ -106,7 +106,7 @@ $cp = $this->checkPerformance()->create($this->checkperformance);
- Average services per host + translate('Average services per host') ?> average_services_per_host); ?> @@ -118,20 +118,20 @@ $cp = $this->checkPerformance()->create($this->checkperformance);
-

Active checks

+

translate('Active checks') ?>

- - + + @@ -139,7 +139,7 @@ $cp = $this->checkPerformance()->create($this->checkperformance); @@ -148,18 +148,18 @@ $cp = $this->checkPerformance()->create($this->checkperformance);
LatencyExecution timetranslate('Latency') ?>translate('Execution time') ?>
- Host Checks + translate('Host Checks') ?> host_active_count; ?> host_active_latency_avg); ?>s
- Service Checks + translate('Service Checks') ?> service_active_count; ?> service_active_latency_avg); ?>s
-

Passive checks

+

translate('Passive checks') ?>

From 8c305f59f2bbc2426847cabf1b3283a373c4ad10 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 06:56:36 +0100 Subject: [PATCH 30/61] LoginForm: re-establish placeholder texts --- application/forms/Authentication/LoginForm.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/forms/Authentication/LoginForm.php b/application/forms/Authentication/LoginForm.php index 41107be18..a6d69d15a 100644 --- a/application/forms/Authentication/LoginForm.php +++ b/application/forms/Authentication/LoginForm.php @@ -32,7 +32,7 @@ class LoginForm extends Form array( 'required' => true, 'label' => t('Username'), - 'placeholder' => t(''), + 'placeholder' => t('Please enter your username...'), 'class' => false === isset($formData['username']) ? 'autofocus' : '' ) ); @@ -42,7 +42,7 @@ class LoginForm extends Form array( 'required' => true, 'label' => t('Password'), - 'placeholder' => t(''), + 'placeholder' => t('...and your password'), 'class' => isset($formData['username']) ? 'autofocus' : '' ) ); From 6e62b2f0f4a6c116548f2cc826311d323ed3c1bd Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 07:16:32 +0100 Subject: [PATCH 31/61] monitoring/css: reduce basic header sizes --- modules/monitoring/public/css/module.less | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 65150c5e2..030eba7af 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -1,6 +1,18 @@ // {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}} +h1 { + font-size: 1em; +} + +h2 { + font-size: 1em; +} + +h3 { + font-size: 1em; +} + table.action.comments td p, table.action.downtimes td p { margin: 0; font-size: 0.8em; From 3844087740c2934da910dac3b7bf9c5fef31b6a7 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 07:51:51 +0100 Subject: [PATCH 32/61] css/main-content: reduce dashboard header sizes --- public/css/icinga/main-content.less | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/public/css/icinga/main-content.less b/public/css/icinga/main-content.less index dd9c89c92..a9d5a94a9 100644 --- a/public/css/icinga/main-content.less +++ b/public/css/icinga/main-content.less @@ -170,6 +170,18 @@ table.benchmark { width: 96%; } +.dashboard h1 { + font-size: 1.2em; +} + +.dashboard h2 { + font-size: 1.1em; +} + +.dashboard h3 { + font-size: 1em; +} + .dashboard table.benchmark { font-size: 0.9em; } From a20fa3201d74b906991a2c3f8cd357934da855cd Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 07:53:16 +0100 Subject: [PATCH 33/61] tinystatesummary: use h1, styling --- .../list/components/hostssummary.phtml | 7 +++-- .../list/components/servicesummary.phtml | 6 ++-- .../show/components/hostservicesummary.phtml | 7 +++-- modules/monitoring/public/css/module.less | 30 +++++++++---------- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml b/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml index c455d26ae..2e19ff352 100644 --- a/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml +++ b/modules/monitoring/application/views/scripts/list/components/hostssummary.phtml @@ -6,9 +6,9 @@ $selfUrl = 'monitoring/list/hosts'; $currentUrl = Url::fromRequest()->getRelativeUrl(); ?> -

compact ? ' data-base-target="col1"' : '' ?>> +

compact ? ' data-base-target="col1"' : '' ?>> qlink(sprintf($this->translate('%s hosts:'), $this->stats->hosts_total), $selfUrl); ?> - + stats->hosts_up): ?> qlink( @@ -80,4 +80,5 @@ $currentUrl = Url::fromRequest()->getRelativeUrl(); ) ?> -

+ + diff --git a/modules/monitoring/application/views/scripts/list/components/servicesummary.phtml b/modules/monitoring/application/views/scripts/list/components/servicesummary.phtml index 8533c80c7..dab7071a1 100644 --- a/modules/monitoring/application/views/scripts/list/components/servicesummary.phtml +++ b/modules/monitoring/application/views/scripts/list/components/servicesummary.phtml @@ -4,8 +4,9 @@ use Icinga\Web\Url; $selfUrl = 'monitoring/list/services'; $currentUrl = Url::fromRequest()->getRelativeUrl(); -?>

compact ? ' data-base-target="col1"' : '' ?>> +?>

compact ? ' data-base-target="col1"' : '' ?>> qlink(sprintf($this->translate('%s services:'), $this->stats->services_total), $selfUrl) ?> + stats->services_ok): ?> qlink( $this->stats->services_ok, @@ -79,5 +80,6 @@ foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $ array('title' => sprintf($this->translate('Services with state %s'), strtoupper($this->translate('pending')))) ) ?> -

+ + diff --git a/modules/monitoring/application/views/scripts/show/components/hostservicesummary.phtml b/modules/monitoring/application/views/scripts/show/components/hostservicesummary.phtml index 26a0da082..f42e70278 100644 --- a/modules/monitoring/application/views/scripts/show/components/hostservicesummary.phtml +++ b/modules/monitoring/application/views/scripts/show/components/hostservicesummary.phtml @@ -5,13 +5,13 @@ $selfUrl = Url::fromPath('monitoring/show/services', array('host' => $this->obje $currentUrl = Url::fromRequest()->without('limit')->getRelativeUrl(); ?> -

compact ? ' data-base-target="col1"' : '' ?>> +

compact ? ' data-base-target="col1"' : '' ?>> stats->services_total > 0): ?> qlink(sprintf($this->translate('%s configured services:'), $object->stats->services_total), $selfUrl) ?> translate('No services configured on this host'); ?> - + stats->services_ok > 0): ?> qlink( $object->stats->services_ok, @@ -84,5 +84,6 @@ foreach (array(2 => 'critical', 3 => 'unknown', 1 => 'warning') as $stateId => $ array('title' => sprintf($this->translate('Services with state %s'), strtoupper($this->translate('pending')))) ) ?> -

+ + diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 030eba7af..84b3ba899 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -92,36 +92,36 @@ div.contacts div.notification-periods { margin-top: 0.5em; } -h3.tinystatesummary { - line-height: 2em; - font-size: 0.95em; - margin-right: 1em; - border-bottom: 2px solid @colorPetrol; +h1.tinystatesummary .badges { + display: inline-block; + margin-bottom: 4px; + margin-left: 1em; } -h3.tinystatesummary a { - color: inherit; - text-decoration: none; - padding: 1px 3px; +h1.tinystatesummary .state { + border-radius: 0.3em; } -h3.tinystatesummary a:hover { - text-decoration: underline; +h1.tinystatesummary .state > a { + color: white; + font-size: 0.7em; + padding: 2px 5px; +} + +h1.tinystatesummary .state.handled a { } /* State badges */ span.state { - font-size: 1em; - font-weight: 700; + font-weight: bold; color: white; font-weight: bold; padding: 1px 2px; margin-right: 5px; - } span.state.active { - border: 2px solid white; + border: 2px solid #555; } span.state span.state { From 1f5d4a28c0fc660b7c369ad59da4a90156e4a591 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 08:09:39 +0100 Subject: [PATCH 34/61] monitoring/css:align selection info to header --- modules/monitoring/public/css/module.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 6a2dae87e..05bfbb17a 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -173,7 +173,7 @@ table.avp .customvar ul { } div.selection-info { - padding-top:0.5em; + padding-top: 3px; float: right; } From 108f854848aa94e8b5e552400ab3f70dec4b5a94 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 08:11:53 +0100 Subject: [PATCH 35/61] monitoring/list: let filter know special params --- modules/monitoring/application/controllers/ListController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index a58304cd6..2558525c6 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -608,8 +608,8 @@ class Monitoring_ListController extends Controller { $editor = Widget::create('filterEditor') ->setQuery($query) - ->preserveParams('limit', 'sort', 'dir', 'format', 'view', 'backend') - ->ignoreParams('page', 'objecttype', 'from', 'to', 'state', 'btn_submit') + ->preserveParams('limit', 'sort', 'dir', 'format', 'view', 'backend', 'renderLayout', 'stateType', 'addColumns') + ->ignoreParams('page', 'objecttype', 'from', 'to', 'btn_submit') ->handleRequest($this->getRequest()); $query->applyFilter($editor->getFilter()); From 2bac63e6d8658fab079c4a2f98b48d1e33633fec Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 08:34:56 +0100 Subject: [PATCH 36/61] monitoring/css: badges --- modules/monitoring/public/css/module.less | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 05bfbb17a..1fa693f93 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -98,13 +98,9 @@ h1.tinystatesummary .badges { margin-left: 1em; } -h1.tinystatesummary .state { - border-radius: 0.3em; -} - h1.tinystatesummary .state > a { color: white; - font-size: 0.7em; + font-size: 0.8em; padding: 2px 5px; } From b3a154deed974c6dd5079aa81e3b6f25af0b435e Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 08:49:58 +0100 Subject: [PATCH 37/61] css/defaults: buttons should respect font settings --- public/css/icinga/defaults.less | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/css/icinga/defaults.less b/public/css/icinga/defaults.less index 4c990d0e9..ff54bd38d 100644 --- a/public/css/icinga/defaults.less +++ b/public/css/icinga/defaults.less @@ -91,6 +91,10 @@ h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover { text-decoration: underline; } +button { + font-family: inherit; +} + #fontsize-calc { display: none; width: 1000em; From 8d674376855825836a34197d533a22bc8b92feb2 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 09:10:13 +0100 Subject: [PATCH 38/61] show/services: render service in _next container --- .../monitoring/application/views/scripts/show/services.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/monitoring/application/views/scripts/show/services.phtml b/modules/monitoring/application/views/scripts/show/services.phtml index a78b3215b..ae4f8f699 100644 --- a/modules/monitoring/application/views/scripts/show/services.phtml +++ b/modules/monitoring/application/views/scripts/show/services.phtml @@ -2,4 +2,4 @@ render('show/components/header.phtml') ?> render('show/components/hostservicesummary.phtml') ?> - + From 32f1e0c1711d558f670f2e77c340de91df72c8d8 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 09:34:49 +0100 Subject: [PATCH 39/61] css/main-content: normalize headers, once more --- public/css/icinga/main-content.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/css/icinga/main-content.less b/public/css/icinga/main-content.less index ccdd63795..6e742161a 100644 --- a/public/css/icinga/main-content.less +++ b/public/css/icinga/main-content.less @@ -171,11 +171,11 @@ table.benchmark { } .dashboard h1 { - font-size: 1.2em; + font-size: 1em; } .dashboard h2 { - font-size: 1.1em; + font-size: 1em; } .dashboard h3 { From 0af623b4626478c5a6fdf5ac5a1fde4a5ed4b129 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 09:40:42 +0100 Subject: [PATCH 40/61] css: reduce .controls complexity and special rules --- public/css/icinga/main-content.less | 4 ++++ public/css/icinga/monitoring-colors.less | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/public/css/icinga/main-content.less b/public/css/icinga/main-content.less index 6e742161a..7f6914e3d 100644 --- a/public/css/icinga/main-content.less +++ b/public/css/icinga/main-content.less @@ -189,3 +189,7 @@ table.benchmark { .left { text-align: left !important; } + +.controls a { + color: inherit; +} diff --git a/public/css/icinga/monitoring-colors.less b/public/css/icinga/monitoring-colors.less index 7beee80d0..113241968 100644 --- a/public/css/icinga/monitoring-colors.less +++ b/public/css/icinga/monitoring-colors.less @@ -816,10 +816,3 @@ div.timeline { } /* End of monitoring timeline styles */ - -.controls { - font-size: 0.9em; -} -.controls a { - color: black; -} From c6ffdb3862f98017a1cf61ecc597a2496e9bf991 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 09:44:47 +0100 Subject: [PATCH 41/61] Widget\FilterEditor: fix failing parameter checking --- library/Icinga/Web/Widget/FilterEditor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Web/Widget/FilterEditor.php b/library/Icinga/Web/Widget/FilterEditor.php index 3721e488c..cc354912a 100644 --- a/library/Icinga/Web/Widget/FilterEditor.php +++ b/library/Icinga/Web/Widget/FilterEditor.php @@ -585,7 +585,7 @@ class FilterEditor extends AbstractWidget } else { $parent = $filter->getById($addTo); $f = Filter::expression($add['column'], $add['sign'], $add['value']); - if ($add['operator']) { + if (isset($add['operator'])) { switch($add['operator']) { case 'AND': if ($parent->isExpression()) { From eb823c40452eab0e61e47280db8a8a084c606336 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 09:53:25 +0100 Subject: [PATCH 42/61] Widget\FilterEditor: fix root element stripping --- library/Icinga/Web/Widget/FilterEditor.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/Icinga/Web/Widget/FilterEditor.php b/library/Icinga/Web/Widget/FilterEditor.php index cc354912a..2abc89744 100644 --- a/library/Icinga/Web/Widget/FilterEditor.php +++ b/library/Icinga/Web/Widget/FilterEditor.php @@ -218,7 +218,12 @@ class FilterEditor extends AbstractWidget if ($strip) { $redirect = $this->url(); - $filter->replaceById($strip, $filter->getById($strip . '-1')); + $subId = $strip . '-1'; + if ($filter->getId() === $strip) { + $filter = $filter->getById($strip . '-1'); + } else { + $filter->replaceById($strip, $filter->getById($strip . '-1')); + } $redirect->setQueryString($filter->toQueryString())->getParams()->add('modifyFilter'); $this->redirectNow($redirect->addParams($preserve)); } From 3f6c28dfb3431e38d90bb1513c56a5806cce292e Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 10:04:14 +0100 Subject: [PATCH 43/61] css/monitoring-colors: make text readable on hover --- public/css/icinga/monitoring-colors.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/css/icinga/monitoring-colors.less b/public/css/icinga/monitoring-colors.less index 113241968..c2abd9aba 100644 --- a/public/css/icinga/monitoring-colors.less +++ b/public/css/icinga/monitoring-colors.less @@ -194,8 +194,12 @@ tr.state.handled td.state { } /* HOVER colors */ +tr[href]:hover { + color: black; + background-color: #eee; +} -tr[href]:hover, tr.state[href]:hover td.state { +tr.state[href]:hover td.state { color: white; background-color: #eee; } From 704a87c0f252b83ee40b297f7c65cd6507cde709 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 10:07:30 +0100 Subject: [PATCH 44/61] FilterEditor: make active element fit hover colors --- library/Icinga/Web/Widget/FilterEditor.php | 6 +++--- public/css/icinga/widgets.less | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/library/Icinga/Web/Widget/FilterEditor.php b/library/Icinga/Web/Widget/FilterEditor.php index 2abc89744..3b7f10e9e 100644 --- a/library/Icinga/Web/Widget/FilterEditor.php +++ b/library/Icinga/Web/Widget/FilterEditor.php @@ -346,7 +346,7 @@ class FilterEditor extends AbstractWidget protected function renderFilter($filter, $level = 0) { if ($level === 0 && $filter->isChain() && $filter->isEmpty()) { - return '
  • ' . $this->renderNewFilter() . '
'; + return '
  • ' . $this->renderNewFilter() . '
'; } if ($filter instanceof FilterChain) { @@ -403,7 +403,7 @@ class FilterEditor extends AbstractWidget . $this->text($filter) . $this->removeLink($filter) . $this->addLink($filter) - . '
  • ' + . '
  • ' . $this->renderNewFilter() .$this->cancelLink() . '
  • ' ; @@ -670,7 +670,7 @@ class FilterEditor extends AbstractWidget . '
    ' - . '
    • ' + . '
      • ' . $this->renderFilter($this->filter) . '
      ' . '
      ' diff --git a/public/css/icinga/widgets.less b/public/css/icinga/widgets.less index 2870f7c07..235783f45 100644 --- a/public/css/icinga/widgets.less +++ b/public/css/icinga/widgets.less @@ -251,3 +251,7 @@ li li .badge { .badge-pending { background-color: @colorUnknown; } + +.widgetFilter li.active { + background-color: #eee; +} From b5aa08ca361642174549cfe74861454f8bdadf7d Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 10:17:09 +0100 Subject: [PATCH 45/61] selectioninfo: make it look lighter --- .../views/scripts/list/components/selectioninfo.phtml | 4 ++-- modules/monitoring/public/css/module.less | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/monitoring/application/views/scripts/list/components/selectioninfo.phtml b/modules/monitoring/application/views/scripts/list/components/selectioninfo.phtml index 82b9d246c..a9945bc7d 100644 --- a/modules/monitoring/application/views/scripts/list/components/selectioninfo.phtml +++ b/modules/monitoring/application/views/scripts/list/components/selectioninfo.phtml @@ -1,6 +1,6 @@ translate('Press and hold the Ctrl key while clicking on rows to select multiple rows or press and hold the Shift key to select a range of rows.', 'multiselection'); ?> -
      - 0 translate('row(s) selected', 'multiselection') ?> icon('help', $helpMessage) ?> +
      + 0 translate('row(s) selected', 'multiselection') ?>
      diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less index 1fa693f93..675988056 100644 --- a/modules/monitoring/public/css/module.less +++ b/modules/monitoring/public/css/module.less @@ -169,8 +169,10 @@ table.avp .customvar ul { } div.selection-info { - padding-top: 3px; + padding-top: 0.4em; float: right; + cursor: help; + font-size: 0.8em; } .optionbox { From a5411c7a1c447fe7488866fbc12f7a05b79d146b Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Wed, 19 Nov 2014 10:33:41 +0100 Subject: [PATCH 46/61] Dashboard: Fix reading and disabled system dashboards refs #4537 --- application/views/scripts/dashboard/settings.phtml | 1 + library/Icinga/Web/Widget/Dashboard.php | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/application/views/scripts/dashboard/settings.phtml b/application/views/scripts/dashboard/settings.phtml index b14c236df..83fba6588 100644 --- a/application/views/scripts/dashboard/settings.phtml +++ b/application/views/scripts/dashboard/settings.phtml @@ -38,6 +38,7 @@ + getDisabled() === true) continue; ?>
    - Host Checks + translate('Host Checks') ?> host_passive_count; ?>
    - Service Checks + translate('Service Checks') ?> service_passive_count; ?>
    diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index ccc8cf279..e663ddf44 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -114,7 +114,11 @@ class Dashboard extends AbstractWidget */ private function loadUserDashboards() { - $config = Config::fromIni($this->getConfigFile()); + try { + $config = Config::fromIni($this->getConfigFile()); + } catch (NotReadableError $e) { + return; + } if (! count($config)) { return false; } From 47d81ccf7bef240471a305e69d6c5a1720f75f01 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 10:31:51 +0100 Subject: [PATCH 47/61] css: allow to override vendor styles * no more hovered icon underline * simulate padding for headers in .controls --- application/fonts/fontello-ifont/css/ifont-embedded.css | 2 +- library/Icinga/Web/StyleSheet.php | 6 +++--- public/css/icinga/main-content.less | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/application/fonts/fontello-ifont/css/ifont-embedded.css b/application/fonts/fontello-ifont/css/ifont-embedded.css index 593eb8bc0..92bcfdff9 100644 --- a/application/fonts/fontello-ifont/css/ifont-embedded.css +++ b/application/fonts/fontello-ifont/css/ifont-embedded.css @@ -167,4 +167,4 @@ .icon-chart-area:before { content: '\e870'; } /* '' */ .icon-chart-bar:before { content: '\e871'; } /* '' */ .icon-beaker:before { content: '\e872'; } /* '' */ -.icon-magic:before { content: '\e873'; } /* '' */ \ No newline at end of file +.icon-magic:before { content: '\e873'; } /* '' */ diff --git a/library/Icinga/Web/StyleSheet.php b/library/Icinga/Web/StyleSheet.php index b40b37927..719d1c829 100644 --- a/library/Icinga/Web/StyleSheet.php +++ b/library/Icinga/Web/StyleSheet.php @@ -11,6 +11,8 @@ use Icinga\Web\LessCompiler; class StyleSheet { protected static $lessFiles = array( + '../application/fonts/fontello-ifont/css/ifont-embedded.css', + 'css/vendor/tipsy.css', 'css/icinga/defaults.less', 'css/icinga/layout-colors.less', 'css/icinga/layout-structure.less', @@ -24,9 +26,7 @@ class StyleSheet 'css/icinga/pagination.less', 'css/icinga/monitoring-colors.less', 'css/icinga/selection-toolbar.less', - 'css/icinga/login.less', - '../application/fonts/fontello-ifont/css/ifont-embedded.css', - 'css/vendor/tipsy.css' + 'css/icinga/login.less' ); public static function compileForPdf() diff --git a/public/css/icinga/main-content.less b/public/css/icinga/main-content.less index 7f6914e3d..6972e95dc 100644 --- a/public/css/icinga/main-content.less +++ b/public/css/icinga/main-content.less @@ -193,3 +193,12 @@ table.benchmark { .controls a { color: inherit; } + +/* controls have no padding as of tabs */ +.controls > h1 { + margin-right: 1em; +} + +[class^="icon-"]:before, [class*=" icon-"]:before { + text-decoration: none; +} From 2c143ff348b0e34d43686e932c4ac790570f9788 Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Wed, 19 Nov 2014 11:03:06 +0100 Subject: [PATCH 48/61] Fix alert summary page layout --- .../controllers/AlertsummaryController.php | 2 +- .../views/scripts/alertsummary/index.phtml | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/monitoring/application/controllers/AlertsummaryController.php b/modules/monitoring/application/controllers/AlertsummaryController.php index e90bc1c5e..6d56c8d22 100644 --- a/modules/monitoring/application/controllers/AlertsummaryController.php +++ b/modules/monitoring/application/controllers/AlertsummaryController.php @@ -64,7 +64,7 @@ class Monitoring_AlertsummaryController extends Controller */ public function indexAction() { - $this->addTitleTab('alertsummary'); + $this->addTitleTab('alertsummary', t('Alert Summary')); $this->view->intervalBox = $this->createIntervalBox(); $this->view->recentAlerts = $this->createRecentAlerts(); $this->view->interval = $this->getInterval(); diff --git a/modules/monitoring/application/views/scripts/alertsummary/index.phtml b/modules/monitoring/application/views/scripts/alertsummary/index.phtml index 2a9a5e067..624b942b3 100644 --- a/modules/monitoring/application/views/scripts/alertsummary/index.phtml +++ b/modules/monitoring/application/views/scripts/alertsummary/index.phtml @@ -11,19 +11,19 @@ $helper = $this->getHelper('MonitoringState');
    -

    translate('Alert summary'); ?>

    + -
    -
    -

    translate('Notifications and problems'); ?>

    -
    +
    +
    +

    translate('Notifications and Problems'); ?>

    +
    render(); ?>
    -
    -

    translate('Time to reaction (Ack, Recover)'); ?>

    -
    +
    +

    translate('Time to Reaction (Ack, Recover)'); ?>

    +
    render(); ?>
    @@ -56,7 +56,7 @@ $helper = $this->getHelper('MonitoringState');
    recentAlerts): ?> -

    translate('Top 5 recent alerts'); ?>

    +

    translate('Top 5 Recent Alerts'); ?>

    @@ -69,7 +69,7 @@ $helper = $this->getHelper('MonitoringState');
    -

    translate('History'); ?>

    +

    translate('History'); ?>

    partial('list/notifications.phtml', array( From a2592f8d7b2f9e13cb1e35927ff1e5ada1c8c64f Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Wed, 19 Nov 2014 11:23:28 +0100 Subject: [PATCH 49/61] Fix alert summary chart colors --- .../application/controllers/AlertsummaryController.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/monitoring/application/controllers/AlertsummaryController.php b/modules/monitoring/application/controllers/AlertsummaryController.php index 6d56c8d22..8fd70627d 100644 --- a/modules/monitoring/application/controllers/AlertsummaryController.php +++ b/modules/monitoring/application/controllers/AlertsummaryController.php @@ -433,7 +433,7 @@ class Monitoring_AlertsummaryController extends Controller $gridChart->drawBars( array( 'label' => $this->translate('Notifications'), - 'color' => 'blue', + 'color' => '#049baf', 'data' => $notifications, 'showPoints' => true ) @@ -442,7 +442,7 @@ class Monitoring_AlertsummaryController extends Controller $gridChart->drawLines( array( 'label' => $this->translate('Avg (min)'), - 'color' => 'orange', + 'color' => '#ffaa44', 'data' => $dAvg, 'showPoints' => true ) @@ -451,7 +451,7 @@ class Monitoring_AlertsummaryController extends Controller $gridChart->drawLines( array( 'label' => $this->translate('Max (min)'), - 'color' => 'red', + 'color' => '#ff5566', 'data' => $dMax, 'showPoints' => true ) @@ -478,7 +478,7 @@ class Monitoring_AlertsummaryController extends Controller $gridChart->drawBars( array( 'label' => $this->translate('Notifications'), - 'color' => 'green', + 'color' => '#049baf', 'data' => $this->notificationData, 'showPoints' => true ) @@ -487,7 +487,7 @@ class Monitoring_AlertsummaryController extends Controller $gridChart->drawLines( array( 'label' => $this->translate('Defects'), - 'color' => 'red', + 'color' => '#ff5566', 'data' => $this->problemData, 'showPoints' => true ) From a40f357f3cf5abf5671f66c5d509d2db3e9736db Mon Sep 17 00:00:00 2001 From: Marius Hein Date: Wed, 19 Nov 2014 11:47:31 +0100 Subject: [PATCH 50/61] Dashboard: Show error message when can not write to file refs #4537 --- .../controllers/DashboardController.php | 40 ++++++++++++++++--- .../views/scripts/dashboard/error.phtml | 13 ++++++ .../scripts/dashboard/new-component.phtml | 1 - library/Icinga/File/Ini/IniWriter.php | 10 +++++ library/Icinga/Web/Widget/Dashboard.php | 17 ++++++-- 5 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 application/views/scripts/dashboard/error.phtml diff --git a/application/controllers/DashboardController.php b/application/controllers/DashboardController.php index 105b40762..94a6b383c 100644 --- a/application/controllers/DashboardController.php +++ b/application/controllers/DashboardController.php @@ -44,7 +44,8 @@ class DashboardController extends ActionController $params['url'] = rawurldecode($this->_request->getParam('url')); $form->populate($params); } - $form->setOnSuccess(function (Form $form) use ($dashboard) { + $action = $this; + $form->setOnSuccess(function (Form $form) use ($dashboard, $action) { try { $pane = $dashboard->getPane($form->getValue('pane')); } catch (ProgrammingError $e) { @@ -55,7 +56,14 @@ class DashboardController extends ActionController $component = new Dashboard\Component($form->getValue('component'), $form->getValue('url'), $pane); $component->setUserWidget(); $pane->addComponent($component); - $dashboard->write(); + try { + $dashboard->write(); + } catch (\Zend_Config_Exception $e) { + $action->view->error = $e; + $action->view->config = $dashboard->createWriter(); + $action->render('error'); + return false; + } Notification::success(t('Component created')); return true; }); @@ -83,7 +91,8 @@ class DashboardController extends ActionController 400 ); } - $form->setOnSuccess(function (Form $form) use ($dashboard) { + $action = $this; + $form->setOnSuccess(function (Form $form) use ($dashboard, $action) { try { $pane = $dashboard->getPane($form->getValue('pane')); } catch (ProgrammingError $e) { @@ -108,7 +117,14 @@ class DashboardController extends ActionController $oldPane = $dashboard->getPane($form->getValue('org_pane')); $oldPane->removeComponent($component->getTitle()); } - $dashboard->write(); + try { + $dashboard->write(); + } catch (\Zend_Config_Exception $e) { + $action->view->error = $e; + $action->view->config = $dashboard->createWriter(); + $action->render('error'); + return false; + } Notification::success(t('Component updated')); return true; }); @@ -140,13 +156,19 @@ class DashboardController extends ActionController } $pane = $this->_request->getParam('pane'); $component = $this->_request->getParam('component'); - $form->setOnSuccess(function (Form $form) use ($dashboard, $component, $pane) { + $action = $this; + $form->setOnSuccess(function (Form $form) use ($dashboard, $component, $pane, $action) { try { $pane = $dashboard->getPane($pane); $pane->removeComponent($component); $dashboard->write(); Notification::success(t('Component has been removed from') . ' ' . $pane->getTitle()); return true; + } catch (\Zend_Config_Exception $e) { + $action->view->error = $e; + $action->view->config = $dashboard->createWriter(); + $action->render('error'); + return false; } catch (ProgrammingError $e) { Notification::error($e->getMessage()); return false; @@ -172,13 +194,19 @@ class DashboardController extends ActionController ); } $pane = $this->_request->getParam('pane'); - $form->setOnSuccess(function (Form $form) use ($dashboard, $pane) { + $action = $this; + $form->setOnSuccess(function (Form $form) use ($dashboard, $pane, $action) { try { $pane = $dashboard->getPane($pane); $dashboard->removePane($pane->getTitle()); $dashboard->write(); Notification::success(t('Pane has been removed') . ': ' . $pane->getTitle()); return true; + } catch (\Zend_Config_Exception $e) { + $action->view->error = $e; + $action->view->config = $dashboard->createWriter(); + $action->render('error'); + return false; } catch (ProgrammingError $e) { Notification::error($e->getMessage()); return false; diff --git a/application/views/scripts/dashboard/error.phtml b/application/views/scripts/dashboard/error.phtml new file mode 100644 index 000000000..e5a0f3939 --- /dev/null +++ b/application/views/scripts/dashboard/error.phtml @@ -0,0 +1,13 @@ +
    +

    +

    + + config->getFilename(); ?>;. +
    + +

    +
    config->render(); ?>
    +
    +

    +

    error->getMessage(); ?>

    +
    diff --git a/application/views/scripts/dashboard/new-component.phtml b/application/views/scripts/dashboard/new-component.phtml index 456d14a65..46c8b2255 100644 --- a/application/views/scripts/dashboard/new-component.phtml +++ b/application/views/scripts/dashboard/new-component.phtml @@ -1,7 +1,6 @@
    tabs ?>
    -

    form; ?> diff --git a/library/Icinga/File/Ini/IniWriter.php b/library/Icinga/File/Ini/IniWriter.php index cf9355b56..e3b757b78 100644 --- a/library/Icinga/File/Ini/IniWriter.php +++ b/library/Icinga/File/Ini/IniWriter.php @@ -229,4 +229,14 @@ class IniWriter extends Zend_Config_Writer_FileAbstract return $combinations; } + + /** + * Getter for filename + * + * @return string + */ + public function getFilename() + { + return $this->_filename; + } } diff --git a/library/Icinga/Web/Widget/Dashboard.php b/library/Icinga/Web/Widget/Dashboard.php index e663ddf44..c97bdf578 100644 --- a/library/Icinga/Web/Widget/Dashboard.php +++ b/library/Icinga/Web/Widget/Dashboard.php @@ -86,9 +86,11 @@ class Dashboard extends AbstractWidget } /** - * Write user specific dashboards to disk + * Create a writer object + * + * @return IniWriter */ - public function write() + public function createWriter() { $configFile = $this->getConfigFile(); $output = array(); @@ -105,8 +107,15 @@ class Dashboard extends AbstractWidget $co = new ConfigObject($output); $config = new Config($co); - $writer = new IniWriter(array('config' => $config, 'filename' => $configFile)); - $writer->write(); + return new IniWriter(array('config' => $config, 'filename' => $configFile)); + } + + /** + * Write user specific dashboards to disk + */ + public function write() + { + $this->createWriter()->write(); } /** From c74f7531dcb18dca678cceac1f3c0ec5da7b8fa0 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Wed, 19 Nov 2014 11:52:23 +0100 Subject: [PATCH 51/61] Do not display host- and servicegroups as boxes but as table instead --- .../controllers/ListController.php | 22 +- .../views/scripts/list/hostgroups.phtml | 515 +++++++++-------- .../views/scripts/list/servicegroups.phtml | 518 +++++++++--------- .../Backend/Ido/Query/GroupsummaryQuery.php | 15 +- public/css/icinga/monitoring-colors.less | 123 +++++ 5 files changed, 658 insertions(+), 535 deletions(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 2558525c6..4ad4af319 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -490,7 +490,16 @@ class Monitoring_ListController extends Controller 'services_critical_unhandled', 'services_warning_handled', 'services_warning_unhandled', - 'services_pending' + 'services_pending', + 'services_ok_last_state_change', + 'services_pending_last_state_change', + 'services_warning_last_state_change_handled', + 'services_critical_last_state_change_handled', + 'services_unknown_last_state_change_handled', + 'services_warning_last_state_change_unhandled', + 'services_critical_last_state_change_unhandled', + 'services_unknown_last_state_change_unhandled', + 'services_total' )); $this->filterQuery($query); $this->view->servicegroups = $query->paginate(); @@ -521,7 +530,16 @@ class Monitoring_ListController extends Controller 'services_critical_unhandled', 'services_warning_handled', 'services_warning_unhandled', - 'services_pending' + 'services_pending', + 'services_ok_last_state_change', + 'services_pending_last_state_change', + 'services_warning_last_state_change_handled', + 'services_critical_last_state_change_handled', + 'services_unknown_last_state_change_handled', + 'services_warning_last_state_change_unhandled', + 'services_critical_last_state_change_unhandled', + 'services_unknown_last_state_change_unhandled', + 'services_total' )); $this->filterQuery($query); $this->view->hostgroups = $query->paginate(); diff --git a/modules/monitoring/application/views/scripts/list/hostgroups.phtml b/modules/monitoring/application/views/scripts/list/hostgroups.phtml index 5a60c7a68..0a786132c 100644 --- a/modules/monitoring/application/views/scripts/list/hostgroups.phtml +++ b/modules/monitoring/application/views/scripts/list/hostgroups.phtml @@ -1,266 +1,253 @@ -compact): ?> -
    - tabs ?> -
    - +compact): ?>
    -
    - - - -
    -

    - - hostgroup; ?> - -

    -
    - - - - - - - - - - - - - -
    translate('Hosts'); ?>translate('Services'); ?>
    -hosts_down_handled || $h->hosts_down_unhandled): ?> - -
    -hosts_down_unhandled): ?> - - hosts_down_unhandled; ?> translate('DOWN', 'icinga.state') ?> - - -hosts_down_handled): ?> - - hosts_down_handled . ' ' . ($h->hosts_down_unhandled ? $this->translate('Acknowledged') : $this->translate('DOWN', 'icinga.state')); ?> - - -
    - - -hosts_unreachable_handled || $h->hosts_unreachable_unhandled): ?> - -
    -hosts_unreachable_unhandled): ?> - - hosts_unreachable_unhandled; ?> translate('UNREACHABLE', 'icinga.state') ?> - - -hosts_unreachable_handled): ?> - - hosts_unreachable_handled . ' ' . ($h->hosts_unreachable_unhandled ? $this->translate('Acknowledged') : $this->translate('UNREACHABLE', 'icinga.state')) ?> - - -
    - - -hosts_up): ?> - -
    - - hosts_up; ?> translate('UP', 'icinga.state') ?> - -
    - - -hosts_pending): ?> - -
    - - hosts_pending; ?> translate('PENDING', 'icinga.state') ?> - -
    - - -
    -services_critical_handled || $h->services_critical_unhandled): ?> - -
    -services_critical_unhandled): ?> - - services_critical_unhandled; ?> translate('CRITICAL', 'icinga.state') ?> - - -services_critical_handled): ?> - - services_critical_handled . ' ' . ($h->services_critical_unhandled ? $this->translate('Acknowledged') : $this->translate('CRITICAL', 'icinga.state')); ?> - - -
    - - -services_warning_handled || $h->services_warning_unhandled): ?> - -
    -services_warning_unhandled): ?> - - services_warning_unhandled; ?> translate('WARNING', 'icinga.state') ?> - - -services_warning_handled): ?> - - services_warning_handled . ' ' . ($h->services_warning_unhandled ? $this->translate('Acknowledged') : $this->translate('WARNING', 'icinga.state')); ?> - - -
    - - -services_unknown_handled || $h->services_unknown_unhandled): ?> - -
    -services_unknown_unhandled): ?> - - services_unknown_unhandled; ?> translate('UNKNOWN', 'icinga.state') ?> - - -services_unknown_handled): ?> - - services_unknown_handled . ' ' . ($h->services_unknown_unhandled ? $this->translate('Acknowledged') : $this->translate('UNKNOWN', 'icinga.state')); ?> - - -
    - - -services_ok): ?> - -
    - - services_ok; ?> translate('OK', 'icinga.state') ?> - -
    - - -services_pending): ?> - -
    - - services_pending; ?> translate('PENDING', 'icinga.state') ?> - -
    - - -
    -
    -
    - -
    + +
    + tabs ?> + widget('limiter')->setMaxLimit(count($hostgroups)); ?> + paginationControl($hostgroups, null, null, array('preserve' => $this->preserve)); ?>
    +
    + filterEditor; ?> + + translate('No host groups matching the filter'); + echo '
    '; + return; + } + ?> + + + + + + + + + + + services_critical_last_state_change_unhandled): ?> + + services_unknown_last_state_change_unhandled): ?> + + services_warning_last_state_change_unhandled): ?> + + services_critical_last_state_change_handled): ?> + + services_unknown_last_state_change_handled): ?> + + services_warning_last_state_change_handled): ?> + + services_ok_last_state_change): ?> + + + + + + + + + + + + + + +
    translate('Last Problem'); ?>translate('Host Group'); ?>translate('Total Services'); ?>translate('Service States'); ?>
    + translate('CRITICAL'); ?> +
    + prefixedTimeSince($h->services_critical_last_state_change_unhandled); ?> +
    + translate('UNKNOWN'); ?> +
    + prefixedTimeSince($h->services_unknown_last_state_change_unhandled); ?> +
    + translate('WARNING'); ?> +
    + prefixedTimeSince($h->services_warning_last_state_change_unhandled); ?> +
    + translate('CRITICAL'); ?> +
    + prefixedTimeSince($h->services_critical_last_state_change_handled); ?> +
    + translate('UNKNOWN'); ?> +
    + prefixedTimeSince($h->services_unknown_last_state_change_handled); ?> +
    + translate('WARNING'); ?> +
    + prefixedTimeSince($h->services_warning_last_state_change_handled); ?> +
    + translate('OK'); ?> +
    + prefixedTimeSince($h->services_ok_last_state_change); ?> +
    + translate('PENDING'); ?> +
    + prefixedTimeSince($h->services_pending_last_state_change); ?> +
    + + hostgroup; ?> + + + services_total; ?> + + services_ok): ?> + + + services_ok; ?> + + + + + - + + + + services_critical_unhandled): ?> + + + services_critical_unhandled; ?> + + + services_critical_handled): ?> + + + services_critical_handled; ?> + + + + services_critical_unhandled): ?> + + + services_critical_unhandled && !$h->services_critical_handled): ?> + + - + + + + services_unknown_unhandled): ?> + + + services_unknown_unhandled; ?> + + + services_unknown_handled): ?> + + + services_unknown_handled; ?> + + + + services_unknown_unhandled): ?> + + + services_unknown_unhandled && !$h->services_unknown_handled): ?> + + - + + + + services_warning_unhandled): ?> + + + services_warning_unhandled; ?> + + + services_warning_handled): ?> + + + services_warning_handled; ?> + + + + services_warning_unhandled): ?> + + + services_warning_unhandled && !$h->services_warning_handled): ?> + + - + + + + services_pending): ?> + + + services_pending; ?> + + + + + - + + +
    +
    \ No newline at end of file diff --git a/modules/monitoring/application/views/scripts/list/servicegroups.phtml b/modules/monitoring/application/views/scripts/list/servicegroups.phtml index 7f9e4dd3d..50f680100 100644 --- a/modules/monitoring/application/views/scripts/list/servicegroups.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegroups.phtml @@ -1,269 +1,253 @@ -compact): ?> -
    - tabs ?> -
    - +compact): ?>
    -
    - - - -
    -

    - - servicegroup; ?> - -

    -
    - - - - - - - - - - - - - -
    translate('Hosts'); ?>translate('Services'); ?>
    -hosts_down_handled || $servicegroup->hosts_down_unhandled): ?> - -
    -hosts_down_unhandled): ?> - - hosts_down_unhandled; ?> translate('DOWN', 'icinga.state') ?> - - -hosts_down_handled): ?> - - hosts_down_handled . ' ' . ($servicegroup->hosts_down_unhandled ? $this->translate('Acknowledged') : 'DOWN'); ?> - - -
    - - -hosts_unreachable_handled || $servicegroup->hosts_unreachable_unhandled): ?> - -
    -hosts_unreachable_unhandled): ?> - - hosts_unreachable_unhandled; ?> translate('UNREACHABLE', 'icinga.state') ?> - - -hosts_unreachable_handled): ?> - - hosts_unreachable_handled . ' ' . ($servicegroup->hosts_unreachable_unhandled ? $this->translate('Acknowledged') : 'UNREACHABLE'); ?> - - -
    - - -hosts_up): ?> - -
    - - hosts_up; ?> translate('UP', 'icinga.state') ?> - -
    - - -hosts_pending): ?> - -
    - - hosts_pending; ?> translate('PENDING', 'icinga.state') ?> - -
    - - -
    -services_critical_handled || $servicegroup->services_critical_unhandled): ?> - -
    -services_critical_unhandled): ?> - - services_critical_unhandled; ?> translate('CRITICAL', 'icinga.state') ?> - - -services_critical_handled): ?> - - services_critical_handled . ' ' . ($servicegroup->services_critical_unhandled ? $this->translate('Acknowledged') : 'CRITICAL'); ?> - - -
    - - -services_warning_handled || $servicegroup->services_warning_unhandled): ?> - -
    -services_warning_unhandled): ?> - - services_warning_unhandled; ?> translate('WARNING', 'icinga.state') ?> - - -services_warning_handled): ?> - - services_warning_handled . ' ' . ($servicegroup->services_warning_unhandled ? $this->translate('Acknowledged') : 'WARNING'); ?> - - -
    - - -services_unknown_handled || $servicegroup->services_unknown_unhandled): ?> - -
    -services_unknown_unhandled): ?> - - services_unknown_unhandled; ?> translate('UNKNOWN', 'icinga.state') ?> - - -services_unknown_handled): ?> - - services_unknown_handled . ' ' . ($servicegroup->services_unknown_unhandled ? $this->translate('Acknowledged') : 'UNKNOWN'); ?> - - -
    - - -services_ok): ?> - -
    - - services_ok; ?> translate('OK', 'icinga.state') ?> - -
    - - -services_pending): ?> - -
    - - services_pending; ?> translate('PENDING', 'icinga.state') ?> - -
    - - -
    -
    -
    - -
    + +
    + tabs ?> + widget('limiter')->setMaxLimit(count($servicegroups)); ?> + paginationControl($servicegroups, null, null, array('preserve' => $this->preserve)); ?>
    +
    + filterEditor; ?> + + translate('No service groups matching the filter'); + echo '
    '; + return; + } + ?> + + + + + + + + + + + services_critical_last_state_change_unhandled): ?> + + services_unknown_last_state_change_unhandled): ?> + + services_warning_last_state_change_unhandled): ?> + + services_critical_last_state_change_handled): ?> + + services_unknown_last_state_change_handled): ?> + + services_warning_last_state_change_handled): ?> + + services_ok_last_state_change): ?> + + + + + + + + + + + + + + +
    translate('Last Problem'); ?>translate('Service Group'); ?>translate('Total Services'); ?>translate('Service States'); ?>
    + translate('CRITICAL'); ?> +
    + prefixedTimeSince($s->services_critical_last_state_change_unhandled); ?> +
    + translate('UNKNOWN'); ?> +
    + prefixedTimeSince($s->services_unknown_last_state_change_unhandled); ?> +
    + translate('WARNING'); ?> +
    + prefixedTimeSince($s->services_warning_last_state_change_unhandled); ?> +
    + translate('CRITICAL'); ?> +
    + prefixedTimeSince($s->services_critical_last_state_change_handled); ?> +
    + translate('UNKNOWN'); ?> +
    + prefixedTimeSince($s->services_unknown_last_state_change_handled); ?> +
    + translate('WARNING'); ?> +
    + prefixedTimeSince($s->services_warning_last_state_change_handled); ?> +
    + translate('OK'); ?> +
    + prefixedTimeSince($s->services_ok_last_state_change); ?> +
    + translate('PENDING'); ?> +
    + prefixedTimeSince($s->services_pending_last_state_change); ?> +
    + + servicegroup; ?> + + + services_total; ?> + + services_ok): ?> + + + services_ok; ?> + + + + + - + + + + services_critical_unhandled): ?> + + + services_critical_unhandled; ?> + + + services_critical_handled): ?> + + + services_critical_handled; ?> + + + + services_critical_unhandled): ?> + + + services_critical_unhandled && !$s->services_critical_handled): ?> + + - + + + + services_unknown_unhandled): ?> + + + services_unknown_unhandled; ?> + + + services_unknown_handled): ?> + + + services_unknown_handled; ?> + + + + services_unknown_unhandled): ?> + + + services_unknown_unhandled && !$s->services_unknown_handled): ?> + + - + + + + services_warning_unhandled): ?> + + + services_warning_unhandled; ?> + + + services_warning_handled): ?> + + + services_warning_handled; ?> + + + + services_warning_unhandled): ?> + + + services_warning_unhandled && !$s->services_warning_handled): ?> + + - + + + + services_pending): ?> + + + services_pending; ?> + + + + + - + + +
    +
    \ No newline at end of file diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/GroupsummaryQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/GroupsummaryQuery.php index 5a6bce41f..d38c40c8f 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/GroupsummaryQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/GroupsummaryQuery.php @@ -24,6 +24,7 @@ class GroupSummaryQuery extends IdoQuery 'hostgroup' => 'hostgroup' ), 'servicestatussummary' => array( + 'services_total' => 'SUM(CASE WHEN object_type = \'service\' THEN 1 ELSE 0 END)', 'services_ok' => 'SUM(CASE WHEN object_type = \'service\' AND state = 0 THEN 1 ELSE 0 END)', 'services_pending' => 'SUM(CASE WHEN object_type = \'service\' AND state = 99 THEN 1 ELSE 0 END)', 'services_warning' => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 THEN 1 ELSE 0 END)', @@ -35,6 +36,14 @@ class GroupSummaryQuery extends IdoQuery 'services_warning_unhandled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND acknowledged + in_downtime + host_state = 0 THEN 1 ELSE 0 END)', 'services_critical_unhandled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND acknowledged + in_downtime + host_state = 0 THEN 1 ELSE 0 END)', 'services_unknown_unhandled' => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND acknowledged + in_downtime + host_state = 0 THEN 1 ELSE 0 END)', + 'services_ok_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 0 THEN state_change ELSE 0 END)', + 'services_pending_last_state_change' => 'MAX(CASE WHEN object_type = \'service\' AND state = 99 THEN state_change ELSE 0 END)', + 'services_warning_last_state_change_handled' => 'MAX(CASE WHEN object_type = \'service\' AND state = 1 AND acknowledged + in_downtime + host_state > 0 THEN state_change ELSE 0 END)', + 'services_critical_last_state_change_handled' => 'MAX(CASE WHEN object_type = \'service\' AND state = 2 AND acknowledged + in_downtime + host_state > 0 THEN state_change ELSE 0 END)', + 'services_unknown_last_state_change_handled' => 'MAX(CASE WHEN object_type = \'service\' AND state = 3 AND acknowledged + in_downtime + host_state > 0 THEN state_change ELSE 0 END)', + 'services_warning_last_state_change_unhandled' => 'MAX(CASE WHEN object_type = \'service\' AND state = 1 AND acknowledged + in_downtime + host_state = 0 THEN state_change ELSE 0 END)', + 'services_critical_last_state_change_unhandled' => 'MAX(CASE WHEN object_type = \'service\' AND state = 2 AND acknowledged + in_downtime + host_state = 0 THEN state_change ELSE 0 END)', + 'services_unknown_last_state_change_unhandled' => 'MAX(CASE WHEN object_type = \'service\' AND state = 3 AND acknowledged + in_downtime + host_state = 0 THEN state_change ELSE 0 END)', 'servicegroup' => 'servicegroup' ) ); @@ -57,7 +66,8 @@ class GroupSummaryQuery extends IdoQuery $columns + array( 'state' => 'host_state', 'acknowledged' => 'host_acknowledged', - 'in_downtime' => 'host_in_downtime' + 'in_downtime' => 'host_in_downtime', + 'state_change' => 'host_last_state_change' ) ); if (in_array('servicegroup', $this->desiredColumns)) { @@ -68,7 +78,8 @@ class GroupSummaryQuery extends IdoQuery $columns + array( 'state' => 'service_state', 'acknowledged' => 'service_acknowledged', - 'in_downtime' => 'service_in_downtime' + 'in_downtime' => 'service_in_downtime', + 'state_change' => 'service_last_state_change' ) ); diff --git a/public/css/icinga/monitoring-colors.less b/public/css/icinga/monitoring-colors.less index c2abd9aba..f705b7844 100644 --- a/public/css/icinga/monitoring-colors.less +++ b/public/css/icinga/monitoring-colors.less @@ -820,3 +820,126 @@ div.timeline { } /* End of monitoring timeline styles */ + +/* Monitoring groupsummary styles */ + +table.groupview { + width: 100%; + margin-top: 1em; + border-collapse: separate; + border-spacing: 0.1em; + + thead th { + font-size: 0.9em; + } + + tbody { + tr { + &:hover { + color: #333; + } + + a { + color: #333; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + } + + td.services-total { + width: 10%; + text-align: center; + } + + td.state { + width: 10%; + color: white; + text-align: center; + + &.change { + width: 10%; + white-space: nowrap; + padding: 0.3em 0.5em 0.3em 0.5em; + + strong { + font-size: 0.8em; + } + + span.timesince { + font-size: 0.8em; + } + } + + &.ok { + color: #333; + border-left-style: solid; + border-left-width: 1.5em; + border-color: @colorOk; + } + + &.pending { + color: #333; + border-left-style: solid; + border-left-width: 1.5em; + border-color: @colorPending; + } + + &.warning { + background-color: @colorWarning; + + &.handled { + background-color: inherit; + color: #333; + border-left-style: solid; + border-left-width: 1.5em; + border-color: @colorWarningHandled; + } + } + + &.unknown { + background-color: @colorUnknown; + + &.handled { + color: #333; + background-color: inherit; + border-left-style: solid; + border-left-width: 1.5em; + border-color: @colorUnknownHandled; + } + } + + &.critical { + background-color: @colorCritical; + + &.handled { + color: #333; + background-color: inherit; + border-left-style: solid; + border-left-width: 1.5em; + border-color: @colorCriticalHandled; + } + } + + span { + &.no-state { + color: #333; + } + + &.state { + &.handled { + margin-right: 2px; + } + + a { + color: white; + } + } + } + } + } +} + +/* End of monitoring groupsummary styles */ From 42a8352a8f625e5120f1cb8f983b7d4d5a923d35 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 12:07:40 +0100 Subject: [PATCH 52/61] list/eventgrid: use filter, not filterEditor --- modules/monitoring/application/controllers/ListController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 4ad4af319..041273333 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -396,7 +396,8 @@ class Monitoring_ListController extends Controller array('day', $form->getValue('state')) ); $this->params->remove(array('objecttype', 'from', 'to', 'state', 'btn_submit')); - $this->filterQuery($query); + $this->view->filter = Filter::fromQuerystring((string) $this->params); + $query->applyFilter($this->view->filter); $this->view->summary = $query->getQuery()->fetchAll(); $this->view->column = $form->getValue('state'); // $this->view->orientationBox = $orientationBox; From 91ed348a471c136f5eef078bc31a51f3342e4238 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Wed, 19 Nov 2014 13:25:11 +0100 Subject: [PATCH 53/61] css/login: center form --- public/css/icinga/login.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/css/icinga/login.less b/public/css/icinga/login.less index 8eb4e2258..1c3148360 100644 --- a/public/css/icinga/login.less +++ b/public/css/icinga/login.less @@ -75,7 +75,7 @@ form { margin-left: auto; margin-right: auto; - width: 40em; + width: 35em; } form input { From fecdb34388b87477068f66b446ea756d342a74e0 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Nov 2014 13:35:14 +0100 Subject: [PATCH 54/61] Packages: Update paths in icingacli --- packages/files/bin/icingacli | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/files/bin/icingacli b/packages/files/bin/icingacli index 1e9b0ef12..10b4857aa 100755 --- a/packages/files/bin/icingacli +++ b/packages/files/bin/icingacli @@ -1,6 +1,6 @@ #!/usr/bin/php dispatch(); +require_once '/usr/share/php/Icinga/Application/Cli.php'; + +Icinga\Application\Cli::start('/usr/share/icingaweb')->dispatch(); From 91233b0d6c59d91888e922d4deabf1571ccaca8c Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Nov 2014 13:36:02 +0100 Subject: [PATCH 55/61] Packages: Add files/apache/icingaweb.conf in favor of files/icingaweb-apache2.conf --- packages/files/apache/icingaweb.conf | 38 +++++++++++++++++++++++++++ packages/files/icingaweb-apache2.conf | 19 -------------- 2 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 packages/files/apache/icingaweb.conf delete mode 100644 packages/files/icingaweb-apache2.conf diff --git a/packages/files/apache/icingaweb.conf b/packages/files/apache/icingaweb.conf new file mode 100644 index 000000000..e8c0c8f00 --- /dev/null +++ b/packages/files/apache/icingaweb.conf @@ -0,0 +1,38 @@ +Alias /icingaweb "/usr/share/icingaweb/public" + + + Options SymLinksIfOwnerMatch + AllowOverride None + + + # Apache 2.4 + + Require all granted + + + + + # Apache 2.2 + Order allow,deny + Allow from all + + + SetEnv ICINGAWEB_CONFIGDIR "/etc/icingaweb" + + EnableSendfile Off + + + RewriteEngine on + RewriteBase /icingaweb/ + RewriteCond %{REQUEST_FILENAME} -s [OR] + RewriteCond %{REQUEST_FILENAME} -l [OR] + RewriteCond %{REQUEST_FILENAME} -d + RewriteRule ^.*$ - [NC,L] + RewriteRule ^.*$ index.php [NC,L] + + + + DirectoryIndex error_norewrite.html + ErrorDocument 404 /error_norewrite.html + + diff --git a/packages/files/icingaweb-apache2.conf b/packages/files/icingaweb-apache2.conf deleted file mode 100644 index cde9aeec3..000000000 --- a/packages/files/icingaweb-apache2.conf +++ /dev/null @@ -1,19 +0,0 @@ -Alias /icingaweb "/usr/share/icingaweb/public" - - - Options SymLinksIfOwnerMatch - AllowOverride None - Order allow,deny - Allow from all - - # SetEnv ICINGAWEB_CONFIGDIR /etc/icingaweb - - RewriteEngine on - RewriteBase /icingaweb/ - RewriteCond %{REQUEST_FILENAME} -s [OR] - RewriteCond %{REQUEST_FILENAME} -l [OR] - RewriteCond %{REQUEST_FILENAME} -d - RewriteRule ^.*$ - [NC,L] - RewriteRule ^.*$ index.php [NC,L] - - From 6cb914af354babdbd33919c36851b70ad05810e3 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Nov 2014 13:42:49 +0100 Subject: [PATCH 56/61] Packages: Update library path in index.php --- packages/files/public/index.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/files/public/index.php b/packages/files/public/index.php index 1acee9445..ebd223c03 100644 --- a/packages/files/public/index.php +++ b/packages/files/public/index.php @@ -1,6 +1,3 @@ Date: Wed, 19 Nov 2014 13:42:59 +0100 Subject: [PATCH 57/61] Changes login screen and added header --- .../views/scripts/authentication/login.phtml | 1 + public/css/icinga/login.less | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/application/views/scripts/authentication/login.phtml b/application/views/scripts/authentication/login.phtml index e931d0448..584d8ad16 100644 --- a/application/views/scripts/authentication/login.phtml +++ b/application/views/scripts/authentication/login.phtml @@ -5,6 +5,7 @@
    +

    Welcome to Icinga Web 2

    errorInfo)): ?> diff --git a/public/css/icinga/login.less b/public/css/icinga/login.less index 1c3148360..cfae3c478 100644 --- a/public/css/icinga/login.less +++ b/public/css/icinga/login.less @@ -39,18 +39,17 @@ .form { position: absolute; font-size: 0.9em; - top: 50%; + top: 45%; left: 0; bottom: 0; right: 0; } .form h1 { - text-align: left; + text-align: center; font-size: 1.5em; - margin-left: auto; - margin-right: auto; - width: 12em; + margin-left: 2.3em; + border: none; color: @colorTextDefault; } @@ -108,9 +107,10 @@ } .footer { - margin-top: 2em; + margin-top: 7em; font-size: 0.9em; - text-align: center; + text-align: center; + margin-left: 5em; } div.config-note { From 968ede12df4dfb0cb5d583cd8aa9e5908bc6f905 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Nov 2014 13:43:58 +0100 Subject: [PATCH 58/61] Packages: Remove files from rpm subdirectory Those files are superseded by those beneath files. --- packages/rpm/etc/httpd/conf.d/icingaweb.conf | 32 ------------------- .../rpm/etc/icingaweb2/authentication.ini | 6 ---- .../modules/monitoring/backends.ini | 8 ----- .../modules/monitoring/instances.ini | 2 -- packages/rpm/etc/icingaweb2/resources.ini | 28 ---------------- packages/rpm/usr/bin/icingacli | 6 ---- 6 files changed, 82 deletions(-) delete mode 100644 packages/rpm/etc/httpd/conf.d/icingaweb.conf delete mode 100644 packages/rpm/etc/icingaweb2/authentication.ini delete mode 100644 packages/rpm/etc/icingaweb2/modules/monitoring/backends.ini delete mode 100644 packages/rpm/etc/icingaweb2/modules/monitoring/instances.ini delete mode 100644 packages/rpm/etc/icingaweb2/resources.ini delete mode 100755 packages/rpm/usr/bin/icingacli diff --git a/packages/rpm/etc/httpd/conf.d/icingaweb.conf b/packages/rpm/etc/httpd/conf.d/icingaweb.conf deleted file mode 100644 index 1db9f20f2..000000000 --- a/packages/rpm/etc/httpd/conf.d/icingaweb.conf +++ /dev/null @@ -1,32 +0,0 @@ -Alias /icingaweb "/usr/share/icingaweb2/public" - - - Options SymLinksIfOwnerMatch - AllowOverride None - - - # Apache 2.4 - - Require all granted - - - - - # Apache 2.2 - Order allow,deny - Allow from all - - - SetEnv ICINGAWEB_CONFIGDIR /etc/icingaweb2 - - EnableSendfile Off - - RewriteEngine on - RewriteBase /icingaweb/ - RewriteCond %{REQUEST_FILENAME} -s [OR] - RewriteCond %{REQUEST_FILENAME} -l [OR] - RewriteCond %{REQUEST_FILENAME} -d - RewriteRule ^.*$ - [NC,L] - RewriteRule ^.*$ index.php [NC,L] - - diff --git a/packages/rpm/etc/icingaweb2/authentication.ini b/packages/rpm/etc/icingaweb2/authentication.ini deleted file mode 100644 index 3ec9c033a..000000000 --- a/packages/rpm/etc/icingaweb2/authentication.ini +++ /dev/null @@ -1,6 +0,0 @@ -[autologin] -backend = autologin - -[internal_db_authentication] -backend = db -resource = internal_db diff --git a/packages/rpm/etc/icingaweb2/modules/monitoring/backends.ini b/packages/rpm/etc/icingaweb2/modules/monitoring/backends.ini deleted file mode 100644 index 6dd67d4b5..000000000 --- a/packages/rpm/etc/icingaweb2/modules/monitoring/backends.ini +++ /dev/null @@ -1,8 +0,0 @@ -[localdb] -type = ido -resource = "ido" - -[locallive] -disabled = "1" -type = livestatus -resource = livestatus diff --git a/packages/rpm/etc/icingaweb2/modules/monitoring/instances.ini b/packages/rpm/etc/icingaweb2/modules/monitoring/instances.ini deleted file mode 100644 index 037baa8b9..000000000 --- a/packages/rpm/etc/icingaweb2/modules/monitoring/instances.ini +++ /dev/null @@ -1,2 +0,0 @@ -[icinga] -path = "/var/run/icinga2/cmd/icinga2.cmd" diff --git a/packages/rpm/etc/icingaweb2/resources.ini b/packages/rpm/etc/icingaweb2/resources.ini deleted file mode 100644 index 833f84ba8..000000000 --- a/packages/rpm/etc/icingaweb2/resources.ini +++ /dev/null @@ -1,28 +0,0 @@ -[internal_db] -type = db -db = mysql -host = localhost -port = 3306 -password = icingaweb -username = icingaweb -dbname = icingaweb - -[ido] -type = db -db = mysql -host = localhost -port = 3306 -password = icinga -username = icinga -dbname = icinga - -[livestatus] -type = livestatus -socket = /var/run/icinga2/cmd/livestatus - -[logfile] -type = file -filename = "/var/log/icingaweb2/icingaweb2.log" -fields = "/^(?[0-9]{4}(-[0-9]{2}){2}T[0-9]{2}(:[0-9]{2}){2}(\\+[0-9]{2}:[0-9]{2})?) - (?[A-Za-z]+) - (?.*)$/" -; format: PCRE -; diff --git a/packages/rpm/usr/bin/icingacli b/packages/rpm/usr/bin/icingacli deleted file mode 100755 index d6c4010b6..000000000 --- a/packages/rpm/usr/bin/icingacli +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/php -dispatch(); From 1d4f7f8806748a7f16682fe28008ebbcebd924d2 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Nov 2014 13:45:02 +0100 Subject: [PATCH 59/61] Packages: Rename rpm/README.md to RPM.d --- packages/rpm/{README.md => RPM.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/rpm/{README.md => RPM.md} (100%) diff --git a/packages/rpm/README.md b/packages/rpm/RPM.md similarity index 100% rename from packages/rpm/README.md rename to packages/rpm/RPM.md From a0ec7c2396d84be39fa2b67b755cb5f95ec29e64 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Wed, 19 Nov 2014 13:45:24 +0100 Subject: [PATCH 60/61] Packages: Move rpm/RPM.md one directory up --- packages/{rpm => }/RPM.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/{rpm => }/RPM.md (100%) diff --git a/packages/rpm/RPM.md b/packages/RPM.md similarity index 100% rename from packages/rpm/RPM.md rename to packages/RPM.md From 066ea782aaee7501b830df4b45d3b112c30cbb79 Mon Sep 17 00:00:00 2001 From: Bernd Erk Date: Wed, 19 Nov 2014 13:48:56 +0100 Subject: [PATCH 61/61] Fixes Check now button --- .../application/forms/Command/Object/CheckNowCommandForm.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php b/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php index 477624bb6..01006683f 100644 --- a/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php @@ -28,8 +28,6 @@ class CheckNowCommandForm extends ObjectsCommandForm */ public function addSubmitButton() { - $iconUrl = $this->getView()->href('img/icons/refresh_petrol.png'); - $this->addElements(array( array( 'button', @@ -38,7 +36,7 @@ class CheckNowCommandForm extends ObjectsCommandForm 'ignore' => true, 'type' => 'submit', 'value' => mt('monitoring', 'Check now'), - 'label' => ' ' . mt('monitoring', 'Check now'), + 'label' => ' ' . mt('monitoring', 'Check now'), 'decorators' => array('ViewHelper'), 'escape' => false, 'class' => 'link-like'