From 76ed655bdb9bc16c5f97b0c12dbbc4b09017e4b2 Mon Sep 17 00:00:00 2001 From: Srdjan Arsic Date: Wed, 26 Feb 2025 17:14:19 +0100 Subject: [PATCH 1/6] unified pipeline studio view component --- .../pages/view-preview/root-view-wrapper.tsx | 2 +- .../src/pages/view-preview/view-preview.tsx | 8 +- .../pipeline-edit/canvas/canvas-button.tsx | 14 - .../pipeline-edit/canvas/canvas-controls.tsx | 15 - .../stage-group-add-in-node-context-menu.tsx | 57 - .../stage-group-node-context-menu.tsx | 92 - .../context-menu/stage-node-context-menu.tsx | 71 - .../step-group-node-context-menu.tsx | 71 - .../context-menu/step-node-context-menu.tsx | 71 - .../hooks/useAnimatePipeline.tsx | 88 - .../mocks/animations/demoExecutionMock.tsx | 236 - .../pipeline-edit/mocks/demoExecutionMock.tsx | 236 - .../views/pipeline-edit/mocks/demoPSYaml.tsx | 33 - .../mocks/pipelineExecutionMock.tsx | 433 - .../pipeline-edit/mocks/pipelineYaml1.ts | 24 - .../pipeline-edit/mocks/pipelineYaml2.ts | 11 - .../views/pipeline-edit/nodes-factory.tsx | 66 - .../nodes/custim-add-content-node.tsx | 23 - .../nodes/custom-end-content-node.tsx | 9 - ...stom-parallel-stage-group-content-node.tsx | 63 - ...ustom-parallel-step-group-content-node.tsx | 62 - ...custom-serial-stage-group-content-node.tsx | 63 - .../custom-serial-step-group-content-node.tsx | 62 - .../nodes/custom-stage-content-node.tsx | 61 - .../nodes/custom-start-content-node.tsx | 9 - .../views/pipeline-edit/nodes/types.ts | 7 - .../views/pipeline-edit/pipeline-edit.tsx | 162 - .../pipeline-edit/pipeline-execution.tsx | 69 - .../pipeline-edit/pipeline-nodes/add-node.tsx | 24 - .../components/floating-add-button.tsx | 75 - .../pipeline-edit/pipeline-nodes/end-node.tsx | 9 - .../pipeline-edit/pipeline-nodes/index.ts | 17 - .../pipeline-nodes/parallel-group-node.tsx | 103 - .../pipeline-nodes/serial-group-node.tsx | 103 - .../pipeline-nodes/stage-node.tsx | 103 - .../pipeline-nodes/start-node.tsx | 9 - .../pipeline-nodes/step-node.tsx | 103 - .../views/pipeline-edit/types/common.ts | 4 - .../pipeline-edit/utils/step-icon-utils.tsx | 41 - .../views/pipeline-edit/utils/utils.ts | 49 - .../pipeline-graph/pipeline-graph-minimal.tsx | 8 +- .../views/pipeline-graph/pipeline-graph.tsx | 7 +- .../unified-pipeline-studio/mocks/pipeline.ts | 19 + .../unified-pipeline-studio.store.ts | 28 + .../unified-pipeline-studio.tsx | 18 + packages/ui/package.json | 1 + .../src/components/form-primitives/label.tsx | 17 +- packages/ui/src/components/form.tsx | 166 + .../components/pipeline-nodes/add-node.tsx | 3 +- .../components/collapse-button.tsx | 6 +- .../components/collapsed-group-node.tsx | 26 +- .../pipeline-nodes/components/custom-port.tsx | 0 .../components/execution-status.tsx | 17 +- .../components/floating-add-button.tsx | 32 +- .../pipeline-nodes/components/index.ts | 7 + .../components/node-menu-trigger.tsx | 5 +- .../pipeline-nodes/components/node-title.tsx | 4 +- .../components/warning-label.tsx | 4 +- .../components/pipeline-nodes/end-node.tsx | 7 +- .../ui/src/components/pipeline-nodes/index.ts | 4 +- .../pipeline-nodes/parallel-group-node.tsx | 69 +- .../pipeline-nodes/serial-group-node.tsx | 69 +- .../components/pipeline-nodes/stage-node.tsx | 66 +- .../components/pipeline-nodes/start-node.tsx | 6 +- .../components}/pipeline-nodes/step-node.css | 4 +- .../components/pipeline-nodes/step-node.tsx | 137 +- .../ui/src/components/pipeline-nodes/types.ts | 3 - .../components/pipeline-nodes/types/types.ts | 1 + packages/ui/src/components/resizable.tsx | 37 + packages/ui/src/views/index.ts | 4 +- .../nodes/step-content-node.tsx | 51 - .../utils/common-step-utils.ts | 9 - .../components/pipeline-studio-graph-view.tsx | 108 - .../components/pipeline-studio-internal.tsx | 72 - packages/ui/src/views/pipeline-edit/index.ts | 22 - .../src/views/pipeline-edit/pipeline-edit.tsx | 176 - .../views/pipeline-edit/pipeline-studio.tsx | 58 - .../entity-form/entity-form-layout.tsx | 27 + .../entity-form-section-layout.tsx | 23 + .../unified-pipeline-studio-entity-form.tsx | 195 + .../components/form-inputs/ArrayInput.tsx | 105 + .../components/form-inputs/BooleanInput.tsx | 52 + .../components/form-inputs/GroupInput.tsx | 65 + .../components/form-inputs/ListInput.tsx | 133 + .../components/form-inputs/NumberInput.tsx | 43 + .../components/form-inputs/SelectInput.tsx | 66 + .../components/form-inputs/Separator.tsx | 21 + .../components/form-inputs/TextAreaInput.tsx | 43 + .../components/form-inputs/TextInput.tsx | 43 + .../form-inputs/common/InputError.tsx | 21 + .../form-inputs/common/InputLabel.tsx | 30 + .../form-inputs/common/InputWrapper.tsx | 5 + .../components/form-inputs/common/Layout.tsx | 22 + .../components/form-inputs/factory/factory.ts | 24 + .../components/form-inputs/types.ts | 30 + .../canvas/canvas-button.tsx | 0 .../canvas/canvas-controls.tsx | 0 .../graph-implementation/config/config.ts | 15 + .../stage-group-add-in-node-context-menu.tsx | 2 +- .../stage-group-node-context-menu.tsx | 2 +- .../context-menu/stage-node-context-menu.tsx | 2 +- .../step-group-node-context-menu.tsx | 2 +- .../context-menu/step-node-context-menu.tsx | 2 +- .../UnifiedPipelineStudioNodeContext.tsx} | 29 +- .../factory/content-node-bank.ts | 64 + .../factory/content-node-factory.ts | 23 + .../nodes/add-content-node.tsx | 2 +- .../nodes/end-content-node.tsx | 0 .../parallel-stage-group-content-node.tsx | 28 +- .../parallel-step-group-content-node.tsx | 32 +- .../nodes/serial-stage-group-content-node.tsx | 30 +- .../nodes/serial-step-group-content-node.tsx | 32 +- .../nodes/stage-content-node.tsx | 29 +- .../nodes/start-content-node.tsx | 0 .../nodes/step-content-node.tsx | 24 +- .../types/common-node-data-type.ts | 3 + .../types/content-node-type.ts | 0 .../types/yaml-entity-type.ts | 0 .../utils/common-step-utils.ts | 3 +- .../utils/problems-utils.tsx | 0 .../utils/step-icon-utils.tsx | 0 .../utils/step-name-utils.ts | 0 .../utils/yaml-to-pipeline-graph.tsx | 0 .../components/step-form-layout.tsx | 27 + .../step-palette-content-layout.tsx | 29 + .../components/step-palette-item-layout.tsx | 33 + .../components/step-palette-layout.tsx | 15 + .../components/step-palette-section.tsx | 45 + .../components/palette-drawer/types/types.ts | 9 + .../uinfied-pipeline-step-palette-drawer.tsx | 98 + ...unified-pipeline-studio-problems-panel.tsx | 22 + .../components/steps/action-step.tsx | 102 + .../components/steps/approval-step.tsx | 73 + .../components/steps/background-step.tsx | 8 + .../components/steps/barrier-step.tsx | 19 + .../components/steps/group.ts | 12 + .../components/steps/harness-steps.tsx | 112 + .../components/steps/parallel.ts | 12 + .../steps/partials/container-partial.ts | 231 + .../components/steps/queue-step.tsx | 31 + .../components/steps/run-step.tsx | 99 + .../components/steps/run-test-step.tsx | 130 + .../components/steps/types.ts | 39 + .../unified-pipeline-right-drawer.tsx | 57 + .../unified-pipeline-studio-footer.tsx} | 22 +- .../unified-pipeline-studio-graph-view.tsx | 82 + .../unified-pipeline-studio-internal.tsx | 9 + .../unified-pipeline-studio-layout.tsx | 40 + ...ied-pipeline-studio-node-context-menu.tsx} | 2 +- .../unified-pipeline-studio-panel.tsx | 45 + .../unified-pipeline-studio-yaml-view.tsx} | 148 +- .../unified-popover-commit-info.tsx} | 0 .../components/visual-yaml-toggle.tsx | 0 .../unified-pipeline-studio-context.tsx | 200 + .../views/unified-pipeline-studio/index.ts | 1 + .../schema/unified-schema.json} | 0 .../theme/monaco-theme.ts | 0 .../types/common-types.ts | 15 + .../types/right-drawer-types.ts | 5 + .../unified-pipeline-studio-internal.tsx | 42 + .../unified-pipeline-studio.tsx | 97 + .../utils/__tests__/yaml-mocks/pipeline1.ts | 0 .../utils/__tests__/yaml-mocks/pipeline2.ts | 0 .../utils/__tests__/yaml-mocks/pipeline3.ts | 0 .../utils/__tests__/yaml-mocks/pipeline4.ts | 0 .../utils/__tests__/yaml-mocks/pipeline5.ts | 0 .../utils/__tests__/yaml-utils.test.ts | 0 .../utils/common-utils.ts | 0 .../utils/entity-form-utils.ts | 14 + .../utils/inline-actions.ts | 8 + .../utils/yaml-doc-utils.ts | 0 .../utils/yaml-utils.ts | 0 pnpm-lock.yaml | 8432 ++++++++++------- 173 files changed, 8908 insertions(+), 6758 deletions(-) delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/canvas/canvas-button.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/canvas/canvas-controls.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-group-add-in-node-context-menu.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-group-node-context-menu.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-node-context-menu.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/context-menu/step-group-node-context-menu.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/context-menu/step-node-context-menu.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/hooks/useAnimatePipeline.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/mocks/animations/demoExecutionMock.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/mocks/demoExecutionMock.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/mocks/demoPSYaml.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineExecutionMock.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineYaml1.ts delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineYaml2.ts delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes-factory.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/custim-add-content-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-end-content-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-parallel-stage-group-content-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-parallel-step-group-content-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-serial-stage-group-content-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-serial-step-group-content-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-stage-content-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-start-content-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/nodes/types.ts delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-edit.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-execution.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/add-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/floating-add-button.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/end-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/index.ts delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/parallel-group-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/serial-group-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/stage-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/start-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/step-node.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/types/common.ts delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/utils/step-icon-utils.tsx delete mode 100644 apps/design-system/src/subjects/views/pipeline-edit/utils/utils.ts create mode 100644 apps/design-system/src/subjects/views/unified-pipeline-studio/mocks/pipeline.ts create mode 100644 apps/design-system/src/subjects/views/unified-pipeline-studio/unified-pipeline-studio.store.ts create mode 100644 apps/design-system/src/subjects/views/unified-pipeline-studio/unified-pipeline-studio.tsx create mode 100644 packages/ui/src/components/form.tsx rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/components}/pipeline-nodes/components/collapse-button.tsx (68%) rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/components}/pipeline-nodes/components/collapsed-group-node.tsx (72%) rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/components}/pipeline-nodes/components/custom-port.tsx (100%) rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/components}/pipeline-nodes/components/execution-status.tsx (67%) create mode 100644 packages/ui/src/components/pipeline-nodes/components/index.ts rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/components}/pipeline-nodes/components/node-menu-trigger.tsx (77%) rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/components}/pipeline-nodes/components/node-title.tsx (71%) rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/components}/pipeline-nodes/components/warning-label.tsx (55%) rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/components}/pipeline-nodes/step-node.css (89%) delete mode 100644 packages/ui/src/components/pipeline-nodes/types.ts create mode 100644 packages/ui/src/components/pipeline-nodes/types/types.ts create mode 100644 packages/ui/src/components/resizable.tsx delete mode 100644 packages/ui/src/views/pipeline-edit/components/graph-implementation/nodes/step-content-node.tsx delete mode 100644 packages/ui/src/views/pipeline-edit/components/graph-implementation/utils/common-step-utils.ts delete mode 100644 packages/ui/src/views/pipeline-edit/components/pipeline-studio-graph-view.tsx delete mode 100644 packages/ui/src/views/pipeline-edit/components/pipeline-studio-internal.tsx delete mode 100644 packages/ui/src/views/pipeline-edit/index.ts delete mode 100644 packages/ui/src/views/pipeline-edit/pipeline-edit.tsx delete mode 100644 packages/ui/src/views/pipeline-edit/pipeline-studio.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/entity-form/entity-form-layout.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/entity-form/entity-form-section-layout.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/entity-form/unified-pipeline-studio-entity-form.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/ArrayInput.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/BooleanInput.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/GroupInput.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/ListInput.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/NumberInput.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/SelectInput.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/Separator.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/TextAreaInput.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/TextInput.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/common/InputError.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/common/InputLabel.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/common/InputWrapper.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/common/Layout.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/factory/factory.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/form-inputs/types.ts rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/canvas/canvas-button.tsx (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/canvas/canvas-controls.tsx (100%) create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/graph-implementation/config/config.ts rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/context-menu/stage-group-add-in-node-context-menu.tsx (95%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/context-menu/stage-group-node-context-menu.tsx (97%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/context-menu/stage-node-context-menu.tsx (96%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/context-menu/step-group-node-context-menu.tsx (96%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/context-menu/step-node-context-menu.tsx (96%) rename packages/ui/src/views/{pipeline-edit/components/graph-implementation/context/PipelineStudioNodeContext.tsx => unified-pipeline-studio/components/graph-implementation/context/UnifiedPipelineStudioNodeContext.tsx} (79%) create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/graph-implementation/factory/content-node-bank.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/graph-implementation/factory/content-node-factory.ts rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/nodes/add-content-node.tsx (89%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/nodes/end-content-node.tsx (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/nodes/parallel-stage-group-content-node.tsx (67%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/nodes/parallel-step-group-content-node.tsx (62%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/nodes/serial-stage-group-content-node.tsx (64%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/nodes/serial-step-group-content-node.tsx (62%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/nodes/stage-content-node.tsx (62%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/nodes/start-content-node.tsx (100%) rename apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-step-node.tsx => packages/ui/src/views/unified-pipeline-studio/components/graph-implementation/nodes/step-content-node.tsx (67%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/types/common-node-data-type.ts (61%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/types/content-node-type.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/types/yaml-entity-type.ts (100%) rename {apps/design-system/src/subjects/views/pipeline-edit => packages/ui/src/views/unified-pipeline-studio/components/graph-implementation}/utils/common-step-utils.ts (94%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/utils/problems-utils.tsx (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/utils/step-icon-utils.tsx (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/utils/step-name-utils.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/graph-implementation/utils/yaml-to-pipeline-graph.tsx (100%) create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/palette-drawer/components/step-form-layout.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/palette-drawer/components/step-palette-content-layout.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/palette-drawer/components/step-palette-item-layout.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/palette-drawer/components/step-palette-layout.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/palette-drawer/components/step-palette-section.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/palette-drawer/types/types.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/palette-drawer/uinfied-pipeline-step-palette-drawer.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/panel/unified-pipeline-studio-problems-panel.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/action-step.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/approval-step.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/background-step.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/barrier-step.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/group.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/harness-steps.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/parallel.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/partials/container-partial.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/queue-step.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/run-step.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/run-test-step.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/steps/types.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/unified-pipeline-right-drawer.tsx rename packages/ui/src/views/{pipeline-edit/components/pipeline-studio-footer.tsx => unified-pipeline-studio/components/unified-pipeline-studio-footer.tsx} (82%) create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/unified-pipeline-studio-graph-view.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/unified-pipeline-studio-internal.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/unified-pipeline-studio-layout.tsx rename packages/ui/src/views/{pipeline-edit/components/pipeline-studio-node-context-menu.tsx => unified-pipeline-studio/components/unified-pipeline-studio-node-context-menu.tsx} (83%) create mode 100644 packages/ui/src/views/unified-pipeline-studio/components/unified-pipeline-studio-panel.tsx rename packages/ui/src/views/{pipeline-edit/components/pipeline-studio-yaml-view.tsx => unified-pipeline-studio/components/unified-pipeline-studio-yaml-view.tsx} (52%) rename packages/ui/src/views/{pipeline-edit/components/popover-commit-info.tsx => unified-pipeline-studio/components/unified-popover-commit-info.tsx} (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/components/visual-yaml-toggle.tsx (100%) create mode 100644 packages/ui/src/views/unified-pipeline-studio/context/unified-pipeline-studio-context.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/index.ts rename packages/ui/src/views/{pipeline-edit/schema/unifiedSchema.json => unified-pipeline-studio/schema/unified-schema.json} (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/theme/monaco-theme.ts (100%) create mode 100644 packages/ui/src/views/unified-pipeline-studio/types/common-types.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/types/right-drawer-types.ts create mode 100644 packages/ui/src/views/unified-pipeline-studio/unified-pipeline-studio-internal.tsx create mode 100644 packages/ui/src/views/unified-pipeline-studio/unified-pipeline-studio.tsx rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/__tests__/yaml-mocks/pipeline1.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/__tests__/yaml-mocks/pipeline2.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/__tests__/yaml-mocks/pipeline3.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/__tests__/yaml-mocks/pipeline4.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/__tests__/yaml-mocks/pipeline5.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/__tests__/yaml-utils.test.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/common-utils.ts (100%) create mode 100644 packages/ui/src/views/unified-pipeline-studio/utils/entity-form-utils.ts rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/inline-actions.ts (95%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/yaml-doc-utils.ts (100%) rename packages/ui/src/views/{pipeline-edit => unified-pipeline-studio}/utils/yaml-utils.ts (100%) diff --git a/apps/design-system/src/pages/view-preview/root-view-wrapper.tsx b/apps/design-system/src/pages/view-preview/root-view-wrapper.tsx index 69909c7c82..5e59bc96cb 100644 --- a/apps/design-system/src/pages/view-preview/root-view-wrapper.tsx +++ b/apps/design-system/src/pages/view-preview/root-view-wrapper.tsx @@ -59,7 +59,7 @@ const RootViewWrapper: FC> = ({ childre items={settingsMenu} /> -
+
diff --git a/apps/design-system/src/pages/view-preview/view-preview.tsx b/apps/design-system/src/pages/view-preview/view-preview.tsx index cecbe3a7b2..23d010fcd6 100644 --- a/apps/design-system/src/pages/view-preview/view-preview.tsx +++ b/apps/design-system/src/pages/view-preview/view-preview.tsx @@ -10,7 +10,6 @@ import ExecutionListWrapper from '@subjects/views/execution-list/execution-list' import { LabelsForm } from '@subjects/views/labels/labels-form' import { ProjectLabelsList } from '@subjects/views/labels/project-labels-list' import { RepoLabelsList } from '@subjects/views/labels/repo-labels-list' -import PipelineStudioWrapper from '@subjects/views/pipeline-edit/pipeline-edit' 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' @@ -41,6 +40,7 @@ import { RepoWebhooksList } from '@subjects/views/repo-webhooks-list/repo-webhoo import { SignInView } from '@subjects/views/signin' import { SignUpView } from '@subjects/views/signup' import { SpaceSettingsMembers } from '@subjects/views/space-settings-members/space-settings-members' +import UnifiedPipelineStudioWrapper from '@subjects/views/unified-pipeline-studio/unified-pipeline-studio' import { useTranslationStore } from '@utils/viewUtils' import { ChatEmptyPreviewWrapper, ChatPreviewWrapper } from '@harnessio/ui/components' @@ -276,9 +276,9 @@ export const viewPreviews: Record = { ) }, - 'pipeline-studio': { - label: 'Pipeline Studio', - element: + 'unified-pipeline-studio': { + label: 'Unified Pipeline Studio', + element: }, 'pipeline-graph': { label: 'Pipeline Graph', diff --git a/apps/design-system/src/subjects/views/pipeline-edit/canvas/canvas-button.tsx b/apps/design-system/src/subjects/views/pipeline-edit/canvas/canvas-button.tsx deleted file mode 100644 index 88d020662c..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/canvas/canvas-button.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export function CanvasButton(props: React.PropsWithChildren<{ onClick: () => void }>) { - const { children, onClick } = props - - return ( -
- {children} -
- ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/canvas/canvas-controls.tsx b/apps/design-system/src/subjects/views/pipeline-edit/canvas/canvas-controls.tsx deleted file mode 100644 index fa539b73de..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/canvas/canvas-controls.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useCanvasContext } from '@harnessio/pipeline-graph' - -import { CanvasButton } from './canvas-button' - -export function CanvasControls() { - const { reset } = useCanvasContext() - - return ( -
- reset()}> -
-
-
- ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-group-add-in-node-context-menu.tsx b/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-group-add-in-node-context-menu.tsx deleted file mode 100644 index ebe3021d57..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-group-add-in-node-context-menu.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { DropdownMenu, Icon, Text } from '@harnessio/ui/components' -import { usePipelineStudioNodeContext, YamlEntityType } from '@harnessio/ui/views' - -export const StageGroupAddInNodeContextMenu = () => { - const { contextMenuData, onAddIntention, hideContextMenu } = usePipelineStudioNodeContext() - - if (!contextMenuData) return null - - return ( - { - if (open === false) { - hideContextMenu() - } - }} - > - - { - onAddIntention(contextMenuData.nodeData, 'in', YamlEntityType.Stage) - }} - > - - Add Stage - - - { - onAddIntention(contextMenuData.nodeData, 'in', YamlEntityType.SerialStageGroup) - }} - > - - Add Serial group - - { - onAddIntention(contextMenuData.nodeData, 'in', YamlEntityType.ParallelStageGroup) - }} - > - - Add Parallel group - - - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-group-node-context-menu.tsx b/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-group-node-context-menu.tsx deleted file mode 100644 index 7ca0b6188b..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-group-node-context-menu.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { DropdownMenu, Icon, Text } from '@harnessio/ui/components' -import { usePipelineStudioNodeContext, YamlEntityType } from '@harnessio/ui/views' - -export const StageGroupNodeContextMenu = () => { - const { contextMenuData, onAddIntention, hideContextMenu, onEditIntention, onDeleteIntention } = - usePipelineStudioNodeContext() - - if (!contextMenuData) return null - - return ( - { - if (open === false) { - hideContextMenu() - } - }} - > - - { - onEditIntention(contextMenuData.nodeData) - }} - > - - Edit - - - { - onAddIntention(contextMenuData.nodeData, 'before', YamlEntityType.SerialStageGroup) - }} - > - - Add Serial Stages Group before - - { - onAddIntention(contextMenuData.nodeData, 'after', YamlEntityType.SerialStageGroup) - }} - > - - Add Serial Stages Group after - - - { - onAddIntention(contextMenuData.nodeData, 'before', YamlEntityType.ParallelStageGroup) - }} - > - - Add Parallel Stages Group before - - { - onAddIntention(contextMenuData.nodeData, 'after', YamlEntityType.ParallelStageGroup) - }} - > - - Add Parallel Stages Group after - - - {/* */} - {/* */} - { - onDeleteIntention(contextMenuData.nodeData) - }} - > - - Delete - - - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-node-context-menu.tsx b/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-node-context-menu.tsx deleted file mode 100644 index 34bbed2376..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/stage-node-context-menu.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { DropdownMenu, Icon, Text } from '@harnessio/ui/components' -import { usePipelineStudioNodeContext, YamlEntityType } from '@harnessio/ui/views' - -export const StageNodeContextMenu = (): (() => React.ReactNode)[] | null | any => { - const { contextMenuData, onAddIntention, hideContextMenu, onEditIntention, onDeleteIntention } = - usePipelineStudioNodeContext() - - if (!contextMenuData) return null - - return ( - { - if (open === false) { - hideContextMenu() - } - }} - > - - { - onEditIntention(contextMenuData.nodeData) - }} - > - - Edit - - - { - onAddIntention(contextMenuData.nodeData, 'before', YamlEntityType.Stage) // TODO what to add - }} - > - - Add stage before - - { - onAddIntention(contextMenuData.nodeData, 'after', YamlEntityType.Stage) // TODO what to add - }} - > - - Add stage after - - - {/* */} - {/* */} - { - onDeleteIntention(contextMenuData.nodeData) - }} - > - - Delete - - - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/step-group-node-context-menu.tsx b/apps/design-system/src/subjects/views/pipeline-edit/context-menu/step-group-node-context-menu.tsx deleted file mode 100644 index 1c5009f5ba..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/step-group-node-context-menu.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { DropdownMenu, Icon, Text } from '@harnessio/ui/components' -import { usePipelineStudioNodeContext } from '@harnessio/ui/views' - -export const StepGroupNodeContextMenu = () => { - const { contextMenuData, onAddIntention, hideContextMenu, onEditIntention, onDeleteIntention } = - usePipelineStudioNodeContext() - - if (!contextMenuData) return null - - return ( - { - if (open === false) { - hideContextMenu() - } - }} - > - - { - onEditIntention(contextMenuData.nodeData) - }} - > - - Edit - - - { - onAddIntention(contextMenuData.nodeData, 'before') - }} - > - - Add Step/Group before - - { - onAddIntention(contextMenuData.nodeData, 'after') - }} - > - - Add Step/Group after - - - {/* */} - {/* */} - { - onDeleteIntention(contextMenuData.nodeData) - }} - > - - Delete - - - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/step-node-context-menu.tsx b/apps/design-system/src/subjects/views/pipeline-edit/context-menu/step-node-context-menu.tsx deleted file mode 100644 index b1a61b5d48..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/context-menu/step-node-context-menu.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { DropdownMenu, Icon, Text } from '@harnessio/ui/components' -import { usePipelineStudioNodeContext } from '@harnessio/ui/views' - -export const StepNodeContextMenu = (): (() => React.ReactNode)[] | null | any => { - const { contextMenuData, onAddIntention, hideContextMenu, onEditIntention, onDeleteIntention } = - usePipelineStudioNodeContext() - - if (!contextMenuData) return null - - return ( - { - if (open === false) { - hideContextMenu() - } - }} - > - - { - onEditIntention(contextMenuData.nodeData) - }} - > - - Edit - - - { - onAddIntention(contextMenuData.nodeData, 'before') // TODO what to add - }} - > - - Add step/group before - - { - onAddIntention(contextMenuData.nodeData, 'after') // TODO what to add - }} - > - - Add step/group after - - - {/* */} - {/* */} - { - onDeleteIntention(contextMenuData.nodeData) - }} - > - - Delete - - - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/hooks/useAnimatePipeline.tsx b/apps/design-system/src/subjects/views/pipeline-edit/hooks/useAnimatePipeline.tsx deleted file mode 100644 index 602693948b..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/hooks/useAnimatePipeline.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { useEffect, useState } from 'react' - -import { AnyContainerNodeType, ParallelContainerNodeType, SerialContainerNodeType } from '@harnessio/pipeline-graph' - -import { PipelineNodeStatus } from '../nodes/types' - -export const useAnimatePipeline = ({ - nodes, - delay = 1 -}: { - nodes: AnyContainerNodeType[] - delay?: number -}): { nodes: AnyContainerNodeType[] } => { - const [animatedNodes, setAnimatedNodes] = useState(nodes) - - const updateNodeState = (node: AnyContainerNodeType, state: PipelineNodeStatus) => { - node.data = { ...(node.data ?? {}), state } - } - - const processParallelGroup = (node: ParallelContainerNodeType, callback: () => void) => { - if (!node.children || node.children.length === 0) { - callback() - return - } - - let completedCount = 0 - node.children.forEach(child => { - processStageOrStep(child, () => { - completedCount++ - if (completedCount === node.children!.length) { - updateNodeState(node, PipelineNodeStatus.Success) - setAnimatedNodes([...animatedNodes]) - callback() - } - }) - }) - } - - const processSerialGroup = (node: SerialContainerNodeType, callback: () => void) => { - if (!node.children || node.children.length === 0) { - callback() - return - } - - const processNext = (index: number) => { - if (index >= node.children!.length) { - updateNodeState(node, PipelineNodeStatus.Success) - setAnimatedNodes([...animatedNodes]) - callback() - return - } - - processStageOrStep(node.children![index], () => processNext(index + 1)) - } - - processNext(0) - } - - const processStageOrStep = (node: AnyContainerNodeType, callback: () => void) => { - updateNodeState(node, PipelineNodeStatus.Executing) - setAnimatedNodes([...animatedNodes]) - - setTimeout(() => { - if (node.type === 'ParallelStageGroup') { - processParallelGroup(node as ParallelContainerNodeType, callback) - } else if ((node as SerialContainerNodeType).children && (node as SerialContainerNodeType).children.length > 0) { - processSerialGroup(node as SerialContainerNodeType, callback) - } else { - updateNodeState(node, PipelineNodeStatus.Success) - setAnimatedNodes([...animatedNodes]) - callback() - } - }, delay * 1000) - } - - useEffect(() => { - if (animatedNodes.length === 0) return - - const processNext = (index: number) => { - if (index >= animatedNodes.length) return - processStageOrStep(animatedNodes[index], () => processNext(index + 1)) - } - - processNext(0) - }, [nodes, delay]) - - return { nodes: animatedNodes } -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/mocks/animations/demoExecutionMock.tsx b/apps/design-system/src/subjects/views/pipeline-edit/mocks/animations/demoExecutionMock.tsx deleted file mode 100644 index 2832096481..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/mocks/animations/demoExecutionMock.tsx +++ /dev/null @@ -1,236 +0,0 @@ -import { Icon } from '@harnessio/ui/components' - -export const demoExecutionMock = [ - { - type: 'Start', - config: { - width: 40, - height: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideLeftPort: true - }, - data: {}, - path: 'pipeline.children.0', - containerType: 'leaf' - }, - { - type: 'ParallelStageGroup', - config: { - maxWidth: 200, - minHeight: 50, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0', - yamlChildrenPath: 'pipeline.stages.0.parallel.stages', - yamlEntityType: 'ParallelStageGroup', - name: 'Parallel 1' - // state: 'executing' - }, - children: [ - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 50, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.0', - yamlChildrenPath: 'pipeline.stages.0.parallel.stages.0.steps', - yamlEntityType: 'Stage', - name: 'Stage 1' - // state: 'success' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.0.steps.0', - yamlEntityType: 'Step', - name: 'npm install', - icon: - // state: 'error' - }, - path: 'pipeline.children.1.children.0.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.0.steps.1', - yamlEntityType: 'Step', - name: 'npm test', - icon: , - selected: false - // state: 'executing' - }, - path: 'pipeline.children.1.children.0.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.1.children.0', - containerType: 'serial' - }, - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 50, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.1', - yamlChildrenPath: 'pipeline.stages.0.parallel.stages.1.steps', - yamlEntityType: 'Stage', - name: 'Stage 2' - // state: 'executing' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.1.steps.0', - yamlEntityType: 'Step', - name: 'go build', - icon: , - selected: false - // state: 'warning', - // warningMessage: 'Timeout' - }, - path: 'pipeline.children.1.children.1.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.1.steps.1', - yamlEntityType: 'Step', - name: 'go test -cover', - icon: , - selected: false - // state: 'executing' - }, - path: 'pipeline.children.1.children.1.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.1.children.1', - containerType: 'serial' - } - ], - path: 'pipeline.children.1', - containerType: 'parallel' - }, - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 50, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.1', - yamlChildrenPath: 'pipeline.stages.1.steps', - yamlEntityType: 'Stage', - name: 'Stage 2', - // state: 'success', - warningMessage: 'Timeout' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.1.steps.0', - yamlEntityType: 'Step', - name: 'docker', - icon: , - selected: false - // state: 'warning', - // warningMessage: 'Timeout' - }, - path: 'pipeline.children.2.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.1.steps.1', - yamlEntityType: 'Step', - name: 'Step 2', - icon: , - selected: false - // // state: 'pending' - }, - path: 'pipeline.children.2.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.2', - containerType: 'serial' - }, - { - type: 'End', - config: { - width: 40, - height: 40, - hideDeleteButton: true, - hideAfterAdd: true, - hideRightPort: true - }, - data: {}, - path: 'pipeline.children.3', - containerType: 'leaf' - } -] diff --git a/apps/design-system/src/subjects/views/pipeline-edit/mocks/demoExecutionMock.tsx b/apps/design-system/src/subjects/views/pipeline-edit/mocks/demoExecutionMock.tsx deleted file mode 100644 index 4c83f1a5ce..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/mocks/demoExecutionMock.tsx +++ /dev/null @@ -1,236 +0,0 @@ -import { Icon } from '@harnessio/ui/components' - -export const demoExecutionMock = [ - { - type: 'Start', - config: { - width: 36, - height: 36, - hideDeleteButton: true, - hideBeforeAdd: true, - hideLeftPort: true - }, - data: {}, - path: 'pipeline.children.0', - containerType: 'leaf' - }, - { - type: 'ParallelStageGroup', - config: { - maxWidth: 200, - minHeight: 50, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0', - yamlChildrenPath: 'pipeline.stages.0.parallel.stages', - yamlEntityType: 'ParallelStageGroup', - name: 'Parallel 1', - state: 'executing' - }, - children: [ - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 50, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.0', - yamlChildrenPath: 'pipeline.stages.0.parallel.stages.0.steps', - yamlEntityType: 'Stage', - name: 'Stage 1', - state: 'success' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.0.steps.0', - yamlEntityType: 'Step', - name: 'npm install', - icon: , - state: 'error' - }, - path: 'pipeline.children.1.children.0.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.0.steps.1', - yamlEntityType: 'Step', - name: 'npm test', - icon: , - selected: false, - state: 'executing' - }, - path: 'pipeline.children.1.children.0.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.1.children.0', - containerType: 'serial' - }, - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 50, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.1', - yamlChildrenPath: 'pipeline.stages.0.parallel.stages.1.steps', - yamlEntityType: 'Stage', - name: 'Stage 2', - state: 'executing' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.1.steps.0', - yamlEntityType: 'Step', - name: 'go build', - icon: , - selected: false, - state: 'warning', - warningMessage: 'Timeout' - }, - path: 'pipeline.children.1.children.1.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.parallel.stages.1.steps.1', - yamlEntityType: 'Step', - name: 'go test -cover', - icon: , - selected: false, - state: 'executing' - }, - path: 'pipeline.children.1.children.1.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.1.children.1', - containerType: 'serial' - } - ], - path: 'pipeline.children.1', - containerType: 'parallel' - }, - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 50, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.1', - yamlChildrenPath: 'pipeline.stages.1.steps', - yamlEntityType: 'Stage', - name: 'Stage 2', - state: 'success', - warningMessage: 'Timeout' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.1.steps.0', - yamlEntityType: 'Step', - name: 'docker', - icon: , - selected: false, - state: 'warning', - warningMessage: 'Timeout' - }, - path: 'pipeline.children.2.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.1.steps.1', - yamlEntityType: 'Step', - name: 'Step 2', - icon: , - selected: false, - state: 'success' - }, - path: 'pipeline.children.2.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.2', - containerType: 'serial' - }, - { - type: 'End', - config: { - width: 36, - height: 36, - hideDeleteButton: true, - hideAfterAdd: true, - hideRightPort: true - }, - data: {}, - path: 'pipeline.children.3', - containerType: 'leaf' - } -] diff --git a/apps/design-system/src/subjects/views/pipeline-edit/mocks/demoPSYaml.tsx b/apps/design-system/src/subjects/views/pipeline-edit/mocks/demoPSYaml.tsx deleted file mode 100644 index 72dfb945fa..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/mocks/demoPSYaml.tsx +++ /dev/null @@ -1,33 +0,0 @@ -export const demoPSYaml = `pipeline: - stages: - - parallel: - stages: - - steps: - - run: - container: node - script: npm install - - run: - container: node - script: npm test - - - steps: - - run: - container: golang:1.23 - script: go build - - run: - container: golang:1.23 - script: go test -cover - - - steps: - - template: - uses: docker - with: - connector: connector.dockerhub - repo: harness/petstore - tags: latest - - - template: - uses: slack - with: - channel: general -` diff --git a/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineExecutionMock.tsx b/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineExecutionMock.tsx deleted file mode 100644 index 4da3c08146..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineExecutionMock.tsx +++ /dev/null @@ -1,433 +0,0 @@ -import { Icon } from '@harnessio/ui/components' - -export const serialContainerConfig = { - paddingLeft: 40, - paddingRight: 40, - paddingTop: 69, - paddingBottom: 24, - nodeGap: 40 -} - -export const parallelContainerConfig = { - paddingLeft: 40, - paddingRight: 40, - paddingTop: 69, - paddingBottom: 24, - nodeGap: 40 -} - -export const executionMock = [ - { - type: 'Start', - config: { - width: 40, - height: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideLeftPort: true - }, - data: {}, - path: 'pipeline.children.0', - containerType: 'leaf' - }, - { - type: 'SerialStageGroup', - config: { - minWidth: 200, - minHeight: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0', - yamlChildrenPath: 'pipeline.stages.0.group.stages', - yamlEntityType: 'SerialStageGroup', - name: 'Serial 1', - state: 'executing' - }, - children: [ - { - type: 'ParallelStageGroup', - config: { - minWidth: 200, - minHeight: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.0', - yamlChildrenPath: 'pipeline.stages.0.group.stages.0.parallel.stages', - yamlEntityType: 'ParallelStageGroup', - name: 'Parallel 1', - state: 'executing' - }, - children: [ - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.0.parallel.stages.0', - yamlChildrenPath: 'pipeline.stages.0.group.stages.0.parallel.stages.0.steps', - yamlEntityType: 'Stage', - state: 'success', - name: 'Stage 1' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.0.parallel.stages.0.steps.0', - yamlEntityType: 'Step', - name: 'go build', - icon: , - state: 'success', - selected: false - }, - path: 'pipeline.children.1.children.0.children.0.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.0.parallel.stages.0.steps.1', - yamlEntityType: 'Step', - name: 'go test', - icon: , - state: 'error', - selected: false - }, - path: 'pipeline.children.1.children.0.children.0.children.1', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.0.parallel.stages.0.steps.1', - yamlEntityType: 'Step', - name: 'go test', - icon: , - state: 'executing', - selected: false - }, - path: 'pipeline.children.1.children.0.children.0.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.1.children.0.children.0', - containerType: 'serial' - }, - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.0.parallel.stages.1', - yamlChildrenPath: 'pipeline.stages.0.group.stages.0.parallel.stages.1.steps', - yamlEntityType: 'Stage', - name: 'Stage 2', - state: 'executing' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.0.parallel.stages.1.steps.0', - yamlEntityType: 'Step', - name: 'Software Supply Chain Validation 1', - icon: , - state: 'warning', - selected: false, - warningMessage: 'High memory usage' - }, - path: 'pipeline.children.1.children.0.children.1.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.0.parallel.stages.1.steps.0', - yamlEntityType: 'Step', - name: 'Software Supply Chain Validation 2', - icon: , - state: 'warning', - selected: false, - warningMessage: 'High CPU usage' - }, - path: 'pipeline.children.1.children.0.children.1.children.0', - containerType: 'leaf' - } - ], - path: 'pipeline.children.1.children.0.children.1', - containerType: 'serial' - } - ], - path: 'pipeline.children.1.children.0', - containerType: 'parallel' - }, - { - type: 'SerialStageGroup', - config: { - minWidth: 200, - minHeight: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1', - yamlChildrenPath: 'pipeline.stages.0.group.stages.1.group.stages', - yamlEntityType: 'SerialStageGroup', - name: 'Serial 2', - state: 'success' - }, - children: [ - { - type: 'Stage', - config: { - minWidth: 200, - minHeight: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideAfterAdd: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0', - yamlChildrenPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps', - yamlEntityType: 'Stage', - state: 'warning', - name: 'Stage 1' - }, - children: [ - { - type: 'SerialStepGroup', - config: { - minWidth: 200, - minHeight: 40, - hideDeleteButton: true, - hideCollapseButton: false - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.0', - yamlChildrenPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.0.group.steps', - yamlEntityType: 'SerialStepGroup', - name: 'Serial steps 1', - state: 'executing' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.0.group.steps.0', - yamlEntityType: 'Step', - name: 'multi line step name multi line step name multi line step name multi line step name ', - icon: , - state: 'success', - selected: false - }, - path: 'pipeline.children.1.children.1.children.0.children.0.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.0.group.steps.1', - yamlEntityType: 'Step', - name: 'go test', - icon: , - state: 'executing', - selected: false - }, - path: 'pipeline.children.1.children.1.children.0.children.0.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.1.children.1.children.0.children.0', - containerType: 'serial' - }, - { - type: 'ParallelStepGroup', - config: { - minWidth: 200, - minHeight: 40, - hideDeleteButton: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.1', - yamlChildrenPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.1.parallel.steps', - yamlEntityType: 'ParallelStepGroup', - name: 'Parallel steps 2', - state: 'success' - }, - children: [ - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.1.parallel.steps.0', - yamlEntityType: 'Step', - name: 'go build', - icon: , - state: 'success', - selected: false - }, - path: 'pipeline.children.1.children.1.children.0.children.1.children.0', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.1.parallel.steps.1', - yamlEntityType: 'Step', - name: 'go test', - icon: , - state: 'error', - selected: false - }, - path: 'pipeline.children.1.children.1.children.0.children.1.children.1', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.1.parallel.steps.1', - yamlEntityType: 'Step', - name: 'go test', - icon: , - state: 'executing', - selected: false - }, - path: 'pipeline.children.1.children.1.children.0.children.1.children.1', - containerType: 'leaf' - }, - { - type: 'Step', - config: { - maxWidth: 200, - minHeight: 50, - width: 200, - hideDeleteButton: false, - selectable: true - }, - data: { - yamlPath: 'pipeline.stages.0.group.stages.1.group.stages.0.steps.1.parallel.steps.1', - yamlEntityType: 'Step', - name: 'go test', - icon: , - state: 'success', - selected: false - }, - path: 'pipeline.children.1.children.1.children.0.children.1.children.1', - containerType: 'leaf' - } - ], - path: 'pipeline.children.1.children.1.children.0.children.1', - containerType: 'parallel' - } - ], - path: 'pipeline.children.1.children.1.children.0', - containerType: 'serial' - } - ], - path: 'pipeline.children.1.children.1', - containerType: 'serial' - } - ], - path: 'pipeline.children.1', - containerType: 'serial' - }, - { - type: 'End', - config: { - width: 40, - height: 40, - hideDeleteButton: true, - hideAfterAdd: true, - hideRightPort: true - }, - data: {}, - path: 'pipeline.children.2', - containerType: 'leaf' - } -] diff --git a/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineYaml1.ts b/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineYaml1.ts deleted file mode 100644 index 5b24607e45..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineYaml1.ts +++ /dev/null @@ -1,24 +0,0 @@ -export const pipelineYaml1 = `pipeline: - stages: - - group: - stages: - - parallel: - stages: - - steps: - - run: go build - - run: go test - - steps: - - run: npm test - - group: - stages: - - steps: - - group: - steps: - - run: go build - - run: go test - - - parallel: - steps: - - run: go build - - run: go test -` diff --git a/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineYaml2.ts b/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineYaml2.ts deleted file mode 100644 index 9b07b6cef0..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/mocks/pipelineYaml2.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const pipelineYaml2 = ` -pipeline: - stages: - - group: - stages: [] - - group: - stages: - - steps: [] - - parallel: - stages: [] -` diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes-factory.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes-factory.tsx deleted file mode 100644 index c14d078cf0..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes-factory.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { ContainerNode } from '@harnessio/pipeline-graph' -import { ContentNodeFactory, ContentNodeType } from '@harnessio/ui/views' - -import { CustomEndContentNode } from './nodes/custom-end-content-node' -import { CustomParallelStageGroupContentNode } from './nodes/custom-parallel-stage-group-content-node' -import { CustomSerialStageGroupContentNode } from './nodes/custom-serial-stage-group-content-node' -import { CustomSerialStepGroupContentNode } from './nodes/custom-serial-step-group-content-node' -import { CustomStageContentNode } from './nodes/custom-stage-content-node' -import { CustomStartContentNode } from './nodes/custom-start-content-node' -import { CustomStepContentNode } from './nodes/custom-step-node' - -export const contentNodeFactory = new ContentNodeFactory() - -// --- UI RELATED --- - -contentNodeFactory.registerEntity(ContentNodeType.Start, { - type: ContentNodeType.Start, - component: CustomStartContentNode, - containerType: ContainerNode.leaf -}) - -contentNodeFactory.registerEntity(ContentNodeType.End, { - type: ContentNodeType.End, - component: CustomEndContentNode, - containerType: ContainerNode.leaf -}) - -// --- STEP REPLATED --- - -contentNodeFactory.registerEntity(ContentNodeType.Step, { - type: ContentNodeType.Step, - component: CustomStepContentNode, - containerType: ContainerNode.leaf -}) - -contentNodeFactory.registerEntity(ContentNodeType.ParallelStepGroup, { - type: ContentNodeType.ParallelStepGroup, - component: CustomParallelStageGroupContentNode, - containerType: ContainerNode.parallel -}) - -contentNodeFactory.registerEntity(ContentNodeType.SerialStepGroup, { - type: ContentNodeType.SerialStepGroup, - component: CustomSerialStepGroupContentNode, - containerType: ContainerNode.serial -}) - -// --- STAGE REPLATED --- - -contentNodeFactory.registerEntity(ContentNodeType.Stage, { - type: ContentNodeType.Stage, - component: CustomStageContentNode, - containerType: ContainerNode.serial -}) - -contentNodeFactory.registerEntity(ContentNodeType.ParallelStageGroup, { - type: ContentNodeType.ParallelStageGroup, - component: CustomParallelStageGroupContentNode, - containerType: ContainerNode.parallel -}) - -contentNodeFactory.registerEntity(ContentNodeType.SerialStageGroup, { - type: ContentNodeType.SerialStageGroup, - component: CustomSerialStageGroupContentNode, - containerType: ContainerNode.serial -}) diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custim-add-content-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes/custim-add-content-node.tsx deleted file mode 100644 index d76dc3a740..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custim-add-content-node.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { LeafNodeInternalType } from '@harnessio/pipeline-graph' -import { CommonNodeDataType, usePipelineStudioNodeContext } from '@harnessio/ui/views' - -import { StageGroupAddInNodeContextMenu } from '../context-menu/stage-group-add-in-node-context-menu' -import { PipelineNodes } from '../pipeline-nodes' - -export interface CustomAddNodeDataType extends CommonNodeDataType {} - -export function CustomAddNode(props: { node: LeafNodeInternalType }) { - const { node } = props - const { data } = node - - const { showContextMenu } = usePipelineStudioNodeContext() - - return ( - { - e.stopPropagation() - showContextMenu(StageGroupAddInNodeContextMenu, data, e.currentTarget) - }} - /> - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-end-content-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-end-content-node.tsx deleted file mode 100644 index 24e9c84520..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-end-content-node.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { LeafNodeInternalType } from '@harnessio/pipeline-graph' - -import { PipelineNodes } from '../pipeline-nodes' - -export interface EndNodeDataType {} - -export function CustomEndContentNode(_props: { node: LeafNodeInternalType }) { - return -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-parallel-stage-group-content-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-parallel-stage-group-content-node.tsx deleted file mode 100644 index 6cdaa3336d..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-parallel-stage-group-content-node.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { useMemo } from 'react' - -import { ParallelNodeInternalType } from '@harnessio/pipeline-graph' -import { CommonNodeDataType, usePipelineStudioNodeContext } from '@harnessio/ui/views' - -import { StageGroupAddInNodeContextMenu } from '../context-menu/stage-group-add-in-node-context-menu' -import { StageGroupNodeContextMenu } from '../context-menu/stage-group-node-context-menu' -import { PipelineNodes } from '../pipeline-nodes' -import { GlobalData } from '../types/common' - -export interface CustomParallelStageGroupContentNodeDataType extends CommonNodeDataType { - icon?: React.ReactElement -} - -export function CustomParallelStageGroupContentNode(props: { - node: ParallelNodeInternalType - children?: React.ReactElement - collapsed?: boolean - isFirst?: boolean - isLast?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' -}) { - const { node, children, collapsed, isFirst, parentNodeType } = props - const data = node.data as CustomParallelStageGroupContentNodeDataType - - const { selectionPath, showContextMenu, onSelectIntention, onAddIntention, globalData } = - usePipelineStudioNodeContext() - - const { hideContextMenu, hideFloatingButtons } = globalData ?? {} - - const selected = useMemo(() => selectionPath === data.yamlPath, [selectionPath]) - - return ( - { - e.stopPropagation() - showContextMenu(StageGroupAddInNodeContextMenu, data, e.currentTarget, true) - }} - onEllipsisClick={e => { - e.stopPropagation() - showContextMenu(StageGroupNodeContextMenu, data, e.currentTarget) - }} - onHeaderClick={e => { - e.stopPropagation() - onSelectIntention(data) - }} - onAddClick={position => { - onAddIntention(data, position) - }} - > - {children} - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-parallel-step-group-content-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-parallel-step-group-content-node.tsx deleted file mode 100644 index 64117a47de..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-parallel-step-group-content-node.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useMemo } from 'react' - -import { ParallelNodeInternalType } from '@harnessio/pipeline-graph' -import { CommonNodeDataType, usePipelineStudioNodeContext } from '@harnessio/ui/views' - -import { StepGroupNodeContextMenu } from '../context-menu/step-group-node-context-menu' -import { PipelineNodes } from '../pipeline-nodes' -import { GlobalData } from '../types/common' - -export interface CustomParallelStepGroupContentNodeDataType extends CommonNodeDataType { - icon?: React.ReactElement -} - -export function CustomParallelStepGroupContentNode(props: { - node: ParallelNodeInternalType - children?: React.ReactElement - collapsed?: boolean - isFirst?: boolean - isLast?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' -}) { - const { node, children, collapsed, isFirst, parentNodeType } = props - const data = node.data as CustomParallelStepGroupContentNodeDataType - - const { selectionPath, showContextMenu, onSelectIntention, onAddIntention, globalData } = - usePipelineStudioNodeContext() - - const { hideContextMenu, hideFloatingButtons } = globalData ?? {} - - const selected = useMemo(() => selectionPath === data.yamlPath, [selectionPath]) - - return ( - { - e.stopPropagation() - onAddIntention(data, 'in') - }} - onEllipsisClick={e => { - e.stopPropagation() - showContextMenu(StepGroupNodeContextMenu, data, e.currentTarget) - }} - onHeaderClick={e => { - e.stopPropagation() - onSelectIntention(data) - }} - onAddClick={position => { - onAddIntention(data, position) - }} - > - {children} - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-serial-stage-group-content-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-serial-stage-group-content-node.tsx deleted file mode 100644 index 7495cdab2b..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-serial-stage-group-content-node.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { useMemo } from 'react' - -import { SerialNodeInternalType } from '@harnessio/pipeline-graph' -import { CommonNodeDataType, usePipelineStudioNodeContext } from '@harnessio/ui/views' - -import { StageGroupAddInNodeContextMenu } from '../context-menu/stage-group-add-in-node-context-menu' -import { StageGroupNodeContextMenu } from '../context-menu/stage-group-node-context-menu' -import { PipelineNodes } from '../pipeline-nodes' -import { GlobalData } from '../types/common' - -export interface CustomSerialStageGroupContentNodeDataType extends CommonNodeDataType { - icon?: React.ReactElement -} - -export function CustomSerialStageGroupContentNode(props: { - node: SerialNodeInternalType - children?: React.ReactElement - collapsed?: boolean - isFirst?: boolean - isLast?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' -}) { - const { node, children, collapsed, isFirst, parentNodeType } = props - const data = node.data as CustomSerialStageGroupContentNodeDataType - - const { selectionPath, showContextMenu, onSelectIntention, onAddIntention, globalData } = - usePipelineStudioNodeContext() - - const { hideContextMenu, hideFloatingButtons } = globalData ?? {} - - const selected = useMemo(() => selectionPath === data.yamlPath, [selectionPath]) - - return ( - { - e.stopPropagation() - showContextMenu(StageGroupAddInNodeContextMenu, data, e.currentTarget, true) - }} - onEllipsisClick={e => { - e.stopPropagation() - showContextMenu(StageGroupNodeContextMenu, data, e.currentTarget) - }} - onHeaderClick={e => { - e.stopPropagation() - onSelectIntention(data) - }} - onAddClick={position => { - onAddIntention(data, position) - }} - > - {children} - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-serial-step-group-content-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-serial-step-group-content-node.tsx deleted file mode 100644 index 0cf12c8095..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-serial-step-group-content-node.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useMemo } from 'react' - -import { SerialNodeInternalType } from '@harnessio/pipeline-graph' -import { CommonNodeDataType, usePipelineStudioNodeContext } from '@harnessio/ui/views' - -import { StepGroupNodeContextMenu } from '../context-menu/step-group-node-context-menu' -import { PipelineNodes } from '../pipeline-nodes' -import { GlobalData } from '../types/common' - -export interface CustomSerialStepGroupContentNodeDataType extends CommonNodeDataType { - icon?: React.ReactElement -} - -export function CustomSerialStepGroupContentNode(props: { - node: SerialNodeInternalType - children?: React.ReactElement - collapsed?: boolean - isFirst?: boolean - isLast?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' -}) { - const { node, children, collapsed, isFirst, parentNodeType } = props - const data = node.data as CustomSerialStepGroupContentNodeDataType - - const { selectionPath, showContextMenu, onSelectIntention, onAddIntention, globalData } = - usePipelineStudioNodeContext() - - const { hideContextMenu, hideFloatingButtons } = globalData ?? {} - - const selected = useMemo(() => selectionPath === data.yamlPath, [selectionPath]) - - return ( - { - e.stopPropagation() - onAddIntention(data, 'in') - }} - onEllipsisClick={e => { - e.stopPropagation() - showContextMenu(StepGroupNodeContextMenu, data, e.currentTarget) - }} - onHeaderClick={e => { - e.stopPropagation() - onSelectIntention(data) - }} - onAddClick={position => { - onAddIntention(data, position) - }} - > - {children} - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-stage-content-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-stage-content-node.tsx deleted file mode 100644 index 3a9c120194..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-stage-content-node.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { useMemo } from 'react' - -import { SerialNodeInternalType } from '@harnessio/pipeline-graph' -import { CommonNodeDataType, usePipelineStudioNodeContext } from '@harnessio/ui/views' - -import { StageNodeContextMenu } from '../context-menu/stage-node-context-menu' -import { PipelineNodes } from '../pipeline-nodes' -import { GlobalData } from '../types/common' - -export interface CustomStageContentNodeDataType extends CommonNodeDataType { - icon?: React.ReactElement -} - -export function CustomStageContentNode(props: { - node: SerialNodeInternalType - children?: React.ReactElement - collapsed?: boolean - isFirst?: boolean - isLast?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' -}) { - const { node, children, collapsed, isFirst, parentNodeType } = props - const data = node.data as CustomStageContentNodeDataType - - const { selectionPath, showContextMenu, onAddIntention, onSelectIntention, globalData } = - usePipelineStudioNodeContext() - - const { hideContextMenu, hideFloatingButtons } = globalData ?? {} - - const selected = useMemo(() => selectionPath === data.yamlPath, [selectionPath]) - - return ( - { - onAddIntention(data, 'in') - }} - onEllipsisClick={e => { - e.stopPropagation() - showContextMenu(StageNodeContextMenu, data, e.currentTarget) - }} - onHeaderClick={e => { - e.stopPropagation() - onSelectIntention(data) - }} - onAddClick={position => { - onAddIntention(data, position) - }} - > - {children} - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-start-content-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-start-content-node.tsx deleted file mode 100644 index cce0e0c6c3..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/custom-start-content-node.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { LeafNodeInternalType } from '@harnessio/pipeline-graph' - -import { PipelineNodes } from '../pipeline-nodes' - -export interface CustomStartNodeDataType {} - -export function CustomStartContentNode(_props: { node: LeafNodeInternalType }) { - return -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/nodes/types.ts b/apps/design-system/src/subjects/views/pipeline-edit/nodes/types.ts deleted file mode 100644 index 7216e0cdc6..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/nodes/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum PipelineNodeStatus { - Success = 'success', - Executing = 'executing', - Executed = 'executed', - Warning = 'warning', - Error = 'error' -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-edit.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-edit.tsx deleted file mode 100644 index ee42d47186..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-edit.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { useState } from 'react' - -import { CollapseButton } from '@subjects/views/pipeline-edit/pipeline-nodes/components/collapse-button.tsx' - -import { Button, ButtonGroup, Icon } from '@harnessio/ui/components' -import { - CommonNodeDataType, - deleteItemInArray, - ErrorDataType, - injectItemInArray, - PipelineEdit, - YamlEntityType -} from '@harnessio/ui/views' - -import { demoPSYaml } from './mocks/demoPSYaml' -import { parallelContainerConfig, serialContainerConfig } from './mocks/pipelineExecutionMock' -import { contentNodeFactory } from './nodes-factory' -import PipelineExecution from './pipeline-execution' -import CustomPort from './pipeline-nodes/components/custom-port' -import { getIconBasedOnStep } from './utils/step-icon-utils' - -const PipelineStudioWrapper = () => { - const [yamlRevision, setYamlRevision] = useState({ yaml: demoPSYaml }) - const [view, setView] = useState<'graph' | 'yaml'>('graph') - const [isExecution, setIsExecution] = useState(true) - - const [selectedPath, setSelectedPath] = useState() - const [errorData, setErrorData] = useState() - - const processAddIntention = ( - nodeData: CommonNodeDataType, - position: 'after' | 'before' | 'in', - yamlEntityTypeToAdd?: YamlEntityType | undefined - ) => { - let newYaml = yamlRevision.yaml - - switch (yamlEntityTypeToAdd) { - case YamlEntityType.SerialStageGroup: - // NOTE: if we are adding in the array we have to provide path to children array - newYaml = injectItemInArray(yamlRevision.yaml, { - path: position === 'in' && nodeData.yamlChildrenPath ? nodeData.yamlChildrenPath : nodeData.yamlPath, - position, - item: { group: { stages: [] } } - }) - break - - case YamlEntityType.ParallelStageGroup: - // NOTE: if we are adding in the array we have to provide path to children array - newYaml = injectItemInArray(yamlRevision.yaml, { - path: position === 'in' && nodeData.yamlChildrenPath ? nodeData.yamlChildrenPath : nodeData.yamlPath, - position, - item: { parallel: { stages: [] } } - }) - break - - case YamlEntityType.Stage: - // NOTE: if we are adding in the array we have to provide path to children array - newYaml = injectItemInArray(yamlRevision.yaml, { - path: position === 'in' && nodeData.yamlChildrenPath ? nodeData.yamlChildrenPath : nodeData.yamlPath, - position, - item: { steps: [] } - }) - break - - default: - if (nodeData.yamlEntityType === YamlEntityType.Stage) { - // TODO: set addIntent state and open drawer.... - } - break - } - - setYamlRevision({ yaml: newYaml }) - } - - const isYamlInvalid = errorData && !errorData?.isYamlValid - - return ( -
{ - setSelectedPath(undefined) - }} - > - - - - - - - {isExecution && } - - {!isExecution && ( - <> - { - const { id, path /*, pathLength, targetNode*/ } = props - // TODO - const pathStyle = ` stroke="hsl(var(--canary-border-03))"` - const staticPath = `` - return { level1: staticPath, level2: '' } - }} - portComponent={CustomPort} - collapseButtonComponent={CollapseButton} - edgesConfig={{ radius: 10, parallelNodeOffset: 10, serialNodeOffset: 10 }} - yamlRevision={yamlRevision} - onYamlRevisionChange={setYamlRevision} - view={view} - selectedPath={selectedPath} - contentNodeFactory={contentNodeFactory} - serialContainerConfig={serialContainerConfig} - parallelContainerConfig={parallelContainerConfig} - getStepIcon={getIconBasedOnStep} - onErrorChange={data => { - setErrorData(data) - }} - onAddIntention={(nodeData, position, yamlEntityTypeToAdd) => { - console.log('onAddIntention') - processAddIntention(nodeData, position, yamlEntityTypeToAdd) - }} - onDeleteIntention={data => { - console.log('onDeleteIntention') - const updatedYaml = deleteItemInArray(yamlRevision.yaml, { path: data.yamlPath }) - setYamlRevision({ yaml: updatedYaml }) - }} - onEditIntention={() => { - console.log('onEditIntention') - }} - onSelectIntention={data => { - console.log('onSelectIntention') - setSelectedPath(data.yamlPath) - }} - onRevealInYaml={() => { - console.log('onSelectIntention') - }} - /> - - )} -
- ) -} - -export default PipelineStudioWrapper diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-execution.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-execution.tsx deleted file mode 100644 index 963c972563..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-execution.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useMemo } from 'react' - -import { CollapseButton } from '@subjects/views/pipeline-edit/pipeline-nodes/components/collapse-button.tsx' - -import { CanvasProvider, PipelineGraph } from '@harnessio/pipeline-graph' -import { PipelineStudioNodeContextMenu, PipelineStudioNodeContextProvider } from '@harnessio/ui/views' - -import { CanvasControls } from './canvas/canvas-controls' -import { useAnimatePipeline } from './hooks/useAnimatePipeline' -import { demoExecutionMock } from './mocks/animations/demoExecutionMock' -import { parallelContainerConfig, serialContainerConfig } from './mocks/pipelineExecutionMock' -import { contentNodeFactory } from './nodes-factory' -import CustomPort from './pipeline-nodes/components/custom-port' -import { GlobalData } from './types/common' - -const globalDataConfigForExecution: GlobalData = { - hideContextMenu: true, - hideFloatingButtons: true -} - -const PipelineExecution = () => { - return ( -
- undefined} - onDeleteIntention={() => undefined} - onEditIntention={() => undefined} - onRevealInYaml={() => undefined} - onSelectIntention={() => undefined} - globalData={globalDataConfigForExecution} - > - - - -
- ) -} - -export default PipelineExecution - -const PipelineExecutionInner = () => { - const nodes = useMemo(() => contentNodeFactory.getNodesDefinition(), [contentNodeFactory]) - const { nodes: animatedNodes } = useAnimatePipeline({ nodes: demoExecutionMock }) - - return ( -
- - { - const { id, path /*, pathLength, targetNode*/ } = props - // TODO - const pathStyle = ` stroke="hsl(var(--canary-border-03))"` - const staticPath = `` - return { level1: staticPath, level2: '' } - }} - portComponent={CustomPort} - collapseButtonComponent={CollapseButton} - edgesConfig={{ radius: 10, parallelNodeOffset: 10, serialNodeOffset: 10 }} - data={animatedNodes} - nodes={nodes} - serialContainerConfig={serialContainerConfig} - parallelContainerConfig={parallelContainerConfig} - /> - - -
- ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/add-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/add-node.tsx deleted file mode 100644 index ea71d19d30..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/add-node.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { Button, Icon } from '@harnessio/ui/components' - -export interface AddNodeProp { - onClick?: (event: React.MouseEvent) => void -} - -export function AddNode(props: AddNodeProp) { - const { onClick } = props - - return ( -
- -
- ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/floating-add-button.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/floating-add-button.tsx deleted file mode 100644 index 498d44c56a..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/floating-add-button.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { CSSProperties } from 'react' - -import { - parallelContainerConfig, - serialContainerConfig -} from '@subjects/views/pipeline-edit/mocks/pipelineExecutionMock' - -import { Button, Icon } from '@harnessio/ui/components' - -const CONTAINER_WIDTH = '40' -const CONTAINER_HEIGHT = '40' - -export interface FloatingAddButtonProp { - parentNodeType?: 'leaf' | 'serial' | 'parallel' - position: 'before' | 'after' - onClick: (event: React.MouseEvent) => void - collapsed?: boolean -} - -export function FloatingAddButton(props: FloatingAddButtonProp) { - const { onClick, position, parentNodeType, collapsed } = props - - const style: CSSProperties = {} - if (position === 'before' && parentNodeType === 'serial') { - style.left = `-${CONTAINER_WIDTH}px` - style.width = `${CONTAINER_WIDTH}px` - style.top = '0px' - style.bottom = '0px' - } else if (position === 'after' && parentNodeType === 'serial') { - style.right = `-${CONTAINER_WIDTH}px` - style.width = `${CONTAINER_WIDTH}px` - style.top = '0px' - style.bottom = '0px' - } - if (position === 'before' && parentNodeType === 'parallel') { - style.top = `-${CONTAINER_HEIGHT}px` - style.height = `${CONTAINER_HEIGHT}px` - style.left = '0px' - style.right = '0px' - } else if (position === 'after' && parentNodeType === 'parallel') { - style.bottom = `-${CONTAINER_HEIGHT}px` - style.height = `${CONTAINER_HEIGHT}px` - style.left = '0px' - style.right = '0px' - } - - const typeStyleConf = - parentNodeType === 'parallel' - ? parallelContainerConfig - : parentNodeType === 'serial' - ? serialContainerConfig - : undefined - const buttonMarginTopValue = - !!typeStyleConf && collapsed === false ? typeStyleConf.paddingTop - typeStyleConf.paddingBottom : 0 - - return ( -
- -
- ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/end-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/end-node.tsx deleted file mode 100644 index b3b05115ab..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/end-node.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Icon } from '@harnessio/ui/components' - -export function EndNode() { - return ( -
- -
- ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/index.ts b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/index.ts deleted file mode 100644 index 07a836e9ac..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { AddNode } from './add-node' -import { EndNode } from './end-node' -import { ParallelGroupNode } from './parallel-group-node' -import { SerialGroupNode } from './serial-group-node' -import { StageNode } from './stage-node' -import { StartNode } from './start-node' -import { StepNode } from './step-node' - -export const PipelineNodes = { - AddNode, - StageNode, - StartNode, - EndNode, - StepNode, - SerialGroupNode, - ParallelGroupNode -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/parallel-group-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/parallel-group-node.tsx deleted file mode 100644 index 8c32a9bb7e..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/parallel-group-node.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { NodeMenuTrigger } from '@subjects/views/pipeline-edit/pipeline-nodes/components/node-menu-trigger.tsx' -import { NodeTitle } from '@subjects/views/pipeline-edit/pipeline-nodes/components/node-title.tsx' -import { getNestedStepsCount } from '@subjects/views/pipeline-edit/utils/common-step-utils' - -import { ParallelNodeInternalType } from '@harnessio/pipeline-graph' -import { Button, Icon } from '@harnessio/ui/components' -import { cn } from '@harnessio/ui/views' - -import { CustomParallelStepGroupContentNodeDataType } from '../nodes/custom-parallel-step-group-content-node' -import { CollapsedGroupNode } from './components/collapsed-group-node' -import { ExecutionStatus } from './components/execution-status' -import { FloatingAddButton } from './components/floating-add-button' - -export interface ParallelGroupNodeProps { - name?: string - children?: React.ReactElement - collapsed?: boolean - isEmpty?: boolean - selected?: boolean - isFirst?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' - node: ParallelNodeInternalType - hideContextMenu?: boolean - hideFloatingButtons?: boolean - onEllipsisClick: (e: React.MouseEvent) => void - onAddInClick: (e: React.MouseEvent) => void - onHeaderClick: (e: React.MouseEvent) => void - onAddClick?: (position: 'before' | 'after', e: React.MouseEvent) => void -} - -export function ParallelGroupNode(props: ParallelGroupNodeProps) { - const { - name, - children, - collapsed, - isEmpty, - selected, - isFirst, - parentNodeType, - node, - onEllipsisClick, - onAddInClick, - onHeaderClick, - onAddClick, - hideContextMenu, - hideFloatingButtons - } = props - - const nodeData = node.data - const counter = getNestedStepsCount(node.children) - - return ( - <> - - -
- - - - {!hideContextMenu && } - - {!collapsed && isEmpty && ( - - )} - - {!hideFloatingButtons && isFirst && ( - { - onAddClick?.('before', e) - }} - collapsed={collapsed} - /> - )} - {!hideFloatingButtons && ( - { - onAddClick?.('after', e) - }} - collapsed={collapsed} - /> - )} - {collapsed ? : children} - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/serial-group-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/serial-group-node.tsx deleted file mode 100644 index e7834a89a3..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/serial-group-node.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { NodeMenuTrigger } from '@subjects/views/pipeline-edit/pipeline-nodes/components/node-menu-trigger.tsx' -import { NodeTitle } from '@subjects/views/pipeline-edit/pipeline-nodes/components/node-title.tsx' -import { getNestedStepsCount } from '@subjects/views/pipeline-edit/utils/common-step-utils' - -import { SerialNodeInternalType } from '@harnessio/pipeline-graph' -import { Button, Icon } from '@harnessio/ui/components' -import { cn } from '@harnessio/ui/views' - -import { CustomSerialStepGroupContentNodeDataType } from '../nodes/custom-serial-step-group-content-node' -import { CollapsedGroupNode } from './components/collapsed-group-node' -import { ExecutionStatus } from './components/execution-status' -import { FloatingAddButton } from './components/floating-add-button' - -export interface SerialGroupNodeProps { - name?: string - children?: React.ReactElement - collapsed?: boolean - isEmpty?: boolean - selected?: boolean - isFirst?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' - node: SerialNodeInternalType - hideContextMenu?: boolean - hideFloatingButtons?: boolean - onEllipsisClick: (e: React.MouseEvent) => void - onAddInClick: (e: React.MouseEvent) => void - onHeaderClick: (e: React.MouseEvent) => void - onAddClick?: (position: 'before' | 'after', e: React.MouseEvent) => void -} - -export function SerialGroupNode(props: SerialGroupNodeProps) { - const { - name, - children, - collapsed, - isEmpty, - selected, - isFirst, - onEllipsisClick, - onAddInClick, - onHeaderClick, - onAddClick, - parentNodeType, - node, - hideContextMenu, - hideFloatingButtons - } = props - - const nodeData = node.data - const counter = getNestedStepsCount(node.children) - - return ( - <> - - -
- - - - {!hideContextMenu && } - - {!collapsed && isEmpty && ( - - )} - - {!hideFloatingButtons && isFirst && ( - { - onAddClick?.('before', e) - }} - collapsed={collapsed} - /> - )} - {!hideFloatingButtons && ( - { - onAddClick?.('after', e) - }} - collapsed={collapsed} - /> - )} - {collapsed ? : children} - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/stage-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/stage-node.tsx deleted file mode 100644 index 26fcb7bc92..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/stage-node.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { NodeMenuTrigger } from '@subjects/views/pipeline-edit/pipeline-nodes/components/node-menu-trigger.tsx' -import { NodeTitle } from '@subjects/views/pipeline-edit/pipeline-nodes/components/node-title.tsx' -import { getNestedStepsCount } from '@subjects/views/pipeline-edit/utils/common-step-utils' - -import { SerialNodeInternalType } from '@harnessio/pipeline-graph' -import { Button, Icon } from '@harnessio/ui/components' -import { cn } from '@harnessio/ui/views' - -import { CustomSerialStageGroupContentNodeDataType } from '../nodes/custom-serial-stage-group-content-node' -import { CollapsedGroupNode } from './components/collapsed-group-node' -import { ExecutionStatus } from './components/execution-status' -import { FloatingAddButton } from './components/floating-add-button' - -export interface StageNodeProps { - name?: string - children?: React.ReactElement - collapsed?: boolean - isEmpty?: boolean - selected?: boolean - isFirst?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' - node: SerialNodeInternalType - hideContextMenu?: boolean - hideFloatingButtons?: boolean - onEllipsisClick?: (e: React.MouseEvent) => void - onAddInClick: (e: React.MouseEvent) => void - onHeaderClick: (e: React.MouseEvent) => void - onAddClick?: (position: 'before' | 'after', e: React.MouseEvent) => void -} - -export function StageNode(props: StageNodeProps) { - const { - name, - children, - collapsed, - isEmpty, - selected, - isFirst, - onEllipsisClick, - onAddInClick, - onHeaderClick, - onAddClick, - parentNodeType, - node, - hideContextMenu, - hideFloatingButtons - } = props - - const nodeData = node.data - const counter = getNestedStepsCount(node.children) - - return ( - <> - - -
- - - - {!hideContextMenu && } - - {!collapsed && isEmpty && ( - - )} - - {!hideFloatingButtons && isFirst && ( - { - onAddClick?.('before', e) - }} - collapsed={collapsed} - /> - )} - {!hideFloatingButtons && ( - { - onAddClick?.('after', e) - }} - collapsed={collapsed} - /> - )} - - {collapsed ? : children} - - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/start-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/start-node.tsx deleted file mode 100644 index 42d3a49f02..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/start-node.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Icon } from '@harnessio/ui/components' - -export function StartNode() { - return ( -
- -
- ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/step-node.tsx b/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/step-node.tsx deleted file mode 100644 index d483ca46e5..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/step-node.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { cn } from '@harnessio/ui/views' - -import './step-node.css' - -import { LeafNodeInternalType } from '@harnessio/pipeline-graph' - -import { StepNodeDataType } from '../nodes/custom-step-node' -import { ExecutionStatus } from './components/execution-status' -import { FloatingAddButton } from './components/floating-add-button' -import { NodeMenuTrigger } from './components/node-menu-trigger' -import { WarningLabel } from './components/warning-label' - -export interface StepNodeProps { - name?: string - icon?: React.ReactNode - selected?: boolean - isFirst?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' - node: LeafNodeInternalType - hideContextMenu?: boolean - hideFloatingButtons?: boolean - onEllipsisClick?: (e: React.MouseEvent) => void - onClick?: (e: React.MouseEvent) => void - onAddClick?: (position: 'before' | 'after', e: React.MouseEvent) => void - counter?: number - isCollapsedNode?: boolean -} - -export function StepNode(props: StepNodeProps) { - const { - node, - name, - icon, - selected, - onEllipsisClick, - onClick, - onAddClick, - isFirst, - parentNodeType, - counter, - isCollapsedNode, - hideContextMenu, - hideFloatingButtons - } = props - - const nodeData = node.data - - return ( - <> - - -
-
- {!hideContextMenu && } - - {!hideFloatingButtons && isFirst && !isCollapsedNode && ( - { - onAddClick?.('before', e) - }} - /> - )} - {!hideFloatingButtons && !isCollapsedNode && ( - { - onAddClick?.('after', e) - }} - /> - )} - {!!icon &&
{icon}
} - - {name} - {!!counter && ({counter})} - - {nodeData.warningMessage && {nodeData.warningMessage}} -
-
- - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/types/common.ts b/apps/design-system/src/subjects/views/pipeline-edit/types/common.ts deleted file mode 100644 index 354de2ecd4..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/types/common.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface GlobalData { - hideContextMenu?: boolean - hideFloatingButtons?: boolean -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/utils/step-icon-utils.tsx b/apps/design-system/src/subjects/views/pipeline-edit/utils/step-icon-utils.tsx deleted file mode 100644 index 224d3c7d6c..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/utils/step-icon-utils.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Icon, IconProps } from '@harnessio/ui/components' - -import { - getIsActionStep, - getIsBackgroundStep, - getIsRunStep, - getIsRunTestStep, - getIsTemplateStep -} from './common-step-utils' - -const getIconNameBasedOnStep = (step: any): IconProps['name'] => { - if (getIsRunStep(step)) return 'run' - - if (getIsRunTestStep(step)) return 'run-test' - - if (getIsBackgroundStep(step)) return 'cog-6' - - if (getIsActionStep(step)) return 'github-actions' - - if (getIsTemplateStep(step)) { - switch (step.template.uses) { - case 'slack': - return 'slack' - break - case 'docker': - return 'docker' - break - } - } - - /** - * Yet to add Bitrise plugins, - * Request backend to add a property to identify bitrise-plugin - */ - - return 'harness' -} - -export const getIconBasedOnStep = (step: any): JSX.Element => { - return -} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/utils/utils.ts b/apps/design-system/src/subjects/views/pipeline-edit/utils/utils.ts deleted file mode 100644 index d034054372..0000000000 --- a/apps/design-system/src/subjects/views/pipeline-edit/utils/utils.ts +++ /dev/null @@ -1,49 +0,0 @@ -export function createRoundedRectPath(x: number, y: number, width: number, height: number, radius: number) { - return ( - 'M' + - (x + radius) + - ',' + - y + - 'h' + - (width - 2 * radius) + - 'a' + - radius + - ',' + - radius + - ' 0 0 1 ' + - radius + - ',' + - radius + - 'v' + - (height - 2 * radius) + - 'a' + - radius + - ',' + - radius + - ' 0 0 1 ' + - -radius + - ',' + - radius + - 'h' + - (2 * radius - width) + - 'a' + - -radius + - ',' + - -radius + - ' 0 0 1 ' + - -radius + - ',' + - -radius + - 'v' + - (2 * radius - height) + - 'a' + - radius + - ',' + - -radius + - ' 0 0 1 ' + - radius + - ',' + - -radius + - 'z' - ) -} diff --git a/apps/design-system/src/subjects/views/pipeline-graph/pipeline-graph-minimal.tsx b/apps/design-system/src/subjects/views/pipeline-graph/pipeline-graph-minimal.tsx index c1e5bb613a..4ca27318b7 100644 --- a/apps/design-system/src/subjects/views/pipeline-graph/pipeline-graph-minimal.tsx +++ b/apps/design-system/src/subjects/views/pipeline-graph/pipeline-graph-minimal.tsx @@ -18,9 +18,7 @@ import { Icon, Text } from '@harnessio/ui/components' import '@harnessio/pipeline-graph/dist/index.css' -import { useState } from 'react' - -import { VisualYamlToggle, type VisualYamlValue } from '@harnessio/ui/views' +// import { VisualYamlToggle, type VisualYamlValue } from '@harnessio/ui/views' // ***************************************************** // 2. Define content nodes types @@ -223,11 +221,11 @@ const data: AnyContainerNodeType[] = [ ] const PipelineGraphMinimalWrapper = () => { - const [view, setView] = useState('visual') + // const [view, setView] = useState('visual') return (
- + {/* */}
diff --git a/apps/design-system/src/subjects/views/pipeline-graph/pipeline-graph.tsx b/apps/design-system/src/subjects/views/pipeline-graph/pipeline-graph.tsx index 9172692ddf..54bfaba6f1 100644 --- a/apps/design-system/src/subjects/views/pipeline-graph/pipeline-graph.tsx +++ b/apps/design-system/src/subjects/views/pipeline-graph/pipeline-graph.tsx @@ -11,7 +11,8 @@ import { SerialNodeInternalType } from '@harnessio/pipeline-graph' import { Icon, PipelineNodes } from '@harnessio/ui/components' -import { PipelineStudioFooter } from '@harnessio/ui/views' + +// import { PipelineStudioFooter } from '@harnessio/ui/views' // ***************************************************** // 1. Import CSS @@ -291,10 +292,10 @@ const PipelineGraphWrapper = () => { - + /> */} ) } diff --git a/apps/design-system/src/subjects/views/unified-pipeline-studio/mocks/pipeline.ts b/apps/design-system/src/subjects/views/unified-pipeline-studio/mocks/pipeline.ts new file mode 100644 index 0000000000..b2cbdca315 --- /dev/null +++ b/apps/design-system/src/subjects/views/unified-pipeline-studio/mocks/pipeline.ts @@ -0,0 +1,19 @@ +export const pipeline1 = `pipeline: + stages: + - group: + stages: + - parallel: + stages: + - steps: + - run: go build + - run: go test + - steps: + - run: npm test + - group: + stages: + - steps: + - run: go build + - steps: + - run: npm run + - run: npm test +` diff --git a/apps/design-system/src/subjects/views/unified-pipeline-studio/unified-pipeline-studio.store.ts b/apps/design-system/src/subjects/views/unified-pipeline-studio/unified-pipeline-studio.store.ts new file mode 100644 index 0000000000..dbb70867e2 --- /dev/null +++ b/apps/design-system/src/subjects/views/unified-pipeline-studio/unified-pipeline-studio.store.ts @@ -0,0 +1,28 @@ +import { useState } from 'react' + +import { IUnifiedPipelineStudioStore } from '@harnessio/ui/views' +import { YamlRevision } from '@harnessio/yaml-editor/dist/components/YamlEditor' + +import { pipeline1 } from './mocks/pipeline' + +export const usePipelineStudioStore = (): IUnifiedPipelineStudioStore => { + const [selectedPath, onSelectedPathChange] = useState() + const [yamlRevision, onYamlRevisionChange] = useState({ yaml: pipeline1 }) + const [panelOpen, onPanelOpenChange] = useState(true) + const [errors, onErrorsChange] = useState({ + isYamlValid: true, + problems: [], + problemsCount: { all: 0, error: 0, info: 0, warning: 0 } + }) + + return { + yamlRevision, + onYamlRevisionChange, + selectedPath, + onSelectedPathChange, + errors, + onErrorsChange, + panelOpen, + onPanelOpenChange + } +} diff --git a/apps/design-system/src/subjects/views/unified-pipeline-studio/unified-pipeline-studio.tsx b/apps/design-system/src/subjects/views/unified-pipeline-studio/unified-pipeline-studio.tsx new file mode 100644 index 0000000000..5b7a5c84fa --- /dev/null +++ b/apps/design-system/src/subjects/views/unified-pipeline-studio/unified-pipeline-studio.tsx @@ -0,0 +1,18 @@ +import { FC } from 'react' + +import { useTranslationStore } from '@utils/viewUtils' + +import { UnifiedPipelineStudio } from '@harnessio/ui/views' + +import { usePipelineStudioStore } from './unified-pipeline-studio.store' + +const PipelineStudioViewWrapper: FC> = () => { + return ( + + ) +} + +export default PipelineStudioViewWrapper diff --git a/packages/ui/package.json b/packages/ui/package.json index 80e5debd9b..aba679a862 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -61,6 +61,7 @@ "@git-diff-view/shiki": "^0.0.21", "@harnessio/pipeline-graph": "workspace:*", "@harnessio/yaml-editor": "workspace:*", + "@harnessio/forms": "workspace:*", "@hookform/resolvers": "^3.6.0", "@radix-ui/react-accordion": "^1.2.2", "@radix-ui/react-alert-dialog": "^1.1.4", diff --git a/packages/ui/src/components/form-primitives/label.tsx b/packages/ui/src/components/form-primitives/label.tsx index 401fcb5780..4f9d1e5234 100644 --- a/packages/ui/src/components/form-primitives/label.tsx +++ b/packages/ui/src/components/form-primitives/label.tsx @@ -46,12 +46,15 @@ interface LabelProps * @example * */ -const Label = ({ htmlFor, optional, color, variant, children, className }: LabelProps) => { - return ( - - {children} {optional && (optional)} - - ) -} +const Label = forwardRef, LabelProps>( + ({ htmlFor, optional, color, variant, children, className }: LabelProps, ref) => { + return ( + + {children} {optional && (optional)} + + ) + } +) +Label.displayName = 'Label' export { Label } diff --git a/packages/ui/src/components/form.tsx b/packages/ui/src/components/form.tsx new file mode 100644 index 0000000000..83170ee84d --- /dev/null +++ b/packages/ui/src/components/form.tsx @@ -0,0 +1,166 @@ +import * as React from 'react' +import { + Controller, + FormProvider, + useForm, + useFormContext, + type ControllerProps, + type FieldPath, + type FieldValues, + type SubmitHandler, + type UseFormReturn +} from 'react-hook-form' + +import type * as LabelPrimitive from '@radix-ui/react-label' +import { Slot } from '@radix-ui/react-slot' +import { cn } from '@utils/cn' + +import { Label } from '.' + +interface ZodFormProps { + form: UseFormReturn + onSubmit: SubmitHandler +} + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> = { + name: TName +} + +const FormFieldContext = React.createContext({} as FormFieldContextValue) + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +>({ + ...props +}: ControllerProps) => { + return ( + + + + ) +} + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext) + const itemContext = React.useContext(FormItemContext) + const { getFieldState, formState } = useFormContext() + + const fieldState = getFieldState(fieldContext.name, formState) + + if (!fieldContext) { + throw new Error('useFormField should be used within ') + } + + const { id } = itemContext + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState + } +} + +type FormItemContextValue = { + id: string +} + +const FormItemContext = React.createContext({} as FormItemContextValue) + +const FormItem = React.forwardRef>( + ({ className, ...props }, ref) => { + const id = React.useMemo(() => Math.random().toString(36).substr(2, 9), []) + + return ( + +
+ + ) + } +) +FormItem.displayName = 'FormItem' + +const FormLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => { + const { error, formItemId } = useFormField() + + return
) diff --git a/packages/ui/src/components/pipeline-nodes/components/index.ts b/packages/ui/src/components/pipeline-nodes/components/index.ts new file mode 100644 index 0000000000..5dbea9987b --- /dev/null +++ b/packages/ui/src/components/pipeline-nodes/components/index.ts @@ -0,0 +1,7 @@ +import { CollapsedGroupNode } from './collapsed-group-node' +import Port from './custom-port' + +export const PipelineNodesComponents = { + Port, + CollapsedGroupNode +} diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/node-menu-trigger.tsx b/packages/ui/src/components/pipeline-nodes/components/node-menu-trigger.tsx similarity index 77% rename from apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/node-menu-trigger.tsx rename to packages/ui/src/components/pipeline-nodes/components/node-menu-trigger.tsx index 46afbb23bb..49fc3b9e01 100644 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/node-menu-trigger.tsx +++ b/packages/ui/src/components/pipeline-nodes/components/node-menu-trigger.tsx @@ -1,8 +1,9 @@ import { FC } from 'react' -import { SerialGroupNodeProps } from '@subjects/views/pipeline-edit/pipeline-nodes/serial-group-node.tsx' +import { Button } from '@components/button' +import { Icon } from '@components/icon' -import { Button, Icon } from '@harnessio/ui/components' +import { SerialGroupNodeProps } from '../serial-group-node' export interface NodeMenuTriggerProps { onEllipsisClick?: SerialGroupNodeProps['onEllipsisClick'] diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/node-title.tsx b/packages/ui/src/components/pipeline-nodes/components/node-title.tsx similarity index 71% rename from apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/node-title.tsx rename to packages/ui/src/components/pipeline-nodes/components/node-title.tsx index 42faf115e2..b7a4fb6fb6 100644 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/node-title.tsx +++ b/packages/ui/src/components/pipeline-nodes/components/node-title.tsx @@ -1,6 +1,6 @@ import { FC } from 'react' -import { SerialGroupNodeProps } from '@subjects/views/pipeline-edit/pipeline-nodes/serial-group-node.tsx' +import { SerialGroupNodeProps } from '../serial-group-node' export interface NodeTitleProps extends Pick { counter?: number @@ -13,7 +13,7 @@ export const NodeTitle: FC = ({ name, onHeaderClick, counter }) role="button" tabIndex={0} title={name} - className="text-foreground-3 text-14 cursor-pointer truncate px-8 pt-0.5 font-medium leading-snug" + className="cursor-pointer truncate px-8 pt-0.5 text-14 font-medium leading-snug text-foreground-3" onClick={onHeaderClick} > {name} ({counter}) diff --git a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/warning-label.tsx b/packages/ui/src/components/pipeline-nodes/components/warning-label.tsx similarity index 55% rename from apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/warning-label.tsx rename to packages/ui/src/components/pipeline-nodes/components/warning-label.tsx index de095f4464..16cd684acd 100644 --- a/apps/design-system/src/subjects/views/pipeline-edit/pipeline-nodes/components/warning-label.tsx +++ b/packages/ui/src/components/pipeline-nodes/components/warning-label.tsx @@ -1,8 +1,8 @@ -import { Icon } from '@harnessio/ui/components' +import { Icon } from '@components/icon' export function WarningLabel({ children }: { children: JSX.Element | string }) { return ( - + {children} diff --git a/packages/ui/src/components/pipeline-nodes/end-node.tsx b/packages/ui/src/components/pipeline-nodes/end-node.tsx index 824c4e72e6..32cf7a3d6d 100644 --- a/packages/ui/src/components/pipeline-nodes/end-node.tsx +++ b/packages/ui/src/components/pipeline-nodes/end-node.tsx @@ -1,8 +1,9 @@ +import { Icon } from '@components/icon' + export function EndNode() { return ( -
- {/* TODO: replace with icon */} -
+
+
) } diff --git a/packages/ui/src/components/pipeline-nodes/index.ts b/packages/ui/src/components/pipeline-nodes/index.ts index 2611347a5c..39c6e71f76 100644 --- a/packages/ui/src/components/pipeline-nodes/index.ts +++ b/packages/ui/src/components/pipeline-nodes/index.ts @@ -6,6 +6,8 @@ import { StageNode } from './stage-node' import { StartNode } from './start-node' import { StepNode } from './step-node' +export * from './components' + export const PipelineNodes = { AddNode, StageNode, @@ -15,5 +17,3 @@ export const PipelineNodes = { SerialGroupNode, ParallelGroupNode } - -export * from './types' diff --git a/packages/ui/src/components/pipeline-nodes/parallel-group-node.tsx b/packages/ui/src/components/pipeline-nodes/parallel-group-node.tsx index a7b1384b1f..20112d7d61 100644 --- a/packages/ui/src/components/pipeline-nodes/parallel-group-node.tsx +++ b/packages/ui/src/components/pipeline-nodes/parallel-group-node.tsx @@ -1,25 +1,40 @@ +import { Button } from '@components/button' +import { Icon } from '@components/icon' import { cn } from '@utils/cn' -import { Button, Icon, NodeProps } from '..' +import { ParallelContainerConfig } from '@harnessio/pipeline-graph/src/types/container-node' + +import { ExecutionStatus } from './components/execution-status' import { FloatingAddButton } from './components/floating-add-button' +import { NodeMenuTrigger } from './components/node-menu-trigger' +import { NodeTitle } from './components/node-title' +import { ExecutionStatusType } from './types/types' -export interface ParallelGroupNodeProps extends NodeProps { +export interface ParallelGroupNodeProps { name?: string + executionStatus?: ExecutionStatusType + allChildrenCount?: number children?: React.ReactElement collapsed?: boolean isEmpty?: boolean selected?: boolean isFirst?: boolean parentNodeType?: 'leaf' | 'serial' | 'parallel' + hideContextMenu?: boolean + hideFloatingButtons?: boolean onEllipsisClick: (e: React.MouseEvent) => void onAddInClick: (e: React.MouseEvent) => void onHeaderClick: (e: React.MouseEvent) => void onAddClick?: (position: 'before' | 'after', e: React.MouseEvent) => void + parallelContainerConfig?: Partial + serialContainerConfig?: Partial } export function ParallelGroupNode(props: ParallelGroupNodeProps) { const { name, + allChildrenCount, + executionStatus, children, collapsed, isEmpty, @@ -30,41 +45,27 @@ export function ParallelGroupNode(props: ParallelGroupNodeProps) { onAddInClick, onHeaderClick, onAddClick, - mode + hideContextMenu, + hideFloatingButtons, + serialContainerConfig, + parallelContainerConfig } = props return ( <> + +
-
-
- {name} -
-
+ - {mode !== 'Execution' && ( - - )} + {!hideContextMenu && } {!collapsed && isEmpty && ( - )} + {!hideContextMenu && } {!collapsed && isEmpty && ( - )} + {!hideContextMenu && } {!collapsed && isEmpty && ( - )} + <> + - {mode !== 'Execution' && isFirst && ( - { - onAddClick?.('before', e) - }} - /> - )} - {mode !== 'Execution' && ( - { - onAddClick?.('after', e) - }} - /> - )} +
+
+ {!hideContextMenu && } - {/* position="left" */} -
{icon}
- - {name} - -
+ {!hideFloatingButtons && isFirst && !isCollapsedNode && ( + { + onAddClick?.('before', e) + }} + parallelContainerConfig={parallelContainerConfig} + serialContainerConfig={serialContainerConfig} + /> + )} + {!hideFloatingButtons && !isCollapsedNode && ( + { + onAddClick?.('after', e) + }} + parallelContainerConfig={parallelContainerConfig} + serialContainerConfig={serialContainerConfig} + /> + )} + {!!icon &&
{icon}
} + + {name} + {!!counter && ({counter})} + + {warningMessage && {warningMessage}} +
+
+ ) } diff --git a/packages/ui/src/components/pipeline-nodes/types.ts b/packages/ui/src/components/pipeline-nodes/types.ts deleted file mode 100644 index c9baf6da8f..0000000000 --- a/packages/ui/src/components/pipeline-nodes/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface NodeProps { - mode?: 'Edit' | 'Execution' -} diff --git a/packages/ui/src/components/pipeline-nodes/types/types.ts b/packages/ui/src/components/pipeline-nodes/types/types.ts new file mode 100644 index 0000000000..e6a8316dd5 --- /dev/null +++ b/packages/ui/src/components/pipeline-nodes/types/types.ts @@ -0,0 +1 @@ +export type ExecutionStatusType = 'executing' | 'success' | 'warning' | 'error' | undefined diff --git a/packages/ui/src/components/resizable.tsx b/packages/ui/src/components/resizable.tsx new file mode 100644 index 0000000000..dcdf840992 --- /dev/null +++ b/packages/ui/src/components/resizable.tsx @@ -0,0 +1,37 @@ +import * as ResizablePrimitive from 'react-resizable-panels' + +import { DragHandleDots2Icon } from '@radix-ui/react-icons' +import { cn } from '@utils/cn' + +const ResizablePanelGroup = ({ className, ...props }: React.ComponentProps) => ( + +) + +const ResizablePanel = ResizablePrimitive.Panel + +const ResizableHandle = ({ + withHandle, + className, + ...props +}: React.ComponentProps & { + withHandle?: boolean +}) => ( + div]:rotate-90', + className + )} + {...props} + > + {withHandle && ( +
+ +
+ )} +
+) + +export { ResizablePanelGroup, ResizablePanel, ResizableHandle } diff --git a/packages/ui/src/views/index.ts b/packages/ui/src/views/index.ts index 27fdf2a16c..b521476c02 100644 --- a/packages/ui/src/views/index.ts +++ b/packages/ui/src/views/index.ts @@ -40,8 +40,8 @@ export * from './profile-settings' // pipelines export * from './pipelines' -// pipeline-edit -export * from './pipeline-edit' +// unified-pipeline-studio +export * from './unified-pipeline-studio' // user-management export * from './user-management' diff --git a/packages/ui/src/views/pipeline-edit/components/graph-implementation/nodes/step-content-node.tsx b/packages/ui/src/views/pipeline-edit/components/graph-implementation/nodes/step-content-node.tsx deleted file mode 100644 index 7a9f5574f1..0000000000 --- a/packages/ui/src/views/pipeline-edit/components/graph-implementation/nodes/step-content-node.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useMemo } from 'react' - -import { PipelineNodes } from '@components/pipeline-nodes' - -import { LeafNodeInternalType } from '@harnessio/pipeline-graph' - -import { StepNodeContextMenu } from '../context-menu/step-node-context-menu' -import { usePipelineStudioNodeContext } from '../context/PipelineStudioNodeContext' -import { CommonNodeDataType } from '../types/common-node-data-type' - -export interface StepNodeDataType extends CommonNodeDataType { - icon?: React.ReactElement - state?: 'success' | 'loading' - selected?: boolean -} - -export function StepContentNode(props: { - node: LeafNodeInternalType - isFirst?: boolean - isLast?: boolean - parentNodeType?: 'leaf' | 'serial' | 'parallel' -}) { - const { node, isFirst, parentNodeType } = props - - const data = node.data - - const { selectionPath, showContextMenu, onSelectIntention, onAddIntention } = usePipelineStudioNodeContext() - - const selected = useMemo(() => selectionPath === data.yamlPath, [selectionPath]) - - return ( - { - e.stopPropagation() - showContextMenu(StepNodeContextMenu, data, e.currentTarget) - }} - onClick={e => { - e.stopPropagation() - onSelectIntention(data) - }} - onAddClick={position => { - onAddIntention(data, position) - }} - > - ) -} diff --git a/packages/ui/src/views/pipeline-edit/components/graph-implementation/utils/common-step-utils.ts b/packages/ui/src/views/pipeline-edit/components/graph-implementation/utils/common-step-utils.ts deleted file mode 100644 index ba85355559..0000000000 --- a/packages/ui/src/views/pipeline-edit/components/graph-implementation/utils/common-step-utils.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const getIsRunStep = (step: Record) => Object.hasOwn(step, 'run') - -export const getIsRunTestStep = (step: Record) => Object.hasOwn(step, 'run-test') - -export const getIsBackgroundStep = (step: Record) => Object.hasOwn(step, 'background') - -export const getIsActionStep = (step: Record) => Object.hasOwn(step, 'action') - -export const getIsTemplateStep = (step: Record) => Object.hasOwn(step, 'template') diff --git a/packages/ui/src/views/pipeline-edit/components/pipeline-studio-graph-view.tsx b/packages/ui/src/views/pipeline-edit/components/pipeline-studio-graph-view.tsx deleted file mode 100644 index 33c33f68d4..0000000000 --- a/packages/ui/src/views/pipeline-edit/components/pipeline-studio-graph-view.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { useEffect, useMemo, useState } from 'react' - -import { parse } from 'yaml' - -import { AnyContainerNodeType, CanvasProvider, PipelineGraph, PipelineGraphProps } from '@harnessio/pipeline-graph' - -import { ContentNodeFactory, YamlRevision } from '../pipeline-studio' -import { CanvasControls } from './graph-implementation/canvas/canvas-controls' -import { yaml2Nodes } from './graph-implementation/utils/yaml-to-pipeline-graph' - -import '@harnessio/pipeline-graph/dist/index.css' - -import { ParallelContainerConfig, SerialContainerConfig } from '@harnessio/pipeline-graph/src/types/container-node' - -import { ContentNodeType } from './graph-implementation/types/content-node-type' - -const startNode = { - type: ContentNodeType.Start, - config: { - width: 40, - height: 40, - hideDeleteButton: true, - hideBeforeAdd: true, - hideLeftPort: true - }, - data: {} -} satisfies AnyContainerNodeType - -const endNode = { - type: ContentNodeType.End, - config: { - width: 40, - height: 40, - hideDeleteButton: true, - hideAfterAdd: true, - hideRightPort: true - }, - data: {} -} satisfies AnyContainerNodeType - -export interface PipelineStudioGraphViewProps - extends Pick< - PipelineGraphProps, - 'edgesConfig' | 'portComponent' | 'customCreateSVGPath' | 'collapseButtonComponent' - > { - contentNodeFactory: ContentNodeFactory - yamlRevision: YamlRevision - onYamlRevisionChange: (YamlRevision: YamlRevision) => void - getStepIcon?: (step: Record) => JSX.Element - serialContainerConfig?: Partial - parallelContainerConfig?: Partial -} - -export const PipelineStudioGraphView = (props: PipelineStudioGraphViewProps): React.ReactElement => { - const { - yamlRevision, - contentNodeFactory, - getStepIcon, - serialContainerConfig, - parallelContainerConfig, - customCreateSVGPath, - edgesConfig, - portComponent, - collapseButtonComponent - } = props - - const [data, setData] = useState([]) - - useEffect(() => { - return () => { - setData([]) - } - }, []) - - useEffect(() => { - const yamlJson = parse(yamlRevision.yaml) - const newData = yaml2Nodes(yamlJson, { getStepIcon }) - - newData.unshift(startNode) - newData.push(endNode) - setData(newData) - - // NOTE: this will output json for execution mock - console.log(newData) - }, [yamlRevision]) - - const nodes = useMemo(() => { - return contentNodeFactory.getNodesDefinition() - }, [contentNodeFactory]) - - return ( -
- - - - -
- ) -} diff --git a/packages/ui/src/views/pipeline-edit/components/pipeline-studio-internal.tsx b/packages/ui/src/views/pipeline-edit/components/pipeline-studio-internal.tsx deleted file mode 100644 index d618581d29..0000000000 --- a/packages/ui/src/views/pipeline-edit/components/pipeline-studio-internal.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { YamlEditorContextProvider } from '@harnessio/yaml-editor' - -import { ContentNodeFactory, YamlRevision } from '../pipeline-studio' -import { PipelineStudioGraphView, PipelineStudioGraphViewProps } from './pipeline-studio-graph-view' -import { PipelineStudioYamlView, PipelineStudioYamlViewProps } from './pipeline-studio-yaml-view' - -export interface PipelineStudioInternalProps - extends Pick< - PipelineStudioGraphViewProps, - | 'serialContainerConfig' - | 'parallelContainerConfig' - | 'getStepIcon' - | 'customCreateSVGPath' - | 'edgesConfig' - | 'portComponent' - | 'collapseButtonComponent' - > { - view: 'yaml' | 'graph' - contentNodeFactory: ContentNodeFactory - yamlRevision: YamlRevision - onYamlRevisionChange: (YamlRevision: YamlRevision) => void - yamlEditorConfig?: PipelineStudioYamlViewProps['yamlEditorConfig'] - onErrorChange?: PipelineStudioYamlViewProps['onErrorChange'] - animateYamlOnUpdate?: boolean - onYamlAnimateEnd?: () => void -} - -export default function PipelineStudioInternal(props: PipelineStudioInternalProps) { - const { - view, - yamlRevision, - onYamlRevisionChange, - contentNodeFactory, - yamlEditorConfig, - onErrorChange, - getStepIcon, - animateYamlOnUpdate: animateOnUpdate, - onYamlAnimateEnd: onAnimateEnd, - serialContainerConfig, - parallelContainerConfig, - customCreateSVGPath, - edgesConfig, - portComponent, - collapseButtonComponent - } = props - - return view === 'graph' ? ( - - ) : ( - - - - ) -} diff --git a/packages/ui/src/views/pipeline-edit/index.ts b/packages/ui/src/views/pipeline-edit/index.ts deleted file mode 100644 index c4cf359238..0000000000 --- a/packages/ui/src/views/pipeline-edit/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -// TODO: review exports after POC - -export * from './pipeline-edit' -export { PipelineStudioNodeContextMenu } from './components/pipeline-studio-node-context-menu' - -export { ContentNodeFactory } from './pipeline-studio' -export * from './utils/yaml-utils' -export * from './components/graph-implementation/types/yaml-entity-type' -export * from './components/graph-implementation/types/common-node-data-type' -export * from './components/graph-implementation/types/content-node-type' -export * from './components/graph-implementation/context/PipelineStudioNodeContext' -export * from './components/pipeline-studio-footer' -export * from './components/visual-yaml-toggle' - -export * from './components/graph-implementation/canvas/canvas-controls' - -export { yaml2Nodes, yamlString2Nodes } from './components/graph-implementation/utils/yaml-to-pipeline-graph' - -export type { ErrorDataType } from './components/pipeline-studio-yaml-view' - -// TODO: temporary -export { cn } from '@utils/cn' diff --git a/packages/ui/src/views/pipeline-edit/pipeline-edit.tsx b/packages/ui/src/views/pipeline-edit/pipeline-edit.tsx deleted file mode 100644 index e8f9754969..0000000000 --- a/packages/ui/src/views/pipeline-edit/pipeline-edit.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import { PipelineStudioGraphViewProps } from '@views/pipeline-edit/components/pipeline-studio-graph-view' - -import { ContainerNode } from '@harnessio/pipeline-graph' - -import { PipelineStudioNodeContextProvider } from './components/graph-implementation/context/PipelineStudioNodeContext' -import { EndContentNode } from './components/graph-implementation/nodes/end-content-node' -import { ParallelStageGroupContentNode } from './components/graph-implementation/nodes/parallel-stage-group-content-node' -import { ParallelStepGroupContentNode } from './components/graph-implementation/nodes/parallel-step-group-content-node' -import { SerialStageGroupContentNode } from './components/graph-implementation/nodes/serial-stage-group-content-node' -import { SerialStepGroupContentNode } from './components/graph-implementation/nodes/serial-step-group-content-node' -import { StageContentNode } from './components/graph-implementation/nodes/stage-content-node' -import { StartContentNode } from './components/graph-implementation/nodes/start-content-node' -import { StepContentNode } from './components/graph-implementation/nodes/step-content-node' -import { CommonNodeDataType } from './components/graph-implementation/types/common-node-data-type' -import { ContentNodeType } from './components/graph-implementation/types/content-node-type' -import { YamlEntityType } from './components/graph-implementation/types/yaml-entity-type' -import { PipelineStudioNodeContextMenu } from './components/pipeline-studio-node-context-menu' -import { ErrorDataType } from './components/pipeline-studio-yaml-view' -import { ContentNodeFactory, PipelineStudio, PipelineStudioProps, YamlRevision } from './pipeline-studio' - -export interface PipelineEditProps - extends Pick, - Pick< - PipelineStudioProps, - | 'yamlEditorConfig' - | 'getStepIcon' - | 'customCreateSVGPath' - | 'edgesConfig' - | 'portComponent' - | 'collapseButtonComponent' - > { - /** pipeline view */ - view: 'yaml' | 'graph' - /** yaml state */ - yamlRevision: YamlRevision - /** yaml change callback */ - onYamlRevisionChange: (YamlRevision: YamlRevision) => void - /** selected path */ - selectedPath?: string - onSelectIntention: (nodeData: CommonNodeDataType) => undefined - onAddIntention: ( - nodeData: CommonNodeDataType, - position: 'after' | 'before' | 'in', - yamlEntityTypeToAdd?: YamlEntityType - ) => void - onEditIntention: (nodeData: CommonNodeDataType) => undefined - onDeleteIntention: (nodeData: CommonNodeDataType) => undefined - onRevealInYaml: (_path: string | undefined) => undefined - onErrorChange?: (data: ErrorDataType) => void - contentNodeFactory?: ContentNodeFactory - animateYamlOnUpdate?: boolean - onYamlAnimateEnd?: () => void -} - -export const PipelineEdit = (props: PipelineEditProps): JSX.Element => { - const { - view, - yamlRevision, - onYamlRevisionChange, - onAddIntention, - onDeleteIntention, - onEditIntention, - onSelectIntention, - onRevealInYaml, - yamlEditorConfig, - selectedPath, - onErrorChange, - getStepIcon, - contentNodeFactory, - animateYamlOnUpdate, - onYamlAnimateEnd, - serialContainerConfig, - parallelContainerConfig, - customCreateSVGPath, - edgesConfig, - portComponent, - collapseButtonComponent - } = props - - const defaultContentNodeFactory = new ContentNodeFactory() - - defaultContentNodeFactory.registerEntity(ContentNodeType.Start, { - type: ContentNodeType.Start, - component: StartContentNode, - containerType: ContainerNode.leaf - }) - - defaultContentNodeFactory.registerEntity(ContentNodeType.End, { - type: ContentNodeType.End, - component: EndContentNode, - containerType: ContainerNode.leaf - }) - - // --- - - defaultContentNodeFactory.registerEntity(ContentNodeType.Step, { - type: ContentNodeType.Step, - component: StepContentNode, - containerType: ContainerNode.leaf - }) - - defaultContentNodeFactory.registerEntity(ContentNodeType.ParallelStepGroup, { - type: ContentNodeType.ParallelStepGroup, - component: ParallelStepGroupContentNode, - containerType: ContainerNode.parallel - }) - - defaultContentNodeFactory.registerEntity(ContentNodeType.SerialStepGroup, { - type: ContentNodeType.SerialStepGroup, - component: SerialStepGroupContentNode, - containerType: ContainerNode.serial - }) - - // --- - - defaultContentNodeFactory.registerEntity(ContentNodeType.Stage, { - type: ContentNodeType.Stage, - component: StageContentNode, - containerType: ContainerNode.serial - }) - - defaultContentNodeFactory.registerEntity(ContentNodeType.ParallelStageGroup, { - type: ContentNodeType.ParallelStageGroup, - component: ParallelStageGroupContentNode, - containerType: ContainerNode.parallel - }) - - defaultContentNodeFactory.registerEntity(ContentNodeType.SerialStageGroup, { - type: ContentNodeType.SerialStageGroup, - component: SerialStageGroupContentNode, - containerType: ContainerNode.serial - }) - - if (contentNodeFactory) { - contentNodeFactory.getNodesDefinition().forEach(nodeContentDef => { - defaultContentNodeFactory.registerEntity( - nodeContentDef.type as ContentNodeType, - { - type: nodeContentDef.type, - component: nodeContentDef.component, - containerType: nodeContentDef.containerType - } as any - ) - }) - } - - return ( - - - - - ) -} diff --git a/packages/ui/src/views/pipeline-edit/pipeline-studio.tsx b/packages/ui/src/views/pipeline-edit/pipeline-studio.tsx deleted file mode 100644 index 04fd8a3ee4..0000000000 --- a/packages/ui/src/views/pipeline-edit/pipeline-studio.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { PipelineStudioGraphViewProps } from '@views/pipeline-edit/components/pipeline-studio-graph-view' - -import { NodeContent } from '@harnessio/pipeline-graph' - -import { ContentNodeType } from './components/graph-implementation/types/content-node-type' -import PipelineStudioInternal, { PipelineStudioInternalProps } from './components/pipeline-studio-internal' - -export class ContentNodeFactory { - private entityBank: Map - - constructor() { - this.entityBank = new Map() - } - - registerEntity(entityType: ContentNodeType, definition: NodeContent) { - this.entityBank.set(entityType, definition) - } - - getEntityDefinition(entityType: ContentNodeType) { - return this.entityBank.get(entityType) - } - - getNodesDefinition(): NodeContent[] { - return Array.from(this.entityBank.values()) - } -} - -export interface YamlRevision { - yaml: string - revision?: number -} - -export interface PipelineStudioProps - extends Pick< - PipelineStudioGraphViewProps, - | 'serialContainerConfig' - | 'parallelContainerConfig' - | 'customCreateSVGPath' - | 'edgesConfig' - | 'portComponent' - | 'collapseButtonComponent' - > { - view: 'yaml' | 'graph' - contentNodeFactory: ContentNodeFactory - yamlRevision: YamlRevision - onYamlRevisionChange: (YamlRevision: YamlRevision) => void - yamlEditorConfig?: PipelineStudioInternalProps['yamlEditorConfig'] - onErrorChange?: PipelineStudioInternalProps['onErrorChange'] - getStepIcon?: PipelineStudioInternalProps['getStepIcon'] - animateYamlOnUpdate?: boolean - onYamlAnimateEnd?: () => void -} - -const PipelineStudio = (props: PipelineStudioProps): JSX.Element => { - return -} - -export { PipelineStudio } diff --git a/packages/ui/src/views/unified-pipeline-studio/components/entity-form/entity-form-layout.tsx b/packages/ui/src/views/unified-pipeline-studio/components/entity-form/entity-form-layout.tsx new file mode 100644 index 0000000000..cb3c06f4d6 --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/entity-form/entity-form-layout.tsx @@ -0,0 +1,27 @@ +const EntityFormLayout = { + Root: function Root({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Header: function Header({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Title: function Title({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Description: function Title({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Actions: function Title({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Footer: function Footer({ children }: { children: React.ReactNode }) { + return
{children}
+ } +} + +export { EntityFormLayout } diff --git a/packages/ui/src/views/unified-pipeline-studio/components/entity-form/entity-form-section-layout.tsx b/packages/ui/src/views/unified-pipeline-studio/components/entity-form/entity-form-section-layout.tsx new file mode 100644 index 0000000000..da6d17df42 --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/entity-form/entity-form-section-layout.tsx @@ -0,0 +1,23 @@ +const EntityFormSectionLayout = { + Root: function Root({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Header: function Header({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Title: function Title({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Description: function Title({ children }: { children: React.ReactNode }) { + return
{children}
+ }, + + Form: function Title({ children }: { children: React.ReactNode }) { + return
{children}
+ } +} + +export { EntityFormSectionLayout } diff --git a/packages/ui/src/views/unified-pipeline-studio/components/entity-form/unified-pipeline-studio-entity-form.tsx b/packages/ui/src/views/unified-pipeline-studio/components/entity-form/unified-pipeline-studio-entity-form.tsx new file mode 100644 index 0000000000..a632ed3b7f --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/entity-form/unified-pipeline-studio-entity-form.tsx @@ -0,0 +1,195 @@ +import { useEffect, useMemo, useState } from 'react' + +import { Button } from '@components/button' +import { Icon } from '@components/icon' +import { addNameInput } from '@views/unified-pipeline-studio/utils/entity-form-utils' +import { get } from 'lodash-es' +import { parse } from 'yaml' + +import { + getTransformers, + IFormDefinition, + inputTransformValues, + outputTransformValues, + RenderForm, + RootForm, + useZodValidationResolver +} from '@harnessio/forms' + +import { useUnifiedPipelineStudioContext } from '../../../unified-pipeline-studio/context/unified-pipeline-studio-context' +import { inputComponentFactory } from '../form-inputs/factory/factory' +import { InputType } from '../form-inputs/types' +import { getHarnessSteOrGroupIdentifier, getHarnessStepOrGroupDefinition } from '../steps/harness-steps' +import { EntityFormLayout } from './entity-form-layout' +import { EntityFormSectionLayout } from './entity-form-section-layout' + +interface UnifiedPipelineStudioEntityFormProps { + requestClose: () => void +} + +export const UnifiedPipelineStudioEntityForm = (props: UnifiedPipelineStudioEntityFormProps): JSX.Element => { + const { requestClose } = props + const { yamlRevision, addStepIntention, editStepIntention, requestYamlModifications, setFormEntity, formEntity } = + useUnifiedPipelineStudioContext() + + const [defaultStepValues, setDefaultStepValues] = useState({}) + + useEffect(() => { + console.log(editStepIntention) + if (editStepIntention) { + const yamlJson = parse(yamlRevision.yaml) + const step = get(yamlJson, editStepIntention.path) + console.log(step) + + const harnessStepIdentifier = getHarnessSteOrGroupIdentifier(step) + console.log(harnessStepIdentifier) + + // process harness step + if (harnessStepIdentifier) { + const stepDefinition = getHarnessStepOrGroupDefinition(harnessStepIdentifier) + console.log(stepDefinition, 'stepDefinition') + + if (stepDefinition) { + const transformers = getTransformers(stepDefinition?.formDefinition ?? { inputs: [] }) + const stepValue = inputTransformValues(step, transformers) + setDefaultStepValues(stepValue) + setFormEntity({ + source: 'embedded', + type: 'step', + data: { + identifier: stepDefinition.identifier, + description: stepDefinition.description + } + }) + } + } + // process templates step + // TODO + // else if (step[TEMPLATE_STEP_IDENTIFIER]) { + // setDefaultStepValues(step) + // listTemplates({ space_ref: spaceId || '', queryParams: { query: step.template.uses } }).then(response => { + // const editStep = response.body.find(plugin => plugin.identifier === step.template.uses) + // setFormStep(editStep ? { stepSource: StepSource.Templates, data: editStep } : null) + // }) + // } else if (step[GROUP_IDENTIFIER] || step[PARALLEL_IDENTIFIER]) { + // setDefaultStepValues(step) + // setFormStep({ + // stepSource: StepSource.Harness, + // data: { + // identifier: step[GROUP_IDENTIFIER] ? GROUP_IDENTIFIER : PARALLEL_IDENTIFIER + // } + // }) + // } + } + }, [editStepIntention]) + + const formDefinition: IFormDefinition = useMemo(() => { + if (formEntity?.source === 'embedded') { + const harnessStepDefinition = getHarnessStepOrGroupDefinition(formEntity.data.identifier) + if (harnessStepDefinition) { + return { + ...harnessStepDefinition.formDefinition, + inputs: addNameInput(harnessStepDefinition.formDefinition.inputs, 'name') + } + } + } else if (formEntity?.source === 'external') { + // TODO + // const stepData = JSON.parse(formStep?.data?.data ?? '{}') as StepDefinitionType + // const inputs = stepData.template.inputs + // const formInputs: IFormDefinition['inputs'] = Object.keys(inputs).map(inputName => { + // return apiInput2IInputDefinition(inputName, inputs[inputName], 'template.with') + // }) + // return { inputs: addNameInput(formInputs, 'name') } + } + + return { inputs: [] } + }, [formEntity]) + + const resolver = useZodValidationResolver(formDefinition, { + validationConfig: { + requiredMessage: 'Required input', + requiredMessagePerInput: { [InputType.select]: 'Selection is required' } + } + }) + + return ( + { + const transformers = getTransformers(formDefinition) + const stepValue = outputTransformValues(values, transformers) + + // TODO: "external" + // if (formStep?.stepSource === StepSource.Templates) { + // // NOTE: add 'uses' for template step + // stepValue = { + // ...stepValue, + // template: { + // uses: formStep?.data.identifier, + // ...stepValue.template + // } + // } + // } + + if (addStepIntention) { + requestYamlModifications.injectInArray({ + path: addStepIntention.path, + position: addStepIntention.position, + item: stepValue + }) + } else if (editStepIntention) { + requestYamlModifications.updateInArray({ + path: editStepIntention.path, + item: stepValue + }) + } + + requestClose() + }} + validateAfterFirstSubmit={true} + > + {rootForm => ( + + + {editStepIntention ? 'Edit' : 'Add'} Step + {formEntity?.data.description} + {/* + + */} + + + {/* */} + {/* General */} + {/* Read documentation to learn more. */} + {/* */} + + + + + +
+ + +
+ {editStepIntention && ( + + )} +
+
+ )} +
+ ) +} diff --git a/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/ArrayInput.tsx b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/ArrayInput.tsx new file mode 100644 index 0000000000..3f21abafae --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/ArrayInput.tsx @@ -0,0 +1,105 @@ +import { useCallback } from 'react' + +import { Button } from '@components/button' +import { FormField, FormItem } from '@components/form' +import { Icon } from '@components/icon' + +import { + AnyFormikValue, + Controller, + IInputDefinition, + InputComponent, + InputProps, + RenderInputs, + useFieldArray +} from '@harnessio/forms' + +import { InputError } from './common/InputError' +import InputLabel from './common/InputLabel' +import InputWrapper from './common/InputWrapper' +import { InputType } from './types' + +export type UIInputWithConfigsForArray = Omit + +export interface ArrayInputConfig { + inputType: InputType.array + inputConfig: { + input: IInputDefinition + } +} + +function ArrayInputInternal(props: InputProps): JSX.Element { + const { readonly, path, input, factory } = props + const { label, required, inputConfig, description } = input + + const { fields, append, remove } = useFieldArray({ + name: path + }) + + const getChildInputs = useCallback( + (rowInput: UIInputWithConfigsForArray, parentPath: string, idx: number): IInputDefinition[] => { + const retInput = { + ...rowInput, + // NOTE: create absolute path using parent path and index + path: `${parentPath}[${idx}]` + } as IInputDefinition + + return [retInput] + }, + [] + ) + + return ( + + ( + + + ( +
+
+ {fields.map((item, idx) => ( +
+ {inputConfig?.input && ( + + )} +
+ +
+
+ ))} +
+
+ +
+
+ )} + /> + +
+ )} + /> +
+ ) +} + +export class ArrayInput extends InputComponent { + public internalType = InputType.array + + renderComponent(props: InputProps): JSX.Element { + return + } +} diff --git a/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/BooleanInput.tsx b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/BooleanInput.tsx new file mode 100644 index 0000000000..e4caaf9ad0 --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/BooleanInput.tsx @@ -0,0 +1,52 @@ +import { FormControl, FormField, FormItem } from '@components/form' +import { Switch } from '@components/switch' + +import { InputComponent, InputProps, type AnyFormikValue, type UseFormReturn } from '@harnessio/forms' + +import { InputError } from './common/InputError' +import InputLabel from './common/InputLabel' +import InputWrapper from './common/InputWrapper' +import { InputType } from './types' + +export interface BooleanInputConfig { + inputType: InputType.boolean + inputConfig?: { + onChange: (value: AnyFormikValue, formik: UseFormReturn) => void + } +} + +function BooleanInputInternal(props: InputProps): JSX.Element { + const { readonly, path, input } = props + const { label = '', required, description } = input + + return ( + + ( + + + { + field.onChange(value) + }} + /> + + + + + )} + /> + + ) +} + +export class BooleanInput extends InputComponent { + public internalType = InputType.boolean + + renderComponent(props: InputProps): JSX.Element { + return + } +} diff --git a/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/GroupInput.tsx b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/GroupInput.tsx new file mode 100644 index 0000000000..12527eae78 --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/GroupInput.tsx @@ -0,0 +1,65 @@ +import { useEffect, useState } from 'react' + +import { Accordion } from '@components/accordion' +import { Icon } from '@components/icon' +import { get } from 'lodash-es' + +import { InputComponent, InputProps, RenderInputs, useFormContext, type AnyFormikValue } from '@harnessio/forms' + +import InputLabel from './common/InputLabel' +import { Layout } from './common/Layout' +import { InputType } from './types' + +export interface GroupInputConfig { + inputType: InputType.group +} + +function GroupInputInternal(props: InputProps): JSX.Element { + const { input, factory, path } = props + const { label = '', inputs = [], required, description } = input + + const { formState } = useFormContext() + const error = get(formState.errors, path) + + // NOTE: consider: if group is open hide error as it will be visible in the form + //const [isOpen, setIsOpen] = useState(false) + + // TODO: WORKAROUND/POC + const [forceMount, setForceMount] = useState(true) + useEffect(() => { + setForceMount(undefined) + }, []) + + return ( + setIsOpen(!!value)} + > + + + + + {error && } + + + + + + + + ) +} + +export class GroupInput extends InputComponent { + public internalType = InputType.group + + constructor() { + super() + } + + renderComponent(props: InputProps): JSX.Element { + return + } +} diff --git a/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/ListInput.tsx b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/ListInput.tsx new file mode 100644 index 0000000000..175fc7e1e0 --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/ListInput.tsx @@ -0,0 +1,133 @@ +import { useCallback } from 'react' + +import { Button } from '@components/button' +import { FormField, FormItem } from '@components/form' +import { Icon } from '@components/icon' + +import { + AnyFormikValue, + Controller, + IInputDefinition, + InputComponent, + InputProps, + RenderInputs, + useFieldArray +} from '@harnessio/forms' + +import { InputError } from './common/InputError' +import InputLabel from './common/InputLabel' +import InputWrapper from './common/InputWrapper' +import { InputType } from './types' + +export type UIInputWithConfigsForList = Omit, 'path'> & { + relativePath: string +} + +export interface ListInputConfig { + inputType: InputType.list + inputConfig: { + inputs: UIInputWithConfigsForList[] + layout?: 'grid' | 'default' + } +} + +function ListInputInternal(props: InputProps): JSX.Element { + const { readonly, path, input, factory } = props + const { label, required, inputConfig, description } = input + + const isGrid = inputConfig?.layout === 'grid' + // const len = inputConfig?.inputs.length + // const frArr = new Array(len).fill('1fr', 0, len) + const rowClass = isGrid ? `grid gap-2` : 'flex flex-col space-y-4' + const rowStyle = isGrid ? { gridTemplateColumns: `repeat(${inputConfig?.inputs.length}, 1fr) auto` } : {} + + const { fields, append, remove } = useFieldArray({ + name: path + }) + + const getChildInputs = useCallback( + (rowInputs: UIInputWithConfigsForList[], parentPath: string, idx: number): IInputDefinition[] => { + return rowInputs.map(orgInput => { + const retInput = { + ...orgInput, + // NOTE: create absolute path using parent path, index and relative paths + path: `${parentPath}[${idx}].${orgInput.relativePath}` + } as IInputDefinition + + if (isGrid) { + // label is rendered in header + delete retInput.label + // required is only used for optional label (validation is part of the root formik) + retInput.required = true + } + + return retInput + }) + }, + [inputConfig?.layout] + ) + + return ( + + ( + + + ( +
+
+ {isGrid && fields.length > 0 && ( +
+ {inputConfig?.inputs.map(rowInput => ( + + ))} +
+ )} + {fields.map((_item, idx) => ( +
+ {inputConfig?.inputs && ( + + )} +
+ +
+
+ ))} +
+ +
+ )} + /> + +
+ )} + /> +
+ ) +} + +export class ListInput extends InputComponent { + public internalType = InputType.list + + renderComponent(props: InputProps): JSX.Element { + return + } +} diff --git a/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/NumberInput.tsx b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/NumberInput.tsx new file mode 100644 index 0000000000..9f8f07672b --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/NumberInput.tsx @@ -0,0 +1,43 @@ +import { FormControl, FormField, FormItem } from '@components/form' +import { Input } from '@components/input' + +import { InputComponent, InputProps, type AnyFormikValue } from '@harnessio/forms' + +import { InputError } from './common/InputError' +import InputLabel from './common/InputLabel' +import InputWrapper from './common/InputWrapper' +import { InputType } from './types' + +export interface NumberInputConfig { + inputType: InputType.number +} + +function NumberInputInternal(props: InputProps): JSX.Element { + const { readonly, path, input } = props + const { label = '', required, placeholder, description } = input + + return ( + + ( + + + + + + + + )} + /> + + ) +} + +export class NumberInput extends InputComponent { + public internalType = InputType.number + + renderComponent(props: InputProps): JSX.Element { + return + } +} diff --git a/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/SelectInput.tsx b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/SelectInput.tsx new file mode 100644 index 0000000000..723f7790e8 --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/SelectInput.tsx @@ -0,0 +1,66 @@ +import { FormControl, FormField, FormItem } from '@components/form' +import { Select } from '@components/select' + +import { InputComponent, InputProps, type AnyFormikValue } from '@harnessio/forms' + +import { InputError } from './common/InputError' +import InputLabel from './common/InputLabel' +import InputWrapper from './common/InputWrapper' +import { InputType } from './types' + +export interface SelectOption { + label: string + value: string +} + +export interface SelectInputConfig { + inputType: InputType.select + inputConfig: { + options: SelectOption[] + } +} +function SelectInputInternal(props: InputProps): JSX.Element { + const { readonly, path, input } = props + const { label = '', required, description, inputConfig } = input + + return ( + + ( + + + + { + field.onChange(value) + }} + > + + {inputConfig?.options.map(item => { + return ( + + {item.label} + + ) + })} + + + + + + )} + /> + + ) +} + +export class SelectInput extends InputComponent { + public internalType = InputType.select + + renderComponent(props: InputProps): JSX.Element { + return + } +} diff --git a/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/Separator.tsx b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/Separator.tsx new file mode 100644 index 0000000000..5efa1d0dc7 --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/Separator.tsx @@ -0,0 +1,21 @@ +import { FormSeparator } from '@components/form-primitives' + +import { InputComponent, type AnyFormikValue } from '@harnessio/forms' + +import { InputType } from './types' + +export interface SeparatorInputConfig { + inputType: InputType.separator +} + +function SeparatorInputInternal(): JSX.Element { + return +} + +export class SeparatorInput extends InputComponent { + public internalType = InputType.separator + + renderComponent(): JSX.Element { + return + } +} diff --git a/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/TextAreaInput.tsx b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/TextAreaInput.tsx new file mode 100644 index 0000000000..f8d5b7e359 --- /dev/null +++ b/packages/ui/src/views/unified-pipeline-studio/components/form-inputs/TextAreaInput.tsx @@ -0,0 +1,43 @@ +import { FormControl, FormField, FormItem } from '@components/form' + +import { InputComponent, InputProps, type AnyFormikValue } from '@harnessio/forms' +import { Textarea } from '@harnessio/ui/components' + +import { InputError } from './common/InputError' +import InputLabel from './common/InputLabel' +import InputWrapper from './common/InputWrapper' +import { InputType } from './types' + +export interface TextAreaInputConfig { + inputType: InputType.textarea +} + +function TextAreaInputInternal(props: InputProps): JSX.Element { + const { readonly, path, input } = props + const { label = '', required, placeholder, description } = input + + return ( + + ( + + + +