Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,36 @@ jest.mock('@openmetadata/ui-core-components', () => ({
}) => <span {...rest}>{children}</span>,
}));

jest.mock('../../common/HeaderShell/HeaderShell.component', () => ({
__esModule: true,
default: ({
breadcrumb,
leading,
title,
subtitle,
badge,
actions,
'data-testid': dataTestId,
}: {
breadcrumb?: React.ReactNode;
leading?: React.ReactNode;
title?: React.ReactNode;
subtitle?: React.ReactNode;
badge?: React.ReactNode;
actions?: React.ReactNode;
'data-testid'?: string;
}) => (
<div data-testid={dataTestId}>
{breadcrumb}
{leading}
{title}
{badge}
{subtitle}
{actions}
</div>
),
}));

jest.mock('../../../assets/svg/edit-new.svg', () => ({
ReactComponent: () => null,
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import {
Badge,
Button,
Card,
Dialog,
Input,
Modal,
Expand All @@ -28,12 +27,14 @@ import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
import { ReactComponent as WorkflowIcon } from '../../../assets/svg/workflow.svg';
import HeaderShell from '../../common/HeaderShell/HeaderShell.component';
import { useWorkflowModeContext } from '../../../contexts/WorkflowModeContext';
import { WorkflowHeaderProps } from '../../../interface/workflow-builder-components.interface';
import { showErrorToast } from '../../../utils/ToastUtils';
import { WorkflowControls } from './WorkflowControls';

export const WorkflowHeader: React.FC<WorkflowHeaderProps> = ({
breadcrumb,
title,
workflowName,
handleTestWorkflow,
Expand Down Expand Up @@ -89,89 +90,96 @@ export const WorkflowHeader: React.FC<WorkflowHeaderProps> = ({
};

return (
<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">
<>
<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>

<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>
{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}
/>
)}
</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
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>
)}
</div>
</div>
}
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="h3"
className="tw:m-0 tw:text-primary"
data-testid="workflow-title"
size="text-xl"
weight="semibold">
{title}
</Typography>
}
variant="gradient"
/>

<ModalOverlay isOpen={isEditModalOpen} onOpenChange={setIsEditModalOpen}>
<Modal>
Expand Down Expand Up @@ -209,6 +217,6 @@ export const WorkflowHeader: React.FC<WorkflowHeaderProps> = ({
</Dialog>
</Modal>
</ModalOverlay>
</Card>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ export interface WorkflowControlsProps {
}

export interface WorkflowHeaderProps {
breadcrumb?: React.ReactNode;
title: string;
workflowName?: string;
children?: React.ReactNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import { useTranslation } from 'react-i18next';
import { Navigate } from 'react-router-dom';
import { Edge, Node, ReactFlowProvider } from 'reactflow';
import DeleteModal from '../../../components/common/DeleteModal/DeleteModal';
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 All @@ -48,6 +49,7 @@ import {
WorkflowModeProvider,
} from '../../../contexts/WorkflowModeContext';
import { NodeType } from '../../../generated/governance/workflows/elements/nodeType';
import { useIsAiMode } from '../../../hooks/useAppMode';
import { useFqn } from '../../../hooks/useFqn';
import { useWorkflowActions } from '../../../hooks/useWorkflowActions';
import { useWorkflowHistory } from '../../../hooks/useWorkflowHistory';
Expand All @@ -73,6 +75,7 @@ const WorkflowBuilderInternal: React.FC<WorkflowBuilderInternalProps> = ({
workflowLogic,
}) => {
const { t } = useTranslation();
const isAiMode = useIsAiMode();
const {
canAccessSidebar,
canDragNodes,
Expand Down Expand Up @@ -408,15 +411,23 @@ const WorkflowBuilderInternal: React.FC<WorkflowBuilderInternalProps> = ({
workflowMetadata?.displayName || 'Workflow Builder';
const workflowName = workflowMetadata?.name;

const breadcrumbs = useMemo(() => {
return [
{
activeTitle: false,
name: t('label.workflow-plural'),
url: getWorkflowDefinitionsListPath(),
},
];
}, [workflowDisplayName, t]);
const breadcrumb = useMemo(
() => (
<HeaderBreadcrumb
noMargin
items={[
getGlossaryHomeCrumb(t),
{
label: t('label.workflow-plural'),
href: getWorkflowDefinitionsListPath(),
},
{ label: workflowDisplayName },
]}
showHome={false}
/>
),
Comment thread
anuj-kumary marked this conversation as resolved.
[workflowDisplayName, t]
);

if (loading) {
return <Loader />;
Expand All @@ -440,18 +451,20 @@ const WorkflowBuilderInternal: React.FC<WorkflowBuilderInternalProps> = ({
height: 'calc(100vh - var(--ant-navbar-height))',
overflow: 'hidden',
}}
pageTitle={t('label.workflow-plural')}>
pageTitle={t('label.workflow-plural')}
variant={isAiMode ? 'compact' : 'default'}>
{isConnectionModalOpen && (
<div className="tw:fixed tw:inset-0 tw:bg-black/30 tw:z-9999" />
)}

<div className="tw:bg-gray-50 tw:flex tw:flex-1 tw:min-h-0 tw:flex-col tw:overflow-hidden">
<div className="tw:mb-4 tw:shrink-0">
<TitleBreadcrumb titleLinks={breadcrumbs} />
</div>

<div
className={classNames(
'tw:flex tw:flex-1 tw:min-h-0 tw:flex-col tw:overflow-hidden',
{ 'tw:bg-gray-50': !isAiMode }
)}>
<div className="tw:shrink-0">
<WorkflowHeader
breadcrumb={breadcrumb}
handleDeleteWorkflow={handleShowDeleteModal}
handleRevertAndCancel={handleRevertAndCancel}
handleRunWorkflow={handleRunWorkflow}
Expand Down
Loading