| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| import React, { Fragment, useEffect, useState, useCallback, useMemo } from 'react' |
| import { CSSTransition } from 'react-transition-group' |
| import { useHistory, useLocation, Link } from 'react-router-dom' |
| import dayjs from '@/utils/time' |
| import { |
| API_PROXY_ENDPOINT, |
| ISSUE_TYPES_ENDPOINT, |
| ISSUE_FIELDS_ENDPOINT, |
| BOARDS_ENDPOINT, |
| } from '@/config/jiraApiProxy' |
| import { integrationsData } from '@/data/integrations' |
| import { Divider, Elevation, Card, Intent, Colors } from '@blueprintjs/core' |
| import { |
| Providers, |
| ProviderTypes, |
| ProviderIcons, |
| ConnectionStatus, |
| ConnectionStatusLabels, |
| } from '@/data/Providers' |
| import Nav from '@/components/Nav' |
| import Sidebar from '@/components/Sidebar' |
| // import AppCrumbs from '@/components/Breadcrumbs' |
| import Content from '@/components/Content' |
| import { ToastNotification } from '@/components/Toast' |
| |
| import { DataEntities, DataEntityTypes } from '@/data/DataEntities' |
| import { NullBlueprint, BlueprintMode } from '@/data/NullBlueprint' |
| import { NullBlueprintConnection } from '@/data/NullBlueprintConnection' |
| import { NullConnection } from '@/data/NullConnection' |
| |
| import { |
| WorkflowSteps, |
| WorkflowAdvancedSteps, |
| DEFAULT_DATA_ENTITIES, |
| DEFAULT_BOARDS, |
| } from '@/data/BlueprintWorkflow' |
| |
| import useBlueprintManager from '@/hooks/useBlueprintManager' |
| import usePipelineManager from '@/hooks/usePipelineManager' |
| import useConnectionManager from '@/hooks/useConnectionManager' |
| import useBlueprintValidation from '@/hooks/useBlueprintValidation' |
| import usePipelineValidation from '@/hooks/usePipelineValidation' |
| import useConnectionValidation from '@/hooks/useConnectionValidation' |
| import useJIRA from '@/hooks/useJIRA' |
| |
| import WorkflowStepsBar from '@/components/blueprints/WorkflowStepsBar' |
| import WorkflowActions from '@/components/blueprints/WorkflowActions' |
| import ConnectionDialog from '@/components/blueprints/ConnectionDialog' |
| import CodeInspector from '@/components/pipelines/CodeInspector' |
| // import NoData from '@/components/NoData' |
| |
| import DataConnections from '@/components/blueprints/create-workflow/DataConnections' |
| import DataScopes from '@/components/blueprints/create-workflow/DataScopes' |
| import DataTransformations from '@/components/blueprints/create-workflow/DataTransformations' |
| import DataSync from '@/components/blueprints/create-workflow/DataSync' |
| import AdvancedJSON from '@/components/blueprints/create-workflow/AdvancedJSON' |
| import AdvancedJSONValidation from '@/components/blueprints/create-workflow/AdvancedJSONValidation' |
| |
| import { DEVLAKE_ENDPOINT } from '@/utils/config' |
| import request from '@/utils/request' |
| |
| // import ConnectionTabs from '@/components/blueprints/ConnectionTabs' |
| |
| const CreateBlueprint = (props) => { |
| const history = useHistory() |
| // const dispatch = useDispatch() |
| |
| const [blueprintAdvancedSteps, setBlueprintAdvancedSteps] = useState( |
| WorkflowAdvancedSteps |
| ) |
| const [blueprintNormalSteps, setBlueprintNormalSteps] = |
| useState(WorkflowSteps) |
| const [blueprintSteps, setBlueprintSteps] = useState(blueprintNormalSteps) |
| const [advancedMode, setAdvancedMode] = useState(false) |
| const [activeStep, setActiveStep] = useState( |
| blueprintSteps.find((s) => s.id === 1) |
| ) |
| const [activeProvider, setActiveProvider] = useState(integrationsData[0]) |
| |
| const [enabledProviders, setEnabledProviders] = useState([]) |
| const [runTasks, setRunTasks] = useState([]) |
| const [runTasksAdvanced, setRunTasksAdvanced] = useState([]) |
| const [runNow, setRunNow] = useState(false) |
| const [newBlueprintId, setNewBlueprintId] = useState() |
| const [existingTasks, setExistingTasks] = useState([]) |
| |
| const [isValidConfiguration, setIsValidConfiguration] = useState(false) |
| const [validationAdvancedError, setValidationAdvancedError] = useState() |
| |
| const [connectionDialogIsOpen, setConnectionDialogIsOpen] = useState(false) |
| const [managedConnection, setManagedConnection] = useState( |
| NullBlueprintConnection |
| ) |
| |
| const [connectionsList, setConnectionsList] = useState([]) |
| |
| const [dataEntitiesList, setDataEntitiesList] = useState([ |
| ...DEFAULT_DATA_ENTITIES, |
| ]) |
| const [boardsList, setBoardsList] = useState([]) |
| |
| const [blueprintConnections, setBlueprintConnections] = useState([]) |
| const [configuredConnection, setConfiguredConnection] = useState() |
| const [dataEntities, setDataEntities] = useState({}) |
| const [activeConnectionTab, setActiveConnectionTab] = useState() |
| |
| const [onlineStatus, setOnlineStatus] = useState([]) |
| const [showBlueprintInspector, setShowBlueprintInspector] = useState(false) |
| |
| const [dataScopes, setDataScopes] = useState([]) |
| const [dataConnections, setDataConnections] = useState([]) |
| const [transformations, setTransformations] = useState({}) |
| |
| const [projectId, setProjectId] = useState([]) |
| const [projects, setProjects] = useState({}) |
| const [boards, setBoards] = useState({}) |
| const [boardId, setBoardId] = useState([]) |
| const [connectionId, setConnectionId] = useState('') |
| const [connections, setConnections] = useState([]) |
| const [repositories, setRepositories] = useState([]) |
| const [selectedConnection, setSelectedConnection] = useState() |
| const [repositoryName, setRepositoryName] = useState('') |
| const [owner, setOwner] = useState('') |
| const [gitExtractorUrl, setGitExtractorUrl] = useState('') |
| const [gitExtractorRepoId, setGitExtractorRepoId] = useState('') |
| const [selectedGithubRepo, setSelectedGithubRepo] = useState() |
| const [refDiffRepoId, setRefDiffRepoId] = useState('') |
| const [refDiffPairs, setRefDiffPairs] = useState([]) |
| const [refDiffTasks, setRefDiffTasks] = useState([ |
| 'calculateCommitsDiff', |
| 'calculateIssuesDiff', |
| ]) |
| |
| const [canAdvanceNext, setCanAdvanceNext] = useState(true) |
| const [canAdvancePrev, setCanAdvancePrev] = useState(true) |
| |
| const [configuredProject, setConfiguredProject] = useState( |
| projects.length > 0 ? projects[0] : null |
| ) |
| const [configuredBoard, setConfiguredBoard] = useState( |
| boards.length > 0 ? boards[0] : null |
| ) |
| |
| const activeTransformation = useMemo(() => transformations[configuredProject || configuredBoard?.id], [transformations, configuredProject, configuredBoard?.id]) |
| |
| const { |
| activeConnection, |
| // eslint-disable-next-line no-unused-vars |
| blueprint, |
| // eslint-disable-next-line no-unused-vars |
| blueprints, |
| name, |
| cronConfig, |
| customCronConfig, |
| // eslint-disable-next-line no-unused-vars |
| cronPresets, |
| tasks: blueprintTasks, |
| settings: blueprintSettings, |
| detectedProviderTasks, |
| enable, |
| mode, |
| rawConfiguration, |
| setName: setBlueprintName, |
| setCronConfig, |
| setCustomCronConfig, |
| setTasks: setBlueprintTasks, |
| setSettings: setBlueprintSettings, |
| setDetectedProviderTasks, |
| setEnable: setEnableBlueprint, |
| setMode: setBlueprintMode, |
| setIsManual: setIsManualBlueprint, |
| setRawConfiguration, |
| // eslint-disable-next-line no-unused-vars |
| isFetching: isFetchingBlueprints, |
| isSaving, |
| createCronExpression: createCron, |
| // eslint-disable-next-line no-unused-vars |
| getCronSchedule: getSchedule, |
| getNextRunDate, |
| getCronPreset, |
| getCronPresetByConfig, |
| saveBlueprint, |
| deleteBlueprint, |
| isDeleting: isDeletingBlueprint, |
| isManual: isManualBlueprint, |
| saveComplete: saveBlueprintComplete |
| } = useBlueprintManager() |
| |
| const { |
| pipelineName, |
| pipelines, |
| runPipeline, |
| cancelPipeline, |
| fetchPipeline, |
| fetchAllPipelines, |
| pipelineRun, |
| buildPipelineStages, |
| isRunning, |
| isFetchingAll: isFetchingAllPipelines, |
| // eslint-disable-next-line no-unused-vars |
| errors: pipelineErrors, |
| setSettings: setPipelineSettings, |
| setPipelineName, |
| // eslint-disable-next-line no-unused-vars |
| lastRunId, |
| // eslint-disable-next-line no-unused-vars |
| allowedProviders, |
| // eslint-disable-next-line no-unused-vars |
| detectPipelineProviders, |
| } = usePipelineManager(null, runTasks) |
| |
| const { |
| validate: validatePipeline, |
| validateAdvanced: validateAdvancedPipeline, |
| errors: validationErrors, |
| setErrors: setPipelineErrors, |
| isValid: isValidPipeline, |
| detectedProviders, |
| parseJSON |
| } = usePipelineValidation({ |
| enabledProviders, |
| pipelineName, |
| projectId, |
| projects, |
| boardId, |
| boards, |
| owner, |
| repositoryName, |
| connectionId, |
| gitExtractorUrl, |
| gitExtractorRepoId, |
| refDiffRepoId, |
| refDiffTasks, |
| refDiffPairs, |
| tasks: runTasks, |
| tasksAdvanced: runTasksAdvanced, |
| advancedMode, |
| mode, |
| connection: configuredConnection, |
| entities: dataEntities, |
| rawConfiguration |
| }) |
| |
| const { |
| fetchIssueTypes, |
| fetchFields, |
| fetchBoards, |
| boards: jiraApiBoards, |
| issueTypes: jiraApiIssueTypes, |
| fields: jiraApiFields, |
| isFetching: isFetchingJIRA, |
| error: jiraProxyError, |
| } = useJIRA( |
| { |
| apiProxyPath: API_PROXY_ENDPOINT, |
| issuesEndpoint: ISSUE_TYPES_ENDPOINT, |
| fieldsEndpoint: ISSUE_FIELDS_ENDPOINT, |
| boardsEndpoint: BOARDS_ENDPOINT, |
| }, |
| configuredConnection |
| ) |
| |
| const { |
| testConnection, |
| testAllConnections, |
| saveConnection, |
| fetchConnection, |
| allProviderConnections, |
| errors: connectionErrors, |
| isSaving: isSavingConnection, |
| isTesting: isTestingConnection, |
| isFetching: isFetchingConnection, |
| showError, |
| testStatus, |
| name: connectionName, |
| endpointUrl, |
| proxy, |
| token, |
| initialTokenStore, |
| username, |
| password, |
| provider, |
| setActiveConnection, |
| setProvider, |
| setName, |
| setEndpointUrl, |
| setProxy, |
| setUsername, |
| setPassword, |
| setToken, |
| setInitialTokenStore, |
| setTestStatus, |
| setTestResponse, |
| setAllTestResponses, |
| setSaveComplete: setSaveConnectionComplete, |
| fetchAllConnections, |
| connectionLimitReached, |
| clearConnection: clearActiveConnection, |
| testResponse, |
| testedConnections, |
| allTestResponses, |
| saveComplete: saveConnectionComplete |
| } = useConnectionManager( |
| { |
| activeProvider, |
| connectionId: managedConnection?.connectionId, |
| }, |
| managedConnection && managedConnection?.id !== null |
| ) |
| |
| const { |
| validate: validateBlueprint, |
| errors: blueprintValidationErrors, |
| isValid: isValidBlueprint, |
| fieldHasError, |
| getFieldError, |
| } = useBlueprintValidation({ |
| name, |
| boards, |
| projects, |
| cronConfig, |
| customCronConfig, |
| enable, |
| tasks: blueprintTasks, |
| mode, |
| connections: blueprintConnections, |
| entities: dataEntities, |
| activeStep, |
| activeProvider: provider, |
| activeConnection: configuredConnection |
| }) |
| |
| const { |
| validate: validateConnection, |
| errors: connectionValidationErrors, |
| isValid: isValidConnection, |
| } = useConnectionValidation({ |
| activeProvider, |
| name: connectionName, |
| endpointUrl, |
| proxy, |
| token, |
| username, |
| password, |
| }) |
| |
| const isValidStep = useCallback((stepId) => { }, []) |
| |
| const nextStep = useCallback(() => { |
| setActiveStep((aS) => |
| blueprintSteps.find( |
| (s) => s.id === Math.min(aS.id + 1, blueprintSteps.length) |
| ) |
| ) |
| }, [blueprintSteps]) |
| |
| const prevStep = useCallback(() => { |
| setActiveStep((aS) => |
| blueprintSteps.find((s) => s.id === Math.max(aS.id - 1, 1)) |
| ) |
| setConfiguredProject(null) |
| setConfiguredBoard(null) |
| }, [blueprintSteps]) |
| |
| const testSelectedConnections = useCallback((connections, savedConnection = {}, callback = () => {}) => { |
| const runTest = async () => { |
| const results = await Promise.all(connections.map( |
| c => { |
| const testPayload = c.connectionId === savedConnection?.id && c.name === savedConnection?.name ? { |
| endpoint: savedConnection?.endpoint, |
| username: savedConnection?.username, |
| password: savedConnection?.password, |
| token: savedConnection?.token, |
| proxy: savedConnection?.proxy |
| } : { |
| endpoint: c.endpoint, |
| username: c.username, |
| password: c.password, |
| token: c.token, |
| proxy: c.proxy |
| } |
| return request.post(`${DEVLAKE_ENDPOINT}/plugins/${c.plugin}/test`, testPayload) |
| }) |
| ) |
| setOnlineStatus(results.map(r => r)) |
| } |
| if (mode === BlueprintMode.NORMAL && connections.length > 0) { |
| runTest() |
| } |
| callback() |
| }, [mode]) |
| |
| const handleConnectionTabChange = useCallback( |
| (tab) => { |
| console.log('>> CONNECTION TAB CHANGED', tab) |
| const selectedConnection = blueprintConnections.find( |
| (c) => c.id === Number(tab.split('-')[1]) |
| ) |
| setActiveConnectionTab(tab) |
| setActiveProvider( |
| integrationsData.find((p) => p.id === selectedConnection.provider) |
| ) |
| setProvider( |
| integrationsData.find((p) => p.id === selectedConnection.provider) |
| ) |
| setConfiguredConnection(selectedConnection) |
| }, |
| [blueprintConnections, setProvider] |
| ) |
| |
| const handleConnectionDialogOpen = useCallback(() => { |
| console.log('>>> MANAGING CONNECTION', managedConnection) |
| }, [managedConnection]) |
| |
| const handleConnectionDialogClose = useCallback((savedConnection = {}) => { |
| fetchAllConnections(false, true) |
| testSelectedConnections(blueprintConnections, savedConnection) |
| setConnectionDialogIsOpen(false) |
| setManagedConnection(NullBlueprintConnection) |
| setTestStatus(0) |
| setTestResponse(null) |
| setAllTestResponses({}) |
| setInitialTokenStore({}) |
| clearActiveConnection() |
| setActiveConnection(NullConnection) |
| // setSaveConnectionComplete(null) |
| }, [ |
| blueprintConnections, |
| testSelectedConnections, |
| fetchAllConnections, |
| clearActiveConnection, |
| setActiveConnection, |
| setAllTestResponses, |
| setInitialTokenStore, |
| // setSaveConnectionComplete, |
| setTestResponse, |
| setTestStatus |
| ]) |
| |
| const handleTransformationCancel = useCallback(() => { |
| setConfiguredProject(null) |
| setConfiguredBoard(null) |
| console.log('>> Cancel Modify - Transformation Settings') |
| }, []) |
| |
| const handleTransformationClear = useCallback(() => { |
| console.log( |
| '>>> CLEARING TRANSFORMATION RULES!', |
| '==> PROJECT =', |
| configuredProject, |
| '==> BOARD =', |
| configuredBoard |
| ) |
| setTransformations((existingTransformations) => ({ |
| ...existingTransformations, |
| [configuredProject]: {}, |
| [configuredBoard?.id]: {}, |
| })) |
| setConfiguredProject(null) |
| setConfiguredBoard(null) |
| }, [setTransformations, configuredProject, configuredBoard]) |
| |
| const handleBlueprintSave = useCallback(() => { |
| console.log('>>> SAVING BLUEPRINT!!') |
| setRunNow(false) |
| saveBlueprint() |
| }, [saveBlueprint]) |
| |
| const handleBlueprintSaveAndRun = useCallback(() => { |
| console.log('>>> SAVING BLUEPRINT & RUNNING NOW!!') |
| setRunNow(true) |
| saveBlueprint() |
| }, [saveBlueprint]) |
| |
| const getRestrictedDataEntities = useCallback(() => { |
| let items = [] |
| switch (configuredConnection.provider) { |
| case Providers.GITLAB: |
| case Providers.JIRA: |
| case Providers.TAPD: |
| case Providers.GITHUB: |
| items = dataEntitiesList.filter((d) => d.name !== 'ci-cd') |
| break |
| case Providers.JENKINS: |
| items = dataEntitiesList.filter((d) => d.name === 'ci-cd') |
| break |
| } |
| return items |
| }, [dataEntitiesList, configuredConnection]) |
| |
| const createProviderScopes = useCallback( |
| ( |
| providerId, |
| connection, |
| connectionIdx, |
| entities = [], |
| boards = [], |
| projects = [], |
| transformations = [], |
| defaultScope = { transformation: {}, options: {}, entities: [] } |
| ) => { |
| console.log( |
| '>>> CREATING PROVIDER SCOPE FOR CONNECTION...', |
| connectionIdx, |
| connection |
| ) |
| let newScope = { |
| ...defaultScope, |
| entities: entities[connection.id]?.map((entity) => entity.value) || [], |
| } |
| switch (providerId) { |
| case Providers.JIRA: |
| newScope = boards[connection.id]?.map((b) => ({ |
| ...newScope, |
| options: { |
| boardId: Number(b.id), |
| // @todo: verify initial value of since date for jira provider |
| // since: new Date(), |
| }, |
| transformation: { ...transformations[b.id] }, |
| })) |
| break |
| case Providers.GITLAB: |
| newScope = projects[connection.id]?.map((p) => ({ |
| ...newScope, |
| options: { |
| projectId: Number(p), |
| }, |
| transformation: {}, |
| })) |
| break |
| case Providers.JENKINS: |
| newScope = { |
| ...newScope, |
| } |
| break |
| case Providers.TAPD: |
| newScope = { |
| ...newScope, |
| } |
| break |
| case Providers.GITHUB: |
| newScope = projects[connection.id]?.map((p) => ({ |
| ...newScope, |
| options: { |
| owner: p.split('/')[0], |
| repo: p.split('/')[1], |
| }, |
| transformation: { ...transformations[p] }, |
| })) |
| break |
| } |
| return Array.isArray(newScope) ? newScope.flat() : [newScope] |
| }, |
| [] |
| ) |
| |
| const manageConnection = useCallback( |
| (connection) => { |
| console.log('>> MANAGE CONNECTION...', connection) |
| if (connection?.id !== null) { |
| setActiveProvider( |
| integrationsData.find((p) => p.id === connection.provider) |
| ) |
| setProvider(integrationsData.find((p) => p.id === connection.provider)) |
| // fetchConnection(true, false, connection.id) |
| setManagedConnection(connection) |
| setConnectionDialogIsOpen(true) |
| } |
| }, |
| [setProvider] |
| ) |
| |
| const addProjectTransformation = useCallback((project) => { |
| setConfiguredProject(project) |
| ToastNotification.clear() |
| }, []) |
| |
| const addBoardTransformation = useCallback((board) => { |
| setConfiguredBoard(board) |
| ToastNotification.clear() |
| }, []) |
| |
| const addConnection = useCallback(() => { |
| setManagedConnection(NullBlueprintConnection) |
| setConnectionDialogIsOpen(true) |
| }, []) |
| |
| const setTransformationSettings = useCallback( |
| (settings, configuredEntity) => { |
| console.log( |
| '>> SETTING TRANSFORMATION SETTINGS PROJECT/BOARD...', |
| configuredEntity, |
| settings |
| ) |
| setTransformations((existingTransformations) => ({ |
| ...existingTransformations, |
| [configuredEntity]: { |
| ...existingTransformations[configuredEntity], |
| ...settings, |
| }, |
| })) |
| }, |
| [setTransformations] |
| ) |
| |
| const handleTransformationSave = useCallback((settings, entity) => { |
| console.log('>> SAVING / CLOSING Transformation Settings') |
| // manual @save disabled, reactive auto-saving writes settings to transform object... |
| // setTransformationSettings(settings, entity) |
| setConfiguredProject(null) |
| setConfiguredBoard(null) |
| ToastNotification.clear() |
| ToastNotification.show({ message: 'Transformation Rules Added.', intent: Intent.SUCCESS, icon: 'small-tick' }) |
| }, []) |
| |
| const handleAdvancedMode = (enableAdvanced = true) => { |
| setAdvancedMode(enableAdvanced) |
| } |
| |
| const isValidCode = useCallback(() => { |
| let isValid = false |
| try { |
| const parsedCode = parseJSON(rawConfiguration) |
| isValid = true |
| setValidationAdvancedError(null) |
| } catch (e) { |
| console.log('>> FORMAT CODE: Invalid Code Format!', e) |
| isValid = false |
| setValidationAdvancedError(e.message) |
| } |
| setIsValidConfiguration(isValid) |
| return isValid |
| }, [rawConfiguration, parseJSON]) |
| |
| useEffect(() => { |
| console.log('>> ACTIVE STEP CHANGED: ', activeStep) |
| if (mode === BlueprintMode.NORMAL && activeStep?.id === 1) { |
| const enableNotifications = false |
| const getAllSources = true |
| fetchAllConnections(enableNotifications, getAllSources) |
| } |
| if (mode === BlueprintMode.NORMAL && ([2, 3].includes(activeStep?.id))) { |
| fetchBoards() |
| fetchIssueTypes() |
| fetchFields() |
| } |
| setBlueprintNormalSteps((bS) => [ |
| ...bS.map((s) => |
| s.id < activeStep?.id |
| ? { ...s, complete: true } |
| : { ...s, complete: false } |
| ), |
| ]) |
| setBlueprintAdvancedSteps((bS) => [ |
| ...bS.map((s) => |
| s.id < activeStep?.id |
| ? { ...s, complete: true } |
| : { ...s, complete: false } |
| ), |
| ]) |
| }, [ |
| activeStep, |
| fetchAllConnections, |
| fetchBoards, |
| fetchFields, |
| fetchIssueTypes, |
| mode |
| ]) |
| |
| useEffect(() => { |
| console.log('>>> ALL DATA PROVIDER CONNECTIONS...', allProviderConnections) |
| setConnectionsList( |
| allProviderConnections?.map((c, cIdx) => ({ |
| ...c, |
| id: cIdx, |
| name: c.name, |
| title: c.name, |
| value: c.id, |
| status: |
| ConnectionStatusLabels[c.status] || |
| ConnectionStatusLabels[ConnectionStatus.OFFLINE], |
| statusResponse: null, |
| provider: c.provider, |
| plugin: c.provider, |
| })) |
| ) |
| }, [allProviderConnections]) |
| |
| useEffect(() => { |
| console.log( |
| '>> PIPELINE RUN TASK SETTINGS FOR PIPELINE MANAGER ....', |
| runTasks |
| ) |
| setPipelineSettings({ |
| name: pipelineName, |
| // blueprintId: saveBlueprintComplete?.id || 0, |
| plan: advancedMode ? runTasksAdvanced : [[...runTasks]], |
| }) |
| // setRawConfiguration(JSON.stringify(buildPipelineStages(runTasks, true), null, ' ')) |
| if (advancedMode) { |
| validateAdvancedPipeline() |
| setBlueprintTasks(runTasksAdvanced) |
| } else { |
| validatePipeline() |
| setBlueprintTasks([[...runTasks]]) |
| } |
| }, [ |
| pipelineName, |
| advancedMode, |
| runTasks, |
| runTasksAdvanced, |
| setPipelineSettings, |
| validatePipeline, |
| validateAdvancedPipeline, |
| setBlueprintTasks, |
| // saveBlueprintComplete?.id |
| ]) |
| |
| useEffect(() => { |
| console.log( |
| '>> BLUEPRINT SETTINGS FOR PIPELINE MANAGER ....', |
| blueprintSettings |
| ) |
| }, [blueprintSettings]) |
| |
| useEffect(() => { |
| validateBlueprint() |
| }, [ |
| name, |
| cronConfig, |
| customCronConfig, |
| blueprintTasks, |
| connectionsList, |
| enable, |
| validateBlueprint, |
| ]) |
| |
| useEffect(() => { |
| setIsManualBlueprint(cronConfig === 'manual') |
| }, [cronConfig, setIsManualBlueprint]) |
| |
| useEffect(() => { }, [activeConnectionTab]) |
| |
| useEffect(() => { |
| console.log('>>>> MY SELECTED BLUEPRINT CONNECTIONS...', blueprintConnections) |
| const someConnection = blueprintConnections.find(c => c) |
| if (someConnection) { |
| setConfiguredConnection(someConnection) |
| setActiveConnectionTab(`connection-${someConnection?.id}`) |
| setActiveProvider( |
| integrationsData.find((p) => p.id === someConnection.provider) |
| ) |
| setProvider( |
| integrationsData.find((p) => p.id === someConnection.provider) |
| ) |
| } |
| const getDefaultEntities = (providerId) => { |
| let entities = [] |
| switch (providerId) { |
| case Providers.GITHUB: |
| case Providers.GITLAB: |
| entities = DEFAULT_DATA_ENTITIES.filter((d) => d.name !== 'ci-cd') |
| break |
| case Providers.JIRA: |
| entities = DEFAULT_DATA_ENTITIES.filter((d) => d.name === 'issue-tracking' || d.name === 'cross-domain') |
| break |
| case Providers.JENKINS: |
| entities = DEFAULT_DATA_ENTITIES.filter((d) => d.name === 'ci-cd') |
| break |
| } |
| return entities |
| } |
| const initializeEntities = (pV, cV) => ({ |
| ...pV, |
| [cV.id]: !pV[cV.id] ? getDefaultEntities(cV?.provider) : [], |
| }) |
| const initializeProjects = (pV, cV) => ({ ...pV, [cV.id]: [] }) |
| const initializeBoards = (pV, cV) => ({ ...pV, [cV.id]: [] }) |
| setDataEntities((dE) => ({ |
| ...blueprintConnections.reduce(initializeEntities, {}), |
| })) |
| setProjects((p) => ({ |
| ...blueprintConnections.reduce(initializeProjects, {}), |
| })) |
| setBoards((b) => ({ |
| ...blueprintConnections.reduce(initializeBoards, {}), |
| })) |
| setEnabledProviders([ |
| ...new Set(blueprintConnections.map((c) => c.provider)), |
| ]) |
| |
| testSelectedConnections(blueprintConnections) |
| }, [blueprintConnections, setProvider, testSelectedConnections]) |
| |
| useEffect(() => { |
| console.log('>> CONFIGURING CONNECTION', configuredConnection) |
| if (configuredConnection) { |
| setConfiguredProject(null) |
| setConfiguredBoard(null) |
| switch (configuredConnection.provider) { |
| case Providers.GITLAB: |
| case Providers.GITHUB: |
| setDataEntitiesList( |
| DEFAULT_DATA_ENTITIES.filter((d) => d.name !== 'ci-cd') |
| ) |
| // setConfiguredProject(projects.length > 0 ? projects[0] : null) |
| break |
| case Providers.JIRA: |
| setDataEntitiesList( |
| DEFAULT_DATA_ENTITIES.filter((d) => d.name === 'issue-tracking' || d.name === 'cross-domain') |
| ) |
| break |
| case Providers.JENKINS: |
| setDataEntitiesList( |
| DEFAULT_DATA_ENTITIES.filter((d) => d.name === 'ci-cd') |
| ) |
| break |
| default: |
| setDataEntitiesList(DEFAULT_DATA_ENTITIES) |
| break |
| } |
| } |
| }, [configuredConnection, setActiveConnectionTab]) |
| |
| useEffect(() => { |
| console.log('>> DATA ENTITIES', dataEntities) |
| }, [dataEntities]) |
| |
| useEffect(() => { |
| console.log('>> BOARDS', boards) |
| }, [boards]) |
| |
| useEffect(() => { |
| setBlueprintSettings((currentSettings) => ({ |
| ...currentSettings, |
| connections: blueprintConnections.map((c, cIdx) => ({ |
| ...NullBlueprintConnection, |
| connectionId: c.value, |
| plugin: c.plugin || c.provider, |
| scope: createProviderScopes( |
| c.provider, |
| c, |
| cIdx, |
| dataEntities, |
| boards, |
| projects, |
| transformations |
| ), |
| })), |
| })) |
| // validatePipeline() |
| }, [ |
| blueprintConnections, |
| dataEntities, |
| boards, |
| projects, |
| transformations, |
| validatePipeline, |
| createProviderScopes, |
| setBlueprintSettings, |
| ]) |
| |
| useEffect(() => { |
| console.log('>> PROJECTS LIST', projects) |
| console.log('>> BOARDS LIST', boards) |
| const getDefaultTransformations = (providerId) => { |
| let transforms = {} |
| switch (providerId) { |
| case Providers.GITHUB: |
| transforms = { |
| prType: '', |
| prComponent: '', |
| issueSeverity: '', |
| issueComponent: '', |
| issuePriority: '', |
| issueTypeRequirement: '', |
| issueTypeBug: '', |
| issueTypeIncident: '', |
| refdiff: null, |
| } |
| break |
| case Providers.JIRA: |
| transforms = { |
| epicKeyField: '', |
| typeMappings: {}, |
| storyPointField: '', |
| remotelinkCommitShaPattern: '', |
| bugTags: [], |
| incidentTags: [], |
| requirementTags: [], |
| } |
| break |
| case Providers.JENKINS: |
| // No Transform Settings... |
| break |
| case Providers.TAPD: |
| // No Transform Settings... |
| break |
| case Providers.GITLAB: |
| // No Transform Settings... |
| break |
| } |
| return transforms |
| } |
| |
| const initializeTransformations = (pV, cV) => ({ |
| ...pV, |
| [cV]: getDefaultTransformations(configuredConnection?.provider), |
| }) |
| const projectTransformation = projects[configuredConnection?.id] |
| const boardTransformation = boards[configuredConnection?.id]?.map( |
| (b) => b.id |
| ) |
| if (projectTransformation) { |
| setTransformations((cT) => ({ |
| ...projectTransformation.reduce(initializeTransformations, {}), |
| // Spread Current/Existing Transformations Settings |
| ...cT, |
| })) |
| } |
| if (boardTransformation) { |
| setTransformations((cT) => ({ |
| ...boardTransformation.reduce(initializeTransformations, {}), // @todo: FIXME |
| // Spread Current/Existing Transformations Settings |
| ...cT, |
| })) |
| } |
| }, [projects, boards, configuredConnection]) |
| |
| useEffect(() => { |
| console.log( |
| '>>> SELECTED PROJECT TO CONFIGURE...', |
| configuredProject, |
| ) |
| // setActiveTransformation((aT) => |
| // configuredProject !== null ? transformations[configuredProject] : {} |
| // ) |
| setCanAdvanceNext(!configuredProject) |
| }, [configuredProject, setCanAdvanceNext]) |
| |
| useEffect(() => { |
| console.log( |
| '>>> SELECTED BOARD TO CONFIGURE...', |
| configuredBoard?.id, |
| ) |
| // setActiveTransformation((aT) => |
| // configuredBoard ? transformations[configuredBoard?.id] : aT |
| // ) |
| setCanAdvanceNext(!configuredBoard) |
| }, [configuredBoard, setCanAdvanceNext]) |
| |
| useEffect(() => { |
| console.log('>>> BLUEPRINT WORKFLOW STEPS...', blueprintSteps) |
| }, [blueprintSteps]) |
| |
| useEffect(() => { |
| setBlueprintSteps( |
| advancedMode ? blueprintAdvancedSteps : blueprintNormalSteps |
| ) |
| setBlueprintMode( |
| advancedMode ? BlueprintMode.ADVANCED : BlueprintMode.NORMAL |
| ) |
| }, [ |
| advancedMode, |
| blueprintNormalSteps, |
| blueprintAdvancedSteps, |
| setBlueprintMode, |
| ]) |
| |
| useEffect(() => { |
| if (isValidCode()) { |
| setRunTasksAdvanced(JSON.parse(rawConfiguration)) |
| } |
| }, [rawConfiguration, isValidCode]) |
| |
| useEffect(() => { |
| if (saveBlueprintComplete?.id) { |
| setNewBlueprintId(saveBlueprintComplete?.id) |
| } |
| }, [ |
| saveBlueprintComplete, |
| setPipelineSettings, |
| setPipelineSettings, |
| setNewBlueprintId, |
| runNow, |
| runPipeline, |
| history |
| ]) |
| |
| useEffect(() => { |
| if (runNow && newBlueprintId) { |
| const newPipelineConfiguration = { |
| name: `${saveBlueprintComplete?.name} ${Date.now()}`, |
| blueprintId: saveBlueprintComplete?.id, |
| plan: saveBlueprintComplete?.plan, |
| } |
| runPipeline(newPipelineConfiguration) |
| setRunNow(false) |
| history.push(`/blueprints/detail/${saveBlueprintComplete?.id}`) |
| } else if (newBlueprintId) { |
| history.push(`/blueprints/detail/${saveBlueprintComplete?.id}`) |
| } |
| }, [ |
| runNow, |
| saveBlueprintComplete, |
| newBlueprintId, |
| runPipeline, |
| history |
| ]) |
| |
| useEffect(() => { |
| console.log('>>> FETCHED JIRA API BOARDS FROM PROXY...', jiraApiBoards) |
| setBoardsList(jiraApiBoards) |
| }, [jiraApiBoards]) |
| |
| useEffect(() => { |
| if (saveConnectionComplete?.id && connectionDialogIsOpen) { |
| handleConnectionDialogClose(saveConnectionComplete) |
| // fetchAllConnections(false, true) |
| // testSelectedConnections(blueprintConnections, saveConnectionComplete) |
| } |
| return () => setSaveConnectionComplete(null) |
| }, [ |
| connectionDialogIsOpen, |
| saveConnectionComplete, |
| fetchAllConnections, |
| blueprintConnections, |
| testSelectedConnections, |
| handleConnectionDialogClose, |
| setSaveConnectionComplete |
| ]) |
| |
| useEffect(() => { |
| console.log('>>> ONLINE STATUS UPDATED...', onlineStatus) |
| setDataConnections(blueprintConnections.map((c, cIdx) => ({ |
| ...c, |
| statusResponse: onlineStatus[cIdx], |
| status: onlineStatus[cIdx]?.status |
| }))) |
| }, [onlineStatus, blueprintConnections]) |
| |
| useEffect(() => { |
| setConnectionsList(cList => cList.map((c, cIdx) => ({ |
| ...c, |
| statusResponse: dataConnections.find(dC => dC.id === c.id && dC.provider === c.provider), |
| status: dataConnections.find(dC => dC.id === c.id && dC.provider === c.provider)?.status |
| }))) |
| setCanAdvanceNext(dataConnections.every(dC => dC.status === 200)) |
| }, [dataConnections]) |
| |
| return ( |
| <> |
| <div className='container'> |
| <Nav /> |
| <Sidebar /> |
| <Content> |
| <main className='main'> |
| <WorkflowStepsBar activeStep={activeStep} steps={blueprintSteps} /> |
| |
| <div |
| className={`workflow-content workflow-step-id-${activeStep?.id}`} |
| > |
| {advancedMode ? ( |
| <> |
| {activeStep?.id === 1 && ( |
| <AdvancedJSON |
| activeStep={activeStep} |
| advancedMode={advancedMode} |
| runTasksAdvanced={runTasksAdvanced} |
| blueprintConnections={blueprintConnections} |
| connectionsList={connectionsList} |
| name={name} |
| setBlueprintName={setBlueprintName} |
| // setBlueprintConnections={setBlueprintConnections} |
| fieldHasError={fieldHasError} |
| getFieldError={getFieldError} |
| // addConnection={addConnection} |
| // manageConnection={manageConnection} |
| onAdvancedMode={handleAdvancedMode} |
| // @todo add multistage checker method |
| isMultiStagePipeline={() => { }} |
| rawConfiguration={rawConfiguration} |
| setRawConfiguration={setRawConfiguration} |
| isSaving={isSaving} |
| isValidConfiguration={isValidConfiguration} |
| validationAdvancedError={validationAdvancedError} |
| validationErrors={validationErrors} |
| /> |
| )} |
| |
| {activeStep?.id === 2 && ( |
| <DataSync |
| activeStep={activeStep} |
| advancedMode={advancedMode} |
| cronConfig={cronConfig} |
| customCronConfig={customCronConfig} |
| createCron={createCron} |
| setCronConfig={setCronConfig} |
| getCronPreset={getCronPreset} |
| fieldHasError={fieldHasError} |
| getFieldError={getFieldError} |
| setCustomCronConfig={setCustomCronConfig} |
| getCronPresetByConfig={getCronPresetByConfig} |
| /> |
| )} |
| </> |
| ) : ( |
| <> |
| {activeStep?.id === 1 && ( |
| <DataConnections |
| activeStep={activeStep} |
| advancedMode={advancedMode} |
| blueprintConnections={dataConnections} |
| // blueprintConnections={blueprintConnections} |
| // blueprintConnections={[...blueprintConnections.map((c, cIdx) => ({...c, statusResponse: onlineStatus[cIdx], status: onlineStatus[cIdx]?.status }))]} |
| onlineStatus={onlineStatus} |
| connectionsList={connectionsList} |
| name={name} |
| setBlueprintName={setBlueprintName} |
| setBlueprintConnections={setBlueprintConnections} |
| fieldHasError={fieldHasError} |
| getFieldError={getFieldError} |
| addConnection={addConnection} |
| manageConnection={manageConnection} |
| onAdvancedMode={handleAdvancedMode} |
| isTesting={isTestingConnection} |
| /> |
| )} |
| |
| {activeStep?.id === 2 && ( |
| <DataScopes |
| provider={provider} |
| activeStep={activeStep} |
| advancedMode={advancedMode} |
| activeConnectionTab={activeConnectionTab} |
| blueprintConnections={blueprintConnections} |
| dataEntitiesList={dataEntitiesList} |
| boardsList={boardsList} |
| boards={boards} |
| dataEntities={dataEntities} |
| projects={projects} |
| configuredConnection={configuredConnection} |
| handleConnectionTabChange={handleConnectionTabChange} |
| setDataEntities={setDataEntities} |
| setProjects={setProjects} |
| setBoards={setBoards} |
| prevStep={prevStep} |
| isSaving={isSaving} |
| isRunning={isRunning} |
| validationErrors={[...validationErrors, ...blueprintValidationErrors]} |
| /> |
| )} |
| |
| {activeStep?.id === 3 && ( |
| <DataTransformations |
| provider={provider} |
| activeStep={activeStep} |
| advancedMode={advancedMode} |
| activeConnectionTab={activeConnectionTab} |
| blueprintConnections={blueprintConnections} |
| dataEntities={dataEntities} |
| projects={projects} |
| boardsList={boardsList} |
| boards={boards} |
| issueTypes={jiraApiIssueTypes} |
| fields={jiraApiFields} |
| configuredConnection={configuredConnection} |
| configuredProject={configuredProject} |
| configuredBoard={configuredBoard} |
| handleConnectionTabChange={handleConnectionTabChange} |
| prevStep={prevStep} |
| addBoardTransformation={addBoardTransformation} |
| addProjectTransformation={addProjectTransformation} |
| transformations={transformations} |
| activeTransformation={activeTransformation} |
| setTransformations={setTransformations} |
| setTransformationSettings={setTransformationSettings} |
| isSaving={isSaving} |
| isSavingConnection={isSavingConnection} |
| isRunning={isRunning} |
| onSave={handleTransformationSave} |
| onCancel={handleTransformationCancel} |
| onClear={handleTransformationClear} |
| fieldHasError={fieldHasError} |
| getFieldError={getFieldError} |
| jiraProxyError={jiraProxyError} |
| isFetchingJIRA={isFetchingJIRA} |
| /> |
| )} |
| |
| {activeStep?.id === 4 && ( |
| <DataSync |
| activeStep={activeStep} |
| advancedMode={advancedMode} |
| cronConfig={cronConfig} |
| customCronConfig={customCronConfig} |
| createCron={createCron} |
| setCronConfig={setCronConfig} |
| getCronPreset={getCronPreset} |
| fieldHasError={fieldHasError} |
| getFieldError={getFieldError} |
| setCustomCronConfig={setCustomCronConfig} |
| getCronPresetByConfig={getCronPresetByConfig} |
| /> |
| )} |
| </> |
| )} |
| </div> |
| |
| <WorkflowActions |
| activeStep={activeStep} |
| blueprintSteps={blueprintSteps} |
| advancedMode={advancedMode} |
| setShowBlueprintInspector={setShowBlueprintInspector} |
| validationErrors={[...validationErrors, ...blueprintValidationErrors]} |
| onNext={nextStep} |
| onPrev={prevStep} |
| onSave={handleBlueprintSave} |
| onSaveAndRun={handleBlueprintSaveAndRun} |
| isLoading={isSaving || isFetchingJIRA || isFetchingConnection || isTestingConnection} |
| isValid={advancedMode ? isValidBlueprint && isValidPipeline : isValidBlueprint} |
| canGoNext={canAdvanceNext} |
| /> |
| </main> |
| </Content> |
| </div> |
| |
| <ConnectionDialog |
| integrations={integrationsData} |
| activeProvider={activeProvider} |
| setProvider={setActiveProvider} |
| setTestStatus={setTestStatus} |
| setTestResponse={setTestResponse} |
| connection={managedConnection} |
| errors={connectionErrors} |
| validationErrors={connectionValidationErrors} |
| endpointUrl={endpointUrl} |
| name={connectionName} |
| proxy={proxy} |
| token={token} |
| initialTokenStore={initialTokenStore} |
| username={username} |
| password={password} |
| isOpen={connectionDialogIsOpen} |
| isTesting={isTestingConnection} |
| isSaving={isSavingConnection} |
| isValid={isValidConnection} |
| onClose={handleConnectionDialogClose} |
| onOpen={handleConnectionDialogOpen} |
| onTest={testConnection} |
| onSave={saveConnection} |
| onValidate={validateConnection} |
| onNameChange={setName} |
| onEndpointChange={setEndpointUrl} |
| onProxyChange={setProxy} |
| onTokenChange={setToken} |
| onUsernameChange={setUsername} |
| onPasswordChange={setPassword} |
| testStatus={testStatus} |
| testResponse={testResponse} |
| allTestResponses={allTestResponses} |
| /> |
| |
| <CodeInspector |
| title={name} |
| titleIcon='add' |
| subtitle='JSON CONFIGURATION' |
| isOpen={showBlueprintInspector} |
| activePipeline={ |
| !advancedMode |
| ? { |
| // ID: 0, |
| name, |
| // tasks: blueprintTasks, |
| settings: blueprintSettings, |
| cronConfig: isManualBlueprint ? '0 0 * * *' : (cronConfig === 'custom' ? customCronConfig : cronConfig), |
| enable, |
| mode, |
| isManual: isManualBlueprint |
| } |
| : { |
| name, |
| plan: blueprintTasks, |
| cronConfig: isManualBlueprint ? '0 0 * * *' : (cronConfig === 'custom' ? customCronConfig : cronConfig), |
| enable, |
| mode, |
| isManual: isManualBlueprint |
| } |
| } |
| onClose={setShowBlueprintInspector} |
| hasBackdrop={false} |
| /> |
| </> |
| ) |
| } |
| |
| export default CreateBlueprint |