) + */ +article { + margin: var(--block-spacing-vertical) 0; + padding: var(--block-spacing-vertical) var(--block-spacing-horizontal); + border-radius: var(--border-radius); + background: var(--card-background-color); + box-shadow: var(--card-box-shadow); +} +article > header, +article > footer { + margin-right: calc(var(--block-spacing-horizontal) * -1); + margin-left: calc(var(--block-spacing-horizontal) * -1); + padding: calc(var(--block-spacing-vertical) * 0.66) var(--block-spacing-horizontal); + background-color: var(--card-sectionning-background-color); +} +article > header { + margin-top: calc(var(--block-spacing-vertical) * -1); + margin-bottom: var(--block-spacing-vertical); + border-bottom: var(--border-width) solid var(--card-border-color); + border-top-right-radius: var(--border-radius); + border-top-left-radius: var(--border-radius); +} +article > footer { + margin-top: var(--block-spacing-vertical); + margin-bottom: calc(var(--block-spacing-vertical) * -1); + border-top: var(--border-width) solid var(--card-border-color); + border-bottom-right-radius: var(--border-radius); + border-bottom-left-radius: var(--border-radius); +} + +/** + * Modal () + */ +:root { + --scrollbar-width: 0px; +} + +dialog { + display: flex; + z-index: 999; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + align-items: center; + justify-content: center; + width: inherit; + min-width: 100%; + height: inherit; + min-height: 100%; + padding: var(--spacing); + border: 0; + -webkit-backdrop-filter: var(--modal-overlay-backdrop-filter); + backdrop-filter: var(--modal-overlay-backdrop-filter); + background-color: var(--modal-overlay-background-color); + color: var(--color); +} +dialog article { + max-height: calc(100vh - var(--spacing) * 2); + overflow: auto; +} +@media (min-width: 576px) { + dialog article { + max-width: 510px; + } +} +@media (min-width: 768px) { + dialog article { + max-width: 700px; + } +} +dialog article > header, +dialog article > footer { + padding: calc(var(--block-spacing-vertical) * 0.5) var(--block-spacing-horizontal); +} +dialog article > header .close { + margin: 0; + margin-left: var(--spacing); + float: right; +} +dialog article > footer { + text-align: right; +} +dialog article > footer [role=button] { + margin-bottom: 0; +} +dialog article > footer [role=button]:not(:first-of-type) { + margin-left: calc(var(--spacing) * 0.5); +} +dialog article p:last-of-type { + margin: 0; +} +dialog article .close { + display: block; + width: 1rem; + height: 1rem; + margin-top: calc(var(--block-spacing-vertical) * -0.5); + margin-bottom: var(--typography-spacing-vertical); + margin-left: auto; + background-image: var(--icon-close); + background-position: center; + background-size: auto 1rem; + background-repeat: no-repeat; + opacity: 0.5; + transition: opacity var(--transition); +} +dialog article .close:is([aria-current], :hover, :active, :focus) { + opacity: 1; +} +dialog:not([open]), dialog[open=false] { + display: none; +} + +.modal-is-open { + padding-right: var(--scrollbar-width, 0px); + overflow: hidden; + pointer-events: none; + touch-action: none; +} +.modal-is-open dialog { + pointer-events: auto; +} + +:where(.modal-is-opening, .modal-is-closing) dialog, +:where(.modal-is-opening, .modal-is-closing) dialog > article { + animation-duration: 0.2s; + animation-timing-function: ease-in-out; + animation-fill-mode: both; +} +:where(.modal-is-opening, .modal-is-closing) dialog { + animation-duration: 0.8s; + animation-name: modal-overlay; +} +:where(.modal-is-opening, .modal-is-closing) dialog > article { + animation-delay: 0.2s; + animation-name: modal; +} + +.modal-is-closing dialog, +.modal-is-closing dialog > article { + animation-delay: 0s; + animation-direction: reverse; +} + +@keyframes modal-overlay { + from { + -webkit-backdrop-filter: none; + backdrop-filter: none; + background-color: transparent; + } +} +@keyframes modal { + from { + transform: translateY(-100%); + opacity: 0; + } +} +/** + * Nav + */ +:where(nav li)::before { + float: left; + content: ""; +} + +nav, +nav ul { + display: flex; +} + +nav { + justify-content: space-between; +} +nav ol, +nav ul { + align-items: center; + margin-bottom: 0; + padding: 0; + list-style: none; +} +nav ol:first-of-type, +nav ul:first-of-type { + margin-left: calc(var(--nav-element-spacing-horizontal) * -1); +} +nav ol:last-of-type, +nav ul:last-of-type { + margin-right: calc(var(--nav-element-spacing-horizontal) * -1); +} +nav li { + display: inline-block; + margin: 0; + padding: var(--nav-element-spacing-vertical) var(--nav-element-spacing-horizontal); +} +nav li > * { + --spacing: 0; +} +nav :where(a, [role=link]) { + display: inline-block; + margin: calc(var(--nav-link-spacing-vertical) * -1) calc(var(--nav-link-spacing-horizontal) * -1); + padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal); + border-radius: var(--border-radius); + text-decoration: none; +} +nav :where(a, [role=link]):is([aria-current], :hover, :active, :focus) { + text-decoration: none; +} +nav[aria-label=breadcrumb] { + align-items: center; + justify-content: start; +} +nav[aria-label=breadcrumb] ul li:not(:first-child) { + -webkit-margin-start: var(--nav-link-spacing-horizontal); + margin-inline-start: var(--nav-link-spacing-horizontal); +} +nav[aria-label=breadcrumb] ul li:not(:last-child) ::after { + position: absolute; + width: calc(var(--nav-link-spacing-horizontal) * 2); + -webkit-margin-start: calc(var(--nav-link-spacing-horizontal) / 2); + margin-inline-start: calc(var(--nav-link-spacing-horizontal) / 2); + content: "/"; + color: var(--muted-color); + text-align: center; +} +nav[aria-label=breadcrumb] a[aria-current] { + background-color: transparent; + color: inherit; + text-decoration: none; + pointer-events: none; +} +nav [role=button] { + margin-right: inherit; + margin-left: inherit; + padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal); +} + +aside nav, +aside ol, +aside ul, +aside li { + display: block; +} +aside li { + padding: calc(var(--nav-element-spacing-vertical) * 0.5) var(--nav-element-spacing-horizontal); +} +aside li a { + display: block; +} +aside li [role=button] { + margin: inherit; +} + +[dir=rtl] nav[aria-label=breadcrumb] ul li:not(:last-child) ::after { + content: "\\"; +} + +/** + * Progress + */ +progress { + display: inline-block; + vertical-align: baseline; +} + +progress { + -webkit-appearance: none; + -moz-appearance: none; + display: inline-block; + appearance: none; + width: 100%; + height: 0.5rem; + margin-bottom: calc(var(--spacing) * 0.5); + overflow: hidden; + border: 0; + border-radius: var(--border-radius); + background-color: var(--progress-background-color); + color: var(--progress-color); +} +progress::-webkit-progress-bar { + border-radius: var(--border-radius); + background: none; +} +progress[value]::-webkit-progress-value { + background-color: var(--progress-color); +} +progress::-moz-progress-bar { + background-color: var(--progress-color); +} +@media (prefers-reduced-motion: no-preference) { + progress:indeterminate { + background: var(--progress-background-color) linear-gradient(to right, var(--progress-color) 30%, var(--progress-background-color) 30%) top left/150% 150% no-repeat; + animation: progress-indeterminate 1s linear infinite; + } + progress:indeterminate[value]::-webkit-progress-value { + background-color: transparent; + } + progress:indeterminate::-moz-progress-bar { + background-color: transparent; + } +} + +@media (prefers-reduced-motion: no-preference) { + [dir=rtl] progress:indeterminate { + animation-direction: reverse; + } +} + +@keyframes progress-indeterminate { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} +/** + * Dropdown ([role="list"]) + */ +details[role=list], +li[role=list] { + position: relative; +} + +details[role=list] summary + ul, +li[role=list] > ul { + display: flex; + z-index: 99; + position: absolute; + top: auto; + right: 0; + left: 0; + flex-direction: column; + margin: 0; + padding: 0; + border: var(--border-width) solid var(--dropdown-border-color); + border-radius: var(--border-radius); + border-top-right-radius: 0; + border-top-left-radius: 0; + background-color: var(--dropdown-background-color); + box-shadow: var(--card-box-shadow); + color: var(--dropdown-color); + white-space: nowrap; +} +details[role=list] summary + ul li, +li[role=list] > ul li { + width: 100%; + margin-bottom: 0; + padding: calc(var(--form-element-spacing-vertical) * 0.5) var(--form-element-spacing-horizontal); + list-style: none; +} +details[role=list] summary + ul li:first-of-type, +li[role=list] > ul li:first-of-type { + margin-top: calc(var(--form-element-spacing-vertical) * 0.5); +} +details[role=list] summary + ul li:last-of-type, +li[role=list] > ul li:last-of-type { + margin-bottom: calc(var(--form-element-spacing-vertical) * 0.5); +} +details[role=list] summary + ul li a, +li[role=list] > ul li a { + display: block; + margin: calc(var(--form-element-spacing-vertical) * -0.5) calc(var(--form-element-spacing-horizontal) * -1); + padding: calc(var(--form-element-spacing-vertical) * 0.5) var(--form-element-spacing-horizontal); + overflow: hidden; + color: var(--dropdown-color); + text-decoration: none; + text-overflow: ellipsis; +} +details[role=list] summary + ul li a:hover, +li[role=list] > ul li a:hover { + background-color: var(--dropdown-hover-background-color); +} + +details[role=list] summary::after, +li[role=list] > a::after { + display: block; + width: 1rem; + height: calc(1rem * var(--line-height, 1.5)); + -webkit-margin-start: 0.5rem; + margin-inline-start: 0.5rem; + float: right; + transform: rotate(0deg); + background-position: right center; + background-size: 1rem auto; + background-repeat: no-repeat; + content: ""; +} + +details[role=list] { + padding: 0; + border-bottom: none; +} +details[role=list] summary { + margin-bottom: 0; +} +details[role=list] summary:not([role]) { + height: calc(1rem * var(--line-height) + var(--form-element-spacing-vertical) * 2 + var(--border-width) * 2); + padding: var(--form-element-spacing-vertical) var(--form-element-spacing-horizontal); + border: var(--border-width) solid var(--form-element-border-color); + border-radius: var(--border-radius); + background-color: var(--form-element-background-color); + color: var(--form-element-placeholder-color); + line-height: inherit; + cursor: pointer; + transition: background-color var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition); +} +details[role=list] summary:not([role]):active, details[role=list] summary:not([role]):focus { + border-color: var(--form-element-active-border-color); + background-color: var(--form-element-active-background-color); +} +details[role=list] summary:not([role]):focus { + box-shadow: 0 0 0 var(--outline-width) var(--form-element-focus-color); +} +details[role=list][open] summary { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +details[role=list][open] summary::before { + display: block; + z-index: 1; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: none; + content: ""; + cursor: default; +} + +nav details[role=list] summary, +nav li[role=list] a { + display: flex; + direction: ltr; +} + +nav details[role=list] summary + ul, +nav li[role=list] > ul { + min-width: -moz-fit-content; + min-width: fit-content; + border-radius: var(--border-radius); +} +nav details[role=list] summary + ul li a, +nav li[role=list] > ul li a { + border-radius: 0; +} + +nav details[role=list] summary, +nav details[role=list] summary:not([role]) { + height: auto; + padding: var(--nav-link-spacing-vertical) var(--nav-link-spacing-horizontal); +} +nav details[role=list][open] summary { + border-radius: var(--border-radius); +} +nav details[role=list] summary + ul { + margin-top: var(--outline-width); + -webkit-margin-start: 0; + margin-inline-start: 0; +} +nav details[role=list] summary[role=link] { + margin-bottom: calc(var(--nav-link-spacing-vertical) * -1); + line-height: var(--line-height); +} +nav details[role=list] summary[role=link] + ul { + margin-top: calc(var(--nav-link-spacing-vertical) + var(--outline-width)); + -webkit-margin-start: calc(var(--nav-link-spacing-horizontal) * -1); + margin-inline-start: calc(var(--nav-link-spacing-horizontal) * -1); +} + +li[role=list]:hover > ul, +li[role=list] a:active ~ ul, +li[role=list] a:focus ~ ul { + display: flex; +} +li[role=list] > ul { + display: none; + margin-top: calc(var(--nav-link-spacing-vertical) + var(--outline-width)); + -webkit-margin-start: calc(var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal)); + margin-inline-start: calc(var(--nav-element-spacing-horizontal) - var(--nav-link-spacing-horizontal)); +} +li[role=list] > a::after { + background-image: var(--icon-chevron); +} + +label > details[role=list] { + margin-top: calc(var(--spacing) * 0.25); + margin-bottom: var(--spacing); +} + +/** + * Loading ([aria-busy=true]) + */ +[aria-busy=true] { + cursor: progress; +} + +[aria-busy=true]:not(input, select, textarea, html)::before { + display: inline-block; + width: 1em; + height: 1em; + border: 0.1875em solid currentColor; + border-radius: 1em; + border-right-color: transparent; + content: ""; + vertical-align: text-bottom; + vertical-align: -0.125em; + animation: spinner 0.75s linear infinite; + opacity: var(--loading-spinner-opacity); +} +[aria-busy=true]:not(input, select, textarea, html):not(:empty)::before { + margin-right: calc(var(--spacing) * 0.5); + margin-left: 0; + -webkit-margin-start: 0; + margin-inline-start: 0; + -webkit-margin-end: calc(var(--spacing) * 0.5); + margin-inline-end: calc(var(--spacing) * 0.5); +} +[aria-busy=true]:not(input, select, textarea, html):empty { + text-align: center; +} + +button[aria-busy=true], +input[type=submit][aria-busy=true], +input[type=button][aria-busy=true], +input[type=reset][aria-busy=true], +a[aria-busy=true] { + pointer-events: none; +} + +@keyframes spinner { + to { + transform: rotate(360deg); + } +} +/** + * Tooltip ([data-tooltip]) + */ +[data-tooltip] { + position: relative; +} +[data-tooltip]:not(a, button, input) { + border-bottom: 1px dotted; + text-decoration: none; + cursor: help; +} +[data-tooltip][data-placement=top]::before, [data-tooltip][data-placement=top]::after, [data-tooltip]::before, [data-tooltip]::after { + display: block; + z-index: 99; + position: absolute; + bottom: 100%; + left: 50%; + padding: 0.25rem 0.5rem; + overflow: hidden; + transform: translate(-50%, -0.25rem); + border-radius: var(--border-radius); + background: var(--tooltip-background-color); + content: attr(data-tooltip); + color: var(--tooltip-color); + font-style: normal; + font-weight: var(--font-weight); + font-size: 0.875rem; + text-decoration: none; + text-overflow: ellipsis; + white-space: nowrap; + opacity: 0; + pointer-events: none; +} +[data-tooltip][data-placement=top]::after, [data-tooltip]::after { + padding: 0; + transform: translate(-50%, 0rem); + border-top: 0.3rem solid; + border-right: 0.3rem solid transparent; + border-left: 0.3rem solid transparent; + border-radius: 0; + background-color: transparent; + content: ""; + color: var(--tooltip-background-color); +} +[data-tooltip][data-placement=bottom]::before, [data-tooltip][data-placement=bottom]::after { + top: 100%; + bottom: auto; + transform: translate(-50%, 0.25rem); +} +[data-tooltip][data-placement=bottom]:after { + transform: translate(-50%, -0.3rem); + border: 0.3rem solid transparent; + border-bottom: 0.3rem solid; +} +[data-tooltip][data-placement=left]::before, [data-tooltip][data-placement=left]::after { + top: 50%; + right: 100%; + bottom: auto; + left: auto; + transform: translate(-0.25rem, -50%); +} +[data-tooltip][data-placement=left]:after { + transform: translate(0.3rem, -50%); + border: 0.3rem solid transparent; + border-left: 0.3rem solid; +} +[data-tooltip][data-placement=right]::before, [data-tooltip][data-placement=right]::after { + top: 50%; + right: auto; + bottom: auto; + left: 100%; + transform: translate(0.25rem, -50%); +} +[data-tooltip][data-placement=right]:after { + transform: translate(-0.3rem, -50%); + border: 0.3rem solid transparent; + border-right: 0.3rem solid; +} +[data-tooltip]:focus::before, [data-tooltip]:focus::after, [data-tooltip]:hover::before, [data-tooltip]:hover::after { + opacity: 1; +} +@media (hover: hover) and (pointer: fine) { + [data-tooltip][data-placement=bottom]:focus::before, [data-tooltip][data-placement=bottom]:focus::after, [data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::before, [data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after, [data-tooltip]:hover::before, [data-tooltip]:hover::after { + animation-duration: 0.2s; + animation-name: tooltip-slide-top; + } + [data-tooltip][data-placement=bottom]:focus::after, [data-tooltip][data-placement=bottom]:hover [data-tooltip]:focus::after, [data-tooltip]:hover::after { + animation-name: tooltip-caret-slide-top; + } + [data-tooltip][data-placement=bottom]:focus::before, [data-tooltip][data-placement=bottom]:focus::after, [data-tooltip][data-placement=bottom]:hover::before, [data-tooltip][data-placement=bottom]:hover::after { + animation-duration: 0.2s; + animation-name: tooltip-slide-bottom; + } + [data-tooltip][data-placement=bottom]:focus::after, [data-tooltip][data-placement=bottom]:hover::after { + animation-name: tooltip-caret-slide-bottom; + } + [data-tooltip][data-placement=left]:focus::before, [data-tooltip][data-placement=left]:focus::after, [data-tooltip][data-placement=left]:hover::before, [data-tooltip][data-placement=left]:hover::after { + animation-duration: 0.2s; + animation-name: tooltip-slide-left; + } + [data-tooltip][data-placement=left]:focus::after, [data-tooltip][data-placement=left]:hover::after { + animation-name: tooltip-caret-slide-left; + } + [data-tooltip][data-placement=right]:focus::before, [data-tooltip][data-placement=right]:focus::after, [data-tooltip][data-placement=right]:hover::before, [data-tooltip][data-placement=right]:hover::after { + animation-duration: 0.2s; + animation-name: tooltip-slide-right; + } + [data-tooltip][data-placement=right]:focus::after, [data-tooltip][data-placement=right]:hover::after { + animation-name: tooltip-caret-slide-right; + } +} +@keyframes tooltip-slide-top { + from { + transform: translate(-50%, 0.75rem); + opacity: 0; + } + to { + transform: translate(-50%, -0.25rem); + opacity: 1; + } +} +@keyframes tooltip-caret-slide-top { + from { + opacity: 0; + } + 50% { + transform: translate(-50%, -0.25rem); + opacity: 0; + } + to { + transform: translate(-50%, 0rem); + opacity: 1; + } +} +@keyframes tooltip-slide-bottom { + from { + transform: translate(-50%, -0.75rem); + opacity: 0; + } + to { + transform: translate(-50%, 0.25rem); + opacity: 1; + } +} +@keyframes tooltip-caret-slide-bottom { + from { + opacity: 0; + } + 50% { + transform: translate(-50%, -0.5rem); + opacity: 0; + } + to { + transform: translate(-50%, -0.3rem); + opacity: 1; + } +} +@keyframes tooltip-slide-left { + from { + transform: translate(0.75rem, -50%); + opacity: 0; + } + to { + transform: translate(-0.25rem, -50%); + opacity: 1; + } +} +@keyframes tooltip-caret-slide-left { + from { + opacity: 0; + } + 50% { + transform: translate(0.05rem, -50%); + opacity: 0; + } + to { + transform: translate(0.3rem, -50%); + opacity: 1; + } +} +@keyframes tooltip-slide-right { + from { + transform: translate(-0.75rem, -50%); + opacity: 0; + } + to { + transform: translate(0.25rem, -50%); + opacity: 1; + } +} +@keyframes tooltip-caret-slide-right { + from { + opacity: 0; + } + 50% { + transform: translate(-0.05rem, -50%); + opacity: 0; + } + to { + transform: translate(-0.3rem, -50%); + opacity: 1; + } +} + +/** + * Accessibility & User interaction + */ +[aria-controls] { + cursor: pointer; +} + +[aria-disabled=true], +[disabled] { + cursor: not-allowed; +} + +[aria-hidden=false][hidden] { + display: initial; +} + +[aria-hidden=false][hidden]:not(:focus) { + clip: rect(0, 0, 0, 0); + position: absolute; +} + +a, +area, +button, +input, +label, +select, +summary, +textarea, +[tabindex] { + -ms-touch-action: manipulation; +} + +[dir=rtl] { + direction: rtl; +} + +/** +* Reduce Motion Features +*/ +@media (prefers-reduced-motion: reduce) { + *:not([aria-busy=true]), + :not([aria-busy=true])::before, + :not([aria-busy=true])::after { + background-attachment: initial !important; + animation-duration: 1ms !important; + animation-delay: -1ms !important; + animation-iteration-count: 1 !important; + scroll-behavior: auto !important; + transition-delay: 0s !important; + transition-duration: 0s !important; + } +} + +/*# sourceMappingURL=pico.css.map */ \ No newline at end of file diff --git a/argos/server/static/styles.css b/argos/server/static/styles.css new file mode 100644 index 0000000..9857fe8 --- /dev/null +++ b/argos/server/static/styles.css @@ -0,0 +1 @@ +@import url("pico.css"); \ No newline at end of file diff --git a/argos/server/templates/base.html b/argos/server/templates/base.html new file mode 100644 index 0000000..eb9e6ae --- /dev/null +++ b/argos/server/templates/base.html @@ -0,0 +1,20 @@ + + + + + Argos + + + + + + Argos monitoring + + + + {% block content %} + {% endblock %} + + + + \ No newline at end of file diff --git a/argos/server/templates/index.html b/argos/server/templates/index.html new file mode 100644 index 0000000..0d343cb --- /dev/null +++ b/argos/server/templates/index.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} +{% block content %} + + + + + + Domain + Current status + + + + {% for domain, status in domains.items() %} + + + + {{ domain }} + + + {% if status == "ok" %}✅{% elif statuts == "warning"%}⚠{% elif status == "critical"%}❌{% endif %} + + {% endfor %} + + + + +{% endblock %} \ No newline at end of file diff --git a/config.yaml b/config.yaml index d4a9a28..43b9184 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ general: - frequency: "1h" # Run checks every 4 hours. + frequency: "1m" # Run checks every minute. alerts: error: - local @@ -8,7 +8,6 @@ general: alert: - local service: - port: 8888 secrets: # Secrets can be generated using `openssl rand -base64 32`. - "O4kt8Max9/k0EmHaEJ0CGGYbBNFmK8kOZNIoUk3Kjwc" diff --git a/tests/test_api.py b/tests/test_api.py index d90ca67..d7323cf 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -14,7 +14,7 @@ def test_db(): def test_read_tasks_requires_auth(): with TestClient(app) as client: - response = client.get("/tasks") + response = client.get("/api/tasks") assert response.status_code == 403 @@ -22,7 +22,7 @@ def test_tasks_retrieval_and_results(test_db): with TestClient(app) as client: token = app.state.config.service.secrets[0] client.headers = {"Authorization": f"Bearer {token}"} - response = client.get("/tasks") + response = client.get("/api/tasks") assert response.status_code == 200 tasks = response.json() @@ -35,7 +35,11 @@ def test_tasks_retrieval_and_results(test_db): ) data = [r.model_dump() for r in results] - response = client.post("/results", json=data) + response = client.post("/api/results", json=data) assert response.status_code == 201 assert test_db.query(models.Result).count() == 2 + + # The list of tasks should be empty now + response = client.get("/api/tasks") + assert len(response.json()) == 0