Skip to content

Commit fd8c690

Browse files
refactor(pipeline-builder): replace innerHTML with createElement, O(1) tool lookup
- Replace all 7 innerHTML string concatenations with createElement calls, matching codebase conventions (social-proof-toasts, activity-feed, etc.) - Pre-build _toolById hash map for O(1) tool lookups instead of O(n) linear scans in findTool() called per-node during updatePipeline() - Pre-parse pipeline keys into _pipelineEntries array at module load, avoiding String.split() on every updatePipeline() call - Use object-based selectedSet in findPipelines() for O(1) membership checks instead of Array.indexOf() - Extract _createToolButton, _createPipelineNode, _createArrow, _createHub, _buildVisualization, _createResultCard, _buildDescription as focused DOM builder functions - Use while(el.firstChild) removeChild pattern for clearing containers instead of innerHTML = ''
1 parent 529c013 commit fd8c690

2 files changed

Lines changed: 370 additions & 126 deletions

File tree

dist/bundle.js

Lines changed: 185 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7045,7 +7045,6 @@ var AIGlossary = (function () {
70457045

70467046
/* === src/modules/pipeline-builder.js === */
70477047

7048-
70497048
/* ────────── Integration Pipeline Builder ────────── */
70507049
var PipelineBuilder = (function () {
70517050
'use strict';
@@ -7086,6 +7085,25 @@ var PipelineBuilder = (function () {
70867085
'gmail+sheets': { name: 'Email → Data', flow: 'AgentBox extracts data from incoming emails and logs it into spreadsheets.' }
70877086
};
70887087

7088+
// Pre-built O(1) tool lookup by id — avoids linear scan in findTool()
7089+
var _toolById = {};
7090+
for (var _i = 0; _i < INTEGRATIONS.length; _i++) {
7091+
_toolById[INTEGRATIONS[_i].id] = INTEGRATIONS[_i];
7092+
}
7093+
7094+
// Pre-parsed pipeline entries with split keys — avoids re-splitting on
7095+
// every updatePipeline() call and enables fast Set-based membership checks
7096+
var _pipelineEntries = [];
7097+
(function () {
7098+
var keys = Object.keys(PIPELINES);
7099+
for (var i = 0; i < keys.length; i++) {
7100+
_pipelineEntries.push({
7101+
parts: keys[i].split('+'),
7102+
pipeline: PIPELINES[keys[i]]
7103+
});
7104+
}
7105+
})();
7106+
70897107
var selected = [];
70907108
var _section = null;
70917109

@@ -7100,23 +7118,37 @@ var PipelineBuilder = (function () {
71007118
updatePipeline();
71017119
}
71027120

7121+
/** Create a tool button element for the grid. */
7122+
function _createToolButton(tool) {
7123+
var btn = document.createElement('button');
7124+
btn.className = 'pipeline-tool-btn';
7125+
btn.setAttribute('data-tool', tool.id);
7126+
btn.setAttribute('aria-pressed', 'false');
7127+
btn.setAttribute('role', 'switch');
7128+
btn.setAttribute('aria-label', 'Add ' + tool.name + ' to pipeline');
7129+
btn.setAttribute('title', tool.desc);
7130+
7131+
var iconSpan = document.createElement('span');
7132+
iconSpan.className = 'pipeline-tool-icon';
7133+
iconSpan.textContent = tool.icon;
7134+
7135+
var nameSpan = document.createElement('span');
7136+
nameSpan.className = 'pipeline-tool-name';
7137+
nameSpan.textContent = tool.name;
7138+
7139+
btn.appendChild(iconSpan);
7140+
btn.appendChild(nameSpan);
7141+
btn.addEventListener('click', function () { toggleTool(tool.id); });
7142+
return btn;
7143+
}
7144+
71037145
function renderToolGrid() {
71047146
var grid = section().querySelector('.pipeline-tool-grid');
71057147
if (!grid) return;
7106-
grid.innerHTML = '';
7107-
INTEGRATIONS.forEach(function (tool) {
7108-
var btn = document.createElement('button');
7109-
btn.className = 'pipeline-tool-btn';
7110-
btn.setAttribute('data-tool', tool.id);
7111-
btn.setAttribute('aria-pressed', 'false');
7112-
btn.setAttribute('role', 'switch');
7113-
btn.setAttribute('aria-label', 'Add ' + tool.name + ' to pipeline');
7114-
btn.setAttribute('title', tool.desc);
7115-
btn.innerHTML = '<span class="pipeline-tool-icon">' + tool.icon +
7116-
'</span><span class="pipeline-tool-name">' + tool.name + '</span>';
7117-
btn.addEventListener('click', function () { toggleTool(tool.id); });
7118-
grid.appendChild(btn);
7119-
});
7148+
while (grid.firstChild) grid.removeChild(grid.firstChild);
7149+
for (var i = 0; i < INTEGRATIONS.length; i++) {
7150+
grid.appendChild(_createToolButton(INTEGRATIONS[i]));
7151+
}
71207152
}
71217153

71227154
function toggleTool(id) {
@@ -7142,79 +7174,169 @@ var PipelineBuilder = (function () {
71427174
}
71437175
}
71447176

7145-
function updatePipeline() {
7146-
var viz = section().querySelector('.pipeline-visualization');
7147-
var desc = section().querySelector('.pipeline-description');
7148-
var counter = section().querySelector('.pipeline-counter');
7149-
if (!viz || !desc) return;
7177+
// ── DOM builders for pipeline visualization ──────────────────────
71507178

7151-
if (counter) counter.textContent = selected.length + ' / 5 tools selected';
7179+
/** Create a single pipeline node (icon + name). */
7180+
function _createPipelineNode(tool) {
7181+
var node = document.createElement('div');
7182+
node.className = 'pipeline-node';
71527183

7153-
if (selected.length === 0) {
7154-
viz.innerHTML = '<p class="pipeline-empty">Select tools above to build your agent pipeline</p>';
7155-
desc.innerHTML = '';
7156-
return;
7157-
}
7184+
var icon = document.createElement('span');
7185+
icon.className = 'pipeline-node-icon';
7186+
icon.textContent = tool.icon;
7187+
7188+
var name = document.createElement('span');
7189+
name.className = 'pipeline-node-name';
7190+
name.textContent = tool.name;
7191+
7192+
node.appendChild(icon);
7193+
node.appendChild(name);
7194+
return node;
7195+
}
7196+
7197+
/** Create an arrow separator between pipeline nodes. */
7198+
function _createArrow() {
7199+
var arrow = document.createElement('div');
7200+
arrow.className = 'pipeline-arrow';
7201+
arrow.setAttribute('aria-hidden', 'true');
7202+
arrow.textContent = '→';
7203+
return arrow;
7204+
}
7205+
7206+
/** Create the central AgentBox hub element. */
7207+
function _createHub() {
7208+
var hub = document.createElement('div');
7209+
hub.className = 'pipeline-hub';
7210+
7211+
var icon = document.createElement('span');
7212+
icon.className = 'pipeline-hub-icon';
7213+
icon.textContent = '🤖';
7214+
7215+
var label = document.createElement('span');
7216+
label.className = 'pipeline-hub-label';
7217+
label.textContent = 'AgentBox';
7218+
7219+
var sub = document.createElement('span');
7220+
sub.className = 'pipeline-hub-sub';
7221+
sub.textContent = 'connects everything';
7222+
7223+
hub.appendChild(icon);
7224+
hub.appendChild(label);
7225+
hub.appendChild(sub);
7226+
return hub;
7227+
}
7228+
7229+
/** Build the flow visualization (nodes + arrows + hub) for the current selection. */
7230+
function _buildVisualization() {
7231+
var frag = document.createDocumentFragment();
7232+
var flow = document.createElement('div');
7233+
flow.className = 'pipeline-flow';
71587234

7159-
// Build visual pipeline
7160-
var html = '<div class="pipeline-flow">';
71617235
for (var i = 0; i < selected.length; i++) {
7162-
var tool = findTool(selected[i]);
7236+
var tool = _toolById[selected[i]];
71637237
if (!tool) continue;
7164-
html += '<div class="pipeline-node">';
7165-
html += '<span class="pipeline-node-icon">' + tool.icon + '</span>';
7166-
html += '<span class="pipeline-node-name">' + tool.name + '</span>';
7167-
html += '</div>';
7238+
flow.appendChild(_createPipelineNode(tool));
71687239
if (i < selected.length - 1) {
7169-
html += '<div class="pipeline-arrow" aria-hidden="true">→</div>';
7240+
flow.appendChild(_createArrow());
71707241
}
71717242
}
7172-
html += '</div>';
71737243

7174-
// AgentBox hub in center
7175-
html += '<div class="pipeline-hub">';
7176-
html += '<span class="pipeline-hub-icon">🤖</span>';
7177-
html += '<span class="pipeline-hub-label">AgentBox</span>';
7178-
html += '<span class="pipeline-hub-sub">connects everything</span>';
7179-
html += '</div>';
7244+
frag.appendChild(flow);
7245+
frag.appendChild(_createHub());
7246+
return frag;
7247+
}
71807248

7181-
viz.innerHTML = html;
7249+
/** Create a single pipeline result card (name + description). */
7250+
function _createResultCard(pipeline) {
7251+
var card = document.createElement('div');
7252+
card.className = 'pipeline-result-card';
7253+
7254+
var name = document.createElement('strong');
7255+
name.className = 'pipeline-result-name';
7256+
name.textContent = pipeline.name;
7257+
7258+
var flowP = document.createElement('p');
7259+
flowP.className = 'pipeline-result-flow';
7260+
flowP.textContent = pipeline.flow;
7261+
7262+
card.appendChild(name);
7263+
card.appendChild(flowP);
7264+
return card;
7265+
}
7266+
7267+
/** Build the description section showing matched pipelines or a generic message. */
7268+
function _buildDescription(matches) {
7269+
var wrapper = document.createElement('div');
71827270

7183-
// Find matching pipelines
7184-
var matches = findPipelines();
71857271
if (matches.length === 0) {
7186-
desc.innerHTML = '<div class="pipeline-result"><p class="pipeline-generic">AgentBox can connect these tools and automate workflows between them. Add more tools to see specific pipeline recipes!</p></div>';
7272+
wrapper.className = 'pipeline-result';
7273+
var p = document.createElement('p');
7274+
p.className = 'pipeline-generic';
7275+
p.textContent = 'AgentBox can connect these tools and automate workflows between them. Add more tools to see specific pipeline recipes!';
7276+
wrapper.appendChild(p);
71877277
} else {
7188-
var descHtml = '<div class="pipeline-results-list">';
7189-
descHtml += '<h4 class="pipeline-results-title">🔗 ' + matches.length + ' automation' + (matches.length > 1 ? 's' : '') + ' available</h4>';
7190-
for (var m = 0; m < matches.length; m++) {
7191-
descHtml += '<div class="pipeline-result-card">';
7192-
descHtml += '<strong class="pipeline-result-name">' + matches[m].name + '</strong>';
7193-
descHtml += '<p class="pipeline-result-flow">' + matches[m].flow + '</p>';
7194-
descHtml += '</div>';
7278+
wrapper.className = 'pipeline-results-list';
7279+
7280+
var title = document.createElement('h4');
7281+
title.className = 'pipeline-results-title';
7282+
title.textContent = '🔗 ' + matches.length + ' automation' + (matches.length > 1 ? 's' : '') + ' available';
7283+
wrapper.appendChild(title);
7284+
7285+
for (var i = 0; i < matches.length; i++) {
7286+
wrapper.appendChild(_createResultCard(matches[i]));
71957287
}
7196-
descHtml += '</div>';
7197-
desc.innerHTML = descHtml;
71987288
}
7289+
7290+
return wrapper;
71997291
}
72007292

7201-
function findTool(id) {
7202-
for (var i = 0; i < INTEGRATIONS.length; i++) {
7203-
if (INTEGRATIONS[i].id === id) return INTEGRATIONS[i];
7293+
// ── Core update logic ────────────────────────────────────────────
7294+
7295+
function updatePipeline() {
7296+
var viz = section().querySelector('.pipeline-visualization');
7297+
var desc = section().querySelector('.pipeline-description');
7298+
var counter = section().querySelector('.pipeline-counter');
7299+
if (!viz || !desc) return;
7300+
7301+
if (counter) counter.textContent = selected.length + ' / 5 tools selected';
7302+
7303+
// Clear previous content
7304+
while (viz.firstChild) viz.removeChild(viz.firstChild);
7305+
while (desc.firstChild) desc.removeChild(desc.firstChild);
7306+
7307+
if (selected.length === 0) {
7308+
var empty = document.createElement('p');
7309+
empty.className = 'pipeline-empty';
7310+
empty.textContent = 'Select tools above to build your agent pipeline';
7311+
viz.appendChild(empty);
7312+
return;
72047313
}
7205-
return null;
7314+
7315+
viz.appendChild(_buildVisualization());
7316+
7317+
var matches = findPipelines();
7318+
desc.appendChild(_buildDescription(matches));
7319+
}
7320+
7321+
function findTool(id) {
7322+
return _toolById[id] || null;
72067323
}
72077324

72087325
function findPipelines() {
7326+
// Build a Set of selected ids for O(1) membership checks
7327+
var selectedSet = {};
7328+
for (var s = 0; s < selected.length; s++) {
7329+
selectedSet[selected[s]] = true;
7330+
}
7331+
72097332
var matches = [];
7210-
var keys = Object.keys(PIPELINES);
7211-
for (var k = 0; k < keys.length; k++) {
7212-
var parts = keys[k].split('+');
7333+
for (var k = 0; k < _pipelineEntries.length; k++) {
7334+
var parts = _pipelineEntries[k].parts;
72137335
var allPresent = true;
72147336
for (var p = 0; p < parts.length; p++) {
7215-
if (selected.indexOf(parts[p]) < 0) { allPresent = false; break; }
7337+
if (!selectedSet[parts[p]]) { allPresent = false; break; }
72167338
}
7217-
if (allPresent) matches.push(PIPELINES[keys[k]]);
7339+
if (allPresent) matches.push(_pipelineEntries[k].pipeline);
72187340
}
72197341
return matches;
72207342
}

0 commit comments

Comments
 (0)