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 2023/01/17 03:05:53 UTC

[incubator-devlake] branch main updated: refactor(config-ui): simplify the definition of plugins (#4214)

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 782d7c1e2 refactor(config-ui): simplify the definition of plugins (#4214)
782d7c1e2 is described below

commit 782d7c1e2c2d0384c50ad4103f04f9d2c91eca63
Author: 青湛 <0x...@gmail.com>
AuthorDate: Tue Jan 17 11:05:48 2023 +0800

    refactor(config-ui): simplify the definition of plugins (#4214)
    
    * feat(config-ui): encapsulate base plugin configuration
    
    * refactor(config-ui): simplified plugin configuration definition
    
    * refactor(config-ui): delete the definition of plugins
    
    * refactor(config-ui): separate component gitlab-token
    
    * refactor(config-ui): optimize configuration item content
    
    * refactor(config-ui): use global hook to replace plugin hook
---
 config-ui/src/hooks/index.ts                       |   1 +
 .../jenkins => }/hooks/user-proxy-prefix.ts        |   9 +-
 .../src/pages/blueprint/create/step-two/index.tsx  |   4 +-
 .../blueprint/create/step-two/use-columns.tsx      |   4 +-
 .../pages/blueprint/detail/blueprint-detail.tsx    |   3 +-
 .../pages/blueprint/detail/panel/configuration.tsx |   6 +-
 config-ui/src/pages/blueprint/detail/types.ts      |   4 +-
 config-ui/src/pages/blueprint/types.ts             |   4 +-
 config-ui/src/pages/connection/form/api.ts         |   9 +-
 .../form/components/github-token/index.tsx         |   4 +-
 .../form/components/gitlab-token/index.tsx         |  53 +++++++++++
 .../src/pages/connection/form/components/index.ts  |   3 +-
 config-ui/src/pages/connection/form/index.tsx      |  45 ++++-----
 config-ui/src/pages/connection/form/use-form.ts    |   3 +-
 config-ui/src/pages/connection/home/index.tsx      |   4 +-
 config-ui/src/pages/connection/list/api.ts         |   3 +-
 config-ui/src/pages/connection/list/connection.tsx |   3 +-
 config-ui/src/pages/connection/list/index.tsx      |   6 +-
 .../src/pages/pipeline/components/task/index.tsx   |  10 +-
 config-ui/src/pages/pipeline/types.ts              |   4 +-
 .../project/detail/panel/incoming-webhooks.tsx     |   3 +-
 config-ui/src/pages/project/detail/use-project.ts  |   7 +-
 config-ui/src/pages/transformation/detail/api.ts   |   7 +-
 .../src/pages/transformation/detail/index.tsx      |  11 ++-
 .../src/pages/transformation/detail/use-detail.ts  |   7 +-
 config-ui/src/pages/transformation/home/index.tsx  |   7 +-
 .../src/plugins/components/data-scope-list/api.ts  |   4 +-
 .../plugins/components/data-scope-list/index.tsx   |   3 +-
 .../data-scope-list/use-data-scope-list.ts         |  12 +--
 .../src/plugins/components/data-scope/index.tsx    |   9 +-
 .../components/data-scope/use-data-scope.ts        |   9 +-
 .../src/plugins/components/transformation/api.ts   |   5 +-
 .../plugins/components/transformation/index.tsx    |   9 +-
 .../transformation/use-transformation.ts           |  12 +--
 config-ui/src/plugins/register/ae/config.ts        |   8 +-
 .../src/plugins/register/azure/assets/icon.svg     |  32 +++----
 config-ui/src/plugins/register/azure/config.ts     |   7 +-
 .../plugins/register/{ae => base}/assets/icon.svg  |   0
 .../src/plugins/register/{dora => base}/config.ts  |  25 +++--
 .../src/plugins/register/base/connection-fields.ts | 101 +++++++++++++++++++++
 .../register/{jenkins/hooks => base}/index.ts      |   3 +-
 .../src/plugins/register/bitbucket/assets/icon.svg |  20 +---
 config-ui/src/plugins/register/bitbucket/config.ts |  72 ++++++---------
 config-ui/src/plugins/register/dbt/assets/icon.svg |  27 ------
 config-ui/src/plugins/register/dbt/config.ts       |   8 +-
 .../src/plugins/register/dora/assets/icon.svg      |  27 ------
 config-ui/src/plugins/register/dora/config.ts      |   8 +-
 .../src/plugins/register/feishu/assets/icon.svg    |  27 ------
 config-ui/src/plugins/register/feishu/config.ts    |   8 +-
 .../src/plugins/register/gitee/assets/icon.svg     |  20 +---
 config-ui/src/plugins/register/gitee/config.ts     |   7 +-
 .../plugins/register/gitextractor/assets/icon.svg  |  16 ----
 .../src/plugins/register/gitextractor/config.ts    |   7 +-
 .../src/plugins/register/github/assets/icon.svg    |  20 +---
 .../miller-columns/use-miller-columns.ts           |   8 +-
 .../components/repo-selector/use-repo-selector.ts  |   8 +-
 config-ui/src/plugins/register/github/config.ts    |  70 +++++---------
 .../src/plugins/register/github/hooks/index.ts     |  19 ----
 .../register/github/hooks/user-proxy-prefix.ts     |  22 -----
 .../register/github_graphql/assets/icon.svg        |  20 +---
 .../src/plugins/register/github_graphql/config.ts  |   7 +-
 .../src/plugins/register/gitlab/assets/icon.svg    |  22 +----
 .../miller-columns/use-miller-columns.ts           |   8 +-
 .../project-selector/use-project-selector.ts       |   8 +-
 config-ui/src/plugins/register/gitlab/config.ts    |  60 +++++-------
 .../src/plugins/register/gitlab/hooks/index.ts     |  19 ----
 .../register/gitlab/hooks/user-proxy-prefix.ts     |  22 -----
 .../src/plugins/register/jenkins/assets/icon.svg   |  34 +++----
 .../miller-columns/use-miller-columns.ts           |   8 +-
 config-ui/src/plugins/register/jenkins/config.ts   |  69 +++++---------
 .../issue-tracking/use-issue-tracking.ts           |   8 +-
 .../miller-columns/use-miller-columns.ts           |   8 +-
 config-ui/src/plugins/register/jira/config.ts      |  70 ++++++--------
 config-ui/src/plugins/register/jira/hooks/index.ts |  19 ----
 .../register/jira/hooks/user-proxy-prefix.ts       |  22 -----
 .../src/plugins/register/refdiff/assets/icon.svg   |  27 ------
 config-ui/src/plugins/register/refdiff/config.ts   |   8 +-
 .../src/plugins/register/starrocks/assets/icon.svg |  27 ------
 config-ui/src/plugins/register/starrocks/config.ts |   8 +-
 .../src/plugins/register/tapd/assets/icon.svg      |  26 ++----
 config-ui/src/plugins/register/tapd/config.ts      |  69 +++++---------
 .../src/plugins/register/webook/assets/icon.svg    |  12 ++-
 config-ui/src/plugins/register/webook/config.ts    |   4 +-
 .../src/plugins/register/zentao/assets/icon.svg    |   6 +-
 config-ui/src/plugins/register/zentao/config.ts    |  69 +++++---------
 config-ui/src/plugins/types.ts                     |  31 +------
 config-ui/src/store/connections/types.ts           |   4 +-
 .../src/store/connections/use-context-value.ts     |   4 +-
 config-ui/src/store/transformations/api.ts         |   4 +-
 config-ui/src/store/transformations/types.ts       |   4 +-
 .../src/store/transformations/use-context-value.ts |   4 +-
 91 files changed, 602 insertions(+), 966 deletions(-)

diff --git a/config-ui/src/hooks/index.ts b/config-ui/src/hooks/index.ts
index bdf49dea4..cc1534ba8 100644
--- a/config-ui/src/hooks/index.ts
+++ b/config-ui/src/hooks/index.ts
@@ -16,5 +16,6 @@
  *
  */
 
+export * from './user-proxy-prefix';
 export * from './use-auto-refresh';
 export * from './use-operator';
diff --git a/config-ui/src/plugins/register/jenkins/hooks/user-proxy-prefix.ts b/config-ui/src/hooks/user-proxy-prefix.ts
similarity index 78%
rename from config-ui/src/plugins/register/jenkins/hooks/user-proxy-prefix.ts
rename to config-ui/src/hooks/user-proxy-prefix.ts
index 7c8b82144..0137928db 100644
--- a/config-ui/src/plugins/register/jenkins/hooks/user-proxy-prefix.ts
+++ b/config-ui/src/hooks/user-proxy-prefix.ts
@@ -18,5 +18,10 @@
 
 import { useMemo } from 'react';
 
-export const useProxyPrefix = (connectionId: ID) =>
-  useMemo(() => `/plugins/jenkins/connections/${connectionId}/proxy/rest`, [connectionId]);
+interface Props {
+  plugin: string;
+  connectionId: ID;
+}
+
+export const useProxyPrefix = ({ plugin, connectionId }: Props) =>
+  useMemo(() => `/plugins/${plugin}/connections/${connectionId}/proxy/rest`, [plugin, connectionId]);
diff --git a/config-ui/src/pages/blueprint/create/step-two/index.tsx b/config-ui/src/pages/blueprint/create/step-two/index.tsx
index 40d572f8f..82609fdf1 100644
--- a/config-ui/src/pages/blueprint/create/step-two/index.tsx
+++ b/config-ui/src/pages/blueprint/create/step-two/index.tsx
@@ -21,7 +21,7 @@ import { Icon } from '@blueprintjs/core';
 
 import { Card, Table, Divider } from '@/components';
 import { useConnection } from '@/store';
-import { Plugins, DataScope } from '@/plugins';
+import { DataScope } from '@/plugins';
 
 import type { BPConnectionItemType } from '../types';
 import { useCreateBP } from '../bp-context';
@@ -44,7 +44,7 @@ export const StepTwo = () => {
     onChangeShowDetail(false);
   };
 
-  const handleDeleteScope = (plugin: Plugins, connectionId: ID, scopeId: ID) => {
+  const handleDeleteScope = (plugin: string, connectionId: ID, scopeId: ID) => {
     const unique = `${plugin}-${connectionId}`;
 
     onChangeScopeMap({
diff --git a/config-ui/src/pages/blueprint/create/step-two/use-columns.tsx b/config-ui/src/pages/blueprint/create/step-two/use-columns.tsx
index 3514292ce..75889231c 100644
--- a/config-ui/src/pages/blueprint/create/step-two/use-columns.tsx
+++ b/config-ui/src/pages/blueprint/create/step-two/use-columns.tsx
@@ -20,7 +20,7 @@ import React, { useMemo } from 'react';
 import { Button, Intent } from '@blueprintjs/core';
 
 import type { ColumnType } from '@/components';
-import { Plugins, DataScopeList } from '@/plugins';
+import { DataScopeList } from '@/plugins';
 
 import type { BPConnectionItemType } from '../types';
 
@@ -28,7 +28,7 @@ import * as S from './styled';
 
 interface Props {
   onDetail: (connection: BPConnectionItemType) => void;
-  onDelete: (plugin: Plugins, connectionId: ID, scopeId: ID) => void;
+  onDelete: (plugin: string, connectionId: ID, scopeId: ID) => void;
 }
 
 export const useColumns = ({ onDetail, onDelete }: Props) => {
diff --git a/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx b/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
index e58cefba8..9690500cc 100644
--- a/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
+++ b/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
@@ -21,7 +21,6 @@ import type { TabId } from '@blueprintjs/core';
 import { Tabs, Tab } from '@blueprintjs/core';
 
 import { PageLoading } from '@/components';
-import { Plugins } from '@/plugins';
 
 import type { UseDetailProps } from './use-detail';
 import { useDetail } from './use-detail';
@@ -39,7 +38,7 @@ export const BlueprintDetail = ({ id }: Props) => {
   });
 
   const showJenkinsTips = useMemo(() => {
-    const jenkins = blueprint && blueprint.settings?.connections.find((cs) => cs.plugin === Plugins.Jenkins);
+    const jenkins = blueprint && blueprint.settings?.connections.find((cs) => cs.plugin === 'jenkins');
     return jenkins && !jenkins.scopes.length;
   }, [blueprint]);
 
diff --git a/config-ui/src/pages/blueprint/detail/panel/configuration.tsx b/config-ui/src/pages/blueprint/detail/panel/configuration.tsx
index 5f9478ef2..3369a067f 100644
--- a/config-ui/src/pages/blueprint/detail/panel/configuration.tsx
+++ b/config-ui/src/pages/blueprint/detail/panel/configuration.tsx
@@ -23,7 +23,7 @@ import dayjs from 'dayjs';
 
 import { Table, ColumnType } from '@/components';
 import { getCron, transformEntities } from '@/config';
-import { PluginConfig, DataScopeList, Plugins } from '@/plugins';
+import { PluginConfig, DataScopeList } from '@/plugins';
 
 import type { BlueprintType } from '../../types';
 import { ModeEnum } from '../../types';
@@ -59,7 +59,7 @@ export const Configuration = ({ blueprint, operating, onUpdate, onRefresh }: Pro
   const connections = useMemo(
     () =>
       blueprint.settings?.connections
-        .filter((cs) => cs.plugin !== Plugins.Webhook)
+        .filter((cs) => cs.plugin !== 'webhook')
         .map((cs: any) => {
           const plugin = PluginConfig.find((p) => p.plugin === cs.plugin) as any;
           return {
@@ -149,7 +149,7 @@ export const Configuration = ({ blueprint, operating, onUpdate, onRefresh }: Pro
               plugin={plugin}
               connectionId={connectionId}
               scopeIds={scopeIds}
-              onDelete={(plugin: Plugins, connectionId: ID, scopeId: ID) =>
+              onDelete={(plugin: string, connectionId: ID, scopeId: ID) =>
                 handleUpdateConnection({
                   plugin,
                   connectionId,
diff --git a/config-ui/src/pages/blueprint/detail/types.ts b/config-ui/src/pages/blueprint/detail/types.ts
index c0559550d..19e2a2ab8 100644
--- a/config-ui/src/pages/blueprint/detail/types.ts
+++ b/config-ui/src/pages/blueprint/detail/types.ts
@@ -16,13 +16,11 @@
  *
  */
 
-import { Plugins } from '@/plugins';
-
 export type ConfigConnectionItemType = {
   icon: string;
   name: string;
   connectionId: ID;
-  plugin: Plugins;
+  plugin: string;
   entities: string[];
   selectedEntites: string[];
   scope: Array<{ id: string; entities: string[] }>;
diff --git a/config-ui/src/pages/blueprint/types.ts b/config-ui/src/pages/blueprint/types.ts
index 66f51b029..9d86b95a3 100644
--- a/config-ui/src/pages/blueprint/types.ts
+++ b/config-ui/src/pages/blueprint/types.ts
@@ -16,8 +16,6 @@
  *
  */
 
-import { Plugins } from '@/plugins';
-
 export enum ModeEnum {
   advanced = 'ADVANCED',
   normal = 'NORMAL',
@@ -41,7 +39,7 @@ export type BlueprintType = {
     version: string;
     createdDateAfter: null | string;
     connections: Array<{
-      plugin: Plugins;
+      plugin: string;
       connectionId: ID;
       scopes: Array<{
         id: string;
diff --git a/config-ui/src/pages/connection/form/api.ts b/config-ui/src/pages/connection/form/api.ts
index a896f868f..fa09cefbe 100644
--- a/config-ui/src/pages/connection/form/api.ts
+++ b/config-ui/src/pages/connection/form/api.ts
@@ -16,18 +16,17 @@
  *
  */
 
-import { Plugins } from '@/plugins';
 import { request } from '@/utils';
 
-export const testConnection = (plugin: Plugins, payload: any) =>
+export const testConnection = (plugin: string, payload: any) =>
   request(`/plugins/${plugin}/test`, { method: 'post', data: payload });
 
-export const createConnection = (plugin: Plugins, payload: any) =>
+export const createConnection = (plugin: string, payload: any) =>
   request(`/plugins/${plugin}/connections`, { method: 'post', data: payload });
 
-export const getConnection = (plugin: Plugins, id: ID) => request(`/plugins/${plugin}/connections/${id}`);
+export const getConnection = (plugin: string, id: ID) => request(`/plugins/${plugin}/connections/${id}`);
 
-export const updateConnection = (plugin: Plugins, id: ID, payload: any) =>
+export const updateConnection = (plugin: string, id: ID, payload: any) =>
   request(`/plugins/${plugin}/connections/${id}`, {
     method: 'patch',
     data: payload,
diff --git a/config-ui/src/pages/connection/form/components/github-token/index.tsx b/config-ui/src/pages/connection/form/components/github-token/index.tsx
index 5f3a3ab34..e6943fb13 100644
--- a/config-ui/src/pages/connection/form/components/github-token/index.tsx
+++ b/config-ui/src/pages/connection/form/components/github-token/index.tsx
@@ -20,8 +20,6 @@ import React, { useEffect, useState } from 'react';
 import { InputGroup, Button, Intent } from '@blueprintjs/core';
 import { pick } from 'lodash';
 
-import { Plugins } from '@/plugins';
-
 import * as API from '../../api';
 
 import * as S from './styled';
@@ -43,7 +41,7 @@ export const GitHubToken = ({ form, value, onChange }: Props) => {
 
   const testToken = async (token: string): Promise<TokenItem> => {
     try {
-      const res = await API.testConnection(Plugins.GitHub, {
+      const res = await API.testConnection('github', {
         ...pick(form, ['endpoint', 'proxy']),
         token,
       });
diff --git a/config-ui/src/pages/connection/form/components/gitlab-token/index.tsx b/config-ui/src/pages/connection/form/components/gitlab-token/index.tsx
new file mode 100644
index 000000000..ee3f4590c
--- /dev/null
+++ b/config-ui/src/pages/connection/form/components/gitlab-token/index.tsx
@@ -0,0 +1,53 @@
+/*
+ * 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 from 'react';
+import { InputGroup } from '@blueprintjs/core';
+
+interface Props {
+  placeholder?: string;
+  initialValue?: string;
+  value?: string;
+  onChange?: (value: string) => void;
+}
+
+export const GitLabToken = ({ placeholder, initialValue, value, onChange }: Props) => {
+  const handleChangeValue = (e: React.ChangeEvent<HTMLInputElement>) => {
+    onChange?.(e.target.value);
+  };
+
+  return (
+    <div>
+      <p>
+        <a
+          href="https://devlake.apache.org/docs/UserManuals/ConfigUI/GitLab/#auth-tokens"
+          target="_blank"
+          rel="noreferrer"
+        >
+          Learn about how to create a personal access token
+        </a>
+      </p>
+      <InputGroup
+        placeholder={placeholder}
+        type="password"
+        value={value ?? initialValue}
+        onChange={handleChangeValue}
+      />
+    </div>
+  );
+};
diff --git a/config-ui/src/pages/connection/form/components/index.ts b/config-ui/src/pages/connection/form/components/index.ts
index 90e7488a6..3fc2e5b52 100644
--- a/config-ui/src/pages/connection/form/components/index.ts
+++ b/config-ui/src/pages/connection/form/components/index.ts
@@ -16,5 +16,6 @@
  *
  */
 
-export * from './github-token';
 export * from './rate-limit';
+export * from './github-token';
+export * from './gitlab-token';
diff --git a/config-ui/src/pages/connection/form/index.tsx b/config-ui/src/pages/connection/form/index.tsx
index 297bfd084..7375a7632 100644
--- a/config-ui/src/pages/connection/form/index.tsx
+++ b/config-ui/src/pages/connection/form/index.tsx
@@ -24,9 +24,9 @@ import { Tooltip2 } from '@blueprintjs/popover2';
 
 import { PageHeader, Card, PageLoading } from '@/components';
 import type { PluginConfigConnectionType } from '@/plugins';
-import { Plugins, PluginConfig } from '@/plugins';
+import { PluginConfig } from '@/plugins';
 
-import { GitHubToken, RateLimit } from './components';
+import { RateLimit, GitHubToken, GitLabToken } from './components';
 import { useForm } from './use-form';
 import * as S from './styled';
 
@@ -34,12 +34,12 @@ export const ConnectionFormPage = () => {
   const [form, setForm] = useState<Record<string, any>>({});
 
   const history = useHistory();
-  const { plugin, cid } = useParams<{ plugin: Plugins; cid?: string }>();
+  const { plugin, cid } = useParams<{ plugin: string; cid?: string }>();
   const { loading, operating, connection, onTest, onCreate, onUpdate } = useForm({ plugin, id: cid });
 
   const {
     name,
-    connection: { initialValues, fields },
+    connection: { fields },
   } = useMemo(() => PluginConfig.find((p) => p.plugin === plugin) as PluginConfigConnectionType, [plugin]);
 
   useEffect(() => {
@@ -47,7 +47,7 @@ export const ConnectionFormPage = () => {
       ...form,
       ...(connection ?? {}),
     });
-  }, [initialValues, connection]);
+  }, [connection]);
 
   const error = useMemo(
     () => !!(fields.filter((field) => field.required) ?? []).find((field) => !form[field.key]),
@@ -68,6 +68,7 @@ export const ConnectionFormPage = () => {
     required,
     placeholder,
     tooltip,
+    initialValue,
   }: PluginConfigConnectionType['connection']['fields']['0']) => {
     return (
       <FormGroup
@@ -89,7 +90,7 @@ export const ConnectionFormPage = () => {
         {type === 'text' && (
           <InputGroup
             placeholder={placeholder}
-            value={form[key] ?? ''}
+            value={form[key] ?? initialValue ?? ''}
             onChange={(e) => setForm({ ...form, [`${key}`]: e.target.value })}
           />
         )}
@@ -104,7 +105,7 @@ export const ConnectionFormPage = () => {
         {type === 'switch' && (
           <S.SwitchWrapper>
             <Switch
-              checked={form[key] ?? initialValues?.[key] ?? false}
+              checked={form[key] ?? initialValue ?? false}
               onChange={(e) =>
                 setForm({
                   ...form,
@@ -116,7 +117,7 @@ export const ConnectionFormPage = () => {
         )}
         {type === 'rateLimit' && (
           <RateLimit
-            initialValue={initialValues?.rateLimitPerHour}
+            initialValue={initialValue}
             value={form.rateLimitPerHour}
             onChange={(value) =>
               setForm({
@@ -139,23 +140,17 @@ export const ConnectionFormPage = () => {
           />
         )}
         {type === 'gitlabToken' && (
-          <div>
-            <p>
-              <a
-                href="https://devlake.apache.org/docs/UserManuals/ConfigUI/GitLab/#auth-tokens"
-                target="_blank"
-                rel="noreferrer"
-              >
-                Learn about how to create a personal access token
-              </a>
-            </p>
-            <InputGroup
-              placeholder={placeholder}
-              type="password"
-              value={form[key] ?? ''}
-              onChange={(e) => setForm({ ...form, [`${key}`]: e.target.value })}
-            />
-          </div>
+          <GitLabToken
+            placeholder={placeholder}
+            initialValue={initialValue}
+            value={form.token}
+            onChange={(value) =>
+              setForm({
+                ...form,
+                token: value,
+              })
+            }
+          />
         )}
       </FormGroup>
     );
diff --git a/config-ui/src/pages/connection/form/use-form.ts b/config-ui/src/pages/connection/form/use-form.ts
index e2bbafffe..5c9431c66 100644
--- a/config-ui/src/pages/connection/form/use-form.ts
+++ b/config-ui/src/pages/connection/form/use-form.ts
@@ -19,13 +19,12 @@
 import { useState, useMemo, useEffect } from 'react';
 import { useHistory } from 'react-router-dom';
 
-import { Plugins } from '@/plugins';
 import { operator } from '@/utils';
 
 import * as API from './api';
 
 interface Props {
-  plugin: Plugins;
+  plugin: string;
   id?: ID;
 }
 
diff --git a/config-ui/src/pages/connection/home/index.tsx b/config-ui/src/pages/connection/home/index.tsx
index 01ba0358b..be30601a4 100644
--- a/config-ui/src/pages/connection/home/index.tsx
+++ b/config-ui/src/pages/connection/home/index.tsx
@@ -21,7 +21,7 @@ import { useHistory } from 'react-router-dom';
 import { Tag, Intent } from '@blueprintjs/core';
 
 import type { PluginConfigConnectionType } from '@/plugins';
-import { PluginConfig, PluginType, Plugins } from '@/plugins';
+import { PluginConfig, PluginType } from '@/plugins';
 
 import * as S from './styled';
 
@@ -31,7 +31,7 @@ export const ConnectionHomePage = () => {
   const [connections, webhook] = useMemo(
     () => [
       PluginConfig.filter((p) => p.type === PluginType.Connection) as PluginConfigConnectionType[],
-      PluginConfig.filter((p) => p.plugin === Plugins.Webhook),
+      PluginConfig.filter((p) => p.plugin === 'webhook'),
     ],
     [],
   );
diff --git a/config-ui/src/pages/connection/list/api.ts b/config-ui/src/pages/connection/list/api.ts
index 1bfdb0386..3d7df8db5 100644
--- a/config-ui/src/pages/connection/list/api.ts
+++ b/config-ui/src/pages/connection/list/api.ts
@@ -16,8 +16,7 @@
  *
  */
 
-import { Plugins } from '@/plugins';
 import { request } from '@/utils';
 
-export const deleteConnection = (plugin: Plugins, id: ID) =>
+export const deleteConnection = (plugin: string, id: ID) =>
   request(`/plugins/${plugin}/connections/${id}`, { method: 'delete' });
diff --git a/config-ui/src/pages/connection/list/connection.tsx b/config-ui/src/pages/connection/list/connection.tsx
index b02101b71..49387335a 100644
--- a/config-ui/src/pages/connection/list/connection.tsx
+++ b/config-ui/src/pages/connection/list/connection.tsx
@@ -22,7 +22,6 @@ import { ButtonGroup, Button, Intent, Position } from '@blueprintjs/core';
 import { Popover2 } from '@blueprintjs/popover2';
 
 import { Table, ColumnType } from '@/components';
-import { Plugins } from '@/plugins';
 import type { ConnectionItemType } from '@/store';
 import { useConnection, ConnectionStatus } from '@/store';
 import { operator } from '@/utils';
@@ -31,7 +30,7 @@ import * as API from './api';
 import * as S from './styled';
 
 interface Props {
-  plugin: Plugins;
+  plugin: string;
 }
 
 export const Connection = ({ plugin }: Props) => {
diff --git a/config-ui/src/pages/connection/list/index.tsx b/config-ui/src/pages/connection/list/index.tsx
index 8eeb04aa7..2568a0abd 100644
--- a/config-ui/src/pages/connection/list/index.tsx
+++ b/config-ui/src/pages/connection/list/index.tsx
@@ -21,14 +21,14 @@ import { useParams } from 'react-router-dom';
 
 import { PageHeader } from '@/components';
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginConfig } from '@/plugins';
+import { PluginConfig } from '@/plugins';
 import { WebHookConnection } from '@/plugins/register/webook';
 import { ConnectionContextProvider } from '@/store';
 
 import { Connection } from './connection';
 
 export const ConnectionListPage = () => {
-  const { plugin } = useParams<{ plugin: Plugins }>();
+  const { plugin } = useParams<{ plugin: string }>();
 
   const config = useMemo(() => PluginConfig.find((p) => p.plugin === plugin) as PluginConfigType, [plugin]);
 
@@ -40,7 +40,7 @@ export const ConnectionListPage = () => {
           { name: config.name, path: `/connections/${plugin}` },
         ]}
       >
-        {plugin === Plugins.Webhook ? <WebHookConnection /> : <Connection plugin={plugin} />}
+        {plugin === 'webhook' ? <WebHookConnection /> : <Connection plugin={plugin} />}
       </PageHeader>
     </ConnectionContextProvider>
   );
diff --git a/config-ui/src/pages/pipeline/components/task/index.tsx b/config-ui/src/pages/pipeline/components/task/index.tsx
index 8ec91ee9a..93f3a298d 100644
--- a/config-ui/src/pages/pipeline/components/task/index.tsx
+++ b/config-ui/src/pages/pipeline/components/task/index.tsx
@@ -21,7 +21,7 @@ import { Intent } from '@blueprintjs/core';
 
 import { TextTooltip } from '@/components';
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginConfig } from '@/plugins';
+import { PluginConfig } from '@/plugins';
 
 import type { TaskType } from '../../types';
 import { StatusEnum } from '../../types';
@@ -45,16 +45,16 @@ export const PipelineTask = ({ task }: Props) => {
     let name = config.name;
 
     switch (true) {
-      case [Plugins.GitHub, Plugins.GitHubGraphql].includes(config.plugin):
+      case ['github', 'github_graphql'].includes(config.plugin):
         name = `${name}:${options.name}`;
         break;
-      case Plugins.GitExtractor === config.plugin:
+      case ['gitextractor'].includes(config.plugin):
         name = `${name}:${options.repoId}`;
         break;
-      case [Plugins.DORA, Plugins.RefDiff].includes(config.plugin):
+      case ['dora', 'refdiff'].includes(config.plugin):
         name = `${name}:${options.projectName}`;
         break;
-      case Plugins.GitLab === config.plugin:
+      case ['gitlab'].includes(config.plugin):
         name = `${name}:projectId:${options.projectId}`;
         break;
       case [Plugins.JIRA, Plugins.Jenkins].includes(config.plugin):
diff --git a/config-ui/src/pages/pipeline/types.ts b/config-ui/src/pages/pipeline/types.ts
index 9ea6389a9..49b757d12 100644
--- a/config-ui/src/pages/pipeline/types.ts
+++ b/config-ui/src/pages/pipeline/types.ts
@@ -16,8 +16,6 @@
  *
  */
 
-import { Plugins } from '@/plugins';
-
 export enum StatusEnum {
   CREATED = 'TASK_CREATED',
   PENDING = 'TASK_PENDING',
@@ -43,7 +41,7 @@ export type PipelineType = {
 
 export type TaskType = {
   id: ID;
-  plugin: Plugins;
+  plugin: string;
   status: StatusEnum;
   pipelineRow: number;
   pipelineCol: number;
diff --git a/config-ui/src/pages/project/detail/panel/incoming-webhooks.tsx b/config-ui/src/pages/project/detail/panel/incoming-webhooks.tsx
index fc4df48aa..d6425949a 100644
--- a/config-ui/src/pages/project/detail/panel/incoming-webhooks.tsx
+++ b/config-ui/src/pages/project/detail/panel/incoming-webhooks.tsx
@@ -21,7 +21,6 @@ import { Button, Intent } from '@blueprintjs/core';
 
 import NoData from '@/images/no-webhook.svg';
 import { Card } from '@/components';
-import { Plugins } from '@/plugins';
 import type { WebhookItemType } from '@/plugins/register/webook';
 import { WebhookCreateDialog, WebhookSelectorDialog, WebHookConnection } from '@/plugins/register/webook';
 
@@ -41,7 +40,7 @@ export const IncomingWebhooksPanel = ({ project, saving, onSelectWebhook, onCrea
     () =>
       project.blueprint
         ? project.blueprint.settings.connections
-            .filter((cs: any) => cs.plugin === Plugins.Webhook)
+            .filter((cs: any) => cs.plugin === 'webhook')
             .map((cs: any) => cs.connectionId)
         : [],
     [project],
diff --git a/config-ui/src/pages/project/detail/use-project.ts b/config-ui/src/pages/project/detail/use-project.ts
index 6332a4f9c..7e396c662 100644
--- a/config-ui/src/pages/project/detail/use-project.ts
+++ b/config-ui/src/pages/project/detail/use-project.ts
@@ -19,8 +19,7 @@
 import { useState, useEffect, useMemo } from 'react';
 import { useHistory } from 'react-router-dom';
 
-import type { WebhookItemType } from '@/plugins';
-import { Plugins } from '@/plugins';
+import type { WebhookItemType } from '@/plugins/register/webook';
 import { operator } from '@/utils';
 
 import type { ProjectType } from './types';
@@ -82,7 +81,7 @@ export const useProject = (name: string) => {
         connections: [
           ...project?.blueprint.settings.connections,
           ...items.map((it) => ({
-            plugin: Plugins.Webhook,
+            plugin: 'webhook',
             connectionId: it.id,
           })),
         ],
@@ -106,7 +105,7 @@ export const useProject = (name: string) => {
         connections: [
           ...project?.blueprint.settings.connections,
           {
-            plugin: Plugins.Webhook,
+            plugin: 'webhook',
             connectionId: id,
           },
         ],
diff --git a/config-ui/src/pages/transformation/detail/api.ts b/config-ui/src/pages/transformation/detail/api.ts
index 6d321e3a9..ee2c2900a 100644
--- a/config-ui/src/pages/transformation/detail/api.ts
+++ b/config-ui/src/pages/transformation/detail/api.ts
@@ -17,17 +17,16 @@
  */
 
 import { request } from '@/utils';
-import { Plugins } from '@/plugins';
 
-export const createTransformation = (plugin: Plugins, payload: any) =>
+export const createTransformation = (plugin: string, payload: any) =>
   request(`/plugins/${plugin}/transformation_rules`, {
     method: 'post',
     data: payload,
   });
 
-export const getTransformation = (plugin: Plugins, id: ID) => request(`/plugins/${plugin}/transformation_rules/${id}`);
+export const getTransformation = (plugin: string, id: ID) => request(`/plugins/${plugin}/transformation_rules/${id}`);
 
-export const updateTransformation = (plugin: Plugins, id: ID, payload: any) =>
+export const updateTransformation = (plugin: string, id: ID, payload: any) =>
   request(`/plugins/${plugin}/transformation_rules/${id}`, {
     method: 'patch',
     data: payload,
diff --git a/config-ui/src/pages/transformation/detail/index.tsx b/config-ui/src/pages/transformation/detail/index.tsx
index f8043aa73..df181a3dd 100644
--- a/config-ui/src/pages/transformation/detail/index.tsx
+++ b/config-ui/src/pages/transformation/detail/index.tsx
@@ -21,7 +21,6 @@ import { useParams, useHistory } from 'react-router-dom';
 import { InputGroup, ButtonGroup, Button, Intent } from '@blueprintjs/core';
 
 import { PageLoading, PageHeader, Card } from '@/components';
-import { Plugins } from '@/plugins';
 import { GitHubTransformation } from '@/plugins/register/github';
 import { GitLabTransformation } from '@/plugins/register/gitlab';
 import { JenkinsTransformation } from '@/plugins/register/jenkins';
@@ -30,7 +29,7 @@ import { useDetail } from './use-detail';
 import * as S from './styled';
 
 export const TransformationDetailPage = () => {
-  const { plugin, tid } = useParams<{ plugin: Plugins; tid?: string }>();
+  const { plugin, tid } = useParams<{ plugin: string; tid?: string }>();
   const history = useHistory();
 
   const { loading, operating, name, transformation, onChangeName, onChangeTransformation, onSave } = useDetail({
@@ -67,16 +66,18 @@ export const TransformationDetailPage = () => {
           />
         </Card>
         <Card className="card">
-          {plugin === Plugins.GitHub && (
+          {plugin === 'github' && (
             <GitHubTransformation transformation={transformation} setTransformation={onChangeTransformation} />
           )}
-          {plugin === Plugins.GitLab && (
+
+          {plugin === 'gitlab' && (
             <GitLabTransformation transformation={transformation} setTransformation={onChangeTransformation} />
           )}
 
-          {plugin === Plugins.Jenkins && (
+          {plugin === 'jenkins' && (
             <JenkinsTransformation transformation={transformation} setTransformation={onChangeTransformation} />
           )}
+
           <div className="action">
             <ButtonGroup>
               <Button disabled={operating} outlined text="Cancel" onClick={() => history.push('/transformations')} />
diff --git a/config-ui/src/pages/transformation/detail/use-detail.ts b/config-ui/src/pages/transformation/detail/use-detail.ts
index 94ce9a0ba..8c86f24eb 100644
--- a/config-ui/src/pages/transformation/detail/use-detail.ts
+++ b/config-ui/src/pages/transformation/detail/use-detail.ts
@@ -19,13 +19,14 @@
 import { useState, useEffect, useMemo } from 'react';
 import { useHistory } from 'react-router-dom';
 
-import { Plugins, PluginConfig } from '@/plugins';
+import type { PluginConfigConnectionType } from '@/plugins';
+import { PluginConfig } from '@/plugins';
 import { operator } from '@/utils';
 
 import * as API from './api';
 
 interface Props {
-  plugin: Plugins;
+  plugin: string;
   id?: ID;
 }
 
@@ -34,7 +35,7 @@ export const useDetail = ({ plugin, id }: Props) => {
   const [operating, setOperating] = useState(false);
   const [name, setName] = useState('');
   const [transformation, setTransformation] = useState<any>(
-    PluginConfig.find((pc) => pc.plugin === plugin)?.transformation,
+    (PluginConfig.find((pc) => pc.plugin === plugin) as PluginConfigConnectionType)?.transformation,
   );
 
   const history = useHistory();
diff --git a/config-ui/src/pages/transformation/home/index.tsx b/config-ui/src/pages/transformation/home/index.tsx
index 5022de1ae..f660bb84d 100644
--- a/config-ui/src/pages/transformation/home/index.tsx
+++ b/config-ui/src/pages/transformation/home/index.tsx
@@ -22,7 +22,6 @@ import { ButtonGroup, Button, Icon, Intent } from '@blueprintjs/core';
 
 import { PageHeader, Table, ColumnType, Dialog, Selector } from '@/components';
 import type { PluginConfigType } from '@/plugins';
-import { Plugins } from '@/plugins';
 import { TransformationContextProvider, TransformationContextConsumer, TransformationItemType } from '@/store';
 
 import * as S from './styled';
@@ -52,7 +51,7 @@ export const TransformationHomePage = () => {
           key: 'action',
           align: 'center',
           render: (_, row) =>
-            row.plugin !== Plugins.JIRA && (
+            row.plugin !== 'jira' && (
               <Button
                 minimal
                 intent={Intent.PRIMARY}
@@ -97,7 +96,7 @@ export const TransformationHomePage = () => {
                 isOpen={isOpen}
                 title="Select a Data Source"
                 okText="Continue"
-                okDisabled={!selectedPlugin || selectedPlugin.plugin === Plugins.JIRA}
+                okDisabled={!selectedPlugin || selectedPlugin.plugin === 'jira'}
                 onOk={() => history.push(`/transformations/${selectedPlugin?.plugin}/create`)}
                 onCancel={() => setIsOpen(false)}
               >
@@ -110,7 +109,7 @@ export const TransformationHomePage = () => {
                     selectedItem={selectedPlugin}
                     onChangeItem={(selectedItem) => setSelectedPlugin(selectedItem)}
                   />
-                  {selectedPlugin?.plugin === Plugins.JIRA && (
+                  {selectedPlugin?.plugin === 'jira' && (
                     <div className="warning">
                       <Icon icon="error" />
                       <span>
diff --git a/config-ui/src/plugins/components/data-scope-list/api.ts b/config-ui/src/plugins/components/data-scope-list/api.ts
index 30c19aa11..9035ede94 100644
--- a/config-ui/src/plugins/components/data-scope-list/api.ts
+++ b/config-ui/src/plugins/components/data-scope-list/api.ts
@@ -18,7 +18,5 @@
 
 import { request } from '@/utils';
 
-import { Plugins } from '@/plugins';
-
-export const getDataScopeRepo = (plugin: Plugins, connectionId: ID, repoId: ID) =>
+export const getDataScopeRepo = (plugin: string, connectionId: ID, repoId: ID) =>
   request(`/plugins/${plugin}/connections/${connectionId}/scopes/${repoId}`);
diff --git a/config-ui/src/plugins/components/data-scope-list/index.tsx b/config-ui/src/plugins/components/data-scope-list/index.tsx
index 010fe63ff..0f3eed8ed 100644
--- a/config-ui/src/plugins/components/data-scope-list/index.tsx
+++ b/config-ui/src/plugins/components/data-scope-list/index.tsx
@@ -21,7 +21,6 @@ import { Button, Icon, Intent, Position } from '@blueprintjs/core';
 import { Tooltip2 } from '@blueprintjs/popover2';
 
 import { Loading, DeleteButton } from '@/components';
-import { Plugins } from '@/plugins';
 
 import type { UseDataScopeList } from './use-data-scope-list';
 import { useDataScopeList } from './use-data-scope-list';
@@ -30,7 +29,7 @@ import * as S from './styled';
 interface Props extends UseDataScopeList {
   groupByTs: boolean;
   scopeIds: string[];
-  onDelete?: (plugin: Plugins, connectionId: ID, scopeId: ID) => void;
+  onDelete?: (plugin: string, connectionId: ID, scopeId: ID) => void;
 }
 
 export const DataScopeList = ({ groupByTs, scopeIds, onDelete, ...props }: Props) => {
diff --git a/config-ui/src/plugins/components/data-scope-list/use-data-scope-list.ts b/config-ui/src/plugins/components/data-scope-list/use-data-scope-list.ts
index 8bcb9e804..079be9a98 100644
--- a/config-ui/src/plugins/components/data-scope-list/use-data-scope-list.ts
+++ b/config-ui/src/plugins/components/data-scope-list/use-data-scope-list.ts
@@ -19,8 +19,6 @@
 import { useState, useEffect, useMemo } from 'react';
 import { groupBy } from 'lodash';
 
-import { Plugins } from '@/plugins';
-
 import * as API from './api';
 
 type ScopeItem = {
@@ -30,7 +28,7 @@ type ScopeItem = {
 };
 
 export interface UseDataScopeList {
-  plugin: Plugins;
+  plugin: string;
   connectionId: ID;
   scopeIds: string[];
 }
@@ -42,25 +40,25 @@ export const useDataScopeList = ({ plugin, connectionId, scopeIds }: UseDataScop
   const formatScope = (scope: any) => {
     return scope.map((sc: any) => {
       switch (true) {
-        case plugin === Plugins.GitHub:
+        case plugin === 'github':
           return {
             id: `${sc.githubId}`,
             name: sc.name,
             transformationRuleName: sc.transformationRuleName,
           };
-        case plugin === Plugins.JIRA:
+        case plugin === 'jira':
           return {
             id: `${sc.boardId}`,
             name: sc.name,
             transformationRuleName: sc.transformationRuleName,
           };
-        case plugin === Plugins.GitLab:
+        case plugin === 'gitlab':
           return {
             id: `${sc.gitlabId}`,
             name: sc.name,
             transformationRuleName: sc.transformationRuleName,
           };
-        case plugin === Plugins.Jenkins:
+        case plugin === 'jenkins':
           return {
             id: sc.jobFullName,
             name: sc.jobFullName,
diff --git a/config-ui/src/plugins/components/data-scope/index.tsx b/config-ui/src/plugins/components/data-scope/index.tsx
index 2c2987ba7..3253bba20 100644
--- a/config-ui/src/plugins/components/data-scope/index.tsx
+++ b/config-ui/src/plugins/components/data-scope/index.tsx
@@ -20,7 +20,6 @@ import React from 'react';
 import { ButtonGroup, Button, Intent } from '@blueprintjs/core';
 
 import { transformEntities } from '@/config';
-import { Plugins } from '@/plugins';
 import { GitHubDataScope } from '@/plugins/register/github';
 import { JIRADataScope } from '@/plugins/register/jira';
 import { GitLabDataScope } from '@/plugins/register/gitlab';
@@ -47,7 +46,7 @@ export const DataScope = ({ plugin, connectionId, entities, onCancel, ...props }
   return (
     <S.Wrapper>
       <div className="block">
-        {plugin === Plugins.GitHub && (
+        {plugin === 'github' && (
           <GitHubDataScope
             connectionId={connectionId}
             disabledItems={disabledScope}
@@ -56,7 +55,7 @@ export const DataScope = ({ plugin, connectionId, entities, onCancel, ...props }
           />
         )}
 
-        {plugin === Plugins.JIRA && (
+        {plugin === 'jira' && (
           <JIRADataScope
             connectionId={connectionId}
             disabledItems={disabledScope}
@@ -65,7 +64,7 @@ export const DataScope = ({ plugin, connectionId, entities, onCancel, ...props }
           />
         )}
 
-        {plugin === Plugins.GitLab && (
+        {plugin === 'gitlab' && (
           <GitLabDataScope
             connectionId={connectionId}
             disabledItems={disabledScope}
@@ -74,7 +73,7 @@ export const DataScope = ({ plugin, connectionId, entities, onCancel, ...props }
           />
         )}
 
-        {plugin === Plugins.Jenkins && (
+        {plugin === 'jenkins' && (
           <JenkinsDataScope
             connectionId={connectionId}
             disabledItems={disabledScope}
diff --git a/config-ui/src/plugins/components/data-scope/use-data-scope.ts b/config-ui/src/plugins/components/data-scope/use-data-scope.ts
index 1c4915dc1..7632315b6 100644
--- a/config-ui/src/plugins/components/data-scope/use-data-scope.ts
+++ b/config-ui/src/plugins/components/data-scope/use-data-scope.ts
@@ -20,7 +20,6 @@ import { useState, useEffect, useMemo } from 'react';
 import { omit } from 'lodash';
 
 import { transformEntities } from '@/config';
-import { Plugins } from '@/plugins';
 import { operator } from '@/utils';
 
 import * as API from './api';
@@ -57,13 +56,13 @@ export const useDataScope = ({ plugin, connectionId, entities, initialValues, on
 
   const getPluginId = (scope: any) => {
     switch (true) {
-      case plugin === Plugins.GitHub:
+      case plugin === 'github':
         return scope.githubId;
-      case plugin === Plugins.JIRA:
+      case plugin === 'jira':
         return scope.boardId;
-      case plugin === Plugins.GitLab:
+      case plugin === 'gitlab':
         return scope.gitlabId;
-      case plugin === Plugins.Jenkins:
+      case plugin === 'jenkins':
         return scope.jobFullName;
     }
   };
diff --git a/config-ui/src/plugins/components/transformation/api.ts b/config-ui/src/plugins/components/transformation/api.ts
index c16e70e36..907e943f0 100644
--- a/config-ui/src/plugins/components/transformation/api.ts
+++ b/config-ui/src/plugins/components/transformation/api.ts
@@ -17,20 +17,19 @@
  */
 
 import { request } from '@/utils';
-import { Plugins } from '@/plugins';
 
 type GetRulesParams = {
   page: number;
   pageSize: number;
 };
 
-export const getRules = (plugin: Plugins, params?: GetRulesParams) =>
+export const getRules = (plugin: string, params?: GetRulesParams) =>
   request(`/plugins/${plugin}/transformation_rules`, {
     method: 'get',
     data: params,
   });
 
-export const getDataScopeRepo = (plugin: Plugins, connectionId: ID, repoId: ID) =>
+export const getDataScopeRepo = (plugin: string, connectionId: ID, repoId: ID) =>
   request(`/plugins/${plugin}/connections/${connectionId}/scopes/${repoId}`);
 
 export const updateDataScope = (plugin: string, connectionId: ID, payload: any) =>
diff --git a/config-ui/src/plugins/components/transformation/index.tsx b/config-ui/src/plugins/components/transformation/index.tsx
index bc610a811..cb2c04a7f 100644
--- a/config-ui/src/plugins/components/transformation/index.tsx
+++ b/config-ui/src/plugins/components/transformation/index.tsx
@@ -21,7 +21,6 @@ import { RadioGroup, Radio, InputGroup, ButtonGroup, Button, Intent } from '@blu
 
 import { Divider, Selector, MultiSelector } from '@/components';
 
-import { Plugins } from '@/plugins';
 import { GitHubTransformation } from '@/plugins/register/github';
 import { JIRATransformation } from '@/plugins/register/jira';
 import { GitLabTransformation } from '@/plugins/register/gitlab';
@@ -138,11 +137,11 @@ export const Transformation = ({ from, plugin, connectionId, onCancel, ...props
         <>
           <Divider />
           <div className="block">
-            {plugin === Plugins.GitHub && (
+            {plugin === 'github' && (
               <GitHubTransformation transformation={transformation} setTransformation={onChangeTransformation} />
             )}
 
-            {plugin === Plugins.JIRA && (
+            {plugin === 'jira' && (
               <JIRATransformation
                 connectionId={connectionId}
                 transformation={transformation}
@@ -150,11 +149,11 @@ export const Transformation = ({ from, plugin, connectionId, onCancel, ...props
               />
             )}
 
-            {plugin === Plugins.GitLab && (
+            {plugin === 'gitlab' && (
               <GitLabTransformation transformation={transformation} setTransformation={onChangeTransformation} />
             )}
 
-            {plugin === Plugins.Jenkins && (
+            {plugin === 'jenkins' && (
               <JenkinsTransformation transformation={transformation} setTransformation={onChangeTransformation} />
             )}
 
diff --git a/config-ui/src/plugins/components/transformation/use-transformation.ts b/config-ui/src/plugins/components/transformation/use-transformation.ts
index 220aa09ce..f7231692c 100644
--- a/config-ui/src/plugins/components/transformation/use-transformation.ts
+++ b/config-ui/src/plugins/components/transformation/use-transformation.ts
@@ -19,14 +19,14 @@
 import { useState, useEffect, useMemo } from 'react';
 
 import type { PluginConfigConnectionType } from '@/plugins';
-import { Plugins, PluginConfig } from '@/plugins';
+import { PluginConfig } from '@/plugins';
 import { operator } from '@/utils';
 
 import type { RuleItem, ScopeItem } from './types';
 import * as API from './api';
 
 export interface UseTransformationProps {
-  plugin: Plugins;
+  plugin: string;
   connectionId: ID;
   scopeIds: ID[];
   name: string;
@@ -136,13 +136,13 @@ export const useTransformation = ({
       transformation,
       getScopeKey(sc: any) {
         switch (true) {
-          case plugin === Plugins.GitHub:
+          case plugin === 'github':
             return sc.githubId;
-          case plugin === Plugins.JIRA:
+          case plugin === 'jira':
             return sc.boardId;
-          case plugin === Plugins.GitLab:
+          case plugin === 'gitlab':
             return sc.gitlabId;
-          case plugin === Plugins.Jenkins:
+          case plugin === 'jenkins':
             return sc.jobFullName;
         }
       },
diff --git a/config-ui/src/plugins/register/ae/config.ts b/config-ui/src/plugins/register/ae/config.ts
index 266a5ccd6..f0d873cb3 100644
--- a/config-ui/src/plugins/register/ae/config.ts
+++ b/config-ui/src/plugins/register/ae/config.ts
@@ -17,13 +17,11 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
 
-import Icon from './assets/icon.svg';
+import { BasePipelineConfig } from '../base';
 
 export const AEConfig: PluginConfigType = {
-  plugin: Plugins.AE,
+  ...BasePipelineConfig,
+  plugin: 'ae',
   name: 'AE',
-  type: PluginType.Pipeline,
-  icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/azure/assets/icon.svg b/config-ui/src/plugins/register/azure/assets/icon.svg
index 262235aba..e04a117e1 100644
--- a/config-ui/src/plugins/register/azure/assets/icon.svg
+++ b/config-ui/src/plugins/register/azure/assets/icon.svg
@@ -1,22 +1,14 @@
-<!--
-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.
--->
 <svg width="100" height="100" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <path d="M41.6217 5.85234C41.4483 5.33862 41.1182 4.89221 40.6778 4.57602C40.2374 4.25982 39.7088 4.08978 39.1667 4.08984H21.0298C21.5719 4.08987 22.1004 4.25995 22.5408 4.57613C22.9812 4.89231 23.3114 5.33867 23.4848 5.85234L39.2248 52.4898C39.3564 52.8796 39.3932 53.2952 39.3324 53.702C39.2715 54.1089 39.1146 54.4955 38.8747 54.8297C38.6348 55.1639 38.3187 55.4362 37.9527 55.624C37.5867 55.8118 37.1812 55.9098 36.7698 55.9098H54.9073C55.3186 55.9097 55.7241 55.8117 56.09 55.6238C56 [...]
-    <path fill-rule="evenodd" clip-rule="evenodd" d="M31.191 37.6631L36.195 52.49C36.3266 52.8798 36.3635 53.2953 36.3026 53.7022C36.2417 54.109 36.0848 54.4956 35.8449 54.8298C35.6176 55.1465 35.3219 55.4076 34.9801 55.5939C34.7877 55.4895 34.6076 55.3604 34.445 55.2087L17.8625 39.7312C17.687 39.5676 17.5648 39.355 17.5119 39.121C17.4589 38.887 17.4777 38.6425 17.5657 38.4193C17.6537 38.1961 17.8069 38.0046 18.0053 37.8697C18.2038 37.7348 18.4382 37.6628 18.6781 37.6631H31.191Z" fill="# [...]
-    <path fill-rule="evenodd" clip-rule="evenodd" d="M26.4536 35.6629L28.4847 29.645L20.4548 5.85233C20.2814 5.33865 19.9512 4.8923 19.5108 4.57612C19.4799 4.55394 19.4486 4.53248 19.4169 4.51175C19.385 4.53256 19.3535 4.55411 19.3225 4.57639C18.8814 4.89314 18.5508 5.34028 18.3773 5.85484L2.63788 52.4905C2.5064 52.8802 2.46961 53.2956 2.53054 53.7024C2.59148 54.1092 2.74839 54.4956 2.9883 54.8297C3.22821 55.1638 3.54422 55.4359 3.91019 55.6237C4.27616 55.8114 4.68157 55.9093 5.09288 55. [...]
-    <path fill-rule="evenodd" clip-rule="evenodd" d="M31.191 37.6631L36.195 52.49C36.3266 52.8798 36.3635 53.2953 36.3026 53.7022C36.2417 54.109 36.0848 54.4956 35.8449 54.8298C35.6176 55.1465 35.3219 55.4076 34.9801 55.5939C34.7877 55.4895 34.6076 55.3604 34.445 55.2087L17.8625 39.7312C17.687 39.5676 17.5648 39.355 17.5119 39.121C17.4589 38.887 17.4777 38.6425 17.5657 38.4193C17.6537 38.1961 17.8069 38.0046 18.0053 37.8697C18.2038 37.7348 18.4382 37.6628 18.6781 37.6631H31.191Z" fill="# [...]
+    <path
+        d="M41.6217 5.85234C41.4483 5.33862 41.1182 4.89221 40.6778 4.57602C40.2374 4.25982 39.7088 4.08978 39.1667 4.08984H21.0298C21.5719 4.08987 22.1004 4.25995 22.5408 4.57613C22.9812 4.89231 23.3114 5.33867 23.4848 5.85234L39.2248 52.4898C39.3564 52.8796 39.3932 53.2952 39.3324 53.702C39.2715 54.1089 39.1146 54.4955 38.8747 54.8297C38.6348 55.1639 38.3187 55.4362 37.9527 55.624C37.5867 55.8118 37.1812 55.9098 36.7698 55.9098H54.9073C55.3186 55.9097 55.7241 55.8117 56.09 55.6238C56.4 [...]
+        fill="#7497F7" />
+    <path fill-rule="evenodd" clip-rule="evenodd"
+        d="M31.191 37.6631L36.195 52.49C36.3266 52.8798 36.3635 53.2953 36.3026 53.7022C36.2417 54.109 36.0848 54.4956 35.8449 54.8298C35.6176 55.1465 35.3219 55.4076 34.9801 55.5939C34.7877 55.4895 34.6076 55.3604 34.445 55.2087L17.8625 39.7312C17.687 39.5676 17.5648 39.355 17.5119 39.121C17.4589 38.887 17.4777 38.6425 17.5657 38.4193C17.6537 38.1961 17.8069 38.0046 18.0053 37.8697C18.2038 37.7348 18.4382 37.6628 18.6781 37.6631H31.191Z"
+        fill="#7497F7" />
+    <path fill-rule="evenodd" clip-rule="evenodd"
+        d="M26.4536 35.6629L28.4847 29.645L20.4548 5.85233C20.2814 5.33865 19.9512 4.8923 19.5108 4.57612C19.4799 4.55394 19.4486 4.53248 19.4169 4.51175C19.385 4.53256 19.3535 4.55411 19.3225 4.57639C18.8814 4.89314 18.5508 5.34028 18.3773 5.85484L2.63788 52.4905C2.5064 52.8802 2.46961 53.2956 2.53054 53.7024C2.59148 54.1092 2.74839 54.4956 2.9883 54.8297C3.22821 55.1638 3.54422 55.4359 3.91019 55.6237C4.27616 55.8114 4.68157 55.9093 5.09288 55.9092H17.7579C18.3007 55.9091 18.8299 55.73 [...]
+        fill="#7497F7" />
+    <path fill-rule="evenodd" clip-rule="evenodd"
+        d="M31.191 37.6631L36.195 52.49C36.3266 52.8798 36.3635 53.2953 36.3026 53.7022C36.2417 54.109 36.0848 54.4956 35.8449 54.8298C35.6176 55.1465 35.3219 55.4076 34.9801 55.5939C34.7877 55.4895 34.6076 55.3604 34.445 55.2087L17.8625 39.7312C17.687 39.5676 17.5648 39.355 17.5119 39.121C17.4589 38.887 17.4777 38.6425 17.5657 38.4193C17.6537 38.1961 17.8069 38.0046 18.0053 37.8697C18.2038 37.7348 18.4382 37.6628 18.6781 37.6631H31.191Z"
+        fill="#7497F7" />
 </svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/azure/config.ts b/config-ui/src/plugins/register/azure/config.ts
index f3ca0186a..ebbcbf2e8 100644
--- a/config-ui/src/plugins/register/azure/config.ts
+++ b/config-ui/src/plugins/register/azure/config.ts
@@ -17,13 +17,14 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import { BasePipelineConfig } from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const AzureConfig: PluginConfigType = {
-  plugin: Plugins.Azure,
+  ...BasePipelineConfig,
+  plugin: 'azure',
   name: 'Azure',
-  type: PluginType.Pipeline,
   icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/ae/assets/icon.svg b/config-ui/src/plugins/register/base/assets/icon.svg
similarity index 100%
rename from config-ui/src/plugins/register/ae/assets/icon.svg
rename to config-ui/src/plugins/register/base/assets/icon.svg
diff --git a/config-ui/src/plugins/register/dora/config.ts b/config-ui/src/plugins/register/base/config.ts
similarity index 69%
copy from config-ui/src/plugins/register/dora/config.ts
copy to config-ui/src/plugins/register/base/config.ts
index 623181a90..684ee1970 100644
--- a/config-ui/src/plugins/register/dora/config.ts
+++ b/config-ui/src/plugins/register/base/config.ts
@@ -16,14 +16,27 @@
  *
  */
 
-import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+import { PluginType } from '../../types';
 
 import Icon from './assets/icon.svg';
 
-export const DORAConfig: PluginConfigType = {
-  plugin: Plugins.DORA,
-  name: 'DORA',
+export const BaseConnectionConfig = {
+  type: PluginType.Connection,
+  plugin: undefined,
+  name: undefined,
+  icon: Icon,
+  isBeta: undefined,
+  connection: {
+    initialValues: [],
+    fields: [],
+  },
+  entities: [],
+  transformation: {},
+} as const;
+
+export const BasePipelineConfig = {
   type: PluginType.Pipeline,
+  plugin: undefined,
+  name: undefined,
   icon: Icon,
-};
+} as const;
diff --git a/config-ui/src/plugins/register/base/connection-fields.ts b/config-ui/src/plugins/register/base/connection-fields.ts
new file mode 100644
index 000000000..8b4ce6e17
--- /dev/null
+++ b/config-ui/src/plugins/register/base/connection-fields.ts
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ *
+ */
+
+export const ConnectionName = (custom = {}) => ({
+  key: 'name',
+  label: 'Connection Name',
+  type: 'text' as const,
+  required: true,
+  ...custom,
+});
+
+export const ConnectionEndpoint = (custom = {}) => ({
+  key: 'endpoint',
+  label: 'Endpoint URL',
+  type: 'text' as const,
+  required: true,
+  ...custom,
+});
+
+export const ConnectionUsername = (custom = {}) => ({
+  key: 'username',
+  label: 'Username',
+  type: 'text' as const,
+  required: true,
+  placeholder: 'Username',
+  ...custom,
+});
+
+export const ConnectionPassword = (custom = {}) => ({
+  key: 'password',
+  label: 'Password',
+  type: 'password' as const,
+  required: true,
+  placeholder: 'Password',
+  ...custom,
+});
+
+export const ConnectionToken = (custom = {}) => ({
+  key: 'token',
+  label: 'Token',
+  type: 'password' as const,
+  required: true,
+  ...custom,
+});
+
+export const ConnectionProxy = (custom = {}) => ({
+  key: 'proxy',
+  label: 'Proxy URL',
+  type: 'text' as const,
+  placeholder: 'eg. http://proxy.localhost:8080',
+  tooltip: 'Add a proxy if your network can not access Server directly.',
+  ...custom,
+});
+
+export const ConnectionRatelimit = (custom = {}) => ({
+  key: 'rateLimitPerHour',
+  label: 'Fixed Rate Limit (per hour)',
+  type: 'rateLimit' as const,
+  tooltip: 'Rate Limit requests per hour,\nEnter a numeric value > 0 to enable.',
+  ...custom,
+});
+
+export const ConnectionGitHubToken = () => ({
+  key: 'token',
+  label: 'Basic Auth Token',
+  type: 'githubToken' as const,
+  required: true,
+  tooltip: "Due to Github's rate limit, input more tokens, \ncomma separated, to accelerate data collection.",
+});
+
+export const ConnectionGitHubGraphql = () => ({
+  key: 'enableGraphql',
+  label: 'Use Graphql APIs',
+  type: 'switch' as const,
+  tooltip:
+    'GraphQL APIs are 10+ times faster than REST APIs, but it may not be supported in GitHub on-premise versions.',
+  initialValue: true,
+});
+
+export const ConnectionGitLabToken = () => ({
+  key: 'token',
+  label: 'Access Token',
+  type: 'gitlabToken' as const,
+  required: true,
+  placeholder: 'eg. ff9d1ad0e5c04f1f98fa',
+});
diff --git a/config-ui/src/plugins/register/jenkins/hooks/index.ts b/config-ui/src/plugins/register/base/index.ts
similarity index 92%
rename from config-ui/src/plugins/register/jenkins/hooks/index.ts
rename to config-ui/src/plugins/register/base/index.ts
index b935965d7..8e1d25aad 100644
--- a/config-ui/src/plugins/register/jenkins/hooks/index.ts
+++ b/config-ui/src/plugins/register/base/index.ts
@@ -16,4 +16,5 @@
  *
  */
 
-export * from './user-proxy-prefix';
+export * from './config';
+export * from './connection-fields';
diff --git a/config-ui/src/plugins/register/bitbucket/assets/icon.svg b/config-ui/src/plugins/register/bitbucket/assets/icon.svg
index d68937906..c1c19de57 100644
--- a/config-ui/src/plugins/register/bitbucket/assets/icon.svg
+++ b/config-ui/src/plugins/register/bitbucket/assets/icon.svg
@@ -1,19 +1,5 @@
-<!--
-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.
--->
 <svg width="100" height="100" viewBox="0 0 52 48" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <path d="M1.68758 0.51967C1.44443 0.516534 1.20354 0.566658 0.98183 0.666529C0.760116 0.766397 0.562951 0.913588 0.404177 1.09776C0.245403 1.28194 0.128869 1.49864 0.0627574 1.73265C-0.00335344 1.96666 -0.0174403 2.2123 0.0214867 2.45233L7.09404 45.3875C7.18216 45.9129 7.45259 46.3904 7.85783 46.7363C8.26307 47.0821 8.77721 47.2741 9.30994 47.2785H43.2399C43.6392 47.2836 44.0271 47.1451 44.3329 46.8883C44.6387 46.6314 44.8421 46.2732 44.906 45.879L49.1639 19.7392H33.4921L31.4689 31.5 [...]
+    <path
+        d="M1.68758 0.51967C1.44443 0.516534 1.20354 0.566658 0.98183 0.666529C0.760116 0.766397 0.562951 0.913588 0.404177 1.09776C0.245403 1.28194 0.128869 1.49864 0.0627574 1.73265C-0.00335344 1.96666 -0.0174403 2.2123 0.0214867 2.45233L7.09404 45.3875C7.18216 45.9129 7.45259 46.3904 7.85783 46.7363C8.26307 47.0821 8.77721 47.2741 9.30994 47.2785H43.2399C43.6392 47.2836 44.0271 47.1451 44.3329 46.8883C44.6387 46.6314 44.8421 46.2732 44.906 45.879L49.1639 19.7392H33.4921L31.4689 31.550 [...]
+        fill="#7497F7" />
 </svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/bitbucket/config.ts b/config-ui/src/plugins/register/bitbucket/config.ts
index 51ba32ee8..3364aeb49 100644
--- a/config-ui/src/plugins/register/bitbucket/config.ts
+++ b/config-ui/src/plugins/register/bitbucket/config.ts
@@ -17,62 +17,44 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import {
+  BaseConnectionConfig,
+  ConnectionName,
+  ConnectionEndpoint,
+  ConnectionUsername,
+  ConnectionPassword,
+  ConnectionProxy,
+  ConnectionRatelimit,
+} from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const BitBucketConfig: PluginConfigType = {
-  plugin: Plugins.BitBucket,
+  ...BaseConnectionConfig,
+  plugin: 'bitbucket',
   name: 'BitBucket',
-  type: PluginType.Connection,
-  isBeta: true,
   icon: Icon,
+  isBeta: true,
   connection: {
-    initialValues: {
-      rateLimitPerHour: 10000,
-    },
     fields: [
-      {
-        key: 'name',
-        label: 'Connection Name',
-        type: 'text',
-        required: true,
+      ConnectionName({
+        initialValue: 'BitBucket',
         placeholder: 'eg. BitBucket',
-      },
-      {
-        key: 'endpoint',
-        label: 'Endpoint URL',
-        type: 'text',
-        required: true,
+      }),
+      ConnectionEndpoint({
+        initialValue: 'https://api.bitbucket.org/2.0/',
         placeholder: 'eg. https://api.bitbucket.org/2.0/',
-      },
-      {
-        key: 'username',
-        label: 'Username',
-        type: 'text',
-        required: true,
-        placeholder: 'eg. admin',
-      },
-      {
-        key: 'password',
+      }),
+      ConnectionUsername(),
+      ConnectionPassword({
         label: 'App Password',
-        type: 'password',
-        required: true,
-        placeholder: 'eg. ************',
-      },
-      {
-        key: 'proxy',
-        label: 'Proxy URL',
-        type: 'text',
-        placeholder: 'eg. http://proxy.localhost:8080',
-        tooltip: 'Add a proxy if your network can not access BitBucket directly.',
-      },
-      {
-        key: 'rateLimitPerHour',
-        label: 'Fixed Rate Limit (per hour)',
-        type: 'rateLimit',
-        tooltip: 'Rate Limit requests per hour,\nEnter a numeric value > 0 to enable.',
-      },
+        placeholder: 'App Password',
+      }),
+      ConnectionProxy(),
+      ConnectionRatelimit({
+        initialValue: 10000,
+      }),
     ],
   },
   entities: [],
diff --git a/config-ui/src/plugins/register/dbt/assets/icon.svg b/config-ui/src/plugins/register/dbt/assets/icon.svg
deleted file mode 100644
index 379fbdc0a..000000000
--- a/config-ui/src/plugins/register/dbt/assets/icon.svg
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-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.
--->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#7497F7" height="800px" width="800px" version="1.1" viewBox="0 0 231.087 231.087" enable-background="new 0 0 231.087 231.087">
-    <g>
-        <path d="m230.042,142.627c-1.871-2.744-5.612-3.452-8.355-1.581l-65.513,44.667-14.55-19.473c-1.526-2.036-4.241-2.977-6.788-2.129-3.185,1.06-4.908,4.501-3.848,7.686l11.908,35.785c0.45,1.33 1.184,2.645 2.18,3.757 3.94,4.401 10.702,4.776 15.104,0.836l.777-.695 68.129-60.985c2.216-1.981 2.676-5.346 0.956-7.868z"/>
-        <path d="m120.211,190.676h-108.211v-162.49h158.43v124.823c0,3.313 2.687,6 6,6s6-2.687 6-6v-130.823c0-3.313-2.687-6-6-6h-170.43c-3.313,0-6,2.687-6,6v174.49c0,3.313 2.687,6 6,6h114.211c3.313,0 6-2.687 6-6 0-3.314-2.687-6-6-6z"/>
-        <path d="m139.694,53.855h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,79.79h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,105.725h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m145.694,137.659c0-3.313-2.687-6-6-6h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.314,0 6-2.686 6-6z"/>
-        <path d="M42.735,156.329c-3.313,0-6,2.687-6,6s2.687,6,6,6h48.479c3.313,0,6-2.687,6-6s-2.687-6-6-6H42.735z"/>
-    </g>
-</svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/dbt/config.ts b/config-ui/src/plugins/register/dbt/config.ts
index a44c69534..8b19b8ea9 100644
--- a/config-ui/src/plugins/register/dbt/config.ts
+++ b/config-ui/src/plugins/register/dbt/config.ts
@@ -17,13 +17,11 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
 
-import Icon from './assets/icon.svg';
+import { BasePipelineConfig } from '../base';
 
 export const DBTConfig: PluginConfigType = {
-  plugin: Plugins.DBT,
+  ...BasePipelineConfig,
+  plugin: 'dbt',
   name: 'DBT',
-  type: PluginType.Pipeline,
-  icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/dora/assets/icon.svg b/config-ui/src/plugins/register/dora/assets/icon.svg
deleted file mode 100644
index 379fbdc0a..000000000
--- a/config-ui/src/plugins/register/dora/assets/icon.svg
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-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.
--->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#7497F7" height="800px" width="800px" version="1.1" viewBox="0 0 231.087 231.087" enable-background="new 0 0 231.087 231.087">
-    <g>
-        <path d="m230.042,142.627c-1.871-2.744-5.612-3.452-8.355-1.581l-65.513,44.667-14.55-19.473c-1.526-2.036-4.241-2.977-6.788-2.129-3.185,1.06-4.908,4.501-3.848,7.686l11.908,35.785c0.45,1.33 1.184,2.645 2.18,3.757 3.94,4.401 10.702,4.776 15.104,0.836l.777-.695 68.129-60.985c2.216-1.981 2.676-5.346 0.956-7.868z"/>
-        <path d="m120.211,190.676h-108.211v-162.49h158.43v124.823c0,3.313 2.687,6 6,6s6-2.687 6-6v-130.823c0-3.313-2.687-6-6-6h-170.43c-3.313,0-6,2.687-6,6v174.49c0,3.313 2.687,6 6,6h114.211c3.313,0 6-2.687 6-6 0-3.314-2.687-6-6-6z"/>
-        <path d="m139.694,53.855h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,79.79h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,105.725h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m145.694,137.659c0-3.313-2.687-6-6-6h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.314,0 6-2.686 6-6z"/>
-        <path d="M42.735,156.329c-3.313,0-6,2.687-6,6s2.687,6,6,6h48.479c3.313,0,6-2.687,6-6s-2.687-6-6-6H42.735z"/>
-    </g>
-</svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/dora/config.ts b/config-ui/src/plugins/register/dora/config.ts
index 623181a90..fe7f06084 100644
--- a/config-ui/src/plugins/register/dora/config.ts
+++ b/config-ui/src/plugins/register/dora/config.ts
@@ -17,13 +17,11 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
 
-import Icon from './assets/icon.svg';
+import { BasePipelineConfig } from '../base';
 
 export const DORAConfig: PluginConfigType = {
-  plugin: Plugins.DORA,
+  ...BasePipelineConfig,
+  plugin: 'dora',
   name: 'DORA',
-  type: PluginType.Pipeline,
-  icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/feishu/assets/icon.svg b/config-ui/src/plugins/register/feishu/assets/icon.svg
deleted file mode 100644
index 379fbdc0a..000000000
--- a/config-ui/src/plugins/register/feishu/assets/icon.svg
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-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.
--->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#7497F7" height="800px" width="800px" version="1.1" viewBox="0 0 231.087 231.087" enable-background="new 0 0 231.087 231.087">
-    <g>
-        <path d="m230.042,142.627c-1.871-2.744-5.612-3.452-8.355-1.581l-65.513,44.667-14.55-19.473c-1.526-2.036-4.241-2.977-6.788-2.129-3.185,1.06-4.908,4.501-3.848,7.686l11.908,35.785c0.45,1.33 1.184,2.645 2.18,3.757 3.94,4.401 10.702,4.776 15.104,0.836l.777-.695 68.129-60.985c2.216-1.981 2.676-5.346 0.956-7.868z"/>
-        <path d="m120.211,190.676h-108.211v-162.49h158.43v124.823c0,3.313 2.687,6 6,6s6-2.687 6-6v-130.823c0-3.313-2.687-6-6-6h-170.43c-3.313,0-6,2.687-6,6v174.49c0,3.313 2.687,6 6,6h114.211c3.313,0 6-2.687 6-6 0-3.314-2.687-6-6-6z"/>
-        <path d="m139.694,53.855h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,79.79h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,105.725h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m145.694,137.659c0-3.313-2.687-6-6-6h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.314,0 6-2.686 6-6z"/>
-        <path d="M42.735,156.329c-3.313,0-6,2.687-6,6s2.687,6,6,6h48.479c3.313,0,6-2.687,6-6s-2.687-6-6-6H42.735z"/>
-    </g>
-</svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/feishu/config.ts b/config-ui/src/plugins/register/feishu/config.ts
index 10c2b78c1..6be499ffb 100644
--- a/config-ui/src/plugins/register/feishu/config.ts
+++ b/config-ui/src/plugins/register/feishu/config.ts
@@ -17,13 +17,11 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
 
-import Icon from './assets/icon.svg';
+import { BasePipelineConfig } from '../base';
 
 export const FeiShuConfig: PluginConfigType = {
-  plugin: Plugins.FeiShu,
+  ...BasePipelineConfig,
+  plugin: 'feishu',
   name: 'FeiShu',
-  type: PluginType.Pipeline,
-  icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/gitee/assets/icon.svg b/config-ui/src/plugins/register/gitee/assets/icon.svg
index a1fafc0a4..eb56342dc 100644
--- a/config-ui/src/plugins/register/gitee/assets/icon.svg
+++ b/config-ui/src/plugins/register/gitee/assets/icon.svg
@@ -1,19 +1,5 @@
-<!--
-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.
--->
 <svg width="100" height="100" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <path fill-rule="evenodd" clip-rule="evenodd" d="M30 4C44.3597 4 56 15.6403 56 30C56 44.3597 44.3597 56 30 56C15.6403 56 4 44.3597 4 30C4 15.6403 15.6403 4 30 4ZM43.1616 15.5556C43.1614 15.5556 43.1611 15.5556 43.1608 15.5564H25.1856C19.8673 15.5564 15.5557 19.8677 15.5557 25.1863V43.1615C15.5557 43.8706 16.1305 44.4454 16.8396 44.4454H35.7781C40.5645 44.4454 44.4447 40.5653 44.4447 35.7789V28.3962C44.4447 27.6871 43.8698 27.1123 43.1607 27.1123H28.3949C27.6859 27.1126 27.1112 27.687 [...]
+    <path fill-rule="evenodd" clip-rule="evenodd"
+        d="M30 4C44.3597 4 56 15.6403 56 30C56 44.3597 44.3597 56 30 56C15.6403 56 4 44.3597 4 30C4 15.6403 15.6403 4 30 4ZM43.1616 15.5556C43.1614 15.5556 43.1611 15.5556 43.1608 15.5564H25.1856C19.8673 15.5564 15.5557 19.8677 15.5557 25.1863V43.1615C15.5557 43.8706 16.1305 44.4454 16.8396 44.4454H35.7781C40.5645 44.4454 44.4447 40.5653 44.4447 35.7789V28.3962C44.4447 27.6871 43.8698 27.1123 43.1607 27.1123H28.3949C27.6859 27.1126 27.1112 27.6873 27.1106 28.3962L27.1098 31.606C27.1093 3 [...]
+        fill="#7497F7" />
 </svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/gitee/config.ts b/config-ui/src/plugins/register/gitee/config.ts
index 24685ff03..64d528f49 100644
--- a/config-ui/src/plugins/register/gitee/config.ts
+++ b/config-ui/src/plugins/register/gitee/config.ts
@@ -17,13 +17,14 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import { BasePipelineConfig } from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const GiteeConfig: PluginConfigType = {
-  plugin: Plugins.Gitee,
+  ...BasePipelineConfig,
+  plugin: 'gitee',
   name: 'Gitee',
-  type: PluginType.Pipeline,
   icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/gitextractor/assets/icon.svg b/config-ui/src/plugins/register/gitextractor/assets/icon.svg
index 97c0d6885..f381c1841 100644
--- a/config-ui/src/plugins/register/gitextractor/assets/icon.svg
+++ b/config-ui/src/plugins/register/gitextractor/assets/icon.svg
@@ -1,19 +1,3 @@
-<!--
-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.
--->
 <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="97" height="97">
     <path fill="#7497F7" d="M92.71 44.408 52.591 4.291c-2.31-2.311-6.057-2.311-8.369 0l-8.33 8.332L46.459 23.19c2.456-.83 5.272-.273 7.229 1.685 1.969 1.97 2.521 4.81 1.67 7.275l10.186 10.185c2.465-.85 5.307-.3 7.275 1.671 2.75 2.75 2.75 7.206 0 9.958-2.752 2.751-7.208 2.751-9.961 0-2.068-2.07-2.58-5.11-1.531-7.658l-9.5-9.499v24.997c.67.332 1.303.774 1.861 1.332 2.75 2.75 2.75 7.206 0 9.959-2.75 2.749-7.209 2.749-9.957 0-2.75-2.754-2.75-7.21 0-9.959.68-.679 1.467-1.193 2.307-1.537v-25.23 [...]
 </svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/gitextractor/config.ts b/config-ui/src/plugins/register/gitextractor/config.ts
index 1f750a6ed..400941ead 100644
--- a/config-ui/src/plugins/register/gitextractor/config.ts
+++ b/config-ui/src/plugins/register/gitextractor/config.ts
@@ -17,13 +17,14 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import { BasePipelineConfig } from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const GitExtractorConfig: PluginConfigType = {
-  plugin: Plugins.GitExtractor,
+  ...BasePipelineConfig,
+  plugin: 'gitextractor',
   name: 'GitExtractor',
-  type: PluginType.Pipeline,
   icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/github/assets/icon.svg b/config-ui/src/plugins/register/github/assets/icon.svg
index 67375bbfd..a2c8de27a 100644
--- a/config-ui/src/plugins/register/github/assets/icon.svg
+++ b/config-ui/src/plugins/register/github/assets/icon.svg
@@ -1,19 +1,5 @@
-<!--
-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.
--->
 <svg width="100" height="100" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <path d="M18 3C9.7125 3 3 9.7125 3 18C2.9983 21.1489 3.98822 24.2184 5.82933 26.773C7.67043 29.3276 10.2692 31.2376 13.257 32.232C14.007 32.3625 14.2875 31.9125 14.2875 31.518C14.2875 31.1625 14.268 29.982 14.268 28.725C10.5 29.4195 9.525 27.807 9.225 26.9625C9.0555 26.5305 8.325 25.2 7.6875 24.843C7.1625 24.5625 6.4125 23.868 7.668 23.85C8.85 23.8305 9.693 24.9375 9.975 25.3875C11.325 27.6555 13.482 27.018 14.343 26.625C14.475 25.65 14.868 24.9945 15.3 24.6195C11.9625 24.2445 8.475  [...]
+    <path
+        d="M18 3C9.7125 3 3 9.7125 3 18C2.9983 21.1489 3.98822 24.2184 5.82933 26.773C7.67043 29.3276 10.2692 31.2376 13.257 32.232C14.007 32.3625 14.2875 31.9125 14.2875 31.518C14.2875 31.1625 14.268 29.982 14.268 28.725C10.5 29.4195 9.525 27.807 9.225 26.9625C9.0555 26.5305 8.325 25.2 7.6875 24.843C7.1625 24.5625 6.4125 23.868 7.668 23.85C8.85 23.8305 9.693 24.9375 9.975 25.3875C11.325 27.6555 13.482 27.018 14.343 26.625C14.475 25.65 14.868 24.9945 15.3 24.6195C11.9625 24.2445 8.475 22 [...]
+        fill="#7497F7" />
 </svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/github/components/miller-columns/use-miller-columns.ts b/config-ui/src/plugins/register/github/components/miller-columns/use-miller-columns.ts
index 921047760..1bb248a8a 100644
--- a/config-ui/src/plugins/register/github/components/miller-columns/use-miller-columns.ts
+++ b/config-ui/src/plugins/register/github/components/miller-columns/use-miller-columns.ts
@@ -19,8 +19,9 @@
 import { useState, useEffect, useMemo, useCallback } from 'react';
 import { ItemType, ColumnType } from 'miller-columns-select';
 
+import { useProxyPrefix } from '@/hooks';
+
 import type { ScopeItemType } from '../../types';
-import { useProxyPrefix } from '../../hooks';
 import * as API from '../../api';
 
 const DEFAULT_PAGE_SIZE = 30;
@@ -46,7 +47,10 @@ export const useMillerColumns = ({ connectionId }: UseMillerColumnsProps) => {
   const [loadedIds, setLoadedIds] = useState<ID[]>([]);
   const [mapPage, setMapPage] = useState<MapPageType>({});
 
-  const prefix = useProxyPrefix(connectionId);
+  const prefix = useProxyPrefix({
+    plugin: 'github',
+    connectionId,
+  });
 
   const formatOrgs = (orgs: any, parentId: ID | null = null) =>
     orgs.map((it: any) => ({
diff --git a/config-ui/src/plugins/register/github/components/repo-selector/use-repo-selector.ts b/config-ui/src/plugins/register/github/components/repo-selector/use-repo-selector.ts
index 7c357f987..bfd09acc1 100644
--- a/config-ui/src/plugins/register/github/components/repo-selector/use-repo-selector.ts
+++ b/config-ui/src/plugins/register/github/components/repo-selector/use-repo-selector.ts
@@ -18,8 +18,9 @@
 
 import { useState, useEffect, useMemo } from 'react';
 
+import { useProxyPrefix } from '@/hooks';
+
 import type { ScopeItemType } from '../../types';
-import { useProxyPrefix } from '../../hooks';
 import * as API from '../../api';
 
 export interface UseRepoSelectorProps {
@@ -31,7 +32,10 @@ export const useRepoSelector = ({ connectionId }: UseRepoSelectorProps) => {
   const [items, setItems] = useState<ScopeItemType[]>([]);
   const [search, setSearch] = useState('');
 
-  const prefix = useProxyPrefix(connectionId);
+  const prefix = useProxyPrefix({
+    plugin: 'github',
+    connectionId,
+  });
 
   useEffect(() => {
     if (!search) return;
diff --git a/config-ui/src/plugins/register/github/config.ts b/config-ui/src/plugins/register/github/config.ts
index d67eda0b7..138248abf 100644
--- a/config-ui/src/plugins/register/github/config.ts
+++ b/config-ui/src/plugins/register/github/config.ts
@@ -17,62 +17,40 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import {
+  BaseConnectionConfig,
+  ConnectionName,
+  ConnectionEndpoint,
+  ConnectionGitHubToken,
+  ConnectionGitHubGraphql,
+  ConnectionProxy,
+  ConnectionRatelimit,
+} from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const GitHubConfig: PluginConfigType = {
-  plugin: Plugins.GitHub,
+  ...BaseConnectionConfig,
+  plugin: 'github',
   name: 'GitHub',
-  type: PluginType.Connection,
   icon: Icon,
   connection: {
-    initialValues: {
-      enableGraphql: true,
-      rateLimitPerHour: 4500,
-    },
     fields: [
-      {
-        key: 'name',
-        label: 'Connection Name',
-        type: 'text',
-        required: true,
+      ConnectionName({
+        initialValue: 'GitHub',
         placeholder: 'eg. GitHub',
-      },
-      {
-        key: 'endpoint',
-        label: 'Endpoint URL',
-        type: 'text',
-        required: true,
+      }),
+      ConnectionEndpoint({
+        initialValue: 'https://api.github.com/',
         placeholder: 'eg. https://api.github.com/',
-      },
-      {
-        key: 'token',
-        label: 'Basic Auth Token',
-        type: 'githubToken',
-        required: true,
-        tooltip: "Due to Github's rate limit, input more tokens, \ncomma separated, to accelerate data collection.",
-      },
-      {
-        key: 'proxy',
-        label: 'Proxy URL',
-        type: 'text',
-        placeholder: 'eg. http://proxy.localhost:8080',
-        tooltip: 'Add a proxy if your network can not access GitHub directly.',
-      },
-      {
-        key: 'enableGraphql',
-        label: 'Use Graphql APIs',
-        type: 'switch',
-        tooltip:
-          'GraphQL APIs are 10+ times faster than REST APIs, but it may not be supported in GitHub on-premise versions.',
-      },
-      {
-        key: 'rateLimitPerHour',
-        label: 'Fixed Rate Limit (per hour)',
-        type: 'rateLimit',
-        tooltip: 'Rate Limit requests per hour,\nEnter a numeric value > 0 to enable.',
-      },
+      }),
+      ConnectionGitHubToken(),
+      ConnectionGitHubGraphql(),
+      ConnectionProxy(),
+      ConnectionRatelimit({
+        initialValue: 4500,
+      }),
     ],
   },
   entities: ['CODE', 'TICKET', 'CODEREVIEW', 'CROSS', 'CICD'],
diff --git a/config-ui/src/plugins/register/github/hooks/index.ts b/config-ui/src/plugins/register/github/hooks/index.ts
deleted file mode 100644
index b935965d7..000000000
--- a/config-ui/src/plugins/register/github/hooks/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- *
- */
-
-export * from './user-proxy-prefix';
diff --git a/config-ui/src/plugins/register/github/hooks/user-proxy-prefix.ts b/config-ui/src/plugins/register/github/hooks/user-proxy-prefix.ts
deleted file mode 100644
index cc821172a..000000000
--- a/config-ui/src/plugins/register/github/hooks/user-proxy-prefix.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 { useMemo } from 'react';
-
-export const useProxyPrefix = (connectionId: ID) =>
-  useMemo(() => `/plugins/github/connections/${connectionId}/proxy/rest`, [connectionId]);
diff --git a/config-ui/src/plugins/register/github_graphql/assets/icon.svg b/config-ui/src/plugins/register/github_graphql/assets/icon.svg
index 67375bbfd..a2c8de27a 100644
--- a/config-ui/src/plugins/register/github_graphql/assets/icon.svg
+++ b/config-ui/src/plugins/register/github_graphql/assets/icon.svg
@@ -1,19 +1,5 @@
-<!--
-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.
--->
 <svg width="100" height="100" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <path d="M18 3C9.7125 3 3 9.7125 3 18C2.9983 21.1489 3.98822 24.2184 5.82933 26.773C7.67043 29.3276 10.2692 31.2376 13.257 32.232C14.007 32.3625 14.2875 31.9125 14.2875 31.518C14.2875 31.1625 14.268 29.982 14.268 28.725C10.5 29.4195 9.525 27.807 9.225 26.9625C9.0555 26.5305 8.325 25.2 7.6875 24.843C7.1625 24.5625 6.4125 23.868 7.668 23.85C8.85 23.8305 9.693 24.9375 9.975 25.3875C11.325 27.6555 13.482 27.018 14.343 26.625C14.475 25.65 14.868 24.9945 15.3 24.6195C11.9625 24.2445 8.475  [...]
+    <path
+        d="M18 3C9.7125 3 3 9.7125 3 18C2.9983 21.1489 3.98822 24.2184 5.82933 26.773C7.67043 29.3276 10.2692 31.2376 13.257 32.232C14.007 32.3625 14.2875 31.9125 14.2875 31.518C14.2875 31.1625 14.268 29.982 14.268 28.725C10.5 29.4195 9.525 27.807 9.225 26.9625C9.0555 26.5305 8.325 25.2 7.6875 24.843C7.1625 24.5625 6.4125 23.868 7.668 23.85C8.85 23.8305 9.693 24.9375 9.975 25.3875C11.325 27.6555 13.482 27.018 14.343 26.625C14.475 25.65 14.868 24.9945 15.3 24.6195C11.9625 24.2445 8.475 22 [...]
+        fill="#7497F7" />
 </svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/github_graphql/config.ts b/config-ui/src/plugins/register/github_graphql/config.ts
index f7a847b42..c21edbfba 100644
--- a/config-ui/src/plugins/register/github_graphql/config.ts
+++ b/config-ui/src/plugins/register/github_graphql/config.ts
@@ -17,13 +17,14 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import { BasePipelineConfig } from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const GitHubGraphqlConfig: PluginConfigType = {
-  plugin: Plugins.GitHubGraphql,
+  ...BasePipelineConfig,
+  plugin: 'github_graphql',
   name: 'GitHubGraphql',
-  type: PluginType.Pipeline,
   icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/gitlab/assets/icon.svg b/config-ui/src/plugins/register/gitlab/assets/icon.svg
index 0943bd442..fe7a104cc 100644
--- a/config-ui/src/plugins/register/gitlab/assets/icon.svg
+++ b/config-ui/src/plugins/register/gitlab/assets/icon.svg
@@ -1,19 +1,5 @@
-<!--
-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.
--->
 <svg width="100" height="100" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M8.80197 4.12524L12 15.0002H24L27.198 4.12524C27.2339 4.00187 27.3085 3.8933 27.4108 3.81551C27.5131 3.73772 27.6377 3.69483 27.7662 3.69315C27.8947 3.69147 28.0203 3.73109 28.1246 3.80618C28.2289 3.88126 28.3063 3.98785 28.3455 4.11024L33.588 20.4962C33.6352 20.6437 33.6356 20.8022 33.5891 20.9499C33.5426 21.0976 33.4516 21.2273 33.3285 21.3212L18 33.0002L2.66997 21.3212C2.5471 21.2272 2.45635 21.0974 2.41016 20.9497C2.36397 20.8019 2.3646 20.6436 2.41197 20.4962L7.65447 4.1102 [...]
-</svg>
+    <path
+        d="M8.80197 4.12524L12 15.0002H24L27.198 4.12524C27.2339 4.00187 27.3085 3.8933 27.4108 3.81551C27.5131 3.73772 27.6377 3.69483 27.7662 3.69315C27.8947 3.69147 28.0203 3.73109 28.1246 3.80618C28.2289 3.88126 28.3063 3.98785 28.3455 4.11024L33.588 20.4962C33.6352 20.6437 33.6356 20.8022 33.5891 20.9499C33.5426 21.0976 33.4516 21.2273 33.3285 21.3212L18 33.0002L2.66997 21.3212C2.5471 21.2272 2.45635 21.0974 2.41016 20.9497C2.36397 20.8019 2.3646 20.6436 2.41197 20.4962L7.65447 4.11 [...]
+        fill="#7497F7" />
+</svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/gitlab/components/miller-columns/use-miller-columns.ts b/config-ui/src/plugins/register/gitlab/components/miller-columns/use-miller-columns.ts
index ea2d4594a..67a510f9b 100644
--- a/config-ui/src/plugins/register/gitlab/components/miller-columns/use-miller-columns.ts
+++ b/config-ui/src/plugins/register/gitlab/components/miller-columns/use-miller-columns.ts
@@ -19,8 +19,9 @@
 import { useState, useEffect, useMemo } from 'react';
 import { ItemType, ColumnType } from 'miller-columns-select';
 
+import { useProxyPrefix } from '@/hooks';
+
 import type { ScopeItemType } from '../../types';
-import { useProxyPrefix } from '../../hooks';
 import * as API from '../../api';
 
 const DEFAULT_PAGE_SIZE = 20;
@@ -56,7 +57,10 @@ export const useMillerColumns = ({ connectionId }: UseMillerColumnsProps) => {
   const [expandedIds, setExpandedIds] = useState<ID[]>([]);
   const [map, setMap] = useState<MapType>({});
 
-  const prefix = useProxyPrefix(connectionId);
+  const prefix = useProxyPrefix({
+    plugin: 'gitlab',
+    connectionId,
+  });
 
   const formatGroups = (arr: any, parentId: ID | null = null): GitLabItemType[] =>
     arr.map((it: any) => ({
diff --git a/config-ui/src/plugins/register/gitlab/components/project-selector/use-project-selector.ts b/config-ui/src/plugins/register/gitlab/components/project-selector/use-project-selector.ts
index b6f8bdbc7..adcae293c 100644
--- a/config-ui/src/plugins/register/gitlab/components/project-selector/use-project-selector.ts
+++ b/config-ui/src/plugins/register/gitlab/components/project-selector/use-project-selector.ts
@@ -18,8 +18,9 @@
 
 import { useState, useEffect, useMemo } from 'react';
 
+import { useProxyPrefix } from '@/hooks';
+
 import type { ScopeItemType } from '../../types';
-import { useProxyPrefix } from '../../hooks';
 import * as API from '../../api';
 
 export interface UseProjectSelectorProps {
@@ -32,7 +33,10 @@ export const useProjectSelector = ({ connectionId }: UseProjectSelectorProps) =>
   const [search, setSearch] = useState('');
   const [membership, setMembership] = useState(true);
 
-  const prefix = useProxyPrefix(connectionId);
+  const prefix = useProxyPrefix({
+    plugin: 'gitlab',
+    connectionId,
+  });
 
   useEffect(() => {
     if (!search) return;
diff --git a/config-ui/src/plugins/register/gitlab/config.ts b/config-ui/src/plugins/register/gitlab/config.ts
index 174279667..ec9deebf7 100644
--- a/config-ui/src/plugins/register/gitlab/config.ts
+++ b/config-ui/src/plugins/register/gitlab/config.ts
@@ -17,54 +17,38 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import {
+  BaseConnectionConfig,
+  ConnectionName,
+  ConnectionEndpoint,
+  ConnectionGitLabToken,
+  ConnectionProxy,
+  ConnectionRatelimit,
+} from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const GitLabConfig: PluginConfigType = {
-  plugin: Plugins.GitLab,
+  ...BaseConnectionConfig,
+  plugin: 'gitlab',
   name: 'GitLab',
-  type: PluginType.Connection,
   icon: Icon,
   connection: {
-    initialValues: {
-      rateLimitPerHour: 5000,
-    },
     fields: [
-      {
-        key: 'name',
-        label: 'Connection Name',
-        type: 'text',
-        required: true,
+      ConnectionName({
+        initialValue: 'GitLab',
         placeholder: 'eg. GitLab',
-      },
-      {
-        key: 'endpoint',
-        label: 'Endpoint URL',
-        type: 'text',
-        required: true,
+      }),
+      ConnectionEndpoint({
+        initialValue: 'https://gitlab.com/api/v4/',
         placeholder: 'eg. https://gitlab.com/api/v4/',
-      },
-      {
-        key: 'token',
-        label: 'Access Token',
-        type: 'gitlabToken',
-        required: true,
-        placeholder: 'eg. ff9d1ad0e5c04f1f98fa',
-      },
-      {
-        key: 'proxy',
-        label: 'Proxy URL',
-        type: 'text',
-        placeholder: 'eg. http://proxy.localhost:8080',
-        tooltip: 'Add a proxy if your network can not access GitLab directly.',
-      },
-      {
-        key: 'rateLimitPerHour',
-        label: 'Fixed Rate Limit (per hour)',
-        type: 'rateLimit',
-        tooltip: 'Rate Limit requests per hour,\nEnter a numeric value > 0 to enable.',
-      },
+      }),
+      ConnectionGitLabToken(),
+      ConnectionProxy(),
+      ConnectionRatelimit({
+        initialValue: 5000,
+      }),
     ],
   },
   entities: ['CODE', 'TICKET', 'CODEREVIEW', 'CROSS', 'CICD'],
diff --git a/config-ui/src/plugins/register/gitlab/hooks/index.ts b/config-ui/src/plugins/register/gitlab/hooks/index.ts
deleted file mode 100644
index b935965d7..000000000
--- a/config-ui/src/plugins/register/gitlab/hooks/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- *
- */
-
-export * from './user-proxy-prefix';
diff --git a/config-ui/src/plugins/register/gitlab/hooks/user-proxy-prefix.ts b/config-ui/src/plugins/register/gitlab/hooks/user-proxy-prefix.ts
deleted file mode 100644
index 753e24108..000000000
--- a/config-ui/src/plugins/register/gitlab/hooks/user-proxy-prefix.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 { useMemo } from 'react';
-
-export const useProxyPrefix = (connectionId: ID) =>
-  useMemo(() => `/plugins/gitlab/connections/${connectionId}/proxy/rest`, [connectionId]);
diff --git a/config-ui/src/plugins/register/jenkins/assets/icon.svg b/config-ui/src/plugins/register/jenkins/assets/icon.svg
index 94ad53162..c3c239927 100644
--- a/config-ui/src/plugins/register/jenkins/assets/icon.svg
+++ b/config-ui/src/plugins/register/jenkins/assets/icon.svg
@@ -1,22 +1,14 @@
-<!--
-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.
--->
 <svg width="100" height="100" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M25.2912 2.67189C23.4918 1.74972 21.1902 1 18.4387 1C5.88829 1 5.42346 9.33694 5.42346 9.33694C5.42346 9.33694 3.3992 10.0417 2.79942 13.2055C2.43206 15.1248 2.91188 16.4968 3.34672 17.284C2.92688 17.7338 2.57451 18.2662 2.30461 18.8659C1.66734 20.2829 1.5174 21.9548 1.89226 23.5817C2.26712 25.2086 3.11431 26.6256 4.28388 27.5702C5.54341 28.5899 7.08785 28.9572 8.51232 28.5899C8.5873 28.5749 8.65477 28.5524 8.72974 28.5299C11.4288 32.6159 15.5372 35 20.0131 35C27.8927 35 34.3103 [...]
-<path d="M22.0673 25.2461C23.7317 25.6809 24.9313 25.591 24.9313 25.591L24.9613 23.8666C24.9613 23.8666 24.0691 23.8891 22.4047 23.6942C20.7403 23.4992 19.1359 22.9744 19.1359 22.9744C19.1359 22.9744 19.8557 24.6763 22.0598 25.2536L22.0673 25.2461Z" fill="#7497F7"/>
-<path d="M21.4376 27.0079C18.5961 26.3557 16.4369 22.9669 16.4369 22.9669C16.4369 22.9669 15.7322 27.4203 20.7478 29.0172C24.4215 30.1868 26.1758 26.8805 26.1758 26.8805C26.1758 26.8805 24.279 27.6602 21.4376 27.0079Z" fill="#7497F7"/>
-<path d="M19.3308 10.2816C19.3308 10.2816 19.4433 11.6386 20.8153 13.183C22.1873 14.7275 22.9295 14.7499 22.5022 15.6646C22.0748 16.5793 20.1705 17.0966 18.5811 16.9466C15.7547 16.6842 15.6422 15.2373 15.6422 15.2373C15.6422 15.2373 17.8014 15.4847 18.6261 15.2373C19.4508 14.9899 19.6907 14.2926 19.4508 13.7078C18.6861 11.871 19.3233 10.2816 19.3233 10.2816H19.3308Z" fill="#7497F7"/>
-</svg>
+    <path
+        d="M25.2912 2.67189C23.4918 1.74972 21.1902 1 18.4387 1C5.88829 1 5.42346 9.33694 5.42346 9.33694C5.42346 9.33694 3.3992 10.0417 2.79942 13.2055C2.43206 15.1248 2.91188 16.4968 3.34672 17.284C2.92688 17.7338 2.57451 18.2662 2.30461 18.8659C1.66734 20.2829 1.5174 21.9548 1.89226 23.5817C2.26712 25.2086 3.11431 26.6256 4.28388 27.5702C5.54341 28.5899 7.08785 28.9572 8.51232 28.5899C8.5873 28.5749 8.65477 28.5524 8.72974 28.5299C11.4288 32.6159 15.5372 35 20.0131 35C27.8927 35 34.31 [...]
+        fill="#7497F7" />
+    <path
+        d="M22.0673 25.2461C23.7317 25.6809 24.9313 25.591 24.9313 25.591L24.9613 23.8666C24.9613 23.8666 24.0691 23.8891 22.4047 23.6942C20.7403 23.4992 19.1359 22.9744 19.1359 22.9744C19.1359 22.9744 19.8557 24.6763 22.0598 25.2536L22.0673 25.2461Z"
+        fill="#7497F7" />
+    <path
+        d="M21.4376 27.0079C18.5961 26.3557 16.4369 22.9669 16.4369 22.9669C16.4369 22.9669 15.7322 27.4203 20.7478 29.0172C24.4215 30.1868 26.1758 26.8805 26.1758 26.8805C26.1758 26.8805 24.279 27.6602 21.4376 27.0079Z"
+        fill="#7497F7" />
+    <path
+        d="M19.3308 10.2816C19.3308 10.2816 19.4433 11.6386 20.8153 13.183C22.1873 14.7275 22.9295 14.7499 22.5022 15.6646C22.0748 16.5793 20.1705 17.0966 18.5811 16.9466C15.7547 16.6842 15.6422 15.2373 15.6422 15.2373C15.6422 15.2373 17.8014 15.4847 18.6261 15.2373C19.4508 14.9899 19.6907 14.2926 19.4508 13.7078C18.6861 11.871 19.3233 10.2816 19.3233 10.2816H19.3308Z"
+        fill="#7497F7" />
+</svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/jenkins/components/miller-columns/use-miller-columns.ts b/config-ui/src/plugins/register/jenkins/components/miller-columns/use-miller-columns.ts
index abd293fb1..aa19f1bd6 100644
--- a/config-ui/src/plugins/register/jenkins/components/miller-columns/use-miller-columns.ts
+++ b/config-ui/src/plugins/register/jenkins/components/miller-columns/use-miller-columns.ts
@@ -19,8 +19,9 @@
 import { useState, useEffect, useMemo } from 'react';
 import type { ItemType, ColumnType } from 'miller-columns-select';
 
+import { useProxyPrefix } from '@/hooks';
+
 import type { ScopeItemType } from '../../types';
-import { useProxyPrefix } from '../../hooks';
 import * as API from '../../api';
 
 export type JenkinsItemType = ItemType<
@@ -44,7 +45,10 @@ export const useMillerColumns = ({ connectionId }: UseMillerColumnsProps) => {
   const [loadedIds, setLoadedIds] = useState<ID[]>([]);
   const [expandedIds, setExpandedIds] = useState<ID[]>([]);
 
-  const prefix = useProxyPrefix(connectionId);
+  const prefix = useProxyPrefix({
+    plugin: 'jenkins',
+    connectionId,
+  });
 
   const formatJobs = (jobs: any, parentId: ID | null = null) =>
     jobs.map((it: any) => ({
diff --git a/config-ui/src/plugins/register/jenkins/config.ts b/config-ui/src/plugins/register/jenkins/config.ts
index 7b017b475..cf34ac356 100644
--- a/config-ui/src/plugins/register/jenkins/config.ts
+++ b/config-ui/src/plugins/register/jenkins/config.ts
@@ -17,61 +17,40 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import {
+  BaseConnectionConfig,
+  ConnectionName,
+  ConnectionEndpoint,
+  ConnectionUsername,
+  ConnectionPassword,
+  ConnectionProxy,
+  ConnectionRatelimit,
+} from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const JenkinsConfig: PluginConfigType = {
-  plugin: Plugins.Jenkins,
+  ...BaseConnectionConfig,
+  plugin: 'jenkins',
   name: 'Jenkins',
-  type: PluginType.Connection,
   icon: Icon,
   connection: {
-    initialValues: {
-      rateLimitPerHour: 10000,
-    },
     fields: [
-      {
-        key: 'name',
-        label: 'Connection Name',
-        type: 'text',
-        required: true,
+      ConnectionName({
+        initialValue: 'Jenkins',
         placeholder: 'eg. Jenkins',
-      },
-      {
-        key: 'endpoint',
-        label: 'Endpoint URL',
-        type: 'text',
-        required: true,
+      }),
+      ConnectionEndpoint({
+        initialValue: 'https://api.jenkins.io/',
         placeholder: 'eg. https://api.jenkins.io/',
-      },
-      {
-        key: 'username',
-        label: 'Username',
-        type: 'text',
-        required: true,
-        placeholder: 'eg. admin',
-      },
-      {
-        key: 'password',
-        label: 'Password',
-        type: 'password',
-        required: true,
-        placeholder: 'eg. ************',
-      },
-      {
-        key: 'proxy',
-        label: 'Proxy URL',
-        type: 'text',
-        placeholder: 'eg. http://proxy.localhost:8080',
-        tooltip: 'Add a proxy if your network can not access Jenkins directly.',
-      },
-      {
-        key: 'rateLimitPerHour',
-        label: 'Fixed Rate Limit (per hour)',
-        type: 'rateLimit',
-        tooltip: 'Rate Limit requests per hour,\nEnter a numeric value > 0 to enable.',
-      },
+      }),
+      ConnectionUsername(),
+      ConnectionPassword(),
+      ConnectionProxy(),
+      ConnectionRatelimit({
+        initialValue: 10000,
+      }),
     ],
   },
   entities: ['CICD'],
diff --git a/config-ui/src/plugins/register/jira/components/issue-tracking/use-issue-tracking.ts b/config-ui/src/plugins/register/jira/components/issue-tracking/use-issue-tracking.ts
index f0cee9d3e..e922af08d 100644
--- a/config-ui/src/plugins/register/jira/components/issue-tracking/use-issue-tracking.ts
+++ b/config-ui/src/plugins/register/jira/components/issue-tracking/use-issue-tracking.ts
@@ -19,7 +19,8 @@
 import { useState, useEffect, useMemo } from 'react';
 import { uniqWith } from 'lodash';
 
-import { useProxyPrefix } from '../../hooks';
+import { useProxyPrefix } from '@/hooks';
+
 import * as API from '../../api';
 
 export type IssueTypeItem = {
@@ -41,7 +42,10 @@ export const useIssueTracking = ({ connectionId }: UseIssueTrackingProps) => {
   const [issueTypes, setIssueTypes] = useState<IssueTypeItem[]>([]);
   const [fields, setFields] = useState<FieldItem[]>([]);
 
-  const prefix = useProxyPrefix(connectionId);
+  const prefix = useProxyPrefix({
+    plugin: 'jira',
+    connectionId,
+  });
 
   useEffect(() => {
     (async () => {
diff --git a/config-ui/src/plugins/register/jira/components/miller-columns/use-miller-columns.ts b/config-ui/src/plugins/register/jira/components/miller-columns/use-miller-columns.ts
index 748448fa5..e92da3183 100644
--- a/config-ui/src/plugins/register/jira/components/miller-columns/use-miller-columns.ts
+++ b/config-ui/src/plugins/register/jira/components/miller-columns/use-miller-columns.ts
@@ -19,8 +19,9 @@
 import { useState, useEffect, useMemo } from 'react';
 import type { ItemType } from 'miller-columns-select';
 
+import { useProxyPrefix } from '@/hooks';
+
 import type { ScopeItemType } from '../../types';
-import { useProxyPrefix } from '../../hooks';
 import * as API from '../../api';
 
 const DEFAULT_PAGE_SIZE = 50;
@@ -36,7 +37,10 @@ export const useMillerColumns = ({ connectionId }: UseMillerColumnsProps) => {
   const [isLast, setIsLast] = useState(false);
   const [page, setPage] = useState(1);
 
-  const prefix = useProxyPrefix(connectionId);
+  const prefix = useProxyPrefix({
+    plugin: 'jira',
+    connectionId,
+  });
 
   const updateItems = (arr: any) =>
     arr.map((it: any) => ({
diff --git a/config-ui/src/plugins/register/jira/config.ts b/config-ui/src/plugins/register/jira/config.ts
index 4d38cf804..d56c4a100 100644
--- a/config-ui/src/plugins/register/jira/config.ts
+++ b/config-ui/src/plugins/register/jira/config.ts
@@ -17,62 +17,44 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import {
+  BaseConnectionConfig,
+  ConnectionName,
+  ConnectionEndpoint,
+  ConnectionUsername,
+  ConnectionPassword,
+  ConnectionProxy,
+  ConnectionRatelimit,
+} from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const JIRAConfig: PluginConfigType = {
-  plugin: Plugins.JIRA,
+  ...BaseConnectionConfig,
+  plugin: 'jira',
   name: 'JIRA',
-  type: PluginType.Connection,
   icon: Icon,
   connection: {
-    initialValues: {
-      rateLimitPerHour: 3000,
-    },
     fields: [
-      {
-        key: 'name',
-        label: 'Connection Name',
-        type: 'text',
-        required: true,
+      ConnectionName({
+        initialValue: 'JIRA',
         placeholder: 'eg. JIRA',
-      },
-      {
-        key: 'endpoint',
-        label: 'Endpoint URL',
-        type: 'text',
-        required: true,
+      }),
+      ConnectionEndpoint({
+        initialValue: 'https://your-domain.atlassian.net/rest/',
         placeholder: 'eg. https://your-domain.atlassian.net/rest/',
-      },
-      {
-        key: 'username',
+      }),
+      ConnectionUsername({
         label: 'Username / E-mail',
-        type: 'text',
-        required: true,
-        placeholder: 'eg. admin',
-      },
-      {
-        key: 'password',
-        label: 'Password',
-        type: 'password',
-        required: true,
-        placeholder: 'eg. ************',
+      }),
+      ConnectionPassword({
         tooltip: 'If you are using JIRA Cloud or JIRA Server,\nyour API Token should be used as password.',
-      },
-      {
-        key: 'proxy',
-        label: 'Proxy URL',
-        type: 'text',
-        placeholder: 'eg. http://proxy.localhost:8080',
-        tooltip: 'Add a proxy if your network can not access JIRA directly.',
-      },
-      {
-        key: 'rateLimitPerHour',
-        label: 'Fixed Rate Limit (per hour)',
-        type: 'rateLimit',
-        tooltip: 'Rate Limit requests per hour,\nEnter a numeric value > 0 to enable.',
-      },
+      }),
+      ConnectionProxy(),
+      ConnectionRatelimit({
+        initialValue: 3000,
+      }),
     ],
   },
   entities: ['TICKET', 'CROSS'],
diff --git a/config-ui/src/plugins/register/jira/hooks/index.ts b/config-ui/src/plugins/register/jira/hooks/index.ts
deleted file mode 100644
index b935965d7..000000000
--- a/config-ui/src/plugins/register/jira/hooks/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- *
- */
-
-export * from './user-proxy-prefix';
diff --git a/config-ui/src/plugins/register/jira/hooks/user-proxy-prefix.ts b/config-ui/src/plugins/register/jira/hooks/user-proxy-prefix.ts
deleted file mode 100644
index cfeba9ea3..000000000
--- a/config-ui/src/plugins/register/jira/hooks/user-proxy-prefix.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 { useMemo } from 'react';
-
-export const useProxyPrefix = (connectionId: ID) =>
-  useMemo(() => `/plugins/jira/connections/${connectionId}/proxy/rest`, [connectionId]);
diff --git a/config-ui/src/plugins/register/refdiff/assets/icon.svg b/config-ui/src/plugins/register/refdiff/assets/icon.svg
deleted file mode 100644
index 379fbdc0a..000000000
--- a/config-ui/src/plugins/register/refdiff/assets/icon.svg
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-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.
--->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#7497F7" height="800px" width="800px" version="1.1" viewBox="0 0 231.087 231.087" enable-background="new 0 0 231.087 231.087">
-    <g>
-        <path d="m230.042,142.627c-1.871-2.744-5.612-3.452-8.355-1.581l-65.513,44.667-14.55-19.473c-1.526-2.036-4.241-2.977-6.788-2.129-3.185,1.06-4.908,4.501-3.848,7.686l11.908,35.785c0.45,1.33 1.184,2.645 2.18,3.757 3.94,4.401 10.702,4.776 15.104,0.836l.777-.695 68.129-60.985c2.216-1.981 2.676-5.346 0.956-7.868z"/>
-        <path d="m120.211,190.676h-108.211v-162.49h158.43v124.823c0,3.313 2.687,6 6,6s6-2.687 6-6v-130.823c0-3.313-2.687-6-6-6h-170.43c-3.313,0-6,2.687-6,6v174.49c0,3.313 2.687,6 6,6h114.211c3.313,0 6-2.687 6-6 0-3.314-2.687-6-6-6z"/>
-        <path d="m139.694,53.855h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,79.79h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,105.725h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m145.694,137.659c0-3.313-2.687-6-6-6h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.314,0 6-2.686 6-6z"/>
-        <path d="M42.735,156.329c-3.313,0-6,2.687-6,6s2.687,6,6,6h48.479c3.313,0,6-2.687,6-6s-2.687-6-6-6H42.735z"/>
-    </g>
-</svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/refdiff/config.ts b/config-ui/src/plugins/register/refdiff/config.ts
index 96758ed67..916696dfc 100644
--- a/config-ui/src/plugins/register/refdiff/config.ts
+++ b/config-ui/src/plugins/register/refdiff/config.ts
@@ -17,13 +17,11 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
 
-import Icon from './assets/icon.svg';
+import { BasePipelineConfig } from '../base';
 
 export const RefDiffConfig: PluginConfigType = {
-  plugin: Plugins.RefDiff,
+  ...BasePipelineConfig,
+  plugin: 'refdiff',
   name: 'RefDiff',
-  type: PluginType.Pipeline,
-  icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/starrocks/assets/icon.svg b/config-ui/src/plugins/register/starrocks/assets/icon.svg
deleted file mode 100644
index 379fbdc0a..000000000
--- a/config-ui/src/plugins/register/starrocks/assets/icon.svg
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-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.
--->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#7497F7" height="800px" width="800px" version="1.1" viewBox="0 0 231.087 231.087" enable-background="new 0 0 231.087 231.087">
-    <g>
-        <path d="m230.042,142.627c-1.871-2.744-5.612-3.452-8.355-1.581l-65.513,44.667-14.55-19.473c-1.526-2.036-4.241-2.977-6.788-2.129-3.185,1.06-4.908,4.501-3.848,7.686l11.908,35.785c0.45,1.33 1.184,2.645 2.18,3.757 3.94,4.401 10.702,4.776 15.104,0.836l.777-.695 68.129-60.985c2.216-1.981 2.676-5.346 0.956-7.868z"/>
-        <path d="m120.211,190.676h-108.211v-162.49h158.43v124.823c0,3.313 2.687,6 6,6s6-2.687 6-6v-130.823c0-3.313-2.687-6-6-6h-170.43c-3.313,0-6,2.687-6,6v174.49c0,3.313 2.687,6 6,6h114.211c3.313,0 6-2.687 6-6 0-3.314-2.687-6-6-6z"/>
-        <path d="m139.694,53.855h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,79.79h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m139.694,105.725h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.313,0 6-2.687 6-6s-2.686-6-6-6z"/>
-        <path d="m145.694,137.659c0-3.313-2.687-6-6-6h-96.959c-3.313,0-6,2.687-6,6s2.687,6 6,6h96.959c3.314,0 6-2.686 6-6z"/>
-        <path d="M42.735,156.329c-3.313,0-6,2.687-6,6s2.687,6,6,6h48.479c3.313,0,6-2.687,6-6s-2.687-6-6-6H42.735z"/>
-    </g>
-</svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/starrocks/config.ts b/config-ui/src/plugins/register/starrocks/config.ts
index 29a64cc37..1a24fac9f 100644
--- a/config-ui/src/plugins/register/starrocks/config.ts
+++ b/config-ui/src/plugins/register/starrocks/config.ts
@@ -17,13 +17,11 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
 
-import Icon from './assets/icon.svg';
+import { BasePipelineConfig } from '../base';
 
 export const StarRocksConfig: PluginConfigType = {
-  plugin: Plugins.StarRocks,
+  ...BasePipelineConfig,
+  plugin: 'starrocks',
   name: 'StarRocks',
-  type: PluginType.Pipeline,
-  icon: Icon,
 };
diff --git a/config-ui/src/plugins/register/tapd/assets/icon.svg b/config-ui/src/plugins/register/tapd/assets/icon.svg
index 5859f9422..504813a1d 100644
--- a/config-ui/src/plugins/register/tapd/assets/icon.svg
+++ b/config-ui/src/plugins/register/tapd/assets/icon.svg
@@ -1,22 +1,8 @@
-<!--
-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.
--->
 <svg width="100" height="100" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <path d="M30.1151 10.3491L27.9087 3.35706L4.95635 10.3491L6.96429 17.3253L15.0198 15.0396L19.4008 29.492L26.5992 27.246L22.1389 12.8491L30.1151 10.3491Z" fill="#7497F7"/>
-    <path d="M2.25 33.6666H15.2659L2.25 12.0317V33.6666Z" fill="#7497F7"/>
-    <path d="M33.0119 2.33325L27.2103 33.6666H33.75V2.33325H33.0119Z" fill="#7497F7"/>
-    <path d="M2.25 2.33325V8.6904L23.6944 2.33325H2.25Z" fill="#7497F7"/>
+    <path
+        d="M30.1151 10.3491L27.9087 3.35706L4.95635 10.3491L6.96429 17.3253L15.0198 15.0396L19.4008 29.492L26.5992 27.246L22.1389 12.8491L30.1151 10.3491Z"
+        fill="#7497F7" />
+    <path d="M2.25 33.6666H15.2659L2.25 12.0317V33.6666Z" fill="#7497F7" />
+    <path d="M33.0119 2.33325L27.2103 33.6666H33.75V2.33325H33.0119Z" fill="#7497F7" />
+    <path d="M2.25 2.33325V8.6904L23.6944 2.33325H2.25Z" fill="#7497F7" />
 </svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/tapd/config.ts b/config-ui/src/plugins/register/tapd/config.ts
index f7dce9b59..dae2ad7c3 100644
--- a/config-ui/src/plugins/register/tapd/config.ts
+++ b/config-ui/src/plugins/register/tapd/config.ts
@@ -17,62 +17,41 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import {
+  BaseConnectionConfig,
+  ConnectionName,
+  ConnectionEndpoint,
+  ConnectionUsername,
+  ConnectionPassword,
+  ConnectionProxy,
+  ConnectionRatelimit,
+} from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const TAPDConfig: PluginConfigType = {
-  plugin: Plugins.TAPD,
+  ...BaseConnectionConfig,
+  plugin: 'tapd',
   name: 'TAPD',
-  type: PluginType.Connection,
   isBeta: true,
   icon: Icon,
   connection: {
-    initialValues: {
-      rateLimitPerHour: 3000,
-    },
     fields: [
-      {
-        key: 'name',
-        label: 'Connection Name',
-        type: 'text',
-        required: true,
+      ConnectionName({
+        initialValue: 'TAPD',
         placeholder: 'eg. TAPD',
-      },
-      {
-        key: 'endpoint',
-        label: 'Endpoint URL',
-        type: 'text',
-        required: true,
+      }),
+      ConnectionEndpoint({
+        initialValue: 'https://api.tapd.cn/',
         placeholder: 'eg. https://api.tapd.cn/',
-      },
-      {
-        key: 'username',
-        label: 'Username',
-        type: 'text',
-        required: true,
-        placeholder: 'eg. admin',
-      },
-      {
-        key: 'password',
-        label: 'Password',
-        type: 'password',
-        required: true,
-        placeholder: 'eg. ************',
-      },
-      {
-        key: 'proxy',
-        label: 'Proxy URL',
-        type: 'text',
-        placeholder: 'eg. http://proxy.localhost:8080',
-        tooltip: 'Add a proxy if your network can not access TAPD directly.',
-      },
-      {
-        key: 'rateLimitPerHour',
-        label: 'Fixed Rate Limit (per hour)',
-        type: 'rateLimit',
-        tooltip: 'Rate Limit requests per hour,\nEnter a numeric value > 0 to enable.',
-      },
+      }),
+      ConnectionUsername(),
+      ConnectionPassword(),
+      ConnectionProxy(),
+      ConnectionRatelimit({
+        initialValue: 3000,
+      }),
     ],
   },
   entities: ['TICKET'],
diff --git a/config-ui/src/plugins/register/webook/assets/icon.svg b/config-ui/src/plugins/register/webook/assets/icon.svg
index 548503935..220540b88 100644
--- a/config-ui/src/plugins/register/webook/assets/icon.svg
+++ b/config-ui/src/plugins/register/webook/assets/icon.svg
@@ -1,5 +1,11 @@
 <svg width="100" height="100" viewBox="0 0 58 52" fill="none" xmlns="http://www.w3.org/2000/svg">
-  <path d="M27.2239 21.9899C24.8672 25.8703 22.6083 29.6289 20.3028 33.3587C19.7113 34.3151 19.4179 35.0951 19.8914 36.3131C21.1971 39.6749 19.3543 42.947 15.8922 43.8365C12.6319 44.6743 9.44613 42.5714 8.79873 39.1488C8.2243 36.1184 10.626 33.1474 14.0369 32.6745C14.3226 32.6334 14.6144 32.6289 15.0942 32.5939L20.2842 24.0791C17.0239 20.9013 15.0771 17.1851 15.5071 12.5811C15.8176 9.32719 17.1186 6.51426 19.5064 4.20918C21.7027 2.06888 24.5804 0.728584 27.6616 0.410795C30.7429 0.0930059 [...]
-  <path d="M33.9556 17.3995C35.6153 20.2687 37.3028 23.1774 38.9733 26.0664C47.4206 23.5074 53.789 28.0856 56.0727 32.9892C58.8331 38.9116 56.9468 45.9257 51.527 49.5794C45.9643 53.3305 38.9283 52.6889 33.9991 47.8719L37.8664 44.7017C42.7351 47.7898 46.9921 47.6438 50.153 43.9886C51.4577 42.4671 52.1615 40.5375 52.1365 38.5507C52.1114 36.564 51.3591 34.652 50.0164 33.1626C46.8166 29.6396 42.5286 29.5316 37.3463 32.9147C35.1961 29.1789 33.0086 25.4734 30.9267 21.7117C30.2249 20.4436 29.45 [...]
-  <path d="M37.9269 40.8548H27.7564C26.7815 44.7807 24.6763 47.951 21.0496 49.9672C18.3007 51.5212 15.0826 52.0823 11.955 51.5531C5.99955 50.6119 1.13243 45.3616 0.700828 39.4483C0.216445 32.7505 4.9159 26.7978 11.1818 25.4597C11.615 26.9985 12.0512 28.5524 12.4844 30.0866C6.7401 32.9588 4.74667 36.5776 6.35507 41.1042C7.77096 45.0864 11.7889 47.2698 16.1623 46.4259C20.6242 45.5638 22.8722 41.9328 22.599 36.1048C26.828 36.1048 31.0602 36.0622 35.2892 36.126C36.9411 36.1519 38.2157 35.984 [...]
+  <path
+    d="M27.2239 21.9899C24.8672 25.8703 22.6083 29.6289 20.3028 33.3587C19.7113 34.3151 19.4179 35.0951 19.8914 36.3131C21.1971 39.6749 19.3543 42.947 15.8922 43.8365C12.6319 44.6743 9.44613 42.5714 8.79873 39.1488C8.2243 36.1184 10.626 33.1474 14.0369 32.6745C14.3226 32.6334 14.6144 32.6289 15.0942 32.5939L20.2842 24.0791C17.0239 20.9013 15.0771 17.1851 15.5071 12.5811C15.8176 9.32719 17.1186 6.51426 19.5064 4.20918C21.7027 2.06888 24.5804 0.728584 27.6616 0.410795C30.7429 0.0930059 33. [...]
+    fill="#7497F7" />
+  <path
+    d="M33.9556 17.3995C35.6153 20.2687 37.3028 23.1774 38.9733 26.0664C47.4206 23.5074 53.789 28.0856 56.0727 32.9892C58.8331 38.9116 56.9468 45.9257 51.527 49.5794C45.9643 53.3305 38.9283 52.6889 33.9991 47.8719L37.8664 44.7017C42.7351 47.7898 46.9921 47.6438 50.153 43.9886C51.4577 42.4671 52.1615 40.5375 52.1365 38.5507C52.1114 36.564 51.3591 34.652 50.0164 33.1626C46.8166 29.6396 42.5286 29.5316 37.3463 32.9147C35.1961 29.1789 33.0086 25.4734 30.9267 21.7117C30.2249 20.4436 29.4502 1 [...]
+    fill="#7497F7" />
+  <path
+    d="M37.9269 40.8548H27.7564C26.7815 44.7807 24.6763 47.951 21.0496 49.9672C18.3007 51.5212 15.0826 52.0823 11.955 51.5531C5.99955 50.6119 1.13243 45.3616 0.700828 39.4483C0.216445 32.7505 4.9159 26.7978 11.1818 25.4597C11.615 26.9985 12.0512 28.5524 12.4844 30.0866C6.7401 32.9588 4.74667 36.5776 6.35507 41.1042C7.77096 45.0864 11.7889 47.2698 16.1623 46.4259C20.6242 45.5638 22.8722 41.9328 22.599 36.1048C26.828 36.1048 31.0602 36.0622 35.2892 36.126C36.9411 36.1519 38.2157 35.9846 39 [...]
+    fill="#7497F7" />
 </svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/webook/config.ts b/config-ui/src/plugins/register/webook/config.ts
index d9b7b6440..e4c198e47 100644
--- a/config-ui/src/plugins/register/webook/config.ts
+++ b/config-ui/src/plugins/register/webook/config.ts
@@ -17,12 +17,12 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+import { PluginType } from '@/plugins';
 
 import Icon from './assets/icon.svg';
 
 export const WebhookConfig: PluginConfigType = {
-  plugin: Plugins.Webhook,
+  plugin: 'webhook',
   name: 'Webhook',
   type: PluginType.Incoming_Connection,
   icon: Icon,
diff --git a/config-ui/src/plugins/register/zentao/assets/icon.svg b/config-ui/src/plugins/register/zentao/assets/icon.svg
index 8a87d177f..c450e329e 100644
--- a/config-ui/src/plugins/register/zentao/assets/icon.svg
+++ b/config-ui/src/plugins/register/zentao/assets/icon.svg
@@ -1,3 +1,5 @@
 <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path d="M18 2.5C14.8355 2.5 11.7421 3.43838 9.11088 5.19649C6.4797 6.95459 4.42894 9.45345 3.21793 12.3771C2.00693 15.3007 1.69008 18.5177 2.30744 21.6214C2.92481 24.7251 4.44866 27.5761 6.6863 29.8137C8.92394 32.0513 11.7749 33.5752 14.8786 34.1926C17.9823 34.8099 21.1993 34.4931 24.1229 33.2821C27.0466 32.0711 29.5454 30.0203 31.3035 27.3891C33.0616 24.7579 34 21.6645 34 18.5C34 14.2565 32.3143 10.1869 29.3137 7.18629C26.3131 4.18571 22.2435 2.5 18 2.5V2.5ZM27.3675 19.085C26.4589 19.1 [...]
-</svg>
+  <path
+    d="M18 2.5C14.8355 2.5 11.7421 3.43838 9.11088 5.19649C6.4797 6.95459 4.42894 9.45345 3.21793 12.3771C2.00693 15.3007 1.69008 18.5177 2.30744 21.6214C2.92481 24.7251 4.44866 27.5761 6.6863 29.8137C8.92394 32.0513 11.7749 33.5752 14.8786 34.1926C17.9823 34.8099 21.1993 34.4931 24.1229 33.2821C27.0466 32.0711 29.5454 30.0203 31.3035 27.3891C33.0616 24.7579 34 21.6645 34 18.5C34 14.2565 32.3143 10.1869 29.3137 7.18629C26.3131 4.18571 22.2435 2.5 18 2.5V2.5ZM27.3675 19.085C26.4589 19.133 [...]
+    fill="#7497F7" />
+</svg>
\ No newline at end of file
diff --git a/config-ui/src/plugins/register/zentao/config.ts b/config-ui/src/plugins/register/zentao/config.ts
index bebfcaee9..8026ad79e 100644
--- a/config-ui/src/plugins/register/zentao/config.ts
+++ b/config-ui/src/plugins/register/zentao/config.ts
@@ -17,62 +17,41 @@
  */
 
 import type { PluginConfigType } from '@/plugins';
-import { Plugins, PluginType } from '@/plugins';
+
+import {
+  BaseConnectionConfig,
+  ConnectionName,
+  ConnectionEndpoint,
+  ConnectionUsername,
+  ConnectionPassword,
+  ConnectionProxy,
+  ConnectionRatelimit,
+} from '../base';
 
 import Icon from './assets/icon.svg';
 
 export const ZenTaoConfig: PluginConfigType = {
-  plugin: Plugins.ZenTao,
+  ...BaseConnectionConfig,
+  plugin: 'zentao',
   name: 'ZenTao',
-  type: PluginType.Connection,
   isBeta: true,
   icon: Icon,
   connection: {
-    initialValues: {
-      rateLimitPerHour: 10000,
-    },
     fields: [
-      {
-        key: 'name',
-        label: 'Connection Name',
-        type: 'text',
-        required: true,
+      ConnectionName({
+        initialValue: 'ZenTao',
         placeholder: 'eg. ZenTao',
-      },
-      {
-        key: 'endpoint',
-        label: 'Endpoint URL',
-        type: 'text',
-        required: true,
+      }),
+      ConnectionEndpoint({
+        initialValue: 'https://your-domain:port/api.php/v1/',
         placeholder: 'eg. https://your-domain:port/api.php/v1/',
-      },
-      {
-        key: 'username',
-        label: 'Username',
-        type: 'text',
-        required: true,
-        placeholder: 'eg. admin',
-      },
-      {
-        key: 'password',
-        label: 'Password',
-        type: 'password',
-        required: true,
-        placeholder: 'eg. ************',
-      },
-      {
-        key: 'proxy',
-        label: 'Proxy URL',
-        type: 'text',
-        placeholder: 'eg. http://proxy.localhost:8080',
-        tooltip: 'Add a proxy if your network can not access ZenTao directly.',
-      },
-      {
-        key: 'rateLimitPerHour',
-        label: 'Fixed Rate Limit (per hour)',
-        type: 'rateLimit',
-        tooltip: 'Rate Limit requests per hour,\nEnter a numeric value > 0 to enable.',
-      },
+      }),
+      ConnectionUsername(),
+      ConnectionPassword(),
+      ConnectionProxy(),
+      ConnectionRatelimit({
+        initialValue: 10000,
+      }),
     ],
   },
   entities: ['TICKET'],
diff --git a/config-ui/src/plugins/types.ts b/config-ui/src/plugins/types.ts
index 6d4c95044..d4d9c40fc 100644
--- a/config-ui/src/plugins/types.ts
+++ b/config-ui/src/plugins/types.ts
@@ -16,27 +16,6 @@
  *
  */
 
-export enum Plugins {
-  AE = 'ae',
-  Azure = 'azure',
-  BitBucket = 'bitbucket',
-  DBT = 'dbt',
-  DORA = 'dora',
-  FeiShu = 'feishu',
-  Gitee = 'gitee',
-  GitExtractor = 'gitextractor',
-  GitHub = 'github',
-  GitHubGraphql = 'github_graphql',
-  GitLab = 'gitlab',
-  Jenkins = 'jenkins',
-  JIRA = 'jira',
-  RefDiff = 'refdiff',
-  StarRocks = 'starrocks',
-  TAPD = 'tapd',
-  Webhook = 'webhook',
-  ZenTao = 'zentao',
-}
-
 export enum PluginType {
   Connection = 'connection',
   Incoming_Connection = 'incoming_connection',
@@ -44,13 +23,12 @@ export enum PluginType {
 }
 
 export type PluginConfigConnectionType = {
-  plugin: Plugins;
-  name: string;
   type: PluginType.Connection;
+  plugin: string;
+  name: string;
   icon: string;
   isBeta?: boolean;
   connection: {
-    initialValues?: Record<string, any>;
     fields: Array<{
       key: string;
       type: 'text' | 'password' | 'switch' | 'rateLimit' | 'githubToken' | 'gitlabToken';
@@ -58,6 +36,7 @@ export type PluginConfigConnectionType = {
       required?: boolean;
       placeholder?: string;
       tooltip?: string;
+      initialValue?: any;
     }>;
   };
   entities: string[];
@@ -65,9 +44,9 @@ export type PluginConfigConnectionType = {
 };
 
 export type PluginConfigAnotherType = {
-  plugin: Plugins;
-  name: string;
   type: PluginType.Incoming_Connection | PluginType.Pipeline;
+  plugin: string;
+  name: string;
   icon: string;
 };
 
diff --git a/config-ui/src/store/connections/types.ts b/config-ui/src/store/connections/types.ts
index 468ca56c4..7e23be1d6 100644
--- a/config-ui/src/store/connections/types.ts
+++ b/config-ui/src/store/connections/types.ts
@@ -16,8 +16,6 @@
  *
  */
 
-import { Plugins } from '@/plugins';
-
 export enum ConnectionStatusEnum {
   ONLINE = 'online',
   OFFLINE = 'offline',
@@ -28,7 +26,7 @@ export enum ConnectionStatusEnum {
 export type ConnectionItemType = {
   unique: string;
   status: ConnectionStatusEnum;
-  plugin: Plugins;
+  plugin: string;
   id: ID;
   name: string;
   icon: string;
diff --git a/config-ui/src/store/connections/use-context-value.ts b/config-ui/src/store/connections/use-context-value.ts
index 7a416cb9f..b978471cc 100644
--- a/config-ui/src/store/connections/use-context-value.ts
+++ b/config-ui/src/store/connections/use-context-value.ts
@@ -19,14 +19,14 @@
 import { useState, useEffect, useCallback, useMemo } from 'react';
 
 import type { PluginConfigConnectionType } from '@/plugins';
-import { Plugins, PluginConfig, PluginType } from '@/plugins';
+import { PluginConfig, PluginType } from '@/plugins';
 
 import type { ConnectionItemType } from './types';
 import { ConnectionStatusEnum } from './types';
 import * as API from './api';
 
 export interface UseContextValueProps {
-  plugin?: Plugins;
+  plugin?: string;
   filterBeta?: boolean;
 }
 
diff --git a/config-ui/src/store/transformations/api.ts b/config-ui/src/store/transformations/api.ts
index e08cd108b..da7ad6e04 100644
--- a/config-ui/src/store/transformations/api.ts
+++ b/config-ui/src/store/transformations/api.ts
@@ -18,6 +18,4 @@
 
 import { request } from '@/utils';
 
-import { Plugins } from '@/plugins';
-
-export const getTransformation = (plugin: Plugins) => request(`/plugins/${plugin}/transformation_rules`);
+export const getTransformation = (plugin: string) => request(`/plugins/${plugin}/transformation_rules`);
diff --git a/config-ui/src/store/transformations/types.ts b/config-ui/src/store/transformations/types.ts
index 5fc29b885..48a344e90 100644
--- a/config-ui/src/store/transformations/types.ts
+++ b/config-ui/src/store/transformations/types.ts
@@ -16,10 +16,8 @@
  *
  */
 
-import { Plugins } from '@/plugins';
-
 export type TransformationItemType = {
   id: ID;
   name: string;
-  plugin: Plugins;
+  plugin: string;
 };
diff --git a/config-ui/src/store/transformations/use-context-value.ts b/config-ui/src/store/transformations/use-context-value.ts
index 4914a29b8..0a6911629 100644
--- a/config-ui/src/store/transformations/use-context-value.ts
+++ b/config-ui/src/store/transformations/use-context-value.ts
@@ -18,7 +18,7 @@
 
 import { useState, useEffect, useCallback, useMemo } from 'react';
 
-import { PluginConfig, PluginType, Plugins } from '@/plugins';
+import { PluginConfig, PluginType } from '@/plugins';
 
 import type { TransformationItemType } from './types';
 import * as API from './api';
@@ -29,7 +29,7 @@ export const useContextValue = () => {
 
   const allConnections = useMemo(() => PluginConfig.filter((p) => p.type === PluginType.Connection && !p.isBeta), []);
 
-  const getTransformation = async (plugin: Plugins) => {
+  const getTransformation = async (plugin: string) => {
     try {
       return await API.getTransformation(plugin);
     } catch {