aa-fatanalysis 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aa_fatanalysis-0.1.0/.gitignore +8 -0
- aa_fatanalysis-0.1.0/LICENSE +21 -0
- aa_fatanalysis-0.1.0/PKG-INFO +82 -0
- aa_fatanalysis-0.1.0/README.md +40 -0
- aa_fatanalysis-0.1.0/fatanalysis/__init__.py +1 -0
- aa_fatanalysis-0.1.0/fatanalysis/apps.py +6 -0
- aa_fatanalysis-0.1.0/fatanalysis/auth_hooks.py +30 -0
- aa_fatanalysis-0.1.0/fatanalysis/forms.py +15 -0
- aa_fatanalysis-0.1.0/fatanalysis/migrations/0001_initial.py +36 -0
- aa_fatanalysis-0.1.0/fatanalysis/migrations/0002_alter_uploadperiod_upload_date.py +19 -0
- aa_fatanalysis-0.1.0/fatanalysis/migrations/__init__.py +1 -0
- aa_fatanalysis-0.1.0/fatanalysis/models.py +27 -0
- aa_fatanalysis-0.1.0/fatanalysis/templates/fatanalysis/base.html +21 -0
- aa_fatanalysis-0.1.0/fatanalysis/templates/fatanalysis/import_csv.html +20 -0
- aa_fatanalysis-0.1.0/fatanalysis/templates/fatanalysis/index.html +94 -0
- aa_fatanalysis-0.1.0/fatanalysis/templates/fatanalysis/overview.html +141 -0
- aa_fatanalysis-0.1.0/fatanalysis/templates/fatanalysis/period_delete.html +24 -0
- aa_fatanalysis-0.1.0/fatanalysis/templates/fatanalysis/period_detail.html +90 -0
- aa_fatanalysis-0.1.0/fatanalysis/templates/fatanalysis/period_list.html +66 -0
- aa_fatanalysis-0.1.0/fatanalysis/templates/fatanalysis/player_detail.html +139 -0
- aa_fatanalysis-0.1.0/fatanalysis/tests/__init__.py +0 -0
- aa_fatanalysis-0.1.0/fatanalysis/tests/test_settings.py +26 -0
- aa_fatanalysis-0.1.0/fatanalysis/urls.py +15 -0
- aa_fatanalysis-0.1.0/fatanalysis/views.py +374 -0
- aa_fatanalysis-0.1.0/pyproject.toml +50 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Maddog Broekman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: aa-fatanalysis
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: FAT Analysis Plugin for Alliance Auth
|
|
5
|
+
Author-email: Maddog Broekman <maddogbroekman@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Maddog Broekman
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Keywords: allianceauth,fatanalysis
|
|
29
|
+
Classifier: Environment :: Web Environment
|
|
30
|
+
Classifier: Framework :: Django
|
|
31
|
+
Classifier: Framework :: Django :: 5.2
|
|
32
|
+
Classifier: Intended Audience :: Developers
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Operating System :: OS Independent
|
|
35
|
+
Classifier: Programming Language :: Python
|
|
36
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
37
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
38
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
39
|
+
Requires-Python: <3.14,>=3.10
|
|
40
|
+
Requires-Dist: allianceauth>=5
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
# FAT Analysis
|
|
44
|
+
|
|
45
|
+
Alliance Auth plugin for analyzing FATs (Fleet Activity Tracking). This plugin allows for the upload of 30-day and 90-day FAT CSV files, parses them dynamically, and provides overviews and interactive charts on both a per-character and per-corporation basis.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
1. **Activate your Alliance Auth virtual environment**
|
|
50
|
+
```bash
|
|
51
|
+
source /home/allianceserver/venv/auth/bin/activate
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
2. **Install the plugin**
|
|
55
|
+
Navigate to the directory containing this plugin and run:
|
|
56
|
+
```bash
|
|
57
|
+
pip install -e .
|
|
58
|
+
```
|
|
59
|
+
*(Or install via git / pip once published to a repository)*
|
|
60
|
+
|
|
61
|
+
3. **Update your Alliance Auth settings**
|
|
62
|
+
Add `'fatanalysis'` to your `INSTALLED_APPS` in `myauth/myauth/settings/local.py`:
|
|
63
|
+
```python
|
|
64
|
+
INSTALLED_APPS += [
|
|
65
|
+
'fatanalysis',
|
|
66
|
+
]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
4. **Run migrations**
|
|
70
|
+
```bash
|
|
71
|
+
python manage.py makemigrations
|
|
72
|
+
python manage.py migrate
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
5. **Restart Alliance Auth services**
|
|
76
|
+
```bash
|
|
77
|
+
sudo systemctl restart supervisor
|
|
78
|
+
```
|
|
79
|
+
*(Or restart gunicorn and celery according to your specific setup)*
|
|
80
|
+
|
|
81
|
+
## Permissions
|
|
82
|
+
Assign the `fatanalysis.basic_access` permission in the admin panel to any user or group that should have access to view and upload FAT analysis data.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# FAT Analysis
|
|
2
|
+
|
|
3
|
+
Alliance Auth plugin for analyzing FATs (Fleet Activity Tracking). This plugin allows for the upload of 30-day and 90-day FAT CSV files, parses them dynamically, and provides overviews and interactive charts on both a per-character and per-corporation basis.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
1. **Activate your Alliance Auth virtual environment**
|
|
8
|
+
```bash
|
|
9
|
+
source /home/allianceserver/venv/auth/bin/activate
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. **Install the plugin**
|
|
13
|
+
Navigate to the directory containing this plugin and run:
|
|
14
|
+
```bash
|
|
15
|
+
pip install -e .
|
|
16
|
+
```
|
|
17
|
+
*(Or install via git / pip once published to a repository)*
|
|
18
|
+
|
|
19
|
+
3. **Update your Alliance Auth settings**
|
|
20
|
+
Add `'fatanalysis'` to your `INSTALLED_APPS` in `myauth/myauth/settings/local.py`:
|
|
21
|
+
```python
|
|
22
|
+
INSTALLED_APPS += [
|
|
23
|
+
'fatanalysis',
|
|
24
|
+
]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
4. **Run migrations**
|
|
28
|
+
```bash
|
|
29
|
+
python manage.py makemigrations
|
|
30
|
+
python manage.py migrate
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
5. **Restart Alliance Auth services**
|
|
34
|
+
```bash
|
|
35
|
+
sudo systemctl restart supervisor
|
|
36
|
+
```
|
|
37
|
+
*(Or restart gunicorn and celery according to your specific setup)*
|
|
38
|
+
|
|
39
|
+
## Permissions
|
|
40
|
+
Assign the `fatanalysis.basic_access` permission in the admin panel to any user or group that should have access to view and upload FAT analysis data.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from allianceauth import hooks
|
|
2
|
+
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
|
3
|
+
from django.utils.translation import gettext_lazy as _
|
|
4
|
+
|
|
5
|
+
from . import urls
|
|
6
|
+
|
|
7
|
+
class FatAnalysisMenuItem(MenuItemHook):
|
|
8
|
+
"""This class ensures only authorized users will see the menu entry"""
|
|
9
|
+
def __init__(self):
|
|
10
|
+
# Setup menu entry for sidebar
|
|
11
|
+
MenuItemHook.__init__(
|
|
12
|
+
self,
|
|
13
|
+
_('FAT Analysis'),
|
|
14
|
+
'fas fa-chart-line fa-fw',
|
|
15
|
+
'fatanalysis:index',
|
|
16
|
+
navactive=['fatanalysis:']
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def render(self, request):
|
|
20
|
+
if request.user.has_perm('fatanalysis.basic_access'):
|
|
21
|
+
return MenuItemHook.render(self, request)
|
|
22
|
+
return ''
|
|
23
|
+
|
|
24
|
+
@hooks.register('menu_item_hook')
|
|
25
|
+
def register_menu():
|
|
26
|
+
return FatAnalysisMenuItem()
|
|
27
|
+
|
|
28
|
+
@hooks.register('url_hook')
|
|
29
|
+
def register_urls():
|
|
30
|
+
return UrlHook(urls, 'fatanalysis', r'^fatanalysis/')
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from django import forms
|
|
2
|
+
|
|
3
|
+
class CsvImportForm(forms.Form):
|
|
4
|
+
PERIOD_CHOICES = (
|
|
5
|
+
(30, '30 Days'),
|
|
6
|
+
(90, '90 Days'),
|
|
7
|
+
)
|
|
8
|
+
csv_file = forms.FileField(label='FAT CSV File')
|
|
9
|
+
period_type = forms.ChoiceField(choices=PERIOD_CHOICES, label='Period Type')
|
|
10
|
+
custom_date = forms.DateTimeField(
|
|
11
|
+
required=False,
|
|
12
|
+
label='Custom Date (Optional)',
|
|
13
|
+
help_text='Leave empty to use current date and time. Use format YYYY-MM-DD HH:MM if your browser does not show a date picker.',
|
|
14
|
+
widget=forms.DateTimeInput(attrs={'type': 'datetime-local'})
|
|
15
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Generated by Django 5.2.16 on 2026-07-31 17:05
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
initial = True
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
('eveonline', '0025_remove_evecharacter_last_updated_and_more'),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.CreateModel(
|
|
17
|
+
name='UploadPeriod',
|
|
18
|
+
fields=[
|
|
19
|
+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
20
|
+
('upload_date', models.DateTimeField(auto_now_add=True)),
|
|
21
|
+
('uploader', models.CharField(max_length=255)),
|
|
22
|
+
('period_type', models.IntegerField(choices=[(30, '30 Days'), (90, '90 Days')])),
|
|
23
|
+
],
|
|
24
|
+
),
|
|
25
|
+
migrations.CreateModel(
|
|
26
|
+
name='FatEntry',
|
|
27
|
+
fields=[
|
|
28
|
+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
29
|
+
('character_name', models.CharField(max_length=255)),
|
|
30
|
+
('total_fats', models.IntegerField(default=0)),
|
|
31
|
+
('fat_details', models.JSONField(blank=True, default=dict)),
|
|
32
|
+
('character', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.evecharacter')),
|
|
33
|
+
('period', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fat_entries', to='fatanalysis.uploadperiod')),
|
|
34
|
+
],
|
|
35
|
+
),
|
|
36
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Generated by Django 5.2.15 on 2026-07-31 17:31
|
|
2
|
+
|
|
3
|
+
import django.utils.timezone
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('fatanalysis', '0001_initial'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterField(
|
|
15
|
+
model_name='uploadperiod',
|
|
16
|
+
name='upload_date',
|
|
17
|
+
field=models.DateTimeField(default=django.utils.timezone.now),
|
|
18
|
+
),
|
|
19
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Migrations module
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
from allianceauth.eveonline.models import EveCharacter
|
|
3
|
+
from django.utils import timezone
|
|
4
|
+
|
|
5
|
+
class UploadPeriod(models.Model):
|
|
6
|
+
PERIOD_CHOICES = (
|
|
7
|
+
(30, '30 Days'),
|
|
8
|
+
(90, '90 Days'),
|
|
9
|
+
)
|
|
10
|
+
upload_date = models.DateTimeField(default=timezone.now)
|
|
11
|
+
uploader = models.CharField(max_length=255)
|
|
12
|
+
period_type = models.IntegerField(choices=PERIOD_CHOICES)
|
|
13
|
+
|
|
14
|
+
def __str__(self):
|
|
15
|
+
return f"{self.get_period_type_display()} Upload ({self.upload_date.strftime('%Y-%m-%d %H:%M')})"
|
|
16
|
+
|
|
17
|
+
class FatEntry(models.Model):
|
|
18
|
+
period = models.ForeignKey(UploadPeriod, on_delete=models.CASCADE, related_name='fat_entries')
|
|
19
|
+
character = models.ForeignKey(EveCharacter, on_delete=models.SET_NULL, null=True, blank=True)
|
|
20
|
+
character_name = models.CharField(max_length=255)
|
|
21
|
+
total_fats = models.IntegerField(default=0)
|
|
22
|
+
|
|
23
|
+
# Stores dynamic fleet types (e.g. Strategic, QRF, Astartes) without hardcoding columns
|
|
24
|
+
fat_details = models.JSONField(default=dict, blank=True)
|
|
25
|
+
|
|
26
|
+
def __str__(self):
|
|
27
|
+
return f"{self.character_name} - {self.total_fats} FATs"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{% extends "allianceauth/base-bs5.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block page_title %}{% trans "FAT Analysis" %}{% endblock page_title %}
|
|
5
|
+
|
|
6
|
+
{% block content %}
|
|
7
|
+
<div class="row">
|
|
8
|
+
<div class="col-md-12">
|
|
9
|
+
<h1 class="page-header text-center">{% trans "FAT Analysis Dashboard" %}</h1>
|
|
10
|
+
{% block fatanalysis_content %}{% endblock %}
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
{% endblock %}
|
|
14
|
+
|
|
15
|
+
{% block extra_css %}
|
|
16
|
+
{% include 'bundles/datatables-css-bs5.html' %}
|
|
17
|
+
{% endblock %}
|
|
18
|
+
|
|
19
|
+
{% block extra_javascript %}
|
|
20
|
+
{% include 'bundles/datatables-js-bs5.html' %}
|
|
21
|
+
{% endblock %}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{% extends "fatanalysis/base.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
{% load django_bootstrap5 %}
|
|
4
|
+
|
|
5
|
+
{% block fatanalysis_content %}
|
|
6
|
+
<div class="panel panel-default">
|
|
7
|
+
<div class="panel-heading">
|
|
8
|
+
<h3 class="panel-title">{% trans "Import FAT CSV" %}</h3>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="panel-body">
|
|
11
|
+
<p>{% trans "Upload your 30 or 90 days FAT CSV file here. The system will automatically parse all columns, including any dynamic fleet types." %}</p>
|
|
12
|
+
<form method="POST" enctype="multipart/form-data">
|
|
13
|
+
{% csrf_token %}
|
|
14
|
+
{% bootstrap_form form %}
|
|
15
|
+
<button type="submit" class="btn btn-primary">{% trans "Upload" %}</button>
|
|
16
|
+
<a href="{% url 'fatanalysis:index' %}" class="btn btn-default">{% trans "Cancel" %}</a>
|
|
17
|
+
</form>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
{% endblock %}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{% extends "fatanalysis/base.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block fatanalysis_content %}
|
|
5
|
+
<div class="row">
|
|
6
|
+
<div class="col-md-12">
|
|
7
|
+
<a href="{% url 'fatanalysis:period_list' %}" class="btn btn-default pull-right" style="margin-left: 10px;">
|
|
8
|
+
<i class="fas fa-list"></i> {% trans "Manage Periods" %}
|
|
9
|
+
</a>
|
|
10
|
+
<a href="{% url 'fatanalysis:import_csv' %}" class="btn btn-primary pull-right">
|
|
11
|
+
<i class="fas fa-upload"></i> {% trans "Import CSV" %}
|
|
12
|
+
</a>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<br>
|
|
16
|
+
|
|
17
|
+
<div class="panel panel-default">
|
|
18
|
+
<div class="panel-heading">
|
|
19
|
+
<h3 class="panel-title">{% trans "FAT Trend Over Time (Alliance Total)" %}</h3>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="panel-body">
|
|
22
|
+
<canvas id="trendChart" height="100"></canvas>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="row">
|
|
27
|
+
<div class="col-md-6">
|
|
28
|
+
<div class="panel panel-default text-center">
|
|
29
|
+
<div class="panel-body">
|
|
30
|
+
<h3>{% trans "30 Days Dashboard" %}</h3>
|
|
31
|
+
<p>{% trans "View the latest 30 days FATs per character." %}</p>
|
|
32
|
+
<a href="{% url 'fatanalysis:overview_30' %}" class="btn btn-primary btn-lg">
|
|
33
|
+
<i class="fas fa-calendar-alt"></i> {% trans "30 Days Overview" %}
|
|
34
|
+
</a>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="col-md-6">
|
|
39
|
+
<div class="panel panel-default text-center">
|
|
40
|
+
<div class="panel-body">
|
|
41
|
+
<h3>{% trans "90 Days Dashboard" %}</h3>
|
|
42
|
+
<p>{% trans "View the latest 90 days FATs per character." %}</p>
|
|
43
|
+
<a href="{% url 'fatanalysis:overview_90' %}" class="btn btn-primary btn-lg">
|
|
44
|
+
<i class="fas fa-calendar-alt"></i> {% trans "90 Days Overview" %}
|
|
45
|
+
</a>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
{% endblock %}
|
|
51
|
+
|
|
52
|
+
{% block extra_javascript %}
|
|
53
|
+
{{ block.super }}
|
|
54
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
55
|
+
<script>
|
|
56
|
+
$(document).ready(function() {
|
|
57
|
+
|
|
58
|
+
// Trend Chart
|
|
59
|
+
const trendCtx = document.getElementById('trendChart').getContext('2d');
|
|
60
|
+
new Chart(trendCtx, {
|
|
61
|
+
type: 'bar',
|
|
62
|
+
data: {
|
|
63
|
+
labels: {{ trend_labels|safe }},
|
|
64
|
+
datasets: [
|
|
65
|
+
{
|
|
66
|
+
label: '{% trans "30 Days FATs" %}',
|
|
67
|
+
data: {{ trend_30|safe }},
|
|
68
|
+
borderColor: '#36A2EB',
|
|
69
|
+
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
|
70
|
+
tension: 0.1,
|
|
71
|
+
fill: true
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
label: '{% trans "90 Days FATs" %}',
|
|
75
|
+
data: {{ trend_90|safe }},
|
|
76
|
+
borderColor: '#FF6384',
|
|
77
|
+
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
|
78
|
+
tension: 0.1,
|
|
79
|
+
fill: true
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
options: {
|
|
84
|
+
responsive: true,
|
|
85
|
+
scales: {
|
|
86
|
+
y: {
|
|
87
|
+
beginAtZero: true
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
{% endblock %}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{% extends "fatanalysis/base.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block fatanalysis_content %}
|
|
5
|
+
<div class="row">
|
|
6
|
+
<div class="col-md-12">
|
|
7
|
+
<a href="{% url 'fatanalysis:index' %}" class="btn btn-default pull-right">
|
|
8
|
+
<i class="fas fa-arrow-left"></i> {% trans "Back to Dashboard" %}
|
|
9
|
+
</a>
|
|
10
|
+
<h2>{{ title }} <small>({{ period.upload_date|date:"Y-m-d"|default:"No uploads yet" }})</small></h2>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
{% if period %}
|
|
14
|
+
<div class="row">
|
|
15
|
+
<div class="col-md-12">
|
|
16
|
+
<div class="panel panel-default">
|
|
17
|
+
<div class="panel-heading">
|
|
18
|
+
<h3 class="panel-title">{% trans "Historical FAT Trend" %} ({{ period_type }} {% trans "Days" %})</h3>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="panel-body">
|
|
21
|
+
<canvas id="historicalTrendChart" height="100"></canvas>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div class="row">
|
|
28
|
+
<div class="col-md-4">
|
|
29
|
+
<div class="panel panel-default">
|
|
30
|
+
<div class="panel-heading">
|
|
31
|
+
<h3 class="panel-title">{% trans "Top 10 Players" %}</h3>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="panel-body">
|
|
34
|
+
<canvas id="topPlayersChart"></canvas>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="col-md-8">
|
|
39
|
+
<div class="panel panel-default">
|
|
40
|
+
<div class="panel-heading">
|
|
41
|
+
<h3 class="panel-title">{% trans "All Players" %}</h3>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="panel-body">
|
|
44
|
+
<table class="table table-striped table-hover" id="overview-table">
|
|
45
|
+
<thead>
|
|
46
|
+
<tr>
|
|
47
|
+
<th>{% trans "Character" %}</th>
|
|
48
|
+
<th>{% trans "Total FATs" %}</th>
|
|
49
|
+
{% for header in dynamic_headers %}
|
|
50
|
+
<th>{{ header }}</th>
|
|
51
|
+
{% endfor %}
|
|
52
|
+
</tr>
|
|
53
|
+
</thead>
|
|
54
|
+
<tbody>
|
|
55
|
+
{% for entry in entries %}
|
|
56
|
+
<tr>
|
|
57
|
+
<td>
|
|
58
|
+
<a href="{% url 'fatanalysis:player_detail' character_name=entry.character_name period_type=period_type %}">
|
|
59
|
+
{{ entry.character_name }}
|
|
60
|
+
</a>
|
|
61
|
+
</td>
|
|
62
|
+
<td><strong>{{ entry.total_fats }}</strong></td>
|
|
63
|
+
{% for value in entry.dynamic_values %}
|
|
64
|
+
<td>{{ value }}</td>
|
|
65
|
+
{% endfor %}
|
|
66
|
+
</tr>
|
|
67
|
+
{% empty %}
|
|
68
|
+
<tr>
|
|
69
|
+
<td colspan="{{ dynamic_headers|length|add:2 }}" class="text-center">{% trans "No FAT data available." %}</td>
|
|
70
|
+
</tr>
|
|
71
|
+
{% endfor %}
|
|
72
|
+
</tbody>
|
|
73
|
+
</table>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
{% else %}
|
|
79
|
+
<div class="alert alert-info">
|
|
80
|
+
{% trans "No uploads found for this period type yet." %}
|
|
81
|
+
</div>
|
|
82
|
+
{% endif %}
|
|
83
|
+
{% endblock %}
|
|
84
|
+
|
|
85
|
+
{% block extra_javascript %}
|
|
86
|
+
{{ block.super }}
|
|
87
|
+
{% if period %}
|
|
88
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
89
|
+
<script>
|
|
90
|
+
$(document).ready(function() {
|
|
91
|
+
$('#overview-table').DataTable({
|
|
92
|
+
"order": [[ 1, "desc" ]]
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Pie Chart for Top Players
|
|
96
|
+
const topCtx = document.getElementById('topPlayersChart').getContext('2d');
|
|
97
|
+
new Chart(topCtx, {
|
|
98
|
+
type: 'pie',
|
|
99
|
+
data: {
|
|
100
|
+
labels: {{ top_labels|safe }},
|
|
101
|
+
datasets: [{
|
|
102
|
+
data: {{ top_data|safe }},
|
|
103
|
+
backgroundColor: [
|
|
104
|
+
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF',
|
|
105
|
+
'#FF9F40', '#E7E9ED', '#8AC926', '#1982C4', '#6A4C93'
|
|
106
|
+
]
|
|
107
|
+
}]
|
|
108
|
+
},
|
|
109
|
+
options: {
|
|
110
|
+
responsive: true
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Trend Chart
|
|
115
|
+
const trendCtx = document.getElementById('historicalTrendChart').getContext('2d');
|
|
116
|
+
new Chart(trendCtx, {
|
|
117
|
+
type: 'line',
|
|
118
|
+
data: {
|
|
119
|
+
labels: {{ trend_labels|safe }},
|
|
120
|
+
datasets: [{
|
|
121
|
+
label: '{{ period_type }} {% trans "Days FATs" %}',
|
|
122
|
+
data: {{ trend_data|safe }},
|
|
123
|
+
borderColor: '#36A2EB',
|
|
124
|
+
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
|
125
|
+
tension: 0.1,
|
|
126
|
+
fill: true
|
|
127
|
+
}]
|
|
128
|
+
},
|
|
129
|
+
options: {
|
|
130
|
+
responsive: true,
|
|
131
|
+
scales: {
|
|
132
|
+
y: {
|
|
133
|
+
beginAtZero: true
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
</script>
|
|
140
|
+
{% endif %}
|
|
141
|
+
{% endblock %}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{% extends "fatanalysis/base.html" %}
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
|
|
4
|
+
{% block fatanalysis_content %}
|
|
5
|
+
<div class="row">
|
|
6
|
+
<div class="col-md-6 col-md-offset-3">
|
|
7
|
+
<div class="panel panel-danger">
|
|
8
|
+
<div class="panel-heading">
|
|
9
|
+
<h3 class="panel-title">{% trans "Delete Upload Period" %}</h3>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="panel-body">
|
|
12
|
+
<p>{% trans "Are you sure you want to delete the FAT upload for" %} <strong>{{ period.get_period_type_display }}</strong> {% trans "on" %} <strong>{{ period.upload_date|date:"Y-m-d H:i" }}</strong>?</p>
|
|
13
|
+
<p class="text-danger">{% trans "This will also delete all associated FAT entries and data. This action cannot be undone." %}</p>
|
|
14
|
+
|
|
15
|
+
<form method="POST">
|
|
16
|
+
{% csrf_token %}
|
|
17
|
+
<button type="submit" class="btn btn-danger">{% trans "Yes, Delete" %}</button>
|
|
18
|
+
<a href="{% url 'fatanalysis:period_list' %}" class="btn btn-default">{% trans "Cancel" %}</a>
|
|
19
|
+
</form>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
{% endblock %}
|