summaryrefslogtreecommitdiffstats
path: root/public
diff options
context:
space:
mode:
Diffstat (limited to 'public')
-rw-r--r--public/css/module.less213
-rw-r--r--public/js/module.js112
2 files changed, 325 insertions, 0 deletions
diff --git a/public/css/module.less b/public/css/module.less
new file mode 100644
index 0000000..bb651e7
--- /dev/null
+++ b/public/css/module.less
@@ -0,0 +1,213 @@
+div.images {
+ h3 {
+ clear: both;
+ }
+
+ img.svg {
+ float: left;
+ border: none;
+ }
+
+}
+
+div.images.object-detail-view {
+ display: block;
+
+ img.graphiteImg {
+ width: 100%;
+ display: block;
+ }
+}
+
+.timerangepicker-container {
+ display: flex;
+ padding: .25em 0;
+
+ .button-link {
+ line-height: 1.75;
+ width: 2.25em;
+
+ i {
+ display: inline-block;
+ width: 100%;
+ text-align: center;
+ }
+
+ i:before {
+ margin-right: 0;
+ }
+ }
+}
+
+form[name=form_timerangepickercommon_graphite] {
+ display: inline-flex;
+ flex: 1 1 auto;
+ width: 0;
+ max-width: 43.25em;
+
+ &:not(:last-child) {
+ margin-right: .25em;
+ }
+
+ select {
+ min-width: 3.5em;
+ max-width: 7em;
+ flex: 1 1 auto;
+ width: auto;
+
+ &:not(:last-of-type) {
+ margin-right: .25em;
+ }
+ }
+}
+
+form[name=form_timerangepickercustom_graphite] {
+ min-width: 21em;
+
+ .control-label-group {
+ text-align: left;
+ }
+
+ input[type=date] {
+ min-width: 11em;
+ }
+
+ input[type=time] {
+ min-width: 5em;
+ }
+}
+
+.flyover[id^="graphite-customrange-"] {
+ display: inline-block;
+}
+
+.grid {
+ margin-right: -1em;
+ margin-bottom: -1em;
+
+ .empty-state {
+ .rounded-corners();
+ background-color: @gray-lightest;
+ margin-right: 1em;
+ padding: 1em;
+ text-align: center;
+ }
+}
+
+.grid-item {
+ display: inline-block;
+ border-radius: .25em;
+ border: 1px solid @gray-lighter;
+ min-width: 302px;
+ vertical-align: top;
+ margin-right: 1em;
+ margin-bottom: 1em;
+}
+
+.grid-item h2 {
+ margin-top: 0;
+ background: @gray-lightest;
+ border-bottom: 1px solid @gray-lighter;
+ padding:.25em .5em;
+ max-width: 100%;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.grid-item > .images:not(:last-child) {
+ margin-right: 1em;
+ display: inline-block;
+}
+
+.grid-item .graphiteImg {
+ margin-right: 1px;
+}
+
+.grid-item > p {
+ padding: .5em;
+ margin-bottom: 0;
+}
+
+p.load-more {
+ margin-right: 1em;
+ text-align: right;
+}
+
+// TODO: Remove once ipl-web v0.7.0 is required
+.controls:not(.default-layout) {
+ .box-shadow(0, 0, 0, 1px, @gray-lighter);
+
+ .pagination-control {
+ float: left;
+ }
+
+ .sort-control,
+ .limit-control {
+ float: right;
+ margin-left: .5em;
+ }
+
+ .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,
+ .filter {
+ 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;
+ }
+ }
+ }
+}
+
+/* Graph colors */
+
+@graphite-graph-bg-color: @body-bg-color;
+@graphite-graph-fg-color: @text-color;
+@graphite-graph-major-grid-color: @gray-light;
+@graphite-graph-minor-grid-color: @graphite-graph-bg-color;
+
+@light-mode: {
+ --graphite-graph-bg-color: var(--body-bg-color);
+ --graphite-graph-fg-color: var(--text-color);
+ --graphite-graph-major-grid-color: var(--gray-light);
+ --graphite-graph-minor-grid-color: var(--graphite-graph-bg-color);
+};
+
+.graphite-graph-color-registry {
+ display: none;
+
+ background-color: @graphite-graph-bg-color;
+ color: @graphite-graph-fg-color;
+ border-top-color: @graphite-graph-major-grid-color;
+ border-bottom-color: @graphite-graph-minor-grid-color;
+}
diff --git a/public/js/module.js b/public/js/module.js
new file mode 100644
index 0000000..a2a32f2
--- /dev/null
+++ b/public/js/module.js
@@ -0,0 +1,112 @@
+/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
+
+(function(Icinga) {
+
+ "use strict";
+
+ class Graphite extends Icinga.EventListener {
+ constructor(icinga) {
+ super(icinga);
+
+ this._colorParams = null;
+ this._resizeTimer = null;
+ this._onResizeBound = this.onResize.bind(this);
+ this._onModeChangeBound = this.onModeChange.bind(this);
+ this._mediaQueryList = window.matchMedia('(prefers-color-scheme: light)');
+
+ this.on('css-reloaded', 'head', this.onCssReloaded, this);
+ this.on('rendered', '#main > .container', this.onRendered, this);
+ window.addEventListener('resize', this._onResizeBound, { passive: true });
+ this._mediaQueryList.addEventListener('change', this._onModeChangeBound, { passive: true });
+ }
+
+ get colorParams() {
+ if (this._colorParams === null) {
+ let colorRegistry = document.querySelector('.graphite-graph-color-registry');
+ let registryStyle = window.getComputedStyle(colorRegistry);
+
+ this._colorParams = {
+ bgcolor: this.rgbToHex(registryStyle.backgroundColor, 'black'),
+ fgcolor: this.rgbToHex(registryStyle.color, 'white'),
+ majorGridLineColor: this.rgbToHex(registryStyle.borderTopColor, '0000003F'),
+ minorGridLineColor: this.rgbToHex(registryStyle.borderBottomColor, 'black')
+ };
+ }
+
+ return this._colorParams;
+ }
+
+ unbind(emitter) {
+ super.unbind(emitter);
+
+ window.removeEventListener('resize', this._onResizeBound);
+ this._mediaQueryList.removeEventListener('change', this._onModeChangeBound);
+
+ this._onResizeBound = null;
+ this._onModeChangeBound = null;
+ this._mediaQueryList = null;
+ }
+
+ onCssReloaded(event) {
+ let _this = event.data.self;
+
+ _this._colorParams = null;
+ _this.updateImages(document);
+ }
+
+ onRendered(event, autorefresh, scripted, autosubmit) {
+ let _this = event.data.self;
+ let container = event.target;
+
+ _this.updateImages(container);
+ }
+
+ onResize() {
+ // Images are not updated instantly, the user might not yet be finished resizing the window
+ if (this._resizeTimer !== null) {
+ clearTimeout(this._resizeTimer);
+ }
+
+ this._resizeTimer = setTimeout(() => this.updateImages(document), 200);
+ }
+
+ onModeChange() {
+ this._colorParams = null;
+ this.updateImages(document);
+ }
+
+ updateImages(container) {
+ container.querySelectorAll('img.graphiteImg[data-actualimageurl]').forEach(img => {
+ let params = { ...this.colorParams }; // Theming ftw!
+ params.r = (new Date()).getTime(); // To bypass the browser cache
+ params.width = img.scrollWidth; // It's either fixed or dependent on parent width
+
+ img.src = this.icinga.utils.addUrlParams(img.dataset.actualimageurl, params);
+ });
+ }
+
+ rgbToHex(rgb, def) {
+ if (! rgb) {
+ return def;
+ }
+
+ let match = rgb.match(/rgba?\((\d+), (\d+), (\d+)(?:, ([\d.]+))?\)/);
+ if (match === null) {
+ return def;
+ }
+
+ let alpha = '';
+ if (typeof match[4] !== 'undefined') {
+ alpha = Math.round(parseFloat(match[4]) * 255).toString(16);
+ }
+
+ return parseInt(match[1], 10).toString(16).padStart(2, '0')
+ + parseInt(match[2], 10).toString(16).padStart(2, '0')
+ + parseInt(match[3], 10).toString(16).padStart(2, '0')
+ + alpha;
+ }
+ }
+
+ Icinga.Behaviors.Graphite = Graphite;
+
+})(Icinga);