338 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			338 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
{% extends "administration/base.html" %}
 | 
						|
 | 
						|
{% load i18n %}
 | 
						|
{% load static %}
 | 
						|
 | 
						|
{% block content %}
 | 
						|
<section class="pf-c-page__main-section pf-m-light">
 | 
						|
    <div class="pf-c-content">
 | 
						|
        <h1>{% trans 'System Overview' %}</h1>
 | 
						|
    </div>
 | 
						|
</section>
 | 
						|
<section class="pf-c-page__main-section">
 | 
						|
    <div class="pf-l-gallery pf-m-gutter">
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-4-col" style="grid-column-end: span 3;grid-row-end: span 2;">
 | 
						|
            <div class="pf-c-card__header">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-server"></i> {% trans 'Logins over the last 24 hours' %}
 | 
						|
                </div>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-card__body" style="position: relative; height:100%; width:100%">
 | 
						|
                <canvas id="logins-last-metrics"></canvas>
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-4-col" style="grid-column-end: span 2;grid-row-end: span 3;">
 | 
						|
            <div class="pf-c-card__header">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-server"></i> {% trans 'Apps with most usage' %}
 | 
						|
                </div>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-card__body">
 | 
						|
                <table class="pf-c-table pf-m-compact" role="grid">
 | 
						|
                    <thead>
 | 
						|
                        <tr role="row">
 | 
						|
                            <th role="columnheader" scope="col">{% trans 'Application' %}</th>
 | 
						|
                            <th role="columnheader" scope="col">{% trans 'Logins' %}</th>
 | 
						|
                            <th role="columnheader" scope="col"></th>
 | 
						|
                        </tr>
 | 
						|
                    </thead>
 | 
						|
                    <tbody role="rowgroup">
 | 
						|
                        {% for app in most_used_applications %}
 | 
						|
                        <tr role="row">
 | 
						|
                            <td role="cell">
 | 
						|
                                {{ app.application.name }}
 | 
						|
                            </td>
 | 
						|
                            <td role="cell">
 | 
						|
                                {{ app.total_logins }}
 | 
						|
                            </td>
 | 
						|
                            <td role="cell">
 | 
						|
                                <progress value="{{ app.total_logins }}" max="{{ most_used_applications.0.total_logins }}"></progress>
 | 
						|
                            </td>
 | 
						|
                        </tr>
 | 
						|
                        {% endfor %}
 | 
						|
                    </tbody>
 | 
						|
                </table>
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact">
 | 
						|
            <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-plugged"></i> {% trans 'Providers' %}
 | 
						|
                </div>
 | 
						|
                <a href="{% url 'passbook_admin:providers' %}">
 | 
						|
                    <i class="fa fa-external-link-alt"> </i>
 | 
						|
                </a>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-card__body">
 | 
						|
                {% if providers_without_application.exists %}
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <i class="fa fa-exclamation-triangle"></i> {{ provider_count }}
 | 
						|
                </p>
 | 
						|
                <p>{% trans 'Warning: At least one Provider has no application assigned.' %}</p>
 | 
						|
                {% else %}
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <i class="fa fa-check-circle"></i> {{ provider_count }}
 | 
						|
                </p>
 | 
						|
                {% endif %}
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact">
 | 
						|
            <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-infrastructure"></i> {% trans 'Policies' %}
 | 
						|
                </div>
 | 
						|
                <a href="{% url 'passbook_admin:policies' %}">
 | 
						|
                    <i class="fa fa-external-link-alt"> </i>
 | 
						|
                </a>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-card__body">
 | 
						|
                {% if policies_without_binding %}
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <i class="fa fa-exclamation-triangle"></i> {{ policy_count }}
 | 
						|
                </p>
 | 
						|
                <p>{% trans 'Policies without binding exist.' %}</p>
 | 
						|
                {% else %}
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <i class="fa fa-check-circle"></i> {{ policy_count }}
 | 
						|
                </p>
 | 
						|
                {% endif %}
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact">
 | 
						|
            <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-user"></i> {% trans 'Users' %}
 | 
						|
                </div>
 | 
						|
                <a href="{% url 'passbook_admin:users' %}">
 | 
						|
                    <i class="fa fa-external-link-alt"> </i>
 | 
						|
                </a>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-card__body">
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <i class="fa fa-check-circle"></i> {{ user_count }}
 | 
						|
                </p>
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact">
 | 
						|
            <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-bundle"></i> {% trans 'Version' %}
 | 
						|
                </div>
 | 
						|
                <a href="https://github.com/BeryJu/passbook/releases" target="_blank">
 | 
						|
                    <i class="fa fa-external-link-alt"> </i>
 | 
						|
                </a>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-card__body">
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    {% if version >= version_latest %}
 | 
						|
                    <i class="fa fa-check-circle"></i> {{ version }}
 | 
						|
                    {% else %}
 | 
						|
                    <i class="fa fa-exclamation-triangle"></i> {{ version }}
 | 
						|
                    {% endif %}
 | 
						|
                </p>
 | 
						|
                {% if version >= version_latest %}
 | 
						|
                    {% blocktrans %}
 | 
						|
                    Up-to-date!
 | 
						|
                    {% endblocktrans %}
 | 
						|
                {% else %}
 | 
						|
                    {% blocktrans with latest=version_latest %}
 | 
						|
                    {{ latest }} is available!
 | 
						|
                    {% endblocktrans %}
 | 
						|
                {% endif %}
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact">
 | 
						|
            <div class="pf-c-card__header">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-server"></i> {% trans 'Workers' %}
 | 
						|
                </div>
 | 
						|
            </div>
 | 
						|
            <fetch-fill-slot class="pf-c-card__body" url="{% url 'passbook_api:admin_overview-list' %}" key="worker_count">
 | 
						|
                <div slot="value < 1">
 | 
						|
                    <p class="pb-aggregate-card">
 | 
						|
                        <i class="fa fa-exclamation-triangle"></i> <span data-value></span>
 | 
						|
                    </p>
 | 
						|
                    <p>{% trans 'No workers connected.' %}</p>
 | 
						|
                </div>
 | 
						|
                <div slot="value >= 1">
 | 
						|
                    <p class="pb-aggregate-card">
 | 
						|
                        <i class="fa fa-check-circle"></i> <span data-value></span>
 | 
						|
                    </p>
 | 
						|
                </div>
 | 
						|
                <div>
 | 
						|
                    <span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading...">
 | 
						|
                        <span class="pf-c-spinner__clipper"></span>
 | 
						|
                        <span class="pf-c-spinner__lead-ball"></span>
 | 
						|
                        <span class="pf-c-spinner__tail-ball"></span>
 | 
						|
                    </span>
 | 
						|
                </div>
 | 
						|
            </fetch-fill-slot>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact">
 | 
						|
            <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-server"></i> {% trans 'Cached Policies' %}
 | 
						|
                </div>
 | 
						|
                <a data-target="modal" data-modal="clearPolicyCache">
 | 
						|
                    <i class="fa fa-trash"> </i>
 | 
						|
                </a>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-card__body">
 | 
						|
                {% if cached_policies < 1 %}
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <i class="fa fa-exclamation-triangle"></i> {{ cached_policies }}
 | 
						|
                </p>
 | 
						|
                <p>{% trans 'No policies cached. Users may experience slow response times.' %}</p>
 | 
						|
                {% else %}
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <i class="fa fa-check-circle"></i> {{ cached_policies }}
 | 
						|
                </p>
 | 
						|
                {% endif %}
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div class="pf-c-card pf-c-card-aggregate pf-l-gallery__item pf-m-compact">
 | 
						|
            <div class="pf-c-card__header pf-l-flex pf-m-justify-content-space-between">
 | 
						|
                <div class="pf-c-card__header-main">
 | 
						|
                    <i class="pf-icon pf-icon-server"></i> {% trans 'Cached Flows' %}
 | 
						|
                </div>
 | 
						|
                <a data-target="modal" data-modal="clearFlowCache">
 | 
						|
                    <i class="fa fa-trash"> </i>
 | 
						|
                </a>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-card__body">
 | 
						|
                {% if cached_flows < 1 %}
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <span class="fa fa-exclamation-triangle"></span> {{ cached_flows }}
 | 
						|
                </p>
 | 
						|
                <p>{% trans 'No flows cached.' %}</p>
 | 
						|
                {% else %}
 | 
						|
                <p class="pb-aggregate-card">
 | 
						|
                    <i class="fa fa-check-circle"></i> {{ cached_flows }}
 | 
						|
                </p>
 | 
						|
                {% endif %}
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
    </div>
 | 
						|
</section>
 | 
						|
 | 
						|
<div class="pf-c-backdrop" id="clearPolicyCache" hidden>
 | 
						|
    <div class="pf-l-bullseye">
 | 
						|
        <div class="pf-c-modal-box pf-m-sm" role="dialog">
 | 
						|
            <button data-modal-close class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
 | 
						|
                <i class="fas fa-times" aria-hidden="true"></i>
 | 
						|
            </button>
 | 
						|
            <div class="pf-c-modal-box__header">
 | 
						|
                <h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Clear Policy Cache' %}?</h1>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-modal-box__body" id="modal-description">
 | 
						|
                <form method="post" id="clear_policies">
 | 
						|
                    {% csrf_token %}
 | 
						|
                    <input type="hidden" name="clear_policies">
 | 
						|
                    <p>
 | 
						|
                        {% blocktrans %}
 | 
						|
                        Are you sure you want to clear the policy cache? This will cause all policies to be re-evaluated on their next usage.
 | 
						|
                        {% endblocktrans %}
 | 
						|
                    </p>
 | 
						|
                </form>
 | 
						|
            </div>
 | 
						|
            <footer class="pf-c-modal-box__footer pf-m-align-left">
 | 
						|
                <button form="clear_policies" class="pf-c-button pf-m-primary" type="submit">{% trans 'Clear' %}</button>
 | 
						|
                <button data-modal-close class="pf-c-button pf-m-link" type="button">{% trans 'Cancel' %}</button>
 | 
						|
            </footer>
 | 
						|
        </div>
 | 
						|
    </div>
 | 
						|
</div>
 | 
						|
 | 
						|
<div class="pf-c-backdrop" id="clearFlowCache" hidden>
 | 
						|
    <div class="pf-l-bullseye">
 | 
						|
        <div class="pf-c-modal-box pf-m-sm" role="dialog">
 | 
						|
            <button data-modal-close class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
 | 
						|
                <i class="fas fa-times" aria-hidden="true"></i>
 | 
						|
            </button>
 | 
						|
            <div class="pf-c-modal-box__header">
 | 
						|
                <h1 class="pf-c-title pf-m-2xl" id="modal-title">{% trans 'Clear Flow Cache' %}?</h1>
 | 
						|
            </div>
 | 
						|
            <div class="pf-c-modal-box__body" id="modal-description">
 | 
						|
                <form method="post" id="clear_flows">
 | 
						|
                    {% csrf_token %}
 | 
						|
                    <input type="hidden" name="clear_flows">
 | 
						|
                    <p>
 | 
						|
                        {% blocktrans %}
 | 
						|
                        Are you sure you want to clear the flow cache? This will cause all flows to be re-evaluated on their next usage.
 | 
						|
                        {% endblocktrans %}
 | 
						|
                    </p>
 | 
						|
                </form>
 | 
						|
            </div>
 | 
						|
            <footer class="pf-c-modal-box__footer pf-m-align-left">
 | 
						|
                <button form="clear_flows" class="pf-c-button pf-m-primary" type="submit">{% trans 'Clear' %}</button>
 | 
						|
                <button data-modal-close class="pf-c-button pf-m-link" type="button">{% trans 'Cancel' %}</button>
 | 
						|
            </footer>
 | 
						|
        </div>
 | 
						|
    </div>
 | 
						|
</div>
 | 
						|
 | 
						|
<script src="{% static 'node_modules/chart.js/dist/Chart.bundle.min.js' %}"></script>
 | 
						|
<script>
 | 
						|
var ctx = document.getElementById('logins-last-metrics').getContext('2d');
 | 
						|
fetch("{% url 'passbook_api:admin_metrics-list' %}").then(r => r.json()).then(r => {
 | 
						|
    var myChart = new Chart(ctx, {
 | 
						|
        type: 'bar',
 | 
						|
        data: {
 | 
						|
            datasets: [
 | 
						|
                {
 | 
						|
                    label: 'Failed Logins',
 | 
						|
                    backgroundColor: "rgba(201, 25, 11, .5)",
 | 
						|
                    spanGaps: true,
 | 
						|
                    data: r.logins_failed_per_1h,
 | 
						|
                },
 | 
						|
                {
 | 
						|
                    label: 'Successful Logins',
 | 
						|
                    backgroundColor: "rgba(189, 229, 184, .5)",
 | 
						|
                    spanGaps: true,
 | 
						|
                    data: r.logins_per_1h,
 | 
						|
                },
 | 
						|
            ]
 | 
						|
        },
 | 
						|
        options: {
 | 
						|
            maintainAspectRatio: false,
 | 
						|
            spanGaps: true,
 | 
						|
            scales: {
 | 
						|
                xAxes: [{
 | 
						|
                    stacked: true,
 | 
						|
                    gridLines: {
 | 
						|
                        color: "rgba(0, 0, 0, 0)",
 | 
						|
                    },
 | 
						|
                    type: 'time',
 | 
						|
                    offset: true,
 | 
						|
                    ticks: {
 | 
						|
                        callback: function (value, index, values) {
 | 
						|
                            const date = new Date();
 | 
						|
                            const delta = (date - values[index].value);
 | 
						|
                            const ago = Math.round(delta / 1000 / 3600);
 | 
						|
                            return `${ago} Hours ago`;
 | 
						|
                        },
 | 
						|
                        autoSkip: true,
 | 
						|
                        maxTicksLimit: 8
 | 
						|
                    }
 | 
						|
                }],
 | 
						|
                yAxes: [{
 | 
						|
                    stacked: true,
 | 
						|
                    gridLines: {
 | 
						|
                        color: "rgba(0, 0, 0, 0)",
 | 
						|
                    }
 | 
						|
                }]
 | 
						|
            }
 | 
						|
        }
 | 
						|
    });
 | 
						|
});
 | 
						|
</script>
 | 
						|
 | 
						|
{% endblock %}
 |