This is an automated email from the ASF dual-hosted git repository.

klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new 7e6723d4 feat: add connection rate limit setting (#2783)
7e6723d4 is described below

commit 7e6723d4d0c5fb37e7858638782cf598c926e1f3
Author: Julien Chinapen <[email protected]>
AuthorDate: Sun Aug 21 22:29:08 2022 -0400

    feat: add connection rate limit setting (#2783)
    
    * feat: add connection rate limit setting
    
    * fix: apply linting cleanups
    
    * fix: enable rate-limit for jenkins provider
    
    * fix: change payload prop name to rateLimitPerHour
    
    * fix: switch value prop and add tapd config
    
    Co-authored-by: Klesh Wong <[email protected]>
---
 .../src/components/blueprints/ConnectionDialog.jsx |  4 +
 config-ui/src/data/NullConnection.js               |  1 +
 config-ui/src/data/Providers.js                    | 39 ++++++---
 config-ui/src/hooks/useConnectionManager.jsx       | 20 +++++
 config-ui/src/hooks/useConnectionValidation.jsx    |  3 +
 .../src/pages/blueprints/create-blueprint.jsx      |  5 ++
 .../pages/configure/connections/AddConnection.jsx  |  5 ++
 .../configure/connections/ConfigureConnection.jsx  |  5 ++
 .../pages/configure/connections/ConnectionForm.jsx | 99 +++++++++++++++-------
 9 files changed, 138 insertions(+), 43 deletions(-)

diff --git a/config-ui/src/components/blueprints/ConnectionDialog.jsx 
b/config-ui/src/components/blueprints/ConnectionDialog.jsx
index 9857b91f..f428951b 100644
--- a/config-ui/src/components/blueprints/ConnectionDialog.jsx
+++ b/config-ui/src/components/blueprints/ConnectionDialog.jsx
@@ -95,6 +95,7 @@ const ConnectionDialog = (props) => {
     name,
     endpointUrl,
     proxy,
+    rateLimit = 0,
     token,
     initialTokenStore = {},
     username,
@@ -116,6 +117,7 @@ const ConnectionDialog = (props) => {
     onNameChange = () => {},
     onEndpointChange = () => {},
     onProxyChange = () => {},
+    onRateLimitChange = () => {},
     onTokenChange = () => {},
     onUsernameChange = () => {},
     onPasswordChange = () => {},
@@ -287,6 +289,7 @@ const ConnectionDialog = (props) => {
                     name={name}
                     endpointUrl={endpointUrl}
                     proxy={proxy}
+                    rateLimit={rateLimit}
                     token={token}
                     initialTokenStore={initialTokenStore}
                     username={username}
@@ -298,6 +301,7 @@ const ConnectionDialog = (props) => {
                     onNameChange={onNameChange}
                     onEndpointChange={onEndpointChange}
                     onProxyChange={onProxyChange}
+                    onRateLimitChange={onRateLimitChange}
                     onTokenChange={onTokenChange}
                     onUsernameChange={onUsernameChange}
                     onPasswordChange={onPasswordChange}
diff --git a/config-ui/src/data/NullConnection.js 
b/config-ui/src/data/NullConnection.js
index f10daa02..70207389 100644
--- a/config-ui/src/data/NullConnection.js
+++ b/config-ui/src/data/NullConnection.js
@@ -21,6 +21,7 @@ const NullConnection = {
   name: null,
   endpoint: null,
   proxy: null,
+  rateLimit: 0,
   token: null,
   username: null,
   password: null,
diff --git a/config-ui/src/data/Providers.js b/config-ui/src/data/Providers.js
index caa94c93..7a33b798 100644
--- a/config-ui/src/data/Providers.js
+++ b/config-ui/src/data/Providers.js
@@ -81,7 +81,8 @@ const ProviderFormLabels = {
     proxy: 'Proxy URL',
     token: 'Basic Auth Token',
     username: 'Username',
-    password: 'Password'
+    password: 'Password',
+    rateLimit: 'Rate Limit'
   },
   gitlab: {
     name: 'Connection Name',
@@ -89,7 +90,8 @@ const ProviderFormLabels = {
     proxy: 'Proxy URL',
     token: 'Access Token',
     username: 'Username',
-    password: 'Password'
+    password: 'Password',
+    rateLimit: <>Rate Limit <sup>(per hour)</sup></>
   },
   jenkins: {
     name: 'Connection Name',
@@ -97,7 +99,8 @@ const ProviderFormLabels = {
     proxy: 'Proxy URL',
     token: 'Basic Auth Token',
     username: 'Username',
-    password: 'Password'
+    password: 'Password',
+    rateLimit: <>Rate Limit <sup>(per hour)</sup></>
   },
   tapd: {
     name: 'Connection Name',
@@ -106,13 +109,14 @@ const ProviderFormLabels = {
     token: 'Basic Auth Token',
     username: 'Username',
     password: 'Password',
+    rateLimit: <>Rate Limit <sup>(per hour)</sup></>
   },
   jira: {
     name: 'Connection Name',
     endpoint: 'Endpoint URL',
     token: 'Basic Auth Token',
     username: 'Username / E-mail',
-    // password; 'Password',
+    proxy: 'Proxy URL',
     password: (
       <>
         Password
@@ -134,17 +138,17 @@ const ProviderFormLabels = {
           />
         </Tooltip>
       </>),
+    rateLimit: <>Rate Limit <sup>(per hour)</sup></>
   },
   github: {
     name: 'Connection Name',
     endpoint: 'Endpoint URL',
     proxy: 'Proxy URL',
-    // token: 'Auth Token(s)',
     token: (
       <>
         Auth Token(s)
         <Tooltip
-          content={(<span>Due to Github’s rate limit, input more tokens, <br 
/>comma separated, to accelerate data collection.</span>)}
+          content={(<span>Due to Github's rate limit, input more tokens, <br 
/>comma separated, to accelerate data collection.</span>)}
           intent='primary'
         >
           <Icon
@@ -162,8 +166,9 @@ const ProviderFormLabels = {
         </Tooltip>
       </>),
     username: 'Username',
-    password: 'Password'
-  },
+    password: 'Password',
+    rateLimit: <>Rate Limit <sup>(per hour)</sup></>
+  }
 }
 
 const ProviderFormPlaceholders = {
@@ -173,7 +178,8 @@ const ProviderFormPlaceholders = {
     proxy: 'eg. http://proxy.localhost:8080',
     token: 'eg. 3f5cda2a23ff410792e0',
     username: 'Enter Username / E-mail',
-    password: 'Enter Password'
+    password: 'Enter Password',
+    rateLimit: '1000'
   },
   gitlab: {
     name: 'eg. GitLab',
@@ -181,7 +187,8 @@ const ProviderFormPlaceholders = {
     proxy: 'eg. http://proxy.localhost:8080',
     token: 'eg. ff9d1ad0e5c04f1f98fa',
     username: 'Enter Username / E-mail',
-    password: 'Enter Password'
+    password: 'Enter Password',
+    rateLimit: '1000'
   },
   jenkins: {
     name: 'eg. Jenkins',
@@ -189,7 +196,8 @@ const ProviderFormPlaceholders = {
     proxy: 'eg. http://proxy.localhost:8080',
     token: 'eg. 6b057ffe68464c93a057',
     username: 'eg. admin',
-    password: 'eg. ************'
+    password: 'eg. ************',
+    rateLimit: '1000'
   },
   tapd: {
     name: 'eg. Tapd',
@@ -197,7 +205,8 @@ const ProviderFormPlaceholders = {
     proxy: 'eg. http://proxy.localhost:8080',
     token: 'eg. 6b057ffe68464c93a057',
     username: 'eg. admin',
-    password: 'eg. ************'
+    password: 'eg. ************',
+    rateLimit: '1000'
   },
   jira: {
     name: 'eg. JIRA',
@@ -205,7 +214,8 @@ const ProviderFormPlaceholders = {
     proxy: 'eg. http://proxy.localhost:8080',
     token: 'eg. 8c06a7cc50b746bfab30',
     username: 'eg. admin',
-    password: 'eg. ************'
+    password: 'eg. ************',
+    rateLimit: '1000'
   },
   github: {
     name: 'eg. GitHub',
@@ -213,7 +223,8 @@ const ProviderFormPlaceholders = {
     proxy: 'eg. http://proxy.localhost:8080',
     token: 'eg. 4c5cbdb62c165e2b3d18, 40008ebccff9837bb8d2',
     username: 'eg. admin',
-    password: 'eg. ************'
+    password: 'eg. ************',
+    rateLimit: '1000'
   }
 }
 
diff --git a/config-ui/src/hooks/useConnectionManager.jsx 
b/config-ui/src/hooks/useConnectionManager.jsx
index b7ad258e..ce5d0f48 100644
--- a/config-ui/src/hooks/useConnectionManager.jsx
+++ b/config-ui/src/hooks/useConnectionManager.jsx
@@ -44,6 +44,7 @@ function useConnectionManager (
   const [name, setName] = useState()
   const [endpointUrl, setEndpointUrl] = useState()
   const [proxy, setProxy] = useState()
+  const [rateLimit, setRateLimit] = useState(0)
   const [token, setToken] = useState()
   const [initialTokenStore, setInitialTokenStore] = useState({
     0: '',
@@ -148,6 +149,7 @@ function useConnectionManager (
           username: username,
           password: password,
           proxy: proxy,
+          rateLimitPerHour: rateLimit,
           ...connectionPayload,
         }
         break
@@ -158,6 +160,7 @@ function useConnectionManager (
           username: username,
           password: password,
           proxy: proxy,
+          rateLimitPerHour: rateLimit,
           ...connectionPayload,
         }
         break
@@ -167,6 +170,7 @@ function useConnectionManager (
           endpoint: endpointUrl,
           token: token,
           proxy: proxy,
+          rateLimitPerHour: rateLimit,
           ...connectionPayload,
         }
         break
@@ -177,6 +181,7 @@ function useConnectionManager (
           endpoint: endpointUrl,
           username: username,
           password: password,
+          rateLimitPerHour: rateLimit,
           ...connectionPayload,
         }
         break
@@ -186,6 +191,7 @@ function useConnectionManager (
           endpoint: endpointUrl,
           token: token,
           proxy: proxy,
+          rateLimitPerHour: rateLimit,
           ...connectionPayload,
         }
         break
@@ -321,6 +327,7 @@ function useConnectionManager (
             name: connectionData.name || connectionData.Name,
             endpoint: connectionData.endpoint || connectionData.Endpoint,
             proxy: connectionData.proxy || connectionData.Proxy,
+            rateLimit: connectionData.rateLimit,
             username: connectionData.username || connectionData.Username,
             password: connectionData.password || connectionData.Password,
             token: connectionData.token || connectionData.auth
@@ -544,6 +551,7 @@ function useConnectionManager (
       2: ''
     })
     setProxy('')
+    setRateLimit(0)
   }, [])
 
   useEffect(() => {
@@ -555,22 +563,32 @@ function useConnectionManager (
         case Providers.JENKINS:
           setUsername(activeConnection.username)
           setPassword(activeConnection.password)
+          setRateLimit(activeConnection.rateLimit)
           break
         case Providers.GITLAB:
           setToken(activeConnection.basicAuthEncoded || activeConnection.token 
|| activeConnection.auth)
           setProxy(activeConnection.Proxy || activeConnection.proxy)
+          setRateLimit(activeConnection.rateLimit)
           break
         case Providers.GITHUB:
           setToken(connectionToken)
           setInitialTokenStore(connectionToken?.split(',')?.reduce((tS, cT, 
id) => ({ ...tS, [id]: cT }), {}))
           setProxy(activeConnection.Proxy || activeConnection.proxy)
+          setRateLimit(activeConnection.rateLimit)
           break
         case Providers.JIRA:
         // setToken(activeConnection.basicAuthEncoded || 
activeConnection.token)
           setUsername(activeConnection.username)
           setPassword(activeConnection.password)
           setProxy(activeConnection.Proxy || activeConnection.proxy)
+          setRateLimit(activeConnection.rateLimit)
           break
+        case Providers.TAPD:
+          setUsername(activeConnection.username)
+          setPassword(activeConnection.password)
+          setProxy(activeConnection.Proxy || activeConnection.proxy)
+          setRateLimit(activeConnection.rateLimit)
+        break
       }
       ToastNotification.clear()
       // ToastNotification.show({ message: `Fetched settings for 
${activeConnection.name}.`, intent: 'success', icon: 'small-tick' })
@@ -657,6 +675,7 @@ function useConnectionManager (
     name,
     endpointUrl,
     proxy,
+    rateLimit,
     username,
     password,
     token,
@@ -667,6 +686,7 @@ function useConnectionManager (
     setName,
     setEndpointUrl,
     setProxy,
+    setRateLimit,
     setToken,
     setInitialTokenStore,
     setUsername,
diff --git a/config-ui/src/hooks/useConnectionValidation.jsx 
b/config-ui/src/hooks/useConnectionValidation.jsx
index 20c300b8..0af438d5 100644
--- a/config-ui/src/hooks/useConnectionValidation.jsx
+++ b/config-ui/src/hooks/useConnectionValidation.jsx
@@ -25,6 +25,7 @@ function useConnectionValidation ({
   name,
   endpointUrl,
   proxy,
+  rateLimit,
   token,
   username,
   password
@@ -48,6 +49,7 @@ function useConnectionValidation ({
       'NAME', name,
       'ENDPOINT URL', endpointUrl,
       'PROXY URL', proxy,
+      'RATE LIMIT', rateLimit,
       'TOKEN', token,
       'USERNAME', username,
       'PASSWORD', password
@@ -100,6 +102,7 @@ function useConnectionValidation ({
     name,
     endpointUrl,
     proxy,
+    rateLimit,
     token,
     username,
     password,
diff --git a/config-ui/src/pages/blueprints/create-blueprint.jsx 
b/config-ui/src/pages/blueprints/create-blueprint.jsx
index b6b6aa8d..6c632c74 100644
--- a/config-ui/src/pages/blueprints/create-blueprint.jsx
+++ b/config-ui/src/pages/blueprints/create-blueprint.jsx
@@ -268,6 +268,7 @@ const CreateBlueprint = (props) => {
     name: connectionName,
     endpointUrl,
     proxy,
+    rateLimit,
     token,
     initialTokenStore,
     username,
@@ -278,6 +279,7 @@ const CreateBlueprint = (props) => {
     setName,
     setEndpointUrl,
     setProxy,
+    setRateLimit,
     setUsername,
     setPassword,
     setToken,
@@ -333,6 +335,7 @@ const CreateBlueprint = (props) => {
     name: connectionName,
     endpointUrl,
     proxy,
+    rateLimit,
     token,
     username,
     password,
@@ -1129,6 +1132,7 @@ const CreateBlueprint = (props) => {
         endpointUrl={endpointUrl}
         name={connectionName}
         proxy={proxy}
+        rateLimit={rateLimit}
         token={token}
         initialTokenStore={initialTokenStore}
         username={username}
@@ -1145,6 +1149,7 @@ const CreateBlueprint = (props) => {
         onNameChange={setName}
         onEndpointChange={setEndpointUrl}
         onProxyChange={setProxy}
+        onRateLimitChange={setRateLimit}
         onTokenChange={setToken}
         onUsernameChange={setUsername}
         onPasswordChange={setPassword}
diff --git a/config-ui/src/pages/configure/connections/AddConnection.jsx 
b/config-ui/src/pages/configure/connections/AddConnection.jsx
index 4ad749bf..4cf69f9f 100644
--- a/config-ui/src/pages/configure/connections/AddConnection.jsx
+++ b/config-ui/src/pages/configure/connections/AddConnection.jsx
@@ -57,6 +57,7 @@ export default function AddConnection () {
     name,
     endpointUrl,
     proxy,
+    rateLimit,
     token,
     initialTokenStore,
     username,
@@ -64,6 +65,7 @@ export default function AddConnection () {
     setName,
     setEndpointUrl,
     setProxy,
+    setRateLimit,
     setUsername,
     setPassword,
     setToken,
@@ -84,6 +86,7 @@ export default function AddConnection () {
     name,
     endpointUrl,
     proxy,
+    rateLimit,
     token,
     username,
     password
@@ -164,6 +167,7 @@ export default function AddConnection () {
                   name={name}
                   endpointUrl={endpointUrl}
                   proxy={proxy}
+                  rateLimit={rateLimit}
                   token={token}
                   initialTokenStore={initialTokenStore}
                   username={username}
@@ -175,6 +179,7 @@ export default function AddConnection () {
                   onNameChange={setName}
                   onEndpointChange={setEndpointUrl}
                   onProxyChange={setProxy}
+                  onRateLimitChange={setRateLimit}
                   onTokenChange={setToken}
                   onUsernameChange={setUsername}
                   onPasswordChange={setPassword}
diff --git a/config-ui/src/pages/configure/connections/ConfigureConnection.jsx 
b/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
index f6607597..ce62c221 100644
--- a/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
+++ b/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
@@ -57,6 +57,7 @@ export default function ConfigureConnection () {
     name,
     endpointUrl,
     proxy,
+    rateLimit = 0,
     username,
     password,
     token,
@@ -71,6 +72,7 @@ export default function ConfigureConnection () {
     setName,
     setEndpointUrl,
     setProxy,
+    setRateLimit,
     setUsername,
     setPassword,
     setToken,
@@ -106,6 +108,7 @@ export default function ConfigureConnection () {
     name,
     endpointUrl,
     proxy,
+    rateLimit,
     token,
     username,
     password
@@ -250,6 +253,7 @@ export default function ConfigureConnection () {
                             name={name}
                             endpointUrl={endpointUrl}
                             proxy={proxy}
+                            rateLimit={rateLimit}
                             token={token}
                             initialTokenStore={initialTokenStore}
                             username={username}
@@ -262,6 +266,7 @@ export default function ConfigureConnection () {
                             onNameChange={setName}
                             onEndpointChange={setEndpointUrl}
                             onProxyChange={setProxy}
+                            onRateLimitChange={setRateLimit}
                             onTokenChange={setToken}
                             onUsernameChange={setUsername}
                             onPasswordChange={setPassword}
diff --git a/config-ui/src/pages/configure/connections/ConnectionForm.jsx 
b/config-ui/src/pages/configure/connections/ConnectionForm.jsx
index c929fa54..46c1f3b2 100644
--- a/config-ui/src/pages/configure/connections/ConnectionForm.jsx
+++ b/config-ui/src/pages/configure/connections/ConnectionForm.jsx
@@ -31,6 +31,7 @@ import {
   // PopoverInteractionKind,
   Intent,
   PopoverInteractionKind,
+  NumericInput
 } from '@blueprintjs/core'
 import { Providers } from '@/data/Providers'
 import FormValidationErrors from '@/components/messages/FormValidationErrors'
@@ -56,6 +57,7 @@ export default function ConnectionForm (props) {
     username,
     password,
     proxy = '',
+    rateLimit = 0,
     isSaving,
     isTesting,
     showError,
@@ -72,6 +74,7 @@ export default function ConnectionForm (props) {
     onUsernameChange = () => {},
     onPasswordChange = () => {},
     onProxyChange = () => {},
+    onRateLimitChange = () => {},
     onValidate = () => {},
     authType = 'token',
     sourceLimits = {},
@@ -89,6 +92,7 @@ export default function ConnectionForm (props) {
   const connectionUsernameRef = useRef()
   const connectionPasswordRef = useRef()
   const connectionProxyRef = useRef()
+  const connectionRateLimitRef = useRef()
 
   // const [isValidForm, setIsValidForm] = useState(true)
   const [allowedAuthTypes, setAllowedAuthTypes] = useState(['token', 'plain'])
@@ -123,8 +127,9 @@ export default function ConnectionForm (props) {
       token,
       username,
       password,
+      rateLimit,
     })
-  }, [name, endpointUrl, token, username, password, onValidate])
+  }, [name, endpointUrl, token, username, password, rateLimit, onValidate])
   const fieldHasError = (fieldId) => {
     return validationErrors.some((e) => e.includes(fieldId))
   }
@@ -702,39 +707,75 @@ export default function ConnectionForm (props) {
             </div>
           </>
         )}
-        {[Providers.GITHUB, Providers.GITLAB, Providers.JIRA, 
Providers.TAPD].includes(
+        {[Providers.GITHUB, Providers.GITLAB, Providers.JIRA, 
Providers.JENKINS, Providers.TAPD].includes(
           activeProvider.id
         ) && (
-          <div className='formContainer'>
-            <FormGroup
-              disabled={isTesting || isSaving || isLocked}
-              inline={true}
-              labelFor='connection-proxy'
-              className={formGroupClassName}
-              contentClassName='formGroupContent'
-            >
-              <Label>{labels ? labels.proxy : <>Proxy&nbsp;URL</>}</Label>
-              <InputGroup
-                id='connection-proxy'
-                inputRef={connectionProxyRef}
-                tabIndex={3}
-                placeholder={
-                  placeholders.proxy
-                    ? placeholders.proxy
-                    : 'http://proxy.localhost:8080'
-                }
-                defaultValue={proxy}
-                onChange={(e) => onProxyChange(e.target.value)}
+          <>
+            <div className='formContainer'>
+              <FormGroup
                 disabled={isTesting || isSaving || isLocked}
-                className={`input input-proxy ${
-                  fieldHasError('Proxy') ? 'invalid-field' : ''
+                inline={true}
+                labelFor='connection-proxy'
+                className={formGroupClassName}
+                contentClassName='formGroupContent'
+              >
+                <Label>{labels ? labels.proxy : <>Proxy&nbsp;URL</>}</Label>
+                <InputGroup
+                  id='connection-proxy'
+                  inputRef={connectionProxyRef}
+                  tabIndex={3}
+                  placeholder={
+                    placeholders.proxy
+                      ? placeholders.proxy
+                      : 'http://proxy.localhost:8080'
+                  }
+                  defaultValue={proxy}
+                  onChange={(e) => onProxyChange(e.target.value)}
+                  disabled={isTesting || isSaving || isLocked}
+                  className={`input input-proxy ${
+                    fieldHasError('Proxy') ? 'invalid-field' : ''
+                  }`}
+                  rightElement={
+                    <InputValidationError error={getFieldError('Proxy')} />
+                  }
+                />
+              </FormGroup>
+            </div>
+            <div className='formContainer'>
+              <FormGroup
+                disabled={isTesting || isSaving || isLocked}
+                inline={true}
+                labelFor='connection-ratelimit'
+                className={formGroupClassName}
+                contentClassName='formGroupContent'
+              >
+                <Label>{labels ? labels.rateLimit : 
<>Rate&nbsp;Limit</>}</Label>
+                <NumericInput
+                  id='connection-ratelimit'
+                  ref={connectionRateLimitRef}
+                  disabled={isTesting || isSaving || isLocked}
+                  min={0}
+                  max={1000000000}
+                  clampValueOnBlur={true}
+                  className={`input input-ratelimit ${
+                  fieldHasError('RateLimit') ? 'invalid-field' : ''
                 }`}
-                rightElement={
-                  <InputValidationError error={getFieldError('Proxy')} />
+                  fill={false}
+                  placeholder={
+                  placeholders.rateLimit
+                    ? placeholders.rateLimit
+                    : '1000'
                 }
-              />
-            </FormGroup>
-          </div>
+                  allowNumericCharactersOnly={true}
+                  onValueChange={(rateLimitPerHour) => { 
onRateLimitChange(rateLimitPerHour) }}
+                  value={rateLimit}
+                  rightElement={
+                    <InputValidationError error={getFieldError('RateLimit')} />
+                }
+                />
+              </FormGroup>
+            </div>
+          </>
         )}
         {enableActions && (
           <div

Reply via email to