diff --git a/components/FormRelation.vue b/components/FormRelation.vue index 582afb10..c4beaf0f 100644 --- a/components/FormRelation.vue +++ b/components/FormRelation.vue @@ -396,7 +396,7 @@ const is_vector = (external || layer.isGeoLayer()) this.runAddRelationWorkflow({ workflow: is_vector - ? new this._add_link_workflow.selectandcopy({ + ? this._add_link_workflow.selectandcopy({ copyLayer: layer, isVector: true, help: 'editing.steps.help.copy', @@ -421,7 +421,7 @@ */ addVectorRelation() { this.runAddRelationWorkflow({ - workflow: new this._add_link_workflow.add(), + workflow: this._add_link_workflow.add(), isVector: Layer.LayerTypes.VECTOR === this._layerType, }); this.show_vector_tools = false; @@ -473,7 +473,7 @@ this.resize(); } else { this.runAddRelationWorkflow({ - workflow: new this._add_link_workflow.add(), + workflow: this._add_link_workflow.add(), isVector: Layer.LayerTypes.VECTOR === this._layerType, }); } @@ -572,14 +572,14 @@ * * @since g3w-client-plugin-editing@v3.7.4 */ - onCommit({ new_relations = {} }) { + onCommit({ relations = {} }) { const relationLayer = getEditingLayerById(this.relation.child); // there is a new relation saved on server - if (new_relations[relationLayer.getId()] && Array.isArray(new_relations[relationLayer.getId()].new)) { + if (relations[relationLayer.getId()] && Array.isArray(relations[relationLayer.getId()].new)) { this._new_relations_ids = [ ...(this._new_relations_ids || []), - ...new_relations[relationLayer.getId()].new.map(({ clientid, id }) => ({ clientid, id })) + ...relations[relationLayer.getId()].new.map(({ clientid, id }) => ({ clientid, id })) ] } }, @@ -906,11 +906,10 @@ await promise; } catch (e) { console.trace('START TOOL FAILED', e); - return Promise.reject(e); } finally { relationtool.state.active = false; } - } catch (e) { + } catch(e) { console.warn(e); } }, @@ -1029,7 +1028,7 @@ this.disabled = true; const is_vector = Layer.LayerTypes.VECTOR === this._layerType; - const workflow = new this._add_link_workflow.link( is_vector ? { + const workflow = this._add_link_workflow.link( is_vector ? { selectStyle: SELECTED_STYLES[this.getLayer().getGeometryType()] } : {}); const options = this._createWorkflowOptions(); diff --git a/components/Toolbox.vue b/components/Toolbox.vue index 5e1fd24b..2f1441e9 100644 --- a/components/Toolbox.vue +++ b/components/Toolbox.vue @@ -98,7 +98,7 @@ diff --git a/components/UserMessage.vue b/components/UserMessage.vue index 65c8e88f..ef14f92c 100644 --- a/components/UserMessage.vue +++ b/components/UserMessage.vue @@ -24,6 +24,7 @@ diff --git a/deprecated.js b/deprecated.js index 8d47e8f9..21bc13c0 100644 --- a/deprecated.js +++ b/deprecated.js @@ -1,93 +1,97 @@ import { promisify } from '../../utils/promisify'; +class Queque { + constructor() { this.tasks = []; } + addTask(task) { this.tasks.push(task); } + run(reverse = false) { while (this.tasks.length) { const task = reverse ? this.tasks.pop() : this.tasks.shift(); task(); } } + flush() { return this.tasks.splice(0); } + getLength() { return this.tasks.length; } + clear() { this.run(); this.tasks = []; } +} + + /** * Class Flow of workflow step by step * * ORIGINAL SOURCE: g3w-client/src/core/workflow/flow.js@v3.9.1 * ORIGINAL SOURCE: g3w-client/src/core/workflow/queque.js@v3.9.1 */ -export function Flow() { - console.warn('[G3W-CLIENT] g3wsdk.core.workflow.Flow is deprecated'); - - class Queque { - constructor() { this.tasks = []; } - addTask(task) { this.tasks.push(task); } - run(reverse = false) { while (this.tasks.length) { const task = reverse ? this.tasks.pop() : this.tasks.shift(); task(); } } - flush() { return this.tasks.splice(0); } - getLength() { return this.tasks.length; } - clear() { this.run(); this.tasks = []; } +export class Flow extends g3wsdk.core.G3WObject { + constructor() { + super(); + console.warn('[G3W-CLIENT] g3wsdk.core.workflow.Flow is deprecated'); + this.steps = []; + this.counter = 0; + this.context = null; + this.queques = { + end: new Queque(), + micro: new Queque() + }; + this.inputs; + this.d; + this._workflow; } - let steps = []; - let inputs; - let counter = 0; - let context = null; - let d; - let _workflow; - this.queques = { - end: new Queque(), - micro: new Queque() - }; //start workflow - this.start = function(workflow) { - d = $.Deferred(); - if (counter > 0) { + start(workflow) { + this.d = $.Deferred(); + if (this.counter > 0) { console.log("reset workflow before restarting"); } - _workflow = workflow; - inputs = workflow.getInputs(); - context = workflow.getContext(); - steps = workflow.getSteps(); + this._workflow = workflow; + this.inputs = workflow.getInputs(); + this.context = workflow.getContext(); + this.steps = workflow.getSteps(); // check if there are steps - if (steps && steps.length) { + if (this.steps && this.steps.length) { //run step (first) - this.runStep(steps[0], inputs, context); + this.runStep(this.steps[0], this.inputs, this.context); } // return a promise that will be reolved if all step go right - return d.promise(); + return this.d.promise(); }; //run step - this.runStep = function(step, inputs) { + runStep(step, inputs) { //run step that run task - _workflow.setMessages({ + this._workflow.setMessages({ help: step.state.help }); const runMicroTasks = this.queques.micro.getLength(); - step.run(inputs, context, this.queques) + step.run(inputs, this.context, this.queques) .then(outputs => { runMicroTasks && this.queques.micro.run(); this.onDone(outputs); }) - .fail(error => this.onError(error)); + .fail(e => this.onError(e)); }; //check if all step are resolved - this.onDone = function(outputs) { - counter++; - if (counter === steps.length) { - counter = 0; - d.resolve(outputs); + onDone(outputs) { + this.counter++; + if (this.counter === this.steps.length) { + this.counter = 0; + this.d.resolve(outputs); return; } - this.runStep(steps[counter], outputs); + this.runStep(this.steps[this.counter], outputs); }; // in case of error - this.onError = function(err) { - counter = 0; + onError(e) { + this.counter = 0; this.clearQueques(); - d.reject(err); + this.d.reject(e); }; // stop flow - this.stop = function() { + stop() { const d = $.Deferred(); - steps[counter].isRunning() ? steps[counter].stop() : null; + this.steps[counter].isRunning() ? this.steps[this.counter].stop() : null; this.clearQueques(); - if (counter > 0) { + if (this.counter > 0) { // set counter to 0 - counter = 0; + this.counter = 0; // reject flow d.reject(); } else { @@ -97,15 +101,13 @@ export function Flow() { return d.promise(); }; - this.clearQueques = function(){ + clearQueques(){ this.queques.micro.clear(); this.queques.end.clear(); } - g3wsdk.core.utils.base(this) } -g3wsdk.core.utils.inherit(Flow, g3wsdk.core.G3WObject); /** * ORIGINAL SOURCE: g3w-client/src/services/editing.js@v3.9.1 @@ -812,15 +814,15 @@ export class Session extends g3wsdk.core.G3WObject { return; } - const { new_relations = {} } = response.response; // check if new relations are saved on server + const { relations = {} } = response.response; // check if new relations are saved on server // sync server data with local data - for (const id in new_relations) { + for (const id in relations) { Session.Registry .getSession(id) // get session of relation by id .getEditor() .applyCommitResponse({ // apply commit response to current editing relation layer - response: new_relations[id], + response: relations[id], result: true }); } diff --git a/g3wsdk/editing/editor.js b/g3wsdk/editing/editor.js index af687128..a0f2cd07 100644 --- a/g3wsdk/editing/editor.js +++ b/g3wsdk/editing/editor.js @@ -8,6 +8,8 @@ import { ToolBox } from '../../toolboxes/toolbox'; import { promisify, $promisify } from '../../utils/promisify'; +import { getRelationsInEditing } from "../../utils/getRelationsInEditing"; +import {getRelationId} from "editing/utils/getRelationId"; const { ApplicationState, G3WObject } = g3wsdk.core; const { FeaturesStore } = g3wsdk.core.layer.features; @@ -320,7 +322,7 @@ export default class Editor extends G3WObject { // properties - properties of feature returned by server response.response.new.forEach(({ clientid, id, properties } = {}) => { //get feature from current layer in editing - const feature = this._featuresstore.getFeatureById(clientid); + const feature = this.getEditingSource().getFeatureById(clientid); // set new id feature.setId(id); //set properties @@ -346,6 +348,33 @@ export default class Editor extends G3WObject { }); + //@since 3.9.0 take in account update properties returned by server (Useful in case of media input changes) + (response.response.update || []).forEach(({ id, properties } = {}) => { + //get feature from current layer in editing + const feature = this.getEditingSource().getFeatureById(id); + //set properties + feature.setProperties(properties); + //Loop on eventual relation updated or created + relations.forEach(r => { // handle relations (if provided) + Object + .entries(r) + .forEach(([ id, opts = {}]) => { // id - relation layer id, opts - Object contain relation properties + //get the editing source of relation layer + const source = ToolBox.get(id).getSession().getEditor().getEditingSource(); + // handle value to relation field saved on server + (opts.ids || []).forEach(id => { + const rFeature = source.getFeatureById(id); + if (rFeature) { + opts.fatherField.forEach((ff, i) => {// loop relation ids + rFeature.set(opts.childField[i], feature.get(ff)) // set father feature `value` and `name` + }) + } + }) + }); + }); + + }); + const features = this.readEditingFeatures(); features.forEach(f => f.clearState()); // reset state of the editing features (update, new etc..) @@ -439,10 +468,10 @@ export default class Editor extends G3WObject { */ stop() { return $promisify(async () => { - const response = await promisify(this._layer.unlock()); + const { result } = await promisify(this._layer.unlock()); this.clear(); - return response; - }); + return result; + }) } /** diff --git a/g3wsdk/workflow/workflow.js b/g3wsdk/workflow/workflow.js index 32e5a525..bd4a9c21 100644 --- a/g3wsdk/workflow/workflow.js +++ b/g3wsdk/workflow/workflow.js @@ -368,10 +368,10 @@ export class Workflow extends G3WObject { if (showUserMessage) { GUI.showUserMessage({ - title: 'plugins.editing.workflow.title.steps', - type: 'tool', + title: 'plugins.editing.workflow.title.steps', + type: 'tool', position: 'left', - size: 'small', + size: 'small', closable: false, hooks: { body: { diff --git a/i18n/de.js b/i18n/de.js index de265b8d..d7ad6480 100644 --- a/i18n/de.js +++ b/i18n/de.js @@ -42,6 +42,7 @@ export default { update_feature: "Feature-Attribut aktualisieren", update_multi_features: "Attribute ausgewählter Features aktualisieren", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Bearbeiten Sie Beziehungsdatensätze von einem oder mehreren übergeordneten features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/en.js b/i18n/en.js index 2b72cc7b..5f5a6cae 100644 --- a/i18n/en.js +++ b/i18n/en.js @@ -44,6 +44,7 @@ export default { update_feature: "Update feature attribute", update_multi_features: "Update attributes of selected features", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Edit relations records from one or mode parent features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/fi.js b/i18n/fi.js index f1fd6af5..486a5126 100644 --- a/i18n/fi.js +++ b/i18n/fi.js @@ -42,6 +42,7 @@ export default { update_feature: "Päivitä ominaisuus", update_multi_features: "Muokkaa valittujen ominaisuuksien attribuutteja", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Edit relations records from one or mode parent features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/fr.js b/i18n/fr.js index e495c1e9..4990dbd3 100644 --- a/i18n/fr.js +++ b/i18n/fr.js @@ -42,6 +42,7 @@ export default { update_feature: "Modifier les attributs des fonctionnalités", update_multi_features: "Modifier les attributs des fonctionnalités sélectionnées", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Modifier les enregistrements de relation à partir d'une ou plusieurs entités parents", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/it.js b/i18n/it.js index 9bffae24..6681e9fe 100644 --- a/i18n/it.js +++ b/i18n/it.js @@ -44,6 +44,7 @@ export default { update_feature: "Modifica attributi elemento", update_multi_features: "Modifica gli attributi degli elementi selezionati", update_multi_features_relations: "Modifica gli attributi di tutte le relazioni selezionate", + update_multi_features_relations_from_parents : "Edita i record relazionati di uno o più padri", copyfeaturefromexternallayer: "Crea elemento da un livello esterno" }, toolsoftool: { diff --git a/i18n/pl.js b/i18n/pl.js index 65f2b92c..e61416b0 100644 --- a/i18n/pl.js +++ b/i18n/pl.js @@ -39,6 +39,7 @@ export default { update_feature: "Update feature attribute", update_multi_features: "Update attributes of selected features", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Edit relations records from one or mode parent features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/ro.js b/i18n/ro.js index 5a2a092d..3555cc26 100644 --- a/i18n/ro.js +++ b/i18n/ro.js @@ -42,6 +42,7 @@ export default { update_feature: "Actualizează atributul entității", update_multi_features: "Actualizează atributele entităților selectate", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Editați înregistrările relațiilor de la una sau mai multe caracteristici părinte", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/i18n/se.js b/i18n/se.js index 43b60a11..48663441 100644 --- a/i18n/se.js +++ b/i18n/se.js @@ -42,6 +42,7 @@ export default { update_feature: "Uppdatera egenskap", update_multi_features: "Ändra attributen för de valda funktionerna", update_multi_features_relations: "Update attributes of all selected relations", + update_multi_features_relations_from_parents : "Edit relations records from one or mode parent features", copyfeaturefromexternallayer: "Create Feature from added layer" }, toolsoftool: { diff --git a/icons/EditMultiRelationFeatures.png b/icons/EditMultiRelationFeatures.png new file mode 100644 index 00000000..d521c4ab Binary files /dev/null and b/icons/EditMultiRelationFeatures.png differ diff --git a/toolboxes/toolbox.js b/toolboxes/toolbox.js index b2fba5b1..847751a3 100644 --- a/toolboxes/toolbox.js +++ b/toolboxes/toolbox.js @@ -80,15 +80,21 @@ export class ToolBox extends G3WObject { constructor(layer, dependencies = []) { super(); - const is_vector = [undefined, Layer.LayerTypes.VECTOR].includes(layer.getType()); - const geometryType = is_vector && layer.getGeometryType(); - const is_point = is_vector && Geometry.isPointGeometryType(geometryType); - const is_line = is_vector && Geometry.isLineGeometryType(geometryType); - const is_poly = is_vector && Geometry.isPolygonGeometryType(geometryType); - const is_table = Layer.LayerTypes.TABLE === layer.getType(); - const isMultiGeometry = geometryType && Geometry.isMultiGeometry(geometryType); - const iconGeometry = is_vector && (is_point ? 'Point' : is_line ? 'Line' : 'Polygon'); - + const is_vector = [undefined, Layer.LayerTypes.VECTOR].includes(layer.getType()); + const geometryType = is_vector && layer.getGeometryType(); + const is_point = is_vector && Geometry.isPointGeometryType(geometryType); + const is_line = is_vector && Geometry.isLineGeometryType(geometryType); + const is_poly = is_vector && Geometry.isPolygonGeometryType(geometryType); + const is_table = Layer.LayerTypes.TABLE === layer.getType(); + const isMultiGeometry = geometryType && Geometry.isMultiGeometry(geometryType); + const iconGeometry = is_vector && (is_point ? 'Point' : is_line ? 'Line' : 'Polygon'); + //@since 3.9.0 Check if layer has relation layers editable + const editable_relations = layer.getRelations().getArray() + .filter(relation => { + const l = CatalogLayersStoresRegistry.getLayerById(getRelationId({ layerId: layer.getId(), relation })); + return l.isEditable(); + }) + .map(r => r); this._start = false; /** constraint loading features to a filter set */ @@ -103,7 +109,7 @@ export class ToolBox extends G3WObject { * _states: [ * { * id: unique key - * state: [state] // example: history contsins features state + * state: [state] // example: history contains features state * // array because a tool can apply changes to more than one features at time (split di una feature) * }, * { @@ -396,11 +402,12 @@ export class ToolBox extends G3WObject { description: `editing.workflow.steps.${ApplicationState.ismobile ? 'selectDrawBoxAtLeast2Feature' : 'selectMultiPointSHIFTAtLeast2Feature'}`, buttonnext: { disabled: true, - condition:({ features=[] }) => features.length < 2, - done: () => { Workflow.Stack.getCurrent().clearUserMessagesSteps(); } + condition:({ features = [] }) => features.length < 2, + done: () => { Workflow.Stack.getCurrent().clearUserMessagesSteps(); }, }, dynamic: 0, - done: false + done: false, + reset() { this.dynamic = 0; }, } } }), @@ -408,6 +415,160 @@ export class ToolBox extends G3WObject { ], }), }, + // @since 3.9.0 Edit Attributes of relations features to Multi features + (is_vector) && capabilities.includes('change_attr_feature') && editable_relations.filter(r => 'ONE' !== r.getType()).length > 0 && { + id: 'editmultiattributesrelationfeatures', + type: ['change_attr_feature'], + name: "editing.tools.update_multi_features_relations_from_parents", + icon: "EditMultiRelationFeatures.png", + /** ORIGINAL SOURCE: g3w-client-plugin-editing/workflows/editmultifeatureattributesworkflow.js@v3.7.1 */ + op: new Workflow({ + layer, + type: 'editmultiattributesrelationfeatures', + helpMessage: 'editing.tools.update_multi_features_relations_from_parents', + registerEscKeyEvent: true, + runOnce: true, + steps: [ + new SelectElementsStep({ + type: 'multiple', + steps: { + select: { + description: `editing.workflow.steps.${ApplicationState.ismobile ? 'selectDrawBoxAtLeast2Feature' : 'selectMultiPointSHIFTAtLeast2Feature'}`, + buttonnext: { + disabled: true, + condition: ({ features = [] }) => features.length < 2, + done: () => { Workflow.Stack.getCurrent().clearUserMessagesSteps(); } + }, + dynamic: 0, + done: false, + reset() { this.dynamic = 0; }, + } + } + }), + new Step({ + run: async (inputs, context) => { + GUI.setModal(true); + const relations = editable_relations.filter(r => 'ONE' !== r.getType()); + //get relation features from feature parent layer + await Promise.allSettled(inputs.features.map(feature => getLayersDependencyFeatures(inputs.layer.getId(), { + relations, + feature, + filterType: 'fid', + }))) + //get first relation layer id + let relationLayerId = relations[0].getChild(); + + //In case of multi relation in editing + if (relations.length > 1) { + //ser relation layer id + try { + await new Promise((resolve, reject) => { + const vueInstance = new (Vue.extend({ + name: 'multi-relations-fetures', + template: `