summaryrefslogtreecommitdiffstats
path: root/public/css
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:36:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:36:40 +0000
commita0901c4b7f2db488cb4fb3be2dd921a0308f4659 (patch)
treefafb393cf330a60df129ff10d0059eb7b14052a7 /public/css
parentInitial commit. (diff)
downloadicingadb-web-upstream.tar.xz
icingadb-web-upstream.zip
Adding upstream version 1.0.2.upstream/1.0.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'public/css')
-rw-r--r--public/css/common.less357
-rw-r--r--public/css/form/schedule-service-downtime-form.less21
-rw-r--r--public/css/list/action-list.less14
-rw-r--r--public/css/list/comment-list.less50
-rw-r--r--public/css/list/downtime-list.less93
-rw-r--r--public/css/list/item-list.less239
-rw-r--r--public/css/list/item-table.less176
-rw-r--r--public/css/list/list-item.less139
-rw-r--r--public/css/list/state-item-table.less34
-rw-r--r--public/css/list/state-row-item.less42
-rw-r--r--public/css/list/user-list.less26
-rw-r--r--public/css/markdown.less80
-rw-r--r--public/css/mixin/progress-bar.less179
-rw-r--r--public/css/mixin/state-badges.less31
-rw-r--r--public/css/mixins.less22
-rw-r--r--public/css/view/service-grid.less60
-rw-r--r--public/css/widget/actions.less20
-rw-r--r--public/css/widget/cancel-button.less0
-rw-r--r--public/css/widget/check-attempt.less17
-rw-r--r--public/css/widget/check-statistics.less55
-rw-r--r--public/css/widget/comment-popup.less74
-rw-r--r--public/css/widget/custom-var-table.less60
-rw-r--r--public/css/widget/donut-container.less24
-rw-r--r--public/css/widget/downtime-card.less47
-rw-r--r--public/css/widget/host-state-badges.less3
-rw-r--r--public/css/widget/key-value-list.less19
-rw-r--r--public/css/widget/migrate-popup.less163
-rw-r--r--public/css/widget/monitoring-health.less136
-rw-r--r--public/css/widget/notice.less23
-rw-r--r--public/css/widget/object-features.less53
-rw-r--r--public/css/widget/object-inspection.less17
-rw-r--r--public/css/widget/object-meta-info.less95
-rw-r--r--public/css/widget/object-statistics.less44
-rw-r--r--public/css/widget/performance-data-table.less57
-rw-r--r--public/css/widget/quick-actions.less47
-rw-r--r--public/css/widget/service-state-badges.less3
-rw-r--r--public/css/widget/state-badge.less47
-rw-r--r--public/css/widget/state-change.less128
-rw-r--r--public/css/widget/tag-list.less31
-rw-r--r--public/css/widget/view-mode-switcher.less45
40 files changed, 2771 insertions, 0 deletions
diff --git a/public/css/common.less b/public/css/common.less
new file mode 100644
index 0000000..777cc33
--- /dev/null
+++ b/public/css/common.less
@@ -0,0 +1,357 @@
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+@exports: {
+ @iplWebAssets: "../lib/icinga/icinga-php-library";
+};
+
+& > .content.full-width {
+ padding-left: 0;
+ padding-right: 0;
+
+ .list-item {
+ padding-left: 1em;
+ padding-right: 1em;
+ }
+}
+
+& > .content.full-height {
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+.plugin-output {
+ .monospace();
+ word-break: break-word;
+}
+
+.empty-state {
+ color: @gray-semilight;
+}
+
+div.show-more {
+ .clearfix();
+ float: right;
+}
+
+.state-ball.state-not-available {
+ .ball-solid(@gray-light);
+ .animate(pulse 1.5s infinite both);
+}
+
+.icon-ball {
+ .ball();
+ .ball-outline(@gray);
+ text-align: center;
+
+ i:before {
+ margin-right: 0;
+ }
+}
+
+.user-ball {
+ .ball();
+ .ball-size-xl();
+ .ball-solid(@gray-semilight);
+ font-weight: bold;
+ line-height: 1.75;
+ text-transform: uppercase;
+}
+
+.usergroup-ball {
+ .ball();
+ .ball-outline(@gray);
+ .ball-size-xl();
+ line-height: 1.75;
+ text-transform: uppercase;
+}
+
+.ack-badge {
+ text-transform: uppercase;
+ line-height: 1;
+ margin-top: -.25em;
+ align-self: flex-start;
+
+ i {
+ vertical-align: baseline;
+ }
+}
+
+.controls {
+ .box-shadow(0, 0, 0, 1px, @gray-lighter);
+ flex-shrink: 0;
+ position: relative; // Required for the host meta info control
+ z-index: 1; // The content may clip, this ensures the separator is always visible
+
+ > :not(:only-child) {
+ margin-bottom: .5em;
+ }
+
+ #object-meta-info {
+ margin-bottom: 0;
+
+ .object-meta-info {
+ margin-bottom: .5em;
+ }
+ }
+
+ &.overdue,
+ &.overdue .tabs li.active a,
+ &.overdue .object-meta-info-control {
+ background-color: @gray-lighter;
+ }
+
+ .limit-control,
+ .view-mode-switcher,
+ .sort-control {
+ margin-left: .5em;
+ float: right;
+ }
+
+ .toggle-switch {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .item-list {
+ width: 100%;
+
+ .list-item .main {
+ border-top: none;
+ }
+
+ .list-item .visual {
+ width: auto;
+ margin-top: 0;
+ }
+
+ .list-item .visual,
+ .list-item .main {
+ padding-bottom: .25em;
+ padding-top: .25em;
+ }
+ }
+
+ .search-controls .continue-with {
+ margin-right: -.5em;
+ margin-left: .5em;
+ }
+
+ .show-more {
+ margin-top: .25em;
+ }
+
+ .notice {
+ display: none;
+ }
+
+ // TODO: Remove once ipl-web v0.7.0 is required
+ &:not(.default-layout) {
+ .pagination-control {
+ float: left;
+ }
+
+ .sort-control {
+ display: flex;
+ justify-content: flex-end;
+
+ :not(.form-element) > label {
+ margin-right: 0;
+ }
+
+ .control-button {
+ margin: 0;
+ }
+ }
+
+ > :not(:only-child) {
+ margin-bottom: 0.5em;
+ }
+
+ .search-suggestions {
+ margin-bottom: 2.5em;
+ }
+
+ .search-controls {
+ clear: both;
+ display: flex;
+ min-width: 100%;
+
+ .search-bar {
+ flex: 1 1 auto;
+
+ & ~ .control-button:last-child {
+ margin-right: -.5em;
+ }
+
+ & ~ .control-button {
+ margin-left: .5em;
+ }
+ }
+ }
+ }
+}
+
+.content > h2:first-child,
+.object-detail > h2:first-child {
+ margin-top: 0;
+}
+
+.content.full-width > h2 {
+ margin-left: 1em / 1.333em; // 1em / h2 font size
+}
+
+.object-detail .plugin-output {
+ .rounded-corners(.25em);
+ background-color: @gray-lighter;
+ padding: .5em;
+}
+
+.object-detail .item-list {
+ &.action-list .list-item {
+ margin-right: -1em;
+ margin-left: -1em;
+ padding-right: 1em;
+ padding-left: 1em;
+ }
+
+ .list-item:last-of-type .caption {
+ min-height: 1.5em;
+ max-height: 3em;
+ height: auto;
+ }
+}
+
+.perfdata-wrapper {
+ svg {
+ width: 100%;
+ }
+
+ svg:not(:last-child) {
+ margin-bottom: 1em;
+ }
+}
+
+.text-center {
+ text-align: center;
+}
+
+.text-muted {
+ color: @gray;
+}
+
+.accompanying-text {
+ color: @text-color-light;
+
+ .subject {
+ color: @text-color;
+ .user-select(all);
+ }
+}
+
+.comment-detail {
+ > form,
+ > h2:not(:first-child) {
+ margin-top: 1em;
+ }
+}
+
+.footer {
+ display: flex;
+ .box-shadow(0, -1px, 0, 0, @gray-lighter);
+ color: @text-color-light;
+
+ .selection-count {
+ flex: 1 1 auto;
+
+ .selected-items {
+ font-size: 1.25em;
+ }
+ }
+
+ .status-bar, .selection-count {
+ font-size: .857em;
+ padding: .25em 1em;
+ line-height: 1.7;
+ }
+}
+
+.status-bar {
+ margin-left: auto;
+
+ .item-count {
+ font-size: 1.25em;
+ }
+
+ .state-badges {
+ display: inline-block;
+ margin: 0 0 0 .417em;
+ }
+}
+
+.multiselect-summary {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+
+ // Donut
+ > div:first-child {
+ height: 4em;
+ width: 4em;
+
+ > svg {
+ height: auto;
+ max-width: 100%;
+ }
+ }
+
+ > .vertical-key-value {
+ padding: 0 .5em;
+ }
+}
+
+.hostgroup-list.minimal,
+.servicegroup-list.minimal {
+ .col {
+ padding: 0;
+ }
+
+ .title br {
+ display: none;
+ }
+
+ .vertical-key-value {
+ br {
+ display: none;
+ }
+
+ .key {
+ padding-left: .417em;
+ }
+
+ .value {
+ vertical-align: middle;
+ }
+ }
+}
+
+.hostgroup-list > col.object-statistics-graph,
+.servicegropup-list > col.object-statistics-graph {
+ padding-right: .25em;
+}
+
+.history-list,
+.objectHeader {
+ .visual.small-state-change .state-change {
+ padding-top: .25em;
+ }
+}
+
+.comment-popup {
+ .comment-list .main {
+ // This is necessary to limit the visible comment lines
+ // because the popup is shown in detailed list mode only
+ .caption {
+ height: 3em;
+ }
+ }
+}
diff --git a/public/css/form/schedule-service-downtime-form.less b/public/css/form/schedule-service-downtime-form.less
new file mode 100644
index 0000000..a65264d
--- /dev/null
+++ b/public/css/form/schedule-service-downtime-form.less
@@ -0,0 +1,21 @@
+.downtime-duration {
+ > label {
+ display: flex;
+ flex: 1 1 auto;
+ flex-flow: row-reverse;
+
+ input {
+ flex: 1 1 auto;
+ }
+
+ span {
+ margin-left: .5em;
+ padding: .5625em 0;
+ line-height: 1.1em;
+ }
+
+ &:not(:last-child) {
+ margin-right: 1.5em;
+ }
+ }
+}
diff --git a/public/css/list/action-list.less b/public/css/list/action-list.less
new file mode 100644
index 0000000..5bb08f4
--- /dev/null
+++ b/public/css/list/action-list.less
@@ -0,0 +1,14 @@
+.action-list {
+ [data-action-item]:hover {
+ background-color: @tr-hover-color;
+ cursor: pointer;
+ }
+
+ [data-action-item].active {
+ background-color: @tr-active-color;
+ }
+
+ &[data-icinga-multiselect-url] * {
+ user-select: none;
+ }
+}
diff --git a/public/css/list/comment-list.less b/public/css/list/comment-list.less
new file mode 100644
index 0000000..46b194d
--- /dev/null
+++ b/public/css/list/comment-list.less
@@ -0,0 +1,50 @@
+// Style
+
+// Layout
+
+.comment-list:not(.detailed) .list-item {
+ .title > i:first-child {
+ margin-right: 0;
+ }
+
+ .title > .subject + .badge,
+ .title > .badge + .subject,
+ .title > .badge:last-of-type {
+ margin-left: 0;
+ }
+
+ .title a {
+ &:not(.subject) {
+ .text-ellipsis();
+ }
+ }
+
+ .title .subject:not(:last-child) {
+ margin-left: 0;
+ }
+
+ .title .subject:nth-child(3):last-child {
+ margin-left: 0;
+ }
+}
+
+.comment-list.minimal .list-item {
+ .user-ball {
+ font-size: .857em;
+ height: 1.75em;
+ line-height: 1.5em;
+ width: 1.75em;
+ }
+}
+
+.comment-list.detailed .list-item {
+ .title > .subject:nth-child(3),
+ .title > .badge + .subject:last-child {
+ margin-left: .3em;
+ }
+
+ .caption {
+ max-height: 4.5em;
+ white-space: normal;
+ }
+}
diff --git a/public/css/list/downtime-list.less b/public/css/list/downtime-list.less
new file mode 100644
index 0000000..222bc7e
--- /dev/null
+++ b/public/css/list/downtime-list.less
@@ -0,0 +1,93 @@
+// Style
+
+.downtime-list .list-item,
+.downtime-detail .list-item {
+ .progress {
+ .progress-bar {
+ background-color: @color-ok;
+ }
+ }
+
+ .visual {
+ background-color: @gray-lighter;
+ }
+
+ .main {
+ border-top: 1px solid @gray-light;
+ }
+
+ &:first-child .main {
+ border-top: none;
+
+ .progress-bar {
+ border-top: 1px solid @gray-light;
+ }
+ }
+
+ &.in-effect {
+ .visual {
+ background-color: @color-ok;
+ color: @text-color-on-icinga-blue;
+ }
+
+ .main {
+ padding-top: 0; // If active the progress bar represents the padding top
+ }
+ }
+}
+
+// Layout
+
+.downtime-list .list-item {
+ .caption > * {
+ display: inline;
+ }
+}
+
+.downtime-list .list-item,
+.downtime-detail .list-item {
+ .progress {
+ height: 2px;
+ margin-bottom: ~"calc(.5em - 2px)";
+ min-width: 100%;
+ position: relative;
+
+ .progress-bar {
+ height: 100%;
+ max-width: 100%;
+ }
+ }
+
+ &:first-child .main .progress-bar {
+ height: ~"calc(100% + 1px)"; // +1px due to the border added exclusively for the first item
+ }
+
+ .visual {
+ justify-content: center;
+ flex-shrink: 0;
+ line-height: 1em;
+ margin-right: .5em;
+ padding: .5em .25em;
+ text-align: center;
+ width: 6em;
+
+ strong {
+ font-size: 1.5em;
+ line-height: 1em;
+ }
+ }
+}
+
+.item-list.downtime-list.minimal .list-item {
+ .visual {
+ display: block;
+ line-height: 1.5;
+ width: 8em;
+ white-space: nowrap;
+
+ strong {
+ display: inline-block;
+ font-size: 1em;
+ }
+ }
+}
diff --git a/public/css/list/item-list.less b/public/css/list/item-list.less
new file mode 100644
index 0000000..cd39aac
--- /dev/null
+++ b/public/css/list/item-list.less
@@ -0,0 +1,239 @@
+// Style
+
+.item-list {
+ list-style-type: none;
+
+ > .empty-state {
+ .rounded-corners();
+ background-color: @gray-lighter;
+ }
+
+ .show-more:hover,
+ .page-separator:hover {
+ background: none;
+ }
+
+ > .show-more a {
+ .rounded-corners(.25em);
+ background: @low-sat-blue;
+ text-align: center;
+
+ &:hover {
+ opacity: .8;
+ text-decoration: none;
+ }
+ }
+
+ > .page-separator:after {
+ content: "";
+ display: block;
+ width: 100%;
+ height: 1px;
+ background: @gray;
+ align-self: center;
+ margin-left: .25em;
+ }
+
+ > .page-separator a {
+ color: @gray;
+ font-weight: bold;
+
+ &:hover {
+ text-decoration: none;
+ }
+ }
+
+ > .page-separator + .list-item .main {
+ border-top: none;
+ }
+}
+
+// Layout
+
+.item-list {
+ margin: 0;
+ padding: 0;
+
+ .list-item {
+ display: flex;
+
+ &.show-more a {
+ flex: 1;
+ margin: 1.5em 0;
+ padding: .5em 0;
+ }
+
+ .main {
+ flex: 1 1 auto;
+ padding: .5em 0;
+ width: 0;
+ margin-left: .5em;
+ }
+
+ .visual {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ }
+
+ .caption {
+ height: 3em;
+ text-overflow: ellipsis;
+ overflow: hidden;
+
+ .line-clamp();
+
+ img {
+ max-height: 1em;
+ }
+ }
+
+ header {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ }
+
+ footer {
+ display: flex;
+ justify-content: space-between;
+ }
+ }
+
+ > .empty-state {
+ margin: 0 1em;
+ padding: 1em;
+ text-align: center;
+ }
+}
+
+.item-list.minimal {
+ > .empty-state {
+ padding: .25em;
+ }
+
+ .list-item {
+ header {
+ max-width: 100%;
+ }
+
+ .visual {
+ width: 2.2em;
+ }
+
+ .check-attempt {
+ display: none;
+ }
+
+ .title {
+ p {
+ display: inline;
+
+ & + p {
+ margin-left: .417em;
+ }
+ }
+ }
+
+ .caption {
+ flex: 1 1 auto;
+ height: 1.5em;
+ margin-right: 1em;
+ width: 0;
+
+ .line-clamp("reset");
+ }
+
+ .caption,
+ .caption .plugin-output {
+ .text-ellipsis();
+ }
+ }
+}
+
+.item-list:not(.detailed) .list-item {
+ .title {
+ display: inline-flex;
+ align-items: baseline;
+ white-space: nowrap;
+ min-width: 0;
+
+ > * {
+ margin: 0 .28125em; // 0 calculated &nbsp; width
+
+ &:first-child {
+ margin-left: 0;
+ }
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+
+ .subject {
+ .text-ellipsis();
+ }
+ }
+}
+
+.item-list.detailed .list-item {
+ .title {
+ word-break: break-word;
+ -webkit-hyphens: auto;
+ -ms-hyphens: auto;
+ hyphens: auto;
+ }
+
+ .caption {
+ display: block;
+ height: auto;
+ max-height: 7.5em; /* 5 lines */
+ position: relative;
+
+ .line-clamp(4)
+ }
+}
+
+.item-list {
+ .icon-image {
+ width: 3em;
+ height: 3em;
+ text-align: center;
+ margin-top: .5em;
+ margin-left: .5em;
+ overflow: hidden;
+
+ img {
+ max-height: 100%;
+ max-width: 100%;
+ height: auto;
+ width: auto;
+ }
+ }
+
+ &.minimal {
+ .icon-image {
+ height: 2em;
+ width: 2em;
+ line-height: 2;
+ }
+ }
+}
+
+.controls .list-item:not(:last-child) {
+ margin-bottom: .5em;
+}
+
+.controls .item-list:not(.detailed):not(.minimal) .list-item {
+ .plugin-output {
+ line-height: 1.5
+ }
+
+ .caption {
+ height: 2.5em;
+ }
+}
+
+.controls .item-list.minimal .icon-image {
+ margin-top: 0;
+}
diff --git a/public/css/list/item-table.less b/public/css/list/item-table.less
new file mode 100644
index 0000000..c307416
--- /dev/null
+++ b/public/css/list/item-table.less
@@ -0,0 +1,176 @@
+// Style
+
+.item-table {
+ padding: 0;
+
+ thead {
+ th {
+ font-weight: normal;
+
+ // Border styles start
+ form {
+ padding: 0 0 0 1px;
+ border-bottom: 1px solid @gray-light;
+ background: linear-gradient(to top, @gray-light, @body-bg-color);
+
+ button {
+ background: @body-bg-color;
+ }
+ }
+ &:first-child form {
+ padding-left: 0;
+ }
+ // Border styles end
+ }
+
+ button {
+ .appearance(none);
+ border: none;
+ background: none;
+ padding: .1em .5em;
+
+ text-align: left;
+ color: @text-color-light;
+
+ > .icon {
+ opacity: 0;
+ width: 0;
+ transition: opacity .25s linear, width .25s ease;
+ }
+ &:hover .icon,
+ &:focus .icon,
+ &.active .icon {
+ opacity: 1;
+ width: 1em;
+ }
+
+ &.active {
+ font-weight: bold;
+ }
+ }
+ }
+
+ > .empty-state,
+ > tbody > tr:first-child .empty-state {
+ .rounded-corners();
+ background-color: @gray-lightest;
+ }
+
+ .list-item:not(:last-child) > *:not(.visual),
+ .row-item:not(:last-child) {
+ border-bottom: 1px solid @gray-light;
+ }
+}
+
+@media print {
+ .list-item.page-break-follows {
+ &:not(:last-child) > *:not(.visual) {
+ border-bottom: none;
+ }
+ }
+}
+
+// Layout
+
+table.item-table {
+ table-layout: fixed;
+}
+
+.item-table {
+ display: table;
+ width: 100%;
+ margin: 0;
+
+ thead {
+ position: sticky;
+ top: 0;
+
+ th {
+ // That's layout, yes, controls overflow when scrolling
+ padding: 1em 0 0 0;
+ background: @body-bg-color;
+ }
+
+ th button {
+ width: 100%;
+ display: inline-flex;
+ align-items: baseline;
+ justify-content: space-between;
+
+ span {
+ .text-ellipsis();
+ }
+ }
+ }
+
+ th.has-visual {
+ width: 3em;
+ }
+
+ tbody td {
+ .text-ellipsis();
+ vertical-align: top;
+ }
+
+ .list-item {
+ display: table-row;
+ }
+
+ .list-item > .col {
+ display: table-cell;
+ vertical-align: middle;
+ white-space: nowrap;
+
+ &:not(:last-child) {
+ padding-right: 1em;
+ }
+
+ &.title {
+ .text-ellipsis();
+ width: 100%;
+ }
+
+ > * {
+ display: inline-block;
+
+ &:not(:last-child) {
+ margin-right: .5em;
+ }
+ }
+ }
+
+ .list-item > *:not(.visual) {
+ padding: .5em 0;
+ }
+
+ .list-item > .visual {
+ display: table-cell;
+ padding: .5em 1em 0 0;
+ }
+
+ > .empty-state,
+ > tbody > tr:first-child .empty-state {
+ margin: 0 1em;
+ padding: 1em;
+ text-align: center;
+ }
+}
+
+.content.full-width .item-table .list-item {
+ // The .list-item itself can't have padding because of `display:table-row`
+ &:before, &:after {
+ display: inline-block;
+ content: '\00a0';
+ width: 1em;
+ }
+}
+
+#layout.twocols table.item-table {
+ > thead > tr > th,
+ > tbody > tr > td {
+ &:nth-child(n+6) {
+ display: none;
+ width: 0;
+ }
+ }
+}
diff --git a/public/css/list/list-item.less b/public/css/list/list-item.less
new file mode 100644
index 0000000..2370b59
--- /dev/null
+++ b/public/css/list/list-item.less
@@ -0,0 +1,139 @@
+// Style
+
+.list-item {
+ color: @text-color-light;
+
+ &.overdue {
+ background-color: @gray-lighter;
+ }
+
+ &.overdue header > *:not(time),
+ &.overdue .caption {
+ opacity: 0.6;
+ }
+
+ &.overdue time {
+ .rounded-corners();
+ background-color: @color-critical;
+ color: @text-color-on-icinga-blue;
+ }
+
+ &:not(:first-child) > .main {
+ border-top: 1px solid @gray-light;
+ }
+
+ &:not(:first-child) .visual {
+ margin-top: 1px;
+ }
+
+ .caption {
+ i {
+ opacity: 0.8;
+ }
+
+ a {
+ color: @text-color;
+ }
+ }
+
+ .title {
+ span.subject,
+ .state-text {
+ color: @text-color;
+ }
+
+ .state-text {
+ text-transform: uppercase;
+ }
+
+ a {
+ color: @text-color;
+ font-weight: bold;
+
+ &:hover {
+ color: @icinga-blue;
+ text-decoration: none;
+ }
+ }
+ }
+
+ footer {
+ .status-icons {
+ color: @gray-light;
+ }
+ }
+}
+
+@media print {
+ .list-item.page-break-follows + .list-item {
+ .main {
+ border-top: 1px solid transparent;
+ }
+ }
+}
+
+// Layout
+
+.list-item {
+ &.overdue time {
+ margin-right: -.5em;
+ padding: 0 0.5em;
+ }
+
+ .visual {
+ padding: .5em 0;
+ width: 2.5em;
+
+ .check-attempt {
+ margin-top: .5em;
+ }
+ }
+
+ .caption {
+ p {
+ display: inline-block;
+ }
+
+ &.plugin-output, .plugin-output {
+ font-size: 11/12em;
+ line-height: 1.5*12/11em;
+ }
+ }
+
+ .title {
+ margin-right: 1em;
+
+ p {
+ margin: 0;
+ }
+ }
+
+ time {
+ white-space: nowrap;
+ }
+
+ footer {
+ > * {
+ font-size: .857em;
+ line-height: 1.5*.857em;
+ }
+
+ .status-icons {
+ display: flex;
+ align-items: center;
+ }
+
+ .performance-data {
+ .inline-pie {
+ display: inline-block;
+ line-height: 1.5*.857em;
+ height: 1em;
+ width: 1em;
+
+ &:not(:last-child) {
+ margin-right: .209em;
+ }
+ }
+ }
+ }
+}
diff --git a/public/css/list/state-item-table.less b/public/css/list/state-item-table.less
new file mode 100644
index 0000000..aece148
--- /dev/null
+++ b/public/css/list/state-item-table.less
@@ -0,0 +1,34 @@
+// Layout
+
+#layout.wide-layout .item-table th.has-plugin-output {
+ width: 50em;
+}
+#layout.default-layout .item-table th.has-plugin-output {
+ width: 30em;
+}
+#layout.compact-layout .item-table th.has-plugin-output {
+ width: 10em;
+}
+
+#layout.twocols table.item-table {
+ .has-plugin-output {
+ width: auto;
+ }
+}
+
+table.item-table {
+ th.has-visual {
+ button {
+ display: inline-flex;
+ justify-content: center;
+ }
+
+ span > .icon:before {
+ margin: 0;
+ }
+ }
+
+ .visual {
+ text-align: center;
+ }
+}
diff --git a/public/css/list/state-row-item.less b/public/css/list/state-row-item.less
new file mode 100644
index 0000000..31c7e5a
--- /dev/null
+++ b/public/css/list/state-row-item.less
@@ -0,0 +1,42 @@
+// Style
+
+.row-item {
+ .plugin-output {
+ overflow: hidden;
+ .line-clamp();
+ }
+
+ .subject {
+ font-weight: bold;
+ }
+}
+
+// Layout
+
+.row-item {
+ .performance-data {
+ overflow: hidden;
+ .line-clamp(2);
+ white-space: normal;
+ margin-left: -.25em;
+
+ .inline-pie {
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ margin-left: .25em;
+ }
+ }
+
+ .has-icon-images {
+ height: 2.5em;
+ vertical-align: middle;
+
+ img {
+ max-height: 100%;
+ max-width: 100%;
+ height: auto;
+ width: auto;
+ }
+ }
+}
diff --git a/public/css/list/user-list.less b/public/css/list/user-list.less
new file mode 100644
index 0000000..078d1b9
--- /dev/null
+++ b/public/css/list/user-list.less
@@ -0,0 +1,26 @@
+// Layout
+
+.controls .user-list,
+.controls .usergroup-list {
+ .usergroup-ball,
+ .user-ball {
+ height: 1.5em;
+ width: 1.5em;
+ line-height: ~"calc(1.5em - 4px)";
+ display: block;
+ }
+
+ .title br {
+ display: none;
+ }
+
+ .list-item {
+ & > .visual {
+ padding-top: 0.25em;
+ }
+
+ & > .col {
+ padding: .25em 0;
+ }
+ }
+}
diff --git a/public/css/markdown.less b/public/css/markdown.less
new file mode 100644
index 0000000..bebede5
--- /dev/null
+++ b/public/css/markdown.less
@@ -0,0 +1,80 @@
+.markdown {
+ > p,
+ > hr,
+ > ul,
+ > ol,
+ > table,
+ > pre,
+ > blockquote,
+ li > ul,
+ li > ol {
+ margin: 1em 0 1em 0;
+
+ &:first-child {
+ margin-top: 0;
+ }
+ }
+
+ p {
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ }
+
+ a {
+ border-bottom: 1px dotted @text-color-light;
+
+ &:hover, &:focus {
+ border-bottom: 1px solid @text-color;
+ text-decoration: none;
+ }
+
+ img {
+ max-width: 32em;
+ }
+
+ &.with-thumbnail {
+ img {
+ padding: 1px;
+ }
+
+ &:hover, &:focus {
+ img {
+ padding: 0;
+ }
+ }
+ }
+ }
+
+ table {
+ border-collapse: collapse;
+
+ th {
+ text-align: left;
+ background-color: @gray-lighter;
+ }
+
+ &, th, td {
+ border: 1px solid;
+ border-color: @gray-light;
+ }
+ }
+}
+
+.markdown.inline {
+ img {
+ max-height: 100%;
+ vertical-align: middle;
+ }
+
+ a.with-thumbnail {
+ &, &:hover, &:focus {
+ border-bottom: none;
+ }
+ }
+}
diff --git a/public/css/mixin/progress-bar.less b/public/css/mixin/progress-bar.less
new file mode 100644
index 0000000..532ca2c
--- /dev/null
+++ b/public/css/mixin/progress-bar.less
@@ -0,0 +1,179 @@
+.progress-bar() {
+ &.progress-bar {
+ .above,
+ .below {
+ list-style-type: none;
+ position: relative;
+ margin: 0;
+ }
+
+ .above {
+ padding: ~"calc(1em + 1px) 10%";
+ }
+
+ .below {
+ padding: 1.25em 10%;
+ }
+
+ .positioned {
+ position: absolute;
+ }
+
+ :not(.positioned).end .bubble {
+ // to move the center of the bubble to the end of the wrapper (for check-statistics end bubble only).
+ transform: translate(50%, 0);
+ }
+
+ .bubble {
+ .rounded-corners(.25em);
+ background-color: @body-bg-color;
+ border: 1px solid;
+ border-color: @gray-light;
+ position: relative;
+ box-shadow: 0 0 1em 0 rgba(0, 0, 0, .1);
+ padding: .25em .5em;
+ text-align: center;
+ width: auto;
+ // The wrapper of .bubble is dynamically moved to the left based on the value of the progress bar
+ // This moves the center of the bubble to the beginning of the wrapper regardless of the size of the content.
+ transform: translate(-50%, 0);
+ z-index: 1;
+
+ > * {
+ position: relative;
+ z-index: 2;
+ }
+
+ &:hover {
+ z-index: 5;
+ }
+
+ &:before {
+ background-color: @body-bg-color;
+ border-bottom: 1px solid @gray-light;
+ border-right: 1px solid @gray-light;
+ content: "";
+ display: block;
+ height: 1em;
+ margin-left: -.5em;
+ transform: rotate(45deg);
+ width: 1em;
+ z-index: 1;
+
+ position: absolute;
+ bottom: -.5em;
+ left: 50%;
+ }
+
+ &.upwards:before {
+ bottom: auto;
+ top: -.5em;
+ transform: rotate(225deg);
+ }
+
+ &.right {
+ // This is (.675em (:before placement) + .5em (half :before width)) + 1px (:before border)
+ transform: translate(~"calc(-1.175em - 1px)", 0);
+ }
+
+ &.right:before {
+ bottom: auto;
+ left: 1.175em;
+ top: -.5em;
+ }
+
+ &.left {
+ // entire width (moves the right border in place of the left) + (.675em (:before placement) + .5em (half :before width)) + 1px (:before border)
+ transform: translate(~"calc(-100% + 1.175em + 1px)", 0);
+ }
+
+ &.left:before {
+ bottom: auto;
+ left: auto;
+ right: .675em;
+ top: -.5em;
+ }
+ }
+
+ .above .positioned {
+ bottom: 0;
+ }
+
+ .below .positioned {
+ top: 0;
+ }
+
+ .vertical-key-value {
+ .key {
+ white-space: nowrap;
+ }
+
+ .value {
+ white-space: nowrap;
+ font-size: 1em;
+ line-height: 1;
+ }
+ }
+
+ .timeline {
+ .rounded-corners(.5em);
+ background-color: @gray-lighter;
+ height: 1em;
+ margin: 1em 0;
+ position: relative;
+ width: 100%;
+ z-index: 1;
+
+ .marker {
+ .rounded-corners(50%);
+ background-color: @gray-light;
+ height: .857em;
+ margin-left: -.857/2em;
+ margin-top: -1/12em;
+ width: .857em;
+ z-index: 2;
+
+ position: absolute;
+ top: 2/12em;
+
+ &.now {
+ background-color: @gray;
+ }
+
+ &.start,
+ &.end {
+ background-color: @icinga-blue;
+ }
+ }
+ }
+
+ .timeline-overlay {
+ height: 100%;
+ opacity: .6;
+ position: absolute;
+
+ &:before,
+ &:after {
+ content: "";
+ display: block;
+ height: 1em;
+ width: .5em;
+
+ position: absolute;
+ top: 0;
+ }
+
+ &:before {
+ border-bottom-left-radius: .5em;
+ border-top-left-radius: .5em;
+ left: -.5em;
+ }
+
+ &:after {
+ border-bottom-right-radius: .5em;
+ border-top-right-radius: .5em;
+ right: -.5em;
+ }
+ }
+ }
+}
diff --git a/public/css/mixin/state-badges.less b/public/css/mixin/state-badges.less
new file mode 100644
index 0000000..61116cf
--- /dev/null
+++ b/public/css/mixin/state-badges.less
@@ -0,0 +1,31 @@
+.state-badges() {
+ &.state-badges {
+ padding: 0;
+
+ ul {
+ padding: 0;
+ }
+
+ li {
+ display: inline-block;
+ }
+
+ li > ul > li:first-child:not(:last-child) .state-badge {
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+ }
+
+ li > ul > li:last-child:not(:first-child) .state-badge {
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+ }
+
+ > li:not(:last-child) {
+ margin-right: .25em;
+ }
+
+ li > ul > li:last-child {
+ margin-left: 1px;
+ }
+ }
+}
diff --git a/public/css/mixins.less b/public/css/mixins.less
new file mode 100644
index 0000000..c6607c2
--- /dev/null
+++ b/public/css/mixins.less
@@ -0,0 +1,22 @@
+/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
+
+.line-clamp(@numOfLines: 2) when (@numOfLines > 1) {
+ display: -webkit-box;
+ -webkit-line-clamp: @numOfLines;
+ -webkit-box-orient: vertical;
+}
+.line-clamp(@numOfLines: 2) when (@numOfLines = "reset") {
+ display: block; // Would have used "revert", but browser support is still poor and it's not final yet
+ -webkit-line-clamp: initial;
+ -webkit-box-orient: initial;
+}
+
+.text-ellipsis() {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.monospace() {
+ font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
+}
diff --git a/public/css/view/service-grid.less b/public/css/view/service-grid.less
new file mode 100644
index 0000000..41400e5
--- /dev/null
+++ b/public/css/view/service-grid.less
@@ -0,0 +1,60 @@
+.service-grid-table {
+ width: 0;
+ white-space: nowrap;
+
+ td {
+ color: @gray-light;
+ padding: 0.2em;
+ text-align: center;
+ width: 1em;
+ }
+
+ .rotate-45 {
+ height: 10em;
+
+ div {
+ .transform(translate(0.4em, 2.8em) rotate(315deg));
+ width: 1.5em;
+ }
+ }
+
+ .service-grid-table-more {
+ text-align: center;
+ a {
+ display: inline;
+ }
+ }
+}
+
+.joystick-pagination {
+ margin: 0 auto;
+ font-size: 130%;
+
+ a {
+ color: @text-color;
+ outline: none;
+
+ &:hover {
+ color: @text-color-light;
+ }
+ &:focus, &:active {
+ color: @icinga-blue;
+ }
+ }
+
+ i {
+ display: block;
+ height: 1.5em;
+ width: 1.5em;
+ }
+}
+
+.service-grid-link {
+ .bg-stateful();
+ .rounded-corners();
+
+ display: inline-block;
+ height: 1.5em;
+ vertical-align: middle;
+ width: 1.5em;
+}
diff --git a/public/css/widget/actions.less b/public/css/widget/actions.less
new file mode 100644
index 0000000..796fc38
--- /dev/null
+++ b/public/css/widget/actions.less
@@ -0,0 +1,20 @@
+.object-detail-actions a {
+ border-bottom: 1px solid @gray-light;
+ display: inline-block;
+ margin-bottom: .25em;
+
+ .text-ellipsis();
+ max-width: 32em;
+
+ &:hover {
+ border-color: @icinga-blue-light;
+ color: @icinga-blue;
+ text-decoration: none;
+ }
+}
+
+ul.object-detail-actions {
+ list-style-type: none;
+ padding: 0;
+ margin: 0;
+}
diff --git a/public/css/widget/cancel-button.less b/public/css/widget/cancel-button.less
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/public/css/widget/cancel-button.less
diff --git a/public/css/widget/check-attempt.less b/public/css/widget/check-attempt.less
new file mode 100644
index 0000000..1042a08
--- /dev/null
+++ b/public/css/widget/check-attempt.less
@@ -0,0 +1,17 @@
+.check-attempt {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.check-attempt .ball {
+ background-color: @gray-light;
+
+ &:not(:last-child) {
+ margin-right: 1/6em;
+ }
+
+ &.taken {
+ background-color: @gray-semilight;
+ }
+}
diff --git a/public/css/widget/check-statistics.less b/public/css/widget/check-statistics.less
new file mode 100644
index 0000000..e2b5ac0
--- /dev/null
+++ b/public/css/widget/check-statistics.less
@@ -0,0 +1,55 @@
+.check-statistics {
+ .card();
+ .progress-bar();
+ .card-footer {
+ display: flex;
+ justify-content: center;
+ border-top: 1px solid @gray-light;
+
+ .key {
+ width: auto;
+ margin-right: .28125em; //calculated &nbsp; width
+ font-size: .83333333em;
+ }
+ }
+
+ .check-attempt {
+ display: inline-flex;
+ }
+
+ &.progress-bar .below {
+ padding: 0;
+ margin-left: 10%;
+ margin-right: auto;
+
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ &:before {
+ background-color: @gray;
+ content: "";
+ display: block;
+ height: .25em;
+ width: 100%;
+
+ position: absolute;
+ top: ~"calc(50% - .125em)";
+ }
+ }
+
+ .interval {
+ background-color: @body-bg-color;
+ position: relative;
+ }
+
+ .check-overdue {
+ background-color: @color-down;
+ opacity: 1;
+
+ &:before,
+ &:after {
+ background-color: @color-down;
+ }
+ }
+}
diff --git a/public/css/widget/comment-popup.less b/public/css/widget/comment-popup.less
new file mode 100644
index 0000000..4012697
--- /dev/null
+++ b/public/css/widget/comment-popup.less
@@ -0,0 +1,74 @@
+.comment-popup {
+ font-size: 1em / .857em; // // default font size / footer font size = 12px
+ height: 6em;
+ border-radius: 0.25em;
+ border: 1px solid;
+ border-color: @gray-light;
+ background-color: @body-bg-color;
+}
+
+.comment-wrapper {
+ position: relative;
+
+ .comment-popup {
+ position: absolute;
+ top: 2.5em;
+ left: -1.6em;
+ z-index: 1;
+ display: none;
+ width: 50em;
+ }
+
+ .comment-popup:before {
+ content: '';
+ position: absolute;
+ display: inline-block;
+ width: 1.5em;
+ height: 1.5em;
+ left: 1.5em;
+ top: ~"calc(-0.75em - 1px)";
+ border-left: 1px solid @gray-light;
+ border-top: 1px solid @gray-light;
+ background-color: @body-bg-color;
+ z-index: -1;
+ transform: rotate(45deg);
+ }
+}
+
+ul.item-list li:last-child .comment-wrapper {
+ .comment-popup {
+ top: -7em;
+ }
+
+ .comment-popup:before {
+ bottom: ~"calc(-0.75em - 1px)";
+ top: unset;
+ transform: rotate(225deg);
+ }
+}
+
+.comment-wrapper:hover .comment-popup {
+ display: block
+}
+
+#layout {
+ &.twocols {
+ .comment-popup {
+ width: 35em;
+ }
+
+ &.poor-layout,
+ &.compact-layout {
+ .comment-popup {
+ width: 25em;
+ }
+ }
+ }
+
+ &.poor-layout,
+ &.minimal-layout {
+ .comment-popup {
+ width: 25em;
+ }
+ }
+}
diff --git a/public/css/widget/custom-var-table.less b/public/css/widget/custom-var-table.less
new file mode 100644
index 0000000..46f1984
--- /dev/null
+++ b/public/css/widget/custom-var-table.less
@@ -0,0 +1,60 @@
+.custom-var-table {
+ .level-1 th {
+ padding-left: .5em;
+ }
+
+ .level-2 th {
+ padding-left: 1em;
+ }
+
+ .level-3 th {
+ padding-left: 1.5em;
+ }
+
+ .level-4 th {
+ padding-left: 2em;
+ }
+
+ .level-5 th {
+ padding-left: 2.5em;
+ }
+
+ .level-6 th {
+ padding-left: 3em;
+ }
+
+ thead th {
+ padding-left: 0;
+ text-align: left;
+ font-weight: bold;
+ font-size: 1.167em;
+
+ > span {
+ :nth-child(1),
+ :nth-child(2) {
+ display: none;
+ }
+ }
+ }
+
+ &.can-collapse thead th > span, // Icinga Web 2 < 2.12
+ &[data-can-collapse] thead th > span { // >= 2.12
+ :nth-child(1) {
+ display: none;
+ }
+
+ :nth-child(2) {
+ display: inline-block;
+ }
+ }
+
+ &.collapsed thead th > span {
+ :nth-child(1) {
+ display: inline-block;
+ }
+
+ :nth-child(2) {
+ display: none;
+ }
+ }
+}
diff --git a/public/css/widget/donut-container.less b/public/css/widget/donut-container.less
new file mode 100644
index 0000000..6fc4466
--- /dev/null
+++ b/public/css/widget/donut-container.less
@@ -0,0 +1,24 @@
+.donut-container {
+ .card();
+
+ h2 {
+ margin: 0;
+ }
+
+ .state-badges {
+ text-align: center;
+ }
+
+ &:not(:last-of-type) {
+ margin-right: 1em;
+ margin-bottom: 1em;
+ }
+
+ .donut {
+ margin: 0 auto;
+ }
+}
+
+#layout.minimal-layout .donut-container {
+ width: 100%;
+}
diff --git a/public/css/widget/downtime-card.less b/public/css/widget/downtime-card.less
new file mode 100644
index 0000000..bffaf22
--- /dev/null
+++ b/public/css/widget/downtime-card.less
@@ -0,0 +1,47 @@
+.downtime-progress {
+ .progress-bar();
+
+ &.flexible.in-effect .marker {
+ &.start,
+ &.end {
+ background-color: @gray-light;
+ }
+
+ &.flex-start,
+ &.flex-end {
+ background-color: @icinga-blue;
+ }
+ }
+
+ .downtime-elapsed {
+ background-color: @color-ok;
+
+ &:before,
+ &:after {
+ background-color: @color-ok;
+ }
+ }
+
+ .downtime-overrun {
+ background-color: @color-down;
+
+ &:before,
+ &:after {
+ background-color: @color-down;
+ }
+ }
+
+ .downtime-elapsed + .downtime-overrun {
+ &:before {
+ display: none;
+ }
+ }
+}
+
+.downtime-progress.progress-bar {
+ // This requires more specificity, otherwise it has no effect
+ .above,
+ .below {
+ padding: 2em 10%;
+ }
+}
diff --git a/public/css/widget/host-state-badges.less b/public/css/widget/host-state-badges.less
new file mode 100644
index 0000000..d55a45c
--- /dev/null
+++ b/public/css/widget/host-state-badges.less
@@ -0,0 +1,3 @@
+.host-state-badges {
+ .state-badges();
+}
diff --git a/public/css/widget/key-value-list.less b/public/css/widget/key-value-list.less
new file mode 100644
index 0000000..cd99f5f
--- /dev/null
+++ b/public/css/widget/key-value-list.less
@@ -0,0 +1,19 @@
+.key-value-list {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+
+ li {
+ display: flex;
+ }
+
+ li > span {
+ padding: .25em;
+
+ &.label {
+ display: block;
+ padding-left: 0;
+ width: 12em;
+ }
+ }
+}
diff --git a/public/css/widget/migrate-popup.less b/public/css/widget/migrate-popup.less
new file mode 100644
index 0000000..f7adb22
--- /dev/null
+++ b/public/css/widget/migrate-popup.less
@@ -0,0 +1,163 @@
+#migrate-popup {
+ @transitionLength: 350ms;
+
+ display: flex;
+ min-width: 16em;
+ z-index: 1000;
+ position: fixed;
+ top: 0;
+ right: 4em;
+ pointer-events: none;
+ line-height: 1.5em;
+
+ .transform(translateY(-100%));
+ .transition(transform @transitionLength ease-in);
+
+ &.active {
+ .transform(translateY(0%));
+ .transition(transform @transitionLength ease-out);
+ }
+
+ .suggestion-area {
+ .transform(translateY(0%));
+ .transition(transform 0s linear @transitionLength);
+ }
+
+ &.active .suggestion-area {
+ .transition(transform @transitionLength ease-out);
+ }
+
+ &.minimized .suggestion-area {
+ .transform(translateY(-100%));
+ .transition(transform @transitionLength ease-in);
+ }
+
+ &.hidden .suggestion-area {
+ .transition(none);
+ }
+
+ .minimizer {
+ width: 1.25em;
+ height: 1.5em;
+ margin-left: -1px;
+ z-index: 1;
+ pointer-events: auto;
+
+ border-bottom-right-radius: 4px;
+ background-color: @body-bg-color;
+
+ .transition(none);
+
+ i:before {
+ width: 1em;
+ margin: .1em 0 0 0;
+ content: '\f102';
+ font-size: 1.25em;
+ cursor: pointer;
+ color: @gray-light;
+ }
+
+ i:hover:before {
+ color: @menu-highlight-color;
+ }
+ }
+
+ &.minimized .minimizer {
+ border-bottom-left-radius: 4px;
+ .transition(border-bottom-left-radius 0s linear @transitionLength);
+ }
+
+ &.hidden .minimizer i:before {
+ content: '\f103';
+ }
+
+ &:not(.active) .suggestion-area, &.hidden .suggestion-area {
+ box-shadow: none;
+ }
+
+ .suggestion-area {
+ padding: .75em;
+ flex-grow: 1;
+ pointer-events: auto;
+ font-size: .75em;
+
+ background: @body-bg-color;
+ border-radius: 0 0 4px 4px;
+ box-shadow: 0 0 1em 0 rgba(0, 0, 0, 0.3);
+
+ button {
+ .link-button();
+ }
+
+ p {
+ margin-bottom: .5em;
+ color: @text-color-light;
+ }
+
+ & > button.close {
+ float: right;
+ margin-top: 1em;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+
+ ul {
+ padding: 0;
+ margin: .5em 0 0;
+ list-style-type: none;
+ }
+
+ li {
+ margin: .5em 0;
+ display: flex;
+
+ &:last-of-type {
+ margin-bottom: 0;
+ }
+ }
+
+ li {
+ :not(:last-child) {
+ margin-right: .5em;
+ }
+
+ button:hover{
+ opacity: 0.8;
+ }
+
+ button[value="1"] {
+ flex-grow: 1;
+
+ color: @text-color;
+ text-decoration: underline;
+ }
+
+ button[value="0"] {
+ i:before {
+ margin: 0;
+ content: '\e804';
+ }
+ }
+ }
+
+ form {
+ margin-top: 0.5em;
+ width: 100%;
+
+ .control-group {
+ display: flex;
+ align-items: center;
+
+ .control-label-group {
+ margin-right: .5em;
+ }
+
+ label {
+ margin-left: auto;
+ }
+ }
+ }
+ }
+}
diff --git a/public/css/widget/monitoring-health.less b/public/css/widget/monitoring-health.less
new file mode 100644
index 0000000..f0ed252
--- /dev/null
+++ b/public/css/widget/monitoring-health.less
@@ -0,0 +1,136 @@
+.monitoring-health {
+ max-width: 65em;
+
+ > section:not(:last-child) {
+ margin-bottom: 4em;
+ }
+
+ .vertical-key-value .value {
+ display: inline-block;
+ margin-bottom: .25em;
+ }
+
+ .check-summary {
+ padding: .5em 0;
+
+ .col {
+ padding: 0 1em .5em 1em;
+ }
+
+ .col:not(:last-child) {
+ border-right: 1px solid @gray-light;
+ }
+ }
+
+ .check-summary,
+ .instance-features {
+ .rounded-corners();
+ border: 1px solid;
+ border-color: @gray-light;
+ display: flex;
+ width: 100%;
+ }
+
+ .check-summary,
+ .col-content,
+ .icinga-info {
+ width: 100%;
+
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-around;
+ }
+
+
+ .icinga-info {
+ margin-bottom: -2em;
+
+ .vertical-key-value {
+ margin-bottom: 2em;
+ }
+ }
+
+ .col {
+ flex: 1 1 auto;
+ text-align: center;
+
+ > h3 {
+ margin: 0 0 1em;
+ }
+ }
+
+ .icinga-health {
+ .rounded-corners();
+ margin-bottom: 2em;
+ padding: 1em;
+ text-align: center;
+ width: 100%;
+ font-weight: bold;
+
+ &.up {
+ border: 1px solid;
+ border-color: @color-up;
+ color: @color-up;
+ }
+
+ &.down {
+ background-color: @color-down;
+ color: @body-bg-color;
+ }
+ }
+
+ .instance-features {
+ .control-group {
+ flex: 1 1 auto;
+ margin: .5em 0;
+ padding: .5em;
+ width: 0;
+
+ display: flex;
+ align-items: center;
+ flex-direction: column-reverse;
+ justify-content: flex-end;
+
+ &:not(:last-of-type) {
+ border-right: 1px solid @gray-light;
+ }
+
+ .control-label-group {
+ font-size: 10/12em;
+ margin-right: 0;
+ margin-top: 1em;
+ padding: 0;
+ text-align: center;
+ width: auto;
+
+ label {
+ text-align: center;
+ }
+ }
+
+ .toggle-switch {
+ margin: 0;
+ }
+ }
+ }
+}
+
+#layout.minimal-layout {
+ .icinga-info {
+ .vertical-key-value {
+ width: 100%;
+ }
+ }
+
+ .instance-features {
+ flex-wrap: wrap;
+
+ .control-group {
+ width: 33%;
+
+ &:nth-child(3n) {
+ border-right: none;
+ }
+ }
+ }
+}
diff --git a/public/css/widget/notice.less b/public/css/widget/notice.less
new file mode 100644
index 0000000..7067665
--- /dev/null
+++ b/public/css/widget/notice.less
@@ -0,0 +1,23 @@
+// Style
+
+.notice {
+ @margin: 1em / 1.25;
+ @padding: .75em / 1.25;
+
+ .rounded-corners();
+ padding: @padding;
+ color: @text-color-on-icinga-blue;
+ background-color: @state-warning;
+ font-weight: bold;
+ font-size: 1.25em;
+
+ // Layout
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ margin: 0 @margin @margin @margin;
+
+ > span {
+ .text-ellipsis();
+ }
+}
diff --git a/public/css/widget/object-features.less b/public/css/widget/object-features.less
new file mode 100644
index 0000000..b39414d
--- /dev/null
+++ b/public/css/widget/object-features.less
@@ -0,0 +1,53 @@
+form.object-features {
+ span.description {
+ text-align: left;
+ }
+
+ .control-label-group {
+ text-align: left;
+ margin-right: 0;
+ width: @name-value-table-name-width;
+ color: @text-color-light;
+
+ label {
+ font-size: inherit;
+ }
+ }
+
+ .control-group {
+ margin-top: 0;
+ margin-bottom: 0;
+
+ &.indeterminate {
+ justify-content: flex-start;
+
+ .control-label-group {
+ flex: 0 1 auto;
+ }
+
+ select {
+ width: auto;
+ flex: 0 1 auto;
+
+ & + span.hint {
+ flex: 0 1 auto;
+ }
+ }
+ }
+ }
+
+ .toggle-switch {
+ margin-left: @table-column-padding;
+ }
+
+ select {
+ margin-right: .5em;
+ margin-left: @table-column-padding;
+
+ & + span.hint {
+ margin: .35em;
+ color: @gray-light;
+ font-style: italic;
+ }
+ }
+}
diff --git a/public/css/widget/object-inspection.less b/public/css/widget/object-inspection.less
new file mode 100644
index 0000000..60a99bf
--- /dev/null
+++ b/public/css/widget/object-inspection.less
@@ -0,0 +1,17 @@
+// Style
+
+// Layout
+
+.inspection-detail {
+ th {
+ width: 16em;
+ }
+
+ pre, td {
+ white-space: break-spaces;
+ word-break: break-word;
+ -webkit-hyphens: auto;
+ -ms-hyphens: auto;
+ hyphens: auto;
+ }
+}
diff --git a/public/css/widget/object-meta-info.less b/public/css/widget/object-meta-info.less
new file mode 100644
index 0000000..82ad044
--- /dev/null
+++ b/public/css/widget/object-meta-info.less
@@ -0,0 +1,95 @@
+// Style
+
+.object-meta-info {
+ .vertical-key-value .value {
+ font-weight: normal;
+ }
+
+ .vertical-key-value:first-child {
+ text-align: left;
+ }
+
+ .vertical-key-value:last-child {
+ text-align: right;
+ }
+}
+
+.object-meta-info-control {
+ .link-button();
+
+ .rounded-corners(0 0 .5em .5em);
+ border: 1px solid;
+ border-color: @gray-lighter;
+ border-top-width: 0;
+ background: @body-bg-color;
+}
+
+// Layout
+
+.object-meta-info {
+ display: flex;
+ justify-content: space-between;
+
+ .horizontal-key-value {
+ padding: 0;
+
+ .key {
+ width: 9em;
+ }
+ }
+
+ .vertical-key-value {
+ &:first-child {
+ .text-ellipsis();
+ margin-right: 1em;
+ }
+
+ &:last-child {
+ white-space: nowrap;
+ margin-left: 1em;
+ }
+ }
+
+ .horizontal-key-value .value,
+ .horizontal-key-value .key,
+ .vertical-key-value .value,
+ .vertical-key-value .key {
+ font-size: 16/18em;
+ line-height: 18/16; // compensate smaller font-size (1/font-size)
+ }
+}
+
+.object-meta-info-control {
+ position: absolute;
+ right: 2.25em;
+ bottom: -2.5em; // height + margin-bottom
+ height: 2em;
+ padding: .25em;
+
+ .collapse-icon,
+ .expand-icon {
+ font-size: 1.2em;
+
+ &:before {
+ margin-right: 0;
+ }
+ }
+
+ .collapse-icon {
+ display: block;
+ }
+
+ .expand-icon {
+ display: none;
+ }
+}
+
+.collapsed + .object-meta-info-control {
+ .collapse-icon {
+ display: none;
+ }
+
+ .expand-icon {
+ display: block;
+ }
+}
diff --git a/public/css/widget/object-statistics.less b/public/css/widget/object-statistics.less
new file mode 100644
index 0000000..5a9c97a
--- /dev/null
+++ b/public/css/widget/object-statistics.less
@@ -0,0 +1,44 @@
+ul.object-statistics {
+ // Reset defaults
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+
+ display: flex;
+ align-items: center;
+
+ > li:not(:last-child) {
+ margin-right: 1em;
+ }
+}
+
+.object-statistics-graph .donut-graph {
+ height: 2em;
+ width: 2em;
+ vertical-align: middle;
+}
+
+.object-statistics-total a {
+ display: inline-block;
+ line-height: 1;
+ position: relative;
+
+ &:hover:before {
+ .rounded-corners();
+ background-color: @gray-lighter;
+ content: "";
+ display: block;
+ z-index: 1;
+
+ position: absolute;
+ bottom: -.4em;
+ left: -.4em;
+ top: -.4em;
+ right: -.4em;
+ }
+
+ .vertical-key-value {
+ position: relative;
+ z-index: 2;
+ }
+}
diff --git a/public/css/widget/performance-data-table.less b/public/css/widget/performance-data-table.less
new file mode 100644
index 0000000..a1a7b6e
--- /dev/null
+++ b/public/css/widget/performance-data-table.less
@@ -0,0 +1,57 @@
+/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */
+
+.performance-data-table {
+ width: 100%;
+ overflow-x: auto;
+ display: block;
+
+ tr:not(:last-child) {
+ border-bottom: 1px solid @gray-lighter;
+ }
+
+ td {
+ text-align: right;
+ .text-ellipsis();
+ }
+
+ th {
+ font-size: .857em;
+ font-weight: normal;
+ text-transform: uppercase;
+ letter-spacing: .05em;
+ }
+
+ thead {
+ border-bottom: 1px solid @gray-light;
+ }
+
+ th:first-child,
+ td:first-child {
+ padding-left: 0;
+ }
+
+ .title {
+ text-align: left;
+ width: 100%;
+ }
+
+ td.title {
+ font-weight: bold;
+ }
+
+ .sparkline-col {
+ min-width: 1.75em;
+ width: 1.75em;
+ padding: 2/12em 0;
+ }
+
+ .inline-pie > svg {
+ vertical-align: middle;
+ }
+
+ .no-value {
+ color: @gray-semilight;
+ text-align: center;
+ display: block;
+ }
+}
diff --git a/public/css/widget/quick-actions.less b/public/css/widget/quick-actions.less
new file mode 100644
index 0000000..bddea43
--- /dev/null
+++ b/public/css/widget/quick-actions.less
@@ -0,0 +1,47 @@
+.quick-actions {
+ display: flex;
+ flex-wrap: wrap;
+ list-style-type: none;
+ margin: 0 -.5em;
+ padding: 0;
+
+ a {
+ text-decoration: none;
+ }
+
+ a,
+ button {
+ padding: .25em;
+ .rounded-corners();
+ display: inline-flex;
+ align-items: baseline;
+
+ &:hover {
+ background: @gray-lighter;
+ }
+ }
+
+ li {
+ margin: 0 .25em .5em .25em;
+ vertical-align: middle;
+ white-space: nowrap;
+ }
+}
+
+.controls:not(.default-layout) > .quick-actions:last-child,
+.controls > .quick-actions:last-child {
+ margin-bottom: 0;
+}
+
+#layout.twocols:not(.wide-layout) {
+ .quick-actions {
+ justify-content: space-between;
+ min-width: 100%;
+ }
+}
+
+#layout.wide-layout .controls {
+ .quick-actions {
+ float: left;
+ }
+}
diff --git a/public/css/widget/service-state-badges.less b/public/css/widget/service-state-badges.less
new file mode 100644
index 0000000..8a97faa
--- /dev/null
+++ b/public/css/widget/service-state-badges.less
@@ -0,0 +1,3 @@
+.service-state-badges {
+ .state-badges();
+}
diff --git a/public/css/widget/state-badge.less b/public/css/widget/state-badge.less
new file mode 100644
index 0000000..2f81c1e
--- /dev/null
+++ b/public/css/widget/state-badge.less
@@ -0,0 +1,47 @@
+.state-badge {
+ .rounded-corners();
+ color: @text-color-on-icinga-blue;
+ display: inline-block;
+ font-size: 1em;
+ min-width: 2em;
+ padding: .25em;
+ text-align: center;
+
+ &.handled {
+ opacity: .8;
+ }
+
+ &.state-critical {
+ background-color: @color-critical;
+ }
+
+ &.state-down {
+ background-color: @color-down;
+ }
+
+ &.state-ok {
+ background-color: @color-ok;
+ }
+
+ &.state-pending {
+ background-color: @color-pending;
+ }
+
+ &.state-unknown {
+ background-color: @color-unknown;
+ }
+
+ &.state-up {
+ background-color: @color-up;
+ }
+
+ &.state-warning {
+ background-color: @color-warning;
+ }
+}
+
+a .state-badge {
+ &:not(.disabled):hover {
+ filter: brightness(80%);
+ }
+}
diff --git a/public/css/widget/state-change.less b/public/css/widget/state-change.less
new file mode 100644
index 0000000..adc8d42
--- /dev/null
+++ b/public/css/widget/state-change.less
@@ -0,0 +1,128 @@
+.state-change {
+ display: inline-flex;
+
+ &.reversed-state-balls {
+ // This is needed, because with ~ we can address only subsequent nodes
+ flex-direction: row-reverse;
+ }
+
+ .state-ball {
+ .box-shadow(0, 0, 0, 1px, @body-bg-color);
+ }
+
+ // Same on same
+ .state-ball ~ .state-ball {
+ &.ball-size-xs {
+ margin-left: -.05em;
+ }
+
+ &.ball-size-s {
+ margin-left: -.15em;
+ }
+
+ &.ball-size-m {
+ margin-left: -.275em;
+ }
+
+ &.ball-size-ml {
+ margin-left: -.375em;
+ }
+
+ &.ball-size-l,
+ &.ball-size-xl {
+ margin-left: -.875em;
+ }
+ }
+
+ // big left, smaller right
+ &:not(.reversed-state-balls) .ball-size-l ~ .state-ball {
+ &.ball-size-ml {
+ margin-top: .25em;
+ margin-left: -.5em;
+ margin-right: .25em;
+ }
+ }
+
+ // smaller left, big right
+ &.reversed-state-balls .ball-size-l ~ .state-ball {
+ &.ball-size-ml {
+ z-index: -1;
+ margin-top: .25em;
+ margin-right: -.5em;
+ }
+ }
+
+ .state-ball.state-ok,
+ .state-ball.state-up,
+ .state-pending {
+ &.ball-size-l,
+ &.ball-size-xl {
+ background-color: @body-bg-color;
+ }
+ }
+
+ // Avoid transparency on overlapping solid state-change state-balls
+ .state-ball.handled {
+ position: relative;
+ opacity: 1;
+
+ i {
+ position: relative;
+ z-index: 3;
+ }
+
+ &:before {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ border-radius: 50%;
+ opacity: .6;
+ z-index: 2
+ }
+
+ &:after {
+ content: "";
+ display: block;
+ position: absolute;
+ top: -2px;
+ left: -2px;
+ right: -2px;
+ bottom: -2px;
+ border-radius: 50%;
+ background-color: @body-bg-color;
+ z-index: 1;
+ }
+
+ &.state-pending:before {
+ background-color: @color-pending;
+ }
+
+ &.state-down:before {
+ background-color: @color-down;
+ }
+
+ &.state-warning:before {
+ background-color: @color-warning;
+ }
+
+ &.state-critical:before {
+ background-color: @color-critical;
+ }
+
+ &.state-unknown:before {
+ background-color: @color-unknown;
+ }
+ }
+}
+
+.overdue .state-change .state-ball {
+ .box-shadow(0, 0, 0, 1px, @gray-lighter);
+
+ &.handled:after {
+ background-color: @gray-lighter;
+ }
+}
diff --git a/public/css/widget/tag-list.less b/public/css/widget/tag-list.less
new file mode 100644
index 0000000..fe96691
--- /dev/null
+++ b/public/css/widget/tag-list.less
@@ -0,0 +1,31 @@
+.tag-list {
+ line-height: 1.5;
+ list-style-type: none;
+ margin: -.25em 0 0 0; // TODO: This is wrong here, if at all this must be part of wherever this widget is placed
+ padding: 0;
+
+ > li {
+ display: inline-block;
+
+ &:not(:last-child) {
+ margin-right: .417em;
+ margin-bottom: .25em; // TODO: Really? It's an inline ul, bottom margin is outer layout..
+ }
+
+ i {
+ opacity: 0.8;
+ }
+ }
+
+ > li > a {
+ .rounded-corners();
+ background-color: @gray-lighter;
+ display: block;
+ padding: .25em .5em;
+
+ &:hover {
+ background-color: @gray-light;
+ text-decoration: none;
+ }
+ }
+}
diff --git a/public/css/widget/view-mode-switcher.less b/public/css/widget/view-mode-switcher.less
new file mode 100644
index 0000000..7eda2a8
--- /dev/null
+++ b/public/css/widget/view-mode-switcher.less
@@ -0,0 +1,45 @@
+.view-mode-switcher {
+ list-style-type: none;
+ margin: 0 0 0.25em 0;
+ padding: 0;
+ display: flex;
+
+ input {
+ display: none;
+ }
+
+ label {
+ color: @control-color;
+ line-height: 1;
+ background: @low-sat-blue;
+ padding: 14/16*.25em 14/16*.5em;
+ font-size: 16/12em;
+ height: 24/16em; // desired pixel height / font-size
+ cursor: pointer;
+
+ &:first-of-type {
+ border-top-left-radius: 0.25em;
+ border-bottom-left-radius: 0.25em;
+ }
+
+ &:last-of-type {
+ border-top-right-radius: 0.25em;
+ border-bottom-right-radius: 0.25em;
+ }
+
+ &:not(:last-of-type) {
+ border-right: 1px solid @low-sat-blue-dark;
+ }
+
+ i {
+ // fix height for Chrome
+ display: block;
+ }
+ }
+
+ input[checked] + label {
+ background-color: @control-color;
+ color: @text-color-on-icinga-blue;
+ cursor: default;
+ }
+}