mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add "groups" to API forms
This commit is contained in:
parent
cd4a797e71
commit
5b42ab7332
@ -730,6 +730,13 @@
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.form-panel {
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
||||
.modal input {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -276,6 +276,7 @@
|
||||
constructForm('{% url "api-part-list" %}', {
|
||||
method: 'POST',
|
||||
fields: fields,
|
||||
groups: partGroups(),
|
||||
title: '{% trans "Create Part" %}',
|
||||
onSuccess: function(data) {
|
||||
// Follow the new part
|
||||
|
@ -264,6 +264,10 @@ function constructForm(url, options) {
|
||||
// Default HTTP method
|
||||
options.method = options.method || 'PATCH';
|
||||
|
||||
// Default "groups" definition
|
||||
options.groups = options.groups || {};
|
||||
options.current_group = null;
|
||||
|
||||
// Construct an "empty" data object if not provided
|
||||
if (!options.data) {
|
||||
options.data = {};
|
||||
@ -413,6 +417,11 @@ function constructFormBody(fields, options) {
|
||||
fields[field].choices = field_options.choices;
|
||||
}
|
||||
|
||||
// Group
|
||||
if (field_options.group) {
|
||||
fields[field].group = field_options.group;
|
||||
}
|
||||
|
||||
// Field prefix
|
||||
if (field_options.prefix) {
|
||||
fields[field].prefix = field_options.prefix;
|
||||
@ -465,8 +474,12 @@ function constructFormBody(fields, options) {
|
||||
html += constructField(name, field, options);
|
||||
}
|
||||
|
||||
// TODO: Dynamically create the modals,
|
||||
// so that we can have an infinite number of stacks!
|
||||
if (options.current_group) {
|
||||
// Close out the current group
|
||||
html += `</div></div>`;
|
||||
|
||||
console.log(`finally, ending group '${console.current_group}'`);
|
||||
}
|
||||
|
||||
// Create a new modal if one does not exists
|
||||
if (!options.modal) {
|
||||
@ -535,6 +548,8 @@ function constructFormBody(fields, options) {
|
||||
submitFormData(fields, options);
|
||||
}
|
||||
});
|
||||
|
||||
initializeGroups(fields, options);
|
||||
}
|
||||
|
||||
|
||||
@ -960,6 +975,49 @@ function addClearCallback(name, field, options) {
|
||||
}
|
||||
|
||||
|
||||
// Initialize callbacks and initial states for groups
|
||||
function initializeGroups(fields, options) {
|
||||
|
||||
var modal = options.modal;
|
||||
|
||||
// Callback for when the group is expanded
|
||||
$(modal).find('.form-panel-content').on('show.bs.collapse', function() {
|
||||
|
||||
var panel = $(this).closest('.form-panel');
|
||||
var group = panel.attr('group');
|
||||
|
||||
var icon = $(modal).find(`#group-icon-${group}`);
|
||||
|
||||
icon.removeClass('fa-angle-right');
|
||||
icon.addClass('fa-angle-up');
|
||||
});
|
||||
|
||||
// Callback for when the group is collapsed
|
||||
$(modal).find('.form-panel-content').on('hide.bs.collapse', function() {
|
||||
|
||||
var panel = $(this).closest('.form-panel');
|
||||
var group = panel.attr('group');
|
||||
|
||||
var icon = $(modal).find(`#group-icon-${group}`);
|
||||
|
||||
icon.removeClass('fa-angle-up');
|
||||
icon.addClass('fa-angle-right');
|
||||
});
|
||||
|
||||
// Set initial state of each specified group
|
||||
for (var group in options.groups) {
|
||||
|
||||
var group_options = options.groups[group];
|
||||
|
||||
if (group_options.collapsed) {
|
||||
$(modal).find(`#form-panel-content-${group}`).collapse("hide");
|
||||
} else {
|
||||
$(modal).find(`#form-panel-content-${group}`).collapse("show");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function initializeRelatedFields(fields, options) {
|
||||
|
||||
var field_names = options.field_names;
|
||||
@ -1353,6 +1411,8 @@ function renderModelData(name, model, data, parameters, options) {
|
||||
*/
|
||||
function constructField(name, parameters, options) {
|
||||
|
||||
var html = '';
|
||||
|
||||
// Shortcut for simple visual fields
|
||||
if (parameters.type == 'candy') {
|
||||
return constructCandyInput(name, parameters, options);
|
||||
@ -1365,13 +1425,62 @@ function constructField(name, parameters, options) {
|
||||
return constructHiddenInput(name, parameters, options);
|
||||
}
|
||||
|
||||
// Are we ending a group?
|
||||
if (options.current_group && parameters.group != options.current_group) {
|
||||
html += `</div></div>`;
|
||||
|
||||
console.log(`ending group '${options.current_group}'`);
|
||||
|
||||
// Null out the current "group" so we can start a new one
|
||||
options.current_group = null;
|
||||
}
|
||||
|
||||
// Are we starting a new group?
|
||||
if (parameters.group) {
|
||||
|
||||
var group = parameters.group;
|
||||
|
||||
var group_options = options.groups[group] || {};
|
||||
|
||||
// Are we starting a new group?
|
||||
// Add HTML for the start of a separate panel
|
||||
if (parameters.group != options.current_group) {
|
||||
|
||||
console.log(`starting group '${group}'`);
|
||||
|
||||
html += `
|
||||
<div class='panel form-panel' id='form-panel-${group}' group='${group}'>
|
||||
<div class='panel-heading form-panel-heading' id='form-panel-heading-${group}'>`;
|
||||
if (group_options.collapsible) {
|
||||
html += `
|
||||
<div data-toggle='collapse' data-target='#form-panel-content-${group}'>
|
||||
<a href='#'><span id='group-icon-${group}' class='fas fa-angle-up'></span>
|
||||
`;
|
||||
} else {
|
||||
html += `<div>`;
|
||||
}
|
||||
|
||||
html += `<h4 style='display: inline;'>${group_options.title || group}</h4>`;
|
||||
|
||||
if (group_options.collapsible) {
|
||||
html += `</a>`;
|
||||
}
|
||||
|
||||
html += `
|
||||
</div></div>
|
||||
<div class='panel-content form-panel-content' id='form-panel-content-${group}'>
|
||||
`;
|
||||
}
|
||||
|
||||
// Keep track of the group we are in
|
||||
options.current_group = group;
|
||||
}
|
||||
|
||||
var form_classes = 'form-group';
|
||||
|
||||
if (parameters.errors) {
|
||||
form_classes += ' has-error';
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
// Optional content to render before the field
|
||||
if (parameters.before) {
|
||||
|
@ -13,6 +13,26 @@ function yesNoLabel(value) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function partGroups(options={}) {
|
||||
|
||||
return {
|
||||
attributes: {
|
||||
title: '{% trans "Part Attributes" %}',
|
||||
collapsible: true,
|
||||
},
|
||||
create: {
|
||||
title: '{% trans "Part Creation Options" %}',
|
||||
collapsible: true,
|
||||
},
|
||||
duplicate: {
|
||||
title: '{% trans "Part Duplication Options" %}',
|
||||
collapsible: true,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Construct fieldset for part forms
|
||||
function partFields(options={}) {
|
||||
|
||||
@ -48,36 +68,41 @@ function partFields(options={}) {
|
||||
minimum_stock: {
|
||||
icon: 'fa-boxes',
|
||||
},
|
||||
attributes: {
|
||||
type: 'candy',
|
||||
html: `<hr><h4><i>{% trans "Part Attributes" %}</i></h4><hr>`
|
||||
},
|
||||
component: {
|
||||
value: global_settings.PART_COMPONENT,
|
||||
group: 'attributes',
|
||||
},
|
||||
assembly: {
|
||||
value: global_settings.PART_ASSEMBLY,
|
||||
group: 'attributes',
|
||||
},
|
||||
is_template: {
|
||||
value: global_settings.PART_TEMPLATE,
|
||||
group: 'attributes',
|
||||
},
|
||||
trackable: {
|
||||
value: global_settings.PART_TRACKABLE,
|
||||
group: 'attributes',
|
||||
},
|
||||
purchaseable: {
|
||||
value: global_settings.PART_PURCHASEABLE,
|
||||
group: 'attributes',
|
||||
},
|
||||
salable: {
|
||||
value: global_settings.PART_SALABLE,
|
||||
group: 'attributes',
|
||||
},
|
||||
virtual: {
|
||||
value: global_settings.PART_VIRTUAL,
|
||||
group: 'attributes',
|
||||
},
|
||||
};
|
||||
|
||||
// If editing a part, we can set the "active" status
|
||||
if (options.edit) {
|
||||
fields.active = {};
|
||||
fields.active = {
|
||||
group: 'attributes'
|
||||
};
|
||||
}
|
||||
|
||||
// Pop expiry field
|
||||
@ -91,16 +116,12 @@ function partFields(options={}) {
|
||||
// No supplier parts available yet
|
||||
delete fields["default_supplier"];
|
||||
|
||||
fields.create = {
|
||||
type: 'candy',
|
||||
html: `<hr><h4><i>{% trans "Part Creation Options" %}</i></h4><hr>`,
|
||||
};
|
||||
|
||||
if (global_settings.PART_CREATE_INITIAL) {
|
||||
fields.initial_stock = {
|
||||
type: 'decimal',
|
||||
label: '{% trans "Initial Stock Quantity" %}',
|
||||
help_text: '{% trans "Initialize part stock with specified quantity" %}',
|
||||
group: 'create',
|
||||
};
|
||||
}
|
||||
|
||||
@ -109,21 +130,18 @@ function partFields(options={}) {
|
||||
label: '{% trans "Copy Category Parameters" %}',
|
||||
help_text: '{% trans "Copy parameter templates from selected part category" %}',
|
||||
value: global_settings.PART_CATEGORY_PARAMETERS,
|
||||
group: 'create',
|
||||
};
|
||||
}
|
||||
|
||||
// Additional fields when "duplicating" a part
|
||||
if (options.duplicate) {
|
||||
|
||||
fields.duplicate = {
|
||||
type: 'candy',
|
||||
html: `<hr><h4><i>{% trans "Part Duplication Options" %}</i></h4><hr>`,
|
||||
};
|
||||
|
||||
fields.copy_from = {
|
||||
type: 'integer',
|
||||
hidden: true,
|
||||
value: options.duplicate,
|
||||
group: 'duplicate',
|
||||
},
|
||||
|
||||
fields.copy_image = {
|
||||
@ -131,6 +149,7 @@ function partFields(options={}) {
|
||||
label: '{% trans "Copy Image" %}',
|
||||
help_text: '{% trans "Copy image from original part" %}',
|
||||
value: true,
|
||||
group: 'duplicate',
|
||||
},
|
||||
|
||||
fields.copy_bom = {
|
||||
@ -138,6 +157,7 @@ function partFields(options={}) {
|
||||
label: '{% trans "Copy BOM" %}',
|
||||
help_text: '{% trans "Copy bill of materials from original part" %}',
|
||||
value: global_settings.PART_COPY_BOM,
|
||||
group: 'duplicate',
|
||||
};
|
||||
|
||||
fields.copy_parameters = {
|
||||
@ -145,6 +165,7 @@ function partFields(options={}) {
|
||||
label: '{% trans "Copy Parameters" %}',
|
||||
help_text: '{% trans "Copy parameter data from original part" %}',
|
||||
value: global_settings.PART_COPY_PARAMETERS,
|
||||
group: 'duplicate',
|
||||
};
|
||||
}
|
||||
|
||||
@ -191,8 +212,11 @@ function editPart(pk, options={}) {
|
||||
edit: true
|
||||
});
|
||||
|
||||
var groups = partGroups({});
|
||||
|
||||
constructForm(url, {
|
||||
fields: fields,
|
||||
groups: partGroups(),
|
||||
title: '{% trans "Edit Part" %}',
|
||||
reload: true,
|
||||
});
|
||||
@ -221,6 +245,7 @@ function duplicatePart(pk, options={}) {
|
||||
constructForm('{% url "api-part-list" %}', {
|
||||
method: 'POST',
|
||||
fields: fields,
|
||||
groups: partGroups(),
|
||||
title: '{% trans "Duplicate Part" %}',
|
||||
data: data,
|
||||
onSuccess: function(data) {
|
||||
|
Loading…
Reference in New Issue
Block a user