Просмотр исходного кода

Introduce UserConfigForm for managing user preferences

jeremystretch 4 лет назад
Родитель
Сommit
70f257b1ea

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox.js.map


+ 0 - 2
netbox/project-static/src/buttons/index.ts

@@ -1,7 +1,6 @@
 import { initConnectionToggle } from './connectionToggle';
 import { initDepthToggle } from './depthToggle';
 import { initMoveButtons } from './moveOptions';
-import { initPreferenceUpdate } from './preferences';
 import { initReslug } from './reslug';
 import { initSelectAll } from './selectAll';
 
@@ -11,7 +10,6 @@ export function initButtons(): void {
     initConnectionToggle,
     initReslug,
     initSelectAll,
-    initPreferenceUpdate,
     initMoveButtons,
   ]) {
     func();

+ 0 - 30
netbox/project-static/src/buttons/preferences.ts

@@ -1,30 +0,0 @@
-import { setColorMode } from '../colorMode';
-import { getElement } from '../util';
-
-/**
- * Perform actions in the UI based on the value of user profile updates.
- *
- * @param event Form Submit
- */
-function handlePreferenceSave(event: Event): void {
-  // Create a FormData instance to access the form values.
-  const form = event.currentTarget as HTMLFormElement;
-  const formData = new FormData(form);
-
-  // Update the UI color mode immediately when the user preference changes.
-  if (formData.get('ui.colormode') === 'dark') {
-    setColorMode('dark');
-  } else if (formData.get('ui.colormode') === 'light') {
-    setColorMode('light');
-  }
-}
-
-/**
- * Initialize handlers for user profile updates.
- */
-export function initPreferenceUpdate(): void {
-  const form = getElement<HTMLFormElement>('preferences-update');
-  if (form !== null) {
-    form.addEventListener('submit', handlePreferenceSave);
-  }
-}

+ 15 - 45
netbox/templates/users/preferences.html

@@ -1,57 +1,27 @@
 {% extends 'users/base.html' %}
 {% load helpers %}
+{% load form_helpers %}
 
 {% block title %}User Preferences{% endblock %}
 
 {% block content %}
   <form method="post" action="" id="preferences-update">
     {% csrf_token %}
-    <div class="field-group mb-3">
-      <h5>Color Mode</h5>
-      <p class="text-muted">Set preferred UI color mode</p>
-      {% with color_mode=preferences|get_key:'ui.colormode'%}
-      <div class="form-check form-check-inline">
-        <input class="form-check-input" type="radio" name="ui.colormode" id="color-mode-preference-dark" value="dark"{% if color_mode == 'dark'%} checked{% endif %}>
-        <label class="form-check-label" for="color-mode-preference-dark">Dark</label>
-      </div>
-      <div class="form-check form-check-inline">
-        <input class="form-check-input" type="radio" name="ui.colormode" id="color-mode-preference-light" value="light"{% if color_mode == 'light'%} checked{% endif %}>
-        <label class="form-check-label" for="color-mode-preference-light">Light</label>
-      </div>
-      {% endwith %}
-    </div>
-    <div class="row mb-3">
-      <div class="col">
-        <button type="submit" class="btn btn-primary" name="_update">Save</button>
+
+    {% for group, fields in form.Meta.fieldsets %}
+      <div class="field-group my-5">
+        <div class="row mb-2">
+          <h5 class="offset-sm-3">{{ group }}</h5>
+        </div>
+        {% for name in fields %}
+            {% render_field form|getfield:name %}
+        {% endfor %}
       </div>
+    {% endfor %}
+
+    <div class="text-end my-3">
+      <a class="btn btn-outline-secondary" href="{% url 'user:preferences' %}">Cancel</a>
+      <button type="submit" name="_update" class="btn btn-primary">Save </button>
     </div>
-    {% if preferences %}
-      <div class="field-group mb-3">
-        <h5>Other Preferences</h5>
-        <table class="table table-striped">
-          <thead>
-            <tr>
-              <th><input type="checkbox" class="toggle form-check-input" title="Toggle All"></th>
-              <th>Preference</th>
-              <th>Value</th>
-            </tr>
-          </thead>
-          <tbody>
-            {% for key, value in preferences.items %}
-              <tr>
-                <td class="min-width"><input class="form-check-input" type="checkbox" name="pk" value="{{ key }}"></td>
-                <td><samp>{{ key }}</samp></td>
-                <td><samp>{{ value }}</samp></td>
-              </tr>
-            {% endfor %}
-          </tbody>
-        </table>
-        <button type="submit" class="btn btn-danger" name="_delete">
-          <span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Clear Selected
-        </button>
-      </div>
-    {% else %}
-      <h3 class="text-muted text-center">No preferences found</h3>
-    {% endif %}
   </form>
 {% endblock %}

+ 65 - 1
netbox/users/forms.py

@@ -2,7 +2,9 @@ from django import forms
 from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm
 
 from utilities.forms import BootstrapMixin, DateTimePicker
-from .models import Token
+from utilities.paginator import EnhancedPaginator
+from utilities.utils import flatten_dict
+from .models import Token, UserConfig
 
 
 class LoginForm(BootstrapMixin, AuthenticationForm):
@@ -13,6 +15,68 @@ class PasswordChangeForm(BootstrapMixin, DjangoPasswordChangeForm):
     pass
 
 
+def get_page_lengths():
+    return [
+        (v, str(v)) for v in EnhancedPaginator.default_page_lengths
+    ]
+
+
+class UserConfigForm(BootstrapMixin, forms.ModelForm):
+    pagination__per_page = forms.TypedChoiceField(
+        label='Page length',
+        coerce=lambda val: int(val),
+        choices=get_page_lengths,
+        required=False
+    )
+    ui__colormode = forms.ChoiceField(
+        label='Color mode',
+        choices=(
+            ('light', 'Light'),
+            ('dark', 'Dark'),
+        ),
+        required=False
+    )
+    extras__configcontext__format = forms.ChoiceField(
+        label='ConfigContext format',
+        choices=(
+            ('json', 'JSON'),
+            ('yaml', 'YAML'),
+        ),
+        required=False
+    )
+
+    class Meta:
+        model = UserConfig
+        fields = ()
+        fieldsets = (
+            ('User Interface', (
+                'pagination__per_page',
+                'ui__colormode',
+            )),
+            ('Miscellaneous', (
+                'extras__configcontext__format',
+            )),
+        )
+
+    def __init__(self, *args, instance=None, **kwargs):
+
+        # Get initial data from UserConfig instance
+        initial_data = flatten_dict(instance.data, separator='__')
+        kwargs['initial'] = initial_data
+
+        super().__init__(*args, instance=instance, **kwargs)
+
+    def save(self, *args, **kwargs):
+
+        # Set UserConfig data
+        for field_name, value in self.cleaned_data.items():
+            pref_name = field_name.replace('__', '.')
+            print(f'{pref_name}: {value}')
+            self.instance.set(pref_name, value, commit=False)
+
+        return super().save(*args, **kwargs)
+
+
 class TokenForm(BootstrapMixin, forms.ModelForm):
     key = forms.CharField(
         required=False,

+ 16 - 20
netbox/users/views.py

@@ -19,7 +19,7 @@ from extras.models import ObjectChange
 from extras.tables import ObjectChangeTable
 from netbox.config import get_config
 from utilities.forms import ConfirmationForm
-from .forms import LoginForm, PasswordChangeForm, TokenForm
+from .forms import LoginForm, PasswordChangeForm, TokenForm, UserConfigForm
 from .models import Token
 
 
@@ -137,32 +137,28 @@ class UserConfigView(LoginRequiredMixin, View):
     template_name = 'users/preferences.html'
 
     def get(self, request):
+        userconfig = request.user.config
+        form = UserConfigForm(instance=userconfig)
 
         return render(request, self.template_name, {
-            'preferences': request.user.config.all(),
+            'form': form,
             'active_tab': 'preferences',
         })
 
     def post(self, request):
         userconfig = request.user.config
-        data = userconfig.all()
-
-        # Delete selected preferences
-        if "_delete" in request.POST:
-            for key in request.POST.getlist('pk'):
-                if key in data:
-                    userconfig.clear(key)
-        # Update specific values
-        elif "_update" in request.POST:
-            for key in request.POST:
-                if not key.startswith('_') and not key.startswith('csrf'):
-                    for value in request.POST.getlist(key):
-                        userconfig.set(key, value)
-
-        userconfig.save()
-        messages.success(request, "Your preferences have been updated.")
-
-        return redirect('user:preferences')
+        form = UserConfigForm(request.POST, instance=userconfig)
+
+        if form.is_valid():
+            form.save()
+
+            messages.success(request, "Your preferences have been updated.")
+            return redirect('user:preferences')
+
+        return render(request, self.template_name, {
+            'form': form,
+            'active_tab': 'preferences',
+        })
 
 
 class ChangePasswordView(LoginRequiredMixin, View):

+ 1 - 1
netbox/utilities/utils.py

@@ -282,7 +282,7 @@ def flatten_dict(d, prefix='', separator='.'):
     for k, v in d.items():
         key = separator.join([prefix, k]) if prefix else k
         if type(v) is dict:
-            ret.update(flatten_dict(v, prefix=key))
+            ret.update(flatten_dict(v, prefix=key, separator=separator))
         else:
             ret[key] = v
     return ret

Некоторые файлы не были показаны из-за большого количества измененных файлов