Skip to content

Commit 50bf8b7

Browse files
feat(web): add connector tooltips and adjust port direction
1 parent c62ea00 commit 50bf8b7

2 files changed

Lines changed: 115 additions & 18 deletions

File tree

apps/web/src/app/workflow-editor.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,52 +2307,49 @@ export class WorkflowEditor {
23072307
node.id,
23082308
SUBAGENT_TARGET_HANDLE,
23092309
'port-subagent-target',
2310-
'Subagent target'
2310+
'Set as subagent'
23112311
)
23122312
);
23132313
}
23142314

23152315
if (node.type !== 'start') {
2316-
const portIn = this.createPort(node.id, 'input', 'port-in', '', this.getNodeHeaderPortTop(node));
2316+
const inputTooltip = node.type === 'end' ? 'End input' : 'Input';
2317+
const portIn = this.createPort(node.id, 'input', 'port-in', inputTooltip, this.getNodeHeaderPortTop(node));
23172318
el.appendChild(portIn);
23182319
}
23192320

23202321
if (node.type !== 'end') {
23212322
if (node.type === 'if') {
23222323
const conditions = this.getIfConditions(node);
23232324
if (this.shouldAggregateCollapsedIfPorts(node)) {
2324-
const title = `${conditions.length} condition branches (expand to wire specific branches)`;
23252325
const aggregateConditionPort = this.createPort(
23262326
node.id,
23272327
this.getIfConditionHandle(0),
23282328
'port-out port-condition port-condition-aggregate',
2329-
title,
2329+
'Expand to connect',
23302330
this.getNodeHeaderCenterYOffset(node) - AGGREGATE_PORT_RADIUS,
23312331
false
23322332
);
23332333
aggregateConditionPort.textContent = String(conditions.length);
2334-
aggregateConditionPort.setAttribute('aria-label', `${conditions.length} conditions`);
2334+
aggregateConditionPort.setAttribute('aria-label', 'Expand to connect');
23352335
el.appendChild(aggregateConditionPort);
23362336
el.appendChild(
23372337
this.createPort(
23382338
node.id,
23392339
IF_FALLBACK_HANDLE,
23402340
'port-out port-condition-fallback',
2341-
'False fallback',
2341+
'Fallback path',
23422342
this.getNodeSecondaryPortTop(node)
23432343
)
23442344
);
23452345
} else {
2346-
conditions.forEach((condition: any, index: any) => {
2347-
const operatorLabel = condition.operator === 'contains' ? 'Contains' : 'Equal';
2348-
const conditionValue = condition.value || '';
2349-
const title = `Condition ${index + 1}: ${operatorLabel} "${conditionValue}"`;
2346+
conditions.forEach((_condition: any, index: any) => {
23502347
el.appendChild(
23512348
this.createPort(
23522349
node.id,
23532350
this.getIfConditionHandle(index),
23542351
'port-out port-condition',
2355-
title,
2352+
`Condition ${index + 1}`,
23562353
this.getIfConditionPortTop(node, index)
23572354
)
23582355
);
@@ -2362,20 +2359,20 @@ export class WorkflowEditor {
23622359
node.id,
23632360
IF_FALLBACK_HANDLE,
23642361
'port-out port-condition-fallback',
2365-
'False fallback',
2362+
'Fallback path',
23662363
this.getIfFallbackPortTop(node)
23672364
)
23682365
);
23692366
}
23702367
} else if (node.type === 'agent') {
2371-
el.appendChild(this.createPort(node.id, 'output', 'port-out', '', this.getNodeHeaderPortTop(node)));
2368+
el.appendChild(this.createPort(node.id, 'output', 'port-out', 'Output', this.getNodeHeaderPortTop(node)));
23722369
if (node.data?.tools?.subagents) {
23732370
el.appendChild(
23742371
this.createPort(
23752372
node.id,
23762373
SUBAGENT_HANDLE,
23772374
'port-subagent',
2378-
'Subagent'
2375+
'Add subagent'
23792376
)
23802377
);
23812378
}
@@ -2385,7 +2382,7 @@ export class WorkflowEditor {
23852382
node.id,
23862383
'approve',
23872384
'port-out port-true',
2388-
'Approve',
2385+
'Approve path',
23892386
this.getNodeHeaderPortTop(node)
23902387
)
23912388
);
@@ -2394,12 +2391,13 @@ export class WorkflowEditor {
23942391
node.id,
23952392
'reject',
23962393
'port-out port-false',
2397-
'Reject',
2394+
'Reject path',
23982395
this.getNodeSecondaryPortTop(node)
23992396
)
24002397
);
24012398
} else {
2402-
el.appendChild(this.createPort(node.id, 'output', 'port-out', '', this.getNodeHeaderPortTop(node)));
2399+
const outputTooltip = node.type === 'start' ? 'Next step' : 'Output';
2400+
el.appendChild(this.createPort(node.id, 'output', 'port-out', outputTooltip, this.getNodeHeaderPortTop(node)));
24032401
}
24042402
}
24052403
}
@@ -2414,7 +2412,11 @@ export class WorkflowEditor {
24142412
): HTMLDivElement {
24152413
const port = document.createElement('div');
24162414
port.className = `port ${className}${connectable ? '' : ' port-disabled'}`;
2417-
if (title) port.title = title;
2415+
if (title) {
2416+
port.title = title;
2417+
port.setAttribute('data-tooltip', title);
2418+
port.setAttribute('aria-label', title);
2419+
}
24182420
if (typeof top === 'number') {
24192421
port.style.top = `${top}px`;
24202422
}

apps/web/src/workflow-editor.css

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,101 @@ path.connection-line.active {
530530
transform: none;
531531
}
532532

533+
.port[data-tooltip]:hover::after,
534+
.port[data-tooltip]:focus-visible::after {
535+
content: attr(data-tooltip);
536+
position: absolute;
537+
top: 50%;
538+
left: auto;
539+
right: calc(100% + var(--UI-Spacing-spacing-s));
540+
transform: translateY(-50%);
541+
width: max-content;
542+
max-width: 220px;
543+
padding: var(--UI-Spacing-spacing-xs) var(--UI-Spacing-spacing-s);
544+
border-radius: var(--UI-Radius-radius-xs);
545+
border: 1px solid var(--Colors-Stroke-Strong);
546+
background: var(--Colors-Backgrounds-Main-Top);
547+
color: var(--Colors-Text-Body-Strong);
548+
font-size: var(--Fonts-Body-Default-xxs);
549+
line-height: 1.3;
550+
white-space: nowrap;
551+
z-index: 120;
552+
box-shadow: 0 3px 2px 0 var(--Colors-Shadow-Card);
553+
pointer-events: none;
554+
}
555+
556+
.port[data-tooltip]:hover::before,
557+
.port[data-tooltip]:focus-visible::before {
558+
content: '';
559+
position: absolute;
560+
top: 50%;
561+
left: auto;
562+
right: calc(100% + var(--UI-Spacing-spacing-xxs));
563+
transform: translateY(-50%);
564+
border-top: 6px solid transparent;
565+
border-bottom: 6px solid transparent;
566+
border-right: none;
567+
border-left: 6px solid var(--Colors-Backgrounds-Main-Top);
568+
z-index: 121;
569+
pointer-events: none;
570+
}
571+
572+
.port-out[data-tooltip]:hover::after,
573+
.port-out[data-tooltip]:focus-visible::after {
574+
left: calc(100% + var(--UI-Spacing-spacing-s));
575+
right: auto;
576+
}
577+
578+
.port-out[data-tooltip]:hover::before,
579+
.port-out[data-tooltip]:focus-visible::before {
580+
left: calc(100% + var(--UI-Spacing-spacing-xxs));
581+
right: auto;
582+
border-right: 6px solid var(--Colors-Backgrounds-Main-Top);
583+
border-left: none;
584+
}
585+
586+
.port-subagent-target[data-tooltip]:hover::after,
587+
.port-subagent-target[data-tooltip]:focus-visible::after {
588+
top: auto;
589+
left: 50%;
590+
right: auto;
591+
bottom: calc(100% + var(--UI-Spacing-spacing-s));
592+
transform: translateX(-50%);
593+
}
594+
595+
.port-subagent-target[data-tooltip]:hover::before,
596+
.port-subagent-target[data-tooltip]:focus-visible::before {
597+
top: auto;
598+
left: 50%;
599+
right: auto;
600+
bottom: calc(100% + var(--UI-Spacing-spacing-xxs));
601+
transform: translateX(-50%);
602+
border-top: none;
603+
border-bottom: 6px solid var(--Colors-Backgrounds-Main-Top);
604+
border-left: 6px solid transparent;
605+
border-right: 6px solid transparent;
606+
}
607+
608+
.port-subagent[data-tooltip]:hover::after,
609+
.port-subagent[data-tooltip]:focus-visible::after {
610+
top: calc(100% + var(--UI-Spacing-spacing-s));
611+
left: 50%;
612+
right: auto;
613+
transform: translateX(-50%);
614+
}
615+
616+
.port-subagent[data-tooltip]:hover::before,
617+
.port-subagent[data-tooltip]:focus-visible::before {
618+
top: calc(100% + var(--UI-Spacing-spacing-xxs));
619+
left: 50%;
620+
right: auto;
621+
transform: translateX(-50%);
622+
border-top: 6px solid var(--Colors-Backgrounds-Main-Top);
623+
border-bottom: none;
624+
border-left: 6px solid transparent;
625+
border-right: 6px solid transparent;
626+
}
627+
533628
.port-in { left: -8px; }
534629
.port-out { right: -8px; }
535630
.port-true { top: 45px; border-color: var(--Colors-Alert-Success-Default); }

0 commit comments

Comments
 (0)