| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- {% extends 'generic/_base.html' %}
- {% load buttons %}
- {% load helpers %}
- {% load i18n %}
- {% load render_table from django_tables2 %}
- {% load humanize %}
- {% block title %}{% trans "System" %}{% endblock %}
- {% block controls %}
- <a href="?export=true" class="btn btn-purple">
- <i class="mdi mdi-download"></i> {% trans "Export All" %}
- </a>
- {% endblock controls %}
- {% block tabs %}
- <ul class="nav nav-tabs" role="tablist">
- <li class="nav-item" role="presentation">
- <a class="nav-link active" id="status-tab" data-bs-toggle="tab" data-bs-target="#status-panel" type="button" role="tab" aria-selected="true">
- {% trans "Status" %}
- </a>
- </li>
- <li class="nav-item" role="presentation">
- <a class="nav-link" id="config-tab" data-bs-toggle="tab" data-bs-target="#config-panel" type="button" role="tab">
- {% trans "Config" %}
- </a>
- </li>
- <li class="nav-item" role="presentation">
- <a class="nav-link" id="plugins-tab" data-bs-toggle="tab" data-bs-target="#plugins-panel" type="button" role="tab">
- {% trans "Plugins" %}
- </a>
- </li>
- <li class="nav-item" role="presentation">
- <a class="nav-link" id="objects-tab" data-bs-toggle="tab" data-bs-target="#objects-panel" type="button" role="tab">
- {% trans "Object Counts" %}
- </a>
- </li>
- <li class="nav-item" role="presentation">
- <a class="nav-link" id="database-tab" data-bs-toggle="tab" data-bs-target="#database-panel" type="button" role="tab">
- {% trans "Database" %}
- </a>
- </li>
- </ul>
- {% endblock tabs %}
- {% block content %}
- {# Status panel #}
- <div class="tab-pane show active" id="status-panel" role="tabpanel" aria-labelledby="status-tab">
- <div class="row mb-3">
- <div class="col">
- <div class="card">
- <h2 class="card-header">{% trans "System Status" %}</h2>
- <table class="table table-hover attr-table">
- <tr>
- <th scope="row">{% trans "System hostname" %}</th>
- <td>{{ settings.HOSTNAME }}</td>
- </tr>
- <tr>
- <th scope="row">{% trans "NetBox release" %}</th>
- <td>
- {{ stats.netbox_release.name }}
- {% if stats.netbox_release.published %}
- ({{ stats.netbox_release.published|isodate }})
- {% endif %}
- </td>
- </tr>
- <tr>
- <th scope="row">{% trans "Python version" %}</th>
- <td>{{ stats.python_version }}</td>
- </tr>
- <tr>
- <th scope="row">{% trans "Django version" %}</th>
- <td>{{ stats.django_version }}</td>
- </tr>
- <tr>
- <th scope="row">{% trans "PostgreSQL version" %}</th>
- <td>{{ stats.postgresql_version }}</td>
- </tr>
- <tr>
- <th scope="row">{% trans "Database name" %}</th>
- <td>{{ stats.database_name }}</td>
- </tr>
- <tr>
- <th scope="row">{% trans "Database size" %}</th>
- <td>
- {% if stats.database_size %}
- {{ stats.database_size }}
- {% else %}
- <span class="text-muted">{% trans "Unavailable" %}</span>
- {% endif %}
- </td>
- </tr>
- <tr>
- <th scope="row">{% trans "RQ workers" %}</th>
- <td>
- <a href="{% url 'core:background_queue_list' %}">{{ stats.rq_worker_count }}</a>
- ({% trans "default queue" %})
- </td>
- </tr>
- <tr>
- <th scope="row">{% trans "System time" %}</th>
- <td>{% now 'Y-m-d H:i:s T' %}</td>
- </tr>
- </table>
- </div>
- <div class="card">
- <h2 class="card-header">{% trans "Django Apps" %}</h2>
- {% if django_apps %}
- <table class="table table-hover attr-table">
- {% for app_name, version in django_apps.items %}
- <tr>
- <td>{{ app_name }}</td>
- <td>{{ version }}</td>
- </tr>
- {% endfor %}
- </table>
- {% else %}
- <div class="card-body text-muted">
- {% trans "None found" %}
- </div>
- {% endif %}
- </div>
- </div>
- </div>
- </div>
- {# Config panel #}
- <div class="tab-pane" id="config-panel" role="tabpanel" aria-labelledby="config-tab">
- <div class="row mb-3">
- <div class="col">
- <div class="card">
- <h2 class="card-header">{% trans "Current Configuration" %}</h2>
- {% include 'core/inc/config_data.html' %}
- </div>
- </div>
- </div>
- </div>
- {# Plugins panel #}
- <div class="tab-pane" id="plugins-panel" role="tabpanel" aria-labelledby="plugins-tab">
- <div class="row mb-3">
- <div class="col">
- <div class="card">
- <h2 class="card-header">{% trans "Installed Plugins" %}</h2>
- {% if plugins %}
- <table class="table table-hover attr-table">
- {% for plugin, version in plugins.items %}
- <tr>
- <td>{{ plugin }}</td>
- <td>{{ version }}</td>
- </tr>
- {% endfor %}
- </table>
- {% else %}
- <div class="card-body text-muted">
- {% trans "No plugins are installed." %}
- </div>
- {% endif %}
- </div>
- </div>
- </div>
- </div>
- {# Objects panel #}
- <div class="tab-pane" id="objects-panel" role="tabpanel" aria-labelledby="objects-tab">
- <div class="row mb-3">
- <div class="col col-md-12">
- <div class="card">
- <h2 class="card-header">{% trans "Object Counts" %}</h2>
- <table class="table table-hover attr-table">
- {% for object_type, count in objects.items %}
- <tr{% if not count %} class="text-muted"{% endif %}>
- <td>{{ object_type }}</td>
- <td>{{ count }}</td>
- </tr>
- {% endfor %}
- </table>
- </div>
- </div>
- </div>
- </div>
- {# Database panel #}
- <div class="tab-pane" id="database-panel" role="tabpanel" aria-labelledby="database-tab">
- {% if db_schema %}
- {# Summary boxes #}
- <div class="row mb-3">
- <div class="col-md-4">
- <div class="card text-center">
- <div class="card-body">
- <div class="display-6 fw-bold">{{ db_schema_stats.total_tables|intcomma }}</div>
- <div class="text-muted">{% trans "Tables" %}</div>
- </div>
- </div>
- </div>
- <div class="col-md-4">
- <div class="card text-center">
- <div class="card-body">
- <div class="display-6 fw-bold">{{ db_schema_stats.total_columns|intcomma }}</div>
- <div class="text-muted">{% trans "Columns" %}</div>
- </div>
- </div>
- </div>
- <div class="col-md-4">
- <div class="card text-center">
- <div class="card-body">
- <div class="display-6 fw-bold">{{ db_schema_stats.total_indexes|intcomma }}</div>
- <div class="text-muted">{% trans "Indexes" %}</div>
- </div>
- </div>
- </div>
- </div>
- {# Tables grouped by app prefix #}
- {% for group in db_schema_groups %}
- <div class="card mb-3">
- <h2 class="card-header">
- <button class="accordion-button collapsed p-0 w-100" type="button"
- data-bs-toggle="collapse" data-bs-target="#db-group-body-{{ group.name }}"
- aria-expanded="false" aria-controls="db-group-body-{{ group.name }}">
- {{ group.name }}
- {% if group.is_plugin %}<span class="badge text-bg-purple ms-1">{% trans "plugin" %}</span>{% endif %}
- <span class="badge bg-secondary text-bg-gray ms-1">{{ group.tables|length }} {% trans "tables" %}</span>
- <span class="badge bg-secondary text-bg-gray ms-1">{{ group.index_count }} {% trans "indexes" %}</span>
- <span class="accordion-button-toggle"><i class="mdi mdi-chevron-down"></i></span>
- </button>
- </h2>
- <div id="db-group-body-{{ group.name }}" class="collapse">
- <div class="accordion accordion-flush" id="db-group-{{ group.name }}">
- {% for table in group.tables %}
- <div class="accordion-item">
- <h5 class="accordion-header" id="table-heading-{{ group.name }}-{{ forloop.counter }}">
- <button class="accordion-button border-bottom collapsed font-monospace" type="button"
- data-bs-toggle="collapse" data-bs-target="#table-collapse-{{ group.name }}-{{ forloop.counter }}"
- aria-expanded="false" aria-controls="table-collapse-{{ group.name }}-{{ forloop.counter }}">
- {{ table.name }}
- <span class="badge bg-secondary text-white ms-2">{{ table.columns|length }} {% trans "columns" %}</span>
- {% if table.indexes %}
- <span class="badge bg-secondary text-white ms-1">{{ table.indexes|length }} {% trans "indexes" %}</span>
- {% endif %}
- <span class="accordion-button-toggle"><i class="mdi mdi-chevron-down"></i></span>
- </button>
- </h5>
- <div id="table-collapse-{{ group.name }}-{{ forloop.counter }}" class="accordion-collapse collapse"
- aria-labelledby="table-heading-{{ group.name }}-{{ forloop.counter }}">
- <div class="accordion-body p-0">
- <div class="px-3 py-2">
- <strong>{% trans "Columns" %}</strong>
- <table class="table table-hover table-sm mb-0 mt-1">
- <thead>
- <tr>
- <th>{% trans "Column" %}</th>
- <th>{% trans "Type" %}</th>
- <th>{% trans "Nullable" %}</th>
- <th>{% trans "Default" %}</th>
- </tr>
- </thead>
- <tbody>
- {% for column in table.columns %}
- <tr>
- <td class="font-monospace">{{ column.name }}</td>
- <td class="font-monospace text-muted">{{ column.type }}</td>
- <td>
- {% if column.nullable %}
- <span class="text-success">{% trans "yes" %}</span>
- {% else %}
- <span class="text-muted">{% trans "no" %}</span>
- {% endif %}
- </td>
- <td class="font-monospace text-muted">{{ column.default|default:"" }}</td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </div>
- {% if table.indexes %}
- <div class="px-3 py-2 border-top">
- <strong>{% trans "Indexes" %}</strong>
- <table class="table table-hover table-sm mb-0 mt-1">
- <thead>
- <tr>
- <th>{% trans "Name" %}</th>
- <th>{% trans "Definition" %}</th>
- </tr>
- </thead>
- <tbody>
- {% for index in table.indexes %}
- <tr>
- <td class="font-monospace">{{ index.name }}</td>
- <td class="font-monospace text-muted">{{ index.definition }}</td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </div>
- {% endif %}
- </div>
- </div>
- </div>
- {% endfor %}
- </div>
- </div>
- </div>
- {% endfor %}
- {% else %}
- <div class="card mb-3">
- <div class="card-body text-muted">
- {% trans "Schema information unavailable." %}
- </div>
- </div>
- {% endif %}
- </div>
- {% endblock content %}
|