Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code Multiplexer Component #89

Open
ColtonMcInroy opened this issue Feb 6, 2023 · 4 comments
Open

Code Multiplexer Component #89

ColtonMcInroy opened this issue Feb 6, 2023 · 4 comments

Comments

@ColtonMcInroy
Copy link

ColtonMcInroy commented Feb 6, 2023

One thing I ran into was wanting to be able to use a single code component to handle multiple inputs and outputs. This would allow for a smaller footprint when designing flows and prevent duplication of code components.

I do not have the component fully fleshed out yet, missing the readme, and because I built this before the fix for #82 still suffers the initial issue. I think this would be a great component to add, or possibly even replace current code component.

<script total>

	exports.name = 'Multiplexer';
	exports.icon = 'fa fa-exchange-alt';
	exports.author = 'Colton McInroy';
	exports.version = '1';
	exports.group = 'Common';
	exports.config = { name: 'Label', inputs: [{ id: 'input', name: 'Input' }], outputs: [{ id: 'output', name: 'Output' }], code: '// instance {FlowStreamInstance};\n// $ {FlowStreamMessage};\n// vars {Object};\n// repo {Object};\n// data {String/Number/Boolean/Date/Buffer/Object};\n// $.send(\'output\', data); // or simply send(data); which uses the first output\n// $.destroy();\n// $.throw(err);\n\n// IMPORTANT: If you do not perform re-send, you need to destroy this message via $.destroy() method\n// IMPORTANT: methods $.send(), $.destroy() and $.throw() can be executed only once\n\n// $.send(\'output\', data);\n// $.destroy();\nif ($.input === \'input\') {\n	$.send(\'output\', data);\n	return;\n}' };
	exports.inputs = [{ id: 'input', name: 'Input' }];
	exports.outputs = [{ id: 'output', name: 'Output' }];

	// exports.npm = ['npm_module_1', 'npm_module_2@version'];
	// exports.meta = { readonly: false, singleton: false, hidden: false };

	exports.make = function(instance, config) {
		let fn;
		// instance.main.variables {Object}
		// instance.main.variables2 {Object}
		// instance.save();
		// instance.replace(str); // replaces {variable_name} for values from "variables" and "variables2"
		// instance.status(obj, [refresh_delay_in_ms]);

		instance.message = function($) {
			// var data = $.data;
			// $.send('output', data);
			// or $.destroy();

			if (fn) {
				try {
					// var send = data => $.send('output', data);
					fn($.data, instance, $, $, F.require, $.send, $.repo, $.vars, $.data);
				} catch (e) {
					$.throw(e);
					$.destroy();
				}
			}
		};

		instance.configure = function() {
			if (!config.outputs.length || !config.inputs.length)
				return;

			// "config" is changed
			instance.inputs = [];
			instance.outputs = [];

			config.inputs.forEach((input, i) => {
				instance.inputs.push({ id: input.id || 'input' + (i + 1), name: input.name || 'Input #' + (i + 1) });
			});
			config.outputs.forEach((output, i) => {
				instance.outputs.push({ id: output.id || 'output' + (i + 1), name: output.name || 'Output #' + (i + 1) });
			});
			instance.save();

			try {
				if (config.code) {
					instance.status(1);
					fn = new Function('value', 'instance', '$', 'message', 'require', 'send', 'repo', 'vars', 'data', config.code);
				} else {
					instance.status(0);
					fn = null;
				}
			} catch (e) {
				fn = null;
				instance.throw('Code: ' + e.message);
			}
		};

		instance.close = function() {
			// this instance is closed
			fn = null;
		};

		instance.variables = function(variables) {
			// FlowStream variables are changed
		};

		instance.variables2 = function(variables) {
			// Global variables are changed
		};

		instance.configure();

	};

</script>

<readme>
Markdown readme

</readme>

<settings>
	<div class="padding">
		<div data---="input__?.name" class="m">Name</div>
		<section class="switch-inputs m">
			<label class="ui-input-label">Inputs</label>
			<div class="switch-thead">
				<div class="row">
					<div class="col-md-1">#</div>
					<div class="col-md-5">Input id</div>
					<div class="col-md-5">Input name</div>
					<div class="col-md-1">Action</div>
				</div>
			</div>
			<ui-bind path="?.inputs" config="template:.switch-input -> data-index" clas="block">
				<ui-component name="movable" path="?.inputs" config="selector:.dragme;exec:FUNC.switch_input_dragged">
					<script type="text/html">
						{{ foreach con in value }}
						<div class="switch-input dragme" data-index="{{ $index }}" draggable="true">
							<div class="row">
								<div class="col-md-1">
									{{ ($index + 1) }}.
								</div>
								<div class="col-md-5">
									<ui-component name="input" path="?.inputs[{{ $index }}].id"></ui-component>
								</div>
								<div class="col-md-5">
									<ui-component name="input" path="?.inputs[{{ $index }}].name"></ui-component>
								</div>
								<div class="col-md-1">
									<i class="ti ti-trash red exec" data-exec="FUNC.switch_remove_input"></i>
								</div>
							</div>
						</div>
						{{ end }}
					</script>
				</ui-component>
			</ui-bind>
			<div class="help m">Each input corresponds to an output index. First input --> First output, etc.</div>
			<button class="button-add exec" data-exec="FUNC.switch_add_input">ADD</button>
		</section>
		<section class="switch-outputs m">
			<label class="ui-input-label">Outputs</label>
			<div class="switch-thead">
				<div class="row">
					<div class="col-md-1">#</div>
					<div class="col-md-5">Output id</div>
					<div class="col-md-5">Output name</div>
					<div class="col-md-1">Action</div>
				</div>
			</div>
			<ui-bind path="?.outputs" config="template:.switch-output -> data-index" clas="block">
				<ui-component name="movable" path="?.outputs" config="selector:.dragme;exec:FUNC.switch_output_dragged">
					<script type="text/html">
						{{ foreach con in value }}
						<div class="switch-output dragme" data-index="{{ $index }}" draggable="true">
							<div class="row">
								<div class="col-md-1">
									{{ ($index + 1) }}.
								</div>
								<div class="col-md-5">
									<ui-component name="input" path="?.outputs[{{ $index }}].id"></ui-component>
								</div>
								<div class="col-md-5">
									<ui-component name="input" path="?.outputs[{{ $index }}].name"></ui-component>
								</div>
								<div class="col-md-1">
									<i class="ti ti-trash red exec" data-exec="FUNC.switch_remove_output"></i>
								</div>
							</div>
						</div>
						{{ end }}
					</script>
				</ui-component>
			</ui-bind>
			<div class="help m">Each output corresponds to an output index. First output --> First output, etc.</div>
			<button class="button-add exec" data-exec="FUNC.switch_add_output">ADD</button>
		</section>
		<button class="button exec" style="width: 200px;" data-exec="FUNC.switch_readme"><i class="ti ti-info-circle blue"></i>Show configuration info</button>
		<div class="ui-input-label">Code:</div>
		<ui-component name="codemirror" path="?.code" config="type:javascript;minheight:200;parent:auto;margin:60;tabs:true;trim:true" class="m"></ui-component>
	</div>
</settings>

<script>

	FUNC.switch_readme = function() {
		EXEC('flow/readme', flow.info.selected.component);
	};

	FUNC.switch_add_input = function(el) {
		var scope = el.scope();
		PUSH(scope.path + '.inputs', { operator: '==', type: 'string', value: '' });
	};

	FUNC.switch_remove_input = function(el) {
		var path = el.scope().path;
		var config = GET(path);
		var index = el.closest('.switch-input').attrd('index');
		config.inputs.splice(index, 1);
		SET(path, config);
		console.log(config);
	};

	FUNC.switch_input_dragged = function(list, dragged, target) {
		dragged = $(dragged);
		var dragged_index = dragged.attrd('index');
		var target_index = $(target).attrd('index');
		var path = dragged.scope().path;
		var config = GET(path);
		var dragged_item = config.inputs.splice(dragged_index, 1)[0];
		config.inputs.splice(target_index, 0, dragged_item);
		SET(path, config);
	};

	FUNC.switch_add_output = function(el) {
		var scope = el.scope();
		PUSH(scope.path + '.outputs', { });
	};

	FUNC.switch_remove_output = function(el) {
		var path = el.scope().path;
		var config = GET(path);
		var index = el.closest('.switch-output').attrd('index');
		config.outputs.splice(index, 1);
		SET(path, config);
		console.log(config);
	};

	FUNC.switch_output_dragged = function(list, dragged, target) {
		dragged = $(dragged);
		var dragged_index = dragged.attrd('index');
		var target_index = $(target).attrd('index');
		var path = dragged.scope().path;
		var config = GET(path);
		var dragged_item = config.outputs.splice(dragged_index, 1)[0];
		config.outputs.splice(target_index, 0, dragged_item);
		SET(path, config);
	};

	FUNC.switch_tooltip = function(el) {
		var opt = {};
		opt.element = el;
		var id = el.attrd('id');
		opt.html = REPO.switch_tooltips[id];

		SETTER('tooltip', 'show', opt);
	};

	// Client-side script
	// Optional, you can remove it

	// A custom helper for the component instances
	// The method below captures each instance of this component
	TOUCH(function(exports, reinit) {

		var name = exports.name + ' --> ' + exports.id;

		console.log(name, 'initialized' + (reinit ? ' : UPDATE' : ''));

		exports.settings = function(meta) {
			// Triggered when the user opens settings
			console.log(name, 'settings', meta);
		};

		exports.configure = function(config, isinit) {
			// Triggered when the config is changed
			console.log(name, 'configure', config);
			var changes = exports.instance.changes;
			if (changes && changes.newbie) {

				const inputs = [];
				for (const input of exports.instance.config.inputs) {
					let i = inputs.length+1;
					inputs.push({ id: input.id || 'input' + i, name: input.name || 'Input #' + i });
				}
				exports.instance.inputs = inputs;

				const outputs = [];
				for (const output of exports.instance.config.outputs) {
					let i = outputs.length+1;
					outputs.push({ id: output.id || 'output' + i, name: output.name || 'Output #' + i });
				}
				exports.instance.outputs = outputs;

				UPD('flow.data');
			}
		};

		exports.status = function(status, isinit) {
			// Triggered when the status is changed
			console.log(name, 'status', status);
		};

		exports.note = function(note, isinit) {
			// Triggered when the note is changed
			console.log(name, 'note', note);
		};

		exports.variables = function(variables) {
			// Triggered when the variables are changed
			console.log(name, 'variables', variables);
		};

		exports.variables2 = function(variables) {
			// Triggered when the variables2 are changed
			console.log(name, 'variables2', variables);
		};

		exports.close = function() {
			// Triggered when the instance is closing due to some reasons
			console.log(name, 'close');
		};

	});
</script>

<style>
	.CLASS footer { padding: 10px; font-size: 12px; }

	.button-add { height: 24px; font-size: 12px; border: 1px solid #E0E0E0; border-radius: var(--radius); color: #000; background-color: #f0f0f0; margin: 0; padding: 2px 10px; }
	.button-add:hover { background-color: #F8F8F8; }
	.button-add:active { background-color: #E0E0E0; }

	.ui-dark .button-add { border-color: #404040; color: #FFF; background-color: #202020; }
	.ui-dark .button-add:hover { background-color: #303030; }
	.ui-dark .button-add:active { background-color: #404040; }

	.switch-input-group { clear: both; height: 36px; }
	.switch-input-group > ui-component:first-child .ui-input-control { border-right: none; border-bottom-right-radius: 0; border-top-right-radius: 0; width: 120px; float: left; background-color: #f0f0f0; }
	.switch-input-group > ui-component:last-child .ui-input-control { border-bottom-left-radius: 0; border-top-left-radius: 0; float: left; width: calc(100% - 120px); }
	.switch-input-group.wide > ui-component:first-child .ui-input-control { width: 200px; }
	.switch-input-group.wide > ui-component:last-child .ui-input-control { width: calc(100% - 200px); }
	.switch-inputs { border: 1px solid #e0e0e0; padding: 8px; border-radius: 3px; }
	.switch-input { border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px; margin-bottom:4px; }
	.switch-input > .row > .col-md-1 { height: 36px; line-height: 36px; }

	.switch-output-group { clear: both; height: 36px; }
	.switch-output-group > ui-component:first-child .ui-output-control { border-right: none; border-bottom-right-radius: 0; border-top-right-radius: 0; width: 120px; float: left; background-color: #f0f0f0; }
	.switch-output-group > ui-component:last-child .ui-output-control { border-bottom-left-radius: 0; border-top-left-radius: 0; float: left; width: calc(100% - 120px); }
	.switch-output-group.wide > ui-component:first-child .ui-output-control { width: 200px; }
	.switch-output-group.wide > ui-component:last-child .ui-output-control { width: calc(100% - 200px); }
	.switch-outputs { border: 1px solid #e0e0e0; padding: 8px; border-radius: 3px; }
	.switch-output { border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px; margin-bottom:4px; }
	.switch-output > .row > .col-md-1 { height: 36px; line-height: 36px; }

	.switch-help { background-color: #e7e7ff; border-radius: 3px; padding: 4px; }
	.switch-thead { padding: 8px; margin-bottom:4px; }
</style>

<body>
	<header>
		<i class="ICON"></i>NAME (<span data-bind="CONFIG.name__text"></span>)
	</header>
</body>
@petersirka
Copy link
Collaborator

@ColtonMcInroy Instead of using syntax highlighter here, please upload .html files only.

@ColtonMcInroy
Copy link
Author

Sorry about that, here you go... Does not allow .html so here is a .html.gz

Multiplexer.html.gz

@petersirka
Copy link
Collaborator

@ColtonMcInroy I can publish it to the main FlowStreamComponents repo if you agree, but please add readme information. Thank you!

@ColtonMcInroy
Copy link
Author

Here is an updated version of this component with readme information provided.
Multiplexer.zip

One thing I should mention, currently I used the "Switch" component to figure out how to handle creating the inputs/outputs. The drag/drop for re-ordering functionality in both the Switch component and this multiplexer component do not appear to work. I have not had time to look into it yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants