diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 61815f0587..ac7cf1f4e1 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -837,6 +837,12 @@ input[type="submit"] { pointer-events: none; /* Prevent this div from blocking links underneath */ } +.notes { + border-radius: 5px; + background-color: #fafafa; + padding: 5px; +} + .alert { display: none; border-radius: 5px; @@ -853,6 +859,11 @@ input[type="submit"] { margin-right: 2px; } +.btn-small { + padding: 3px; + padding-left: 5px; +} + .btn-remove { padding: 3px; padding-left: 5px; diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html deleted file mode 100644 index 7128980472..0000000000 --- a/InvenTree/part/templates/part/attachments.html +++ /dev/null @@ -1,86 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Part Attachments" %} -{% endblock %} - -{% block details %} - -{% include "attachment_table.html" with attachments=part.part_attachments %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadAttachmentTable( - '{% url "api-part-attachment-list" %}', - { - filters: { - part: {{ part.pk }}, - }, - onEdit: function(pk) { - var url = `/api/part/attachment/${pk}/`; - - constructForm(url, { - fields: { - comment: {}, - }, - title: '{% trans "Edit Attachment" %}', - onSuccess: reloadAttachmentTable, - }); - }, - onDelete: function(pk) { - var url = `/api/part/attachment/${pk}/`; - - constructForm(url, { - method: 'DELETE', - confirmMessage: '{% trans "Confirm Delete Operation" %}', - title: '{% trans "Delete Attachment" %}', - onSuccess: reloadAttachmentTable, - }); - } - } - ); - - enableDragAndDrop( - '#attachment-dropzone', - '{% url "api-part-attachment-list" %}', - { - data: { - part: {{ part.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - reloadAttachmentTable(); - } - } - ); - - $("#new-attachment").click(function() { - - constructForm( - '{% url "api-part-attachment-list" %}', - { - method: 'POST', - fields: { - attachment: {}, - comment: {}, - part: { - value: {{ part.pk }}, - hidden: true, - } - }, - onSuccess: reloadAttachmentTable, - title: '{% trans "Add Attachment" %}', - } - ) - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 5132721fec..8a78eb85a5 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -1,6 +1,7 @@ {% extends "part/part_base.html" %} {% load static %} {% load i18n %} +{% load markdownify %} {% block menubar %} @@ -135,11 +136,38 @@ {% endif %} {% if part.responsible %} <tr> - <td><span class='fas fa-user'>d</span></td> + <td><span class='fas fa-user'></span></td> <td><strong>{% trans "Responsible User" %}</strong></td> <td>{{ part.responsible }}</td> </tr> {% endif %} + + <tr><td colspan="3"></td></tr> + + <tr> + <td><span class='fas fa-sticky-note'></span></td> + <td> + <strong>{% trans "Notes" %}</strong> + </td> + <td> + <div class='btn-group float-right'> + <button type='button' id='edit-notes' title='{% trans "Edit Notes" %}' class='btn btn-small btn-default'> + <span class='fas fa-edit'> + </span> + </button> + </div> + </td> + </tr> + <tr> + <td colspan='3'> + {% if part.notes %} + <div class='notes'> + {{ part.notes | markdownify }} + </div> + {% endif %} + </td> + </tr> + </table> </div> <div class='col-sm-6'> @@ -240,23 +268,35 @@ {% block post_content_panel %} -<div class='panel panel-default panel-inventree'> - <div class='panel-heading'> - <h4> - {% trans "Part Parameters" %} - </h4> - </div> - <div class='panel-content'> - <div id='param-button-toolbar'> - <div class='button-toolbar container-fluid' style='float: right;'> - {% if roles.part.add %} - <button title='{% trans "Add new parameter" %}' class='btn btn-success' id='param-create'> - <span class='fas fa-plus-circle'></span> {% trans "New Parameter" %} - </button> - {% endif %} +<div class='row'> + <div class='col-sm-6'> + <div class='panel panel-default panel-inventree'> + <div class='panel-heading'> + <h4>{% trans "Parameters" %}</h4> + </div> + <div class='panel-content'> + <div id='param-button-toolbar'> + <div class='button-toolbar container-fluid' style='float: right;'> + {% if roles.part.add %} + <button title='{% trans "Add new parameter" %}' class='btn btn-success' id='param-create'> + <span class='fas fa-plus-circle'></span> {% trans "New Parameter" %} + </button> + {% endif %} + </div> + </div> + <table id='parameter-table' class='table table-condensed table-striped' data-toolbar="#param-button-toolbar"></table> + </div> + </div> + </div> + <div class='col-sm-6'> + <div class='panel panel-default panel-inventree'> + <div class='panel-heading'> + <h4>{% trans "Attachments" %}</h4> + </div> + <div class='panel-content'> + {% include "attachment_table.html" %} </div> </div> - <table id='parameter-table' class='table table-condensed table-striped' data-toolbar="#param-button-toolbar"></table> </div> </div> @@ -269,6 +309,18 @@ {% block js_ready %} {{ block.super }} + $('#edit-notes').click(function() { + constructForm('{% url "api-part-detail" part.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Part Notes" %}', + reload: true, + }); + }); + $(".slidey").change(function() { var field = $(this).attr('fieldname'); @@ -337,4 +389,68 @@ }); }); + loadAttachmentTable( + '{% url "api-part-attachment-list" %}', + { + filters: { + part: {{ part.pk }}, + }, + onEdit: function(pk) { + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + }, + onDelete: function(pk) { + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-part-attachment-list" %}', + { + data: { + part: {{ part.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + reloadAttachmentTable(); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm( + '{% url "api-part-attachment-list" %}', + { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + part: { + value: {{ part.pk }}, + hidden: true, + } + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Add Attachment" %}', + } + ) + }); + {% endblock %} diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index afe4fee374..e8617dc677 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -109,16 +109,4 @@ </a> </li> {% endif %} - <li class='list-group-item {% if tab == "attachments" %}active{% endif %}' title='{% trans "Attachments" %}'> - <a href='{% url "part-attachments" part.id %}'> - <span class='menu-tab-icon fas fa-paperclip sidebar-icon'></span> - {% trans "Attachments" %} - </a> - </li> - <li class='list-group-item {% if tab == "notes" %}active{% endif %}' title='{% trans "Part Notes" %}'> - <a href='{% url "part-notes" part.id %}'> - <span class='menu-tab-icon fas fa-clipboard sidebar-icon'></span> - {% trans "Notes" %} - </a> - </li> </ul> diff --git a/InvenTree/part/templates/part/notes.html b/InvenTree/part/templates/part/notes.html deleted file mode 100644 index 63e0190d48..0000000000 --- a/InvenTree/part/templates/part/notes.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load crispy_forms_tags %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Part Notes" %} -{% if roles.part.change and not editing %} -<button title='{% trans "Edit notes" %}' class='btn btn-default' id='edit-notes'><span class='fas fa-edit'></span></button> -{% endif %} -{% endblock %} - -{% block details %} - -{% if editing %} -<form method='POST'> - {% csrf_token %} - - {{ form }} - <hr> - - <button type="submit" class='btn btn-default'>{% trans "Save" %}</button> - -</form> - -{{ form.media }} - -{% else %} - -<div class='panel panel-default'> - {% if part.notes %} - <div class='panel-content'> - {{ part.notes | markdownify }} - </div> - {% endif %} -</div> - -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'part-notes' part.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index 8843a839a1..1fa7227f5e 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -61,8 +61,6 @@ part_detail_urls = [ url(r'^tests/', views.PartDetail.as_view(template_name='part/part_tests.html'), name='part-test-templates'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^related-parts/?', views.PartDetail.as_view(template_name='part/related.html'), name='part-related'), - url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'), - url(r'^notes/?', views.PartNotes.as_view(), name='part-notes'), url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 561b9be0fb..4acf5fcdb6 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -13,7 +13,7 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import HttpResponseRedirect from django.utils.translation import gettext_lazy as _ from django.urls import reverse, reverse_lazy -from django.views.generic import DetailView, ListView, UpdateView +from django.views.generic import DetailView, ListView from django.forms.models import model_to_dict from django.forms import HiddenInput, CheckboxInput from django.conf import settings @@ -747,40 +747,6 @@ class PartImportAjax(FileManagementAjaxView, PartImport): return PartImport.validate(self, self.steps.current, form, **kwargs) -class PartNotes(UpdateView): - """ View for editing the 'notes' field of a Part object. - Presents a live markdown editor. - """ - - context_object_name = 'part' - # form_class = part_forms.EditNotesForm - template_name = 'part/notes.html' - model = Part - - role_required = 'part.change' - - fields = ['notes'] - - def get_success_url(self): - """ Return the success URL for this form """ - - return reverse('part-notes', kwargs={'pk': self.get_object().id}) - - def get_context_data(self, **kwargs): - - part = self.get_object() - - context = super().get_context_data(**kwargs) - - context['editing'] = str2bool(self.request.GET.get('edit', '')) - - ctx = part.get_context_data(self.request) - - context.update(ctx) - - return context - - class PartDetail(InvenTreeRoleMixin, DetailView): """ Detail view for Part object """ diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index b71551747c..6dd7dbd968 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -353,12 +353,16 @@ function constructFormBody(fields, options) { // Override existing query filters (if provided!) fields[field].filters = Object.assign(fields[field].filters || {}, field_options.filters); + // TODO: Refactor the following code with Object.assign (see above) + // Secondary modal options fields[field].secondary = field_options.secondary; // Edit callback fields[field].onEdit = field_options.onEdit; + fields[field].multiline = field_options.multiline; + // Custom help_text if (field_options.help_text) { fields[field].help_text = field_options.help_text; @@ -1483,7 +1487,11 @@ function constructInputOptions(name, classes, type, parameters) { opts.push(`placeholder='${parameters.placeholder}'`); } - return `<input ${opts.join(' ')}>`; + if (parameters.multiline) { + return `<textarea ${opts.join(' ')}></textarea>`; + } else { + return `<input ${opts.join(' ')}>`; + } }