mirror of
https://github.com/mentos1386/zdravko.git
synced 2025-03-29 12:27:55 +00:00
feat: groups for monitors
This commit is contained in:
parent
571fee81f5
commit
24e8414e03
13 changed files with 258 additions and 116 deletions
database
deploy
internal
web
|
@ -58,8 +58,9 @@ type Monitor struct {
|
||||||
CreatedAt *Time `db:"created_at"`
|
CreatedAt *Time `db:"created_at"`
|
||||||
UpdatedAt *Time `db:"updated_at"`
|
UpdatedAt *Time `db:"updated_at"`
|
||||||
|
|
||||||
Id string `db:"id"`
|
Id string `db:"id"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
|
Group string `db:"group"`
|
||||||
|
|
||||||
Schedule string `db:"schedule"`
|
Schedule string `db:"schedule"`
|
||||||
Script string `db:"script"`
|
Script string `db:"script"`
|
||||||
|
|
|
@ -9,6 +9,7 @@ CREATE TABLE oauth2_states (
|
||||||
CREATE TABLE monitors (
|
CREATE TABLE monitors (
|
||||||
id TEXT NOT NULL,
|
id TEXT NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
|
"group" TEXT NOT NULL DEFAULT 'default',
|
||||||
schedule TEXT NOT NULL,
|
schedule TEXT NOT NULL,
|
||||||
script TEXT NOT NULL,
|
script TEXT NOT NULL,
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@ primary_region = 'waw'
|
||||||
ROOT_URL = 'https://zdravko.mnts.dev'
|
ROOT_URL = 'https://zdravko.mnts.dev'
|
||||||
TEMPORAL_SERVER_HOST = 'server.process.zdravko.internal:7233'
|
TEMPORAL_SERVER_HOST = 'server.process.zdravko.internal:7233'
|
||||||
|
|
||||||
TEMPORAL_DATABASE_PATH = '/data/temporal-7.db'
|
TEMPORAL_DATABASE_PATH = '/data/temporal-8.db'
|
||||||
DATABASE_PATH = '/data/zdravko-7.db'
|
DATABASE_PATH = '/data/zdravko-8.db'
|
||||||
|
|
||||||
[processes]
|
[processes]
|
||||||
server = '--temporal --server'
|
server = '--temporal --server'
|
||||||
|
|
|
@ -13,14 +13,15 @@ import (
|
||||||
|
|
||||||
type IndexData struct {
|
type IndexData struct {
|
||||||
*components.Base
|
*components.Base
|
||||||
HealthChecks []*HealthCheck
|
Monitors map[string][]*Monitor
|
||||||
MonitorsLength int
|
MonitorsLength int
|
||||||
TimeRange string
|
TimeRange string
|
||||||
Status models.MonitorStatus
|
Status models.MonitorStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type HealthCheck struct {
|
type Monitor struct {
|
||||||
Name string
|
Name string
|
||||||
|
Group string
|
||||||
Status models.MonitorStatus
|
Status models.MonitorStatus
|
||||||
History *History
|
History *History
|
||||||
}
|
}
|
||||||
|
@ -96,7 +97,7 @@ func (h *BaseHandler) Index(c echo.Context) error {
|
||||||
|
|
||||||
overallStatus := models.MonitorSuccess
|
overallStatus := models.MonitorSuccess
|
||||||
|
|
||||||
monitorsWithHistory := make([]*HealthCheck, len(monitors))
|
monitorsWithHistory := make([]*Monitor, len(monitors))
|
||||||
for i, monitor := range monitors {
|
for i, monitor := range monitors {
|
||||||
history, err := services.GetMonitorHistoryForMonitor(ctx, h.db, monitor.Id)
|
history, err := services.GetMonitorHistoryForMonitor(ctx, h.db, monitor.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -118,21 +119,26 @@ func (h *BaseHandler) Index(c echo.Context) error {
|
||||||
overallStatus = status
|
overallStatus = status
|
||||||
}
|
}
|
||||||
|
|
||||||
monitorsWithHistory[i] = &HealthCheck{
|
monitorsWithHistory[i] = &Monitor{
|
||||||
Name: monitor.Name,
|
Name: monitor.Name,
|
||||||
|
Group: monitor.Group,
|
||||||
Status: status,
|
Status: status,
|
||||||
History: historyResult,
|
History: historyResult,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monitorsByGroup := map[string][]*Monitor{}
|
||||||
|
for _, monitor := range monitorsWithHistory {
|
||||||
|
monitorsByGroup[monitor.Group] = append(monitorsByGroup[monitor.Group], monitor)
|
||||||
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "index.tmpl", &IndexData{
|
return c.Render(http.StatusOK, "index.tmpl", &IndexData{
|
||||||
Base: &components.Base{
|
Base: &components.Base{
|
||||||
NavbarActive: GetPageByTitle(Pages, "Status"),
|
NavbarActive: GetPageByTitle(Pages, "Status"),
|
||||||
Navbar: Pages,
|
Navbar: Pages,
|
||||||
},
|
},
|
||||||
HealthChecks: monitorsWithHistory,
|
Monitors: monitorsByGroup,
|
||||||
MonitorsLength: len(monitors),
|
TimeRange: timeRange,
|
||||||
TimeRange: timeRange,
|
Status: overallStatus,
|
||||||
Status: overallStatus,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.tjo.space/mentos1386/zdravko/database/models"
|
"code.tjo.space/mentos1386/zdravko/database/models"
|
||||||
|
@ -17,12 +18,14 @@ import (
|
||||||
|
|
||||||
type CreateMonitor struct {
|
type CreateMonitor struct {
|
||||||
Name string `validate:"required"`
|
Name string `validate:"required"`
|
||||||
|
Group string `validate:"required"`
|
||||||
WorkerGroups string `validate:"required"`
|
WorkerGroups string `validate:"required"`
|
||||||
Schedule string `validate:"required,cron"`
|
Schedule string `validate:"required,cron"`
|
||||||
Script string `validate:"required"`
|
Script string `validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateMonitor struct {
|
type UpdateMonitor struct {
|
||||||
|
Group string `validate:"required"`
|
||||||
WorkerGroups string `validate:"required"`
|
WorkerGroups string `validate:"required"`
|
||||||
Schedule string `validate:"required,cron"`
|
Schedule string `validate:"required,cron"`
|
||||||
Script string `validate:"required"`
|
Script string `validate:"required"`
|
||||||
|
@ -35,7 +38,8 @@ type MonitorWithWorkerGroupsAndStatus struct {
|
||||||
|
|
||||||
type SettingsMonitors struct {
|
type SettingsMonitors struct {
|
||||||
*Settings
|
*Settings
|
||||||
Monitors []*MonitorWithWorkerGroupsAndStatus
|
Monitors map[string][]*MonitorWithWorkerGroupsAndStatus
|
||||||
|
MonitorGroups []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingsMonitor struct {
|
type SettingsMonitor struct {
|
||||||
|
@ -64,13 +68,23 @@ func (h *BaseHandler) SettingsMonitorsGET(c echo.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monitorGroups := []string{}
|
||||||
|
monitorsByGroup := map[string][]*MonitorWithWorkerGroupsAndStatus{}
|
||||||
|
for _, monitor := range monitorsWithStatus {
|
||||||
|
monitorsByGroup[monitor.Group] = append(monitorsByGroup[monitor.Group], monitor)
|
||||||
|
if slices.Contains(monitorGroups, monitor.Group) == false {
|
||||||
|
monitorGroups = append(monitorGroups, monitor.Group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return c.Render(http.StatusOK, "settings_monitors.tmpl", &SettingsMonitors{
|
return c.Render(http.StatusOK, "settings_monitors.tmpl", &SettingsMonitors{
|
||||||
Settings: NewSettings(
|
Settings: NewSettings(
|
||||||
cc.Principal.User,
|
cc.Principal.User,
|
||||||
GetPageByTitle(SettingsPages, "Monitors"),
|
GetPageByTitle(SettingsPages, "Monitors"),
|
||||||
[]*components.Page{GetPageByTitle(SettingsPages, "Monitors")},
|
[]*components.Page{GetPageByTitle(SettingsPages, "Monitors")},
|
||||||
),
|
),
|
||||||
Monitors: monitorsWithStatus,
|
Monitors: monitorsByGroup,
|
||||||
|
MonitorGroups: monitorGroups,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +188,7 @@ func (h *BaseHandler) SettingsMonitorsDescribePOST(c echo.Context) error {
|
||||||
monitorId := c.Param("id")
|
monitorId := c.Param("id")
|
||||||
|
|
||||||
update := UpdateMonitor{
|
update := UpdateMonitor{
|
||||||
|
Group: c.FormValue("group"),
|
||||||
WorkerGroups: strings.TrimSpace(c.FormValue("workergroups")),
|
WorkerGroups: strings.TrimSpace(c.FormValue("workergroups")),
|
||||||
Schedule: c.FormValue("schedule"),
|
Schedule: c.FormValue("schedule"),
|
||||||
Script: c.FormValue("script"),
|
Script: c.FormValue("script"),
|
||||||
|
@ -187,6 +202,7 @@ func (h *BaseHandler) SettingsMonitorsDescribePOST(c echo.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
monitor.Group = update.Group
|
||||||
monitor.Schedule = update.Schedule
|
monitor.Schedule = update.Schedule
|
||||||
monitor.Script = update.Script
|
monitor.Script = update.Script
|
||||||
|
|
||||||
|
@ -251,6 +267,7 @@ func (h *BaseHandler) SettingsMonitorsCreatePOST(c echo.Context) error {
|
||||||
|
|
||||||
create := CreateMonitor{
|
create := CreateMonitor{
|
||||||
Name: c.FormValue("name"),
|
Name: c.FormValue("name"),
|
||||||
|
Group: c.FormValue("group"),
|
||||||
Schedule: c.FormValue("schedule"),
|
Schedule: c.FormValue("schedule"),
|
||||||
WorkerGroups: c.FormValue("workergroups"),
|
WorkerGroups: c.FormValue("workergroups"),
|
||||||
Script: c.FormValue("script"),
|
Script: c.FormValue("script"),
|
||||||
|
@ -282,6 +299,7 @@ func (h *BaseHandler) SettingsMonitorsCreatePOST(c echo.Context) error {
|
||||||
|
|
||||||
monitor := &models.Monitor{
|
monitor := &models.Monitor{
|
||||||
Name: create.Name,
|
Name: create.Name,
|
||||||
|
Group: create.Group,
|
||||||
Id: monitorId,
|
Id: monitorId,
|
||||||
Schedule: create.Schedule,
|
Schedule: create.Schedule,
|
||||||
Script: create.Script,
|
Script: create.Script,
|
||||||
|
|
|
@ -62,7 +62,7 @@ func SetMonitorStatus(ctx context.Context, temporal client.Client, id string, st
|
||||||
|
|
||||||
func CreateMonitor(ctx context.Context, db *sqlx.DB, monitor *models.Monitor) error {
|
func CreateMonitor(ctx context.Context, db *sqlx.DB, monitor *models.Monitor) error {
|
||||||
_, err := db.NamedExecContext(ctx,
|
_, err := db.NamedExecContext(ctx,
|
||||||
"INSERT INTO monitors (id, name, script, schedule) VALUES (:id, :name, :script, :schedule)",
|
`INSERT INTO monitors (id, name, "group", script, schedule) VALUES (:id, :name, :group, :script, :schedule)`,
|
||||||
monitor,
|
monitor,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
|
@ -70,7 +70,7 @@ func CreateMonitor(ctx context.Context, db *sqlx.DB, monitor *models.Monitor) er
|
||||||
|
|
||||||
func UpdateMonitor(ctx context.Context, db *sqlx.DB, monitor *models.Monitor) error {
|
func UpdateMonitor(ctx context.Context, db *sqlx.DB, monitor *models.Monitor) error {
|
||||||
_, err := db.NamedExecContext(ctx,
|
_, err := db.NamedExecContext(ctx,
|
||||||
"UPDATE monitors SET name=:name, script=:script, schedule=:schedule WHERE id=:id",
|
`UPDATE monitors SET "group"=:group, script=:script, schedule=:schedule WHERE id=:id`,
|
||||||
monitor,
|
monitor,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
|
@ -126,6 +126,7 @@ func GetMonitorWithWorkerGroups(ctx context.Context, db *sqlx.DB, id string) (*m
|
||||||
SELECT
|
SELECT
|
||||||
monitors.id,
|
monitors.id,
|
||||||
monitors.name,
|
monitors.name,
|
||||||
|
monitors."group",
|
||||||
monitors.script,
|
monitors.script,
|
||||||
monitors.schedule,
|
monitors.schedule,
|
||||||
monitors.created_at,
|
monitors.created_at,
|
||||||
|
@ -150,6 +151,7 @@ WHERE monitors.id=$1
|
||||||
err = rows.Scan(
|
err = rows.Scan(
|
||||||
&monitor.Id,
|
&monitor.Id,
|
||||||
&monitor.Name,
|
&monitor.Name,
|
||||||
|
&monitor.Group,
|
||||||
&monitor.Script,
|
&monitor.Script,
|
||||||
&monitor.Schedule,
|
&monitor.Schedule,
|
||||||
&monitor.CreatedAt,
|
&monitor.CreatedAt,
|
||||||
|
@ -181,6 +183,7 @@ func GetMonitorsWithWorkerGroups(ctx context.Context, db *sqlx.DB) ([]*models.Mo
|
||||||
SELECT
|
SELECT
|
||||||
monitors.id,
|
monitors.id,
|
||||||
monitors.name,
|
monitors.name,
|
||||||
|
monitors."group",
|
||||||
monitors.script,
|
monitors.script,
|
||||||
monitors.schedule,
|
monitors.schedule,
|
||||||
monitors.created_at,
|
monitors.created_at,
|
||||||
|
@ -205,6 +208,7 @@ ORDER BY monitors.name
|
||||||
err = rows.Scan(
|
err = rows.Scan(
|
||||||
&monitor.Id,
|
&monitor.Id,
|
||||||
&monitor.Name,
|
&monitor.Name,
|
||||||
|
&monitor.Group,
|
||||||
&monitor.Script,
|
&monitor.Script,
|
||||||
&monitor.Schedule,
|
&monitor.Schedule,
|
||||||
&monitor.CreatedAt,
|
&monitor.CreatedAt,
|
||||||
|
|
|
@ -56,10 +56,10 @@ code {
|
||||||
@apply bg-blue-700 text-white;
|
@apply bg-blue-700 text-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monitors {
|
.monitors .monitors-list {
|
||||||
@apply grid justify-items-stretch justify-stretch items-center mt-20 bg-white shadow-md p-5 rounded-lg;
|
@apply grid justify-items-stretch justify-stretch items-center bg-white shadow-md p-5 py-2 rounded-lg;
|
||||||
}
|
}
|
||||||
.monitors > div:not(:last-child) {
|
.monitors .monitors-list > div:not(:last-child) {
|
||||||
@apply mb-3;
|
@apply mb-3;
|
||||||
}
|
}
|
||||||
.monitors .time-range > a {
|
.monitors .time-range > a {
|
||||||
|
@ -113,9 +113,16 @@ code {
|
||||||
.settings section table thead th {
|
.settings section table thead th {
|
||||||
@apply px-6 py-4 text-center text-xs font-semibold text-gray-600 uppercase tracking-wider;
|
@apply px-6 py-4 text-center text-xs font-semibold text-gray-600 uppercase tracking-wider;
|
||||||
}
|
}
|
||||||
|
.settings section table tbody tr {
|
||||||
|
@apply odd:bg-white even:bg-gray-50;
|
||||||
|
}
|
||||||
.settings section table tbody tr th {
|
.settings section table tbody tr th {
|
||||||
@apply px-6 py-4 font-medium text-gray-900 whitespace-nowrap text-center;
|
@apply px-6 py-4 font-medium text-gray-900 whitespace-nowrap text-center;
|
||||||
}
|
}
|
||||||
.settings section table tbody tr td {
|
.settings section table tbody tr td {
|
||||||
@apply px-6 py-4 text-center whitespace-nowrap;
|
@apply px-6 py-4 text-center whitespace-nowrap;
|
||||||
}
|
}
|
||||||
|
.settings section table tbody tr.row-special {
|
||||||
|
@apply bg-gray-100;
|
||||||
|
@apply font-semibold text-xs uppercase tracking-wider;
|
||||||
|
}
|
||||||
|
|
|
@ -697,6 +697,10 @@ video {
|
||||||
height: 1.25rem;
|
height: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-6 {
|
||||||
|
height: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.h-8 {
|
.h-8 {
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
}
|
}
|
||||||
|
@ -731,6 +735,10 @@ video {
|
||||||
width: 1.25rem;
|
width: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-6 {
|
||||||
|
width: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.w-fit {
|
.w-fit {
|
||||||
width: -moz-fit-content;
|
width: -moz-fit-content;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
@ -796,6 +804,10 @@ video {
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gap-20 {
|
||||||
|
gap: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.gap-4 {
|
.gap-4 {
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
@ -1039,11 +1051,21 @@ video {
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-lg {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.text-sm {
|
.text-sm {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-xl {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.text-xs {
|
.text-xs {
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
|
@ -1322,8 +1344,7 @@ code {
|
||||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
.monitors {
|
.monitors .monitors-list {
|
||||||
margin-top: 5rem;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: stretch;
|
justify-content: stretch;
|
||||||
|
@ -1332,12 +1353,14 @@ code {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||||
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.monitors > div:not(:last-child) {
|
.monitors .monitors-list > div:not(:last-child) {
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1581,6 +1604,16 @@ code {
|
||||||
color: rgb(75 85 99 / var(--tw-text-opacity));
|
color: rgb(75 85 99 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings section table tbody tr:nth-child(odd) {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings section table tbody tr:nth-child(even) {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.settings section table tbody tr th {
|
.settings section table tbody tr th {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding-left: 1.5rem;
|
padding-left: 1.5rem;
|
||||||
|
@ -1602,6 +1635,16 @@ code {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings section table tbody tr.row-special {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
.hover\:bg-blue-800:hover {
|
.hover\:bg-blue-800:hover {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(30 64 175 / var(--tw-bg-opacity));
|
background-color: rgb(30 64 175 / var(--tw-bg-opacity));
|
||||||
|
@ -1703,6 +1746,11 @@ code {
|
||||||
justify-self: end;
|
justify-self: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sm\:px-0 {
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.sm\:px-8 {
|
.sm\:px-8 {
|
||||||
padding-left: 2rem;
|
padding-left: 2rem;
|
||||||
padding-right: 2rem;
|
padding-right: 2rem;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{{ define "main" }}
|
{{ define "main" }}
|
||||||
<div class="container max-w-screen-md flex flex-col mt-20">
|
<div class="container max-w-screen-md flex flex-col mt-20 gap-20">
|
||||||
{{ if eq .MonitorsLength 0 }}
|
{{ $length := len .Monitors }}
|
||||||
|
{{ if eq $length 0 }}
|
||||||
<section>
|
<section>
|
||||||
<div class="py-8 px-4 mx-auto max-w-screen-xl text-center lg:py-16">
|
<div class="py-8 px-4 mx-auto max-w-screen-xl text-center lg:py-16">
|
||||||
<h1
|
<h1
|
||||||
|
@ -57,13 +58,15 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<div class="monitors">
|
<div class="monitors flex flex-col gap-4">
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
<div class="grid grid-cols-1 sm:grid-cols-2 px-4 sm:px-0">
|
||||||
<p class="text-l font-normal text-gray-800 text-center sm:text-left">
|
<h2
|
||||||
|
class="text-xl font-normal text-gray-800 text-center sm:text-left"
|
||||||
|
>
|
||||||
Monitors
|
Monitors
|
||||||
</p>
|
</h2>
|
||||||
<div
|
<div
|
||||||
class="inline-flex gap-1 rounded-md shadow-sm justify-self-center sm:justify-self-end time-range py-1 px-1 bg-gray-100"
|
class="inline-flex gap-1 rounded-md shadow-sm justify-self-center sm:justify-self-end time-range py-1 px-1 bg-white"
|
||||||
role="group"
|
role="group"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
|
@ -86,46 +89,61 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ range .HealthChecks }}
|
{{ range $group, $monitors := .Monitors }}
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
<div class="monitors-list">
|
||||||
<div class="flex items-center">
|
<h3 class="text-lg font-semibold flex flex-row gap-2">
|
||||||
{{ if eq .Status "SUCCESS" }}
|
<!--<span
|
||||||
<span
|
class="flex w-3 h-3 bg-green-400 rounded-full self-center"
|
||||||
class="flex w-3 h-3 me-2 bg-green-400 rounded-full"
|
></span>-->
|
||||||
></span>
|
<span class="flex-1">{{ $group }}</span>
|
||||||
{{ else if eq .Status "FAILURE" }}
|
<svg class="feather h-6 w-6 overflow-visible self-center">
|
||||||
<span class="flex w-3 h-3 me-2 bg-red-400 rounded-full"></span>
|
<use href="/static/icons/feather-sprite.svg#chevron-down" />
|
||||||
{{ else }}
|
</svg>
|
||||||
<span class="flex w-3 h-3 me-2 bg-gray-200 rounded-full"></span>
|
</h3>
|
||||||
{{ end }}
|
{{ range $monitors }}
|
||||||
<p>{{ .Name }}</p>
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
||||||
</div>
|
<div class="flex items-center gap-2">
|
||||||
<div class="justify-self-end text-sm">
|
{{ if eq .Status "SUCCESS" }}
|
||||||
{{ .History.Uptime }}% uptime
|
<span class="flex w-3 h-3 bg-green-400 rounded-full"></span>
|
||||||
</div>
|
{{ else if eq .Status "FAILURE" }}
|
||||||
<div
|
<span class="flex w-3 h-3 bg-red-400 rounded-full"></span>
|
||||||
class="grid gap-px col-span-2 grid-flow-col h-8 rounded overflow-hidden"
|
{{ else }}
|
||||||
>
|
<span class="flex w-3 h-3 bg-gray-200 rounded-full"></span>
|
||||||
{{ range .History.List }}
|
{{ end }}
|
||||||
{{ if eq . "SUCCESS" }}
|
<h4>{{ .Name }}</h4>
|
||||||
<div class="bg-green-400 hover:bg-green-500 flex-auto"></div>
|
</div>
|
||||||
{{ else if eq . "FAILURE" }}
|
<div class="justify-self-end text-sm">
|
||||||
<div class="bg-red-400 hover:bg-red-500 flex-auto"></div>
|
{{ .History.Uptime }}% uptime
|
||||||
{{ else }}
|
</div>
|
||||||
<div class="bg-gray-200 hover:bg-gray-300 flex-auto"></div>
|
<div
|
||||||
{{ end }}
|
class="grid gap-px col-span-2 grid-flow-col h-8 rounded overflow-hidden"
|
||||||
{{ end }}
|
>
|
||||||
</div>
|
{{ range .History.List }}
|
||||||
<div class="text-slate-500 justify-self-start text-sm">
|
{{ if eq . "SUCCESS" }}
|
||||||
{{ if eq $.TimeRange "90days" }}
|
<div
|
||||||
90 days ago
|
class="bg-green-400 hover:bg-green-500 flex-auto"
|
||||||
{{ else if eq $.TimeRange "48hours" }}
|
></div>
|
||||||
48 hours ago
|
{{ else if eq . "FAILURE" }}
|
||||||
{{ else if eq $.TimeRange "90minutes" }}
|
<div class="bg-red-400 hover:bg-red-500 flex-auto"></div>
|
||||||
90 minutes ago
|
{{ else }}
|
||||||
{{ end }}
|
<div
|
||||||
</div>
|
class="bg-gray-200 hover:bg-gray-300 flex-auto"
|
||||||
<div class="text-slate-500 justify-self-end text-sm">Now</div>
|
></div>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<div class="text-slate-500 justify-self-start text-sm">
|
||||||
|
{{ if eq $.TimeRange "90days" }}
|
||||||
|
90 days ago
|
||||||
|
{{ else if eq $.TimeRange "48hours" }}
|
||||||
|
48 hours ago
|
||||||
|
{{ else if eq $.TimeRange "90minutes" }}
|
||||||
|
90 minutes ago
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<div class="text-slate-500 justify-self-end text-sm">Now</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
</caption>
|
</caption>
|
||||||
<thead class="text-xs text-gray-700 uppercase bg-gray-50">
|
<thead class="text-xs text-gray-700 uppercase bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th scope="col">Group</th>
|
||||||
<th scope="col">Name</th>
|
<th scope="col">Name</th>
|
||||||
<th scope="col">Worker Groups</th>
|
<th scope="col">Worker Groups</th>
|
||||||
<th scope="col">Status</th>
|
<th scope="col">Status</th>
|
||||||
|
@ -57,51 +58,71 @@
|
||||||
<th scope="col">Action</th>
|
<th scope="col">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
{{ range .Monitors }}
|
<tbody>
|
||||||
<tbody>
|
{{ range .MonitorGroups }}
|
||||||
<tr>
|
{{ $currentGroup := . }}
|
||||||
|
<tr class="row-special">
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
{{ .Name }}
|
{{ . }}
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td></td>
|
||||||
{{ range .WorkerGroups }}
|
<td></td>
|
||||||
<span
|
<td></td>
|
||||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800"
|
<td></td>
|
||||||
>
|
<td></td>
|
||||||
{{ . }}
|
|
||||||
</span>
|
|
||||||
{{ end }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ if eq .Status "ACTIVE" }}
|
|
||||||
<span
|
|
||||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
|
|
||||||
>
|
|
||||||
ACTIVE
|
|
||||||
</span>
|
|
||||||
{{ else if eq .Status "PAUSED" }}
|
|
||||||
<span
|
|
||||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800"
|
|
||||||
>
|
|
||||||
PAUSED
|
|
||||||
</span>
|
|
||||||
{{ else }}
|
|
||||||
<span
|
|
||||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
|
|
||||||
>
|
|
||||||
UNKNOWN
|
|
||||||
</span>
|
|
||||||
{{ end }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ .Schedule }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="/settings/monitors/{{ .Id }}" class="link">Details</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
{{ range $group, $monitors := $.Monitors }}
|
||||||
{{ end }}
|
{{ if eq $group $currentGroup }}
|
||||||
|
{{ range $monitors }}
|
||||||
|
<tr>
|
||||||
|
<th scope="row"></th>
|
||||||
|
<th scope="row">
|
||||||
|
{{ .Name }}
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{ range .WorkerGroups }}
|
||||||
|
<span
|
||||||
|
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800"
|
||||||
|
>
|
||||||
|
{{ . }}
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ if eq .Status "ACTIVE" }}
|
||||||
|
<span
|
||||||
|
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
|
||||||
|
>
|
||||||
|
ACTIVE
|
||||||
|
</span>
|
||||||
|
{{ else if eq .Status "PAUSED" }}
|
||||||
|
<span
|
||||||
|
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800"
|
||||||
|
>
|
||||||
|
PAUSED
|
||||||
|
</span>
|
||||||
|
{{ else }}
|
||||||
|
<span
|
||||||
|
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
|
||||||
|
>
|
||||||
|
UNKNOWN
|
||||||
|
</span>
|
||||||
|
{{ end }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ .Schedule }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/settings/monitors/{{ .Id }}" class="link"
|
||||||
|
>Details</a
|
||||||
|
>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -2,8 +2,20 @@
|
||||||
<section class="p-5">
|
<section class="p-5">
|
||||||
<form action="/settings/monitors/create" method="post">
|
<form action="/settings/monitors/create" method="post">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<input type="name" name="name" id="name" placeholder="Github.com" />
|
<input type="text" name="name" id="name" placeholder="Github.com" />
|
||||||
<p>Name of the monitor can be anything.</p>
|
<p>Name of the monitor can be anything.</p>
|
||||||
|
<label for="group">Group</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="group"
|
||||||
|
id="group"
|
||||||
|
placeholder="default"
|
||||||
|
value="default"
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
Group monitors together. This affects how they are presented on the
|
||||||
|
homepage.
|
||||||
|
</p>
|
||||||
<label for="workergroups">Worker Groups</label>
|
<label for="workergroups">Worker Groups</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|
|
@ -2,6 +2,12 @@
|
||||||
<section class="p-5">
|
<section class="p-5">
|
||||||
<form action="/settings/monitors/{{ .Monitor.Id }}" method="post">
|
<form action="/settings/monitors/{{ .Monitor.Id }}" method="post">
|
||||||
<h2>Configuration</h2>
|
<h2>Configuration</h2>
|
||||||
|
<label for="group">Group</label>
|
||||||
|
<input type="text" name="group" id="group" value="{{ .Monitor.Group }}" />
|
||||||
|
<p>
|
||||||
|
Group monitors together. This affects how they are presented on the
|
||||||
|
homepage.
|
||||||
|
</p>
|
||||||
<label for="workergroups">Worker Groups</label>
|
<label for="workergroups">Worker Groups</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|
|
@ -56,8 +56,8 @@
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
{{ range .WorkerGroups }}
|
<tbody>
|
||||||
<tbody>
|
{{ range .WorkerGroups }}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
{{ .Name }}
|
{{ .Name }}
|
||||||
|
@ -86,8 +86,8 @@
|
||||||
>
|
>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
{{ end }}
|
||||||
{{ end }}
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
Loading…
Reference in a new issue