diff options
author | Alexander Shubin <aleksandrs.subins@zabbix.com> | 2022-11-04 19:49:18 +0300 |
---|---|---|
committer | Andrejs Verza <andrejs.verza@zabbix.com> | 2022-11-04 19:49:18 +0300 |
commit | 2181d67326038b8a3ef2f420fa26579f13046278 (patch) | |
tree | a3879879bc80ff262345771b2487bda8061c397e | |
parent | 013f74ffb5d098cde3f86e6baba2a135c517373a (diff) | |
parent | 953c2171dcb59a87e1c854c6ae1a855bd3073d57 (diff) |
..F....... [ZBXNEXT-7469] simplified creation of dashboard widgets; moved widgets to modules; updated modules framework
Merge in ZBX/zabbix from feature/ZBXNEXT-7469-6.3 to master
* commit '953c2171dcb59a87e1c854c6ae1a855bd3073d57': (152 commits)
..F....... [ZBXNEXT-7469] implemented dashboard configuration monitoring #4
..F....... [ZBXNEXT-7469] implemented dashboard configuration monitoring #3
..F....... [ZBXNEXT-7469] implemented dashboard configuration monitoring #2
..F....... [ZBXNEXT-7469] implemented dashboard configuration monitoring
..F....... [ZBXNEXT-7469] added phpdocs to Widget form view
..F....... [ZBXNEXT-7469] fixed page loading errors #4
..F....... [ZBXNEXT-7469] fixed page loading errors #3
..F....... [ZBXNEXT-7469] fixed page loading errors #2
..F....... [ZBXNEXT-7469] fixed page loading errors
..F....... [ZBXNEXT-7469] fixed inaccessible widget
..F....... [ZBXNEXT-7469] fixed console errors when no widget modules are available
..F....... [ZBXNEXT-7469] fixed widget placeholder freeze when no modules are enabled
.......... [ZBXNEXT-7469] updated widget type remembering test after intentional change of behavior
..F....... [ZBXNEXT-7469] fixed style of inaccessible widgets
..F....... [ZBXNEXT-7469] fixed saving new dashboards
..F....... [ZBXNEXT-7469] fixed saving templated dashboards
..F....... [ZBXNEXT-7469] fixed saving the last used type of added widgets
..F....... [ZBXNEXT-7469] fixed copying and pasting inaccessible widgets
..F....... [ZBXNEXT-7469] fixed addition of widgets when no widgets available
..F....... [ZBXNEXT-7469] fixed static header of inaccessible widgets
...
540 files changed, 16583 insertions, 15873 deletions
diff --git a/ChangeLog.d/feature/ZBXNEXT-7469 b/ChangeLog.d/feature/ZBXNEXT-7469 new file mode 100755 index 00000000000..5cf2410476c --- /dev/null +++ b/ChangeLog.d/feature/ZBXNEXT-7469 @@ -0,0 +1 @@ +..F....... [ZBXNEXT-7469] simplified creation of dashboard widgets; moved widgets to modules; updated modules framework (ashubin, averza) diff --git a/create/src/data.tmpl b/create/src/data.tmpl index 28ae0e9ed47..4e132af5593 100644 --- a/create/src/data.tmpl +++ b/create/src/data.tmpl @@ -1002,3 +1002,29 @@ ROW |25 |4 |0 |modules.default_access|1 | |NULL ROW |26 |4 |0 |api.access |0 | |NULL |NULL | ROW |27 |4 |0 |actions.default_access|0 | |NULL |NULL | +TABLE |module +FIELDS|moduleid|id |relative_path |status|config| +ROW |1 |actionlog |widgets/actionlog |1 |[] | +ROW |2 |clock |widgets/clock |1 |[] | +ROW |3 |dataover |widgets/dataover |1 |[] | +ROW |4 |discovery |widgets/discovery |1 |[] | +ROW |5 |favgraphs |widgets/favgraphs |1 |[] | +ROW |6 |favmaps |widgets/favmaps |1 |[] | +ROW |7 |geomap |widgets/geomap |1 |[] | +ROW |8 |graph |widgets/graph |1 |[] | +ROW |9 |graphprototype |widgets/graphprototype|1 |[] | +ROW |10 |hostavail |widgets/hostavail |1 |[] | +ROW |11 |item |widgets/item |1 |[] | +ROW |12 |map |widgets/map |1 |[] | +ROW |13 |navtree |widgets/navtree |1 |[] | +ROW |14 |plaintext |widgets/plaintext |1 |[] | +ROW |15 |problemhosts |widgets/problemhosts |1 |[] | +ROW |16 |problems |widgets/problems |1 |[] | +ROW |17 |problemsbysv |widgets/problemsbysv |1 |[] | +ROW |18 |slareport |widgets/slareport |1 |[] | +ROW |19 |svggraph |widgets/svggraph |1 |[] | +ROW |20 |systeminfo |widgets/systeminfo |1 |[] | +ROW |21 |tophosts |widgets/tophosts |1 |[] | +ROW |22 |trigover |widgets/trigover |1 |[] | +ROW |23 |url |widgets/url |1 |[] | +ROW |24 |web |widgets/web |1 |[] | diff --git a/create/src/schema.tmpl b/create/src/schema.tmpl index 3151cedbaca..24a1eefee6f 100644 --- a/create/src/schema.tmpl +++ b/create/src/schema.tmpl @@ -1683,7 +1683,7 @@ FIELD |tls_psk_identity|t_varchar(128)|'' |NOT NULL |ZBX_PROXY FIELD |tls_psk |t_varchar(512) |'' |NOT NULL |ZBX_PROXY UNIQUE |1 |tls_psk_identity -TABLE|module|moduleid| +TABLE|module|moduleid|ZBX_DATA FIELD |moduleid |t_id | |NOT NULL |0 FIELD |id |t_varchar(255) |'' |NOT NULL |0 FIELD |relative_path |t_varchar(255) |'' |NOT NULL |0 @@ -1987,4 +1987,4 @@ TABLE|dbversion|dbversionid| FIELD |dbversionid |t_id | |NOT NULL |0 FIELD |mandatory |t_integer |'0' |NOT NULL | FIELD |optional |t_integer |'0' |NOT NULL | -ROW |1 |6030061 |6030061 +ROW |1 |6030063 |6030063 diff --git a/sass/stylesheets/sass/components/_columns-wrapper.scss b/sass/stylesheets/sass/components/_columns-wrapper.scss new file mode 100644 index 00000000000..3f10c77bf29 --- /dev/null +++ b/sass/stylesheets/sass/components/_columns-wrapper.scss @@ -0,0 +1,79 @@ +.columns-wrapper { + $column-count: (2, 3); + $column-size: ( + 5: 5%, + 10: 10%, + 15: 15%, + 20: 20%, + 33: 33.33333%, + 35: 35%, + 40: 40%, + 50: 50%, + 75: 75%, + 90: 90%, + 95: 95% + ); + + display: flex; + flex-wrap: wrap; + align-items: start; + + &.columns-nowrap { + flex-wrap: nowrap; + } + + // Dynamically generated classes for the columns count: + // .columns-2 + // .columns-3 + @each $count in $column-count { + &.columns-#{$count} > { + div, + li { + display: block; + flex: 0 0 (100% / $count); + max-width: (100% / $count); + } + } + } + + // Dynamically generated classes for the column width: + // .column-5 + // .column-10 + // .column-15 + // .column-20 + // .column-33 + // .column-35 + // .column-40 + // .column-50 + // .column-75 + // .column-90 + // .column-95 + @each $class, $width in $column-size { + .column-#{$class} { + flex: 0 0 $width; + max-width: $width; + } + } + + .column-center { + display: flex; + justify-content: center; + text-align: center; + } + + .column-middle { + display: flex; + align-items: center; + } + + & > { + div, + ul { + &:not(:last-child) { + section { + margin-right: 10px; + } + } + } + } +} diff --git a/sass/stylesheets/sass/components/_section.scss b/sass/stylesheets/sass/components/_section.scss new file mode 100644 index 00000000000..e0c21a3aaf2 --- /dev/null +++ b/sass/stylesheets/sass/components/_section.scss @@ -0,0 +1,72 @@ +section { + background-color: $ui-bg-color; + border: 1px solid $ui-border-color; + + .section-head { + display: flex; + height: 32px; + line-height: 32px; + + h4 { + padding: 0 10px; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + font-weight: bold; + line-height: inherit; + color: lighten($font-color, 15%); + } + } + + .section-toggle { + @extend %btn-widget-defaults; + + width: 24px; + height: 24px; + margin: 2px 2px 0 auto; + background: url($sprite-path) no-repeat -6px -654px; + } + + .section-foot { + padding: 0 10px; + text-align: right; + line-height: 32px; + color: $font-alt-color; + } + + &.section-collapsed { + .section-body, + .section-foot { + display: none; + } + + .section-toggle { + background-position: -6px -689px; + } + } + + &:not(:last-child) { + margin-bottom: 10px; + } + + .list-table { + border: 0; + + tbody tr:last-child { + td { + border-bottom: 1px solid $table-border-color; + } + } + + td, + th { + &:first-child { + padding-left: 10px; + } + + &:last-child { + padding-right: 10px; + } + } + } +} diff --git a/sass/stylesheets/sass/components/dashboard/_dashboard.scss b/sass/stylesheets/sass/components/dashboard/_dashboard.scss index 726e26674ff..6855839e555 100644 --- a/sass/stylesheets/sass/components/dashboard/_dashboard.scss +++ b/sass/stylesheets/sass/components/dashboard/_dashboard.scss @@ -978,10 +978,6 @@ .msg-warning { margin: 0 10px; } - - &.dashboard-widget-fluid { - margin-right: 0; - } } %dashboard-widget-td { diff --git a/sass/stylesheets/sass/components/dashboard/_widget-clock.scss b/sass/stylesheets/sass/components/dashboard/_widget-clock.scss index 41497454cf9..638de52aaed 100644 --- a/sass/stylesheets/sass/components/dashboard/_widget-clock.scss +++ b/sass/stylesheets/sass/components/dashboard/_widget-clock.scss @@ -1,39 +1,40 @@ // Widget configuration. form.dashboard-widget-clock { - .fields-group-date, - .fields-group-time, - .fields-group-tzone { - display: grid; - grid-template-columns: 60px 120px repeat(2, minmax(60px, max-content) auto); - align-items: center; - column-gap: 10px; - row-gap: 5px; - - label { - text-align: right; - } + .fields-group { + &.fields-group-date, + &.fields-group-time, + &.fields-group-tzone { + display: grid; + grid-template-columns: 60px 120px repeat(2, minmax(60px, max-content) auto); + align-items: center; + column-gap: 10px; + row-gap: 5px; - .field-size { - input { - margin-right: 5px; + label { + text-align: right; } - } - } - .fields-group-time { - .field-format { - grid-column: 4 / -1; + .field-size { + input { + margin-right: 5px; + } + } } - } - .fields-group-tzone { - .field-format { - grid-column: 2 / -1; + &.fields-group-time { + .field-format { + grid-column: 4 / -1; + } } - .field-timezone { - grid-column: 2 / -1; + &.fields-group-tzone { + .form-field { + &.field-tzone-timezone, + &.field-tzone-format { + grid-column: 2 / -1; + } + } } } } @@ -41,7 +42,7 @@ form.dashboard-widget-clock { // Widget view. div.dashboard-widget-clock { - &.clock-digital { + .clock-digital { $line-height: 1.14; box-sizing: border-box; diff --git a/sass/stylesheets/sass/components/dashboard/_widget-inaccessible.scss b/sass/stylesheets/sass/components/dashboard/_widget-inaccessible.scss new file mode 100755 index 00000000000..8349b4eb3c2 --- /dev/null +++ b/sass/stylesheets/sass/components/dashboard/_widget-inaccessible.scss @@ -0,0 +1,8 @@ +.dashboard-widget-inaccessible { + display: grid; + align-items: center; + padding-right: 10px; + padding-left: 10px; + text-align: center; + color: $font-alt-color; +} diff --git a/sass/stylesheets/sass/components/dashboard/_widget-item.scss b/sass/stylesheets/sass/components/dashboard/_widget-item.scss index f3a36d2d73a..3c1c86646d9 100644 --- a/sass/stylesheets/sass/components/dashboard/_widget-item.scss +++ b/sass/stylesheets/sass/components/dashboard/_widget-item.scss @@ -1,71 +1,73 @@ // Widget configuration. form.dashboard-widget-item { - .fields-group-description, - .fields-group-value, - .fields-group-time, - .fields-group-change-indicator { - display: grid; - grid-template-columns: minmax(100px, max-content) 3fr max-content auto; - align-items: center; - column-gap: 10px; - row-gap: 5px; - - label { - text-align: right; - } + .fields-group { + &.fields-group-description, + &.fields-group-value, + &.fields-group-time, + &.fields-group-change-indicator { + display: grid; + grid-template-columns: minmax(100px, max-content) 3fr max-content auto; + align-items: center; + column-gap: 10px; + row-gap: 5px; + + label { + text-align: right; + } - hr { - grid-column: 1 / -1; - margin: 0; - width: 100%; - border: solid $table-border-color; - border-width: 1px 0 0 0; - } + hr { + grid-column: 1 / -1; + margin: 0; + width: 100%; + border: solid $table-border-color; + border-width: 1px 0 0 0; + } - .field-fluid { - grid-column: 2 / -1; - } + .field-fluid { + grid-column: 2 / -1; + } - .offset-3 { - grid-column-start: 3; - } + .offset-3 { + grid-column-start: 3; + } - .field-size { - input { - margin-right: 5px; + .field-size { + input { + margin-right: 5px; + } } - } - .form-field { - line-height: 24px; + .form-field { + line-height: 24px; + } } - } - .fields-group-description { - .form-field:nth-child(1) { - grid-column: 1 / -1; + &.fields-group-description { + .form-field:nth-child(1) { + grid-column: 1 / -1; + } } - } - .fields-group-value { - grid-template-columns: minmax(100px, max-content) 3fr max-content auto; + &.fields-group-value { + grid-template-columns: minmax(100px, max-content) 3fr max-content auto; - .units-show { - display: flex; + .units-show { + display: flex; - label[for='units'] { - width: 100%; + label[for='units'] { + width: 100%; + } } } - } - .fields-group-change-indicator { - grid-template-columns: repeat(3, max-content 96px); - } + &.fields-group-change-indicator { + grid-template-columns: repeat(3, max-content 96px); - .fields-group-change-indicator .input-color-picker { - display: block; + .input-color-picker { + display: block; + } + } } } @@ -74,12 +76,14 @@ form.dashboard-widget-item { div.dashboard-widget-item { $line-height: 1.14; - box-sizing: border-box; - height: 100%; - padding: 10px; - overflow-x: hidden; + > div { + box-sizing: border-box; + height: 100%; + padding: 10px; + overflow-x: hidden; - @extend %webkit-scrollbar; + @extend %webkit-scrollbar; + } a { box-sizing: border-box; diff --git a/sass/stylesheets/sass/components/dashboard/_widget-svggraph.scss b/sass/stylesheets/sass/components/dashboard/_widget-svggraph.scss index e32ad97b80a..671d18331ff 100644 --- a/sass/stylesheets/sass/components/dashboard/_widget-svggraph.scss +++ b/sass/stylesheets/sass/components/dashboard/_widget-svggraph.scss @@ -1,12 +1,30 @@ // Widget configuration. form.dashboard-widget-svggraph { + .svg-graph-preview, .graph-widget-config-tabs { - padding: 10px 0; + grid-column: 1 / -1; + } + + .svg-graph-preview { + position: relative; + min-width: 1110px; + height: 300px; + + > div { + position: absolute; + top: 0; + right: 0; + left: 0; + margin: 0 -10px; + height: 300px; + background: $ui-bg-color; + z-index: 3; + } + } + .graph-widget-config-tabs { > .tabs-nav { - margin-right: 0; - margin-left: 0; border-top: 1px solid $ui-border-color; } @@ -19,6 +37,7 @@ form.dashboard-widget-svggraph { } .table-forms-container { + margin: -10px 0 0 0; border: 1px solid $ui-border-color; border-top: none; } @@ -27,32 +46,30 @@ form.dashboard-widget-svggraph { padding: 0; } - .dataset-head { - display: grid; - grid-template-columns: 24px 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; + .dataset-head, + .dataset-body.list-accordion-item-body { + display: contents; } - .dataset-body.list-accordion-item-body { - display: grid; - grid-template-columns: 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; - position: relative; - margin-top: 10px; + .dataset-head { + .multiselect { + width: 100%; + } + } + .dataset-body { .form-grid { padding-top: 0; &:first-child { - grid-column-start: 2; + grid-column-start: 3; } } } .drag-icon { position: absolute; + top: 5px; left: -14px; } @@ -88,17 +105,15 @@ form.dashboard-widget-svggraph { margin-top: -5px; margin-bottom: -5px; } - - .list-accordion-item-head { - padding: 0; - } } .list-accordion-item { position: relative; - width: 100%; + display: grid; + grid-template-columns: 24px 24px 1fr 1fr 24px; + grid-gap: 10px; + align-items: start; padding: 5px 0; - list-style-type: none; &.list-accordion-item-opened { &::before { @@ -119,10 +134,6 @@ form.dashboard-widget-svggraph { overflow: hidden; } - .dataset-body { - display: none; - } - .dataset-head { .table-forms-separator { border: none; @@ -138,6 +149,10 @@ form.dashboard-widget-svggraph { } } + .dataset-body { + display: none; + } + .items-list { padding-left: 0; } @@ -167,9 +182,129 @@ form.dashboard-widget-svggraph { } } + .overrides-list { + position: relative; + margin: -5px 0 -5px 15px; + } + + .overrides-list-item { + position: relative; + display: grid; + grid-template-columns: 1fr 1fr 24px; + grid-gap: 5px 10px; + align-items: start; + padding: 5px 0; + + &.sortable { + overflow: visible; + margin-top: -5px; + margin-bottom: -5px; + } + + .multiselect { + width: 100%; + } + + .btn-remove { + right: 0; + top: 0; + vertical-align: baseline; + } + } + + .overrides-foot { + padding: 5px 0; + } + + .overrides-options-list { + grid-column: 1 / -1; + padding: 0 24px 8px 0; + border-bottom: 1px solid $table-border-color; + white-space: normal; + + > li { + display: inline-block; + margin-right: 5px; + margin-bottom: 2px; + line-height: 22px; + white-space: nowrap; + + .color-picker { + line-height: 22px; + } + + > div { + position: relative; + padding: 1px 18px 1px 1px; + background-color: $ui-bg-selected-color; + border-radius: 2px; + + > span { + color: lighten($ui-bg-selected-color, 100%); + padding-left: 8px; + line-height: 22px; + } + + > input[type=text] { + border-style: none; + line-height: 22px; + min-height: 22px; + width: 85px; + } + + > .subfilter-disable-btn { + position: absolute; + right: 0; + top: 0; + min-height: 24px; + } + } + } + + .btn-alt { + .plus-icon { + margin-right: 0; + } + } + + .color-picker { + .color-picker-preview { + margin: 1px; + width: 20px; + min-height: 20px; + background-position: -323px -411px; + } + } + } + .no-items-message { display: none; line-height: 24px; color: $font-alt-color; } } + +[theme="hc-dark"] form.dashboard-widget-svggraph { + .overrides-options-list { + > li > div { + border: 1px solid $ui-tab-bg-selected-color; + background-color: transparent !important; + + > .subfilter-disable-btn { + border: none !important; + top: 0; + } + } + } +} + +[theme="hc-light"] form.dashboard-widget-svggraph { + .overrides-options-list { + > li > div { + > .subfilter-disable-btn { + border: none !important; + top: 0; + } + } + } +} diff --git a/sass/stylesheets/sass/hc-dark.scss b/sass/stylesheets/sass/hc-dark.scss index 9c09a085b52..0b7410f1e30 100644 --- a/sass/stylesheets/sass/hc-dark.scss +++ b/sass/stylesheets/sass/hc-dark.scss @@ -1206,6 +1206,7 @@ td.inactive-bg { } // Multiline input control. + .multilineinput-control { button { &::after { @@ -1231,6 +1232,7 @@ td.inactive-bg { } // Time selection. + .ui-tabs-nav { .btn-info { &::after { @@ -1480,19 +1482,6 @@ td.inactive-bg { } } -// Overrides. -.overrides-options-list { - > li > div { - border: 1px solid $ui-tab-bg-selected-color; - background-color: transparent !important; - - > .subfilter-disable-btn { - border: none !important; - top: 0; - } - } -} - .totals-list { > div { border-top: 1px solid $ui-border-color; @@ -1511,6 +1500,7 @@ td.inactive-bg { } // Widget "Host availability". + .host-avail-widget { td:not(:first-child) { border-left: 1px solid $ui-border-color; @@ -1524,7 +1514,8 @@ td.inactive-bg { } } -// Widget "Navigation tree" +// Widget "Navigation tree". + .navtree { .tree .tree-item > .tree-row { min-width: 410px; @@ -1532,6 +1523,7 @@ td.inactive-bg { } // Widget "Problems by severity". + .by-severity-widget { > div { min-width: 65px; @@ -1544,13 +1536,13 @@ td.inactive-bg { } } -// InputSecret and ButtonDropdown +// InputSecret and ButtonDropdown. .btn-undo.is-focused { box-shadow: 0 1px 0px $blue, 0 -1px 0px $blue; } -// Tabfilter +// Tabfilter. .filter-container.tabfilter-container { .icon-filter::before { @@ -1574,7 +1566,7 @@ td.inactive-bg { } } -// HOST INTERFACES +// Host interfaces. .interfaces { .interface-row { @@ -1591,3 +1583,17 @@ td.inactive-bg { } } } + +// Section (components/_section.scss). + +section { + .section-toggle { + background-position: -318px -654px; + } + + &.section-collapsed { + .section-toggle { + background-position: -318px -690px; + } + } +} diff --git a/sass/stylesheets/sass/hc-light.scss b/sass/stylesheets/sass/hc-light.scss index 6f7675dc024..681db702d8c 100644 --- a/sass/stylesheets/sass/hc-light.scss +++ b/sass/stylesheets/sass/hc-light.scss @@ -1314,18 +1314,6 @@ td.inactive-bg { } } -// Overrides. -.overrides-options-list { - > li > div { - background-color: $ui-bg-selected-color !important; - - > .subfilter-disable-btn { - border: none !important; - top: 0; - } - } -} - .totals-list { > div { border-top: 1px solid $ui-border-color; @@ -1344,6 +1332,7 @@ td.inactive-bg { } // Widget "Host availability". + .host-avail-widget { td:not(:first-child) { border-left: 1px solid $ui-border-color; @@ -1357,7 +1346,8 @@ td.inactive-bg { } } -// Widget "Navigation tree" +// Widget "Navigation tree". + .navtree { .tree .tree-item > .tree-row { min-width: 410px; @@ -1365,6 +1355,7 @@ td.inactive-bg { } // Widget "Problems by severity". + .by-severity-widget { > div { min-width: 65px; @@ -1377,7 +1368,7 @@ td.inactive-bg { } } -// InputSecret and ButtonDropdown +// InputSecret and ButtonDropdown. .btn-undo.is-focused { box-shadow: 0 1px 0px $blue, 0 -1px 0px $blue; @@ -1403,7 +1394,7 @@ td.inactive-bg { } } -// HOST INTERFACES +// Host interfaces. .interfaces { .interface-row { @@ -1420,3 +1411,17 @@ td.inactive-bg { } } } + +// Section (components/_section.scss). + +section { + .section-toggle { + background-position: -165px -654px; + } + + &.section-collapsed { + .section-toggle { + background-position: -165px -690px; + } + } +} diff --git a/sass/stylesheets/sass/layout/_form-grid.scss b/sass/stylesheets/sass/layout/_form-grid.scss index dedda435665..ebd643498df 100644 --- a/sass/stylesheets/sass/layout/_form-grid.scss +++ b/sass/stylesheets/sass/layout/_form-grid.scss @@ -1,6 +1,5 @@ .form-grid { display: grid; - padding: 5px; row-gap: 10px; column-gap: 10px; @@ -26,6 +25,11 @@ &.fields-group-label { padding-top: 5px; } + + .icon-help-hint, + .icon-info { + margin-left: 5px; + } } > .form-field, diff --git a/sass/stylesheets/sass/screen.scss b/sass/stylesheets/sass/screen.scss index b9908891d6f..2710253f8b9 100644 --- a/sass/stylesheets/sass/screen.scss +++ b/sass/stylesheets/sass/screen.scss @@ -30,8 +30,10 @@ $browser-sprite-path: '../img/browser-sprite.png?20220722'; @import "components/buttons"; @import "components/color-picker"; +@import "components/columns-wrapper"; @import "components/dashboard/dashboard"; @import "components/dashboard/widget-clock"; +@import "components/dashboard/widget-inaccessible"; @import "components/dashboard/widget-item"; @import "components/dashboard/widget-slareport"; @import "components/dashboard/widget-svggraph"; @@ -45,6 +47,7 @@ $browser-sprite-path: '../img/browser-sprite.png?20220722'; @import "components/message-box"; @import "components/radio-list-control"; @import "components/range-control"; +@import "components/section"; @import "components/service/info"; @import "components/subfilter"; @import "components/svg-graph"; @@ -2616,10 +2619,10 @@ $var-icons: ( } $trigger-expression-tree-icons: ( - top-bottom: url($sprite-path) no-repeat -84px -300px, - top-bottom-right: url($sprite-path) no-repeat -84px -334px, - top-right: url($sprite-path) no-repeat -84px -372px, - empty: url($sprite-path) no-repeat -84px -350px + top-bottom: -84px -300px, + top-bottom-right: -84px -334px, + top-right: -84px -372px, + empty: -84px -350px ); %trigger-expression-tree-icons-common { @@ -3082,7 +3085,7 @@ $form-icon-btn: ( margin: 0 10px; .dashboard-widget-head { - margin-bottom: 14px; + margin-bottom: 12px; .icon-doc-link { margin-right: -26px; @@ -3101,11 +3104,15 @@ $form-icon-btn: ( width: 100%; max-height: calc(100vh - 220px); max-width: inherit; - margin: 0 -10px 10px; + margin: 0 -10px 8px; padding: 0 10px; position: relative; @extend %webkit-scrollbar; + > form { + padding: 2px 0; + } + .table-forms { .table-forms-td-right { padding-right: 8px; @@ -3740,23 +3747,6 @@ $form-icon-btn: ( stroke-width: 2px; } -.svg-graph-preview { - margin-top: 10px; - min-width: 1120px; - height: 300px; - position: relative; - - > div { - background: $ui-bg-color; - height: 300px; - position: absolute; - left: 0; - right: 0; - top: 0; - z-index: 3; // More than z-index of form controls, less than z-index of .msg-*. - } -} - .svg-graph-hintbox { font-size: 12px; line-height: 18px; @@ -4727,73 +4717,6 @@ svg { word-break: break-word; } -.overrides-list { - display: table; - width: 90%; - max-width: 738px; - padding-left: 15px; - - .overrides-list-item { - display: table-row; - - .btn-remove { - position: relative; - right: -73px; - top: 3px; - } - } -} - -.overrides-options-list { - white-space: normal; - padding: 5px 0 8px; - margin-bottom: 10px; - border-bottom: 1px solid $table-border-color; - - > li { - display: inline-block; - margin: 2px 7px 2px 0; - white-space: nowrap; - vertical-align: middle; - - > div { - position: relative; - padding: 1px 18px 1px 1px; - background-color: $ui-bg-selected-color; - border-radius: 2px; - - > span { - color: lighten($ui-bg-selected-color, 100%); - padding-left: 8px; - line-height: 22px; - } - - > input[type=text] { - border-style: none; - line-height: 22px; - min-height: 22px; - width: 85px; - } - - > .subfilter-disable-btn { - position: absolute; - right: 0; - top: 0; - min-height: 24px; - } - } - } - - .color-picker { - .color-picker-preview { - margin: 1px; - width: 20px; - min-height: 20px; - background-position: -323px -411px; - } - } -} - .list-accordion-foot { > div { display: table-cell; @@ -4871,75 +4794,6 @@ svg { } } -.columns-wrapper { - $column-count: (2, 3); - $column-size: ( - 5: 5%, - 10: 10%, - 15: 15%, - 20: 20%, - 33: 33.33333%, - 35: 35%, - 40: 40%, - 50: 50%, - 75: 75%, - 90: 90%, - 95: 95% - ); - - display: flex; - flex-wrap: wrap; - align-items: start; - - &.columns-nowrap { - flex-wrap: nowrap; - } - - // Dynamically generated classes for the columns count: - // .columns-2 - // .columns-3 - @each $count in $column-count { - &.columns-#{$count} > { - div, - li { - display: block; - flex: 0 0 (100% / $count); - max-width: (100% / $count); - } - } - } - - // Dynamically generated classes for the column width: - // .column-5 - // .column-10 - // .column-15 - // .column-20 - // .column-33 - // .column-35 - // .column-40 - // .column-50 - // .column-75 - // .column-90 - // .column-95 - @each $class, $width in $column-size { - .column-#{$class} { - flex: 0 0 $width; - max-width: $width; - } - } - - .column-center { - display: flex; - justify-content: center; - text-align: center; - } - - .column-middle { - display: flex; - align-items: center; - } -} - .preprocessing-list { $name-width: 295px; $on-fail-width: 100px; diff --git a/sass/stylesheets/sass/utils/_sortable.scss b/sass/stylesheets/sass/utils/_sortable.scss index 34bce40cd69..f5c8c857f4f 100644 --- a/sass/stylesheets/sass/utils/_sortable.scss +++ b/sass/stylesheets/sass/utils/_sortable.scss @@ -9,8 +9,14 @@ @if $ui-transitions { transition: left .2s, top .2s; + } + } - .sortable-item:not(.sortable-dragging) { + .sortable-item { + box-sizing: border-box; + + @if $ui-transitions { + &:not(.sortable-dragging) { transition: left .2s, top .2s; } } diff --git a/src/libs/zbxdbupgrade/dbupgrade_6030.c b/src/libs/zbxdbupgrade/dbupgrade_6030.c index a5313d6bb5c..5a0499ec53d 100644 --- a/src/libs/zbxdbupgrade/dbupgrade_6030.c +++ b/src/libs/zbxdbupgrade/dbupgrade_6030.c @@ -476,6 +476,92 @@ static int DBpatch_6030061(void) return DBmodify_field_type("triggers", &field, NULL); } +static int DBpatch_6030062(void) +{ + DB_RESULT result; + DB_ROW row; + char *sql; + size_t sql_alloc = 4096, sql_offset = 0; + int ret = SUCCEED; + + if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) + return SUCCEED; + + sql = zbx_malloc(NULL, sql_alloc); + + zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset); + + result = DBselect("select moduleid,relative_path from module"); + + while (NULL != (row = DBfetch(result))) + { + const char *rel_path = row[1]; + char *updated_path, *updated_path_esc; + + if (NULL == rel_path || '\0' == *rel_path) + continue; + + updated_path = zbx_dsprintf(NULL, "modules/%s", rel_path); + + updated_path_esc = DBdyn_escape_string(updated_path); + + zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update module set relative_path='%s' " + "where moduleid=%s;\n", updated_path_esc, row[0]); + + zbx_free(updated_path); + zbx_free(updated_path_esc); + + ret = DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset); + } + DBfree_result(result); + + zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset); + + if (SUCCEED == ret && 16 < sql_offset) + { + if (ZBX_DB_OK > DBexecute("%s", sql)) + ret = FAIL; + } + + zbx_free(sql); + + return ret; +} + +static int DBpatch_6030063(void) +{ + zbx_db_insert_t db_insert; + int i, ret = FAIL; + + const char *modules[] = { + "actionlog", "clock", "dataover", "discovery", "favgraphs", "favmaps", "geomap", "graph", + "graphprototype", "hostavail", "item", "map", "navtree", "plaintext", "problemhosts", + "problems", "problemsbysv", "slareport", "svggraph", "systeminfo", "tophosts", "trigover", + "url", "web" + }; + + if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER)) + return SUCCEED; + + zbx_db_insert_prepare(&db_insert, "module", "moduleid", "id", "relative_path", "status", "config", NULL); + + for (i = 0; i < (int)ARRSIZE(modules); i++) + { + char *path; + + path = zbx_dsprintf(NULL, "widgets/%s", modules[i]); + zbx_db_insert_add_values(&db_insert, __UINT64_C(0), modules[i], path, 1, "[]"); + zbx_free(path); + } + + zbx_db_insert_autoincrement(&db_insert, "moduleid"); + ret = zbx_db_insert_execute(&db_insert); + + zbx_db_insert_clean(&db_insert); + + return ret; +} + #endif DBPATCH_START(6030) @@ -544,5 +630,7 @@ DBPATCH_ADD(6030058, 0, 1) DBPATCH_ADD(6030059, 0, 1) DBPATCH_ADD(6030060, 0, 1) DBPATCH_ADD(6030061, 0, 1) +DBPATCH_ADD(6030062, 0, 1) +DBPATCH_ADD(6030063, 0, 1) DBPATCH_END() diff --git a/ui/app/controllers/CControllerDashboardConfigurationHashGet.php b/ui/app/controllers/CControllerDashboardConfigurationHashGet.php new file mode 100644 index 00000000000..3e7f789a3ff --- /dev/null +++ b/ui/app/controllers/CControllerDashboardConfigurationHashGet.php @@ -0,0 +1,98 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +class CControllerDashboardConfigurationHashGet extends CController { + + protected function init(): void { + $this->setPostContentType(self::POST_CONTENT_TYPE_JSON); + } + + /** + * @throws JsonException + */ + protected function checkInput(): bool { + $fields = [ + 'dashboardid' => 'required|db dashboard.dashboardid|not_empty', + 'templateid' => 'db dashboard.dashboardid|not_empty' + ]; + + $ret = $this->validateInput($fields); + + if (!$ret) { + $this->setResponse( + new CControllerResponseData(['main_block' => json_encode([ + 'error' => [ + 'messages' => array_column(get_and_clear_messages(), 'message') + ] + ], JSON_THROW_ON_ERROR)]) + ); + } + + return $ret; + } + + protected function checkPermissions(): bool { + return true; + } + + /** + * @throws APIException|JsonException + */ + protected function doAction(): void { + $configuration_hash = null; + + if ($this->checkAccess(CRoleHelper::UI_MONITORING_DASHBOARD)) { + if ($this->hasInput('templateid')) { + $db_dashboards = API::TemplateDashboard()->get([ + 'output' => ['name', 'display_period', 'auto_start'], + 'selectPages' => ['dashboard_pageid', 'name', 'display_period', 'widgets'], + 'dashboardids' => $this->getInput('dashboardid') + ]); + } + else { + $db_dashboards = API::Dashboard()->get([ + 'output' => ['name', 'display_period', 'auto_start'], + 'selectPages' => ['dashboard_pageid', 'name', 'display_period', 'widgets'], + 'dashboardids' => $this->getInput('dashboardid') + ]); + } + + if ($db_dashboards) { + $db_dashboard = $db_dashboards[0]; + + $db_dashboard['pages'] = CDashboardHelper::preparePagesForGrid($db_dashboard['pages'], + $this->hasInput('templateid') ? $this->getInput('templateid') : null, + true + ); + + $widget_defaults = APP::ModuleManager()->getWidgetsDefaults($this->hasInput('templateid')); + + $configuration_hash = CDashboardHelper::getConfigurationHash($db_dashboard, $widget_defaults); + } + } + + $output = [ + 'configuration_hash' => $configuration_hash + ]; + + $this->setResponse(new CControllerResponseData(['main_block' => json_encode($output, JSON_THROW_ON_ERROR)])); + } +} diff --git a/ui/app/controllers/CControllerDashboardPrint.php b/ui/app/controllers/CControllerDashboardPrint.php index 724ae1d15b4..4dc3a5886a6 100644 --- a/ui/app/controllers/CControllerDashboardPrint.php +++ b/ui/app/controllers/CControllerDashboardPrint.php @@ -63,7 +63,7 @@ class CControllerDashboardPrint extends CController { $data = [ 'dashboard' => $dashboard, - 'widget_defaults' => CWidgetConfig::getDefaults(CWidgetConfig::CONTEXT_DASHBOARD), + 'widget_defaults' => APP::ModuleManager()->getWidgetsDefaults(), 'time_period' => getTimeSelectorPeriod($time_selector_options) ]; diff --git a/ui/app/controllers/CControllerDashboardUpdate.php b/ui/app/controllers/CControllerDashboardUpdate.php index 899e2263ded..3ed6849c0fa 100644 --- a/ui/app/controllers/CControllerDashboardUpdate.php +++ b/ui/app/controllers/CControllerDashboardUpdate.php @@ -21,7 +21,9 @@ class CControllerDashboardUpdate extends CController { - private $dashboard_pages; + private ?array $db_dashboard = null; + + private ?array $dashboard_pages = null; protected function init() { $this->setPostContentType(self::POST_CONTENT_TYPE_JSON); @@ -35,17 +37,32 @@ class CControllerDashboardUpdate extends CController { 'display_period' => 'required|db dashboard.display_period|in '.implode(',', DASHBOARD_DISPLAY_PERIODS), 'auto_start' => 'required|db dashboard.auto_start|in 0,1', 'pages' => 'array', - 'sharing' => 'array' + 'sharing' => 'array', + 'clone' => 'in 1' ]; $ret = $this->validateInput($fields); + if ($ret && $this->hasInput('clone')) { + $validator = new CNewValidator($this->getInputAll(), [ + 'dashboardid' => 'required' + ]); + + foreach ($validator->getAllErrors() as $error) { + info($error); + } + + if ($validator->isErrorFatal() || $validator->isError()) { + $ret = false; + } + } + if ($ret) { $sharing_errors = $this->validateSharing(); [ 'dashboard_pages' => $this->dashboard_pages, 'errors' => $dashboard_pages_errors - ] = CDashboardHelper::validateDashboardPages($this->getInput('pages', []), null); + ] = CDashboardHelper::validateDashboardPages($this->getInput('pages', [])); $errors = array_merge($sharing_errors, $dashboard_pages_errors); @@ -70,90 +87,135 @@ class CControllerDashboardUpdate extends CController { } protected function checkPermissions() { - return $this->checkAccess(CRoleHelper::UI_MONITORING_DASHBOARD) - && $this->checkAccess(CRoleHelper::ACTIONS_EDIT_DASHBOARDS); + if (!$this->checkAccess(CRoleHelper::UI_MONITORING_DASHBOARD) + || !$this->checkAccess(CRoleHelper::ACTIONS_EDIT_DASHBOARDS)) { + return false; + } + + if ($this->hasInput('dashboardid')) { + $db_dashboards = API::Dashboard()->get([ + 'output' => ['dashboardid'], + 'selectPages' => ['widgets'], + 'dashboardids' => $this->getInput('dashboardid'), + 'editable' => true + ]); + + if (!$db_dashboards) { + return false; + } + + $this->db_dashboard = $db_dashboards[0]; + } + + return true; } protected function doAction() { - $save_dashboard = [ - 'name' => $this->getInput('name'), - 'userid' => $this->getInput('userid', 0), - 'display_period' => $this->getInput('display_period'), - 'auto_start' => $this->getInput('auto_start'), - 'pages' => [] - ]; + $output = []; - if ($this->hasInput('dashboardid')) { - $save_dashboard['dashboardid'] = $this->getInput('dashboardid'); - } + try { + $db_widgets = []; + + if ($this->db_dashboard !== null) { + foreach ($this->db_dashboard['pages'] as $db_dashboard_page) { + foreach ($db_dashboard_page['widgets'] as $db_widget) { + $db_widgets[$db_widget['widgetid']] = $db_widget; + } + } + } - foreach ($this->dashboard_pages as $dashboard_page) { - $save_dashboard_page = [ - 'name' => $dashboard_page['name'], - 'display_period' => $dashboard_page['display_period'], - 'widgets' => [] + $save_dashboard = [ + 'name' => $this->getInput('name'), + 'userid' => $this->getInput('userid', 0), + 'display_period' => $this->getInput('display_period'), + 'auto_start' => $this->getInput('auto_start'), + 'pages' => [] ]; - // Set dashboard_pageid if it exists and not cloning the dashboard. - if (array_key_exists('dashboardid', $save_dashboard) - && array_key_exists('dashboard_pageid', $dashboard_page)) { - $save_dashboard_page['dashboard_pageid'] = $dashboard_page['dashboard_pageid']; + if ($this->db_dashboard !== null && !$this->hasInput('clone')) { + $save_dashboard['dashboardid'] = $this->db_dashboard['dashboardid']; } - foreach ($dashboard_page['widgets'] as $widget) { - $save_widget = [ - 'x' => $widget['pos']['x'], - 'y' => $widget['pos']['y'], - 'width' => $widget['pos']['width'], - 'height' => $widget['pos']['height'], - 'type' => $widget['type'], - 'name' => $widget['name'], - 'view_mode' => $widget['view_mode'], - 'fields' => $widget['form']->fieldsToApi() + foreach ($this->dashboard_pages as $dashboard_page) { + $save_dashboard_page = [ + 'name' => $dashboard_page['name'], + 'display_period' => $dashboard_page['display_period'], + 'widgets' => [] ]; - // Set widgetid if it exists and not cloning the dashboard. - if (array_key_exists('dashboardid', $save_dashboard) && array_key_exists('widgetid', $widget)) { - $save_widget['widgetid'] = $widget['widgetid']; + if (array_key_exists('dashboard_pageid', $dashboard_page) && !$this->hasInput('clone')) { + $save_dashboard_page['dashboard_pageid'] = $dashboard_page['dashboard_pageid']; } - $save_dashboard_page['widgets'][] = $save_widget; - } + foreach ($dashboard_page['widgets'] as $widget) { + $save_widget = [ + 'x' => $widget['pos']['x'], + 'y' => $widget['pos']['y'], + 'width' => $widget['pos']['width'], + 'height' => $widget['pos']['height'] + ]; + + if ($widget['type'] !== ZBX_WIDGET_INACCESSIBLE) { + $save_widget += [ + 'type' => $widget['type'], + 'name' => $widget['name'], + 'view_mode' => $widget['view_mode'], + 'fields' => $widget['form']->fieldsToApi() + ]; + } + else { + if (!array_key_exists('widgetid', $widget) + || !array_key_exists($widget['widgetid'], $db_widgets)) { + error(_('No permissions to referred object or it does not exist!')); - $save_dashboard['pages'][] = $save_dashboard_page; - } + throw new InvalidArgumentException(); + } - if ($this->hasInput('sharing')) { - $sharing = $this->getInput('sharing'); + $db_widget = $db_widgets[$widget['widgetid']]; - $save_dashboard['private'] = $sharing['private']; + $save_widget += [ + 'type' => $db_widget['type'], + 'name' => $db_widget['name'], + 'view_mode' => $db_widget['view_mode'], + 'fields' => $db_widget['fields'] + ]; + } - if (array_key_exists('users', $sharing)) { - $save_dashboard['users'] = $sharing['users']; - } + if (array_key_exists('widgetid', $widget) && !$this->hasInput('clone')) { + $save_widget['widgetid'] = $widget['widgetid']; + } + + $save_dashboard_page['widgets'][] = $save_widget; + } - if (array_key_exists('userGroups', $sharing)) { - $save_dashboard['userGroups'] = $sharing['userGroups']; + $save_dashboard['pages'][] = $save_dashboard_page; } - } - if (array_key_exists('dashboardid', $save_dashboard)) { - $result = API::Dashboard()->update($save_dashboard); + if ($this->hasInput('sharing')) { + $sharing = $this->getInput('sharing'); - $success_title = _('Dashboard updated'); - $error_title = _('Failed to update dashboard'); - } - else { - $result = API::Dashboard()->create($save_dashboard); + $save_dashboard['private'] = $sharing['private']; - $success_title = _('Dashboard created'); - $error_title = _('Failed to create dashboard'); - } + if (array_key_exists('users', $sharing)) { + $save_dashboard['users'] = $sharing['users']; + } - $output = []; + if (array_key_exists('userGroups', $sharing)) { + $save_dashboard['userGroups'] = $sharing['userGroups']; + } + } + + $result = $this->db_dashboard !== null && !$this->hasInput('clone') + ? API::Dashboard()->update($save_dashboard) + : API::Dashboard()->create($save_dashboard); + + if (!$result) { + throw new InvalidArgumentException(); + } - if ($result) { - $output['success']['title'] = $success_title; + $output['success']['title'] = $this->db_dashboard !== null && !$this->hasInput('clone') + ? _('Dashboard updated') + : _('Dashboard created'); if ($messages = get_and_clear_messages()) { $output['success']['messages'] = array_column($messages, 'message'); @@ -161,9 +223,11 @@ class CControllerDashboardUpdate extends CController { $output['dashboardid'] = $result['dashboardids'][0]; } - else { + catch (InvalidArgumentException $e) { $output['error'] = [ - 'title' => $error_title, + 'title' => $this->db_dashboard !== null && !$this->hasInput('clone') + ? _('Failed to update dashboard') + : _('Failed to create dashboard'), 'messages' => array_column(get_and_clear_messages(), 'message') ]; } diff --git a/ui/app/controllers/CControllerDashboardView.php b/ui/app/controllers/CControllerDashboardView.php index ef207da6776..8ea10a11570 100644 --- a/ui/app/controllers/CControllerDashboardView.php +++ b/ui/app/controllers/CControllerDashboardView.php @@ -28,10 +28,10 @@ class CControllerDashboardView extends CController { protected function checkInput() { $fields = [ 'dashboardid' => 'db dashboard.dashboardid', - 'source_dashboardid' => 'db dashboard.dashboardid', 'hostid' => 'db hosts.hostid', 'new' => 'in 1', 'cancel' => 'in 1', + 'clone' => 'in 1', 'from' => 'range_time', 'to' => 'range_time', 'slideshow' => 'in 1' @@ -39,6 +39,20 @@ class CControllerDashboardView extends CController { $ret = $this->validateInput($fields) && $this->validateTimeSelectorPeriod(); + if ($ret && $this->hasInput('clone')) { + $validator = new CNewValidator($this->getInputAll(), [ + 'dashboardid' => 'required' + ]); + + foreach ($validator->getAllErrors() as $error) { + info($error); + } + + if ($validator->isErrorFatal() || $validator->isError()) { + $ret = false; + } + } + if (!$ret) { $this->setResponse(new CControllerResponseFatal()); } @@ -51,7 +65,7 @@ class CControllerDashboardView extends CController { return false; } - if ($this->hasInput('new') || $this->hasInput('source_dashboardid')) { + if ($this->hasInput('new') || $this->hasInput('clone')) { return $this->checkAccess(CRoleHelper::ACTIONS_EDIT_DASHBOARDS); } @@ -69,6 +83,9 @@ class CControllerDashboardView extends CController { return true; } + /** + * @throws JsonException + */ protected function doAction() { [$dashboard, $error] = $this->getDashboard(); @@ -99,18 +116,25 @@ class CControllerDashboardView extends CController { $time_selector_options = [ 'profileIdx' => 'web.dashboard.filter', - 'profileIdx2' => ($dashboard['dashboardid'] !== null) ? $dashboard['dashboardid'] : 0, + 'profileIdx2' => $dashboard['dashboardid'] ?? 0, 'from' => $this->hasInput('from') ? $this->getInput('from') : null, 'to' => $this->hasInput('to') ? $this->getInput('to') : null ]; updateTimeSelectorPeriod($time_selector_options); + $widget_defaults = APP::ModuleManager()->getWidgetsDefaults(); + $data = [ 'dashboard' => $dashboard, - 'widget_defaults' => CWidgetConfig::getDefaults(CWidgetConfig::CONTEXT_DASHBOARD), + 'widget_defaults' => $widget_defaults, + 'widget_last_type' => CDashboardHelper::getWidgetLastType(), + 'configuration_hash' => $dashboard['dashboardid'] !== null + ? CDashboardHelper::getConfigurationHash($dashboard, $widget_defaults) + : null, 'has_time_selector' => CDashboardHelper::hasTimeSelector($dashboard['pages']), 'time_period' => getTimeSelectorPeriod($time_selector_options), + 'clone' => $this->hasInput('clone'), 'active_tab' => CProfile::get('web.dashboard.filter.active', 1) ]; @@ -143,10 +167,8 @@ class CControllerDashboardView extends CController { /** * Get dashboard data from API. - * - * @return array */ - private function getDashboard() { + private function getDashboard(): array { $dashboard = null; $error = null; @@ -172,19 +194,18 @@ class CControllerDashboardView extends CController { 'has_related_reports' => false ]; } - elseif ($this->hasInput('source_dashboardid')) { - // Clone dashboard and show as new. + elseif ($this->hasInput('clone')) { $dashboards = API::Dashboard()->get([ - 'output' => ['name', 'private', 'display_period', 'auto_start'], + 'output' => ['dashboardid', 'name', 'private', 'display_period', 'auto_start'], 'selectPages' => ['dashboard_pageid', 'name', 'display_period', 'widgets'], 'selectUsers' => ['userid', 'permission'], 'selectUserGroups' => ['usrgrpid', 'permission'], - 'dashboardids' => [$this->getInput('source_dashboardid')] + 'dashboardids' => $this->getInput('dashboardid') ]); if ($dashboards) { $dashboard = [ - 'dashboardid' => null, + 'dashboardid' => $dashboards[0]['dashboardid'], 'name' => $dashboards[0]['name'], 'display_period' => $dashboards[0]['display_period'], 'auto_start' => $dashboards[0]['auto_start'], @@ -231,7 +252,7 @@ class CControllerDashboardView extends CController { $dashboards = API::Dashboard()->get([ 'output' => ['dashboardid', 'name', 'userid', 'display_period', 'auto_start'], 'selectPages' => ['dashboard_pageid', 'name', 'display_period', 'widgets'], - 'dashboardids' => [$dashboardid], + 'dashboardids' => $dashboardid, 'preservekeys' => true ]); @@ -266,14 +287,8 @@ class CControllerDashboardView extends CController { /** * Checks, if any of widgets has checked dynamic field. - * - * @param array $grid_pages - * - * @static - * - * @return bool */ - private static function hasDynamicWidgets($grid_pages) { + private static function hasDynamicWidgets($grid_pages): bool { foreach ($grid_pages as $page) { foreach ($page['widgets'] as $widget) { if (array_key_exists('dynamic', $widget['fields']) && $widget['fields']['dynamic'] == 1) { diff --git a/ui/app/controllers/CControllerDashboardWidgetCheck.php b/ui/app/controllers/CControllerDashboardWidgetCheck.php index 5c1c159bddc..6c9d3208dbf 100644 --- a/ui/app/controllers/CControllerDashboardWidgetCheck.php +++ b/ui/app/controllers/CControllerDashboardWidgetCheck.php @@ -19,9 +19,14 @@ **/ +use Zabbix\Core\{ + CModule, + CWidget +}; + class CControllerDashboardWidgetCheck extends CController { - private $context; + private ?CWidget $widget = null; protected function init() { $this->setPostContentType(self::POST_CONTENT_TYPE_JSON); @@ -29,26 +34,33 @@ class CControllerDashboardWidgetCheck extends CController { protected function checkInput() { $fields = [ - 'templateid' => 'db dashboard.templateid', 'type' => 'required|string', - 'name' => 'required|string', - 'fields' => 'json' + 'fields' => 'array', + 'templateid' => 'db dashboard.templateid', + 'name' => 'required|string' ]; $ret = $this->validateInput($fields); if ($ret) { - $this->context = $this->hasInput('templateid') - ? CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - : CWidgetConfig::CONTEXT_DASHBOARD; + $widget = APP::ModuleManager()->getModule($this->getInput('type')); - if (!CWidgetConfig::isWidgetTypeSupportedInContext($this->getInput('type'), $this->context)) { - error(_('Widget type is not supported in this context.')); + if ($widget !== null && $widget->getType() === CModule::TYPE_WIDGET) { + $this->widget = $widget; + } + else { + error(_('Inaccessible widget type.')); $ret = false; } } + if ($ret && $this->hasInput('templateid') && !$this->widget->hasTemplateSupport()) { + error(_('Widget type is not supported in this context.')); + + $ret = false; + } + if (!$ret) { $this->setResponse( new CControllerResponseData(['main_block' => json_encode([ @@ -67,8 +79,8 @@ class CControllerDashboardWidgetCheck extends CController { } protected function doAction() { - $form = CWidgetConfig::getForm($this->getInput('type'), $this->getInput('fields', '{}'), - ($this->context === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD) ? $this->getInput('templateid') : null + $form = $this->widget->getForm($this->getInput('fields', []), + $this->hasInput('templateid') ? $this->getInput('templateid') : null ); $output = []; diff --git a/ui/app/controllers/CControllerDashboardWidgetConfigure.php b/ui/app/controllers/CControllerDashboardWidgetConfigure.php deleted file mode 100644 index 9c34138eac8..00000000000 --- a/ui/app/controllers/CControllerDashboardWidgetConfigure.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CControllerDashboardWidgetConfigure extends CController { - - private $context; - - protected function init() { - $this->setPostContentType(self::POST_CONTENT_TYPE_JSON); - } - - protected function checkInput() { - $fields = [ - 'templateid' => 'db dashboard.templateid', - 'type' => 'required|string', - 'fields' => 'json', - 'view_mode' => 'required|in '.implode(',', [ZBX_WIDGET_VIEW_MODE_NORMAL, ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER]) - ]; - - $ret = $this->validateInput($fields); - - if ($ret) { - $this->context = $this->hasInput('templateid') - ? CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - : CWidgetConfig::CONTEXT_DASHBOARD; - - if (!CWidgetConfig::isWidgetTypeSupportedInContext($this->getInput('type'), $this->context)) { - error(_('Widget type is not supported in this context.')); - - $ret = false; - } - } - - if (!$ret) { - $this->setResponse( - new CControllerResponseData(['main_block' => json_encode([ - 'error' => [ - 'messages' => array_column(get_and_clear_messages(), 'message') - ] - ])]) - ); - } - - return $ret; - } - - protected function checkPermissions() { - return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); - } - - protected function doAction() { - $type = $this->getInput('type'); - - $form = CWidgetConfig::getForm($type, $this->getInput('fields', '{}'), - ($this->context === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD) ? $this->getInput('templateid') : null - ); - - // Fix possibly corrupted data to the defaults. - $form->validate(); - - $output = [ - 'configuration' => CWidgetConfig::getConfiguration($type, $form->getFieldsData(), - $this->getInput('view_mode') - ) - ]; - - $this->setResponse(new CControllerResponseData(['main_block' => json_encode($output)])); - } -} diff --git a/ui/app/controllers/CControllerDashboardWidgetEdit.php b/ui/app/controllers/CControllerDashboardWidgetEdit.php index bf020dfe72d..7390872df0d 100644 --- a/ui/app/controllers/CControllerDashboardWidgetEdit.php +++ b/ui/app/controllers/CControllerDashboardWidgetEdit.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,18 +19,36 @@ **/ +use Zabbix\Core\{ + CModule, + CWidget +}; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldMultiSelectGraph, + CWidgetFieldMultiSelectGraphPrototype, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldMultiSelectItem, + CWidgetFieldMultiSelectItemPrototype, + CWidgetFieldMultiSelectService, + CWidgetFieldMultiSelectSla, + CWidgetFieldSelectResource +}; + class CControllerDashboardWidgetEdit extends CController { - private $context; + private ?CWidget $widget; - protected function checkInput() { + protected function checkInput(): bool { $fields = [ + 'type' => 'string|required', + 'fields' => 'array', 'templateid' => 'db dashboard.templateid', - 'type' => 'string', 'name' => 'string', 'view_mode' => 'in '.implode(',', [ZBX_WIDGET_VIEW_MODE_NORMAL, ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER]), - 'prev_type' => 'string', - 'fields' => 'json', 'unique_id' => 'string', 'dashboard_page_unique_id' => 'string' ]; @@ -38,94 +56,92 @@ class CControllerDashboardWidgetEdit extends CController { $ret = $this->validateInput($fields); if ($ret) { - $this->context = $this->hasInput('templateid') - ? CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - : CWidgetConfig::CONTEXT_DASHBOARD; + $widget = APP::ModuleManager()->getModule($this->getInput('type')); - if ($this->hasInput('type')) { - if (!CWidgetConfig::isWidgetTypeSupportedInContext($this->getInput('type'), $this->context)) { - error(_('Widget type is not supported in this context.')); + if ($widget !== null && $widget->getType() === CModule::TYPE_WIDGET) { + $this->widget = $widget; + } + else { + error(_('Inaccessible widget type.')); - $ret = false; - } + $ret = false; } } + if ($ret && $this->hasInput('templateid') && !$this->widget->hasTemplateSupport()) { + error(_('Widget type is not supported in this context.')); + + $ret = false; + } + if (!$ret) { $this->setResponse( - (new CControllerResponseData(['main_block' => json_encode([ - 'error' => [ - 'messages' => array_column(get_and_clear_messages(), 'message') - ] - ])]))->disableView() + (new CControllerResponseData([ + 'main_block' => json_encode([ + 'header' => $this->hasInput('unique_id') ? _('Edit widget') : _('Add widget'), + 'error' => [ + 'messages' => array_column(get_and_clear_messages(), 'message') + ] + ], JSON_THROW_ON_ERROR) + ]))->disableView() ); } return $ret; } - protected function checkPermissions() { - return ($this->context === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD) + protected function checkPermissions(): bool { + return $this->hasInput('templateid') ? ($this->getUserType() >= USER_TYPE_ZABBIX_ADMIN) : ($this->getUserType() >= USER_TYPE_ZABBIX_USER); } - protected function doAction() { - $known_widget_types = CWidgetConfig::getKnownWidgetTypes($this->context); - - natsort($known_widget_types); + protected function doAction(): void { + $known_types = []; + $deprecated_types = []; - if ($this->hasInput('type')) { - $type = $this->getInput('type'); - - if (!array_key_exists($type, $known_widget_types) || $this->getInput('prev_type', $type) !== $type) { - CProfile::update('web.dashboard.last_widget_type', $type, PROFILE_TYPE_STR); + /** @var CWidget $widget */ + foreach (APP::ModuleManager()->getWidgets($this->hasInput('templateid')) as $widget) { + if (!$widget->isDeprecated()) { + $known_types[$widget->getId()] = $widget->getDefaultName(); } - } - else { - $type = CProfile::get('web.dashboard.last_widget_type'); - if (!array_key_exists($type, $known_widget_types)) { - $type = array_keys($known_widget_types)[0]; + else { + $deprecated_types[$widget->getId()] = $widget->getDefaultName(); } } - $templateid = ($this->context === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD) - ? $this->getInput('templateid') - : null; + natcasesort($known_types); + natcasesort($deprecated_types); - $form = CWidgetConfig::getForm($type, $this->getInput('fields', '{}'), $templateid); + $form = $this->widget->getForm($this->getInput('fields', []), + $this->hasInput('templateid') ? $this->getInput('templateid') : null + ); // Transforms corrupted data to default values. $form->validate(); $this->setResponse(new CControllerResponseData([ - 'user' => [ - 'debug_mode' => $this->getDebugMode() - ], - 'dialogue' => [ - 'type' => $type, - 'name' => $this->getInput('name', ''), - 'view_mode' => $this->getInput('view_mode', ZBX_WIDGET_VIEW_MODE_NORMAL), - 'fields' => $form->getFields() - ], - 'templateid' => $templateid, + 'name' => $this->getInput('name', ''), + 'type' => $this->getInput('type'), + 'known_types' => $known_types, + 'deprecated_types' => $deprecated_types, + 'fields' => $form->getFields(), + 'view_mode' => $this->getInput('view_mode', ZBX_WIDGET_VIEW_MODE_NORMAL), 'unique_id' => $this->hasInput('unique_id') ? $this->getInput('unique_id') : null, 'dashboard_page_unique_id' => $this->hasInput('dashboard_page_unique_id') ? $this->getInput('dashboard_page_unique_id') : null, - 'known_widget_types' => $known_widget_types, - 'captions' => $this->getCaptions($form) + 'captions' => $this->getCaptions($form), + 'user' => [ + 'debug_mode' => $this->getDebugMode() + ] ])); } /** * Prepares mapped list of names for all required resources. - * - * @param CWidgetForm $form - * - * @return array */ - private function getCaptions($form) { + private function getCaptions(CWidgetForm $form): array { $captions = ['simple' => [], 'ms' => []]; foreach ($form->getFields() as $field) { @@ -137,12 +153,8 @@ class CControllerDashboardWidgetEdit extends CController { $captions['simple'][$resource_type] = []; } - if ($id != 0) { - switch ($resource_type) { - case WIDGET_FIELD_SELECT_RES_SYSMAP: - $captions['simple'][$resource_type][$id] = _('Inaccessible map'); - break; - } + if ($id != 0 && $resource_type == CWidgetFieldSelectResource::RESOURCE_TYPE_SYSMAP) { + $captions['simple'][$resource_type][$id] = _('Inaccessible map'); } } } @@ -152,19 +164,17 @@ class CControllerDashboardWidgetEdit extends CController { continue; } - switch ($resource_type) { - case WIDGET_FIELD_SELECT_RES_SYSMAP: - $maps = API::Map()->get([ - 'sysmapids' => array_keys($list), - 'output' => ['sysmapid', 'name'] - ]); - - if ($maps) { - foreach ($maps as $map) { - $list[$map['sysmapid']] = $map['name']; - } + if ($resource_type == CWidgetFieldSelectResource::RESOURCE_TYPE_SYSMAP) { + $maps = API::Map()->get([ + 'sysmapids' => array_keys($list), + 'output' => ['sysmapid', 'name'] + ]); + + if ($maps) { + foreach ($maps as $map) { + $list[$map['sysmapid']] = $map['name']; } - break; + } } } unset($list); @@ -182,35 +192,35 @@ class CControllerDashboardWidgetEdit extends CController { ]; foreach ($form->getFields() as $field) { - if ($field instanceof CWidgetFieldMsGroup) { + if ($field instanceof CWidgetFieldMultiSelectGroup) { $key = 'groups'; $var = 'group'; } - elseif ($field instanceof CWidgetFieldMsHost) { + elseif ($field instanceof CWidgetFieldMultiSelectHost) { $key = 'hosts'; $var = 'host'; } - elseif ($field instanceof CWidgetFieldMsItem) { + elseif ($field instanceof CWidgetFieldMultiSelectItem) { $key = 'items'; $var = 'item'; } - elseif ($field instanceof CWidgetFieldMsGraph) { + elseif ($field instanceof CWidgetFieldMultiSelectGraph) { $key = 'graphs'; $var = 'graph'; } - elseif ($field instanceof CWidgetFieldMsItemPrototype) { + elseif ($field instanceof CWidgetFieldMultiSelectItemPrototype) { $key = 'item_prototypes'; $var = 'prototype_item'; } - elseif ($field instanceof CWidgetFieldMsGraphPrototype) { + elseif ($field instanceof CWidgetFieldMultiSelectGraphPrototype) { $key = 'graph_prototypes'; $var = 'prototype_graph'; } - elseif ($field instanceof CWidgetFieldMsService) { + elseif ($field instanceof CWidgetFieldMultiSelectService) { $key = 'services'; $var = 'service'; } - elseif ($field instanceof CWidgetFieldMsSla) { + elseif ($field instanceof CWidgetFieldMultiSelectSla) { $key = 'slas'; $var = 'sla'; } diff --git a/ui/app/controllers/CControllerDashboardWidgetRfRate.php b/ui/app/controllers/CControllerDashboardWidgetRfRate.php index a7f8a2e603a..d8bc3432d47 100644 --- a/ui/app/controllers/CControllerDashboardWidgetRfRate.php +++ b/ui/app/controllers/CControllerDashboardWidgetRfRate.php @@ -19,8 +19,6 @@ **/ -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; - class CControllerDashboardWidgetRfRate extends CController { protected function init() { diff --git a/ui/app/controllers/CControllerDashboardWidgetView.php b/ui/app/controllers/CControllerDashboardWidgetView.php new file mode 100644 index 00000000000..f589e96f726 --- /dev/null +++ b/ui/app/controllers/CControllerDashboardWidgetView.php @@ -0,0 +1,107 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Core\CWidget; + +use Zabbix\Widgets\CWidgetForm; + +/** + * Class containing methods for operations with widgets. + */ +abstract class CControllerDashboardWidgetView extends CController { + + protected ?CWidget $widget; + protected CWidgetForm $form; + + protected array $validation_rules = []; + protected array $fields_values = []; + + protected function init(): void { + $this->setPostContentType(self::POST_CONTENT_TYPE_JSON); + + $this->setValidationRules([ + 'name' => 'string', + 'fields' => 'array' + ]); + } + + protected function setValidationRules(array $validation_rules): self { + $this->validation_rules = $validation_rules; + + return $this; + } + + protected function addValidationRules(array $validation_rules): self { + $this->validation_rules = array_merge($this->validation_rules, $validation_rules); + + return $this; + } + + protected function checkPermissions(): bool { + return $this->getUserType() >= USER_TYPE_ZABBIX_USER; + } + + protected function checkInput(): bool { + $this->widget = APP::ModuleManager()->getActionModule(); + + $validation_rules = $this->validation_rules; + + if ($this->widget->hasTemplateSupport()) { + $validation_rules['templateid'] = 'db dashboard.templateid'; + } + + $ret = $this->validateInput($validation_rules); + + if ($ret) { + $this->form = $this->widget->getForm($this->getInput('fields', []), + $this->hasInput('templateid') ? $this->getInput('templateid') : null + ); + + if ($errors = $this->form->validate()) { + foreach ($errors as $error) { + error($error); + } + + $ret = false; + } + } + + if ($ret) { + $this->fields_values = $this->form->getFieldsValues(); + } + + if (!$ret) { + $this->setResponse( + (new CControllerResponseData(['main_block' => json_encode([ + 'error' => [ + 'messages' => array_column(get_and_clear_messages(), 'message') + ] + ], JSON_THROW_ON_ERROR)]))->disableView() + ); + } + + return $ret; + } + + protected function getForm(): CWidgetForm { + return $this->form; + } +} diff --git a/ui/app/controllers/CControllerDashboardWidgetsSanitize.php b/ui/app/controllers/CControllerDashboardWidgetsSanitize.php index 5d2f8d8a07a..7137ffd41b6 100644 --- a/ui/app/controllers/CControllerDashboardWidgetsSanitize.php +++ b/ui/app/controllers/CControllerDashboardWidgetsSanitize.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,19 +19,20 @@ **/ +use Zabbix\Core\CModule; + /** * Controller for sanitizing fields of widgets before pasting previously copied widget. */ class CControllerDashboardWidgetsSanitize extends CController { - private $context; - private $widgets = []; + private array $widgets_data = []; - protected function init() { + protected function init(): void { $this->setPostContentType(self::POST_CONTENT_TYPE_JSON); } - protected function checkInput() { + protected function checkInput(): bool { $fields = [ 'templateid' => 'db dashboard.templateid', 'widgets' => 'array' @@ -40,14 +41,10 @@ class CControllerDashboardWidgetsSanitize extends CController { $ret = $this->validateInput($fields); if ($ret) { - $this->context = $this->hasInput('templateid') - ? CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - : CWidgetConfig::CONTEXT_DASHBOARD; - foreach ($this->getInput('widgets', []) as $widget) { $validator = new CNewValidator($widget, [ 'type' => 'required|string', - 'fields' => 'required|json' + 'fields' => 'required|array' ]); foreach ($validator->getAllErrors() as $error) { @@ -60,9 +57,17 @@ class CControllerDashboardWidgetsSanitize extends CController { break; } - $widget = $validator->getValidInput(); + $widget_input = $validator->getValidInput(); + + $widget = APP::ModuleManager()->getModule($widget_input['type']); + + if ($widget === null || $widget->getType() !== CModule::TYPE_WIDGET) { + $this->widgets_data[] = null; - if (!CWidgetConfig::isWidgetTypeSupportedInContext($widget['type'], $this->context)) { + continue; + } + + if ($this->hasInput('templateid') && !$widget->hasTemplateSupport()) { error(_('Widget type is not supported in this context.')); $ret = false; @@ -70,7 +75,12 @@ class CControllerDashboardWidgetsSanitize extends CController { break; } - $this->widgets[] = $widget; + $this->widgets_data[] = [ + 'type' => $widget_input['type'], + 'form' => $widget->getForm($widget_input['fields'], + $this->hasInput('templateid') ? $this->getInput('templateid') : null + ) + ]; } } @@ -80,29 +90,27 @@ class CControllerDashboardWidgetsSanitize extends CController { 'error' => [ 'messages' => array_column(get_and_clear_messages(), 'message') ] - ])]) + ], JSON_THROW_ON_ERROR)]) ); } return $ret; } - protected function checkPermissions() { + protected function checkPermissions(): bool { return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); } - protected function doAction() { + protected function doAction(): void { $widgets = []; - foreach ($this->widgets as $widget) { - $form = CWidgetConfig::getForm($widget['type'], $widget['fields'], - ($this->context === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD) ? $this->getInput('templateid') : null - ); - - $widgets[] = ['fields' => $form->fieldsToApi()]; + foreach ($this->widgets_data as $index => $widget_data) { + if ($widget_data !== null) { + $widgets[$index] = ['fields' => $widget_data['form']->fieldsToApi()]; + } } - if ($this->context === CWidgetConfig::CONTEXT_DASHBOARD) { + if (!$this->hasInput('templateid')) { $widgets = CDashboardHelper::unsetInaccessibleFields([['widgets' => $widgets]]); $widgets = $widgets[0]['widgets']; } @@ -111,11 +119,16 @@ class CControllerDashboardWidgetsSanitize extends CController { 'widgets' => [] ]; - foreach ($widgets as $widget_index => $widget) { - $output_fields = []; + foreach ($this->widgets_data as $index => $widget_data) { + if ($widget_data === null) { + $output['widgets'][$index] = null; - foreach ($widget['fields'] as $field) { + continue; + } + + $output_fields = []; + foreach ($widgets[$index]['fields'] as $field) { if (array_key_exists($field['name'], $output_fields)) { if (!is_array($output_fields[$field['name']])) { $output_fields[$field['name']] = [$output_fields[$field['name']]]; @@ -128,9 +141,9 @@ class CControllerDashboardWidgetsSanitize extends CController { } } - $output['widgets'][$widget_index]['fields'] = $output_fields; + $output['widgets'][$index]['fields'] = $output_fields; } - $this->setResponse(new CControllerResponseData(['main_block' => json_encode($output)])); + $this->setResponse(new CControllerResponseData(['main_block' => json_encode($output, JSON_THROW_ON_ERROR)])); } } diff --git a/ui/app/controllers/CControllerFavouriteCreate.php b/ui/app/controllers/CControllerFavoriteCreate.php index bdc2ae6256c..33b7e6b29c0 100644 --- a/ui/app/controllers/CControllerFavouriteCreate.php +++ b/ui/app/controllers/CControllerFavoriteCreate.php @@ -19,7 +19,7 @@ **/ -class CControllerFavouriteCreate extends CController { +class CControllerFavoriteCreate extends CController { protected function checkInput() { $fields = [ diff --git a/ui/app/controllers/CControllerFavouriteDelete.php b/ui/app/controllers/CControllerFavoriteDelete.php index 1a7cf92c1ab..468d0a88373 100644 --- a/ui/app/controllers/CControllerFavouriteDelete.php +++ b/ui/app/controllers/CControllerFavoriteDelete.php @@ -19,7 +19,12 @@ **/ -class CControllerFavouriteDelete extends CController { +use Zabbix\Core\CWidget; + +class CControllerFavoriteDelete extends CController { + + private const WIDGET_FAV_GRAPHS = 'favgraphs'; + private const WIDGET_FAV_MAPS = 'favmaps'; protected function checkInput() { $fields = [ @@ -46,10 +51,10 @@ class CControllerFavouriteDelete extends CController { 'sysmapid' => 'web.favorite.sysmapids' ]; - $widgetids = [ - 'graphid' => WIDGET_FAV_GRAPHS, - 'itemid' => WIDGET_FAV_GRAPHS, - 'sysmapid' => WIDGET_FAV_MAPS + $affected_widget_types = [ + 'graphid' => self::WIDGET_FAV_GRAPHS, + 'itemid' => self::WIDGET_FAV_GRAPHS, + 'sysmapid' => self::WIDGET_FAV_MAPS ]; $object = $this->getInput('object'); @@ -73,7 +78,8 @@ class CControllerFavouriteDelete extends CController { } else { ZABBIX.Dashboard.getSelectedDashboardPage().getWidgets().forEach((widget) => { - if (widget.getType() === "'.$widgetids[$object].'") { + if (widget.getType() === "'.$affected_widget_types[$object].'" + && widget.getState() === WIDGET_STATE_ACTIVE) { widget._startUpdating(); } }); diff --git a/ui/app/controllers/CControllerHintboxEventlist.php b/ui/app/controllers/CControllerHintboxEventlist.php index 73f20d4f297..a6ccad55510 100644 --- a/ui/app/controllers/CControllerHintboxEventlist.php +++ b/ui/app/controllers/CControllerHintboxEventlist.php @@ -34,7 +34,7 @@ class CControllerHintboxEventlist extends CController { $fields = [ 'triggerid' => 'required|db triggers.triggerid', 'eventid_till' => 'required|db events.eventid', - 'show_timeline' => 'required|in 0,1', + 'show_timeline' => 'required|in '.implode(',', [ZBX_TIMELINE_OFF, ZBX_TIMELINE_ON]), 'show_tags' => 'required|in '.implode(',', [SHOW_TAGS_NONE, SHOW_TAGS_1, SHOW_TAGS_2, SHOW_TAGS_3]), 'filter_tags' => 'array', 'tag_name_format' => 'required|in '.implode(',', [TAG_NAME_FULL, TAG_NAME_SHORTENED, TAG_NAME_NONE]), diff --git a/ui/app/controllers/CControllerHostDashboardView.php b/ui/app/controllers/CControllerHostDashboardView.php index e738c79f444..b2062fe2d2c 100644 --- a/ui/app/controllers/CControllerHostDashboardView.php +++ b/ui/app/controllers/CControllerHostDashboardView.php @@ -60,6 +60,9 @@ class CControllerHostDashboardView extends CController { return (bool) $this->host; } + /** + * @throws APIException|JsonException + */ protected function doAction() { $host_dashboards = $this->getSortedHostDashboards(); @@ -101,11 +104,14 @@ class CControllerHostDashboardView extends CController { updateTimeSelectorPeriod($time_selector_options); + $widget_defaults = APP::ModuleManager()->getWidgetsDefaults(true); + $data = [ 'host' => $this->host, 'host_dashboards' => $host_dashboards, 'dashboard' => $dashboard, - 'widget_defaults' => CWidgetConfig::getDefaults(CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD), + 'widget_defaults' => $widget_defaults, + 'configuration_hash' => CDashboardHelper::getConfigurationHash($dashboard, $widget_defaults), 'has_time_selector' => CDashboardHelper::hasTimeSelector($dashboard['pages']), 'time_period' => getTimeSelectorPeriod($time_selector_options), 'active_tab' => CProfile::get('web.dashboard.filter.active', 1) diff --git a/ui/app/controllers/CControllerModuleEdit.php b/ui/app/controllers/CControllerModuleEdit.php index 0f0405e107a..faec576705d 100644 --- a/ui/app/controllers/CControllerModuleEdit.php +++ b/ui/app/controllers/CControllerModuleEdit.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -26,16 +26,14 @@ class CControllerModuleEdit extends CController { /** * Current module data. - * - * @var array */ - private $module = []; + private array $module = []; - protected function init() { + protected function init(): void { $this->disableSIDValidation(); } - protected function checkInput() { + protected function checkInput(): bool { $fields = [ 'moduleid' => 'required|db module.moduleid', @@ -53,7 +51,7 @@ class CControllerModuleEdit extends CController { return $ret; } - protected function checkPermissions() { + protected function checkPermissions(): bool { if (!$this->checkAccess(CRoleHelper::UI_ADMINISTRATION_GENERAL)) { return false; } @@ -72,12 +70,12 @@ class CControllerModuleEdit extends CController { return true; } - protected function doAction() { - $module_manager = new CModuleManager(APP::ModuleManager()->getModulesDir()); + protected function doAction(): void { + $module_manager = new CModuleManager(APP::getRootDir()); $manifest = $module_manager->addModule($this->module['relative_path']); - if ($manifest) { + if ($manifest !== null) { $data = [ 'moduleid' => $this->getInput('moduleid'), 'name' => $manifest['name'], @@ -88,15 +86,12 @@ class CControllerModuleEdit extends CController { 'namespace' => $manifest['namespace'], 'url' => array_key_exists('url', $manifest) ? $manifest['url'] : null, 'status' => $this->hasInput('form_refresh') - ? $this->hasInput('status') - ? MODULE_STATUS_ENABLED - : MODULE_STATUS_DISABLED + ? ($this->hasInput('status') ? MODULE_STATUS_ENABLED : MODULE_STATUS_DISABLED) : $this->module['status'] ]; $response = new CControllerResponseData($data); $response->setTitle(_('Modules')); - $this->setResponse($response); } else { $response = new CControllerResponseRedirect((new CUrl('zabbix.php')) @@ -104,7 +99,8 @@ class CControllerModuleEdit extends CController { ->setArgument('page', CPagerHelper::loadPage('module.list', null)) ); CMessageHelper::setErrorTitle(_s('Cannot load module at: %1$s.', $this->module['relative_path'])); - $this->setResponse($response); } + + $this->setResponse($response); } } diff --git a/ui/app/controllers/CControllerModuleList.php b/ui/app/controllers/CControllerModuleList.php index 9c953b870a9..7b9ac9b8abe 100644 --- a/ui/app/controllers/CControllerModuleList.php +++ b/ui/app/controllers/CControllerModuleList.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -24,11 +24,11 @@ */ class CControllerModuleList extends CController { - protected function init() { + protected function init(): void { $this->disableSIDValidation(); } - protected function checkInput() { + protected function checkInput(): bool { $fields = [ 'sort' => 'in name', 'sortorder' => 'in '.ZBX_SORT_DOWN.','.ZBX_SORT_UP, @@ -48,11 +48,11 @@ class CControllerModuleList extends CController { return $ret; } - protected function checkPermissions() { + protected function checkPermissions(): bool { return $this->checkAccess(CRoleHelper::UI_ADMINISTRATION_GENERAL); } - protected function doAction() { + protected function doAction(): void { // sort fields $sort_field = $this->getInput('sort', CProfile::get('web.modules.sort', 'name')); $sort_order = $this->getInput('sortorder', CProfile::get('web.modules.sortorder', ZBX_SORT_UP)); @@ -87,13 +87,14 @@ class CControllerModuleList extends CController { 'preservekeys' => true ]); - $module_manager = new CModuleManager(APP::ModuleManager()->getModulesDir()); + $module_manager = new CModuleManager(APP::getRootDir()); $modules = []; foreach ($db_modules as $moduleid => $db_module) { $manifest = $module_manager->addModule($db_module['relative_path']); - if ($manifest && ($filter['name'] === '' || mb_stripos($manifest['name'], $filter['name']) !== false)) { + if ($manifest !== null + && ($filter['name'] === '' || mb_stripos($manifest['name'], $filter['name']) !== false)) { $modules[$moduleid] = $db_module + $manifest; } } diff --git a/ui/app/controllers/CControllerModuleScan.php b/ui/app/controllers/CControllerModuleScan.php index 257852a8a6e..832ee6e0b81 100644 --- a/ui/app/controllers/CControllerModuleScan.php +++ b/ui/app/controllers/CControllerModuleScan.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -24,15 +24,15 @@ */ class CControllerModuleScan extends CController { - protected function checkInput() { + protected function checkInput(): bool { return true; } - protected function checkPermissions() { + protected function checkPermissions(): bool { return $this->checkAccess(CRoleHelper::UI_ADMINISTRATION_GENERAL); } - protected function doAction() { + protected function doAction(): void { get_and_clear_messages(); $db_modules_create = []; @@ -53,36 +53,38 @@ class CControllerModuleScan extends CController { $db_moduleids[$db_module['relative_path']] = $moduleid; } - $module_manager = new CModuleManager(APP::ModuleManager()->getModulesDir()); + $module_manager = new CModuleManager(APP::getRootDir()); - foreach (new DirectoryIterator($module_manager->getModulesDir()) as $item) { - if (!$item->isDir() || $item->isDot()) { - continue; - } + foreach (['widgets', 'modules'] as $modules_dir) { + foreach (new DirectoryIterator(APP::getRootDir().'/'.$modules_dir) as $item) { + if (!$item->isDir() || $item->isDot()) { + continue; + } - $relative_path = $item->getFilename(); + $relative_path = $modules_dir.'/'.$item->getFilename(); - $manifest = $module_manager->addModule($relative_path); + $manifest = $module_manager->addModule($relative_path); - if (!$manifest) { - continue; - } + if (!$manifest) { + continue; + } - $is_stored = array_key_exists($relative_path, $db_moduleids); - $is_healthy = !$is_stored || $db_modules[$db_moduleids[$relative_path]]['id'] === $manifest['id']; + $is_stored = array_key_exists($relative_path, $db_moduleids); + $is_healthy = !$is_stored || $db_modules[$db_moduleids[$relative_path]]['id'] === $manifest['id']; - if ($is_healthy) { - $healthy_modules[] = $relative_path; - } + if ($is_healthy) { + $healthy_modules[] = $relative_path; + } - if (!$is_stored || !$is_healthy) { - $db_modules_create[] = [ - 'id' => $manifest['id'], - 'relative_path' => $relative_path, - 'status' => MODULE_STATUS_DISABLED, - 'config' => $manifest['config'] - ]; - $db_modules_create_names[] = $manifest['name']; + if (!$is_stored || !$is_healthy) { + $db_modules_create[] = [ + 'id' => $manifest['id'], + 'relative_path' => $relative_path, + 'status' => MODULE_STATUS_DISABLED, + 'config' => $manifest['config'] + ]; + $db_modules_create_names[] = $manifest['name']; + } } } diff --git a/ui/app/controllers/CControllerModuleUpdate.php b/ui/app/controllers/CControllerModuleUpdate.php index 3fcd763c5c1..f4a8a592df8 100644 --- a/ui/app/controllers/CControllerModuleUpdate.php +++ b/ui/app/controllers/CControllerModuleUpdate.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -26,12 +26,10 @@ class CControllerModuleUpdate extends CController { /** * List of modules to update. - * - * @var array */ - private $modules = []; + private array $modules = []; - protected function checkInput() { + protected function checkInput(): bool { $fields = [ 'moduleids' => 'required|array_db module.moduleid', @@ -49,7 +47,7 @@ class CControllerModuleUpdate extends CController { return $ret; } - protected function checkPermissions() { + protected function checkPermissions(): bool { if (!$this->checkAccess(CRoleHelper::UI_ADMINISTRATION_GENERAL)) { return false; } @@ -65,7 +63,7 @@ class CControllerModuleUpdate extends CController { return (count($this->modules) == count($moduleids)); } - protected function doAction() { + protected function doAction(): void { $set_status = ($this->getAction() === 'module.update') ? ($this->hasInput('status') ? MODULE_STATUS_ENABLED : MODULE_STATUS_DISABLED) : ($this->getAction() === 'module.enable' ? MODULE_STATUS_ENABLED : MODULE_STATUS_DISABLED); @@ -78,8 +76,8 @@ class CControllerModuleUpdate extends CController { 'preservekeys' => true ]); - $module_manager = new CModuleManager(APP::ModuleManager()->getModulesDir()); - $module_manager_enabled = new CModuleManager(APP::ModuleManager()->getModulesDir()); + $module_manager = new CModuleManager(APP::getRootDir()); + $module_manager_enabled = new CModuleManager(APP::getRootDir()); foreach ($db_modules as $moduleid => $db_module) { $new_status = array_key_exists($moduleid, $this->modules) ? $set_status : $db_module['status']; diff --git a/ui/app/controllers/CControllerProblem.php b/ui/app/controllers/CControllerProblem.php index 642fa9d21bb..e1fe131309e 100644 --- a/ui/app/controllers/CControllerProblem.php +++ b/ui/app/controllers/CControllerProblem.php @@ -44,7 +44,7 @@ abstract class CControllerProblem extends CController { 'show_suppressed' => 0, 'unacknowledged' => 0, 'compact_view' => 0, - 'show_timeline' => 1, + 'show_timeline' => ZBX_TIMELINE_ON, 'details' => 0, 'highlight_row' => 0, 'show_opdata' => OPERATIONAL_DATA_SHOW_NONE, diff --git a/ui/app/controllers/CControllerProblemView.php b/ui/app/controllers/CControllerProblemView.php index 1c2fb8d5bcf..b5bbe1420b3 100644 --- a/ui/app/controllers/CControllerProblemView.php +++ b/ui/app/controllers/CControllerProblemView.php @@ -45,7 +45,7 @@ class CControllerProblemView extends CControllerProblem { 'show_suppressed' => 'in 0,1', 'unacknowledged' => 'in 0,1', 'compact_view' => 'in 0,1', - 'show_timeline' => 'in 0,1', + 'show_timeline' => 'in '.ZBX_TIMELINE_OFF.','.ZBX_TIMELINE_ON, 'details' => 'in 0,1', 'highlight_row' => 'in 0,1', 'show_opdata' => 'in '.OPERATIONAL_DATA_SHOW_NONE.','.OPERATIONAL_DATA_SHOW_SEPARATELY.','.OPERATIONAL_DATA_SHOW_WITH_PROBLEM, diff --git a/ui/app/controllers/CControllerProblemViewRefresh.php b/ui/app/controllers/CControllerProblemViewRefresh.php index 8bf640164b4..7753a6a52e1 100644 --- a/ui/app/controllers/CControllerProblemViewRefresh.php +++ b/ui/app/controllers/CControllerProblemViewRefresh.php @@ -49,7 +49,7 @@ class CControllerProblemViewRefresh extends CControllerProblemView { 'show_suppressed' => 'in 0,1', 'unacknowledged' => 'in 0,1', 'compact_view' => 'in 0,1', - 'show_timeline' => 'in 0,1', + 'show_timeline' => 'in '.ZBX_TIMELINE_OFF.','.ZBX_TIMELINE_ON, 'details' => 'in 0,1', 'highlight_row' => 'in 0,1', 'show_opdata' => 'in '.OPERATIONAL_DATA_SHOW_NONE.','.OPERATIONAL_DATA_SHOW_SEPARATELY.','.OPERATIONAL_DATA_SHOW_WITH_PROBLEM, @@ -132,7 +132,7 @@ class CControllerProblemViewRefresh extends CControllerProblemView { 'show_suppressed' => $this->getInput('show_suppressed', ZBX_PROBLEM_SUPPRESSED_FALSE), 'unacknowledged' => $this->getInput('unacknowledged', 0), 'compact_view' => $this->getInput('compact_view', 0), - 'show_timeline' => $this->getInput('show_timeline', 0), + 'show_timeline' => $this->getInput('show_timeline', ZBX_TIMELINE_OFF), 'details' => $this->getInput('details', 0), 'highlight_row' => $this->getInput('highlight_row', 0), 'show_opdata' => $this->getInput('show_opdata', OPERATIONAL_DATA_SHOW_NONE), diff --git a/ui/app/controllers/CControllerProfileUpdate.php b/ui/app/controllers/CControllerProfileUpdate.php index aedc4491e8d..c164d456109 100644 --- a/ui/app/controllers/CControllerProfileUpdate.php +++ b/ui/app/controllers/CControllerProfileUpdate.php @@ -41,6 +41,7 @@ class CControllerProfileUpdate extends CController { case 'web.correlation.filter.active': case 'web.dashboard.filter.active': case 'web.dashboard.hostid': + case 'web.dashboard.last_widget_type': case 'web.discovery.filter.active': case 'web.discoveryconf.filter.active': case 'web.hostgroups.filter.active': @@ -63,9 +64,9 @@ class CControllerProfileUpdate extends CController { case 'web.proxies.filter.active': case 'web.scheduledreport.filter.active': case 'web.scripts.filter.active': - case 'web.search.hats.'.WIDGET_SEARCH_HOSTS.'.state': - case 'web.search.hats.'.WIDGET_SEARCH_TEMPLATES.'.state': - case 'web.search.hats.'.WIDGET_SEARCH_HOSTGROUP.'.state': + case 'web.search.hats.'.SECTION_SEARCH_HOSTS.'.state': + case 'web.search.hats.'.SECTION_SEARCH_TEMPLATES.'.state': + case 'web.search.hats.'.SECTION_SEARCH_HOSTGROUP.'.state': case 'web.service.filter.active': case 'web.service_actions.filter.active': case 'web.sidebar.mode': @@ -81,8 +82,8 @@ class CControllerProfileUpdate extends CController { case 'web.templates.triggers.filter.active': case 'web.token.filter.active': case 'web.toptriggers.filter.active': - case 'web.tr_events.hats.'.WIDGET_HAT_EVENTACTIONS.'.state': - case 'web.tr_events.hats.'.WIDGET_HAT_EVENTLIST.'.state': + case 'web.tr_events.hats.'.SECTION_HAT_EVENTACTIONS.'.state': + case 'web.tr_events.hats.'.SECTION_HAT_EVENTLIST.'.state': case 'web.user.filter.active': case 'web.user.token.filter.active': case 'web.usergroup.filter.active': @@ -104,6 +105,7 @@ class CControllerProfileUpdate extends CController { if ($ret) { switch ($this->getInput('idx')) { + case 'web.dashboard.last_widget_type': case 'web.dashboard.widget.geomap.default_view': case 'web.dashboard.widget.geomap.severity_filter': $ret = $this->hasInput('value_str'); @@ -132,6 +134,15 @@ class CControllerProfileUpdate extends CController { DBstart(); switch ($idx) { // PROFILE_TYPE_STR + case 'web.dashboard.last_widget_type': + $value_str = $this->getInput('value_str'); + if ($value_str === '') { + CProfile::delete($idx); + } + else { + CProfile::update($idx, $value_str, PROFILE_TYPE_STR); + } + break; case 'web.dashboard.widget.geomap.default_view': case 'web.dashboard.widget.geomap.severity_filter': $value_str = $this->getInput('value_str'); diff --git a/ui/app/controllers/CControllerTemplateDashboardEdit.php b/ui/app/controllers/CControllerTemplateDashboardEdit.php index b500e89857e..bc32eb03d6e 100644 --- a/ui/app/controllers/CControllerTemplateDashboardEdit.php +++ b/ui/app/controllers/CControllerTemplateDashboardEdit.php @@ -21,13 +21,13 @@ class CControllerTemplateDashboardEdit extends CController { - private $dashboard; + private array $dashboard; - protected function init() { + protected function init(): void { $this->disableSIDValidation(); } - protected function checkInput() { + protected function checkInput(): bool { $fields = [ 'templateid' => 'db dashboard.templateid', 'dashboardid' => 'db dashboard.dashboardid' @@ -44,7 +44,7 @@ class CControllerTemplateDashboardEdit extends CController { return $ret; } - protected function checkPermissions() { + protected function checkPermissions(): bool { if ($this->getUserType() < USER_TYPE_ZABBIX_ADMIN) { return false; } @@ -61,12 +61,11 @@ class CControllerTemplateDashboardEdit extends CController { return (bool) $this->dashboard; } - else { - return isWritableHostTemplates((array) $this->getInput('templateid')); - } + + return isWritableHostTemplates((array) $this->getInput('templateid')); } - protected function doAction() { + protected function doAction(): void { if ($this->hasInput('dashboardid')) { $dashboard = $this->dashboard; $dashboard['pages'] = CDashboardHelper::preparePagesForGrid($dashboard['pages'], $dashboard['templateid'], @@ -93,7 +92,8 @@ class CControllerTemplateDashboardEdit extends CController { $data = [ 'dashboard' => $dashboard, - 'widget_defaults' => CWidgetConfig::getDefaults(CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD), + 'widget_defaults' => APP::ModuleManager()->getWidgetsDefaults(true), + 'widget_last_type' => CDashboardHelper::getWidgetLastType(true), 'time_period' => getTimeSelectorPeriod([]), 'page' => CPagerHelper::loadPage('template.dashboard.list', null) ]; diff --git a/ui/app/controllers/CControllerTemplateDashboardUpdate.php b/ui/app/controllers/CControllerTemplateDashboardUpdate.php index dba47d81081..7070aff5335 100644 --- a/ui/app/controllers/CControllerTemplateDashboardUpdate.php +++ b/ui/app/controllers/CControllerTemplateDashboardUpdate.php @@ -21,7 +21,9 @@ class CControllerTemplateDashboardUpdate extends CController { - private $dashboard_pages; + private ?array $db_dashboard = null; + + private ?array $dashboard_pages = null; protected function init() { $this->setPostContentType(self::POST_CONTENT_TYPE_JSON); @@ -71,83 +73,121 @@ class CControllerTemplateDashboardUpdate extends CController { } if ($this->hasInput('dashboardid')) { - return (bool) API::TemplateDashboard()->get([ - 'output' => [], - 'dashboardids' => [$this->getInput('dashboardid')], - 'templateids' => [$this->getInput('templateid')], + $db_dashboards = API::TemplateDashboard()->get([ + 'output' => ['dashboardid'], + 'selectPages' => ['widgets'], + 'dashboardids' => $this->getInput('dashboardid'), + 'templateids' => $this->getInput('templateid'), 'editable' => true ]); + + if (!$db_dashboards) { + return false; + } + + $this->db_dashboard = $db_dashboards[0]; + + return true; } else { - return isWritableHostTemplates((array) $this->getInput('templateid')); + return isWritableHostTemplates([$this->getInput('templateid')]); } } protected function doAction() { - $save_dashboard = [ - 'name' => $this->getInput('name'), - 'display_period' => $this->getInput('display_period'), - 'auto_start' => $this->getInput('auto_start'), - 'pages' => [] - ]; + $output = []; - if ($this->hasInput('dashboardid')) { - $save_dashboard['dashboardid'] = $this->getInput('dashboardid'); - } - else { - $save_dashboard['templateid'] = $this->getInput('templateid'); - } + try { + $db_widgets = []; + + if ($this->db_dashboard !== null) { + foreach ($this->db_dashboard['pages'] as $db_dashboard_page) { + foreach ($db_dashboard_page['widgets'] as $db_widget) { + $db_widgets[$db_widget['widgetid']] = $db_widget; + } + } + } - foreach ($this->dashboard_pages as $dashboard_page) { - $save_dashboard_page = [ - 'name' => $dashboard_page['name'], - 'display_period' => $dashboard_page['display_period'], - 'widgets' => [] + $save_dashboard = [ + 'name' => $this->getInput('name'), + 'display_period' => $this->getInput('display_period'), + 'auto_start' => $this->getInput('auto_start'), + 'pages' => [] ]; - if (array_key_exists('dashboard_pageid', $dashboard_page)) { - $save_dashboard_page['dashboard_pageid'] = $dashboard_page['dashboard_pageid']; + if ($this->db_dashboard !== null) { + $save_dashboard['dashboardid'] = $this->db_dashboard['dashboardid']; + } + else { + $save_dashboard['templateid'] = $this->getInput('templateid'); } - foreach ($dashboard_page['widgets'] as $widget) { - $save_widget = [ - 'x' => $widget['pos']['x'], - 'y' => $widget['pos']['y'], - 'width' => $widget['pos']['width'], - 'height' => $widget['pos']['height'], - 'type' => $widget['type'], - 'name' => $widget['name'], - 'view_mode' => $widget['view_mode'], - 'fields' => $widget['form']->fieldsToApi() + foreach ($this->dashboard_pages as $dashboard_page) { + $save_dashboard_page = [ + 'name' => $dashboard_page['name'], + 'display_period' => $dashboard_page['display_period'], + 'widgets' => [] ]; - if (array_key_exists('widgetid', $widget)) { - $save_widget['widgetid'] = $widget['widgetid']; + if (array_key_exists('dashboard_pageid', $dashboard_page)) { + $save_dashboard_page['dashboard_pageid'] = $dashboard_page['dashboard_pageid']; } - $save_dashboard_page['widgets'][] = $save_widget; - } - - $save_dashboard['pages'][] = $save_dashboard_page; - } - - if ($this->hasInput('dashboardid')) { - $result = API::TemplateDashboard()->update($save_dashboard); + foreach ($dashboard_page['widgets'] as $widget) { + $save_widget = [ + 'x' => $widget['pos']['x'], + 'y' => $widget['pos']['y'], + 'width' => $widget['pos']['width'], + 'height' => $widget['pos']['height'] + ]; + + if ($widget['type'] !== ZBX_WIDGET_INACCESSIBLE) { + $save_widget += [ + 'type' => $widget['type'], + 'name' => $widget['name'], + 'view_mode' => $widget['view_mode'], + 'fields' => $widget['form']->fieldsToApi() + ]; + } + else { + if (!array_key_exists('widgetid', $widget) + || !array_key_exists($widget['widgetid'], $db_widgets)) { + error(_('No permissions to referred object or it does not exist!')); + + throw new InvalidArgumentException(); + } + + $db_widget = $db_widgets[$widget['widgetid']]; + + $save_widget += [ + 'type' => $db_widget['type'], + 'name' => $db_widget['name'], + 'view_mode' => $db_widget['view_mode'], + 'fields' => $db_widget['fields'] + ]; + } + + if (array_key_exists('widgetid', $widget)) { + $save_widget['widgetid'] = $widget['widgetid']; + } + + $save_dashboard_page['widgets'][] = $save_widget; + } - $success_title = _('Dashboard updated'); - $error_title = _('Failed to update dashboard'); - } - else { - $result = API::TemplateDashboard()->create($save_dashboard); + $save_dashboard['pages'][] = $save_dashboard_page; + } - $success_title = _('Dashboard created'); - $error_title = _('Failed to create dashboard'); - } + $result = $this->db_dashboard !== null + ? API::TemplateDashboard()->update($save_dashboard) + : API::TemplateDashboard()->create($save_dashboard); - $output = []; + if (!$result) { + throw new InvalidArgumentException(); + } - if ($result) { - $output['success']['title'] = $success_title; + $output['success']['title'] = $this->db_dashboard !== null + ? _('Dashboard updated') + : _('Dashboard created'); if ($messages = get_and_clear_messages()) { $output['success']['messages'] = array_column($messages, 'message'); @@ -155,9 +195,11 @@ class CControllerTemplateDashboardUpdate extends CController { $output['dashboardid'] = $result['dashboardids'][0]; } - else { + catch (InvalidArgumentException $e) { $output['error'] = [ - 'title' => $error_title, + 'title' => $this->db_dashboard !== null && !$this->hasInput('clone') + ? _('Failed to update dashboard') + : _('Failed to create dashboard'), 'messages' => array_column(get_and_clear_messages(), 'message') ]; } diff --git a/ui/app/controllers/CControllerUserEdit.php b/ui/app/controllers/CControllerUserEdit.php index 8d1c892cb38..d4938c53669 100644 --- a/ui/app/controllers/CControllerUserEdit.php +++ b/ui/app/controllers/CControllerUserEdit.php @@ -113,6 +113,7 @@ class CControllerUserEdit extends CControllerUserEditGeneral { 'new_media' => [], 'roleid' => '', 'role' => [], + 'modules_rules' => [], 'user_type' => '', 'sid' => $this->getUserSID(), 'form_refresh' => 0, @@ -175,7 +176,7 @@ class CControllerUserEdit extends CControllerUserEditGeneral { $roles = API::Role()->get([ 'output' => ['name', 'type'], 'selectRules' => ['services.read.mode', 'services.read.list', 'services.read.tag', - 'services.write.mode', 'services.write.list', 'services.write.tag' + 'services.write.mode', 'services.write.list', 'services.write.tag', 'modules' ], 'roleids' => $data['roleid'] ]); @@ -217,6 +218,10 @@ class CControllerUserEdit extends CControllerUserEditGeneral { 'serviceids' => array_column($role['rules']['services.write.list'], 'serviceid') ]); $data['service_write_tag'] = $role['rules']['services.write.tag']; + + foreach ($role['rules']['modules'] as $rule) { + $data['modules_rules'][$rule['moduleid']] = $rule['status']; + } } } @@ -241,12 +246,34 @@ class CControllerUserEdit extends CControllerUserEditGeneral { $data['templategroups_rights'] = collapseGroupRights(getTemplateGroupsRights($user_groups)); } - $data['modules'] = API::Module()->get([ - 'output' => ['id'], - 'filter' => ['status' => MODULE_STATUS_ENABLED], - 'preservekeys' => true + $data['modules'] = []; + + $db_modules = API::Module()->get([ + 'output' => ['moduleid', 'relative_path', 'status'] ]); + if ($db_modules) { + $module_manager = new CModuleManager(APP::getRootDir()); + + foreach ($db_modules as $db_module) { + $manifest = $module_manager->addModule($db_module['relative_path']); + + if ($manifest !== null) { + $data['modules'][$db_module['moduleid']] = $manifest['name']; + } + } + } + + natcasesort($data['modules']); + + $disabled_modules = array_filter($db_modules, + static function(array $db_module): bool { + return $db_module['status'] == MODULE_STATUS_DISABLED; + } + ); + + $data['disabled_moduleids'] = array_column($disabled_modules, 'moduleid', 'moduleid'); + $data['mediatypes'] = API::MediaType()->get([ 'output' => ['status'], 'preservekeys' => true diff --git a/ui/app/controllers/CControllerUserroleEdit.php b/ui/app/controllers/CControllerUserroleEdit.php index f18e80d3c09..bc4f96d72f3 100644 --- a/ui/app/controllers/CControllerUserroleEdit.php +++ b/ui/app/controllers/CControllerUserroleEdit.php @@ -180,7 +180,19 @@ class CControllerUserroleEdit extends CControllerUserroleEditGeneral { ]; } - $data['labels'] = $this->getLabels(); + $db_modules = API::Module()->get([ + 'output' => ['moduleid', 'relative_path', 'status'] + ]); + + $disabled_modules = array_filter($db_modules, + static function(array $db_module): bool { + return $db_module['status'] == MODULE_STATUS_DISABLED; + } + ); + + $data['disabled_moduleids'] = array_column($disabled_modules, 'moduleid', 'moduleid'); + + $data['labels'] = $this->getLabels($db_modules); $data['rules']['service_read_list'] = API::Service()->get([ 'output' => ['serviceid', 'name'], @@ -291,10 +303,7 @@ class CControllerUserroleEdit extends CControllerUserroleEditGeneral { return $data; } - /** - * @throws APIException - */ - private function getLabels(): array { + private function getLabels(array $db_modules): array { $labels = [ 'sections' => CRoleHelper::getUiSectionsLabels(USER_TYPE_SUPER_ADMIN), 'actions' => CRoleHelper::getActionsLabels(USER_TYPE_SUPER_ADMIN) @@ -304,23 +313,21 @@ class CControllerUserroleEdit extends CControllerUserroleEditGeneral { $labels['rules'][$section] = CRoleHelper::getUiSectionRulesLabels($section, USER_TYPE_SUPER_ADMIN); } - $db_modules = API::Module()->get([ - 'output' => ['moduleid', 'relative_path'], - 'filter' => [ - 'status' => MODULE_STATUS_ENABLED - ] - ]); + $labels['modules'] = []; if ($db_modules) { - $module_manager = new CModuleManager(APP::ModuleManager()->getModulesDir()); - foreach ($db_modules as $module) { - $manifest = $module_manager->addModule($module['relative_path']); - $labels['modules'][$module['moduleid']] = $manifest['name']; + $module_manager = new CModuleManager(APP::getRootDir()); + + foreach ($db_modules as $db_module) { + $manifest = $module_manager->addModule($db_module['relative_path']); + + if ($manifest !== null) { + $labels['modules'][$db_module['moduleid']] = $manifest['name']; + } } } - else { - $labels['modules'] = []; - } + + natcasesort($labels['modules']); return $labels; } diff --git a/ui/app/controllers/CControllerUserroleEditGeneral.php b/ui/app/controllers/CControllerUserroleEditGeneral.php index 5abbc45d05d..e5a5a9479f1 100644 --- a/ui/app/controllers/CControllerUserroleEditGeneral.php +++ b/ui/app/controllers/CControllerUserroleEditGeneral.php @@ -97,10 +97,8 @@ abstract class CControllerUserroleEditGeneral extends CController { */ private function getModuleSectionRules(): array { $db_modules = API::Module()->get([ - 'output' => ['moduleid'], - 'filter' => [ - 'status' => MODULE_STATUS_ENABLED - ] + 'output' => [], + 'preservekeys' => true ]); $modules = $this->getInput('modules', []); @@ -113,7 +111,7 @@ abstract class CControllerUserroleEditGeneral extends CController { 'status' => $modules[$moduleid] ]; }, - array_column($db_modules, 'moduleid') + array_keys($db_modules) ), 'modules.default_access' => $this->getInput('modules_default_access') ]; diff --git a/ui/app/controllers/CControllerWidget.php b/ui/app/controllers/CControllerWidget.php deleted file mode 100644 index 2c9404ed442..00000000000 --- a/ui/app/controllers/CControllerWidget.php +++ /dev/null @@ -1,148 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Class containing methods for operations with widgets. - */ -abstract class CControllerWidget extends CController { - - /** - * @var int $type Widget type WIDGET_*. - */ - private $type; - - /** - * @var array $validation_rules Validation rules for input parameters. - */ - private $validation_rules = []; - - /** - * @var object $form CWidgetForm object. - */ - private $form; - - /** - * Initialization function. - */ - protected function init() { - $this->setPostContentType(self::POST_CONTENT_TYPE_JSON); - } - - /** - * Check user permissions. - * - * @return bool - */ - protected function checkPermissions() { - return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); - } - - /** - * Set widget type. - * - * @param int $type Widget type WIDGET_*. - * - * @return object - */ - protected function setType($type) { - $this->type = $type; - - return $this; - } - - protected function getContext(): string { - return $this->hasInput('templateid') - ? CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - : CWidgetConfig::CONTEXT_DASHBOARD; - } - - /** - * Set validation rules for input parameters. - * - * @param array $validation_rules Validation rules for input parameters. - * - * @return object - */ - protected function setValidationRules(array $validation_rules) { - $this->validation_rules = $validation_rules; - - return $this; - } - - /** - * Returns default widget name. - * - * @return string - */ - protected function getDefaultName() { - return CWidgetConfig::getKnownWidgetTypes($this->getContext())[$this->type]; - } - - /** - * Validate input parameters. - * - * @return bool - */ - protected function checkInput() { - $validation_rules = $this->validation_rules; - - if (CWidgetConfig::isWidgetTypeSupportedInContext($this->type, CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD)) { - $validation_rules['templateid'] = 'db dashboard.templateid'; - } - - $ret = $this->validateInput($validation_rules); - - if ($ret) { - $this->form = CWidgetConfig::getForm($this->type, $this->getInput('fields', '{}'), - $this->hasInput('templateid') ? $this->getInput('templateid') : null - ); - - if ($errors = $this->form->validate()) { - foreach ($errors as $error) { - error($error); - } - - $ret = false; - } - } - - if (!$ret) { - $this->setResponse( - (new CControllerResponseData(['main_block' => json_encode([ - 'error' => [ - 'messages' => array_column(get_and_clear_messages(), 'message') - ] - ])]))->disableView() - ); - } - - return $ret; - } - - /** - * Returns form object. - * - * @return object - */ - protected function getForm() { - return $this->form; - } -} diff --git a/ui/app/controllers/CControllerWidgetIterator.php b/ui/app/controllers/CControllerWidgetIterator.php index 5ac5b1169cb..4dde652dd62 100644 --- a/ui/app/controllers/CControllerWidgetIterator.php +++ b/ui/app/controllers/CControllerWidgetIterator.php @@ -22,50 +22,28 @@ /** * Class containing methods for operations with widget iterators. */ -abstract class CControllerWidgetIterator extends CControllerWidget { +abstract class CControllerWidgetIterator extends CControllerDashboardWidgetView { - /** - * @var array $iterator_validation_rules Validation rules for input parameters of the iterator. - */ - private static $iterator_validation_rules = [ - 'page' => 'required|ge 1' - ]; + protected function init(): void { + parent::init(); - public function __construct() { - parent::__construct(); - - $this->setValidationRules(self::$iterator_validation_rules); - } - - /** - * Set validation rules for input parameters. - * - * @param array $validation_rules Validation rules for input parameters. - * - * @return object - */ - protected function setValidationRules(array $validation_rules) { - return parent::setValidationRules(array_merge(self::$iterator_validation_rules, $validation_rules)); + $this->addValidationRules([ + 'page' => 'required|ge 1' + ]); } /** * Get realistic page number for given number of child widgets. - * - * @param int $num_widgets Number of child widgets. - * - * @return int Page number. */ - protected function getIteratorPage($num_widgets) { + protected function getIteratorPage(int $num_widgets): int { return max(1, min((int) $this->getInput('page'), $this->getIteratorPageCount($num_widgets))); } /** * Get number of child widgets to show on a single page. - * - * @return int Number of child widgets. */ - protected function getIteratorPageSize() { - $fields_data = $this->getForm()->getFieldsData(); + protected function getIteratorPageSize(): int { + $fields_data = $this->getForm()->getFieldsValues(); return min($fields_data['rows'] * $fields_data['columns'], floor(DASHBOARD_MAX_COLUMNS * DASHBOARD_WIDGET_MAX_ROWS / DASHBOARD_WIDGET_MIN_ROWS) @@ -74,12 +52,8 @@ abstract class CControllerWidgetIterator extends CControllerWidget { /** * Get number of pages for given number of child widgets. - * - * @param int $num_widgets Number of child widgets. - * - * @return int Number of pages. */ - protected function getIteratorPageCount($num_widgets) { + protected function getIteratorPageCount(int $num_widgets): int { return (floor(max(0, $num_widgets - 1) / $this->getIteratorPageSize()) + 1); } } diff --git a/ui/app/controllers/CControllerWidgetProblemsBySvView.php b/ui/app/controllers/CControllerWidgetProblemsBySvView.php deleted file mode 100644 index 0478bd98a75..00000000000 --- a/ui/app/controllers/CControllerWidgetProblemsBySvView.php +++ /dev/null @@ -1,74 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; - -class CControllerWidgetProblemsBySvView extends CControllerWidget { - - public function __construct() { - parent::__construct(); - - $this->setType(WIDGET_PROBLEMS_BY_SV); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json', - 'initial_load' => 'in 0,1' - ]); - } - - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - - $filter = [ - 'groupids' => getSubGroups($fields['groupids']), - 'exclude_groupids' => getSubGroups($fields['exclude_groupids']), - 'hostids' => $fields['hostids'], - 'problem' => $fields['problem'], - 'severities' => $fields['severities'], - 'show_type' => $fields['show_type'], - 'layout' => $fields['layout'], - 'show_suppressed' => $fields['show_suppressed'], - 'hide_empty_groups' => $fields['hide_empty_groups'], - 'show_opdata' => $fields['show_opdata'], - 'ext_ack' => $fields['ext_ack'], - 'show_timeline' => $fields['show_timeline'], - 'evaltype' => $fields['evaltype'], - 'tags' => $fields['tags'] - ]; - - $data = getSystemStatusData($filter); - - if ($filter['show_type'] == WIDGET_PROBLEMS_BY_SV_SHOW_TOTALS) { - $data['groups'] = getSystemStatusTotals($data); - } - - $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), - 'initial_load' => (bool) $this->getInput('initial_load', 0), - 'data' => $data, - 'filter' => $filter, - 'user' => [ - 'debug_mode' => $this->getDebugMode() - ], - 'allowed' => $data['allowed'] - ])); - } -} diff --git a/ui/app/controllers/CControllerWidgetSvgGraphView.php b/ui/app/controllers/CControllerWidgetSvgGraphView.php deleted file mode 100644 index 50913d4110a..00000000000 --- a/ui/app/controllers/CControllerWidgetSvgGraphView.php +++ /dev/null @@ -1,183 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; - -class CControllerWidgetSvgGraphView extends CControllerWidget { - - const GRAPH_WIDTH_MIN = 1; - const GRAPH_WIDTH_MAX = 65535; - const GRAPH_HEIGHT_MIN = 1; - const GRAPH_HEIGHT_MAX = 65535; - - public function __construct() { - parent::__construct(); - - $this->setType(WIDGET_SVG_GRAPH); - $this->setValidationRules([ - 'name' => 'string', - 'edit_mode' => 'in 0,1', - 'content_width' => 'int32|ge '.self::GRAPH_WIDTH_MIN.'|le '.self::GRAPH_WIDTH_MAX, - 'content_height' => 'int32|ge '.self::GRAPH_HEIGHT_MIN.'|le '.self::GRAPH_HEIGHT_MAX, - 'preview' => 'in 1', - 'from' => 'string', - 'to' => 'string', - 'fields' => 'json' - ]); - } - - protected function doAction(): void { - $fields = $this->getForm()->getFieldsData(); - $edit_mode = $this->getInput('edit_mode', 0); - $width = (int) $this->getInput('content_width', self::GRAPH_WIDTH_MIN); - $height = (int) $this->getInput('content_height', self::GRAPH_HEIGHT_MIN); - $preview = (bool) $this->getInput('preview', 0); // Configuration preview. - - $dashboard_time = !CWidgetFormSvgGraph::hasOverrideTime($fields); - - if ($dashboard_time && !$preview) { - $from = $this->getInput('from'); - $to = $this->getInput('to'); - } - else { - $from = $fields['time_from']; - $to = $fields['time_to']; - } - - $range_time_parser = new CRangeTimeParser(); - - $range_time_parser->parse($from); - $time_from = $range_time_parser->getDateTime(true)->getTimestamp(); - - $range_time_parser->parse($to); - $time_to = $range_time_parser->getDateTime(false)->getTimestamp(); - - $parser = new CNumberParser(['with_size_suffix' => true, 'with_time_suffix' => true]); - - $percentile_left_value = $parser->parse($fields['percentile_left_value']) == CParser::PARSE_SUCCESS - ? $parser->calcValue() - : null; - - $percentile_right_value = $parser->parse($fields['percentile_right_value']) == CParser::PARSE_SUCCESS - ? $parser->calcValue() - : null; - - $lefty_min = $parser->parse($fields['lefty_min']) == CParser::PARSE_SUCCESS ? $parser->calcValue() : null; - $lefty_max = $parser->parse($fields['lefty_max']) == CParser::PARSE_SUCCESS ? $parser->calcValue() : null; - $righty_min = $parser->parse($fields['righty_min']) == CParser::PARSE_SUCCESS ? $parser->calcValue() : null; - $righty_max = $parser->parse($fields['righty_max']) == CParser::PARSE_SUCCESS ? $parser->calcValue() : null; - - $graph_data = [ - 'data_sets' => array_values($fields['ds']), - 'data_source' => $fields['source'], - 'dashboard_time' => $dashboard_time, - 'displaying' => [ - 'show_simple_triggers' => $fields['simple_triggers'] == SVG_GRAPH_SIMPLE_TRIGGERS_ON, - 'show_working_time' => $fields['working_time'] == SVG_GRAPH_WORKING_TIME_ON, - 'show_percentile_left' => $fields['percentile_left'] == SVG_GRAPH_PERCENTILE_LEFT_ON, - 'percentile_left_value' => $percentile_left_value, - 'show_percentile_right' => $fields['percentile_right'] == SVG_GRAPH_PERCENTILE_RIGHT_ON, - 'percentile_right_value' => $percentile_right_value - ], - 'time_period' => [ - 'time_from' => $time_from, - 'time_to' => $time_to - ], - 'axes' => [ - 'show_left_y_axis' => $fields['lefty'] == SVG_GRAPH_AXIS_SHOW, - 'left_y_min' => $lefty_min, - 'left_y_max' => $lefty_max, - 'left_y_units' => $fields['lefty_units'] == SVG_GRAPH_AXIS_UNITS_STATIC - ? $fields['lefty_static_units'] - : null, - 'show_right_y_axis' => $fields['righty'] == SVG_GRAPH_AXIS_SHOW, - 'right_y_min' => $righty_min, - 'right_y_max' => $righty_max, - 'right_y_units' => $fields['righty_units'] == SVG_GRAPH_AXIS_UNITS_STATIC - ? $fields['righty_static_units'] - : null, - 'show_x_axis' => $fields['axisx'] == SVG_GRAPH_AXIS_SHOW - ], - 'legend' => [ - 'show_legend' => $fields['legend'] == SVG_GRAPH_LEGEND_ON, - 'legend_columns' => $fields['legend_columns'], - 'legend_lines' => $fields['legend_lines'], - 'legend_statistic' => $fields['legend_statistic'] - ], - 'problems' => [ - 'show_problems' => $fields['show_problems'] == SVG_GRAPH_PROBLEMS_SHOW, - 'graph_item_problems' => $fields['graph_item_problems'] == SVG_GRAPH_SELECTED_ITEM_PROBLEMS, - 'problemhosts' => $fields['problemhosts'], - 'severities' => $fields['severities'], - 'problem_name' => $fields['problem_name'], - 'evaltype' => $fields['evaltype'], - 'tags' => $fields['tags'] - ], - 'overrides' => array_values($fields['or']) - ]; - - $svg_options = CSvgGraphHelper::get($graph_data, $width, $height); - if ($svg_options['errors']) { - error($svg_options['errors']); - } - - if (!$preview) { - $svg_options['data'] = zbx_array_merge($svg_options['data'], [ - 'sbox' => $graph_data['dashboard_time'] && !$edit_mode, - 'show_problems' => $graph_data['problems']['show_problems'], - 'show_simple_triggers' => $graph_data['displaying']['show_simple_triggers'], - 'time_from' => $graph_data['time_period']['time_from'], - 'hint_max_rows' => ZBX_WIDGET_ROWS - ]); - } - - $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), - 'svg' => $svg_options['svg'].$svg_options['legend'], - 'svg_options' => $svg_options, - 'preview' => $preview, - 'info' => self::makeWidgetInfo($fields), - 'user' => [ - 'debug_mode' => $this->getDebugMode() - ] - ])); - } - - /** - * Make widget specific info to show in widget's header. - * - * @param array $fields - * - * @return array - */ - private static function makeWidgetInfo(array $fields) { - $info = []; - - if (CWidgetFormSvgGraph::hasOverrideTime($fields)) { - $info[] = [ - 'icon' => 'btn-info-clock', - 'hint' => relativeDateToText($fields['time_from'], $fields['time_to']) - ]; - } - - return $info; - } -} diff --git a/ui/app/controllers/CControllerWidgetTrigOverView.php b/ui/app/controllers/CControllerWidgetTrigOverView.php deleted file mode 100644 index bd2a6590536..00000000000 --- a/ui/app/controllers/CControllerWidgetTrigOverView.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CControllerWidgetTrigOverView extends CControllerWidget { - - public function __construct() { - parent::__construct(); - - $this->setType(WIDGET_TRIG_OVER); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json', - 'initial_load' => 'in 0,1' - ]); - } - - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - - $data = [ - 'name' => $this->getInput('name', $this->getDefaultName()), - 'initial_load' => (bool) $this->getInput('initial_load', 0), - 'style' => $fields['style'], - 'user' => [ - 'debug_mode' => $this->getDebugMode() - ] - ]; - - $trigger_options = [ - 'skipDependent' => ($fields['show'] == TRIGGERS_OPTION_ALL) ? null : true, - 'only_true' => ($fields['show'] == TRIGGERS_OPTION_RECENT_PROBLEM) ? true : null, - 'filter' => [ - 'value' => ($fields['show'] == TRIGGERS_OPTION_IN_PROBLEM) ? TRIGGER_VALUE_TRUE : null - ] - ]; - - $problem_options = [ - 'show_suppressed' => $fields['show_suppressed'], - 'show_recent' => ($fields['show'] == TRIGGERS_OPTION_RECENT_PROBLEM) ? true : null, - 'tags' => (array_key_exists('tags', $fields) && $fields['tags']) ? $fields['tags'] : null, - 'evaltype' => array_key_exists('evaltype', $fields) ? $fields['evaltype'] : TAG_EVAL_TYPE_AND_OR - ]; - - $host_options = [ - 'hostids' => $fields['hostids'] ? $fields['hostids'] : null - ]; - - [$data['db_hosts'], $data['db_triggers'], $data['dependencies'], $data['triggers_by_name'], - $data['hosts_by_name'], $data['exceeded_limit'] - ] = getTriggersOverviewData(getSubGroups($fields['groupids']), $host_options, $trigger_options, $problem_options - ); - - $this->setResponse(new CControllerResponseData($data)); - } -} diff --git a/ui/app/partials/configuration.hostgroup.edit.html.php b/ui/app/partials/configuration.hostgroup.edit.html.php index a2f87f6e3b7..c74febd3b3d 100644 --- a/ui/app/partials/configuration.hostgroup.edit.html.php +++ b/ui/app/partials/configuration.hostgroup.edit.html.php @@ -27,7 +27,7 @@ $form = (new CForm()) ->setId('hostgroupForm') ->setName('hostgroupForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('groupid', $data['groupid']) ->addItem((new CInput('submit', null))->addStyle('display: none;')); diff --git a/ui/app/partials/configuration.templategroup.edit.html.php b/ui/app/partials/configuration.templategroup.edit.html.php index fb51ba8ae3a..105b525f78d 100644 --- a/ui/app/partials/configuration.templategroup.edit.html.php +++ b/ui/app/partials/configuration.templategroup.edit.html.php @@ -27,7 +27,7 @@ $form = (new CForm()) ->setId('templategroupForm') ->setName('templategroupForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('groupid', $data['groupid']) ->addItem((new CInput('submit'))->addStyle('display: none;')); diff --git a/ui/app/partials/layout.htmlpage.header.php b/ui/app/partials/layout.htmlpage.header.php index 5a343ccc248..fd124e61b49 100644 --- a/ui/app/partials/layout.htmlpage.header.php +++ b/ui/app/partials/layout.htmlpage.header.php @@ -26,7 +26,6 @@ global $DB, $ZBX_SERVER_NAME; -$theme = ZBX_DEFAULT_THEME; $scripts = $data['javascript']['files']; $page_title = $data['page']['title']; @@ -34,12 +33,11 @@ if (isset($ZBX_SERVER_NAME) && $ZBX_SERVER_NAME !== '') { $page_title = $ZBX_SERVER_NAME.NAME_DELIMITER.$page_title; } -$pageHeader = new CPageHeader($page_title, CWebUser::getLang()); +$page_header = new CHtmlPageHeader($page_title, CWebUser::getLang()); if (!empty($DB['DB'])) { - $theme = getUserTheme($data['user']); - - $pageHeader + $page_header + ->setTheme(getUserTheme($data['user'])) ->addStyle(getTriggerSeverityCss()) ->addStyle(getTriggerStatusCss()); @@ -50,16 +48,28 @@ if (!empty($DB['DB'])) { } // Show GUI messages in pages with menus and in kiosk mode. -$show_gui_messaging = (!defined('ZBX_PAGE_NO_MENU') || $data['web_layout_mode'] == ZBX_LAYOUT_KIOSKMODE) - ? intval(!CWebUser::isGuest()) +$show_gui_messaging = !defined('ZBX_PAGE_NO_MENU') || $data['web_layout_mode'] == ZBX_LAYOUT_KIOSKMODE + ? (int)!CWebUser::isGuest() : null; -$pageHeader - ->addCssFile('assets/styles/'.CHtml::encode($theme).'.css') - ->addJsBeforeScripts( - 'var PHP_TZ_OFFSET = '.date('Z').','. - 'PHP_ZBX_FULL_DATE_TIME = "'.ZBX_FULL_DATE_TIME.'";' - ) +$modules_assets = APP::ModuleManager()->getAssets(); + +$page_header->addCssFile('assets/styles/'.$page_header->getTheme().'.css'); + +foreach ($modules_assets as $module_id => $assets) { + $module = APP::ModuleManager()->getModule($module_id); + $relative_path = $module->getRelativePath().'/assets/css'; + + foreach ($assets['css'] as $css_file) { + $page_header->addCssFile((new CUrl($relative_path.'/'.$css_file))->getUrl()); + } +} + +$page_header + ->addJavaScript(' + const PHP_TZ_OFFSET = '.date('Z').'; + const PHP_ZBX_FULL_DATE_TIME = "'.ZBX_FULL_DATE_TIME.'"; + ') ->addJsFile((new CUrl('js/browsers.js'))->getUrl()) ->addJsFile((new CUrl('jsLoader.php')) ->setArgument('lang', $data['user']['lang']) @@ -69,18 +79,35 @@ $pageHeader ); foreach ($data['stylesheet']['files'] as $css_file) { - $pageHeader->addCssFile($css_file); + $page_header->addCssFile($css_file); } if ($scripts) { - $pageHeader->addJsFile((new CUrl('jsLoader.php')) - ->setArgument('ver', ZABBIX_VERSION) - ->setArgument('lang', $data['user']['lang']) - ->setArgument('files', $scripts) - ->getUrl() + $page_header->addJsFile( + (new CUrl('jsLoader.php')) + ->setArgument('ver', ZABBIX_VERSION) + ->setArgument('lang', $data['user']['lang']) + ->setArgument('files', $scripts) + ->getUrl() ); + + $page_header->addJavaScript('if (locale === undefined) { var locale = {}; }'); + + foreach ($modules_assets as $module_id => $assets) { + $module = APP::ModuleManager()->getModule($module_id); + $relative_path = $module->getRelativePath().'/assets/js'; + $translation_strings = $module->getTranslationStrings(); + + foreach ($assets['js'] as $js_file) { + $page_header->addJsFile((new CUrl($relative_path.'/'.$js_file))->getUrl()); + + if (array_key_exists($js_file, $translation_strings)) { + $page_header->addJsTranslationStrings($translation_strings[$js_file]); + } + } + } } -$pageHeader->display(); +$page_header->show(); echo '<body>'; diff --git a/ui/app/partials/monitoring.host.filter.php b/ui/app/partials/monitoring.host.filter.php index 9395bcb62da..abf6c43f0bc 100644 --- a/ui/app/partials/monitoring.host.filter.php +++ b/ui/app/partials/monitoring.host.filter.php @@ -178,12 +178,12 @@ if (array_key_exists('render_html', $data)) { return; } -(new CScriptTemplate('filter-monitoring-hosts')) +(new CTemplateTag('filter-monitoring-hosts')) ->setAttribute('data-template', 'monitoring.host.filter') ->addItem($template) ->show(); -(new CScriptTemplate('filter-tag-row-tmpl')) +(new CTemplateTag('filter-tag-row-tmpl')) ->addItem( (new CRow([ (new CTextBox('tags[#{rowNum}][tag]', '#{tag}')) diff --git a/ui/app/partials/monitoring.latest.filter.php b/ui/app/partials/monitoring.latest.filter.php index e411a032f8b..370dcd4ec2c 100644 --- a/ui/app/partials/monitoring.latest.filter.php +++ b/ui/app/partials/monitoring.latest.filter.php @@ -220,12 +220,12 @@ if (array_key_exists('render_html', $data)) { return; } -(new CScriptTemplate('filter-monitoring-latest')) +(new CTemplateTag('filter-monitoring-latest')) ->setAttribute('data-template', 'monitoring.latest.filter') ->addItem($template) ->show(); -(new CScriptTemplate('filter-tag-row-tmpl')) +(new CTemplateTag('filter-tag-row-tmpl')) ->addItem( (new CRow([ (new CTextBox('tags[#{rowNum}][tag]', '#{tag}')) diff --git a/ui/app/partials/monitoring.problem.filter.php b/ui/app/partials/monitoring.problem.filter.php index fd5c3bdece8..1c9d69605ec 100644 --- a/ui/app/partials/monitoring.problem.filter.php +++ b/ui/app/partials/monitoring.problem.filter.php @@ -268,7 +268,7 @@ $right_column = (new CFormList()) (new CDiv([ (new CLabel(_('Show timeline'), 'show_timeline_#{uniqid}'))->addClass(ZBX_STYLE_SECOND_COLUMN_LABEL), (new CCheckBox('show_timeline')) - ->setChecked($data['show_timeline'] == 1) + ->setChecked($data['show_timeline'] == ZBX_TIMELINE_ON) ->setEnabled($data['compact_view'] == 0) ->setUncheckedValue(0) ->setId('show_timeline_#{uniqid}') @@ -323,12 +323,12 @@ if (array_key_exists('render_html', $data)) { return; } -(new CScriptTemplate('filter-monitoring-problem')) +(new CTemplateTag('filter-monitoring-problem')) ->setAttribute('data-template', 'monitoring.problem.filter') ->addItem($template) ->show(); -(new CScriptTemplate('filter-inventory-row')) +(new CTemplateTag('filter-inventory-row')) ->addItem( (new CRow([ (new CSelect('inventory[#{rowNum}][field]')) @@ -346,7 +346,7 @@ if (array_key_exists('render_html', $data)) { ) ->show(); -(new CScriptTemplate('filter-tag-row-tmpl')) +(new CTemplateTag('filter-tag-row-tmpl')) ->addItem( (new CRow([ (new CTextBox('tags[#{rowNum}][tag]', '#{tag}')) diff --git a/ui/app/views/administration.audit.settings.edit.php b/ui/app/views/administration.audit.settings.edit.php index 687a178cf9a..a3839c367a2 100644 --- a/ui/app/views/administration.audit.settings.edit.php +++ b/ui/app/views/administration.audit.settings.edit.php @@ -25,7 +25,7 @@ $this->includeJsFile('administration.audit.settings.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Audit log')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_AUDITLOG_EDIT)); @@ -36,7 +36,7 @@ $form = (new CForm()) ->setArgument('action', 'audit.settings.update') ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); $audit_settings_tab = (new CFormGrid()) ->addItem([ @@ -66,6 +66,6 @@ $form->addItem( )) ); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/administration.authentication.edit.php b/ui/app/views/administration.authentication.edit.php index fa4966f40cc..b8261f12705 100644 --- a/ui/app/views/administration.authentication.edit.php +++ b/ui/app/views/administration.authentication.edit.php @@ -335,14 +335,14 @@ $saml_tab = (new CFormGrid()) ) ]); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Authentication')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::USERS_AUTHENTICATION_EDIT)) ->addItem((new CForm()) ->addVar('action', $data['action_submit']) ->addVar('ldap_removed_userdirectoryids', $data['ldap_removed_userdirectoryids']) ->setId('authentication-form') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->disablePasswordAutofill() ->addItem((new CTabView()) ->setSelected($data['form_refresh'] ? null : 0) @@ -358,7 +358,7 @@ $saml_tab = (new CFormGrid()) ->show(); (new CScriptTag( - 'view.init('. json_encode([ + 'view.init('.json_encode([ 'ldap_servers' => $data['ldap_servers'], 'ldap_default_row_index' => $data['ldap_default_row_index'], 'db_authentication_type' => $data['db_authentication_type'] diff --git a/ui/app/views/administration.autoreg.edit.php b/ui/app/views/administration.autoreg.edit.php index 8d4d1563356..dcf0fa249e2 100644 --- a/ui/app/views/administration.autoreg.edit.php +++ b/ui/app/views/administration.autoreg.edit.php @@ -25,7 +25,7 @@ $this->includeJsFile('administration.autoreg.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Autoregistration')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_AUTOREG_EDIT)); @@ -37,7 +37,7 @@ $autoreg_form = (new CForm()) ->setArgument('action', 'autoreg.edit') ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('tls_accept', $data['tls_accept']); $autoreg_tab = (new CFormList()) @@ -92,6 +92,6 @@ $autoreg_view = (new CTabView()) $autoreg_form->addItem($autoreg_view); -$widget +$html_page ->addItem($autoreg_form) ->show(); diff --git a/ui/app/views/administration.geomaps.edit.php b/ui/app/views/administration.geomaps.edit.php index 458040020e4..aefa0dde59e 100644 --- a/ui/app/views/administration.geomaps.edit.php +++ b/ui/app/views/administration.geomaps.edit.php @@ -114,7 +114,7 @@ $form = (new CForm()) ->setArgument('action', 'geomaps.update') ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addItem( (new CTabView()) ->addTab('geomaps_tab', _('Geographical maps'), $form_grid) @@ -123,7 +123,7 @@ $form = (new CForm()) )) ); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Geographical maps')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_GEOMAPS_EDIT)) @@ -131,7 +131,7 @@ $form = (new CForm()) ->show(); (new CScriptTag( - 'view.init('. json_encode([ + 'view.init('.json_encode([ 'tile_providers' => $data['tile_providers'] ]).');' )) diff --git a/ui/app/views/administration.gui.edit.php b/ui/app/views/administration.gui.edit.php index e0f9dc6e495..8a53e919ee0 100644 --- a/ui/app/views/administration.gui.edit.php +++ b/ui/app/views/administration.gui.edit.php @@ -25,7 +25,7 @@ $this->includeJsFile('administration.gui.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('GUI')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_GUI_EDIT)); @@ -149,13 +149,13 @@ $gui_view = (new CTabView()) )); $form = (new CForm()) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->setAction((new CUrl('zabbix.php')) ->setArgument('action', 'gui.update') ->getUrl() ) ->addItem($gui_view); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/administration.housekeeping.edit.php b/ui/app/views/administration.housekeeping.edit.php index 12dcf91afab..0fc45fc2462 100644 --- a/ui/app/views/administration.housekeeping.edit.php +++ b/ui/app/views/administration.housekeeping.edit.php @@ -25,7 +25,7 @@ $this->includeJsFile('administration.housekeeping.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Housekeeping')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_HOUSEKEEPING_EDIT)); @@ -35,7 +35,7 @@ $form = (new CForm()) ->setArgument('action', 'housekeeping.update') ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); $house_keeper_tab = (new CFormList()) ->addRow((new CTag('h4', true, _('Events and alerts')))->addClass('input-section-header')) @@ -267,6 +267,6 @@ $form->addItem( )) ); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/administration.iconmap.edit.php b/ui/app/views/administration.iconmap.edit.php index a629a7fbe42..9ca537f5552 100644 --- a/ui/app/views/administration.iconmap.edit.php +++ b/ui/app/views/administration.iconmap.edit.php @@ -25,7 +25,7 @@ $this->includeJsFile('administration.iconmap.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Icon mapping')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_ICONMAP_EDIT)); @@ -46,7 +46,7 @@ $form = (new CForm()) ->setArgument('action', ($data['iconmapid'] != 0) ? 'iconmap.update' : 'iconmap.create') ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', 1); if ($data['iconmapid'] != 0) { @@ -162,4 +162,4 @@ else { $form->addItem($tab); -$widget->addItem($form)->show(); +$html_page->addItem($form)->show(); diff --git a/ui/app/views/administration.iconmap.list.php b/ui/app/views/administration.iconmap.list.php index f3aca4fac78..69d978214c7 100644 --- a/ui/app/views/administration.iconmap.list.php +++ b/ui/app/views/administration.iconmap.list.php @@ -23,7 +23,7 @@ * @var CView $this */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Icon mapping')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_ICONMAP_LIST)) @@ -52,4 +52,4 @@ foreach ($data['iconmaps'] as $icon_map) { ), $row]); } -$widget->addItem($table)->show(); +$html_page->addItem($table)->show(); diff --git a/ui/app/views/administration.image.edit.php b/ui/app/views/administration.image.edit.php index 25da1e73c7d..c3c2ba5bd7e 100644 --- a/ui/app/views/administration.image.edit.php +++ b/ui/app/views/administration.image.edit.php @@ -25,7 +25,7 @@ $this->includeJsFile('administration.image.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Images')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_IMAGE_EDIT)); @@ -34,7 +34,7 @@ $form = (new CForm('post', (new CUrl('zabbix.php')) ->setArgument('action', ($data['imageid'] == 0) ? 'image.create' : 'image.update') ->getUrl(), 'multipart/form-data') ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('imagetype', $data['imagetype']); if ($data['imageid'] != 0) { @@ -103,4 +103,4 @@ else { )); } -$widget->addItem($form->addItem($tab_view))->show(); +$html_page->addItem($form->addItem($tab_view))->show(); diff --git a/ui/app/views/administration.image.list.php b/ui/app/views/administration.image.list.php index 742da721d01..de68260aa3c 100644 --- a/ui/app/views/administration.image.list.php +++ b/ui/app/views/administration.image.list.php @@ -26,7 +26,7 @@ $this->includeJsFile('administration.image.list.js.php'); $page_url = (new CUrl('zabbix.php'))->setArgument('action', 'image.list'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Images')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_IMAGE_LIST)) @@ -72,7 +72,7 @@ $widget = (new CWidget()) ); if (!$data['images']) { - $widget->addItem(new CTableInfo()); + $html_page->addItem(new CTableInfo()); } else { $image_table = (new CDiv()) @@ -113,14 +113,14 @@ else { $image_table->addItem($image_row); } - $widget->addItem( + $html_page->addItem( (new CForm())->addItem( (new CTabView())->addTab('image', null, $image_table) ) ); } -$widget->show(); +$html_page->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/app/views/administration.macros.edit.php b/ui/app/views/administration.macros.edit.php index 5b32bcf530c..00136237c58 100644 --- a/ui/app/views/administration.macros.edit.php +++ b/ui/app/views/administration.macros.edit.php @@ -25,7 +25,7 @@ $this->includeJsFile('administration.macros.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Macros')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_MACROS_EDIT)); @@ -103,9 +103,9 @@ $form = (new CForm()) ->setName('macrosForm') ->disablePasswordAutofill() ->setAction((new CUrl('zabbix.php'))->setArgument('action', 'macros.update')->getUrl()) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addItem($tab_view); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/administration.mediatype.edit.php b/ui/app/views/administration.mediatype.edit.php index 560ae0df974..53abc87b13b 100644 --- a/ui/app/views/administration.mediatype.edit.php +++ b/ui/app/views/administration.mediatype.edit.php @@ -28,7 +28,7 @@ $this->addJsFile('multilineinput.js'); $this->includeJsFile('administration.mediatype.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Media types')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ALERTS_MEDIATYPE_EDIT)); @@ -45,7 +45,7 @@ $mediaTypeForm = (new CForm()) ->addVar('mediatypeid', $data['mediatypeid']) ->addItem((new CVar('status', MEDIA_TYPE_STATUS_DISABLED))->removeId()) ->disablePasswordAutofill() - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); // Create form list. $mediatype_formlist = (new CFormList()) @@ -201,7 +201,7 @@ $row_template = (new CTag('script', true)) ]))->addClass('form_row') ); -$widget->addItem($row_template); +$html_page->addItem($row_template); $parameters_table->addRow([(new CButton('parameter_add', _('Add'))) ->addClass(ZBX_STYLE_BTN_LINK) @@ -389,4 +389,4 @@ else { $mediaTypeForm->addItem($tabs); // append form to widget -$widget->addItem($mediaTypeForm)->show(); +$html_page->addItem($mediaTypeForm)->show(); diff --git a/ui/app/views/administration.mediatype.list.php b/ui/app/views/administration.mediatype.list.php index 31deae8e74a..18c59826cd5 100644 --- a/ui/app/views/administration.mediatype.list.php +++ b/ui/app/views/administration.mediatype.list.php @@ -27,7 +27,7 @@ if ($data['uncheck']) { uncheckTableRows('mediatype'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Media types')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ALERTS_MEDIATYPE_LIST)) ->setControls((new CTag('nav', true, @@ -201,4 +201,6 @@ $mediaTypeForm->addItem([ ]); // append form to widget -$widget->addItem($mediaTypeForm)->show(); +$html_page + ->addItem($mediaTypeForm) + ->show(); diff --git a/ui/app/views/administration.miscconfig.edit.php b/ui/app/views/administration.miscconfig.edit.php index d3acc4377fe..5bc136c70f2 100644 --- a/ui/app/views/administration.miscconfig.edit.php +++ b/ui/app/views/administration.miscconfig.edit.php @@ -26,7 +26,7 @@ $this->includeJsFile('administration.miscconfig.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Other configuration parameters')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_MISCCONFIG_EDIT)); @@ -189,7 +189,7 @@ $form = (new CForm()) ->setArgument('action', 'miscconfig.update') ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addItem( (new CTabView()) ->addTab('other', _('Other parameters'), $from_list) @@ -199,7 +199,7 @@ $form = (new CForm()) )) ); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/administration.module.edit.php b/ui/app/views/administration.module.edit.php index 8b6f3394e79..3a094bf0b3f 100644 --- a/ui/app/views/administration.module.edit.php +++ b/ui/app/views/administration.module.edit.php @@ -19,7 +19,12 @@ **/ -$widget = (new CWidget()) +/** + * @var CView $this + * @var array $data + */ + +$html_page = (new CHtmlPage()) ->setTitle(_('Modules')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_MODULE_EDIT)) ->setTitleSubmenu(getAdministrationGeneralSubmenu()); @@ -32,7 +37,7 @@ $form = (new CForm()) ->setArgument('moduleids[]', $data['moduleid']) ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); // create module tab $module_tab = (new CFormList()) @@ -70,6 +75,6 @@ $tabs->setFooter(makeFormFooter( $form->addItem($tabs); // append form to widget -$widget->addItem($form); +$html_page->addItem($form); -$widget->show(); +$html_page->show(); diff --git a/ui/app/views/administration.module.list.php b/ui/app/views/administration.module.list.php index 8dec962295e..66d1671fb72 100644 --- a/ui/app/views/administration.module.list.php +++ b/ui/app/views/administration.module.list.php @@ -19,11 +19,16 @@ **/ +/** + * @var CView $this + * @var array $data + */ + if ($data['uncheck']) { uncheckTableRows('modules'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Modules')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_MODULE_LIST)) @@ -127,6 +132,6 @@ $form->addItem([ ]); // append form to widget -$widget->addItem($form); +$html_page->addItem($form); -$widget->show(); +$html_page->show(); diff --git a/ui/app/views/administration.queue.details.php b/ui/app/views/administration.queue.details.php index ca7401d07b3..efd243912a5 100644 --- a/ui/app/views/administration.queue.details.php +++ b/ui/app/views/administration.queue.details.php @@ -23,7 +23,7 @@ * @var CView $this */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Queue details')) ->setTitleSubmenu([ 'main_section' => [ @@ -75,7 +75,7 @@ if (CWebUser::getRefresh()) { ->show(); } -$widget +$html_page ->addItem($table) ->addItem((new CDiv()) ->addClass(ZBX_STYLE_TABLE_PAGING) diff --git a/ui/app/views/administration.queue.overview.php b/ui/app/views/administration.queue.overview.php index 70f6479f84c..10f70776376 100644 --- a/ui/app/views/administration.queue.overview.php +++ b/ui/app/views/administration.queue.overview.php @@ -23,7 +23,7 @@ * @var CView $this */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Queue overview')) ->setTitleSubmenu([ 'main_section' => [ @@ -87,6 +87,6 @@ if (CWebUser::getRefresh()) { ->show(); } -$widget +$html_page ->addItem($table) ->show(); diff --git a/ui/app/views/administration.queue.overview.proxy.php b/ui/app/views/administration.queue.overview.proxy.php index e0bc7d038cd..0d8d286aa89 100644 --- a/ui/app/views/administration.queue.overview.proxy.php +++ b/ui/app/views/administration.queue.overview.proxy.php @@ -23,7 +23,7 @@ * @var CView $this */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Queue overview by proxy')) ->setTitleSubmenu([ 'main_section' => [ @@ -87,7 +87,7 @@ if (CWebUser::getRefresh()) { ->show(); } -$widget +$html_page ->addItem($table) ->addItem((new CDiv()) ->addClass(ZBX_STYLE_TABLE_PAGING) diff --git a/ui/app/views/administration.regex.edit.php b/ui/app/views/administration.regex.edit.php index 74bb5612be7..b00a9b5b942 100644 --- a/ui/app/views/administration.regex.edit.php +++ b/ui/app/views/administration.regex.edit.php @@ -25,7 +25,7 @@ $this->includeJsFile('administration.regex.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Regular expressions')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_REGEX_EDIT)); @@ -39,7 +39,7 @@ if ($data['regexid'] != 0) { $form = (new CForm()) ->setId('regex') ->setAction($action->getUrl()) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); $table = (new CTable()) ->setId('tbl_expr') @@ -172,6 +172,6 @@ else { $form->addItem($reg_exp_view); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/administration.regex.list.php b/ui/app/views/administration.regex.list.php index a018be5308b..0084f79667c 100644 --- a/ui/app/views/administration.regex.list.php +++ b/ui/app/views/administration.regex.list.php @@ -27,7 +27,7 @@ if ($data['uncheck']) { uncheckTableRows('regex'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Regular expressions')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_REGEX_LIST)) @@ -82,4 +82,4 @@ $form->addItem([ ], 'regex') ]); -$widget->addItem($form)->show(); +$html_page->addItem($form)->show(); diff --git a/ui/app/views/administration.script.edit.php b/ui/app/views/administration.script.edit.php index c1e2eb0d08d..4811b6cfc53 100644 --- a/ui/app/views/administration.script.edit.php +++ b/ui/app/views/administration.script.edit.php @@ -27,7 +27,7 @@ $this->addJsFile('multilineinput.js'); $this->includeJsFile('administration.script.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Scripts')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ALERTS_SCRIPT_EDIT)); @@ -50,12 +50,12 @@ $row_template = (new CTag('script', true)) ]))->addClass('form_row') ); -$widget->addItem($row_template); +$html_page->addItem($row_template); $form = (new CForm()) ->setId('script-form') ->setName('scripts') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', 1) ->addVar('scriptid', $data['scriptid']); @@ -314,4 +314,4 @@ else { $form->addItem($scriptView); -$widget->addItem($form)->show(); +$html_page->addItem($form)->show(); diff --git a/ui/app/views/administration.script.list.php b/ui/app/views/administration.script.list.php index 37efe676307..a720894830d 100644 --- a/ui/app/views/administration.script.list.php +++ b/ui/app/views/administration.script.list.php @@ -27,7 +27,7 @@ if ($data['uncheck']) { uncheckTableRows('script'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Scripts')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ALERTS_SCRIPT_LIST)) ->setControls((new CTag('nav', true, @@ -223,6 +223,6 @@ $scriptsForm->addItem([ ]); // append form to widget -$widget +$html_page ->addItem($scriptsForm) ->show(); diff --git a/ui/app/views/administration.token.list.php b/ui/app/views/administration.token.list.php index afeef1cd41f..364997a3475 100644 --- a/ui/app/views/administration.token.list.php +++ b/ui/app/views/administration.token.list.php @@ -100,7 +100,7 @@ $filter = (new CFilter()) ) ]); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('API tokens')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::USERS_TOKEN_LIST)) ->setControls( @@ -210,7 +210,7 @@ $token_form->addItem([ ], 'token') ]); -$widget +$html_page ->addItem($token_form) ->show(); diff --git a/ui/app/views/administration.trigdisplay.edit.php b/ui/app/views/administration.trigdisplay.edit.php index 6d41f7d30ed..992e6246f9f 100644 --- a/ui/app/views/administration.trigdisplay.edit.php +++ b/ui/app/views/administration.trigdisplay.edit.php @@ -27,7 +27,7 @@ $this->addJsFile('colorpicker.js'); $this->includeJsFile('administration.trigdisplay.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Trigger displaying options')) ->setTitleSubmenu(getAdministrationGeneralSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_TRIGDISPLAY_EDIT)); @@ -156,7 +156,7 @@ $form_list = (new CFormList()) ->addInfo(_('Custom severity names affect all locales and require manual translation!')); $form = (new CForm()) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->setAction((new CUrl('zabbix.php')) ->setArgument('action', 'trigdisplay.update') ->getUrl() @@ -170,4 +170,4 @@ $form = (new CForm()) )) ); -$widget->addItem($form)->show(); +$html_page->addItem($form)->show(); diff --git a/ui/app/views/administration.user.edit.php b/ui/app/views/administration.user.edit.php index e6e15ede54b..eae9f85cf28 100644 --- a/ui/app/views/administration.user.edit.php +++ b/ui/app/views/administration.user.edit.php @@ -29,7 +29,7 @@ $this->includeJsFile(($data['action'] === 'user.edit') : 'administration.userprofile.edit.js.php' ); -$widget = new CWidget(); +$html_page = new CHtmlPage(); if ($data['action'] === 'user.edit') { $widget_name = _('Users'); @@ -40,13 +40,14 @@ else { $widget_name .= ($data['name'] !== '' || $data['surname'] !== '') ? $data['name'].' '.$data['surname'] : $data['username']; - $widget->setTitleSubmenu(getUserSettingsSubmenu()); + $html_page->setTitleSubmenu(getUserSettingsSubmenu()); $doc_url = CDocHelper::USERS_USERPROFILE_EDIT; } -$widget +$html_page ->setTitle($widget_name) ->setDocUrl(CDocHelper::getUrl($doc_url)); + $tabs = new CTabView(); if ($data['form_refresh'] == 0) { @@ -57,7 +58,7 @@ if ($data['form_refresh'] == 0) { $user_form = (new CForm()) ->setId('user-form') ->setName('user_form') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('action', $data['action']) ->addVar('userid', $data['userid']); @@ -615,11 +616,12 @@ if ($data['action'] === 'user.edit') { else { $elements = []; - foreach ($data['modules'] as $moduleid => $module) { - $elements[] = (new CSpan($module['id']))->addClass( - CRoleHelper::checkAccess('modules.module.'.$moduleid, $data['roleid']) - ? ZBX_STYLE_STATUS_GREEN - : ZBX_STYLE_STATUS_GREY + foreach ($data['modules'] as $moduleid => $module_name) { + $elements[] = (new CSpan($module_name))->addClass( + array_key_exists($moduleid, $data['disabled_moduleids']) + || $data['modules_rules'][$moduleid] == MODULE_STATUS_DISABLED + ? ZBX_STYLE_STATUS_GREY + : ZBX_STYLE_STATUS_GREEN ); } @@ -824,6 +826,6 @@ else { // Append tab to form. $user_form->addItem($tabs); -$widget +$html_page ->addItem($user_form) ->show(); diff --git a/ui/app/views/administration.user.list.php b/ui/app/views/administration.user.list.php index 0d534a0fb4d..5d66a4eed16 100644 --- a/ui/app/views/administration.user.list.php +++ b/ui/app/views/administration.user.list.php @@ -29,7 +29,7 @@ if ($data['uncheck']) { uncheckTableRows('user'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Users')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::USERS_USER_LIST)) ->setControls((new CList([ @@ -253,6 +253,6 @@ $form->addItem([ ]); // Append form to widget. -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/administration.user.token.list.php b/ui/app/views/administration.user.token.list.php index 481e31648bd..0541adf051a 100644 --- a/ui/app/views/administration.user.token.list.php +++ b/ui/app/views/administration.user.token.list.php @@ -66,7 +66,7 @@ $filter = (new CFilter()) ) ]); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('API tokens')) ->setTitleSubmenu(getUserSettingsSubmenu()) ->setDocUrl(CDocHelper::getUrl(CDocHelper::USERS_USER_TOKEN_LIST)) @@ -163,7 +163,7 @@ $token_form->addItem([ ], 'user.token') ]); -$widget +$html_page ->addItem($token_form) ->show(); diff --git a/ui/app/views/administration.usergroup.edit.php b/ui/app/views/administration.usergroup.edit.php index 5074c3811f8..058e2077f77 100644 --- a/ui/app/views/administration.usergroup.edit.php +++ b/ui/app/views/administration.usergroup.edit.php @@ -26,14 +26,14 @@ $this->includeJsFile('administration.usergroup.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('User groups')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::USERS_USERGROUP_EDIT)); $form = (new CForm()) ->setId('user-group-form') ->setName('user_group_form') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); if ($data['usrgrpid'] != 0) { $form->addVar('usrgrpid', $data['usrgrpid']); @@ -347,5 +347,7 @@ else { // append tab to form $form->addItem($tabs); -$widget->addItem($form); -$widget->show(); + +$html_page + ->addItem($form) + ->show(); diff --git a/ui/app/views/administration.usergroup.list.php b/ui/app/views/administration.usergroup.list.php index e3fd2111fd6..352e983ec32 100644 --- a/ui/app/views/administration.usergroup.list.php +++ b/ui/app/views/administration.usergroup.list.php @@ -27,7 +27,7 @@ if ($data['uncheck']) { uncheckTableRows('usergroup'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('User groups')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::USERS_USERGROUP_LIST)) ->setControls( @@ -240,5 +240,6 @@ $form->addItem([ ], 'usergroup') ]); -$widget->addItem($form); -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/app/views/administration.userrole.edit.php b/ui/app/views/administration.userrole.edit.php index 56566463447..ad5eaf50179 100644 --- a/ui/app/views/administration.userrole.edit.php +++ b/ui/app/views/administration.userrole.edit.php @@ -26,14 +26,14 @@ $this->includeJsFile('administration.userrole.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('User roles')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::USERS_USERROLE_EDIT)); $form = (new CForm()) ->setId('userrole-form') ->setName('user_role_form') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); if ($data['roleid'] !== null) { $form->addVar('roleid', $data['roleid']); @@ -244,28 +244,31 @@ $form_grid->addItem( ); $modules = []; -foreach ($data['labels']['modules'] as $moduleid => $label) { - $modules[] = new CDiv( + +foreach ($data['labels']['modules'] as $moduleid => $module_name) { + $module = new CDiv( (new CCheckBox('modules['.$moduleid.']', 1)) ->setChecked( - array_key_exists($moduleid, $data['rules']['modules']) ? $data['rules']['modules'][$moduleid] : true + array_key_exists($moduleid, $data['rules']['modules']) + ? $data['rules']['modules'][$moduleid] + : !array_key_exists($moduleid, $data['disabled_moduleids']) ) ->setReadonly($data['readonly']) - ->setLabel($label) + ->setLabel($module_name) ->setUncheckedValue(0) ); + + if (array_key_exists($moduleid, $data['disabled_moduleids'])) { + $module->addItem((new CSpan([' (', _('Disabled'), ')']))->addClass(ZBX_STYLE_RED)); + } + + $modules[] = $module; } if ($modules) { - $form_grid->addItem([ - new CFormField( - (new CDiv( - (new CDiv($modules)) - ->addClass(ZBX_STYLE_COLUMNS) - ->addClass(ZBX_STYLE_COLUMNS_3) - ))->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) - ) - ]); + $form_grid->addItem( + new CFormField($modules) + ); } else { $form_grid->addItem( @@ -405,8 +408,10 @@ $form_grid->addItem( $tabs = (new CTabView())->addTab('user_role_tab', _('User role'), $form_grid); $form->addItem((new CTabView())->addTab('user_role_tab', _('User role'), $form_grid)); -$widget->addItem($form); -$widget->show(); + +$html_page + ->addItem($form) + ->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/app/views/administration.userrole.list.php b/ui/app/views/administration.userrole.list.php index 29dd580cd01..d331d0ebb2a 100644 --- a/ui/app/views/administration.userrole.list.php +++ b/ui/app/views/administration.userrole.list.php @@ -27,7 +27,7 @@ if ($data['uncheck']) { uncheckTableRows('userrole'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('User roles')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::USERS_USERROLE_LIST)) ->setControls( @@ -130,5 +130,6 @@ $form->addItem([ ], 'userrole') ]); -$widget->addItem($form); -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/app/views/configuration.correlation.edit.php b/ui/app/views/configuration.correlation.edit.php index 0c0d1d868fb..60b75563b31 100644 --- a/ui/app/views/configuration.correlation.edit.php +++ b/ui/app/views/configuration.correlation.edit.php @@ -26,7 +26,7 @@ $this->addJsFile('popup.condition.common.js'); $this->includeJsFile('configuration.correlation.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Event correlation rules')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_CORRELATION_EDIT)); @@ -37,7 +37,7 @@ $form = (new CForm()) ->setArgument('action', 'correlation.condition.add') ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); if ($data['correlationid'] != 0) { $form->addVar('correlationid', $data['correlationid']); @@ -193,6 +193,6 @@ else { $form->addItem($correlation_tabs); -$widget->addItem($form); - -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/app/views/configuration.correlation.list.php b/ui/app/views/configuration.correlation.list.php index 6c8b6a37d6c..cdcd91514a6 100644 --- a/ui/app/views/configuration.correlation.list.php +++ b/ui/app/views/configuration.correlation.list.php @@ -27,7 +27,7 @@ if ($data['uncheck']) { uncheckTableRows('correlation'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Event correlation')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_CORRELATION_LIST)) ->setControls( @@ -148,6 +148,6 @@ $form->addItem([ ], 'correlation') ]); -$widget->addItem($form); - -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/app/views/configuration.dashboard.edit.php b/ui/app/views/configuration.dashboard.edit.php index ffade88dad0..e000f6be98c 100644 --- a/ui/app/views/configuration.dashboard.edit.php +++ b/ui/app/views/configuration.dashboard.edit.php @@ -30,23 +30,14 @@ $this->addJsFile('class.dashboard.js'); $this->addJsFile('class.dashboard.page.js'); $this->addJsFile('class.dashboard.widget.placeholder.js'); $this->addJsFile('class.widget.js'); +$this->addJsFile('class.widget.inaccessible.js'); $this->addJsFile('class.widget.iterator.js'); -$this->addJsFile('class.widget.clock.js'); -$this->addJsFile('class.widget.graph.js'); -$this->addJsFile('class.widget.graph-prototype.js'); -$this->addJsFile('class.widget.item.js'); -$this->addJsFile('class.widget.map.js'); -$this->addJsFile('class.widget.navtree.js'); $this->addJsFile('class.widget.paste-placeholder.js'); -$this->addJsFile('class.widget.problems.js'); -$this->addJsFile('class.widget.problemsbysv.js'); -$this->addJsFile('class.widget.svggraph.js'); -$this->addJsFile('class.widget.trigerover.js'); $this->addJsFile('class.sortable.js'); $this->includeJsFile('configuration.dashboard.edit.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Dashboards')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::CONFIGURATION_DASHBOARDS_EDIT)) ->setControls( @@ -105,7 +96,7 @@ $dashboard->addItem( $dashboard->addItem((new CDiv())->addClass(ZBX_STYLE_DASHBOARD_GRID)); -$widget +$html_page ->addItem($dashboard) ->show(); @@ -113,6 +104,7 @@ $widget view.init('.json_encode([ 'dashboard' => $data['dashboard'], 'widget_defaults' => $data['widget_defaults'], + 'widget_last_type' => $data['widget_last_type'], 'time_period' => $data['time_period'], 'page' => $data['page'] ]).'); diff --git a/ui/app/views/configuration.dashboard.list.php b/ui/app/views/configuration.dashboard.list.php index 9cf4790743d..9d761d37a72 100644 --- a/ui/app/views/configuration.dashboard.list.php +++ b/ui/app/views/configuration.dashboard.list.php @@ -70,7 +70,7 @@ $form->addItem([ ], $checkbox_hash) ]); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Dashboards')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::CONFIGURATION_DASHBOARDS_LIST)) ->setControls( diff --git a/ui/app/views/configuration.discovery.edit.php b/ui/app/views/configuration.discovery.edit.php index 71831c0bffd..729b59a626a 100644 --- a/ui/app/views/configuration.discovery.edit.php +++ b/ui/app/views/configuration.discovery.edit.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/configuration.discovery.edit.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Discovery rules')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_DISCOVERY_EDIT)); @@ -33,7 +33,7 @@ $widget = (new CWidget()) $discoveryForm = (new CForm()) ->setId('discoveryForm') ->setName('discoveryForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); if (!empty($this->data['druleid'])) { $discoveryForm->addVar('druleid', $this->data['druleid']); @@ -174,6 +174,6 @@ else { $discoveryForm->addItem($discoveryTabs); -$widget->addItem($discoveryForm); - -$widget->show(); +$html_page + ->addItem($discoveryForm) + ->show(); diff --git a/ui/app/views/configuration.discovery.list.php b/ui/app/views/configuration.discovery.list.php index 0ac9244e180..d3b247c308b 100644 --- a/ui/app/views/configuration.discovery.list.php +++ b/ui/app/views/configuration.discovery.list.php @@ -27,7 +27,7 @@ if ($data['uncheck']) { uncheckTableRows('discovery'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Discovery rules')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_DISCOVERY_LIST)) ->setControls( @@ -121,7 +121,6 @@ $discoveryForm->addItem([ ], 'discovery') ]); -// append form to widget -$widget->addItem($discoveryForm); - -$widget->show(); +$html_page + ->addItem($discoveryForm) + ->show(); diff --git a/ui/app/views/configuration.host.edit.php b/ui/app/views/configuration.host.edit.php index 7d336fa09e1..5a0484d69ea 100644 --- a/ui/app/views/configuration.host.edit.php +++ b/ui/app/views/configuration.host.edit.php @@ -62,7 +62,7 @@ if ($data['warning']) { $data['warning'] = null; } -(new CWidget()) +(new CHtmlPage()) ->setTitle(($data['hostid'] == 0) ? _('New host') : _('Host')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_HOST_EDIT)) ->addItem(new CPartial('configuration.host.edit.html', $data)) diff --git a/ui/app/views/configuration.host.list.php b/ui/app/views/configuration.host.list.php index ec2fb854499..cc265e8adb9 100644 --- a/ui/app/views/configuration.host.list.php +++ b/ui/app/views/configuration.host.list.php @@ -31,7 +31,7 @@ if ($data['uncheck']) { uncheckTableRows('hosts'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Hosts')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_HOST_LIST)) ->setControls((new CTag('nav', true, (new CList()) @@ -166,7 +166,7 @@ $filter = (new CFilter()) ]) ]); -$widget->addItem($filter); +$html_page->addItem($filter); // table hosts $form = (new CForm())->setName('hosts'); @@ -545,7 +545,7 @@ $form->addItem([ ], 'hosts') ]); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/configuration.hostgroup.edit.php b/ui/app/views/configuration.hostgroup.edit.php index f8036856dc9..e1131f78201 100644 --- a/ui/app/views/configuration.hostgroup.edit.php +++ b/ui/app/views/configuration.hostgroup.edit.php @@ -48,7 +48,7 @@ $data += [ ] ]; -(new CWidget()) +(new CHtmlPage()) ->setTitle(($data['groupid'] == 0) ? _('New host group') : _('Host group')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_HOSTGROUPS_EDIT)) ->addItem(new CPartial('configuration.hostgroup.edit.html', $data)) diff --git a/ui/app/views/configuration.hostgroup.list.php b/ui/app/views/configuration.hostgroup.list.php index 34a6d781ead..969125349a4 100644 --- a/ui/app/views/configuration.hostgroup.list.php +++ b/ui/app/views/configuration.hostgroup.list.php @@ -26,7 +26,7 @@ $this->includeJsFile('configuration.hostgroup.list.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Host groups')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_HOSTGROUPS_LIST)) ->setControls( @@ -201,7 +201,7 @@ $form->addItem([ ], 'hostgroup') ]); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/configuration.templategroup.edit.php b/ui/app/views/configuration.templategroup.edit.php index 732a8abe1b7..9ee12f1b36a 100644 --- a/ui/app/views/configuration.templategroup.edit.php +++ b/ui/app/views/configuration.templategroup.edit.php @@ -48,7 +48,7 @@ $data += [ ] ]; -(new CWidget()) +(new CHtmlPage()) ->setTitle(($data['groupid'] == 0) ? _('New template group') : _('Template group')) ->addItem(new CPartial('configuration.templategroup.edit.html', $data)) ->show(); diff --git a/ui/app/views/configuration.templategroup.list.php b/ui/app/views/configuration.templategroup.list.php index add2c591c7c..6e5c81b9384 100644 --- a/ui/app/views/configuration.templategroup.list.php +++ b/ui/app/views/configuration.templategroup.list.php @@ -26,7 +26,7 @@ $this->includeJsFile('configuration.templategroup.list.js.php'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Template groups')) ->setControls((new CTag('nav', true, (new CList()) ->addItem(CWebUser::getType() == USER_TYPE_SUPER_ADMIN @@ -148,7 +148,7 @@ $form->addItem([ ], 'templategroup') ]); -$widget +$html_page ->addItem($filter) ->addItem($form) ->show(); diff --git a/ui/app/views/js/configuration.dashboard.edit.js.php b/ui/app/views/js/configuration.dashboard.edit.js.php index 6bfa2ab1a9c..58fdff1fd51 100644 --- a/ui/app/views/js/configuration.dashboard.edit.js.php +++ b/ui/app/views/js/configuration.dashboard.edit.js.php @@ -26,12 +26,10 @@ <script> const view = { - dashboard: null, - page: null, is_busy: false, is_busy_saving: false, - init({dashboard, widget_defaults, time_period, page}) { + init({dashboard, widget_defaults, widget_last_type, time_period, page}) { this.dashboard = dashboard; this.page = page; @@ -60,19 +58,19 @@ max_rows: <?= DASHBOARD_MAX_ROWS ?>, widget_min_rows: <?= DASHBOARD_WIDGET_MIN_ROWS ?>, widget_max_rows: <?= DASHBOARD_WIDGET_MAX_ROWS ?>, - widget_defaults: widget_defaults, + widget_defaults, + widget_last_type, is_editable: true, is_edit_mode: true, can_edit_dashboards: true, is_kiosk_mode: false, - time_period: time_period, + time_period, dynamic_hostid: null }); for (const page of dashboard.pages) { for (const widget of page.widgets) { widget.fields = (typeof widget.fields === 'object') ? widget.fields : {}; - widget.configuration = (typeof widget.configuration === 'object') ? widget.configuration : {}; } ZABBIX.Dashboard.addDashboardPage(page); diff --git a/ui/app/views/js/monitoring.dashboard.print.js.php b/ui/app/views/js/monitoring.dashboard.print.js.php index cfd11d78048..0031fc1812b 100644 --- a/ui/app/views/js/monitoring.dashboard.print.js.php +++ b/ui/app/views/js/monitoring.dashboard.print.js.php @@ -67,7 +67,6 @@ for (const page of dashboard.pages) { for (const widget of page.widgets) { widget.fields = (typeof widget.fields === 'object') ? widget.fields : {}; - widget.configuration = (typeof widget.configuration === 'object') ? widget.configuration : {}; } ZABBIX.Dashboard.addDashboardPage(page); diff --git a/ui/app/views/js/monitoring.dashboard.view.js.php b/ui/app/views/js/monitoring.dashboard.view.js.php index 9f6dc5cd740..c1a623d43f4 100644 --- a/ui/app/views/js/monitoring.dashboard.view.js.php +++ b/ui/app/views/js/monitoring.dashboard.view.js.php @@ -26,18 +26,25 @@ <script> const view = { - dashboard: null, - time_period: null, - dynamic: null, - has_time_selector: null, is_busy: false, is_busy_saving: false, - init({dashboard, time_period, dynamic, has_time_selector, widget_defaults, web_layout_mode}) { + init({ + dashboard, + widget_defaults, + widget_last_type, + configuration_hash, + has_time_selector, + time_period, + dynamic, + web_layout_mode, + clone + }) { this.dashboard = dashboard; + this.has_time_selector = has_time_selector; this.time_period = time_period; this.dynamic = dynamic; - this.has_time_selector = has_time_selector; + this.clone = clone; timeControl.refreshPage = false; @@ -73,20 +80,21 @@ max_rows: <?= DASHBOARD_MAX_ROWS ?>, widget_min_rows: <?= DASHBOARD_WIDGET_MIN_ROWS ?>, widget_max_rows: <?= DASHBOARD_WIDGET_MAX_ROWS ?>, - widget_defaults: widget_defaults, + widget_defaults, + widget_last_type, + configuration_hash, is_editable: dashboard.can_edit_dashboards && dashboard.editable && web_layout_mode != <?= ZBX_LAYOUT_KIOSKMODE ?>, - is_edit_mode: dashboard.dashboardid === null, + is_edit_mode: dashboard.dashboardid === null || clone, can_edit_dashboards: dashboard.can_edit_dashboards, is_kiosk_mode: web_layout_mode == <?= ZBX_LAYOUT_KIOSKMODE ?>, - time_period: time_period, + time_period, dynamic_hostid: dynamic.host ? dynamic.host.id : null }); for (const page of dashboard.pages) { for (const widget of page.widgets) { widget.fields = (typeof widget.fields === 'object') ? widget.fields : {}; - widget.configuration = (typeof widget.configuration === 'object') ? widget.configuration : {}; } ZABBIX.Dashboard.addDashboardPage(page); @@ -102,7 +110,7 @@ jQuery('#dynamic_hostid').on('change', this.events.dynamicHostChange); } - if (dashboard.dashboardid === null) { + if (dashboard.dashboardid === null || clone) { this.edit(); ZABBIX.Dashboard.editProperties(); } @@ -116,6 +124,8 @@ } } + ZABBIX.Dashboard.on(DASHBOARD_EVENT_CONFIGURATION_OUTDATED, this.events.configurationOutdated); + if (dynamic.has_dynamic_widgets) { // Perform dynamic host switch when browser back/previous buttons are pressed. window.addEventListener('popstate', this.events.popState); @@ -183,6 +193,10 @@ request_data.sharing = this.dashboard.sharing; + if (this.clone) { + request_data.clone = '1'; + } + const curl = new Curl('zabbix.php'); curl.setArgument('action', 'dashboard.update'); @@ -224,7 +238,7 @@ messages = exception.error.messages; } else { - title = this.dashboard.dashboardid === null + title = this.dashboard.dashboardid === null || this.clone ? <?= json_encode(_('Failed to create dashboard')) ?> : <?= json_encode(_('Failed to update dashboard')) ?>; } @@ -311,14 +325,14 @@ clickCallback: () => ZABBIX.Dashboard.pasteWidget( ZABBIX.Dashboard.getStoredWidgetDataCopy() ), - disabled: (ZABBIX.Dashboard.getStoredWidgetDataCopy() === null) + disabled: ZABBIX.Dashboard.getStoredWidgetDataCopy() === null }, { label: <?= json_encode(_('Paste page')) ?>, clickCallback: () => ZABBIX.Dashboard.pasteDashboardPage( ZABBIX.Dashboard.getStoredDashboardPageDataCopy() ), - disabled: (ZABBIX.Dashboard.getStoredDashboardPageDataCopy() === null) + disabled: ZABBIX.Dashboard.getStoredDashboardPageDataCopy() === null } ] } @@ -380,10 +394,14 @@ applyProperties() { const dashboard_data = ZABBIX.Dashboard.getData(); - document.getElementById('<?= ZBX_STYLE_PAGE_TITLE ?>').textContent = dashboard_data.name; + document.getElementById('<?= CHtmlPage::PAGE_TITLE_ID ?>').textContent = dashboard_data.name; document.getElementById('dashboard-direct-link').textContent = dashboard_data.name; }, + configurationOutdated() { + location.href = location.href; + }, + busy() { view.is_busy = true; view.updateBusy(); diff --git a/ui/app/views/js/monitoring.host.dashboard.view.js.php b/ui/app/views/js/monitoring.host.dashboard.view.js.php index c65356010cf..7b7adbbaf5d 100644 --- a/ui/app/views/js/monitoring.host.dashboard.view.js.php +++ b/ui/app/views/js/monitoring.host.dashboard.view.js.php @@ -26,7 +26,7 @@ <script> const view = { - init({host, dashboard, widget_defaults, time_period, web_layout_mode}) { + init({host, dashboard, widget_defaults, configuration_hash, time_period, web_layout_mode}) { timeControl.refreshPage = false; ZABBIX.Dashboard = new CDashboard(document.querySelector('.<?= ZBX_STYLE_DASHBOARD ?>'), { @@ -61,7 +61,8 @@ max_rows: <?= DASHBOARD_MAX_ROWS ?>, widget_min_rows: <?= DASHBOARD_WIDGET_MIN_ROWS ?>, widget_max_rows: <?= DASHBOARD_WIDGET_MAX_ROWS ?>, - widget_defaults: widget_defaults, + widget_defaults, + configuration_hash, is_editable: false, is_edit_mode: false, can_edit_dashboards: false, @@ -73,7 +74,6 @@ for (const page of dashboard.pages) { for (const widget of page.widgets) { widget.fields = (typeof widget.fields === 'object') ? widget.fields : {}; - widget.configuration = (typeof widget.configuration === 'object') ? widget.configuration : {}; } ZABBIX.Dashboard.addDashboardPage(page); @@ -81,6 +81,8 @@ ZABBIX.Dashboard.activate(); + ZABBIX.Dashboard.on(DASHBOARD_EVENT_CONFIGURATION_OUTDATED, this.events.configurationOutdated); + if (web_layout_mode == <?= ZBX_LAYOUT_NORMAL ?>) { document.getElementById('dashboardid').addEventListener('change', this.events.dashboardChange); } @@ -89,6 +91,10 @@ }, events: { + configurationOutdated() { + location.href = location.href; + }, + dashboardChange(e) { e.target.closest('form').submit(); } diff --git a/ui/app/views/js/popup.massupdate.tmpl.js.php b/ui/app/views/js/popup.massupdate.tmpl.js.php index f4761332b6c..b792eb51230 100644 --- a/ui/app/views/js/popup.massupdate.tmpl.js.php +++ b/ui/app/views/js/popup.massupdate.tmpl.js.php @@ -24,7 +24,7 @@ * @var array $data */ ?> -<?= (new CScriptTemplate('valuemap-rename-row-tmpl'))->addItem( +<?= (new CTemplateTag('valuemap-rename-row-tmpl'))->addItem( (new CRow([ (new CTextBox('valuemap_rename[#{rowNum}][from]', '', false, DB::getFieldLength('valuemap', 'name'))) ->addStyle('width: 100%;'), diff --git a/ui/app/views/monitoring.charts.view.php b/ui/app/views/monitoring.charts.view.php index e031f3c433e..7fe528b8638 100644 --- a/ui/app/views/monitoring.charts.view.php +++ b/ui/app/views/monitoring.charts.view.php @@ -36,7 +36,7 @@ $this->includeJsFile('monitoring.charts.view.js.php'); $this->enableLayoutModes(); $web_layout_mode = $this->getLayoutMode(); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Graphs')) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_CHARTS_VIEW)) @@ -89,24 +89,24 @@ if ($web_layout_mode == ZBX_LAYOUT_NORMAL) { new CPartial('monitoring.charts.subfilter', $data['subfilters'])); } -$widget->addItem($filter); +$html_page->addItem($filter); if (!$data['filter_hostids']) { - $widget->addItem((new CTableInfo())->setNoDataMessage(_('Specify host to see the graphs.'))); + $html_page->addItem((new CTableInfo())->setNoDataMessage(_('Specify host to see the graphs.'))); } elseif ($data['charts']) { $table = (new CTable()) ->setAttribute('style', 'width: 100%;') ->setId('charts'); - $widget + $html_page ->addItem($table) ->addItem($data['paging']); } else { - $widget->addItem(new CTableInfo()); + $html_page->addItem(new CTableInfo()); } -$widget->show(); +$html_page->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/app/views/monitoring.dashboard.list.php b/ui/app/views/monitoring.dashboard.list.php index 50730374c9f..cdc4205e740 100644 --- a/ui/app/views/monitoring.dashboard.list.php +++ b/ui/app/views/monitoring.dashboard.list.php @@ -31,7 +31,7 @@ $this->addJsFile('layout.mode.js'); $this->enableLayoutModes(); $web_layout_mode = $this->getLayoutMode(); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Dashboards')) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DASHBOARDS_LIST)) @@ -52,7 +52,7 @@ $widget = (new CWidget()) ); if ($web_layout_mode == ZBX_LAYOUT_NORMAL) { - $widget + $html_page ->addItem((new CFilter()) ->setResetUrl((new CUrl('zabbix.php'))->setArgument('action', 'dashboard.list')) ->setProfile($data['profileIdx']) @@ -128,5 +128,6 @@ $form->addItem([ ], 'dashboard') ]); -$widget->addItem($form); -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/app/views/monitoring.dashboard.print.php b/ui/app/views/monitoring.dashboard.print.php index d0fb077c6b8..911f46aac8f 100644 --- a/ui/app/views/monitoring.dashboard.print.php +++ b/ui/app/views/monitoring.dashboard.print.php @@ -38,19 +38,9 @@ $this->addJsFile('class.dashboard.page.js'); $this->addJsFile('class.dashboard.widget.placeholder.js'); $this->addJsFile('class.geomaps.js'); $this->addJsFile('class.widget.js'); +$this->addJsFile('class.widget.inaccessible.js'); $this->addJsFile('class.widget.iterator.js'); -$this->addJsFile('class.widget.clock.js'); -$this->addJsFile('class.widget.geomap.js'); -$this->addJsFile('class.widget.graph.js'); -$this->addJsFile('class.widget.graph-prototype.js'); -$this->addJsFile('class.widget.item.js'); -$this->addJsFile('class.widget.map.js'); -$this->addJsFile('class.widget.navtree.js'); $this->addJsFile('class.widget.paste-placeholder.js'); -$this->addJsFile('class.widget.problems.js'); -$this->addJsFile('class.widget.problemsbysv.js'); -$this->addJsFile('class.widget.svggraph.js'); -$this->addJsFile('class.widget.trigerover.js'); $this->addJsFile('class.csvggraph.js'); $this->addJsFile('class.svg.canvas.js'); $this->addJsFile('class.svg.map.js'); @@ -63,7 +53,7 @@ $this->addCssFile('assets/styles/vendors/Leaflet/Leaflet/leaflet.css'); $this->enableLayoutModes(); $this->setLayoutMode(ZBX_LAYOUT_KIOSKMODE); -(new CWidget()) +(new CHtmlPage()) ->addItem( (new CDiv()) ->addClass(ZBX_STYLE_DASHBOARD) diff --git a/ui/app/views/monitoring.dashboard.view.php b/ui/app/views/monitoring.dashboard.view.php index e34b71a6d41..0623b5f8968 100644 --- a/ui/app/views/monitoring.dashboard.view.php +++ b/ui/app/views/monitoring.dashboard.view.php @@ -39,19 +39,9 @@ $this->addJsFile('class.dashboard.page.js'); $this->addJsFile('class.dashboard.widget.placeholder.js'); $this->addJsFile('class.geomaps.js'); $this->addJsFile('class.widget.js'); +$this->addJsFile('class.widget.inaccessible.js'); $this->addJsFile('class.widget.iterator.js'); -$this->addJsFile('class.widget.clock.js'); -$this->addJsFile('class.widget.geomap.js'); -$this->addJsFile('class.widget.graph.js'); -$this->addJsFile('class.widget.graph-prototype.js'); -$this->addJsFile('class.widget.item.js'); -$this->addJsFile('class.widget.map.js'); -$this->addJsFile('class.widget.navtree.js'); $this->addJsFile('class.widget.paste-placeholder.js'); -$this->addJsFile('class.widget.problems.js'); -$this->addJsFile('class.widget.problemsbysv.js'); -$this->addJsFile('class.widget.svggraph.js'); -$this->addJsFile('class.widget.trigerover.js'); $this->addJsFile('class.calendar.js'); $this->addJsFile('layout.mode.js'); $this->addJsFile('class.coverride.js'); @@ -100,7 +90,7 @@ if ($data['dynamic']['has_dynamic_widgets']) { ]); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle($data['dashboard']['name']) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DASHBOARDS_VIEW)) @@ -137,9 +127,11 @@ $widget = (new CWidget()) (new CButton('dashboard-config'))->addClass(ZBX_STYLE_BTN_DASHBOARD_CONF), (new CList()) ->addClass(ZBX_STYLE_BTN_SPLIT) - ->addItem((new CButton('dashboard-add-widget', - [(new CSpan())->addClass(ZBX_STYLE_PLUS_ICON), _('Add')] - ))->addClass(ZBX_STYLE_BTN_ALT)) + ->addItem( + (new CButton('dashboard-add-widget', + [(new CSpan())->addClass(ZBX_STYLE_PLUS_ICON), _('Add')] + ))->addClass(ZBX_STYLE_BTN_ALT) + ) ->addItem( (new CButton('dashboard-add', '​')) ->addClass(ZBX_STYLE_BTN_ALT) @@ -197,7 +189,7 @@ $widget = (new CWidget()) ]))); if ($data['has_time_selector']) { - $widget->addItem( + $html_page->addItem( (new CFilter()) ->setProfile($data['time_period']['profileIdx'], $data['time_period']['profileIdx2']) ->setActiveTab($data['active_tab']) @@ -252,7 +244,7 @@ if ($web_layout_mode != ZBX_LAYOUT_KIOSKMODE) { $dashboard->addItem((new CDiv())->addClass(ZBX_STYLE_DASHBOARD_GRID)); -$widget +$html_page ->addItem($dashboard) ->show(); @@ -260,10 +252,13 @@ $widget view.init('.json_encode([ 'dashboard' => $data['dashboard'], 'widget_defaults' => $data['widget_defaults'], + 'widget_last_type' => $data['widget_last_type'], + 'configuration_hash' => $data['configuration_hash'], 'has_time_selector' => $data['has_time_selector'], 'time_period' => $data['time_period'], 'dynamic' => $data['dynamic'], - 'web_layout_mode' => $web_layout_mode + 'web_layout_mode' => $web_layout_mode, + 'clone' => $data['clone'] ]).'); ')) ->setOnDocumentReady() diff --git a/ui/app/views/monitoring.dashboard.widget.edit.php b/ui/app/views/monitoring.dashboard.widget.edit.php deleted file mode 100644 index b137f5f9257..00000000000 --- a/ui/app/views/monitoring.dashboard.widget.edit.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * @var CView $this - * @var array $data - */ - -$widget_view = include('include/classes/widgets/views/widget.'.$data['dialogue']['type'].'.form.view.php'); - -$form = $widget_view['form']->addClass('dashboard-widget-'.$data['dialogue']['type']); - -// Submit button is needed to enable submit event on Enter on inputs. -$form->addItem((new CInput('submit', 'dashboard_widget_config_submit'))->addStyle('display: none;')); - -$output = [ - 'header' => $data['unique_id'] !== null ? _s('Edit widget') : _s('Add widget'), - 'doc_url' => CDocHelper::getUrl(CDocHelper::DASHBOARDS_WIDGET_EDIT), - 'body' => '', - 'buttons' => [ - [ - 'title' => $data['unique_id'] !== null ? _s('Apply') : _s('Add'), - 'class' => 'dialogue-widget-save', - 'keepOpen' => true, - 'isSubmit' => true, - 'action' => 'ZABBIX.Dashboard.applyWidgetProperties();' - ] - ], - 'data' => [ - 'original_properties' => [ - 'type' => $data['dialogue']['type'], - 'unique_id' => $data['unique_id'], - 'dashboard_page_unique_id' => $data['dashboard_page_unique_id'] - ] - ] -]; - -if (($messages = getMessages()) !== null) { - $output['body'] .= $messages->toString(); -} - -$output['body'] .= $form->toString(); - -if (array_key_exists('jq_templates', $widget_view)) { - foreach ($widget_view['jq_templates'] as $id => $jq_template) { - $output['body'] .= '<script type="text/x-jquery-tmpl" id="'.$id.'">'.$jq_template.'</script>'; - } -} - -$scripts = [ - $this->readJsFile('monitoring.dashboard.widget.edit.js.php'), - 'widget_form.init();' -]; - -if (array_key_exists('scripts', $widget_view)) { - $scripts = array_merge($scripts, $widget_view['scripts']); -} - -$output['body'] .= get_js(implode("\n", $scripts)); - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); diff --git a/ui/app/views/monitoring.discovery.view.php b/ui/app/views/monitoring.discovery.view.php index bd156a5824f..76cf3e5db47 100644 --- a/ui/app/views/monitoring.discovery.view.php +++ b/ui/app/views/monitoring.discovery.view.php @@ -30,7 +30,7 @@ $this->addJsFile('layout.mode.js'); $this->enableLayoutModes(); $web_layout_mode = $this->getLayoutMode(); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Status of discovery')) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_DISCOVERY_VIEW)) @@ -77,4 +77,4 @@ $discovery_table = CScreenBuilder::getScreen([ ] ])->get(); -$widget->addItem($discovery_table)->show(); +$html_page->addItem($discovery_table)->show(); diff --git a/ui/app/views/monitoring.host.dashboard.view.php b/ui/app/views/monitoring.host.dashboard.view.php index 95461164381..5b154ebbd4f 100644 --- a/ui/app/views/monitoring.host.dashboard.view.php +++ b/ui/app/views/monitoring.host.dashboard.view.php @@ -28,7 +28,7 @@ if (array_key_exists('error', $data)) { } if (array_key_exists('no_data', $data)) { - (new CWidget()) + (new CHtmlPage()) ->setTitle(_('Dashboards')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_HOST_DASHBOARD_VIEW)) ->addItem(new CTableInfo()) @@ -44,18 +44,9 @@ $this->addJsFile('class.dashboard.js'); $this->addJsFile('class.dashboard.page.js'); $this->addJsFile('class.dashboard.widget.placeholder.js'); $this->addJsFile('class.widget.js'); +$this->addJsFile('class.widget.inaccessible.js'); $this->addJsFile('class.widget.iterator.js'); -$this->addJsFile('class.widget.clock.js'); -$this->addJsFile('class.widget.graph.js'); -$this->addJsFile('class.widget.graph-prototype.js'); -$this->addJsFile('class.widget.item.js'); -$this->addJsFile('class.widget.map.js'); -$this->addJsFile('class.widget.navtree.js'); $this->addJsFile('class.widget.paste-placeholder.js'); -$this->addJsFile('class.widget.problems.js'); -$this->addJsFile('class.widget.problemsbysv.js'); -$this->addJsFile('class.widget.svggraph.js'); -$this->addJsFile('class.widget.trigerover.js'); $this->addJsFile('layout.mode.js'); $this->addJsFile('class.sortable.js'); @@ -64,7 +55,7 @@ $this->includeJsFile('monitoring.host.dashboard.view.js.php'); $this->enableLayoutModes(); $web_layout_mode = $this->getLayoutMode(); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle($data['dashboard']['name']) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_HOST_DASHBOARD_VIEW)) @@ -129,7 +120,7 @@ $widget = (new CWidget()) ]))); if ($data['has_time_selector']) { - $widget->addItem( + $html_page->addItem( (new CFilter()) ->setProfile($data['time_period']['profileIdx'], $data['time_period']['profileIdx2']) ->setActiveTab($data['active_tab']) @@ -182,7 +173,7 @@ if (count($data['dashboard']['pages']) > 1 $dashboard->addItem((new CDiv())->addClass(ZBX_STYLE_DASHBOARD_GRID)); - $widget + $html_page ->addItem($dashboard) ->show(); @@ -191,6 +182,7 @@ if (count($data['dashboard']['pages']) > 1 'host' => $data['host'], 'dashboard' => $data['dashboard'], 'widget_defaults' => $data['widget_defaults'], + 'configuration_hash' => $data['configuration_hash'], 'time_period' => $data['time_period'], 'web_layout_mode' => $web_layout_mode ]).'); @@ -199,7 +191,7 @@ if (count($data['dashboard']['pages']) > 1 ->show(); } else { - $widget + $html_page ->addItem(new CTableInfo()) ->show(); } diff --git a/ui/app/views/monitoring.host.view.php b/ui/app/views/monitoring.host.view.php index f50e9c56edd..fcee4d1d6ed 100644 --- a/ui/app/views/monitoring.host.view.php +++ b/ui/app/views/monitoring.host.view.php @@ -45,7 +45,7 @@ if ($data['can_create_hosts']) { $nav_items->addItem(get_icon('kioskmode', ['mode' => $web_layout_mode])); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Hosts')) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_HOST_VIEW)) @@ -66,18 +66,19 @@ if ($web_layout_mode == ZBX_LAYOUT_NORMAL) { // Set javascript options for tab filter initialization in monitoring.host.view.js.php file. $data['filter_options'] = $filter->options; - $widget->addItem($filter); + $html_page->addItem($filter); } else { $data['filter_options'] = null; } -$widget->addItem((new CForm()) - ->setName('host_view') - ->addClass('is-loading') -); - -$widget->show(); +$html_page + ->addItem( + (new CForm()) + ->setName('host_view') + ->addClass('is-loading') + ) + ->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/app/views/monitoring.latest.view.php b/ui/app/views/monitoring.latest.view.php index d95fdaf18a8..965166b187d 100644 --- a/ui/app/views/monitoring.latest.view.php +++ b/ui/app/views/monitoring.latest.view.php @@ -39,7 +39,7 @@ if ($data['uncheck']) { uncheckTableRows('latest'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Latest data')) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_LATEST_VIEW)) @@ -64,19 +64,19 @@ if ($web_layout_mode == ZBX_LAYOUT_NORMAL) { // Set javascript options for tab filter initialization in monitoring.latest.view.js.php file. $data['filter_options'] = $filter->options; - $widget->addItem($filter); + $html_page->addItem($filter); } else { $data['filter_options'] = null; } -$widget->addItem(new CPartial('monitoring.latest.view.html', array_intersect_key($data, - array_flip(['filter', 'sort_field', 'sort_order', 'view_curl', 'paging', 'hosts', 'items', 'history', 'config', - 'tags', 'maintenances', 'items_rw' - ]) -))); - -$widget->show(); +$html_page + ->addItem(new CPartial('monitoring.latest.view.html', array_intersect_key($data, + array_flip(['filter', 'sort_field', 'sort_order', 'view_curl', 'paging', 'hosts', 'items', 'history', 'config', + 'tags', 'maintenances', 'items_rw' + ]) + ))) + ->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/app/views/monitoring.map.view.php b/ui/app/views/monitoring.map.view.php index 5afe2dcf90a..ebfe9b5f8e3 100644 --- a/ui/app/views/monitoring.map.view.php +++ b/ui/app/views/monitoring.map.view.php @@ -33,7 +33,7 @@ $this->includeJsFile('monitoring.map.view.js.php'); $this->enableLayoutModes(); $web_layout_mode = $this->getLayoutMode(); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Maps')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_MAP_VIEW)) ->setWebLayoutMode($web_layout_mode) @@ -62,7 +62,7 @@ $web_layout_mode = $this->getLayoutMode(); ))->setEnabled($data['allowed_edit']) : null ) - ->addItem(get_icon('favourite', [ + ->addItem(get_icon('favorite', [ 'fav' => 'web.favorite.sysmapids', 'elname' => 'sysmapid', 'elid' => $data['map']['sysmapid'] diff --git a/ui/app/views/monitoring.problem.view.php b/ui/app/views/monitoring.problem.view.php index 41b26a66a8b..49e2cc9beee 100644 --- a/ui/app/views/monitoring.problem.view.php +++ b/ui/app/views/monitoring.problem.view.php @@ -39,7 +39,7 @@ if ($data['action'] === 'problem.view') { uncheckTableRows('problem'); } - $widget = (new CWidget()) + $html_page = (new CHtmlPage()) ->setTitle(_('Problems')) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_PROBLEMS_VIEW)) @@ -66,14 +66,14 @@ if ($data['action'] === 'problem.view') { // Set javascript options for tab filter initialization in monitoring.problem.view.js.php file. $data['filter_options'] = $filter->options; - $widget->addItem($filter); + $html_page->addItem($filter); } else { $data['filter_options'] = null; } $this->includeJsFile('monitoring.problem.view.js.php', $data); - $widget + $html_page ->addItem(new CPartial('monitoring.problem.view.html', array_intersect_key($data, array_flip(['page', 'action', 'sort', 'sortorder', 'filter', 'tabfilter_idx']) ))) diff --git a/ui/app/views/monitoring.web.view.php b/ui/app/views/monitoring.web.view.php index 20595245dfb..242e54f0703 100644 --- a/ui/app/views/monitoring.web.view.php +++ b/ui/app/views/monitoring.web.view.php @@ -33,7 +33,7 @@ $this->includeJsFile('monitoring.web.view.js.php'); $this->enableLayoutModes(); $web_layout_mode = $this->getLayoutMode(); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Web monitoring')) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_WEB_VIEW)) diff --git a/ui/app/views/monitoring.widget.dataover.view.php b/ui/app/views/monitoring.widget.dataover.view.php deleted file mode 100644 index dcca9a7703b..00000000000 --- a/ui/app/views/monitoring.widget.dataover.view.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * @var CView $this - */ - -if ($data['style'] == STYLE_TOP) { - $table = (new CPartial('dataoverview.table.top', $data))->getOutput(); -} -else { - $table = (new CPartial('dataoverview.table.left', $data))->getOutput(); -} - -$output = [ - 'name' => $data['name'], - 'body' => $table -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); diff --git a/ui/app/views/monitoring.widget.graph.view.php b/ui/app/views/monitoring.widget.graph.view.php deleted file mode 100644 index 3a85991c624..00000000000 --- a/ui/app/views/monitoring.widget.graph.view.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * @var CView $this - */ - -$output = [ - 'name' => $data['name'] -]; - -if ($data['is_resource_available']) { - $link_url = ($data['widget']['graph_url'] !== null) ? $data['widget']['graph_url'] : 'javascript:void(0)'; - - $output['body'] = (new CDiv()) - ->addClass('flickerfreescreen') - ->addItem((new CLink(null, $link_url))->addClass(ZBX_STYLE_DASHBOARD_WIDGET_GRAPH_LINK)) - ->toString(); - - $output['async_data'] = $data['widget']; -} -else { - $output['body'] = (new CTableInfo()) - ->setNoDataMessage(_('No permissions to referred object or it does not exist!')) - ->toString(); -} - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); diff --git a/ui/app/views/monitoring.widget.map.view.php b/ui/app/views/monitoring.widget.map.view.php deleted file mode 100644 index 293c9e151eb..00000000000 --- a/ui/app/views/monitoring.widget.map.view.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * @var CView $this - */ - -$item = new CDashboardWidgetMap($data['sysmap_data'], $data['widget_settings']); - -$output = [ - 'name' => $data['name'], - 'body' => $item->toString(), - 'sysmap_data' => $item->getScriptData() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($this->data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); diff --git a/ui/app/views/monitoring.widget.svggraph.view.php b/ui/app/views/monitoring.widget.svggraph.view.php deleted file mode 100644 index b081a44c305..00000000000 --- a/ui/app/views/monitoring.widget.svggraph.view.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * @var CView $this - */ - -$output = [ - 'body' => $data['svg'] -]; - -if (!$data['preview']) { - $output += [ - 'name' => $data['name'], - 'svg_options' => $data['svg_options'] - ]; - - if ($data['info'] !== null) { - $output += [ - 'info' => $data['info'] - ]; - } -} - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if (!$data['preview'] && $data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); diff --git a/ui/app/views/monitoring.widget.trigover.view.php b/ui/app/views/monitoring.widget.trigover.view.php deleted file mode 100644 index 9b9c93d1571..00000000000 --- a/ui/app/views/monitoring.widget.trigover.view.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * @var CView $this - */ - -if ($data['style'] == STYLE_TOP) { - $table = (new CPartial('trigoverview.table.top', $data))->getOutput(); -} -else { - $table = (new CPartial('trigoverview.table.left', $data))->getOutput(); -} - -$output = [ - 'name' => $data['name'], - 'body' => $table -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); diff --git a/ui/app/views/popup.massupdate.service.php b/ui/app/views/popup.massupdate.service.php index ed88a153f74..fa3bd38ba93 100644 --- a/ui/app/views/popup.massupdate.service.php +++ b/ui/app/views/popup.massupdate.service.php @@ -45,7 +45,7 @@ $tags_form_grid = (new CFormGrid()) renderTagTable([['tag' => '', 'value' => '']]) ->setHeader([_('Name'), _('Value'), _('Action')]) ->addClass('tags-table'), - (new CScriptTemplate('tag-row-tmpl')) + (new CTemplateTag('tag-row-tmpl')) ->addItem(renderTagTableRow('#{rowNum}', '', '', ZBX_TAG_MANUAL, ['add_post_js' => false])) ])) ->setId('tags-div') diff --git a/ui/app/views/popup.service.edit.php b/ui/app/views/popup.service.edit.php index 7db4c330145..006852a8bce 100644 --- a/ui/app/views/popup.service.edit.php +++ b/ui/app/views/popup.service.edit.php @@ -73,7 +73,7 @@ $service_tab = (new CFormGrid()) ->addClass('element-table-add') )) ), - (new CScriptTemplate('problem-tag-row-tmpl')) + (new CTemplateTag('problem-tag-row-tmpl')) ->addItem( (new CRow([ (new CTextBox('problem_tags[#{rowNum}][tag]', '#{tag}', false, @@ -252,7 +252,7 @@ $tags_tab = (new CFormGrid()) renderTagTable($data['form']['tags']) ->addClass('tags-table') ->setHeader((new CRowHeader([_('Name'), _('Value'), _('Action')]))->addClass(ZBX_STYLE_GREY)), - (new CScriptTemplate('tag-row-tmpl')) + (new CTemplateTag('tag-row-tmpl')) ->addItem(renderTagTableRow('#{rowNum}', '', '', ZBX_TAG_MANUAL, ['add_post_js' => false])) ]) ) diff --git a/ui/app/views/popup.sla.edit.php b/ui/app/views/popup.sla.edit.php index 555cb46cd37..e7c08919817 100644 --- a/ui/app/views/popup.sla.edit.php +++ b/ui/app/views/popup.sla.edit.php @@ -136,7 +136,7 @@ $sla_tab = (new CFormGrid()) ->addClass('element-table-add') )) ), - (new CScriptTemplate('service-tag-row-tmpl')) + (new CTemplateTag('service-tag-row-tmpl')) ->addItem( (new CRow([ (new CTextBox('service_tags[#{rowNum}][tag]', '#{tag}', false, diff --git a/ui/app/views/popup.view.php b/ui/app/views/popup.view.php index e616e7f2b58..51f560851b4 100644 --- a/ui/app/views/popup.view.php +++ b/ui/app/views/popup.view.php @@ -25,7 +25,7 @@ $this->addJsFile('class.calendar.js'); -(new CWidget())->show(); +(new CHtmlPage())->show(); (new CScriptTag( 'PopUp("'.$data['popup']['action'].'", '.json_encode($data['popup']['options']).');'. diff --git a/ui/app/views/proxy.list.php b/ui/app/views/proxy.list.php index 48f331ea475..64861b44e54 100644 --- a/ui/app/views/proxy.list.php +++ b/ui/app/views/proxy.list.php @@ -229,7 +229,7 @@ $form->addItem( ], 'proxy') ); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Proxies')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_PROXY_LIST)) ->setControls( diff --git a/ui/app/views/report.status.php b/ui/app/views/report.status.php index ae5f6c38152..0658436199b 100644 --- a/ui/app/views/report.status.php +++ b/ui/app/views/report.status.php @@ -26,7 +26,7 @@ require_once __DIR__.'/../../include/blocks.inc.php'; -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('System information')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::REPORT_STATUS)) ->addItem( diff --git a/ui/app/views/reports.auditlog.list.php b/ui/app/views/reports.auditlog.list.php index 7f1adddbba6..911fd046805 100644 --- a/ui/app/views/reports.auditlog.list.php +++ b/ui/app/views/reports.auditlog.list.php @@ -53,7 +53,7 @@ $filter_actions = (new CCheckBoxList('filter_actions')) ->addClass(ZBX_STYLE_COLUMNS_3) ->setOptions($filter_actions_options); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Audit log')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::REPORTS_AUDITLOG_LIST)) ->addItem($filter @@ -157,7 +157,7 @@ $obj = [ 'timeControl.processObjects();') )->show(); -$widget +$html_page ->addItem( (new CForm('get')) ->setName('auditForm') diff --git a/ui/app/views/reports.scheduledreport.edit.php b/ui/app/views/reports.scheduledreport.edit.php index 105f9055853..83a38bc9a1b 100644 --- a/ui/app/views/reports.scheduledreport.edit.php +++ b/ui/app/views/reports.scheduledreport.edit.php @@ -29,7 +29,7 @@ $this->includeJsFile('reports.scheduledreport.edit.js.php', [ 'dashboard_inaccessible' => $data['dashboard_inaccessible'] ]); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Scheduled reports')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::REPORTS_SCHEDULEDREPORT_EDIT)); @@ -41,7 +41,7 @@ $form = (new CForm()) ->setArgument('action', ($data['reportid'] == 0) ? 'scheduledreport.create' : 'scheduledreport.update') ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE); + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID); if ($data['reportid'] != 0) { $form->addVar('reportid', $data['reportid']); @@ -58,6 +58,6 @@ $form_grid = new CPartial('scheduledreport.formgrid.html', [ $form->addItem((new CTabView())->addTab('scheduledreport_tab', _('Scheduled report'), $form_grid)); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/reports.scheduledreport.list.php b/ui/app/views/reports.scheduledreport.list.php index 9f645997285..6bcfd395267 100644 --- a/ui/app/views/reports.scheduledreport.list.php +++ b/ui/app/views/reports.scheduledreport.list.php @@ -27,7 +27,7 @@ if ($data['uncheck']) { uncheckTableRows('scheduledreport'); } -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Scheduled reports')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::REPORTS_SCHEDULEDREPORT_LIST)) ->setControls( @@ -100,6 +100,6 @@ $form->addItem([ ], 'scheduledreport') ]); -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/search.php b/ui/app/views/search.php index c69680f1514..13553001022 100644 --- a/ui/app/views/search.php +++ b/ui/app/views/search.php @@ -26,7 +26,7 @@ $this->includeJsFile('search.js.php'); -$widgets = []; +$sections = []; $table = (new CTableInfo()) ->setHeader((new CRowHeader()) @@ -179,13 +179,12 @@ foreach ($data['hosts'] as $hostid => $host) { ]); } -$widgets[] = (new CCollapsibleUiWidget(WIDGET_SEARCH_HOSTS, $table)) - ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FLUID) - ->setExpanded((bool) CProfile::get('web.search.hats.'.WIDGET_SEARCH_HOSTS.'.state', true)) - ->setHeader(_('Hosts'), [], 'web.search.hats.'.WIDGET_SEARCH_HOSTS.'.state') - ->setFooter(new CList([ - _s('Displaying %1$s of %2$s found', count($data['hosts']), $data['total_hosts_cnt']) - ])); +$sections[] = (new CSectionCollapsible($table)) + ->setId(SECTION_SEARCH_HOSTS) + ->setHeader(new CTag('h4', true, _('Hosts'))) + ->setFooter(_s('Displaying %1$s of %2$s found', count($data['hosts']), $data['total_hosts_cnt'])) + ->setProfileIdx('web.search.hats.'.SECTION_SEARCH_HOSTS.'.state') + ->setExpanded((bool) CProfile::get('web.search.hats.'.SECTION_SEARCH_HOSTS.'.state', true)); $table = (new CTableInfo()) ->setHeader((new CRowHeader()) @@ -260,13 +259,12 @@ foreach ($data['host_groups'] as $groupid => $group) { ]); } -$widgets[] = (new CCollapsibleUiWidget(WIDGET_SEARCH_HOSTGROUP, $table)) - ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FLUID) - ->setExpanded((bool) CProfile::get('web.search.hats.'.WIDGET_SEARCH_HOSTGROUP.'.state', true)) - ->setHeader(_('Host groups'), [], 'web.search.hats.'.WIDGET_SEARCH_HOSTGROUP.'.state') - ->setFooter(new CList([ - _s('Displaying %1$s of %2$s found', count($data['host_groups']), $data['total_host_groups_cnt']) - ])); +$sections[] = (new CSectionCollapsible($table)) + ->setId(SECTION_SEARCH_HOSTGROUP) + ->setHeader(new CTag('h4', true, _('Host groups'))) + ->setFooter(_s('Displaying %1$s of %2$s found', count($data['host_groups']), $data['total_host_groups_cnt'])) + ->setProfileIdx('web.search.hats.'.SECTION_SEARCH_HOSTGROUP.'.state') + ->setExpanded((bool) CProfile::get('web.search.hats.'.SECTION_SEARCH_HOSTGROUP.'.state', true)); if ($data['admin']) { $table = (new CTableInfo()) @@ -359,13 +357,12 @@ if ($data['admin']) { ]); } - $widgets[] = (new CCollapsibleUiWidget(WIDGET_SEARCH_TEMPLATES, $table)) - ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FLUID) - ->setExpanded((bool) CProfile::get('web.search.hats.'.WIDGET_SEARCH_TEMPLATES.'.state', true)) - ->setHeader(_('Templates'), [], 'web.search.hats.'.WIDGET_SEARCH_TEMPLATES.'.state') - ->setFooter(new CList([ - _s('Displaying %1$s of %2$s found', count($data['templates']), $data['total_templates_cnt']) - ])); + $sections[] = (new CSectionCollapsible($table)) + ->setId(SECTION_SEARCH_TEMPLATES) + ->setHeader(new CTag('h4', true, _('Templates'))) + ->setFooter(_s('Displaying %1$s of %2$s found', count($data['templates']), $data['total_templates_cnt'])) + ->setProfileIdx('web.search.hats.'.SECTION_SEARCH_TEMPLATES.'.state') + ->setExpanded((bool) CProfile::get('web.search.hats.'.SECTION_SEARCH_TEMPLATES.'.state', true)); } $table = (new CTableInfo()) @@ -404,18 +401,19 @@ foreach ($data['template_groups'] as $groupid => $group) { $table->addRow([$name_link, $templates_link]); } -$widgets[] = (new CCollapsibleUiWidget(WIDGET_SEARCH_TEMPLATEGROUP, $table)) - ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FLUID) - ->setExpanded((bool) CProfile::get('web.search.hats.'.WIDGET_SEARCH_TEMPLATEGROUP.'.state', true)) - ->setHeader(_('Template groups'), [], 'web.search.hats.'.WIDGET_SEARCH_TEMPLATEGROUP.'.state') - ->setFooter(new CList([ +$sections[] = (new CSectionCollapsible($table)) + ->setId(SECTION_SEARCH_TEMPLATEGROUP) + ->setHeader(new CTag('h4', true, _('Template groups'))) + ->setFooter( _s('Displaying %1$s of %2$s found', count($data['template_groups']), $data['total_template_groups_cnt']) - ])); + ) + ->setProfileIdx('web.search.hats.'.SECTION_SEARCH_TEMPLATEGROUP.'.state') + ->setExpanded((bool) CProfile::get('web.search.hats.'.SECTION_SEARCH_TEMPLATEGROUP.'.state', true)); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Search').': '.$data['search']) ->setDocUrl(CDocHelper::getUrl(CDocHelper::SEARCH)) - ->addItem(new CDiv($widgets)) + ->addItem(new CDiv($sections)) ->show(); (new CScriptTag('view.init();')) diff --git a/ui/app/views/service.list.edit.php b/ui/app/views/service.list.edit.php index 0204c4dd2cb..c3af2b06971 100644 --- a/ui/app/views/service.list.edit.php +++ b/ui/app/views/service.list.edit.php @@ -119,7 +119,7 @@ $filter->addFilterTab(_('Filter'), [ ]) ]); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Services')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::SERVICES_SERVICE_EDIT)) ->setControls( diff --git a/ui/app/views/service.list.php b/ui/app/views/service.list.php index c7ef9a32212..b82e443341c 100644 --- a/ui/app/views/service.list.php +++ b/ui/app/views/service.list.php @@ -101,7 +101,7 @@ if ($web_layout_mode == ZBX_LAYOUT_NORMAL) { ]); } -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Services')) ->setWebLayoutMode($web_layout_mode) ->setDocUrl(CDocHelper::getUrl(CDocHelper::SERVICES_SERVICE_LIST)) diff --git a/ui/app/views/sla.list.php b/ui/app/views/sla.list.php index 67e1ecc8461..41b76b4206a 100644 --- a/ui/app/views/sla.list.php +++ b/ui/app/views/sla.list.php @@ -181,7 +181,7 @@ if ($data['has_access'][CRoleHelper::ACTIONS_MANAGE_SLA]) { ); } -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('SLA')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::SERVICES_SLA_LIST)) ->setControls( diff --git a/ui/app/views/slareport.list.php b/ui/app/views/slareport.list.php index 6e4865306b4..7d534b1b4d3 100644 --- a/ui/app/views/slareport.list.php +++ b/ui/app/views/slareport.list.php @@ -88,7 +88,7 @@ $filter = (new CFilter()) ]) ]); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('SLA report')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::SERVICES_SLAREPORT_LIST)) ->addItem($filter); @@ -196,7 +196,7 @@ else { $form->addItem($report); } -$widget +$html_page ->addItem($form) ->show(); diff --git a/ui/app/views/system.warning.php b/ui/app/views/system.warning.php index a03ab3f4061..20543ac8a3b 100644 --- a/ui/app/views/system.warning.php +++ b/ui/app/views/system.warning.php @@ -21,11 +21,15 @@ /** * @var CView $this + * @var array $data */ -$pageHeader = (new CPageHeader(_('Fatal error, please report to the Zabbix team'), CWebUser::getLang())) - ->addCssFile('assets/styles/'.CHtml::encode($data['theme']).'.css') - ->display(); +$page_header = (new CHtmlPageHeader(_('Fatal error, please report to the Zabbix team'), CWebUser::getLang())); + +$page_header + ->setTheme($data['theme']) + ->addCssFile('assets/styles/'.$page_header->getTheme().'.css') + ->show(); $buttons = [ (new CButton('back', _s('Go to "%1$s"', CMenuHelper::getFirstLabel()))) diff --git a/ui/app/views/widget.edit.php b/ui/app/views/widget.edit.php new file mode 100755 index 00000000000..8a57fcd6fb4 --- /dev/null +++ b/ui/app/views/widget.edit.php @@ -0,0 +1,29 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Widget default form view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetFormView($data))->show(); diff --git a/ui/app/views/widget.view.php b/ui/app/views/widget.view.php new file mode 100755 index 00000000000..deb9f49f584 --- /dev/null +++ b/ui/app/views/widget.view.php @@ -0,0 +1,29 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Widget default view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetView($data))->show(); diff --git a/ui/assets/styles/blue-theme.css b/ui/assets/styles/blue-theme.css index 0565707ee38..d59fa10f67e 100644 --- a/ui/assets/styles/blue-theme.css +++ b/ui/assets/styles/blue-theme.css @@ -336,7 +336,9 @@ svg a { top: 0; left: 0; transition: left .2s, top .2s; } - .sortable .sortable-list .sortable-item:not(.sortable-dragging) { + .sortable .sortable-item { + box-sizing: border-box; } + .sortable .sortable-item:not(.sortable-dragging) { transition: left .2s, top .2s; } .sortable.sortable-dragging .sortable-item { position: absolute; } @@ -654,7 +656,6 @@ footer { .form-grid { display: grid; - padding: 5px; row-gap: 10px; column-gap: 10px; grid-template-columns: minmax(15%, max-content) auto; } @@ -670,6 +671,9 @@ footer { word-wrap: break-word; } .form-grid > label.fields-group-label { padding-top: 5px; } + .form-grid > label .icon-help-hint, + .form-grid > label .icon-info { + margin-left: 5px; } .form-grid > .form-field, .form-grid > .field-fluid, .form-grid .form-actions { @@ -872,6 +876,66 @@ footer { .color-picker-dialogue .color-picker-input input { padding-left: 25px; } +.columns-wrapper { + display: flex; + flex-wrap: wrap; + align-items: start; } + .columns-wrapper.columns-nowrap { + flex-wrap: nowrap; } + .columns-wrapper.columns-2 > div, + .columns-wrapper.columns-2 > li { + display: block; + flex: 0 0 50%; + max-width: 50%; } + .columns-wrapper.columns-3 > div, + .columns-wrapper.columns-3 > li { + display: block; + flex: 0 0 33.33333%; + max-width: 33.33333%; } + .columns-wrapper .column-5 { + flex: 0 0 5%; + max-width: 5%; } + .columns-wrapper .column-10 { + flex: 0 0 10%; + max-width: 10%; } + .columns-wrapper .column-15 { + flex: 0 0 15%; + max-width: 15%; } + .columns-wrapper .column-20 { + flex: 0 0 20%; + max-width: 20%; } + .columns-wrapper .column-33 { + flex: 0 0 33.33333%; + max-width: 33.33333%; } + .columns-wrapper .column-35 { + flex: 0 0 35%; + max-width: 35%; } + .columns-wrapper .column-40 { + flex: 0 0 40%; + max-width: 40%; } + .columns-wrapper .column-50 { + flex: 0 0 50%; + max-width: 50%; } + .columns-wrapper .column-75 { + flex: 0 0 75%; + max-width: 75%; } + .columns-wrapper .column-90 { + flex: 0 0 90%; + max-width: 90%; } + .columns-wrapper .column-95 { + flex: 0 0 95%; + max-width: 95%; } + .columns-wrapper .column-center { + display: flex; + justify-content: center; + text-align: center; } + .columns-wrapper .column-middle { + display: flex; + align-items: center; } + .columns-wrapper > div:not(:last-child) section, + .columns-wrapper > ul:not(:last-child) section { + margin-right: 10px; } + .header-kioskmode-controls .dashboard-kioskmode-controls li { margin-right: 6px; } @@ -1421,8 +1485,6 @@ footer { .dashboard-widget .msg-good, .dashboard-widget .msg-warning { margin: 0 10px; } - .dashboard-widget.dashboard-widget-fluid { - margin-right: 0; } .dashboard-grid-widget-content .list-table th:first-child, .dashboard-grid-widget-content .list-table td:first-child, .dashboard-grid-iterator.iterator-alt-content .dashboard-grid-iterator-content > div .list-table th:first-child, .dashboard-grid-iterator.iterator-alt-content .dashboard-grid-iterator-content > div .list-table td:first-child, .dashboard-widget .list-table th:first-child, .dashboard-widget .list-table td:first-child, .overlay-dialogue .list-table th:first-child, .overlay-dialogue .list-table td:first-child { padding-left: 10px; } @@ -1483,30 +1545,22 @@ footer { .wrapper.layout-kioskmode .dashboard-navigation { display: none; } -form.dashboard-widget-clock .fields-group-date, -form.dashboard-widget-clock .fields-group-time, -form.dashboard-widget-clock .fields-group-tzone { +form.dashboard-widget-clock .fields-group.fields-group-date, form.dashboard-widget-clock .fields-group.fields-group-time, form.dashboard-widget-clock .fields-group.fields-group-tzone { display: grid; grid-template-columns: 60px 120px repeat(2, minmax(60px, max-content) auto); align-items: center; column-gap: 10px; row-gap: 5px; } - form.dashboard-widget-clock .fields-group-date label, - form.dashboard-widget-clock .fields-group-time label, - form.dashboard-widget-clock .fields-group-tzone label { + form.dashboard-widget-clock .fields-group.fields-group-date label, form.dashboard-widget-clock .fields-group.fields-group-time label, form.dashboard-widget-clock .fields-group.fields-group-tzone label { text-align: right; } - form.dashboard-widget-clock .fields-group-date .field-size input, - form.dashboard-widget-clock .fields-group-time .field-size input, - form.dashboard-widget-clock .fields-group-tzone .field-size input { + form.dashboard-widget-clock .fields-group.fields-group-date .field-size input, form.dashboard-widget-clock .fields-group.fields-group-time .field-size input, form.dashboard-widget-clock .fields-group.fields-group-tzone .field-size input { margin-right: 5px; } -form.dashboard-widget-clock .fields-group-time .field-format { +form.dashboard-widget-clock .fields-group.fields-group-time .field-format { grid-column: 4 / -1; } -form.dashboard-widget-clock .fields-group-tzone .field-format { - grid-column: 2 / -1; } -form.dashboard-widget-clock .fields-group-tzone .field-timezone { +form.dashboard-widget-clock .fields-group.fields-group-tzone .form-field.field-tzone-timezone, form.dashboard-widget-clock .fields-group.fields-group-tzone .form-field.field-tzone-format { grid-column: 2 / -1; } -div.dashboard-widget-clock.clock-digital { +div.dashboard-widget-clock .clock-digital { box-sizing: border-box; min-height: 100%; padding: 10px; @@ -1514,9 +1568,9 @@ div.dashboard-widget-clock.clock-digital { flex-direction: column; justify-content: center; align-items: center; } - div.dashboard-widget-clock.clock-digital .clock-date, - div.dashboard-widget-clock.clock-digital .clock-time, - div.dashboard-widget-clock.clock-digital .clock-time-zone { + div.dashboard-widget-clock .clock-digital .clock-date, + div.dashboard-widget-clock .clock-digital .clock-time, + div.dashboard-widget-clock .clock-digital .clock-time-zone { max-width: 100%; white-space: nowrap; overflow: hidden; @@ -1524,150 +1578,137 @@ div.dashboard-widget-clock.clock-digital { font-size: calc(var(--content-height) * var(--widget-clock-font) / 1.14); line-height: 1.14; flex-shrink: 0; } - div.dashboard-widget-clock.clock-digital .bold { + div.dashboard-widget-clock .clock-digital .bold { font-weight: bold; } - div.dashboard-widget-clock.clock-digital .clock-disabled { + div.dashboard-widget-clock .clock-digital .clock-disabled { font-size: calc(var(--content-height) * 0.6 / 1.14); color: #768d99; font-weight: bold; } -form.dashboard-widget-item .fields-group-description, -form.dashboard-widget-item .fields-group-value, -form.dashboard-widget-item .fields-group-time, -form.dashboard-widget-item .fields-group-change-indicator { +.dashboard-widget-inaccessible { + display: grid; + align-items: center; + padding-right: 10px; + padding-left: 10px; + text-align: center; + color: #768d99; } + +form.dashboard-widget-item .fields-group.fields-group-description, form.dashboard-widget-item .fields-group.fields-group-value, form.dashboard-widget-item .fields-group.fields-group-time, form.dashboard-widget-item .fields-group.fields-group-change-indicator { display: grid; grid-template-columns: minmax(100px, max-content) 3fr max-content auto; align-items: center; column-gap: 10px; row-gap: 5px; } - form.dashboard-widget-item .fields-group-description label, - form.dashboard-widget-item .fields-group-value label, - form.dashboard-widget-item .fields-group-time label, - form.dashboard-widget-item .fields-group-change-indicator label { + form.dashboard-widget-item .fields-group.fields-group-description label, form.dashboard-widget-item .fields-group.fields-group-value label, form.dashboard-widget-item .fields-group.fields-group-time label, form.dashboard-widget-item .fields-group.fields-group-change-indicator label { text-align: right; } - form.dashboard-widget-item .fields-group-description hr, - form.dashboard-widget-item .fields-group-value hr, - form.dashboard-widget-item .fields-group-time hr, - form.dashboard-widget-item .fields-group-change-indicator hr { + form.dashboard-widget-item .fields-group.fields-group-description hr, form.dashboard-widget-item .fields-group.fields-group-value hr, form.dashboard-widget-item .fields-group.fields-group-time hr, form.dashboard-widget-item .fields-group.fields-group-change-indicator hr { grid-column: 1 / -1; margin: 0; width: 100%; border: solid #ebeef0; border-width: 1px 0 0 0; } - form.dashboard-widget-item .fields-group-description .field-fluid, - form.dashboard-widget-item .fields-group-value .field-fluid, - form.dashboard-widget-item .fields-group-time .field-fluid, - form.dashboard-widget-item .fields-group-change-indicator .field-fluid { + form.dashboard-widget-item .fields-group.fields-group-description .field-fluid, form.dashboard-widget-item .fields-group.fields-group-value .field-fluid, form.dashboard-widget-item .fields-group.fields-group-time .field-fluid, form.dashboard-widget-item .fields-group.fields-group-change-indicator .field-fluid { grid-column: 2 / -1; } - form.dashboard-widget-item .fields-group-description .offset-3, - form.dashboard-widget-item .fields-group-value .offset-3, - form.dashboard-widget-item .fields-group-time .offset-3, - form.dashboard-widget-item .fields-group-change-indicator .offset-3 { + form.dashboard-widget-item .fields-group.fields-group-description .offset-3, form.dashboard-widget-item .fields-group.fields-group-value .offset-3, form.dashboard-widget-item .fields-group.fields-group-time .offset-3, form.dashboard-widget-item .fields-group.fields-group-change-indicator .offset-3 { grid-column-start: 3; } - form.dashboard-widget-item .fields-group-description .field-size input, - form.dashboard-widget-item .fields-group-value .field-size input, - form.dashboard-widget-item .fields-group-time .field-size input, - form.dashboard-widget-item .fields-group-change-indicator .field-size input { + form.dashboard-widget-item .fields-group.fields-group-description .field-size input, form.dashboard-widget-item .fields-group.fields-group-value .field-size input, form.dashboard-widget-item .fields-group.fields-group-time .field-size input, form.dashboard-widget-item .fields-group.fields-group-change-indicator .field-size input { margin-right: 5px; } - form.dashboard-widget-item .fields-group-description .form-field, - form.dashboard-widget-item .fields-group-value .form-field, - form.dashboard-widget-item .fields-group-time .form-field, - form.dashboard-widget-item .fields-group-change-indicator .form-field { + form.dashboard-widget-item .fields-group.fields-group-description .form-field, form.dashboard-widget-item .fields-group.fields-group-value .form-field, form.dashboard-widget-item .fields-group.fields-group-time .form-field, form.dashboard-widget-item .fields-group.fields-group-change-indicator .form-field { line-height: 24px; } -form.dashboard-widget-item .fields-group-description .form-field:nth-child(1) { +form.dashboard-widget-item .fields-group.fields-group-description .form-field:nth-child(1) { grid-column: 1 / -1; } -form.dashboard-widget-item .fields-group-value { +form.dashboard-widget-item .fields-group.fields-group-value { grid-template-columns: minmax(100px, max-content) 3fr max-content auto; } - form.dashboard-widget-item .fields-group-value .units-show { + form.dashboard-widget-item .fields-group.fields-group-value .units-show { display: flex; } - form.dashboard-widget-item .fields-group-value .units-show label[for='units'] { + form.dashboard-widget-item .fields-group.fields-group-value .units-show label[for='units'] { width: 100%; } -form.dashboard-widget-item .fields-group-change-indicator { +form.dashboard-widget-item .fields-group.fields-group-change-indicator { grid-template-columns: repeat(3, max-content 96px); } -form.dashboard-widget-item .fields-group-change-indicator .input-color-picker { - display: block; } + form.dashboard-widget-item .fields-group.fields-group-change-indicator .input-color-picker { + display: block; } -div.dashboard-widget-item { +div.dashboard-widget-item > div { box-sizing: border-box; height: 100%; padding: 10px; overflow-x: hidden; } - div.dashboard-widget-item a { - box-sizing: border-box; - display: flex; - flex-direction: column; - height: 100%; - color: inherit; } - div.dashboard-widget-item a:focus, div.dashboard-widget-item a:hover, div.dashboard-widget-item a:visited { - border: none; } - div.dashboard-widget-item a > div { - display: flex; - flex: 1 1 calc(100% / 3); } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .item-value, - div.dashboard-widget-item .item-time { - flex: 1 1 auto; - max-width: 100%; } - div.dashboard-widget-item .item-value { +div.dashboard-widget-item a { + box-sizing: border-box; + display: flex; + flex-direction: column; + height: 100%; + color: inherit; } + div.dashboard-widget-item a:focus, div.dashboard-widget-item a:hover, div.dashboard-widget-item a:visited { + border: none; } + div.dashboard-widget-item a > div { display: flex; - flex-wrap: wrap; - margin: 0 5px; } - div.dashboard-widget-item .item-value > .units:first-child, div.dashboard-widget-item .item-value > .units:last-child { - flex: 0 0 100%; } - div.dashboard-widget-item .item-value > .units:first-child { - margin-bottom: -0.07em; } - div.dashboard-widget-item .item-value > .units:last-child { - margin-top: -0.07em; } - div.dashboard-widget-item .item-value.type-text { + flex: 1 1 calc(100% / 3); } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .item-value, +div.dashboard-widget-item .item-time { + flex: 1 1 auto; + max-width: 100%; } +div.dashboard-widget-item .item-value { + display: flex; + flex-wrap: wrap; + margin: 0 5px; } + div.dashboard-widget-item .item-value > .units:first-child, div.dashboard-widget-item .item-value > .units:last-child { + flex: 0 0 100%; } + div.dashboard-widget-item .item-value > .units:first-child { + margin-bottom: -0.07em; } + div.dashboard-widget-item .item-value > .units:last-child { + margin-top: -0.07em; } + div.dashboard-widget-item .item-value.type-text { + min-width: 0; } + div.dashboard-widget-item .item-value.type-text .item-value-content { min-width: 0; } - div.dashboard-widget-item .item-value.type-text .item-value-content { - min-width: 0; } - div.dashboard-widget-item .item-value-content { - display: flex; - align-items: baseline; - overflow: hidden; } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .item-time, - div.dashboard-widget-item .type-text .value { - display: block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .value, - div.dashboard-widget-item .decimals, - div.dashboard-widget-item .units, - div.dashboard-widget-item .item-time { - font-size: calc(var(--content-height) * var(--widget-item-font) / 1.14); - line-height: 1.14; } - div.dashboard-widget-item .units:not(:last-child), - div.dashboard-widget-item .change-indicator:not(:last-child) { - margin-right: 5px; } - div.dashboard-widget-item .units:not(:first-child), - div.dashboard-widget-item .change-indicator:not(:first-child) { - margin-left: 5px; } - div.dashboard-widget-item .svg-arrow { - height: calc(var(--content-height) * var(--widget-item-font) * 0.72 / 1.14); } - div.dashboard-widget-item .item-value-no-data { - color: #768d99; } - div.dashboard-widget-item .left { - justify-content: flex-start; - max-width: max-content; - margin-right: auto; } - div.dashboard-widget-item .center { - justify-content: center; } - div.dashboard-widget-item .right { - justify-content: flex-end; - max-width: max-content; - margin-left: auto; } - div.dashboard-widget-item .top { - align-self: flex-start; } - div.dashboard-widget-item .middle { - align-self: center; } - div.dashboard-widget-item .bottom { - align-self: flex-end; } - div.dashboard-widget-item .bold { - font-weight: bold; } +div.dashboard-widget-item .item-value-content { + display: flex; + align-items: baseline; + overflow: hidden; } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .item-time, +div.dashboard-widget-item .type-text .value { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .value, +div.dashboard-widget-item .decimals, +div.dashboard-widget-item .units, +div.dashboard-widget-item .item-time { + font-size: calc(var(--content-height) * var(--widget-item-font) / 1.14); + line-height: 1.14; } +div.dashboard-widget-item .units:not(:last-child), +div.dashboard-widget-item .change-indicator:not(:last-child) { + margin-right: 5px; } +div.dashboard-widget-item .units:not(:first-child), +div.dashboard-widget-item .change-indicator:not(:first-child) { + margin-left: 5px; } +div.dashboard-widget-item .svg-arrow { + height: calc(var(--content-height) * var(--widget-item-font) * 0.72 / 1.14); } +div.dashboard-widget-item .item-value-no-data { + color: #768d99; } +div.dashboard-widget-item .left { + justify-content: flex-start; + max-width: max-content; + margin-right: auto; } +div.dashboard-widget-item .center { + justify-content: center; } +div.dashboard-widget-item .right { + justify-content: flex-end; + max-width: max-content; + margin-left: auto; } +div.dashboard-widget-item .top { + align-self: flex-start; } +div.dashboard-widget-item .middle { + align-self: center; } +div.dashboard-widget-item .bottom { + align-self: flex-end; } +div.dashboard-widget-item .bold { + font-weight: bold; } .dashboard-widget-item .svg-arrow-up { fill: #3DC51D; } @@ -1680,40 +1721,47 @@ div.dashboard-widget-slareport .date-vertical { writing-mode: vertical-lr; transform: rotate(180deg); } +form.dashboard-widget-svggraph .svg-graph-preview, form.dashboard-widget-svggraph .graph-widget-config-tabs { - padding: 10px 0; } - form.dashboard-widget-svggraph .graph-widget-config-tabs > .tabs-nav { - margin-right: 0; - margin-left: 0; - border-top: 1px solid #dfe4e7; } - form.dashboard-widget-svggraph .graph-widget-config-tabs .ui-tabs-nav { - position: sticky; + grid-column: 1 / -1; } +form.dashboard-widget-svggraph .svg-graph-preview { + position: relative; + min-width: 1110px; + height: 300px; } + form.dashboard-widget-svggraph .svg-graph-preview > div { + position: absolute; top: 0; + right: 0; + left: 0; + margin: 0 -10px; + height: 300px; background: #ffffff; z-index: 3; } +form.dashboard-widget-svggraph .graph-widget-config-tabs > .tabs-nav { + border-top: 1px solid #dfe4e7; } +form.dashboard-widget-svggraph .graph-widget-config-tabs .ui-tabs-nav { + position: sticky; + top: 0; + background: #ffffff; + z-index: 3; } form.dashboard-widget-svggraph .table-forms-container, form.dashboard-widget-svggraph .browser-warning-container { + margin: -10px 0 0 0; border: 1px solid #dfe4e7; border-top: none; } form.dashboard-widget-svggraph .table-forms-separator { padding: 0; } -form.dashboard-widget-svggraph .dataset-head { - display: grid; - grid-template-columns: 24px 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; } +form.dashboard-widget-svggraph .dataset-head, form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body { - display: grid; - grid-template-columns: 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; - position: relative; - margin-top: 10px; } - form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body .form-grid { - padding-top: 0; } - form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body .form-grid:first-child { - grid-column-start: 2; } + display: contents; } +form.dashboard-widget-svggraph .dataset-head .multiselect { + width: 100%; } +form.dashboard-widget-svggraph .dataset-body .form-grid { + padding-top: 0; } + form.dashboard-widget-svggraph .dataset-body .form-grid:first-child { + grid-column-start: 3; } form.dashboard-widget-svggraph .drag-icon { position: absolute; + top: 5px; left: -14px; } form.dashboard-widget-svggraph .td-drag-icon .drag-icon { top: 0; @@ -1735,13 +1783,13 @@ form.dashboard-widget-svggraph .list-vertical-accordion { overflow: visible; margin-top: -5px; margin-bottom: -5px; } - form.dashboard-widget-svggraph .list-vertical-accordion .list-accordion-item-head { - padding: 0; } form.dashboard-widget-svggraph .list-accordion-item { position: relative; - width: 100%; - padding: 5px 0; - list-style-type: none; } + display: grid; + grid-template-columns: 24px 24px 1fr 1fr 24px; + grid-gap: 10px; + align-items: start; + padding: 5px 0; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-opened::before { content: ' '; position: absolute; @@ -1753,8 +1801,6 @@ form.dashboard-widget-svggraph .list-accordion-item { form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .multiselect { height: 24px; overflow: hidden; } - form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-body { - display: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .table-forms-separator { border: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table thead, @@ -1762,6 +1808,8 @@ form.dashboard-widget-svggraph .list-accordion-item { form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table .table-col-handle, form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table .table-col-action { display: none; } + form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-body { + display: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .items-list { padding-left: 0; } form.dashboard-widget-svggraph .single-item-table .table-col-handle { @@ -1780,11 +1828,83 @@ form.dashboard-widget-svggraph .single-item-table .single-item-table-row:last-ch padding-bottom: 0; } form.dashboard-widget-svggraph .single-item-table tfoot td { padding: 5px 5px 5px 10px; } +form.dashboard-widget-svggraph .overrides-list { + position: relative; + margin: -5px 0 -5px 15px; } +form.dashboard-widget-svggraph .overrides-list-item { + position: relative; + display: grid; + grid-template-columns: 1fr 1fr 24px; + grid-gap: 5px 10px; + align-items: start; + padding: 5px 0; } + form.dashboard-widget-svggraph .overrides-list-item.sortable { + overflow: visible; + margin-top: -5px; + margin-bottom: -5px; } + form.dashboard-widget-svggraph .overrides-list-item .multiselect { + width: 100%; } + form.dashboard-widget-svggraph .overrides-list-item .btn-remove { + right: 0; + top: 0; + vertical-align: baseline; } +form.dashboard-widget-svggraph .overrides-foot { + padding: 5px 0; } +form.dashboard-widget-svggraph .overrides-options-list { + grid-column: 1 / -1; + padding: 0 24px 8px 0; + border-bottom: 1px solid #ebeef0; + white-space: normal; } + form.dashboard-widget-svggraph .overrides-options-list > li { + display: inline-block; + margin-right: 5px; + margin-bottom: 2px; + line-height: 22px; + white-space: nowrap; } + form.dashboard-widget-svggraph .overrides-options-list > li .color-picker { + line-height: 22px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div { + position: relative; + padding: 1px 18px 1px 1px; + background-color: #768d99; + border-radius: 2px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > span { + color: white; + padding-left: 8px; + line-height: 22px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > input[type=text] { + border-style: none; + line-height: 22px; + min-height: 22px; + width: 85px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + position: absolute; + right: 0; + top: 0; + min-height: 24px; } + form.dashboard-widget-svggraph .overrides-options-list .btn-alt .plus-icon { + margin-right: 0; } + form.dashboard-widget-svggraph .overrides-options-list .color-picker .color-picker-preview { + margin: 1px; + width: 20px; + min-height: 20px; + background-position: -323px -411px; } form.dashboard-widget-svggraph .no-items-message { display: none; line-height: 24px; color: #768d99; } +[theme="hc-dark"] form.dashboard-widget-svggraph .overrides-options-list > li > div { + border: 1px solid #0275b8; + background-color: transparent !important; } + [theme="hc-dark"] form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + border: none !important; + top: 0; } + +[theme="hc-light"] form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + border: none !important; + top: 0; } + form.dashboard-widget-tophosts #list_columns .text { max-width: 250px; } form.dashboard-widget-tophosts #column { @@ -2557,6 +2677,49 @@ div.dashboard-widget-tophosts z-bar-gauge { font-size: 0; border-left: 1px solid #ebeef0; } +section { + background-color: #ffffff; + border: 1px solid #dfe4e7; } + section .section-head { + display: flex; + height: 32px; + line-height: 32px; } + section .section-head h4 { + padding: 0 10px; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + font-weight: bold; + line-height: inherit; + color: #3c5563; } + section .section-toggle { + width: 24px; + height: 24px; + margin: 2px 2px 0 auto; + background: url("../img/icon-sprite.svg?20220722") no-repeat -6px -654px; } + section .section-foot { + padding: 0 10px; + text-align: right; + line-height: 32px; + color: #768d99; } + section.section-collapsed .section-body, + section.section-collapsed .section-foot { + display: none; } + section.section-collapsed .section-toggle { + background-position: -6px -689px; } + section:not(:last-child) { + margin-bottom: 10px; } + section .list-table { + border: 0; } + section .list-table tbody tr:last-child td { + border-bottom: 1px solid #ebeef0; } + section .list-table td:first-child, + section .list-table th:first-child { + padding-left: 10px; } + section .list-table td:last-child, + section .list-table th:last-child { + padding-right: 10px; } + .service-info { margin: -10px 0; border-left: 4px solid #429e47; } @@ -4536,13 +4699,13 @@ button { width: 24px; height: 24px; } -.filter-container.tabfilter-container .icon-edit, .btn-dashboard-page-properties, .btn-iterator-page-previous, .btn-iterator-page-next, .btn-widget-action, .btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle, .btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle, .btn-widget-edit, .btn-alarm-on, .btn-alarm-off, .btn-sound-on, .btn-sound-off, .btn-info-clock, .btn-dashboard-conf, .interfaces .interface-row[data-type="2"] .interface-btn-toggle { +section .section-toggle, .filter-container.tabfilter-container .icon-edit, .btn-dashboard-page-properties, .btn-iterator-page-previous, .btn-iterator-page-next, .btn-widget-action, .btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle, .btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle, .btn-widget-edit, .btn-alarm-on, .btn-alarm-off, .btn-sound-on, .btn-sound-off, .btn-info-clock, .btn-dashboard-conf, .interfaces .interface-row[data-type="2"] .interface-btn-toggle { border: 0; min-height: 0; padding: 0; opacity: .5; transition: opacity .2s ease-out; } - .filter-container.tabfilter-container [disabled].icon-edit, [disabled].btn-dashboard-page-properties, [disabled].btn-iterator-page-previous, [disabled].btn-iterator-page-next, [disabled].btn-widget-action, [disabled].btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle, [disabled].btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle, [disabled].btn-widget-edit, [disabled].btn-alarm-on, [disabled].btn-alarm-off, [disabled].btn-sound-on, [disabled].btn-sound-off, [disabled].btn-info-clock, [disabled].btn-dashboard-conf, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle, .filter-container.tabfilter-container [disabled].icon-edit:hover, [disabled].btn-dashboard-page-properties:hover, [disabled].btn-iterator-page-previous:hover, [disabled].btn-iterator-page-next:hover, [disabled].btn-widget-action:hover, [disabled].btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-edit:hover, [disabled].btn-alarm-on:hover, [disabled].btn-alarm-off:hover, [disabled].btn-sound-on:hover, [disabled].btn-sound-off:hover, [disabled].btn-info-clock:hover, [disabled].btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:hover, .filter-container.tabfilter-container [disabled].icon-edit:focus, [disabled].btn-dashboard-page-properties:focus, [disabled].btn-iterator-page-previous:focus, [disabled].btn-iterator-page-next:focus, [disabled].btn-widget-action:focus, [disabled].btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-edit:focus, [disabled].btn-alarm-on:focus, [disabled].btn-alarm-off:focus, [disabled].btn-sound-on:focus, [disabled].btn-sound-off:focus, [disabled].btn-info-clock:focus, [disabled].btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:focus, .filter-container.tabfilter-container [disabled].icon-edit:active, [disabled].btn-dashboard-page-properties:active, [disabled].btn-iterator-page-previous:active, [disabled].btn-iterator-page-next:active, [disabled].btn-widget-action:active, [disabled].btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-edit:active, [disabled].btn-alarm-on:active, [disabled].btn-alarm-off:active, [disabled].btn-sound-on:active, [disabled].btn-sound-off:active, [disabled].btn-info-clock:active, [disabled].btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:active { + section [disabled].section-toggle, .filter-container.tabfilter-container [disabled].icon-edit, [disabled].btn-dashboard-page-properties, [disabled].btn-iterator-page-previous, [disabled].btn-iterator-page-next, [disabled].btn-widget-action, [disabled].btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle, [disabled].btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle, [disabled].btn-widget-edit, [disabled].btn-alarm-on, [disabled].btn-alarm-off, [disabled].btn-sound-on, [disabled].btn-sound-off, [disabled].btn-info-clock, [disabled].btn-dashboard-conf, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle, section [disabled].section-toggle:hover, .filter-container.tabfilter-container [disabled].icon-edit:hover, [disabled].btn-dashboard-page-properties:hover, [disabled].btn-iterator-page-previous:hover, [disabled].btn-iterator-page-next:hover, [disabled].btn-widget-action:hover, [disabled].btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-edit:hover, [disabled].btn-alarm-on:hover, [disabled].btn-alarm-off:hover, [disabled].btn-sound-on:hover, [disabled].btn-sound-off:hover, [disabled].btn-info-clock:hover, [disabled].btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:hover, section [disabled].section-toggle:focus, .filter-container.tabfilter-container [disabled].icon-edit:focus, [disabled].btn-dashboard-page-properties:focus, [disabled].btn-iterator-page-previous:focus, [disabled].btn-iterator-page-next:focus, [disabled].btn-widget-action:focus, [disabled].btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-edit:focus, [disabled].btn-alarm-on:focus, [disabled].btn-alarm-off:focus, [disabled].btn-sound-on:focus, [disabled].btn-sound-off:focus, [disabled].btn-info-clock:focus, [disabled].btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:focus, section [disabled].section-toggle:active, .filter-container.tabfilter-container [disabled].icon-edit:active, [disabled].btn-dashboard-page-properties:active, [disabled].btn-iterator-page-previous:active, [disabled].btn-iterator-page-next:active, [disabled].btn-widget-action:active, [disabled].btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-edit:active, [disabled].btn-alarm-on:active, [disabled].btn-alarm-off:active, [disabled].btn-sound-on:active, [disabled].btn-sound-off:active, [disabled].btn-info-clock:active, [disabled].btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:active { background-color: transparent; opacity: .25; } @@ -4570,7 +4733,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active { .inaccessible .subfilter-enabled { color: #bfbfbf; } -.filter-container.tabfilter-container .icon-edit:hover, .btn-dashboard-page-properties:hover, .btn-iterator-page-previous:hover, .btn-iterator-page-next:hover, .btn-widget-action:hover, .btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:hover, .btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:hover, .btn-widget-edit:hover, .btn-alarm-on:hover, .btn-alarm-off:hover, .btn-sound-on:hover, .btn-sound-off:hover, .btn-info-clock:hover, .btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:hover, .filter-container.tabfilter-container .icon-edit:focus, .btn-dashboard-page-properties:focus, .btn-iterator-page-previous:focus, .btn-iterator-page-next:focus, .btn-widget-action:focus, .btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:focus, .btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:focus, .btn-widget-edit:focus, .btn-alarm-on:focus, .btn-alarm-off:focus, .btn-sound-on:focus, .btn-sound-off:focus, .btn-info-clock:focus, .btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:focus, .filter-container.tabfilter-container .icon-edit:active, .btn-dashboard-page-properties:active, .btn-iterator-page-previous:active, .btn-iterator-page-next:active, .btn-widget-action:active, .btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:active, .btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:active, .btn-widget-edit:active, .btn-alarm-on:active, .btn-alarm-off:active, .btn-sound-on:active, .btn-sound-off:active, .btn-info-clock:active, .btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:active { +section .section-toggle:hover, .filter-container.tabfilter-container .icon-edit:hover, .btn-dashboard-page-properties:hover, .btn-iterator-page-previous:hover, .btn-iterator-page-next:hover, .btn-widget-action:hover, .btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:hover, .btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:hover, .btn-widget-edit:hover, .btn-alarm-on:hover, .btn-alarm-off:hover, .btn-sound-on:hover, .btn-sound-off:hover, .btn-info-clock:hover, .btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:hover, section .section-toggle:focus, .filter-container.tabfilter-container .icon-edit:focus, .btn-dashboard-page-properties:focus, .btn-iterator-page-previous:focus, .btn-iterator-page-next:focus, .btn-widget-action:focus, .btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:focus, .btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:focus, .btn-widget-edit:focus, .btn-alarm-on:focus, .btn-alarm-off:focus, .btn-sound-on:focus, .btn-sound-off:focus, .btn-info-clock:focus, .btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:focus, section .section-toggle:active, .filter-container.tabfilter-container .icon-edit:active, .btn-dashboard-page-properties:active, .btn-iterator-page-previous:active, .btn-iterator-page-next:active, .btn-widget-action:active, .btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:active, .btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:active, .btn-widget-edit:active, .btn-alarm-on:active, .btn-alarm-off:active, .btn-sound-on:active, .btn-sound-off:active, .btn-info-clock:active, .btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:active { background-color: transparent; opacity: 1; } @@ -4663,16 +4826,16 @@ button[disabled], button[disabled]:hover, button[disabled]:active { content: ''; } .icon-tree-top-bottom::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -300px; } + background-position: -84px -300px; } .icon-tree-top-bottom-right::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -334px; } + background-position: -84px -334px; } .icon-tree-top-right::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -372px; } + background-position: -84px -372px; } .icon-tree-empty::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -350px; } + background-position: -84px -350px; } .icon-cal { background: transparent url("../img/icon-sprite.svg?20220722") no-repeat -42px -834px; } @@ -4953,7 +5116,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active { overflow: hidden; margin: 0 10px; } .overlay-dialogue.modal .dashboard-widget-head { - margin-bottom: 14px; } + margin-bottom: 12px; } .overlay-dialogue.modal .dashboard-widget-head .icon-doc-link { margin-right: -26px; } .overlay-dialogue.modal .dashboard-widget-head .overlay-close-btn { @@ -4966,9 +5129,11 @@ button[disabled], button[disabled]:hover, button[disabled]:active { width: 100%; max-height: calc(100vh - 220px); max-width: inherit; - margin: 0 -10px 10px; + margin: 0 -10px 8px; padding: 0 10px; position: relative; } + .overlay-dialogue.modal .overlay-dialogue-body > form { + padding: 2px 0; } .overlay-dialogue.modal .overlay-dialogue-body .table-forms .table-forms-td-right { padding-right: 8px; } .overlay-dialogue.modal .overlay-dialogue-body .table-forms .table-forms-row-with-second-field { @@ -5365,20 +5530,6 @@ button[disabled], button[disabled]:hover, button[disabled]:active { stroke: #e33734; stroke-width: 2px; } -.svg-graph-preview { - margin-top: 10px; - min-width: 1120px; - height: 300px; - position: relative; } - .svg-graph-preview > div { - background: #ffffff; - height: 300px; - position: absolute; - left: 0; - right: 0; - top: 0; - z-index: 3; } - .svg-graph-hintbox { font-size: 12px; line-height: 18px; @@ -5931,22 +6082,22 @@ span.is-loading { padding: 10px 0 0; text-align: center; } -.dashboard-grid-widget-content, div.dashboard-widget-item, .msg-details ul, z-select button.focusable, +.dashboard-grid-widget-content, div.dashboard-widget-item > div, .msg-details ul, z-select button.focusable, .z-select button.focusable, z-select .list, .z-select .list, .multiselect-available, textarea, select, .setup-right-body, .overlay-dialogue.modal .overlay-dialogue-body, .overlay-dialogue .hintbox-wrap, .overlay-dialogue .maps-container, .notif-body, .debug-output, .overlay-descr, .overflow-table, .import-compare .toc, .import-compare .diff { scrollbar-width: thin; } - .dashboard-grid-widget-content::-webkit-scrollbar, div.dashboard-widget-item::-webkit-scrollbar, .msg-details ul::-webkit-scrollbar, z-select button.focusable::-webkit-scrollbar, + .dashboard-grid-widget-content::-webkit-scrollbar, div.dashboard-widget-item > div::-webkit-scrollbar, .msg-details ul::-webkit-scrollbar, z-select button.focusable::-webkit-scrollbar, .z-select button.focusable::-webkit-scrollbar, z-select .list::-webkit-scrollbar, .z-select .list::-webkit-scrollbar, .multiselect-available::-webkit-scrollbar, textarea::-webkit-scrollbar, select::-webkit-scrollbar, .setup-right-body::-webkit-scrollbar, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar, .overlay-dialogue .maps-container::-webkit-scrollbar, .notif-body::-webkit-scrollbar, .debug-output::-webkit-scrollbar, .overlay-descr::-webkit-scrollbar, .overflow-table::-webkit-scrollbar, .import-compare .toc::-webkit-scrollbar, .import-compare .diff::-webkit-scrollbar { width: 9px; } - .dashboard-grid-widget-content::-webkit-scrollbar-track, div.dashboard-widget-item::-webkit-scrollbar-track, .msg-details ul::-webkit-scrollbar-track, z-select button.focusable::-webkit-scrollbar-track, + .dashboard-grid-widget-content::-webkit-scrollbar-track, div.dashboard-widget-item > div::-webkit-scrollbar-track, .msg-details ul::-webkit-scrollbar-track, z-select button.focusable::-webkit-scrollbar-track, .z-select button.focusable::-webkit-scrollbar-track, z-select .list::-webkit-scrollbar-track, .z-select .list::-webkit-scrollbar-track, .multiselect-available::-webkit-scrollbar-track, textarea::-webkit-scrollbar-track, select::-webkit-scrollbar-track, .setup-right-body::-webkit-scrollbar-track, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar-track, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar-track, .overlay-dialogue .maps-container::-webkit-scrollbar-track, .notif-body::-webkit-scrollbar-track, .debug-output::-webkit-scrollbar-track, .overlay-descr::-webkit-scrollbar-track, .overflow-table::-webkit-scrollbar-track, .import-compare .toc::-webkit-scrollbar-track, .import-compare .diff::-webkit-scrollbar-track { background-color: rgba(172, 187, 194, 0.55); } - .dashboard-grid-widget-content::-webkit-scrollbar-thumb, div.dashboard-widget-item::-webkit-scrollbar-thumb, .msg-details ul::-webkit-scrollbar-thumb, z-select button.focusable::-webkit-scrollbar-thumb, + .dashboard-grid-widget-content::-webkit-scrollbar-thumb, div.dashboard-widget-item > div::-webkit-scrollbar-thumb, .msg-details ul::-webkit-scrollbar-thumb, z-select button.focusable::-webkit-scrollbar-thumb, .z-select button.focusable::-webkit-scrollbar-thumb, z-select .list::-webkit-scrollbar-thumb, .z-select .list::-webkit-scrollbar-thumb, .multiselect-available::-webkit-scrollbar-thumb, textarea::-webkit-scrollbar-thumb, select::-webkit-scrollbar-thumb, .setup-right-body::-webkit-scrollbar-thumb, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar-thumb, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar-thumb, .overlay-dialogue .maps-container::-webkit-scrollbar-thumb, .notif-body::-webkit-scrollbar-thumb, .debug-output::-webkit-scrollbar-thumb, .overlay-descr::-webkit-scrollbar-thumb, .overflow-table::-webkit-scrollbar-thumb, .import-compare .toc::-webkit-scrollbar-thumb, .import-compare .diff::-webkit-scrollbar-thumb { @@ -6087,53 +6238,6 @@ svg { white-space: normal; word-break: break-word; } -.overrides-list { - display: table; - width: 90%; - max-width: 738px; - padding-left: 15px; } - .overrides-list .overrides-list-item { - display: table-row; } - .overrides-list .overrides-list-item .btn-remove { - position: relative; - right: -73px; - top: 3px; } - -.overrides-options-list { - white-space: normal; - padding: 5px 0 8px; - margin-bottom: 10px; - border-bottom: 1px solid #ebeef0; } - .overrides-options-list > li { - display: inline-block; - margin: 2px 7px 2px 0; - white-space: nowrap; - vertical-align: middle; } - .overrides-options-list > li > div { - position: relative; - padding: 1px 18px 1px 1px; - background-color: #768d99; - border-radius: 2px; } - .overrides-options-list > li > div > span { - color: white; - padding-left: 8px; - line-height: 22px; } - .overrides-options-list > li > div > input[type=text] { - border-style: none; - line-height: 22px; - min-height: 22px; - width: 85px; } - .overrides-options-list > li > div > .subfilter-disable-btn { - position: absolute; - right: 0; - top: 0; - min-height: 24px; } - .overrides-options-list .color-picker .color-picker-preview { - margin: 1px; - width: 20px; - min-height: 20px; - background-position: -323px -411px; } - .list-accordion-foot > div { display: table-cell; padding-top: 10px; } @@ -6179,63 +6283,6 @@ svg { text-overflow: ellipsis; line-height: 24px; } -.columns-wrapper { - display: flex; - flex-wrap: wrap; - align-items: start; } - .columns-wrapper.columns-nowrap { - flex-wrap: nowrap; } - .columns-wrapper.columns-2 > div, - .columns-wrapper.columns-2 > li { - display: block; - flex: 0 0 50%; - max-width: 50%; } - .columns-wrapper.columns-3 > div, - .columns-wrapper.columns-3 > li { - display: block; - flex: 0 0 33.33333%; - max-width: 33.33333%; } - .columns-wrapper .column-5 { - flex: 0 0 5%; - max-width: 5%; } - .columns-wrapper .column-10 { - flex: 0 0 10%; - max-width: 10%; } - .columns-wrapper .column-15 { - flex: 0 0 15%; - max-width: 15%; } - .columns-wrapper .column-20 { - flex: 0 0 20%; - max-width: 20%; } - .columns-wrapper .column-33 { - flex: 0 0 33.33333%; - max-width: 33.33333%; } - .columns-wrapper .column-35 { - flex: 0 0 35%; - max-width: 35%; } - .columns-wrapper .column-40 { - flex: 0 0 40%; - max-width: 40%; } - .columns-wrapper .column-50 { - flex: 0 0 50%; - max-width: 50%; } - .columns-wrapper .column-75 { - flex: 0 0 75%; - max-width: 75%; } - .columns-wrapper .column-90 { - flex: 0 0 90%; - max-width: 90%; } - .columns-wrapper .column-95 { - flex: 0 0 95%; - max-width: 95%; } - .columns-wrapper .column-center { - display: flex; - justify-content: center; - text-align: center; } - .columns-wrapper .column-middle { - display: flex; - align-items: center; } - .preprocessing-list { display: block; max-width: 930px; diff --git a/ui/assets/styles/dark-theme.css b/ui/assets/styles/dark-theme.css index 6e4aaf7960b..238ffee0199 100644 --- a/ui/assets/styles/dark-theme.css +++ b/ui/assets/styles/dark-theme.css @@ -349,7 +349,9 @@ svg a { top: 0; left: 0; transition: left .2s, top .2s; } - .sortable .sortable-list .sortable-item:not(.sortable-dragging) { + .sortable .sortable-item { + box-sizing: border-box; } + .sortable .sortable-item:not(.sortable-dragging) { transition: left .2s, top .2s; } .sortable.sortable-dragging .sortable-item { position: absolute; } @@ -667,7 +669,6 @@ footer { .form-grid { display: grid; - padding: 5px; row-gap: 10px; column-gap: 10px; grid-template-columns: minmax(15%, max-content) auto; } @@ -683,6 +684,9 @@ footer { word-wrap: break-word; } .form-grid > label.fields-group-label { padding-top: 5px; } + .form-grid > label .icon-help-hint, + .form-grid > label .icon-info { + margin-left: 5px; } .form-grid > .form-field, .form-grid > .field-fluid, .form-grid .form-actions { @@ -885,6 +889,66 @@ footer { .color-picker-dialogue .color-picker-input input { padding-left: 25px; } +.columns-wrapper { + display: flex; + flex-wrap: wrap; + align-items: start; } + .columns-wrapper.columns-nowrap { + flex-wrap: nowrap; } + .columns-wrapper.columns-2 > div, + .columns-wrapper.columns-2 > li { + display: block; + flex: 0 0 50%; + max-width: 50%; } + .columns-wrapper.columns-3 > div, + .columns-wrapper.columns-3 > li { + display: block; + flex: 0 0 33.33333%; + max-width: 33.33333%; } + .columns-wrapper .column-5 { + flex: 0 0 5%; + max-width: 5%; } + .columns-wrapper .column-10 { + flex: 0 0 10%; + max-width: 10%; } + .columns-wrapper .column-15 { + flex: 0 0 15%; + max-width: 15%; } + .columns-wrapper .column-20 { + flex: 0 0 20%; + max-width: 20%; } + .columns-wrapper .column-33 { + flex: 0 0 33.33333%; + max-width: 33.33333%; } + .columns-wrapper .column-35 { + flex: 0 0 35%; + max-width: 35%; } + .columns-wrapper .column-40 { + flex: 0 0 40%; + max-width: 40%; } + .columns-wrapper .column-50 { + flex: 0 0 50%; + max-width: 50%; } + .columns-wrapper .column-75 { + flex: 0 0 75%; + max-width: 75%; } + .columns-wrapper .column-90 { + flex: 0 0 90%; + max-width: 90%; } + .columns-wrapper .column-95 { + flex: 0 0 95%; + max-width: 95%; } + .columns-wrapper .column-center { + display: flex; + justify-content: center; + text-align: center; } + .columns-wrapper .column-middle { + display: flex; + align-items: center; } + .columns-wrapper > div:not(:last-child) section, + .columns-wrapper > ul:not(:last-child) section { + margin-right: 10px; } + .header-kioskmode-controls .dashboard-kioskmode-controls li { margin-right: 6px; } @@ -1434,8 +1498,6 @@ footer { .dashboard-widget .msg-good, .dashboard-widget .msg-warning { margin: 0 10px; } - .dashboard-widget.dashboard-widget-fluid { - margin-right: 0; } .dashboard-grid-widget-content .list-table th:first-child, .dashboard-grid-widget-content .list-table td:first-child, .dashboard-grid-iterator.iterator-alt-content .dashboard-grid-iterator-content > div .list-table th:first-child, .dashboard-grid-iterator.iterator-alt-content .dashboard-grid-iterator-content > div .list-table td:first-child, .dashboard-widget .list-table th:first-child, .dashboard-widget .list-table td:first-child, .overlay-dialogue .list-table th:first-child, .overlay-dialogue .list-table td:first-child { padding-left: 10px; } @@ -1496,30 +1558,22 @@ footer { .wrapper.layout-kioskmode .dashboard-navigation { display: none; } -form.dashboard-widget-clock .fields-group-date, -form.dashboard-widget-clock .fields-group-time, -form.dashboard-widget-clock .fields-group-tzone { +form.dashboard-widget-clock .fields-group.fields-group-date, form.dashboard-widget-clock .fields-group.fields-group-time, form.dashboard-widget-clock .fields-group.fields-group-tzone { display: grid; grid-template-columns: 60px 120px repeat(2, minmax(60px, max-content) auto); align-items: center; column-gap: 10px; row-gap: 5px; } - form.dashboard-widget-clock .fields-group-date label, - form.dashboard-widget-clock .fields-group-time label, - form.dashboard-widget-clock .fields-group-tzone label { + form.dashboard-widget-clock .fields-group.fields-group-date label, form.dashboard-widget-clock .fields-group.fields-group-time label, form.dashboard-widget-clock .fields-group.fields-group-tzone label { text-align: right; } - form.dashboard-widget-clock .fields-group-date .field-size input, - form.dashboard-widget-clock .fields-group-time .field-size input, - form.dashboard-widget-clock .fields-group-tzone .field-size input { + form.dashboard-widget-clock .fields-group.fields-group-date .field-size input, form.dashboard-widget-clock .fields-group.fields-group-time .field-size input, form.dashboard-widget-clock .fields-group.fields-group-tzone .field-size input { margin-right: 5px; } -form.dashboard-widget-clock .fields-group-time .field-format { +form.dashboard-widget-clock .fields-group.fields-group-time .field-format { grid-column: 4 / -1; } -form.dashboard-widget-clock .fields-group-tzone .field-format { - grid-column: 2 / -1; } -form.dashboard-widget-clock .fields-group-tzone .field-timezone { +form.dashboard-widget-clock .fields-group.fields-group-tzone .form-field.field-tzone-timezone, form.dashboard-widget-clock .fields-group.fields-group-tzone .form-field.field-tzone-format { grid-column: 2 / -1; } -div.dashboard-widget-clock.clock-digital { +div.dashboard-widget-clock .clock-digital { box-sizing: border-box; min-height: 100%; padding: 10px; @@ -1527,9 +1581,9 @@ div.dashboard-widget-clock.clock-digital { flex-direction: column; justify-content: center; align-items: center; } - div.dashboard-widget-clock.clock-digital .clock-date, - div.dashboard-widget-clock.clock-digital .clock-time, - div.dashboard-widget-clock.clock-digital .clock-time-zone { + div.dashboard-widget-clock .clock-digital .clock-date, + div.dashboard-widget-clock .clock-digital .clock-time, + div.dashboard-widget-clock .clock-digital .clock-time-zone { max-width: 100%; white-space: nowrap; overflow: hidden; @@ -1537,150 +1591,137 @@ div.dashboard-widget-clock.clock-digital { font-size: calc(var(--content-height) * var(--widget-clock-font) / 1.14); line-height: 1.14; flex-shrink: 0; } - div.dashboard-widget-clock.clock-digital .bold { + div.dashboard-widget-clock .clock-digital .bold { font-weight: bold; } - div.dashboard-widget-clock.clock-digital .clock-disabled { + div.dashboard-widget-clock .clock-digital .clock-disabled { font-size: calc(var(--content-height) * 0.6 / 1.14); color: #737373; font-weight: bold; } -form.dashboard-widget-item .fields-group-description, -form.dashboard-widget-item .fields-group-value, -form.dashboard-widget-item .fields-group-time, -form.dashboard-widget-item .fields-group-change-indicator { +.dashboard-widget-inaccessible { + display: grid; + align-items: center; + padding-right: 10px; + padding-left: 10px; + text-align: center; + color: #737373; } + +form.dashboard-widget-item .fields-group.fields-group-description, form.dashboard-widget-item .fields-group.fields-group-value, form.dashboard-widget-item .fields-group.fields-group-time, form.dashboard-widget-item .fields-group.fields-group-change-indicator { display: grid; grid-template-columns: minmax(100px, max-content) 3fr max-content auto; align-items: center; column-gap: 10px; row-gap: 5px; } - form.dashboard-widget-item .fields-group-description label, - form.dashboard-widget-item .fields-group-value label, - form.dashboard-widget-item .fields-group-time label, - form.dashboard-widget-item .fields-group-change-indicator label { + form.dashboard-widget-item .fields-group.fields-group-description label, form.dashboard-widget-item .fields-group.fields-group-value label, form.dashboard-widget-item .fields-group.fields-group-time label, form.dashboard-widget-item .fields-group.fields-group-change-indicator label { text-align: right; } - form.dashboard-widget-item .fields-group-description hr, - form.dashboard-widget-item .fields-group-value hr, - form.dashboard-widget-item .fields-group-time hr, - form.dashboard-widget-item .fields-group-change-indicator hr { + form.dashboard-widget-item .fields-group.fields-group-description hr, form.dashboard-widget-item .fields-group.fields-group-value hr, form.dashboard-widget-item .fields-group.fields-group-time hr, form.dashboard-widget-item .fields-group.fields-group-change-indicator hr { grid-column: 1 / -1; margin: 0; width: 100%; border: solid #383838; border-width: 1px 0 0 0; } - form.dashboard-widget-item .fields-group-description .field-fluid, - form.dashboard-widget-item .fields-group-value .field-fluid, - form.dashboard-widget-item .fields-group-time .field-fluid, - form.dashboard-widget-item .fields-group-change-indicator .field-fluid { + form.dashboard-widget-item .fields-group.fields-group-description .field-fluid, form.dashboard-widget-item .fields-group.fields-group-value .field-fluid, form.dashboard-widget-item .fields-group.fields-group-time .field-fluid, form.dashboard-widget-item .fields-group.fields-group-change-indicator .field-fluid { grid-column: 2 / -1; } - form.dashboard-widget-item .fields-group-description .offset-3, - form.dashboard-widget-item .fields-group-value .offset-3, - form.dashboard-widget-item .fields-group-time .offset-3, - form.dashboard-widget-item .fields-group-change-indicator .offset-3 { + form.dashboard-widget-item .fields-group.fields-group-description .offset-3, form.dashboard-widget-item .fields-group.fields-group-value .offset-3, form.dashboard-widget-item .fields-group.fields-group-time .offset-3, form.dashboard-widget-item .fields-group.fields-group-change-indicator .offset-3 { grid-column-start: 3; } - form.dashboard-widget-item .fields-group-description .field-size input, - form.dashboard-widget-item .fields-group-value .field-size input, - form.dashboard-widget-item .fields-group-time .field-size input, - form.dashboard-widget-item .fields-group-change-indicator .field-size input { + form.dashboard-widget-item .fields-group.fields-group-description .field-size input, form.dashboard-widget-item .fields-group.fields-group-value .field-size input, form.dashboard-widget-item .fields-group.fields-group-time .field-size input, form.dashboard-widget-item .fields-group.fields-group-change-indicator .field-size input { margin-right: 5px; } - form.dashboard-widget-item .fields-group-description .form-field, - form.dashboard-widget-item .fields-group-value .form-field, - form.dashboard-widget-item .fields-group-time .form-field, - form.dashboard-widget-item .fields-group-change-indicator .form-field { + form.dashboard-widget-item .fields-group.fields-group-description .form-field, form.dashboard-widget-item .fields-group.fields-group-value .form-field, form.dashboard-widget-item .fields-group.fields-group-time .form-field, form.dashboard-widget-item .fields-group.fields-group-change-indicator .form-field { line-height: 24px; } -form.dashboard-widget-item .fields-group-description .form-field:nth-child(1) { +form.dashboard-widget-item .fields-group.fields-group-description .form-field:nth-child(1) { grid-column: 1 / -1; } -form.dashboard-widget-item .fields-group-value { +form.dashboard-widget-item .fields-group.fields-group-value { grid-template-columns: minmax(100px, max-content) 3fr max-content auto; } - form.dashboard-widget-item .fields-group-value .units-show { + form.dashboard-widget-item .fields-group.fields-group-value .units-show { display: flex; } - form.dashboard-widget-item .fields-group-value .units-show label[for='units'] { + form.dashboard-widget-item .fields-group.fields-group-value .units-show label[for='units'] { width: 100%; } -form.dashboard-widget-item .fields-group-change-indicator { +form.dashboard-widget-item .fields-group.fields-group-change-indicator { grid-template-columns: repeat(3, max-content 96px); } -form.dashboard-widget-item .fields-group-change-indicator .input-color-picker { - display: block; } + form.dashboard-widget-item .fields-group.fields-group-change-indicator .input-color-picker { + display: block; } -div.dashboard-widget-item { +div.dashboard-widget-item > div { box-sizing: border-box; height: 100%; padding: 10px; overflow-x: hidden; } - div.dashboard-widget-item a { - box-sizing: border-box; - display: flex; - flex-direction: column; - height: 100%; - color: inherit; } - div.dashboard-widget-item a:focus, div.dashboard-widget-item a:hover, div.dashboard-widget-item a:visited { - border: none; } - div.dashboard-widget-item a > div { - display: flex; - flex: 1 1 calc(100% / 3); } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .item-value, - div.dashboard-widget-item .item-time { - flex: 1 1 auto; - max-width: 100%; } - div.dashboard-widget-item .item-value { +div.dashboard-widget-item a { + box-sizing: border-box; + display: flex; + flex-direction: column; + height: 100%; + color: inherit; } + div.dashboard-widget-item a:focus, div.dashboard-widget-item a:hover, div.dashboard-widget-item a:visited { + border: none; } + div.dashboard-widget-item a > div { display: flex; - flex-wrap: wrap; - margin: 0 5px; } - div.dashboard-widget-item .item-value > .units:first-child, div.dashboard-widget-item .item-value > .units:last-child { - flex: 0 0 100%; } - div.dashboard-widget-item .item-value > .units:first-child { - margin-bottom: -0.07em; } - div.dashboard-widget-item .item-value > .units:last-child { - margin-top: -0.07em; } - div.dashboard-widget-item .item-value.type-text { + flex: 1 1 calc(100% / 3); } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .item-value, +div.dashboard-widget-item .item-time { + flex: 1 1 auto; + max-width: 100%; } +div.dashboard-widget-item .item-value { + display: flex; + flex-wrap: wrap; + margin: 0 5px; } + div.dashboard-widget-item .item-value > .units:first-child, div.dashboard-widget-item .item-value > .units:last-child { + flex: 0 0 100%; } + div.dashboard-widget-item .item-value > .units:first-child { + margin-bottom: -0.07em; } + div.dashboard-widget-item .item-value > .units:last-child { + margin-top: -0.07em; } + div.dashboard-widget-item .item-value.type-text { + min-width: 0; } + div.dashboard-widget-item .item-value.type-text .item-value-content { min-width: 0; } - div.dashboard-widget-item .item-value.type-text .item-value-content { - min-width: 0; } - div.dashboard-widget-item .item-value-content { - display: flex; - align-items: baseline; - overflow: hidden; } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .item-time, - div.dashboard-widget-item .type-text .value { - display: block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .value, - div.dashboard-widget-item .decimals, - div.dashboard-widget-item .units, - div.dashboard-widget-item .item-time { - font-size: calc(var(--content-height) * var(--widget-item-font) / 1.14); - line-height: 1.14; } - div.dashboard-widget-item .units:not(:last-child), - div.dashboard-widget-item .change-indicator:not(:last-child) { - margin-right: 5px; } - div.dashboard-widget-item .units:not(:first-child), - div.dashboard-widget-item .change-indicator:not(:first-child) { - margin-left: 5px; } - div.dashboard-widget-item .svg-arrow { - height: calc(var(--content-height) * var(--widget-item-font) * 0.72 / 1.14); } - div.dashboard-widget-item .item-value-no-data { - color: #737373; } - div.dashboard-widget-item .left { - justify-content: flex-start; - max-width: max-content; - margin-right: auto; } - div.dashboard-widget-item .center { - justify-content: center; } - div.dashboard-widget-item .right { - justify-content: flex-end; - max-width: max-content; - margin-left: auto; } - div.dashboard-widget-item .top { - align-self: flex-start; } - div.dashboard-widget-item .middle { - align-self: center; } - div.dashboard-widget-item .bottom { - align-self: flex-end; } - div.dashboard-widget-item .bold { - font-weight: bold; } +div.dashboard-widget-item .item-value-content { + display: flex; + align-items: baseline; + overflow: hidden; } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .item-time, +div.dashboard-widget-item .type-text .value { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .value, +div.dashboard-widget-item .decimals, +div.dashboard-widget-item .units, +div.dashboard-widget-item .item-time { + font-size: calc(var(--content-height) * var(--widget-item-font) / 1.14); + line-height: 1.14; } +div.dashboard-widget-item .units:not(:last-child), +div.dashboard-widget-item .change-indicator:not(:last-child) { + margin-right: 5px; } +div.dashboard-widget-item .units:not(:first-child), +div.dashboard-widget-item .change-indicator:not(:first-child) { + margin-left: 5px; } +div.dashboard-widget-item .svg-arrow { + height: calc(var(--content-height) * var(--widget-item-font) * 0.72 / 1.14); } +div.dashboard-widget-item .item-value-no-data { + color: #737373; } +div.dashboard-widget-item .left { + justify-content: flex-start; + max-width: max-content; + margin-right: auto; } +div.dashboard-widget-item .center { + justify-content: center; } +div.dashboard-widget-item .right { + justify-content: flex-end; + max-width: max-content; + margin-left: auto; } +div.dashboard-widget-item .top { + align-self: flex-start; } +div.dashboard-widget-item .middle { + align-self: center; } +div.dashboard-widget-item .bottom { + align-self: flex-end; } +div.dashboard-widget-item .bold { + font-weight: bold; } .dashboard-widget-item .svg-arrow-up { fill: #3DC51D; } @@ -1693,40 +1734,47 @@ div.dashboard-widget-slareport .date-vertical { writing-mode: vertical-lr; transform: rotate(180deg); } +form.dashboard-widget-svggraph .svg-graph-preview, form.dashboard-widget-svggraph .graph-widget-config-tabs { - padding: 10px 0; } - form.dashboard-widget-svggraph .graph-widget-config-tabs > .tabs-nav { - margin-right: 0; - margin-left: 0; - border-top: 1px solid #303030; } - form.dashboard-widget-svggraph .graph-widget-config-tabs .ui-tabs-nav { - position: sticky; + grid-column: 1 / -1; } +form.dashboard-widget-svggraph .svg-graph-preview { + position: relative; + min-width: 1110px; + height: 300px; } + form.dashboard-widget-svggraph .svg-graph-preview > div { + position: absolute; top: 0; + right: 0; + left: 0; + margin: 0 -10px; + height: 300px; background: #2b2b2b; z-index: 3; } +form.dashboard-widget-svggraph .graph-widget-config-tabs > .tabs-nav { + border-top: 1px solid #303030; } +form.dashboard-widget-svggraph .graph-widget-config-tabs .ui-tabs-nav { + position: sticky; + top: 0; + background: #2b2b2b; + z-index: 3; } form.dashboard-widget-svggraph .table-forms-container, form.dashboard-widget-svggraph .browser-warning-container { + margin: -10px 0 0 0; border: 1px solid #303030; border-top: none; } form.dashboard-widget-svggraph .table-forms-separator { padding: 0; } -form.dashboard-widget-svggraph .dataset-head { - display: grid; - grid-template-columns: 24px 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; } +form.dashboard-widget-svggraph .dataset-head, form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body { - display: grid; - grid-template-columns: 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; - position: relative; - margin-top: 10px; } - form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body .form-grid { - padding-top: 0; } - form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body .form-grid:first-child { - grid-column-start: 2; } + display: contents; } +form.dashboard-widget-svggraph .dataset-head .multiselect { + width: 100%; } +form.dashboard-widget-svggraph .dataset-body .form-grid { + padding-top: 0; } + form.dashboard-widget-svggraph .dataset-body .form-grid:first-child { + grid-column-start: 3; } form.dashboard-widget-svggraph .drag-icon { position: absolute; + top: 5px; left: -14px; } form.dashboard-widget-svggraph .td-drag-icon .drag-icon { top: 0; @@ -1748,13 +1796,13 @@ form.dashboard-widget-svggraph .list-vertical-accordion { overflow: visible; margin-top: -5px; margin-bottom: -5px; } - form.dashboard-widget-svggraph .list-vertical-accordion .list-accordion-item-head { - padding: 0; } form.dashboard-widget-svggraph .list-accordion-item { position: relative; - width: 100%; - padding: 5px 0; - list-style-type: none; } + display: grid; + grid-template-columns: 24px 24px 1fr 1fr 24px; + grid-gap: 10px; + align-items: start; + padding: 5px 0; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-opened::before { content: ' '; position: absolute; @@ -1766,8 +1814,6 @@ form.dashboard-widget-svggraph .list-accordion-item { form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .multiselect { height: 24px; overflow: hidden; } - form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-body { - display: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .table-forms-separator { border: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table thead, @@ -1775,6 +1821,8 @@ form.dashboard-widget-svggraph .list-accordion-item { form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table .table-col-handle, form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table .table-col-action { display: none; } + form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-body { + display: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .items-list { padding-left: 0; } form.dashboard-widget-svggraph .single-item-table .table-col-handle { @@ -1793,11 +1841,83 @@ form.dashboard-widget-svggraph .single-item-table .single-item-table-row:last-ch padding-bottom: 0; } form.dashboard-widget-svggraph .single-item-table tfoot td { padding: 5px 5px 5px 10px; } +form.dashboard-widget-svggraph .overrides-list { + position: relative; + margin: -5px 0 -5px 15px; } +form.dashboard-widget-svggraph .overrides-list-item { + position: relative; + display: grid; + grid-template-columns: 1fr 1fr 24px; + grid-gap: 5px 10px; + align-items: start; + padding: 5px 0; } + form.dashboard-widget-svggraph .overrides-list-item.sortable { + overflow: visible; + margin-top: -5px; + margin-bottom: -5px; } + form.dashboard-widget-svggraph .overrides-list-item .multiselect { + width: 100%; } + form.dashboard-widget-svggraph .overrides-list-item .btn-remove { + right: 0; + top: 0; + vertical-align: baseline; } +form.dashboard-widget-svggraph .overrides-foot { + padding: 5px 0; } +form.dashboard-widget-svggraph .overrides-options-list { + grid-column: 1 / -1; + padding: 0 24px 8px 0; + border-bottom: 1px solid #383838; + white-space: normal; } + form.dashboard-widget-svggraph .overrides-options-list > li { + display: inline-block; + margin-right: 5px; + margin-bottom: 2px; + line-height: 22px; + white-space: nowrap; } + form.dashboard-widget-svggraph .overrides-options-list > li .color-picker { + line-height: 22px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div { + position: relative; + padding: 1px 18px 1px 1px; + background-color: #4f4f4f; + border-radius: 2px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > span { + color: white; + padding-left: 8px; + line-height: 22px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > input[type=text] { + border-style: none; + line-height: 22px; + min-height: 22px; + width: 85px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + position: absolute; + right: 0; + top: 0; + min-height: 24px; } + form.dashboard-widget-svggraph .overrides-options-list .btn-alt .plus-icon { + margin-right: 0; } + form.dashboard-widget-svggraph .overrides-options-list .color-picker .color-picker-preview { + margin: 1px; + width: 20px; + min-height: 20px; + background-position: -323px -411px; } form.dashboard-widget-svggraph .no-items-message { display: none; line-height: 24px; color: #737373; } +[theme="hc-dark"] form.dashboard-widget-svggraph .overrides-options-list > li > div { + border: 1px solid #69808d; + background-color: transparent !important; } + [theme="hc-dark"] form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + border: none !important; + top: 0; } + +[theme="hc-light"] form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + border: none !important; + top: 0; } + form.dashboard-widget-tophosts #list_columns .text { max-width: 250px; } form.dashboard-widget-tophosts #column { @@ -2570,6 +2690,49 @@ div.dashboard-widget-tophosts z-bar-gauge { font-size: 0; border-left: 1px solid #0e1012; } +section { + background-color: #2b2b2b; + border: 1px solid #303030; } + section .section-head { + display: flex; + height: 32px; + line-height: 32px; } + section .section-head h4 { + padding: 0 10px; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + font-weight: bold; + line-height: inherit; + color: white; } + section .section-toggle { + width: 24px; + height: 24px; + margin: 2px 2px 0 auto; + background: url("../img/icon-sprite.svg?20220722") no-repeat -6px -654px; } + section .section-foot { + padding: 0 10px; + text-align: right; + line-height: 32px; + color: #737373; } + section.section-collapsed .section-body, + section.section-collapsed .section-foot { + display: none; } + section.section-collapsed .section-toggle { + background-position: -6px -689px; } + section:not(:last-child) { + margin-bottom: 10px; } + section .list-table { + border: 0; } + section .list-table tbody tr:last-child td { + border-bottom: 1px solid #383838; } + section .list-table td:first-child, + section .list-table th:first-child { + padding-left: 10px; } + section .list-table td:last-child, + section .list-table th:last-child { + padding-right: 10px; } + .service-info { margin: -10px 0; border-left: 4px solid #59db8f; } @@ -4547,13 +4710,13 @@ button { width: 24px; height: 24px; } -.filter-container.tabfilter-container .icon-edit, .btn-dashboard-page-properties, .btn-iterator-page-previous, .btn-iterator-page-next, .btn-widget-action, .btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle, .btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle, .btn-widget-edit, .btn-alarm-on, .btn-alarm-off, .btn-sound-on, .btn-sound-off, .btn-info-clock, .btn-dashboard-conf, .interfaces .interface-row[data-type="2"] .interface-btn-toggle { +section .section-toggle, .filter-container.tabfilter-container .icon-edit, .btn-dashboard-page-properties, .btn-iterator-page-previous, .btn-iterator-page-next, .btn-widget-action, .btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle, .btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle, .btn-widget-edit, .btn-alarm-on, .btn-alarm-off, .btn-sound-on, .btn-sound-off, .btn-info-clock, .btn-dashboard-conf, .interfaces .interface-row[data-type="2"] .interface-btn-toggle { border: 0; min-height: 0; padding: 0; opacity: .5; transition: opacity .2s ease-out; } - .filter-container.tabfilter-container [disabled].icon-edit, [disabled].btn-dashboard-page-properties, [disabled].btn-iterator-page-previous, [disabled].btn-iterator-page-next, [disabled].btn-widget-action, [disabled].btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle, [disabled].btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle, [disabled].btn-widget-edit, [disabled].btn-alarm-on, [disabled].btn-alarm-off, [disabled].btn-sound-on, [disabled].btn-sound-off, [disabled].btn-info-clock, [disabled].btn-dashboard-conf, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle, .filter-container.tabfilter-container [disabled].icon-edit:hover, [disabled].btn-dashboard-page-properties:hover, [disabled].btn-iterator-page-previous:hover, [disabled].btn-iterator-page-next:hover, [disabled].btn-widget-action:hover, [disabled].btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-edit:hover, [disabled].btn-alarm-on:hover, [disabled].btn-alarm-off:hover, [disabled].btn-sound-on:hover, [disabled].btn-sound-off:hover, [disabled].btn-info-clock:hover, [disabled].btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:hover, .filter-container.tabfilter-container [disabled].icon-edit:focus, [disabled].btn-dashboard-page-properties:focus, [disabled].btn-iterator-page-previous:focus, [disabled].btn-iterator-page-next:focus, [disabled].btn-widget-action:focus, [disabled].btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-edit:focus, [disabled].btn-alarm-on:focus, [disabled].btn-alarm-off:focus, [disabled].btn-sound-on:focus, [disabled].btn-sound-off:focus, [disabled].btn-info-clock:focus, [disabled].btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:focus, .filter-container.tabfilter-container [disabled].icon-edit:active, [disabled].btn-dashboard-page-properties:active, [disabled].btn-iterator-page-previous:active, [disabled].btn-iterator-page-next:active, [disabled].btn-widget-action:active, [disabled].btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-edit:active, [disabled].btn-alarm-on:active, [disabled].btn-alarm-off:active, [disabled].btn-sound-on:active, [disabled].btn-sound-off:active, [disabled].btn-info-clock:active, [disabled].btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:active { + section [disabled].section-toggle, .filter-container.tabfilter-container [disabled].icon-edit, [disabled].btn-dashboard-page-properties, [disabled].btn-iterator-page-previous, [disabled].btn-iterator-page-next, [disabled].btn-widget-action, [disabled].btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle, [disabled].btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle, [disabled].btn-widget-edit, [disabled].btn-alarm-on, [disabled].btn-alarm-off, [disabled].btn-sound-on, [disabled].btn-sound-off, [disabled].btn-info-clock, [disabled].btn-dashboard-conf, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle, section [disabled].section-toggle:hover, .filter-container.tabfilter-container [disabled].icon-edit:hover, [disabled].btn-dashboard-page-properties:hover, [disabled].btn-iterator-page-previous:hover, [disabled].btn-iterator-page-next:hover, [disabled].btn-widget-action:hover, [disabled].btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-edit:hover, [disabled].btn-alarm-on:hover, [disabled].btn-alarm-off:hover, [disabled].btn-sound-on:hover, [disabled].btn-sound-off:hover, [disabled].btn-info-clock:hover, [disabled].btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:hover, section [disabled].section-toggle:focus, .filter-container.tabfilter-container [disabled].icon-edit:focus, [disabled].btn-dashboard-page-properties:focus, [disabled].btn-iterator-page-previous:focus, [disabled].btn-iterator-page-next:focus, [disabled].btn-widget-action:focus, [disabled].btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-edit:focus, [disabled].btn-alarm-on:focus, [disabled].btn-alarm-off:focus, [disabled].btn-sound-on:focus, [disabled].btn-sound-off:focus, [disabled].btn-info-clock:focus, [disabled].btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:focus, section [disabled].section-toggle:active, .filter-container.tabfilter-container [disabled].icon-edit:active, [disabled].btn-dashboard-page-properties:active, [disabled].btn-iterator-page-previous:active, [disabled].btn-iterator-page-next:active, [disabled].btn-widget-action:active, [disabled].btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-edit:active, [disabled].btn-alarm-on:active, [disabled].btn-alarm-off:active, [disabled].btn-sound-on:active, [disabled].btn-sound-off:active, [disabled].btn-info-clock:active, [disabled].btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:active { background-color: transparent; opacity: .25; } @@ -4581,7 +4744,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active { .inaccessible .subfilter-enabled { color: #b2b2b2; } -.filter-container.tabfilter-container .icon-edit:hover, .btn-dashboard-page-properties:hover, .btn-iterator-page-previous:hover, .btn-iterator-page-next:hover, .btn-widget-action:hover, .btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:hover, .btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:hover, .btn-widget-edit:hover, .btn-alarm-on:hover, .btn-alarm-off:hover, .btn-sound-on:hover, .btn-sound-off:hover, .btn-info-clock:hover, .btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:hover, .filter-container.tabfilter-container .icon-edit:focus, .btn-dashboard-page-properties:focus, .btn-iterator-page-previous:focus, .btn-iterator-page-next:focus, .btn-widget-action:focus, .btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:focus, .btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:focus, .btn-widget-edit:focus, .btn-alarm-on:focus, .btn-alarm-off:focus, .btn-sound-on:focus, .btn-sound-off:focus, .btn-info-clock:focus, .btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:focus, .filter-container.tabfilter-container .icon-edit:active, .btn-dashboard-page-properties:active, .btn-iterator-page-previous:active, .btn-iterator-page-next:active, .btn-widget-action:active, .btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:active, .btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:active, .btn-widget-edit:active, .btn-alarm-on:active, .btn-alarm-off:active, .btn-sound-on:active, .btn-sound-off:active, .btn-info-clock:active, .btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:active { +section .section-toggle:hover, .filter-container.tabfilter-container .icon-edit:hover, .btn-dashboard-page-properties:hover, .btn-iterator-page-previous:hover, .btn-iterator-page-next:hover, .btn-widget-action:hover, .btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:hover, .btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:hover, .btn-widget-edit:hover, .btn-alarm-on:hover, .btn-alarm-off:hover, .btn-sound-on:hover, .btn-sound-off:hover, .btn-info-clock:hover, .btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:hover, section .section-toggle:focus, .filter-container.tabfilter-container .icon-edit:focus, .btn-dashboard-page-properties:focus, .btn-iterator-page-previous:focus, .btn-iterator-page-next:focus, .btn-widget-action:focus, .btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:focus, .btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:focus, .btn-widget-edit:focus, .btn-alarm-on:focus, .btn-alarm-off:focus, .btn-sound-on:focus, .btn-sound-off:focus, .btn-info-clock:focus, .btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:focus, section .section-toggle:active, .filter-container.tabfilter-container .icon-edit:active, .btn-dashboard-page-properties:active, .btn-iterator-page-previous:active, .btn-iterator-page-next:active, .btn-widget-action:active, .btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:active, .btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:active, .btn-widget-edit:active, .btn-alarm-on:active, .btn-alarm-off:active, .btn-sound-on:active, .btn-sound-off:active, .btn-info-clock:active, .btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:active { background-color: transparent; opacity: 1; } @@ -4674,16 +4837,16 @@ button[disabled], button[disabled]:hover, button[disabled]:active { content: ''; } .icon-tree-top-bottom::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -300px; } + background-position: -84px -300px; } .icon-tree-top-bottom-right::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -334px; } + background-position: -84px -334px; } .icon-tree-top-right::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -372px; } + background-position: -84px -372px; } .icon-tree-empty::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -350px; } + background-position: -84px -350px; } .icon-cal { background: transparent url("../img/icon-sprite.svg?20220722") no-repeat -42px -834px; } @@ -4964,7 +5127,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active { overflow: hidden; margin: 0 10px; } .overlay-dialogue.modal .dashboard-widget-head { - margin-bottom: 14px; } + margin-bottom: 12px; } .overlay-dialogue.modal .dashboard-widget-head .icon-doc-link { margin-right: -26px; } .overlay-dialogue.modal .dashboard-widget-head .overlay-close-btn { @@ -4977,9 +5140,11 @@ button[disabled], button[disabled]:hover, button[disabled]:active { width: 100%; max-height: calc(100vh - 220px); max-width: inherit; - margin: 0 -10px 10px; + margin: 0 -10px 8px; padding: 0 10px; position: relative; } + .overlay-dialogue.modal .overlay-dialogue-body > form { + padding: 2px 0; } .overlay-dialogue.modal .overlay-dialogue-body .table-forms .table-forms-td-right { padding-right: 8px; } .overlay-dialogue.modal .overlay-dialogue-body .table-forms .table-forms-row-with-second-field { @@ -5376,20 +5541,6 @@ button[disabled], button[disabled]:hover, button[disabled]:active { stroke: #e45959; stroke-width: 2px; } -.svg-graph-preview { - margin-top: 10px; - min-width: 1120px; - height: 300px; - position: relative; } - .svg-graph-preview > div { - background: #2b2b2b; - height: 300px; - position: absolute; - left: 0; - right: 0; - top: 0; - z-index: 3; } - .svg-graph-hintbox { font-size: 12px; line-height: 18px; @@ -5942,22 +6093,22 @@ span.is-loading { padding: 10px 0 0; text-align: center; } -.dashboard-grid-widget-content, div.dashboard-widget-item, .msg-details ul, z-select button.focusable, +.dashboard-grid-widget-content, div.dashboard-widget-item > div, .msg-details ul, z-select button.focusable, .z-select button.focusable, z-select .list, .z-select .list, .multiselect-available, textarea, select, .setup-right-body, .overlay-dialogue.modal .overlay-dialogue-body, .overlay-dialogue .hintbox-wrap, .overlay-dialogue .maps-container, .notif-body, .debug-output, .overlay-descr, .overflow-table, .import-compare .toc, .import-compare .diff { scrollbar-width: thin; } - .dashboard-grid-widget-content::-webkit-scrollbar, div.dashboard-widget-item::-webkit-scrollbar, .msg-details ul::-webkit-scrollbar, z-select button.focusable::-webkit-scrollbar, + .dashboard-grid-widget-content::-webkit-scrollbar, div.dashboard-widget-item > div::-webkit-scrollbar, .msg-details ul::-webkit-scrollbar, z-select button.focusable::-webkit-scrollbar, .z-select button.focusable::-webkit-scrollbar, z-select .list::-webkit-scrollbar, .z-select .list::-webkit-scrollbar, .multiselect-available::-webkit-scrollbar, textarea::-webkit-scrollbar, select::-webkit-scrollbar, .setup-right-body::-webkit-scrollbar, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar, .overlay-dialogue .maps-container::-webkit-scrollbar, .notif-body::-webkit-scrollbar, .debug-output::-webkit-scrollbar, .overlay-descr::-webkit-scrollbar, .overflow-table::-webkit-scrollbar, .import-compare .toc::-webkit-scrollbar, .import-compare .diff::-webkit-scrollbar { width: 9px; } - .dashboard-grid-widget-content::-webkit-scrollbar-track, div.dashboard-widget-item::-webkit-scrollbar-track, .msg-details ul::-webkit-scrollbar-track, z-select button.focusable::-webkit-scrollbar-track, + .dashboard-grid-widget-content::-webkit-scrollbar-track, div.dashboard-widget-item > div::-webkit-scrollbar-track, .msg-details ul::-webkit-scrollbar-track, z-select button.focusable::-webkit-scrollbar-track, .z-select button.focusable::-webkit-scrollbar-track, z-select .list::-webkit-scrollbar-track, .z-select .list::-webkit-scrollbar-track, .multiselect-available::-webkit-scrollbar-track, textarea::-webkit-scrollbar-track, select::-webkit-scrollbar-track, .setup-right-body::-webkit-scrollbar-track, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar-track, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar-track, .overlay-dialogue .maps-container::-webkit-scrollbar-track, .notif-body::-webkit-scrollbar-track, .debug-output::-webkit-scrollbar-track, .overlay-descr::-webkit-scrollbar-track, .overflow-table::-webkit-scrollbar-track, .import-compare .toc::-webkit-scrollbar-track, .import-compare .diff::-webkit-scrollbar-track { background-color: #1f1f1f; } - .dashboard-grid-widget-content::-webkit-scrollbar-thumb, div.dashboard-widget-item::-webkit-scrollbar-thumb, .msg-details ul::-webkit-scrollbar-thumb, z-select button.focusable::-webkit-scrollbar-thumb, + .dashboard-grid-widget-content::-webkit-scrollbar-thumb, div.dashboard-widget-item > div::-webkit-scrollbar-thumb, .msg-details ul::-webkit-scrollbar-thumb, z-select button.focusable::-webkit-scrollbar-thumb, .z-select button.focusable::-webkit-scrollbar-thumb, z-select .list::-webkit-scrollbar-thumb, .z-select .list::-webkit-scrollbar-thumb, .multiselect-available::-webkit-scrollbar-thumb, textarea::-webkit-scrollbar-thumb, select::-webkit-scrollbar-thumb, .setup-right-body::-webkit-scrollbar-thumb, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar-thumb, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar-thumb, .overlay-dialogue .maps-container::-webkit-scrollbar-thumb, .notif-body::-webkit-scrollbar-thumb, .debug-output::-webkit-scrollbar-thumb, .overlay-descr::-webkit-scrollbar-thumb, .overflow-table::-webkit-scrollbar-thumb, .import-compare .toc::-webkit-scrollbar-thumb, .import-compare .diff::-webkit-scrollbar-thumb { @@ -6098,53 +6249,6 @@ svg { white-space: normal; word-break: break-word; } -.overrides-list { - display: table; - width: 90%; - max-width: 738px; - padding-left: 15px; } - .overrides-list .overrides-list-item { - display: table-row; } - .overrides-list .overrides-list-item .btn-remove { - position: relative; - right: -73px; - top: 3px; } - -.overrides-options-list { - white-space: normal; - padding: 5px 0 8px; - margin-bottom: 10px; - border-bottom: 1px solid #383838; } - .overrides-options-list > li { - display: inline-block; - margin: 2px 7px 2px 0; - white-space: nowrap; - vertical-align: middle; } - .overrides-options-list > li > div { - position: relative; - padding: 1px 18px 1px 1px; - background-color: #4f4f4f; - border-radius: 2px; } - .overrides-options-list > li > div > span { - color: white; - padding-left: 8px; - line-height: 22px; } - .overrides-options-list > li > div > input[type=text] { - border-style: none; - line-height: 22px; - min-height: 22px; - width: 85px; } - .overrides-options-list > li > div > .subfilter-disable-btn { - position: absolute; - right: 0; - top: 0; - min-height: 24px; } - .overrides-options-list .color-picker .color-picker-preview { - margin: 1px; - width: 20px; - min-height: 20px; - background-position: -323px -411px; } - .list-accordion-foot > div { display: table-cell; padding-top: 10px; } @@ -6190,63 +6294,6 @@ svg { text-overflow: ellipsis; line-height: 24px; } -.columns-wrapper { - display: flex; - flex-wrap: wrap; - align-items: start; } - .columns-wrapper.columns-nowrap { - flex-wrap: nowrap; } - .columns-wrapper.columns-2 > div, - .columns-wrapper.columns-2 > li { - display: block; - flex: 0 0 50%; - max-width: 50%; } - .columns-wrapper.columns-3 > div, - .columns-wrapper.columns-3 > li { - display: block; - flex: 0 0 33.33333%; - max-width: 33.33333%; } - .columns-wrapper .column-5 { - flex: 0 0 5%; - max-width: 5%; } - .columns-wrapper .column-10 { - flex: 0 0 10%; - max-width: 10%; } - .columns-wrapper .column-15 { - flex: 0 0 15%; - max-width: 15%; } - .columns-wrapper .column-20 { - flex: 0 0 20%; - max-width: 20%; } - .columns-wrapper .column-33 { - flex: 0 0 33.33333%; - max-width: 33.33333%; } - .columns-wrapper .column-35 { - flex: 0 0 35%; - max-width: 35%; } - .columns-wrapper .column-40 { - flex: 0 0 40%; - max-width: 40%; } - .columns-wrapper .column-50 { - flex: 0 0 50%; - max-width: 50%; } - .columns-wrapper .column-75 { - flex: 0 0 75%; - max-width: 75%; } - .columns-wrapper .column-90 { - flex: 0 0 90%; - max-width: 90%; } - .columns-wrapper .column-95 { - flex: 0 0 95%; - max-width: 95%; } - .columns-wrapper .column-center { - display: flex; - justify-content: center; - text-align: center; } - .columns-wrapper .column-middle { - display: flex; - align-items: center; } - .preprocessing-list { display: block; max-width: 930px; diff --git a/ui/assets/styles/hc-dark.css b/ui/assets/styles/hc-dark.css index 21c633bc729..089bb7af81a 100644 --- a/ui/assets/styles/hc-dark.css +++ b/ui/assets/styles/hc-dark.css @@ -336,7 +336,9 @@ svg a { top: 0; left: 0; transition: left .2s, top .2s; } - .sortable .sortable-list .sortable-item:not(.sortable-dragging) { + .sortable .sortable-item { + box-sizing: border-box; } + .sortable .sortable-item:not(.sortable-dragging) { transition: left .2s, top .2s; } .sortable.sortable-dragging .sortable-item { position: absolute; } @@ -654,7 +656,6 @@ footer { .form-grid { display: grid; - padding: 5px; row-gap: 10px; column-gap: 10px; grid-template-columns: minmax(15%, max-content) auto; } @@ -670,6 +671,9 @@ footer { word-wrap: break-word; } .form-grid > label.fields-group-label { padding-top: 5px; } + .form-grid > label .icon-help-hint, + .form-grid > label .icon-info { + margin-left: 5px; } .form-grid > .form-field, .form-grid > .field-fluid, .form-grid .form-actions { @@ -872,6 +876,66 @@ footer { .color-picker-dialogue .color-picker-input input { padding-left: 25px; } +.columns-wrapper { + display: flex; + flex-wrap: wrap; + align-items: start; } + .columns-wrapper.columns-nowrap { + flex-wrap: nowrap; } + .columns-wrapper.columns-2 > div, + .columns-wrapper.columns-2 > li { + display: block; + flex: 0 0 50%; + max-width: 50%; } + .columns-wrapper.columns-3 > div, + .columns-wrapper.columns-3 > li { + display: block; + flex: 0 0 33.33333%; + max-width: 33.33333%; } + .columns-wrapper .column-5 { + flex: 0 0 5%; + max-width: 5%; } + .columns-wrapper .column-10 { + flex: 0 0 10%; + max-width: 10%; } + .columns-wrapper .column-15 { + flex: 0 0 15%; + max-width: 15%; } + .columns-wrapper .column-20 { + flex: 0 0 20%; + max-width: 20%; } + .columns-wrapper .column-33 { + flex: 0 0 33.33333%; + max-width: 33.33333%; } + .columns-wrapper .column-35 { + flex: 0 0 35%; + max-width: 35%; } + .columns-wrapper .column-40 { + flex: 0 0 40%; + max-width: 40%; } + .columns-wrapper .column-50 { + flex: 0 0 50%; + max-width: 50%; } + .columns-wrapper .column-75 { + flex: 0 0 75%; + max-width: 75%; } + .columns-wrapper .column-90 { + flex: 0 0 90%; + max-width: 90%; } + .columns-wrapper .column-95 { + flex: 0 0 95%; + max-width: 95%; } + .columns-wrapper .column-center { + display: flex; + justify-content: center; + text-align: center; } + .columns-wrapper .column-middle { + display: flex; + align-items: center; } + .columns-wrapper > div:not(:last-child) section, + .columns-wrapper > ul:not(:last-child) section { + margin-right: 10px; } + .header-kioskmode-controls .dashboard-kioskmode-controls li { margin-right: 6px; } @@ -1421,8 +1485,6 @@ footer { .dashboard-widget .msg-good, .dashboard-widget .msg-warning { margin: 0 10px; } - .dashboard-widget.dashboard-widget-fluid { - margin-right: 0; } .dashboard-grid-widget-content .list-table th:first-child, .dashboard-grid-widget-content .list-table td:first-child, .dashboard-grid-iterator.iterator-alt-content .dashboard-grid-iterator-content > div .list-table th:first-child, .dashboard-grid-iterator.iterator-alt-content .dashboard-grid-iterator-content > div .list-table td:first-child, .dashboard-widget .list-table th:first-child, .dashboard-widget .list-table td:first-child, .overlay-dialogue .list-table th:first-child, .overlay-dialogue .list-table td:first-child { padding-left: 10px; } @@ -1483,30 +1545,22 @@ footer { .wrapper.layout-kioskmode .dashboard-navigation { display: none; } -form.dashboard-widget-clock .fields-group-date, -form.dashboard-widget-clock .fields-group-time, -form.dashboard-widget-clock .fields-group-tzone { +form.dashboard-widget-clock .fields-group.fields-group-date, form.dashboard-widget-clock .fields-group.fields-group-time, form.dashboard-widget-clock .fields-group.fields-group-tzone { display: grid; grid-template-columns: 60px 120px repeat(2, minmax(60px, max-content) auto); align-items: center; column-gap: 10px; row-gap: 5px; } - form.dashboard-widget-clock .fields-group-date label, - form.dashboard-widget-clock .fields-group-time label, - form.dashboard-widget-clock .fields-group-tzone label { + form.dashboard-widget-clock .fields-group.fields-group-date label, form.dashboard-widget-clock .fields-group.fields-group-time label, form.dashboard-widget-clock .fields-group.fields-group-tzone label { text-align: right; } - form.dashboard-widget-clock .fields-group-date .field-size input, - form.dashboard-widget-clock .fields-group-time .field-size input, - form.dashboard-widget-clock .fields-group-tzone .field-size input { + form.dashboard-widget-clock .fields-group.fields-group-date .field-size input, form.dashboard-widget-clock .fields-group.fields-group-time .field-size input, form.dashboard-widget-clock .fields-group.fields-group-tzone .field-size input { margin-right: 5px; } -form.dashboard-widget-clock .fields-group-time .field-format { +form.dashboard-widget-clock .fields-group.fields-group-time .field-format { grid-column: 4 / -1; } -form.dashboard-widget-clock .fields-group-tzone .field-format { - grid-column: 2 / -1; } -form.dashboard-widget-clock .fields-group-tzone .field-timezone { +form.dashboard-widget-clock .fields-group.fields-group-tzone .form-field.field-tzone-timezone, form.dashboard-widget-clock .fields-group.fields-group-tzone .form-field.field-tzone-format { grid-column: 2 / -1; } -div.dashboard-widget-clock.clock-digital { +div.dashboard-widget-clock .clock-digital { box-sizing: border-box; min-height: 100%; padding: 10px; @@ -1514,9 +1568,9 @@ div.dashboard-widget-clock.clock-digital { flex-direction: column; justify-content: center; align-items: center; } - div.dashboard-widget-clock.clock-digital .clock-date, - div.dashboard-widget-clock.clock-digital .clock-time, - div.dashboard-widget-clock.clock-digital .clock-time-zone { + div.dashboard-widget-clock .clock-digital .clock-date, + div.dashboard-widget-clock .clock-digital .clock-time, + div.dashboard-widget-clock .clock-digital .clock-time-zone { max-width: 100%; white-space: nowrap; overflow: hidden; @@ -1524,150 +1578,137 @@ div.dashboard-widget-clock.clock-digital { font-size: calc(var(--content-height) * var(--widget-clock-font) / 1.14); line-height: 1.14; flex-shrink: 0; } - div.dashboard-widget-clock.clock-digital .bold { + div.dashboard-widget-clock .clock-digital .bold { font-weight: bold; } - div.dashboard-widget-clock.clock-digital .clock-disabled { + div.dashboard-widget-clock .clock-digital .clock-disabled { font-size: calc(var(--content-height) * 0.6 / 1.14); color: #cacaca; font-weight: bold; } -form.dashboard-widget-item .fields-group-description, -form.dashboard-widget-item .fields-group-value, -form.dashboard-widget-item .fields-group-time, -form.dashboard-widget-item .fields-group-change-indicator { +.dashboard-widget-inaccessible { + display: grid; + align-items: center; + padding-right: 10px; + padding-left: 10px; + text-align: center; + color: #cacaca; } + +form.dashboard-widget-item .fields-group.fields-group-description, form.dashboard-widget-item .fields-group.fields-group-value, form.dashboard-widget-item .fields-group.fields-group-time, form.dashboard-widget-item .fields-group.fields-group-change-indicator { display: grid; grid-template-columns: minmax(100px, max-content) 3fr max-content auto; align-items: center; column-gap: 10px; row-gap: 5px; } - form.dashboard-widget-item .fields-group-description label, - form.dashboard-widget-item .fields-group-value label, - form.dashboard-widget-item .fields-group-time label, - form.dashboard-widget-item .fields-group-change-indicator label { + form.dashboard-widget-item .fields-group.fields-group-description label, form.dashboard-widget-item .fields-group.fields-group-value label, form.dashboard-widget-item .fields-group.fields-group-time label, form.dashboard-widget-item .fields-group.fields-group-change-indicator label { text-align: right; } - form.dashboard-widget-item .fields-group-description hr, - form.dashboard-widget-item .fields-group-value hr, - form.dashboard-widget-item .fields-group-time hr, - form.dashboard-widget-item .fields-group-change-indicator hr { + form.dashboard-widget-item .fields-group.fields-group-description hr, form.dashboard-widget-item .fields-group.fields-group-value hr, form.dashboard-widget-item .fields-group.fields-group-time hr, form.dashboard-widget-item .fields-group.fields-group-change-indicator hr { grid-column: 1 / -1; margin: 0; width: 100%; border: solid #333333; border-width: 1px 0 0 0; } - form.dashboard-widget-item .fields-group-description .field-fluid, - form.dashboard-widget-item .fields-group-value .field-fluid, - form.dashboard-widget-item .fields-group-time .field-fluid, - form.dashboard-widget-item .fields-group-change-indicator .field-fluid { + form.dashboard-widget-item .fields-group.fields-group-description .field-fluid, form.dashboard-widget-item .fields-group.fields-group-value .field-fluid, form.dashboard-widget-item .fields-group.fields-group-time .field-fluid, form.dashboard-widget-item .fields-group.fields-group-change-indicator .field-fluid { grid-column: 2 / -1; } - form.dashboard-widget-item .fields-group-description .offset-3, - form.dashboard-widget-item .fields-group-value .offset-3, - form.dashboard-widget-item .fields-group-time .offset-3, - form.dashboard-widget-item .fields-group-change-indicator .offset-3 { + form.dashboard-widget-item .fields-group.fields-group-description .offset-3, form.dashboard-widget-item .fields-group.fields-group-value .offset-3, form.dashboard-widget-item .fields-group.fields-group-time .offset-3, form.dashboard-widget-item .fields-group.fields-group-change-indicator .offset-3 { grid-column-start: 3; } - form.dashboard-widget-item .fields-group-description .field-size input, - form.dashboard-widget-item .fields-group-value .field-size input, - form.dashboard-widget-item .fields-group-time .field-size input, - form.dashboard-widget-item .fields-group-change-indicator .field-size input { + form.dashboard-widget-item .fields-group.fields-group-description .field-size input, form.dashboard-widget-item .fields-group.fields-group-value .field-size input, form.dashboard-widget-item .fields-group.fields-group-time .field-size input, form.dashboard-widget-item .fields-group.fields-group-change-indicator .field-size input { margin-right: 5px; } - form.dashboard-widget-item .fields-group-description .form-field, - form.dashboard-widget-item .fields-group-value .form-field, - form.dashboard-widget-item .fields-group-time .form-field, - form.dashboard-widget-item .fields-group-change-indicator .form-field { + form.dashboard-widget-item .fields-group.fields-group-description .form-field, form.dashboard-widget-item .fields-group.fields-group-value .form-field, form.dashboard-widget-item .fields-group.fields-group-time .form-field, form.dashboard-widget-item .fields-group.fields-group-change-indicator .form-field { line-height: 24px; } -form.dashboard-widget-item .fields-group-description .form-field:nth-child(1) { +form.dashboard-widget-item .fields-group.fields-group-description .form-field:nth-child(1) { grid-column: 1 / -1; } -form.dashboard-widget-item .fields-group-value { +form.dashboard-widget-item .fields-group.fields-group-value { grid-template-columns: minmax(100px, max-content) 3fr max-content auto; } - form.dashboard-widget-item .fields-group-value .units-show { + form.dashboard-widget-item .fields-group.fields-group-value .units-show { display: flex; } - form.dashboard-widget-item .fields-group-value .units-show label[for='units'] { + form.dashboard-widget-item .fields-group.fields-group-value .units-show label[for='units'] { width: 100%; } -form.dashboard-widget-item .fields-group-change-indicator { +form.dashboard-widget-item .fields-group.fields-group-change-indicator { grid-template-columns: repeat(3, max-content 96px); } -form.dashboard-widget-item .fields-group-change-indicator .input-color-picker { - display: block; } + form.dashboard-widget-item .fields-group.fields-group-change-indicator .input-color-picker { + display: block; } -div.dashboard-widget-item { +div.dashboard-widget-item > div { box-sizing: border-box; height: 100%; padding: 10px; overflow-x: hidden; } - div.dashboard-widget-item a { - box-sizing: border-box; - display: flex; - flex-direction: column; - height: 100%; - color: inherit; } - div.dashboard-widget-item a:focus, div.dashboard-widget-item a:hover, div.dashboard-widget-item a:visited { - border: none; } - div.dashboard-widget-item a > div { - display: flex; - flex: 1 1 calc(100% / 3); } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .item-value, - div.dashboard-widget-item .item-time { - flex: 1 1 auto; - max-width: 100%; } - div.dashboard-widget-item .item-value { +div.dashboard-widget-item a { + box-sizing: border-box; + display: flex; + flex-direction: column; + height: 100%; + color: inherit; } + div.dashboard-widget-item a:focus, div.dashboard-widget-item a:hover, div.dashboard-widget-item a:visited { + border: none; } + div.dashboard-widget-item a > div { display: flex; - flex-wrap: wrap; - margin: 0 5px; } - div.dashboard-widget-item .item-value > .units:first-child, div.dashboard-widget-item .item-value > .units:last-child { - flex: 0 0 100%; } - div.dashboard-widget-item .item-value > .units:first-child { - margin-bottom: -0.07em; } - div.dashboard-widget-item .item-value > .units:last-child { - margin-top: -0.07em; } - div.dashboard-widget-item .item-value.type-text { + flex: 1 1 calc(100% / 3); } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .item-value, +div.dashboard-widget-item .item-time { + flex: 1 1 auto; + max-width: 100%; } +div.dashboard-widget-item .item-value { + display: flex; + flex-wrap: wrap; + margin: 0 5px; } + div.dashboard-widget-item .item-value > .units:first-child, div.dashboard-widget-item .item-value > .units:last-child { + flex: 0 0 100%; } + div.dashboard-widget-item .item-value > .units:first-child { + margin-bottom: -0.07em; } + div.dashboard-widget-item .item-value > .units:last-child { + margin-top: -0.07em; } + div.dashboard-widget-item .item-value.type-text { + min-width: 0; } + div.dashboard-widget-item .item-value.type-text .item-value-content { min-width: 0; } - div.dashboard-widget-item .item-value.type-text .item-value-content { - min-width: 0; } - div.dashboard-widget-item .item-value-content { - display: flex; - align-items: baseline; - overflow: hidden; } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .item-time, - div.dashboard-widget-item .type-text .value { - display: block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .value, - div.dashboard-widget-item .decimals, - div.dashboard-widget-item .units, - div.dashboard-widget-item .item-time { - font-size: calc(var(--content-height) * var(--widget-item-font) / 1.14); - line-height: 1.14; } - div.dashboard-widget-item .units:not(:last-child), - div.dashboard-widget-item .change-indicator:not(:last-child) { - margin-right: 5px; } - div.dashboard-widget-item .units:not(:first-child), - div.dashboard-widget-item .change-indicator:not(:first-child) { - margin-left: 5px; } - div.dashboard-widget-item .svg-arrow { - height: calc(var(--content-height) * var(--widget-item-font) * 0.72 / 1.14); } - div.dashboard-widget-item .item-value-no-data { - color: #cacaca; } - div.dashboard-widget-item .left { - justify-content: flex-start; - max-width: max-content; - margin-right: auto; } - div.dashboard-widget-item .center { - justify-content: center; } - div.dashboard-widget-item .right { - justify-content: flex-end; - max-width: max-content; - margin-left: auto; } - div.dashboard-widget-item .top { - align-self: flex-start; } - div.dashboard-widget-item .middle { - align-self: center; } - div.dashboard-widget-item .bottom { - align-self: flex-end; } - div.dashboard-widget-item .bold { - font-weight: bold; } +div.dashboard-widget-item .item-value-content { + display: flex; + align-items: baseline; + overflow: hidden; } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .item-time, +div.dashboard-widget-item .type-text .value { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .value, +div.dashboard-widget-item .decimals, +div.dashboard-widget-item .units, +div.dashboard-widget-item .item-time { + font-size: calc(var(--content-height) * var(--widget-item-font) / 1.14); + line-height: 1.14; } +div.dashboard-widget-item .units:not(:last-child), +div.dashboard-widget-item .change-indicator:not(:last-child) { + margin-right: 5px; } +div.dashboard-widget-item .units:not(:first-child), +div.dashboard-widget-item .change-indicator:not(:first-child) { + margin-left: 5px; } +div.dashboard-widget-item .svg-arrow { + height: calc(var(--content-height) * var(--widget-item-font) * 0.72 / 1.14); } +div.dashboard-widget-item .item-value-no-data { + color: #cacaca; } +div.dashboard-widget-item .left { + justify-content: flex-start; + max-width: max-content; + margin-right: auto; } +div.dashboard-widget-item .center { + justify-content: center; } +div.dashboard-widget-item .right { + justify-content: flex-end; + max-width: max-content; + margin-left: auto; } +div.dashboard-widget-item .top { + align-self: flex-start; } +div.dashboard-widget-item .middle { + align-self: center; } +div.dashboard-widget-item .bottom { + align-self: flex-end; } +div.dashboard-widget-item .bold { + font-weight: bold; } .dashboard-widget-item .svg-arrow-up { fill: #3DC51D; } @@ -1683,40 +1724,47 @@ div.dashboard-widget-slareport .date-vertical { writing-mode: vertical-lr; transform: rotate(180deg); } +form.dashboard-widget-svggraph .svg-graph-preview, form.dashboard-widget-svggraph .graph-widget-config-tabs { - padding: 10px 0; } - form.dashboard-widget-svggraph .graph-widget-config-tabs > .tabs-nav { - margin-right: 0; - margin-left: 0; - border-top: 1px solid #444444; } - form.dashboard-widget-svggraph .graph-widget-config-tabs .ui-tabs-nav { - position: sticky; + grid-column: 1 / -1; } +form.dashboard-widget-svggraph .svg-graph-preview { + position: relative; + min-width: 1110px; + height: 300px; } + form.dashboard-widget-svggraph .svg-graph-preview > div { + position: absolute; top: 0; - background: #070707; + right: 0; + left: 0; + margin: 0 -10px; + height: 300px; + background: #000000; z-index: 3; } +form.dashboard-widget-svggraph .graph-widget-config-tabs > .tabs-nav { + border-top: 1px solid #444444; } +form.dashboard-widget-svggraph .graph-widget-config-tabs .ui-tabs-nav { + position: sticky; + top: 0; + background: #070707; + z-index: 3; } form.dashboard-widget-svggraph .table-forms-container, form.dashboard-widget-svggraph .browser-warning-container { + margin: -10px 0 0 0; border: 1px solid #444444; border-top: none; } form.dashboard-widget-svggraph .table-forms-separator { padding: 0; } -form.dashboard-widget-svggraph .dataset-head { - display: grid; - grid-template-columns: 24px 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; } +form.dashboard-widget-svggraph .dataset-head, form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body { - display: grid; - grid-template-columns: 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; - position: relative; - margin-top: 10px; } - form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body .form-grid { - padding-top: 0; } - form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body .form-grid:first-child { - grid-column-start: 2; } + display: contents; } +form.dashboard-widget-svggraph .dataset-head .multiselect { + width: 100%; } +form.dashboard-widget-svggraph .dataset-body .form-grid { + padding-top: 0; } + form.dashboard-widget-svggraph .dataset-body .form-grid:first-child { + grid-column-start: 3; } form.dashboard-widget-svggraph .drag-icon { position: absolute; + top: 5px; left: -14px; } form.dashboard-widget-svggraph .td-drag-icon .drag-icon { top: 0; @@ -1738,13 +1786,13 @@ form.dashboard-widget-svggraph .list-vertical-accordion { overflow: visible; margin-top: -5px; margin-bottom: -5px; } - form.dashboard-widget-svggraph .list-vertical-accordion .list-accordion-item-head { - padding: 0; } form.dashboard-widget-svggraph .list-accordion-item { position: relative; - width: 100%; - padding: 5px 0; - list-style-type: none; } + display: grid; + grid-template-columns: 24px 24px 1fr 1fr 24px; + grid-gap: 10px; + align-items: start; + padding: 5px 0; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-opened::before { content: ' '; position: absolute; @@ -1756,8 +1804,6 @@ form.dashboard-widget-svggraph .list-accordion-item { form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .multiselect { height: 24px; overflow: hidden; } - form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-body { - display: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .table-forms-separator { border: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table thead, @@ -1765,6 +1811,8 @@ form.dashboard-widget-svggraph .list-accordion-item { form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table .table-col-handle, form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table .table-col-action { display: none; } + form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-body { + display: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .items-list { padding-left: 0; } form.dashboard-widget-svggraph .single-item-table .table-col-handle { @@ -1783,11 +1831,83 @@ form.dashboard-widget-svggraph .single-item-table .single-item-table-row:last-ch padding-bottom: 0; } form.dashboard-widget-svggraph .single-item-table tfoot td { padding: 5px 5px 5px 10px; } +form.dashboard-widget-svggraph .overrides-list { + position: relative; + margin: -5px 0 -5px 15px; } +form.dashboard-widget-svggraph .overrides-list-item { + position: relative; + display: grid; + grid-template-columns: 1fr 1fr 24px; + grid-gap: 5px 10px; + align-items: start; + padding: 5px 0; } + form.dashboard-widget-svggraph .overrides-list-item.sortable { + overflow: visible; + margin-top: -5px; + margin-bottom: -5px; } + form.dashboard-widget-svggraph .overrides-list-item .multiselect { + width: 100%; } + form.dashboard-widget-svggraph .overrides-list-item .btn-remove { + right: 0; + top: 0; + vertical-align: baseline; } +form.dashboard-widget-svggraph .overrides-foot { + padding: 5px 0; } +form.dashboard-widget-svggraph .overrides-options-list { + grid-column: 1 / -1; + padding: 0 24px 8px 0; + border-bottom: 1px solid #333333; + white-space: normal; } + form.dashboard-widget-svggraph .overrides-options-list > li { + display: inline-block; + margin-right: 5px; + margin-bottom: 2px; + line-height: 22px; + white-space: nowrap; } + form.dashboard-widget-svggraph .overrides-options-list > li .color-picker { + line-height: 22px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div { + position: relative; + padding: 1px 18px 1px 1px; + background-color: #dddddd; + border-radius: 2px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > span { + color: white; + padding-left: 8px; + line-height: 22px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > input[type=text] { + border-style: none; + line-height: 22px; + min-height: 22px; + width: 85px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + position: absolute; + right: 0; + top: 0; + min-height: 24px; } + form.dashboard-widget-svggraph .overrides-options-list .btn-alt .plus-icon { + margin-right: 0; } + form.dashboard-widget-svggraph .overrides-options-list .color-picker .color-picker-preview { + margin: 1px; + width: 20px; + min-height: 20px; + background-position: -323px -411px; } form.dashboard-widget-svggraph .no-items-message { display: none; line-height: 24px; color: #cacaca; } +[theme="hc-dark"] form.dashboard-widget-svggraph .overrides-options-list > li > div { + border: 1px solid #ffffff; + background-color: transparent !important; } + [theme="hc-dark"] form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + border: none !important; + top: 0; } + +[theme="hc-light"] form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + border: none !important; + top: 0; } + form.dashboard-widget-tophosts #list_columns .text { max-width: 250px; } form.dashboard-widget-tophosts #column { @@ -2542,6 +2662,49 @@ div.dashboard-widget-tophosts z-bar-gauge { font-size: 0; border-left: 1px solid #111111; } +section { + background-color: #000000; + border: 1px solid #444444; } + section .section-head { + display: flex; + height: 32px; + line-height: 32px; } + section .section-head h4 { + padding: 0 10px; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + font-weight: bold; + line-height: inherit; + color: white; } + section .section-toggle { + width: 24px; + height: 24px; + margin: 2px 2px 0 auto; + background: url("../img/icon-sprite.svg?20220722") no-repeat -6px -654px; } + section .section-foot { + padding: 0 10px; + text-align: right; + line-height: 32px; + color: #cacaca; } + section.section-collapsed .section-body, + section.section-collapsed .section-foot { + display: none; } + section.section-collapsed .section-toggle { + background-position: -6px -689px; } + section:not(:last-child) { + margin-bottom: 10px; } + section .list-table { + border: 0; } + section .list-table tbody tr:last-child td { + border-bottom: 1px solid #333333; } + section .list-table td:first-child, + section .list-table th:first-child { + padding-left: 10px; } + section .list-table td:last-child, + section .list-table th:last-child { + padding-right: 10px; } + .service-info { margin: -10px 0; border-left: 4px solid #23d545; } @@ -4498,13 +4661,13 @@ button { width: 24px; height: 24px; } -.filter-container.tabfilter-container .icon-edit, .btn-dashboard-page-properties, .btn-iterator-page-previous, .btn-iterator-page-next, .btn-widget-action, .btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle, .btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle, .btn-widget-edit, .btn-alarm-on, .btn-alarm-off, .btn-sound-on, .btn-sound-off, .btn-info-clock, .btn-dashboard-conf, .interfaces .interface-row[data-type="2"] .interface-btn-toggle { +section .section-toggle, .filter-container.tabfilter-container .icon-edit, .btn-dashboard-page-properties, .btn-iterator-page-previous, .btn-iterator-page-next, .btn-widget-action, .btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle, .btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle, .btn-widget-edit, .btn-alarm-on, .btn-alarm-off, .btn-sound-on, .btn-sound-off, .btn-info-clock, .btn-dashboard-conf, .interfaces .interface-row[data-type="2"] .interface-btn-toggle { border: 0; min-height: 0; padding: 0; opacity: .5; transition: opacity .2s ease-out; } - .filter-container.tabfilter-container [disabled].icon-edit, [disabled].btn-dashboard-page-properties, [disabled].btn-iterator-page-previous, [disabled].btn-iterator-page-next, [disabled].btn-widget-action, [disabled].btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle, [disabled].btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle, [disabled].btn-widget-edit, [disabled].btn-alarm-on, [disabled].btn-alarm-off, [disabled].btn-sound-on, [disabled].btn-sound-off, [disabled].btn-info-clock, [disabled].btn-dashboard-conf, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle, .filter-container.tabfilter-container [disabled].icon-edit:hover, [disabled].btn-dashboard-page-properties:hover, [disabled].btn-iterator-page-previous:hover, [disabled].btn-iterator-page-next:hover, [disabled].btn-widget-action:hover, [disabled].btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-edit:hover, [disabled].btn-alarm-on:hover, [disabled].btn-alarm-off:hover, [disabled].btn-sound-on:hover, [disabled].btn-sound-off:hover, [disabled].btn-info-clock:hover, [disabled].btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:hover, .filter-container.tabfilter-container [disabled].icon-edit:focus, [disabled].btn-dashboard-page-properties:focus, [disabled].btn-iterator-page-previous:focus, [disabled].btn-iterator-page-next:focus, [disabled].btn-widget-action:focus, [disabled].btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-edit:focus, [disabled].btn-alarm-on:focus, [disabled].btn-alarm-off:focus, [disabled].btn-sound-on:focus, [disabled].btn-sound-off:focus, [disabled].btn-info-clock:focus, [disabled].btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:focus, .filter-container.tabfilter-container [disabled].icon-edit:active, [disabled].btn-dashboard-page-properties:active, [disabled].btn-iterator-page-previous:active, [disabled].btn-iterator-page-next:active, [disabled].btn-widget-action:active, [disabled].btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-edit:active, [disabled].btn-alarm-on:active, [disabled].btn-alarm-off:active, [disabled].btn-sound-on:active, [disabled].btn-sound-off:active, [disabled].btn-info-clock:active, [disabled].btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:active { + section [disabled].section-toggle, .filter-container.tabfilter-container [disabled].icon-edit, [disabled].btn-dashboard-page-properties, [disabled].btn-iterator-page-previous, [disabled].btn-iterator-page-next, [disabled].btn-widget-action, [disabled].btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle, [disabled].btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle, [disabled].btn-widget-edit, [disabled].btn-alarm-on, [disabled].btn-alarm-off, [disabled].btn-sound-on, [disabled].btn-sound-off, [disabled].btn-info-clock, [disabled].btn-dashboard-conf, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle, section [disabled].section-toggle:hover, .filter-container.tabfilter-container [disabled].icon-edit:hover, [disabled].btn-dashboard-page-properties:hover, [disabled].btn-iterator-page-previous:hover, [disabled].btn-iterator-page-next:hover, [disabled].btn-widget-action:hover, [disabled].btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-edit:hover, [disabled].btn-alarm-on:hover, [disabled].btn-alarm-off:hover, [disabled].btn-sound-on:hover, [disabled].btn-sound-off:hover, [disabled].btn-info-clock:hover, [disabled].btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:hover, section [disabled].section-toggle:focus, .filter-container.tabfilter-container [disabled].icon-edit:focus, [disabled].btn-dashboard-page-properties:focus, [disabled].btn-iterator-page-previous:focus, [disabled].btn-iterator-page-next:focus, [disabled].btn-widget-action:focus, [disabled].btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-edit:focus, [disabled].btn-alarm-on:focus, [disabled].btn-alarm-off:focus, [disabled].btn-sound-on:focus, [disabled].btn-sound-off:focus, [disabled].btn-info-clock:focus, [disabled].btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:focus, section [disabled].section-toggle:active, .filter-container.tabfilter-container [disabled].icon-edit:active, [disabled].btn-dashboard-page-properties:active, [disabled].btn-iterator-page-previous:active, [disabled].btn-iterator-page-next:active, [disabled].btn-widget-action:active, [disabled].btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-edit:active, [disabled].btn-alarm-on:active, [disabled].btn-alarm-off:active, [disabled].btn-sound-on:active, [disabled].btn-sound-off:active, [disabled].btn-info-clock:active, [disabled].btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:active { background-color: transparent; opacity: .25; } @@ -4532,7 +4695,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active { .inaccessible .subfilter-enabled { color: #bfbfbf; } -.filter-container.tabfilter-container .icon-edit:hover, .btn-dashboard-page-properties:hover, .btn-iterator-page-previous:hover, .btn-iterator-page-next:hover, .btn-widget-action:hover, .btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:hover, .btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:hover, .btn-widget-edit:hover, .btn-alarm-on:hover, .btn-alarm-off:hover, .btn-sound-on:hover, .btn-sound-off:hover, .btn-info-clock:hover, .btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:hover, .filter-container.tabfilter-container .icon-edit:focus, .btn-dashboard-page-properties:focus, .btn-iterator-page-previous:focus, .btn-iterator-page-next:focus, .btn-widget-action:focus, .btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:focus, .btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:focus, .btn-widget-edit:focus, .btn-alarm-on:focus, .btn-alarm-off:focus, .btn-sound-on:focus, .btn-sound-off:focus, .btn-info-clock:focus, .btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:focus, .filter-container.tabfilter-container .icon-edit:active, .btn-dashboard-page-properties:active, .btn-iterator-page-previous:active, .btn-iterator-page-next:active, .btn-widget-action:active, .btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:active, .btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:active, .btn-widget-edit:active, .btn-alarm-on:active, .btn-alarm-off:active, .btn-sound-on:active, .btn-sound-off:active, .btn-info-clock:active, .btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:active { +section .section-toggle:hover, .filter-container.tabfilter-container .icon-edit:hover, .btn-dashboard-page-properties:hover, .btn-iterator-page-previous:hover, .btn-iterator-page-next:hover, .btn-widget-action:hover, .btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:hover, .btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:hover, .btn-widget-edit:hover, .btn-alarm-on:hover, .btn-alarm-off:hover, .btn-sound-on:hover, .btn-sound-off:hover, .btn-info-clock:hover, .btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:hover, section .section-toggle:focus, .filter-container.tabfilter-container .icon-edit:focus, .btn-dashboard-page-properties:focus, .btn-iterator-page-previous:focus, .btn-iterator-page-next:focus, .btn-widget-action:focus, .btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:focus, .btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:focus, .btn-widget-edit:focus, .btn-alarm-on:focus, .btn-alarm-off:focus, .btn-sound-on:focus, .btn-sound-off:focus, .btn-info-clock:focus, .btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:focus, section .section-toggle:active, .filter-container.tabfilter-container .icon-edit:active, .btn-dashboard-page-properties:active, .btn-iterator-page-previous:active, .btn-iterator-page-next:active, .btn-widget-action:active, .btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:active, .btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:active, .btn-widget-edit:active, .btn-alarm-on:active, .btn-alarm-off:active, .btn-sound-on:active, .btn-sound-off:active, .btn-info-clock:active, .btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:active { background-color: transparent; opacity: 1; } @@ -4625,16 +4788,16 @@ button[disabled], button[disabled]:hover, button[disabled]:active { content: ''; } .icon-tree-top-bottom::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -300px; } + background-position: -84px -300px; } .icon-tree-top-bottom-right::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -334px; } + background-position: -84px -334px; } .icon-tree-top-right::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -372px; } + background-position: -84px -372px; } .icon-tree-empty::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -350px; } + background-position: -84px -350px; } .icon-cal { background: transparent url("../img/icon-sprite.svg?20220722") no-repeat -42px -834px; } @@ -4915,7 +5078,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active { overflow: hidden; margin: 0 10px; } .overlay-dialogue.modal .dashboard-widget-head { - margin-bottom: 14px; } + margin-bottom: 12px; } .overlay-dialogue.modal .dashboard-widget-head .icon-doc-link { margin-right: -26px; } .overlay-dialogue.modal .dashboard-widget-head .overlay-close-btn { @@ -4928,9 +5091,11 @@ button[disabled], button[disabled]:hover, button[disabled]:active { width: 100%; max-height: calc(100vh - 220px); max-width: inherit; - margin: 0 -10px 10px; + margin: 0 -10px 8px; padding: 0 10px; position: relative; } + .overlay-dialogue.modal .overlay-dialogue-body > form { + padding: 2px 0; } .overlay-dialogue.modal .overlay-dialogue-body .table-forms .table-forms-td-right { padding-right: 8px; } .overlay-dialogue.modal .overlay-dialogue-body .table-forms .table-forms-row-with-second-field { @@ -5327,20 +5492,6 @@ button[disabled], button[disabled]:hover, button[disabled]:active { stroke: #ff5050; stroke-width: 2px; } -.svg-graph-preview { - margin-top: 10px; - min-width: 1120px; - height: 300px; - position: relative; } - .svg-graph-preview > div { - background: #000000; - height: 300px; - position: absolute; - left: 0; - right: 0; - top: 0; - z-index: 3; } - .svg-graph-hintbox { font-size: 12px; line-height: 18px; @@ -5884,22 +6035,22 @@ span.is-loading { padding: 10px 0 0; text-align: center; } -.dashboard-grid-widget-content, div.dashboard-widget-item, .msg-details ul, z-select button.focusable, +.dashboard-grid-widget-content, div.dashboard-widget-item > div, .msg-details ul, z-select button.focusable, .z-select button.focusable, z-select .list, .z-select .list, .multiselect-available, textarea, select, .setup-right-body, .overlay-dialogue.modal .overlay-dialogue-body, .overlay-dialogue .hintbox-wrap, .overlay-dialogue .maps-container, .notif-body, .debug-output, .overlay-descr, .overflow-table, .import-compare .toc, .import-compare .diff { scrollbar-width: thin; } - .dashboard-grid-widget-content::-webkit-scrollbar, div.dashboard-widget-item::-webkit-scrollbar, .msg-details ul::-webkit-scrollbar, z-select button.focusable::-webkit-scrollbar, + .dashboard-grid-widget-content::-webkit-scrollbar, div.dashboard-widget-item > div::-webkit-scrollbar, .msg-details ul::-webkit-scrollbar, z-select button.focusable::-webkit-scrollbar, .z-select button.focusable::-webkit-scrollbar, z-select .list::-webkit-scrollbar, .z-select .list::-webkit-scrollbar, .multiselect-available::-webkit-scrollbar, textarea::-webkit-scrollbar, select::-webkit-scrollbar, .setup-right-body::-webkit-scrollbar, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar, .overlay-dialogue .maps-container::-webkit-scrollbar, .notif-body::-webkit-scrollbar, .debug-output::-webkit-scrollbar, .overlay-descr::-webkit-scrollbar, .overflow-table::-webkit-scrollbar, .import-compare .toc::-webkit-scrollbar, .import-compare .diff::-webkit-scrollbar { width: 9px; } - .dashboard-grid-widget-content::-webkit-scrollbar-track, div.dashboard-widget-item::-webkit-scrollbar-track, .msg-details ul::-webkit-scrollbar-track, z-select button.focusable::-webkit-scrollbar-track, + .dashboard-grid-widget-content::-webkit-scrollbar-track, div.dashboard-widget-item > div::-webkit-scrollbar-track, .msg-details ul::-webkit-scrollbar-track, z-select button.focusable::-webkit-scrollbar-track, .z-select button.focusable::-webkit-scrollbar-track, z-select .list::-webkit-scrollbar-track, .z-select .list::-webkit-scrollbar-track, .multiselect-available::-webkit-scrollbar-track, textarea::-webkit-scrollbar-track, select::-webkit-scrollbar-track, .setup-right-body::-webkit-scrollbar-track, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar-track, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar-track, .overlay-dialogue .maps-container::-webkit-scrollbar-track, .notif-body::-webkit-scrollbar-track, .debug-output::-webkit-scrollbar-track, .overlay-descr::-webkit-scrollbar-track, .overflow-table::-webkit-scrollbar-track, .import-compare .toc::-webkit-scrollbar-track, .import-compare .diff::-webkit-scrollbar-track { background-color: #1f1f1f; } - .dashboard-grid-widget-content::-webkit-scrollbar-thumb, div.dashboard-widget-item::-webkit-scrollbar-thumb, .msg-details ul::-webkit-scrollbar-thumb, z-select button.focusable::-webkit-scrollbar-thumb, + .dashboard-grid-widget-content::-webkit-scrollbar-thumb, div.dashboard-widget-item > div::-webkit-scrollbar-thumb, .msg-details ul::-webkit-scrollbar-thumb, z-select button.focusable::-webkit-scrollbar-thumb, .z-select button.focusable::-webkit-scrollbar-thumb, z-select .list::-webkit-scrollbar-thumb, .z-select .list::-webkit-scrollbar-thumb, .multiselect-available::-webkit-scrollbar-thumb, textarea::-webkit-scrollbar-thumb, select::-webkit-scrollbar-thumb, .setup-right-body::-webkit-scrollbar-thumb, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar-thumb, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar-thumb, .overlay-dialogue .maps-container::-webkit-scrollbar-thumb, .notif-body::-webkit-scrollbar-thumb, .debug-output::-webkit-scrollbar-thumb, .overlay-descr::-webkit-scrollbar-thumb, .overflow-table::-webkit-scrollbar-thumb, .import-compare .toc::-webkit-scrollbar-thumb, .import-compare .diff::-webkit-scrollbar-thumb { @@ -6040,53 +6191,6 @@ svg { white-space: normal; word-break: break-word; } -.overrides-list { - display: table; - width: 90%; - max-width: 738px; - padding-left: 15px; } - .overrides-list .overrides-list-item { - display: table-row; } - .overrides-list .overrides-list-item .btn-remove { - position: relative; - right: -73px; - top: 3px; } - -.overrides-options-list { - white-space: normal; - padding: 5px 0 8px; - margin-bottom: 10px; - border-bottom: 1px solid #333333; } - .overrides-options-list > li { - display: inline-block; - margin: 2px 7px 2px 0; - white-space: nowrap; - vertical-align: middle; } - .overrides-options-list > li > div { - position: relative; - padding: 1px 18px 1px 1px; - background-color: #dddddd; - border-radius: 2px; } - .overrides-options-list > li > div > span { - color: white; - padding-left: 8px; - line-height: 22px; } - .overrides-options-list > li > div > input[type=text] { - border-style: none; - line-height: 22px; - min-height: 22px; - width: 85px; } - .overrides-options-list > li > div > .subfilter-disable-btn { - position: absolute; - right: 0; - top: 0; - min-height: 24px; } - .overrides-options-list .color-picker .color-picker-preview { - margin: 1px; - width: 20px; - min-height: 20px; - background-position: -323px -411px; } - .list-accordion-foot > div { display: table-cell; padding-top: 10px; } @@ -6132,63 +6236,6 @@ svg { text-overflow: ellipsis; line-height: 24px; } -.columns-wrapper { - display: flex; - flex-wrap: wrap; - align-items: start; } - .columns-wrapper.columns-nowrap { - flex-wrap: nowrap; } - .columns-wrapper.columns-2 > div, - .columns-wrapper.columns-2 > li { - display: block; - flex: 0 0 50%; - max-width: 50%; } - .columns-wrapper.columns-3 > div, - .columns-wrapper.columns-3 > li { - display: block; - flex: 0 0 33.33333%; - max-width: 33.33333%; } - .columns-wrapper .column-5 { - flex: 0 0 5%; - max-width: 5%; } - .columns-wrapper .column-10 { - flex: 0 0 10%; - max-width: 10%; } - .columns-wrapper .column-15 { - flex: 0 0 15%; - max-width: 15%; } - .columns-wrapper .column-20 { - flex: 0 0 20%; - max-width: 20%; } - .columns-wrapper .column-33 { - flex: 0 0 33.33333%; - max-width: 33.33333%; } - .columns-wrapper .column-35 { - flex: 0 0 35%; - max-width: 35%; } - .columns-wrapper .column-40 { - flex: 0 0 40%; - max-width: 40%; } - .columns-wrapper .column-50 { - flex: 0 0 50%; - max-width: 50%; } - .columns-wrapper .column-75 { - flex: 0 0 75%; - max-width: 75%; } - .columns-wrapper .column-90 { - flex: 0 0 90%; - max-width: 90%; } - .columns-wrapper .column-95 { - flex: 0 0 95%; - max-width: 95%; } - .columns-wrapper .column-center { - display: flex; - justify-content: center; - text-align: center; } - .columns-wrapper .column-middle { - display: flex; - align-items: center; } - .preprocessing-list { display: block; max-width: 930px; @@ -8024,13 +8071,6 @@ td.inactive-bg { .problem-icon-list .status-disaster-bg::before { background-position: -472px -432px; } -.overrides-options-list > li > div { - border: 1px solid #ffffff; - background-color: transparent !important; } - .overrides-options-list > li > div > .subfilter-disable-btn { - border: none !important; - top: 0; } - .totals-list > div { border-top: 1px solid #444444; color: #ffffff; } @@ -8074,3 +8114,8 @@ td.inactive-bg { background-position: -318px -690px; } .interfaces .interface-row[data-type="2"].list-accordion-item-opened .interface-btn-toggle { background-position: -318px -655px; } + +section .section-toggle { + background-position: -318px -654px; } +section.section-collapsed .section-toggle { + background-position: -318px -690px; } diff --git a/ui/assets/styles/hc-light.css b/ui/assets/styles/hc-light.css index 83cdcd1f8b2..09919987373 100644 --- a/ui/assets/styles/hc-light.css +++ b/ui/assets/styles/hc-light.css @@ -336,7 +336,9 @@ svg a { top: 0; left: 0; transition: left .2s, top .2s; } - .sortable .sortable-list .sortable-item:not(.sortable-dragging) { + .sortable .sortable-item { + box-sizing: border-box; } + .sortable .sortable-item:not(.sortable-dragging) { transition: left .2s, top .2s; } .sortable.sortable-dragging .sortable-item { position: absolute; } @@ -654,7 +656,6 @@ footer { .form-grid { display: grid; - padding: 5px; row-gap: 10px; column-gap: 10px; grid-template-columns: minmax(15%, max-content) auto; } @@ -670,6 +671,9 @@ footer { word-wrap: break-word; } .form-grid > label.fields-group-label { padding-top: 5px; } + .form-grid > label .icon-help-hint, + .form-grid > label .icon-info { + margin-left: 5px; } .form-grid > .form-field, .form-grid > .field-fluid, .form-grid .form-actions { @@ -872,6 +876,66 @@ footer { .color-picker-dialogue .color-picker-input input { padding-left: 25px; } +.columns-wrapper { + display: flex; + flex-wrap: wrap; + align-items: start; } + .columns-wrapper.columns-nowrap { + flex-wrap: nowrap; } + .columns-wrapper.columns-2 > div, + .columns-wrapper.columns-2 > li { + display: block; + flex: 0 0 50%; + max-width: 50%; } + .columns-wrapper.columns-3 > div, + .columns-wrapper.columns-3 > li { + display: block; + flex: 0 0 33.33333%; + max-width: 33.33333%; } + .columns-wrapper .column-5 { + flex: 0 0 5%; + max-width: 5%; } + .columns-wrapper .column-10 { + flex: 0 0 10%; + max-width: 10%; } + .columns-wrapper .column-15 { + flex: 0 0 15%; + max-width: 15%; } + .columns-wrapper .column-20 { + flex: 0 0 20%; + max-width: 20%; } + .columns-wrapper .column-33 { + flex: 0 0 33.33333%; + max-width: 33.33333%; } + .columns-wrapper .column-35 { + flex: 0 0 35%; + max-width: 35%; } + .columns-wrapper .column-40 { + flex: 0 0 40%; + max-width: 40%; } + .columns-wrapper .column-50 { + flex: 0 0 50%; + max-width: 50%; } + .columns-wrapper .column-75 { + flex: 0 0 75%; + max-width: 75%; } + .columns-wrapper .column-90 { + flex: 0 0 90%; + max-width: 90%; } + .columns-wrapper .column-95 { + flex: 0 0 95%; + max-width: 95%; } + .columns-wrapper .column-center { + display: flex; + justify-content: center; + text-align: center; } + .columns-wrapper .column-middle { + display: flex; + align-items: center; } + .columns-wrapper > div:not(:last-child) section, + .columns-wrapper > ul:not(:last-child) section { + margin-right: 10px; } + .header-kioskmode-controls .dashboard-kioskmode-controls li { margin-right: 6px; } @@ -1421,8 +1485,6 @@ footer { .dashboard-widget .msg-good, .dashboard-widget .msg-warning { margin: 0 10px; } - .dashboard-widget.dashboard-widget-fluid { - margin-right: 0; } .dashboard-grid-widget-content .list-table th:first-child, .dashboard-grid-widget-content .list-table td:first-child, .dashboard-grid-iterator.iterator-alt-content .dashboard-grid-iterator-content > div .list-table th:first-child, .dashboard-grid-iterator.iterator-alt-content .dashboard-grid-iterator-content > div .list-table td:first-child, .dashboard-widget .list-table th:first-child, .dashboard-widget .list-table td:first-child, .overlay-dialogue .list-table th:first-child, .overlay-dialogue .list-table td:first-child { padding-left: 10px; } @@ -1483,30 +1545,22 @@ footer { .wrapper.layout-kioskmode .dashboard-navigation { display: none; } -form.dashboard-widget-clock .fields-group-date, -form.dashboard-widget-clock .fields-group-time, -form.dashboard-widget-clock .fields-group-tzone { +form.dashboard-widget-clock .fields-group.fields-group-date, form.dashboard-widget-clock .fields-group.fields-group-time, form.dashboard-widget-clock .fields-group.fields-group-tzone { display: grid; grid-template-columns: 60px 120px repeat(2, minmax(60px, max-content) auto); align-items: center; column-gap: 10px; row-gap: 5px; } - form.dashboard-widget-clock .fields-group-date label, - form.dashboard-widget-clock .fields-group-time label, - form.dashboard-widget-clock .fields-group-tzone label { + form.dashboard-widget-clock .fields-group.fields-group-date label, form.dashboard-widget-clock .fields-group.fields-group-time label, form.dashboard-widget-clock .fields-group.fields-group-tzone label { text-align: right; } - form.dashboard-widget-clock .fields-group-date .field-size input, - form.dashboard-widget-clock .fields-group-time .field-size input, - form.dashboard-widget-clock .fields-group-tzone .field-size input { + form.dashboard-widget-clock .fields-group.fields-group-date .field-size input, form.dashboard-widget-clock .fields-group.fields-group-time .field-size input, form.dashboard-widget-clock .fields-group.fields-group-tzone .field-size input { margin-right: 5px; } -form.dashboard-widget-clock .fields-group-time .field-format { +form.dashboard-widget-clock .fields-group.fields-group-time .field-format { grid-column: 4 / -1; } -form.dashboard-widget-clock .fields-group-tzone .field-format { - grid-column: 2 / -1; } -form.dashboard-widget-clock .fields-group-tzone .field-timezone { +form.dashboard-widget-clock .fields-group.fields-group-tzone .form-field.field-tzone-timezone, form.dashboard-widget-clock .fields-group.fields-group-tzone .form-field.field-tzone-format { grid-column: 2 / -1; } -div.dashboard-widget-clock.clock-digital { +div.dashboard-widget-clock .clock-digital { box-sizing: border-box; min-height: 100%; padding: 10px; @@ -1514,9 +1568,9 @@ div.dashboard-widget-clock.clock-digital { flex-direction: column; justify-content: center; align-items: center; } - div.dashboard-widget-clock.clock-digital .clock-date, - div.dashboard-widget-clock.clock-digital .clock-time, - div.dashboard-widget-clock.clock-digital .clock-time-zone { + div.dashboard-widget-clock .clock-digital .clock-date, + div.dashboard-widget-clock .clock-digital .clock-time, + div.dashboard-widget-clock .clock-digital .clock-time-zone { max-width: 100%; white-space: nowrap; overflow: hidden; @@ -1524,150 +1578,137 @@ div.dashboard-widget-clock.clock-digital { font-size: calc(var(--content-height) * var(--widget-clock-font) / 1.14); line-height: 1.14; flex-shrink: 0; } - div.dashboard-widget-clock.clock-digital .bold { + div.dashboard-widget-clock .clock-digital .bold { font-weight: bold; } - div.dashboard-widget-clock.clock-digital .clock-disabled { + div.dashboard-widget-clock .clock-digital .clock-disabled { font-size: calc(var(--content-height) * 0.6 / 1.14); color: #333333; font-weight: bold; } -form.dashboard-widget-item .fields-group-description, -form.dashboard-widget-item .fields-group-value, -form.dashboard-widget-item .fields-group-time, -form.dashboard-widget-item .fields-group-change-indicator { +.dashboard-widget-inaccessible { + display: grid; + align-items: center; + padding-right: 10px; + padding-left: 10px; + text-align: center; + color: #333333; } + +form.dashboard-widget-item .fields-group.fields-group-description, form.dashboard-widget-item .fields-group.fields-group-value, form.dashboard-widget-item .fields-group.fields-group-time, form.dashboard-widget-item .fields-group.fields-group-change-indicator { display: grid; grid-template-columns: minmax(100px, max-content) 3fr max-content auto; align-items: center; column-gap: 10px; row-gap: 5px; } - form.dashboard-widget-item .fields-group-description label, - form.dashboard-widget-item .fields-group-value label, - form.dashboard-widget-item .fields-group-time label, - form.dashboard-widget-item .fields-group-change-indicator label { + form.dashboard-widget-item .fields-group.fields-group-description label, form.dashboard-widget-item .fields-group.fields-group-value label, form.dashboard-widget-item .fields-group.fields-group-time label, form.dashboard-widget-item .fields-group.fields-group-change-indicator label { text-align: right; } - form.dashboard-widget-item .fields-group-description hr, - form.dashboard-widget-item .fields-group-value hr, - form.dashboard-widget-item .fields-group-time hr, - form.dashboard-widget-item .fields-group-change-indicator hr { + form.dashboard-widget-item .fields-group.fields-group-description hr, form.dashboard-widget-item .fields-group.fields-group-value hr, form.dashboard-widget-item .fields-group.fields-group-time hr, form.dashboard-widget-item .fields-group.fields-group-change-indicator hr { grid-column: 1 / -1; margin: 0; width: 100%; border: solid #888888; border-width: 1px 0 0 0; } - form.dashboard-widget-item .fields-group-description .field-fluid, - form.dashboard-widget-item .fields-group-value .field-fluid, - form.dashboard-widget-item .fields-group-time .field-fluid, - form.dashboard-widget-item .fields-group-change-indicator .field-fluid { + form.dashboard-widget-item .fields-group.fields-group-description .field-fluid, form.dashboard-widget-item .fields-group.fields-group-value .field-fluid, form.dashboard-widget-item .fields-group.fields-group-time .field-fluid, form.dashboard-widget-item .fields-group.fields-group-change-indicator .field-fluid { grid-column: 2 / -1; } - form.dashboard-widget-item .fields-group-description .offset-3, - form.dashboard-widget-item .fields-group-value .offset-3, - form.dashboard-widget-item .fields-group-time .offset-3, - form.dashboard-widget-item .fields-group-change-indicator .offset-3 { + form.dashboard-widget-item .fields-group.fields-group-description .offset-3, form.dashboard-widget-item .fields-group.fields-group-value .offset-3, form.dashboard-widget-item .fields-group.fields-group-time .offset-3, form.dashboard-widget-item .fields-group.fields-group-change-indicator .offset-3 { grid-column-start: 3; } - form.dashboard-widget-item .fields-group-description .field-size input, - form.dashboard-widget-item .fields-group-value .field-size input, - form.dashboard-widget-item .fields-group-time .field-size input, - form.dashboard-widget-item .fields-group-change-indicator .field-size input { + form.dashboard-widget-item .fields-group.fields-group-description .field-size input, form.dashboard-widget-item .fields-group.fields-group-value .field-size input, form.dashboard-widget-item .fields-group.fields-group-time .field-size input, form.dashboard-widget-item .fields-group.fields-group-change-indicator .field-size input { margin-right: 5px; } - form.dashboard-widget-item .fields-group-description .form-field, - form.dashboard-widget-item .fields-group-value .form-field, - form.dashboard-widget-item .fields-group-time .form-field, - form.dashboard-widget-item .fields-group-change-indicator .form-field { + form.dashboard-widget-item .fields-group.fields-group-description .form-field, form.dashboard-widget-item .fields-group.fields-group-value .form-field, form.dashboard-widget-item .fields-group.fields-group-time .form-field, form.dashboard-widget-item .fields-group.fields-group-change-indicator .form-field { line-height: 24px; } -form.dashboard-widget-item .fields-group-description .form-field:nth-child(1) { +form.dashboard-widget-item .fields-group.fields-group-description .form-field:nth-child(1) { grid-column: 1 / -1; } -form.dashboard-widget-item .fields-group-value { +form.dashboard-widget-item .fields-group.fields-group-value { grid-template-columns: minmax(100px, max-content) 3fr max-content auto; } - form.dashboard-widget-item .fields-group-value .units-show { + form.dashboard-widget-item .fields-group.fields-group-value .units-show { display: flex; } - form.dashboard-widget-item .fields-group-value .units-show label[for='units'] { + form.dashboard-widget-item .fields-group.fields-group-value .units-show label[for='units'] { width: 100%; } -form.dashboard-widget-item .fields-group-change-indicator { +form.dashboard-widget-item .fields-group.fields-group-change-indicator { grid-template-columns: repeat(3, max-content 96px); } -form.dashboard-widget-item .fields-group-change-indicator .input-color-picker { - display: block; } + form.dashboard-widget-item .fields-group.fields-group-change-indicator .input-color-picker { + display: block; } -div.dashboard-widget-item { +div.dashboard-widget-item > div { box-sizing: border-box; height: 100%; padding: 10px; overflow-x: hidden; } - div.dashboard-widget-item a { - box-sizing: border-box; - display: flex; - flex-direction: column; - height: 100%; - color: inherit; } - div.dashboard-widget-item a:focus, div.dashboard-widget-item a:hover, div.dashboard-widget-item a:visited { - border: none; } - div.dashboard-widget-item a > div { - display: flex; - flex: 1 1 calc(100% / 3); } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .item-value, - div.dashboard-widget-item .item-time { - flex: 1 1 auto; - max-width: 100%; } - div.dashboard-widget-item .item-value { +div.dashboard-widget-item a { + box-sizing: border-box; + display: flex; + flex-direction: column; + height: 100%; + color: inherit; } + div.dashboard-widget-item a:focus, div.dashboard-widget-item a:hover, div.dashboard-widget-item a:visited { + border: none; } + div.dashboard-widget-item a > div { display: flex; - flex-wrap: wrap; - margin: 0 5px; } - div.dashboard-widget-item .item-value > .units:first-child, div.dashboard-widget-item .item-value > .units:last-child { - flex: 0 0 100%; } - div.dashboard-widget-item .item-value > .units:first-child { - margin-bottom: -0.07em; } - div.dashboard-widget-item .item-value > .units:last-child { - margin-top: -0.07em; } - div.dashboard-widget-item .item-value.type-text { + flex: 1 1 calc(100% / 3); } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .item-value, +div.dashboard-widget-item .item-time { + flex: 1 1 auto; + max-width: 100%; } +div.dashboard-widget-item .item-value { + display: flex; + flex-wrap: wrap; + margin: 0 5px; } + div.dashboard-widget-item .item-value > .units:first-child, div.dashboard-widget-item .item-value > .units:last-child { + flex: 0 0 100%; } + div.dashboard-widget-item .item-value > .units:first-child { + margin-bottom: -0.07em; } + div.dashboard-widget-item .item-value > .units:last-child { + margin-top: -0.07em; } + div.dashboard-widget-item .item-value.type-text { + min-width: 0; } + div.dashboard-widget-item .item-value.type-text .item-value-content { min-width: 0; } - div.dashboard-widget-item .item-value.type-text .item-value-content { - min-width: 0; } - div.dashboard-widget-item .item-value-content { - display: flex; - align-items: baseline; - overflow: hidden; } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .item-time, - div.dashboard-widget-item .type-text .value { - display: block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } - div.dashboard-widget-item .item-description, - div.dashboard-widget-item .value, - div.dashboard-widget-item .decimals, - div.dashboard-widget-item .units, - div.dashboard-widget-item .item-time { - font-size: calc(var(--content-height) * var(--widget-item-font) / 1.14); - line-height: 1.14; } - div.dashboard-widget-item .units:not(:last-child), - div.dashboard-widget-item .change-indicator:not(:last-child) { - margin-right: 5px; } - div.dashboard-widget-item .units:not(:first-child), - div.dashboard-widget-item .change-indicator:not(:first-child) { - margin-left: 5px; } - div.dashboard-widget-item .svg-arrow { - height: calc(var(--content-height) * var(--widget-item-font) * 0.72 / 1.14); } - div.dashboard-widget-item .item-value-no-data { - color: #333333; } - div.dashboard-widget-item .left { - justify-content: flex-start; - max-width: max-content; - margin-right: auto; } - div.dashboard-widget-item .center { - justify-content: center; } - div.dashboard-widget-item .right { - justify-content: flex-end; - max-width: max-content; - margin-left: auto; } - div.dashboard-widget-item .top { - align-self: flex-start; } - div.dashboard-widget-item .middle { - align-self: center; } - div.dashboard-widget-item .bottom { - align-self: flex-end; } - div.dashboard-widget-item .bold { - font-weight: bold; } +div.dashboard-widget-item .item-value-content { + display: flex; + align-items: baseline; + overflow: hidden; } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .item-time, +div.dashboard-widget-item .type-text .value { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } +div.dashboard-widget-item .item-description, +div.dashboard-widget-item .value, +div.dashboard-widget-item .decimals, +div.dashboard-widget-item .units, +div.dashboard-widget-item .item-time { + font-size: calc(var(--content-height) * var(--widget-item-font) / 1.14); + line-height: 1.14; } +div.dashboard-widget-item .units:not(:last-child), +div.dashboard-widget-item .change-indicator:not(:last-child) { + margin-right: 5px; } +div.dashboard-widget-item .units:not(:first-child), +div.dashboard-widget-item .change-indicator:not(:first-child) { + margin-left: 5px; } +div.dashboard-widget-item .svg-arrow { + height: calc(var(--content-height) * var(--widget-item-font) * 0.72 / 1.14); } +div.dashboard-widget-item .item-value-no-data { + color: #333333; } +div.dashboard-widget-item .left { + justify-content: flex-start; + max-width: max-content; + margin-right: auto; } +div.dashboard-widget-item .center { + justify-content: center; } +div.dashboard-widget-item .right { + justify-content: flex-end; + max-width: max-content; + margin-left: auto; } +div.dashboard-widget-item .top { + align-self: flex-start; } +div.dashboard-widget-item .middle { + align-self: center; } +div.dashboard-widget-item .bottom { + align-self: flex-end; } +div.dashboard-widget-item .bold { + font-weight: bold; } .dashboard-widget-item .svg-arrow-up { fill: #3DC51D; } @@ -1683,40 +1724,47 @@ div.dashboard-widget-slareport .date-vertical { writing-mode: vertical-lr; transform: rotate(180deg); } +form.dashboard-widget-svggraph .svg-graph-preview, form.dashboard-widget-svggraph .graph-widget-config-tabs { - padding: 10px 0; } - form.dashboard-widget-svggraph .graph-widget-config-tabs > .tabs-nav { - margin-right: 0; - margin-left: 0; - border-top: 1px solid #9f9f9f; } - form.dashboard-widget-svggraph .graph-widget-config-tabs .ui-tabs-nav { - position: sticky; + grid-column: 1 / -1; } +form.dashboard-widget-svggraph .svg-graph-preview { + position: relative; + min-width: 1110px; + height: 300px; } + form.dashboard-widget-svggraph .svg-graph-preview > div { + position: absolute; top: 0; - background: #f3f3f3; + right: 0; + left: 0; + margin: 0 -10px; + height: 300px; + background: #ffffff; z-index: 3; } +form.dashboard-widget-svggraph .graph-widget-config-tabs > .tabs-nav { + border-top: 1px solid #9f9f9f; } +form.dashboard-widget-svggraph .graph-widget-config-tabs .ui-tabs-nav { + position: sticky; + top: 0; + background: #f3f3f3; + z-index: 3; } form.dashboard-widget-svggraph .table-forms-container, form.dashboard-widget-svggraph .browser-warning-container { + margin: -10px 0 0 0; border: 1px solid #9f9f9f; border-top: none; } form.dashboard-widget-svggraph .table-forms-separator { padding: 0; } -form.dashboard-widget-svggraph .dataset-head { - display: grid; - grid-template-columns: 24px 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; } +form.dashboard-widget-svggraph .dataset-head, form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body { - display: grid; - grid-template-columns: 24px 1fr 1fr 24px; - grid-gap: 10px; - align-items: start; - position: relative; - margin-top: 10px; } - form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body .form-grid { - padding-top: 0; } - form.dashboard-widget-svggraph .dataset-body.list-accordion-item-body .form-grid:first-child { - grid-column-start: 2; } + display: contents; } +form.dashboard-widget-svggraph .dataset-head .multiselect { + width: 100%; } +form.dashboard-widget-svggraph .dataset-body .form-grid { + padding-top: 0; } + form.dashboard-widget-svggraph .dataset-body .form-grid:first-child { + grid-column-start: 3; } form.dashboard-widget-svggraph .drag-icon { position: absolute; + top: 5px; left: -14px; } form.dashboard-widget-svggraph .td-drag-icon .drag-icon { top: 0; @@ -1738,13 +1786,13 @@ form.dashboard-widget-svggraph .list-vertical-accordion { overflow: visible; margin-top: -5px; margin-bottom: -5px; } - form.dashboard-widget-svggraph .list-vertical-accordion .list-accordion-item-head { - padding: 0; } form.dashboard-widget-svggraph .list-accordion-item { position: relative; - width: 100%; - padding: 5px 0; - list-style-type: none; } + display: grid; + grid-template-columns: 24px 24px 1fr 1fr 24px; + grid-gap: 10px; + align-items: start; + padding: 5px 0; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-opened::before { content: ' '; position: absolute; @@ -1756,8 +1804,6 @@ form.dashboard-widget-svggraph .list-accordion-item { form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .multiselect { height: 24px; overflow: hidden; } - form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-body { - display: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .table-forms-separator { border: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table thead, @@ -1765,6 +1811,8 @@ form.dashboard-widget-svggraph .list-accordion-item { form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table .table-col-handle, form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-head .single-item-table .table-col-action { display: none; } + form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .dataset-body { + display: none; } form.dashboard-widget-svggraph .list-accordion-item.list-accordion-item-closed .items-list { padding-left: 0; } form.dashboard-widget-svggraph .single-item-table .table-col-handle { @@ -1783,11 +1831,83 @@ form.dashboard-widget-svggraph .single-item-table .single-item-table-row:last-ch padding-bottom: 0; } form.dashboard-widget-svggraph .single-item-table tfoot td { padding: 5px 5px 5px 10px; } +form.dashboard-widget-svggraph .overrides-list { + position: relative; + margin: -5px 0 -5px 15px; } +form.dashboard-widget-svggraph .overrides-list-item { + position: relative; + display: grid; + grid-template-columns: 1fr 1fr 24px; + grid-gap: 5px 10px; + align-items: start; + padding: 5px 0; } + form.dashboard-widget-svggraph .overrides-list-item.sortable { + overflow: visible; + margin-top: -5px; + margin-bottom: -5px; } + form.dashboard-widget-svggraph .overrides-list-item .multiselect { + width: 100%; } + form.dashboard-widget-svggraph .overrides-list-item .btn-remove { + right: 0; + top: 0; + vertical-align: baseline; } +form.dashboard-widget-svggraph .overrides-foot { + padding: 5px 0; } +form.dashboard-widget-svggraph .overrides-options-list { + grid-column: 1 / -1; + padding: 0 24px 8px 0; + border-bottom: 1px solid #888888; + white-space: normal; } + form.dashboard-widget-svggraph .overrides-options-list > li { + display: inline-block; + margin-right: 5px; + margin-bottom: 2px; + line-height: 22px; + white-space: nowrap; } + form.dashboard-widget-svggraph .overrides-options-list > li .color-picker { + line-height: 22px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div { + position: relative; + padding: 1px 18px 1px 1px; + background-color: #333333; + border-radius: 2px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > span { + color: white; + padding-left: 8px; + line-height: 22px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > input[type=text] { + border-style: none; + line-height: 22px; + min-height: 22px; + width: 85px; } + form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + position: absolute; + right: 0; + top: 0; + min-height: 24px; } + form.dashboard-widget-svggraph .overrides-options-list .btn-alt .plus-icon { + margin-right: 0; } + form.dashboard-widget-svggraph .overrides-options-list .color-picker .color-picker-preview { + margin: 1px; + width: 20px; + min-height: 20px; + background-position: -323px -411px; } form.dashboard-widget-svggraph .no-items-message { display: none; line-height: 24px; color: #333333; } +[theme="hc-dark"] form.dashboard-widget-svggraph .overrides-options-list > li > div { + border: 1px solid #888888; + background-color: transparent !important; } + [theme="hc-dark"] form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + border: none !important; + top: 0; } + +[theme="hc-light"] form.dashboard-widget-svggraph .overrides-options-list > li > div > .subfilter-disable-btn { + border: none !important; + top: 0; } + form.dashboard-widget-tophosts #list_columns .text { max-width: 250px; } form.dashboard-widget-tophosts #column { @@ -2542,6 +2662,49 @@ div.dashboard-widget-tophosts z-bar-gauge { font-size: 0; border-left: 1px solid #ffffff; } +section { + background-color: #ffffff; + border: 1px solid #9f9f9f; } + section .section-head { + display: flex; + height: 32px; + line-height: 32px; } + section .section-head h4 { + padding: 0 10px; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + font-weight: bold; + line-height: inherit; + color: #262626; } + section .section-toggle { + width: 24px; + height: 24px; + margin: 2px 2px 0 auto; + background: url("../img/icon-sprite.svg?20220722") no-repeat -6px -654px; } + section .section-foot { + padding: 0 10px; + text-align: right; + line-height: 32px; + color: #333333; } + section.section-collapsed .section-body, + section.section-collapsed .section-foot { + display: none; } + section.section-collapsed .section-toggle { + background-position: -6px -689px; } + section:not(:last-child) { + margin-bottom: 10px; } + section .list-table { + border: 0; } + section .list-table tbody tr:last-child td { + border-bottom: 1px solid #888888; } + section .list-table td:first-child, + section .list-table th:first-child { + padding-left: 10px; } + section .list-table td:last-child, + section .list-table th:last-child { + padding-right: 10px; } + .service-info { margin: -10px 0; border-left: 4px solid #009900; } @@ -4498,13 +4661,13 @@ button { width: 24px; height: 24px; } -.filter-container.tabfilter-container .icon-edit, .btn-dashboard-page-properties, .btn-iterator-page-previous, .btn-iterator-page-next, .btn-widget-action, .btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle, .btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle, .btn-widget-edit, .btn-alarm-on, .btn-alarm-off, .btn-sound-on, .btn-sound-off, .btn-info-clock, .btn-dashboard-conf, .interfaces .interface-row[data-type="2"] .interface-btn-toggle { +section .section-toggle, .filter-container.tabfilter-container .icon-edit, .btn-dashboard-page-properties, .btn-iterator-page-previous, .btn-iterator-page-next, .btn-widget-action, .btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle, .btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle, .btn-widget-edit, .btn-alarm-on, .btn-alarm-off, .btn-sound-on, .btn-sound-off, .btn-info-clock, .btn-dashboard-conf, .interfaces .interface-row[data-type="2"] .interface-btn-toggle { border: 0; min-height: 0; padding: 0; opacity: .5; transition: opacity .2s ease-out; } - .filter-container.tabfilter-container [disabled].icon-edit, [disabled].btn-dashboard-page-properties, [disabled].btn-iterator-page-previous, [disabled].btn-iterator-page-next, [disabled].btn-widget-action, [disabled].btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle, [disabled].btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle, [disabled].btn-widget-edit, [disabled].btn-alarm-on, [disabled].btn-alarm-off, [disabled].btn-sound-on, [disabled].btn-sound-off, [disabled].btn-info-clock, [disabled].btn-dashboard-conf, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle, .filter-container.tabfilter-container [disabled].icon-edit:hover, [disabled].btn-dashboard-page-properties:hover, [disabled].btn-iterator-page-previous:hover, [disabled].btn-iterator-page-next:hover, [disabled].btn-widget-action:hover, [disabled].btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-edit:hover, [disabled].btn-alarm-on:hover, [disabled].btn-alarm-off:hover, [disabled].btn-sound-on:hover, [disabled].btn-sound-off:hover, [disabled].btn-info-clock:hover, [disabled].btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:hover, .filter-container.tabfilter-container [disabled].icon-edit:focus, [disabled].btn-dashboard-page-properties:focus, [disabled].btn-iterator-page-previous:focus, [disabled].btn-iterator-page-next:focus, [disabled].btn-widget-action:focus, [disabled].btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-edit:focus, [disabled].btn-alarm-on:focus, [disabled].btn-alarm-off:focus, [disabled].btn-sound-on:focus, [disabled].btn-sound-off:focus, [disabled].btn-info-clock:focus, [disabled].btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:focus, .filter-container.tabfilter-container [disabled].icon-edit:active, [disabled].btn-dashboard-page-properties:active, [disabled].btn-iterator-page-previous:active, [disabled].btn-iterator-page-next:active, [disabled].btn-widget-action:active, [disabled].btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-edit:active, [disabled].btn-alarm-on:active, [disabled].btn-alarm-off:active, [disabled].btn-sound-on:active, [disabled].btn-sound-off:active, [disabled].btn-info-clock:active, [disabled].btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:active { + section [disabled].section-toggle, .filter-container.tabfilter-container [disabled].icon-edit, [disabled].btn-dashboard-page-properties, [disabled].btn-iterator-page-previous, [disabled].btn-iterator-page-next, [disabled].btn-widget-action, [disabled].btn-widget-collapse, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle, [disabled].btn-widget-expand, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle, [disabled].btn-widget-edit, [disabled].btn-alarm-on, [disabled].btn-alarm-off, [disabled].btn-sound-on, [disabled].btn-sound-off, [disabled].btn-info-clock, [disabled].btn-dashboard-conf, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle, section [disabled].section-toggle:hover, .filter-container.tabfilter-container [disabled].icon-edit:hover, [disabled].btn-dashboard-page-properties:hover, [disabled].btn-iterator-page-previous:hover, [disabled].btn-iterator-page-next:hover, [disabled].btn-widget-action:hover, [disabled].btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:hover, [disabled].btn-widget-edit:hover, [disabled].btn-alarm-on:hover, [disabled].btn-alarm-off:hover, [disabled].btn-sound-on:hover, [disabled].btn-sound-off:hover, [disabled].btn-info-clock:hover, [disabled].btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:hover, section [disabled].section-toggle:focus, .filter-container.tabfilter-container [disabled].icon-edit:focus, [disabled].btn-dashboard-page-properties:focus, [disabled].btn-iterator-page-previous:focus, [disabled].btn-iterator-page-next:focus, [disabled].btn-widget-action:focus, [disabled].btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:focus, [disabled].btn-widget-edit:focus, [disabled].btn-alarm-on:focus, [disabled].btn-alarm-off:focus, [disabled].btn-sound-on:focus, [disabled].btn-sound-off:focus, [disabled].btn-info-clock:focus, [disabled].btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:focus, section [disabled].section-toggle:active, .filter-container.tabfilter-container [disabled].icon-edit:active, [disabled].btn-dashboard-page-properties:active, [disabled].btn-iterator-page-previous:active, [disabled].btn-iterator-page-next:active, [disabled].btn-widget-action:active, [disabled].btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed [disabled].list-accordion-item-toggle:active, [disabled].btn-widget-edit:active, [disabled].btn-alarm-on:active, [disabled].btn-alarm-off:active, [disabled].btn-sound-on:active, [disabled].btn-sound-off:active, [disabled].btn-info-clock:active, [disabled].btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] [disabled].interface-btn-toggle:active { background-color: transparent; opacity: .25; } @@ -4532,7 +4695,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active { .inaccessible .subfilter-enabled { color: #bfbfbf; } -.filter-container.tabfilter-container .icon-edit:hover, .btn-dashboard-page-properties:hover, .btn-iterator-page-previous:hover, .btn-iterator-page-next:hover, .btn-widget-action:hover, .btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:hover, .btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:hover, .btn-widget-edit:hover, .btn-alarm-on:hover, .btn-alarm-off:hover, .btn-sound-on:hover, .btn-sound-off:hover, .btn-info-clock:hover, .btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:hover, .filter-container.tabfilter-container .icon-edit:focus, .btn-dashboard-page-properties:focus, .btn-iterator-page-previous:focus, .btn-iterator-page-next:focus, .btn-widget-action:focus, .btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:focus, .btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:focus, .btn-widget-edit:focus, .btn-alarm-on:focus, .btn-alarm-off:focus, .btn-sound-on:focus, .btn-sound-off:focus, .btn-info-clock:focus, .btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:focus, .filter-container.tabfilter-container .icon-edit:active, .btn-dashboard-page-properties:active, .btn-iterator-page-previous:active, .btn-iterator-page-next:active, .btn-widget-action:active, .btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:active, .btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:active, .btn-widget-edit:active, .btn-alarm-on:active, .btn-alarm-off:active, .btn-sound-on:active, .btn-sound-off:active, .btn-info-clock:active, .btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:active { +section .section-toggle:hover, .filter-container.tabfilter-container .icon-edit:hover, .btn-dashboard-page-properties:hover, .btn-iterator-page-previous:hover, .btn-iterator-page-next:hover, .btn-widget-action:hover, .btn-widget-collapse:hover, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:hover, .btn-widget-expand:hover, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:hover, .btn-widget-edit:hover, .btn-alarm-on:hover, .btn-alarm-off:hover, .btn-sound-on:hover, .btn-sound-off:hover, .btn-info-clock:hover, .btn-dashboard-conf:hover, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:hover, section .section-toggle:focus, .filter-container.tabfilter-container .icon-edit:focus, .btn-dashboard-page-properties:focus, .btn-iterator-page-previous:focus, .btn-iterator-page-next:focus, .btn-widget-action:focus, .btn-widget-collapse:focus, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:focus, .btn-widget-expand:focus, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:focus, .btn-widget-edit:focus, .btn-alarm-on:focus, .btn-alarm-off:focus, .btn-sound-on:focus, .btn-sound-off:focus, .btn-info-clock:focus, .btn-dashboard-conf:focus, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:focus, section .section-toggle:active, .filter-container.tabfilter-container .icon-edit:active, .btn-dashboard-page-properties:active, .btn-iterator-page-previous:active, .btn-iterator-page-next:active, .btn-widget-action:active, .btn-widget-collapse:active, .list-vertical-accordion .list-accordion-item-opened .list-accordion-item-toggle:active, .btn-widget-expand:active, .list-vertical-accordion .list-accordion-item-closed .list-accordion-item-toggle:active, .btn-widget-edit:active, .btn-alarm-on:active, .btn-alarm-off:active, .btn-sound-on:active, .btn-sound-off:active, .btn-info-clock:active, .btn-dashboard-conf:active, .interfaces .interface-row[data-type="2"] .interface-btn-toggle:active { background-color: transparent; opacity: 1; } @@ -4625,16 +4788,16 @@ button[disabled], button[disabled]:hover, button[disabled]:active { content: ''; } .icon-tree-top-bottom::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -300px; } + background-position: -84px -300px; } .icon-tree-top-bottom-right::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -334px; } + background-position: -84px -334px; } .icon-tree-top-right::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -372px; } + background-position: -84px -372px; } .icon-tree-empty::before { - background-position: url("../img/icon-sprite.svg?20220722") no-repeat -84px -350px; } + background-position: -84px -350px; } .icon-cal { background: transparent url("../img/icon-sprite.svg?20220722") no-repeat -42px -834px; } @@ -4915,7 +5078,7 @@ button[disabled], button[disabled]:hover, button[disabled]:active { overflow: hidden; margin: 0 10px; } .overlay-dialogue.modal .dashboard-widget-head { - margin-bottom: 14px; } + margin-bottom: 12px; } .overlay-dialogue.modal .dashboard-widget-head .icon-doc-link { margin-right: -26px; } .overlay-dialogue.modal .dashboard-widget-head .overlay-close-btn { @@ -4928,9 +5091,11 @@ button[disabled], button[disabled]:hover, button[disabled]:active { width: 100%; max-height: calc(100vh - 220px); max-width: inherit; - margin: 0 -10px 10px; + margin: 0 -10px 8px; padding: 0 10px; position: relative; } + .overlay-dialogue.modal .overlay-dialogue-body > form { + padding: 2px 0; } .overlay-dialogue.modal .overlay-dialogue-body .table-forms .table-forms-td-right { padding-right: 8px; } .overlay-dialogue.modal .overlay-dialogue-body .table-forms .table-forms-row-with-second-field { @@ -5327,20 +5492,6 @@ button[disabled], button[disabled]:hover, button[disabled]:active { stroke: #990000; stroke-width: 2px; } -.svg-graph-preview { - margin-top: 10px; - min-width: 1120px; - height: 300px; - position: relative; } - .svg-graph-preview > div { - background: #ffffff; - height: 300px; - position: absolute; - left: 0; - right: 0; - top: 0; - z-index: 3; } - .svg-graph-hintbox { font-size: 12px; line-height: 18px; @@ -5884,22 +6035,22 @@ span.is-loading { padding: 10px 0 0; text-align: center; } -.dashboard-grid-widget-content, div.dashboard-widget-item, .msg-details ul, z-select button.focusable, +.dashboard-grid-widget-content, div.dashboard-widget-item > div, .msg-details ul, z-select button.focusable, .z-select button.focusable, z-select .list, .z-select .list, .multiselect-available, textarea, select, .setup-right-body, .overlay-dialogue.modal .overlay-dialogue-body, .overlay-dialogue .hintbox-wrap, .overlay-dialogue .maps-container, .notif-body, .debug-output, .overlay-descr, .overflow-table, .import-compare .toc, .import-compare .diff { scrollbar-width: thin; } - .dashboard-grid-widget-content::-webkit-scrollbar, div.dashboard-widget-item::-webkit-scrollbar, .msg-details ul::-webkit-scrollbar, z-select button.focusable::-webkit-scrollbar, + .dashboard-grid-widget-content::-webkit-scrollbar, div.dashboard-widget-item > div::-webkit-scrollbar, .msg-details ul::-webkit-scrollbar, z-select button.focusable::-webkit-scrollbar, .z-select button.focusable::-webkit-scrollbar, z-select .list::-webkit-scrollbar, .z-select .list::-webkit-scrollbar, .multiselect-available::-webkit-scrollbar, textarea::-webkit-scrollbar, select::-webkit-scrollbar, .setup-right-body::-webkit-scrollbar, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar, .overlay-dialogue .maps-container::-webkit-scrollbar, .notif-body::-webkit-scrollbar, .debug-output::-webkit-scrollbar, .overlay-descr::-webkit-scrollbar, .overflow-table::-webkit-scrollbar, .import-compare .toc::-webkit-scrollbar, .import-compare .diff::-webkit-scrollbar { width: 9px; } - .dashboard-grid-widget-content::-webkit-scrollbar-track, div.dashboard-widget-item::-webkit-scrollbar-track, .msg-details ul::-webkit-scrollbar-track, z-select button.focusable::-webkit-scrollbar-track, + .dashboard-grid-widget-content::-webkit-scrollbar-track, div.dashboard-widget-item > div::-webkit-scrollbar-track, .msg-details ul::-webkit-scrollbar-track, z-select button.focusable::-webkit-scrollbar-track, .z-select button.focusable::-webkit-scrollbar-track, z-select .list::-webkit-scrollbar-track, .z-select .list::-webkit-scrollbar-track, .multiselect-available::-webkit-scrollbar-track, textarea::-webkit-scrollbar-track, select::-webkit-scrollbar-track, .setup-right-body::-webkit-scrollbar-track, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar-track, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar-track, .overlay-dialogue .maps-container::-webkit-scrollbar-track, .notif-body::-webkit-scrollbar-track, .debug-output::-webkit-scrollbar-track, .overlay-descr::-webkit-scrollbar-track, .overflow-table::-webkit-scrollbar-track, .import-compare .toc::-webkit-scrollbar-track, .import-compare .diff::-webkit-scrollbar-track { background-color: #999999; } - .dashboard-grid-widget-content::-webkit-scrollbar-thumb, div.dashboard-widget-item::-webkit-scrollbar-thumb, .msg-details ul::-webkit-scrollbar-thumb, z-select button.focusable::-webkit-scrollbar-thumb, + .dashboard-grid-widget-content::-webkit-scrollbar-thumb, div.dashboard-widget-item > div::-webkit-scrollbar-thumb, .msg-details ul::-webkit-scrollbar-thumb, z-select button.focusable::-webkit-scrollbar-thumb, .z-select button.focusable::-webkit-scrollbar-thumb, z-select .list::-webkit-scrollbar-thumb, .z-select .list::-webkit-scrollbar-thumb, .multiselect-available::-webkit-scrollbar-thumb, textarea::-webkit-scrollbar-thumb, select::-webkit-scrollbar-thumb, .setup-right-body::-webkit-scrollbar-thumb, .overlay-dialogue.modal .overlay-dialogue-body::-webkit-scrollbar-thumb, .overlay-dialogue .hintbox-wrap::-webkit-scrollbar-thumb, .overlay-dialogue .maps-container::-webkit-scrollbar-thumb, .notif-body::-webkit-scrollbar-thumb, .debug-output::-webkit-scrollbar-thumb, .overlay-descr::-webkit-scrollbar-thumb, .overflow-table::-webkit-scrollbar-thumb, .import-compare .toc::-webkit-scrollbar-thumb, .import-compare .diff::-webkit-scrollbar-thumb { @@ -6040,53 +6191,6 @@ svg { white-space: normal; word-break: break-word; } -.overrides-list { - display: table; - width: 90%; - max-width: 738px; - padding-left: 15px; } - .overrides-list .overrides-list-item { - display: table-row; } - .overrides-list .overrides-list-item .btn-remove { - position: relative; - right: -73px; - top: 3px; } - -.overrides-options-list { - white-space: normal; - padding: 5px 0 8px; - margin-bottom: 10px; - border-bottom: 1px solid #888888; } - .overrides-options-list > li { - display: inline-block; - margin: 2px 7px 2px 0; - white-space: nowrap; - vertical-align: middle; } - .overrides-options-list > li > div { - position: relative; - padding: 1px 18px 1px 1px; - background-color: #333333; - border-radius: 2px; } - .overrides-options-list > li > div > span { - color: white; - padding-left: 8px; - line-height: 22px; } - .overrides-options-list > li > div > input[type=text] { - border-style: none; - line-height: 22px; - min-height: 22px; - width: 85px; } - .overrides-options-list > li > div > .subfilter-disable-btn { - position: absolute; - right: 0; - top: 0; - min-height: 24px; } - .overrides-options-list .color-picker .color-picker-preview { - margin: 1px; - width: 20px; - min-height: 20px; - background-position: -323px -411px; } - .list-accordion-foot > div { display: table-cell; padding-top: 10px; } @@ -6132,63 +6236,6 @@ svg { text-overflow: ellipsis; line-height: 24px; } -.columns-wrapper { - display: flex; - flex-wrap: wrap; - align-items: start; } - .columns-wrapper.columns-nowrap { - flex-wrap: nowrap; } - .columns-wrapper.columns-2 > div, - .columns-wrapper.columns-2 > li { - display: block; - flex: 0 0 50%; - max-width: 50%; } - .columns-wrapper.columns-3 > div, - .columns-wrapper.columns-3 > li { - display: block; - flex: 0 0 33.33333%; - max-width: 33.33333%; } - .columns-wrapper .column-5 { - flex: 0 0 5%; - max-width: 5%; } - .columns-wrapper .column-10 { - flex: 0 0 10%; - max-width: 10%; } - .columns-wrapper .column-15 { - flex: 0 0 15%; - max-width: 15%; } - .columns-wrapper .column-20 { - flex: 0 0 20%; - max-width: 20%; } - .columns-wrapper .column-33 { - flex: 0 0 33.33333%; - max-width: 33.33333%; } - .columns-wrapper .column-35 { - flex: 0 0 35%; - max-width: 35%; } - .columns-wrapper .column-40 { - flex: 0 0 40%; - max-width: 40%; } - .columns-wrapper .column-50 { - flex: 0 0 50%; - max-width: 50%; } - .columns-wrapper .column-75 { - flex: 0 0 75%; - max-width: 75%; } - .columns-wrapper .column-90 { - flex: 0 0 90%; - max-width: 90%; } - .columns-wrapper .column-95 { - flex: 0 0 95%; - max-width: 95%; } - .columns-wrapper .column-center { - display: flex; - justify-content: center; - text-align: center; } - .columns-wrapper .column-middle { - display: flex; - align-items: center; } - .preprocessing-list { display: block; max-width: 930px; @@ -7938,12 +7985,6 @@ td.inactive-bg { .problem-icon-list .status-disaster-bg::before { background-position: -472px -409px; } -.overrides-options-list > li > div { - background-color: #333333 !important; } - .overrides-options-list > li > div > .subfilter-disable-btn { - border: none !important; - top: 0; } - .totals-list > div { border-top: 1px solid #9f9f9f; color: #000000; } @@ -7985,3 +8026,8 @@ td.inactive-bg { background-position: -165px -690px; } .interfaces .interface-row[data-type="2"].list-accordion-item-opened .interface-btn-toggle { background-position: -165px -655px; } + +section .section-toggle { + background-position: -165px -654px; } +section.section-collapsed .section-toggle { + background-position: -165px -690px; } diff --git a/ui/hostinventoriesoverview.php b/ui/hostinventoriesoverview.php index 97750f5e7b2..d1e3ed30286 100644 --- a/ui/hostinventoriesoverview.php +++ b/ui/hostinventoriesoverview.php @@ -142,7 +142,7 @@ $select_groupby = (new CSelect('filter_groupby')) ->addOption(new CSelectOption('', _('not selected'))) ->addOptions(CSelect::createOptionsFromArray($inventories)); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Host inventory overview')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::INVENTORY_HOST_OVERVIEW)) ->addItem( diff --git a/ui/httpdetails.php b/ui/httpdetails.php index 0aa84c36788..61a14f9a76b 100644 --- a/ui/httpdetails.php +++ b/ui/httpdetails.php @@ -181,7 +181,7 @@ $graph_time->insertFlickerfreeJs(); CScreenBuilder::insertScreenStandardJs($graph_in->timeline); // Create graphs widget. -$widget = (new CWidget()) +(new CHtmlPage()) ->setTitle(_('Details of web scenario').': '.$http_test_name) ->setWebLayoutMode($page['web_layout_mode']) ->setControls((new CTag('nav', true, diff --git a/ui/include/classes/api/services/CConfiguration.php b/ui/include/classes/api/services/CConfiguration.php index fe93d89239d..fe3f85c7f23 100644 --- a/ui/include/classes/api/services/CConfiguration.php +++ b/ui/include/classes/api/services/CConfiguration.php @@ -209,9 +209,7 @@ class CConfiguration extends CApiService { ->setStrict(true) ->validate($data, '/'); - $all_versions = ['1.0', '2.0', '3.0', '3.2', '3.4', '4.0', '4.2', '4.4', '5.0', '5.2', '5.4', '6.0', '6.2']; - - foreach ($all_versions as $version) { + foreach ($import_converter_factory::getSequentialVersions() as $version) { if ($data['zabbix_export']['version'] !== $version) { continue; } @@ -281,7 +279,7 @@ class CConfiguration extends CApiService { ->setPreview(true) ->validate($data, '/'); - foreach (['1.0', '2.0', '3.0', '3.2', '3.4', '4.0', '4.2', '4.4', '5.0', '5.2', '5.4', '6.0'] as $version) { + foreach ($import_converter_factory::getSequentialVersions() as $version) { if ($data['zabbix_export']['version'] !== $version) { continue; } diff --git a/ui/include/classes/api/services/CModule.php b/ui/include/classes/api/services/CModule.php index b2190d10e98..9b060c26e7e 100644 --- a/ui/include/classes/api/services/CModule.php +++ b/ui/include/classes/api/services/CModule.php @@ -132,7 +132,7 @@ class CModule extends CApiService { * * @param array $modules * - * @throws APIException if the input is invalid. + * @throws APIException|JsonException */ private static function validateCreate(array &$modules): void { $api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'fields' => [ @@ -147,7 +147,7 @@ class CModule extends CApiService { } foreach ($modules as &$module) { - $module['config'] = json_encode($module['config']); + $module['config'] = json_encode($module['config'], JSON_THROW_ON_ERROR); } unset($module); } @@ -196,7 +196,7 @@ class CModule extends CApiService { * @param array $modules * @param array|null $db_modules * - * @throws APIException if the input is invalid. + * @throws APIException|JsonException */ private static function validateUpdate(array &$modules, array &$db_modules = null): void { $api_input_rules = ['type' => API_OBJECTS, 'flags' => API_NOT_EMPTY | API_NORMALIZE, 'uniq' => [['moduleid']], 'fields' => [ @@ -221,7 +221,7 @@ class CModule extends CApiService { foreach ($modules as &$module) { if (array_key_exists('config', $module)) { - $module['config'] = json_encode($module['config']); + $module['config'] = json_encode($module['config'], JSON_THROW_ON_ERROR); } } unset($module); diff --git a/ui/include/classes/api/services/CRole.php b/ui/include/classes/api/services/CRole.php index 34ff83732d4..fb87a1d1c20 100644 --- a/ui/include/classes/api/services/CRole.php +++ b/ui/include/classes/api/services/CRole.php @@ -700,7 +700,7 @@ class CRole extends CApiService { return; } - $unavailable_moduleids = array_diff(array_keys($moduleids), self::getEnabledModuleIds()); + $unavailable_moduleids = array_diff(array_keys($moduleids), self::getModuleIds()); if ($unavailable_moduleids) { self::exception(ZBX_API_ERROR_PARAMETERS, @@ -1036,7 +1036,7 @@ class CRole extends CApiService { $index = 0; - foreach (self::getEnabledModuleIds() as $moduleid) { + foreach (self::getModuleIds() as $moduleid) { if (array_key_exists($moduleid, $new_modules_rules)) { $module_status = $new_modules_rules[$moduleid]['status']; } @@ -1154,7 +1154,7 @@ class CRole extends CApiService { * @return array */ protected function applyQueryFilterOptions($table_name, $table_alias, array $options, array $sql_parts): array { - $sqlParts = parent::applyQueryFilterOptions($table_name, $table_alias, $options, $sql_parts); + $sql_parts = parent::applyQueryFilterOptions($table_name, $table_alias, $options, $sql_parts); if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) { $sql_parts['from']['users'] = 'users u'; @@ -1162,7 +1162,7 @@ class CRole extends CApiService { $sql_parts['where'][] = 'u.userid='.self::$userData['userid']; } - return $sqlParts; + return $sql_parts; } /** @@ -1417,7 +1417,7 @@ class CRole extends CApiService { if (in_array('modules', $output, true)) { $modules = []; - foreach (self::getEnabledModuleIds() as $moduleid) { + foreach (self::getModuleIds() as $moduleid) { $modules[$moduleid] = [ 'moduleid' => $moduleid, 'status' => $modules_default_access @@ -1520,12 +1520,9 @@ class CRole extends CApiService { * * @throws APIException */ - private static function getEnabledModuleIds(): array { + private static function getModuleIds(): array { $modules = API::getApiService('module')->get([ 'output' => [], - 'filter' => [ - 'status' => MODULE_STATUS_ENABLED - ], 'preservekeys' => true ], false); diff --git a/ui/include/classes/core/CModule.php b/ui/include/classes/core/CModule.php index 86cac8653ba..41c52c44492 100644 --- a/ui/include/classes/core/CModule.php +++ b/ui/include/classes/core/CModule.php @@ -19,119 +19,115 @@ **/ -namespace Core; +namespace Zabbix\Core; -use CController as CAction; +use API, + CController as CAction; /** * Base class for user modules. If Module.php is not provided by user module, this class will be instantiated instead. */ class CModule { - /** - * Module directory path. - * - * @var string - */ - private $dir; + public const TYPE_MODULE = 'module'; + public const TYPE_WIDGET = 'widget'; - /** - * Module manifest. - * - * @var array - */ - private $manifest; + protected array $manifest; + protected string $moduleid; + protected string $relative_path; - /** - * @param string $dir Module directory path. - * @param array $manifest Module manifest. - */ - public function __construct(string $dir, array $manifest) { - $this->dir = $dir; + public function __construct(array $manifest, string $moduleid, string $relative_path) { $this->manifest = $manifest; + $this->moduleid = $moduleid; + $this->relative_path = $relative_path; } - /** - * Initialize module. - */ public function init(): void { } - /** - * Get module directory path. - * - * @return string - */ - final public function getDir(): string { - return $this->dir; - } - - /** - * Get module manifest. - * - * @return array - */ - final public function getManifest(): array { + public function getManifest(): array { return $this->manifest; } - /** - * Get module id. - * - * @return string - */ - final public function getId(): string { + public function getId(): string { return $this->manifest['id']; } - /** - * Get module namespace. - * - * @return string - */ - final public function getNamespace(): string { + public function getName(): string { + return $this->manifest['name']; + } + + public function getNamespace(): string { return $this->manifest['namespace']; } - /** - * Get module version. - * - * @return string - */ - final public function getVersion(): string { + public function getVersion(): string { return $this->manifest['version']; } - /** - * Get module actions. - * - * @return array - */ - final public function getActions(): array { + public function getType(): string { + return $this->manifest['type']; + } + + public function getAuthor(): string { + return $this->manifest['author']; + } + + public function getUrl(): string { + return $this->manifest['url']; + } + + public function getDescription(): string { + return $this->manifest['description']; + } + + public function getActions(): array { return $this->manifest['actions']; } - /** - * Get module configuration. - * - * @return array - */ - final public function getConfig(): array { + public function getAssets(): array { + return $this->manifest['assets']; + } + + public function getConfig(): array { return $this->manifest['config']; } + public function setConfig(array $config): self { + $this->manifest['config'] = $config; + + API::Module()->update([[ + 'moduleid' => $this->moduleid, + 'config' => $config + ]]); + + return $this; + } + /** * Get module configuration option. * - * @param string $name Option name. - * @param mixed $default Default value. + * @param string|null $name Option name. + * @param mixed $default Default value. * * @return mixed Configuration option (if exists) or the $default value. */ - final public function getOption(string $name = null, $default = null) { + public function getOption(string $name = null, $default = null) { return array_key_exists($name, $this->manifest['config']) ? $this->manifest['config'][$name] : $default; } + public function getModuleId(): string { + return $this->moduleid; + } + + public function getRelativePath(): string { + return $this->relative_path; + } + + public function getTranslationStrings(): array { + return []; + } + /** * Event handler, triggered before executing the action. * diff --git a/ui/include/classes/core/CModuleManager.php b/ui/include/classes/core/CModuleManager.php index d54a96b593c..cf3f1229dbb 100644 --- a/ui/include/classes/core/CModuleManager.php +++ b/ui/include/classes/core/CModuleManager.php @@ -19,8 +19,12 @@ **/ -use Core\CModule, - CController as CAction; +use CController as CAction; + +use Zabbix\Core\{ + CModule, + CWidget +}; /** * Module manager class for testing and loading user modules. @@ -28,64 +32,65 @@ use Core\CModule, final class CModuleManager { /** + * Lowest supported manifest version. + */ + private const MIN_MANIFEST_VERSION = 2; + + /** * Highest supported manifest version. */ - const MAX_MANIFEST_VERSION = 1; + private const MAX_MANIFEST_VERSION = 2; /** - * Home path of modules. - * - * @var string + * Root path of modules. + */ + private string $root_path; + + /** + * Current action name. */ - private $modules_dir; + private string $action_name; /** * Manifest data of added modules. - * - * @var array */ - private $manifests = []; + private array $manifests = []; /** - * List of instantiated, initialized modules. - * - * @var array + * DB moduleids of added modules. */ - private $modules = []; + private array $moduleids = []; /** - * List of errors caused by module initialization. - * - * @var array + * List of instantiated, initialized modules. */ - private $errors = []; + private array $modules = []; /** - * @param string $modules_dir Home path of modules. + * List of errors caused by module initialization. */ - public function __construct(string $modules_dir) { - $this->modules_dir = $modules_dir; - } + private array $errors = []; /** - * Get home path of modules. - * - * @return string + * @param string $root_path Root path of modules. */ - public function getModulesDir(): string { - return $this->modules_dir; + public function __construct(string $root_path) { + $this->root_path = $root_path; } /** * Add module and prepare it's manifest data. * * @param string $relative_path Relative path to the module. - * @param string $id Stored module ID to optionally check the manifest module ID against. + * @param string|null $moduleid DB module ID. + * @param string|null $id Stored module ID to optionally check the manifest module ID against. * @param array|null $config Override configuration to use instead of one stored in the manifest file. * * @return array|null Either manifest data or null if manifest file had errors or IDs didn't match. */ - public function addModule(string $relative_path, string $id = null, array $config = null): ?array { + public function addModule(string $relative_path, string $moduleid = null, string $id = null, + array $config = null): ?array { + $manifest = $this->loadManifest($relative_path); // Ignore module without a valid manifest. @@ -104,88 +109,12 @@ final class CModuleManager { } $this->manifests[$relative_path] = $manifest; + $this->moduleids[$relative_path] = $moduleid; return $manifest; } - /** - * Get namespaces of all added modules. - * - * @return array - */ - public function getNamespaces(): array { - $namespaces = []; - - foreach ($this->manifests as $relative_path => $manifest) { - $module_path = $this->modules_dir.'/'.$relative_path; - $namespaces['Modules\\'.$manifest['namespace']] = [$module_path]; - } - - return $namespaces; - } - - /** - * Check added modules for conflicts. - * - * @return array Lists of conflicts and conflicting modules. - */ - public function checkConflicts(): array { - $ids = []; - $namespaces = []; - $actions = []; - - foreach ($this->manifests as $relative_path => $manifest) { - $ids[$manifest['id']][] = $relative_path; - $namespaces[$manifest['namespace']][] = $relative_path; - foreach (array_keys($manifest['actions']) as $action_name) { - $actions[$action_name][] = $relative_path; - } - } - - foreach (['ids', 'namespaces', 'actions'] as $var) { - $$var = array_filter($$var, function($list) { - return count($list) > 1; - }); - } - - $conflicts = []; - $conflicting_manifests = []; - - foreach ($ids as $id => $relative_paths) { - $conflicts[] = _s('Identical ID (%1$s) is used by modules located at %2$s.', $id, - implode(', ', $relative_paths) - ); - $conflicting_manifests = array_merge($conflicting_manifests, $relative_paths); - } - - foreach ($namespaces as $namespace => $relative_paths) { - $conflicts[] = _s('Identical namespace (%1$s) is used by modules located at %2$s.', $namespace, - implode(', ', $relative_paths) - ); - $conflicting_manifests = array_merge($conflicting_manifests, $relative_paths); - } - - $relative_paths = array_unique(array_reduce($actions, function($carry, $item) { - return array_merge($carry, $item); - }, [])); - - if ($relative_paths) { - $conflicts[] = _s('Identical actions are used by modules located at %1$s.', implode(', ', $relative_paths)); - $conflicting_manifests = array_merge($conflicting_manifests, $relative_paths); - } - - return [ - 'conflicts' => $conflicts, - 'conflicting_manifests' => array_unique($conflicting_manifests) - ]; - } - - /** - * Check, instantiate and initialize all added modules. - * - * @return array List of initialized modules. - */ - public function initModules(): array { + public function initModules(): void { [ 'conflicts' => $this->errors, 'conflicting_manifests' => $conflicting_manifests @@ -194,63 +123,66 @@ final class CModuleManager { $non_conflicting_manifests = array_diff_key($this->manifests, array_flip($conflicting_manifests)); foreach ($non_conflicting_manifests as $relative_path => $manifest) { - $path = $this->modules_dir.'/'.$relative_path; + $base_classname = $manifest['type'] === CModule::TYPE_WIDGET ? CWidget::class : CModule::class; + $classname = $manifest['type'] === CModule::TYPE_WIDGET ? 'Widget' : 'Module'; - if (is_file($path.'/Module.php')) { - $module_class = implode('\\', ['Modules', $manifest['namespace'], 'Module']); + $module_class = $base_classname; + + try { + if (is_file($this->root_path.'/'.$relative_path.'/'.$classname.'.php')) { + $module_class = implode('\\', [$manifest['namespace'], $classname]); - if (!class_exists($module_class, true)) { - $this->errors[] = _s('Wrong Module.php class name for module located at %1$s.', $relative_path); + if (!class_exists($module_class)) { + $this->errors[] = _s('Wrong %1$s.php class name for module located at %2$s.', $classname, + $relative_path + ); - continue; + return; + } } - } - else { - $module_class = CModule::class; - } - try { /** @var CModule $instance */ - $instance = new $module_class($path, $manifest); + $instance = new $module_class($manifest, $this->moduleids[$relative_path], $relative_path); - if ($instance instanceof CModule) { + if ($instance instanceof $base_classname) { $instance->init(); $this->modules[$instance->getId()] = $instance; } else { - $this->errors[] = _s('Module.php class must extend %1$s for module located at %2$s.', - CModule::class, $relative_path + $this->errors[] = _s('%1$s.php class must extend %2$s for module located at %3$s.', + $classname, $base_classname, $relative_path ); } } - catch (Exception $e) { + catch (Throwable $e) { $this->errors[] = _s('%1$s - thrown by module located at %2$s.', $e->getMessage(), $relative_path); } } - - return $this->modules; } /** - * Get add initialized modules. - * - * @return array + * Get initialized modules. */ public function getModules(): array { return $this->modules; } + public function setActionName(string $action_name): self { + $this->action_name = $action_name; + + return $this; + } + /** - * Get loaded module instance associated with given action name. - * - * @param string $action_name + * Get loaded module instance associated with action. * * @return CModule|null */ - public function getModuleByActionName(string $action_name): ?CModule { + public function getActionModule(): ?CModule { + /** @var CModule $module */ foreach ($this->modules as $module) { - if (array_key_exists($action_name, $module->getActions())) { + if (array_key_exists($this->action_name, $module->getActions())) { return $module; } } @@ -259,17 +191,69 @@ final class CModuleManager { } /** + * Get initialized widget modules. + */ + public function getWidgets(bool $for_template_dashboard_only = false): array { + $widgets = []; + + /** @var CWidget $widget */ + foreach ($this->modules as $widget) { + if (!($widget instanceof CWidget) || ($for_template_dashboard_only && !$widget->hasTemplateSupport())) { + continue; + } + $widgets[$widget->getId()] = $widget; + } + + return $widgets; + } + + public function getWidgetsDefaults(bool $for_template_dashboard_only = false): array { + $widget_defaults = []; + + /** @var CWidget $widget */ + foreach (APP::ModuleManager()->getWidgets($for_template_dashboard_only) as $widget) { + $widget_defaults[$widget->getId()] = $widget->getDefaults(); + } + + return $widget_defaults; + } + + public function getModule($module_id): ?CModule { + if (!array_key_exists($module_id, $this->modules)) { + return null; + } + + return $this->modules[$module_id]; + } + + public function getManifests(): array { + return $this->manifests; + } + + /** + * Get namespaces of all added modules. + */ + public function getNamespaces(): array { + $namespaces = []; + + foreach ($this->manifests as $relative_path => $manifest) { + $namespaces[$manifest['namespace']] = [$this->root_path.'/'.$relative_path]; + } + + return $namespaces; + } + + /** * Get actions of all initialized modules. - * - * @return array */ public function getActions(): array { $actions = []; + /** @var CModule $module */ foreach ($this->modules as $module) { foreach ($module->getActions() as $name => $data) { $actions[$name] = [ - 'class' => implode('\\', ['Modules', $module->getNamespace(), 'Actions', + 'class' => implode('\\', [$module->getNamespace(), 'Actions', str_replace('/', '\\', $data['class']) ]), 'layout' => array_key_exists('layout', $data) ? $data['layout'] : 'layout.htmlpage', @@ -281,6 +265,86 @@ final class CModuleManager { return $actions; } + public function getAssets(): array { + $assets = []; + + /** @var CModule $module */ + foreach ($this->modules as $module) { + if ($module->getType() === CModule::TYPE_WIDGET && !CRouter::isDashboardAction($this->action_name)) { + continue; + } + + $assets[$module->getId()] = $module->getAssets(); + } + + return $assets; + } + + /** + * Get errors encountered while module initialization. + */ + public function getErrors(): array { + return $this->errors; + } + + /** + * Check added modules for conflicts. + * + * @return array Lists of conflicts and conflicting modules. + */ + public function checkConflicts(): array { + $ids = []; + $namespaces = []; + $actions = []; + + foreach ($this->manifests as $relative_path => $manifest) { + $ids[$manifest['id']][] = $relative_path; + $namespaces[$manifest['namespace']][] = $relative_path; + foreach (array_keys($manifest['actions']) as $action_name) { + $actions[$action_name][] = $relative_path; + } + } + + foreach (['ids', 'namespaces', 'actions'] as $var) { + $$var = array_filter($$var, static function($list) { + return count($list) > 1; + }); + } + + $conflicts = []; + $conflicting_manifests = []; + + foreach ($ids as $id => $relative_paths) { + $conflicts[] = _s('Identical ID (%1$s) is used by modules located at %2$s.', $id, + implode(', ', $relative_paths) + ); + $conflicting_manifests = array_merge($conflicting_manifests, $relative_paths); + } + + foreach ($namespaces as $namespace => $relative_paths) { + $conflicts[] = _s('Identical namespace (%1$s) is used by modules located at %2$s.', $namespace, + implode(', ', $relative_paths) + ); + $conflicting_manifests = array_merge($conflicting_manifests, $relative_paths); + } + + $relative_paths = array_unique(array_reduce($actions, static function($carry, $item) { + return array_merge($carry, $item); + }, [])); + + if ($relative_paths) { + $conflicts[] = _s('Identical actions are used by modules located at %1$s.', implode(', ', $relative_paths)); + $conflicting_manifests = array_merge($conflicting_manifests, $relative_paths); + } + + $this->errors = $conflicts; + + return [ + 'conflicts' => $conflicts, + 'conflicting_manifests' => array_unique($conflicting_manifests) + ]; + } + /** * Publish an event to all loaded modules. The module of the responsible action will be served last. * @@ -288,7 +352,7 @@ final class CModuleManager { * @param string $event Event to publish. */ public function publishEvent(CAction $action, string $event): void { - $action_module = $this->getModuleByActionName($action->getAction()); + $action_module = $this->getActionModule(); foreach ($this->modules as $module) { if ($module != $action_module) { @@ -302,15 +366,6 @@ final class CModuleManager { } /** - * Get errors encountered while module initialization. - * - * @return array - */ - public function getErrors(): array { - return $this->errors; - } - - /** * Load and parse module manifest file. * * @param string $relative_path Relative path to the module. @@ -318,8 +373,13 @@ final class CModuleManager { * @return array|null Either manifest data or null if manifest file had errors. */ private function loadManifest(string $relative_path): ?array { - $module_path = $this->modules_dir.'/'.$relative_path; - $manifest_file_name = $module_path.'/manifest.json'; + $relative_path_parts = explode('/', $relative_path, 2); + + if (count($relative_path_parts) != 2) { + return null; + } + + $manifest_file_name = $this->root_path.'/'.$relative_path.'/manifest.json'; if (!is_file($manifest_file_name) || !is_readable($manifest_file_name)) { return null; @@ -343,24 +403,60 @@ final class CModuleManager { } // Check manifest version. - if (!is_numeric($manifest['manifest_version']) || $manifest['manifest_version'] > self::MAX_MANIFEST_VERSION) { + if (!is_numeric($manifest['manifest_version']) || $manifest['manifest_version'] < self::MIN_MANIFEST_VERSION + || $manifest['manifest_version'] > self::MAX_MANIFEST_VERSION) { + return null; + } + + if (trim($manifest['id']) === '' || trim($manifest['name']) === '') { return null; } // Check manifest namespace syntax. - if (!preg_match('/^[a-z_]+$/i', $manifest['namespace'])) { + if (!preg_match('/^[0-9a-z_]+$/i', $manifest['namespace'])) { + return null; + } + + $manifest['namespace'] = ucfirst($relative_path_parts[0]).'\\'.$manifest['namespace']; + + // Check module type. + if (array_key_exists('type', $manifest) + && !in_array($manifest['type'], [CModule::TYPE_MODULE, CModule::TYPE_WIDGET], true)) { return null; } // Ensure empty defaults. $manifest += [ + 'type' => CModule::TYPE_MODULE, 'author' => '', 'url' => '', 'description' => '', 'actions' => [], + 'assets' => [], 'config' => [] ]; + $manifest['assets'] += [ + 'css' => [], + 'js' => [] + ]; + + if ($manifest['type'] === CModule::TYPE_WIDGET) { + if (!array_key_exists('widget', $manifest)) { + $manifest['widget'] = []; + } + + $manifest['widget'] += [ + 'name' => '', + 'form_class' => CWidget::DEFAULT_FORM_CLASS, + 'js_class' => CWidget::DEFAULT_JS_CLASS, + 'size' => CWidget::DEFAULT_SIZE, + 'refresh_rate' => CWidget::DEFAULT_REFRESH_RATE, + 'template_support' => false, + 'use_time_selector' => false + ]; + } + return $manifest; } } diff --git a/ui/include/classes/core/CWidget.php b/ui/include/classes/core/CWidget.php new file mode 100755 index 00000000000..9824972d19c --- /dev/null +++ b/ui/include/classes/core/CWidget.php @@ -0,0 +1,164 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Zabbix\Core; + +use CControllerDashboardWidgetEdit; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\CWidgetFieldSelect; + +/** + * Base class for user widgets. If Widget.php is not provided by user widget, this class will be instantiated instead. + */ +class CWidget extends CModule { + + public const DEFAULT_FORM_CLASS = 'WidgetForm'; + public const DEFAULT_JS_CLASS = 'CWidget'; + public const DEFAULT_SIZE = ['width' => 12, 'height' => 5]; + public const DEFAULT_REFRESH_RATE = 60; + + // Dashboard widget dynamic state. + public const SIMPLE_ITEM = 0; + public const DYNAMIC_ITEM = 1; + + final public function getForm(array $values, ?string $templateid): CWidgetForm { + $form_class = implode('\\', [$this->getNamespace(), 'Includes', $this->manifest['widget']['form_class']]); + + if (!class_exists($form_class)) { + $form_class = CWidgetForm::class; + } + + $form = new $form_class($values, $templateid); + + if ($templateid === null) { + $refresh_rates = self::getRefreshRates(); + + $form->addField( + (new CWidgetFieldSelect('rf_rate', _('Refresh interval'), + [ + -1 => _('Default').' ('.$refresh_rates[$this->getDefaultRefreshRate()].')' + ] + $refresh_rates + ))->setDefault(-1) + ); + } + + return $form + ->addFields() + ->setFieldsValues(); + } + + final public function getActions(): array { + $actions = parent::getActions() + [ + 'widget.'.$this->getId().'.view' => [], + 'widget.'.$this->getId().'.edit' => [] + ]; + + $actions['widget.'.$this->getId().'.view'] += [ + 'class' => 'WidgetView', + 'view' => 'widget.view', + 'layout' => 'layout.widget' + ]; + + $actions['widget.'.$this->getId().'.edit'] += [ + 'class' => CControllerDashboardWidgetEdit::class, + 'view' => 'widget.edit', + 'layout' => 'layout.json' + ]; + + return $actions; + } + + public function getDefaults(): array { + return [ + 'name' => $this->getDefaultName(), + 'size' => $this->getDefaultSize(), + 'js_class' => $this->getJSClass() + ]; + } + + public function isDeprecated(): bool { + return false; + } + + public function getDefaultName(): string { + return $this->manifest['widget']['name'] !== '' + ? $this->manifest['widget']['name'] + : $this->getName(); + } + + public function getDefaultSize(): array { + $size = $this->manifest['widget']['size']; + + if (!array_key_exists('width', $size) || !array_key_exists('height', $size)) { + return self::DEFAULT_SIZE; + } + + if ($size['width'] < 1) { + $size['width'] = 1; + } + + if ($size['width'] > DASHBOARD_MAX_COLUMNS) { + $size['width'] = DASHBOARD_MAX_COLUMNS; + } + + if ($size['height'] < DASHBOARD_WIDGET_MIN_ROWS) { + $size['height'] = DASHBOARD_WIDGET_MIN_ROWS; + } + + if ($size['height'] > DASHBOARD_WIDGET_MAX_ROWS) { + $size['height'] = DASHBOARD_WIDGET_MAX_ROWS; + } + + return $size; + } + + public function getJSClass(): string { + return $this->manifest['widget']['js_class']; + } + + public function getDefaultRefreshRate(): int { + return array_key_exists($this->manifest['widget']['refresh_rate'], self::getRefreshRates()) + ? (int) $this->manifest['widget']['refresh_rate'] + : self::DEFAULT_REFRESH_RATE; + } + + public function hasTemplateSupport(): bool { + return (bool) $this->manifest['widget']['template_support']; + } + + public function usesTimeSelector(array $fields_values): bool { + return (bool) $this->manifest['widget']['use_time_selector']; + } + + private static function getRefreshRates(): array { + return [ + 0 => _('No refresh'), + 10 => _n('%1$s second', '%1$s seconds', 10), + 30 => _n('%1$s second', '%1$s seconds', 30), + 60 => _n('%1$s minute', '%1$s minutes', 1), + 120 => _n('%1$s minute', '%1$s minutes', 2), + 600 => _n('%1$s minute', '%1$s minutes', 10), + 900 => _n('%1$s minute', '%1$s minutes', 15) + ]; + } +} diff --git a/ui/include/classes/core/ZBase.php b/ui/include/classes/core/ZBase.php index 21e406536b7..697c6b28500 100644 --- a/ui/include/classes/core/ZBase.php +++ b/ui/include/classes/core/ZBase.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,8 +19,9 @@ **/ -use Core\CModule, - CController as CAction; +use Zabbix\Core\CModule; + +use CController as CAction; require_once dirname(__FILE__).'/CAutoloader.php'; @@ -42,7 +43,7 @@ class ZBase { * * @var string */ - protected $rootDir; + protected $root_dir; /** * @var array of config data from zabbix config file @@ -71,10 +72,9 @@ class ZBase { */ private $mode; - /** - * @var CModuleManager - */ - private $module_manager; + private CModuleManager $module_manager; + + private ?CView $view = null; /** * Returns the current instance of APP. @@ -83,7 +83,7 @@ class ZBase { * * @return APP */ - public static function getInstance() { + public static function getInstance(): APP { if (self::$instance === null) { self::$instance = new static; } @@ -96,7 +96,7 @@ class ZBase { * * @return CComponentRegistry */ - public static function Component() { + public static function Component(): CComponentRegistry { return self::getInstance()->component_registry; } @@ -105,15 +105,22 @@ class ZBase { * * @return CModuleManager */ - public static function ModuleManager() { + public static function ModuleManager(): CModuleManager { return self::getInstance()->module_manager; } /** + * @return CView|null + */ + public static function View(): ?CView { + return self::getInstance()->view; + } + + /** * Init modules required to run frontend. */ protected function init() { - $this->rootDir = $this->findRootDir(); + $this->root_dir = $this->findRootDir(); $this->initAutoloader(); $this->component_registry = new CComponentRegistry; @@ -195,6 +202,7 @@ class ZBase { $this->initComponents(); $this->initModuleManager(); + /** @var CRouter $router */ $router = $this->component_registry->get('router'); $router->addActions($this->module_manager->getActions()); $router->setAction($action_name); @@ -268,11 +276,9 @@ class ZBase { /** * Returns the absolute path to the root dir. - * - * @return string */ - public static function getRootDir() { - return self::getInstance()->rootDir; + public static function getRootDir(): string { + return self::getInstance()->root_dir; } /** @@ -291,68 +297,64 @@ class ZBase { */ private function getIncludePaths() { return [ - $this->rootDir.'/include/classes/api', - $this->rootDir.'/include/classes/api/services', - $this->rootDir.'/include/classes/api/helpers', - $this->rootDir.'/include/classes/api/item_types', - $this->rootDir.'/include/classes/api/managers', - $this->rootDir.'/include/classes/api/clients', - $this->rootDir.'/include/classes/api/wrappers', - $this->rootDir.'/include/classes/core', - $this->rootDir.'/include/classes/data', - $this->rootDir.'/include/classes/mvc', - $this->rootDir.'/include/classes/db', - $this->rootDir.'/include/classes/debug', - $this->rootDir.'/include/classes/validators', - $this->rootDir.'/include/classes/validators/schema', - $this->rootDir.'/include/classes/validators/string', - $this->rootDir.'/include/classes/validators/object', - $this->rootDir.'/include/classes/validators/hostgroup', - $this->rootDir.'/include/classes/validators/host', - $this->rootDir.'/include/classes/validators/hostprototype', - $this->rootDir.'/include/classes/validators/event', - $this->rootDir.'/include/classes/export', - $this->rootDir.'/include/classes/export/writers', - $this->rootDir.'/include/classes/export/elements', - $this->rootDir.'/include/classes/graph', - $this->rootDir.'/include/classes/graphdraw', - $this->rootDir.'/include/classes/import', - $this->rootDir.'/include/classes/import/converters', - $this->rootDir.'/include/classes/import/importers', - $this->rootDir.'/include/classes/import/preprocessors', - $this->rootDir.'/include/classes/import/readers', - $this->rootDir.'/include/classes/import/validators', - $this->rootDir.'/include/classes/items', - $this->rootDir.'/include/classes/triggers', - $this->rootDir.'/include/classes/server', - $this->rootDir.'/include/classes/screens', - $this->rootDir.'/include/classes/services', - $this->rootDir.'/include/classes/sysmaps', - $this->rootDir.'/include/classes/helpers', - $this->rootDir.'/include/classes/helpers/trigger', - $this->rootDir.'/include/classes/macros', - $this->rootDir.'/include/classes/html', - $this->rootDir.'/include/classes/html/pageheader', - $this->rootDir.'/include/classes/html/svg', - $this->rootDir.'/include/classes/html/widget', - $this->rootDir.'/include/classes/html/interfaces', - $this->rootDir.'/include/classes/parsers', - $this->rootDir.'/include/classes/parsers/results', - $this->rootDir.'/include/classes/controllers', - $this->rootDir.'/include/classes/routing', - $this->rootDir.'/include/classes/json', - $this->rootDir.'/include/classes/user', - $this->rootDir.'/include/classes/setup', - $this->rootDir.'/include/classes/regexp', - $this->rootDir.'/include/classes/ldap', - $this->rootDir.'/include/classes/pagefilter', - $this->rootDir.'/include/classes/widgets/fields', - $this->rootDir.'/include/classes/widgets/forms', - $this->rootDir.'/include/classes/widgets', - $this->rootDir.'/include/classes/xml', - $this->rootDir.'/include/classes/vaults', - $this->rootDir.'/local/app/controllers', - $this->rootDir.'/app/controllers' + $this->root_dir.'/include/classes/api', + $this->root_dir.'/include/classes/api/services', + $this->root_dir.'/include/classes/api/helpers', + $this->root_dir.'/include/classes/api/item_types', + $this->root_dir.'/include/classes/api/managers', + $this->root_dir.'/include/classes/api/clients', + $this->root_dir.'/include/classes/api/wrappers', + $this->root_dir.'/include/classes/core', + $this->root_dir.'/include/classes/data', + $this->root_dir.'/include/classes/mvc', + $this->root_dir.'/include/classes/db', + $this->root_dir.'/include/classes/debug', + $this->root_dir.'/include/classes/validators', + $this->root_dir.'/include/classes/validators/schema', + $this->root_dir.'/include/classes/validators/string', + $this->root_dir.'/include/classes/validators/object', + $this->root_dir.'/include/classes/validators/hostgroup', + $this->root_dir.'/include/classes/validators/host', + $this->root_dir.'/include/classes/validators/hostprototype', + $this->root_dir.'/include/classes/validators/event', + $this->root_dir.'/include/classes/export', + $this->root_dir.'/include/classes/export/writers', + $this->root_dir.'/include/classes/export/elements', + $this->root_dir.'/include/classes/graph', + $this->root_dir.'/include/classes/graphdraw', + $this->root_dir.'/include/classes/import', + $this->root_dir.'/include/classes/import/converters', + $this->root_dir.'/include/classes/import/importers', + $this->root_dir.'/include/classes/import/preprocessors', + $this->root_dir.'/include/classes/import/readers', + $this->root_dir.'/include/classes/import/validators', + $this->root_dir.'/include/classes/items', + $this->root_dir.'/include/classes/triggers', + $this->root_dir.'/include/classes/server', + $this->root_dir.'/include/classes/screens', + $this->root_dir.'/include/classes/services', + $this->root_dir.'/include/classes/sysmaps', + $this->root_dir.'/include/classes/helpers', + $this->root_dir.'/include/classes/helpers/trigger', + $this->root_dir.'/include/classes/macros', + $this->root_dir.'/include/classes/html', + $this->root_dir.'/include/classes/html/svg', + $this->root_dir.'/include/classes/html/widgets', + $this->root_dir.'/include/classes/html/interfaces', + $this->root_dir.'/include/classes/parsers', + $this->root_dir.'/include/classes/parsers/results', + $this->root_dir.'/include/classes/controllers', + $this->root_dir.'/include/classes/routing', + $this->root_dir.'/include/classes/json', + $this->root_dir.'/include/classes/user', + $this->root_dir.'/include/classes/setup', + $this->root_dir.'/include/classes/regexp', + $this->root_dir.'/include/classes/ldap', + $this->root_dir.'/include/classes/pagefilter', + $this->root_dir.'/include/classes/xml', + $this->root_dir.'/include/classes/vaults', + $this->root_dir.'/local/app/controllers', + $this->root_dir.'/app/controllers' ]; } @@ -389,7 +391,7 @@ class ZBase { * Load zabbix config file. */ protected function loadConfigFile(): void { - $configFile = $this->getRootDir().CConfigFile::CONFIG_FILE_PATH; + $configFile = $this->root_dir.CConfigFile::CONFIG_FILE_PATH; $config = new CConfigFile($configFile); @@ -401,10 +403,11 @@ class ZBase { */ protected function initAutoloader() { // Register base directory path for 'include' and 'require' functions. - set_include_path(get_include_path().PATH_SEPARATOR.$this->rootDir); + set_include_path(get_include_path().PATH_SEPARATOR.$this->root_dir); $autoloader = new CAutoloader; $autoloader->addNamespace('', $this->getIncludePaths()); - $autoloader->addNamespace('Core', [$this->rootDir.'/include/classes/core']); + $autoloader->addNamespace('Zabbix\\Core', [$this->root_dir.'/include/classes/core']); + $autoloader->addNamespace('Zabbix\\Widgets', [$this->root_dir.'/include/classes/widgets']); $autoloader->register(); $this->autoloader = $autoloader; } @@ -490,7 +493,7 @@ class ZBase { error($error); } - require_once $this->getRootDir().'/include/translateDefines.inc.php'; + require_once $this->root_dir.'/include/translateDefines.inc.php'; } /** @@ -559,11 +562,24 @@ class ZBase { try { if ($action_class === null) { - throw new Exception(_('Class not found.')); + throw new Exception(_('Page not found')); } if (!class_exists($action_class)) { - throw new Exception(_s('Class %1$s not found for action %2$s.', $action_class, $action_name)); + $namespace_parts = explode('\\', $action_class); + + if (count($namespace_parts) > 1) { + $action_class_fallback = end($namespace_parts); + + if (!class_exists($action_class_fallback)) { + throw new Exception(_s('Class %1$s not found for action %2$s.', $action_class, $action_name)); + } + + $action_class = $action_class_fallback; + } + else { + throw new Exception(_s('Class %1$s not found for action %2$s.', $action_class, $action_name)); + } } $action = new $action_class(); @@ -573,19 +589,25 @@ class ZBase { } $action->setAction($action_name); + $this->module_manager->setActionName($action_name); $modules = $this->module_manager->getModules(); - $action_module = $this->module_manager->getModuleByActionName($action_name); + $action_module = $this->module_manager->getActionModule(); - if ($action_module) { + if ($action_module !== null) { $modules = array_replace([$action_module->getId() => $action_module], $modules); + + if ($action_module->getType() === CModule::TYPE_WIDGET) { + CView::registerDirectory($this->root_dir.'/'.$action_module->getRelativePath().'/views'); + CPartial::registerDirectory($this->root_dir.'/'.$action_module->getRelativePath().'/partials'); + } } foreach (array_reverse($modules) as $module) { - if (is_subclass_of($module, CModule::class)) { - CView::registerDirectory($module->getDir().'/views'); - CPartial::registerDirectory($module->getDir().'/partials'); + if ($module->getType() === CModule::TYPE_MODULE) { + CView::registerDirectory($this->root_dir.'/'.$module->getRelativePath().'/views'); + CPartial::registerDirectory($this->root_dir.'/'.$module->getRelativePath().'/partials'); } } @@ -605,29 +627,7 @@ class ZBase { $this->denyPageAccess($router); } catch (Exception $e) { - switch ($router->getLayout()) { - case 'layout.json': - case 'layout.widget': - echo (new CView('layout.json', [ - 'main_block' => json_encode([ - 'error' => [ - 'title' => $e->getMessage() - ] - ]) - ]))->getOutput(); - - break; - - default: - echo (new CView('general.warning', [ - 'header' => $e->getMessage(), - 'messages' => [], - 'theme' => getUserTheme(CWebUser::$data) - ]))->getOutput(); - } - - session_write_close(); - exit(); + self::terminateWithError($router, $e->getMessage()); } } @@ -687,17 +687,23 @@ class ZBase { ]; if ($router->getView() !== null && $response->isViewEnabled()) { - $view = new CView($router->getView(), $response->getData()); + $this->view = new CView($router->getView(), $response->getData()); + + $module = $this->module_manager->getActionModule(); + + if ($module !== null) { + $this->view->setAssetsPath($module->getRelativePath().'/assets'); + } $layout_data = array_replace($layout_data_defaults, [ - 'main_block' => $view->getOutput(), + 'main_block' => $this->view->getOutput(), 'javascript' => [ - 'files' => $view->getJsFiles() + 'files' => $this->view->getJsFiles() ], 'stylesheet' => [ - 'files' => $view->getCssFiles() + 'files' => $this->view->getCssFiles() ], - 'web_layout_mode' => $view->getLayoutMode() + 'web_layout_mode' => $this->view->getLayoutMode() ]); } else { @@ -782,6 +788,52 @@ class ZBase { exit(); } + private static function terminateWithError(CRouter $router, string $error): void { + switch ($router->getLayout()) { + case 'layout.json': + case 'layout.widget': + $layout = 'layout.json'; + break; + + case null: + if ((array_key_exists('CONTENT_TYPE', $_SERVER) && $_SERVER['CONTENT_TYPE'] === 'application/json') + || (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) + && strcasecmp($_SERVER['HTTP_X_REQUESTED_WITH'], 'XMLHttpRequest') == 0)) { + $layout = 'layout.json'; + } + else { + $layout = 'general.warning'; + } + break; + + default: + $layout = 'general.warning'; + } + + switch ($layout) { + case 'layout.json': + echo (new CView('layout.json', [ + 'main_block' => json_encode([ + 'error' => [ + 'title' => $error + ] + ]) + ]))->getOutput(); + + break; + + default: + echo (new CView('general.warning', [ + 'header' => $error, + 'messages' => [], + 'theme' => getUserTheme(CWebUser::$data) + ]))->getOutput(); + } + + session_write_close(); + exit(); + } + /** * Set layout mode using URL parameters. */ @@ -797,7 +849,7 @@ class ZBase { /** * Initialize menu for main navigation. Register instance as component with 'menu.main' key. */ - private function initComponents() { + private function initComponents(): void { $this->component_registry->register('router', new CRouter()); $this->component_registry->register('menu.main', CMenuHelper::getMainMenu()); $this->component_registry->register('menu.user', CMenuHelper::getUserMenu()); @@ -806,8 +858,8 @@ class ZBase { /** * Initialize module manager and load all enabled and allowed modules according to user role settings. */ - private function initModuleManager() { - $this->module_manager = new CModuleManager($this->rootDir.'/modules'); + private function initModuleManager(): void { + $this->module_manager = new CModuleManager($this->root_dir); $db_modules = API::getApiService('module')->get([ 'output' => ['moduleid', 'id', 'relative_path', 'config'], @@ -822,8 +874,8 @@ class ZBase { continue; } - $manifest = $this->module_manager->addModule($db_module['relative_path'], $db_module['id'], - $db_module['config'] + $manifest = $this->module_manager->addModule($db_module['relative_path'], $db_module['moduleid'], + $db_module['id'], $db_module['config'] ); if (!$manifest) { diff --git a/ui/include/classes/helpers/CDashboardHelper.php b/ui/include/classes/helpers/CDashboardHelper.php index 59969e79e51..9dcff28757c 100644 --- a/ui/include/classes/helpers/CDashboardHelper.php +++ b/ui/include/classes/helpers/CDashboardHelper.php @@ -19,26 +19,23 @@ **/ +use Zabbix\Core\{ + CModule, + CWidget +}; + class CDashboardHelper { /** * Get dashboard owner name. - * - * @static - * - * @param string $userid - * - * @return string */ - public static function getOwnerName($userid): string { + public static function getOwnerName(string $userid): string { $users = API::User()->get([ 'output' => ['name', 'surname', 'username'], 'userids' => $userid ]); - $name = $users ? getUserFullname($users[0]) : _('Inaccessible user'); - - return $name; + return $users ? getUserFullname($users[0]) : _('Inaccessible user'); } /** @@ -64,14 +61,6 @@ class CDashboardHelper { /** * Prepare widget pages for dashboard grid. - * - * @static - * - * @param array $pages - * @param string $templateid - * @param bool $with_rf_rate - * - * @return array */ public static function preparePagesForGrid(array $pages, ?string $templateid, bool $with_rf_rate): array { if (!$pages) { @@ -80,63 +69,58 @@ class CDashboardHelper { $grid_pages = []; - $context = ($templateid === null) - ? CWidgetConfig::CONTEXT_DASHBOARD - : CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD; - - $known_widget_types = array_keys(CWidgetConfig::getKnownWidgetTypes($context)); - foreach ($pages as $page) { $grid_page_widgets = []; CArrayHelper::sort($page['widgets'], ['y', 'x']); - foreach ($page['widgets'] as $widget) { - if (!in_array($widget['type'], $known_widget_types)) { - continue; - } - - $widgetid = $widget['widgetid']; - $fields_orig = self::convertWidgetFields($widget['fields']); - - // Transforms corrupted data to default values. - $widget_form = CWidgetConfig::getForm($widget['type'], json_encode($fields_orig), $templateid); - $widget_form->validate(); - $fields = $widget_form->getFieldsData(); - - if ($with_rf_rate) { - $rf_rate = (int) CProfile::get('web.dashboard.widget.rf_rate', -1, $widgetid); + foreach ($page['widgets'] as $widget_data) { + $grid_page_widget = [ + 'widgetid' => $widget_data['widgetid'], + 'type' => $widget_data['type'], + 'name' => $widget_data['name'], + 'view_mode' => $widget_data['view_mode'], + 'pos' => [ + 'x' => (int) $widget_data['x'], + 'y' => (int) $widget_data['y'], + 'width' => (int) $widget_data['width'], + 'height' => (int) $widget_data['height'] + ], + 'rf_rate' => 0, + 'fields' => [] + ]; - if ($rf_rate == -1) { - if ($context === CWidgetConfig::CONTEXT_DASHBOARD) { - $rf_rate = ($fields['rf_rate'] == -1) - ? CWidgetConfig::getDefaultRfRate($widget['type']) - : $fields['rf_rate']; - } - else { - $rf_rate = CWidgetConfig::getDefaultRfRate($widget['type']); + /** @var CWidget $widget */ + $widget = APP::ModuleManager()->getModule($widget_data['type']); + + if ($widget !== null && $widget->getType() === CModule::TYPE_WIDGET + && ($templateid === null || $widget->hasTemplateSupport())) { + $grid_page_widget['fields'] = self::convertWidgetFields($widget_data['fields']); + + if ($with_rf_rate) { + $rf_rate = (int) CProfile::get('web.dashboard.widget.rf_rate', -1, $widget_data['widgetid']); + + if ($rf_rate == -1) { + if ($templateid === null) { + // Transforms corrupted data to default values. + $widget_form = $widget->getForm($grid_page_widget['fields'], $templateid); + $widget_form->validate(); + $values = $widget_form->getFieldsValues(); + + $rf_rate = $values['rf_rate'] == -1 + ? $widget->getDefaultRefreshRate() + : $values['rf_rate']; + } + else { + $rf_rate = $widget->getDefaultRefreshRate(); + } } + + $grid_page_widget['rf_rate'] = $rf_rate; } } - else { - $rf_rate = 0; - } - $grid_page_widgets[] = [ - 'widgetid' => $widgetid, - 'type' => $widget['type'], - 'name' => $widget['name'], - 'view_mode' => $widget['view_mode'], - 'pos' => [ - 'x' => (int) $widget['x'], - 'y' => (int) $widget['y'], - 'width' => (int) $widget['width'], - 'height' => (int) $widget['height'] - ], - 'rf_rate' => $rf_rate, - 'fields' => $fields_orig, - 'configuration' => CWidgetConfig::getConfiguration($widget['type'], $fields, $widget['view_mode']) - ]; + $grid_page_widgets[] = $grid_page_widget; } $grid_pages[] = [ @@ -358,8 +342,11 @@ class CDashboardHelper { */ public static function hasTimeSelector(array $pages): bool { foreach ($pages as $page) { - foreach ($page['widgets'] as $widget) { - if (CWidgetConfig::usesTimeSelector($widget['type'], $widget['fields'])) { + foreach ($page['widgets'] as $widget_data) { + $widget = App::ModuleManager()->getModule($widget_data['type']); + + if ($widget !== null && $widget->getType() === CModule::TYPE_WIDGET + && $widget->usesTimeSelector($widget_data['fields'])) { return true; } } @@ -411,10 +398,10 @@ class CDashboardHelper { $dashboard_page['widgets'] = []; } - foreach ($dashboard_page['widgets'] as $widget_index => &$widget) { + foreach ($dashboard_page['widgets'] as $widget_index => &$widget_data) { $widget_errors = []; - if (!array_key_exists('pos', $widget)) { + if (!array_key_exists('pos', $widget_data)) { $widget_errors[] = _s('Invalid parameter "%1$s": %2$s.', 'pages['.$dashboard_page_index.'][widgets]['.$widget_index.']', _s('the parameter "%1$s" is missing', 'pos') @@ -422,7 +409,7 @@ class CDashboardHelper { } else { foreach (['x', 'y', 'width', 'height'] as $field) { - if (!is_array($widget['pos']) || !array_key_exists($field, $widget['pos'])) { + if (!is_array($widget_data['pos']) || !array_key_exists($field, $widget_data['pos'])) { $widget_errors[] = _s('Invalid parameter "%1$s": %2$s.', 'pages['.$dashboard_page_index.'][widgets]['.$widget_index.'][pos]', _s('the parameter "%1$s" is missing', $field) @@ -432,7 +419,7 @@ class CDashboardHelper { } foreach (['type', 'name', 'view_mode'] as $field) { - if (!array_key_exists($field, $widget)) { + if (!array_key_exists($field, $widget_data)) { $widget_errors[] = _s('Invalid parameter "%1$s": %2$s.', 'pages['.$dashboard_page_index.'][widgets]['.$widget_index.']', _s('the parameter "%1$s" is missing', $field) @@ -446,28 +433,45 @@ class CDashboardHelper { break 2; } - $widget_fields = array_key_exists('fields', $widget) ? $widget['fields'] : '{}'; - $widget['form'] = CWidgetConfig::getForm($widget['type'], $widget_fields, $templateid); - unset($widget['fields']); + $widget_fields = array_key_exists('fields', $widget_data) ? $widget_data['fields'] : []; + unset($widget_data['fields']); + + if ($widget_data['type'] === ZBX_WIDGET_INACCESSIBLE) { + continue; + } - if ($widget_errors = $widget['form']->validate()) { - if ($widget['name'] === '') { - $context = $templateid !== null - ? CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - : CWidgetConfig::CONTEXT_DASHBOARD; + $widget = APP::ModuleManager()->getModule($widget_data['type']); - $widget_name = CWidgetConfig::getKnownWidgetTypes($context)[$widget['type']]; + if ($widget === null || $widget->getType() !== CModule::TYPE_WIDGET) { + if ($widget_data['name'] !== '') { + $widget_name = $widget_data['name']; } else { - $widget_name = $widget['name']; + $widget_name = 'pages['.$dashboard_page_index.'][widgets]['.$widget_index.']'; } + $errors[] = _s('Cannot save widget "%1$s".', $widget_name).' '._('Inaccessible widget type.'); + + continue; + } + + $widget_name = $widget_data['name'] !== '' ? $widget_data['name'] : $widget->getDefaultName(); + + if ($templateid !== null && !$widget->hasTemplateSupport()) { + $errors[] = _s('Cannot save widget "%1$s".', $widget_name).' '._('Inaccessible widget type.'); + + continue; + } + + $widget_data['form'] = $widget->getForm($widget_fields, $templateid); + + if ($widget_errors = $widget_data['form']->validate()) { foreach ($widget_errors as $error) { $errors[] = _s('Cannot save widget "%1$s".', $widget_name).' '.$error; } } } - unset($widget); + unset($widget_data); } unset($dashboard_page); @@ -568,4 +572,52 @@ class CDashboardHelper { return $dashboards; } + + public static function getWidgetLastType(bool $for_template_dashboard_only = false): ?string { + $known_widgets = APP::ModuleManager()->getWidgets($for_template_dashboard_only); + + $widget_last_type = CProfile::get('web.dashboard.last_widget_type'); + + if (!array_key_exists($widget_last_type, $known_widgets)) { + $current_types = []; + $deprecated_types = []; + + /** @var CWidget $widget */ + foreach ($known_widgets as $widget) { + if (!$widget->isDeprecated()) { + $current_types[$widget->getId()] = $widget->getDefaultName(); + } + else { + $deprecated_types[$widget->getId()] = $widget->getDefaultName(); + } + } + + natcasesort($current_types); + natcasesort($deprecated_types); + + if ($current_types) { + $widget_last_type = array_key_first($current_types); + } + elseif ($deprecated_types) { + $widget_last_type = array_key_first($deprecated_types); + } + else { + $widget_last_type = null; + } + } + + return $widget_last_type; + } + + /** + * @throws JsonException + */ + public static function getConfigurationHash(array $dashboard, array $widget_defaults): string { + ksort($widget_defaults); + + return md5(json_encode([ + array_intersect_key($dashboard, array_flip(['name', 'display_period', 'auto_start', 'pages'])), + $widget_defaults + ], JSON_THROW_ON_ERROR)); + } } diff --git a/ui/include/classes/helpers/CDocHelper.php b/ui/include/classes/helpers/CDocHelper.php index 03287ed8936..a1f2b3095b2 100644 --- a/ui/include/classes/helpers/CDocHelper.php +++ b/ui/include/classes/helpers/CDocHelper.php @@ -153,15 +153,15 @@ class CDocHelper { const USERS_USERROLE_EDIT = 'web_interface/frontend_sections/users/user_roles#default-user-roles'; const USERS_USERROLE_LIST = 'web_interface/frontend_sections/users/user_roles'; - public static function getUrl($path): ?string { + public static function getUrl($path): string { if (CBrandHelper::isRebranded()) { - return null; + return ''; } if (preg_match('/^\d+\.\d+/', ZABBIX_VERSION, $version)) { return ZBX_DOCUMENTATION_URL.'/'.$version[0].'/en/manual/'.$path; } - return null; + return ''; } } diff --git a/ui/include/classes/helpers/CMessageHelper.php b/ui/include/classes/helpers/CMessageHelper.php index 1ae461866cb..68560c27c84 100644 --- a/ui/include/classes/helpers/CMessageHelper.php +++ b/ui/include/classes/helpers/CMessageHelper.php @@ -161,10 +161,9 @@ class CMessageHelper { /** * Clear messages. */ - public static function clear(bool $clear_title = true): void { - if ($clear_title) { - self::$title = null; - } + public static function clear(): void { + self::$type = null; + self::$title = null; self::$messages = []; } diff --git a/ui/include/classes/helpers/CSvgGraphHelper.php b/ui/include/classes/helpers/CSvgGraphHelper.php index a9cb6c78046..85ca3cc6925 100644 --- a/ui/include/classes/helpers/CSvgGraphHelper.php +++ b/ui/include/classes/helpers/CSvgGraphHelper.php @@ -19,6 +19,8 @@ **/ +use Zabbix\Widgets\Fields\CWidgetFieldGraphDataSet; + /** * Class calculates graph data and makes SVG graph. */ @@ -109,7 +111,7 @@ class CSvgGraphHelper { $max_metrics = SVG_GRAPH_MAX_NUMBER_OF_METRICS; foreach ($data_sets as $index => $data_set) { - if ($data_set['dataset_type'] == CWidgetHelper::DATASET_TYPE_SINGLE_ITEM) { + if ($data_set['dataset_type'] == CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM) { continue; } @@ -179,7 +181,7 @@ class CSvgGraphHelper { $max_metrics = SVG_GRAPH_MAX_NUMBER_OF_METRICS; foreach ($data_sets as $index => $data_set) { - if ($data_set['dataset_type'] == CWidgetHelper::DATASET_TYPE_PATTERN_ITEM) { + if ($data_set['dataset_type'] == CWidgetFieldGraphDataSet::DATASET_TYPE_PATTERN_ITEM) { continue; } @@ -750,7 +752,7 @@ class CSvgGraphHelper { * Find problems at given time period that matches specified problem options. */ private static function getProblems(array $metrics, array $problem_options, array $time_period): array { - if ($problem_options['show_problems'] != SVG_GRAPH_PROBLEMS_SHOW) { + if ($problem_options['show_problems'] == SVG_GRAPH_PROBLEMS_OFF) { return []; } diff --git a/ui/include/classes/html/CBarGauge.php b/ui/include/classes/html/CBarGauge.php index 2afa30bcea2..5b5941eea97 100644 --- a/ui/include/classes/html/CBarGauge.php +++ b/ui/include/classes/html/CBarGauge.php @@ -20,7 +20,8 @@ class CBarGauge extends CTag { - private $thresholds = []; + + private array $thresholds = []; public function __construct() { parent::__construct('z-bar-gauge', true); diff --git a/ui/include/classes/html/CCollapsibleUiWidget.php b/ui/include/classes/html/CCollapsibleUiWidget.php deleted file mode 100644 index 58fb46c8fd4..00000000000 --- a/ui/include/classes/html/CCollapsibleUiWidget.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * A class for rendering a widget that can be collapsed or expanded. - */ -class CCollapsibleUiWidget extends CUiWidget { - - /** - * Expand/collapse widget. - * - * Supported values: - * - true - expanded; - * - false - collapsed. - * - * @var bool - */ - private $expanded = true; - - /** - * Sets the header and adds a default expand-collapse icon. - * - * @param string $caption Header caption. - * @param array $controls (optional) - * @param string $idx (optional) - * - * @return $this - */ - public function setHeader($caption, array $controls = [], $idx = '') { - $icon = (new CRedirectButton(null, null)) - ->setId($this->id.'_icon') - ->onClick('changeWidgetState(this, "'.$this->id.'", "'.$idx.'");'); - - if ($this->expanded) { - $icon - ->addClass(ZBX_STYLE_BTN_WIDGET_COLLAPSE) - ->setTitle(_('Collapse')); - } - else { - $icon - ->addClass(ZBX_STYLE_BTN_WIDGET_EXPAND) - ->setTitle(_('Expand')); - } - - $controls[] = $icon; - - parent::setHeader($caption, $controls); - - return $this; - } - - /** - * Display the widget in expanded or collapsed state. - */ - protected function build() { - $body = (new CDiv($this->body)) - ->addClass('body') - ->setId($this->id); - - if (!$this->expanded) { - $body->setAttribute('style', 'display: none;'); - - if ($this->footer) { - $this->footer->setAttribute('style', 'display: none;'); - } - } - - $this->cleanItems(); - $this->addItem($this->header); - $this->addItem($body); - $this->addItem($this->footer); - - return $this; - } - - /** - * Sets expanded or collapsed state of the widget. - * - * @param bool - */ - public function setExpanded($expanded) { - $this->expanded = $expanded; - return $this; - } -} diff --git a/ui/include/classes/html/CColor.php b/ui/include/classes/html/CColor.php index 178454953a7..f991288ffe7 100644 --- a/ui/include/classes/html/CColor.php +++ b/ui/include/classes/html/CColor.php @@ -64,11 +64,9 @@ class CColor extends CDiv { /** * Enable default color button. - - * @return CColor */ - public function enableUseDefault(): self { - $this->use_default = true; + public function enableUseDefault($use_default = true): self { + $this->use_default = $use_default; return $this; } diff --git a/ui/include/classes/html/widget/CWidget.php b/ui/include/classes/html/CHtmlPage.php index 70dbac9f539..4fc21fe8b9a 100644 --- a/ui/include/classes/html/widget/CWidget.php +++ b/ui/include/classes/html/CHtmlPage.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,7 +19,9 @@ **/ -class CWidget { +class CHtmlPage { + + public const PAGE_TITLE_ID = 'page-title-general'; private const ZBX_STYLE_HEADER_TITLE = 'header-title'; private const ZBX_STYLE_HEADER_DOC_LINK = 'header-doc-link'; @@ -27,104 +29,83 @@ class CWidget { private const ZBX_STYLE_HEADER_CONTROLS = 'header-controls'; private const ZBX_STYLE_HEADER_KIOSKMODE_CONTROLS = 'header-kioskmode-controls'; - private $title; - private $title_submenu; - private $doc_url; - private $controls; - private $kiosk_mode_controls; + private string $title = ''; + private array $title_submenu = []; - /** - * Navigation, displayed exclusively in ZBX_LAYOUT_NORMAL mode. - * - * @var mixed - */ - private $navigation; + private ?CTag $controls = null; + private ?CList $kiosk_mode_controls = null; + + private string $doc_url = ''; + + private array $items = []; /** - * The contents of the body of the widget. - * - * @var array + * Navigation, displayed exclusively in ZBX_LAYOUT_NORMAL mode. */ - protected $body = []; + private ?CList $navigation = null; /** * Layout mode (ZBX_LAYOUT_NORMAL|ZBX_LAYOUT_KIOSKMODE). - * - * @var integer */ - protected $web_layout_mode = ZBX_LAYOUT_NORMAL; + private int $web_layout_mode = ZBX_LAYOUT_NORMAL; - public function setTitle($title) { + public function setTitle(string $title): self { $this->title = $title; return $this; } - public function setTitleSubmenu($title_submenu) { + public function setTitleSubmenu(array $title_submenu): self { $this->title_submenu = $title_submenu; return $this; } - public function setDocUrl($doc_url) { + public function setDocUrl(string $doc_url): self { $this->doc_url = $doc_url; return $this; } - public function setControls($controls) { + public function setControls(?CTag $controls): self { $this->controls = $controls; return $this; } - public function setKioskModeControls($kiosk_mode_controls) { + public function setKioskModeControls(?CList $kiosk_mode_controls): self { $this->kiosk_mode_controls = $kiosk_mode_controls; return $this; } - /** - * Set layout mode. - * - * @param integer $web_layout_mode - * - * @return CWidget - */ - public function setWebLayoutMode($web_layout_mode) { + public function setWebLayoutMode(int $web_layout_mode): self { $this->web_layout_mode = $web_layout_mode; return $this; } - /** - * Set navigation for displaying exclusively in ZBX_LAYOUT_NORMAL mode. - * - * @param mixed $navigation - * - * @return CWidget - */ - public function setNavigation($navigation) { + public function setNavigation(?CList $navigation): self { $this->navigation = $navigation; return $this; } - public function addItem($items = null) { - if (!is_null($items)) { - $this->body[] = $items; + public function addItem($value): self { + if ($value !== null) { + $this->items[] = $value; } return $this; } - public function show() { + public function show(): self { echo $this->toString(); return $this; } - public function toString() { + private function toString() { $items = []; if ($this->web_layout_mode == ZBX_LAYOUT_KIOSKMODE) { @@ -138,7 +119,7 @@ class CWidget { ) ); } - elseif ($this->title !== null || $this->controls !== null || $this->doc_url !== null) { + elseif ($this->title !== '' || $this->doc_url !== '' || $this->controls !== null) { $items[] = $this->createTopHeader(); } @@ -152,27 +133,28 @@ class CWidget { ? (new CDiv($this->navigation))->addClass(self::ZBX_STYLE_HEADER_NAVIGATION) : null; - $items[] = new CTag('main', true, [$navigation, $this->body]); + $items[] = new CTag('main', true, [$navigation, $this->items]); return unpack_object($items); } private function createTopHeader(): CTag { $divs = [ - (new CTag('nav', true, (new CButton(null, _('Show sidebar'))) - ->setId('sidebar-button-toggle') - ->addClass('button-toggle') - ->setAttribute('title', _('Show sidebar')) + (new CTag('nav', true, + (new CButton(null, _('Show sidebar'))) + ->setId('sidebar-button-toggle') + ->addClass('button-toggle') + ->setAttribute('title', _('Show sidebar')) )) ->addClass('sidebar-nav-toggle') ->setAttribute('role', 'navigation') ->setAttribute('aria-label', _('Sidebar control')) ]; - if ($this->title !== null) { - $title_tag = (new CTag('h1', true, $this->title))->setId(ZBX_STYLE_PAGE_TITLE); + if ($this->title !== '') { + $title_tag = (new CTag('h1', true, $this->title))->setId(self::PAGE_TITLE_ID); - if ($this->title_submenu) { + if ($this->title_submenu !== []) { $title_tag = (new CLinkAction($title_tag)) ->setMenuPopup([ 'type' => 'submenu', @@ -189,7 +171,7 @@ class CWidget { $divs[] = new CDiv($title_tag); } - if ($this->doc_url !== null) { + if ($this->doc_url !== '') { $divs[] = (new CDiv( (new CLink(null, $this->doc_url)) ->setTitle(_('Help')) diff --git a/ui/include/classes/html/CHtmlPageHeader.php b/ui/include/classes/html/CHtmlPageHeader.php new file mode 100644 index 00000000000..c0944d6e244 --- /dev/null +++ b/ui/include/classes/html/CHtmlPageHeader.php @@ -0,0 +1,181 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Class for rendering html page head part. + */ +class CHtmlPageHeader { + + /** + * Page title. + */ + protected string $title; + + /** + * Language attribute. + */ + protected string $lang; + + /** + * Theme attribute. + */ + protected string $theme = ZBX_DEFAULT_THEME; + + /** + * CSS files list. + */ + protected array $css_files = []; + + /** + * Inline CSS styles. + */ + protected array $styles = []; + + /** + * JavaScripts to render before JS files. + */ + protected array $js = []; + + /** + * JS files list. + */ + protected array $js_files = []; + + protected string $sid; + + public function __construct(string $title, string $lang) { + $this->title = CHtml::encode($title); + $this->lang = $lang; + $this->sid = substr(CSessionHelper::getId(), 16, 16); + } + + public function setTheme(string $theme): self { + $this->theme = CHtml::encode($theme); + + return $this; + } + + public function getTheme(): string { + return $this->theme; + } + + /** + * Add path to css file to render in page head. + */ + public function addCssFile(string $css_file): self { + $this->css_files[$css_file] = $css_file; + + return $this; + } + + /** + * Add css style to render in page head. + */ + public function addStyle(string $style): self { + $this->styles[] = $style; + + return $this; + } + + /** + * Add JavaScript to render in page head before js file includes are rendered. + */ + public function addJavaScript(string $js): self { + $this->js[] = $js; + + return $this; + } + + /** + * Add path to js file to render in page head. + */ + public function addJsFile(string $js_file): self { + $this->js_files[$js_file] = $js_file; + + return $this; + } + + public function addJsTranslationStrings(array $translations_strings): self { + foreach ($translations_strings as $orig_string => $string) { + $this->addJavaScript('locale[\''.$orig_string.'\'] = '.json_encode($string, JSON_THROW_ON_ERROR).';'); + } + + return $this; + } + + /** + * Show page head html. + */ + public function show(): CHtmlPageHeader { + echo '<!DOCTYPE html>'; + echo '<html lang="'.$this->lang.'" theme="'.$this->theme.'">'; + echo <<<HTML + <head> + <meta http-equiv="X-UA-Compatible" content="IE=Edge"/> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta name="Author" content="Zabbix SIA" /> + <title>$this->title</title> + <link rel="icon" href="favicon.ico"> + <link rel="apple-touch-icon-precomposed" sizes="76x76" href="assets/img/apple-touch-icon-76x76-precomposed.png"> + <link rel="apple-touch-icon-precomposed" sizes="120x120" href="assets/img/apple-touch-icon-120x120-precomposed.png"> + <link rel="apple-touch-icon-precomposed" sizes="152x152" href="assets/img/apple-touch-icon-152x152-precomposed.png"> + <link rel="apple-touch-icon-precomposed" sizes="180x180" href="assets/img/apple-touch-icon-180x180-precomposed.png"> + <link rel="icon" sizes="192x192" href="assets/img/touch-icon-192x192.png"> + <meta name="csrf-token" content="$this->sid"/> + <meta name="msapplication-TileImage" content="assets/img/ms-tile-144x144.png"> + <meta name="msapplication-TileColor" content="#d40000"> + <meta name="msapplication-config" content="none"/> + HTML; + + foreach ($this->css_files as $path) { + if (parse_url($path, PHP_URL_QUERY) === null) { + $path .= '?'.(int) filemtime($path); + } + + echo '<link rel="stylesheet" type="text/css" href="'.htmlspecialchars($path).'" />'."\n"; + } + + if ($this->styles) { + echo '<style>'; + echo implode("\n", $this->styles); + echo '</style>'; + } + + if ($this->js) { + echo '<script>'; + echo implode("\n", $this->js); + echo '</script>'; + } + + foreach ($this->js_files as $path) { + if (parse_url($path, PHP_URL_QUERY) === null) { + $path .= '?'.(int) filemtime($path); + } + + echo '<script src="'.htmlspecialchars($path).'"></script>'."\n"; + } + + echo '</head>'."\n"; + + return $this; + } +} diff --git a/ui/include/classes/html/CLabel.php b/ui/include/classes/html/CLabel.php index 513dfe94eb0..ab41f1493fc 100644 --- a/ui/include/classes/html/CLabel.php +++ b/ui/include/classes/html/CLabel.php @@ -21,12 +21,18 @@ class CLabel extends CTag { - public function __construct($label, $for = null) { + public function __construct($label, $id = null) { parent::__construct('label', true, $label); - if ($for !== null) { - $this->setAttribute('for', zbx_formatDomId($for)); + $this->setFor($id); + } + + public function setFor($id): self { + if ($id !== null) { + $this->setAttribute('for', zbx_formatDomId($id)); } + + return $this; } /** diff --git a/ui/include/classes/html/CRadioButtonList.php b/ui/include/classes/html/CRadioButtonList.php index 8ff7c4c8138..69f195c1982 100644 --- a/ui/include/classes/html/CRadioButtonList.php +++ b/ui/include/classes/html/CRadioButtonList.php @@ -100,7 +100,7 @@ class CRadioButtonList extends CList { return $this; } - public function setModern($modern) { + public function setModern($modern = true) { $this->modern = $modern; return $this; diff --git a/ui/include/classes/html/CSection.php b/ui/include/classes/html/CSection.php new file mode 100644 index 00000000000..18c77db3930 --- /dev/null +++ b/ui/include/classes/html/CSection.php @@ -0,0 +1,68 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +class CSection extends CTag { + + private const ZBX_STYLE_HEAD = 'section-head'; + private const ZBX_STYLE_BODY = 'section-body'; + private const ZBX_STYLE_FOOT = 'section-foot'; + + protected ?CDiv $header = null; + protected ?CDiv $footer = null; + + public function __construct($items = null) { + parent::__construct('section', true, $items); + } + + public function addItem($value): self { + if ($value !== null) { + $this->items[] = $value; + } + + return $this; + } + + public function setHeader($header_items): self { + if ($header_items !== null) { + $this->header = (new CDiv($header_items))->addClass(self::ZBX_STYLE_HEAD); + } + + return $this; + } + + public function setFooter($footer_items): self { + if ($footer_items !== null) { + $this->footer = (new CDiv($footer_items))->addClass(self::ZBX_STYLE_FOOT); + } + + return $this; + } + + public function toString($destroy = true): string { + $body = (new CDiv($this->items))->addClass(self::ZBX_STYLE_BODY); + + $this->cleanItems(); + + parent::addItem([$this->header, $body, $this->footer]); + + return parent::toString($destroy); + } +} diff --git a/ui/include/classes/html/CSectionCollapsible.php b/ui/include/classes/html/CSectionCollapsible.php new file mode 100755 index 00000000000..55d3ebf1171 --- /dev/null +++ b/ui/include/classes/html/CSectionCollapsible.php @@ -0,0 +1,59 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +class CSectionCollapsible extends CSection { + + private const ZBX_STYLE_COLLAPSED = 'section-collapsed'; + private const ZBX_STYLE_TOGGLE = 'section-toggle'; + + private bool $is_expanded = true; + private string $profile_key = ''; + + public function setExpanded(bool $is_expanded): self { + $this->is_expanded = $is_expanded; + + return $this; + } + + public function setProfileIdx(string $profile_key): self { + $this->profile_key = $profile_key; + + return $this; + } + + public function toString($destroy = true): string { + $this->addClass($this->is_expanded ? null : self::ZBX_STYLE_COLLAPSED); + + $toggle = (new CSimpleButton()) + ->addClass(self::ZBX_STYLE_TOGGLE) + ->setTitle($this->is_expanded ? _('Collapse') : _('Expand')) + ->onClick('toggleSection("'.$this->getId().'", "'.$this->profile_key.'");'); + + if ($this->header === null) { + $this->setHeader($toggle); + } + else { + $this->header->addItem($toggle); + } + + return parent::toString($destroy); + } +} diff --git a/ui/include/classes/html/CTemplateTag.php b/ui/include/classes/html/CTemplateTag.php new file mode 100644 index 00000000000..79a60f26648 --- /dev/null +++ b/ui/include/classes/html/CTemplateTag.php @@ -0,0 +1,34 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Class to embed HTML template. + */ +class CTemplateTag extends CTag { + + public function __construct($id, $value = null) { + parent::__construct('template', true); + + $this + ->setId($id) + ->addItem($value); + } +} diff --git a/ui/include/classes/html/CUiWidget.php b/ui/include/classes/html/CUiWidget.php deleted file mode 100644 index 0823642534b..00000000000 --- a/ui/include/classes/html/CUiWidget.php +++ /dev/null @@ -1,136 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CUiWidget extends CDiv { - - /** - * Widget id. - * - * @var string - */ - public $id; - - /** - * Expand/collapse widget. - * - * Supported values: - * - true - expanded; - * - false - collapsed. - * - * @var bool - */ - public $open; - - /** - * Header div. - * - * @var CDiv - */ - protected $header; - - /** - * Body div. - * - * @var array - */ - protected $body; - - /** - * Footer div. - * - * @var CDiv - */ - protected $footer; - - /** - * Construct widget. - * - * @param string $id - * @param string|array|CTag $body - */ - public function __construct($id, $body = null) { - $this->id = $id; - $this->body = $body ? [$body] : []; - - parent::__construct(); - - $this->addClass(ZBX_STYLE_DASHBOARD_WIDGET); - $this->setId($this->id.'_widget'); - } - - /** - * Set widget header. - * - * @param string $caption - * @param array $controls - * - * @return $this - */ - public function setHeader($caption, array $controls = []) { - $this->header = (new CDiv()) - ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_HEAD) - ->addItem( - (new CTag('h4', true, $caption))->setId($this->id.'_header') - ); - - if ($controls) { - $this->header->addItem(new CList($controls)); - } - - return $this; - } - - /** - * Set widget footer. - * - * @param string|array|CTag $footer - * @param bool $right - */ - public function setFooter($list) { - $this->footer = $list; - $this->footer->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FOOT); - return $this; - } - - /** - * Build widget header, body and footer. - */ - protected function build() { - $body = (new CDiv($this->body)) - ->setId($this->id); - - $this->cleanItems(); - - $this->addItem($this->header); - $this->addItem($body); - $this->addItem($this->footer); - return $this; - } - - /** - * Get widget html. - */ - public function toString($destroy = true) { - $this->build(); - - return parent::toString($destroy); - } -} diff --git a/ui/include/classes/html/pageheader/CPageHeader.php b/ui/include/classes/html/pageheader/CPageHeader.php deleted file mode 100644 index e272f094998..00000000000 --- a/ui/include/classes/html/pageheader/CPageHeader.php +++ /dev/null @@ -1,190 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Class for rendering html page head part. - */ -class CPageHeader { - - /** - * @var string page title - */ - protected $title; - - /** - * @var string Language attribute. - */ - protected $lang; - - /** - * @var array of css file paths - */ - protected $cssFiles = []; - - /** - * @var array of css styles - */ - protected $styles = []; - - /** - * @var array of js file paths - */ - protected $jsFiles = []; - - /** - * @var array of js scripts to render before js files - */ - protected $jsBefore = []; - - /** - * @var array of js scripts to render after js files - */ - protected $js = []; - - /** - * @var {string} sid - */ - protected $sid; - - /** - * @param string $title - * @param string $lang - */ - public function __construct(string $title, string $lang) { - $this->title = CHtml::encode($title); - $this->lang = $lang; - $this->sid = substr(CSessionHelper::getId(), 16, 16); - } - - /** - * Add path to css file to render in page head. - * - * @param string $path - */ - public function addCssFile($path) { - $this->cssFiles[$path] = $path; - return $this; - } - - /** - * Add css style to render in page head. - * - * @param string $style - */ - public function addStyle($style) { - $this->styles[] = $style; - return $this; - } - - /** - * Add path to js file to render in page head. - * - * @param string $path - */ - public function addJsFile($path) { - $this->jsFiles[$path] = $path; - return $this; - } - - /** - * Add js script to render in page head after js file includes are rendered. - * - * @param string $js - */ - public function addJs($js) { - $this->js[] = $js; - return $this; - } - - /** - * Add js script to render in page head before js file includes are rendered. - * - * @param string $js - */ - public function addJsBeforeScripts($js) { - $this->jsBefore[] = $js; - return $this; - } - - /** - * Display page head html. - */ - public function display() { - echo '<!DOCTYPE html>'."\n"; - echo '<html lang="'.$this->lang.'">'."\n"; - echo <<<HTML - <head> - <meta http-equiv="X-UA-Compatible" content="IE=Edge"/> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="Author" content="Zabbix SIA" /> - <title>$this->title</title> - <link rel="icon" href="favicon.ico"> - <link rel="apple-touch-icon-precomposed" sizes="76x76" href="assets/img/apple-touch-icon-76x76-precomposed.png"> - <link rel="apple-touch-icon-precomposed" sizes="120x120" href="assets/img/apple-touch-icon-120x120-precomposed.png"> - <link rel="apple-touch-icon-precomposed" sizes="152x152" href="assets/img/apple-touch-icon-152x152-precomposed.png"> - <link rel="apple-touch-icon-precomposed" sizes="180x180" href="assets/img/apple-touch-icon-180x180-precomposed.png"> - <link rel="icon" sizes="192x192" href="assets/img/touch-icon-192x192.png"> - <meta name="csrf-token" content="$this->sid"/> - <meta name="msapplication-TileImage" content="assets/img/ms-tile-144x144.png"> - <meta name="msapplication-TileColor" content="#d40000"> - <meta name="msapplication-config" content="none"/> - -HTML; - - foreach ($this->cssFiles as $path) { - if (parse_url($path, PHP_URL_QUERY) === null) { - $path .= '?'.(int) filemtime($path); - } - - echo '<link rel="stylesheet" type="text/css" href="'.htmlspecialchars($path).'" />'."\n"; - } - - if ($this->styles) { - echo '<style type="text/css">'; - echo implode("\n", $this->styles); - echo '</style>'; - } - - if ($this->jsBefore) { - echo '<script>'; - echo implode("\n", $this->jsBefore); - echo '</script>'; - } - - foreach ($this->jsFiles as $path) { - if (parse_url($path, PHP_URL_QUERY) === null) { - $path .= '?'.(int) filemtime($path); - } - - echo '<script src="'.htmlspecialchars($path).'"></script>'."\n"; - } - - if ($this->js) { - echo '<script>'; - echo implode("\n", $this->js); - echo '</script>'; - } - - echo '</head>'."\n"; - return $this; - } -} diff --git a/ui/include/classes/html/widgets/CWidgetFieldCheckBoxListView.php b/ui/include/classes/html/widgets/CWidgetFieldCheckBoxListView.php new file mode 100755 index 00000000000..2fe19e51d1d --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldCheckBoxListView.php @@ -0,0 +1,59 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldCheckBoxList; + +class CWidgetFieldCheckBoxListView extends CWidgetFieldView { + + private array $classes = []; + + public function __construct(CWidgetFieldCheckBoxList $field) { + $this->field = $field; + } + + public function getView(): CList { + $checkbox_list = (new CList())->addClass(ZBX_STYLE_LIST_CHECK_RADIO); + + foreach ($this->classes as $class) { + $checkbox_list->addClass($class); + } + + foreach ($this->field->getValues() as $key => $label) { + $checkbox_list->addItem( + (new CCheckBox($this->field->getName().'[]', $key)) + ->setLabel($label) + ->setId($this->field->getName().'_'.$key) + ->setChecked(in_array($key, $this->field->getValue())) + ->setEnabled(!$this->isDisabled()) + ); + } + + return $checkbox_list; + } + + public function addClass(?string $class): self { + if ($class !== null) { + $this->classes[] = $class; + } + + return $this; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldCheckBoxView.php b/ui/include/classes/html/widgets/CWidgetFieldCheckBoxView.php new file mode 100755 index 00000000000..f2a3dbfa274 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldCheckBoxView.php @@ -0,0 +1,40 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldCheckBox; + +class CWidgetFieldCheckBoxView extends CWidgetFieldView { + + public function __construct(CWidgetFieldCheckBox $field) { + $this->field = $field; + } + + public function getView(): array { + return [ + (new CVar($this->field->getName(), '0'))->removeId(), + (new CCheckBox($this->field->getName())) + ->setChecked((bool) $this->field->getValue()) + ->setEnabled(!$this->isDisabled()) + ->setLabel($this->field->getCaption()) + ->onChange($this->field->getAction()) + ]; + } +} diff --git a/ui/include/classes/html/CScriptTemplate.php b/ui/include/classes/html/widgets/CWidgetFieldColorView.php index 5d3f4212036..0c7ee880f64 100644..100755 --- a/ui/include/classes/html/CScriptTemplate.php +++ b/ui/include/classes/html/widgets/CWidgetFieldColorView.php @@ -19,34 +19,27 @@ **/ -/** - * Class to embed script HTML template. - */ -class CScriptTemplate extends CTag { - - /** - * Create a <script type="text/x-jquery-tmpl" id="{$id}"> HTML template. - * - * @param string $id Template id - */ - public function __construct($id) { - parent::__construct('script', true); - $this->setAttribute('type', 'text/x-jquery-tmpl'); - $this->setId($id); +use Zabbix\Widgets\Fields\CWidgetFieldColor; + +class CWidgetFieldColorView extends CWidgetFieldView { + + public function __construct(CWidgetFieldColor $field) { + $this->field = $field; } - public function addItem($value) { - if (is_array($value)) { - array_map([$this, 'addItem'], $value); - } - else { - $this->items[] = $value; + public function getLabel(): ?CLabel { + $label = parent::getLabel(); + + if ($label !== null) { + $label->setFor('lbl_'.$this->field->getName()); } - return $this; + return $label; } - protected function bodyToString(): string { - return implode("\n", $this->items); + public function getView(): CColor { + return (new CColor($this->field->getName(), $this->field->getValue())) + ->appendColorPickerJs(false) + ->enableUseDefault(!$this->field->hasAllowInherited()); } } diff --git a/ui/include/classes/html/widgets/CWidgetFieldColumnsListView.php b/ui/include/classes/html/widgets/CWidgetFieldColumnsListView.php new file mode 100755 index 00000000000..ffdd353366b --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldColumnsListView.php @@ -0,0 +1,91 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldColumnsList; + +class CWidgetFieldColumnsListView extends CWidgetFieldView { + + public function __construct(CWidgetFieldColumnsList $field) { + $this->field = $field; + } + + public function getView(): CTag { + $columns = $this->field->getValue(); + + $header = [ + '', + (new CColHeader(_('Name')))->addStyle('width: 39%'), + (new CColHeader(_('Data')))->addStyle('width: 59%'), + _('Action') + ]; + + $row_actions = [ + (new CButton('edit', _('Edit'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->removeId(), + (new CButton('remove', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->removeId() + ]; + + $table = (new CTable()) + ->setId('list_'.$this->field->getName()) + ->setHeader($header); + + foreach ($columns as $column_index => $column) { + $column_data = [new CVar('sortorder['.$this->field->getName().'][]', $column_index)]; + + foreach ($column as $key => $value) { + $column_data[] = new CVar($this->field->getName().'['.$column_index.']['.$key.']', $value); + } + + if ($column['data'] == CWidgetFieldColumnsList::DATA_HOST_NAME) { + $label = new CTag('em', true, _('Host name')); + } + else if ($column['data'] == CWidgetFieldColumnsList::DATA_TEXT) { + $label = new CTag('em', true, $column['text']); + } + elseif (array_key_exists('item', $column)) { + $label = $column['item']; + } + else { + $label = ''; + } + + $table->addRow((new CRow([ + (new CCol((new CDiv)->addClass(ZBX_STYLE_DRAG_ICON)))->addClass(ZBX_STYLE_TD_DRAG_ICON), + (new CDiv($column['name']))->addClass('text'), + (new CDiv($label))->addClass('text'), + (new CList(array_merge($row_actions, [$column_data])))->addClass(ZBX_STYLE_HOR_LIST) + ]))->addClass('sortable')); + } + + $table->addRow( + (new CCol( + (new CButton('add', _('Add'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->setEnabled(!$this->isDisabled()) + ))->setColSpan(count($header)) + ); + + return $table; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldDatePickerView.php b/ui/include/classes/html/widgets/CWidgetFieldDatePickerView.php new file mode 100755 index 00000000000..d6b2fce25ba --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldDatePickerView.php @@ -0,0 +1,62 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldDatePicker; + +class CWidgetFieldDatePickerView extends CWidgetFieldView { + + private string $date_format = ''; + + private string $placeholder = ''; + + public function __construct(CWidgetFieldDatePicker $field) { + $this->field = $field; + } + + public function getView(): CDateSelector { + $date_selector = (new CDateSelector($this->field->getName(), $this->field->getValue())) + ->setMaxLength(DB::getFieldLength('widget_field', 'value_str')) + ->setAriaRequired($this->isRequired()) + ->setEnabled(!$this->isDisabled()); + + if ($this->date_format !== '') { + $date_selector->setDateFormat($this->date_format); + } + + if ($this->placeholder !== '') { + $date_selector->setPlaceholder($this->placeholder); + } + + return $date_selector; + } + + public function setDateFormat(string $date_format): self { + $this->date_format = $date_format; + + return $this; + } + + public function setPlaceholder(string $placeholder): self { + $this->placeholder = $placeholder; + + return $this; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldGraphDataSetView.php b/ui/include/classes/html/widgets/CWidgetFieldGraphDataSetView.php new file mode 100755 index 00000000000..e57baa95751 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldGraphDataSetView.php @@ -0,0 +1,440 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldGraphDataSet; + +class CWidgetFieldGraphDataSetView extends CWidgetFieldView { + + public function __construct(CWidgetFieldGraphDataSet $field) { + $this->field = $field; + } + + public function getView(): CList { + $list = (new CList()) + ->setId('data_sets') + ->addClass(ZBX_STYLE_SORTABLE_LIST); + + $values = $this->field->getValue(); + + if (!$values) { + $values[] = CWidgetFieldGraphDataSet::getDefaults(); + } + + // Get item names for single item datasets. + $itemids = array_merge(...array_column($values, 'itemids')); + $item_names = []; + if ($itemids) { + $item_names = CWidgetFieldGraphDataSet::getItemNames($itemids); + } + + foreach ($values as $i => $value) { + if ($value['dataset_type'] == CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM) { + $value['item_names'] = $item_names; + } + + $list->addItem( + $this->getGraphDataSetLayout($value, $value['dataset_type'], $i == 0, $i) + ); + } + + return $list; + } + + public function getFooterView(): CList { + return (new CList()) + ->addClass(ZBX_STYLE_BTN_SPLIT) + ->addItem([ + (new CButton(null, [ + (new CSpan())->addClass(ZBX_STYLE_PLUS_ICON), + _('Add new data set') + ])) + ->setId('dataset-add') + ->addClass(ZBX_STYLE_BTN_ALT), + (new CButton(null, '​')) + ->setId('dataset-menu') + ->addClass(ZBX_STYLE_BTN_ALT) + ->addClass(ZBX_STYLE_BTN_TOGGLE_CHEVRON) + ]); + } + + public function getTemplates(): array { + $value = ['color' => '#{color}'] + CWidgetFieldGraphDataSet::getDefaults(); + + return [ + new CTemplateTag('dataset-pattern-item-tmpl', + $this->getGraphDataSetLayout($value, CWidgetFieldGraphDataSet::DATASET_TYPE_PATTERN_ITEM, true) + ), + new CTemplateTag('dataset-single-item-tmpl', + $this->getGraphDataSetLayout($value, CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM, true) + ), + new CTemplateTag('dataset-item-row-tmpl', $this->getItemRowTemplate()), + ]; + } + + private function getGraphDataSetLayout(array $value, int $dataset_type, bool $is_opened, + $row_num = '#{rowNum}'): CListItem { + $field_name = $this->field->getName(); + + $dataset_head = [ + new CDiv((new CSimpleButton(' '))->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_TOGGLE)), + new CVar($field_name.'['.$row_num.'][dataset_type]', $dataset_type, '') + ]; + + if ($dataset_type == CWidgetFieldGraphDataSet::DATASET_TYPE_PATTERN_ITEM) { + $host_pattern_field = (new CPatternSelect([ + 'name' => $field_name.'['.$row_num.'][hosts][]', + 'object_name' => 'hosts', + 'data' => $value['hosts'], + 'placeholder' => _('host pattern'), + 'wildcard_allowed' => 1, + 'popup' => [ + 'parameters' => [ + 'srctbl' => 'hosts', + 'srcfld1' => 'host', + 'dstfrm' => $this->form_name, + 'dstfld1' => zbx_formatDomId($field_name.'['.$row_num.'][hosts][]') + ] + ], + 'add_post_js' => false + ]))->addClass('js-hosts-multiselect'); + + $dataset_head = array_merge($dataset_head, [ + (new CColor($field_name.'['.$row_num.'][color]', $value['color'])) + ->appendColorPickerJs(false), + $host_pattern_field, + (new CPatternSelect([ + 'name' => $field_name.'['.$row_num.'][items][]', + 'object_name' => 'items', + 'data' => $value['items'], + 'placeholder' => _('item pattern'), + 'wildcard_allowed' => 1, + 'popup' => [ + 'parameters' => [ + 'srctbl' => 'items', + 'srcfld1' => 'name', + 'real_hosts' => 1, + 'numeric' => 1, + 'dstfrm' => $this->form_name, + 'dstfld1' => zbx_formatDomId($field_name.'['.$row_num.'][items][]') + ], + 'filter_preselect' => [ + 'id' => $host_pattern_field->getId(), + 'submit_as' => 'host_pattern', + 'submit_parameters' => [ + 'host_pattern_wildcard_allowed' => 1, + 'host_pattern_multiple' => 1 + ], + 'multiple' => true + ] + ], + 'autosuggest' => [ + 'filter_preselect' => [ + 'id' => $host_pattern_field->getId(), + 'submit_as' => 'host_pattern', + 'submit_parameters' => [ + 'host_pattern_wildcard_allowed' => 1, + 'host_pattern_multiple' => 1 + ], + 'multiple' => true + ] + ], + 'add_post_js' => false + ]))->addClass('js-items-multiselect') + ]); + } + else { + $item_rows = []; + foreach($value['itemids'] as $i => $itemid) { + $item_name = array_key_exists($itemid, $value['item_names']) + ? $value['item_names'][$itemid] + : ''; + + $item_rows[] = $this->getItemRowTemplate($row_num, ($i + 1), $itemid, $item_name, $value['color'][$i]); + } + + $empty_msg_block = (new CDiv(_('No item selected.')))->addClass('no-items-message'); + + $items_list = (new CTable()) + ->addClass('single-item-table') + ->setAttribute('data-set', $row_num) + ->setColumns([ + (new CTableColumn())->addClass('table-col-handle'), + (new CTableColumn())->addClass('table-col-color'), + (new CTableColumn())->addClass('table-col-no'), + (new CTableColumn(_('Name')))->addClass('table-col-name'), + (new CTableColumn(_('Action')))->addClass('table-col-action') + ]) + ->addItem([ + $item_rows, + (new CTag('tfoot', true)) + ->addItem( + (new CCol( + (new CList()) + ->addClass(ZBX_STYLE_INLINE_FILTER_FOOTER) + ->addItem( + (new CSimpleButton(_('Add'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('js-add-item') + ) + ))->setColSpan(5) + ) + ]); + + $dataset_head = array_merge($dataset_head, [ + (new CDiv([$empty_msg_block, $items_list]))->addClass('items-list table-forms-separator') + ]); + } + + $dataset_head[] = (new CDiv( + (new CButton()) + ->setAttribute('title', _('Delete')) + ->addClass(ZBX_STYLE_BTN_REMOVE) + ->removeId() + ))->addClass('dataset-actions'); + + return (new CListItem([ + (new CDiv()) + ->addClass(ZBX_STYLE_DRAG_ICON) + ->addClass(ZBX_STYLE_SORTABLE_DRAG_HANDLE) + ->addClass('js-main-drag-icon'), + (new CDiv()) + ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_HEAD) + ->addClass('dataset-head') + ->addItem($dataset_head), + (new CDiv()) + ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_BODY) + ->addClass('dataset-body') + ->addItem([ + (new CFormGrid()) + ->addItem([ + new CLabel(_('Draw')), + new CFormField( + (new CRadioButtonList($field_name.'['.$row_num.'][type]', (int) $value['type'])) + ->addClass('js-type') + ->addValue(_('Line'), SVG_GRAPH_TYPE_LINE) + ->addValue(_('Points'), SVG_GRAPH_TYPE_POINTS) + ->addValue(_('Staircase'), SVG_GRAPH_TYPE_STAIRCASE) + ->addValue(_('Bar'), SVG_GRAPH_TYPE_BAR) + ->setModern() + ) + ]) + ->addItem([ + new CLabel(_('Stacked'), $field_name.'['.$row_num.'][stacked]'), + new CFormField([ + (new CVar($field_name.'['.$row_num.'][stacked]', '0'))->removeId(), + (new CCheckBox($field_name.'['.$row_num.'][stacked]')) + ->addClass('js-stacked') + ->setChecked((bool) $value['stacked']) + ->setEnabled($value['type'] != SVG_GRAPH_TYPE_POINTS) + ]) + ]) + ->addItem([ + new CLabel(_('Width')), + new CFormField( + (new CRangeControl($field_name.'['.$row_num.'][width]', (int) $value['width'])) + ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) + ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) + ->setStep(1) + ->setMin(0) + ->setMax(10) + ) + ]) + ->addItem([ + new CLabel(_('Point size')), + new CFormField( + (new CRangeControl($field_name.'['.$row_num.'][pointsize]', (int) $value['pointsize'])) + ->setEnabled($value['type'] == SVG_GRAPH_TYPE_POINTS) + ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) + ->setStep(1) + ->setMin(1) + ->setMax(10) + ) + ]) + ->addItem([ + new CLabel(_('Transparency')), + new CFormField( + (new CRangeControl($field_name.'['.$row_num.'][transparency]', + (int) $value['transparency']) + ) + ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) + ->setStep(1) + ->setMin(0) + ->setMax(10) + ) + ]) + ->addItem([ + new CLabel(_('Fill')), + new CFormField( + (new CRangeControl($field_name.'['.$row_num.'][fill]', (int) $value['fill'])) + ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) + ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) + ->setStep(1) + ->setMin(0) + ->setMax(10) + ) + ]), + (new CFormGrid()) + ->addItem([ + new CLabel(_('Missing data')), + new CFormField( + (new CRadioButtonList($field_name.'['.$row_num.'][missingdatafunc]', + (int) $value['missingdatafunc']) + ) + ->addValue(_('None'), SVG_GRAPH_MISSING_DATA_NONE) + ->addValue(_x('Connected', 'missing data function'), + SVG_GRAPH_MISSING_DATA_CONNECTED + ) + ->addValue(_x('Treat as 0', 'missing data function'), + SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO + ) + ->addValue(_x('Last known', 'missing data function'), + SVG_GRAPH_MISSING_DATA_LAST_KNOWN + ) + ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) + ->setModern() + ) + ]) + ->addItem([ + new CLabel(_('Y-axis')), + new CFormField( + (new CRadioButtonList($field_name.'['.$row_num.'][axisy]', (int) $value['axisy'])) + ->addValue(_('Left'), GRAPH_YAXIS_SIDE_LEFT) + ->addValue(_('Right'), GRAPH_YAXIS_SIDE_RIGHT) + ->setModern() + ) + ]) + ->addItem([ + new CLabel(_('Time shift'), $field_name.'['.$row_num.'][timeshift]'), + new CFormField( + (new CTextBox($field_name.'['.$row_num.'][timeshift]', $value['timeshift'])) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) + ->setAttribute('placeholder', _('none')) + ) + ]) + ->addItem([ + new CLabel(_('Aggregation function'), + 'label-'.$field_name.'_'.$row_num.'_aggregate_function' + ), + new CFormField( + (new CSelect($field_name.'['.$row_num.'][aggregate_function]')) + ->setId($field_name.'_'.$row_num.'_aggregate_function') + ->setFocusableElementId('label-'.$field_name.'_'.$row_num.'_aggregate_function') + ->setValue((int) $value['aggregate_function']) + ->addOptions(CSelect::createOptionsFromArray([ + AGGREGATE_NONE => graph_item_aggr_fnc2str(AGGREGATE_NONE), + AGGREGATE_MIN => graph_item_aggr_fnc2str(AGGREGATE_MIN), + AGGREGATE_MAX => graph_item_aggr_fnc2str(AGGREGATE_MAX), + AGGREGATE_AVG => graph_item_aggr_fnc2str(AGGREGATE_AVG), + AGGREGATE_COUNT => graph_item_aggr_fnc2str(AGGREGATE_COUNT), + AGGREGATE_SUM => graph_item_aggr_fnc2str(AGGREGATE_SUM), + AGGREGATE_FIRST => graph_item_aggr_fnc2str(AGGREGATE_FIRST), + AGGREGATE_LAST => graph_item_aggr_fnc2str(AGGREGATE_LAST) + ])) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) + ) + ]) + ->addItem([ + new CLabel(_('Aggregation interval'), $field_name.'['.$row_num.'][aggregate_interval]'), + new CFormField( + (new CTextBox($field_name.'['.$row_num.'][aggregate_interval]', + $value['aggregate_interval'] + )) + ->setEnabled($value['aggregate_function'] != AGGREGATE_NONE) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) + ->setAttribute('placeholder', GRAPH_AGGREGATE_DEFAULT_INTERVAL) + ) + ]) + ->addItem([ + new CLabel(_('Aggregate')), + new CFormField( + (new CRadioButtonList($field_name.'['.$row_num.'][aggregate_grouping]', + (int) $value['aggregate_grouping']) + ) + ->addValue(_('Each item'), GRAPH_AGGREGATE_BY_ITEM) + ->addValue(_('Data set'), GRAPH_AGGREGATE_BY_DATASET) + ->setEnabled($value['aggregate_function'] != AGGREGATE_NONE) + ->setModern() + ) + ]) + ->addItem([ + new CLabel(_('Approximation'), + 'label-'.$field_name.'_'.$row_num.'_approximation' + ), + new CFormField( + (new CSelect($field_name.'['.$row_num.'][approximation]')) + ->setId($field_name.'_'.$row_num.'_approximation') + ->setFocusableElementId('label-'.$field_name.'_'.$row_num.'_approximation') + ->setValue((int) $value['approximation']) + ->addOptions(CSelect::createOptionsFromArray([ + APPROXIMATION_ALL => [ + 'label' => _('all'), + 'disabled' => $value['type'] != SVG_GRAPH_TYPE_LINE || $value['stacked'] + ], + APPROXIMATION_MIN => _('min'), + APPROXIMATION_AVG => _('avg'), + APPROXIMATION_MAX => _('max') + ])) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) + ) + ]) + ]) + ])) + ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM) + ->addClass(ZBX_STYLE_SORTABLE_ITEM) + ->addClass($is_opened ? ZBX_STYLE_LIST_ACCORDION_ITEM_OPENED : ZBX_STYLE_LIST_ACCORDION_ITEM_CLOSED) + ->setAttribute('data-set', $row_num) + ->setAttribute('data-type', $dataset_type); + } + + private function getItemRowTemplate($ds_num = '#{dsNum}', $row_num = '#{rowNum}', $itemid = '#{itemid}', + $name = '#{name}', $color = '#{color}'): CRow { + return (new CRow([ + (new CCol( + (new CDiv())->addClass(ZBX_STYLE_DRAG_ICON) + )) + ->addClass('table-col-handle') + ->addClass(ZBX_STYLE_TD_DRAG_ICON), + (new CCol( + (new CColor($this->field->getName().'['.$ds_num.'][color][]', $color, + 'items_'.$ds_num.'_'.$row_num.'_color' + ))->appendColorPickerJs(false) + ))->addClass('table-col-color'), + (new CCol(new CSpan($row_num.':')))->addClass('table-col-no'), + (new CCol( + (new CLink($name)) + ->setId('items_'.$ds_num.'_'.$row_num.'_name') + ->addClass('js-click-expend') + ))->addClass('table-col-name'), + (new CCol([ + (new CButton('button', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove'), + new CVar($this->field->getName().'['.$ds_num.'][itemids][]', $itemid, + 'items_'.$ds_num.'_'.$row_num.'_input' + ) + ])) + ->addClass('table-col-action') + ->addClass(ZBX_STYLE_NOWRAP) + ])) + ->addClass(ZBX_STYLE_SORTABLE) + ->addClass('single-item-table-row'); + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldGraphOverrideView.php b/ui/include/classes/html/widgets/CWidgetFieldGraphOverrideView.php new file mode 100755 index 00000000000..a15914f30d1 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldGraphOverrideView.php @@ -0,0 +1,348 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldGraphOverride; + +class CWidgetFieldGraphOverrideView extends CWidgetFieldView { + + public function __construct(CWidgetFieldGraphOverride $field) { + $this->field = $field; + } + + public function getView(): CList { + $list = (new CList())->addClass(ZBX_STYLE_OVERRIDES_LIST); + + $i = 0; + foreach ($this->field->getValue() as $override) { + $list->addItem($this->getItemTemplate($override, $i)); + + $i++; + } + + $list->addItem( + (new CDiv( + (new CButton('override_add', [(new CSpan())->addClass(ZBX_STYLE_PLUS_ICON), _('Add new override')])) + ->addClass(ZBX_STYLE_BTN_ALT) + ->setId('override-add') + )), + 'overrides-foot' + ); + + return $list; + } + + public function getJavaScript(): string { + return ' + // Define it as function to avoid redundancy. + function initializeOverrides() { + jQuery("#overrides .'.ZBX_STYLE_OVERRIDES_OPTIONS_LIST.'").overrides({ + add: ".'.ZBX_STYLE_BTN_ALT.'", + options: "input[type=hidden]", + captions: '.json_encode($this->getGraphOverrideOptionNames()).', + makeName: function(option, row_id) { + return "'.$this->field->getName().'[" + row_id + "][" + option + "]"; + }, + makeOption: function(name) { + return name.match( + /.*\[('.implode('|', $this->field->getOverrideOptions()).')\]/ + )[1]; + }, + override: ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", + overridesList: ".'.ZBX_STYLE_OVERRIDES_LIST.'", + onUpdate: () => widget_svggraph_form.onGraphConfigChange(), + menu: '.json_encode($this->getGraphOverrideMenu()).' + }); + } + + // Initialize dynamicRows. + jQuery("#overrides") + .dynamicRows({ + template: "#overrides-row", + beforeRow: ".overrides-foot", + remove: ".'.ZBX_STYLE_BTN_REMOVE.'", + add: "#override-add", + row: ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'" + }) + .bind("afteradd.dynamicRows", function(event, options) { + const container = jQuery(".overlay-dialogue-body"); + + container.scrollTop(Math.max(container.scrollTop(), + jQuery("#widget-dialogue-form")[0].scrollHeight - container.height() + )); + + jQuery(".multiselect", jQuery("#overrides")).each(function() { + jQuery(this).multiSelect(jQuery(this).data("params")); + }); + + widget_svggraph_form.updateVariableOrder(jQuery("#overrides"), ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", "or"); + widget_svggraph_form.onGraphConfigChange(); + }) + .bind("afterremove.dynamicRows", function(event, options) { + widget_svggraph_form.updateVariableOrder(jQuery("#overrides"), ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", "or"); + widget_svggraph_form.onGraphConfigChange(); + }) + .bind("tableupdate.dynamicRows", function(event, options) { + widget_svggraph_form.updateVariableOrder(jQuery("#overrides"), ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", "or"); + initializeOverrides(); + if (jQuery("#overrides .'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'").length > 1) { + jQuery("#overrides .drag-icon").removeClass("disabled"); + jQuery("#overrides").sortable("enable"); + } + else { + jQuery("#overrides .drag-icon").addClass("disabled"); + jQuery("#overrides").sortable("disable"); + } + }); + + // Initialize overrides UI control. + initializeOverrides(); + + // Initialize override pattern-selectors. + jQuery(".multiselect", jQuery("#overrides")).each(function() { + jQuery(this).multiSelect(jQuery(this).data("params")); + }); + + // Make overrides sortable. + if (jQuery("#overrides .'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'").length < 2) { + jQuery("#overrides .drag-icon").addClass("disabled"); + } + + jQuery("#overrides").sortable({ + items: ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", + containment: "parent", + handle: ".drag-icon", + tolerance: "pointer", + scroll: false, + cursor: "grabbing", + opacity: 0.6, + axis: "y", + disabled: function() { + return jQuery("#overrides .'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'").length < 2; + }(), + start: function() { // Workaround to fix wrong scrolling at initial sort. + jQuery(this).sortable("refreshPositions"); + }, + stop: () => widget_svggraph_form.onGraphConfigChange(), + update: function() { + widget_svggraph_form.updateVariableOrder(jQuery("#overrides"), ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", "or"); + } + }); + '; + } + + public function getTemplates(): array { + return [ + new CTemplateTag('overrides-row', $this->getItemTemplate(CWidgetFieldGraphOverride::getDefaults())) + ]; + } + + /** + * Function returns array containing string values used as titles for override options. + */ + private function getGraphOverrideOptionNames(): array { + return [ + 'width' => _('Width'), + 'type' => _('Draw'), + 'type'.SVG_GRAPH_TYPE_LINE => _('Line'), + 'type'.SVG_GRAPH_TYPE_POINTS => _('Points'), + 'type'.SVG_GRAPH_TYPE_STAIRCASE => _('Staircase'), + 'type'.SVG_GRAPH_TYPE_BAR => _('Bar'), + 'transparency' => _('Transparency'), + 'fill' => _('Fill'), + 'pointsize' => _('Point size'), + 'missingdatafunc' => _('Missing data'), + 'missingdatafunc'.SVG_GRAPH_MISSING_DATA_NONE => _('None'), + 'missingdatafunc'.SVG_GRAPH_MISSING_DATA_CONNECTED => _x('Connected', 'missing data function'), + 'missingdatafunc'.SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO => _x('Treat as 0', 'missing data function'), + 'missingdatafunc'.SVG_GRAPH_MISSING_DATA_LAST_KNOWN => _x('Last known', 'missing data function'), + 'axisy' => _('Y-axis'), + 'axisy'.GRAPH_YAXIS_SIDE_LEFT => _('Left'), + 'axisy'.GRAPH_YAXIS_SIDE_RIGHT => _('Right'), + 'timeshift' => _('Time shift') + ]; + } + + /** + * Function returns array used to construct override field menu of available override options. + */ + private function getGraphOverrideMenu(): array { + return [ + 'sections' => [ + [ + 'name' => _('ADD OVERRIDE'), + 'options' => [ + ['name' => _('Base color'), 'callback' => 'addOverride', 'args' => ['color', '']], + + ['name' => _('Width').'/0', 'callback' => 'addOverride', 'args' => ['width', 0]], + ['name' => _('Width').'/1', 'callback' => 'addOverride', 'args' => ['width', 1]], + ['name' => _('Width').'/2', 'callback' => 'addOverride', 'args' => ['width', 2]], + ['name' => _('Width').'/3', 'callback' => 'addOverride', 'args' => ['width', 3]], + ['name' => _('Width').'/4', 'callback' => 'addOverride', 'args' => ['width', 4]], + ['name' => _('Width').'/5', 'callback' => 'addOverride', 'args' => ['width', 5]], + ['name' => _('Width').'/6', 'callback' => 'addOverride', 'args' => ['width', 6]], + ['name' => _('Width').'/7', 'callback' => 'addOverride', 'args' => ['width', 7]], + ['name' => _('Width').'/8', 'callback' => 'addOverride', 'args' => ['width', 8]], + ['name' => _('Width').'/9', 'callback' => 'addOverride', 'args' => ['width', 9]], + ['name' => _('Width').'/10', 'callback' => 'addOverride', 'args' => ['width', 10]], + + ['name' => _('Draw').'/'._('Line'), 'callback' => 'addOverride', 'args' => ['type', SVG_GRAPH_TYPE_LINE]], + ['name' => _('Draw').'/'._('Points'), 'callback' => 'addOverride', 'args' => ['type', SVG_GRAPH_TYPE_POINTS]], + ['name' => _('Draw').'/'._('Staircase'), 'callback' => 'addOverride', 'args' => ['type', SVG_GRAPH_TYPE_STAIRCASE]], + ['name' => _('Draw').'/'._('Bar'), 'callback' => 'addOverride', 'args' => ['type', SVG_GRAPH_TYPE_BAR]], + + ['name' => _('Transparency').'/0', 'callback' => 'addOverride', 'args' => ['transparency', 0]], + ['name' => _('Transparency').'/1', 'callback' => 'addOverride', 'args' => ['transparency', 1]], + ['name' => _('Transparency').'/2', 'callback' => 'addOverride', 'args' => ['transparency', 2]], + ['name' => _('Transparency').'/3', 'callback' => 'addOverride', 'args' => ['transparency', 3]], + ['name' => _('Transparency').'/4', 'callback' => 'addOverride', 'args' => ['transparency', 4]], + ['name' => _('Transparency').'/5', 'callback' => 'addOverride', 'args' => ['transparency', 5]], + ['name' => _('Transparency').'/6', 'callback' => 'addOverride', 'args' => ['transparency', 6]], + ['name' => _('Transparency').'/7', 'callback' => 'addOverride', 'args' => ['transparency', 7]], + ['name' => _('Transparency').'/8', 'callback' => 'addOverride', 'args' => ['transparency', 8]], + ['name' => _('Transparency').'/9', 'callback' => 'addOverride', 'args' => ['transparency', 9]], + ['name' => _('Transparency').'/10', 'callback' => 'addOverride', 'args' => ['transparency', 10]], + + ['name' => _('Fill').'/0', 'callback' => 'addOverride', 'args' => ['fill', 0]], + ['name' => _('Fill').'/1', 'callback' => 'addOverride', 'args' => ['fill', 1]], + ['name' => _('Fill').'/2', 'callback' => 'addOverride', 'args' => ['fill', 2]], + ['name' => _('Fill').'/3', 'callback' => 'addOverride', 'args' => ['fill', 3]], + ['name' => _('Fill').'/4', 'callback' => 'addOverride', 'args' => ['fill', 4]], + ['name' => _('Fill').'/5', 'callback' => 'addOverride', 'args' => ['fill', 5]], + ['name' => _('Fill').'/6', 'callback' => 'addOverride', 'args' => ['fill', 6]], + ['name' => _('Fill').'/7', 'callback' => 'addOverride', 'args' => ['fill', 7]], + ['name' => _('Fill').'/8', 'callback' => 'addOverride', 'args' => ['fill', 8]], + ['name' => _('Fill').'/9', 'callback' => 'addOverride', 'args' => ['fill', 9]], + ['name' => _('Fill').'/10', 'callback' => 'addOverride', 'args' => ['fill', 10]], + + ['name' => _('Point size').'/1', 'callback' => 'addOverride', 'args' => ['pointsize', 1]], + ['name' => _('Point size').'/2', 'callback' => 'addOverride', 'args' => ['pointsize', 2]], + ['name' => _('Point size').'/3', 'callback' => 'addOverride', 'args' => ['pointsize', 3]], + ['name' => _('Point size').'/4', 'callback' => 'addOverride', 'args' => ['pointsize', 4]], + ['name' => _('Point size').'/5', 'callback' => 'addOverride', 'args' => ['pointsize', 5]], + ['name' => _('Point size').'/6', 'callback' => 'addOverride', 'args' => ['pointsize', 6]], + ['name' => _('Point size').'/7', 'callback' => 'addOverride', 'args' => ['pointsize', 7]], + ['name' => _('Point size').'/8', 'callback' => 'addOverride', 'args' => ['pointsize', 8]], + ['name' => _('Point size').'/9', 'callback' => 'addOverride', 'args' => ['pointsize', 9]], + ['name' => _('Point size').'/10', 'callback' => 'addOverride', 'args' => ['pointsize', 10]], + + ['name' => _('Missing data').'/'._('None'), 'callback' => 'addOverride', 'args' => ['missingdatafunc', SVG_GRAPH_MISSING_DATA_NONE]], + ['name' => _('Missing data').'/'._x('Connected', 'missing data function'), 'callback' => 'addOverride', 'args' => ['missingdatafunc', SVG_GRAPH_MISSING_DATA_CONNECTED]], + ['name' => _('Missing data').'/'._x('Treat as 0', 'missing data function'), 'callback' => 'addOverride', 'args' => ['missingdatafunc', SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO]], + ['name' => _('Missing data').'/'._x('Last known', 'missing data function'), 'callback' => 'addOverride', 'args' => ['missingdatafunc', SVG_GRAPH_MISSING_DATA_LAST_KNOWN]], + + ['name' => _('Y-axis').'/'._('Left'), 'callback' => 'addOverride', 'args' => ['axisy', GRAPH_YAXIS_SIDE_LEFT]], + ['name' => _('Y-axis').'/'._('Right'), 'callback' => 'addOverride', 'args' => ['axisy', GRAPH_YAXIS_SIDE_RIGHT]], + + ['name' => _('Time shift'), 'callback' => 'addOverride', 'args' => ['timeshift']] + ] + ] + ] + ]; + } + + private function getItemTemplate(array $value, $row_num = '#{rowNum}'): CListItem { + $inputs = []; + + // Create override options list. + foreach ($this->field->getOverrideOptions() as $option) { + if (array_key_exists($option, $value)) { + $inputs[] = (new CVar($this->field->getName().'['.$row_num.']['.$option.']', $value[$option])); + } + } + + $host_pattern_field = (new CPatternSelect([ + 'name' => $this->field->getName().'['.$row_num.'][hosts][]', + 'object_name' => 'hosts', + 'data' => $value['hosts'], + 'placeholder' => _('host pattern'), + 'wildcard_allowed' => 1, + 'popup' => [ + 'parameters' => [ + 'srctbl' => 'hosts', + 'srcfld1' => 'hostid', + 'dstfrm' => $this->form_name, + 'dstfld1' => zbx_formatDomId($this->field->getName().'['.$row_num.'][hosts][]') + ] + ], + 'add_post_js' => false + ])) + ->setEnabled(!$this->isDisabled()) + ->setAriaRequired($this->isRequired()); + + return (new CListItem([ + (new CDiv())->addClass(ZBX_STYLE_DRAG_ICON), + $host_pattern_field, + (new CPatternSelect([ + 'name' => $this->field->getName().'['.$row_num.'][items][]', + 'object_name' => 'items', + 'data' => $value['items'], + 'placeholder' => _('item pattern'), + 'wildcard_allowed' => 1, + 'popup' => [ + 'parameters' => [ + 'srctbl' => 'items', + 'srcfld1' => 'itemid', + 'real_hosts' => 1, + 'numeric' => 1, + 'dstfrm' => $this->form_name, + 'dstfld1' => zbx_formatDomId($this->field->getName().'['.$row_num.'][items][]') + ], + 'filter_preselect' => [ + 'id' => $host_pattern_field->getId(), + 'submit_as' => 'host_pattern', + 'submit_parameters' => [ + 'host_pattern_wildcard_allowed' => 1, + 'host_pattern_multiple' => 1 + ], + 'multiple' => true + ] + ], + 'autosuggest' => [ + 'filter_preselect' => [ + 'id' => $host_pattern_field->getId(), + 'submit_as' => 'host_pattern', + 'submit_parameters' => [ + 'host_pattern_wildcard_allowed' => 1, + 'host_pattern_multiple' => 1 + ], + 'multiple' => true + ] + ], + 'add_post_js' => false + ])) + ->setEnabled(!$this->isDisabled()) + ->setAriaRequired($this->isRequired()), + (new CDiv( + (new CButton()) + ->setAttribute('title', _('Delete')) + ->addClass(ZBX_STYLE_BTN_REMOVE) + ->removeId() + ))->addClass('dataset-actions'), + (new CList($inputs)) + ->addClass(ZBX_STYLE_OVERRIDES_OPTIONS_LIST) + ->addItem( + (new CButton(null, (new CSpan())->addClass(ZBX_STYLE_PLUS_ICON))) + ->setAttribute('data-row', $row_num) + ->addClass(ZBX_STYLE_BTN_ALT) + ) + ]))->addClass(ZBX_STYLE_OVERRIDES_LIST_ITEM); + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldHostPatternSelectView.php b/ui/include/classes/html/widgets/CWidgetFieldHostPatternSelectView.php new file mode 100755 index 00000000000..2f16643f678 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldHostPatternSelectView.php @@ -0,0 +1,65 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldHostPatternSelect; + +class CWidgetFieldHostPatternSelectView extends CWidgetFieldView { + + private string $placeholder = ''; + + public function __construct(CWidgetFieldHostPatternSelect $field) { + $this->field = $field; + } + + public function setPlaceholder(string $placeholder): self { + $this->placeholder = $placeholder; + + return $this; + } + + public function getView(): CPatternSelect { + return (new CPatternSelect([ + 'name' => $this->field->getName().'[]', + 'object_name' => 'hosts', + 'data' => $this->field->getValue(), + 'placeholder' => $this->placeholder, + 'wildcard_allowed' => 1, + 'popup' => [ + 'parameters' => [ + 'srctbl' => 'hosts', + 'srcfld1' => 'hostid', + 'dstfrm' => $this->form_name, + 'dstfld1' => zbx_formatDomId($this->field->getName().'[]') + ] + ], + 'add_post_js' => false + ])) + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ->setEnabled(!$this->isDisabled()) + ->setAriaRequired($this->isRequired()); + } + + public function getJavaScript(): string { + $field_id = zbx_formatDomId($this->field->getName().'[]'); + + return 'jQuery("#'.$field_id.'").multiSelect(jQuery("#'.$field_id.'").data("params"));'; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldIntegerBoxView.php b/ui/include/classes/html/widgets/CWidgetFieldIntegerBoxView.php new file mode 100755 index 00000000000..f1e36ee5e6a --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldIntegerBoxView.php @@ -0,0 +1,37 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldIntegerBox; + +class CWidgetFieldIntegerBoxView extends CWidgetFieldView { + + public function __construct(CWidgetFieldIntegerBox $field) { + $this->field = $field; + } + + public function getView(): CNumericBox { + return (new CNumericBox($this->field->getName(), $this->field->getValue(), $this->field->getMaxLength(), false, + !$this->isNotEmpty() + )) + ->setWidth(ZBX_TEXTAREA_NUMERIC_STANDARD_WIDTH) + ->setAriaRequired($this->isRequired()); + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldLatLngView.php b/ui/include/classes/html/widgets/CWidgetFieldLatLngView.php new file mode 100755 index 00000000000..d06e5c4e1fc --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldLatLngView.php @@ -0,0 +1,72 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldLatLng; + +class CWidgetFieldLatLngView extends CWidgetFieldView { + + private string $placeholder = ''; + + private int $width = ZBX_TEXTAREA_MEDIUM_WIDTH; + + public function __construct(CWidgetFieldLatLng $field) { + $this->field = $field; + + $this->setHelpHint([ + _('Comma separated center coordinates and zoom level to display when the widget is initially loaded.'), + BR(), + _('Supported formats:'), + (new CList([ + new CListItem((new CSpan('<lat>,<lng>,<zoom>'))->addClass(ZBX_STYLE_MONOSPACE_FONT)), + new CListItem((new CSpan('<lat>,<lng>'))->addClass(ZBX_STYLE_MONOSPACE_FONT)) + ]))->addClass(ZBX_STYLE_LIST_DASHED), + BR(), + _s('The maximum zoom level is "%1$s".', CSettingsHelper::get(CSettingsHelper::GEOMAPS_MAX_ZOOM)), + BR(), + _('Initial view is ignored if the default view is set.') + ]); + } + + public function setPlaceholder(string $placeholder): self { + $this->placeholder = $placeholder; + + return $this; + } + + public function setWidth(int $width): self { + $this->width = $width; + + return $this; + } + + public function getView(): CTextBox { + $textbox = (new CTextBox($this->field->getName(), $this->field->getValue())) + ->setWidth($this->width) + ->setEnabled(!$this->isDisabled()) + ->setAriaRequired($this->isRequired()); + + if ($this->placeholder !== '') { + $textbox = $textbox->setAttribute('placeholder', $this->placeholder); + } + + return $textbox; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGraphPrototypeView.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGraphPrototypeView.php new file mode 100755 index 00000000000..eb4169a0faa --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGraphPrototypeView.php @@ -0,0 +1,42 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelectGraphPrototype; + +class CWidgetFieldMultiSelectGraphPrototypeView extends CWidgetFieldMultiSelectView { + + public function __construct(CWidgetFieldMultiSelectGraphPrototype $field, array $data) { + parent::__construct($field, $data); + } + + protected function getObjectName(): string { + return 'graph_prototypes'; + } + + protected function getPopupParameters(): array { + return [ + 'srctbl' => 'graph_prototypes', + 'srcfld1' => 'graphid', + 'srcfld2' => 'name', + 'with_graph_prototypes' => true + ]; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGraphView.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGraphView.php new file mode 100755 index 00000000000..a67260b30ac --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGraphView.php @@ -0,0 +1,42 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelectGraph; + +class CWidgetFieldMultiSelectGraphView extends CWidgetFieldMultiSelectView { + + public function __construct(CWidgetFieldMultiSelectGraph $field, array $data) { + parent::__construct($field, $data); + } + + protected function getObjectName(): string { + return 'graphs'; + } + + protected function getPopupParameters(): array { + return [ + 'srctbl' => 'graphs', + 'srcfld1' => 'graphid', + 'srcfld2' => 'name', + 'with_graphs' => true + ]; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGroupView.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGroupView.php new file mode 100755 index 00000000000..42ac95d0721 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectGroupView.php @@ -0,0 +1,42 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelectGroup; + +class CWidgetFieldMultiSelectGroupView extends CWidgetFieldMultiSelectView { + + public function __construct(CWidgetFieldMultiSelectGroup $field, array $data) { + parent::__construct($field, $data); + } + + protected function getObjectName(): string { + return 'hostGroup'; + } + + protected function getPopupParameters(): array { + return [ + 'srctbl' => 'host_groups', + 'srcfld1' => 'groupid', + 'real_hosts' => true, + 'enrich_parent_groups' => true + ]; + } +} diff --git a/ui/app/views/js/monitoring.dashboard.widget.edit.js.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectHostView.php index b0f46f671e7..23d727818e5 100644..100755 --- a/ui/app/views/js/monitoring.dashboard.widget.edit.js.php +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectHostView.php @@ -17,21 +17,24 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -?> -window.widget_form = new class { - init() { - document.getElementById('type').addEventListener('change', () => ZABBIX.Dashboard.reloadWidgetProperties()); +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelectHost; - document.getElementById('widget-dialogue-form').addEventListener('change', (e) => { - const is_trimmable = e.target.matches( - 'input[type="text"]:not([data-no-trim="1"]), textarea:not([data-no-trim="1"])' - ); +class CWidgetFieldMultiSelectHostView extends CWidgetFieldMultiSelectView { - if (is_trimmable) { - e.target.value = e.target.value.trim(); - } - }, {capture: true}); + public function __construct(CWidgetFieldMultiSelectHost $field, array $data) { + parent::__construct($field, $data); } -}; + + protected function getObjectName(): string { + return 'hosts'; + } + + protected function getPopupParameters(): array { + return [ + 'srctbl' => 'hosts', + 'srcfld1' => 'hostid' + ]; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldMultiSelectItemPrototypeView.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectItemPrototypeView.php new file mode 100755 index 00000000000..8de80be206f --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectItemPrototypeView.php @@ -0,0 +1,40 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelectItemPrototype; + +class CWidgetFieldMultiSelectItemPrototypeView extends CWidgetFieldMultiSelectView { + + public function __construct(CWidgetFieldMultiSelectItemPrototype $field, array $data) { + parent::__construct($field, $data); + } + + protected function getObjectName(): string { + return 'item_prototypes'; + } + + protected function getPopupParameters(): array { + return [ + 'srctbl' => 'item_prototypes', + 'srcfld1' => 'itemid' + ]; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldMultiSelectItemView.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectItemView.php new file mode 100755 index 00000000000..74c7816ef41 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectItemView.php @@ -0,0 +1,40 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelectItem; + +class CWidgetFieldMultiSelectItemView extends CWidgetFieldMultiSelectView { + + public function __construct(CWidgetFieldMultiSelectItem $field, array $data) { + parent::__construct($field, $data); + } + + protected function getObjectName(): string { + return 'items'; + } + + protected function getPopupParameters(): array { + return [ + 'srctbl' => 'items', + 'srcfld1' => 'itemid' + ]; + } +} diff --git a/ui/include/classes/widgets/views/js/widget.problems.form.view.js.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectServiceView.php index 64206926d0c..4b68ec939b4 100644..100755 --- a/ui/include/classes/widgets/views/js/widget.problems.form.view.js.php +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectServiceView.php @@ -17,17 +17,19 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -?> -window.widget_problems_form = new class { +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelectService; - init({sort_with_enabled_show_timeline}) { - document.getElementById('sort_triggers').addEventListener('change', (e) => { - const show_timeline = document.getElementById('show_timeline'); +class CWidgetFieldMultiSelectServiceView extends CWidgetFieldMultiSelectView { - show_timeline.disabled = !sort_with_enabled_show_timeline[e.target.value]; - show_timeline.checked = !show_timeline.disabled; - }); + public function __construct(CWidgetFieldMultiSelectService $field, array $data) { + parent::__construct($field, $data); + + $this->custom_select = true; + } + + protected function getObjectName(): string { + return 'services'; } -}; +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldMultiSelectSlaView.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectSlaView.php new file mode 100755 index 00000000000..6b3b87ede1a --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectSlaView.php @@ -0,0 +1,40 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelectSla; + +class CWidgetFieldMultiSelectSlaView extends CWidgetFieldMultiSelectView { + + public function __construct(CWidgetFieldMultiSelectSla $field, array $data) { + parent::__construct($field, $data); + } + + protected function getObjectName(): string { + return 'sla'; + } + + protected function getPopupParameters(): array { + return [ + 'srctbl' => 'sla', + 'srcfld1' => 'slaid' + ]; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldMultiSelectView.php b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectView.php new file mode 100755 index 00000000000..17e148e670c --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldMultiSelectView.php @@ -0,0 +1,106 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldMultiSelect; + +abstract class CWidgetFieldMultiSelectView extends CWidgetFieldView { + + protected const OBJECT_NAME = ''; + + protected ?CMultiSelect $multiselect = null; + + protected array $data; + + protected bool $custom_select = false; + + protected array $filter_preselect = []; + + public function __construct(CWidgetFieldMultiSelect $field, array $data) { + $this->field = $field; + $this->data = $data; + } + + public function getId(): string { + return $this->multiselect->getId(); + } + + public function getLabel(): ?CLabel { + $label = parent::getLabel(); + + return $label !== null + ? $label->setFor($this->getId().'_ms') + : null; + } + + public function getView(): CMultiSelect { + if ($this->multiselect === null) { + $multiselect_name = $this->field->getName().($this->field->isMultiple() ? '[]' : ''); + + $options = [ + 'name' => $multiselect_name, + 'object_name' => $this->getObjectName(), + 'multiple' => $this->field->isMultiple(), + 'data' => $this->data, + 'add_post_js' => false + ]; + + if ($this->custom_select) { + $options['custom_select'] = true; + } + else { + $options['popup'] = [ + 'parameters' => [ + 'dstfrm' => $this->form_name, + 'dstfld1' => zbx_formatDomId($multiselect_name) + ] + $this->getPopupParameters() + $this->field->getFilterParameters() + ]; + + if ($this->filter_preselect) { + $options['popup']['filter_preselect'] = $this->filter_preselect; + } + } + + $this->multiselect = (new CMultiSelect($options)) + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ->setAriaRequired($this->isRequired()); + } + + return $this->multiselect; + } + + public function getJavaScript(): string { + return $this->getView()->getPostJS(); + } + + public function setFilterPreselect(array $filter_preselect): self { + $this->filter_preselect = $filter_preselect; + + return $this; + } + + protected function getObjectName(): string { + return ''; + } + + protected function getPopupParameters(): array { + return []; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldNumericBoxView.php b/ui/include/classes/html/widgets/CWidgetFieldNumericBoxView.php new file mode 100755 index 00000000000..4f2957c0b42 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldNumericBoxView.php @@ -0,0 +1,58 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldNumericBox; + +class CWidgetFieldNumericBoxView extends CWidgetFieldView { + + private string $placeholder = ''; + + private int $width = ZBX_TEXTAREA_NUMERIC_BIG_WIDTH; + + public function __construct(CWidgetFieldNumericBox $field) { + $this->field = $field; + } + + public function setPlaceholder(string $placeholder): self { + $this->placeholder = $placeholder; + + return $this; + } + + public function setWidth(int $width): self { + $this->width = $width; + + return $this; + } + + public function getView(): CTextBox { + $textbox = (new CTextBox($this->field->getName(), $this->field->getValue())) + ->setWidth($this->width) + ->setAriaRequired($this->isRequired()) + ->setEnabled(!$this->isDisabled()); + + if ($this->placeholder !== '') { + $textbox = $textbox->setAttribute('placeholder', $this->placeholder); + } + + return $textbox; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldRadioButtonListView.php b/ui/include/classes/html/widgets/CWidgetFieldRadioButtonListView.php new file mode 100755 index 00000000000..158026e7bc7 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldRadioButtonListView.php @@ -0,0 +1,43 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldRadioButtonList; + +class CWidgetFieldRadioButtonListView extends CWidgetFieldView { + + public function __construct(CWidgetFieldRadioButtonList $field) { + $this->field = $field; + } + + public function getView(): CRadioButtonList { + $radio_button_list = (new CRadioButtonList($this->field->getName(), $this->field->getValue())) + ->setModern() + ->setAriaRequired($this->isRequired()); + + foreach ($this->field->getValues() as $key => $value) { + $radio_button_list + ->addValue($value, $key, null, $this->field->getAction()) + ->setEnabled(!$this->isDisabled()); + } + + return $radio_button_list; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldRangeControlView.php b/ui/include/classes/html/widgets/CWidgetFieldRangeControlView.php new file mode 100755 index 00000000000..f736024fc7b --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldRangeControlView.php @@ -0,0 +1,52 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldRangeControl; + +class CWidgetFieldRangeControlView extends CWidgetFieldView { + + protected ?CRangeControl $range_control = null; + + public function __construct(CWidgetFieldRangeControl $field) { + $this->field = $field; + } + + public function getView(): CRangeControl { + return $this->getRangeControl(); + } + + public function getJavaScript(): string { + return $this->getRangeControl()->getPostJS(); + } + + private function getRangeControl(): CRangeControl { + if ($this->range_control === null) { + $this->range_control = (new CRangeControl($this->field->getName(), (int) $this->field->getValue())) + ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) + ->setStep($this->field->getStep()) + ->setMin($this->field->getMin()) + ->setMax($this->field->getMax()) + ->setEnabled(!$this->isDisabled()); + } + + return $this->range_control; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldSelectResourceView.php b/ui/include/classes/html/widgets/CWidgetFieldSelectResourceView.php new file mode 100755 index 00000000000..df6b80cf05f --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldSelectResourceView.php @@ -0,0 +1,54 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldSelectResource; + +class CWidgetFieldSelectResourceView extends CWidgetFieldView { + + private array $data; + + public function __construct(CWidgetFieldSelectResource $field, array $data) { + $this->field = $field; + $this->data = $data; + } + + public function getView(): array { + $caption = $this->field->getValue() != 0 + ? $this->data[$this->field->getResourceType()][$this->field->getValue()] + : ''; + + return [ + (new CTextBox($this->field->getName().'_caption', $caption, true)) + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ->setAriaRequired($this->isRequired()), + (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), + (new CButton('select', _('Select'))) + ->addClass(ZBX_STYLE_BTN_GREY) + ->onClick('return PopUp("popup.generic", + '.json_encode($this->field->getPopupOptions($this->form_name)).', + {dialogue_class: "modal-popup-generic"} + );'), + new CVar($this->field->getName(), $this->field->getValue()) + ]; + } + + +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldSelectView.php b/ui/include/classes/html/widgets/CWidgetFieldSelectView.php new file mode 100755 index 00000000000..94475f64ced --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldSelectView.php @@ -0,0 +1,55 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldSelect; + +class CWidgetFieldSelectView extends CWidgetFieldView { + + protected ?CSelect $select = null; + + public function __construct(CWidgetFieldSelect $field) { + $this->field = $field; + } + + public function getLabel(): ?CLabel { + $label = parent::getLabel(); + + if ($label !== null) { + $label->setFor($this->getView()->getFocusableElementId()); + } + + return $label; + } + + public function getView(): CSelect { + if ($this->select === null) { + $this->select = (new CSelect($this->field->getName())) + ->setId($this->field->getName()) + ->setFocusableElementId('label-'.$this->field->getName()) + ->setValue($this->field->getValue()) + ->addOptions(CSelect::createOptionsFromArray($this->field->getValues())) + ->setDisabled($this->isDisabled()) + ->setAriaRequired($this->isRequired()); + } + + return $this->select; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldSeveritiesView.php b/ui/include/classes/html/widgets/CWidgetFieldSeveritiesView.php new file mode 100755 index 00000000000..3831e8db139 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldSeveritiesView.php @@ -0,0 +1,36 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldSeverities; + +class CWidgetFieldSeveritiesView extends CWidgetFieldView { + + public function __construct(CWidgetFieldSeverities $field) { + $this->field = $field; + } + + public function getView(): CSeverityCheckBoxList { + return (new CSeverityCheckBoxList($this->field->getName())) + ->setChecked($this->field->getValue()) + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ->setEnabled(!$this->isDisabled()); + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldTagsView.php b/ui/include/classes/html/widgets/CWidgetFieldTagsView.php new file mode 100755 index 00000000000..a7d08e29fdb --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldTagsView.php @@ -0,0 +1,118 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldTags; + +class CWidgetFieldTagsView extends CWidgetFieldView { + + public function __construct(CWidgetFieldTags $field) { + $this->field = $field; + } + + public function getView(): CTable { + $tags = $this->field->getValue(); + + if (!$tags) { + $tags = [CWidgetFieldTags::DEFAULT_TAG]; + } + + $tags_table = (new CTable()) + ->setId('tags_table_'.$this->field->getName()) + ->addClass('table-tags') + ->addClass('table-initial-width'); + + $i = 0; + + foreach ($tags as $tag) { + $tags_table->addItem($this->getRowTemplate($tag, $i)); + + $i++; + } + + $tags_table->addRow( + (new CCol( + (new CButton('tags_add', _('Add'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-add') + ->setEnabled(!$this->isDisabled()) + ))->setColSpan(3) + ); + + return $tags_table; + } + + public function getJavaScript(): string { + return ' + jQuery("#tags_table_'.$this->field->getName().'") + .dynamicRows({template: "#'.$this->field->getName().'-row-tmpl"}) + .on("afteradd.dynamicRows", function() { + const rows = this.querySelectorAll(".form_row"); + new CTagFilterItem(rows[rows.length - 1]); + }); + + // Init existing fields once loaded. + document.querySelectorAll("#tags_table_'.$this->field->getName().' .form_row").forEach(row => { + new CTagFilterItem(row); + }); + '; + } + + public function getTemplates(): array { + return [ + new CTemplateTag($this->field->getName().'-row-tmpl', $this->getRowTemplate(CWidgetFieldTags::DEFAULT_TAG)) + ]; + } + + private function getRowTemplate(array $tag, $row_num = '#{rowNum}'): CRow { + return (new CRow([ + (new CTextBox($this->field->getName().'['.$row_num.'][tag]', $tag['tag'])) + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) + ->setAriaRequired($this->isRequired()) + ->setEnabled(!$this->isDisabled() || $row_num === '#{rowNum}') + ->setAttribute('placeholder', _('tag')), + (new CSelect($this->field->getName().'['.$row_num.'][operator]')) + ->addOptions(CSelect::createOptionsFromArray([ + TAG_OPERATOR_EXISTS => _('Exists'), + TAG_OPERATOR_EQUAL => _('Equals'), + TAG_OPERATOR_LIKE => _('Contains'), + TAG_OPERATOR_NOT_EXISTS => _('Does not exist'), + TAG_OPERATOR_NOT_EQUAL => _('Does not equal'), + TAG_OPERATOR_NOT_LIKE => _('Does not contain') + ])) + ->setValue($tag['operator']) + ->setFocusableElementId($this->field->getName().'-'.$row_num.'-operator-select') + ->setId($this->field->getName().'_'.$row_num.'_operator') + ->setDisabled($this->isDisabled() && $row_num !== '#{rowNum}'), + (new CTextBox($this->field->getName().'['.$row_num.'][value]', $tag['value'])) + ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) + ->setAriaRequired($this->isRequired()) + ->setId($this->field->getName().'_'.$row_num.'_value') + ->setEnabled(!$this->isDisabled() || $row_num === '#{rowNum}') + ->setAttribute('placeholder', _('value')), + (new CCol( + (new CButton($this->field->getName().'['.$row_num.'][remove]', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove') + ->setEnabled(!$this->isDisabled() || $row_num === '#{rowNum}') + ))->addClass(ZBX_STYLE_NOWRAP) + ]))->addClass('form_row'); + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldTextAreaView.php b/ui/include/classes/html/widgets/CWidgetFieldTextAreaView.php new file mode 100755 index 00000000000..1c7a6bfb7a6 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldTextAreaView.php @@ -0,0 +1,59 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldTextArea; + +class CWidgetFieldTextAreaView extends CWidgetFieldView { + + private int $width = ZBX_TEXTAREA_STANDARD_WIDTH; + private ?int $adaptive_width = null; + + public function __construct(CWidgetFieldTextArea $field) { + $this->field = $field; + } + + public function setWidth(int $width): self { + $this->width = $width; + + return $this; + } + + public function setAdaptiveWidth(int $adaptive_width): self { + $this->adaptive_width = $adaptive_width; + + return $this; + } + + public function getView(): CTextArea { + $textarea = (new CTextArea($this->field->getName(), $this->field->getValue())) + ->setEnabled(!$this->isDisabled()) + ->setAriaRequired($this->isRequired()); + + if ($this->adaptive_width !== null) { + $textarea->setAdaptiveWidth($this->adaptive_width); + } + else { + $textarea->setWidth($this->width); + } + + return $textarea; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldTextBoxView.php b/ui/include/classes/html/widgets/CWidgetFieldTextBoxView.php new file mode 100755 index 00000000000..8a8a666d9b8 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldTextBoxView.php @@ -0,0 +1,71 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldTextBox; + +class CWidgetFieldTextBoxView extends CWidgetFieldView { + + private string $placeholder = ''; + + private int $width = ZBX_TEXTAREA_STANDARD_WIDTH; + private ?int $adaptive_width = null; + + public function __construct(CWidgetFieldTextBox $field) { + $this->field = $field; + } + + public function setPlaceholder(string $placeholder): self { + $this->placeholder = $placeholder; + + return $this; + } + + public function setWidth(int $width): self { + $this->width = $width; + + return $this; + } + + public function setAdaptiveWidth(int $adaptive_width): self { + $this->adaptive_width = $adaptive_width; + + return $this; + } + + public function getView(): CTextBox { + $textbox = (new CTextBox($this->field->getName(), $this->field->getValue())) + ->setEnabled(!$this->isDisabled()) + ->setAriaRequired($this->isRequired()); + + if ($this->placeholder !== '') { + $textbox = $textbox->setAttribute('placeholder', $this->placeholder); + } + + if ($this->adaptive_width !== null) { + $textbox->setAdaptiveWidth($this->adaptive_width); + } + else { + $textbox->setWidth($this->width); + } + + return $textbox; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldThresholdsView.php b/ui/include/classes/html/widgets/CWidgetFieldThresholdsView.php new file mode 100755 index 00000000000..331efe4e145 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldThresholdsView.php @@ -0,0 +1,100 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldThresholds; + +class CWidgetFieldThresholdsView extends CWidgetFieldView { + + public function __construct(CWidgetFieldThresholds $field) { + $this->field = $field; + } + + public function getView(): CDiv { + $thresholds_table = (new CTable()) + ->setId($this->field->getName().'-table') + ->addClass(ZBX_STYLE_TABLE_FORMS) + ->setHeader([ + '', + (new CColHeader(_('Threshold')))->setWidth('100%'), + _('Action') + ]) + ->setFooter(new CRow( + new CCol( + (new CSimpleButton(_('Add'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-add') + ) + )); + + foreach ($this->field->getValue() as $i => $threshold) { + $thresholds_table->addRow( + $this->getRowTemplate($i, $threshold['color'], $threshold['threshold']) + ); + } + + return (new CDiv($thresholds_table)) + ->addClass('table-forms-separator') + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH); + } + + public function getJavaScript(): string { + return ' + var $thresholds_table = jQuery("#'.$this->field->getName().'-table"); + + $thresholds_table + .dynamicRows({template: "#'.$this->field->getName().'-row-tmpl"}) + .on("afteradd.dynamicRows", function(opt) { + const rows = this.querySelectorAll(".form_row"); + const colors = jQuery("#widget-dialogue-form")[0] + .querySelectorAll(".'.ZBX_STYLE_COLOR_PICKER.' input"); + const used_colors = []; + for (const color of colors) { + if (color.value !== "" && color.name.includes("thresholds")) { + used_colors.push(color.value); + } + } + jQuery(".color-picker input", rows[rows.length - 1]) + .val(colorPalette.getNextColor(used_colors)) + .colorpicker({ + appendTo: ".overlay-dialogue-body" + }); + }); + '; + } + + public function getTemplates(): array { + return [ + new CTemplateTag($this->field->getName().'-row-tmpl', $this->getRowTemplate()) + ]; + } + + public function getRowTemplate($row_num = '#{rowNum}', $color = '#{color}', $threshold = '#{threshold}'): CRow { + return (new CRow([ + (new CColor($this->field->getName().'['.$row_num.'][color]', $color))->appendColorPickerJs(false), + (new CTextBox($this->field->getName().'['.$row_num.'][threshold]', $threshold, false)) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) + ->setAriaRequired(), + (new CButton($this->field->getName().'['.$row_num.'][remove]', _('Remove'))) + ->addClass(ZBX_STYLE_BTN_LINK) + ->addClass('element-table-remove') + ]))->addClass('form_row'); + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldTimeZoneView.php b/ui/include/classes/html/widgets/CWidgetFieldTimeZoneView.php new file mode 100755 index 00000000000..d7fc2fb65bc --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldTimeZoneView.php @@ -0,0 +1,47 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldTimeZone; + +class CWidgetFieldTimeZoneView extends CWidgetFieldSelectView { + + public function __construct(CWidgetFieldTimeZone $field) { + parent::__construct($field); + } + + public function getJavaScript(): string { + return ' + var timezone_select = document.getElementById("'.$this->field->getName().'"); + var timezone_from_list = timezone_select.getOptionByValue(Intl.DateTimeFormat().resolvedOptions().timeZone); + var local_list_item = timezone_select.getOptionByValue("'.TIMEZONE_DEFAULT_LOCAL.'"); + + if (timezone_from_list && local_list_item) { + const title = `${local_list_item.label}: ${timezone_from_list.label}`; + local_list_item.label = title; + local_list_item._node.innerText = title; + + if (timezone_select.selectedIndex === local_list_item._index) { + timezone_select._preselect(timezone_select.selectedIndex); + } + } + '; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldUrlView.php b/ui/include/classes/html/widgets/CWidgetFieldUrlView.php new file mode 100755 index 00000000000..3b4158bef5a --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldUrlView.php @@ -0,0 +1,35 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldUrl; + +class CWidgetFieldUrlView extends CWidgetFieldView { + + public function __construct(CWidgetFieldUrl $field) { + $this->field = $field; + } + + public function getView(): CTextBox { + return (new CTextBox($this->field->getName(), $this->field->getValue())) + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ->setAriaRequired($this->isRequired()); + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldView.php b/ui/include/classes/html/widgets/CWidgetFieldView.php new file mode 100755 index 00000000000..7d3e3b01cb6 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldView.php @@ -0,0 +1,91 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\CWidgetField; + +abstract class CWidgetFieldView { + + protected CWidgetField $field; + + protected string $form_name = ''; + + protected ?CTag $hint = null; + protected $help_hint; + + public function setFormName($form_name): self { + $this->form_name = $form_name; + + return $this; + } + + public function setHint(CTag $hint): self { + $this->hint = $hint; + + return $this; + } + + public function setHelpHint($help_hint): self { + $this->help_hint = $help_hint; + + return $this; + } + + public function getLabel(): ?CLabel { + $label = $this->field->getLabel(); + + if ($label === null) { + return null; + } + + return new CLabel([ + $label, + $this->hint, + $this->help_hint !== null ? makeHelpIcon($this->help_hint) : null + ], zbx_formatDomId($this->field->getName())); + } + + /** + * @return null|array|CTag + */ + public function getView() { + return null; + } + + public function getJavaScript(): string { + return ''; + } + + public function getTemplates(): array { + return []; + } + + public function isNotEmpty(): bool { + return ($this->field->getFlags() & CWidgetField::FLAG_NOT_EMPTY) !== 0; + } + + public function isRequired(): bool { + return ($this->field->getFlags() & CWidgetField::FLAG_LABEL_ASTERISK) !== 0; + } + + public function isDisabled(): bool { + return ($this->field->getFlags() & CWidgetField::FLAG_DISABLED) !== 0; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFieldWidgetSelectView.php b/ui/include/classes/html/widgets/CWidgetFieldWidgetSelectView.php new file mode 100755 index 00000000000..0a643d27810 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFieldWidgetSelectView.php @@ -0,0 +1,72 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\Fields\CWidgetFieldWidgetSelect; + +class CWidgetFieldWidgetSelectView extends CWidgetFieldView { + + protected ?CSelect $select = null; + + public function __construct(CWidgetFieldWidgetSelect $field) { + $this->field = $field; + } + + public function getLabel(): ?CLabel { + $label = parent::getLabel(); + + if ($label !== null) { + $label->setFor($this->getView()->getFocusableElementId()); + } + + return $label; + } + + public function getView(): CSelect { + if ($this->select === null) { + $this->select = (new CSelect($this->field->getName())) + ->setId($this->field->getName()) + ->setFocusableElementId('label-'.$this->field->getName()) + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ->setAriaRequired($this->isRequired()); + } + + return $this->select; + } + + public function getJavaScript(): string { + return ' + var filter_select = document.getElementById("'.$this->field->getName().'"); + + filter_select.addOption('.json_encode(['label' => _('Select widget'), 'value' => '-1']).'); + filter_select.selectedIndex = 0; + + ZABBIX.Dashboard.getSelectedDashboardPage().getWidgets().forEach((widget) => { + if (widget.getType() === "'.$this->field->getSearchByValue().'") { + const widget_reference = widget.getFields().reference; + filter_select.addOption({label: widget.getHeaderName(), value: widget_reference}); + if (widget_reference === "'.$this->field->getValue().'") { + filter_select.value = "'.$this->field->getValue().'"; + } + } + }); + '; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetFormView.php b/ui/include/classes/html/widgets/CWidgetFormView.php new file mode 100755 index 00000000000..d85d6c74f80 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetFormView.php @@ -0,0 +1,281 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Zabbix\Widgets\CWidgetField; + +class CWidgetFormView { + + private array $data; + private string $name; + + private array $vars = []; + private array $javascript = []; + private array $templates = []; + + private CFormGrid $form_grid; + + public function __construct($data, $name = 'widget_dialogue_form') { + $this->data = $data; + $this->name = $name; + + $this->makeFormGrid(); + } + + /** + * Add configuration row with single label and multiple CWidgetFieldView-s as content. + * + * @param array|string|null $label + * @param array $items + * @param string|null $row_class + * + * @return $this + */ + public function addFieldsGroup($label, array $items, string $row_class = null): self { + foreach ($items as &$item) { + if ($item instanceof CWidgetFieldView) { + $item = $this->makeField($item); + } + } + unset($item); + + $this->form_grid->addItem([ + $label !== null + ? (new CLabel($label)) + ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP_LABEL) + ->addClass($row_class) + : null, + (new CDiv($items)) + ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP) + ->addClass($row_class) + ]); + + return $this; + } + + /** + * Add configuration row based on single CWidgetFieldView. + * + * @param CWidgetFieldView|null $field_view + * @param string|null $row_class + * @param bool $show_label + * + * @return $this + */ + public function addField(?CWidgetFieldView $field_view, string $row_class = null, bool $show_label = true): self { + if ($field_view !== null) { + $this->registerFieldView($field_view); + + $this->form_grid->addItem($this->makeField($field_view, $row_class, $show_label)); + } + + return $this; + } + + /** + * Prepare CWidgetFieldView for addFieldGroup() items array in default view or by custom CHTML. + * + * @param CWidgetFieldView $field_view + * @param array $items + * @param string|null $row_class + * + * @return array Label and field views taken from field object or $items array if not empty. + */ + public function makeCustomField(CWidgetFieldView $field_view, array $items = [], string $row_class = null): array { + $this->registerFieldView($field_view); + + return $items ?: $this->makeField($field_view, $row_class); + } + + public function addItem($value): self { + $this->form_grid->addItem($value); + + return $this; + } + + public function addVar(string $name, string $value): self { + $this->vars[] = (new CVar($name, $value))->removeId(); + + return $this; + } + + public function addFieldVar(?CWidgetField $field): self { + if ($field !== null) { + $this->vars[] = new CVar($field->getName(), $field->getValue()); + } + + return $this; + } + + public function addJavaScript(string $javascript): self { + $this->javascript[] = $javascript; + + return $this; + } + + public function includeJsFile(string $file_path): self { + $view = APP::View(); + + if ($view !== null) { + ob_start(); + + if ((include $view->getDirectory().'/'.$file_path) === false) { + ob_end_clean(); + + throw new RuntimeException(sprintf('Cannot read file: "%s".', $file_path)); + } + + $this->javascript[] = ob_get_clean(); + } + + + return $this; + } + + /** + * @throws JsonException + */ + public function show(): void { + $output = [ + 'header' => $this->data['unique_id'] !== null ? _('Edit widget') : _('Add widget'), + 'body' => implode('', [ + (new CForm()) + ->cleanItems() + ->setId('widget-dialogue-form') + ->setName($this->name) + ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FORM) + ->addClass('dashboard-widget-'.$this->data['type']) + ->addItem($this->vars) + ->addItem($this->form_grid) + // Submit button is needed to enable submit event on Enter on inputs. + ->addItem((new CInput('submit', 'dashboard_widget_config_submit'))->addStyle('display: none;')), + implode('', $this->templates), + $this->javascript ? new CScriptTag($this->javascript) : '' + ]), + 'buttons' => [ + [ + 'title' => $this->data['unique_id'] !== null ? _('Apply') : _('Add'), + 'class' => 'dialogue-widget-save', + 'keepOpen' => true, + 'isSubmit' => true, + 'action' => 'ZABBIX.Dashboard.applyWidgetProperties();' + ] + ], + 'doc_url' => CDocHelper::getUrl(CDocHelper::DASHBOARDS_WIDGET_EDIT), + 'data' => [ + 'original_properties' => [ + 'type' => $this->data['type'], + 'unique_id' => $this->data['unique_id'], + 'dashboard_page_unique_id' => $this->data['dashboard_page_unique_id'] + ] + ] + ]; + + if ($error = get_and_clear_messages()) { + $output['error'] = [ + 'messages' => array_column($error, 'message') + ]; + } + + if ($this->data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { + CProfiler::getInstance()->stop(); + $output['debug'] = CProfiler::getInstance()->make()->toString(); + } + + echo json_encode($output, JSON_THROW_ON_ERROR); + } + + private function addTemplate(?CTemplateTag $template): void { + if ($template !== null) { + $this->templates[$template->getId()] = $template; + } + } + + private function registerFieldView(CWidgetFieldView $field_view): void { + $field_view->setFormName($this->name); + + $this->addJavaScript($field_view->getJavaScript()); + + foreach ($field_view->getTemplates() as $template) { + $this->addTemplate($template); + } + } + + private function makeFormGrid(): void { + $types_select = (new CSelect('type')) + ->setFocusableElementId('label-type') + ->setId('type') + ->setValue($this->data['type']) + ->setAttribute('autofocus', 'autofocus') + ->addOptions(CSelect::createOptionsFromArray($this->data['known_types'])) + ->addStyle('max-width: '.ZBX_TEXTAREA_MEDIUM_WIDTH.'px'); + + if ($this->data['deprecated_types']) { + $types_select->addOptionGroup( + (new CSelectOptionGroup(_('Deprecated'))) + ->addOptions(CSelect::createOptionsFromArray($this->data['deprecated_types'])) + ); + } + + $this->form_grid = (new CFormGrid()) + ->addItem([ + new CLabel(_('Type'), 'label-type'), + new CFormField(array_key_exists($this->data['type'], $this->data['deprecated_types']) + ? [$types_select, ' ', makeWarningIcon(_('Widget is deprecated.'))] + : $types_select + ) + ]) + ->addItem( + (new CFormField( + (new CCheckBox('show_header')) + ->setLabel(_('Show header')) + ->setLabelPosition(CCheckBox::LABEL_POSITION_LEFT) + ->setId('show_header') + ->setChecked($this->data['view_mode'] == ZBX_WIDGET_VIEW_MODE_NORMAL) + ))->addClass('form-field-show-header') + ) + ->addItem([ + new CLabel(_('Name'), 'name'), + new CFormField( + (new CTextBox('name', $this->data['name'])) + ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ->setAttribute('placeholder', _('default')) + ) + ]); + + if (array_key_exists('rf_rate', $this->data['fields'])) { + $this->addField(new CWidgetFieldSelectView($this->data['fields']['rf_rate'])); + } + } + + private function makeField(CWidgetFieldView $field_view, string $row_class = null, bool $show_label = true): array { + $label = $show_label ? $field_view->getLabel() : null; + + return [ + $label !== null + ? $label + ->addClass($row_class) + ->setAsteriskMark($field_view->isRequired()) + : null, + (new CFormField($field_view->getView())) + ->addClass($row_class) + ]; + } +} diff --git a/ui/include/classes/html/widgets/CWidgetView.php b/ui/include/classes/html/widgets/CWidgetView.php new file mode 100755 index 00000000000..33f09802990 --- /dev/null +++ b/ui/include/classes/html/widgets/CWidgetView.php @@ -0,0 +1,69 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +class CWidgetView extends CObject { + + private array $data; + + private array $vars = []; + + public function __construct($data) { + parent::__construct(); + + $this->data = $data; + } + + public function setVar(string $name, $value): self { + $this->vars[$name] = $value; + + return $this; + } + + /** + * @throws JsonException + */ + public function show($destroy = true): void { + $output = []; + + if (array_key_exists('name', $this->data)) { + $output['name'] = $this->data['name']; + } + + if ($this->items) { + $output['body'] = implode('', $this->items); + } + + foreach ($this->vars as $name => $value) { + $output[$name] = $value; + } + + if ($messages = get_and_clear_messages()) { + $output['messages'] = array_column($messages, 'message'); + } + + if (array_key_exists('user', $this->data) && $this->data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { + CProfiler::getInstance()->stop(); + $output['debug'] = CProfiler::getInstance()->make()->toString(); + } + + echo json_encode($output, JSON_THROW_ON_ERROR); + } +} diff --git a/ui/include/classes/import/converters/C62ImportConverter.php b/ui/include/classes/import/converters/C62ImportConverter.php index 1a79ace08ff..19bb2ccf11d 100644 --- a/ui/include/classes/import/converters/C62ImportConverter.php +++ b/ui/include/classes/import/converters/C62ImportConverter.php @@ -24,6 +24,15 @@ */ class C62ImportConverter extends CConverter { + private const DASHBOARD_WIDGET_TYPE = [ + CXmlConstantName::DASHBOARD_WIDGET_TYPE_CLOCK => CXmlConstantValue::DASHBOARD_WIDGET_TYPE_CLOCK, + CXmlConstantName::DASHBOARD_WIDGET_TYPE_GRAPH_CLASSIC => CXmlConstantValue::DASHBOARD_WIDGET_TYPE_GRAPH_CLASSIC, + CXmlConstantName::DASHBOARD_WIDGET_TYPE_GRAPH_PROTOTYPE => CXmlConstantValue::DASHBOARD_WIDGET_TYPE_GRAPH_PROTOTYPE, + CXmlConstantName::DASHBOARD_WIDGET_TYPE_ITEM => CXmlConstantValue::DASHBOARD_WIDGET_TYPE_ITEM, + CXmlConstantName::DASHBOARD_WIDGET_TYPE_PLAIN_TEXT => CXmlConstantValue::DASHBOARD_WIDGET_TYPE_PLAIN_TEXT, + CXmlConstantName::DASHBOARD_WIDGET_TYPE_URL => CXmlConstantValue::DASHBOARD_WIDGET_TYPE_URL + ]; + /** * Convert import data from 6.2 to 6.4 version. * @@ -75,6 +84,10 @@ class C62ImportConverter extends CConverter { if (array_key_exists('discovery_rules', $template)) { $template['discovery_rules'] = self::convertDiscoveryRules($template['discovery_rules']); } + + if (array_key_exists('dashboards', $template)) { + $template['dashboards'] = self::convertDashboards($template['dashboards']); + } } unset($template); @@ -116,4 +129,34 @@ class C62ImportConverter extends CConverter { return $item_prototypes; } + + /** + * Convert dashboards. + * + * @param array $dashboards + * + * @return array + */ + private static function convertDashboards(array $dashboards): array { + foreach ($dashboards as &$dashboard) { + if (!array_key_exists('pages', $dashboard)) { + continue; + } + + foreach ($dashboard['pages'] as &$dashboard_page) { + if (!array_key_exists('widgets', $dashboard_page)) { + continue; + } + + foreach ($dashboard_page['widgets'] as &$widget) { + $widget['type'] = self::DASHBOARD_WIDGET_TYPE[$widget['type']]; + } + unset($widget); + } + unset($dashboard_page); + } + unset($dashboard); + + return $dashboards; + } } diff --git a/ui/include/classes/import/converters/CImportConverterFactory.php b/ui/include/classes/import/converters/CImportConverterFactory.php index 97e693ff11c..a4a88562064 100644 --- a/ui/include/classes/import/converters/CImportConverterFactory.php +++ b/ui/include/classes/import/converters/CImportConverterFactory.php @@ -22,23 +22,29 @@ /** * Factory for creating import conversions. */ -class CImportConverterFactory extends CRegistryFactory { +final class CImportConverterFactory extends CRegistryFactory { + + private const SEQUENTIAL_CONVERTERS = [ + '1.0' => 'C10ImportConverter', + '2.0' => 'C20ImportConverter', + '3.0' => 'C30ImportConverter', + '3.2' => 'C32ImportConverter', + '3.4' => 'C34ImportConverter', + '4.0' => 'C40ImportConverter', + '4.2' => 'C42ImportConverter', + '4.4' => 'C44ImportConverter', + '5.0' => 'C50ImportConverter', + '5.2' => 'C52ImportConverter', + '5.4' => 'C54ImportConverter', + '6.0' => 'C60ImportConverter', + '6.2' => 'C62ImportConverter' + ]; public function __construct() { - parent::__construct([ - '1.0' => 'C10ImportConverter', - '2.0' => 'C20ImportConverter', - '3.0' => 'C30ImportConverter', - '3.2' => 'C32ImportConverter', - '3.4' => 'C34ImportConverter', - '4.0' => 'C40ImportConverter', - '4.2' => 'C42ImportConverter', - '4.4' => 'C44ImportConverter', - '5.0' => 'C50ImportConverter', - '5.2' => 'C52ImportConverter', - '5.4' => 'C54ImportConverter', - '6.0' => 'C60ImportConverter', - '6.2' => 'C62ImportConverter' - ]); + parent::__construct(self::SEQUENTIAL_CONVERTERS); + } + + public static function getSequentialVersions() { + return array_keys(self::SEQUENTIAL_CONVERTERS); } } diff --git a/ui/include/classes/import/validators/C64XmlValidator.php b/ui/include/classes/import/validators/C64XmlValidator.php index 4b385810d3e..625fe8cb1e1 100644 --- a/ui/include/classes/import/validators/C64XmlValidator.php +++ b/ui/include/classes/import/validators/C64XmlValidator.php @@ -374,15 +374,6 @@ class C64XmlValidator extends CXmlValidatorGeneral { CXmlConstantValue::CUSTOM_INTERFACES_YES => CXmlConstantName::YES ]; - private $DASHBOARD_WIDGET_TYPE = [ - CXmlConstantValue::DASHBOARD_WIDGET_TYPE_CLOCK => CXmlConstantName::DASHBOARD_WIDGET_TYPE_CLOCK, - CXmlConstantValue::DASHBOARD_WIDGET_TYPE_GRAPH_CLASSIC => CXmlConstantName::DASHBOARD_WIDGET_TYPE_GRAPH_CLASSIC, - CXmlConstantValue::DASHBOARD_WIDGET_TYPE_GRAPH_PROTOTYPE => CXmlConstantName::DASHBOARD_WIDGET_TYPE_GRAPH_PROTOTYPE, - CXmlConstantValue::DASHBOARD_WIDGET_TYPE_ITEM => CXmlConstantName::DASHBOARD_WIDGET_TYPE_ITEM, - CXmlConstantValue::DASHBOARD_WIDGET_TYPE_PLAIN_TEXT => CXmlConstantName::DASHBOARD_WIDGET_TYPE_PLAIN_TEXT, - CXmlConstantValue::DASHBOARD_WIDGET_TYPE_URL => CXmlConstantName::DASHBOARD_WIDGET_TYPE_URL - ]; - private $DASHBOARD_WIDGET_FIELD_TYPE = [ CXmlConstantValue::DASHBOARD_WIDGET_FIELD_TYPE_INTEGER => CXmlConstantName::DASHBOARD_WIDGET_FIELD_TYPE_INTEGER, CXmlConstantValue::DASHBOARD_WIDGET_FIELD_TYPE_STRING => CXmlConstantName::DASHBOARD_WIDGET_FIELD_TYPE_STRING, @@ -1745,7 +1736,7 @@ class C64XmlValidator extends CXmlValidatorGeneral { 'display_period' => ['type' => XML_STRING, 'default' => '0'], 'widgets' => ['type' => XML_INDEXED_ARRAY, 'prefix' => 'widget', 'rules' => [ 'widget' => ['type' => XML_ARRAY, 'rules' => [ - 'type' => ['type' => XML_STRING | XML_REQUIRED, 'in' => $this->DASHBOARD_WIDGET_TYPE], + 'type' => ['type' => XML_STRING | XML_REQUIRED], 'name' => ['type' => XML_STRING, 'default' => ''], 'x' => ['type' => XML_STRING, 'default' => '0'], 'y' => ['type' => XML_STRING, 'default' => '0'], diff --git a/ui/include/classes/mvc/CControllerResponse.php b/ui/include/classes/mvc/CControllerResponse.php index ddb418c6327..90559fed541 100644 --- a/ui/include/classes/mvc/CControllerResponse.php +++ b/ui/include/classes/mvc/CControllerResponse.php @@ -39,7 +39,7 @@ abstract class CControllerResponse { CMessageHelper::restoreScheduleMessages(); } - (new CPageHeader(_('Loading...'), CWebUser::getLang()))->display(); + (new CHtmlPageHeader(_('Loading...'), CWebUser::getLang()))->show(); echo '<body>'; diff --git a/ui/include/classes/mvc/CRouter.php b/ui/include/classes/mvc/CRouter.php index 4f444971dbe..c9a5f96d0bb 100644 --- a/ui/include/classes/mvc/CRouter.php +++ b/ui/include/classes/mvc/CRouter.php @@ -22,38 +22,28 @@ class CRouter { /** * Layout used for view rendering. - * - * @var string */ - private $layout = null; + private ?string $layout = null; /** * Controller class for action handling. - * - * @var string */ - private $controller = null; + private ?string $controller = null; /** * View used to generate HTML, CSV, JSON and other content. - * - * @var string */ - private $view = null; + private ?string $view = null; /** * Unique action (request) identifier. - * - * @var string */ - private $action = null; + private ?string $action = null; /** * Mapping between action and corresponding controller, layout and view. - * - * @var array */ - private $routes = [ + private array $routes = [ // action controller layout view 'action.operation.get' => ['CControllerActionOperationGet', 'layout.json', null], 'action.operation.validate' => ['CControllerActionOperationValidate', 'layout.json', null], @@ -74,6 +64,7 @@ class CRouter { 'correlation.enable' => ['CControllerCorrelationEnable', null, null], 'correlation.list' => ['CControllerCorrelationList', 'layout.htmlpage', 'configuration.correlation.list'], 'correlation.update' => ['CControllerCorrelationUpdate', null, null], + 'dashboard.configuration.hash.get' => ['CControllerDashboardConfigurationHashGet', 'layout.json', null], 'dashboard.delete' => ['CControllerDashboardDelete', null, null], 'dashboard.list' => ['CControllerDashboardList', 'layout.htmlpage', 'monitoring.dashboard.list'], 'dashboard.page.properties.check' => ['CControllerDashboardPagePropertiesCheck', 'layout.json', null], @@ -85,8 +76,6 @@ class CRouter { 'dashboard.update' => ['CControllerDashboardUpdate', 'layout.json', null], 'dashboard.view' => ['CControllerDashboardView', 'layout.htmlpage', 'monitoring.dashboard.view'], 'dashboard.widget.check' => ['CControllerDashboardWidgetCheck', 'layout.json', null], - 'dashboard.widget.configure' => ['CControllerDashboardWidgetConfigure', 'layout.json', null], - 'dashboard.widget.edit' => ['CControllerDashboardWidgetEdit', 'layout.json', 'monitoring.dashboard.widget.edit'], 'dashboard.widget.rfrate' => ['CControllerDashboardWidgetRfRate', 'layout.json', null], 'dashboard.widgets.sanitize' => ['CControllerDashboardWidgetsSanitize', 'layout.json', null], 'discovery.create' => ['CControllerDiscoveryCreate', null, null], @@ -102,8 +91,8 @@ class CRouter { 'export.sysmaps' => ['CControllerExport', 'layout.export', null], 'export.templates' => ['CControllerExport', 'layout.export', null], 'export.valuemaps' => ['CControllerExport', 'layout.export', null], - 'favourite.create' => ['CControllerFavouriteCreate', 'layout.javascript', null], - 'favourite.delete' => ['CControllerFavouriteDelete', 'layout.javascript', null], + 'favorite.create' => ['CControllerFavoriteCreate', 'layout.javascript', null], + 'favorite.delete' => ['CControllerFavoriteDelete', 'layout.javascript', null], 'geomaps.edit' => ['CControllerGeomapsEdit', 'layout.htmlpage', 'administration.geomaps.edit'], 'geomaps.update' => ['CControllerGeomapsUpdate', null, null], 'gui.edit' => ['CControllerGuiEdit', 'layout.htmlpage', 'administration.gui.edit'], @@ -217,7 +206,6 @@ class CRouter { 'popup.testtriggerexpr' => ['CControllerPopupTestTriggerExpr', 'layout.json', 'popup.testtriggerexpr'], 'popup.token.edit' => ['CControllerPopupTokenEdit', 'layout.json', 'popup.token.edit'], 'popup.token.view' => ['CControllerPopupTokenView', 'layout.json', 'popup.token.view'], - 'popup.tophosts.column.edit' => ['CControllerPopupTopHostsColumnEdit', 'layout.json', 'popup.tophosts.column.edit'], 'popup.triggerexpr' => ['CControllerPopupTriggerExpr', 'layout.json', 'popup.triggerexpr'], 'popup.valuemap.edit' => ['CControllerPopupValueMapEdit', 'layout.json', 'popup.valuemap.edit'], 'popup.valuemap.update' => ['CControllerPopupValueMapUpdate', 'layout.json', null], @@ -315,32 +303,6 @@ class CRouter { 'userrole.list' => ['CControllerUserroleList', 'layout.htmlpage', 'administration.userrole.list'], 'userrole.update' => ['CControllerUserroleUpdate', null, null], 'web.view' => ['CControllerWebView', 'layout.htmlpage', 'monitoring.web.view'], - 'widget.actionlog.view' => ['CControllerWidgetActionLogView', 'layout.widget', 'monitoring.widget.actionlog.view'], - 'widget.clock.view' => ['CControllerWidgetClockView', 'layout.widget', 'monitoring.widget.clock.view'], - 'widget.dataover.view' => ['CControllerWidgetDataOverView', 'layout.widget', 'monitoring.widget.dataover.view'], - 'widget.discovery.view' => ['CControllerWidgetDiscoveryView', 'layout.widget', 'monitoring.widget.discovery.view'], - 'widget.favgraphs.view' => ['CControllerWidgetFavGraphsView', 'layout.widget', 'monitoring.widget.favgraphs.view'], - 'widget.favmaps.view' => ['CControllerWidgetFavMapsView', 'layout.widget', 'monitoring.widget.favmaps.view'], - 'widget.geomap.view' => ['CControllerWidgetGeoMapView', 'layout.widget', 'monitoring.widget.geomap.view'], - 'widget.graph.view' => ['CControllerWidgetGraphView', 'layout.widget', 'monitoring.widget.graph.view'], - 'widget.graphprototype.view' => ['CControllerWidgetIteratorGraphPrototypeView', 'layout.json', null], - 'widget.hostavail.view' => ['CControllerWidgetHostAvailView', 'layout.widget', 'monitoring.widget.hostavail.view'], - 'widget.item.view' => ['CControllerWidgetItemView', 'layout.widget', 'monitoring.widget.item.view'], - 'widget.map.view' => ['CControllerWidgetMapView', 'layout.widget', 'monitoring.widget.map.view'], - 'widget.navtree.item.edit' => ['CControllerWidgetNavTreeItemEdit', 'layout.json', 'monitoring.widget.navtreeitem.edit'], - 'widget.navtree.item.update' => ['CControllerWidgetNavTreeItemUpdate', 'layout.json', null], - 'widget.navtree.view' => ['CControllerWidgetNavTreeView', 'layout.widget', 'monitoring.widget.navtree.view'], - 'widget.plaintext.view' => ['CControllerWidgetPlainTextView', 'layout.widget', 'monitoring.widget.plaintext.view'], - 'widget.problemhosts.view' => ['CControllerWidgetProblemHostsView', 'layout.widget', 'monitoring.widget.problemhosts.view'], - 'widget.problems.view' => ['CControllerWidgetProblemsView', 'layout.widget', 'monitoring.widget.problems.view'], - 'widget.problemsbysv.view' => ['CControllerWidgetProblemsBySvView', 'layout.widget', 'monitoring.widget.problemsbysv.view'], - 'widget.slareport.view' => ['CControllerWidgetSlaReportView', 'layout.widget', 'monitoring.widget.slareport.view'], - 'widget.svggraph.view' => ['CControllerWidgetSvgGraphView', 'layout.widget', 'monitoring.widget.svggraph.view'], - 'widget.systeminfo.view' => ['CControllerWidgetSystemInfoView', 'layout.widget', 'monitoring.widget.systeminfo.view'], - 'widget.tophosts.view' => ['CControllerWidgetTopHostsView', 'layout.widget', 'monitoring.widget.tophosts.view'], - 'widget.trigover.view' => ['CControllerWidgetTrigOverView', 'layout.widget', 'monitoring.widget.trigover.view'], - 'widget.url.view' => ['CControllerWidgetUrlView', 'layout.widget', 'monitoring.widget.url.view'], - 'widget.web.view' => ['CControllerWidgetWebView', 'layout.widget', 'monitoring.widget.web.view'], // legacy actions 'actionconf.php' => ['CLegacyAction', null, null], @@ -381,6 +343,13 @@ class CRouter { 'triggers.php' => ['CLegacyAction', null, null] ]; + private const DASHBOARD_ACTIONS = [ + 'dashboard.print', + 'dashboard.view', + 'host.dashboard.view', + 'template.dashboard.edit' + ]; + /** * Add new actions (potentially overwriting the existing ones). * @@ -420,39 +389,23 @@ class CRouter { } } - /** - * Returns layout name. - * - * @return string|null - */ public function getLayout(): ?string { return $this->layout; } - /** - * Returns controller name. - * - * @return string|null - */ public function getController(): ?string { return $this->controller; } - /** - * Returns view name. - * - * @return string|null - */ public function getView(): ?string { return $this->view; } - /** - * Returns action name. - * - * @return string|null - */ public function getAction(): ?string { return $this->action; } + + public static function isDashboardAction(string $action): bool { + return in_array($action, self::DASHBOARD_ACTIONS, true); + } } diff --git a/ui/include/classes/mvc/CView.php b/ui/include/classes/mvc/CView.php index 92f0a769c16..89dfaef5093 100644 --- a/ui/include/classes/mvc/CView.php +++ b/ui/include/classes/mvc/CView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -26,61 +26,45 @@ class CView { /** * Directory list of MVC views ordered by search priority. - * - * @static - * - * @var array */ - private static $directories = ['local/app/views', 'app/views', 'include/views']; + private static array $directories = ['local/app/views', 'app/views', 'include/views']; /** * Indicates support of web layout modes. - * - * @var boolean */ - private $layout_modes_enabled = false; + private bool $layout_modes_enabled = false; /** * Explicitly set layout mode. - * - * @var int */ - private $layout_mode; + private ?int $layout_mode = null; /** - * View name. - * - * @var string + * Directory where the view file was found. */ - private $name; + private ?string $directory = null; + + private string $assets_path = 'assets'; /** - * Data provided for view. - * - * @var array + * View name. */ - private $data; + private string $name; /** - * Directory where the view file was found. - * - * @var string + * List of JavaScript files for inclusion into HTML page using <script src="...">. */ - private $directory; + private array $js_files = []; /** - * List of JavaScript files for inclusion into a HTML page using <script src="...">. - * - * @var array + * List of CSS files for inclusion into HTML page using <link rel="stylesheet" type="text/css" src="...">. */ - private $js_files = []; + private array $css_files = []; /** - * List of CSS files for inclusion into a HTML page using <link rel="stylesheet" type="text/css" src="...">. - * - * @var array + * Data provided for view. */ - private $css_files = []; + private array $data; /** * Create a view based on view name and data. @@ -91,7 +75,7 @@ class CView { * @throws InvalidArgumentException if view name not valid. * @throws RuntimeException if view not found or not readable. */ - public function __construct($name, array $data = []) { + public function __construct(string $name, array $data = []) { if (!preg_match('/^[a-z]+(\/[a-z]+)*(\.[a-z]+)*$/', $name)) { throw new InvalidArgumentException(sprintf('Invalid view name: "%s".', $name)); } @@ -100,6 +84,7 @@ class CView { foreach (self::$directories as $directory) { $file_path = $directory.'/'.$name.'.php'; + if (is_file($file_path)) { $this->directory = $directory; break; @@ -118,15 +103,27 @@ class CView { $this->data = $data; } + public function getDirectory(): string { + return $this->directory; + } + + public function setAssetsPath(string $asset_path): self { + $this->assets_path = $asset_path; + + return $this; + } + + public function getAssetsPath(): string { + RETURN $this->assets_path; + } + /** * Render view and return the output. * Note: view should only output textual content like HTML, JSON, scripts or similar. * * @throws RuntimeException if view not found, not readable or returned false. - * - * @return string */ - public function getOutput() { + public function getOutput(): string { $data = $this->data; $file_path = $this->directory.'/'.$this->name.'.php'; @@ -148,17 +145,15 @@ class CView { * - JavaScript file will be searched in the "js" subdirectory of the view file. * - A copy of $data variable will be available for using within the file. * - * @param string $file_name - * @param array $data - * - * @throws RuntimeException if the file not found, not readable or returned false. + * @param string $file_name + * @param array|null $data * * @return string */ - public function readJsFile(string $file_name, ?array $data = null): string { - $data = ($data === null) ? $this->data : $data; + public function readJsFile(string $file_name, array $data = null, $relative_dir = '/js'): string { + $data = $data ?? $this->data; - $file_path = $this->directory.'/js/'.$file_name; + $file_path = $this->directory.$relative_dir.'/'.$file_name; ob_start(); @@ -177,40 +172,37 @@ class CView { * - JavaScript file will be searched in the "js" subdirectory of the view file. * - A copy of $data variable will be available for using within the file. * - * @param string $file_name - * @param array $data - * * @throws RuntimeException if the file not found, not readable or returned false. */ - public function includeJsFile(string $file_name, array $data = null) { + public function includeJsFile(string $file_name, array $data = null): self { echo $this->readJsFile($file_name, $data); + + return $this; } /** * Add a native JavaScript file to this view. - * - * @param string $src */ - public function addJsFile($src) { - $this->js_files[] = $src; + public function addJsFile(string $js): self { + $this->js_files[] = $js; + + return $this; } /** * Get list of native JavaScript files added to this view. - * - * @return array */ - public function getJsFiles() { + public function getJsFiles(): array { return $this->js_files; } /** * Add a CSS file to this view. - * - * @param string $src */ - public function addCssFile($src) { - $this->css_files[] = $src; + public function addCssFile($css): self { + $this->css_files[] = $css; + + return $this; } /** @@ -218,15 +210,17 @@ class CView { * * @return array */ - public function getCssFiles() { + public function getCssFiles(): array { return $this->css_files; } /** * Enable support of web layout modes. */ - public function enableLayoutModes() { + public function enableLayoutModes(): self { $this->layout_modes_enabled = true; + + return $this; } /** @@ -234,8 +228,10 @@ class CView { * * @param int $layout_mode ZBX_LAYOUT_NORMAL | ZBX_LAYOUT_KIOSKMODE */ - public function setLayoutMode(int $layout_mode): void { + public function setLayoutMode(int $layout_mode): self { $this->layout_mode = $layout_mode; + + return $this; } /** @@ -243,9 +239,9 @@ class CView { * * @return int ZBX_LAYOUT_NORMAL | ZBX_LAYOUT_KIOSKMODE */ - public function getLayoutMode() { + public function getLayoutMode(): int { if ($this->layout_modes_enabled) { - return ($this->layout_mode !== null) ? $this->layout_mode : CViewHelper::loadLayoutMode(); + return $this->layout_mode ?? CViewHelper::loadLayoutMode(); } return ZBX_LAYOUT_NORMAL; @@ -253,11 +249,9 @@ class CView { /** * Register custom directory of MVC views. The last registered will have the first priority. - * - * @param string $directory */ - public static function registerDirectory($directory) { - if (!in_array($directory, self::$directories)) { + public static function registerDirectory(string $directory): void { + if (!in_array($directory, self::$directories, true)) { array_unshift(self::$directories, $directory); } } diff --git a/ui/include/classes/setup/CSetupWizard.php b/ui/include/classes/setup/CSetupWizard.php index 97fb1b9eb19..6216713e257 100644 --- a/ui/include/classes/setup/CSetupWizard.php +++ b/ui/include/classes/setup/CSetupWizard.php @@ -320,7 +320,7 @@ class CSetupWizard extends CForm { // make zabbix.conf.php downloadable header('Content-Type: application/x-httpd-php'); header('Content-Disposition: attachment; filename="'.basename(CConfigFile::CONFIG_FILE_PATH).'"'); - $config = new CConfigFile(APP::getInstance()->getRootDir().CConfigFile::CONFIG_FILE_PATH); + $config = new CConfigFile(APP::getRootDir().CConfigFile::CONFIG_FILE_PATH); $config->config = [ 'DB' => [ 'TYPE' => $this->getConfig('DB_TYPE'), @@ -973,7 +973,7 @@ class CSetupWizard extends CForm { $this->setConfig('ZBX_CONFIG_FILE_CORRECT', true); - $config_file_name = APP::getInstance()->getRootDir().CConfigFile::CONFIG_FILE_PATH; + $config_file_name = APP::getRootDir().CConfigFile::CONFIG_FILE_PATH; $config = new CConfigFile($config_file_name); $config->config = [ 'DB' => [ diff --git a/ui/include/classes/widgets/CWidgetConfig.php b/ui/include/classes/widgets/CWidgetConfig.php deleted file mode 100644 index 1d37c52e602..00000000000 --- a/ui/include/classes/widgets/CWidgetConfig.php +++ /dev/null @@ -1,501 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CWidgetConfig { - - /** - * Array of deprecated widgets constants. - */ - public const DEPRECATED_WIDGETS = [ - WIDGET_DATA_OVER - ]; - - /** - * Classifier for non-template dashboards. - */ - public const CONTEXT_DASHBOARD = 'dashboard'; - - /** - * Classifier for template and host dashboards. - */ - public const CONTEXT_TEMPLATE_DASHBOARD = 'template_dashboard'; - - /** - * Get default names for all widget types. - * - * @static - * - * @param string $context CWidgetConfig::CONTEXT_DASHBOARD | CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - * - * @return array - */ - public static function getKnownWidgetTypes(string $context): array { - $types = [ - WIDGET_ACTION_LOG => _('Action log'), - WIDGET_CLOCK => _('Clock'), - WIDGET_DATA_OVER => _('Data overview'), - WIDGET_DISCOVERY => _('Discovery status'), - WIDGET_FAV_GRAPHS => _('Favorite graphs'), - WIDGET_FAV_MAPS => _('Favorite maps'), - WIDGET_GEOMAP => _('Geomap'), - WIDGET_ITEM => _('Item value'), - WIDGET_GRAPH => _('Graph (classic)'), - WIDGET_GRAPH_PROTOTYPE => _('Graph prototype'), - WIDGET_HOST_AVAIL => _('Host availability'), - WIDGET_MAP => _('Map'), - WIDGET_NAV_TREE => _('Map navigation tree'), - WIDGET_PLAIN_TEXT => _('Plain text'), - WIDGET_PROBLEM_HOSTS => _('Problem hosts'), - WIDGET_PROBLEMS => _('Problems'), - WIDGET_PROBLEMS_BY_SV => _('Problems by severity'), - WIDGET_SLA_REPORT => _('SLA report'), - WIDGET_SVG_GRAPH => _('Graph'), - WIDGET_SYSTEM_INFO => _('System information'), - WIDGET_TRIG_OVER => _('Trigger overview'), - WIDGET_URL => _('URL'), - WIDGET_WEB => _('Web monitoring'), - WIDGET_TOP_HOSTS => _('Top hosts') - ]; - - $types = array_filter($types, - function(string $type) use ($context): bool { - return self::isWidgetTypeSupportedInContext($type, $context); - }, - ARRAY_FILTER_USE_KEY - ); - - return $types; - } - - /** - * Get JavaScript classes for all widget types. - * - * @static - * - * @return array - */ - public static function getJSClasses(): array { - return [ - WIDGET_ACTION_LOG => 'CWidget', - WIDGET_CLOCK => 'CWidgetClock', - WIDGET_DATA_OVER => 'CWidget', - WIDGET_DISCOVERY => 'CWidget', - WIDGET_FAV_GRAPHS => 'CWidget', - WIDGET_FAV_MAPS => 'CWidget', - WIDGET_GEOMAP => 'CWidgetGeoMap', - WIDGET_ITEM => 'CWidgetItem', - WIDGET_GRAPH => 'CWidgetGraph', - WIDGET_GRAPH_PROTOTYPE => 'CWidgetGraphPrototype', - WIDGET_HOST_AVAIL => 'CWidget', - WIDGET_MAP => 'CWidgetMap', - WIDGET_NAV_TREE => 'CWidgetNavTree', - WIDGET_PLAIN_TEXT => 'CWidget', - WIDGET_PROBLEM_HOSTS => 'CWidget', - WIDGET_PROBLEMS => 'CWidgetProblems', - WIDGET_PROBLEMS_BY_SV => 'CWidgetProblemsBySv', - WIDGET_SLA_REPORT => 'CWidget', - WIDGET_SVG_GRAPH => 'CWidgetSvgGraph', - WIDGET_SYSTEM_INFO => 'CWidget', - WIDGET_TRIG_OVER => 'CWidgetTrigerOver', - WIDGET_URL => 'CWidget', - WIDGET_WEB => 'CWidget', - WIDGET_TOP_HOSTS => 'CWidget' - ]; - } - - /** - * Get reference field name for widgets of the given type. - * - * @static - * - * @return string|null - */ - public static function getReferenceField(string $type): ?string { - switch ($type) { - case WIDGET_MAP: - case WIDGET_NAV_TREE: - return 'reference'; - - default: - return null; - } - } - - /** - * Get foreign reference field names for widgets of the given type. - * - * @static - * - * @return array - */ - public static function getForeignReferenceFields(string $type): array { - switch ($type) { - case WIDGET_MAP: - return ['filter_widget_reference']; - - default: - return []; - } - } - - /** - * Get default widget dimensions. - * - * @static - * - * @return array - */ - private static function getDefaultDimensions(): array { - return [ - WIDGET_ACTION_LOG => ['width' => 12, 'height' => 5], - WIDGET_CLOCK => ['width' => 4, 'height' => 3], - WIDGET_DATA_OVER => ['width' => 12, 'height' => 5], - WIDGET_DISCOVERY => ['width' => 6, 'height' => 3], - WIDGET_FAV_GRAPHS => ['width' => 4, 'height' => 3], - WIDGET_FAV_MAPS => ['width' => 4, 'height' => 3], - WIDGET_GEOMAP => ['width' => 12, 'height' => 5], - WIDGET_ITEM => ['width' => 4, 'height' => 3], - WIDGET_GRAPH => ['width' => 12, 'height' => 5], - WIDGET_GRAPH_PROTOTYPE => ['width' => 16, 'height' => 5], - WIDGET_HOST_AVAIL => ['width' => 6, 'height' => 3], - WIDGET_MAP => ['width' => 18, 'height' => 5], - WIDGET_NAV_TREE => ['width' => 6, 'height' => 5], - WIDGET_PLAIN_TEXT => ['width' => 6, 'height' => 3], - WIDGET_PROBLEM_HOSTS => ['width' => 12, 'height' => 5], - WIDGET_PROBLEMS => ['width' => 12, 'height' => 5], - WIDGET_PROBLEMS_BY_SV => ['width' => 12, 'height' => 5], - WIDGET_SLA_REPORT => ['width' => 12, 'height' => 5], - WIDGET_SVG_GRAPH => ['width' => 12, 'height' => 5], - WIDGET_SYSTEM_INFO => ['width' => 12, 'height' => 5], - WIDGET_TRIG_OVER => ['width' => 12, 'height' => 5], - WIDGET_URL => ['width' => 12, 'height' => 5], - WIDGET_WEB => ['width' => 6, 'height' => 3], - WIDGET_TOP_HOSTS => ['width' => 12, 'height' => 5] - ]; - } - - /** - * Get default values for widgets. - * - * @static - * - * @param string $context CWidgetConfig::CONTEXT_DASHBOARD | CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - * - * @return array - */ - public static function getDefaults(string $context): array { - $ret = []; - - $dimensions = self::getDefaultDimensions(); - $js_clases = self::getJSClasses(); - - foreach (self::getKnownWidgetTypes($context) as $type => $name) { - $ret[$type] = [ - 'name' => $name, - 'size' => $dimensions[$type], - 'js_class' => $js_clases[$type], - 'iterator' => self::isIterator($type), - 'reference_field' => self::getReferenceField($type), - 'foreign_reference_fields' => self::getForeignReferenceFields($type) - ]; - } - - return $ret; - } - - /** - * Check if widget type is supported in a given context. - * - * @static - * - * @param string $type Widget type - 'WIDGET_*' constant. - * @param string $context CWidgetConfig::CONTEXT_DASHBOARD | CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - * - * @return bool - */ - public static function isWidgetTypeSupportedInContext(string $type, string $context): bool { - switch ($context) { - case self::CONTEXT_DASHBOARD: - return true; - - case self::CONTEXT_TEMPLATE_DASHBOARD: - switch ($type) { - case WIDGET_CLOCK: - case WIDGET_GRAPH: - case WIDGET_GRAPH_PROTOTYPE: - case WIDGET_ITEM: - case WIDGET_PLAIN_TEXT: - case WIDGET_URL: - return true; - - default: - return false; - } - } - } - - /** - * Get default refresh rate for widget type. - * - * @static - * - * @param string $type Widget type - 'WIDGET_*' constant. - * - * @return int default refresh rate, 0 for no refresh - */ - public static function getDefaultRfRate(string $type): int { - switch ($type) { - case WIDGET_ACTION_LOG: - case WIDGET_DATA_OVER: - case WIDGET_TOP_HOSTS: - case WIDGET_DISCOVERY: - case WIDGET_GEOMAP: - case WIDGET_GRAPH: - case WIDGET_GRAPH_PROTOTYPE: - case WIDGET_PLAIN_TEXT: - case WIDGET_ITEM: - case WIDGET_PROBLEM_HOSTS: - case WIDGET_PROBLEMS: - case WIDGET_PROBLEMS_BY_SV: - case WIDGET_SVG_GRAPH: - case WIDGET_TRIG_OVER: - case WIDGET_WEB: - return SEC_PER_MIN; - - case WIDGET_CLOCK: - case WIDGET_FAV_GRAPHS: - case WIDGET_FAV_MAPS: - case WIDGET_HOST_AVAIL: - case WIDGET_MAP: - case WIDGET_NAV_TREE: - case WIDGET_SYSTEM_INFO: - return 15 * SEC_PER_MIN; - - case WIDGET_SLA_REPORT: - case WIDGET_URL: - return 0; - } - } - - /** - * Get all possible widget refresh intervals. - * - * @return array - */ - public static function getRfRates() { - return [ - 0 => _('No refresh'), - SEC_PER_MIN / 6 => _n('%1$s second', '%1$s seconds', 10), - SEC_PER_MIN / 2 => _n('%1$s second', '%1$s seconds', 30), - SEC_PER_MIN => _n('%1$s minute', '%1$s minutes', 1), - SEC_PER_MIN * 2 => _n('%1$s minute', '%1$s minutes', 2), - SEC_PER_MIN * 10 => _n('%1$s minute', '%1$s minutes', 10), - SEC_PER_MIN * 15 => _n('%1$s minute', '%1$s minutes', 15) - ]; - } - - /** - * Check if time selector is necessary for widget having specified type and fields. - * - * @static - * - * @param string $type Widget type - 'WIDGET_*' constant. - * @param array $fields - * - * @return bool - */ - public static function usesTimeSelector(string $type, array $fields): bool { - switch ($type) { - case WIDGET_GRAPH: - case WIDGET_GRAPH_PROTOTYPE: - return true; - - case WIDGET_SVG_GRAPH: - return !CWidgetFormSvgGraph::hasOverrideTime($fields); - - default: - return false; - } - } - - /** - * Check if widget type belongs to iterators. - * - * @static - * - * @param string $type Widget type - 'WIDGET_*' constant. - * - * @return bool - */ - public static function isIterator(string $type): bool { - switch ($type) { - case WIDGET_GRAPH_PROTOTYPE: - return true; - - default: - return false; - } - } - - /** - * Check if widget has padding or not. - * - * @static - * - * @param string $type Widget type - 'WIDGET_*' constant. - * @param array $fields Widget form fields - * @param int $view_mode Widget view mode. ZBX_WIDGET_VIEW_MODE_NORMAL by default - * - * @return bool - */ - private static function hasPadding(string $type, array $fields, int $view_mode): bool { - if ($view_mode == ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER) { - switch ($type) { - case WIDGET_CLOCK: - return $fields['clock_type'] === WIDGET_CLOCK_TYPE_ANALOG; - - case WIDGET_GRAPH: - case WIDGET_MAP: - case WIDGET_SVG_GRAPH: - return true; - - default: - return false; - } - } - else { - switch ($type) { - case WIDGET_CLOCK: - return $fields['clock_type'] === WIDGET_CLOCK_TYPE_ANALOG; - - case WIDGET_HOST_AVAIL: - return (count($fields['interface_type']) != 1); - - case WIDGET_PROBLEMS_BY_SV: - return $fields['show_type'] != WIDGET_PROBLEMS_BY_SV_SHOW_TOTALS; - - case WIDGET_GRAPH_PROTOTYPE: - case WIDGET_ITEM: - case WIDGET_URL: - return false; - - default: - return true; - } - } - } - - /** - * Get widget configuration based on widget type, fields and current view mode. - * - * @param string $type Widget type - 'WIDGET_*' constant. - * @param array $fields Widget form fields - * @param int $view_mode Widget view mode - * - * @return array - */ - public static function getConfiguration(string $type, array $fields, int $view_mode): array { - return [ - 'padding' => self::hasPadding($type, $fields, $view_mode) - ]; - } - - /** - * Get Form object for widget with provided data. - * - * @static - * - * @param string $type Widget type - 'WIDGET_*' constant. - * @param string $data JSON string with widget fields. - * @param string|null $templateid Template ID for template dashboards or null for non-template dashboards. - * - * @return CWidgetForm - */ - public static function getForm(string $type, string $data, ?string $templateid): CWidgetForm { - switch ($type) { - case WIDGET_ACTION_LOG: - return new CWidgetFormActionLog($data, $templateid); - - case WIDGET_CLOCK: - return new CWidgetFormClock($data, $templateid); - - case WIDGET_DATA_OVER: - return new CWidgetFormDataOver($data, $templateid); - - case WIDGET_GEOMAP: - return new CWidgetFormGeoMap($data, $templateid); - - case WIDGET_GRAPH: - return new CWidgetFormGraph($data, $templateid); - - case WIDGET_GRAPH_PROTOTYPE: - return new CWidgetFormGraphPrototype($data, $templateid); - - case WIDGET_HOST_AVAIL: - return new CWidgetFormHostAvail($data, $templateid); - - case WIDGET_MAP: - return new CWidgetFormMap($data, $templateid); - - case WIDGET_NAV_TREE: - return new CWidgetFormNavTree($data, $templateid); - - case WIDGET_PLAIN_TEXT: - return new CWidgetFormPlainText($data, $templateid); - - case WIDGET_PROBLEM_HOSTS: - return new CWidgetFormProblemHosts($data, $templateid); - - case WIDGET_PROBLEMS: - return new CWidgetFormProblems($data, $templateid); - - case WIDGET_PROBLEMS_BY_SV: - return new CWidgetFormProblemsBySv($data, $templateid); - - case WIDGET_SLA_REPORT: - return new CWidgetFormSlaReport($data, $templateid); - - case WIDGET_SVG_GRAPH: - return new CWidgetFormSvgGraph($data, $templateid); - - case WIDGET_SYSTEM_INFO: - return new CWidgetFormSystemInfo($data, $templateid); - - case WIDGET_TRIG_OVER: - return new CWidgetFormTrigOver($data, $templateid); - - case WIDGET_URL: - return new CWidgetFormUrl($data, $templateid); - - case WIDGET_WEB: - return new CWidgetFormWeb($data, $templateid); - - case WIDGET_ITEM: - return new CWidgetFormItem($data, $templateid); - - case WIDGET_TOP_HOSTS: - return new CWidgetFormTopHosts($data, $templateid); - - default: - return new CWidgetForm($data, $templateid, $type); - } - } -} diff --git a/ui/include/classes/widgets/fields/CWidgetField.php b/ui/include/classes/widgets/CWidgetField.php index 8eda42f3da7..76a0444288b 100644 --- a/ui/include/classes/widgets/fields/CWidgetField.php +++ b/ui/include/classes/widgets/CWidgetField.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -18,197 +18,115 @@ ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -class CWidgetField { - const FLAG_ACKNOWLEDGES = 0x01; - const FLAG_NOT_EMPTY = 0x02; - const FLAG_LABEL_ASTERISK = 0x04; - const FLAG_DISABLED = 0x08; +namespace Zabbix\Widgets; + +use CApiInputValidator; + +abstract class CWidgetField { + + public const FLAG_ACKNOWLEDGES = 0x01; + public const FLAG_NOT_EMPTY = 0x02; + public const FLAG_LABEL_ASTERISK = 0x04; + public const FLAG_DISABLED = 0x08; + + protected string $name; + protected ?string $label; + protected ?string $full_name = null; + + protected ?int $save_type = null; - protected $name; - protected $full_name; - protected $label; protected $value; protected $default; - protected $save_type; - protected $action; - protected $validation_rules = []; - protected $strict_validation_rules = null; - protected $ex_validation_rules = []; - protected $flags; + + protected ?string $action = null; + + protected int $flags = 0x00; + + protected array $validation_rules = []; + protected ?array $strict_validation_rules = null; + protected array $ex_validation_rules = []; /** - * Create widget field (general) - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. + * @param string $name Field name in form. + * @param string|null $label Label for the field in form. */ - public function __construct($name, $label = null) { + public function __construct(string $name, string $label = null) { $this->name = $name; $this->label = $label; $this->value = null; $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->flags = 0x00; } - public function setValue($value) { - $this->value = $value; - - return $this; + public function getName(): string { + return $this->name; } - public function setDefault($value) { - $this->default = $value; - - return $this; + public function getLabel(): ?string { + return $this->label; } /** - * Set JS code that will be called on field change. - * - * @param string $action JS function to call on field change. - * - * @return $this + * Set field full name which will appear in case of error messages. For example: + * Invalid parameter "<FULL NAME>": too many decimal places. */ - public function setAction($action) { - $this->action = $action; - - return $this; - } - - protected function setSaveType($save_type) { - switch ($save_type) { - case ZBX_WIDGET_FIELD_TYPE_INT32: - $this->validation_rules = ['type' => API_INT32]; - break; - - case ZBX_WIDGET_FIELD_TYPE_STR: - $this->validation_rules = ['type' => API_STRING_UTF8, 'length' => 255]; - break; - - case ZBX_WIDGET_FIELD_TYPE_GROUP: - case ZBX_WIDGET_FIELD_TYPE_HOST: - case ZBX_WIDGET_FIELD_TYPE_ITEM: - case ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE: - case ZBX_WIDGET_FIELD_TYPE_GRAPH: - case ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE: - case ZBX_WIDGET_FIELD_TYPE_SERVICE: - case ZBX_WIDGET_FIELD_TYPE_SLA: - $this->validation_rules = ['type' => API_IDS]; - break; - - case ZBX_WIDGET_FIELD_TYPE_MAP: - $this->validation_rules = ['type' => API_ID]; - break; - - default: - exit(_('Internal error.')); - } - - $this->save_type = $save_type; + public function setFullName(string $name): self { + $this->full_name = $name; return $this; } - protected function setValidationRules(array $validation_rules) { - $this->validation_rules = $validation_rules; - } - - protected function getValidationRules() { - return $this->validation_rules; - } - - /** - * Set validation rules for "strict" mode. - * - * @param array|null $strict_validation_rules - */ - protected function setStrictValidationRules(array $strict_validation_rules = null) { - $this->strict_validation_rules = $strict_validation_rules; - } - - protected function setExValidationRules(array $ex_validation_rules) { - $this->ex_validation_rules = $ex_validation_rules; - } - /** * Get field value. If no value is set, will return default value. - * - * @return mixed */ public function getValue() { - return ($this->value === null) ? $this->default : $this->value; + return $this->value ?? $this->default; } - public function getLabel() { - return $this->label; - } + public function setValue($value): self { + $this->value = $value; - public function getName() { - return $this->name; + return $this; } - /** - * Set field full name which will appear in case of error messages. For example: - * Invalid parameter "<FULL NAME>": too many decimal places. - * - * @param string $name - * - * @return CWidgetField - */ - public function setFullName($name) { - $this->full_name = $name; + public function setDefault($value): self { + $this->default = $value; return $this; } - public function getAction() { + public function getAction(): ?string { return $this->action; } - public function getSaveType() { - return $this->save_type; + /** + * Set JS code that will be called on field change. + * + * @param string $action JS function to call on field change. + */ + public function setAction(string $action): self { + $this->action = $action; + + return $this; } /** - * Set additional flags for validation rule array. - * - * @param array $validation_rule - * @param int $flag - * + * Get additional flags, which can be used in configuration form. */ - protected static function setValidationRuleFlag(array &$validation_rule, $flag) { - if (array_key_exists('flags', $validation_rule)) { - $validation_rule['flags'] |= $flag; - } - else { - $validation_rule['flags'] = $flag; - } + public function getFlags(): int { + return $this->flags; } /** * Set additional flags, which can be used in configuration form. - * - * @param int $flags - * - * @return $this */ - public function setFlags($flags) { + public function setFlags(int $flags): self { $this->flags = $flags; return $this; } /** - * Get additional flags, which can be used in configuration form. - * - * @return int - */ - public function getFlags() { - return $this->flags; - } - - /** * @param bool $strict Widget form submit validation? * * @return array Errors. @@ -220,13 +138,14 @@ class CWidgetField { ? $this->strict_validation_rules : $this->validation_rules; $validation_rules += $this->ex_validation_rules; - $value = ($this->value === null) ? $this->default : $this->value; + + $value = $this->value ?? $this->default; if ($this->full_name !== null) { $label = $this->full_name; } else { - $label = ($this->label === null) ? $this->name : $this->label; + $label = $this->label ?? $this->name; } if (CApiInputValidator::validate($validation_rules, $value, $label, $error)) { @@ -245,9 +164,9 @@ class CWidgetField { * Reference is needed here to avoid array merging in CWidgetForm::fieldsToApi method. With large number of widget * fields it causes significant performance decrease. * - * @param array $widget_fields reference to Array of widget fields. + * @param array $widget_fields reference to Array of widget fields. */ - public function toApi(array &$widget_fields = []) { + public function toApi(array &$widget_fields = []): void { $value = $this->getValue(); if ($value !== null && $value !== $this->default) { @@ -268,4 +187,75 @@ class CWidgetField { } } } + + protected function setSaveType($save_type): self { + switch ($save_type) { + case ZBX_WIDGET_FIELD_TYPE_INT32: + $this->validation_rules = ['type' => API_INT32]; + break; + + case ZBX_WIDGET_FIELD_TYPE_STR: + $this->validation_rules = ['type' => API_STRING_UTF8, 'length' => 255]; + break; + + case ZBX_WIDGET_FIELD_TYPE_GROUP: + case ZBX_WIDGET_FIELD_TYPE_HOST: + case ZBX_WIDGET_FIELD_TYPE_ITEM: + case ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE: + case ZBX_WIDGET_FIELD_TYPE_GRAPH: + case ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE: + case ZBX_WIDGET_FIELD_TYPE_SERVICE: + case ZBX_WIDGET_FIELD_TYPE_SLA: + $this->validation_rules = ['type' => API_IDS]; + break; + + case ZBX_WIDGET_FIELD_TYPE_MAP: + $this->validation_rules = ['type' => API_ID]; + break; + + default: + exit(_('Internal error.')); + } + + $this->save_type = $save_type; + + return $this; + } + + protected function getValidationRules(): array { + return $this->validation_rules; + } + + protected function setValidationRules(array $validation_rules): self { + $this->validation_rules = $validation_rules; + + return $this; + } + + /** + * Set validation rules for "strict" mode. + */ + protected function setStrictValidationRules(array $strict_validation_rules = null): self { + $this->strict_validation_rules = $strict_validation_rules; + + return $this; + } + + protected function setExValidationRules(array $ex_validation_rules): self { + $this->ex_validation_rules = $ex_validation_rules; + + return $this; + } + + /** + * Set additional flags for validation rule array. + */ + protected static function setValidationRuleFlag(array &$validation_rule, int $flag): void { + if (array_key_exists('flags', $validation_rule)) { + $validation_rule['flags'] |= $flag; + } + else { + $validation_rule['flags'] = $flag; + } + } } diff --git a/ui/include/classes/widgets/forms/CWidgetForm.php b/ui/include/classes/widgets/CWidgetForm.php index a48a5c86d27..308a0a72645 100644 --- a/ui/include/classes/widgets/forms/CWidgetForm.php +++ b/ui/include/classes/widgets/CWidgetForm.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,76 +19,95 @@ **/ -class CWidgetForm { - - protected $fields; +namespace Zabbix\Widgets; - /** - * Widget fields array that came from AJAX request. - * - * @var array - */ - protected $data; +class CWidgetForm { - protected $templateid; + protected array $fields = []; - public function __construct($data, $templateid, $type) { - $this->data = json_decode($data, true); + protected array $values; + protected ?string $templateid; + public function __construct(array $values, ?string $templateid) { + $this->values = $this->normalizeValues($values); $this->templateid = $templateid; + } - $this->fields = []; + public function addFields(): self { + return $this; + } - if ($templateid === null) { - // Refresh interval field. - $default_rf_rate = ''; + public function addField(?CWidgetField $field): self { + if ($field !== null) { + $this->fields[$field->getName()] = $field; + } - foreach (CWidgetConfig::getRfRates() as $rf_rate => $label) { - if ($rf_rate == CWidgetConfig::getDefaultRfRate($type)) { - $default_rf_rate = $label; - break; - } - } + return $this; + } - $rf_rates = [ - -1 => _('Default').' ('.$default_rf_rate.')' - ]; - $rf_rates += CWidgetConfig::getRfRates(); + public function getFields(): array { + return $this->fields; + } - $rf_rate_field = (new CWidgetFieldSelect('rf_rate', _('Refresh interval'), $rf_rates)) - ->setDefault(-1); + public function getFieldValue(string $field_name) { + return $this->fields[$field_name]->getValue(); + } - if (array_key_exists('rf_rate', $this->data)) { - $rf_rate_field->setValue($this->data['rf_rate']); - } + public function getFieldsValues(): array { + $values = []; - $this->fields[$rf_rate_field->getName()] = $rf_rate_field; + foreach ($this->fields as $field) { + $values[$field->getName()] = $field->getValue(); } - // Add Columns and Rows fields for Iterator widgets. - - if (CWidgetConfig::isIterator($type)) { - $field_columns = (new CWidgetFieldIntegerBox('columns', _('Columns'), 1, DASHBOARD_MAX_COLUMNS)) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) - ->setDefault(2); + return $values; + } - if (array_key_exists('columns', $this->data)) { - $field_columns->setValue($this->data['columns']); + public function setFieldsValues(): self { + foreach ($this->fields as $field) { + if (array_key_exists($field->getName(), $this->values)) { + $field->setValue($this->values[$field->getName()]); } + } - $this->fields[$field_columns->getName()] = $field_columns; + return $this; + } - $field_rows = (new CWidgetFieldIntegerBox('rows', _('Rows'), 1, - floor(DASHBOARD_WIDGET_MAX_ROWS / DASHBOARD_WIDGET_MIN_ROWS))) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) - ->setDefault(1); + /** + * Validate form fields. + * + * @param bool $strict Enables more strict validation of the form fields. + * Must be enabled for validation of input parameters in the widget configuration form. + * + * @return array + */ + public function validate(bool $strict = false): array { + $errors = []; - if (array_key_exists('rows', $this->data)) { - $field_rows->setValue($this->data['rows']); - } + foreach ($this->fields as $field) { + $errors = array_merge($errors, $field->validate($strict)); + } + + return $errors; + } + + /** + * Prepares array, ready to be passed to CDashboard API functions. + * + * @return array Array of widget fields ready for saving in API. + */ + public function fieldsToApi(): array { + $api_fields = []; - $this->fields[$field_rows->getName()] = $field_rows; + foreach ($this->fields as $field) { + $field->toApi($api_fields); } + + return $api_fields; + } + + protected function normalizeValues(array $values): array { + return self::convertDottedKeys($values); } /** @@ -119,9 +138,9 @@ class CWidgetForm { * * @return array */ - protected static function convertDottedKeys(array $data) { + protected static function convertDottedKeys(array $data): array { // API doesn't guarantee fields to be retrieved in same order as stored. Sorting by key... - uksort($data, function ($key1, $key2) { + uksort($data, static function ($key1, $key2) { foreach (['key1', 'key2'] as $var) { if (preg_match('/^([a-z]+)\.([a-z_]+)\.(\d+)\.(\d+)$/', (string) $$var, $matches) === 1) { $$var = $matches[1].'.'.$matches[3].'.'.$matches[2].'.'.$matches[4]; @@ -152,62 +171,4 @@ class CWidgetForm { return $data; } - - /** - * Return fields for this form. - * - * @return array An array of CWidgetField. - */ - public function getFields() { - return $this->fields; - } - - /** - * Returns widget fields data as array. - * - * @return array Key/value pairs where key is field name and value is it's data. - */ - public function getFieldsData() { - $data = []; - - foreach ($this->fields as $field) { - /* @var $field CWidgetField */ - $data[$field->getName()] = $field->getValue(); - } - - return $data; - } - - /** - * Validate form fields. - * - * @param bool $strict Enables more strict validation of the form fields. - * Must be enabled for validation of input parameters in the widget configuration form. - * - * @return array - */ - public function validate($strict = false) { - $errors = []; - - foreach ($this->fields as $field) { - $errors = array_merge($errors, $field->validate($strict)); - } - - return $errors; - } - - /** - * Prepares array, ready to be passed to CDashboard API functions. - * - * @return array Array of widget fields ready for saving in API. - */ - public function fieldsToApi() { - $api_fields = []; - - foreach ($this->fields as $field) { - $field->toApi($api_fields); - } - - return $api_fields; - } } diff --git a/ui/include/classes/widgets/CWidgetHelper.php b/ui/include/classes/widgets/CWidgetHelper.php deleted file mode 100644 index 4336c73ac7c..00000000000 --- a/ui/include/classes/widgets/CWidgetHelper.php +++ /dev/null @@ -1,1611 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CWidgetHelper { - - public const DATASET_TYPE_SINGLE_ITEM = 0; - public const DATASET_TYPE_PATTERN_ITEM = 1; - - /** - * Create CForm for widget configuration form. - * - * @return CForm - */ - public static function createForm(): CForm { - return (new CForm('post')) - ->cleanItems() - ->setId('widget-dialogue-form') - ->setName('widget_dialogue_form') - ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FORM); - } - - /** - * Create CFormGrid for widget configuration form with default fields in it. - * - * @param string $name - * @param string $type - * @param int $view_mode ZBX_WIDGET_VIEW_MODE_NORMAL | ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER - * @param array $known_widget_types - * @param CWidgetFieldSelect|null $field_rf_rate - * - * @return CFormGrid - */ - public static function createFormGrid(string $name, string $type, int $view_mode, array $known_widget_types, - ?CWidgetFieldSelect $field_rf_rate): CFormGrid { - - $deprecated_widget_types = array_intersect_key($known_widget_types, - array_flip(CWidgetConfig::DEPRECATED_WIDGETS) - ); - - $widget_types_select = (new CSelect('type')) - ->setFocusableElementId('label-type') - ->setId('type') - ->setValue($type) - ->setAttribute('autofocus', 'autofocus') - ->addOptions(CSelect::createOptionsFromArray( - array_diff_key($known_widget_types, $deprecated_widget_types)) - ); - - if ($deprecated_widget_types) { - $widget_types_select->addOptionGroup( - (new CSelectOptionGroup(_('Deprecated'))) - ->addOptions(CSelect::createOptionsFromArray($deprecated_widget_types)) - ); - } - - return (new CFormGrid()) - ->addItem([ - new CLabel(_('Type'), 'label-type'), - new CFormField(array_key_exists($type, $deprecated_widget_types) - ? [$widget_types_select, ' ', makeWarningIcon(_('Widget is deprecated.'))] - : $widget_types_select - ) - ]) - ->addItem( - (new CFormField( - (new CCheckBox('show_header')) - ->setLabel(_('Show header')) - ->setLabelPosition(CCheckBox::LABEL_POSITION_LEFT) - ->setId('show_header') - ->setChecked($view_mode == ZBX_WIDGET_VIEW_MODE_NORMAL) - ))->addClass('form-field-show-header') - ) - ->addItem([ - new CLabel(_('Name'), 'name'), - new CFormField( - (new CTextBox('name', $name)) - ->setAttribute('placeholder', _('default')) - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) - ) - ]) - ->addItem($field_rf_rate !== null - ? [ - self::getLabel($field_rf_rate), - new CFormField(self::getSelect($field_rf_rate)) - ] - : null - ); - } - - /** - * Creates label linked to the field. - * - * @param CWidgetField $field - * @param string $class Custom CSS class for label. - * @param mixed $hint Hint box text. - * - * @return CLabel - */ - public static function getLabel($field, $class = null, $hint = null) { - $help_icon = ($hint !== null) - ? makeHelpIcon($hint) - : null; - - if ($field instanceof CWidgetFieldSelect) { - return (new CLabel([$field->getLabel(), $help_icon], 'label-'.$field->getName())) - ->setAsteriskMark(self::isAriaRequired($field)) - ->addClass($class); - } - - return (new CLabel([$field->getLabel(), $help_icon], $field->getName())) - ->setAsteriskMark(self::isAriaRequired($field)) - ->addClass($class); - } - - /** - * @param CWidgetFieldSelect $field - * - * @return CSelect - */ - public static function getSelect($field) { - return (new CSelect($field->getName())) - ->setId($field->getName()) - ->setFocusableElementId('label-'.$field->getName()) - ->setValue($field->getValue()) - ->addOptions(CSelect::createOptionsFromArray($field->getValues())) - ->setDisabled($field->getFlags() & CWidgetField::FLAG_DISABLED) - ->setAriaRequired(self::isAriaRequired($field)); - } - - /** - * @param CWidgetFieldTextArea $field - * - * @return CTextArea - */ - public static function getTextArea($field) { - return (new CTextArea($field->getName(), $field->getValue())) - ->setAriaRequired(self::isAriaRequired($field)) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setAdaptiveWidth($field->getWidth()); - } - - /** - * @param CWidgetFieldTextBox $field - * - * @return CTextBox - */ - public static function getTextBox($field) { - return (new CTextBox($field->getName(), $field->getValue())) - ->setAriaRequired(self::isAriaRequired($field)) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setAttribute('placeholder', $field->getPlaceholder()) - ->setWidth($field->getWidth()); - } - - /** - * @param CWidgetFieldLatLng $field - * - * @return CTextBox - */ - public static function getLatLngZoomBox($field) { - return (new CTextBox($field->getName(), $field->getValue())) - ->setAttribute('placeholder', $field->getPlaceholder()) - ->setWidth($field->getWidth()); - } - - /** - * @param CWidgetFieldUrl $field - * - * @return CTextBox - */ - public static function getUrlBox($field) { - return (new CTextBox($field->getName(), $field->getValue())) - ->setAriaRequired(self::isAriaRequired($field)) - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH); - } - - /** - * @param CWidgetFieldRangeControl $field - * - * @return CRangeControl - */ - public static function getRangeControl($field) { - return (new CRangeControl($field->getName(), (int) $field->getValue())) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ->setStep($field->getStep()) - ->setMin($field->getMin()) - ->setMax($field->getMax()); - } - - /** - * @param CWidgetFieldHostPatternSelect $field Widget field object. - * @param string $form_name HTML form element name. - * - * @return CPatternSelect - */ - public static function getHostPatternSelect($field, $form_name) { - return (new CPatternSelect([ - 'name' => $field->getName().'[]', - 'object_name' => 'hosts', - 'data' => $field->getValue(), - 'placeholder' => $field->getPlaceholder(), - 'wildcard_allowed' => 1, - 'popup' => [ - 'parameters' => [ - 'srctbl' => 'hosts', - 'srcfld1' => 'hostid', - 'dstfrm' => $form_name, - 'dstfld1' => zbx_formatDomId($field->getName().'[]') - ] - ], - 'add_post_js' => false - ])) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setAriaRequired(self::isAriaRequired($field)) - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH); - } - - /** - * @param CWidgetFieldCheckBox $field - * - * @return array - */ - public static function getCheckBox($field) { - return [(new CVar($field->getName(), '0'))->removeId(), (new CCheckBox($field->getName())) - ->setChecked((bool) $field->getValue()) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setLabel($field->getCaption()) - ->onChange($field->getAction()) - ]; - } - - /** - * @param CWidgetFieldColor $field - * @param bool $use_default Tell the Color picker whether to use Default color feature or not. - * - * @return CColor - */ - public static function getColor($field, $use_default = false) { - // appendColorPickerJs(false), because the script responsible for it is in widget.item.form.view. - $color_picker = (new CColor($field->getName(), $field->getValue()))->appendColorPickerJs(false); - if ($use_default) { - $color_picker->enableUseDefault(); - } - return $color_picker; - } - - /** - * Creates label linked to the multiselect field. - * - * @param CWidgetFieldMs $field - * - * @return CLabel - */ - public static function getMultiselectLabel($field) { - $field_name = $field->getName(); - - if ($field instanceof CWidgetFieldMs) { - $field_name .= ($field->isMultiple() ? '[]' : ''); - } - else { - $field_name .= '[]'; - } - - return (new CLabel($field->getLabel(), $field_name.'_ms')) - ->setAsteriskMark(self::isAriaRequired($field)); - } - - /** - * @param CWidgetFieldMs $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - private static function getMultiselectField($field, $captions, $form_name, $object_name, $popup_options) { - $field_name = $field->getName().($field->isMultiple() ? '[]' : ''); - $options = [ - 'name' => $field_name, - 'object_name' => $object_name, - 'multiple' => $field->isMultiple(), - 'data' => $captions, - 'popup' => [ - 'parameters' => [ - 'dstfrm' => $form_name, - 'dstfld1' => zbx_formatDomId($field_name) - ] + $popup_options - ], - 'add_post_js' => false - ]; - - if ($field instanceof CWidgetFieldMsHost && $field->getFilterPreselect()) { - $options['popup']['filter_preselect']['id'] = $field->getFilterPreselect(); - $options['popup']['filter_preselect']['submit_as'] = 'groupid'; - } - - return (new CMultiSelect($options)) - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)); - } - - /** - * @param CWidgetFieldMsGroup $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - public static function getGroup($field, $captions, $form_name) { - return self::getMultiselectField($field, $captions, $form_name, 'hostGroup', [ - 'srctbl' => 'host_groups', - 'srcfld1' => 'groupid', - 'real_hosts' => true, - 'enrich_parent_groups' => true - ] + $field->getFilterParameters()); - } - - /** - * @param CWidgetFieldMsHost $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - public static function getHost($field, $captions, $form_name) { - return self::getMultiselectField($field, $captions, $form_name, 'hosts', [ - 'srctbl' => 'hosts', - 'srcfld1' => 'hostid' - ] + $field->getFilterParameters()); - } - - /** - * @param CWidgetFieldMsItem $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - public static function getItem($field, $captions, $form_name) { - return self::getMultiselectField($field, $captions, $form_name, 'items', [ - 'srctbl' => 'items', - 'srcfld1' => 'itemid' - ] + $field->getFilterParameters()); - } - - /** - * @param CWidgetFieldMsGraph $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - public static function getGraph($field, $captions, $form_name) { - return self::getMultiselectField($field, $captions, $form_name, 'graphs', [ - 'srctbl' => 'graphs', - 'srcfld1' => 'graphid', - 'srcfld2' => 'name', - 'with_graphs' => true - ] + $field->getFilterParameters()); - } - - /** - * @param CWidgetFieldMsItemPrototype $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - public static function getItemPrototype($field, $captions, $form_name) { - return self::getMultiselectField($field, $captions, $form_name, 'item_prototypes', [ - 'srctbl' => 'item_prototypes', - 'srcfld1' => 'itemid' - ] + $field->getFilterParameters()); - } - - /** - * @param CWidgetFieldMsGraphPrototype $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - public static function getGraphPrototype($field, $captions, $form_name) { - return self::getMultiselectField($field, $captions, $form_name, 'graph_prototypes', [ - 'srctbl' => 'graph_prototypes', - 'srcfld1' => 'graphid', - 'srcfld2' => 'name', - 'with_graph_prototypes' => true - ] + $field->getFilterParameters()); - } - - /** - * @param CWidgetFieldMsService $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - public static function getService($field, $captions, $form_name) { - return (new CMultiSelect([ - 'name' => $field->getName().($field->isMultiple() ? '[]' : ''), - 'object_name' => 'services', - 'multiple' => $field->isMultiple(), - 'data' => $captions, - 'custom_select' => true, - 'add_post_js' => false - ])) - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)); - } - - /** - * @param CWidgetFieldMsSla $field - * @param array $captions - * @param string $form_name - * - * @return CMultiSelect - */ - public static function getSla($field, $captions, $form_name) { - return self::getMultiselectField($field, $captions, $form_name, 'sla', [ - 'srctbl' => 'sla', - 'srcfld1' => 'slaid' - ] + $field->getFilterParameters()); - } - - public static function getSelectResource($field, $caption, $form_name) { - return [ - (new CTextBox($field->getName().'_caption', $caption, true)) - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)), - (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), - (new CButton('select', _('Select'))) - ->addClass(ZBX_STYLE_BTN_GREY) - ->onClick('return PopUp("popup.generic", '.json_encode($field->getPopupOptions($form_name)).', - {dialogue_class: "modal-popup-generic"} - );') - ]; - } - - /** - * Creates select field without values, to later fill it by JS script. - * - * @param CWidgetFieldWidgetSelect $field - * - * @return CSelect - */ - public static function getEmptySelect($field) { - return (new CSelect($field->getName())) - ->setFocusableElementId('label-'.$field->getName()) - ->setId($field->getName()) - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)); - } - - /** - * @param CWidgetFieldIntegerBox $field - * - * @return CNumericBox - */ - public static function getIntegerBox(CWidgetFieldIntegerBox $field): CNumericBox { - return (new CNumericBox($field->getName(), $field->getValue(), $field->getMaxLength(), false, - ($field->getFlags() & CWidgetField::FLAG_NOT_EMPTY) == 0 - )) - ->setWidth(ZBX_TEXTAREA_NUMERIC_STANDARD_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)); - } - - /** - * @param CWidgetFieldNumericBox $field - * - * @return CTextBox - */ - public static function getNumericBox($field) { - return (new CTextBox($field->getName(), $field->getValue())) - ->setAriaRequired(self::isAriaRequired($field)) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setAttribute('placeholder', $field->getPlaceholder()) - ->setWidth($field->getWidth()); - } - - /** - * @param CWidgetFieldRadioButtonList $field - * - * @return CRadioButtonList - */ - public static function getRadioButtonList($field) { - $radio_button_list = (new CRadioButtonList($field->getName(), $field->getValue())) - ->setModern($field->getModern()) - ->setAriaRequired(self::isAriaRequired($field)); - - foreach ($field->getValues() as $key => $value) { - $radio_button_list - ->addValue($value, $key, null, $field->getAction()) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)); - } - - return $radio_button_list; - } - - /** - * @param CWidgetFieldSeverities $field - * - * @return CSeverityCheckBoxList - */ - public static function getSeverities($field) { - return (new CSeverityCheckBoxList($field->getName())) - ->setChecked($field->getValue()) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH); - } - - /** - * @param CWidgetFieldCheckBoxList $field - * @param array $list Option list array. - * @param array $class_list List of additional CSS classes. - * - * @return CList - */ - public static function getCheckBoxList($field, array $list, array $class_list = []) { - $checkbox_list = (new CList())->addClass(ZBX_STYLE_LIST_CHECK_RADIO); - if ($class_list) { - foreach ($class_list as $class) { - $checkbox_list->addClass($class); - } - } - - foreach ($list as $key => $label) { - $checkbox_list->addItem( - (new CCheckBox($field->getName().'[]', $key)) - ->setLabel($label) - ->setId($field->getName().'_'.$key) - ->setChecked(in_array($key, $field->getValue())) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ); - } - - return $checkbox_list; - } - - /** - * @param CWidgetFieldColumnsList $field Widget columns field. - * - * @return CDiv - */ - public static function getWidgetColumns(CWidgetFieldColumnsList $field) { - $columns = $field->getValue(); - $header = [ - '', - (new CColHeader(_('Name')))->addStyle('width: 39%'), - (new CColHeader(_('Data')))->addStyle('width: 59%'), - _('Action') - ]; - $row_actions = [ - (new CButton('edit', _('Edit'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->removeId(), - (new CButton('remove', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->removeId() - ]; - $table = (new CTable()) - ->setId('list_'.$field->getName()) - ->setHeader($header); - $enabled = !($field->getFlags() & CWidgetField::FLAG_DISABLED); - - foreach ($columns as $column_index => $column) { - $column_data = [new CVar('sortorder['.$field->getName().'][]', $column_index)]; - - foreach ($column as $key => $value) { - $column_data[] = new CVar($field->getName().'['.$column_index.']['.$key.']', $value); - } - - $label = array_key_exists('item', $column) ? $column['item'] : ''; - - if ($column['data'] == CWidgetFieldColumnsList::DATA_HOST_NAME) { - $label = new CTag('em', true, _('Host name')); - } - else if ($column['data'] == CWidgetFieldColumnsList::DATA_TEXT) { - $label = new CTag('em', true, $column['text']); - } - - $table->addRow((new CRow([ - (new CCol((new CDiv)->addClass(ZBX_STYLE_DRAG_ICON)))->addClass(ZBX_STYLE_TD_DRAG_ICON), - (new CDiv($column['name']))->addClass('text'), - (new CDiv($label))->addClass('text'), - (new CList(array_merge($row_actions, [$column_data])))->addClass(ZBX_STYLE_HOR_LIST) - ]))->addClass('sortable')); - } - - $table->addRow( - (new CCol( - (new CButton('add', _('Add'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->setEnabled($enabled) - ))->setColSpan(count($header)) - ); - - return $table; - } - - /** - * @param CWidgetFieldTags $field - * - * @return CTable - */ - public static function getTags($field) { - $tags = $field->getValue(); - - if (!$tags) { - $tags = [['tag' => '', 'operator' => TAG_OPERATOR_LIKE, 'value' => '']]; - } - - $tags_table = (new CTable()) - ->setId('tags_table_'.$field->getName()) - ->addClass('table-tags') - ->addClass('table-initial-width'); - - $enabled = !($field->getFlags() & CWidgetField::FLAG_DISABLED); - $i = 0; - - foreach ($tags as $tag) { - $zselect_operator = (new CSelect($field->getName().'['.$i.'][operator]')) - ->addOptions(CSelect::createOptionsFromArray([ - TAG_OPERATOR_EXISTS => _('Exists'), - TAG_OPERATOR_EQUAL => _('Equals'), - TAG_OPERATOR_LIKE => _('Contains'), - TAG_OPERATOR_NOT_EXISTS => _('Does not exist'), - TAG_OPERATOR_NOT_EQUAL => _('Does not equal'), - TAG_OPERATOR_NOT_LIKE => _('Does not contain') - ])) - ->setValue($tag['operator']) - ->setFocusableElementId($field->getName().'-'.$i.'-operator-select') - ->setId($field->getName().'_'.$i.'_operator'); - - if (!$enabled) { - $zselect_operator->setDisabled(); - } - - $tags_table->addRow([ - (new CTextBox($field->getName().'['.$i.'][tag]', $tag['tag'])) - ->setAttribute('placeholder', _('tag')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)) - ->setEnabled($enabled), - $zselect_operator, - (new CTextBox($field->getName().'['.$i.'][value]', $tag['value'])) - ->setAttribute('placeholder', _('value')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)) - ->setId($field->getName().'_'.$i.'_value') - ->setEnabled($enabled), - (new CCol( - (new CButton($field->getName().'['.$i.'][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ->setEnabled($enabled) - ))->addClass(ZBX_STYLE_NOWRAP) - ], 'form_row'); - - $i++; - } - - $tags_table->addRow( - (new CCol( - (new CButton('tags_add', _('Add'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-add') - ->setEnabled($enabled) - ))->setColSpan(3) - ); - - return $tags_table; - } - - /** - * JS Template for one tag line for Tags field - * - * @param CWidgetFieldTags $field - * - * @return string - */ - public static function getTagsTemplate($field) { - return (new CRow([ - (new CTextBox($field->getName().'[#{rowNum}][tag]')) - ->setAttribute('placeholder', _('tag')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)), - (new CSelect($field->getName().'[#{rowNum}][operator]')) - ->addOptions(CSelect::createOptionsFromArray([ - TAG_OPERATOR_EXISTS => _('Exists'), - TAG_OPERATOR_EQUAL => _('Equals'), - TAG_OPERATOR_LIKE => _('Contains'), - TAG_OPERATOR_NOT_EXISTS => _('Does not exist'), - TAG_OPERATOR_NOT_EQUAL => _('Does not equal'), - TAG_OPERATOR_NOT_LIKE => _('Does not contain') - ])) - ->setValue(TAG_OPERATOR_LIKE) - ->setFocusableElementId($field->getName().'-#{rowNum}-operator-select') - ->setId($field->getName().'_#{rowNum}_operator'), - (new CTextBox($field->getName().'[#{rowNum}][value]')) - ->setAttribute('placeholder', _('value')) - ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) - ->setAriaRequired(self::isAriaRequired($field)) - ->setId($field->getName().'_#{rowNum}_value'), - (new CCol( - (new CButton($field->getName().'[#{rowNum}][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ))->addClass(ZBX_STYLE_NOWRAP) - ])) - ->addClass('form_row') - ->toString(); - } - - /** - * @param CWidgetFieldDatePicker $field - * - * @return CDateSelector - */ - public static function getDatePicker(CWidgetFieldDatePicker $field): CDateSelector { - return (new CDateSelector($field->getName(), $field->getValue())) - ->setAriaRequired(self::isAriaRequired($field)) - ->setMaxLength(DB::getFieldLength('widget_field', 'value_str')) - ->setEnabled(($field->getFlags() & CWidgetField::FLAG_DISABLED) == 0); - } - - /** - * Function returns array containing HTML objects filled with given values. Used to generate HTML in widget - * overrides field. - * - * @param CWidgetFieldGraphOverride $field - * @param array $value Values to fill in particular data set row. See self::setValue() for - * detailed description. - * @param string $form_name Name of form in which data set fields resides. - * @param int|string $row_num Unique data set numeric identifier. Used to make unique field names. - * - * @return CListItem - */ - public static function getGraphOverrideLayout($field, array $value, $form_name, $row_num) { - $inputs = []; - - // Create override options list. - foreach (CWidgetFieldGraphOverride::getOverrideOptions() as $option) { - if (array_key_exists($option, $value)) { - $inputs[] = (new CVar($field->getName().'['.$row_num.']['.$option.']', $value[$option])); - } - } - - return (new CListItem([ - /** - * First line: host pattern field, item pattern field. - * Contains also drag and drop button and delete button. - */ - (new CDiv([ - (new CDiv()) - ->addClass(ZBX_STYLE_DRAG_ICON) - ->addStyle('position: absolute; margin-left: -25px;'), - (new CDiv([ - (new CDiv( - (new CPatternSelect([ - 'name' => $field->getName().'['.$row_num.'][hosts][]', - 'object_name' => 'hosts', - 'data' => $value['hosts'], - 'placeholder' => _('host pattern'), - 'wildcard_allowed' => 1, - 'popup' => [ - 'parameters' => [ - 'srctbl' => 'hosts', - 'srcfld1' => 'hostid', - 'dstfrm' => $form_name, - 'dstfld1' => zbx_formatDomId($field->getName().'['.$row_num.'][hosts][]') - ] - ], - 'add_post_js' => false - ])) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setAriaRequired(self::isAriaRequired($field)) - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ))->addClass(ZBX_STYLE_COLUMN_50), - (new CDiv( - (new CPatternSelect([ - 'name' => $field->getName().'['.$row_num.'][items][]', - 'object_name' => 'items', - 'data' => $value['items'], - 'placeholder' => _('item pattern'), - 'multiple' => true, - 'wildcard_allowed' => 1, - 'popup' => [ - 'parameters' => [ - 'srctbl' => 'items', - 'srcfld1' => 'itemid', - 'real_hosts' => 1, - 'numeric' => 1, - 'dstfrm' => $form_name, - 'dstfld1' => zbx_formatDomId($field->getName().'['.$row_num.'][items][]') - ] - ], - 'add_post_js' => false - ])) - ->setEnabled(!($field->getFlags() & CWidgetField::FLAG_DISABLED)) - ->setAriaRequired(self::isAriaRequired($field)) - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ))->addClass(ZBX_STYLE_COLUMN_50) - ])) - ->addClass(ZBX_STYLE_COLUMNS) - ->addClass(ZBX_STYLE_COLUMNS_NOWRAP) - ->addClass(ZBX_STYLE_COLUMN_95), - - (new CDiv( - (new CButton()) - ->setAttribute('title', _('Delete')) - ->addClass(ZBX_STYLE_BTN_REMOVE) - ->removeId() - )) - ->addClass(ZBX_STYLE_COLUMN_5) - ])) - ->addClass(ZBX_STYLE_COLUMNS), - - // Selected override options. - (new CList($inputs)) - ->addClass(ZBX_STYLE_OVERRIDES_OPTIONS_LIST) - ->addItem((new CButton(null, (new CSpan()) - ->addClass(ZBX_STYLE_PLUS_ICON) - ->addStyle('margin-right: 0px;') - )) - ->setAttribute('data-row', $row_num) - ->addClass(ZBX_STYLE_BTN_ALT) - ) - ])) - ->addClass(ZBX_STYLE_OVERRIDES_LIST_ITEM); - } - - /** - * Return template used by dynamic rows in CWidgetFieldGraphOverride field. - * - * @param CWidgetFieldGraphOverride $field - * @param string $form_name Form name in which override field is located. - * - * @return string - */ - public static function getGraphOverrideTemplate($field, $form_name) { - $value = CWidgetFieldGraphOverride::getDefaults(); - - return self::getGraphOverrideLayout($field, $value, $form_name, '#{rowNum}')->toString(); - } - - /** - * @param CWidgetFieldGraphOverride $field - * - * @return CList - */ - public static function getGraphOverride($field, $form_name) { - $list = (new CList())->addClass(ZBX_STYLE_OVERRIDES_LIST); - - $values = $field->getValue(); - - if (!$values) { - $values = []; - } - - $i = 0; - - foreach ($values as $override) { - $list->addItem(self::getGraphOverrideLayout($field, $override, $form_name, $i)); - - $i++; - } - - // Add 'Add' button under the list. - $list->addItem( - (new CDiv( - (new CButton('override_add', [(new CSpan())->addClass(ZBX_STYLE_PLUS_ICON), _('Add new override')])) - ->addClass(ZBX_STYLE_BTN_ALT) - ->setId('override-add') - )), - 'overrides-foot' - ); - - return $list; - } - - /** - * Function returns array containing string values used as titles for override options. - * - * @return array - */ - private static function getGraphOverrideOptionNames() { - return [ - 'width' => _('Width'), - 'type' => _('Draw'), - 'type'.SVG_GRAPH_TYPE_LINE => _('Line'), - 'type'.SVG_GRAPH_TYPE_POINTS => _('Points'), - 'type'.SVG_GRAPH_TYPE_STAIRCASE => _('Staircase'), - 'type'.SVG_GRAPH_TYPE_BAR => _('Bar'), - 'transparency' => _('Transparency'), - 'fill' => _('Fill'), - 'pointsize' => _('Point size'), - 'missingdatafunc' => _('Missing data'), - 'missingdatafunc'.SVG_GRAPH_MISSING_DATA_NONE => _('None'), - 'missingdatafunc'.SVG_GRAPH_MISSING_DATA_CONNECTED => _x('Connected', 'missing data function'), - 'missingdatafunc'.SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO => _x('Treat as 0', 'missing data function'), - 'missingdatafunc'.SVG_GRAPH_MISSING_DATA_LAST_KNOWN => _x('Last known', 'missing data function'), - 'axisy' => _('Y-axis'), - 'axisy'.GRAPH_YAXIS_SIDE_LEFT => _('Left'), - 'axisy'.GRAPH_YAXIS_SIDE_RIGHT => _('Right'), - 'timeshift' => _('Time shift') - ]; - } - - /** - * Function returns array used to construct override field menu of available override options. - * - * @return array - */ - private static function getGraphOverrideMenu() { - return [ - 'sections' => [ - [ - 'name' => _('ADD OVERRIDE'), - 'options' => [ - ['name' => _('Base color'), 'callback' => 'addOverride', 'args' => ['color', '']], - - ['name' => _('Width').'/0', 'callback' => 'addOverride', 'args' => ['width', 0]], - ['name' => _('Width').'/1', 'callback' => 'addOverride', 'args' => ['width', 1]], - ['name' => _('Width').'/2', 'callback' => 'addOverride', 'args' => ['width', 2]], - ['name' => _('Width').'/3', 'callback' => 'addOverride', 'args' => ['width', 3]], - ['name' => _('Width').'/4', 'callback' => 'addOverride', 'args' => ['width', 4]], - ['name' => _('Width').'/5', 'callback' => 'addOverride', 'args' => ['width', 5]], - ['name' => _('Width').'/6', 'callback' => 'addOverride', 'args' => ['width', 6]], - ['name' => _('Width').'/7', 'callback' => 'addOverride', 'args' => ['width', 7]], - ['name' => _('Width').'/8', 'callback' => 'addOverride', 'args' => ['width', 8]], - ['name' => _('Width').'/9', 'callback' => 'addOverride', 'args' => ['width', 9]], - ['name' => _('Width').'/10', 'callback' => 'addOverride', 'args' => ['width', 10]], - - ['name' => _('Draw').'/'._('Line'), 'callback' => 'addOverride', 'args' => ['type', SVG_GRAPH_TYPE_LINE]], - ['name' => _('Draw').'/'._('Points'), 'callback' => 'addOverride', 'args' => ['type', SVG_GRAPH_TYPE_POINTS]], - ['name' => _('Draw').'/'._('Staircase'), 'callback' => 'addOverride', 'args' => ['type', SVG_GRAPH_TYPE_STAIRCASE]], - ['name' => _('Draw').'/'._('Bar'), 'callback' => 'addOverride', 'args' => ['type', SVG_GRAPH_TYPE_BAR]], - - ['name' => _('Transparency').'/0', 'callback' => 'addOverride', 'args' => ['transparency', 0]], - ['name' => _('Transparency').'/1', 'callback' => 'addOverride', 'args' => ['transparency', 1]], - ['name' => _('Transparency').'/2', 'callback' => 'addOverride', 'args' => ['transparency', 2]], - ['name' => _('Transparency').'/3', 'callback' => 'addOverride', 'args' => ['transparency', 3]], - ['name' => _('Transparency').'/4', 'callback' => 'addOverride', 'args' => ['transparency', 4]], - ['name' => _('Transparency').'/5', 'callback' => 'addOverride', 'args' => ['transparency', 5]], - ['name' => _('Transparency').'/6', 'callback' => 'addOverride', 'args' => ['transparency', 6]], - ['name' => _('Transparency').'/7', 'callback' => 'addOverride', 'args' => ['transparency', 7]], - ['name' => _('Transparency').'/8', 'callback' => 'addOverride', 'args' => ['transparency', 8]], - ['name' => _('Transparency').'/9', 'callback' => 'addOverride', 'args' => ['transparency', 9]], - ['name' => _('Transparency').'/10', 'callback' => 'addOverride', 'args' => ['transparency', 10]], - - ['name' => _('Fill').'/0', 'callback' => 'addOverride', 'args' => ['fill', 0]], - ['name' => _('Fill').'/1', 'callback' => 'addOverride', 'args' => ['fill', 1]], - ['name' => _('Fill').'/2', 'callback' => 'addOverride', 'args' => ['fill', 2]], - ['name' => _('Fill').'/3', 'callback' => 'addOverride', 'args' => ['fill', 3]], - ['name' => _('Fill').'/4', 'callback' => 'addOverride', 'args' => ['fill', 4]], - ['name' => _('Fill').'/5', 'callback' => 'addOverride', 'args' => ['fill', 5]], - ['name' => _('Fill').'/6', 'callback' => 'addOverride', 'args' => ['fill', 6]], - ['name' => _('Fill').'/7', 'callback' => 'addOverride', 'args' => ['fill', 7]], - ['name' => _('Fill').'/8', 'callback' => 'addOverride', 'args' => ['fill', 8]], - ['name' => _('Fill').'/9', 'callback' => 'addOverride', 'args' => ['fill', 9]], - ['name' => _('Fill').'/10', 'callback' => 'addOverride', 'args' => ['fill', 10]], - - ['name' => _('Point size').'/1', 'callback' => 'addOverride', 'args' => ['pointsize', 1]], - ['name' => _('Point size').'/2', 'callback' => 'addOverride', 'args' => ['pointsize', 2]], - ['name' => _('Point size').'/3', 'callback' => 'addOverride', 'args' => ['pointsize', 3]], - ['name' => _('Point size').'/4', 'callback' => 'addOverride', 'args' => ['pointsize', 4]], - ['name' => _('Point size').'/5', 'callback' => 'addOverride', 'args' => ['pointsize', 5]], - ['name' => _('Point size').'/6', 'callback' => 'addOverride', 'args' => ['pointsize', 6]], - ['name' => _('Point size').'/7', 'callback' => 'addOverride', 'args' => ['pointsize', 7]], - ['name' => _('Point size').'/8', 'callback' => 'addOverride', 'args' => ['pointsize', 8]], - ['name' => _('Point size').'/9', 'callback' => 'addOverride', 'args' => ['pointsize', 9]], - ['name' => _('Point size').'/10', 'callback' => 'addOverride', 'args' => ['pointsize', 10]], - - ['name' => _('Missing data').'/'._('None'), 'callback' => 'addOverride', 'args' => ['missingdatafunc', SVG_GRAPH_MISSING_DATA_NONE]], - ['name' => _('Missing data').'/'._x('Connected', 'missing data function'), 'callback' => 'addOverride', 'args' => ['missingdatafunc', SVG_GRAPH_MISSING_DATA_CONNECTED]], - ['name' => _('Missing data').'/'._x('Treat as 0', 'missing data function'), 'callback' => 'addOverride', 'args' => ['missingdatafunc', SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO]], - ['name' => _('Missing data').'/'._x('Last known', 'missing data function'), 'callback' => 'addOverride', 'args' => ['missingdatafunc', SVG_GRAPH_MISSING_DATA_LAST_KNOWN]], - - ['name' => _('Y-axis').'/'._('Left'), 'callback' => 'addOverride', 'args' => ['axisy', GRAPH_YAXIS_SIDE_LEFT]], - ['name' => _('Y-axis').'/'._('Right'), 'callback' => 'addOverride', 'args' => ['axisy', GRAPH_YAXIS_SIDE_RIGHT]], - - ['name' => _('Time shift'), 'callback' => 'addOverride', 'args' => ['timeshift']] - ] - ] - ] - ]; - } - - /** - * Return javascript necessary to initialize CWidgetFieldGraphOverride field. - * - * @param CWidgetFieldGraphOverride $field - * - * @return string - */ - public static function getGraphOverrideJavascript($field) { - return ' - // Define it as function to avoid redundancy. - function initializeOverrides() { - jQuery("#overrides .'.ZBX_STYLE_OVERRIDES_OPTIONS_LIST.'").overrides({ - add: ".'.ZBX_STYLE_BTN_ALT.'", - options: "input[type=hidden]", - captions: '.json_encode(self::getGraphOverrideOptionNames()).', - makeName: function(option, row_id) { - return "'.$field->getName().'[" + row_id + "][" + option + "]"; - }, - makeOption: function(name) { - return name.match( - /.*\[('.implode('|', CWidgetFieldGraphOverride::getOverrideOptions()).')\]/ - )[1]; - }, - override: ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", - overridesList: ".'.ZBX_STYLE_OVERRIDES_LIST.'", - onUpdate: () => widget_svggraph_form.onGraphConfigChange(), - menu: '.json_encode(self::getGraphOverrideMenu()).' - }); - } - - // Initialize dynamicRows. - jQuery("#overrides") - .dynamicRows({ - template: "#overrides-row", - beforeRow: ".overrides-foot", - remove: ".'.ZBX_STYLE_BTN_REMOVE.'", - add: "#override-add", - row: ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'" - }) - .bind("afteradd.dynamicRows", function(event, options) { - const container = jQuery(".overlay-dialogue-body"); - - container.scrollTop(Math.max(container.scrollTop(), - jQuery("#widget-dialogue-form")[0].scrollHeight - container.height() - )); - - jQuery(".multiselect", jQuery("#overrides")).each(function() { - jQuery(this).multiSelect(jQuery(this).data("params")); - }); - - widget_svggraph_form.updateVariableOrder(jQuery("#overrides"), ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", "or"); - widget_svggraph_form.onGraphConfigChange(); - }) - .bind("afterremove.dynamicRows", function(event, options) { - widget_svggraph_form.updateVariableOrder(jQuery("#overrides"), ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", "or"); - widget_svggraph_form.onGraphConfigChange(); - }) - .bind("tableupdate.dynamicRows", function(event, options) { - widget_svggraph_form.updateVariableOrder(jQuery("#overrides"), ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", "or"); - initializeOverrides(); - if (jQuery("#overrides .'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'").length > 1) { - jQuery("#overrides .drag-icon").removeClass("disabled"); - jQuery("#overrides").sortable("enable"); - } - else { - jQuery("#overrides .drag-icon").addClass("disabled"); - jQuery("#overrides").sortable("disable"); - } - }); - - // Initialize overrides UI control. - initializeOverrides(); - - // Initialize override pattern-selectors. - jQuery(".multiselect", jQuery("#overrides")).each(function() { - jQuery(this).multiSelect(jQuery(this).data("params")); - }); - - // Make overrides sortable. - if (jQuery("#overrides .'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'").length < 2) { - jQuery("#overrides .drag-icon").addClass("disabled"); - } - - jQuery("#overrides").sortable({ - items: ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", - containment: "parent", - handle: ".drag-icon", - tolerance: "pointer", - scroll: false, - cursor: "grabbing", - opacity: 0.6, - axis: "y", - disabled: function() { - return jQuery("#overrides .'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'").length < 2; - }(), - start: function() { // Workaround to fix wrong scrolling at initial sort. - jQuery(this).sortable("refreshPositions"); - }, - stop: () => widget_svggraph_form.onGraphConfigChange(), - update: function() { - widget_svggraph_form.updateVariableOrder(jQuery("#overrides"), ".'.ZBX_STYLE_OVERRIDES_LIST_ITEM.'", "or"); - } - }); - '; - } - - /** - * Function returns array containing HTML objects filled with given values. Used to generate HTML row in widget - * data set field. - * - * @param string $field_name - * @param array $value Values to fill in particular data set row. See self::setValue() for detailed - * description. - * @param string $form_name Name of form in which data set fields resides. - * @param int|string $row_num Unique data set numeric identifier. Used to make unique field names. - * @param bool $is_opened Either accordion row is made opened or closed. - * - * @return CListItem - */ - private static function getGraphDataSetLayout($field_name, array $value, $form_name, $row_num, $is_opened, - int $dataset_type = CWidgetHelper::DATASET_TYPE_PATTERN_ITEM) { - $dataset_head = [ - new CDiv((new CSimpleButton(' '))->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_TOGGLE)), - new CVar($field_name.'['.$row_num.'][dataset_type]', $dataset_type, '') - ]; - - if ($dataset_type == self::DATASET_TYPE_PATTERN_ITEM) { - $host_pattern_field = (new CPatternSelect([ - 'name' => $field_name.'['.$row_num.'][hosts][]', - 'object_name' => 'hosts', - 'data' => $value['hosts'], - 'placeholder' => _('host pattern'), - 'wildcard_allowed' => 1, - 'popup' => [ - 'parameters' => [ - 'srctbl' => 'hosts', - 'srcfld1' => 'host', - 'dstfrm' => $form_name, - 'dstfld1' => zbx_formatDomId($field_name.'['.$row_num.'][hosts][]') - ] - ], - 'add_post_js' => false - ])) - ->addClass('js-hosts-multiselect') - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH); - - $dataset_head = array_merge($dataset_head, [ - (new CColor($field_name.'['.$row_num.'][color]', $value['color']))->appendColorPickerJs(false), - $host_pattern_field, - (new CPatternSelect([ - 'name' => $field_name.'['.$row_num.'][items][]', - 'object_name' => 'items', - 'data' => $value['items'], - 'placeholder' => _('item pattern'), - 'wildcard_allowed' => 1, - 'popup' => [ - 'parameters' => [ - 'srctbl' => 'items', - 'srcfld1' => 'name', - 'real_hosts' => 1, - 'numeric' => 1, - 'dstfrm' => $form_name, - 'dstfld1' => zbx_formatDomId($field_name.'['.$row_num.'][items][]') - ], - 'filter_preselect' => [ - 'id' => $host_pattern_field->getId(), - 'submit_as' => 'host_pattern', - 'submit_parameters' => [ - 'host_pattern_wildcard_allowed' => 1, - 'host_pattern_multiple' => 1 - ], - 'multiple' => true - ] - ], - 'autosuggest' => [ - 'filter_preselect' => [ - 'id' => $host_pattern_field->getId(), - 'submit_as' => 'host_pattern', - 'submit_parameters' => [ - 'host_pattern_wildcard_allowed' => 1, - 'host_pattern_multiple' => 1 - ], - 'multiple' => true - ] - ], - 'add_post_js' => false - ])) - ->addClass('js-items-multiselect') - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ]); - } - else { - $item_rows = []; - foreach($value['itemids'] as $i => $itemid) { - $item_name = array_key_exists($itemid, $value['item_names']) - ? $value['item_names'][$itemid] - : ''; - - $item_rows[] = (new CRow([ - (new CCol( - (new CDiv())->addClass(ZBX_STYLE_DRAG_ICON) - )) - ->addClass('table-col-handle') - ->addClass(ZBX_STYLE_TD_DRAG_ICON), - (new CCol( - (new CColor($field_name.'['.$row_num.'][color][]', $value['color'][$i], - 'items_'.$row_num.'_'.($i + 1).'_color' - ))->appendColorPickerJs(false) - ))->addClass('table-col-color'), - (new CCol(new CSpan(($i + 1).':')))->addClass('table-col-no'), - (new CCol( - (new CLink($item_name)) - ->setId('items_'.$row_num.'_'.($i + 1).'_name') - ->addClass('js-click-expend') - ))->addClass('table-col-name'), - (new CCol([ - (new CButton('button', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove'), - new CVar($field_name.'['.$row_num.'][itemids][]', $itemid, - 'items_'.$row_num.'_'.($i + 1).'_input' - ) - ])) - ->addClass('table-col-action') - ->addClass(ZBX_STYLE_NOWRAP) - ])) - ->addClass(ZBX_STYLE_SORTABLE) - ->addClass('single-item-table-row'); - } - - $empty_msg_block = (new CDiv(_('No item selected.')))->addClass('no-items-message'); - - $items_list = (new CTable()) - ->addClass('single-item-table') - ->setAttribute('data-set', $row_num) - ->setColumns([ - (new CTableColumn())->addClass('table-col-handle'), - (new CTableColumn())->addClass('table-col-color'), - (new CTableColumn())->addClass('table-col-no'), - (new CTableColumn(_('Name')))->addClass('table-col-name'), - (new CTableColumn(_('Action')))->addClass('table-col-action') - ]) - ->addItem([ - $item_rows, - (new CTag('tfoot', true)) - ->addItem( - (new CCol( - (new CList()) - ->addClass(ZBX_STYLE_INLINE_FILTER_FOOTER) - ->addItem( - (new CSimpleButton(_('Add'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('js-add-item') - ) - ))->setColSpan(5) - ) - ]); - - $dataset_head = array_merge($dataset_head, [ - (new CDiv([$empty_msg_block, $items_list]))->addClass('items-list table-forms-separator') - ]); - } - - $dataset_head[] = (new CDiv( - (new CButton()) - ->setAttribute('title', _('Delete')) - ->addClass(ZBX_STYLE_BTN_REMOVE) - ->removeId() - ))->addClass('dataset-actions'); - - return (new CListItem([ - (new CDiv()) - ->addClass(ZBX_STYLE_DRAG_ICON) - ->addClass(ZBX_STYLE_SORTABLE_DRAG_HANDLE) - ->addClass('js-main-drag-icon'), - (new CDiv()) - ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_HEAD) - ->addClass('dataset-head') - ->addItem($dataset_head), - (new CDiv()) - ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM_BODY) - ->addClass('dataset-body') - ->addItem([ - (new CFormGrid()) - ->addItem([ - new CLabel(_('Draw')), - new CFormField( - (new CRadioButtonList($field_name.'['.$row_num.'][type]', (int) $value['type'])) - ->addClass('js-type') - ->addValue(_('Line'), SVG_GRAPH_TYPE_LINE) - ->addValue(_('Points'), SVG_GRAPH_TYPE_POINTS) - ->addValue(_('Staircase'), SVG_GRAPH_TYPE_STAIRCASE) - ->addValue(_('Bar'), SVG_GRAPH_TYPE_BAR) - ->setModern(true) - ) - ]) - ->addItem([ - new CLabel(_('Stacked'), $field_name.'['.$row_num.'][stacked]'), - new CFormField([ - (new CVar($field_name.'['.$row_num.'][stacked]', '0'))->removeId(), - (new CCheckBox($field_name.'['.$row_num.'][stacked]')) - ->addClass('js-stacked') - ->setChecked((bool) $value['stacked']) - ->setEnabled($value['type'] != SVG_GRAPH_TYPE_POINTS) - ]) - ]) - ->addItem([ - new CLabel(_('Width')), - new CFormField( - (new CRangeControl($field_name.'['.$row_num.'][width]', (int) $value['width'])) - ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ->setStep(1) - ->setMin(0) - ->setMax(10) - ) - ]) - ->addItem([ - new CLabel(_('Point size')), - new CFormField( - (new CRangeControl($field_name.'['.$row_num.'][pointsize]', (int) $value['pointsize'])) - ->setEnabled($value['type'] == SVG_GRAPH_TYPE_POINTS) - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ->setStep(1) - ->setMin(1) - ->setMax(10) - ) - ]) - ->addItem([ - new CLabel(_('Transparency')), - new CFormField( - (new CRangeControl($field_name.'['.$row_num.'][transparency]', - (int) $value['transparency']) - ) - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ->setStep(1) - ->setMin(0) - ->setMax(10) - ) - ]) - ->addItem([ - new CLabel(_('Fill')), - new CFormField( - (new CRangeControl($field_name.'['.$row_num.'][fill]', (int) $value['fill'])) - ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ->setStep(1) - ->setMin(0) - ->setMax(10) - ) - ]), - (new CFormGrid()) - ->addItem([ - new CLabel(_('Missing data')), - new CFormField( - (new CRadioButtonList($field_name.'['.$row_num.'][missingdatafunc]', - (int) $value['missingdatafunc']) - ) - ->addValue(_('None'), SVG_GRAPH_MISSING_DATA_NONE) - ->addValue(_x('Connected', 'missing data function'), - SVG_GRAPH_MISSING_DATA_CONNECTED - ) - ->addValue(_x('Treat as 0', 'missing data function'), - SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO - ) - ->addValue(_x('Last known', 'missing data function'), - SVG_GRAPH_MISSING_DATA_LAST_KNOWN - ) - ->setEnabled(!in_array($value['type'], [SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_BAR])) - ->setModern(true) - ) - ]) - ->addItem([ - new CLabel(_('Y-axis')), - new CFormField( - (new CRadioButtonList($field_name.'['.$row_num.'][axisy]', (int) $value['axisy'])) - ->addValue(_('Left'), GRAPH_YAXIS_SIDE_LEFT) - ->addValue(_('Right'), GRAPH_YAXIS_SIDE_RIGHT) - ->setModern(true) - ) - ]) - ->addItem([ - new CLabel(_('Time shift'), $field_name.'['.$row_num.'][timeshift]'), - new CFormField( - (new CTextBox($field_name.'['.$row_num.'][timeshift]', $value['timeshift'])) - ->setAttribute('placeholder', _('none')) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) - ) - ]) - ->addItem([ - new CLabel(_('Aggregation function'), - 'label-'.$field_name.'_'.$row_num.'_aggregate_function' - ), - new CFormField( - (new CSelect($field_name.'['.$row_num.'][aggregate_function]')) - ->setId($field_name.'_'.$row_num.'_aggregate_function') - ->setFocusableElementId('label-'.$field_name.'_'.$row_num.'_aggregate_function') - ->setValue((int) $value['aggregate_function']) - ->addOptions(CSelect::createOptionsFromArray([ - AGGREGATE_NONE => graph_item_aggr_fnc2str(AGGREGATE_NONE), - AGGREGATE_MIN => graph_item_aggr_fnc2str(AGGREGATE_MIN), - AGGREGATE_MAX => graph_item_aggr_fnc2str(AGGREGATE_MAX), - AGGREGATE_AVG => graph_item_aggr_fnc2str(AGGREGATE_AVG), - AGGREGATE_COUNT => graph_item_aggr_fnc2str(AGGREGATE_COUNT), - AGGREGATE_SUM => graph_item_aggr_fnc2str(AGGREGATE_SUM), - AGGREGATE_FIRST => graph_item_aggr_fnc2str(AGGREGATE_FIRST), - AGGREGATE_LAST => graph_item_aggr_fnc2str(AGGREGATE_LAST) - ])) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) - ) - ]) - ->addItem([ - new CLabel(_('Aggregation interval'), $field_name.'['.$row_num.'][aggregate_interval]'), - new CFormField( - (new CTextBox($field_name.'['.$row_num.'][aggregate_interval]', - $value['aggregate_interval'] - )) - ->setEnabled($value['aggregate_function'] != AGGREGATE_NONE) - ->setAttribute('placeholder', GRAPH_AGGREGATE_DEFAULT_INTERVAL) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) - ) - ]) - ->addItem([ - new CLabel(_('Aggregate')), - new CFormField( - (new CRadioButtonList($field_name.'['.$row_num.'][aggregate_grouping]', - (int) $value['aggregate_grouping']) - ) - ->addValue(_('Each item'), GRAPH_AGGREGATE_BY_ITEM) - ->addValue(_('Data set'), GRAPH_AGGREGATE_BY_DATASET) - ->setEnabled($value['aggregate_function'] != AGGREGATE_NONE) - ->setModern(true) - ) - ]) - ->addItem([ - new CLabel(_('Approximation'), - 'label-'.$field_name.'_'.$row_num.'_approximation' - ), - new CFormField( - (new CSelect($field_name.'['.$row_num.'][approximation]')) - ->setId($field_name.'_'.$row_num.'_approximation') - ->setFocusableElementId('label-'.$field_name.'_'.$row_num.'_approximation') - ->setValue((int) $value['approximation']) - ->addOptions(CSelect::createOptionsFromArray([ - APPROXIMATION_ALL => [ - 'label' => _('all'), - 'disabled' => ($value['type'] != SVG_GRAPH_TYPE_LINE || (bool) $value['stacked']) - ], - APPROXIMATION_MIN => _('min'), - APPROXIMATION_AVG => _('avg'), - APPROXIMATION_MAX => _('max') - ])) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) - ) - ]) - ]) - ])) - ->addClass(ZBX_STYLE_LIST_ACCORDION_ITEM) - ->addClass(ZBX_STYLE_SORTABLE_ITEM) - ->addClass($is_opened ? ZBX_STYLE_LIST_ACCORDION_ITEM_OPENED : ZBX_STYLE_LIST_ACCORDION_ITEM_CLOSED) - ->setAttribute('data-set', $row_num) - ->setAttribute('data-type', $dataset_type); - } - - /** - * Return template used by dynamic rows in CWidgetFieldGraphDataSet field. - * - * @param CWidgetFieldGraphDataSet $field - * @param string $form_name Form name in which data set field resides. - * @param int $dataset_type - * - * @return string - */ - public static function getGraphDataSetTemplate($field, $form_name, int $dataset_type) { - $value = ['color' => '#{color}'] + CWidgetFieldGraphDataSet::getDefaults(); - - return self::getGraphDataSetLayout($field->getName(), $value, $form_name, '#{rowNum}', true, $dataset_type)->toString(); - } - - /** - * @param CWidgetFieldGraphDataSet $field - * - * @return CList - */ - public static function getGraphDataSet($field, $form_name) { - $list = (new CList()) - ->setId('data_sets') - ->addClass(ZBX_STYLE_SORTABLE_LIST); - - $values = $field->getValue(); - - if (!$values) { - $values[] = CWidgetFieldGraphDataSet::getDefaults(); - } - - // Get item names for single item datasets. - $itemids = array_merge(...array_column($values, 'itemids')); - if ($itemids) { - $names = self::getItemNames($itemids); - } - - foreach ($values as $i => $value) { - if ($value['dataset_type'] == self::DATASET_TYPE_SINGLE_ITEM) { - $value['item_names'] = $names; - } - - $list->addItem( - self::getGraphDataSetLayout($field->getName(), $value, $form_name, $i, $i == 0, $value['dataset_type']) - ); - } - - return $list; - } - - public static function getGraphDataSetFooter() { - return (new CList()) - ->addClass(ZBX_STYLE_BTN_SPLIT) - ->addItem([ - (new CButton(null, [ - (new CSpan())->addClass(ZBX_STYLE_PLUS_ICON), - _('Add new data set') - ])) - ->setId('dataset-add') - ->addClass(ZBX_STYLE_BTN_ALT), - (new CButton(null, '​')) - ->setId('dataset-menu') - ->addClass(ZBX_STYLE_BTN_ALT) - ->addClass(ZBX_STYLE_BTN_TOGGLE_CHEVRON) - ]); - } - - private static function getItemNames(array $itemids): array { - $names = []; - - $items = API::Item()->get([ - 'output' => ['itemid', 'hostid', 'name'], - 'selectHosts' => ['hostid', 'name'], - 'webitems' => true, - 'itemids' => $itemids, - 'preservekeys' => true - ]); - - if (!$items) { - return $names; - } - - foreach ($items as $item) { - $hosts = array_column($item['hosts'], 'name', 'hostid'); - $names[$item['itemid']] = $hosts[$item['hostid']].NAME_DELIMITER.$item['name']; - } - - return $names; - } - - public static function getThresholds(CWidgetFieldThresholds $field): CDiv { - $thresholds_table = (new CTable()) - ->setId(sprintf(CWidgetFieldThresholds::THRESHOLDS_TABLE_ID, $field->getName())) - ->addClass(ZBX_STYLE_TABLE_FORMS) - ->setHeader([ - '', - (new CColHeader(_('Threshold')))->setWidth('100%'), - _('Action') - ]) - ->setFooter(new CRow( - new CCol( - (new CSimpleButton(_('Add'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-add') - ) - )); - - foreach ($field->getValue() as $i => $threshold) { - $thresholds_table->addRow( - self::getThresholdsTemplate($field->getName(), $i, $threshold['color'], $threshold['threshold']) - ); - } - - return (new CDiv($thresholds_table)) - ->addClass('table-forms-separator') - ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH); - } - - public static function getThresholdsTemplate($name, $index = '#{rowNum}', $color = '#{color}', - $threshold = '#{threshold}'): CRow { - return (new CRow([ - (new CColor($name.'['.$index.'][color]', $color))->appendColorPickerJs(false), - (new CTextBox($name.'['.$index.'][threshold]', $threshold, false)) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) - ->setAriaRequired(), - (new CButton($name.'['.$index.'][remove]', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove') - ]))->addClass('form_row'); - } - - /** - * @param CWidgetField $field - * - * @return int - */ - public static function isAriaRequired($field) { - return ($field->getFlags() & CWidgetField::FLAG_LABEL_ASTERISK); - } -} diff --git a/ui/include/classes/widgets/fields/CWidgetFieldCheckBox.php b/ui/include/classes/widgets/fields/CWidgetFieldCheckBox.php index a12565c4d96..716a030382c 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldCheckBox.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldCheckBox.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -18,30 +18,35 @@ ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ + +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldCheckBox extends CWidgetField { - private $caption; + public const DEFAULT_VALUE = 0; + + private ?string $caption; /** - * Check box widget field. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. - * @param string $caption Text after checkbox. + * @param string|null $caption Text after checkbox. */ - public function __construct($name, $label, $caption = null) { + public function __construct(string $name, string $label = null, string $caption = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32); - $this->setDefault(0); $this->caption = $caption; + + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32); } - public function setValue($value) { + public function setValue($value): self { return parent::setValue((int) $value); } - public function getCaption() { + public function getCaption(): ?string { return $this->caption; } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldCheckBoxList.php b/ui/include/classes/widgets/fields/CWidgetFieldCheckBoxList.php index 5fc1f3f0762..9127e262ac9 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldCheckBoxList.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldCheckBoxList.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,24 +19,39 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldCheckBoxList extends CWidgetField { - public function __construct($name, $label) { + public const DEFAULT_VALUE = []; + + private array $values; + + public function __construct(string $name, string $label = null, array $values = []) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32); - $this->setDefault([]); - $this->setValidationRules(['type' => API_INTS32]); + $this->values = $values; + + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32) + ->setValidationRules(['type' => API_INTS32]); + } + + public function getValues(): array { + return $this->values; } - public function setValue($value) { + public function setValue($value): self { $this->value = (array) $value; return $this; } - public function setDefault($values) { - $this->default = (array) $values; + public function setDefault($value): self { + $this->default = (array) $value; return $this; } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldColor.php b/ui/include/classes/widgets/fields/CWidgetFieldColor.php index b70d550631a..a0082e1c484 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldColor.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldColor.php @@ -19,21 +19,37 @@ **/ -/** - * Class for widget field color. - */ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldColor extends CWidgetField { + public const DEFAULT_VALUE = ''; + + private bool $allow_inherited = false; + + public function __construct(string $name, string $label = null) { + parent::__construct($name, $label); + + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_COLOR, 'flags' => API_ALLOW_NULL]); + } + + public function hasAllowInherited(): bool { + return $this->allow_inherited; + } + /** - * Create color widget field. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. + * Tell the Color picker whether to use Default (inherited) color feature or not. */ - public function __construct($name, $label) { - parent::__construct($name, $label); + public function allowInherited($allow_inherited = true): self { + $this->allow_inherited = $allow_inherited; - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_COLOR, 'flags' => API_ALLOW_NULL]); + return $this; } + + } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldColumnsList.php b/ui/include/classes/widgets/fields/CWidgetFieldColumnsList.php index f74c303dd67..dc6e43d5108 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldColumnsList.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldColumnsList.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2021 Zabbix SIA @@ -19,92 +19,90 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldColumnsList extends CWidgetField { // Source of value to display in column. - const DATA_ITEM_VALUE = 1; - const DATA_HOST_NAME = 2; - const DATA_TEXT = 3; + public const DATA_ITEM_VALUE = 1; + public const DATA_HOST_NAME = 2; + public const DATA_TEXT = 3; // Column value display type. - const DISPLAY_AS_IS = 1; - const DISPLAY_BAR = 2; - const DISPLAY_INDICATORS = 3; + public const DISPLAY_AS_IS = 1; + public const DISPLAY_BAR = 2; + public const DISPLAY_INDICATORS = 3; // Where to select data for aggregation function. - const HISTORY_DATA_AUTO = 1; - const HISTORY_DATA_HISTORY = 2; - const HISTORY_DATA_TRENDS = 3; + public const HISTORY_DATA_AUTO = 1; + public const HISTORY_DATA_HISTORY = 2; + public const HISTORY_DATA_TRENDS = 3; // Predefined colors for thresholds. Each next threshold takes next sequential value from palette. - const THRESHOLDS_DEFAULT_COLOR_PALETTE = [ - 'FF465C','B0AF07','0EC9AC','524BBC','ED1248','D1E754','2AB5FF','385CC7','EC1594','BAE37D', - '6AC8FF','EE2B29','3CA20D','6F4BBC','00A1FF','F3601B','1CAE59','45CFDB','894BBC','6D6D6D' + public const THRESHOLDS_DEFAULT_COLOR_PALETTE = [ + 'FF465C', 'B0AF07', '0EC9AC', '524BBC', 'ED1248', 'D1E754', '2AB5FF', '385CC7', 'EC1594', 'BAE37D', + '6AC8FF', 'EE2B29', '3CA20D', '6F4BBC', '00A1FF', 'F3601B', '1CAE59', '45CFDB', '894BBC', '6D6D6D' ]; - public function __construct($name, $label) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_OBJECTS, 'fields' => [ - 'name' => ['type' => API_STRING_UTF8, 'default' => '', 'length' => 255], - 'data' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [self::DATA_ITEM_VALUE, self::DATA_HOST_NAME, self::DATA_TEXT])], - 'item' => ['type' => API_MULTIPLE, 'rules' => [ - ['if' => ['field' => 'data', 'in' => self::DATA_ITEM_VALUE], - 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => 255], - ['else' => true, - 'type' => API_STRING_UTF8] - ]], - 'timeshift' => ['type' => API_TIME_UNIT, 'in' => implode(':', [ZBX_MIN_TIMESHIFT, ZBX_MAX_TIMESHIFT])], - 'aggregate_function' => ['type' => API_INT32, 'in' => implode(',', [AGGREGATE_NONE, AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_AVG, AGGREGATE_COUNT, AGGREGATE_SUM, AGGREGATE_FIRST, AGGREGATE_LAST]), 'default' => AGGREGATE_NONE], - 'aggregate_interval' => ['type' => API_MULTIPLE, 'rules' => [ - ['if' => ['field' => 'aggregate_function', 'in' => implode(',', [AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_AVG, AGGREGATE_COUNT, AGGREGATE_SUM, AGGREGATE_FIRST, AGGREGATE_LAST])], - 'type' => API_TIME_UNIT, 'flags' => API_REQUIRED | API_NOT_EMPTY | API_TIME_UNIT_WITH_YEAR, 'in' => implode(':', [1, ZBX_MAX_TIMESHIFT])], - ['else' => true, - 'type' => API_STRING_UTF8] - ]], - 'display' => ['type' => API_MULTIPLE, 'rules' => [ - ['if' => ['field' => 'data', 'in' => self::DATA_ITEM_VALUE], - 'type' => API_INT32, 'default' => self::DISPLAY_AS_IS, 'in' => implode(',', [self::DISPLAY_AS_IS, self::DISPLAY_BAR, self::DISPLAY_INDICATORS])], - ['else' => true, - 'type' => API_INT32] - ]], - 'history' => ['type' => API_MULTIPLE, 'rules' => [ - ['if' => ['field' => 'data', 'in' => self::DATA_ITEM_VALUE], - 'type' => API_INT32, 'default' => self::HISTORY_DATA_AUTO, 'in' => implode(',', [self::HISTORY_DATA_AUTO, self::HISTORY_DATA_HISTORY, self::HISTORY_DATA_TRENDS])], - ['else' => true, - 'type' => API_INT32] - ]], - 'base_color' => ['type' => API_COLOR], - 'min' => ['type' => API_NUMERIC], - 'max' => ['type' => API_NUMERIC], - 'thresholds' => ['type' => API_OBJECTS, 'uniq' => [['threshold']], 'fields' => [ - 'color' => ['type' => API_COLOR], - 'threshold' => ['type' => API_NUMERIC] - ]], - 'text' => ['type' => API_MULTIPLE, 'rules' => [ - ['if' => ['field' => 'data', 'in' => self::DATA_TEXT], - 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => 255], - ['else' => true, - 'type' => API_STRING_UTF8] - ]] - ]]); + $this + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_OBJECTS, 'fields' => [ + 'name' => ['type' => API_STRING_UTF8, 'default' => '', 'length' => 255], + 'data' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [self::DATA_ITEM_VALUE, self::DATA_HOST_NAME, self::DATA_TEXT])], + 'item' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'data', 'in' => self::DATA_ITEM_VALUE], + 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => 255], + ['else' => true, + 'type' => API_STRING_UTF8] + ]], + 'timeshift' => ['type' => API_TIME_UNIT, 'in' => implode(':', [ZBX_MIN_TIMESHIFT, ZBX_MAX_TIMESHIFT])], + 'aggregate_function' => ['type' => API_INT32, 'in' => implode(',', [AGGREGATE_NONE, AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_AVG, AGGREGATE_COUNT, AGGREGATE_SUM, AGGREGATE_FIRST, AGGREGATE_LAST]), 'default' => AGGREGATE_NONE], + 'aggregate_interval' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'aggregate_function', 'in' => implode(',', [AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_AVG, AGGREGATE_COUNT, AGGREGATE_SUM, AGGREGATE_FIRST, AGGREGATE_LAST])], + 'type' => API_TIME_UNIT, 'flags' => API_REQUIRED | API_NOT_EMPTY | API_TIME_UNIT_WITH_YEAR, 'in' => implode(':', [1, ZBX_MAX_TIMESHIFT])], + ['else' => true, + 'type' => API_STRING_UTF8] + ]], + 'display' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'data', 'in' => self::DATA_ITEM_VALUE], + 'type' => API_INT32, 'default' => self::DISPLAY_AS_IS, 'in' => implode(',', [self::DISPLAY_AS_IS, self::DISPLAY_BAR, self::DISPLAY_INDICATORS])], + ['else' => true, + 'type' => API_INT32] + ]], + 'history' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'data', 'in' => self::DATA_ITEM_VALUE], + 'type' => API_INT32, 'default' => self::HISTORY_DATA_AUTO, 'in' => implode(',', [self::HISTORY_DATA_AUTO, self::HISTORY_DATA_HISTORY, self::HISTORY_DATA_TRENDS])], + ['else' => true, + 'type' => API_INT32] + ]], + 'base_color' => ['type' => API_COLOR], + 'min' => ['type' => API_NUMERIC], + 'max' => ['type' => API_NUMERIC], + 'thresholds' => ['type' => API_OBJECTS, 'uniq' => [['threshold']], 'fields' => [ + 'color' => ['type' => API_COLOR], + 'threshold' => ['type' => API_NUMERIC] + ]], + 'text' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'data', 'in' => self::DATA_TEXT], + 'type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => 255], + ['else' => true, + 'type' => API_STRING_UTF8] + ]] + ]]); } - public function setValue($value) { + public function setValue($value): self { $this->value = (array) $value; return $this; } - /** - * Prepares array entry for widget field, ready to be passed to CDashboard API functions. - * Reference is needed here to avoid array merging in CWidgetForm::fieldsToApi method. With large number of widget - * fields it causes significant performance decrease. - * - * @param array $widget_fields reference to Array of widget fields. - */ - public function toApi(array &$widget_fields = []) { + public function toApi(array &$widget_fields = []): void { $fields = [ 'name' => ZBX_WIDGET_FIELD_TYPE_STR, 'data' => ZBX_WIDGET_FIELD_TYPE_INT32, diff --git a/ui/include/classes/widgets/fields/CWidgetFieldDatePicker.php b/ui/include/classes/widgets/fields/CWidgetFieldDatePicker.php index 881b9f22785..faf3f03bd60 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldDatePicker.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldDatePicker.php @@ -19,43 +19,42 @@ **/ +namespace Zabbix\Widgets\Fields; + +use CAbsoluteTimeParser, + CParser, + CRelativeTimeParser, + DB; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldDatePicker extends CWidgetField { - /** - * @var bool - */ - private $is_date_only; - - /** - * @param string $name - * @param string $label - * @param bool $is_date_only - */ - public function __construct(string $name, string $label, bool $is_date_only) { + public const DEFAULT_VALUE = ''; + + private bool $is_date_only; + + public function __construct(string $name, string $label = null, bool $is_date_only = false) { parent::__construct($name, $label); $this->is_date_only = $is_date_only; - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules([ - 'type' => API_STRING_UTF8, - 'length' => DB::getFieldLength('widget_field', 'value_str') - ]); - $this->setDefault(''); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules([ + 'type' => API_STRING_UTF8, + 'length' => DB::getFieldLength('widget_field', 'value_str') + ]); } - /** - * @param $flags - * - * @return CWidgetFieldDatePicker - */ - public function setFlags($flags): self { + public function setFlags(int $flags): self { parent::setFlags($flags); $validation_rules = $this->getValidationRules(); $validation_rules['flags'] = $validation_rules['flags'] ?? 0x00; - if (($flags & self::FLAG_NOT_EMPTY) != 0) { + if (($flags & self::FLAG_NOT_EMPTY) !== 0) { $validation_rules['flags'] |= API_NOT_EMPTY; } else { @@ -67,11 +66,6 @@ class CWidgetFieldDatePicker extends CWidgetField { return $this; } - /** - * @param bool $strict - * - * @return array - */ public function validate(bool $strict = false): array { if ($errors = parent::validate($strict)) { return $errors; @@ -80,7 +74,7 @@ class CWidgetFieldDatePicker extends CWidgetField { $label = $this->full_name ?? $this->label ?? $this->name; $value = $this->value ?? $this->default; - if ($value === '' && ($this->getFlags() & self::FLAG_NOT_EMPTY) == 0) { + if ($value === '' && ($this->getFlags() & self::FLAG_NOT_EMPTY) === 0) { $this->setValue(''); return []; diff --git a/ui/include/classes/widgets/fields/CWidgetFieldGraphDataSet.php b/ui/include/classes/widgets/fields/CWidgetFieldGraphDataSet.php index b65418b16f5..1ff879942f8 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldGraphDataSet.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldGraphDataSet.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,61 +19,65 @@ **/ +namespace Zabbix\Widgets\Fields; + +use API, + CApiInputValidator; + +use Zabbix\Widgets\CWidgetField; + /** * Class for data set widget field used in Graph widget configuration Data set tab. */ class CWidgetFieldGraphDataSet extends CWidgetField { + public const DEFAULT_VALUE = []; + + public const DATASET_TYPE_SINGLE_ITEM = 0; + public const DATASET_TYPE_PATTERN_ITEM = 1; + // Predefined colors for data-sets in JSON format. Each next data set takes next sequential value from palette. - const DEFAULT_COLOR_PALETTE = ["FF465C","B0AF07","0EC9AC","524BBC","ED1248","D1E754","2AB5FF","385CC7","EC1594","BAE37D","6AC8FF","EE2B29","3CA20D","6F4BBC","00A1FF","F3601B","1CAE59","45CFDB","894BBC","6D6D6D"]; + public const DEFAULT_COLOR_PALETTE = [ + 'FF465C', 'B0AF07', '0EC9AC', '524BBC', 'ED1248', 'D1E754', '2AB5FF', '385CC7', 'EC1594', 'BAE37D', + '6AC8FF', 'EE2B29', '3CA20D', '6F4BBC', '00A1FF', 'F3601B', '1CAE59', '45CFDB', '894BBC', '6D6D6D' + ]; // First color from the default color palette. - const DEFAULT_COLOR = 'FF465C'; - - /** - * Create widget field for Data set selection. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. - */ - public function __construct($name, $label) { + private const DEFAULT_COLOR = 'FF465C'; + + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_OBJECTS, 'fields' => [ - 'dataset_type' => ['type' => API_INT32, 'in' => implode(',', [CWidgetHelper::DATASET_TYPE_SINGLE_ITEM, CWidgetHelper::DATASET_TYPE_PATTERN_ITEM])], - 'hosts' => ['type' => API_STRINGS_UTF8, 'flags' => null], - 'items' => ['type' => API_STRINGS_UTF8, 'flags' => null], - 'itemids' => ['type' => API_IDS, 'flags' => null], - 'color' => ['type' => API_COLOR, 'flags' => API_REQUIRED | API_NOT_EMPTY], - 'type' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [SVG_GRAPH_TYPE_LINE, SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_STAIRCASE, SVG_GRAPH_TYPE_BAR])], - 'stacked' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [SVG_GRAPH_STACKED_OFF, SVG_GRAPH_STACKED_ON])], - 'width' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], - 'pointsize' => ['type' => API_INT32, 'in' => implode(',', range(1, 10))], - 'transparency' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', range(0, 10))], - 'fill' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], - 'missingdatafunc' => ['type' => API_INT32, 'in' => implode(',', [SVG_GRAPH_MISSING_DATA_NONE, SVG_GRAPH_MISSING_DATA_CONNECTED, SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO, SVG_GRAPH_MISSING_DATA_LAST_KNOWN])], - 'axisy' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [GRAPH_YAXIS_SIDE_LEFT, GRAPH_YAXIS_SIDE_RIGHT])], - 'timeshift' => ['type' => API_TIME_UNIT, 'flags' => API_REQUIRED, 'in' => implode(':', [ZBX_MIN_TIMESHIFT, ZBX_MAX_TIMESHIFT])], - 'aggregate_function' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [AGGREGATE_NONE, AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_AVG, AGGREGATE_COUNT, AGGREGATE_SUM, AGGREGATE_FIRST, AGGREGATE_LAST])], - 'aggregate_interval' => ['type' => API_MULTIPLE, 'rules' => [ - ['if' => ['field' => 'aggregate_function', 'in' => implode(',', [AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_AVG, AGGREGATE_COUNT, AGGREGATE_SUM, AGGREGATE_FIRST, AGGREGATE_LAST])], - 'type' => API_TIME_UNIT, 'flags' => API_REQUIRED | API_NOT_EMPTY | API_TIME_UNIT_WITH_YEAR, 'in' => implode(':', [1, ZBX_MAX_TIMESHIFT])], - ['else' => true, 'type' => API_STRING_UTF8, 'in' => GRAPH_AGGREGATE_DEFAULT_INTERVAL] - ]], - 'aggregate_grouping' => ['type' => API_INT32, 'in' => implode(',', [GRAPH_AGGREGATE_BY_ITEM, GRAPH_AGGREGATE_BY_DATASET])], - 'approximation' => ['type' => API_INT32, 'in' => implode(',', [APPROXIMATION_MIN, APPROXIMATION_AVG, APPROXIMATION_MAX, APPROXIMATION_ALL])] - ]]); - - $this->setDefault([]); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_OBJECTS, 'fields' => [ + 'dataset_type' => ['type' => API_INT32, 'in' => implode(',', [self::DATASET_TYPE_SINGLE_ITEM, self::DATASET_TYPE_PATTERN_ITEM])], + 'hosts' => ['type' => API_STRINGS_UTF8, 'flags' => null], + 'items' => ['type' => API_STRINGS_UTF8, 'flags' => null], + 'itemids' => ['type' => API_IDS, 'flags' => null], + 'color' => ['type' => API_COLOR, 'flags' => API_REQUIRED | API_NOT_EMPTY], + 'type' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [SVG_GRAPH_TYPE_LINE, SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_STAIRCASE, SVG_GRAPH_TYPE_BAR])], + 'stacked' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [SVG_GRAPH_STACKED_OFF, SVG_GRAPH_STACKED_ON])], + 'width' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], + 'pointsize' => ['type' => API_INT32, 'in' => implode(',', range(1, 10))], + 'transparency' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', range(0, 10))], + 'fill' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], + 'missingdatafunc' => ['type' => API_INT32, 'in' => implode(',', [SVG_GRAPH_MISSING_DATA_NONE, SVG_GRAPH_MISSING_DATA_CONNECTED, SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO, SVG_GRAPH_MISSING_DATA_LAST_KNOWN])], + 'axisy' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [GRAPH_YAXIS_SIDE_LEFT, GRAPH_YAXIS_SIDE_RIGHT])], + 'timeshift' => ['type' => API_TIME_UNIT, 'flags' => API_REQUIRED, 'in' => implode(':', [ZBX_MIN_TIMESHIFT, ZBX_MAX_TIMESHIFT])], + 'aggregate_function' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [AGGREGATE_NONE, AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_AVG, AGGREGATE_COUNT, AGGREGATE_SUM, AGGREGATE_FIRST, AGGREGATE_LAST])], + 'aggregate_interval' => ['type' => API_MULTIPLE, 'rules' => [ + ['if' => ['field' => 'aggregate_function', 'in' => implode(',', [AGGREGATE_MIN, AGGREGATE_MAX, AGGREGATE_AVG, AGGREGATE_COUNT, AGGREGATE_SUM, AGGREGATE_FIRST, AGGREGATE_LAST])], + 'type' => API_TIME_UNIT, 'flags' => API_REQUIRED | API_NOT_EMPTY | API_TIME_UNIT_WITH_YEAR, 'in' => implode(':', [1, ZBX_MAX_TIMESHIFT])], + ['else' => true, 'type' => API_STRING_UTF8, 'in' => GRAPH_AGGREGATE_DEFAULT_INTERVAL] + ]], + 'aggregate_grouping' => ['type' => API_INT32, 'in' => implode(',', [GRAPH_AGGREGATE_BY_ITEM, GRAPH_AGGREGATE_BY_DATASET])], + 'approximation' => ['type' => API_INT32, 'in' => implode(',', [APPROXIMATION_MIN, APPROXIMATION_AVG, APPROXIMATION_MAX, APPROXIMATION_ALL])] + ]]); } - /** - * Set field values for the datasets. - * - * @return $this - */ - public function setValue($value) { + public function setValue($value): self { $data_sets = []; foreach ((array) $value as $data_set) { @@ -83,14 +87,7 @@ class CWidgetFieldGraphDataSet extends CWidgetField { return parent::setValue($data_sets); } - /** - * Set additional flags, which can be used in configuration form. - * - * @param int $flags - * - * @return $this - */ - public function setFlags($flags) { + public function setFlags($flags): self { parent::setFlags($flags); if ($flags & self::FLAG_NOT_EMPTY) { @@ -102,20 +99,15 @@ class CWidgetFieldGraphDataSet extends CWidgetField { $this->setStrictValidationRules($strict_validation_rules); } else { - $this->setStrictValidationRules(null); + $this->setStrictValidationRules(); } return $this; } - /** - * Default values filled in newly created data set or used as unspecified values. - * - * @return array - */ - public static function getDefaults() { + public static function getDefaults(): array { return [ - 'dataset_type' => CWidgetHelper::DATASET_TYPE_PATTERN_ITEM, + 'dataset_type' => self::DATASET_TYPE_PATTERN_ITEM, 'hosts' => [], 'items' => [], 'itemids' => [], @@ -136,11 +128,29 @@ class CWidgetFieldGraphDataSet extends CWidgetField { ]; } - /** - * @param bool $strict Widget form submit validation? - * - * @return array Errors. - */ + public static function getItemNames(array $itemids): array { + $names = []; + + $items = API::Item()->get([ + 'output' => ['itemid', 'hostid', 'name'], + 'selectHosts' => ['hostid', 'name'], + 'webitems' => true, + 'itemids' => $itemids, + 'preservekeys' => true + ]); + + if (!$items) { + return $names; + } + + foreach ($items as $item) { + $hosts = array_column($item['hosts'], 'name', 'hostid'); + $names[$item['itemid']] = $hosts[$item['hostid']].NAME_DELIMITER.$item['name']; + } + + return $names; + } + public function validate(bool $strict = false): array { $errors = []; @@ -148,13 +158,14 @@ class CWidgetFieldGraphDataSet extends CWidgetField { ? $this->strict_validation_rules : $this->validation_rules; $validation_rules += $this->ex_validation_rules; - $value = ($this->value === null) ? $this->default : $this->value; + + $value = $this->value ?? $this->default; if ($this->full_name !== null) { $label = $this->full_name; } else { - $label = ($this->label === null) ? $this->name : $this->label; + $label = $this->label ?? $this->name; } if ($strict) { @@ -170,7 +181,7 @@ class CWidgetFieldGraphDataSet extends CWidgetField { foreach ($value as $i => $data) { $validation_rules_by_type = $validation_rules; - if ($data['dataset_type'] == CWidgetHelper::DATASET_TYPE_SINGLE_ITEM) { + if ($data['dataset_type'] == self::DATASET_TYPE_SINGLE_ITEM) { $validation_rules_by_type['fields']['itemids']['flags'] |= API_REQUIRED; $validation_rules_by_type['fields']['color']['type'] = API_COLORS; @@ -200,14 +211,7 @@ class CWidgetFieldGraphDataSet extends CWidgetField { return $errors; } - /** - * Prepares array entry for widget field, ready to be passed to CDashboard API functions. - * Reference is needed here to avoid array merging in CWidgetForm::fieldsToApi method. With large number of widget - * fields it causes significant performance decrease. - * - * @param array $widget_fields Reference to array of widget fields. - */ - public function toApi(array &$widget_fields = []) { + public function toApi(array &$widget_fields = []): void { $value = $this->getValue(); $dataset_fields = [ @@ -251,8 +255,8 @@ class CWidgetFieldGraphDataSet extends CWidgetField { 'value' => $itemid ]; } - // Field "color" stored as array for dataset type CWidgetHelper::DATASET_TYPE_SINGLE_ITEM (0) - if ($val['dataset_type'] == CWidgetHelper::DATASET_TYPE_SINGLE_ITEM) { + // Field "color" stored as array for dataset type DATASET_TYPE_SINGLE_ITEM (0) + if ($val['dataset_type'] == self::DATASET_TYPE_SINGLE_ITEM) { foreach ($val['color'] as $num => $color) { $widget_fields[] = [ 'type' => ZBX_WIDGET_FIELD_TYPE_STR, diff --git a/ui/include/classes/widgets/fields/CWidgetFieldGraphOverride.php b/ui/include/classes/widgets/fields/CWidgetFieldGraphOverride.php index f9a6a6ba166..ef9558b47bf 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldGraphOverride.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldGraphOverride.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,43 +19,43 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + /** * Class for override widget field used in Graph widget configuration overrides tab. */ class CWidgetFieldGraphOverride extends CWidgetField { - /** - * Create widget field for Graph Override selection. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. - */ - public function __construct($name, $label) { + public const DEFAULT_VALUE = []; + + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_OBJECTS, 'fields' => [ - 'hosts' => ['type' => API_STRINGS_UTF8, 'flags' => API_REQUIRED], - 'items' => ['type' => API_STRINGS_UTF8, 'flags' => API_REQUIRED], - 'color' => ['type' => API_COLOR], - 'type' => ['type' => API_INT32, 'in' => implode(',', [SVG_GRAPH_TYPE_LINE, SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_STAIRCASE, SVG_GRAPH_TYPE_BAR])], - 'width' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], - 'pointsize' => ['type' => API_INT32, 'in' => implode(',', range(1, 10))], - 'transparency' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], - 'fill' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], - 'missingdatafunc' => ['type' => API_INT32, 'in' => implode(',', [SVG_GRAPH_MISSING_DATA_NONE, SVG_GRAPH_MISSING_DATA_CONNECTED, SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO])], - 'axisy' => ['type' => API_INT32, 'in' => implode(',', [GRAPH_YAXIS_SIDE_LEFT, GRAPH_YAXIS_SIDE_RIGHT])], - 'timeshift' => ['type' => API_TIME_UNIT, 'in' => implode(':', [ZBX_MIN_TIMESHIFT, ZBX_MAX_TIMESHIFT])] - ]]); - $this->setDefault([]); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_OBJECTS, 'fields' => [ + 'hosts' => ['type' => API_STRINGS_UTF8, 'flags' => API_REQUIRED], + 'items' => ['type' => API_STRINGS_UTF8, 'flags' => API_REQUIRED], + 'color' => ['type' => API_COLOR], + 'type' => ['type' => API_INT32, 'in' => implode(',', [SVG_GRAPH_TYPE_LINE, SVG_GRAPH_TYPE_POINTS, SVG_GRAPH_TYPE_STAIRCASE, SVG_GRAPH_TYPE_BAR])], + 'width' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], + 'pointsize' => ['type' => API_INT32, 'in' => implode(',', range(1, 10))], + 'transparency' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], + 'fill' => ['type' => API_INT32, 'in' => implode(',', range(0, 10))], + 'missingdatafunc' => ['type' => API_INT32, 'in' => implode(',', [SVG_GRAPH_MISSING_DATA_NONE, SVG_GRAPH_MISSING_DATA_CONNECTED, SVG_GRAPH_MISSING_DATA_TREAT_AS_ZERO])], + 'axisy' => ['type' => API_INT32, 'in' => implode(',', [GRAPH_YAXIS_SIDE_LEFT, GRAPH_YAXIS_SIDE_RIGHT])], + 'timeshift' => ['type' => API_TIME_UNIT, 'in' => implode(':', [ZBX_MIN_TIMESHIFT, ZBX_MAX_TIMESHIFT])] + ]]); + } + + public function getOverrideOptions(): array { + return ['color', 'width', 'type', 'transparency', 'fill', 'pointsize', 'missingdatafunc', 'axisy', 'timeshift']; } - /** - * Set field values for the overrides. - * - * @return $this - */ - public function setValue($value) { + public function setValue($value): self { $overrides = []; foreach ((array) $value as $override) { @@ -65,17 +65,17 @@ class CWidgetFieldGraphOverride extends CWidgetField { return parent::setValue($overrides); } - /** - * Set additional flags, which can be used in configuration form. - * - * @param int $flags - * - * @return $this - */ - public function setFlags($flags) { + public static function getDefaults(): array { + return [ + 'hosts' => [], + 'items' => [] + ]; + } + + public function setFlags(int $flags): self { parent::setFlags($flags); - if ($flags & self::FLAG_NOT_EMPTY) { + if (($flags & self::FLAG_NOT_EMPTY) !== 0) { $strict_validation_rules = $this->getValidationRules(); self::setValidationRuleFlag($strict_validation_rules['fields']['hosts'], API_NOT_EMPTY); self::setValidationRuleFlag($strict_validation_rules['fields']['items'], API_NOT_EMPTY); @@ -84,47 +84,21 @@ class CWidgetFieldGraphOverride extends CWidgetField { $this->setStrictValidationRules($strict_validation_rules); } else { - $this->setStrictValidationRules(null); + $this->setStrictValidationRules(); } return $this; } - /** - * Default values filled in newly created data set or used as unspecified values. - * - * @return array - */ - public static function getDefaults() { - return [ - 'hosts' => [], - 'items' => [] - ]; - } - - /** - * Returns array of supported override options. - * - * @return array - */ - public static function getOverrideOptions() { - return ['color', 'width', 'type', 'transparency', 'fill', 'pointsize', 'missingdatafunc', 'axisy', 'timeshift']; - } - - /** - * @param bool $strict - * - * @return array - */ public function validate(bool $strict = false): array { $errors = parent::validate($strict); $value = $this->getValue(); - $label = ($this->label === null) ? $this->name : $this->label; + $label = $this->label ?? $this->name; // Validate options. if (!$errors && $strict) { foreach ($value as $index => $overrides) { - if (!array_intersect(self::getOverrideOptions(), array_keys($overrides))) { + if (!array_intersect($this->getOverrideOptions(), array_keys($overrides))) { $errors[] = _s('Invalid parameter "%1$s": %2$s.', $label.'/'.($index + 1), _('at least one override option must be specified') ); @@ -136,14 +110,7 @@ class CWidgetFieldGraphOverride extends CWidgetField { return $errors; } - /** - * Prepares array entry for widget field, ready to be passed to CDashboard API functions. - * Reference is needed here to avoid array merging in CWidgetForm::fieldsToApi method. With large number of widget - * fields it causes significant performance decrease. - * - * @param array $widget_fields reference to Array of widget fields. - */ - public function toApi(array &$widget_fields = []) { + public function toApi(array &$widget_fields = []): void { $value = $this->getValue(); foreach ($value as $index => $val) { @@ -163,7 +130,7 @@ class CWidgetFieldGraphOverride extends CWidgetField { ]; } - foreach (self::getOverrideOptions() as $opt) { + foreach ($this->getOverrideOptions() as $opt) { if (array_key_exists($opt, $val)) { $widget_fields[] = [ 'type' => ($opt === 'color' || $opt === 'timeshift') diff --git a/ui/include/classes/widgets/fields/CWidgetFieldHidden.php b/ui/include/classes/widgets/fields/CWidgetFieldHidden.php deleted file mode 100644 index d1d8bf21b54..00000000000 --- a/ui/include/classes/widgets/fields/CWidgetFieldHidden.php +++ /dev/null @@ -1,35 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CWidgetFieldHidden extends CWidgetField { - - /** - * Hidden widget field. Will not be displayed for user. Can contain string, int or id type value. - * - * @param string $name field name in form - * @param int $save_type ZBX_WIDGET_FIELD_TYPE_ constant. Defines how field will be saved in database. - */ - public function __construct($name, $save_type) { - parent::__construct($name, null); - - $this->setSaveType($save_type); - } -} diff --git a/ui/include/classes/widgets/fields/CWidgetFieldHostPatternSelect.php b/ui/include/classes/widgets/fields/CWidgetFieldHostPatternSelect.php index d988491be0d..165cdcc2d20 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldHostPatternSelect.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldHostPatternSelect.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,36 +19,23 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldHostPatternSelect extends CWidgetField { - private $placeholder; + public const DEFAULT_VALUE = []; - /** - * Textarea widget field. - * - * @param string $name field name in form - * @param string $label label for the field in form - */ - public function __construct($name, $label) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setDefault([]); - - /* - * Set validation rules bypassing a parent::setSaveType to skip validation of length. - * Save type is set in self::toApi method for each string field separately. - */ - $this->setValidationRules(['type' => API_STRINGS_UTF8]); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setValidationRules(['type' => API_STRINGS_UTF8]); } - /** - * Prepares array entry for widget field, ready to be passed to CDashboard API functions. - * Reference is needed here to avoid array merging in CWidgetForm::fieldsToApi method. With large number of widget - * fields it causes significant performance decrease. - * - * @param array $widget_fields reference to array of widget fields. - */ - public function toApi(array &$widget_fields = []) { + public function toApi(array &$widget_fields = []): void { $value = $this->getValue(); if ($value !== $this->default) { @@ -61,20 +48,4 @@ class CWidgetFieldHostPatternSelect extends CWidgetField { } } } - - public function setPlaceholder($placeholder) { - $this->placeholder = $placeholder; - - return $this; - } - - public function getPlaceholder() { - return $this->placeholder; - } - - public function getJavascript() { - $fieldid = zbx_formatDomId($this->getName().'[]'); - - return 'jQuery("#'.$fieldid.'").multiSelect(jQuery("#'.$fieldid.'").data("params"));'; - } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldIntegerBox.php b/ui/include/classes/widgets/fields/CWidgetFieldIntegerBox.php index a246dfda320..32c12e43393 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldIntegerBox.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldIntegerBox.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,47 +19,33 @@ **/ -/** - * Widget Field for integer values. - */ -class CWidgetFieldIntegerBox extends CWidgetField { +namespace Zabbix\Widgets\Fields; - /** - * Allowed min value - * - * @var int - */ - private $min; +use Zabbix\Widgets\CWidgetField; - /** - * Allowed max value - * - * @var int - */ - private $max; +class CWidgetFieldIntegerBox extends CWidgetField { + + private int $max; /** - * A numeric box widget field. - * - * @param string $name field name in form - * @param string $label label for the field in form - * @param int $min minimal allowed value (this included) - * @param int $max maximal allowed value (this included) + * @param int $min Minimal allowed value. + * @param int $max Maximal allowed value. */ - public function __construct($name, $label, $min = 0, $max = ZBX_MAX_INT32) { + public function __construct(string $name, string $label = null, int $min = 0, int $max = ZBX_MAX_INT32) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32); - $this->min = $min; $this->max = $max; - $this->setExValidationRules(['in' => $this->min.':'.$this->max]); - } - public function getMaxLength() { - return strlen((string) $this->max); + $this + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32) + ->setExValidationRules(['in' => $min.':'.$this->max]); } - public function setValue($value) { + public function setValue($value): self { return parent::setValue((int) $value); } + + public function getMaxLength(): int { + return strlen((string) $this->max); + } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldLatLng.php b/ui/include/classes/widgets/fields/CWidgetFieldLatLng.php index 798a8a21d92..60494f70cf4 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldLatLng.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldLatLng.php @@ -19,39 +19,23 @@ **/ -class CWidgetFieldLatLng extends CWidgetField { +namespace Zabbix\Widgets\Fields; - /** - * @var string - */ - private $placeholder; +use Zabbix\Widgets\CWidgetField; - /** - * @var int - */ - private $width; +class CWidgetFieldLatLng extends CWidgetField { + + public const DEFAULT_VALUE = ''; /** * Latitude, longitude and zoom level input text box widget field. - * - * @param string $name field name in form - * @param string $label label for the field in form */ - public function __construct($name, $label) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_LAT_LNG_ZOOM, 'length' => 255]); - $this->placeholder = '40.6892494,-74.0466891'; - $this->width = ZBX_TEXTAREA_MEDIUM_WIDTH; - $this->setDefault(''); - } - - public function getPlaceholder() { - return $this->placeholder; - } - - public function getWidth() { - return $this->width; + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_LAT_LNG_ZOOM, 'length' => 255]); } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMsHost.php b/ui/include/classes/widgets/fields/CWidgetFieldMsHost.php deleted file mode 100644 index d168170ee68..00000000000 --- a/ui/include/classes/widgets/fields/CWidgetFieldMsHost.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CWidgetFieldMsHost extends CWidgetFieldMs { - - /** - * ID for Host group Multiselect element used to prefill Application PoPup Host group filter. - * Analog for multiselect filter_preselect_fields['hostgroups'] property. - * - * @var string (nullable) ID for Multiselect element. - */ - protected $filter_preselect; - - /** - * Create widget field for Host selection - * - * @param string $name field name in form - * @param string $label label for the field in form - */ - public function __construct(string $name, string $label) { - parent::__construct($name, $label); - - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_HOST); - } - - public function setFilterPreselect(string $id) { - $this->filter_preselect = $id; - return $this; - } - - public function getFilterPreselect() { - return $this->filter_preselect; - } -} diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMs.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelect.php index 5dc9946c683..45984fa57e4 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldMs.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelect.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,106 +19,72 @@ **/ -class CWidgetFieldMs extends CWidgetField { +namespace Zabbix\Widgets\Fields; - /** - * Is selecting multiple objects or a single one? - * - * @var bool - */ - protected $multiple = true; +use Zabbix\Widgets\CWidgetField; - /** - * Additional filter parameters used for data selection. - * - * @var array - */ - protected $filter_parameters = []; +abstract class CWidgetFieldMultiSelect extends CWidgetField { - /** - * Multiselect widget field. - * Will create text box field with select button, that will allow to select specified resource. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. - */ - public function __construct($name, $label) { + // Is selecting multiple objects or a single one? + private bool $is_multiple = true; + + // Additional filter parameters used for data selection. + protected array $filter_parameters = []; + + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); $this->setDefault([]); } - /** - * Set additional validation flags. - * - * @param int $flags - * - * @return CWidgetFieldMs - */ - public function setFlags($flags) { + public function setValue($value): self { + $this->value = (array) $value; + + return $this; + } + + public function setFlags(int $flags): self { parent::setFlags($flags); - if ($flags & self::FLAG_NOT_EMPTY) { + if (($flags & self::FLAG_NOT_EMPTY) !== 0) { $strict_validation_rules = $this->getValidationRules(); self::setValidationRuleFlag($strict_validation_rules, API_NOT_EMPTY); $this->setStrictValidationRules($strict_validation_rules); } else { - $this->setStrictValidationRules(null); + $this->setStrictValidationRules(); } return $this; } /** - * @return CWidgetFieldMs - */ - public function setValue($value) { - $this->value = (array) $value; - - return $this; - } - - /** * Is selecting multiple values or a single value? - * - * @return bool */ - public function isMultiple() { - return $this->multiple; + public function isMultiple(): bool { + return $this->is_multiple; } /** * Set field to multiple objects mode. - * - * @param bool $multiple - * - * @return CWidgetFieldMs */ - public function setMultiple($multiple) { - $this->multiple = $multiple; + public function setMultiple(bool $is_multiple = true): self { + $this->is_multiple = $is_multiple; return $this; } /** * Get additional filter parameters. - * - * @return array */ - public function getFilterParameters() { + public function getFilterParameters(): array { return $this->filter_parameters; } /** * Set an additional filter parameter for data selection. - * - * @param string $name - * @param mixed $value - * - * @return CWidgetFieldMs */ - public function setFilterParameter($name, $value) { + public function setFilterParameter(string $name, $value): self { $this->filter_parameters[$name] = $value; return $this; diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMsGraph.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectGraph.php index 2904ebe8c77..756ed0be4e2 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldMsGraph.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectGraph.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,22 +19,20 @@ **/ -class CWidgetFieldMsGraph extends CWidgetFieldMs { +namespace Zabbix\Widgets\Fields; - public function __construct($name, $label, $hostid = null) { +class CWidgetFieldMultiSelectGraph extends CWidgetFieldMultiSelect { + + public function __construct(string $name, string $label = null, $hostid = null) { parent::__construct($name, $label); $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_GRAPH); if ($hostid === null) { - $this->filter_parameters += [ - 'real_hosts' => true - ]; + $this->setFilterParameter('real_hosts', true); } else { - $this->filter_parameters += [ - 'hostid' => $hostid - ]; + $this->setFilterParameter('hostid', $hostid); } } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMsGraphPrototype.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectGraphPrototype.php index 10e63026729..1d5736c8e12 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldMsGraphPrototype.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectGraphPrototype.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,22 +19,20 @@ **/ -class CWidgetFieldMsGraphPrototype extends CWidgetFieldMs { +namespace Zabbix\Widgets\Fields; - public function __construct($name, $label, $hostid = null) { +class CWidgetFieldMultiSelectGraphPrototype extends CWidgetFieldMultiSelect { + + public function __construct(string $name, string $label = null, $hostid = null) { parent::__construct($name, $label); $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_GRAPH_PROTOTYPE); if ($hostid === null) { - $this->filter_parameters += [ - 'real_hosts' => true - ]; + $this->setFilterParameter('real_hosts', true); } else { - $this->filter_parameters += [ - 'hostid' => $hostid - ]; + $this->setFilterParameter('hostid', $hostid); } } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMsGroup.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectGroup.php index dae91733aac..9c9e7743d34 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldMsGroup.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectGroup.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,9 +19,11 @@ **/ -class CWidgetFieldMsGroup extends CWidgetFieldMs { +namespace Zabbix\Widgets\Fields; - public function __construct($name, $label) { +class CWidgetFieldMultiSelectGroup extends CWidgetFieldMultiSelect { + + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_GROUP); diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectHost.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectHost.php new file mode 100644 index 00000000000..65987d9253a --- /dev/null +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectHost.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Zabbix\Widgets\Fields; + +class CWidgetFieldMultiSelectHost extends CWidgetFieldMultiSelect { + + public function __construct(string $name, string $label = null) { + parent::__construct($name, $label); + + $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_HOST); + } +} diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMsItem.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectItem.php index 9ba02f81d27..ad25de8d77f 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldMsItem.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectItem.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,22 +19,20 @@ **/ -class CWidgetFieldMsItem extends CWidgetFieldMs { +namespace Zabbix\Widgets\Fields; - public function __construct($name, $label, $hostid = null) { +class CWidgetFieldMultiSelectItem extends CWidgetFieldMultiSelect { + + public function __construct(string $name, string $label = null, $hostid = null) { parent::__construct($name, $label); $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_ITEM); if ($hostid === null) { - $this->filter_parameters += [ - 'real_hosts' => true - ]; + $this->setFilterParameter('real_hosts', true); } else { - $this->filter_parameters += [ - 'hostid' => $hostid - ]; + $this->setFilterParameter('hostid', $hostid); } } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMsItemPrototype.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectItemPrototype.php index c380af8124a..d29b5435020 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldMsItemPrototype.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectItemPrototype.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,22 +19,20 @@ **/ -class CWidgetFieldMsItemPrototype extends CWidgetFieldMs { +namespace Zabbix\Widgets\Fields; - public function __construct($name, $label, $hostid = null) { +class CWidgetFieldMultiSelectItemPrototype extends CWidgetFieldMultiSelect { + + public function __construct(string $name, string $label = null, $hostid = null) { parent::__construct($name, $label); $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_ITEM_PROTOTYPE); if ($hostid === null) { - $this->filter_parameters += [ - 'real_hosts' => true - ]; + $this->setFilterParameter('real_hosts', true); } else { - $this->filter_parameters += [ - 'hostid' => $hostid - ]; + $this->setFilterParameter('hostid', $hostid); } } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMsService.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectService.php index ab88ce01186..7d7ed555588 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldMsService.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectService.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,15 +19,11 @@ **/ -class CWidgetFieldMsService extends CWidgetFieldMs { +namespace Zabbix\Widgets\Fields; - /** - * Create widget field for Service selection - * - * @param string $name field name in form - * @param string $label label for the field in form - */ - public function __construct($name, $label) { +class CWidgetFieldMultiSelectService extends CWidgetFieldMultiSelect { + + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_SERVICE); diff --git a/ui/include/classes/widgets/fields/CWidgetFieldMsSla.php b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectSla.php index 0e77590975a..55cc0dd2667 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldMsSla.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldMultiSelectSla.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,15 +19,11 @@ **/ -class CWidgetFieldMsSla extends CWidgetFieldMs { +namespace Zabbix\Widgets\Fields; - /** - * Create widget field for SLA selection - * - * @param string $name field name in form - * @param string $label label for the field in form - */ - public function __construct($name, $label) { +class CWidgetFieldMultiSelectSla extends CWidgetFieldMultiSelect { + + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_SLA); diff --git a/ui/include/classes/widgets/fields/CWidgetFieldNavTree.php b/ui/include/classes/widgets/fields/CWidgetFieldNavTree.php index 1fc163f4b9a..6ff384232e3 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldNavTree.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldNavTree.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,41 +19,45 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldNavTree extends CWidgetField { - /** - * Create widget field for Tags selection. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. - */ - public function __construct($name, $label) { + public const DEFAULT_VALUE = []; + + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_OBJECTS, 'flags' => API_PRESERVE_KEYS, 'fields' => [ - 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => 255], - 'order' => ['type' => API_INT32, 'in' => '1:'.ZBX_MAX_INT32, 'default' => 1], - 'parent' => ['type' => API_INT32, 'in' => '0:'.ZBX_MAX_INT32, 'default' => 0], - 'sysmapid' => ['type' => API_ID, 'default' => '0'] - ]]); - $this->setDefault([]); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_OBJECTS, 'flags' => API_PRESERVE_KEYS, 'fields' => [ + 'name' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED | API_NOT_EMPTY, 'length' => 255], + 'order' => ['type' => API_INT32, 'in' => '1:'.ZBX_MAX_INT32, 'default' => 1], + 'parent' => ['type' => API_INT32, 'in' => '0:'.ZBX_MAX_INT32, 'default' => 0], + 'sysmapid' => ['type' => API_ID, 'default' => '0'] + ]]); } - public function setValue($value) { + public function setValue($value): self { $this->value = (array) $value; return $this; } - /** - * Prepares array entry for widget field, ready to be passed to CDashboard API functions. - * Reference is needed here to avoid array merging in CWidgetForm::fieldsToApi method. With large number of widget - * fields it causes significant performance decrease. - * - * @param array $widget_fields reference to Array of widget fields. - */ - public function toApi(array &$widget_fields = []) { + public function validate(bool $strict = false): array { + $errors = parent::validate($strict); + + if (!$errors) { + $this->setValue(self::validateNavTree($this->getValue(), $errors)); + } + + return $errors; + } + + public function toApi(array &$widget_fields = []): void { $value = $this->getValue(); foreach ($value as $index => $val) { @@ -96,13 +100,8 @@ class CWidgetFieldNavTree extends CWidgetField { /** * Check and fix the tree of the maps. - * - * @param array $navtree_items - * @param string $navtree_items[<id>]['parent'] - * - * @return array */ - static private function validateNavTree(array $navtree_items, array &$errors) { + private static function validateNavTree(array $navtree_items, array &$errors): array { // Check for incorrect parent IDs. foreach ($navtree_items as $fieldid => &$navtree_item) { if ($navtree_item['parent'] != 0 && !array_key_exists($navtree_item['parent'], $navtree_items)) { @@ -115,7 +114,7 @@ class CWidgetFieldNavTree extends CWidgetField { unset($navtree_item); // Find and fix circular dependencies. - foreach ($navtree_items as $fieldid => $navtree_item) { + foreach ($navtree_items as $navtree_item) { $parentid = $navtree_item['parent']; $parentids = [$parentid => true]; @@ -133,19 +132,4 @@ class CWidgetFieldNavTree extends CWidgetField { return $navtree_items; } - - /** - * @param bool $strict - * - * @return array - */ - public function validate(bool $strict = false): array { - $errors = parent::validate($strict); - - if (!$errors) { - $this->setValue(self::validateNavTree($this->getValue(), $errors)); - } - - return $errors; - } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldNumericBox.php b/ui/include/classes/widgets/fields/CWidgetFieldNumericBox.php index 4981289b46f..9aa6e68dcf6 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldNumericBox.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldNumericBox.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,50 +19,24 @@ **/ -/** - * Widget Field for numeric data. - */ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldNumericBox extends CWidgetField { - private $placeholder; - private $width; + public const DEFAULT_VALUE = ''; /** * A numeric box widget field. * Supported signed decimal values with suffix (KMGTsmhdw). - * - * @param string $name field name in form - * @param string $label label for the field in form */ - public function __construct($name, $label) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_NUMERIC, 'length' => 255]); - $this->setDefault(''); - } - - public function getMaxLength() { - return strlen((string) $this->max); - } - - public function setPlaceholder($placeholder) { - $this->placeholder = $placeholder; - - return $this; - } - - public function getPlaceholder() { - return $this->placeholder; - } - - public function setWidth($width) { - $this->width = $width; - - return $this; - } - - public function getWidth() { - return $this->width; + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_NUMERIC, 'length' => 255]); } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldRadioButtonList.php b/ui/include/classes/widgets/fields/CWidgetFieldRadioButtonList.php index 4764301cf9b..6da247c53e7 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldRadioButtonList.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldRadioButtonList.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,41 +19,34 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldRadioButtonList extends CWidgetField { - private $values; - private $modern = false; + private array $values; /** * Radio button widget field. Can use both, string and integer type keys. * - * @param string $name field name in form - * @param string $label label for the field in form - * @param array $values key/value pairs of radio button values. Key - saved in DB. Value - visible to user. + * @param array $values key/value pairs of radio button values. Key - saved in DB. Value - visible to user. */ - public function __construct($name, $label, $values) { + public function __construct(string $name, string $label = null, array $values = []) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32); $this->values = $values; - $this->setExValidationRules(['in' => implode(',', array_keys($this->values))]); - } - - public function setValue($value) { - return parent::setValue((int) $value); - } - - public function setModern($modern) { - $this->modern = $modern; - return $this; + $this + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32) + ->setExValidationRules(['in' => implode(',', array_keys($this->values))]); } - public function getModern() { - return $this->modern; + public function getValues(): array { + return $this->values; } - public function getValues() { - return $this->values; + public function setValue($value): self { + return parent::setValue((int) $value); } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldRangeControl.php b/ui/include/classes/widgets/fields/CWidgetFieldRangeControl.php index 43246743f36..8e92698fac2 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldRangeControl.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldRangeControl.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,65 +19,48 @@ **/ -/** - * Widget Field for numeric box - */ -class CWidgetFieldRangeControl extends CWidgetField { +namespace Zabbix\Widgets\Fields; - /** - * Allowed min value - * - * @var int - */ - private $min; +use Zabbix\Widgets\CWidgetField; - /** - * Allowed max value - * - * @var int - */ - private $max; +class CWidgetFieldRangeControl extends CWidgetField { - /** - * Step value - * - * @var int - */ - private $step; + private int $min; + private int $max; + private int $step; /** - * A numeric box widget field. - * - * @param string $name field name in form - * @param string $label label for the field in form - * @param int $min minimal allowed value (this included) - * @param int $max maximal allowed value (this included) - * @param int $step step value + * @param int $min Minimal allowed value. + * @param int $max Maximal allowed value. */ - public function __construct($name, $label, $min = 0, $max = ZBX_MAX_INT32, $step = 1) { + public function __construct(string $name, string $label = null, int $min = 0, int $max = ZBX_MAX_INT32, + int $step = 1) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32); $this->min = $min; $this->max = $max; $this->step = $step; - $this->setExValidationRules(['in' => $this->min.':'.$this->max]); + + $this + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32) + ->setExValidationRules(['in' => $this->min.':'.$this->max]); } - public function setValue($value) { + public function setValue($value): self { $this->value = (int) $value; + return $this; } - public function getMin() { + public function getMin(): int { return $this->min; } - public function getMax() { + public function getMax(): int { return $this->max; } - public function getStep() { + public function getStep(): int { return $this->step; } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldReference.php b/ui/include/classes/widgets/fields/CWidgetFieldReference.php index 0505d00e490..a4445c68857 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldReference.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldReference.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,10 +19,16 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldReference extends CWidgetField { + public const DEFAULT_VALUE = ''; + // This field name is reserved by Zabbix for this particular use case. See comments below. - const FIELD_NAME = 'reference'; + public const FIELD_NAME = 'reference'; /** * Reference widget field. If added to widget, will generate unique value across the dashboard @@ -33,19 +39,17 @@ class CWidgetFieldReference extends CWidgetField { * All reference fields for all widgets on dashboard should share the same name. * It is needed to make possible search if value is not taken by some other widget in same dashboard. */ - parent::__construct(self::FIELD_NAME, null); + parent::__construct(self::FIELD_NAME); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); } /** - * Set field value. - * * @param string $value Reference value. Only numeric characters allowed. - * - * @return CWidgetFieldReference */ - public function setValue($value) { + public function setValue($value): self { if ($value === '' || ctype_alnum($value)) { $this->value = $value; } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldSelect.php b/ui/include/classes/widgets/fields/CWidgetFieldSelect.php index c9380869366..055a64ad840 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldSelect.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldSelect.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,38 +19,37 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldSelect extends CWidgetField { - private $values; + public const DEFAULT_VALUE = null; + + private array $values; /** * CSelect widget field. Can use both, string and integer type keys. * - * @param string $name Field name in form - * @param string $label Label for the field in form * @param array $values Key/value pairs of select option values. Key - saved in DB. Value - visible to user. */ - public function __construct($name, $label, $values) { + public function __construct(string $name, string $label, array $values) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32); $this->values = $values; - $this->setExValidationRules(['in' => implode(',', array_keys($this->values))]); + + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_INT32) + ->setExValidationRules(['in' => implode(',', array_keys($this->values))]); } - public function setValue($value) { + public function setValue($value): self { return parent::setValue((int) $value); } - public function getValues() { + public function getValues(): array { return $this->values; } - - public function setAction($action) { - throw new RuntimeException(sprintf('Method is not implemented: "%s".', __METHOD__)); - } - - public function getAction() { - throw new RuntimeException(sprintf('Method is not implemented: "%s".', __METHOD__)); - } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldSelectResource.php b/ui/include/classes/widgets/fields/CWidgetFieldSelectResource.php index 06c7bec9ad6..1cc86819715 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldSelectResource.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldSelectResource.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,78 +19,80 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldSelectResource extends CWidgetField { - protected $srctbl; - protected $srcfld1; - protected $srcfld2; - protected $dstfld1; - protected $dstfld2; - protected $resource_type; + public const RESOURCE_TYPE_SYSMAP = 1; + + public const DEFAULT_VALUE = '0'; + + private string $resource_type; + + private array $popup_options = [ + 'srctbl' => null, + 'srcfld1' => null, + 'srcfld2' => null, + 'dstfld1' => null, + 'dstfld2' => null, + 'dstfrm' => null + ]; /** * Select resource type widget field. Will create text box field with select button, - * that will allow to select specified resource. - * - * @param string $name field name in form - * @param string $label label for the field in form - * @param int $resource_type WIDGET_FIELD_SELECT_RES_ constant. + * that will allow selecting specified resource. */ - public function __construct($name, $label, $resource_type) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); + $this->popup_options = array_merge($this->popup_options, [ + 'dstfld1' => $this->name, + 'dstfld2' => $this->name.'_caption' + ]); + + $this->setDefault(self::DEFAULT_VALUE); + } + + public function getResourceType(): int { + return $this->resource_type; + } + + public function setResourceType(int $resource_type): self { $this->resource_type = $resource_type; - switch ($resource_type) { - case WIDGET_FIELD_SELECT_RES_SYSMAP: - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_MAP); - $this->srctbl = 'sysmaps'; - $this->srcfld1 = 'sysmapid'; - $this->srcfld2 = 'name'; - break; + if ($this->resource_type == self::RESOURCE_TYPE_SYSMAP) { + $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_MAP); + + $this->popup_options = array_merge($this->popup_options, [ + 'srctbl' => 'sysmaps', + 'srcfld1' => 'sysmapid', + 'srcfld2' => 'name' + ]); } - $this->dstfld1 = $name; - $this->dstfld2 = $this->name.'_caption'; - $this->setDefault('0'); + return $this; } - /** - * Set additional flags, which can be used in configuration form. - * - * @param int $flags - * - * @return $this - */ - public function setFlags($flags) { + public function setFlags(int $flags): self { parent::setFlags($flags); - if ($flags & self::FLAG_NOT_EMPTY) { + if (($flags & self::FLAG_NOT_EMPTY) !== 0) { $strict_validation_rules = $this->getValidationRules(); self::setValidationRuleFlag($strict_validation_rules, API_NOT_EMPTY); $this->setStrictValidationRules($strict_validation_rules); } else { - $this->setStrictValidationRules(null); + $this->setStrictValidationRules(); } return $this; } - public function getResourceType() { - return $this->resource_type; - } - - public function getPopupOptions($dstfrm) { - $popup_options = [ - 'srctbl' => $this->srctbl, - 'srcfld1' => $this->srcfld1, - 'srcfld2' => $this->srcfld2, - 'dstfld1' => $this->dstfld1, - 'dstfld2' => $this->dstfld2, - 'dstfrm' => $dstfrm - ]; - - return $popup_options; + public function getPopupOptions(string $form_name): array { + return array_merge($this->popup_options, [ + 'dstfrm' => $form_name + ]); } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldSeverities.php b/ui/include/classes/widgets/fields/CWidgetFieldSeverities.php index 5c661cd673a..7e72d150d16 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldSeverities.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldSeverities.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,9 +19,11 @@ **/ +namespace Zabbix\Widgets\Fields; + class CWidgetFieldSeverities extends CWidgetFieldCheckBoxList { - public function __construct($name, $label) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); $this->setExValidationRules( diff --git a/ui/include/classes/widgets/fields/CWidgetFieldTags.php b/ui/include/classes/widgets/fields/CWidgetFieldTags.php index 528af29a696..febcc6c862f 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldTags.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldTags.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,36 +19,30 @@ **/ -class CWidgetFieldTags extends CWidgetField { +namespace Zabbix\Widgets\Fields; - /** - * Create widget field for Tags selection. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. - */ - public function __construct($name, $label) { - parent::__construct($name, $label); +use Zabbix\Widgets\CWidgetField; - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_OBJECTS, 'fields' => [ - 'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => 255], - 'operator' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [TAG_OPERATOR_LIKE, TAG_OPERATOR_EQUAL, TAG_OPERATOR_NOT_LIKE, TAG_OPERATOR_NOT_EQUAL, TAG_OPERATOR_EXISTS, TAG_OPERATOR_NOT_EXISTS])], - 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => 255] - ]]); - $this->setDefault([]); - } +class CWidgetFieldTags extends CWidgetField { - public function setValue($value) { - $this->value = (array) $value; + public const DEFAULT_VALUE = []; + public const DEFAULT_TAG = ['tag' => '', 'operator' => TAG_OPERATOR_LIKE, 'value' => '']; - return $this; + public function __construct(string $name, string $label = null) { + parent::__construct($name, $label); + + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_OBJECTS, 'fields' => [ + 'tag' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => 255], + 'operator' => ['type' => API_INT32, 'flags' => API_REQUIRED, 'in' => implode(',', [TAG_OPERATOR_LIKE, TAG_OPERATOR_EQUAL, TAG_OPERATOR_NOT_LIKE, TAG_OPERATOR_NOT_EQUAL, TAG_OPERATOR_EXISTS, TAG_OPERATOR_NOT_EXISTS])], + 'value' => ['type' => API_STRING_UTF8, 'flags' => API_REQUIRED, 'length' => 255] + ]]); } /** * Get field value. If no value is set, will return default value. - * - * @return mixed */ public function getValue() { $value = parent::getValue(); @@ -62,35 +56,13 @@ class CWidgetFieldTags extends CWidgetField { return $value; } - /** - * Add dynamic row script and fix the distance between AND/OR buttons and tag inputs below them. - * - * @return string - */ - public function getJavascript() { - return 'var tags_table = jQuery("#tags_table_'.$this->getName().'");'. - - 'tags_table'. - '.dynamicRows({template: "#tag-row-tmpl"})'. - '.on("afteradd.dynamicRows", function() {'. - 'var rows = this.querySelectorAll(".form_row");'. - 'new CTagFilterItem(rows[rows.length - 1]);'. - '});'. + public function setValue($value): self { + $this->value = (array) $value; - // Init existing fields once loaded. - 'document.querySelectorAll("#tags_table_'.$this->getName().' .form_row").forEach(row => {'. - 'new CTagFilterItem(row);'. - '});'; + return $this; } - /** - * Prepares array entry for widget field, ready to be passed to CDashboard API functions. - * Reference is needed here to avoid array merging in CWidgetForm::fieldsToApi method. With large number of widget - * fields it causes significant performance decrease. - * - * @param array $widget_fields reference to Array of widget fields. - */ - public function toApi(array &$widget_fields = []) { + public function toApi(array &$widget_fields = []): void { $value = $this->getValue(); foreach ($value as $index => $val) { diff --git a/ui/include/classes/widgets/fields/CWidgetFieldTextArea.php b/ui/include/classes/widgets/fields/CWidgetFieldTextArea.php index 6d3edfec74a..5d9b8633e58 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldTextArea.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldTextArea.php @@ -19,53 +19,34 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldTextArea extends CWidgetField { - private $width; + public const DEFAULT_VALUE = ''; - /** - * Textarea widget field. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. - */ - public function __construct($name, $label) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setDefault(''); - $this->width = ZBX_TEXTAREA_STANDARD_WIDTH; + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); } - /** - * Set additional flags, which can be used in configuration form. - * - * @param int $flags - * - * @return $this - */ - public function setFlags($flags) { + public function setFlags(int $flags): self { parent::setFlags($flags); - if ($flags & self::FLAG_NOT_EMPTY) { + if (($flags & self::FLAG_NOT_EMPTY) !== 0) { $strict_validation_rules = $this->getValidationRules(); self::setValidationRuleFlag($strict_validation_rules, API_NOT_EMPTY); $this->setStrictValidationRules($strict_validation_rules); } else { - $this->setStrictValidationRules(null); + $this->setStrictValidationRules(); } return $this; } - - public function setWidth($width) { - $this->width = $width; - - return $this; - } - - public function getWidth() { - return $this->width; - } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldTextBox.php b/ui/include/classes/widgets/fields/CWidgetFieldTextBox.php index 1dbeaddb245..6932d86f9b1 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldTextBox.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldTextBox.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,64 +19,40 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldTextBox extends CWidgetField { - private $placeholder; - private $width; + public const DEFAULT_VALUE = ''; /** * Text box widget field. - * - * @param string $name field name in form - * @param string $label label for the field in form */ - public function __construct($name, $label) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setDefault(''); - $this->width = ZBX_TEXTAREA_STANDARD_WIDTH; + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); } /** * Set additional flags, which can be used in configuration form. - * - * @param int $flags - * - * @return $this */ - public function setFlags($flags) { + public function setFlags(int $flags): self { parent::setFlags($flags); - if ($flags & self::FLAG_NOT_EMPTY) { + if (($flags & self::FLAG_NOT_EMPTY) !== 0) { $strict_validation_rules = $this->getValidationRules(); self::setValidationRuleFlag($strict_validation_rules, API_NOT_EMPTY); $this->setStrictValidationRules($strict_validation_rules); } else { - $this->setStrictValidationRules(null); + $this->setStrictValidationRules(); } return $this; } - - public function setPlaceholder($placeholder) { - $this->placeholder = $placeholder; - - return $this; - } - - public function getPlaceholder() { - return $this->placeholder; - } - - public function setWidth($width) { - $this->width = $width; - - return $this; - } - - public function getWidth() { - return $this->width; - } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldThresholds.php b/ui/include/classes/widgets/fields/CWidgetFieldThresholds.php index dac9b93f543..0988fb29143 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldThresholds.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldThresholds.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,29 +19,34 @@ **/ +namespace Zabbix\Widgets\Fields; + +use CArrayHelper, + CNumberParser, + CParser; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldThresholds extends CWidgetField { - public const THRESHOLDS_TABLE_ID = '%s-table'; - public const THRESHOLDS_ROW_TMPL_ID = '%s-row-tmpl'; + public const DEFAULT_VALUE = []; /** * Create widget field for Thresholds selection. - * - * @param string $name Field name in form. - * @param string $label Label for the field in form. */ - public function __construct($name, $label) { + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_OBJECTS, 'uniq' => [['threshold']], 'fields' => [ - 'color' => ['type' => API_COLOR, 'flags' => API_REQUIRED | API_NOT_EMPTY], - 'threshold' => ['type' => API_NUMERIC, 'flags' => API_REQUIRED] - ]]); - $this->setDefault([]); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_OBJECTS, 'uniq' => [['threshold']], 'fields' => [ + 'color' => ['type' => API_COLOR, 'flags' => API_REQUIRED | API_NOT_EMPTY], + 'threshold' => ['type' => API_NUMERIC, 'flags' => API_REQUIRED] + ]]); } - public function setValue($value) { + public function setValue($value): self { $thresholds = []; foreach ($value as $threshold) { @@ -81,29 +86,7 @@ class CWidgetFieldThresholds extends CWidgetField { return []; } - public function getJavascript() { - return 'var thresholds_table = jQuery("#'.sprintf(self::THRESHOLDS_TABLE_ID, $this->getName()).'");'. - 'thresholds_table'. - '.dynamicRows({template: "#'.sprintf(self::THRESHOLDS_ROW_TMPL_ID, $this->getName()).'"})'. - '.on("afteradd.dynamicRows", function(opt) {'. - 'const rows = this.querySelectorAll(".form_row");'. - 'const colors = jQuery("#widget-dialogue-form")[0]'. - '.querySelectorAll(".'.ZBX_STYLE_COLOR_PICKER.' input");'. - 'const used_colors = [];'. - 'for (const color of colors) {'. - 'if (color.value !== "" && color.name.includes("thresholds")) {'. - 'used_colors.push(color.value);'. - '}'. - '}'. - 'jQuery(".color-picker input", rows[rows.length - 1])'. - '.val(colorPalette.getNextColor(used_colors))'. - '.colorpicker({'. - 'appendTo: ".overlay-dialogue-body"'. - '});'. - '});'; - } - - public function toApi(array &$widget_fields = []) { + public function toApi(array &$widget_fields = []): void { $value = $this->getValue(); foreach ($value as $index => $val) { diff --git a/ui/include/classes/widgets/fields/CWidgetFieldTimeZone.php b/ui/include/classes/widgets/fields/CWidgetFieldTimeZone.php index 202283188f3..32806e9885a 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldTimeZone.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldTimeZone.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,62 +19,33 @@ **/ -class CWidgetFieldTimeZone extends CWidgetField { +namespace Zabbix\Widgets\Fields; - private $values; +use CTimezoneHelper; - /** - * CSelect widget field. - * - * @param string $name Field name in form - * @param string $label Label for the field in form - * @param array $values Key/value pairs of select option values. Key - saved in DB. Value - visible to user. - */ - public function __construct($name, $label, $values = null) { - parent::__construct($name, $label); +class CWidgetFieldTimeZone extends CWidgetFieldSelect { - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); + public const DEFAULT_VALUE = ''; - if ($values === null) { - $this->values = $this->generateValues(); - } + public function __construct(string $name, string $label = null, array $values = null) { + parent::__construct($name, $label, $values === null + ? [ + ZBX_DEFAULT_TIMEZONE => CTimezoneHelper::getTitle(CTimezoneHelper::getSystemTimezone(), + _('System default') + ), + TIMEZONE_DEFAULT_LOCAL => _('Local default') + ] + CTimezoneHelper::getList() + : null + ); - $this->setExValidationRules(['in' => implode(',', array_keys($this->values))]); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); } - public function setValue($value) { - return parent::setValue($value); - } - - public function getValues() { - return $this->values; - } - - private function generateValues() { - return [ - ZBX_DEFAULT_TIMEZONE => CTimezoneHelper::getTitle(CTimezoneHelper::getSystemTimezone(), - _('System default') - ), - TIMEZONE_DEFAULT_LOCAL => _('Local default') - ] + CTimezoneHelper::getList(); - } - - public function getJavascript() { - return ' - var timezone_select = document.getElementById("'.$this->getName().'"); - var local_time_zone = Intl.DateTimeFormat().resolvedOptions().timeZone; - var timezone_from_list = timezone_select.getOptionByValue(local_time_zone); - var local_list_item = timezone_select.getOptionByValue("'.TIMEZONE_DEFAULT_LOCAL.'"); - - if (timezone_from_list && local_list_item) { - const title = local_list_item.label + ": " + timezone_from_list.label; - local_list_item.label = title; - local_list_item._node.innerText = title; + public function setValue($value): self { + $this->value = $value; - if (timezone_select.selectedIndex === local_list_item._index) { - timezone_select._preselect(timezone_select.selectedIndex); - } - } - '; + return $this; } } diff --git a/ui/include/classes/widgets/fields/CWidgetFieldUrl.php b/ui/include/classes/widgets/fields/CWidgetFieldUrl.php index 31c760be381..7d8706deb1a 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldUrl.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldUrl.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,39 +19,33 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldUrl extends CWidgetField { - /** - * URL widget field. - * - * @param string $name field name in form - * @param string $label label for the field in form - */ - public function __construct($name, $label) { + public const DEFAULT_VALUE = ''; + + public function __construct(string $name, string $label = null) { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); - $this->setValidationRules(['type' => API_URL, 'flags' => API_ALLOW_USER_MACRO]); - $this->setDefault(''); + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR) + ->setValidationRules(['type' => API_URL, 'flags' => API_ALLOW_USER_MACRO]); } - /** - * Set additional flags, which can be used in configuration form. - * - * @param int $flags - * - * @return $this - */ - public function setFlags($flags) { + public function setFlags(int $flags): self { parent::setFlags($flags); - if ($flags & self::FLAG_NOT_EMPTY) { + if (($flags & self::FLAG_NOT_EMPTY) !== 0) { $strict_validation_rules = $this->getValidationRules(); self::setValidationRuleFlag($strict_validation_rules, API_NOT_EMPTY); $this->setStrictValidationRules($strict_validation_rules); } else { - $this->setStrictValidationRules(null); + $this->setStrictValidationRules(); } return $this; diff --git a/ui/include/classes/widgets/fields/CWidgetFieldWidgetSelect.php b/ui/include/classes/widgets/fields/CWidgetFieldWidgetSelect.php index b9dd08205fd..39b131a0d10 100644 --- a/ui/include/classes/widgets/fields/CWidgetFieldWidgetSelect.php +++ b/ui/include/classes/widgets/fields/CWidgetFieldWidgetSelect.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,82 +19,55 @@ **/ +namespace Zabbix\Widgets\Fields; + +use Zabbix\Widgets\CWidgetField; + class CWidgetFieldWidgetSelect extends CWidgetField { - private $search_by_value; + public const DEFAULT_VALUE = -1; + + private string $search_by_value; /** * Field that creates a selection of widgets in current dashboard, filtered by given key of widget array. * - * @param string $name Name of field in config form and widget['fields'] array. - * @param string $label Field label in config form. - * @param mixed $search_type Value that will be searched in widgets. + * @param string $search_by_value Value that will be searched in widgets. */ - public function __construct($name, $label, $search_by_value) { + public function __construct(string $name, string $label = null, string $search_by_value = '') { parent::__construct($name, $label); - $this->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); $this->search_by_value = $search_by_value; + + $this + ->setDefault(self::DEFAULT_VALUE) + ->setSaveType(ZBX_WIDGET_FIELD_TYPE_STR); } - /** - * Set additional flags, which can be used in configuration form. - * - * @param int $flags - * - * @return $this - */ - public function setFlags($flags) { + public function getSearchByValue(): string { + return $this->search_by_value; + } + + public function setFlags(int $flags): self { parent::setFlags($flags); - if ($flags & self::FLAG_NOT_EMPTY) { + if (($flags & self::FLAG_NOT_EMPTY) !== 0) { $strict_validation_rules = $this->getValidationRules(); self::setValidationRuleFlag($strict_validation_rules, API_NOT_EMPTY); $this->setStrictValidationRules($strict_validation_rules); } else { - $this->setStrictValidationRules(null); + $this->setStrictValidationRules(); } return $this; } - /** - * JS code, that should be executed, to fill the select element with values and select current one. - * - * @return string - */ - public function getJavascript() { - return ' - var filter_select = document.getElementById("'.$this->getName().'"); - - filter_select.addOption('.json_encode(['label' => _('Select widget'), 'value' => '-1']).'); - filter_select.selectedIndex = 0; - - ZABBIX.Dashboard.getSelectedDashboardPage().getWidgets().forEach((widget) => { - if (widget.getType() === "'.$this->search_by_value.'") { - filter_select.addOption({label: widget.getHeaderName(), value: widget.getFields().reference}); - if (widget.getFields().reference === "'.$this->getValue().'") { - filter_select.value = "'.$this->getValue().'"; - } - } - }); - '; - } - - public function setValue($value) { + public function setValue($value): self { if ($value === '' || ctype_alnum($value)) { $this->value = $value; } return $this; } - - public function setAction($action) { - throw new RuntimeException(sprintf('Method is not implemented: "%s".', __METHOD__)); - } - - public function getAction() { - throw new RuntimeException(sprintf('Method is not implemented: "%s".', __METHOD__)); - } } diff --git a/ui/include/classes/widgets/forms/CWidgetFormActionLog.php b/ui/include/classes/widgets/forms/CWidgetFormActionLog.php deleted file mode 100644 index 2603dfddd90..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormActionLog.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Action log widget form. - */ -class CWidgetFormActionLog extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_ACTION_LOG); - - $field_sort = (new CWidgetFieldSelect('sort_triggers', _('Sort entries by'), [ - SCREEN_SORT_TRIGGERS_TIME_DESC => _('Time').' ('._('descending').')', - SCREEN_SORT_TRIGGERS_TIME_ASC => _('Time').' ('._('ascending').')', - SCREEN_SORT_TRIGGERS_TYPE_DESC => _('Type').' ('._('descending').')', - SCREEN_SORT_TRIGGERS_TYPE_ASC => _('Type').' ('._('ascending').')', - SCREEN_SORT_TRIGGERS_STATUS_DESC => _('Status').' ('._('descending').')', - SCREEN_SORT_TRIGGERS_STATUS_ASC => _('Status').' ('._('ascending').')', - SCREEN_SORT_TRIGGERS_RECIPIENT_DESC => _('Recipient').' ('._('descending').')', - SCREEN_SORT_TRIGGERS_RECIPIENT_ASC => _('Recipient').' ('._('ascending').')' - ])) - ->setDefault(SCREEN_SORT_TRIGGERS_TIME_DESC); - - if (array_key_exists('sort_triggers', $this->data)) { - $field_sort->setValue($this->data['sort_triggers']); - } - - $this->fields[$field_sort->getName()] = $field_sort; - - $field_lines = (new CWidgetFieldIntegerBox('show_lines', _('Show lines'), ZBX_MIN_WIDGET_LINES, - ZBX_MAX_WIDGET_LINES - )) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) - ->setDefault(25); - - if (array_key_exists('show_lines', $this->data)) { - $field_lines->setValue($this->data['show_lines']); - } - - $this->fields[$field_lines->getName()] = $field_lines; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormClock.php b/ui/include/classes/widgets/forms/CWidgetFormClock.php deleted file mode 100644 index 6e619dcc6bf..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormClock.php +++ /dev/null @@ -1,255 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Clock widget form. - */ -class CWidgetFormClock extends CWidgetForm { - - /** - * Minimum value of percentage. - * - * @var int - */ - private const WIDGET_CLOCK_PERCENT_MIN = 1; - - /** - * Maximum value of percentage. - * - * @var int - */ - private const WIDGET_CLOCK_PERCENT_MAX = 100; - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_CLOCK); - - // Time type field. - $field_time_type = (new CWidgetFieldSelect('time_type', _('Time type'), [ - TIME_TYPE_LOCAL => _('Local time'), - TIME_TYPE_SERVER => _('Server time'), - TIME_TYPE_HOST => _('Host time') - ]))->setDefault(TIME_TYPE_LOCAL); - - if (array_key_exists('time_type', $this->data)) { - $field_time_type->setValue($this->data['time_type']); - } - - $this->fields[$field_time_type->getName()] = $field_time_type; - - // Item field. - if ($field_time_type->getValue() === TIME_TYPE_HOST) { - // Item multiselector with single value. - $field_item = (new CWidgetFieldMsItem('itemid', _('Item'), $templateid)) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) - ->setMultiple(false); - - if (array_key_exists('itemid', $this->data)) { - $field_item->setValue($this->data['itemid']); - } - - $this->fields[$field_item->getName()] = $field_item; - } - - // clock type - $field_clock_type = (new CWidgetFieldRadioButtonList('clock_type', _('Clock type'), [ - WIDGET_CLOCK_TYPE_ANALOG => _('Analog'), - WIDGET_CLOCK_TYPE_DIGITAL => _('Digital') - ])) - ->setDefault(WIDGET_CLOCK_TYPE_ANALOG) - ->setModern(true); - - if (array_key_exists('clock_type', $this->data)) { - $field_clock_type->setValue($this->data['clock_type']); - } - - $this->fields[$field_clock_type->getName()] = $field_clock_type; - - // field show - $field_show =(new CWidgetFieldCheckBoxList('show', _('Show'))) - ->setDefault([WIDGET_CLOCK_SHOW_TIME]) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK); - - if (array_key_exists('show', $this->data)) { - $field_show->setValue($this->data['show']); - } - - $this->fields[$field_show->getName()] = $field_show; - - // advanced configuration - $field_adv_conf = (new CWidgetFieldCheckBox('adv_conf', _('Advanced configuration')))->setDefault(0); - - if (array_key_exists('adv_conf', $this->data)) { - $field_adv_conf->setValue($this->data['adv_conf']); - } - - $this->fields[$field_adv_conf->getName()] = $field_adv_conf; - - // background color - $field_bg_color = (new CWidgetFieldColor('bg_color', _('Background color')))->setDefault(''); - - if (array_key_exists('bg_color', $this->data)) { - $field_bg_color->setValue($this->data['bg_color']); - } - - $this->fields[$field_bg_color->getName()] = $field_bg_color; - - // date size - $field_date_size = (new CWidgetFieldIntegerBox('date_size', _('Size'), self::WIDGET_CLOCK_PERCENT_MIN, - self::WIDGET_CLOCK_PERCENT_MAX - ))->setDefault(20); - - if (array_key_exists('date_size', $this->data)) { - $field_date_size->setValue($this->data['date_size']); - } - - $this->fields[$field_date_size->getName()] = $field_date_size; - - // date bold - $field_date_bold = (new CWidgetFieldCheckBox('date_bold', _('Bold')))->setDefault(0); - - if (array_key_exists('date_bold', $this->data)) { - $field_date_bold->setValue($this->data['date_bold']); - } - - $this->fields[$field_date_bold->getName()] = $field_date_bold; - - // date color - $field_date_color = (new CWidgetFieldColor('date_color', _('Color')))->setDefault(''); - - if (array_key_exists('date_color', $this->data)) { - $field_date_color->setValue($this->data['date_color']); - } - - $this->fields[$field_date_color->getName()] = $field_date_color; - - // time size - $field_time_size = (new CWidgetFieldIntegerBox('time_size', _('Size'), self::WIDGET_CLOCK_PERCENT_MIN, - self::WIDGET_CLOCK_PERCENT_MAX - ))->setDefault(30); - - if (array_key_exists('time_size', $this->data)) { - $field_time_size->setValue($this->data['time_size']); - } - - $this->fields[$field_time_size->getName()] = $field_time_size; - - // time bold - $field_time_bold = (new CWidgetFieldCheckBox('time_bold', _('Bold')))->setDefault(0); - - if (array_key_exists('time_bold', $this->data)) { - $field_time_bold->setValue($this->data['time_bold']); - } - - $this->fields[$field_time_bold->getName()] = $field_time_bold; - - // time color - $field_time_color = (new CWidgetFieldColor('time_color', _('Color')))->setDefault(''); - - if (array_key_exists('time_color', $this->data)) { - $field_time_color->setValue($this->data['time_color']); - } - - $this->fields[$field_time_color->getName()] = $field_time_color; - - // time seconds - $field_time_sec = (new CWidgetFieldCheckBox('time_sec', _('Seconds')))->setDefault(1); - - if (array_key_exists('time_sec', $this->data)) { - $field_time_sec->setValue($this->data['time_sec']); - } - - $this->fields[$field_time_sec->getName()] = $field_time_sec; - - // time format - $field_time_format = (new CWidgetFieldRadioButtonList('time_format', _('Format'), [ - WIDGET_CLOCK_HOUR_TWENTY_FOUR => _('24-hour'), - WIDGET_CLOCK_HOUR_TWELVE => _('12-hour') - ])) - ->setDefault(WIDGET_CLOCK_HOUR_TWENTY_FOUR) - ->setModern(true); - - if (array_key_exists('time_format', $this->data)) { - $field_time_format->setValue($this->data['time_format']); - } - - $this->fields[$field_time_format->getName()] = $field_time_format; - - // time zone size - $field_tzone_size = (new CWidgetFieldIntegerBox('tzone_size', _('Size'), self::WIDGET_CLOCK_PERCENT_MIN, - self::WIDGET_CLOCK_PERCENT_MAX - ))->setDefault(20); - - if (array_key_exists('tzone_size', $this->data)) { - $field_tzone_size->setValue($this->data['tzone_size']); - } - - $this->fields[$field_tzone_size->getName()] = $field_tzone_size; - - // time zone bold - $field_tzone_bold = (new CWidgetFieldCheckBox('tzone_bold', _('Bold')))->setDefault(0); - - if (array_key_exists('tzone_bold', $this->data)) { - $field_tzone_bold->setValue($this->data['tzone_bold']); - } - - $this->fields[$field_tzone_bold->getName()] = $field_tzone_bold; - - // time zone color - $field_tzone_color = (new CWidgetFieldColor('tzone_color', _('Color')))->setDefault(''); - - if (array_key_exists('tzone_color', $this->data)) { - $field_tzone_color->setValue($this->data['tzone_color']); - } - - $this->fields[$field_tzone_color->getName()] = $field_tzone_color; - - // time zone time zone - $field_tzone_timezone = (new CWidgetFieldTimeZone('tzone_timezone', _('Time zone'))) - ->setDefault(ZBX_DEFAULT_TIMEZONE); - - if ($field_time_type->getValue() === TIME_TYPE_LOCAL) { - $field_tzone_timezone->setDefault(TIMEZONE_DEFAULT_LOCAL); - } - - if (array_key_exists('tzone_timezone', $this->data)) { - $field_tzone_timezone->setValue($this->data['tzone_timezone']); - } - elseif ($field_time_type->getValue() === TIME_TYPE_LOCAL) { - $field_tzone_timezone->setValue(TIMEZONE_DEFAULT_LOCAL); - } - - $this->fields[$field_tzone_timezone->getName()] = $field_tzone_timezone; - - // time zone format - $field_tzone_format = (new CWidgetFieldRadioButtonList('tzone_format', _('Format'), [ - WIDGET_CLOCK_TIMEZONE_SHORT => _('Short'), - WIDGET_CLOCK_TIMEZONE_FULL => _('Full') - ])) - ->setDefault(WIDGET_CLOCK_TIMEZONE_SHORT) - ->setModern(true); - - if (array_key_exists('tzone_format', $this->data)) { - $field_tzone_format->setValue($this->data['tzone_format']); - } - - $this->fields[$field_tzone_format->getName()] = $field_tzone_format; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormDataOver.php b/ui/include/classes/widgets/forms/CWidgetFormDataOver.php deleted file mode 100644 index d6b5a4a6380..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormDataOver.php +++ /dev/null @@ -1,97 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Data overview widget form. - */ -class CWidgetFormDataOver extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_DATA_OVER); - - $this->data = self::convertDottedKeys($this->data); - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - $this->fields[$field_groups->getName()] = $field_groups; - - // Hosts. - $field_hosts = new CWidgetFieldMsHost('hostids', _('Hosts')); - $field_hosts->setFilterPreselect('groupids_'); - - if (array_key_exists('hostids', $this->data)) { - $field_hosts->setValue($this->data['hostids']); - } - - $this->fields[$field_hosts->getName()] = $field_hosts; - - // Tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Tags array: tag, operator and value. No label, because it belongs to previous group. - $field_tags = new CWidgetFieldTags('tags', ''); - - if (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - - // Show suppressed problems. - $field_show_suppressed = (new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems'))) - ->setDefault(ZBX_PROBLEM_SUPPRESSED_FALSE); - - if (array_key_exists('show_suppressed', $this->data)) { - $field_show_suppressed->setValue($this->data['show_suppressed']); - } - - $this->fields[$field_show_suppressed->getName()] = $field_show_suppressed; - - // Hosts names location. - $field_style = (new CWidgetFieldRadioButtonList('style', _('Hosts location'), [ - STYLE_LEFT => _('Left'), - STYLE_TOP => _('Top') - ])) - ->setDefault(STYLE_LEFT) - ->setModern(true); - - if (array_key_exists('style', $this->data)) { - $field_style->setValue($this->data['style']); - } - - $this->fields[$field_style->getName()] = $field_style; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormGeoMap.php b/ui/include/classes/widgets/forms/CWidgetFormGeoMap.php deleted file mode 100644 index be0a49f437c..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormGeoMap.php +++ /dev/null @@ -1,83 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Geomap widget form. - */ -class CWidgetFormGeoMap extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_GEOMAP); - - $this->data = self::convertDottedKeys($this->data); - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - - $this->fields[$field_groups->getName()] = $field_groups; - - // Hosts field. - $field_hosts = new CWidgetFieldMsHost('hostids', _('Hosts')); - $field_hosts->setFilterPreselect('groupids_'); - - if (array_key_exists('hostids', $this->data)) { - $field_hosts->setValue($this->data['hostids']); - } - - $this->fields[$field_hosts->getName()] = $field_hosts; - - // Tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Tags array: tag, operator and value. No label, because it belongs to previous group. - $field_tags = new CWidgetFieldTags('tags', ''); - - if (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - - // Default view. - $field_default_view = new CWidgetFieldLatLng('default_view', _('Initial view')); - - if (array_key_exists('default_view', $this->data)) { - $field_default_view->setValue($this->data['default_view']); - } - - $this->fields[$field_default_view->getName()] = $field_default_view; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormGraph.php b/ui/include/classes/widgets/forms/CWidgetFormGraph.php deleted file mode 100644 index 034923647ef..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormGraph.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Graph widget form. - */ -class CWidgetFormGraph extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_GRAPH); - - // Select graph type field. - $field_source = (new CWidgetFieldRadioButtonList('source_type', _('Source'), [ - ZBX_WIDGET_FIELD_RESOURCE_GRAPH => _('Graph'), - ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH => _('Simple graph') - ])) - ->setDefault(ZBX_WIDGET_FIELD_RESOURCE_GRAPH) - ->setAction('ZABBIX.Dashboard.reloadWidgetProperties()') - ->setModern(true); - - if (array_key_exists('source_type', $this->data)) { - $field_source->setValue($this->data['source_type']); - } - - $this->fields[$field_source->getName()] = $field_source; - - if (array_key_exists('source_type', $this->data) - && $this->data['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) { - // Select simple graph field. - $field_item = (new CWidgetFieldMsItem('itemid', _('Item'), $templateid)) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) - ->setMultiple(false) - ->setFilterParameter('numeric', true); - - if ($templateid === null) { - // For groups and hosts selection. - $field_item->setFilterParameter('with_simple_graph_items', true); - } - - if (array_key_exists('itemid', $this->data)) { - $field_item->setValue($this->data['itemid']); - } - - $this->fields[$field_item->getName()] = $field_item; - } - else { - // Select graph field. - $field_graph = (new CWidgetFieldMsGraph('graphid', _('Graph'), $templateid)) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) - ->setMultiple(false); - - if (array_key_exists('graphid', $this->data)) { - $field_graph->setValue($this->data['graphid']); - } - - $this->fields[$field_graph->getName()] = $field_graph; - } - - // Show legend checkbox. - $field_legend = (new CWidgetFieldCheckBox('show_legend', _('Show legend')))->setDefault(1); - - if (array_key_exists('show_legend', $this->data)) { - $field_legend->setValue($this->data['show_legend']); - } - - $this->fields[$field_legend->getName()] = $field_legend; - - // Dynamic item. - if ($templateid === null) { - $field_dynamic = (new CWidgetFieldCheckBox('dynamic', _('Enable host selection')))->setDefault(WIDGET_SIMPLE_ITEM); - - $field_dynamic->setValue(array_key_exists('dynamic', $this->data) ? $this->data['dynamic'] : false); - - $this->fields[$field_dynamic->getName()] = $field_dynamic; - } - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormGraphPrototype.php b/ui/include/classes/widgets/forms/CWidgetFormGraphPrototype.php deleted file mode 100644 index fb940335cc4..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormGraphPrototype.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Graph prototype widget form. - */ -class CWidgetFormGraphPrototype extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_GRAPH_PROTOTYPE); - - // Select graph type field. - $field_source = (new CWidgetFieldRadioButtonList('source_type', _('Source'), [ - ZBX_WIDGET_FIELD_RESOURCE_GRAPH_PROTOTYPE => _('Graph prototype'), - ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH_PROTOTYPE => _('Simple graph prototype') - ])) - ->setDefault(ZBX_WIDGET_FIELD_RESOURCE_GRAPH_PROTOTYPE) - ->setAction('ZABBIX.Dashboard.reloadWidgetProperties()') - ->setModern(true); - - if (array_key_exists('source_type', $this->data)) { - $field_source->setValue($this->data['source_type']); - } - - $this->fields[$field_source->getName()] = $field_source; - - if (array_key_exists('source_type', $this->data) - && $this->data['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH_PROTOTYPE) { - // Select simple graph prototype field. - $field_item_prototype = (new CWidgetFieldMsItemPrototype('itemid', _('Item prototype'), $templateid)) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) - ->setMultiple(false) - ->setFilterParameter('numeric', true); - - if ($templateid === null) { - // For groups and hosts selection. - $field_item_prototype->setFilterParameter('with_simple_graph_item_prototypes', true); - } - - if (array_key_exists('itemid', $this->data)) { - $field_item_prototype->setValue($this->data['itemid']); - } - - $this->fields[$field_item_prototype->getName()] = $field_item_prototype; - } - else { - // Select graph prototype field. - $field_graph_prototype = (new CWidgetFieldMsGraphPrototype('graphid', _('Graph prototype'), $templateid)) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) - ->setMultiple(false); - - if (array_key_exists('graphid', $this->data)) { - $field_graph_prototype->setValue($this->data['graphid']); - } - - $this->fields[$field_graph_prototype->getName()] = $field_graph_prototype; - } - - // Show legend checkbox. - $field_legend = (new CWidgetFieldCheckBox('show_legend', _('Show legend')))->setDefault(1); - - if (array_key_exists('show_legend', $this->data)) { - $field_legend->setValue($this->data['show_legend']); - } - - $this->fields[$field_legend->getName()] = $field_legend; - - // Dynamic item. - if ($templateid === null) { - $field_dynamic = (new CWidgetFieldCheckBox('dynamic', _('Enable host selection')))->setDefault(WIDGET_SIMPLE_ITEM); - - $field_dynamic->setValue(array_key_exists('dynamic', $this->data) ? $this->data['dynamic'] : false); - - $this->fields[$field_dynamic->getName()] = $field_dynamic; - } - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormHostAvail.php b/ui/include/classes/widgets/forms/CWidgetFormHostAvail.php deleted file mode 100644 index e3aedaa5f5c..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormHostAvail.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Host availability widget form. - */ -class CWidgetFormHostAvail extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_HOST_AVAIL); - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - $this->fields[$field_groups->getName()] = $field_groups; - - // Interface type. - $field_interface_type = new CWidgetFieldCheckBoxList('interface_type', _('Interface type')); - - if (array_key_exists('interface_type', $this->data)) { - $field_interface_type->setValue($this->data['interface_type']); - } - - $this->fields[$field_interface_type->getName()] = $field_interface_type; - - // Layout. - $field_layout = (new CWidgetFieldRadioButtonList('layout', _('Layout'), [ - STYLE_HORIZONTAL => _('Horizontal'), - STYLE_VERTICAL => _('Vertical') - ])) - ->setDefault(STYLE_HORIZONTAL) - ->setModern(true); - - if (array_key_exists('layout', $this->data)) { - $field_layout->setValue($this->data['layout']); - } - - $this->fields[$field_layout->getName()] = $field_layout; - - // Show hosts in maintenance. - $field_maintenance = (new CWidgetFieldCheckBox('maintenance', _('Show hosts in maintenance'))) - ->setDefault(HOST_MAINTENANCE_STATUS_OFF); - - if (array_key_exists('maintenance', $this->data)) { - $field_maintenance->setValue($this->data['maintenance']); - } - - $this->fields[$field_maintenance->getName()] = $field_maintenance; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormItem.php b/ui/include/classes/widgets/forms/CWidgetFormItem.php deleted file mode 100644 index 96272bd7d51..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormItem.php +++ /dev/null @@ -1,461 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Single item widget form. - */ -class CWidgetFormItem extends CWidgetForm { - - /** - * Minimum value of percentage. - * - * @var int - */ - private const WIDGET_ITEM_PERCENT_MIN = 1; - - /** - * Maximum value of percentage. - * - * @var int - */ - private const WIDGET_ITEM_PERCENT_MAX = 100; - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_ITEM); - - $this->data = self::convertDottedKeys($this->data); - - // Item field. - $field_item = (new CWidgetFieldMsItem('itemid', _('Item'), $templateid)) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) - ->setMultiple(false); - - if (array_key_exists('itemid', $this->data)) { - $field_item->setValue($this->data['itemid']); - } - - $this->fields[$field_item->getName()] = $field_item; - - // Show checkboxes. - $field_show = (new CWidgetFieldCheckBoxList('show', _('Show'))) - ->setDefault([WIDGET_ITEM_SHOW_DESCRIPTION, WIDGET_ITEM_SHOW_VALUE, WIDGET_ITEM_SHOW_TIME, - WIDGET_ITEM_SHOW_CHANGE_INDICATOR - ]) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK); - - if (array_key_exists('show', $this->data)) { - $field_show->setValue($this->data['show']); - } - - $this->fields[$field_show->getName()] = $field_show; - - // Advanced configuration. - $field_adv_conf = (new CWidgetFieldCheckBox('adv_conf', _('Advanced configuration')))->setDefault(0); - - if (array_key_exists('adv_conf', $this->data)) { - $field_adv_conf->setValue($this->data['adv_conf']); - } - - $this->fields[$field_adv_conf->getName()] = $field_adv_conf; - - // Description textarea field. - $field_desc = (new CWidgetFieldTextArea('description', _('Description'))) - ->setDefault('{ITEM.NAME}') - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) - ->setWidth(ZBX_TEXTAREA_BIG_WIDTH - 38); - - if (array_key_exists('description', $this->data)) { - $field_desc->setValue($this->data['description']); - } - - $this->fields[$field_desc->getName()] = $field_desc; - - // Description horizontal position. - $field_desc_h_pos = (new CWidgetFieldRadioButtonList('desc_h_pos', _('Horizontal position'), [ - WIDGET_ITEM_POS_LEFT => _('Left'), - WIDGET_ITEM_POS_CENTER => _('Center'), - WIDGET_ITEM_POS_RIGHT => _('Right') - ])) - ->setDefault(WIDGET_ITEM_POS_CENTER) - ->setModern(true); - - if (array_key_exists('desc_h_pos', $this->data)) { - $field_desc_h_pos->setValue($this->data['desc_h_pos']); - } - - $this->fields[$field_desc_h_pos->getName()] = $field_desc_h_pos; - - // Description vertical position. - $field_desc_v_pos = (new CWidgetFieldRadioButtonList('desc_v_pos', _('Vertical position'), [ - WIDGET_ITEM_POS_TOP => _('Top'), - WIDGET_ITEM_POS_MIDDLE => _('Middle'), - WIDGET_ITEM_POS_BOTTOM => _('Bottom') - ])) - ->setDefault(WIDGET_ITEM_POS_BOTTOM) - ->setModern(true); - - if (array_key_exists('desc_v_pos', $this->data)) { - $field_desc_v_pos->setValue($this->data['desc_v_pos']); - } - - $this->fields[$field_desc_v_pos->getName()] = $field_desc_v_pos; - - // Description size. - $field_desc_size = (new CWidgetFieldIntegerBox('desc_size', _('Size'), self::WIDGET_ITEM_PERCENT_MIN, - self::WIDGET_ITEM_PERCENT_MAX - ))->setDefault(15); - - if (array_key_exists('desc_size', $this->data)) { - $field_desc_size->setValue($this->data['desc_size']); - } - - $this->fields[$field_desc_size->getName()] = $field_desc_size; - - // Description bold. - $field_desc_bold = (new CWidgetFieldCheckBox('desc_bold', _('Bold')))->setDefault(0); - - if (array_key_exists('desc_bold', $this->data)) { - $field_desc_bold->setValue($this->data['desc_bold']); - } - - $this->fields[$field_desc_bold->getName()] = $field_desc_bold; - - // Description color. - $field_desc_color = (new CWidgetFieldColor('desc_color', _('Color'))) - ->setDefault(''); - - if (array_key_exists('desc_color', $this->data)) { - $field_desc_color->setValue($this->data['desc_color']); - } - - $this->fields[$field_desc_color->getName()] = $field_desc_color; - - // Value decimal places. - $field_decimal_places = (new CWidgetFieldIntegerBox('decimal_places', _('Decimal places'), 0, 10)) - ->setDefault(2); - - if (array_key_exists('decimal_places', $this->data)) { - $field_decimal_places->setValue($this->data['decimal_places']); - } - - $this->fields[$field_decimal_places->getName()] = $field_decimal_places; - - // Value decimal size. - $field_decimal_size = (new CWidgetFieldIntegerBox('decimal_size', _('Size'), self::WIDGET_ITEM_PERCENT_MIN, - self::WIDGET_ITEM_PERCENT_MAX - ))->setDefault(35); - - if (array_key_exists('decimal_size', $this->data)) { - $field_decimal_size->setValue($this->data['decimal_size']); - } - - $this->fields[$field_decimal_size->getName()] = $field_decimal_size; - - // Value horizontal position. - $field_value_h_pos = (new CWidgetFieldRadioButtonList('value_h_pos', _('Horizontal position'), [ - WIDGET_ITEM_POS_LEFT => _('Left'), - WIDGET_ITEM_POS_CENTER => _('Center'), - WIDGET_ITEM_POS_RIGHT => _('Right') - ])) - ->setDefault(WIDGET_ITEM_POS_CENTER) - ->setModern(true); - - if (array_key_exists('value_h_pos', $this->data)) { - $field_value_h_pos->setValue($this->data['value_h_pos']); - } - - $this->fields[$field_value_h_pos->getName()] = $field_value_h_pos; - - // Value vertical position. - $field_value_v_pos = (new CWidgetFieldRadioButtonList('value_v_pos', _('Vertical position'), [ - WIDGET_ITEM_POS_TOP => _('Top'), - WIDGET_ITEM_POS_MIDDLE => _('Middle'), - WIDGET_ITEM_POS_BOTTOM => _('Bottom') - ])) - ->setDefault(WIDGET_ITEM_POS_MIDDLE) - ->setModern(true); - - if (array_key_exists('value_v_pos', $this->data)) { - $field_value_v_pos->setValue($this->data['value_v_pos']); - } - - $this->fields[$field_value_v_pos->getName()] = $field_value_v_pos; - - // Value size. - $field_value_size = (new CWidgetFieldIntegerBox('value_size', _('Size'), self::WIDGET_ITEM_PERCENT_MIN, - self::WIDGET_ITEM_PERCENT_MAX - ))->setDefault(45); - - if (array_key_exists('value_size', $this->data)) { - $field_value_size->setValue($this->data['value_size']); - } - - $this->fields[$field_value_size->getName()] = $field_value_size; - - // Value bold. - $field_value_bold = (new CWidgetFieldCheckBox('value_bold', _('Bold')))->setDefault(1); - - if (array_key_exists('value_bold', $this->data)) { - $field_value_bold->setValue($this->data['value_bold']); - } - - $this->fields[$field_value_bold->getName()] = $field_value_bold; - - // Value color. - $field_value_color = (new CWidgetFieldColor('value_color', _('Color'))) - ->setDefault(''); - - if (array_key_exists('value_color', $this->data)) { - $field_value_color->setValue($this->data['value_color']); - } - - $this->fields[$field_value_color->getName()] = $field_value_color; - - // Units show. - $field_units_show = (new CWidgetFieldCheckBox('units_show', _('Units')))->setDefault(1); - - if (array_key_exists('units_show', $this->data)) { - $field_units_show->setValue($this->data['units_show']); - } - - $this->fields[$field_units_show->getName()] = $field_units_show; - - // Units input field. - $field_units = new CWidgetFieldTextBox('units', _('Units')); - - if (array_key_exists('units', $this->data)) { - $field_units->setValue($this->data['units']); - } - - $this->fields[$field_units->getName()] = $field_units; - - // Units position. - $field_units_pos = (new CWidgetFieldSelect('units_pos', _('Position'), [ - WIDGET_ITEM_POS_BEFORE => _('Before value'), - WIDGET_ITEM_POS_ABOVE => _('Above value'), - WIDGET_ITEM_POS_AFTER => _('After value'), - WIDGET_ITEM_POS_BELOW => _('Below value') - ])) - ->setDefault(WIDGET_ITEM_POS_AFTER); - - if (array_key_exists('units_pos', $this->data)) { - $field_units_pos->setValue($this->data['units_pos']); - } - - $this->fields[$field_units_pos->getName()] = $field_units_pos; - - // Units size. - $field_units_size = (new CWidgetFieldIntegerBox('units_size', _('Size'), self::WIDGET_ITEM_PERCENT_MIN, - self::WIDGET_ITEM_PERCENT_MAX - ))->setDefault(35); - - if (array_key_exists('units_size', $this->data)) { - $field_units_size->setValue($this->data['units_size']); - } - - $this->fields[$field_units_size->getName()] = $field_units_size; - - // Units bold. - $field_units_bold = (new CWidgetFieldCheckBox('units_bold', _('Bold')))->setDefault(1); - - if (array_key_exists('units_bold', $this->data)) { - $field_units_bold->setValue($this->data['units_bold']); - } - - $this->fields[$field_units_bold->getName()] = $field_units_bold; - - // Units color. - $field_units_color = (new CWidgetFieldColor('units_color', _('Color'))) - ->setDefault(''); - - if (array_key_exists('units_color', $this->data)) { - $field_units_color->setValue($this->data['units_color']); - } - - $this->fields[$field_units_color->getName()] = $field_units_color; - - // Time horizontal position. - $field_time_h_pos = (new CWidgetFieldRadioButtonList('time_h_pos', _('Horizontal position'), [ - WIDGET_ITEM_POS_LEFT => _('Left'), - WIDGET_ITEM_POS_CENTER => _('Center'), - WIDGET_ITEM_POS_RIGHT => _('Right') - ])) - ->setDefault(WIDGET_ITEM_POS_CENTER) - ->setModern(true); - - if (array_key_exists('time_h_pos', $this->data)) { - $field_time_h_pos->setValue($this->data['time_h_pos']); - } - - $this->fields[$field_time_h_pos->getName()] = $field_time_h_pos; - - // Time vertical position. - $field_time_v_pos = (new CWidgetFieldRadioButtonList('time_v_pos', _('Vertical position'), [ - WIDGET_ITEM_POS_TOP => _('Top'), - WIDGET_ITEM_POS_MIDDLE => _('Middle'), - WIDGET_ITEM_POS_BOTTOM => _('Bottom') - ])) - ->setDefault(WIDGET_ITEM_POS_TOP) - ->setModern(true); - - if (array_key_exists('time_v_pos', $this->data)) { - $field_time_v_pos->setValue($this->data['time_v_pos']); - } - - $this->fields[$field_time_v_pos->getName()] = $field_time_v_pos; - - // Time size. - $field_time_size = (new CWidgetFieldIntegerBox('time_size', _('Size'), self::WIDGET_ITEM_PERCENT_MIN, - self::WIDGET_ITEM_PERCENT_MAX - ))->setDefault(15); - - if (array_key_exists('time_size', $this->data)) { - $field_time_size->setValue($this->data['time_size']); - } - - $this->fields[$field_time_size->getName()] = $field_time_size; - - // Time bold. - $field_time_bold = (new CWidgetFieldCheckBox('time_bold', _('Bold')))->setDefault(0); - - if (array_key_exists('time_bold', $this->data)) { - $field_time_bold->setValue($this->data['time_bold']); - } - - $this->fields[$field_time_bold->getName()] = $field_time_bold; - - // Time color. - $field_time_color = (new CWidgetFieldColor('time_color', _('Color'))) - ->setDefault(''); - - if (array_key_exists('time_color', $this->data)) { - $field_time_color->setValue($this->data['time_color']); - } - - $this->fields[$field_time_color->getName()] = $field_time_color; - - // Change indicator up arrow color. - $field_up_color = (new CWidgetFieldColor('up_color', _('Change indicator'))) - ->setDefault(''); - - if (array_key_exists('up_color', $this->data)) { - $field_up_color->setValue($this->data['up_color']); - } - - $this->fields[$field_up_color->getName()] = $field_up_color; - - // Change indicator down arrow color. - $field_down_color = (new CWidgetFieldColor('down_color', _('Change indicator'))) - ->setDefault(''); - - if (array_key_exists('down_color', $this->data)) { - $field_down_color->setValue($this->data['down_color']); - } - - $this->fields[$field_down_color->getName()] = $field_down_color; - - // Change indicator up/down arrow color. - $field_updown_color = (new CWidgetFieldColor('updown_color', _('Change indicator'))) - ->setDefault(''); - - if (array_key_exists('updown_color', $this->data)) { - $field_updown_color->setValue($this->data['updown_color']); - } - - $this->fields[$field_updown_color->getName()] = $field_updown_color; - - // Background color. - $field_bg_color = (new CWidgetFieldColor('bg_color', _('Background color'))) - ->setDefault(''); - - if (array_key_exists('bg_color', $this->data)) { - $field_bg_color->setValue($this->data['bg_color']); - } - - $this->fields[$field_bg_color->getName()] = $field_bg_color; - - // Thresholds. - $field_thresholds = (new CWidgetFieldThresholds('thresholds', _('Thresholds'))); - - if (array_key_exists('thresholds', $this->data)) { - $field_thresholds->setValue($this->data['thresholds']); - } - - $this->fields[$field_thresholds->getName()] = $field_thresholds; - - // Dynamic item. - if ($templateid === null) { - $dynamic_item = (new CWidgetFieldCheckBox('dynamic', _('Enable host selection')))->setDefault(WIDGET_SIMPLE_ITEM); - - if (array_key_exists('dynamic', $this->data)) { - $dynamic_item->setValue($this->data['dynamic']); - } - - $this->fields[$dynamic_item->getName()] = $dynamic_item; - } - } - - /** - * Validate form fields. - * - * @param bool $strict Enables more strict validation of the form fields. - * Must be enabled for validation of input parameters in the widget configuration form. - * - * @return array - */ - public function validate($strict = false) { - $errors = parent::validate($strict); - - // Check if one of the objects (description, value or time) occupies same space. - $fields = [ - ['show' => WIDGET_ITEM_SHOW_DESCRIPTION, 'h_pos' => 'desc_h_pos', 'v_pos' => 'desc_v_pos'], - ['show' => WIDGET_ITEM_SHOW_VALUE, 'h_pos' => 'value_h_pos', 'v_pos' => 'value_v_pos'], - ['show' => WIDGET_ITEM_SHOW_TIME, 'h_pos' => 'time_h_pos', 'v_pos' => 'time_v_pos'] - ]; - $fields_count = count($fields); - $show = $this->fields['show']->getValue(); - - for ($i = 0; $i < $fields_count - 1; $i++) { - if (!in_array($fields[$i]['show'], $show)) { - continue; - } - - $i_h_pos = $this->fields[$fields[$i]['h_pos']]->getValue(); - $i_v_pos = $this->fields[$fields[$i]['v_pos']]->getValue(); - - for ($j = $i + 1; $j < $fields_count; $j++) { - if (!in_array($fields[$j]['show'], $show)) { - continue; - } - - $j_h_pos = $this->fields[$fields[$j]['h_pos']]->getValue(); - $j_v_pos = $this->fields[$fields[$j]['v_pos']]->getValue(); - - if ($i_h_pos == $j_h_pos && $i_v_pos == $j_v_pos) { - $errors[] = _('Two or more fields cannot occupy same space.'); - break 2; - } - } - } - - return $errors; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormMap.php b/ui/include/classes/widgets/forms/CWidgetFormMap.php deleted file mode 100644 index 4f1230e95be..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormMap.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Map widget form. - */ -class CWidgetFormMap extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_MAP); - - // Widget reference field. - $field_reference = (new CWidgetFieldReference())->setDefault(''); - - if (array_key_exists($field_reference->getName(), $this->data)) { - $field_reference->setValue($this->data[$field_reference->getName()]); - } - - $this->fields[$field_reference->getName()] = $field_reference; - - // Select source type field. - $field_source_type = (new CWidgetFieldRadioButtonList('source_type', _('Source type'), [ - WIDGET_SYSMAP_SOURCETYPE_MAP => _('Map'), - WIDGET_SYSMAP_SOURCETYPE_FILTER => _('Map navigation tree') - ])) - ->setDefault(WIDGET_SYSMAP_SOURCETYPE_MAP) - ->setAction('ZABBIX.Dashboard.reloadWidgetProperties()') - ->setModern(true); - - if (array_key_exists('source_type', $this->data)) { - $field_source_type->setValue($this->data['source_type']); - } - - $this->fields[$field_source_type->getName()] = $field_source_type; - - if ($field_source_type->getValue() === WIDGET_SYSMAP_SOURCETYPE_FILTER) { - // Select filter widget field. - $field_filter_widget = (new CWidgetFieldWidgetSelect('filter_widget_reference', _('Filter'), - WIDGET_NAV_TREE - )) - ->setDefault('') - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK); - - if (array_key_exists('filter_widget_reference', $this->data)) { - $field_filter_widget->setValue($this->data['filter_widget_reference']); - } - - $this->fields[$field_filter_widget->getName()] = $field_filter_widget; - } - else { - // Select sysmap field. - $field_map = (new CWidgetFieldSelectResource('sysmapid', _('Map'), WIDGET_FIELD_SELECT_RES_SYSMAP)) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK); - - if (array_key_exists('sysmapid', $this->data)) { - $field_map->setValue($this->data['sysmapid']); - } - - $this->fields[$field_map->getName()] = $field_map; - } - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormNavTree.php b/ui/include/classes/widgets/forms/CWidgetFormNavTree.php deleted file mode 100644 index fa5e68a87a2..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormNavTree.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Map navigation widget form. - */ -class CWidgetFormNavTree extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_NAV_TREE); - - $this->data = self::convertDottedKeys($this->data); - - // Widget reference field. - $field_reference = (new CWidgetFieldReference())->setDefault(''); - - if (array_key_exists($field_reference->getName(), $this->data)) { - $field_reference->setValue($this->data[$field_reference->getName()]); - } - - $this->fields[$field_reference->getName()] = $field_reference; - - // Elements of the tree. - $field_navtree = new CWidgetFieldNavTree('navtree', ''); - - if (array_key_exists('navtree', $this->data)) { - $field_navtree->setValue($this->data['navtree']); - } - - $this->fields[$field_navtree->getName()] = $field_navtree; - - // Show unavailable maps. - $show_unavailable_maps = (new CWidgetFieldCheckBox('show_unavailable', _('Show unavailable maps'))) - ->setDefault(0); - - if (array_key_exists('show_unavailable', $this->data)) { - $show_unavailable_maps->setValue($this->data['show_unavailable']); - } - - $this->fields[$show_unavailable_maps->getName()] = $show_unavailable_maps; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormPlainText.php b/ui/include/classes/widgets/forms/CWidgetFormPlainText.php deleted file mode 100644 index fd5ed730fb4..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormPlainText.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Plain text widget form. - */ -class CWidgetFormPlainText extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_PLAIN_TEXT); - - // Items selector. - $field_items = (new CWidgetFieldMsItem('itemids', _('Items'), $templateid)) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK); - - if (array_key_exists('itemids', $this->data)) { - $field_items->setValue($this->data['itemids']); - } - - $this->fields[$field_items->getName()] = $field_items; - - // Location of the item names. - $field_style = (new CWidgetFieldRadioButtonList('style', _('Items location'), [ - STYLE_LEFT => _('Left'), - STYLE_TOP => _('Top') - ])) - ->setDefault(STYLE_LEFT) - ->setModern(true); - - if (array_key_exists('style', $this->data)) { - $field_style->setValue($this->data['style']); - } - - $this->fields[$field_style->getName()] = $field_style; - - // Number of records to display. - $field_lines = (new CWidgetFieldIntegerBox('show_lines', _('Show lines'), ZBX_MIN_WIDGET_LINES, - ZBX_MAX_WIDGET_LINES - )) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) - ->setDefault(ZBX_DEFAULT_WIDGET_LINES); - - if (array_key_exists('show_lines', $this->data)) { - $field_lines->setValue($this->data['show_lines']); - } - - $this->fields[$field_lines->getName()] = $field_lines; - - // Show text as HTML. - $field_show_as_html = (new CWidgetFieldCheckBox('show_as_html', _('Show text as HTML')))->setDefault(0); - - if (array_key_exists('show_as_html', $this->data)) { - $field_show_as_html->setValue($this->data['show_as_html']); - } - - $this->fields[$field_show_as_html->getName()] = $field_show_as_html; - - // Dynamic item. - if ($templateid === null) { - $dynamic_item = (new CWidgetFieldCheckBox('dynamic', _('Enable host selection')))->setDefault(WIDGET_SIMPLE_ITEM); - - if (array_key_exists('dynamic', $this->data)) { - $dynamic_item->setValue($this->data['dynamic']); - } - - $this->fields[$dynamic_item->getName()] = $dynamic_item; - } - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormProblemHosts.php b/ui/include/classes/widgets/forms/CWidgetFormProblemHosts.php deleted file mode 100644 index 9db26f80e32..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormProblemHosts.php +++ /dev/null @@ -1,136 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Problem hosts widget form. - */ -class CWidgetFormProblemHosts extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_PROBLEM_HOSTS); - - $this->data = self::convertDottedKeys($this->data); - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - - $this->fields[$field_groups->getName()] = $field_groups; - - // Exclude host groups. - $field_exclude_groups = new CWidgetFieldMsGroup('exclude_groupids', _('Exclude host groups')); - - if (array_key_exists('exclude_groupids', $this->data)) { - $field_exclude_groups->setValue($this->data['exclude_groupids']); - } - - $this->fields[$field_exclude_groups->getName()] = $field_exclude_groups; - - // Hosts field. - $field_hosts = new CWidgetFieldMsHost('hostids', _('Hosts')); - $field_hosts->setFilterPreselect('groupids_'); - - if (array_key_exists('hostids', $this->data)) { - $field_hosts->setValue($this->data['hostids']); - } - - $this->fields[$field_hosts->getName()] = $field_hosts; - - // Problem field. - $field_problem = new CWidgetFieldTextBox('problem', _('Problem')); - - if (array_key_exists('problem', $this->data)) { - $field_problem->setValue($this->data['problem']); - } - - $this->fields[$field_problem->getName()] = $field_problem; - - // Severity field. - $field_severities = new CWidgetFieldSeverities('severities', _('Severity')); - - if (array_key_exists('severities', $this->data)) { - $field_severities->setValue($this->data['severities']); - } - - $this->fields[$field_severities->getName()] = $field_severities; - - // Tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Tags array: tag, operator and value. No label, because it belongs to previous group. - $field_tags = new CWidgetFieldTags('tags', ''); - - if (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - - // Show suppressed problems. - $field_show_suppressed = (new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems'))) - ->setDefault(ZBX_PROBLEM_SUPPRESSED_FALSE); - - if (array_key_exists('show_suppressed', $this->data)) { - $field_show_suppressed->setValue($this->data['show_suppressed']); - } - - $this->fields[$field_show_suppressed->getName()] = $field_show_suppressed; - - // Hide groups without problems. - $field_hide_empty_groups = new CWidgetFieldCheckBox('hide_empty_groups', _('Hide groups without problems')); - - if (array_key_exists('hide_empty_groups', $this->data)) { - $field_hide_empty_groups->setValue($this->data['hide_empty_groups']); - } - - $this->fields[$field_hide_empty_groups->getName()] = $field_hide_empty_groups; - - // Problem display. - $field_ext_ack = (new CWidgetFieldRadioButtonList('ext_ack', _('Problem display'), [ - EXTACK_OPTION_ALL => _('All'), - EXTACK_OPTION_BOTH => _('Separated'), - EXTACK_OPTION_UNACK => _('Unacknowledged only') - ])) - ->setDefault(EXTACK_OPTION_ALL) - ->setFlags(CWidgetField::FLAG_ACKNOWLEDGES) - ->setModern(true); - - if (array_key_exists('ext_ack', $this->data)) { - $field_ext_ack->setValue($this->data['ext_ack']); - } - - $this->fields[$field_ext_ack->getName()] = $field_ext_ack; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormProblems.php b/ui/include/classes/widgets/forms/CWidgetFormProblems.php deleted file mode 100644 index 5236da642de..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormProblems.php +++ /dev/null @@ -1,243 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Problems widget form. - */ -class CWidgetFormProblems extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_PROBLEMS); - - $this->data = self::convertDottedKeys($this->data); - - // Output information option. - $field_show = (new CWidgetFieldRadioButtonList('show', _('Show'), [ - TRIGGERS_OPTION_RECENT_PROBLEM => _('Recent problems'), - TRIGGERS_OPTION_IN_PROBLEM => _('Problems'), - TRIGGERS_OPTION_ALL => _('History') - ])) - ->setDefault(TRIGGERS_OPTION_RECENT_PROBLEM) - ->setModern(true); - - if (array_key_exists('show', $this->data)) { - $field_show->setValue($this->data['show']); - } - - $this->fields[$field_show->getName()] = $field_show; - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - - $this->fields[$field_groups->getName()] = $field_groups; - - // Exclude host groups. - $field_exclude_groups = new CWidgetFieldMsGroup('exclude_groupids', _('Exclude host groups')); - - if (array_key_exists('exclude_groupids', $this->data)) { - $field_exclude_groups->setValue($this->data['exclude_groupids']); - } - - $this->fields[$field_exclude_groups->getName()] = $field_exclude_groups; - - // Hosts field. - $field_hosts = new CWidgetFieldMsHost('hostids', _('Hosts')); - $field_hosts->setFilterPreselect('groupids_'); - - if (array_key_exists('hostids', $this->data)) { - $field_hosts->setValue($this->data['hostids']); - } - - $this->fields[$field_hosts->getName()] = $field_hosts; - - // Problem field. - $field_problem = new CWidgetFieldTextBox('problem', _('Problem')); - - if (array_key_exists('problem', $this->data)) { - $field_problem->setValue($this->data['problem']); - } - - $this->fields[$field_problem->getName()] = $field_problem; - - // Severity field. - $field_severities = new CWidgetFieldSeverities('severities', _('Severity')); - - if (array_key_exists('severities', $this->data)) { - $field_severities->setValue($this->data['severities']); - } - - $this->fields[$field_severities->getName()] = $field_severities; - - // Tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Tags array: tag, operator and value. No label, because it belongs to previous group. - $field_tags = new CWidgetFieldTags('tags', ''); - - if (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - - // Show tags. - $field_show_tags = (new CWidgetFieldRadioButtonList('show_tags', _('Show tags'), [ - SHOW_TAGS_NONE => _('None'), - SHOW_TAGS_1 => SHOW_TAGS_1, - SHOW_TAGS_2 => SHOW_TAGS_2, - SHOW_TAGS_3 => SHOW_TAGS_3 - ])) - ->setDefault(SHOW_TAGS_NONE) - ->setModern(true) - ->setAction('var disabled = jQuery(this).filter("[value=\''.SHOW_TAGS_NONE.'\']").is(":checked");'. - 'jQuery("#tag_priority").prop("disabled", disabled);'. - 'jQuery("#tag_name_format input").prop("disabled", disabled)' - ); - - if (array_key_exists('show_tags', $this->data)) { - $field_show_tags->setValue($this->data['show_tags']); - } - - $this->fields[$field_show_tags->getName()] = $field_show_tags; - - // Tag name. - $tag_format_line = (new CWidgetFieldRadioButtonList('tag_name_format', _('Tag name'), [ - TAG_NAME_FULL => _('Full'), - TAG_NAME_SHORTENED => _('Shortened'), - TAG_NAME_NONE => _('None') - ])) - ->setDefault(TAG_NAME_FULL) - ->setModern(true); - - if (array_key_exists('tag_name_format', $this->data)) { - $tag_format_line->setValue($this->data['tag_name_format']); - } - $this->fields[$tag_format_line->getName()] = $tag_format_line; - - // Tag display priority. - $tag_priority = (new CWidgetFieldTextBox('tag_priority', _('Tag display priority'))); - - if (array_key_exists('tag_priority', $this->data)) { - $tag_priority->setValue($this->data['tag_priority']); - } - $this->fields[$tag_priority->getName()] = $tag_priority; - - // Show operational data. - $field_show_opdata = (new CWidgetFieldRadioButtonList('show_opdata', _('Show operational data'), [ - OPERATIONAL_DATA_SHOW_NONE => _('None'), - OPERATIONAL_DATA_SHOW_SEPARATELY => _('Separately'), - OPERATIONAL_DATA_SHOW_WITH_PROBLEM => _('With problem name') - ])) - ->setDefault(OPERATIONAL_DATA_SHOW_NONE) - ->setModern(true); - - if (array_key_exists('show_opdata', $this->data)) { - $field_show_opdata->setValue($this->data['show_opdata']); - } - - $this->fields[$field_show_opdata->getName()] = $field_show_opdata; - - // Show suppressed problems. - $field_show_suppressed = (new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems'))) - ->setDefault(ZBX_PROBLEM_SUPPRESSED_FALSE); - - if (array_key_exists('show_suppressed', $this->data)) { - $field_show_suppressed->setValue($this->data['show_suppressed']); - } - - $this->fields[$field_show_suppressed->getName()] = $field_show_suppressed; - - // Show unacknowledged only. - $field_unacknowledged = (new CWidgetFieldCheckBox('unacknowledged', _('Show unacknowledged only'))) - ->setFlags(CWidgetField::FLAG_ACKNOWLEDGES); - - if (array_key_exists('unacknowledged', $this->data)) { - $field_unacknowledged->setValue($this->data['unacknowledged']); - } - - $this->fields[$field_unacknowledged->getName()] = $field_unacknowledged; - - $sort_with_enabled_show_timeline = [ - SCREEN_SORT_TRIGGERS_TIME_DESC => true, - SCREEN_SORT_TRIGGERS_TIME_ASC => true - ]; - - // Sort entries by. - $field_sort = (new CWidgetFieldSelect('sort_triggers', _('Sort entries by'), [ - SCREEN_SORT_TRIGGERS_TIME_DESC => _('Time').' ('._('descending').')', - SCREEN_SORT_TRIGGERS_TIME_ASC => _('Time').' ('._('ascending').')', - SCREEN_SORT_TRIGGERS_SEVERITY_DESC => _('Severity').' ('._('descending').')', - SCREEN_SORT_TRIGGERS_SEVERITY_ASC => _('Severity').' ('._('ascending').')', - SCREEN_SORT_TRIGGERS_NAME_DESC => _('Problem').' ('._('descending').')', - SCREEN_SORT_TRIGGERS_NAME_ASC => _('Problem').' ('._('ascending').')', - SCREEN_SORT_TRIGGERS_HOST_NAME_DESC => _('Host').' ('._('descending').')', - SCREEN_SORT_TRIGGERS_HOST_NAME_ASC => _('Host').' ('._('ascending').')' - ])) - ->setDefault(SCREEN_SORT_TRIGGERS_TIME_DESC); - - if (array_key_exists('sort_triggers', $this->data)) { - $field_sort->setValue($this->data['sort_triggers']); - } - - $this->fields[$field_sort->getName()] = $field_sort; - - // Show timeline. - $field_show_timeline = (new CWidgetFieldCheckBox('show_timeline', _('Show timeline')))->setDefault(1); - - if (array_key_exists('show_timeline', $this->data)) { - $field_show_timeline->setValue($this->data['show_timeline']); - } - - if (!array_key_exists($field_sort->getValue(), $sort_with_enabled_show_timeline)) { - $field_show_timeline->setFlags(CWidgetField::FLAG_DISABLED); - } - - $this->fields[$field_show_timeline->getName()] = $field_show_timeline; - - // Show lines. - $field_lines = (new CWidgetFieldIntegerBox('show_lines', _('Show lines'), ZBX_MIN_WIDGET_LINES, - ZBX_MAX_WIDGET_LINES - )) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) - ->setDefault(ZBX_DEFAULT_WIDGET_LINES); - - if (array_key_exists('show_lines', $this->data)) { - $field_lines->setValue($this->data['show_lines']); - } - - $this->fields[$field_lines->getName()] = $field_lines; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormProblemsBySv.php b/ui/include/classes/widgets/forms/CWidgetFormProblemsBySv.php deleted file mode 100644 index c76820d6624..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormProblemsBySv.php +++ /dev/null @@ -1,202 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Problems by severity widget form. - */ -class CWidgetFormProblemsBySv extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_PROBLEMS_BY_SV); - - $this->data = self::convertDottedKeys($this->data); - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - - $this->fields[$field_groups->getName()] = $field_groups; - - // Exclude host groups. - $field_exclude_groups = new CWidgetFieldMsGroup('exclude_groupids', _('Exclude host groups')); - - if (array_key_exists('exclude_groupids', $this->data)) { - $field_exclude_groups->setValue($this->data['exclude_groupids']); - } - - $this->fields[$field_exclude_groups->getName()] = $field_exclude_groups; - - // Hosts field. - $field_hosts = new CWidgetFieldMsHost('hostids', _('Hosts')); - $field_hosts->setFilterPreselect('groupids_'); - - if (array_key_exists('hostids', $this->data)) { - $field_hosts->setValue($this->data['hostids']); - } - - $this->fields[$field_hosts->getName()] = $field_hosts; - - // Problem field. - $field_problem = new CWidgetFieldTextBox('problem', _('Problem')); - - if (array_key_exists('problem', $this->data)) { - $field_problem->setValue($this->data['problem']); - } - - $this->fields[$field_problem->getName()] = $field_problem; - - // Severity field. - $field_severities = new CWidgetFieldSeverities('severities', _('Severity')); - - if (array_key_exists('severities', $this->data)) { - $field_severities->setValue($this->data['severities']); - } - - $this->fields[$field_severities->getName()] = $field_severities; - - // Tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Tags array: tag, operator and value. No label, because it belongs to previous group. - $field_tags = new CWidgetFieldTags('tags', ''); - - if (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - - // Show type. - $field_show_type = (new CWidgetFieldRadioButtonList('show_type', _('Show'), [ - WIDGET_PROBLEMS_BY_SV_SHOW_GROUPS => _('Host groups'), - WIDGET_PROBLEMS_BY_SV_SHOW_TOTALS => _('Totals') - ])) - ->setDefault(WIDGET_PROBLEMS_BY_SV_SHOW_GROUPS) - ->setModern(true) - ->setAction('var disabled = jQuery(this).filter("[value=\''.WIDGET_PROBLEMS_BY_SV_SHOW_GROUPS.'\']")'. - '.is(":checked");'. - 'jQuery("#hide_empty_groups").prop("disabled", !disabled);'. - 'jQuery("#layout input").prop("disabled", disabled)' - ); - - if (array_key_exists('show_type', $this->data)) { - $field_show_type->setValue($this->data['show_type']); - } - - $this->fields[$field_show_type->getName()] = $field_show_type; - - // Layout. - $field_layout = (new CWidgetFieldRadioButtonList('layout', _('Layout'), [ - STYLE_HORIZONTAL => _('Horizontal'), - STYLE_VERTICAL => _('Vertical') - ])) - ->setDefault(STYLE_HORIZONTAL) - ->setModern(true); - - if (array_key_exists('layout', $this->data)) { - $field_layout->setValue($this->data['layout']); - } - - if ($field_show_type->getValue() == WIDGET_PROBLEMS_BY_SV_SHOW_GROUPS) { - $field_layout->setFlags(CWidgetField::FLAG_DISABLED); - } - - $this->fields[$field_layout->getName()] = $field_layout; - - // Show operational data. - $field_show_opdata = (new CWidgetFieldRadioButtonList('show_opdata', _('Show operational data'), [ - OPERATIONAL_DATA_SHOW_NONE => _('None'), - OPERATIONAL_DATA_SHOW_SEPARATELY => _('Separately'), - OPERATIONAL_DATA_SHOW_WITH_PROBLEM => _('With problem name') - ])) - ->setDefault(OPERATIONAL_DATA_SHOW_NONE) - ->setModern(true); - - if (array_key_exists('show_opdata', $this->data)) { - $field_show_opdata->setValue($this->data['show_opdata']); - } - - $this->fields[$field_show_opdata->getName()] = $field_show_opdata; - - // Show suppressed problems. - $field_show_suppressed = (new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems'))) - ->setDefault(ZBX_PROBLEM_SUPPRESSED_FALSE); - - if (array_key_exists('show_suppressed', $this->data)) { - $field_show_suppressed->setValue($this->data['show_suppressed']); - } - - $this->fields[$field_show_suppressed->getName()] = $field_show_suppressed; - - // Hide groups without problems. - $field_hide_empty_groups = new CWidgetFieldCheckBox('hide_empty_groups', _('Hide groups without problems')); - - if (array_key_exists('hide_empty_groups', $this->data)) { - $field_hide_empty_groups->setValue($this->data['hide_empty_groups']); - } - - if ($field_show_type->getValue() == WIDGET_PROBLEMS_BY_SV_SHOW_TOTALS) { - $field_hide_empty_groups->setFlags(CWidgetField::FLAG_DISABLED); - } - - $this->fields[$field_hide_empty_groups->getName()] = $field_hide_empty_groups; - - // Problem display. - $field_ext_ack = (new CWidgetFieldRadioButtonList('ext_ack', _('Problem display'), [ - EXTACK_OPTION_ALL => _('All'), - EXTACK_OPTION_BOTH => _('Separated'), - EXTACK_OPTION_UNACK => _('Unacknowledged only') - ])) - ->setDefault(EXTACK_OPTION_ALL) - ->setFlags(CWidgetField::FLAG_ACKNOWLEDGES) - ->setModern(true); - - if (array_key_exists('ext_ack', $this->data)) { - $field_ext_ack->setValue($this->data['ext_ack']); - } - - $this->fields[$field_ext_ack->getName()] = $field_ext_ack; - - // Show timeline. - $field_show_timeline = (new CWidgetFieldCheckBox('show_timeline', _('Show timeline'))) - ->setDefault(1); - - if (array_key_exists('show_timeline', $this->data)) { - $field_show_timeline->setValue($this->data['show_timeline']); - } - - $this->fields[$field_show_timeline->getName()] = $field_show_timeline; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormSlaReport.php b/ui/include/classes/widgets/forms/CWidgetFormSlaReport.php deleted file mode 100644 index e1a2f2705b0..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormSlaReport.php +++ /dev/null @@ -1,145 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CWidgetFormSlaReport extends CWidgetForm -{ - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_SLA_REPORT); - - // SLA. - $field_sla = (new CWidgetFieldMsSla('slaid', _('SLA'))) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) - ->setMultiple(false); - - if (array_key_exists('slaid', $this->data)) { - $field_sla->setValue($this->data['slaid']); - } - - $this->fields[$field_sla->getName()] = $field_sla; - - // Service. - $field_service = (new CWidgetFieldMsService('serviceid', _('Service'))) - ->setMultiple(false); - - if (array_key_exists('serviceid', $this->data)) { - $field_service->setValue($this->data['serviceid']); - } - - $this->fields[$field_service->getName()] = $field_service; - - // Show periods. - $field_show_periods = (new CWidgetFieldIntegerBox('show_periods', _('Show periods'), 1, - ZBX_SLA_MAX_REPORTING_PERIODS - ))->setDefault(ZBX_SLA_DEFAULT_REPORTING_PERIODS); - - if (array_key_exists('show_periods', $this->data)) { - $field_show_periods->setValue($this->data['show_periods']); - } - - $this->fields[$field_show_periods->getName()] = $field_show_periods; - - // Date from. - $field_date_from = new CWidgetFieldDatePicker('date_from', _('From'), true); - - if (array_key_exists('date_from', $this->data)) { - $field_date_from->setValue($this->data['date_from']); - } - - $this->fields[$field_date_from->getName()] = $field_date_from; - - // Date to. - $field_date_to = new CWidgetFieldDatePicker('date_to', _('To'), true); - - if (array_key_exists('date_to', $this->data)) { - $field_date_to->setValue($this->data['date_to']); - } - - $this->fields[$field_date_to->getName()] = $field_date_to; - } - - /** - * @param bool $strict - * - * @return array - */ - public function validate($strict = false): array { - if ($errors = parent::validate($strict)) { - return $errors; - } - - $errors = []; - - $slaids = $this->fields['slaid']->getValue(); - - $slas = $slaids - ? API::Sla()->get([ - 'output' => ['timezone'], - 'slaids' => $slaids, - 'filter' => [ - 'status' => ZBX_SLA_STATUS_ENABLED - ] - ]) - : []; - - $sla = $slas ? $slas[0] : null; - - $timezone = new DateTimeZone($sla !== null && $sla['timezone'] !== ZBX_DEFAULT_TIMEZONE - ? $sla['timezone'] - : CTimezoneHelper::getSystemTimezone() - ); - - $absolute_time_parser = new CAbsoluteTimeParser(); - - $period_from = null; - - if ($absolute_time_parser->parse($this->fields['date_from']->getValue()) == CParser::PARSE_SUCCESS) { - $period_from = $absolute_time_parser - ->getDateTime(true, $timezone) - ->getTimestamp(); - - if ($period_from < 0 || $period_from > ZBX_MAX_DATE) { - $period_from = null; - - $errors[] = _s('Incorrect value for field "%1$s": %2$s.', _s('From'), _('a date is expected')); - } - } - - $period_to = null; - - if ($absolute_time_parser->parse($this->fields['date_to']->getValue()) == CParser::PARSE_SUCCESS) { - $period_to = $absolute_time_parser - ->getDateTime(false, $timezone) - ->getTimestamp(); - - if ($period_to < 0 || $period_to > ZBX_MAX_DATE) { - $period_to = null; - - $errors[] = _s('Incorrect value for field "%1$s": %2$s.', _s('To'), _('a date is expected')); - } - } - - if ($period_from !== null && $period_to !== null && $period_to <= $period_from) { - $errors[] = _s('"%1$s" date must be less than "%2$s" date.', _('From'), _('To')); - } - - return $errors; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormSvgGraph.php b/ui/include/classes/widgets/forms/CWidgetFormSvgGraph.php deleted file mode 100644 index ca4f60adc92..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormSvgGraph.php +++ /dev/null @@ -1,635 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -class CWidgetFormSvgGraph extends CWidgetForm { - - private const WIDGET_ITEM_PERCENTILE_MIN = 1; - private const WIDGET_ITEM_PERCENTILE_MAX = 100; - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_SVG_GRAPH); - - $this->data = self::convertDottedKeys($this->data); - - $this->initDataSetFields(); - $this->initDisplayingOptionsFields(); - $this->initTimePeriodFields(); - $this->initAxesFields(); - $this->initLegendFields(); - $this->initProblemsFields(); - $this->initOverridesFields(); - } - - /** - * Validate form fields. - * - * @param bool $strict Enables more strict validation of the form fields. - * Must be enabled for validation of input parameters in the widget configuration form. - * - * @throws Exception - * - * @return array - */ - public function validate($strict = false): array { - $errors = parent::validate($strict); - - $number_parser_w_suffix = new CNumberParser(['with_size_suffix' => true, 'with_time_suffix' => true]); - $number_parser_wo_suffix = new CNumberParser(); - - // Percentiles - if ($this->fields['percentile_left']->getValue() == SVG_GRAPH_PERCENTILE_LEFT_ON) { - $percentile_left_value = $this->fields['percentile_left_value']->getValue(); - - if ($percentile_left_value !== '') { - $percentile_left_value_calculated = - $number_parser_wo_suffix->parse($percentile_left_value) == CParser::PARSE_SUCCESS - ? $number_parser_wo_suffix->calcValue() - : null; - - if ($percentile_left_value_calculated === null - || $percentile_left_value_calculated < self::WIDGET_ITEM_PERCENTILE_MIN - || $percentile_left_value_calculated > self::WIDGET_ITEM_PERCENTILE_MAX) { - $errors[] = _s('Invalid parameter "%1$s": %2$s.', _('Percentile line (left)'), - _s('value must be between "%1$s" and "%2$s"', self::WIDGET_ITEM_PERCENTILE_MIN, - self::WIDGET_ITEM_PERCENTILE_MAX - ) - ); - } - } - } - - if ($this->fields['percentile_right']->getValue() == SVG_GRAPH_PERCENTILE_RIGHT_ON) { - $percentile_right_value = $this->fields['percentile_right_value']->getValue(); - - if ($percentile_right_value !== '') { - $percentile_right_value_calculated = - $number_parser_wo_suffix->parse($percentile_right_value) == CParser::PARSE_SUCCESS - ? $number_parser_wo_suffix->calcValue() - : null; - - if ($percentile_right_value_calculated === null - || $percentile_right_value_calculated < self::WIDGET_ITEM_PERCENTILE_MIN - || $percentile_right_value_calculated > self::WIDGET_ITEM_PERCENTILE_MAX) { - $errors[] = _s('Invalid parameter "%1$s": %2$s.', _('Percentile line (right)'), - _s('value must be between "%1$s" and "%2$s"', self::WIDGET_ITEM_PERCENTILE_MIN, - self::WIDGET_ITEM_PERCENTILE_MAX - ) - ); - } - } - } - - // Test graph custom time period. - if ($this->fields['graph_time']->getValue() == SVG_GRAPH_CUSTOM_TIME) { - $errors = array_merge($errors, self::validateTimeSelectorPeriod($this->fields['time_from']->getValue(), - $this->fields['time_to']->getValue() - )); - } - - // Validate Min/Max values in Axes tab. - if ($this->fields['lefty']->getValue() == SVG_GRAPH_AXIS_SHOW) { - $lefty_min = - $number_parser_w_suffix->parse($this->fields['lefty_min']->getValue()) == CParser::PARSE_SUCCESS - ? $number_parser_w_suffix->calcValue() - : ''; - - $lefty_max = - $number_parser_w_suffix->parse($this->fields['lefty_max']->getValue()) == CParser::PARSE_SUCCESS - ? $number_parser_w_suffix->calcValue() - : ''; - - if ($lefty_min !== '' && $lefty_max !== '' && $lefty_min >= $lefty_max) { - $errors[] = _s('Invalid parameter "%1$s": %2$s.', _('Left Y').'/'._('Max'), - _('Y axis MAX value must be greater than Y axis MIN value') - ); - } - } - - if ($this->fields['righty']->getValue() == SVG_GRAPH_AXIS_SHOW) { - $righty_min = - $number_parser_w_suffix->parse($this->fields['righty_min']->getValue()) == CParser::PARSE_SUCCESS - ? $number_parser_w_suffix->calcValue() - : ''; - - $righty_max = - $number_parser_w_suffix->parse($this->fields['righty_max']->getValue()) == CParser::PARSE_SUCCESS - ? $number_parser_w_suffix->calcValue() - : ''; - - if ($righty_min !== '' && $righty_max !== '' && $righty_min >= $righty_max) { - $errors[] = _s('Invalid parameter "%1$s": %2$s.', _('Right Y').'/'._('Max'), - _('Y axis MAX value must be greater than Y axis MIN value') - ); - } - } - - return $errors; - } - - /** - * Check if widget configuration is set to use overridden time. - * - * @param array $fields Widget configuration fields. - * - * @return bool - */ - public static function hasOverrideTime(array $fields): bool { - return array_key_exists('graph_time', $fields) && $fields['graph_time'] == SVG_GRAPH_CUSTOM_TIME; - } - - private function initDataSetFields(): void { - $field_ds = (new CWidgetFieldGraphDataSet('ds', _('Data set')))->setFlags(CWidgetField::FLAG_NOT_EMPTY); - - if (array_key_exists('ds', $this->data)) { - $field_ds->setValue($this->data['ds']); - } - - $this->fields[$field_ds->getName()] = $field_ds; - } - - private function initDisplayingOptionsFields(): void { - // History data selection. - $field_data_source = (new CWidgetFieldRadioButtonList('source', _('History data selection'), [ - SVG_GRAPH_DATA_SOURCE_AUTO => _x('Auto', 'history source selection method'), - SVG_GRAPH_DATA_SOURCE_HISTORY => _('History'), - SVG_GRAPH_DATA_SOURCE_TRENDS => _('Trends') - ])) - ->setDefault(SVG_GRAPH_DATA_SOURCE_AUTO) - ->setModern(true); - - if (array_key_exists('source', $this->data)) { - $field_data_source->setValue($this->data['source']); - } - - $this->fields[$field_data_source->getName()] = $field_data_source; - - // Simple triggers. - $field_simple_triggers = new CWidgetFieldCheckBox('simple_triggers', _('Simple triggers')); - - if (array_key_exists('simple_triggers', $this->data)) { - $field_simple_triggers->setValue($this->data['simple_triggers']); - } - - $this->fields[$field_simple_triggers->getName()] = $field_simple_triggers; - - // Working time. - $field_working_time = new CWidgetFieldCheckBox('working_time', _('Working time')); - - if (array_key_exists('working_time', $this->data)) { - $field_working_time->setValue($this->data['working_time']); - } - - $this->fields[$field_working_time->getName()] = $field_working_time; - - // Percentile line left. - $field_percentile_left = new CWidgetFieldCheckBox('percentile_left', _('Percentile line (left)')); - - if (array_key_exists('percentile_left', $this->data)) { - $field_percentile_left->setValue($this->data['percentile_left']); - } - - $this->fields[$field_percentile_left->getName()] = $field_percentile_left; - - // Percentile line left value. - $field_percentile_left_value = (new CWidgetFieldTextBox('percentile_left_value', null)) - ->setPlaceholder(_('value')) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH); - - if ($field_percentile_left->getValue() != SVG_GRAPH_PERCENTILE_LEFT_ON) { - $field_percentile_left_value->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('percentile_left_value', $this->data)) { - $field_percentile_left_value->setValue($this->data['percentile_left_value']); - } - - $this->fields[$field_percentile_left_value->getName()] = $field_percentile_left_value; - - // Percentile line right. - $field_percentile_right = new CWidgetFieldCheckBox('percentile_right', _('Percentile line (right)')); - - if (array_key_exists('percentile_right', $this->data)) { - $field_percentile_right->setValue($this->data['percentile_right']); - } - - $this->fields[$field_percentile_right->getName()] = $field_percentile_right; - - // Percentile line right value. - $field_percentile_right_value = (new CWidgetFieldTextBox('percentile_right_value', null)) - ->setPlaceholder(_('value')) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH); - - if ($field_percentile_right->getValue() != SVG_GRAPH_PERCENTILE_RIGHT_ON) { - $field_percentile_right_value->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('percentile_right_value', $this->data)) { - $field_percentile_right_value->setValue($this->data['percentile_right_value']); - } - - $this->fields[$field_percentile_right_value->getName()] = $field_percentile_right_value; - } - - private function initTimePeriodFields(): void { - // Checkbox to specify either relative dashboard time or widget's own time. - $field_graph_time = new CWidgetFieldCheckBox('graph_time', _('Set custom time period')); - - if (array_key_exists('graph_time', $this->data)) { - $field_graph_time->setValue($this->data['graph_time']); - } - - $this->fields[$field_graph_time->getName()] = $field_graph_time; - - // Date from. - $field_time_from = (new CWidgetFieldDatePicker('time_from', _('From'), false)) - ->setDefault('now-1h') - ->setFlags(CWidgetField::FLAG_NOT_EMPTY); - - if ($field_graph_time->getValue() != SVG_GRAPH_CUSTOM_TIME) { - $field_time_from->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('time_from', $this->data)) { - $field_time_from->setValue($this->data['time_from']); - } - - $this->fields[$field_time_from->getName()] = $field_time_from; - - // Time to. - $field_time_to = (new CWidgetFieldDatePicker('time_to', _('To'), false)) - ->setDefault('now') - ->setFlags(CWidgetField::FLAG_NOT_EMPTY); - - if ($field_graph_time->getValue() != SVG_GRAPH_CUSTOM_TIME) { - $field_time_to->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('time_to', $this->data)) { - $field_time_to->setValue($this->data['time_to']); - } - - $this->fields[$field_time_to->getName()] = $field_time_to; - } - - private function initAxesFields(): void { - // Show left Y axis. - $field_lefty = (new CWidgetFieldCheckBox('lefty', _('Left Y'), _('Show')))->setDefault(SVG_GRAPH_AXIS_SHOW); - - if (array_key_exists('lefty', $this->data)) { - $field_lefty->setValue($this->data['lefty']); - } - - $this->fields[$field_lefty->getName()] = $field_lefty; - - // Min value on left Y axis. - $field_lefty_min = (new CWidgetFieldNumericBox('lefty_min', _('Min'))) - ->setPlaceholder(_('calculated')) - ->setFullName(_('Left Y').'/'._('Min')) - ->setWidth(ZBX_TEXTAREA_SMALL_WIDTH); - - if ($field_lefty->getValue() != SVG_GRAPH_AXIS_SHOW) { - $field_lefty_min->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('lefty_min', $this->data)) { - $field_lefty_min->setValue($this->data['lefty_min']); - } - - $this->fields[$field_lefty_min->getName()] = $field_lefty_min; - - // Max value on left Y axis. - $field_lefty_max = (new CWidgetFieldNumericBox('lefty_max', _('Max'))) - ->setPlaceholder(_('calculated')) - ->setFullName(_('Left Y').'/'._('Max')) - ->setWidth(ZBX_TEXTAREA_SMALL_WIDTH); - - if ($field_lefty->getValue() != SVG_GRAPH_AXIS_SHOW) { - $field_lefty_max->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('lefty_max', $this->data)) { - $field_lefty_max->setValue($this->data['lefty_max']); - } - - $this->fields[$field_lefty_max->getName()] = $field_lefty_max; - - // Specify the type of units on left Y axis. - $field_lefty_units = (new CWidgetFieldSelect('lefty_units', _('Units'), [ - SVG_GRAPH_AXIS_UNITS_AUTO => _x('Auto', 'history source selection method'), - SVG_GRAPH_AXIS_UNITS_STATIC => _x('Static', 'history source selection method') - ]))->setDefault(SVG_GRAPH_AXIS_UNITS_AUTO); - - if ($field_lefty->getValue() != SVG_GRAPH_AXIS_SHOW) { - $field_lefty_units->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('lefty_units', $this->data)) { - $field_lefty_units->setValue($this->data['lefty_units']); - } - - $this->fields[$field_lefty_units->getName()] = $field_lefty_units; - - // Static units on left Y axis. - $field_lefty_static_units = (new CWidgetFieldTextBox('lefty_static_units', null)) - ->setPlaceholder(_('value')) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH); - - if ($field_lefty->getValue() != SVG_GRAPH_AXIS_SHOW - || $field_lefty_units->getValue() != SVG_GRAPH_AXIS_UNITS_STATIC) { - $field_lefty_static_units->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('lefty_static_units', $this->data)) { - $field_lefty_static_units->setValue($this->data['lefty_static_units']); - } - - $this->fields[$field_lefty_static_units->getName()] = $field_lefty_static_units; - - // Show right Y axis. - $field_righty = (new CWidgetFieldCheckBox('righty', _('Right Y'), _('Show')))->setDefault(SVG_GRAPH_AXIS_SHOW); - - if (array_key_exists('righty', $this->data)) { - $field_righty->setValue($this->data['righty']); - } - - $this->fields[$field_righty->getName()] = $field_righty; - - // Min value on right Y axis. - $field_righty_min = (new CWidgetFieldNumericBox('righty_min', _('Min'))) - ->setPlaceholder(_('calculated')) - ->setFullName(_('Right Y').'/'._('Min')) - ->setWidth(ZBX_TEXTAREA_SMALL_WIDTH); - - if ($field_righty->getValue() != SVG_GRAPH_AXIS_SHOW) { - $field_righty_min->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('righty_min', $this->data)) { - $field_righty_min->setValue($this->data['righty_min']); - } - - $this->fields[$field_righty_min->getName()] = $field_righty_min; - - // Max value on right Y axis. - $field_righty_max = (new CWidgetFieldNumericBox('righty_max', _('Max'))) - ->setPlaceholder(_('calculated')) - ->setFullName(_('Right Y').'/'._('Max')) - ->setWidth(ZBX_TEXTAREA_SMALL_WIDTH); - - if ($field_righty->getValue() != SVG_GRAPH_AXIS_SHOW) { - $field_righty_max->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('righty_max', $this->data)) { - $field_righty_max->setValue($this->data['righty_max']); - } - - $this->fields[$field_righty_max->getName()] = $field_righty_max; - - // Specify the type of units on right Y axis. - $field_righty_units = (new CWidgetFieldSelect('righty_units', _('Units'), [ - SVG_GRAPH_AXIS_UNITS_AUTO => _x('Auto', 'history source selection method'), - SVG_GRAPH_AXIS_UNITS_STATIC => _x('Static', 'history source selection method') - ]))->setDefault(SVG_GRAPH_AXIS_UNITS_AUTO); - - if ($field_righty->getValue() != SVG_GRAPH_AXIS_SHOW) { - $field_righty_units->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('righty_units', $this->data)) { - $field_righty_units->setValue($this->data['righty_units']); - } - - $this->fields[$field_righty_units->getName()] = $field_righty_units; - - // Static units on right Y axis. - $field_righty_static_units = (new CWidgetFieldTextBox('righty_static_units', null)) - ->setPlaceholder(_('value')) - ->setWidth(ZBX_TEXTAREA_TINY_WIDTH); - - if ($field_righty->getValue() != SVG_GRAPH_AXIS_SHOW - || $field_righty_units->getValue() != SVG_GRAPH_AXIS_UNITS_STATIC) { - $field_righty_static_units->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('righty_static_units', $this->data)) { - $field_righty_static_units->setValue($this->data['righty_static_units']); - } - - $this->fields[$field_righty_static_units->getName()] = $field_righty_static_units; - - // Show X axis. - $field_axisx = (new CWidgetFieldCheckBox('axisx', _('X-Axis'), _('Show')))->setDefault(SVG_GRAPH_AXIS_SHOW); - - if (array_key_exists('axisx', $this->data)) { - $field_axisx->setValue($this->data['axisx']); - } - - $this->fields[$field_axisx->getName()] = $field_axisx; - } - - private function initLegendFields(): void { - /** - * Legend tab. - * - * Contains check-box field to show/hide legend and field to specify number of lines in which legend is shown. - */ - - $field_legend = (new CWidgetFieldCheckBox('legend', _('Show legend')))->setDefault(SVG_GRAPH_LEGEND_ON); - - if (array_key_exists('legend', $this->data)) { - $field_legend->setValue($this->data['legend']); - } - - $this->fields[$field_legend->getName()] = $field_legend; - - // Show legend statistic. - $field_legend_statistic = (new CWidgetFieldCheckBox('legend_statistic', _('Display min/max/avg'))) - ->setDefault(SVG_GRAPH_LEGEND_STATISTIC_OFF); - - if ($field_legend->getValue() == SVG_GRAPH_LEGEND_OFF) { - $field_legend_statistic->setFlags(CWidgetField::FLAG_DISABLED); - } - if (array_key_exists('legend_statistic', $this->data)) { - $field_legend_statistic->setValue($this->data['legend_statistic']); - } - - $this->fields[$field_legend_statistic->getName()] = $field_legend_statistic; - - // Number of lines. - $field_legend_lines = (new CWidgetFieldRangeControl('legend_lines', _('Number of rows'), - SVG_GRAPH_LEGEND_LINES_MIN, SVG_GRAPH_LEGEND_LINES_MAX - ))->setDefault(SVG_GRAPH_LEGEND_LINES_MIN); - - if ($field_legend->getValue() == SVG_GRAPH_LEGEND_OFF) { - $field_legend_lines->setFlags(CWidgetField::FLAG_DISABLED); - } - if (array_key_exists('legend_lines', $this->data)) { - $field_legend_lines->setValue($this->data['legend_lines']); - } - - $this->fields[$field_legend_lines->getName()] = $field_legend_lines; - - // Number of columns. - $field_legend_columns = (new CWidgetFieldRangeControl('legend_columns', _('Number of columns'), - SVG_GRAPH_LEGEND_COLUMNS_MIN, SVG_GRAPH_LEGEND_COLUMNS_MAX - ))->setDefault(SVG_GRAPH_LEGEND_COLUMNS_MAX); - - if ($field_legend_statistic->getValue() == SVG_GRAPH_LEGEND_STATISTIC_ON) { - $field_legend_columns->setFlags(CWidgetField::FLAG_DISABLED); - } - if (array_key_exists('legend_columns', $this->data)) { - $field_legend_columns->setValue($this->data['legend_columns']); - } - - $this->fields[$field_legend_columns->getName()] = $field_legend_columns; - } - - private function initProblemsFields(): void { - // Checkbox: Selected items only. - $field_show_problems = new CWidgetFieldCheckBox('show_problems', _('Show problems')); - - if (array_key_exists('show_problems', $this->data)) { - $field_show_problems->setValue($this->data['show_problems']); - } - - $this->fields[$field_show_problems->getName()] = $field_show_problems; - - // Checkbox: Selected items only. - $field_problems = (new CWidgetFieldCheckBox('graph_item_problems', _('Selected items only'))) - ->setDefault(SVG_GRAPH_SELECTED_ITEM_PROBLEMS); - - if ($field_show_problems->getValue() != SVG_GRAPH_PROBLEMS_SHOW) { - $field_problems->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('graph_item_problems', $this->data)) { - $field_problems->setValue($this->data['graph_item_problems']); - } - - $this->fields[$field_problems->getName()] = $field_problems; - - // Problem hosts. - $field_problemhosts = (new CWidgetFieldHostPatternSelect('problemhosts', _('Problem hosts'))) - ->setPlaceholder(_('host pattern')); - - if ($field_show_problems->getValue() != SVG_GRAPH_PROBLEMS_SHOW) { - $field_problemhosts->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('problemhosts', $this->data)) { - $field_problemhosts->setValue($this->data['problemhosts']); - } - - $this->fields[$field_problemhosts->getName()] = $field_problemhosts; - - // Severity checkboxes list. - $field_severities = new CWidgetFieldSeverities('severities', _('Severity')); - - if ($field_show_problems->getValue() != SVG_GRAPH_PROBLEMS_SHOW) { - $field_severities->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('severities', $this->data)) { - $field_severities->setValue($this->data['severities']); - } - - $this->fields[$field_severities->getName()] = $field_severities; - - // Problem name input-text field. - $field_problem_name = (new CWidgetFieldTextBox('problem_name', _('Problem'))) - ->setPlaceholder(_('problem pattern')); - - if ($field_show_problems->getValue() != SVG_GRAPH_PROBLEMS_SHOW) { - $field_problem_name->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('problem_name', $this->data)) { - $field_problem_name->setValue($this->data['problem_name']); - } - - $this->fields[$field_problem_name->getName()] = $field_problem_name; - - // Problem tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if ($field_show_problems->getValue() != SVG_GRAPH_PROBLEMS_SHOW) { - $field_evaltype->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Problem tags field. - $field_tags = new CWidgetFieldTags('tags', ''); - - if ($field_show_problems->getValue() != SVG_GRAPH_PROBLEMS_SHOW) { - $field_tags->setFlags(CWidgetField::FLAG_DISABLED); - } - elseif (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - } - - private function initOverridesFields(): void { - $field_or = (new CWidgetFieldGraphOverride('or', _('Overrides')))->setFlags(CWidgetField::FLAG_NOT_EMPTY); - - if (array_key_exists('or', $this->data)) { - $field_or->setValue($this->data['or']); - } - - $this->fields[$field_or->getName()] = $field_or; - } - - /** - * Validate "from" and "to" parameters for allowed period. - * - * @param string $from - * @param string $to - * - * @return array - */ - private static function validateTimeSelectorPeriod(string $from, string $to): array { - $errors = []; - $ts = []; - $ts['now'] = time(); - $range_time_parser = new CRangeTimeParser(); - - foreach (['from' => $from, 'to' => $to] as $field => $value) { - $range_time_parser->parse($value); - $ts[$field] = $range_time_parser - ->getDateTime($field === 'from') - ->getTimestamp(); - } - - $period = $ts['to'] - $ts['from'] + 1; - $range_time_parser->parse('now-'.CSettingsHelper::get(CSettingsHelper::MAX_PERIOD)); - $max_period = 1 + $ts['now'] - $range_time_parser - ->getDateTime(true) - ->getTimestamp(); - - if ($period < ZBX_MIN_PERIOD) { - $errors[] = _n('Minimum time period to display is %1$s minute.', - 'Minimum time period to display is %1$s minutes.', (int) (ZBX_MIN_PERIOD / SEC_PER_MIN) - ); - } - elseif ($period > $max_period) { - $errors[] = _n('Maximum time period to display is %1$s day.', - 'Maximum time period to display is %1$s days.', (int) round($max_period / SEC_PER_DAY) - ); - } - - return $errors; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormSystemInfo.php b/ui/include/classes/widgets/forms/CWidgetFormSystemInfo.php deleted file mode 100644 index 7a2f318bdcc..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormSystemInfo.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * System information widget form. - */ -class CWidgetFormSystemInfo extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_SYSTEM_INFO); - - $field_info_type = (new CWidgetFieldRadioButtonList('info_type', _('Show'), [ - ZBX_SYSTEM_INFO_SERVER_STATS => _('System stats'), - ZBX_SYSTEM_INFO_HAC_STATUS => _('High availability nodes') - ])) - ->setDefault(ZBX_SYSTEM_INFO_SERVER_STATS) - ->setModern(true); - - if (array_key_exists('info_type', $this->data)) { - $field_info_type->setValue($this->data['info_type']); - } - - $this->fields[$field_info_type->getName()] = $field_info_type; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormTopHosts.php b/ui/include/classes/widgets/forms/CWidgetFormTopHosts.php deleted file mode 100644 index a594b86e201..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormTopHosts.php +++ /dev/null @@ -1,171 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2021 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Top hosts data widget form. - */ -class CWidgetFormTopHosts extends CWidgetForm { - - const ORDER_TOPN = 2; - const ORDER_BOTTOMN = 3; - - const DEFAULT_HOSTS_COUNT = 10; - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_TOP_HOSTS); - - $this->data = self::convertDottedKeys($this->data); - - if (array_key_exists('columnsthresholds', $this->data)) { - foreach ($this->data['columnsthresholds'] as $column_index => $fields) { - $this->data['columns'][$column_index]['thresholds'] = []; - - foreach ($fields as $field_key => $field_values) { - foreach ($field_values as $value_index => $value) { - $this->data['columns'][$column_index]['thresholds'][$value_index][$field_key] = $value; - } - } - } - } - - // Apply sortable changes to data. - if (array_key_exists('sortorder', $this->data)) { - if (array_key_exists('column', $this->data) && array_key_exists('columns', $this->data['sortorder'])) { - // Fix selected column index when columns were sorted. - $this->data['column'] = array_search($this->data['column'], $this->data['sortorder']['columns']); - } - - foreach ($this->data['sortorder'] as $key => $sortorder) { - if (!array_key_exists($key, $this->data)) { - continue; - } - - $sorted = []; - - foreach ($sortorder as $index) { - $sorted[] = $this->data[$key][$index]; - } - - $this->data[$key] = $sorted; - } - } - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - - $this->fields[$field_groups->getName()] = $field_groups; - - // Hosts. - $field_hosts = new CWidgetFieldMsHost('hostids', _('Hosts')); - $field_hosts->setFilterPreselect('groupids_'); - - if (array_key_exists('hostids', $this->data)) { - $field_hosts->setValue($this->data['hostids']); - } - - $this->fields[$field_hosts->getName()] = $field_hosts; - - // Tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Host tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Tags array: tag, operator and value. No label, because it belongs to previous group. - $field_tags = new CWidgetFieldTags('tags', ''); - - if (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - - // Columns definition table. - $field_columns = (new CWidgetFieldColumnsList('columns', _('Columns'))) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK); - $field_column_values = []; - - if (array_key_exists('columns', $this->data)) { - $field_columns->setValue($this->data['columns']); - - foreach ($this->data['columns'] as $key => $value) { - if ($value['data'] == CWidgetFieldColumnsList::DATA_ITEM_VALUE) { - $field_column_values[$key] = ($value['name'] === '') ? $value['item'] : $value['name']; - } - } - } - - $this->fields[$field_columns->getName()] = $field_columns; - - // Order. - $field_order = (new CWidgetFieldRadioButtonList('order', _('Order'), [ - self::ORDER_TOPN => _('Top N'), - self::ORDER_BOTTOMN => _('Bottom N') - ])) - ->setDefault(self::ORDER_TOPN) - ->setModern(true); - - if (array_key_exists('order', $this->data)) { - $field_order->setValue($this->data['order']); - } - - $this->fields[$field_order->getName()] = $field_order; - - // Field column. - $field_column = (new CWidgetFieldSelect('column', _('Order column'), $field_column_values)) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK); - - if (array_key_exists('column', $this->data)) { - $field_column->setValue($this->data['column']); - } - else if ($field_column_values) { - reset($field_column_values); - $field_column->setValue((int) key($field_column_values)); - } - - $this->fields[$field_column->getName()] = $field_column; - - // Host count. - $field_count = (new CWidgetFieldIntegerBox('count', _('Host count'), ZBX_MIN_WIDGET_LINES, - ZBX_MAX_WIDGET_LINES - )) - ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) - ->setDefault(self::DEFAULT_HOSTS_COUNT); - - if (array_key_exists('count', $this->data)) { - $field_count->setValue((int) $this->data['count']); - } - - $this->fields[$field_count->getName()] = $field_count; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormTrigOver.php b/ui/include/classes/widgets/forms/CWidgetFormTrigOver.php deleted file mode 100644 index e4a1e76ca0c..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormTrigOver.php +++ /dev/null @@ -1,113 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Trigger overview widget form. - */ -class CWidgetFormTrigOver extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_TRIG_OVER); - - $this->data = self::convertDottedKeys($this->data); - - // Output information option. - $field_show = (new CWidgetFieldRadioButtonList('show', _('Show'), [ - TRIGGERS_OPTION_RECENT_PROBLEM => _('Recent problems'), - TRIGGERS_OPTION_IN_PROBLEM => _('Problems'), - TRIGGERS_OPTION_ALL => _('Any') - ])) - ->setDefault(TRIGGERS_OPTION_RECENT_PROBLEM) - ->setModern(true); - - if (array_key_exists('show', $this->data)) { - $field_show->setValue($this->data['show']); - } - - $this->fields[$field_show->getName()] = $field_show; - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - - $this->fields[$field_groups->getName()] = $field_groups; - - // Hosts. - $field_hosts = new CWidgetFieldMsHost('hostids', _('Hosts')); - $field_hosts->setFilterPreselect('groupids_'); - - if (array_key_exists('hostids', $this->data)) { - $field_hosts->setValue($this->data['hostids']); - } - - $this->fields[$field_hosts->getName()] = $field_hosts; - - // Tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Tags array: tag, operator and value. No label, because it belongs to previous group. - $field_tags = new CWidgetFieldTags('tags', ''); - - if (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - - // Show suppressed problems. - $field_show_suppressed = (new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems'))) - ->setDefault(ZBX_PROBLEM_SUPPRESSED_FALSE); - - if (array_key_exists('show_suppressed', $this->data)) { - $field_show_suppressed->setValue($this->data['show_suppressed']); - } - - $this->fields[$field_show_suppressed->getName()] = $field_show_suppressed; - - // Hosts names location. - $field_style = (new CWidgetFieldRadioButtonList('style', _('Hosts location'), [ - STYLE_LEFT => _('Left'), - STYLE_TOP => _('Top') - ])) - ->setDefault(STYLE_LEFT) - ->setModern(true); - - if (array_key_exists('style', $this->data)) { - $field_style->setValue($this->data['style']); - } - - $this->fields[$field_style->getName()] = $field_style; - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormUrl.php b/ui/include/classes/widgets/forms/CWidgetFormUrl.php deleted file mode 100644 index 2be6bd78530..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormUrl.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * URL widget form. - */ -class CWidgetFormUrl extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_URL); - - // URL field. - $field_url = (new CWidgetFieldUrl('url', _('URL'))) - ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK); - - if (array_key_exists('url', $this->data)) { - $field_url->setValue($this->data['url']); - } - - $this->fields[$field_url->getName()] = $field_url; - - // Dynamic item. - if ($templateid === null) { - $field_dynamic = (new CWidgetFieldCheckBox('dynamic', _('Enable host selection')))->setDefault(WIDGET_SIMPLE_ITEM); - - if (array_key_exists('dynamic', $this->data)) { - $field_dynamic->setValue($this->data['dynamic']); - } - - $this->fields[$field_dynamic->getName()] = $field_dynamic; - } - } -} diff --git a/ui/include/classes/widgets/forms/CWidgetFormWeb.php b/ui/include/classes/widgets/forms/CWidgetFormWeb.php deleted file mode 100644 index 00b33dc89e7..00000000000 --- a/ui/include/classes/widgets/forms/CWidgetFormWeb.php +++ /dev/null @@ -1,93 +0,0 @@ -<?php -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Web widget form. - */ -class CWidgetFormWeb extends CWidgetForm { - - public function __construct($data, $templateid) { - parent::__construct($data, $templateid, WIDGET_WEB); - - $this->data = self::convertDottedKeys($this->data); - - // Host groups. - $field_groups = new CWidgetFieldMsGroup('groupids', _('Host groups')); - - if (array_key_exists('groupids', $this->data)) { - $field_groups->setValue($this->data['groupids']); - } - - $this->fields[$field_groups->getName()] = $field_groups; - - // Exclude host groups. - $field_exclude_groups = new CWidgetFieldMsGroup('exclude_groupids', _('Exclude host groups')); - - if (array_key_exists('exclude_groupids', $this->data)) { - $field_exclude_groups->setValue($this->data['exclude_groupids']); - } - - $this->fields[$field_exclude_groups->getName()] = $field_exclude_groups; - - // Hosts field. - $field_hosts = new CWidgetFieldMsHost('hostids', _('Hosts')); - $field_hosts->setFilterPreselect('groupids_'); - - if (array_key_exists('hostids', $this->data)) { - $field_hosts->setValue($this->data['hostids']); - } - - $this->fields[$field_hosts->getName()] = $field_hosts; - - // Tag evaltype (And/Or). - $field_evaltype = (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ - TAG_EVAL_TYPE_AND_OR => _('And/Or'), - TAG_EVAL_TYPE_OR => _('Or') - ])) - ->setDefault(TAG_EVAL_TYPE_AND_OR) - ->setModern(true); - - if (array_key_exists('evaltype', $this->data)) { - $field_evaltype->setValue($this->data['evaltype']); - } - - $this->fields[$field_evaltype->getName()] = $field_evaltype; - - // Tags array: tag, operator and value. No label, because it belongs to previous group. - $field_tags = new CWidgetFieldTags('tags', ''); - - if (array_key_exists('tags', $this->data)) { - $field_tags->setValue($this->data['tags']); - } - - $this->fields[$field_tags->getName()] = $field_tags; - - // Show hosts in maintenance. - $field_maintenance = (new CWidgetFieldCheckBox('maintenance', _('Show hosts in maintenance'))) - ->setDefault(1); - - if (array_key_exists('maintenance', $this->data)) { - $field_maintenance->setValue($this->data['maintenance']); - } - - $this->fields[$field_maintenance->getName()] = $field_maintenance; - } -} diff --git a/ui/include/classes/widgets/views/js/widget.clock.form.view.js.php b/ui/include/classes/widgets/views/js/widget.clock.form.view.js.php deleted file mode 100644 index c7469b37ab3..00000000000 --- a/ui/include/classes/widgets/views/js/widget.clock.form.view.js.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ -?> - - -window.widget_clock_form = new class { - - init() { - this.form = document.getElementById('widget-dialogue-form'); - this.time_type = document.getElementById('time_type'); - this.clock_type = document.getElementById('clock_type'); - - this.show_date = document.getElementById('show_1'); - this.show_time = document.getElementById('show_2'); - this.show_tzone = document.getElementById('show_3'); - - this.advanced_configuration = document.getElementById('adv_conf'); - - for (const colorpicker of this.form.querySelectorAll('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) { - $(colorpicker).colorpicker({ - appendTo: '.overlay-dialogue-body', - use_default: true, - onUpdate: window.setIndicatorColor - }); - } - - this.time_type.addEventListener('change', () => { - ZABBIX.Dashboard.reloadWidgetProperties(); - this.updateForm(); - }); - - for (const checkbox of this.clock_type.querySelectorAll('input')) { - checkbox.addEventListener('change', () => this.updateForm()); - } - - const show = [this.show_date, this.show_time, this.show_tzone]; - - for (const checkbox of show) { - checkbox.addEventListener('change', (e) => { - if (show.filter((checkbox) => checkbox.checked).length > 0) { - this.updateForm(); - } - else { - e.target.checked = true; - } - }); - } - - this.advanced_configuration.addEventListener('change', () => this.updateForm()); - - this.updateForm(); - } - - updateForm() { - const is_digital = this.clock_type.querySelector('input:checked').value == <?= WIDGET_CLOCK_TYPE_DIGITAL ?>; - - const show_date_row = is_digital && this.advanced_configuration.checked && this.show_date.checked; - const show_time_row = is_digital && this.advanced_configuration.checked && this.show_time.checked; - const show_tzone_row = is_digital && this.advanced_configuration.checked && this.show_tzone.checked; - - for (const element of this.form.querySelectorAll('.js-row-show, .js-row-adv-conf')) { - element.style.display = is_digital ? '' : 'none'; - } - - for (const element of this.form.querySelectorAll('.js-row-bg-color')) { - element.style.display = is_digital && this.advanced_configuration.checked ? '' : 'none'; - } - - for (const element of this.form.querySelectorAll('.js-row-date')) { - element.style.display = show_date_row ? '' : 'none'; - } - - for (const element of this.form.querySelectorAll('.js-row-time')) { - element.style.display = show_time_row ? '' : 'none'; - } - - for (const element of this.form.querySelectorAll('.js-row-tzone')) { - element.style.display = show_tzone_row ? '' : 'none'; - } - - for (const element of this.form.querySelectorAll('.js-row-tzone-timezone, .js-row-tzone-format')) { - element.style.display = this.time_type.value != <?= TIME_TYPE_HOST ?> ? '' : 'none'; - } - } -}; diff --git a/ui/include/classes/widgets/views/widget.clock.form.view.php b/ui/include/classes/widgets/views/widget.clock.form.view.php deleted file mode 100644 index 23232749fb1..00000000000 --- a/ui/include/classes/widgets/views/widget.clock.form.view.php +++ /dev/null @@ -1,179 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Clock widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = [$this->readJsFile('../../../include/classes/widgets/views/js/widget.clock.form.view.js.php')]; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Time type. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['time_type']), - new CFormField(CWidgetHelper::getSelect($fields['time_type'])) -]); - -// Item. -if (array_key_exists('itemid', $fields)) { - $field_itemid = CWidgetHelper::getItem($fields['itemid'], $data['captions']['ms']['items']['itemid'], - $form->getName() - ); - $form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['itemid']), - new CFormField($field_itemid) - ]); - $scripts[] = $field_itemid->getPostJS(); -} - -// Clock type. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['clock_type']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['clock_type'])) -]); - -// Show. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show'])->addClass('js-row-show'), - (new CFormField( - CWidgetHelper::getCheckBoxList($fields['show'], [ - WIDGET_CLOCK_SHOW_DATE => _('Date'), - WIDGET_CLOCK_SHOW_TIME => _('Time'), - WIDGET_CLOCK_SHOW_TIMEZONE => _('Time zone') - ]) - ))->addClass('js-row-show') -]); - -// Advanced configuration. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['adv_conf'])->addClass('js-row-adv-conf'), - (new CFormField( - CWidgetHelper::getCheckBox($fields['adv_conf']) - ))->addClass('js-row-adv-conf') -]); - -// Background color. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['bg_color'])->addClass('js-row-bg-color'), - (new CFormField( - CWidgetHelper::getColor($fields['bg_color'], true) - ))->addClass('js-row-bg-color') -]); - -// Date. -$form_grid->addItem([ - (new CLabel(_('Date'))) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP_LABEL) - ->addClass('js-row-date'), - (new CDiv([ - CWidgetHelper::getLabel($fields['date_size']), - (new CFormField([CWidgetHelper::getIntegerBox($fields['date_size']), '%']))->addClass('field-size'), - - CWidgetHelper::getLabel($fields['date_bold']), - new CFormField(CWidgetHelper::getCheckBox($fields['date_bold'])), - - CWidgetHelper::getLabel($fields['date_color'])->addClass('offset-3'), - new CFormField(CWidgetHelper::getColor($fields['date_color'], true)) - ])) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP) - ->addClass('fields-group-date') - ->addClass('js-row-date') -]); - -// Time. -$form_grid->addItem([ - (new CLabel(_('Time'))) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP_LABEL) - ->addClass('js-row-time'), - (new CDiv([ - CWidgetHelper::getLabel($fields['time_size']), - (new CFormField([CWidgetHelper::getIntegerBox($fields['time_size']), '%']))->addClass('field-size'), - - CWidgetHelper::getLabel($fields['time_bold']), - new CFormField(CWidgetHelper::getCheckBox($fields['time_bold'])), - - CWidgetHelper::getLabel($fields['time_color'])->addClass('offset-3'), - new CFormField(CWidgetHelper::getColor($fields['time_color'], true)), - - CWidgetHelper::getLabel($fields['time_sec']), - new CFormField(CWidgetHelper::getCheckBox($fields['time_sec'])), - - CWidgetHelper::getLabel($fields['time_format']), - (new CFormField(CWidgetHelper::getRadioButtonList($fields['time_format'])))->addClass('field-format') - ])) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP) - ->addClass('fields-group-time') - ->addClass('js-row-time') -]); - -// Time zone. -$form_grid->addItem([ - (new CLabel(_('Time zone'))) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP_LABEL) - ->addClass('js-row-tzone'), - (new CDiv([ - CWidgetHelper::getLabel($fields['tzone_size']), - (new CFormField([CWidgetHelper::getIntegerBox($fields['tzone_size']), '%']))->addClass('field-size'), - - CWidgetHelper::getLabel($fields['tzone_bold']), - new CFormField(CWidgetHelper::getCheckBox($fields['tzone_bold'])), - - CWidgetHelper::getLabel($fields['tzone_color'])->addClass('offset-3'), - new CFormField(CWidgetHelper::getColor($fields['tzone_color'], true)), - - (CWidgetHelper::getLabel($fields['tzone_timezone']))->addClass('js-row-tzone-timezone'), - (new CFormField(CWidgetHelper::getSelect($fields['tzone_timezone']))) - ->addClass('field-timezone') - ->addClass('js-row-tzone-timezone'), - - (CWidgetHelper::getLabel($fields['tzone_format']))->addClass('js-row-tzone-format'), - (new CFormField(CWidgetHelper::getRadioButtonList($fields['tzone_format']))) - ->addClass('field-format') - ->addClass('js-row-tzone-format') - ])) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP) - ->addClass('fields-group-tzone') - ->addClass('js-row-tzone') -]); - -$scripts[] = $fields['tzone_timezone']->getJavascript(); - -$form->addItem($form_grid); - -$scripts[] = ' - widget_clock_form.init(); -'; - -return [ - 'form' => $form, - 'scripts' => $scripts -]; diff --git a/ui/include/classes/widgets/views/widget.dataover.form.view.php b/ui/include/classes/widgets/views/widget.dataover.form.view.php deleted file mode 100644 index 4823ba334fe..00000000000 --- a/ui/include/classes/widgets/views/widget.dataover.form.view.php +++ /dev/null @@ -1,90 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Data overview widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Hosts. -$field_hostids = CWidgetHelper::getHost($fields['hostids'], $data['captions']['ms']['hosts']['hostids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['hostids']), - new CFormField($field_hostids) -]); -$scripts[] = $field_hostids->getPostJS(); - -// Tags. -$form_grid - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem( - new CFormField(CWidgetHelper::getTags($fields['tags'])) - ); -$scripts[] = $fields['tags']->getJavascript(); -$jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - -// Show suppressed problems. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_suppressed']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_suppressed'])) -]); - -// Hosts location. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['style']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['style'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/classes/widgets/views/widget.geomap.form.view.php b/ui/include/classes/widgets/views/widget.geomap.form.view.php deleted file mode 100644 index 0a61d3d2cb3..00000000000 --- a/ui/include/classes/widgets/views/widget.geomap.form.view.php +++ /dev/null @@ -1,96 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Map widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Hosts. -$field_hostids = CWidgetHelper::getHost($fields['hostids'], $data['captions']['ms']['hosts']['hostids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['hostids']), - new CFormField($field_hostids) -]); -$scripts[] = $field_hostids->getPostJS(); - -// Tags. -$form_grid - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem( - new CFormField(CWidgetHelper::getTags($fields['tags'])) - ); -$scripts[] = $fields['tags']->getJavascript(); -$jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - -// Initial view. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['default_view'], null, [ - _('Comma separated center coordinates and zoom level to display when the widget is initially loaded.'), - BR(), - _('Supported formats:'), - (new CList([ - new CListItem((new CSpan('<lat>,<lng>,<zoom>'))->addClass(ZBX_STYLE_MONOSPACE_FONT)), - new CListItem((new CSpan('<lat>,<lng>'))->addClass(ZBX_STYLE_MONOSPACE_FONT)) - ]))->addClass(ZBX_STYLE_LIST_DASHED), - BR(), - _s('The maximum zoom level is "%1$s".', CSettingsHelper::get(CSettingsHelper::GEOMAPS_MAX_ZOOM)), - BR(), - _('Initial view is ignored if the default view is set.') - ]), - new CFormField(CWidgetHelper::getLatLngZoomBox($fields['default_view'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/classes/widgets/views/widget.graph.form.view.php b/ui/include/classes/widgets/views/widget.graph.form.view.php deleted file mode 100644 index 31dea04b1dc..00000000000 --- a/ui/include/classes/widgets/views/widget.graph.form.view.php +++ /dev/null @@ -1,89 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Graph widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Source. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['source_type']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['source_type'])) -]); - -// Graph. -if (array_key_exists('graphid', $fields)) { - $field_graphid = CWidgetHelper::getGraph($fields['graphid'], $data['captions']['ms']['graphs']['graphid'], - $form->getName() - ); - $form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['graphid']), - new CFormField($field_graphid) - ]); - $scripts[] = $field_graphid->getPostJS(); -} - -// Item. -if (array_key_exists('itemid', $fields)) { - $field_itemid = CWidgetHelper::getItem($fields['itemid'], $data['captions']['ms']['items']['itemid'], - $form->getName() - ); - $form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['itemid']), - new CFormField($field_itemid) - ]); - $scripts[] = $field_itemid->getPostJS(); -} - -// Show legend. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_legend']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_legend'])) -]); - -// Dynamic item. -if ($data['templateid'] === null) { - $form_grid->addItem([ - CWidgetHelper::getLabel($fields['dynamic']), - new CFormField(CWidgetHelper::getCheckBox($fields['dynamic'])) - ]); -} - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts -]; diff --git a/ui/include/classes/widgets/views/widget.graphprototype.form.view.php b/ui/include/classes/widgets/views/widget.graphprototype.form.view.php deleted file mode 100644 index 400b4c9ef87..00000000000 --- a/ui/include/classes/widgets/views/widget.graphprototype.form.view.php +++ /dev/null @@ -1,101 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Graph prototype widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Source. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['source_type']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['source_type'])) -]); - -// Graph prototype. -if (array_key_exists('graphid', $fields)) { - $field_graphid = CWidgetHelper::getGraphPrototype($fields['graphid'], - $data['captions']['ms']['graph_prototypes']['graphid'], $form->getName() - ); - $form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['graphid']), - new CFormField($field_graphid) - ]); - $scripts[] = $field_graphid->getPostJS(); -} - -// Item prototype. -if (array_key_exists('itemid', $fields)) { - $field_itemid = CWidgetHelper::getItemPrototype($fields['itemid'], - $data['captions']['ms']['item_prototypes']['itemid'], $form->getName() - ); - $form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['itemid']), - new CFormField($field_itemid) - ]); - $scripts[] = $field_itemid->getPostJS(); -} - -// Show legend. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_legend']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_legend'])) -]); - -// Dynamic item. -if ($data['templateid'] === null) { - $form_grid->addItem([ - CWidgetHelper::getLabel($fields['dynamic']), - new CFormField(CWidgetHelper::getCheckBox($fields['dynamic'])) - ]); -} - -// Columns. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['columns']), - new CFormField(CWidgetHelper::getIntegerBox($fields['columns'])) -]); - -// Rows. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['rows']), - new CFormField(CWidgetHelper::getIntegerBox($fields['rows'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts -]; diff --git a/ui/include/classes/widgets/views/widget.hostavail.form.view.php b/ui/include/classes/widgets/views/widget.hostavail.form.view.php deleted file mode 100644 index a691fc0cafc..00000000000 --- a/ui/include/classes/widgets/views/widget.hostavail.form.view.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Host availability widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Interface type. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['interface_type']), - new CFormField( - CWidgetHelper::getCheckBoxList($fields['interface_type'], [ - INTERFACE_TYPE_AGENT => _('Zabbix agent'), - INTERFACE_TYPE_SNMP => _('SNMP'), - INTERFACE_TYPE_JMX => _('JMX'), - INTERFACE_TYPE_IPMI => _('IPMI') - ]) - ) -]); - -// Layout. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['layout']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['layout'])) -]); - -// Show hosts in maintenance. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['maintenance']), - new CFormField(CWidgetHelper::getCheckBox($fields['maintenance'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts -]; diff --git a/ui/include/classes/widgets/views/widget.item.form.view.php b/ui/include/classes/widgets/views/widget.item.form.view.php deleted file mode 100644 index cad8ddd6962..00000000000 --- a/ui/include/classes/widgets/views/widget.item.form.view.php +++ /dev/null @@ -1,262 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Item value widget. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = [$this->readJsFile('../../../include/classes/widgets/views/js/widget.item.form.view.js.php')]; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Item. -$field_itemid = CWidgetHelper::getItem($fields['itemid'], $data['captions']['ms']['items']['itemid'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['itemid']), - new CFormField($field_itemid) -]); -$scripts[] = $field_itemid->getPostJS(); - -// Show. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show']), - new CFormField( - CWidgetHelper::getCheckBoxList($fields['show'], [ - WIDGET_ITEM_SHOW_DESCRIPTION => _('Description'), - WIDGET_ITEM_SHOW_VALUE => _('Value'), - WIDGET_ITEM_SHOW_TIME => _('Time'), - WIDGET_ITEM_SHOW_CHANGE_INDICATOR => _('Change indicator') - ], [ZBX_STYLE_COLUMNS, ZBX_STYLE_COLUMNS_2]) - ) -]); - -// Advanced configuration. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['adv_conf']), - new CFormField(CWidgetHelper::getCheckBox($fields['adv_conf'])) -]); - -// Description. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['description'], CFormGrid::ZBX_STYLE_FIELDS_GROUP_LABEL, [ - _('Supported macros:'), - (new CList([ - '{HOST.*}', - '{ITEM.*}', - '{INVENTORY.*}', - _('User macros') - ]))->addClass(ZBX_STYLE_LIST_DASHED) - ])->addClass('js-row-description'), - (new CDiv([ - new CFormField( - CWidgetHelper::getTextArea($fields['description']) - ->setAttribute('maxlength', DB::getFieldLength('widget_field', 'value_str')) - ), - - CWidgetHelper::getLabel($fields['desc_h_pos']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['desc_h_pos'])), - - CWidgetHelper::getLabel($fields['desc_size']), - (new CFormField([CWidgetHelper::getIntegerBox($fields['desc_size']), '%']))->addClass('field-size'), - - CWidgetHelper::getLabel($fields['desc_v_pos']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['desc_v_pos'])), - - CWidgetHelper::getLabel($fields['desc_bold']), - new CFormField(CWidgetHelper::getCheckBox($fields['desc_bold'])), - - CWidgetHelper::getLabel($fields['desc_color'])->addClass('offset-3'), - new CFormField(CWidgetHelper::getColor($fields['desc_color'], true)) - ])) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP) - ->addClass('fields-group-description') - ->addClass('js-row-description') -]); - -// Value. -$form_grid->addItem([ - (new CLabel(_('Value'))) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP_LABEL) - ->addClass('js-row-value'), - (new CDiv([ - CWidgetHelper::getLabel($fields['decimal_places']), - new CFormField(CWidgetHelper::getIntegerBox($fields['decimal_places'])), - - CWidgetHelper::getLabel($fields['decimal_size']), - (new CFormField([CWidgetHelper::getIntegerBox($fields['decimal_size']), '%']))->addClass('field-size'), - - new CTag('hr'), - - CWidgetHelper::getLabel($fields['value_h_pos']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['value_h_pos'])), - - CWidgetHelper::getLabel($fields['value_size']), - (new CFormField([CWidgetHelper::getIntegerBox($fields['value_size']), '%']))->addClass('field-size'), - - CWidgetHelper::getLabel($fields['value_v_pos']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['value_v_pos'])), - - CWidgetHelper::getLabel($fields['value_bold']), - new CFormField(CWidgetHelper::getCheckBox($fields['value_bold'])), - - CWidgetHelper::getLabel($fields['value_color'])->addClass('offset-3'), - new CFormField(CWidgetHelper::getColor($fields['value_color'], true)), - - new CTag('hr'), - - (new CDiv([ - CWidgetHelper::getCheckBox($fields['units_show']), - CWidgetHelper::getLabel($fields['units']) - ]))->addClass('units-show'), - - (new CFormField( - CWidgetHelper::getTextBox($fields['units']) - ->setAttribute('style', '') - ->setAdaptiveWidth(ZBX_TEXTAREA_BIG_WIDTH) - ))->addClass(CFormField::ZBX_STYLE_FORM_FIELD_FLUID), - - CWidgetHelper::getLabel($fields['units_pos'], null, - _('Position is ignored for s, uptime and unixtime units.') - ), - new CFormField(CWidgetHelper::getSelect($fields['units_pos'])), - - CWidgetHelper::getLabel($fields['units_size']), - (new CFormField([CWidgetHelper::getIntegerBox($fields['units_size']), '%']))->addClass('field-size'), - - CWidgetHelper::getLabel($fields['units_bold'])->addClass('offset-3'), - new CFormField(CWidgetHelper::getCheckBox($fields['units_bold'])), - - CWidgetHelper::getLabel($fields['units_color'])->addClass('offset-3'), - new CFormField(CWidgetHelper::getColor($fields['units_color'], true)) - ])) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP) - ->addClass('fields-group-value') - ->addClass('js-row-value') -]); - -// Time. -$form_grid->addItem([ - (new CLabel(_('Time'))) - ->addCLass(CFormGrid::ZBX_STYLE_FIELDS_GROUP_LABEL) - ->addClass('js-row-time'), - (new CDiv([ - CWidgetHelper::getLabel($fields['time_h_pos']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['time_h_pos'])), - - CWidgetHelper::getLabel($fields['time_size']), - (new CFormField([CWidgetHelper::getIntegerBox($fields['time_size']), '%']))->addClass('field-size'), - - CWidgetHelper::getLabel($fields['time_v_pos']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['time_v_pos'])), - - CWidgetHelper::getLabel($fields['time_bold']), - new CFormField(CWidgetHelper::getCheckBox($fields['time_bold'])), - - CWidgetHelper::getLabel($fields['time_color'])->addClass('offset-3'), - new CFormField(CWidgetHelper::getColor($fields['time_color'], true)) - ])) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP) - ->addClass('fields-group-time') - ->addClass('js-row-time') -]); - -// Change indicator. -$form_grid->addItem([ - (new CLabel(_('Change indicator'))) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP_LABEL) - ->addClass('js-row-change-indicator'), - (new CDiv([ - (new CSvgArrow(['up' => true, 'fill_color' => $fields['up_color']->getValue()])) - ->setId('change-indicator-up') - ->setSize(14, 20), - new CFormField(CWidgetHelper::getColor($fields['up_color'], true)), - - (new CSvgArrow(['down' => true, 'fill_color' => $fields['down_color']->getValue()])) - ->setId('change-indicator-down') - ->setSize(14, 20), - new CFormField(CWidgetHelper::getColor($fields['down_color'], true)), - - (new CSvgArrow(['up' => true, 'down' => true, 'fill_color' => $fields['updown_color']->getValue()])) - ->setId('change-indicator-updown') - ->setSize(14, 20), - new CFormField(CWidgetHelper::getColor($fields['updown_color'], true)) - ])) - ->addClass(CFormGrid::ZBX_STYLE_FIELDS_GROUP) - ->addClass('fields-group-change-indicator') - ->addClass('js-row-change-indicator') -]); - -// Background color. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['bg_color'])->addClass('js-row-bg-color'), - (new CFormField(CWidgetHelper::getColor($fields['bg_color'], true)))->addClass('js-row-bg-color') -]); - -// Thresholds. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['thresholds']) - ->addItem( - (new CSpan([ - ' ', - makeWarningIcon(_('This setting applies only to numeric data.')) - ]))->setId('item-value-thresholds-warning')) - ->addClass('js-row-thresholds'), - (new CFormField(CWidgetHelper::getThresholds($fields['thresholds'])))->addClass('js-row-thresholds') -]); -$scripts[] = $fields['thresholds']->getJavascript(); - -$thresholds_tmpl_id = sprintf(CWidgetFieldThresholds::THRESHOLDS_ROW_TMPL_ID, $fields['thresholds']->getName()); -$jq_templates[$thresholds_tmpl_id] = CWidgetHelper::getThresholdsTemplate($fields['thresholds']->getName()) - ->toString(); - -// Dynamic item. -if ($data['templateid'] === null) { - $form_grid->addItem([ - CWidgetHelper::getLabel($fields['dynamic']), - new CFormField(CWidgetHelper::getCheckBox($fields['dynamic'])) - ]); -} - -$form->addItem($form_grid); - -$scripts[] = ' - widget_item_form.init('.json_encode([ - 'thresholds_colors' => CWidgetFieldColumnsList::THRESHOLDS_DEFAULT_COLOR_PALETTE - ]).'); -'; - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/classes/widgets/views/widget.map.form.view.php b/ui/include/classes/widgets/views/widget.map.form.view.php deleted file mode 100644 index c2de3627efc..00000000000 --- a/ui/include/classes/widgets/views/widget.map.form.view.php +++ /dev/null @@ -1,85 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Map widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Map widget reference. -$form->addVar($fields[CWidgetFieldReference::FIELD_NAME]->getName(), - $fields[CWidgetFieldReference::FIELD_NAME]->getValue() -); - -// Source type. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['source_type']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['source_type'])) -]); - -// Map. -if (array_key_exists('sysmapid', $fields)) { - $field = $fields['sysmapid']; - - $form->addVar($field->getName(), $field->getValue()); - - $form_grid->addItem([ - CWidgetHelper::getLabel($field), - new CFormField( - CWidgetHelper::getSelectResource( - $field, - $field->getValue() != 0 - ? $data['captions']['simple'][$field->getResourceType()][$field->getValue()] - : '', - $form->getName() - ) - ) - ]); -} - -// Filter. -if (array_key_exists('filter_widget_reference', $fields)) { - $form_grid->addItem([ - CWidgetHelper::getLabel($fields['filter_widget_reference']), - new CFormField(CWidgetHelper::getEmptySelect($fields['filter_widget_reference'])) - ]); - $scripts[] = $fields['filter_widget_reference']->getJavascript(); -} - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts -]; diff --git a/ui/include/classes/widgets/views/widget.navtree.form.view.php b/ui/include/classes/widgets/views/widget.navtree.form.view.php deleted file mode 100644 index 96601e3f47d..00000000000 --- a/ui/include/classes/widgets/views/widget.navtree.form.view.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Map navigation tree widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Map widget reference. -$form->addItem( - (new CVar($fields[CWidgetFieldReference::FIELD_NAME]->getName(), - $fields[CWidgetFieldReference::FIELD_NAME]->getValue() - ))->removeId() -); - -// Add dynamically created fields navtree.name.<N>, navtree.parent.<N>, navtree.order.<N> and navtree.sysmapid.<N>. -foreach ($fields['navtree']->getValue() as $i => $navtree_item) { - $form->addItem((new CVar($fields['navtree']->getName().'.name.'.$i, $navtree_item['name']))->removeId()); - - if ($navtree_item['order'] != 1) { - $form->addItem((new CVar($fields['navtree']->getName().'.order.'.$i, $navtree_item['order']))->removeId()); - } - if ($navtree_item['parent'] != 0) { - $form->addItem((new CVar($fields['navtree']->getName().'.parent.'.$i, $navtree_item['parent']))->removeId()); - } - if (array_key_exists('sysmapid', $navtree_item)) { - $form->addItem( - (new CVar($fields['navtree']->getName().'.sysmapid.'.$i, $navtree_item['sysmapid']))->removeId() - ); - } -} - -// Show unavailable maps. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_unavailable']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_unavailable'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form -]; diff --git a/ui/include/classes/widgets/views/widget.plaintext.form.view.php b/ui/include/classes/widgets/views/widget.plaintext.form.view.php deleted file mode 100644 index 649a4d0941b..00000000000 --- a/ui/include/classes/widgets/views/widget.plaintext.form.view.php +++ /dev/null @@ -1,81 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Plain text widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Items. -$field_itemids = CWidgetHelper::getItem($fields['itemids'], $data['captions']['ms']['items']['itemids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['itemids']), - new CFormField($field_itemids) -]); -$scripts[] = $field_itemids->getPostJS(); - -// Items location. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['style']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['style'])) -]); - -// Show lines. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_lines']), - new CFormField(CWidgetHelper::getIntegerBox($fields['show_lines'])) -]); - -// Show text as HTML. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_as_html']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_as_html'])) -]); - -// Dynamic item. -if ($data['templateid'] === null) { - $form_grid->addItem([ - CWidgetHelper::getLabel($fields['dynamic']), - new CFormField(CWidgetHelper::getCheckBox($fields['dynamic'])) - ]); -} - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts -]; diff --git a/ui/include/classes/widgets/views/widget.problemhosts.form.view.php b/ui/include/classes/widgets/views/widget.problemhosts.form.view.php deleted file mode 100644 index c748d2119dd..00000000000 --- a/ui/include/classes/widgets/views/widget.problemhosts.form.view.php +++ /dev/null @@ -1,118 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Problem hosts widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Exclude host groups. -$field_exclude_groupids = CWidgetHelper::getGroup($fields['exclude_groupids'], - $data['captions']['ms']['groups']['exclude_groupids'], $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['exclude_groupids']), - new CFormField($field_exclude_groupids) -]); -$scripts[] = $field_exclude_groupids->getPostJS(); - -// Hosts. -$field_hostids = CWidgetHelper::getHost($fields['hostids'], $data['captions']['ms']['hosts']['hostids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['hostids']), - new CFormField($field_hostids) -]); -$scripts[] = $field_hostids->getPostJS(); - -// Problem. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['problem']), - new CFormField(CWidgetHelper::getTextBox($fields['problem'])) -]); - -// Severity. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['severities']), - new CFormField(CWidgetHelper::getSeverities($fields['severities'])) -]); - -// Tags. -$form_grid - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem( - new CFormField(CWidgetHelper::getTags($fields['tags'])) - ); -$scripts[] = $fields['tags']->getJavascript(); -$jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - -// Show suppressed problems. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_suppressed']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_suppressed'])) -]); - -// Hide groups without problems. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['hide_empty_groups']), - new CFormField(CWidgetHelper::getCheckBox($fields['hide_empty_groups'])) -]); - -// Problem display. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['ext_ack']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['ext_ack'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/classes/widgets/views/widget.problems.form.view.php b/ui/include/classes/widgets/views/widget.problems.form.view.php deleted file mode 100644 index a806e7464a4..00000000000 --- a/ui/include/classes/widgets/views/widget.problems.form.view.php +++ /dev/null @@ -1,178 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Problems widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = [$this->readJsFile('../../../include/classes/widgets/views/js/widget.problems.form.view.js.php')]; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Show. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['show'])) -]); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Exclude host groups. -$field_exclude_groupids = CWidgetHelper::getGroup($fields['exclude_groupids'], - $data['captions']['ms']['groups']['exclude_groupids'], $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['exclude_groupids']), - new CFormField($field_exclude_groupids) -]); -$scripts[] = $field_exclude_groupids->getPostJS(); - -// Hosts. -$field_hostids = CWidgetHelper::getHost($fields['hostids'], $data['captions']['ms']['hosts']['hostids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['hostids']), - new CFormField($field_hostids) -]); -$scripts[] = $field_hostids->getPostJS(); - -// Problem. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['problem']), - new CFormField(CWidgetHelper::getTextBox($fields['problem'])) -]); - -// Severity. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['severities']), - new CFormField(CWidgetHelper::getSeverities($fields['severities'])) -]); - -// Tags. -$form_grid - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem( - new CFormField(CWidgetHelper::getTags($fields['tags'])) - ); -$scripts[] = $fields['tags']->getJavascript(); -$jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - -// Show tags. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_tags']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['show_tags'])) -]); - -// Tag name. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['tag_name_format']), - new CFormField( - CWidgetHelper::getRadioButtonList($fields['tag_name_format']) - ->setEnabled($fields['show_tags']->getValue() !== SHOW_TAGS_NONE) - ) -]); - -// Tag display priority. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['tag_priority']), - new CFormField( - CWidgetHelper::getTextBox($fields['tag_priority']) - ->setAttribute('placeholder', _('comma-separated list')) - ->setEnabled($fields['show_tags']->getValue() !== SHOW_TAGS_NONE) - ) -]); - -// Show operational data. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_opdata']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['show_opdata'])) -]); - -// Show suppressed problems. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_suppressed']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_suppressed'])) -]); - -// Show unacknowledged only. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['unacknowledged']), - new CFormField(CWidgetHelper::getCheckBox($fields['unacknowledged'])) -]); - -// Sort entries by. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['sort_triggers']), - new CFormField(CWidgetHelper::getSelect($fields['sort_triggers'])) -]); - -// Show timeline. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_timeline']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_timeline'])) -]); - -// Show lines. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_lines']), - new CFormField(CWidgetHelper::getIntegerBox($fields['show_lines'])) -]); - -$form - ->addItem($form_grid) - ->addItem( - (new CScriptTag(' - widget_problems_form.init('.json_encode([ - 'sort_with_enabled_show_timeline' => [ - SCREEN_SORT_TRIGGERS_TIME_DESC => true, - SCREEN_SORT_TRIGGERS_TIME_ASC => true - ] - ]).'); - '))->setOnDocumentReady() - ); - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/classes/widgets/views/widget.problemsbysv.form.view.php b/ui/include/classes/widgets/views/widget.problemsbysv.form.view.php deleted file mode 100644 index f1e48a701ce..00000000000 --- a/ui/include/classes/widgets/views/widget.problemsbysv.form.view.php +++ /dev/null @@ -1,142 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Problems by severity widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Exclude host groups. -$field_exclude_groupids = CWidgetHelper::getGroup($fields['exclude_groupids'], - $data['captions']['ms']['groups']['exclude_groupids'], $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['exclude_groupids']), - new CFormField($field_exclude_groupids) -]); -$scripts[] = $field_exclude_groupids->getPostJS(); - -// Hosts. -$field_hostids = CWidgetHelper::getHost($fields['hostids'], $data['captions']['ms']['hosts']['hostids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['hostids']), - new CFormField($field_hostids) -]); -$scripts[] = $field_hostids->getPostJS(); - -// Problem. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['problem']), - new CFormField(CWidgetHelper::getTextBox($fields['problem'])) -]); - -// Severity. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['severities']), - new CFormField(CWidgetHelper::getSeverities($fields['severities'])) -]); - -// Tags. -$form_grid - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem( - new CFormField(CWidgetHelper::getTags($fields['tags'])) - ); -$scripts[] = $fields['tags']->getJavascript(); -$jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - -// Show. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_type']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['show_type'])) -]); - -// Layout. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['layout']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['layout'])) -]); - -// Show operational data. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_opdata']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['show_opdata'])) -]); - -// Show suppressed problems. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_suppressed']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_suppressed'])) -]); - -// Hide groups without problems. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['hide_empty_groups']), - new CFormField(CWidgetHelper::getCheckBox($fields['hide_empty_groups'])) -]); - -// Problem display. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['ext_ack']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['ext_ack'])) -]); - -// Show timeline. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_timeline']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_timeline'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/classes/widgets/views/widget.slareport.form.view.php b/ui/include/classes/widgets/views/widget.slareport.form.view.php deleted file mode 100644 index 9a470ac3cfe..00000000000 --- a/ui/include/classes/widgets/views/widget.slareport.form.view.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * SLA report widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = [$this->readJsFile('../../../include/classes/widgets/views/js/widget.slareport.form.view.js.php')]; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// SLA. -$field_slaid = CWidgetHelper::getSla($fields['slaid'], $data['captions']['ms']['slas']['slaid'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['slaid']), - new CFormField($field_slaid) -]); -$scripts[] = $field_slaid->getPostJS(); - -// Service. -$field_serviceid = CWidgetHelper::getService($fields['serviceid'], $data['captions']['ms']['services']['serviceid'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['serviceid']), - new CFormField($field_serviceid) -]); -$scripts[] = $field_serviceid->getPostJS(); - -// Show periods. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_periods']), - new CFormField(CWidgetHelper::getIntegerBox($fields['show_periods'])) -]); - -// From. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['date_from']), - new CFormField( - CWidgetHelper::getDatePicker($fields['date_from']) - ->setDateFormat(ZBX_DATE) - ->setPlaceholder(_('YYYY-MM-DD')) - ) -]); - -// To. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['date_to']), - new CFormField( - CWidgetHelper::getDatePicker($fields['date_to']) - ->setDateFormat(ZBX_DATE) - ->setPlaceholder(_('YYYY-MM-DD')) - ) -]); - -$form->addItem($form_grid); - -$scripts[] = ' - widget_slareport_form.init('.json_encode([ - 'serviceid_field_id' => $fields['serviceid']->getName(), - 'serviceid_multiple' => $fields['serviceid']->isMultiple() - ]).'); -'; - -return [ - 'form' => $form, - 'scripts' => $scripts -]; diff --git a/ui/include/classes/widgets/views/widget.svggraph.form.view.php b/ui/include/classes/widgets/views/widget.svggraph.form.view.php deleted file mode 100644 index 4c42861e105..00000000000 --- a/ui/include/classes/widgets/views/widget.svggraph.form.view.php +++ /dev/null @@ -1,328 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * SVG graph widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = [$this->readJsFile('../../../include/classes/widgets/views/js/widget.svggraph.form.view.js.php')]; -$jq_templates = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -$graph_preview = (new CDiv()) - ->addClass(ZBX_STYLE_SVG_GRAPH_PREVIEW) - ->addItem((new CDiv())->setId('svg-graph-preview')); - -$form_tabs = (new CTabView()) - ->addTab('data_set', _('Data set'), getDatasetTab($fields, $jq_templates, $form->getName()), - TAB_INDICATOR_GRAPH_DATASET - ) - ->addTab('displaying_options', _('Displaying options'), getDisplayOptionsTab($fields), - TAB_INDICATOR_GRAPH_DISPLAY_OPTIONS - ) - ->addTab('time_period', _('Time period'), getTimePeriodTab($fields), TAB_INDICATOR_GRAPH_TIME) - ->addTab('axes', _('Axes'), getAxesTab($fields), TAB_INDICATOR_GRAPH_AXES) - ->addTab('legend_tab', _('Legend'), getLegendTab($fields, $scripts), TAB_INDICATOR_GRAPH_LEGEND) - ->addTab('problems', _('Problems'), getProblemsTab($fields, $scripts, $jq_templates, $form->getName()), - TAB_INDICATOR_GRAPH_PROBLEMS - ) - ->addTab('overrides', _('Overrides'), getOverridesTab($fields, $scripts, $jq_templates, $form->getName()), - TAB_INDICATOR_GRAPH_OVERRIDES - ) - ->addClass('graph-widget-config-tabs') - ->setSelected(0); -$scripts[] = $form_tabs->makeJavascript(); - -$form - ->addItem($form_grid) - ->addItem($graph_preview) - ->addItem($form_tabs); - -$scripts[] = ' - widget_svggraph_form.init('.json_encode([ - 'form_id' => $form->getId(), - 'form_tabs_id' => $form_tabs->getId(), - 'color_palette' => CWidgetFieldGraphDataSet::DEFAULT_COLOR_PALETTE - ]).'); -'; - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; - -function getGraphDataSetItemRow(): string { - return (new CRow([ - (new CCol( - (new CDiv())->addClass(ZBX_STYLE_DRAG_ICON) - )) - ->addClass('table-col-handle') - ->addClass(ZBX_STYLE_TD_DRAG_ICON), - (new CCol( - (new CColor('ds[#{dsNum}][color][]', '#{color}', 'items_#{dsNum}_#{rowNum}_color')) - ->appendColorPickerJs(false) - ))->addClass('table-col-color'), - (new CCol(new CSpan('#{rowNum}:')))->addClass('table-col-no'), - (new CCol( - (new CLink('#{name}')) - ->setId('items_#{dsNum}_#{rowNum}_name') - ->addClass('js-click-expend') - ))->addClass('table-col-name'), - (new CCol([ - (new CButton('button', _('Remove'))) - ->addClass(ZBX_STYLE_BTN_LINK) - ->addClass('element-table-remove'), - (new CVar('ds[#{dsNum}][itemids][]', '#{itemid}', 'items_#{dsNum}_#{rowNum}_input')) - ])) - ->addClass('table-col-action') - ->addClass(ZBX_STYLE_NOWRAP) - ])) - ->addClass('sortable') - ->addClass('single-item-table-row') - ->toString(); -} - -function getDatasetTab(array $fields, array &$jq_templates, string $form_name): CFormGrid { - $jq_templates['dataset-single-item-tmpl'] = CWidgetHelper::getGraphDataSetTemplate($fields['ds'], $form_name, - CWidgetHelper::DATASET_TYPE_SINGLE_ITEM - ); - $jq_templates['dataset-pattern-item-tmpl'] = CWidgetHelper::getGraphDataSetTemplate($fields['ds'], $form_name, - CWidgetHelper::DATASET_TYPE_PATTERN_ITEM - ); - $jq_templates['dataset-item-row-tmpl'] = getGraphDataSetItemRow(); - - return (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['ds']), - (new CFormField(CWidgetHelper::getGraphDataSet($fields['ds'], $form_name))) - ->addClass(ZBX_STYLE_LIST_VERTICAL_ACCORDION), - (new CFormField(CWidgetHelper::getGraphDataSetFooter()))->addClass(ZBX_STYLE_LIST_ACCORDION_FOOT) - ]); -} - -function getDisplayOptionsTab(array $fields): CDiv { - return (new CDiv()) - ->addClass(ZBX_STYLE_GRID_COLUMNS) - ->addClass(ZBX_STYLE_GRID_COLUMNS_2) - ->addItem( - (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['source']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['source'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['simple_triggers']), - new CFormField(CWidgetHelper::getCheckBox($fields['simple_triggers'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['working_time']), - new CFormField(CWidgetHelper::getCheckBox($fields['working_time'])) - ]) - ) - ->addItem( - (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['percentile_left']), - new CFormField([ - CWidgetHelper::getCheckBox($fields['percentile_left']), - CWidgetHelper::getTextBox($fields['percentile_left_value']) - ]) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['percentile_right']), - new CFormField([ - CWidgetHelper::getCheckBox($fields['percentile_right']), - CWidgetHelper::getTextBox($fields['percentile_right_value']) - ]) - ]) - ); -} - -function getTimePeriodTab(array $fields): CFormGrid { - return (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['graph_time']), - new CFormField(CWidgetHelper::getCheckBox($fields['graph_time'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['time_from']), - new CFormField( - CWidgetHelper::getDatePicker($fields['time_from']) - ->setDateFormat(ZBX_FULL_DATE_TIME) - ->setPlaceholder(_('YYYY-MM-DD hh:mm:ss')) - ) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['time_to']), - new CFormField( - CWidgetHelper::getDatePicker($fields['time_to']) - ->setDateFormat(ZBX_FULL_DATE_TIME) - ->setPlaceholder(_('YYYY-MM-DD hh:mm:ss')) - ) - ]); -} - -function getAxesTab(array $fields): CDiv { - return (new CDiv()) - ->addClass(ZBX_STYLE_GRID_COLUMNS) - ->addClass(ZBX_STYLE_GRID_COLUMNS_3) - ->addItem( - (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['lefty']), - new CFormField(CWidgetHelper::getCheckBox($fields['lefty'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['lefty_min']), - new CFormField(CWidgetHelper::getNumericBox($fields['lefty_min'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['lefty_max']), - new CFormField(CWidgetHelper::getNumericBox($fields['lefty_max'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['lefty_units']), - new CFormField([ - CWidgetHelper::getSelect($fields['lefty_units'])->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), - CWidgetHelper::getTextBox($fields['lefty_static_units']) - ]) - ]) - ) - ->addItem( - (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['righty']), - new CFormField(CWidgetHelper::getCheckBox($fields['righty'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['righty_min']), - new CFormField(CWidgetHelper::getNumericBox($fields['righty_min'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['righty_max']), - new CFormField(CWidgetHelper::getNumericBox($fields['righty_max'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['righty_units']), - new CFormField([ - CWidgetHelper::getSelect($fields['righty_units'])->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), - CWidgetHelper::getTextBox($fields['righty_static_units']) - ]) - ]) - ) - ->addItem( - (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['axisx']), - new CFormField(CWidgetHelper::getCheckBox($fields['axisx'])) - ]) - ); -} - -function getLegendTab(array $fields, array &$scripts): CDiv { - $field_legend_lines = CWidgetHelper::getRangeControl($fields['legend_lines']); - $field_legend_columns = CWidgetHelper::getRangeControl($fields['legend_columns']); - - $scripts[] = $field_legend_lines->getPostJS(); - $scripts[] = $field_legend_columns->getPostJS(); - - return (new CDiv()) - ->addClass(ZBX_STYLE_GRID_COLUMNS) - ->addClass(ZBX_STYLE_GRID_COLUMNS_2) - ->addItem( - (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['legend']), - new CFormField(CWidgetHelper::getCheckBox($fields['legend'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['legend_statistic']), - new CFormField(CWidgetHelper::getCheckBox($fields['legend_statistic'])) - ]) - ) - ->addItem( - (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['legend_lines']), - new CFormField($field_legend_lines) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['legend_columns']), - new CFormField($field_legend_columns) - ]) - ); -} - -function getProblemsTab(array $fields, array &$scripts, array &$jq_templates, string $form_name): CFormGrid { - $scripts[] = $fields['problemhosts']->getJavascript(); - $scripts[] = $fields['tags']->getJavascript(); - $jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - - return (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['show_problems']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_problems'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['graph_item_problems']), - new CFormField(CWidgetHelper::getCheckBox($fields['graph_item_problems'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['problemhosts']), - new CFormField(CWidgetHelper::getHostPatternSelect($fields['problemhosts'], $form_name)) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['severities']), - new CFormField(CWidgetHelper::getSeverities($fields['severities'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['problem_name']), - new CFormField(CWidgetHelper::getTextBox($fields['problem_name'])) - ]) - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem(new CFormField(CWidgetHelper::getTags($fields['tags']))); -} - -function getOverridesTab(array $fields, array &$scripts, array &$jq_templates, string $form_name): CFormGrid { - $scripts[] = CWidgetHelper::getGraphOverrideJavascript($fields['or']); - $jq_templates['overrides-row'] = CWidgetHelper::getGraphOverrideTemplate($fields['or'], $form_name); - - return (new CFormGrid()) - ->addItem([ - CWidgetHelper::getLabel($fields['or']), - new CFormField(CWidgetHelper::getGraphOverride($fields['or'], $form_name)) - ]); -} diff --git a/ui/include/classes/widgets/views/widget.tophosts.form.view.php b/ui/include/classes/widgets/views/widget.tophosts.form.view.php deleted file mode 100644 index b740f4f2ea5..00000000000 --- a/ui/include/classes/widgets/views/widget.tophosts.form.view.php +++ /dev/null @@ -1,118 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Data overview widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = [$this->readJsFile('../../../include/classes/widgets/views/js/widget.tophosts.form.view.js.php')]; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Hosts. -$field_hostids = CWidgetHelper::getHost($fields['hostids'], $data['captions']['ms']['hosts']['hostids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['hostids']), - new CFormField($field_hostids) -]); -$scripts[] = $field_hostids->getPostJS(); - -// Host tags. -$form_grid - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem( - new CFormField(CWidgetHelper::getTags($fields['tags'])) - ); -$scripts[] = $fields['tags']->getJavascript(); -$jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - -// Columns. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['columns']), - (new CFormField( - CWidgetHelper::getWidgetColumns($fields['columns']) - ))->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR) -]); - -// Order. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['order']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['order'])) -]); - -// Order column. -$column = CWidgetHelper::getSelect($fields['column']); -if (!$fields['column']->getValues()) { - $column = (new CDiv(_('Add item column')))->addClass( - ($fields['column']->getFlags() & CWidgetField::FLAG_DISABLED) - ? ZBX_STYLE_DISABLED - : null - ); -} -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['column']), - new CFormField($column) -]); - -// Hosts count. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['count']), - new CFormField(CWidgetHelper::getIntegerBox($fields['count'])) -]); - -$form->addItem($form_grid); - -$scripts[] = ' - widget_tophosts_form.init('.json_encode([ - 'form_id' => $form->getId() - ]).'); -'; - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/classes/widgets/views/widget.trigover.form.view.php b/ui/include/classes/widgets/views/widget.trigover.form.view.php deleted file mode 100644 index af3327ed14e..00000000000 --- a/ui/include/classes/widgets/views/widget.trigover.form.view.php +++ /dev/null @@ -1,96 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Trigger overview widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Show. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['show'])) -]); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Hosts. -$field_hostids = CWidgetHelper::getHost($fields['hostids'], $data['captions']['ms']['hosts']['hostids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['hostids']), - new CFormField($field_hostids) -]); -$scripts[] = $field_hostids->getPostJS(); - -// Tags. -$form_grid - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem( - new CFormField(CWidgetHelper::getTags($fields['tags'])) - ); -$scripts[] = $fields['tags']->getJavascript(); -$jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - -// Show suppressed problems. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_suppressed']), - new CFormField(CWidgetHelper::getCheckBox($fields['show_suppressed'])) -]); - -// Hosts location. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['style']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['style'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/classes/widgets/views/widget.url.form.view.php b/ui/include/classes/widgets/views/widget.url.form.view.php deleted file mode 100644 index b055cbbd4a0..00000000000 --- a/ui/include/classes/widgets/views/widget.url.form.view.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * URL widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// URL. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['url']), - new CFormField(CWidgetHelper::getUrlBox($fields['url'])) -]); - -// Dynamic item. -if ($data['templateid'] === null) { - $form_grid->addItem([ - CWidgetHelper::getLabel($fields['dynamic']), - new CFormField(CWidgetHelper::getCheckBox($fields['dynamic'])) - ]); -} - -$form->addItem($form_grid); - -return [ - 'form' => $form -]; diff --git a/ui/include/classes/widgets/views/widget.web.form.view.php b/ui/include/classes/widgets/views/widget.web.form.view.php deleted file mode 100644 index 40b5364f77d..00000000000 --- a/ui/include/classes/widgets/views/widget.web.form.view.php +++ /dev/null @@ -1,94 +0,0 @@ -<?php declare(strict_types = 0); -/* -** Zabbix -** Copyright (C) 2001-2022 Zabbix SIA -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -**/ - - -/** - * Web widget form view. - * - * @var CView $this - * @var array $data - */ - -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$scripts = []; - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Host groups. -$field_groupids = CWidgetHelper::getGroup($fields['groupids'], $data['captions']['ms']['groups']['groupids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['groupids']), - new CFormField($field_groupids) -]); -$scripts[] = $field_groupids->getPostJS(); - -// Exclude host groups. -$field_exclude_groupids = CWidgetHelper::getGroup($fields['exclude_groupids'], - $data['captions']['ms']['groups']['exclude_groupids'], $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['exclude_groupids']), - new CFormField($field_exclude_groupids) -]); -$scripts[] = $field_exclude_groupids->getPostJS(); - -// Hosts. -$field_hostids = CWidgetHelper::getHost($fields['hostids'], $data['captions']['ms']['hosts']['hostids'], - $form->getName() -); -$form_grid->addItem([ - CWidgetHelper::getMultiselectLabel($fields['hostids']), - new CFormField($field_hostids) -]); -$scripts[] = $field_hostids->getPostJS(); - -// Tags. -$form_grid - ->addItem([ - CWidgetHelper::getLabel($fields['evaltype']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['evaltype'])) - ]) - ->addItem( - new CFormField(CWidgetHelper::getTags($fields['tags'])) - ); -$scripts[] = $fields['tags']->getJavascript(); -$jq_templates['tag-row-tmpl'] = CWidgetHelper::getTagsTemplate($fields['tags']); - -// Show hosts in maintenance. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['maintenance']), - new CFormField(CWidgetHelper::getCheckBox($fields['maintenance'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form, - 'scripts' => $scripts, - 'jq_templates' => $jq_templates -]; diff --git a/ui/include/defines.inc.php b/ui/include/defines.inc.php index 36200260754..f42c123840b 100644 --- a/ui/include/defines.inc.php +++ b/ui/include/defines.inc.php @@ -18,11 +18,11 @@ ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -define('ZABBIX_VERSION', '6.4.0beta3'); +define('ZABBIX_VERSION', '6.4.0beta2'); define('ZABBIX_API_VERSION', '6.4.0'); define('ZABBIX_EXPORT_VERSION', '6.4'); -define('ZABBIX_DB_VERSION', 6030061); +define('ZABBIX_DB_VERSION', 6030063); define('DB_VERSION_SUPPORTED', 0); define('DB_VERSION_LOWER_THAN_MINIMUM', 1); @@ -134,9 +134,6 @@ define('EXTACK_OPTION_ALL', 0); define('EXTACK_OPTION_UNACK', 1); define('EXTACK_OPTION_BOTH', 2); -define('WIDGET_PROBLEMS_BY_SV_SHOW_GROUPS', 0); -define('WIDGET_PROBLEMS_BY_SV_SHOW_TOTALS', 1); - define('TRIGGERS_OPTION_RECENT_PROBLEM', 1); define('TRIGGERS_OPTION_ALL', 2); define('TRIGGERS_OPTION_IN_PROBLEM', 3); @@ -860,7 +857,7 @@ define('SCREEN_SORT_TRIGGERS_NAME_DESC', 16); define('SCREEN_MODE_PREVIEW', 0); define('SCREEN_MODE_EDIT', 1); -define('SCREEN_MODE_SLIDESHOW', 2); +define('SCREEN_MODE_SLIDESHOW', 2); define('SCREEN_MODE_JS', 3); define('SCREEN_REFRESH_RESPONSIVENESS', 10); @@ -1177,7 +1174,8 @@ define('SVG_GRAPH_PERCENTILE_LEFT_ON', 1); define('SVG_GRAPH_PERCENTILE_RIGHT_OFF', 0); define('SVG_GRAPH_PERCENTILE_RIGHT_ON', 1); -define('SVG_GRAPH_CUSTOM_TIME', 1); +define('SVG_GRAPH_CUSTOM_TIME_OFF', 0); +define('SVG_GRAPH_CUSTOM_TIME_ON', 1); define('SVG_GRAPH_LEGEND_OFF', 0); define('SVG_GRAPH_LEGEND_ON', 1); @@ -1191,11 +1189,13 @@ define('SVG_GRAPH_LEGEND_LINES_MAX', 10); define('SVG_GRAPH_LEGEND_COLUMNS_MIN', 1); define('SVG_GRAPH_LEGEND_COLUMNS_MAX', 4); -define('SVG_GRAPH_PROBLEMS_SHOW', 1); +define('SVG_GRAPH_PROBLEMS_OFF', 0); +define('SVG_GRAPH_PROBLEMS_ON', 1); define('SVG_GRAPH_SELECTED_ITEM_PROBLEMS', 1); -define('SVG_GRAPH_AXIS_SHOW', 1); +define('SVG_GRAPH_AXIS_OFF', 0); +define('SVG_GRAPH_AXIS_ON', 1); define('SVG_GRAPH_AXIS_UNITS_AUTO', 0); define('SVG_GRAPH_AXIS_UNITS_STATIC', 1); @@ -1292,6 +1292,9 @@ define('ZBX_FUNCTION_TYPE_OPERATOR', 5); define('ZBX_FUNCTION_TYPE_PREDICTION', 6); define('ZBX_FUNCTION_TYPE_STRING', 7); +define('ZBX_TIMELINE_OFF', 0); +define('ZBX_TIMELINE_ON', 1); + /** * @deprecated use either a literal space " " or a non-breakable space " " instead */ @@ -1609,94 +1612,28 @@ define('ZBX_ACTIONS_POPUP_MAX_WIDTH', 800); define('ZBX_HINTBOX_CONTENT_LIMIT', 8192); -// dashboard widgets -define('WIDGET_ACTION_LOG', 'actionlog'); +// Dashboard widget types supported in templates (used only in import converters). define('WIDGET_CLOCK', 'clock'); -define('WIDGET_DISCOVERY', 'discovery'); -define('WIDGET_FAV_GRAPHS', 'favgraphs'); -define('WIDGET_FAV_MAPS', 'favmaps'); -define('WIDGET_GEOMAP', 'geomap'); define('WIDGET_GRAPH', 'graph'); define('WIDGET_GRAPH_PROTOTYPE', 'graphprototype'); -define('WIDGET_HOST_AVAIL', 'hostavail'); -define('WIDGET_MAP', 'map'); -define('WIDGET_NAV_TREE', 'navtree'); +define('WIDGET_ITEM', 'item'); define('WIDGET_PLAIN_TEXT', 'plaintext'); -define('WIDGET_PROBLEM_HOSTS', 'problemhosts'); -define('WIDGET_PROBLEMS', 'problems'); -define('WIDGET_PROBLEMS_BY_SV', 'problemsbysv'); -define('WIDGET_SLA_REPORT', 'slareport'); -define('WIDGET_SVG_GRAPH', 'svggraph'); -define('WIDGET_SYSTEM_INFO', 'systeminfo'); -define('WIDGET_TOP_HOSTS', 'tophosts'); -define('WIDGET_TRIG_OVER', 'trigover'); define('WIDGET_URL', 'url'); -define('WIDGET_WEB', 'web'); -define('WIDGET_ITEM', 'item'); -// Deprecated widgets -define('WIDGET_DATA_OVER', 'dataover'); - -// Clock widget type -define('WIDGET_CLOCK_TYPE_ANALOG', 0); -define('WIDGET_CLOCK_TYPE_DIGITAL', 1); - -// Clock time zone format -define('WIDGET_CLOCK_TIMEZONE_SHORT', 0); -define('WIDGET_CLOCK_TIMEZONE_FULL', 1); - -// Clock widget time format -define('WIDGET_CLOCK_HOUR_TWENTY_FOUR', 0); -define('WIDGET_CLOCK_HOUR_TWELVE', 1); - -// Item widget object positions. -define('WIDGET_ITEM_POS_LEFT', 0); -define('WIDGET_ITEM_POS_CENTER', 1); -define('WIDGET_ITEM_POS_RIGHT', 2); - -define('WIDGET_ITEM_POS_TOP', 0); -define('WIDGET_ITEM_POS_MIDDLE', 1); -define('WIDGET_ITEM_POS_BOTTOM', 2); - -define('WIDGET_ITEM_POS_BEFORE', 0); -define('WIDGET_ITEM_POS_ABOVE', 1); -define('WIDGET_ITEM_POS_AFTER', 2); -define('WIDGET_ITEM_POS_BELOW', 3); - -// sysmap widget source types -define('WIDGET_SYSMAP_SOURCETYPE_MAP', 1); -define('WIDGET_SYSMAP_SOURCETYPE_FILTER', 2); - -// widget select resource field types -define('WIDGET_FIELD_SELECT_RES_SYSMAP', 1); - -// max depth of navigation tree -define('WIDGET_NAVIGATION_TREE_MAX_DEPTH', 10); - -// event details widgets -define('WIDGET_HAT_TRIGGERDETAILS', 'hat_triggerdetails'); -define('WIDGET_HAT_EVENTDETAILS', 'hat_eventdetails'); -define('WIDGET_HAT_EVENTACTIONS', 'hat_eventactions'); -define('WIDGET_HAT_EVENTLIST', 'hat_eventlist'); -// search widget -define('WIDGET_SEARCH_HOSTS', 'search_hosts'); -define('WIDGET_SEARCH_HOSTGROUP', 'search_hostgroup'); -define('WIDGET_SEARCH_TEMPLATES', 'search_templates'); -define('WIDGET_SEARCH_TEMPLATEGROUP', 'search_templategroup'); - -// dashboard widget dynamic state -define('WIDGET_SIMPLE_ITEM', 0); -define('WIDGET_DYNAMIC_ITEM', 1); - -// clock widget blocks -define('WIDGET_CLOCK_SHOW_DATE', 1); -define('WIDGET_CLOCK_SHOW_TIME', 2); -define('WIDGET_CLOCK_SHOW_TIMEZONE', 3); - -// item widget blocks -define('WIDGET_ITEM_SHOW_DESCRIPTION', 1); -define('WIDGET_ITEM_SHOW_VALUE', 2); -define('WIDGET_ITEM_SHOW_TIME', 3); -define('WIDGET_ITEM_SHOW_CHANGE_INDICATOR', 4); + +// Inaccessible widget type. +define('ZBX_WIDGET_INACCESSIBLE', 'inaccessible'); + +// event details sections +define('SECTION_HAT_TRIGGERDETAILS', 'hat_triggerdetails'); +define('SECTION_HAT_EVENTDETAILS', 'hat_eventdetails'); +define('SECTION_HAT_EVENTACTIONS', 'hat_eventactions'); +define('SECTION_HAT_EVENTLIST', 'hat_eventlist'); + +// search sections +define('SECTION_SEARCH_HOSTS', 'search_hosts'); +define('SECTION_SEARCH_HOSTGROUP', 'search_hostgroup'); +define('SECTION_SEARCH_TEMPLATES', 'search_templates'); +define('SECTION_SEARCH_TEMPLATEGROUP', 'search_templategroup'); // widget defaults define('ZBX_WIDGET_ROWS', 20); @@ -1723,9 +1660,6 @@ define('ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH_PROTOTYPE', 3); define('ZBX_WIDGET_VIEW_MODE_NORMAL', 0); define('ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER', 1); -// top hosts widget -define('ZBX_WIDGET_TOP_HOSTS_DEFAULT_FILL', '#97AAB3'); - // validation define('DB_ID', "({}>=0&&bccomp({},\"9223372036854775807\")<=0)&&"); define('NOT_EMPTY', "({}!='')&&"); @@ -1921,7 +1855,6 @@ define('ZBX_STYLE_DASHBOARD_NEXT_PAGE', 'dashboard-next-page'); define('ZBX_STYLE_DASHBOARD_TOGGLE_SLIDESHOW', 'dashboard-toggle-slideshow'); define('ZBX_STYLE_DASHBOARD_WIDGET', 'dashboard-widget'); define('ZBX_STYLE_DASHBOARD_WIDGET_FORM', 'dashboard-widget-form'); -define('ZBX_STYLE_DASHBOARD_WIDGET_FLUID', 'dashboard-widget-fluid'); define('ZBX_STYLE_DASHBOARD_WIDGET_HEAD', 'dashboard-widget-head'); define('ZBX_STYLE_DASHBOARD_WIDGET_FOOT', 'dashboard-widget-foot'); define('ZBX_STYLE_DASHBOARD_EDIT', 'dashboard-edit'); @@ -2064,7 +1997,6 @@ define('ZBX_STYLE_OVERLAY_DESCR_URL', 'overlay-descr-url'); define('ZBX_STYLE_OVERFLOW_ELLIPSIS', 'overflow-ellipsis'); define('ZBX_STYLE_PAGING_BTN_CONTAINER', 'paging-btn-container'); define('ZBX_STYLE_PAGING_SELECTED', 'paging-selected'); -define('ZBX_STYLE_PAGE_TITLE', 'page-title-general'); define('ZBX_STYLE_PAGE_TITLE_SUBMENU', 'page-title-submenu'); define('ZBX_STYLE_RED', 'red'); define('ZBX_STYLE_RED_BG', 'red-bg'); diff --git a/ui/include/func.inc.php b/ui/include/func.inc.php index d34d9b36b0a..55600959ffc 100644 --- a/ui/include/func.inc.php +++ b/ui/include/func.inc.php @@ -1625,7 +1625,7 @@ function access_deny($mode = ACCESS_DENY_OBJECT) { show_error_message(_('No permissions to referred object or it does not exist!')); require_once dirname(__FILE__).'/page_header.php'; - (new CWidget())->show(); + (new CHtmlPage())->show(); require_once dirname(__FILE__).'/page_footer.php'; } // deny access to a page @@ -1806,8 +1806,20 @@ function makeMessageBox(string $class, array $messages, string $title = null, bo function filter_messages(): array { if (!CSettingsHelper::getGlobal(CSettingsHelper::SHOW_TECHNICAL_ERRORS) && CWebUser::getType() != USER_TYPE_SUPER_ADMIN && !CWebUser::getDebugMode()) { + + $type = CMessageHelper::getType(); + $title = CMessageHelper::getTitle(); $messages = CMessageHelper::getMessages(); - CMessageHelper::clear(false); + CMessageHelper::clear(); + + if ($title !== null) { + if ($type === CMessageHelper::MESSAGE_TYPE_SUCCESS) { + CMessageHelper::setSuccessTitle($title); + } + else { + CMessageHelper::setErrorTitle($title); + } + } $generic_exists = false; foreach ($messages as $message) { diff --git a/ui/include/html.inc.php b/ui/include/html.inc.php index 9c4b6e549bf..f808e6a092f 100644 --- a/ui/include/html.inc.php +++ b/ui/include/html.inc.php @@ -140,7 +140,7 @@ function BR() { function get_icon($type, $params = []) { switch ($type) { - case 'favourite': + case 'favorite': if (CFavorite::exists($params['fav'], $params['elid'], $params['elname'])) { $icon = (new CRedirectButton(SPACE, null)) ->addClass(ZBX_STYLE_BTN_REMOVE_FAV) @@ -806,11 +806,11 @@ function makePageFooter($with_version = true) { /** * Get drop-down submenu item list for the User settings section. * - * @return array|null Menu definition for CWidget::setTitleSubmenu. + * @return array Menu definition for CHtmlPage::setTitleSubmenu. */ -function getUserSettingsSubmenu(): ?array { +function getUserSettingsSubmenu(): array { if (!CWebUser::checkAccess(CRoleHelper::ACTIONS_MANAGE_API_TOKENS)) { - return null; + return []; } $profile_url = (new CUrl('zabbix.php')) @@ -834,7 +834,7 @@ function getUserSettingsSubmenu(): ?array { /** * Get drop-down submenu item list for the Administration->General section. * - * @return array Menu definition for CWidget::setTitleSubmenu. + * @return array Menu definition for CHtmlPage::setTitleSubmenu. */ function getAdministrationGeneralSubmenu() { $gui_url = (new CUrl('zabbix.php')) diff --git a/ui/include/page_header.php b/ui/include/page_header.php index 693c40e50f3..79c3fecef32 100644 --- a/ui/include/page_header.php +++ b/ui/include/page_header.php @@ -114,28 +114,27 @@ if ($page['type'] == PAGE_TYPE_HTML) { global $ZBX_SERVER_NAME; // page title - $pageTitle = ''; + $page_title = ''; if (isset($ZBX_SERVER_NAME) && $ZBX_SERVER_NAME !== '') { - $pageTitle = $ZBX_SERVER_NAME.NAME_DELIMITER; + $page_title = $ZBX_SERVER_NAME.NAME_DELIMITER; } - $pageTitle .= isset($page['title']) ? $page['title'] : _('Zabbix'); + $page_title .= isset($page['title']) ? $page['title'] : _('Zabbix'); if (defined('ZBX_PAGE_DO_JS_REFRESH') && CWebUser::getRefresh() != 0) { - $pageTitle .= ' ['._s('refreshed every %1$s sec.', CWebUser::getRefresh()).']'; + $page_title .= ' ['._s('refreshed every %1$s sec.', CWebUser::getRefresh()).']'; } - $pageHeader = new CPageHeader($pageTitle, CWebUser::getLang()); + $page_header = new CHtmlPageHeader($page_title, CWebUser::getLang()); $is_standard_page = (!defined('ZBX_PAGE_NO_MENU') || $page['web_layout_mode'] == ZBX_LAYOUT_KIOSKMODE); - $theme = ZBX_DEFAULT_THEME; if (!ZBX_PAGE_NO_THEME) { global $DB; if (!empty($DB['DB'])) { - $theme = getUserTheme(CWebUser::$data); - - $pageHeader->addStyle(getTriggerSeverityCss()); - $pageHeader->addStyle(getTriggerStatusCss()); + $page_header + ->setTheme(getUserTheme(CWebUser::$data)) + ->addStyle(getTriggerSeverityCss()) + ->addStyle(getTriggerStatusCss()); // perform Zabbix server check only for standard pages if ($is_standard_page && CSettingsHelper::get(CSettingsHelper::SERVER_CHECK_INTERVAL)) { @@ -143,39 +142,65 @@ if ($page['type'] == PAGE_TYPE_HTML) { } } } - $pageHeader->addCssFile('assets/styles/'.CHtml::encode($theme).'.css'); + + $page_header->addCssFile('assets/styles/'.$page_header->getTheme().'.css'); + + foreach (APP::ModuleManager()->getAssets() as $module_id => $assets) { + $module = APP::ModuleManager()->getModule($module_id); + $relative_path = $module->getRelativePath().'/assets/css'; + + foreach ($assets['css'] as $css_file) { + $page_header->addCssFile((new CUrl($relative_path.'/'.$css_file))->getUrl()); + } + } if ($page['file'] == 'sysmap.php') { - $pageHeader->addCssFile('imgstore.php?css=1&output=css'); + $page_header->addCssFile('imgstore.php?css=1&output=css'); } - $pageHeader - ->addJsFile((new CUrl('js/browsers.js'))->getUrl()) - ->addJsBeforeScripts( - 'var PHP_TZ_OFFSET = '.date('Z').','. - 'PHP_ZBX_FULL_DATE_TIME = "'.ZBX_FULL_DATE_TIME.'";' - ); + $page_header + ->addJavaScript(' + const PHP_TZ_OFFSET = '.date('Z').'; + const PHP_ZBX_FULL_DATE_TIME = "'.ZBX_FULL_DATE_TIME.'"; + ') + ->addJsFile((new CUrl('js/browsers.js'))->getUrl()); // Show GUI messages in pages with menus and in fullscreen mode. if (!defined('ZBX_PAGE_NO_JSLOADER')) { - $pageHeader->addJsFile((new CUrl('jsLoader.php')) - ->setArgument('ver', ZABBIX_VERSION) - ->setArgument('lang', CWebUser::$data['lang']) - ->setArgument('showGuiMessaging', ($is_standard_page && !CWebUser::isGuest()) ? 1 : null) - ->getUrl() - ); - - if (array_key_exists('scripts', $page) && $page['scripts']) { - $pageHeader->addJsFile((new CUrl('jsLoader.php')) + $page_header->addJsFile( + (new CUrl('jsLoader.php')) ->setArgument('ver', ZABBIX_VERSION) ->setArgument('lang', CWebUser::$data['lang']) - ->setArgument('files', $page['scripts']) + ->setArgument('showGuiMessaging', ($is_standard_page && !CWebUser::isGuest()) ? 1 : null) ->getUrl() + ); + + if (array_key_exists('scripts', $page) && $page['scripts']) { + $page_header->addJsFile( + (new CUrl('jsLoader.php')) + ->setArgument('ver', ZABBIX_VERSION) + ->setArgument('lang', CWebUser::$data['lang']) + ->setArgument('files', $page['scripts']) + ->getUrl() ); } + + foreach (APP::ModuleManager()->getAssets() as $module_id => $assets) { + $module = APP::ModuleManager()->getModule($module_id); + $relative_path = $module->getRelativePath().'/assets/js'; + $translation_strings = $module->getTranslationStrings(); + + foreach ($assets['js'] as $js_file) { + $page_header->addJsFile((new CUrl($relative_path.'/'.$js_file))->getUrl()); + + if (array_key_exists($js_file, $translation_strings)) { + $page_header->addJsTranslationStrings($translation_strings[$js_file]); + } + } + } } - $pageHeader->display(); + $page_header->show(); echo '<body>'; } diff --git a/ui/include/validate.inc.php b/ui/include/validate.inc.php index af7fa11b066..f777d2aab02 100644 --- a/ui/include/validate.inc.php +++ b/ui/include/validate.inc.php @@ -378,7 +378,7 @@ function invalid_url($msg = null) { unset_all(); show_error_message($msg); - (new CWidget())->show(); + (new CHtmlPage())->show(); require_once dirname(__FILE__).'/page_footer.php'; } diff --git a/ui/include/views/administration.auditacts.list.php b/ui/include/views/administration.auditacts.list.php index 241b33fa074..16527340b71 100644 --- a/ui/include/views/administration.auditacts.list.php +++ b/ui/include/views/administration.auditacts.list.php @@ -23,7 +23,7 @@ * @var CView $this */ -$auditWidget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Action log')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ADMINISTRATION_AUDITACTS_LIST)); @@ -47,7 +47,7 @@ $filterColumn->addRow(new CLabel(_('Recipients'), 'filter_userids__ms'), [ ]))->setWidth(ZBX_TEXTAREA_FILTER_STANDARD_WIDTH) ]); -$auditWidget->addItem( +$html_page->addItem( (new CFilter()) ->setResetUrl(new CUrl('auditacts.php')) ->setProfile($data['timeline']['profileIdx']) @@ -141,7 +141,6 @@ $objData = [ zbx_add_post_js('timeControl.addObject("events", '.zbx_jsvalue($data['timeline']).', '.zbx_jsvalue($objData).');'); zbx_add_post_js('timeControl.processObjects();'); -// append form to widget -$auditWidget->addItem($auditForm); - -$auditWidget->show(); +$html_page + ->addItem($auditForm) + ->show(); diff --git a/ui/include/views/configuration.action.edit.php b/ui/include/views/configuration.action.edit.php index a4f3c51bcf0..25ebb5a2575 100644 --- a/ui/include/views/configuration.action.edit.php +++ b/ui/include/views/configuration.action.edit.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/configuration.action.edit.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Actions')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ALERTS_ACTION_EDIT)); @@ -37,7 +37,7 @@ $actionForm = (new CForm()) ->setArgument('eventsource', $data['eventsource']) ->getUrl() ) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']); if ($data['actionid']) { @@ -539,7 +539,6 @@ $action_tabs->setFooter([ ]); $actionForm->addItem($action_tabs); -// Append form to widget. -$widget->addItem($actionForm); - -$widget->show(); +$html_page + ->addItem($actionForm) + ->show(); diff --git a/ui/include/views/configuration.action.list.php b/ui/include/views/configuration.action.list.php index cc0fd295d84..c7c229a04d6 100644 --- a/ui/include/views/configuration.action.list.php +++ b/ui/include/views/configuration.action.list.php @@ -59,7 +59,7 @@ foreach ($submenu_source as $value => $label) { $current_url = (new CUrl('actionconf.php'))->setArgument('eventsource', $data['eventsource']); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle($title) ->setTitleSubmenu(['main_section' => ['items' => $submenu]]) ->setDocUrl(CDocHelper::getUrl(CDocHelper::ALERTS_ACTION_LIST)) @@ -180,7 +180,6 @@ $actionForm->addItem([ ], $data['eventsource']) ]); -// append form to widget -$widget->addItem($actionForm); - -$widget->show(); +$html_page + ->addItem($actionForm) + ->show(); diff --git a/ui/include/views/configuration.copy.elements.php b/ui/include/views/configuration.copy.elements.php index 82fd613109d..68110cac228 100644 --- a/ui/include/views/configuration.copy.elements.php +++ b/ui/include/views/configuration.copy.elements.php @@ -24,7 +24,7 @@ * @var array $data */ -$widget = (new CWidget())->setTitle($data['title']); +$html_page = (new CHtmlPage())->setTitle($data['title']); // append host summary to widget header if ($data['hostid'] != 0) { @@ -42,13 +42,13 @@ if ($data['hostid'] != 0) { $host_table_element = ''; } - $widget->setNavigation(getHostNavigation($host_table_element, $data['hostid'])); + $html_page->setNavigation(getHostNavigation($host_table_element, $data['hostid'])); } // create form $form = (new CForm('post', (new CUrl())->getUrl())) ->setName('elements_form') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('action', $data['action']) ->addVar($data['elements_field'], $data['elements']) ->addVar('hostid', $data['hostid']); @@ -81,11 +81,11 @@ $tab_view->setFooter(makeFormFooter( )); $form->addItem($tab_view); -$widget->addItem($form); +$html_page->addItem($form); require_once dirname(__FILE__).'/js/configuration.copy.elements.js.php'; -$widget->show(); +$html_page->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/include/views/configuration.graph.edit.php b/ui/include/views/configuration.graph.edit.php index c10c07c64d8..1d85b47b2d5 100644 --- a/ui/include/views/configuration.graph.edit.php +++ b/ui/include/views/configuration.graph.edit.php @@ -23,16 +23,16 @@ * @var CView $this */ -$widget = new CWidget(); +$html_page = new CHtmlPage(); if ($data['parent_discoveryid'] === null) { - $widget + $html_page ->setTitle(_('Graphs')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_GRAPH_EDIT)) ->setNavigation(getHostNavigation('graphs', $data['hostid'])); } else { - $widget + $html_page ->setTitle(_('Graph prototypes')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_PROTOTYPE_GRAPH_EDIT)) ->setNavigation(getHostNavigation('graphs', $data['hostid'], $data['parent_discoveryid'])); @@ -46,7 +46,7 @@ $url = (new CUrl('graphs.php')) // Create form. $graphForm = (new CForm('post', $url)) ->setName('graphForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']) ->addVar('hostid', $data['hostid']); @@ -533,10 +533,9 @@ require_once dirname(__FILE__).'/js/configuration.graph.edit.js.php'; $graphForm->addItem($graphTab); -// Append form to widget. -$widget->addItem($graphForm); - -$widget->show(); +$html_page + ->addItem($graphForm) + ->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/include/views/configuration.graph.list.php b/ui/include/views/configuration.graph.list.php index d999c4a345b..c30e18a1ded 100644 --- a/ui/include/views/configuration.graph.list.php +++ b/ui/include/views/configuration.graph.list.php @@ -26,7 +26,7 @@ $this->includeJsFile('configuration.graph.list.js.php'); if (!empty($this->data['parent_discoveryid'])) { - $widget = (new CWidget()) + $html_page = (new CHtmlPage()) ->setTitle(_('Graph prototypes')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_GRAPH_PROTOTYPE_LIST @@ -48,7 +48,7 @@ if (!empty($this->data['parent_discoveryid'])) { ->setNavigation(getHostNavigation('graphs', $this->data['hostid'], $this->data['parent_discoveryid'])); } else { - $widget = (new CWidget()) + $html_page = (new CHtmlPage()) ->setTitle(_('Graphs')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_GRAPH_LIST @@ -75,13 +75,13 @@ else { ); if (!empty($this->data['hostid'])) { - $widget->setNavigation(getHostNavigation('graphs', $this->data['hostid'])); + $html_page->setNavigation(getHostNavigation('graphs', $this->data['hostid'])); } // Add filter tab. $hg_ms_params = $data['context'] === 'host' ? ['with_hosts' => true] : ['with_templates' => true]; - $widget->addItem( + $html_page->addItem( (new CFilter()) ->setResetUrl((new CUrl('graphs.php'))->setArgument('context', $data['context'])) ->setProfile($data['profileIdx']) @@ -270,7 +270,6 @@ $graphForm->addItem([ ) ]); -// append form to widget -$widget->addItem($graphForm); - -$widget->show(); +$html_page + ->addItem($graphForm) + ->show(); diff --git a/ui/include/views/configuration.host.discovery.edit.php b/ui/include/views/configuration.host.discovery.edit.php index aa08f03049c..7d7fe2672b7 100644 --- a/ui/include/views/configuration.host.discovery.edit.php +++ b/ui/include/views/configuration.host.discovery.edit.php @@ -24,7 +24,7 @@ * @var array $data */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Discovery rules')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_HOST_DISCOVERY_EDIT)) ->setNavigation(getHostNavigation('discoveries', $data['hostid'], @@ -38,7 +38,7 @@ $url = (new CUrl('host_discovery.php')) $form = (new CForm('post', $url)) ->setId('host-discovery-form') ->setName('itemForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']) ->addVar('hostid', $data['hostid']) ->addVar('backurl', $data['backurl']); @@ -1021,11 +1021,11 @@ else { $tab->setFooter(new CFormGrid($form_actions)); $form->addItem($tab); -$widget->addItem($form); +$html_page->addItem($form); require_once __DIR__.'/js/configuration.host.discovery.edit.js.php'; -$widget->show(); +$html_page->show(); (new CScriptTag(' item_form.init('.json_encode([ diff --git a/ui/include/views/configuration.host.discovery.list.php b/ui/include/views/configuration.host.discovery.list.php index c5a4f46d2d2..2dc1a73c8d5 100644 --- a/ui/include/views/configuration.host.discovery.list.php +++ b/ui/include/views/configuration.host.discovery.list.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/configuration.host.discovery.list.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Discovery rules')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_DISCOVERY_LIST @@ -52,7 +52,7 @@ $widget = (new CWidget()) ); if ($data['hostid'] != 0) { - $widget->setNavigation(getHostNavigation('discoveries', $data['hostid'])); + $html_page->setNavigation(getHostNavigation('discoveries', $data['hostid'])); } // Add filter tab. @@ -177,7 +177,7 @@ $filter_column3->addRow(_('Status'), $filter->addFilterTab(_('Filter'), [$filter_column1, $filter_column2, $filter_column3]); -$widget->addItem($filter); +$html_page->addItem($filter); $url = (new CUrl('host_discovery.php')) ->setArgument('context', $data['context']) @@ -361,10 +361,9 @@ $discoveryForm->addItem([$discoveryTable, $data['paging'], new CActionButtonList $button_list, $data['checkbox_hash'] )]); -// Append form to widget. -$widget->addItem($discoveryForm); - -$widget->show(); +$html_page + ->addItem($discoveryForm) + ->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/include/views/configuration.host.prototype.edit.php b/ui/include/views/configuration.host.prototype.edit.php index 2c5093777d0..d182b45711b 100644 --- a/ui/include/views/configuration.host.prototype.edit.php +++ b/ui/include/views/configuration.host.prototype.edit.php @@ -29,7 +29,7 @@ require_once __DIR__.'/js/common.template.edit.js.php'; $host_prototype = $data['host_prototype']; $parent_host = $data['parent_host']; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Host prototypes')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_HOST_PROTOTYPE_EDIT)) ->setNavigation(getHostNavigation('hosts', $data['discovery_rule']['hostid'], $data['discovery_rule']['itemid'])); @@ -48,7 +48,7 @@ $url = (new CUrl('host_prototypes.php')) $form = (new CForm('post', $url)) ->setId('host-prototype-form') ->setName('hostPrototypeForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', getRequest('form', 1)) ->addVar('parent_discoveryid', $data['discovery_rule']['itemid']) ->addVar('tls_accept', $parent_host['tls_accept']) @@ -449,6 +449,7 @@ else { } $form->addItem($tabs); -$widget->addItem($form); -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/include/views/configuration.host.prototype.list.php b/ui/include/views/configuration.host.prototype.list.php index da4db4cdd5a..9db4adf4165 100644 --- a/ui/include/views/configuration.host.prototype.list.php +++ b/ui/include/views/configuration.host.prototype.list.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/configuration.host.prototype.list.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Host prototypes')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_PROTOTYPE_LIST @@ -206,7 +206,6 @@ $itemForm->addItem([ ) ]); -// append form to widget -$widget->addItem($itemForm); - -$widget->show(); +$html_page + ->addItem($itemForm) + ->show(); diff --git a/ui/include/views/configuration.httpconf.edit.php b/ui/include/views/configuration.httpconf.edit.php index 7da317aece8..33ca974d66c 100644 --- a/ui/include/views/configuration.httpconf.edit.php +++ b/ui/include/views/configuration.httpconf.edit.php @@ -23,13 +23,13 @@ * @var CView $this */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Web monitoring')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_HTTPCONF_EDIT)); // append host summary to widget header if (!empty($this->data['hostid'])) { - $widget->setNavigation(getHostNavigation('web', $this->data['hostid'])); + $html_page->setNavigation(getHostNavigation('web', $this->data['hostid'])); } $url = (new CUrl('httpconf.php')) @@ -40,7 +40,7 @@ $url = (new CUrl('httpconf.php')) $http_form = (new CForm('post', $url)) ->setId('http-form') ->setName('httpForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $this->data['form']) ->addVar('hostid', $this->data['hostid']) ->addVar('templated', $this->data['templated']); @@ -281,7 +281,7 @@ else { } $http_form->addItem($http_tab); -$widget->addItem($http_form); +$html_page->addItem($http_form); $this->data['scenario_tab_data'] = [ 'agent_visibility' => [], @@ -300,7 +300,7 @@ zbx_subarray_push($this->data['scenario_tab_data']['agent_visibility'], ZBX_AGEN require_once dirname(__FILE__).'/js/configuration.httpconf.edit.js.php'; -$widget->show(); +$html_page->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/include/views/configuration.httpconf.list.php b/ui/include/views/configuration.httpconf.list.php index ba061589981..23c2538def5 100644 --- a/ui/include/views/configuration.httpconf.list.php +++ b/ui/include/views/configuration.httpconf.list.php @@ -88,7 +88,7 @@ $filter = (new CFilter()) ->addvar('context', $data['context']) ->addFilterTab(_('Filter'), [$filter_column_left, $filter_column_right]); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Web monitoring')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_HTTPCONF_LIST @@ -115,10 +115,10 @@ $widget = (new CWidget()) ); if (!empty($this->data['hostid'])) { - $widget->setNavigation(getHostNavigation('web', $this->data['hostid'])); + $html_page->setNavigation(getHostNavigation('web', $this->data['hostid'])); } -$widget->addItem($filter); +$html_page->addItem($filter); $url = (new CUrl('httpconf.php')) ->setArgument('context', $data['context']) @@ -237,10 +237,9 @@ $httpForm->addItem([$httpTable, $data['paging'], new CActionButtonList('action', $data['hostid'] )]); -// Append form to widget. -$widget->addItem($httpForm); - -$widget->show(); +$html_page + ->addItem($httpForm) + ->show(); (new CScriptTag('view.init();')) ->setOnDocumentReady() diff --git a/ui/include/views/configuration.item.edit.php b/ui/include/views/configuration.item.edit.php index aefee634f76..4e527061832 100644 --- a/ui/include/views/configuration.item.edit.php +++ b/ui/include/views/configuration.item.edit.php @@ -24,14 +24,14 @@ * @var array $data */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Items')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_ITEM_EDIT)); $host = $data['host']; if (!empty($data['hostid'])) { - $widget->setNavigation(getHostNavigation('items', $data['hostid'])); + $html_page->setNavigation(getHostNavigation('items', $data['hostid'])); } $url = (new CUrl('items.php')) @@ -42,7 +42,7 @@ $url = (new CUrl('items.php')) $form = (new CForm('post', $url)) ->setId('item-form') ->setName('itemForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']) ->addVar('hostid', $data['hostid']); @@ -1103,11 +1103,11 @@ else { } $form->addItem($item_tabs); -$widget->addItem($form); +$html_page->addItem($form); require_once __DIR__.'/js/configuration.item.edit.js.php'; -$widget->show(); +$html_page->show(); (new CScriptTag(' item_form.init('.json_encode([ diff --git a/ui/include/views/configuration.item.list.php b/ui/include/views/configuration.item.list.php index c7c335c23ef..4eade5ab61c 100644 --- a/ui/include/views/configuration.item.list.php +++ b/ui/include/views/configuration.item.list.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/configuration.item.list.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Items')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_ITEM_LIST @@ -52,10 +52,10 @@ $widget = (new CWidget()) ); if ($data['hostid'] != 0) { - $widget->setNavigation(getHostNavigation('items', $data['hostid'])); + $html_page->setNavigation(getHostNavigation('items', $data['hostid'])); } -$widget->addItem(new CPartial('configuration.filter.items', [ +$html_page->addItem(new CPartial('configuration.filter.items', [ 'filter_data' => $data['filter_data'], 'subfilter' => $data['subfilter'], 'context' => $data['context'] @@ -343,10 +343,9 @@ $itemForm->addItem([$itemTable, $data['paging'], new CActionButtonList('action', $data['checkbox_hash'] )]); -// Append form to widget. -$widget->addItem($itemForm); - -$widget->show(); +$html_page + ->addItem($itemForm) + ->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/include/views/configuration.item.prototype.edit.php b/ui/include/views/configuration.item.prototype.edit.php index 0f19cb6a33b..9ce17bf2fc2 100644 --- a/ui/include/views/configuration.item.prototype.edit.php +++ b/ui/include/views/configuration.item.prototype.edit.php @@ -24,12 +24,12 @@ * @var array $data */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Item prototypes')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_ITEM_PROTOTYPE_EDIT)); if (!empty($data['hostid'])) { - $widget->setNavigation(getHostNavigation('items', $data['hostid'], $data['parent_discoveryid'])); + $html_page->setNavigation(getHostNavigation('items', $data['hostid'], $data['parent_discoveryid'])); } $url = (new CUrl('disc_prototypes.php')) @@ -40,7 +40,7 @@ $url = (new CUrl('disc_prototypes.php')) $form = (new CForm('post', $url)) ->setId('item-prototype-form') ->setName('itemForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']) ->addVar('parent_discoveryid', $data['parent_discoveryid']); @@ -942,11 +942,11 @@ else { } $form->addItem($item_tabs); -$widget->addItem($form); +$html_page->addItem($form); require_once __DIR__.'/js/configuration.item.prototype.edit.js.php'; -$widget->show(); +$html_page->show(); (new CScriptTag(' item_form.init('.json_encode([ diff --git a/ui/include/views/configuration.item.prototype.list.php b/ui/include/views/configuration.item.prototype.list.php index d15cd8ef074..5de2fa06b49 100644 --- a/ui/include/views/configuration.item.prototype.list.php +++ b/ui/include/views/configuration.item.prototype.list.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/configuration.item.prototype.list.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Item prototypes')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_ITEM_PROTOTYPE_LIST @@ -226,7 +226,6 @@ $itemForm->addItem([ ) ]); -// append form to widget -$widget->addItem($itemForm); - -$widget->show(); +$html_page + ->addItem($itemForm) + ->show(); diff --git a/ui/include/views/configuration.maintenance.edit.php b/ui/include/views/configuration.maintenance.edit.php index 82fd38a3775..9184f0b60c6 100644 --- a/ui/include/views/configuration.maintenance.edit.php +++ b/ui/include/views/configuration.maintenance.edit.php @@ -25,14 +25,14 @@ require_once dirname(__FILE__).'/js/configuration.maintenance.edit.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Maintenance periods')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_MAINTENANCE_EDIT)); $maintenance_form = (new CForm()) ->setId('maintenance-form') ->setName('maintenanceForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']); if (array_key_exists('maintenanceid', $data) && $data['maintenanceid']) { @@ -281,6 +281,6 @@ else { $maintenance_form->addItem($maintenance_tab); -$widget->addItem($maintenance_form); - -$widget->show(); +$html_page + ->addItem($maintenance_form) + ->show(); diff --git a/ui/include/views/configuration.maintenance.list.php b/ui/include/views/configuration.maintenance.list.php index 8a0fe745fe8..e096aa44b56 100644 --- a/ui/include/views/configuration.maintenance.list.php +++ b/ui/include/views/configuration.maintenance.list.php @@ -23,7 +23,7 @@ * @var CView $this */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Maintenance periods')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_MAINTENANCE_LIST)) ->setControls( @@ -129,7 +129,6 @@ $maintenanceForm->addItem([ ]) ]); -// append form to widget -$widget->addItem($maintenanceForm); - -$widget->show(); +$html_page + ->addItem($maintenanceForm) + ->show(); diff --git a/ui/include/views/configuration.template.edit.php b/ui/include/views/configuration.template.edit.php index dc5239869c7..0a86265f25e 100644 --- a/ui/include/views/configuration.template.edit.php +++ b/ui/include/views/configuration.template.edit.php @@ -25,12 +25,12 @@ require_once __DIR__.'/js/common.template.edit.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Templates')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_TEMPLATES_EDIT)); if ($data['form'] !== 'clone' && $data['form'] !== 'full_clone') { - $widget->setNavigation(getHostNavigation('', $data['templateid'])); + $html_page->setNavigation(getHostNavigation('', $data['templateid'])); } $tabs = new CTabView(); @@ -42,7 +42,7 @@ if (!hasRequest('form_refresh')) { $form = (new CForm()) ->setId('templates-form') ->setName('templatesForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']); if ($data['templateid'] != 0) { @@ -236,6 +236,7 @@ else { } $form->addItem($tabs); -$widget->addItem($form); -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/include/views/configuration.template.list.php b/ui/include/views/configuration.template.list.php index 4d7ead032c2..55839182cc0 100644 --- a/ui/include/views/configuration.template.list.php +++ b/ui/include/views/configuration.template.list.php @@ -83,7 +83,7 @@ $filter = (new CFilter()) (new CFormList())->addRow(_('Tags'), $filter_tags_table) ]); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Templates')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_TEMPLATES_LIST)) ->setControls((new CTag('nav', true, @@ -296,6 +296,6 @@ $form->addItem([ ) ]); -$widget->addItem($form); - -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/include/views/configuration.trigger.prototype.edit.php b/ui/include/views/configuration.trigger.prototype.edit.php index 407e4f392d8..d77434b6065 100644 --- a/ui/include/views/configuration.trigger.prototype.edit.php +++ b/ui/include/views/configuration.trigger.prototype.edit.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/configuration.triggers.edit.js.php'; -$triggersWidget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Trigger prototypes')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_TRIGGER_PROTOTYPE_EDIT)) ->setNavigation(getHostNavigation('triggers', $data['hostid'], $data['parent_discoveryid'])); @@ -39,7 +39,7 @@ $url = (new CUrl('trigger_prototypes.php')) $triggersForm = (new CForm('post', $url)) ->setId('triggers-prototype-form') ->setName('triggersForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']) ->addItem((new CVar('parent_discoveryid', $data['parent_discoveryid']))->removeId()) ->addVar('expression_constructor', $data['expression_constructor']) @@ -749,9 +749,9 @@ else { // append tabs to form $triggersForm->addItem($triggersTab); -$triggersWidget->addItem($triggersForm); - -$triggersWidget->show(); +$html_page + ->addItem($triggersForm) + ->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/include/views/configuration.trigger.prototype.list.php b/ui/include/views/configuration.trigger.prototype.list.php index 82fef6e1bb5..ecc66d76ae2 100644 --- a/ui/include/views/configuration.trigger.prototype.list.php +++ b/ui/include/views/configuration.trigger.prototype.list.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/configuration.trigger.prototype.list.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Trigger prototypes')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_TRIGGER_PROTOTYPE_LIST @@ -226,7 +226,6 @@ $triggersForm->addItem([ ) ]); -// append form to widget -$widget->addItem($triggersForm); - -$widget->show(); +$html_page + ->addItem($triggersForm) + ->show(); diff --git a/ui/include/views/configuration.triggers.edit.php b/ui/include/views/configuration.triggers.edit.php index b2799572593..893d8c6bcf3 100644 --- a/ui/include/views/configuration.triggers.edit.php +++ b/ui/include/views/configuration.triggers.edit.php @@ -25,13 +25,13 @@ require_once dirname(__FILE__).'/js/configuration.triggers.edit.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Triggers')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::DATA_COLLECTION_TRIGGERS_EDIT)); // Append host summary to widget header. if ($data['hostid'] != 0) { - $widget->setNavigation(getHostNavigation('triggers', $data['hostid'])); + $html_page->setNavigation(getHostNavigation('triggers', $data['hostid'])); } $url = (new CUrl('triggers.php')) @@ -42,7 +42,7 @@ $url = (new CUrl('triggers.php')) $triggersForm = (new CForm('post', $url)) ->setid('triggers-form') ->setName('triggersForm') - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) ->addVar('form', $data['form']) ->addVar('hostid', $data['hostid']) ->addVar('expression_constructor', $data['expression_constructor']) @@ -730,9 +730,9 @@ else { // Append tabs to form. $triggersForm->addItem($triggersTab); -$widget->addItem($triggersForm); - -$widget->show(); +$html_page + ->addItem($triggersForm) + ->show(); (new CScriptTag(' view.init('.json_encode([ diff --git a/ui/include/views/configuration.triggers.list.php b/ui/include/views/configuration.triggers.list.php index 8cc3488ddfc..911f86b8dac 100644 --- a/ui/include/views/configuration.triggers.list.php +++ b/ui/include/views/configuration.triggers.list.php @@ -146,7 +146,7 @@ $filter = (new CFilter()) ->addvar('context', $data['context'], 'filter_context') ->addFilterTab(_('Filter'), [$filter_column1, $filter_column2]); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Triggers')) ->setDocUrl(CDocHelper::getUrl($data['context'] === 'host' ? CDocHelper::DATA_COLLECTION_HOST_TRIGGERS_LIST @@ -173,10 +173,10 @@ $widget = (new CWidget()) ); if ($data['single_selected_hostid'] != 0) { - $widget->setNavigation(getHostNavigation('triggers', $data['single_selected_hostid'])); + $html_page->setNavigation(getHostNavigation('triggers', $data['single_selected_hostid'])); } -$widget->addItem($filter); +$html_page->addItem($filter); $url = (new CUrl('triggers.php')) ->setArgument('context', $data['context']) @@ -370,10 +370,9 @@ $triggers_form->addItem([ ) ]); -// append form to widget -$widget->addItem($triggers_form); - -$widget->show(); +$html_page + ->addItem($triggers_form) + ->show(); (new CScriptTag('view.init();')) ->setOnDocumentReady() diff --git a/ui/include/views/general.warning.php b/ui/include/views/general.warning.php index b2f3f2ba3c9..90b3bd0bfba 100644 --- a/ui/include/views/general.warning.php +++ b/ui/include/views/general.warning.php @@ -21,11 +21,15 @@ /** * @var CView $this + * @var array $data */ -$pageHeader = (new CPageHeader(_('Warning').' ['._s('refreshed every %1$s sec.', 30).']', CWebUser::getLang())) - ->addCssFile('assets/styles/'.CHtml::encode($data['theme']).'.css') - ->display(); +$page_header = (new CHtmlPageHeader(_('Warning').' ['._s('refreshed every %1$s sec.', 30).']', CWebUser::getLang())); + +$page_header + ->setTheme($data['theme']) + ->addCssFile('assets/styles/'.$page_header->getTheme().'.css') + ->show(); $buttons = array_key_exists('buttons', $data) ? $data['buttons'] diff --git a/ui/include/views/inventory.host.list.php b/ui/include/views/inventory.host.list.php index 4809399d35b..9ddcfa202ba 100644 --- a/ui/include/views/inventory.host.list.php +++ b/ui/include/views/inventory.host.list.php @@ -23,7 +23,7 @@ * @var CView $this */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Host inventory')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::INVENTORY_HOST_LIST)); @@ -37,7 +37,7 @@ foreach ($data['host_inventories'] as $inventoryField) { } // filter -$widget->addItem( +$html_page->addItem( (new CFilter()) ->setResetUrl(new CUrl('hostinventories.php')) ->setProfile($data['profileIdx']) @@ -112,6 +112,6 @@ foreach ($this->data['hosts'] as $host) { $table->addRow($row); } -$widget->addItem([$table, $this->data['paging']]); - -$widget->show(); +$html_page + ->addItem([$table, $this->data['paging']]) + ->show(); diff --git a/ui/include/views/inventory.host.view.php b/ui/include/views/inventory.host.view.php index 56052600dff..52c2b24132a 100644 --- a/ui/include/views/inventory.host.view.php +++ b/ui/include/views/inventory.host.view.php @@ -260,12 +260,13 @@ $hostInventoriesTab->setFooter(makeFormFooter(null, [new CButtonCancel()])); $web_layout_mode = CViewHelper::loadLayoutMode(); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Host inventory')) ->setWebLayoutMode($web_layout_mode) ->setControls((new CList())->addItem(get_icon('kioskmode', ['mode' => $web_layout_mode]))) - ->addItem((new CForm()) - ->setAttribute('aria-labelledby', ZBX_STYLE_PAGE_TITLE) - ->addItem($hostInventoriesTab) + ->addItem( + (new CForm()) + ->setAttribute('aria-labelledby', CHtmlPage::PAGE_TITLE_ID) + ->addItem($hostInventoriesTab) ) ->show(); diff --git a/ui/include/views/monitoring.history.php b/ui/include/views/monitoring.history.php index f20ef746389..23e3480b0a2 100644 --- a/ui/include/views/monitoring.history.php +++ b/ui/include/views/monitoring.history.php @@ -26,7 +26,7 @@ $this->includeJsFile('monitoring.history.js.php'); $web_layout_mode = CViewHelper::loadLayoutMode(); -$historyWidget = (new CWidget())->setWebLayoutMode($web_layout_mode); +$html_page = (new CHtmlPage())->setWebLayoutMode($web_layout_mode); $header = [ 'left' => _n('%1$s item', '%1$s items', count($data['items'])), @@ -52,12 +52,8 @@ if ($data['items']) { } if ((count($data['items']) == 1 || $same_host) && $data['itemids']) { - $header['left'] = [ - $host_name, - NAME_DELIMITER, - count($data['items']) == 1 ? $item['name'] : $header['left'] - ]; - $header_row[] = implode('', $header['left']); + $header['left'] = $host_name.NAME_DELIMITER.(count($data['items']) == 1 ? $item['name'] : $header['left']); + $header_row[] = $header['left']; } else { $header_row[] = $header['left']; @@ -103,7 +99,7 @@ if ($data['action'] !== HISTORY_GRAPH && $data['action'] !== HISTORY_BATCH_GRAPH } if ($data['action'] == HISTORY_GRAPH && count($data['items']) == 1) { - $action_list->addItem(get_icon('favourite', [ + $action_list->addItem(get_icon('favorite', [ 'fav' => 'web.favorite.graphids', 'elid' => $item['itemid'], 'elname' => 'itemid' @@ -222,7 +218,7 @@ if ($data['itemids']) { // append plaintext to widget if ($data['plaintext']) { foreach ($header_row as $text) { - $historyWidget->addItem([new CSpan($text), BR()]); + $html_page->addItem([new CSpan($text), BR()]); } if ($data['itemids']) { @@ -231,11 +227,11 @@ if ($data['plaintext']) { foreach ($screen as $text) { $pre->addItem([$text, BR()]); } - $historyWidget->addItem($pre); + $html_page->addItem($pre); } } else { - $historyWidget + $html_page ->setTitle($header['left']) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_HISTORY)) ->setControls((new CTag('nav', true, $header['right']))->setAttribute('aria-label', _('Content controls'))); @@ -272,10 +268,10 @@ else { if ($data['itemids']) { if ($data['action'] !== HISTORY_LATEST) { - $historyWidget->addItem($filter_form); + $html_page->addItem($filter_form); } - $historyWidget->addItem($screen->get()); + $html_page->addItem($screen->get()); if ($data['action'] !== HISTORY_LATEST) { CScreenBuilder::insertScreenStandardJs($screen->timeline); @@ -283,10 +279,10 @@ else { } else { if ($filter_tab) { - $historyWidget->addItem($filter_form); + $html_page->addItem($filter_form); } - $historyWidget->addItem( + $html_page->addItem( (new CTableInfo()) ->setHeader([ (new CColHeader(_('Timestamp')))->addClass(ZBX_STYLE_CELL_WIDTH), @@ -298,4 +294,4 @@ else { } } -$historyWidget->show(); +$html_page->show(); diff --git a/ui/include/views/monitoring.sysmap.constructor.php b/ui/include/views/monitoring.sysmap.constructor.php index cdc039c2f87..430eeb0b700 100644 --- a/ui/include/views/monitoring.sysmap.constructor.php +++ b/ui/include/views/monitoring.sysmap.constructor.php @@ -87,7 +87,7 @@ zbx_add_post_js('ZABBIX.apps.map.run("'.ZBX_STYLE_MAP_AREA.'", '.json_encode([ 'defaultIconName' => $data['defaultIconName'] ], JSON_FORCE_OBJECT).');'); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Network maps')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_SYSMAP_CONSTRUCTOR)) ->setNavigation($menu) diff --git a/ui/include/views/monitoring.sysmap.edit.php b/ui/include/views/monitoring.sysmap.edit.php index 0d0883731c8..3ffc716d352 100644 --- a/ui/include/views/monitoring.sysmap.edit.php +++ b/ui/include/views/monitoring.sysmap.edit.php @@ -25,7 +25,7 @@ require_once dirname(__FILE__).'/js/monitoring.sysmap.edit.js.php'; -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Network maps')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_SYSMAP_EDIT)); @@ -436,7 +436,6 @@ else { $form->addItem($tabs); -// Append form to widget. -$widget->addItem($form); - -$widget->show(); +$html_page + ->addItem($form) + ->show(); diff --git a/ui/include/views/monitoring.sysmap.list.php b/ui/include/views/monitoring.sysmap.list.php index 37c54a4d4e0..2401f0bd819 100644 --- a/ui/include/views/monitoring.sysmap.list.php +++ b/ui/include/views/monitoring.sysmap.list.php @@ -23,7 +23,7 @@ * @var CView $this */ -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Maps')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::MONITORING_SYSMAP_LIST)) ->setControls( @@ -123,7 +123,6 @@ $sysmapForm->addItem([ ]) ]); -// append form to widget -$widget->addItem($sysmapForm); - -$widget->show(); +$html_page + ->addItem($sysmapForm) + ->show(); diff --git a/ui/include/views/reports.toptriggers.php b/ui/include/views/reports.toptriggers.php index fc9ee507398..60e8e70dcff 100644 --- a/ui/include/views/reports.toptriggers.php +++ b/ui/include/views/reports.toptriggers.php @@ -115,7 +115,7 @@ $obj_data = [ zbx_add_post_js('timeControl.addObject("toptriggers", '.zbx_jsvalue($data['filter']).', '.zbx_jsvalue($obj_data).');'); zbx_add_post_js('timeControl.processObjects();'); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('100 busiest triggers')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::REPORTS_TOPTRIGGERS)) ->addItem($filterForm) diff --git a/ui/js/class.dashboard.js b/ui/js/class.dashboard.js index 2a5c3a09e4e..681b96062c7 100644 --- a/ui/js/class.dashboard.js +++ b/ui/js/class.dashboard.js @@ -33,6 +33,7 @@ const DASHBOARD_EVENT_BUSY = 'dashboard-busy'; const DASHBOARD_EVENT_IDLE = 'dashboard-idle'; const DASHBOARD_EVENT_EDIT = 'dashboard-edit'; const DASHBOARD_EVENT_APPLY_PROPERTIES = 'dashboard-apply-properties'; +const DASHBOARD_EVENT_CONFIGURATION_OUTDATED = 'dashboard-configuration-outdated'; class CDashboard extends CBaseComponent { @@ -48,6 +49,8 @@ class CDashboard extends CBaseComponent { widget_min_rows, widget_max_rows, widget_defaults, + widget_last_type = null, + configuration_hash = null, is_editable, is_edit_mode, can_edit_dashboards, @@ -85,7 +88,9 @@ class CDashboard extends CBaseComponent { this._max_rows = max_rows; this._widget_min_rows = widget_min_rows; this._widget_max_rows = widget_max_rows; - this._widget_defaults = widget_defaults; + this._widget_defaults = {...widget_defaults}; + this._widget_last_type = widget_last_type; + this._configuration_hash = configuration_hash; this._is_editable = is_editable; this._is_edit_mode = is_edit_mode; this._can_edit_dashboards = can_edit_dashboards; @@ -132,6 +137,11 @@ class CDashboard extends CBaseComponent { this._slideshow_switch_time = null; this._slideshow_timeout_id = null; + this._configuration_check_period = 60000; + this._configuration_check_steady_period = 2000; + this._configuration_check_time = null; + this._configuration_check_timeout_id = null; + this._is_unsaved = false; if (!this._is_kiosk_mode) { @@ -173,8 +183,12 @@ class CDashboard extends CBaseComponent { this._target.classList.add(ZBX_STYLE_DASHBOARD_IS_EDIT_MODE); } - if (!this._is_edit_mode && this._data.auto_start == 1 && this._dashboard_pages.size > 1) { - this._startSlideshow(); + if (!this._is_edit_mode) { + this._startConfigurationChecker(); + + if (this._data.auto_start == 1 && this._dashboard_pages.size > 1) { + this._startSlideshow(); + } } } @@ -197,6 +211,7 @@ class CDashboard extends CBaseComponent { this._tabs.enableSorting(); } + this._stopConfigurationChecker(); this._stopSlideshow(); this._target.classList.add(ZBX_STYLE_DASHBOARD_IS_EDIT_MODE); @@ -282,7 +297,7 @@ class CDashboard extends CBaseComponent { } this._slideshow_switch_time = Math.max(Date.now() + this._slideshow_steady_period, - timeout_ms + this._slideshow_switch_time + this._slideshow_switch_time + timeout_ms ); this._slideshow_timeout_id = setTimeout(() => this._switchSlideshow(), @@ -310,6 +325,101 @@ class CDashboard extends CBaseComponent { } } + _startConfigurationChecker() { + if (this._configuration_check_timeout_id !== null) { + clearTimeout(this._configuration_check_timeout_id); + } + + this._configuration_check_time = Date.now() + this._configuration_check_period; + this._configuration_check_timeout_id = setTimeout(() => this._checkConfiguration(), + this._configuration_check_period + ); + } + + _stopConfigurationChecker() { + if (this._configuration_check_timeout_id === null) { + return; + } + + clearTimeout(this._configuration_check_timeout_id); + + this._configuration_check_time = null; + this._configuration_check_timeout_id = null; + } + + _checkConfiguration() { + this._configuration_check_timeout_id = null; + + if (this._isUserInteracting()) { + this._configuration_check_time = Date.now() + this._configuration_check_steady_period; + this._configuration_check_timeout_id = setTimeout(() => this._checkConfiguration(), + this._configuration_check_steady_period + ); + + return; + } + + const busy_condition = this._createBusyCondition(); + + Promise.resolve() + .then(() => this._promiseCheckConfiguration()) + .catch((exception) => { + console.log('Could not check the dashboard configuration', exception); + }) + .finally(() => { + this._configuration_check_time = Math.max(Date.now() + this._configuration_check_steady_period, + this._configuration_check_time + this._configuration_check_period + ); + + this._configuration_check_timeout_id = setTimeout(() => this._checkConfiguration(), + this._configuration_check_time - Date.now() + ); + + this._deleteBusyCondition(busy_condition); + }); + } + + _promiseCheckConfiguration() { + const curl = new Curl('zabbix.php'); + + curl.setArgument('action', 'dashboard.configuration.hash.get'); + + return fetch(curl.getUrl(), { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ + templateid: this._data.templateid ?? undefined, + dashboardid: this._data.dashboardid + }) + }) + .then((response) => response.json()) + .then((response) => { + if ('error' in response) { + throw {error: response.error}; + } + + if (response.configuration_hash !== null && this._configuration_hash !== response.configuration_hash) { + this.fire(DASHBOARD_EVENT_CONFIGURATION_OUTDATED); + } + }); + } + + _keepSteadyConfigurationChecker() { + if (this._configuration_check_timeout_id === null) { + return; + } + + if (this._configuration_check_time - Date.now() < this._configuration_check_steady_period) { + clearTimeout(this._configuration_check_timeout_id); + + this._configuration_check_time = Date.now() + this._configuration_check_steady_period; + + this._configuration_check_timeout_id = setTimeout(() => this._checkConfiguration(), + this._configuration_check_time - Date.now() + ); + } + } + _announceWidgets() { const dashboard_pages = Array.from(this._dashboard_pages.keys()); @@ -502,16 +612,26 @@ class CDashboard extends CBaseComponent { } pasteDashboardPage(new_dashboard_page_data) { + this._clearWarnings(); + if (this._dashboard_pages.size >= this._max_dashboard_pages) { this._warnDashboardExhausted(); return; } + const widgets = []; + + for (const widget of new_dashboard_page_data.widgets) { + if (widget.type in this._widget_defaults) { + widgets.push(widget); + } + } + const busy_condition = this._createBusyCondition(); return Promise.resolve() - .then(() => this._promiseDashboardWidgetsSanitize(new_dashboard_page_data.widgets)) + .then(() => this._promiseDashboardWidgetsSanitize(widgets)) .then((response) => { if (this._dashboard_pages.size >= this._max_dashboard_pages) { this._warnDashboardExhausted(); @@ -519,31 +639,42 @@ class CDashboard extends CBaseComponent { return; } - const widgets = new_dashboard_page_data.widgets; + if (response.widgets.length < new_dashboard_page_data.widgets.length) { + this._warn(t('Inaccessible widgets were not pasted.')); + } + + const sane_widgets = []; for (let i = 0; i < response.widgets.length; i++) { - widgets[i].fields = response.widgets[i].fields; + if (response.widgets[i] !== null) { + sane_widgets.push({ + ...widgets[i], + fields: response.widgets[i].fields + }); + } } const used_references = this._getUsedReferences(); const reference_substitution = new Map(); - for (const widget of widgets) { - const reference_field = this._widget_defaults[widget.type].reference_field; + for (const widget of sane_widgets) { + const widget_class = eval(this._widget_defaults[widget.type].js_class); - if (reference_field !== null) { - const old_reference = widget.fields[reference_field]; + if (widget_class.hasReferenceField()) { + const old_reference = widget.fields.reference; const new_reference = this._createReference({used_references}); - widget.fields[reference_field] = new_reference; + widget.fields.reference = new_reference; used_references.add(new_reference); reference_substitution.set(old_reference, new_reference); } } - for (const widget of widgets) { - for (const reference_field of this._widget_defaults[widget.type].foreign_reference_fields) { + for (const widget of sane_widgets) { + const widget_class = eval(this._widget_defaults[widget.type].js_class); + + for (const reference_field of widget_class.getForeignReferenceFields()) { const old_reference = widget.fields[reference_field]; if (reference_substitution.has(old_reference)) { @@ -556,7 +687,7 @@ class CDashboard extends CBaseComponent { dashboard_pageid: null, name: new_dashboard_page_data.name, display_period: new_dashboard_page_data.display_period, - widgets + widgets: sane_widgets }); this._selectDashboardPage(dashboard_page, {is_async: true}); @@ -583,6 +714,14 @@ class CDashboard extends CBaseComponent { } pasteWidget(new_widget_data, {widget = null, new_widget_pos = null} = {}) { + this._clearWarnings(); + + if (!(new_widget_data.type in this._widget_defaults)) { + this._warn(t('Cannot paste inaccessible widget.')); + + return; + } + const dashboard_page = this._selected_dashboard_page; if (widget !== null) { @@ -612,23 +751,21 @@ class CDashboard extends CBaseComponent { dashboard_page.deleteWidget(widget, {is_batch_mode: true}); } - const reference_field = this._widget_defaults[new_widget_data.type].reference_field; + const new_widget_class = eval(this._widget_defaults[new_widget_data.type].js_class); - if (reference_field !== null) { - new_widget_data.fields[reference_field] = this._createReference(); + if (new_widget_class.hasReferenceField()) { + new_widget_data.fields.reference = this._createReference(); } let references = []; for (const widget of dashboard_page.getWidgets()) { - const reference_field = this._widget_defaults[widget.getType()].reference_field; - - if (reference_field !== null) { - references.push(widget.getFields()[reference_field]); + if (widget.constructor.hasReferenceField()) { + references.push(widget.getFields()['reference']); } } - for (const reference_field of this._widget_defaults[new_widget_data.type].foreign_reference_fields) { + for (const reference_field of new_widget_class.getForeignReferenceFields()) { if (reference_field in new_widget_data.fields && !references.includes(new_widget_data.fields[reference_field])) { new_widget_data.fields[reference_field] = ''; @@ -654,6 +791,14 @@ class CDashboard extends CBaseComponent { return; } + if (response.widgets[0] === null) { + dashboard_page.deleteWidget(paste_placeholder_widget); + + this._warn(t('Cannot paste inaccessible widget.')); + + return; + } + dashboard_page.replaceWidget(paste_placeholder_widget, { ...new_widget_data, fields: response.widgets[0].fields, @@ -691,7 +836,7 @@ class CDashboard extends CBaseComponent { for (const widget_data of widgets_data) { request_widgets_data.push({ type: widget_data.type, - fields: JSON.stringify(widget_data.fields) + fields: widget_data.fields }); } @@ -787,6 +932,8 @@ class CDashboard extends CBaseComponent { if (!this._is_edit_mode) { this._storeSelectedDashboardPage(dashboard_page); + this._keepSteadyConfigurationChecker(); + if (this._isSlideshowRunning()) { this._keepSteadySlideshow(); } @@ -794,8 +941,12 @@ class CDashboard extends CBaseComponent { this._promiseSelectDashboardPage(dashboard_page, {is_async}) .then(() => { - if (this._isSlideshowRunning()) { - this._startSlideshow(); + if (!this._is_edit_mode) { + this._keepSteadyConfigurationChecker(); + + if (this._isSlideshowRunning()) { + this._startSlideshow(); + } } }); } @@ -1127,7 +1278,19 @@ class CDashboard extends CBaseComponent { } editWidgetProperties(properties = {}, {new_widget_pos = null} = {}) { - const overlay = PopUp('dashboard.widget.edit', { + this._clearWarnings(); + + if (properties.type === undefined) { + properties.type = this._widget_last_type; + + if (properties.type === null) { + this._warn(t('Cannot add widget: no widgets available.')); + + return; + } + } + + const overlay = PopUp(`widget.${properties.type}.edit`, { templateid: this._data.templateid ?? undefined, ...properties }, { @@ -1184,6 +1347,18 @@ class CDashboard extends CBaseComponent { } } + document.getElementById('type').addEventListener('change', () => this.reloadWidgetProperties()); + + form.addEventListener('change', (e) => { + const do_trim = e.target.matches( + 'input[type="text"]:not([data-no-trim="1"]), textarea:not([data-no-trim="1"])' + ); + + if (do_trim) { + e.target.value = e.target.value.trim(); + } + }, {capture: true}); + try { new TabIndicators(); } @@ -1207,12 +1382,11 @@ class CDashboard extends CBaseComponent { const properties = { type: fields.type, - prev_type: overlay.data.original_properties.type, unique_id: overlay.data.original_properties.unique_id ?? undefined, dashboard_page_unique_id: overlay.data.original_properties.dashboard_page_unique_id ?? undefined }; - if (properties.type === properties.prev_type) { + if (properties.type === overlay.data.original_properties.type) { properties.name = fields.name; properties.view_mode = fields.show_header == 1 ? ZBX_WIDGET_VIEW_MODE_NORMAL @@ -1222,9 +1396,11 @@ class CDashboard extends CBaseComponent { delete fields.name; delete fields.show_header; - properties.fields = JSON.stringify(fields); + properties.fields = fields; } + overlay.$dialogue[0].dispatchEvent(new CustomEvent('overlay.reload')); + this.editWidgetProperties(properties, {new_widget_pos: this._new_widget_pos}); } @@ -1256,18 +1432,24 @@ class CDashboard extends CBaseComponent { return Promise.resolve() .then(() => this._promiseDashboardWidgetCheck({templateid, type, name, view_mode, fields})) - .then(() => this._promiseDashboardWidgetConfigure({templateid, type, view_mode, fields})) - .then((configuration) => { + .then(() => { overlayDialogueDestroy(overlay.dialogueid); if (widget !== null && widget.getType() === type) { - widget.updateProperties({name, view_mode, fields, configuration}); + widget.updateProperties({name, view_mode, fields}); return; } - if (this._widget_defaults[type].reference_field !== null) { - fields[this._widget_defaults[type].reference_field] = this._createReference(); + if (type !== this._widget_last_type) { + this._widget_last_type = type; + updateUserProfile('web.dashboard.last_widget_type', type, [], PROFILE_TYPE_STR); + } + + const widget_class = eval(this._widget_defaults[type].js_class); + + if (widget_class.hasReferenceField()) { + fields.reference = this._createReference(); } const widget_data = { @@ -1275,7 +1457,6 @@ class CDashboard extends CBaseComponent { name, view_mode, fields, - configuration, widgetid: null, pos: widget === null ? this._new_widget_pos_reserved : widget.getPos(), is_new: widget === null, @@ -1332,45 +1513,25 @@ class CDashboard extends CBaseComponent { }); } - _promiseDashboardWidgetCheck({templateid, type, name, view_mode, fields}) { - const fields_str = Object.keys(fields).length > 0 ? JSON.stringify(fields) : undefined; - - const curl = new Curl('zabbix.php'); - - curl.setArgument('action', 'dashboard.widget.check'); - - return fetch(curl.getUrl(), { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({templateid, type, name, view_mode, fields: fields_str}) - }) - .then((response) => response.json()) - .then((response) => { - if ('error' in response) { - throw {error: response.error}; - } - }); + _isEditingWidgetProperties() { + return this._is_edit_widget_properties_cancel_subscribed; } - _promiseDashboardWidgetConfigure({templateid, type, view_mode, fields}) { - const fields_str = Object.keys(fields).length > 0 ? JSON.stringify(fields) : undefined; - + _promiseDashboardWidgetCheck({templateid, type, name, view_mode, fields}) { const curl = new Curl('zabbix.php'); - curl.setArgument('action', 'dashboard.widget.configure'); + curl.setArgument('action', 'dashboard.widget.check'); return fetch(curl.getUrl(), { method: 'POST', headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({templateid, type, view_mode, fields: fields_str}) + body: JSON.stringify({templateid, type, name, view_mode, fields}) }) .then((response) => response.json()) .then((response) => { if ('error' in response) { throw {error: response.error}; } - - return response.configuration; }); } @@ -1385,7 +1546,26 @@ class CDashboard extends CBaseComponent { if (this._can_edit_dashboards) { menu_actions.push({ label: t('Copy'), - clickCallback: () => this._storeDashboardPageDataCopy(dashboard_page.getDataCopy()) + clickCallback: () => { + this._clearWarnings(); + + const data_copy = dashboard_page.getDataCopy(); + const data_copy_widgets = data_copy.widgets; + + data_copy.widgets = []; + + for (const widget of data_copy_widgets) { + if (widget.type in this._widget_defaults) { + data_copy.widgets.push(widget); + } + } + + this._storeDashboardPageDataCopy(data_copy); + + if (data_copy.widgets.length < data_copy_widgets.length) { + this._warn(t('Inaccessible widgets were not copied.')); + } + } }); } @@ -1430,25 +1610,23 @@ class CDashboard extends CBaseComponent { // Dashboard view methods. - _warnDashboardExhausted() { + _warn(warning) { this._clearWarnings(); - this._warning_message_box = makeMessageBox('warning', [], sprintf( + this._warning_message_box = makeMessageBox('warning', [], warning); + + addMessage(this._warning_message_box); + } + + _warnDashboardExhausted() { + this._warn(sprintf( t('Cannot add dashboard page: maximum number of %1$d dashboard pages has been added.'), this._max_dashboard_pages )); - - addMessage(this._warning_message_box); } _warnDashboardPageExhausted() { - this._clearWarnings(); - - this._warning_message_box = makeMessageBox('warning', [], - t('Cannot add widget: not enough free space on the dashboard.') - ); - - addMessage(this._warning_message_box); + this._warn(t('Cannot add widget: not enough free space on the dashboard.')); } _clearWarnings() { @@ -1676,14 +1854,13 @@ class CDashboard extends CBaseComponent { for (const dashboard_page of this._dashboard_pages.keys()) { for (const widget of dashboard_page.getWidgets()) { - const type = widget.getType(); const fields = widget.getFields(); - if (this._widget_defaults[type].reference_field !== null) { - used_references.add(fields[this._widget_defaults[type].reference_field]); + if (widget.constructor.hasReferenceField()) { + used_references.add(fields.reference); } - for (const reference_field of this._widget_defaults[type].foreign_reference_fields) { + for (const reference_field of widget.constructor.getForeignReferenceFields()) { used_references.add(fields[reference_field]); } } @@ -1704,31 +1881,23 @@ class CDashboard extends CBaseComponent { }, dashboardPageWidgetAdd: (e) => { + const dashboard_page = this._selected_dashboard_page; + const new_widget_data = this.getStoredWidgetDataCopy(); const new_widget_pos = e.detail.new_widget_pos; if (new_widget_data !== null) { - const dashboard_page = this._selected_dashboard_page; - - let menu_was_cancelled = true; - const menu = [ { label: t('Actions'), items: [ { label: t('Add widget'), - clickCallback: () => { - this.editWidgetProperties({}, {new_widget_pos}); - menu_was_cancelled = false; - } + clickCallback: () => this.editWidgetProperties({}, {new_widget_pos}) }, { label: t('Paste widget'), - clickCallback: () => { - this.pasteWidget(new_widget_data, {new_widget_pos}); - menu_was_cancelled = false; - } + clickCallback: () => this.pasteWidget(new_widget_data, {new_widget_pos}) } ] } @@ -1741,7 +1910,7 @@ class CDashboard extends CBaseComponent { jQuery(placeholder).menuPopup(menu, placeholder_event, { closeCallback: () => { - if (menu_was_cancelled) { + if (!this._isEditingWidgetProperties()) { dashboard_page.resetWidgetPlaceholder(); } } @@ -1749,6 +1918,10 @@ class CDashboard extends CBaseComponent { } else { this.editWidgetProperties({}, {new_widget_pos}); + + if (!this._isEditingWidgetProperties()) { + dashboard_page.resetWidgetPlaceholder(); + } } }, @@ -1780,7 +1953,7 @@ class CDashboard extends CBaseComponent { type: widget.getType(), name: widget.getName(), view_mode: widget.getViewMode(), - fields: JSON.stringify(widget.getFields()), + fields: widget.getFields(), unique_id: widget.getUniqueId(), dashboard_page_unique_id: dashboard_page.getUniqueId() }); @@ -1907,6 +2080,8 @@ class CDashboard extends CBaseComponent { } if (!this._is_edit_mode) { + this._keepSteadyConfigurationChecker(); + if (this._isSlideshowRunning()) { this._keepSteadySlideshow(); } diff --git a/ui/js/class.dashboard.page.js b/ui/js/class.dashboard.page.js index bacb46c58ca..33a87f18a68 100644 --- a/ui/js/class.dashboard.page.js +++ b/ui/js/class.dashboard.page.js @@ -323,19 +323,26 @@ class CDashboardPage extends CBaseComponent { return null; } - addWidget({type, name, view_mode, fields, configuration, widgetid, pos, is_new, rf_rate, unique_id}) { - const widget = this._createWidget(this._widget_defaults[type].js_class, { - type, - name, - view_mode, - fields, - configuration, - widgetid, - pos, - is_new, - rf_rate, - unique_id - }); + addWidget({type, name, view_mode, fields, widgetid, pos, is_new, rf_rate, unique_id}) { + let widget; + + if (type in this._widget_defaults) { + widget = this._createWidget(eval(this._widget_defaults[type].js_class), { + type, + name, + view_mode, + fields, + defaults: this._widget_defaults[type], + widgetid, + pos, + is_new, + rf_rate, + unique_id + }); + } + else { + widget = this._createInaccessibleWidget({name, widgetid, pos, unique_id}); + } this._doAddWidget(widget); @@ -406,14 +413,13 @@ class CDashboardPage extends CBaseComponent { return this.addWidget(widget_data); } - _createWidget(js_class, {type, name, view_mode, fields, configuration, widgetid, pos, is_new, rf_rate, unique_id}) { - return new (eval(js_class))({ + _createWidget(widget_class, {type, name, view_mode, fields, defaults, widgetid, pos, is_new, rf_rate, unique_id}) { + return new widget_class({ type, name, view_mode, fields, - configuration, - defaults: this._widget_defaults[type], + defaults, widgetid, pos, is_new, @@ -433,18 +439,34 @@ class CDashboardPage extends CBaseComponent { can_edit_dashboards: this._can_edit_dashboards, time_period: this._time_period, dynamic_hostid: this._dynamic_hostid, - scope_id: this._unique_id, + unique_id + }); + } + + _createInaccessibleWidget({name, widgetid, pos, unique_id}) { + return this._createWidget(CWidgetInaccessible, { + type: 'inaccessible', + name, + view_mode: ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER, + fields: {}, + defaults: { + name: t('Inaccessible widget') + }, + widgetid, + pos, + is_new: false, + rf_rate: 0, unique_id }); } _createPastePlaceholderWidget({type, name, view_mode, pos, unique_id}) { - return this._createWidget('CWidgetPastePlaceholder', { - type, + return this._createWidget(CWidgetPastePlaceholder, { + type: 'paste-placeholder', name, view_mode, fields: {}, - configuration: {}, + defaults: this._widget_defaults[type], widgetid: null, pos, is_new: false, diff --git a/ui/js/class.sortable.js b/ui/js/class.sortable.js index 6b8211c3085..e07755058b1 100644 --- a/ui/js/class.sortable.js +++ b/ui/js/class.sortable.js @@ -258,6 +258,8 @@ class CSortable extends CBaseComponent { item.style.left = `${item_rect.x - list_rect.x}px`; item.style.top = `${item_rect.y - list_rect.y}px`; + item.style.width = `${item_rect.width}px`; + item.style.height = `${item_rect.height}px`; } this._target.classList.add(ZBX_STYLE_SORTABLE_DRAGGING); @@ -268,6 +270,9 @@ class CSortable extends CBaseComponent { this._drag_item = drag_item; this._drag_item.style.left = `${drag_item_rect.x - target_rect.x}px`; this._drag_item.style.top = `${drag_item_rect.y - target_rect.y}px`; + this._drag_item.style.width = `${drag_item_rect.width}px`; + this._drag_item.style.height = `${drag_item_rect.height}px`; + this._target.appendChild(this._drag_item); // Hide the actual dragging item. @@ -355,6 +360,8 @@ class CSortable extends CBaseComponent { drag_item.classList.remove(ZBX_STYLE_SORTABLE_DRAGGING); drag_item.style.left = ''; drag_item.style.top = ''; + drag_item.style.width = ''; + drag_item.style.height = ''; this._target.classList.remove(ZBX_STYLE_SORTABLE_DRAGGING); this._list.style.width = ''; @@ -363,6 +370,8 @@ class CSortable extends CBaseComponent { for (const item of items) { item.style.left = ''; item.style.top = ''; + item.style.width = ''; + item.style.height = ''; } // Re-focus the dragged item. diff --git a/ui/js/class.tabfilter.js b/ui/js/class.tabfilter.js index a0faf3c281a..4ee58041b90 100644 --- a/ui/js/class.tabfilter.js +++ b/ui/js/class.tabfilter.js @@ -56,7 +56,7 @@ class CTabFilter extends CBaseComponent { options.data[options.selected].expanded = true; } - for (const template of this._target.querySelectorAll('[type="text/x-jquery-tmpl"][data-template]')) { + for (const template of this._target.querySelectorAll('[data-template]')) { this._templates[template.getAttribute('data-template')] = template; } diff --git a/ui/js/class.widget.inaccessible.js b/ui/js/class.widget.inaccessible.js new file mode 100644 index 00000000000..411b19bba4e --- /dev/null +++ b/ui/js/class.widget.inaccessible.js @@ -0,0 +1,74 @@ +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +class CWidgetInaccessible extends CWidget { + + _doStart() { + super._doStart(); + + this._updateButtons(); + + this._content_body.innerHTML = `<div>${t('No permissions to referred object or it does not exist!')}</div>`; + } + + _updateButtons() { + for (const button of this._content_header.querySelectorAll('button')) { + button.hidden = !button.classList.contains('js-widget-action') || !this.isEditMode(); + } + } + + setEditMode() { + super.setEditMode(); + + this._updateButtons(); + } + + _promiseUpdate() { + return Promise.resolve(); + } + + getActionsContextMenu({can_paste_widget}) { + const menu = super.getActionsContextMenu({can_paste_widget}); + + for (const section of menu) { + switch (section.label) { + case t('Actions'): + for (const item of section.items) { + if (item.label === t('Copy')) { + item.disabled = true; + } + } + break; + + case t('Refresh interval'): + for (const item of section.items) { + item.disabled = true; + } + break; + } + } + + return menu; + } + + _hasPadding() { + return true; + } +} diff --git a/ui/js/widgets/class.widget.iterator.js b/ui/js/class.widget.iterator.js index 12080a2e6fb..d1c8db7131b 100644 --- a/ui/js/widgets/class.widget.iterator.js +++ b/ui/js/class.widget.iterator.js @@ -318,7 +318,6 @@ class CWidgetIterator extends CWidget { name: data.name, view_mode: this._view_mode, fields: data.fields, - configuration: data.configuration, defaults: data.defaults, widgetid: data.widgetid, is_new: false, diff --git a/ui/js/widgets/class.widget.js b/ui/js/class.widget.js index 2b5456d2f41..2584a6c23cc 100644 --- a/ui/js/widgets/class.widget.js +++ b/ui/js/class.widget.js @@ -38,12 +38,19 @@ const WIDGET_EVENT_DELETE = 'widget-delete'; class CWidget extends CBaseComponent { + static hasReferenceField() { + return false; + } + + static getForeignReferenceFields() { + return []; + } + constructor({ type, name, view_mode, fields, - configuration, defaults, widgetid = null, pos = null, @@ -59,7 +66,6 @@ class CWidget extends CBaseComponent { can_edit_dashboards, time_period, dynamic_hostid, - scope_id, unique_id }) { super(document.createElement('div')); @@ -68,7 +74,6 @@ class CWidget extends CBaseComponent { this._name = name; this._view_mode = view_mode; this._fields = fields; - this._configuration = configuration; this._defaults = defaults; this._widgetid = widgetid; this._pos = pos; @@ -92,7 +97,6 @@ class CWidget extends CBaseComponent { this._can_edit_dashboards = can_edit_dashboards; this._time_period = time_period; this._dynamic_hostid = dynamic_hostid; - this._scope_id = scope_id; this._unique_id = unique_id; this._init(); @@ -342,15 +346,17 @@ class CWidget extends CBaseComponent { this._fields = fields; } - _setConfiguration(configuration) { - this._configuration = configuration; + _hasPadding() { + return this._view_mode != ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER; + } + _updatePadding() { if (this._state !== WIDGET_STATE_INITIAL) { - this._content_body.classList.toggle('no-padding', !this._configuration.padding); + this._content_body.classList.toggle('no-padding', !this._hasPadding()); } } - updateProperties({name, view_mode, fields, configuration}) { + updateProperties({name, view_mode, fields}) { if (name !== undefined) { this._setName(name); } @@ -363,9 +369,7 @@ class CWidget extends CBaseComponent { this._setFields(fields); } - if (configuration !== undefined) { - this._setConfiguration(configuration); - } + this._updatePadding(); this._show_preloader_asap = true; @@ -409,7 +413,6 @@ class CWidget extends CBaseComponent { name: this._name, view_mode: this._view_mode, fields: this._fields, - configuration: this._configuration, pos: is_single_copy ? { width: this._pos.width, @@ -435,7 +438,7 @@ class CWidget extends CBaseComponent { type: this._type, name: this._name, view_mode: this._view_mode, - fields: Object.keys(this._fields).length > 0 ? JSON.stringify(this._fields) : undefined + fields: Object.keys(this._fields).length > 0 ? this._fields : undefined }; } @@ -630,7 +633,7 @@ class CWidget extends CBaseComponent { dashboardid: this._dashboard.dashboardid ?? undefined, widgetid: this._widgetid ?? undefined, name: this._name !== '' ? this._name : undefined, - fields: Object.keys(this._fields).length > 0 ? JSON.stringify(this._fields) : undefined, + fields: Object.keys(this._fields).length > 0 ? this._fields : undefined, view_mode: this._view_mode, edit_mode: this._is_edit_mode ? 1 : 0, dynamic_hostid: this._dashboard.templateid !== null || this.supportsDynamicHosts() @@ -872,7 +875,7 @@ class CWidget extends CBaseComponent { this._button_edit = document.createElement('button'); this._button_edit.type = 'button'; this._button_edit.title = t('Edit') - this._button_edit.classList.add('btn-widget-edit'); + this._button_edit.classList.add('btn-widget-edit', 'js-widget-edit'); const li = document.createElement('li'); @@ -885,7 +888,7 @@ class CWidget extends CBaseComponent { this._button_actions.title = t('Actions'); this._button_actions.setAttribute('aria-expanded', 'false'); this._button_actions.setAttribute('aria-haspopup', 'true'); - this._button_actions.classList.add('btn-widget-action'); + this._button_actions.classList.add('btn-widget-action', 'js-widget-action'); const li = document.createElement('li'); @@ -898,7 +901,8 @@ class CWidget extends CBaseComponent { this._content_body = document.createElement('div'); this._content_body.classList.add(this._css_classes.content); - this._content_body.classList.toggle('no-padding', !this._configuration.padding); + this._content_body.classList.add(`dashboard-widget-${this._type}`); + this._content_body.classList.toggle('no-padding', !this._hasPadding()); this._container.appendChild(this._content_body); diff --git a/ui/js/widgets/class.widget.paste-placeholder.js b/ui/js/class.widget.paste-placeholder.js index 88db8992684..88db8992684 100644 --- a/ui/js/widgets/class.widget.paste-placeholder.js +++ b/ui/js/class.widget.paste-placeholder.js diff --git a/ui/js/common.js b/ui/js/common.js index cd696caa9e4..bad37ea49a6 100644 --- a/ui/js/common.js +++ b/ui/js/common.js @@ -361,7 +361,16 @@ function PopUp(action, parameters, { .then(function(resp) { if ('error' in resp) { overlay.setProperties({ - content: makeMessageBox('bad', resp.error.messages, resp.error.title, false) + title: resp.header !== undefined ? resp.header : '', + content: makeMessageBox('bad', resp.error.messages, resp.error.title, false), + buttons: [ + { + 'title': t('Cancel'), + 'class': 'btn-alt js-cancel', + 'cancel': true, + 'action': function() {} + } + ] }); } else { @@ -401,6 +410,26 @@ function PopUp(action, parameters, { overlay.recoverFocus(); overlay.containFocus(); + }) + .fail((resp) => { + const error = resp.responseJSON !== undefined && resp.responseJSON.error !== undefined + ? resp.responseJSON.error + : {title: t('Unexpected server error.')}; + + overlay.setProperties({ + content: makeMessageBox('bad', error.messages, error.title, false), + buttons: [ + { + 'title': t('Cancel'), + 'class': 'btn-alt js-cancel', + 'cancel': true, + 'action': function() {} + } + ] + }); + + overlay.recoverFocus(); + overlay.containFocus(); }); addToOverlaysStack(overlay); @@ -522,15 +551,18 @@ function closeDialogHandler(event) { * @return {object|undefined|null} Overlay object, if found. */ function removeFromOverlaysStack(dialogueid, return_focus) { - var overlay = null; - if (return_focus !== false) { return_focus = true; } - overlay = overlays_stack.removeById(dialogueid); + const overlay = overlays_stack.removeById(dialogueid); + if (overlay && return_focus) { - jQuery(overlay.element).focus(); + if (overlay.element !== undefined) { + const element = overlay.element instanceof jQuery ? overlay.element[0] : overlay.element; + + element.focus({preventScroll: true}); + } } // Remove event listener. diff --git a/ui/js/main.js b/ui/js/main.js index 44ca0377e77..ec143333d4b 100644 --- a/ui/js/main.js +++ b/ui/js/main.js @@ -655,10 +655,10 @@ var hintBox = { }; /** - * Add object to the list of favourites. + * Add object to the list of favorites. */ function add2favorites(object, objectid) { - sendAjaxData('zabbix.php?action=favourite.create', { + sendAjaxData('zabbix.php?action=favorite.create', { data: { object: object, objectid: objectid @@ -667,10 +667,10 @@ function add2favorites(object, objectid) { } /** - * Remove object from the list of favourites. Remove all favourites if objectid==0. + * Remove object from the list of favorites. Remove all favorites if objectid==0. */ function rm4favorites(object, objectid) { - sendAjaxData('zabbix.php?action=favourite.delete', { + sendAjaxData('zabbix.php?action=favorite.delete', { data: { object: object, objectid: objectid @@ -684,7 +684,7 @@ function rm4favorites(object, objectid) { * @param {string} idx User profile index * @param {string} value Value * @param {object} idx2 An array of IDs - * @param {integer} profile_type Profile type + * @param {int} profile_type Profile type */ function updateUserProfile(idx, value, idx2, profile_type = PROFILE_TYPE_INT) { const value_fields = { @@ -701,25 +701,23 @@ function updateUserProfile(idx, value, idx2, profile_type = PROFILE_TYPE_INT) { }); } -function changeWidgetState(obj, widgetId, idx) { - var widgetObj = jQuery('#' + widgetId + '_widget'), - css = switchElementClass(obj, 'btn-widget-collapse', 'btn-widget-expand'), - state = 0; +/** + * Section collapse toggle. + * + * @param {string} id + * @param {string|null} profile_idx If not null, stores state in profile. + */ +function toggleSection(id, profile_idx) { + const section = document.getElementById(id); + const toggle = section.querySelector('.section-toggle'); - if (css === 'btn-widget-expand') { - jQuery('.body', widgetObj).slideUp(50); - jQuery('.dashboard-widget-foot', widgetObj).slideUp(50); - } - else { - jQuery('.body', widgetObj).slideDown(50); - jQuery('.dashboard-widget-foot', widgetObj).slideDown(50); + let is_collapsed = section.classList.contains('section-collapsed'); - state = 1; - } + section.classList.toggle('section-collapsed', !is_collapsed); + toggle.setAttribute('title', is_collapsed ? t('S_COLLAPSE') : t('S_EXPAND')); - obj.title = (state == 1) ? t('S_COLLAPSE') : t('S_EXPAND'); - if (idx !== '' && typeof idx !== 'undefined') { - updateUserProfile(idx, state, []); + if (profile_idx !== '') { + updateUserProfile(profile_idx, is_collapsed ? '1' : '0', []); } } diff --git a/ui/js/menupopup.js b/ui/js/menupopup.js index 6fd90b81f9a..50da50c3b7e 100644 --- a/ui/js/menupopup.js +++ b/ui/js/menupopup.js @@ -611,7 +611,8 @@ function getMenuPopupDashboard(options, trigger_element) { const url_clone = new Curl('zabbix.php', false); url_clone.setArgument('action', 'dashboard.view'); - url_clone.setArgument('source_dashboardid', options.dashboardid); + url_clone.setArgument('dashboardid', options.dashboardid); + url_clone.setArgument('clone', '1'); const url_delete = new Curl('zabbix.php', false); url_delete.setArgument('action', 'dashboard.delete'); diff --git a/ui/jsLoader.php b/ui/jsLoader.php index 2adaa6a783b..49d5c21e422 100644 --- a/ui/jsLoader.php +++ b/ui/jsLoader.php @@ -36,20 +36,10 @@ $available_js = [ 'class.dashboard.js' => '', 'class.dashboard.page.js' => '', 'class.dashboard.widget.placeholder.js' => '', - 'class.widget.js' => 'widgets/', - 'class.widget.iterator.js' => 'widgets/', - 'class.widget.clock.js' => 'widgets/', - 'class.widget.geomap.js' => 'widgets/', - 'class.widget.graph.js' => 'widgets/', - 'class.widget.graph-prototype.js' => 'widgets/', - 'class.widget.item.js' => 'widgets/', - 'class.widget.map.js' => 'widgets/', - 'class.widget.navtree.js' => 'widgets/', - 'class.widget.paste-placeholder.js' => 'widgets/', - 'class.widget.problems.js' => 'widgets/', - 'class.widget.problemsbysv.js' => 'widgets/', - 'class.widget.svggraph.js' => 'widgets/', - 'class.widget.trigerover.js' => 'widgets/', + 'class.widget.js' => '', + 'class.widget.inaccessible.js' => '', + 'class.widget.iterator.js' => '', + 'class.widget.paste-placeholder.js' => '', 'hostinterfacemanager.js' => '', 'hostmacrosmanager.js' => '', 'menupopup.js' => '', @@ -136,6 +126,8 @@ $translate_strings = [ 'Actions' => _('Actions'), 'Cannot add dashboard page: maximum number of %1$d dashboard pages has been added.' => _('Cannot add dashboard page: maximum number of %1$d dashboard pages has been added.'), 'Cannot add widget: not enough free space on the dashboard.' => _('Cannot add widget: not enough free space on the dashboard.'), + 'Cannot add widget: no widgets available.' => _('Cannot add widget: no widgets available.'), + 'Cannot paste inaccessible widget.' => _('Cannot paste inaccessible widget.'), 'Copy' => _('Copy'), 'Delete' => _('Delete'), 'Failed to paste dashboard page.' => _('Failed to paste dashboard page.'), @@ -143,12 +135,17 @@ $translate_strings = [ 'Failed to update dashboard page properties.' => _('Failed to update dashboard page properties.'), 'Failed to update dashboard properties.' => _('Failed to update dashboard properties.'), 'Failed to update widget properties.' => _('Failed to update widget properties.'), + 'Inaccessible widgets were not copied.' => _('Inaccessible widgets were not copied.'), + 'Inaccessible widgets were not pasted.' => _('Inaccessible widgets were not pasted.'), 'Page %1$d' => _('Page %1$d'), 'Paste widget' => _('Paste widget'), 'Properties' => _('Properties'), 'Start slideshow' => _('Start slideshow'), 'Stop slideshow' => _('Stop slideshow') ], + 'class.dashboard.page.js' => [ + 'Inaccessible widget' => _('Inaccessible widget') + ], 'class.dashboard.widget.placeholder.js' => [ 'Add a new widget' => _('Add a new widget'), 'Click and drag to desired size.' => _('Click and drag to desired size.'), @@ -172,26 +169,11 @@ $translate_strings = [ 'Paste' => _s('Paste'), 'Refresh interval' => _s('Refresh interval') ], - 'class.widget.geomap.js' => [ - 'Actions' => _('Actions'), - 'Set this view as default' => _('Set this view as default'), - 'Reset to initial view' => _('Reset to initial view'), - 'No problems' => _('No problems'), - 'Not classified' => _('Not classified'), - 'Information' => _('Information'), - 'Warning' => _('Warning'), - 'Average' => _('Average'), - 'High' => _('High'), - 'Disaster' => _('Disaster'), - 'Host' => _('Host'), - 'D' => _x('D', 'abbreviation of severity level'), - 'H' => _x('H', 'abbreviation of severity level'), - 'A' => _x('A', 'abbreviation of severity level'), - 'W' => _x('W', 'abbreviation of severity level'), - 'I' => _x('I', 'abbreviation of severity level'), - 'N' => _x('N', 'abbreviation of severity level'), - 'Navigate to default view' => _('Navigate to default view'), - 'Navigate to initial view' => _('Navigate to initial view') + 'class.widget.inaccessible.js' => [ + 'Actions' => _s('Actions'), + 'Copy' => _s('Copy'), + 'Inaccessible widget' => _('Inaccessible widget'), + 'Refresh interval' => _s('Refresh interval') ], 'class.widget.iterator.js' => [ 'Next page' => _s('Next page'), @@ -199,24 +181,6 @@ $translate_strings = [ 'Widget is too small for the specified number of columns and rows.' => _s('Widget is too small for the specified number of columns and rows.') ], - 'class.widget.graph.js' => [ - 'Actions' => _s('Actions'), - 'Download image' => _s('Download image') - ], - 'class.widget.navtree.js' => [ - 'Add' => _s('Add'), - 'Add child element' => _s('Add child element'), - 'Add multiple maps' => _s('Add multiple maps'), - 'Apply' => _s('Apply'), - 'Cancel' => _s('Cancel'), - 'Edit' => _s('Edit'), - 'Edit tree element' => _s('Edit tree element'), - 'Remove' => _s('Remove') - ], - 'class.widget.svggraph.js' => [ - 'Actions' => _s('Actions'), - 'Download image' => _s('Download image') - ], 'functions.js' => [ 'Cancel' => _('Cancel'), 'S_CLOSE' => _('Close'), @@ -420,7 +384,8 @@ $translate_strings = [ ], 'common.js' => [ 'Cancel' => _('Cancel'), - 'Ok' => _('Ok') + 'Ok' => _('Ok'), + 'Unexpected server error.' => _('Unexpected server error.') ], 'component.z-select.js' => [ 'All' => _('All') diff --git a/ui/report2.php b/ui/report2.php index 808fae031df..032bc9c9cef 100644 --- a/ui/report2.php +++ b/ui/report2.php @@ -156,7 +156,7 @@ $triggerData = isset($_REQUEST['triggerid']) ]) : null; -$reportWidget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Availability report')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::REPORT2)); @@ -167,7 +167,7 @@ if ($triggerData) { $triggerData['hostid'] = $host['hostid']; $triggerData['hostname'] = $host['name']; - $reportWidget->setControls((new CTag('nav', true, + $html_page->setControls((new CTag('nav', true, (new CList()) ->addItem(new CLink($triggerData['hostname'], (new CUrl('report2.php')) ->setArgument('page', CPagerHelper::loadPage('report2.php', null)) @@ -180,7 +180,7 @@ if ($triggerData) { $table = (new CTableInfo()) ->addRow(new CImg('chart4.php?triggerid='.$_REQUEST['triggerid'])); - $reportWidget->addItem(BR()) + $html_page->addItem(BR()) ->addItem($table) ->show(); } @@ -195,7 +195,7 @@ else { ->addOption(new CSelectOption(AVAILABILITY_REPORT_BY_HOST, _('By host'))) ->addOption(new CSelectOption(AVAILABILITY_REPORT_BY_TEMPLATE, _('By trigger template'))); - $reportWidget->setControls((new CForm('get')) + $html_page->setControls((new CForm('get')) ->cleanItems() ->setAttribute('aria-label', _('Main filter')) ->addItem((new CList()) @@ -494,7 +494,7 @@ else { } unset($trigger); - $reportWidget->addItem( + $html_page->addItem( (new CFilter()) ->setResetUrl(new CUrl('report2.php')) ->setProfile($data['filter']['timeline']['profileIdx']) @@ -563,7 +563,7 @@ else { ); zbx_add_post_js('timeControl.processObjects();'); - $reportWidget + $html_page ->addItem([$triggerTable, $paging]) ->show(); } diff --git a/ui/report4.php b/ui/report4.php index 9fa0c9f2cd6..281cb753a75 100644 --- a/ui/report4.php +++ b/ui/report4.php @@ -61,7 +61,7 @@ CArrayHelper::sort($db_media_types, ['name']); $media_types = array_column($db_media_types, 'name', 'mediatypeid'); -$widget = (new CWidget()) +$html_page = (new CHtmlPage()) ->setTitle(_('Notifications')) ->setDocUrl(CDocHelper::getUrl(CDocHelper::REPORT4)); @@ -121,7 +121,7 @@ if ($media_types) { ]); } - $widget->setControls((new CForm('get')) + $html_page->setControls((new CForm('get')) ->cleanItems() ->setAttribute('aria-label', _('Main filter')) ->addItem($controls) @@ -258,7 +258,7 @@ else { $table = new CTableInfo(); } -$widget +$html_page ->addItem($table) ->show(); diff --git a/ui/setup.php b/ui/setup.php index 2174a12a028..6a3dc3a8209 100644 --- a/ui/setup.php +++ b/ui/setup.php @@ -160,8 +160,11 @@ DBclose(); $setup_wizard = new CSetupWizard(); // page title -(new CPageHeader(_('Installation'), substr($default_lang, 0, strpos($default_lang, '_')))) - ->addCssFile('assets/styles/'.CHtml::encode($default_theme).'.css') +$page_header = (new CHtmlPageHeader(_('Installation'), substr($default_lang, 0, strpos($default_lang, '_')))); + +$page_header + ->setTheme($default_theme) + ->addCssFile('assets/styles/'.$page_header->getTheme().'.css') ->addJsFile((new CUrl('js/browsers.js'))->getUrl()) ->addJsFile((new CUrl('jsLoader.php')) ->setArgument('ver', ZABBIX_VERSION) @@ -174,7 +177,7 @@ $setup_wizard = new CSetupWizard(); ->setArgument('files', ['setup.js']) ->getUrl() ) - ->display(); + ->show(); /* * Displaying diff --git a/ui/tests/include/web/elements/CWidgetElement.php b/ui/tests/include/web/elements/CWidgetElement.php index 5d4b1348377..beb333f7861 100644 --- a/ui/tests/include/web/elements/CWidgetElement.php +++ b/ui/tests/include/web/elements/CWidgetElement.php @@ -33,7 +33,7 @@ class CWidgetElement extends CElement { * @return integer */ public function getRefreshInterval() { - $this->query('xpath:.//button[@class="btn-widget-action"]')->waitUntilPresent()->one()->click(true); + $this->query('xpath:.//button[contains(@class, "btn-widget-action")]')->waitUntilPresent()->one()->click(true); $selected = $this->query('xpath://ul[@role="menu"]//a[contains(@aria-label, "selected")]')->one(); $aria_label = explode(', ', $selected->getAttribute('aria-label'), 3); @@ -66,7 +66,7 @@ class CWidgetElement extends CElement { * @return boolean */ public function isEditable() { - return $this->query('xpath:.//button[@class="btn-widget-edit"]')->one()->isPresent(); + return $this->query('xpath:.//button[contains(@class, "btn-widget-edit")]')->one()->isPresent(); } /** @@ -77,7 +77,7 @@ class CWidgetElement extends CElement { public function edit() { // Edit can sometimes fail so we have to retry this operation. for ($i = 0; $i < 4; $i++) { - $this->query('xpath:.//button[@class="btn-widget-edit"]')->waitUntilPresent()->one()->click(true); + $this->query('xpath:.//button[contains(@class, "btn-widget-edit")]')->waitUntilPresent()->one()->click(true); try { return $this->query('xpath://div[@data-dialogueid="widget_properties"]//form')->waitUntilVisible()->asForm()->one(); diff --git a/ui/tests/selenium/dashboard/testDashboardItemValueWidget.php b/ui/tests/selenium/dashboard/testDashboardItemValueWidget.php index 025c8314dcb..3a987bf1516 100644 --- a/ui/tests/selenium/dashboard/testDashboardItemValueWidget.php +++ b/ui/tests/selenium/dashboard/testDashboardItemValueWidget.php @@ -1350,8 +1350,9 @@ class testDashboardItemValueWidget extends CWebTest { CDataHelper::addItemData(42244, $index, time() + $index); $this->page->refresh()->waitUntilReady(); $rgb = implode(', ', sscanf($threshold['color'], "%02x%02x%02x")); - $this->assertEquals('rgba('.$rgb.', 1)', $dashboard->getWidget($data['fields']['Name'])->getContent() - ->query('class:dashboard-widget-item')->one()->getCSSValue('background-color') + + $this->assertEquals('rgba('.$rgb.', 1)', $dashboard->getWidget($data['fields']['Name']) + ->query('xpath:.//div[contains(@class, "dashboard-widget-item")]/div')->one()->getCSSValue('background-color') ); $index++; } diff --git a/ui/tests/selenium/dashboard/testPageDashboardWidgets.php b/ui/tests/selenium/dashboard/testPageDashboardWidgets.php index 8e240aa1c7f..2862cc86117 100644 --- a/ui/tests/selenium/dashboard/testPageDashboardWidgets.php +++ b/ui/tests/selenium/dashboard/testPageDashboardWidgets.php @@ -105,21 +105,22 @@ class testPageDashboardWidgets extends CWebTest { $default_form->fill(['Type' => 'Clock']); $default_form->waitUntilReloaded(); $overlay->close(); - // Check that widget type is remembered as Clock. - $this->checkLastSelectedWidgetType('Clock', 'clock'); + // Check that widget type is not remembered without submitting the form. + $this->checkLastSelectedWidgetType(); // Save edit widget form without changing widget type. $sys_info_form = $dashboard->getWidget('System information')->edit(); $this->assertEquals('System information', $sys_info_form->getField('Type')->getValue()); $sys_info_form->submit(); $this->page->waitUntilReady(); - // Check that widget type is still remembered as Clock. - $this->checkLastSelectedWidgetType('Clock', 'clock'); + // Check that widget type is still unchanged. + $this->checkLastSelectedWidgetType(); // Opening edit widget form and change widget type. $change_form = $dashboard->getWidget('System information')->edit(); $change_form->fill(['Type' => 'Data overview']); - $overlay->close(); + $change_form->waitUntilReloaded(); + $change_form->submit(); // Check that widget type inherited from previous widget. $this->checkLastSelectedWidgetType('Data overview', 'dataover'); @@ -186,7 +187,7 @@ class testPageDashboardWidgets extends CWebTest { // Change dashboard owner. $owner = $configuration->getField('Owner'); $owner->clear(); - $owner->select('test-user'); + $owner->fill('test-user'); // Change dashboard name. $configuration->getField('Name')->clear()->type('Dashboard create test'); $configuration->submit(); diff --git a/ui/tests/selenium/data/sources/CopyWidgetsDashboards.php b/ui/tests/selenium/data/sources/CopyWidgetsDashboards.php index 8d7d016f864..4aa259216e7 100644 --- a/ui/tests/selenium/data/sources/CopyWidgetsDashboards.php +++ b/ui/tests/selenium/data/sources/CopyWidgetsDashboards.php @@ -170,7 +170,7 @@ class CopyWidgetsDashboards { ] ], [ - 'name' => 'Test copy Favourite graphs', + 'name' => 'Test copy Favorite graphs', 'type' => 'favgraphs', 'x' => 20, 'y' => 7, @@ -186,7 +186,7 @@ class CopyWidgetsDashboards { ] ], [ - 'name' => 'Test copy Favourite maps', + 'name' => 'Test copy Favorite maps', 'type' => 'favmaps', 'x' => 14, 'y' => 10, diff --git a/ui/tests/selenium/data/sources/TopHostsWidget.php b/ui/tests/selenium/data/sources/TopHostsWidget.php index 701ae100438..6d6fa221121 100644 --- a/ui/tests/selenium/data/sources/TopHostsWidget.php +++ b/ui/tests/selenium/data/sources/TopHostsWidget.php @@ -129,7 +129,7 @@ class TopHostsWidget { [ 'type' => 0, 'name' => 'column', - 'value' => 0 + 'value' => 1 ], [ 'type' => 1, diff --git a/ui/tests/selenium/modules/module_number_1/Module.php b/ui/tests/selenium/modules/module_number_1/Module.php index 29ac7341018..7f2db59f59f 100644 --- a/ui/tests/selenium/modules/module_number_1/Module.php +++ b/ui/tests/selenium/modules/module_number_1/Module.php @@ -2,7 +2,7 @@ namespace Modules\Example_A; -use Core\CModule, +use Zabbix\Core\CModule, APP, CMenu; diff --git a/ui/tests/selenium/modules/module_number_1/manifest.json b/ui/tests/selenium/modules/module_number_1/manifest.json index a5a5d681f8a..24e4b4bd020 100644 --- a/ui/tests/selenium/modules/module_number_1/manifest.json +++ b/ui/tests/selenium/modules/module_number_1/manifest.json @@ -1,5 +1,5 @@ { - "manifest_version": 1, + "manifest_version": 2, "id": "1st module id", "name": "1st Module name", "author": "1st Module author", diff --git a/ui/tests/selenium/modules/module_number_1/views/first.module.php b/ui/tests/selenium/modules/module_number_1/views/first.module.php index 241c411bb00..253dfb54ba9 100644 --- a/ui/tests/selenium/modules/module_number_1/views/first.module.php +++ b/ui/tests/selenium/modules/module_number_1/views/first.module.php @@ -1,6 +1,6 @@ <?php -(new CWidget()) +(new CHtmlPage()) ->addItem( (new CTag('h1', true, 'If You see this message - 1st module is working')) )->show(); diff --git a/ui/tests/selenium/modules/module_number_2/Module.php b/ui/tests/selenium/modules/module_number_2/Module.php index 749400799c7..4bf34ee290d 100644 --- a/ui/tests/selenium/modules/module_number_2/Module.php +++ b/ui/tests/selenium/modules/module_number_2/Module.php @@ -2,7 +2,7 @@ namespace Modules\Example_B; -use Core\CModule, +use Zabbix\Core\CModule, APP, CMenu; diff --git a/ui/tests/selenium/modules/module_number_2/manifest.json b/ui/tests/selenium/modules/module_number_2/manifest.json index 4039b0c3d18..fb444f702e0 100644 --- a/ui/tests/selenium/modules/module_number_2/manifest.json +++ b/ui/tests/selenium/modules/module_number_2/manifest.json @@ -1,5 +1,5 @@ { - "manifest_version": 0.99, + "manifest_version": 2.0, "id": "two", "name": "2nd Module name !@#$%^&*()_+", "author": "2nd Module author !@#$%^&*()_+", diff --git a/ui/tests/selenium/modules/module_number_2/views/second.module.php b/ui/tests/selenium/modules/module_number_2/views/second.module.php index 39b7f7acfb2..b16e7f3a6ef 100644 --- a/ui/tests/selenium/modules/module_number_2/views/second.module.php +++ b/ui/tests/selenium/modules/module_number_2/views/second.module.php @@ -1,6 +1,6 @@ <?php -(new CWidget()) +(new CHtmlPage()) ->addItem( (new CTag('h1', true, '2nd module is also working')) )->show(); diff --git a/ui/tests/selenium/modules/module_number_3/Module.php b/ui/tests/selenium/modules/module_number_3/Module.php index ab32c67e4f5..62435cd5515 100644 --- a/ui/tests/selenium/modules/module_number_3/Module.php +++ b/ui/tests/selenium/modules/module_number_3/Module.php @@ -2,7 +2,7 @@ namespace Modules\Example_C; -use Core\CModule, +use Zabbix\Core\CModule, APP, CMenu; diff --git a/ui/tests/selenium/modules/module_number_3/manifest.json b/ui/tests/selenium/modules/module_number_3/manifest.json index 3266063c0b3..75117cee725 100644 --- a/ui/tests/selenium/modules/module_number_3/manifest.json +++ b/ui/tests/selenium/modules/module_number_3/manifest.json @@ -1,5 +1,5 @@ { - "manifest_version": 1.01, + "manifest_version": 2.01, "id": "3", "name": "This module should not be loaded", "author": "module author", diff --git a/ui/tests/selenium/modules/module_number_3/views/third.module.php b/ui/tests/selenium/modules/module_number_3/views/third.module.php index b3a60b195d0..085a1ee086e 100644 --- a/ui/tests/selenium/modules/module_number_3/views/third.module.php +++ b/ui/tests/selenium/modules/module_number_3/views/third.module.php @@ -1,6 +1,6 @@ <?php -(new CWidget()) +(new CHtmlPage()) ->addItem( (new CTag('h1', true, 'You should not see this message')) )->show(); diff --git a/ui/tests/selenium/modules/module_number_4/Module.php b/ui/tests/selenium/modules/module_number_4/Module.php index dcd0bb13a90..52c472c3114 100644 --- a/ui/tests/selenium/modules/module_number_4/Module.php +++ b/ui/tests/selenium/modules/module_number_4/Module.php @@ -2,7 +2,7 @@ namespace Modules\Example_A; -use Core\CModule, +use Zabbix\Core\CModule, APP, CMenu; diff --git a/ui/tests/selenium/modules/module_number_4/manifest.json b/ui/tests/selenium/modules/module_number_4/manifest.json index e5a3450b197..249a5fb208b 100644 --- a/ui/tests/selenium/modules/module_number_4/manifest.json +++ b/ui/tests/selenium/modules/module_number_4/manifest.json @@ -1,5 +1,5 @@ { - "manifest_version": 0.01, + "manifest_version": 2.00, "id": "4", "name": "4th Module", "author": "", diff --git a/ui/tests/selenium/modules/module_number_4/views/forth.module.php b/ui/tests/selenium/modules/module_number_4/views/forth.module.php index bd1000cc1b6..f0ba934eaa8 100644 --- a/ui/tests/selenium/modules/module_number_4/views/forth.module.php +++ b/ui/tests/selenium/modules/module_number_4/views/forth.module.php @@ -1,6 +1,6 @@ <?php -(new CWidget()) +(new CHtmlPage()) ->addItem( (new CTag('h1', true, '4th module - cannot be enabled together with 1st module')) )->show(); diff --git a/ui/tests/selenium/modules/module_number_5/Module.php b/ui/tests/selenium/modules/module_number_5/Module.php index 0f93a364c4e..f9120308bb5 100644 --- a/ui/tests/selenium/modules/module_number_5/Module.php +++ b/ui/tests/selenium/modules/module_number_5/Module.php @@ -2,7 +2,7 @@ namespace Modules\Example_E; -use Core\CModule, +use Zabbix\Core\CModule, APP, CMenu; diff --git a/ui/tests/selenium/modules/module_number_5/manifest.json b/ui/tests/selenium/modules/module_number_5/manifest.json index 7f1802f3548..442fbabae04 100644 --- a/ui/tests/selenium/modules/module_number_5/manifest.json +++ b/ui/tests/selenium/modules/module_number_5/manifest.json @@ -1,5 +1,5 @@ { - "manifest_version": 0.01, + "manifest_version": 2, "id": "5", "name": "5th Module", "author": "", diff --git a/ui/tests/selenium/modules/module_number_5/views/fifth.module.php b/ui/tests/selenium/modules/module_number_5/views/fifth.module.php index 5f702c5a5a5..5cd1eee6bea 100644 --- a/ui/tests/selenium/modules/module_number_5/views/fifth.module.php +++ b/ui/tests/selenium/modules/module_number_5/views/fifth.module.php @@ -1,6 +1,6 @@ <?php -(new CWidget()) +(new CHtmlPage()) ->addItem( (new CTag('h1', true, 'Если ты это читаешь то 5ый модуль работает')) )->show(); diff --git a/ui/tests/selenium/modules/module_number_6/Module.php b/ui/tests/selenium/modules/module_number_6/Module.php index 4e19b0c8107..d5d5837f38e 100644 --- a/ui/tests/selenium/modules/module_number_6/Module.php +++ b/ui/tests/selenium/modules/module_number_6/Module.php @@ -2,7 +2,7 @@ namespace Modules\Example_F; -use Core\CModule, +use Zabbix\Core\CModule, APP, CMenu; diff --git a/ui/tests/selenium/modules/module_number_6/manifest.json b/ui/tests/selenium/modules/module_number_6/manifest.json index d0a79518577..474d69d8321 100644 --- a/ui/tests/selenium/modules/module_number_6/manifest.json +++ b/ui/tests/selenium/modules/module_number_6/manifest.json @@ -1,5 +1,5 @@ { - "manifest_version": 0.01, + "manifest_version": 2.000, "id": "6", "name": "шестой модуль", "author": "Работник Заббикса", diff --git a/ui/tests/selenium/problems/testFormUpdateProblem.php b/ui/tests/selenium/problems/testFormUpdateProblem.php index f7f283832e7..838536384ce 100644 --- a/ui/tests/selenium/problems/testFormUpdateProblem.php +++ b/ui/tests/selenium/problems/testFormUpdateProblem.php @@ -936,12 +936,12 @@ class testFormUpdateProblem extends CWebTest { // Check Event details page. $row->getColumn('Time')->query('tag:a')->waitUntilClickable()->one()->click(); $this->page->assertHeader('Event details'); - $this->checkHistoryTable($this->query("xpath://div[@id=\"hat_eventactions_widget\"]//table")->asTable()->one(), + $this->checkHistoryTable($this->query("xpath://section[@id=\"hat_eventactions\"]//table")->asTable()->one(), 'User/Recipient', 'Action' ); // Check Actions hint in Event list. - $event_list_table = $this->query('xpath://div[@id="hat_eventlist_widget"]//table')->asTable()->one(); + $event_list_table = $this->query('xpath://section[@id="hat_eventlist"]//table')->asTable()->one(); $event_list_table->getRow(0)->getColumn('Actions')->query($unsuppress_button)->waitUntilClickable()->one()->click(); $hint->invalidate(); $this->checkHistoryTable($hint->query('class:list-table')->asTable()->one(), 'User', 'Action'); diff --git a/ui/tests/selenium/roles/testFormUserRoles.php b/ui/tests/selenium/roles/testFormUserRoles.php index 3483986dfff..059407eaf8e 100644 --- a/ui/tests/selenium/roles/testFormUserRoles.php +++ b/ui/tests/selenium/roles/testFormUserRoles.php @@ -1345,12 +1345,19 @@ class testFormUserRoles extends CWebTest { */ public function testFormUserRoles_Modules() { $this->page->login(); + foreach ([true, false] as $enable_modules) { $modules = ['4th Module', '5th Module']; $this->page->open('zabbix.php?action=userrole.edit&roleid=2')->waitUntilReady(); $form = $this->query('id:userrole-form')->waitUntilPresent()->asForm()->one(); + if ($enable_modules === true) { - $this->assertTrue($form->query('xpath://label[text()="No enabled modules found."]')->one()->isDisplayed()); + foreach ($modules as $module) { + $this->assertFalse($form->query("xpath:.//label[text()=".CXPathHelper::escapeQuotes($module)."]") + ->one(false)->isValid() + ); + } + $this->page->open('zabbix.php?action=module.list')->waitUntilReady(); $this->query('button:Scan directory')->one()->click(); $table = $this->query('class:list-table')->asTable()->one(); @@ -1360,7 +1367,6 @@ class testFormUserRoles extends CWebTest { $this->page->waitUntilReady(); } else { - $this->assertFalse($form->query('xpath://label[text()="No enabled modules found."]')->one($enable_modules)->isDisplayed()); foreach ($modules as $module) { $form->getField($module)->isChecked(); } diff --git a/ui/tests/selenium/testDocumentationLinks.php b/ui/tests/selenium/testDocumentationLinks.php index 741b7e50228..603a9067489 100644 --- a/ui/tests/selenium/testDocumentationLinks.php +++ b/ui/tests/selenium/testDocumentationLinks.php @@ -117,7 +117,7 @@ class testDocumentationLinks extends CWebTest { 'actions' => [ [ 'callback' => 'openFormWithLink', - 'element' => 'xpath:(//button[@class="btn-widget-edit"])[1]' + 'element' => 'xpath:(//button[contains(@class, "btn-widget-edit")])[1]' ] ] ] @@ -687,7 +687,7 @@ class testDocumentationLinks extends CWebTest { 'actions' => [ [ 'callback' => 'openFormWithLink', - 'element' => 'xpath:(//button[@class="btn-widget-edit"])[1]' + 'element' => 'xpath:(//button[contains(@class, "btn-widget-edit")])[1]' ] ], 'doc_link' => '/en/manual/web_interface/frontend_sections/dashboards/widgets' diff --git a/ui/tests/selenium/testPageAdministrationGeneralModules.php b/ui/tests/selenium/testPageAdministrationGeneralModules.php index fe488eecb37..4ea9799f49e 100644 --- a/ui/tests/selenium/testPageAdministrationGeneralModules.php +++ b/ui/tests/selenium/testPageAdministrationGeneralModules.php @@ -41,6 +41,12 @@ class testPageAdministrationGeneralModules extends CWebTest { ]; } + private static $widget_names = ['Action log', 'Clock', 'Data overview', 'Discovery status', 'Favorite graphs', + 'Favorite maps','Geomap', 'Graph', 'Graph (classic)', 'Graph prototype', 'Host availability', 'Item value', + 'Map', 'Map navigation tree', 'Plain text', 'Problem hosts', 'Problems', 'Problems by severity', 'SLA report', + 'System information', 'Top hosts', 'Trigger overview', 'URL', 'Web monitoring' + ]; + public function testPageAdministrationGeneralModules_Layout() { $modules = [ [ @@ -79,6 +85,21 @@ class testPageAdministrationGeneralModules extends CWebTest { 'Status' => 'Disabled' ] ]; + + // Create an array with widgt modules that should be present by default. + $widget_modules = []; + $i = 0; + + foreach (self::$widget_names as $name) { + $widget_modules[$i]['Name'] = $name; + $widget_modules[$i]['Version'] = '1.0'; + $widget_modules[$i]['Author'] = 'Zabbix SIA'; + $widget_modules[$i]['Description'] = ''; + $widget_modules[$i]['Status'] = 'Enabled'; + + $i++; + } + // Open modules page and check header. $this->page->login()->open('zabbix.php?action=module.list'); $this->assertEquals('Modules', $this->query('tag:h1')->one()->getText()); @@ -87,12 +108,17 @@ class testPageAdministrationGeneralModules extends CWebTest { foreach (['Scan directory' => true, 'Enable' => false, 'Disable' => false] as $button => $enabled) { $this->assertTrue($this->query('button', $button)->one()->isEnabled($enabled)); } - // Check that modules are not being loaded until the 'Scan directory' button is pressed. - $this->assertEquals($this->query('class:nothing-to-show')->one()->getText(), 'No data found.'); - $this->assertEquals('Displaying 0 of 0 found', $this->query('class:table-stats')->one()->getText()); + + $table = $this->query('class:list-table')->asTable()->one(); + + // Check that only widget modules are present until the 'Scan directory' button is pressed. + $this->assertTableData($widget_modules); + + $count = $table->getRows()->count(); + $this->assertTableStats($count); + $this->assertEquals('0 selected', $this->query('id:selected_count')->one()->getText()); // Check modules table headers. - $table = $this->query('class:list-table')->asTable()->one(); $headers = $table->getHeadersText(); // Remove empty element from headers array. array_shift($headers); @@ -101,8 +127,14 @@ class testPageAdministrationGeneralModules extends CWebTest { // Load modules. $this->loadModules(); + $all_modules = array_merge($widget_modules, $modules); + // Sort column contents ascending. + usort($all_modules, function($a, $b) { + return strcmp($a['Name'], $b['Name']); + }); + // Check parameters of modules in the modules table. - $this->assertTableData($modules); + $this->assertTableData($all_modules); $count = CDBHelper::getCount('SELECT moduleid FROM module'); $this->assertEquals('Displaying '.$count.' of '.$count.' found', $this->query('class:table-stats')->one()->getText()); @@ -121,8 +153,8 @@ class testPageAdministrationGeneralModules extends CWebTest { 'Version' => '1', 'Author' => '1st Module author', 'Description' => '1st Module description', - 'Directory' => 'module_number_1', - 'Namespace' => 'Example_A', + 'Directory' => 'modules/module_number_1', + 'Namespace' => 'Modules\Example_A', 'Homepage' => '1st module URL', 'Enabled' => false ] @@ -134,8 +166,8 @@ class testPageAdministrationGeneralModules extends CWebTest { 'Version' => 'two !@#$%^&*()_+', 'Author' => '2nd Module author !@#$%^&*()_+', 'Description' => 'Module description !@#$%^&*()_+', - 'Directory' => 'module_number_2', - 'Namespace' => 'Example_B', + 'Directory' => 'modules/module_number_2', + 'Namespace' => 'Modules\Example_B', 'Homepage' => '!@#$%^&*()_+', 'Enabled' => false ] @@ -147,8 +179,8 @@ class testPageAdministrationGeneralModules extends CWebTest { 'Version' => '', 'Author' => '-', 'Description' => '-', - 'Directory' => 'module_number_4', - 'Namespace' => 'Example_A', + 'Directory' => 'modules/module_number_4', + 'Namespace' => 'Modules\Example_A', 'Homepage' => '-', 'Enabled' => false ] @@ -160,8 +192,8 @@ class testPageAdministrationGeneralModules extends CWebTest { 'Version' => '', 'Author' => '-', 'Description' => 'Adding top-level and sub-level menu', - 'Directory' => 'module_number_5', - 'Namespace' => 'Example_E', + 'Directory' => 'modules/module_number_5', + 'Namespace' => 'Modules\Example_E', 'Homepage' => '-', 'Enabled' => false ] @@ -173,8 +205,8 @@ class testPageAdministrationGeneralModules extends CWebTest { 'Version' => 'бета 2', 'Author' => 'Работник Заббикса', 'Description' => 'Удалить "Reports" из меню верхнего уровня, а так же удалить "Maps" из секции "Monitoring".', - 'Directory' => 'module_number_6', - 'Namespace' => 'Example_F', + 'Directory' => 'modules/module_number_6', + 'Namespace' => 'Modules\Example_F', 'Homepage' => '-', 'Enabled' => false ] @@ -277,9 +309,8 @@ class testPageAdministrationGeneralModules extends CWebTest { 'action' => 'forth.module' ] ], -// 'error_title' => 'Cannot update module: 4th Module.', - 'error_details' => 'Identical namespace (Example_A) is used by modules located at '. - 'module_number_1, module_number_4.' + 'error_details' => 'Identical namespace (Modules\Example_A) is used by modules located at '. + 'modules/module_number_1, modules/module_number_4.' ] ] ], @@ -409,9 +440,7 @@ class testPageAdministrationGeneralModules extends CWebTest { 'filter' => [ 'Status' => 'Enabled' ], - 'expected' => [ - '2nd Module name !@#$%^&*()_+' - ] + 'expected' => array_merge(['2nd Module name !@#$%^&*()_+'], self::$widget_names) ] ], // Retrieve only Disabled modules. diff --git a/ui/tests/selenium/testSID.php b/ui/tests/selenium/testSID.php index bc7f1c4a6ce..3669387d956 100644 --- a/ui/tests/selenium/testSID.php +++ b/ui/tests/selenium/testSID.php @@ -248,13 +248,6 @@ class testSID extends CWebTest { 'json_output' => true ]], - // Dashboard widget configure. - [[ - 'link' => 'zabbix.php?action=dashboard.widget.configure&type=actionlog&view_mode=0&fields=%7B%22rf_rate'. - '%22%3A%22-1%22%2C%22sort_triggers%22%3A%224%22%2C%22show_lines%22%3A%2225%22%7D', - 'json_output' => true - ]], - // Dashboard widget refresh rate. [[ 'link' => 'zabbix.php?action=dashboard.widget.rfrate&widgetid=2002&rf_rate=120', @@ -278,12 +271,6 @@ class testSID extends CWebTest { 'link' => 'zabbix.php?form_refresh=1&templateid=10076&dashboardids%5B146%5D=146&action=template.dashboard.delete' ]], - // Template dashboard widget edit. - [[ - 'link' => 'zabbix.php?action=dashboard.widget.edit&templateid=10076', - 'json_output' => true - ]], - // User token delete. [[ 'link' => 'zabbix.php?action=token.delete&action_src=user.token.list&tokenids%5B0%5D=1', @@ -606,11 +593,11 @@ class testSID extends CWebTest { // Export. [['link' => 'zabbix.php?action=export.hosts&format=yaml&backurl=hosts.php&form_refresh=1&hosts%5B50011%5D=50011']], - // Favourite create. - [['link' => 'zabbix.php?action=favourite.create&object=screenid&objectid=200021']], + // Favorite create. + [['link' => 'zabbix.php?action=favorite.create&object=screenid&objectid=200021']], - // Favourite delete. - [['link' => 'zabbix.php?action=favourite.delete&object=screenid&objectid=200021']], + // Favorite delete. + [['link' => 'zabbix.php?action=favorite.delete&object=screenid&objectid=200021']], // Host creation. [[ diff --git a/ui/tests/selenium/users/testFormUserPermissions.php b/ui/tests/selenium/users/testFormUserPermissions.php index 38b8e9ac8c7..85607986122 100644 --- a/ui/tests/selenium/users/testFormUserPermissions.php +++ b/ui/tests/selenium/users/testFormUserPermissions.php @@ -461,9 +461,23 @@ class testFormUserPermissions extends CWebTest { * Check enabled/disabled module. */ public function testFormUserPermissions_Module() { + $widget_modules = ['Action log', 'Clock', 'Data overview', 'Discovery status', 'Favorite graphs', 'Favorite maps', + 'Geomap', 'Graph', 'Graph (classic)', 'Graph prototype', 'Host availability', 'Item value', 'Map', + 'Map navigation tree', 'Plain text', 'Problem hosts', 'Problems', 'Problems by severity', 'SLA report', + 'System information', 'Top hosts', 'Trigger overview', 'URL', 'Web monitoring' + ]; + $this->page->login()->open('zabbix.php?action=user.edit&userid='.self::$admin_user)->waitUntilReady(); $this->query('xpath://form[@name="user_form"]')->waitUntilPresent()->one()->asForm()->selectTab('Permissions'); - $this->assertTrue($this->query('xpath://em[text()="No enabled modules found."]')->one()->isDisplayed()); + + // Check that the default modules are present in form. + $modules_selector = 'xpath://h4[text()="Access to modules"]/../../following::li[1]//span'; + $modules = $this->query($modules_selector)->all()->asText(); + + foreach (array_values($modules) as $module_name) { + $this->assertTrue(in_array($module_name, $widget_modules)); + } + $this->page->open('zabbix.php?action=module.list')->waitUntilReady(); $this->query('button:Scan directory')->one()->click(); $table = $this->query('class:list-table')->asTable()->one(); @@ -471,20 +485,24 @@ class testFormUserPermissions extends CWebTest { $this->query('button:Enable')->one()->click(); $this->page->acceptAlert(); $this->page->waitUntilReady(); - $selector = 'xpath://h4[text()="Access to modules"]/../../following::li/div/div/span[text()='; + foreach ([true, false] as $enable_modules) { $this->page->open('zabbix.php?action=user.edit&userid='.self::$admin_user)->waitUntilReady(); $this->query('xpath://form[@name="user_form"]')->waitUntilPresent()->one()->asForm()->selectTab('Permissions'); if ($enable_modules) { - $this->assertEquals('status-green', $this->query($selector.'"4"]')->one()->getAttribute('class')); + $this->assertEquals('status-green', $this->query($modules_selector.'[text()="4th Module"]')->one() + ->getAttribute('class') + ); $this->page->open('zabbix.php?action=userrole.edit&roleid='.self::$admin_roleid); $form = $this->query('id:userrole-form')->waitUntilPresent()->asForm()->one(); $form->getField('4th Module')->uncheck(); $form->submit(); } else { - $this->assertEquals('status-grey', $this->query($selector.'"4"]')->one()->getAttribute('class')); + $this->assertEquals('status-grey', $this->query($modules_selector.'[text()="4th Module"]')->one() + ->getAttribute('class') + ); } } } diff --git a/ui/tests/unit/bootstrap.php b/ui/tests/unit/bootstrap.php index 3fbbcae5f04..3ee9b0a4d60 100644 --- a/ui/tests/unit/bootstrap.php +++ b/ui/tests/unit/bootstrap.php @@ -73,5 +73,6 @@ $autoloader->addNamespace('', [ __DIR__.'/include/classes/import/converters', __DIR__.'/include/classes/include/classes/vaults' ]); -$autoloader->addNamespace('Core', [__DIR__.'/../../include/classes/core']); +$autoloader->addNamespace('Zabbix\\Core', [__DIR__.'/../../include/classes/core']); +$autoloader->addNamespace('Zabbix\\Widgets', [__DIR__.'/../../include/classes/widgets']); $autoloader->register(); diff --git a/ui/tests/unit/include/classes/import/CImportDataAdapterTest.php b/ui/tests/unit/include/classes/import/CImportDataAdapterTest.php index ae62d19d55e..1119ecabcb7 100644 --- a/ui/tests/unit/include/classes/import/CImportDataAdapterTest.php +++ b/ui/tests/unit/include/classes/import/CImportDataAdapterTest.php @@ -4279,9 +4279,7 @@ class CImportDataAdapterTest extends TestCase { ->setStrict(true) ->validate($source, '/'); - $versions = ['1.0', '2.0', '3.0', '3.2', '3.4', '4.0', '4.2', '4.4', '5.0', '5.2', '5.4', '6.0', '6.2']; - - foreach ($versions as $version) { + foreach ($import_converter_factory::getSequentialVersions() as $version) { if ($source['zabbix_export']['version'] !== $version) { continue; } diff --git a/ui/tr_events.php b/ui/tr_events.php index d088c17f210..30c2a5c175e 100644 --- a/ui/tr_events.php +++ b/ui/tr_events.php @@ -37,20 +37,10 @@ require_once dirname(__FILE__).'/include/page_header.php'; // VAR TYPE OPTIONAL FLAGS VALIDATION EXCEPTION $fields = [ 'triggerid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, PAGE_TYPE_HTML.'=='.$page['type']], - 'eventid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, PAGE_TYPE_HTML.'=='.$page['type']], - // Ajax - 'widget' => [T_ZBX_STR, O_OPT, P_ACT, IN('"'.WIDGET_HAT_EVENTACTIONS.'","'.WIDGET_HAT_EVENTLIST.'"'), null], - 'state' => [T_ZBX_INT, O_OPT, P_ACT, IN('0,1'), null] + 'eventid' => [T_ZBX_INT, O_OPT, P_SYS, DB_ID, PAGE_TYPE_HTML.'=='.$page['type']] ]; check_fields($fields); -/* - * Ajax - */ -if (hasRequest('widget') && hasRequest('state')) { - CProfile::update('web.tr_events.hats.'.getRequest('widget').'.state', getRequest('state'), PROFILE_TYPE_INT); -} - if ($page['type'] == PAGE_TYPE_JS || $page['type'] == PAGE_TYPE_HTML_BLOCK) { require_once dirname(__FILE__).'/include/page_footer.php'; exit; @@ -171,35 +161,36 @@ require_once dirname(__FILE__).'/include/views/js/tr_events.js.php'; $event_tab = (new CDiv([ new CDiv([ - (new CUiWidget(WIDGET_HAT_TRIGGERDETAILS, make_trigger_details($trigger, $event['eventid']))) - ->setHeader(_('Trigger details')), - (new CUiWidget(WIDGET_HAT_EVENTDETAILS, make_event_details($event, $allowed))) - ->setHeader(_('Event details')) + (new CSection(make_trigger_details($trigger, $event['eventid']))) + ->setId(SECTION_HAT_TRIGGERDETAILS) + ->setHeader(new CTag('h4', true, _('Trigger details'))), + (new CSection(make_event_details($event, $allowed))) + ->setId(SECTION_HAT_EVENTDETAILS) + ->setHeader(new CTag('h4', true, _('Event details'))) ]), new CDiv([ - (new CCollapsibleUiWidget(WIDGET_HAT_EVENTACTIONS, - makeEventDetailsActionsTable($actions, $users, $mediatypes) - )) - ->setExpanded((bool) CProfile::get('web.tr_events.hats.'.WIDGET_HAT_EVENTACTIONS.'.state', true)) - ->setHeader(_('Actions'), [], 'web.tr_events.hats.'.WIDGET_HAT_EVENTACTIONS.'.state') - ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FLUID), - (new CCollapsibleUiWidget(WIDGET_HAT_EVENTLIST, make_small_eventlist($event, $allowed))) - ->setExpanded((bool) CProfile::get('web.tr_events.hats.'.WIDGET_HAT_EVENTLIST.'.state', true)) - ->setHeader(_('Event list [previous 20]'), [], 'web.tr_events.hats.'.WIDGET_HAT_EVENTLIST.'.state') - ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_FLUID) + (new CSectionCollapsible(makeEventDetailsActionsTable($actions, $users, $mediatypes))) + ->setId(SECTION_HAT_EVENTACTIONS) + ->setHeader(new CTag('h4', true, _('Actions'))) + ->setProfileIdx('web.tr_events.hats.'.SECTION_HAT_EVENTACTIONS.'.state') + ->setExpanded((bool) CProfile::get('web.tr_events.hats.'.SECTION_HAT_EVENTACTIONS.'.state', true)), + (new CSectionCollapsible(make_small_eventlist($event, $allowed))) + ->setId(SECTION_HAT_EVENTLIST) + ->setHeader(new CTag('h4', true, _('Event list [previous 20]'))) + ->setProfileIdx('web.tr_events.hats.'.SECTION_HAT_EVENTLIST.'.state') + ->setExpanded((bool) CProfile::get('web.tr_events.hats.'.SECTION_HAT_EVENTLIST.'.state', true)), ]) ])) ->addClass(ZBX_STYLE_COLUMNS) ->addClass(ZBX_STYLE_COLUMNS_2); -(new CWidget()) +(new CHtmlPage()) ->setTitle(_('Event details')) ->setWebLayoutMode($page['web_layout_mode']) ->setDocUrl(CDocHelper::getUrl(CDocHelper::TR_EVENTS)) ->setControls( (new CTag('nav', true, - (new CList()) - ->addItem(get_icon('kioskmode', ['mode' => $page['web_layout_mode']])) + (new CList())->addItem(get_icon('kioskmode', ['mode' => $page['web_layout_mode']])) ))->setAttribute('aria-label', _('Content controls')) ) ->addItem($event_tab) diff --git a/ui/widgets/actionlog/Widget.php b/ui/widgets/actionlog/Widget.php new file mode 100755 index 00000000000..e1609372bbb --- /dev/null +++ b/ui/widgets/actionlog/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\ActionLog; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Action log'); + } +} diff --git a/ui/app/controllers/CControllerWidgetActionLogView.php b/ui/widgets/actionlog/actions/WidgetView.php index 9c17ba7e272..494dce08606 100644 --- a/ui/app/controllers/CControllerWidgetActionLogView.php +++ b/ui/widgets/actionlog/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,33 +19,27 @@ **/ -class CControllerWidgetActionLogView extends CControllerWidget { +namespace Widgets\ActionLog\Actions; - public function __construct() { - parent::__construct(); +use API, + CControllerDashboardWidgetView, + CControllerResponseData; - $this->setType(WIDGET_ACTION_LOG); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } +class WidgetView extends CControllerDashboardWidgetView { - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - - list($sortfield, $sortorder) = self::getSorting($fields['sort_triggers']); - $alerts = $this->getAlerts($sortfield, $sortorder, $fields['show_lines']); + protected function doAction(): void { + [$sortfield, $sortorder] = self::getSorting($this->fields_values['sort_triggers']); + $alerts = $this->getAlerts($sortfield, $sortorder, $this->fields_values['show_lines']); $db_users = $this->getDbUsers($alerts); $actions = API::Action()->get([ 'output' => ['actionid', 'name'], - 'actionids' => array_unique(zbx_objectValues($alerts, 'actionid')), + 'actionids' => array_unique(array_column($alerts, 'actionid')), 'preservekeys' => true ]); $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'actions' => $actions, 'alerts' => $alerts, 'db_users' => $db_users, @@ -57,16 +51,7 @@ class CControllerWidgetActionLogView extends CControllerWidget { ])); } - /** - * Get alerts. - * - * @param string $sortfield - * @param string $sortorder - * @param int $show_lines - * - * @return array - */ - private function getAlerts($sortfield, $sortorder, $show_lines) { + private function getAlerts(string $sortfield, string $sortorder, $show_lines): array { $alerts = API::Alert()->get([ 'output' => ['clock', 'sendto', 'subject', 'message', 'status', 'retries', 'error', 'userid', 'actionid', 'mediatypeid', 'alerttype' @@ -79,6 +64,7 @@ class CControllerWidgetActionLogView extends CControllerWidget { foreach ($alerts as &$alert) { $alert['description'] = ''; + if ($alert['mediatypeid'] != 0 && array_key_exists(0, $alert['mediatypes'])) { $alert['description'] = $alert['mediatypes'][0]['name']; $alert['maxattempts'] = $alert['mediatypes'][0]['maxattempts']; @@ -92,14 +78,7 @@ class CControllerWidgetActionLogView extends CControllerWidget { return $alerts; } - /** - * Get users. - * - * @param array $alerts - * - * @return array - */ - private function getDbUsers(array $alerts) { + private function getDbUsers(array $alerts): array { $userids = []; foreach ($alerts as $alert) { @@ -116,16 +95,7 @@ class CControllerWidgetActionLogView extends CControllerWidget { : []; } - /** - * Get sorting. - * - * @param int $sort_triggers - * - * @static - * - * @return array - */ - private static function getSorting($sort_triggers) { + private static function getSorting(int $sort_triggers): array { switch ($sort_triggers) { case SCREEN_SORT_TRIGGERS_TIME_ASC: return ['clock', ZBX_SORT_UP]; diff --git a/ui/widgets/actionlog/includes/WidgetForm.php b/ui/widgets/actionlog/includes/WidgetForm.php new file mode 100644 index 00000000000..fa0d39fdfa8 --- /dev/null +++ b/ui/widgets/actionlog/includes/WidgetForm.php @@ -0,0 +1,59 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\ActionLog\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldIntegerBox, + CWidgetFieldSelect +}; + +/** + * Action log widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + (new CWidgetFieldSelect('sort_triggers', _('Sort entries by'), [ + SCREEN_SORT_TRIGGERS_TIME_DESC => _('Time').' ('._('descending').')', + SCREEN_SORT_TRIGGERS_TIME_ASC => _('Time').' ('._('ascending').')', + SCREEN_SORT_TRIGGERS_TYPE_DESC => _('Type').' ('._('descending').')', + SCREEN_SORT_TRIGGERS_TYPE_ASC => _('Type').' ('._('ascending').')', + SCREEN_SORT_TRIGGERS_STATUS_DESC => _('Status').' ('._('descending').')', + SCREEN_SORT_TRIGGERS_STATUS_ASC => _('Status').' ('._('ascending').')', + SCREEN_SORT_TRIGGERS_RECIPIENT_DESC => _('Recipient').' ('._('descending').')', + SCREEN_SORT_TRIGGERS_RECIPIENT_ASC => _('Recipient').' ('._('ascending').')' + ]))->setDefault(SCREEN_SORT_TRIGGERS_TIME_DESC) + ) + ->addField( + (new CWidgetFieldIntegerBox('show_lines', _('Show lines'), ZBX_MIN_WIDGET_LINES, ZBX_MAX_WIDGET_LINES)) + ->setDefault(ZBX_DEFAULT_WIDGET_LINES) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ); + } +} diff --git a/ui/widgets/actionlog/manifest.json b/ui/widgets/actionlog/manifest.json new file mode 100755 index 00000000000..d7c59e5f60a --- /dev/null +++ b/ui/widgets/actionlog/manifest.json @@ -0,0 +1,9 @@ +{ + "manifest_version": 2.0, + "id": "actionlog", + "type": "widget", + "name": "Action log", + "namespace": "ActionLog", + "version": "1.0", + "author": "Zabbix SIA" +} diff --git a/ui/widgets/actionlog/views/widget.edit.php b/ui/widgets/actionlog/views/widget.edit.php new file mode 100755 index 00000000000..677ee2cc440 --- /dev/null +++ b/ui/widgets/actionlog/views/widget.edit.php @@ -0,0 +1,36 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Action log widget form view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldSelectView($data['fields']['sort_triggers']) + ) + ->addField( + new CWidgetFieldIntegerBoxView($data['fields']['show_lines']) + ) + ->show(); diff --git a/ui/app/views/monitoring.widget.actionlog.view.php b/ui/widgets/actionlog/views/widget.view.php index f45fe68e66b..68b683319f9 100644 --- a/ui/app/views/monitoring.widget.actionlog.view.php +++ b/ui/widgets/actionlog/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,13 +20,14 @@ /** + * Action log widget view. + * * @var CView $this * @var array $data */ // indicator of sort field -$sort_div = (new CSpan()) - ->addClass(($data['sortorder'] === ZBX_SORT_DOWN) ? ZBX_STYLE_ARROW_DOWN : ZBX_STYLE_ARROW_UP); +$sort_div = (new CSpan())->addClass($data['sortorder'] === ZBX_SORT_DOWN ? ZBX_STYLE_ARROW_DOWN : ZBX_STYLE_ARROW_UP); // create alert table $table = (new CTableInfo()) @@ -59,7 +60,7 @@ foreach ($data['alerts'] as $alert) { $info_icons = makeErrorIcon($alert['error']); } else { - $info_icons = null; + $info_icons = []; } $message = ($alert['alerttype'] == ALERT_TYPE_MESSAGE) @@ -84,18 +85,6 @@ foreach ($data['alerts'] as $alert) { ]); } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/clock/Widget.php b/ui/widgets/clock/Widget.php new file mode 100755 index 00000000000..c20635500d3 --- /dev/null +++ b/ui/widgets/clock/Widget.php @@ -0,0 +1,48 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Clock; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + // Clock type. + public const TYPE_ANALOG = 0; + public const TYPE_DIGITAL = 1; + + // Clock time zone format. + public const TIMEZONE_SHORT = 0; + public const TIMEZONE_FULL = 1; + + // Clock time format. + public const HOUR_24 = 0; + public const HOUR_12 = 1; + + // Form blocks. + public const SHOW_DATE = 1; + public const SHOW_TIME = 2; + public const SHOW_TIMEZONE = 3; + + public function getDefaultName(): string { + return _('Clock'); + } +} diff --git a/ui/app/controllers/CControllerWidgetClockView.php b/ui/widgets/clock/actions/WidgetView.php index f3fb20a7210..62ce9a2f435 100644..100755 --- a/ui/app/controllers/CControllerWidgetClockView.php +++ b/ui/widgets/clock/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,24 +19,33 @@ **/ -class CControllerWidgetClockView extends CControllerWidget { +namespace Widgets\Clock\Actions; - public function __construct() { - parent::__construct(); +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CTimezoneHelper, + DateTime, + DateTimeZone, + Exception, + Manager; - $this->setType(WIDGET_CLOCK); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json', +use Widgets\Clock\Widget; + +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'dynamic_hostid' => 'db hosts.hostid' ]); } - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); + protected function doAction(): void { $config_defaults = [ - 'name' => $this->getDefaultName(), - 'type' => $fields['clock_type'], + 'name' => $this->widget->getDefaultName(), + 'type' => $this->fields_values['clock_type'], 'time' => null, 'time_zone_offset' => null, 'date' => date(ZBX_DATE), @@ -45,35 +54,35 @@ class CControllerWidgetClockView extends CControllerWidget { 'critical_error' => null ]; - switch ($fields['time_type']) { + switch ($this->fields_values['time_type']) { case TIME_TYPE_HOST: - $clock_data = $this->configureHostTime($fields) + $config_defaults; + $clock_data = $this->configureHostTime() + $config_defaults; break; case TIME_TYPE_SERVER: - $clock_data = $this->configureFields($fields) + $config_defaults; + $clock_data = $this->configureFields() + $config_defaults; $clock_data['name'] = _('Server'); break; default: - $clock_data = $this->configureFields($fields) + $config_defaults; + $clock_data = $this->configureFields() + $config_defaults; $clock_data['name'] = _('Local'); break; } - // Pass clock configiguration to browser script. - if ($fields['clock_type'] === WIDGET_CLOCK_TYPE_DIGITAL) { - $clock_data['show'] = $fields['show']; - $clock_data['bg_color'] = $fields['bg_color']; - $clock_data['time_format'] = $fields['time_format']; - $clock_data['seconds'] = ($fields['time_sec'] == 1); - $clock_data['tzone_format'] = $fields['tzone_format']; + // Pass clock configuration to browser script. + if ($this->fields_values['clock_type'] === Widget::TYPE_DIGITAL) { + $clock_data['show'] = $this->fields_values['show']; + $clock_data['bg_color'] = $this->fields_values['bg_color']; + $clock_data['time_format'] = $this->fields_values['time_format']; + $clock_data['seconds'] = ($this->fields_values['time_sec'] == 1); + $clock_data['tzone_format'] = $this->fields_values['tzone_format']; } $this->setResponse(new CControllerResponseData([ 'name' => $this->getInput('name', $clock_data['name']), 'clock_data' => $clock_data, - 'styles' => self::getFieldStyles($fields), + 'styles' => $this->getFieldStyles(), 'user' => [ 'debug_mode' => $this->getDebugMode() ] @@ -88,18 +97,14 @@ class CControllerWidgetClockView extends CControllerWidget { * * @return string Return time zone name from list or 'local' if time zone must be set via browser. */ - protected function makeTimeZoneValue(string $time_zone, int $format = WIDGET_CLOCK_TIMEZONE_SHORT): string { + private function makeTimeZoneValue(string $time_zone, int $format = Widget::TIMEZONE_SHORT): string { if ($time_zone === TIMEZONE_DEFAULT_LOCAL) { return $time_zone; } - elseif ($time_zone === ZBX_DEFAULT_TIMEZONE) { - $zone = CTimezoneHelper::getSystemTimezone(); - } - else { - $zone = $time_zone; - } - if ($format === WIDGET_CLOCK_TIMEZONE_SHORT) { + $zone = $time_zone === ZBX_DEFAULT_TIMEZONE ? CTimezoneHelper::getSystemTimezone() : $time_zone; + + if ($format === Widget::TIMEZONE_SHORT) { if (($pos = strrpos($zone, '/')) !== false) { $zone = substr($zone, $pos + 1); } @@ -111,37 +116,19 @@ class CControllerWidgetClockView extends CControllerWidget { return str_replace('_', ' ', $zone); } - /** - * @param array $fields - * - * @return boolean - */ - protected function showDate(array $fields): bool { - return ($fields['clock_type'] === WIDGET_CLOCK_TYPE_DIGITAL - && in_array(WIDGET_CLOCK_SHOW_DATE, $fields['show']) - ); + private function showDate(): bool { + return $this->fields_values['clock_type'] === Widget::TYPE_DIGITAL + && in_array(Widget::SHOW_DATE, $this->fields_values['show']); } - /** - * @param array $fields - * - * @return boolean - */ - protected function showTime(array $fields): bool { - return ($fields['clock_type'] === WIDGET_CLOCK_TYPE_ANALOG - || in_array(WIDGET_CLOCK_SHOW_TIMEZONE, $fields['show']) - ); + private function showTime(): bool { + return $this->fields_values['clock_type'] === Widget::TYPE_ANALOG + || in_array(Widget::SHOW_TIME, $this->fields_values['show']); } - /** - * @param array $fields - * - * @return boolean - */ - protected function showTimeZone(array $fields): bool { - return ($fields['clock_type'] === WIDGET_CLOCK_TYPE_DIGITAL - && in_array(WIDGET_CLOCK_SHOW_TIMEZONE, $fields['show']) - ); + private function showTimeZone(): bool { + return $this->fields_values['clock_type'] === Widget::TYPE_DIGITAL + && in_array(Widget::SHOW_TIMEZONE, $this->fields_values['show']); } /** @@ -149,7 +136,7 @@ class CControllerWidgetClockView extends CControllerWidget { * * @return array */ - protected function makeTimeFromDateTime(DateTime $date): array { + private function makeTimeFromDateTime(DateTime $date): array { $time = []; $time['time'] = $date->getTimestamp(); @@ -165,7 +152,7 @@ class CControllerWidgetClockView extends CControllerWidget { * * @return DateTime|null Returns created DateTime object or null if time zone is set by browser. */ - protected function makeDateTimeFromTimeZone(string $time_zone): ?DateTime { + private function makeDateTimeFromTimeZone(string $time_zone): ?DateTime { if ($time_zone === TIMEZONE_DEFAULT_LOCAL) { return null; } @@ -179,46 +166,15 @@ class CControllerWidgetClockView extends CControllerWidget { return $now; } - /** - * Create required clock field values both for analog and digital clock. - * - * @param array $fields Saved clock configuration. - * - * @return array Return prepared clock configuration. - */ - protected function configureFields(array $fields): array { - $clock = []; - - $date = $this->makeDateTimeFromTimeZone($fields['tzone_timezone']); - - if ($this->showDate($fields) && $date !== null) { - $clock['date'] = $date->format(ZBX_DATE); - } - - if ($this->showTime($fields) && $date !== null) { - $clock = array_merge($clock, $this->makeTimeFromDateTime($date)); - } - - if ($this->showTimeZone($fields)) { - $clock['time_zone'] = $this->makeTimeZoneValue($fields['tzone_timezone'], $fields['tzone_format']); - } - - return $clock; - } - - /** - * @param array $fields Saved clock configuration. - * - * @return array - */ - protected function configureHostTime(array $fields): array { + private function configureHostTime(): array { + $items = []; $clock = ['is_enabled' => true]; - if ($this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD) { + if ($this->hasInput('templateid')) { if ($this->hasInput('dynamic_hostid')) { $template_items = API::Item()->get([ 'output' => ['key_'], - 'itemids' => $fields['itemid'], + 'itemids' => $this->fields_values['itemid'], 'webitems' => true ]); @@ -233,9 +189,6 @@ class CControllerWidgetClockView extends CControllerWidget { 'webitems' => true ]); } - else { - $items = []; - } } // Editing template dashboard? else { @@ -246,7 +199,7 @@ class CControllerWidgetClockView extends CControllerWidget { $items = API::Item()->get([ 'output' => ['itemid', 'value_type'], 'selectHosts' => ['name'], - 'itemids' => $fields['itemid'], + 'itemids' => $this->fields_values['itemid'], 'webitems' => true ]); } @@ -267,7 +220,7 @@ class CControllerWidgetClockView extends CControllerWidget { try { $now = new DateTime($last_value['value']); - if ($this->showDate($fields)) { + if ($this->showDate()) { $clock['date'] = $now->format(ZBX_DATE); } @@ -275,7 +228,7 @@ class CControllerWidgetClockView extends CControllerWidget { $clock['time'] = time() - ($last_value['clock'] - $now->getTimestamp()); - if ($this->showTimeZone($fields)) { + if ($this->showTimeZone()) { $clock['time_zone'] = 'UTC'.$now->format('P'); } } @@ -295,39 +248,62 @@ class CControllerWidgetClockView extends CControllerWidget { } /** + * Create required clock field values both for analog and digital clock. + */ + private function configureFields(): array { + $clock = []; + + $date = $this->makeDateTimeFromTimeZone($this->fields_values['tzone_timezone']); + + if ($date !== null) { + if ($this->showDate()) { + $clock['date'] = $date->format(ZBX_DATE); + } + + if ($this->showTime()) { + $clock = array_merge($clock, $this->makeTimeFromDateTime($date)); + } + } + + if ($this->showTimeZone()) { + $clock['time_zone'] = $this->makeTimeZoneValue($this->fields_values['tzone_timezone'], + $this->fields_values['tzone_format'] + ); + } + + return $clock; + } + + /** * Groups enabled field styles by field name (Date, Time, Time zone). - * - * @param array $fields Saved clock configuration. - * - * @return array */ - protected static function getFieldStyles(array $fields): array { + private function getFieldStyles(): array { $cells = []; - if ($fields['clock_type'] === WIDGET_CLOCK_TYPE_DIGITAL) { - $show = $fields['show']; + if ($this->fields_values['clock_type'] === Widget::TYPE_DIGITAL) { + $show = $this->fields_values['show']; - if (in_array(WIDGET_CLOCK_SHOW_DATE, $show)) { + if (in_array(Widget::SHOW_DATE, $show)) { $cells['date'] = [ - 'size' => $fields['date_size'], - 'bold' => ($fields['date_bold'] == 1), - 'color' => $fields['date_color'] + 'size' => $this->fields_values['date_size'], + 'bold' => ($this->fields_values['date_bold'] == 1), + 'color' => $this->fields_values['date_color'] ]; } - if (in_array(WIDGET_CLOCK_SHOW_TIME, $show)) { + if (in_array(Widget::SHOW_TIME, $show)) { $cells['time'] = [ - 'size' => $fields['time_size'], - 'bold' => ($fields['time_bold'] == 1), - 'color' => $fields['time_color'] + 'size' => $this->fields_values['time_size'], + 'bold' => ($this->fields_values['time_bold'] == 1), + 'color' => $this->fields_values['time_color'] ]; } - if (in_array(WIDGET_CLOCK_SHOW_TIMEZONE, $show)) { + if (in_array(Widget::SHOW_TIMEZONE, $show)) { $cells['timezone'] = [ - 'size' => $fields['tzone_size'], - 'bold' => ($fields['tzone_bold'] == 1), - 'color' => $fields['tzone_color'] + 'size' => $this->fields_values['tzone_size'], + 'bold' => ($this->fields_values['tzone_bold'] == 1), + 'color' => $this->fields_values['tzone_color'] ]; } } diff --git a/ui/js/widgets/class.widget.clock.js b/ui/widgets/clock/assets/js/class.widget.js index 5c27ab4c20a..e93d59040ff 100644..100755 --- a/ui/js/widgets/class.widget.clock.js +++ b/ui/widgets/clock/assets/js/class.widget.js @@ -258,4 +258,8 @@ class CWidgetClock extends CWidget { clock_time_zone.textContent = timezone_text; } + + _hasPadding() { + return this._fields.clock_type === undefined || this._fields.clock_type == CWidgetClock.TYPE_ANALOG; + } } diff --git a/ui/widgets/clock/includes/WidgetForm.php b/ui/widgets/clock/includes/WidgetForm.php new file mode 100755 index 00000000000..ac94bea7d6b --- /dev/null +++ b/ui/widgets/clock/includes/WidgetForm.php @@ -0,0 +1,142 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Clock\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldCheckBoxList, + CWidgetFieldColor, + CWidgetFieldIntegerBox, + CWidgetFieldMultiSelectItem, + CWidgetFieldRadioButtonList, + CWidgetFieldSelect, + CWidgetFieldTimeZone +}; + +use Widgets\Clock\Widget; + +/** + * Clock widget form. + */ +class WidgetForm extends CWidgetForm { + + private const SIZE_PERCENT_MIN = 1; + private const SIZE_PERCENT_MAX = 100; + + private const DEFAULT_DATE_SIZE = 20; + private const DEFAULT_TIME_SIZE = 30; + private const DEFAULT_TIMEZONE_SIZE = 20; + + public function addFields(): self { + $time_type = array_key_exists('time_type', $this->values) ? $this->values['time_type'] : null; + + return $this + ->addField( + (new CWidgetFieldSelect('time_type', _('Time type'), [ + TIME_TYPE_LOCAL => _('Local time'), + TIME_TYPE_SERVER => _('Server time'), + TIME_TYPE_HOST => _('Host time') + ]))->setDefault(TIME_TYPE_LOCAL) + ) + ->addField($time_type == TIME_TYPE_HOST + ? (new CWidgetFieldMultiSelectItem('itemid', _('Item'), $this->templateid)) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ->setMultiple(false) + : null + ) + ->addField( + (new CWidgetFieldRadioButtonList('clock_type', _('Clock type'), [ + Widget::TYPE_ANALOG => _('Analog'), + Widget::TYPE_DIGITAL => _('Digital') + ]))->setDefault(Widget::TYPE_ANALOG) + ) + ->addField( + (new CWidgetFieldCheckBoxList('show', _('Show'), [ + Widget::SHOW_DATE => _('Date'), + Widget::SHOW_TIME => _('Time'), + Widget::SHOW_TIMEZONE => _('Time zone') + ])) + ->setDefault([Widget::SHOW_TIME]) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField( + new CWidgetFieldCheckBox('adv_conf', _('Advanced configuration')) + ) + ->addField( + (new CWidgetFieldColor('bg_color', _('Background color')))->allowInherited() + ) + ->addField( + (new CWidgetFieldIntegerBox('date_size', _('Size'), self::SIZE_PERCENT_MIN, self::SIZE_PERCENT_MAX)) + ->setDefault(self::DEFAULT_DATE_SIZE) + ) + ->addField( + new CWidgetFieldCheckBox('date_bold', _('Bold')) + ) + ->addField( + (new CWidgetFieldColor('date_color', _('Color')))->allowInherited() + ) + ->addField( + (new CWidgetFieldIntegerBox('time_size', _('Size'), self::SIZE_PERCENT_MIN, self::SIZE_PERCENT_MAX)) + ->setDefault(self::DEFAULT_TIME_SIZE) + ) + ->addField( + new CWidgetFieldCheckBox('time_bold', _('Bold')) + ) + ->addField( + (new CWidgetFieldColor('time_color', _('Color')))->allowInherited() + ) + ->addField( + (new CWidgetFieldCheckBox('time_sec', _('Seconds')))->setDefault(1) + ) + ->addField( + (new CWidgetFieldRadioButtonList('time_format', _('Format'), [ + Widget::HOUR_24 => _('24-hour'), + Widget::HOUR_12 => _('12-hour') + ]))->setDefault(Widget::HOUR_24) + ) + ->addField( + (new CWidgetFieldIntegerBox('tzone_size', _('Size'), self::SIZE_PERCENT_MIN, self::SIZE_PERCENT_MAX)) + ->setDefault(self::DEFAULT_TIMEZONE_SIZE) + ) + ->addField( + new CWidgetFieldCheckBox('tzone_bold', _('Bold')) + ) + ->addField( + (new CWidgetFieldColor('tzone_color', _('Color')))->allowInherited() + ) + ->addField( + (new CWidgetFieldTimeZone('tzone_timezone', _('Time zone'))) + ->setDefault($time_type == TIME_TYPE_LOCAL ? TIMEZONE_DEFAULT_LOCAL : ZBX_DEFAULT_TIMEZONE) + ) + ->addField( + (new CWidgetFieldRadioButtonList('tzone_format', _('Format'), [ + Widget::TIMEZONE_SHORT => _('Short'), + Widget::TIMEZONE_FULL => _('Full') + ]))->setDefault(Widget::TIMEZONE_SHORT) + ); + } +} diff --git a/ui/widgets/clock/manifest.json b/ui/widgets/clock/manifest.json new file mode 100755 index 00000000000..9bd304f5c83 --- /dev/null +++ b/ui/widgets/clock/manifest.json @@ -0,0 +1,21 @@ +{ + "manifest_version": 2.0, + "id": "clock", + "type": "widget", + "name": "Clock", + "namespace": "Clock", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "template_support": true, + "size": { + "width": 4, + "height": 3 + }, + "js_class": "CWidgetClock", + "refresh_rate": 900 + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/widgets/clock/views/widget.edit.js.php b/ui/widgets/clock/views/widget.edit.js.php new file mode 100755 index 00000000000..d6f548906b8 --- /dev/null +++ b/ui/widgets/clock/views/widget.edit.js.php @@ -0,0 +1,105 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Widgets\Clock\Widget; + +?> + +window.widget_clock_form = new class { + + init() { + this._form = document.getElementById('widget-dialogue-form'); + this._time_type = document.getElementById('time_type'); + this._clock_type = document.getElementById('clock_type'); + + this._show_date = document.getElementById('show_1'); + this._show_time = document.getElementById('show_2'); + this._show_tzone = document.getElementById('show_3'); + + this._advanced_configuration = document.getElementById('adv_conf'); + + for (const colorpicker of this._form.querySelectorAll('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) { + $(colorpicker).colorpicker({ + appendTo: '.overlay-dialogue-body', + use_default: true, + onUpdate: window.setIndicatorColor + }); + } + + this._time_type.addEventListener('change', () => { + ZABBIX.Dashboard.reloadWidgetProperties(); + this.updateForm(); + }); + + for (const checkbox of this._clock_type.querySelectorAll('input')) { + checkbox.addEventListener('change', () => this.updateForm()); + } + + const show = [this._show_date, this._show_time, this._show_tzone]; + + for (const checkbox of show) { + checkbox.addEventListener('change', (e) => { + if (show.filter((checkbox) => checkbox.checked).length > 0) { + this.updateForm(); + } + else { + e.target.checked = true; + } + }); + } + + this._advanced_configuration.addEventListener('change', () => this.updateForm()); + + this.updateForm(); + } + + updateForm() { + const is_digital = this._clock_type.querySelector('input:checked').value == <?= Widget::TYPE_DIGITAL ?>; + + const show_date_row = is_digital && this._advanced_configuration.checked && this._show_date.checked; + const show_time_row = is_digital && this._advanced_configuration.checked && this._show_time.checked; + const show_tzone_row = is_digital && this._advanced_configuration.checked && this._show_tzone.checked; + + for (const element of this._form.querySelectorAll('.js-row-show, .js-row-adv-conf')) { + element.style.display = is_digital ? '' : 'none'; + } + + for (const element of this._form.querySelectorAll('.js-row-bg-color')) { + element.style.display = is_digital && this._advanced_configuration.checked ? '' : 'none'; + } + + for (const element of this._form.querySelectorAll('.fields-group-date')) { + element.style.display = show_date_row ? '' : 'none'; + } + + for (const element of this._form.querySelectorAll('.fields-group-time')) { + element.style.display = show_time_row ? '' : 'none'; + } + + for (const element of this._form.querySelectorAll('.fields-group-tzone')) { + element.style.display = show_tzone_row ? '' : 'none'; + } + + for (const element of this._form.querySelectorAll('.field-tzone-timezone, .field-tzone-format')) { + element.style.display = this._time_type.value != <?= TIME_TYPE_HOST ?> ? '' : 'none'; + } + } +}; diff --git a/ui/widgets/clock/views/widget.edit.php b/ui/widgets/clock/views/widget.edit.php new file mode 100755 index 00000000000..bc782d0cb08 --- /dev/null +++ b/ui/widgets/clock/views/widget.edit.php @@ -0,0 +1,130 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Clock widget form view. + * + * @var CView $this + * @var array $data + */ + +$form = (new CWidgetFormView($data)); + +$form + ->addField( + new CWidgetFieldSelectView($data['fields']['time_type']) + ) + ->addField(array_key_exists('itemid', $data['fields']) + ? new CWidgetFieldMultiSelectItemView($data['fields']['itemid'], $data['captions']['ms']['items']['itemid']) + : null + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['clock_type']) + ) + ->addField( + new CWidgetFieldCheckBoxListView($data['fields']['show']), + 'js-row-show' + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['adv_conf']), + 'js-row-adv-conf' + ) + ->addField( + new CWidgetFieldColorView($data['fields']['bg_color']), + 'js-row-bg-color' + ) + ->addFieldsGroup(_('Date'), getDateFieldsGroupViews($form, $data['fields']), 'fields-group-date') + ->addFieldsGroup(_('Time'), getTimeFieldsGroupViews($form, $data['fields']), 'fields-group-time') + ->addFieldsGroup(_('Time zone'), getTimeZoneFieldsGroupViews($form, $data['fields']), 'fields-group-tzone') + ->includeJsFile('widget.edit.js.php') + ->addJavaScript('widget_clock_form.init();') + ->show(); + +function getDateFieldsGroupViews(CWidgetFormView $form, array $fields): array { + $date_size = new CWidgetFieldIntegerBoxView($fields['date_size']); + $date_color = new CWidgetFieldColorView($fields['date_color']); + + return [ + $form->makeCustomField($date_size, [ + $date_size->getLabel(), + (new CFormField([$date_size->getView(), '%']))->addClass('field-size') + ]), + + new CWidgetFieldCheckBoxView($fields['date_bold']), + + $form->makeCustomField($date_color, [ + $date_color->getLabel()->addClass('offset-3'), + new CFormField($date_color->getView()) + ]) + ]; +} + +function getTimeFieldsGroupViews(CWidgetFormView $form, array $fields): array { + $time_size = new CWidgetFieldIntegerBoxView($fields['time_size']); + $time_color = new CWidgetFieldColorView($fields['time_color']); + $time_format = new CWidgetFieldRadioButtonListView($fields['time_format']); + + return [ + $form->makeCustomField($time_size, [ + $time_size->getLabel(), + (new CFormField([$time_size->getView(), '%']))->addClass('field-size') + ]), + + new CWidgetFieldCheckBoxView($fields['time_bold']), + + $form->makeCustomField($time_color, [ + $time_color->getLabel()->addClass('offset-3'), + new CFormField($time_color->getView()) + ]), + + new CWidgetFieldCheckBoxView($fields['time_sec']), + + $form->makeCustomField($time_format, [ + $time_format->getLabel(), + (new CFormField($time_format->getView()))->addClass('field-format') + ]) + ]; +} + +function getTimeZoneFieldsGroupViews(CWidgetFormView $form, array $fields): array { + $tzone_size = new CWidgetFieldIntegerBoxView($fields['tzone_size']); + $tzone_color = new CWidgetFieldColorView($fields['tzone_color']); + $tzone_timezone = new CWidgetFieldTimeZoneView($fields['tzone_timezone']); + $tzone_format = new CWidgetFieldRadioButtonListView($fields['tzone_format']); + + return [ + $form->makeCustomField($tzone_size, [ + $tzone_size->getLabel(), + (new CFormField([$tzone_size->getView(), '%']))->addClass('field-size') + ]), + + new CWidgetFieldCheckBoxView($fields['tzone_bold']), + + $form->makeCustomField($tzone_color, [ + $tzone_color->getLabel()->addClass('offset-3'), + new CFormField($tzone_color->getView()) + ]), + + $form->makeCustomField($tzone_timezone, [], 'field-tzone-timezone'), + + $form->makeCustomField($tzone_format, [], 'field-tzone-format') + ]; +} diff --git a/ui/app/views/monitoring.widget.clock.view.php b/ui/widgets/clock/views/widget.view.php index 89b4ef1fe98..482208fa6f6 100644..100755 --- a/ui/app/views/monitoring.widget.clock.view.php +++ b/ui/widgets/clock/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,20 +20,21 @@ /** + * Clock widget view. + * * @var CView $this * @var array $data */ -if ($data['clock_data']['critical_error'] !== null) { - $item = (new CTableInfo())->setNoDataMessage($data['clock_data']['critical_error']); +use Widgets\Clock\Widget; + +$view = new CWidgetView($data); - $output = [ - 'name' => $data['name'], - 'body' => $item->toString() - ]; +if ($data['clock_data']['critical_error'] !== null) { + $body = (new CTableInfo())->setNoDataMessage($data['clock_data']['critical_error']); } else { - if ($data['clock_data']['type'] == WIDGET_CLOCK_TYPE_DIGITAL) { + if ($data['clock_data']['type'] == Widget::TYPE_DIGITAL) { $clock_data = $data['clock_data']; $rows = []; @@ -43,17 +44,17 @@ else { $div = new CDiv(); switch ($show) { - case WIDGET_CLOCK_SHOW_DATE: + case Widget::SHOW_DATE: $div->addClass('clock-date'); $styles = $data['styles']['date']; break; - case WIDGET_CLOCK_SHOW_TIME: + case Widget::SHOW_TIME: $div->addClass('clock-time'); $styles = $data['styles']['time']; break; - case WIDGET_CLOCK_SHOW_TIMEZONE: + case Widget::SHOW_TIMEZONE: $div->addClass('clock-time-zone'); $styles = $data['styles']['timezone']; break; @@ -83,9 +84,7 @@ else { ->addClass('clock-disabled'); } - $body = (new CDiv($rows)) - ->addClass('dashboard-widget-clock') - ->addClass('clock-digital'); + $body = (new CDiv($rows))->addClass('clock-digital'); if ($clock_data['bg_color'] !== '') { $body->addStyle('background-color: #'.$clock_data['bg_color']); @@ -95,22 +94,9 @@ else { $body = (new CClock())->setEnabled($data['clock_data']['is_enabled']); } - $output = [ - 'name' => $data['name'], - 'body' => $body->toString(), - 'clock_data' => $data['clock_data'] - ]; -} - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance() - ->make() - ->toString(); + $view->setVar('clock_data', $data['clock_data']); } -echo json_encode($output); +$view + ->addItem($body) + ->show(); diff --git a/ui/widgets/dataover/Widget.php b/ui/widgets/dataover/Widget.php new file mode 100755 index 00000000000..f0805d55f12 --- /dev/null +++ b/ui/widgets/dataover/Widget.php @@ -0,0 +1,35 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\DataOver; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Data overview'); + } + + public function isDeprecated(): bool { + return true; + } +} diff --git a/ui/app/controllers/CControllerWidgetDataOverView.php b/ui/widgets/dataover/actions/WidgetView.php index abc140e7f1b..29f96642b5c 100644 --- a/ui/app/controllers/CControllerWidgetDataOverView.php +++ b/ui/widgets/dataover/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,31 +19,24 @@ **/ -class CControllerWidgetDataOverView extends CControllerWidget { +namespace Widgets\DataOver\Actions; - public function __construct() { - parent::__construct(); +use CControllerDashboardWidgetView, + CControllerResponseData; - $this->setType(WIDGET_DATA_OVER); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } - - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); +class WidgetView extends CControllerDashboardWidgetView { - $groupids = $fields['groupids'] ? getSubGroups($fields['groupids']) : null; - $hostids = $fields['hostids'] ? $fields['hostids'] : null; + protected function doAction(): void { + $groupids = $this->fields_values['groupids'] ? getSubGroups($this->fields_values['groupids']) : null; + $hostids = $this->fields_values['hostids'] ?: null; - [$items, $hosts, $has_hidden_data] = getDataOverview($groupids, $hostids, $fields); + [$items, $hosts, $has_hidden_data] = getDataOverview($groupids, $hostids, $this->fields_values); $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), - 'groupids' => getSubGroups($fields['groupids']), - 'show_suppressed' => $fields['show_suppressed'], - 'style' => $fields['style'], + 'name' => $this->getInput('name', $this->widget->getDefaultName()), + 'groupids' => getSubGroups($this->fields_values['groupids']), + 'show_suppressed' => $this->fields_values['show_suppressed'], + 'style' => $this->fields_values['style'], 'items' => $items, 'hosts' => $hosts, 'has_hidden_data' => $has_hidden_data, diff --git a/ui/widgets/dataover/includes/WidgetForm.php b/ui/widgets/dataover/includes/WidgetForm.php new file mode 100644 index 00000000000..a0b7556bd83 --- /dev/null +++ b/ui/widgets/dataover/includes/WidgetForm.php @@ -0,0 +1,66 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\DataOver\Includes; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldRadioButtonList, + CWidgetFieldTags +}; + +/** + * Data overview widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectHost('hostids', _('Hosts')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ]))->setDefault(TAG_EVAL_TYPE_AND_OR) + ) + ->addField( + new CWidgetFieldTags('tags') + ) + ->addField( + new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('style', _('Hosts location'), [ + STYLE_LEFT => _('Left'), + STYLE_TOP => _('Top') + ]))->setDefault(STYLE_LEFT) + ); + } +} diff --git a/ui/widgets/dataover/manifest.json b/ui/widgets/dataover/manifest.json new file mode 100755 index 00000000000..2d52fda7364 --- /dev/null +++ b/ui/widgets/dataover/manifest.json @@ -0,0 +1,9 @@ +{ + "manifest_version": 2.0, + "id": "dataover", + "type": "widget", + "name": "Data overview", + "namespace": "DataOver", + "version": "1.0", + "author": "Zabbix SIA" +} diff --git a/ui/widgets/dataover/views/widget.edit.php b/ui/widgets/dataover/views/widget.edit.php new file mode 100755 index 00000000000..0e7acc85ecc --- /dev/null +++ b/ui/widgets/dataover/views/widget.edit.php @@ -0,0 +1,51 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Data overview widget form view. + * + * @var CView $this + * @var array $data + */ + +$groupids = new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], + $data['captions']['ms']['groups']['groupids'] +); + +(new CWidgetFormView($data)) + ->addField($groupids) + ->addField( + (new CWidgetFieldMultiSelectHostView($data['fields']['hostids'], $data['captions']['ms']['hosts']['hostids'])) + ->setFilterPreselect(['id' => $groupids->getId(), 'submit_as' => 'groupid']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['evaltype']) + ) + ->addField( + new CWidgetFieldTagsView($data['fields']['tags']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_suppressed']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['style']) + ) + ->show(); diff --git a/ui/widgets/dataover/views/widget.view.php b/ui/widgets/dataover/views/widget.view.php new file mode 100644 index 00000000000..c9c3cb60eab --- /dev/null +++ b/ui/widgets/dataover/views/widget.view.php @@ -0,0 +1,34 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Data overview widget view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetView($data)) + ->addItem($data['style'] == STYLE_TOP + ? (new CPartial('dataoverview.table.top', $data))->getOutput() + : (new CPartial('dataoverview.table.left', $data))->getOutput() + ) + ->show(); diff --git a/ui/widgets/discovery/Widget.php b/ui/widgets/discovery/Widget.php new file mode 100755 index 00000000000..e51d9b66a23 --- /dev/null +++ b/ui/widgets/discovery/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Discovery; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Discovery status'); + } +} diff --git a/ui/app/controllers/CControllerWidgetDiscoveryView.php b/ui/widgets/discovery/actions/WidgetView.php index 92e30c38eb9..58dad250854 100644 --- a/ui/app/controllers/CControllerWidgetDiscoveryView.php +++ b/ui/widgets/discovery/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,21 +19,18 @@ **/ -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; +namespace Widgets\Discovery\Actions; -class CControllerWidgetDiscoveryView extends CControllerWidget { +use API, + CArrayHelper, + CControllerDashboardWidgetView, + CControllerResponseData, + CRoleHelper, + CWebUser; - public function __construct() { - parent::__construct(); +class WidgetView extends CControllerDashboardWidgetView { - $this->setType(WIDGET_DISCOVERY); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } - - protected function doAction() { + protected function doAction(): void { if ($this->getUserType() >= USER_TYPE_ZABBIX_ADMIN) { $drules = API::DRule()->get([ 'output' => ['druleid', 'name'], @@ -65,7 +62,7 @@ class CControllerWidgetDiscoveryView extends CControllerWidget { } $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'drules' => $drules, 'error' => $error, 'user' => [ diff --git a/ui/widgets/discovery/manifest.json b/ui/widgets/discovery/manifest.json new file mode 100755 index 00000000000..ccd3eef7e4c --- /dev/null +++ b/ui/widgets/discovery/manifest.json @@ -0,0 +1,15 @@ +{ + "manifest_version": 2.0, + "id": "discovery", + "type": "widget", + "name": "Discovery status", + "namespace": "Discovery", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "size": { + "width": 6, + "height": 3 + } + } +} diff --git a/ui/app/views/monitoring.widget.discovery.view.php b/ui/widgets/discovery/views/widget.view.php index 93946fb6e59..e6d825dce63 100644 --- a/ui/app/views/monitoring.widget.discovery.view.php +++ b/ui/widgets/discovery/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,6 +20,8 @@ /** + * Discovery status widget view. + * * @var CView $this * @var array $data */ @@ -45,24 +47,12 @@ else { ->setArgument('filter_druleids', [$drule['druleid']]) ) : $drule['name'], - ($drule['up'] != 0) ? (new CSpan($drule['up']))->addClass(ZBX_STYLE_GREEN) : '', - ($drule['down'] != 0) ? (new CSpan($drule['down']))->addClass(ZBX_STYLE_RED) : '' + $drule['up'] != 0 ? (new CSpan($drule['up']))->addClass(ZBX_STYLE_GREEN) : '', + $drule['down'] != 0 ? (new CSpan($drule['down']))->addClass(ZBX_STYLE_RED) : '' ]); } } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/favgraphs/Widget.php b/ui/widgets/favgraphs/Widget.php new file mode 100755 index 00000000000..c27391cd799 --- /dev/null +++ b/ui/widgets/favgraphs/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\FavGraphs; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Favorite graphs'); + } +} diff --git a/ui/app/controllers/CControllerWidgetFavGraphsView.php b/ui/widgets/favgraphs/actions/WidgetView.php index aafc056e4a1..458729dbbb3 100644 --- a/ui/app/controllers/CControllerWidgetFavGraphsView.php +++ b/ui/widgets/favgraphs/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,26 +19,23 @@ **/ -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; +namespace Widgets\FavGraphs\Actions; -class CControllerWidgetFavGraphsView extends CControllerWidget { +use API, + CArrayHelper, + CControllerDashboardWidgetView, + CControllerResponseData, + CFavorite, + CRoleHelper; - public function __construct() { - parent::__construct(); +class WidgetView extends CControllerDashboardWidgetView { - $this->setType(WIDGET_FAV_GRAPHS); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } - - protected function doAction() { + protected function doAction(): void { $graphs = []; $itemids = []; - foreach (CFavorite::get('web.favorite.graphids') as $favourite) { - $itemids[$favourite['value']] = true; + foreach (CFavorite::get('web.favorite.graphids') as $favorite) { + $itemids[$favorite['value']] = true; } if ($itemids) { @@ -60,7 +57,7 @@ class CControllerWidgetFavGraphsView extends CControllerWidget { CArrayHelper::sort($graphs, ['label']); $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'graphs' => $graphs, 'user' => [ 'debug_mode' => $this->getDebugMode() diff --git a/ui/widgets/favgraphs/manifest.json b/ui/widgets/favgraphs/manifest.json new file mode 100755 index 00000000000..18e13ed26d3 --- /dev/null +++ b/ui/widgets/favgraphs/manifest.json @@ -0,0 +1,16 @@ +{ + "manifest_version": 2.0, + "id": "favgraphs", + "type": "widget", + "name": "Favorite graphs", + "namespace": "FavGraphs", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "size": { + "width": 4, + "height": 3 + }, + "refresh_rate": 900 + } +} diff --git a/ui/app/views/monitoring.widget.favgraphs.view.php b/ui/widgets/favgraphs/views/widget.view.php index c3e3b1b7e6b..a9db81a4202 100644 --- a/ui/app/views/monitoring.widget.favgraphs.view.php +++ b/ui/widgets/favgraphs/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,7 +20,10 @@ /** + * Favorite graphs widget view. + * * @var CView $this + * @var array $data */ $table = (new CTableInfo())->setNoDataMessage(_('No graphs added.')); @@ -43,18 +46,6 @@ foreach ($data['graphs'] as $graph) { ]); } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/favmaps/Widget.php b/ui/widgets/favmaps/Widget.php new file mode 100755 index 00000000000..b1ddd4f5d80 --- /dev/null +++ b/ui/widgets/favmaps/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\FavMaps; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Favorite maps'); + } +} diff --git a/ui/app/controllers/CControllerWidgetFavMapsView.php b/ui/widgets/favmaps/actions/WidgetView.php index ca139c25f7f..3921422e912 100644 --- a/ui/app/controllers/CControllerWidgetFavMapsView.php +++ b/ui/widgets/favmaps/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,26 +19,23 @@ **/ -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; +namespace Widgets\FavMaps\Actions; -class CControllerWidgetFavMapsView extends CControllerWidget { +use API, + CArrayHelper, + CControllerDashboardWidgetView, + CControllerResponseData, + CFavorite, + CRoleHelper; - public function __construct() { - parent::__construct(); +class WidgetView extends CControllerDashboardWidgetView { - $this->setType(WIDGET_FAV_MAPS); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } - - protected function doAction() { + protected function doAction(): void { $maps = []; $mapids = []; - foreach (CFavorite::get('web.favorite.sysmapids') as $favourite) { - $mapids[$favourite['value']] = true; + foreach (CFavorite::get('web.favorite.sysmapids') as $favorite) { + $mapids[$favorite['value']] = true; } if ($mapids) { @@ -58,7 +55,7 @@ class CControllerWidgetFavMapsView extends CControllerWidget { CArrayHelper::sort($maps, ['label']); $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', CWidgetConfig::getKnownWidgetTypes($this->getContext())[WIDGET_FAV_MAPS]), + 'name' => $this->getInput('name', $this->widget !== null ? $this->widget->getDefaultName() : ''), 'maps' => $maps, 'user' => [ 'debug_mode' => $this->getDebugMode() diff --git a/ui/widgets/favmaps/manifest.json b/ui/widgets/favmaps/manifest.json new file mode 100755 index 00000000000..3ea016df3de --- /dev/null +++ b/ui/widgets/favmaps/manifest.json @@ -0,0 +1,16 @@ +{ + "manifest_version": 2.0, + "id": "favmaps", + "type": "widget", + "name": "Favorite maps", + "namespace": "FavMaps", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "size": { + "width": 4, + "height": 3 + }, + "refresh_rate": 900 + } +} diff --git a/ui/app/views/monitoring.widget.favmaps.view.php b/ui/widgets/favmaps/views/widget.view.php index c0ddad1e7f4..21e940cd8ff 100644 --- a/ui/app/views/monitoring.widget.favmaps.view.php +++ b/ui/widgets/favmaps/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,7 +20,10 @@ /** + * Favorite maps widget view. + * * @var CView $this + * @var array $data */ $table = (new CTableInfo())->setNoDataMessage(_('No maps added.')); @@ -42,18 +45,6 @@ foreach ($data['maps'] as $map) { ]); } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/geomap/Widget.php b/ui/widgets/geomap/Widget.php new file mode 100755 index 00000000000..5a3c82ae937 --- /dev/null +++ b/ui/widgets/geomap/Widget.php @@ -0,0 +1,57 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Geomap; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Geomap'); + } + + public function getTranslationStrings(): array { + return [ + 'class.widget.js' => [ + 'Actions' => _('Actions'), + 'Set this view as default' => _('Set this view as default'), + 'Reset to initial view' => _('Reset to initial view'), + 'No problems' => _('No problems'), + 'Not classified' => _('Not classified'), + 'Information' => _('Information'), + 'Warning' => _('Warning'), + 'Average' => _('Average'), + 'High' => _('High'), + 'Disaster' => _('Disaster'), + 'Host' => _('Host'), + 'D' => _x('D', 'abbreviation of severity level'), + 'H' => _x('H', 'abbreviation of severity level'), + 'A' => _x('A', 'abbreviation of severity level'), + 'W' => _x('W', 'abbreviation of severity level'), + 'I' => _x('I', 'abbreviation of severity level'), + 'N' => _x('N', 'abbreviation of severity level'), + 'Navigate to default view' => _('Navigate to default view'), + 'Navigate to initial view' => _('Navigate to initial view') + ] + ]; + } +} diff --git a/ui/app/controllers/CControllerWidgetGeoMapView.php b/ui/widgets/geomap/actions/WidgetView.php index a0264e2e9ea..895bd55d149 100644 --- a/ui/app/controllers/CControllerWidgetGeoMapView.php +++ b/ui/widgets/geomap/actions/WidgetView.php @@ -19,50 +19,45 @@ **/ -class CControllerWidgetGeoMapView extends CControllerWidget { +namespace Widgets\Geomap\Actions; - const NO_PROBLEMS_MARKER_COLOR = '#009900'; +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CGeomapCoordinatesParser, + CParser, + CProfile, + CSettingsHelper, + CSeverityHelper; - /** - * Widget id. - * - * @param string - */ - protected $widgetid; +class WidgetView extends CControllerDashboardWidgetView { - /** - * Widget fields. - * - * @param array - */ - protected $fields; + private const NO_PROBLEMS_MARKER_COLOR = '#009900'; + + protected string $widgetid; /** * Global geomap configuration. * * @param array */ - protected $geomap_config; + protected array $geomap_config; - public function __construct() { - parent::__construct(); + protected function init(): void { + parent::init(); - $this->setType(WIDGET_GEOMAP); - $this->setValidationRules([ - 'name' => 'string', + $this->addValidationRules([ 'initial_load' => 'in 0,1', 'widgetid' => 'db widget.widgetid', - 'unique_id' => 'required|string', - 'fields' => 'json' + 'unique_id' => 'required|string' ]); } - protected function doAction() { + protected function doAction(): void { $this->widgetid = $this->getInput('widgetid', 0); - $this->fields = $this->getForm()->getFieldsData(); $data = [ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'hosts' => self::convertToRFC7946($this->getHosts()), 'user' => [ 'debug_mode' => $this->getDebugMode() @@ -83,39 +78,18 @@ class CControllerWidgetGeoMapView extends CControllerWidget { } /** - * Create an array of problem severity colors. - * - * @static - * - * @return array - */ - protected static function getSeveritySettings(): array { - $severity_config = [ - -1 => self::NO_PROBLEMS_MARKER_COLOR - ]; - - for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) { - $severity_config[$severity] = '#'.CSeverityHelper::getColor($severity); - } - - return $severity_config; - } - - /** * Get hosts and their properties to show on the map as markers. - * - * @return array */ - protected function getHosts(): array { - $filter_groupids = $this->fields['groupids'] ? getSubGroups($this->fields['groupids']) : null; + private function getHosts(): array { + $filter_groupids = $this->fields_values['groupids'] ? getSubGroups($this->fields_values['groupids']) : null; $hosts = API::Host()->get([ 'output' => ['hostid', 'name'], 'selectInventory' => ['location_lat', 'location_lon'], 'groupids' => $filter_groupids, - 'hostids' => $this->fields['hostids'] ? $this->fields['hostids'] : null, - 'evaltype' => $this->fields['evaltype'], - 'tags' => $this->fields['tags'], + 'hostids' => $this->fields_values['hostids'] ?: null, + 'evaltype' => $this->fields_values['evaltype'], + 'tags' => $this->fields_values['tags'], 'filter' => [ 'inventory_mode' => [HOST_INVENTORY_MANUAL, HOST_INVENTORY_AUTOMATIC] ], @@ -123,7 +97,7 @@ class CControllerWidgetGeoMapView extends CControllerWidget { 'preservekeys' => true ]); - $hosts = array_filter($hosts, function ($host) { + $hosts = array_filter($hosts, static function ($host) { $lat = $host['inventory']['location_lat']; $lng = $host['inventory']['location_lon']; @@ -174,7 +148,7 @@ class CControllerWidgetGeoMapView extends CControllerWidget { $severity_filter = ($severity_filter !== '') ? array_flip(explode(',', $severity_filter)) : []; if ($severity_filter && count($severity_filter) != 7) { - $hosts = array_filter($hosts, function ($host) use ($severity_filter, $problems_by_host) { + $hosts = array_filter($hosts, static function ($host) use ($severity_filter, $problems_by_host) { return array_key_exists($host['hostid'], $problems_by_host) ? (bool) array_intersect_key(array_filter($problems_by_host[$host['hostid']]), $severity_filter) : array_key_exists(-1, $severity_filter); @@ -202,10 +176,8 @@ class CControllerWidgetGeoMapView extends CControllerWidget { /** * Get initial map center point, zoom level and coordinates to center when clicking on navigate home button. - * - * @return array */ - protected function getMapCenter(): array { + private function getMapCenter(): array { $geoloc_parser = new CGeomapCoordinatesParser(); $home_coords = []; $center = []; @@ -217,9 +189,9 @@ class CControllerWidgetGeoMapView extends CControllerWidget { $center['zoom'] = min($this->geomap_config['max_zoom'], $center['zoom']); } - if (array_key_exists('default_view', $this->fields) - && $this->fields['default_view'] !== '' - && $geoloc_parser->parse($this->fields['default_view']) == CParser::PARSE_SUCCESS) { + if (array_key_exists('default_view', $this->fields_values) + && $this->fields_values['default_view'] !== '' + && $geoloc_parser->parse($this->fields_values['default_view']) == CParser::PARSE_SUCCESS) { $initial_view = $geoloc_parser->result; if (array_key_exists('zoom', $initial_view)) { @@ -242,56 +214,59 @@ class CControllerWidgetGeoMapView extends CControllerWidget { ]; return [ - 'center' => $center ? $center : $defaults, + 'center' => $center ?: $defaults, 'home_coords' => $home_coords ]; } + private function getUserProfileFilter(): array { + return [ + 'severity' => CProfile::get('web.dashboard.widget.geomap.severity_filter', [], $this->widgetid) + ]; + } + /** * Get global map configuration. - * - * @static - * - * @return array */ - protected static function getMapConfig(): array { + private static function getMapConfig(): array { if (CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_PROVIDER) === '') { - $config = [ + return [ 'tile_url' => CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_URL), 'max_zoom' => CSettingsHelper::get(CSettingsHelper::GEOMAPS_MAX_ZOOM), 'attribution' => CSettingsHelper::get(CSettingsHelper::GEOMAPS_ATTRIBUTION) ]; } - else { - $tile_provider = getTileProviders()[CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_PROVIDER)]; - $config = [ - 'tile_url' => $tile_provider['geomaps_tile_url'], - 'max_zoom' => $tile_provider['geomaps_max_zoom'], - 'attribution' => $tile_provider['geomaps_attribution'] - ]; - } + $tile_provider = getTileProviders()[CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_PROVIDER)]; - return $config; + return [ + 'tile_url' => $tile_provider['geomaps_tile_url'], + 'max_zoom' => $tile_provider['geomaps_max_zoom'], + 'attribution' => $tile_provider['geomaps_attribution'] + ]; } - protected function getUserProfileFilter(): array { - return [ - 'severity' => CProfile::get('web.dashboard.widget.geomap.severity_filter', [], $this->widgetid) + /** + * Create an array of problem severity colors. + */ + private static function getSeveritySettings(): array { + $severity_config = [ + -1 => self::NO_PROBLEMS_MARKER_COLOR ]; + + for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) { + $severity_config[$severity] = '#'.CSeverityHelper::getColor($severity); + } + + return $severity_config; } /** * Convert array of hosts to valid GeoJSON (RFC7946) object. - * - * @static - * - * @param array $hosts - * - * @return array */ - protected static function convertToRFC7946(array $hosts) : array { + private static function convertToRFC7946(array $hosts) : array { $geo_json = []; + foreach ($hosts as $host) { $problems = array_filter($host['problems']); $severities = array_keys($problems); diff --git a/ui/js/widgets/class.widget.geomap.js b/ui/widgets/geomap/assets/js/class.widget.js index 600093bc471..1d115d87f5a 100644..100755 --- a/ui/js/widgets/class.widget.geomap.js +++ b/ui/widgets/geomap/assets/js/class.widget.js @@ -46,10 +46,23 @@ class CWidgetGeoMap extends CWidget { } _processUpdateResponse(response) { - super._processUpdateResponse(response); + if (this._initial_load) { + super._processUpdateResponse(response); + } + else { + let message_box = this._content_body.querySelector('output'); + + if (message_box !== null) { + message_box.remove(); + } - if ('geomap' in response) { - if ('config' in response.geomap) { + if (response.messages !== undefined) { + this._content_body.prepend(makeMessageBox('bad', response.messages)[0]); + } + } + + if (response.geomap !== undefined) { + if (response.geomap.config !== undefined) { this._initMap(response.geomap.config); } @@ -59,30 +72,10 @@ class CWidgetGeoMap extends CWidget { this._initial_load = false; } - updateProperties({name, view_mode, fields, configuration}) { + updateProperties({name, view_mode, fields}) { this._initial_load = true; - super.updateProperties({name, view_mode, fields, configuration}); - } - - _setContents({name, body, messages, info, debug}) { - this._setHeaderName(name); - - if (this._initial_load) { - this._content_body.innerHTML = ''; - } - - if (messages !== undefined) { - this._content_body.insertAdjacentHTML('beforeend', messages); - } - - if (this._initial_load) { - this._content_body.insertAdjacentHTML('beforeend', body); - } - - if (debug !== undefined) { - this._content_body.insertAdjacentHTML('beforeend', debug); - } + super.updateProperties({name, view_mode, fields}); } _addMarkers(hosts) { diff --git a/ui/widgets/geomap/includes/WidgetForm.php b/ui/widgets/geomap/includes/WidgetForm.php new file mode 100644 index 00000000000..83add4ae233 --- /dev/null +++ b/ui/widgets/geomap/includes/WidgetForm.php @@ -0,0 +1,60 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Geomap\Includes; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldLatLng, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldRadioButtonList, + CWidgetFieldTags +}; + +/** + * Geomap widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectHost('hostids', _('Hosts')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ]))->setDefault(TAG_EVAL_TYPE_AND_OR) + ) + ->addField( + new CWidgetFieldTags('tags') + ) + ->addField( + new CWidgetFieldLatLng('default_view', _('Initial view')) + ); + } +} diff --git a/ui/widgets/geomap/manifest.json b/ui/widgets/geomap/manifest.json new file mode 100755 index 00000000000..0de69c9350a --- /dev/null +++ b/ui/widgets/geomap/manifest.json @@ -0,0 +1,15 @@ +{ + "manifest_version": 2.0, + "id": "geomap", + "type": "widget", + "name": "Geomap", + "namespace": "Geomap", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "js_class": "CWidgetGeoMap" + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/widgets/geomap/views/widget.edit.php b/ui/widgets/geomap/views/widget.edit.php new file mode 100755 index 00000000000..90f9a562fef --- /dev/null +++ b/ui/widgets/geomap/views/widget.edit.php @@ -0,0 +1,48 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Geomap widget form view. + * + * @var CView $this + * @var array $data + */ + +$groupids = new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], + $data['captions']['ms']['groups']['groupids'] +); + +(new CWidgetFormView($data)) + ->addField($groupids) + ->addField( + (new CWidgetFieldMultiSelectHostView($data['fields']['hostids'], $data['captions']['ms']['hosts']['hostids'])) + ->setFilterPreselect(['id' => $groupids->getId(), 'submit_as' => 'groupid']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['evaltype']) + ) + ->addField( + new CWidgetFieldTagsView($data['fields']['tags']) + ) + ->addField( + (new CWidgetFieldLatLngView($data['fields']['default_view']))->setPlaceholder('40.6892494,-74.0466891') + ) + ->show(); diff --git a/ui/widgets/geomap/views/widget.view.php b/ui/widgets/geomap/views/widget.view.php new file mode 100644 index 00000000000..5d8775d6b5c --- /dev/null +++ b/ui/widgets/geomap/views/widget.view.php @@ -0,0 +1,34 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Geomap widget view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetView($data)) + ->addItem( + (new CDiv())->setId($data['unique_id']) + ) + ->setVar('geomap', array_intersect_key($data, array_flip(['config', 'hosts']))) + ->show(); diff --git a/ui/widgets/graph/Widget.php b/ui/widgets/graph/Widget.php new file mode 100755 index 00000000000..a0bdfbe9c52 --- /dev/null +++ b/ui/widgets/graph/Widget.php @@ -0,0 +1,40 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Graph; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Graph (classic)'); + } + + public function getTranslationStrings(): array { + return [ + 'class.widget.js' => [ + 'Actions' => _s('Actions'), + 'Download image' => _s('Download image') + ] + ]; + } +} diff --git a/ui/app/controllers/CControllerWidgetGraphView.php b/ui/widgets/graph/actions/WidgetView.php index ea69a05caa7..e42e320df37 100644 --- a/ui/app/controllers/CControllerWidgetGraphView.php +++ b/ui/widgets/graph/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,25 +19,34 @@ **/ -class CControllerWidgetGraphView extends CControllerWidget { +namespace Widgets\Graph\Actions; - public function __construct() { - parent::__construct(); +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CGraphDraw, + CMacrosResolverHelper, + CRoleHelper, + CUrl, + CWebUser; - $this->setType(WIDGET_GRAPH); - $this->setValidationRules([ - 'name' => 'string', +use Zabbix\Core\CWidget; + +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'edit_mode' => 'in 0,1', 'dashboardid' => 'db dashboard.dashboardid', - 'fields' => 'json', 'dynamic_hostid' => 'db hosts.hostid', 'content_width' => 'int32', 'content_height' => 'int32' ]); } - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); + protected function doAction(): void { $edit_mode = (int) $this->getInput('edit_mode', 0); $width = (int) $this->getInput('content_width', 100); @@ -48,18 +57,20 @@ class CControllerWidgetGraphView extends CControllerWidget { $profileIdx = 'web.dashboard.filter'; $profileIdx2 = $this->getInput('dashboardid', 0); $is_resource_available = true; - $header_name = $this->getDefaultName(); + $header_name = $this->widget->getDefaultName(); - if ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH && $fields['graphid']) { + if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH && $this->fields_values['graphid']) { $resource_type = SCREEN_RESOURCE_GRAPH; - $resourceid = reset($fields['graphid']); + $resourceid = reset($this->fields_values['graphid']); $graph_dims = getGraphDims($resourceid); $graph_dims['graphHeight'] = $height; $graph_dims['width'] = $width; } - elseif ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH && $fields['itemid']) { + elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH + && $this->fields_values['itemid']) { + $resource_type = SCREEN_RESOURCE_SIMPLE_GRAPH; - $resourceid = $fields['itemid'][0]; + $resourceid = $this->fields_values['itemid'][0]; $graph_dims = getGraphDims(); $graph_dims['graphHeight'] = $height; $graph_dims['width'] = $width; @@ -68,7 +79,7 @@ class CControllerWidgetGraphView extends CControllerWidget { $resource_type = null; $graph_dims = getGraphDims(); } - $graph_dims['shiftYtop'] = CLineGraphDraw::DEFAULT_TOP_BOTTOM_PADDING; + $graph_dims['shiftYtop'] = CGraphDraw::DEFAULT_TOP_BOTTOM_PADDING; $time_control_data = [ 'id' => '', @@ -88,13 +99,13 @@ class CControllerWidgetGraphView extends CControllerWidget { 'profileIdx2' => $profileIdx2 ]; - $is_template_dashboard = ($this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD); - $is_dynamic_item = ($is_template_dashboard || $fields['dynamic'] == WIDGET_DYNAMIC_ITEM); + $is_template_dashboard = $this->hasInput('templateid'); + $is_dynamic_item = ($is_template_dashboard || $this->fields_values['dynamic'] == CWidget::DYNAMIC_ITEM); // Replace graph item by particular host item if dynamic items are used. if ($is_dynamic_item && $dynamic_hostid != 0 && $resourceid) { // Find same simple-graph item in selected $dynamic_hostid host. - if ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) { + if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) { $src_items = API::Item()->get([ 'output' => ['key_'], 'itemids' => $resourceid, @@ -120,7 +131,7 @@ class CControllerWidgetGraphView extends CControllerWidget { } } // Find requested host and change graph details. - elseif ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) { + elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) { // get host $hosts = API::Host()->get([ 'output' => ['hostid', 'host', 'name'], @@ -200,7 +211,7 @@ class CControllerWidgetGraphView extends CControllerWidget { if (!$resourceid) { $is_resource_available = false; } - elseif ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) { + elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) { $items = API::Item()->get([ 'output' => ['name', 'key_', 'delay', 'hostid'], 'selectHosts' => ['name'], @@ -214,7 +225,7 @@ class CControllerWidgetGraphView extends CControllerWidget { $is_resource_available = false; } } - elseif ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) { + elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) { // get graph, used below $graph = API::Graph()->get([ 'output' => API_OUTPUT_EXTEND, @@ -232,7 +243,7 @@ class CControllerWidgetGraphView extends CControllerWidget { if ($is_resource_available) { // Build graph action and data source links. - if ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) { + if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) { if (!$edit_mode) { $time_control_data['loadSBox'] = 1; } @@ -242,26 +253,26 @@ class CControllerWidgetGraphView extends CControllerWidget { ->setArgument('itemids', [$resourceid]) ->setArgument('width', $width) ->setArgument('height', $height) - ->setArgument('legend', $fields['show_legend']); + ->setArgument('legend', $this->fields_values['show_legend']); } else { $graph_src = new CUrl('chart3.php'); } $graph_src - ->setArgument('from', '') - ->setArgument('to', ''); + ->setArgument('from') + ->setArgument('to'); $header_name = $is_template_dashboard ? $item['name'] : $item['hosts'][0]['name'].NAME_DELIMITER.$item['name']; } - elseif ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) { + elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) { $graph_src = ''; $prepend_host_name = $is_template_dashboard ? false - : (count($graph['hosts']) == 1 || $is_dynamic_item && $dynamic_hostid != 0); + : count($graph['hosts']) == 1 || ($is_dynamic_item && $dynamic_hostid != 0); $header_name = $prepend_host_name ? $graph['hosts'][0]['name'].NAME_DELIMITER.$graph['name'] @@ -320,9 +331,9 @@ class CControllerWidgetGraphView extends CControllerWidget { $graph_src ->setArgument('width', $width) ->setArgument('height', $height) - ->setArgument('legend', ($fields['show_legend'] && $graph['show_legend']) ? 1 : 0) - ->setArgument('from', '') - ->setArgument('to', ''); + ->setArgument('legend', $this->fields_values['show_legend'] && $graph['show_legend'] ? 1 : 0) + ->setArgument('from') + ->setArgument('to'); } $graph_src @@ -340,7 +351,7 @@ class CControllerWidgetGraphView extends CControllerWidget { $graph_url = null; } else { - if ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) { + if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) { $has_host_graph = $is_dynamic_item && $dynamic_hostid != 0 ? (bool) API::Graph()->get([ 'output' => [], @@ -359,8 +370,8 @@ class CControllerWidgetGraphView extends CControllerWidget { ->setArgument('filter_name', $graph['name']) ->setArgument('filter_show', GRAPH_FILTER_HOST) ->setArgument('filter_set', '1') - ->setArgument('from', '') - ->setArgument('to', '') + ->setArgument('from') + ->setArgument('to') : null; } else { @@ -371,8 +382,8 @@ class CControllerWidgetGraphView extends CControllerWidget { $graph_url = $this->checkAccess(CRoleHelper::UI_MONITORING_LATEST_DATA) ? (new CUrl('history.php')) ->setArgument('itemids', [$resourceid]) - ->setArgument('from', '') - ->setArgument('to', '') + ->setArgument('from') + ->setArgument('to') : null; } } diff --git a/ui/js/widgets/class.widget.graph.js b/ui/widgets/graph/assets/js/class.widget.js index 0222248600c..22f077b0979 100644..100755 --- a/ui/js/widgets/class.widget.graph.js +++ b/ui/widgets/graph/assets/js/class.widget.js @@ -72,14 +72,14 @@ class CWidgetGraph extends CWidget { } } - updateProperties({name, view_mode, fields, configuration}) { + updateProperties({name, view_mode, fields}) { if (this._state === WIDGET_STATE_ACTIVE) { this._stopUpdating(true); } this._is_graph_mode = false; - super.updateProperties({name, view_mode, fields, configuration}); + super.updateProperties({name, view_mode, fields}); } setEditMode() { @@ -229,4 +229,8 @@ class CWidgetGraph extends CWidget { return menu; } + + _hasPadding() { + return true; + } } diff --git a/ui/widgets/graph/includes/WidgetForm.php b/ui/widgets/graph/includes/WidgetForm.php new file mode 100644 index 00000000000..5b57cf414aa --- /dev/null +++ b/ui/widgets/graph/includes/WidgetForm.php @@ -0,0 +1,84 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Graph\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldMultiSelectGraph, + CWidgetFieldMultiSelectItem, + CWidgetFieldRadioButtonList +}; + +/** + * Graph (classic) widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + $this->addField( + (new CWidgetFieldRadioButtonList('source_type', _('Source'), [ + ZBX_WIDGET_FIELD_RESOURCE_GRAPH => _('Graph'), + ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH => _('Simple graph') + ])) + ->setDefault(ZBX_WIDGET_FIELD_RESOURCE_GRAPH) + ->setAction('ZABBIX.Dashboard.reloadWidgetProperties()') + ); + + if (array_key_exists('source_type', $this->values) + && $this->values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) { + + $field_item = (new CWidgetFieldMultiSelectItem('itemid', _('Item'), $this->templateid)) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ->setMultiple(false) + ->setFilterParameter('numeric', true); + + if ($this->templateid === null) { + $field_item->setFilterParameter('with_simple_graph_items', true); + } + + $this->addField($field_item); + } + else { + $this->addField( + (new CWidgetFieldMultiSelectGraph('graphid', _('Graph'), $this->templateid)) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ->setMultiple(false) + ); + } + + $this + ->addField( + (new CWidgetFieldCheckBox('show_legend', _('Show legend')))->setDefault(1) + ) + ->addField($this->templateid === null + ? new CWidgetFieldCheckBox('dynamic', _('Enable host selection')) + : null + ); + + return $this; + } +} diff --git a/ui/widgets/graph/manifest.json b/ui/widgets/graph/manifest.json new file mode 100755 index 00000000000..678aa28c550 --- /dev/null +++ b/ui/widgets/graph/manifest.json @@ -0,0 +1,17 @@ +{ + "manifest_version": 2.0, + "id": "graph", + "type": "widget", + "name": "Graph (classic)", + "namespace": "Graph", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "template_support": true, + "js_class": "CWidgetGraph", + "use_time_selector": true + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/include/classes/widgets/views/widget.actionlog.form.view.php b/ui/widgets/graph/views/widget.edit.php index 06591ee02d0..b88316c64df 100644..100755 --- a/ui/include/classes/widgets/views/widget.actionlog.form.view.php +++ b/ui/widgets/graph/views/widget.edit.php @@ -20,35 +20,29 @@ /** - * Action log widget form view. + * Graph (classic) widget form view. * * @var CView $this * @var array $data */ -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Sort entries by. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['sort_triggers']), - new CFormField(CWidgetHelper::getSelect($fields['sort_triggers'])) -]); - -// Show lines. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['show_lines']), - new CFormField(CWidgetHelper::getIntegerBox($fields['show_lines'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form -]; +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['source_type']) + ) + ->addField(array_key_exists('graphid', $data['fields']) + ? new CWidgetFieldMultiSelectGraphView($data['fields']['graphid'], $data['captions']['ms']['graphs']['graphid']) + : null + ) + ->addField(array_key_exists('itemid', $data['fields']) + ? new CWidgetFieldMultiSelectItemView($data['fields']['itemid'], $data['captions']['ms']['items']['itemid']) + : null + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_legend']) + ) + ->addField(array_key_exists('dynamic', $data['fields']) + ? new CWidgetFieldCheckBoxView($data['fields']['dynamic']) + : null + ) + ->show(); diff --git a/ui/widgets/graph/views/widget.view.php b/ui/widgets/graph/views/widget.view.php new file mode 100644 index 00000000000..5b77fa37c54 --- /dev/null +++ b/ui/widgets/graph/views/widget.view.php @@ -0,0 +1,49 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Graph (classic) widget view. + * + * @var CView $this + * @var array $data + */ + +$view = new CWidgetView($data); + +if ($data['is_resource_available']) { + $view + ->addItem( + (new CDiv()) + ->addClass('flickerfreescreen') + ->addItem( + (new CLink(null, $data['widget']['graph_url'] ?? 'javascript:void(0)')) + ->addClass(ZBX_STYLE_DASHBOARD_WIDGET_GRAPH_LINK) + ) + ) + ->setVar('async_data', $data['widget']); +} +else { + $view->addItem( + (new CTableInfo())->setNoDataMessage(_('No permissions to referred object or it does not exist!')) + ); +} + +$view->show(); diff --git a/ui/widgets/graphprototype/Widget.php b/ui/widgets/graphprototype/Widget.php new file mode 100755 index 00000000000..4c21e63d00b --- /dev/null +++ b/ui/widgets/graphprototype/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\GraphPrototype; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Graph prototype'); + } +} diff --git a/ui/app/controllers/CControllerWidgetIteratorGraphPrototypeView.php b/ui/widgets/graphprototype/actions/WidgetView.php index 367d8120a2a..556e573c0f2 100644 --- a/ui/app/controllers/CControllerWidgetIteratorGraphPrototypeView.php +++ b/ui/widgets/graphprototype/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,28 +19,35 @@ **/ -class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetIterator { +namespace Widgets\GraphPrototype\Actions; - public function __construct() { - parent::__construct(); +use API, + APP, + CControllerResponseData, + CControllerWidgetIterator, + CTableInfo; - $this->setType(WIDGET_GRAPH_PROTOTYPE); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json', +use Zabbix\Core\CWidget; + +class WidgetView extends CControllerWidgetIterator { + + protected const GRAPH_WIDGET_ID = 'graph'; + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'view_mode' => 'in '.implode(',', [ZBX_WIDGET_VIEW_MODE_NORMAL, ZBX_WIDGET_VIEW_MODE_HIDDEN_HEADER]), 'dynamic_hostid' => 'db hosts.hostid' ]); } - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - - if ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH_PROTOTYPE) { - $data = $this->doGraphPrototype($fields); + protected function doAction(): void { + if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH_PROTOTYPE) { + $data = $this->doGraphPrototype(); } - elseif ($fields['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH_PROTOTYPE) { - $data = $this->doSimpleGraphPrototype($fields); + elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH_PROTOTYPE) { + $data = $this->doSimpleGraphPrototype(); } else { error(_('Page received incorrect data')); @@ -50,25 +57,23 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera $data['error']['messages'] = array_column($messages, 'message'); } - $this->setResponse(new CControllerResponseData(['main_block' => json_encode($data)])); + $this->setResponse(new CControllerResponseData(['main_block' => json_encode($data, JSON_THROW_ON_ERROR)])); } /** * Get graph prototype widget data for graph prototype source. * - * @param array $fields Widget form fields data - * * @return array Dashboard response data */ - protected function doGraphPrototype(array $fields) { + protected function doGraphPrototype(): array { $options = [ 'output' => ['graphid', 'name'], 'selectHosts' => ['hostid', 'name'], 'selectDiscoveryRule' => ['hostid'] ]; - $is_template_dashboard = ($this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD); - $is_dynamic_item = ($is_template_dashboard || $fields['dynamic'] == WIDGET_DYNAMIC_ITEM); + $is_template_dashboard = $this->hasInput('templateid'); + $is_dynamic_item = ($is_template_dashboard || $this->fields_values['dynamic'] == CWidget::DYNAMIC_ITEM); $dynamic_hostid = $this->getInput('dynamic_hostid', 0); @@ -76,7 +81,7 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera // The key of the actual graph prototype selected on widget's edit form. $graph_prototype = API::GraphPrototype()->get([ 'output' => ['name'], - 'graphids' => reset($fields['graphid']) + 'graphids' => reset($this->fields_values['graphid']) ]); if ($graph_prototype) { $graph_prototype = reset($graph_prototype); @@ -91,7 +96,7 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera } else { // Just fetch the item prototype selected on widget's edit form. - $options['graphids'] = reset($fields['graphid']); + $options['graphids'] = reset($this->fields_values['graphid']); } // Use this graph prototype as base for collecting created graphs. @@ -121,7 +126,7 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera if ($graph['graphDiscovery']['parent_graphid'] === $graph_prototype['graphid']) { $prepend_host_name = $is_template_dashboard ? false - : (count($graph['hosts']) == 1 || $is_dynamic_item && $dynamic_hostid != 0); + : count($graph['hosts']) == 1 || ($is_dynamic_item && $dynamic_hostid != 0); $graphs_collected[$graph['graphid']] = $prepend_host_name ? $graph['hosts'][0]['name'].NAME_DELIMITER.$graph['name'] @@ -140,21 +145,24 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera $children = []; - foreach ($graphs_collected as $graphid => $name) { - $child_fields = [ - 'source_type' => ZBX_WIDGET_FIELD_RESOURCE_GRAPH, - 'graphid' => $graphid, - 'show_legend' => $fields['show_legend'] - ]; - - $children[] = [ - 'widgetid' => (string) $graphid, - 'type' => WIDGET_GRAPH, - 'name' => $name, - 'fields' => $child_fields, - 'configuration' => CWidgetConfig::getConfiguration(WIDGET_GRAPH, $fields, $this->getInput('view_mode')), - 'defaults' => CWidgetConfig::getDefaults($this->getContext())[WIDGET_GRAPH] - ]; + $widget = APP::ModuleManager()->getModule(self::GRAPH_WIDGET_ID); + + if ($widget !== null) { + foreach ($graphs_collected as $graphid => $name) { + $child_fields = [ + 'source_type' => ZBX_WIDGET_FIELD_RESOURCE_GRAPH, + 'graphid' => $graphid, + 'show_legend' => $this->fields_values['show_legend'] + ]; + + $children[] = [ + 'widgetid' => (string) $graphid, + 'type' => self::GRAPH_WIDGET_ID, + 'name' => $name, + 'fields' => $child_fields, + 'defaults' => $widget->getDefaults() + ]; + } } if ($this->hasInput('name')) { @@ -179,20 +187,16 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera /** * Get graph prototype widget data for simple graph prototype source. - * - * @param array $fields Widget form fields data - * - * @return array Dashboard response data */ - protected function doSimpleGraphPrototype(array $fields) { + protected function doSimpleGraphPrototype(): array { $options = [ 'output' => ['itemid', 'name'], 'selectHosts' => ['name'], 'selectDiscoveryRule' => ['hostid'] ]; - $is_template_dashboard = ($this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD); - $is_dynamic_item = ($is_template_dashboard || $fields['dynamic'] == WIDGET_DYNAMIC_ITEM); + $is_template_dashboard = $this->hasInput('templateid'); + $is_dynamic_item = ($is_template_dashboard || $this->fields_values['dynamic'] == CWidget::DYNAMIC_ITEM); $dynamic_hostid = $this->getInput('dynamic_hostid', 0); @@ -200,7 +204,7 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera // The key of the actual item prototype selected on widget's edit form. $item_prototype = API::ItemPrototype()->get([ 'output' => ['key_'], - 'itemids' => reset($fields['itemid']) + 'itemids' => reset($this->fields_values['itemid']) ]); if ($item_prototype) { $item_prototype = reset($item_prototype); @@ -215,7 +219,7 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera } else { // Just fetch the item prototype selected on widget's edit form. - $options['itemids'] = reset($fields['itemid']); + $options['itemids'] = reset($this->fields_values['itemid']); } // Use this item prototype as base for collecting created items. @@ -262,21 +266,24 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera $children = []; - foreach ($items_collected as $itemid => $name) { - $child_fields = [ - 'source_type' => ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH, - 'itemid' => $itemid, - 'show_legend' => $fields['show_legend'] - ]; - - $children[] = [ - 'widgetid' => (string) $itemid, - 'type' => WIDGET_GRAPH, - 'name' => $name, - 'fields' => $child_fields, - 'configuration' => CWidgetConfig::getConfiguration(WIDGET_GRAPH, $fields, $this->getInput('view_mode')), - 'defaults' => CWidgetConfig::getDefaults($this->getContext())[WIDGET_GRAPH] - ]; + $widget = APP::ModuleManager()->getModule(self::GRAPH_WIDGET_ID); + + if ($widget !== null) { + foreach ($items_collected as $itemid => $name) { + $child_fields = [ + 'source_type' => ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH, + 'itemid' => $itemid, + 'show_legend' => $this->fields_values['show_legend'] + ]; + + $children[] = [ + 'widgetid' => (string) $itemid, + 'type' => self::GRAPH_WIDGET_ID, + 'name' => $name, + 'fields' => $child_fields, + 'defaults' => $widget->getDefaults() + ]; + } } if ($this->hasInput('name')) { @@ -297,13 +304,11 @@ class CControllerWidgetIteratorGraphPrototypeView extends CControllerWidgetItera } /** - * Get graph prototype widget data for no permissions error. - * - * @return array Dashboard response data + * Get graph prototype widget data for no permission's error. */ - protected function inaccessibleError() { + protected function inaccessibleError(): array { return [ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'body' => (new CTableInfo()) ->setNoDataMessage(_('No permissions to referred object or it does not exist!')) ->toString() diff --git a/ui/js/widgets/class.widget.graph-prototype.js b/ui/widgets/graphprototype/assets/js/class.widget.js index 8d2e194b8aa..6cb0cd11537 100644..100755 --- a/ui/js/widgets/class.widget.graph-prototype.js +++ b/ui/widgets/graphprototype/assets/js/class.widget.js @@ -23,4 +23,8 @@ class CWidgetGraphPrototype extends CWidgetIterator { _updateWidget(widget) { widget.resize(); } + + _hasPadding() { + return false; + } } diff --git a/ui/widgets/graphprototype/includes/WidgetForm.php b/ui/widgets/graphprototype/includes/WidgetForm.php new file mode 100644 index 00000000000..3107c113949 --- /dev/null +++ b/ui/widgets/graphprototype/includes/WidgetForm.php @@ -0,0 +1,102 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\GraphPrototype\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldIntegerBox, + CWidgetFieldMultiSelectGraphPrototype, + CWidgetFieldMultiSelectItemPrototype, + CWidgetFieldRadioButtonList +}; + +/** + * Graph prototype widget form. + */ +class WidgetForm extends CWidgetForm { + + private const DEFAULT_COLUMNS_COUNT = 2; + private const DEFAULT_ROWS_COUNT = 1; + + public function addFields(): self { + $this->addField( + (new CWidgetFieldRadioButtonList('source_type', _('Source'), [ + ZBX_WIDGET_FIELD_RESOURCE_GRAPH_PROTOTYPE => _('Graph prototype'), + ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH_PROTOTYPE => _('Simple graph prototype') + ])) + ->setDefault(ZBX_WIDGET_FIELD_RESOURCE_GRAPH_PROTOTYPE) + ->setAction('ZABBIX.Dashboard.reloadWidgetProperties()') + ); + + if (array_key_exists('source_type', $this->values) + && $this->values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH_PROTOTYPE) { + + $field_item_prototype = (new CWidgetFieldMultiSelectItemPrototype('itemid', _('Item prototype'), + $this->templateid + )) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ->setMultiple(false) + ->setFilterParameter('numeric', true); + + if ($this->templateid === null) { + $field_item_prototype->setFilterParameter('with_simple_graph_item_prototypes', true); + } + + $this->addField($field_item_prototype); + } + else { + $this->addField( + (new CWidgetFieldMultiSelectGraphPrototype('graphid', _('Graph prototype'), $this->templateid)) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ->setMultiple(false) + ); + } + + $this + ->addField( + (new CWidgetFieldCheckBox('show_legend', _('Show legend')))->setDefault(1) + ) + ->addField($this->templateid === null + ? new CWidgetFieldCheckBox('dynamic', _('Enable host selection')) + : null + ) + ->addField( + (new CWidgetFieldIntegerBox('columns', _('Columns'), 1, DASHBOARD_MAX_COLUMNS)) + ->setDefault(self::DEFAULT_COLUMNS_COUNT) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField( + (new CWidgetFieldIntegerBox('rows', _('Rows'), 1, + floor(DASHBOARD_WIDGET_MAX_ROWS / DASHBOARD_WIDGET_MIN_ROWS) + )) + ->setDefault(self::DEFAULT_ROWS_COUNT) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ); + + return $this; + } +} diff --git a/ui/widgets/graphprototype/manifest.json b/ui/widgets/graphprototype/manifest.json new file mode 100755 index 00000000000..ae1feb40df3 --- /dev/null +++ b/ui/widgets/graphprototype/manifest.json @@ -0,0 +1,27 @@ +{ + "manifest_version": 2.0, + "id": "graphprototype", + "type": "widget", + "name": "Graph prototype", + "namespace": "GraphPrototype", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "template_support": true, + "size": { + "width": 16, + "height": 5 + }, + "js_class": "CWidgetGraphPrototype", + "use_time_selector": true + }, + "actions": { + "widget.graphprototype.view": { + "layout": "layout.json", + "view": null + } + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/widgets/graphprototype/views/widget.edit.php b/ui/widgets/graphprototype/views/widget.edit.php new file mode 100755 index 00000000000..4f7bdafbdd1 --- /dev/null +++ b/ui/widgets/graphprototype/views/widget.edit.php @@ -0,0 +1,58 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Graph prototype widget form view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['source_type']) + ) + ->addField(array_key_exists('graphid', $data['fields']) + ? new CWidgetFieldMultiSelectGraphPrototypeView($data['fields']['graphid'], + $data['captions']['ms']['graph_prototypes']['graphid'] + ) + : null + ) + ->addField(array_key_exists('itemid', $data['fields']) + ? new CWidgetFieldMultiSelectItemPrototypeView($data['fields']['itemid'], + $data['captions']['ms']['item_prototypes']['itemid'] + ) + : null + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_legend']) + ) + ->addField(array_key_exists('dynamic', $data['fields']) + ? new CWidgetFieldCheckBoxView($data['fields']['dynamic']) + : null + ) + ->addField( + new CWidgetFieldIntegerBoxView($data['fields']['columns']) + ) + ->addField( + new CWidgetFieldIntegerBoxView($data['fields']['rows']) + ) + ->show(); diff --git a/ui/widgets/hostavail/Widget.php b/ui/widgets/hostavail/Widget.php new file mode 100755 index 00000000000..940838ff348 --- /dev/null +++ b/ui/widgets/hostavail/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\HostAvail; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Host availability'); + } +} diff --git a/ui/app/controllers/CControllerWidgetHostAvailView.php b/ui/widgets/hostavail/actions/WidgetView.php index db696075f0e..42c27b2dc53 100644 --- a/ui/app/controllers/CControllerWidgetHostAvailView.php +++ b/ui/widgets/hostavail/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,29 +19,26 @@ **/ -class CControllerWidgetHostAvailView extends CControllerWidget { +namespace Widgets\HostAvail\Actions; - public function __construct() { - parent::__construct(); +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CItemGeneral; - $this->setType(WIDGET_HOST_AVAIL); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } +class WidgetView extends CControllerDashboardWidgetView { - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - - $interface_types = CItem::INTERFACE_TYPES_BY_PRIORITY; + protected function doAction(): void { + $interface_types = CItemGeneral::INTERFACE_TYPES_BY_PRIORITY; // Sanitize non-existing interface types. - $fields['interface_type'] = array_values(array_intersect($interface_types, $fields['interface_type'])); + $this->fields_values['interface_type'] = array_values( + array_intersect($interface_types, $this->fields_values['interface_type']) + ); - $groupids = $fields['groupids'] ? getSubGroups($fields['groupids']) : null; + $groupids = $this->fields_values['groupids'] ? getSubGroups($this->fields_values['groupids']) : null; - $hosts_types = $fields['interface_type'] ? $fields['interface_type'] : $interface_types; + $hosts_types = $this->fields_values['interface_type'] ?: $interface_types; $hosts_total = array_fill_keys($interface_types, 0); $hosts_count = array_fill_keys($interface_types, [ @@ -54,10 +51,11 @@ class CControllerWidgetHostAvailView extends CControllerWidget { 'output' => [], 'selectInterfaces' => ['type', 'available'], 'groupids' => $groupids, - 'filter' => ($fields['maintenance'] == HOST_MAINTENANCE_STATUS_OFF) + 'filter' => $this->fields_values['maintenance'] == HOST_MAINTENANCE_STATUS_OFF ? ['status' => HOST_STATUS_MONITORED, 'maintenance_status' => HOST_MAINTENANCE_STATUS_OFF] : ['status' => HOST_STATUS_MONITORED] ]); + $availability_priority = [INTERFACE_AVAILABLE_FALSE, INTERFACE_AVAILABLE_UNKNOWN, INTERFACE_AVAILABLE_TRUE]; foreach ($db_hosts as $host) { @@ -78,8 +76,8 @@ class CControllerWidgetHostAvailView extends CControllerWidget { } $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), - 'layout' => $fields['layout'], + 'name' => $this->getInput('name', $this->widget->getDefaultName()), + 'layout' => $this->fields_values['layout'], 'hosts_types' => $hosts_types, 'hosts_count' => $hosts_count, 'hosts_total' => $hosts_total, diff --git a/ui/widgets/hostavail/assets/js/class.widget.js b/ui/widgets/hostavail/assets/js/class.widget.js new file mode 100644 index 00000000000..da3018177b7 --- /dev/null +++ b/ui/widgets/hostavail/assets/js/class.widget.js @@ -0,0 +1,27 @@ +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +class CWidgetHostAvail extends CWidget { + + _hasPadding() { + return this._view_mode == ZBX_WIDGET_VIEW_MODE_NORMAL + && (this._fields.interface_type === undefined || this._fields.interface_type.length !== 1); + } +} diff --git a/ui/widgets/hostavail/includes/WidgetForm.php b/ui/widgets/hostavail/includes/WidgetForm.php new file mode 100644 index 00000000000..9fb67d845b9 --- /dev/null +++ b/ui/widgets/hostavail/includes/WidgetForm.php @@ -0,0 +1,61 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\HostAvail\Includes; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldCheckBoxList, + CWidgetFieldMultiSelectGroup, + CWidgetFieldRadioButtonList +}; + +/** + * Host availability widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldCheckBoxList('interface_type', _('Interface type'), [ + INTERFACE_TYPE_AGENT => _('Zabbix agent'), + INTERFACE_TYPE_SNMP => _('SNMP'), + INTERFACE_TYPE_JMX => _('JMX'), + INTERFACE_TYPE_IPMI => _('IPMI') + ]) + ) + ->addField( + (new CWidgetFieldRadioButtonList('layout', _('Layout'), [ + STYLE_HORIZONTAL => _('Horizontal'), + STYLE_VERTICAL => _('Vertical') + ]))->setDefault(STYLE_HORIZONTAL) + ) + ->addField( + new CWidgetFieldCheckBox('maintenance', _('Show hosts in maintenance')) + ); + } +} diff --git a/ui/widgets/hostavail/manifest.json b/ui/widgets/hostavail/manifest.json new file mode 100755 index 00000000000..c900192643e --- /dev/null +++ b/ui/widgets/hostavail/manifest.json @@ -0,0 +1,20 @@ +{ + "manifest_version": 2.0, + "id": "hostavail", + "type": "widget", + "name": "Host availability", + "namespace": "HostAvail", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "js_class": "CWidgetHostAvail", + "size": { + "width": 6, + "height": 3 + }, + "refresh_rate": 900 + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/include/classes/widgets/views/widget.discovery.form.view.php b/ui/widgets/hostavail/views/widget.edit.php index 830ec0dd161..61c853f1ecd 100644..100755 --- a/ui/include/classes/widgets/views/widget.discovery.form.view.php +++ b/ui/widgets/hostavail/views/widget.edit.php @@ -20,23 +20,23 @@ /** - * Discovery status widget form view. + * Host availability widget form view. * * @var CView $this * @var array $data */ -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -$form->addItem($form_grid); - -return [ - 'form' => $form -]; +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], $data['captions']['ms']['groups']['groupids']) + ) + ->addField( + new CWidgetFieldCheckBoxListView($data['fields']['interface_type']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['layout']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['maintenance']) + ) + ->show(); diff --git a/ui/app/views/monitoring.widget.hostavail.view.php b/ui/widgets/hostavail/views/widget.view.php index 94ca2a936c4..d85f1361486 100644 --- a/ui/app/views/monitoring.widget.hostavail.view.php +++ b/ui/widgets/hostavail/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,6 +20,8 @@ /** + * Host availability widget view. + * * @var CView $this * @var array $data */ @@ -113,18 +115,6 @@ else { } } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/item/Widget.php b/ui/widgets/item/Widget.php new file mode 100755 index 00000000000..9a151d3b6f7 --- /dev/null +++ b/ui/widgets/item/Widget.php @@ -0,0 +1,55 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Item; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + // Form blocks. + public const SHOW_DESCRIPTION = 1; + public const SHOW_VALUE = 2; + public const SHOW_TIME = 3; + public const SHOW_CHANGE_INDICATOR = 4; + + // Objects positions. + public const POSITION_LEFT = 0; + public const POSITION_CENTER = 1; + public const POSITION_RIGHT = 2; + + public const POSITION_TOP = 0; + public const POSITION_MIDDLE = 1; + public const POSITION_BOTTOM = 2; + + public const POSITION_BEFORE = 0; + public const POSITION_ABOVE = 1; + public const POSITION_AFTER = 2; + public const POSITION_BELOW = 3; + + public const CHANGE_INDICATOR_UP = 1; + public const CHANGE_INDICATOR_DOWN = 2; + public const CHANGE_INDICATOR_UP_DOWN = 3; + + public function getDefaultName(): string { + return _('Item value'); + } +} diff --git a/ui/app/controllers/CControllerWidgetItemView.php b/ui/widgets/item/actions/WidgetView.php index 43b4632b8bc..2e12a94b87d 100644 --- a/ui/app/controllers/CControllerWidgetItemView.php +++ b/ui/widgets/item/actions/WidgetView.php @@ -19,29 +19,36 @@ **/ -class CControllerWidgetItemView extends CControllerWidget { +namespace Widgets\Item\Actions; - public const CHANGE_INDICATOR_UP = 1; - public const CHANGE_INDICATOR_DOWN = 2; - public const CHANGE_INDICATOR_UP_DOWN = 3; +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CMacrosResolverHelper, + CSettingsHelper, + CUrl, + CValueMapHelper, + Manager; - public function __construct() { - parent::__construct(); +use Widgets\Item\Widget; - $this->setType(WIDGET_ITEM); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json', +use Zabbix\Core\CWidget; + +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'dynamic_hostid' => 'db hosts.hostid' ]); } - protected function doAction() { - $name = $this->getDefaultName(); + protected function doAction(): void { + $name = $this->widget->getDefaultName(); $cells = []; $url = null; $error = ''; - $fields = $this->getForm()->getFieldsData(); $history_period = timeUnitToSeconds(CSettingsHelper::get(CSettingsHelper::HISTORY_PERIOD)); $description = ''; $value = null; @@ -50,15 +57,26 @@ class CControllerWidgetItemView extends CControllerWidget { $units = ''; $decimals = null; $last_value = null; + + $options = [ + 'output' => ['value_type'], + 'selectValueMap' => ['mappings'], + 'itemids' => $this->fields_values['itemid'], + 'webitems' => true, + 'preservekeys' => true + ]; + + $is_template_dashboard = $this->hasInput('templateid'); $is_dynamic = ($this->hasInput('dynamic_hostid') - && ($this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - || $fields['dynamic'] == WIDGET_DYNAMIC_ITEM) + && ($is_template_dashboard || $this->fields_values['dynamic'] == CWidget::DYNAMIC_ITEM) ); + $tmp_items = []; + if ($is_dynamic) { $tmp_items = API::Item()->get([ 'output' => ['key_'], - 'itemids' => $fields['itemid'], + 'itemids' => $this->fields_values['itemid'], 'webitems' => true ]); @@ -75,17 +93,8 @@ class CControllerWidgetItemView extends CControllerWidget { ]; } } - else { - $options = [ - 'output' => ['value_type'], - 'selectValueMap' => ['mappings'], - 'itemids' => $fields['itemid'], - 'webitems' => true, - 'preservekeys' => true - ]; - } - $show = array_flip($fields['show']); + $show = array_flip($this->fields_values['show']); /* * Select original item name in several cases: if user is in normal dashboards or in template dashboards when @@ -93,25 +102,23 @@ class CControllerWidgetItemView extends CControllerWidget { * overwritten. Host name can be attached to item name with delimiter when user is in normal dashboards. */ if ($this->getInput('name', '') === '') { - if ($this->getContext() === CWidgetConfig::CONTEXT_DASHBOARD - || $this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - && $this->hasInput('dynamic_hostid') && $tmp_items) { + if (!$is_template_dashboard || ($this->hasInput('dynamic_hostid') && $tmp_items)) { $options['output'] = array_merge($options['output'], ['name']); } - if ($this->getContext() === CWidgetConfig::CONTEXT_DASHBOARD) { + if (!$is_template_dashboard) { $options['selectHosts'] = ['name']; } } // Add other fields in case current widget is set in dynamic mode, template dashboard or has a specified host. - if ($is_dynamic && $tmp_items || !$is_dynamic) { + if (($is_dynamic && $tmp_items) || !$is_dynamic) { // If description contains user macros, we need "itemid" and "hostid" to resolve them. - if (array_key_exists(WIDGET_ITEM_SHOW_DESCRIPTION, $show)) { + if (array_key_exists(Widget::SHOW_DESCRIPTION, $show)) { $options['output'] = array_merge($options['output'], ['itemid', 'hostid']); } - if (array_key_exists(WIDGET_ITEM_SHOW_VALUE, $show) && $fields['units_show'] == 1) { + if (array_key_exists(Widget::SHOW_VALUE, $show) && $this->fields_values['units_show'] == 1) { $options['output'][] = 'units'; } } @@ -128,8 +135,8 @@ class CControllerWidgetItemView extends CControllerWidget { else { $items = API::Item()->get($options); - if ($fields['itemid']) { - $itemid = $fields['itemid'][0]; + if ($this->fields_values['itemid']) { + $itemid = $this->fields_values['itemid'][0]; } } @@ -143,7 +150,7 @@ class CControllerWidgetItemView extends CControllerWidget { $last_value = $history[$itemid][0]['value']; // Time can be shown independently. - if (array_key_exists(WIDGET_ITEM_SHOW_TIME, $show)) { + if (array_key_exists(Widget::SHOW_TIME, $show)) { $time = date(ZBX_FULL_DATE_TIME, (int) $history[$itemid][0]['clock']); } @@ -151,17 +158,17 @@ class CControllerWidgetItemView extends CControllerWidget { case ITEM_VALUE_TYPE_FLOAT: case ITEM_VALUE_TYPE_UINT64: // Override item units if needed. - if (array_key_exists(WIDGET_ITEM_SHOW_VALUE, $show) && $fields['units_show'] == 1) { - $units = ($fields['units'] === '') + if (array_key_exists(Widget::SHOW_VALUE, $show) && $this->fields_values['units_show'] == 1) { + $units = $this->fields_values['units'] === '' ? $items[$itemid]['units'] - : $fields['units']; + : $this->fields_values['units']; } // Apply unit conversion always because it will also convert values to scientific notation. $raw_units = convertUnitsRaw([ 'value' => $last_value, 'units' => $units, - 'decimals' => $fields['decimal_places'] + 'decimals' => $this->fields_values['decimal_places'] ]); // Get the converted value (this is not the final value). $value = $raw_units['value']; @@ -179,7 +186,7 @@ class CControllerWidgetItemView extends CControllerWidget { * to 10 (maximum), the value will be converted to 0.0012340000. */ if ($raw_units['is_numeric']) { - $value = self::convertNumeric($value, $fields['decimal_places'], $value_type); + $value = self::convertNumeric($value, $this->fields_values['decimal_places'], $value_type); } /* @@ -202,12 +209,12 @@ class CControllerWidgetItemView extends CControllerWidget { ); // Show of hide change indicator for mapped value. - if (array_key_exists(WIDGET_ITEM_SHOW_CHANGE_INDICATOR, $show)) { - $change_indicator = self::CHANGE_INDICATOR_UP_DOWN; + if (array_key_exists(Widget::SHOW_CHANGE_INDICATOR, $show)) { + $change_indicator = Widget::CHANGE_INDICATOR_UP_DOWN; } } elseif (array_key_exists(1, $history[$itemid]) - && array_key_exists(WIDGET_ITEM_SHOW_CHANGE_INDICATOR, $show)) { + && array_key_exists(Widget::SHOW_CHANGE_INDICATOR, $show)) { /* * If there is no value mapping and there is more than one value, add up or down change * indicator. Do not show change indicator if value is the same. @@ -215,10 +222,10 @@ class CControllerWidgetItemView extends CControllerWidget { $prev_value = $history[$itemid][1]['value']; if ($last_value > $prev_value) { - $change_indicator = self::CHANGE_INDICATOR_UP; + $change_indicator = Widget::CHANGE_INDICATOR_UP; } elseif ($last_value < $prev_value) { - $change_indicator = self::CHANGE_INDICATOR_DOWN; + $change_indicator = Widget::CHANGE_INDICATOR_DOWN; } } break; @@ -234,7 +241,7 @@ class CControllerWidgetItemView extends CControllerWidget { ); if ($mapping !== false) { - // Currently it is same as in latest data with original value in parenthesis. + // Currently, it is same as in the latest data with original value in parentheses. $value = $mapping.' ('.$value.')'; } @@ -245,11 +252,11 @@ class CControllerWidgetItemView extends CControllerWidget { $value = str_replace("\n", " ", $value); if (array_key_exists(1, $history[$itemid]) - && array_key_exists(WIDGET_ITEM_SHOW_CHANGE_INDICATOR, $show)) { + && array_key_exists(Widget::SHOW_CHANGE_INDICATOR, $show)) { $prev_value = $history[$itemid][1]['value']; if ($last_value !== $prev_value) { - $change_indicator = self::CHANGE_INDICATOR_UP_DOWN; + $change_indicator = Widget::CHANGE_INDICATOR_UP_DOWN; } } break; @@ -259,36 +266,32 @@ class CControllerWidgetItemView extends CControllerWidget { $value_type = ITEM_VALUE_TYPE_TEXT; // Since there is no value, we can still show time. - if (array_key_exists(WIDGET_ITEM_SHOW_TIME, $show)) { + if (array_key_exists(Widget::SHOW_TIME, $show)) { $time = date(ZBX_FULL_DATE_TIME); } } if ($this->getInput('name', '') === '') { - if ($this->getContext() === CWidgetConfig::CONTEXT_DASHBOARD - || $this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - && $this->hasInput('dynamic_hostid')) { + if (!$is_template_dashboard || $this->hasInput('dynamic_hostid')) { // Resolve original item name when user is in normal dashboards or template dashboards view mode. $name = $items[$itemid]['name']; } - if ($this->getContext() === CWidgetConfig::CONTEXT_DASHBOARD) { + if (!$is_template_dashboard) { $name = $items[$itemid]['hosts'][0]['name'].NAME_DELIMITER.$name; } } /* * It doesn't matter if item has value or not, description can be resolved separately if needed. If item - * will have value it will resolve, otherwise it will not. + * will have value, it will resolve, otherwise it will not. */ - if (array_key_exists(WIDGET_ITEM_SHOW_DESCRIPTION, $show)) { + if (array_key_exists(Widget::SHOW_DESCRIPTION, $show)) { // Overwrite item name with the custom description. - $items[$itemid]['name'] = $fields['description']; + $items[$itemid]['name'] = $this->fields_values['description']; // Do not resolve macros if using template dashboard. Template dashboards only have edit mode. - if ($this->getContext() === CWidgetConfig::CONTEXT_DASHBOARD - || $this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD - && $this->hasInput('dynamic_hostid')) { + if (!$is_template_dashboard || $this->hasInput('dynamic_hostid')) { $items = CMacrosResolverHelper::resolveWidgetItemNames($items); } @@ -296,7 +299,7 @@ class CControllerWidgetItemView extends CControllerWidget { $description = $items[$itemid]['name']; } - $cells = self::arrangeByCells($fields, [ + $cells = self::arrangeByCells($this->fields_values, [ 'description' => $description, 'value_type' => $value_type, 'units' => $units, @@ -322,10 +325,10 @@ class CControllerWidgetItemView extends CControllerWidget { $error = _('No permissions to referred object or it does not exist!'); } - $bg_color = $fields['bg_color']; + $bg_color = $this->fields_values['bg_color']; if ($last_value !== null) { - foreach ($fields['thresholds'] as $threshold) { + foreach ($this->fields_values['thresholds'] as $threshold) { if ($threshold['threshold_value'] > $last_value) { break; } @@ -356,7 +359,7 @@ class CControllerWidgetItemView extends CControllerWidget { * @return string */ private static function convertNumeric(string $value, int $decimals, string $value_type): string { - if ($value >= pow(10, ZBX_FLOAT_DIG)) { + if ($value >= (10 ** ZBX_FLOAT_DIG)) { return sprintf('%.'.ZBX_FLOAT_DIG.'E', $value); } @@ -376,118 +379,118 @@ class CControllerWidgetItemView extends CControllerWidget { * * @static * - * @param array $fields Input fields from the form. - * @param array $fields['show'] Flags to show description, value, time and change indicator. - * @param int $fields['desc_v_pos'] Vertical position of the description. - * @param int $fields['desc_h_pos'] Horizontal position of the description. - * @param int $fields['desc_bold'] Font weight of the description (0 - normal, 1 - bold). - * @param int $fields['desc_size'] Font size of the description. - * @param string $fields['desc_color'] Font color of the description. - * @param int $fields['value_v_pos'] Vertical position of the value. - * @param int $fields['value_h_pos'] Horizontal position of the value. - * @param int $fields['value_bold'] Font weight of the value (0 - normal, 1 - bold). - * @param int $fields['value_size'] Font size of the value. - * @param string $fields['value_color'] Font color of the value. - * @param int $fields['units_show'] Display units or not (0 - hide, 1 - show). - * @param int $fields['units_pos'] Position of the units. - * @param int $fields['units_bold'] Font weight of the units (0 - normal, 1 - bold). - * @param int $fields['units_size'] Font size of the units. - * @param string $fields['units_color'] Font color of the units. - * @param int $fields['decimal_size'] Font size of the fraction. - * @param int $fields['time_v_pos'] Vertical position of the time. - * @param int $fields['time_h_pos'] Horizontal position of the time. - * @param int $fields['time_bold'] Font weight of the time (0 - normal, 1 - bold). - * @param int $fields['time_size'] Font size of the time. - * @param string $fields['time_color'] Font color of the time. - * @param array $values Array of pre-processed data that needs to be displayed. - * @param string $values['description'] Item description with all macros resolved. - * @param string $values['value_type'] Calculated value type. It can be integer or text. - * @param string $values['units'] Units of the item. Can be empty string if nothing to show. - * @param string|null $values['value'] Value of the item or NULL if there is no value. - * @param string|null $values['decimals'] Decimal places or NULL if there is no decimals to show. - * @param int|null $values['change_indicator'] Change indicator type or NULL if indicator should not be shown. - * @param string $values['time'] Time when item received the value or current time if no data. - * @param array $values['items'] The original array of items. - * @param string $values['itemid'] Item ID from the host. + * @param array $fields_values Input fields from the form. + * @param array $fields_values ['show'] Flags to show description, value, time and change indicator. + * @param int $fields_values ['desc_v_pos'] Vertical position of the description. + * @param int $fields_values ['desc_h_pos'] Horizontal position of the description. + * @param int $fields_values ['desc_bold'] Font weight of the description (0 - normal, 1 - bold). + * @param int $fields_values ['desc_size'] Font size of the description. + * @param string $fields_values ['desc_color'] Font color of the description. + * @param int $fields_values ['value_v_pos'] Vertical position of the value. + * @param int $fields_values ['value_h_pos'] Horizontal position of the value. + * @param int $fields_values ['value_bold'] Font weight of the value (0 - normal, 1 - bold). + * @param int $fields_values ['value_size'] Font size of the value. + * @param string $fields_values ['value_color'] Font color of the value. + * @param int $fields_values ['units_show'] Display units or not (0 - hide, 1 - show). + * @param int $fields_values ['units_pos'] Position of the units. + * @param int $fields_values ['units_bold'] Font weight of the units (0 - normal, 1 - bold). + * @param int $fields_values ['units_size'] Font size of the units. + * @param string $fields_values ['units_color'] Font color of the units. + * @param int $fields_values ['decimal_size'] Font size of the fraction. + * @param int $fields_values ['time_v_pos'] Vertical position of the time. + * @param int $fields_values ['time_h_pos'] Horizontal position of the time. + * @param int $fields_values ['time_bold'] Font weight of the time (0 - normal, 1 - bold). + * @param int $fields_values ['time_size'] Font size of the time. + * @param string $fields_values ['time_color'] Font color of the time. + * @param array $data Array of pre-processed data that needs to be displayed. + * @param string $data ['description'] Item description with all macros resolved. + * @param string $data ['value_type'] Calculated value type. It can be integer or text. + * @param string $data ['units'] Units of the item. Can be empty string if nothing to show. + * @param string|null $data ['value'] Value of the item or NULL if there is no value. + * @param string|null $data ['decimals'] Decimal places or NULL if there is no decimals to show. + * @param int|null $data ['change_indicator'] Change indicator type or NULL if indicator should not be shown. + * @param string $data ['time'] Time when item received the value or current time if no data. + * @param array $data ['items'] The original array of items. + * @param string $data ['itemid'] Item ID from the host. * * @return array */ - private static function arrangeByCells(array $fields, array $values): array { + private static function arrangeByCells(array $fields_values, array $data): array { $cells = []; - $show = array_flip($fields['show']); + $show = array_flip($fields_values['show']); - if (array_key_exists(WIDGET_ITEM_SHOW_DESCRIPTION, $show)) { - $cells[$fields['desc_v_pos']][$fields['desc_h_pos']] = [ + if (array_key_exists(Widget::SHOW_DESCRIPTION, $show)) { + $cells[$fields_values['desc_v_pos']][$fields_values['desc_h_pos']] = [ 'item_description' => [ - 'text' => $values['description'], - 'font_size' => $fields['desc_size'], - 'bold' => ($fields['desc_bold'] == 1), - 'color' => $fields['desc_color'] + 'text' => $data['description'], + 'font_size' => $fields_values['desc_size'], + 'bold' => ($fields_values['desc_bold'] == 1), + 'color' => $fields_values['desc_color'] ] ]; } - if (array_key_exists(WIDGET_ITEM_SHOW_VALUE, $show)) { + if (array_key_exists(Widget::SHOW_VALUE, $show)) { $item_value_cell = [ - 'value_type' => $values['value_type'] + 'value_type' => $data['value_type'] ]; - if ($fields['units_show'] == 1 && $values['units'] !== '') { + if ($fields_values['units_show'] == 1 && $data['units'] !== '') { $item_value_cell['parts']['units'] = [ - 'text' => $values['units'], - 'font_size' => $fields['units_size'], - 'bold' => ($fields['units_bold'] == 1), - 'color' => $fields['units_color'] + 'text' => $data['units'], + 'font_size' => $fields_values['units_size'], + 'bold' => ($fields_values['units_bold'] == 1), + 'color' => $fields_values['units_color'] ]; - $item_value_cell['units_pos'] = $fields['units_pos']; + $item_value_cell['units_pos'] = $fields_values['units_pos']; } $item_value_cell['parts']['value'] = [ - 'text' => $values['value'], - 'font_size' => $fields['value_size'], - 'bold' => ($fields['value_bold'] == 1), - 'color' => $fields['value_color'] + 'text' => $data['value'], + 'font_size' => $fields_values['value_size'], + 'bold' => ($fields_values['value_bold'] == 1), + 'color' => $fields_values['value_color'] ]; - if ($values['decimals'] !== null) { + if ($data['decimals'] !== null) { $item_value_cell['parts']['decimals'] = [ - 'text' => $values['decimals'], - 'font_size' => $fields['decimal_size'], - 'bold' => ($fields['value_bold'] == 1), - 'color' => $fields['value_color'] + 'text' => $data['decimals'], + 'font_size' => $fields_values['decimal_size'], + 'bold' => ($fields_values['value_bold'] == 1), + 'color' => $fields_values['value_color'] ]; } - $cells[$fields['value_v_pos']][$fields['value_h_pos']] = [ + $cells[$fields_values['value_v_pos']][$fields_values['value_h_pos']] = [ 'item_value' => $item_value_cell ]; } - if (array_key_exists(WIDGET_ITEM_SHOW_CHANGE_INDICATOR, $show) && $values['change_indicator'] !== null) { + if (array_key_exists(Widget::SHOW_CHANGE_INDICATOR, $show) && $data['change_indicator'] !== null) { $colors = [ - self::CHANGE_INDICATOR_UP => $fields['up_color'], - self::CHANGE_INDICATOR_DOWN => $fields['down_color'], - self::CHANGE_INDICATOR_UP_DOWN => $fields['updown_color'] + Widget::CHANGE_INDICATOR_UP => $fields_values['up_color'], + Widget::CHANGE_INDICATOR_DOWN => $fields_values['down_color'], + Widget::CHANGE_INDICATOR_UP_DOWN => $fields_values['updown_color'] ]; // Change indicator can be displayed with or without value. - $cells[$fields['value_v_pos']][$fields['value_h_pos']]['item_value']['parts']['change_indicator'] = [ - 'type' => $values['change_indicator'], - 'font_size' => ($values['decimals'] !== null) - ? max($fields['value_size'], $fields['decimal_size']) - : $fields['value_size'], - 'color' => $colors[$values['change_indicator']] + $cells[$fields_values['value_v_pos']][$fields_values['value_h_pos']]['item_value']['parts']['change_indicator'] = [ + 'type' => $data['change_indicator'], + 'font_size' => ($data['decimals'] !== null) + ? max($fields_values['value_size'], $fields_values['decimal_size']) + : $fields_values['value_size'], + 'color' => $colors[$data['change_indicator']] ]; } - if (array_key_exists(WIDGET_ITEM_SHOW_TIME, $show)) { - $cells[$fields['time_v_pos']][$fields['time_h_pos']] = [ + if (array_key_exists(Widget::SHOW_TIME, $show)) { + $cells[$fields_values['time_v_pos']][$fields_values['time_h_pos']] = [ 'item_time' => [ - 'text' => $values['time'], - 'font_size' => $fields['time_size'], - 'bold' => ($fields['time_bold'] == 1), - 'color' => $fields['time_color'] + 'text' => $data['time'], + 'font_size' => $fields_values['time_size'], + 'bold' => ($fields_values['time_bold'] == 1), + 'color' => $fields_values['time_color'] ] ]; } diff --git a/ui/js/widgets/class.widget.item.js b/ui/widgets/item/assets/js/class.widget.js index 46c488d5ed9..df49766ae7f 100644..100755 --- a/ui/js/widgets/class.widget.item.js +++ b/ui/widgets/item/assets/js/class.widget.js @@ -47,4 +47,8 @@ class CWidgetItem extends CWidget { this._resize_observer.disconnect(); } + + _hasPadding() { + return false; + } } diff --git a/ui/widgets/item/includes/WidgetForm.php b/ui/widgets/item/includes/WidgetForm.php new file mode 100644 index 00000000000..a897683828f --- /dev/null +++ b/ui/widgets/item/includes/WidgetForm.php @@ -0,0 +1,247 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Item\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldCheckBoxList, + CWidgetFieldColor, + CWidgetFieldIntegerBox, + CWidgetFieldMultiSelectItem, + CWidgetFieldRadioButtonList, + CWidgetFieldSelect, + CWidgetFieldTextArea, + CWidgetFieldTextBox, + CWidgetFieldThresholds +}; + +use Widgets\Item\Widget; + +/** + * Single item widget form. + */ +class WidgetForm extends CWidgetForm { + + private const SIZE_PERCENT_MIN = 1; + private const SIZE_PERCENT_MAX = 100; + + private const DEFAULT_DESCRIPTION_SIZE = 15; + private const DEFAULT_DECIMAL_SIZE = 35; + private const DEFAULT_VALUE_SIZE = 45; + private const DEFAULT_UNITS_SIZE = 35; + private const DEFAULT_TIME_SIZE = 15; + + public function validate(bool $strict = false): array { + $errors = parent::validate($strict); + + // Check if one of the objects (description, value or time) occupies same space. + $fields = [ + ['show' => Widget::SHOW_DESCRIPTION, 'h_pos' => 'desc_h_pos', 'v_pos' => 'desc_v_pos'], + ['show' => Widget::SHOW_VALUE, 'h_pos' => 'value_h_pos', 'v_pos' => 'value_v_pos'], + ['show' => Widget::SHOW_TIME, 'h_pos' => 'time_h_pos', 'v_pos' => 'time_v_pos'] + ]; + + $fields_count = count($fields); + $show = $this->getFieldValue('show'); + + for ($i = 0; $i < $fields_count - 1; $i++) { + if (!in_array($fields[$i]['show'], $show)) { + continue; + } + + $i_h_pos = $this->getFieldValue($fields[$i]['h_pos']); + $i_v_pos = $this->getFieldValue($fields[$i]['v_pos']); + + for ($j = $i + 1; $j < $fields_count; $j++) { + if (!in_array($fields[$j]['show'], $show)) { + continue; + } + + $j_h_pos = $this->getFieldValue($fields[$j]['h_pos']); + $j_v_pos = $this->getFieldValue($fields[$j]['v_pos']); + + if ($i_h_pos == $j_h_pos && $i_v_pos == $j_v_pos) { + $errors[] = _('Two or more fields cannot occupy same space.'); + break 2; + } + } + } + + return $errors; + } + + public function addFields(): self { + return $this + ->addField( + (new CWidgetFieldMultiSelectItem('itemid', _('Item'), $this->templateid)) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ->setMultiple(false) + ) + ->addField( + (new CWidgetFieldCheckBoxList('show', _('Show'), [ + Widget::SHOW_DESCRIPTION => _('Description'), + Widget::SHOW_VALUE => _('Value'), + Widget::SHOW_TIME => _('Time'), + Widget::SHOW_CHANGE_INDICATOR => _('Change indicator') + ])) + ->setDefault([Widget::SHOW_DESCRIPTION, Widget::SHOW_VALUE, Widget::SHOW_TIME, + Widget::SHOW_CHANGE_INDICATOR + ]) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField( + new CWidgetFieldCheckBox('adv_conf', _('Advanced configuration')) + ) + ->addField( + (new CWidgetFieldTextArea('description', _('Description'))) + ->setDefault('{ITEM.NAME}') + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField( + (new CWidgetFieldRadioButtonList('desc_h_pos', _('Horizontal position'), [ + Widget::POSITION_LEFT => _('Left'), + Widget::POSITION_CENTER => _('Center'), + Widget::POSITION_RIGHT => _('Right') + ]))->setDefault(Widget::POSITION_CENTER) + ) + ->addField( + (new CWidgetFieldRadioButtonList('desc_v_pos', _('Vertical position'), [ + Widget::POSITION_TOP => _('Top'), + Widget::POSITION_MIDDLE => _('Middle'), + Widget::POSITION_BOTTOM => _('Bottom') + ]))->setDefault(Widget::POSITION_BOTTOM) + ) + ->addField( + (new CWidgetFieldIntegerBox('desc_size', _('Size'), self::SIZE_PERCENT_MIN, self::SIZE_PERCENT_MAX)) + ->setDefault(self::DEFAULT_DESCRIPTION_SIZE) + ) + ->addField( + new CWidgetFieldCheckBox('desc_bold', _('Bold')) + ) + ->addField( + new CWidgetFieldColor('desc_color', _('Color')) + ) + ->addField( + (new CWidgetFieldIntegerBox('decimal_places', _('Decimal places'), 0, 10))->setDefault(2) + ) + ->addField( + (new CWidgetFieldIntegerBox('decimal_size', _('Size'), self::SIZE_PERCENT_MIN, self::SIZE_PERCENT_MAX)) + ->setDefault(self::DEFAULT_DECIMAL_SIZE) + ) + ->addField( + (new CWidgetFieldRadioButtonList('value_h_pos', _('Horizontal position'), [ + Widget::POSITION_LEFT => _('Left'), + Widget::POSITION_CENTER => _('Center'), + Widget::POSITION_RIGHT => _('Right') + ]))->setDefault(Widget::POSITION_CENTER) + ) + ->addField( + (new CWidgetFieldRadioButtonList('value_v_pos', _('Vertical position'), [ + Widget::POSITION_TOP => _('Top'), + Widget::POSITION_MIDDLE => _('Middle'), + Widget::POSITION_BOTTOM => _('Bottom') + ]))->setDefault(Widget::POSITION_MIDDLE) + ) + ->addField( + (new CWidgetFieldIntegerBox('value_size', _('Size'), self::SIZE_PERCENT_MIN, self::SIZE_PERCENT_MAX)) + ->setDefault(self::DEFAULT_VALUE_SIZE) + ) + ->addField( + (new CWidgetFieldCheckBox('value_bold', _('Bold')))->setDefault(1) + ) + ->addField( + new CWidgetFieldColor('value_color', _('Color')) + ) + ->addField( + (new CWidgetFieldCheckBox('units_show', _('Units')))->setDefault(1) + ) + ->addField( + new CWidgetFieldTextBox('units', _('Units')) + ) + ->addField( + (new CWidgetFieldSelect('units_pos', _('Position'), [ + Widget::POSITION_BEFORE => _('Before value'), + Widget::POSITION_ABOVE => _('Above value'), + Widget::POSITION_AFTER => _('After value'), + Widget::POSITION_BELOW => _('Below value') + ]))->setDefault(Widget::POSITION_AFTER) + ) + ->addField( + (new CWidgetFieldIntegerBox('units_size', _('Size'), self::SIZE_PERCENT_MIN, self::SIZE_PERCENT_MAX)) + ->setDefault(self::DEFAULT_UNITS_SIZE) + ) + ->addField( + (new CWidgetFieldCheckBox('units_bold', _('Bold')))->setDefault(1) + ) + ->addField( + new CWidgetFieldColor('units_color', _('Color')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('time_h_pos', _('Horizontal position'), [ + Widget::POSITION_LEFT => _('Left'), + Widget::POSITION_CENTER => _('Center'), + Widget::POSITION_RIGHT => _('Right') + ]))->setDefault(Widget::POSITION_CENTER) + ) + ->addField( + (new CWidgetFieldRadioButtonList('time_v_pos', _('Vertical position'), [ + Widget::POSITION_TOP => _('Top'), + Widget::POSITION_MIDDLE => _('Middle'), + Widget::POSITION_BOTTOM => _('Bottom') + ]))->setDefault(Widget::POSITION_TOP) + ) + ->addField( + (new CWidgetFieldIntegerBox('time_size', _('Size'), self::SIZE_PERCENT_MIN, self::SIZE_PERCENT_MAX)) + ->setDefault(self::DEFAULT_TIME_SIZE) + ) + ->addField( + new CWidgetFieldCheckBox('time_bold', _('Bold')) + ) + ->addField( + new CWidgetFieldColor('time_color', _('Color')) + ) + ->addField( + new CWidgetFieldColor('up_color', _('Change indicator')) + ) + ->addField( + new CWidgetFieldColor('down_color', _('Change indicator')) + ) + ->addField( + new CWidgetFieldColor('updown_color', _('Change indicator')) + ) + ->addField( + new CWidgetFieldColor('bg_color', _('Background color')) + ) + ->addField( + new CWidgetFieldThresholds('thresholds', _('Thresholds')) + ) + ->addField($this->templateid === null + ? new CWidgetFieldCheckBox('dynamic', _('Enable host selection')) + : null + ); + } +} diff --git a/ui/widgets/item/manifest.json b/ui/widgets/item/manifest.json new file mode 100755 index 00000000000..1d3ec5853d7 --- /dev/null +++ b/ui/widgets/item/manifest.json @@ -0,0 +1,20 @@ +{ + "manifest_version": 2.0, + "id": "item", + "type": "widget", + "name": "Item value", + "namespace": "Item", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "template_support": true, + "size": { + "width": 4, + "height": 3 + }, + "js_class": "CWidgetItem" + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/include/classes/widgets/views/js/widget.item.form.view.js.php b/ui/widgets/item/views/widget.edit.js.php index 4da14e1f08d..0988316ae8b 100644..100755 --- a/ui/include/classes/widgets/views/js/widget.item.form.view.js.php +++ b/ui/widgets/item/views/widget.edit.js.php @@ -17,25 +17,28 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -?> +use Widgets\Item\Widget; + +?> + window.widget_item_form = new class { init({thresholds_colors}) { - this.form = document.getElementById('widget-dialogue-form'); + this._form = document.getElementById('widget-dialogue-form'); - this.show_description = document.getElementById(`show_${<?= WIDGET_ITEM_SHOW_DESCRIPTION ?>}`); - this.show_value = document.getElementById(`show_${<?= WIDGET_ITEM_SHOW_VALUE ?>}`); - this.show_time = document.getElementById(`show_${<?= WIDGET_ITEM_SHOW_TIME ?>}`); - this.show_change_indicator = document.getElementById(`show_${<?= WIDGET_ITEM_SHOW_CHANGE_INDICATOR ?>}`); + this._show_description = document.getElementById(`show_${<?= Widget::SHOW_DESCRIPTION ?>}`); + this._show_value = document.getElementById(`show_${<?= Widget::SHOW_VALUE ?>}`); + this._show_time = document.getElementById(`show_${<?= Widget::SHOW_TIME ?>}`); + this._show_change_indicator = document.getElementById(`show_${<?= Widget::SHOW_CHANGE_INDICATOR ?>}`); - this.advance_configuration = document.getElementById('adv_conf'); - this.units_show = document.getElementById('units_show'); + this._advance_configuration = document.getElementById('adv_conf'); + this._units_show = document.getElementById('units_show'); jQuery('#itemid').on('change', () => this.updateWarningIcon()); - for (const colorpicker of this.form.querySelectorAll('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) { + for (const colorpicker of this._form.querySelectorAll('.<?= ZBX_STYLE_COLOR_PICKER ?> input')) { $(colorpicker).colorpicker({ appendTo: ".overlay-dialogue-body", use_default: !colorpicker.name.includes('thresholds'), @@ -45,7 +48,7 @@ window.widget_item_form = new class { }); } - const show = [this.show_description, this.show_value, this.show_time, this.show_change_indicator]; + const show = [this._show_description, this._show_value, this._show_time, this._show_change_indicator]; for (const checkbox of show) { checkbox.addEventListener('change', (e) => { @@ -58,86 +61,81 @@ window.widget_item_form = new class { }); } - for (const checkbox of [this.advance_configuration, this.units_show]) { + for (const checkbox of [this._advance_configuration, this._units_show]) { checkbox.addEventListener('change', () => this.updateForm()); } colorPalette.setThemeColors(thresholds_colors); this.updateForm(); - this.updateWarningIcon(); } updateForm() { - const show_description_row = this.advance_configuration.checked && this.show_description.checked; - const show_value_row = this.advance_configuration.checked && this.show_value.checked; - const show_time_row = this.advance_configuration.checked && this.show_time.checked; - const show_change_indicator_row = this.advance_configuration.checked && this.show_change_indicator.checked; - const show_bg_color_row = this.advance_configuration.checked; - const show_thresholds_row = this.advance_configuration.checked; - - for (const element of this.form.querySelectorAll('.js-row-description')) { + const show_description_row = this._advance_configuration.checked && this._show_description.checked; + const show_value_row = this._advance_configuration.checked && this._show_value.checked; + const show_time_row = this._advance_configuration.checked && this._show_time.checked; + const show_change_indicator_row = this._advance_configuration.checked && this._show_change_indicator.checked; + const show_bg_color_row = this._advance_configuration.checked; + const show_thresholds_row = this._advance_configuration.checked; + + for (const element of this._form.querySelectorAll('.fields-group-description')) { element.style.display = show_description_row ? '' : 'none'; - } - for (const element of this.form.querySelectorAll('.js-row-description input, .js-row-description textarea')) { - element.disabled = !show_description_row; + + for (const input of element.querySelectorAll('input, textarea')) { + input.disabled = !show_description_row; + } } - for (const element of this.form.querySelectorAll('.js-row-value')) { + for (const element of this._form.querySelectorAll('.fields-group-value')) { element.style.display = show_value_row ? '' : 'none'; - } - for (const element of this.form.querySelectorAll('.js-row-value input')) { - element.disabled = !show_value_row; + + for (const input of element.querySelectorAll('input')) { + input.disabled = !show_value_row; + } } for(const element of document.querySelectorAll('#units, #units_pos, #units_size, #units_bold, #units_color')) { - element.disabled = !show_value_row || !this.units_show.checked; + element.disabled = !show_value_row || !this._units_show.checked; } - for (const element of this.form.querySelectorAll('.js-row-time')) { + for (const element of this._form.querySelectorAll('.fields-group-time')) { element.style.display = show_time_row ? '' : 'none'; - } - for (const element of this.form.querySelectorAll('.js-row-time input')) { - element.disabled = !show_time_row; + + for (const input of element.querySelectorAll('input')) { + input.disabled = !show_time_row; + } } - for (const element of this.form.querySelectorAll('.js-row-change-indicator')) { + for (const element of this._form.querySelectorAll('.fields-group-change-indicator')) { element.style.display = show_change_indicator_row ? '' : 'none'; - } - for (const element of this.form.querySelectorAll('.js-row-change-indicator input')) { - element.disabled = !show_change_indicator_row; + + for (const input of element.querySelectorAll('input')) { + input.disabled = !show_change_indicator_row; + } } - for (const element of this.form.querySelectorAll('.js-row-bg-color')) { + for (const element of this._form.querySelectorAll('.js-row-bg-color')) { element.style.display = show_bg_color_row ? '' : 'none'; - } - for (const element of this.form.querySelectorAll('.js-row-bg-color input')) { - element.disabled = !show_bg_color_row; - } - for (const element of this.form.querySelectorAll('.js-row-thresholds')) { - element.style.display = show_thresholds_row ? '' : 'none'; + for (const input of element.querySelectorAll('input')) { + input.disabled = !show_bg_color_row; + } } - for (const element of this.form.querySelectorAll('.js-row-thresholds input')) { - element.disabled = !show_thresholds_row; - } - } - setIndicatorColor(name, color) { - const indicator_ids = { - up_color: 'change-indicator-up', - down_color: 'change-indicator-down', - updown_color: 'change-indicator-updown' - }; + for (const element of this._form.querySelectorAll('.js-row-thresholds')) { + element.style.display = show_thresholds_row ? '' : 'none'; - document.getElementById(indicator_ids[name]) - .querySelector("polygon").style.fill = (color !== '') ? `#${color}` : ''; + for (const input of element.querySelectorAll('input')) { + input.disabled = !show_thresholds_row; + } + } } updateWarningIcon() { - document.getElementById('item-value-thresholds-warning').style.display = 'none'; - + const thresholds_warning = document.getElementById('item-value-thresholds-warning'); const ms_item_data = $('#itemid').multiSelect('getData'); + thresholds_warning.style.display = 'none'; + if (ms_item_data.length > 0) { const curl = new Curl('jsrpc.php', false); curl.setArgument('method', 'item_value_type.get'); @@ -150,10 +148,10 @@ window.widget_item_form = new class { switch (response.result) { case '<?= ITEM_VALUE_TYPE_FLOAT ?>': case '<?= ITEM_VALUE_TYPE_UINT64 ?>': - document.getElementById('item-value-thresholds-warning').style.display = 'none'; + thresholds_warning.style.display = 'none'; break; default: - document.getElementById('item-value-thresholds-warning').style.display = ''; + thresholds_warning.style.display = ''; } }) .catch((exception) => { @@ -161,4 +159,15 @@ window.widget_item_form = new class { }); } } + + setIndicatorColor(name, color) { + const indicator_ids = { + up_color: 'change-indicator-up', + down_color: 'change-indicator-down', + updown_color: 'change-indicator-updown' + }; + + document.getElementById(indicator_ids[name]) + .querySelector("polygon").style.fill = (color !== '') ? `#${color}` : ''; + } }; diff --git a/ui/widgets/item/views/widget.edit.php b/ui/widgets/item/views/widget.edit.php new file mode 100755 index 00000000000..b68f26acae9 --- /dev/null +++ b/ui/widgets/item/views/widget.edit.php @@ -0,0 +1,237 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Item value widget form view. + * + * @var CView $this + * @var array $data + */ + +use Zabbix\Widgets\Fields\CWidgetFieldColumnsList; + +$form = new CWidgetFormView($data); + +$form + ->addField( + new CWidgetFieldMultiSelectItemView($data['fields']['itemid'], $data['captions']['ms']['items']['itemid']) + ) + ->addField( + (new CWidgetFieldCheckBoxListView($data['fields']['show'])) + ->addClass(ZBX_STYLE_GRID_COLUMNS) + ->addClass(ZBX_STYLE_GRID_COLUMNS_2) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['adv_conf']) + ) + ->addFieldsGroup([ + _('Description'), + makeHelpIcon([ + _('Supported macros:'), + (new CList([ + '{HOST.*}', + '{ITEM.*}', + '{INVENTORY.*}', + _('User macros') + ]))->addClass(ZBX_STYLE_LIST_DASHED) + ]) + ], getDescriptionFieldsGroupViews($form, $data['fields']), + 'fields-group-description' + ) + ->addFieldsGroup(_('Value'), getValueFieldsGroupViews($form, $data['fields']), + 'fields-group-value' + ) + ->addFieldsGroup(_('Time'), getTimeFieldsGroupViews($form, $data['fields']), + 'fields-group-time' + ) + ->addFieldsGroup(_('Change indicator'), getChangeIndicatorFieldsGroupViews($form, $data['fields']), + 'fields-group-change-indicator' + ) + ->addField( + new CWidgetFieldColorView($data['fields']['bg_color']), + 'js-row-bg-color' + ) + ->addField( + (new CWidgetFieldThresholdsView($data['fields']['thresholds'])) + ->setHint( + makeWarningIcon(_('This setting applies only to numeric data.'))->setId('item-value-thresholds-warning') + ), + 'js-row-thresholds' + ) + ->addField(array_key_exists('dynamic', $data['fields']) + ? new CWidgetFieldCheckBoxView($data['fields']['dynamic']) + : null + ) + ->includeJsFile('widget.edit.js.php') + ->addJavaScript('widget_item_form.init('.json_encode([ + 'thresholds_colors' => CWidgetFieldColumnsList::THRESHOLDS_DEFAULT_COLOR_PALETTE + ], JSON_THROW_ON_ERROR).');') + ->show(); + +function getDescriptionFieldsGroupViews(CWidgetFormView $form, array $fields): array { + $description = (new CWidgetFieldTextAreaView($fields['description'])) + ->setAdaptiveWidth(ZBX_TEXTAREA_BIG_WIDTH - 38); + $desc_size = new CWidgetFieldIntegerBoxView($fields['desc_size']); + $desc_color = new CWidgetFieldColorView($fields['desc_color']); + + return [ + $form->makeCustomField($description, [ + new CFormField( + $description->getView()->setAttribute('maxlength', DB::getFieldLength('widget_field', 'value_str')) + ) + ]), + + new CWidgetFieldRadioButtonListView($fields['desc_h_pos']), + + $form->makeCustomField($desc_size, [ + $desc_size->getLabel(), + (new CFormField([$desc_size->getView(), '%']))->addClass('field-size') + ]), + + new CWidgetFieldRadioButtonListView($fields['desc_v_pos']), + + new CWidgetFieldCheckBoxView($fields['desc_bold']), + + $form->makeCustomField($desc_color, [ + $desc_color->getLabel()->addClass('offset-3'), + new CFormField($desc_color->getView()) + ]) + ]; +} + +function getValueFieldsGroupViews(CWidgetFormView $form, array $fields): array { + $decimal_size = new CWidgetFieldIntegerBoxView($fields['decimal_size']); + $value_size = new CWidgetFieldIntegerBoxView($fields['value_size']); + $value_color = new CWidgetFieldColorView($fields['value_color']); + $units_show = new CWidgetFieldCheckBoxView($fields['units_show']); + $units = (new CWidgetFieldTextBoxView($fields['units']))->setAdaptiveWidth(ZBX_TEXTAREA_BIG_WIDTH); + $units_size = new CWidgetFieldIntegerBoxView($fields['units_size']); + $units_bold = new CWidgetFieldCheckBoxView($fields['units_bold']); + $units_color = new CWidgetFieldColorView($fields['units_color']); + + return [ + new CWidgetFieldIntegerBoxView($fields['decimal_places']), + + $form->makeCustomField($decimal_size, [ + $decimal_size->getLabel(), + (new CFormField([$decimal_size->getView(), '%']))->addClass('field-size') + ]), + + new CTag('hr'), + + new CWidgetFieldRadioButtonListView($fields['value_h_pos']), + + $form->makeCustomField($value_size, [ + $value_size->getLabel(), + (new CFormField([$value_size->getView(), '%']))->addClass('field-size') + ]), + + new CWidgetFieldRadioButtonListView($fields['value_v_pos']), + + new CWidgetFieldCheckBoxView($fields['value_bold']), + + $form->makeCustomField($value_color, [ + $value_color->getLabel()->addClass('offset-3'), + new CFormField($value_color->getView()) + ]), + + new CTag('hr'), + + (new CDiv([ + $units_show->getView(), + $units->getLabel() + ]))->addClass('units-show'), + + (new CFormField( + $units->getView() + ))->addClass(CFormField::ZBX_STYLE_FORM_FIELD_FLUID), + + (new CWidgetFieldSelectView($fields['units_pos'])) + ->setHelpHint(_('Position is ignored for s, uptime and unixtime units.')), + + $form->makeCustomField($units_size, [ + $units_size->getLabel(), + (new CFormField([$units_size->getView(), '%']))->addClass('field-size') + ]), + + $form->makeCustomField($units_bold, [ + $units_bold->getLabel()->addClass('offset-3'), + new CFormField($units_bold->getView()) + ]), + + $form->makeCustomField($units_color, [ + $units_color->getLabel()->addClass('offset-3'), + new CFormField($units_color->getView()) + ]) + ]; +} + +function getTimeFieldsGroupViews(CWidgetFormView $form, array $fields): array { + $time_size = new CWidgetFieldIntegerBoxView($fields['time_size']); + $time_color = new CWidgetFieldColorView($fields['time_color']); + + return [ + new CWidgetFieldRadioButtonListView($fields['time_h_pos']), + + $form->makeCustomField($time_size, [ + $time_size->getLabel(), + (new CFormField([$time_size->getView(), '%']))->addClass('field-size') + ]), + + new CWidgetFieldRadioButtonListView($fields['time_v_pos']), + + new CWidgetFieldCheckBoxView($fields['time_bold']), + + $form->makeCustomField($time_color, [ + $time_color->getLabel()->addClass('offset-3'), + new CFormField($time_color->getView()) + ]) + ]; +} + +function getChangeIndicatorFieldsGroupViews(CWidgetFormView $form, array $fields): array { + $up_color = new CWidgetFieldColorView($fields['up_color']); + $down_color = new CWidgetFieldColorView($fields['down_color']); + $updown_color = new CWidgetFieldColorView($fields['updown_color']); + + return [ + (new CSvgArrow(['up' => true, 'fill_color' => $fields['up_color']->getValue()])) + ->setId('change-indicator-up') + ->setSize(14, 20), + $form->makeCustomField($up_color, [ + new CFormField($up_color->getView()) + ]), + + (new CSvgArrow(['down' => true, 'fill_color' => $fields['down_color']->getValue()])) + ->setId('change-indicator-down') + ->setSize(14, 20), + $form->makeCustomField($down_color, [ + new CFormField($down_color->getView()) + ]), + + (new CSvgArrow(['up' => true, 'down' => true, 'fill_color' => $fields['updown_color']->getValue()])) + ->setId('change-indicator-updown') + ->setSize(14, 20), + $form->makeCustomField($updown_color, [ + new CFormField($updown_color->getView()) + ]) + ]; +} diff --git a/ui/app/views/monitoring.widget.item.view.php b/ui/widgets/item/views/widget.view.php index 87c88a0efa7..9b5eb07c08b 100644 --- a/ui/app/views/monitoring.widget.item.view.php +++ b/ui/widgets/item/views/widget.view.php @@ -20,23 +20,27 @@ /** + * Item value widget view. + * * @var CView $this * @var array $data */ +use Widgets\Item\Widget; + if ($data['error'] !== '') { $body = (new CTableInfo())->setNoDataMessage($data['error']); } else { $classes_vertical = [ - WIDGET_ITEM_POS_TOP => 'top', - WIDGET_ITEM_POS_MIDDLE => 'middle', - WIDGET_ITEM_POS_BOTTOM => 'bottom' + Widget::POSITION_TOP => 'top', + Widget::POSITION_MIDDLE => 'middle', + Widget::POSITION_BOTTOM => 'bottom' ]; $classes_horizontal = [ - WIDGET_ITEM_POS_LEFT => 'left', - WIDGET_ITEM_POS_CENTER => 'center', - WIDGET_ITEM_POS_RIGHT => 'right' + Widget::POSITION_LEFT => 'left', + Widget::POSITION_CENTER => 'center', + Widget::POSITION_RIGHT => 'right' ]; $rows = []; @@ -97,29 +101,18 @@ else { $rows[] = new CDiv($cols); } - $body = (new CDiv( + $body = new CDiv( new CLink($rows, $data['url']) - ))->addClass('dashboard-widget-item'); - - $body->addStyle('background-color: #'.$data['bg_color'].';'); -} - -$output = [ - 'name' => $data['name'], - 'body' => $body->toString() -]; + ); -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); + if ($data['bg_color'] !== '') { + $body->addStyle('background-color: #'.$data['bg_color'].';'); + } } -echo json_encode($output); - +(new CWidgetView($data)) + ->addItem($body) + ->show(); /** * Prepare content for value cell. @@ -137,14 +130,14 @@ function drawValueCell(array $cell_data): array { } // Units ABOVE value. - if (array_key_exists('units', $cell_data['parts']) && $cell_data['units_pos'] == WIDGET_ITEM_POS_ABOVE) { + if (array_key_exists('units', $cell_data['parts']) && $cell_data['units_pos'] == Widget::POSITION_ABOVE) { $item_cell[] = $units_div; } $item_content_div = (new CDiv())->addClass('item-value-content'); // Units BEFORE value. - if (array_key_exists('units', $cell_data['parts']) && $cell_data['units_pos'] == WIDGET_ITEM_POS_BEFORE) { + if (array_key_exists('units', $cell_data['parts']) && $cell_data['units_pos'] == Widget::POSITION_BEFORE) { $item_content_div->addItem($units_div); } @@ -167,7 +160,7 @@ function drawValueCell(array $cell_data): array { } // Units AFTER value. - if (array_key_exists('units', $cell_data['parts']) && $cell_data['units_pos'] == WIDGET_ITEM_POS_AFTER) { + if (array_key_exists('units', $cell_data['parts']) && $cell_data['units_pos'] == Widget::POSITION_AFTER) { $item_content_div->addItem($units_div); } @@ -181,13 +174,13 @@ function drawValueCell(array $cell_data): array { ); switch ($change_data['type']) { - case CControllerWidgetItemView::CHANGE_INDICATOR_UP: + case Widget::CHANGE_INDICATOR_UP: $arrow_data = ['up' => true, 'fill_color' => $change_data['color']]; break; - case CControllerWidgetItemView::CHANGE_INDICATOR_DOWN: + case Widget::CHANGE_INDICATOR_DOWN: $arrow_data = ['down' => true, 'fill_color' => $change_data['color']]; break; - case CControllerWidgetItemView::CHANGE_INDICATOR_UP_DOWN: + case Widget::CHANGE_INDICATOR_UP_DOWN: $arrow_data = ['up' => true, 'down' => true, 'fill_color' => $change_data['color']]; break; } @@ -197,7 +190,7 @@ function drawValueCell(array $cell_data): array { } // Units BELOW value. - if (array_key_exists('units', $cell_data['parts']) && $cell_data['units_pos'] == WIDGET_ITEM_POS_BELOW) { + if (array_key_exists('units', $cell_data['parts']) && $cell_data['units_pos'] == Widget::POSITION_BELOW) { $item_cell[] = $units_div; } diff --git a/ui/widgets/map/Widget.php b/ui/widgets/map/Widget.php new file mode 100755 index 00000000000..ef9af2ca6dd --- /dev/null +++ b/ui/widgets/map/Widget.php @@ -0,0 +1,34 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Map; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public const SOURCETYPE_MAP = 1; + public const SOURCETYPE_FILTER = 2; + + public function getDefaultName(): string { + return _('Map'); + } +} diff --git a/ui/app/controllers/CControllerWidgetMapView.php b/ui/widgets/map/actions/WidgetView.php index 58e2504268a..454aeec6e34 100644 --- a/ui/app/controllers/CControllerWidgetMapView.php +++ b/ui/widgets/map/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -18,27 +18,28 @@ ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; -class CControllerWidgetMapView extends CControllerWidget { +namespace Widgets\Map\Actions; - public function __construct() { - parent::__construct(); +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CMapHelper; - $this->setType(WIDGET_MAP); - $this->setValidationRules([ - 'name' => 'string', +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'initial_load' => 'in 0,1', - 'fields' => 'json', 'current_sysmapid' => 'db sysmaps.sysmapid', 'unique_id' => 'string', 'previous_maps' => 'array' ]); } - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - $sysmap_data = null; + protected function doAction(): void { $previous_map = null; $sysmapid = null; $error = null; @@ -60,11 +61,13 @@ class CControllerWidgetMapView extends CControllerWidget { if ($this->hasInput('current_sysmapid')) { $sysmapid = $this->getInput('current_sysmapid'); } - elseif (array_key_exists('sysmapid', $fields)) { - $sysmapid = $fields['sysmapid']; + elseif (array_key_exists('sysmapid', $this->fields_values)) { + $sysmapid = $this->fields_values['sysmapid']; } - $sysmap_data = CMapHelper::get(($sysmapid == null) ? [] : [$sysmapid], ['unique_id' => $this->getInput('unique_id')]); + $sysmap_data = CMapHelper::get($sysmapid == null ? [] : [$sysmapid], + ['unique_id' => $this->getInput('unique_id')] + ); if ($sysmapid === null || $sysmap_data['id'] < 0) { $error = _('No permissions to referred object or it does not exist!'); @@ -79,14 +82,14 @@ class CControllerWidgetMapView extends CControllerWidget { // Pass variables to view. $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'sysmap_data' => $sysmap_data ?: [], 'widget_settings' => [ 'current_sysmapid' => $sysmapid, - 'filter_widget_reference' => array_key_exists('filter_widget_reference', $fields) - ? $fields['filter_widget_reference'] + 'filter_widget_reference' => array_key_exists('filter_widget_reference', $this->fields_values) + ? $this->fields_values['filter_widget_reference'] : null, - 'source_type' => $fields['source_type'], + 'source_type' => $this->fields_values['source_type'], 'previous_map' => $previous_map, 'initial_load' => $this->getInput('initial_load', 1), 'error' => $error diff --git a/ui/js/widgets/class.widget.map.js b/ui/widgets/map/assets/js/class.widget.js index 03c90e2b9e0..43f3a568b44 100644..100755 --- a/ui/js/widgets/class.widget.map.js +++ b/ui/widgets/map/assets/js/class.widget.js @@ -18,19 +18,26 @@ **/ -const WIDGET_SYSMAP_SOURCETYPE_MAP = 1; -const WIDGET_SYSMAP_SOURCETYPE_FILTER = 2; +class CWidgetMap extends CWidget { -const WIDGET_SYSMAP_EVENT_SUBMAP_SELECT = 'widget-sysmap-submap-select'; + static SOURCETYPE_MAP = 1; + static SOURCETYPE_FILTER = 2; -class CWidgetMap extends CWidget { + static EVENT_SUBMAP_SELECT = 'widget-map.submap-select'; + + static WIDGET_NAVTREE_EVENT_MARK = 'widget-navtree.mark'; + static WIDGET_NAVTREE_EVENT_SELECT = 'widget-navtree.select'; + + static getForeignReferenceFields() { + return ['filter_widget_reference']; + } _init() { super._init(); this._map_svg = null; - this._source_type = this._fields.source_type || WIDGET_SYSMAP_SOURCETYPE_MAP; + this._source_type = this._fields.source_type || CWidgetMap.SOURCETYPE_MAP; this._filter_widget = null; this._filter_itemid = null; @@ -61,8 +68,8 @@ class CWidgetMap extends CWidget { super._doDestroy(); if (this._filter_widget) { - this._filter_widget.off(WIDGET_NAVTREE_EVENT_MARK, this._events.mark); - this._filter_widget.off(WIDGET_NAVTREE_EVENT_SELECT, this._events.select); + this._filter_widget.off(CWidgetMap.WIDGET_NAVTREE_EVENT_MARK, this._events.mark); + this._filter_widget.off(CWidgetMap.WIDGET_NAVTREE_EVENT_SELECT, this._events.select); } } @@ -70,18 +77,17 @@ class CWidgetMap extends CWidget { super.announceWidgets(widgets); if (this._filter_widget !== null) { - this._filter_widget.off(WIDGET_NAVTREE_EVENT_MARK, this._events.mark); - this._filter_widget.off(WIDGET_NAVTREE_EVENT_SELECT, this._events.select); + this._filter_widget.off(CWidgetMap.WIDGET_NAVTREE_EVENT_MARK, this._events.mark); + this._filter_widget.off(CWidgetMap.WIDGET_NAVTREE_EVENT_SELECT, this._events.select); } - if (this._source_type == WIDGET_SYSMAP_SOURCETYPE_FILTER) { + if (this._source_type == CWidgetMap.SOURCETYPE_FILTER) { for (const widget of widgets) { - if (widget instanceof CWidgetNavTree - && widget._fields.reference === this._fields.filter_widget_reference) { + if (widget._fields.reference === this._fields.filter_widget_reference) { this._filter_widget = widget; - this._filter_widget.on(WIDGET_NAVTREE_EVENT_MARK, this._events.mark); - this._filter_widget.on(WIDGET_NAVTREE_EVENT_SELECT, this._events.select); + this._filter_widget.on(CWidgetMap.WIDGET_NAVTREE_EVENT_MARK, this._events.mark); + this._filter_widget.on(CWidgetMap.WIDGET_NAVTREE_EVENT_SELECT, this._events.select); } } } @@ -90,7 +96,7 @@ class CWidgetMap extends CWidget { _promiseUpdate() { if (!this._has_contents || this._map_svg === null) { if (this._sysmapid !== null - || this._source_type == WIDGET_SYSMAP_SOURCETYPE_MAP + || this._source_type == CWidgetMap.SOURCETYPE_MAP || this._filter_widget === null) { return super._promiseUpdate(); } @@ -174,7 +180,7 @@ class CWidgetMap extends CWidget { this._navigateToMap(item.sysmapid); - this.fire(WIDGET_SYSMAP_EVENT_SUBMAP_SELECT, { + this.fire(CWidgetMap.EVENT_SUBMAP_SELECT, { sysmapid: item.sysmapid, parent_itemid: item.parent_itemid, back: true @@ -221,7 +227,7 @@ class CWidgetMap extends CWidget { this._navigateToMap(sysmapid); - this.fire(WIDGET_SYSMAP_EVENT_SUBMAP_SELECT, { + this.fire(CWidgetMap.EVENT_SUBMAP_SELECT, { sysmapid, parent_itemid: this._filter_itemid }); @@ -247,4 +253,8 @@ class CWidgetMap extends CWidget { this._startUpdating(); } + + _hasPadding() { + return true; + } } diff --git a/ui/widgets/map/includes/WidgetForm.php b/ui/widgets/map/includes/WidgetForm.php new file mode 100644 index 00000000000..c91463cc66f --- /dev/null +++ b/ui/widgets/map/includes/WidgetForm.php @@ -0,0 +1,73 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Map\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldRadioButtonList, + CWidgetFieldReference, + CWidgetFieldSelectResource, + CWidgetFieldWidgetSelect +}; + +use Widgets\Map\Widget; + +use Zabbix\Core\CWidget; + +/** + * Map widget form. + */ +class WidgetForm extends CWidgetForm { + + private const WIDGET_NAV_TREE = 'navtree'; + + public function addFields(): self { + $this->addField( + (new CWidgetFieldRadioButtonList('source_type', _('Source type'), [ + Widget::SOURCETYPE_MAP => _('Map'), + Widget::SOURCETYPE_FILTER => _('Map navigation tree') + ])) + ->setDefault(Widget::SOURCETYPE_MAP) + ->setAction('ZABBIX.Dashboard.reloadWidgetProperties()') + ); + + if (!array_key_exists('source_type', $this->values) || $this->values['source_type'] == Widget::SOURCETYPE_MAP) { + $this->addField( + (new CWidgetFieldSelectResource('sysmapid', _('Map'))) + ->setResourceType(CWidgetFieldSelectResource::RESOURCE_TYPE_SYSMAP) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ); + } + else { + $this->addField( + (new CWidgetFieldWidgetSelect('filter_widget_reference', _('Filter'), self::WIDGET_NAV_TREE)) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ); + } + + return $this; + } +} diff --git a/ui/include/classes/html/CDashboardWidgetMap.php b/ui/widgets/map/includes/WidgetMap.php index 701f0d2bed3..1c77957b14c 100644 --- a/ui/include/classes/html/CDashboardWidgetMap.php +++ b/ui/widgets/map/includes/WidgetMap.php @@ -19,82 +19,72 @@ **/ +namespace Widgets\Map\Includes; + +use CDiv, + CLink, + CSpan, + CTableInfo; + +use Widgets\Map\Widget; + /** * Dashboard Map widget class. Creates all widget specific JavaScript and HTML content for map widget's view. */ -class CDashboardWidgetMap extends CDiv { +class WidgetMap extends CDiv +{ /** * Reference of linked map navigation tree widget. - * - * @var string */ - private $filter_widget_reference; + private ?string $filter_widget_reference; /** * Map that will be linked to 'go back to [previous map name]' link in dashboard map widget. - * - * @var array|null - array must contain at least integer value 'sysmapid' and string 'name'. + * Array must contain at least integer value 'sysmapid' and string 'name'. */ - private $previous_map; + private ?array $previous_map; /** * Response array of CMapHelper::get() that represents currently opened map. - * - * @var array|null */ - private $sysmap_data; + private array $sysmap_data; /** * Requested sysmapid. - * - * @var int */ - private $current_sysmapid; + private ?int $current_sysmapid; /** * The type of source of map widget. - * - * @var int - allowed values are WIDGET_SYSMAP_SOURCETYPE_MAP and WIDGET_SYSMAP_SOURCETYPE_FILTER. + * Allowed values are Widget::SOURCETYPE_MAP and Widget::SOURCETYPE_FILTER. */ - private $source_type; + private int $source_type; /** * Represents either this is initial or repeated load of map widget. - * - * @var int - allowed values are 0 and 1. - */ - private $initial_load; - - /** - * Unique ID of widget. - * - * @var string + * Allowed values are 0 and 1. */ - private $uniqueid; + private int $initial_load; /** * The error message displayed in map widget. - * - * @var string|null */ - private $error; + private ?string $error; /** * Class constructor. * - * @param array $sysmap_data An array of requested map in the form created by CMapHelper::get() - * method. - * @param array $widget_settings An array contains widget settings. - * @param string|null $widget_settings['error'] A string of error message or null in case if error is - * not detected. - * @param int $widget_settings['current_sysmapid'] An integer of requested sysmapid. - * @param string $widget_settings['filter_widget_reference'] A string of linked map navigation tree - * reference. - * @param int $widget_settings['source_type'] The type of source of map widget. - * @param array|null $widget_settings['previous_map'] Sysmapid and name of map linked as previous. - * @param int $widget_settings['initial_load'] Integer represents either this is initial load or - * repeated. + * @param array $sysmap_data An array of requested map in the form created by CMapHelper::get() method. + * @param array $widget_settings An array contains widget settings. + * string|null $widget_settings['error'] A string of error message or null in case + * if error is not detected. + * int $widget_settings['current_sysmapid'] An integer of requested sysmapid. + * string $widget_settings['filter_widget_reference'] A string of linked map navigation tree reference. + * int $widget_settings['source_type'] The type of source of map widget. + * array|null $widget_settings['previous_map'] Sysmapid and name of map linked as previous. + * int $widget_settings['initial_load'] Integer represents either this is initial load + * or repeated. */ public function __construct(array $sysmap_data, array $widget_settings) { parent::__construct(); @@ -110,10 +100,8 @@ class CDashboardWidgetMap extends CDiv { /** * A javascript that is used as widget's script_inline parameter. - * - * @return string */ - public function getScriptData() { + public function getScriptData(): array { $map_data = [ 'current_sysmapid' => null, 'filter_widget_reference' => null, @@ -124,7 +112,7 @@ class CDashboardWidgetMap extends CDiv { $map_data['current_sysmapid'] = $this->current_sysmapid; } - if ($this->source_type == WIDGET_SYSMAP_SOURCETYPE_FILTER + if ($this->source_type == Widget::SOURCETYPE_FILTER && $this->filter_widget_reference && $this->initial_load) { $map_data['filter_widget_reference'] = $this->filter_widget_reference; @@ -133,7 +121,7 @@ class CDashboardWidgetMap extends CDiv { if ($this->sysmap_data && $this->error === null) { $map_data['map_options'] = $this->sysmap_data; } - elseif ($this->error !== null && $this->source_type == WIDGET_SYSMAP_SOURCETYPE_FILTER) { + elseif ($this->error !== null && $this->source_type == Widget::SOURCETYPE_FILTER) { $map_data['error_msg'] = (new CTableInfo()) ->setNoDataMessage($this->error) ->toString(); @@ -142,12 +130,15 @@ class CDashboardWidgetMap extends CDiv { return $map_data; } - /** - * Build an object of HTML used in widget content. - */ - private function build() { + public function toString($destroy = true): string { + $this->build(); + + return parent::toString($destroy); + } + + private function build(): void { $this->addClass(ZBX_STYLE_SYSMAP); - $this->setId(uniqid()); + $this->setId(uniqid('', true)); if ($this->error === null) { if ($this->previous_map) { @@ -157,39 +148,32 @@ class CDashboardWidgetMap extends CDiv { (new CLink( (new CSpan()) ->addClass(ZBX_STYLE_BTN_BACK_MAP) - ->addItem((new CDiv())->addClass(ZBX_STYLE_BTN_BACK_MAP_ICON)) - ->addItem((new CDiv()) - ->addClass(ZBX_STYLE_BTN_BACK_MAP_CONTENT) - ->addItem(_s('Go back to %1$s', $this->previous_map['name'])) + ->addItem( + (new CDiv())->addClass(ZBX_STYLE_BTN_BACK_MAP_ICON) + ) + ->addItem( + (new CDiv()) + ->addClass(ZBX_STYLE_BTN_BACK_MAP_CONTENT) + ->addItem(_s('Go back to %1$s', $this->previous_map['name'])) ), - '#' + '#' ))->addClass('js-previous-map') ); $this->addItem($go_back_div); } - $map_div = (new CDiv((new CDiv($this->sysmap_data['aria_label']))->addClass(ZBX_STYLE_INLINE_SR_ONLY))) - ->addClass('sysmap-widget-container'); + $map_div = (new CDiv( + (new CDiv($this->sysmap_data['aria_label']))->addClass(ZBX_STYLE_INLINE_SR_ONLY)) + )->addClass('sysmap-widget-container'); $this->addStyle('position:relative;'); $this->addItem($map_div); } - elseif ($this->source_type == WIDGET_SYSMAP_SOURCETYPE_MAP) { - $this->addItem((new CTableInfo())->setNoDataMessage($this->error)); + elseif ($this->source_type == Widget::SOURCETYPE_MAP) { + $this->addItem( + (new CTableInfo())->setNoDataMessage($this->error) + ); } } - - /** - * Gets string representation of widget HTML content. - * - * @param bool $destroy - * - * @return string - */ - public function toString($destroy = true) { - $this->build(); - - return parent::toString($destroy); - } } diff --git a/ui/widgets/map/manifest.json b/ui/widgets/map/manifest.json new file mode 100755 index 00000000000..78f6cd2d973 --- /dev/null +++ b/ui/widgets/map/manifest.json @@ -0,0 +1,20 @@ +{ + "manifest_version": 2.0, + "id": "map", + "type": "widget", + "name": "Map", + "namespace": "Map", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "size": { + "width": 18, + "height": 5 + }, + "js_class": "CWidgetMap", + "refresh_rate": 900 + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/app/views/monitoring.widget.geomap.view.php b/ui/widgets/map/views/widget.edit.php index 84fa6e1ee17..7c88db3a6ed 100644..100755 --- a/ui/app/views/monitoring.widget.geomap.view.php +++ b/ui/widgets/map/views/widget.edit.php @@ -20,26 +20,22 @@ /** + * Map widget form view. + * * @var CView $this * @var array $data */ -$output = [ - 'name' => $data['name'], - 'body' => - (new CDiv()) - ->setId($data['unique_id']) - ->toString(), - 'geomap' => array_intersect_key($data, array_flip(['config', 'hosts'])) -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['source_type']) + ) + ->addField(array_key_exists('sysmapid', $data['fields']) + ? new CWidgetFieldSelectResourceView($data['fields']['sysmapid'], $data['captions']['simple']) + : null + ) + ->addField(array_key_exists('filter_widget_reference', $data['fields']) + ? new CWidgetFieldWidgetSelectView($data['fields']['filter_widget_reference']) + : null + ) + ->show(); diff --git a/ui/widgets/map/views/widget.view.php b/ui/widgets/map/views/widget.view.php new file mode 100644 index 00000000000..d74b9f53755 --- /dev/null +++ b/ui/widgets/map/views/widget.view.php @@ -0,0 +1,36 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Map widget view. + * + * @var CView $this + * @var array $data + */ + +use Widgets\Map\Includes\WidgetMap; + +$item = new WidgetMap($data['sysmap_data'], $data['widget_settings']); + +(new CWidgetView($data)) + ->addItem($item) + ->setVar('sysmap_data', $item->getScriptData()) + ->show(); diff --git a/ui/widgets/navtree/Widget.php b/ui/widgets/navtree/Widget.php new file mode 100755 index 00000000000..80bb2f455cc --- /dev/null +++ b/ui/widgets/navtree/Widget.php @@ -0,0 +1,49 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\NavTree; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + // Max depth of navigation tree. + public const MAX_DEPTH = 10; + + public function getDefaultName(): string { + return _('Map navigation tree'); + } + + public function getTranslationStrings(): array { + return [ + 'class.widget.js' => [ + 'Add' => _s('Add'), + 'Add child element' => _s('Add child elementsssss'), + 'Add multiple maps' => _s('Add multiple maps'), + 'Apply' => _s('Apply'), + 'Cancel' => _s('Cancel'), + 'Edit' => _s('Edit'), + 'Edit tree element' => _s('Edit tree element'), + 'Remove' => _s('Remove') + ] + ]; + } +} diff --git a/ui/app/controllers/CControllerWidgetNavTreeItemEdit.php b/ui/widgets/navtree/actions/NavTreeItemEdit.php index 07ed735aafd..97a1e5e93a4 100644 --- a/ui/app/controllers/CControllerWidgetNavTreeItemEdit.php +++ b/ui/widgets/navtree/actions/NavTreeItemEdit.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,17 +19,25 @@ **/ -class CControllerWidgetNavTreeItemEdit extends CController { +namespace Widgets\NavTree\Actions; - protected function init() { +use API, + CController, + CControllerResponseData; + +use Widgets\NavTree\Widget; + +class NavTreeItemEdit extends CController { + + protected function init(): void { $this->disableSIDValidation(); } - protected function checkInput() { + protected function checkInput(): bool { $fields = [ 'name' => 'required|string', 'sysmapid' => 'required|db sysmaps.sysmapid', - 'depth' => 'required|ge 1|le '.WIDGET_NAVIGATION_TREE_MAX_DEPTH + 'depth' => 'required|ge 1|le '.Widget::MAX_DEPTH ]; $ret = $this->validateInput($fields); @@ -40,18 +48,18 @@ class CControllerWidgetNavTreeItemEdit extends CController { 'error' => [ 'messages' => array_column(get_and_clear_messages(), 'message') ] - ])]) + ], JSON_THROW_ON_ERROR)]) ); } return $ret; } - protected function checkPermissions() { - return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); + protected function checkPermissions(): bool { + return $this->getUserType() >= USER_TYPE_ZABBIX_USER; } - protected function doAction() { + protected function doAction(): void { $sysmapid = $this->getInput('sysmapid'); $sysmap = ['sysmapid' => $sysmapid, 'name' => '']; diff --git a/ui/app/controllers/CControllerWidgetNavTreeItemUpdate.php b/ui/widgets/navtree/actions/NavTreeItemUpdate.php index ef2e47417d4..0aa8ef74316 100644 --- a/ui/app/controllers/CControllerWidgetNavTreeItemUpdate.php +++ b/ui/widgets/navtree/actions/NavTreeItemUpdate.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -18,20 +18,27 @@ ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; -class CControllerWidgetNavTreeItemUpdate extends CController { +namespace Widgets\NavTree\Actions; - protected function init() { +use API, + CController, + CControllerResponseData; + +use Widgets\NavTree\Widget; + +class NavTreeItemUpdate extends CController { + + protected function init(): void { $this->disableSIDValidation(); } - protected function checkInput() { + protected function checkInput(): bool { $fields = [ 'name' => 'required|string|not_empty', 'sysmapid' => 'db sysmaps.sysmapid', 'add_submaps' => 'in 0,1', - 'depth' => 'ge 1|le '.WIDGET_NAVIGATION_TREE_MAX_DEPTH + 'depth' => 'ge 1|le '.Widget::MAX_DEPTH ]; $ret = $this->validateInput($fields); @@ -42,18 +49,18 @@ class CControllerWidgetNavTreeItemUpdate extends CController { 'error' => [ 'messages' => array_column(get_and_clear_messages(), 'message') ] - ])]) + ], JSON_THROW_ON_ERROR)]) ); } return $ret; } - protected function checkPermissions() { - return ($this->getUserType() >= USER_TYPE_ZABBIX_USER); + protected function checkPermissions(): bool { + return $this->getUserType() >= USER_TYPE_ZABBIX_USER; } - protected function doAction() { + protected function doAction(): void { $sysmapid = $this->getInput('sysmapid', 0); $add_submaps = (int) $this->getInput('add_submaps', 0); $depth = (int) $this->getInput('depth', 1); @@ -78,7 +85,7 @@ class CControllerWidgetNavTreeItemUpdate extends CController { $sysmapids[$sysmapid] = true; do { - if ($depth++ > WIDGET_NAVIGATION_TREE_MAX_DEPTH) { + if ($depth++ > Widget::MAX_DEPTH) { break; } @@ -121,6 +128,6 @@ class CControllerWidgetNavTreeItemUpdate extends CController { 'preservekeys' => true ]) : [] - ])])); + ], JSON_THROW_ON_ERROR)])); } } diff --git a/ui/app/controllers/CControllerWidgetNavTreeView.php b/ui/widgets/navtree/actions/WidgetView.php index a1b5a2412d2..706789994fc 100644 --- a/ui/app/controllers/CControllerWidgetNavTreeView.php +++ b/ui/widgets/navtree/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,25 +19,111 @@ **/ -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; +namespace Widgets\NavTree\Actions; -class CControllerWidgetNavTreeView extends CControllerWidget { +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CProfile, + CSeverityHelper; - private $problems_per_severity_tpl; +class WidgetView extends CControllerDashboardWidgetView { - public function __construct() { - parent::__construct(); + private array $problems_per_severity_tpl; - $this->setType(WIDGET_NAV_TREE); - $this->setValidationRules([ + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'name' => 'string', - 'widgetid' => 'db widget.widgetid', - 'initial_load' => 'in 0,1', - 'fields' => 'json' + 'fields' => 'array' ]); } - protected function getNumberOfProblemsBySysmap(array $navtree_items = []) { + protected function doAction(): void { + // Get list of sysmapids. + $sysmapids = []; + $navtree_items = []; + + foreach ($this->fields_values['navtree'] as $id => $navtree_item) { + $sysmapid = array_key_exists('sysmapid', $navtree_item) ? $navtree_item['sysmapid'] : 0; + + if ($sysmapid != 0) { + $sysmapids[$sysmapid] = true; + } + + $navtree_items[$id] = [ + 'parent' => $navtree_item['parent'], + 'sysmapid' => $sysmapid, + 'child_sysmapids' => [] + ]; + } + + // Propagate item mapids to all its parent items. + foreach ($navtree_items as $navtree_item) { + $parent = $navtree_item['parent']; + + while (array_key_exists($parent, $navtree_items)) { + if ($navtree_item['sysmapid'] != 0) { + $navtree_items[$parent]['child_sysmapids'][$navtree_item['sysmapid']] = true; + } + $parent = $navtree_items[$parent]['parent']; + } + } + + // Get severity levels and colors and select list of sysmapids to count problems per maps. + $this->problems_per_severity_tpl = []; + $severity_config = []; + + $maps_accessible = $sysmapids + ? API::Map()->get([ + 'output' => [], + 'sysmapids' => array_keys($sysmapids), + 'preservekeys' => true + ]) + : []; + + for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) { + $this->problems_per_severity_tpl[$severity] = 0; + $severity_config[$severity] = [ + 'name' => CSeverityHelper::getName($severity), + 'style_class' => CSeverityHelper::getStatusStyle($severity) + ]; + } + + $widgetid = $this->getInput('widgetid', 0); + $navtree_item_selected = 0; + $navtree_items_opened = []; + + if ($widgetid) { + $pattern = 'web.dashboard.widget.navtree.item-%.toggle'; + $discard_from_start = strpos($pattern, '%'); + $discard_from_end = strlen($pattern) - $discard_from_start - 1; + + foreach (CProfile::findByIdxPattern($pattern, $widgetid) as $item_opened) { + $navtree_items_opened[] = substr($item_opened, $discard_from_start, -$discard_from_end); + } + + $navtree_item_selected = CProfile::get('web.dashboard.widget.navtree.item.selected', 0, $widgetid); + } + + $this->setResponse(new CControllerResponseData([ + 'name' => $this->getInput('name', $this->widget->getDefaultName()), + 'navtree' => $this->fields_values['navtree'], + 'navtree_item_selected' => $navtree_item_selected, + 'navtree_items_opened' => $navtree_items_opened, + 'problems' => $this->getNumberOfProblemsBySysmap($navtree_items), + 'show_unavailable' => $this->fields_values['show_unavailable'], + 'maps_accessible' => array_keys($maps_accessible), + 'severity_config' => $severity_config, + 'initial_load' => $this->getInput('initial_load', 0), + 'user' => [ + 'debug_mode' => $this->getDebugMode() + ] + ])); + } + + private function getNumberOfProblemsBySysmap(array $navtree_items = []): array { $response = []; $sysmapids = []; @@ -124,7 +210,7 @@ class CControllerWidgetNavTreeView extends CControllerWidget { break; case SYSMAP_ELEMENT_TYPE_TRIGGER: - foreach (zbx_objectValues($selement['elements'], 'triggerid') as $triggerid) { + foreach (array_column($selement['elements'], 'triggerid') as $triggerid) { $problems_per_trigger[$triggerid] = $this->problems_per_severity_tpl; } break; @@ -153,7 +239,7 @@ class CControllerWidgetNavTreeView extends CControllerWidget { } // Select lowest severity to reduce amount of data returned by API. - $severity_min = min(zbx_objectValues($sysmaps, 'severity_min')); + $severity_min = min(array_column($sysmaps, 'severity_min')); // Get triggers related to host groups. if ($host_groups) { @@ -240,10 +326,10 @@ class CControllerWidgetNavTreeView extends CControllerWidget { } } - // Count problems occurred in triggers which are related to links. + // Count problems occurred in triggers which are related to the links. foreach ($map['links'] as $link) { $uncounted_problem_triggers = array_diff_key( - array_flip(zbx_objectValues($link['linktriggers'], 'triggerid')), + array_flip(array_column($link['linktriggers'], 'triggerid')), $problems_counted ); @@ -253,9 +339,9 @@ class CControllerWidgetNavTreeView extends CControllerWidget { // Remove problems which are less important than map's min-severity. if ($map['severity_min'] > 0) { - foreach ($problems_to_add as $sev => $probl) { - if ($map['severity_min'] > $sev) { - $problems_to_add[$sev] = 0; + foreach (array_keys($problems_to_add) as $severity) { + if ($map['severity_min'] > $severity) { + $problems_to_add[$severity] = 0; } } } @@ -280,9 +366,9 @@ class CControllerWidgetNavTreeView extends CControllerWidget { return $response; } - protected function getElementProblems(array $selement, array $problems_per_trigger, array $sysmaps, + private function getElementProblems(array $selement, array $problems_per_trigger, array $sysmaps, array $submaps_relations, $severity_min = 0, array &$problems_counted = [], array $triggers_per_hosts = [], - array $triggers_per_host_groups = []) { + array $triggers_per_host_groups = []): ?array { $problems = null; switch ($selement['elementtype']) { @@ -306,7 +392,7 @@ class CControllerWidgetNavTreeView extends CControllerWidget { case SYSMAP_ELEMENT_TYPE_TRIGGER: $problems = $this->problems_per_severity_tpl; $uncounted_problem_triggers = array_diff_key( - array_flip(zbx_objectValues($selement['elements'], 'triggerid')), + array_flip(array_column($selement['elements'], 'triggerid')), $problems_counted ); foreach ($uncounted_problem_triggers as $triggerid => $var) { @@ -343,7 +429,7 @@ class CControllerWidgetNavTreeView extends CControllerWidget { // Recursively find all submaps in any depth and put them into an array. $maps_to_process[$submap_element['sysmapid']] = false; - while (array_filter($maps_to_process, function($item) {return !$item;})) { + while (array_filter($maps_to_process, static function($item) {return !$item;})) { foreach ($maps_to_process as $linked_map => $val) { $maps_to_process[$linked_map] = true; @@ -381,7 +467,7 @@ class CControllerWidgetNavTreeView extends CControllerWidget { foreach ($sysmaps[$sysmapid]['links'] as $link) { if ($link['permission'] >= PERM_READ) { $uncounted_problem_triggers = array_diff_key( - array_flip(zbx_objectValues($link['linktriggers'], 'triggerid')), + array_flip(array_column($link['linktriggers'], 'triggerid')), $problems_counted ); foreach ($uncounted_problem_triggers as $triggerid => $var) { @@ -399,9 +485,9 @@ class CControllerWidgetNavTreeView extends CControllerWidget { // Remove problems which are less important than $severity_min. if ($problems !== null && $severity_min > 0) { - foreach ($problems as $sev => $probl) { - if ($severity_min > $sev) { - $problems[$sev] = 0; + foreach (array_keys($problems) as $severity) { + if ($severity_min > $severity) { + $problems[$severity] = 0; } } } @@ -409,91 +495,6 @@ class CControllerWidgetNavTreeView extends CControllerWidget { return $problems; } - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - $error = null; - - // Get list of sysmapids. - $sysmapids = []; - $navtree_items = []; - foreach ($fields['navtree'] as $id => $navtree_item) { - $sysmapid = array_key_exists('sysmapid', $navtree_item) ? $navtree_item['sysmapid'] : 0; - if ($sysmapid != 0) { - $sysmapids[$sysmapid] = true; - } - - $navtree_items[$id] = [ - 'parent' => $navtree_item['parent'], - 'sysmapid' => $sysmapid, - 'child_sysmapids' => [] - ]; - } - - // Propagate item mapids to all its parent items. - foreach ($navtree_items as $navtree_item) { - $parent = $navtree_item['parent']; - - while (array_key_exists($parent, $navtree_items)) { - if ($navtree_item['sysmapid'] != 0) { - $navtree_items[$parent]['child_sysmapids'][$navtree_item['sysmapid']] = true; - } - $parent = $navtree_items[$parent]['parent']; - } - } - - // Get severity levels and colors and select list of sysmapids to count problems per maps. - $this->problems_per_severity_tpl = []; - $severity_config = []; - - $maps_accessible = $sysmapids - ? API::Map()->get([ - 'output' => [], - 'sysmapids' => array_keys($sysmapids), - 'preservekeys' => true - ]) - : []; - - for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) { - $this->problems_per_severity_tpl[$severity] = 0; - $severity_config[$severity] = [ - 'name' => CSeverityHelper::getName($severity), - 'style_class' => CSeverityHelper::getStatusStyle($severity) - ]; - } - - $widgetid = $this->getInput('widgetid', 0); - $navtree_item_selected = 0; - $navtree_items_opened = []; - - if ($widgetid) { - $pattern = 'web.dashboard.widget.navtree.item-%.toggle'; - $discard_from_start = strpos($pattern, '%'); - $discard_from_end = strlen($pattern) - $discard_from_start - 1; - - foreach (CProfile::findByIdxPattern($pattern, $widgetid) as $item_opened) { - $navtree_items_opened[] = substr($item_opened, $discard_from_start, -$discard_from_end); - } - - $navtree_item_selected = CProfile::get('web.dashboard.widget.navtree.item.selected', 0, $widgetid); - } - - $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), - 'navtree' => $fields['navtree'], - 'navtree_item_selected' => $navtree_item_selected, - 'navtree_items_opened' => $navtree_items_opened, - 'problems' => $this->getNumberOfProblemsBySysmap($navtree_items), - 'show_unavailable' => $fields['show_unavailable'], - 'maps_accessible' => array_keys($maps_accessible), - 'severity_config' => $severity_config, - 'initial_load' => $this->getInput('initial_load', 0), - 'error' => $error, - 'user' => [ - 'debug_mode' => $this->getDebugMode() - ] - ])); - } - /** * Function is used to sum problems in 2 arrays. * @@ -507,7 +508,7 @@ class CControllerWidgetNavTreeView extends CControllerWidget { * * @return array Array containing problems in both arrays summed. */ - protected static function sumArrayValues(array $a1, array $a2) { + private static function sumArrayValues(array $a1, array $a2): array { foreach ($a1 as $key => &$value) { $value += $a2[$key]; } diff --git a/ui/js/widgets/class.widget.navtree.js b/ui/widgets/navtree/assets/js/class.widget.js index b105ba36f69..7ff0f26e5be 100644..100755 --- a/ui/js/widgets/class.widget.navtree.js +++ b/ui/widgets/navtree/assets/js/class.widget.js @@ -18,11 +18,17 @@ **/ -const WIDGET_NAVTREE_EVENT_MARK = 'widget-navtree-mark'; -const WIDGET_NAVTREE_EVENT_SELECT = 'widget-navtree-select'; - class CWidgetNavTree extends CWidget { + static EVENT_MARK = 'widget-navtree.mark'; + static EVENT_SELECT = 'widget-navtree.select'; + + static WIDGET_MAP_EVENT_SUBMAP_SELECT = 'widget-map.submap-select'; + + static hasReferenceField() { + return true; + } + _init() { super._init(); @@ -66,7 +72,7 @@ class CWidgetNavTree extends CWidget { this._maps = []; for (const widget of widgets) { - if (widget instanceof CWidgetMap && this._fields.reference === widget._fields.filter_widget_reference) { + if (this._fields.reference === widget._fields.filter_widget_reference) { this._maps.push(widget); } } @@ -228,7 +234,7 @@ class CWidgetNavTree extends CWidget { [this._widgetid] ); - this.fire(WIDGET_NAVTREE_EVENT_SELECT, { + this.fire(CWidgetNavTree.EVENT_SELECT, { sysmapid: this._navtree[this._navtree_item_selected].sysmapid, itemid: this._navtree_item_selected }); @@ -280,7 +286,7 @@ class CWidgetNavTree extends CWidget { sysmapid = this._navtree[this._navtree_item_selected].sysmapid; } - this.fire(WIDGET_NAVTREE_EVENT_SELECT, {sysmapid, itemid: this._navtree_item_selected}); + this.fire(CWidgetNavTree.EVENT_SELECT, {sysmapid, itemid: this._navtree_item_selected}); } } @@ -312,7 +318,7 @@ class CWidgetNavTree extends CWidget { if (!this._is_edit_mode) { for (const widget of this._maps) { - widget.on(WIDGET_SYSMAP_EVENT_SUBMAP_SELECT, this._events.selectSubmap); + widget.on(CWidgetNavTree.WIDGET_MAP_EVENT_SUBMAP_SELECT, this._events.selectSubmap); } } } @@ -345,7 +351,7 @@ class CWidgetNavTree extends CWidget { if (!this._is_edit_mode) { for (const widget of this._maps) { - widget.off(WIDGET_SYSMAP_EVENT_SUBMAP_SELECT, this._events.selectSubmap); + widget.off(CWidgetNavTree.WIDGET_MAP_EVENT_SUBMAP_SELECT, this._events.selectSubmap); } } } @@ -741,7 +747,7 @@ class CWidgetNavTree extends CWidget { updateUserProfile('web.dashboard.widget.navtree.item.selected', this._navtree_item_selected, [this._widgetid]); - this.fire(WIDGET_NAVTREE_EVENT_MARK, {itemid: this._navtree_item_selected}); + this.fire(CWidgetNavTree.EVENT_MARK, {itemid: this._navtree_item_selected}); return true; } diff --git a/ui/include/classes/html/CNavigationTree.php b/ui/widgets/navtree/includes/NavigationTree.php index 0dfaad22216..559d00237d4 100644 --- a/ui/include/classes/html/CNavigationTree.php +++ b/ui/widgets/navtree/includes/NavigationTree.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,26 +19,28 @@ **/ -class CNavigationTree extends CDiv { +namespace Widgets\NavTree\Includes; - private $error; - private $data; +use CDiv; + +use Widgets\NavTree\Widget; + +class NavigationTree extends CDiv +{ + + private array $data; public function __construct(array $data = []) { parent::__construct(); $this->data = $data; - $this->setId(uniqid()); - $this->addClass(ZBX_STYLE_NAVIGATIONTREE); + $this + ->setId(uniqid('', true)) + ->addClass(ZBX_STYLE_NAVIGATIONTREE); } - public function setError($value) { - $this->error = $value; - return $this; - } - - public function getScriptData() { + public function getScriptData(): array { return [ 'problems' => $this->data['problems'], 'severity_levels' => $this->data['severity_config'], @@ -48,19 +50,17 @@ class CNavigationTree extends CDiv { 'maps_accessible' => array_map('strval', $this->data['maps_accessible']), 'show_unavailable' => $this->data['show_unavailable'], 'initial_load' => $this->data['initial_load'], - 'max_depth' => WIDGET_NAVIGATION_TREE_MAX_DEPTH + 'max_depth' => Widget::MAX_DEPTH ]; } - private function build() { - if ($this->error !== null) { - $this->addClass(ZBX_STYLE_DISABLED); - } - - $this->addItem((new CDiv())->addClass('tree')); + private function build(): void { + $this->addItem( + (new CDiv())->addClass('tree') + ); } - public function toString($destroy = true) { + public function toString($destroy = true): string { $this->build(); return parent::toString($destroy); diff --git a/ui/widgets/navtree/includes/WidgetForm.php b/ui/widgets/navtree/includes/WidgetForm.php new file mode 100644 index 00000000000..8cdeb8d4257 --- /dev/null +++ b/ui/widgets/navtree/includes/WidgetForm.php @@ -0,0 +1,49 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\NavTree\Includes; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldNavTree, + CWidgetFieldReference +}; + +/** + * Map navigation widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + new CWidgetFieldReference() + ) + ->addField( + new CWidgetFieldNavTree('navtree') + ) + ->addField( + new CWidgetFieldCheckBox('show_unavailable', _('Show unavailable maps')) + ); + } +} diff --git a/ui/widgets/navtree/manifest.json b/ui/widgets/navtree/manifest.json new file mode 100755 index 00000000000..c61b253e2d7 --- /dev/null +++ b/ui/widgets/navtree/manifest.json @@ -0,0 +1,31 @@ +{ + "manifest_version": 2.0, + "id": "navtree", + "type": "widget", + "name": "Map navigation tree", + "namespace": "NavTree", + "version": "1.0", + "author": "Zabbix SIA", + "actions": { + "widget.navtree.item.edit": { + "class": "NavTreeItemEdit", + "view": "navtreeitem.edit", + "layout": "layout.json" + }, + "widget.navtree.item.update": { + "class": "NavTreeItemUpdate", + "layout": "layout.json" + } + }, + "widget": { + "size": { + "width": 6, + "height": 5 + }, + "js_class": "CWidgetNavTree", + "refresh_rate": 900 + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/app/views/js/monitoring.widget.navtreeitem.edit.js.php b/ui/widgets/navtree/views/navtreeitem.edit.js.php index fd68a9c09a0..8a2328db2ef 100644 --- a/ui/app/views/js/monitoring.widget.navtreeitem.edit.js.php +++ b/ui/widgets/navtree/views/navtreeitem.edit.js.php @@ -17,13 +17,9 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ - - -/** - * @var CView $this - */ ?> + window.navtreeitem_edit_popup = new class { init() { jQuery('#sysmapname').on('change', (e) => { diff --git a/ui/app/views/monitoring.widget.navtreeitem.edit.php b/ui/widgets/navtree/views/navtreeitem.edit.php index 3cadc71947b..9abfe7ced60 100644 --- a/ui/app/views/monitoring.widget.navtreeitem.edit.php +++ b/ui/widgets/navtree/views/navtreeitem.edit.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,47 +20,63 @@ /** + * Map navigation tree item edit form view. + * * @var CView $this + * @var array $data */ +use Widgets\NavTree\Widget; + $form = (new CForm('post')) ->cleanItems() ->setId('widget-dialogue-form') ->setName('widget_dialogue_form') ->addItem((new CInput('submit', 'submit'))->addStyle('display: none;')); -$form_list = (new CFormList()) - ->addRow( +$form_grid = (new CFormGrid()) + ->addItem([ (new CLabel(_('Name'), 'name'))->setAsteriskMark(), - (new CTextBox('name', $data['name'])) - ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) - ->setAttribute('autofocus', 'autofocus') - ->setAriaRequired() - ) - ->addRow(_('Linked map'), [ - new CVar('sysmapid', $data['sysmap']['sysmapid']), - (new CTextBox('sysmapname', $data['sysmap']['name'], true))->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH), - (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), - (new CButton('select', _('Select')))->addClass(ZBX_STYLE_BTN_GREY) + new CFormField( + (new CTextBox('name', $data['name'])) + ->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH) + ->setAttribute('autofocus', 'autofocus') + ->setAriaRequired() + ) + ]) + ->addItem([ + new CLabel(_('Linked map')), + new CFormField([ + new CVar('sysmapid', $data['sysmap']['sysmapid']), + (new CTextBox('sysmapname', $data['sysmap']['name'], true))->setWidth(ZBX_TEXTAREA_MEDIUM_WIDTH), + (new CDiv())->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), + (new CButton('select', _('Select')))->addClass(ZBX_STYLE_BTN_GREY) + ]) ]); -if ($data['depth'] >= WIDGET_NAVIGATION_TREE_MAX_DEPTH) { - $form_list->addRow(null, _('Cannot add submaps. Max depth reached.')); +if ($data['depth'] >= Widget::MAX_DEPTH) { + $form_grid->addItem([ + null, + new CFormField(_('Cannot add submaps. Max depth reached.')) + ]); } else { - $form_list->addRow(null, [ - new CCheckBox('add_submaps', 1), - new CLabel(_('Add submaps'), 'add_submaps') + $form_grid->addItem([ + null, + new CFormField([ + new CCheckBox('add_submaps', 1), + new CLabel(_('Add submaps'), 'add_submaps') + ]) ]); } $form - ->addItem($form_list) + ->addItem($form_grid) ->addItem((new CScriptTag('navtreeitem_edit_popup.init();'))->setOnDocumentReady()); $output = [ 'body' => $form->toString(), - 'script_inline' => $this->readJsFile('monitoring.widget.navtreeitem.edit.js.php') + 'script_inline' => $this->readJsFile('navtreeitem.edit.js.php', null, '') ]; if ($messages = get_and_clear_messages()) { @@ -72,4 +88,4 @@ if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { $output['debug'] = CProfiler::getInstance()->make()->toString(); } -echo json_encode($output); +echo json_encode($output, JSON_THROW_ON_ERROR); diff --git a/ui/widgets/navtree/views/widget.edit.php b/ui/widgets/navtree/views/widget.edit.php new file mode 100755 index 00000000000..9523d90642d --- /dev/null +++ b/ui/widgets/navtree/views/widget.edit.php @@ -0,0 +1,53 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Map navigation tree widget form view. + * + * @var CView $this + * @var array $data + */ + +use Zabbix\Widgets\Fields\CWidgetFieldReference; + +$form = (new CWidgetFormView($data)) + ->addFieldVar($data['fields'][CWidgetFieldReference::FIELD_NAME]); + +// Add dynamically created fields navtree.name.<N>, navtree.parent.<N>, navtree.order.<N> and navtree.sysmapid.<N>. +foreach ($data['fields']['navtree']->getValue() as $i => $navtree_item) { + $form->addVar($data['fields']['navtree']->getName().'.name.'.$i, $navtree_item['name']); + + if ($navtree_item['order'] != 1) { + $form->addVar($data['fields']['navtree']->getName().'.order.'.$i, $navtree_item['order']); + } + + if ($navtree_item['parent'] != 0) { + $form->addVar($data['fields']['navtree']->getName().'.parent.'.$i, $navtree_item['parent']); + } + + if (array_key_exists('sysmapid', $navtree_item)) { + $form->addVar($data['fields']['navtree']->getName().'.sysmapid.'.$i, $navtree_item['sysmapid']); + } +} + +$form + ->addField(new CWidgetFieldCheckBoxView($data['fields']['show_unavailable'])) + ->show(); diff --git a/ui/app/views/monitoring.widget.navtree.view.php b/ui/widgets/navtree/views/widget.view.php index 3ec7643f991..ae0eefce964 100644 --- a/ui/app/views/monitoring.widget.navtree.view.php +++ b/ui/widgets/navtree/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,10 +20,15 @@ /** + * Map navigation tree widget view. + * * @var CView $this + * @var array $data */ -$item = new CNavigationTree([ +use Widgets\NavTree\Includes\NavigationTree; + +$item = new NavigationTree([ 'problems' => $data['problems'], 'severity_config' => $data['severity_config'], 'initial_load' => $data['initial_load'], @@ -34,23 +39,7 @@ $item = new CNavigationTree([ 'show_unavailable' => $data['show_unavailable'] ]); -if ($data['error'] !== null) { - $item->setError($data['error']); -} - -$output = [ - 'name' => $data['name'], - 'body' => $item->toString(), - 'navtree_data' => $item->getScriptData() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($item) + ->setVar('navtree_data', $item->getScriptData()) + ->show(); diff --git a/ui/widgets/plaintext/Widget.php b/ui/widgets/plaintext/Widget.php new file mode 100755 index 00000000000..e5d5e71049b --- /dev/null +++ b/ui/widgets/plaintext/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\PlainText; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Plain text'); + } +} diff --git a/ui/app/controllers/CControllerWidgetPlainTextView.php b/ui/widgets/plaintext/actions/WidgetView.php index 71b445664d2..3eb5972458a 100644 --- a/ui/app/controllers/CControllerWidgetPlainTextView.php +++ b/ui/widgets/plaintext/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,45 +19,50 @@ **/ -/** - * Class for Dashboard Plain-text widget view. - */ -class CControllerWidgetPlainTextView extends CControllerWidget { +namespace Widgets\PlainText\Actions; - public function __construct() { - parent::__construct(); +use API, + CArrayHelper, + CControllerDashboardWidgetView, + CControllerResponseData, + CJsScript, + CPre, + Manager; - $this->setType(WIDGET_PLAIN_TEXT); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json', +use Zabbix\Core\CWidget; + +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'dynamic_hostid' => 'db hosts.hostid' ]); } - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); + protected function doAction(): void { $error = null; - $dynamic_widget_name = $this->getDefaultName(); + $dynamic_widget_name = $this->widget->getDefaultName(); $same_host = true; $items = []; $histories = []; // Editing template dashboard? - if ($this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD && !$this->hasInput('dynamic_hostid')) { + if ($this->hasInput('templateid') && !$this->hasInput('dynamic_hostid')) { $error = _('No data.'); } else { - $is_template_dashboard = ($this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD); - $is_dynamic_item = ($is_template_dashboard || $fields['dynamic'] == WIDGET_DYNAMIC_ITEM); + $is_template_dashboard = $this->hasInput('templateid'); + $is_dynamic_item = ($is_template_dashboard || $this->fields_values['dynamic'] == CWidget::DYNAMIC_ITEM); - if ($fields['itemids']) { + if ($this->fields_values['itemids']) { $items = API::Item()->get([ 'output' => ['itemid', 'name', 'key_', 'value_type', 'units', 'valuemapid'], 'selectHosts' => ['name'], 'selectValueMap' => ['mappings'], - 'itemids' => $fields['itemids'], + 'itemids' => $this->fields_values['itemids'], 'webitems' => true, 'preservekeys' => true ]); @@ -83,14 +88,14 @@ class CControllerWidgetPlainTextView extends CControllerWidget { $error = _('No permissions to referred object or it does not exist!'); } else { - $histories = Manager::History()->getLastValues($items, $fields['show_lines']); + $histories = Manager::History()->getLastValues($items, $this->fields_values['show_lines']); if ($histories) { - $histories = call_user_func_array('array_merge', $histories); + $histories = array_merge(...$histories); foreach ($histories as &$history) { $history['value'] = formatHistoryValue($history['value'], $items[$history['itemid']], false); - $history['value'] = $fields['show_as_html'] + $history['value'] = $this->fields_values['show_as_html'] ? new CJsScript($history['value']) : new CPre($history['value']); } @@ -133,9 +138,9 @@ class CControllerWidgetPlainTextView extends CControllerWidget { 'name' => $this->getInput('name', $dynamic_widget_name), 'items' => $items, 'histories' => $histories, - 'style' => $fields['style'], + 'style' => $this->fields_values['style'], 'same_host' => $same_host, - 'show_lines' => $fields['show_lines'], + 'show_lines' => $this->fields_values['show_lines'], 'error' => $error, 'user' => [ 'debug_mode' => $this->getDebugMode() diff --git a/ui/widgets/plaintext/includes/WidgetForm.php b/ui/widgets/plaintext/includes/WidgetForm.php new file mode 100644 index 00000000000..ae1d9135e2a --- /dev/null +++ b/ui/widgets/plaintext/includes/WidgetForm.php @@ -0,0 +1,68 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\PlainText\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldIntegerBox, + CWidgetFieldMultiSelectItem, + CWidgetFieldRadioButtonList +}; + +/** + * Plain text widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + (new CWidgetFieldMultiSelectItem('itemids', _('Items'), $this->templateid)) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField( + (new CWidgetFieldRadioButtonList('style', _('Items location'), [ + STYLE_LEFT => _('Left'), + STYLE_TOP => _('Top') + ]))->setDefault(STYLE_LEFT) + ) + ->addField( + (new CWidgetFieldIntegerBox('show_lines', _('Show lines'), ZBX_MIN_WIDGET_LINES, + ZBX_MAX_WIDGET_LINES + )) + ->setDefault(ZBX_DEFAULT_WIDGET_LINES) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField( + new CWidgetFieldCheckBox('show_as_html', _('Show text as HTML')) + ) + ->addField($this->templateid === null + ? new CWidgetFieldCheckBox('dynamic', _('Enable host selection')) + : null + ); + } +} diff --git a/ui/widgets/plaintext/manifest.json b/ui/widgets/plaintext/manifest.json new file mode 100755 index 00000000000..0a67be5aea9 --- /dev/null +++ b/ui/widgets/plaintext/manifest.json @@ -0,0 +1,16 @@ +{ + "manifest_version": 2.0, + "id": "plaintext", + "type": "widget", + "name": "Plain text", + "namespace": "PlainText", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "template_support": true, + "size": { + "width": 6, + "height": 3 + } + } +} diff --git a/ui/include/classes/widgets/views/widget.systeminfo.form.view.php b/ui/widgets/plaintext/views/widget.edit.php index 83a7fc8d19f..2da1e13b652 100644..100755 --- a/ui/include/classes/widgets/views/widget.systeminfo.form.view.php +++ b/ui/widgets/plaintext/views/widget.edit.php @@ -20,29 +20,27 @@ /** - * System information widget form view. + * Plain text widget form view. * * @var CView $this * @var array $data */ -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -// Show. -$form_grid->addItem([ - CWidgetHelper::getLabel($fields['info_type']), - new CFormField(CWidgetHelper::getRadioButtonList($fields['info_type'])) -]); - -$form->addItem($form_grid); - -return [ - 'form' => $form -]; +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldMultiSelectItemView($data['fields']['itemids'], $data['captions']['ms']['items']['itemids']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['style']) + ) + ->addField( + new CWidgetFieldIntegerBoxView($data['fields']['show_lines']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_as_html']) + ) + ->addField(array_key_exists('dynamic', $data['fields']) + ? new CWidgetFieldCheckBoxView($data['fields']['dynamic']) + : null + ) + ->show(); diff --git a/ui/app/views/monitoring.widget.plaintext.view.php b/ui/widgets/plaintext/views/widget.view.php index 6da0507002e..5ddea6ea7e0 100644 --- a/ui/app/views/monitoring.widget.plaintext.view.php +++ b/ui/widgets/plaintext/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,6 +20,8 @@ /** + * Plain text widget view. + * * @var CView $this * @var array $data */ @@ -74,9 +76,10 @@ else { } else { if (($history_item === null && $row_values) - || $history_item !== null - && (($clock != 0 && $history_item['clock'] != $clock) - || array_key_exists($history_item['itemid'], $row_values))) { + || ($history_item !== null && ( + ($clock != 0 && $history_item['clock'] != $clock) + || array_key_exists($history_item['itemid'], $row_values))) + ) { $table_row = [ (new CCol(zbx_date2str(DATE_TIME_FORMAT_SECONDS, $clock)))->addClass(ZBX_STYLE_NOWRAP) ]; @@ -97,18 +100,6 @@ else { } while ($history_item !== null && $table->getNumRows() < $data['show_lines']); } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/problemhosts/Widget.php b/ui/widgets/problemhosts/Widget.php new file mode 100755 index 00000000000..038bb9a766f --- /dev/null +++ b/ui/widgets/problemhosts/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\ProblemHosts; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Problem hosts'); + } +} diff --git a/ui/app/controllers/CControllerWidgetProblemHostsView.php b/ui/widgets/problemhosts/actions/WidgetView.php index 5bbebf8efe1..63ff9ee9947 100644 --- a/ui/app/controllers/CControllerWidgetProblemHostsView.php +++ b/ui/widgets/problemhosts/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,41 +19,35 @@ **/ -require_once dirname(__FILE__).'/../../include/blocks.inc.php'; +namespace Widgets\ProblemHosts\Actions; -class CControllerWidgetProblemHostsView extends CControllerWidget { +use API, + CArrayHelper, + CControllerDashboardWidgetView, + CControllerResponseData, + CRoleHelper; - public function __construct() { - parent::__construct(); +class WidgetView extends CControllerDashboardWidgetView { - $this->setType(WIDGET_PROBLEM_HOSTS); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } - - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - - $filter_groupids = $fields['groupids'] ? getSubGroups($fields['groupids']) : null; - $filter_hostids = $fields['hostids'] ? $fields['hostids'] : null; - $filter_problem = ($fields['problem'] !== '') ? $fields['problem'] : null; - $filter_severities = $fields['severities'] - ? $fields['severities'] - : range(TRIGGER_SEVERITY_NOT_CLASSIFIED, TRIGGER_SEVERITY_COUNT - 1); - $filter_show_suppressed = $fields['show_suppressed']; - $filter_ext_ack = $fields['ext_ack']; + protected function doAction(): void { + $filter_groupids = $this->fields_values['groupids'] ? getSubGroups($this->fields_values['groupids']) : null; + $filter_hostids = $this->fields_values['hostids'] ?: null; + $filter_problem = $this->fields_values['problem'] !== '' ? $this->fields_values['problem'] : null; + $filter_severities = $this->fields_values['severities'] ?: range(TRIGGER_SEVERITY_NOT_CLASSIFIED, + TRIGGER_SEVERITY_COUNT - 1 + ); + $filter_show_suppressed = $this->fields_values['show_suppressed']; + $filter_ext_ack = $this->fields_values['ext_ack']; - if ($fields['exclude_groupids']) { - $exclude_groupids = getSubGroups($fields['exclude_groupids']); + if ($this->fields_values['exclude_groupids']) { + $exclude_groupids = getSubGroups($this->fields_values['exclude_groupids']); if ($filter_hostids === null) { // Get all groups if no selected groups defined. if ($filter_groupids === null) { $filter_groupids = array_keys(API::HostGroup()->get([ 'output' => [], - 'real_hosts' => true, + 'with_hosts' => true, 'preservekeys' => true ])); } @@ -143,8 +137,8 @@ class CControllerWidgetProblemHostsView extends CControllerWidget { 'name' => $filter_problem ], 'severities' => $filter_severities, - 'evaltype' => $fields['evaltype'], - 'tags' => $fields['tags'], + 'evaltype' => $this->fields_values['evaltype'], + 'tags' => $this->fields_values['tags'], 'acknowledged' => ($filter_ext_ack == EXTACK_OPTION_UNACK) ? false : null, 'suppressed' => ($filter_show_suppressed == ZBX_PROBLEM_SUPPRESSED_FALSE) ? false : null ]); @@ -232,14 +226,14 @@ class CControllerWidgetProblemHostsView extends CControllerWidget { // Pass results to view. $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'filter' => [ - 'hostids' => $fields['hostids'], - 'problem' => $fields['problem'], + 'hostids' => $this->fields_values['hostids'], + 'problem' => $this->fields_values['problem'], 'severities' => $filter_severities, - 'show_suppressed' => $fields['show_suppressed'], - 'hide_empty_groups' => $fields['hide_empty_groups'], - 'ext_ack' => $fields['ext_ack'] + 'show_suppressed' => $this->fields_values['show_suppressed'], + 'hide_empty_groups' => $this->fields_values['hide_empty_groups'], + 'ext_ack' => $this->fields_values['ext_ack'] ], 'hosts_data' => $hosts_data, 'groups' => $groups, diff --git a/ui/widgets/problemhosts/includes/WidgetForm.php b/ui/widgets/problemhosts/includes/WidgetForm.php new file mode 100644 index 00000000000..020df198807 --- /dev/null +++ b/ui/widgets/problemhosts/includes/WidgetForm.php @@ -0,0 +1,86 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\ProblemHosts\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldRadioButtonList, + CWidgetFieldSeverities, + CWidgetFieldTags, + CWidgetFieldTextBox +}; + +/** + * Problem hosts widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectGroup('exclude_groupids', _('Exclude host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectHost('hostids', _('Hosts')) + ) + ->addField( + new CWidgetFieldTextBox('problem', _('Problem')) + ) + ->addField( + new CWidgetFieldSeverities('severities', _('Severity')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ]))->setDefault(TAG_EVAL_TYPE_AND_OR) + ) + ->addField( + new CWidgetFieldTags('tags') + ) + ->addField( + new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems')) + ) + ->addField( + new CWidgetFieldCheckBox('hide_empty_groups', _('Hide groups without problems')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('ext_ack', _('Problem display'), [ + EXTACK_OPTION_ALL => _('All'), + EXTACK_OPTION_BOTH => _('Separated'), + EXTACK_OPTION_UNACK => _('Unacknowledged only') + ])) + ->setDefault(EXTACK_OPTION_ALL) + ->setFlags(CWidgetField::FLAG_ACKNOWLEDGES) + ); + } +} diff --git a/ui/widgets/problemhosts/manifest.json b/ui/widgets/problemhosts/manifest.json new file mode 100755 index 00000000000..64e49e8a263 --- /dev/null +++ b/ui/widgets/problemhosts/manifest.json @@ -0,0 +1,9 @@ +{ + "manifest_version": 2.0, + "id": "problemhosts", + "type": "widget", + "name": "Problem hosts", + "namespace": "ProblemHosts", + "version": "1.0", + "author": "Zabbix SIA" +} diff --git a/ui/widgets/problemhosts/views/widget.edit.php b/ui/widgets/problemhosts/views/widget.edit.php new file mode 100755 index 00000000000..3aefd30aeb9 --- /dev/null +++ b/ui/widgets/problemhosts/views/widget.edit.php @@ -0,0 +1,65 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Problem hosts widget form view. + * + * @var CView $this + * @var array $data + */ + +$groupids = new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], + $data['captions']['ms']['groups']['groupids'] +); + +(new CWidgetFormView($data)) + ->addField($groupids) + ->addField( + new CWidgetFieldMultiSelectGroupView($data['fields']['exclude_groupids'], + $data['captions']['ms']['groups']['exclude_groupids'] + ) + ) + ->addField( + (new CWidgetFieldMultiSelectHostView($data['fields']['hostids'], $data['captions']['ms']['hosts']['hostids'])) + ->setFilterPreselect(['id' => $groupids->getId(), 'submit_as' => 'groupid']) + ) + ->addField( + new CWidgetFieldTextBoxView($data['fields']['problem']) + ) + ->addField( + new CWidgetFieldSeveritiesView($data['fields']['severities']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['evaltype']) + ) + ->addField( + new CWidgetFieldTagsView($data['fields']['tags']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_suppressed']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['hide_empty_groups']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['ext_ack']) + ) + ->show(); diff --git a/ui/app/views/monitoring.widget.problemhosts.view.php b/ui/widgets/problemhosts/views/widget.view.php index 6057af525a5..0489e1638ff 100644 --- a/ui/app/views/monitoring.widget.problemhosts.view.php +++ b/ui/widgets/problemhosts/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,6 +20,8 @@ /** + * Problem hosts widget view. + * * @var CView $this * @var array $data */ @@ -39,7 +41,7 @@ $table = (new CTableInfo()) $url_group = $data['allowed_ui_problems'] ? (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_name', '') + ->setArgument('filter_name') ->setArgument('show', TRIGGERS_OPTION_RECENT_PROBLEM) ->setArgument('hostids', $data['filter']['hostids']) ->setArgument('name', $data['filter']['problem']) @@ -51,7 +53,7 @@ $url_group = $data['allowed_ui_problems'] $url_host = $data['allowed_ui_problems'] ? (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_name', '') + ->setArgument('filter_name') ->setArgument('show', TRIGGERS_OPTION_RECENT_PROBLEM) ->setArgument('name', $data['filter']['problem']) ->setArgument('show_suppressed', ($data['filter']['show_suppressed'] == ZBX_PROBLEM_SUPPRESSED_TRUE) @@ -125,7 +127,7 @@ foreach ($data['groups'] as $group) { case EXTACK_OPTION_BOTH: if ($group['hosts_problematic_count'] != 0) { - $unack_span = ($last_unack_count !== null) ? [$last_unack_count, ' '._('of').' '] : null; + $unack_span = $last_unack_count !== null ? [$last_unack_count, ' '._('of').' '] : null; $group_row[] = (new CCol([$unack_span, $problematic_count])) ->addClass(CSeverityHelper::getStyle((int) $group['highest_severity'])); } @@ -151,18 +153,6 @@ foreach ($data['groups'] as $group) { $table->addRow($group_row); } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/problems/Widget.php b/ui/widgets/problems/Widget.php new file mode 100755 index 00000000000..1eea9555573 --- /dev/null +++ b/ui/widgets/problems/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Problems; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Problems'); + } +} diff --git a/ui/app/controllers/CControllerWidgetProblemsView.php b/ui/widgets/problems/actions/WidgetView.php index ee71c1ce81d..a9b0d769579 100644 --- a/ui/app/controllers/CControllerWidgetProblemsView.php +++ b/ui/widgets/problems/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,41 +19,45 @@ **/ -class CControllerWidgetProblemsView extends CControllerWidget { +namespace Widgets\Problems\Actions; - public function __construct() { - parent::__construct(); +use CControllerDashboardWidgetView, + CControllerResponseData, + CRoleHelper, + CScreenProblem, + CSettingsHelper; - $this->setType(WIDGET_PROBLEMS); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json', +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'initial_load' => 'in 0,1' ]); } - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); - + protected function doAction(): void { $data = CScreenProblem::getData([ - 'show' => $fields['show'], - 'groupids' => $fields['groupids'], - 'exclude_groupids' => $fields['exclude_groupids'], - 'hostids' => $fields['hostids'], - 'name' => $fields['problem'], - 'severities' => $fields['severities'], - 'evaltype' => $fields['evaltype'], - 'tags' => $fields['tags'], - 'show_suppressed' => $fields['show_suppressed'], - 'unacknowledged' => $fields['unacknowledged'], - 'show_opdata' => $fields['show_opdata'] + 'show' => $this->fields_values['show'], + 'groupids' => $this->fields_values['groupids'], + 'exclude_groupids' => $this->fields_values['exclude_groupids'], + 'hostids' => $this->fields_values['hostids'], + 'name' => $this->fields_values['problem'], + 'severities' => $this->fields_values['severities'], + 'evaltype' => $this->fields_values['evaltype'], + 'tags' => $this->fields_values['tags'], + 'show_suppressed' => $this->fields_values['show_suppressed'], + 'unacknowledged' => $this->fields_values['unacknowledged'], + 'show_opdata' => $this->fields_values['show_opdata'] ]); - list($sortfield, $sortorder) = self::getSorting($fields['sort_triggers']); + + [$sortfield, $sortorder] = self::getSorting($this->fields_values['sort_triggers']); $data = CScreenProblem::sortData($data, $sortfield, $sortorder); - if (count($data['problems']) > $fields['show_lines']) { + if (count($data['problems']) > $this->fields_values['show_lines']) { $info = _n('%1$d of %3$d%2$s problem is shown', '%1$d of %3$d%2$s problems are shown', - min($fields['show_lines'], count($data['problems'])), + min($this->fields_values['show_lines'], count($data['problems'])), (count($data['problems']) > CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT)) ? '+' : '', min(CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT), count($data['problems'])) ); @@ -61,17 +65,18 @@ class CControllerWidgetProblemsView extends CControllerWidget { else { $info = ''; } - $data['problems'] = array_slice($data['problems'], 0, $fields['show_lines'], true); + $data['problems'] = array_slice($data['problems'], 0, $this->fields_values['show_lines'], true); $data = CScreenProblem::makeData($data, [ - 'show' => $fields['show'], + 'show' => $this->fields_values['show'], 'details' => 0, - 'show_opdata' => $fields['show_opdata'] + 'show_opdata' => $this->fields_values['show_opdata'] ]); - if ($fields['show_tags']) { - $data['tags'] = makeTags($data['problems'], true, 'eventid', $fields['show_tags'], $fields['tags'], null, - $fields['tag_name_format'], $fields['tag_priority'] + if ($this->fields_values['show_tags']) { + $data['tags'] = makeTags($data['problems'], true, 'eventid', $this->fields_values['show_tags'], + $this->fields_values['tags'], null, $this->fields_values['tag_name_format'], + $this->fields_values['tag_priority'] ); } @@ -80,17 +85,17 @@ class CControllerWidgetProblemsView extends CControllerWidget { } $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'initial_load' => (bool) $this->getInput('initial_load', 0), 'fields' => [ - 'show' => $fields['show'], - 'show_lines' => $fields['show_lines'], - 'show_tags' => $fields['show_tags'], - 'show_timeline' => $fields['show_timeline'], - 'tags' => $fields['tags'], - 'tag_name_format' => $fields['tag_name_format'], - 'tag_priority' => $fields['tag_priority'], - 'show_opdata' => $fields['show_opdata'] + 'show' => $this->fields_values['show'], + 'show_lines' => $this->fields_values['show_lines'], + 'show_tags' => $this->fields_values['show_tags'], + 'show_timeline' => $this->fields_values['show_timeline'], + 'tags' => $this->fields_values['tags'], + 'tag_name_format' => $this->fields_values['tag_name_format'], + 'tag_priority' => $this->fields_values['tag_priority'], + 'show_opdata' => $this->fields_values['show_opdata'] ], 'data' => $data, 'info' => $info, @@ -113,17 +118,7 @@ class CControllerWidgetProblemsView extends CControllerWidget { ])); } - /** - * Get sorting. - * - * @param int $sort_triggers - * - * @static - * - * @return array - */ - private static function getSorting($sort_triggers) - { + private static function getSorting(int $sort_triggers): array { switch ($sort_triggers) { case SCREEN_SORT_TRIGGERS_TIME_ASC: return ['clock', ZBX_SORT_UP]; diff --git a/ui/js/widgets/class.widget.problems.js b/ui/widgets/problems/assets/js/class.widget.js index 74f24f02da6..74f24f02da6 100644..100755 --- a/ui/js/widgets/class.widget.problems.js +++ b/ui/widgets/problems/assets/js/class.widget.js diff --git a/ui/widgets/problems/includes/WidgetForm.php b/ui/widgets/problems/includes/WidgetForm.php new file mode 100644 index 00000000000..74ef9ea6810 --- /dev/null +++ b/ui/widgets/problems/includes/WidgetForm.php @@ -0,0 +1,159 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Problems\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldIntegerBox, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldRadioButtonList, + CWidgetFieldSelect, + CWidgetFieldSeverities, + CWidgetFieldTags, + CWidgetFieldTextBox +}; + +/** + * Problems widget form. + */ +class WidgetForm extends CWidgetForm { + + private bool $show_tags = false; + + protected function normalizeValues(array $values): array { + $values = self::convertDottedKeys($values); + + if (array_key_exists('show_tags', $values)) { + $this->show_tags = $values['show_tags'] !== SHOW_TAGS_NONE; + } + + return $values; + } + + public function addFields(): self { + return $this + ->addField( + (new CWidgetFieldRadioButtonList('show', _('Show'), [ + TRIGGERS_OPTION_RECENT_PROBLEM => _('Recent problems'), + TRIGGERS_OPTION_IN_PROBLEM => _('Problems'), + TRIGGERS_OPTION_ALL => _('History') + ]))->setDefault(TRIGGERS_OPTION_RECENT_PROBLEM) + ) + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectGroup('exclude_groupids', _('Exclude host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectHost('hostids', _('Hosts')) + ) + ->addField( + new CWidgetFieldTextBox('problem', _('Problem')) + ) + ->addField( + new CWidgetFieldSeverities('severities', _('Severity')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ]))->setDefault(TAG_EVAL_TYPE_AND_OR) + ) + ->addField( + new CWidgetFieldTags('tags') + ) + ->addField( + (new CWidgetFieldRadioButtonList('show_tags', _('Show tags'), [ + SHOW_TAGS_NONE => _('None'), + SHOW_TAGS_1 => SHOW_TAGS_1, + SHOW_TAGS_2 => SHOW_TAGS_2, + SHOW_TAGS_3 => SHOW_TAGS_3 + ]))->setDefault(SHOW_TAGS_NONE) + ) + ->addField( + (new CWidgetFieldRadioButtonList('tag_name_format', _('Tag name'), [ + TAG_NAME_FULL => _('Full'), + TAG_NAME_SHORTENED => _('Shortened'), + TAG_NAME_NONE => _('None') + ])) + ->setDefault(TAG_NAME_FULL) + ->setFlags($this->show_tags ? 0x00 : CWidgetField::FLAG_DISABLED) + ) + ->addField( + (new CWidgetFieldTextBox('tag_priority', _('Tag display priority'))) + ->setFlags($this->show_tags ? 0x00 : CWidgetField::FLAG_DISABLED) + ) + ->addField( + (new CWidgetFieldRadioButtonList('show_opdata', _('Show operational data'), [ + OPERATIONAL_DATA_SHOW_NONE => _('None'), + OPERATIONAL_DATA_SHOW_SEPARATELY => _('Separately'), + OPERATIONAL_DATA_SHOW_WITH_PROBLEM => _('With problem name') + ]))->setDefault(OPERATIONAL_DATA_SHOW_NONE) + ) + ->addField( + new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems')) + ) + ->addField( + (new CWidgetFieldCheckBox('unacknowledged', _('Show unacknowledged only'))) + ->setFlags(CWidgetField::FLAG_ACKNOWLEDGES) + ) + ->addField( + (new CWidgetFieldSelect('sort_triggers', _('Sort entries by'), [ + SCREEN_SORT_TRIGGERS_TIME_DESC => _('Time').' ('._('descending').')', + SCREEN_SORT_TRIGGERS_TIME_ASC => _('Time').' ('._('ascending').')', + SCREEN_SORT_TRIGGERS_SEVERITY_DESC => _('Severity').' ('._('descending').')', + SCREEN_SORT_TRIGGERS_SEVERITY_ASC => _('Severity').' ('._('ascending').')', + SCREEN_SORT_TRIGGERS_NAME_DESC => _('Problem').' ('._('descending').')', + SCREEN_SORT_TRIGGERS_NAME_ASC => _('Problem').' ('._('ascending').')', + SCREEN_SORT_TRIGGERS_HOST_NAME_DESC => _('Host').' ('._('descending').')', + SCREEN_SORT_TRIGGERS_HOST_NAME_ASC => _('Host').' ('._('ascending').')' + ]))->setDefault(SCREEN_SORT_TRIGGERS_TIME_DESC) + ) + ->addField( + (new CWidgetFieldCheckBox('show_timeline', _('Show timeline'))) + ->setDefault(ZBX_TIMELINE_ON) + ->setFlags( + !array_key_exists('sort_triggers', $this->values) + || !array_key_exists($this->values['sort_triggers'], [ + SCREEN_SORT_TRIGGERS_TIME_DESC => true, + SCREEN_SORT_TRIGGERS_TIME_ASC => true + ]) + ? CWidgetField::FLAG_DISABLED + : 0x00 + ) + ) + ->addField( + (new CWidgetFieldIntegerBox('show_lines', _('Show lines'), ZBX_MIN_WIDGET_LINES, + ZBX_MAX_WIDGET_LINES + )) + ->setDefault(ZBX_DEFAULT_WIDGET_LINES) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ); + } +} diff --git a/ui/widgets/problems/manifest.json b/ui/widgets/problems/manifest.json new file mode 100755 index 00000000000..163736d87a9 --- /dev/null +++ b/ui/widgets/problems/manifest.json @@ -0,0 +1,15 @@ +{ + "manifest_version": 2.0, + "id": "problems", + "type": "widget", + "name": "Problems", + "namespace": "Problems", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "js_class": "CWidgetProblems" + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/widgets/problems/views/widget.edit.js.php b/ui/widgets/problems/views/widget.edit.js.php new file mode 100755 index 00000000000..08a310da9d9 --- /dev/null +++ b/ui/widgets/problems/views/widget.edit.js.php @@ -0,0 +1,59 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ +?> + + +window.widget_problems_form = new class { + + init({sort_with_enabled_show_timeline}) { + this._sort_with_enabled_show_timeline = sort_with_enabled_show_timeline; + + this._show_tags = document.getElementById('show_tags'); + this._show_tags.addEventListener('change', () => this.updateForm()); + + this._sort_triggers = document.getElementById('sort_triggers'); + this._sort_triggers.addEventListener('change', () => this.updateForm()); + + this._show_timeline = document.getElementById('show_timeline'); + this._show_timeline_value = this._show_timeline.checked; + + this.updateForm(); + } + + updateForm() { + const show_tags = this._show_tags.querySelector('input:checked').value != <?= SHOW_TAGS_NONE ?>; + + document.getElementById('tag_priority').disabled = !show_tags; + + for (const radio of document.querySelectorAll('#tag_name_format input')) { + radio.disabled = !show_tags; + } + + if (this._sort_with_enabled_show_timeline[this._sort_triggers.value]) { + this._show_timeline.disabled = false; + this._show_timeline.checked = this._show_timeline_value; + } + else { + this._show_timeline.disabled = true; + this._show_timeline_value = this._show_timeline.checked; + this._show_timeline.checked = false; + } + } +}; diff --git a/ui/widgets/problems/views/widget.edit.php b/ui/widgets/problems/views/widget.edit.php new file mode 100755 index 00000000000..d1f4ac6bacd --- /dev/null +++ b/ui/widgets/problems/views/widget.edit.php @@ -0,0 +1,93 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Problems widget form view. + * + * @var CView $this + * @var array $data + */ + +$groupids = new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], + $data['captions']['ms']['groups']['groupids'] +); + +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['show']) + ) + ->addField($groupids) + ->addField( + new CWidgetFieldMultiSelectGroupView($data['fields']['exclude_groupids'], + $data['captions']['ms']['groups']['exclude_groupids'] + ) + ) + ->addField( + (new CWidgetFieldMultiSelectHostView($data['fields']['hostids'], $data['captions']['ms']['hosts']['hostids'])) + ->setFilterPreselect(['id' => $groupids->getId(), 'submit_as' => 'groupid']) + ) + ->addField( + new CWidgetFieldTextBoxView($data['fields']['problem']) + ) + ->addField( + new CWidgetFieldSeveritiesView($data['fields']['severities']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['evaltype']) + ) + ->addField( + new CWidgetFieldTagsView($data['fields']['tags']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['show_tags']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['tag_name_format']) + ) + ->addField( + (new CWidgetFieldTextBoxView($data['fields']['tag_priority']))->setPlaceholder(_('comma-separated list')) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['show_opdata']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_suppressed']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['unacknowledged']) + ) + ->addField( + new CWidgetFieldSelectView($data['fields']['sort_triggers']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_timeline']) + ) + ->addField( + new CWidgetFieldIntegerBoxView($data['fields']['show_lines']) + ) + ->includeJsFile('widget.edit.js.php') + ->addJavaScript('widget_problems_form.init('.json_encode([ + 'sort_with_enabled_show_timeline' => [ + SCREEN_SORT_TRIGGERS_TIME_DESC => true, + SCREEN_SORT_TRIGGERS_TIME_ASC => true + ] + ], JSON_THROW_ON_ERROR).');') + ->show(); diff --git a/ui/app/views/monitoring.widget.problems.view.php b/ui/widgets/problems/views/widget.view.php index 6f2a1abd30c..e0ee472868c 100644 --- a/ui/app/views/monitoring.widget.problems.view.php +++ b/ui/widgets/problems/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,6 +20,8 @@ /** + * Problems widget view. + * * @var CView $this * @var array $data */ @@ -29,8 +31,8 @@ $sort_div = (new CSpan())->addClass(($data['sortorder'] === ZBX_SORT_DOWN) ? ZBX $url_details = $data['allowed_ui_problems'] ? (new CUrl('tr_events.php')) - ->setArgument('triggerid', '') - ->setArgument('eventid', '') + ->setArgument('triggerid') + ->setArgument('eventid') : null; $show_timeline = ($data['sortfield'] === 'clock' && $data['fields']['show_timeline']); @@ -133,6 +135,9 @@ foreach ($data['data']['problems'] as $eventid => $problem) { $is_acknowledged = ($problem['acknowledged'] == EVENT_ACKNOWLEDGED); + $cell_r_clock = ''; + $cell_status = ''; + if ($show_recovery_data) { if ($problem['r_eventid'] != 0) { $cell_r_clock = ($problem['r_clock'] >= $today) @@ -142,9 +147,6 @@ foreach ($data['data']['problems'] as $eventid => $problem) { ->addClass(ZBX_STYLE_NOWRAP) ->addClass(ZBX_STYLE_RIGHT); } - else { - $cell_r_clock = ''; - } $cell_status = new CSpan($value_str); @@ -188,7 +190,7 @@ foreach ($data['data']['problems'] as $eventid => $problem) { ->setHint(_s('Unsuppressed by: %1$s', $user_unsuppressed)); } elseif ($problem['suppression_data']) { - $info_icons[] = makeSuppressedProblemIcon($problem['suppression_data'], false); + $info_icons[] = makeSuppressedProblemIcon($problem['suppression_data']); } elseif (isEventRecentlySuppressed($problem['acknowledges'], $suppression_action)) { // Show blinking button if suppression was made but is not yet processed by server. @@ -327,18 +329,6 @@ if ($data['info'] !== '') { ]); } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/problemsbysv/Widget.php b/ui/widgets/problemsbysv/Widget.php new file mode 100755 index 00000000000..0ae2847a0af --- /dev/null +++ b/ui/widgets/problemsbysv/Widget.php @@ -0,0 +1,34 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\ProblemsBySv; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public const SHOW_GROUPS = 0; + public const SHOW_TOTALS = 1; + + public function getDefaultName(): string { + return _('Problems by severity'); + } +} diff --git a/ui/widgets/problemsbysv/actions/WidgetView.php b/ui/widgets/problemsbysv/actions/WidgetView.php new file mode 100644 index 00000000000..ff2ab751808 --- /dev/null +++ b/ui/widgets/problemsbysv/actions/WidgetView.php @@ -0,0 +1,77 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\ProblemsBySv\Actions; + +use APP, + CControllerDashboardWidgetView, + CControllerResponseData; + +use Widgets\ProblemsBySv\Widget; + +require_once APP::getRootDir().'/include/blocks.inc.php'; + +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ + 'initial_load' => 'in 0,1' + ]); + } + + protected function doAction(): void { + $filter = [ + 'groupids' => getSubGroups($this->fields_values['groupids']), + 'exclude_groupids' => getSubGroups($this->fields_values['exclude_groupids']), + 'hostids' => $this->fields_values['hostids'], + 'problem' => $this->fields_values['problem'], + 'severities' => $this->fields_values['severities'], + 'show_type' => $this->fields_values['show_type'], + 'layout' => $this->fields_values['layout'], + 'show_suppressed' => $this->fields_values['show_suppressed'], + 'hide_empty_groups' => $this->fields_values['hide_empty_groups'], + 'show_opdata' => $this->fields_values['show_opdata'], + 'ext_ack' => $this->fields_values['ext_ack'], + 'show_timeline' => $this->fields_values['show_timeline'], + 'evaltype' => $this->fields_values['evaltype'], + 'tags' => $this->fields_values['tags'] + ]; + + $data = getSystemStatusData($filter); + + if ($filter['show_type'] == Widget::SHOW_TOTALS) { + $data['groups'] = getSystemStatusTotals($data); + } + + $this->setResponse(new CControllerResponseData([ + 'name' => $this->getInput('name', $this->widget->getDefaultName()), + 'initial_load' => (bool) $this->getInput('initial_load', 0), + 'data' => $data, + 'filter' => $filter, + 'user' => [ + 'debug_mode' => $this->getDebugMode() + ], + 'allowed' => $data['allowed'] + ])); + } +} diff --git a/ui/js/widgets/class.widget.problemsbysv.js b/ui/widgets/problemsbysv/assets/js/class.widget.js index 8571443e8ba..5caedf36c9b 100644..100755 --- a/ui/js/widgets/class.widget.problemsbysv.js +++ b/ui/widgets/problemsbysv/assets/js/class.widget.js @@ -20,6 +20,9 @@ class CWidgetProblemsBySv extends CWidget { + static SHOW_GROUPS = 0; + static SHOW_TOTALS = 1; + _registerEvents() { super._registerEvents(); @@ -61,4 +64,9 @@ class CWidgetProblemsBySv extends CWidget { $.unsubscribe('acknowledge.create', this._events.acknowledgeCreated); } + + _hasPadding() { + return this._view_mode == ZBX_WIDGET_VIEW_MODE_NORMAL + && this._fields.show_type != CWidgetProblemsBySv.SHOW_TOTALS; + } } diff --git a/ui/widgets/problemsbysv/includes/WidgetForm.php b/ui/widgets/problemsbysv/includes/WidgetForm.php new file mode 100644 index 00000000000..39b39533711 --- /dev/null +++ b/ui/widgets/problemsbysv/includes/WidgetForm.php @@ -0,0 +1,123 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\ProblemsBySv\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldRadioButtonList, + CWidgetFieldSeverities, + CWidgetFieldTags, + CWidgetFieldTextBox +}; + +use Widgets\ProblemsBySv\Widget; + +/** + * Problems by severity widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectGroup('exclude_groupids', _('Exclude host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectHost('hostids', _('Hosts')) + ) + ->addField( + new CWidgetFieldTextBox('problem', _('Problem')) + ) + ->addField( + new CWidgetFieldSeverities('severities', _('Severity')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ]))->setDefault(TAG_EVAL_TYPE_AND_OR) + ) + ->addField( + new CWidgetFieldTags('tags') + ) + ->addField( + (new CWidgetFieldRadioButtonList('show_type', _('Show'), [ + Widget::SHOW_GROUPS => _('Host groups'), + Widget::SHOW_TOTALS => _('Totals') + ]))->setDefault(Widget::SHOW_GROUPS) + ) + ->addField( + (new CWidgetFieldRadioButtonList('layout', _('Layout'), [ + STYLE_HORIZONTAL => _('Horizontal'), + STYLE_VERTICAL => _('Vertical') + ])) + ->setDefault(STYLE_HORIZONTAL) + ->setFlags( + !array_key_exists('show_type', $this->values) + || !$this->values['show_type'] == Widget::SHOW_TOTALS + ? CWidgetField::FLAG_DISABLED + : 0x00 + ) + ) + ->addField( + (new CWidgetFieldRadioButtonList('show_opdata', _('Show operational data'), [ + OPERATIONAL_DATA_SHOW_NONE => _('None'), + OPERATIONAL_DATA_SHOW_SEPARATELY => _('Separately'), + OPERATIONAL_DATA_SHOW_WITH_PROBLEM => _('With problem name') + ]))->setDefault(OPERATIONAL_DATA_SHOW_NONE) + ) + ->addField( + new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems')) + ) + ->addField( + (new CWidgetFieldCheckBox('hide_empty_groups', _('Hide groups without problems'))) + ->setFlags( + array_key_exists('show_type', $this->values) + && $this->values['show_type'] == Widget::SHOW_TOTALS + ? CWidgetField::FLAG_DISABLED + : 0x00 + ) + ) + ->addField( + (new CWidgetFieldRadioButtonList('ext_ack', _('Problem display'), [ + EXTACK_OPTION_ALL => _('All'), + EXTACK_OPTION_BOTH => _('Separated'), + EXTACK_OPTION_UNACK => _('Unacknowledged only') + ])) + ->setDefault(EXTACK_OPTION_ALL) + ->setFlags(CWidgetField::FLAG_ACKNOWLEDGES) + ) + ->addField( + (new CWidgetFieldCheckBox('show_timeline', _('Show timeline')))->setDefault(ZBX_TIMELINE_ON) + ); + } +} diff --git a/ui/widgets/problemsbysv/manifest.json b/ui/widgets/problemsbysv/manifest.json new file mode 100755 index 00000000000..7ece0b1b02d --- /dev/null +++ b/ui/widgets/problemsbysv/manifest.json @@ -0,0 +1,15 @@ +{ + "manifest_version": 2.0, + "id": "problemsbysv", + "type": "widget", + "name": "Problems by severity", + "namespace": "ProblemsBySv", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "js_class": "CWidgetProblemsBySv" + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/widgets/problemsbysv/views/widget.edit.js.php b/ui/widgets/problemsbysv/views/widget.edit.js.php new file mode 100755 index 00000000000..add705553ac --- /dev/null +++ b/ui/widgets/problemsbysv/views/widget.edit.js.php @@ -0,0 +1,44 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +use Widgets\ProblemsBySv\Widget; + +?> + +window.widget_problemsbysv_form = new class { + + init() { + this._show_type = document.getElementById('show_type'); + this._show_type.addEventListener('change', () => this.updateForm()); + + this.updateForm(); + } + + updateForm() { + const show_type_totals = this._show_type.querySelector('input:checked').value == <?= Widget::SHOW_TOTALS ?>; + + document.getElementById('hide_empty_groups').disabled = show_type_totals; + + for (const radio of document.querySelectorAll('#layout input')) { + radio.disabled = !show_type_totals; + } + } +}; diff --git a/ui/widgets/problemsbysv/views/widget.edit.php b/ui/widgets/problemsbysv/views/widget.edit.php new file mode 100755 index 00000000000..76f97532f26 --- /dev/null +++ b/ui/widgets/problemsbysv/views/widget.edit.php @@ -0,0 +1,79 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Problems by severity widget form view. + * + * @var CView $this + * @var array $data + */ + +$groupids = new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], + $data['captions']['ms']['groups']['groupids'] +); + +(new CWidgetFormView($data)) + ->addField($groupids) + ->addField( + new CWidgetFieldMultiSelectGroupView($data['fields']['exclude_groupids'], + $data['captions']['ms']['groups']['exclude_groupids'] + ) + ) + ->addField( + (new CWidgetFieldMultiSelectHostView($data['fields']['hostids'], $data['captions']['ms']['hosts']['hostids'])) + ->setFilterPreselect(['id' => $groupids->getId(), 'submit_as' => 'groupid']) + ) + ->addField( + new CWidgetFieldTextBoxView($data['fields']['problem']) + ) + ->addField( + new CWidgetFieldSeveritiesView($data['fields']['severities']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['evaltype']) + ) + ->addField( + new CWidgetFieldTagsView($data['fields']['tags']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['show_type']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['layout']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['show_opdata']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_suppressed']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['hide_empty_groups']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['ext_ack']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_timeline']) + ) + ->includeJsFile('widget.edit.js.php') + ->addJavaScript('widget_problemsbysv_form.init();') + ->show(); diff --git a/ui/app/views/monitoring.widget.problemsbysv.view.php b/ui/widgets/problemsbysv/views/widget.view.php index dbff193b4a6..5c1c01e1551 100644 --- a/ui/app/views/monitoring.widget.problemsbysv.view.php +++ b/ui/widgets/problemsbysv/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,11 +20,15 @@ /** + * Problems by severity widget view. + * * @var CView $this * @var array $data */ -if ($data['filter']['show_type'] == WIDGET_PROBLEMS_BY_SV_SHOW_TOTALS) { +use Widgets\ProblemsBySv\Widget; + +if ($data['filter']['show_type'] == Widget::SHOW_TOTALS) { $table = makeSeverityTotals($data) ->addClass(ZBX_STYLE_BY_SEVERITY_WIDGET) ->addClass(ZBX_STYLE_TOTALS_LIST) @@ -50,36 +54,22 @@ else { ? $data['filter']['hide_empty_groups'] : 0; - $groupurl = (new CUrl('zabbix.php')) + $group_url = (new CUrl('zabbix.php')) ->setArgument('action', 'problem.view') - ->setArgument('filter_name', '') + ->setArgument('filter_name') ->setArgument('show', TRIGGERS_OPTION_RECENT_PROBLEM) - ->setArgument('hostids', - array_key_exists('hostids', $data['filter']) ? $data['filter']['hostids'] : null - ) + ->setArgument('hostids', array_key_exists('hostids', $data['filter']) ? $data['filter']['hostids'] : null) ->setArgument('name', array_key_exists('problem', $data['filter']) ? $data['filter']['problem'] : null) ->setArgument('show_suppressed', (array_key_exists('show_suppressed', $data['filter']) && $data['filter']['show_suppressed'] == 1) ? 1 : null ); - $table = makeSeverityTable($data, $hide_empty_groups, $groupurl) + $table = makeSeverityTable($data, $hide_empty_groups, $group_url) ->addClass(ZBX_STYLE_BY_SEVERITY_WIDGET) ->setHeader($header) ->setHeadingColumn(0); } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/slareport/Widget.php b/ui/widgets/slareport/Widget.php new file mode 100755 index 00000000000..55156007717 --- /dev/null +++ b/ui/widgets/slareport/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\SlaReport; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('SLA report'); + } +} diff --git a/ui/app/controllers/CControllerWidgetSlaReportView.php b/ui/widgets/slareport/actions/WidgetView.php index 18abbac170a..5944ea060f2 100644 --- a/ui/app/controllers/CControllerWidgetSlaReportView.php +++ b/ui/widgets/slareport/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,30 +19,28 @@ **/ -class CControllerWidgetSlaReportView extends CControllerWidget { +namespace Widgets\SlaReport\Actions; - public function __construct() { - parent::__construct(); +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CParser, + CRangeTimeParser, + CRoleHelper, + CSettingsHelper, + CTimezoneHelper, + CWebUser, + DateTimeZone; - $this->setType(WIDGET_SLA_REPORT); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } +class WidgetView extends CControllerDashboardWidgetView { - /** - * @throws APIException - */ protected function doAction(): void { - $fields = $this->getForm()->getFieldsData(); - $data = [ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'has_access' => [ CRoleHelper::ACTIONS_MANAGE_SLA => $this->checkAccess(CRoleHelper::ACTIONS_MANAGE_SLA) ], - 'has_serviceid' => (bool) $fields['serviceid'], + 'has_serviceid' => (bool) $this->fields_values['serviceid'], 'has_permissions_error' => false, 'rows_per_page' => CWebUser::$data['rows_per_page'], 'search_limit' => CSettingsHelper::get(CSettingsHelper::SEARCH_LIMIT), @@ -51,10 +49,10 @@ class CControllerWidgetSlaReportView extends CControllerWidget { ] ]; - $db_slas = $fields['slaid'] + $db_slas = $this->fields_values['slaid'] ? API::Sla()->get([ 'output' => ['slaid', 'name', 'period', 'slo', 'timezone', 'status'], - 'slaids' => $fields['slaid'] + 'slaids' => $this->fields_values['slaid'] ]) : []; @@ -64,7 +62,7 @@ class CControllerWidgetSlaReportView extends CControllerWidget { if ($data['sla']['status'] == ZBX_SLA_STATUS_ENABLED) { $data['services'] = API::Service()->get([ 'output' => ['name'], - 'serviceids' => $fields['serviceid'] ?: null, + 'serviceids' => $this->fields_values['serviceid'] ?: null, 'slaids' => $data['sla']['slaid'], 'sortfield' => 'name', 'sortorder' => ZBX_SORT_UP, @@ -72,10 +70,10 @@ class CControllerWidgetSlaReportView extends CControllerWidget { 'preservekeys' => true ]); - if ($fields['serviceid'] && !$data['services']) { + if ($this->fields_values['serviceid'] && !$data['services']) { $service_accessible = API::Service()->get([ 'output' => [], - 'serviceids' => $fields['serviceid'] + 'serviceids' => $this->fields_values['serviceid'] ]); if (!$service_accessible) { @@ -91,8 +89,8 @@ class CControllerWidgetSlaReportView extends CControllerWidget { $range_time_parser = new CRangeTimeParser(); - if ($fields['date_from'] !== '' - && $range_time_parser->parse($fields['date_from']) == CParser::PARSE_SUCCESS) { + if ($this->fields_values['date_from'] !== '' + && $range_time_parser->parse($this->fields_values['date_from']) == CParser::PARSE_SUCCESS) { $period_from = $range_time_parser->getDateTime(true, $timezone)->getTimestamp(); if ($period_from < 0 || $period_from > ZBX_MAX_DATE) { @@ -105,8 +103,8 @@ class CControllerWidgetSlaReportView extends CControllerWidget { $period_from = null; } - if ($fields['date_to'] !== '' - && $range_time_parser->parse($fields['date_to']) == CParser::PARSE_SUCCESS) { + if ($this->fields_values['date_to'] !== '' + && $range_time_parser->parse($this->fields_values['date_to']) == CParser::PARSE_SUCCESS) { $period_to = $range_time_parser->getDateTime(false, $timezone)->getTimestamp(); if ($period_to < 0 || $period_to > ZBX_MAX_DATE) { @@ -122,7 +120,7 @@ class CControllerWidgetSlaReportView extends CControllerWidget { $data['sli'] = API::Sla()->getSli([ 'slaid' => $data['sla']['slaid'], 'serviceids' => array_slice(array_keys($data['services']), 0, $data['rows_per_page']), - 'periods' => $fields['show_periods'] !== '' ? $fields['show_periods'] : null, + 'periods' => $this->fields_values['show_periods'] !== '' ? $this->fields_values['show_periods'] : null, 'period_from' => $period_from, 'period_to' => $period_to ]); diff --git a/ui/widgets/slareport/includes/WidgetForm.php b/ui/widgets/slareport/includes/WidgetForm.php new file mode 100644 index 00000000000..b36086ce6cd --- /dev/null +++ b/ui/widgets/slareport/includes/WidgetForm.php @@ -0,0 +1,127 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\SlaReport\Includes; + +use API, + CAbsoluteTimeParser, + CParser, + CTimezoneHelper, + DateTimeZone; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldDatePicker, + CWidgetFieldIntegerBox, + CWidgetFieldMultiSelectService, + CWidgetFieldMultiSelectSla +}; + +/** + * SLA report widget form. + */ +class WidgetForm extends CWidgetForm { + + public function validate(bool $strict = false): array { + if ($errors = parent::validate($strict)) { + return $errors; + } + + $errors = []; + + $slaids = $this->getFieldValue('slaid'); + + $slas = $slaids + ? API::Sla()->get([ + 'output' => ['timezone'], + 'slaids' => $slaids, + 'filter' => [ + 'status' => ZBX_SLA_STATUS_ENABLED + ] + ]) + : []; + + $sla = $slas ? $slas[0] : null; + + $timezone = new DateTimeZone($sla !== null && $sla['timezone'] !== ZBX_DEFAULT_TIMEZONE + ? $sla['timezone'] + : CTimezoneHelper::getSystemTimezone() + ); + + $absolute_time_parser = new CAbsoluteTimeParser(); + + $period_from = null; + + if ($absolute_time_parser->parse($this->getFieldValue('date_from')) == CParser::PARSE_SUCCESS) { + $period_from = $absolute_time_parser->getDateTime(true, $timezone)->getTimestamp(); + + if ($period_from < 0 || $period_from > ZBX_MAX_DATE) { + $period_from = null; + + $errors[] = _s('Incorrect value for field "%1$s": %2$s.', _s('From'), _('a date is expected')); + } + } + + $period_to = null; + + if ($absolute_time_parser->parse($this->getFieldValue('date_to')) == CParser::PARSE_SUCCESS) { + $period_to = $absolute_time_parser->getDateTime(false, $timezone)->getTimestamp(); + + if ($period_to < 0 || $period_to > ZBX_MAX_DATE) { + $period_to = null; + + $errors[] = _s('Incorrect value for field "%1$s": %2$s.', _s('To'), _('a date is expected')); + } + } + + if ($period_from !== null && $period_to !== null && $period_to <= $period_from) { + $errors[] = _s('"%1$s" date must be less than "%2$s" date.', _('From'), _('To')); + } + + return $errors; + } + + public function addFields(): self { + return $this + ->addField( + (new CWidgetFieldMultiSelectSla('slaid', _('SLA'))) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ->setMultiple(false) + ) + ->addField( + (new CWidgetFieldMultiSelectService('serviceid', _('Service')))->setMultiple(false) + ) + ->addField( + (new CWidgetFieldIntegerBox('show_periods', _('Show periods'), 1, ZBX_SLA_MAX_REPORTING_PERIODS)) + ->setDefault(ZBX_SLA_DEFAULT_REPORTING_PERIODS) + ) + ->addField( + new CWidgetFieldDatePicker('date_from', _('From'), true) + ) + ->addField( + new CWidgetFieldDatePicker('date_to', _('To'), true) + ); + } +} diff --git a/ui/widgets/slareport/manifest.json b/ui/widgets/slareport/manifest.json new file mode 100755 index 00000000000..978ee685497 --- /dev/null +++ b/ui/widgets/slareport/manifest.json @@ -0,0 +1,12 @@ +{ + "manifest_version": 2.0, + "id": "slareport", + "type": "widget", + "name": "SLA report", + "namespace": "SlaReport", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "refresh_rate": 0 + } +} diff --git a/ui/include/classes/widgets/views/js/widget.slareport.form.view.js.php b/ui/widgets/slareport/views/widget.edit.js.php index f1ace3f7ddb..647484b88ed 100644..100755 --- a/ui/include/classes/widgets/views/js/widget.slareport.form.view.js.php +++ b/ui/widgets/slareport/views/widget.edit.js.php @@ -23,14 +23,14 @@ window.widget_slareport_form = new class { init({serviceid_field_id}) { - this.$service = jQuery(`#${serviceid_field_id}`); - this.$service.multiSelect('getSelectButton').addEventListener('click', () => this.selectService()); + this._$service = jQuery(`#${serviceid_field_id}`); + this._$service.multiSelect('getSelectButton').addEventListener('click', () => this.selectService()); } selectService() { const exclude_serviceids = []; - for (const service of this.$service.multiSelect('getData')) { + for (const service of this._$service.multiSelect('getData')) { exclude_serviceids.push(service.id); } @@ -47,7 +47,7 @@ window.widget_slareport_form = new class { data.push({id: service.serviceid, name: service.name}); } - this.$service.multiSelect('addData', data); + this._$service.multiSelect('addData', data); }); } }; diff --git a/ui/widgets/slareport/views/widget.edit.php b/ui/widgets/slareport/views/widget.edit.php new file mode 100755 index 00000000000..700de0afe80 --- /dev/null +++ b/ui/widgets/slareport/views/widget.edit.php @@ -0,0 +1,55 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * SLA report widget form view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldMultiSelectSlaView($data['fields']['slaid'], $data['captions']['ms']['slas']['slaid']) + ) + ->addField( + new CWidgetFieldMultiSelectServiceView($data['fields']['serviceid'], + $data['captions']['ms']['services']['serviceid'] + ) + ) + ->addField( + new CWidgetFieldIntegerBoxView($data['fields']['show_periods']) + ) + ->addField( + (new CWidgetFieldDatePickerView($data['fields']['date_from'])) + ->setDateFormat(ZBX_DATE) + ->setPlaceholder(_('YYYY-MM-DD')) + ) + ->addField( + (new CWidgetFieldDatePickerView($data['fields']['date_to'])) + ->setDateFormat(ZBX_DATE) + ->setPlaceholder(_('YYYY-MM-DD')) + ) + ->includeJsFile('widget.edit.js.php') + ->addJavaScript('widget_slareport_form.init('.json_encode([ + 'serviceid_field_id' => $data['fields']['serviceid']->getName() + ], JSON_THROW_ON_ERROR).');') + ->show(); diff --git a/ui/app/views/monitoring.widget.slareport.view.php b/ui/widgets/slareport/views/widget.view.php index 9c418f332b0..be524a6979e 100644 --- a/ui/app/views/monitoring.widget.slareport.view.php +++ b/ui/widgets/slareport/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,6 +20,8 @@ /** + * SLA report widget view. + * * @var CView $this * @var array $data */ @@ -128,18 +130,6 @@ else { } } -$output = [ - 'name' => $data['name'], - 'body' => (new CDiv($report))->addClass('dashboard-widget-slareport')->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($report) + ->show(); diff --git a/ui/widgets/svggraph/Widget.php b/ui/widgets/svggraph/Widget.php new file mode 100755 index 00000000000..a1c011df9c0 --- /dev/null +++ b/ui/widgets/svggraph/Widget.php @@ -0,0 +1,46 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\SvgGraph; + +use Widgets\SvgGraph\Includes\WidgetForm; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Graph'); + } + + public function usesTimeSelector(array $fields_values): bool { + return !WidgetForm::hasOverrideTime($fields_values); + } + + public function getTranslationStrings(): array { + return [ + 'class.widget.js' => [ + 'Actions' => _s('Actions'), + 'Download image' => _s('Download image') + ] + ]; + } +} diff --git a/ui/widgets/svggraph/actions/WidgetView.php b/ui/widgets/svggraph/actions/WidgetView.php new file mode 100644 index 00000000000..f0d0591ef3f --- /dev/null +++ b/ui/widgets/svggraph/actions/WidgetView.php @@ -0,0 +1,195 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\SvgGraph\Actions; + +use CControllerDashboardWidgetView, + CControllerResponseData, + CNumberParser, + CParser, + CRangeTimeParser, + CSvgGraphHelper; + +use Widgets\SvgGraph\Includes\WidgetForm; + +class WidgetView extends CControllerDashboardWidgetView { + + private const GRAPH_WIDTH_MIN = 1; + private const GRAPH_WIDTH_MAX = 65535; + private const GRAPH_HEIGHT_MIN = 1; + private const GRAPH_HEIGHT_MAX = 65535; + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ + 'edit_mode' => 'in 0,1', + 'content_width' => 'int32|ge '.self::GRAPH_WIDTH_MIN.'|le '.self::GRAPH_WIDTH_MAX, + 'content_height' => 'int32|ge '.self::GRAPH_HEIGHT_MIN.'|le '.self::GRAPH_HEIGHT_MAX, + 'preview' => 'in 1', + 'from' => 'string', + 'to' => 'string' + ]); + } + + protected function doAction(): void { + $edit_mode = $this->getInput('edit_mode', 0); + $width = (int) $this->getInput('content_width', self::GRAPH_WIDTH_MIN); + $height = (int) $this->getInput('content_height', self::GRAPH_HEIGHT_MIN); + $preview = (bool) $this->getInput('preview', 0); // Configuration preview. + + $dashboard_time = !WidgetForm::hasOverrideTime($this->fields_values); + + if ($dashboard_time && !$preview) { + $from = $this->getInput('from'); + $to = $this->getInput('to'); + } + else { + $from = $this->fields_values['time_from']; + $to = $this->fields_values['time_to']; + } + + $range_time_parser = new CRangeTimeParser(); + + $range_time_parser->parse($from); + $time_from = $range_time_parser->getDateTime(true)->getTimestamp(); + + $range_time_parser->parse($to); + $time_to = $range_time_parser->getDateTime(false)->getTimestamp(); + + $parser = new CNumberParser(['with_size_suffix' => true, 'with_time_suffix' => true]); + + $percentile_left_value = $parser->parse($this->fields_values['percentile_left_value']) == CParser::PARSE_SUCCESS + ? $parser->calcValue() + : null; + + $percentile_right_value = $parser->parse($this->fields_values['percentile_right_value']) == CParser::PARSE_SUCCESS + ? $parser->calcValue() + : null; + + $lefty_min = $parser->parse($this->fields_values['lefty_min']) == CParser::PARSE_SUCCESS + ? $parser->calcValue() + : null; + + $lefty_max = $parser->parse($this->fields_values['lefty_max']) == CParser::PARSE_SUCCESS + ? $parser->calcValue() + : null; + + $righty_min = $parser->parse($this->fields_values['righty_min']) == CParser::PARSE_SUCCESS + ? $parser->calcValue() + : null; + + $righty_max = $parser->parse($this->fields_values['righty_max']) == CParser::PARSE_SUCCESS + ? $parser->calcValue() + : null; + + $graph_data = [ + 'data_sets' => array_values($this->fields_values['ds']), + 'data_source' => $this->fields_values['source'], + 'dashboard_time' => $dashboard_time, + 'displaying' => [ + 'show_simple_triggers' => $this->fields_values['simple_triggers'] == SVG_GRAPH_SIMPLE_TRIGGERS_ON, + 'show_working_time' => $this->fields_values['working_time'] == SVG_GRAPH_WORKING_TIME_ON, + 'show_percentile_left' => $this->fields_values['percentile_left'] == SVG_GRAPH_PERCENTILE_LEFT_ON, + 'percentile_left_value' => $percentile_left_value, + 'show_percentile_right' => $this->fields_values['percentile_right'] == SVG_GRAPH_PERCENTILE_RIGHT_ON, + 'percentile_right_value' => $percentile_right_value + ], + 'time_period' => [ + 'time_from' => $time_from, + 'time_to' => $time_to + ], + 'axes' => [ + 'show_left_y_axis' => $this->fields_values['lefty'] == SVG_GRAPH_AXIS_ON, + 'left_y_min' => $lefty_min, + 'left_y_max' => $lefty_max, + 'left_y_units' => $this->fields_values['lefty_units'] == SVG_GRAPH_AXIS_UNITS_STATIC + ? $this->fields_values['lefty_static_units'] + : null, + 'show_right_y_axis' => $this->fields_values['righty'] == SVG_GRAPH_AXIS_ON, + 'right_y_min' => $righty_min, + 'right_y_max' => $righty_max, + 'right_y_units' => $this->fields_values['righty_units'] == SVG_GRAPH_AXIS_UNITS_STATIC + ? $this->fields_values['righty_static_units'] + : null, + 'show_x_axis' => $this->fields_values['axisx'] == SVG_GRAPH_AXIS_ON + ], + 'legend' => [ + 'show_legend' => $this->fields_values['legend'] == SVG_GRAPH_LEGEND_ON, + 'legend_columns' => $this->fields_values['legend_columns'], + 'legend_lines' => $this->fields_values['legend_lines'], + 'legend_statistic' => $this->fields_values['legend_statistic'] + ], + 'problems' => [ + 'show_problems' => $this->fields_values['show_problems'] == SVG_GRAPH_PROBLEMS_ON, + 'graph_item_problems' => $this->fields_values['graph_item_problems'] == SVG_GRAPH_SELECTED_ITEM_PROBLEMS, + 'problemhosts' => $this->fields_values['problemhosts'], + 'severities' => $this->fields_values['severities'], + 'problem_name' => $this->fields_values['problem_name'], + 'evaltype' => $this->fields_values['evaltype'], + 'tags' => $this->fields_values['tags'] + ], + 'overrides' => array_values($this->fields_values['or']) + ]; + + $svg_options = CSvgGraphHelper::get($graph_data, $width, $height); + if ($svg_options['errors']) { + error($svg_options['errors']); + } + + if (!$preview) { + $svg_options['data'] = zbx_array_merge($svg_options['data'], [ + 'sbox' => $graph_data['dashboard_time'] && !$edit_mode, + 'show_problems' => $graph_data['problems']['show_problems'], + 'show_simple_triggers' => $graph_data['displaying']['show_simple_triggers'], + 'time_from' => $graph_data['time_period']['time_from'], + 'hint_max_rows' => ZBX_WIDGET_ROWS + ]); + } + + $this->setResponse(new CControllerResponseData([ + 'name' => $this->getInput('name', $this->widget->getDefaultName()), + 'svg' => $svg_options['svg'].$svg_options['legend'], + 'svg_options' => $svg_options, + 'preview' => $preview, + 'info' => $this->makeWidgetInfo(), + 'user' => [ + 'debug_mode' => $this->getDebugMode() + ] + ])); + } + + /** + * Make widget specific info to show in widget's header. + */ + private function makeWidgetInfo(): array { + $info = []; + + if (WidgetForm::hasOverrideTime($this->fields_values)) { + $info[] = [ + 'icon' => 'btn-info-clock', + 'hint' => relativeDateToText($this->fields_values['time_from'], $this->fields_values['time_to']) + ]; + } + + return $info; + } +} diff --git a/ui/js/widgets/class.widget.svggraph.js b/ui/widgets/svggraph/assets/js/class.widget.js index 3f832b5cc45..02cb14f77ca 100644..100755 --- a/ui/js/widgets/class.widget.svggraph.js +++ b/ui/widgets/svggraph/assets/js/class.widget.js @@ -154,4 +154,8 @@ class CWidgetSvgGraph extends CWidget { return menu; } + + _hasPadding() { + return true; + } } diff --git a/ui/widgets/svggraph/includes/WidgetForm.php b/ui/widgets/svggraph/includes/WidgetForm.php new file mode 100644 index 00000000000..27135b2e10c --- /dev/null +++ b/ui/widgets/svggraph/includes/WidgetForm.php @@ -0,0 +1,470 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\SvgGraph\Includes; + +use CNumberParser, + CParser, + CRangeTimeParser, + CSettingsHelper; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldDatePicker, + CWidgetFieldGraphDataSet, + CWidgetFieldGraphOverride, + CWidgetFieldHostPatternSelect, + CWidgetFieldNumericBox, + CWidgetFieldRadioButtonList, + CWidgetFieldRangeControl, + CWidgetFieldSelect, + CWidgetFieldSeverities, + CWidgetFieldTags, + CWidgetFieldTextBox +}; + +/** + * Graph widget form view. + */ +class WidgetForm extends CWidgetForm { + + private const PERCENTILE_MIN = 1; + private const PERCENTILE_MAX = 100; + + private bool $percentile_left_on = false; + private bool $percentile_right_on = false; + + private bool $graph_time_on = false; + + private bool $lefty_on = true; + private bool $lefty_units_static = false; + private bool $righty_on = true; + private bool $righty_units_static = false; + + private bool $legend_on = true; + private bool $legend_statistic_on = false; + + private bool $problems_on = false; + + public function validate(bool $strict = false): array { + $errors = parent::validate($strict); + + $number_parser_w_suffix = new CNumberParser(['with_size_suffix' => true, 'with_time_suffix' => true]); + $number_parser_wo_suffix = new CNumberParser(); + + // Percentiles + if ($this->getFieldValue('percentile_left') == SVG_GRAPH_PERCENTILE_LEFT_ON) { + $percentile_left_value = $this->getFieldValue('percentile_left_value'); + + if ($percentile_left_value !== '') { + $percentile_left_value_calculated = + $number_parser_wo_suffix->parse($percentile_left_value) == CParser::PARSE_SUCCESS + ? $number_parser_wo_suffix->calcValue() + : null; + + if ($percentile_left_value_calculated === null + || $percentile_left_value_calculated < self::PERCENTILE_MIN + || $percentile_left_value_calculated > self::PERCENTILE_MAX) { + $errors[] = _s('Invalid parameter "%1$s": %2$s.', _('Percentile line (left)'), + _s('value must be between "%1$s" and "%2$s"', self::PERCENTILE_MIN, self::PERCENTILE_MAX) + ); + } + } + } + + if ($this->getFieldValue('percentile_right') == SVG_GRAPH_PERCENTILE_RIGHT_ON) { + $percentile_right_value = $this->getFieldValue('percentile_right_value'); + + if ($percentile_right_value !== '') { + $percentile_right_value_calculated = + $number_parser_wo_suffix->parse($percentile_right_value) == CParser::PARSE_SUCCESS + ? $number_parser_wo_suffix->calcValue() + : null; + + if ($percentile_right_value_calculated === null + || $percentile_right_value_calculated < self::PERCENTILE_MIN + || $percentile_right_value_calculated > self::PERCENTILE_MAX) { + $errors[] = _s('Invalid parameter "%1$s": %2$s.', _('Percentile line (right)'), + _s('value must be between "%1$s" and "%2$s"', self::PERCENTILE_MIN, self::PERCENTILE_MAX) + ); + } + } + } + + // Test graph custom time period. + if ($this->getFieldValue('graph_time') == SVG_GRAPH_CUSTOM_TIME_ON) { + $errors = array_merge($errors, self::validateTimeSelectorPeriod($this->getFieldValue('time_from'), + $this->getFieldValue('time_to') + )); + } + + // Validate Min/Max values in Axes tab. + if ($this->getFieldValue('lefty') == SVG_GRAPH_AXIS_ON) { + $lefty_min = $number_parser_w_suffix->parse($this->getFieldValue('lefty_min')) == CParser::PARSE_SUCCESS + ? $number_parser_w_suffix->calcValue() + : null; + + $lefty_max = $number_parser_w_suffix->parse($this->getFieldValue('lefty_max')) == CParser::PARSE_SUCCESS + ? $number_parser_w_suffix->calcValue() + : null; + + if ($lefty_min !== null && $lefty_max !== null && $lefty_min >= $lefty_max) { + $errors[] = _s('Invalid parameter "%1$s": %2$s.', _('Left Y').'/'._('Max'), + _('Y axis MAX value must be greater than Y axis MIN value') + ); + } + } + + if ($this->getFieldValue('righty') == SVG_GRAPH_AXIS_ON) { + $righty_min = $number_parser_w_suffix->parse($this->getFieldValue('righty_min')) == CParser::PARSE_SUCCESS + ? $number_parser_w_suffix->calcValue() + : null; + + $righty_max = $number_parser_w_suffix->parse($this->getFieldValue('righty_max')) == CParser::PARSE_SUCCESS + ? $number_parser_w_suffix->calcValue() + : null; + + if ($righty_min !== null && $righty_max !== null && $righty_min >= $righty_max) { + $errors[] = _s('Invalid parameter "%1$s": %2$s.', _('Right Y').'/'._('Max'), + _('Y axis MAX value must be greater than Y axis MIN value') + ); + } + } + + return $errors; + } + + protected function normalizeValues(array $values): array { + $values = parent::normalizeValues($values); + + if (array_key_exists('percentile_left', $values)) { + $this->percentile_left_on = $values['percentile_left'] == SVG_GRAPH_PERCENTILE_LEFT_ON; + } + + if (!$this->percentile_left_on) { + unset($values['percentile_left_value']); + } + + if (array_key_exists('percentile_right', $values)) { + $this->percentile_right_on = $values['percentile_right'] == SVG_GRAPH_PERCENTILE_RIGHT_ON; + } + + if (!$this->percentile_right_on) { + unset($values['percentile_right_value']); + } + + if (array_key_exists('graph_time', $values)) { + $this->graph_time_on = $values['graph_time'] == SVG_GRAPH_CUSTOM_TIME_ON; + } + + if (!$this->graph_time_on) { + unset($values['time_from'], $values['time_to']); + } + + if (array_key_exists('lefty', $values)) { + $this->lefty_on = $values['lefty'] == SVG_GRAPH_AXIS_ON; + } + + if (!$this->lefty_on) { + unset($values['lefty_min'], $values['lefty_max'], $values['lefty_units']); + } + + if (array_key_exists('lefty_units', $values)) { + $this->lefty_units_static = $values['lefty_units'] == SVG_GRAPH_AXIS_UNITS_STATIC; + } + + if (!$this->lefty_on || !$this->lefty_units_static) { + unset($values['lefty_static_units']); + } + + if (array_key_exists('righty', $values)) { + $this->righty_on = $values['righty'] == SVG_GRAPH_AXIS_ON; + } + + if (!$this->righty_on) { + unset($values['righty_min'], $values['righty_max'], $values['righty_units']); + } + + if (array_key_exists('righty_units', $values)) { + $this->righty_units_static = $values['righty_units'] == SVG_GRAPH_AXIS_UNITS_STATIC; + } + + if (!$this->righty_on || !$this->righty_units_static) { + unset($values['righty_static_units']); + } + + if (array_key_exists('legend', $values)) { + $this->legend_on = $values['legend'] == SVG_GRAPH_LEGEND_ON; + } + + if (array_key_exists('legend_statistic', $values)) { + $this->legend_statistic_on = $values['legend_statistic'] == SVG_GRAPH_LEGEND_STATISTIC_ON; + } + + if (array_key_exists('show_problems', $values)) { + $this->problems_on = $values['show_problems'] == SVG_GRAPH_PROBLEMS_ON; + } + + if (!$this->problems_on) { + unset($values['graph_item_problems'], $values['problemhosts'], $values['severities'], + $values['problem_name'], $values['evaltype'], $values['tags'] + ); + } + + return $values; + } + + public function addFields(): self { + return $this + ->initDataSetFields() + ->initDisplayingOptionsFields() + ->initTimePeriodFields() + ->initAxesFields() + ->initLegendFields() + ->initProblemsFields() + ->initOverridesFields(); + } + + private function initDataSetFields(): self { + return $this->addField( + (new CWidgetFieldGraphDataSet('ds', _('Data set')))->setFlags(CWidgetField::FLAG_NOT_EMPTY) + ); + } + + private function initDisplayingOptionsFields(): self { + return $this + ->addField( + (new CWidgetFieldRadioButtonList('source', _('History data selection'), [ + SVG_GRAPH_DATA_SOURCE_AUTO => _x('Auto', 'history source selection method'), + SVG_GRAPH_DATA_SOURCE_HISTORY => _('History'), + SVG_GRAPH_DATA_SOURCE_TRENDS => _('Trends') + ]))->setDefault(SVG_GRAPH_DATA_SOURCE_AUTO) + ) + ->addField( + new CWidgetFieldCheckBox('simple_triggers', _('Simple triggers')) + ) + ->addField( + new CWidgetFieldCheckBox('working_time', _('Working time')) + ) + ->addField( + new CWidgetFieldCheckBox('percentile_left', _('Percentile line (left)')) + ) + ->addField( + (new CWidgetFieldTextBox('percentile_left_value', null)) + ->setFlags(!$this->percentile_left_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + new CWidgetFieldCheckBox('percentile_right', _('Percentile line (right)')) + ) + ->addField( + (new CWidgetFieldTextBox('percentile_right_value', null)) + ->setFlags(!$this->percentile_right_on ? CWidgetField::FLAG_DISABLED : 0x00) + ); + } + + private function initTimePeriodFields(): self { + return $this + ->addField( + new CWidgetFieldCheckBox('graph_time', _('Set custom time period')) + ) + ->addField( + (new CWidgetFieldDatePicker('time_from', _('From'))) + ->setDefault('now-1h') + ->setFlags($this->graph_time_on + ? CWidgetField::FLAG_NOT_EMPTY + : CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_DISABLED + ) + ) + ->addField( + (new CWidgetFieldDatePicker('time_to', _('To'))) + ->setDefault('now') + ->setFlags($this->graph_time_on + ? CWidgetField::FLAG_NOT_EMPTY + : CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_DISABLED + ) + ); + } + + private function initAxesFields(): self { + return $this + ->addField( + (new CWidgetFieldCheckBox('lefty', _('Left Y'), _('Show')))->setDefault(SVG_GRAPH_AXIS_ON) + ) + ->addField( + (new CWidgetFieldNumericBox('lefty_min', _('Min'))) + ->setFullName(_('Left Y').'/'._('Min')) + ->setFlags(!$this->lefty_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldNumericBox('lefty_max', _('Max'))) + ->setFullName(_('Left Y').'/'._('Max')) + ->setFlags(!$this->lefty_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldSelect('lefty_units', _('Units'), [ + SVG_GRAPH_AXIS_UNITS_AUTO => _x('Auto', 'history source selection method'), + SVG_GRAPH_AXIS_UNITS_STATIC => _x('Static', 'history source selection method') + ])) + ->setDefault(SVG_GRAPH_AXIS_UNITS_AUTO) + ->setFlags(!$this->lefty_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldTextBox('lefty_static_units')) + ->setFlags(!$this->lefty_on || !$this->lefty_units_static ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldCheckBox('righty', _('Right Y'), _('Show')))->setDefault(SVG_GRAPH_AXIS_ON) + ) + ->addField( + (new CWidgetFieldNumericBox('righty_min', _('Min'))) + ->setFullName(_('Right Y').'/'._('Min')) + ->setFlags(!$this->righty_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldNumericBox('righty_max', _('Max'))) + ->setFullName(_('Right Y').'/'._('Max')) + ->setFlags(!$this->righty_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldSelect('righty_units', _('Units'), [ + SVG_GRAPH_AXIS_UNITS_AUTO => _x('Auto', 'history source selection method'), + SVG_GRAPH_AXIS_UNITS_STATIC => _x('Static', 'history source selection method') + ])) + ->setDefault(SVG_GRAPH_AXIS_UNITS_AUTO) + ->setFlags(!$this->righty_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldTextBox('righty_static_units', null)) + ->setFlags(!$this->righty_on || !$this->righty_units_static ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldCheckBox('axisx', _('X-Axis'), _('Show')))->setDefault(SVG_GRAPH_AXIS_ON) + ); + } + + private function initLegendFields(): self { + return $this + ->addField( + (new CWidgetFieldCheckBox('legend', _('Show legend')))->setDefault(SVG_GRAPH_LEGEND_ON) + ) + ->addField( + (new CWidgetFieldCheckBox('legend_statistic', _('Display min/max/avg'))) + ->setFlags(!$this->legend_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldRangeControl('legend_lines', _('Number of rows'), + SVG_GRAPH_LEGEND_LINES_MIN, SVG_GRAPH_LEGEND_LINES_MAX + )) + ->setDefault(SVG_GRAPH_LEGEND_LINES_MIN) + ->setFlags(!$this->legend_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldRangeControl('legend_columns', _('Number of columns'), + SVG_GRAPH_LEGEND_COLUMNS_MIN, SVG_GRAPH_LEGEND_COLUMNS_MAX + )) + ->setDefault(SVG_GRAPH_LEGEND_COLUMNS_MAX) + ->setFlags(!$this->legend_on || $this->legend_statistic_on ? CWidgetField::FLAG_DISABLED : 0x00) + ); + } + + private function initProblemsFields(): self { + return $this + ->addField( + new CWidgetFieldCheckBox('show_problems', _('Show problems')) + ) + ->addField( + (new CWidgetFieldCheckBox('graph_item_problems', _('Selected items only'))) + ->setDefault(SVG_GRAPH_SELECTED_ITEM_PROBLEMS) + ->setFlags(!$this->problems_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldHostPatternSelect('problemhosts', _('Problem hosts'))) + ->setFlags(!$this->problems_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldSeverities('severities', _('Severity'))) + ->setFlags(!$this->problems_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldTextBox('problem_name', _('Problem'))) + ->setFlags(!$this->problems_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ])) + ->setDefault(TAG_EVAL_TYPE_AND_OR) + ->setFlags(!$this->problems_on ? CWidgetField::FLAG_DISABLED : 0x00) + ) + ->addField( + (new CWidgetFieldTags('tags'))->setFlags(!$this->problems_on ? CWidgetField::FLAG_DISABLED : 0x00) + ); + } + + private function initOverridesFields(): self { + return $this->addField( + (new CWidgetFieldGraphOverride('or', _('Overrides')))->setFlags(CWidgetField::FLAG_NOT_EMPTY) + ); + } + + /** + * Check if widget configuration is set to use overridden time. + */ + public static function hasOverrideTime(array $fields_values): bool { + return array_key_exists('graph_time', $fields_values) + && $fields_values['graph_time'] == SVG_GRAPH_CUSTOM_TIME_ON; + } + + private static function validateTimeSelectorPeriod(string $from, string $to): array { + $errors = []; + $ts = []; + $ts['now'] = time(); + $range_time_parser = new CRangeTimeParser(); + + foreach (['from' => $from, 'to' => $to] as $field => $value) { + $range_time_parser->parse($value); + $ts[$field] = $range_time_parser->getDateTime($field === 'from')->getTimestamp(); + } + + $period = $ts['to'] - $ts['from'] + 1; + $range_time_parser->parse('now-'.CSettingsHelper::get(CSettingsHelper::MAX_PERIOD)); + $max_period = 1 + $ts['now'] - $range_time_parser->getDateTime(true)->getTimestamp(); + + if ($period < ZBX_MIN_PERIOD) { + $errors[] = _n('Minimum time period to display is %1$s minute.', + 'Minimum time period to display is %1$s minutes.', (int) (ZBX_MIN_PERIOD / SEC_PER_MIN) + ); + } + elseif ($period > $max_period) { + $errors[] = _n('Maximum time period to display is %1$s day.', + 'Maximum time period to display is %1$s days.', (int) round($max_period / SEC_PER_DAY) + ); + } + + return $errors; + } +} diff --git a/ui/widgets/svggraph/manifest.json b/ui/widgets/svggraph/manifest.json new file mode 100755 index 00000000000..db64bfc347d --- /dev/null +++ b/ui/widgets/svggraph/manifest.json @@ -0,0 +1,15 @@ +{ + "manifest_version": 2.0, + "id": "svggraph", + "type": "widget", + "name": "Graph", + "namespace": "SvgGraph", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "js_class": "CWidgetSvgGraph" + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/include/classes/widgets/views/js/widget.svggraph.form.view.js.php b/ui/widgets/svggraph/views/widget.edit.js.php index a1512cbcb4e..7764e8e40eb 100644..100755 --- a/ui/include/classes/widgets/views/js/widget.svggraph.form.view.js.php +++ b/ui/widgets/svggraph/views/widget.edit.js.php @@ -17,21 +17,24 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -?> +use Zabbix\Widgets\Fields\CWidgetFieldGraphDataSet; + +?> + window.widget_svggraph_form = new class { constructor() { this._dataset_index = 0; } - init({form_id, form_tabs_id, color_palette}) { + init({form_tabs_id, color_palette}) { colorPalette.setThemeColors(color_palette); this._$overlay_body = jQuery('.overlay-dialogue-body'); - this._form = document.getElementById(form_id); - this._form_id = form_id; + this._form = document.getElementById('widget-dialogue-form'); + this._dataset_wrapper = document.getElementById('data_sets'); @@ -119,8 +122,8 @@ window.widget_svggraph_form = new class { } if (e.target.classList.contains('js-click-expend') - || e.target.classList.contains('color-picker-preview') - || e.target.classList.contains('<?= ZBX_STYLE_BTN_GREY ?>')) { + || e.target.classList.contains('color-picker-preview') + || e.target.classList.contains('<?= ZBX_STYLE_BTN_GREY ?>')) { jQuery('#data_sets').zbx_vertical_accordion('expandNth', jQuery(e.target).closest('.<?= ZBX_STYLE_LIST_ACCORDION_ITEM ?>').index() ); @@ -131,7 +134,7 @@ window.widget_svggraph_form = new class { jQuery(window).trigger('resize'); const dataset = data.section[0]; - if (dataset.dataset.type == '<?= CWidgetHelper::DATASET_TYPE_SINGLE_ITEM ?>') { + if (dataset.dataset.type == '<?= CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM ?>') { const message_block = dataset.querySelector('.no-items-message'); if (dataset.querySelectorAll('.single-item-table-row').length == 0) { @@ -143,7 +146,7 @@ window.widget_svggraph_form = new class { jQuery(window).trigger('resize'); const dataset = data.section[0]; - if (dataset.dataset.type == '<?= CWidgetHelper::DATASET_TYPE_SINGLE_ITEM ?>') { + if (dataset.dataset.type == '<?= CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM ?>') { const message_block = dataset.querySelector('.no-items-message'); if (dataset.querySelectorAll('.single-item-table-row').length == 0) { @@ -191,7 +194,7 @@ window.widget_svggraph_form = new class { document .getElementById('dataset-add') .addEventListener('click', () => { - this._addDataset(<?= CWidgetHelper::DATASET_TYPE_PATTERN_ITEM ?>); + this._addDataset(<?= CWidgetFieldGraphDataSet::DATASET_TYPE_PATTERN_ITEM ?>); }); document @@ -199,7 +202,7 @@ window.widget_svggraph_form = new class { .addEventListener('click', this._addDatasetMenu); window.addPopupValues = (list) => { - if (!isset('object', list) || list.object != 'itemid') { + if (!isset('object', list) || list.object !== 'itemid') { return false; } @@ -274,13 +277,13 @@ window.widget_svggraph_form = new class { { label: <?= json_encode(_('Item pattern')) ?>, clickCallback: () => { - widget_svggraph_form._addDataset(<?= CWidgetHelper::DATASET_TYPE_PATTERN_ITEM ?>); + widget_svggraph_form._addDataset(<?= CWidgetFieldGraphDataSet::DATASET_TYPE_PATTERN_ITEM ?>); } }, { label: <?= json_encode(_('Item list')) ?>, clickCallback: () => { - widget_svggraph_form._addDataset(<?= CWidgetHelper::DATASET_TYPE_SINGLE_ITEM ?>); + widget_svggraph_form._addDataset(<?= CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM ?>); } } ] @@ -311,7 +314,7 @@ window.widget_svggraph_form = new class { _addDataset(type) { jQuery(this._dataset_wrapper).zbx_vertical_accordion('collapseAll'); - const template = type == <?= CWidgetHelper::DATASET_TYPE_SINGLE_ITEM ?> + const template = type == <?= CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM ?> ? new Template(jQuery('#dataset-single-item-tmpl').html()) : new Template(jQuery('#dataset-pattern-item-tmpl').html()); @@ -325,7 +328,7 @@ window.widget_svggraph_form = new class { this._dataset_wrapper.insertAdjacentHTML('beforeend', template.evaluate({ rowNum: this._dataset_index++, - color: type == <?= CWidgetHelper::DATASET_TYPE_SINGLE_ITEM ?> + color: type == <?= CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM ?> ? '' : colorPalette.getNextColor(used_colors) })); @@ -359,7 +362,7 @@ window.widget_svggraph_form = new class { const cloned_dataset = this._getOpenedDataset(); - if (dataset.dataset.type == <?= CWidgetHelper::DATASET_TYPE_SINGLE_ITEM ?>) { + if (dataset.dataset.type == <?= CWidgetFieldGraphDataSet::DATASET_TYPE_SINGLE_ITEM ?>) { for (const row of dataset.querySelectorAll('.single-item-table-row')) { this._addSingleItem( row.querySelector(`[name^='ds[${dataset.getAttribute('data-set')}][itemids]`).value, @@ -456,7 +459,7 @@ window.widget_svggraph_form = new class { srctbl: 'items', srcfld1: 'itemid', srcfld2: 'name', - dstfrm: this._form_id, + dstfrm: this._form.id, numeric: 1, writeonly: 1, multiselect: 1, @@ -571,7 +574,7 @@ window.widget_svggraph_form = new class { srctbl: 'items', srcfld1: 'itemid', srcfld2: 'name', - dstfrm: widget_svggraph_form._form_id, + dstfrm: widget_svggraph_form._form.id, dstfld1: `items_${dataset_index}_${i}_input`, dstfld2: `items_${dataset_index}_${i}_name`, numeric: 1, @@ -783,7 +786,7 @@ window.widget_svggraph_form = new class { form_fields.or[i] = jQuery.extend({'hosts': [], 'items': []}, form_fields.or[i]); } } - data.fields = JSON.stringify(form_fields); + data.fields = form_fields; if (preview_data.xhr) { preview_data.xhr.abort(); diff --git a/ui/widgets/svggraph/views/widget.edit.php b/ui/widgets/svggraph/views/widget.edit.php new file mode 100755 index 00000000000..0211a20f94c --- /dev/null +++ b/ui/widgets/svggraph/views/widget.edit.php @@ -0,0 +1,289 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Graph widget form view. + * + * @var CView $this + * @var array $data + */ + +use Zabbix\Widgets\Fields\CWidgetFieldGraphDataSet; + +$form = (new CWidgetFormView($data)); + +$preview = (new CDiv()) + ->addClass(ZBX_STYLE_SVG_GRAPH_PREVIEW) + ->addItem((new CDiv())->setId('svg-graph-preview')); + +$form_tabs = (new CTabView()) + ->addTab('data_set', _('Data set'), getDatasetTab($form, $data['fields']), + TAB_INDICATOR_GRAPH_DATASET + ) + ->addTab('displaying_options', _('Displaying options'), getDisplayOptionsTab($form, $data['fields']), + TAB_INDICATOR_GRAPH_DISPLAY_OPTIONS + ) + ->addTab('time_period', _('Time period'), getTimePeriodTab($form, $data['fields']), + TAB_INDICATOR_GRAPH_TIME + ) + ->addTab('axes', _('Axes'), getAxesTab($form, $data['fields']), + TAB_INDICATOR_GRAPH_AXES + ) + ->addTab('legend_tab', _('Legend'), getLegendTab($form, $data['fields']), + TAB_INDICATOR_GRAPH_LEGEND + ) + ->addTab('problems', _('Problems'), getProblemsTab($form, $data['fields']), + TAB_INDICATOR_GRAPH_PROBLEMS + ) + ->addTab('overrides', _('Overrides'), getOverridesTab($form, $data['fields']), + TAB_INDICATOR_GRAPH_OVERRIDES + ) + ->addClass('graph-widget-config-tabs') + ->setSelected(0); + +$form + ->addItem([$preview, $form_tabs]) + ->addJavaScript($form_tabs->makeJavascript()) + ->includeJsFile('widget.edit.js.php') + ->addJavaScript('widget_svggraph_form.init('.json_encode([ + 'form_tabs_id' => $form_tabs->getId(), + 'color_palette' => CWidgetFieldGraphDataSet::DEFAULT_COLOR_PALETTE + ], JSON_THROW_ON_ERROR).');') + ->show(); + +function getDatasetTab(CWidgetFormView $form, array $fields): CFormGrid { + $dataset = new CWidgetFieldGraphDataSetView($fields['ds']); + + return new CFormGrid( + $form->makeCustomField($dataset, [ + $dataset->getLabel(), + (new CFormField($dataset->getView()))->addClass(ZBX_STYLE_LIST_VERTICAL_ACCORDION), + (new CFormField($dataset->getFooterView()))->addClass(ZBX_STYLE_LIST_ACCORDION_FOOT) + ]) + ); +} + +function getDisplayOptionsTab(CWidgetFormView $form, array $fields): CDiv { + $percentile_left = new CWidgetFieldCheckBoxView($fields['percentile_left']); + $percentile_left_value = (new CWidgetFieldTextBoxView($fields['percentile_left_value'])) + ->setPlaceholder(_('value')) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH); + + $percentile_right = new CWidgetFieldCheckBoxView($fields['percentile_right']); + $percentile_right_value = (new CWidgetFieldTextBoxView($fields['percentile_right_value'])) + ->setPlaceholder(_('value')) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH); + + return (new CDiv()) + ->addClass(ZBX_STYLE_GRID_COLUMNS) + ->addClass(ZBX_STYLE_GRID_COLUMNS_2) + ->addItem( + new CFormGrid([ + $form->makeCustomField( + new CWidgetFieldRadioButtonListView($fields['source']) + ), + + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['simple_triggers']) + ), + + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['working_time']) + ) + ]) + ) + ->addItem( + new CFormGrid([ + $form->makeCustomField($percentile_left, [ + $percentile_left->getLabel(), + new CFormField([ + $percentile_left->getView(), + $percentile_left_value->getView() + ]) + ]), + + $form->makeCustomField($percentile_right, [ + $percentile_right->getLabel(), + new CFormField([ + $percentile_right->getView(), + $percentile_right_value->getView() + ]) + ]) + ]) + ); +} + +function getTimePeriodTab(CWidgetFormView $form, array $fields): CFormGrid { + return new CFormGrid([ + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['graph_time']) + ), + + $form->makeCustomField( + (new CWidgetFieldDatePickerView($fields['time_from'])) + ->setDateFormat(ZBX_FULL_DATE_TIME) + ->setPlaceholder(_('YYYY-MM-DD hh:mm:ss')) + ), + + $form->makeCustomField( + (new CWidgetFieldDatePickerView($fields['time_to'])) + ->setDateFormat(ZBX_FULL_DATE_TIME) + ->setPlaceholder(_('YYYY-MM-DD hh:mm:ss')) + ), + ]); +} + +function getAxesTab(CWidgetFormView $form, array $fields): CDiv { + $lefty_units = new CWidgetFieldSelectView($fields['lefty_units']); + $lefty_static_units = (new CWidgetFieldTextBoxView($fields['lefty_static_units'])) + ->setPlaceholder(_('value')) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH); + + $righty_units = new CWidgetFieldSelectView($fields['righty_units']); + $righty_static_units = (new CWidgetFieldTextBoxView($fields['righty_static_units'])) + ->setPlaceholder(_('value')) + ->setWidth(ZBX_TEXTAREA_TINY_WIDTH); + + return (new CDiv()) + ->addClass(ZBX_STYLE_GRID_COLUMNS) + ->addClass(ZBX_STYLE_GRID_COLUMNS_3) + ->addItem( + new CFormGrid([ + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['lefty']) + ), + + $form->makeCustomField( + (new CWidgetFieldNumericBoxView($fields['lefty_min']))->setPlaceholder(_('calculated')) + ), + + $form->makeCustomField( + (new CWidgetFieldNumericBoxView($fields['lefty_max']))->setPlaceholder(_('calculated')) + ), + + $form->makeCustomField($lefty_units, [ + $lefty_units->getLabel(), + new CFormField([ + $lefty_units->getView()->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), + $lefty_static_units->getView() + ]) + ]) + ]) + ) + ->addItem( + new CFormGrid([ + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['righty']) + ), + + $form->makeCustomField( + (new CWidgetFieldNumericBoxView($fields['righty_min']))->setPlaceholder(_('calculated')) + ), + + $form->makeCustomField( + (new CWidgetFieldNumericBoxView($fields['righty_max']))->setPlaceholder(_('calculated')) + ), + + $form->makeCustomField($righty_units, [ + $righty_units->getLabel(), + new CFormField([ + $righty_units->getView()->addClass(ZBX_STYLE_FORM_INPUT_MARGIN), + $righty_static_units->getView() + ]) + ]) + ]) + ) + ->addItem( + new CFormGrid( + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['axisx']) + ) + ) + ); +} + +function getLegendTab(CWidgetFormView $form, array $fields): CDiv { + return (new CDiv()) + ->addClass(ZBX_STYLE_GRID_COLUMNS) + ->addClass(ZBX_STYLE_GRID_COLUMNS_2) + ->addItem( + new CFormGrid([ + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['legend']) + ), + + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['legend_statistic']) + ) + ]) + ) + ->addItem( + new CFormGrid([ + $form->makeCustomField( + new CWidgetFieldRangeControlView($fields['legend_lines']) + ), + + $form->makeCustomField( + new CWidgetFieldRangeControlView($fields['legend_columns']) + ) + ]) + ); +} + +function getProblemsTab(CWidgetFormView $form, array $fields): CFormGrid { + return new CFormGrid([ + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['show_problems']) + ), + + $form->makeCustomField( + new CWidgetFieldCheckBoxView($fields['graph_item_problems']) + ), + + $form->makeCustomField( + (new CWidgetFieldHostPatternSelectView($fields['problemhosts']))->setPlaceholder(_('host pattern')) + ), + + $form->makeCustomField( + new CWidgetFieldSeveritiesView($fields['severities']) + ), + + $form->makeCustomField( + (new CWidgetFieldTextBoxView($fields['problem_name']))->setPlaceholder(_('problem pattern')) + ), + + $form->makeCustomField( + new CWidgetFieldRadioButtonListView($fields['evaltype']) + ), + + $form->makeCustomField( + new CWidgetFieldTagsView($fields['tags']) + ) + ]); +} + +function getOverridesTab(CWidgetFormView $form, array $fields): CFormGrid { + return new CFormGrid( + $form->makeCustomField( + new CWidgetFieldGraphOverrideView($fields['or']) + ) + ); +} diff --git a/ui/include/classes/widgets/views/widget.favmaps.form.view.php b/ui/widgets/svggraph/views/widget.view.php index 044ea1f4f57..cbf56edf763 100644 --- a/ui/include/classes/widgets/views/widget.favmaps.form.view.php +++ b/ui/widgets/svggraph/views/widget.view.php @@ -20,23 +20,20 @@ /** - * Favorite maps widget form view. + * Graph widget view. * * @var CView $this * @var array $data */ -$fields = $data['dialogue']['fields']; +$view = (new CWidgetView($data))->addItem($data['svg']); -$form = CWidgetHelper::createForm(); +if (!$data['preview']) { + $view->setVar('svg_options', $data['svg_options']); -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); + if ($data['info'] !== null) { + $view->setVar('info', $data['info']); + } +} -$form->addItem($form_grid); - -return [ - 'form' => $form -]; +$view->show(); diff --git a/ui/widgets/systeminfo/Widget.php b/ui/widgets/systeminfo/Widget.php new file mode 100755 index 00000000000..42f863b77b2 --- /dev/null +++ b/ui/widgets/systeminfo/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\SystemInfo; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('System information'); + } +} diff --git a/ui/app/controllers/CControllerWidgetSystemInfoView.php b/ui/widgets/systeminfo/actions/WidgetView.php index f79b2b17557..e0763c4fc7d 100644 --- a/ui/app/controllers/CControllerWidgetSystemInfoView.php +++ b/ui/widgets/systeminfo/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,27 +19,20 @@ **/ -require_once __DIR__.'/../../include/blocks.inc.php'; +namespace Widgets\SystemInfo\Actions; -class CControllerWidgetSystemInfoView extends CControllerWidget { +use CControllerDashboardWidgetView, + CControllerResponseData, + CSystemInfoHelper, + CWebUser; - public function __construct() { - parent::__construct(); - - $this->setType(WIDGET_SYSTEM_INFO); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } - - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); +class WidgetView extends CControllerDashboardWidgetView { + protected function doAction(): void { $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'system_info' => CSystemInfoHelper::getData(), - 'info_type' => $fields['info_type'], + 'info_type' => $this->fields_values['info_type'], 'user_type' => CWebUser::getType(), 'user' => [ 'debug_mode' => $this->getDebugMode() diff --git a/ui/widgets/systeminfo/includes/WidgetForm.php b/ui/widgets/systeminfo/includes/WidgetForm.php new file mode 100644 index 00000000000..27b92eec41d --- /dev/null +++ b/ui/widgets/systeminfo/includes/WidgetForm.php @@ -0,0 +1,42 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\SystemInfo\Includes; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\CWidgetFieldRadioButtonList; + +/** + * System information widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + (new CWidgetFieldRadioButtonList('info_type', _('Show'), [ + ZBX_SYSTEM_INFO_SERVER_STATS => _('System stats'), + ZBX_SYSTEM_INFO_HAC_STATUS => _('High availability nodes') + ]))->setDefault(ZBX_SYSTEM_INFO_SERVER_STATS) + ); + } +} diff --git a/ui/widgets/systeminfo/manifest.json b/ui/widgets/systeminfo/manifest.json new file mode 100755 index 00000000000..ec77d9e7503 --- /dev/null +++ b/ui/widgets/systeminfo/manifest.json @@ -0,0 +1,12 @@ +{ + "manifest_version": 2.0, + "id": "systeminfo", + "type": "widget", + "name": "System information", + "namespace": "SystemInfo", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "refresh_rate": 900 + } +} diff --git a/ui/widgets/systeminfo/views/widget.edit.php b/ui/widgets/systeminfo/views/widget.edit.php new file mode 100755 index 00000000000..1874ccb4fa1 --- /dev/null +++ b/ui/widgets/systeminfo/views/widget.edit.php @@ -0,0 +1,33 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * System information widget form view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['info_type']) + ) + ->show(); diff --git a/ui/app/views/monitoring.widget.systeminfo.view.php b/ui/widgets/systeminfo/views/widget.view.php index 37c71a2b995..021e95b5f70 100644 --- a/ui/app/views/monitoring.widget.systeminfo.view.php +++ b/ui/widgets/systeminfo/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,6 +20,8 @@ /** + * System information widget view. + * * @var CView $this * @var array $data */ @@ -51,18 +53,6 @@ switch ($data['info_type']) { $body = ''; } -$output = [ - 'name' => $data['name'], - 'body' => $body -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($body) + ->show(); diff --git a/ui/widgets/tophosts/Widget.php b/ui/widgets/tophosts/Widget.php new file mode 100755 index 00000000000..14108f1c4dd --- /dev/null +++ b/ui/widgets/tophosts/Widget.php @@ -0,0 +1,36 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\TopHosts; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public const DEFAULT_FILL = '#97AAB3'; + + public const ORDER_TOP_N = 2; + public const ORDER_BOTTOM_N = 3; + + public function getDefaultName(): string { + return _('Top hosts'); + } +} diff --git a/ui/app/controllers/CControllerPopupTopHostsColumnEdit.php b/ui/widgets/tophosts/actions/ColumnEdit.php index 5e67f74638f..6513a3dd2f1 100644 --- a/ui/app/controllers/CControllerPopupTopHostsColumnEdit.php +++ b/ui/widgets/tophosts/actions/ColumnEdit.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2021 Zabbix SIA @@ -19,46 +19,56 @@ **/ -class CControllerPopupTopHostsColumnEdit extends CController { - - protected $column_defaults = [ - 'name' => '', - 'data' => CWidgetFieldColumnsList::DATA_ITEM_VALUE, - 'item' => '', - 'timeshift' => '', - 'aggregate_function' => AGGREGATE_NONE, - 'aggregate_interval' => '1h', - 'display' => CWidgetFieldColumnsList::DISPLAY_AS_IS, - 'history' => CWidgetFieldColumnsList::HISTORY_DATA_AUTO, - 'min' => '', - 'max' => '', - 'base_color' => '', - 'text' => '', - 'thresholds' => [] +namespace Widgets\TopHosts\Actions; + +use CArrayHelper, + CController, + CControllerResponseData, + CNumberParser, + CParser; + +use Zabbix\Widgets\Fields\CWidgetFieldColumnsList; + +class ColumnEdit extends CController { + + protected array $column_defaults = [ + 'name' => '', + 'data' => CWidgetFieldColumnsList::DATA_ITEM_VALUE, + 'item' => '', + 'timeshift' => '', + 'aggregate_function' => AGGREGATE_NONE, + 'aggregate_interval' => '1h', + 'display' => CWidgetFieldColumnsList::DISPLAY_AS_IS, + 'history' => CWidgetFieldColumnsList::HISTORY_DATA_AUTO, + 'min' => '', + 'max' => '', + 'base_color' => '', + 'text' => '', + 'thresholds' => [] ]; - protected function init() { + protected function init(): void { $this->disableSIDValidation(); } - protected function checkInput() { + protected function checkInput(): bool { // Validation is done by CWidgetFieldColumnsList $fields = [ - 'name' => 'string', - 'data' => 'int32', - 'item' => 'string', - 'timeshift' => 'string', - 'aggregate_function' => 'int32', - 'aggregate_interval' => 'string', - 'display' => 'int32', - 'history' => 'int32', - 'min' => 'string', - 'max' => 'string', - 'base_color' => 'string', - 'thresholds' => 'array', - 'text' => 'string', - 'edit' => 'in 1', - 'update' => 'in 1' + 'name' => 'string', + 'data' => 'int32', + 'item' => 'string', + 'timeshift' => 'string', + 'aggregate_function' => 'int32', + 'aggregate_interval' => 'string', + 'display' => 'int32', + 'history' => 'int32', + 'min' => 'string', + 'max' => 'string', + 'base_color' => 'string', + 'thresholds' => 'array', + 'text' => 'string', + 'edit' => 'in 1', + 'update' => 'in 1' ]; $ret = $this->validateInput($fields) && $this->validateFields($this->getInputAll()); @@ -69,7 +79,7 @@ class CControllerPopupTopHostsColumnEdit extends CController { 'error' => [ 'messages' => array_column(get_and_clear_messages(), 'message') ] - ])]))->disableView() + ], JSON_THROW_ON_ERROR)]))->disableView() ); } @@ -91,23 +101,23 @@ class CControllerPopupTopHostsColumnEdit extends CController { return !$errors; } - protected function checkPermissions() { + protected function checkPermissions(): bool { return true; } - protected function doAction() { + protected function doAction(): void { $input = $this->getInputAll(); unset($input['update']); if (!$this->hasInput('update')) { $this->setResponse(new CControllerResponseData([ - 'action' => $this->getAction(), - 'thresholds_colors' => CWidgetFieldColumnsList::THRESHOLDS_DEFAULT_COLOR_PALETTE, - 'errors' => hasErrorMessages() ? getMessages() : null, - 'user' => [ - 'debug_mode' => $this->getDebugMode() - ] - ] + $input + $this->column_defaults)); + 'action' => $this->getAction(), + 'thresholds_colors' => CWidgetFieldColumnsList::THRESHOLDS_DEFAULT_COLOR_PALETTE, + 'errors' => hasErrorMessages() ? getMessages() : null, + 'user' => [ + 'debug_mode' => $this->getDebugMode() + ] + ] + $input + $this->column_defaults)); return; } @@ -140,6 +150,8 @@ class CControllerPopupTopHostsColumnEdit extends CController { } } - $this->setResponse((new CControllerResponseData(['main_block' => json_encode($input)]))->disableView()); + $this->setResponse( + (new CControllerResponseData(['main_block' => json_encode($input, JSON_THROW_ON_ERROR)]))->disableView() + ); } } diff --git a/ui/app/controllers/CControllerWidgetTopHostsView.php b/ui/widgets/tophosts/actions/WidgetView.php index 1eed40c3514..8c9596ba6ef 100644 --- a/ui/app/controllers/CControllerWidgetTopHostsView.php +++ b/ui/widgets/tophosts/actions/WidgetView.php @@ -19,51 +19,50 @@ **/ -class CControllerWidgetTopHostsView extends CControllerWidget { +namespace Widgets\TopHosts\Actions; - public function __construct() { - parent::__construct(); +use API, + CControllerDashboardWidgetView, + CControllerResponseData, + CHousekeepingHelper, + CMacrosResolverHelper, + CNumberParser, + CParser, + CSettingsHelper, + Manager; - $this->setType(WIDGET_TOP_HOSTS); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } +use Widgets\TopHosts\Widget; + +use Zabbix\Widgets\Fields\CWidgetFieldColumnsList; + +class WidgetView extends CControllerDashboardWidgetView { - protected function doAction() { + protected function doAction(): void { $data = [ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'user' => [ 'debug_mode' => $this->getDebugMode() ] ]; - $data += self::getData($this->getForm()->getFieldsData()); + $data += $this->getData(); $this->setResponse(new CControllerResponseData($data)); } - /** - * @param array $fields - * - * @throws Exception - * - * @return array - */ - private static function getData(array $fields): array { - $configuration = $fields['columns']; + private function getData(): array { + $configuration = $this->fields_values['columns']; - $groupids = $fields['groupids'] ? getSubGroups($fields['groupids']) : null; - $hostids = $fields['hostids'] ?: null; + $groupids = $this->fields_values['groupids'] ? getSubGroups($this->fields_values['groupids']) : null; + $hostids = $this->fields_values['hostids'] ?: null; - if (array_key_exists('tags', $fields)) { + if (array_key_exists('tags', $this->fields_values)) { $hosts = API::Host()->get([ 'output' => ['name'], 'groupids' => $groupids, 'hostids' => $hostids, - 'evaltype' => $fields['evaltype'], - 'tags' => $fields['tags'], + 'evaltype' => $this->fields_values['evaltype'], + 'tags' => $this->fields_values['tags'], 'monitored_hosts' => true, 'preservekeys' => true ]); @@ -76,7 +75,7 @@ class CControllerWidgetTopHostsView extends CControllerWidget { $time_now = time(); - $master_column = $configuration[$fields['column']]; + $master_column = $configuration[$this->fields_values['column']]; $master_items_only_numeric_allowed = self::isNumericOnlyColumn($master_column); $master_items = self::getItems($master_column['item'], $master_items_only_numeric_allowed, $groupids, $hostids); @@ -95,7 +94,7 @@ class CControllerWidgetTopHostsView extends CControllerWidget { } ); - if ($fields['order'] == CWidgetFormTopHosts::ORDER_TOPN) { + if ($this->fields_values['order'] == Widget::ORDER_TOP_N) { if ($master_items_only_numeric_present) { arsort($master_item_values, SORT_NUMERIC); @@ -118,7 +117,7 @@ class CControllerWidgetTopHostsView extends CControllerWidget { } } - $master_item_values = array_slice($master_item_values, 0, $fields['count'], true); + $master_item_values = array_slice($master_item_values, 0, $this->fields_values['count'], true); $master_items = array_intersect_key($master_items, $master_item_values); $master_hostids = []; @@ -158,7 +157,7 @@ class CControllerWidgetTopHostsView extends CControllerWidget { unset($threshold); } - if ($column_index == $fields['column']) { + if ($column_index == $this->fields_values['column']) { $column_items = $master_items; $column_item_values = $master_item_values; @@ -174,7 +173,7 @@ class CControllerWidgetTopHostsView extends CControllerWidget { } else { $numeric_only = self::isNumericOnlyColumn($column); - $column_items = !$calc_extremes || $column['min'] !== '' && $column['max'] !== '' + $column_items = !$calc_extremes || ($column['min'] !== '' && $column['max'] !== '') ? self::getItems($column['item'], $numeric_only, $groupids, array_keys($master_hostids)) : self::getItems($column['item'], $numeric_only, $groupids, $hostids); @@ -269,25 +268,12 @@ class CControllerWidgetTopHostsView extends CControllerWidget { ]; } - /** - * @param array $column - * - * @return bool - */ private static function isNumericOnlyColumn(array $column): bool { return $column['aggregate_function'] != AGGREGATE_NONE || $column['display'] != CWidgetFieldColumnsList::DISPLAY_AS_IS || array_key_exists('thresholds', $column); } - /** - * @param string $name - * @param bool $numeric_only - * @param array|null $groupids - * @param array|null $hostids - * - * @return array - */ private static function getItems(string $name, bool $numeric_only, ?array $groupids, ?array $hostids): array { $items = API::Item()->get([ 'output' => ['itemid', 'hostid', 'key_', 'history', 'trends', 'value_type', 'units'], @@ -318,13 +304,6 @@ class CControllerWidgetTopHostsView extends CControllerWidget { return $items; } - /** - * @param array $items - * @param array $column - * @param int $time_now - * - * @return array - */ private static function getItemValues(array $items, array $column, int $time_now): array { static $history_period; @@ -387,14 +366,6 @@ class CControllerWidgetTopHostsView extends CControllerWidget { return $result; } - /** - * @param array $items - * @param int $time_from - * @param int $time_now - * @param int $data_source - * - * @return void - */ private static function addDataSource(array &$items, int $time_from, int $time_now, int $data_source): void { if ($data_source == CWidgetFieldColumnsList::HISTORY_DATA_HISTORY || $data_source == CWidgetFieldColumnsList::HISTORY_DATA_TRENDS) { diff --git a/ui/widgets/tophosts/includes/WidgetForm.php b/ui/widgets/tophosts/includes/WidgetForm.php new file mode 100644 index 00000000000..633f6152c68 --- /dev/null +++ b/ui/widgets/tophosts/includes/WidgetForm.php @@ -0,0 +1,139 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2021 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\TopHosts\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldColumnsList, + CWidgetFieldIntegerBox, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldRadioButtonList, + CWidgetFieldSelect, + CWidgetFieldTags +}; + +use Widgets\TopHosts\Widget; + +/** + * Top hosts data widget form. + */ +class WidgetForm extends CWidgetForm { + + private const DEFAULT_HOSTS_COUNT = 10; + private const DEFAULT_ORDER_COLUMN = 0; + + private array $field_column_values = []; + + protected function normalizeValues(array $values): array { + $values = self::convertDottedKeys($values); + + if (array_key_exists('columnsthresholds', $values)) { + foreach ($values['columnsthresholds'] as $column_index => $fields) { + $values['columns'][$column_index]['thresholds'] = []; + + foreach ($fields as $field_key => $field_values) { + foreach ($field_values as $value_index => $value) { + $values['columns'][$column_index]['thresholds'][$value_index][$field_key] = $value; + } + } + } + } + + // Apply sortable changes to data. + if (array_key_exists('sortorder', $values)) { + if (array_key_exists('column', $values) && array_key_exists('columns', $values['sortorder'])) { + // Fix selected column index when columns were sorted. + $values['column'] = array_search($values['column'], $values['sortorder']['columns'], true); + } + + foreach ($values['sortorder'] as $key => $sortorder) { + if (!array_key_exists($key, $values)) { + continue; + } + + $sorted = []; + + foreach ($sortorder as $index) { + $sorted[] = $values[$key][$index]; + } + + $values[$key] = $sorted; + } + } + + if (array_key_exists('columns', $values)) { + foreach ($values['columns'] as $key => $value) { + if ($value['data'] == CWidgetFieldColumnsList::DATA_ITEM_VALUE) { + $this->field_column_values[$key] = ($value['name'] === '') ? $value['item'] : $value['name']; + } + } + } + + return $values; + } + + public function addFields(): self { + return $this + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectHost('hostids', _('Hosts')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Host tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ]))->setDefault(TAG_EVAL_TYPE_AND_OR) + ) + ->addField( + new CWidgetFieldTags('tags', '') + ) + ->addField( + (new CWidgetFieldColumnsList('columns', _('Columns')))->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField( + (new CWidgetFieldRadioButtonList('order', _('Order'), [ + Widget::ORDER_TOP_N => _('Top N'), + Widget::ORDER_BOTTOM_N => _('Bottom N') + ]))->setDefault(Widget::ORDER_TOP_N) + ) + ->addField( + (new CWidgetFieldSelect('column', _('Order column'), $this->field_column_values)) + ->setDefault($this->field_column_values + ? self::DEFAULT_ORDER_COLUMN + : CWidgetFieldSelect::DEFAULT_VALUE + ) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField( + (new CWidgetFieldIntegerBox('count', _('Host count'), ZBX_MIN_WIDGET_LINES, ZBX_MAX_WIDGET_LINES)) + ->setDefault(self::DEFAULT_HOSTS_COUNT) + ->setFlags(CWidgetField::FLAG_LABEL_ASTERISK) + ); + } +} diff --git a/ui/widgets/tophosts/manifest.json b/ui/widgets/tophosts/manifest.json new file mode 100755 index 00000000000..6ccb8b33cd2 --- /dev/null +++ b/ui/widgets/tophosts/manifest.json @@ -0,0 +1,16 @@ +{ + "manifest_version": 2.0, + "id": "tophosts", + "type": "widget", + "name": "Top hosts", + "namespace": "TopHosts", + "version": "1.0", + "author": "Zabbix SIA", + "actions": { + "widget.tophosts.column.edit": { + "class": "ColumnEdit", + "view": "column.edit", + "layout": "layout.json" + } + } +} diff --git a/ui/app/views/js/popup.tophosts.column.edit.js.php b/ui/widgets/tophosts/views/column.edit.js.php index d11bc9eaac8..d9adf48cebf 100644 --- a/ui/app/views/js/popup.tophosts.column.edit.js.php +++ b/ui/widgets/tophosts/views/column.edit.js.php @@ -17,9 +17,12 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ -?> +use Zabbix\Widgets\Fields\CWidgetFieldColumnsList; + +?> + window.tophosts_column_edit_form = new class { init({form_name, thresholds, thresholds_colors}) { diff --git a/ui/app/views/popup.tophosts.column.edit.php b/ui/widgets/tophosts/views/column.edit.php index 10739a1f874..b0d1fc47c6b 100644 --- a/ui/app/views/popup.tophosts.column.edit.php +++ b/ui/widgets/tophosts/views/column.edit.php @@ -24,6 +24,8 @@ * @var array $data */ +use Zabbix\Widgets\Fields\CWidgetFieldColumnsList; + $form = (new CForm()) ->setName('tophosts_column') ->addStyle('display: none;') @@ -73,8 +75,8 @@ $form_grid->addItem([ (new CLabel(_('Text'), 'text'))->setAsteriskMark(), new CFormField( (new CTextBox('text', $data['text'])) - ->setAttribute('placeholder', _('Text, supports {INVENTORY.*}, {HOST.*} macros')) ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH) + ->setAttribute('placeholder', _('Text, supports {INVENTORY.*}, {HOST.*} macros')) ) ]); @@ -108,8 +110,8 @@ $form_grid->addItem([ new CLabel(_('Time shift'), 'timeshift'), new CFormField( (new CTextBox('timeshift', $data['timeshift'])) - ->setAttribute('placeholder', _('none')) ->setWidth(ZBX_TEXTAREA_TINY_WIDTH) + ->setAttribute('placeholder', _('none')) ) ]); @@ -159,7 +161,7 @@ $form_grid->addItem([ ->addValue(_('As is'), CWidgetFieldColumnsList::DISPLAY_AS_IS) ->addValue(_('Bar'), CWidgetFieldColumnsList::DISPLAY_BAR) ->addValue(_('Indicators'), CWidgetFieldColumnsList::DISPLAY_INDICATORS) - ->setModern(true) + ->setModern() ) ]); @@ -176,7 +178,7 @@ $form_grid->addItem([ ->addValue(_('Auto'), CWidgetFieldColumnsList::HISTORY_DATA_AUTO) ->addValue(_('History'), CWidgetFieldColumnsList::HISTORY_DATA_HISTORY) ->addValue(_('Trends'), CWidgetFieldColumnsList::HISTORY_DATA_TRENDS) - ->setModern(true) + ->setModern() ) ]); @@ -191,8 +193,8 @@ $form_grid->addItem([ new CLabel(_('Min'), 'min'), new CFormField( (new CTextBox('min', $data['min'])) - ->setAttribute('placeholder', _('calculated')) ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) + ->setAttribute('placeholder', _('calculated')) ) ]); @@ -201,8 +203,8 @@ $form_grid->addItem([ new CLabel(_('Max'), 'max'), new CFormField( (new CTextBox('max', $data['max'])) - ->setAttribute('placeholder', _('calculated')) ->setWidth(ZBX_TEXTAREA_FILTER_SMALL_WIDTH) + ->setAttribute('placeholder', _('calculated')) ) ]); @@ -230,7 +232,7 @@ $thresholds = (new CDiv( ->setWidth(ZBX_TEXTAREA_STANDARD_WIDTH); $thresholds->addItem( - (new CScriptTemplate('thresholds-row-tmpl')) + (new CTemplateTag('thresholds-row-tmpl')) ->addItem((new CRow([ (new CColor('thresholds[#{rowNum}][color]', '#{color}'))->appendColorPickerJs(false), (new CTextBox('thresholds[#{rowNum}][threshold]', '#{threshold}', false)) @@ -255,16 +257,16 @@ $form ->addItem( (new CScriptTag(' tophosts_column_edit_form.init('.json_encode([ - 'form_name' => $form->getName(), - 'thresholds' => $data['thresholds'], - 'thresholds_colors' => $data['thresholds_colors'] - ]).'); + 'form_name' => $form->getName(), + 'thresholds' => $data['thresholds'], + 'thresholds_colors' => $data['thresholds_colors'] + ], JSON_THROW_ON_ERROR).'); '))->setOnDocumentReady() ); $output = [ 'header' => array_key_exists('edit', $data) ? _('Update column') : _('New column'), - 'script_inline' => implode('', $scripts).$this->readJsFile('popup.tophosts.column.edit.js.php'), + 'script_inline' => implode('', $scripts).$this->readJsFile('column.edit.js.php', null, ''), 'body' => $form->toString(), 'buttons' => [ [ @@ -281,4 +283,4 @@ if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { $output['debug'] = CProfiler::getInstance()->make()->toString(); } -echo json_encode($output); +echo json_encode($output, JSON_THROW_ON_ERROR); diff --git a/ui/include/classes/widgets/views/js/widget.tophosts.form.view.js.php b/ui/widgets/tophosts/views/widget.edit.js.php index ab39855b96e..5139a711209 100644..100755 --- a/ui/include/classes/widgets/views/js/widget.tophosts.form.view.js.php +++ b/ui/widgets/tophosts/views/widget.edit.js.php @@ -22,8 +22,9 @@ window.widget_tophosts_form = new class { - init(options) { - this._form = document.getElementById(options.form_id); + init() { + this._form = document.getElementById('widget-dialogue-form'); + this._list_columns = document.getElementById('list_columns'); this.initSortable(this._list_columns); @@ -79,7 +80,7 @@ window.widget_tophosts_form = new class { case 'add': this._column_index = this._list_columns.querySelectorAll('tr').length; - column_popup = PopUp('popup.tophosts.column.edit', {}).$dialogue[0]; + column_popup = PopUp('widget.tophosts.column.edit', {}).$dialogue[0]; column_popup.addEventListener('dialogue.submit', (e) => this.updateColumns(e)); column_popup.addEventListener('overlay.close', this.removeColorpicker); break; @@ -89,7 +90,7 @@ window.widget_tophosts_form = new class { this._column_index = target.closest('tr').querySelector('[name="sortorder[columns][]"]').value; - column_popup = PopUp('popup.tophosts.column.edit', + column_popup = PopUp('widget.tophosts.column.edit', {...form_fields.columns[this._column_index], edit: 1}).$dialogue[0]; column_popup.addEventListener('dialogue.submit', (e) => this.updateColumns(e)); column_popup.addEventListener('overlay.close', this.removeColorpicker); @@ -142,7 +143,7 @@ window.widget_tophosts_form = new class { ZABBIX.Dashboard.reloadWidgetProperties(); } - // Need to remove function after subpopups auto close. + // Need to remove function after sub-popups auto close. removeColorpicker() { $('#color_picker').hide(); } diff --git a/ui/widgets/tophosts/views/widget.edit.php b/ui/widgets/tophosts/views/widget.edit.php new file mode 100755 index 00000000000..97d2f27ffab --- /dev/null +++ b/ui/widgets/tophosts/views/widget.edit.php @@ -0,0 +1,85 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Top hosts widget form view. + * + * @var CView $this + * @var array $data + */ + +use Zabbix\Widgets\Fields\{ + CWidgetFieldColumnsList, + CWidgetFieldSelect +}; + +$form = (new CWidgetFormView($data)); + +$groupids = new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], + $data['captions']['ms']['groups']['groupids'] +); + +$form + ->addField($groupids) + ->addField( + (new CWidgetFieldMultiSelectHostView($data['fields']['hostids'], $data['captions']['ms']['hosts']['hostids'])) + ->setFilterPreselect(['id' => $groupids->getId(), 'submit_as' => 'groupid']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['evaltype']) + ) + ->addField( + new CWidgetFieldTagsView($data['fields']['tags']) + ) + ->addItem( + getColumnsField($form, $data['fields']['columns']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['order']) + ) + ->addItem( + getColumnField($form, $data['fields']['column']) + ) + ->addField( + new CWidgetFieldIntegerBoxView($data['fields']['count']) + ) + ->includeJsFile('widget.edit.js.php') + ->addJavaScript('widget_tophosts_form.init();') + ->show(); + +function getColumnsField(CWidgetFormView $form, CWidgetFieldColumnsList $field): array { + $columns = new CWidgetFieldColumnsListView($field); + + return $form->makeCustomField($columns, [ + $columns->getLabel(), + (new CFormField($columns->getView()))->addClass(ZBX_STYLE_TABLE_FORMS_SEPARATOR) + ]); +} + +function getColumnField(CWidgetFormView $form, CWidgetFieldSelect $field): array { + $column = new CWidgetFieldSelectView($field); + + return $form->makeCustomField($column, [ + $column->getLabel(), + (new CFormField($field->getValues() ? $column->getView() : _('Add item column'))) + ->addClass($column->isDisabled() ? ZBX_STYLE_DISABLED : null) + ]); +} diff --git a/ui/app/views/monitoring.widget.tophosts.view.php b/ui/widgets/tophosts/views/widget.view.php index d353b2522dc..463f3672bf5 100644 --- a/ui/app/views/monitoring.widget.tophosts.view.php +++ b/ui/widgets/tophosts/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2021 Zabbix SIA @@ -20,10 +20,16 @@ /** + * Top hosts widget view. + * * @var CView $this * @var array $data */ +use Widgets\TopHosts\Widget; + +use Zabbix\Widgets\Fields\CWidgetFieldColumnsList; + $header = []; foreach ($data['configuration'] as $column_config) { @@ -108,7 +114,7 @@ foreach ($data['rows'] as $columns) { ->setValue($column['value']) ->setAttribute('fill', $column_config['base_color'] !== '' ? '#'.$column_config['base_color'] - : ZBX_WIDGET_TOP_HOSTS_DEFAULT_FILL + : Widget::DEFAULT_FILL ) ->setAttribute('min', $column_config['min']) ->setAttribute('max', $column_config['max']); @@ -142,20 +148,6 @@ foreach ($data['rows'] as $columns) { $table->addRow($row); } -$output = [ - 'name' => $data['name'], - 'body' => (new CDiv($table)) - ->addClass('dashboard-widget-tophosts') - ->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); diff --git a/ui/widgets/trigover/Widget.php b/ui/widgets/trigover/Widget.php new file mode 100755 index 00000000000..a892ea2c087 --- /dev/null +++ b/ui/widgets/trigover/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\TrigOver; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Trigger overview'); + } +} diff --git a/ui/widgets/trigover/actions/WidgetView.php b/ui/widgets/trigover/actions/WidgetView.php new file mode 100644 index 00000000000..064615dcf90 --- /dev/null +++ b/ui/widgets/trigover/actions/WidgetView.php @@ -0,0 +1,78 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\TrigOver\Actions; + +use CControllerDashboardWidgetView, + CControllerResponseData; + +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ + 'initial_load' => 'in 0,1' + ]); + } + + protected function doAction(): void { + $data = [ + 'name' => $this->getInput('name', $this->widget->getDefaultName()), + 'initial_load' => (bool) $this->getInput('initial_load', 0), + 'style' => $this->fields_values['style'], + 'user' => [ + 'debug_mode' => $this->getDebugMode() + ] + ]; + + $trigger_options = [ + 'skipDependent' => ($this->fields_values['show'] == TRIGGERS_OPTION_ALL) ? null : true, + 'only_true' => $this->fields_values['show'] == TRIGGERS_OPTION_RECENT_PROBLEM ? true : null, + 'filter' => [ + 'value' => $this->fields_values['show'] == TRIGGERS_OPTION_IN_PROBLEM ? TRIGGER_VALUE_TRUE : null + ] + ]; + + $problem_options = [ + 'show_suppressed' => $this->fields_values['show_suppressed'], + 'show_recent' => $this->fields_values['show'] == TRIGGERS_OPTION_RECENT_PROBLEM ? true : null, + 'tags' => array_key_exists('tags', $this->fields_values) && $this->fields_values['tags'] + ? $this->fields_values['tags'] + : null, + 'evaltype' => array_key_exists('evaltype', $this->fields_values) + ? $this->fields_values['evaltype'] + : TAG_EVAL_TYPE_AND_OR + ]; + + $host_options = [ + 'hostids' => $this->fields_values['hostids'] ?: null + ]; + + [$data['db_hosts'], $data['db_triggers'], $data['dependencies'], $data['triggers_by_name'], + $data['hosts_by_name'], $data['exceeded_limit'] + ] = getTriggersOverviewData(getSubGroups($this->fields_values['groupids']), $host_options, $trigger_options, + $problem_options + ); + + $this->setResponse(new CControllerResponseData($data)); + } +} diff --git a/ui/js/widgets/class.widget.trigerover.js b/ui/widgets/trigover/assets/js/class.widget.js index 3db90c588e9..3db90c588e9 100644..100755 --- a/ui/js/widgets/class.widget.trigerover.js +++ b/ui/widgets/trigover/assets/js/class.widget.js diff --git a/ui/widgets/trigover/includes/WidgetForm.php b/ui/widgets/trigover/includes/WidgetForm.php new file mode 100644 index 00000000000..a8fdde27a12 --- /dev/null +++ b/ui/widgets/trigover/includes/WidgetForm.php @@ -0,0 +1,73 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\TrigOver\Includes; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldRadioButtonList, + CWidgetFieldTags +}; + +/** + * Trigger overview widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + (new CWidgetFieldRadioButtonList('show', _('Show'), [ + TRIGGERS_OPTION_RECENT_PROBLEM => _('Recent problems'), + TRIGGERS_OPTION_IN_PROBLEM => _('Problems'), + TRIGGERS_OPTION_ALL => _('Any') + ]))->setDefault(TRIGGERS_OPTION_RECENT_PROBLEM) + ) + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectHost('hostids', _('Hosts')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ]))->setDefault(TAG_EVAL_TYPE_AND_OR) + ) + ->addField( + new CWidgetFieldTags('tags') + ) + ->addField( + new CWidgetFieldCheckBox('show_suppressed', _('Show suppressed problems')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('style', _('Hosts location'), [ + STYLE_LEFT => _('Left'), + STYLE_TOP => _('Top') + ]))->setDefault(STYLE_LEFT) + ); + } +} diff --git a/ui/widgets/trigover/manifest.json b/ui/widgets/trigover/manifest.json new file mode 100755 index 00000000000..7579d58cb4f --- /dev/null +++ b/ui/widgets/trigover/manifest.json @@ -0,0 +1,15 @@ +{ + "manifest_version": 2.0, + "id": "trigover", + "type": "widget", + "name": "Trigger overview", + "namespace": "TrigOver", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "js_class": "CWidgetTrigerOver" + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/app/partials/trigoverview.table.left.php b/ui/widgets/trigover/partials/table.left.php index 58e34cea1bd..58e34cea1bd 100644 --- a/ui/app/partials/trigoverview.table.left.php +++ b/ui/widgets/trigover/partials/table.left.php diff --git a/ui/app/partials/trigoverview.table.top.php b/ui/widgets/trigover/partials/table.top.php index 126d6b8ccb8..126d6b8ccb8 100644 --- a/ui/app/partials/trigoverview.table.top.php +++ b/ui/widgets/trigover/partials/table.top.php diff --git a/ui/widgets/trigover/views/widget.edit.php b/ui/widgets/trigover/views/widget.edit.php new file mode 100755 index 00000000000..bc4354d2908 --- /dev/null +++ b/ui/widgets/trigover/views/widget.edit.php @@ -0,0 +1,54 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Trigger overview widget form view. + * + * @var CView $this + * @var array $data + */ + +$groupids = new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], + $data['captions']['ms']['groups']['groupids'] +); + +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['show']) + ) + ->addField($groupids) + ->addField( + (new CWidgetFieldMultiSelectHostView($data['fields']['hostids'], $data['captions']['ms']['hosts']['hostids'])) + ->setFilterPreselect(['id' => $groupids->getId(), 'submit_as' => 'groupid']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['evaltype']) + ) + ->addField( + new CWidgetFieldTagsView($data['fields']['tags']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['show_suppressed']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['style']) + ) + ->show(); diff --git a/ui/widgets/trigover/views/widget.view.php b/ui/widgets/trigover/views/widget.view.php new file mode 100644 index 00000000000..fa0322e0084 --- /dev/null +++ b/ui/widgets/trigover/views/widget.view.php @@ -0,0 +1,34 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Trigger overview widget view. + * + * @var CView $this + * @var array $data + */ + +(new CWidgetView($data)) + ->addItem($data['style'] == STYLE_TOP + ? (new CPartial('table.top', $data))->getOutput() + : (new CPartial('table.left', $data))->getOutput() + ) + ->show(); diff --git a/ui/widgets/url/Widget.php b/ui/widgets/url/Widget.php new file mode 100755 index 00000000000..59d6459cd13 --- /dev/null +++ b/ui/widgets/url/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Url; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('URL'); + } +} diff --git a/ui/app/controllers/CControllerWidgetUrlView.php b/ui/widgets/url/actions/WidgetView.php index e09881d5dd1..0a3df77d9c7 100644 --- a/ui/app/controllers/CControllerWidgetUrlView.php +++ b/ui/widgets/url/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,31 +19,37 @@ **/ -class CControllerWidgetUrlView extends CControllerWidget { +namespace Widgets\Url\Actions; - public function __construct() { - parent::__construct(); +use CControllerDashboardWidgetView, + CControllerResponseData, + CHtmlUrlValidator, + CMacrosResolverHelper, + CSettingsHelper; - $this->setType(WIDGET_URL); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json', +use Zabbix\Core\CWidget; + +class WidgetView extends CControllerDashboardWidgetView { + + protected function init(): void { + parent::init(); + + $this->addValidationRules([ 'dynamic_hostid' => 'db hosts.hostid' ]); } - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); + protected function doAction(): void { $error = null; - $is_template_dashboard = ($this->getContext() === CWidgetConfig::CONTEXT_TEMPLATE_DASHBOARD); + $is_template_dashboard = $this->hasInput('templateid'); // Editing template dashboard? if ($is_template_dashboard && !$this->hasInput('dynamic_hostid')) { $error = _('No data.'); } else { - $is_dynamic_item = ($is_template_dashboard || $fields['dynamic'] == WIDGET_DYNAMIC_ITEM); + $is_dynamic_item = ($is_template_dashboard || $this->fields_values['dynamic'] == CWidget::DYNAMIC_ITEM); $dynamic_hostid = $this->getInput('dynamic_hostid', '0'); @@ -53,22 +59,24 @@ class CControllerWidgetUrlView extends CControllerWidget { else { $resolved_url = CMacrosResolverHelper::resolveWidgetURL([ 'config' => $is_dynamic_item ? 'widgetURL' : 'widgetURLUser', - 'url' => $fields['url'], + 'url' => $this->fields_values['url'], 'hostid' => $is_dynamic_item ? $dynamic_hostid : '0' ]); - $fields['url'] = $resolved_url ? $resolved_url : $fields['url']; + if ($resolved_url) { + $this->fields_values['url'] = $resolved_url; + } } - if (!$error && !CHtmlUrlValidator::validate($fields['url'], ['allow_user_macro' => false])) { - $error = _s('Provided URL "%1$s" is invalid.', $fields['url']); + if (!$error && !CHtmlUrlValidator::validate($this->fields_values['url'], ['allow_user_macro' => false])) { + $error = _s('Provided URL "%1$s" is invalid.', $this->fields_values['url']); } } $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'url' => [ - 'url' => $fields['url'], + 'url' => $this->fields_values['url'], 'error' => $error ], 'user' => [ diff --git a/ui/widgets/url/assets/js/class.widget.js b/ui/widgets/url/assets/js/class.widget.js new file mode 100644 index 00000000000..2bbc25468ed --- /dev/null +++ b/ui/widgets/url/assets/js/class.widget.js @@ -0,0 +1,26 @@ +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +class CWidgetUrl extends CWidget { + + _hasPadding() { + return false; + } +} diff --git a/ui/widgets/url/includes/WidgetForm.php b/ui/widgets/url/includes/WidgetForm.php new file mode 100644 index 00000000000..5227ba8c6af --- /dev/null +++ b/ui/widgets/url/includes/WidgetForm.php @@ -0,0 +1,50 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Url\Includes; + +use Zabbix\Widgets\{ + CWidgetField, + CWidgetForm +}; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldUrl +}; + +/** + * URL widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + (new CWidgetFieldUrl('url', _('URL'))) + ->setFlags(CWidgetField::FLAG_NOT_EMPTY | CWidgetField::FLAG_LABEL_ASTERISK) + ) + ->addField($this->templateid === null + ? new CWidgetFieldCheckBox('dynamic', _('Enable host selection')) + : null + ); + } +} diff --git a/ui/widgets/url/manifest.json b/ui/widgets/url/manifest.json new file mode 100755 index 00000000000..89fae2d5c34 --- /dev/null +++ b/ui/widgets/url/manifest.json @@ -0,0 +1,17 @@ +{ + "manifest_version": 2.0, + "id": "url", + "type": "widget", + "name": "URL", + "namespace": "Url", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "js_class": "CWidgetUrl", + "template_support": true, + "refresh_rate": 0 + }, + "assets": { + "js": ["class.widget.js"] + } +} diff --git a/ui/include/classes/widgets/views/widget.favgraphs.form.view.php b/ui/widgets/url/views/widget.edit.php index f2c89a24dae..acce744eedd 100644..100755 --- a/ui/include/classes/widgets/views/widget.favgraphs.form.view.php +++ b/ui/widgets/url/views/widget.edit.php @@ -20,23 +20,18 @@ /** - * Favorite graphs widget form view. + * URL widget form view. * * @var CView $this * @var array $data */ -$fields = $data['dialogue']['fields']; - -$form = CWidgetHelper::createForm(); - -$form_grid = CWidgetHelper::createFormGrid($data['dialogue']['name'], $data['dialogue']['type'], - $data['dialogue']['view_mode'], $data['known_widget_types'], - $data['templateid'] === null ? $fields['rf_rate'] : null -); - -$form->addItem($form_grid); - -return [ - 'form' => $form -]; +(new CWidgetFormView($data)) + ->addField( + new CWidgetFieldUrlView($data['fields']['url']) + ) + ->addField(array_key_exists('dynamic', $data['fields']) + ? new CWidgetFieldCheckBoxView($data['fields']['dynamic']) + : null + ) + ->show(); diff --git a/ui/app/views/monitoring.widget.url.view.php b/ui/widgets/url/views/widget.view.php index 6543fac574c..f9ad0e05158 100644 --- a/ui/app/views/monitoring.widget.url.view.php +++ b/ui/widgets/url/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,7 +20,10 @@ /** + * URL widget form view. + * * @var CView $this + * @var array $data */ if ($data['url']['error'] !== null) { @@ -34,18 +37,6 @@ else { } } -$output = [ - 'name' => $data['name'], - 'body' => $item->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($item) + ->show(); diff --git a/ui/widgets/web/Widget.php b/ui/widgets/web/Widget.php new file mode 100755 index 00000000000..2876651451b --- /dev/null +++ b/ui/widgets/web/Widget.php @@ -0,0 +1,31 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Web; + +use Zabbix\Core\CWidget; + +class Widget extends CWidget { + + public function getDefaultName(): string { + return _('Web monitoring'); + } +} diff --git a/ui/app/controllers/CControllerWidgetWebView.php b/ui/widgets/web/actions/WidgetView.php index 2ba1f59accc..dc13e46a1df 100644 --- a/ui/app/controllers/CControllerWidgetWebView.php +++ b/ui/widgets/web/actions/WidgetView.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -19,29 +19,28 @@ **/ -class CControllerWidgetWebView extends CControllerWidget { +namespace Widgets\Web\Actions; - public function __construct() { - parent::__construct(); +use API, + CApiTagHelper, + CArrayHelper, + CControllerDashboardWidgetView, + CControllerResponseData, + CRoleHelper, + Manager; - $this->setType(WIDGET_WEB); - $this->setValidationRules([ - 'name' => 'string', - 'fields' => 'json' - ]); - } +class WidgetView extends CControllerDashboardWidgetView { - protected function doAction() { - $fields = $this->getForm()->getFieldsData(); + protected function doAction(): void { + $filter_groupids = $this->fields_values['groupids'] ? getSubGroups($this->fields_values['groupids']) : null; + $filter_hostids = $this->fields_values['hostids'] ?: null; + $filter_maintenance = ($this->fields_values['maintenance'] == 0) ? 0 : null; - $filter_groupids = $fields['groupids'] ? getSubGroups($fields['groupids']) : null; - $filter_hostids = $fields['hostids'] ? $fields['hostids'] : null; - $filter_maintenance = ($fields['maintenance'] == 0) ? 0 : null; - - if ($fields['exclude_groupids']) { - $exclude_groupids = getSubGroups($fields['exclude_groupids']); + if ($this->fields_values['exclude_groupids']) { + $exclude_groupids = getSubGroups($this->fields_values['exclude_groupids']); if ($filter_hostids === null) { + // Get all groups if no selected groups defined. if ($filter_groupids === null) { $filter_groupids = array_keys(API::HostGroup()->get([ @@ -98,11 +97,13 @@ class CControllerWidgetWebView extends CControllerWidget { unset($group); // Fetch links between HTTP tests and host groups. - $where_tags = (array_key_exists('tags', $fields) && $fields['tags']) - ? CApiTagHelper::addWhereCondition($fields['tags'], $fields['evaltype'], 'ht', 'httptest_tag', 'httptestid') + $where_tags = (array_key_exists('tags', $this->fields_values) && $this->fields_values['tags']) + ? CApiTagHelper::addWhereCondition($this->fields_values['tags'], $this->fields_values['evaltype'], 'ht', + 'httptest_tag', 'httptestid' + ) : ''; - $result = DbFetchArray(DBselect($s= + $result = DbFetchArray(DBselect( 'SELECT DISTINCT ht.httptestid,hg.groupid'. ' FROM httptest ht,hosts_groups hg'. ' WHERE ht.hostid=hg.hostid'. @@ -113,7 +114,7 @@ class CControllerWidgetWebView extends CControllerWidget { )); // Fetch HTTP test execution data. - $httptest_data = Manager::HttpTest()->getLastData(zbx_objectValues($result, 'httptestid')); + $httptest_data = Manager::HttpTest()->getLastData(array_column($result, 'httptestid')); foreach ($result as $row) { $group = &$groups[$row['groupid']]; @@ -129,7 +130,7 @@ class CControllerWidgetWebView extends CControllerWidget { } $this->setResponse(new CControllerResponseData([ - 'name' => $this->getInput('name', $this->getDefaultName()), + 'name' => $this->getInput('name', $this->widget->getDefaultName()), 'groups' => $groups, 'user' => [ 'debug_mode' => $this->getDebugMode() diff --git a/ui/widgets/web/includes/WidgetForm.php b/ui/widgets/web/includes/WidgetForm.php new file mode 100644 index 00000000000..66c5e4dc40b --- /dev/null +++ b/ui/widgets/web/includes/WidgetForm.php @@ -0,0 +1,63 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +namespace Widgets\Web\Includes; + +use Zabbix\Widgets\CWidgetForm; + +use Zabbix\Widgets\Fields\{ + CWidgetFieldCheckBox, + CWidgetFieldMultiSelectGroup, + CWidgetFieldMultiSelectHost, + CWidgetFieldRadioButtonList, + CWidgetFieldTags +}; + +/** + * Web monitoring widget form. + */ +class WidgetForm extends CWidgetForm { + + public function addFields(): self { + return $this + ->addField( + new CWidgetFieldMultiSelectGroup('groupids', _('Host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectGroup('exclude_groupids', _('Exclude host groups')) + ) + ->addField( + new CWidgetFieldMultiSelectHost('hostids', _('Hosts')) + ) + ->addField( + (new CWidgetFieldRadioButtonList('evaltype', _('Tags'), [ + TAG_EVAL_TYPE_AND_OR => _('And/Or'), + TAG_EVAL_TYPE_OR => _('Or') + ]))->setDefault(TAG_EVAL_TYPE_AND_OR) + ) + ->addField( + new CWidgetFieldTags('tags') + ) + ->addField( + (new CWidgetFieldCheckBox('maintenance', _('Show hosts in maintenance')))->setDefault(1) + ); + } +} diff --git a/ui/widgets/web/manifest.json b/ui/widgets/web/manifest.json new file mode 100755 index 00000000000..b25bf093139 --- /dev/null +++ b/ui/widgets/web/manifest.json @@ -0,0 +1,15 @@ +{ + "manifest_version": 2.0, + "id": "web", + "type": "widget", + "name": "Web monitoring", + "namespace": "Web", + "version": "1.0", + "author": "Zabbix SIA", + "widget": { + "size": { + "width": 6, + "height": 3 + } + } +} diff --git a/ui/widgets/web/views/widget.edit.php b/ui/widgets/web/views/widget.edit.php new file mode 100755 index 00000000000..f49a111499f --- /dev/null +++ b/ui/widgets/web/views/widget.edit.php @@ -0,0 +1,53 @@ +<?php declare(strict_types = 0); +/* +** Zabbix +** Copyright (C) 2001-2022 Zabbix SIA +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +**/ + + +/** + * Web monitoring widget form view. + * + * @var CView $this + * @var array $data + */ + +$groupids = new CWidgetFieldMultiSelectGroupView($data['fields']['groupids'], + $data['captions']['ms']['groups']['groupids'] +); + +(new CWidgetFormView($data)) + ->addField($groupids) + ->addField( + new CWidgetFieldMultiSelectGroupView($data['fields']['exclude_groupids'], + $data['captions']['ms']['groups']['exclude_groupids'] + ) + ) + ->addField( + (new CWidgetFieldMultiSelectHostView($data['fields']['hostids'], $data['captions']['ms']['hosts']['hostids'])) + ->setFilterPreselect(['id' => $groupids->getId(), 'submit_as' => 'groupid']) + ) + ->addField( + new CWidgetFieldRadioButtonListView($data['fields']['evaltype']) + ) + ->addField( + new CWidgetFieldTagsView($data['fields']['tags']) + ) + ->addField( + new CWidgetFieldCheckBoxView($data['fields']['maintenance']) + ) + ->show(); diff --git a/ui/app/views/monitoring.widget.web.view.php b/ui/widgets/web/views/widget.view.php index dd4297af86e..d9d00083f69 100644 --- a/ui/app/views/monitoring.widget.web.view.php +++ b/ui/widgets/web/views/widget.view.php @@ -1,4 +1,4 @@ -<?php +<?php declare(strict_types = 0); /* ** Zabbix ** Copyright (C) 2001-2022 Zabbix SIA @@ -20,6 +20,8 @@ /** + * Web monitoring widget view. + * * @var CView $this * @var array $data */ @@ -53,24 +55,12 @@ foreach ($data['groups'] as $group) { $table->addRow([ $group_name, - ($group['ok'] != 0) ? (new CSpan($group['ok']))->addClass(ZBX_STYLE_GREEN) : '', - ($group['failed'] != 0) ? (new CSpan($group['failed']))->addClass(ZBX_STYLE_RED) : '', - ($group['unknown'] != 0) ? (new CSpan($group['unknown']))->addClass(ZBX_STYLE_GREY) : '' + $group['ok'] != 0 ? (new CSpan($group['ok']))->addClass(ZBX_STYLE_GREEN) : '', + $group['failed'] != 0 ? (new CSpan($group['failed']))->addClass(ZBX_STYLE_RED) : '', + $group['unknown'] != 0 ? (new CSpan($group['unknown']))->addClass(ZBX_STYLE_GREY) : '' ]); } -$output = [ - 'name' => $data['name'], - 'body' => $table->toString() -]; - -if ($messages = get_and_clear_messages()) { - $output['messages'] = array_column($messages, 'message'); -} - -if ($data['user']['debug_mode'] == GROUP_DEBUG_MODE_ENABLED) { - CProfiler::getInstance()->stop(); - $output['debug'] = CProfiler::getInstance()->make()->toString(); -} - -echo json_encode($output); +(new CWidgetView($data)) + ->addItem($table) + ->show(); |