You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by li...@apache.org on 2022/10/31 02:57:07 UTC

[incubator-devlake] branch main updated: feat: setup configuration-ui plugin registry (#2886)

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

likyh 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 c215d73f feat: setup configuration-ui plugin registry (#2886)
c215d73f is described below

commit c215d73fba30c1c0114ab5be871f15b3645d6a53
Author: Julien Chinapen <ju...@merico.dev>
AuthorDate: Sun Oct 30 22:57:02 2022 -0400

    feat: setup configuration-ui plugin registry (#2886)
    
    * feat: enable rate limit per hour toggle options
    
    * fix: reset rateLimit to 0 on disable
    
    * fix: add effect dependency
    
    * fix: update rate limit config for new providers
    
    * fix: extract rate limit tooltip as data const
    
    * fix: use shared rate limit tooltip for bitbucket
    
    * feat: setup configuration-ui plugin registry
    
    * fix: update configure connection with new hook
    
    * fix: register auzre bitbucket and gitee plugins
    
    * fix: register dbt dora refdiff and starrocks
    
    * feat: create hoc for loading transformations
    
    * fix: fetch all connection sources dynamically
    
    * fix: register gitextractor plugin
    
    * fix: register feishu plugin
    
    * fix: add exist check for transform components
    
    * fix: build sidebar connections menu dynamically
    
    * fix: memoize sidebar active menu
    
    * chore: cleanup unused code in connection dialog
    
    * chore: disable legacy blueprint add dialog
    
    * fix: use dynamic providers on data scopes grid
    
    * fix: use provider configs from integrations hook
    
    * fix: create menu item data model
    
    * fix: use provider labels config from igm hook
    
    * fix: only register plugins that are enabled
    
    * fix: setup tooltips from plugin registry
    
    * fix: import tooltips on create-blueprint
    
    * docs: update readme.md for config-ui
    
    * chore: cleanup provider transformation settings
    
    * fix: restore connection limit configuration
    
    * fix: add basic plugin validation
    
    * fix: create connection status data constant
    
    * chore: update comments in Providers.js
    
    * feat: create integrations context and provider
    
    * fix: use context for connections selector
    
    * fix: use integrations context for bp validation
    
    * refactor: use integrations context with hooks
    
    * refactor: use integrations context on DataScopes
    
    * fix: use integrations context on ConnectionForm
    
    * refactor: use integrations context on stage task
    
    * fix: add provider labels to integrations context
    
    * fix: add private prop to Plugin data model
    
    * refactor: store default transforms in registry
    
    * fix: replace props with integrations context
    
    * fix: cleanup json formatting for registry files
    
    * refactor: build scope options from registry
    
    * fix: update plugin model with fields getter
    
    * fix: generate key from entity model
    
    * fix: get default entities from plugin instance
    
    * fix: remove unused Providers in useJIRA hook
    
    * fix: remove unused integrations hook props
    
    * fix: remove unused integrations hook props
    
    * fix: use integrations context with Deployment.jsx
    
    * fix: use double bang syntax for connection limit
---
 config-ui/README.md                                | 126 +++++++++
 config-ui/src/components/NoData.jsx                |   4 +-
 config-ui/src/components/Sidebar.jsx               |  59 ++--
 .../src/components/Sidebar/MenuConfiguration.jsx   | 128 +++------
 .../src/components/blueprints/ConnectionDialog.jsx |  86 +-----
 .../components/blueprints/ConnectionsSelector.jsx  |  39 +--
 .../src/components/blueprints/DataScopesGrid.jsx   |   3 +-
 .../blueprints/ProviderTransformationSettings.jsx  | 150 ++++------
 .../blueprints/create-workflow/DataScopes.jsx      |   7 +-
 .../blueprints/create-workflow/DataSync.jsx        |  14 +-
 .../create-workflow/DataTransformations.jsx        |  29 +-
 .../blueprints/transformations/CICD/Deployment.jsx |  16 +-
 .../src/components/pipelines/StageTaskCaption.jsx  |   2 +-
 .../src/components/pipelines/StageTaskName.jsx     |   7 +-
 .../src/{index.js => data/ConnectionStatus.js}     |  23 +-
 config-ui/src/data/NullProvider.js                 |   1 +
 config-ui/src/data/Providers.js                    |  24 +-
 config-ui/src/data/integrations.jsx                |   2 +
 .../hooks/data-scope/useTransformationsManager.jsx | 221 ++++++++-------
 config-ui/src/hooks/useBlueprintValidation.jsx     |   7 +-
 config-ui/src/hooks/useConnectionManager.jsx       |  52 ++--
 config-ui/src/hooks/useConnectionValidation.jsx    |   8 +-
 config-ui/src/hooks/useDataScopesManager.jsx       | 209 ++++++++------
 config-ui/src/hooks/useIntegrations.jsx            | 305 ++++++++++++++++++++-
 config-ui/src/hooks/useJIRA.jsx                    |  19 --
 config-ui/src/hooks/usePipelineManager.jsx         |  21 +-
 config-ui/src/hooks/usePipelineValidation.jsx      |  22 +-
 config-ui/src/index.js                             |   5 +-
 config-ui/src/models/DataEntity.js                 | 102 +++++++
 config-ui/src/models/GithubProject.js              |   7 +
 config-ui/src/models/GitlabProject.js              |   7 +
 config-ui/src/models/JenkinsJob.js                 |   6 +
 config-ui/src/models/JiraBoard.js                  |   7 +
 .../src/models/{JenkinsJob.js => MenuItem.js}      |  41 ++-
 config-ui/src/models/Plugin.js                     | 109 ++++++++
 .../src/pages/blueprints/blueprint-detail.jsx      |  19 +-
 .../src/pages/blueprints/blueprint-settings.jsx    |  44 ++-
 .../src/pages/blueprints/create-blueprint.jsx      | 131 ++++-----
 config-ui/src/pages/blueprints/index.jsx           |  67 +++--
 .../pages/configure/connections/AddConnection.jsx  | 111 ++++----
 .../configure/connections/ConfigureConnection.jsx  | 153 ++++++-----
 .../pages/configure/connections/ConnectionForm.jsx |  72 ++++-
 .../src/pages/configure/integration/index.jsx      |  68 ++++-
 .../src/pages/configure/integration/manage.jsx     |  61 +++--
 config-ui/src/pages/configure/settings/github.jsx  |   2 +
 config-ui/src/pages/configure/settings/jira.jsx    |   2 +
 config-ui/src/pages/configure/settings/tapd.jsx    |   2 +
 config-ui/src/registry/plugins/ae.json             |  13 +
 config-ui/src/registry/plugins/azure.json          |  53 ++++
 config-ui/src/registry/plugins/bitbucket.json      |  53 ++++
 config-ui/src/registry/plugins/dbt.json            |  12 +
 config-ui/src/registry/plugins/dora.json           |  12 +
 config-ui/src/registry/plugins/feishu.json         |  12 +
 config-ui/src/registry/plugins/gitee.json          |  56 ++++
 config-ui/src/registry/plugins/gitextractor.json   |  12 +
 config-ui/src/registry/plugins/github.json         |  63 +++++
 config-ui/src/registry/plugins/gitlab.json         |  52 ++++
 config-ui/src/registry/plugins/jenkins.json        |  54 ++++
 config-ui/src/registry/plugins/jira.json           |  65 +++++
 config-ui/src/registry/plugins/refdiff.json        |  12 +
 config-ui/src/registry/plugins/starrocks.json      |  12 +
 config-ui/src/registry/plugins/tapd.json           |  55 ++++
 config-ui/src/store/integrations-context.jsx       |  73 +++++
 63 files changed, 2296 insertions(+), 913 deletions(-)

diff --git a/config-ui/README.md b/config-ui/README.md
index d72cf86d..09aa0bc6 100644
--- a/config-ui/README.md
+++ b/config-ui/README.md
@@ -42,6 +42,132 @@ Server will listen on `http://localhost:9000`
 
 For actual production use, the **Docker Image** for Config-UI should be used as outlined in the main project README.md
 
+## Plugin Registration
+
+### Step 1. Create Registry JSON Configuration
+Depending on the nature of the plugin, see a similar integration in `registry/plugins/` folder and copy as base template. For example, to model after GitHub copy `registry/plugins/github.json` to a uniquely named JSON registry file.
+
+```
+# Example "Merico"
+$> cp registry/plugins/github.json registry/plugins/merico.json"
+```
+
+**Configure Plugin Options**
+The newly created registry file needs to customized with **Name** and **Type** (`Default="integration"`), and all related **Connection** property fields (_Labels_, Tooltips, etc)
+
+Since not all Plugins created may have **UI** capabilities, the `type` property is used to distinguish _variance_ in behavior.
+
+- integration
+- plugin
+- pipeline
+- webhook
+
+The **Enabled** property (`enabled`) must be set to `true` to allow the plugin the be registered. 
+
+```
+# Sample Config for "Merico" Plugin
+{
+  "id": "merico",
+  "name": "Merico",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "isBeta": false,
+  "isProvider": true,
+  "icon": "src/images/integrations/merico.svg",
+  ...
+  ...
+  ...
+}
+```
+
+### Step 2. Register the JSON Configuration
+Next, the new plugin needs to be registered with the **Integrations Manager Hook** (`@hooks/useIntegrations.jsx`). 
+1. Import the new Plugin JSON File
+2. Add Plugin to the bottom of `pluginRegistry` Array
+
+```
+$> vi hooks/useIntegrations.jsx`
+....
+....
+import DbtPlugin from '@/registry/plugins/dbt.json'
+import StarrocksPlugin from '@/registry/plugins/starrocks.json'
+import DoraPlugin from '@/registry/plugins/dora.json'
+# Register Merico Plugin
++ import MericoPlugin from '@/registry/plugins/merico.json'
+
+function useIntegrations(
+  pluginRegistry = [
+    JiraPlugin,
+    GitHubPlugin,
+    ...
+    ...
+    # Load Merico Plugin
+    + MericoPlugin
+
+```
+
+### Step 3. Define & Register Transformation Settings Component (Optional)
+
+If this new Plugin requires **Transformation Settings**, the transformation settings component must be created and imported. You may use an existing transformation settings file as a reference. In the future there will be support to create transformation settings dynamically from configuration.
+
+1. Create and Design React Transformation **JSX Component** in `settings/[my-plugin.jsx]`
+
+```jsx
+# Example Transformation Settings Template for "Merico"
+export default function MericoSettings(props) {
+  const {
+    Providers,
+    ProviderLabels,
+    provider,
+    connection,
+    entities = [],
+    transformation = {},
+    isSaving = false,
+    isSavingConnection = false,
+    onSettingsChange = () => {}
+  } = props
+
+  return (
+    <>
+     
+    </>
+  )
+}
+```
+
+3. Import & **Register Provider Transformation Settings** in `components/blueprints/ProviderTransformationSettings.jsx`.  Update the `TransformationComponents` Map to Load the Plugin
+
+```jsx
+# components/blueprints/ProviderTransformationSettings.jsx
+import AzureSettings from '@/pages/configure/settings/azure'
+import BitbucketSettings from '@/pages/configure/settings/bitbucket'
+import GiteeSettings from '@/pages/configure/settings/gitee'
+# Import/Register Merico Plugin
++ import MericoSettings from '@/pages/configure/settings/merico'
+
+const ProviderTransformationSettings = (props) => { 
+  ...
+  ...
+  ...
+  // Provider Transformation Components (LOCAL)
+  const TransformationComponents = useMemo(
+    () => ({
+      ...
+      ...
+      [Providers.AZURE]: AzureSettings,
+      [Providers.BITBUCKET]: BitbucketSettings,
+      [Providers.GITEE]: GiteeSettings
+      # Load Merico Plugin
+      + [Providers.MERICO]: MericoSettings
+    }),
+    [Providers]
+  )
+
+}
+```
+
+
 ## Testing
 
 ### Cypress E2E Tests
diff --git a/config-ui/src/components/NoData.jsx b/config-ui/src/components/NoData.jsx
index a3fb1f48..b63c5d1f 100644
--- a/config-ui/src/components/NoData.jsx
+++ b/config-ui/src/components/NoData.jsx
@@ -40,10 +40,12 @@ const NoData = (props) => {
           </h4>
           <div>{message}</div>
         </div>
-        {onClick && actionText && (
+        {onClick && actionText ? (
           <Button intent={Intent.NONE} onClick={onClick}>
             {actionText}
           </Button>
+        ) : (
+          <p>&nbsp;</p>
         )}
       </div>
     </>
diff --git a/config-ui/src/components/Sidebar.jsx b/config-ui/src/components/Sidebar.jsx
index 3c3356da..5714353e 100644
--- a/config-ui/src/components/Sidebar.jsx
+++ b/config-ui/src/components/Sidebar.jsx
@@ -15,7 +15,13 @@
  * limitations under the License.
  *
  */
-import React, { useEffect, useState, useContext } from 'react'
+import React, {
+  useEffect,
+  useState,
+  useContext,
+  useMemo,
+  useCallback
+} from 'react'
 import {
   // BrowserRouter as Router,
   useRouteMatch
@@ -29,35 +35,46 @@ import { ReactComponent as Logo } from '@/images/devlake-logo.svg'
 import { ReactComponent as LogoText } from '@/images/devlake-textmark.svg'
 
 import '@/styles/sidebar.scss'
-import UIContext from '../store/UIContext'
+import UIContext from '@/store/UIContext'
 
-const Sidebar = () => {
+const Sidebar = (props) => {
+  const { integrations = [] } = props
   const activeRoute = useRouteMatch()
   const uiContext = useContext(UIContext)
 
-  const [menu, setMenu] = useState(MenuConfiguration(activeRoute))
+  const getMenu = useCallback(
+    () => MenuConfiguration(activeRoute, integrations),
+    [activeRoute, integrations]
+  )
+
+  const ActiveMenu = useMemo(() => getMenu(), [getMenu])
+
+  const [menu, setMenu] = useState(ActiveMenu)
   const [versionTag, setVersionTag] = useState('')
 
-  useEffect(() => {
-    setMenu(MenuConfiguration(activeRoute))
-  }, [activeRoute])
+  // useEffect(() => {
+  //   setMenu(ActiveMenu)
+  // }, [ActiveMenu])
 
   useEffect(() => {
-    const fetchVersion = async () => {
-      try {
-        const versionUrl = `${DEVLAKE_ENDPOINT}/version`
-        const res = await request.get(versionUrl).catch((e) => {
-          console.log('>>> API VERSION ERROR...', e)
-          setVersionTag('')
-        })
-        setVersionTag(res?.data ? res.data?.version : '')
-      } catch (e) {
-        setVersionTag('')
-      }
-    }
-    fetchVersion()
+    // @todo: re-enable version fetch
+    // const fetchVersion = async () => {
+    //   try {
+    //     const versionUrl = `${DEVLAKE_ENDPOINT}/version`
+    //     const res = await request.get(versionUrl).catch((e) => {
+    //       console.log('>>> API VERSION ERROR...', e)
+    //       setVersionTag('')
+    //     })
+    //     setVersionTag(res?.data ? res.data?.version : '')
+    //   } catch (e) {
+    //     setVersionTag('')
+    //   }
+    // }
+    // fetchVersion()
   }, [])
 
+  // useEffect(() => {}, [integrations])
+
   return uiContext.sidebarVisible ? (
     <Card
       interactive={false}
@@ -85,7 +102,7 @@ const Sidebar = () => {
       >
         <sup style={{ fontSize: '9px', color: '#cccccc', marginLeft: '-30px' }}>DEV</sup>LAKE
       </h3> */}
-      <SidebarMenu menu={menu} />
+      <SidebarMenu menu={ActiveMenu} />
       <span className='copyright-tag'>
         {/* <span className='version-tag'>{versionTag || ''}</span><br /> */}
         <strong>Apache 2.0 License</strong>
diff --git a/config-ui/src/components/Sidebar/MenuConfiguration.jsx b/config-ui/src/components/Sidebar/MenuConfiguration.jsx
index 8b674201..ce51c3a3 100644
--- a/config-ui/src/components/Sidebar/MenuConfiguration.jsx
+++ b/config-ui/src/components/Sidebar/MenuConfiguration.jsx
@@ -16,10 +16,11 @@
  *
  */
 import React from 'react'
-import { ProviderLabels } from '@/data/Providers'
+// import { ProviderLabels } from '@/data/Providers'
 import { GRAFANA_URL } from '@/utils/config'
+import MenuItem from '@/models/MenuItem'
 
-const MenuConfiguration = (activeRoute) => {
+const MenuConfiguration = (activeRoute, integrations = []) => {
   return [
     {
       id: 0,
@@ -29,98 +30,37 @@ const MenuConfiguration = (activeRoute) => {
         activeRoute.url.startsWith('/integrations') || activeRoute.url === '/',
       icon: 'data-connection',
       classNames: [],
-      children: [
-        {
-          id: 0,
-          label: ProviderLabels.JIRA,
-          route: '/integrations/jira',
-          active:
-            activeRoute.url.endsWith('/integrations/jira') ||
-            activeRoute.url.endsWith('/jira'),
-          icon: 'layers',
-          classNames: []
-        },
-        {
-          id: 1,
-          label: ProviderLabels.GITHUB,
-          route: '/integrations/github',
-          active:
-            activeRoute.url.endsWith('/integrations/github') ||
-            activeRoute.url.endsWith('/github'),
-          icon: 'layers',
-          classNames: []
-        },
-        {
-          id: 2,
-          label: ProviderLabels.GITLAB,
-          route: '/integrations/gitlab',
-          active:
-            activeRoute.url.endsWith('/integrations/gitlab') ||
-            activeRoute.url.endsWith('/gitlab'),
-          icon: 'layers',
-          classNames: []
-        },
-        {
-          id: 3,
-          label: ProviderLabels.JENKINS,
-          route: '/integrations/jenkins',
-          active:
-            activeRoute.url.endsWith('/integrations/jenkins') ||
-            activeRoute.url.endsWith('/jenkins'),
-          icon: 'layers',
-          classNames: []
-        },
-        {
-          id: 4,
-          label: `${ProviderLabels.TAPD} (beta)`,
-          route: '/integrations/tapd',
-          active:
-            activeRoute.url.endsWith('/integrations/tapd') ||
-            activeRoute.url.endsWith('/tapd'),
-          icon: 'layers',
-          classNames: []
-        },
-        {
-          id: 5,
-          label: `${ProviderLabels.AZURE}`,
-          route: '/integrations/azure',
-          active:
-            activeRoute.url.endsWith('/integrations/azure') ||
-            activeRoute.url.endsWith('/azure'),
-          icon: 'layers',
-          classNames: []
-        },
-        {
-          id: 6,
-          label: `${ProviderLabels.BITBUCKET}`,
-          route: '/integrations/bitbucket',
-          active:
-            activeRoute.url.endsWith('/integrations/bitbucket') ||
-            activeRoute.url.endsWith('/bitbucket'),
-          icon: 'layers',
-          classNames: []
-        },
-        {
-          id: 7,
-          label: `${ProviderLabels.GITEE}`,
-          route: '/integrations/gitee',
-          active:
-            activeRoute.url.endsWith('/integrations/gitee') ||
-            activeRoute.url.endsWith('/gitee'),
-          icon: 'layers',
-          classNames: []
-        },
-        {
-          id: 8,
-          label: 'Incoming Webhook',
-          route: '/connections/incoming-webhook',
-          active:
-            activeRoute.url.endsWith('/connections/incoming-webhook') ||
-            activeRoute.url.endsWith('/webhook'),
-          icon: 'layers',
-          classNames: []
-        }
-      ]
+      children: integrations.map(
+        (p, pIdx) =>
+          new MenuItem({
+            id: pIdx,
+            // @todo: support disable prop with json config
+            // disabled: false,
+            label: p?.name,
+            route: `/integrations/${p?.id}`,
+            active:
+              activeRoute.url.endsWith(`/integrations/${p?.id}`) ||
+              activeRoute.url.endsWith(`${p.id}`),
+            icon: p?.icon ? (
+              <img
+                className='providerMenuIconSvg'
+                src={'/' + p?.icon}
+                width={16}
+                height={16}
+                style={{
+                  display: 'flex',
+                  alignSelf: 'center',
+                  width: '16px',
+                  height: '16px'
+                }}
+              />
+            ) : (
+              'layers'
+            ),
+            classNames: []
+            // children: []
+          })
+      )
     },
     {
       id: 1,
diff --git a/config-ui/src/components/blueprints/ConnectionDialog.jsx b/config-ui/src/components/blueprints/ConnectionDialog.jsx
index aa34454f..b0d50f3a 100644
--- a/config-ui/src/components/blueprints/ConnectionDialog.jsx
+++ b/config-ui/src/components/blueprints/ConnectionDialog.jsx
@@ -30,15 +30,6 @@ import {
   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'
@@ -49,58 +40,6 @@ const Modes = {
   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
-  },
-  {
-    id: 5,
-    name: Providers.TAPD,
-    title: ProviderLabels[Providers.TAPD.toUpperCase()],
-    value: Providers.TAPD
-  },
-  {
-    id: 6,
-    name: Providers.AZURE,
-    title: ProviderLabels[Providers.AZURE.toUpperCase()],
-    value: Providers.AZURE
-  },
-  {
-    id: 7,
-    name: Providers.BITBUCKET,
-    title: ProviderLabels[Providers.BITBUCKET.toUpperCase()],
-    value: Providers.BITBUCKET
-  },
-  {
-    id: 8,
-    name: Providers.GITEE,
-    title: ProviderLabels[Providers.GITEE.toUpperCase()],
-    value: Providers.GITEE
-  }
-]
-
 const ConnectionDialog = (props) => {
   const {
     isOpen = false,
@@ -124,9 +63,11 @@ const ConnectionDialog = (props) => {
     isSaving = false,
     isValid = false,
     // editMode = false,
-    dataSourcesList = DATA_SOURCES_LIST,
-    labels = ProviderLabels[connection.provider],
-    placeholders = ProviderFormPlaceholders[connection.provider],
+    dataSourcesList = [],
+    labels,
+    placeholders,
+    tooltips,
+    sourceLimits,
     onTest = () => {},
     onSave = () => {},
     onClose = () => {},
@@ -242,7 +183,7 @@ const ConnectionDialog = (props) => {
                     contentClassName='formGroupContent'
                   >
                     <Label style={{ display: 'inline', marginRight: 0 }}>
-                      {labels ? labels.datasource : <>Data Source</>}
+                      <>Data Source</>
                       <span className='requiredStar'>*</span>
                     </Label>
                     <Select
@@ -331,17 +272,12 @@ const ConnectionDialog = (props) => {
                     allTestResponses={allTestResponses}
                     errors={errors}
                     showError={showConnectionError}
-                    authType={
-                      [Providers.JENKINS, Providers.JIRA].includes(
-                        activeProvider?.id
-                      )
-                        ? 'plain'
-                        : 'token'
-                    }
+                    authType={activeProvider?.getAuthenticationType()}
                     showLimitWarning={false}
-                    sourceLimits={ProviderConnectionLimits}
-                    labels={ProviderFormLabels[activeProvider?.id]}
-                    placeholders={ProviderFormPlaceholders[activeProvider?.id]}
+                    sourceLimits={sourceLimits}
+                    labels={labels}
+                    placeholders={placeholders}
+                    tooltips={tooltips}
                     enableActions={false}
                     // formGroupClassName='formGroup-inline'
                     showHeadline={false}
diff --git a/config-ui/src/components/blueprints/ConnectionsSelector.jsx b/config-ui/src/components/blueprints/ConnectionsSelector.jsx
index f6438b68..f0f68e80 100644
--- a/config-ui/src/components/blueprints/ConnectionsSelector.jsx
+++ b/config-ui/src/components/blueprints/ConnectionsSelector.jsx
@@ -18,7 +18,8 @@
 import React from 'react'
 import { Button, Intent, MenuItem } from '@blueprintjs/core'
 import { MultiSelect } from '@blueprintjs/select'
-import { ProviderIcons } from '@/data/Providers'
+import IntegrationsContext from '@/store/integrations-context'
+// import { ProviderIcons } from '@/data/Providers'
 
 const ConnectionsSelector = (props) => {
   const {
@@ -41,22 +42,26 @@ const ConnectionsSelector = (props) => {
         }
         key={item.id}
         label={
-          <span style={{ marginLeft: '20px' }}>
-            <span
-              style={{
-                display: 'inline-block',
-                marginTop: '2px',
-                width: '14px',
-                height: '14px'
-              }}
-            >
-              {ProviderIcons[item.provider] ? (
-                ProviderIcons[item.provider](14, 14)
-              ) : (
-                <></>
-              )}
-            </span>
-          </span>
+          <IntegrationsContext.Consumer>
+            {({ ProviderIcons }) => (
+              <span style={{ marginLeft: '20px' }}>
+                <span
+                  style={{
+                    display: 'inline-block',
+                    marginTop: '2px',
+                    width: '14px',
+                    height: '14px'
+                  }}
+                >
+                  {ProviderIcons[item.provider] ? (
+                    ProviderIcons[item.provider](14, 14)
+                  ) : (
+                    <></>
+                  )}
+                </span>
+              </span>
+            )}
+          </IntegrationsContext.Consumer>
         }
         onClick={handleClick}
         text={
diff --git a/config-ui/src/components/blueprints/DataScopesGrid.jsx b/config-ui/src/components/blueprints/DataScopesGrid.jsx
index 16c87f5b..c9caac27 100644
--- a/config-ui/src/components/blueprints/DataScopesGrid.jsx
+++ b/config-ui/src/components/blueprints/DataScopesGrid.jsx
@@ -17,11 +17,12 @@
  */
 import React from 'react'
 import { Button, Intent, Card, Elevation, Tag } from '@blueprintjs/core'
-import { Providers, ProviderLabels, ProviderIcons } from '@/data/Providers'
+// import { Providers, ProviderLabels, ProviderIcons } from '@/data/Providers'
 import { NullBlueprint, BlueprintMode } from '@/data/NullBlueprint'
 
 const DataScopesGrid = (props) => {
   const {
+    providers: Providers = {},
     connections = [],
     blueprint = NullBlueprint,
     mode = BlueprintMode.NORMAL,
diff --git a/config-ui/src/components/blueprints/ProviderTransformationSettings.jsx b/config-ui/src/components/blueprints/ProviderTransformationSettings.jsx
index f746934d..70b35bac 100644
--- a/config-ui/src/components/blueprints/ProviderTransformationSettings.jsx
+++ b/config-ui/src/components/blueprints/ProviderTransformationSettings.jsx
@@ -15,15 +15,9 @@
  * limitations under the License.
  *
  */
-import React, { useEffect } from 'react'
-import {
-  Providers
-  // ProviderTypes,
-  // ProviderIcons,
-  // ConnectionStatus,
-  // ConnectionStatusLabels,
-} from '@/data/Providers'
-// import { DataEntities, DataEntityTypes } from '@/data/DataEntities'
+import React, { useMemo } from 'react'
+import NoData from '@/components/NoData'
+
 import JiraSettings from '@/pages/configure/settings/jira'
 import GitlabSettings from '@/pages/configure/settings/gitlab'
 import JenkinsSettings from '@/pages/configure/settings/jenkins'
@@ -33,8 +27,28 @@ import AzureSettings from '@/pages/configure/settings/azure'
 import BitbucketSettings from '@/pages/configure/settings/bitbucket'
 import GiteeSettings from '@/pages/configure/settings/gitee'
 
+// Transformation Higher-Order Component (HOC) Settings Loader
+const withTransformationSettings = (
+  TransformationComponent,
+  TransformationProps
+) =>
+  TransformationComponent ? (
+    <TransformationComponent {...TransformationProps} />
+  ) : (
+    <NoData
+      title='No Transformations'
+      icon='disable'
+      message='This provider does not have additional transformation settings'
+      onClick={null}
+      actionText={null}
+    />
+  )
+
 const ProviderTransformationSettings = (props) => {
   const {
+    Providers = {},
+    ProviderLabels = {},
+    ProviderIcons = {},
     provider,
     blueprint,
     connection,
@@ -50,102 +64,32 @@ const ProviderTransformationSettings = (props) => {
     isFetchingJIRA = false
   } = props
 
-  return (
-    <div className='transformation-settings' data-provider={provider?.id}>
-      {provider?.id === Providers.GITHUB && (
-        <GithubSettings
-          provider={provider}
-          connection={connection}
-          transformation={transformation}
-          onSettingsChange={onSettingsChange}
-          entities={entities[connection?.id]}
-          isSaving={isSaving}
-          isSavingConnection={isSavingConnection}
-        />
-      )}
-
-      {provider?.id === Providers.GITLAB && (
-        <GitlabSettings
-          provider={provider}
-          connection={connection}
-          transformation={transformation}
-          onSettingsChange={onSettingsChange}
-          entities={entities[connection?.id]}
-          isSaving={isSaving}
-          isSavingConnection={isSavingConnection}
-        />
-      )}
+  // Provider Transformation Components (LOCAL)
+  const TransformationComponents = useMemo(
+    () => ({
+      [Providers.GITHUB]: GithubSettings,
+      [Providers.GITLAB]: GitlabSettings,
+      [Providers.JIRA]: JiraSettings,
+      [Providers.JENKINS]: JenkinsSettings,
+      [Providers.TAPD]: TapdSettings,
+      [Providers.AZURE]: AzureSettings,
+      [Providers.BITBUCKET]: BitbucketSettings,
+      [Providers.GITEE]: GiteeSettings
+    }),
+    [Providers]
+  )
 
-      {provider?.id === Providers.JIRA && (
-        <JiraSettings
-          provider={provider}
-          connection={connection}
-          issueTypes={issueTypes}
-          fields={fields}
-          transformation={transformation}
-          onSettingsChange={onSettingsChange}
-          entities={entities[connection?.id]}
-          isSaving={isSaving}
-          isSavingConnection={isSavingConnection}
-          jiraProxyError={jiraProxyError}
-          isFetchingJIRA={isFetchingJIRA}
-        />
-      )}
+  // Dynamic Transformation Settings via HOC
+  const TransformationWithProviderSettings = withTransformationSettings(
+    provider?.id && TransformationComponents[provider?.id]
+      ? TransformationComponents[provider?.id]
+      : null,
+    { ...props, entities: props.entities[props?.connection?.id] }
+  )
 
-      {provider?.id === Providers.JENKINS && (
-        <JenkinsSettings
-          provider={provider}
-          connection={connection}
-          transformation={transformation}
-          onSettingsChange={onSettingsChange}
-          entities={entities[connection?.id]}
-          isSaving={isSaving}
-          isSavingConnection={isSavingConnection}
-        />
-      )}
-      {provider?.id === Providers.TAPD && (
-        <TapdSettings
-          provider={provider}
-          connection={connection}
-          onSettingsChange={onSettingsChange}
-          entities={entities[connection?.id]}
-          isSaving={isSaving}
-          isSavingConnection={isSavingConnection}
-        />
-      )}
-      {provider?.id === Providers.AZURE && (
-        <AzureSettings
-          provider={provider}
-          connection={connection}
-          transformation={transformation}
-          onSettingsChange={onSettingsChange}
-          entities={entities[connection?.id]}
-          isSaving={isSaving}
-          isSavingConnection={isSavingConnection}
-        />
-      )}
-      {provider?.id === Providers.BITBUCKET && (
-        <BitbucketSettings
-          provider={provider}
-          connection={connection}
-          transformation={transformation}
-          onSettingsChange={onSettingsChange}
-          entities={entities[connection?.id]}
-          isSaving={isSaving}
-          isSavingConnection={isSavingConnection}
-        />
-      )}
-      {provider?.id === Providers.GITEE && (
-        <GiteeSettings
-          provider={provider}
-          connection={connection}
-          transformation={transformation}
-          onSettingsChange={onSettingsChange}
-          entities={entities[connection?.id]}
-          isSaving={isSaving}
-          isSavingConnection={isSavingConnection}
-        />
-      )}
+  return (
+    <div className='transformation-settings' data-provider={provider?.id}>
+      {TransformationWithProviderSettings}
     </div>
   )
 }
diff --git a/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx b/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
index 65cb5be4..5262e941 100644
--- a/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
+++ b/config-ui/src/components/blueprints/create-workflow/DataScopes.jsx
@@ -15,7 +15,7 @@
  * limitations under the License.
  *
  */
-import React, { useEffect, useMemo } from 'react'
+import React, { useEffect, useMemo, useContext } from 'react'
 import {
   Button,
   Card,
@@ -24,7 +24,8 @@ import {
   Intent,
   TagInput
 } from '@blueprintjs/core'
-import { ProviderIcons, Providers } from '@/data/Providers'
+import IntegrationsContext from '@/store/integrations-context'
+// import { ProviderIcons, Providers } from '@/data/Providers'
 import ConnectionTabs from '@/components/blueprints/ConnectionTabs'
 import BoardsSelector from '@/components/blueprints/BoardsSelector'
 import DataEntitiesSelector from '@/components/blueprints/DataEntitiesSelector'
@@ -67,6 +68,8 @@ const DataScopes = (props) => {
     cardStyle = {}
   } = props
 
+  const { Providers, ProviderIcons } = useContext(IntegrationsContext)
+
   const selectedBoards = useMemo(
     () => boards[configuredConnection.id],
     [boards, configuredConnection?.id]
diff --git a/config-ui/src/components/blueprints/create-workflow/DataSync.jsx b/config-ui/src/components/blueprints/create-workflow/DataSync.jsx
index 488ce0ca..cce1a429 100644
--- a/config-ui/src/components/blueprints/create-workflow/DataSync.jsx
+++ b/config-ui/src/components/blueprints/create-workflow/DataSync.jsx
@@ -33,13 +33,13 @@ import {
   Card,
   Colors
 } from '@blueprintjs/core'
-import {
-  Providers,
-  ProviderTypes,
-  ProviderIcons,
-  ConnectionStatus,
-  ConnectionStatusLabels
-} from '@/data/Providers'
+// import {
+//   Providers,
+//   ProviderTypes,
+//   ProviderIcons,
+//   ConnectionStatus,
+//   ConnectionStatusLabels
+// } from '@/data/Providers'
 
 import InputValidationError from '@/components/validation/InputValidationError'
 
diff --git a/config-ui/src/components/blueprints/create-workflow/DataTransformations.jsx b/config-ui/src/components/blueprints/create-workflow/DataTransformations.jsx
index 9e51e58b..d54c05ff 100644
--- a/config-ui/src/components/blueprints/create-workflow/DataTransformations.jsx
+++ b/config-ui/src/components/blueprints/create-workflow/DataTransformations.jsx
@@ -15,7 +15,13 @@
  * limitations under the License.
  *
  */
-import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useState,
+  useContext
+} from 'react'
 import {
   Button,
   Card,
@@ -26,8 +32,9 @@ import {
   MenuItem
 } from '@blueprintjs/core'
 import { Select } from '@blueprintjs/select'
-import { integrationsData } from '@/data/integrations'
-import { ProviderIcons, Providers } from '@/data/Providers'
+import IntegrationsContext from '@/store/integrations-context'
+// import { integrationsData } from '@/data/integrations'
+// import { ProviderIcons, Providers } from '@/data/Providers'
 import { DataEntityTypes } from '@/data/DataEntities'
 import { DEFAULT_DATA_ENTITIES } from '@/data/BlueprintWorkflow'
 import { Variants } from '@/data/Variants'
@@ -79,6 +86,9 @@ const DataTransformations = (props) => {
     cardStyle = {}
   } = props
 
+  const { Integrations, Providers, ProviderIcons, ProviderLabels } =
+    useContext(IntegrationsContext)
+
   const noTransformationsAvailable = useMemo(
     () =>
       [Providers.TAPD].includes(configuredConnection?.provider) ||
@@ -86,7 +96,13 @@ const DataTransformations = (props) => {
         dataEntities[configuredConnection?.id].every(
           (e) => e.value !== DataEntityTypes.DEVOPS
         )),
-    [configuredConnection?.provider, configuredConnection?.id, dataEntities]
+    [
+      configuredConnection?.provider,
+      configuredConnection?.id,
+      dataEntities,
+      Providers.TAPD,
+      Providers.GITLAB
+    ]
   )
 
   const boardsAndProjects = useMemo(
@@ -366,7 +382,10 @@ const DataTransformations = (props) => {
                       ) && (
                         <ProviderTransformationSettings
                           key={configuredProject?.id || configuredBoard?.id}
-                          provider={integrationsData.find(
+                          Providers={Providers}
+                          ProviderLabels={ProviderLabels}
+                          ProviderIcons={ProviderIcons}
+                          provider={Integrations.find(
                             (i) => i.id === configuredConnection?.provider
                           )}
                           blueprint={blueprint}
diff --git a/config-ui/src/components/blueprints/transformations/CICD/Deployment.jsx b/config-ui/src/components/blueprints/transformations/CICD/Deployment.jsx
index 15b46884..5bb2ec70 100644
--- a/config-ui/src/components/blueprints/transformations/CICD/Deployment.jsx
+++ b/config-ui/src/components/blueprints/transformations/CICD/Deployment.jsx
@@ -15,7 +15,8 @@
  * limitations under the License.
  *
  */
-import React, { useState, useEffect, useMemo } from 'react'
+import React, { useState, useEffect, useMemo, useContext } from 'react'
+import IntegrationsContext from '@/store/integrations-context'
 import {
   Intent,
   FormGroup,
@@ -24,7 +25,6 @@ import {
   Radio,
   Tag
 } from '@blueprintjs/core'
-import { Providers, ProviderLabels } from '@/data/Providers'
 
 const Deployment = (props) => {
   const {
@@ -34,6 +34,8 @@ const Deployment = (props) => {
     onSettingsChange = () => {}
   } = props
 
+  const { Providers, ProviderLabels } = useContext(IntegrationsContext)
+
   const [selectValue, setSelectValue] = useState(1)
 
   useEffect(() => {
@@ -82,7 +84,13 @@ const Deployment = (props) => {
     }
 
     return [radio1, radio2]
-  }, [provider])
+  }, [
+    provider,
+    ProviderLabels,
+    Providers.JENKINS,
+    Providers.GITHUB,
+    Providers.GITLAB
+  ])
 
   const tagHints = useMemo(() => {
     let hint1
@@ -115,7 +123,7 @@ const Deployment = (props) => {
     }
 
     return [hint1, hint2]
-  }, [provider])
+  }, [provider, Providers.JENKINS, Providers.GITHUB, Providers.GITLAB])
 
   return (
     <>
diff --git a/config-ui/src/components/pipelines/StageTaskCaption.jsx b/config-ui/src/components/pipelines/StageTaskCaption.jsx
index c1b5fae9..170ca22c 100644
--- a/config-ui/src/components/pipelines/StageTaskCaption.jsx
+++ b/config-ui/src/components/pipelines/StageTaskCaption.jsx
@@ -18,7 +18,7 @@
 import React from 'react'
 import { Colors } from '@blueprintjs/core'
 import dayjs from '@/utils/time'
-import { Providers } from '@/data/Providers'
+// import { Providers } from '@/data/Providers'
 
 const StageTaskCaption = (props) => {
   const { task, options } = props
diff --git a/config-ui/src/components/pipelines/StageTaskName.jsx b/config-ui/src/components/pipelines/StageTaskName.jsx
index 8ad33d18..b4b044ce 100644
--- a/config-ui/src/components/pipelines/StageTaskName.jsx
+++ b/config-ui/src/components/pipelines/StageTaskName.jsx
@@ -15,8 +15,9 @@
  * limitations under the License.
  *
  */
-import React, { useEffect, useRef } from 'react'
-import { Providers, ProviderLabels, ProviderIcons } from '@/data/Providers'
+import React, { useEffect, useRef, useContext } from 'react'
+import IntegrationsContext from '@/store/integrations-context'
+// import { Providers, ProviderLabels, ProviderIcons } from '@/data/Providers'
 import {
   Icon,
   Colors,
@@ -31,6 +32,8 @@ import dayjs from '@/utils/time'
 
 const StageTaskName = (props) => {
   const { task, showDetails = null, onClose = () => {} } = props
+  const { Providers, ProviderIcons, ProviderLabels } =
+    useContext(IntegrationsContext)
 
   const popoverTriggerRef = useRef()
 
diff --git a/config-ui/src/index.js b/config-ui/src/data/ConnectionStatus.js
similarity index 69%
copy from config-ui/src/index.js
copy to config-ui/src/data/ConnectionStatus.js
index 0a1693a5..a8e001d2 100644
--- a/config-ui/src/index.js
+++ b/config-ui/src/data/ConnectionStatus.js
@@ -15,15 +15,18 @@
  * limitations under the License.
  *
  */
+const ConnectionStatus = {
+  OFFLINE: 0,
+  ONLINE: 1,
+  DISCONNECTED: 2,
+  TESTING: 3
+}
 
-import React from 'react'
-import ReactDOM from 'react-dom'
-import App from './App'
-import { UIContextProvider } from '@/store/UIContext'
+const ConnectionStatusLabels = {
+  [ConnectionStatus.OFFLINE]: 'Offline',
+  [ConnectionStatus.ONLINE]: 'Online',
+  [ConnectionStatus.DISCONNECTED]: 'Disconnected',
+  [ConnectionStatus.TESTING]: 'Testing'
+}
 
-ReactDOM.render(
-  <UIContextProvider>
-    <App />
-  </UIContextProvider>,
-  document.getElementById('app')
-)
+export { ConnectionStatus, ConnectionStatusLabels }
diff --git a/config-ui/src/data/NullProvider.js b/config-ui/src/data/NullProvider.js
index 0c20822a..728b9291 100644
--- a/config-ui/src/data/NullProvider.js
+++ b/config-ui/src/data/NullProvider.js
@@ -19,6 +19,7 @@ import React from 'react'
 import { Icon } from '@blueprintjs/core'
 import { Providers, ProviderLabels } from '@/data/Providers'
 
+// -- warning -- legacy constant will be removed in a future release
 const NullProvider = {
   id: Providers.NULL, // Unique ID, for a Provider (alphanumeric, lowercase)
   enabled: false, // Enabled Flag
diff --git a/config-ui/src/data/Providers.js b/config-ui/src/data/Providers.js
index 9a3eece8..1a4d4f97 100644
--- a/config-ui/src/data/Providers.js
+++ b/config-ui/src/data/Providers.js
@@ -26,12 +26,17 @@ import { ReactComponent as AzureProviderIcon } from '@/images/integrations/azure
 import { ReactComponent as BitbucketProviderIcon } from '@/images/integrations/bitbucket.svg'
 import { ReactComponent as GiteeProviderIcon } from '@/images/integrations/gitee.svg'
 import { RateLimitTooltip } from '@/data/ConnectionTooltips.js'
-// import GitExtractorIcon from '@/images/git.png'
-// import RefDiffIcon from '@/images/git-diff.png'
 import FeishuIcon from '@/images/feishu.png'
-// import DBTIcon from '@/images/dbt.png'
-// import AEIcon from '@/images/ae.png'
 
+/**
+ *  !! WARNING !! DO NOT USE (DEVELOPMENT USE ONLY)
+ *  Provider Configuration now managed by Plugin Registry,
+ *  This functionality is being replaced by the Integrations Manager Hook!
+ *  see src/hooks/useIntegrations.jsx for more information.
+ *  ---------------------------------------------------------------
+ */
+
+// @note: replaced by Integrations Hook
 const Providers = {
   NULL: 'null',
   GITLAB: 'gitlab',
@@ -51,12 +56,14 @@ const Providers = {
   DORA: 'dora' // (not a true provider)
 }
 
+// @note: replaced by Integrations Hook
 const ProviderTypes = {
   PLUGIN: 'plugin',
   INTEGRATION: 'integration',
   PIPELINE: 'pipeline'
 }
 
+// @note: replaced by Integrations Hook
 const ProviderLabels = {
   NULL: 'NullProvider',
   GITLAB: 'GitLab',
@@ -76,6 +83,7 @@ const ProviderLabels = {
   DORA: 'DORA' // (not a true provider)
 }
 
+// @note: replaced by Integrations Hook and/or delete
 const ProviderConnectionLimits = {
   // (All providers are mult-connection, no source limits defined)
   // jenkins: null,
@@ -84,8 +92,8 @@ const ProviderConnectionLimits = {
   // gitlab: null
 }
 
-// NOTE: Not all fields may be referenced/displayed for a provider,
-// ie. JIRA prefers $token over $username and $password
+// @note: replaced by Integrations Hook
+// @todo: handle tooltips dynamically at form layer
 const ProviderFormLabels = {
   null: {
     name: 'Connection Name',
@@ -262,6 +270,7 @@ const ProviderFormLabels = {
   }
 }
 
+// @note: replaced by Integrations Hook
 const ProviderFormPlaceholders = {
   null: {
     name: 'eg. Enter Instance Name',
@@ -346,6 +355,7 @@ const ProviderFormPlaceholders = {
   }
 }
 
+// @note: replaced by Integrations Hook
 const ProviderIcons = {
   [Providers.GITLAB]: (w, h) => (
     <GitlabProviderIcon width={w || 24} height={h || 24} />
@@ -381,6 +391,7 @@ const ProviderIcons = {
   )
 }
 
+// @note: migrated to @data/ConnectionStatus
 const ConnectionStatus = {
   OFFLINE: 0,
   ONLINE: 1,
@@ -388,6 +399,7 @@ const ConnectionStatus = {
   TESTING: 3
 }
 
+// @note: migrated to @data/ConnectionStatus
 const ConnectionStatusLabels = {
   [ConnectionStatus.OFFLINE]: 'Offline',
   [ConnectionStatus.ONLINE]: 'Online',
diff --git a/config-ui/src/data/integrations.jsx b/config-ui/src/data/integrations.jsx
index 375d4ab8..1a10f7aa 100644
--- a/config-ui/src/data/integrations.jsx
+++ b/config-ui/src/data/integrations.jsx
@@ -37,6 +37,7 @@ import { ReactComponent as GiteeProvider } from '@/images/integrations/gitee.svg
 // import RefDiffProvider from '@/images/git-diff.png'
 // import { ReactComponent as NullProvider } from '@/images/integrations/null.svg'
 
+// @todo: TO-BE replaced with Integrations Hook
 const integrationsData = [
   {
     id: Providers.GITLAB,
@@ -208,6 +209,7 @@ const integrationsData = [
   }
 ]
 
+// @todo: deprecate this var, used for legacy V11 Pipeline
 const pluginsData = [
   {
     id: Providers.GITEXTRACTOR,
diff --git a/config-ui/src/hooks/data-scope/useTransformationsManager.jsx b/config-ui/src/hooks/data-scope/useTransformationsManager.jsx
index c846ca99..a5205666 100644
--- a/config-ui/src/hooks/data-scope/useTransformationsManager.jsx
+++ b/config-ui/src/hooks/data-scope/useTransformationsManager.jsx
@@ -15,103 +15,108 @@
  * limitations under the License.
  *
  */
-import { useCallback, useState } from 'react'
-import { Providers } from '@/data/Providers'
+import { useCallback, useState, useContext } from 'react'
+import IntegrationsContext from '@/store/integrations-context'
+// import { Providers } from '@/data/Providers'
 import TransformationSettings from '@/models/TransformationSettings'
 import { isEqual } from 'lodash'
 
-// TODO separate to each plugin
-const getDefaultTransformations = (provider) => {
-  let transforms = {}
-  switch (provider) {
-    case Providers.GITHUB:
-      transforms = {
-        prType: '',
-        prComponent: '',
-        prBodyClosePattern: '',
-        issueSeverity: '',
-        issueComponent: '',
-        issuePriority: '',
-        issueTypeRequirement: '',
-        issueTypeBug: '',
-        issueTypeIncident: '',
-        refdiff: null,
-        productionPattern: '',
-        deploymentPattern: ''
-        // stagingPattern: '',
-        // testingPattern: ''
-      }
-      break
-    case Providers.JIRA:
-      transforms = {
-        epicKeyField: '',
-        typeMappings: {},
-        storyPointField: '',
-        remotelinkCommitShaPattern: '',
-        bugTags: [],
-        incidentTags: [],
-        requirementTags: [],
-        // @todo: verify if jira utilizes deploy tag(s)?
-        productionPattern: '',
-        deploymentPattern: ''
-        // stagingPattern: '',
-        // testingPattern: ''
-      }
-      break
-    case Providers.JENKINS:
-      transforms = {
-        productionPattern: '',
-        deploymentPattern: ''
-        // stagingPattern: '',
-        // testingPattern: ''
-      }
-      break
-    case Providers.GITLAB:
-      transforms = {
-        productionPattern: '',
-        deploymentPattern: ''
-        // stagingPattern: '',
-        // testingPattern: ''
-      }
-      break
-    case Providers.TAPD:
-      // @todo: complete tapd transforms #2673
-      transforms = {
-        issueTypeRequirement: '',
-        issueTypeBug: '',
-        issueTypeIncident: '',
-        productionPattern: '',
-        deploymentPattern: ''
-        // stagingPattern: '',
-        // testingPattern: ''
-      }
-      break
-  }
-  return transforms
-}
-
 // manage transformations in one place
 const useTransformationsManager = () => {
+  const { Providers, ProviderTransformations, Integrations } =
+    useContext(IntegrationsContext)
   const [transformations, setTransformations] = useState({})
 
-  const generateKey = (
-    connectionProvider,
-    connectionId,
-    projectNameOrBoard
-  ) => {
-    let key = `not-distinguished`
-    switch (connectionProvider) {
-      case Providers.GITHUB:
-      case Providers.GITLAB:
-      case Providers.JENKINS:
-        key = projectNameOrBoard?.id
-        break
-      case Providers.JIRA:
-        key = projectNameOrBoard?.id
-        break
-    }
-    return `${connectionProvider}/${connectionId}/${key}`
-  }
+  const getDefaultTransformations = useCallback(
+    (provider) => {
+      // let transforms = {}
+      const transforms = ProviderTransformations[provider] || {}
+      // @note: Default Transformations configured in Plugin Registry! (see @src/registry/plugins)
+      // switch (provider) {
+      //   case Providers.GITHUB:
+      //     transforms = {
+      //       prType: '',
+      //       prComponent: '',
+      //       prBodyClosePattern: '',
+      //       issueSeverity: '',
+      //       issueComponent: '',
+      //       issuePriority: '',
+      //       issueTypeRequirement: '',
+      //       issueTypeBug: '',
+      //       issueTypeIncident: '',
+      //       refdiff: null,
+      //       productionPattern: '',
+      //       deploymentPattern: ''
+      //       // stagingPattern: '',
+      //       // testingPattern: ''
+      //     }
+      //     break
+      //   case Providers.JIRA:
+      //     transforms = {
+      //       epicKeyField: '',
+      //       typeMappings: {},
+      //       storyPointField: '',
+      //       remotelinkCommitShaPattern: '',
+      //       bugTags: [],
+      //       incidentTags: [],
+      //       requirementTags: [],
+      //       // @todo: verify if jira utilizes deploy tag(s)?
+      //       productionPattern: '',
+      //       deploymentPattern: ''
+      //       // stagingPattern: '',
+      //       // testingPattern: ''
+      //     }
+      //     break
+      //   case Providers.JENKINS:
+      //     transforms = {
+      //       productionPattern: '',
+      //       deploymentPattern: ''
+      //       // stagingPattern: '',
+      //       // testingPattern: ''
+      //     }
+      //     break
+      //   case Providers.GITLAB:
+      //     transforms = {
+      //       productionPattern: '',
+      //       deploymentPattern: ''
+      //       // stagingPattern: '',
+      //       // testingPattern: ''
+      //     }
+      //     break
+      //   case Providers.TAPD:
+      //     // @todo: complete tapd transforms #2673
+      //     transforms = {
+      //       issueTypeRequirement: '',
+      //       issueTypeBug: '',
+      //       issueTypeIncident: '',
+      //       productionPattern: '',
+      //       deploymentPattern: ''
+      //       // stagingPattern: '',
+      //       // testingPattern: ''
+      //     }
+      //     break
+      // }
+      return transforms
+    },
+    [ProviderTransformations]
+  )
+
+  const generateKey = useCallback(
+    (connectionProvider, connectionId, entity) => {
+      let key = `not-distinguished`
+      key = entity ? entity?.getConfiguredEntityId() : key
+      console.info(
+        '>> GENERATING TRANSFORMATION KEY FOR ENTITY...',
+        connectionProvider,
+        connectionId,
+        entity,
+        key,
+        `${connectionProvider}/${connectionId}/${key}`
+      )
+      return `${connectionProvider}/${connectionId}/${key}`
+    },
+    []
+  )
 
   // change some setting in specific connection's specific transformation
   const changeTransformationSettings = useCallback(
@@ -134,7 +139,7 @@ const useTransformationsManager = () => {
         })
       }))
     },
-    [setTransformations]
+    [setTransformations, generateKey]
   )
 
   // set a default value for connection's specific transformation
@@ -158,7 +163,12 @@ const useTransformationsManager = () => {
         }))
       }
     },
-    [setTransformations, transformations]
+    [
+      setTransformations,
+      generateKey,
+      getDefaultTransformations,
+      transformations
+    ]
   )
 
   // get specific connection's specific transformation
@@ -178,7 +188,27 @@ const useTransformationsManager = () => {
       )
       return transformations[key]
     },
-    [transformations]
+    [transformations, generateKey]
+  )
+
+  // get provider's specific scope options
+  // @todo: refactor "projectNameOrBoard" to "entity" in all areas
+  const getTransformationScopeOptions = useCallback(
+    (connectionProvider, projectNameOrBoard) => {
+      const key = generateKey(connectionProvider, projectNameOrBoard)
+      const plugin = Integrations.find((p) => p.id === connectionProvider)
+      console.debug(
+        '>> useTransformationsManager.getScopeOptions...',
+
+        connectionProvider,
+        projectNameOrBoard
+      )
+      return plugin &&
+        typeof plugin?.getDefaultTransformationScopeOptions === 'function'
+        ? plugin.getDefaultTransformationScopeOptions(projectNameOrBoard)
+        : {}
+    },
+    [Integrations, generateKey]
   )
 
   // clear connection's transformation
@@ -198,7 +228,7 @@ const useTransformationsManager = () => {
         [key]: null
       }))
     },
-    [setTransformations]
+    [setTransformations, generateKey]
   )
 
   // check connection's transformation is changed
@@ -221,11 +251,12 @@ const useTransformationsManager = () => {
       )
       return !isEqual(defaultTransform, storedTransform)
     },
-    [transformations]
+    [transformations, generateKey, getDefaultTransformations]
   )
 
   return {
     getTransformation,
+    getTransformationScopeOptions,
     changeTransformationSettings,
     initializeDefaultTransformation,
     clearTransformationSettings,
diff --git a/config-ui/src/hooks/useBlueprintValidation.jsx b/config-ui/src/hooks/useBlueprintValidation.jsx
index 13dd1faf..c6b2a695 100644
--- a/config-ui/src/hooks/useBlueprintValidation.jsx
+++ b/config-ui/src/hooks/useBlueprintValidation.jsx
@@ -15,10 +15,11 @@
  * limitations under the License.
  *
  */
-import { useCallback, useEffect, useState } from 'react'
+import { useCallback, useEffect, useState, useContext } from 'react'
 import parser from 'cron-parser'
 import { BlueprintMode } from '@/data/NullBlueprint'
-import { Providers } from '@/data/Providers'
+import IntegrationsContext from '@/store/integrations-context'
+// import { Providers } from '@/data/Providers'
 
 function useBlueprintValidation({
   name,
@@ -35,6 +36,8 @@ function useBlueprintValidation({
   activeProvider = null,
   activeConnection = null
 }) {
+  const { Providers } = useContext(IntegrationsContext)
+
   const [errors, setErrors] = useState([])
   const [isValid, setIsValid] = useState(false)
 
diff --git a/config-ui/src/hooks/useConnectionManager.jsx b/config-ui/src/hooks/useConnectionManager.jsx
index e7b90404..25c112c0 100644
--- a/config-ui/src/hooks/useConnectionManager.jsx
+++ b/config-ui/src/hooks/useConnectionManager.jsx
@@ -23,12 +23,11 @@ import request from '@/utils/request'
 import Connection from '@/models/Connection'
 import ProviderListConnection from '@/models/ProviderListConnection'
 import {
-  Providers,
-  ProviderConnectionLimits,
   ConnectionStatus,
   ConnectionStatusLabels
-} from '@/data/Providers'
+} from '@/data/ConnectionStatus'
 
+import useIntegrations from '@/hooks/useIntegrations'
 import useNetworkOfflineMode from '@/hooks/useNetworkOfflineMode'
 
 function useConnectionManager(
@@ -38,6 +37,12 @@ function useConnectionManager(
   const history = useHistory()
   const { handleOfflineMode } = useNetworkOfflineMode()
 
+  const {
+    integrations: Integrations,
+    Providers,
+    ProviderConnectionLimits
+  } = useIntegrations()
+
   const [provider, setProvider] = useState(activeProvider)
   const [name, setName] = useState()
   // @todo: refactor to endpoint and setEndpoint
@@ -71,9 +76,9 @@ function useConnectionManager(
   const connectionCount = useMemo(() => allConnections.length, [allConnections])
   const connectionLimitReached = useMemo(
     () =>
-      sourceLimits[provider?.id] &&
-      connectionCount >= sourceLimits[provider?.id],
-    [provider?.id, sourceLimits, connectionCount]
+      ProviderConnectionLimits[provider?.id] &&
+      connectionCount >= ProviderConnectionLimits[provider?.id],
+    [provider?.id, ProviderConnectionLimits, connectionCount]
   )
   const [connectionsList, setConnectionsList] = useState([])
 
@@ -165,7 +170,7 @@ function useConnectionManager(
       }
       runTest()
     },
-    [provider?.id, connectionTestPayload]
+    [provider?.id, connectionTestPayload, Providers.GITHUB]
   )
 
   const notifyConnectionSaveSuccess = useCallback(
@@ -348,33 +353,12 @@ function useConnectionManager(
         console.log('>> FETCHING ALL CONNECTION SOURCES')
         let c = null
         if (allSources) {
-          // @todo: build promises dynamically from $integrationsData
-          const aC = await Promise.all([
-            request.get(
-              `${DEVLAKE_ENDPOINT}/plugins/${Providers.JIRA}/connections`
-            ),
-            request.get(
-              `${DEVLAKE_ENDPOINT}/plugins/${Providers.GITLAB}/connections`
-            ),
-            request.get(
-              `${DEVLAKE_ENDPOINT}/plugins/${Providers.JENKINS}/connections`
-            ),
-            request.get(
-              `${DEVLAKE_ENDPOINT}/plugins/${Providers.GITHUB}/connections`
-            ),
-            request.get(
-              `${DEVLAKE_ENDPOINT}/plugins/${Providers.TAPD}/connections`
-            ),
-            request.get(
-              `${DEVLAKE_ENDPOINT}/plugins/${Providers.AZURE}/connections`
-            ),
-            request.get(
-              `${DEVLAKE_ENDPOINT}/plugins/${Providers.BITBUCKET}/connections`
-            ),
-            request.get(
-              `${DEVLAKE_ENDPOINT}/plugins/${Providers.GITEE}/connections`
+          // Fetch All Provider Integrations from IM Hook
+          const aC = await Promise.all(
+            Integrations.map((p) =>
+              request.get(`${DEVLAKE_ENDPOINT}/plugins/${p?.id}/connections`)
             )
-          ])
+          )
           const builtConnections = aC.map((providerResponse) =>
             []
               .concat(
@@ -441,7 +425,7 @@ function useConnectionManager(
         handleOfflineMode(e.response?.status, e.response)
       }
     },
-    [provider?.id, handleOfflineMode]
+    [provider?.id, handleOfflineMode, Integrations]
   )
 
   const deleteConnection = useCallback(
diff --git a/config-ui/src/hooks/useConnectionValidation.jsx b/config-ui/src/hooks/useConnectionValidation.jsx
index 651a5b26..fbf109a6 100644
--- a/config-ui/src/hooks/useConnectionValidation.jsx
+++ b/config-ui/src/hooks/useConnectionValidation.jsx
@@ -15,8 +15,9 @@
  * limitations under the License.
  *
  */
-import { useState, useEffect, useCallback } from 'react'
-import { Providers } from '@/data/Providers'
+import { useState, useEffect, useCallback, useContext } from 'react'
+import IntegrationsContext from '@/store/integrations-context'
+// import { Providers } from '@/data/Providers'
 
 function useConnectionValidation({
   activeProvider,
@@ -28,6 +29,8 @@ function useConnectionValidation({
   username,
   password
 }) {
+  const { Providers } = useContext(IntegrationsContext)
+
   const [errors, setErrors] = useState([])
   const [isValid, setIsValid] = useState(false)
   const [validURIs, setValidURIs] = useState(['http://', 'https://'])
@@ -105,6 +108,7 @@ function useConnectionValidation({
 
     setErrors(errs)
   }, [
+    Providers,
     name,
     endpointUrl,
     proxy,
diff --git a/config-ui/src/hooks/useDataScopesManager.jsx b/config-ui/src/hooks/useDataScopesManager.jsx
index c7b84b9e..72c0d476 100644
--- a/config-ui/src/hooks/useDataScopesManager.jsx
+++ b/config-ui/src/hooks/useDataScopesManager.jsx
@@ -19,13 +19,13 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
 import { BlueprintMode } from '@/data/NullBlueprint'
 import { DEFAULT_DATA_ENTITIES } from '@/data/BlueprintWorkflow'
 import { integrationsData } from '@/data/integrations'
-import TransformationSettings from '@/models/TransformationSettings'
+// import TransformationSettings from '@/models/TransformationSettings'
 import JiraBoard from '@/models/JiraBoard'
 import GitHubProject from '@/models/GithubProject'
 import GitlabProject from '@/models/GitlabProject'
-import { ProviderIcons, ProviderLabels, Providers } from '@/data/Providers'
 import { DataScopeModes } from '@/data/DataScopes'
 import JenkinsJob from '@/models/JenkinsJob'
+import useIntegrations from '@/hooks/useIntegrations'
 import useTransformationsManager from '@/hooks/data-scope/useTransformationsManager'
 
 function useDataScopesManager({
@@ -35,6 +35,13 @@ function useDataScopesManager({
   /* connection, */ settings = {},
   setSettings = () => {}
 }) {
+  const {
+    integrations: Integrations,
+    Providers,
+    ProviderLabels,
+    ProviderIcons
+  } = useIntegrations()
+
   const [connections, setConnections] = useState([])
   const [newConnections, setNewConnections] = useState([])
 
@@ -53,6 +60,7 @@ function useDataScopesManager({
   const [entities, setEntities] = useState({})
   const {
     getTransformation,
+    getTransformationScopeOptions,
     changeTransformationSettings,
     initializeDefaultTransformation,
     clearTransformationSettings,
@@ -88,7 +96,6 @@ function useDataScopesManager({
     ]
   )
 
-  // @todo: generate scopes dynamically from $integrationsData (in future Integrations Hook [plugin registry])
   const createProviderScopes = useCallback(
     (
       providerId,
@@ -108,68 +115,88 @@ function useDataScopesManager({
         ...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?.value),
-              title: b.title
-              // @todo: verify initial value of since date for jira provider
-              // since: new Date(),
-            },
-            transformation: {
-              ...getTransformation(connection?.providerId, connection?.id, b)
-            }
-          }))
-          break
-        case Providers.GITLAB:
-          newScope = projects[connection.id]?.map((p) => ({
-            ...newScope,
-            options: {
-              projectId: Number(p.value),
-              title: p.title
-            },
-            transformation: {
-              ...getTransformation(connection?.providerId, connection?.id, p)
-            }
-          }))
-          break
-        case Providers.JENKINS:
-          newScope = projects[connection.id]?.map((p) => ({
-            ...newScope,
-            options: {
-              jobName: p.value
-            },
-            transformation: {
-              ...getTransformation(connection?.providerId, connection?.id, p)
-            }
-          }))
-          break
-        case Providers.GITHUB:
-          newScope = projects[connection.id]?.map((p) => ({
-            ...newScope,
-            options: {
-              owner: p.value.split('/')[0],
-              repo: p.value.split('/')[1]
-            },
-            transformation: {
-              ...getTransformation(connection?.providerId, connection?.id, p)
-            }
-          }))
-          break
-        case Providers.TAPD:
-          newScope = {
-            ...newScope
-            // options: {
-            // },
-            // transformation: {},
-          }
-          break
-      }
+      // Generate scopes Dynamically for all Project/Board/Job/... Entities
+      // @todo: refactor again when boards & projects get merged...
+      newScope = [
+        ...(Array.isArray(boards[connection.id]) ? boards[connection.id] : []),
+        ...(Array.isArray(projects[connection.id])
+          ? projects[connection.id]
+          : [])
+      ].map((e) => ({
+        ...newScope,
+        options: {
+          ...getTransformationScopeOptions(connection?.providerId, e)
+        },
+        transformation: {
+          ...getTransformation(connection?.providerId, connection?.id, e)
+        }
+      }))
+      // switch (providerId) {
+      //   case Providers.JIRA:
+      //     newScope = boards[connection.id]?.map((b) => ({
+      //       ...newScope,
+      //       options: {
+      //         boardId: Number(b?.value),
+      //         title: b.title
+      //         // @todo: verify initial value of since date for jira provider
+      //         // since: new Date(),
+      //       },
+      //       transformation: {
+      //         ...getTransformation(connection?.providerId, connection?.id, b)
+      //       }
+      //     }))
+      //     break
+      //   case Providers.GITLAB:
+      //     newScope = projects[connection.id]?.map((p) => ({
+      //       ...newScope,
+      //       options: {
+      //         projectId: Number(p.value),
+      //         title: p.title
+      //       },
+      //       transformation: {
+      //         ...getTransformation(connection?.providerId, connection?.id, p)
+      //       }
+      //     }))
+      //     break
+      //   case Providers.JENKINS:
+      //     newScope = projects[connection.id]?.map((p) => ({
+      //       ...newScope,
+      //       options: {
+      //         jobName: p.value
+      //       },
+      //       transformation: {
+      //         ...getTransformation(connection?.providerId, connection?.id, p)
+      //       }
+      //     }))
+      //     break
+      //   case Providers.GITHUB:
+      //     newScope = projects[connection.id]?.map((p) => ({
+      //       ...newScope,
+      //       options: {
+      //         owner: p.value.split('/')[0],
+      //         repo: p.value.split('/')[1]
+      //       },
+      //       transformation: {
+      //         ...getTransformation(connection?.providerId, connection?.id, p)
+      //       }
+      //     }))
+      //     break
+      //   case Providers.TAPD:
+      //     newScope = {
+      //       ...newScope
+      //       // options: {
+      //       // },
+      //       // transformation: {},
+      //     }
+      //     break
+      // }
       return Array.isArray(newScope) ? newScope.flat() : [newScope]
     },
-    [getTransformation]
+    [
+      getTransformation,
+      getTransformationScopeOptions
+      // Providers
+    ]
   )
 
   const createProviderConnections = useCallback(
@@ -282,7 +309,7 @@ function useDataScopesManager({
           return []
       }
     },
-    [getGithubProjects, getGitlabProjects, getJenkinsProjects]
+    [getGithubProjects, getGitlabProjects, getJenkinsProjects, Providers]
   )
 
   const getAdvancedGithubProjects = useCallback(
@@ -297,7 +324,7 @@ function useDataScopesManager({
             })
           ]
         : [],
-    []
+    [Providers.GITHUB]
   )
 
   const getAdvancedGitlabProjects = useCallback(
@@ -312,7 +339,7 @@ function useDataScopesManager({
             })
           ]
         : [],
-    []
+    [Providers.GITLAB]
   )
 
   const getAdvancedJiraBoards = useCallback(
@@ -327,7 +354,7 @@ function useDataScopesManager({
             })
           ]
         : [],
-    []
+    [Providers.JIRA]
   )
 
   // (altered version from PR No. 2926)
@@ -363,27 +390,16 @@ function useDataScopesManager({
     []
   )
 
-  const getDefaultEntities = useCallback((providerId) => {
-    let entities = []
-    switch (providerId) {
-      case Providers.GITHUB:
-      case Providers.GITLAB:
-        entities = DEFAULT_DATA_ENTITIES
-        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
-      case Providers.TAPD:
-        entities = DEFAULT_DATA_ENTITIES.filter((d) => d.name === 'ci-cd')
-        break
-    }
-    return entities
-  }, [])
+  const getDefaultEntities = useCallback(
+    (providerId) => {
+      console.log('GET ENTITIES FOR PROVIDER =', providerId)
+      let entities = []
+      const plugin = Integrations.find((p) => p.id === providerId)
+      entities = plugin ? plugin?.getDataEntities() : []
+      return entities
+    },
+    [Integrations]
+  )
 
   const createNormalConnection = useCallback(
     (
@@ -448,7 +464,7 @@ function useDataScopesManager({
       stage: 1,
       totalStages: 1
     }),
-    [getProjects]
+    [getProjects, ProviderLabels, ProviderIcons, Providers.JIRA]
   )
 
   const createAdvancedConnection = useCallback(
@@ -521,7 +537,11 @@ function useDataScopesManager({
       getAdvancedGithubProjects,
       getAdvancedGitlabProjects,
       getAdvancedJiraBoards,
-      getDefaultEntities
+      getDefaultEntities,
+      ProviderIcons,
+      ProviderLabels,
+      Providers.GITLAB,
+      Providers.JIRA
     ]
   )
 
@@ -611,7 +631,7 @@ function useDataScopesManager({
         )
         break
     }
-  }, [connection, changeTransformationSettings])
+  }, [connection, changeTransformationSettings, Providers])
 
   useEffect(() => {
     console.log('>>>>> DATA SCOPES MANAGER: Connection List...', connections)
@@ -682,6 +702,13 @@ function useDataScopesManager({
     )
   }, [connection])
 
+  useEffect(() => {
+    console.log(
+      '>>>>> DATA SCOPES MANAGER: SELECTED NEW CONNECTIONS...',
+      newConnections
+    )
+  }, [newConnections])
+
   return {
     connections,
     newConnections,
diff --git a/config-ui/src/hooks/useIntegrations.jsx b/config-ui/src/hooks/useIntegrations.jsx
index 6f831b43..a3c5f884 100644
--- a/config-ui/src/hooks/useIntegrations.jsx
+++ b/config-ui/src/hooks/useIntegrations.jsx
@@ -15,17 +15,308 @@
  * limitations under the License.
  *
  */
-import { useState, useEffect } from 'react'
-import { integrationsData } from '@/data/integrations'
+import React, { useState, useEffect, useCallback, useMemo } from 'react'
 
-function useIntegrations(data = []) {
-  const [integrations, setIntegrations] = useState(integrationsData)
+import Plugin from '@/models/Plugin'
 
-  useEffect(() => {
-    // setIntegrations(integrationsData)
+// LOCAL PLUGIN REGISTRY
+// "integration" Plugins a.k.a "Providers"
+import JiraPlugin from '@/registry/plugins/jira.json'
+import GitHubPlugin from '@/registry/plugins/github.json'
+import GitLabPlugin from '@/registry/plugins/gitlab.json'
+import JenkinsPlugin from '@/registry/plugins/jenkins.json'
+import TapdPlugin from '@/registry/plugins/tapd.json'
+import AzurePlugin from '@/registry/plugins/azure.json'
+import BitbucketPlugin from '@/registry/plugins/bitbucket.json'
+import GiteePlugin from '@/registry/plugins/gitee.json'
+import AePlugin from '@/registry/plugins/ae.json'
+import RefdiffPlugin from '@/registry/plugins/refdiff.json'
+import DbtPlugin from '@/registry/plugins/dbt.json'
+import StarrocksPlugin from '@/registry/plugins/starrocks.json'
+import DoraPlugin from '@/registry/plugins/dora.json'
+
+const ProviderTypes = {
+  PLUGIN: 'plugin',
+  INTEGRATION: 'integration',
+  PIPELINE: 'pipeline',
+  WEBHOOK: 'webhook'
+}
+
+function useIntegrations(
+  pluginRegistry = [
+    JiraPlugin,
+    GitHubPlugin,
+    GitLabPlugin,
+    JenkinsPlugin,
+    TapdPlugin,
+    AzurePlugin,
+    BitbucketPlugin,
+    GiteePlugin,
+    AePlugin,
+    RefdiffPlugin,
+    DbtPlugin,
+    StarrocksPlugin,
+    DoraPlugin
+  ]
+) {
+  const [registry, setRegistry] = useState(pluginRegistry || [])
+  const [plugins, setPlugins] = useState([])
+
+  // @todo: fetch live/dynamic plugins from API
+  const [apiPlugins, setApiPlugins] = useState([])
+  const [apiRegistry, setApiRegistry] = useState([])
+
+  const [activeProvider, setActiveProvider] = useState()
+
+  const integrations = useMemo(
+    () => plugins.filter((p) => p.type === ProviderTypes.INTEGRATION),
+    [plugins]
+  )
+
+  const DataSources = useMemo(
+    () =>
+      integrations.map((P, iDx) => ({
+        id: iDx + 1,
+        name: P.name,
+        title: P.name,
+        value: P.id
+      })),
+    [integrations]
+  )
+
+  const Providers = useMemo(
+    () =>
+      plugins
+        .map((P) => P.id)
+        .reduce(
+          (pV, cV, iDx) => ({ ...pV, [cV.toString()?.toUpperCase()]: cV }),
+          {}
+        ),
+    [plugins]
+  )
+
+  const ProviderLabels = useMemo(
+    () =>
+      plugins
+        .map((P) => P)
+        .reduce(
+          (pV, cV, iDx) => ({
+            ...pV,
+            [cV?.id.toString()?.toUpperCase()]: cV.name
+          }),
+          {}
+        ),
+    [plugins]
+  )
+
+  const ProviderFormLabels = useMemo(
+    () =>
+      integrations
+        .map((P) => P.getConnectionFormLabels())
+        .reduce((pV, cV, iDx) => ({ ...pV, [integrations[iDx]?.id]: cV }), {}),
+    [integrations]
+  )
+
+  const ProviderFormPlaceholders = useMemo(
+    () =>
+      integrations
+        .map((P) => P.getConnectionFormPlaceholders())
+        .reduce((pV, cV, iDx) => ({ ...pV, [integrations[iDx]?.id]: cV }), {}),
+    [integrations]
+  )
+
+  const ProviderFormTooltips = useMemo(
+    () =>
+      integrations
+        .map((P) => P.getConnectionFormTooltips())
+        .reduce((pV, cV, iDx) => ({ ...pV, [integrations[iDx]?.id]: cV }), {}),
+    [integrations]
+  )
+
+  const ProviderIcons = useMemo(
+    () =>
+      integrations
+        .map((p) => p.icon)
+        .reduce(
+          (pV, cV, iDx) => ({
+            ...pV,
+            [integrations[iDx]?.id]: (w, h) => (
+              <img
+                src={'/' + cV}
+                style={{ width: `${w}px`, height: `${h}px` }}
+              />
+            )
+          }),
+          {}
+        ),
+    [integrations]
+  )
+
+  const ProviderConnectionLimits = useMemo(
+    () =>
+      integrations
+        .map((P) => parseInt(P.connectionLimit, 10))
+        .reduce((pV, cV, iDx) => ({ ...pV, [integrations[iDx]?.id]: cV }), {}),
+    [integrations]
+  )
+
+  const ProviderTransformations = useMemo(
+    () =>
+      integrations
+        .map((P) => P.getDefaultTransformations())
+        .reduce((pV, cV, iDx) => ({ ...pV, [integrations[iDx]?.id]: cV }), {}),
+    [integrations]
+  )
+
+  const registerPlugin = useCallback((pluginConfig) => {
+    console.log(
+      '>>> REGISTERING PLUGIN...',
+      `${pluginConfig?.name} [${pluginConfig?.type}]`
+    )
+    // @todo: Validate Plugin before Registration
+    return new Plugin(pluginConfig)
+  }, [])
+
+  const validatePlugin = useCallback((pluginConfig) => {
+    let isValid = false
+    const requiredProperties = [
+      'id',
+      'name',
+      'type',
+      'enabled',
+      'multiConnection',
+      'icon'
+    ]
+    // todo: enhance plugin validation
+    try {
+      console.log('>>> INTEGRATIONS HOOK: VALIDATING PLUGIN...', pluginConfig)
+      JSON.parse(JSON.stringify(pluginConfig))
+      isValid = requiredProperties.every((p) =>
+        Object.prototype.hasOwnProperty.call(pluginConfig, p)
+      )
+      if (!isValid) {
+        console.log(
+          '>>> INTEGRATIONS HOOK: PLUGIN SCHEMA INCOMPLETE, MISSING REQUIRED PROPERTIES!',
+          pluginConfig
+        )
+      }
+    } catch (e) {
+      console.log(
+        '>>> INTEGRATIONS HOOK: PLUGIN VALIDATION FAILED!',
+        e,
+        pluginConfig
+      )
+    }
+    return isValid
   }, [])
 
-  return [integrations, setIntegrations]
+  const getPlugin = useCallback(
+    (pluginId) => {
+      return plugins.find((p) => p.id === pluginId)
+    },
+    [plugins]
+  )
+
+  useEffect(() => {
+    console.log(
+      '>>> INTEGRATIONS HOOK: PLUGIN REGISTRY CONFIGURATION!!!',
+      registry
+    )
+    setPlugins((aP) => [
+      // ...aP,
+      ...registry
+        .filter((p) => p.enabled)
+        .filter((p) => validatePlugin(p))
+        .map((p) => registerPlugin(p))
+    ])
+  }, [registry, setPlugins, validatePlugin, registerPlugin])
+
+  useEffect(() => {
+    console.log(
+      '>>> INTEGRATIONS HOOK: REGISTERED PLUGIN OBJECT CLASSES...',
+      plugins
+    )
+    setActiveProvider(plugins[0])
+  }, [plugins])
+
+  useEffect(() => {
+    console.log(
+      '>>> INTEGRATIONS HOOK: REGISTERED LIVE API PLUGIN OBJECT CLASSES...',
+      apiPlugins
+    )
+  }, [apiPlugins])
+
+  useEffect(() => {
+    console.log('>>> INTEGRATIONS HOOK: ACTIVE PROVIDER..', activeProvider)
+  }, [activeProvider])
+
+  useEffect(() => {
+    console.log(
+      '>>> INTEGRATIONS HOOK: PROVIDERS CONFIGURATION LIST ...',
+      Providers
+    )
+    console.log(
+      '>>> INTEGRATIONS HOOK: PROVIDER LABELS CONFIGURATION LIST ...',
+      ProviderLabels
+    )
+    console.log(
+      '>>> INTEGRATIONS HOOK: PROVIDER CONFIGURATION CONNECTION FORM LABELS..',
+      ProviderFormLabels
+    )
+    console.log(
+      '>>> INTEGRATIONS HOOK: PROVIDER CONFIGURATION CONNECTION  FORM PLACEHOLDERS..',
+      ProviderFormPlaceholders
+    )
+    console.log(
+      '>>> INTEGRATIONS HOOK: PROVIDER CONFIGURATION CONNECTION  FORM TOOLTIPS..',
+      ProviderFormTooltips
+    )
+    console.log(
+      '>>> INTEGRATIONS HOOK: PROVIDER CONFIGURATION PROVIDER ICONS..',
+      ProviderIcons
+    )
+    console.log(
+      '>>> INTEGRATIONS HOOK: PROVIDER CONNECTION LIMITS...',
+      ProviderConnectionLimits
+    )
+    console.log(
+      '>>> INTEGRATIONS HOOK: PROVIDER DATA SOURCES LIST...',
+      DataSources
+    )
+  }, [
+    activeProvider,
+    Providers,
+    ProviderLabels,
+    ProviderFormLabels,
+    ProviderFormPlaceholders,
+    ProviderConnectionLimits,
+    ProviderFormTooltips,
+    ProviderIcons,
+    DataSources
+  ])
+
+  return {
+    activeProvider,
+    registry,
+    plugins,
+    apiPlugins,
+    apiRegistry,
+    integrations,
+    DataSources,
+    Providers,
+    ProviderLabels,
+    ProviderFormLabels,
+    ProviderFormPlaceholders,
+    ProviderFormTooltips,
+    ProviderIcons,
+    ProviderConnectionLimits,
+    ProviderTypes,
+    ProviderTransformations,
+    setRegistry,
+    setApiRegistry,
+    setActiveProvider,
+    getPlugin
+  }
 }
 
 export default useIntegrations
diff --git a/config-ui/src/hooks/useJIRA.jsx b/config-ui/src/hooks/useJIRA.jsx
index eccaa5be..08b36da5 100644
--- a/config-ui/src/hooks/useJIRA.jsx
+++ b/config-ui/src/hooks/useJIRA.jsx
@@ -18,8 +18,6 @@
 import { useEffect, useState, useCallback } from 'react'
 import request from '@/utils/request'
 import { ToastNotification } from '@/components/Toast'
-import { Providers } from '@/data/Providers'
-import DataScopeConnection from '@/models/DataScopeConnection'
 
 const useJIRA = (
   { apiProxyPath, issuesEndpoint, fieldsEndpoint, boardsEndpoint },
@@ -41,9 +39,6 @@ const useJIRA = (
   const [error, setError] = useState()
 
   const fetchIssueTypes = useCallback(() => {
-    // if (activeConnection?.plugin !== Providers.JIRA) {
-    //   return
-    // }
     try {
       if (apiProxyPath.includes('null') || !activeConnection?.connectionId) {
         throw new Error('Connection ID is Null')
@@ -82,9 +77,6 @@ const useJIRA = (
   }, [issuesEndpoint, activeConnection, apiProxyPath])
 
   const fetchFields = useCallback(() => {
-    // if (activeConnection?.plugin !== Providers.JIRA) {
-    //   return
-    // }
     try {
       if (apiProxyPath.includes('null') || !activeConnection?.connectionId) {
         throw new Error('Connection ID is Null')
@@ -124,9 +116,6 @@ const useJIRA = (
 
   const fetchBoards = useCallback(
     async (search, callback = () => {}) => {
-      // if (activeConnection?.plugin !== Providers.JIRA) {
-      //   return
-      // }
       try {
         if (apiProxyPath.includes('null') || !activeConnection?.connectionId) {
           throw new Error('Connection ID is Null')
@@ -273,10 +262,6 @@ const useJIRA = (
     )
   }, [boardsResponse])
 
-  // useEffect(() => {
-  //   console.log('>>> ALL JIRA RESOURCES!', allResources)
-  // }, [allResources])
-
   useEffect(() => {
     console.log('>>> JIRA API PROXY: FIELD SELECTOR LIST DATA', fields)
   }, [fields])
@@ -291,10 +276,6 @@ const useJIRA = (
     }
   }, [error])
 
-  // useEffect(() => {
-  //   console.log('>>> JIRA PROXY ACTIVE CONNECTION...', activeConnection)
-  // }, [activeConnection])
-
   return {
     isFetching,
     fetchFields,
diff --git a/config-ui/src/hooks/usePipelineManager.jsx b/config-ui/src/hooks/usePipelineManager.jsx
index aa1a60f8..5a97c7ec 100644
--- a/config-ui/src/hooks/usePipelineManager.jsx
+++ b/config-ui/src/hooks/usePipelineManager.jsx
@@ -15,12 +15,13 @@
  * limitations under the License.
  *
  */
-import { useState, useEffect, useCallback, useMemo } from 'react'
+import { useState, useEffect, useCallback, useMemo, useContext } from 'react'
 import { DEVLAKE_ENDPOINT } from '@/utils/config'
 import request from '@/utils/request'
 import { NullPipelineRun } from '@/data/NullPipelineRun'
 import { ToastNotification } from '@/components/Toast'
-import { Providers } from '@/data/Providers'
+import IntegrationsContext from '@/store/integrations-context'
+// import { Providers } from '@/data/Providers'
 import { Intent } from '@blueprintjs/core'
 // import { integrationsData } from '@/data/integrations'
 
@@ -28,6 +29,7 @@ function usePipelineManager(
   myPipelineName = `COLLECTION ${Date.now()}`,
   initialTasks = []
 ) {
+  const { Providers } = useContext(IntegrationsContext)
   // const [integrations, setIntegrations] = useState(integrationsData)
   const [pipelineName, setPipelineName] = useState(
     myPipelineName ?? `COLLECTION ${Date.now()}`
@@ -47,18 +49,9 @@ function usePipelineManager(
   const [activePipeline, setActivePipeline] = useState(NullPipelineRun)
   const [lastRunId, setLastRunId] = useState(null)
   const [pipelineRun, setPipelineRun] = useState(NullPipelineRun)
-  const [allowedProviders, setAllowedProviders] = useState([
-    Providers.JIRA,
-    Providers.GITLAB,
-    Providers.JENKINS,
-    Providers.GITHUB,
-    Providers.REFDIFF,
-    Providers.GITEXTRACTOR,
-    Providers.FEISHU,
-    Providers.AE,
-    Providers.DBT,
-    Providers.TAPD
-  ])
+  const [allowedProviders, setAllowedProviders] = useState(
+    Object.keys(Providers)
+  )
 
   const PIPELINES_ENDPOINT = useMemo(() => `${DEVLAKE_ENDPOINT}/pipelines`, [])
   const [logfile, setLogfile] = useState('logging.tar.gz')
diff --git a/config-ui/src/hooks/usePipelineValidation.jsx b/config-ui/src/hooks/usePipelineValidation.jsx
index f1cd789b..1fabba0a 100644
--- a/config-ui/src/hooks/usePipelineValidation.jsx
+++ b/config-ui/src/hooks/usePipelineValidation.jsx
@@ -15,8 +15,9 @@
  * limitations under the License.
  *
  */
-import { useCallback, useEffect, useState } from 'react'
-import { Providers } from '@/data/Providers'
+import { useCallback, useEffect, useState, useContext } from 'react'
+import IntegrationsContext from '@/store/integrations-context'
+// import { Providers } from '@/data/Providers'
 import { BlueprintMode } from '@/data/NullBlueprint'
 
 function usePipelineValidation({
@@ -43,22 +44,13 @@ function usePipelineValidation({
   entities = [],
   rawConfiguration
 }) {
+  const { Providers } = useContext(IntegrationsContext)
   const [errors, setErrors] = useState([])
   const [isValid, setIsValid] = useState(false)
   const [detectedProviders, setDetectedProviders] = useState([])
-  const [allowedProviders, setAllowedProviders] = useState([
-    Providers.JIRA,
-    Providers.GITLAB,
-    Providers.JENKINS,
-    Providers.GITHUB,
-    Providers.REFDIFF,
-    Providers.GITEXTRACTOR,
-    Providers.FEISHU,
-    Providers.AE,
-    Providers.DBT,
-    Providers.STARROCKS,
-    Providers.TAPD
-  ])
+  const [allowedProviders, setAllowedProviders] = useState(
+    Object.keys(Providers)
+  )
 
   const clear = () => {
     setErrors([])
diff --git a/config-ui/src/index.js b/config-ui/src/index.js
index 0a1693a5..83f0e9df 100644
--- a/config-ui/src/index.js
+++ b/config-ui/src/index.js
@@ -20,10 +20,13 @@ import React from 'react'
 import ReactDOM from 'react-dom'
 import App from './App'
 import { UIContextProvider } from '@/store/UIContext'
+import { IntegrationsContextProvider } from '@/store/integrations-context'
 
 ReactDOM.render(
   <UIContextProvider>
-    <App />
+    <IntegrationsContextProvider>
+      <App />
+    </IntegrationsContextProvider>
   </UIContextProvider>,
   document.getElementById('app')
 )
diff --git a/config-ui/src/models/DataEntity.js b/config-ui/src/models/DataEntity.js
new file mode 100644
index 00000000..435987b1
--- /dev/null
+++ b/config-ui/src/models/DataEntity.js
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ *
+ */
+
+/**
+ * @type {object}
+ */
+const DataEntityTypes = {
+  CODE: 'CODE',
+  TICKET: 'TICKET',
+  CODE_REVIEW: 'CODEREVIEW',
+  CROSSDOMAIN: 'CROSS',
+  DEVOPS: 'CICD'
+  // USER: 'user',
+}
+
+/**
+ * @type {<Array<Object>>}
+ */
+const DataEntityList = [
+  {
+    id: 1,
+    name: 'source-code-management',
+    title: 'Source Code Management',
+    value: DataEntityTypes.CODE
+  },
+  {
+    id: 2,
+    name: 'issue-tracking',
+    title: 'Issue Tracking',
+    value: DataEntityTypes.TICKET
+  },
+  {
+    id: 3,
+    name: 'code-review',
+    title: 'Code Review',
+    value: DataEntityTypes.CODE_REVIEW
+  },
+  {
+    id: 4,
+    name: 'cross-domain',
+    title: 'Crossdomain',
+    value: DataEntityTypes.CROSSDOMAIN
+  },
+  {
+    id: 5,
+    name: 'ci-cd',
+    title: 'CI/CD',
+    value: DataEntityTypes.DEVOPS
+  }
+]
+
+/**
+ * @typedef {object} DataEntity
+ * @property {number} id
+ * @property {string} name
+ * @property {string?} title
+ * @property {string} value
+ * @property {'CODE'|'TICKET'|'CODEREVIEW'|'CROSS'|'CICD'} type
+ */
+class DataEntity {
+  constructor(data = {}) {
+    this.id = data?.type
+      ? DataEntityList.find((e) => e.value === data?.type)?.id
+      : 0
+    this.name = data?.type
+      ? DataEntityList.find((e) => e.value === data?.type)?.name
+      : DataEntityList[0]?.name
+    this.title = data?.type
+      ? DataEntityList.find((e) => e.value === data?.type)?.title
+      : DataEntityList[0]?.title
+    this.value = data?.type
+      ? DataEntityList.find((e) => e.value === data?.type)?.value
+      : DataEntityList[0]?.type
+    this.type = data?.type || DataEntityList[0]?.type
+  }
+
+  get(property) {
+    return this[property]
+  }
+
+  set(property, value) {
+    this[property] = value
+    return this.property
+  }
+}
+
+export default DataEntity
diff --git a/config-ui/src/models/GithubProject.js b/config-ui/src/models/GithubProject.js
index d7aebbd8..bce54912 100644
--- a/config-ui/src/models/GithubProject.js
+++ b/config-ui/src/models/GithubProject.js
@@ -63,6 +63,13 @@ class GitHubProject {
   getConfiguredEntityId() {
     return this.name.toString() || this.id
   }
+
+  getTransformationScopeOptions() {
+    return {
+      owner: this.owner,
+      repo: this.repo
+    }
+  }
 }
 
 export default GitHubProject
diff --git a/config-ui/src/models/GitlabProject.js b/config-ui/src/models/GitlabProject.js
index 6ab3b0d9..70d8f22b 100644
--- a/config-ui/src/models/GitlabProject.js
+++ b/config-ui/src/models/GitlabProject.js
@@ -102,6 +102,13 @@ class GitlabProject {
   getConfiguredEntityId() {
     return this.id
   }
+
+  getTransformationScopeOptions() {
+    return {
+      projectId: this.id,
+      title: this.title
+    }
+  }
 }
 
 export default GitlabProject
diff --git a/config-ui/src/models/JenkinsJob.js b/config-ui/src/models/JenkinsJob.js
index a5fe7c8d..f2bc3ade 100644
--- a/config-ui/src/models/JenkinsJob.js
+++ b/config-ui/src/models/JenkinsJob.js
@@ -53,6 +53,12 @@ class JenkinsJob {
   getConfiguredEntityId() {
     return this.name.toString() || this.id
   }
+
+  getTransformationScopeOptions() {
+    return {
+      jobName: this.value
+    }
+  }
 }
 
 export default JenkinsJob
diff --git a/config-ui/src/models/JiraBoard.js b/config-ui/src/models/JiraBoard.js
index 89573bf0..9ccaa98f 100644
--- a/config-ui/src/models/JiraBoard.js
+++ b/config-ui/src/models/JiraBoard.js
@@ -72,6 +72,13 @@ class JiraBoard {
   getConfiguredEntityId() {
     return this.id
   }
+
+  getTransformationScopeOptions() {
+    return {
+      boardId: this.id,
+      title: this.title
+    }
+  }
 }
 
 export default JiraBoard
diff --git a/config-ui/src/models/JenkinsJob.js b/config-ui/src/models/MenuItem.js
similarity index 58%
copy from config-ui/src/models/JenkinsJob.js
copy to config-ui/src/models/MenuItem.js
index a5fe7c8d..eb77d256 100644
--- a/config-ui/src/models/JenkinsJob.js
+++ b/config-ui/src/models/MenuItem.js
@@ -17,28 +17,27 @@
  */
 
 /**
- * @typedef {object} JenkinsJob
+ * @typedef {object} MenuItem
  * @property {number?} id
- * @property {number?} key
- * @property {number?} projectId
- * @property {string|number?} name
- * @property {string|number?} value
- * @property {string|number?} title
- * @property {boolean?} useApi
- * @property {project|board|job?} variant
- * @property {string?} providerId
+ * @property {boolean?} disabled
+ * @property {string?} label
+ * @property {string|Object?} route
+ * @property {boolean?} active
+ * @property {string|Object} icon
+ * @property {<Array<string>>?} classNames
+ * @property {<Array<MenuItem>>?} children
+ * @property {string?} target
  */
-class JenkinsJob {
+class MenuItem {
   constructor(data = {}) {
     this.id = data?.id || null
-    this.key = data?.key || this.id || null
-    this.name = data?.name || null
-    this.value = data?.value || this.name || this.id || null
-    this.title = data?.title || this.name || this.id || null
-
-    this.useApi = data?.useApi || true
-    this.variant = data?.variant || 'job'
-    this.providerId = 'jenkins'
+    this.disabled = !!data?.disabled
+    this.label = data?.label || null
+    this.route = data?.route || '#'
+    this.active = !!data?.active
+    this.icon = data?.icon || null
+    this.classNames = Array.isArray(data?.classNames) ? data?.classNames : []
+    this.target = data?.target || null
   }
 
   get(property) {
@@ -49,10 +48,6 @@ class JenkinsJob {
     this[property] = value
     return this.property
   }
-
-  getConfiguredEntityId() {
-    return this.name.toString() || this.id
-  }
 }
 
-export default JenkinsJob
+export default MenuItem
diff --git a/config-ui/src/models/Plugin.js b/config-ui/src/models/Plugin.js
new file mode 100644
index 00000000..cb887a3d
--- /dev/null
+++ b/config-ui/src/models/Plugin.js
@@ -0,0 +1,109 @@
+/*
+ * 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 DataEntity from './DataEntity'
+
+/**
+ * @typedef {object} Plugin
+ * @property {string|number?} id
+ * @property {string} name
+ * @property {string?} description
+ * @property {'integration'|'pipeline'|'plugin'?} type
+ * @property {bool} enabled
+ * @property {bool} isBeta
+ * @property {bool} isProvider
+ * @property {bool} multiConnection
+ * @property {bool} private
+ * @property {object?} icon
+ * @property {object?} connection
+ * @property {object?} settings
+ * @property {number?} connectionLimit
+ * @property {<Array<DataEntity>>?} entities
+ * @property {object?} transformations
+ */
+class Plugin {
+  constructor(data = {}) {
+    this.id = data?.id || Math.random() * 99999
+    this.name = data?.name || 'New Plugin'
+    this.type = data?.type || 'integration'
+    this.description = data?.description || null
+    this.enabled = data?.enabled || false
+    this.isBeta = data?.isBeta || false
+    this.isProvider = data?.isProvider || false
+    this.multiConnection = data?.multiConnection || false
+    this.private = data?.private || false
+    this.icon = data?.icon || null
+    this.connection = data?.connection || null
+    this.connectionLimit = data?.connectionLimit || 0
+    this.entities = data?.entities?.map((e) => new DataEntity({ type: e })) || [
+      new DataEntity({ type: 'CODE' })
+    ]
+    this.transformations = data?.transformations || {
+      scopes: { options: {} },
+      default: {}
+    }
+  }
+
+  get(property) {
+    return this[property]
+  }
+
+  set(property, value) {
+    this[property] = value
+    return this.property
+  }
+
+  getAuthenticationType() {
+    return this.connection?.authentication || 'plain'
+  }
+
+  getConnectionFields() {
+    return this.connection ? this.connection?.fields : {}
+  }
+
+  getConnectionFormLabels() {
+    return this.connection ? this.connection?.labels : {}
+  }
+
+  getConnectionFormPlaceholders() {
+    return this.connection ? this.connection?.placeholders : {}
+  }
+
+  getConnectionFormTooltips() {
+    return this.connection ? this.connection?.tooltips : {}
+  }
+
+  getDefaultTransformations() {
+    return this.transformations?.default || {}
+  }
+
+  getDefaultTransformationScopeOptions(entity) {
+    const scopeOptions = {
+      ...(this.transformations?.scopes?.options || {}),
+      ...(entity && typeof entity.getTransformationScopeOptions === 'function'
+        ? entity.getTransformationScopeOptions()
+        : {})
+    }
+    return scopeOptions
+  }
+
+  getDataEntities() {
+    return this.entities || []
+  }
+}
+
+export default Plugin
diff --git a/config-ui/src/pages/blueprints/blueprint-detail.jsx b/config-ui/src/pages/blueprints/blueprint-detail.jsx
index 96756537..0820a3e2 100644
--- a/config-ui/src/pages/blueprints/blueprint-detail.jsx
+++ b/config-ui/src/pages/blueprints/blueprint-detail.jsx
@@ -41,7 +41,7 @@ import {
 } from '@blueprintjs/core'
 import { NullBlueprint } from '@/data/NullBlueprint'
 import { NullPipelineRun } from '@/data/NullPipelineRun'
-import { Providers, ProviderLabels, ProviderIcons } from '@/data/Providers'
+// import { Providers, ProviderLabels, ProviderIcons } from '@/data/Providers'
 import {
   StageStatus,
   TaskStatus,
@@ -59,6 +59,7 @@ import StageLane from '@/components/pipelines/StageLane'
 import { ToastNotification } from '@/components/Toast'
 import BlueprintNavigationLinks from '@/components/blueprints/BlueprintNavigationLinks'
 
+import useIntegrations from '@/hooks/useIntegrations'
 import useBlueprintManager from '@/hooks/useBlueprintManager'
 import usePipelineManager from '@/hooks/usePipelineManager'
 import usePaginator from '@/hooks/usePaginator'
@@ -66,6 +67,18 @@ import usePaginator from '@/hooks/usePaginator'
 const BlueprintDetail = (props) => {
   // eslint-disable-next-line no-unused-vars
   const history = useHistory()
+
+  const {
+    registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    Providers,
+    ProviderIcons,
+    ProviderLabels,
+    activeProvider,
+    setActiveProvider
+  } = useIntegrations()
+
   const { bId } = useParams()
 
   const [blueprintId, setBlueprintId] = useState()
@@ -313,7 +326,7 @@ const BlueprintDetail = (props) => {
         plan: blueprint?.plan
       })
     }
-  }, [blueprint, setPipelineSettings])
+  }, [blueprint, setPipelineSettings, ProviderLabels])
 
   useEffect(() => {
     console.log('>>>> FETCHED ALL PIPELINES..', pipelines, activeBlueprint?.id)
@@ -440,7 +453,7 @@ const BlueprintDetail = (props) => {
     <>
       <div className='container'>
         <Nav />
-        <Sidebar />
+        <Sidebar key={Integrations} integrations={Integrations} />
         <Content>
           <main className='main'>
             <div
diff --git a/config-ui/src/pages/blueprints/blueprint-settings.jsx b/config-ui/src/pages/blueprints/blueprint-settings.jsx
index ae4d47d7..e4e736c8 100644
--- a/config-ui/src/pages/blueprints/blueprint-settings.jsx
+++ b/config-ui/src/pages/blueprints/blueprint-settings.jsx
@@ -39,13 +39,13 @@ import {
   Classes,
   Popover
 } from '@blueprintjs/core'
-
-import { integrationsData } from '@/data/integrations'
+import useIntegrations from '@/hooks/useIntegrations'
+// import { integrationsData } from '@/data/integrations'
 import JiraBoard from '@/models/JiraBoard'
 import DataScopeConnection from '@/models/DataScopeConnection'
 import { NullBlueprint, BlueprintMode } from '@/data/NullBlueprint'
 import { NullPipelineRun } from '@/data/NullPipelineRun'
-import { Providers, ProviderLabels, ProviderIcons } from '@/data/Providers'
+// import { Providers, ProviderLabels, ProviderIcons } from '@/data/Providers'
 import { TaskStatus } from '@/data/Task'
 
 import Nav from '@/components/Nav'
@@ -89,7 +89,18 @@ const BlueprintSettings = (props) => {
   const history = useHistory()
   const { bId } = useParams()
 
-  const [activeProvider, setActiveProvider] = useState(integrationsData[0])
+  const {
+    registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    Providers,
+    ProviderLabels,
+    ProviderIcons,
+    activeProvider,
+    setActiveProvider
+  } = useIntegrations()
+
+  // const [activeProvider, setActiveProvider] = useState(integrationsData[0])
   // @disabled Provided By Data Scopes Manager
   // const [activeTransformation, setActiveTransformation] = useState()
 
@@ -482,7 +493,7 @@ const BlueprintSettings = (props) => {
       console.log('>>> MODIFYING DATA CONNECTION SCOPE...', connectionWithScope)
       setActiveProvider((aP) =>
         connection
-          ? integrationsData.find((i) => i.id === connection?.provider)
+          ? Integrations.find((i) => i.id === connection?.provider)
           : aP
       )
       setActiveSetting((aS) => ({
@@ -501,7 +512,9 @@ const BlueprintSettings = (props) => {
       connectionsList,
       connections,
       setScopeConnection,
-      setConfiguredConnection
+      setConfiguredConnection,
+      setActiveProvider,
+      Integrations
     ]
   )
 
@@ -575,7 +588,8 @@ const BlueprintSettings = (props) => {
     entities,
     configuredConnection,
     activeProvider?.id,
-    activeBlueprint?.mode
+    activeBlueprint?.mode,
+    Providers
   ])
 
   // @note: lifted higher to dsm hook
@@ -762,7 +776,8 @@ const BlueprintSettings = (props) => {
     getJiraMappedBoards,
     setRawConfiguration,
     createAdvancedConnection,
-    createNormalConnection
+    createNormalConnection,
+    Providers.JIRA
   ])
 
   useEffect(() => {
@@ -879,7 +894,8 @@ const BlueprintSettings = (props) => {
     // activeProvider,
     // isFetchingJIRA,
     // jiraApiBoards,
-    scopeConnection
+    scopeConnection,
+    Providers.JIRA
   ])
 
   useEffect(() => {
@@ -913,7 +929,8 @@ const BlueprintSettings = (props) => {
     scopeConnection?.connectionId,
     scopeConnection?.providerId,
     getJiraMappedBoards,
-    setConnections
+    setConnections,
+    Providers.JIRA
   ])
 
   useEffect(() => {
@@ -945,7 +962,8 @@ const BlueprintSettings = (props) => {
     scopeConnection?.providerId,
     getJiraMappedBoards,
     setConnections,
-    boardSearch
+    boardSearch,
+    Providers.JIRA
   ])
 
   useEffect(() => {
@@ -1037,7 +1055,7 @@ const BlueprintSettings = (props) => {
     <>
       <div className='container'>
         <Nav />
-        <Sidebar />
+        <Sidebar key={Integrations} integrations={Integrations} />
         <Content>
           <main className='main'>
             {activeBlueprint?.id !== null && blueprintErrors.length === 0 && (
@@ -1257,6 +1275,7 @@ const BlueprintSettings = (props) => {
                         Data Scope and Transformation
                       </h2>
                       <DataScopesGrid
+                        providers={Providers}
                         connections={connections}
                         blueprint={activeBlueprint}
                         onModify={modifyConnection}
@@ -1298,6 +1317,7 @@ const BlueprintSettings = (props) => {
                       </div>
                     </div>
                     <DataScopesGrid
+                      providers={Providers}
                       connections={connections}
                       blueprint={activeBlueprint}
                       onModify={() => modifySetting('plan')}
diff --git a/config-ui/src/pages/blueprints/create-blueprint.jsx b/config-ui/src/pages/blueprints/create-blueprint.jsx
index 4a21cb63..13773464 100644
--- a/config-ui/src/pages/blueprints/create-blueprint.jsx
+++ b/config-ui/src/pages/blueprints/create-blueprint.jsx
@@ -31,9 +31,9 @@ import {
   ISSUE_FIELDS_ENDPOINT,
   BOARDS_ENDPOINT
 } from '@/config/jiraApiProxy'
-import { integrationsData } from '@/data/integrations'
+// import { integrationsData } from '@/data/integrations'
 import { Intent } from '@blueprintjs/core'
-import { Providers } from '@/data/Providers'
+// import { Providers } from '@/data/Providers'
 import Nav from '@/components/Nav'
 import Sidebar from '@/components/Sidebar'
 // import AppCrumbs from '@/components/Breadcrumbs'
@@ -51,6 +51,7 @@ import {
   DEFAULT_DATA_ENTITIES
 } from '@/data/BlueprintWorkflow'
 
+import useIntegrations from '@/hooks/useIntegrations'
 import useBlueprintManager from '@/hooks/useBlueprintManager'
 import usePipelineManager from '@/hooks/usePipelineManager'
 import useConnectionManager from '@/hooks/useConnectionManager'
@@ -91,6 +92,22 @@ const CreateBlueprint = (props) => {
   const history = useHistory()
   // const dispatch = useDispatch()
 
+  const {
+    registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    activeProvider,
+    DataSources: DataSourcesList,
+    Providers,
+    ProviderLabels,
+    ProviderIcons,
+    ProviderFormLabels,
+    ProviderFormPlaceholders,
+    ProviderFormTooltips,
+    ProviderConnectionLimits,
+    setActiveProvider
+  } = useIntegrations()
+
   const [blueprintAdvancedSteps, setBlueprintAdvancedSteps] = useState(
     WorkflowAdvancedSteps
   )
@@ -101,7 +118,9 @@ const CreateBlueprint = (props) => {
   const [activeStep, setActiveStep] = useState(
     blueprintSteps.find((s) => s.id === 1)
   )
-  const [activeProvider, setActiveProvider] = useState(integrationsData[0])
+
+  // @todo: Replace with Integrations Hook
+  // const [activeProvider, setActiveProvider] = useState(integrationsData[0])
 
   const [enabledProviders, setEnabledProviders] = useState([])
   const [runTasks, setRunTasks] = useState([])
@@ -118,6 +137,20 @@ const CreateBlueprint = (props) => {
     NullBlueprintConnection
   )
 
+  const ConnectionFormLabels = useMemo(
+    () => ProviderFormLabels[activeProvider?.id],
+    [ProviderFormLabels, activeProvider?.id]
+  )
+  const ConnectionFormPlaceholders = useMemo(
+    () => ProviderFormPlaceholders[activeProvider?.id],
+    [ProviderFormPlaceholders, activeProvider?.id]
+  )
+
+  const ConnectionFormTooltips = useMemo(
+    () => ProviderFormTooltips[activeProvider?.id],
+    [ProviderFormTooltips, activeProvider?.id]
+  )
+
   const [dataEntitiesList, setDataEntitiesList] = useState([
     ...DEFAULT_DATA_ENTITIES
   ])
@@ -462,14 +495,20 @@ const CreateBlueprint = (props) => {
       )
       setActiveConnectionTab(tab)
       setActiveProvider(
-        integrationsData.find((p) => p.id === selectedConnection.provider)
+        Integrations.find((p) => p.id === selectedConnection.provider)
       )
       setProvider(
-        integrationsData.find((p) => p.id === selectedConnection.provider)
+        Integrations.find((p) => p.id === selectedConnection.provider)
       )
       setConfiguredConnection(selectedConnection)
     },
-    [blueprintConnections, setProvider, setConfiguredConnection]
+    [
+      blueprintConnections,
+      setProvider,
+      setActiveProvider,
+      setConfiguredConnection,
+      Integrations
+    ]
   )
 
   const handleConnectionDialogOpen = useCallback(() => {
@@ -565,16 +604,16 @@ const CreateBlueprint = (props) => {
         break
     }
     return items
-  }, [dataEntitiesList, configuredConnection])
+  }, [dataEntitiesList, configuredConnection, Providers])
 
   const manageConnection = useCallback(
     (connection) => {
       console.log('>> MANAGE CONNECTION...', connection)
       if (connection?.id !== null) {
         setActiveProvider(
-          integrationsData.find((p) => p.id === connection.provider)
+          Integrations.find((p) => p.id === connection.provider)
         )
-        setProvider(integrationsData.find((p) => p.id === connection.provider))
+        setProvider(Integrations.find((p) => p.id === connection.provider))
         setManagedConnection(connection)
         setConnectionDialogIsOpen(true)
       }
@@ -583,7 +622,8 @@ const CreateBlueprint = (props) => {
       setProvider,
       setActiveProvider,
       setManagedConnection,
-      setConnectionDialogIsOpen
+      setConnectionDialogIsOpen,
+      Integrations
     ]
   )
 
@@ -683,7 +723,8 @@ const CreateBlueprint = (props) => {
     fetchFields,
     fetchIssueTypes,
     enabledProviders,
-    mode
+    mode,
+    Providers.JIRA
   ])
 
   useEffect(() => {
@@ -757,31 +798,10 @@ const CreateBlueprint = (props) => {
       setConfiguredConnection(someConnection)
       setActiveConnectionTab(`connection-${someConnection?.id}`)
       setActiveProvider(
-        integrationsData.find((p) => p.id === someConnection.provider)
-      )
-      setProvider(
-        integrationsData.find((p) => p.id === someConnection.provider)
+        Integrations.find((p) => p.id === someConnection.provider)
       )
+      setProvider(Integrations.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
-    //     case Providers.TAPD:
-    //       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) : []
@@ -807,10 +827,12 @@ const CreateBlueprint = (props) => {
     getDefaultEntities,
     setConfiguredConnection,
     setProvider,
+    setActiveProvider,
     setBoards,
     setDataEntities,
     setProjects,
-    testSelectedConnections
+    testSelectedConnections,
+    Integrations
   ])
 
   useEffect(() => {
@@ -818,35 +840,18 @@ const CreateBlueprint = (props) => {
     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')
-          )
-          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
-      }
+      const plugin = Integrations.find(
+        (p) => p.id === configuredConnection?.provider
+      )
+      setDataEntitiesList((dL) => (plugin ? plugin?.getDataEntities() : dL))
     }
   }, [
     configuredConnection,
     setActiveConnectionTab,
     setConfiguredBoard,
-    setConfiguredProject
+    setConfiguredProject,
+    Providers,
+    Integrations
   ])
 
   useEffect(() => {
@@ -1004,7 +1009,7 @@ const CreateBlueprint = (props) => {
     <>
       <div className='container'>
         <Nav />
-        <Sidebar />
+        <Sidebar key={Integrations} integrations={Integrations} />
         <Content>
           <main className='main'>
             <WorkflowStepsBar activeStep={activeStep} steps={blueprintSteps} />
@@ -1217,7 +1222,8 @@ const CreateBlueprint = (props) => {
       </div>
 
       <ConnectionDialog
-        integrations={integrationsData}
+        integrations={Integrations}
+        dataSourcesList={DataSourcesList}
         activeProvider={activeProvider}
         setProvider={setActiveProvider}
         setTestStatus={setTestStatus}
@@ -1252,6 +1258,9 @@ const CreateBlueprint = (props) => {
         testStatus={testStatus}
         testResponse={testResponse}
         allTestResponses={allTestResponses}
+        labels={ConnectionFormLabels}
+        placeholders={ConnectionFormPlaceholders}
+        tooltips={ConnectionFormTooltips}
       />
 
       <CodeInspector
diff --git a/config-ui/src/pages/blueprints/index.jsx b/config-ui/src/pages/blueprints/index.jsx
index f059a6f1..3beb030c 100644
--- a/config-ui/src/pages/blueprints/index.jsx
+++ b/config-ui/src/pages/blueprints/index.jsx
@@ -31,6 +31,7 @@ import {
   NonIdealState,
   Elevation
 } from '@blueprintjs/core'
+import useIntegrations from '@/hooks/useIntegrations'
 import usePipelineManager from '@/hooks/usePipelineManager'
 import useBlueprintManager from '@/hooks/useBlueprintManager'
 import useBlueprintValidation from '@/hooks/useBlueprintValidation'
@@ -39,13 +40,21 @@ import Nav from '@/components/Nav'
 import Sidebar from '@/components/Sidebar'
 import AppCrumbs from '@/components/Breadcrumbs'
 import Content from '@/components/Content'
-import AddBlueprintDialog from '@/components/blueprints/AddBlueprintDialog'
+// import AddBlueprintDialog from '@/components/blueprints/AddBlueprintDialog'
 import { ReactComponent as NoBlueprintsIcon } from '@/images/no-blueprints.svg'
 import BlueprintsGrid from '@/components/blueprints/BlueprintsGrid'
 
 const Blueprints = (props) => {
   const history = useHistory()
 
+  const {
+    registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    activeProvider,
+    setActiveProvider
+  } = useIntegrations()
+
   const {
     // eslint-disable-next-line no-unused-vars
     blueprint,
@@ -217,31 +226,31 @@ const Blueprints = (props) => {
     console.log('>>> ACTIVE/EXPANDED BLUEPRINT', activeBlueprint)
   }, [activeBlueprint, getSchedule, pipelines])
 
-  useEffect(() => {
-    if (draftBlueprint && draftBlueprint.id) {
-      console.log('>>> DRAFT = ', draftBlueprint)
-      setBlueprintName(draftBlueprint.name)
-      setCronConfig(
-        !isStandardCronPreset(draftBlueprint.cronConfig)
-          ? 'custom'
-          : draftBlueprint.cronConfig
-      )
-      setCustomCronConfig(draftBlueprint.cronConfig)
-      setBlueprintTasks(draftBlueprint.tasks)
-      setEnableBlueprint(draftBlueprint.enable)
-      setDetectedProviderTasks(draftBlueprint.tasks.flat())
-      setBlueprintDialogIsOpen(true)
-    }
-  }, [
-    draftBlueprint,
-    setBlueprintName,
-    setCronConfig,
-    isStandardCronPreset,
-    setBlueprintTasks,
-    setEnableBlueprint,
-    setCustomCronConfig,
-    setDetectedProviderTasks
-  ])
+  // useEffect(() => {
+  //   if (draftBlueprint && draftBlueprint.id) {
+  //     console.log('>>> DRAFT = ', draftBlueprint)
+  //     setBlueprintName(draftBlueprint.name)
+  //     setCronConfig(
+  //       !isStandardCronPreset(draftBlueprint.cronConfig)
+  //         ? 'custom'
+  //         : draftBlueprint.cronConfig
+  //     )
+  //     setCustomCronConfig(draftBlueprint.cronConfig)
+  //     setBlueprintTasks(draftBlueprint.tasks)
+  //     setEnableBlueprint(draftBlueprint.enable)
+  //     setDetectedProviderTasks(draftBlueprint.tasks.flat())
+  //     setBlueprintDialogIsOpen(true)
+  //   }
+  // }, [
+  //   draftBlueprint,
+  //   setBlueprintName,
+  //   setCronConfig,
+  //   isStandardCronPreset,
+  //   setBlueprintTasks,
+  //   setEnableBlueprint,
+  //   setCustomCronConfig,
+  //   setDetectedProviderTasks
+  // ])
 
   useEffect(() => {
     if (saveComplete?.id) {
@@ -340,7 +349,7 @@ const Blueprints = (props) => {
     <>
       <div className='container'>
         <Nav />
-        <Sidebar />
+        <Sidebar key={Integrations} integrations={Integrations} />
         <Content>
           <main className='main'>
             {/* <AppCrumbs
@@ -462,7 +471,7 @@ const Blueprints = (props) => {
         </Content>
       </div>
 
-      <AddBlueprintDialog
+      {/* <AddBlueprintDialog
         isLoading={isFetchingAllPipelines}
         isOpen={blueprintDialogIsOpen}
         setIsOpen={setBlueprintDialogIsOpen}
@@ -490,7 +499,7 @@ const Blueprints = (props) => {
         detectedProviders={detectedProviderTasks}
         getCronPreset={getCronPreset}
         getCronPresetByConfig={getCronPresetByConfig}
-      />
+      /> */}
     </>
   )
 }
diff --git a/config-ui/src/pages/configure/connections/AddConnection.jsx b/config-ui/src/pages/configure/connections/AddConnection.jsx
index 9242ac78..93603f14 100644
--- a/config-ui/src/pages/configure/connections/AddConnection.jsx
+++ b/config-ui/src/pages/configure/connections/AddConnection.jsx
@@ -23,15 +23,16 @@ import Sidebar from '@/components/Sidebar'
 import AppCrumbs from '@/components/Breadcrumbs'
 import Content from '@/components/Content'
 import ConnectionForm from '@/pages/configure/connections/ConnectionForm'
-import { integrationsData } from '@/data/integrations'
-import {
-  ProviderConnectionLimits,
-  ProviderFormLabels,
-  ProviderFormPlaceholders,
-  ProviderLabels,
-  Providers
-} from '@/data/Providers'
+// import { integrationsData } from '@/data/integrations'
+// import {
+//   ProviderConnectionLimits,
+//   ProviderFormLabels,
+//   ProviderFormPlaceholders,
+//   ProviderLabels,
+//   Providers
+// } from '@/data/Providers'
 
+import useIntegrations from '@/hooks/useIntegrations'
 import useConnectionManager from '@/hooks/useConnectionManager'
 import useConnectionValidation from '@/hooks/useConnectionValidation'
 
@@ -42,9 +43,23 @@ export default function AddConnection() {
   const history = useHistory()
   const { providerId } = useParams()
 
-  const [activeProvider, setActiveProvider] = useState(
-    integrationsData.find((p) => p.id === providerId)
-  )
+  const {
+    registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    activeProvider,
+    Providers,
+    ProviderFormLabels,
+    ProviderFormPlaceholders,
+    ProviderFormTooltips,
+    ProviderConnectionLimits,
+    setActiveProvider
+  } = useIntegrations()
+
+  // @todo: Replace with Integrations Hook
+  // const [activeProvider, setActiveProvider] = useState(
+  //   integrationsData.find((p) => p.id === providerId)
+  // )
 
   const {
     testConnection,
@@ -95,7 +110,7 @@ export default function AddConnection() {
   })
 
   const cancel = () => {
-    history.push(`/integrations/${activeProvider.id}`)
+    history.push(`/integrations/${activeProvider?.id}`)
   }
 
   // const resetForm = () => {
@@ -107,34 +122,35 @@ export default function AddConnection() {
   // }
 
   useEffect(() => {
+    // @todo: Cleanup Restricted Provider Names (Legacy Feature)
     // Selected Provider
-    if (activeProvider?.id) {
-      fetchAllConnections()
-      switch (activeProvider.id) {
-        case Providers.JENKINS:
-          // setName(ProviderLabels.JENKINS)
-          break
-        case Providers.GITHUB:
-        case Providers.GITLAB:
-        case Providers.JIRA:
-        case Providers.TAPD:
-        default:
-          setName('')
-          break
-      }
-    }
-  }, [activeProvider.id, fetchAllConnections, setName])
+    // if (activeProvider?.id) {
+    //   fetchAllConnections()
+    //   switch (activeProvider?.id) {
+    //     case Providers.JENKINS:
+    //       // setName(ProviderLabels.JENKINS)
+    //       break
+    //     case Providers.GITHUB:
+    //     case Providers.GITLAB:
+    //     case Providers.JIRA:
+    //     case Providers.TAPD:
+    //     default:
+    //       setName('')
+    //       break
+    //   }
+    // }
+  }, [activeProvider?.id, fetchAllConnections, setName])
 
   useEffect(() => {
     console.log('>>>> DETECTED PROVIDER = ', providerId)
-    setActiveProvider(integrationsData.find((p) => p.id === providerId))
-  }, [providerId])
+    setActiveProvider(Integrations.find((p) => p.id === providerId))
+  }, [providerId, setActiveProvider, Integrations])
 
   return (
     <>
       <div className='container'>
         <Nav />
-        <Sidebar />
+        <Sidebar key={Integrations} integrations={Integrations} />
         <Content>
           <main className='main'>
             <AppCrumbs
@@ -142,12 +158,12 @@ export default function AddConnection() {
                 { href: '/', icon: false, text: 'Dashboard' },
                 { href: '/integrations', icon: false, text: 'Connections' },
                 {
-                  href: `/integrations/${activeProvider.id}`,
+                  href: `/integrations/${activeProvider?.id}`,
                   icon: false,
-                  text: `${activeProvider.name}`
+                  text: `${activeProvider?.name}`
                 },
                 {
-                  href: `/connections/add/${activeProvider.id}`,
+                  href: `/connections/add/${activeProvider?.id}`,
                   icon: false,
                   text: 'Add Connection',
                   current: true
@@ -157,19 +173,25 @@ export default function AddConnection() {
             <div style={{ width: '100%' }}>
               <Link
                 style={{ float: 'right', marginLeft: '10px', color: '#777777' }}
-                to={`/integrations/${activeProvider.id}`}
+                to={`/integrations/${activeProvider?.id}`}
               >
                 <Icon icon='undo' size={16} /> Go Back
               </Link>
               <div style={{ display: 'flex' }}>
                 <div>
                   <span style={{ marginRight: '10px' }}>
-                    {activeProvider.icon}
+                    <img
+                      className='providerIconSvg'
+                      src={'/' + activeProvider?.icon}
+                      width={40}
+                      height={40}
+                      style={{ width: '40px', height: '40px' }}
+                    />
                   </span>
                 </div>
                 <div>
                   <h1 style={{ margin: 0 }}>
-                    {activeProvider.name} Add Connection
+                    {activeProvider?.name} Add Connection
                   </h1>
                   <p className='page-description'>
                     Create a new connection for this provider.
@@ -208,18 +230,11 @@ export default function AddConnection() {
                   allTestResponses={allTestResponses}
                   errors={errors}
                   showError={showError}
-                  authType={
-                    [
-                      Providers.JENKINS,
-                      Providers.JIRA,
-                      Providers.TAPD
-                    ].includes(activeProvider.id)
-                      ? 'plain'
-                      : 'token'
-                  }
+                  authType={activeProvider?.getAuthenticationType()}
                   sourceLimits={ProviderConnectionLimits}
-                  labels={ProviderFormLabels[activeProvider.id]}
-                  placeholders={ProviderFormPlaceholders[activeProvider.id]}
+                  labels={ProviderFormLabels[activeProvider?.id]}
+                  placeholders={ProviderFormPlaceholders[activeProvider?.id]}
+                  tooltips={ProviderFormTooltips[activeProvider?.id]}
                 />
               </div>
               {/* {validationErrors.length > 0 && (
diff --git a/config-ui/src/pages/configure/connections/ConfigureConnection.jsx b/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
index 434af61c..8baccbf8 100644
--- a/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
+++ b/config-ui/src/pages/configure/connections/ConfigureConnection.jsx
@@ -23,21 +23,24 @@ import Sidebar from '@/components/Sidebar'
 import AppCrumbs from '@/components/Breadcrumbs'
 import Content from '@/components/Content'
 import ContentLoader from '@/components/loaders/ContentLoader'
+import useIntegrations from '@/hooks/useIntegrations'
 import useConnectionManager from '@/hooks/useConnectionManager'
-import useSettingsManager from '@/hooks/useSettingsManager'
+// import useSettingsManager from '@/hooks/useSettingsManager'
 import useConnectionValidation from '@/hooks/useConnectionValidation'
 import ConnectionForm from '@/pages/configure/connections/ConnectionForm'
 import DeleteAction from '@/components/actions/DeleteAction'
 import DeleteConfirmationMessage from '@/components/actions/DeleteConfirmationMessage'
 
-import { integrationsData } from '@/data/integrations'
+// @todo: Replace with Integrations Hook
+// import { integrationsData } from '@/data/integrations'
 import { NullSettings } from '@/data/NullSettings'
-import {
-  ProviderConnectionLimits,
-  ProviderFormLabels,
-  ProviderFormPlaceholders,
-  Providers
-} from '@/data/Providers'
+// @todo: Replace with Integrations Hook
+// import {
+//   ProviderConnectionLimits,
+//   ProviderFormLabels,
+//   ProviderFormPlaceholders,
+//   Providers
+// } from '@/data/Providers'
 
 import '@/styles/integration.scss'
 import '@/styles/connections.scss'
@@ -47,9 +50,23 @@ export default function ConfigureConnection() {
   const history = useHistory()
   const { providerId, connectionId } = useParams()
 
-  const [activeProvider, setActiveProvider] = useState(
-    integrationsData.find((p) => p.id === providerId)
-  )
+  const {
+    registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    activeProvider,
+    Providers,
+    ProviderFormLabels,
+    ProviderFormPlaceholders,
+    ProviderFormTooltips,
+    ProviderConnectionLimits,
+    setActiveProvider
+  } = useIntegrations()
+
+  // @todo: Replace with Integrations Hook
+  // const [activeProvider, setActiveProvider] = useState(
+  //   integrationsData.find((p) => p.id === providerId)
+  // )
   // const [activeConnection, setActiveConnection] = useState(NullConnection)
   const [showConnectionSettings, setShowConnectionSettings] = useState(true)
   const [deleteId, setDeleteId] = useState(null)
@@ -97,17 +114,17 @@ export default function ConfigureConnection() {
     true
   )
 
-  const {
-    saveSettings,
-    // errors: settingsErrors,
-    isSaving
-    // isTesting,
-    // showError,
-  } = useSettingsManager({
-    activeProvider,
-    activeConnection,
-    settings
-  })
+  // const {
+  //   saveSettings,
+  //   // errors: settingsErrors,
+  //   isSaving
+  //   // isTesting,
+  //   // showError,
+  // } = useSettingsManager({
+  //   activeProvider,
+  //   activeConnection,
+  //   settings
+  // })
 
   const {
     validate,
@@ -125,42 +142,43 @@ export default function ConfigureConnection() {
   })
 
   const cancel = () => {
-    history.push(`/integrations/${activeProvider.id}`)
+    history.push(`/integrations/${activeProvider?.id}`)
   }
 
-  const renderProviderSettings = useCallback(
-    (providerId, activeProvider) => {
-      console.log('>>> RENDERING PROVIDER SETTINGS...')
-      let settingsComponent = null
-      if (activeProvider && activeProvider.settings) {
-        settingsComponent = activeProvider.settings({
-          activeProvider,
-          activeConnection,
-          isSaving,
-          isSavingConnection,
-          setSettings
-        })
-      } else {
-        // @todo create & display "fallback/empty settings" view
-        console.log(
-          '>> WARNING: NO PROVIDER SETTINGS RENDERED, PROVIDER = ',
-          activeProvider
-        )
-      }
-      return settingsComponent
-    },
-    [activeConnection, isSaving, isSavingConnection]
-  )
+  // @todo: cleanup unused render helper
+  // const renderProviderSettings = useCallback(
+  //   (providerId, activeProvider) => {
+  //     console.log('>>> RENDERING PROVIDER SETTINGS...')
+  //     let settingsComponent = null
+  //     if (activeProvider && activeProvider.settings) {
+  //       settingsComponent = activeProvider.settings({
+  //         activeProvider,
+  //         activeConnection,
+  //         isSaving,
+  //         isSavingConnection,
+  //         setSettings
+  //       })
+  //     } else {
+  //       // @todo create & display "fallback/empty settings" view
+  //       console.log(
+  //         '>> WARNING: NO PROVIDER SETTINGS RENDERED, PROVIDER = ',
+  //         activeProvider
+  //       )
+  //     }
+  //     return settingsComponent
+  //   },
+  //   [activeConnection, isSaving, isSavingConnection]
+  // )
 
   useEffect(() => {
     console.log('>>>> DETECTED PROVIDER ID = ', providerId)
     console.log('>>>> DETECTED CONNECTION ID = ', connectionId)
     if (connectionId && providerId) {
-      setActiveProvider(integrationsData.find((p) => p.id === providerId))
+      setActiveProvider(Integrations.find((p) => p.id === providerId))
     } else {
       console.log('NO PARAMS!')
     }
-  }, [connectionId, providerId])
+  }, [connectionId, providerId, Integrations, setActiveProvider])
 
   useEffect(() => {}, [settings])
 
@@ -179,7 +197,7 @@ export default function ConfigureConnection() {
     <>
       <div className='container'>
         <Nav />
-        <Sidebar />
+        <Sidebar key={Integrations} integrations={Integrations} />
         <Content>
           <main className='main'>
             <AppCrumbs
@@ -187,12 +205,12 @@ export default function ConfigureConnection() {
                 { href: '/', icon: false, text: 'Dashboard' },
                 { href: '/integrations', icon: false, text: 'Connections' },
                 {
-                  href: `/integrations/${activeProvider.id}`,
+                  href: `/integrations/${activeProvider?.id}`,
                   icon: false,
-                  text: `${activeProvider.name}`
+                  text: `${activeProvider?.name}`
                 },
                 {
-                  href: `/connections/configure/${activeProvider.id}/${activeConnection?.id}`,
+                  href: `/connections/configure/${activeProvider?.id}/${activeConnection?.id}`,
                   icon: false,
                   text: `${
                     activeConnection ? activeConnection.name : 'Configure'
@@ -209,7 +227,7 @@ export default function ConfigureConnection() {
                     marginLeft: '10px',
                     color: '#777777'
                   }}
-                  to={`/integrations/${activeProvider.id}`}
+                  to={`/integrations/${activeProvider?.id}`}
                 >
                   <Icon icon='fast-backward' size={16} /> Connection List
                 </Link>
@@ -217,7 +235,13 @@ export default function ConfigureConnection() {
               <div style={{ display: 'flex', justifyContent: 'flex-start' }}>
                 <div>
                   <span style={{ marginRight: '10px' }}>
-                    {activeProvider.icon}
+                    <img
+                      className='providerIconSvg'
+                      src={'/' + activeProvider?.icon}
+                      width={40}
+                      height={40}
+                      style={{ width: '40px', height: '40px' }}
+                    />
                   </span>
                 </div>
                 {isLoadingConnection && (
@@ -232,11 +256,11 @@ export default function ConfigureConnection() {
                       <h1 style={{ margin: 0 }}>
                         Manage{' '}
                         <strong style={{ fontWeight: 900 }}>
-                          {activeProvider.name}
+                          {activeProvider?.name}
                         </strong>{' '}
                         Settings
                       </h1>
-                      {activeProvider.multiConnection && (
+                      {activeProvider?.multiConnection && (
                         <div style={{ paddingTop: '5px' }}>
                           <DeleteAction
                             id={deleteId}
@@ -263,7 +287,7 @@ export default function ConfigureConnection() {
                           Providers.GITLAB,
                           Providers.JIRA,
                           Providers.TAPD
-                        ].includes(activeProvider.id) && (
+                        ].includes(activeProvider?.id) && (
                           <h2 style={{ margin: 0 }}>
                             #{activeConnection?.id} {activeConnection.name}
                           </h2>
@@ -337,21 +361,14 @@ export default function ConfigureConnection() {
                           allTestResponses={allTestResponses}
                           errors={errors}
                           showError={showConnectionError}
-                          authType={
-                            [
-                              Providers.JENKINS,
-                              Providers.JIRA,
-                              Providers.TAPD
-                            ].includes(activeProvider.id)
-                              ? 'plain'
-                              : 'token'
-                          }
+                          authType={activeProvider?.getAuthenticationType()}
                           showLimitWarning={false}
                           sourceLimits={ProviderConnectionLimits}
-                          labels={ProviderFormLabels[activeProvider.id]}
+                          labels={ProviderFormLabels[activeProvider?.id]}
                           placeholders={
-                            ProviderFormPlaceholders[activeProvider.id]
+                            ProviderFormPlaceholders[activeProvider?.id]
                           }
+                          tooltips={ProviderFormTooltips[activeProvider?.id]}
                         />
                       </div>
                     ) : (
diff --git a/config-ui/src/pages/configure/connections/ConnectionForm.jsx b/config-ui/src/pages/configure/connections/ConnectionForm.jsx
index 27141721..deb7eab0 100644
--- a/config-ui/src/pages/configure/connections/ConnectionForm.jsx
+++ b/config-ui/src/pages/configure/connections/ConnectionForm.jsx
@@ -15,7 +15,14 @@
  * limitations under the License.
  *
  */
-import React, { useEffect, useState, useCallback, useRef, useMemo } from 'react'
+import React, {
+  useEffect,
+  useState,
+  useCallback,
+  useRef,
+  useMemo,
+  useContext
+} from 'react'
 import {
   Button,
   Colors,
@@ -32,15 +39,33 @@ import {
   Intent,
   PopoverInteractionKind,
   NumericInput,
-  Switch
+  Switch,
+  Tooltip
 } from '@blueprintjs/core'
-import { Providers } from '@/data/Providers'
+import IntegrationsContext from '@/store/integrations-context'
+// import { Providers } from '@/data/Providers'
 import FormValidationErrors from '@/components/messages/FormValidationErrors'
 import InputValidationError from '@/components/validation/InputValidationError'
 
 import '@/styles/integration.scss'
 import '@/styles/connections.scss'
 
+const TooltipIcon = (props) => (
+  <Icon
+    icon='info-sign'
+    size={12}
+    style={{
+      float: 'left',
+      display: 'inline-block',
+      alignContent: 'center',
+      marginBottom: '4px',
+      marginLeft: '8px',
+      color: '#999'
+    }}
+    {...props}
+  />
+)
+
 export default function ConnectionForm(props) {
   const {
     isLocked = false,
@@ -80,13 +105,16 @@ export default function ConnectionForm(props) {
     authType = 'token',
     sourceLimits = {},
     showLimitWarning = true,
-    labels,
-    placeholders,
+    labels = {},
+    placeholders = {},
+    tooltips = {},
     enableActions = true,
     formGroupClassName = 'formGroup',
     showHeadline = true
   } = props
 
+  const { Providers } = useContext(IntegrationsContext)
+
   const connectionNameRef = useRef()
   const connectionEndpointRef = useRef()
   const connectionTokenRef = useRef()
@@ -240,7 +268,12 @@ export default function ConnectionForm(props) {
       console.log('>> PERSONAL ACCESS TOKENS ENTERED...', personalAccessTokens)
       syncPersonalAcessTokens()
     }
-  }, [activeProvider?.id, personalAccessTokens, syncPersonalAcessTokens])
+  }, [
+    activeProvider?.id,
+    personalAccessTokens,
+    syncPersonalAcessTokens,
+    Providers.GITHUB
+  ])
 
   useEffect(() => {
     console.log(
@@ -435,6 +468,15 @@ export default function ConnectionForm(props) {
             >
               <Label>
                 {labels ? labels.token : <>Basic&nbsp;Auth&nbsp;Token</>}
+                {tooltips?.token ? (
+                  <Tooltip
+                    className='connection-tooltip'
+                    intent={Intent.PRIMARY}
+                    content={tooltips?.token}
+                  >
+                    <TooltipIcon />
+                  </Tooltip>
+                ) : null}
                 <span className='requiredStar'>*</span>
               </Label>
               {[Providers.GITHUB].includes(activeProvider?.id) ? (
@@ -716,6 +758,15 @@ export default function ConnectionForm(props) {
               >
                 <Label>
                   {labels ? labels.password : <>Password</>}
+                  {tooltips?.password ? (
+                    <Tooltip
+                      className='connection-tooltip'
+                      intent={Intent.PRIMARY}
+                      content={tooltips?.password}
+                    >
+                      <TooltipIcon />
+                    </Tooltip>
+                  ) : null}
                   <span className='requiredStar'>*</span>
                 </Label>
                 <InputGroup
@@ -797,6 +848,15 @@ export default function ConnectionForm(props) {
               >
                 <Label>
                   {labels ? labels.rateLimitPerHour : <>Rate&nbsp;Limit</>}
+                  {tooltips?.rateLimitPerHour ? (
+                    <Tooltip
+                      className='connection-tooltip'
+                      intent={Intent.PRIMARY}
+                      content={tooltips?.rateLimitPerHour}
+                    >
+                      <TooltipIcon />
+                    </Tooltip>
+                  ) : null}
                 </Label>
                 <div
                   className='ratelimit-options'
diff --git a/config-ui/src/pages/configure/integration/index.jsx b/config-ui/src/pages/configure/integration/index.jsx
index 80ee4d96..ef3ce932 100644
--- a/config-ui/src/pages/configure/integration/index.jsx
+++ b/config-ui/src/pages/configure/integration/index.jsx
@@ -17,11 +17,14 @@
  */
 import React, { useEffect, useState } from 'react'
 import { useHistory } from 'react-router-dom'
+import { Colors, Icon } from '@blueprintjs/core'
 import Nav from '@/components/Nav'
 import Sidebar from '@/components/Sidebar'
 import AppCrumbs from '@/components/Breadcrumbs'
 import Content from '@/components/Content'
-import { integrationsData } from '@/data/integrations'
+// @todo: replace with Integrations Hook
+// import { integrationsData } from '@/data/integrations'
+import useIntegrations from '@/hooks/useIntegrations'
 import { ReactComponent as WebHookProviderIcon } from '@/images/integrations/incoming-webhook.svg'
 
 import '@/styles/integration.scss'
@@ -29,30 +32,37 @@ import '@/styles/integration.scss'
 export default function Integration() {
   const history = useHistory()
 
-  const [activeProvider, setActiveProvider] = useState(integrationsData[0])
+  const {
+    registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    activeProvider,
+    setActiveProvider
+  } = useIntegrations()
+  // const [activeProvider, setActiveProvider] = useState(integrationsData[0])
 
   const handleProviderClick = (providerId) => {
-    const theProvider = integrationsData.find((p) => p.id === providerId)
+    const theProvider = Plugins.find((p) => p.id === providerId)
     if (theProvider) {
       setActiveProvider(theProvider)
       history.push(`/integrations/${theProvider.id}`)
     } else {
-      setActiveProvider(integrationsData[0])
+      setActiveProvider(Plugins.find[0])
     }
   }
 
-  useEffect(() => {
-    // Selected Provider
-    console.log(activeProvider)
-  }, [activeProvider, history])
+  // useEffect(() => {
+  //   // Selected Provider
+  //   console.log(activeProvider)
+  // }, [activeProvider, history])
 
-  useEffect(() => {}, [])
+  // useEffect(() => {}, [])
 
   return (
     <>
       <div className='container'>
         <Nav />
-        <Sidebar />
+        <Sidebar key={Integrations} integrations={Integrations} />
         <Content>
           <main className='main'>
             <AppCrumbs
@@ -69,18 +79,50 @@ export default function Integration() {
             <div className='headlineContainer'>
               <h1>Data Connections</h1>
               <p className='page-description'>
-                {integrationsData.length} connections are available for data
+                {Integrations.length} connections are available for data
                 collection.
               </p>
             </div>
             <div className='integrationProviders'>
-              {integrationsData.map((provider) => (
+              {Integrations.map((provider) => (
                 <div
                   className='iProvider'
                   key={`provider-${provider.id}`}
                   onClick={() => handleProviderClick(provider.id)}
+                  style={{ position: 'relative' }}
                 >
-                  <div className='providerIcon'>{provider.iconDashboard}</div>
+                  {provider?.private && (
+                    <span
+                      style={{
+                        width: '20px',
+                        height: '20px',
+                        position: 'absolute',
+                        top: '-5px',
+                        right: '-5px',
+                        textAlign: 'center',
+                        lineHeight: '16px',
+                        backgroundColor: '#fff',
+                        display: 'block',
+                        borderRadius: '50%',
+                        border: '1px solid #eee'
+                      }}
+                    >
+                      <Icon
+                        icon='lock'
+                        size={10}
+                        style={{ color: Colors.RED5 }}
+                      />
+                    </span>
+                  )}
+                  <div className='providerIcon'>
+                    <img
+                      className='providerIconSvg'
+                      src={provider.icon}
+                      width={40}
+                      height={40}
+                      style={{ width: '40px', height: '40px' }}
+                    />
+                  </div>
                   <div className='providerName'>
                     {provider.name}{' '}
                     {provider.isBeta && (
diff --git a/config-ui/src/pages/configure/integration/manage.jsx b/config-ui/src/pages/configure/integration/manage.jsx
index aca63b6d..84379cc8 100644
--- a/config-ui/src/pages/configure/integration/manage.jsx
+++ b/config-ui/src/pages/configure/integration/manage.jsx
@@ -33,9 +33,10 @@ import Sidebar from '@/components/Sidebar'
 import AppCrumbs from '@/components/Breadcrumbs'
 import Content from '@/components/Content'
 import { ToastNotification } from '@/components/Toast'
+import useIntegrations from '@/hooks/useIntegrations'
 import useConnectionManager from '@/hooks/useConnectionManager'
 
-import { integrationsData } from '@/data/integrations'
+// import { integrationsData } from '@/data/integrations'
 import DeleteAction from '@/components/actions/DeleteAction'
 import DeleteConfirmationMessage from '@/components/actions/DeleteConfirmationMessage'
 import ContentLoader from '@/components/loaders/ContentLoader'
@@ -47,10 +48,18 @@ export default function ManageIntegration() {
 
   const { providerId } = useParams()
 
-  const [integrations, setIntegrations] = useState(integrationsData)
-  const [activeProvider, setActiveProvider] = useState(
-    integrations.find((p) => p.id === providerId)
-  )
+  const {
+    registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    activeProvider,
+    setActiveProvider
+  } = useIntegrations()
+
+  // const [integrations, setIntegrations] = useState(integrationsData)
+  // const [activeProvider, setActiveProvider] = useState(
+  //   integrations.find((p) => p.id === providerId)
+  // )
   const [isRunningDelete, setIsRunningDelete] = useState(false)
 
   const [deleteId, setDeleteId] = useState(null)
@@ -65,13 +74,14 @@ export default function ManageIntegration() {
     fetchAllConnections,
     errors,
     deleteComplete,
-    testAllConnections
+    testAllConnections,
+    setProvider: setConnectionProvider
   } = useConnectionManager({
     activeProvider
   })
 
   const addConnection = () => {
-    history.push(`/connections/add/${activeProvider.id}`)
+    history.push(`/connections/add/${activeProvider?.id}`)
   }
 
   const editConnection = (connection, e) => {
@@ -81,13 +91,13 @@ export default function ManageIntegration() {
       (!e.target.classList.contains('cell-actions') ||
         !e.target.classList.contains('actions-link'))
     ) {
-      history.push(`/connections/edit/${activeProvider.id}/${connection.id}`)
+      history.push(`/connections/edit/${activeProvider?.id}/${connection.id}`)
     }
   }
 
   const configureConnection = (connection) => {
     const { id, ID, endpoint } = connection
-    history.push(`/connections/configure/${activeProvider.id}/${id || ID}`)
+    history.push(`/connections/configure/${activeProvider?.id}/${id || ID}`)
     console.log('>> editing/modifying connection: ', id, endpoint)
   }
 
@@ -140,14 +150,16 @@ export default function ManageIntegration() {
   }
 
   useEffect(() => {
-    fetchAllConnections(false)
+    if (activeProvider) {
+      fetchAllConnections(false)
+    }
   }, [activeProvider, fetchAllConnections])
 
   useEffect(() => {
     console.log('>> ACTIVE PROVIDER = ', providerId)
-    setIntegrations(integrations)
-    setActiveProvider(integrations.find((p) => p.id === providerId))
-  }, [integrations, providerId])
+    setActiveProvider(Integrations.find((p) => p.id === providerId))
+    setConnectionProvider(Integrations.find((p) => p.id === providerId))
+  }, [Integrations, providerId, setActiveProvider, setConnectionProvider])
 
   useEffect(() => {
     let flushTimeout
@@ -171,7 +183,7 @@ export default function ManageIntegration() {
     <>
       <div className='container'>
         <Nav />
-        <Sidebar />
+        <Sidebar key={Integrations} integrations={Integrations} />
         <Content>
           <main className='main'>
             <AppCrumbs
@@ -179,9 +191,9 @@ export default function ManageIntegration() {
                 { href: '/', icon: false, text: 'Dashboard' },
                 { href: '/integrations', icon: false, text: 'Connections' },
                 {
-                  href: `/integrations/${activeProvider.id}`,
+                  href: `/integrations/${activeProvider?.id}`,
                   icon: false,
-                  text: `${activeProvider.name}`,
+                  text: `${activeProvider?.name}`,
                   current: true
                 }
               ]}
@@ -196,13 +208,19 @@ export default function ManageIntegration() {
               <div style={{ display: 'flex' }}>
                 <div>
                   <span style={{ marginRight: '10px' }}>
-                    {activeProvider.icon}
+                    <img
+                      className='providerIconSvg'
+                      src={'/' + activeProvider?.icon}
+                      width={40}
+                      height={40}
+                      style={{ width: '40px', height: '40px' }}
+                    />
                   </span>
                 </div>
                 <div>
                   <h1 style={{ margin: 0 }}>
-                    {activeProvider.name} Connections{' '}
-                    {activeProvider.isBeta && (
+                    {activeProvider?.name} Connections{' '}
+                    {activeProvider?.isBeta && (
                       <>
                         <sup>(beta)</sup>
                       </>
@@ -282,6 +300,7 @@ export default function ManageIntegration() {
                     </p>
                     <p>
                       <Button
+                        disabled={connectionLimitReached}
                         onClick={addConnection}
                         rightIcon='add'
                         intent='primary'
@@ -461,7 +480,7 @@ export default function ManageIntegration() {
                         ))}
                       </tbody>
                     </table>
-                    {connectionLimitReached && (
+                    {!!connectionLimitReached && (
                       <p
                         style={{
                           margin: 0,
@@ -490,7 +509,7 @@ export default function ManageIntegration() {
                     }}
                   >
                     Fetched <strong>{connections.length}</strong> connection(s)
-                    from Lake API for <strong>{activeProvider.name}</strong>
+                    from Lake API for <strong>{activeProvider?.name}</strong>
                   </p>
                 </>
               )}
diff --git a/config-ui/src/pages/configure/settings/github.jsx b/config-ui/src/pages/configure/settings/github.jsx
index b9ef32d9..9ab9a766 100644
--- a/config-ui/src/pages/configure/settings/github.jsx
+++ b/config-ui/src/pages/configure/settings/github.jsx
@@ -37,6 +37,8 @@ import '@/styles/connections.scss'
 
 export default function GithubSettings(props) {
   const {
+    Providers,
+    ProviderLabels,
     provider,
     connection,
     entities = [],
diff --git a/config-ui/src/pages/configure/settings/jira.jsx b/config-ui/src/pages/configure/settings/jira.jsx
index 8c397802..491963db 100644
--- a/config-ui/src/pages/configure/settings/jira.jsx
+++ b/config-ui/src/pages/configure/settings/jira.jsx
@@ -53,6 +53,8 @@ const createTypeMapObject = (customType, standardType) => {
 
 export default function JiraSettings(props) {
   const {
+    Providers,
+    ProviderLabels,
     provider,
     connection,
     issueTypes = [],
diff --git a/config-ui/src/pages/configure/settings/tapd.jsx b/config-ui/src/pages/configure/settings/tapd.jsx
index 3d472a98..a98b9af1 100644
--- a/config-ui/src/pages/configure/settings/tapd.jsx
+++ b/config-ui/src/pages/configure/settings/tapd.jsx
@@ -24,6 +24,8 @@ import '@/styles/connections.scss'
 
 export default function TapdSettings(props) {
   const {
+    Providers,
+    ProviderLabels,
     provider,
     connection,
     entities = [],
diff --git a/config-ui/src/registry/plugins/ae.json b/config-ui/src/registry/plugins/ae.json
new file mode 100644
index 00000000..ec9b770e
--- /dev/null
+++ b/config-ui/src/registry/plugins/ae.json
@@ -0,0 +1,13 @@
+{
+  "id": "ae",
+  "name": "AE",
+  "type": "plugin",
+  "enabled": true,
+  "multiConnection": false,
+  "isBeta": false,
+  "isProvider": false,
+  "icon": "src/images/integrations/ae.svg",
+  "private": false,
+  "connection": null,
+  "entities": []
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/azure.json b/config-ui/src/registry/plugins/azure.json
new file mode 100644
index 00000000..8e796718
--- /dev/null
+++ b/config-ui/src/registry/plugins/azure.json
@@ -0,0 +1,53 @@
+{
+  "id": "azure",
+  "name": "Azure CI",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "connectionLimit": 0,
+  "isBeta": false,
+  "isProvider": true,
+  "icon": "src/images/integrations/azure.svg",
+  "private": false,
+  "connection": {
+    "authentication": "plain",
+    "fields": {
+      "name": { "enable": true, "required": true, "readonly": false },
+      "endpoint": { },
+      "proxy": { },
+      "username": { },
+      "password": { },
+      "rateLimitPerHour": { }
+    },
+    "labels": {
+      "name": "Connection Name",
+      "endpoint": "Endpoint URL",
+      "proxy": "Proxy URL",
+      "username": "Username",
+      "password": "Password",
+      "rateLimitPerHour": "Rate Limit (per hour)"
+    },
+    "placeholders": {
+      "name": "eg. Azure CI",
+      "endpoint": "URL eg. https://api.azure.com/",
+      "proxy": "eg. http://proxy.localhost:8080",
+      "username": "eg. admin",
+      "password": "eg. ************",
+      "rateLimitPerHour": "1000"
+    },
+    "tooltips": {
+      "rateLimitPerHour": "Rate Limit requests per hour,\nEnter a numeric value > 0 to enable."
+    }
+  },
+  "entities": ["CICD"],
+  "transformations": {
+    "scopes": {
+      "options": {
+      }
+    },
+    "default": {
+      "productionPattern": "",
+      "deploymentPattern": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/bitbucket.json b/config-ui/src/registry/plugins/bitbucket.json
new file mode 100644
index 00000000..9f159a56
--- /dev/null
+++ b/config-ui/src/registry/plugins/bitbucket.json
@@ -0,0 +1,53 @@
+{
+  "id": "bitbucket",
+  "name": "Bitbucket",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "connectionLimit": 0,
+  "isBeta": false,
+  "isProvider": true,
+  "icon": "src/images/integrations/bitbucket.svg",
+  "private": false,
+  "connection": {
+    "authentication": "plain",
+    "fields": {
+      "name": { "enable": true, "required": true, "readonly": false },
+      "endpoint": { },
+      "proxy": { },
+      "username": { },
+      "password": { },
+      "rateLimitPerHour": { }
+    },
+    "labels": {
+      "name": "Connection Name",
+      "endpoint": "Endpoint URL",
+      "proxy": "Proxy URL",
+      "username": "Username",
+      "password": "Password",
+      "rateLimitPerHour": "Rate Limit (per hour)"
+    },
+    "placeholders": {
+      "name": "eg. Bitbucket",
+      "endpoint": "URL eg. https://api.bitbucket.io/",
+      "proxy": "eg. http://proxy.localhost:8080",
+      "username": "eg. admin",
+      "password": "eg. ************",
+      "rateLimitPerHour": "1000"
+    },
+    "tooltips": {
+      "rateLimitPerHour": "Rate Limit requests per hour,\nEnter a numeric value > 0 to enable."
+    }
+  },
+  "entities": ["CICD"],
+  "transformations": {
+    "scopes": {
+      "options": {
+      }
+    },
+    "default": {
+      "productionPattern": "",
+      "deploymentPattern": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/dbt.json b/config-ui/src/registry/plugins/dbt.json
new file mode 100644
index 00000000..900b7446
--- /dev/null
+++ b/config-ui/src/registry/plugins/dbt.json
@@ -0,0 +1,12 @@
+{
+  "id": "dbt",
+  "name": "DBT",
+  "type": "pipeline",
+  "enabled": true,
+  "multiConnection": false,
+  "isBeta": false,
+  "isProvider": false,
+  "icon": "src/images/integrations/dbt.svg",
+  "private": false,
+  "connection": null
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/dora.json b/config-ui/src/registry/plugins/dora.json
new file mode 100644
index 00000000..8fef1081
--- /dev/null
+++ b/config-ui/src/registry/plugins/dora.json
@@ -0,0 +1,12 @@
+{
+  "id": "dora",
+  "name": "DORA",
+  "type": "webhook",
+  "enabled": true,
+  "multiConnection": false,
+  "isBeta": false,
+  "isProvider": false,
+  "icon": "src/images/integrations/dora.svg",
+  "private": false,
+  "connection": null
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/feishu.json b/config-ui/src/registry/plugins/feishu.json
new file mode 100644
index 00000000..c7a704fe
--- /dev/null
+++ b/config-ui/src/registry/plugins/feishu.json
@@ -0,0 +1,12 @@
+{
+  "id": "feishu",
+  "name": "Feishu",
+  "type": "pipeline",
+  "enabled": true,
+  "multiConnection": false,
+  "isBeta": false,
+  "isProvider": false,
+  "icon": "src/images/integrations/feishu.svg",
+  "private": false,
+  "connection": null
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/gitee.json b/config-ui/src/registry/plugins/gitee.json
new file mode 100644
index 00000000..575d97e6
--- /dev/null
+++ b/config-ui/src/registry/plugins/gitee.json
@@ -0,0 +1,56 @@
+{
+  "id": "gitee",
+  "name": "Gitee",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "connectionLimit": 0,
+  "isBeta": false,
+  "isProvider": true,
+  "icon": "src/images/integrations/gitee.svg",
+  "private": false,
+  "connection": {
+    "authentication": "token",
+    "fields": {
+      "name": { "enable": true, "required": true, "readonly": false },
+      "endpoint": { },
+      "proxy": { },
+      "username": { },
+      "password": { },
+      "token": { },
+      "rateLimitPerHour": { }
+    },
+    "labels": {
+      "name": "Connection Name",
+      "endpoint": "Endpoint URL",
+      "proxy": "Proxy URL",
+      "username": "Username",
+      "password": "Password",
+      "token": "Access Token",
+      "rateLimitPerHour": "Rate Limit (per hour)"
+    },
+    "placeholders": {
+      "name": "eg. Gitee",
+      "endpoint": "URL eg. https://api.gitee.io/",
+      "proxy": "eg. http://proxy.localhost:8080",
+      "username": "eg. admin",
+      "password": "eg. ************",
+      "token": "eg. ff9d1ad0e5c04f1f98fa",
+      "rateLimitPerHour": "1000"
+    },
+    "tooltips": {
+      "rateLimitPerHour": "Rate Limit requests per hour,\nEnter a numeric value > 0 to enable."
+    }
+  },
+  "entities": ["CICD"],
+  "transformations": {
+    "scopes": {
+      "options": {
+      }
+    },
+    "default": {
+      "productionPattern": "",
+      "deploymentPattern": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/gitextractor.json b/config-ui/src/registry/plugins/gitextractor.json
new file mode 100644
index 00000000..0060a841
--- /dev/null
+++ b/config-ui/src/registry/plugins/gitextractor.json
@@ -0,0 +1,12 @@
+{
+  "id": "gitextractor",
+  "name": "GitExtractor",
+  "type": "pipeline",
+  "enabled": true,
+  "multiConnection": false,
+  "isBeta": false,
+  "isProvider": false,
+  "icon": "src/images/integrations/gitextractor.svg",
+  "private": false,
+  "connection": null
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/github.json b/config-ui/src/registry/plugins/github.json
new file mode 100644
index 00000000..37e6e5b9
--- /dev/null
+++ b/config-ui/src/registry/plugins/github.json
@@ -0,0 +1,63 @@
+{
+  "id": "github",
+  "name": "GitHub",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "connectionLimit": 0,
+  "isBeta": false,
+  "isProvider": true,
+  "icon": "src/images/integrations/github.svg",
+  "private": false,
+  "connection": {
+    "authentication": "token",
+    "fields": {
+      "name": { "enable": true, "required": true, "readonly": false },
+      "endpoint": { },
+      "proxy": { },
+      "token": { },
+      "rateLimitPerHour": { }
+    },
+    "labels": {
+        "name": "Connection Name",
+        "endpoint": "Endpoint URL",
+        "proxy": "Proxy URL",
+        "token": "Basic Auth Token",
+        "rateLimitPerHour": "Rate Limit (per hour)"
+    },
+    "placeholders": {
+        "name": "eg. GitHub",
+        "endpoint": "eg. https://api.github.com/",
+        "proxy": "eg. http://proxy.localhost:8080",
+        "token": "eg. 4c5cbdb62c165e2b3d18, 40008ebccff9837bb8d2",
+        "rateLimitPerHour": "1000"
+    },
+    "tooltips": {
+      "token": "Due to Github's rate limit, input more tokens, \ncomma separated, to accelerate data collection.",
+      "rateLimitPerHour": "Rate Limit requests per hour,\nEnter a numeric value > 0 to enable."
+    }
+ },
+ "entities": ["CODE", "TICKET", "CROSS"],
+ "transformations": {
+    "scopes": {
+      "options": {
+        "owner": null,
+        "repo": null
+      }
+    },
+    "default": {
+      "prType": "",
+      "prComponent": "",
+      "prBodyClosePattern": "",
+      "issueSeverity": "",
+      "issueComponent": "",
+      "issuePriority": "",
+      "issueTypeRequirement": "",
+      "issueTypeBug": "",
+      "issueTypeIncident": "",
+      "refdiff": null,
+      "productionPattern": "",
+      "deploymentPattern": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/gitlab.json b/config-ui/src/registry/plugins/gitlab.json
new file mode 100644
index 00000000..4e95e87e
--- /dev/null
+++ b/config-ui/src/registry/plugins/gitlab.json
@@ -0,0 +1,52 @@
+{
+  "id": "gitlab",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "connectionLimit": 0,
+  "isBeta": false,
+  "isProvider": true,
+  "name": "GitLab",
+  "icon": "src/images/integrations/gitlab.svg",
+  "private": false,
+  "connection": {
+    "authentication": "token",
+    "fields": {
+      "name": { "enable": true, "required": true, "readonly": false },
+      "endpoint": { },
+      "proxy": { },
+      "token": { },
+      "rateLimitPerHour": { }
+    },
+    "labels": {
+      "name": "Connection Name",
+      "endpoint": "Endpoint URL",
+      "proxy": "Proxy URL",
+      "token": "Access Token",
+      "rateLimitPerHour": "Rate Limit (per hour)"
+    },
+    "placeholders": {
+      "name": "eg. GitLab",
+      "endpoint": "eg. https://gitlab.com/api/v4/",
+      "proxy": "eg. http://proxy.localhost:8080",
+      "token": "eg. ff9d1ad0e5c04f1f98fa",
+      "rateLimitPerHour": "1000"
+    },
+    "tooltips": {
+      "rateLimitPerHour": "Rate Limit requests per hour,\nEnter a numeric value > 0 to enable."
+    }
+  },
+  "entities": ["CODE", "TICKET", "CROSS", "CICD"],
+  "transformations": {
+    "scopes": {
+      "options": {
+        "projectId": null,
+        "title": null
+      }
+    },
+    "default": {
+      "productionPattern": "",
+      "deploymentPattern": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/jenkins.json b/config-ui/src/registry/plugins/jenkins.json
new file mode 100644
index 00000000..806e82e9
--- /dev/null
+++ b/config-ui/src/registry/plugins/jenkins.json
@@ -0,0 +1,54 @@
+{
+  "id": "jenkins",
+  "name": "Jenkins",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "connectionLimit": 0,
+  "isBeta": false,
+  "isProvider": true,
+  "icon": "src/images/integrations/jenkins.svg",
+  "private": false,
+  "connection": {
+    "authentication": "plain",
+    "fields": {
+      "name": { "enable": true, "required": true, "readonly": false },
+      "endpoint": { },
+      "proxy": { },
+      "username": { },
+      "password": { },
+      "rateLimitPerHour": { }
+    },
+    "labels": {
+      "name": "Connection Name",
+      "endpoint": "Endpoint URL",
+      "proxy": "Proxy URL",
+      "username": "Username",
+      "password": "Password",
+      "rateLimitPerHour": "Rate Limit (per hour)"
+    },
+    "placeholders": {
+      "name": "eg. Jenkins",
+      "endpoint": "URL eg. https://api.jenkins.io/",
+      "proxy": "eg. http://proxy.localhost:8080",
+      "username": "eg. admin",
+      "password": "eg. ************",
+      "rateLimitPerHour": "1000"
+    },
+    "tooltips": {
+      "rateLimitPerHour": "Rate Limit requests per hour,\nEnter a numeric value > 0 to enable."
+    }
+  },
+  "entities": ["CICD"],
+  "transformations": {
+    "scopes": {
+      "options": {
+        "jobName": null
+      }
+    },
+    "default": {
+      "productionPattern": "",
+      "deploymentPattern": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/jira.json b/config-ui/src/registry/plugins/jira.json
new file mode 100644
index 00000000..3cce3141
--- /dev/null
+++ b/config-ui/src/registry/plugins/jira.json
@@ -0,0 +1,65 @@
+{
+  "id": "jira",
+  "name": "JIRA",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "connectionLimit": 0,
+  "isBeta": false,
+  "isProvider": true,
+  "icon": "src/images/integrations/jira.svg",
+  "private": false,
+  "connection": {
+    "authentication": "plain",
+    "fields": {
+      "name": { 
+      },
+      "endpoint": { },
+      "username": { },
+      "password": { },
+      "proxy": { },
+      "rateLimitPerHour": { }
+   },
+   "labels": {
+      "name": "Connection Name",
+      "endpoint": "Endpoint URL",
+      "username": "Username / E-mail",
+      "password": "Password",
+      "proxy": "Proxy URL",
+      "rateLimitPerHour": "Rate Limit (per hour)"
+   },
+   "placeholders": {
+    "name": "eg. JIRA",
+    "endpoint": "eg. https://your-domain.atlassian.net/rest/",
+    "username": "eg. admin",
+    "password": "eg. ************",
+    "proxy": "eg. http://proxy.localhost:8080",
+    "rateLimit": "1000"
+  },
+  "tooltips": {
+    "password": "If you are using JIRA Cloud or JIRA Server,\nyour API Token should be used as password.",
+    "rateLimitPerHour": "Rate Limit requests per hour,\nEnter a numeric value > 0 to enable."
+    
+  }
+ },
+ "entities": ["TICKET", "CROSS"],
+ "transformations": {
+    "scopes": {
+      "options": {
+        "boardId": null,
+        "title": null
+      }
+    },
+    "default": {
+      "epicKeyField": "",
+      "typeMappings": {},
+      "storyPointField": "",
+      "remotelinkCommitShaPattern": "",
+      "bugTags": [],
+      "incidentTags": [],
+      "requirementTags": [],
+      "productionPattern": "",
+      "deploymentPattern": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/refdiff.json b/config-ui/src/registry/plugins/refdiff.json
new file mode 100644
index 00000000..02708925
--- /dev/null
+++ b/config-ui/src/registry/plugins/refdiff.json
@@ -0,0 +1,12 @@
+{
+  "id": "refdiff",
+  "name": "RefDiff",
+  "type": "pipeline",
+  "enabled": true,
+  "multiConnection": false,
+  "isBeta": false,
+  "isProvider": false,
+  "icon": "src/images/integrations/refdiff.svg",
+  "private": false,
+  "connection": null
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/starrocks.json b/config-ui/src/registry/plugins/starrocks.json
new file mode 100644
index 00000000..444b5a89
--- /dev/null
+++ b/config-ui/src/registry/plugins/starrocks.json
@@ -0,0 +1,12 @@
+{
+  "id": "starrocks",
+  "name": "Starrocks",
+  "type": "pipeline",
+  "enabled": true,
+  "multiConnection": false,
+  "isBeta": false,
+  "isProvider": false,
+  "icon": "src/images/integrations/starrocks.svg",
+  "private": false,
+  "connection": null
+}
\ No newline at end of file
diff --git a/config-ui/src/registry/plugins/tapd.json b/config-ui/src/registry/plugins/tapd.json
new file mode 100644
index 00000000..9a30999f
--- /dev/null
+++ b/config-ui/src/registry/plugins/tapd.json
@@ -0,0 +1,55 @@
+{
+  "id": "tapd",
+  "name": "TAPD",
+  "type": "integration",
+  "enabled": true,
+  "multiConnection": true,
+  "connectionLimit": 0,
+  "isBeta": true,
+  "isProvider": true,
+  "icon": "src/images/integrations/tapd.svg",
+  "private": false,
+  "connection": {
+    "authentication": "plain",
+    "fields": {
+      "name": { "enable": true, "required": true, "readonly": false },
+      "endpoint": { },
+      "proxy": { },
+      "username": { },
+      "password": { },
+      "rateLimitPerHour": { }
+    },
+    "labels": {
+      "name": "Connection Name",
+      "endpoint": "Endpoint URL",
+      "proxy": "Proxy URL",
+      "username": "Username",
+      "password": "Password",
+      "rateLimitPerHour": "Rate Limit (per hour)"
+    },
+    "placeholders": {
+      "name": "eg. Tapd",
+      "endpoint": "URL eg. https://api.tapd.cn/",
+      "proxy": "eg. http://proxy.localhost:8080",
+      "username": "eg. admin",
+      "password": "eg. ************",
+      "rateLimit": "1000"
+    },
+    "tooltips": {
+    }
+  },
+  "entities": ["CODE", "TICKET"],
+  "transformations": {
+    "scopes": {
+      "options": {
+      }
+    },
+    "default": {
+      "issueTypeRequirement": "",
+      "issueTypeBug": "",
+      "issueTypeIncident": "",
+      "productionPattern": "",
+      "deploymentPattern": ""
+    }
+  }
+}
\ No newline at end of file
diff --git a/config-ui/src/store/integrations-context.jsx b/config-ui/src/store/integrations-context.jsx
new file mode 100644
index 00000000..37b0a133
--- /dev/null
+++ b/config-ui/src/store/integrations-context.jsx
@@ -0,0 +1,73 @@
+/*
+ * 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, { useState } from 'react'
+import useIntegrations from '@/hooks/useIntegrations'
+
+const IntegrationsContext = React.createContext({
+  registry: {},
+  plugins: {},
+  integrations: {},
+  activeProvider: null,
+  Providers: {},
+  ProviderIcons: {},
+  ProviderFormLabels: {},
+  ProviderFormPlaceholders: {},
+  ProviderConnectionLimits: {},
+  ProviderTransformations: {},
+  setActiveProvider: () => {}
+})
+
+export const IntegrationsContextProvider = (props) => {
+  const {
+    registry: Registry,
+    plugins: Plugins,
+    integrations: Integrations,
+    activeProvider,
+    Providers,
+    ProviderLabels,
+    ProviderIcons,
+    ProviderFormLabels,
+    ProviderFormPlaceholders,
+    ProviderConnectionLimits,
+    ProviderTransformations,
+    setActiveProvider
+  } = useIntegrations()
+
+  const contextValue = {
+    Registry,
+    Plugins,
+    Integrations,
+    activeProvider,
+    Providers,
+    ProviderLabels,
+    ProviderIcons,
+    ProviderFormLabels,
+    ProviderFormPlaceholders,
+    ProviderConnectionLimits,
+    ProviderTransformations,
+    setActiveProvider
+  }
+
+  return (
+    <IntegrationsContext.Provider value={contextValue}>
+      {props.children}
+    </IntegrationsContext.Provider>
+  )
+}
+
+export default IntegrationsContext