Merge pull request #1444 from merico-dev/jc-1386-configure-connection-ux-updates
`fix` `v0.9.2` data integrations - configure connection form ux updates
diff --git a/config-ui/src/components/validation/InputValidationError.jsx b/config-ui/src/components/validation/InputValidationError.jsx
new file mode 100644
index 0000000..3eb8f57
--- /dev/null
+++ b/config-ui/src/components/validation/InputValidationError.jsx
@@ -0,0 +1,31 @@
+import React from 'react'
+import {
+ Colors,
+ Icon,
+ Popover,
+ PopoverInteractionKind,
+ Intent,
+ Position
+} from '@blueprintjs/core'
+
+const InputValidationError = (props) => {
+ const { error, position = Position.TOP } = props
+ return error
+ ? (
+ <div className='inline-input-error' style={{ outline: 'none', cursor: 'pointer', margin: '5px 5px 3px 5px' }}>
+ <Popover
+ position={position}
+ usePortal={true}
+ openOnTargetFocus={true}
+ intent={Intent.WARNING}
+ interactionKind={PopoverInteractionKind.HOVER_TARGET_ONLY}
+ >
+ <Icon icon='warning-sign' size={12} color={Colors.RED5} style={{ outline: 'none' }} />
+ <div style={{ outline: 'none', padding: '5px', borderTop: `2px solid ${Colors.RED5}` }}>{error}</div>
+ </Popover>
+ </div>
+ )
+ : null
+}
+
+export default InputValidationError
diff --git a/config-ui/src/data/Providers.js b/config-ui/src/data/Providers.js
index 75acee0..5747fdc 100644
--- a/config-ui/src/data/Providers.js
+++ b/config-ui/src/data/Providers.js
@@ -91,44 +91,44 @@
const ProviderFormPlaceholders = {
null: {
- name: 'Enter Instance Name',
- endpoint: 'Enter Endpoint URL eg. https://null-api.localhost',
- proxy: 'Enter Proxy URL eg. http://proxy.localhost:8080',
- token: 'Enter Auth Token eg. 3f5cda2a23ff410792e0',
+ name: 'eg. Enter Instance Name',
+ endpoint: 'eg. https://null-api.localhost',
+ proxy: 'eg. http://proxy.localhost:8080',
+ token: 'eg. 3f5cda2a23ff410792e0',
username: 'Enter Username / E-mail',
password: 'Enter Password'
},
gitlab: {
- name: 'Enter Instance Name',
- endpoint: 'Enter Endpoint URL eg. https://gitlab.com/api/v4',
- proxy: 'Enter Proxy URL eg. http://proxy.localhost:8080',
- token: 'Enter Auth Token eg. ff9d1ad0e5c04f1f98fa',
+ name: 'eg. GitLab',
+ endpoint: 'eg. https://gitlab.com/api/v4',
+ proxy: 'eg. http://proxy.localhost:8080',
+ token: 'eg. ff9d1ad0e5c04f1f98fa',
username: 'Enter Username / E-mail',
password: 'Enter Password'
},
jenkins: {
- name: 'Enter Instance Name',
- endpoint: 'Enter Endpoint URL eg. https://api.jenkins.io',
- proxy: 'Enter Proxy URL eg. http://proxy.localhost:8080',
- token: 'Enter Auth Token eg. 6b057ffe68464c93a057',
- username: 'Enter Username / E-mail',
- password: 'Enter Password'
+ name: 'eg. Jenkins',
+ endpoint: 'URL eg. https://api.jenkins.io',
+ proxy: 'eg. http://proxy.localhost:8080',
+ token: 'eg. 6b057ffe68464c93a057',
+ username: 'eg. admin',
+ password: 'eg. ************'
},
jira: {
- name: 'Enter Instance Name',
- endpoint: 'Enter Endpoint URL eg. https://your-domain.atlassian.net/rest/',
- proxy: 'Enter Proxy URL eg. http://proxy.localhost:8080',
- token: 'Enter Auth Token eg. 8c06a7cc50b746bfab30',
- username: 'Enter Username / E-mail',
- password: 'Enter Password'
+ name: 'eg. JIRA',
+ endpoint: 'eg. https://your-domain.atlassian.net/rest/',
+ proxy: 'eg. http://proxy.localhost:8080',
+ token: 'eg. 8c06a7cc50b746bfab30',
+ username: 'eg. admin',
+ password: 'eg. ************'
},
github: {
- name: 'Enter Instance Name',
- endpoint: 'Enter Endpoint URL eg. https://api.github.com',
- proxy: 'Enter Proxy URL eg. http://proxy.localhost:8080',
- token: 'Enter Auth Token(s) eg. 4c5cbdb62c165e2b3d18, 40008ebccff9837bb8d2',
- username: 'Enter Username / E-mail',
- password: 'Enter Password'
+ name: 'eg. GitHub',
+ endpoint: 'eg. https://api.github.com',
+ proxy: 'eg. http://proxy.localhost:8080',
+ token: 'eg. 4c5cbdb62c165e2b3d18, 40008ebccff9837bb8d2',
+ username: 'eg. admin',
+ password: 'eg. ************'
}
}
diff --git a/config-ui/src/pages/configure/connections/ConfigureConnection.jsx b/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
index 5a67de2..71665e4 100644
--- a/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
+++ b/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
@@ -10,6 +10,8 @@
Intent,
Card,
Elevation,
+ Popover,
+ Colors,
} from '@blueprintjs/core'
import Nav from '@/components/Nav'
import Sidebar from '@/components/Sidebar'
@@ -218,7 +220,8 @@
</div>
{activeConnection && (
<>
- <h2 style={{ margin: 0 }}>{activeConnection.name}</h2>
+ {activeProvider.id === Providers.JIRA &&
+ (<h2 style={{ margin: 0 }}>#{activeConnection.ID} {activeConnection.name}</h2>)}
<p className='page-description'>Manage settings and options for this connection.</p>
</>
)}
@@ -246,6 +249,7 @@
<div className='editConnection' style={{ display: 'flex' }}>
<ConnectionForm
isValid={isValidForm}
+ validationErrors={validationErrors}
activeProvider={activeProvider}
name={name}
endpointUrl={endpointUrl}
@@ -285,9 +289,9 @@
</p>
</>
)}
- {validationErrors.length > 0 && (
+ {/* {validationErrors.length > 0 && (
<FormValidationErrors errors={validationErrors} />
- )}
+ )} */}
</Card>
<div style={{ marginTop: '30px' }}>
{renderProviderSettings(providerId, activeProvider)}
diff --git a/config-ui/src/pages/configure/connections/ConnectionForm.jsx b/config-ui/src/pages/configure/connections/ConnectionForm.jsx
index f20f6ab..836df2d 100644
--- a/config-ui/src/pages/configure/connections/ConnectionForm.jsx
+++ b/config-ui/src/pages/configure/connections/ConnectionForm.jsx
@@ -7,11 +7,15 @@
Tag,
Elevation,
Popover,
+ // PopoverInteractionKind,
Position,
- Intent
+ Intent,
+ PopoverInteractionKind
} from '@blueprintjs/core'
import { Providers } from '@/data/Providers'
import GenerateTokenForm from '@/pages/configure/connections/GenerateTokenForm'
+import FormValidationErrors from '@/components/messages/FormValidationErrors'
+import InputValidationError from '@/components/validation/InputValidationError'
import '@/styles/integration.scss'
import '@/styles/connections.scss'
@@ -20,6 +24,7 @@
const {
isLocked = false,
isValid = true,
+ validationErrors = [],
activeProvider,
name,
endpointUrl,
@@ -83,6 +88,14 @@
setShowTokenCreator(isOpen)
}
+ const fieldHasError = (fieldId) => {
+ return validationErrors.some(e => e.includes(fieldId))
+ }
+
+ const getFieldError = (fieldId) => {
+ return validationErrors.find(e => e.includes(fieldId))
+ }
+
useEffect(() => {
if (!allowedAuthTypes.includes(authType)) {
console.log('INVALID AUTH TYPE!')
@@ -158,10 +171,10 @@
label=''
inline={true}
labelFor='connection-name'
- className='formGroup'
+ className='formGroup-inline'
contentClassName='formGroupContent'
>
- <Label style={{ display: 'inline' }}>
+ <Label style={{ display: 'inline', marginRight: 0 }}>
{labels
? labels.name
: (
@@ -176,9 +189,15 @@
placeholder={placeholders ? placeholders.name : 'Enter Instance Name'}
value={name}
onChange={(e) => onNameChange(e.target.value)}
- className='input connection-name-input'
+ className={`input connection-name-input ${fieldHasError('Connection Source') ? 'invalid-field' : ''}`}
leftIcon={[Providers.GITHUB, Providers.GITLAB, Providers.JENKINS].includes(activeProvider.id) ? 'lock' : null}
- fill
+ inline={true}
+ rightElement={(
+ <InputValidationError
+ error={getFieldError('Connection Source')}
+ />
+ )}
+ // fill
/>
</FormGroup>
</div>
@@ -206,8 +225,13 @@
placeholder={placeholders ? placeholders.endpoint : 'Enter Endpoint URL'}
value={endpointUrl}
onChange={(e) => onEndpointChange(e.target.value)}
- className='input'
+ className={`input endpoint-url-input ${fieldHasError('Endpoint') ? 'invalid-field' : ''}`}
fill
+ rightElement={(
+ <InputValidationError
+ error={getFieldError('Endpoint')}
+ />
+ )}
/>
{/* <a href='#' style={{ margin: '5px 0 5px 5px' }}><Icon icon='info-sign' size='16' /></a> */}
</FormGroup>
@@ -237,9 +261,14 @@
placeholder={placeholders ? placeholders.token : 'Enter Auth Token eg. EJrLG8DNeXADQcGOaaaX4B47'}
value={token}
onChange={(e) => onTokenChange(e.target.value)}
- className='input'
+ className={`input auth-input ${fieldHasError('Auth') ? 'invalid-field' : ''}`}
fill
required
+ rightElement={(
+ <InputValidationError
+ error={getFieldError('Auth')}
+ />
+ )}
/>
{
activeProvider.id === Providers.JIRA &&
@@ -305,8 +334,13 @@
placeholder='Enter Username'
defaultValue={username}
onChange={(e) => onUsernameChange(e.target.value)}
- className='input'
- style={{ maxWidth: '300px' }}
+ className={`input username-input ${fieldHasError('Username') ? 'invalid-field' : ''}`}
+ // style={{ maxWidth: '300px' }}
+ rightElement={(
+ <InputValidationError
+ error={getFieldError('Username')}
+ />
+ )}
/>
</FormGroup>
</div>
@@ -334,8 +368,13 @@
placeholder='Enter Password'
defaultValue={password}
onChange={(e) => onPasswordChange(e.target.value)}
- className='input'
- style={{ maxWidth: '300px' }}
+ className={`input password-input ${fieldHasError('Password') ? 'invalid-field' : ''}`}
+ // style={{ maxWidth: '300px' }}
+ rightElement={(
+ <InputValidationError
+ error={getFieldError('Password')}
+ />
+ )}
/>
</FormGroup>
</div>
@@ -363,7 +402,12 @@
defaultValue={proxy}
onChange={(e) => onProxyChange(e.target.value)}
disabled={isTesting || isSaving || isLocked}
- className='input'
+ className={`input input-proxy ${fieldHasError('Proxy') ? 'invalid-field' : ''}`}
+ rightElement={(
+ <InputValidationError
+ error={getFieldError('Proxy')}
+ />
+ )}
/>
</FormGroup>
</div>
@@ -383,6 +427,14 @@
/>
</div>
<div style={{ display: 'flex' }}>
+ <div style={{ justifyContent: 'center', padding: '8px' }}>
+ {validationErrors.length > 0 && (
+ <Popover interactionKind={PopoverInteractionKind.HOVER_TARGET_ONLY}>
+ <Icon icon='warning-sign' size={16} color={Colors.RED5} style={{ outline: 'none' }} />
+ <div style={{ padding: '5px' }}><FormValidationErrors errors={validationErrors} /></div>
+ </Popover>
+ )}
+ </div>
<Button className='btn-cancel' icon='remove' text='Cancel' onClick={onCancel} disabled={isSaving || isTesting} />
<Button
className='btn-save'
diff --git a/config-ui/src/styles/integration.scss b/config-ui/src/styles/integration.scss
index 6441a9e..62c56a6 100644
--- a/config-ui/src/styles/integration.scss
+++ b/config-ui/src/styles/integration.scss
@@ -114,4 +114,29 @@
background-position: center center;
background-repeat: no-repeat;
background-size: 12px 12px;
+}
+
+.configureConnection {
+ min-width: 690px;
+ max-width: 860px;
+ margin-right: auto;
+
+ .bp3-input-group {
+ &.connection-name-input, &.username-input, &.password-input {
+ min-width: 320px;
+ width: auto;
+ max-width: 460px;
+ }
+ }
+}
+
+.bp3-input-group {
+ &.invalid-field {
+ + label { font-weight: bold }
+ > input {
+ box-shadow: rgb(232, 28, 28) 0px 0px 0px 1px, rgba(232, 71, 28, 0.3) 0px 0px 0px 3px, rgba(16, 22, 26, 0.2) 0px 1px 1px 0px inset;
+ box-sizing: border-box;
+ background-color: #ffeeee;
+ }
+ }
}
\ No newline at end of file