diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:31 +0000 |
commit | f66ab8dae2f3d0418759f81a3a64dc9517a62449 (patch) | |
tree | fbff2135e7013f196b891bbde54618eb050e4aaf /public | |
parent | Initial commit. (diff) | |
download | icingaweb2-module-director-f66ab8dae2f3d0418759f81a3a64dc9517a62449.tar.xz icingaweb2-module-director-f66ab8dae2f3d0418759f81a3a64dc9517a62449.zip |
Adding upstream version 1.10.2.upstream/1.10.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | public/css/module.less | 1835 | ||||
-rw-r--r-- | public/img/globe.png | bin | 0 -> 882 bytes | |||
-rw-r--r-- | public/img/leaf.gif | bin | 0 -> 945 bytes | |||
-rw-r--r-- | public/img/script.png | bin | 0 -> 471 bytes | |||
-rw-r--r-- | public/img/server.png | bin | 0 -> 423 bytes | |||
-rw-r--r-- | public/img/service.png | bin | 0 -> 601 bytes | |||
-rw-r--r-- | public/img/tree.png | bin | 0 -> 524 bytes | |||
-rw-r--r-- | public/js/module.js | 840 |
8 files changed, 2675 insertions, 0 deletions
diff --git a/public/css/module.less b/public/css/module.less new file mode 100644 index 0000000..1f11251 --- /dev/null +++ b/public/css/module.less @@ -0,0 +1,1835 @@ +div.action-bar a:focus, .tabs a:focus { + outline: none; + text-decoration: underline; + + &:before { + text-decoration: none; + } +} + +table.common-table td { + padding-top: 0.2em; + padding-bottom: 0.2em; + vertical-align: middle; + + p { + word-break: break-word; + } +} + +#layout.minimal-layout table.common-table td { + padding-top: 0.5em; + padding-bottom: 0.5em; +} + +table.common-table thead th { + border-bottom: 1px solid @text-color; +} +table.common-table tbody td { + border-bottom: 1px solid @gray-lighter; +} + +a:before { + text-decoration: none; +} + +form.director-form { + max-width: 68em; +} + +form.director-form:focus { + outline: none; +} + +div.action-bar a, div.action-bar form i { + color: @icinga-blue; +} + +div.action-bar > a { + margin-right: 1em; +} + +.controls > .pagination-control li > a { + padding: 0.5em 0 0.5em 0; +} + +.controls > .pagination-control > ul { + float: right; +} + +div.action-bar { + .pagination-control { + float: none; + clear: none; + display: inline-block; + line-height: inherit; + margin: 0; + vertical-align: middle; + } + + form.director-form input { + margin: 0; + } + input { + max-width: unset; + } + select { + line-height: 1.25em; + } +} + +div.action-bar ul { + padding: 0; + margin: 0; + + li { + list-style-type: none; + a { display: block; } + } +} + +div.action-bar > ul { + display: inline-block; +} + +div.action-bar > ul ul { + padding: 0.5em 0em 1em 0em; + min-width: 10em; + position: absolute; + display: none; + color: @text-color-inverted; + background-color: @icinga-blue; + + a { + display: block; + padding: 0.3em 2em 0.3em 2em; + margin: 0; + outline: none; + color: @text-color-inverted; + + &:hover { + text-decoration: underline; + } + } + + li.active a { + font-weight: bold; + } +} + +div.action-bar > ul > li:hover ul { + display: block; +} +div.action-bar > ul > li > a { + padding: 0.2em 0.5em; +} +div.action-bar > ul > li:hover { + background-color: @icinga-blue; + & > a { + color: @text-color-inverted; + text-decoration: none; + } +} + +#layout.twocols div.action-bar .pagination-control { + li { + display: none; + } + + li:nth-child(1), li.active, li:last-child { + display: list-item; + } + + li.active a { + border-bottom: none; + } +} + +.content a { + color: @icinga-blue; + &:hover { + text-decoration: underline; + } +} + +p { + max-width: 56em; +} + +table.common-table { + max-width: 68em; + + a { + color: inherit; + text-decoration: none; + } + + th { + padding-top: 0.5em; + } + td { + vertical-align: top; + } + + pre { + margin: 0; + padding: 0.2em; + max-height: 10em; + background: none; + overflow: auto; + word-break: keep-all; + white-space: pre; + display: inline-block; + -ms-overflow-style: none; + scrollbar-width: none; + &::-webkit-scrollbar { + display: none; + } + } +} + +table.history { + td:last-of-type { + text-align: right; + } +} + +span.disabled { + cursor: no-drop; + color: @gray-light; +} + +.controls span.action-links { + display: block; + margin-bottom: 0.5em; + a { + color: @icinga-blue; + margin-right: 1em; + } + form.director-form { + display: inline; + margin-right: 1em; + } +} + +.action-bar { + form.director-form { + display: inline; + margin-right: 1em; + } +} + +pre.disabled { + color: @disabled-gray; +} + +form.director-form i.link-color::before { + color: @icinga-blue; +} + +/* TODO: remove this, but autosubmit looks ugly otherwise */ +form.director-form input[disabled] { + background: inherit; +} +/* END OF TODO */ + +pre { + background: none; +} + +pre.logfile { + font-size: 0.875em; + padding: 1em; + background: @gray-lighter; + color: @gray; + overflow: auto; + white-space: pre; + + a { + color: @link-color; + } + + .loglevel, .application { + font-weight: bold; + } + + .critical { + color: @color-critical; + } + + .warning { + color: @color-warning; + } + + .information { + color: @color-ok; + } + + .notice { + // color: @color-ok; + } + + .debug { + color: @color-pending; + } + + .error-hint { + color: @text-color; + font-weight: 900; + } +} + +pre.generated-config { + + a { + color: @link-color; + font-weight: bold; + } + + .highlight { + border-bottom: 1px dashed @gray-light; + &::before { + // icon: right-big + font-family: 'ifont'; + content: '\e826'; + margin-left: -1em; + padding-top: 0em; + float: left; + } + + &.critical::before { + color: @color-critical; + } + &.warning::before { + color: @color-warning; + } + &.ok::before { + color: @color-ok; + } + } +} + +pre.agent-deployment-instructions { + color: @text-color; + height: 14em; + overflow: scroll; +} + +table.avp th { + font-size: inherit; +} + +.content form.director-form { + margin-top: 0.5em; + margin-bottom: 2em; +} + +.content form.director-form.inline { + margin: 0; + + i.icon::before { + color: @icinga-blue; + } +} + +.invisible { + position: absolute; + left: -100%; +} + +form.director-form input[type=file] { + padding-right: 1em; +} + + +form.director-form input[type=submit] { + .button(); + border-width: 1px; + margin-top: 0.5em; + + &:disabled { + border-color: @gray-light; + background-color: @gray-light; + color: @disabled-gray; + } +} + +form.director-form input[type=submit]:first-of-type { + border-width: 2px; +} + +form.director-form input[type=submit].link-button { + color: @icinga-blue; + background: none; + border: none; + font-weight: normal; + padding: 0; + margin: 0; + + text-align: left; + + &:hover { + text-decoration: underline; + } +} + +form.director-form p.description { + padding: 1em 1em; + margin: 0; + font-style: italic; + width: 100%; +} + +form.director-form { + input[type=text], input[type=button], select, select option, textarea { + -webkit-appearance: none; + -moz-appearance: none; + } +} + +form.director-form ul.form-errors { + list-style-type: none; + margin-bottom: 0.5em; + padding: 0; + + ul.errors { + list-style-type: none; + padding: 0; + } + + ul.errors li { + background: @color-critical; + font-weight: bold; + padding: 0.5em 1em; + color: @text-color-inverted; + } +} + +form.director-form { + select::-ms-expand, input::-ms-expand, textarea::-ms-expand { /* for IE 11 */ + display: none; + } + + select { + border: 1px solid @gray-light; + cursor: pointer; + background: none; + } + + input[type=text], input[type=password], textarea, select { + max-width: 36em; + min-width: 20em; + width: 100%; + line-height: 2em; + height: 2.4em; + padding-left: 0.5em; + border-style: solid; + border-color: transparent; + border-bottom-color: @gray-lighter; + border-width: 1px 1px 1px 3px; + background-color: @low-sat-blue; + + &.search { + background: transparent url("../img/icons/search.png") no-repeat scroll 0.5em center / 1em 1em; + padding-left: 2em; + } + } + + textarea { + max-width: 100%; + } + + select[multiple] { + height: auto; + } + + select option { + height: 2em; + padding-top: 0.3em; + } + + select[multiple=multiple] { + height: auto; + } + + label { + line-height: 2em; + } +} + +form.director-form dl { + margin: 0; + padding: 0; +} + +.strike-links a, table.common-table .strike-links a { + text-decoration: line-through; + &:hover { + text-decoration: line-through; + } +} +.strike-links span.ro-service { + text-decoration: line-through; +} + +// TODO: figure out whether form.editor and filter-related CSS is still required +div.filter > form.search, div.filter > a { + // Duplicated by quicksearch + display: none; +} + +div.filter form.editor > ul.tree ul li.active { + background-color: @tr-hover-color; +} + +div.filter form.editor { + padding-top: 1em; + select, input[type=text] { + line-height: unset; + height: auto; + } +} + +form.director-form.editor { + select, input[type=text] { + background: @low-sat-blue; + max-width: unset; + min-width: unset; + width: auto; + } + .tree li a { + padding: 0; + } +} + +ul.extensible-set { + margin: 0; + padding: 0; + list-style-type: none; + display: inline-block; + width: 100%; + max-width: 36em; + min-width: 20em; + border-bottom: 1px solid @gray-lighter; + + input[type=text], input[type=password], textarea, select { + border-color: transparent; + } + + li { + display: inline; + } + + select { + width: 100%; + } + + input[type=text] { + background-color: @low-sat-blue; + .rounded-corners(0.5em); + border: 1px solid transparent; + padding: 0.1em 0.3em; + margin: 0.2em 0.2em; + width: 30%; + min-width: 4em; + text-overflow: ellipsis; + } + + span.inline-buttons { + position: absolute; + z-index: 10; + right: 0.225em; + top: -0.275em; + input[type=submit] { + font-family: 'ifont'; + width: 2em; + height: 2em; + font-size: 1em; + margin-left: 0.2em; + padding: 1px 0 1px 0; + } + } + + select.extend-set, input.extend-set { + display: none; + } +} + +form.director-form { + #_FAKE_SUBMIT { + position: absolute; + left: -100%; + } +} + +form.director-form dd.active ul.extensible-set, ul.extensible-set.sortable { + + li { + display: list-item; + position: relative; + clear: both; + } + + input[type=text], select { + width: 100%; + } + + input[type=text] { + background-color: @low-sat-blue; + .rounded-corners(0); + border: 1px solid @gray-light; + padding: 0.25em 0.5em; + margin: 0; + } +} + +form.director-form dd.active ul.extensible-set { + border: 1px solid @icinga-blue; + + input[type=submit]:first-of-type { + border-width: 1px; + } + + select.extend-set, input.extend-set { + display: inline; + } +} + +form.director-form { + select::-moz-focus-inner { + border: 0; + } + + select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #000; + } + + select, input[type=text], textarea { + &:hover { + border-style: dotted solid dotted solid; + border-color: @gray-light; + } + + &:focus, &:focus:hover { + border-style: solid; + border-color: @icinga-blue; + outline: none; + } + } + + select option { + padding-left: 0.5em; + } + + select option[value=""] { + color: @disabled-gray; + background-color: @low-sat-blue; + } +} + +a { + &.state-critical { + color: @color-critical; + } + + &.state-warning { + color: @color-warning; + } + + &.state-ok { + color: @color-ok; + } + + &.state-unknown { + color: @color-unknown; + } + + &.state-pending { + color: @color-pending; + } +} +ul.tabs a.state-critical { + background-color: @color-critical; + font-weight: bold; + color: @text-color-inverted; +} +ul.tabs a.state-warning { + background-color: @color-warning; + font-weight: bold; + color: @text-color-inverted; +} +ul.tabs a.state-ok { + background-color: @color-ok; + font-weight: bold; + color: @text-color-inverted; +} +ul.tabs a.state-unknown { + background-color: @color-unknown; + font-weight: bold; + color: @text-color-inverted; +} + +a:hover::before { + text-decoration: none; +} + +ul.main-actions { + margin: 0; + padding: 0; + min-width: 38em; + max-width: 64em; + + li { + list-style-type: none; + + text-align: left; + display: inline-block; + padding: 0; + clear: both; + width: 18em; + min-width: 16em; + vertical-align: top; + + a { + i { + font-size: 3em; + display: block; + float: left; + line-height: 1em; + margin-right: 0.3em; + color: @text-color-light; + } + + &.state-critical i { + color: @color-critical; + } + + &.state-warning i { + color: @color-warning; + } + + &.state-ok i { + color: @color-ok; + } + + &.state-unknown i { + color: @color-unknown; + } + + &.state-pending i { + color: @color-pending; + } + + border-left: 0.5em solid transparent; + padding: 1em; + color: @text-color; + font-weight: bold; + display: block; + text-decoration: none; + min-height: 12em; + + overflow: hidden; + + &.active { + border-color: @icinga-blue; + background-color: @tr-active-color; + } + + &:hover { + background-color: @tr-hover-color; + text-decoration: none; + } + + &:active, &:focus { + background-color: @tr-hover-color; + outline: none; + } + } + + p { + font-weight: normal; + margin-bottom: 0.5em; + padding-left: 4.5em; + color: @text-color-light; + } + } +} + +#layout.compact-layout.twocols ul.main-actions, +#layout.minimal-layout ul.main-actions { + max-width: unset; + min-width: unset; + li { + width: 100%; + a { + height: auto; + min-height: unset; + } + > a > i { + font-size: 3em; + } + + > a > p { + padding-left: 4.5em; + } + margin-bottom: 0.5em; + } +} + +#layout.minimal-layout div.content form.director-form { + dt, dd { + display: block; + width: auto; + } + fieldset.collapsed { + dd, dt, ul, div { + display: none; + } + } + dt label { + color: @text-color; + } + fieldset { + min-width: unset; + } + + input[type=text], input[type=password], textarea, select { + max-width: unset; + min-width: unset; + border-color: @gray-light; + } + dd.active { + input[type=text], input[type=password], textarea, select { + border-color: @icinga-blue; + } + } + ul.extensible-set { + max-width: unset; + } + dd ul.extensible-set { + border: 1px solid @gray-light; + } + dd.active ul.extensible-set { + border: 1px solid @icinga-blue; + + input[type=submit]:first-of-type { + border-width: 1px; + } + } + + dd.active ul.extensible-set, ul.extensible-set.sortable { + input[type=text], select { + width: 100%; + } + + input[type=text] { + background-color: @low-sat-blue; + border: 1px solid @gray-light; + } + } + +} + +form.director-form fieldset { + margin: 0; + padding: 0 0 1.5em 0; + border: none; + + legend { + margin: 0em 0 0.5em 0; + font-size: 1em; + border-bottom: 1px solid @gray-light; + font-weight: bold; + display: block; + width: 100%; + padding-left: 1em; + line-height: 2em; + cursor: pointer; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + + &:hover { + border-color: @text-color; + } + + &::before { + // icon: down-dir + font-family: 'ifont'; + content: '\e81d'; + margin-left: -1em; + padding-top: 0em; + float: left; + color: inherit; + } + } + + &.collapsed { + legend { + margin: 0; + } + + dd, dt, ul, div { + display: none; + } + + legend::before { + // icon: right-dir + content: '\e820'; + } + + margin-bottom: 0.2em; + padding-bottom: 0; + } +} + + +/* BEGIN Forms */ +form.director-form dt label { + width: auto; + font-weight: normal; + font-size: inherit; + + &.required { + &::after { + content: '*' + } + } + + &:hover { + text-decoration: underline; + cursor: pointer; + } +} + +form.director-form fieldset { + min-width: 36em; +} + +form.director-form dd input.related-action[type='submit'] { + display: none; +} + +form.director-form dd.active li.active input.related-action[type='submit'] { + display: inline-block; +} + +form.director-form { + p.description { + color: @gray; + font-style: italic; + padding: 0.25em 0.5em; + display: none; + } + + dd.active { + p.description { + font-style: normal; + display: block; + height: auto; + color: @text-color; + } + } +} + +form.director-form.db-selector { + padding: 0; + margin: 0; + select { + float: right; + text-align: center; + max-width: 20em; + margin-top: 0.5em; + min-width: 14em; + width: auto; + } +} + +// Adjustments for the legacy layout to keep backwards compatibility +#layout.twocols > #main &#col1 { + width: 50%; +} +#layout.twocols > #main &#col2 { + width: 50%; +} +#layout.twocols > #main &#col1 + #col2 { + width: 50%; +} + +// Adjustments for the flexbox layout +#layout.twocols > #content-wrapper &#col2, +#layout.twocols > #content-wrapper &#col1 + #col2 { + flex-grow: 1; +} + +form.director-form dd { + padding: 0.3em 0.5em; + margin: 0; +} + +form.director-form dt { + padding: 0.5em 0.5em; + margin: 0; +} + +form.director-form dt.active, form.director-form dd.active { + background-color: @tr-active-color; +} + +form.director-form dt { + display: inline-block; + vertical-align: top; + min-width: 12em; + min-height: 2.5em; + width: 30%; + &.errors label { + color: @color-critical; + } +} + +form.director-form .errors label { + color: @color-critical; +} + +form.director-form dd { + display: inline-block; + width: 63%; + min-height: 2.5em; + vertical-align: top; + margin: 0; + &.errors { + input[type=text], select { + border-color: @color-critical; + } + } + + &.full-width { + padding: 0.5em; + width: 100%; + } +} + +form.director-form dd:after { + display: block; + content: ''; +} + +form.director-form textarea { + height: auto; +} + +form.director-form dd ul.errors { + list-style-type: none; + padding-left: 0.3em; + + li { + color: @color-critical; + padding: 0.3em; + } +} + +form.director-form div.hint { + padding: 1em; + background-color: @tr-hover-color; + margin: 1em 0; + max-width: 65em; + font-size: 1em; + + pre { + font-style: normal; + background-color: @body-bg-color; + margin: 0; + padding: 1em; + } +} + +/* END of Forms */ + +ul.health-check-result { + list-style-type: none; + padding: 0; + margin-bottom: 2em; + li { + line-height: 2em; + } + .badge { + font-weight: bold; + } +} + +.title-badges { + .badge { + font-size: 0.6em; + margin-left: 0.5em; + } +} + +li.state { + border-left: 0.5em solid transparent; + margin-bottom: 0.5em; + padding-left: 1em; + &.state-ok { + border-color: @color-ok; + } + &.state-warning { + border-color: @color-warning; + } + &.state-critical { + border-color: @color-critical; + } + &.state-unknown { + border-color: @color-unknown; + } + &.state-pending { + border-color: @color-pending; + } +} + +span.error { + color: @color-critical; + + a { + color: @color-critical; + } +} + +p.legacy-error { + color: @text-color-inverted; + padding: 1em 2em; + background-color: @color-critical; + +} + +table th.actions, table td.actions { + text-align: right; +} + +table tr.disabled td { + color: @gray-light; + font-style: italic; +} + +/* Simple table, test */ +table.syncstate { + tr td:first-child { + padding-left: 2em; + &::before { + font-family: 'ifont'; + // icon-help: + content: '\e85b'; + float: left; + font-weight: bold; + margin-left: -1.5em; + line-height: 1.5em; + } + } + + tr.in-sync td:first-child::before { + content: '\e803'; + color: @color-ok; + } + + tr.pending-changes td:first-child::before { + content: '\e864'; + color: @color-warning; + } + + tr.failing td:first-child::before { + content: '\e804'; + color: @color-critical; + } +} + +table.jobs { + tr td:first-child { + padding-left: 2em; + &::before { + font-family: 'ifont'; + // icon-help: + content: '\e85b'; + float: left; + font-weight: bold; + margin-left: -1.5em; + line-height: 1.5em; + } + } + + tr.ok td:first-child::before { + content: '\e803'; + color: @color-ok; + } + + tr.warning td:first-child::before { + content: '\e864'; + color: @color-warning; + } + + tr.pending td:first-child::before { + content: '\e864'; + color: @color-pending; + } + + tr.critical td:first-child::before { + content: '\e804'; + color: @color-critical; + } +} + +table.icinga-objects { + tr td:first-child { + padding-left: 2em; + &::before { + font-family: 'ifont'; + // icon-wrench: + content: '\e83d'; + float: left; + font-weight: bold; + margin-left: -1.5em; + line-height: 1.5em; + } + } + + tr.icinga-object-external td:first-child::before { + color: @gray; + // icon-pin + content: '\e879'; + } + + tr.icinga-object td:first-child::before { + color: @text-color; + // icon-thumbs-up + // content: '\e867'; + // icon-ok + content: '\e803'; + } + + tr.icinga-template td:first-child::before { + color: @gray-light; + // icon-paste + content: '\e817'; + } + + tr.icinga-apply td:first-child::before { + color: @text-color; + // resize-full-alt + content: '\e829'; + } + +} + +div.content.compact table.icinga-objects thead { + display: none; +} + +table.deployment-log { + + tr td:nth-child(2), tr th:nth-child(2) { + text-align: right; + padding-right: 1em; + } + + tr th:first-child { + padding-left: 2em; + } + + tr td:first-child { + padding-left: 2em; + &::before { + font-family: 'ifont'; + // icon-help: + content: '\e85b'; + float: left; + font-weight: bold; + margin-left: -1.5em; + line-height: 1.5em; + } + } + + tr.succeeded td:first-child::before { + // icon-ok + color: @color-ok; + content: '\e803'; + } + + tr.pending td:first-child::before { + color: @gray; + // icon-spinner + content: '\e874'; + .animate(spin 2s infinite linear); + } + + tr.failed td:first-child::before { + // icon-ok + color: @color-critical; + content: '\e804'; + } + + tr.running td, tr.running td a { + font-weight: bold; + } +} + +th.table-header-day { + text-align: right; +} + +table.activity-log { + td { + max-height: 2em; + } + tr th:first-child { + padding-left: 2em; + } + + tr td:last-child { + text-align: right; + white-space: nowrap; + width:10%; + } + + tr td:first-child { + padding-left: 2em; + &::before { + font-family: 'ifont'; + // icon-help: + content: '\e85b'; + float: left; + font-weight: bold; + margin-left: -1.5em; + line-height: 1.5em; + } + } + + tr.action-create td:first-child::before { + // icon-plus + color: @color-pending; + content: '\e805'; + } + + tr.action-modify td:first-child::before { + // icon-wrench + color: @color-ok; + content: '\e83d'; + } + + tr.action-delete td:first-child::before { + // icon-cancel + color: @color-critical; + content: '\e804'; + } + + tr.undeployed td, tr.undeployed a { + color: @gray; + } + + tr.undeployed { + background-color: @gray-lightest; + &.active { + background-color: @gray-lighter; + } + &[href]:hover { + background-color: @gray-light; + td, a { + color: @text-color; + } + } + } + + tr.branched { + background-color: @gray-lightest; + color: @color-pending; + } + + tr.undeployed td:first-child::before { + color: @gray; + } + + div.range-comment-container { + width: 100%; + position: absolute; + height: 100%; + background: @body-bg-color; + border-radius: 1em; + } + a.range-comment { + width: 100%; + height: 100%; + display: block; + border-radius: 1em; + padding: 0.2em 1em; + vertical-align: middle; + &::-webkit-scrollbar { + display: none; + } + scrollbar-width: none; + -ms-overflow-style: none; + overflow-y:auto; + overflow-x:hidden; + word-break: break-word; + &:hover { + cursor: default; + text-decoration: none; + } + background: fade(@color-warning-handled, 20%); + &:hover { + background: fade(@color-warning-handled, 60%); + } + } + td.comment-cell { + padding: 0; + min-width: 10em; + width: 40%; + position: relative; + &.continuing div.range-comment-container { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + a.range-comment { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } + } + &.continued div.range-comment-container { + border-top-left-radius: 0; + border-top-right-radius: 0; + a.range-comment { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } + } +} + +tr.branch_modified { + color: @color-pending; +} + +table.config-diff { + + tr th:first-child { + padding-left: 2em; + } + + tr td:first-child { + padding-left: 2em; + &::before { + font-family: 'ifont'; + // icon-help: + content: '\e85b'; + float: left; + font-weight: bold; + margin-left: -1.5em; + line-height: 1.5em; + } + } + + tr.file-unmodified td:first-child::before { + // icon-ok + color: @color-ok; + content: '\e803'; + } + + tr.file-created td:first-child::before { + // icon-plus + color: @color-pending; + content: '\e805'; + } + + tr.file-removed td:first-child::before { + // icon-cancel + color: @color-critical; + content: '\e804'; + } + + tr.file-modified td:first-child::before { + // icon-flapping + color: @color-warning; + content: '\e85d'; + } +} + +input[type=submit].icon-button { + font-family: 'ifont'; + font-weight: normal; + background: none; + border: none; + padding: 0.2em 0.4em 0.2em 0.4em; + margin: 0 0 0 0.2em; + + &:hover { + background-color: @icinga-blue; + } + + &:disabled { + background-color: unset; + color: @gray-light; + cursor: default; + } +} + +/** BEGIN breadcrumb **/ + +// Hint: .badges is unused right now +.breadcrumb { + list-style: none; + overflow: hidden; + padding: 0; + + .badges { + display: inline-block; + padding: 0 0 0 0.5em; + .badge { + line-height: 1.25em; + font-size: 0.8em; + border: 1px solid @text-color; + margin: -0.25em 1px 0 0; + } + } +} + +.breadcrumb { + > .critical a { color: @text-color-inverted; background: @color-critical; } + > .critical.handled a { color: @text-color-inverted; background: @color-critical-handled; } + > .unknown a { color: @text-color-inverted; background: @color-unknown; } + > .unknown.handled a { color: @text-color-inverted; background: @color-unknown-handled; } + > .warning a { color: @text-color-inverted; background: @color-warning; } + > .warning.handled a { color: @text-color-inverted; background: @color-warning-handled; } + > .ok a { color: @text-color-inverted; background: @color-ok; } +} + +.breadcrumb { + > .critical a:after { border-left-color: @color-critical; } + > .critical.handled a:after { border-left-color: @color-critical-handled; } + > .unknown a:after { border-left-color: @color-unknown; } + > .unknown.handled a:after { border-left-color: @color-unknown-handled; } + > .warning a:after { border-left-color: @color-warning; } + > .warning.handled a:after { border-left-color: @color-warning-handled; } + > .ok a:after { border-left-color: @color-ok; } +} + +.breadcrumb:after { + content:''; + display:block; + clear: both; +} +.breadcrumb li { + float: left; + cursor: pointer; + user-select: none; + background: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + +} +.breadcrumb li a { + // color: white; + color: @icinga-blue; + margin: 0; + // font-size: 1.2em; + text-decoration: none; + padding-left: 2em; + // line-height: 1.5em; + // background: @icinga-blue; + border: 1px none @icinga-blue; + border-right-style: solid; + border-left-style: solid; + position: relative; + display: block; + float: left; + &:focus { + outline: none; + } + &:hover { + text-decoration: none; + } +} +.action-bar .breadcrumb li a { + padding-left: 2em; +} + +.breadcrumb li a:before, .breadcrumb li a:after { + content: " "; + display: block; + width: 0; + height: 0; + border-top: 1.3em solid transparent; + border-bottom: 1.2em solid transparent; + position: absolute; + margin-top: -1.2em; + top: 50%; + left: 100%; +} + +.breadcrumb li a:before { + border-left: 1.2em solid @icinga-blue; + margin-left: 1px; + z-index: 1; +} + +.breadcrumb li a:after { + border-left: 1.2em solid @body-bg-color; + z-index: 2; +} + +.breadcrumb li:first-child a { + padding-left: 1em; + padding-right: 0.5em; +} +.breadcrumb li:last-child a { + color: @text-color; +} + +.breadcrumb li:not(:last-child) a:hover { background: @icinga-blue; color: @text-color-on-icinga-blue; } +.breadcrumb li:not(:last-child) a:hover:after { border-left-color: @icinga-blue; } +.breadcrumb li:last-child:hover, .breadcrumb li:last-child a:hover { background: transparent; text-decoration: underline; } + +.breadcrumb li a:focus { + text-decoration: underline; +} +/** END of breadcrumb **/ + + + +ul.filter-root { + margin-top: 0; + width: 100%; + padding-left: 0.5em; + list-style-type: none; + ul { + list-style-type: none; + padding-left: 1.5em; + } + + ul.filter { + padding-left: 1.5em; + list-style-type: none; + width: 100%; + } + + li.filter-chain, div.filter-expression { + width: 100%; + padding: 0.3em 0.5em; + min-width: 30em; + } + + ul li.filter-chain::before, ul .filter-expression::before { + font-family: 'ifont'; + // Formerly: icon-down-open: e821 + // icon-right-small: + content: '\e877'; + float: left; + margin-left: -1.5em; + margin-top: 0.5em; + } + + ul.extensible-set { + padding-left: 0; + border: none; + display: inline-block; + vertical-align: top; + li::before { + content: none; + } + } + + .filter-chain > input[type=submit].icon-button, .filter-expression > input[type=submit].icon-button { + display: none; + font-family: 'ifont'; + font-weight: normal; + background: none; + border: none; + padding: 0.2em 0.4em 0.2em 0.4em; + margin: 0 0 0 0.2em; + } + + .active input[type=submit].icon-button, + li:hover input[type=submit].icon-button, + div:hover input[type=submit].icon-button + { + display: inline; + } +} + +.errors > ul.filter-root { + input[type=text], select { + border-color: transparent; + border-bottom-color: @gray-lighter; + } + + select.column, select.operator { + border-left-color: @color-critical; + } +} + + +form.director-form li.filter-chain > select.operator { + min-width: 5em; + max-width: 5em; + width: 5em; +} + +form.director-form div.filter-expression { + .column { + min-width: 7em; + max-width: 30em; + width: auto; + } + + .sign { + min-width: 4em; + max-width: 4em; + width: 4em; + margin: 0 0.3em; + &.wide { + min-width: 6em; + max-width: 8em; + width: 8em; + } + } + + div.expression-wrapper { + display: inline-block; + vertical-align: top; + } + + div.expression-wrapper > input[type=text], + div.expression-wrapper > select { + min-width: 7em; + width: 10em; + max-width: 10em; + } +} + +ul.director-suggestions { +/* + min-width: 18.5em; + max-width: 34.65em; + width: 100%; + */ + width: 20em; + max-height: 25em; + overflow-y: auto; + overflow-x: hidden; + border: 1px solid @icinga-blue; + position: absolute; + z-index: 2000; + padding: 0; + margin: 0; + list-style-type: none; + background-color: @low-sat-blue; + li { + margin: 0; + padding: 0.5em 1em; + } + + li:hover { + background-color: @tr-hover-color; + cursor: pointer; + } + + li.active { + color: @text-color; + &:hover { + color: @text-color; + } + } + + table.benchmark { + font-size: 0.8em; + font-family: @font-family-fixed; + } +} + +table.pivot { + width: 100%; + table-layout: fixed; + + thead th { + text-align: center; + } + + tbody th { + text-align: right; + width: 25%; + } + tbody td { + text-align: center; + } + tbody td > a { + display: block; + font-size: 2em; + line-height: 1.5em; + text-decoration: none; + color: @icinga-blue; + &:hover { + background: @tr-active-color; + text-decoration: none; + } + } +} + +.tree li a { + display: inline-block; + padding-left: 2.4em; + line-height: 2em; + text-decoration: none; + color: @text-color; + outline: 0; + background-repeat: no-repeat; + background-position: 0.8em 0.4em; +} + +ul.tree li > .handle { + background-image: none; + &:before { + content: '\e806'; + font-family: 'ifont'; + position: absolute; + font-size: 0.6em; + margin-left: 0.25em; + margin-top: 0.9em; + } +} +ul.tree li.collapsed > .handle { + background-image: none; + &:before { + content: '\e805'; + } +} +.tree li a { + padding-left: 1em; +} + +div.sql-dump { + background-color: @gray-lightest; + border: 1px solid @gray-light; + padding: 1em; +} + +div.exception { + margin: 1em; +} + +h2.action-create::before { + color: @color-pending; +} +h2.action-modify::before { + color: @color-ok; +} +h2.action-delete::before { + color: @color-critical; +} + +/* Special components */ +table.table-basket-changes { + min-width: 18em; + max-width: 100%; + th { + width: 80%; + font-weight: normal; + text-align: left; + min-width: 10em; + } +} diff --git a/public/img/globe.png b/public/img/globe.png Binary files differnew file mode 100644 index 0000000..48e5b6b --- /dev/null +++ b/public/img/globe.png diff --git a/public/img/leaf.gif b/public/img/leaf.gif Binary files differnew file mode 100644 index 0000000..445769d --- /dev/null +++ b/public/img/leaf.gif diff --git a/public/img/script.png b/public/img/script.png Binary files differnew file mode 100644 index 0000000..28f7652 --- /dev/null +++ b/public/img/script.png diff --git a/public/img/server.png b/public/img/server.png Binary files differnew file mode 100644 index 0000000..ee0c771 --- /dev/null +++ b/public/img/server.png diff --git a/public/img/service.png b/public/img/service.png Binary files differnew file mode 100644 index 0000000..0f1c2fd --- /dev/null +++ b/public/img/service.png diff --git a/public/img/tree.png b/public/img/tree.png Binary files differnew file mode 100644 index 0000000..298343e --- /dev/null +++ b/public/img/tree.png diff --git a/public/js/module.js b/public/js/module.js new file mode 100644 index 0000000..07fe265 --- /dev/null +++ b/public/js/module.js @@ -0,0 +1,840 @@ + +(function (Icinga) { + + var Director = function (module) { + this.module = module; + + this.initialize(); + + this.openedFieldsets = {}; + + this.module.icinga.logger.debug('Director module loaded'); + }; + + Director.prototype = { + + initialize: function () { + /** + * Tell Icinga about our event handlers + */ + this.module.on('rendered', this.rendered); + this.module.on('beforerender', this.beforeRender); + this.module.on('click', 'fieldset > legend', this.toggleFieldset); + // Disabled + // this.module.on('click', 'div.controls ul.tabs a', this.detailTabClick); + this.module.on('click', 'input.related-action', this.extensibleSetAction); + this.module.on('click', 'ul.filter-root input[type=submit]', this.setAutoSubmitted); + this.module.on('focus', 'form input, form textarea, form select', this.formElementFocus); + this.module.on('keyup', '.director-suggest', this.autoSuggest); + this.module.on('keydown', '.director-suggest', this.suggestionKeyDown); + this.module.on('dblclick', '.director-suggest', this.suggestionDoubleClick); + this.module.on('focus', '.director-suggest', this.enterSuggestionField); + this.module.on('focusout', '.director-suggest', this.leaveSuggestionField); + this.module.on('mousedown', '.director-suggestions li', this.clickSuggestion); + this.module.on('dblclick', 'ul.tabs a', this.tabWantsFullscreen); + this.module.on('change', 'form input.autosubmit, form select.autosubmit', this.setAutoSubmitted); + this.module.icinga.logger.debug('Director module initialized'); + }, + + tabWantsFullscreen: function (ev) { + var icinga = this.module.icinga; + var $a, $container, id; + + if (icinga.ui.isOneColLayout()) { + return; + } + + $a = $(ev.currentTarget); + if ($a.hasClass('refresh-container-control')) { + return; + } + $container = $a.closest('.container'); + id = $container.attr('id'); + + icinga.loader.stopPendingRequestsFor($container); + if (id === 'col2') { + icinga.ui.moveToLeft(); + } + + icinga.ui.layout1col(); + icinga.history.pushCurrentState(); + ev.preventDefault(); + ev.stopPropagation(); + }, + + /** + * Autocomplete/suggestion eventhandler + * + * Triggered when pressing a key in a form element with suggestions + * @param ev + */ + suggestionKeyDown: function (ev) { + var $el = $(ev.currentTarget); + var key = ev.which; + + if (key === 13) { + /** + * RETURN key pressed. In case there are any suggestions: + * - let's choose the active one (if set) + * - stop the event + * + * This let's return bubble up in case there is no suggestion list shown + */ + if (this.hasActiveSuggestion($el)) { + this.chooseActiveSuggestion($el); + ev.stopPropagation(); + ev.preventDefault(); + } else { + this.removeSuggestionList($el); + if ($el.closest('.extensible-set')) { + $el.trigger('change'); + } else { + $el.closest('form').submit(); + } + } + } else if (key === 27) { + // ESC key pressed. Remove suggestions if any + this.removeSuggestionList($el); + } else if (key === 39) { + /** + * RIGHT ARROW key pressed. In case there are any suggestions: + * - let's choose the active one (if set) + * - stop the event only if an element has been chosen + * + * This allows to use the right arrow key normally in all other situations + */ + if (this.hasSuggestions($el)) { + if (this.chooseActiveSuggestion($el)) { + ev.stopPropagation(); + ev.preventDefault(); + } + } + } else if (key === 38 ) { + /** + * UP ARROW key pressed. In any case: + * - stop the event + * - activate the previous suggestion if any + */ + ev.stopPropagation(); + ev.preventDefault(); + this.activatePrevSuggestion($el); + } else if (key === 40 ) { // down + /** + * DOWN ARROW key pressed. In any case: + * - stop the event + * - activate the next suggestion if any + */ + ev.stopPropagation(); + ev.preventDefault(); + this.activateNextSuggestion($el); + } + }, + + suggestionDoubleClick: function (ev) { + var $el = $(ev.currentTarget); + this.getSuggestionList($el); + }, + + /** + * Autocomplete/suggestion eventhandler + * + * Triggered when releasing a key in a form element with suggestions + * + * @param ev + */ + autoSuggest: function (ev) { + // Ignore special keys, most of them have already been handled on 'keydown' + var key = ev.which; + if (key === 9 || // TAB + key === 13 || // RETURN + key === 27 || // ESC + key === 37 || // LEFT ARROW + key === 38 || // UP ARROW + key === 39 ) { // RIGHT ARROW + return; + } + + var $el = $(ev.currentTarget); + if (key === 40) { // DOWN ARROW + this.getSuggestionList($el); + } else { + this.getSuggestionList($el, true); + } + }, + + /** + * Activate the next related suggestion if any + * + * This walks down the suggestion list, takes care about scrolling and restarts from + * top once reached the bottom + * + * @param $el + */ + activateNextSuggestion: function ($el) { + var $list = this.getSuggestionList($el); + var $next; + var $active = $list.find('li.active'); + if ($active.length) { + $next = $active.next('li'); + if ($next.length === 0) { + $next = $list.find('li').first(); + } + } else { + $next = $list.find('li').first(); + } + if ($next.length) { + // Will not happen when list is empty or last element is active + $list.find('li.active').removeClass('active'); + $next.addClass('active'); + $list.scrollTop($next.offset().top - $list.offset().top - 64 + $list.scrollTop()); + } + }, + + /** + * Activate the previous related suggestion if any + * + * This walks up through the suggestion list and takes care about scrolling. + * Puts the focus back on the input field once reached the top and restarts + * from bottom when moving up from there + * + * @param $el + */ + activatePrevSuggestion: function ($el) { + var $list = this.getSuggestionList($el); + var $prev; + var $active = $list.find('li.active'); + if ($active.length) { + $prev = $active.prev('li'); + } else { + $prev = $list.find('li').last(); + } + $list.find('li.active').removeClass('active'); + + if ($prev.length) { + $prev.addClass('active'); + $list.scrollTop($prev.offset().top - $list.offset().top - 64 + $list.scrollTop()); + } else { + $el.focus(); + $el.val($el.val()); + } + }, + + /** + * Whether a related suggestion list element exists + * + * @param $input + * @returns {boolean} + */ + hasSuggestionList: function ($input) { + var $ul = $input.siblings('ul.director-suggestions'); + return $ul.length > 0; + }, + + /** + * Whether any related suggestions are currently being shown + * + * @param $input + * @returns {boolean} + */ + hasSuggestions: function ($input) { + var $ul = $input.siblings('ul.director-suggestions'); + return $ul.length > 0 && $ul.is(':visible'); + }, + + /** + * Get a suggestion list. Optionally force refresh + * + * @param $input + * @param $forceRefresh + * + * @returns {jQuery} + */ + getSuggestionList: function ($input, $forceRefresh) { + var $ul = $input.siblings('ul.director-suggestions'); + if ($ul.length) { + if ($forceRefresh) { + return this.refreshSuggestionList($ul, $input); + } else { + return $ul; + } + } else { + $ul = $('<ul class="director-suggestions"></ul>'); + $input.parent().css({ + position: 'relative' + }); + $ul.insertAfter($input); + var suggestionWidth = (parseInt($input.css('width')) * 2) + 'px'; + $ul.css({width: suggestionWidth}); + return this.refreshSuggestionList($ul, $input); + } + }, + + /** + * Refresh a given suggestion list + * + * @param $suggestions + * + * @param $el + * @returns {jQuery} + */ + refreshSuggestionList: function ($suggestions, $el) { + // Not sure whether we need this Accept-header + var headers = { 'X-Icinga-Accept': 'text/html' }; + var icinga = this.module.icinga; + + // Ask for a new window id in case we don't already have one + if (icinga.ui.hasWindowId()) { + headers['X-Icinga-WindowId'] = icinga.ui.getWindowId(); + } else { + headers['X-Icinga-WindowId'] = 'undefined'; + } + + // var onResponse = function (data, textStatus, req) { + var onResponse = function (data) { + $suggestions.html(data); + var $li = $suggestions.find('li'); + if ($li.length) { + $suggestions.show(); + } else { + $suggestions.hide(); + } + }; + + var req = $.ajax({ + type: 'POST', + url: this.module.icinga.config.baseUrl + '/director/suggest', + data: { + value: $el.val(), + context: $el.data('suggestion-context'), + for_host: $el.data('suggestion-for-host') + }, + headers: headers + }); + req.done(onResponse); + + return $suggestions; + }, + + /** + * Click handler for proposed suggestions + * + * @param ev + */ + clickSuggestion: function (ev) { + this.chooseSuggestion($(ev.currentTarget)); + }, + + /** + * Choose a specific suggestion + + * @param $suggestion + */ + chooseSuggestion: function ($suggestion) { + var $el = $suggestion.closest('ul').siblings('.director-suggest'); + var val = $suggestion.text(); + + // extract label and key from key + var re = /^(.+) \[(\w+)]$/; + + var withLabel = val.match(re); + if (withLabel) { + val = withLabel[2]; + } + + if (val.match(/\.$/)) { + $el.val(val); + this.getSuggestionList($el, true); + } else { + $el.focus(); + $el.val(val); + $el.trigger('change'); + this.getSuggestionList($el).remove(); + } + }, + + /** + * Choose the current active suggestion related to a given element + * + * Returns true in case there was any, false otherwise + * + * @param $el + * @returns {boolean} + */ + chooseActiveSuggestion: function ($el) { + var $list = this.getSuggestionList($el); + var $active = $list.find('li.active'); + if ($active.length === 0) { + $active = $list.find('li:hover'); + } + if ($active.length) { + this.chooseSuggestion($active); + return true; + } else { + $list.remove(); + return false; + } + }, + + hasActiveSuggestion: function ($el) { + if (this.hasSuggestions($el)) { + var $list = this.getSuggestionList($el); + var $active = $list.find('li.active'); + if ($active.length === 0) { + $active = $list.find('li:hover'); + } + return $active.length > 0; + } else { + return false; + } + }, + + /** + * Remove related suggestion list if any + * + * @param $el + */ + removeSuggestionList: function ($el) { + if (this.hasSuggestionList($el)) { + this.getSuggestionList($el).remove(); + } + }, + + /** + * Show suggestions when arriving to an empty auto-completion field + * + * @param ev + */ + enterSuggestionField: function (ev) { + // Has been disabled long time ago, as we do not want to open + // extensible Sets on focus. Should we re-enable this and just + // blacklist extensible sets? + // + // var $el = $(ev.currentTarget); + // if ($el.val() === '' || $el.val().match(/\.$/)) { + // this.getSuggestionList($el) + // } + }, + + /** + * Close suggestions when leaving the related form element + * + * @param ev + */ + leaveSuggestionField: function (ev) { +// return; + var _this = this; + setTimeout(function () { + _this.removeSuggestionList($(ev.currentTarget)); + }, 100); + }, + + /** + * Sets an autosubmit flag on the container related to an event + * + * This will be used in beforeRender to determine whether the request has been triggered by an + * auto-submission + * + * @param ev + */ + setAutoSubmitted: function (ev) { + $(ev.currentTarget).closest('.container').data('directorAutosubmit', 'yes'); + }, + + /** + * Caused problems with differing tabs, should not be used + * + * @deprecated + */ + detailTabClick: function (ev) { + var $a = $(ev.currentTarget); + if ($a.closest('#col2').length === 0) { + return; + } + + this.alignDetailLinks(); + }, + + /** + * Caused problems with differing tabs, should not be used + * + * @deprecated + */ + alignDetailLinks: function () { + var self = this; + var $a = $('#col2').find('div.controls ul.tabs li.active a'); + if ($a.length !== 1) { + return; + } + + var $leftTable = $('#col1').find('> div.content').find('table.icinga-objects'); + if ($leftTable.length !== 1) { + return; + } + + var tabPath = self.pathFromHref($a); + + $leftTable.find('tr').each(function (idx, tr) { + var $tr = $(tr); + if ($tr.is('[href]')) { + self.setHrefPath($tr, tabPath); + } else { + // Unfortunately we currently run BEFORE the action table + // handler + var $a = $tr.find('a[href].rowaction'); + if ($a.length === 0) { + $a = $tr.find('a[href]').first(); + } + + if ($a.length) { + self.setHrefPath($a, tabPath); + } + } + }); + + $leftTable.find('tr[href]').each(function (idx, tr) { + var $tr = $(tr); + self.setHrefPath($tr, tabPath); + }); + }, + + pathFromHref: function ($el) { + return this.module.icinga.utils.parseUrl($el.attr('href')).path + }, + + setHrefPath: function ($el, path) { + var a = this.module.icinga.utils.getUrlHelper(); + a.href = $el.attr('href'); + a.pathname = path; + $el.attr('href', a.href); + }, + + extensibleSetAction: function (ev) { + var iid, $li, $prev, $next; + var el = ev.currentTarget; + if (el.name.match(/__MOVE_UP$/)) { + $li = $(el).closest('li'); + $prev = $li.prev(); + // TODO: document what's going on here. + if ($li.find('input[type=text].autosubmit')) { + iid = $prev.find('input[type=text]').attr('id'); + if (iid) { + $li.closest('.container').data('activeExtensibleEntry', iid); + } else { + return true; + } + } + if ($prev.length) { + $prev.before($li.detach()); + this.fixRelatedActions($li.closest('ul')); + } + ev.preventDefault(); + ev.stopPropagation(); + return false; + } else if (el.name.match(/__MOVE_DOWN$/)) { + $li = $(el).closest('li'); + $next = $li.next(); + // TODO: document what's going on here. + if ($li.find('input[type=text].autosubmit')) { + iid = $next.find('input[type=text]').attr('id'); + if (iid) { + $li.closest('.container').data('activeExtensibleEntry', iid); + } else { + return true; + } + } + if ($next.length && ! $next.find('.extend-set').length) { + $next.after($li.detach()); + this.fixRelatedActions($li.closest('ul')); + } + ev.preventDefault(); + ev.stopPropagation(); + return false; + } else if (el.name.match(/__REMOVE$/)) { + $li = $(el).closest('li'); + if ($li.find('.autosubmit').length) { + // Autosubmit element, let the server handle this + return true; + } + + $li.remove(); + this.fixRelatedActions($li.closest('ul')); + ev.preventDefault(); + ev.stopPropagation(); + return false; + } else if (el.name.match(/__DROP_DOWN$/)) { + ev.preventDefault(); + ev.stopPropagation(); + var $el = $(ev.currentTarget).closest('li').find('input[type=text]'); + this.getSuggestionList($el); + return false; + } + }, + + fixRelatedActions: function ($ul) { + var $uls = $ul.find('li'); + var last = $uls.length - 1; + if ($ul.find('.extend-set').length) { + last--; + } + + $uls.each(function (idx, li) { + var $li = $(li); + if (idx === 0) { + $li.find('.action-move-up').attr('disabled', 'disabled'); + if (last === 0) { + $li.find('.action-move-down').attr('disabled', 'disabled'); + } else { + $li.find('.action-move-down').removeAttr('disabled'); + } + } else if (idx === last) { + $li.find('.action-move-up').removeAttr('disabled'); + $li.find('.action-move-down').attr('disabled', 'disabled'); + } else { + $li.find('.action-move-up').removeAttr('disabled'); + $li.find('.action-move-down').removeAttr('disabled'); + } + }); + }, + + formElementFocus: function (ev) { + var $input = $(ev.currentTarget); + if ($input.closest('form.editor').length) { + return; + } + var $set = $input.closest('.extensible-set'); + if ($set.length) { + var $textInputs = $('input[type=text]', $set); + if ($textInputs.length > 1) { + $textInputs.not(':first').attr('tabIndex', '-1'); + } + } + + var $dd = $input.closest('dd'); + if ($dd.attr('id') && $dd.attr('id').match(/button/)) { + return; + } + var $li = $input.closest('li'); + var $dt = $dd.prev(); + var $form = $dd.closest('form'); + + $form.find('dt, dd, li').removeClass('active'); + $li.addClass('active'); + $dt.addClass('active'); + $dd.addClass('active'); + }, + + highlightFormErrors: function ($container) { + $container.find('dd ul.errors').each(function (idx, ul) { + var $ul = $(ul); + var $dd = $ul.closest('dd'); + var $dt = $dd.prev(); + + $dt.addClass('errors'); + $dd.addClass('errors'); + }); + }, + + toggleFieldset: function (ev) { + ev.stopPropagation(); + var $fieldset = $(ev.currentTarget).closest('fieldset'); + $fieldset.toggleClass('collapsed'); + this.fixFieldsetInfo($fieldset); + this.openedFieldsets[$fieldset.attr('id')] = ! $fieldset.hasClass('collapsed'); + }, + + beforeRender: function (ev) { + var $container = $(ev.currentTarget); + var id = $container.attr('id'); + var requests = this.module.icinga.loader.requests; + if (typeof requests[id] !== 'undefined' && requests[id].autorefresh) { + $container.data('director-autorefreshed', 'yes'); + } else { + $container.removeData('director-autorefreshed'); + } + + // Remove the temporary directorAutosubmit flag and set or remove + // the directorAutosubmitted property accordingly + if ($container.data('directorAutosubmit') === 'yes') { + $container.removeData('directorAutosubmit'); + $container.data('directorAutosubmitted', 'yes'); + } else { + $container.removeData('directorAutosubmitted'); + } + }, + + /** + * Whether the given container has been autosubmitted + * + * @param $container + * @returns {boolean} + */ + containerIsAutoSubmitted: function ($container) { + return $container.data('directorAutosubmitted') === 'yes'; + }, + + /** + * Whether the given container has been autorefreshed + * + * @param $container + * @returns {boolean} + */ + containerIsAutorefreshed: function ($container) { + return $container.data('director-autorefreshed') === 'yes'; + }, + + rendered: function (ev) { + var iid; + var icinga = this.module.icinga; + var $container = $(ev.currentTarget); + if ($container.children('div.controls').first().data('directorWindowId') === '_UNDEFINED_') { + var $url = $container.data('icingaUrl'); + if (typeof $url !== 'undefined') { + icinga.loader.loadUrl($url, $container).autorefresh = true; + } + + $container.children('div.controls').children().hide(); + $container.children('div.content').hide(); + return; + } + this.restoreContainerFieldsets($container); + this.backupAllExtensibleSetDefaultValues($container); + this.highlightFormErrors($container); + this.scrollHighlightIntoView($container); + this.scrollActiveRowIntoView($container); + this.highlightActiveDashlet($container); + iid = $container.data('activeExtensibleEntry'); + if (iid) { + $('#' + iid).focus(); + $container.removeData('activeExtensibleEntry'); + } + // Disabled for now + // this.alignDetailLinks(); + if (! this.containerIsAutorefreshed($container) && ! this.containerIsAutoSubmitted($container)) { + this.putFocusOnFirstFormElement($container); + } + + // Turn off autocomplete for all suggested fields + $container.find('input.director-suggest').each(this.disableAutocomplete); + }, + + highlightActiveDashlet: function ($container) { + if (this.module.icinga.ui.isOneColLayout()) { + return; + } + + var url, $actions, $match; + var id = $container.attr('id'); + if (id === 'col1') { + url = $('#col2').data('icingaUrl'); + $actions = $('.main-actions', $container); + } else if (id === 'col2') { + url = $container.data('icingaUrl'); + $actions = $('.main-actions', $('#col1')); + } + if (! $actions.length) { + return; + } + + $match = $('li a[href*="' + url + '"]', $actions); + if ($match.length) { + $('li a.active', $actions).removeClass('active'); + $match.first().addClass('active'); + } + }, + + restoreContainerFieldsets: function ($container) { + var self = this; + $container.find('form').each(self.restoreFieldsets.bind(self)); + }, + + putFocusOnFirstFormElement: function ($container) { + $container.find('form.autofocus').find('label').first().focus(); + }, + + scrollHighlightIntoView: function ($container) { + var $hl = $container.find('.highlight'); + var $content = $container.find('> div.content'); + + if ($hl.length) { + $container.animate({ + scrollTop: $hl.offset().top - $content.offset().top + }, 700); + } + }, + + scrollActiveRowIntoView: function ($container) { + var $tr = $container.find('table.table-row-selectable > tbody > tr.active'); + var $content = $container.find('> div.content'); + if ($tr.length) { + $container.animate({ + scrollTop: $tr.offset().top - $content.offset().top + }, 500); + } + }, + + backupAllExtensibleSetDefaultValues: function ($container) { + var self = this; + $container.find('.extensible-set').each(function (idx, eSet) { + $(eSet).find('input[type=text]').each(self.backupDefaultValue); + $(eSet).find('select').each(self.backupDefaultValue); + }); + }, + + backupDefaultValue: function (idx, el) { + $(el).data('originalvalue', el.value); + }, + + restoreFieldsets: function (idx, form) { + var $form = $(form); + var self = this; + var $sets = $('fieldset', $form); + + $sets.each(function (idx, fieldset) { + var $fieldset = $(fieldset); + if ($fieldset.attr('id') === 'fieldset-assign') { + return; + } + if ($fieldset.find('.required').length === 0 && (! self.fieldsetWasOpened($fieldset))) { + $fieldset.addClass('collapsed'); + self.fixFieldsetInfo($fieldset); + } + }); + + if ($sets.length === 1) { + $sets.first().removeClass('collapsed'); + } + }, + + fieldsetWasOpened: function ($fieldset) { + var id = $fieldset.attr('id'); + if (typeof this.openedFieldsets[id] === 'undefined') { + return false; + } + return this.openedFieldsets[id]; + }, + + fixFieldsetInfo: function ($fieldset) { + if ($fieldset.hasClass('collapsed')) { + if ($fieldset.find('legend span.element-count').length === 0) { + var cnt = $fieldset.find('dt, li').not('.extensible-set li').length; + if (cnt > 0) { + $fieldset.find('legend').append($('<span class="element-count"> (' + cnt + ')</span>')); + } + } + } else { + $fieldset.find('legend span.element-count').remove(); + } + }, + + disableAutocomplete: function () { + $(this) + .attr('autocomplete', 'off') + .attr('autocorrect', 'off') + .attr('autocapitalize', 'off') + .attr('spellcheck', 'false'); + } + }; + + Icinga.availableModules.director = Director; + +}(Icinga)); |