2146 lines
		
	
	
		
			63 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			2146 lines
		
	
	
		
			63 KiB
		
	
	
	
		
			Ruby
		
	
	
	
class Api::V1::Projects::PipelinesController < Api::V1::BaseController
 | 
						|
  include RepositoriesHelper
 | 
						|
  before_action :require_operate_above, except: [:upload_results, :run_results]
 | 
						|
 | 
						|
  def index
 | 
						|
    pipelines = Action::Pipeline.where(project_id: @project.id).order(updated_at: :desc)
 | 
						|
    @files = $gitea_client.get_repos_contents_by_owner_repo_filepath(@project&.owner&.login, @project&.identifier, ".gitea/workflows") rescue []
 | 
						|
    @action_runs = Gitea::ActionRun.where(repo_id: @project.gpid)
 | 
						|
    group_data = @action_runs.where(status: [1,2]).group(:workflow_id, :status).count
 | 
						|
    db_files = pipelines.pluck(:file_name)
 | 
						|
    @run_result = []
 | 
						|
    @files.map { |i| i['name'] }.each do |file|
 | 
						|
      unless db_files.include?(".gitea/workflows/#{file}")
 | 
						|
        pipeline = Action::Pipeline.find_or_initialize_by(pipeline_name: file.to_s.gsub(".yml", "").gsub(".yaml", ""),
 | 
						|
                                        file_name: ".gitea/workflows/#{file}",
 | 
						|
                                        branch: @project.default_branch,
 | 
						|
                                        is_graphic_design: false,
 | 
						|
                                        disable: false,
 | 
						|
                                        project_id: @project.id)
 | 
						|
        interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, ".gitea/workflows/#{file}", ref: @project.default_branch)
 | 
						|
        if interactor.success?
 | 
						|
          pipeline.yaml = decode64_content(interactor.result, @owner, @project.repository, @project.default_branch, nil)
 | 
						|
        end
 | 
						|
        pipeline.user_id  = current_user.id
 | 
						|
        pipeline.save
 | 
						|
        # 导入的流水线统一先禁用
 | 
						|
        $gitea_hat_client.post_repos_actions_disable(@project&.owner&.login, @project&.identifier, {query: {workflow: file}}) rescue nil
 | 
						|
      end
 | 
						|
      last_action_run = @action_runs.where(workflow_id: file).order(updated: :desc).first
 | 
						|
      last_action_run_json = last_action_run.present? ? {
 | 
						|
        id: last_action_run.id,
 | 
						|
        schedule: last_action_run.schedule_id > 0,
 | 
						|
        title: last_action_run.title,
 | 
						|
        index: last_action_run.index,
 | 
						|
        status: last_action_run.status,
 | 
						|
        started: last_action_run.started,
 | 
						|
        stopped: last_action_run.stopped,
 | 
						|
        length: last_action_run.stopped-last_action_run.started,
 | 
						|
        created: last_action_run.created,
 | 
						|
        updated: last_action_run.updated,
 | 
						|
      } : {}
 | 
						|
 | 
						|
      total = 0
 | 
						|
      success = 0
 | 
						|
      failure = 0
 | 
						|
      group_data.each do |k,v|
 | 
						|
        total += v if k[0] == file
 | 
						|
        success += v if k[0] == file && k[1] == 1
 | 
						|
        failure += v if k[0] == file && k[1] == 2
 | 
						|
      end
 | 
						|
      @run_result << {
 | 
						|
        filename: ".gitea/workflows/#{file}",
 | 
						|
        total: total,
 | 
						|
        success: success,
 | 
						|
        failure: failure
 | 
						|
      }.merge(last_action_run_json)
 | 
						|
    end
 | 
						|
    # Rails.logger.info("@run_result======#{@run_result}")
 | 
						|
    disabled_config = Gitea::RepoUnit.where(repo_id: @project.gpid, type: 10)&.first&.config
 | 
						|
    @disabled_workflows = disabled_config.present? ? JSON.parse(disabled_config)["DisabledWorkflows"] : []
 | 
						|
    @pipelines = Action::Pipeline.where(project_id: @project.id).order(updated_at: :desc)
 | 
						|
    @pipelines = kaminari_paginate(@pipelines)
 | 
						|
  end
 | 
						|
 | 
						|
  def test_yaml
 | 
						|
    pipeline_yaml = build_pipeline_yaml_new("test", JSON.parse(demo2.to_json))
 | 
						|
    respond_to do |format|
 | 
						|
      format.html { @nodes = Action::Node.all }
 | 
						|
      # format.yaml { @nodes = Action::Node.all }
 | 
						|
      format.yaml { render template: "api/v1/projects/pipelines/test_yaml", content_type: "text/html" }
 | 
						|
      format.json { render_ok({ pipeline_yaml: pipeline_yaml }) }
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def create
 | 
						|
    @pipeline = params[:id].present? ? Action::Pipeline.find(params[:id]) : Action::Pipeline.find_or_initialize_by(pipeline_name: params[:pipeline_name], project_id: @project.id)
 | 
						|
    if @pipeline.pipeline_name != params[:pipeline_name]
 | 
						|
      has_pipeline = Action::Pipeline.where(pipeline_name: params[:pipeline_name], project_id: @project.id).where.not(id: @pipeline.id)
 | 
						|
      tip_exception("已经存在#{params[:pipeline_name]}流水线!") if has_pipeline.present?
 | 
						|
      if @pipeline.yaml.present?
 | 
						|
        sha = get_pipeline_file_sha(@pipeline.file_name, @pipeline.branch)
 | 
						|
        if sha.present?
 | 
						|
          interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, content_params("update", params[:pipeline_name]).merge(sha: sha, from_path: "#{@pipeline.pipeline_name}"))
 | 
						|
          tip_exception(interactor.error) unless interactor.success?
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
    @pipeline.pipeline_name = params[:pipeline_name]
 | 
						|
    @pipeline.file_name = ".gitea/workflows/#{@pipeline.pipeline_name}.yml"
 | 
						|
    @pipeline.branch = params[:branch] || @project.default_branch
 | 
						|
    @pipeline.is_graphic_design = params[:pipeline_type] == 2 ? true : false
 | 
						|
    @pipeline.pipeline_type = params[:pipeline_type] if params[:pipeline_type].present?
 | 
						|
    @pipeline.save!
 | 
						|
  end
 | 
						|
 | 
						|
  def save_yaml
 | 
						|
    @pipeline = params[:id].present? ? Action::Pipeline.find(params[:id]) : Action::Pipeline.find_or_initialize_by(pipeline_name: params[:pipeline_name], project_id: @project.id)
 | 
						|
    @pipeline.file_name = ".gitea/workflows/#{@pipeline.pipeline_name}.yml"
 | 
						|
    @pipeline.branch = params[:branch] if params[:branch].present?
 | 
						|
    @pipeline.json = params[:pipeline_json].to_json if params[:pipeline_json].present?
 | 
						|
    @pipeline.pipeline_name = params[:pipeline_name] if params[:pipeline_name].present?
 | 
						|
    pipeline_yaml = params[:pipeline_yaml].present? ? params[:pipeline_yaml] : build_pipeline_yaml_new(@pipeline.pipeline_name, params[:pipeline_json])
 | 
						|
    tip_exception("流水线yaml内空不能为空") if pipeline_yaml.blank?
 | 
						|
    @pipeline.yaml = pipeline_yaml
 | 
						|
    #Rails.logger.info "pipeline_yaml base64=========================#{Base64.encode64(@pipeline.yaml).gsub(/\n/, '')}"
 | 
						|
    sha = get_pipeline_file_sha(@pipeline.file_name, @pipeline.branch)
 | 
						|
    #Rails.logger.info "content_params=========#{content_params("create")}"
 | 
						|
    interactor = sha.present? ? Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, content_params("update").merge(sha: sha)) : Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params("create"))
 | 
						|
    tip_exception(interactor.error) unless interactor.success?
 | 
						|
    file = interactor.result
 | 
						|
    @pipeline.pipeline_type = @pipeline.json.present? ? 2 : 1
 | 
						|
    @pipeline.save
 | 
						|
    render_ok({ pipeline_yaml: pipeline_yaml, pipeline_name: @pipeline.pipeline_name, file_name: @pipeline.file_name, sha: sha.present? ? sha : file['content']['sha'] })
 | 
						|
  end
 | 
						|
 | 
						|
  def build_yaml
 | 
						|
    if params[:pipeline_json].present?
 | 
						|
      pipeline_yaml = build_pipeline_yaml(params[:pipeline_name], params[:pipeline_json])
 | 
						|
    else
 | 
						|
      pipeline_yaml = build_test_yaml
 | 
						|
    end
 | 
						|
    # render plain: pipeline_yaml
 | 
						|
    render_ok({ pipeline_yaml: pipeline_yaml })
 | 
						|
  end
 | 
						|
 | 
						|
  def update
 | 
						|
    @pipeline = Action::Pipeline.find(params[:id])
 | 
						|
    @pipeline.pipeline_name = params[:pipeline_name]
 | 
						|
    @pipeline.file_name = ".gitea/workflows/#{@pipeline.pipeline_name}.yml"
 | 
						|
    @pipeline.branch = params[:branch] || @project.default_branch
 | 
						|
    @pipeline.json = params[:pipeline_json].to_json
 | 
						|
    pipeline_yaml = build_pipeline_yaml(params[:pipeline_name], params[:pipeline_json])
 | 
						|
    tip_exception("流水线yaml内空不能为空") if pipeline_yaml.blank?
 | 
						|
    @pipeline.yaml = pipeline_yaml
 | 
						|
    @pipeline.save
 | 
						|
    sha = get_pipeline_file_sha(@pipeline.file_name, @pipeline.branch)
 | 
						|
    interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, content_params("create").merge(sha: sha))
 | 
						|
    tip_exception(interactor.error) unless interactor.success?
 | 
						|
    file = interactor.result
 | 
						|
    render_ok({ pipeline_yaml: pipeline_yaml, pipeline_name: params[:pipeline_name], file_name: @pipeline.file_name, sha: file['content']['sha'] })
 | 
						|
  end
 | 
						|
 | 
						|
  def destroy
 | 
						|
    @pipeline = Action::Pipeline.find(params[:id])
 | 
						|
    if @pipeline
 | 
						|
      sha = get_pipeline_file_sha(@pipeline.file_name, @pipeline.branch)
 | 
						|
      if sha.present?
 | 
						|
        interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, del_content_params(sha).merge(identifier: @project.identifier))
 | 
						|
        tip_exception(interactor.error) unless interactor.success?
 | 
						|
      end
 | 
						|
      Gitea::ActionRun.where(repo_id: @pipeline.project.gpid).destroy_all
 | 
						|
      @pipeline.destroy!
 | 
						|
    end
 | 
						|
    render_ok
 | 
						|
  end
 | 
						|
 | 
						|
  def upload_results
 | 
						|
    tip_exception("参数错误") if params[:owner].blank? || params[:repo].blank? || params[:run_id].blank?
 | 
						|
    @project, @owner = Project.find_with_namespace(params[:owner], params[:repo])
 | 
						|
    tip_exception("项目不存在") if @project.blank?
 | 
						|
    result = Action::PipelineResult.find_or_initialize_by(run_id: params[:run_id], step_id: params[:step_id], project_id: @project.id)
 | 
						|
    result.step_id = params[:step_id]
 | 
						|
    result.job_name = params[:job_name]
 | 
						|
    result.job_show_type = params[:job_show_type] || "html"
 | 
						|
    result.job_result = params[:job_result]
 | 
						|
    if result.save!
 | 
						|
      render_ok
 | 
						|
    else
 | 
						|
      render_error("保存失败")
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def run_results
 | 
						|
    tip_exception("参数错误") if params[:owner].blank? || params[:repo].blank? || params[:run_id].blank?
 | 
						|
    @project, @owner = Project.find_with_namespace(params[:owner], params[:repo])
 | 
						|
    tip_exception("项目不存在") if @project.blank?
 | 
						|
    results = Action::PipelineResult.where(run_id: params[:run_id], project_id: @project.id)
 | 
						|
    render_ok(run_results: results.as_json(only: %i[id run_id job_name job_show_type job_result]))
 | 
						|
  end
 | 
						|
 | 
						|
  def show
 | 
						|
    @pipeline = Action::Pipeline.find_by(id: params[:id])
 | 
						|
    disabled_config = Gitea::RepoUnit.where(repo_id: @project.gpid, type: 10)&.first&.config
 | 
						|
    @disabled_workflows = disabled_config.present? ? JSON.parse(disabled_config)["DisabledWorkflows"] : []
 | 
						|
    # @pipeline = Action::Pipeline.new(id: 0, pipeline_name: "test-ss", yaml: build_test_yaml) if @pipeline.blank?
 | 
						|
  end
 | 
						|
 | 
						|
  def build_pipeline_yaml_new(pipeline_name, pipeline_json)
 | 
						|
    @pipeline_name = pipeline_name
 | 
						|
    job_nodes = pipeline_json["nodes"].select { |node| node["data"]["name"].to_s.include?("job") }
 | 
						|
    on_nodes = pipeline_json["nodes"].select { |node| ["on-push", "on-schedule", "on-pull_request", "on-fork"].include?(node["data"]["name"]) }
 | 
						|
    @on_nodes = build_nodes(on_nodes)
 | 
						|
    @job_nodes = []
 | 
						|
    job_nodes.each do |job|
 | 
						|
      node = Action::Node.find_by(name: job["data"]["name"])
 | 
						|
      next if node.blank?
 | 
						|
      node.label = job["data"]["label"] if job["data"]["label"].present?
 | 
						|
      node.node_id = job["id"] if job["id"].present?
 | 
						|
      next_edge_nodes = pipeline_json["edges"].select { |edge| edge["source"]["cell"].include?(job["id"]) }
 | 
						|
      node_ids = next_edge_nodes.map { |t| t["target"]["cell"] }
 | 
						|
      next_step_node = pipeline_json["nodes"].select { |node| node_ids.include?(node["id"]) && !node["data"]["name"].to_s.include?("job") }&.first
 | 
						|
      parent_node = pipeline_json["edges"].select { |edge| edge["target"]["cell"].include?(job["id"]) }.first
 | 
						|
      node.parent_node_id = parent_node.present? ? parent_node["source"]["cell"] : ""
 | 
						|
      node.sub_nodes = []
 | 
						|
      get_all_child_nodes(pipeline_json, node, next_step_node) if next_step_node.present?
 | 
						|
      @job_nodes.push(node)
 | 
						|
    end
 | 
						|
    yaml = ERB.new(File.read(File.join(Rails.root, "app/views/api/v1/projects/pipelines", "build_pipeline.yaml.erb"))).result(binding)
 | 
						|
    pipeline_yaml = yaml.gsub(/^\s*\n/, "")
 | 
						|
    Rails.logger.info "========================="
 | 
						|
    Rails.logger.info pipeline_yaml
 | 
						|
    pipeline_yaml
 | 
						|
  end
 | 
						|
 | 
						|
  private
 | 
						|
 | 
						|
  def get_pipeline_file_sha(file_name, branch)
 | 
						|
    file_path_uri = URI.parse(URI.encode(file_name))
 | 
						|
    interactor = Repositories::EntriesInteractor.call(@project.owner, @project.identifier, file_path_uri, ref: branch || @project.default_branch)
 | 
						|
    if interactor.success?
 | 
						|
      file = interactor.result
 | 
						|
      file['sha']
 | 
						|
    else
 | 
						|
      nil
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def content_params(opt, rename_file=nil)
 | 
						|
    {
 | 
						|
      filepath: ".gitea/workflows/#{rename_file.present? ? rename_file : @pipeline.pipeline_name}.yml",
 | 
						|
      branch: @pipeline.branch,
 | 
						|
      new_branch: @pipeline.branch,
 | 
						|
      content: opt == "create" ? Base64.encode64(@pipeline.yaml).gsub(/\n/, '') : @pipeline.yaml,
 | 
						|
      message: opt == "create" ? "创建流水线:#{@pipeline.pipeline_name}" : "修改流水线:#{@pipeline.pipeline_name}",
 | 
						|
      committer: {
 | 
						|
        email: current_user.mail,
 | 
						|
        name: current_user.login
 | 
						|
      },
 | 
						|
      identifier: @project.identifier
 | 
						|
    }
 | 
						|
  end
 | 
						|
 | 
						|
  def del_content_params(sha)
 | 
						|
    {
 | 
						|
      filepath: ".gitea/workflows/#{@pipeline.pipeline_name}.yml",
 | 
						|
      base64_filepath: Base64.encode64(".gitea/workflows/#{@pipeline.pipeline_name}.yml").gsub(/\n/, ''),
 | 
						|
      branch: @pipeline.branch,
 | 
						|
      sha: sha
 | 
						|
    }
 | 
						|
  end
 | 
						|
 | 
						|
  def build_nodes(params_nodes)
 | 
						|
    steps_nodes = []
 | 
						|
    params_nodes.each do |input_node|
 | 
						|
      node = Action::Node.find_by(name: input_node["data"]["name"])
 | 
						|
      next if node.blank?
 | 
						|
      node.label = input_node["data"]["label"] if input_node["data"]["label"].present?
 | 
						|
      node.node_id = input_node["id"] if input_node["id"].present?
 | 
						|
      run_values = {}
 | 
						|
      input_values = {}
 | 
						|
      if input_node["data"]["inputs"].present?
 | 
						|
        input_node["data"]["inputs"].each do |input|
 | 
						|
          if input["name"].to_s.gsub("--", "") == "run"
 | 
						|
            run_values = run_values.merge({ "#{input["name"].gsub("--", "")}": "#{input["value"]}" })
 | 
						|
          else
 | 
						|
            input_values = input_values.merge({ "#{input["name"].gsub("--", "")}": "#{input["value"]}" })
 | 
						|
          end
 | 
						|
        end
 | 
						|
        node.run_values = run_values
 | 
						|
        node.input_values = input_values
 | 
						|
      end
 | 
						|
      steps_nodes.push(node)
 | 
						|
    end
 | 
						|
    steps_nodes
 | 
						|
  end
 | 
						|
 | 
						|
  def get_all_child_nodes(pipeline_json, job_node, target_node)
 | 
						|
    job_node.sub_nodes.push(get_node_info(target_node))
 | 
						|
    target_edge = pipeline_json["edges"].select { |node| node["source"]["cell"].to_s.include?(target_node["id"]) }&.first
 | 
						|
    # 判断是否有子节点
 | 
						|
    if target_edge.present?
 | 
						|
      next_node = pipeline_json["nodes"].select { |node| node["id"].include?(target_edge["target"]["cell"]) }.first
 | 
						|
      get_all_child_nodes(pipeline_json, job_node, next_node)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def get_node_info(input_node)
 | 
						|
    node = Action::Node.find_by(name: input_node["data"]["name"])
 | 
						|
    return nil if node.blank?
 | 
						|
    node.label = input_node["data"]["label"] if input_node["data"]["label"].present?
 | 
						|
    node.node_id = input_node["id"] if input_node["id"].present?
 | 
						|
    run_values = {}
 | 
						|
    input_values = {}
 | 
						|
    if input_node["data"]["inputs"].present?
 | 
						|
      input_node["data"]["inputs"].each do |input|
 | 
						|
        if input["name"].to_s.gsub("--", "") == "run"
 | 
						|
          run_values = run_values.merge({ "#{input["name"].gsub("--", "")}": "#{input["value"]}" })
 | 
						|
        else
 | 
						|
          input_values = input_values.merge({ "#{input["name"].gsub("--", "")}": "#{input["value"]}" })
 | 
						|
        end
 | 
						|
      end
 | 
						|
      node.run_values = run_values
 | 
						|
      node.input_values = input_values
 | 
						|
    end
 | 
						|
    node
 | 
						|
  end
 | 
						|
 | 
						|
  def demo2
 | 
						|
    {
 | 
						|
      "nodes": [
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 290,
 | 
						|
            "y": 190
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "on-push-b2c871f-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "on-push-b2c871f-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "on-push-b2c871f-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "on-push-b2c871f-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "on-push-b2c871f",
 | 
						|
          "data": {
 | 
						|
            "id": "on-push-b2c871f",
 | 
						|
            "label": "代码push事件启动",
 | 
						|
            "name": "on-push",
 | 
						|
            "full_name": "on-push",
 | 
						|
            "description": "GitLink仓库push事件",
 | 
						|
            "icon": "http://172.20.32.201:4000/api/attachments/c2f255e7-f359-4085-b5ce-1f05850ad74c",
 | 
						|
            "action_node_types_id": 3,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "start",
 | 
						|
            "is_mutil_link": true,
 | 
						|
            "link_type": "job",
 | 
						|
            "inputs": [
 | 
						|
              {
 | 
						|
                "id": 6,
 | 
						|
                "name": "branches",
 | 
						|
                "input_type": "input",
 | 
						|
                "description": "分支名称,多个分支英文逗号隔开,如'master,dev'",
 | 
						|
                "is_required": true,
 | 
						|
                "value": "master"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": 7,
 | 
						|
                "name": "paths-ignore",
 | 
						|
                "input_type": "input",
 | 
						|
                "description": "忽略文件,多个文件英文逗号隔开,如'**.md,**.yaml'",
 | 
						|
                "is_required": false,
 | 
						|
                "value": "'*.md'"
 | 
						|
              }
 | 
						|
            ],
 | 
						|
            "x": 673,
 | 
						|
            "y": 495,
 | 
						|
            "img": "http://172.20.32.201:4000/api/attachments/c2f255e7-f359-4085-b5ce-1f05850ad74c",
 | 
						|
            "branches": "master",
 | 
						|
            "paths-ignore": "'*.md'"
 | 
						|
          },
 | 
						|
          "zIndex": 1,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 680,
 | 
						|
            "y": 190
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "job-ed9ed25-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-ed9ed25-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-ed9ed25-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-ed9ed25-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "job-ed9ed25",
 | 
						|
          "data": {
 | 
						|
            "id": "job-ed9ed25",
 | 
						|
            "label": "单元测试",
 | 
						|
            "name": "job",
 | 
						|
            "full_name": "",
 | 
						|
            "description": "允许并行多个任务",
 | 
						|
            "icon": "",
 | 
						|
            "action_node_types_id": 7,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "job",
 | 
						|
            "is_mutil_link": true,
 | 
						|
            "link_type": "job,step",
 | 
						|
            "inputs": [],
 | 
						|
            "x": 1093,
 | 
						|
            "y": 513,
 | 
						|
            "img": ""
 | 
						|
          },
 | 
						|
          "zIndex": 2,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 1090,
 | 
						|
            "y": 190
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "job-3359fd2c-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-3359fd2c-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-3359fd2c-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-3359fd2c-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "job-3359fd2c",
 | 
						|
          "data": {
 | 
						|
            "id": "job-3359fd2c",
 | 
						|
            "label": "压力测试",
 | 
						|
            "name": "job",
 | 
						|
            "full_name": "",
 | 
						|
            "description": "允许并行多个任务",
 | 
						|
            "icon": "",
 | 
						|
            "action_node_types_id": 7,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "job",
 | 
						|
            "is_mutil_link": true,
 | 
						|
            "link_type": "job,step",
 | 
						|
            "inputs": [],
 | 
						|
            "x": 1493,
 | 
						|
            "y": 540,
 | 
						|
            "img": ""
 | 
						|
          },
 | 
						|
          "zIndex": 3,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 680,
 | 
						|
            "y": 380
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "shell-79d5ba5d-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-79d5ba5d-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-79d5ba5d-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-79d5ba5d-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "shell-79d5ba5d",
 | 
						|
          "data": {
 | 
						|
            "id": "shell-79d5ba5d",
 | 
						|
            "label": "运行Shell脚本",
 | 
						|
            "name": "shell",
 | 
						|
            "full_name": "shell",
 | 
						|
            "description": "",
 | 
						|
            "icon": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "action_node_types_id": 4,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "step",
 | 
						|
            "is_mutil_link": false,
 | 
						|
            "link_type": "step",
 | 
						|
            "inputs": [
 | 
						|
              {
 | 
						|
                "id": 3,
 | 
						|
                "name": "run",
 | 
						|
                "input_type": "input",
 | 
						|
                "is_required": false,
 | 
						|
                "value": "echo 111"
 | 
						|
              }
 | 
						|
            ],
 | 
						|
            "x": 1190,
 | 
						|
            "y": 662,
 | 
						|
            "img": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "run": "echo 111"
 | 
						|
          },
 | 
						|
          "zIndex": 5,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 1470,
 | 
						|
            "y": 190
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "job-7760b89e-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-7760b89e-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-7760b89e-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "job-7760b89e-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "job-7760b89e",
 | 
						|
          "data": {
 | 
						|
            "id": "job-7760b89e",
 | 
						|
            "label": "功能测试",
 | 
						|
            "name": "job",
 | 
						|
            "full_name": "",
 | 
						|
            "description": "允许并行多个任务",
 | 
						|
            "icon": "",
 | 
						|
            "action_node_types_id": 7,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "job",
 | 
						|
            "is_mutil_link": true,
 | 
						|
            "link_type": "job,step",
 | 
						|
            "inputs": [],
 | 
						|
            "x": 1909,
 | 
						|
            "y": 552,
 | 
						|
            "img": ""
 | 
						|
          },
 | 
						|
          "zIndex": 4,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 1090,
 | 
						|
            "y": 370
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "shell-dd97c50-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-dd97c50-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-dd97c50-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-dd97c50-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "shell-dd97c50",
 | 
						|
          "data": {
 | 
						|
            "id": "shell-dd97c50",
 | 
						|
            "label": "运行Shell脚本",
 | 
						|
            "name": "shell",
 | 
						|
            "full_name": "shell",
 | 
						|
            "description": "",
 | 
						|
            "icon": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "action_node_types_id": 4,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "step",
 | 
						|
            "is_mutil_link": false,
 | 
						|
            "link_type": "step",
 | 
						|
            "inputs": [
 | 
						|
              {
 | 
						|
                "id": 3,
 | 
						|
                "name": "run",
 | 
						|
                "input_type": "input",
 | 
						|
                "is_required": false,
 | 
						|
                "value": "echo 444"
 | 
						|
              }
 | 
						|
            ],
 | 
						|
            "x": 1572,
 | 
						|
            "y": 725,
 | 
						|
            "img": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "run": "echo 444"
 | 
						|
          },
 | 
						|
          "zIndex": 7,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 680,
 | 
						|
            "y": 560
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "shell-799aadee-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-799aadee-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-799aadee-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-799aadee-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "shell-799aadee",
 | 
						|
          "data": {
 | 
						|
            "id": "shell-799aadee",
 | 
						|
            "label": "唱首歌",
 | 
						|
            "name": "shell",
 | 
						|
            "full_name": "shell",
 | 
						|
            "description": "",
 | 
						|
            "icon": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "action_node_types_id": 4,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "step",
 | 
						|
            "is_mutil_link": false,
 | 
						|
            "link_type": "step",
 | 
						|
            "inputs": [
 | 
						|
              {
 | 
						|
                "id": 3,
 | 
						|
                "name": "run",
 | 
						|
                "input_type": "input",
 | 
						|
                "is_required": false,
 | 
						|
                "value": "echo 222"
 | 
						|
              }
 | 
						|
            ],
 | 
						|
            "x": 1190,
 | 
						|
            "y": 922,
 | 
						|
            "img": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "run": "echo 222"
 | 
						|
          },
 | 
						|
          "zIndex": 6,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 1470,
 | 
						|
            "y": 370
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "shell-1766a765-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-1766a765-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-1766a765-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-1766a765-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "shell-1766a765",
 | 
						|
          "data": {
 | 
						|
            "id": "shell-1766a765",
 | 
						|
            "label": "运行Shell脚本",
 | 
						|
            "name": "shell",
 | 
						|
            "full_name": "shell",
 | 
						|
            "description": "",
 | 
						|
            "icon": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "action_node_types_id": 4,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "step",
 | 
						|
            "is_mutil_link": false,
 | 
						|
            "link_type": "step",
 | 
						|
            "inputs": [
 | 
						|
              {
 | 
						|
                "id": 3,
 | 
						|
                "name": "run",
 | 
						|
                "input_type": "input",
 | 
						|
                "is_required": false,
 | 
						|
                "value": "echo 666"
 | 
						|
              }
 | 
						|
            ],
 | 
						|
            "x": 1986,
 | 
						|
            "y": 702,
 | 
						|
            "img": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "run": "echo 666"
 | 
						|
          },
 | 
						|
          "zIndex": 9,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 1090,
 | 
						|
            "y": 550
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "shell-4e09400-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-4e09400-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-4e09400-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-4e09400-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "shell-4e09400",
 | 
						|
          "data": {
 | 
						|
            "id": "shell-4e09400",
 | 
						|
            "label": "测试报告浏览",
 | 
						|
            "name": "shell",
 | 
						|
            "full_name": "shell",
 | 
						|
            "description": "",
 | 
						|
            "icon": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "action_node_types_id": 4,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "step",
 | 
						|
            "is_mutil_link": false,
 | 
						|
            "link_type": "step",
 | 
						|
            "inputs": [
 | 
						|
              {
 | 
						|
                "id": 3,
 | 
						|
                "name": "run",
 | 
						|
                "input_type": "input",
 | 
						|
                "is_required": false,
 | 
						|
                "value": "echo 555"
 | 
						|
              }
 | 
						|
            ],
 | 
						|
            "x": 1577,
 | 
						|
            "y": 904,
 | 
						|
            "img": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "run": "echo 555"
 | 
						|
          },
 | 
						|
          "zIndex": 8,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 680,
 | 
						|
            "y": 760
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "shell-5cec9ec-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-5cec9ec-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-5cec9ec-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "shell-5cec9ec-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "shell-5cec9ec",
 | 
						|
          "data": {
 | 
						|
            "id": "shell-5cec9ec",
 | 
						|
            "label": "运行Shell脚本",
 | 
						|
            "name": "shell",
 | 
						|
            "full_name": "shell",
 | 
						|
            "description": "",
 | 
						|
            "icon": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "action_node_types_id": 4,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "step",
 | 
						|
            "is_mutil_link": false,
 | 
						|
            "link_type": "step",
 | 
						|
            "inputs": [
 | 
						|
              {
 | 
						|
                "id": 3,
 | 
						|
                "name": "run",
 | 
						|
                "input_type": "input",
 | 
						|
                "is_required": false,
 | 
						|
                "value": "echo 333"
 | 
						|
              }
 | 
						|
            ],
 | 
						|
            "x": 1189,
 | 
						|
            "y": 1082,
 | 
						|
            "img": "http://172.20.32.201:4000/api/attachments/1d739f94-4e5e-41b8-be7b-13482a099c76",
 | 
						|
            "run": "echo 333"
 | 
						|
          },
 | 
						|
          "zIndex": 10,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "position": {
 | 
						|
            "x": 1470,
 | 
						|
            "y": 560
 | 
						|
          },
 | 
						|
          "size": {
 | 
						|
            "width": 212,
 | 
						|
            "height": 48
 | 
						|
          },
 | 
						|
          "view": "react-shape-view",
 | 
						|
          "shape": "data-processing-dag-node",
 | 
						|
          "ports": {
 | 
						|
            "groups": {
 | 
						|
              "top": {
 | 
						|
                "position": {
 | 
						|
                  "name": "top",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "bottom": {
 | 
						|
                "position": {
 | 
						|
                  "name": "bottom",
 | 
						|
                  "args": {
 | 
						|
                    "dx": 0
 | 
						|
                  }
 | 
						|
                },
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "left": {
 | 
						|
                "position": "left",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              },
 | 
						|
              "right": {
 | 
						|
                "position": "right",
 | 
						|
                "attrs": {
 | 
						|
                  "circle": {
 | 
						|
                    "r": 4,
 | 
						|
                    "magnet": true,
 | 
						|
                    "strokeWidth": 1,
 | 
						|
                    "fill": "#fff",
 | 
						|
                    "stroke": "#85A5FF"
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              }
 | 
						|
            },
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "id": "checkout-gitlink-f6e67fe-left",
 | 
						|
                "group": "left"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "checkout-gitlink-f6e67fe-right",
 | 
						|
                "group": "right"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "checkout-gitlink-f6e67fe-top",
 | 
						|
                "group": "top"
 | 
						|
              },
 | 
						|
              {
 | 
						|
                "id": "checkout-gitlink-f6e67fe-bottom",
 | 
						|
                "group": "bottom"
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          },
 | 
						|
          "id": "checkout-gitlink-f6e67fe",
 | 
						|
          "data": {
 | 
						|
            "id": "checkout-gitlink-f6e67fe",
 | 
						|
            "label": "加速版-克隆代码",
 | 
						|
            "name": "checkout-gitlink",
 | 
						|
            "full_name": "https://gitlink.org.cn/actions/checkout@v4",
 | 
						|
            "description": "",
 | 
						|
            "icon": "http://172.20.32.201:4000/api/attachments/c2f255e7-f359-4085-b5ce-1f05850ad74c",
 | 
						|
            "action_node_types_id": 6,
 | 
						|
            "yaml": "",
 | 
						|
            "sort_no": 0,
 | 
						|
            "use_count": 0,
 | 
						|
            "node_type": "step",
 | 
						|
            "is_mutil_link": false,
 | 
						|
            "link_type": "step",
 | 
						|
            "inputs": [],
 | 
						|
            "x": 2017,
 | 
						|
            "y": 887,
 | 
						|
            "img": "http://172.20.32.201:4000/api/attachments/c2f255e7-f359-4085-b5ce-1f05850ad74c"
 | 
						|
          },
 | 
						|
          "zIndex": 11,
 | 
						|
          "isDelete": true,
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "x": "100%",
 | 
						|
                  "y": 0
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        }
 | 
						|
      ],
 | 
						|
      "edges": [
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "9cd9fab0-875a-4ddc-9d32-06fb5abcd986",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "on-push-b2c871f",
 | 
						|
            "port": "on-push-b2c871f-right"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "job-ed9ed25",
 | 
						|
            "port": "job-ed9ed25-left"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "32fee66b-377e-49a6-9f5c-b6a7cb78b4f0",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "job-ed9ed25",
 | 
						|
            "port": "job-ed9ed25-right"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "job-3359fd2c",
 | 
						|
            "port": "job-3359fd2c-left"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "84b37c54-b347-4ecb-8e7d-f338bb83c503",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "job-3359fd2c",
 | 
						|
            "port": "job-3359fd2c-right"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "job-7760b89e",
 | 
						|
            "port": "job-7760b89e-left"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "1703563e-2233-4d23-89ec-ed61f4243791",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "job-ed9ed25",
 | 
						|
            "port": "job-ed9ed25-bottom"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "shell-79d5ba5d",
 | 
						|
            "port": "shell-79d5ba5d-top"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "0be52bf9-8be4-43a9-aaca-1632eaf450ce",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "shell-79d5ba5d",
 | 
						|
            "port": "shell-79d5ba5d-bottom"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "shell-799aadee",
 | 
						|
            "port": "shell-799aadee-top"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "5b9800bd-5486-4b30-9142-49e6c5a2f78b",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "job-3359fd2c",
 | 
						|
            "port": "job-3359fd2c-bottom"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "shell-dd97c50",
 | 
						|
            "port": "shell-dd97c50-top"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "0b01ccf2-0ac9-48d5-a5d1-34a4ccc3f1f7",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "shell-dd97c50",
 | 
						|
            "port": "shell-dd97c50-bottom"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "shell-4e09400",
 | 
						|
            "port": "shell-4e09400-top"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "c10ada7b-ada5-4970-b05d-ea31b97c1408",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "job-7760b89e",
 | 
						|
            "port": "job-7760b89e-bottom"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "shell-1766a765",
 | 
						|
            "port": "shell-1766a765-top"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "78909862-8e2a-4750-8b5c-c621a7c327ba",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "shell-799aadee",
 | 
						|
            "port": "shell-799aadee-bottom"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "shell-5cec9ec",
 | 
						|
            "port": "shell-5cec9ec-top"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          "shape": "data-processing-curve",
 | 
						|
          "inherit": "edge",
 | 
						|
          "connector": {
 | 
						|
            "name": "rounded",
 | 
						|
            "args": {
 | 
						|
              "radius": 10
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "router": {
 | 
						|
            "name": "manhattan"
 | 
						|
          },
 | 
						|
          "attrs": {
 | 
						|
            "line": {
 | 
						|
              "strokeDasharray": "0"
 | 
						|
            }
 | 
						|
          },
 | 
						|
          "id": "cf60eaaf-3503-4c6e-96d8-ca8d273b107b",
 | 
						|
          "zIndex": -1,
 | 
						|
          "source": {
 | 
						|
            "cell": "shell-1766a765",
 | 
						|
            "port": "shell-1766a765-bottom"
 | 
						|
          },
 | 
						|
          "target": {
 | 
						|
            "cell": "checkout-gitlink-f6e67fe",
 | 
						|
            "port": "checkout-gitlink-f6e67fe-top"
 | 
						|
          },
 | 
						|
          "tools": {
 | 
						|
            "items": [
 | 
						|
              {
 | 
						|
                "name": "button-remove",
 | 
						|
                "args": {
 | 
						|
                  "distance": -40
 | 
						|
                }
 | 
						|
              }
 | 
						|
            ]
 | 
						|
          }
 | 
						|
        }
 | 
						|
      ]
 | 
						|
    }
 | 
						|
  end
 | 
						|
 | 
						|
end
 |