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:
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