Skip to content

Pipeline graph documentation #804

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions apps/design-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"dependencies": {
"@harnessio/ui": "workspace:*",
"@harnessio/yaml-editor": "workspace:*",
"@harnessio/pipeline-graph": "workspace:*",
"clsx": "^2.1.1",
"monaco-editor": "0.50.0",
"react": "^18.3.1",
Expand Down
12 changes: 12 additions & 0 deletions apps/design-system/src/pages/view-preview/view-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { RepoSettingsViewWrapper } from '@/pages/view-preview/repo-settings-view
import ExecutionListWrapper from '@subjects/views/execution-list/execution-list'
import { ProjectLabelsList } from '@subjects/views/labels/project-labels-list'
import { RepoLabelsList } from '@subjects/views/labels/repo-labels-list'
import PipelineGraphWrapper from '@subjects/views/pipeline-graph/pipeline-graph'
import PipelineGraphMinimalWrapper from '@subjects/views/pipeline-graph/pipeline-graph-minimal'
import PipelineListWrapper from '@subjects/views/pipeline-list/pipeline-list'
import PullRequestCompareWrapper from '@subjects/views/pull-request-compare/pull-request-compare'
import PullRequestChanges from '@subjects/views/pull-request-conversation/pull-request-changes'
Expand Down Expand Up @@ -132,6 +134,16 @@ export const viewPreviews: Record<string, ReactNode> = {
<PipelineListWrapper />
</RepoViewWrapper>
),
'pipeline-graph': (
<RepoViewWrapper>
<PipelineGraphWrapper />
</RepoViewWrapper>
),
'pipeline-graph-minimal': (
<RepoViewWrapper>
<PipelineGraphMinimalWrapper />
</RepoViewWrapper>
),
'execution-list': (
<RepoViewWrapper>
<ExecutionListWrapper />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import {
AnyContainerNodeType,
CanvasProvider,
ContainerNode,
LeafNodeInternalType,
NodeContent,
ParallelNodeContent,
ParallelNodeInternalType,
PipelineGraph,
SerialNodeContent,
SerialNodeInternalType
} from '@harnessio/pipeline-graph'
import { Icon, Text } from '@harnessio/ui/components'

// *****************************************************
// 1. Import CSS
// *****************************************************

import '@harnessio/pipeline-graph/dist/index.css'

// *****************************************************
// 2. Define content nodes types
// *****************************************************

export enum ContentNodeTypes {
step = 'step',
parallel = 'parallel',
serial = 'serial'
}

// *****************************************************
// 3. Define nodes
// *****************************************************

// * step node
export interface StepNodeDataType {
name?: string
icon?: React.ReactElement
selected?: boolean
}

export function StepNodeComponent({ node }: { node: LeafNodeInternalType<StepNodeDataType> }) {
const { name, icon } = node.data

return (
<div className={'bg-primary-foreground border-borders-2 box-border size-full rounded-xl border'}>
<div>{icon}</div>
<Text title={name} className="text-primary m-2 line-clamp-2 cursor-default">
{name}
</Text>
</div>
)
}

// * serial group node
export interface SerialGroupNodeDataType {
name?: string
selected?: boolean
}

export function SerialGroupNodeComponent({
node,
children
}: {
node: SerialNodeInternalType<SerialGroupNodeDataType>
children: React.ReactElement
}) {
const { name } = node.data

return (
<>
<div className="border-borders-2 absolute inset-0 -z-10 rounded-xl border" />
<div className="absolute inset-x-0 top-0 h-0">
<div title={name} className="text-primary-muted h-9 cursor-default truncate px-9 pt-2.5">
{name}
</div>
</div>

{children}
</>
)
}

// * parallel group node
export interface ParallelGroupNodeDataType {
name?: string
selected?: boolean
}

export function ParallelGroupNodeComponent({
node,
children
}: {
node: ParallelNodeInternalType<ParallelGroupNodeDataType>
children: React.ReactElement
}) {
const { name } = node.data

return (
<>
<div className="border-borders-2 absolute inset-0 -z-10 rounded-xl border" />
<div className="absolute inset-x-0 top-0 h-0">
<div title={name} className="text-primary-muted h-9 cursor-default truncate px-9 pt-2.5">
{name}
</div>
</div>

{children}
</>
)
}

// *****************************************************
// 4. Match Content and containers nodes
// *****************************************************

const nodes: NodeContent[] = [
{
type: ContentNodeTypes.serial,
containerType: ContainerNode.serial,
component: SerialGroupNodeComponent
} as SerialNodeContent,
{
type: ContentNodeTypes.parallel,
containerType: ContainerNode.parallel,
component: ParallelGroupNodeComponent
} as ParallelNodeContent,
{
type: ContentNodeTypes.step,
containerType: ContainerNode.leaf,
component: StepNodeComponent
} as NodeContent
]

// *****************************************************
// 5. Graph data model
// *****************************************************

const data: AnyContainerNodeType[] = [
{
type: ContentNodeTypes.step,
data: {
name: 'Step 1',
icon: <Icon name="harness-plugin" className="m-2 size-8" />
} satisfies StepNodeDataType,
config: {
width: 160,
height: 80
}
},
{
type: ContentNodeTypes.serial,
config: {
minWidth: 200,
minHeight: 40
},
data: {
name: 'Serial group'
} satisfies SerialGroupNodeDataType,
children: [
{
type: ContentNodeTypes.step,
data: {
name: 'Step 2',
icon: <Icon name="harness-plugin" className="m-2 size-8" />
} satisfies StepNodeDataType,
config: {
width: 160,
height: 80
}
},
{
type: ContentNodeTypes.step,
data: {
name: 'Step 3',
icon: <Icon name="harness-plugin" className="m-2 size-8" />
} satisfies StepNodeDataType,
config: {
width: 160,
height: 80
}
}
]
},
{
type: ContentNodeTypes.parallel,
config: {
minWidth: 200,
minHeight: 40
},
data: {
name: 'Parallel group'
} satisfies ParallelGroupNodeDataType,
children: [
{
type: ContentNodeTypes.step,
data: {
name: 'Step 4',
icon: <Icon name="harness-plugin" className="m-2 size-8" />
} satisfies StepNodeDataType,
config: {
width: 160,
height: 80
}
},
{
type: ContentNodeTypes.step,
data: {
name: 'Step 4',
icon: <Icon name="harness-plugin" className="m-2 size-8" />
} satisfies StepNodeDataType,
config: {
width: 160,
height: 80
}
}
]
}
]

const PipelineGraphMinimalWrapper = () => {
return (
<CanvasProvider>
<PipelineGraph data={data} nodes={nodes} config={{ edgeClassName: 'stroke-borders-2' }} />
</CanvasProvider>
)
}

export default PipelineGraphMinimalWrapper
Loading