/* +-------------------------------------------------------------------------+ | Copyright (C) 2004-2025 The Cacti Group | | | | This program is free software; you can redistribute it and/or | | modify it under the terms of the GNU General Public License | | as published by the Free Software Foundation; either version 2 | | of the License, or (at your option) any later version. | | | | This program is distributed in the hope that it will be useful, | | but WITHOUT ANY WARRANTY; without even the implied warranty of | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | GNU General Public License for more details. | +-------------------------------------------------------------------------+ | Cacti: The Complete RRDtool-based Graphing Solution | +-------------------------------------------------------------------------+ | This code is designed, written, and maintained by the Cacti Group. See | | about.php and/or the AUTHORS file for specific developer information. | +-------------------------------------------------------------------------+ | http://www.cacti.net/ | +-------------------------------------------------------------------------+ */ /* main container magic */ .monitor_container { display: flex; flex-wrap: wrap; align-content: space-between; justify-content: space-between; } /* When the server sets --monitor-title-ch (the longest trimmed description in view), widen every tile title to it so long hostnames wrap within their own tile instead of blending into neighbours. inline-block keeps the title centred under the glyph (via the frame's text-align) in every view, and max-width stops it overflowing a fixed-width tile. */ .monitor_container[style*='--monitor-title-ch'] [class$='_title'] { display: inline-block; width: calc(var(--monitor-title-ch, 11) * 1ch + 8px) !important; max-width: 100%; box-sizing: border-box; vertical-align: top; } .monitor_sub_container { display: flex; flex-wrap: wrap; align-content: space-between; justify-content: space-between; } /* flex box table */ .monitorTableHeader { width: 100%; } .monitorTable { line-height: 16px; color: rgb(68, 68, 68); } .monitorSubTable { min-width: 10vw; max-width: 100vw; padding: 3px; flex-grow: 4; } /* footer section */ .monitorFooter { display: table; width: 100%; } .monitorFooterText { color: gray; } .monitorFooterTextBold { color: black; } .monitorLinkIcon { vertical-align: middle; padding: 3px; font-size: 20px; } .monitor_device_frame { text-align: center; display: inline-block; } .monitor_device_frame a { padding: 3px 3px 8px; display: block; } /* Uptime/time-in-state line under a tile hostname: normal weight (not bold), pulled up tight to the hostname, with the frame padding below separating rows. */ .monitor_uptime { display: block; font-weight: normal; line-height: 1.1; margin-top: -2px; } /* * Status legend. Rendered as a wrapping CSS grid whose columns share one width * (seeded from the longest label via --monitor-chip-min) so every chip is equal * width across all rows, as rounded chips with spacing between them. * A legend is a colour key, so the chips use their own solid, opaque colours * with white text to stay legible on every theme rather than inheriting the * subtle tile tints. Per-theme tuning lives in each theme's css (see * deepness.css for the emerald-accented variant). */ .monitorLegend { display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--monitor-chip-min, 8ch), 1fr)); gap: 4px; width: 100%; margin-top: 4px; } /* Legend footer: keeps the legend centered beneath the device list in normal document flow, so it never overlays the final rows or action controls. */ .monitorLegendFooter { display: table; width: 100%; margin: 8px auto 0; } .monitorLegend .monitorLegendItem { box-sizing: border-box; width: 100%; min-width: 0; text-align: center; white-space: nowrap; padding: 4px 6px; border-radius: 3px; color: #ffffff; } .monitorLegend .deviceUpFull { background-color: #2b8235; } .monitorLegend .deviceDownFull { background-color: #a12820; } .monitorLegend .deviceDownMutedFull { background-color: #93302a; } .monitorLegend .deviceRecoveringFull { background-color: #9a6a1a; } .monitorLegend .deviceThresholdFull { background-color: #a85712; } .monitorLegend .deviceThresholdMutedFull { background-color: #6a4a9c; } .monitorLegend .deviceWarningFull { background-color: #7d6f18; } .monitorLegend .deviceAlertFull { background-color: #86407a; } .monitorLegend .deviceUnknownFull { background-color: #5f5f57; } .monitorLegend .deviceUnmonitoredFull { background-color: #3f6a8a; } .monitorLegend .deviceServiceCheckFull { background-color: #157f87; } /* Device status icons share the legend's solid palette so a tile's colour matches its legend key. Core themes set .deviceXxx colours with !important, so these need it too. */ .mon_icon.deviceUp { color: #2b8235 !important; } .mon_icon.deviceDown { color: #a12820 !important; } .mon_icon.deviceDownMuted { color: #93302a !important; } .mon_icon.deviceRecovering { color: #9a6a1a !important; } .mon_icon.deviceThreshold { color: #a85712 !important; } .mon_icon.deviceThresholdMuted { color: #6a4a9c !important; } .mon_icon.deviceWarning { color: #7d6f18 !important; } .mon_icon.deviceAlert { color: #86407a !important; } .mon_icon.deviceUnknown { color: #5f5f57 !important; } .mon_icon.deviceUnmonitored { color: #3f6a8a !important; } .mon_icon.deviceServiceCheck { color: #157f87 !important; } /* List-view status pill: adopts the Cacti deviceStatus pill shape and uses the same solid palette as the legend chips (colour the pill, not the row). */ .monitorStatus { display: inline-block; padding: 2px 10px; border-radius: 10px; color: #ffffff; white-space: nowrap; } .monitorStatus.deviceUp { background-color: #2b8235; } .monitorStatus.deviceDown { background-color: #a12820; } .monitorStatus.deviceDownMuted { background-color: #93302a; } .monitorStatus.deviceRecovering { background-color: #9a6a1a; } .monitorStatus.deviceThreshold { background-color: #a85712; } .monitorStatus.deviceThresholdMuted { background-color: #6a4a9c; } .monitorStatus.deviceWarning { background-color: #7d6f18; } .monitorStatus.deviceAlert { background-color: #86407a; } .monitorStatus.deviceUnknown { background-color: #5f5f57; } .monitorStatus.deviceUnmonitored { background-color: #3f6a8a; } .monitorStatus.deviceServiceCheck { background-color: #157f87; } /* Clickable list-view pills (events, thresholds, service checks, criticality). Share the status palette for event pills and a graduated, deliberately non-alarming palette for criticality (no red for Mission Critical). */ .monitorPill { display: inline-block; padding: 2px 8px; border-radius: 10px; color: #ffffff; white-space: nowrap; font-size: 11px; line-height: 1.5; margin: 1px; } .monitorFilterPill { cursor: pointer; } .monitorPillMuted { background-color: #5f5f57; } .monitorPill.deviceDown { background-color: #a12820; } .monitorPill.deviceDownMuted { background-color: #93302a; } .monitorPill.deviceRecovering { background-color: #9a6a1a; } .monitorPill.deviceWarning { background-color: #7d6f18; } .monitorPill.deviceAlert { background-color: #86407a; } .monitorPill.deviceThreshold { background-color: #a85712; } .monitorPill.deviceThresholdMuted { background-color: #6a4a9c; } .monitorPill.deviceServiceCheck { background-color: #157f87; } /* Criticality: Not Set (grey) -> Low (blue) -> Medium (teal) -> High (amber) -> Mission Critical (violet). */ .monitorCrit0 { background-color: #5f5f57; } .monitorCrit1 { background-color: #3f6a8a; } .monitorCrit2 { background-color: #157f87; } .monitorCrit3 { background-color: #a85712; } .monitorCrit4 { background-color: #6a4a9c; } /* extra small styles */ .monitor_exsmall { height: 55px; width: 35px; } .monitor_exsmall_title { display: table-cell; text-align: center; width: 90px !important; word-wrap: break-word; overflow: hidden; } .monitor_exsmall_tiles { height: 20px; min-width: 20px; } .monitor_exsmall_tilesadt { min-height: 35px; width: 94px; box-sizing: border-box; } .monitor_exsmall td { font-size: 12px; } .monitor_exsmall .monitorLinkIcon { font-size: 20px; } .monitor_exsmall i, .monitor_exsmall_tiles i, .monitor_exsmall_tilesadt i { font-size: 10px; } .monitor_device_exsmall { font-size: 10px; padding: 2px; } /* small styles */ .monitor_small { height: 58px; min-width: 28px; } .monitor_small_title { display: table-cell; text-align: center; width: 90px !important; word-wrap: break-word; overflow: hidden; } .monitor_small_tiles { height: 28px; min-width: 28px; } .monitor_small_tilesadt { min-height: 45px; width: 94px; box-sizing: border-box; } .monitor_small i, .monitor_small_tiles i, .monitor_small_tilesadt i { font-size: 20px; min-width: 28px; } .monitor_small .monitorLinkIcon { font-size: 20px; } .monitor_small td { font-size: 12px; } .monitor_device_small { font-size: 10px; padding: 2px; min-width: 28px; } /* medium styles */ .monitor_medium { height: 78px; min-width: 58px; } .monitor_medium_title { display: table-cell; text-align: center; width: 100px !important; word-wrap: break-word; overflow: hidden; } .monitor_medium_tiles { height: 48px; min-width: 58px; } .monitor_medium_tilesadt { min-height: 65px; width: 108px; box-sizing: border-box; } .monitor_medium i, .monitor_medium_tiles i, .monitor_medium_tilesadt i { font-size: 40px; min-width: 58px; } .monitor_medium td { font-size: 13px; } .monitor_medium a, .monitor_medium_tiles a, .monitor_medium_tilesadt a { font-size: 13px; min-width: 58px; } .monitor_medium .monitorLinkIcon { font-size: 20px; } .monitor_medium .monitorLinkIcon { font-size: 20px; } .monitor_device_medium { font-size: 13px; min-width: 58px; padding: 2px; } /* large styles */ .monitor_large { height: 118px; width: 128px !important; } .monitor_large_title { display: table-cell; text-align: center; width: 128px !important; word-wrap: break-word; overflow: hidden; } .monitor_large_tiles { height: 88px; min-width: 88px; } .monitor_large_tilesadt { min-height: 102px; width: 128px; box-sizing: border-box; justify-content: center; } .monitor_large i, .monitor_large_tiles i, .monitor_large_tilesadt i { font-size: 80px; min-width: 98px; } .monitor_large td { font-size: 15px; } .monitor_large a, .monitor_large_tiles a, .monitor_large_tilesadt a { font-size: 15px; min-width: 98px; } .monitor_large .monitorLinkIcon { font-size: 28px; } .monitor_device_large { font-size: 10px; padding: 2px; min-width: 148px; } /* ex-large styles */ .monitor_exlarge { height: 168px; min-width: 128px; } .monitor_exlarge_title { display: table-cell; text-align: center; width: 128px !important; word-wrap: break-word; overflow: hidden; } .monitor_exlarge_tiles { height: 128px; min-width: 128px; } .monitor_exlarge_tilesadt { min-height: 148px; width: 128px; box-sizing: border-box; } .monitor_exlarge i, .monitor_exlarge_tiles i, .monitor_exlarge_tilesadt i { font-size: 120px; min-width: 128px; } .monitor_exlarge td { font-size: 16px; } .monitor_exlarge, .monitor_exlarge .monitorLinkIcon { font-size: 16px; } .monitor_exlarge .monitorLinkIcon { font-size: 38px; } .monitor_exlarge a, .monitor_exlarge_tiles a, .monitor_exlarge_tilesadt a { font-size: 16px; min-width: 128px; } .monitor_device_exlarge { font-size: 10px; padding: 2px; } /* zoom error styles */ .monitor_errorzoom { height: 118px; width: 200px !important; } .monitor_errorzoom_title { text-align: center; word-wrap: break-word; overflow: hidden; line-height: 1.5; } .monitor_errorzoom_tiles { height: 88px; min-width: 88px; } .monitor_errorzoom_tilesadt { min-height: 102px; width: 128px; box-sizing: border-box; justify-content: center; } .monitor_errorzoom i, .monitor_errorzoom_tiles i, .monitor_errorzoom_tilesadt i { font-size: 80px; min-width: 98px; } .monitor_errorzoom td { font-size: 15px; } .monitor_errorzoom a, .monitor_errorzoom_tiles a, .monitor_errorzoom_tilesadt a { font-size: 15px; min-width: 98px; } .monitor_errorzoom .monitorLinkIcon { font-size: 28px; } .monitor_device_errorzoom { font-size: 10px; padding: 2px; min-width: 148px; } .monitorHover { min-width: 400px; max-width: 1000px; } .monitorHover td:first-child { padding-right: 5px; vertical-align: text-top; white-space: nowrap; } .monitorFilterTable { display: table; margin-left: auto; margin-right: auto; width: 50%; } .monitorFilterRow { display: table-row; margin: auto; width: 100%; } .monitorFilterCell { display: table-cell; } .monitorFilterCell .ui-button, .monitorFilterCell button { margin: 2px ! important; } .monitorFilterCell .ui-selectmenu-button, .monitorFilterCell select { min-width: 150px ! important; max-width: 150px ! important; margin: 2px ! important; } .monitorFilterForm { padding-bottom: 2px; width: 100%; } .monitorFilterText { padding-left: 5px; padding-right: 5px; } .cactiPageBottom { z-index: -1; } /* List-view Actions column icon */ .monitorActions { font-size: 16px; } .monitorActions + .monitorActions { margin-left: 8px; } /* Graphs action glyph (orange), matching the convention used by HMIB. */ .monitorGraph { color: #cc6600; } /* Device detail panels (intropage-style cards) in the Actions dialog */ .monitorPanels { /* Plain block stacking (not flex) so a card can never collapse to its min-content width inside the jQuery UI dialog content box. */ display: block; width: 100%; box-sizing: border-box; } /* Don't override the content box's overflow: the dialog sizes to its content (height: auto in openHostPanel), so forcing overflow here created a scroll box that fought the theme's own .ui-dialog .ui-dialog-content rules and squashed the panels. Keep border-box only so padding can't overflow. */ #monitorPanelDialog.ui-dialog-content, #monitorPanelDialog { box-sizing: border-box; } .monitorPanel { display: block; width: 100%; box-sizing: border-box; margin-bottom: 10px; border: 1px solid rgba(128, 128, 128, 0.35); border-radius: 6px; overflow: hidden; } .monitorPanel:last-child { margin-bottom: 0; } .monitorPanelHeader { background-color: rgba(128, 128, 128, 0.15); padding: 6px 10px; font-weight: bold; } .monitorPanelHeader i { margin-right: 6px; } .monitorPanelBody { padding: 6px 10px; } .monitorPanelProps, .monitorPanelLinks, .monitorPanelSyslog { list-style: none; margin: 0; padding: 0; } .monitorPanelProps li { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 3px 0; border-bottom: 1px dotted rgba(128, 128, 128, 0.2); } .monitorPanelProps li:last-child { border-bottom: none; } .monitorPanelLabel { color: gray; white-space: nowrap; } .monitorPanelValue { text-align: right; word-break: break-word; } .monitorPanelLinks li { padding: 3px 0; } .monitorPanelLinks i { width: 18px; text-align: center; margin-right: 4px; } .monitorPanelSyslog li { display: flex; gap: 8px; padding: 2px 0; font-size: 12px; border-bottom: 1px dotted rgba(128, 128, 128, 0.2); } .monitorPanelSyslog li:last-child { border-bottom: none; } .monitorSyslogTime { color: gray; white-space: nowrap; } .monitorSyslogMsg { word-break: break-word; } .monitorPanelLoading { padding: 20px; text-align: center; color: gray; } /* Grouping card grid: a wrapping flexbox so cards always stretch to fill the full horizontal space. A CSS grid was tried first, but Cacti renders this content inside a shrink-to-fit `display:table` box (html_start_box with $div=true), which breaks grid auto-fill track counting and clipped the cards to roughly half the page. Flexbox grows each card to fill its row regardless of that containing block. */ .monitorGroupGrid { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-start; width: 100%; } .monitorGroupCard { flex: 1 1 260px; min-width: 260px; box-sizing: border-box; } /* A busier group (span 2) gets a wider basis and matching flex-grow so it takes proportionally more room when sharing a row with smaller cards. The busiest groups (span 3-4) take a full row of their own so their many tiles flow the whole page width instead of being squeezed beside smaller cards. */ .monitorGroupCard[data-span="2"] { flex-grow: 2; flex-basis: 530px; } .monitorGroupCard[data-span="3"], .monitorGroupCard[data-span="4"] { flex-basis: 100%; } .monitorGroupCard .monitorPanelBody { padding: 6px; } .monitorGroupCard .monitor_container { justify-content: flex-start; } .monitorGroupDrag { cursor: move; margin-right: 6px; opacity: 0.65; } .monitorGroupPlaceholder { border: 2px dashed rgba(128, 128, 128, 0.5); border-radius: 6px; min-height: 60px; } /* Group card titles coloured by the group's worst device status. Marked !important so the Cacti core device-status classes (e.g. .deviceDown, which force a red text/background) cannot override the title's palette and leave unreadable low-contrast text on the coloured header. */ .monitorGroupTitle.deviceUp { background-color: #2b8235 !important; color: #ffffff !important; } .monitorGroupTitle.deviceDown { background-color: #a12820 !important; color: #ffffff !important; } .monitorGroupTitle.deviceDownMuted { background-color: #93302a !important; color: #ffffff !important; } .monitorGroupTitle.deviceRecovering { background-color: #9a6a1a !important; color: #ffffff !important; } .monitorGroupTitle.deviceThreshold { background-color: #a85712 !important; color: #ffffff !important; } .monitorGroupTitle.deviceThresholdMuted { background-color: #6a4a9c !important; color: #ffffff !important; } .monitorGroupTitle.deviceWarning { background-color: #7d6f18 !important; color: #ffffff !important; } .monitorGroupTitle.deviceAlert { background-color: #86407a !important; color: #ffffff !important; } .monitorGroupTitle.deviceUnknown { background-color: #5f5f57 !important; color: #ffffff !important; } .monitorGroupTitle.deviceUnmonitored { background-color: #3f6a8a !important; color: #ffffff !important; } .monitorGroupTitle.deviceServiceCheck { background-color: #157f87 !important; color: #ffffff !important; }