From patchwork Thu Apr 1 13:35:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leo-Andres Hofmann X-Patchwork-Id: 4014 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) client-signature ECDSA (P-384)) (Client CN "mail01.haj.ipfire.org", Issuer "R3" (verified OK)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4FB41x71Bsz3x1r for ; Thu, 1 Apr 2021 13:35:33 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [172.28.1.201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) client-signature ECDSA (P-384)) (Client CN "mail02.haj.ipfire.org", Issuer "R3" (verified OK)) by mail01.ipfire.org (Postfix) with ESMTPS id 4FB41v5q99z25t; Thu, 1 Apr 2021 13:35:31 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [127.0.0.1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4FB41v3l5zz2ySW; Thu, 1 Apr 2021 13:35:31 +0000 (UTC) Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) client-signature ECDSA (P-384)) (Client CN "mail01.haj.ipfire.org", Issuer "R3" (verified OK)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4FB41t0Fljz2xfL for ; Thu, 1 Apr 2021 13:35:30 +0000 (UTC) Received: from arche.uberspace.de (arche.uberspace.de [185.26.156.147]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mail01.ipfire.org (Postfix) with ESMTPS id 4FB41s2Y2Hz1FW for ; Thu, 1 Apr 2021 13:35:29 +0000 (UTC) Received: (qmail 10544 invoked from network); 1 Apr 2021 13:35:27 -0000 Received: from localhost (HELO localhost) (127.0.0.1) by arche.uberspace.de with SMTP; 1 Apr 2021 13:35:27 -0000 From: Leo-Andres Hofmann To: development@lists.ipfire.org Subject: [PATCH 1/3] rrdimage: Add scripts for new graph display method Date: Thu, 1 Apr 2021 15:35:14 +0200 Message-Id: <20210401133516.1058-1-hofmann@leo-andres.de> X-Mailer: git-send-email 2.27.0.windows.1 MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lists.ipfire.org; s=202003rsa; t=1617284129; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=jeXMm0SillRQ02uHAo0EAvLq5NhDgnljQWV9hVNy+N4=; b=wcCpGlUjPtlyZDWOlwtJU/P4/oImWed6WBRlWVY0T4FFO7ZDIC1cxmSfX14o2aonQpKvfy WmKZFJrfg5sup/8NGetul21mkqDcG6xLN5MwZAGjLh9ZOMEEGimq2UmDRSpngc3LF8z0RX v4mzeceyqKVxtAbEOGf6edjNrfzPc5rcCBcj+IvDqFV+GiszCT0Sz5Y8a56StsBBAvE67S SMOhbKsRenxnXZ7XAVPnL75EpV33gIb5RdFzoxOyAvsNtLvQNnOOcF7Biwwby7qUkVNOYG CaoRxoPnX8dLFkCKfahUgFd/0Dj4I42n3U3IClEO1LgTBcbwVJ5HMX7Tg9mbuw== ARC-Seal: i=1; s=202003rsa; d=lists.ipfire.org; t=1617284129; a=rsa-sha256; cv=none; b=q2tjka3MQnjKL8hegF72UcxI9cDIM8vysCzcBQ7aAnXxptbfMJzTYdU/vPGxusyFGJOkfi bvQfms11Qak9xcGoNds/l9jqBXuFXJ38CXlbb+aAxLSWibYArR+Bq02x9+0mb+RioQfMh8 uIzJkVD9nOCY4poYYoIOZJ0fJpqQbyvBOT8YeZuHmNxINce470cudNn5UK0n5CfYpeaRJY yIRtpWordNXn8CnDLyYnekgXQ1+QSOxXlkt/QtkeotaFxf/U4zfnoCyP2V43nVTA72iB9o vCFBtk+4Ud9rIKyZ0mZsk1F11I8XyXYlx7ryAI+9Jjn2cGexcb5JT16E+KHb2g== ARC-Authentication-Results: i=1; mail01.ipfire.org; dkim=none; spf=pass (mail01.ipfire.org: domain of hofmann@leo-andres.de designates 185.26.156.147 as permitted sender) smtp.mailfrom=hofmann@leo-andres.de X-Rspamd-Queue-Id: 4FB41s2Y2Hz1FW Authentication-Results: mail01.ipfire.org; dkim=none; dmarc=none; spf=pass (mail01.ipfire.org: domain of hofmann@leo-andres.de designates 185.26.156.147 as permitted sender) smtp.mailfrom=hofmann@leo-andres.de X-Rspamd-Server: mail01.haj.ipfire.org X-Spamd-Result: default: False [-0.34 / 11.00]; RCVD_TLS_LAST(0.00)[]; ARC_NA(0.00)[]; FROM_HAS_DN(0.00)[]; R_MISSING_CHARSET(2.50)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; MIME_GOOD(-0.10)[text/plain]; TO_DN_NONE(0.00)[]; BROKEN_CONTENT_TYPE(1.50)[]; RCPT_COUNT_ONE(0.00)[1]; ARC_SIGNED(0.00)[lists.ipfire.org:s=202003rsa:i=1]; IP_REPUTATION_HAM(-2.04)[asn: 205766(-0.29), country: DE(-0.01), ip: 185.26.156.147(-0.73)]; MID_CONTAINS_FROM(1.00)[]; R_SPF_ALLOW(-0.20)[+mx]; DMARC_NA(0.00)[leo-andres.de]; FROM_EQ_ENVFROM(0.00)[]; R_DKIM_NA(0.00)[]; MIME_TRACE(0.00)[0:+]; ASN(0.00)[asn:205766, ipnet:185.26.156.0/24, country:DE]; RCVD_COUNT_TWO(0.00)[2]; BAYES_HAM(-3.00)[99.99%] X-BeenThere: development@lists.ipfire.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: IPFire development talk List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: development-bounces@lists.ipfire.org Sender: "Development" This patch adds two scripts which will later be used to display graphs: -> getrrdimage.cgi: Generates PNG images for graphs. Until now, each CGI with embedded graphs had to be able to output images. These functions are now gathered in this new script. The additional parameter handling can be removed and the CGIs can be simplified. This makes it easier to use and output the graphs. -> rrdimage.js: Interactive Javascript functions This allows the user to select time ranges without reloading the page. In addition, the graphs are now periodically updated, allowing users to live monitor the data. Signed-off-by: Leo-Andres Hofmann --- config/cfgroot/graphs.pl | 10 +- config/rootfiles/common/web-user-interface | 2 + html/cgi-bin/getrrdimage.cgi | 245 +++++++++++++++++++++ html/html/include/rrdimage.js | 122 ++++++++++ 4 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 html/cgi-bin/getrrdimage.cgi create mode 100644 html/html/include/rrdimage.js diff --git a/config/cfgroot/graphs.pl b/config/cfgroot/graphs.pl index e4c3613fb..beddff032 100644 --- a/config/cfgroot/graphs.pl +++ b/config/cfgroot/graphs.pl @@ -29,6 +29,12 @@ require '/var/ipfire/general-functions.pl'; require "${General::swroot}/lang.pl"; require "${General::swroot}/header.pl"; +# Graph image size in pixel +our %image_size = ('width' => 910, 'height' => 300); + +# List of all available time ranges +our @time_ranges = ("hour", "day", "week", "month", "year"); + my $ERROR; my @GRAPH_ARGS = ( @@ -48,8 +54,8 @@ my @GRAPH_ARGS = ( "-W www.ipfire.org", # Default size - "-w 910", - "-h 300", + "-w $image_size{'width'}", + "-h $image_size{'height'}", # Use alternative grid "--alt-y-grid", diff --git a/config/rootfiles/common/web-user-interface b/config/rootfiles/common/web-user-interface index 540bf1e4b..23e9f3e5e 100644 --- a/config/rootfiles/common/web-user-interface +++ b/config/rootfiles/common/web-user-interface @@ -20,6 +20,7 @@ srv/web/ipfire/cgi-bin/extrahd.cgi srv/web/ipfire/cgi-bin/fireinfo.cgi srv/web/ipfire/cgi-bin/firewall.cgi srv/web/ipfire/cgi-bin/fwhosts.cgi +srv/web/ipfire/cgi-bin/getrrdimage.cgi srv/web/ipfire/cgi-bin/gpl.cgi #srv/web/ipfire/cgi-bin/guardian.cgi srv/web/ipfire/cgi-bin/gui.cgi @@ -300,6 +301,7 @@ srv/web/ipfire/html/images/view-refresh.png srv/web/ipfire/html/images/wakeup.gif srv/web/ipfire/html/images/window-new.png srv/web/ipfire/html/include +srv/web/ipfire/html/include/rrdimage.js srv/web/ipfire/html/include/zoneconf.js srv/web/ipfire/html/index.cgi srv/web/ipfire/html/redirect-templates diff --git a/html/cgi-bin/getrrdimage.cgi b/html/cgi-bin/getrrdimage.cgi new file mode 100644 index 000000000..0caefe0ac --- /dev/null +++ b/html/cgi-bin/getrrdimage.cgi @@ -0,0 +1,245 @@ +#!/usr/bin/perl +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2005-2021 IPFire Team # +# # +# 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 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +use strict; +use URI; +use GD; +use GD::Text::Wrap; +use experimental 'smartmatch'; + +# debugging +#use warnings; +#use CGI::Carp 'fatalsToBrowser'; + +require '/var/ipfire/general-functions.pl'; +require "${General::swroot}/lang.pl"; +require "${General::swroot}/header.pl"; +require "${General::swroot}/graphs.pl"; + +# List of graph origins that getrrdimage.cgi can process directly +# (unknown origins are forwarded to ensure compatibility) +my @supported_origins = ("entropy.cgi", "hardwaregraphs.cgi", "media.cgi", + "memory.cgi","netexternal.cgi", "netinternal.cgi", "netother.cgi", + "netovpnrw.cgi", "netovpnsrv.cgi", "qos.cgi", "system.cgi"); + +### Process GET parameters ### +# URL format: /?origin=[graph origin cgi]&graph=[graph name]&range=[time range] +my $uri = URI->new($ENV{'REQUEST_URI'}); +my %query = $uri->query_form; + +my $origin = lc $query{'origin'}; # lower case +my $graph = $query{'graph'}; +my $range = lc $query{'range'}; # lower case + +# Check parameters +unless(($origin =~ /^\w+?\.cgi$/) && ($graph =~ /^[\w-]+?$/) && ($range ~~ @Graphs::time_ranges)) { + # Send HTTP headers + _start_png_output(); + + _print_error("URL parameters missing or malformed."); + exit; +} + +# Unsupported graph origin: Redirect request to the CGI specified in the "origin" parameter +# This enables backwards compatibility with addons that use Graphs::makegraphbox to ouput their own graphs +unless($origin ~~ @supported_origins) { + # Rewrite to old URL format: /[graph origin cgi]?[graph name]?[time range] + my $location = "https://$ENV{'SERVER_NAME'}:$ENV{'SERVER_PORT'}/cgi-bin/${origin}?${graph}?${range}"; + + # Send HTTP redirect + print "Status: 302 Found\n"; + print "Location: $location\n"; + print "Content-type: text/html; charset=UTF-8\n"; + print "\n"; # End of HTTP headers + + print "Unsupported origin, request redirected to '$location'"; + exit; +} + +### Create graphs ### +# Send HTTP headers +_start_png_output(); + +# Graphs are first grouped by their origin. +# This is because some graph categories require special parameter handling. +my $graphstatus = ''; +if($origin eq "entropy.cgi") { ## entropy.cgi + $graphstatus = Graphs::updateentropygraph($range); +# ------ + +} elsif($origin eq "hardwaregraphs.cgi") { ## hardwaregraphs.cgi + if($graph eq "hwtemp") { + $graphstatus = Graphs::updatehwtempgraph($range); + } elsif($graph eq "hwfan") { + $graphstatus = Graphs::updatehwfangraph($range); + } elsif($graph eq "hwvolt") { + $graphstatus = Graphs::updatehwvoltgraph($range); + } elsif($graph eq "thermaltemp") { + $graphstatus = Graphs::updatethermaltempgraph($range); + } elsif($graph =~ "sd?") { + $graphstatus = Graphs::updatehddgraph($graph, $range); + } elsif($graph =~ "nvme?") { + $graphstatus = Graphs::updatehddgraph($graph, $range); + } else { + $graphstatus = "Unknown graph name."; + } +# ------ + +} elsif($origin eq "media.cgi") { ## media.cgi + if ($graph =~ "sd?" || $graph =~ "mmcblk?" || $graph =~ "nvme?n?" || $graph =~ "xvd??" || $graph =~ "vd?" || $graph =~ "md*" ) { + $graphstatus = Graphs::updatediskgraph($graph, $range); + } else { + $graphstatus = "Unknown graph name."; + } +# ------ + +} elsif($origin eq "memory.cgi") { ## memory.cgi + if($graph eq "memory") { + $graphstatus = Graphs::updatememorygraph($range); + } elsif($graph eq "swap") { + $graphstatus = Graphs::updateswapgraph($range); + } else { + $graphstatus = "Unknown graph name."; + } +# ------ + +} elsif($origin eq "netexternal.cgi") { ## netexternal.cgi + $graphstatus = Graphs::updateifgraph($graph, $range); +# ------ + +} elsif($origin eq "netinternal.cgi") { ## netinternal.cgi + if ($graph =~ /wireless/){ + $graph =~ s/wireless//g; + $graphstatus = Graphs::updatewirelessgraph($graph, $range); + } else { + $graphstatus = Graphs::updateifgraph($graph, $range); + } +# ------ + +} elsif($origin eq "netother.cgi") { ## netother.cgi + if($graph eq "conntrack") { + $graphstatus = Graphs::updateconntrackgraph($range); + } elsif($graph eq "fwhits") { + $graphstatus = Graphs::updatefwhitsgraph($range); + } else { + $graphstatus = Graphs::updatepinggraph($graph, $range); + } +# ------ + +} elsif($origin eq "netovpnrw.cgi") { ## netovpnrw.cgi + if($graph ne "UNDEF") { + $graphstatus = Graphs::updatevpngraph($graph, $range); + } else { + $graphstatus = "Unknown graph name."; + } +# ------ + +} elsif($origin eq "netovpnsrv.cgi") { ## netovpnsrv.cgi + if ($graph =~ /ipsec-/){ + $graph =~ s/ipsec-//g; + $graphstatus = Graphs::updateifgraph($graph, $range); + } else { + $graphstatus = Graphs::updatevpnn2ngraph($graph, $range); + } +# ------ + +} elsif($origin eq "qos.cgi") { ## qos.cgi + $graphstatus = Graphs::updateqosgraph($graph, $range); +# ------ + +} elsif($origin eq "services.cgi") { ## services.cgi + if($graph eq "processescpu") { + $graphstatus = Graphs::updateprocessescpugraph($range); + } elsif($graph eq "processesmemory") { + $graphstatus = Graphs::updateprocessesmemorygraph($range); + } else { + $graphstatus = "Unknown graph name."; + } +# ------ + +} elsif($origin eq "system.cgi") { ## system.cgi + if($graph eq "cpu") { + $graphstatus = Graphs::updatecpugraph($range); + } elsif($graph eq "cpufreq") { + $graphstatus = Graphs::updatecpufreqgraph($range); + } elsif($graph eq "load") { + $graphstatus = Graphs::updateloadgraph($range); + } else { + $graphstatus = "Unknown graph name."; + } +# ------ + +} else { + $graphstatus = "Unknown graph origin."; +} + +### Print error message ### +# Add request parameters for debugging +if($graphstatus) { + $graphstatus = "$graphstatus\n($origin, $graph, $range)"; + _print_error($graphstatus); +} + +###--- Internal functions ---### + +# Send HTTP headers and switch to binary output +# (don't print any non-image data to STDOUT afterwards) +sub _start_png_output { + print "Cache-Control: no-cache, no-store\n"; + print "Content-Type: image/png\n"; + print "\n"; # End of HTTP headers + binmode(STDOUT); +} + +# Print error message to PNG output +sub _print_error { + my ($message) = @_; + $message = "- Error -\n \n$message"; + + # Create new image with the same size as a graph + my $img = GD::Image->new($Graphs::image_size{'width'}, $Graphs::image_size{'height'}); + $img->interlaced('true'); + + # Basic colors + my $color_background = $img->colorAllocate(255, 255, 255); + my $color_border = $img->colorAllocate(255, 0, 0); + my $color_text = $img->colorAllocate(0, 0, 0); + + # Background and border + $img->setThickness(2); + $img->filledRectangle(0, 0, $img->width, $img->height, $color_background); + $img->rectangle(10, 10, $img->width - 10, $img->height - 10, $color_border); + + # Draw message with line-wrap + my $textbox = GD::Text::Wrap->new($img, + text => $message, + width => ($img->width - 50), + color => $color_text, + align => 'center', + line_space => 5, + preserve_nl => 1 + ); + $textbox->set_font(gdLargeFont); + $textbox->draw(25, 25); + + # Get PNG output + print $img->png; +} diff --git a/html/html/include/rrdimage.js b/html/html/include/rrdimage.js new file mode 100644 index 000000000..e7ee4c769 --- /dev/null +++ b/html/html/include/rrdimage.js @@ -0,0 +1,122 @@ +/*############################################################################# +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2007-2021 IPFire Team # +# # +# 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 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +// "onclick" event handler for graph time range select button +// buttonObj: reference to the button +function rrdimage_selectRange(buttonObj) { + if(! (buttonObj && ('range' in buttonObj.dataset))) { + return; //required parameters are missing + } + + // Get selected time range from button + const range = buttonObj.dataset.range; + + // Get surrounding div box and select new range + let graphBox = $(buttonObj).closest('div'); + _rrdimg_setRange(graphBox, range); +} + +// Document loaded: Process all graphs, start reload timers +$(function() { + $('div.rrdimage').each(function() { + let graphBox = $(this); + _rrdimg_setRange(graphBox, graphBox.data('defaultRange'), true); + }); +}); + +//--- Internal functions --- + +// Set or update graph time range, start automatic reloading +// graphBox: jQuery object, reference to graph div box +// range: time range (day, hour, ...) +// initMode: don't immediately reload graph, but force timers and attributes update +function _rrdimg_setRange(graphBox, range, initMode = false) { + if(! ((graphBox instanceof jQuery) && (graphBox.length === 1))) { + return; //graphBox element missing + } + + // Check range parameter, default to "day" on error + if(! ["hour", "day", "week", "month", "year"].includes(range)) { + range = "day"; + } + + // Check if the time range is changed + if((graphBox.data('range') !== range) || initMode) { + graphBox.data('range', range); //Store new range + + // Update button highlighting + graphBox.find('button').removeClass('selected'); + graphBox.find(`button[data-range="${range}"]`).addClass('selected'); + } + + // Clear pending reload timer to prevent multiple image reloads + let timerId = graphBox.data('reloadTimer'); + if(timerId !== undefined) { + window.clearInterval(timerId); + graphBox.removeData('reloadTimer'); + } + + // Determine auto reload interval (in seconds), + // interval = 0 disables auto reloading by default + let interval = 0; + switch(range) { + case 'hour': + interval = 60; + break; + + case 'day': + case 'week': + interval = 300; + break; + } + + // Start reload timer and store reference + if(interval > 0) { + timerId = window.setInterval(function(graphRef) { + _rrdimg_reload(graphRef); + }, interval * 1000, graphBox); + graphBox.data('reloadTimer', timerId); + } + + // Always reload image unless disabled by init mode + if(! initMode) { + _rrdimg_reload(graphBox); + } +} + +// Reload graph image, add timestamp to prevent caching +// graphBox: jQuery object (graph element must be valid) +function _rrdimg_reload(graphBox) { + const origin = graphBox.data('origin'); + const graph = graphBox.data('graph'); + const timestamp = Date.now(); + + // Get user selected range or fall back to default + let range = graphBox.data('range'); + if(! range) { + range = graphBox.data('defaultRange'); + } + + // Generate new image URL with timestamp + const imageUrl = `/cgi-bin/getrrdimage.cgi?origin=${origin}&graph=${graph}&range=${range}×tamp=${timestamp}`; + + // Get graph image and set new URL + graphBox.children('img').first().attr('src', imageUrl); +} From patchwork Thu Apr 1 13:35:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leo-Andres Hofmann X-Patchwork-Id: 4012 Return-Path: Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) client-signature ECDSA (P-384)) (Client CN "mail01.haj.ipfire.org", Issuer "R3" (verified OK)) by web04.haj.ipfire.org (Postfix) with ESMTPS id 4FB41w0wqPz3x1r for ; Thu, 1 Apr 2021 13:35:32 +0000 (UTC) Received: from mail02.haj.ipfire.org (mail02.haj.ipfire.org [172.28.1.201]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384 client-signature ECDSA (P-384) client-digest SHA384) (Client CN "mail02.haj.ipfire.org", Issuer "R3" (verified OK)) by mail01.ipfire.org (Postfix) with ESMTPS id 4FB41t3JB0z1T5; Thu, 1 Apr 2021 13:35:30 +0000 (UTC) Received: from mail02.haj.ipfire.org (localhost [127.0.0.1]) by mail02.haj.ipfire.org (Postfix) with ESMTP id 4FB41t23zkz2xfL; Thu, 1 Apr 2021 13:35:30 +0000 (UTC) Received: from mail01.ipfire.org (mail01.haj.ipfire.org [172.28.1.202]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) client-signature ECDSA (P-384)) (Client CN "mail01.haj.ipfire.org", Issuer "R3" (verified OK)) by mail02.haj.ipfire.org (Postfix) with ESMTPS id 4FB41s682Rz2xPx for ; Thu, 1 Apr 2021 13:35:29 +0000 (UTC) Received: from arche.uberspace.de (arche.uberspace.de [185.26.156.147]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mail01.ipfire.org (Postfix) with ESMTPS id 4FB41s2hlyz1Kf for ; Thu, 1 Apr 2021 13:35:29 +0000 (UTC) Received: (qmail 10548 invoked from network); 1 Apr 2021 13:35:28 -0000 Received: from localhost (HELO localhost) (127.0.0.1) by arche.uberspace.de with SMTP; 1 Apr 2021 13:35:28 -0000 From: Leo-Andres Hofmann To: development@lists.ipfire.org Subject: [PATCH 2/3] rrdimage: Add CSS and Javascript to ipfire theme Date: Thu, 1 Apr 2021 15:35:15 +0200 Message-Id: <20210401133516.1058-2-hofmann@leo-andres.de> X-Mailer: git-send-email 2.27.0.windows.1 In-Reply-To: <20210401133516.1058-1-hofmann@leo-andres.de> References: <20210401133516.1058-1-hofmann@leo-andres.de> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lists.ipfire.org; s=202003rsa; t=1617284129; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JZ3199Oim4TujbIaQQlExZPppn3zTktIB8zkjvvK3yM=; b=RZ45LrJRtckHfnnMZpX8H59I+PIVdK+3iaR5qq6bwWD8J2rhlgfAS9p6McBqqSVwaF95qC wbHRRUixH2qme60A2/3DyRspblT12uhiKSSeTMTn7a+3FO0YbGdGoGChcV7x+grTd1L6uF PJCbR3VVfK7h27sCqvlPxh0fhojDgOgDwDL0gbAE9ETvxurGsk8k/bF+K7Vld3w4lt+C1d fH+Mxv2vbF9a4rSoHTPuo59ShBm3J4EeU6KpuXb5SeIP+sPT050Kj+9jleSlLf325zZSHA 4kL0GFxTJZlhRFG1AqQYLmnogb5aTXJtQAxXO70zTKOP73cBefpyfsY35nZhcg== ARC-Seal: i=1; s=202003rsa; d=lists.ipfire.org; t=1617284129; a=rsa-sha256; cv=none; b=YzocF/gOYzHhD0LAYKzWIMlvtmTKmFYbFIoQQyMuKGE/BkxKyhgsVMT7FOEfmCYRyDFP6p Bb3wzcfnqWfZauaI842mc8soXwvsIOwLmaJVTLmapkdR0FW+zM4SS6pWNJHXY2EyEhJAUz sOpGH4640fYuI2Y//20ejKIjI6e9claB3UiM5m8eG7TlTvW03b/5qTCOO9u9klWo6m0Hji q5fTWryX12RlUMZ47vwDyYKF2rekaiqu29LX0+9DxZWosKUOcYYTT15JN4UxAGHwiQdcVT 3UgkzWmPYtZ4LUhzPKWmX+AJJrEVfzgd9/Oq9NWNsML+vDkQ8yBVR7eIwMNtnw== ARC-Authentication-Results: i=1; mail01.ipfire.org; dkim=none; spf=pass (mail01.ipfire.org: domain of hofmann@leo-andres.de designates 185.26.156.147 as permitted sender) smtp.mailfrom=hofmann@leo-andres.de X-Rspamd-Queue-Id: 4FB41s2hlyz1Kf Authentication-Results: mail01.ipfire.org; dkim=none; dmarc=none; spf=pass (mail01.ipfire.org: domain of hofmann@leo-andres.de designates 185.26.156.147 as permitted sender) smtp.mailfrom=hofmann@leo-andres.de X-Rspamd-Server: mail01.haj.ipfire.org X-Spamd-Result: default: False [2.96 / 11.00]; RCVD_TLS_LAST(0.00)[]; ARC_NA(0.00)[]; R_SPF_ALLOW(-0.20)[+mx]; FROM_HAS_DN(0.00)[]; R_MISSING_CHARSET(2.50)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; TO_DN_NONE(0.00)[]; BROKEN_CONTENT_TYPE(1.50)[]; RCPT_COUNT_ONE(0.00)[1]; ARC_SIGNED(0.00)[lists.ipfire.org:s=202003rsa:i=1]; IP_REPUTATION_HAM(-2.04)[asn: 205766(-0.29), country: DE(-0.01), ip: 185.26.156.147(-0.73)]; MID_CONTAINS_FROM(1.00)[]; MIME_HTML_ONLY(0.20)[]; DMARC_NA(0.00)[leo-andres.de]; FROM_EQ_ENVFROM(0.00)[]; R_DKIM_NA(0.00)[]; MIME_TRACE(0.00)[0:~]; ASN(0.00)[asn:205766, ipnet:185.26.156.0/24, country:DE]; RCVD_COUNT_TWO(0.00)[2] X-BeenThere: development@lists.ipfire.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: IPFire development talk List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: development-bounces@lists.ipfire.org Sender: "Development" This patch adds styling for the new graph time range buttons and loads the Javascript in the HTML head. Signed-off-by: Leo-Andres Hofmann --- html/html/themes/ipfire/include/css/style.css | 37 +++++++++++++++++-- html/html/themes/ipfire/include/functions.pl | 1 + 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/html/html/themes/ipfire/include/css/style.css b/html/html/themes/ipfire/include/css/style.css index 9421fc111..10644a9f8 100644 --- a/html/html/themes/ipfire/include/css/style.css +++ b/html/html/themes/ipfire/include/css/style.css @@ -328,7 +328,38 @@ table.fw-nat tbody tr td { height: 2.25em; } -iframe.graph { - width: 100%; - min-height: 300px; +/* RRD graph images */ + +div.rrdimage > ul { + list-style-type: none; + margin: 0; + display: flex; + justify-content: center; +} +.rrdimage li:not(:first-child)::before { + content: "-"; + padding: 0 0.3em; +} + +.rrdimage button { + padding: 0.3em; + font-weight: 700; + color: #d90000; /* link color */ + border: none; + background: none; + cursor: pointer; + text-decoration: underline; +} +.rrdimage button:focus { + outline: none; + box-shadow: none; +} +.rrdimage button.selected { + background-color: rgba(135, 203, 0, 0.2); +} + +div.rrdimage > img { + box-sizing: border-box; + max-width: 100%; + min-height: 290px; } diff --git a/html/html/themes/ipfire/include/functions.pl b/html/html/themes/ipfire/include/functions.pl index 9aec77497..c76af336d 100644 --- a/html/html/themes/ipfire/include/functions.pl +++ b/html/html/themes/ipfire/include/functions.pl @@ -128,6 +128,7 @@ print < +