Skip to content

Commit

Permalink
Immprove TraderoBotGroup UX
Browse files Browse the repository at this point in the history
- Add ``Move Botzinhos to Group`` action
  • Loading branch information
math-a3k committed Aug 30, 2023
1 parent e92d2c6 commit 00fa2e6
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 2 deletions.
45 changes: 45 additions & 0 deletions base/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django import forms
from django.core.exceptions import ValidationError
from django.db.models import Model
from django.urls import reverse
from django.utils.safestring import mark_safe

from .models import Symbol, TraderoBot, TraderoBotGroup, User
from .strategies import get_strategies
Expand Down Expand Up @@ -166,6 +168,49 @@ def get_bot_form(self):
return TraderoBotForm(for_group=True, for_group_edit=True)


class BotsModelMultipleChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj): # pragma: no cover
if obj.status == obj.Status.SELLING:
status_class = "text-danger"
elif obj.status == obj.Status.BUYING:
status_class = "text-success"
else:
status_class = "text-muted"
return mark_safe(
f"<span class='text-muted'>#{obj.id:03d}</span> "
f"<a href='{ reverse('base:botzinhos-detail', args=[obj.pk]) }' "
f"class='name-value'>{ obj.name }</a>: { obj.symbol.base_asset }"
f"/{ obj.symbol.quote_asset } | <span class='{ status_class }'>"
f"{ obj.get_status_display() }</span>"
)


class TraderoBotGroupMoveForm(forms.ModelForm):
to_group = forms.ModelChoiceField(
label="To Group", queryset=None, empty_label="(Selecionar)"
)
bots = BotsModelMultipleChoiceField(
queryset=None,
widget=forms.CheckboxSelectMultiple,
)

class Meta:
model = TraderoBotGroup
fields = [
"to_group",
"bots",
]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["to_group"].queryset = TraderoBotGroup.objects.filter(
user=self.instance.user
).order_by("name")
self.fields["bots"].queryset = TraderoBot.objects.filter(
group=self.instance
).order_by("name")


class UserForm(forms.ModelForm):
class Meta:
model = User
Expand Down
5 changes: 4 additions & 1 deletion base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1705,7 +1705,10 @@ class Meta:
objects = TraderoBotManager()

def __str__(self):
return f"BOT #{self.id}: {self.symbol.symbol} | {self.get_status_display()}"
return (
f"[{self.id:03d}] {self.name}: {self.symbol.symbol} | "
f"{self.get_status_display()}"
)

def get_absolute_url(self):
return reverse("base:botzinhos-detail", kwargs={"pk": self.pk})
Expand Down
1 change: 1 addition & 0 deletions base/templates/base/botzinhos_group_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ <h4 class="m-2">Group Actions</h4>
<div class="btn-group">
<a class="btn btn-warning" href="{% url "base:botzinhos-group-update" group.pk %}">Atualizar Grupo</a>
<a class="btn btn-primary" href="{% url "base:botzinhos-create" %}?group={{group.pk}}">Novo(s) Botzinho(s)</a>
<a class="btn btn-warning" href="{% url "base:botzinhos-group-move" group.pk %}">Mover Botzinhos</a>
</div>
<div class="btn-group">
{% url "base:botzinhos-group-action" group.pk "off" as action_url %}
Expand Down
50 changes: 50 additions & 0 deletions base/templates/base/botzinhos_group_move_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{% extends "base/base.html" %}

{% load bootstrap5 symbols %}

{% block title %}
Botzinhos (小bots)
{% endblock title %}

{% block content %}
<div class="container">
<h6 class="text-center">
<span id="date"></span> |
<strong id="clock" class="text-primary"></strong>
<strong>UTC</strong> - Time Interval: <span class="text-primary fw-bolder">| {{ time_interval }}m |</span>
</h6>

{% groups_breadcrumbs request.user %}

<h4 class="mt-2">Mover Botzinhos do Grupo {{ object.name }}</h4>
<form method="post">{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">Enviar</button>
{% endbuttons %}
</form>
</div>
{% endblock content %}

{% block bootstrap5_extra_script %}
<script>
function currentTime() {
let date = new Date();
let hh = date.getUTCHours();
let mm = date.getUTCMinutes();
let ss = date.getUTCSeconds();

hh = (hh < 10) ? "0" + hh : hh;
mm = (mm < 10) ? "0" + mm : mm;
ss = (ss < 10) ? "0" + ss : ss;

let time = hh + ":" + mm + ":" + ss;

document.getElementById("clock").innerText = time;
document.getElementById("date").innerText = date.toLocaleDateString("en-US", {year: 'numeric', month: 'long', day: 'numeric' });
let t = setTimeout(function(){ currentTime() }, 1000);
}

currentTime();
</script>
{% endblock %}
25 changes: 24 additions & 1 deletion base/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def setUpClass(cls):
user=cls.user1, name="Test Group 1"
)
cls.group2, _ = TraderoBotGroup.objects.get_or_create(
user=cls.user2, name="Test Group 2"
user=cls.user1, name="Test Group 2"
)
cls.bot1 = TraderoBot(
group=cls.group1,
Expand Down Expand Up @@ -688,6 +688,29 @@ def test_botzinhos_group_actions(self):
self.assertEqual(response.status_code, 200)
self.assertIn(b"SUCCESS at", response.content)

def test_botzinhos_group_move(self):
self.client.force_login(self.user1)
url = reverse(
"base:botzinhos-group-move",
kwargs={"pk": self.group1.pk},
)
response = self.client.get(
url,
follow=True,
)
self.assertEqual(response.status_code, 200)
response = self.client.post(
url,
{
"to_group": self.group2.pk,
"bots": [self.bot3.pk],
},
follow=True,
)
self.assertEqual(response.status_code, 200)
self.bot3.refresh_from_db()
self.assertEqual(self.bot3.group, self.group2)


class TestAdmin(TestCase):
@classmethod
Expand Down
5 changes: 5 additions & 0 deletions base/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ def default_rate_limit(v):
default_rate_limit(base_views.BotzinhosGroupUpdateView.as_view()),
name="botzinhos-group-update",
),
path(
"Botzinhos/Grupo/<pk>/Mover",
default_rate_limit(base_views.BotzinhosGroupMoveView.as_view()),
name="botzinhos-group-move",
),
path(
"Botzinhos/Grupo/<pk>/Acção/<path:action>",
default_rate_limit(base_views.BotzinhosGroupActionView.as_view()),
Expand Down
27 changes: 27 additions & 0 deletions base/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
TraderoBotForm,
TraderoBotGroupEditForm,
TraderoBotGroupForm,
TraderoBotGroupMoveForm,
UserForm,
)
from .models import Symbol, TradeHistory, TraderoBot, TraderoBotGroup, User
Expand Down Expand Up @@ -358,6 +359,32 @@ def form_valid(self, form):
return super().form_valid(form)


class BotzinhosGroupMoveView(OwnerMixin, LoginRequiredMixin, UpdateView):
model = TraderoBotGroup
form_class = TraderoBotGroupMoveForm
template_name = "base/botzinhos_group_move_form.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["time_interval"] = settings.TIME_INTERVAL_BOTS
context["group"] = self.object
return context

def form_valid(self, form):
bots = form.cleaned_data["bots"]
to_group = form.cleaned_data["to_group"]
TraderoBot.objects.filter(id__in=[b.id for b in bots]).update(
group=to_group
)
self.group = to_group
return super().form_valid(form)

def get_success_url(self):
return reverse(
"base:botzinhos-group-detail", kwargs={"pk": self.group.pk}
)


class BotzinhosGroupActionView(ActionView):
"""
Runs Actions on Botzinhos Group
Expand Down

0 comments on commit 00fa2e6

Please sign in to comment.