Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
useWorkflowModeContext as jest.MockedFunction<typeof useWorkflowModeContext>;

const defaultProps = {
title: 'Glossary Approval Workflow',

Check warning on line 140 in openmetadata-ui/src/main/resources/ui/src/components/WorkflowDefinitions/WorkflowBuilder/WorkflowHeader.test.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

Define a constant instead of duplicating this literal 3 times
workflowName: 'GlossaryTermApprovalWorkflow',
handleTestWorkflow: jest.fn(),
handleSaveWorkflow: jest.fn().mockResolvedValue(undefined),
Expand Down Expand Up @@ -203,7 +203,7 @@

render(<WorkflowHeader {...defaultProps} />);

expect(screen.getByTestId('system-workflow-badge')).toBeInTheDocument();

Check warning on line 206 in openmetadata-ui/src/main/resources/ui/src/components/WorkflowDefinitions/WorkflowBuilder/WorkflowHeader.test.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

Define a constant instead of duplicating this literal 3 times
expect(screen.getByTestId('system-workflow-badge')).toHaveTextContent(
'label.system'
);
Expand Down Expand Up @@ -244,7 +244,7 @@
render(<WorkflowHeader {...defaultProps} />);

expect(
screen.queryByTestId('edit-workflow-title-button')

Check warning on line 247 in openmetadata-ui/src/main/resources/ui/src/components/WorkflowDefinitions/WorkflowBuilder/WorkflowHeader.test.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

Define a constant instead of duplicating this literal 3 times
).not.toBeInTheDocument();
});

Expand Down Expand Up @@ -275,4 +275,21 @@
screen.queryByTestId('edit-workflow-title-button')
).not.toBeInTheDocument();
});

it('renders the AI-mode header with the breadcrumb when isAiMode is true', () => {
mockUseWorkflowModeContext.mockReturnValue(buildContextMock());

render(
<WorkflowHeader
{...defaultProps}
isAiMode
breadcrumb={<div data-testid="ai-breadcrumb">crumb</div>}

Check warning on line 286 in openmetadata-ui/src/main/resources/ui/src/components/WorkflowDefinitions/WorkflowBuilder/WorkflowHeader.test.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

disallow literal string: <div data-testid="ai-breadcrumb">crumb</div>
/>
);

expect(screen.getByTestId('ai-breadcrumb')).toBeInTheDocument();
expect(screen.getByTestId('workflow-title')).toHaveTextContent(
'Glossary Approval Workflow'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import {
Badge,
Button,
Card,
Dialog,
Input,
Modal,
Expand All @@ -35,6 +36,7 @@

export const WorkflowHeader: React.FC<WorkflowHeaderProps> = ({
breadcrumb,
isAiMode = false,
title,
workflowName,
handleTestWorkflow,
Expand All @@ -44,7 +46,7 @@
handleRunWorkflow,
isRunLoading = false,
onUpdateDisplayName,
}) => {

Check warning on line 49 in openmetadata-ui/src/main/resources/ui/src/components/WorkflowDefinitions/WorkflowBuilder/WorkflowHeader.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

{"message":"Function has a complexity of 14 which is greater than 10 authorized.","cost":4,"secondaryLocations":[{"line":49,"column":3,"endLine":49,"endColumn":5,"message":"+1"},{"line":63,"column":65,"endLine":63,"endColumn":67,"message":"+1"},{"line":97,"column":41,"endLine":97,"endColumn":42,"message":"+1"},{"line":98,"column":41,"endLine":98,"endColumn":42,"message":"+1"},{"line":99,"column":42,"endLine":99,"endColumn":43,"message":"+1"},{"line":101,"column":37,"endLine":101,"endColumn":38,"message":"+1"},{"line":102,"column":37,"endLine":102,"endColumn":38,"message":"+1"},{"line":106,"column":44,"endLine":106,"endColumn":46,"message":"+1"},{"line":116,"column":29,"endLine":116,"endColumn":31,"message":"+1"},{"line":132,"column":49,"endLine":132,"endColumn":51,"message":"+1"},{"line":132,"column":38,"endLine":132,"endColumn":40,"message":"+1"},{"line":150,"column":16,"endLine":150,"endColumn":17,"message":"+1"},{"line":168,"column":25,"endLine":168,"endColumn":26,"message":"+1"},{"line":211,"column":30,"endLine":211,"endColumn":32,"message":"+1"}]}
const { t } = useTranslation();
const {
showEditButton,
Expand Down Expand Up @@ -89,97 +91,143 @@
setIsEditModalOpen(false);
};

const workflowControls = (
<WorkflowControls
isRunLoading={isRunLoading}
onCancelWorkflow={showCancelButton ? enterViewMode : undefined}
onDeleteWorkflow={showDeleteButton ? handleDeleteWorkflow : undefined}
onRevertAndCancel={showCancelButton ? handleRevertAndCancel : undefined}
onRunWorkflow={handleRunWorkflow}
onSaveWorkflow={showSaveButton ? handleSaveAndEnterViewMode : undefined}
onTestWorkflow={showTestButton ? handleTestWorkflow : undefined}
/>
);

const editWorkflowButton = showEditButton && (
<Button
color="primary"
data-testid="edit-workflow-button"
size="sm"
onPress={enterEditMode}>
{t('label.edit-workflow')}
</Button>
);

const systemBadge = isNoOp && (
<Tooltip
placement="top"
title={t('message.system-workflow-edit-restriction')}>
<TooltipTrigger>
<Badge
color="gray"
data-testid="system-workflow-badge"
size="sm"
type="color">
{t('label.system')}
</Badge>
</TooltipTrigger>
</Tooltip>
);

const editTitleButton = !isViewMode && !isNoOp && (
<Button
color="tertiary"
data-testid="edit-workflow-title-button"
iconLeading={EditIcon}
size="sm"
onPress={handleOpenEditModal}
/>
);

const workflowIcon = (
<div className="tw:flex tw:items-center tw:justify-center tw:size-8 tw:rounded-md tw:bg-brand-solid">
<WorkflowIcon className="tw:size-4 tw:text-white" />
</div>
);

return (
<>
<HeaderShell
actions={
<>
<WorkflowControls
isRunLoading={isRunLoading}
onCancelWorkflow={showCancelButton ? enterViewMode : undefined}
onDeleteWorkflow={
showDeleteButton ? handleDeleteWorkflow : undefined
}
onRevertAndCancel={
showCancelButton ? handleRevertAndCancel : undefined
}
onRunWorkflow={handleRunWorkflow}
onSaveWorkflow={
showSaveButton ? handleSaveAndEnterViewMode : undefined
}
onTestWorkflow={showTestButton ? handleTestWorkflow : undefined}
/>
{showEditButton && (
<Button
color="primary"
data-testid="edit-workflow-button"
size="sm"
onPress={enterEditMode}>
{t('label.edit-workflow')}
</Button>
)}
</>
}
badge={
<>
{isNoOp && (
<Tooltip
placement="top"
title={t('message.system-workflow-edit-restriction')}>
<TooltipTrigger>
<Badge
color="gray"
data-testid="system-workflow-badge"
size="sm"
type="color">
{t('label.system')}
</Badge>
</TooltipTrigger>
</Tooltip>
)}
{!isViewMode && !isNoOp && (
<Button
color="tertiary"
data-testid="edit-workflow-title-button"
iconLeading={EditIcon}
size="sm"
onPress={handleOpenEditModal}
/>
)}
</>
}
breadcrumb={breadcrumb}
data-testid="workflow-header"
leading={
<div className="tw:flex tw:items-center tw:justify-center tw:size-8 tw:rounded-md tw:bg-brand-solid">
<WorkflowIcon className="tw:size-4 tw:text-white" />
</div>
}
subtitle={
workflowName ? (
{isAiMode ? (
<HeaderShell
actions={
<>
{workflowControls}
{editWorkflowButton}
</>
}
badge={
<>
{systemBadge}
{editTitleButton}
</>
}
breadcrumb={breadcrumb}
data-testid="workflow-header"
leading={workflowIcon}
subtitle={
workflowName ? (
<Typography
ellipsis
as="p"
className="tw:m-0 tw:text-secondary tw:max-w-150"
data-testid="workflow-description"
size="text-sm">
{workflowName}
</Typography>
) : undefined
}
title={
<Typography
ellipsis
as="p"
className="tw:m-0 tw:text-secondary tw:max-w-150"
data-testid="workflow-description"
size="text-sm">
{workflowName}
as="h3"
className="tw:m-0 tw:text-primary"
data-testid="workflow-title"
size="text-xl"
weight="semibold">
{title}
</Typography>
) : undefined
}
title={
<Typography
ellipsis
as="h3"
className="tw:m-0 tw:text-primary"
data-testid="workflow-title"
size="text-xl"
weight="semibold">
{title}
</Typography>
}
variant="gradient"
/>
}
variant="gradient"
/>
) : (
<Card className="tw:px-6 tw:py-4" data-testid="workflow-header">
<div className="tw:flex tw:items-center tw:justify-between">
<div className="tw:flex tw:items-center tw:gap-3">
{workflowIcon}
<div data-testid="workflow-title-section">
<div className="tw:flex tw:items-center tw:gap-2">
<Typography
ellipsis
as="p"
className="tw:m-0 tw:mb-1 tw:text-primary"
data-testid="workflow-title"
size="text-md"
weight="semibold">
{title}
</Typography>
{systemBadge}
{editTitleButton}
</div>
{workflowName && (
<Typography
ellipsis
as="p"
className="tw:m-0 tw:text-secondary tw:max-w-150"
data-testid="workflow-description"
size="text-sm">
{workflowName}
</Typography>
)}
</div>
</div>

<div className="tw:flex tw:gap-3 tw:items-center">
{workflowControls}
{editWorkflowButton}
</div>
</div>
</Card>
)}

<ModalOverlay isOpen={isEditModalOpen} onOpenChange={setIsEditModalOpen}>
<Modal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ export interface WorkflowControlsProps {

export interface WorkflowHeaderProps {
breadcrumb?: React.ReactNode;
isAiMode?: boolean;
title: string;
workflowName?: string;
children?: React.ReactNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import HeaderBreadcrumb from '../../../components/common/HeaderBreadcrumb/HeaderBreadcrumb.component';
import { getGlossaryHomeCrumb } from '../../../components/common/HeaderBreadcrumb/HeaderBreadcrumb.utils';
import Loader from '../../../components/common/Loader/Loader';
import TitleBreadcrumb from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component';
import { UnsavedChangesModal } from '../../../components/Modals/UnsavedChangesModal/UnsavedChangesModal.component';
import PageLayoutV1 from '../../../components/PageLayoutV1/PageLayoutV1';
import {
Expand Down Expand Up @@ -73,7 +74,7 @@

const WorkflowBuilderInternal: React.FC<WorkflowBuilderInternalProps> = ({
workflowLogic,
}) => {

Check warning on line 77 in openmetadata-ui/src/main/resources/ui/src/pages/WorkflowDefinitions/WorkflowBuilder/WorkflowBuilder.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

{"message":"Function has a complexity of 23 which is greater than 10 authorized.","cost":13,"secondaryLocations":[{"line":77,"column":3,"endLine":77,"endColumn":5,"message":"+1"},{"line":250,"column":53,"endLine":250,"endColumn":55,"message":"+1"},{"line":336,"column":37,"endLine":336,"endColumn":39,"message":"+1"},{"line":412,"column":34,"endLine":412,"endColumn":36,"message":"+1"},{"line":446,"column":2,"endLine":446,"endColumn":4,"message":"+1"},{"line":456,"column":41,"endLine":456,"endColumn":43,"message":"+1"},{"line":469,"column":24,"endLine":469,"endColumn":25,"message":"+1"},{"line":470,"column":29,"endLine":470,"endColumn":31,"message":"+1"},{"line":479,"column":19,"endLine":479,"endColumn":21,"message":"+1"},{"line":486,"column":33,"endLine":486,"endColumn":34,"message":"+1"},{"line":519,"column":54,"endLine":519,"endColumn":55,"message":"+1"},{"line":530,"column":20,"endLine":530,"endColumn":21,"message":"+1"},{"line":532,"column":20,"endLine":532,"endColumn":21,"message":"+1"},{"line":560,"column":36,"endLine":560,"endColumn":38,"message":"+1"},{"line":559,"column":29,"endLine":559,"endColumn":31,"message":"+1"},{"line":558,"column":54,"endLine":558,"endColumn":56,"message":"+1"},{"line":565,"column":22,"endLine":565,"endColumn":23,"message":"+1"},{"line":564,"column":31,"endLine":564,"endColumn":33,"message":"+1"},{"line":583,"column":47,"endLine":583,"endColumn":49,"message":"+1"},{"line":584,"column":43,"endLine":584,"endColumn":45,"message":"+1"},{"line":592,"column":57,"endLine":592,"endColumn":59,"message":"+1"},{"line":615,"column":51,"endLine":615,"endColumn":53,"message":"+1"},{"line":618,"column":48,"endLine":618,"endColumn":50,"message":"+1"}]}
const { t } = useTranslation();
const isAiMode = useIsAiMode();
const {
Expand Down Expand Up @@ -330,7 +331,7 @@
} else if (!isEditMode && savedStateOnEdit) {
setSavedStateOnEdit(null);
}
}, [isEditMode, savedStateOnEdit, loading]);

Check warning on line 334 in openmetadata-ui/src/main/resources/ui/src/pages/WorkflowDefinitions/WorkflowBuilder/WorkflowBuilder.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

React Hook useEffect has missing dependencies: 'edges' and 'nodes'. Either include them or remove the dependency array

const navBlockEnabled = isEditMode && hasNodeConfigSaved;

Expand Down Expand Up @@ -394,7 +395,7 @@
showErrorToast(error as AxiosError);
}
},
[

Check warning on line 398 in openmetadata-ui/src/main/resources/ui/src/pages/WorkflowDefinitions/WorkflowBuilder/WorkflowBuilder.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

React Hook useCallback has missing dependencies: 't' and 'workflowLogic'. Either include them or remove the dependency array
workflowDefinition,
workflowMetadata?.description,
handleWorkflowMetadataUpdate,
Expand All @@ -411,6 +412,7 @@
workflowMetadata?.displayName || 'Workflow Builder';
const workflowName = workflowMetadata?.name;

// AI-mode breadcrumb: rendered inside the HeaderShell gradient header.
const breadcrumb = useMemo(
() => (
<HeaderBreadcrumb
Expand All @@ -418,7 +420,7 @@
items={[
getGlossaryHomeCrumb(t),
{
label: t('label.workflow-plural'),

Check warning on line 423 in openmetadata-ui/src/main/resources/ui/src/pages/WorkflowDefinitions/WorkflowBuilder/WorkflowBuilder.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

Define a constant instead of duplicating this literal 3 times
href: getWorkflowDefinitionsListPath(),
},
{ label: workflowDisplayName },
Expand All @@ -429,6 +431,18 @@
[workflowDisplayName, t]
);

// Classic-mode breadcrumb: the legacy TitleBreadcrumb shown above the header.
const breadcrumbs = useMemo(
() => [
{
activeTitle: false,
name: t('label.workflow-plural'),
url: getWorkflowDefinitionsListPath(),
},
],
[t]
);

if (loading) {
return <Loader />;
}
Expand Down Expand Up @@ -462,14 +476,20 @@
'tw:flex tw:flex-1 tw:min-h-0 tw:flex-col tw:overflow-hidden',
{ 'tw:bg-gray-50': !isAiMode }
)}>
{!isAiMode && (
<div className="tw:mb-4 tw:shrink-0">
<TitleBreadcrumb titleLinks={breadcrumbs} />
</div>
)}
<div className="tw:shrink-0">
<WorkflowHeader
breadcrumb={breadcrumb}
breadcrumb={isAiMode ? breadcrumb : undefined}
handleDeleteWorkflow={handleShowDeleteModal}
handleRevertAndCancel={handleRevertAndCancel}
handleRunWorkflow={handleRunWorkflow}
handleSaveWorkflow={handleSaveWorkflowWithSnapshot}
handleTestWorkflow={handleTestWorkflow}
isAiMode={isAiMode}
isRunLoading={isRunLoading}
title={workflowDisplayName}
workflowName={workflowName}
Expand Down Expand Up @@ -508,7 +528,7 @@
isNodeDragEnabled={
canDragNodes
? isNodeDragEnabledWrapper
: canDragNodesInViewMode

Check warning on line 531 in openmetadata-ui/src/main/resources/ui/src/pages/WorkflowDefinitions/WorkflowBuilder/WorkflowBuilder.tsx

View workflow job for this annotation

GitHub Actions / checkstyle

Extract this nested ternary operation into an independent statement
? () => true
: () => false
}
Expand Down
Loading