diff --git a/apps/it_manager/tests.py b/apps/it_manager/tests.py index 5d2f07f..5e5bb96 100644 --- a/apps/it_manager/tests.py +++ b/apps/it_manager/tests.py @@ -152,6 +152,36 @@ class ItManagerEquipmentTests(TestCase): self.assertContains(r, 'role="dialog"') self.assertNotContains(r, 'id="it-equipment-panel-overlay"') + def test_models_catalog_is_popup(self): + r = self.client.get('/it-manager/') + self.assertContains(r, 'id="it-equipment-models-panel"') + self.assertContains(r, 'it-equipment-models-modal-title') + self.assertContains(r, 'itModelsOpenFromEquipment') + self.assertNotContains(r, 'id="it-equipment-models-panel-overlay"') + + def test_model_create_returns_to_equipment_popup(self): + r = self.client.post('/it-manager/equipment/models/create/', { + 'equipment_type': 'laptop', + 'name': 'Latitude 5440', + 'return_to': 'equipment', + }, HTTP_HX_REQUEST='true') + self.assertEqual(r.status_code, 200) + model = EquipmentModel.objects.get(name='Latitude 5440') + self.assertContains(r, 'data-it-equipment-open="1"') + self.assertContains(r, f'data-it-select-model-id="{model.pk}"') + self.assertNotContains(r, 'data-it-models-open="1"') + + def test_model_create_error_reopens_models_popup(self): + r = self.client.post('/it-manager/equipment/models/create/', { + 'equipment_type': 'laptop', + 'name': '', + 'return_to': 'equipment', + }, HTTP_HX_REQUEST='true') + self.assertEqual(r.status_code, 200) + self.assertContains(r, 'data-it-models-open="1"') + self.assertContains(r, 'name="return_to"') + self.assertContains(r, 'it-equipment-models-modal-title') + def test_bulk_create_error_reopens_popup(self): r = self.client.post('/it-manager/equipment/bulk-create/', { 'serial_numbers': 'SN-X', diff --git a/apps/it_manager/views.py b/apps/it_manager/views.py index 40676cf..89eadeb 100644 --- a/apps/it_manager/views.py +++ b/apps/it_manager/views.py @@ -589,12 +589,13 @@ def equipment_model_create_view(request): return HttpResponseForbidden() context_extra = {} + return_to = (request.POST.get('return_to') or '').strip() if request.method == 'POST': equipment_type_id = _resolve_directory('equipment_type', request.POST.get('equipment_type', '')) name = request.POST.get('name', '').strip() if equipment_type_id and name: warranty_months = request.POST.get('warranty_months', '').strip() - EquipmentModel.objects.get_or_create( + model, _created = EquipmentModel.objects.get_or_create( equipment_type_id=equipment_type_id, brand_id=request.POST.get('brand_id') or None, name=name, @@ -603,8 +604,14 @@ def equipment_model_create_view(request): 'notes': request.POST.get('notes', '').strip(), }, ) + if return_to == 'equipment': + context_extra['it_equipment_open'] = True + context_extra['it_select_model_id'] = model.pk else: - context_extra['equipment_form_error'] = 'Вкажіть тип і назву моделі.' + context_extra['equipment_model_form_error'] = 'Вкажіть тип і назву моделі.' + context_extra['it_models_open'] = True + if return_to: + context_extra['it_models_return_to'] = return_to context = _it_manager_context(request) context['it_active_tab'] = 'equipment' diff --git a/static/assets/js/it-manager.js b/static/assets/js/it-manager.js index 6921983..203403c 100644 --- a/static/assets/js/it-manager.js +++ b/static/assets/js/it-manager.js @@ -53,9 +53,93 @@ function itPanelClose(id) { document.body.style.overflow = ''; } +var IT_EQ_DRAFT_KEY = 'it-equipment-draft'; + +function itEquipmentDraftSave() { + var form = document.querySelector('#it-equipment-panel form'); + if (!form || !window.sessionStorage) return; + var data = {}; + form.querySelectorAll('input, textarea, select').forEach(function (el) { + if (!el.name || el.name === 'csrfmiddlewaretoken') return; + if (el.type === 'checkbox' || el.type === 'radio') { + data[el.name] = el.checked ? (el.value || '1') : ''; + data['__checked__' + el.name] = el.checked; + } else { + data[el.name] = el.value; + } + }); + try { sessionStorage.setItem(IT_EQ_DRAFT_KEY, JSON.stringify(data)); } catch (e) {} +} + +function itEquipmentDraftRestore() { + if (!window.sessionStorage) return; + var raw; + try { raw = sessionStorage.getItem(IT_EQ_DRAFT_KEY); } catch (e) { return; } + if (!raw) return; + var data; + try { data = JSON.parse(raw); } catch (e) { return; } + var form = document.querySelector('#it-equipment-panel form'); + if (!form) return; + Object.keys(data).forEach(function (name) { + if (name.indexOf('__checked__') === 0) return; + var el = form.querySelector('[name="' + name + '"]'); + if (!el) return; + if (el.type === 'checkbox' || el.type === 'radio') { + el.checked = !!data['__checked__' + name]; + } else { + el.value = data[name] || ''; + if (el.tagName === 'SELECT') { + el.dispatchEvent(new Event('change', { bubbles: true })); + } + } + }); + var model = document.getElementById('it-equipment-model-select'); + if (model && model.value && typeof itSetSearchableSelectValue === 'function') { + itSetSearchableSelectValue('it-equipment-model-select', model.value); + } +} + +function itEquipmentDraftClear() { + try { sessionStorage.removeItem(IT_EQ_DRAFT_KEY); } catch (e) {} +} + +function itModelsOpenCatalog() { + var ret = document.getElementById('it-models-return-to'); + if (ret) ret.value = ''; + itPanelOpen('it-equipment-models-panel'); +} + +function itModelsOpenFromEquipment() { + itEquipmentDraftSave(); + var ret = document.getElementById('it-models-return-to'); + if (ret) ret.value = 'equipment'; + itPanelClose('it-equipment-panel'); + itPanelOpen('it-equipment-models-panel'); +} + +function itModelsDismiss() { + var ret = document.getElementById('it-models-return-to'); + var back = ret && ret.value === 'equipment'; + itPanelClose('it-equipment-models-panel'); + if (back) { + itPanelOpen('it-equipment-panel'); + itEquipmentDraftRestore(); + } +} + function itModalsInit(root) { if (!root) return; - if (root.getAttribute('data-it-equipment-open') === '1') itPanelOpen('it-equipment-panel'); + if (root.getAttribute('data-it-models-open') === '1') { + itPanelOpen('it-equipment-models-panel'); + return; + } + if (root.getAttribute('data-it-equipment-open') === '1') { + itPanelOpen('it-equipment-panel'); + itEquipmentDraftRestore(); + var mid = root.getAttribute('data-it-select-model-id'); + if (mid) itSetSearchableSelectValue('it-equipment-model-select', mid); + itEquipmentDraftClear(); + } if (root.getAttribute('data-it-worklog-open') === '1') itPanelOpen('it-worklog-panel'); } @@ -441,6 +525,11 @@ document.addEventListener('keydown', function (ev) { itReportPreviewClose(); return; } + var models = document.getElementById('it-equipment-models-panel'); + if (models && models.style.display === 'flex') { + itModelsDismiss(); + return; + } ['it-equipment-panel', 'it-worklog-panel'].forEach(function (id) { var el = document.getElementById(id); if (el && el.style.display === 'flex') itPanelClose(id); diff --git a/templates/pages/it-manager.html b/templates/pages/it-manager.html index dd25e3a..d39a616 100644 --- a/templates/pages/it-manager.html +++ b/templates/pages/it-manager.html @@ -1,7 +1,7 @@ {% load common_tags %} {% load i18n %} {% with active_tab=it_active_tab|default:"equipment" %} -
+

{% trans "IT-отдел" %}

@@ -70,7 +70,7 @@ {% endif %}
- @@ -107,14 +107,14 @@
- {% for m in equipment_models %} {% endfor %}
- +
@@ -158,18 +158,29 @@
- - -
-
- {% trans "Каталог моделей" %} -
{% csrf_token %} + + {% if equipment_model_form_error %} +
+ {{ equipment_model_form_error }} +
+ {% endif %}
{% trans "Новая модель" %}
@@ -198,12 +209,15 @@
- +
+ + +
-
+
{% trans "В каталоге" %} ({{ equipment_models|length }})
{% for m in equipment_models %} @@ -219,6 +233,7 @@ {% endfor %}
+