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

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


The following commit(s) were added to refs/heads/main by this push:
     new 65267623a refactor(config-ui): unified API type definitions and 
exports (#6215)
65267623a is described below

commit 65267623a3ca7c4be4191c0010270a58b3dc3867
Author: 青湛 <[email protected]>
AuthorDate: Thu Oct 12 23:48:32 2023 +1300

    refactor(config-ui): unified API type definitions and exports (#6215)
---
 .../api-keys/api.ts => api/api-key/index.ts}       | 11 ++--
 .../api.ts => api/api-key/types.ts}                |  9 ++--
 .../pipeline/api.ts => api/blueprint/index.ts}     | 26 ++++-----
 .../layout/api.ts => api/blueprint/types.ts}       | 36 +++++++++----
 .../api.ts => api/connection/index.ts}             | 23 ++++++--
 .../connections/api.ts => api/connection/types.ts} | 41 ++++++++------
 config-ui/src/api/index.ts                         | 53 ++++++++++++++++++
 .../pipeline/api.ts => api/pipeline/index.ts}      | 17 +++---
 .../home/api.ts => api/pipeline/types.ts}          | 35 ++++++------
 .../register/github/api.ts => api/plugin/index.ts} | 12 ++++-
 .../jira/api.ts => api/plugin/jira/index.ts}       | 10 ++--
 .../tapd/api.ts => api/plugin/tapd/index.ts}       |  8 +--
 .../detail/api.ts => api/plugin/webhook/index.ts}  | 28 ++++++----
 .../project/detail/api.ts => api/project/index.ts} | 27 +++++-----
 .../{routes/layout/api.ts => api/project/types.ts} | 22 ++++----
 .../api.ts => api/scope-config/index.ts}           | 12 ++---
 .../api.ts => api/scope/index.ts}                  | 56 +++++++++++--------
 .../api.ts => api/scope/types.ts}                  | 39 ++++++++++----
 .../offline/api.ts => api/task/index.ts}           |  5 +-
 .../src/pages/blueprint/connection-detail/api.ts   | 37 -------------
 .../pages/blueprint/connection-detail/index.tsx    | 16 +++---
 .../pages/blueprint/detail/blueprint-detail.tsx    |  4 +-
 .../pages/blueprint/detail/configuration-panel.tsx | 15 +++---
 .../src/pages/blueprint/detail/status-panel.tsx    | 10 ++--
 config-ui/src/pages/blueprint/home/index.tsx       |  6 +--
 config-ui/src/pages/connection/detail/api.ts       | 44 ---------------
 config-ui/src/pages/connection/detail/index.tsx    | 12 ++---
 config-ui/src/pages/project/detail/index.tsx       |  4 +-
 .../src/pages/project/detail/settings-panel.tsx    |  6 +--
 .../src/pages/project/detail/webhooks-panel.tsx    |  9 ++--
 config-ui/src/pages/project/home/api.ts            | 62 ----------------------
 config-ui/src/pages/project/home/index.tsx         |  8 +--
 .../plugins/components/connection-form/index.tsx   | 11 ++--
 .../data-scope-remote/data-scope-remote.tsx        |  4 +-
 .../components/data-scope-remote/search-local.tsx  |  4 +-
 .../components/data-scope-remote/search-remote.tsx |  6 +--
 .../plugins/components/data-scope-select/index.tsx |  9 ++--
 .../plugins/components/scope-config-form/api.ts    | 34 ------------
 .../plugins/components/scope-config-form/index.tsx |  8 +--
 .../components/scope-config-select/index.tsx       |  4 +-
 .../github/connection-fields/githubapp.tsx         |  7 ++-
 .../register/github/connection-fields/token.tsx    |  7 ++-
 config-ui/src/plugins/register/gitlab/api.ts       | 56 -------------------
 .../jira/transformation-fields/dev-panel.tsx       | 10 ++--
 .../jira/transformation-fields/remote-link.tsx     |  4 +-
 .../src/plugins/register/jira/transformation.tsx   |  4 +-
 config-ui/src/plugins/register/tapd/data-scope.tsx |  9 ++--
 .../src/plugins/register/tapd/transformation.tsx   |  8 +--
 config-ui/src/plugins/register/webook/api.ts       | 46 ----------------
 .../register/webook/components/create-dialog.tsx   |  7 +--
 .../register/webook/components/delete-dialog.tsx   |  5 +-
 .../register/webook/components/edit-dialog.tsx     |  7 ++-
 .../register/webook/components/selector-dialog.tsx |  4 +-
 .../register/webook/components/view-dialog.tsx     |  6 +--
 config-ui/src/routes/api-keys/api-keys.tsx         |  8 +--
 .../error/components/needs-db-migrate/index.tsx    |  3 +-
 .../src/routes/error/components/offline/index.tsx  |  3 +-
 config-ui/src/routes/layout/loader.ts              |  7 ++-
 config-ui/src/routes/pipeline/components/info.tsx  |  8 +--
 config-ui/src/routes/pipeline/components/table.tsx |  4 +-
 config-ui/src/routes/pipeline/components/task.tsx  |  4 +-
 config-ui/src/routes/pipeline/components/tasks.tsx |  4 +-
 config-ui/src/routes/pipeline/pipelines.tsx        |  4 +-
 config-ui/src/store/connections/context.tsx        |  6 +--
 64 files changed, 433 insertions(+), 581 deletions(-)

diff --git a/config-ui/src/routes/api-keys/api.ts 
b/config-ui/src/api/api-key/index.ts
similarity index 76%
rename from config-ui/src/routes/api-keys/api.ts
rename to config-ui/src/api/api-key/index.ts
index 7dc79547e..48e82cb6d 100644
--- a/config-ui/src/routes/api-keys/api.ts
+++ b/config-ui/src/api/api-key/index.ts
@@ -17,15 +17,14 @@
  */
 
 import { request } from '@/utils';
-
 import * as T from './types';
 
-export const getApiKeys = (params?: Pagination): Promise<{ count: number; 
apikeys: T.Key[] }> =>
+export const list = (data?: Pagination): Promise<{ count: number; apikeys: 
T.Key[] }> =>
   request('/api-keys', {
-    data: params,
+    data,
   });
 
-export const createApiKey = (data: Pick<T.Key, 'name' | 'expiredAt' | 
'allowedPath'>): Promise<T.Key> =>
+export const create = (data: Pick<T.Key, 'name' | 'expiredAt' | 
'allowedPath'>): Promise<T.Key> =>
   request('/api-keys', {
     method: 'POST',
     data: {
@@ -34,7 +33,9 @@ export const createApiKey = (data: Pick<T.Key, 'name' | 
'expiredAt' | 'allowedPa
     },
   });
 
-export const deleteApiKey = (id: string): Promise<void> =>
+export const remove = (id: string): Promise<void> =>
   request(`/api-keys/${id}`, {
     method: 'DELETE',
   });
+
+export const renew = (id: ID) => request(`/api-keys/${id}`, { method: 'put' });
diff --git a/config-ui/src/routes/error/components/needs-db-migrate/api.ts 
b/config-ui/src/api/api-key/types.ts
similarity index 88%
rename from config-ui/src/routes/error/components/needs-db-migrate/api.ts
rename to config-ui/src/api/api-key/types.ts
index 36e4c8671..574b886f8 100644
--- a/config-ui/src/routes/error/components/needs-db-migrate/api.ts
+++ b/config-ui/src/api/api-key/types.ts
@@ -16,6 +16,9 @@
  *
  */
 
-import { request } from '@/utils';
-
-export const migrate = () => request('/proceed-db-migration');
+export type Key = {
+  name: string;
+  expiredAt?: string;
+  allowedPath: string;
+  creator: string;
+};
diff --git a/config-ui/src/routes/pipeline/api.ts 
b/config-ui/src/api/blueprint/index.ts
similarity index 56%
copy from config-ui/src/routes/pipeline/api.ts
copy to config-ui/src/api/blueprint/index.ts
index 261e04a99..36ad47eaf 100644
--- a/config-ui/src/routes/pipeline/api.ts
+++ b/config-ui/src/api/blueprint/index.ts
@@ -20,25 +20,21 @@ import { request } from '@/utils';
 
 import * as T from './types';
 
-export const getPipelines = (): Promise<{ count: number; pipelines: 
T.Pipeline[] }> => request('/pipelines');
+export const list = (data: Pagination & { type: string }): Promise<{ count: 
number; blueprints: T.Blueprint[] }> =>
+  request('/blueprints', { data });
 
-export const getPipeline = (id: ID) => request(`/pipelines/${id}`);
+export const get = (id: ID): Promise<T.Blueprint> => 
request(`/blueprints/${id}`);
 
-export const deletePipeline = (id: ID) =>
-  request(`/pipelines/${id}`, {
-    method: 'delete',
-  });
-
-export const rerunPipeline = (id: ID) =>
-  request(`/pipelines/${id}/rerun`, {
+export const create = (data: any) =>
+  request('/blueprints', {
     method: 'post',
+    data,
   });
 
-export const getPipelineLog = (id: ID) => 
request(`/pipelines/${id}/logging.tar.gz`);
+export const remove = (id: ID) => request(`/blueprints/${id}`, { method: 
'delete' });
 
-export const getPipelineTasks = (id: ID) => request(`/pipelines/${id}/tasks`);
+export const update = (id: ID, data: T.Blueprint) => 
request(`/blueprints/${id}`, { method: 'patch', data });
 
-export const taskRerun = (id: ID) =>
-  request(`/tasks/${id}/rerun`, {
-    method: 'post',
-  });
+export const pipelines = (id: ID) => request(`/blueprints/${id}/pipelines`);
+
+export const trigger = (id: ID, data: T.TriggerQuery) => 
request(`/blueprints/${id}/trigger`, { method: 'post', data });
diff --git a/config-ui/src/routes/layout/api.ts 
b/config-ui/src/api/blueprint/types.ts
similarity index 62%
copy from config-ui/src/routes/layout/api.ts
copy to config-ui/src/api/blueprint/types.ts
index 20c884f49..ccb1876ac 100644
--- a/config-ui/src/routes/layout/api.ts
+++ b/config-ui/src/api/blueprint/types.ts
@@ -16,18 +16,32 @@
  *
  */
 
-import { request } from '@/utils';
+export enum ModeEnum {
+  advanced = 'ADVANCED',
+  normal = 'NORMAL',
+}
 
-type VersionType = {
-  version: string;
+export type Blueprint = {
+  projectName: string;
+  id: ID;
+  enable: boolean;
+  name: string;
+  mode: ModeEnum;
+  isManual: boolean;
+  cronConfig: string;
+  skipOnFail: boolean;
+  plan: any;
+  timeAfter: null | string;
+  connections: Array<{
+    pluginName: string;
+    connectionId: ID;
+    scopes?: Array<{
+      scopeId: string;
+    }>;
+  }>;
 };
 
-export const getVersion = (signal?: AbortSignal): Promise<VersionType> => 
request('/version', { signal });
-
-type UserInfoType = {
-  user: string;
-  email: string;
-  logoutURI: string;
+export type TriggerQuery = {
+  skipCollectors: boolean;
+  fullSync: boolean;
 };
-
-export const getUserInfo = (signal?: AbortSignal): Promise<UserInfoType> => 
request('/userinfo', { signal });
diff --git a/config-ui/src/plugins/components/connection-form/api.ts 
b/config-ui/src/api/connection/index.ts
similarity index 53%
rename from config-ui/src/plugins/components/connection-form/api.ts
rename to config-ui/src/api/connection/index.ts
index fa09cefbe..138ea6b2e 100644
--- a/config-ui/src/plugins/components/connection-form/api.ts
+++ b/config-ui/src/api/connection/index.ts
@@ -18,16 +18,29 @@
 
 import { request } from '@/utils';
 
-export const testConnection = (plugin: string, payload: any) =>
-  request(`/plugins/${plugin}/test`, { method: 'post', data: payload });
+import * as T from './types';
 
-export const createConnection = (plugin: string, payload: any) =>
+export const list = (plugin: string): Promise<T.Connection[]> => 
request(`/plugins/${plugin}/connections`);
+
+export const get = (plugin: string, connectionId: ID): Promise<T.Connection> =>
+  request(`/plugins/${plugin}/connections/${connectionId}`);
+
+export const create = (plugin: string, payload: T.ConnectionForm): 
Promise<T.Connection> =>
   request(`/plugins/${plugin}/connections`, { method: 'post', data: payload });
 
-export const getConnection = (plugin: string, id: ID) => 
request(`/plugins/${plugin}/connections/${id}`);
+export const remove = (plugin: string, id: ID): Promise<T.Connection> =>
+  request(`/plugins/${plugin}/connections/${id}`, { method: 'delete' });
 
-export const updateConnection = (plugin: string, id: ID, payload: any) =>
+export const update = (plugin: string, id: ID, payload: T.ConnectionForm): 
Promise<T.Connection> =>
   request(`/plugins/${plugin}/connections/${id}`, {
     method: 'patch',
     data: payload,
   });
+
+export const test = (
+  plugin: string,
+  payload: Pick<
+    T.ConnectionForm,
+    'endpoint' | 'authMethod' | 'username' | 'password' | 'token' | 'appId' | 
'secretKey' | 'proxy'
+  >,
+): Promise<T.ConnectionTest> => request(`/plugins/${plugin}/test`, { method: 
'post', data: payload });
diff --git a/config-ui/src/store/connections/api.ts 
b/config-ui/src/api/connection/types.ts
similarity index 73%
rename from config-ui/src/store/connections/api.ts
rename to config-ui/src/api/connection/types.ts
index b7c443272..933133e2d 100644
--- a/config-ui/src/store/connections/api.ts
+++ b/config-ui/src/api/connection/types.ts
@@ -16,34 +16,41 @@
  *
  */
 
-import { request } from '@/utils';
-
-type GetConnectionRes = {
+export type Connection = {
   id: ID;
   name: string;
   endpoint: string;
-  proxy: string;
+  authMethod?: string;
   token?: string;
   username?: string;
   password?: string;
-  authMethod?: string;
+  proxy: string;
+  apiKey?: string;
 };
 
-export const getConnection = (plugin: string): Promise<GetConnectionRes[]> => 
request(`/plugins/${plugin}/connections`);
-
-type TestConnectionPayload = {
-  endpoint: string;
-  proxy: string;
-  token?: string;
+export type ConnectionForm = {
+  name: string;
+  endpoint?: string;
+  authMethod?: string;
   username?: string;
   password?: string;
-  authMethod?: string;
+  token?: string;
   appId?: string;
   secretKey?: string;
+  enableGraphql?: boolean;
+  proxy: string;
+  rateLimitPerHour?: number;
 };
 
-export const testConnection = (plugin: string, data: TestConnectionPayload) =>
-  request(`/plugins/${plugin}/test`, {
-    method: 'post',
-    data,
-  });
+export type ConnectionTest = {
+  message: string;
+  success: boolean;
+  login?: string;
+  installations?: Array<{
+    id: number;
+    account: {
+      login: string;
+    };
+  }>;
+  warning?: string;
+};
diff --git a/config-ui/src/api/index.ts b/config-ui/src/api/index.ts
new file mode 100644
index 000000000..609c65a1c
--- /dev/null
+++ b/config-ui/src/api/index.ts
@@ -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 { request } from '@/utils';
+
+import * as apiKey from './api-key';
+import * as blueprint from './blueprint';
+import * as connection from './connection';
+import * as pipeline from './pipeline';
+import plugin from './plugin';
+import * as project from './project';
+import * as scope from './scope';
+import * as scopeConfig from './scope-config';
+import * as task from './task';
+
+const migrate = () => request('/proceed-db-migration');
+const ping = () => request('/ping');
+const version = (signal?: AbortSignal): Promise<{ version: string }> => 
request('/version', { signal });
+const userInfo = (signal?: AbortSignal): Promise<{ user: string; email: 
string; logoutURI: string }> =>
+  request('/userinfo', { signal });
+
+export const API = {
+  apiKey,
+  blueprint,
+  connection,
+  pipeline,
+  plugin,
+  project,
+  scopeConfig,
+  scope,
+  task,
+  migrate,
+  ping,
+  version,
+  userInfo,
+};
+
+export default API;
diff --git a/config-ui/src/routes/pipeline/api.ts 
b/config-ui/src/api/pipeline/index.ts
similarity index 65%
rename from config-ui/src/routes/pipeline/api.ts
rename to config-ui/src/api/pipeline/index.ts
index 261e04a99..4b90ccc55 100644
--- a/config-ui/src/routes/pipeline/api.ts
+++ b/config-ui/src/api/pipeline/index.ts
@@ -20,25 +20,20 @@ import { request } from '@/utils';
 
 import * as T from './types';
 
-export const getPipelines = (): Promise<{ count: number; pipelines: 
T.Pipeline[] }> => request('/pipelines');
+export const list = (): Promise<{ count: number; pipelines: T.Pipeline[] }> => 
request('/pipelines');
 
-export const getPipeline = (id: ID) => request(`/pipelines/${id}`);
+export const get = (id: ID) => request(`/pipelines/${id}`);
 
-export const deletePipeline = (id: ID) =>
+export const remove = (id: ID) =>
   request(`/pipelines/${id}`, {
     method: 'delete',
   });
 
-export const rerunPipeline = (id: ID) =>
+export const rerun = (id: ID) =>
   request(`/pipelines/${id}/rerun`, {
     method: 'post',
   });
 
-export const getPipelineLog = (id: ID) => 
request(`/pipelines/${id}/logging.tar.gz`);
+export const log = (id: ID) => request(`/pipelines/${id}/logging.tar.gz`);
 
-export const getPipelineTasks = (id: ID) => request(`/pipelines/${id}/tasks`);
-
-export const taskRerun = (id: ID) =>
-  request(`/tasks/${id}/rerun`, {
-    method: 'post',
-  });
+export const tasks = (id: ID) => request(`/pipelines/${id}/tasks`);
diff --git a/config-ui/src/pages/blueprint/home/api.ts 
b/config-ui/src/api/pipeline/types.ts
similarity index 62%
rename from config-ui/src/pages/blueprint/home/api.ts
rename to config-ui/src/api/pipeline/types.ts
index d6554b6aa..f1fbc462b 100644
--- a/config-ui/src/pages/blueprint/home/api.ts
+++ b/config-ui/src/api/pipeline/types.ts
@@ -16,20 +16,25 @@
  *
  */
 
-import { request } from '@/utils';
+export enum PipelineStatus {
+  CREATED = 'TASK_CREATED',
+  PENDING = 'TASK_PENDING',
+  ACTIVE = 'TASK_ACTIVE',
+  RUNNING = 'TASK_RUNNING',
+  RERUN = 'TASK_RERUN',
+  COMPLETED = 'TASK_COMPLETED',
+  PARTIAL = 'TASK_PARTIAL',
+  FAILED = 'TASK_FAILED',
+  CANCELLED = 'TASK_CANCELLED',
+}
 
-import { BlueprintType } from '../types';
-
-type ResponseType = {
-  blueprints: Array<BlueprintType>;
-  count: number;
+export type Pipeline = {
+  id: ID;
+  status: PipelineStatus;
+  beganAt: string | null;
+  finishedAt: string | null;
+  stage: number;
+  finishedTasks: number;
+  totalTasks: number;
+  message: string;
 };
-
-export const getBlueprints = (params: Pagination & { type: string }): 
Promise<ResponseType> =>
-  request('/blueprints', { data: params });
-
-export const createBlueprint = (payload: any) =>
-  request('/blueprints', {
-    method: 'post',
-    data: payload,
-  });
diff --git a/config-ui/src/plugins/register/github/api.ts 
b/config-ui/src/api/plugin/index.ts
similarity index 81%
rename from config-ui/src/plugins/register/github/api.ts
rename to config-ui/src/api/plugin/index.ts
index ad19f05d0..4f6633b38 100644
--- a/config-ui/src/plugins/register/github/api.ts
+++ b/config-ui/src/api/plugin/index.ts
@@ -16,6 +16,14 @@
  *
  */
 
-import { request } from '@/utils';
+import * as jira from './jira';
+import * as tapd from './tapd';
+import * as webhook from './webhook';
 
-export const testConnection = (payload: any) => 
request('/plugins/github/test', { method: 'post', data: payload });
+export const plugin = {
+  jira,
+  tapd,
+  webhook,
+};
+
+export default plugin;
diff --git a/config-ui/src/plugins/register/jira/api.ts 
b/config-ui/src/api/plugin/jira/index.ts
similarity index 77%
rename from config-ui/src/plugins/register/jira/api.ts
rename to config-ui/src/api/plugin/jira/index.ts
index 07f6fd8ef..c9efeb18f 100644
--- a/config-ui/src/plugins/register/jira/api.ts
+++ b/config-ui/src/api/plugin/jira/index.ts
@@ -23,19 +23,19 @@ export type GetBoardsParams = {
   maxResults: number;
 };
 
-export const getBoards = (prefix: string, params: GetBoardsParams) =>
+export const boards = (prefix: string, params: GetBoardsParams) =>
   request(`${prefix}/agile/1.0/board`, { data: params });
 
-export const getIssueType = (prefix: string) => 
request(`${prefix}/api/2/issuetype`);
+export const issueType = (prefix: string) => 
request(`${prefix}/api/2/issuetype`);
 
-export const getField = (prefix: string) => request(`${prefix}/api/2/field`);
+export const field = (prefix: string) => request(`${prefix}/api/2/field`);
 
-export const getApplicationTypes = (connectionId: ID, query: { key: string }) 
=>
+export const applicationTypes = (connectionId: ID, query: { key: string }) =>
   request(`/plugins/jira/connections/${connectionId}/application-types`, {
     data: query,
   });
 
-export const getDevPanelCommits = (connectionId: ID, query: { key: string; 
applicationType: string }) =>
+export const devPanelCommits = (connectionId: ID, query: { key: string; 
applicationType: string }) =>
   request(`/plugins/jira/connections/${connectionId}/dev-panel-commits`, { 
data: query });
 
 export const generateRegex = (pattern: string) =>
diff --git a/config-ui/src/plugins/register/tapd/api.ts 
b/config-ui/src/api/plugin/tapd/index.ts
similarity index 82%
rename from config-ui/src/plugins/register/tapd/api.ts
rename to config-ui/src/api/plugin/tapd/index.ts
index f4cf67bd7..d6fe7ba94 100644
--- a/config-ui/src/plugins/register/tapd/api.ts
+++ b/config-ui/src/api/plugin/tapd/index.ts
@@ -23,16 +23,16 @@ export type GetBoardsParams = {
   maxResults: number;
 };
 
-export const getBoards = (prefix: string, params: GetBoardsParams) =>
+export const boards = (prefix: string, params: GetBoardsParams) =>
   request(`${prefix}/agile/1.0/board`, { data: params });
 
-export const getStatus = (prefix: string, workspaceId: ID, system: string) =>
+export const statusMap = (prefix: string, workspaceId: ID, system: string) =>
   
request(`${prefix}/workflows/status_map?workspace_id=${workspaceId}&system=${system}`);
 
-export const getStoryType = (prefix: string, workspaceId: ID) =>
+export const storyCategories = (prefix: string, workspaceId: ID) =>
   request(`${prefix}/story_categories?workspace_id=${workspaceId}`);
 
-export const prepareToken = (connectionId: ID, params: object) =>
+export const remoteScopePrepareToken = (connectionId: ID, params: object) =>
   
request(`/plugins/tapd/connections/${connectionId}/remote-scopes-prepare-token`,
 {
     method: 'get',
     data: params,
diff --git a/config-ui/src/pages/blueprint/detail/api.ts 
b/config-ui/src/api/plugin/webhook/index.ts
similarity index 55%
rename from config-ui/src/pages/blueprint/detail/api.ts
rename to config-ui/src/api/plugin/webhook/index.ts
index d63293958..eb84d54f5 100644
--- a/config-ui/src/pages/blueprint/detail/api.ts
+++ b/config-ui/src/api/plugin/webhook/index.ts
@@ -16,18 +16,26 @@
  *
  */
 
-import { request } from '@/utils';
+import * as connection from '../../connection';
 
-import type { BlueprintType } from '../types';
+export const list = () => connection.list('webhook');
 
-export const getBlueprint = (id: ID): Promise<BlueprintType> => 
request(`/blueprints/${id}`);
+export const get = (
+  id: ID,
+): Promise<{
+  name: string;
+  postIssuesEndpoint: string;
+  closeIssuesEndpoint: string;
+  postPipelineDeployTaskEndpoint: string;
+  apiKey: {
+    id: string;
+    apiKey: string;
+  };
+}> => connection.get('webook', id) as any;
 
-export const getBlueprintPipelines = (id: ID) => 
request(`/blueprints/${id}/pipelines`);
+export const create = (payload: any): Promise<{ id: string; apiKey: { apiKey: 
string } }> =>
+  connection.create('webhook', payload) as any;
 
-export const runBlueprint = (id: ID, data: { skipCollectors: boolean; 
fullSync: boolean }) =>
-  request(`/blueprints/${id}/trigger`, { method: 'post', data });
+export const remove = (id: ID) => connection.remove('webhook', id);
 
-export const updateBlueprint = (id: ID, payload: BlueprintType) =>
-  request(`/blueprints/${id}`, { method: 'patch', data: payload });
-
-export const deleteBluprint = (id: ID) => request(`/blueprints/${id}`, { 
method: 'delete' });
+export const update = (id: ID, payload: any) => connection.update('webhook', 
id, payload);
diff --git a/config-ui/src/pages/project/detail/api.ts 
b/config-ui/src/api/project/index.ts
similarity index 64%
rename from config-ui/src/pages/project/detail/api.ts
rename to config-ui/src/api/project/index.ts
index bc8fdaca4..21e7ed780 100644
--- a/config-ui/src/pages/project/detail/api.ts
+++ b/config-ui/src/api/project/index.ts
@@ -18,23 +18,26 @@
 
 import { request } from '@/utils';
 
-import type { ProjectType, BlueprintType } from '@/pages';
+import * as T from './types';
 
-export const getProject = (name: string): Promise<ProjectType> => 
request(`/projects/${name}`);
+export const list = (data: Pagination): Promise<{ count: number; projects: 
T.Project[] }> =>
+  request('/projects', { data });
 
-export const updateProject = (name: string, payload: Omit<ProjectType, 
'blueprint'>) =>
-  request(`/projects/${name}`, {
-    method: 'patch',
-    data: payload,
-  });
+export const get = (name: string): Promise<T.Project> => 
request(`/projects/${name}`);
 
-export const updateBlueprint = (id: ID, payload: BlueprintType) =>
-  request(`/blueprints/${id}`, {
-    method: 'patch',
-    data: payload,
+export const create = (data: Pick<T.Project, 'name' | 'description' | 
'metrics'>) =>
+  request('/projects', {
+    method: 'post',
+    data,
   });
 
-export const deleteProject = (name: string) =>
+export const remove = (name: string) =>
   request(`/projects/${name}`, {
     method: 'delete',
   });
+
+export const update = (name: string, data: Pick<T.Project, 'name' | 
'description' | 'metrics'>) =>
+  request(`/projects/${name}`, {
+    method: 'patch',
+    data,
+  });
diff --git a/config-ui/src/routes/layout/api.ts 
b/config-ui/src/api/project/types.ts
similarity index 68%
rename from config-ui/src/routes/layout/api.ts
rename to config-ui/src/api/project/types.ts
index 20c884f49..6f7a3c8a3 100644
--- a/config-ui/src/routes/layout/api.ts
+++ b/config-ui/src/api/project/types.ts
@@ -16,18 +16,14 @@
  *
  */
 
-import { request } from '@/utils';
+import { Blueprint } from '../blueprint/types';
+import { Pipeline } from '../pipeline/types';
 
-type VersionType = {
-  version: string;
+export type Project = {
+  name: string;
+  description: string;
+  metrics: Array<{ pluginName: string; pluginOption: string; enable: boolean 
}>;
+  createdAt: string;
+  blueprint: Blueprint;
+  lastPipeline: Pipeline;
 };
-
-export const getVersion = (signal?: AbortSignal): Promise<VersionType> => 
request('/version', { signal });
-
-type UserInfoType = {
-  user: string;
-  email: string;
-  logoutURI: string;
-};
-
-export const getUserInfo = (signal?: AbortSignal): Promise<UserInfoType> => 
request('/userinfo', { signal });
diff --git a/config-ui/src/plugins/components/scope-config-select/api.ts 
b/config-ui/src/api/scope-config/index.ts
similarity index 77%
rename from config-ui/src/plugins/components/scope-config-select/api.ts
rename to config-ui/src/api/scope-config/index.ts
index 9f0436eaa..caaa789d7 100644
--- a/config-ui/src/plugins/components/scope-config-select/api.ts
+++ b/config-ui/src/api/scope-config/index.ts
@@ -18,20 +18,20 @@
 
 import { request } from '@/utils';
 
-export const getScopeConfigs = (plugin: string, connectionId: ID) =>
+export const list = (plugin: string, connectionId: ID) =>
   request(`/plugins/${plugin}/connections/${connectionId}/scope-configs`);
 
-export const getScopeConfig = (plugin: string, connectionId: ID, id: ID) =>
+export const get = (plugin: string, connectionId: ID, id: ID) =>
   
request(`/plugins/${plugin}/connections/${connectionId}/scope-configs/${id}`);
 
-export const createScopeConfig = (plugin: string, connectionId: ID, payload: 
any) =>
+export const create = (plugin: string, connectionId: ID, data: any) =>
   request(`/plugins/${plugin}/connections/${connectionId}/scope-configs`, {
     method: 'post',
-    data: payload,
+    data,
   });
 
-export const updateScopeConfig = (plugin: string, connectionId: ID, id: ID, 
payload: any) =>
+export const update = (plugin: string, connectionId: ID, id: ID, data: any) =>
   
request(`/plugins/${plugin}/connections/${connectionId}/scope-configs/${id}`, {
     method: 'patch',
-    data: payload,
+    data,
   });
diff --git a/config-ui/src/plugins/components/data-scope-remote/api.ts 
b/config-ui/src/api/scope/index.ts
similarity index 57%
rename from config-ui/src/plugins/components/data-scope-remote/api.ts
rename to config-ui/src/api/scope/index.ts
index 4c042d6b6..4d19d26af 100644
--- a/config-ui/src/plugins/components/data-scope-remote/api.ts
+++ b/config-ui/src/api/scope/index.ts
@@ -20,37 +20,51 @@ import { request } from '@/utils';
 
 import * as T from './types';
 
-export const getRemoteScope = (
+export const list = (
   plugin: string,
   connectionId: ID,
-  params: T.GetRemoteScopeParams,
-): Promise<{ children: T.ResItem[]; nextPageToken: string }> =>
-  request(`/plugins/${plugin}/connections/${connectionId}/remote-scopes`, {
-    method: 'get',
-    data: params,
+  data?: T.ListQuery,
+): Promise<{ count: number; scopes: T.List }> =>
+  request(`/plugins/${plugin}/connections/${connectionId}/scopes`, {
+    data,
   });
 
-export const searchRemoteScope = (
-  plugin: string,
-  connectionId: ID,
-  params: T.SearchRemoteScopeParams,
-): Promise<{ children: T.ResItem[]; count: number }> =>
-  
request(`/plugins/${plugin}/connections/${connectionId}/search-remote-scopes`, {
-    method: 'get',
-    data: params,
+export const get = (plugin: string, connectionId: ID, scopeId: ID) =>
+  request(`/plugins/${plugin}/connections/${connectionId}/scopes/${scopeId}`);
+
+export const remove = (plugin: string, connectionId: ID, scopeId: ID, 
onlyData: boolean) =>
+  
request(`/plugins/${plugin}/connections/${connectionId}/scopes/${scopeId}?delete_data_only=${onlyData}`,
 {
+    method: 'delete',
   });
 
-export const getDataScope = (plugin: string, connectionId: ID, scopeId: 
string) =>
-  request(`/plugins/${plugin}/connections/${connectionId}/scopes/${scopeId}`);
+export const update = (plugin: string, connectionId: ID, scopeId: ID, payload: 
any) =>
+  request(`/plugins/${plugin}/connections/${connectionId}/scopes/${scopeId}`, {
+    method: 'patch',
+    data: payload,
+  });
 
-export const updateDataScope = (plugin: string, connectionId: ID, payload: 
any) =>
+export const batch = (plugin: string, connectionId: ID, payload: any) =>
   request(`/plugins/${plugin}/connections/${connectionId}/scopes`, {
     method: 'put',
     data: payload,
   });
 
-export const updateDataScopeWithType = (plugin: string, connectionId: ID, 
type: string, payload: any) =>
-  request(`/plugins/${plugin}/connections/${connectionId}/${type}/scopes`, {
-    method: 'put',
-    data: payload,
+export const remote = (
+  plugin: string,
+  connectionId: ID,
+  data: T.RemoteQuery,
+): Promise<{ children: T.RemoteScope[]; nextPageToken: string }> =>
+  request(`/plugins/${plugin}/connections/${connectionId}/remote-scopes`, {
+    method: 'get',
+    data,
+  });
+
+export const searchRemote = (
+  plugin: string,
+  connectionId: ID,
+  data: T.SearchRemoteQuery,
+): Promise<{ children: T.RemoteScope[]; count: number }> =>
+  
request(`/plugins/${plugin}/connections/${connectionId}/search-remote-scopes`, {
+    method: 'get',
+    data,
   });
diff --git a/config-ui/src/plugins/components/data-scope-select/api.ts 
b/config-ui/src/api/scope/types.ts
similarity index 64%
rename from config-ui/src/plugins/components/data-scope-select/api.ts
rename to config-ui/src/api/scope/types.ts
index 18396ec48..07f8c4e6b 100644
--- a/config-ui/src/plugins/components/data-scope-select/api.ts
+++ b/config-ui/src/api/scope/types.ts
@@ -16,18 +16,35 @@
  *
  */
 
-import { request } from '@/utils';
-
-type ParamsType = {
+export type ListQuery = Pagination & {
+  blueprint?: boolean;
   searchTerm?: string;
-} & Pagination;
+};
 
-type ResponseType = {
-  scopes: Array<{ scope: { name: string; fullName: string } }>;
-  count: number;
+export type Scope = {
+  name: string;
+  fullName: string;
 };
 
-export const getDataScope = (plugin: string, connectionId: ID, params?: 
ParamsType): Promise<ResponseType> =>
-  request(`/plugins/${plugin}/connections/${connectionId}/scopes`, {
-    data: params,
-  });
+export type List = Array<{
+  scope: Scope;
+  scopeConfig?: { name: string };
+}>;
+
+export type RemoteQuery = {
+  groupId: ID | null;
+  pageToken?: string;
+};
+
+export type RemoteScope = {
+  type: 'group' | 'scope';
+  parentId: ID | null;
+  id: ID;
+  name: string;
+  fullName: string;
+  data: any;
+};
+
+export type SearchRemoteQuery = {
+  search?: string;
+} & Pagination;
diff --git a/config-ui/src/routes/error/components/offline/api.ts 
b/config-ui/src/api/task/index.ts
similarity index 89%
rename from config-ui/src/routes/error/components/offline/api.ts
rename to config-ui/src/api/task/index.ts
index 38f8e0fed..42d73de1f 100644
--- a/config-ui/src/routes/error/components/offline/api.ts
+++ b/config-ui/src/api/task/index.ts
@@ -18,4 +18,7 @@
 
 import { request } from '@/utils';
 
-export const ping = () => request('/ping');
+export const rertun = (id: ID) =>
+  request(`/tasks/${id}/rerun`, {
+    method: 'post',
+  });
diff --git a/config-ui/src/pages/blueprint/connection-detail/api.ts 
b/config-ui/src/pages/blueprint/connection-detail/api.ts
deleted file mode 100644
index d66b7e8b0..000000000
--- a/config-ui/src/pages/blueprint/connection-detail/api.ts
+++ /dev/null
@@ -1,37 +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 { request } from '@/utils';
-
-import { BlueprintType } from '../types';
-
-export const getProject = (pname: string): Promise<{ blueprint: BlueprintType 
}> => request(`/projects/${pname}`);
-
-export const getBlueprint = (id: ID): Promise<BlueprintType> => 
request(`/blueprints/${id}`);
-
-export const updateBlueprint = (id: ID, payload: BlueprintType) =>
-  request(`/blueprints/${id}`, { method: 'patch', data: payload });
-
-export const getConnection = (plugin: string, connectionId: ID) =>
-  request(`/plugins/${plugin}/connections/${connectionId}`);
-
-export const getDataScope = (plugin: string, connectionId: ID, scopeId: ID) =>
-  request(`/plugins/${plugin}/connections/${connectionId}/scopes/${scopeId}`);
-
-export const runBlueprint = (id: ID, skipCollectors: boolean) =>
-  request(`/blueprints/${id}/trigger`, { method: 'post', data: { 
skipCollectors } });
diff --git a/config-ui/src/pages/blueprint/connection-detail/index.tsx 
b/config-ui/src/pages/blueprint/connection-detail/index.tsx
index 3dae857e7..bae6b58f8 100644
--- a/config-ui/src/pages/blueprint/connection-detail/index.tsx
+++ b/config-ui/src/pages/blueprint/connection-detail/index.tsx
@@ -21,6 +21,7 @@ import { useNavigate, useParams } from 'react-router-dom';
 import { Button, Intent, Position } from '@blueprintjs/core';
 import { Popover2 } from '@blueprintjs/popover2';
 
+import API from '@/api';
 import { PageLoading, PageHeader, ExternalLink, Message, Buttons, Table, 
Dialog } from '@/components';
 import { useRefreshData, useTips } from '@/hooks';
 import { DataScopeSelect, getPluginScopeId } from '@/plugins';
@@ -28,7 +29,6 @@ import { operator } from '@/utils';
 
 import { encodeName } from '../../project/utils';
 
-import * as API from './api';
 import * as S from './styled';
 
 export const BlueprintConnectionDetailPage = () => {
@@ -43,18 +43,18 @@ export const BlueprintConnectionDetailPage = () => {
 
   const getBlueprint = async (pname?: string, bid?: string) => {
     if (pname) {
-      const res = await API.getProject(pname);
+      const res = await API.project.get(pname);
       return res.blueprint;
     }
 
-    return API.getBlueprint(bid as any);
+    return API.blueprint.get(bid as any);
   };
 
   const { ready, data } = useRefreshData(async () => {
     const [plugin, connectionId] = unique.split('-');
     const [blueprint, connection] = await Promise.all([
       getBlueprint(pname, bid),
-      API.getConnection(plugin, connectionId),
+      API.connection.get(plugin, connectionId),
     ]);
 
     const scopeIds =
@@ -62,7 +62,7 @@ export const BlueprintConnectionDetailPage = () => {
         .find((cs) => cs.pluginName === plugin && cs.connectionId === 
+connectionId)
         ?.scopes?.map((sc: any) => sc.scopeId) ?? [];
 
-    const scopes = await Promise.all(scopeIds.map((scopeId) => 
API.getDataScope(plugin, connectionId, scopeId)));
+    const scopes = await Promise.all(scopeIds.map((scopeId) => 
API.scope.get(plugin, connectionId, scopeId)));
 
     return {
       blueprint,
@@ -91,7 +91,7 @@ export const BlueprintConnectionDetailPage = () => {
   const handleHideDataScope = () => setIsOpen(false);
 
   const handleRunBP = async (skipCollectors: boolean) => {
-    const [success] = await operator(() => API.runBlueprint(blueprint.id, 
skipCollectors), {
+    const [success] = await operator(() => API.blueprint.trigger(blueprint.id, 
{ skipCollectors, fullSync: false }), {
       setOperating,
       formatMessage: () => 'Trigger blueprint successful.',
     });
@@ -119,7 +119,7 @@ export const BlueprintConnectionDetailPage = () => {
 
   const handleRemoveConnection = async () => {
     const [success] = await operator(() =>
-      API.updateBlueprint(blueprint.id, {
+      API.blueprint.update(blueprint.id, {
         ...blueprint,
         connections: blueprint.connections.filter(
           (cs) => !(cs.pluginName === connection.plugin && cs.connectionId === 
connection.id),
@@ -138,7 +138,7 @@ export const BlueprintConnectionDetailPage = () => {
   const handleChangeDataScope = async (scopeIds: any) => {
     const [success] = await operator(
       () =>
-        API.updateBlueprint(blueprint.id, {
+        API.blueprint.update(blueprint.id, {
           ...blueprint,
           connections: blueprint.connections.map((cs) => {
             if (cs.pluginName === connection.plugin && cs.connectionId === 
connection.id) {
diff --git a/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx 
b/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
index 082a580ee..5491a31a7 100644
--- a/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
+++ b/config-ui/src/pages/blueprint/detail/blueprint-detail.tsx
@@ -20,6 +20,7 @@ import { useState } from 'react';
 import { Tabs, Tab } from '@blueprintjs/core';
 import useUrlState from '@ahooksjs/use-url-state';
 
+import API from '@/api';
 import { PageLoading } from '@/components';
 import { useRefreshData } from '@/hooks';
 
@@ -27,7 +28,6 @@ import { FromEnum } from '../types';
 
 import { ConfigurationPanel } from './configuration-panel';
 import { StatusPanel } from './status-panel';
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -41,7 +41,7 @@ export const BlueprintDetail = ({ id, from }: Props) => {
   const [query, setQuery] = useUrlState({ tab: 'status' });
 
   const { ready, data } = useRefreshData(async () => {
-    const [bpRes, pipelineRes] = await Promise.all([API.getBlueprint(id), 
API.getBlueprintPipelines(id)]);
+    const [bpRes, pipelineRes] = await Promise.all([API.blueprint.get(id), 
API.blueprint.pipelines(id)]);
     return [bpRes, pipelineRes.pipelines[0]];
   }, [version]);
 
diff --git a/config-ui/src/pages/blueprint/detail/configuration-panel.tsx 
b/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
index 58eb17694..4ab0c135d 100644
--- a/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
+++ b/config-ui/src/pages/blueprint/detail/configuration-panel.tsx
@@ -20,6 +20,7 @@ import { useState, useEffect, useMemo } from 'react';
 import { Link } from 'react-router-dom';
 import { Button, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { IconButton, Table, NoData, Buttons } from '@/components';
 import { getCron } from '@/config';
 import { useConnections } from '@/hooks';
@@ -33,7 +34,6 @@ import { ModeEnum } from '../types';
 import { validRawPlan } from '../utils';
 
 import { AdvancedEditor, UpdateNameDialog, UpdatePolicyDialog, 
AddConnectionDialog } from './components';
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -92,7 +92,7 @@ export const ConfigurationPanel = ({ from, blueprint, 
onRefresh, onChangeTab }:
   const handleUpdate = async (payload: any) => {
     const [success] = await operator(
       () =>
-        API.updateBlueprint(blueprint.id, {
+        API.blueprint.update(blueprint.id, {
           ...blueprint,
           ...payload,
         }),
@@ -109,10 +109,13 @@ export const ConfigurationPanel = ({ from, blueprint, 
onRefresh, onChangeTab }:
   };
 
   const handleRun = async () => {
-    const [success] = await operator(() => API.runBlueprint(blueprint.id, { 
skipCollectors: false, fullSync: false }), {
-      setOperating,
-      formatMessage: () => 'Trigger blueprint successful.',
-    });
+    const [success] = await operator(
+      () => API.blueprint.trigger(blueprint.id, { skipCollectors: false, 
fullSync: false }),
+      {
+        setOperating,
+        formatMessage: () => 'Trigger blueprint successful.',
+      },
+    );
 
     if (success) {
       onRefresh();
diff --git a/config-ui/src/pages/blueprint/detail/status-panel.tsx 
b/config-ui/src/pages/blueprint/detail/status-panel.tsx
index b0fbaa42a..018a0de78 100644
--- a/config-ui/src/pages/blueprint/detail/status-panel.tsx
+++ b/config-ui/src/pages/blueprint/detail/status-panel.tsx
@@ -21,6 +21,7 @@ import { useNavigate } from 'react-router-dom';
 import { Button, Switch, Intent, Position, Popover, Menu, MenuItem } from 
'@blueprintjs/core';
 import { Tooltip2 } from '@blueprintjs/popover2';
 
+import API from '@/api';
 import { Card, IconButton, Dialog, Message } from '@/components';
 import { getCron } from '@/config';
 import { useAutoRefresh } from '@/hooks';
@@ -30,7 +31,6 @@ import { formatTime, operator } from '@/utils';
 
 import { BlueprintType, FromEnum } from '../types';
 
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -50,7 +50,7 @@ export const StatusPanel = ({ from, blueprint, pipelineId, 
onRefresh }: Props) =
 
   const { loading, data } = useAutoRefresh<PipelineT.Pipeline[]>(
     async () => {
-      const res = await API.getBlueprintPipelines(blueprint.id);
+      const res = await API.blueprint.pipelines(blueprint.id);
       return res.pipelines;
     },
     [],
@@ -81,7 +81,7 @@ export const StatusPanel = ({ from, blueprint, pipelineId, 
onRefresh }: Props) =
     skipCollectors?: boolean;
     fullSync?: boolean;
   }) => {
-    const [success] = await operator(() => API.runBlueprint(blueprint.id, { 
skipCollectors, fullSync }), {
+    const [success] = await operator(() => API.blueprint.trigger(blueprint.id, 
{ skipCollectors, fullSync }), {
       setOperating,
       formatMessage: () => 'Trigger blueprint successful.',
     });
@@ -94,7 +94,7 @@ export const StatusPanel = ({ from, blueprint, pipelineId, 
onRefresh }: Props) =
   const handleUpdate = async (payload: any) => {
     const [success] = await operator(
       () =>
-        API.updateBlueprint(blueprint.id, {
+        API.blueprint.update(blueprint.id, {
           ...blueprint,
           ...payload,
         }),
@@ -110,7 +110,7 @@ export const StatusPanel = ({ from, blueprint, pipelineId, 
onRefresh }: Props) =
   };
 
   const handleDelete = async () => {
-    const [success] = await operator(() => API.deleteBluprint(blueprint.id), {
+    const [success] = await operator(() => API.blueprint.remove(blueprint.id), 
{
       setOperating,
       formatMessage: () => 'Delete blueprint successful.',
     });
diff --git a/config-ui/src/pages/blueprint/home/index.tsx 
b/config-ui/src/pages/blueprint/home/index.tsx
index 5bc67f692..96946ebee 100644
--- a/config-ui/src/pages/blueprint/home/index.tsx
+++ b/config-ui/src/pages/blueprint/home/index.tsx
@@ -21,6 +21,7 @@ import { Link } from 'react-router-dom';
 import { ButtonGroup, Button, Tag, Intent, FormGroup, InputGroup, RadioGroup, 
Radio } from '@blueprintjs/core';
 import dayjs from 'dayjs';
 
+import API from '@/api';
 import { PageHeader, Table, IconButton, TextTooltip, Dialog } from 
'@/components';
 import { getCronOptions, cronPresets, getCron } from '@/config';
 import { useConnections, useRefreshData } from '@/hooks';
@@ -28,7 +29,6 @@ import { formatTime, operator } from '@/utils';
 
 import { ModeEnum } from '../types';
 
-import * as API from './api';
 import * as S from './styled';
 
 export const BlueprintHomePage = () => {
@@ -43,7 +43,7 @@ export const BlueprintHomePage = () => {
 
   const { onGet } = useConnections();
   const { ready, data } = useRefreshData(
-    () => API.getBlueprints({ type: type.toLocaleUpperCase(), page, pageSize 
}),
+    () => API.blueprint.list({ type: type.toLocaleUpperCase(), page, pageSize 
}),
     [version, type, page, pageSize],
   );
 
@@ -93,7 +93,7 @@ export const BlueprintHomePage = () => {
       payload.plan = [[]];
     }
 
-    const [success] = await operator(() => API.createBlueprint(payload), {
+    const [success] = await operator(() => API.blueprint.create(payload), {
       setOperating: setSaving,
     });
 
diff --git a/config-ui/src/pages/connection/detail/api.ts 
b/config-ui/src/pages/connection/detail/api.ts
deleted file mode 100644
index 9b8a999a0..000000000
--- a/config-ui/src/pages/connection/detail/api.ts
+++ /dev/null
@@ -1,44 +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 { request } from '@/utils';
-
-export const deleteConnection = (plugin: string, id: ID) =>
-  request(`/plugins/${plugin}/connections/${id}`, { method: 'delete' });
-
-export const getDataScopes = (plugin: string, id: ID, payload: Pagination) =>
-  request(`/plugins/${plugin}/connections/${id}/scopes`, {
-    data: {
-      blueprints: true,
-      ...payload,
-    },
-  });
-
-export const getDataScope = (plugin: string, id: ID, scopeId: ID) =>
-  request(`/plugins/${plugin}/connections/${id}/scopes/${scopeId}`);
-
-export const updateDataScope = (plugin: string, id: ID, scopeId: ID, payload: 
any) =>
-  request(`/plugins/${plugin}/connections/${id}/scopes/${scopeId}`, {
-    method: 'patch',
-    data: payload,
-  });
-
-export const deleteDataScope = (plugin: string, id: ID, scopeId: ID, onlyData: 
boolean) =>
-  
request(`/plugins/${plugin}/connections/${id}/scopes/${scopeId}?delete_data_only=${onlyData}`,
 {
-    method: 'delete',
-  });
diff --git a/config-ui/src/pages/connection/detail/index.tsx 
b/config-ui/src/pages/connection/detail/index.tsx
index 8fba456ec..908b403ac 100644
--- a/config-ui/src/pages/connection/detail/index.tsx
+++ b/config-ui/src/pages/connection/detail/index.tsx
@@ -20,6 +20,7 @@ import { useState, useEffect, useMemo } from 'react';
 import { useParams, useNavigate, Link } from 'react-router-dom';
 import { Button, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { PageHeader, Buttons, Dialog, IconButton, Table, Message, toast } from 
'@/components';
 import { useTips, useConnections, useRefreshData } from '@/hooks';
 import ClearImg from '@/images/icons/clear.svg';
@@ -34,7 +35,6 @@ import {
 } from '@/plugins';
 import { operator } from '@/utils';
 
-import * as API from './api';
 import * as S from './styled';
 
 export const ConnectionDetailPage = () => {
@@ -72,7 +72,7 @@ const ConnectionDetail = ({ plugin, connectionId }: Props) => 
{
   const { onGet, onTest, onRefresh } = useConnections();
   const { setTips } = useTips();
   const { ready, data } = useRefreshData(
-    () => API.getDataScopes(plugin, connectionId, { page, pageSize }),
+    () => API.scope.list(plugin, connectionId, { page, pageSize, blueprint: 
true }),
     [version, page, pageSize],
   );
 
@@ -110,7 +110,7 @@ const ConnectionDetail = ({ plugin, connectionId }: Props) 
=> {
     const [, res] = await operator(
       async () => {
         try {
-          await API.deleteConnection(plugin, connectionId);
+          await API.connection.remove(plugin, connectionId);
           return { status: 'success' };
         } catch (err: any) {
           const { status, data } = err.response;
@@ -175,7 +175,7 @@ const ConnectionDetail = ({ plugin, connectionId }: Props) 
=> {
     const [, res] = await operator(
       async () => {
         try {
-          await API.deleteDataScope(plugin, connectionId, scopeId, onlyData);
+          await API.scope.remove(plugin, connectionId, scopeId, onlyData);
           return { status: 'success' };
         } catch (err: any) {
           const { status, data } = err.response;
@@ -216,8 +216,8 @@ const ConnectionDetail = ({ plugin, connectionId }: Props) 
=> {
       () =>
         Promise.all(
           scopeIds.map(async (scopeId) => {
-            const scope = await API.getDataScope(plugin, connectionId, 
scopeId);
-            return API.updateDataScope(plugin, connectionId, scopeId, {
+            const scope = await API.scope.get(plugin, connectionId, scopeId);
+            return API.scope.update(plugin, connectionId, scopeId, {
               ...scope,
               scopeConfigId: +trId,
             });
diff --git a/config-ui/src/pages/project/detail/index.tsx 
b/config-ui/src/pages/project/detail/index.tsx
index 131489b8f..ee4702367 100644
--- a/config-ui/src/pages/project/detail/index.tsx
+++ b/config-ui/src/pages/project/detail/index.tsx
@@ -21,13 +21,13 @@ import { useParams } from 'react-router-dom';
 import { Tabs, Tab } from '@blueprintjs/core';
 import useUrlState from '@ahooksjs/use-url-state';
 
+import API from '@/api';
 import { PageHeader, PageLoading } from '@/components';
 import { useRefreshData } from '@/hooks';
 import { BlueprintDetail, FromEnum } from '@/pages';
 
 import { WebhooksPanel } from './webhooks-panel';
 import { SettingsPanel } from './settings-panel';
-import * as API from './api';
 import * as S from './styled';
 
 export const ProjectDetailPage = () => {
@@ -36,7 +36,7 @@ export const ProjectDetailPage = () => {
   const { pname } = useParams() as { pname: string };
   const [query, setQuery] = useUrlState({ tabId: 'blueprint' });
 
-  const { ready, data } = useRefreshData(() => 
Promise.all([API.getProject(pname)]), [pname, version]);
+  const { ready, data } = useRefreshData(() => 
Promise.all([API.project.get(pname)]), [pname, version]);
 
   const handleChangeTabId = (tabId: string) => {
     setQuery({ tabId });
diff --git a/config-ui/src/pages/project/detail/settings-panel.tsx 
b/config-ui/src/pages/project/detail/settings-panel.tsx
index 94c92feef..963e97f74 100644
--- a/config-ui/src/pages/project/detail/settings-panel.tsx
+++ b/config-ui/src/pages/project/detail/settings-panel.tsx
@@ -20,13 +20,13 @@ import { useEffect, useState } from 'react';
 import { useNavigate } from 'react-router-dom';
 import { InputGroup, Checkbox, Button, Icon, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { Card, FormItem, Buttons, toast, Dialog } from '@/components';
 import { operator } from '@/utils';
 
 import type { ProjectType } from '../types';
 import { validName } from '../utils';
 
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -57,7 +57,7 @@ export const SettingsPanel = ({ project, onRefresh }: Props) 
=> {
 
     const [success] = await operator(
       () =>
-        API.updateProject(project.name, {
+        API.project.update(project.name, {
           name,
           description: '',
           metrics: [
@@ -88,7 +88,7 @@ export const SettingsPanel = ({ project, onRefresh }: Props) 
=> {
   };
 
   const handleDelete = async () => {
-    const [success] = await operator(() => API.deleteProject(project.name), {
+    const [success] = await operator(() => API.project.remove(project.name), {
       setOperating,
       formatMessage: () => 'Delete project successful.',
     });
diff --git a/config-ui/src/pages/project/detail/webhooks-panel.tsx 
b/config-ui/src/pages/project/detail/webhooks-panel.tsx
index 7df534e4e..ea53ae2c5 100644
--- a/config-ui/src/pages/project/detail/webhooks-panel.tsx
+++ b/config-ui/src/pages/project/detail/webhooks-panel.tsx
@@ -19,6 +19,7 @@
 import { useState, useMemo } from 'react';
 import { Button, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { Alert, NoData } from '@/components';
 import type { WebhookItemType } from '@/plugins/register/webook';
 import { WebhookCreateDialog, WebhookSelectorDialog, WebHookConnection } from 
'@/plugins/register/webook';
@@ -26,8 +27,6 @@ import { operator } from '@/utils';
 
 import type { ProjectType } from '../types';
 
-import * as API from './api';
-
 interface Props {
   project: ProjectType;
   onRefresh: () => void;
@@ -61,7 +60,7 @@ export const WebhooksPanel = ({ project, onRefresh }: Props) 
=> {
       ],
     };
 
-    const [success] = await operator(() => 
API.updateBlueprint(project.blueprint.id, payload), {
+    const [success] = await operator(() => 
API.blueprint.update(project.blueprint.id, payload), {
       setOperating,
     });
 
@@ -82,7 +81,7 @@ export const WebhooksPanel = ({ project, onRefresh }: Props) 
=> {
       ],
     };
 
-    const [success] = await operator(() => 
API.updateBlueprint(project.blueprint.id, payload), {
+    const [success] = await operator(() => 
API.blueprint.update(project.blueprint.id, payload), {
       setOperating,
     });
 
@@ -99,7 +98,7 @@ export const WebhooksPanel = ({ project, onRefresh }: Props) 
=> {
       ),
     };
 
-    const [success] = await operator(() => 
API.updateBlueprint(project.blueprint.id, payload), {
+    const [success] = await operator(() => 
API.blueprint.update(project.blueprint.id, payload), {
       setOperating,
     });
 
diff --git a/config-ui/src/pages/project/home/api.ts 
b/config-ui/src/pages/project/home/api.ts
deleted file mode 100644
index 9a9a7d09b..000000000
--- a/config-ui/src/pages/project/home/api.ts
+++ /dev/null
@@ -1,62 +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 { request } from '@/utils';
-
-import type { BlueprintType } from '@/pages/blueprint';
-import * as T from '@/routes/pipeline/types';
-
-type GetProjectsParams = {
-  page: number;
-  pageSize: number;
-};
-
-type GetProjectsResponse = {
-  projects: Array<{
-    name: string;
-    createdAt: string;
-    blueprint: BlueprintType;
-    lastPipeline: T.Pipeline;
-  }>;
-  count: number;
-};
-
-export const getProjects = (params: GetProjectsParams): 
Promise<GetProjectsResponse> =>
-  request('/projects', { data: params });
-
-type CreateProjectPayload = {
-  name: string;
-  description: string;
-  metrics: Array<{
-    pluginName: string;
-    pluginOption: string;
-    enable: boolean;
-  }>;
-};
-
-export const createProject = (payload: CreateProjectPayload) =>
-  request('/projects', {
-    method: 'post',
-    data: payload,
-  });
-
-export const createBlueprint = (payload: any) =>
-  request('/blueprints', {
-    method: 'post',
-    data: payload,
-  });
diff --git a/config-ui/src/pages/project/home/index.tsx 
b/config-ui/src/pages/project/home/index.tsx
index c7a913837..54b167d44 100644
--- a/config-ui/src/pages/project/home/index.tsx
+++ b/config-ui/src/pages/project/home/index.tsx
@@ -21,6 +21,7 @@ import { Link, useNavigate } from 'react-router-dom';
 import { Button, InputGroup, Checkbox, Intent, FormGroup } from 
'@blueprintjs/core';
 import dayjs from 'dayjs';
 
+import API from '@/api';
 import { PageHeader, Table, Dialog, ExternalLink, IconButton, toast } from 
'@/components';
 import { getCron, cronPresets } from '@/config';
 import { useConnections, useRefreshData } from '@/hooks';
@@ -31,7 +32,6 @@ import { PipelineStatus } from '@/routes/pipeline';
 import { validName, encodeName } from '../utils';
 import { BlueprintType, ModeEnum } from '../../blueprint';
 
-import * as API from './api';
 import * as S from './styled';
 
 export const ProjectHomePage = () => {
@@ -43,7 +43,7 @@ export const ProjectHomePage = () => {
   const [enableDora, setEnableDora] = useState(true);
   const [saving, setSaving] = useState(false);
 
-  const { ready, data } = useRefreshData(() => API.getProjects({ page, 
pageSize }), [version, page, pageSize]);
+  const { ready, data } = useRefreshData(() => API.project.list({ page, 
pageSize }), [version, page, pageSize]);
   const { onGet } = useConnections();
 
   const navigate = useNavigate();
@@ -82,7 +82,7 @@ export const ProjectHomePage = () => {
 
     const [success] = await operator(
       async () => {
-        await API.createProject({
+        await API.project.create({
           name,
           description: '',
           metrics: [
@@ -93,7 +93,7 @@ export const ProjectHomePage = () => {
             },
           ],
         });
-        return API.createBlueprint({
+        return API.blueprint.create({
           name: `${name}-Blueprint`,
           projectName: name,
           mode: ModeEnum.normal,
diff --git a/config-ui/src/plugins/components/connection-form/index.tsx 
b/config-ui/src/plugins/components/connection-form/index.tsx
index 0bff7edf3..e64dd6ba4 100644
--- a/config-ui/src/plugins/components/connection-form/index.tsx
+++ b/config-ui/src/plugins/components/connection-form/index.tsx
@@ -20,13 +20,13 @@ import { useMemo, useState } from 'react';
 import { Button, Intent } from '@blueprintjs/core';
 import { pick } from 'lodash';
 
+import API from '@/api';
 import { ExternalLink, PageLoading, Buttons } from '@/components';
 import { useRefreshData } from '@/hooks';
 import { getPluginConfig } from '@/plugins';
 import { operator } from '@/utils';
 
 import { Form } from './fields';
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -36,7 +36,7 @@ interface Props {
 }
 
 export const ConnectionForm = ({ plugin, connectionId, onSuccess }: Props) => {
-  const [values, setValues] = useState<Record<string, any>>({});
+  const [values, setValues] = useState<any>({});
   const [errors, setErrors] = useState<Record<string, any>>({});
   const [operating, setOperating] = useState(false);
 
@@ -54,13 +54,13 @@ export const ConnectionForm = ({ plugin, connectionId, 
onSuccess }: Props) => {
       return {};
     }
 
-    return API.getConnection(plugin, connectionId);
+    return API.connection.get(plugin, connectionId);
   }, [plugin, connectionId]);
 
   const handleTest = async () => {
     await operator(
       () =>
-        API.testConnection(
+        API.connection.test(
           plugin,
           pick(values, [
             'endpoint',
@@ -84,7 +84,8 @@ export const ConnectionForm = ({ plugin, connectionId, 
onSuccess }: Props) => {
 
   const handleSave = async () => {
     const [success, res] = await operator(
-      () => (!connectionId ? API.createConnection(plugin, values) : 
API.updateConnection(plugin, connectionId, values)),
+      () =>
+        !connectionId ? API.connection.create(plugin, values) : 
API.connection.update(plugin, connectionId, values),
       {
         setOperating,
         formatMessage: () => (!connectionId ? 'Create a New Connection 
Successful.' : 'Update Connection Successful.'),
diff --git 
a/config-ui/src/plugins/components/data-scope-remote/data-scope-remote.tsx 
b/config-ui/src/plugins/components/data-scope-remote/data-scope-remote.tsx
index fdd224b52..41a7a5e24 100644
--- a/config-ui/src/plugins/components/data-scope-remote/data-scope-remote.tsx
+++ b/config-ui/src/plugins/components/data-scope-remote/data-scope-remote.tsx
@@ -19,13 +19,13 @@
 import { useState, useMemo } from 'react';
 import { Button, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { Buttons } from '@/components';
 import { getPluginConfig } from '@/plugins';
 import { operator } from '@/utils';
 
 import { SearchLocal } from './search-local';
 import { SearchRemote } from './search-remote';
-import * as API from './api';
 
 interface Props {
   plugin: string;
@@ -43,7 +43,7 @@ export const DataScopeRemote = ({ plugin, connectionId, 
disabledScope, onCancel,
 
   const handleSubmit = async () => {
     const [success, res] = await operator(
-      () => API.updateDataScope(plugin, connectionId, { data: 
selectedScope.map((it) => it.data) }),
+      () => API.scope.batch(plugin, connectionId, { data: 
selectedScope.map((it) => it.data) }),
       {
         setOperating,
         formatMessage: () => 'Add data scope successful.',
diff --git 
a/config-ui/src/plugins/components/data-scope-remote/search-local.tsx 
b/config-ui/src/plugins/components/data-scope-remote/search-local.tsx
index 191b013d5..938ece0a7 100644
--- a/config-ui/src/plugins/components/data-scope-remote/search-local.tsx
+++ b/config-ui/src/plugins/components/data-scope-remote/search-local.tsx
@@ -22,11 +22,11 @@ import type { McsID, McsItem, McsColumn } from 
'miller-columns-select';
 import { MillerColumnsSelect } from 'miller-columns-select';
 import { useDebounce } from 'ahooks';
 
+import API from '@/api';
 import { FormItem, MultiSelector, Loading, Dialog, Message } from 
'@/components';
 import { PluginConfigType } from '@/plugins';
 
 import * as T from './types';
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -88,7 +88,7 @@ export const SearchLocal = ({ plugin, connectionId, config, 
disabledScope, selec
       return;
     }
 
-    const res = await API.getRemoteScope(plugin, connectionId, {
+    const res = await API.scope.remote(plugin, connectionId, {
       groupId,
       pageToken: currentPageToken,
     });
diff --git 
a/config-ui/src/plugins/components/data-scope-remote/search-remote.tsx 
b/config-ui/src/plugins/components/data-scope-remote/search-remote.tsx
index b2b2556db..e0328c65b 100644
--- a/config-ui/src/plugins/components/data-scope-remote/search-remote.tsx
+++ b/config-ui/src/plugins/components/data-scope-remote/search-remote.tsx
@@ -23,11 +23,11 @@ import MillerColumnsSelect from 'miller-columns-select';
 import { useDebounce } from 'ahooks';
 import { uniqBy } from 'lodash';
 
+import API from '@/api';
 import { FormItem, MultiSelector, Loading } from '@/components';
 import { PluginConfigType } from '@/plugins';
 
 import * as T from './types';
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -67,7 +67,7 @@ export const SearchRemote = ({ plugin, connectionId, config, 
disabledScope, sele
   const allItems = useMemo(() => uniqBy([...miller.items, ...search.items], 
'id'), [miller.items, search.items]);
 
   const getItems = async (groupId: ID | null, currentPageToken?: string) => {
-    const res = await API.getRemoteScope(plugin, connectionId, {
+    const res = await API.scope.remote(plugin, connectionId, {
       groupId,
       pageToken: currentPageToken,
     });
@@ -102,7 +102,7 @@ export const SearchRemote = ({ plugin, connectionId, 
config, disabledScope, sele
   const searchItems = async () => {
     if (!searchDebounce) return;
 
-    const res = await API.searchRemoteScope(plugin, connectionId, {
+    const res = await API.scope.searchRemote(plugin, connectionId, {
       search: searchDebounce,
       page: search.page,
       pageSize: 50,
diff --git a/config-ui/src/plugins/components/data-scope-select/index.tsx 
b/config-ui/src/plugins/components/data-scope-select/index.tsx
index ded40244d..65e95bd76 100644
--- a/config-ui/src/plugins/components/data-scope-select/index.tsx
+++ b/config-ui/src/plugins/components/data-scope-select/index.tsx
@@ -22,11 +22,11 @@ import { useDebounce } from 'ahooks';
 import type { McsItem } from 'miller-columns-select';
 import MillerColumnsSelect from 'miller-columns-select';
 
+import API from '@/api';
 import { FormItem, ExternalLink, Message, Buttons, MultiSelector } from 
'@/components';
 import { useRefreshData } from '@/hooks';
 import { getPluginScopeId } from '@/plugins';
 
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -59,7 +59,7 @@ export const DataScopeSelect = ({
   }, []);
 
   const getDataScope = async (page: number) => {
-    const res = await API.getDataScope(plugin, connectionId, { page, pageSize 
});
+    const res = await API.scope.list(plugin, connectionId, { page, pageSize });
     setItems([
       ...items,
       ...res.scopes.map((sc) => ({
@@ -80,10 +80,7 @@ export const DataScopeSelect = ({
 
   const search = useDebounce(query, { wait: 500 });
 
-  const { ready, data } = useRefreshData(
-    () => API.getDataScope(plugin, connectionId, { searchTerm: search }),
-    [search],
-  );
+  const { ready, data } = useRefreshData(() => API.scope.list(plugin, 
connectionId, { searchTerm: search }), [search]);
 
   const searchItems = useMemo(() => data?.scopes.map((sc) => sc.scope) ?? [], 
[data]);
 
diff --git a/config-ui/src/plugins/components/scope-config-form/api.ts 
b/config-ui/src/plugins/components/scope-config-form/api.ts
deleted file mode 100644
index b5d9a186d..000000000
--- a/config-ui/src/plugins/components/scope-config-form/api.ts
+++ /dev/null
@@ -1,34 +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 { request } from '@/utils';
-
-export const getScopeConfig = (plugin: string, connectionId: ID, id: ID) =>
-  
request(`/plugins/${plugin}/connections/${connectionId}/scope-configs/${id}`);
-
-export const createScopeConfig = (plugin: string, connectionId: ID, payload: 
any) =>
-  request(`/plugins/${plugin}/connections/${connectionId}/scope-configs`, {
-    method: 'post',
-    data: payload,
-  });
-
-export const updateScopeConfig = (plugin: string, connectionId: ID, id: ID, 
payload: any) =>
-  
request(`/plugins/${plugin}/connections/${connectionId}/scope-configs/${id}`, {
-    method: 'patch',
-    data: payload,
-  });
diff --git a/config-ui/src/plugins/components/scope-config-form/index.tsx 
b/config-ui/src/plugins/components/scope-config-form/index.tsx
index f52cbee96..08d6062e9 100644
--- a/config-ui/src/plugins/components/scope-config-form/index.tsx
+++ b/config-ui/src/plugins/components/scope-config-form/index.tsx
@@ -20,6 +20,7 @@ import { useState, useEffect, useMemo } from 'react';
 import { omit } from 'lodash';
 import { InputGroup, Button, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { Alert, ExternalLink, Card, FormItem, MultiSelector, Message, Buttons, 
Divider } from '@/components';
 import { transformEntities, EntitiesLabel } from '@/config';
 import { getPluginConfig } from '@/plugins';
@@ -35,7 +36,6 @@ import { operator } from '@/utils';
 
 import { AdditionalSettings } from './fields';
 import { TIPS_MAP } from './misc';
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -80,7 +80,7 @@ export const ScopeConfigForm = ({
 
     (async () => {
       try {
-        const res = await API.getScopeConfig(plugin, connectionId, 
scopeConfigId);
+        const res = await API.scopeConfig.get(plugin, connectionId, 
scopeConfigId);
         setName(res.name);
         setEntities(res.entities);
         setTransformation(omit(res, ['id', 'connectionId', 'name', 'entities', 
'createdAt', 'updatedAt']));
@@ -100,8 +100,8 @@ export const ScopeConfigForm = ({
     const [success, res] = await operator(
       () =>
         !scopeConfigId
-          ? API.createScopeConfig(plugin, connectionId, { name, entities, 
...transformation })
-          : API.updateScopeConfig(plugin, connectionId, scopeConfigId, { name, 
entities, ...transformation }),
+          ? API.scopeConfig.create(plugin, connectionId, { name, entities, 
...transformation })
+          : API.scopeConfig.update(plugin, connectionId, scopeConfigId, { 
name, entities, ...transformation }),
       {
         setOperating,
         formatMessage: () => (!scopeConfigId ? 'Create scope config 
successful.' : 'Update scope config successful'),
diff --git a/config-ui/src/plugins/components/scope-config-select/index.tsx 
b/config-ui/src/plugins/components/scope-config-select/index.tsx
index 0b11031ce..9329aa0bb 100644
--- a/config-ui/src/plugins/components/scope-config-select/index.tsx
+++ b/config-ui/src/plugins/components/scope-config-select/index.tsx
@@ -19,12 +19,12 @@
 import { useState, useEffect, useMemo } from 'react';
 import { Button, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { Buttons, Table, IconButton, Dialog } from '@/components';
 import { useRefreshData } from '@/hooks';
 
 import { ScopeConfigForm } from '../scope-config-form';
 
-import * as API from './api';
 import * as S from './styled';
 
 interface Props {
@@ -41,7 +41,7 @@ export const ScopeConfigSelect = ({ plugin, connectionId, 
scopeConfigId, onCance
   const [isOpen, setIsOpen] = useState(false);
   const [updatedId, setUpdatedId] = useState<ID>();
 
-  const { ready, data } = useRefreshData(() => API.getScopeConfigs(plugin, 
connectionId), [version]);
+  const { ready, data } = useRefreshData(() => API.scopeConfig.list(plugin, 
connectionId), [version]);
 
   const dataSource = useMemo(() => (data ? data : []), [data]);
 
diff --git 
a/config-ui/src/plugins/register/github/connection-fields/githubapp.tsx 
b/config-ui/src/plugins/register/github/connection-fields/githubapp.tsx
index 8c717f745..1058d3192 100644
--- a/config-ui/src/plugins/register/github/connection-fields/githubapp.tsx
+++ b/config-ui/src/plugins/register/github/connection-fields/githubapp.tsx
@@ -20,15 +20,14 @@ import { useEffect, useState } from 'react';
 import { Button, FormGroup, InputGroup, MenuItem, TextArea } from 
'@blueprintjs/core';
 import { Select2 } from '@blueprintjs/select';
 
+import API from '@/api';
 import { ExternalLink } from '@/components';
 
-import * as API from '../api';
-
 import * as S from './styled';
 
 interface Props {
   endpoint?: string;
-  proxy?: string;
+  proxy: string;
   initialValue: any;
   value: any;
   error: string;
@@ -87,7 +86,7 @@ export const GithubApp = ({ endpoint, proxy, initialValue, 
value, error, setValu
     }
 
     try {
-      const res = await API.testConnection({
+      const res = await API.connection.test('github', {
         authMethod: 'AppKey',
         endpoint,
         proxy,
diff --git a/config-ui/src/plugins/register/github/connection-fields/token.tsx 
b/config-ui/src/plugins/register/github/connection-fields/token.tsx
index 91a54fa92..889897880 100644
--- a/config-ui/src/plugins/register/github/connection-fields/token.tsx
+++ b/config-ui/src/plugins/register/github/connection-fields/token.tsx
@@ -19,11 +19,10 @@
 import { useEffect, useState } from 'react';
 import { FormGroup, Button, Icon, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { ExternalLink, FormPassword } from '@/components';
 import { DOC_URL } from '@/release';
 
-import * as API from '../api';
-
 import * as S from './styled';
 
 type TokenItem = {
@@ -35,7 +34,7 @@ type TokenItem = {
 
 interface Props {
   endpoint?: string;
-  proxy?: string;
+  proxy: string;
   initialValue: string;
   value: string;
   error: string;
@@ -54,7 +53,7 @@ export const Token = ({ endpoint, proxy, initialValue, value, 
error, setValue, s
     }
 
     try {
-      const res = await API.testConnection({
+      const res = await API.connection.test('github', {
         authMethod: 'AccessToken',
         endpoint,
         proxy,
diff --git a/config-ui/src/plugins/register/gitlab/api.ts 
b/config-ui/src/plugins/register/gitlab/api.ts
deleted file mode 100644
index bcc42d4d0..000000000
--- a/config-ui/src/plugins/register/gitlab/api.ts
+++ /dev/null
@@ -1,56 +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 { request } from '@/utils';
-
-type PaginationParams = {
-  page: number;
-  per_page: number;
-};
-
-export const getUser = (prefix: string) => request(`${prefix}/user`);
-
-export const getUserGroups = (prefix: string, params: PaginationParams) =>
-  request(`${prefix}/groups`, {
-    data: { top_level_only: 1, ...params },
-  });
-
-export const getUserProjects = (prefix: string, uid: ID, params: 
PaginationParams) =>
-  request(`${prefix}/users/${uid}/projects`, {
-    data: params,
-  });
-
-export const getGroupSubgroups = (prefix: string, gid: ID, params: 
PaginationParams) =>
-  request(`${prefix}/groups/${gid}/subgroups`, {
-    data: params,
-  });
-
-export const getGroupProjects = (prefix: string, gid: ID, params: 
PaginationParams) =>
-  request(`${prefix}/groups/${gid}/projects`, {
-    data: { with_shared: false, ...params },
-  });
-
-type SearchProjectParams = {
-  search: string;
-  membership: boolean;
-};
-
-export const searchProject = (prefix: string, params: SearchProjectParams) =>
-  request(`${prefix}/projects`, {
-    data: params,
-  });
diff --git 
a/config-ui/src/plugins/register/jira/transformation-fields/dev-panel.tsx 
b/config-ui/src/plugins/register/jira/transformation-fields/dev-panel.tsx
index 9a502f1aa..61e327661 100644
--- a/config-ui/src/plugins/register/jira/transformation-fields/dev-panel.tsx
+++ b/config-ui/src/plugins/register/jira/transformation-fields/dev-panel.tsx
@@ -19,11 +19,11 @@
 import { useEffect, useState } from 'react';
 import { InputGroup, Button, RadioGroup, Radio, Icon, Collapse } from 
'@blueprintjs/core';
 
+import API from '@/api';
 import { Dialog, FormItem, toast } from '@/components';
 import JiraIssueTipsImg from '@/images/jira-issue-tips.png';
 import { operator } from '@/utils';
 
-import * as API from '../api';
 import * as S from './styled';
 
 interface Props {
@@ -52,8 +52,8 @@ export const DevPanel = ({ connectionId, transformation, 
setTransformation, isOp
 
     const [success, res] = await operator(
       async () => {
-        const { regex } = await API.generateRegex(pattern);
-        const preview = await API.applyRegex(regex, devPanelCommits);
+        const { regex } = await API.plugin.jira.generateRegex(pattern);
+        const preview = await API.plugin.jira.applyRegex(regex, 
devPanelCommits);
         return {
           regex,
           preview,
@@ -82,7 +82,7 @@ export const DevPanel = ({ connectionId, transformation, 
setTransformation, isOp
   }, [pattern]);
 
   const handleSearch = async () => {
-    const [success, res] = await operator(() => 
API.getApplicationTypes(connectionId, { key: issueKey }), {
+    const [success, res] = await operator(() => 
API.plugin.jira.applicationTypes(connectionId, { key: issueKey }), {
       setOperating: setSearching,
       hideToast: true,
     });
@@ -98,7 +98,7 @@ export const DevPanel = ({ connectionId, transformation, 
setTransformation, isOp
   const handleSubmit = async () => {
     if (step === 1 && applicationType) {
       const [success, res] = await operator(
-        () => API.getDevPanelCommits(connectionId, { key: issueKey, 
applicationType }),
+        () => API.plugin.jira.devPanelCommits(connectionId, { key: issueKey, 
applicationType }),
         {
           setOperating,
           hideToast: true,
diff --git 
a/config-ui/src/plugins/register/jira/transformation-fields/remote-link.tsx 
b/config-ui/src/plugins/register/jira/transformation-fields/remote-link.tsx
index 2d53e6abc..0c89b45a3 100644
--- a/config-ui/src/plugins/register/jira/transformation-fields/remote-link.tsx
+++ b/config-ui/src/plugins/register/jira/transformation-fields/remote-link.tsx
@@ -20,10 +20,10 @@ import { useEffect, useState } from 'react';
 import { InputGroup, Button, Intent } from '@blueprintjs/core';
 import { useDebounce } from 'ahooks';
 
+import API from '@/api';
 import { IconButton } from '@/components';
 import { operator } from '@/utils';
 
-import * as API from '../api';
 import * as S from './styled';
 
 interface Props {
@@ -50,7 +50,7 @@ export const RemoteLink = ({ transformation, 
setTransformation }: Props) => {
   const debouncedPattern = useDebounce(pattern, { wait: 500 });
 
   const getRegex = async () => {
-    const [success, res] = await operator(() => API.generateRegex(pattern), {
+    const [success, res] = await operator(() => 
API.plugin.jira.generateRegex(pattern), {
       hideToast: true,
       setOperating: setGenerating,
     });
diff --git a/config-ui/src/plugins/register/jira/transformation.tsx 
b/config-ui/src/plugins/register/jira/transformation.tsx
index 9ff7941e0..c893ac0f6 100644
--- a/config-ui/src/plugins/register/jira/transformation.tsx
+++ b/config-ui/src/plugins/register/jira/transformation.tsx
@@ -21,12 +21,12 @@ import { FormGroup, Tag, Icon, Intent } from 
'@blueprintjs/core';
 import { Popover2 } from '@blueprintjs/popover2';
 import { uniqWith } from 'lodash';
 
+import API from '@/api';
 import { PageLoading, HelpTooltip, ExternalLink, MultiSelector, Selector, 
Divider } from '@/components';
 import { useProxyPrefix, useRefreshData } from '@/hooks';
 import { DOC_URL } from '@/release';
 
 import { CrossDomain } from './transformation-fields';
-import * as API from './api';
 import * as S from './styled';
 
 enum StandardType {
@@ -67,7 +67,7 @@ export const JiraTransformation = ({ entities, connectionId, 
transformation, set
       };
     }
 
-    const [issueTypes, fields] = await Promise.all([API.getIssueType(prefix), 
API.getField(prefix)]);
+    const [issueTypes, fields] = await 
Promise.all([API.plugin.jira.issueType(prefix), API.plugin.jira.field(prefix)]);
     return {
       issueTypes: uniqWith(issueTypes, (it, oit) => it.name === oit.name),
       fields,
diff --git a/config-ui/src/plugins/register/tapd/data-scope.tsx 
b/config-ui/src/plugins/register/tapd/data-scope.tsx
index 280ae9f47..f083001ef 100644
--- a/config-ui/src/plugins/register/tapd/data-scope.tsx
+++ b/config-ui/src/plugins/register/tapd/data-scope.tsx
@@ -21,11 +21,12 @@ import { Button, ControlGroup, InputGroup, Intent } from 
'@blueprintjs/core';
 import type { McsID, McsItem } from 'miller-columns-select';
 import MillerColumnsSelect from 'miller-columns-select';
 
+import API from '@/api';
 import { ExternalLink, Loading } from '@/components';
 import * as T from '@/plugins/components/data-scope-remote/types';
-import * as API from '@/plugins/components/data-scope-remote/api';
+// import * as API from '@/plugins/components/data-scope-remote/api';
 
-import { prepareToken } from './api';
+// import { prepareToken } from './api';
 
 interface Props {
   connectionId: ID;
@@ -54,7 +55,7 @@ export const DataScope = ({ connectionId, disabledItems, 
selectedItems, onChange
   }, [pageToken]);
 
   const getItems = async (groupId: ID | null, currentPageToken?: string) => {
-    const res = await API.getRemoteScope('tapd', connectionId, {
+    const res = await API.scope.remote('tapd', connectionId, {
       groupId,
       pageToken: currentPageToken,
     });
@@ -76,7 +77,7 @@ export const DataScope = ({ connectionId, disabledItems, 
selectedItems, onChange
       setPageToken(undefined);
       return;
     }
-    const res = await prepareToken(connectionId, {
+    const res = await API.plugin.tapd.remoteScopePrepareToken(connectionId, {
       companyId,
     });
     setPageToken(res.pageToken);
diff --git a/config-ui/src/plugins/register/tapd/transformation.tsx 
b/config-ui/src/plugins/register/tapd/transformation.tsx
index 12450bce5..86b841046 100644
--- a/config-ui/src/plugins/register/tapd/transformation.tsx
+++ b/config-ui/src/plugins/register/tapd/transformation.tsx
@@ -19,10 +19,10 @@
 import { useEffect, useState } from 'react';
 import { FormGroup, Intent, Tag } from '@blueprintjs/core';
 
+import API from '@/api';
 import { HelpTooltip, MultiSelector, PageLoading } from '@/components';
 import { useProxyPrefix, useRefreshData } from '@/hooks';
 
-import * as API from './api';
 import * as S from './styled';
 import { uniqWith } from 'lodash';
 
@@ -74,11 +74,11 @@ export const TapdTransformation = ({ entities, 
connectionId, scopeId, transforma
     }
 
     const [storyType, bugType, taskType, storyStatus, bugStatus, taskStatus] = 
await Promise.all([
-      API.getStoryType(prefix, scopeId),
+      API.plugin.tapd.storyCategories(prefix, scopeId),
       { BUG: 'bug' } as Record<string, string>,
       { TASK: 'task' } as Record<string, string>,
-      API.getStatus(prefix, scopeId, 'story'),
-      API.getStatus(prefix, scopeId, 'bug'),
+      API.plugin.tapd.statusMap(prefix, scopeId, 'story'),
+      API.plugin.tapd.statusMap(prefix, scopeId, 'bug'),
       { open: 'task-open', progressing: 'task-progressing', done: 'task-done' 
} as Record<string, string>,
     ]);
 
diff --git a/config-ui/src/plugins/register/webook/api.ts 
b/config-ui/src/plugins/register/webook/api.ts
deleted file mode 100644
index fa35f40e6..000000000
--- a/config-ui/src/plugins/register/webook/api.ts
+++ /dev/null
@@ -1,46 +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 { request } from '@/utils';
-
-export const getConnections = () => request('/plugins/webhook/connections');
-
-export const getConnection = (id: ID) => 
request(`/plugins/webhook/connections/${id}`);
-
-type Paylod = {
-  name: string;
-};
-
-export const createConnection = (payload: Paylod) =>
-  request('/plugins/webhook/connections', {
-    method: 'post',
-    data: payload,
-  });
-
-export const updateConnection = (id: ID, payload: Paylod) =>
-  request(`/plugins/webhook/connections/${id}`, {
-    method: 'patch',
-    data: payload,
-  });
-
-export const deleteConnection = (id: ID) =>
-  request(`/plugins/webhook/connections/${id}`, {
-    method: 'delete',
-  });
-
-export const renewApiKey = (id: ID) => request(`/api-keys/${id}`, { method: 
'put' });
diff --git a/config-ui/src/plugins/register/webook/components/create-dialog.tsx 
b/config-ui/src/plugins/register/webook/components/create-dialog.tsx
index 0bc1113c3..9d4406bba 100644
--- a/config-ui/src/plugins/register/webook/components/create-dialog.tsx
+++ b/config-ui/src/plugins/register/webook/components/create-dialog.tsx
@@ -19,11 +19,11 @@
 import { useState, useMemo } from 'react';
 import { InputGroup, Icon } from '@blueprintjs/core';
 
+import API from '@/api';
 import { Dialog, FormItem, CopyText, ExternalLink } from '@/components';
 import { useConnections } from '@/hooks';
 import { operator } from '@/utils';
 
-import * as API from '../api';
 import * as S from '../styled';
 
 interface Props {
@@ -51,8 +51,9 @@ export const CreateDialog = ({ isOpen, onCancel, 
onSubmitAfter }: Props) => {
   const handleSubmit = async () => {
     const [success, res] = await operator(
       async () => {
-        const { id, apiKey } = await API.createConnection({ name });
-        const { postIssuesEndpoint, closeIssuesEndpoint, 
postPipelineDeployTaskEndpoint } = await API.getConnection(id);
+        const { id, apiKey } = await API.plugin.webhook.create({ name });
+        const { postIssuesEndpoint, closeIssuesEndpoint, 
postPipelineDeployTaskEndpoint } =
+          await API.plugin.webhook.get(id);
         return {
           id,
           apiKey: apiKey.apiKey,
diff --git a/config-ui/src/plugins/register/webook/components/delete-dialog.tsx 
b/config-ui/src/plugins/register/webook/components/delete-dialog.tsx
index 404ba9a97..2479f1754 100644
--- a/config-ui/src/plugins/register/webook/components/delete-dialog.tsx
+++ b/config-ui/src/plugins/register/webook/components/delete-dialog.tsx
@@ -18,12 +18,11 @@
 
 import { useState } from 'react';
 
+import API from '@/api';
 import { Dialog, Message } from '@/components';
 import { useConnections } from '@/hooks';
 import { operator } from '@/utils';
 
-import * as API from '../api';
-
 interface Props {
   initialId: ID;
   onCancel: () => void;
@@ -36,7 +35,7 @@ export const DeleteDialog = ({ initialId, onCancel, 
onSubmitAfter }: Props) => {
   const { onRefresh } = useConnections();
 
   const handleSubmit = async () => {
-    const [success] = await operator(() => API.deleteConnection(initialId), {
+    const [success] = await operator(() => 
API.plugin.webhook.remove(initialId), {
       setOperating,
     });
 
diff --git a/config-ui/src/plugins/register/webook/components/edit-dialog.tsx 
b/config-ui/src/plugins/register/webook/components/edit-dialog.tsx
index e66b554d1..a9fb55cc7 100644
--- a/config-ui/src/plugins/register/webook/components/edit-dialog.tsx
+++ b/config-ui/src/plugins/register/webook/components/edit-dialog.tsx
@@ -19,12 +19,11 @@
 import { useState, useEffect } from 'react';
 import { InputGroup } from '@blueprintjs/core';
 
+import API from '@/api';
 import { Dialog, FormItem } from '@/components';
 import { useConnections } from '@/hooks';
 import { operator } from '@/utils';
 
-import * as API from '../api';
-
 interface Props {
   initialId: ID;
   onCancel: () => void;
@@ -38,13 +37,13 @@ export const EditDialog = ({ initialId, onCancel }: Props) 
=> {
 
   useEffect(() => {
     (async () => {
-      const res = await API.getConnection(initialId);
+      const res = await API.plugin.webhook.get(initialId);
       setName(res.name);
     })();
   }, [initialId]);
 
   const handleSubmit = async () => {
-    const [success] = await operator(() => API.updateConnection(initialId, { 
name }), {
+    const [success] = await operator(() => 
API.plugin.webhook.update(initialId, { name }), {
       setOperating,
     });
 
diff --git 
a/config-ui/src/plugins/register/webook/components/selector-dialog.tsx 
b/config-ui/src/plugins/register/webook/components/selector-dialog.tsx
index 09fe03945..e3ac67c3b 100644
--- a/config-ui/src/plugins/register/webook/components/selector-dialog.tsx
+++ b/config-ui/src/plugins/register/webook/components/selector-dialog.tsx
@@ -20,10 +20,10 @@ import { useState, useEffect } from 'react';
 import type { McsItem } from 'miller-columns-select';
 import MillerColumnsSelect from 'miller-columns-select';
 
+import API from '@/api';
 import { Dialog, FormItem, Loading } from '@/components';
 
 import * as T from '../types';
-import * as API from '../api';
 import * as S from '../styled';
 
 interface Props {
@@ -48,7 +48,7 @@ export const SelectorDialog = ({ isOpen, saving, onCancel, 
onSubmit }: Props) =>
 
   useEffect(() => {
     (async () => {
-      const res = await API.getConnections();
+      const res = await API.plugin.webhook.list();
       setItems([...updateItems(res)]);
       setIsLast(true);
     })();
diff --git a/config-ui/src/plugins/register/webook/components/view-dialog.tsx 
b/config-ui/src/plugins/register/webook/components/view-dialog.tsx
index b7390df5c..179ea4a6b 100644
--- a/config-ui/src/plugins/register/webook/components/view-dialog.tsx
+++ b/config-ui/src/plugins/register/webook/components/view-dialog.tsx
@@ -19,10 +19,10 @@
 import { useState, useEffect, useMemo } from 'react';
 import { Button, Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { Dialog, FormItem, CopyText, ExternalLink, Message } from 
'@/components';
 import { operator } from '@/utils';
 
-import * as API from '../api';
 import * as S from '../styled';
 
 interface Props {
@@ -45,7 +45,7 @@ export const ViewDialog = ({ initialId, onCancel }: Props) => 
{
 
   useEffect(() => {
     (async () => {
-      const res = await API.getConnection(initialId);
+      const res = await API.plugin.webhook.get(initialId);
       setRecord({
         apiKeyId: res.apiKey.id,
         postIssuesEndpoint: ` curl ${prefix}${res.postIssuesEndpoint} -X 
'POST' -H 'Authorization: Bearer {API_KEY}' -d '{
@@ -67,7 +67,7 @@ export const ViewDialog = ({ initialId, onCancel }: Props) => 
{
   }, [initialId]);
 
   const handleGenerateNewKey = async () => {
-    const [success, res] = await operator(() => 
API.renewApiKey(record.apiKeyId), {
+    const [success, res] = await operator(() => 
API.apiKey.renew(record.apiKeyId), {
       setOperating,
     });
 
diff --git a/config-ui/src/routes/api-keys/api-keys.tsx 
b/config-ui/src/routes/api-keys/api-keys.tsx
index 1cced1076..b37a525e0 100644
--- a/config-ui/src/routes/api-keys/api-keys.tsx
+++ b/config-ui/src/routes/api-keys/api-keys.tsx
@@ -20,6 +20,7 @@ import { useState, useMemo } from 'react';
 import { Button, Intent, InputGroup } from '@blueprintjs/core';
 import { CopyToClipboard } from 'react-copy-to-clipboard';
 
+import API from '@/api';
 import {
   PageHeader,
   Table,
@@ -36,7 +37,6 @@ import {
 import { useRefreshData } from '@/hooks';
 import { operator, formatTime } from '@/utils';
 
-import * as API from './api';
 import * as C from './constant';
 import * as S from './styled';
 
@@ -58,7 +58,7 @@ export const ApiKeys = () => {
     allowedPath: '.*',
   });
 
-  const { data, ready } = useRefreshData(() => API.getApiKeys({ page, pageSize 
}), [version, page, pageSize]);
+  const { data, ready } = useRefreshData(() => API.apiKey.list({ page, 
pageSize }), [version, page, pageSize]);
 
   const [dataSource, total] = useMemo(() => [data?.apikeys ?? [], data?.count 
?? 0], [data]);
 
@@ -71,7 +71,7 @@ export const ApiKeys = () => {
   };
 
   const handleSubmit = async () => {
-    const [success, res] = await operator(() => API.createApiKey(form), {
+    const [success, res] = await operator(() => API.apiKey.create(form), {
       setOperating,
       hideToast: true,
     });
@@ -91,7 +91,7 @@ export const ApiKeys = () => {
   const handleRevoke = async () => {
     if (!currentId) return;
 
-    const [success] = await operator(() => API.deleteApiKey(currentId));
+    const [success] = await operator(() => API.apiKey.remove(currentId));
 
     if (success) {
       setVersion(version + 1);
diff --git a/config-ui/src/routes/error/components/needs-db-migrate/index.tsx 
b/config-ui/src/routes/error/components/needs-db-migrate/index.tsx
index 11e3213e6..09338f073 100644
--- a/config-ui/src/routes/error/components/needs-db-migrate/index.tsx
+++ b/config-ui/src/routes/error/components/needs-db-migrate/index.tsx
@@ -20,11 +20,10 @@ import { useState } from 'react';
 import { Icon, Button, Colors, Intent } from '@blueprintjs/core';
 import { useNavigate } from 'react-router-dom';
 
+import API from '@/api';
 import { Card, Buttons } from '@/components';
 import { operator } from '@/utils';
 
-import * as API from './api';
-
 export const NeedsDBMigrate = () => {
   const [operating, setOperating] = useState(false);
 
diff --git a/config-ui/src/routes/error/components/offline/index.tsx 
b/config-ui/src/routes/error/components/offline/index.tsx
index 37b39aee8..b2fc0df1a 100644
--- a/config-ui/src/routes/error/components/offline/index.tsx
+++ b/config-ui/src/routes/error/components/offline/index.tsx
@@ -20,12 +20,11 @@ import { useMemo, useState } from 'react';
 import { useNavigate } from 'react-router-dom';
 import { Icon, Tag, Button, Intent, Colors, IconName } from 
'@blueprintjs/core';
 
+import API from '@/api';
 import { DEVLAKE_ENDPOINT } from '@/config';
 import { Card, Buttons } from '@/components';
 import { useAutoRefresh } from '@/hooks';
 
-import * as API from './api';
-
 export const Offline = () => {
   const [version, setVersion] = useState(1);
 
diff --git a/config-ui/src/routes/layout/loader.ts 
b/config-ui/src/routes/layout/loader.ts
index 31dee58c8..c06790200 100644
--- a/config-ui/src/routes/layout/loader.ts
+++ b/config-ui/src/routes/layout/loader.ts
@@ -19,18 +19,17 @@
 import { AxiosError } from 'axios';
 import { json } from 'react-router-dom';
 
+import API from '@/api';
 import { ErrorEnum } from '@/routes/error';
 
-import * as API from './api';
-
 type Props = {
   request: Request;
 };
 
 export const loader = async ({ request }: Props) => {
   try {
-    const version = await API.getVersion(request.signal);
-    const userInfo = await API.getUserInfo(request.signal);
+    const version = await API.version(request.signal);
+    const userInfo = await API.userInfo(request.signal);
     return {
       version: version.version,
       userInfo,
diff --git a/config-ui/src/routes/pipeline/components/info.tsx 
b/config-ui/src/routes/pipeline/components/info.tsx
index 3beea1896..5d4e9c728 100644
--- a/config-ui/src/routes/pipeline/components/info.tsx
+++ b/config-ui/src/routes/pipeline/components/info.tsx
@@ -18,13 +18,13 @@
 
 import { useState } from 'react';
 
+import API from '@/api';
 import { Loading, IconButton } from '@/components';
 import { useAutoRefresh } from '@/hooks';
 import { formatTime, operator } from '@/utils';
 
 import * as T from '../types';
 import * as S from '../styled';
-import * as API from '../api';
 
 import { PipelineStatus } from './status';
 import { PipelineDuration } from './duration';
@@ -36,7 +36,7 @@ interface Props {
 export const PipelineInfo = ({ id }: Props) => {
   const [operating, setOperating] = useState(false);
 
-  const { data } = useAutoRefresh<T.Pipeline>(() => API.getPipeline(id), [], {
+  const { data } = useAutoRefresh<T.Pipeline>(() => API.pipeline.get(id), [], {
     cancel: (data) => {
       return !!(
         data &&
@@ -51,7 +51,7 @@ export const PipelineInfo = ({ id }: Props) => {
   });
 
   const handleCancel = async () => {
-    const [success] = await operator(() => API.deletePipeline(id), {
+    const [success] = await operator(() => API.pipeline.remove(id), {
       setOperating,
     });
 
@@ -61,7 +61,7 @@ export const PipelineInfo = ({ id }: Props) => {
   };
 
   const handleRerun = async () => {
-    const [success] = await operator(() => API.rerunPipeline(id), {
+    const [success] = await operator(() => API.pipeline.rerun(id), {
       setOperating,
     });
 
diff --git a/config-ui/src/routes/pipeline/components/table.tsx 
b/config-ui/src/routes/pipeline/components/table.tsx
index c40f19627..659d894c9 100644
--- a/config-ui/src/routes/pipeline/components/table.tsx
+++ b/config-ui/src/routes/pipeline/components/table.tsx
@@ -21,12 +21,12 @@ import { ButtonGroup } from '@blueprintjs/core';
 import { pick } from 'lodash';
 import { saveAs } from 'file-saver';
 
+import API from '@/api';
 import { DEVLAKE_ENDPOINT } from '@/config';
 import { Table, ColumnType, IconButton, Inspector, Dialog } from 
'@/components';
 import { formatTime } from '@/utils';
 
 import * as T from '../types';
-import * as API from '../api';
 
 import { PipelineStatus } from './status';
 import { PipelineDuration } from './duration';
@@ -57,7 +57,7 @@ export const PipelineTable = ({ dataSource, pagination, 
noData }: Props) => {
   };
 
   const handleDownloadLog = async (id: ID) => {
-    const res = await API.getPipelineLog(id);
+    const res = await API.pipeline.log(id);
     if (res) {
       saveAs(`${DEVLAKE_ENDPOINT}/pipelines/${id}/logging.tar.gz`, 
'logging.tar.gz');
     }
diff --git a/config-ui/src/routes/pipeline/components/task.tsx 
b/config-ui/src/routes/pipeline/components/task.tsx
index e96c2e03e..c4b7a8767 100644
--- a/config-ui/src/routes/pipeline/components/task.tsx
+++ b/config-ui/src/routes/pipeline/components/task.tsx
@@ -19,13 +19,13 @@
 import { useState, useMemo } from 'react';
 import { Intent } from '@blueprintjs/core';
 
+import API from '@/api';
 import { TextTooltip, IconButton } from '@/components';
 import { getPluginConfig } from '@/plugins';
 import { operator } from '@/utils';
 
 import * as T from '../types';
 import * as S from '../styled';
-import * as API from '../api';
 
 import { PipelineDuration } from './duration';
 
@@ -88,7 +88,7 @@ export const PipelineTask = ({ task }: Props) => {
   }, [task]);
 
   const handleRerun = async () => {
-    const [success] = await operator(() => API.taskRerun(id), {
+    const [success] = await operator(() => API.task.rertun(id), {
       setOperating,
     });
 
diff --git a/config-ui/src/routes/pipeline/components/tasks.tsx 
b/config-ui/src/routes/pipeline/components/tasks.tsx
index a4b0cdcec..9cde98420 100644
--- a/config-ui/src/routes/pipeline/components/tasks.tsx
+++ b/config-ui/src/routes/pipeline/components/tasks.tsx
@@ -20,12 +20,12 @@ import { useState } from 'react';
 import { Button, Collapse, Icon } from '@blueprintjs/core';
 import { groupBy, sortBy } from 'lodash';
 
+import API from '@/api';
 import { Loading } from '@/components';
 import { useAutoRefresh } from '@/hooks';
 
 import * as T from '../types';
 import * as S from '../styled';
-import * as API from '../api';
 
 import { PipelineTask } from './task';
 
@@ -41,7 +41,7 @@ export const PipelineTasks = ({ id, style }: Props) => {
 
   const { data } = useAutoRefresh<T.PipelineTask[]>(
     async () => {
-      const taskRes = await API.getPipelineTasks(id);
+      const taskRes = await API.pipeline.tasks(id);
       return taskRes.tasks;
     },
     [],
diff --git a/config-ui/src/routes/pipeline/pipelines.tsx 
b/config-ui/src/routes/pipeline/pipelines.tsx
index b990054b8..6fb57a5b6 100644
--- a/config-ui/src/routes/pipeline/pipelines.tsx
+++ b/config-ui/src/routes/pipeline/pipelines.tsx
@@ -17,17 +17,17 @@
  */
 import { useState, useMemo } from 'react';
 
+import API from '@/api';
 import { PageHeader } from '@/components';
 import { useRefreshData } from '@/hooks';
 
 import { PipelineTable } from './components';
-import * as API from './api';
 
 export const Pipelines = () => {
   const [page, setPage] = useState(1);
   const [pageSize] = useState(20);
 
-  const { ready, data } = useRefreshData(() => API.getPipelines());
+  const { ready, data } = useRefreshData(() => API.pipeline.list());
 
   const [dataSource, total] = useMemo(() => [(data?.pipelines ?? []).map((it) 
=> it), data?.count ?? 0], [data]);
 
diff --git a/config-ui/src/store/connections/context.tsx 
b/config-ui/src/store/connections/context.tsx
index d9220e87b..a41b238bc 100644
--- a/config-ui/src/store/connections/context.tsx
+++ b/config-ui/src/store/connections/context.tsx
@@ -20,12 +20,12 @@ import React, { useState, useEffect, useMemo } from 'react';
 
 import { PageLoading } from '@/components';
 
+import API from '@/api';
 import type { PluginConfigType } from '@/plugins';
 import { PluginConfig, PluginType } from '@/plugins';
 
 import type { ConnectionItemType } from './types';
 import { ConnectionStatusEnum } from './types';
-import * as API from './api';
 
 export const ConnectionContext = React.createContext<{
   connections: ConnectionItemType[];
@@ -46,7 +46,7 @@ export const ConnectionContextProvider = ({ children, 
...props }: Props) => {
 
   const queryConnection = async (plugin: string) => {
     try {
-      const res = await API.getConnection(plugin);
+      const res = await API.connection.list(plugin);
       const { name, icon, isBeta, scopeConfig } = plugins.find((p) => p.plugin 
=== plugin) as PluginConfigType;
 
       return res.map((connection) => ({
@@ -74,7 +74,7 @@ export const ConnectionContextProvider = ({ children, 
...props }: Props) => {
     appId,
   }: ConnectionItemType) => {
     try {
-      const res = await API.testConnection(plugin, {
+      const res = await API.connection.test(plugin, {
         endpoint,
         proxy,
         token,

Reply via email to