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;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-panel {
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.modal input {
|
.modal input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -276,6 +276,7 @@
|
|||||||
constructForm('{% url "api-part-list" %}', {
|
constructForm('{% url "api-part-list" %}', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
fields: fields,
|
fields: fields,
|
||||||
|
groups: partGroups(),
|
||||||
title: '{% trans "Create Part" %}',
|
title: '{% trans "Create Part" %}',
|
||||||
onSuccess: function(data) {
|
onSuccess: function(data) {
|
||||||
// Follow the new part
|
// Follow the new part
|
||||||
|
@ -264,6 +264,10 @@ function constructForm(url, options) {
|
|||||||
// Default HTTP method
|
// Default HTTP method
|
||||||
options.method = options.method || 'PATCH';
|
options.method = options.method || 'PATCH';
|
||||||
|
|
||||||
|
// Default "groups" definition
|
||||||
|
options.groups = options.groups || {};
|
||||||
|
options.current_group = null;
|
||||||
|
|
||||||
// Construct an "empty" data object if not provided
|
// Construct an "empty" data object if not provided
|
||||||
if (!options.data) {
|
if (!options.data) {
|
||||||
options.data = {};
|
options.data = {};
|
||||||
@ -413,6 +417,11 @@ function constructFormBody(fields, options) {
|
|||||||
fields[field].choices = field_options.choices;
|
fields[field].choices = field_options.choices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Group
|
||||||
|
if (field_options.group) {
|
||||||
|
fields[field].group = field_options.group;
|
||||||
|
}
|
||||||
|
|
||||||
// Field prefix
|
// Field prefix
|
||||||
if (field_options.prefix) {
|
if (field_options.prefix) {
|
||||||
fields[field].prefix = field_options.prefix;
|
fields[field].prefix = field_options.prefix;
|
||||||
@ -465,8 +474,12 @@ function constructFormBody(fields, options) {
|
|||||||
html += constructField(name, field, options);
|
html += constructField(name, field, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Dynamically create the modals,
|
if (options.current_group) {
|
||||||
// so that we can have an infinite number of stacks!
|
// 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
|
// Create a new modal if one does not exists
|
||||||
if (!options.modal) {
|
if (!options.modal) {
|
||||||
@ -535,6 +548,8 @@ function constructFormBody(fields, options) {
|
|||||||
submitFormData(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) {
|
function initializeRelatedFields(fields, options) {
|
||||||
|
|
||||||
var field_names = options.field_names;
|
var field_names = options.field_names;
|
||||||
@ -1353,6 +1411,8 @@ function renderModelData(name, model, data, parameters, options) {
|
|||||||
*/
|
*/
|
||||||
function constructField(name, parameters, options) {
|
function constructField(name, parameters, options) {
|
||||||
|
|
||||||
|
var html = '';
|
||||||
|
|
||||||
// Shortcut for simple visual fields
|
// Shortcut for simple visual fields
|
||||||
if (parameters.type == 'candy') {
|
if (parameters.type == 'candy') {
|
||||||
return constructCandyInput(name, parameters, options);
|
return constructCandyInput(name, parameters, options);
|
||||||
@ -1365,13 +1425,62 @@ function constructField(name, parameters, options) {
|
|||||||
return constructHiddenInput(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';
|
var form_classes = 'form-group';
|
||||||
|
|
||||||
if (parameters.errors) {
|
if (parameters.errors) {
|
||||||
form_classes += ' has-error';
|
form_classes += ' has-error';
|
||||||
}
|
}
|
||||||
|
|
||||||
var html = '';
|
|
||||||
|
|
||||||
// Optional content to render before the field
|
// Optional content to render before the field
|
||||||
if (parameters.before) {
|
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
|
// Construct fieldset for part forms
|
||||||
function partFields(options={}) {
|
function partFields(options={}) {
|
||||||
|
|
||||||
@ -48,36 +68,41 @@ function partFields(options={}) {
|
|||||||
minimum_stock: {
|
minimum_stock: {
|
||||||
icon: 'fa-boxes',
|
icon: 'fa-boxes',
|
||||||
},
|
},
|
||||||
attributes: {
|
|
||||||
type: 'candy',
|
|
||||||
html: `<hr><h4><i>{% trans "Part Attributes" %}</i></h4><hr>`
|
|
||||||
},
|
|
||||||
component: {
|
component: {
|
||||||
value: global_settings.PART_COMPONENT,
|
value: global_settings.PART_COMPONENT,
|
||||||
|
group: 'attributes',
|
||||||
},
|
},
|
||||||
assembly: {
|
assembly: {
|
||||||
value: global_settings.PART_ASSEMBLY,
|
value: global_settings.PART_ASSEMBLY,
|
||||||
|
group: 'attributes',
|
||||||
},
|
},
|
||||||
is_template: {
|
is_template: {
|
||||||
value: global_settings.PART_TEMPLATE,
|
value: global_settings.PART_TEMPLATE,
|
||||||
|
group: 'attributes',
|
||||||
},
|
},
|
||||||
trackable: {
|
trackable: {
|
||||||
value: global_settings.PART_TRACKABLE,
|
value: global_settings.PART_TRACKABLE,
|
||||||
|
group: 'attributes',
|
||||||
},
|
},
|
||||||
purchaseable: {
|
purchaseable: {
|
||||||
value: global_settings.PART_PURCHASEABLE,
|
value: global_settings.PART_PURCHASEABLE,
|
||||||
|
group: 'attributes',
|
||||||
},
|
},
|
||||||
salable: {
|
salable: {
|
||||||
value: global_settings.PART_SALABLE,
|
value: global_settings.PART_SALABLE,
|
||||||
|
group: 'attributes',
|
||||||
},
|
},
|
||||||
virtual: {
|
virtual: {
|
||||||
value: global_settings.PART_VIRTUAL,
|
value: global_settings.PART_VIRTUAL,
|
||||||
|
group: 'attributes',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// If editing a part, we can set the "active" status
|
// If editing a part, we can set the "active" status
|
||||||
if (options.edit) {
|
if (options.edit) {
|
||||||
fields.active = {};
|
fields.active = {
|
||||||
|
group: 'attributes'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pop expiry field
|
// Pop expiry field
|
||||||
@ -91,16 +116,12 @@ function partFields(options={}) {
|
|||||||
// No supplier parts available yet
|
// No supplier parts available yet
|
||||||
delete fields["default_supplier"];
|
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) {
|
if (global_settings.PART_CREATE_INITIAL) {
|
||||||
fields.initial_stock = {
|
fields.initial_stock = {
|
||||||
type: 'decimal',
|
type: 'decimal',
|
||||||
label: '{% trans "Initial Stock Quantity" %}',
|
label: '{% trans "Initial Stock Quantity" %}',
|
||||||
help_text: '{% trans "Initialize part stock with specified quantity" %}',
|
help_text: '{% trans "Initialize part stock with specified quantity" %}',
|
||||||
|
group: 'create',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,21 +130,18 @@ function partFields(options={}) {
|
|||||||
label: '{% trans "Copy Category Parameters" %}',
|
label: '{% trans "Copy Category Parameters" %}',
|
||||||
help_text: '{% trans "Copy parameter templates from selected part category" %}',
|
help_text: '{% trans "Copy parameter templates from selected part category" %}',
|
||||||
value: global_settings.PART_CATEGORY_PARAMETERS,
|
value: global_settings.PART_CATEGORY_PARAMETERS,
|
||||||
|
group: 'create',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Additional fields when "duplicating" a part
|
// Additional fields when "duplicating" a part
|
||||||
if (options.duplicate) {
|
if (options.duplicate) {
|
||||||
|
|
||||||
fields.duplicate = {
|
|
||||||
type: 'candy',
|
|
||||||
html: `<hr><h4><i>{% trans "Part Duplication Options" %}</i></h4><hr>`,
|
|
||||||
};
|
|
||||||
|
|
||||||
fields.copy_from = {
|
fields.copy_from = {
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
hidden: true,
|
hidden: true,
|
||||||
value: options.duplicate,
|
value: options.duplicate,
|
||||||
|
group: 'duplicate',
|
||||||
},
|
},
|
||||||
|
|
||||||
fields.copy_image = {
|
fields.copy_image = {
|
||||||
@ -131,6 +149,7 @@ function partFields(options={}) {
|
|||||||
label: '{% trans "Copy Image" %}',
|
label: '{% trans "Copy Image" %}',
|
||||||
help_text: '{% trans "Copy image from original part" %}',
|
help_text: '{% trans "Copy image from original part" %}',
|
||||||
value: true,
|
value: true,
|
||||||
|
group: 'duplicate',
|
||||||
},
|
},
|
||||||
|
|
||||||
fields.copy_bom = {
|
fields.copy_bom = {
|
||||||
@ -138,6 +157,7 @@ function partFields(options={}) {
|
|||||||
label: '{% trans "Copy BOM" %}',
|
label: '{% trans "Copy BOM" %}',
|
||||||
help_text: '{% trans "Copy bill of materials from original part" %}',
|
help_text: '{% trans "Copy bill of materials from original part" %}',
|
||||||
value: global_settings.PART_COPY_BOM,
|
value: global_settings.PART_COPY_BOM,
|
||||||
|
group: 'duplicate',
|
||||||
};
|
};
|
||||||
|
|
||||||
fields.copy_parameters = {
|
fields.copy_parameters = {
|
||||||
@ -145,6 +165,7 @@ function partFields(options={}) {
|
|||||||
label: '{% trans "Copy Parameters" %}',
|
label: '{% trans "Copy Parameters" %}',
|
||||||
help_text: '{% trans "Copy parameter data from original part" %}',
|
help_text: '{% trans "Copy parameter data from original part" %}',
|
||||||
value: global_settings.PART_COPY_PARAMETERS,
|
value: global_settings.PART_COPY_PARAMETERS,
|
||||||
|
group: 'duplicate',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,8 +212,11 @@ function editPart(pk, options={}) {
|
|||||||
edit: true
|
edit: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var groups = partGroups({});
|
||||||
|
|
||||||
constructForm(url, {
|
constructForm(url, {
|
||||||
fields: fields,
|
fields: fields,
|
||||||
|
groups: partGroups(),
|
||||||
title: '{% trans "Edit Part" %}',
|
title: '{% trans "Edit Part" %}',
|
||||||
reload: true,
|
reload: true,
|
||||||
});
|
});
|
||||||
@ -221,6 +245,7 @@ function duplicatePart(pk, options={}) {
|
|||||||
constructForm('{% url "api-part-list" %}', {
|
constructForm('{% url "api-part-list" %}', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
fields: fields,
|
fields: fields,
|
||||||
|
groups: partGroups(),
|
||||||
title: '{% trans "Duplicate Part" %}',
|
title: '{% trans "Duplicate Part" %}',
|
||||||
data: data,
|
data: data,
|
||||||
onSuccess: function(data) {
|
onSuccess: function(data) {
|
||||||
|
Loading…
Reference in New Issue
Block a user