Merge branch 'master' into feature/packages-4075
This commit is contained in:
commit
4ea52161a9
|
@ -12,4 +12,6 @@ node default {
|
|||
file { '/etc/profile.d/env.sh':
|
||||
source => 'puppet:////vagrant/.puppet/files/etc/profile.d/env.sh'
|
||||
}
|
||||
@user { vagrant: ensure => present }
|
||||
User <| title == vagrant |> { groups +> icingaweb }
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# TODO(el): This module is not reuseable because it relies on vagrant paths
|
||||
class icingacli {
|
||||
file { '/usr/local/bin/icingacli':
|
||||
ensure => link,
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Icinga\Forms\Security;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use Zend_Form_Element;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Util\String;
|
||||
|
@ -18,14 +19,14 @@ class RoleForm extends ConfigForm
|
|||
/**
|
||||
* Provided permissions by currently loaded modules
|
||||
*
|
||||
* @var array
|
||||
* @type array
|
||||
*/
|
||||
protected $providedPermissions = array();
|
||||
protected $providedPermissions = array('*' => '*');
|
||||
|
||||
/**
|
||||
* Provided restrictions by currently loaded modules
|
||||
*
|
||||
* @var array
|
||||
* @type array
|
||||
*/
|
||||
protected $providedRestrictions = array();
|
||||
|
||||
|
@ -35,14 +36,26 @@ class RoleForm extends ConfigForm
|
|||
*/
|
||||
public function init()
|
||||
{
|
||||
$helper = new Zend_Form_Element('bogus');
|
||||
foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) {
|
||||
foreach ($module->getProvidedPermissions() as $permission) {
|
||||
/** @var object $permission */
|
||||
/** @type object $permission */
|
||||
$this->providedPermissions[$permission->name] = $permission->name . ': ' . $permission->description;
|
||||
}
|
||||
foreach ($module->getProvidedRestrictions() as $restriction) {
|
||||
/** @var object $restriction */
|
||||
$this->providedRestrictions[$restriction->name] = $restriction->description;
|
||||
/** @type object $restriction */
|
||||
$name = $helper->filterName($restriction->name); // Zend only permits alphanumerics, the underscore,
|
||||
// the circumflex and any ASCII character in range
|
||||
// \x7f to \xff (127 to 255)
|
||||
while (isset($this->providedRestrictions[$name])) {
|
||||
// Because Zend_Form_Element::filterName() replaces any not permitted character with the empty
|
||||
// string we may have duplicate names, e.g. 're/striction' and 'restriction'
|
||||
$name .= '_';
|
||||
}
|
||||
$this->providedRestrictions[$name] = array(
|
||||
'description' => $restriction->description,
|
||||
'name' => $restriction->name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,13 +103,13 @@ class RoleForm extends ConfigForm
|
|||
)
|
||||
)
|
||||
));
|
||||
foreach ($this->providedRestrictions as $name => $description) {
|
||||
foreach ($this->providedRestrictions as $name => $spec) {
|
||||
$this->addElement(
|
||||
'text',
|
||||
$name,
|
||||
array(
|
||||
'label' => $name,
|
||||
'description' => $description
|
||||
'label' => $spec['name'],
|
||||
'description' => $spec['description']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -129,6 +142,15 @@ class RoleForm extends ConfigForm
|
|||
? String::trimSplit($role['permissions'])
|
||||
: null;
|
||||
$role['name'] = $name;
|
||||
$restrictions = array();
|
||||
foreach ($this->providedRestrictions as $name => $spec) {
|
||||
if (isset($role[$spec['name']])) {
|
||||
// Translate restriction names to filtered element names
|
||||
$restrictions[$name] = $role[$spec['name']];
|
||||
unset($role[$spec['name']]);
|
||||
}
|
||||
}
|
||||
$role = array_merge($role, $restrictions);
|
||||
$this->populate($role);
|
||||
return $this;
|
||||
}
|
||||
|
@ -230,6 +252,15 @@ class RoleForm extends ConfigForm
|
|||
if (isset($values['permissions'])) {
|
||||
$values['permissions'] = implode(', ', $values['permissions']);
|
||||
}
|
||||
$restrictions = array();
|
||||
foreach ($this->providedRestrictions as $name => $spec) {
|
||||
if (isset($values[$name])) {
|
||||
// Translate filtered element names to restriction names
|
||||
$restrictions[$spec['name']] = $values[$name];
|
||||
unset($values[$name]);
|
||||
}
|
||||
}
|
||||
$values = array_merge($values, $restrictions);
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<?php if ($configMissing): ?>
|
||||
<div class="config-note"><?= sprintf(
|
||||
t(
|
||||
'You seem not to have Icinga Web 2 configured yet so it\'s not possible to log in without any defined '
|
||||
'It appears that you did not configure Icinga Web 2 yet so it\'s not possible to log in without any defined '
|
||||
. 'authentication method. Please define a authentication method by following the instructions in the'
|
||||
. ' %1$sdocumentation%3$s or by using our %2$sweb-based setup-wizard%3$s.'
|
||||
),
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<td>
|
||||
<?php
|
||||
// TODO(el): $role->without(...) or $role->shift(...) would be nice!
|
||||
$restrictions = $role;
|
||||
$restrictions = clone $role;
|
||||
unset($restrictions['users']);
|
||||
unset($restrictions['groups']);
|
||||
unset($restrictions['permissions']);
|
||||
|
|
|
@ -2,21 +2,23 @@
|
|||
|
||||
**Choosing the Authentication Method**
|
||||
|
||||
With Icinga Web 2 you can authenticate against Active Directory, LDAP, a MySQL or PostgreSQL database or delegate
|
||||
authentication to the web server. Authentication methods can be chained to set up fallback authentication methods
|
||||
With Icinga Web 2 you can authenticate against Active Directory, LDAP, a MySQL or a PostgreSQL database or delegate
|
||||
authentication to the web server.
|
||||
|
||||
Authentication methods can be chained to set up fallback authentication methods
|
||||
or if users are spread over multiple places.
|
||||
|
||||
## Configuration
|
||||
## <a id="authentication-configuration"></a> Configuration
|
||||
|
||||
Authentication methods are configured in the INI file **config/authentication.ini**.
|
||||
|
||||
Each section in the authentication configuration represents a single authentication method.
|
||||
|
||||
The order of entries in the authentication configuration determines the order of the authentication methods.
|
||||
If the current authentication method errors or the current authentication method does not know the account being
|
||||
If the current authentication method errors or if the current authentication method does not know the account being
|
||||
authenticated, the next authentication method will be used.
|
||||
|
||||
## External Authentication
|
||||
### <a id="authentication-configuration-external-authentication"></a> External Authentication
|
||||
|
||||
For delegating authentication to the web server simply add `autologin` to your authentication configuration:
|
||||
|
||||
|
@ -27,13 +29,13 @@ backend = autologin
|
|||
|
||||
If your web server is not configured for authentication though the `autologin` section has no effect.
|
||||
|
||||
## Active Directory or LDAP Authentication
|
||||
### <a id="authentication-configuration-ad-or-ldap-authentication"></a> Active Directory or LDAP Authentication
|
||||
|
||||
If you want to authenticate against Active Directory or LDAP, you have to define a
|
||||
[LDAP resource](#resources-configuration-ldap) first which will be referenced as data source for the Active Directory
|
||||
[LDAP resource](#resources-configuration-ldap) which will be referenced as data source for the Active Directory
|
||||
or LDAP configuration method.
|
||||
|
||||
### LDAP
|
||||
#### <a id="authentication-configuration-ldap-authentication"></a> LDAP
|
||||
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
|
@ -52,7 +54,7 @@ user_class = inetOrgPerson
|
|||
user_name_attribute = uid
|
||||
```
|
||||
|
||||
### Active Directory
|
||||
#### <a id="authentication-configuration-ad-authentication"></a> Active Directory
|
||||
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
|
@ -67,10 +69,10 @@ backend = ad
|
|||
resource = my_ad
|
||||
```
|
||||
|
||||
## Database Authentication
|
||||
### <a id="authentication-configuration-db-authentication"></a> Database Authentication
|
||||
|
||||
If you want to authenticate against a MySQL or PostgreSQL database, you have to define a
|
||||
[database resource](#resources-configuration-database) first which will be referenced as data source for the database
|
||||
If you want to authenticate against a MySQL or a PostgreSQL database, you have to define a
|
||||
[database resource](#resources-configuration-database) which will be referenced as data source for the database
|
||||
authentication method.
|
||||
|
||||
Directive | Description
|
||||
|
@ -83,13 +85,31 @@ Directive | Description
|
|||
```
|
||||
[auth_ad]
|
||||
backend = ad
|
||||
resource = my_db
|
||||
resource = icingaweb-mysql
|
||||
```
|
||||
|
||||
#### <a id="authentication-configuration-db-setup"></a> Database Setup
|
||||
|
||||
For authenticating against a database, you have to import one of the following database schemas:
|
||||
|
||||
* **etc/schema/preferences.mysql.sql** (for **MySQL** database)
|
||||
* **etc/schema/preferences.pgsql.sql** (for **PostgreSQL** databases)
|
||||
|
||||
After that you have to define the [database resource](#resources-configuration-database).
|
||||
|
||||
**Manually Creating Users**
|
||||
|
||||
Icinga Web 2 uses the MD5 based BSD password algorithm. For generating a password hash, please use the following
|
||||
command:
|
||||
|
||||
````
|
||||
openssl passwd -1 "password"
|
||||
````
|
||||
|
||||
> Note: The switch to `openssl passwd` is the **number one** (`-1`) for using the MD5 based BSD password algorithm.
|
||||
|
||||
Insert the user into the database using the generated password hash:
|
||||
|
||||
````
|
||||
INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, 'hash from openssl');
|
||||
````
|
||||
|
|
|
@ -26,7 +26,7 @@ repository either via git or http protocol using the following URLs:
|
|||
* http://git.icinga.org/icingaweb2.git
|
||||
|
||||
There is also a browsable version available at
|
||||
[gi.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository").
|
||||
[git.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository").
|
||||
This version also offers snapshots for easy download which you can use if you do not have git present on your system.
|
||||
|
||||
````
|
||||
|
|
|
@ -1,101 +1,53 @@
|
|||
# Preferences
|
||||
# <a id="preferences"></a> Preferences
|
||||
|
||||
Preferences are user based configuration for Icinga Web 2. For example max page
|
||||
items, languages or date time settings can controlled by users.
|
||||
Preferences are settings a user can set for his account only, for example his language and time zone.
|
||||
|
||||
# Architecture
|
||||
**Choosing Where to Store Preferences**
|
||||
|
||||
Preferences are initially loaded from a provider (ini files or database) and
|
||||
stored into session at login time. After this step preferences are only
|
||||
persisted to the configured backend, but never reloaded from them.
|
||||
Preferences can be stored either in INI files or in a MySQL or in a PostgreSQL database. By default, Icinga Web 2 stores
|
||||
preferences in INI files beneath Icinga Web 2's configuration directory.
|
||||
|
||||
# Configuration
|
||||
## <a id="preferences-configuration"></a> Configuration
|
||||
|
||||
Preferences can be configured in config.ini in **preferences** section, default
|
||||
settings are this:
|
||||
Where to store preferences is defined in the INI file **config/config.ini** in the *preferences* section.
|
||||
|
||||
[preferences]
|
||||
type=ini
|
||||
### <a id="preferences-configuration-ini"></a> Store Preferences in INI Files
|
||||
|
||||
The ini provider uses the directory **config/preferences** to create one ini
|
||||
file per user and persists the data into a single file. If you want to drop your
|
||||
preferences just drop the file from disk and you'll start with a new profile.
|
||||
If preferences are stored in INI Files, Icinga Web 2 automatically creates one file per user using the username as
|
||||
file name for storing preferences. A INI file is created once a user saves changed preferences the first time.
|
||||
The files are located beneath the `preferences` directory beneath Icinga Web 2's configuration directory.
|
||||
|
||||
## Database Provider
|
||||
For storing preferences in INI files you have to add the following section to the INI file **config/config.ini**:
|
||||
|
||||
To be more flexible in distributed setups you can store preferences in a
|
||||
database (pgsql or mysql), a typical configuration looks like the following
|
||||
example:
|
||||
```
|
||||
[preferences]
|
||||
type = ini
|
||||
````
|
||||
|
||||
[preferences]
|
||||
type=db
|
||||
resource=icingaweb-pgsql
|
||||
### <a id="preferences-configuration-db"></a> Store Preferences in a Database
|
||||
|
||||
## Null Provider
|
||||
In order to be more flexible in distributed setups you can store preferences in a MySQL or in a PostgreSQL database.
|
||||
For storing preferences in a database, you have to define a [database resource](#resources-configuration-database)
|
||||
which will be referenced as resource for the preferences storage.
|
||||
|
||||
The Null Provider discards all preferences and is mainly used as a fallback when no provider could be
|
||||
created (due to permission errors, database outtakes, etc.).
|
||||
Directive | Description
|
||||
------------------------|------------
|
||||
**type** | `db`
|
||||
**resource** | The name of the database resource defined in [resources.ini](resources).
|
||||
|
||||
[preferences]
|
||||
type=null
|
||||
**Example:**
|
||||
|
||||
If your preferences aren't stored it's best to take a look into the logfiles - errors during the preference setup
|
||||
are displayed as warnings here.
|
||||
```
|
||||
[preferences]
|
||||
type = db
|
||||
resource = icingaweb-mysql
|
||||
```
|
||||
|
||||
### Settings
|
||||
#### <a id="preferences-configuration-db-setup"></a> Database Setup
|
||||
|
||||
* **resource**: A reference to a database declared in *resources.ini*. Please read the chapter about
|
||||
resources for a detailed description about how to set up resources.
|
||||
For storing preferences in a database, you have to import one of the following database schemas:
|
||||
|
||||
### Preparation
|
||||
* **etc/schema/preferences.mysql.sql** (for **MySQL** database)
|
||||
* **etc/schema/preferences.pgsql.sql** (for **PostgreSQL** databases)
|
||||
|
||||
To use this feature you need a running database environment. After creating a
|
||||
database and a writable user you need to import the initial table file:
|
||||
|
||||
* etc/schema/preferences.mysql.sql (for mysql database)
|
||||
* etc/schema/preferemces.pgsql.sql (for postgres databases)
|
||||
|
||||
#### Example for mysql
|
||||
|
||||
# mysql -u root -p
|
||||
mysql> create database icingaweb;
|
||||
mysql> GRANT SELECT,INSERT,UPDATE,DELETE ON icingaweb.* TO \
|
||||
'icingaweb'@'localhost' IDENTIFIED BY 'icingaweb';
|
||||
mysql> exit
|
||||
# mysql -u root -p icingaweb < /path/to/icingaweb/etc/schema/preferences.mysql.sql
|
||||
|
||||
After following these steps above you can configure your preferences provider.
|
||||
|
||||
## Coding API
|
||||
|
||||
You can set, update or remove preferences using the Preference data object
|
||||
which is bound to the user. Here are some simple examples how to work with
|
||||
that:
|
||||
|
||||
$preferences = $user->getPreferences();
|
||||
// Get language with en_US as fallback
|
||||
$preferences->get('app.language', 'en_US');
|
||||
$preferences->set('app.language', 'de_DE');
|
||||
$preferences->remove('app.language');
|
||||
|
||||
// Using transactional mode
|
||||
$preferences->startTransaction();
|
||||
$preferences->set('test.pref1', 'pref1');
|
||||
$preferences->set('test.pref2', 'pref2');
|
||||
$preferences->remove('test.pref3');
|
||||
$preferemces->commit(); // Stores 3 changes in one operation
|
||||
|
||||
More information can be found in the api docs.
|
||||
|
||||
## Namespaces and behaviour
|
||||
|
||||
If you are using this API please obey the following rules:
|
||||
|
||||
* Use dotted notation for preferences
|
||||
* Namespaces starting with one context identifier
|
||||
* **app** as global identified (e.g. app.language)
|
||||
* **mymodule** for your module
|
||||
* **monitoring** for the monitoring module
|
||||
* Use preferences wisely (set only when needed and write small settings)
|
||||
* Use only simple data types, e.g. strings or numbers
|
||||
* If you need complex types you have to do it your self (e.g. serialization)
|
||||
After that you have to define the [database resource](#resources-configuration-database).
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
Icinga Web 2
|
||||
|
||||
@link https://www.icinga.org/icingaweb2/
|
||||
@copyright Copyright (c) 2013-%(YEAR)s Icinga Development Team (https://www.icinga.org)
|
||||
@license http://www.gnu.org/licenses/gpl-2.0.txt, or any later version
|
|
@ -23,16 +23,17 @@ class String
|
|||
}
|
||||
|
||||
/**
|
||||
* Uppercase the first character of each word in a string assuming and removing the underscore as word separator
|
||||
* Uppercase the first character of each word in a string
|
||||
*
|
||||
* Converts 'first_name' to 'firstName' for example.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $separator Word separator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function cname($name)
|
||||
public static function cname($name, $separator = '_')
|
||||
{
|
||||
return str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($name))));
|
||||
return str_replace(' ', '', ucwords(str_replace($separator, ' ', strtolower($name))));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
namespace Icinga\Util;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
|
@ -34,8 +33,8 @@ class Translator
|
|||
*
|
||||
* Falls back to the default domain in case the string cannot be translated using the given domain
|
||||
*
|
||||
* @param string $text The string to translate
|
||||
* @param string $domain The primary domain to use
|
||||
* @param string $text The string to translate
|
||||
* @param string $domain The primary domain to use
|
||||
* @param string|null $context Optional parameter for context based translation
|
||||
*
|
||||
* @return string The translated string
|
||||
|
@ -64,7 +63,7 @@ class Translator
|
|||
*
|
||||
* @param string $textSingular The string in singular form to translate
|
||||
* @param string $textPlural The string in plural form to translate
|
||||
* @param integer $number The number to get the plural or singular string
|
||||
* @param integer $number The amount to determine from whether to return singular or plural
|
||||
* @param string $domain The primary domain to use
|
||||
* @param string|null $context Optional parameter for context based translation
|
||||
*
|
||||
|
|
|
@ -9,6 +9,7 @@ use Zend_Config;
|
|||
use Zend_Form;
|
||||
use Zend_View_Interface;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Form\Decorator\NoScriptApply;
|
||||
use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
||||
|
||||
|
@ -147,7 +148,7 @@ class Form extends Zend_Form
|
|||
/**
|
||||
* Set a callback that is called instead of this form's onSuccess method
|
||||
*
|
||||
* It is called using the following signature: (Request $request, Form $form).
|
||||
* It is called using the following signature: (Form $this).
|
||||
*
|
||||
* @param callable $onSuccess Callback
|
||||
*
|
||||
|
@ -804,6 +805,57 @@ class Form extends Zend_Form
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the translation domain for this form
|
||||
*
|
||||
* The returned translation domain is either determined based on
|
||||
* this form's class path or it is the default `icinga' domain
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTranslationDomain()
|
||||
{
|
||||
if (preg_match('@^Icinga\\\\Module\\\\([A-z]+)\\\\.*$@', get_called_class(), $matches) === 1) {
|
||||
return strtolower($matches[0]);
|
||||
}
|
||||
|
||||
return 'icinga';
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a string
|
||||
*
|
||||
* @param string $text The string to translate
|
||||
* @param string|null $context Optional parameter for context based translation
|
||||
*
|
||||
* @return string The translated string
|
||||
*/
|
||||
protected function translate($text, $context = null)
|
||||
{
|
||||
return Translator::translate($text, $this->getTranslationDomain(), $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a plural string
|
||||
*
|
||||
* @param string $textSingular The string in singular form to translate
|
||||
* @param string $textPlural The string in plural form to translate
|
||||
* @param integer $number The amount to determine from whether to return singular or plural
|
||||
* @param string|null $context Optional parameter for context based translation
|
||||
*
|
||||
* @return string The translated string
|
||||
*/
|
||||
protected function translatePlural($textSingular, $textPlural, $number, $context = null)
|
||||
{
|
||||
return Translator::translatePlural(
|
||||
$textSingular,
|
||||
$textPlural,
|
||||
$number,
|
||||
$this->getTranslationDomain(),
|
||||
$context
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this form
|
||||
*
|
||||
|
|
|
@ -78,8 +78,9 @@ class PhpSession extends Session
|
|||
}
|
||||
}
|
||||
|
||||
if (!is_writable(session_save_path())) {
|
||||
throw new ConfigurationError('Can\'t save session');
|
||||
$sessionSavePath = session_save_path();
|
||||
if (session_module_name() === 'files' && !is_writable($sessionSavePath)) {
|
||||
throw new ConfigurationError("Can't save session, path '$sessionSavePath' is not writable.");
|
||||
}
|
||||
|
||||
if ($this->exists()) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
namespace Icinga\Web\Widget\Chart;
|
||||
|
||||
use Icinga\Chart\PieChart;
|
||||
use Icinga\Module\Monitoring\Plugin\PerfdataSet;
|
||||
use Icinga\Web\Widget\AbstractWidget;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Util\Format;
|
||||
|
@ -28,36 +29,23 @@ class InlinePie extends AbstractWidget
|
|||
const NUMBER_FORMAT_RATIO = 'ratio';
|
||||
|
||||
/**
|
||||
* The template string used for rendering this widget
|
||||
* The template string used for rendering this widget
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $template =<<<'EOD'
|
||||
<span
|
||||
class="sparkline"
|
||||
sparkTitle="{title}"
|
||||
sparkWidth="{width}"
|
||||
sparkHeight="{height}"
|
||||
sparkBorderWidth="{borderWidth}"
|
||||
sparkBorderColor="{borderColor}"
|
||||
sparkTooltipChartTitle="{title}"
|
||||
style="{style}"
|
||||
labels="{labels}"
|
||||
formatted="{formatted}"
|
||||
hideEmptyLabel={hideEmptyLabel}
|
||||
values="{data}"
|
||||
tooltipFormat="{tooltipFormat}"
|
||||
sparkSliceColors="[{colors}]"
|
||||
sparkType="pie"></span>
|
||||
<noscript>
|
||||
<img class="inlinepie"
|
||||
title="{title}" src="{url}" style="position: relative; top: 10px; width: {width}px; height: {height}px; {style}"
|
||||
data-icinga-colors="{colors}" data-icinga-values="{data}"
|
||||
/>
|
||||
</noscript>
|
||||
<span sparkType="pie" class="sparkline {class}" {title} {size} sparkSliceColors="[{colors}]" values="{data}">
|
||||
</span>
|
||||
{noscript}
|
||||
EOD;
|
||||
|
||||
private $noscript =<<<'EOD'
|
||||
<noscript>
|
||||
<img class="inlinepie {class}" {title} src="{url}" data-icinga-colors="{colors}" data-icinga-values="{data}"/>
|
||||
</noscript>
|
||||
EOD;
|
||||
|
||||
|
||||
/**
|
||||
* @var Url
|
||||
*/
|
||||
|
@ -68,35 +56,7 @@ EOD;
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
private $colors = array('#44bb77', '#ffaa44', '#ff5566', '#ddccdd');
|
||||
|
||||
/**
|
||||
* The width of the rendered chart
|
||||
*
|
||||
* @var int The value in px
|
||||
*/
|
||||
private $width = 16;
|
||||
|
||||
/**
|
||||
* The height of the rendered chart
|
||||
*
|
||||
* @var int The value in px
|
||||
*/
|
||||
private $height = 16;
|
||||
|
||||
/**
|
||||
* PieChart border width
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
private $borderWidth = 1;
|
||||
|
||||
/**
|
||||
* The color of the border
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $borderColor = '#fff';
|
||||
private $colors = array('#049BAF', '#ffaa44', '#ff5566', '#ddccdd');
|
||||
|
||||
/**
|
||||
* The title of the chart
|
||||
|
@ -106,11 +66,9 @@ EOD;
|
|||
private $title;
|
||||
|
||||
/**
|
||||
* The style for the HtmlElement
|
||||
*
|
||||
* @var string
|
||||
* @var
|
||||
*/
|
||||
private $style = '';
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* The data displayed by the pie-chart
|
||||
|
@ -120,45 +78,9 @@ EOD;
|
|||
private $data;
|
||||
|
||||
/**
|
||||
* The labels to display for each data set
|
||||
*
|
||||
* @var array
|
||||
* @var
|
||||
*/
|
||||
private $labels = array();
|
||||
|
||||
/**
|
||||
* If the tooltip for the "empty" area should be hidden
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $hideEmptyLabel = false;
|
||||
|
||||
/**
|
||||
* The format string used to display tooltips
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $tooltipFormat = '<b>{{title}}</b></br> {{label}}: {{formatted}} ({{percent}}%)';
|
||||
|
||||
/**
|
||||
* The number format used to render numeric values in tooltips
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $format = self::NUMBER_FORMAT_NONE;
|
||||
|
||||
/**
|
||||
* Set if the tooltip for the empty area should be hidden
|
||||
*
|
||||
* @param bool $hide Whether to hide the empty area
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHideEmptyLabel($hide = true)
|
||||
{
|
||||
$this->hideEmptyLabel = $hide;
|
||||
return $this;
|
||||
}
|
||||
private $class = '';
|
||||
|
||||
/**
|
||||
* Set the data to be displayed.
|
||||
|
@ -175,24 +97,36 @@ EOD;
|
|||
}
|
||||
|
||||
/**
|
||||
* The labels to be displayed in the pie-chart
|
||||
* Set the size of the inline pie
|
||||
*
|
||||
* @param mixed $label The label of the displayed value, or null for no labels
|
||||
* @param int $size Sets both, the height and width
|
||||
*
|
||||
* @return $this
|
||||
* @return $this
|
||||
*/
|
||||
public function setLabel($label)
|
||||
public function setSize($size = null)
|
||||
{
|
||||
if (is_array($label)) {
|
||||
$this->url->setParam('labels', implode(',', array_keys($label)));
|
||||
} elseif ($label != null) {
|
||||
$labelArr = array($label, $label, $label, '');
|
||||
$this->url->setParam('labels', implode(',', $labelArr));
|
||||
$label = $labelArr;
|
||||
} else {
|
||||
$this->url->removeKey('labels');
|
||||
}
|
||||
$this->labels = $label;
|
||||
$this->size = $size;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not display the NoScript fallback html
|
||||
*/
|
||||
public function disableNoScript()
|
||||
{
|
||||
$this->noscript = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class to define the
|
||||
*
|
||||
* @param $class
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSparklineClass($class)
|
||||
{
|
||||
$this->class = $class;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -214,105 +148,6 @@ EOD;
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the used number format
|
||||
*
|
||||
* @param $format string 'bytes' or 'time'
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setNumberFormat($format)
|
||||
{
|
||||
$this->format = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A format string used to render the content of the piechart tooltips
|
||||
*
|
||||
* Placeholders using curly braces '{FOO}' are replace with their specific values. The format
|
||||
* String may contain HTML-Markup. The available replaceable values are:
|
||||
* <ul>
|
||||
* <li><b>label</b>: The description for the current value </li>
|
||||
* <li><b>formatted</b>: A string representing the formatted value </li>
|
||||
* <li><b>value</b>: The raw (non-formatted) value used to render the piechart </li>
|
||||
* <li><b>percent</b>: The percentage of the current value </li>
|
||||
* </ul>
|
||||
* Note: Changes will only affect JavaScript sparklines and not the SVG charts used for fallback
|
||||
*
|
||||
* @param $format
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTooltipFormat($format)
|
||||
{
|
||||
$this->tooltipFormat = $format;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height
|
||||
*
|
||||
* @param $height
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHeight($height)
|
||||
{
|
||||
$this->height = $height;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the border width of the pie chart
|
||||
*
|
||||
* @param float $width Width in px
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBorderWidth($width)
|
||||
{
|
||||
$this->borderWidth = $width;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color of the pie chart border
|
||||
*
|
||||
* @param string $col The color string
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBorderColor($col)
|
||||
{
|
||||
$this->borderColor = $col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width
|
||||
*
|
||||
* @param $width
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setWidth($width)
|
||||
{
|
||||
$this->width = $width;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the styling of the created HtmlElement
|
||||
*
|
||||
* @param string $style
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setStyle($style)
|
||||
{
|
||||
$this->style = $style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of the displayed Data
|
||||
*
|
||||
|
@ -322,7 +157,7 @@ EOD;
|
|||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->title = 'title="' . htmlspecialchars($title) . '"';
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -335,13 +170,10 @@ EOD;
|
|||
*/
|
||||
public function __construct(array $data, $title, $colors = null)
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->setTitle($title);
|
||||
$this->url = Url::fromPath('svg/chart.php');
|
||||
if (array_key_exists('data', $data)) {
|
||||
$this->data = $data['data'];
|
||||
if (array_key_exists('labels', $data)) {
|
||||
$this->labels = $data['labels'];
|
||||
}
|
||||
if (array_key_exists('colors', $data)) {
|
||||
$this->colors = $data['colors'];
|
||||
}
|
||||
|
@ -354,21 +186,6 @@ EOD;
|
|||
$this->setColors($this->colors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a serialization containing the current label array
|
||||
*
|
||||
* @return string A serialized array of labels
|
||||
*/
|
||||
private function createLabelString ()
|
||||
{
|
||||
$labels = $this->labels;
|
||||
foreach ($labels as $key => $label) {
|
||||
$labels[$key] = str_replace('|', '', $label);
|
||||
}
|
||||
return isset($this->labels) && is_array($this->labels) ? implode('|', $this->labels) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this widget via the given view and returns the
|
||||
* HTML as a string
|
||||
|
@ -382,11 +199,11 @@ EOD;
|
|||
$pie->alignTopLeft();
|
||||
$pie->disableLegend();
|
||||
$pie->drawPie(array(
|
||||
'data' => $this->data, 'colors' => $this->colors, 'labels' => $this->labels
|
||||
'data' => $this->data, 'colors' => $this->colors
|
||||
));
|
||||
|
||||
try {
|
||||
$png = $pie->toPng($this->width, $this->height);
|
||||
$png = $pie->toPng($this->size, $this->size);
|
||||
return '<img class="inlinepie" src="data:image/png;base64,' . base64_encode($png) . '" />';
|
||||
} catch (IcingaException $_) {
|
||||
return '';
|
||||
|
@ -394,17 +211,17 @@ EOD;
|
|||
}
|
||||
|
||||
$template = $this->template;
|
||||
// TODO: Check whether we are XHR and don't send
|
||||
$template = str_replace('{noscript}', $this->noscript, $template);
|
||||
$template = str_replace('{url}', $this->url, $template);
|
||||
$template = str_replace('{class}', $this->class, $template);
|
||||
|
||||
// style
|
||||
$template = str_replace('{width}', $this->width, $template);
|
||||
$template = str_replace('{height}', $this->height, $template);
|
||||
$template = str_replace('{title}', htmlspecialchars($this->title), $template);
|
||||
$template = str_replace('{style}', $this->style, $template);
|
||||
$template = str_replace('{size}',
|
||||
isset($this->size) ? 'sparkWidth="' . $this->size . '" sparkHeight="' . $this->size . '" ' : '', $template);
|
||||
$template = str_replace('{title}', $this->title, $template);
|
||||
|
||||
$template = str_replace('{colors}', implode(',', $this->colors), $template);
|
||||
$template = str_replace('{borderWidth}', $this->borderWidth, $template);
|
||||
$template = str_replace('{borderColor}', $this->borderColor, $template);
|
||||
$template = str_replace('{hideEmptyLabel}', $this->hideEmptyLabel ? 'true' : 'false', $template);
|
||||
|
||||
// Locale-ignorant string cast. Please. Do. NOT. Remove. This. Again.
|
||||
// Problem is that implode respects locales when casting floats. This means
|
||||
|
@ -414,38 +231,7 @@ EOD;
|
|||
$data[] = sprintf('%F', $dat);
|
||||
}
|
||||
|
||||
// values
|
||||
$formatted = array();
|
||||
foreach ($this->data as $key => $value) {
|
||||
$formatted[$key] = $this->formatValue($value);
|
||||
}
|
||||
$template = str_replace('{data}', htmlspecialchars(implode(',', $data)), $template);
|
||||
$template = str_replace('{formatted}', htmlspecialchars(implode('|', $formatted)), $template);
|
||||
$template = str_replace('{labels}', htmlspecialchars($this->createLabelString()), $template);
|
||||
$template = str_replace('{tooltipFormat}', $this->tooltipFormat, $template);
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the given value depending on the current value of numberFormat
|
||||
*
|
||||
* @param float $value The value to format
|
||||
*
|
||||
* @return string The formatted value
|
||||
*/
|
||||
private function formatValue($value)
|
||||
{
|
||||
if ($this->format === self::NUMBER_FORMAT_NONE) {
|
||||
return (string)$value;
|
||||
} elseif ($this->format === self::NUMBER_FORMAT_BYTES) {
|
||||
return Format::bytes($value);
|
||||
} elseif ($this->format === self::NUMBER_FORMAT_TIME) {
|
||||
return Format::duration($value);
|
||||
} elseif ($this->format === self::NUMBER_FORMAT_RATIO) {
|
||||
return $value;
|
||||
} else {
|
||||
Logger::warning('Unknown format string "' . $this->format . '" for InlinePie, value not formatted.');
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
namespace Icinga\Web\Widget\Tabextension;
|
||||
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Tab;
|
||||
use Icinga\Web\Widget\Tabs;
|
||||
|
@ -28,35 +29,6 @@ class OutputFormat implements Tabextension
|
|||
*/
|
||||
const TYPE_CSV = 'csv';
|
||||
|
||||
/**
|
||||
* An array containing the tab definitions for all supported types
|
||||
*
|
||||
* Using array_keys on this array or isset allows to check whether a
|
||||
* requested type is supported
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $supportedTypes = array(
|
||||
self::TYPE_PDF => array(
|
||||
'name' => 'pdf',
|
||||
'title' => 'PDF',
|
||||
'icon' => 'file-pdf',
|
||||
'urlParams' => array('format' => 'pdf'),
|
||||
),
|
||||
self::TYPE_CSV => array(
|
||||
'name' => 'csv',
|
||||
'title' => 'CSV',
|
||||
'icon' => 'file-excel',
|
||||
'urlParams' => array('format' => 'csv')
|
||||
),
|
||||
self::TYPE_JSON => array(
|
||||
'name' => 'json',
|
||||
'title' => 'JSON',
|
||||
'icon' => 'img/icons/json.png',
|
||||
'urlParams' => array('format' => 'json')
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* An array of tabs to be added to the dropdown area
|
||||
*
|
||||
|
@ -74,7 +46,7 @@ class OutputFormat implements Tabextension
|
|||
*/
|
||||
public function __construct(array $disabled = array())
|
||||
{
|
||||
foreach ($this->supportedTypes as $type => $tabConfig) {
|
||||
foreach ($this->getSupportedTypes() as $type => $tabConfig) {
|
||||
if (!in_array($type, $disabled)) {
|
||||
$tabConfig['url'] = Url::fromRequest();
|
||||
$tabConfig['tagParams'] = array(
|
||||
|
@ -98,4 +70,44 @@ class OutputFormat implements Tabextension
|
|||
$tabs->addAsDropdown($tab->getName(), $tab);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array containing the tab definitions for all supported types
|
||||
*
|
||||
* Using array_keys on this array or isset allows to check whether a
|
||||
* requested type is supported
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportedTypes()
|
||||
{
|
||||
$supportedTypes = array();
|
||||
|
||||
if (Platform::extensionLoaded('gd')) {
|
||||
$supportedTypes[self::TYPE_PDF] = array(
|
||||
'name' => 'pdf',
|
||||
'title' => 'PDF',
|
||||
'icon' => 'file-pdf',
|
||||
'urlParams' => array('format' => 'pdf'),
|
||||
);
|
||||
}
|
||||
|
||||
$supportedTypes[self::TYPE_CSV] = array(
|
||||
'name' => 'csv',
|
||||
'title' => 'CSV',
|
||||
'icon' => 'file-excel',
|
||||
'urlParams' => array('format' => 'csv')
|
||||
);
|
||||
|
||||
if (Platform::extensionLoaded('json')) {
|
||||
$supportedTypes[self::TYPE_JSON] = array(
|
||||
'name' => 'json',
|
||||
'title' => 'JSON',
|
||||
'icon' => 'img/icons/json.png',
|
||||
'urlParams' => array('format' => 'json')
|
||||
);
|
||||
}
|
||||
|
||||
return $supportedTypes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,8 +72,10 @@ class Monitoring_HostsController extends Controller
|
|||
'host_obsessing'*/
|
||||
));
|
||||
$unhandledObjects = array();
|
||||
$unhandledFilterExpressions = array();
|
||||
$acknowledgedObjects = array();
|
||||
$objectsInDowntime = array();
|
||||
$downtimeFilterExpressions = array();
|
||||
$hostStates = array(
|
||||
Host::getStateText(Host::STATE_UP) => 0,
|
||||
Host::getStateText(Host::STATE_DOWN) => 0,
|
||||
|
@ -81,15 +83,17 @@ class Monitoring_HostsController extends Controller
|
|||
Host::getStateText(Host::STATE_PENDING) => 0,
|
||||
);
|
||||
foreach ($this->hostList as $host) {
|
||||
/** @var Service $host */
|
||||
/** @var Host $host */
|
||||
if ((bool) $host->problem === true && (bool) $host->handled === false) {
|
||||
$unhandledObjects[] = $host;
|
||||
$unhandledFilterExpressions[] = Filter::where('host', $host->getName());
|
||||
}
|
||||
if ((bool) $host->acknowledged === true) {
|
||||
$acknowledgedObjects[] = $host;
|
||||
}
|
||||
if ((bool) $host->in_downtime === true) {
|
||||
$objectsInDowntime[] = $host;
|
||||
$downtimeFilterExpressions[] = Filter::where('downtime_host', $host->getName());
|
||||
}
|
||||
++$hostStates[$host::getStateText($host->state)];
|
||||
}
|
||||
|
@ -108,16 +112,15 @@ class Monitoring_HostsController extends Controller
|
|||
$this->view->hostStates = $hostStates;
|
||||
$this->view->objects = $this->hostList;
|
||||
$this->view->unhandledObjects = $unhandledObjects;
|
||||
$this->view->acknowledgeUnhandledLink = Url::fromRequest()
|
||||
->setPath('monitoring/hosts/acknowledge-problem')
|
||||
->addParams(array('host_problem' => 1, 'host_handled' => 0));
|
||||
$this->view->downtimeUnhandledLink = Url::fromRequest()
|
||||
->setPath('monitoring/hosts/schedule-downtime')
|
||||
->addParams(array('host_problem' => 1, 'host_handled' => 0));
|
||||
$unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString();
|
||||
$this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/hosts/acknowledge-problem')
|
||||
->setQueryString($unhandledFilterQueryString);
|
||||
$this->view->downtimeUnhandledLink = Url::fromPath('monitoring/hosts/schedule-downtime')
|
||||
->setQueryString($unhandledFilterQueryString);
|
||||
$this->view->acknowledgedObjects = $acknowledgedObjects;
|
||||
$this->view->objectsInDowntime = $objectsInDowntime;
|
||||
$this->view->inDowntimeLink = Url::fromRequest()
|
||||
->setPath('monitoring/list/downtimes');
|
||||
$this->view->inDowntimeLink = Url::fromPath('monitoring/list/downtimes')
|
||||
->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString());
|
||||
$this->view->havingCommentsLink = Url::fromRequest()
|
||||
->setPath('monitoring/list/comments');
|
||||
$this->view->hostStatesPieChart = $this->createPieChart(
|
||||
|
@ -131,9 +134,6 @@ class Monitoring_HostsController extends Controller
|
|||
{
|
||||
$chart = new InlinePie(array_values($states), $title, $colors);
|
||||
return $chart
|
||||
->setLabel(array_map('strtoupper', array_keys($states)))
|
||||
->setHeight(100)
|
||||
->setWidth(100)
|
||||
->setTitle($title);
|
||||
}
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ class Monitoring_MultiController extends Controller
|
|||
private function createPie($states, $colors, $title)
|
||||
{
|
||||
$chart = new InlinePie(array_values($states), $title, $colors);
|
||||
$chart->setLabel(array_keys($states))->setHeight(100)->setWidth(100);
|
||||
$chart->setLabel(array_keys($states))->setSize(100);
|
||||
$chart->setTitle($title);
|
||||
return $chart;
|
||||
}
|
||||
|
|
|
@ -74,8 +74,10 @@ class Monitoring_ServicesController extends Controller
|
|||
'service_obsessing'*/
|
||||
));
|
||||
$unhandledObjects = array();
|
||||
$unhandledFilterExpressions = array();
|
||||
$acknowledgedObjects = array();
|
||||
$objectsInDowntime = array();
|
||||
$downtimeFilterExpressions = array();
|
||||
$serviceStates = array(
|
||||
Service::getStateText(Service::STATE_OK) => 0,
|
||||
Service::getStateText(Service::STATE_WARNING) => 0,
|
||||
|
@ -94,12 +96,20 @@ class Monitoring_ServicesController extends Controller
|
|||
/** @var Service $service */
|
||||
if ((bool) $service->problem === true && (bool) $service->handled === false) {
|
||||
$unhandledObjects[] = $service;
|
||||
$unhandledFilterExpressions[] = Filter::matchAll(
|
||||
Filter::where('host', $service->getHost()->getName()),
|
||||
Filter::where('service', $service->getName())
|
||||
);
|
||||
}
|
||||
if ((bool) $service->acknowledged === true) {
|
||||
$acknowledgedObjects[] = $service;
|
||||
}
|
||||
if ((bool) $service->in_downtime === true) {
|
||||
$objectsInDowntime[] = $service;
|
||||
$downtimeFilterExpressions[] = Filter::matchAll(
|
||||
Filter::where('downtime_host', $service->getHost()->getName()),
|
||||
Filter::where('downtime_service', $service->getName())
|
||||
);
|
||||
}
|
||||
++$serviceStates[$service::getStateText($service->state)];
|
||||
if (! isset($knownHostStates[$service->getHost()->getName()])) {
|
||||
|
@ -125,16 +135,15 @@ class Monitoring_ServicesController extends Controller
|
|||
$this->view->serviceStates = $serviceStates;
|
||||
$this->view->objects = $this->serviceList;
|
||||
$this->view->unhandledObjects = $unhandledObjects;
|
||||
$this->view->acknowledgeUnhandledLink = Url::fromRequest()
|
||||
->setPath('monitoring/services/acknowledge-problem')
|
||||
->addParams(array('service_problem' => 1, 'service_handled' => 0));
|
||||
$this->view->downtimeUnhandledLink = Url::fromRequest()
|
||||
->setPath('monitoring/services/schedule-downtime')
|
||||
->addParams(array('service_problem' => 1, 'service_handled' => 0));
|
||||
$unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString();
|
||||
$this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/services/acknowledge-problem')
|
||||
->setQueryString($unhandledFilterQueryString);
|
||||
$this->view->downtimeUnhandledLink = Url::fromPath('monitoring/services/schedule-downtime')
|
||||
->setQueryString($unhandledFilterQueryString);
|
||||
$this->view->acknowledgedObjects = $acknowledgedObjects;
|
||||
$this->view->objectsInDowntime = $objectsInDowntime;
|
||||
$this->view->inDowntimeLink = Url::fromRequest()
|
||||
->setPath('monitoring/list/downtimes');
|
||||
$this->view->inDowntimeLink = Url::fromPath('monitoring/list/downtimes')
|
||||
->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString());
|
||||
$this->view->havingCommentsLink = Url::fromRequest()
|
||||
->setPath('monitoring/list/comments');
|
||||
$this->view->serviceStatesPieChart = $this->createPieChart(
|
||||
|
@ -153,10 +162,10 @@ class Monitoring_ServicesController extends Controller
|
|||
{
|
||||
$chart = new InlinePie(array_values($states), $title, $colors);
|
||||
return $chart
|
||||
->setLabel(array_map('strtoupper', array_keys($states)))
|
||||
->setHeight(100)
|
||||
->setWidth(100)
|
||||
->setTitle($title);
|
||||
// ->setLabel(array_map('strtoupper', array_keys($states)))
|
||||
->setSize(50)
|
||||
->setTitle($title)
|
||||
->setSparklineClass('sparkline-multi');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -104,7 +104,7 @@ class AcknowledgeProblemCommandForm extends ObjectsCommandForm
|
|||
array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -130,7 +130,7 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
|
|||
array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -169,7 +169,7 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
|
|||
),
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group')),
|
||||
array('HtmlTag', array('tag' => 'div')),
|
||||
array(
|
||||
'Description',
|
||||
array('tag' => 'span', 'class' => 'description', 'placement' => 'prepend')
|
||||
|
|
|
@ -9,33 +9,36 @@ use Icinga\Module\Monitoring\Plugin\PerfdataSet;
|
|||
|
||||
class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
|
||||
{
|
||||
public function perfdata($perfdataStr, $compact = false)
|
||||
|
||||
/**
|
||||
* Display the given perfdata string to the user
|
||||
*
|
||||
* @param $perfdataStr The perfdata string
|
||||
* @param bool $compact Whether to display the perfdata in compact mode
|
||||
* @param $color The color indicating the perfdata state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function perfdata($perfdataStr, $compact = false, $color = Perfdata::PERFDATA_DEFAULT)
|
||||
{
|
||||
$pset = PerfdataSet::fromString($perfdataStr)->asArray();
|
||||
$onlyPieChartData = array_filter($pset, function ($e) { return $e->getPercentage() > 0; });
|
||||
if ($compact) {
|
||||
$onlyPieChartData = array_slice($onlyPieChartData, 0, 5);
|
||||
} else {
|
||||
$nonPieChartData = array_filter($pset, function ($e) { return $e->getPercentage() == 0; });
|
||||
}
|
||||
$pieChartData = PerfdataSet::fromString($perfdataStr)->asArray();
|
||||
|
||||
$result = '';
|
||||
$table = array();
|
||||
foreach ($onlyPieChartData as $perfdata) {
|
||||
$pieChart = $this->createInlinePie($perfdata);
|
||||
if ($compact) {
|
||||
$result .= $pieChart->render();
|
||||
} else {
|
||||
if (! $perfdata->isPercentage()) {
|
||||
// TODO: Should we trust sprintf-style placeholders in perfdata titles?
|
||||
$pieChart->setTooltipFormat('{{label}}: {{formatted}} ({{percent}}%)');
|
||||
foreach ($pieChartData as $perfdata) {
|
||||
if ($perfdata->isVisualizable()) {
|
||||
$pieChart = $perfdata->asInlinePie($color);
|
||||
if ($compact) {
|
||||
$result .= $pieChart->render();
|
||||
} else {
|
||||
$table[] = '<tr><th>' . $pieChart->render()
|
||||
. htmlspecialchars($perfdata->getLabel())
|
||||
. '</th><td> '
|
||||
. htmlspecialchars($this->formatPerfdataValue($perfdata)) .
|
||||
' </td></tr>';
|
||||
}
|
||||
// $pieChart->setStyle('margin: 0.2em 0.5em 0.2em 0.5em;');
|
||||
$table[] = '<tr><th>' . $pieChart->render()
|
||||
. htmlspecialchars($perfdata->getLabel())
|
||||
. '</th><td> '
|
||||
. htmlspecialchars($this->formatPerfdataValue($perfdata)) .
|
||||
' </td></tr>';
|
||||
} else {
|
||||
$table[] = (string)$perfdata;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,32 +46,10 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
|
|||
return $result;
|
||||
} else {
|
||||
$pieCharts = empty($table) ? '' : '<table class="perfdata">' . implode("\n", $table) . '</table>';
|
||||
return $pieCharts . "\n" . implode("<br>\n", $nonPieChartData);
|
||||
return $pieCharts;
|
||||
}
|
||||
}
|
||||
|
||||
protected function calculatePieChartData(Perfdata $perfdata)
|
||||
{
|
||||
$rawValue = $perfdata->getValue();
|
||||
$minValue = $perfdata->getMinimumValue() !== null ? $perfdata->getMinimumValue() : 0;
|
||||
$maxValue = $perfdata->getMaximumValue();
|
||||
$usedValue = ($rawValue - $minValue);
|
||||
$unusedValue = ($maxValue - $minValue) - $usedValue;
|
||||
|
||||
$gray = $unusedValue;
|
||||
$green = $orange = $red = 0;
|
||||
// TODO(#6122): Add proper treshold parsing.
|
||||
if ($perfdata->getCriticalThreshold() && $perfdata->getValue() > $perfdata->getCriticalThreshold()) {
|
||||
$red = $usedValue;
|
||||
} elseif ($perfdata->getWarningThreshold() && $perfdata->getValue() > $perfdata->getWarningThreshold()) {
|
||||
$orange = $usedValue;
|
||||
} else {
|
||||
$green = $usedValue;
|
||||
}
|
||||
|
||||
return array($green, $orange, $red, $gray);
|
||||
}
|
||||
|
||||
protected function formatPerfdataValue(Perfdata $perfdata)
|
||||
{
|
||||
if ($perfdata->isBytes()) {
|
||||
|
@ -82,24 +63,4 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
|
|||
return $perfdata->getValue();
|
||||
}
|
||||
|
||||
protected function createInlinePie(Perfdata $perfdata)
|
||||
{
|
||||
$pieChart = new InlinePie($this->calculatePieChartData($perfdata), $perfdata->getLabel());
|
||||
$pieChart->setLabel(htmlspecialchars($perfdata->getLabel()));
|
||||
$pieChart->setHideEmptyLabel();
|
||||
|
||||
//$pieChart->setHeight(32)->setWidth(32);
|
||||
if ($perfdata->isBytes()) {
|
||||
$pieChart->setTooltipFormat('{{label}}: {{formatted}} ({{percent}}%)');
|
||||
$pieChart->setNumberFormat(InlinePie::NUMBER_FORMAT_BYTES);
|
||||
} else if ($perfdata->isSeconds()) {
|
||||
$pieChart->setTooltipFormat('{{label}}: {{formatted}} ({{percent}}%)');
|
||||
$pieChart->setNumberFormat(InlinePie::NUMBER_FORMAT_TIME);
|
||||
} else {
|
||||
$pieChart->setTooltipFormat('{{label}}: {{formatted}}%');
|
||||
$pieChart->setNumberFormat(InlinePie::NUMBER_FORMAT_RATIO);
|
||||
$pieChart->setHideEmptyLabel();
|
||||
}
|
||||
return $pieChart;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||
</td>
|
||||
<td>
|
||||
<?php if (isset($downtime->service)): ?>
|
||||
<a href="<?= $this->href('monitoring/service/show', array(
|
||||
<?= $this->icon('service'); ?> <a href="<?= $this->href('monitoring/service/show', array(
|
||||
'host' => $downtime->host,
|
||||
'service' => $downtime->service
|
||||
)); ?>">
|
||||
|
@ -63,7 +63,7 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||
<?= $this->translate('on'); ?> <?= $downtime->host; ?>
|
||||
</small>
|
||||
<?php else: ?>
|
||||
<a href="<?= $this->href('monitoring/host/show', array(
|
||||
<?= $this->icon('host'); ?> <a href="<?= $this->href('monitoring/host/show', array(
|
||||
'host' => $downtime->host
|
||||
)); ?>">
|
||||
<?= $downtime->host; ?>
|
||||
|
@ -76,7 +76,9 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||
<?php if ($downtime->is_flexible): ?>
|
||||
<?php if ($downtime->is_in_effect): ?>
|
||||
<?= sprintf(
|
||||
$this->translate('This flexible downtime was started on %s at %s and lasts for %s until %s at %s.'),
|
||||
isset($downtime->service)
|
||||
? $this->translate('This flexible service downtime was started on %s at %s and lasts for %s until %s at %s.')
|
||||
: $this->translate('This flexible host downtime was started on %s at %s and lasts for %s until %s at %s.'),
|
||||
date('d.m.y', $downtime->start),
|
||||
date('H:i', $downtime->start),
|
||||
$this->format()->duration($downtime->duration),
|
||||
|
@ -85,7 +87,9 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||
); ?>
|
||||
<?php else: ?>
|
||||
<?= sprintf(
|
||||
$this->translate('This flexible downtime has been scheduled to start between %s - %s and to last for %s.'),
|
||||
isset($downtime->service)
|
||||
? $this->translate('This flexible service downtime has been scheduled to start between %s - %s and to last for %s.')
|
||||
: $this->translate('This flexible host downtime has been scheduled to start between %s - %s and to last for %s.'),
|
||||
date('d.m.y H:i', $downtime->scheduled_start),
|
||||
date('d.m.y H:i', $downtime->scheduled_end),
|
||||
$this->format()->duration($downtime->duration)
|
||||
|
@ -94,7 +98,9 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||
<?php else: ?>
|
||||
<?php if ($downtime->is_in_effect): ?>
|
||||
<?= sprintf(
|
||||
$this->translate('This fixed downtime was started on %s at %s and expires on %s at %s.'),
|
||||
isset($downtime->service)
|
||||
? $this->translate('This fixed service downtime was started on %s at %s and expires on %s at %s.')
|
||||
: $this->translate('This fixed host downtime was started on %s at %s and expires on %s at %s.'),
|
||||
date('d.m.y', $downtime->start),
|
||||
date('H:i', $downtime->start),
|
||||
date('d.m.y', $downtime->end),
|
||||
|
@ -102,7 +108,9 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||
); ?>
|
||||
<?php else: ?>
|
||||
<?= sprintf(
|
||||
$this->translate('This fixed downtime has been scheduled to start on %s at %s and to end on %s at %s.'),
|
||||
isset($downtime->service)
|
||||
? $this->translate('This fixed service downtime has been scheduled to start on %s at %s and to end on %s at %s.')
|
||||
: $this->translate('This fixed host downtime has been scheduled to start on %s at %s and to end on %s at %s.'),
|
||||
date('d.m.y', $downtime->scheduled_start),
|
||||
date('H:i', $downtime->scheduled_start),
|
||||
date('d.m.y', $downtime->scheduled_end),
|
||||
|
|
|
@ -108,10 +108,9 @@ if ($hosts->count() === 0) {
|
|||
$host->host_unhandled_services),
|
||||
'monitoring/show/services',
|
||||
array(
|
||||
'host' => $host->host_name,
|
||||
'service_problem' => 1,
|
||||
'service_acknowledged' => 0,
|
||||
'service_in_downtime' => 0
|
||||
'host' => $host->host_name,
|
||||
'service_problem' => 1,
|
||||
'service_handled' => 0
|
||||
),
|
||||
array('style' => 'font-weight: normal')
|
||||
) ?>)</span>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
use Icinga\Module\Monitoring\Object\Host;
|
||||
use Icinga\Module\Monitoring\Object\Service;
|
||||
use Icinga\Module\Monitoring\Plugin\Perfdata;
|
||||
|
||||
$helper = $this->getHelper('MonitoringState');
|
||||
|
||||
|
|
|
@ -518,12 +518,14 @@ class StatusQuery extends IdoQuery
|
|||
protected function joinServiceproblemsummary()
|
||||
{
|
||||
$sub = new Zend_Db_Expr('(SELECT'
|
||||
. ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth) > 0 THEN 0 ELSE 1 END) AS unhandled_services_count,'
|
||||
. ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth) > 0 THEN 1 ELSE 0 END) AS handled_services_count,'
|
||||
. ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 0 ELSE 1 END) AS unhandled_services_count,'
|
||||
. ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END) AS handled_services_count,'
|
||||
. ' s.host_object_id FROM icinga_servicestatus ss'
|
||||
. ' JOIN icinga_services s'
|
||||
. ' ON s.service_object_id = ss.service_object_id'
|
||||
. ' AND ss.current_state > 0'
|
||||
. ' JOIN icinga_hoststatus hs'
|
||||
. ' ON hs.host_object_id = s.host_object_id'
|
||||
. ' GROUP BY s.host_object_id)');
|
||||
$this->select->joinLeft(
|
||||
array('sps' => $sub),
|
||||
|
|
|
@ -30,7 +30,7 @@ class IcingaCommandFileCommandRenderer implements IcingaCommandRendererInterface
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function escape($commandString)
|
||||
protected function escape($commandString)
|
||||
{
|
||||
return str_replace(array("\r", "\n"), array('\r', '\n'), $commandString);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class IcingaCommandFileCommandRenderer implements IcingaCommandRendererInterface
|
|||
if ($now === null) {
|
||||
$now = time();
|
||||
}
|
||||
return sprintf('[%u] %s', $now, $this->$renderMethod($command));
|
||||
return sprintf('[%u] %s', $now, $this->escape($this->$renderMethod($command)));
|
||||
}
|
||||
|
||||
public function renderAddComment(AddCommentCommand $command)
|
||||
|
|
|
@ -5,9 +5,15 @@
|
|||
namespace Icinga\Module\Monitoring\Plugin;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Web\Widget\Chart\InlinePie;
|
||||
use Zend_Controller_Front;
|
||||
|
||||
class Perfdata
|
||||
{
|
||||
const PERFDATA_DEFAULT = 'green';
|
||||
const PERFDATA_RED = 'red';
|
||||
|
||||
/**
|
||||
* The performance data value being parsed
|
||||
*
|
||||
|
@ -159,6 +165,16 @@ class Perfdata
|
|||
return $this->unit === 'c';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether it is possible to display a visual representation
|
||||
*
|
||||
* @return bool True when the perfdata is visualizable
|
||||
*/
|
||||
public function isVisualizable()
|
||||
{
|
||||
return isset($this->minValue) && isset($this->maxValue) && isset($this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this perfomance data's label
|
||||
*/
|
||||
|
@ -316,4 +332,50 @@ class Perfdata
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function calculatePieChartData( $color)
|
||||
{
|
||||
$rawValue = $this->getValue();
|
||||
$minValue = $this->getMinimumValue() !== null ? $this->getMinimumValue() : 0;
|
||||
$maxValue = $this->getMaximumValue();
|
||||
$usedValue = ($rawValue - $minValue);
|
||||
$unusedValue = ($maxValue - $minValue) - $usedValue;
|
||||
|
||||
$gray = $unusedValue;
|
||||
$green = $orange = $red = 0;
|
||||
|
||||
switch ($color) {
|
||||
case self::PERFDATA_DEFAULT:
|
||||
$green = $usedValue;
|
||||
break;
|
||||
|
||||
case self::PERFDATA_RED:
|
||||
$red = $usedValue;
|
||||
break;
|
||||
|
||||
case self::PERFDATA_ORANGE:
|
||||
$orange = $usedValue;
|
||||
break;
|
||||
}
|
||||
// TODO(#6122): Add proper treshold parsing.
|
||||
|
||||
return array($green, $orange, $red, $gray);
|
||||
}
|
||||
|
||||
|
||||
public function asInlinePie($color)
|
||||
{
|
||||
if (! $this->isVisualizable()) {
|
||||
throw new ProgrammingError('Cannot calculate piechart data for unvisualizable perfdata entry.');
|
||||
}
|
||||
|
||||
$data = $this->calculatePieChartData($color);
|
||||
$pieChart = new InlinePie($data, $this->getLabel() . ' ' . number_format($this->getPercentage(), 2) . '%');
|
||||
$pieChart->setSparklineClass('sparkline-perfdata');
|
||||
|
||||
if (Zend_Controller_Front::getInstance()->getRequest()->isXmlHttpRequest()) {
|
||||
$pieChart->disableNoScript();
|
||||
}
|
||||
return $pieChart;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Tests\Icinga\Regression;
|
||||
|
||||
use Icinga\Test\BaseTestCase;
|
||||
use Icinga\Module\Monitoring\Command\IcingaCommand;
|
||||
use Icinga\Module\Monitoring\Command\Renderer\IcingaCommandFileCommandRenderer;
|
||||
|
||||
|
||||
/**
|
||||
* A command that has a hardcoded parameter with newlines
|
||||
*/
|
||||
class Bug6088Command extends IcingaCommand
|
||||
{
|
||||
public function getParameterWithCarriageReturnAndLineFeed()
|
||||
{
|
||||
return "foo\r\nbar";
|
||||
}
|
||||
|
||||
public function getBug()
|
||||
{
|
||||
return '6088';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A subclass of IcingaCommandFileCommandRenderer to utiliseIcingaCommandFileCommandRenderer
|
||||
* to render an instance of Bug6088Command
|
||||
*/
|
||||
class Bug6088CommandFileCommandRenderer extends IcingaCommandFileCommandRenderer
|
||||
{
|
||||
public function renderBug6088(Bug6088Command $command)
|
||||
{
|
||||
return 'SOLVE_BUG;' . $command->getBug() . ';' . $command->getParameterWithCarriageReturnAndLineFeed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class Bug6088
|
||||
*
|
||||
* Multi-line comments don't work
|
||||
*
|
||||
* @see https://dev.icinga.org/issues/6088
|
||||
*/
|
||||
class Bug6088Test extends BaseTestCase
|
||||
{
|
||||
public function testWhetherCommandParametersWithMultipleLinesAreProperlyEscaped()
|
||||
{
|
||||
$command = new Bug6088Command();
|
||||
$renderer = new Bug6088CommandFileCommandRenderer();
|
||||
$commandString = $renderer->render($command);
|
||||
|
||||
$this->assertEquals(
|
||||
'SOLVE_BUG;6088;foo\r\nbar',
|
||||
substr($commandString, strpos($commandString, ' ') + 1),
|
||||
'Command parameters with multiple lines are not properly escaped'
|
||||
);
|
||||
}
|
||||
}
|
|
@ -51,9 +51,7 @@ $cliPath = realpath(Icinga::app()->getApplicationDir() . '/../bin/icingacli');
|
|||
</div>
|
||||
<p><?= mt('setup', 'In case the IcingaCLI is missing you can create the token manually:'); ?></p>
|
||||
<div class="code">
|
||||
<span>su <?= ($user = Platform::getPhpUser()) !== null ? $user : 'your_webserver_group'; ?> && mkdir -m 2770 <?= dirname($setupTokenPath); ?>;</span>
|
||||
<span>head -c 12 /dev/urandom | base64 | tee <?= $setupTokenPath; ?>;</span>
|
||||
<span>chmod 0660 <?= $setupTokenPath; ?>;</span>
|
||||
<span>su <?= ($user = Platform::getPhpUser()) !== null ? $user : 'your_webserver_user'; ?> -c "mkdir -m 2770 <?= dirname($setupTokenPath); ?>; head -c 12 /dev/urandom | base64 | tee <?= $setupTokenPath; ?>; chmod 0660 <?= $setupTokenPath; ?>;";</span>
|
||||
</div>
|
||||
<p><?= sprintf(
|
||||
mt('setup', 'Please see the %s for an extensive description on how to access and use this wizard.'),
|
||||
|
|
|
@ -461,8 +461,8 @@ class WebWizard extends Wizard implements SetupWizard
|
|||
mt('setup', 'PHP Module: GD'),
|
||||
mt(
|
||||
'setup',
|
||||
'In case you want icons being exported to PDF as'
|
||||
. ' well, you\'ll need the GD extension for PHP.'
|
||||
'In case you want views being exported to PDF,'
|
||||
. ' you\'ll need the GD extension for PHP.'
|
||||
),
|
||||
Platform::extensionLoaded('gd'),
|
||||
Platform::extensionLoaded('gd') ? mt('setup', 'The PHP module GD is available') : (
|
||||
|
|
|
@ -285,3 +285,10 @@ li li .badge {
|
|||
.widgetFilter li.active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.sparkline {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
}
|
|
@ -18,34 +18,33 @@
|
|||
|
||||
$('span.sparkline', el).each(function(i, element) {
|
||||
// read custom options
|
||||
var $spark = $(element);
|
||||
var labels = $spark.attr('labels').split('|');
|
||||
var formatted = $spark.attr('formatted').split('|');
|
||||
var tooltipChartTitle = $spark.attr('sparkTooltipChartTitle') || '';
|
||||
var format = $spark.attr('tooltipformat');
|
||||
var hideEmpty = $spark.attr('hideEmptyLabel') === 'true';
|
||||
$spark.sparkline(
|
||||
'html',
|
||||
{
|
||||
var $spark = $(element);
|
||||
var title = $spark.attr('title');
|
||||
|
||||
if ($spark.attr('labels')) {
|
||||
$spark.removeAttr('original-title');
|
||||
}
|
||||
|
||||
var options;
|
||||
if ($spark.hasClass('sparkline-perfdata')) {
|
||||
options = {
|
||||
enableTagOptions: true,
|
||||
tooltipFormatter: function (sparkline, options, fields) {
|
||||
var out = format;
|
||||
if (hideEmpty && fields.offset === 3) {
|
||||
return '';
|
||||
}
|
||||
var replace = {
|
||||
title: tooltipChartTitle,
|
||||
label: labels[fields.offset] ? labels[fields.offset] : fields.offset,
|
||||
formatted: formatted[fields.offset] ? formatted[fields.offset] : '',
|
||||
value: fields.value,
|
||||
percent: Math.round(fields.percent * 100) / 100
|
||||
};
|
||||
$.each(replace, function(key, value) {
|
||||
out = out.replace('{{' + key + '}}', value);
|
||||
});
|
||||
return out;
|
||||
}
|
||||
});
|
||||
width: 12,
|
||||
height: 12,
|
||||
title: title,
|
||||
disableTooltips: true
|
||||
};
|
||||
$spark.sparkline('html', options);
|
||||
} else if ($spark.hasClass('sparkline-multi')) {
|
||||
options = {
|
||||
width: 100,
|
||||
height: 100,
|
||||
title: title,
|
||||
enableTagOptions: true
|
||||
};
|
||||
$spark.sparkline('html', options);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue