Merge pull request #1808 from SchrodingersGat/part-page-refactor

Move "attachments" and "notes" to "Part Detail" page
This commit is contained in:
Oliver 2021-07-12 23:56:40 +10:00 committed by GitHub
commit 2295008944
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 153 additions and 209 deletions

View File

@ -837,6 +837,12 @@ input[type="submit"] {
pointer-events: none; /* Prevent this div from blocking links underneath */ pointer-events: none; /* Prevent this div from blocking links underneath */
} }
.notes {
border-radius: 5px;
background-color: #fafafa;
padding: 5px;
}
.alert { .alert {
display: none; display: none;
border-radius: 5px; border-radius: 5px;
@ -853,6 +859,11 @@ input[type="submit"] {
margin-right: 2px; margin-right: 2px;
} }
.btn-small {
padding: 3px;
padding-left: 5px;
}
.btn-remove { .btn-remove {
padding: 3px; padding: 3px;
padding-left: 5px; padding-left: 5px;

View File

@ -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 %}

View File

@ -1,6 +1,7 @@
{% extends "part/part_base.html" %} {% extends "part/part_base.html" %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% load markdownify %}
{% block menubar %} {% block menubar %}
@ -135,11 +136,38 @@
{% endif %} {% endif %}
{% if part.responsible %} {% if part.responsible %}
<tr> <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><strong>{% trans "Responsible User" %}</strong></td>
<td>{{ part.responsible }}</td> <td>{{ part.responsible }}</td>
</tr> </tr>
{% endif %} {% 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> </table>
</div> </div>
<div class='col-sm-6'> <div class='col-sm-6'>
@ -240,11 +268,11 @@
{% block post_content_panel %} {% block post_content_panel %}
<div class='row'>
<div class='col-sm-6'>
<div class='panel panel-default panel-inventree'> <div class='panel panel-default panel-inventree'>
<div class='panel-heading'> <div class='panel-heading'>
<h4> <h4>{% trans "Parameters" %}</h4>
{% trans "Part Parameters" %}
</h4>
</div> </div>
<div class='panel-content'> <div class='panel-content'>
<div id='param-button-toolbar'> <div id='param-button-toolbar'>
@ -259,6 +287,18 @@
<table id='parameter-table' class='table table-condensed table-striped' data-toolbar="#param-button-toolbar"></table> <table id='parameter-table' class='table table-condensed table-striped' data-toolbar="#param-button-toolbar"></table>
</div> </div>
</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>
</div>
</div>
{% endblock %} {% endblock %}
@ -269,6 +309,18 @@
{% block js_ready %} {% block js_ready %}
{{ block.super }} {{ 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() { $(".slidey").change(function() {
var field = $(this).attr('fieldname'); 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 %} {% endblock %}

View File

@ -109,16 +109,4 @@
</a> </a>
</li> </li>
{% endif %} {% 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> </ul>

View File

@ -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 %}

View File

@ -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'^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'^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'^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'), url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'),

View File

@ -13,7 +13,7 @@ from django.shortcuts import get_object_or_404
from django.shortcuts import HttpResponseRedirect from django.shortcuts import HttpResponseRedirect
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.urls import reverse, reverse_lazy 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.models import model_to_dict
from django.forms import HiddenInput, CheckboxInput from django.forms import HiddenInput, CheckboxInput
from django.conf import settings from django.conf import settings
@ -747,40 +747,6 @@ class PartImportAjax(FileManagementAjaxView, PartImport):
return PartImport.validate(self, self.steps.current, form, **kwargs) 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): class PartDetail(InvenTreeRoleMixin, DetailView):
""" Detail view for Part object """ Detail view for Part object
""" """

View File

@ -353,12 +353,16 @@ function constructFormBody(fields, options) {
// Override existing query filters (if provided!) // Override existing query filters (if provided!)
fields[field].filters = Object.assign(fields[field].filters || {}, field_options.filters); fields[field].filters = Object.assign(fields[field].filters || {}, field_options.filters);
// TODO: Refactor the following code with Object.assign (see above)
// Secondary modal options // Secondary modal options
fields[field].secondary = field_options.secondary; fields[field].secondary = field_options.secondary;
// Edit callback // Edit callback
fields[field].onEdit = field_options.onEdit; fields[field].onEdit = field_options.onEdit;
fields[field].multiline = field_options.multiline;
// Custom help_text // Custom help_text
if (field_options.help_text) { if (field_options.help_text) {
fields[field].help_text = field_options.help_text; fields[field].help_text = field_options.help_text;
@ -1483,8 +1487,12 @@ function constructInputOptions(name, classes, type, parameters) {
opts.push(`placeholder='${parameters.placeholder}'`); opts.push(`placeholder='${parameters.placeholder}'`);
} }
if (parameters.multiline) {
return `<textarea ${opts.join(' ')}></textarea>`;
} else {
return `<input ${opts.join(' ')}>`; return `<input ${opts.join(' ')}>`;
} }
}
// Construct a "hidden" input // Construct a "hidden" input