partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit 4a9c30103f7515bb27a3e7e32631a1327ec59129
parent 82925f5283828209ffbfad6551bbc4e7e3f40bcd
Author: Felicia Hummel <felicitus@felicitus.org>
Date:   Thu, 15 Dec 2016 14:45:21 +0100

Merge pull request #752 from partkeepr/PartKeepr-163

Part keepr 163
Diffstat:
Msrc/PartKeepr/FrontendBundle/Resources/public/css/PartKeepr.css | 12++++++++++++
Msrc/PartKeepr/FrontendBundle/Resources/public/images/form/reload-trigger.png | 0
Asrc/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-add.png | 0
Asrc/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-delete.png | 0
Asrc/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-save.png | 0
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Components/Importer/Importer.js | 101+++++++++++++++++++++----------------------------------------------------------
Asrc/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/PresetComboBox.js | 267+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/FrontendBundle/Resources/views/index.html.twig | 1+
Msrc/PartKeepr/ImportBundle/Entity/ImportPreset.php | 3++-
9 files changed, 309 insertions(+), 75 deletions(-)

diff --git a/src/PartKeepr/FrontendBundle/Resources/public/css/PartKeepr.css b/src/PartKeepr/FrontendBundle/Resources/public/css/PartKeepr.css @@ -47,6 +47,18 @@ background-image: url(../images/form/reload-trigger.png); } +.x-form-trigger-save { + background-image: url(../images/form/trigger-save.png); +} + +.x-form-trigger-add { + background-image: url(../images/form/trigger-add.png); +} + +.x-form-trigger-delete { + background-image: url(../images/form/trigger-delete.png); +} + .x-form-trigger-link { background-image: url(../images/form/trigger-link.png); } diff --git a/src/PartKeepr/FrontendBundle/Resources/public/images/form/reload-trigger.png b/src/PartKeepr/FrontendBundle/Resources/public/images/form/reload-trigger.png Binary files differ. diff --git a/src/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-add.png b/src/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-add.png Binary files differ. diff --git a/src/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-delete.png b/src/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-delete.png Binary files differ. diff --git a/src/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-save.png b/src/PartKeepr/FrontendBundle/Resources/public/images/form/trigger-save.png Binary files differ. diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Importer/Importer.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Importer/Importer.js @@ -16,30 +16,20 @@ Ext.define("PartKeepr.Importer.Importer", { xtype: 'tbseparator', }, { - xtype: 'combo', - store: { - model: 'PartKeepr.ImportBundle.Entity.ImportPreset', - autoLoad: true - }, + xtype: 'presetcombo', + model: 'PartKeepr.ImportBundle.Entity.ImportPreset', itemId: 'importerPresetCombo', displayField: 'name', - valueField: '@id' - }, { - xtype: 'button', - itemId: "savePreset", - text: i18n("Save Preset") - }, { - xtype: 'button', - itemId: "deletePreset", - text: i18n("Delete Preset") - }, + width: 300 + + } ], items: [ { title: i18n("Mapping"), xtype: 'treepanel', region: 'west', - width: 400, + width: 280, split: true, itemId: 'fieldTree', columns: [ @@ -55,9 +45,6 @@ Ext.define("PartKeepr.Importer.Importer", { header: i18n("Required"), dataIndex: 'required', width: 70, - }, { - header: i18n("Mapping"), - width: 100 } ], store: { @@ -104,22 +91,6 @@ Ext.define("PartKeepr.Importer.Importer", { ] }, { - xtype: 'panel', - region: 'east', - width: 300, - split: true, - layout: 'fit', - - items: [ - { - xtype: 'textarea', - itemId: "debugger", - scrollable: true, - style: 'font-family: monospace;' - } - ] - }, - { xtype: 'tabpanel', region: 'south', height: 265, @@ -199,10 +170,17 @@ Ext.define("PartKeepr.Importer.Importer", { this.down("#importerOneToManyConfiguration").on("configChanged", this.onConfigChange, this); this.down("#importerManyToOneConfiguration").on("configChanged", this.onConfigChange, this); - this.down("#savePreset").on("click", this.onPresetSave, this); - this.down("#importerPresetCombo").on("select", this.onPresetSelect, this); + this.down("#importerPresetCombo").on("selectPreset", this.onPresetSelect, this); + this.down("#importerPresetCombo").setAdditionalFields([ + { + fieldName: "baseEntity", + value: this.model.getName() + } + ]); - this.loadData("/~felicitus/PartKeepr/web/app_dev.php/api/temp_uploaded_files/668"); + this.down("#preview").on("afterrender", this.refreshPreview, this); + this.down("#importerPresetCombo").setConfiguration(this.importConfiguration); + this.validateConfig(); }, applyConfiguration: function () { @@ -225,35 +203,14 @@ Ext.define("PartKeepr.Importer.Importer", { treeMaker.make(rootNode, this.model, "", Ext.bind(this.appendFieldData, this)); rootNode.expand(); }, - onPresetSelect: function (combo, record) + onPresetSelect: function (configuration) { - this.importConfiguration = Ext.decode(record.get("configuration")); - - // @todo check if the json string is correct - // @todo refresh active panels + this.importConfiguration = configuration; this.applyConfiguration(); this.refreshPreview(); - - }, - onPresetSave: function () - { - var presetName = this.down("#importerPresetCombo").getRawValue(); - - if (presetName === "") { - Ext.Msg.alert(i18n("Preset Name Empty"), - i18n("The preset name cannot be empty. Type a preset name in the box to the left.")); - return; - } - - var config = Ext.encode(this.importConfiguration); - - var j = Ext.create("PartKeepr.ImportBundle.Entity.ImportPreset"); - j.set("name", presetName); - j.set("configuration", config); - j.set("baseEntity", this.model.getName()); - j.save(); - + this.down("#importerPresetCombo").setConfiguration(configuration); + this.down("#fieldTree").getSelectionModel().select(this.down("#fieldTree").getRootNode()); }, executeImport: function () { @@ -268,7 +225,7 @@ Ext.define("PartKeepr.Importer.Importer", { }, success: function (response) { - var response = Ext.decode(response.responseText); + var responseData = Ext.decode(response.responseText); var j = Ext.create("Ext.window.Window", { width: 400, @@ -281,7 +238,7 @@ Ext.define("PartKeepr.Importer.Importer", { listeners: { render: function (p) { - p.getEl().dom.innerHTML = "<pre><strong>Import Results</strong>\n\n" + response.logs + "</pre>"; + p.getEl().dom.innerHTML = "<pre><strong>Import Results</strong>\n\n" + responseData.logs + "</pre>"; } } } @@ -311,12 +268,8 @@ Ext.define("PartKeepr.Importer.Importer", { }, onConfigChange: function () { - var str = JSON.stringify(this.importConfiguration, undefined, 4); - - this.down("#debugger").setValue(str); - + this.down("#importerPresetCombo").setConfiguration(this.importConfiguration); Ext.Function.defer(this.refreshPreview, 100, this); - }, refreshPreview: function () { @@ -332,10 +285,10 @@ Ext.define("PartKeepr.Importer.Importer", { }, success: function (response) { - var response = Ext.decode(response.responseText); + var responseData = Ext.decode(response.responseText); if (this.down("#preview").body !== undefined) { - this.down("#preview").body.dom.innerHTML = "<pre>" + response.logs + "</pre>"; + this.down("#preview").body.dom.innerHTML = "<pre>" + responseData.logs + "</pre>"; } }, scope: this @@ -456,8 +409,7 @@ Ext.define("PartKeepr.Importer.Importer", { }, scope: this }); - } - , + }, reconfigureGrid: function (data) { var columns = []; @@ -533,6 +485,7 @@ Ext.define("PartKeepr.Importer.Importer", { if (node.data.required) { switch (configuration.importBehaviour) { case "dontSet": + case undefined: this.appendError(node, i18n("The entity is required, but it is not configured")); break; case "matchData": diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/PresetComboBox.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/PresetComboBox.js @@ -0,0 +1,267 @@ +Ext.define("PartKeepr.PresetCombobox", { + extend: "Ext.form.field.ComboBox", + + xtype: 'presetcombo', + + config: { + /** + * The model to use + * @var string + */ + model: null, + + /** + * The name of the field which contains the serialized configuration + * @var string + */ + configurationField: "configuration", + + /** + * Additional fields to set. Contains a list of objects + * which are defined like this: + * + * { fieldName: "baseEntity", value: "myvalue" } + * @var array + */ + additionalFields: [], + + /** + * Defines the name of the preset name field + * @var string + */ + nameField: "name", + + /** + * Preset for a blank configuration + * @var object + */ + blankConfiguration: {}, + + /** + * Defines if the configuration should be serialized or not + * @var bool + */ + serializeConfiguration: true + + }, + + returnObject: true, + editable: false, + emptyText: i18n("No preset selected"), + forceSelection: true, + allowBlank: true, + valueField: '@id', + + triggers: { + save: { + cls: "x-form-trigger-save", + weight: 1, + tooltip: i18n("Expand All"), + handler: 'onSavePreset', + scope: 'this' + }, + add: { + cls: "x-form-trigger-add", + weight: 2, + handler: 'onAddPreset', + scope: 'this' + }, + delete: { + cls: "x-form-trigger-delete", + weight: 3, + handler: 'onDeletePreset', + scope: 'this', + hidden: true + } + }, + + listeners: { + change: 'onSelectionChange', + scope: 'this' + }, + + /** + * @event selectPreset + * Fires after a preset has been selected + * @param {String} The configuration which was selected + */ + + initComponent: function () + { + if (this.getModel() === null) { + Ext.raise("The configuration property 'model' is not configured, but is required."); + } + + if (this.getConfigurationField() === null) { + Ext.raise("The configuration property 'configurationField' is not configured, but is required."); + } + + this.store = Ext.create("Ext.data.Store", { + model: this.model, + autoLoad: true + }); + + this.on("select", this.onPresetSelect, this); + + this.callParent(arguments); + }, + /** + * Event handler to handle a preset selection. Fires the "selectPreset" event. + */ + onPresetSelect: function () + { + var configuration; + if (this.serializeConfiguration) { + // @todo check if the json string is correct and if it is not, display an error + configuration = Ext.decode(this.getSelection().get(this.configurationField), true); + } else { + configuration = this.getSelection().get(this.configurationField); + } + this.fireEvent("selectPreset", configuration); + }, + /** + * Event handler to ask the user for the preset name, then calls onPresetNameEntered. + */ + onSavePreset: function () + { + var presetName; + + if (this.getSelectedRecord() !== null) { + presetName = this.getSelectedRecord().get(this.nameField); + } else { + presetName = "New Preset"; + } + + Ext.Msg.prompt(i18n("Save Preset"), i18n("Preset Name"), this.onPresetNameEntered, this, false, presetName); + }, + /** + * Event handler to save the preset. Checks if a valid name was given, then calls savePreset on success. + * + * @param {String} buttonId The button ID which was clicked + * @param {String} value The preset name + */ + onPresetNameEntered: function (buttonId, value) + { + if (buttonId === "ok") { + if (this.getStore().find(this.nameField, value) === -1) { + this.savePreset(value); + } else { + Ext.Msg.alert(i18n("Save Preset"), i18n("The selected name is already in use"), this.onSavePreset, + this); + } + } + }, + /** + * Saves a preset with a given name + * @param {String} presetName The preset name + */ + savePreset: function (presetName) + { + var presetRecord = this.getSelectedRecord(); + + if (presetRecord === null) { + presetRecord = Ext.create(this.model); + } else { + if (presetName != presetRecord.get(this.nameField)) { + presetRecord = Ext.create(this.model); + } + } + + if (this.serializeConfiguration) { + presetRecord.set(this.configurationField, Ext.encode(this.configuration)); + } else { + presetRecord.set(this.configurationField, this.configuration); + } + presetRecord.set(this.nameField, presetName); + + var additionalField; + + for (var i = 0; i < this.additionalFields.length; i++) { + additionalField = this.additionalFields[i]; + + presetRecord.set(additionalField.fieldName, additionalField.value); + } + + presetRecord.save({ + success: this.onAfterSave, + scope: this + }); + + }, + /** + * Handler to reload the store and select the newly added preset + * @param {Ext.data.Model} presetRecord The preset to select + */ + onAfterSave: function (presetRecord) + { + this.getStore().reload({ + scope: this, + callback: function () + { + this.select(presetRecord); + } + }); + }, + /** + * Handler to confirm deletion. Calls deletePreset + */ + onDeletePreset: function () + { + Ext.Msg.confirm( + i18n("Confirm preset deletion"), + i18n("Are you sure to delete the preset?"), + this.deletePreset, + this); + }, + /** + * Deletes the currently selected preset if the yes button was clicked + * @param {String} buttonId The selected button + */ + deletePreset: function (buttonId) + { + if (buttonId === "yes") { + var presetRecord = this.getSelectedRecord(); + presetRecord.erase(); + this.setSelection(null); + this.setValue(null); + this.fireEvent("selectPreset", this.blankConfiguration); + } + }, + /** + * Creates a blank preset. Sets the selection to null and fires + * selectPreset with blankConfiguration. + */ + onAddPreset: function () + { + this.setSelection(null); + this.setValue(null); + this.fireEvent("selectPreset", this.blankConfiguration); + }, + /** + * Sets the configuration for the preset + */ + setConfiguration: function (configuration) + { + this.configuration = configuration; + }, + /** + * Sets the additional fields to use when creating or saving a record + */ + setAdditionalFields: function (additionalFields) + { + this.additionalFields = additionalFields; + }, + /** + * Handler to show/hide the delete button + */ + onSelectionChange: function () + { + if (this.getSelectedRecord() !== null) { + this.triggers.delete.show(); + } else { + this.triggers.delete.hide(); + } + } + + +}); diff --git a/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig b/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig @@ -80,6 +80,7 @@ '@PartKeeprFrontendBundle/Resources/public/js/Util/i18n.js' '@PartKeeprFrontendBundle/Resources/public/js/Components/Widgets/EntityQueryPanel.js' '@PartKeeprFrontendBundle/Resources/public/js/Components/Widgets/EntityPicker.js' + '@PartKeeprFrontendBundle/Resources/public/js/Components/Widgets/PresetComboBox.js' '@PartKeeprFrontendBundle/Resources/public/js/Components/Exporter/GridExporter.js' '@PartKeeprFrontendBundle/Resources/public/js/Components/Exporter/GridExporterButton.js' '@PartKeeprFrontendBundle/Resources/public/js/Components/Importer/GridImporterButton.js' diff --git a/src/PartKeepr/ImportBundle/Entity/ImportPreset.php b/src/PartKeepr/ImportBundle/Entity/ImportPreset.php @@ -8,7 +8,8 @@ use PartKeepr\DoctrineReflectionBundle\Annotation\TargetService; use Symfony\Component\Serializer\Annotation\Groups; /** - * @ORM\Entity + * @ORM\Table(uniqueConstraints={@ORM\UniqueConstraint(name="name_entity_unique", columns={"baseEntity", "name"})}) + * @ORM\Entity() * @TargetService(uri="/api/import_presets") */ class ImportPreset extends BaseEntity