blob: 05079dcd72fac986d94f6e37fc7549bc902d3a43 [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, { useEffect, useState, useRef, useCallback } from 'react'
// import dayjs from '@/utils/time'
import {
Button,
Classes,
Colors,
Dialog,
Elevation,
FormGroup,
Icon,
Intent,
Label,
MenuItem,
} from '@blueprintjs/core'
import { Select } from '@blueprintjs/select'
import {
Providers,
// ProviderTypes,
ProviderLabels,
ProviderFormLabels,
ProviderFormPlaceholders,
ProviderConnectionLimits,
// ProviderIcons,
} from '@/data/Providers'
import { NullBlueprintConnection } from '@/data/NullBlueprintConnection'
import InputValidationError from '@/components/validation/InputValidationError'
import ContentLoader from '@/components/loaders/ContentLoader'
import ConnectionForm from '@/pages/configure/connections/ConnectionForm'
const Modes = {
CREATE: 'create',
EDIT: 'edit',
}
// @todo: lift data sources list to configuration level, requires expansion when more providers are added..
const DATA_SOURCES_LIST = [
{
id: 1,
name: Providers.JIRA,
title: ProviderLabels[Providers.JIRA.toUpperCase()],
value: Providers.JIRA,
},
{
id: 2,
name: Providers.GITHUB,
title: ProviderLabels[Providers.GITHUB.toUpperCase()],
value: Providers.GITHUB,
},
{
id: 3,
name: Providers.GITLAB,
title: ProviderLabels[Providers.GITLAB.toUpperCase()],
value: Providers.GITLAB,
},
{
id: 4,
name: Providers.JENKINS,
title: ProviderLabels[Providers.JENKINS.toUpperCase()],
value: Providers.JENKINS,
},
]
const ConnectionDialog = (props) => {
const {
isOpen = false,
activeProvider,
integrations = [],
setProvider = () => {},
setTestStatus = () => {},
setTestResponse = () => {},
connection = NullBlueprintConnection,
name,
endpointUrl,
proxy,
token,
initialTokenStore = {},
username,
password,
isLocked = false,
isLoading = false,
isTesting = false,
isSaving = false,
isValid = false,
// editMode = false,
dataSourcesList = DATA_SOURCES_LIST,
labels = ProviderLabels[connection.provider],
placeholders = ProviderFormPlaceholders[connection.provider],
onTest = () => {},
onSave = () => {},
onClose = () => {},
onCancel = () => {},
onValidate = () => {},
onNameChange = () => {},
onEndpointChange = () => {},
onProxyChange = () => {},
onTokenChange = () => {},
onUsernameChange = () => {},
onPasswordChange = () => {},
showConnectionError = false,
testStatus,
testResponse,
allTestResponses,
errors = [],
validationErrors = [],
canOutsideClickClose = false,
// authType,
// showLimitWarning = false
} = props
const [datasource, setDatasource] = useState(
connection?.id
? dataSourcesList.find((d) => d.value === connection.provider)
: dataSourcesList[0]
)
const [stateErrored, setStateErrored] = useState(false)
const [mode, setMode] = useState(Modes.CREATE)
const getFieldError = (fieldId) => {
return errors.find((e) => e.includes(fieldId))
}
const activateErrorStates = (elementId) => {
setStateErrored(elementId || false)
}
const getConnectionStatusIcon = useCallback(() => {
let i = <Icon icon='full-circle' size='10' color={Colors.RED5} />
switch (testStatus) {
case 1:
i = <Icon icon='full-circle' size='10' color={Colors.GREEN3} />
break
case 2:
i = <Icon icon='full-circle' size='10' color={Colors.RED5} />
break
case 0:
default:
i = <Icon icon='full-circle' size='10' color={Colors.GRAY3} />
break
}
return i
}, [testStatus])
useEffect(() => {
if (connection?.id !== null && connection?.id !== undefined) {
setMode(Modes.EDIT)
setDatasource(
dataSourcesList.find((d) => d.value === connection.provider)
)
} else {
setMode(Modes.CREATE)
}
}, [connection, dataSourcesList])
useEffect(() => {
console.log('>>> DATASOURCE CHANGED....', datasource)
setProvider(integrations.find((p) => p.id === datasource.value))
setTestStatus(0)
setTestResponse(null)
}, [datasource, integrations, setProvider, setTestResponse, setTestStatus])
useEffect(() => {}, [testStatus])
return (
<>
<Dialog
className='dialog-manage-connection'
icon={mode === Modes.EDIT ? 'edit' : 'add'}
title={
mode === Modes.EDIT
? `Modify ${connection?.name} [#${connection?.value}]`
: 'Create a New Data Connection'
}
isOpen={isOpen}
onClose={onClose}
onClosed={() => {}}
// prevent outside close so user can edit without accidental closing of dialog
canOutsideClickClose={canOutsideClickClose}
style={{ backgroundColor: '#ffffff' }}
>
<div className={Classes.DIALOG_BODY}>
{isLoading || isSaving ? (
<ContentLoader
title={`${isSaving ? 'Saving' : 'Loading'} Connection...`}
elevation={Elevation.ZERO}
message='Please wait.'
/>
) : (
<>
<div className='manage-connection'>
<div className='formContainer'>
<FormGroup
disabled={isTesting || isSaving || isLocked}
label=''
inline={true}
labelFor='selector-datasource'
className='formGroup-inline'
contentClassName='formGroupContent'
>
<Label style={{ display: 'inline', marginRight: 0 }}>
{labels ? labels.datasource : <>Data Source</>}
<span className='requiredStar'>*</span>
</Label>
<Select
popoverProps={{ usePortal: false }}
className='selector-datasource'
id='selector-datasource'
inline={false}
fill={true}
items={dataSourcesList}
activeItem={datasource}
itemPredicate={(query, item) =>
item.title.toLowerCase().indexOf(query.toLowerCase()) >=
0}
itemRenderer={(item, { handleClick, modifiers }) => (
<MenuItem
active={modifiers.active}
key={item.value}
label={item.value}
onClick={handleClick}
text={item.title}
/>
)}
noResults={
<MenuItem disabled={true} text='No data sources.' />
}
onItemSelect={(item) => {
setDatasource(item)
}}
readOnly={connection?.id !== null && mode === Modes.EDIT}
>
<Button
disabled={
connection?.id !== null && mode === Modes.EDIT
}
className='btn-select-datasource'
intent={Intent.NONE}
text={
datasource
? `${datasource.title}`
: '< Select Datasource >'
}
rightIcon='double-caret-vertical'
fill
style={{
maxWidth: '260px',
display: 'flex',
justifyContent: 'space-between',
}}
/>
</Select>
</FormGroup>
</div>
<div
className='connection-form-wrapper'
style={{ display: 'flex' }}
>
<ConnectionForm
isValid={isValid}
validationErrors={validationErrors}
activeProvider={activeProvider}
name={name}
endpointUrl={endpointUrl}
proxy={proxy}
token={token}
initialTokenStore={initialTokenStore}
username={username}
password={password}
onSave={onSave}
onTest={onTest}
onCancel={onCancel}
onValidate={onValidate}
onNameChange={onNameChange}
onEndpointChange={onEndpointChange}
onProxyChange={onProxyChange}
onTokenChange={onTokenChange}
onUsernameChange={onUsernameChange}
onPasswordChange={onPasswordChange}
isSaving={isSaving}
isTesting={isTesting}
testStatus={testStatus}
testResponse={testResponse}
allTestResponses={allTestResponses}
errors={errors}
showError={showConnectionError}
authType={
[Providers.JENKINS, Providers.JIRA].includes(
activeProvider?.id
)
? 'plain'
: 'token'
}
showLimitWarning={false}
sourceLimits={ProviderConnectionLimits}
labels={ProviderFormLabels[activeProvider?.id]}
placeholders={ProviderFormPlaceholders[activeProvider?.id]}
enableActions={false}
// formGroupClassName='formGroup-inline'
showHeadline={false}
/>
</div>
</div>
</>
)}
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<div
className='test-response-message'
style={{ marginRight: 'auto' }}
>
{testResponse && (
<>
{testResponse.success
? (
<span style={{ color: Colors.GREEN5 }}>
Successfully Connected!
</span>
)
: (
<span style={{ color: Colors.RED5 }}>
Connection Failed
</span>
)}
</>
)}
</div>
<Button
className='btn-test'
icon={getConnectionStatusIcon()}
disabled={isSaving || !isValid || isTesting}
onClick={() => onTest(false)}
loading={isTesting}
outlined
>
Test Connection
</Button>
<Button
className='btn-save'
disabled={isSaving || !isValid || isTesting}
// icon='cloud-upload'
intent={Intent.PRIMARY}
onClick={() => onSave(connection ? connection.id : null)}
loading={isSaving}
outlined
>
Save Connection
</Button>
</div>
</div>
</Dialog>
</>
)
}
export default ConnectionDialog