Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign user settings UI #1042

Merged
merged 2 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 6 additions & 50 deletions server/crashmanager/forms.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Div, Field, Layout, Submit
from django.conf import settings
from django.forms import (
CharField,
CheckboxSelectMultiple,
ChoiceField,
EmailField,
ModelChoiceField,
ModelForm,
ModelMultipleChoiceField,
Textarea,
TextInput,
)
from django.forms import CharField, EmailField, ModelForm, Textarea, TextInput
from rest_framework.exceptions import ValidationError

from .models import BugProvider, BugzillaTemplate, Tool, User
from .models import BugzillaTemplate, User


class Row(Div):
Expand Down Expand Up @@ -178,31 +168,6 @@ class Meta:


class UserSettingsForm(ModelForm):
helper = FormHelper()
helper.layout = Layout(
"defaultToolsFilter",
Row(
Field("defaultProviderId", wrapper_class="col-md-6"),
Field("defaultTemplateId", wrapper_class="col-md-6"),
),
"email",
HTML("""<p><strong>Subscribe to notifications:</strong></p>"""),
"inaccessible_bug",
"coverage_drop",
"bucket_hit",
"tasks_failed",
Submit("submit", "Save settings", css_class="btn btn-danger"),
)
defaultToolsFilter = ModelMultipleChoiceField(
queryset=Tool.objects.all(),
label="Select the tools you would like to include in your default views:",
widget=CheckboxSelectMultiple(),
required=False,
)
defaultProviderId = ModelChoiceField(
queryset=BugProvider.objects.all(), label="Default Provider:", empty_label=None
)
defaultTemplateId = ChoiceField(label="Default Template:")
email = EmailField(label="Email:")

class Meta:
Expand All @@ -220,17 +185,6 @@ class Meta:
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
super().__init__(*args, **kwargs)

self.fields["defaultTemplateId"].choices = list(
dict.fromkeys(
[
(t.pk, f"{p.classname}: {t}")
for p in BugProvider.objects.all()
for t in p.getInstance().getTemplateList()
]
)
)

instance = kwargs.get("instance", None)
if instance:
self.initial["email"] = instance.user.email
Expand All @@ -239,8 +193,10 @@ def __init__(self, *args, **kwargs):
self.fields["email"].required = False
self.fields["email"].widget.attrs["readonly"] = True

self.fields["defaultToolsFilter"].required = False

def clean_defaultToolsFilter(self):
data = self.cleaned_data["defaultToolsFilter"]
data = self.cleaned_data.get("defaultToolsFilter", None)
if (
self.user
and list(self.user.defaultToolsFilter.all()) != list(data)
Expand All @@ -252,7 +208,7 @@ def clean_defaultToolsFilter(self):
return data

def clean_defaultProviderId(self):
data = self.cleaned_data["defaultProviderId"].id
data = self.cleaned_data["defaultProviderId"]
return data

def save(self, *args, **kwargs):
Expand Down
41 changes: 37 additions & 4 deletions server/crashmanager/templates/usersettings.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% extends 'layouts/layout_base.html' %}
{% load crispy_forms_tags %}

{% block title %}User Settings{% endblock title %}

Expand All @@ -8,19 +7,53 @@
<div class="panel panel-default">
<div class="panel-heading"><i class="bi bi-gear-fill"></i> User Settings</div>
<div class="panel-body">
<form method="post">
<form method="post" class="block">
{% csrf_token %}
{% crispy form %}

<usersettingsform
:default-tools-options="[
{% for tool in defaultToolsFilterChoices %}
{ code: '{{ tool.id }}', name: '{{ tool.name }}' },
{% endfor %}
]"
:default-tools-selected="[
{% for tool in defaultToolsFilter %}
{ code: '{{ tool.id }}', name: '{{ tool.name }}' },
{% endfor %}
]"
:default-provider-options="[
{% for provider in defaultProviderChoices %}
{ id: '{{ provider.id }}', name: '{{ provider.hostname }}' },
{% endfor %}
]"
:default-provider-selected="{{ user.defaultProviderId }}"
:default-template-options="[
{% for template in defaultTemplateChoices %}
{ id: {{ template.0 }}, name: '{{ template.1 }}' },
{% endfor %}
]"
:default-template-selected="{{ user.defaultTemplateId }}"
initial-email="{{ email }}"
:allow-email-edit="{{ allow_email_edit|yesno:'true,false' }}"
:subscribe-notification-options="[
{% for notification in notificationChoices %}
{ code: '{{ notification.id }}', name: '{{ notification.label }}', selected: {{ notification.initial|yesno:'true,false' }} },
{% endfor %}
]"
:form-errors="{{form_errors}}"
/>

</form>
</div>
</div>

{% if bugzilla_providers %}
<div class="panel panel-default">
<div class="panel-heading"><i class="bi bi-gear-fill"></i> Bugzilla Providers Settings</div>
<div class="panel-body">
Provide API Keys to authenticate calls to your Bugzilla Providers on this browser.
{% for p in bugzilla_providers %}
<providerkey :provider-id="{{ p.pk }}" provider-hostname="{{ p.hostname }}"></providerkey>
<providerkey :provider-id="{{ p.pk }}" provider-hostname="{{ p.hostname }}"></providerkey>
{% endfor %}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion server/crashmanager/tests/test_user_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def test_user_settings_simple_get(client):
response = client.get(path)
assert response.status_code == requests.codes["ok"]
assert list(response.context["bugzilla_providers"]) == []
assert response.context["user"] == User.objects.get(user__username="test").user
assert response.context["user"] == User.objects.get(user__username="test")


def test_user_settings_edit(client, cm):
Expand Down
52 changes: 49 additions & 3 deletions server/crashmanager/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from wsgiref.util import FileWrapper

from django.conf import settings as django_settings
from django.conf import settings as djangosettings
from django.core.exceptions import FieldError, PermissionDenied, SuspiciousOperation
from django.db.models import F, Q
from django.db.models.aggregates import Count, Min
Expand Down Expand Up @@ -1666,10 +1667,55 @@ def get_object(self):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["bugzilla_providers"] = BugProvider.objects.filter(
classname="BugzillaProvider"
user_object = self.get_object()

# Prepare form errors if any
form = self.get_form()
form_errors = {field: errors for field, errors in form.errors.items()}

# Prepare all form-related data
context.update(
{
"defaultToolsFilter": user_object.defaultToolsFilter.all(),
"defaultToolsFilterChoices": Tool.objects.all(),
"defaultProviderChoices": BugProvider.objects.all(),
"defaultTemplateChoices": [
(t.pk, f"{p.classname}: {t}")
for p in BugProvider.objects.all()
for t in p.getInstance().getTemplateList()
],
"bugzilla_providers": BugProvider.objects.filter(
classname="BugzillaProvider"
),
"user": user_object,
"email": self.request.user.email,
"allow_email_edit": djangosettings.ALLOW_EMAIL_EDITION,
"form_errors": form_errors,
"notificationChoices": [
{
"id": "inaccessible_bug",
"label": "Inaccessible Bug",
"initial": user_object.inaccessible_bug,
},
{
"id": "coverage_drop",
"label": "Coverage Drop",
"initial": user_object.coverage_drop,
},
{
"id": "bucket_hit",
"label": "Bucket Hit",
"initial": user_object.bucket_hit,
},
{
"id": "tasks_failed",
"label": "Tasks Failed",
"initial": user_object.tasks_failed,
},
],
}
)
context["user"] = self.request.user

return context


Expand Down
11 changes: 11 additions & 0 deletions server/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions server/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"sweetalert": "^2.1.2",
"vue": "^3.4.21",
"vue-loading-overlay": "^6.0.3",
"vue-multiselect": "^3.1.0",
"vue-router": "^4.3.0"
},
"devDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions server/frontend/src/components/ProviderKey.vue
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,7 @@ export default defineComponent({
.mt-light {
margin-top: 0.5rem;
}
.btn {
margin-left: 0.8rem;
}
</style>
Loading