blob: 560da912adfb0dd99ba89dded3bf1311a5d6f887 [file] [log] [blame]
/*
* 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