Compare commits

...

99 Commits
v18 ... main

Author SHA1 Message Date
Magnus Åhall
8fa8bb4c3a Removed datapoint rename confirmation since everything is automatic 2024-07-25 10:59:03 +02:00
Magnus Åhall
7cf2b60803 Bumped to v41 2024-07-25 10:57:05 +02:00
Magnus Åhall
db41d360dc #6, update trigger expressions when renaming datapoints 2024-07-25 10:56:42 +02:00
Magnus Åhall
6685f8bc46 Bumped to v40 2024-07-25 09:39:48 +02:00
Magnus Åhall
96f7b50e4e UI confirm of datapoint renaming 2024-07-25 09:38:43 +02:00
Magnus Åhall
8ef6a2bbfa Added trigger list to datapoint edit 2024-07-25 08:38:06 +02:00
Magnus Åhall
d1599fe2b9 Fixed trigger edit regression and bumped to v39 2024-07-24 16:05:30 +02:00
Magnus Åhall
6909b223a7 Bumped to v38 2024-07-24 15:39:33 +02:00
Magnus Åhall
570ea064aa Faster datapoint latest value display 2024-07-24 15:39:04 +02:00
Magnus Åhall
f8a64e4dfd Added last values for table datapoint, update to current latest values and trigger for future values 2024-07-24 10:27:21 +02:00
Magnus Åhall
a8bdeae3a9 Trying NTFY priority of 5 to get better Firebase notifications 2024-07-19 10:11:53 +02:00
Magnus Åhall
1deb80c776 Bumped to v37 2024-07-07 15:52:08 +02:00
Magnus Åhall
85a6da0b0a Added link to datapoint values from trigger 2024-07-07 15:51:51 +02:00
Magnus Åhall
17e555e7fc Bumped to v36 2024-07-06 09:43:28 +02:00
Magnus Åhall
29e1001665 Regex-based datapoint filter 2024-07-06 09:43:18 +02:00
Magnus Åhall
fe48cf780e Bumped to v35 2024-07-06 09:06:17 +02:00
Magnus Åhall
169c881134 Updated screenshots, fixed graph height 2024-07-06 08:36:49 +02:00
Magnus Åhall
e55e4261dd Updated problems screenshot 2024-07-05 19:55:33 +02:00
Magnus Åhall
c3fbfa307f Bumped to v34 2024-07-05 14:52:14 +02:00
Magnus Åhall
cd123ae1c1 Added button to apply timefilter 2024-07-05 14:52:02 +02:00
Magnus Åhall
9689283c0e Bumped to v33 2024-07-05 12:05:21 +02:00
Magnus Åhall
3adf85a0f6 Redesign of time filter UI 2024-07-05 12:04:56 +02:00
Magnus Åhall
2c5b434fd2 Refactored table CSS, bettered layout in problems 2024-07-05 10:47:50 +02:00
Magnus Åhall
1215b13d47 Bumped to v32 2024-07-04 19:48:05 +02:00
Magnus Åhall
e10783ec54 Fixed error message when trying to change prio to a used number. 2024-07-04 19:38:36 +02:00
Magnus Åhall
06f88f697c Added description to Pushover notification service. 2024-07-04 19:37:18 +02:00
Magnus Åhall
414ca0a95c Reprioritize notification services when updated. 2024-07-04 19:36:56 +02:00
Magnus Åhall
257a4968ec Added Pushover notification 2024-07-04 19:21:02 +02:00
Magnus Åhall
5d24baedac Bumped to v31 2024-07-04 16:55:29 +02:00
Magnus Åhall
fefd4af10c Present times in configured timezone 2024-07-04 16:54:23 +02:00
Magnus Åhall
0de7ca4bef Immediate value presentation when adding datapoint to trigger 2024-07-04 16:48:57 +02:00
Magnus Åhall
3227c22de1 Bumped to v30 2024-07-04 16:30:14 +02:00
Magnus Åhall
1bef8719c0 UI adjustments for problems view 2024-07-04 16:29:53 +02:00
Magnus Åhall
b53b507355 Added SQL for problem 2024-07-04 16:06:11 +02:00
Magnus Åhall
4d7f0d557e Save name of trigger in problem 2024-07-04 15:59:29 +02:00
Magnus Åhall
09241e73a5 UI changes for problems 2024-07-04 15:14:24 +02:00
Magnus Åhall
332788dd20 Bumped to v29 2024-07-04 13:37:24 +02:00
Magnus Åhall
f7dcb4a079 Added timefilter to problems 2024-07-04 13:37:06 +02:00
Magnus Åhall
9700bc9d3c Refactored time filter. 2024-07-04 13:29:39 +02:00
Magnus Åhall
4c908f4891 Renamed to werr for wrapped error library 2024-07-04 09:25:34 +02:00
Magnus Åhall
0f69874475 Bumped to v28 2024-07-04 09:21:46 +02:00
Magnus Åhall
a985f531ea Better datetime display for problems 2024-07-04 09:21:46 +02:00
Magnus Åhall
df714c750b Info icon for problem values 2024-07-04 09:21:46 +02:00
Magnus Åhall
aa368c0b0d Store datapoint values with the problems 2024-07-04 09:21:46 +02:00
865f1ee184 Update README.md 2024-06-30 12:58:27 +02:00
6108cb7046 Update README.md 2024-06-30 12:54:58 +02:00
Magnus Åhall
89c7c30980 Added screenshots 2024-06-30 12:39:24 +02:00
854be4985f Update README.md 2024-06-30 12:28:49 +02:00
Magnus Åhall
3506566e45 Removed session daysvalid 2024-06-30 11:42:00 +02:00
Magnus Åhall
51f96cddb1 Bumped to v27 2024-06-30 11:28:09 +02:00
Magnus Åhall
df8e3fba23 Added filtering of datapoints 2024-06-30 11:27:49 +02:00
7e45798527 Bumped to v26 2024-06-29 20:51:21 +02:00
cd8765e0f2 Refactored time selecting 2024-06-29 20:50:57 +02:00
02794e9629 Fixed NODATA notifications 2024-06-29 19:41:38 +02:00
dd126fece2 Bumped to v25 2024-06-29 19:36:03 +02:00
32523270a8 Merge branch 'notifications' 2024-06-29 19:32:05 +02:00
17a22caa5d Time filtering of notifications 2024-06-29 19:30:26 +02:00
Magnus Åhall
b0ffce05f0 Start of error reporting 2024-06-29 18:09:56 +02:00
e728a302ee Added static resources 2024-06-29 15:21:52 +02:00
ca9a6c3e1d Initial add of notifications 2024-06-29 15:20:31 +02:00
Magnus Åhall
3a4c4730df Updated README with datetime format 2024-06-29 12:09:09 +02:00
Magnus Åhall
3eaf89fb65 Updated README with datetime format 2024-06-29 12:08:40 +02:00
Magnus Åhall
b67d1ec77b Bumped to v24 2024-06-29 11:58:26 +02:00
Magnus Åhall
2b8f160b9e Accept +0200 timezone 2024-06-29 11:57:45 +02:00
Magnus Åhall
24cf7fd4cc Updated gruvbox theme 2024-06-28 17:39:32 +02:00
Magnus Åhall
c01ed135a9 Bumped to v23 2024-06-28 17:18:28 +02:00
Magnus Åhall
a736ae60af Deletion of notification services. 2024-06-28 17:18:08 +02:00
Magnus Åhall
c7ad2aa1b6 Add/edit notifications 2024-06-28 15:28:52 +02:00
Magnus Åhall
1ede36b8aa Removed more chart.js remnants. 2024-06-28 08:22:30 +02:00
Magnus Åhall
4be53ff357 Removed old chart library remnants. 2024-06-28 08:21:23 +02:00
Magnus Åhall
0494d553d0 Plotly graph configuration 2024-06-27 19:07:35 +02:00
Magnus Åhall
ff402b8fcb Bumped to v22 2024-06-27 17:33:18 +02:00
Magnus Åhall
0eb945f3e0 Nicer looking value selector 2024-06-27 17:32:47 +02:00
Magnus Åhall
50664ca965 Better interactive graph support. 2024-06-27 16:53:30 +02:00
Magnus Åhall
16b4bd53f4 Return ts in selected time zone offset. 2024-06-27 16:21:16 +02:00
Magnus Åhall
530204c1a5 Refactored timeparsing from HTML input 2024-06-27 13:45:01 +02:00
Magnus Åhall
ab87da256c Stricter datetime input 2024-06-27 13:14:37 +02:00
Magnus Åhall
3109124a88 Fixed error when adding data to a datapoint without triggers. 2024-06-27 10:33:26 +02:00
Magnus Åhall
22f6b6a413 Add update of timezone setting 2024-06-27 10:02:11 +02:00
Magnus Åhall
65c0984348 Added page layout errors 2024-06-27 09:51:52 +02:00
Magnus Åhall
4b21b0ac07 Graph CSS fixes 2024-06-27 09:14:02 +02:00
Magnus Åhall
617e025be4 Clarified file configuration naming 2024-06-27 09:09:47 +02:00
Magnus Åhall
c28c848b95 Added TIMEZONE to database app config and validate 2024-06-27 09:07:02 +02:00
Magnus Åhall
43d8938459 Added datavalue filtering on date 2024-06-27 08:59:34 +02:00
Magnus Åhall
b6e1139e8a Only show graphs on INT datatype 2024-06-26 12:01:47 +02:00
Magnus Åhall
f0a6ce7b95 Basic graph for INT values 2024-06-26 11:58:54 +02:00
Magnus Åhall
047f39cfa7 Small UI fix 2024-06-25 18:19:15 +02:00
Magnus Åhall
5ff6bc595c Background image in default_light theme 2024-06-25 11:12:40 +02:00
Magnus Åhall
a8661c3908 Bumped to v21 2024-06-25 11:00:59 +02:00
Magnus Åhall
7c72a70440 Remember problem listing 2024-06-25 11:00:39 +02:00
Magnus Åhall
e73d28a8f6 Misc theme fixes 2024-06-25 10:50:31 +02:00
Magnus Åhall
ec7919c9e5 Updated README with theming instructions 2024-06-25 09:58:27 +02:00
Magnus Åhall
7732d8033a Bumped to v20 2024-06-25 09:49:27 +02:00
Magnus Åhall
3ec4bdec2b Fixed icons 2024-06-25 09:49:09 +02:00
Magnus Åhall
aaf4dce6f8 Fixed embedded images 2024-06-25 09:28:53 +02:00
Magnus Åhall
ebba52cded Bumped to v19 2024-06-25 09:22:28 +02:00
Magnus Åhall
54ba7b160b Added theme to configuration page 2024-06-25 09:18:15 +02:00
Magnus Åhall
c77737a20e Fixed icons for default light theme in datapoints page 2024-06-25 09:04:56 +02:00
Magnus Åhall
58e0b2f081 Theming support 2024-06-25 08:59:07 +02:00
158 changed files with 7284 additions and 1376 deletions

150
README.md
View File

@ -1,10 +1,37 @@
---
gitea: none
include_toc: true
---
# Smon
Smon (Simple Monitoring) is a small and easy to maintain single user monitoring system. \
It is developed for the developer's personal need for monitoring a small number of datapoints and get notifications,
without having to maintain a huge system like Zabbix. \
It is also possible to troubleshoot with historial data and graphs.
There is no concept of users or passwords. \
If a requirement, authentiation and authorization can be handled by a HTTP reverse proxy.
All data is sent to the system via an HTTP request to /entry/`datapoint_name`. \
Smon can't poll data.
## Screenshots
| Problems | Datapoints | Graphs | Triggers |
| --- | --- | --- | --- |
| <a href="https://git.ahall.se/magnus/smon/raw/branch/main/screenshots/problems.jpg"><img src="https://git.ahall.se/magnus/smon/raw/branch/main/screenshots/problems_small.jpg"></a> | <a href="https://git.ahall.se/magnus/smon/raw/branch/main/screenshots/datapoints.jpg"><img src="https://git.ahall.se/magnus/smon/raw/branch/main/screenshots/datapoints_small.jpg"></a> | <a href="https://git.ahall.se/magnus/smon/raw/branch/main/screenshots/datapoint_values.jpg"><img src="https://git.ahall.se/magnus/smon/raw/branch/main/screenshots/datapoint_values_small.jpg"></a> | <a href="https://git.ahall.se/magnus/smon/raw/branch/main/screenshots/triggers.jpg"><img src="https://git.ahall.se/magnus/smon/raw/branch/main/screenshots/triggers_small.jpg"></a> |
# Quick start
1) Create an empty database
1) Create the configuration file (default ~/.config/smon.yaml)
1) Run ./smon (will create the database schema)
1) Create an empty database (smon only supports PostgreSQL).
1) Create the configuration file (default ~/.config/smon.yaml).
1) Run ./smon (will create the database schema).
# Configuration
## Configuration
```yaml
network:
@ -23,14 +50,119 @@ database:
username: smon
password: you_wish
session:
daysvalid: 31
application:
logfile: /var/log/smon.log
nodata_interval: 60
```
# Data from systems to datapoints
## Sending data to datapoints
`curl -d "$(time +'%F %T +02')" http://localhost:9000/entry/datapoint_name`
`curl -d 200 http://localhost:9000/entry/datapoint_name`
Use `date '+%FT%T%z'` to get a value from systems in correct format.
# Concepts
Core concepts in Smon are:
* datapoints.
* triggers.
* problems.
* notifications.
* areas.
## Datapoints
A datapoint has a unique name. Recommended is to use only a-z, A-Z, 0-9, dots, dashes and underscores for easier handling in URLs and trigger conditions.
There are three data types:
* INT.
* STRING.
* DATETIME.
INT accepts values like -100, 0, 137 and 29561298561 and is stored in the int8 postgresql type.
STRING is text data and stored by an unlimited varchar.
DATETIME is a date with time and timezone in the format of `2006-01-02T15:04:05+02:00` or `2006-01-02T15:04:05+0200`. Stored in a field of timestamptz.
Recommended is to provide from where (machine, system or script location...) the data is being pushed to Smon in the comment field.
## Triggers
Triggers have datapoints the expression is being able to use.
Expressions are written with the [[https://expr-lang.org/|Expr]] language. See the [[https://expr-lang.org/docs/language-definition|language reference]] for available functions and syntax.
The trigger is evaluating the expression when data is entered through the /entry/`datapoint_name` URL and a problem is issued when the expression returns `true`.
### Examples
The disk usage (reported in percent) for server01 has exceeded 90%:
`server01_disk_usage_root > 90`
It was more than 48 hours since Borg finished on server01:
`(now() - borg_server01_finished).Hours() > 48`
## Problems
One or more datapoints that trips a trigger issues a problem.
Problems are archived in the database and can be looked up historically.
A page of current problems is available to see the current problem state, either as a list or categorised.
Problems can be acknowledged if they are known problems that will not be currently fixed.
## Notifications
Smon has a couple of notification services (currently [[https://ntfy.sh|NTFY]], [[https://pushover.net|Pushover]] and script).
Services are added with a prio. The service with the lowest prio is tried first. \
If sending through the service fails, the next service is tried and so on until one succeeds.
What is sent isn't configurable (for now). What is sent is:
* PROBLEM (when a problem is created) or OK (when a trigger evaluates to false).
* Trigger name
## NTFY
An URL is provided to the topic which should receive the notifications.
## Pushover
The user key and API key for the Pushover application is needed. Additionally, a device key can be specified as well.
## Script
The script service is defined with a filename.
The script is called with three parameters:
1) Problem ID
1) Acknowledge URL
1) Message
## Areas
Go to the `Config` icon to add areas. These are available to categorize triggers and problems for easier troubleshooting.
Each area has sections to further group problems and triggers.
# Development
A couple of small notes on development.
## Theming
* Add theme to select tag in `/views/pages/configuration.gotmpl`.
* Create `/static/less/theme-<theme-name>.less`.
* Create `/static/less/<theme-name>.less`.
* Copy a theme directory under `/static/images/` to the new name.

View File

@ -1,6 +1,6 @@
package main
type SmonConfiguration struct {
type FileConfiguration struct {
LogFile string
NodataInterval int `json:"nodata_interval"` // in seconds
}

83
configuration.go Normal file
View File

@ -0,0 +1,83 @@
package main
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
// Standard
"database/sql"
"time"
)
type Configuration struct {
timezoneLocation *time.Location
Settings map[string]string
}
var smonConfig Configuration
func SmonConfigInit() (cfg Configuration, err error) {
cfg.Settings = make(map[string]string, 8)
var rows *sql.Rows
rows, err = service.Db.Conn.Query(`SELECT * FROM public.configuration`)
if err != nil {
err = werr.Wrap(err)
return
}
defer rows.Close()
for rows.Next() {
var setting, value string
err = rows.Scan(&setting, &value)
if err != nil {
err = werr.Wrap(err)
return
}
cfg.Settings[setting] = value
}
err = cfg.LoadTimezone()
return
}
func (cfg *Configuration) Validate() (err error) {
mandatorySettings := []string{"THEME", "TIMEZONE"}
for _, settingsKey := range mandatorySettings {
if _, found := cfg.Settings[settingsKey]; !found {
return werr.New("Configuration missing setting '%s' in database", settingsKey)
}
}
return
}
func (cfg *Configuration) LoadTimezone() (err error) {
cfg.timezoneLocation, err = time.LoadLocation(cfg.Settings["TIMEZONE"])
return
}
func (cfg *Configuration) Timezone() *time.Location {
return cfg.timezoneLocation
}
func (cfg *Configuration) SetTheme(theme string) (err error) {
cfg.Settings["THEME"] = theme
_, err = service.Db.Conn.Exec(`UPDATE public.configuration SET value=$1 WHERE setting='THEME'`, theme)
return
}
func (cfg *Configuration) SetTimezone(tz string) (err error) {
cfg.Settings["TIMEZONE"] = tz
err = cfg.LoadTimezone()
if err != nil {
return werr.Wrap(err).WithData(tz)
}
_, err = service.Db.Conn.Exec(`UPDATE public.configuration SET value=$1 WHERE setting='TIMEZONE'`, tz)
if err != nil {
return werr.Wrap(err).WithData(tz)
}
return
}

View File

@ -54,14 +54,14 @@ func (dp DatapointValue) Value() any { // {{{
}
if dp.ValueDateTime.Valid {
return dp.ValueDateTime.Time
return dp.ValueDateTime.Time.In(smonConfig.timezoneLocation)
}
return nil
} // }}}
func (dp DatapointValue) FormattedTime() string { // {{{
if dp.ValueDateTime.Valid {
return dp.ValueDateTime.Time.Format("2006-01-02 15:04:05")
return dp.ValueDateTime.Time.In(smonConfig.timezoneLocation).Format("2006-01-02 15:04:05")
}
return "invalid time"
} // }}}
@ -120,8 +120,12 @@ func (dp Datapoint) Update() (err error) { // {{{
} // }}}
func DatapointAdd[T any](name string, value T) (err error) { // {{{
row := service.Db.Conn.QueryRow(`SELECT id, datatype FROM datapoint WHERE name=$1`, name)
type dpRequest = struct {
ID int
value any
}
row := service.Db.Conn.QueryRow(`SELECT id, datatype FROM datapoint WHERE name=$1`, name)
var dpID int
var dpType DatapointType
@ -140,18 +144,24 @@ func DatapointAdd[T any](name string, value T) (err error) { // {{{
case STRING:
_, err = service.Db.Conn.Exec(`INSERT INTO datapoint_value(datapoint_id, value_string) VALUES($1, $2)`, dpID, value)
case DATETIME:
_, err = service.Db.Conn.Exec(`INSERT INTO datapoint_value(datapoint_id, value_datetime) VALUES($1, $2)`, dpID, value)
// Time value is required to be a RFC 3339 formatted time string
var t time.Time
valueStr, ok := any(value).([]byte)
if !ok {
return werr.New("DATETIME value not a string").WithData(dpRequest{dpID, value})
}
t, err = stringToTime(string(valueStr))
if err != nil {
return werr.Wrap(err).WithData(dpRequest{dpID, value}).Log()
}
_, err = service.Db.Conn.Exec(`INSERT INTO datapoint_value(datapoint_id, value_datetime) VALUES($1, $2)`, dpID, t)
}
if err != nil {
err = werr.Wrap(err).WithData(struct {
ID int
value any
}{dpID, value})
err = werr.Wrap(err).WithData(dpRequest{dpID, value})
return
}
service.Db.Conn.Exec(`UPDATE datapoint SET last_value = NOW(), nodata_is_problem = false WHERE id=$1`, dpID)
return
} // }}}
@ -160,30 +170,19 @@ func DatapointsRetrieve() (dps []Datapoint, err error) { // {{{
var rows *sqlx.Rows
rows, err = service.Db.Conn.Queryx(`
SELECT
dp.id,
dp.name,
dp.datatype,
dp.last_value,
dp.group,
dp.comment,
dp.nodata_problem_seconds,
dpv.id AS v_id,
dpv.ts,
dpv.value_int,
dpv.value_string,
dpv.value_datetime
FROM public.datapoint dp
LEFT JOIN (
SELECT
*,
row_number() OVER (PARTITION BY "datapoint_id" ORDER BY ts DESC) AS rn
FROM datapoint_value
) dpv ON dpv.datapoint_id = dp.id AND rn = 1
id, name, datatype, last_value, "group", comment, nodata_problem_seconds,
last_value_id AS v_id,
CASE
WHEN last_value_id IS NULL THEN null
ELSE last_value
END AS ts,
last_value_int AS value_int,
last_value_string AS value_string,
last_value_datetime AS value_datetime
FROM datapoint
ORDER BY
dp.group ASC,
dp.name ASC
"group" ASC,
name ASC
`)
if err != nil {
err = werr.Wrap(err)
@ -243,11 +242,11 @@ func DatapointRetrieve(id int, name string) (dp Datapoint, err error) { // {{{
var query string
var param any
if id > 0 {
query = `SELECT *, true AS found FROM datapoint WHERE id = $1`
query = `SELECT id, "group", name, "datatype", comment, last_value, nodata_problem_seconds, nodata_is_problem, true AS found FROM public.datapoint WHERE id = $1`
param = id
dp.ID = id
} else {
query = `SELECT *, true AS found FROM datapoint WHERE name = $1`
query = `SELECT id, "group", name, "datatype", comment, last_value, nodata_problem_seconds, nodata_is_problem, true AS found FROM public.datapoint WHERE name = $1`
param = name
}
@ -327,8 +326,34 @@ func DatapointDelete(id int) (err error) { // {{{
}
return
} // }}}
func DatapointValues(id int) (values []DatapointValue, err error) { // {{{
rows, err := service.Db.Conn.Queryx(`SELECT * FROM datapoint_value WHERE datapoint_id=$1 ORDER BY ts DESC LIMIT 500`, id)
func DatapointValues(id int, from, to time.Time) (values []DatapointValue, err error) { // {{{
_, err = service.Db.Conn.Exec(`SELECT set_config('timezone', $1, false)`, smonConfig.Timezone().String())
if err != nil {
err = werr.Wrap(err).WithData(smonConfig.Timezone().String())
return
}
rows, err := service.Db.Conn.Queryx(
`
SELECT
id,
datapoint_id,
ts,
value_int,
value_string,
value_datetime
FROM datapoint_value
WHERE
datapoint_id=$1 AND
ts >= $2 AND
ts <= $3
ORDER BY
ts DESC
`,
id,
from,
to,
)
if err != nil {
err = werr.Wrap(err).WithData(id)
return

2
go.mod
View File

@ -3,7 +3,7 @@ module smon
go 1.22.0
require (
git.gibonuddevalla.se/go/webservice v0.2.15
git.gibonuddevalla.se/go/webservice v0.2.16
git.gibonuddevalla.se/go/wrappederror v0.3.4
github.com/expr-lang/expr v1.16.5
github.com/jmoiron/sqlx v1.3.5

76
helper.go Normal file
View File

@ -0,0 +1,76 @@
package main
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
// Standard
"regexp"
"strconv"
"time"
)
var rxpTimezone *regexp.Regexp
func init() {
rxpTimezone = regexp.MustCompile(`(\d\d)(\d\d)$`)
}
func stringToTime(strTime string) (t time.Time, err error) { // {{{
// `date` command %z gives timezone like +0200 instead of +02:00.
// This can easily be fixed here, not requiring all scripts to be fixed.
t, err = time.Parse(time.RFC3339, strTime)
if err != nil {
// Check for aforementioned problem.
parseError, ok := err.(*time.ParseError)
if ok && parseError != nil && parseError.LayoutElem == "Z07:00" {
// Insert the missing colon according to RFC 3339 and try again.
patchedTimeStr := rxpTimezone.ReplaceAllString(strTime, `$1:$2`)
t, err = time.Parse(time.RFC3339, patchedTimeStr)
}
// Couldn't convert to time.ParseError or the retry
// failed. Either way, an error occurs.
if err != nil {
err = werr.Wrap(err).WithData(strTime)
return
}
}
return
} // }}}
func parseHTMLDateTime(str string, dflt time.Time) (t time.Time, err error) { // {{{
// Browser sending 2024-06-27T10:43 (16 characters) when seconds is 00.
if len(str) == 16 {
str += ":00"
}
if str == "" {
return dflt, nil
} else {
t, err = time.ParseInLocation("2006-01-02T15:04:05", str, smonConfig.Timezone())
if err != nil {
err = werr.Wrap(err)
}
}
return
} // }}}
func applyTimeOffset(t time.Time, duration time.Duration, amountStr string) time.Time { // {{{
amount, err := strconv.Atoi(amountStr)
if err != nil {
return t
}
return t.Add(duration * time.Duration(amount))
} // }}}
func presetTimeInterval(duration time.Duration, presetStr string, timeFrom, timeTo *time.Time) () {// {{{
if presetStr == "" {
return
}
now := time.Now()
presetTime, _ := strconv.Atoi(presetStr)
(*timeFrom) = now.Add(duration * -1 * time.Duration(presetTime))
(*timeTo) = now
return
}// }}}

423
main.go
View File

@ -19,15 +19,17 @@ import (
"io/fs"
"log/slog"
"net/http"
"net/url"
"os"
"path"
"slices"
"sort"
"strconv"
"strings"
"time"
)
const VERSION = "v18"
const VERSION = "v41"
var (
logger *slog.Logger
@ -39,7 +41,7 @@ var (
parsedTemplates map[string]*template.Template
componentFilenames []string
notificationManager notification.Manager
smonConf SmonConfiguration
fileConf FileConfiguration
//go:embed sql
sqlFS embed.FS
@ -91,13 +93,13 @@ func main() { // {{{
}
j, _ := json.Marshal(service.Config.Application)
json.Unmarshal(j, &smonConf)
logFile, err = os.OpenFile(smonConf.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
json.Unmarshal(j, &fileConf)
logFile, err = os.OpenFile(fileConf.LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
logger.Error("application", "error", err)
return
}
if smonConf.NodataInterval < 10 {
if fileConf.NodataInterval < 10 {
logger.Error("application → nodata_interval has to be larger or equal to 10.")
return
}
@ -137,6 +139,7 @@ func main() { // {{{
service.Register("/datapoint/update/{id}", false, false, actionDatapointUpdate)
service.Register("/datapoint/delete/{id}", false, false, actionDatapointDelete)
service.Register("/datapoint/values/{id}", false, false, pageDatapointValues)
service.Register("/datapoint/json/{id}", false, false, actionDatapointJson)
service.Register("/triggers", false, false, pageTriggers)
service.Register("/trigger/create/{sectionID}/{name}", false, false, actionTriggerCreate)
@ -147,11 +150,30 @@ func main() { // {{{
service.Register("/trigger/run/{id}", false, false, actionTriggerRun)
service.Register("/trigger/delete/{id}", false, false, actionTriggerDelete)
service.Register("/notifications", false, false, pageNotifications)
service.Register("/configuration", false, false, pageConfiguration)
service.Register("/configuration/theme", false, false, actionConfigurationTheme)
service.Register("/configuration/timezone", false, false, actionConfigurationTimezone)
service.Register("/configuration/notification", false, false, pageConfigurationNotification)
service.Register("/configuration/notification/update/{prio}", false, false, actionConfigurationNotificationUpdate)
service.Register("/configuration/notification/delete/{prio}", false, false, actionConfigurationNotificationDelete)
service.Register("/entry/{datapoint}", false, false, actionEntryDatapoint)
go nodataLoop()
smonConfig, err = SmonConfigInit()
if err != nil {
logger.Error("configuration", "error", werr.Wrap(err))
os.Exit(1)
}
err = smonConfig.Validate()
if err != nil {
logger.Error("configuration", "error", werr.Wrap(err))
os.Exit(1)
}
err = service.Start()
if err != nil {
logger.Error("webserver", "error", werr.Wrap(err))
@ -186,6 +208,20 @@ func httpError(w http.ResponseWriter, err error) { // {{{
j, _ := json.Marshal(resp)
w.Write(j)
} // }}}
func pageError(w http.ResponseWriter, redirectURL string, pageErr error) { // {{{
u, err := url.Parse(redirectURL)
if err != nil {
httpError(w, err)
return
}
values := u.Query()
values.Add("_err", pageErr.Error())
u.RawQuery = values.Encode()
w.Header().Add("Location", u.String())
w.WriteHeader(302)
} // }}}
func staticHandler(w http.ResponseWriter, r *http.Request, sess *session.T) { // {{{
if flagDev && !reloadTemplates(w) {
@ -340,7 +376,7 @@ func getPage(layout, page string) (tmpl *template.Template, err error) { // {{{
funcMap := template.FuncMap{
"format_time": func(t time.Time) template.HTML {
return template.HTML(
t.Local().Format(`<span class="date">2006-01-02</span> <span class="time">15:04<span class="seconds">:05</span></span>`),
t.In(smonConfig.Timezone()).Format(`<span class="date">2006-01-02</span> <span class="time">15:04:05<span class="seconds">:05</span></span>`),
)
},
}
@ -349,9 +385,9 @@ func getPage(layout, page string) (tmpl *template.Template, err error) { // {{{
filenames = append(filenames, componentFilenames...)
logger.Info("template", "op", "parse", "layout", layout, "page", page, "filenames", filenames)
if flagDev {
tmpl, err = template.New("main.gotmpl").Funcs(funcMap).ParseFS(os.DirFS("."), filenames...)
tmpl, err = template.New(layout+".gotmpl").Funcs(funcMap).ParseFS(os.DirFS("."), filenames...)
} else {
tmpl, err = template.New("main.gotmpl").Funcs(funcMap).ParseFS(viewFS, filenames...)
tmpl, err = template.New(layout+".gotmpl").Funcs(funcMap).ParseFS(viewFS, filenames...)
}
if err != nil {
err = werr.Wrap(err).Log()
@ -362,12 +398,13 @@ func getPage(layout, page string) (tmpl *template.Template, err error) { // {{{
return
} // }}}
func pageIndex(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
func pageIndex(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
page := Page{
LAYOUT: "main",
PAGE: "index",
CONFIG: smonConfig.Settings,
}
page.Render(w)
page.Render(w, r)
} // }}}
func actionAreaNew(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
@ -477,13 +514,36 @@ func actionSectionDelete(w http.ResponseWriter, r *http.Request, _ *session.T) {
return
} // }}}
func pageProblems(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
func pageProblems(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
page := Page{
LAYOUT: "main",
PAGE: "problems",
CONFIG: smonConfig.Settings,
}
problems, err := ProblemsRetrieve()
// Manage the values from the timefilter component
var err error
var timeFrom, timeTo time.Time
timeFrom, timeTo, err = timefilterParse(
r.URL.Query().Get("time-f"),
r.URL.Query().Get("time-t"),
r.URL.Query().Get("time-offset"),
r.URL.Query().Get("time-preset"),
)
if err != nil {
httpError(w, err)
return
}
// GET parameters for this page
var selection string
if r.URL.Query().Get("selection") == "all" {
selection = "ALL"
} else {
selection = "CURRENT"
}
problems, err := ProblemsRetrieve(selection == "ALL", timeFrom, timeTo)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
@ -508,8 +568,14 @@ func pageProblems(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
page.Data = map[string]any{
"Problems": problems,
"ProblemsGrouped": problemsGrouped,
"Selection": selection,
"TimeHidden": selection == "CURRENT",
"TimeSubmit": "/problems",
"TimeFrom": timeFrom.Format("2006-01-02T15:04:05"),
"TimeTo": timeTo.Format("2006-01-02T15:04:05"),
}
page.Render(w)
page.Render(w, r)
return
} // }}}
func actionProblemAcknowledge(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
@ -555,6 +621,7 @@ func pageDatapoints(w http.ResponseWriter, r *http.Request, _ *session.T) { // {
page := Page{
LAYOUT: "main",
PAGE: "datapoints",
CONFIG: smonConfig.Settings,
}
datapoints, err := DatapointsRetrieve()
@ -573,7 +640,7 @@ func pageDatapoints(w http.ResponseWriter, r *http.Request, _ *session.T) { // {
page.Data = map[string]any{
"Datapoints": datapoints,
}
page.Render(w)
page.Render(w, r)
return
} // }}}
func pageDatapointEdit(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
@ -596,9 +663,31 @@ func pageDatapointEdit(w http.ResponseWriter, r *http.Request, _ *session.T) { /
}
}
/* Triggers using this datapoint is provided as a list to update
* if changing the datapoint name. Parsing expr and automatically
* changing it to renamed datapoints would be nice in the future. */
var triggers []Trigger
triggers, err = TriggersRetrieveByDatapoint(datapoint.Name)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
slices.SortFunc(triggers, func(a, b Trigger) int {
an := strings.ToUpper(a.Name)
bn := strings.ToUpper(b.Name)
if an < bn {
return -1
}
if an > bn {
return 1
}
return 0
})
page := Page{
LAYOUT: "main",
PAGE: "datapoint_edit",
CONFIG: smonConfig.Settings,
MENU: "datapoints",
Icon: "datapoints",
Label: "Datapoint",
@ -606,8 +695,9 @@ func pageDatapointEdit(w http.ResponseWriter, r *http.Request, _ *session.T) { /
page.Data = map[string]any{
"Datapoint": datapoint,
"Triggers": triggers,
}
page.Render(w)
page.Render(w, r)
return
} // }}}
func actionDatapointUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
@ -621,8 +711,15 @@ func actionDatapointUpdate(w http.ResponseWriter, r *http.Request, _ *session.T)
var nodataSeconds int
nodataSeconds, _ = strconv.Atoi(r.FormValue("nodata_seconds"))
// Datapoint needs to be retrieved from database for the name.
// If name has changed, trigger expressions needs to be updated.
var dp Datapoint
dp.ID = id
dp, err = DatapointRetrieve(id, "")
if err != nil {
httpError(w, werr.Wrap(err).WithData(id).Log())
return
}
prevDatapointName := dp.Name
dp.Group = r.FormValue("group")
dp.Name = r.FormValue("name")
dp.Datatype = DatapointType(r.FormValue("datatype"))
@ -634,6 +731,29 @@ func actionDatapointUpdate(w http.ResponseWriter, r *http.Request, _ *session.T)
return
}
// Update the trigger expressions using this
// datapoint name if changed.
if prevDatapointName != dp.Name {
var triggers []Trigger
triggers, err = TriggersRetrieveByDatapoint(dp.Name)
if err != nil {
httpError(w, werr.Wrap(err).WithData(dp.Name))
return
}
for _, trigger := range triggers {
err = trigger.RenameDatapoint(prevDatapointName, dp.Name)
if err != nil {
httpError(w, werr.Wrap(err).WithData([]string{prevDatapointName, dp.Name}))
return
}
err = trigger.Update()
if err != nil {
httpError(w, werr.Wrap(err).WithData([]string{prevDatapointName, dp.Name, trigger.Name}))
return
}
}
}
w.Header().Add("Location", "/datapoints")
w.WriteHeader(302)
} // }}}
@ -669,16 +789,33 @@ func pageDatapointValues(w http.ResponseWriter, r *http.Request, _ *session.T) {
return
}
// Manage the values from the timefilter component
var timeFrom, timeTo time.Time
timeFrom, timeTo, err = timefilterParse(
r.URL.Query().Get("time-f"),
r.URL.Query().Get("time-t"),
r.URL.Query().Get("time-offset"),
r.URL.Query().Get("time-preset"),
)
// Fetch data point values according to the times.
var values []DatapointValue
values, err = DatapointValues(id)
values, err = DatapointValues(id, timeFrom, timeTo)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
// GET parameters.
display := r.URL.Query().Get("display")
if display == "" && datapoint.Datatype == INT {
display = "graph"
}
page := Page{
LAYOUT: "main",
PAGE: "datapoint_values",
CONFIG: smonConfig.Settings,
MENU: "datapoints",
Icon: "datapoints",
Label: "Values for " + datapoint.Name,
@ -687,12 +824,48 @@ func pageDatapointValues(w http.ResponseWriter, r *http.Request, _ *session.T) {
page.Data = map[string]any{
"Datapoint": datapoint,
"Values": values,
"Display": display,
"TimeSubmit": "/datapoint/values/" + strconv.Itoa(datapoint.ID),
"TimeFrom": timeFrom.Format("2006-01-02T15:04:05"),
"TimeTo": timeTo.Format("2006-01-02T15:04:05"),
}
page.Render(w)
page.Render(w, r)
return
} // }}}
func actionDatapointJson(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
idStr := r.PathValue("id")
id, err := strconv.Atoi(idStr)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
func pageTriggers(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
fromStr := r.URL.Query().Get("time-f")
from, err := time.ParseInLocation("2006-01-02 15:04:05", fromStr[0:min(19, len(fromStr))], smonConfig.Timezone())
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
toStr := r.URL.Query().Get("time-t")
to, err := time.ParseInLocation("2006-01-02 15:04:05", toStr[0:min(19, len(toStr))], smonConfig.Timezone())
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
values, err := DatapointValues(id, from, to)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
j, _ := json.Marshal(values)
w.Write(j)
} // }}}
func pageTriggers(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
areas, err := TriggersRetrieve()
if err != nil {
httpError(w, werr.Wrap(err).Log())
@ -706,12 +879,13 @@ func pageTriggers(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
page := Page{
LAYOUT: "main",
PAGE: "triggers",
CONFIG: smonConfig.Settings,
Data: map[string]any{
"Areas": areas,
},
}
page.Render(w)
page.Render(w, r)
} // }}}
func actionTriggerCreate(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
name := r.PathValue("name")
@ -790,6 +964,7 @@ func pageTriggerEdit(w http.ResponseWriter, r *http.Request, _ *session.T) { //
LAYOUT: "main",
PAGE: "trigger_edit",
MENU: "triggers",
CONFIG: smonConfig.Settings,
Label: "Trigger",
Icon: "triggers",
Data: map[string]any{
@ -798,7 +973,7 @@ func pageTriggerEdit(w http.ResponseWriter, r *http.Request, _ *session.T) { //
},
}
page.Render(w)
page.Render(w, r)
} // }}}
func actionTriggerDatapointAdd(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
triggerID := r.PathValue("id")
@ -828,7 +1003,22 @@ func actionTriggerDatapointAdd(w http.ResponseWriter, r *http.Request, _ *sessio
return
}
j, _ := json.Marshal(struct{ OK bool }{OK: true})
// Also retrieve the datapoint to get the latest value
// for immediate presentation when added.
dp, err := DatapointRetrieve(0, dpName)
if err != nil {
httpError(w, werr.Wrap(err).WithData(dpName).Log())
return
}
dp.LastDatapointValue.TemplateValue = dp.LastDatapointValue.Value()
j, _ := json.Marshal(
struct {
OK bool
Datapoint Datapoint
}{
true,
dp,
})
w.Header().Add("Content-Type", "application/json")
w.Write(j)
} // }}}
@ -920,7 +1110,7 @@ func actionTriggerDelete(w http.ResponseWriter, r *http.Request, _ *session.T) {
w.WriteHeader(302)
} // }}}
func pageConfiguration(w http.ResponseWriter, _ *http.Request, _ *session.T) { // {{{
func pageConfiguration(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
areas, err := AreaRetrieve()
if err != nil {
httpError(w, werr.Wrap(err).Log())
@ -934,10 +1124,193 @@ func pageConfiguration(w http.ResponseWriter, _ *http.Request, _ *session.T) { /
page := Page{
LAYOUT: "main",
PAGE: "configuration",
CONFIG: smonConfig.Settings,
Data: map[string]any{
"Areas": areas,
"Areas": areas,
"NotificationServices": notificationManager.Services(),
"AvailableServices": notification.AvailableServices(),
},
}
page.Render(w)
page.Render(w, r)
} // }}}
func actionConfigurationTheme(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
theme := r.FormValue("theme")
err := smonConfig.SetTheme(theme)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
w.Header().Add("Location", "/configuration")
w.WriteHeader(302)
} // }}}
func actionConfigurationTimezone(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
timezone := r.FormValue("timezone")
_, err := time.LoadLocation(timezone)
if err != nil {
pageError(w, "/configuration", werr.Wrap(err).Log())
return
}
err = smonConfig.SetTimezone(timezone)
if err != nil {
pageError(w, "/configuration", werr.Wrap(err).Log())
return
}
w.Header().Add("Location", "/configuration")
w.WriteHeader(302)
} // }}}
func pageConfigurationNotification(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
// This function is either receiving a type when creating a new service,
// or a prio when editing an existing.
notificationType := r.URL.Query().Get("type")
prioStr := r.URL.Query().Get("prio")
var service notification.Service
if notificationType != "" {
// Create a new instance of the selected notification type.
service = notification.NewInstance(notificationType)
logger.Info("FOO", "service", fmt.Sprintf("%p %#v\n", service, service))
} else {
// Find the existing service for editing.
prio, err := strconv.Atoi(prioStr)
if err != nil {
httpError(w, werr.Wrap(err).Log())
return
}
service = *notificationManager.GetService(prio)
}
if service == nil {
data := struct {
typ string
prio string
}{notificationType, prioStr}
err := fmt.Errorf("Invalid service")
pageError(w, "/configuration", werr.Wrap(err).WithData(data).Log())
return
}
// Make it easier for the user by initiating the prio field
// for new notifications to the highest prio + 1.
if notificationType != "" {
prio := 0
for _, svc := range notificationManager.Services() {
prio = max(prio, svc.GetPrio()+1)
}
service.SetPrio(prio)
}
page := Page{
LAYOUT: "notification",
PAGE: "notification/" + strings.ToLower(service.GetType()),
CONFIG: smonConfig.Settings,
Data: map[string]any{
"Service": service,
},
}
page.Render(w, r)
} // }}}
func actionConfigurationNotificationUpdate(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
prioStr := r.PathValue("prio")
prio, err := strconv.Atoi(prioStr)
if err != nil {
pageError(w, "/configuration", werr.Wrap(err).Log())
return
}
// prio -1 means a new service, not existing in database.
var svc *notification.Service
if prio == -1 {
emptyService := notification.NewInstance(r.PostFormValue("type"))
svc = &emptyService
} else {
svc = notificationManager.GetService(prio)
if svc == nil {
pageError(w, "/configuration", werr.New("Service with prio %d not found", prio).Log())
return
}
}
// The service is given all data to give it a chance to
// validate and throwing errors.
err = r.ParseForm()
if err != nil {
pageError(w, "/configuration", werr.Wrap(err).Log())
return
}
err = (*svc).Update(r.PostForm)
if err != nil {
pageError(w, "/configuration", werr.Wrap(err).Log())
return
}
var created bool
created, err = UpdateNotificationService(*svc)
if err != nil {
pageError(w, "/configuration", werr.Wrap(err).Log())
return
}
(*svc).Commit()
if created {
notificationManager.AddService(*svc)
}
notificationManager.Reprioritize()
w.Header().Add("Location", "/configuration")
w.WriteHeader(302)
} // }}}
func actionConfigurationNotificationDelete(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
prioStr := r.PathValue("prio")
prio, err := strconv.Atoi(prioStr)
if err != nil {
pageError(w, "/configuration", werr.Wrap(err).Log())
return
}
DeleteNotificationService(prio)
notificationManager.RemoveService(prio)
w.Header().Add("Location", "/configuration")
w.WriteHeader(302)
} // }}}
func pageNotifications(w http.ResponseWriter, r *http.Request, _ *session.T) { // {{{
var err error
// Manage the values from the timefilter component
var timeFrom, timeTo time.Time
timeFrom, timeTo, err = timefilterParse(
r.URL.Query().Get("time-f"),
r.URL.Query().Get("time-t"),
r.URL.Query().Get("time-offset"),
r.URL.Query().Get("time-preset"),
)
nss, err := notificationsSent(timeFrom, timeTo)
if err != nil {
pageError(w, "/", werr.Wrap(err).Log())
}
page := Page{
LAYOUT: "main",
PAGE: "notifications",
CONFIG: smonConfig.Settings,
Data: map[string]any{
"Notifications": nss,
"TimeSubmit": "/notifications",
"TimeFrom": timeFrom.Format("2006-01-02T15:04:05"),
"TimeTo": timeTo.Format("2006-01-02T15:04:05"),
},
}
page.Render(w, r)
} // }}}

View File

@ -24,8 +24,7 @@ func nodataLoop() {
var datapoints []Datapoint
var err error
// TODO - should be configurable
ticker := time.NewTicker(time.Second * time.Duration(smonConf.NodataInterval))
ticker := time.NewTicker(time.Second * time.Duration(fileConf.NodataInterval))
for {
<-ticker.C
datapoints, err = nodataDatapoints()

View File

@ -6,6 +6,12 @@ import (
// Standard
"log/slog"
"slices"
"strings"
)
var (
allServices []Service
)
func ServiceFactory(t string, config []byte, prio int, ackURL string, logger *slog.Logger) (Service, error) {
@ -18,6 +24,16 @@ func ServiceFactory(t string, config []byte, prio int, ackURL string, logger *sl
}
ntfy.SetLogger(logger)
return ntfy, nil
case "PUSHOVER":
pushover, err := NewPushover(config, prio, ackURL)
if err != nil {
err = werr.Wrap(err).WithData(config)
return nil, err
}
pushover.SetLogger(logger)
return pushover, nil
case "SCRIPT":
script, err := NewScript(config, prio, ackURL)
if err != nil {
@ -30,3 +46,37 @@ func ServiceFactory(t string, config []byte, prio int, ackURL string, logger *sl
return nil, werr.New("Unknown notification service, '%s'", t).WithCode("002-0000")
}
func NewInstance(typ string) Service {
switch typ {
case "NTFY":
return new(NTFY)
case "PUSHOVER":
return new(Pushover)
case "SCRIPT":
return new(Script)
}
return nil
}
func GetInstance(typ string) Service {
for _, svc := range allServices {
if strings.ToLower(svc.GetType()) == strings.ToLower(typ) {
return svc
}
}
return nil
}
func AvailableServices() []Service {
slices.SortFunc(allServices, func(a, b Service) int {
if a.GetType() < b.GetType() {
return -1
}
if a.GetType() > b.GetType() {
return 1
}
return 0
})
return allServices
}

View File

@ -11,6 +11,9 @@ import (
"io"
"log/slog"
"net/http"
"net/url"
"strconv"
"strings"
)
type NTFY struct {
@ -18,6 +21,13 @@ type NTFY struct {
Prio int
AcknowledgeURL string
logger *slog.Logger
exists bool
updated Service
}
func init() {
allServices = append(allServices, &NTFY{})
}
func NewNTFY(config []byte, prio int, ackURL string) (instance *NTFY, err error) {
@ -44,6 +54,22 @@ func (ntfy *NTFY) GetPrio() int {
return ntfy.Prio
}
func (ntfy *NTFY) SetPrio(prio int) {
ntfy.Prio = prio
}
func (ntfy *NTFY) SetExists(exists bool) {
ntfy.exists = exists
}
func (ntfy NTFY) Exists() bool {
return ntfy.exists
}
func (ntfy *NTFY) String() string {
return ntfy.URL
}
func (ntfy NTFY) Send(problemID int, msg []byte) (err error) {
var req *http.Request
var res *http.Response
@ -55,7 +81,7 @@ func (ntfy NTFY) Send(problemID int, msg []byte) (err error) {
ackURL := fmt.Sprintf("http, OK, %s/notification/ack?problemID=%d", ntfy.AcknowledgeURL, problemID)
req.Header.Add("X-Actions", ackURL)
req.Header.Add("X-Priority", "4") // XXX: should be 5
req.Header.Add("X-Priority", "5")
req.Header.Add("X-Tags", "calendar")
res, err = http.DefaultClient.Do(req)
@ -81,3 +107,40 @@ func (ntfy NTFY) Send(problemID int, msg []byte) (err error) {
return
}
func (ntfy *NTFY) Update(values url.Values) (err error) {
updated := NTFY{}
ntfy.updated = &updated
updated.Prio, err = strconv.Atoi(values.Get("prio"))
if err != nil {
return werr.Wrap(err)
}
givenURL := values.Get("url")
if strings.TrimSpace(givenURL) == "" {
return werr.New("URL cannot be empty")
}
updated.URL = strings.TrimSpace(givenURL)
return
}
func (ntfy *NTFY) Updated() Service {
return ntfy.updated
}
func (ntfy *NTFY) Commit() {
updatedNTFY := ntfy.updated.(*NTFY)
ntfy.Prio = updatedNTFY.Prio
ntfy.URL = updatedNTFY.URL
}
func (ntfy NTFY) JSON() []byte {
data := struct {
URL string `json:"url"`
}{
ntfy.URL,
}
j, _ := json.Marshal(data)
return j
}

View File

@ -6,6 +6,7 @@ import (
// Standard
"log/slog"
"net/url"
"slices"
)
@ -13,7 +14,15 @@ type Service interface {
SetLogger(*slog.Logger)
GetPrio() int
GetType() string
SetPrio(int)
SetExists(bool) // Exists in database
Exists() bool // Exists in database
String() string
Send(int, []byte) error
Update(url.Values) error
Updated() Service
Commit()
JSON() []byte
}
type Manager struct {
@ -28,7 +37,11 @@ func NewManager(logger *slog.Logger) (nm Manager) {
}
func (nm *Manager) AddService(service Service) {
service.SetExists(true)
nm.services = append(nm.services, service)
}
func (nm *Manager) Reprioritize() {
slices.SortFunc(nm.services, func(a, b Service) int {
if a.GetPrio() < b.GetPrio() {
return -1
@ -40,6 +53,22 @@ func (nm *Manager) AddService(service Service) {
})
}
func (nm *Manager) GetService(prio int) *Service {
for _, svc := range nm.services {
if svc.GetPrio() == prio {
return &svc
}
}
return nil
}
func (nm *Manager) RemoveService(prioToRemove int) {
nm.services = slices.DeleteFunc(nm.services, func(svc Service) bool {
return svc.GetPrio() == prioToRemove
})
}
func (nm *Manager) Send(problemID int, msg []byte, fn func(*Service, error)) (err error) {
for i, service := range nm.services {
nm.logger.Info("notification", "service", service.GetType(), "prio", service.GetPrio())
@ -49,7 +78,7 @@ func (nm *Manager) Send(problemID int, msg []byte, fn func(*Service, error)) (er
} else {
data := struct {
ProblemID int
Msg []byte
Msg []byte
}{
problemID,
msg,
@ -61,3 +90,7 @@ func (nm *Manager) Send(problemID int, msg []byte, fn func(*Service, error)) (er
return
}
func (nm *Manager) Services() (services []Service) {
return nm.services
}

198
notification/pushover.go Normal file
View File

@ -0,0 +1,198 @@
package notification
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
// Standard
"bytes"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"strconv"
"strings"
)
type Pushover struct {
Description string
UserKey string `json:"user_key"`
APIKey string `json:"api_key"`
DeviceName string `json:"device_name"`
Prio int
AcknowledgeURL string
logger *slog.Logger
exists bool
updated Service
}
func init() {
allServices = append(allServices, &Pushover{})
}
func NewPushover(config []byte, prio int, ackURL string) (instance *Pushover, err error) {
instance = new(Pushover)
err = json.Unmarshal(config, &instance)
if err != nil {
err = werr.Wrap(err).WithData(config)
return
}
instance.Prio = prio
instance.AcknowledgeURL = ackURL
return instance, nil
}
func (po *Pushover) SetLogger(l *slog.Logger) {
po.logger = l
}
func (po *Pushover) GetType() string {
return "PUSHOVER"
}
func (po *Pushover) GetPrio() int {
return po.Prio
}
func (po *Pushover) SetPrio(prio int) {
po.Prio = prio
}
func (po *Pushover) SetExists(exists bool) {
po.exists = exists
}
func (po Pushover) Exists() bool {
return po.exists
}
func (po *Pushover) String() string {
if po.Description != "" {
return po.Description
}
return fmt.Sprintf("%s, %s", po.UserKey, po.APIKey)
}
func (po Pushover) Send(problemID int, msg []byte) (err error) {
var req *http.Request
var res *http.Response
pushoverRequest, _ := json.Marshal(map[string]string{
"token": po.APIKey,
"user": po.UserKey,
"device": po.DeviceName,
"message": string(msg),
})
req, err = http.NewRequest("POST", "https://api.pushover.net/1/messages.json", bytes.NewReader(pushoverRequest))
if err != nil {
err = werr.Wrap(err).WithData(struct {
UserKey string
APIKey string
Msg []byte
}{
po.UserKey,
po.APIKey,
msg,
},
)
return
}
//ackURL := fmt.Sprintf("http, OK, %s/notification/ack?problemID=%d", po.AcknowledgeURL, problemID)
req.Header.Add("Content-Type", "application/json")
res, err = http.DefaultClient.Do(req)
if err != nil {
err = werr.Wrap(err)
return
}
body, _ := io.ReadAll(res.Body)
poResp := struct {
Status int
Errors []string
}{}
err = json.Unmarshal(body, &poResp)
if err != nil {
err = werr.Wrap(err).WithData(body)
return
}
if poResp.Status != 1 {
err = werr.New("%s", strings.Join(poResp.Errors, ", "))
return
}
if res.StatusCode != 200 {
err = werr.New("Invalid Pushover response").WithData(body)
return
}
return
}
func (po *Pushover) Update(values url.Values) (err error) {
updated := Pushover{}
po.updated = &updated
// Prio
updated.Prio, err = strconv.Atoi(values.Get("prio"))
if err != nil {
return werr.Wrap(err)
}
// Description
updated.Description = strings.TrimSpace(values.Get("description"))
// API (application) key
givenAPIKey := values.Get("api_key")
if strings.TrimSpace(givenAPIKey) == "" {
return werr.New("API key cannot be empty")
}
updated.APIKey = strings.TrimSpace(givenAPIKey)
// User key
givenUserKey := values.Get("user_key")
if strings.TrimSpace(givenUserKey) == "" {
return werr.New("User key cannot be empty")
}
updated.UserKey = strings.TrimSpace(givenUserKey)
// Device name
updated.DeviceName = strings.TrimSpace(values.Get("device_name"))
return
}
func (po *Pushover) Updated() Service {
return po.updated
}
func (po *Pushover) Commit() {
updatedPushover := po.updated.(*Pushover)
po.Prio = updatedPushover.Prio
po.Description = updatedPushover.Description
po.APIKey = updatedPushover.APIKey
po.UserKey = updatedPushover.UserKey
po.DeviceName = updatedPushover.DeviceName
}
func (po Pushover) JSON() []byte {
data := struct {
Description string
APIKey string `json:"api_key"`
UserKey string `json:"user_key"`
DeviceName string `json:"device_name"`
}{
po.Description,
po.APIKey,
po.UserKey,
po.DeviceName,
}
j, _ := json.Marshal(data)
return j
}

View File

@ -7,6 +7,7 @@ import (
// Standard
"encoding/json"
"log/slog"
"net/url"
"os/exec"
"strconv"
"strings"
@ -17,6 +18,13 @@ type Script struct {
Prio int
AcknowledgeURL string
logger *slog.Logger
exists bool
updated Service
}
func init() {
allServices = append(allServices, &Script{})
}
func NewScript(config []byte, prio int, ackURL string) (instance *Script, err error) {
@ -43,6 +51,22 @@ func (script *Script) GetPrio() int {
return script.Prio
}
func (script *Script) SetPrio(prio int) {
script.Prio = prio
}
func (script *Script) SetExists(exists bool) {
script.exists = exists
}
func (script Script) Exists() bool {
return script.exists
}
func (script *Script) String() string {
return script.Filename
}
func (script Script) Send(problemID int, msg []byte) (err error) {
var errbuf strings.Builder
cmd := exec.Command(script.Filename, strconv.Itoa(problemID), script.AcknowledgeURL, string(msg))
@ -68,3 +92,40 @@ func (script Script) Send(problemID int, msg []byte) (err error) {
return
}
func (script *Script) Update(values url.Values) (err error) {
updated := Script{}
script.updated = &updated
updated.Prio, err = strconv.Atoi(values.Get("prio"))
if err != nil {
return werr.Wrap(err)
}
givenFilename := values.Get("filename")
if strings.TrimSpace(givenFilename) == "" {
return werr.New("Filename cannot be empty")
}
updated.Filename = strings.TrimSpace(givenFilename)
return
}
func (script *Script) Updated() Service {
return script.updated
}
func (script *Script) Commit() {
updated := script.updated.(*Script)
script.Prio = updated.Prio
script.Filename = updated.Filename
}
func (script Script) JSON() []byte {
data := struct {
Filename string `json:"filename"`
}{
script.Filename,
}
j, _ := json.Marshal(data)
return j
}

View File

@ -1,11 +1,32 @@
package main
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
"github.com/jmoiron/sqlx"
// Internal
"smon/notification"
// Standard
"database/sql"
"encoding/json"
"time"
)
type NotificationSend struct {
Prio int
Service string
ID int
UUID string
Sent time.Time `db:"send"`
OK bool
Error sql.NullString
ErrorIndented string
Acknowledged bool
TriggerName string `db:"trigger_name"`
}
func notificationLog(notificationService *notification.Service, problemID int, err error) {
if err == nil {
logger.Info("notification", "service", (*notificationService).GetType(), "problemID", problemID, "prio", (*notificationService).GetPrio(), "ok", true)
@ -18,3 +39,61 @@ func notificationLog(notificationService *notification.Service, problemID int, e
logger.Error("notification", "service", (*notificationService).GetType(), "problemID", problemID, "prio", (*notificationService).GetPrio(), "ok", false, "error", err)
}
}
func notificationsSent(from, to time.Time) (nss []NotificationSend, err error) {
var rows *sqlx.Rows
rows, err = service.Db.Conn.Queryx(
`
SELECT
n.prio,
n.service,
COALESCE(t.name, '[NODATA]') AS trigger_name,
ns.id,
ns.uuid,
ns.send,
ns.ok,
ns.error::varchar,
ns.acknowledged
FROM public.notification_send ns
INNER JOIN notification n ON ns.notification_id = n.id
LEFT JOIN problem p ON ns.problem_id = p.id
LEFT JOIN "trigger" t ON p.trigger_id = t.id
WHERE
ns.send >= $1 AND
ns.send <= $2
ORDER BY
send DESC
`,
from,
to,
)
if err != nil {
err = werr.Wrap(err)
return
}
defer rows.Close()
for rows.Next() {
ns := NotificationSend{}
err = rows.StructScan(&ns)
if err != nil {
err = werr.Wrap(err)
return
}
// Error contains json (can be NULL),
// and can at least be presented indented.
foo := make(map[string]any)
json.Unmarshal([]byte(ns.Error.String), &foo)
var j []byte
j, err = json.MarshalIndent(foo, "", " ")
ns.ErrorIndented = string(j)
nss = append(nss, ns)
}
return
}

View File

@ -3,6 +3,7 @@ package main
import (
// External
werr "git.gibonuddevalla.se/go/wrappederror"
"github.com/lib/pq"
// Internal
"smon/notification"
@ -67,13 +68,77 @@ func InitNotificationManager() (nm notification.Manager, err error) { // {{{
return
} // }}}
func UpdateNotificationService(svc notification.Service) (created bool, err error) { // {{{
if svc.Exists() {
_, err = service.Db.Conn.Exec(
`
UPDATE public.notification
SET
prio=$2,
configuration=$3
WHERE
prio=$1
`,
svc.GetPrio(),
svc.Updated().GetPrio(),
svc.Updated().JSON(),
)
} else {
_, err = service.Db.Conn.Exec(
`
INSERT INTO public.notification(prio, configuration, service)
VALUES($1, $2, $3)
`,
svc.Updated().GetPrio(),
svc.Updated().JSON(),
svc.GetType(),
)
created = true
}
if err != nil {
// Check if this is just a duplicated prio, which isn't allowed.
pgErr, isPgErr := err.(*pq.Error)
if isPgErr && pgErr.Code == "23505" {
return false, werr.New("Prio %d is already used by another service", svc.Updated().GetPrio())
}
return false, werr.Wrap(err).WithData(
struct {
Prio int
Configuration []byte
}{
svc.GetPrio(),
svc.JSON(),
},
)
}
return
} // }}}
func DeleteNotificationService(prio int) (err error) { // {{{
_, err = service.Db.Conn.Exec(
`
DELETE FROM public.notification
WHERE
prio = $1
`,
prio,
)
if err != nil {
return werr.Wrap(err).WithData(struct{ Prio int }{prio})
}
return
} // }}}
func AcknowledgeNotification(uuid string) (err error) { // {{{
/*
_, err = service.Db.Conn.Exec(`UPDATE schedule SET acknowledged=true WHERE schedule_uuid=$1`, uuid)
if err != nil {
err = werr.Wrap(err).WithData(uuid)
}
_, err = service.Db.Conn.Exec(`UPDATE schedule SET acknowledged=true WHERE schedule_uuid=$1`, uuid)
if err != nil {
err = werr.Wrap(err).WithData(uuid)
}
*/
return
} // }}}

12
page.go
View File

@ -2,7 +2,7 @@ package main
import (
// External
we "git.gibonuddevalla.se/go/wrappederror"
werr "git.gibonuddevalla.se/go/wrappederror"
// Standard
"fmt"
@ -15,16 +15,17 @@ type Page struct {
LAYOUT string
PAGE string
MENU string
CONFIG map[string]string
Label string
Icon string
Data any
}
func (p *Page) Render(w http.ResponseWriter) {
func (p *Page) Render(w http.ResponseWriter, r *http.Request) {
tmpl, err := getPage(p.LAYOUT, p.PAGE)
if err != nil {
httpError(w, we.Wrap(err).Log())
httpError(w, werr.Wrap(err).Log())
return
}
@ -47,6 +48,9 @@ func (p *Page) Render(w http.ResponseWriter) {
"LAYOUT": p.LAYOUT,
"PAGE": p.PAGE,
"MENU": p.MENU,
"CONFIG": smonConfig.Settings,
"ERROR": r.URL.Query().Get("_err"),
"Label": p.Label,
"Icon": p.Icon,
"Data": p.Data,
@ -54,6 +58,6 @@ func (p *Page) Render(w http.ResponseWriter) {
err = tmpl.Execute(w, data)
if err != nil {
httpError(w, we.Wrap(err).Log())
httpError(w, werr.Wrap(err).Log())
}
}

View File

@ -2,26 +2,31 @@ package main
import (
// External
we "git.gibonuddevalla.se/go/wrappederror"
werr "git.gibonuddevalla.se/go/wrappederror"
// Standard
"database/sql"
"encoding/json"
"fmt"
"sort"
"strings"
"time"
)
type Problem struct {
ID int
Start time.Time
End sql.NullTime
Acknowledged bool
TriggerID int `json:"trigger_id"`
TriggerName string `json:"trigger_name"`
AreaName string `json:"area_name"`
SectionName string `json:"section_name"`
}
type Problem struct { // {{{
ID int
Start time.Time
End time.Time
Acknowledged bool
Datapoints map[string]any
DatapointValues map[string]any `json:"datapoints"`
TriggerID int `json:"trigger_id"`
TriggerName string `json:"trigger_name"`
AreaName string `json:"area_name"`
SectionName string `json:"section_name"`
} // }}}
func ProblemsRetrieve() (problems []Problem, err error) {
func ProblemsRetrieve(showCurrent bool, from, to time.Time) (problems []Problem, err error) { // {{{
problems = []Problem{}
row := service.Db.Conn.QueryRow(`
SELECT
@ -30,28 +35,39 @@ func ProblemsRetrieve() (problems []Problem, err error) {
(SELECT
p.id,
p.start,
p.end,
TO_CHAR(p.end, 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM') AS end,
p.acknowledged,
p.datapoints,
t.id AS trigger_id,
t.name AS trigger_name,
p.trigger_name AS trigger_name,
a.name AS area_name,
s.name AS section_name
FROM problem p
INNER JOIN "trigger" t ON p.trigger_id = t.id
INNER JOIN section s ON t.section_id = s.id
INNER JOIN area a ON s.area_id = a.id
LEFT JOIN "trigger" t ON p.trigger_id = t.id
LEFT JOIN section s ON t.section_id = s.id
LEFT JOIN area a ON s.area_id = a.id
WHERE
p.end IS NULL
CASE
WHEN NOT $1 THEN p.end IS NULL
WHEN $1 THEN
p.start >= $2 AND
(
p.end IS NULL OR
p.end <= $3
)
END
ORDER BY
p.start DESC)
UNION ALL
(SELECT
-1 AS id,
null,
dp.last_value,
null,
false,
'{}',
-1 AS trigger_id,
CONCAT(
'NODATA: ',
@ -64,13 +80,16 @@ func ProblemsRetrieve() (problems []Problem, err error) {
dp.nodata_is_problem
ORDER BY
dp.name ASC)
) AS problems
`)
) AS problems`,
showCurrent,
from,
to,
)
var jsonBody []byte
err = row.Scan(&jsonBody)
if err != nil {
err = we.Wrap(err)
err = werr.Wrap(err)
return
}
@ -80,12 +99,11 @@ func ProblemsRetrieve() (problems []Problem, err error) {
err = json.Unmarshal(jsonBody, &problems)
if err != nil {
err = we.Wrap(err)
err = werr.Wrap(err)
}
return
}
func ProblemStart(trigger Trigger) (problemID int, err error) {
} // }}}
func ProblemStart(trigger Trigger) (problemID int, err error) { // {{{
row := service.Db.Conn.QueryRow(`
SELECT COUNT(id)
FROM problem
@ -99,22 +117,28 @@ func ProblemStart(trigger Trigger) (problemID int, err error) {
var openProblems int
err = row.Scan(&openProblems)
if err != nil && err != sql.ErrNoRows {
err = we.Wrap(err).WithData(trigger.ID)
err = werr.Wrap(err).WithData(trigger.ID)
return
}
// Open up a new problem if no open exists.
if openProblems == 0 {
row = service.Db.Conn.QueryRow(`INSERT INTO problem(trigger_id) VALUES($1) RETURNING id`, trigger.ID)
datapointValuesJson, _ := json.Marshal(trigger.DatapointValues)
row = service.Db.Conn.QueryRow(
`INSERT INTO problem(trigger_id, trigger_name, datapoints, trigger_expression) VALUES($1, $2, $3, $4) RETURNING id`,
trigger.ID,
trigger.Name,
datapointValuesJson,
trigger.Expression,
)
err = row.Scan(&problemID)
if err != nil {
err = we.Wrap(err).WithData(trigger)
err = werr.Wrap(err).WithData(trigger)
}
}
return
}
func ProblemClose(trigger Trigger) (problemID int, err error) {
} // }}}
func ProblemClose(trigger Trigger) (problemID int, err error) { // {{{
row := service.Db.Conn.QueryRow(`UPDATE problem SET "end"=NOW() WHERE trigger_id=$1 AND "end" IS NULL RETURNING id`, trigger.ID)
err = row.Scan(&problemID)
@ -124,17 +148,51 @@ func ProblemClose(trigger Trigger) (problemID int, err error) {
}
if err != nil {
err = we.Wrap(err).WithData(trigger)
err = werr.Wrap(err).WithData(trigger)
return
}
return
}
func ProblemAcknowledge(id int, state bool) (err error) {
} // }}}
func ProblemAcknowledge(id int, state bool) (err error) { // {{{
_, err = service.Db.Conn.Exec(`UPDATE problem SET "acknowledged"=$2 WHERE id=$1`, id, state)
if err != nil {
err = we.Wrap(err).WithData(id)
err = werr.Wrap(err).WithData(id)
return
}
return
}
} // }}}
func (p Problem) FormattedValues() string { // {{{
out := []string{}
for key, val := range p.DatapointValues {
var keyval string
switch val.(type) {
case int:
keyval = fmt.Sprintf("%s: %d", key, val)
case string:
if str, ok := val.(string); ok {
timeVal, err := time.Parse(time.RFC3339, str)
if err == nil {
formattedTime := timeVal.Format("2006-01-02 15:04:05")
keyval = fmt.Sprintf("%s: %s", key, formattedTime)
} else {
keyval = fmt.Sprintf("%s: %s", key, val)
}
}
default:
keyval = fmt.Sprintf("%s: %v", key, val)
}
out = append(out, keyval)
}
sort.Strings(out)
return strings.Join(out, "\n")
} // }}}
func (p Problem) IsArchived() bool { // {{{
return !p.End.IsZero()
} // }}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
screenshots/datapoints.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
screenshots/problems.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
screenshots/triggers.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

5
sql/00018.sql Normal file
View File

@ -0,0 +1,5 @@
CREATE TABLE public."configuration" (
setting varchar NOT NULL,
value varchar DEFAULT '' NOT NULL,
CONSTRAINT configuration_pk PRIMARY KEY (setting)
);

1
sql/00019.sql Normal file
View File

@ -0,0 +1 @@
INSERT INTO public.configuration(setting, value) VALUES('THEME', 'gruvbox');

1
sql/00020.sql Normal file
View File

@ -0,0 +1 @@
INSERT INTO public.configuration(setting, value) VALUES('TIMEZONE', 'Europe/Stockholm');

1
sql/00021.sql Normal file
View File

@ -0,0 +1 @@
CREATE INDEX datapoint_value_ts_idx ON public.datapoint_value (ts);

4
sql/00022.sql Normal file
View File

@ -0,0 +1,4 @@
ALTER TABLE public.problem ALTER COLUMN trigger_id DROP NOT NULL;
ALTER TABLE public.problem ADD COLUMN datapoints JSONB NOT NULL DEFAULT '{}';
ALTER TABLE public.problem DROP CONSTRAINT problem_trigger_fk;
ALTER TABLE public.problem ADD CONSTRAINT problem_trigger_fk FOREIGN KEY (trigger_id) REFERENCES public."trigger"(id) ON DELETE SET NULL ON UPDATE CASCADE;

1
sql/00023.sql Normal file
View File

@ -0,0 +1 @@
ALTER TABLE public.problem ADD COLUMN trigger_expression VARCHAR NOT NULL DEFAULT '';

1
sql/00024.sql Normal file
View File

@ -0,0 +1 @@
ALTER TABLE public.problem ADD COLUMN trigger_name VARCHAR NOT NULL DEFAULT '[Unknown]';

1
sql/00025.sql Normal file
View File

@ -0,0 +1 @@
ALTER TYPE notification_type ADD VALUE 'PUSHOVER';

62
sql/00026.sql Normal file
View File

@ -0,0 +1,62 @@
/* Adding last values to the datapoint table since they are a regularly used value. */
ALTER TABLE public.datapoint ADD COLUMN last_value_id int4 NULL;
ALTER TABLE public.datapoint ADD COLUMN last_value_int int8 NULL;
ALTER TABLE public.datapoint ADD COLUMN last_value_string varchar NULL;
ALTER TABLE public.datapoint ADD COLUMN last_value_datetime timestamptz NULL;
/* Once-run query to update it to the latest, to avoid user having to wait for the next entry. */
UPDATE public.datapoint AS dp
SET
last_value_id = dpv.id,
last_value_int = dpv.value_int,
last_value_string = dpv.value_string,
last_value_datetime = dpv.value_datetime
FROM (
SELECT
dp.id AS datapoint_id,
dpv.id,
dpv.value_int,
dpv.value_string,
dpv.value_datetime
FROM public.datapoint dp
LEFT JOIN (
SELECT
*,
row_number() OVER (PARTITION BY "datapoint_id" ORDER BY ts DESC) AS rn
FROM datapoint_value
) dpv ON dpv.datapoint_id = dp.id AND rn = 1
) AS dpv
WHERE
dpv.datapoint_id = dp.id;
/* A trigger keeps the value current without bugs introduced in software missing the entry. */
CREATE OR REPLACE FUNCTION datapoint_entry()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
UPDATE public.datapoint
SET
nodata_is_problem = false,
last_value = NEW.ts,
last_value_id = NEW.id,
last_value_int = NEW.value_int,
last_value_string = NEW.value_string,
last_value_datetime = NEW.value_datetime
WHERE
id = NEW.datapoint_id;
RETURN NEW;
END;
$$;
CREATE TRIGGER datapoint_entry
AFTER INSERT
ON public.datapoint_value
FOR EACH ROW
EXECUTE PROCEDURE datapoint_entry();

22
sql/00027.sql Normal file
View File

@ -0,0 +1,22 @@
/* Updating a datapoint name also updates the jsonb array entry */
CREATE OR REPLACE FUNCTION update_triggers_datapoint_name()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
UPDATE "trigger"
SET
datapoints = (datapoints - OLD.name) || jsonb_build_array(NEW.name)
WHERE
datapoints ? OLD.name;
RETURN NEW;
END;
$$;
CREATE TRIGGER datapoint_renamed
AFTER UPDATE
ON public.datapoint
FOR EACH ROW
EXECUTE PROCEDURE update_triggers_datapoint_name();

View File

@ -1,130 +0,0 @@
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
*:focus {
outline: none;
}
[onClick] {
cursor: pointer;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #282828;
font-family: sans-serif;
font-weight: 300;
color: #d5c4a1;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #b8bb26;
font-weight: 800;
}
a {
color: #3f9da1;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #202020;
color: #d5c4a1;
padding: 4px 8px;
border: none;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #202020;
color: #d5c4a1;
padding: 8px 32px;
border: 1px solid #535353;
font-size: 1em;
height: 3em;
}
button:focus {
background: #333;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #4e4e4e;
}
span.date {
color: #d5c4a1;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #d5c4a1;
}
span.seconds {
display: none;
}
label {
user-select: none;
}
.description {
border: 1px solid #737373;
color: #3f9da1;
background: #202020;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
}
#areas .area > .name {
display: grid;
grid-template-columns: 1fr min-content;
grid-gap: 0px 16px;
align-items: center;
padding-left: 16px;
padding-right: 8px;
}
#areas .area > .name img {
margin-top: 3px;
margin-bottom: 4px;
height: 16px;
}
#areas .area .section.configuration {
display: grid;
grid-template-columns: 1fr min-content;
grid-gap: 0 16px;
margin-top: 8px;
margin-bottom: 8px;
}
#areas .area .section.configuration:last-child {
margin-bottom: 16px;
}
#areas .area .section.configuration img {
height: 16px;
}

View File

@ -1,168 +0,0 @@
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
*:focus {
outline: none;
}
[onClick] {
cursor: pointer;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #282828;
font-family: sans-serif;
font-weight: 300;
color: #d5c4a1;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #b8bb26;
font-weight: 800;
}
a {
color: #3f9da1;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #202020;
color: #d5c4a1;
padding: 4px 8px;
border: none;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #202020;
color: #d5c4a1;
padding: 8px 32px;
border: 1px solid #535353;
font-size: 1em;
height: 3em;
}
button:focus {
background: #333;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #4e4e4e;
}
span.date {
color: #d5c4a1;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #d5c4a1;
}
span.seconds {
display: none;
}
label {
user-select: none;
}
.description {
border: 1px solid #737373;
color: #3f9da1;
background: #202020;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
}
#datapoints {
display: grid;
grid-template-columns: repeat(6, min-content);
grid-gap: 8px 16px;
margin-top: 16px;
}
#datapoints .group {
font-size: 1.1em;
font-weight: bold;
color: #b8bb26;
margin-top: 1.5em;
padding-bottom: 4px;
}
#datapoints h2 {
border-bottom: unset;
}
#datapoints .header {
font-weight: 800;
font-size: 0.85em;
color: #d5c4a1;
}
#datapoints div {
white-space: nowrap;
align-self: center;
}
#datapoints .icons {
display: flex;
gap: 12px;
align-items: center;
}
#datapoints img.info {
height: 20px;
}
#values {
display: grid;
grid-template-columns: repeat(2, min-content);
gap: 16px;
white-space: nowrap;
}
.widgets {
display: grid;
grid-template-columns: min-content 1fr;
gap: 8px 16px;
}
.widgets .label {
margin-top: 4px;
white-space: nowrap;
}
.widgets input[type="text"],
.widgets textarea {
width: 100%;
}
.widgets .datapoints {
display: grid;
grid-template-columns: min-content 1fr;
gap: 6px 8px;
font-family: "Roboto Mono", monospace;
margin-bottom: 8px;
}
.widgets .action {
display: grid;
grid-template-columns: min-content min-content;
grid-gap: 8px;
}

View File

@ -0,0 +1,46 @@
#areas .area > .name {
display: grid;
grid-template-columns: 1fr min-content;
grid-gap: 0px 16px;
align-items: center;
padding-left: 16px;
padding-right: 8px;
}
#areas .area > .name img {
margin-top: 3px;
margin-bottom: 4px;
height: 16px;
}
#areas .area .section.configuration {
display: grid;
grid-template-columns: 1fr min-content;
grid-gap: 0 16px;
margin-top: 8px;
margin-bottom: 8px;
}
#areas .area .section.configuration:last-child {
margin-bottom: 16px;
}
#areas .area .section.configuration img {
height: 16px;
}
#services {
display: grid;
grid-template-columns: repeat(4, min-content);
gap: 10px 24px;
background-color: #2979b8;
width: min-content;
padding: 16px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
margin-top: 16px;
}
#services .header {
font-weight: bold;
}
#services div {
white-space: nowrap;
}
#services img.delete {
height: 16px;
}

View File

@ -0,0 +1,104 @@
#datapoints-filter.invalid-regex {
background-color: #ffd5d5;
}
#datapoints {
display: grid;
grid-template-columns: repeat(6, min-content);
grid-gap: 8px 16px;
margin-top: 16px;
background-color: #2979b8;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
#datapoints .group {
font-size: 1.1em;
font-weight: bold;
color: #2c6e97;
margin-top: 1.5em;
padding-bottom: 4px;
}
#datapoints h2 {
border-bottom: unset;
}
#datapoints .header {
font-weight: 800;
font-size: 0.85em;
color: #7bb8eb;
}
#datapoints .hidden {
display: none !important;
}
#datapoints div {
white-space: nowrap;
align-self: center;
}
#datapoints .icons {
display: flex;
gap: 12px;
align-items: center;
}
#datapoints img.info {
height: 20px;
}
#values {
display: grid;
grid-template-columns: repeat(2, min-content);
gap: 16px;
white-space: nowrap;
background-color: #2979b8;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
margin-top: 32px;
}
#values .header {
color: #000;
font-weight: bold;
}
.widgets {
display: grid;
grid-template-columns: min-content 1fr;
gap: 8px 16px;
}
.widgets .label {
margin-top: 4px;
white-space: nowrap;
}
.widgets input[type="text"],
.widgets textarea {
width: 100%;
}
.widgets .datapoints {
display: grid;
grid-template-columns: min-content 1fr;
gap: 6px 8px;
font-family: "Roboto Mono", monospace;
margin-bottom: 8px;
}
.widgets .action {
display: grid;
grid-template-columns: min-content min-content;
grid-gap: 8px;
}
.value-selector {
display: grid;
grid-template-columns: repeat(2, min-content);
grid-gap: 4px 16px;
margin-top: 16px;
}
.value-selector button {
width: 100px;
justify-self: end;
margin-top: 16px;
}
.graph {
width: 99%;
border: 1px solid #aaa;
margin-top: 16px;
}
.graph #graph-values {
height: calc(100vh - 200px);
}

View File

@ -0,0 +1,58 @@
body {
background-color: #f8f8f8;
background-image: url('/images/v0/default_light/background.svg');
}
.widgets .action #run-result {
background-color: #fff !important;
border: 1px solid #ccc;
}
#menu .entry .label {
color: #7bb8eb !important;
}
#menu .entry.selected .label {
color: #fff !important;
}
input[type="text"],
textarea,
select {
border: 1px solid #ccc;
}
.description {
border: 1px solid #ccc;
}
button {
background: #2979b8;
color: #fff;
border: 1px solid #2e84cb;
}
button:focus {
background: #2979b8;
}
#areas .area {
background: #fff !important;
border: 1px solid #2979b8;
box-shadow: 5px 5px 8px 0px rgba(0, 0, 0, 0.25);
}
#areas .area .name {
border-top-left-radius: unset;
border-top-right-radius: unset;
}
#areas .area .section .name {
font-weight: normal;
}
dialog {
border-radius: 8px;
}
dialog,
#datapoints,
#problems-list,
#acknowledged-list,
#values,
#services,
#notifications,
#group,
.table {
background-color: #fff !important;
border: 1px solid #ddd;
box-shadow: 5px 5px 8px 0px rgba(0, 0, 0, 0.25);
}

View File

@ -0,0 +1,23 @@
body {
background-image: url(/images/v0/gruvbox/background.svg);
}
#menu {
box-shadow: 2px 0px 5px 3px rgba(0, 0, 0, 0.25);
}
#areas .area {
box-shadow: 5px 5px 15px 0px rgba(0, 0, 0, 0.5);
}
#page-error {
border: unset;
color: #fff;
background-color: #a00;
text-align: center;
}
span.error {
color: #f66;
}
input[type="datetime-local"] {
background-color: #1b4e78;
color: #ccc;
border: 1px solid #535353;
}

View File

View File

@ -0,0 +1,291 @@
.table {
display: grid;
grid-gap: 6px 16px;
align-items: center;
margin-top: 32px;
margin-bottom: 32px;
background-color: #2979b8;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.table .row {
grid-column: 1 / -1;
}
.table > div {
white-space: nowrap;
line-height: 24px;
}
.table .header {
font-size: 0.85em;
font-weight: bold;
color: #7bb8eb;
line-height: unset !important;
}
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
*:focus {
outline: none;
}
[onClick] {
cursor: pointer;
}
#page-error {
display: none;
position: fixed;
z-index: 8192;
width: 500px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 48px;
border: 2px solid #a00;
font-weight: bold;
background: #fff;
box-shadow: 10px 10px 15px 0px rgba(0, 0, 0, 0.25);
}
#page-error.show {
display: block;
position: fixed;
}
#page-error .close {
position: absolute;
top: 16px;
right: 16px;
font-size: 1.5em;
}
#layout {
display: grid;
grid-template-areas: "menu content";
grid-template-columns: 128px 1fr;
height: 100vh;
}
#menu {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: repeat(32, min-content);
align-items: start;
grid-area: menu;
background: #1b4e78;
}
#menu .entry.selected {
background: #2979b8;
}
#menu .entry.selected a {
color: #000 !important;
}
#menu .entry > a {
display: grid;
justify-items: center;
grid-template-rows: 38px 16px;
padding: 16px;
color: #7bb8eb;
text-decoration: none;
}
#menu .entry > a img {
display: block;
width: 32px;
}
#menu .entry > a .label {
font-size: 0.9em;
font-weight: bold;
}
#page {
grid-area: content;
padding: 32px;
}
#page .page-label {
display: grid;
grid-template-columns: min-content 1fr;
grid-gap: 12px;
align-items: center;
margin-bottom: 32px;
}
#page .page-label div {
font-weight: 800;
font-size: 1.5em;
color: #1b4e78;
}
#page .page-label img {
display: block;
}
#areas {
display: flex;
flex-wrap: wrap;
gap: 24px;
margin-top: 16px;
}
#areas .area {
background: #2979b8;
border-radius: 4px;
}
#areas .area > .name {
background: #1b4e78;
color: #fff;
font-weight: 800;
padding: 4px 16px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
#areas .area .section {
margin: 8px 16px;
margin-top: 12px;
margin-bottom: 20px;
}
#areas .area .section:last-child {
margin-bottom: 12px;
}
#areas .area .section .create {
display: grid;
grid-template-columns: min-content min-content;
grid-gap: 8px;
white-space: nowrap;
}
#areas .area .section .create .new {
font-weight: 800;
}
#areas .area .section > .name {
font-weight: 800;
}
dialog {
background: #1b4e78;
border: 1px solid #3f90d4;
color: #555;
box-shadow: 10px 10px 15px 0px rgba(0, 0, 0, 0.25);
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #fff;
font-family: sans-serif;
font-weight: 300;
color: #555;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
margin-top: 32px;
font-size: 1.5em;
color: #1b4e78;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #2c6e97;
font-weight: 800;
}
a {
color: #2c6e97;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #fff;
color: #555;
padding: 4px 8px;
border: 1px solid #484848;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #1b4e78;
color: #555;
padding: 8px 32px;
border: 1px solid #2e84cb;
font-size: 1em;
height: 3em;
}
button:focus {
background: #2979b8;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #d9d9d9;
}
span.date {
color: #555;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #555;
}
span.seconds {
display: none;
}
span.ok {
color: #0a0;
}
span.error {
color: #a00;
}
label {
user-select: none;
}
.description {
border: 1px solid #123450;
color: #2c6e97;
background: #fff;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
}
#time-selector {
position: absolute;
top: 16px;
right: 16px;
display: grid;
grid-template-columns: 8px repeat(2, min-content) 8px min-content 8px 1px 8px repeat(3, min-content) 8px repeat(3, min-content) 8px 1px 8px repeat(2, min-content) 8px;
grid-gap: 6px 8px;
align-items: center;
width: min-content;
background-color: #fff;
border: 1px solid #2979b8;
border-radius: 6px;
}
#time-selector.hidden {
display: none;
}
#time-selector .vertical-line {
background-color: #2979b8;
}
#time-selector .header {
padding-top: 12px;
font-weight: bold;
font-size: 0.85em;
}
#time-selector button {
width: 100px;
margin-top: 12px;
justify-self: end;
}
#time-selector div {
white-space: nowrap;
}

View File

@ -0,0 +1,20 @@
#notifications {
display: grid;
grid-template-columns: repeat(5, min-content);
grid-gap: 4px 16px;
margin-top: 96px;
margin-bottom: 32px;
background-color: #2979b8;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
#notifications div {
white-space: nowrap;
line-height: 24px;
}
#notifications .header {
font-weight: 800;
color: #7bb8eb;
}

View File

@ -0,0 +1,46 @@
#problems-list,
#acknowledged-list {
grid-template-columns: repeat(7, min-content);
}
#problems-list .trigger,
#acknowledged-list .trigger {
color: #1b4e78;
}
#problems-list img.acknowledge,
#acknowledged-list img.acknowledge {
height: 16px;
}
#problems-list .info,
#acknowledged-list .info {
margin-right: 8px;
}
#problems-list .icons,
#acknowledged-list .icons {
display: grid;
grid-template-columns: min-content min-content;
align-items: center;
}
#acknowledged-list.hidden {
display: none;
}
#area-grouped {
display: flex;
flex-wrap: wrap;
gap: 24px;
margin-top: 16px;
align-items: flex-start;
}
#area-grouped .area {
grid-template-columns: repeat(5, min-content);
}
#area-grouped .area .section {
padding: 4px 10px;
border-radius: 5px;
background: #2979b8;
color: #fff;
width: min-content;
margin-bottom: 8px;
}
.hidden {
display: none;
}

View File

@ -0,0 +1,25 @@
.table {
display: grid;
grid-gap: 6px 16px;
align-items: center;
margin-top: 32px;
margin-bottom: 32px;
background-color: #2979b8;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.table .row {
grid-column: 1 / -1;
}
.table > div {
white-space: nowrap;
line-height: 24px;
}
.table .header {
font-size: 0.85em;
font-weight: bold;
color: #7bb8eb;
line-height: unset !important;
}

View File

@ -0,0 +1,51 @@
.widgets {
display: grid;
grid-template-columns: min-content 1fr;
gap: 8px 16px;
}
.widgets .label {
margin-top: 4px;
}
.widgets input[type="text"],
.widgets textarea {
width: 100%;
}
.widgets .datapoints {
font: "Roboto Mono", monospace;
display: grid;
grid-template-columns: repeat(4, min-content);
gap: 6px 8px;
margin-bottom: 8px;
white-space: nowrap;
}
.widgets .datapoints div {
white-space: nowrap;
}
.widgets .datapoints .invalid {
color: #c83737;
}
.widgets .datapoints .delete img {
height: 16px;
}
.widgets .datapoints .values img {
height: 16px;
width: 16px;
}
.widgets .action {
display: grid;
grid-template-columns: min-content min-content 1fr;
grid-gap: 8px;
}
.widgets .action #run-result {
font-family: 'Roboto Mono', monospace;
margin-left: 16px;
padding: 16px;
background: #1b4e78;
min-height: 8em;
}
.widgets .action #run-result.ok {
color: #555;
}
.widgets .action #run-result.error {
color: #fb4934;
}

View File

@ -0,0 +1,13 @@
#areas .area .section .triggers .trigger {
display: grid;
grid-template-columns: min-content 1fr min-content;
grid-gap: 8px;
align-items: center;
margin-top: 8px;
}
#areas .area .section .triggers .trigger img {
height: 16px;
}
#areas .area .section .triggers .trigger .label {
color: inherit;
}

View File

@ -0,0 +1,46 @@
#areas .area > .name {
display: grid;
grid-template-columns: 1fr min-content;
grid-gap: 0px 16px;
align-items: center;
padding-left: 16px;
padding-right: 8px;
}
#areas .area > .name img {
margin-top: 3px;
margin-bottom: 4px;
height: 16px;
}
#areas .area .section.configuration {
display: grid;
grid-template-columns: 1fr min-content;
grid-gap: 0 16px;
margin-top: 8px;
margin-bottom: 8px;
}
#areas .area .section.configuration:last-child {
margin-bottom: 16px;
}
#areas .area .section.configuration img {
height: 16px;
}
#services {
display: grid;
grid-template-columns: repeat(4, min-content);
gap: 10px 24px;
background-color: #333;
width: min-content;
padding: 16px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
margin-top: 16px;
}
#services .header {
font-weight: bold;
}
#services div {
white-space: nowrap;
}
#services img.delete {
height: 16px;
}

View File

@ -0,0 +1,104 @@
#datapoints-filter.invalid-regex {
background-color: #ffd5d5;
}
#datapoints {
display: grid;
grid-template-columns: repeat(6, min-content);
grid-gap: 8px 16px;
margin-top: 16px;
background-color: #333;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
#datapoints .group {
font-size: 1.1em;
font-weight: bold;
color: #b8bb26;
margin-top: 1.5em;
padding-bottom: 4px;
}
#datapoints h2 {
border-bottom: unset;
}
#datapoints .header {
font-weight: 800;
font-size: 0.85em;
color: #777;
}
#datapoints .hidden {
display: none !important;
}
#datapoints div {
white-space: nowrap;
align-self: center;
}
#datapoints .icons {
display: flex;
gap: 12px;
align-items: center;
}
#datapoints img.info {
height: 20px;
}
#values {
display: grid;
grid-template-columns: repeat(2, min-content);
gap: 16px;
white-space: nowrap;
background-color: #333;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
margin-top: 32px;
}
#values .header {
color: #f7edd7;
font-weight: bold;
}
.widgets {
display: grid;
grid-template-columns: min-content 1fr;
gap: 8px 16px;
}
.widgets .label {
margin-top: 4px;
white-space: nowrap;
}
.widgets input[type="text"],
.widgets textarea {
width: 100%;
}
.widgets .datapoints {
display: grid;
grid-template-columns: min-content 1fr;
gap: 6px 8px;
font-family: "Roboto Mono", monospace;
margin-bottom: 8px;
}
.widgets .action {
display: grid;
grid-template-columns: min-content min-content;
grid-gap: 8px;
}
.value-selector {
display: grid;
grid-template-columns: repeat(2, min-content);
grid-gap: 4px 16px;
margin-top: 16px;
}
.value-selector button {
width: 100px;
justify-self: end;
margin-top: 16px;
}
.graph {
width: 99%;
border: 1px solid #aaa;
margin-top: 16px;
}
.graph #graph-values {
height: calc(100vh - 200px);
}

View File

@ -0,0 +1,58 @@
body {
background-color: #f8f8f8;
background-image: url('/images/v0/default_light/background.svg');
}
.widgets .action #run-result {
background-color: #fff !important;
border: 1px solid #ccc;
}
#menu .entry .label {
color: #777 !important;
}
#menu .entry.selected .label {
color: #fff !important;
}
input[type="text"],
textarea,
select {
border: 1px solid #ccc;
}
.description {
border: 1px solid #ccc;
}
button {
background: #333;
color: #fff;
border: 1px solid #535353;
}
button:focus {
background: #333;
}
#areas .area {
background: #fff !important;
border: 1px solid #333;
box-shadow: 5px 5px 8px 0px rgba(0, 0, 0, 0.25);
}
#areas .area .name {
border-top-left-radius: unset;
border-top-right-radius: unset;
}
#areas .area .section .name {
font-weight: normal;
}
dialog {
border-radius: 8px;
}
dialog,
#datapoints,
#problems-list,
#acknowledged-list,
#values,
#services,
#notifications,
#group,
.table {
background-color: #fff !important;
border: 1px solid #ddd;
box-shadow: 5px 5px 8px 0px rgba(0, 0, 0, 0.25);
}

View File

@ -0,0 +1,23 @@
body {
background-image: url(/images/v0/gruvbox/background.svg);
}
#menu {
box-shadow: 2px 0px 5px 3px rgba(0, 0, 0, 0.25);
}
#areas .area {
box-shadow: 5px 5px 15px 0px rgba(0, 0, 0, 0.5);
}
#page-error {
border: unset;
color: #fff;
background-color: #a00;
text-align: center;
}
span.error {
color: #f66;
}
input[type="datetime-local"] {
background-color: #202020;
color: #ccc;
border: 1px solid #535353;
}

View File

View File

@ -1,3 +1,28 @@
.table {
display: grid;
grid-gap: 6px 16px;
align-items: center;
margin-top: 32px;
margin-bottom: 32px;
background-color: #333;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.table .row {
grid-column: 1 / -1;
}
.table > div {
white-space: nowrap;
line-height: 24px;
}
.table .header {
font-size: 0.85em;
font-weight: bold;
color: #777;
line-height: unset !important;
}
html {
box-sizing: border-box;
}
@ -12,100 +37,34 @@ html {
[onClick] {
cursor: pointer;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #282828;
font-family: sans-serif;
font-weight: 300;
color: #d5c4a1;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #b8bb26;
font-weight: 800;
}
a {
color: #3f9da1;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #202020;
color: #d5c4a1;
padding: 4px 8px;
border: none;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #202020;
color: #d5c4a1;
padding: 8px 32px;
border: 1px solid #535353;
font-size: 1em;
height: 3em;
}
button:focus {
background: #333;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #4e4e4e;
}
span.date {
color: #d5c4a1;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #d5c4a1;
}
span.seconds {
#page-error {
display: none;
position: fixed;
z-index: 8192;
width: 500px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 48px;
border: 2px solid #a00;
font-weight: bold;
background: #fff;
box-shadow: 10px 10px 15px 0px rgba(0, 0, 0, 0.25);
}
label {
user-select: none;
#page-error.show {
display: block;
position: fixed;
}
.description {
border: 1px solid #737373;
color: #3f9da1;
background: #202020;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
#page-error .close {
position: absolute;
top: 16px;
right: 16px;
font-size: 1.5em;
}
#layout {
display: grid;
grid-template-areas: "menu content";
grid-template-columns: 96px 1fr;
grid-template-columns: 128px 1fr;
height: 100vh;
}
#menu {
@ -125,9 +84,7 @@ label {
#menu .entry > a {
display: grid;
justify-items: center;
grid-template-rows: 38px
16px
;
grid-template-rows: 38px 16px;
padding: 16px;
color: #777;
text-decoration: none;
@ -162,7 +119,7 @@ label {
#areas {
display: flex;
flex-wrap: wrap;
gap: 12px;
gap: 24px;
margin-top: 16px;
}
#areas .area {
@ -203,3 +160,132 @@ dialog {
color: #d5c4a1;
box-shadow: 10px 10px 15px 0px rgba(0, 0, 0, 0.25);
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #282828;
font-family: sans-serif;
font-weight: 300;
color: #d5c4a1;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
margin-top: 32px;
font-size: 1.5em;
color: #fb4934;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #b8bb26;
font-weight: 800;
}
a {
color: #3f9da1;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #282828;
color: #d5c4a1;
padding: 4px 8px;
border: 1px solid #484848;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #202020;
color: #d5c4a1;
padding: 8px 32px;
border: 1px solid #535353;
font-size: 1em;
height: 3em;
}
button:focus {
background: #333;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #4e4e4e;
}
span.date {
color: #d5c4a1;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #d5c4a1;
}
span.seconds {
display: none;
}
span.ok {
color: #0a0;
}
span.error {
color: #a00;
}
label {
user-select: none;
}
.description {
border: 1px solid #737373;
color: #3f9da1;
background: #282828;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
}
#time-selector {
position: absolute;
top: 16px;
right: 16px;
display: grid;
grid-template-columns: 8px repeat(2, min-content) 8px min-content 8px 1px 8px repeat(3, min-content) 8px repeat(3, min-content) 8px 1px 8px repeat(2, min-content) 8px;
grid-gap: 6px 8px;
align-items: center;
width: min-content;
background-color: #282828;
border: 1px solid #333;
border-radius: 6px;
}
#time-selector.hidden {
display: none;
}
#time-selector .vertical-line {
background-color: #333;
}
#time-selector .header {
padding-top: 12px;
font-weight: bold;
font-size: 0.85em;
}
#time-selector button {
width: 100px;
margin-top: 12px;
justify-self: end;
}
#time-selector div {
white-space: nowrap;
}

View File

@ -0,0 +1,20 @@
#notifications {
display: grid;
grid-template-columns: repeat(5, min-content);
grid-gap: 4px 16px;
margin-top: 96px;
margin-bottom: 32px;
background-color: #333;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
#notifications div {
white-space: nowrap;
line-height: 24px;
}
#notifications .header {
font-weight: 800;
color: #777;
}

View File

@ -0,0 +1,46 @@
#problems-list,
#acknowledged-list {
grid-template-columns: repeat(7, min-content);
}
#problems-list .trigger,
#acknowledged-list .trigger {
color: #fb4934;
}
#problems-list img.acknowledge,
#acknowledged-list img.acknowledge {
height: 16px;
}
#problems-list .info,
#acknowledged-list .info {
margin-right: 8px;
}
#problems-list .icons,
#acknowledged-list .icons {
display: grid;
grid-template-columns: min-content min-content;
align-items: center;
}
#acknowledged-list.hidden {
display: none;
}
#area-grouped {
display: flex;
flex-wrap: wrap;
gap: 24px;
margin-top: 16px;
align-items: flex-start;
}
#area-grouped .area {
grid-template-columns: repeat(5, min-content);
}
#area-grouped .area .section {
padding: 4px 10px;
border-radius: 5px;
background: #333;
color: #fff;
width: min-content;
margin-bottom: 8px;
}
.hidden {
display: none;
}

View File

@ -0,0 +1,25 @@
.table {
display: grid;
grid-gap: 6px 16px;
align-items: center;
margin-top: 32px;
margin-bottom: 32px;
background-color: #333;
padding: 16px 24px;
width: min-content;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.table .row {
grid-column: 1 / -1;
}
.table > div {
white-space: nowrap;
line-height: 24px;
}
.table .header {
font-size: 0.85em;
font-weight: bold;
color: #777;
line-height: unset !important;
}

View File

View File

@ -0,0 +1,51 @@
.widgets {
display: grid;
grid-template-columns: min-content 1fr;
gap: 8px 16px;
}
.widgets .label {
margin-top: 4px;
}
.widgets input[type="text"],
.widgets textarea {
width: 100%;
}
.widgets .datapoints {
font: "Roboto Mono", monospace;
display: grid;
grid-template-columns: repeat(4, min-content);
gap: 6px 8px;
margin-bottom: 8px;
white-space: nowrap;
}
.widgets .datapoints div {
white-space: nowrap;
}
.widgets .datapoints .invalid {
color: #c83737;
}
.widgets .datapoints .delete img {
height: 16px;
}
.widgets .datapoints .values img {
height: 16px;
width: 16px;
}
.widgets .action {
display: grid;
grid-template-columns: min-content min-content 1fr;
grid-gap: 8px;
}
.widgets .action #run-result {
font-family: 'Roboto Mono', monospace;
margin-left: 16px;
padding: 16px;
background: #202020;
min-height: 8em;
}
.widgets .action #run-result.ok {
color: #d5c4a1;
}
.widgets .action #run-result.error {
color: #fb4934;
}

View File

@ -0,0 +1,13 @@
#areas .area .section .triggers .trigger {
display: grid;
grid-template-columns: min-content 1fr min-content;
grid-gap: 8px;
align-items: center;
margin-top: 8px;
}
#areas .area .section .triggers .trigger img {
height: 16px;
}
#areas .area .section .triggers .trigger .label {
color: inherit;
}

View File

@ -1,108 +0,0 @@
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
*:focus {
outline: none;
}
[onClick] {
cursor: pointer;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #282828;
font-family: sans-serif;
font-weight: 300;
color: #d5c4a1;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #b8bb26;
font-weight: 800;
}
a {
color: #3f9da1;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #202020;
color: #d5c4a1;
padding: 4px 8px;
border: none;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #202020;
color: #d5c4a1;
padding: 8px 32px;
border: 1px solid #535353;
font-size: 1em;
height: 3em;
}
button:focus {
background: #333;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #4e4e4e;
}
span.date {
color: #d5c4a1;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #d5c4a1;
}
span.seconds {
display: none;
}
label {
user-select: none;
}
.description {
border: 1px solid #737373;
color: #3f9da1;
background: #202020;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
}
.graph {
margin-top: 192px;
border-radius: 16px;
}

View File

@ -1,155 +0,0 @@
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
*:focus {
outline: none;
}
[onClick] {
cursor: pointer;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #282828;
font-family: sans-serif;
font-weight: 300;
color: #d5c4a1;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #b8bb26;
font-weight: 800;
}
a {
color: #3f9da1;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #202020;
color: #d5c4a1;
padding: 4px 8px;
border: none;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #202020;
color: #d5c4a1;
padding: 8px 32px;
border: 1px solid #535353;
font-size: 1em;
height: 3em;
}
button:focus {
background: #333;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #4e4e4e;
}
span.date {
color: #d5c4a1;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #d5c4a1;
}
span.seconds {
display: none;
}
label {
user-select: none;
}
.description {
border: 1px solid #737373;
color: #3f9da1;
background: #202020;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
}
#problems-list,
#acknowledged-list {
display: grid;
grid-template-columns: repeat(6, min-content);
grid-gap: 4px 16px;
margin-bottom: 32px;
}
#problems-list div,
#acknowledged-list div {
white-space: nowrap;
line-height: 24px;
}
#problems-list .header,
#acknowledged-list .header {
font-weight: 800;
}
#problems-list .trigger,
#acknowledged-list .trigger {
color: #fb4934;
font-weight: 800;
}
#problems-list .acknowledge img,
#acknowledged-list .acknowledge img {
height: 16px;
}
#acknowledged-list.hidden {
display: none;
}
#areas {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 16px;
}
#areas .area .section {
display: grid;
grid-template-columns: repeat(2, min-content);
grid-gap: 8px 12px;
}
#areas .area .section .name {
color: #f7edd7;
grid-column: 1 / -1;
font-weight: bold !important;
line-height: 24px;
}
#areas .area .section div {
white-space: nowrap;
}
.hidden {
display: none;
}

View File

@ -1,148 +0,0 @@
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
*:focus {
outline: none;
}
[onClick] {
cursor: pointer;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #282828;
font-family: sans-serif;
font-weight: 300;
color: #d5c4a1;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #b8bb26;
font-weight: 800;
}
a {
color: #3f9da1;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #202020;
color: #d5c4a1;
padding: 4px 8px;
border: none;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #202020;
color: #d5c4a1;
padding: 8px 32px;
border: 1px solid #535353;
font-size: 1em;
height: 3em;
}
button:focus {
background: #333;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #4e4e4e;
}
span.date {
color: #d5c4a1;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #d5c4a1;
}
span.seconds {
display: none;
}
label {
user-select: none;
}
.description {
border: 1px solid #737373;
color: #3f9da1;
background: #202020;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
}
.widgets {
display: grid;
grid-template-columns: min-content 1fr;
gap: 8px 16px;
}
.widgets .label {
margin-top: 4px;
}
.widgets input[type="text"],
.widgets textarea {
width: 100%;
}
.widgets .datapoints {
font: "Roboto Mono", monospace;
display: grid;
grid-template-columns: min-content min-content 1fr;
gap: 6px 8px;
margin-bottom: 8px;
white-space: nowrap;
}
.widgets .datapoints .invalid {
color: #c83737;
}
.widgets .datapoints .delete img {
height: 16px;
}
.widgets .action {
display: grid;
grid-template-columns: min-content min-content 1fr;
grid-gap: 8px;
}
.widgets .action #run-result {
font-family: 'Roboto Mono', monospace;
margin-left: 16px;
padding: 16px;
background: #202020;
min-height: 8em;
}
.widgets .action #run-result.ok {
color: #d5c4a1;
}
.widgets .action #run-result.error {
color: #fb4934;
}

View File

@ -1,117 +0,0 @@
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
*:focus {
outline: none;
}
[onClick] {
cursor: pointer;
}
html,
body {
margin: 0;
padding: 0;
}
body {
background: #282828;
font-family: sans-serif;
font-weight: 300;
color: #d5c4a1;
font-size: 11pt;
}
h1,
h2 {
margin-bottom: 4px;
}
h1:first-child,
h2:first-child {
margin-top: 0px;
}
h1 {
font-size: 1.5em;
color: #fb4934;
font-weight: 800;
}
h2 {
font-size: 1.25em;
color: #b8bb26;
font-weight: 800;
}
a {
color: #3f9da1;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
b {
font-weight: 800;
}
input[type="text"],
textarea,
select {
font-family: monospace;
background: #202020;
color: #d5c4a1;
padding: 4px 8px;
border: none;
font-size: 1em;
line-height: 1.5em;
}
button {
background: #202020;
color: #d5c4a1;
padding: 8px 32px;
border: 1px solid #535353;
font-size: 1em;
height: 3em;
}
button:focus {
background: #333;
}
.line {
grid-column: 1 / -1;
border-bottom: 1px solid #4e4e4e;
}
span.date {
color: #d5c4a1;
font-weight: 800;
}
span.time {
font-size: 0.9em;
color: #d5c4a1;
}
span.seconds {
display: none;
}
label {
user-select: none;
}
.description {
border: 1px solid #737373;
color: #3f9da1;
background: #202020;
padding: 4px 8px;
margin-top: 8px;
white-space: nowrap;
width: min-content;
border-radius: 8px;
}
#areas .area .section .triggers .trigger {
display: grid;
grid-template-columns: min-content 1fr min-content;
grid-gap: 8px;
align-items: center;
margin-top: 8px;
}
#areas .area .section .triggers .trigger img {
height: 16px;
}
#areas .area .section .triggers .trigger .label {
color: inherit;
}

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="31.999987"
height="29.090721"
viewBox="0 0 8.4666629 7.6969202"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="acknowledge-filled.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="11.5"
inkscape:cy="10"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-89.958296,-148.43122)">
<title
id="title1">thumb-up</title>
<path
d="m 98.424959,151.89488 c 0,-0.42719 -0.346361,-0.7697 -0.769692,-0.7697 h -2.432224 l 0.369452,-1.75874 c 0.0077,-0.0385 0.01149,-0.0809 0.01149,-0.1232 0,-0.15778 -0.06542,-0.30402 -0.169332,-0.40794 l -0.407941,-0.40408 -2.532284,2.53229 c -0.142399,0.1424 -0.227059,0.33482 -0.227059,0.54648 v 3.84845 a 0.76969147,0.76969147 0 0 0 0.769691,0.7697 h 3.463611 c 0.319422,0 0.592664,-0.19242 0.708117,-0.46951 l 1.162234,-2.71317 c 0.03463,-0.0884 0.05388,-0.18087 0.05388,-0.28093 v -0.7697 m -8.466606,4.23331 h 1.539382 v -4.61815 h -1.539382 z"
id="path1"
style="stroke-width:0.384845;fill:#1b4e78;fill-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="31.999987"
height="29.090721"
viewBox="0 0 8.4666629 7.6969202"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="acknowledge-outline.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="11.5"
inkscape:cy="10"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-89.958296,-148.43122)">
<title
id="title1">thumb-up</title>
<title
id="title1-3">thumb-up-outline</title>
<path
d="m 91.497681,151.50999 v 4.61815 h -1.539385 v -4.61815 h 1.539385 m 1.539383,4.61815 a 0.76969186,0.76969186 0 0 1 -0.769692,-0.76969 v -3.84846 c 0,-0.21166 0.08467,-0.40408 0.22706,-0.54263 l 2.532286,-2.53614 0.407936,0.40794 c 0.103912,0.10385 0.169333,0.24631 0.169333,0.40408 l -0.01149,0.1232 -0.365604,1.75875 h 2.428378 c 0.42718,0 0.769693,0.34636 0.769693,0.76969 v 0.76969 c 0,0.10008 -0.01924,0.19242 -0.05388,0.28095 l -1.162236,2.71316 c -0.115446,0.27709 -0.388694,0.46951 -0.708116,0.46951 h -3.463613 m 0,-0.7697 h 3.47516 l 1.142991,-2.69392 v -0.76969 h -3.382795 l 0.434876,-2.04738 -1.670232,1.67408 z"
id="path1"
style="stroke-width:0.384845;fill:#1b4e78;fill-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="257"
height="256"
viewBox="0 0 67.997915 67.733336"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="background.svg"
inkscape:export-filename="gruvbox.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#282828"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="202.5"
inkscape:cy="194"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="color:#000000;overflow:visible;fill:#f8f8f8;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.264584;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000"
id="rect40644"
width="67.733337"
height="67.73333"
x="0"
y="0" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 17.065625,0.1322915 V 67.601042"
id="path37309" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 8.5989583,0.1322915 V 67.601042"
id="path37610" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 25.532292,0.1322915 V 67.601042"
id="path37612" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 33.998959,0.1322915 V 67.601042"
id="path37616" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 42.465625,0.1322915 V 67.601042"
id="path37618" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 50.932292,0.1322915 V 67.601042"
id="path37620" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 59.398959,0.1322915 V 67.601042"
id="path37622" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 67.865626,0.1322915 V 67.601042"
id="path37626" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,50.932293 H 67.601042"
id="path43996" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,59.39896 H 67.601042"
id="path43998" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,42.465626 H 67.601042"
id="path44000" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,33.998959 H 67.601042"
id="path44002" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,25.532293 H 67.601042"
id="path44004" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,17.065626 H 67.601042"
id="path44006" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,8.598959 H 67.601042"
id="path44008" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,0.132292 H 67.601042"
id="path44010" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,55.165625 H 67.601042"
id="path44772" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,63.632292 H 67.601042"
id="path44774" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,46.698958 H 67.601042"
id="path44776" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,38.232291 H 67.601042"
id="path44778" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,29.765625 H 67.601042"
id="path44780" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,21.298958 H 67.601042"
id="path44782" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,12.832291 H 67.601042"
id="path44784" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,4.365624 H 67.601042"
id="path44786" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 12.832292,0.1322915 V 67.601042"
id="path44813" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 4.3656249,0.1322915 V 67.601042"
id="path44815" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 21.298959,0.1322915 V 67.601042"
id="path44817" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 29.765626,0.1322915 V 67.601042"
id="path44819" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 38.232292,0.1322915 V 67.601042"
id="path44821" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 46.698959,0.1322915 V 67.601042"
id="path44823" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 55.165626,0.1322915 V 67.601042"
id="path44825" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#eaeaea;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 63.632293,0.1322915 V 67.601042"
id="path44827" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32.000023"
height="32.890053"
viewBox="0 0 8.4666725 8.70216"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="configuration.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="10.5"
inkscape:cy="10"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.101544,-148.43131)">
<title
id="title1">cog</title>
<title
id="title1-9">cog-outline</title>
<path
d="m 94.33488,151.04195 a 1.7404377,1.7404377 0 0 1 1.740437,1.74043 1.7404377,1.7404377 0 0 1 -1.740437,1.74043 1.7404377,1.7404377 0 0 1 -1.740438,-1.74043 1.7404377,1.7404377 0 0 1 1.740438,-1.74043 m 0,0.8702 a 0.87021889,0.87021889 0 0 0 -0.87022,0.87023 0.87021889,0.87021889 0 0 0 0.87022,0.87022 0.87021889,0.87021889 0 0 0 0.870219,-0.87022 0.87021889,0.87021889 0 0 0 -0.870219,-0.87023 m -0.87022,5.22132 c -0.108784,0 -0.20015,-0.0783 -0.217553,-0.18274 l -0.160998,-1.15305 c -0.274119,-0.1087 -0.509079,-0.2567 -0.735335,-0.43076 l -1.083423,0.43946 c -0.09573,0.0349 -0.213203,0 -0.265416,-0.0957 l -0.870219,-1.50548 c -0.05657,-0.0957 -0.03046,-0.21321 0.05221,-0.27848 l 0.918081,-0.72227 -0.03046,-0.42206 0.03046,-0.43511 -0.918081,-0.70922 c -0.08267,-0.0653 -0.108784,-0.18276 -0.05221,-0.27848 l 0.870219,-1.50548 c 0.05221,-0.0957 0.169692,-0.13485 0.265416,-0.0957 l 1.083423,0.4351 c 0.226256,-0.1697 0.461216,-0.31764 0.735335,-0.42641 l 0.160998,-1.15304 c 0.0174,-0.10443 0.108767,-0.18274 0.217553,-0.18274 h 1.740439 c 0.108768,0 0.20015,0.0783 0.217554,0.18274 l 0.160997,1.15304 c 0.27412,0.10871 0.509079,0.25671 0.735335,0.42641 l 1.083422,-0.4351 c 0.09573,-0.0391 0.213204,0 0.265417,0.0957 l 0.87022,1.50548 c 0.05657,0.0957 0.03046,0.21321 -0.05221,0.27848 l -0.918081,0.70922 0.03046,0.43511 -0.03046,0.4351 0.918081,0.70923 c 0.08267,0.0653 0.108785,0.18275 0.05221,0.27848 l -0.87022,1.50548 c -0.05221,0.0957 -0.169692,0.13485 -0.265417,0.0957 l -1.083422,-0.4351 c -0.226256,0.1697 -0.461215,0.31764 -0.735335,0.4264 l -0.160997,1.15305 c -0.0174,0.10443 -0.108784,0.18274 -0.217554,0.18274 H 93.46466 m 0.543887,-7.83197 -0.160998,1.13565 c -0.522131,0.1087 -0.983348,0.38723 -1.318382,0.77448 l -1.048614,-0.45251 -0.326331,0.56565 0.918081,0.67441 c -0.174045,0.50908 -0.174045,1.06166 0,1.5664 l -0.922433,0.67877 0.326332,0.56564 1.057316,-0.45252 c 0.335034,0.38289 0.7919,0.66137 1.30968,0.7658 l 0.160997,1.13999 h 0.661366 l 0.160997,-1.13565 c 0.51778,-0.1087 0.974646,-0.38725 1.30968,-0.77014 l 1.057315,0.45252 0.326333,-0.56564 -0.922433,-0.67442 c 0.174045,-0.50909 0.174045,-1.06167 0,-1.57075 l 0.918081,-0.67441 -0.326331,-0.56565 -1.048614,0.45251 c -0.335034,-0.38725 -0.796251,-0.66572 -1.318382,-0.77014 l -0.160998,-1.13999 z"
id="path1-1"
style="fill:#7bb8eb;fill-opacity:1;stroke-width:0.435109" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32.000031"
height="32.897346"
viewBox="0 0 8.4666745 8.7040898"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="configuration_selected.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="9.5"
inkscape:cy="10"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.294521,-148.43129)">
<title
id="title1">cog</title>
<path
d="m 94.528826,154.30658 a 1.5232321,1.5232321 0 0 1 -1.523231,-1.52325 1.5232321,1.5232321 0 0 1 1.523231,-1.52323 1.5232321,1.5232321 0 0 1 1.523232,1.52323 1.5232321,1.5232321 0 0 1 -1.523232,1.52325 m 3.233603,-1.10109 c 0.0174,-0.13932 0.03046,-0.27853 0.03046,-0.42216 0,-0.1436 -0.013,-0.28723 -0.03046,-0.4352 l 0.918292,-0.70939 c 0.08269,-0.0653 0.10445,-0.1828 0.05222,-0.27853 l -0.870417,-1.50583 c -0.05222,-0.0957 -0.169732,-0.13488 -0.265478,-0.0957 l -1.083672,0.4352 c -0.226308,-0.16972 -0.461321,-0.31769 -0.735503,-0.4265 l -0.161018,-1.15329 c -0.0174,-0.10445 -0.108809,-0.1828 -0.217605,-0.1828 h -1.740836 c -0.108809,0 -0.200198,0.0783 -0.217605,0.1828 l -0.161035,1.15329 c -0.274181,0.10889 -0.509194,0.25678 -0.735503,0.4265 l -1.08367,-0.4352 c -0.09575,-0.0391 -0.213253,0 -0.265478,0.0957 l -0.870419,1.50583 c -0.05658,0.0957 -0.03046,0.21324 0.05222,0.27853 l 0.918292,0.70939 c -0.0174,0.14804 -0.03046,0.29158 -0.03046,0.4352 0,0.1436 0.013,0.28289 0.03046,0.42216 l -0.918292,0.72245 c -0.08269,0.0653 -0.108809,0.18278 -0.05222,0.27853 l 0.870419,1.50582 c 0.05222,0.0957 0.16973,0.13061 0.265478,0.0957 l 1.08367,-0.43957 c 0.226309,0.17408 0.461322,0.32206 0.735503,0.43087 l 0.161035,1.15329 c 0.0174,0.10445 0.108809,0.1828 0.217605,0.1828 h 1.740836 c 0.108809,0 0.200195,-0.0783 0.217605,-0.1828 l 0.161018,-1.15329 c 0.274182,-0.11317 0.509195,-0.25679 0.735503,-0.43087 l 1.083672,0.43957 c 0.09575,0.0349 0.213253,0 0.265478,-0.0957 l 0.870417,-1.50582 c 0.05223,-0.0957 0.03046,-0.21325 -0.05222,-0.27853 z"
id="path1"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#9bff07;fill-opacity:1;stroke-width:0.710544;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 8.4666667 8.4666664"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="datapoints.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="16"
inkscape:cx="0.53125"
inkscape:cy="20.0625"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showgrid="false" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-102.9229,-148.76801)">
<title
id="title1">file-chart</title>
<title
id="title1-6">chart-timeline-variant</title>
<circle
style="fill:#7bb8eb;fill-opacity:1;stroke-width:0.329648"
id="path1"
cx="103.69108"
cy="156.46651"
r="0.76817483" />
<circle
style="fill:#7bb8eb;fill-opacity:1;stroke-width:0.329648"
id="circle1"
cx="110.62139"
cy="149.53618"
r="0.76817483" />
<circle
style="fill:#7bb8eb;fill-opacity:1;stroke-width:0.329648"
id="circle2"
cx="106.00118"
cy="151.84628"
r="0.76817483" />
<circle
style="fill:#7bb8eb;fill-opacity:1;stroke-width:0.329648"
id="circle3"
cx="108.31129"
cy="154.1564"
r="0.76817483" />
<path
style="fill:none;fill-opacity:1;stroke-width:0.90831457;stroke:#7bb8eb;stroke-opacity:1;stroke-dasharray:none;stroke-linecap:round"
d="m 103.69108,156.46651 2.3101,-4.62023 2.31011,2.31012 2.3101,-4.62022"
id="path3" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 8.4666667 8.4666664"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="datapoints_selected.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="16"
inkscape:cx="0.53125"
inkscape:cy="20.0625"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showgrid="false" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-102.9229,-148.76801)">
<title
id="title1">file-chart</title>
<title
id="title1-6">chart-timeline-variant</title>
<path
d="m 94.987379,153.53513 0.19242,0.0269 1.75874,-1.75874 c -0.0692,-0.25015 -0.004,-0.53493 0.20012,-0.73505 0.30018,-0.30402 0.78508,-0.30402 1.08527,0 0.20396,0.20012 0.26937,0.4849 0.20011,0.73505 l 0.98905,0.98905 0.19242,-0.0269 c 0.0692,0 0.13469,0 0.19242,0.0269 l 1.373891,-1.37389 c -0.0269,-0.0577 -0.0269,-0.1232 -0.0269,-0.19242 a 0.76968815,0.76968815 0 0 1 0.76969,-0.76969 0.76968815,0.76968815 0 0 1 0.7697,0.76969 0.76968815,0.76968815 0 0 1 -0.7697,0.76968 c -0.0692,0 -0.13469,0 -0.19242,-0.0269 l -1.37389,1.3739 c 0.0269,0.0577 0.0269,0.1232 0.0269,0.19242 a 0.76968815,0.76968815 0 0 1 -0.769691,0.76968 0.76968815,0.76968815 0 0 1 -0.76969,-0.76968 l 0.0269,-0.19242 -0.98904,-0.98905 c -0.1232,0.0269 -0.2617,0.0269 -0.38485,0 l -1.75873,1.75873 0.0269,0.19242 a 0.76968815,0.76968815 0 0 1 -0.7697,0.76969 0.76968815,0.76968815 0 0 1 -0.76969,-0.76969 0.76968815,0.76968815 0 0 1 0.76969,-0.76968 z"
id="path1-2"
style="fill:#777777;fill-opacity:1;stroke-width:0.384844" />
<circle
style="fill:#9bff07;fill-opacity:1;stroke-width:0.329648"
id="path1"
cx="103.69108"
cy="156.46651"
r="0.76817483" />
<circle
style="fill:#9bff07;fill-opacity:1;stroke-width:0.329648"
id="circle1"
cx="110.62139"
cy="149.53618"
r="0.76817483" />
<circle
style="fill:#9bff07;fill-opacity:1;stroke-width:0.329648"
id="circle2"
cx="106.00118"
cy="151.84628"
r="0.76817483" />
<circle
style="fill:#9bff07;fill-opacity:1;stroke-width:0.329648"
id="circle3"
cx="108.31129"
cy="154.1564"
r="0.76817483" />
<path
style="fill:none;fill-opacity:1;stroke-width:0.90831457;stroke:#9bff07;stroke-opacity:1;stroke-dasharray:none;stroke-linecap:round"
d="m 103.69108,156.46651 2.3101,-4.62023 2.31011,2.31012 2.3101,-4.62022"
id="path3" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="19.999975"
height="19.999975"
viewBox="0 0 5.29166 5.2916603"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="forward.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
inkscape:cx="9.3028736"
inkscape:cy="12.772116"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-123.825,-155.04583)">
<title
id="title1">alert</title>
<title
id="title1-1">arrow-right-bold-circle</title>
<path
d="m 123.825,157.69166 a 2.6458334,2.6458334 0 0 1 2.64583,-2.64583 2.6458334,2.6458334 0 0 1 2.64583,2.64583 2.6458334,2.6458334 0 0 1 -2.64583,2.64583 2.6458334,2.6458334 0 0 1 -2.64583,-2.64583 m 3.96875,0 -1.32292,-1.32292 v 0.79375 h -1.05833 v 1.05834 h 1.05833 v 0.79375 z"
id="path1"
style="stroke-width:0.264583;fill:#abc837" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,848 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Do not edit this file with editors other than draw.io -->
<svg
version="1.1"
width="809px"
height="152px"
viewBox="-0.5 -0.5 809 152"
content="&lt;mxfile host=&quot;diagram.gibonuddevalla.se&quot; modified=&quot;2024-05-28T10:02:20.373Z&quot; agent=&quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36&quot; etag=&quot;029SYytIuNc7IRsrmX2d&quot; version=&quot;21.6.5&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;Page-1&quot; id=&quot;15J0dj6b0bNp4ZTDu6Jz&quot;&gt;7Vpbc9o6EP41PCYDFjbkMYSkPXPSTmfSmaaPwl5sNbJFZXE7v/5ItmRbxlwSSIAMwwPWSlpJu5++XVluobt48YXjSfSNBUBbTjtYtNCw5Tgd172Rf0qyzCV9t5MLQk6CXNQuBU/kP9A9jXRKAki1LBcJxqggE1vosyQBX1gyzDmb283GjAaWYIJDWBE8+ZiuSn+RQERmFe1S/hVIGJmRO21dM8L+S8jZNNHjtRzk9NUvr46x0aXbpxEO2LwiQvctdMcZE/lTvLgDqmxrm+1hTW0xbw6J2KWDR37Pfvk4+rmI/iXfHwf/OPHzVTE5sTQGgUDaRxcZFxELWYLpfSkdZIsGpbYtS2WbR8YmUtiRwj8gxFI7G08Fk6JIxFTXwoKI58rzb6Xq2tWl4UJrzgpLU0gEXz5XC5Veqlh2y0qm35gl4gHHhCrBV6AzEMTHukLPsNPV5TtGGZeCAMZ4SqVZB+kLCD/Sc/WnfAYPRAiShGahJAwzUzlKBaHUqJBwCFzoB0p1Kjh7gUpN3xkhz5M1q07Ufk3ZlPuwwXNmr2AegtjQDuXtlFcrA2iIfAEWg7SWbMCBYkFm9q7AenOFRbsSYPJBY+wVeNN6Z5hOwWwbLzP0SD6E6mGIBZ4wIu2ha+RARWXRmtclyn0WkL2/U2YqrtLM0beyQceZLPJuur5U9JAhRy3Q8XAsoTzINCc4hkJijSmb5sMaDbWtZG+UeUQEPE1w5ta5ZFN7U7wOaTXw5ggzBNaARU1Nm7BY3QBSPhyon9ZkCCFlVPl3PW5nwAUsNiLN1Bru0YHDMZQ7L2m4aBNVKNhrvxM4He9cyPCzkpqzI6l1eifFas52VvvB2YhC/MGcRlJlA0xSCdALZ+3PWe7pcRb61JxV9ek7sxbFI6CDIqk3TRKWwF6chnbkNOekKA25TZyW50DJKFV/gk+hLmsE46OyrA0gTEmYyGdfmhOkmQdqD0o40FtdEZMgyLEKkufwKNOnYJSlhtlq3UHLHa7Bz1qg7Q2sNTCp0tUqVjZu3RX6KQ67etnWgbGJlq7a16jrWsxk4LQzWrTyH3nmXWh2alq7tgY2HqcS1XW0FVPcA4C9cyG2y8n0bYSHvJNivG57K+ONMU0vlLcH5ZlNvT/lScZrOz2bnDr7UV6hxv0wjtt+bvjJpSeAH+PcAGpeWFyODgc5OqD60eHm2EeHXgP66lSWBLfqHbuiLYrTlPi2E22P7xnQ3hpHX4WkDXhYEyLX+n77W4pDx7fmHK1bA1a/Bpg8YOtO1QuCmh5k60Gdm+saE+YrXtF0KDrsbw3A6t3wq+JvPZS+LR5bKLfgZmGrAXs23CrJ2yqB7Xs8ruK3HOhwsbu3KU7vxIQfdMXQxGu1qPqdCTKW5hWEJccIrSlY1xuXqPrWqNo7uaiKuudybv2058/zvBo1077cjZ4irTXQ1zqqOwCt1e9GETo6rTXdcR3ztHCyWT86TtqP6q7fNe1fwZr30Xk/anwPckn8TyTxN1v/5DN/dHMuqdflyqD5KuDcPvww8z7VLz9A5iqzywvcd/n2A3XfLyeTxfLD4DzMll9fo/v/AQ==&lt;/diagram&gt;&lt;/mxfile&gt;"
style="background-color: rgb(40, 40, 40);"
id="svg54"
sodipodi:docname="graph.svg"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<sodipodi:namedview
id="namedview54"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.2088117"
inkscape:cx="430.58815"
inkscape:cy="69.48973"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="1"
inkscape:current-layer="g26" />
<defs
id="defs1">
<style
type="text/css"
id="style1">@import url(https://fonts.googleapis.com/css?family=Architects+Daughter);
</style>
</defs>
<rect
style="color:#000000;overflow:visible;fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:2.18822;-inkscape-stroke:none;paint-order:markers stroke fill"
id="rect54"
x="-0.5"
y="-0.5"
height="152"
width="809" />
<path
d="m 207,31 h 40 v 40 h 33.63"
fill="none"
stroke="none"
pointer-events="stroke"
id="path1" />
<path
d="m 285.88,71 -7,3.5 1.75,-3.5 -1.75,-3.5 z"
fill="none"
stroke="none"
pointer-events="all"
id="path2" />
<path
d="m 207,31 m 0,0 c 6.49,-3.79 19.53,-3.25 40,0 m -40,0 c 15.58,1.85 28.9,-0.92 40,0 m 0,0 c 0.03,10.14 1.53,14.34 0,40 m 0,-40 c -0.67,10.49 2.06,17.08 0,40 m 0,0 c 8.93,-0.17 24.16,2.12 33.63,0 M 247,71 c 6.76,0.05 14.35,0.31 33.63,0"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="stroke"
id="path3" />
<path
d="m 278.69,67.71 c 0,0 0,0 0,0 m 0,0 c 0,0 0,0 0,0 m 2.37,3.38 c 0.27,-0.22 0.71,-1.01 1.31,-1.51 m -1.31,1.51 c 0.16,-0.14 0.72,-0.69 1.31,-1.51"
fill="none"
stroke="#82b366"
stroke-width="0.5"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path4" />
<path
d="m 285.88,71 m 0,0 c -2.93,0.96 -3.34,2.96 -7,3.5 m 7,-3.5 c -2.1,0.9 -3.91,1.83 -7,3.5 m 0,0 c 0.78,-1.46 0.38,-1.57 1.75,-3.5 m -1.75,3.5 c 0.83,-1.42 0.82,-1.98 1.75,-3.5 m 0,0 c -0.97,-0.78 -1.45,-1.22 -1.75,-3.5 m 1.75,3.5 c -0.51,-0.95 -1.31,-2.23 -1.75,-3.5 m 0,0 c 1.43,-0.28 3.54,1.33 7,3.5 m -7,-3.5 c 1.82,1.53 5.5,1.81 7,3.5"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path5" />
<rect
x="87"
y="1"
width="120"
height="60"
fill="none"
stroke="none"
pointer-events="all"
id="rect5" />
<path
d="m 87,1 c 49.52,0.7 94.52,-2.11 120,0 M 87,1 c 24.93,0.37 51.08,-0.76 120,0 m 0,0 c -1.22,18.86 2.32,39.92 0,60 m 0,-60 c 1.63,20.02 0.5,38.3 0,60 m 0,0 C 173.32,60.93 130.78,59.81 87,61 m 120,0 c -47.55,1.22 -92.93,-0.71 -120,0 m 0,0 C 87.06,47.98 86.28,29.73 87,1 m 0,60 C 87.92,35.94 84.14,14.89 87,1"
fill="none"
stroke="#82b366"
stroke-width="2"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path7" />
<g
transform="translate(-0.5,-0.5)"
id="g7"
style="fill:#ff0000">
<switch
id="switch7"
style="fill:#ff0000">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 31px; margin-left: 88px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<xhtml:b>Datapoint</xhtml:b>
<xhtml:br />
<xhtml:font
style="font-size: 12px;">/entry/&lt;name&gt;</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="147"
y="35"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text7"
style="fill:#ff0000">Datapoint...</text>
</switch>
</g>
<path
d="m 607,31 h 40 v 40 h 33.63"
fill="none"
stroke="none"
pointer-events="stroke"
id="path8" />
<path
d="m 685.88,71 -7,3.5 1.75,-3.5 -1.75,-3.5 z"
fill="none"
stroke="none"
pointer-events="all"
id="path9" />
<path
d="m 607,31 m 0,0 c 8.77,0.4 23.7,3.33 40,0 m -40,0 c 15.21,0.71 32.72,0.56 40,0 m 0,0 c 3.23,12.65 -0.94,17.27 0,40 m 0,-40 c 1.31,9.78 -1.2,19.81 0,40 m 0,0 c 8.58,-3.33 22.5,0.95 33.63,0 M 647,71 c 11.19,2.27 20.59,1.17 33.63,0"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="stroke"
id="path10" />
<path
d="m 679.07,67.28 c 0,0 0,0 0,0 m 0,0 c 0,0 0,0 0,0 m 1.71,4.13 c 0.97,0.01 0.8,-1.21 1.97,-2.26 m -1.97,2.26 c 0.8,-0.79 0.96,-1.54 1.97,-2.26"
fill="none"
stroke="#82b366"
stroke-width="0.5"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path11" />
<path
d="m 685.88,71 m 0,0 c -2.35,0.05 -2.65,2.72 -7,3.5 m 7,-3.5 c -1.3,1.6 -3.32,2.16 -7,3.5 m 0,0 c 0.51,-1.63 1.43,-2.34 1.75,-3.5 m -1.75,3.5 c 0.63,-0.48 0.85,-1.09 1.75,-3.5 m 0,0 c -0.22,-1.45 -0.46,-2.64 -1.75,-3.5 m 1.75,3.5 c -0.78,-1.57 -1.41,-2.26 -1.75,-3.5 m 0,0 c 3.28,1.05 4.93,2.82 7,3.5 m -7,-3.5 c 2.7,1.47 4.72,1.75 7,3.5"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path12" />
<rect
x="487"
y="1"
width="120"
height="60"
fill="none"
stroke="none"
pointer-events="all"
id="rect12" />
<path
d="m 487,1 c 47.23,-4.26 89.88,1.33 120,0 M 487,1 c 31.96,-0.65 65.9,-3.35 120,0 m 0,0 c -2.84,17.32 -1.59,45.81 0,60 m 0,-60 c 0.3,18.08 0.96,34.44 0,60 m 0,0 c -30.28,2.62 -64.25,-3.5 -120,0 m 120,0 c -25.98,1.98 -54.22,1.82 -120,0 m 0,0 c -2.12,-9.5 -1.83,-28.58 0,-60 m 0,60 c -0.51,-22.32 0.05,-40.77 0,-60"
fill="none"
stroke="#82b366"
stroke-width="2"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path14" />
<g
transform="translate(-0.5,-0.5)"
id="g14"
style="fill:#ff0000">
<switch
id="switch14"
style="fill:#ff0000">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 31px; margin-left: 488px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<xhtml:b>Problem</xhtml:b>
<xhtml:br />
<xhtml:font
style="font-size: 12px;">is raised</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="547"
y="35"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text14"
style="fill:#ff0000">Problem...</text>
</switch>
</g>
<path
d="m 407,71 h 40 V 31 h 33.63"
fill="none"
stroke="none"
pointer-events="stroke"
id="path15" />
<path
d="m 485.88,31 -7,3.5 1.75,-3.5 -1.75,-3.5 z"
fill="none"
stroke="none"
pointer-events="all"
id="path16" />
<path
d="m 407,71 m 0,0 c 7.63,-1.69 21.62,0.04 40,0 m -40,0 c 15.4,-0.72 30.81,-0.18 40,0 m 0,0 c -2.38,-14.72 0.28,-24.43 0,-40 m 0,40 c -0.94,-13.57 -0.83,-26.96 0,-40 m 0,0 c 9.39,-1.75 16.61,1.53 33.63,0 M 447,31 c 10.34,0.49 24.2,-1.93 33.63,0"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="stroke"
id="path17" />
<path
d="m 479.09,27.26 c 0,0 0,0 0,0 m 0,0 c 0,0 0,0 0,0 m 1.7,4.14 c 0.29,-1.03 1.33,-1.27 1.97,-2.27 m -1.97,2.27 c 0.47,-0.78 1.17,-1.49 1.97,-2.27"
fill="none"
stroke="#82b366"
stroke-width="0.5"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path18" />
<path
d="m 485.88,31 m 0,0 c -0.3,0.16 -1.52,2.14 -7,3.5 m 7,-3.5 c -3.18,1.74 -5.01,2.05 -7,3.5 m 0,0 c 0.64,-1.51 0.9,-1.14 1.75,-3.5 m -1.75,3.5 c 0.84,-0.95 1.11,-2.66 1.75,-3.5 m 0,0 c -0.66,-0.37 -1.8,-1.97 -1.75,-3.5 m 1.75,3.5 c -0.08,-0.88 -0.62,-1.51 -1.75,-3.5 m 0,0 c 2.35,1.81 4.23,3.5 7,3.5 m -7,-3.5 c 2.41,1.29 3,2.01 7,3.5"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path19" />
<g
transform="translate(-0.5,-0.5)"
id="g19">
<switch
id="switch19">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 50px; margin-left: 445px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; background-color: #282828; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; background-color: rgb(40, 40, 40); white-space: nowrap;"> true </xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="445"
y="54"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text19"> true </text>
</switch>
</g>
<path
d="m 407,71 h 40 v 50 h 33.63"
fill="none"
stroke="none"
pointer-events="stroke"
id="path20" />
<path
d="m 485.88,121 -7,3.5 1.75,-3.5 -1.75,-3.5 z"
fill="none"
stroke="none"
pointer-events="all"
id="path21" />
<path
d="m 407,71 m 0,0 c 7.65,-2.3 19.25,-2.61 40,0 m -40,0 c 11.92,1.34 22.41,-0.85 40,0 m 0,0 c 3.81,16.24 -1.28,32.05 0,50 m 0,-50 c -0.58,14.12 -1.67,29.32 0,50 m 0,0 c 8.51,-2.8 19.92,1.41 33.63,0 M 447,121 c 14.35,-1.07 24.93,-1.37 33.63,0"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="stroke"
id="path22" />
<path
d="m 479.04,117.32 c 0,0 0,0 0,0 m 0,0 c 0,0 0,0 0,0 m 1.7,4.13 c 1.22,-1.01 1.16,-2.12 1.97,-2.26 m -1.97,2.26 c 0.63,-0.61 1.02,-1.07 1.97,-2.26"
fill="none"
stroke="#82b366"
stroke-width="0.5"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path23" />
<path
d="m 485.88,121 m 0,0 c -1.83,0.05 -2.48,2.58 -7,3.5 m 7,-3.5 c -2.3,0.85 -6.05,2.11 -7,3.5 m 0,0 c 1.01,-0.72 0.93,-2.64 1.75,-3.5 m -1.75,3.5 c 0.74,-0.93 0.77,-2.14 1.75,-3.5 m 0,0 c -0.74,-0.67 -1.8,-3.36 -1.75,-3.5 m 1.75,3.5 c -0.83,-1.03 -1.33,-1.92 -1.75,-3.5 m 0,0 c 3.51,2.31 3.27,3.63 7,3.5 m -7,-3.5 c 2.16,1.5 4.62,2.81 7,3.5"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path24" />
<g
transform="translate(-0.5,-0.5)"
id="g24">
<switch
id="switch24">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 102px; margin-left: 447px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; background-color: #282828; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; background-color: rgb(40, 40, 40); white-space: nowrap;"> false </xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="447"
y="106"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text24"> false </text>
</switch>
</g>
<rect
x="287"
y="41"
width="120"
height="60"
fill="none"
stroke="none"
pointer-events="all"
id="rect24" />
<path
d="m 287,41 c 44.95,3.58 93.24,1.57 120,0 m -120,0 c 42.99,-0.87 84.73,2.87 120,0 m 0,0 c -4.47,23.77 2.5,43.71 0,60 m 0,-60 c 0.56,16.13 -0.98,34.57 0,60 m 0,0 c -26.88,-2.69 -52.27,2.19 -120,0 m 120,0 c -32.4,2.74 -63.5,0.36 -120,0 m 0,0 c 3.7,-17.99 -2.95,-41.89 0,-60 m 0,60 c -0.33,-19.57 0.56,-35.44 0,-60"
fill="none"
stroke="#82b366"
stroke-width="2"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path26" />
<g
transform="translate(-0.5,-0.5)"
id="g26"
style="fill:#d40000">
<text
xml:space="preserve"
style="font-weight:bold;font-size:26.6667px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans Bold';text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;fill:#000000;stroke:none;stroke-width:0.999999px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stop-color:#000000"
x="312.51959"
y="68.300392"
id="text55"><tspan
sodipodi:role="line"
id="tspan54"
x="312.51959"
y="68.300392">Trigger</tspan><tspan
sodipodi:role="line"
x="312.51959"
y="101.63377"
id="tspan55">is evaluated</tspan></text>
</g>
<path
d="M 7,31 H 80.63"
fill="none"
stroke="none"
pointer-events="stroke"
id="path27" />
<path
d="m 85.88,31 -7,3.5 1.75,-3.5 -1.75,-3.5 z"
fill="none"
stroke="none"
pointer-events="all"
id="path28" />
<path
d="m 7,31 m 0,0 c 26.08,2.11 55.23,1.7 73.63,0 M 7,31 c 15.96,-0.2 33.69,1.28 73.63,0"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="stroke"
id="path29" />
<path
d="m 78.71,27.7 c 0,0 0,0 0,0 m 0,0 c 0,0 0,0 0,0 m 2.36,3.38 c 0.55,-0.34 0.77,-0.63 1.31,-1.51 m -1.31,1.51 c 0.45,-0.41 1.11,-0.99 1.31,-1.51"
fill="none"
stroke="#82b366"
stroke-width="0.5"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path30" />
<path
d="m 85.88,31 m 0,0 c -0.37,0.56 -4.59,1.88 -7,3.5 m 7,-3.5 c -1.18,0.29 -2.53,1.37 -7,3.5 m 0,0 c 0.35,-0.46 0.45,-2.31 1.75,-3.5 m -1.75,3.5 c 0.79,-0.76 0.97,-1.71 1.75,-3.5 m 0,0 c -0.38,-1.41 -0.91,-1.15 -1.75,-3.5 m 1.75,3.5 c -0.59,-1.6 -1.26,-2.97 -1.75,-3.5 m 0,0 c 3.66,2.91 5.38,2.75 7,3.5 m -7,-3.5 c 1.66,1.24 3.55,1.95 7,3.5"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path31" />
<g
transform="translate(-0.5,-0.5)"
id="g31"
style="fill:#1a1a1a">
<switch
id="switch31"
style="fill:#1a1a1a">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 32px; margin-left: 48px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; background-color: #282828; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; background-color: rgb(40, 40, 40); white-space: nowrap;"> Data </xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="48"
y="36"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text31"
style="fill:#1a1a1a"> Data </text>
</switch>
</g>
<rect
x="687"
y="41"
width="120"
height="60"
fill="none"
stroke="none"
pointer-events="all"
id="rect31" />
<path
d="m 687,41 c 33.41,-1.53 59.02,-2.56 120,0 m -120,0 c 27.61,1.06 54.75,-0.18 120,0 m 0,0 c 1.58,23.68 1.77,41.71 0,60 m 0,-60 c 0.34,13.61 0,26.72 0,60 m 0,0 c -25.22,0.23 -56.29,2.57 -120,0 m 120,0 c -31.44,-0.24 -59.57,-2.58 -120,0 m 0,0 c 1.29,-18.2 3.53,-29.52 0,-60 m 0,60 c -0.97,-18 0.22,-31.89 0,-60"
fill="none"
stroke="#82b366"
stroke-width="2"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path33" />
<g
transform="translate(-0.5,-0.5)"
id="g33"
style="fill:#ff0000">
<switch
id="switch33"
style="fill:#ff0000">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 71px; margin-left: 688px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<xhtml:b>Notification</xhtml:b>
<xhtml:br />
<xhtml:font
style="font-size: 12px;">is sent</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="747"
y="75"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text33"
style="fill:#ff0000">Notification...</text>
</switch>
</g>
<path
d="m 207,111 h 40 V 71 h 33.63"
fill="none"
stroke="none"
pointer-events="stroke"
id="path34" />
<path
d="m 285.88,71 -7,3.5 1.75,-3.5 -1.75,-3.5 z"
fill="none"
stroke="none"
pointer-events="all"
id="path35" />
<path
d="m 207,111 m 0,0 c 6.5,-2.79 17.16,3.7 40,0 m -40,0 c 12.1,-0.1 20.5,-1.59 40,0 m 0,0 c -2.6,-8.64 -0.85,-20.66 0,-40 m 0,40 c 0.38,-12.76 -2.09,-28.51 0,-40 m 0,0 c 16.05,-1.22 27.48,2 33.63,0 M 247,71 c 10.77,2.5 19.08,0.88 33.63,0"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="stroke"
id="path36" />
<path
d="m 278.69,67.71 c 0,0 0,0 0,0 m 0,0 c 0,0 0,0 0,0 m 2.37,3.38 c 0.09,-0.26 0.59,-0.84 1.31,-1.51 m -1.31,1.51 c 0.53,-0.39 0.75,-1.08 1.31,-1.51"
fill="none"
stroke="#82b366"
stroke-width="0.5"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path37" />
<path
d="m 285.88,71 m 0,0 c -1.19,0.85 -4.15,3.4 -7,3.5 m 7,-3.5 c -1.22,1.58 -3.38,1.88 -7,3.5 m 0,0 c 1.15,-0.6 1.97,-3 1.75,-3.5 m -1.75,3.5 c 0.73,-0.62 0.48,-1.46 1.75,-3.5 m 0,0 c -1.18,-1.09 -1.58,-2.61 -1.75,-3.5 m 1.75,3.5 c -0.13,-1.12 -0.54,-1.96 -1.75,-3.5 m 0,0 c 2.72,-0.06 2.71,1.18 7,3.5 m -7,-3.5 c 1.87,1.32 4.46,1.5 7,3.5"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path38" />
<rect
x="87"
y="81"
width="120"
height="60"
fill="none"
stroke="none"
pointer-events="all"
id="rect38" />
<path
d="m 87,81 c 33.45,3.98 63.27,1.28 120,0 M 87,81 c 33.38,1.5 64.78,0.7 120,0 m 0,0 c 0.83,17.08 1.41,43.8 0,60 m 0,-60 c 1.65,12.61 1.8,26.15 0,60 m 0,0 c -34.84,-1 -65.82,1.22 -120,0 m 120,0 c -43.24,2.41 -83.65,-0.54 -120,0 m 0,0 c 4.11,-17.32 1.78,-38.85 0,-60 m 0,60 c 1.06,-20.27 0.9,-41.09 0,-60"
fill="none"
stroke="#82b366"
stroke-width="2"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path40" />
<g
transform="translate(-0.5,-0.5)"
id="g40"
style="fill:#ff0000">
<switch
id="switch40"
style="fill:#ff0000">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 111px; margin-left: 88px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<xhtml:b>Datapoint</xhtml:b>
<xhtml:br />
<xhtml:font
style="font-size: 12px;">/entry/&lt;name&gt;</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="147"
y="115"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text40"
style="fill:#ff0000">Datapoint...</text>
</switch>
</g>
<path
d="M 7,111 H 80.63"
fill="none"
stroke="none"
pointer-events="stroke"
id="path41" />
<path
d="m 85.88,111 -7,3.5 1.75,-3.5 -1.75,-3.5 z"
fill="none"
stroke="none"
pointer-events="all"
id="path42" />
<path
d="m 7,111 m 0,0 c 19.52,-0.37 35.34,-2.67 73.63,0 M 7,111 c 24.85,0.21 48.47,1.85 73.63,0"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="stroke"
id="path43" />
<path
d="m 78.96,107.41 c 0,0 0,0 0,0 m 0,0 c 0,0 0,0 0,0 m 1.7,4.14 c 0.64,-0.76 1.14,-2.32 1.97,-2.27 m -1.97,2.27 c 0.39,-0.74 1.08,-0.71 1.97,-2.27"
fill="none"
stroke="#82b366"
stroke-width="0.5"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path44" />
<path
d="m 85.88,111 m 0,0 c -2.49,1.73 -4.56,1.51 -7,3.5 m 7,-3.5 c -2.46,1.99 -5.5,2.89 -7,3.5 m 0,0 c 0.51,-0.29 0.77,-2.25 1.75,-3.5 m -1.75,3.5 c 0.39,-0.89 0.96,-1.94 1.75,-3.5 m 0,0 c -0.67,-0.42 -1.44,-1.23 -1.75,-3.5 m 1.75,3.5 c -0.82,-0.91 -0.5,-1.69 -1.75,-3.5 m 0,0 c 0.58,-0.17 5.36,3.33 7,3.5 m -7,-3.5 c 1.95,1.39 5.04,2.84 7,3.5"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path45" />
<g
transform="translate(-0.5,-0.5)"
id="g45"
style="fill:#1a1a1a">
<switch
id="switch45"
style="fill:#1a1a1a">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 112px; margin-left: 48px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; background-color: #282828; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; background-color: rgb(40, 40, 40); white-space: nowrap;"> Data </xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="48"
y="116"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text45"
style="fill:#1a1a1a"> Data </text>
</switch>
</g>
<path
d="m 607,121 h 40 V 71 h 33.63"
fill="none"
stroke="none"
pointer-events="stroke"
id="path46" />
<path
d="m 685.88,71 -7,3.5 1.75,-3.5 -1.75,-3.5 z"
fill="none"
stroke="none"
pointer-events="all"
id="path47" />
<path
d="m 607,121 m 0,0 c 11.07,2.84 17.97,3.32 40,0 m -40,0 c 10.46,-1.17 21.02,1.51 40,0 m 0,0 c 1.25,-12.2 -0.39,-22.85 0,-50 m 0,50 c 1.66,-12.45 0.16,-23.76 0,-50 m 0,0 c 10.21,1.48 25.67,-4.31 33.63,0 M 647,71 c 7.35,-0.78 18.04,-1.53 33.63,0"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="stroke"
id="path48" />
<path
d="m 679.07,67.28 c 0,0 0,0 0,0 m 0,0 c 0,0 0,0 0,0 m 1.71,4.13 c 0.72,-0.65 0.91,-1.06 1.97,-2.26 m -1.97,2.26 c 0.65,-0.68 0.88,-1.16 1.97,-2.26"
fill="none"
stroke="#82b366"
stroke-width="0.5"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path49" />
<path
d="m 685.88,71 m 0,0 c -3.66,2.3 -5.2,1.35 -7,3.5 m 7,-3.5 c -2.61,0.72 -3.94,1.38 -7,3.5 m 0,0 c 1.17,-0.26 1.29,-1.91 1.75,-3.5 m -1.75,3.5 c 0.64,-1.36 0.99,-2.28 1.75,-3.5 m 0,0 c -0.9,-0.64 -1.24,-1.77 -1.75,-3.5 m 1.75,3.5 c -0.92,-1.24 -1.37,-2.19 -1.75,-3.5 m 0,0 c 2.66,2.43 3.89,1.48 7,3.5 m -7,-3.5 c 2.08,1.43 4.04,3.03 7,3.5"
fill="none"
stroke="#82b366"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path50" />
<rect
x="487"
y="91"
width="120"
height="60"
fill="none"
stroke="none"
pointer-events="all"
id="rect50" />
<path
d="m 487,91 c 30.03,1.59 64.08,0.88 120,0 m -120,0 c 28.54,1.2 54.89,0.58 120,0 m 0,0 c -4.91,21.35 0.28,41.28 0,60 m 0,-60 c 2.98,18.88 0.1,34.81 0,60 m 0,0 c -33.84,4.46 -69.96,-2.33 -120,0 m 120,0 c -43.37,-2.59 -86.08,-0.66 -120,0 m 0,0 c -3.58,-11.74 -0.61,-33.39 0,-60 m 0,60 c 1.16,-18.54 2.67,-38.41 0,-60"
fill="none"
stroke="#82b366"
stroke-width="2"
stroke-linejoin="round"
stroke-linecap="round"
stroke-miterlimit="10"
pointer-events="all"
id="path52" />
<g
transform="translate(-0.5,-0.5)"
id="g52"
style="fill:#ff0000">
<switch
id="switch52"
style="fill:#ff0000">
<foreignObject
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
style="overflow: visible; text-align: left;">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 121px; margin-left: 488px;">
<xhtml:div
data-drawio-colors="color: #DBDBDB; "
style="box-sizing: border-box; font-size: 0px; text-align: center;">
<xhtml:div
style="display: inline-block; font-size: 14px; font-family: Helvetica; color: rgb(219, 219, 219); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">
<xhtml:b>Problem</xhtml:b>
<xhtml:br />
<xhtml:font
style="font-size: 12px;">is resolved</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="547"
y="125"
fill="#dbdbdb"
font-family="Helvetica"
font-size="14px"
text-anchor="middle"
id="text52"
style="fill:#ff0000">Problem...</text>
</switch>
</g>
<switch
id="switch54">
<g
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
id="g54" />
<a
transform="translate(0,-5)"
xlink:href="https://www.drawio.com/doc/faq/svg-export-text-problems"
target="_blank"
id="a54">
<text
text-anchor="middle"
font-size="10px"
x="50%"
y="100%"
id="text54">Text is not SVG - cannot display</text>
</a>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="17.999989"
height="18"
viewBox="0 0 4.7624969 4.7625001"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="info-filled.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="6.84375"
inkscape:cy="0.6875"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.222917,-148.43125)">
<title
id="title1">information-slab-circle</title>
<title
id="title1-6">information</title>
<path
d="m 92.842292,150.09812 h -0.47625 v -0.47625 h 0.47625 m 0,2.38126 h -0.47625 v -1.42875 h 0.47625 m -0.238125,-2.14313 a 2.3812503,2.3812503 0 0 0 -2.38125,2.38125 2.3812503,2.3812503 0 0 0 2.38125,2.38124 2.3812503,2.3812503 0 0 0 2.381246,-2.38124 2.3812503,2.3812503 0 0 0 -2.381246,-2.38125 z"
id="path1-2"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#1b4e78;fill-opacity:1;stroke-width:0.311724;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="17.999989"
height="18"
viewBox="0 0 4.7624969 4.7625001"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="info-outline.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="21.610952"
inkscape:cy="4.5961943"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.222917,-148.43125)">
<title
id="title1">information-slab-circle</title>
<title
id="title1-6">information-slab-circle-outline</title>
<title
id="title1-5">information-outline</title>
<path
d="m 92.366045,150.09812 h 0.47625 v -0.47625 h -0.47625 m 0.238125,3.09564 c -1.050132,0 -1.905003,-0.85488 -1.905003,-1.90501 0,-1.05013 0.854871,-1.90501 1.905003,-1.90501 1.050133,0 1.905006,0.85488 1.905006,1.90501 0,1.05013 -0.854873,1.90501 -1.905006,1.90501 m 0,-4.28626 a 2.381253,2.381253 0 0 0 -2.381253,2.38125 2.381253,2.381253 0 0 0 2.381253,2.38125 2.381253,2.381253 0 0 0 2.381256,-2.38125 2.381253,2.381253 0 0 0 -2.381256,-2.38125 m -0.238125,3.57188 h 0.47625 v -1.42875 h -0.47625 z"
id="path1-3"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#c9c9c9;fill-opacity:1;stroke-width:0.238125;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="31.999998"
height="28.799999"
viewBox="0 0 8.466666 7.62"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="9.03125"
inkscape:cy="17.3125"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.275834,-148.48417)">
<title
id="title1">alert-octagram</title>
<title
id="title1-7">alert-octagram-outline</title>
<title
id="title1-3">database-alert</title>
<title
id="title1-6">database-alert-outline</title>
<path
d="m 93.6625,148.48417 c -1.871133,0 -3.386666,0.75776 -3.386666,1.69332 v 4.23335 c 0,0.93557 1.519766,1.69333 3.386666,1.69333 1.866901,0 3.386667,-0.75776 3.386667,-1.69333 v -4.23335 c 0,-0.93556 -1.515533,-1.69332 -3.386667,-1.69332 m 2.54,5.92667 c 0,0.21166 -0.901699,0.84666 -2.54,0.84666 -1.6383,0 -2.540001,-0.635 -2.540001,-0.84666 v -0.94403 c 0.681568,0.33019 1.574801,0.52069 2.540001,0.52069 0.9652,0 1.858434,-0.1905 2.54,-0.52069 v 0.94403 m 0,-1.92618 c -0.550333,0.40218 -1.515533,0.65618 -2.54,0.65618 -1.024466,0 -1.989666,-0.254 -2.540001,-0.65618 v -1.18956 c 0.622301,0.35137 1.528234,0.57574 2.540001,0.57574 1.011768,0 1.917701,-0.22437 2.54,-0.57574 v 1.18956 m -2.54,-1.46049 c -1.6383,0 -2.540001,-0.635 -2.540001,-0.84668 0,-0.21166 0.901701,-0.84665 2.540001,-0.84665 1.638301,0 2.54,0.63499 2.54,0.84665 0,0.21168 -0.901699,0.84668 -2.54,0.84668 m 5.08,-0.84668 v 2.54001 h -0.846665 v -2.54001 H 98.7425 m -0.846665,3.38668 H 98.7425 v 0.84667 h -0.846665 z"
id="path1"
style="fill:#7bb8eb;fill-opacity:1;stroke-width:0.423333" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="28.800037"
viewBox="0 0 8.4666665 7.6200101"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="logo_selected.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="9.03125"
inkscape:cy="17.3125"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.275834,-148.48417)">
<title
id="title1">alert-octagram</title>
<title
id="title1-7">alert-octagram-outline</title>
<title
id="title1-3">database-alert</title>
<path
d="m 97.049172,150.1775 c 0,0.93557 -1.515534,1.69334 -3.38667,1.69334 -1.871134,0 -3.386668,-0.75777 -3.386668,-1.69334 0,-0.93557 1.515534,-1.69333 3.386668,-1.69333 1.871136,0 3.38667,0.75776 3.38667,1.69333 m -3.38667,4.65667 c -1.871134,0 -3.386668,-0.75776 -3.386668,-1.69333 v 1.27001 c 0,0.93557 1.515534,1.69333 3.386668,1.69333 1.871136,0 3.38667,-0.75776 3.38667,-1.69333 v -1.27001 c 0,0.93557 -1.515534,1.69333 -3.38667,1.69333 m 0,-2.11667 c -1.871134,0 -3.386668,-0.75776 -3.386668,-1.69332 v 1.26999 c 0,0.93557 1.515534,1.69333 3.386668,1.69333 1.871136,0 3.38667,-0.75776 3.38667,-1.69333 v -1.26999 c 0,0.93556 -1.515534,1.69332 -3.38667,1.69332 m 4.233338,1.69335 h 0.846661 v -0.84668 H 97.89584 v 0.84668 m 0,-4.23335 v 2.54 h 0.846661 v -2.54 z"
id="path1"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#9bff07;fill-opacity:1;stroke-width:0.431972;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="15.63086mm"
height="8.46667mm"
viewBox="0 0 15.63086 8.46667"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
sodipodi:docname="notification_selected.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="11.313708"
inkscape:cx="11.623068"
inkscape:cy="6.3197669"
inkscape:window-width="1916"
inkscape:window-height="1161"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-101.86454,-146.84375)">
<title
id="title1">email-fast</title>
<title
id="title1-8">email-fast-outline</title>
<path
d="m 116.19281,146.84375 h -8.46666 c -0.7164,0 -1.30257,0.58614 -1.30257,1.30254 v 5.86156 c 0,0.72292 0.58617,1.30257 1.30257,1.30257 h 8.46666 c 0.72294,0 1.30259,-0.57965 1.30259,-1.30257 v -5.86156 c 0,-0.7164 -0.57965,-1.30254 -1.30259,-1.30254 m 0,7.1641 h -8.46666 v -4.77389 l 4.23333,2.16877 4.23333,-2.16877 v 4.77389 m -4.23333,-3.70579 -4.23333,-2.15577 h 8.46666 l -4.23333,2.15577 m -6.83846,3.70579 c 0,0.11076 0.0197,0.21487 0.0325,0.32565 h -2.63771 c -0.35951,0 -0.65127,-0.29308 -0.65127,-0.65129 0,-0.35821 0.29176,-0.65127 0.65127,-0.65127 h 2.60515 v 0.97691 m -1.30256,-6.18718 h 1.33512 c -0.0123,0.11075 -0.0325,0.21486 -0.0325,0.32562 v 0.97694 h -1.30256 c -0.35821,0 -0.65129,-0.29306 -0.65129,-0.65127 0,-0.35821 0.29308,-0.65129 0.65129,-0.65129 m -1.30259,3.25641 c 0,-0.35821 0.29311,-0.65127 0.6513,-0.65127 h 1.95385 v 1.30254 h -1.95385 c -0.35819,0 -0.6513,-0.29306 -0.6513,-0.65127 z"
id="path1"
style="stroke-width:0.431972;font-variation-settings:normal;opacity:1;vector-effect:none;fill:#7bb8eb;fill-opacity:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="15.63086mm"
height="8.46667mm"
viewBox="0 0 15.63086 8.46667"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
sodipodi:docname="notification_selected.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="11.313708"
inkscape:cx="11.623068"
inkscape:cy="6.850097"
inkscape:window-width="1916"
inkscape:window-height="1161"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-101.86456,-146.71146)">
<title
id="title1">email-fast</title>
<path
d="m 116.19286,146.71146 h -8.46669 c -0.7164,0 -1.30254,0.58614 -1.30254,1.30254 v 5.86156 c 0,0.72292 0.58614,1.30257 1.30254,1.30257 h 8.46669 c 0.72291,0 1.30256,-0.57965 1.30256,-1.30257 V 148.014 c 0,-0.7164 -0.57965,-1.30254 -1.30256,-1.30254 m 0,2.39021 -4.23334,2.16877 -4.23335,-2.16877 V 148.014 l 4.23335,2.15577 4.23334,-2.15577 v 1.08767 m -11.07182,4.77389 c 0,0.11076 0.0197,0.21487 0.0325,0.32565 h -2.63769 c -0.35951,0 -0.65129,-0.29308 -0.65129,-0.65129 0,-0.35821 0.29178,-0.65127 0.65129,-0.65127 h 2.60513 v 0.97691 m -1.30256,-6.18718 h 1.33512 c -0.0123,0.11075 -0.0325,0.21486 -0.0325,0.32562 v 0.97694 h -1.30256 c -0.35821,0 -0.65129,-0.29306 -0.65129,-0.65127 0,-0.35821 0.29308,-0.65129 0.65129,-0.65129 m -1.30256,3.25641 c 0,-0.35821 0.29308,-0.65127 0.65127,-0.65127 h 1.95385 v 1.30254 h -1.95385 c -0.35819,0 -0.65127,-0.29306 -0.65127,-0.65127 z"
id="path1"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#9bff07;fill-opacity:1;stroke-width:0.32964801;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="20.000002"
height="20.000013"
viewBox="0 0 5.291667 5.2916703"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="ok.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.9208594"
inkscape:cx="9.7574023"
inkscape:cy="10.27095"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.222917,-148.43125)">
<title
id="title1">check-circle</title>
<path
d="m 92.86875,148.43125 c -1.455208,0 -2.645833,1.19063 -2.645833,2.64583 0,1.45521 1.190625,2.64584 2.645833,2.64584 1.455209,0 2.645834,-1.19063 2.645834,-2.64584 0,-1.4552 -1.190625,-2.64583 -2.645834,-2.64583 m -0.529166,3.96875 -1.322917,-1.32292 0.373062,-0.37306 0.949855,0.94721 2.008187,-2.00819 0.373063,0.37571 z"
id="path1"
style="fill:#aad400;stroke-width:0.264583" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="31.999975"
viewBox="0 0 8.4666665 8.4666603"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="problems.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="9.03125"
inkscape:cy="17.3125"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.275834,-148.48417)">
<title
id="title1">alert-octagram</title>
<title
id="title1-7">alert-octagram-outline</title>
<path
d="m 90.275834,154.47132 0.725714,-1.75381 -0.725714,-1.75381 1.75381,-0.72572 0.725715,-1.75381 1.753808,0.72571 1.753809,-0.72571 0.725714,1.75381 1.753811,0.72572 -0.725715,1.75381 0.725715,1.75381 -1.753811,0.72571 -0.725714,1.75382 -1.753809,-0.72572 -1.753808,0.72572 -0.725715,-1.75382 -1.75381,-0.72571 m 1.12745,-3.04973 0.535645,1.29592 -0.535645,1.29592 1.287278,0.52269 0.522687,1.28727 1.295918,-0.53565 1.295919,0.53565 0.522687,-1.28727 1.287278,-0.52269 -0.535646,-1.29592 0.535646,-1.29592 -1.287278,-0.52269 -0.522687,-1.28727 -1.295919,0.53564 -1.295918,-0.53564 -0.522687,1.28727 -1.287278,0.52269 m 2.673911,2.59184 h 0.863945 v 0.86395 h -0.863945 v -0.86395 m 0,-3.45579 h 0.863945 v 2.59184 h -0.863945 v -2.59184"
id="path1-5"
style="stroke-width:0.431972;fill:#7bb8eb;fill-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="31.999975"
viewBox="0 0 8.4666665 8.4666603"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="problems_selected.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="-0.1767767"
inkscape:cy="15.202796"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-90.275834,-148.48417)">
<title
id="title1">alert-octagram</title>
<path
d="m 90.275834,154.47131 0.725714,-1.75382 -0.725714,-1.75379 1.753809,-0.72572 0.725714,-1.75381 1.75381,0.72571 1.75381,-0.72571 0.725715,1.75381 1.753809,0.72572 -0.725715,1.75379 0.725715,1.75382 -1.753809,0.72571 -0.725715,1.75381 -1.75381,-0.72571 -1.75381,0.72571 -0.725714,-1.75381 -1.753809,-0.72571 m 4.665306,0.40605 v -0.86395 h -0.863946 v 0.86395 h 0.863946 m 0,-1.72788 v -2.59184 h -0.863946 v 2.59184 z"
id="path1"
style="stroke-width:0.431972;fill:#9bff07;fill-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="31.99999"
height="32.000011"
viewBox="0 0 8.466664 8.4666699"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="triggers.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="7.5"
inkscape:cy="4"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-87.047917,-148.43125)">
<title
id="title1">script-text</title>
<title
id="title1-6">script-text-outline</title>
<title
id="title1-9">calculator-variant-outline</title>
<path
d="m 94.573842,148.43125 h -6.585184 c -0.517408,0 -0.940741,0.42334 -0.940741,0.94075 v 6.58517 c 0,0.51742 0.423333,0.94075 0.940741,0.94075 h 6.585184 c 0.517409,0 0.940739,-0.42333 0.940739,-0.94075 V 149.372 c 0,-0.51741 -0.42333,-0.94075 -0.940739,-0.94075 m 0,7.52592 H 87.988658 V 149.372 h 6.585184 v 6.58517 m -6.020739,-5.31518 h 2.35185 v 0.70556 h -2.35185 v -0.70556 m 3.198517,3.81001 h 2.351853 v 0.70554 H 91.75162 V 154.452 m 0,-1.22297 h 2.351853 v 0.70556 H 91.75162 v -0.70556 m -2.351851,2.25778 h 0.705556 v -0.94075 h 0.94074 v -0.70555 h -0.94074 v -0.94074 h -0.705556 v 0.94074 h -0.940741 v 0.70555 h 0.940741 v 0.94075 m 2.869259,-3.33963 0.658519,-0.65853 0.658518,0.65853 0.517408,-0.47037 -0.65852,-0.65852 0.65852,-0.65852 -0.517408,-0.51741 -0.658518,0.65853 -0.658519,-0.65853 -0.517408,0.51741 0.658519,0.65852 -0.658519,0.65852 z"
id="path1-1"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#7bb8eb;fill-opacity:1;stroke-width:0.423333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="31.99999"
height="32.000011"
viewBox="0 0 8.466664 8.4666699"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="triggers_selected.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-3.5"
inkscape:cy="65"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-89.918898,-132.29942)">
<title
id="title1">script-text</title>
<title
id="title1-9">calculator-variant</title>
<path
d="m 97.444823,132.29942 h -6.585184 c -0.517408,0 -0.940741,0.42334 -0.940741,0.94075 v 6.58517 c 0,0.51742 0.423333,0.94075 0.940741,0.94075 h 6.585184 c 0.517408,0 0.940742,-0.42333 0.940742,-0.94075 v -6.58517 c 0,-0.51741 -0.423334,-0.94075 -0.940742,-0.94075 m -2.822222,1.92852 0.517408,-0.51741 0.658519,0.65853 0.658518,-0.65853 0.517408,0.51741 -0.65852,0.65852 0.65852,0.65852 -0.517408,0.51741 -0.658518,-0.65853 -0.658519,0.65853 -0.517408,-0.51741 0.658519,-0.65852 -0.658519,-0.65852 m -3.198517,0.28222 h 2.35185 v 0.70556 h -2.35185 v -0.70556 m 2.492962,3.90407 h -0.94074 v 0.94075 H 92.27075 v -0.94075 h -0.940741 v -0.70555 h 0.940741 v -0.94074 h 0.705556 v 0.94074 h 0.94074 v 0.70555 m 3.057408,0.56444 h -2.351853 v -0.70554 h 2.351853 v 0.70554 m 0,-1.12889 h -2.351853 v -0.70554 h 2.351853 z"
id="path1"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#9bff07;fill-opacity:1;stroke-width:1.22872;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="18.500002"
height="15"
viewBox="0 0 4.8947921 3.9687501"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="values.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4.9375"
inkscape:cx="11.64557"
inkscape:cy="25.721519"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-81.359375,-211.79896)">
<title
id="title1">format-list-bulleted</title>
<path
d="m 82.55,211.93125 h 3.704167 v 0.52917 H 82.55 v -0.52917 m 0,2.11667 v -0.52917 h 3.704167 v 0.52917 H 82.55 m -0.79375,-2.24896 a 0.396875,0.396875 0 0 1 0.396875,0.39687 0.396875,0.396875 0 0 1 -0.396875,0.39688 0.396875,0.396875 0 0 1 -0.396875,-0.39688 0.396875,0.396875 0 0 1 0.396875,-0.39687 m 0,1.5875 a 0.396875,0.396875 0 0 1 0.396875,0.39687 0.396875,0.396875 0 0 1 -0.396875,0.39688 0.396875,0.396875 0 0 1 -0.396875,-0.39688 0.396875,0.396875 0 0 1 0.396875,-0.39687 m 0.79375,2.24896 v -0.52917 h 3.704167 v 0.52917 H 82.55 m -0.79375,-0.66146 a 0.396875,0.396875 0 0 1 0.396875,0.39687 0.396875,0.396875 0 0 1 -0.396875,0.39688 0.396875,0.396875 0 0 1 -0.396875,-0.39688 0.396875,0.396875 0 0 1 0.396875,-0.39687 z"
id="path1"
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#1b4e78;fill-opacity:1;stroke-width:0.311724;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="23.157846"
height="20.000013"
viewBox="0 0 6.1271801 5.2916704"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="warning.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
inkscape:cx="9.3028736"
inkscape:cy="12.772116"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-123.825,-155.04583)">
<title
id="title1">alert</title>
<path
d="m 127.21387,158.38793 h -0.65056 v -1.39253 h 0.65056 m 0,2.50657 h -0.65056 v -0.55701 h 0.65056 m -3.38887,1.39254 h 6.12718 l -3.06358,-5.29167 z"
id="path1"
style="fill:#ff9800;fill-opacity:1;stroke-width:0.278508"
sodipodi:nodetypes="cccccccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="31.999987"
height="29.090721"
viewBox="0 0 8.4666629 7.6969202"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
sodipodi:docname="acknowledge.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="28.019106"
inkscape:cy="19.489631"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="1916"
inkscape:window-height="1041"
inkscape:window-x="1920"
inkscape:window-y="1098"
inkscape:window-maximized="1"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-89.958296,-148.43122)">
<title
id="title1">thumb-up</title>
<path
d="m 91.497681,151.50999 v 4.61815 h -1.539385 v -4.61815 h 1.539385 m 1.539383,4.61815 a 0.76969186,0.76969186 0 0 1 -0.769692,-0.76969 v -3.84846 c 0,-0.21166 0.08467,-0.40408 0.22706,-0.54263 l 2.532286,-2.53614 0.407936,0.40794 c 0.103912,0.10385 0.169333,0.24631 0.169333,0.40408 l -0.01149,0.1232 -0.365604,1.75875 h 2.428378 c 0.42718,0 0.769693,0.34636 0.769693,0.76969 v 0.76969 c 0,0.10008 -0.01924,0.19242 -0.05388,0.28095 l -1.162236,2.71316 c -0.115446,0.27709 -0.388694,0.46951 -0.708116,0.46951 h -3.463613 m 0,-0.7697 h 3.47516 l 1.142991,-2.69392 v -0.76969 h -3.382795 l 0.434876,-2.04738 -1.670232,1.67408 z"
id="path1"
style="fill:#666666;fill-opacity:1;stroke-width:0.384845" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="257"
height="256"
viewBox="0 0 67.997915 67.733336"
version="1.1"
id="svg8"
inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"
sodipodi:docname="background.svg"
inkscape:export-filename="gruvbox.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#282828"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="165.63976"
inkscape:cy="121.62237"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="1459"
inkscape:window-height="1404"
inkscape:window-x="3657"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:showpageshadow="true"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d6d6d6"
showborder="true" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="color:#000000;overflow:visible;fill:#222222;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.264584;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000"
id="rect40644"
width="67.733337"
height="67.73333"
x="0"
y="0" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 17.065625,0.1322915 V 67.601042"
id="path37309" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 8.5989583,0.1322915 V 67.601042"
id="path37610" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 25.532292,0.1322915 V 67.601042"
id="path37612" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 33.998959,0.1322915 V 67.601042"
id="path37616" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 42.465625,0.1322915 V 67.601042"
id="path37618" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 50.932292,0.1322915 V 67.601042"
id="path37620" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 59.398959,0.1322915 V 67.601042"
id="path37622" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.26458334;stroke-linecap:round;stroke-dasharray:0.5291667, 0.5291667;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 67.865626,0.1322915 V 67.601042"
id="path37626" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,50.932293 H 67.601042"
id="path43996" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,59.39896 H 67.601042"
id="path43998" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,42.465626 H 67.601042"
id="path44000" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,33.998959 H 67.601042"
id="path44002" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,25.532293 H 67.601042"
id="path44004" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,17.065626 H 67.601042"
id="path44006" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,8.598959 H 67.601042"
id="path44008" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,0.132292 H 67.601042"
id="path44010" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,55.165625 H 67.601042"
id="path44772" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,63.632292 H 67.601042"
id="path44774" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,46.698958 H 67.601042"
id="path44776" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,38.232291 H 67.601042"
id="path44778" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,29.765625 H 67.601042"
id="path44780" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,21.298958 H 67.601042"
id="path44782" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,12.832291 H 67.601042"
id="path44784" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 0.1322915,4.365624 H 67.601042"
id="path44786" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 12.832292,0.1322915 V 67.601042"
id="path44813" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 4.3656249,0.1322915 V 67.601042"
id="path44815" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 21.298959,0.1322915 V 67.601042"
id="path44817" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 29.765626,0.1322915 V 67.601042"
id="path44819" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 38.232292,0.1322915 V 67.601042"
id="path44821" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 46.698959,0.1322915 V 67.601042"
id="path44823" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 55.165626,0.1322915 V 67.601042"
id="path44825" />
<path
style="color:#000000;overflow:visible;fill:#d9664d;fill-opacity:0.97101426;fill-rule:evenodd;stroke:#363231;stroke-width:0.264583;stroke-linecap:round;stroke-dasharray:0.52916598, 0.52916598;stroke-opacity:1;paint-order:markers stroke fill;stop-color:#000000;stroke-dashoffset:0"
d="M 63.632293,0.1322915 V 67.601042"
id="path44827" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Some files were not shown because too many files have changed in this diff Show More