<html lang="en">
<head>
    <title>Expose Dashboard :: {{ subdomains|join(", ") }}</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tailwindcss/ui@latest/dist/tailwind-ui.min.css">
    <script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
    <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.1.0/build/styles/github.min.css">
    <script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.1.0/build/highlight.min.js" async></script>
    <script>
        !function (a, b) {
            "function" == typeof define && define.amd ? define([], b) : "undefined" != typeof module && module.exports ? module.exports = b() : a.ReconnectingWebSocket = b()
        }(this, function () {
            function a(b, c, d) {
                function l(a, b) {
                    var c = document.createEvent("CustomEvent");
                    return c.initCustomEvent(a, !1, !1, b), c
                }

                var e = {
                    debug: !1,
                    automaticOpen: !0,
                    reconnectInterval: 1e3,
                    maxReconnectInterval: 3e4,
                    reconnectDecay: 1.5,
                    timeoutInterval: 2e3
                };
                d || (d = {});
                for (var f in e) this[f] = "undefined" != typeof d[f] ? d[f] : e[f];
                this.url = b, this.reconnectAttempts = 0, this.readyState = WebSocket.CONNECTING, this.protocol = null;
                var h, g = this, i = !1, j = !1, k = document.createElement("div");
                k.addEventListener("open", function (a) {
                    g.onopen(a)
                }), k.addEventListener("close", function (a) {
                    g.onclose(a)
                }), k.addEventListener("connecting", function (a) {
                    g.onconnecting(a)
                }), k.addEventListener("message", function (a) {
                    g.onmessage(a)
                }), k.addEventListener("error", function (a) {
                    g.onerror(a)
                }), this.addEventListener = k.addEventListener.bind(k), this.removeEventListener = k.removeEventListener.bind(k), this.dispatchEvent = k.dispatchEvent.bind(k), this.open = function (b) {
                    h = new WebSocket(g.url, c || []), b || k.dispatchEvent(l("connecting")), (g.debug || a.debugAll) && console.debug("ReconnectingWebSocket", "attempt-connect", g.url);
                    var d = h, e = setTimeout(function () {
                        (g.debug || a.debugAll) && console.debug("ReconnectingWebSocket", "connection-timeout", g.url), j = !0, d.close(), j = !1
                    }, g.timeoutInterval);
                    h.onopen = function () {
                        clearTimeout(e), (g.debug || a.debugAll) && console.debug("ReconnectingWebSocket", "onopen", g.url), g.protocol = h.protocol, g.readyState = WebSocket.OPEN, g.reconnectAttempts = 0;
                        var d = l("open");
                        d.isReconnect = b, b = !1, k.dispatchEvent(d)
                    }, h.onclose = function (c) {
                        if (clearTimeout(e), h = null, i) g.readyState = WebSocket.CLOSED, k.dispatchEvent(l("close")); else {
                            g.readyState = WebSocket.CONNECTING;
                            var d = l("connecting");
                            d.code = c.code, d.reason = c.reason, d.wasClean = c.wasClean, k.dispatchEvent(d), b || j || ((g.debug || a.debugAll) && console.debug("ReconnectingWebSocket", "onclose", g.url), k.dispatchEvent(l("close")));
                            var e = g.reconnectInterval * Math.pow(g.reconnectDecay, g.reconnectAttempts);
                            setTimeout(function () {
                                g.reconnectAttempts++, g.open(!0)
                            }, e > g.maxReconnectInterval ? g.maxReconnectInterval : e)
                        }
                    }, h.onmessage = function (b) {
                        (g.debug || a.debugAll) && console.debug("ReconnectingWebSocket", "onmessage", g.url, b.data);
                        var c = l("message");
                        c.data = b.data, k.dispatchEvent(c)
                    }, h.onerror = function (b) {
                        (g.debug || a.debugAll) && console.debug("ReconnectingWebSocket", "onerror", g.url, b), k.dispatchEvent(l("error"))
                    }
                }, 1 == this.automaticOpen && this.open(!1), this.send = function (b) {
                    if (h) return (g.debug || a.debugAll) && console.debug("ReconnectingWebSocket", "send", g.url, b), h.send(b);
                    throw"INVALID_STATE_ERR : Pausing to reconnect websocket"
                }, this.close = function (a, b) {
                    "undefined" == typeof a && (a = 1e3), i = !0, h && h.close(a, b)
                }, this.refresh = function () {
                    h && h.close()
                }
            }

            return a.prototype.onopen = function () {
            }, a.prototype.onclose = function () {
            }, a.prototype.onconnecting = function () {
            }, a.prototype.onmessage = function () {
            }, a.prototype.onerror = function () {
            }, a.debugAll = !1, a.CONNECTING = WebSocket.CONNECTING, a.OPEN = WebSocket.OPEN, a.CLOSING = WebSocket.CLOSING, a.CLOSED = WebSocket.CLOSED, a
        });
    </script>
    <style>
        .even\:bg-gray-50:nth-child(even) {
            background-color: #f7fafc;
        }
    </style>
</head>
<body>
<div id="app" class="">
    <div class="relative bg-indigo-600" style="marign-left: -1px">
        <div class="max-w-screen-xl mx-auto py-3 px-3 sm:px-6 lg:px-8">
            <div class="pr-16 sm:text-center sm:px-16">
                <p class="font-medium text-white flex justify-center">
                    <span class="inline-block">Waiting for requests on:
                        {% for subdomain in subdomains %}
                            <a class="underline" target="_blank" href="{{ subdomain }}">{{ subdomain }}</a>
                        {% endfor %}
                    </span>
                </p>
            </div>
        </div>
    </div>
    <div class="p-5 flex flex-col md:flex-row">
        <div class="w-full md:w-1/3 flex flex-col mr-5">
            <div class="-my-2 py-2 overflow-x-auto sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8">
                <div class="flex mb-4">
                        <span class="h-8 inline-flex rounded-md shadow-sm">
                              <button @click.prevent="clearLogs"
                                      type="button"
                                      class="inline-flex items-center px-2.5 py-1.5 border border-gray-300 text-xs leading-4 font-medium rounded text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150">
                                Clear
                              </button>
                        </span>

                        <div class="ml-4 flex-grow relative rounded-md shadow-sm">
                            <input class="h-8 form-input block w-full sm:text-sm sm:leading-5" v-model="search" placeholder="Search" />
                        </div>
                </div>
                <div
                    class="align-middle inline-block min-w-full shadow overflow-hidden sm:rounded-lg border-b border-gray-200">
                    <table class="min-w-full">
                        <thead>
                        <tr>
                            <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
                                URL
                            </th>
                            <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
                                Response
                            </th>
                            <th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
                                Duration
                            </th>
                        </tr>
                        </thead>
                        <tbody class="bg-white">
                        <tr v-for="log in filteredLogs"
                            :class="{'bg-gray-100': currentLog === log}"
                            @click="setLog(log)">
                            <td class="cursor-pointer px-6 py-4 whitespace-normal border-b border-gray-200 text-sm leading-5 font-medium text-gray-900">
                                <p>
                                    @{ log.request.method }
                                    @{ log.request.uri }
                                </p>
                                <span class="text-xs">@{ log.subdomain }</span>
                                <span class="text-xs text-gray-600">@{ log.performed_at }</span>
                            </td>
                            <td class="cursor-pointer px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
                                <div v-if="log.response">
                                    <span
                                        v-if="log.response.status >= 200 && log.response.status < 300"
                                        class="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-green-100 text-green-800">
                                      @{ log.response.status } - @{ log.response.reason }
                                    </span>
                                    <span
                                        v-if="log.response.status >= 300 && log.response.status < 400"
                                        class="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-blue-100 text-blue-800">
                                      @{ log.response.status } - @{ log.response.reason }
                                    </span>
                                    <span
                                        v-if="log.response.status >= 400 && log.response.status < 500"
                                        class="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-yellow-100 text-yellow-800">
                                      @{ log.response.status } - @{ log.response.reason }
                                    </span>
                                    <span
                                        v-if="log.response.status >= 500"
                                        class="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-red-100 text-red-800">
                                      @{ log.response.status } - @{ log.response.reason }
                                    </span>
                                </div>
                                <div v-else>
                                    ...
                                </div>
                            </td>
                            <td class="cursor-pointer px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
                                <div v-if="log.response">
                                    @{ log.duration }ms
                                </div>
                            </td>
                        </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
        <div class="w-full md:w-2/3 mt-5 md:mt-0 md:ml-5">
            <div v-if="currentLog" class="bg-white shadow overflow-hidden sm:rounded-lg">
                <div class="px-4 py-5 border-b border-gray-200 sm:px-6">
                    <h3 class="text-lg leading-6 font-medium text-gray-900 flex">
                        @{ currentLog.request.method } @{ currentLog.request.uri }
                        <div class="flex-grow"></div>
                        <span class="inline-flex rounded-md shadow-sm">
                              <button @click.prevent="replay(currentLog)"
                                      type="button"
                                      class="inline-flex items-center px-2.5 py-1.5 border border-gray-300 text-xs leading-4 font-medium rounded text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150">
                                Replay
                              </button>
                        </span>
                        <span class="inline-flex rounded-md shadow-sm ml-4">
                        <button
                            :data-clipboard-text="currentLog.request.curl"
                            type="button"
                            class="clipboard inline-flex items-center px-2.5 py-1.5 border border-gray-300 text-xs leading-4 font-medium rounded text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150">
                            Copy as curl
                        </button>
                        </span>
                    </h3>
                    <p class="mt-1 max-w-2xl text-sm leading-5 text-gray-500">

                        <span class="text-xs text-gray-600">Received at: @{ currentLog.performed_at }</span>
                        <div v-if="currentLog.response">
                            <span
                                v-if="currentLog.response.status >= 200 && currentLog.response.status < 300"
                                class="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-green-100 text-green-800">
                                          @{ currentLog.response.status } - @{ currentLog.response.reason }
                                        </span>
                            <span
                                v-if="currentLog.response.status >= 400 && currentLog.response.status < 500"
                                class="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-yellow-100 text-yellow-800">
                                          @{ currentLog.response.status } - @{ currentLog.response.reason }
                                        </span>
                            <span
                                v-if="currentLog.response.status >= 500"
                                class="inline-flex items-center px-3 py-0.5 rounded-full text-xs font-medium leading-5 bg-red-100 text-red-800">
                                          @{ currentLog.response.status } - @{ currentLog.response.reason }
                                        </span>
                        </div>
                    </p>
                </div>
                <div>
                    <div class="hidden sm:block">
                        <div class="border-b border-gray-200">
                            <nav class="-mb-px flex">
                                <a href="#"
                                   @click.prevent="setView('request')"
                                   :class="{
                                        'border-indigo-500 text-indigo-600 text-indigo-600 focus:text-indigo-800 focus:border-indigo-700': view === 'request',
                                        'border-border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:text-gray-700 focus:border-gray-300': view === 'response',
                                   }"
                                   class="w-1/2 py-4 px-1 text-center border-b-2 font-medium text-sm leading-5 focus:outline-none">
                                    Request
                                </a>
                                <a href="#"
                                   @click.prevent="setView('response')"
                                   :class="{
                                        'border-indigo-500 text-indigo-600': view === 'response',
                                        'border-border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:text-gray-700 focus:border-gray-300': view === 'request',
                                   }"
                                   class="w-1/2 py-4 px-1 text-center border-b-2 font-medium text-sm leading-5 focus:outline-none">
                                    Response
                                </a>
                            </nav>
                        </div>
                    </div>
                </div>

                <div v-if="view === 'request'">
                    <div class="px-4 py-5 border-b border-gray-200 sm:px-6 flex justify-between" v-if="Object.keys(currentLog.request.query).length > 0">
                        <h3 class="text-lg leading-6 font-medium text-gray-900">
                            Query Parameters
                        </h3>
                        <span class="inline-flex rounded-md shadow-sm ml-4">
                            <button
                                type="button"
                                class="clipboard-query inline-flex items-center px-2.5 py-1.5 border border-gray-300 text-xs leading-4 font-medium rounded text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150">
                                Copy as PHP array
                            </button>
                        </span>
                    </div>
                    <div v-for="(value, name) in currentLog.request.query"
                         :key="'query_' + name"
                         class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                        <dt class="text-sm leading-5 font-medium text-gray-700">
                            @{ name }
                        </dt>
                        <dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2 break-all">
                            @{ value }
                        </dd>
                    </div>

                    <div class="px-4 py-5 border-b border-t border-gray-200 sm:px-6 flex justify-between" v-if="Object.keys(currentLog.request.post).length > 0">
                        <h3 class="text-lg leading-6 font-medium text-gray-900">
                            Post Parameters
                        </h3>
                        <span class="inline-flex rounded-md shadow-sm ml-4">
                            <button
                                type="button"
                                class="clipboard-post inline-flex items-center px-2.5 py-1.5 border border-gray-300 text-xs leading-4 font-medium rounded text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150">
                                Copy as PHP array
                            </button>
                        </span>
                    </div>
                    <div v-for="parameter in currentLog.request.post"
                         :key="'post_' + parameter.name"
                         class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                        <dt class="text-sm leading-5 font-medium text-gray-700">
                            @{ parameter.name }
                        </dt>
                        <dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2 break-all">
                            <span
                                v-if="parameter.is_file">File: @{ parameter.filename } (@{ parameter.mime_type })</span>
                            <span v-else>@{ parameter.value }</span>
                        </dd>
                    </div>

                    <div class="px-4 py-5 border-b border-t border-gray-200 sm:px-6 flex justify-between">
                        <h3 class="text-lg leading-6 font-medium text-gray-900">
                            Headers
                        </h3>
                        <span class="inline-flex rounded-md shadow-sm ml-4">
                            <button
                                type="button"
                                class="clipboard-headers inline-flex items-center px-2.5 py-1.5 border border-gray-300 text-xs leading-4 font-medium rounded text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50 transition ease-in-out duration-150">
                                Copy as PHP array
                            </button>
                        </span>
                    </div>
                    <div v-for="(value, header) in currentLog.request.headers"
                         :key="header"
                         class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                        <dt class="text-sm leading-5 font-medium text-gray-700">
                            @{ header }
                        </dt>
                        <dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
                            @{ value }
                        </dd>
                    </div>

                    <div class="px-4 py-5 border-b border-t border-gray-200 sm:px-6">
                        <h3 class="text-lg leading-6 font-medium text-gray-900">
                            Request Body
                        </h3>
                    </div>
                    <div>
                        <pre class="p-6 prettyprint break-all whitespace-pre-wrap">@{ currentLog.request.body }</pre>
                    </div>
                </div>

                <div v-if="view === 'response'">
                    <div class="px-4 py-5 border-b border-gray-200 sm:px-6">
                        <h3 class="text-lg leading-6 font-medium text-gray-900">
                            Headers
                        </h3>
                    </div>
                    <div v-for="(value, header) in currentLog.response.headers"
                         :key="header"
                         class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                        <dt class="text-sm leading-5 font-medium text-gray-700">
                            @{ header }
                        </dt>
                        <dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2 break-all">
                            @{ value }
                        </dd>
                    </div>
                    <div v-if="currentLog.request.additional_data.length !== 0">
                        <div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                            <dt class="text-sm leading-5 font-medium text-gray-900">
                                Debug
                            </dt>
                        </div>
                        <div v-for="(value, key) in currentLog.request.additional_data"
                             :key="'debug'+key"
                             class="even:bg-gray-50 odd:bg-gray-50 px-4 py-3 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                            <dt class="text-sm leading-5 font-medium text-gray-700">
                                @{ key }
                            </dt>
                            <dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
                                <div v-html="value">
                            </dd>
                        </div>
                    </div>

                    <div class="px-4 py-5 border-b border-t border-gray-200 sm:px-6">
                        <h3 class="text-lg leading-6 font-medium text-gray-900">
                            Response
                        </h3>
                    </div>
                    <div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                        <dt class="text-sm leading-5 font-medium text-gray-900">

                        </dt>
                        <div>
                            <div>
                                <nav class="flex">
                                    <a href="#"
                                       @click.prevent="setActiveTab('raw')"
                                       :class="{'outline-none text-gray-700 bg-gray-100': activeTab === 'raw'}"
                                       class="px-3 py-2 font-medium text-sm leading-5 rounded-md text-gray-500 hover:text-gray-700">
                                        Raw
                                    </a>
                                    <a href="#"
                                       @click.prevent="setActiveTab('preview')"
                                       :class="{'outline-none text-gray-700 bg-gray-100': activeTab === 'preview'}"
                                       class="ml-4 px-3 py-2 font-medium text-sm leading-5 rounded-md text-gray-500 hover:text-gray-700 focus:outline-none focus:text-gray-700 focus:bg-gray-100">
                                        Preview
                                    </a>
                                </nav>
                            </div>
                        </div>
                    </div>
                    <div v-if="activeTab === 'raw'">
                        <pre class="p-6 text-sm whitespace-pre-wrap break-all">@{ currentLog.response.body }</pre>
                    </div>
                    <div v-if="activeTab === 'preview'">
                        <div v-if="responseIsJson()">
                            <pre><span id="jsonResponseBody" class="json"></span></pre>
                        </div>
                        <iframe v-else :srcdoc="currentLog.response.body" style="height: 500px;" class="w-full h-full"></iframe>
                    </div>
                </div>
            </div>
            <div v-else  class="flex-col bg-white shadow overflow-hidden sm:rounded-lg justify-center items-center flex py-4">
                <h1 class="text-lg">Waiting for connections...</h1>
                <img src="https://chart.googleapis.com/chart?chs=500x500&cht=qr&chl={{ subdomains[0] | url_encode }}&choe=UTF-8" />
                <a class="text-sm" href="{{ subdomains[0] }}" target="_blank">{{ subdomains[0] }}</a>
            </div>
        </div>
    </div>
</div>

<script>
    new Vue({
        el: '#app',

        delimiters: ['@{', '}'],

        data: {
            search: '',
            currentLog: null,
            view: 'request',
            activeTab: 'raw',
            logs: [],
            maxLogs: {{ max_logs }},
        },

        computed: {
            filteredLogs: function() {
                if (this.search === '') {
                    return this.logs;
                }
                return this.logs.filter(log => {
                    return log.request.uri.indexOf(this.search) !== -1;
                });
            },
        },

        methods: {
            setActiveTab: function(tab) {
                this.activeTab = tab;
                this.$nextTick(function () {
                  this.formatJsonResponse();
                });
            },
            clearLogs: function() {
                fetch('/api/logs/clear');
                this.logs = []
                this.currentLog = null;
            },
            formatJsonResponse: function () {
                if (this.view === 'response' && this.activeTab === 'preview' && this.responseIsJson()) {
                    const target = document.getElementById('jsonResponseBody');
                    target.innerText = JSON.stringify(JSON.parse(this.currentLog.response.body), null, 2)
                    hljs.highlightBlock(target);
                }
            },
            responseIsJson: function() {
              if (! this.currentLog || ! this.currentLog.response || ! this.currentLog.response.headers) {
                return false;
              }

              return /application\/json/g.test(this.currentLog.response.headers['Content-Type']);
            },
            toPhpArray: function(rows, variableName) {
                let output = `$${variableName} = [\n`;

                for (let key in rows) {
                    let value = rows[key];

                    if (typeof value.value !== 'undefined') {
                        value = value.value;
                    }

                    output += `    '${key}' => '${value}',\n`;
                }

                output += `];`;

                return output;
            },
            setLog: function (log) {
                this.currentLog = log;
                this.formatJsonResponse();

                this.$nextTick(function () {
                    this.formatJsonResponse()
                    new ClipboardJS('.clipboard');

                    new ClipboardJS('.clipboard-query', {
                        text: (trigger) => {
                            return this.toPhpArray(this.currentLog.request.query, 'queryParameters');
                        }
                    });

                    new ClipboardJS('.clipboard-post', {
                        text: (trigger) => {
                            return this.toPhpArray(this.currentLog.request.post, 'postParameters');
                        }
                    });

                    new ClipboardJS('.clipboard-headers', {
                        text: (trigger) => {
                            return this.toPhpArray(this.currentLog.request.headers, 'headers');
                        }
                    });
                });
            },
            setView: function (view) {
                this.view = view;
            },
            replay: function (log) {
                fetch('/api/replay/' + log.id);
            },
            connect: function () {
                let conn = new ReconnectingWebSocket(`ws://${window.location.hostname}:${window.location.port}/socket`);

                conn.onmessage = (e) => {
                  const request = JSON.parse(e.data);
                  const index = this.logs.findIndex(log => log.id === request.id);
                  if (index > -1) {
                    this.$set(this.logs, index, request)
                  } else {
                    this.logs.unshift(request);
                  }

                  this.logs = this.logs.splice(0, this.maxLogs);
                };
            },
            loadLogs: function (log) {
                fetch('/api/logs')
                    .then((response) => {
                        return response.json();
                    })
                    .then((data) => {
                        this.logs = data;
                    });
            },
        },

        mounted: function () {
            this.connect();

            this.loadLogs();
        }
    });
</script>
</body>
</html>
