1
0
Fork 0

Progress Indicator ()

closes 
Show progress indicator to track deployment

- Disable deploy button when deployment is in progress.

Co-authored-by: kevin <kevin@procolix.com>
Reviewed-on: 
Reviewed-by: kiara Grouwstra <kiara@procolix.eu>
This commit is contained in:
lois Verheij 2025-03-26 10:14:06 +01:00
parent d78995b34c
commit b4fbc457a6
6 changed files with 91 additions and 45 deletions

View file

@ -1 +1 @@
/home/vg/src/Fediversity/nix/store/mwqqk0qmldzvv4xj9kq2lbah2flhc44z-source/dist/htmx.js /nix/store/mwqqk0qmldzvv4xj9kq2lbah2flhc44z-source/dist/htmx.js

View file

@ -3,3 +3,24 @@ body
margin: 0 margin: 0
font-family: sans-serif font-family: sans-serif
box-sizing: border-box box-sizing: border-box
.loader
width: 48px
height: 48px
border: 5px solid #000
border-bottom-color: #F34508
border-radius: 50%
box-sizing: border-box
animation: rotation 1s linear infinite
display: inline-block
@keyframes rotation
0% { transform: rotate(0deg) }
100% { transform: rotate(360deg) }
#spinner-container
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
display: block

View file

@ -1,11 +1,23 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<form method="post" enctype="multipart/form-data" action="{% url 'configuration_form' %}"> <form method="post" enctype="multipart/form-data" action="{% url 'save' %}">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<button id="deploy-button" class="button"
hx-post="{% url 'deployment_status' %}"
hx-trigger="click"
hx-indicator="#spinner-container"
hx-disabled-elt="this"
hx-swap="none"
name="deploy">
Deploy
</button>
<button class="button" type="submit" name="deploy">Deploy</button>
<button class="button" type="submit" name="save">Save</button> <button class="button" type="submit" name="save">Save</button>
<div id="spinner-container" class="htmx-indicator">
<span class="loader"></span>
</div>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -13,7 +13,7 @@ class ConfigurationForm(TestCase):
password=self.password password=self.password
) )
self.config_url = reverse('configuration_form') self.config_url = reverse('save')
def test_configuration_form_submission(self): def test_configuration_form_submission(self):
config = Configuration.objects.create( config = Configuration.objects.create(
@ -36,12 +36,13 @@ class ConfigurationForm(TestCase):
enable=True, enable=True,
mastodon_enable=True, mastodon_enable=True,
) )
print(form_data)
response = self.client.post(self.config_url, data=form_data) response = self.client.post(self.config_url, data=form_data)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
config.refresh_from_db() config.refresh_from_db()
print(config.parsed_value)
self.assertTrue(config.parsed_value.enable) self.assertTrue(config.parsed_value.enable)
self.assertTrue(config.parsed_value.mastodon.enable) self.assertTrue(config.parsed_value.mastodon.enable)
# this should not have changed # this should not have changed

View file

@ -26,4 +26,6 @@ urlpatterns = [
path("account/", views.AccountDetail.as_view(), name='account_detail'), path("account/", views.AccountDetail.as_view(), name='account_detail'),
path("services/", views.ServiceList.as_view(), name='service_list'), path("services/", views.ServiceList.as_view(), name='service_list'),
path("configuration/", views.ConfigurationForm.as_view(), name='configuration_form'), path("configuration/", views.ConfigurationForm.as_view(), name='configuration_form'),
path("deployment/status/", views.DeploymentStatus.as_view(), name='deployment_status'),
path("save/", views.Save.as_view(), name='save'),
] ]

View file

@ -1,6 +1,7 @@
from enum import Enum from enum import Enum
import json import json
import subprocess import subprocess
import os
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
@ -9,9 +10,9 @@ from django.views.generic import TemplateView, DetailView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from panel import models, settings from panel import models, settings
from panel import models
from panel.configuration import forms from panel.configuration import forms
class Index(TemplateView): class Index(TemplateView):
template_name = 'index.html' template_name = 'index.html'
@ -33,51 +34,12 @@ class ConfigurationForm(LoginRequiredMixin, FormView):
success_url = reverse_lazy('configuration_form') success_url = reverse_lazy('configuration_form')
form_class = forms.Form form_class = forms.Form
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
def get_object(self): def get_object(self):
"""Get or create the configuration object for the current user""" """Get or create the configuration object for the current user"""
obj, created = models.Configuration.objects.get_or_create( obj, created = models.Configuration.objects.get_or_create(
operator=self.request.user, operator=self.request.user,
) )
# Check for deploy button
if "deploy" in self.request.POST.keys():
submission = obj.parsed_value.model_dump_json()
# FIXME: let the user specify these from the form (#190)
dummy_user = {
"initialUser": {
"displayName": "Testy McTestface",
"username": "test",
"password": "testtest",
"email": "test@test.com",
},
}
# serialize back and forth now we still need to manually inject the dummy user
deployment = json.dumps(dummy_user | json.loads(submission))
env = {
"PATH": settings.bin_path,
# pass in form info to our deployment
"DEPLOYMENT": deployment,
}
cmd = [
"nix",
"develop",
# workaround to pass in info to nixops4 thru env vars, tho impure :(
"--extra-experimental-features",
"configurable-impure-env",
"--command",
"nixops4",
"apply",
"test",
]
subprocess.run(
cmd,
cwd=settings.repo_dir,
env=env,
)
return obj return obj
# TODO(@fricklerhandwerk): # TODO(@fricklerhandwerk):
@ -120,9 +82,57 @@ class ConfigurationForm(LoginRequiredMixin, FormView):
initial.update(self.convert_enums_to_names(config_dict)) initial.update(self.convert_enums_to_names(config_dict))
return initial return initial
class Save(ConfigurationForm):
def form_valid(self, form): def form_valid(self, form):
obj = self.get_object() obj = self.get_object()
obj.value = form.to_python().model_dump_json() obj.value = form.to_python().model_dump_json()
obj.save() obj.save()
return super().form_valid(form) return super().form_valid(form)
class DeploymentStatus(ConfigurationForm):
def form_valid(self, form):
obj = self.get_object()
obj.save()
# Check for deploy button
if "deploy" in self.request.POST.keys():
self.deployment(obj)
return super().form_valid(form)
def deployment(self, obj):
submission = obj.parsed_value.model_dump_json()
# FIXME: let the user specify these from the form (#190)
dummy_user = {
"initialUser": {
"displayName": "Testy McTestface",
"username": "test",
"password": "testtest",
"email": "test@test.com",
},
}
# serialize back and forth now we still need to manually inject the dummy user
deployment = json.dumps(dummy_user | json.loads(submission))
env = {
"PATH": settings.bin_path,
# pass in form info to our deployment
"DEPLOYMENT": deployment,
}
cmd = [
"nix",
"develop",
"--extra-experimental-features",
"configurable-impure-env",
"--command",
"nixops4",
"apply",
"test",
]
deployment_result = subprocess.run(
cmd,
cwd=settings.repo_dir,
env=env,
)
print(deployment_result)
return deployment_result