Générer un diagramme / modèle métier par code côté front avec des objets sélectionnés par l'utilisateur

Tags: #<Tag:0x00007fe2962d7cf8>

Bonjour,

Est-il possible d’avoir un exemple de code qui ajoute automatiquement des objets liés à d’autre objets par un relation 1-N ou N-N sur un modeler en fonction d’une liste d’objets sélectionnés.
Sans prendre en compte le placement de ces objets.

Je vous remercie

Jamais fait, mais ça doit pouvoir se faire.

  • Au plus bas niveau un modèle est un SVG donc XML manipulable avec tous les utilitaires XML en back si on connait la sémantique du modèle (à mon avis peu maintenable).
  • Au plus haut niveau front, on doit pouvoir utiliser les APIs du contrôleur du modeleur Simplicite.Diagram.Modeler mais ils n’ont pas forcement été conçus pour être un CLI javascript = public ou silencieux, on a besoin d’un context graphique pour dessiner/mesurer, il se peut qu’il y ait des popups de confirmation ou de choix d’options, etc.

Pour créer un modèle à la volée par code en front, il faut essayer de faire comme suit :

  • créer un modèle comme n’importe quel objet métier via la couche Ajax, objet Model méthode create
  • utiliser le controlleur Simplicite.Diagram.Modeler
    • open = instancier / ouvrir le modèle (dans un div caché ?)
    • insertNode = ajouter des éléments
    • fetchRelatedNodes = insérer les objets connexes (links) à un élément
    • save / close

C’est l’occasion de le faire évoluer car ce besoin revient souvent (Renault, Amadeus, …)

1 Like

Après quelques ajustements pour rendre le modeleur invisible en V4, voici comment créer un modèle métier et y insérer des objets via JavaScript sans interaction utilisateur :

L’exemple utilise le template DemoModel de la démo :

  • Créer une action de liste sur DemoProduct de type Front avec le code suivant :
    javascript:demoNewModel(obj);

  • Coder dans le SCRIPT front de l’objet :

function demoNewModel(obj) {
	var app = $ui.getAjax(),
		diagram, modelId,
		mt = app.getBusinessObject("ModelTemplate", "tmp_ajax_ModelTemplate"),
		mod = app.getBusinessObject("Model", "tmp_ajax_Model"),
		ids = obj.selectedIds;

	// Needs objects to insert
	if (!ids || !ids.length) {
		$ui.alert("no selection");
		return;
	}
	
	// Search the model template
	function getTemplate() {
		mt.search(function(list) {
			if (list && list.length>0)
				createModel(list[0]);
			else
				$ui.alert("no template");
		},{
			mtp_name: "DemoModel"
		});
	}
	// Create a new empty model
	function createModel(tpl) {
		mod.create(load, {
			row_id: "0",
			mod_name: 'Product-' + (new Date()).getTime(),
			mod_template_id: tpl.row_id
		});
	}
	function load() {
		modelId = mod.item.row_id;
		// Load SVG engine
		$ui.loadDiagramEngine(true, function() {
			// Load empty SVG file in object
			mod.get(function() {
				// instanciate in silent mode
				$ui.diagram.open(modelId, { svg:true, hidden:true }, build);
			}, modelId, {
				inlineDocs: true
			});
		});
	}
	// Insert objects in diagram
	function build(d) {
		diagram = d;
		var list = [];
		$(ids).each(function(i,id) {
			list.push({
				object: "DemoProduct", // node object
				id: id, // node row_id
				template: "DemoModel_Product", // node template name
				x: i*30 + 30, // dummy position
				y: i*70 + 30,
				container: null // no container
			});
		});
		// async loading with up-to-date data
		diagram.insertNodes(list, function(nodes) {
			// auto load sibling nodes thru links
			diagram.fetchRelatedNodes(nodes, save);
		});
	}
	function save() {
		diagram.save(function() {
			// Close hidden model
			diagram.close(false);
			// Re-open in a window
			$ui.displayModeler(null, modelId, { svg:true, docked:false });
		}, true); // silent
	}
	getTemplate();
}
  • Ensuite il suffit de sélectionner des produits et de cliquer sur l’action pour :
    • construire un nouveau model
      • lui insérer les objets séléctionnés
      • puis ajouter les objets relatifs (les commandes + clients) liés aux produits insérés
      • Enregistrer et fermer le model
    • réouvrir le model créé dans une fenêtre.

Attention tous les traitements sont asynchrones, donc il est important de bien chainer les callbacks de chaque méthode.

Un helper $ui.diagram.create a été ajouté pour simplifier la création en front, dans l’exemple cela donne :

function demoNewModel(obj) {
	var ids = obj.selectedIds, list = [];
	// Needs objects to insert
	if (!ids || !ids.length) {
		$ui.alert("no selection");
		return;
	}
	$(ids).each(function(i,id) {
		list.push({
			object: "DemoProduct", // node object
			id: id, // node row_id
			template: "DemoModel_Product", // node template name
			x: i*50 + 30, // dummy position
			y: i*30 + 30,
			container: null // no container
		});
	});
	
	// Load SVG engine
	$ui.loadDiagramEngine(true, function() {
		try {
			// Create the model in silent mode
			var name = "Product-" + (new Date()).getTime();
			$ui.diagram.create("DemoModel", name, {
				hidden: true, // hide the modeler
				nodes: list,  // nodes to insert
				fetch: true   // then fetch related orders and customers
			},
			function(diagram) {
				// close the hidden model
				diagram.close(false);
				// Re-open in a window
				$ui.displayModeler(null, diagram.modelId, {
					svg: true,
					docked: false
				});
			});
		}
		catch(e) {
			console.log(e);
		}
	});
}

Cool !
@bmo je pense que ça peut t’intéresser aussi

1 Like

Merci David (et François), j’avais déjà épinglé le post de la semaine dernière =)
J’ai un ticket sur la R5 de notre module GDPR qui porte sur la génération automatique du diagramme de flux des données et acteurs documentés sur les traitements de données personnelles… quelques devoirs de vacances en perspective.

Pour avoir déjà jardiné sur les platebandes du dummy position (coordonnées, calcul d’intersections, smart layout), je sais déjà que c’est là que sera l’os ! … J’ai hâte ;)

@bmo oui chaque chose en son temps…

En V5, il reste pas mal de boulot sur le positionnement 2D des modèles SVG.

  • il faut ré-intégrer les layouts classiques en arbre ou en étoile qui avaient été faits en canvas
  • je travaille actuellement sur un positionnement 2D automatique, un algo NP-complet en javascripts de “remplissage de sac-à-dos”, c’est un enfer… par contre un algo à base de physique des “ressorts” me semble plus efficace pour dessiner des modèles d’objets (entités/relations)

Ce projet est assez inspirant : http://getspringy.com/
je vais essayer de l’intégrer rapidement car ça me chatouille aussi depuis longtemps.