/* Hyrrokkin - A visual modelling tool for constructing directed graphs.
Copyright (C) 2022-2026 Visual Topology Ltd
Licensed under the MIT License
*/
var hyrrokkin = hyrrokkin || {};
hyrrokkin.DesignerSystem = class extends hyrrokkin.SystemBase {
/**
* Create a hyrrokkin graphical editor
*/
constructor() {
super();
this.design = null;
this.container = null;
this.header = null;
this.canvas = null;
this.topology_id = null;
this.workspace_id = null;
this.splash_screen = null;
this.restart_alert = null;
this.model = null;
}
/**
* Initialise hyrrokkin graphical editor
*
* @param {string} element_id - the name of the document element into which hyrrokkin will be loaded
* @param {Object} options - various options to customise hyrrokkin
* @param {Object} model - class instance implementing the hyrrokkin.ModelBase API
*/
async init(element_id, options, model) {
this.min_window_width = options["min_window_width"] || 800;
this.min_window_height = options["min_window_height"] || 600;
let splash_options = options["designer_splash"];
this.splash_screen = null;
if (splash_options) {
this.splash_screen = new hyrrokkin.Alert("Loading...", splash_options);
}
this.canvas_width = options.canvas_width || hyrrokkin.SystemBase.DEFAULT_CANVAS_WIDTH;
this.canvas_height = options.canvas_height || hyrrokkin.SystemBase.DEFAULT_CANVAS_HEIGHT;
this.workspace_id = options.workspace_id;
this.topology_id = options.topology_id;
// l10n
let l10n_utils = await this.load_l10n();
this.model = model;
this.container = hyrrokkin.$$$(element_id);
this.header = this.container.append("div").attr("class", "hyrrokkin_header");
if (options.designer_title) {
this.header.append("h4").attr("class", "hyrrokkin_header_title").text(options.designer_title);
this.header.append("span").attr("class", "hyrrokkin_header_text").text(this.workspace_id + "/" + this.topology_id);
}
let right_div = this.header.append("div")
.attr("class", "hyrrokkin_header_right")
if (options.directory_url) {
right_div.append("a").text(l10n_utils.localise("directory.open")).attr("href", options.directory_url).attr("class", "hyrrokkin_header_link").attr("target","_self");
}
right_div.append("img").attr("src", options.icon_url || "hyrrokkin-ui/images/hyrrokkin-ui.svg").attr("class", "hyrrokkin_header_icon");
this.canvas = this.container.append("div");
let schema = await this.load_schema(options.package_urls);
let core = new hyrrokkin.Core(this.workspace_id, this.topology_id, l10n_utils, schema, model, options.platform_extensions);
this.set_core(core);
let config_status_event_handler = this.core.add_configuration_status_event_handler((package_id, details) => {
this.splash_screen.update_message(schema.get_package_type(package_id).localise(details["status_message"]));
});
await this.open_design();
await this.model.bind(this);
await this.model.load();
await core.init();
if (this.splash_screen) {
setTimeout(() => {
this.splash_screen.close();
this.splash_screen = null;
this.core.remove_configuration_event_handler(config_status_event_handler);
this.add_window_size_alerts();
}, 1000);
} else {
this.add_window_size_alerts();
}
}
async open_design() {
this.canvas.html("");
this.canvas.attr("class","hyrrokkin_design_container");
this.container.style("overflow","hidden");
this.design = new hyrrokkin.Design(this.core, this.canvas, this.canvas_width, this.canvas_height);
}
get_id() {
return this.topology_id;
}
get_workspace_id() {
return this.workspace_id;
}
add_window_size_alerts() {
if (this.min_window_width && this.min_window_height) {
this.design.add_window_size_alerts(this.min_window_width, this.min_window_height);
}
}
is_empty() {
return (this.get_nodes().length === 0);
}
get_nodes() {
return this.design.get_network().get_node_list();
}
get_package_ids_used_by_nodes() {
return this.design.get_network().get_package_ids_used_by_nodes();
}
node_added(node_id, node_type_name, metadata, copy_from_node_id) {
let node_type = this.design.get_schema().get_node_type(node_type_name);
this.design.node_added(node_id, node_type, metadata, copy_from_node_id);
}
node_removed(node_id) {
this.design.node_removed(node_id);
}
node_metadata_updated(node_id, metadata) {
this.design.node_metadata_updated(node_id, metadata);
}
get_upstream_nodes(node_id) {
return this.design.get_network().get_upstream_nodes(node_id);
}
get_downstream_nodes(node_id) {
return this.design.get_network().get_downstream_nodes(node_id);
}
design_metadata_updated(metadata) {
this.design.design_metadata_updated(metadata);
}
link_added(link_id, link_type, from_node_id, from_port_name, to_node_id, to_port_name) {
let from_node = this.design.get_node(from_node_id);
let from_port = from_node.get_ports()[from_port_name];
let to_node = this.design.get_node(to_node_id);
let to_port = to_node.get_ports()[to_port_name];
this.design.link_added(from_port, to_port, link_type, link_id);
}
link_removed(link_id) {
this.design.link_removed(link_id);
}
get_packages() {
return this.design.get_schema().get_package_types();
}
remove_node(node_id) {
this.design.node_removed(node_id);
}
remove_link(link_id) {
this.design.link_removed(link_id);
}
node_blocked(node_id, is_blocked) {
this.design.node_blocked(node_id, is_blocked);
}
clear() {
this.design.clear();
}
close() {
}
note_paused() {
super.note_paused();
this.design.note_paused();
}
note_resumed() {
super.note_resumed();
this.design.note_resumed();
}
note_restarting() {
this.design.close_all_node_windows();
}
note_restarted() {
this.design.note_restarted();
}
}