From 74c105a42ef12d25b09a294821f570f676ddec97 Mon Sep 17 00:00:00 2001 From: Colin Dawson Date: Sat, 14 Mar 2026 23:02:42 +0000 Subject: [PATCH] Upgraded the TaskNameDisplayPanel to be more reusable. --- src/Sass/_domains.scss | 25 ++++++++++ src/Sass/general.scss | 12 +++++ src/components/validationErrorIcon.tsx | 16 ++++-- .../workflowTemplates/components/TaskList.tsx | 3 +- .../components/TaskNameDisplayPanel.tsx | 50 +++++++++++++++++-- .../workflowTemplates/components/TasksTab.tsx | 4 +- 6 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/Sass/_domains.scss b/src/Sass/_domains.scss index 8958c9d..926c686 100644 --- a/src/Sass/_domains.scss +++ b/src/Sass/_domains.scss @@ -63,3 +63,28 @@ min-height: 0; } } + +.workflow-tasks-grid { + grid-template-columns: max-content minmax(0, 1fr); + + > .workflow-tasks-list-host { + width: max-content; + } +} + +.task-list-container--expand-to-content { + width: max-content; + + .selectable-list { + width: max-content; + } + + .task-name-display-panel { + width: max-content; + } + + .task-name-display-panel__name { + overflow: visible; + text-overflow: clip; + } +} diff --git a/src/Sass/general.scss b/src/Sass/general.scss index 6d03a74..d0d5319 100644 --- a/src/Sass/general.scss +++ b/src/Sass/general.scss @@ -25,6 +25,18 @@ white-space: nowrap; } +.validation-error-icon--reserve-space { + display: inline-flex; + align-items: center; + justify-content: center; + flex: 0 0 1rem; + width: 1rem; + + .error-icon { + margin-left: 0; + } +} + .task-name-display-panel--wrap { white-space: normal; diff --git a/src/components/validationErrorIcon.tsx b/src/components/validationErrorIcon.tsx index 6304521..554a662 100644 --- a/src/components/validationErrorIcon.tsx +++ b/src/components/validationErrorIcon.tsx @@ -4,16 +4,26 @@ import React from "react"; interface ValidationErrorIconProps { visible: boolean; + reserveSpace?: boolean; } const ValidationErrorIcon: React.FC = ({ visible, + reserveSpace = false, }) => { - if (!visible) return null; + if (!visible && !reserveSpace) return null; + + const wrapperClassName = reserveSpace + ? "validation-error-icon validation-error-icon--reserve-space" + : "validation-error-icon"; return ( - - + + {visible && ( + + + + )} ); }; diff --git a/src/modules/manager/workflowTemplates/components/TaskList.tsx b/src/modules/manager/workflowTemplates/components/TaskList.tsx index 3141d42..6ecfa8c 100644 --- a/src/modules/manager/workflowTemplates/components/TaskList.tsx +++ b/src/modules/manager/workflowTemplates/components/TaskList.tsx @@ -93,7 +93,7 @@ const TaskList: React.FC = ({ const sortedTasks = sortTasksTopologically(tasks); return ( -
+
@@ -111,6 +111,7 @@ const TaskList: React.FC = ({ showValidationErrorIcon={ validTasksList[x.config.guid as string] === false } + reserveValidationErrorIconSpace={true} /> ); } else return <>; diff --git a/src/modules/manager/workflowTemplates/components/TaskNameDisplayPanel.tsx b/src/modules/manager/workflowTemplates/components/TaskNameDisplayPanel.tsx index 265b14b..0284bd6 100644 --- a/src/modules/manager/workflowTemplates/components/TaskNameDisplayPanel.tsx +++ b/src/modules/manager/workflowTemplates/components/TaskNameDisplayPanel.tsx @@ -11,14 +11,19 @@ export interface TaskNameDisplayPanel { task: TaskDefinition; showValidationErrorIcon: boolean; allowWordWrap?: boolean; + reserveValidationErrorIconSpace?: boolean; } const TaskNameDisplayPanel: React.FC = ({ task, showValidationErrorIcon = false, allowWordWrap = false, + reserveValidationErrorIconSpace = false, }) => { const [tasksMetadata, setTasksMetadata] = React.useState([]); + const [isNameTruncated, setIsNameTruncated] = React.useState(false); + const taskNameRef = React.useRef(null); + const taskName = task.config.name as string; useEffect(() => { const fetchTaskMetadata = async () => { @@ -42,13 +47,52 @@ const TaskNameDisplayPanel: React.FC = ({ ? "task-name-display-panel task-name-display-panel--wrap" : "task-name-display-panel"; + const updateTruncationState = React.useCallback(() => { + const el = taskNameRef.current; + + if (!el || allowWordWrap) { + setIsNameTruncated(false); + return; + } + + setIsNameTruncated(el.scrollWidth > el.clientWidth); + }, [allowWordWrap]); + + useEffect(() => { + updateTruncationState(); + }, [taskName, allowWordWrap, updateTruncationState]); + + useEffect(() => { + const el = taskNameRef.current; + if (!el || allowWordWrap || typeof ResizeObserver === "undefined") { + return; + } + + const observer = new ResizeObserver(() => { + updateTruncationState(); + }); + + observer.observe(el); + + return () => { + observer.disconnect(); + }; + }, [allowWordWrap, updateTruncationState]); + return (
- - {task.config.name as string} + + {taskName} - {} +
); }; diff --git a/src/modules/manager/workflowTemplates/components/TasksTab.tsx b/src/modules/manager/workflowTemplates/components/TasksTab.tsx index f151bee..74357f8 100644 --- a/src/modules/manager/workflowTemplates/components/TasksTab.tsx +++ b/src/modules/manager/workflowTemplates/components/TasksTab.tsx @@ -248,8 +248,8 @@ const TasksTab: React.FC = ({ ); return ( -
-
+
+