Snippets Collections
@FlowPreview
@ExperimentalTime
@Controller
internal class StatusController @Autowired constructor(private val supervisor: ObserveeSupervisor) {
    @GetMapping("/status", produces = [MediaType.TEXT_HTML_VALUE])
    suspend fun index(model: Model): String {
        val observees = ObserveeInfo.from(supervisor.observeeHealthFlows)
        model.addAttribute("observees", observees)
        return "status"
    }

    /**
     * Stream of change to health status of any Observee
     */
    @GetMapping("/status.stream", produces = [MediaType.TEXT_EVENT_STREAM_VALUE, CustomMediaType.TURBO_STREAM_VALUE])
    suspend fun stream(model: Model): String {
        val observees = ObserveeInfo.from(supervisor.observeeHealthFlows.asFlow())
        model.addAttribute("observees", dataDrivenEach(observees))
        return "observee-status.turbo-stream"
    }

    private fun dataDrivenEach(stream: Flow<Any>) = ReactiveDataDriverContextVariable(stream, 1)
}
event: message
id: 0
data: <turbo-stream action="replace" target="observee184">
data:   <template>
data:     <li class="my-1 py-3 d-flex list-group-item list-group-item-success" id="observee184">
data:       <div class="container">
data:         <div class="row">
data:           <div class="col px-0">
data:             <a class="fw-bold text-dark" href="file:src/sample/test.file">Test File</a>
data:           </div>
data:           <div class="col-auto px-0 shadow-sm">
data:             <span class="badge green">Instances
data:               <span class="badge bg-info ms-1 text-dark text-etched">1</span>
data:             </span>
data:           </div>
data:         </div>
data:         <div class="row">
data:           <div class="col px-0">
data:             <span class="fw-bold">Healthy</span>
data:             <span class="fw-lighter x-small fst-italic">at</span>
data:             <time class="fw-lighter x-small font-monospace"
data:                   data-bounce="2021-10-06T00:51:11.603948Z"
data:                   datetime="2021-10-06T00:47:11.186060Z">00:47:11</time>
data:           </div>
data:         </div>
data:       </div>
data:     </li>
data:   </template>
data: </turbo-stream>

event: message
id: 1
data: <turbo-stream action="replace" target="observee193">
data:   <template>
data:     <li class="my-1 py-3 d-flex list-group-item list-group-item-success" id="observee193">
data:       <div class="container">
...
// #ProgressiveEnhancement
(window['EventSource'] && window['Turbo']) ?
  Turbo.connectStreamSource(new EventSource('/status.stream')) :
  console.warn('Turbo Streams over SSE not available');
const zeroPad = n => `${n < 10 ? '0' : ''}${n}`;

function updateClock() {
  const now = new Date();
  const hh = zeroPad(now.getUTCHours());
  const mm = zeroPad(now.getUTCMinutes());
  const ss = zeroPad(now.getUTCSeconds());
  let clock = document.getElementById('clock');
  clock.innerHTML = `${hh}:${mm}:${ss}&nbsp;UTC`;
  clock.setAttribute('datetime', now.toISOString());
}

// #ProgressiveEnhancement
document.getElementById('status_frame_load').click();

updateClock();
setInterval(updateClock, 1000);
<div class="container" data-th-fragment="observee-status-li">
    <div class="row">
        <div class="col px-0">
            <a class="fw-bold text-dark" data-th-href="*{location}" data-th-text="*{label}">
                An Observee
            </a>
        </div>
        <div class="col-auto px-0 shadow-sm">
            <span data-th-class="|badge *{color}|">Instances
                <span class="badge bg-info ms-1 text-shadow" data-th-text="*{count}">99</span>
            </span>
        </div>
    </div>
    <div class="row">
        <div class="col px-0">
            <span class="fw-bold" data-th-text="*{status}">Status</span>
            <span class="fw-lighter x-small fst-italic">at</span>
            <time class="fw-lighter x-small font-monospace"
                  data-th-data-bounce="*{timestampBounce}" data-th-datetime="*{timestamp}"
                  data-th-text="*{hhmmss}">HH:MM:SS
            </time>
        </div>
    </div>
</div>
<turbo-stream action="replace" data-th-each="observee : *{observees}" data-th-target="|observee${observee.id}|">
    <template>
        <li data-th-class="|my-1 py-3 d-flex list-group-item list-group-item-*{alert}|"
            data-th-id="|observee*{id}|"
            data-th-object="${observee}">
            <div data-th-replace="~{fragments/observee-status-li :: observee-status-li}"></div>
        </li>
    </template>
</turbo-stream>
<!DOCTYPE html>
<html lang="${lang}"
      th:lang="${lang}"
      th:with="lang=${#locale.language}"
      xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <link th:replace="~{fragments/html-head}"/>
    <title>status.gallery Status Page (unframed)</title>
    <!-- if Turbo is available, index.html won't have included this head, so the meta refresh won't happen (which is good!) -->
    <!-- if JavaScript is disabled, Turbo won't be available, so this meta refresh will take the place of SSE -->
    <meta content="3" http-equiv="refresh" name="refresh"/>
    <script src="/scripts/status.js" async></script>
</head>
<body>
<div class="bg-light bg-gradient p-3 rounded shadow-lg">
    <h1 class="display-1 text-center" style="text-shadow: 0 1px 0 gray">status.gallery (unframed)</h1>
</div>
<turbo-frame id="status_frame">
    <div class="box">
        <ul class="container list-group">
            <li th:class="|my-1 py-3 d-flex list-group-item list-group-item-*{alert}|"
                th:each="observee : *{observees}"
                th:id="|observee*{id}|"
                th:object="${observee}">
                <div th:replace="~{fragments/observee-status-li :: observee-status-li}"></div>
            </li>
        </ul>
    </div>
</turbo-frame>
</body>
<link th:replace="~{fragments/footer}"/>
</html>
<!--
  ~ Copyright © 2021. Joshua A. Graham https://status.gallery/. See LICENSE.txt for usage rights.
  -->

<!DOCTYPE html>
<html lang="${lang}"
      th:lang="${lang}"
      th:with="lang=${#locale.language}"
      xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <link th:replace="~{fragments/html-head}"/>
    <script src="/scripts/index.js" async defer></script>
    <script src="/scripts/status.js" async></script>
    <title>status.gallery</title>
</head>
<body>
<header class="bg-light bg-gradient p-3 rounded shadow-lg">
    <div class="display-4 text-center text-shadow">status.gallery</div>
    <div class="mx-auto small font-monospace text-center shadow-sm p-1" style="width: 8em">
        <time id="clock" datetime=""></time>
    </div>
</header>
<turbo-frame id="status_frame" autoscroll data-autoscroll-block="start">
    <a href="/status" id="status_frame_load">
        <!-- #ProgressiveEnhancement -->
        <script>document.currentScript.parentElement.hidden = true;</script>
        Status
    </a>
    </div>
</turbo-frame>
<link th:replace="~{fragments/footer}"/>
</body>
</html>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="#449944" media="(prefers-color-scheme: light)" name="theme-color">
<meta content="#003300" media="(prefers-color-scheme: dark)" name="theme-color">

<link href="/stylesheets/bootstrap.min.css" rel="stylesheet"/>
<script src="/scripts/bootstrap.min.js" async defer></script>

<script src="/scripts/turbo.js"></script>

<link href="/stylesheets/main.css" rel="stylesheet"/>
star

Tue Nov 09 2021 05:00:39 GMT+0000 (Coordinated Universal Time)

#lowjs #hotwire #thymeleaf #html
star

Wed Oct 06 2021 00:53:09 GMT+0000 (Coordinated Universal Time)

#lowjs #hotwire #thymeleaf #html
star

Sat Oct 02 2021 06:41:41 GMT+0000 (Coordinated Universal Time) https://bitbucket.org/delitescere/status.gallery/src/main/src/main/resources/static/scripts/status.js

#lowjs #hotwire #thymeleaf #html
star

Sat Oct 02 2021 06:16:19 GMT+0000 (Coordinated Universal Time) https://bitbucket.org/delitescere/status.gallery/src/main/src/main/resources/static/scripts/index.js

#lowjs #hotwire #thymeleaf #html
star

Mon Sep 27 2021 03:07:13 GMT+0000 (Coordinated Universal Time) https://bitbucket.org/delitescere/status.gallery/src/main/src/main/resources/templates/fragments/observee-status-li.html

#lowjs #hotwire #thymeleaf #html
star

Mon Sep 27 2021 01:57:48 GMT+0000 (Coordinated Universal Time) https://bitbucket.org/delitescere/status.gallery/src/main/src/main/resources/templates/observee-status.turbo-stream.html

#lowjs #hotwire #thymeleaf #html
star

Sun Sep 26 2021 11:24:45 GMT+0000 (Coordinated Universal Time) https://bitbucket.org/delitescere/status.gallery/src/main/src/main/resources/templates/status.html

#lowjs #hotwire #thymeleaf #html
star

Sun Sep 26 2021 06:15:37 GMT+0000 (Coordinated Universal Time) https://bitbucket.org/delitescere/status.gallery/src/main/src/main/resources/templates/index.html

#lowjs #hotwire #thymeleaf #html
star

Sun Sep 26 2021 06:12:54 GMT+0000 (Coordinated Universal Time) https://bitbucket.org/delitescere/status.gallery/src/main/src/main/resources/templates/fragments/html-head.html

#lowjs #hotwire #thymeleaf #html

Save snippets that work with our extensions

Available in the Chrome Web Store Get Firefox Add-on Get VS Code extension